diff --git a/src/frame.cpp b/src/frame.cpp index 630d91e..e155d65 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -422,7 +422,7 @@ COMMIT; wxLogMessage("\t\tGenerating random 128 bit wallet secret"); auto text_secret{ DeriveTextSecret(ristretto255::scalar::random(), 1) }; ro::msec start_time{ ro::msec_since_epoch() }; - ristretto255::CMasterSecret MasterSecret(DeriveStrongSecret(&text_secret[0])); + ristretto255::CMasterSecret MasterSecret(ristretto255::scalar(DeriveStrongSecretHash(&text_secret[0]))); decltype(start_time) end_time{ ro::msec_since_epoch() }; wxLogMessage("\t\tStrong secret derivation took %d milliseconds", (end_time - start_time).count()); sql_update_to_misc update_to_misc(db); diff --git a/src/ristretto255.h b/src/ristretto255.h index 8315cba..2b92041 100644 --- a/src/ristretto255.h +++ b/src/ristretto255.h @@ -106,9 +106,13 @@ namespace ristretto255 { template class hsh { public: - static_assert(hashsize > 63 && hashsize % 64 == 0 && crypto_generichash_BYTES_MIN * 8 <= hashsize && hashsize <= crypto_generichash_BYTES_MAX * 8, "Bad hash size."); - static constexpr unsigned int type_indentifier = 2 + (hashsize + 0x90 * 8) / 64; - static_assert(crypto_generichash_BYTES_MAX < 0x90, "Change in max hash has broken our type ids"); + static_assert( + hashsize % 64 == 0 && + crypto_generichash_BYTES_MIN * 8 /*128*/ <= hashsize && hashsize <= crypto_generichash_BYTES_MAX * 8 /*512*/, + "Bad hash size." + ); + static constexpr unsigned int type_indentifier = 5 + (hashsize + 1024) / 64; + static_assert(crypto_generichash_BYTES_MAX < 1024/8, "Change in max hash has broken our type ids"); crypto_generichash_blake2b_state st; hsh() { int i{ crypto_generichash_blake2b_init( @@ -197,9 +201,8 @@ namespace ristretto255 { // is running. template class hash { static_assert( - hashsize > 63 && hashsize % 64 == 0 - && crypto_generichash_BYTES_MIN * 8 <= hashsize - && hashsize <= crypto_generichash_BYTES_MAX * 8, + hashsize % 64 == 0 + && crypto_generichash_BYTES_MIN * 8 <= hashsize && hashsize <= crypto_generichash_BYTES_MAX * 8, "Bad hash size." ); friend point; diff --git a/src/secrets.cpp b/src/secrets.cpp index f1ebbd5..9f52cd7 100644 --- a/src/secrets.cpp +++ b/src/secrets.cpp @@ -30,9 +30,30 @@ std::array DeriveTextSecret(const scalar & blob, uint_fast64_t i){ return txt; } +//Derive a strong hash secret from a string with password strengthening. +//Net effect is convert one scalar into another by a process that is lengthy and costly. +ristretto255::hash<512> DeriveStrongSecretHash(const char* const passwd) { + static std::array salt{ 0 }; + std::array)>randb; + int i{ + crypto_pwhash( + &randb[0], + sizeof(randb), + passwd, + strlen(passwd) + 1, + &salt[0], + 2, 0x10000000, + crypto_pwhash_ALG_ARGON2ID13 + ) + }; + static_assert(crypto_pwhash_OPSLIMIT_MODERATE == 0x00000003 && crypto_pwhash_MEMLIMIT_MODERATE == 0x10000000, "Argon changed, likely breaking all passphrases"); + assert(i == 0); + return hash<512>(randb); +} + //Derive a strong scalar secret from a string with password strengthening. //Net effect is convert one scalar into another by a process that is lengthy and costly. -ristretto255::scalar DeriveStrongSecret(const char* const passwd){ +ristretto255::scalar DeriveStrongSecretScalar(const char* const passwd){ static std::array salt{ 0 }; std::array)>randb; int i{ @@ -54,4 +75,42 @@ ristretto255::scalar DeriveStrongSecret(const char* const passwd){ //Derive scalar secret from another quickly. ristretto255::scalar DeriveSecret(const scalar &sc, uint_fast64_t i) { return ristretto255::scalar(ristretto255::hash<512>(sc, i)); -} \ No newline at end of file +} + +namespace ristretto255 { + extended_private_key::extended_private_key(extended_private_key& parent, std::span path) : + privatekey(parent.privatekey* scalar(hash<512>(parent.chain, path))), + chain(parent.chain, path) + {}; + + extended_private_key::extended_private_key() : + m_valid{ false } + {} + + extended_private_key::extended_private_key(hash<512>&& s) : + privatekey(s), + chain(s), + m_valid{ true } + {}; + + extended_private_key::extended_private_key(const char* const passwd) : + extended_private_key(DeriveStrongSecretHash(passwd)) + {}; + + extended_public_key::extended_public_key() : + m_valid{ false } + {}; + + extended_public_key::extended_public_key(extended_public_key& parent, std::span path) : + publickey(parent.publickey* scalar(hash<512>(parent.chain, path))), + chain(parent.chain, path), + m_valid{ true } + {}; + + extended_public_key::extended_public_key(extended_private_key& p) : + publickey{ p.privatekey.timesBase() }, + chain{ p.chain }, + m_valid{ true } + {}; + +} diff --git a/src/secrets.h b/src/secrets.h index b0f2115..50b907e 100644 --- a/src/secrets.h +++ b/src/secrets.h @@ -2,9 +2,9 @@ //Derive a Short text Secret from a 256 bit random value and a sixty four bit integer std::array DeriveTextSecret(const ristretto255::scalar& blob, uint_fast64_t i); -//Derive a strong scalar secret from a string with password strengthening. +//Derive a strong hash secret from a string with password strengthening. //Net effect is convert one scalar into another by a process that is lengthy and costly. -ristretto255::scalar DeriveStrongSecret(const char* const passwd); +ristretto255::hash<512> DeriveStrongSecretHash(const char* const passwd); //Derive scalar secret from another quickly. ristretto255::scalar DeriveSecret(const ristretto255::scalar &sc, uint_fast64_t i); @@ -12,3 +12,70 @@ template , int> constexpr int rounded_log2(const T val) noexcept { return std::numeric_limits::digits - std::countl_zero(val); } + +namespace ristretto255 { + class extended_private_key { + /* This is the same name and concept as BIP0032 and BIP0044 extended private + and public keys, and used for the same purpose, to deterministically + create a hierarchical tree of secrets each defined by a path from the master + extended key, but utterly incompatible, for BIP secrets use the SECp256k1 + elliptic curve, while I am using ristretto25519, which is much better. + + SECp256k1 was the best curve of Satoshi's day, because Satoshi knew the NIST + curves were and are backdoored, but ristretto25519 is a better elliptic curve + because faster, more compact, and fewer subtle, difficult to comprehend, esoteric, + security holes that the engineer trying to use it is going to fall into. + + Also, the BIP0032 -- BIP0044 extended keys use 32 bitunsigned integers + for the path, but since I want to allow names, among other things, + I use spans of bytes. */ + extended_private_key(hash<512>&&); + public: + static constexpr bool is_machine_independent() { return true; }; + scalar privatekey; + hash<256> chain; + static constexpr unsigned int type_indentifier = 3; + private: + bool m_valid; + public: + extended_private_key(); + extended_private_key(extended_private_key& parent, std::span path); + extended_private_key(const char* const passwd); + template auto operator()(T psz) { + assert(m_valid); + return privatekey*scalar(hash<512>(chain, psz)); + } + bool valid() { return m_valid; } + + }; + + static_assert(sizeof(extended_private_key) == sizeof(hash<256>) + sizeof(scalar) + sizeof(bool)); + + class extended_public_key { + /* This is the same name and concept as BIP0032 and BIP0044 extended private + and public keys, and used for the same purpose, to deterministically + create a hierarchical tree of secrets each defined by a path from the master + extended key, but utterly incompatible */ + public: + static constexpr bool is_machine_independent() { return true; }; + point publickey; + hash<256> chain; + static constexpr unsigned int type_indentifier = 4; + private: + bool m_valid; + public: + extended_public_key(); + extended_public_key(extended_public_key& parent, std::span path); + extended_public_key(extended_private_key&); + template auto operator()(T psz) { + scalar& t(*this); + assert(m_valid); + return publickey * scalar(hash<512>(chain, psz)); + } + bool valid() { return m_valid; } + }; + + static_assert(sizeof(extended_public_key) == sizeof(hash<256>) + sizeof(point) + sizeof(bool)); + std::span serialize(const extended_private_key& pt); + std::span serialize(const extended_public_key& pt); +} diff --git a/src/unit_test.cpp b/src/unit_test.cpp index 8153978..51c0fa1 100644 --- a/src/unit_test.cpp +++ b/src/unit_test.cpp @@ -528,7 +528,7 @@ COMMIT; wxLogMessage(wxT("\t\tGenerating random 128 bit wallet secret")); auto text_secret{ DeriveTextSecret(ristretto255::scalar::random(), 1) }; ro::msec start_time{ ro::msec_since_epoch() }; - ristretto255::CMasterSecret MasterSecret(DeriveStrongSecret(&text_secret[0]) ); + ristretto255::CMasterSecret MasterSecret(scalar(DeriveStrongSecretHash(&text_secret[0])) ); decltype(start_time) end_time{ ro::msec_since_epoch() }; wxLogMessage(wxT("\t\tStrong secret derivation took %d milliseconds"), (end_time - start_time).count()); sql_update_to_misc update_to_misc(db.get()); @@ -610,7 +610,7 @@ namespace ristretto255 { } if (!(singletonApp->m_quick_unit_test)){ auto start_time{ std::chrono::high_resolution_clock::now() }; - auto s1{ DeriveStrongSecret(&text_secret[0]) }; + auto s1{ scalar( DeriveStrongSecretHash(&text_secret[0])) }; auto end_time{ std::chrono::high_resolution_clock::now() }; if (s1 == scalar({ 0x59, 0xf6, 0x73, 0xb4, 0xa0, 0xc7, 0x0d, 0x8b, 0x51, 0xe5, 0x87, 0x7c, 0xf5, 0xd7, 0x6f, 0x55, 0x31, 0xa7, 0x0b, 0x14, 0x28, 0x54, 0x97, 0x08, 0x9f, 0x27, 0x83, 0xe1, 0xc7, 0x5f, 0x55, 0x0f })) { wxLogMessage("\t\tObtained expected strong scalar secret from scalar(7)");