From cceba591b21ef1588fff3a7ea4a050c90906a2d8 Mon Sep 17 00:00:00 2001 From: Ed Tubbs Date: Wed, 5 Feb 2025 14:13:10 -0600 Subject: [PATCH] wallet: update derivation path to m/0'/3'/n' tests: added DeriveNewChildKey test --- src/wallet/test/wallet_tests.cpp | 45 ++++++++++++++++++++++++++++++++ src/wallet/wallet.cpp | 11 ++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 39e44c026..debab5365 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -547,4 +547,49 @@ BOOST_AUTO_TEST_CASE(GetMinimumFee_dust_test) CWallet::discardThreshold = COIN / 100; } +BOOST_FIXTURE_TEST_CASE(derive_new_child_key_test, WalletTestingSetup) +{ + CWallet* wallet = pwalletMain; + LOCK(wallet->cs_wallet); + + // Use a fixed seed and known child public key + std::string testSeedHex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; + std::string expectedPubKeyHex = "0305a077194300e27d320a9504f808a16f05b38dabead31f10104c075d88f81a38"; + std::vector seed = ParseHex(testSeedHex); + + // Initialize the master key with the fixed seed and get the public key + CKey masterKey; + masterKey.Set(seed.begin(), seed.end(), true); + CPubKey masterPubKey = masterKey.GetPubKey(); + BOOST_CHECK(masterKey.VerifyPubKey(masterPubKey)); + + // Set up master metadata: path "m" and master key ID equal to the public key hash + int64_t nCreationTime = GetTime(); + CKeyMetadata masterMetadata(nCreationTime); + masterMetadata.hdKeypath = "m"; + masterMetadata.hdMasterKeyID = masterPubKey.GetID(); + + // Store the master key and metadata in the wallet + wallet->mapKeyMetadata[masterPubKey.GetID()] = masterMetadata; + BOOST_CHECK(wallet->AddKeyPubKey(masterKey, masterPubKey)); + BOOST_CHECK(wallet->SetHDMasterKey(masterPubKey)); + + // Derive a new child key using at derivation path (m/0'/3'/0') + CKeyMetadata childMetadata(GetTime()); + CKey childKey; + wallet->DeriveNewChildKey(childMetadata, childKey); + + // Verify the child key is valid + CPubKey childPubKey = childKey.GetPubKey(); + BOOST_CHECK(childKey.IsValid()); + BOOST_CHECK(childPubKey.IsFullyValid()); + + // Verify that the metadata reflects the path "m/0'/3'/0'" + BOOST_CHECK_EQUAL(childMetadata.hdKeypath, "m/0'/3'/0'"); + + // Verify the child public key matches the expected value + std::string derivedPubKeyHex = HexStr(childPubKey.begin(), childPubKey.end()); + BOOST_CHECK_EQUAL(derivedPubKeyHex, expectedPubKeyHex); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 524e44fa4..55ccb1ba8 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -48,6 +48,7 @@ bool fWalletRbf = DEFAULT_WALLET_RBF; const char * DEFAULT_WALLET_DAT = "wallet.dat"; const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; +const uint32_t BIP44_COIN_TYPE = 3; /** * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) @@ -130,12 +131,12 @@ CPubKey CWallet::GenerateNewKey() void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret) { - // for now we use a fixed keypath scheme of m/0'/0'/k + // for now we use a fixed keypath scheme of m/0'/3'/k CKey key; //master key seed (256bit) CExtKey masterKey; //hd master key CExtKey accountKey; //key at m/0' - CExtKey externalChainChildKey; //key at m/0'/0' - CExtKey childKey; //key at m/0'/0'/' + CExtKey externalChainChildKey; //key at m/0'/3' + CExtKey childKey; //key at m/0'/3'/' // try to get the master key if (!GetKey(hdChain.masterKeyID, key)) @@ -147,8 +148,8 @@ void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret) // use hardened derivation (child keys >= 0x80000000 are hardened after bip32) masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT); - // derive m/0'/0' - accountKey.Derive(externalChainChildKey, BIP32_HARDENED_KEY_LIMIT); + // derive m/0'/3' + accountKey.Derive(externalChainChildKey, BIP44_COIN_TYPE | BIP32_HARDENED_KEY_LIMIT); // derive child key at next index, skip keys already known to the wallet do {