From cd01b2d9bf591a3c863de3bb1346f7735df914d7 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 1 Nov 2021 20:55:31 -0600 Subject: [PATCH] Fix transparent BIP-44 keypaths. --- src/wallet/wallet.cpp | 2 +- src/zcash/address/zip32.cpp | 32 ++++++++++++++++---------------- src/zcash/address/zip32.h | 11 +++-------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5dabde9fe..539ae3009 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -274,7 +274,7 @@ CPubKey CWallet::GenerateNewKey() // All mnemonic seeds are checked at construction to ensure that we can obtain // a valid spending key for the account ZCASH_LEGACY_ACCOUNT; // therefore, the `value()` call here is safe. - BIP32AccountChains accountChains = BIP32AccountChains::ForAccount( + Bip44AccountChains accountChains = Bip44AccountChains::ForAccount( seed, BIP44CoinType(), ZCASH_LEGACY_ACCOUNT).value(); diff --git a/src/zcash/address/zip32.cpp b/src/zcash/address/zip32.cpp index 19686b4f7..b0030f452 100644 --- a/src/zcash/address/zip32.cpp +++ b/src/zcash/address/zip32.cpp @@ -39,7 +39,7 @@ MnemonicSeed MnemonicSeed::Random(uint32_t bip44CoinType, Language language, siz // for a valid diversifier; unlike in the unified spending key case, diversifier // indices don't need to line up with anything. if (libzcash::UnifiedSpendingKey::ForAccount(seed, bip44CoinType, 0).has_value() && - libzcash::BIP32AccountChains::ForAccount(seed, bip44CoinType, ZCASH_LEGACY_ACCOUNT).has_value()) { + libzcash::Bip44AccountChains::ForAccount(seed, bip44CoinType, ZCASH_LEGACY_ACCOUNT).has_value()) { return seed; } } @@ -76,33 +76,33 @@ namespace libzcash { // Transparent // -std::optional> DeriveZip32TransparentAccountKey(const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId) { +std::optional> DeriveBip44TransparentAccountKey(const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId) { auto rawSeed = seed.RawSeed(); auto m = CExtKey::Master(rawSeed.data(), rawSeed.size()); - // We use a fixed keypath scheme of m/32'/coin_type'/account' - // Derive m/32' - auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT); + // We use a fixed keypath scheme of m/44'/coin_type'/account' + // Derive m/44' + auto m_32h = m.Derive(44 | ZIP32_HARDENED_KEY_LIMIT); if (!m_32h.has_value()) return std::nullopt; - // Derive m/32'/coin_type' + // Derive m/44'/coin_type' auto m_32h_cth = m_32h.value().Derive(bip44CoinType | ZIP32_HARDENED_KEY_LIMIT); if (!m_32h_cth.has_value()) return std::nullopt; - // Derive m/32'/coin_type'/account_id' + // Derive m/44'/coin_type'/account_id' auto result = m_32h_cth.value().Derive(accountId | ZIP32_HARDENED_KEY_LIMIT); if (!result.has_value()) return std::nullopt; - auto hdKeypath = "m/32'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(accountId) + "'"; + auto hdKeypath = "m/44'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(accountId) + "'"; return std::make_pair(result.value(), hdKeypath); } -std::optional BIP32AccountChains::ForAccount( +std::optional Bip44AccountChains::ForAccount( const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId) { - auto accountKeyOpt = DeriveZip32TransparentAccountKey(seed, bip44CoinType, accountId); + auto accountKeyOpt = DeriveBip44TransparentAccountKey(seed, bip44CoinType, accountId); if (!accountKeyOpt.has_value()) return std::nullopt; auto accountKey = accountKeyOpt.value(); @@ -111,14 +111,14 @@ std::optional BIP32AccountChains::ForAccount( if (!(external.has_value() && internal.has_value())) return std::nullopt; - return BIP32AccountChains(seed.Fingerprint(), bip44CoinType, accountId, external.value(), internal.value()); + return Bip44AccountChains(seed.Fingerprint(), bip44CoinType, accountId, external.value(), internal.value()); } -std::optional> BIP32AccountChains::DeriveExternal(uint32_t addrIndex) { +std::optional> Bip44AccountChains::DeriveExternal(uint32_t addrIndex) { auto childKey = external.Derive(addrIndex); if (!childKey.has_value()) return std::nullopt; - auto hdKeypath = "m/32'/" + auto hdKeypath = "m/44'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(accountId) + "'/" + "0/" @@ -127,11 +127,11 @@ std::optional> BIP32AccountChains::DeriveExternal( return std::make_pair(childKey.value(), hdKeypath); } -std::optional> BIP32AccountChains::DeriveInternal(uint32_t addrIndex) { +std::optional> Bip44AccountChains::DeriveInternal(uint32_t addrIndex) { auto childKey = internal.Derive(addrIndex); if (!childKey.has_value()) return std::nullopt; - auto hdKeypath = "m/32'/" + auto hdKeypath = "m/44'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(accountId) + "'/" + "1/" @@ -305,7 +305,7 @@ std::optional> UnifiedSpendingKey::ForA UnifiedSpendingKey usk; usk.accountId = accountId; - auto transparentKey = DeriveZip32TransparentAccountKey(seed, bip44CoinType, accountId); + auto transparentKey = DeriveBip44TransparentAccountKey(seed, bip44CoinType, accountId); if (!transparentKey.has_value()) return std::nullopt; usk.transparentKey = transparentKey.value().first; diff --git a/src/zcash/address/zip32.h b/src/zcash/address/zip32.h index 6b97ccb6d..16394a6eb 100644 --- a/src/zcash/address/zip32.h +++ b/src/zcash/address/zip32.h @@ -384,12 +384,7 @@ public: std::optional ParseZip32KeypathAccount(const std::string& keyPath); -std::optional> DeriveZip32TransparentMasterKey( - const HDSeed& seed, - uint32_t bip44CoinType, - uint32_t accountId); - -class BIP32AccountChains { +class Bip44AccountChains { private: uint256 seedFp; uint32_t accountId; @@ -397,10 +392,10 @@ private: CExtKey external; CExtKey internal; - BIP32AccountChains(uint256 seedFpIn, uint32_t bip44CoinTypeIn, uint32_t accountIdIn, CExtKey externalIn, CExtKey internalIn): + Bip44AccountChains(uint256 seedFpIn, uint32_t bip44CoinTypeIn, uint32_t accountIdIn, CExtKey externalIn, CExtKey internalIn): seedFp(seedFpIn), accountId(accountIdIn), bip44CoinType(bip44CoinTypeIn), external(externalIn), internal(internalIn) {} public: - static std::optional ForAccount( + static std::optional ForAccount( const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId);