dash/src/hdchain.cpp

213 lines
6.6 KiB
C++
Raw Normal View History

// Copyright (c) 2014-2020 The Dash Core developers
HD wallet (#1405) * HD wallet Minimal set of changes (no refactoring) backported from Bitcoin upstream to make HD wallets work in Dash 0.12.1.x+ * minimal bip44 (hardcoded account and change) * minimal bip39 Additional cmd-line options for new wallet: -mnemonic -mnemonicpassphrase * Do not recreate HD wallet on encryption Adjusted keypool.py test * Do not store any private keys for hd wallet besides the master one Derive all keys on the fly. Original idea/implementation - btc PR9298, backported and improved * actually use bip39 * pbkdf2 test * backport wallet-hd.py test * Allow specifying hd seed, add dumphdseed rpc, fix bugs - -hdseed cmd-line param to specify HD seed on wallet creation - dumphdseed rpc to dump HD seed - allow seed of any size - fix dumpwallet rpc bug (wasn't decrypting HD seed) - print HD seed and extended public masterkey on dumpwallet * top up keypool on HD wallet encryption * split HD chain: external/internal * add missing cs_wallet lock in init.cpp * fix `const char *` issues (use strings) * default mnemonic passphrase is an empty string in all cases * store mnemonic/mnemonicpassphrase replace dumphdseed with dumphdinfo * Add fCrypted flag to CHDChain * prepare internal structures for multiple HD accounts (plus some code cleanup) * use secure allocator for storing sensitive HD data * use secure strings for mnemonic(passphrase) * small fix in GenerateNewHDChain * use 24 words for mnemonic by default * make sure mnemonic passphrase provided by user does not exceed 256 symbols * more usage of secure allocators and memory_cleanse * code cleanup * rename: CSecureVector -> SecureVector * add missing include * fix warning in rpcdump.cpp * refactor mnemonic_check (also fix a bug) * move bip39 functions to CMnemonic * Few fixes for CMnemonic: - use `SecureVector` for data, bits, seed - `Check` should return bool * init vectors with desired size where possible
2017-05-29 13:51:40 +02:00
// Distributed under the MIT software license, see the accompanying
Backport 11651 (#3358) * scripted-diff: Replace #include "" with #include <> (ryanofsky) -BEGIN VERIFY SCRIPT- for f in \ src/*.cpp \ src/*.h \ src/bench/*.cpp \ src/bench/*.h \ src/compat/*.cpp \ src/compat/*.h \ src/consensus/*.cpp \ src/consensus/*.h \ src/crypto/*.cpp \ src/crypto/*.h \ src/crypto/ctaes/*.h \ src/policy/*.cpp \ src/policy/*.h \ src/primitives/*.cpp \ src/primitives/*.h \ src/qt/*.cpp \ src/qt/*.h \ src/qt/test/*.cpp \ src/qt/test/*.h \ src/rpc/*.cpp \ src/rpc/*.h \ src/script/*.cpp \ src/script/*.h \ src/support/*.cpp \ src/support/*.h \ src/support/allocators/*.h \ src/test/*.cpp \ src/test/*.h \ src/wallet/*.cpp \ src/wallet/*.h \ src/wallet/test/*.cpp \ src/wallet/test/*.h \ src/zmq/*.cpp \ src/zmq/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * scripted-diff: Replace #include "" with #include <> (Dash Specific) -BEGIN VERIFY SCRIPT- for f in \ src/bls/*.cpp \ src/bls/*.h \ src/evo/*.cpp \ src/evo/*.h \ src/governance/*.cpp \ src/governance/*.h \ src/llmq/*.cpp \ src/llmq/*.h \ src/masternode/*.cpp \ src/masternode/*.h \ src/privatesend/*.cpp \ src/privatesend/*.h do base=${f%/*}/ relbase=${base#src/} sed -i "s:#include \"\(.*\)\"\(.*\):if test -e \$base'\\1'; then echo \"#include <\"\$relbase\"\\1>\\2\"; else echo \"#include <\\1>\\2\"; fi:e" $f done -END VERIFY SCRIPT- Signed-off-by: Pasta <pasta@dashboost.org> * build: Remove -I for everything but project root Remove -I from build system for everything but the project root, and built-in dependencies. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/Makefile.test.include * qt: refactor: Use absolute include paths in .ui files * qt: refactor: Changes to make include paths absolute This makes all include paths in the GUI absolute. Many changes are involved as every single source file in src/qt/ assumes to be able to use relative includes. Signed-off-by: Pasta <pasta@dashboost.org> # Conflicts: # src/qt/dash.cpp # src/qt/optionsmodel.cpp # src/qt/test/rpcnestedtests.cpp * test: refactor: Use absolute include paths for test data files * Recommend #include<> syntax in developer notes * refactor: Include obj/build.h instead of build.h * END BACKPORT #11651 Remove trailing whitespace causing travis failure * fix backport 11651 Signed-off-by: Pasta <pasta@dashboost.org> * More of 11651 * fix blockchain.cpp Signed-off-by: pasta <pasta@dashboost.org> * Add missing "qt/" in includes * Add missing "test/" in includes * Fix trailing whitespaces Co-authored-by: Wladimir J. van der Laan <laanwj@gmail.com> Co-authored-by: Russell Yanofsky <russ@yanofsky.org> Co-authored-by: MeshCollider <dobsonsa68@gmail.com> Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
2020-03-19 23:46:56 +01:00
#include <base58.h>
#include <bip39.h>
#include <chainparams.h>
#include <hdchain.h>
#include <tinyformat.h>
#include <util.h>
#include <utilstrencodings.h>
HD wallet (#1405) * HD wallet Minimal set of changes (no refactoring) backported from Bitcoin upstream to make HD wallets work in Dash 0.12.1.x+ * minimal bip44 (hardcoded account and change) * minimal bip39 Additional cmd-line options for new wallet: -mnemonic -mnemonicpassphrase * Do not recreate HD wallet on encryption Adjusted keypool.py test * Do not store any private keys for hd wallet besides the master one Derive all keys on the fly. Original idea/implementation - btc PR9298, backported and improved * actually use bip39 * pbkdf2 test * backport wallet-hd.py test * Allow specifying hd seed, add dumphdseed rpc, fix bugs - -hdseed cmd-line param to specify HD seed on wallet creation - dumphdseed rpc to dump HD seed - allow seed of any size - fix dumpwallet rpc bug (wasn't decrypting HD seed) - print HD seed and extended public masterkey on dumpwallet * top up keypool on HD wallet encryption * split HD chain: external/internal * add missing cs_wallet lock in init.cpp * fix `const char *` issues (use strings) * default mnemonic passphrase is an empty string in all cases * store mnemonic/mnemonicpassphrase replace dumphdseed with dumphdinfo * Add fCrypted flag to CHDChain * prepare internal structures for multiple HD accounts (plus some code cleanup) * use secure allocator for storing sensitive HD data * use secure strings for mnemonic(passphrase) * small fix in GenerateNewHDChain * use 24 words for mnemonic by default * make sure mnemonic passphrase provided by user does not exceed 256 symbols * more usage of secure allocators and memory_cleanse * code cleanup * rename: CSecureVector -> SecureVector * add missing include * fix warning in rpcdump.cpp * refactor mnemonic_check (also fix a bug) * move bip39 functions to CMnemonic * Few fixes for CMnemonic: - use `SecureVector` for data, bits, seed - `Check` should return bool * init vectors with desired size where possible
2017-05-29 13:51:40 +02:00
bool CHDChain::SetNull()
{
LOCK(cs_accounts);
nVersion = CURRENT_VERSION;
id = uint256();
fCrypted = false;
vchSeed.clear();
vchMnemonic.clear();
vchMnemonicPassphrase.clear();
mapAccounts.clear();
// default blank account
mapAccounts.insert(std::pair<uint32_t, CHDAccount>(0, CHDAccount()));
return IsNull();
}
bool CHDChain::IsNull() const
{
return vchSeed.empty() || id == uint256();
}
void CHDChain::SetCrypted(bool fCryptedIn)
{
fCrypted = fCryptedIn;
}
bool CHDChain::IsCrypted() const
{
return fCrypted;
}
void CHDChain::Debug(const std::string& strName) const
HD wallet (#1405) * HD wallet Minimal set of changes (no refactoring) backported from Bitcoin upstream to make HD wallets work in Dash 0.12.1.x+ * minimal bip44 (hardcoded account and change) * minimal bip39 Additional cmd-line options for new wallet: -mnemonic -mnemonicpassphrase * Do not recreate HD wallet on encryption Adjusted keypool.py test * Do not store any private keys for hd wallet besides the master one Derive all keys on the fly. Original idea/implementation - btc PR9298, backported and improved * actually use bip39 * pbkdf2 test * backport wallet-hd.py test * Allow specifying hd seed, add dumphdseed rpc, fix bugs - -hdseed cmd-line param to specify HD seed on wallet creation - dumphdseed rpc to dump HD seed - allow seed of any size - fix dumpwallet rpc bug (wasn't decrypting HD seed) - print HD seed and extended public masterkey on dumpwallet * top up keypool on HD wallet encryption * split HD chain: external/internal * add missing cs_wallet lock in init.cpp * fix `const char *` issues (use strings) * default mnemonic passphrase is an empty string in all cases * store mnemonic/mnemonicpassphrase replace dumphdseed with dumphdinfo * Add fCrypted flag to CHDChain * prepare internal structures for multiple HD accounts (plus some code cleanup) * use secure allocator for storing sensitive HD data * use secure strings for mnemonic(passphrase) * small fix in GenerateNewHDChain * use 24 words for mnemonic by default * make sure mnemonic passphrase provided by user does not exceed 256 symbols * more usage of secure allocators and memory_cleanse * code cleanup * rename: CSecureVector -> SecureVector * add missing include * fix warning in rpcdump.cpp * refactor mnemonic_check (also fix a bug) * move bip39 functions to CMnemonic * Few fixes for CMnemonic: - use `SecureVector` for data, bits, seed - `Check` should return bool * init vectors with desired size where possible
2017-05-29 13:51:40 +02:00
{
DBG(
std::cout << __func__ << ": ---" << strName << "---" << std::endl;
if (fCrypted) {
std::cout << "mnemonic: ***CRYPTED***" << std::endl;
std::cout << "mnemonicpassphrase: ***CRYPTED***" << std::endl;
std::cout << "seed: ***CRYPTED***" << std::endl;
} else {
std::cout << "mnemonic: " << std::string(vchMnemonic.begin(), vchMnemonic.end()).c_str() << std::endl;
std::cout << "mnemonicpassphrase: " << std::string(vchMnemonicPassphrase.begin(), vchMnemonicPassphrase.end()).c_str() << std::endl;
std::cout << "seed: " << HexStr(vchSeed).c_str() << std::endl;
CExtKey extkey;
2020-01-05 03:00:36 +01:00
extkey.SetMaster(vchSeed.data(), vchSeed.size());
HD wallet (#1405) * HD wallet Minimal set of changes (no refactoring) backported from Bitcoin upstream to make HD wallets work in Dash 0.12.1.x+ * minimal bip44 (hardcoded account and change) * minimal bip39 Additional cmd-line options for new wallet: -mnemonic -mnemonicpassphrase * Do not recreate HD wallet on encryption Adjusted keypool.py test * Do not store any private keys for hd wallet besides the master one Derive all keys on the fly. Original idea/implementation - btc PR9298, backported and improved * actually use bip39 * pbkdf2 test * backport wallet-hd.py test * Allow specifying hd seed, add dumphdseed rpc, fix bugs - -hdseed cmd-line param to specify HD seed on wallet creation - dumphdseed rpc to dump HD seed - allow seed of any size - fix dumpwallet rpc bug (wasn't decrypting HD seed) - print HD seed and extended public masterkey on dumpwallet * top up keypool on HD wallet encryption * split HD chain: external/internal * add missing cs_wallet lock in init.cpp * fix `const char *` issues (use strings) * default mnemonic passphrase is an empty string in all cases * store mnemonic/mnemonicpassphrase replace dumphdseed with dumphdinfo * Add fCrypted flag to CHDChain * prepare internal structures for multiple HD accounts (plus some code cleanup) * use secure allocator for storing sensitive HD data * use secure strings for mnemonic(passphrase) * small fix in GenerateNewHDChain * use 24 words for mnemonic by default * make sure mnemonic passphrase provided by user does not exceed 256 symbols * more usage of secure allocators and memory_cleanse * code cleanup * rename: CSecureVector -> SecureVector * add missing include * fix warning in rpcdump.cpp * refactor mnemonic_check (also fix a bug) * move bip39 functions to CMnemonic * Few fixes for CMnemonic: - use `SecureVector` for data, bits, seed - `Check` should return bool * init vectors with desired size where possible
2017-05-29 13:51:40 +02:00
CBitcoinExtKey b58extkey;
b58extkey.SetKey(extkey);
std::cout << "extended private masterkey: " << b58extkey.ToString().c_str() << std::endl;
CExtPubKey extpubkey;
extpubkey = extkey.Neuter();
CBitcoinExtPubKey b58extpubkey;
b58extpubkey.SetKey(extpubkey);
std::cout << "extended public masterkey: " << b58extpubkey.ToString().c_str() << std::endl;
}
);
}
bool CHDChain::SetMnemonic(const SecureVector& vchMnemonic, const SecureVector& vchMnemonicPassphrase, bool fUpdateID)
{
return SetMnemonic(SecureString(vchMnemonic.begin(), vchMnemonic.end()), SecureString(vchMnemonicPassphrase.begin(), vchMnemonicPassphrase.end()), fUpdateID);
}
bool CHDChain::SetMnemonic(const SecureString& ssMnemonic, const SecureString& ssMnemonicPassphrase, bool fUpdateID)
{
SecureString ssMnemonicTmp = ssMnemonic;
if (fUpdateID) {
// can't (re)set mnemonic if seed was already set
if (!IsNull())
return false;
// empty mnemonic i.e. "generate a new one"
if (ssMnemonic.empty()) {
ssMnemonicTmp = CMnemonic::Generate(256);
}
// NOTE: default mnemonic passphrase is an empty string
// printf("mnemonic: %s\n", ssMnemonicTmp.c_str());
if (!CMnemonic::Check(ssMnemonicTmp)) {
throw std::runtime_error(std::string(__func__) + ": invalid mnemonic: `" + std::string(ssMnemonicTmp.c_str()) + "`");
}
CMnemonic::ToSeed(ssMnemonicTmp, ssMnemonicPassphrase, vchSeed);
id = GetSeedHash();
}
vchMnemonic = SecureVector(ssMnemonicTmp.begin(), ssMnemonicTmp.end());
vchMnemonicPassphrase = SecureVector(ssMnemonicPassphrase.begin(), ssMnemonicPassphrase.end());
return !IsNull();
}
bool CHDChain::GetMnemonic(SecureVector& vchMnemonicRet, SecureVector& vchMnemonicPassphraseRet) const
{
// mnemonic was not set, fail
if (vchMnemonic.empty())
return false;
vchMnemonicRet = vchMnemonic;
vchMnemonicPassphraseRet = vchMnemonicPassphrase;
return true;
}
bool CHDChain::GetMnemonic(SecureString& ssMnemonicRet, SecureString& ssMnemonicPassphraseRet) const
{
// mnemonic was not set, fail
if (vchMnemonic.empty())
return false;
ssMnemonicRet = SecureString(vchMnemonic.begin(), vchMnemonic.end());
ssMnemonicPassphraseRet = SecureString(vchMnemonicPassphrase.begin(), vchMnemonicPassphrase.end());
return true;
}
bool CHDChain::SetSeed(const SecureVector& vchSeedIn, bool fUpdateID)
{
vchSeed = vchSeedIn;
if (fUpdateID) {
id = GetSeedHash();
}
return !IsNull();
}
SecureVector CHDChain::GetSeed() const
{
return vchSeed;
}
uint256 CHDChain::GetSeedHash()
{
return Hash(vchSeed.begin(), vchSeed.end());
}
void CHDChain::DeriveChildExtKey(uint32_t nAccountIndex, bool fInternal, uint32_t nChildIndex, CExtKey& extKeyRet)
{
// Use BIP44 keypath scheme i.e. m / purpose' / coin_type' / account' / change / address_index
CExtKey masterKey; //hd master key
CExtKey purposeKey; //key at m/purpose'
CExtKey cointypeKey; //key at m/purpose'/coin_type'
CExtKey accountKey; //key at m/purpose'/coin_type'/account'
CExtKey changeKey; //key at m/purpose'/coin_type'/account'/change
CExtKey childKey; //key at m/purpose'/coin_type'/account'/change/address_index
2020-01-05 03:00:36 +01:00
masterKey.SetMaster(vchSeed.data(), vchSeed.size());
HD wallet (#1405) * HD wallet Minimal set of changes (no refactoring) backported from Bitcoin upstream to make HD wallets work in Dash 0.12.1.x+ * minimal bip44 (hardcoded account and change) * minimal bip39 Additional cmd-line options for new wallet: -mnemonic -mnemonicpassphrase * Do not recreate HD wallet on encryption Adjusted keypool.py test * Do not store any private keys for hd wallet besides the master one Derive all keys on the fly. Original idea/implementation - btc PR9298, backported and improved * actually use bip39 * pbkdf2 test * backport wallet-hd.py test * Allow specifying hd seed, add dumphdseed rpc, fix bugs - -hdseed cmd-line param to specify HD seed on wallet creation - dumphdseed rpc to dump HD seed - allow seed of any size - fix dumpwallet rpc bug (wasn't decrypting HD seed) - print HD seed and extended public masterkey on dumpwallet * top up keypool on HD wallet encryption * split HD chain: external/internal * add missing cs_wallet lock in init.cpp * fix `const char *` issues (use strings) * default mnemonic passphrase is an empty string in all cases * store mnemonic/mnemonicpassphrase replace dumphdseed with dumphdinfo * Add fCrypted flag to CHDChain * prepare internal structures for multiple HD accounts (plus some code cleanup) * use secure allocator for storing sensitive HD data * use secure strings for mnemonic(passphrase) * small fix in GenerateNewHDChain * use 24 words for mnemonic by default * make sure mnemonic passphrase provided by user does not exceed 256 symbols * more usage of secure allocators and memory_cleanse * code cleanup * rename: CSecureVector -> SecureVector * add missing include * fix warning in rpcdump.cpp * refactor mnemonic_check (also fix a bug) * move bip39 functions to CMnemonic * Few fixes for CMnemonic: - use `SecureVector` for data, bits, seed - `Check` should return bool * init vectors with desired size where possible
2017-05-29 13:51:40 +02:00
// Use hardened derivation for purpose, coin_type and account
// (keys >= 0x80000000 are hardened after bip32)
// derive m/purpose'
masterKey.Derive(purposeKey, 44 | 0x80000000);
// derive m/purpose'/coin_type'
purposeKey.Derive(cointypeKey, Params().ExtCoinType() | 0x80000000);
// derive m/purpose'/coin_type'/account'
cointypeKey.Derive(accountKey, nAccountIndex | 0x80000000);
// derive m/purpose'/coin_type'/account'/change
HD wallet (#1405) * HD wallet Minimal set of changes (no refactoring) backported from Bitcoin upstream to make HD wallets work in Dash 0.12.1.x+ * minimal bip44 (hardcoded account and change) * minimal bip39 Additional cmd-line options for new wallet: -mnemonic -mnemonicpassphrase * Do not recreate HD wallet on encryption Adjusted keypool.py test * Do not store any private keys for hd wallet besides the master one Derive all keys on the fly. Original idea/implementation - btc PR9298, backported and improved * actually use bip39 * pbkdf2 test * backport wallet-hd.py test * Allow specifying hd seed, add dumphdseed rpc, fix bugs - -hdseed cmd-line param to specify HD seed on wallet creation - dumphdseed rpc to dump HD seed - allow seed of any size - fix dumpwallet rpc bug (wasn't decrypting HD seed) - print HD seed and extended public masterkey on dumpwallet * top up keypool on HD wallet encryption * split HD chain: external/internal * add missing cs_wallet lock in init.cpp * fix `const char *` issues (use strings) * default mnemonic passphrase is an empty string in all cases * store mnemonic/mnemonicpassphrase replace dumphdseed with dumphdinfo * Add fCrypted flag to CHDChain * prepare internal structures for multiple HD accounts (plus some code cleanup) * use secure allocator for storing sensitive HD data * use secure strings for mnemonic(passphrase) * small fix in GenerateNewHDChain * use 24 words for mnemonic by default * make sure mnemonic passphrase provided by user does not exceed 256 symbols * more usage of secure allocators and memory_cleanse * code cleanup * rename: CSecureVector -> SecureVector * add missing include * fix warning in rpcdump.cpp * refactor mnemonic_check (also fix a bug) * move bip39 functions to CMnemonic * Few fixes for CMnemonic: - use `SecureVector` for data, bits, seed - `Check` should return bool * init vectors with desired size where possible
2017-05-29 13:51:40 +02:00
accountKey.Derive(changeKey, fInternal ? 1 : 0);
// derive m/purpose'/coin_type'/account'/change/address_index
HD wallet (#1405) * HD wallet Minimal set of changes (no refactoring) backported from Bitcoin upstream to make HD wallets work in Dash 0.12.1.x+ * minimal bip44 (hardcoded account and change) * minimal bip39 Additional cmd-line options for new wallet: -mnemonic -mnemonicpassphrase * Do not recreate HD wallet on encryption Adjusted keypool.py test * Do not store any private keys for hd wallet besides the master one Derive all keys on the fly. Original idea/implementation - btc PR9298, backported and improved * actually use bip39 * pbkdf2 test * backport wallet-hd.py test * Allow specifying hd seed, add dumphdseed rpc, fix bugs - -hdseed cmd-line param to specify HD seed on wallet creation - dumphdseed rpc to dump HD seed - allow seed of any size - fix dumpwallet rpc bug (wasn't decrypting HD seed) - print HD seed and extended public masterkey on dumpwallet * top up keypool on HD wallet encryption * split HD chain: external/internal * add missing cs_wallet lock in init.cpp * fix `const char *` issues (use strings) * default mnemonic passphrase is an empty string in all cases * store mnemonic/mnemonicpassphrase replace dumphdseed with dumphdinfo * Add fCrypted flag to CHDChain * prepare internal structures for multiple HD accounts (plus some code cleanup) * use secure allocator for storing sensitive HD data * use secure strings for mnemonic(passphrase) * small fix in GenerateNewHDChain * use 24 words for mnemonic by default * make sure mnemonic passphrase provided by user does not exceed 256 symbols * more usage of secure allocators and memory_cleanse * code cleanup * rename: CSecureVector -> SecureVector * add missing include * fix warning in rpcdump.cpp * refactor mnemonic_check (also fix a bug) * move bip39 functions to CMnemonic * Few fixes for CMnemonic: - use `SecureVector` for data, bits, seed - `Check` should return bool * init vectors with desired size where possible
2017-05-29 13:51:40 +02:00
changeKey.Derive(extKeyRet, nChildIndex);
}
void CHDChain::AddAccount()
{
LOCK(cs_accounts);
mapAccounts.insert(std::pair<uint32_t, CHDAccount>(mapAccounts.size(), CHDAccount()));
}
bool CHDChain::GetAccount(uint32_t nAccountIndex, CHDAccount& hdAccountRet)
{
LOCK(cs_accounts);
if (nAccountIndex > mapAccounts.size() - 1)
return false;
hdAccountRet = mapAccounts[nAccountIndex];
return true;
}
bool CHDChain::SetAccount(uint32_t nAccountIndex, const CHDAccount& hdAccount)
{
LOCK(cs_accounts);
// can only replace existing accounts
if (nAccountIndex > mapAccounts.size() - 1)
return false;
mapAccounts[nAccountIndex] = hdAccount;
return true;
}
size_t CHDChain::CountAccounts()
{
LOCK(cs_accounts);
return mapAccounts.size();
}
std::string CHDPubKey::GetKeyPath() const
{
return strprintf("m/44'/%d'/%d'/%d/%d", Params().ExtCoinType(), nAccountIndex, nChangeIndex, extPubKey.nChild);
}