26 typedef std::vector<uint32_t> KeyPath;
28 std::string FormatKeyPath(
const KeyPath& path)
33 if (i >> 31)
ret +=
'\'';
41 virtual ~PubkeyProvider() =
default;
47 virtual bool IsRange()
const = 0;
50 virtual size_t GetSize()
const = 0;
53 virtual std::string ToString()
const = 0;
56 virtual bool ToPrivateString(
const SigningProvider& arg, std::string& out)
const = 0;
59 class OriginPubkeyProvider final :
public PubkeyProvider
62 std::unique_ptr<PubkeyProvider> m_provider;
64 std::string OriginString()
const 66 return HexStr(std::begin(m_origin.fingerprint),
std::end(m_origin.fingerprint)) + FormatKeyPath(m_origin.path);
70 OriginPubkeyProvider(
KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : m_origin(
std::move(info)), m_provider(
std::move(provider)) {}
73 if (!m_provider->GetPubKey(pos, arg, key, info))
return false;
74 std::copy(std::begin(m_origin.fingerprint),
std::end(m_origin.fingerprint), info.
fingerprint);
75 info.
path.insert(info.
path.begin(), m_origin.path.begin(), m_origin.path.end());
78 bool IsRange()
const override {
return m_provider->IsRange(); }
79 size_t GetSize()
const override {
return m_provider->GetSize(); }
80 std::string ToString()
const override {
return "[" + OriginString() +
"]" + m_provider->ToString(); }
84 if (!m_provider->ToPrivateString(arg, sub))
return false;
85 ret =
"[" + OriginString() +
"]" + std::move(sub);
91 class ConstPubkeyProvider final :
public PubkeyProvider
96 ConstPubkeyProvider(
const CPubKey& pubkey) : m_pubkey(pubkey) {}
101 CKeyID keyid = m_pubkey.GetID();
105 bool IsRange()
const override {
return false; }
106 size_t GetSize()
const override {
return m_pubkey.size(); }
107 std::string ToString()
const override {
return HexStr(m_pubkey.begin(), m_pubkey.end()); }
111 if (!arg.
GetKey(m_pubkey.GetID(), key))
return false;
124 class BIP32PubkeyProvider final :
public PubkeyProvider
133 if (!arg.
GetKey(m_extkey.pubkey.GetID(), key))
return false;
134 ret.nDepth = m_extkey.nDepth;
135 std::copy(m_extkey.vchFingerprint, m_extkey.vchFingerprint +
sizeof(
ret.vchFingerprint),
ret.vchFingerprint);
136 ret.nChild = m_extkey.nChild;
137 ret.chaincode = m_extkey.chaincode;
142 bool IsHardened()
const 144 if (m_derive == DeriveType::HARDENED)
return true;
145 for (
auto entry : m_path) {
146 if (entry >> 31)
return true;
152 BIP32PubkeyProvider(
const CExtPubKey& extkey, KeyPath path,
DeriveType derive) : m_extkey(extkey), m_path(
std::move(path)), m_derive(derive) {}
153 bool IsRange()
const override {
return m_derive != DeriveType::NO; }
154 size_t GetSize()
const override {
return 33; }
159 if (!GetExtKey(arg, extkey))
return false;
160 for (
auto entry : m_path) {
161 extkey.
Derive(extkey, entry);
163 if (m_derive == DeriveType::UNHARDENED) extkey.
Derive(extkey, pos);
164 if (m_derive == DeriveType::HARDENED) extkey.
Derive(extkey, pos | 0x80000000UL);
169 for (
auto entry : m_path) {
170 extkey.
Derive(extkey, entry);
172 if (m_derive == DeriveType::UNHARDENED) extkey.
Derive(extkey, pos);
173 assert(m_derive != DeriveType::HARDENED);
176 CKeyID keyid = m_extkey.pubkey.GetID();
179 if (m_derive == DeriveType::UNHARDENED) info.
path.push_back((uint32_t)pos);
180 if (m_derive == DeriveType::HARDENED) info.
path.push_back(((uint32_t)pos) | 0x80000000L);
183 std::string ToString()
const override 188 if (m_derive == DeriveType::HARDENED)
ret +=
'\'';
192 bool ToPrivateString(
const SigningProvider& arg, std::string& out)
const override 195 if (!GetExtKey(arg, key))
return false;
199 if (m_derive == DeriveType::HARDENED) out +=
'\'';
206 class AddressDescriptor final :
public Descriptor 211 AddressDescriptor(
CTxDestination destination) : m_destination(
std::move(destination)) {}
213 bool IsRange()
const override {
return false; }
229 RawDescriptor(
CScript script) : m_script(
std::move(script)) {}
231 bool IsRange()
const override {
return false; }
232 std::string
ToString()
const override {
return "raw(" +
HexStr(m_script.begin(), m_script.end()) +
")"; }
236 output_scripts = std::vector<CScript>{m_script};
242 class SingleKeyDescriptor final :
public Descriptor 244 const std::function<CScript(const CPubKey&)> m_script_fn;
245 const std::string m_fn_name;
246 std::unique_ptr<PubkeyProvider> m_provider;
249 SingleKeyDescriptor(std::unique_ptr<PubkeyProvider> prov,
const std::function<
CScript(
const CPubKey&)>& fn,
const std::string&
name) : m_script_fn(fn), m_fn_name(
name), m_provider(
std::move(prov)) {}
251 bool IsRange()
const override {
return m_provider->IsRange(); }
252 std::string
ToString()
const override {
return m_fn_name +
"(" + m_provider->ToString() +
")"; }
256 if (!m_provider->ToPrivateString(arg,
ret))
return false;
257 out = m_fn_name +
"(" + std::move(
ret) +
")";
264 if (!m_provider->GetPubKey(pos, arg, key, info))
return false;
265 output_scripts = std::vector<CScript>{m_script_fn(key)};
280 std::vector<std::unique_ptr<PubkeyProvider>> m_providers;
283 MultisigDescriptor(
int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers) : m_threshold(threshold), m_providers(
std::move(providers)) {}
287 for (
const auto& p : m_providers) {
288 if (p->IsRange())
return true;
293 std::string
ToString()
const override 296 for (
const auto& p : m_providers) {
297 ret +=
"," + p->ToString();
299 return std::move(
ret) +
")";
305 for (
const auto& p : m_providers) {
307 if (!p->ToPrivateString(arg, sub))
return false;
308 ret +=
"," + std::move(sub);
310 out = std::move(
ret) +
")";
316 std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
317 entries.reserve(m_providers.size());
319 for (
const auto& p : m_providers) {
320 entries.emplace_back();
321 if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second))
return false;
323 std::vector<CPubKey> pubkeys;
324 pubkeys.reserve(entries.size());
325 for (
auto& entry : entries) {
326 pubkeys.push_back(entry.first);
327 out.
origins.emplace(entry.first.GetID(), std::move(entry.second));
328 out.
pubkeys.emplace(entry.first.GetID(), entry.first);
338 const std::function<CScript(const CScript&)> m_convert_fn;
339 const std::string m_fn_name;
340 std::unique_ptr<Descriptor> m_descriptor;
343 ConvertorDescriptor(std::unique_ptr<Descriptor> descriptor,
const std::function<
CScript(
const CScript&)>& fn,
const std::string&
name) : m_convert_fn(fn), m_fn_name(
name), m_descriptor(
std::move(descriptor)) {}
345 bool IsRange()
const override {
return m_descriptor->IsRange(); }
346 std::string
ToString()
const override {
return m_fn_name +
"(" + m_descriptor->ToString() +
")"; }
350 if (!m_descriptor->ToPrivateString(arg,
ret))
return false;
351 out = m_fn_name +
"(" + std::move(
ret) +
")";
356 std::vector<CScript> sub;
357 if (!m_descriptor->Expand(pos, arg, sub, out))
return false;
358 output_scripts.clear();
359 for (
const auto& script : sub) {
362 output_scripts.push_back(m_convert_fn(script));
372 class ComboDescriptor final :
public Descriptor 374 std::unique_ptr<PubkeyProvider> m_provider;
377 ComboDescriptor(std::unique_ptr<PubkeyProvider> provider) : m_provider(
std::move(provider)) {}
379 bool IsRange()
const override {
return m_provider->IsRange(); }
380 std::string
ToString()
const override {
return "combo(" + m_provider->ToString() +
")"; }
384 if (!m_provider->ToPrivateString(arg,
ret))
return false;
385 out =
"combo(" + std::move(
ret) +
")";
392 if (!m_provider->GetPubKey(pos, arg, key, info))
return false;
397 output_scripts = std::vector<CScript>{std::move(p2pk), std::move(p2pkh)};
398 out.
pubkeys.emplace(keyid, key);
399 out.
origins.emplace(keyid, std::move(info));
405 out.
scripts.emplace(p2wpkh_id, p2wpkh);
406 output_scripts.push_back(std::move(p2wpkh));
407 output_scripts.push_back(std::move(p2sh_p2wpkh));
426 if ((
size_t)sp.
size() >= str.size() && std::equal(str.begin(), str.end(), sp.
begin())) {
436 if ((
size_t)sp.
size() >= str.size() + 2 && sp[str.size()] ==
'(' && sp[sp.
size() - 1] ==
')' && std::equal(str.begin(), str.end(), sp.
begin())) {
437 sp = sp.
subspan(str.size() + 1, sp.
size() - str.size() - 2);
447 auto it = sp.
begin();
448 while (it != sp.
end()) {
451 }
else if (level && *it ==
')') {
453 }
else if (level == 0 && (*it ==
')' || *it ==
',')) {
466 std::vector<Span<const char>>
ret;
467 auto it = sp.
begin();
469 while (it != sp.
end()) {
483 for (
size_t i = 1; i < split.size(); ++i) {
485 bool hardened =
false;
486 if (elem.
size() > 0 && (elem[elem.
size() - 1] ==
'\'' || elem[elem.
size() - 1] ==
'h')) {
491 if (!
ParseUInt32(std::string(elem.
begin(), elem.
end()), &p) || p > 0x7FFFFFFFUL)
return false;
492 out.push_back(p | (((uint32_t)hardened) << 31));
500 auto split = Split(sp,
'/');
501 std::string str(split[0].begin(), split[0].
end());
502 if (split.size() == 1) {
504 std::vector<unsigned char> data =
ParseHex(str);
506 if (pubkey.
IsFullyValid() && (permit_uncompressed || pubkey.
IsCompressed()))
return MakeUnique<ConstPubkeyProvider>(pubkey);
512 return MakeUnique<ConstPubkeyProvider>(pubkey);
520 if (split.back() ==
MakeSpan(
"*").first(1)) {
522 type = DeriveType::UNHARDENED;
523 }
else if (split.back() ==
MakeSpan(
"*'").first(2) || split.back() ==
MakeSpan(
"*h").first(2)) {
525 type = DeriveType::HARDENED;
527 if (!ParseKeyPath(split, path))
return nullptr;
529 extpubkey = extkey.
Neuter();
532 return MakeUnique<BIP32PubkeyProvider>(extpubkey, std::move(path), type);
538 auto origin_split = Split(sp,
']');
539 if (origin_split.size() > 2)
return nullptr;
540 if (origin_split.size() == 1)
return ParsePubkeyInner(origin_split[0], permit_uncompressed, out);
541 if (origin_split[0].size() < 1 || origin_split[0][0] !=
'[')
return nullptr;
542 auto slash_split = Split(origin_split[0].subspan(1),
'/');
543 if (slash_split[0].size() != 8)
return nullptr;
544 std::string fpr_hex = std::string(slash_split[0].begin(), slash_split[0].
end());
545 if (!
IsHex(fpr_hex))
return nullptr;
548 static_assert(
sizeof(info.
fingerprint) == 4,
"Fingerprint must be 4 bytes");
549 assert(fpr_bytes.size() == 4);
550 std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.
fingerprint);
551 if (!ParseKeyPath(slash_split, info.
path))
return nullptr;
552 auto provider = ParsePubkeyInner(origin_split[1], permit_uncompressed, out);
553 if (!provider)
return nullptr;
554 return MakeUnique<OriginPubkeyProvider>(std::move(info), std::move(provider));
560 auto expr = Expr(sp);
561 if (Func(
"pk", expr)) {
562 auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out);
563 if (!pubkey)
return nullptr;
564 return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2PKGetScript,
"pk");
566 if (Func(
"pkh", expr)) {
567 auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out);
568 if (!pubkey)
return nullptr;
569 return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2PKHGetScript,
"pkh");
571 if (ctx == ParseScriptContext::TOP && Func(
"combo", expr)) {
572 auto pubkey = ParsePubkey(expr,
true, out);
573 if (!pubkey)
return nullptr;
574 return MakeUnique<ComboDescriptor>(std::move(pubkey));
576 if (Func(
"multi", expr)) {
577 auto threshold = Expr(expr);
579 std::vector<std::unique_ptr<PubkeyProvider>> providers;
580 if (!
ParseUInt32(std::string(threshold.begin(), threshold.end()), &thres))
return nullptr;
581 size_t script_size = 0;
582 while (expr.size()) {
583 if (!Const(
",", expr))
return nullptr;
584 auto arg = Expr(expr);
585 auto pk = ParsePubkey(arg, ctx != ParseScriptContext::P2WSH, out);
586 if (!pk)
return nullptr;
587 script_size += pk->GetSize() + 1;
588 providers.emplace_back(std::move(pk));
590 if (providers.size() < 1 || providers.size() > 16 || thres < 1 || thres > providers.size())
return nullptr;
591 if (ctx == ParseScriptContext::TOP) {
592 if (providers.size() > 3)
return nullptr;
594 if (ctx == ParseScriptContext::P2SH) {
595 if (script_size + 3 > 520)
return nullptr;
597 return MakeUnique<MultisigDescriptor>(thres, std::move(providers));
599 if (ctx != ParseScriptContext::P2WSH && Func(
"wpkh", expr)) {
600 auto pubkey = ParsePubkey(expr,
false, out);
601 if (!pubkey)
return nullptr;
602 return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2WPKHGetScript,
"wpkh");
604 if (ctx == ParseScriptContext::TOP && Func(
"sh", expr)) {
605 auto desc =
ParseScript(expr, ParseScriptContext::P2SH, out);
606 if (!desc || expr.size())
return nullptr;
607 return MakeUnique<ConvertorDescriptor>(std::move(desc), ConvertP2SH,
"sh");
609 if (ctx != ParseScriptContext::P2WSH && Func(
"wsh", expr)) {
610 auto desc =
ParseScript(expr, ParseScriptContext::P2WSH, out);
611 if (!desc || expr.size())
return nullptr;
612 return MakeUnique<ConvertorDescriptor>(std::move(desc), ConvertP2WSH,
"wsh");
614 if (ctx == ParseScriptContext::TOP && Func(
"addr", expr)) {
617 return MakeUnique<AddressDescriptor>(std::move(dest));
619 if (ctx == ParseScriptContext::TOP && Func(
"raw", expr)) {
620 std::string str(expr.begin(), expr.end());
621 if (!
IsHex(str))
return nullptr;
623 return MakeUnique<RawDescriptor>(
CScript(bytes.begin(), bytes.end()));
constexpr std::ptrdiff_t size() const noexcept
unsigned char fingerprint[4]
constexpr C * end() const noexcept
bool Derive(CExtKey &out, unsigned int nChild) const
std::unique_ptr< Descriptor > Parse(const std::string &descriptor, FlatSigningProvider &out)
Parse a descriptor string.
CPubKey GetPubKey() const
Compute the public key from a private key.
std::map< CKeyID, CKey > keys
CExtKey DecodeExtKey(const std::string &str)
UniValue ret(UniValue::VARR)
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
std::map< CKeyID, KeyOriginInfo > origins
constexpr Span< A > MakeSpan(A(&a)[N])
Create a span to a container exposing data() and size().
CExtPubKey DecodeExtPubKey(const std::string &str)
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
virtual std::string ToString() const =0
Convert the descriptor back to a string, undoing parsing.
constexpr Span< C > subspan(std::ptrdiff_t offset) const noexcept
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid()) ...
std::map< CScriptID, CScript > scripts
boost::variant< CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
An encapsulated public key.
std::map< CKeyID, CPubKey > pubkeys
bool IsHex(const std::string &str)
constexpr Span< C > first(std::ptrdiff_t count) const noexcept
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
virtual bool Expand(int pos, const SigningProvider &provider, std::vector< CScript > &output_scripts, FlatSigningProvider &out) const =0
Expand a descriptor at a specified position.
virtual bool GetKey(const CKeyID &address, CKey &key) const
constexpr C * begin() const noexcept
CTxDestination DecodeDestination(const std::string &str)
bool Derive(CExtPubKey &out, unsigned int nChild) const
std::string EncodeExtPubKey(const CExtPubKey &key)
An interface to be implemented by keystores that support signing.
CExtPubKey Neuter() const
Serialized script, used inside transaction inputs and outputs.
A reference to a CKey: the Hash360 of its serialized public key.
bool ParseUInt32(const std::string &str, uint32_t *out)
Convert decimal string to unsigned 32-bit integer with strict parse error feedback.
A reference to a CScript: the Hash360 of its serialization (see script.h)
std::string EncodeDestination(const CTxDestination &dest)
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
An encapsulated private key.
A Span is an object that can refer to a contiguous sequence of objects.
CKey DecodeSecret(const std::string &str)
virtual bool IsRange() const =0
Whether the expansion of this descriptor depends on the position.
CScript ParseScript(const std::string &s)
std::string EncodeSecret(const CKey &key)
std::vector< uint32_t > path
virtual bool ToPrivateString(const SigningProvider &provider, std::string &out) const =0
Convert the descriptor to a private string.
std::string EncodeExtKey(const CExtKey &key)
Interface for parsed descriptor objects.
bool IsValid() const
Check whether this private key is valid.
std::vector< unsigned char > ParseHex(const char *psz)
bool IsCompressed() const
Check whether this is a compressed public key.