@@ -160,8 +160,12 @@ struct PubkeyProvider
160
160
161
161
virtual ~PubkeyProvider () = default ;
162
162
163
- /* * Derive a public key. If key==nullptr, only info is desired. */
164
- virtual bool GetPubKey (int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const = 0;
163
+ /* * Derive a public key.
164
+ * read_cache is the cache to read keys from (if not nullptr)
165
+ * write_cache is the cache to write keys to (if not nullptr)
166
+ * Caches are not exclusive but this is not tested. Currently we use them exclusively
167
+ */
168
+ virtual bool GetPubKey (int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr , DescriptorCache* write_cache = nullptr ) const = 0;
165
169
166
170
/* * Whether this represent multiple public keys at different positions. */
167
171
virtual bool IsRange () const = 0;
@@ -191,9 +195,9 @@ class OriginPubkeyProvider final : public PubkeyProvider
191
195
192
196
public:
193
197
OriginPubkeyProvider (uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)) {}
194
- bool GetPubKey (int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const override
198
+ bool GetPubKey (int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr , DescriptorCache* write_cache = nullptr ) const override
195
199
{
196
- if (!m_provider->GetPubKey (pos, arg, key, info)) return false ;
200
+ if (!m_provider->GetPubKey (pos, arg, key, info, read_cache, write_cache )) return false ;
197
201
std::copy (std::begin (m_origin.fingerprint ), std::end (m_origin.fingerprint ), info.fingerprint );
198
202
info.path .insert (info.path .begin (), m_origin.path .begin (), m_origin.path .end ());
199
203
return true ;
@@ -221,9 +225,9 @@ class ConstPubkeyProvider final : public PubkeyProvider
221
225
222
226
public:
223
227
ConstPubkeyProvider (uint32_t exp_index, const CPubKey& pubkey) : PubkeyProvider(exp_index), m_pubkey(pubkey) {}
224
- bool GetPubKey (int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const override
228
+ bool GetPubKey (int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr , DescriptorCache* write_cache = nullptr ) const override
225
229
{
226
- if (key) * key = m_pubkey;
230
+ key = m_pubkey;
227
231
info.path .clear ();
228
232
CKeyID keyid = m_pubkey.GetID ();
229
233
std::copy (keyid.begin (), keyid.begin () + sizeof (info.fingerprint ), info.fingerprint );
@@ -271,6 +275,16 @@ class BIP32PubkeyProvider final : public PubkeyProvider
271
275
return true ;
272
276
}
273
277
278
+ // Derives the last xprv
279
+ bool GetDerivedExtKey (const SigningProvider& arg, CExtKey& xprv) const
280
+ {
281
+ if (!GetExtKey (arg, xprv)) return false ;
282
+ for (auto entry : m_path) {
283
+ xprv.Derive (xprv, entry);
284
+ }
285
+ return true ;
286
+ }
287
+
274
288
bool IsHardened () const
275
289
{
276
290
if (m_derive == DeriveType::HARDENED) return true ;
@@ -284,29 +298,47 @@ class BIP32PubkeyProvider final : public PubkeyProvider
284
298
BIP32PubkeyProvider (uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
285
299
bool IsRange () const override { return m_derive != DeriveType::NO; }
286
300
size_t GetSize () const override { return 33 ; }
287
- bool GetPubKey (int pos, const SigningProvider& arg, CPubKey* key , KeyOriginInfo& info ) const override
301
+ bool GetPubKey (int pos, const SigningProvider& arg, CPubKey& key_out , KeyOriginInfo& final_info_out, const DescriptorCache* read_cache = nullptr , DescriptorCache* write_cache = nullptr ) const override
288
302
{
289
- if (key) {
290
- if (IsHardened ()) {
291
- CKey priv_key;
292
- if (!GetPrivKey (pos, arg, priv_key)) return false ;
293
- *key = priv_key.GetPubKey ();
294
- } else {
295
- // TODO: optimize by caching
296
- CExtPubKey extkey = m_root_extkey;
297
- for (auto entry : m_path) {
298
- extkey.Derive (extkey, entry);
299
- }
300
- if (m_derive == DeriveType::UNHARDENED) extkey.Derive (extkey, pos);
301
- assert (m_derive != DeriveType::HARDENED);
302
- *key = extkey.pubkey ;
303
+ // Info of parent of the to be derived pubkey
304
+ KeyOriginInfo parent_info;
305
+ CKeyID keyid = m_root_extkey.pubkey .GetID ();
306
+ std::copy (keyid.begin (), keyid.begin () + sizeof (parent_info.fingerprint ), parent_info.fingerprint );
307
+ parent_info.path = m_path;
308
+
309
+ // Info of the derived key itself which is copied out upon successful completion
310
+ KeyOriginInfo final_info_out_tmp = parent_info;
311
+ if (m_derive == DeriveType::UNHARDENED) final_info_out_tmp.path .push_back ((uint32_t )pos);
312
+ if (m_derive == DeriveType::HARDENED) final_info_out_tmp.path .push_back (((uint32_t )pos) | 0x80000000L );
313
+
314
+ // Derive keys or fetch them from cache
315
+ CExtPubKey final_extkey = m_root_extkey;
316
+ bool der = true ;
317
+ if (read_cache) {
318
+ if (!read_cache->GetCachedDerivedExtPubKey (m_expr_index, pos, final_extkey)) return false ;
319
+ } else if (IsHardened ()) {
320
+ CExtKey xprv;
321
+ if (!GetDerivedExtKey (arg, xprv)) return false ;
322
+ if (m_derive == DeriveType::UNHARDENED) der = xprv.Derive (xprv, pos);
323
+ if (m_derive == DeriveType::HARDENED) der = xprv.Derive (xprv, pos | 0x80000000UL );
324
+ final_extkey = xprv.Neuter ();
325
+ } else {
326
+ for (auto entry : m_path) {
327
+ der = final_extkey.Derive (final_extkey, entry);
328
+ assert (der);
303
329
}
330
+ if (m_derive == DeriveType::UNHARDENED) der = final_extkey.Derive (final_extkey, pos);
331
+ assert (m_derive != DeriveType::HARDENED);
304
332
}
305
- CKeyID keyid = m_root_extkey.pubkey .GetID ();
306
- std::copy (keyid.begin (), keyid.begin () + sizeof (info.fingerprint ), info.fingerprint );
307
- info.path = m_path;
308
- if (m_derive == DeriveType::UNHARDENED) info.path .push_back ((uint32_t )pos);
309
- if (m_derive == DeriveType::HARDENED) info.path .push_back (((uint32_t )pos) | 0x80000000L );
333
+ assert (der);
334
+
335
+ final_info_out = final_info_out_tmp;
336
+ key_out = final_extkey.pubkey ;
337
+
338
+ if (write_cache) {
339
+ write_cache->CacheDerivedExtPubKey (m_expr_index, pos, final_extkey);
340
+ }
341
+
310
342
return true ;
311
343
}
312
344
std::string ToString () const override
@@ -332,10 +364,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
332
364
bool GetPrivKey (int pos, const SigningProvider& arg, CKey& key) const override
333
365
{
334
366
CExtKey extkey;
335
- if (!GetExtKey (arg, extkey)) return false ;
336
- for (auto entry : m_path) {
337
- extkey.Derive (extkey, entry);
338
- }
367
+ if (!GetDerivedExtKey (arg, extkey)) return false ;
339
368
if (m_derive == DeriveType::UNHARDENED) extkey.Derive (extkey, pos);
340
369
if (m_derive == DeriveType::HARDENED) extkey.Derive (extkey, pos | 0x80000000UL );
341
370
key = extkey.key ;
@@ -434,35 +463,20 @@ class DescriptorImpl : public Descriptor
434
463
return ret;
435
464
}
436
465
437
- bool ExpandHelper (int pos, const SigningProvider& arg, Span< const unsigned char >* cache_read , std::vector<CScript>& output_scripts, FlatSigningProvider& out, std::vector< unsigned char >* cache_write ) const
466
+ bool ExpandHelper (int pos, const SigningProvider& arg, const DescriptorCache* read_cache , std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache ) const
438
467
{
439
468
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
440
469
entries.reserve (m_pubkey_args.size ());
441
470
442
471
// Construct temporary data in `entries` and `subscripts`, to avoid producing output in case of failure.
443
472
for (const auto & p : m_pubkey_args) {
444
473
entries.emplace_back ();
445
- // If we have a cache, we don't need GetPubKey to compute the public key.
446
- // Pass in nullptr to signify only origin info is desired.
447
- if (!p->GetPubKey (pos, arg, cache_read ? nullptr : &entries.back ().first , entries.back ().second )) return false ;
448
- if (cache_read) {
449
- // Cached expanded public key exists, use it.
450
- if (cache_read->size () == 0 ) return false ;
451
- bool compressed = ((*cache_read)[0 ] == 0x02 || (*cache_read)[0 ] == 0x03 ) && cache_read->size () >= 33 ;
452
- bool uncompressed = ((*cache_read)[0 ] == 0x04 ) && cache_read->size () >= 65 ;
453
- if (!(compressed || uncompressed)) return false ;
454
- CPubKey pubkey (cache_read->begin (), cache_read->begin () + (compressed ? 33 : 65 ));
455
- entries.back ().first = pubkey;
456
- *cache_read = cache_read->subspan (compressed ? 33 : 65 );
457
- }
458
- if (cache_write) {
459
- cache_write->insert (cache_write->end (), entries.back ().first .begin (), entries.back ().first .end ());
460
- }
474
+ if (!p->GetPubKey (pos, arg, entries.back ().first , entries.back ().second , read_cache, write_cache)) return false ;
461
475
}
462
476
std::vector<CScript> subscripts;
463
477
if (m_subdescriptor_arg) {
464
478
FlatSigningProvider subprovider;
465
- if (!m_subdescriptor_arg->ExpandHelper (pos, arg, cache_read , subscripts, subprovider, cache_write )) return false ;
479
+ if (!m_subdescriptor_arg->ExpandHelper (pos, arg, read_cache , subscripts, subprovider, write_cache )) return false ;
466
480
out = Merge (out, subprovider);
467
481
}
468
482
@@ -486,15 +500,14 @@ class DescriptorImpl : public Descriptor
486
500
return true ;
487
501
}
488
502
489
- bool Expand (int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, std::vector< unsigned char >* cache = nullptr ) const final
503
+ bool Expand (int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache = nullptr ) const final
490
504
{
491
- return ExpandHelper (pos, provider, nullptr , output_scripts, out, cache );
505
+ return ExpandHelper (pos, provider, nullptr , output_scripts, out, write_cache );
492
506
}
493
507
494
- bool ExpandFromCache (int pos, const std::vector< unsigned char >& cache , std::vector<CScript>& output_scripts, FlatSigningProvider& out) const final
508
+ bool ExpandFromCache (int pos, const DescriptorCache& read_cache , std::vector<CScript>& output_scripts, FlatSigningProvider& out) const final
495
509
{
496
- Span<const unsigned char > span = MakeSpan (cache);
497
- return ExpandHelper (pos, DUMMY_SIGNING_PROVIDER, &span, output_scripts, out, nullptr ) && span.size () == 0 ;
510
+ return ExpandHelper (pos, DUMMY_SIGNING_PROVIDER, &read_cache, output_scripts, out, nullptr );
498
511
}
499
512
500
513
void ExpandPrivate (int pos, const SigningProvider& provider, FlatSigningProvider& out) const final
0 commit comments