LCOV - code coverage report
Current view: top level - src/wallet - hdchain.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 108 130 83.1 %
Date: 2026-06-25 07:23:43 Functions: 16 18 88.9 %

          Line data    Source code
       1             : // Copyright (c) 2014-2025 The Dash Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : 
       4             : #include <wallet/hdchain.h>
       5             : 
       6             : #include <wallet/bip39.h>
       7             : #include <chainparams.h>
       8             : #include <tinyformat.h>
       9             : #include <util/system.h>
      10             : 
      11             : namespace wallet {
      12           0 : bool CHDChain::SetNull()
      13             : {
      14           0 :     LOCK(cs);
      15           0 :     nVersion = CURRENT_VERSION;
      16           0 :     id = uint256();
      17           0 :     fCrypted = false;
      18           0 :     vchSeed.clear();
      19           0 :     vchMnemonic.clear();
      20           0 :     vchMnemonicPassphrase.clear();
      21           0 :     mapAccounts.clear();
      22           0 :     return IsNull();
      23           0 : }
      24             : 
      25      210031 : bool CHDChain::IsNull() const
      26             : {
      27      210031 :     LOCK(cs);
      28      210031 :     return vchSeed.empty() || id == uint256();
      29      210031 : }
      30             : 
      31        1450 : void CHDChain::SetCrypted(bool fCryptedIn)
      32             : {
      33        1450 :     LOCK(cs);
      34        1450 :     fCrypted = fCryptedIn;
      35        1450 : }
      36             : 
      37      147700 : bool CHDChain::IsCrypted() const
      38             : {
      39      147700 :     LOCK(cs);
      40      147700 :     return fCrypted;
      41      147700 : }
      42             : 
      43        1450 : bool CHDChain::SetMnemonic(const SecureVector& vchMnemonic, const SecureVector& vchMnemonicPassphrase, bool fUpdateID)
      44             : {
      45        1450 :     return SetMnemonic(SecureString(vchMnemonic.begin(), vchMnemonic.end()), SecureString(vchMnemonicPassphrase.begin(), vchMnemonicPassphrase.end()), fUpdateID);
      46           0 : }
      47             : 
      48        2068 : bool CHDChain::SetMnemonic(const SecureString& ssMnemonic, const SecureString& ssMnemonicPassphrase, bool fUpdateID)
      49             : {
      50        2068 :     LOCK(cs);
      51        2068 :     SecureString ssMnemonicTmp = ssMnemonic;
      52             : 
      53        2068 :     if (fUpdateID) {
      54             :         // can't (re)set mnemonic if seed was already set
      55         618 :         if (!IsNull())
      56           0 :             return false;
      57             : 
      58         618 :         if (ssMnemonicPassphrase.size() > 256) {
      59           0 :             throw std::runtime_error(std::string(__func__) + ": Mnemonic passphrase is too long, must be at most 256 characters");
      60             :         }
      61             : 
      62             :         // empty mnemonic i.e. "generate a new one"
      63         618 :         if (ssMnemonic.empty()) {
      64         598 :             ssMnemonicTmp = CMnemonic::Generate(gArgs.GetIntArg("-mnemonicbits", DEFAULT_MNEMONIC_BITS));
      65         598 :         }
      66             :         // NOTE: default mnemonic passphrase is an empty string
      67             : 
      68             :         // printf("mnemonic: %s\n", ssMnemonicTmp.c_str());
      69         618 :         if (!CMnemonic::Check(ssMnemonicTmp)) {
      70           0 :             throw std::runtime_error(std::string(__func__) + ": invalid mnemonic: `" + std::string(ssMnemonicTmp) + "`");
      71             :         }
      72             : 
      73         618 :         CMnemonic::ToSeed(ssMnemonicTmp, ssMnemonicPassphrase, vchSeed);
      74         618 :         id = GetSeedHash();
      75         618 :     }
      76             : 
      77        2068 :     vchMnemonic = SecureVector(ssMnemonicTmp.begin(), ssMnemonicTmp.end());
      78        2068 :     vchMnemonicPassphrase = SecureVector(ssMnemonicPassphrase.begin(), ssMnemonicPassphrase.end());
      79             : 
      80        2068 :     return !IsNull();
      81        2068 : }
      82             : 
      83        1450 : bool CHDChain::GetMnemonic(SecureVector& vchMnemonicRet, SecureVector& vchMnemonicPassphraseRet) const
      84             : {
      85        1450 :     LOCK(cs);
      86             :     // mnemonic was not set, fail
      87        1450 :     if (vchMnemonic.empty())
      88           0 :         return false;
      89             : 
      90        1450 :     vchMnemonicRet = vchMnemonic;
      91        1450 :     vchMnemonicPassphraseRet = vchMnemonicPassphrase;
      92        1450 :     return true;
      93        1450 : }
      94             : 
      95          88 : bool CHDChain::GetMnemonic(SecureString& ssMnemonicRet, SecureString& ssMnemonicPassphraseRet) const
      96             : {
      97          88 :     LOCK(cs);
      98             :     // mnemonic was not set, fail
      99          88 :     if (vchMnemonic.empty())
     100           2 :         return false;
     101             : 
     102          86 :     ssMnemonicRet = SecureString(vchMnemonic.begin(), vchMnemonic.end());
     103          86 :     ssMnemonicPassphraseRet = SecureString(vchMnemonicPassphrase.begin(), vchMnemonicPassphrase.end());
     104             : 
     105          86 :     return true;
     106          88 : }
     107             : 
     108        1464 : bool CHDChain::SetSeed(const SecureVector& vchSeedIn, bool fUpdateID)
     109             : {
     110        1464 :     LOCK(cs);
     111        1464 :     vchSeed = vchSeedIn;
     112             : 
     113        1464 :     if (fUpdateID) {
     114          14 :         id = GetSeedHash();
     115          14 :     }
     116             : 
     117        1464 :     return !IsNull();
     118        1464 : }
     119             : 
     120        1867 : SecureVector CHDChain::GetSeed() const
     121             : {
     122        1867 :     LOCK(cs);
     123        1867 :     return vchSeed;
     124        1867 : }
     125             : 
     126       49213 : uint256 CHDChain::GetSeedHash()
     127             : {
     128       49213 :     LOCK(cs);
     129       49213 :     return Hash(vchSeed);
     130       49213 : }
     131             : 
     132             : //! Try to derive an extended key, throw if it fails.
     133      234460 : static void DeriveExtKey(CExtKey& key_in, unsigned int index, CExtKey& key_out)
     134             : {
     135      234460 :     if (!key_in.Derive(key_out, index)) {
     136           0 :         throw std::runtime_error("Could not derive extended key");
     137             :     }
     138      234460 : }
     139             : 
     140       46892 : void CHDChain::DeriveChildExtKey(uint32_t nAccountIndex, bool fInternal, uint32_t nChildIndex, CExtKey& extKeyRet, KeyOriginInfo& key_origin)
     141             : {
     142       46892 :     LOCK(cs);
     143             :     // Use BIP44 keypath scheme i.e. m / purpose' / coin_type' / account' / change / address_index
     144       46892 :     CExtKey masterKey;              //hd master key
     145       46892 :     CExtKey purposeKey;             //key at m/purpose'
     146       46892 :     CExtKey cointypeKey;            //key at m/purpose'/coin_type'
     147       46892 :     CExtKey accountKey;             //key at m/purpose'/coin_type'/account'
     148       46892 :     CExtKey changeKey;              //key at m/purpose'/coin_type'/account'/change
     149       46892 :     CExtKey childKey;               //key at m/purpose'/coin_type'/account'/change/address_index
     150             : 
     151       46892 :     masterKey.SetSeed(MakeByteSpan(vchSeed));
     152             : 
     153             :     // Use hardened derivation for purpose, coin_type and account
     154             :     // (keys >= 0x80000000 are hardened after bip32)
     155             : 
     156             :     // derive m/purpose'
     157       46892 :     DeriveExtKey(masterKey, 44 | 0x80000000, purposeKey);
     158             :     // derive m/purpose'/coin_type'
     159       46892 :     DeriveExtKey(purposeKey, Params().ExtCoinType() | 0x80000000, cointypeKey);
     160             :     // derive m/purpose'/coin_type'/account'
     161       46892 :     DeriveExtKey(cointypeKey, nAccountIndex | 0x80000000, accountKey);
     162             :     // derive m/purpose'/coin_type'/account'/change
     163       46892 :     DeriveExtKey(accountKey, fInternal ? 1 : 0, changeKey);
     164             :     // derive m/purpose'/coin_type'/account'/change/address_index
     165       46892 :     DeriveExtKey(changeKey, nChildIndex, extKeyRet);
     166             : 
     167             : #ifdef ENABLE_WALLET
     168             :     // We should never ever update an already existing key_origin here
     169       46892 :     assert(key_origin.path.empty());
     170       46892 :     key_origin.path.push_back(44 | 0x80000000);
     171       46892 :     key_origin.path.push_back(Params().ExtCoinType() | 0x80000000);
     172       46892 :     key_origin.path.push_back(nAccountIndex | 0x80000000);
     173       46892 :     key_origin.path.push_back(fInternal ? 1 : 0);
     174       46892 :     key_origin.path.push_back(nChildIndex);
     175             : 
     176       46892 :     CKeyID master_id = masterKey.key.GetPubKey().GetID();
     177       46892 :     std::copy(master_id.begin(), master_id.begin() + 4, key_origin.fingerprint);
     178             : #endif
     179       46892 : }
     180             : 
     181         632 : void CHDChain::AddAccount()
     182             : {
     183         632 :     LOCK(cs);
     184         632 :     mapAccounts.insert(std::pair<uint32_t, CHDAccount>(mapAccounts.size(), CHDAccount()));
     185         632 : }
     186             : 
     187       32945 : bool CHDChain::GetAccount(uint32_t nAccountIndex, CHDAccount& hdAccountRet)
     188             : {
     189       32945 :     LOCK(cs);
     190       32945 :     if (nAccountIndex > mapAccounts.size() - 1)
     191           0 :         return false;
     192       32945 :     hdAccountRet = mapAccounts[nAccountIndex];
     193       32945 :     return true;
     194       32945 : }
     195             : 
     196       31845 : bool CHDChain::SetAccount(uint32_t nAccountIndex, const CHDAccount& hdAccount)
     197             : {
     198       31845 :     LOCK(cs);
     199             :     // can only replace existing accounts
     200       31845 :     if (nAccountIndex > mapAccounts.size() - 1)
     201           0 :         return false;
     202       31845 :     mapAccounts[nAccountIndex] = hdAccount;
     203       31845 :     return true;
     204       31845 : }
     205             : 
     206        3262 : size_t CHDChain::CountAccounts()
     207             : {
     208        3262 :     LOCK(cs);
     209        3262 :     return mapAccounts.size();
     210        3262 : }
     211             : 
     212           0 : std::string CHDPubKey::GetKeyPath() const
     213             : {
     214           0 :     return strprintf("m/%d'/%d'/%d'/%d/%d", BIP32_PURPOSE_STANDARD, Params().ExtCoinType(), nAccountIndex, nChangeIndex,
     215           0 :                      extPubKey.nChild);
     216             : }
     217             : } // namespace wallet

Generated by: LCOV version 1.16