@@ -40,8 +40,8 @@ struct PubkeyProvider
40
40
{
41
41
virtual ~PubkeyProvider () = default ;
42
42
43
- /* * Derive a public key. */
44
- virtual bool GetPubKey (int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const = 0;
43
+ /* * Derive a public key. If key==nullptr, only info is desired. */
44
+ virtual bool GetPubKey (int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const = 0;
45
45
46
46
/* * Whether this represent multiple public keys at different positions. */
47
47
virtual bool IsRange () const = 0;
@@ -68,7 +68,7 @@ class OriginPubkeyProvider final : public PubkeyProvider
68
68
69
69
public:
70
70
OriginPubkeyProvider (KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : m_origin(std::move(info)), m_provider(std::move(provider)) {}
71
- bool GetPubKey (int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const override
71
+ bool GetPubKey (int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const override
72
72
{
73
73
if (!m_provider->GetPubKey (pos, arg, key, info)) return false ;
74
74
std::copy (std::begin (m_origin.fingerprint ), std::end (m_origin.fingerprint ), info.fingerprint );
@@ -94,9 +94,9 @@ class ConstPubkeyProvider final : public PubkeyProvider
94
94
95
95
public:
96
96
ConstPubkeyProvider (const CPubKey& pubkey) : m_pubkey(pubkey) {}
97
- bool GetPubKey (int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const override
97
+ bool GetPubKey (int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const override
98
98
{
99
- key = m_pubkey;
99
+ if (key) * key = m_pubkey;
100
100
info.path .clear ();
101
101
CKeyID keyid = m_pubkey.GetID ();
102
102
std::copy (keyid.begin (), keyid.begin () + sizeof (info.fingerprint ), info.fingerprint );
@@ -152,26 +152,28 @@ class BIP32PubkeyProvider final : public PubkeyProvider
152
152
BIP32PubkeyProvider (const CExtPubKey& extkey, KeyPath path, DeriveType derive) : m_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
153
153
bool IsRange () const override { return m_derive != DeriveType::NO; }
154
154
size_t GetSize () const override { return 33 ; }
155
- bool GetPubKey (int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const override
155
+ bool GetPubKey (int pos, const SigningProvider& arg, CPubKey* key, KeyOriginInfo& info) const override
156
156
{
157
- if (IsHardened ()) {
158
- CExtKey extkey;
159
- if (!GetExtKey (arg, extkey)) return false ;
160
- for (auto entry : m_path) {
161
- extkey.Derive (extkey, entry);
162
- }
163
- if (m_derive == DeriveType::UNHARDENED) extkey.Derive (extkey, pos);
164
- if (m_derive == DeriveType::HARDENED) extkey.Derive (extkey, pos | 0x80000000UL );
165
- key = extkey.Neuter ().pubkey ;
166
- } else {
167
- // TODO: optimize by caching
168
- CExtPubKey extkey = m_extkey;
169
- for (auto entry : m_path) {
170
- extkey.Derive (extkey, entry);
157
+ if (key) {
158
+ if (IsHardened ()) {
159
+ CExtKey extkey;
160
+ if (!GetExtKey (arg, extkey)) return false ;
161
+ for (auto entry : m_path) {
162
+ extkey.Derive (extkey, entry);
163
+ }
164
+ if (m_derive == DeriveType::UNHARDENED) extkey.Derive (extkey, pos);
165
+ if (m_derive == DeriveType::HARDENED) extkey.Derive (extkey, pos | 0x80000000UL );
166
+ *key = extkey.Neuter ().pubkey ;
167
+ } else {
168
+ // TODO: optimize by caching
169
+ CExtPubKey extkey = m_extkey;
170
+ for (auto entry : m_path) {
171
+ extkey.Derive (extkey, entry);
172
+ }
173
+ if (m_derive == DeriveType::UNHARDENED) extkey.Derive (extkey, pos);
174
+ assert (m_derive != DeriveType::HARDENED);
175
+ *key = extkey.pubkey ;
171
176
}
172
- if (m_derive == DeriveType::UNHARDENED) extkey.Derive (extkey, pos);
173
- assert (m_derive != DeriveType::HARDENED);
174
- key = extkey.pubkey ;
175
177
}
176
178
CKeyID keyid = m_extkey.pubkey .GetID ();
177
179
std::copy (keyid.begin (), keyid.begin () + sizeof (info.fingerprint ), info.fingerprint );
@@ -285,20 +287,33 @@ class DescriptorImpl : public Descriptor
285
287
286
288
bool ToPrivateString (const SigningProvider& arg, std::string& out) const override final { return ToStringHelper (&arg, out, true ); }
287
289
288
- bool Expand (int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const final
290
+ 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
289
291
{
290
292
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
291
293
entries.reserve (m_pubkey_args.size ());
292
294
293
295
// Construct temporary data in `entries` and `subscripts`, to avoid producing output in case of failure.
294
296
for (const auto & p : m_pubkey_args) {
295
297
entries.emplace_back ();
296
- if (!p->GetPubKey (pos, arg, entries.back ().first , entries.back ().second )) return false ;
298
+ if (!p->GetPubKey (pos, arg, cache_read ? nullptr : &entries.back ().first , entries.back ().second )) return false ;
299
+ if (cache_read) {
300
+ // Cached expanded public key exists, use it.
301
+ if (cache_read->size () == 0 ) return false ;
302
+ bool compressed = ((*cache_read)[0 ] == 0x02 || (*cache_read)[0 ] == 0x03 ) && cache_read->size () >= 33 ;
303
+ bool uncompressed = ((*cache_read)[0 ] == 0x04 ) && cache_read->size () >= 65 ;
304
+ if (!(compressed || uncompressed)) return false ;
305
+ CPubKey pubkey (cache_read->begin (), cache_read->begin () + (compressed ? 33 : 65 ));
306
+ entries.back ().first = pubkey;
307
+ *cache_read = cache_read->subspan (compressed ? 33 : 65 );
308
+ }
309
+ if (cache_write) {
310
+ cache_write->insert (cache_write->end (), entries.back ().first .begin (), entries.back ().first .end ());
311
+ }
297
312
}
298
313
std::vector<CScript> subscripts;
299
314
if (m_script_arg) {
300
315
FlatSigningProvider subprovider;
301
- if (!m_script_arg->Expand (pos, arg, subscripts, subprovider)) return false ;
316
+ if (!m_script_arg->ExpandHelper (pos, arg, cache_read, subscripts, subprovider, cache_write )) return false ;
302
317
out = Merge (out, subprovider);
303
318
}
304
319
@@ -322,6 +337,17 @@ class DescriptorImpl : public Descriptor
322
337
}
323
338
return true ;
324
339
}
340
+
341
+ bool Expand (int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, std::vector<unsigned char >* cache = nullptr ) const final
342
+ {
343
+ return ExpandHelper (pos, provider, nullptr , output_scripts, out, cache);
344
+ }
345
+
346
+ bool ExpandFromCache (int pos, const std::vector<unsigned char >& cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const final
347
+ {
348
+ Span<const unsigned char > span = MakeSpan (cache);
349
+ return ExpandHelper (pos, DUMMY_SIGNING_PROVIDER, &span, output_scripts, out, nullptr ) && span.size () == 0 ;
350
+ }
325
351
};
326
352
327
353
/* * Construct a vector with one element, which is moved into it. */
0 commit comments