@@ -40,8 +40,8 @@ struct PubkeyProvider
4040{
4141 virtual ~PubkeyProvider () = default ;
4242
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;
4545
4646 /* * Whether this represent multiple public keys at different positions. */
4747 virtual bool IsRange () const = 0;
@@ -68,7 +68,7 @@ class OriginPubkeyProvider final : public PubkeyProvider
6868
6969public:
7070 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
7272 {
7373 if (!m_provider->GetPubKey (pos, arg, key, info)) return false ;
7474 std::copy (std::begin (m_origin.fingerprint ), std::end (m_origin.fingerprint ), info.fingerprint );
@@ -94,9 +94,9 @@ class ConstPubkeyProvider final : public PubkeyProvider
9494
9595public:
9696 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
9898 {
99- key = m_pubkey;
99+ if (key) * key = m_pubkey;
100100 info.path .clear ();
101101 CKeyID keyid = m_pubkey.GetID ();
102102 std::copy (keyid.begin (), keyid.begin () + sizeof (info.fingerprint ), info.fingerprint );
@@ -152,26 +152,28 @@ class BIP32PubkeyProvider final : public PubkeyProvider
152152 BIP32PubkeyProvider (const CExtPubKey& extkey, KeyPath path, DeriveType derive) : m_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
153153 bool IsRange () const override { return m_derive != DeriveType::NO; }
154154 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
156156 {
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 ;
171176 }
172- if (m_derive == DeriveType::UNHARDENED) extkey.Derive (extkey, pos);
173- assert (m_derive != DeriveType::HARDENED);
174- key = extkey.pubkey ;
175177 }
176178 CKeyID keyid = m_extkey.pubkey .GetID ();
177179 std::copy (keyid.begin (), keyid.begin () + sizeof (info.fingerprint ), info.fingerprint );
@@ -285,20 +287,33 @@ class DescriptorImpl : public Descriptor
285287
286288 bool ToPrivateString (const SigningProvider& arg, std::string& out) const override final { return ToStringHelper (&arg, out, true ); }
287289
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
289291 {
290292 std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
291293 entries.reserve (m_pubkey_args.size ());
292294
293295 // Construct temporary data in `entries` and `subscripts`, to avoid producing output in case of failure.
294296 for (const auto & p : m_pubkey_args) {
295297 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+ }
297312 }
298313 std::vector<CScript> subscripts;
299314 if (m_script_arg) {
300315 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 ;
302317 out = Merge (out, subprovider);
303318 }
304319
@@ -322,6 +337,17 @@ class DescriptorImpl : public Descriptor
322337 }
323338 return true ;
324339 }
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+ }
325351};
326352
327353/* * Construct a vector with one element, which is moved into it. */
0 commit comments