Changeset View
Changeset View
Standalone View
Standalone View
src/script/descriptor.cpp
Show All 35 Lines | std::string FormatKeyPath(const KeyPath &path) { | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
/** Interface for public key objects in descriptors. */ | /** Interface for public key objects in descriptors. */ | ||||
struct PubkeyProvider { | struct PubkeyProvider { | ||||
virtual ~PubkeyProvider() = default; | virtual ~PubkeyProvider() = default; | ||||
/** Derive a public key. */ | /** Derive a public key. If key==nullptr, only info is desired. */ | ||||
virtual bool GetPubKey(int pos, const SigningProvider &arg, CPubKey &key, | virtual bool GetPubKey(int pos, const SigningProvider &arg, CPubKey *key, | ||||
KeyOriginInfo &info) const = 0; | KeyOriginInfo &info) const = 0; | ||||
/** Whether this represent multiple public keys at different positions. */ | /** Whether this represent multiple public keys at different positions. */ | ||||
virtual bool IsRange() const = 0; | virtual bool IsRange() const = 0; | ||||
/** Get the size of the generated public key(s) in bytes (33 or 65). */ | /** Get the size of the generated public key(s) in bytes (33 or 65). */ | ||||
virtual size_t GetSize() const = 0; | virtual size_t GetSize() const = 0; | ||||
Show All 17 Lines | std::string OriginString() const { | ||||
std::end(m_origin.fingerprint)) + | std::end(m_origin.fingerprint)) + | ||||
FormatKeyPath(m_origin.path); | FormatKeyPath(m_origin.path); | ||||
} | } | ||||
public: | public: | ||||
OriginPubkeyProvider(KeyOriginInfo info, | OriginPubkeyProvider(KeyOriginInfo info, | ||||
std::unique_ptr<PubkeyProvider> provider) | std::unique_ptr<PubkeyProvider> provider) | ||||
: m_origin(std::move(info)), m_provider(std::move(provider)) {} | : m_origin(std::move(info)), m_provider(std::move(provider)) {} | ||||
bool GetPubKey(int pos, const SigningProvider &arg, CPubKey &key, | bool GetPubKey(int pos, const SigningProvider &arg, CPubKey *key, | ||||
KeyOriginInfo &info) const override { | KeyOriginInfo &info) const override { | ||||
if (!m_provider->GetPubKey(pos, arg, key, info)) { | if (!m_provider->GetPubKey(pos, arg, key, info)) { | ||||
return false; | return false; | ||||
} | } | ||||
std::copy(std::begin(m_origin.fingerprint), | std::copy(std::begin(m_origin.fingerprint), | ||||
std::end(m_origin.fingerprint), info.fingerprint); | std::end(m_origin.fingerprint), info.fingerprint); | ||||
info.path.insert(info.path.begin(), m_origin.path.begin(), | info.path.insert(info.path.begin(), m_origin.path.begin(), | ||||
m_origin.path.end()); | m_origin.path.end()); | ||||
Show All 16 Lines | |||||
}; | }; | ||||
/** An object representing a parsed constant public key in a descriptor. */ | /** An object representing a parsed constant public key in a descriptor. */ | ||||
class ConstPubkeyProvider final : public PubkeyProvider { | class ConstPubkeyProvider final : public PubkeyProvider { | ||||
CPubKey m_pubkey; | CPubKey m_pubkey; | ||||
public: | public: | ||||
ConstPubkeyProvider(const CPubKey &pubkey) : m_pubkey(pubkey) {} | ConstPubkeyProvider(const CPubKey &pubkey) : m_pubkey(pubkey) {} | ||||
bool GetPubKey(int pos, const SigningProvider &arg, CPubKey &key, | bool GetPubKey(int pos, const SigningProvider &arg, CPubKey *key, | ||||
KeyOriginInfo &info) const override { | KeyOriginInfo &info) const override { | ||||
key = m_pubkey; | if (key) { | ||||
*key = m_pubkey; | |||||
} | |||||
info.path.clear(); | info.path.clear(); | ||||
CKeyID keyid = m_pubkey.GetID(); | CKeyID keyid = m_pubkey.GetID(); | ||||
std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), | std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), | ||||
info.fingerprint); | info.fingerprint); | ||||
return true; | return true; | ||||
} | } | ||||
bool IsRange() const override { return false; } | bool IsRange() const override { return false; } | ||||
size_t GetSize() const override { return m_pubkey.size(); } | size_t GetSize() const override { return m_pubkey.size(); } | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | class BIP32PubkeyProvider final : public PubkeyProvider { | ||||
} | } | ||||
public: | public: | ||||
BIP32PubkeyProvider(const CExtPubKey &extkey, KeyPath path, | BIP32PubkeyProvider(const CExtPubKey &extkey, KeyPath path, | ||||
DeriveType derive) | DeriveType derive) | ||||
: m_extkey(extkey), m_path(std::move(path)), m_derive(derive) {} | : m_extkey(extkey), m_path(std::move(path)), m_derive(derive) {} | ||||
bool IsRange() const override { return m_derive != DeriveType::NO; } | bool IsRange() const override { return m_derive != DeriveType::NO; } | ||||
size_t GetSize() const override { return 33; } | size_t GetSize() const override { return 33; } | ||||
bool GetPubKey(int pos, const SigningProvider &arg, CPubKey &key, | bool GetPubKey(int pos, const SigningProvider &arg, CPubKey *key, | ||||
KeyOriginInfo &info) const override { | KeyOriginInfo &info) const override { | ||||
if (key) { | |||||
if (IsHardened()) { | if (IsHardened()) { | ||||
CExtKey extkey; | CExtKey extkey; | ||||
if (!GetExtKey(arg, extkey)) { | if (!GetExtKey(arg, extkey)) { | ||||
return false; | return false; | ||||
} | } | ||||
for (auto entry : m_path) { | for (auto entry : m_path) { | ||||
extkey.Derive(extkey, entry); | extkey.Derive(extkey, entry); | ||||
} | } | ||||
if (m_derive == DeriveType::UNHARDENED) { | if (m_derive == DeriveType::UNHARDENED) { | ||||
extkey.Derive(extkey, pos); | extkey.Derive(extkey, pos); | ||||
} | } | ||||
if (m_derive == DeriveType::HARDENED) { | if (m_derive == DeriveType::HARDENED) { | ||||
extkey.Derive(extkey, pos | 0x80000000UL); | extkey.Derive(extkey, pos | 0x80000000UL); | ||||
} | } | ||||
key = extkey.Neuter().pubkey; | *key = extkey.Neuter().pubkey; | ||||
} else { | } else { | ||||
// TODO: optimize by caching | // TODO: optimize by caching | ||||
CExtPubKey extkey = m_extkey; | CExtPubKey extkey = m_extkey; | ||||
for (auto entry : m_path) { | for (auto entry : m_path) { | ||||
extkey.Derive(extkey, entry); | extkey.Derive(extkey, entry); | ||||
} | } | ||||
if (m_derive == DeriveType::UNHARDENED) { | if (m_derive == DeriveType::UNHARDENED) { | ||||
extkey.Derive(extkey, pos); | extkey.Derive(extkey, pos); | ||||
} | } | ||||
assert(m_derive != DeriveType::HARDENED); | assert(m_derive != DeriveType::HARDENED); | ||||
key = extkey.pubkey; | *key = extkey.pubkey; | ||||
} | |||||
} | } | ||||
CKeyID keyid = m_extkey.pubkey.GetID(); | CKeyID keyid = m_extkey.pubkey.GetID(); | ||||
std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), | std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), | ||||
info.fingerprint); | info.fingerprint); | ||||
info.path = m_path; | info.path = m_path; | ||||
if (m_derive == DeriveType::UNHARDENED) { | if (m_derive == DeriveType::UNHARDENED) { | ||||
info.path.push_back(uint32_t(pos)); | info.path.push_back(uint32_t(pos)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | std::string ToString() const final { | ||||
return ret; | return ret; | ||||
} | } | ||||
bool ToPrivateString(const SigningProvider &arg, | bool ToPrivateString(const SigningProvider &arg, | ||||
std::string &out) const override final { | std::string &out) const override final { | ||||
return ToStringHelper(&arg, out, true); | return ToStringHelper(&arg, out, true); | ||||
} | } | ||||
bool Expand(int pos, const SigningProvider &arg, | bool ExpandHelper(int pos, const SigningProvider &arg, | ||||
Span<const uint8_t> *cache_read, | |||||
std::vector<CScript> &output_scripts, | std::vector<CScript> &output_scripts, | ||||
FlatSigningProvider &out) const final { | FlatSigningProvider &out, | ||||
std::vector<uint8_t> *cache_write) const { | |||||
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries; | std::vector<std::pair<CPubKey, KeyOriginInfo>> entries; | ||||
entries.reserve(m_pubkey_args.size()); | entries.reserve(m_pubkey_args.size()); | ||||
// Construct temporary data in `entries` and `subscripts`, to avoid | // Construct temporary data in `entries` and `subscripts`, to avoid | ||||
// producing output in case of failure. | // producing output in case of failure. | ||||
for (const auto &p : m_pubkey_args) { | for (const auto &p : m_pubkey_args) { | ||||
entries.emplace_back(); | entries.emplace_back(); | ||||
if (!p->GetPubKey(pos, arg, entries.back().first, | if (!p->GetPubKey(pos, arg, | ||||
cache_read ? nullptr : &entries.back().first, | |||||
entries.back().second)) { | entries.back().second)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (cache_read) { | |||||
// Cached expanded public key exists, use it. | |||||
if (cache_read->size() == 0) { | |||||
return false; | |||||
} | |||||
bool compressed = | |||||
((*cache_read)[0] == 0x02 || (*cache_read)[0] == 0x03) && | |||||
cache_read->size() >= 33; | |||||
bool uncompressed = | |||||
((*cache_read)[0] == 0x04) && cache_read->size() >= 65; | |||||
if (!(compressed || uncompressed)) { | |||||
return false; | |||||
} | |||||
CPubKey pubkey(cache_read->begin(), | |||||
cache_read->begin() + (compressed ? 33 : 65)); | |||||
entries.back().first = pubkey; | |||||
*cache_read = cache_read->subspan(compressed ? 33 : 65); | |||||
} | |||||
if (cache_write) { | |||||
cache_write->insert(cache_write->end(), | |||||
entries.back().first.begin(), | |||||
entries.back().first.end()); | |||||
} | |||||
} | } | ||||
std::vector<CScript> subscripts; | std::vector<CScript> subscripts; | ||||
if (m_script_arg) { | if (m_script_arg) { | ||||
FlatSigningProvider subprovider; | FlatSigningProvider subprovider; | ||||
if (!m_script_arg->Expand(pos, arg, subscripts, subprovider)) { | if (!m_script_arg->ExpandHelper(pos, arg, cache_read, subscripts, | ||||
subprovider, cache_write)) { | |||||
return false; | return false; | ||||
} | } | ||||
out = Merge(out, subprovider); | out = Merge(out, subprovider); | ||||
} | } | ||||
std::vector<CPubKey> pubkeys; | std::vector<CPubKey> pubkeys; | ||||
pubkeys.reserve(entries.size()); | pubkeys.reserve(entries.size()); | ||||
for (auto &entry : entries) { | for (auto &entry : entries) { | ||||
Show All 10 Lines | bool ExpandHelper(int pos, const SigningProvider &arg, | ||||
output_scripts.push_back(std::move(addscript)); | output_scripts.push_back(std::move(addscript)); | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
output_scripts = MakeScripts(pubkeys, nullptr, out); | output_scripts = MakeScripts(pubkeys, nullptr, out); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool Expand(int pos, const SigningProvider &provider, | |||||
std::vector<CScript> &output_scripts, FlatSigningProvider &out, | |||||
std::vector<uint8_t> *cache = nullptr) const final { | |||||
return ExpandHelper(pos, provider, nullptr, output_scripts, out, cache); | |||||
} | |||||
bool ExpandFromCache(int pos, const std::vector<uint8_t> &cache, | |||||
std::vector<CScript> &output_scripts, | |||||
FlatSigningProvider &out) const final { | |||||
Span<const uint8_t> span = MakeSpan(cache); | |||||
return ExpandHelper(pos, DUMMY_SIGNING_PROVIDER, &span, output_scripts, | |||||
out, nullptr) && | |||||
span.size() == 0; | |||||
} | |||||
}; | }; | ||||
/** Construct a vector with one element, which is moved into it. */ | /** Construct a vector with one element, which is moved into it. */ | ||||
template <typename T> std::vector<T> Singleton(T elem) { | template <typename T> std::vector<T> Singleton(T elem) { | ||||
std::vector<T> ret; | std::vector<T> ret; | ||||
ret.emplace_back(std::move(elem)); | ret.emplace_back(std::move(elem)); | ||||
return ret; | return ret; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 479 Lines • Show Last 20 Lines |