From aba252206bf39ac81e6627354062c28fae05b0aa Mon Sep 17 00:00:00 2001 From: mtg0001 <106211915+mtg0001@users.noreply.github.com> Date: Mon, 3 Aug 2026 15:11:55 -0300 Subject: Activate BIP44 wallet derivation (#124) * Add BIP32 path derivation foundation * Add HD wallet schema metadata * Add provisional BIP44 coin type metadata * Activate BIP44 wallet derivation * wallet: scan BIP44 restore depth per branch * wallet: widen default BIP44 restore lookahead --------- Co-authored-by: Gilcimar Duarte --- src/bip32.cpp | 109 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 16 deletions(-) (limited to 'src/bip32.cpp') diff --git a/src/bip32.cpp b/src/bip32.cpp index 6423974..6ba946a 100644 --- a/src/bip32.cpp +++ b/src/bip32.cpp @@ -114,6 +114,43 @@ static bool HmacSha512(const unsigned char* key, int keyLen, len == 64; } +static bool PrivateKeyToCompressedPubKey(const std::vector& privateKey, + unsigned char out[33], + std::string& errorOut) +{ + if (!IsValidPrivateKey(privateKey)) + { + errorOut = "private key is invalid"; + return false; + } + + BIGNUM* bn = BN_bin2bn(&privateKey[0], 32, NULL); + BN_CTX* ctx = BN_CTX_new(); + EC_GROUP* group = EC_GROUP_new_by_curve_name(NID_secp256k1); + EC_POINT* pub = group ? EC_POINT_new(group) : NULL; + + bool ok = false; + if (bn && ctx && group && pub && + EC_POINT_mul(group, pub, bn, NULL, NULL, ctx)) + { + size_t n = EC_POINT_point2oct(group, pub, POINT_CONVERSION_COMPRESSED, + out, 33, ctx); + ok = n == 33; + } + + BN_free(bn); + BN_CTX_free(ctx); + EC_POINT_free(pub); + EC_GROUP_free(group); + + if (!ok) + { + errorOut = "could not serialize parent public key"; + return false; + } + return true; +} + bool BIP39EntropyToMnemonic(const std::vector& entropy, std::string& mnemonicOut, std::string& errorOut) @@ -284,10 +321,10 @@ bool BIP32MasterFromSeed(const std::vector& seed, return true; } -bool BIP32DeriveHardenedChild(const BIP32PrivateNode& parent, - unsigned int childIndex, - BIP32PrivateNode& childOut, - std::string& errorOut) +bool BIP32DeriveChild(const BIP32PrivateNode& parent, + unsigned int childNumber, + BIP32PrivateNode& childOut, + std::string& errorOut) { childOut.privateKey.clear(); childOut.chainCode.clear(); @@ -297,20 +334,21 @@ bool BIP32DeriveHardenedChild(const BIP32PrivateNode& parent, errorOut = "parent private key or chain code is invalid"; return false; } - if (childIndex >= 0x80000000U) + unsigned char data[37]; + if (childNumber & BIP32_HARDENED) { - errorOut = "child index must be non-hardened; hardening is applied here"; - return false; + data[0] = 0x00; + memcpy(data + 1, &parent.privateKey[0], 32); } - - const unsigned int hardened = childIndex | 0x80000000U; - unsigned char data[37]; - data[0] = 0x00; - memcpy(data + 1, &parent.privateKey[0], 32); - data[33] = (unsigned char)((hardened >> 24) & 0xff); - data[34] = (unsigned char)((hardened >> 16) & 0xff); - data[35] = (unsigned char)((hardened >> 8) & 0xff); - data[36] = (unsigned char)(hardened & 0xff); + else + { + if (!PrivateKeyToCompressedPubKey(parent.privateKey, data, errorOut)) + return false; + } + data[33] = (unsigned char)((childNumber >> 24) & 0xff); + data[34] = (unsigned char)((childNumber >> 16) & 0xff); + data[35] = (unsigned char)((childNumber >> 8) & 0xff); + data[36] = (unsigned char)(childNumber & 0xff); unsigned char I[64]; if (!HmacSha512(&parent.chainCode[0], 32, data, sizeof(data), I)) @@ -363,4 +401,43 @@ bool BIP32DeriveHardenedChild(const BIP32PrivateNode& parent, return true; } +bool BIP32DerivePath(const BIP32PrivateNode& root, + const std::vector& path, + BIP32PrivateNode& nodeOut, + std::string& errorOut) +{ + nodeOut.privateKey.clear(); + nodeOut.chainCode.clear(); + errorOut.clear(); + if (!IsValidPrivateKey(root.privateKey) || root.chainCode.size() != 32) + { + errorOut = "root private key or chain code is invalid"; + return false; + } + + BIP32PrivateNode cur = root; + for (size_t i = 0; i < path.size(); i++) + { + BIP32PrivateNode next; + if (!BIP32DeriveChild(cur, path[i], next, errorOut)) + return false; + cur = next; + } + nodeOut = cur; + return true; +} + +bool BIP32DeriveHardenedChild(const BIP32PrivateNode& parent, + unsigned int childIndex, + BIP32PrivateNode& childOut, + std::string& errorOut) +{ + if (childIndex >= BIP32_HARDENED) + { + errorOut = "child index must be non-hardened; hardening is applied here"; + return false; + } + return BIP32DeriveChild(parent, childIndex | BIP32_HARDENED, childOut, errorOut); +} + } // namespace bitflash -- cgit v1.2.3