LCOV - code coverage report
Current view: top level - src/wallet - hdchain.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 4 130 3.1 %
Date: 2026-06-25 07:23:51 Functions: 1 18 5.6 %

          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       22314 : bool CHDChain::IsNull() const
      26             : {
      27       22314 :     LOCK(cs);
      28       22314 :     return vchSeed.empty() || id == uint256();
      29       22314 : }
      30             : 
      31           0 : void CHDChain::SetCrypted(bool fCryptedIn)
      32             : {
      33           0 :     LOCK(cs);
      34           0 :     fCrypted = fCryptedIn;
      35           0 : }
      36             : 
      37           0 : bool CHDChain::IsCrypted() const
      38             : {
      39           0 :     LOCK(cs);
      40           0 :     return fCrypted;
      41           0 : }
      42             : 
      43           0 : bool CHDChain::SetMnemonic(const SecureVector& vchMnemonic, const SecureVector& vchMnemonicPassphrase, bool fUpdateID)
      44             : {
      45           0 :     return SetMnemonic(SecureString(vchMnemonic.begin(), vchMnemonic.end()), SecureString(vchMnemonicPassphrase.begin(), vchMnemonicPassphrase.end()), fUpdateID);
      46           0 : }
      47             : 
      48           0 : bool CHDChain::SetMnemonic(const SecureString& ssMnemonic, const SecureString& ssMnemonicPassphrase, bool fUpdateID)
      49             : {
      50           0 :     LOCK(cs);
      51           0 :     SecureString ssMnemonicTmp = ssMnemonic;
      52             : 
      53           0 :     if (fUpdateID) {
      54             :         // can't (re)set mnemonic if seed was already set
      55           0 :         if (!IsNull())
      56           0 :             return false;
      57             : 
      58           0 :         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           0 :         if (ssMnemonic.empty()) {
      64           0 :             ssMnemonicTmp = CMnemonic::Generate(gArgs.GetIntArg("-mnemonicbits", DEFAULT_MNEMONIC_BITS));
      65           0 :         }
      66             :         // NOTE: default mnemonic passphrase is an empty string
      67             : 
      68             :         // printf("mnemonic: %s\n", ssMnemonicTmp.c_str());
      69           0 :         if (!CMnemonic::Check(ssMnemonicTmp)) {
      70           0 :             throw std::runtime_error(std::string(__func__) + ": invalid mnemonic: `" + std::string(ssMnemonicTmp) + "`");
      71             :         }
      72             : 
      73           0 :         CMnemonic::ToSeed(ssMnemonicTmp, ssMnemonicPassphrase, vchSeed);
      74           0 :         id = GetSeedHash();
      75           0 :     }
      76             : 
      77           0 :     vchMnemonic = SecureVector(ssMnemonicTmp.begin(), ssMnemonicTmp.end());
      78           0 :     vchMnemonicPassphrase = SecureVector(ssMnemonicPassphrase.begin(), ssMnemonicPassphrase.end());
      79             : 
      80           0 :     return !IsNull();
      81           0 : }
      82             : 
      83           0 : bool CHDChain::GetMnemonic(SecureVector& vchMnemonicRet, SecureVector& vchMnemonicPassphraseRet) const
      84             : {
      85           0 :     LOCK(cs);
      86             :     // mnemonic was not set, fail
      87           0 :     if (vchMnemonic.empty())
      88           0 :         return false;
      89             : 
      90           0 :     vchMnemonicRet = vchMnemonic;
      91           0 :     vchMnemonicPassphraseRet = vchMnemonicPassphrase;
      92           0 :     return true;
      93           0 : }
      94             : 
      95           0 : bool CHDChain::GetMnemonic(SecureString& ssMnemonicRet, SecureString& ssMnemonicPassphraseRet) const
      96             : {
      97           0 :     LOCK(cs);
      98             :     // mnemonic was not set, fail
      99           0 :     if (vchMnemonic.empty())
     100           0 :         return false;
     101             : 
     102           0 :     ssMnemonicRet = SecureString(vchMnemonic.begin(), vchMnemonic.end());
     103           0 :     ssMnemonicPassphraseRet = SecureString(vchMnemonicPassphrase.begin(), vchMnemonicPassphrase.end());
     104             : 
     105           0 :     return true;
     106           0 : }
     107             : 
     108           0 : bool CHDChain::SetSeed(const SecureVector& vchSeedIn, bool fUpdateID)
     109             : {
     110           0 :     LOCK(cs);
     111           0 :     vchSeed = vchSeedIn;
     112             : 
     113           0 :     if (fUpdateID) {
     114           0 :         id = GetSeedHash();
     115           0 :     }
     116             : 
     117           0 :     return !IsNull();
     118           0 : }
     119             : 
     120           0 : SecureVector CHDChain::GetSeed() const
     121             : {
     122           0 :     LOCK(cs);
     123           0 :     return vchSeed;
     124           0 : }
     125             : 
     126           0 : uint256 CHDChain::GetSeedHash()
     127             : {
     128           0 :     LOCK(cs);
     129           0 :     return Hash(vchSeed);
     130           0 : }
     131             : 
     132             : //! Try to derive an extended key, throw if it fails.
     133           0 : static void DeriveExtKey(CExtKey& key_in, unsigned int index, CExtKey& key_out)
     134             : {
     135           0 :     if (!key_in.Derive(key_out, index)) {
     136           0 :         throw std::runtime_error("Could not derive extended key");
     137             :     }
     138           0 : }
     139             : 
     140           0 : void CHDChain::DeriveChildExtKey(uint32_t nAccountIndex, bool fInternal, uint32_t nChildIndex, CExtKey& extKeyRet, KeyOriginInfo& key_origin)
     141             : {
     142           0 :     LOCK(cs);
     143             :     // Use BIP44 keypath scheme i.e. m / purpose' / coin_type' / account' / change / address_index
     144           0 :     CExtKey masterKey;              //hd master key
     145           0 :     CExtKey purposeKey;             //key at m/purpose'
     146           0 :     CExtKey cointypeKey;            //key at m/purpose'/coin_type'
     147           0 :     CExtKey accountKey;             //key at m/purpose'/coin_type'/account'
     148           0 :     CExtKey changeKey;              //key at m/purpose'/coin_type'/account'/change
     149           0 :     CExtKey childKey;               //key at m/purpose'/coin_type'/account'/change/address_index
     150             : 
     151           0 :     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           0 :     DeriveExtKey(masterKey, 44 | 0x80000000, purposeKey);
     158             :     // derive m/purpose'/coin_type'
     159           0 :     DeriveExtKey(purposeKey, Params().ExtCoinType() | 0x80000000, cointypeKey);
     160             :     // derive m/purpose'/coin_type'/account'
     161           0 :     DeriveExtKey(cointypeKey, nAccountIndex | 0x80000000, accountKey);
     162             :     // derive m/purpose'/coin_type'/account'/change
     163           0 :     DeriveExtKey(accountKey, fInternal ? 1 : 0, changeKey);
     164             :     // derive m/purpose'/coin_type'/account'/change/address_index
     165           0 :     DeriveExtKey(changeKey, nChildIndex, extKeyRet);
     166             : 
     167             : #ifdef ENABLE_WALLET
     168             :     // We should never ever update an already existing key_origin here
     169           0 :     assert(key_origin.path.empty());
     170           0 :     key_origin.path.push_back(44 | 0x80000000);
     171           0 :     key_origin.path.push_back(Params().ExtCoinType() | 0x80000000);
     172           0 :     key_origin.path.push_back(nAccountIndex | 0x80000000);
     173           0 :     key_origin.path.push_back(fInternal ? 1 : 0);
     174           0 :     key_origin.path.push_back(nChildIndex);
     175             : 
     176           0 :     CKeyID master_id = masterKey.key.GetPubKey().GetID();
     177           0 :     std::copy(master_id.begin(), master_id.begin() + 4, key_origin.fingerprint);
     178             : #endif
     179           0 : }
     180             : 
     181           0 : void CHDChain::AddAccount()
     182             : {
     183           0 :     LOCK(cs);
     184           0 :     mapAccounts.insert(std::pair<uint32_t, CHDAccount>(mapAccounts.size(), CHDAccount()));
     185           0 : }
     186             : 
     187           0 : bool CHDChain::GetAccount(uint32_t nAccountIndex, CHDAccount& hdAccountRet)
     188             : {
     189           0 :     LOCK(cs);
     190           0 :     if (nAccountIndex > mapAccounts.size() - 1)
     191           0 :         return false;
     192           0 :     hdAccountRet = mapAccounts[nAccountIndex];
     193           0 :     return true;
     194           0 : }
     195             : 
     196           0 : bool CHDChain::SetAccount(uint32_t nAccountIndex, const CHDAccount& hdAccount)
     197             : {
     198           0 :     LOCK(cs);
     199             :     // can only replace existing accounts
     200           0 :     if (nAccountIndex > mapAccounts.size() - 1)
     201           0 :         return false;
     202           0 :     mapAccounts[nAccountIndex] = hdAccount;
     203           0 :     return true;
     204           0 : }
     205             : 
     206           0 : size_t CHDChain::CountAccounts()
     207             : {
     208           0 :     LOCK(cs);
     209           0 :     return mapAccounts.size();
     210           0 : }
     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