mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-07-18 11:00:36 +02:00
migrate: Handle HD chains that have identical seeds but different IDs
The seed ID is calculated from a pubkey produced by treating the seed as a private key. This calculation includes a pubkey compression parameter, even thought that compression is completely irrelevant for the usage of the seed as a BIP 32 seed. Thus migration should detect if a seed has been used multiple times by checking if the computed master key was already processed. The spkm_migration fuzzer needs to have it's added descriptors accounting to be updated for this fix.
This commit is contained in:
@@ -628,19 +628,28 @@ std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor()
|
|||||||
|
|
||||||
bool can_support_hd_split_feature = m_hd_chain.nVersion >= CHDChain::VERSION_HD_CHAIN_SPLIT;
|
bool can_support_hd_split_feature = m_hd_chain.nVersion >= CHDChain::VERSION_HD_CHAIN_SPLIT;
|
||||||
|
|
||||||
|
std::set<CExtPubKey> master_xpubs;
|
||||||
for (const CHDChain& chain : chains) {
|
for (const CHDChain& chain : chains) {
|
||||||
|
if (chain.seed_id.IsNull()) continue;
|
||||||
|
|
||||||
|
// Get the master xprv
|
||||||
|
CKey seed_key;
|
||||||
|
if (!GetKey(chain.seed_id, seed_key)) {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
CExtKey master_key;
|
||||||
|
master_key.SetSeed(seed_key);
|
||||||
|
|
||||||
|
// Get the xpub and verify that we haven't already seen this xpub before
|
||||||
|
CExtPubKey master_xpub = master_key.Neuter();
|
||||||
|
const auto& [_, inserted] = master_xpubs.insert(master_xpub);
|
||||||
|
if (!inserted) continue;
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
// Skip if doing internal chain and split chain is not supported
|
// Skip if doing internal chain and split chain is not supported
|
||||||
if (chain.seed_id.IsNull() || (i == 1 && !can_support_hd_split_feature)) {
|
if (i == 1 && !can_support_hd_split_feature) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Get the master xprv
|
|
||||||
CKey seed_key;
|
|
||||||
if (!GetKey(chain.seed_id, seed_key)) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
CExtKey master_key;
|
|
||||||
master_key.SetSeed(seed_key);
|
|
||||||
|
|
||||||
// Make the combo descriptor
|
// Make the combo descriptor
|
||||||
std::string xpub = EncodeExtPubKey(master_key.Neuter());
|
std::string xpub = EncodeExtPubKey(master_key.Neuter());
|
||||||
|
|||||||
@@ -257,10 +257,10 @@ FUZZ_TARGET(spkm_migration, .init = initialize_spkm_migration)
|
|||||||
|
|
||||||
bool add_inactive_hd_chain{fuzzed_data_provider.ConsumeBool() && !keys.empty()};
|
bool add_inactive_hd_chain{fuzzed_data_provider.ConsumeBool() && !keys.empty()};
|
||||||
if (add_inactive_hd_chain) {
|
if (add_inactive_hd_chain) {
|
||||||
hd_key = PickValue(fuzzed_data_provider, keys);
|
CKey inactive_hd_key = PickValue(fuzzed_data_provider, keys);
|
||||||
hd_chain.nVersion = fuzzed_data_provider.ConsumeBool() ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
|
hd_chain.nVersion = fuzzed_data_provider.ConsumeBool() ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
|
||||||
bool dup_chain = hd_chain.seed_id == hd_key.GetPubKey().GetID();
|
bool dup_chain = hd_key.IsValid() && std::equal(hd_key.begin(), hd_key.end(), inactive_hd_key.begin());
|
||||||
hd_chain.seed_id = hd_key.GetPubKey().GetID();
|
hd_chain.seed_id = inactive_hd_key.GetPubKey().GetID();
|
||||||
legacy_data.AddInactiveHDChain(hd_chain);
|
legacy_data.AddInactiveHDChain(hd_chain);
|
||||||
if (!dup_chain) added_chains++;
|
if (!dup_chain) added_chains++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user