Skip to content

Commit a4d1bd1

Browse files
committed
Add private key derivation functions to descriptors
1 parent 03858b2 commit a4d1bd1

File tree

2 files changed

+48
-8
lines changed

2 files changed

+48
-8
lines changed

src/script/descriptor.cpp

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ struct PubkeyProvider
164164

165165
/** Get the descriptor string form including private data (if available in arg). */
166166
virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
167+
168+
/** Derive a private key, if private data is available in arg. */
169+
virtual bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const = 0;
167170
};
168171

169172
class OriginPubkeyProvider final : public PubkeyProvider
@@ -195,6 +198,10 @@ class OriginPubkeyProvider final : public PubkeyProvider
195198
ret = "[" + OriginString() + "]" + std::move(sub);
196199
return true;
197200
}
201+
bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
202+
{
203+
return m_provider->GetPrivKey(pos, arg, key);
204+
}
198205
};
199206

200207
/** An object representing a parsed constant public key in a descriptor. */
@@ -222,6 +229,10 @@ class ConstPubkeyProvider final : public PubkeyProvider
222229
ret = EncodeSecret(key);
223230
return true;
224231
}
232+
bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
233+
{
234+
return arg.GetKey(m_pubkey.GetID(), key);
235+
}
225236
};
226237

227238
enum class DeriveType {
@@ -266,14 +277,9 @@ class BIP32PubkeyProvider final : public PubkeyProvider
266277
{
267278
if (key) {
268279
if (IsHardened()) {
269-
CExtKey extkey;
270-
if (!GetExtKey(arg, extkey)) return false;
271-
for (auto entry : m_path) {
272-
extkey.Derive(extkey, entry);
273-
}
274-
if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
275-
if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
276-
*key = extkey.Neuter().pubkey;
280+
CKey priv_key;
281+
if (!GetPrivKey(pos, arg, priv_key)) return false;
282+
*key = priv_key.GetPubKey();
277283
} else {
278284
// TODO: optimize by caching
279285
CExtPubKey extkey = m_extkey;
@@ -312,6 +318,18 @@ class BIP32PubkeyProvider final : public PubkeyProvider
312318
}
313319
return true;
314320
}
321+
bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
322+
{
323+
CExtKey extkey;
324+
if (!GetExtKey(arg, extkey)) return false;
325+
for (auto entry : m_path) {
326+
extkey.Derive(extkey, entry);
327+
}
328+
if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
329+
if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
330+
key = extkey.key;
331+
return true;
332+
}
315333
};
316334

317335
/** Base class for all Descriptor implementations. */
@@ -462,6 +480,20 @@ class DescriptorImpl : public Descriptor
462480
Span<const unsigned char> span = MakeSpan(cache);
463481
return ExpandHelper(pos, DUMMY_SIGNING_PROVIDER, &span, output_scripts, out, nullptr) && span.size() == 0;
464482
}
483+
484+
void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const final
485+
{
486+
for (const auto& p : m_pubkey_args) {
487+
CKey key;
488+
if (!p->GetPrivKey(pos, provider, key)) continue;
489+
out.keys.emplace(key.GetPubKey().GetID(), key);
490+
}
491+
if (m_script_arg) {
492+
FlatSigningProvider subprovider;
493+
m_script_arg->ExpandPrivate(pos, provider, subprovider);
494+
out = Merge(out, subprovider);
495+
}
496+
}
465497
};
466498

467499
/** Construct a vector with one element, which is moved into it. */

src/script/descriptor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ struct Descriptor {
6060
* out: scripts and public keys necessary for solving the expanded scriptPubKeys will be put here (may be equal to provider).
6161
*/
6262
virtual bool ExpandFromCache(int pos, const std::vector<unsigned char>& cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const = 0;
63+
64+
/** Expand the private key for a descriptor at a specified position, if possible.
65+
*
66+
* pos: the position at which to expand the descriptor. If IsRange() is false, this is ignored.
67+
* provider: the provider to query for the private keys.
68+
* out: any private keys available for the specified pos will be placed here.
69+
*/
70+
virtual void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const = 0;
6371
};
6472

6573
/** Parse a descriptor string. Included private keys are put in out.

0 commit comments

Comments
 (0)