1
0
forked from cheng/wallet

added extended keys

but not going to start using them until
I can save them to the database and reload them
This commit is contained in:
Cheng 2024-07-27 07:32:03 +00:00
parent fe3015b851
commit feb040d800
No known key found for this signature in database
5 changed files with 142 additions and 13 deletions

View File

@ -422,7 +422,7 @@ COMMIT;
wxLogMessage("\t\tGenerating random 128 bit wallet secret"); wxLogMessage("\t\tGenerating random 128 bit wallet secret");
auto text_secret{ DeriveTextSecret(ristretto255::scalar::random(), 1) }; auto text_secret{ DeriveTextSecret(ristretto255::scalar::random(), 1) };
ro::msec start_time{ ro::msec_since_epoch() }; 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() }; decltype(start_time) end_time{ ro::msec_since_epoch() };
wxLogMessage("\t\tStrong secret derivation took %d milliseconds", (end_time - start_time).count()); wxLogMessage("\t\tStrong secret derivation took %d milliseconds", (end_time - start_time).count());
sql_update_to_misc update_to_misc(db); sql_update_to_misc update_to_misc(db);

View File

@ -106,9 +106,13 @@ namespace ristretto255 {
template<unsigned int hashsize = 256> class hsh { template<unsigned int hashsize = 256> class hsh {
public: public:
static_assert(hashsize > 63 && hashsize % 64 == 0 && crypto_generichash_BYTES_MIN * 8 <= hashsize && hashsize <= crypto_generichash_BYTES_MAX * 8, "Bad hash size."); static_assert(
static constexpr unsigned int type_indentifier = 2 + (hashsize + 0x90 * 8) / 64; hashsize % 64 == 0 &&
static_assert(crypto_generichash_BYTES_MAX < 0x90, "Change in max hash has broken our type ids"); 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; crypto_generichash_blake2b_state st;
hsh() { hsh() {
int i{ crypto_generichash_blake2b_init( int i{ crypto_generichash_blake2b_init(
@ -197,9 +201,8 @@ namespace ristretto255 {
// is running. // is running.
template<unsigned int hashsize = 256> class hash { template<unsigned int hashsize = 256> class hash {
static_assert( static_assert(
hashsize > 63 && hashsize % 64 == 0 hashsize % 64 == 0
&& crypto_generichash_BYTES_MIN * 8 <= hashsize && crypto_generichash_BYTES_MIN * 8 <= hashsize && hashsize <= crypto_generichash_BYTES_MAX * 8,
&& hashsize <= crypto_generichash_BYTES_MAX * 8,
"Bad hash size." "Bad hash size."
); );
friend point; friend point;

View File

@ -30,9 +30,30 @@ std::array<char, 27> DeriveTextSecret(const scalar & blob, uint_fast64_t i){
return txt; 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<uint8_t, crypto_pwhash_SALTBYTES> salt{ 0 };
std::array<uint8_t, sizeof(ristretto255::hash<512>)>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. //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. //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<uint8_t, crypto_pwhash_SALTBYTES> salt{ 0 }; static std::array<uint8_t, crypto_pwhash_SALTBYTES> salt{ 0 };
std::array<uint8_t, sizeof(ristretto255::hash<512>)>randb; std::array<uint8_t, sizeof(ristretto255::hash<512>)>randb;
int i{ int i{
@ -54,4 +75,42 @@ ristretto255::scalar DeriveStrongSecret(const char* const passwd){
//Derive scalar secret from another quickly. //Derive scalar secret from another quickly.
ristretto255::scalar DeriveSecret(const scalar &sc, uint_fast64_t i) { ristretto255::scalar DeriveSecret(const scalar &sc, uint_fast64_t i) {
return ristretto255::scalar(ristretto255::hash<512>(sc, i)); return ristretto255::scalar(ristretto255::hash<512>(sc, i));
} }
namespace ristretto255 {
extended_private_key::extended_private_key(extended_private_key& parent, std::span<byte> 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<byte> 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 }
{};
}

View File

@ -2,9 +2,9 @@
//Derive a Short text Secret from a 256 bit random value and a sixty four bit integer //Derive a Short text Secret from a 256 bit random value and a sixty four bit integer
std::array<char, 0x1b> DeriveTextSecret(const ristretto255::scalar& blob, uint_fast64_t i); std::array<char, 0x1b> 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. //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. //Derive scalar secret from another quickly.
ristretto255::scalar DeriveSecret(const ristretto255::scalar &sc, uint_fast64_t i); ristretto255::scalar DeriveSecret(const ristretto255::scalar &sc, uint_fast64_t i);
@ -12,3 +12,70 @@ template <class T, std::enable_if_t<std::_Is_standard_unsigned_integer<T>, int>
constexpr int rounded_log2(const T val) noexcept { constexpr int rounded_log2(const T val) noexcept {
return std::numeric_limits<T>::digits - std::countl_zero(val); return std::numeric_limits<T>::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<byte> path);
extended_private_key(const char* const passwd);
template<class T> 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<byte> path);
extended_public_key(extended_private_key&);
template<class T> 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<const byte> serialize(const extended_private_key& pt);
std::span<const byte> serialize(const extended_public_key& pt);
}

View File

@ -528,7 +528,7 @@ COMMIT;
wxLogMessage(wxT("\t\tGenerating random 128 bit wallet secret")); wxLogMessage(wxT("\t\tGenerating random 128 bit wallet secret"));
auto text_secret{ DeriveTextSecret(ristretto255::scalar::random(), 1) }; auto text_secret{ DeriveTextSecret(ristretto255::scalar::random(), 1) };
ro::msec start_time{ ro::msec_since_epoch() }; 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() }; decltype(start_time) end_time{ ro::msec_since_epoch() };
wxLogMessage(wxT("\t\tStrong secret derivation took %d milliseconds"), (end_time - start_time).count()); wxLogMessage(wxT("\t\tStrong secret derivation took %d milliseconds"), (end_time - start_time).count());
sql_update_to_misc update_to_misc(db.get()); sql_update_to_misc update_to_misc(db.get());
@ -610,7 +610,7 @@ namespace ristretto255 {
} }
if (!(singletonApp->m_quick_unit_test)){ if (!(singletonApp->m_quick_unit_test)){
auto start_time{ std::chrono::high_resolution_clock::now() }; 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() }; 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 })) { 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)"); wxLogMessage("\t\tObtained expected strong scalar secret from scalar(7)");