@@ -302,11 +302,14 @@ class BIP32PubkeyProvider final : public PubkeyProvider
302
302
}
303
303
304
304
// Derives the last xprv
305
- bool GetDerivedExtKey (const SigningProvider& arg, CExtKey& xprv) const
305
+ bool GetDerivedExtKey (const SigningProvider& arg, CExtKey& xprv, CExtKey& last_hardened ) const
306
306
{
307
307
if (!GetExtKey (arg, xprv)) return false ;
308
308
for (auto entry : m_path) {
309
309
xprv.Derive (xprv, entry);
310
+ if (entry >> 31 ) {
311
+ last_hardened = xprv;
312
+ }
310
313
}
311
314
return true ;
312
315
}
@@ -340,6 +343,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
340
343
// Derive keys or fetch them from cache
341
344
CExtPubKey final_extkey = m_root_extkey;
342
345
CExtPubKey parent_extkey = m_root_extkey;
346
+ CExtPubKey last_hardened_extkey;
343
347
bool der = true ;
344
348
if (read_cache) {
345
349
if (!read_cache->GetCachedDerivedExtPubKey (m_expr_index, pos, final_extkey)) {
@@ -351,11 +355,15 @@ class BIP32PubkeyProvider final : public PubkeyProvider
351
355
}
352
356
} else if (IsHardened ()) {
353
357
CExtKey xprv;
354
- if (!GetDerivedExtKey (arg, xprv)) return false ;
358
+ CExtKey lh_xprv;
359
+ if (!GetDerivedExtKey (arg, xprv, lh_xprv)) return false ;
355
360
parent_extkey = xprv.Neuter ();
356
361
if (m_derive == DeriveType::UNHARDENED) der = xprv.Derive (xprv, pos);
357
362
if (m_derive == DeriveType::HARDENED) der = xprv.Derive (xprv, pos | 0x80000000UL );
358
363
final_extkey = xprv.Neuter ();
364
+ if (lh_xprv.key .IsValid ()) {
365
+ last_hardened_extkey = lh_xprv.Neuter ();
366
+ }
359
367
} else {
360
368
for (auto entry : m_path) {
361
369
der = parent_extkey.Derive (parent_extkey, entry);
@@ -374,6 +382,10 @@ class BIP32PubkeyProvider final : public PubkeyProvider
374
382
// Only cache parent if there is any unhardened derivation
375
383
if (m_derive != DeriveType::HARDENED) {
376
384
write_cache->CacheParentExtPubKey (m_expr_index, parent_extkey);
385
+ // Cache last hardened xpub if we have it
386
+ if (last_hardened_extkey.pubkey .IsValid ()) {
387
+ write_cache->CacheLastHardenedExtPubKey (m_expr_index, last_hardened_extkey);
388
+ }
377
389
} else if (final_info_out.path .size () > 0 ) {
378
390
write_cache->CacheDerivedExtPubKey (m_expr_index, pos, final_extkey);
379
391
}
@@ -454,7 +466,8 @@ class BIP32PubkeyProvider final : public PubkeyProvider
454
466
bool GetPrivKey (int pos, const SigningProvider& arg, CKey& key) const override
455
467
{
456
468
CExtKey extkey;
457
- if (!GetDerivedExtKey (arg, extkey)) return false ;
469
+ CExtKey dummy;
470
+ if (!GetDerivedExtKey (arg, extkey, dummy)) return false ;
458
471
if (m_derive == DeriveType::UNHARDENED) extkey.Derive (extkey, pos);
459
472
if (m_derive == DeriveType::HARDENED) extkey.Derive (extkey, pos | 0x80000000UL );
460
473
key = extkey.key ;
@@ -1400,6 +1413,11 @@ void DescriptorCache::CacheDerivedExtPubKey(uint32_t key_exp_pos, uint32_t der_i
1400
1413
xpubs[der_index] = xpub;
1401
1414
}
1402
1415
1416
+ void DescriptorCache::CacheLastHardenedExtPubKey (uint32_t key_exp_pos, const CExtPubKey& xpub)
1417
+ {
1418
+ m_last_hardened_xpubs[key_exp_pos] = xpub;
1419
+ }
1420
+
1403
1421
bool DescriptorCache::GetCachedParentExtPubKey (uint32_t key_exp_pos, CExtPubKey& xpub) const
1404
1422
{
1405
1423
const auto & it = m_parent_xpubs.find (key_exp_pos);
@@ -1418,6 +1436,14 @@ bool DescriptorCache::GetCachedDerivedExtPubKey(uint32_t key_exp_pos, uint32_t d
1418
1436
return true ;
1419
1437
}
1420
1438
1439
+ bool DescriptorCache::GetCachedLastHardenedExtPubKey (uint32_t key_exp_pos, CExtPubKey& xpub) const
1440
+ {
1441
+ const auto & it = m_last_hardened_xpubs.find (key_exp_pos);
1442
+ if (it == m_last_hardened_xpubs.end ()) return false ;
1443
+ xpub = it->second ;
1444
+ return true ;
1445
+ }
1446
+
1421
1447
DescriptorCache DescriptorCache::MergeAndDiff (const DescriptorCache& other)
1422
1448
{
1423
1449
DescriptorCache diff;
@@ -1445,6 +1471,17 @@ DescriptorCache DescriptorCache::MergeAndDiff(const DescriptorCache& other)
1445
1471
diff.CacheDerivedExtPubKey (derived_xpub_map_pair.first , derived_xpub_pair.first , derived_xpub_pair.second );
1446
1472
}
1447
1473
}
1474
+ for (const auto & lh_xpub_pair : other.GetCachedLastHardenedExtPubKeys ()) {
1475
+ CExtPubKey xpub;
1476
+ if (GetCachedLastHardenedExtPubKey (lh_xpub_pair.first , xpub)) {
1477
+ if (xpub != lh_xpub_pair.second ) {
1478
+ throw std::runtime_error (std::string (__func__) + " : New cached last hardened xpub does not match already cached last hardened xpub" );
1479
+ }
1480
+ continue ;
1481
+ }
1482
+ CacheLastHardenedExtPubKey (lh_xpub_pair.first , lh_xpub_pair.second );
1483
+ diff.CacheLastHardenedExtPubKey (lh_xpub_pair.first , lh_xpub_pair.second );
1484
+ }
1448
1485
return diff;
1449
1486
}
1450
1487
@@ -1457,3 +1494,8 @@ const std::unordered_map<uint32_t, ExtPubKeyMap> DescriptorCache::GetCachedDeriv
1457
1494
{
1458
1495
return m_derived_xpubs;
1459
1496
}
1497
+
1498
+ const ExtPubKeyMap DescriptorCache::GetCachedLastHardenedExtPubKeys () const
1499
+ {
1500
+ return m_last_hardened_xpubs;
1501
+ }
0 commit comments