aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/descriptor.cpp86
-rw-r--r--src/script/miniscript.h2
-rw-r--r--src/script/sigcache.cpp3
3 files changed, 60 insertions, 31 deletions
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 857fee1818..b8ade1684a 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -12,10 +12,10 @@
#include <script/standard.h>
#include <uint256.h>
+#include <common/args.h>
#include <span.h>
#include <util/bip32.h>
#include <util/spanparsing.h>
-#include <util/system.h>
#include <util/strencodings.h>
#include <util/vector.h>
@@ -197,7 +197,9 @@ public:
/** Get the descriptor string form including private data (if available in arg). */
virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
- /** Get the descriptor string form with the xpub at the last hardened derivation */
+ /** Get the descriptor string form with the xpub at the last hardened derivation,
+ * and always use h for hardened derivation.
+ */
virtual bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache = nullptr) const = 0;
/** Derive a private key, if private data is available in arg. */
@@ -208,14 +210,15 @@ class OriginPubkeyProvider final : public PubkeyProvider
{
KeyOriginInfo m_origin;
std::unique_ptr<PubkeyProvider> m_provider;
+ bool m_apostrophe;
- std::string OriginString() const
+ std::string OriginString(bool normalized=false) const
{
- return HexStr(m_origin.fingerprint) + FormatHDKeypath(m_origin.path);
+ return HexStr(m_origin.fingerprint) + FormatHDKeypath(m_origin.path, /*apostrophe=*/!normalized && m_apostrophe);
}
public:
- OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)) {}
+ OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider, bool apostrophe) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)), m_apostrophe(apostrophe) {}
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
{
if (!m_provider->GetPubKey(pos, arg, key, info, read_cache, write_cache)) return false;
@@ -242,9 +245,9 @@ public:
// and append that to our own origin string.
if (sub[0] == '[') {
sub = sub.substr(9);
- ret = "[" + OriginString() + std::move(sub);
+ ret = "[" + OriginString(/*normalized=*/true) + std::move(sub);
} else {
- ret = "[" + OriginString() + "]" + std::move(sub);
+ ret = "[" + OriginString(/*normalized=*/true) + "]" + std::move(sub);
}
return true;
}
@@ -312,6 +315,8 @@ class BIP32PubkeyProvider final : public PubkeyProvider
CExtPubKey m_root_extkey;
KeyPath m_path;
DeriveType m_derive;
+ // Whether ' or h is used in harded derivation
+ bool m_apostrophe;
bool GetExtKey(const SigningProvider& arg, CExtKey& ret) const
{
@@ -348,7 +353,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
}
public:
- BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
+ BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive, bool apostrophe) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive), m_apostrophe(apostrophe) {}
bool IsRange() const override { return m_derive != DeriveType::NO; }
size_t GetSize() const override { return 33; }
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key_out, KeyOriginInfo& final_info_out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
@@ -416,31 +421,36 @@ public:
return true;
}
- std::string ToString() const override
+ std::string ToString(bool normalized) const
{
- std::string ret = EncodeExtPubKey(m_root_extkey) + FormatHDKeypath(m_path);
+ const bool use_apostrophe = !normalized && m_apostrophe;
+ std::string ret = EncodeExtPubKey(m_root_extkey) + FormatHDKeypath(m_path, /*apostrophe=*/use_apostrophe);
if (IsRange()) {
ret += "/*";
- if (m_derive == DeriveType::HARDENED) ret += '\'';
+ if (m_derive == DeriveType::HARDENED) ret += use_apostrophe ? '\'' : 'h';
}
return ret;
}
+ std::string ToString() const override
+ {
+ return ToString(/*normalized=*/false);
+ }
bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
{
CExtKey key;
if (!GetExtKey(arg, key)) return false;
- out = EncodeExtKey(key) + FormatHDKeypath(m_path);
+ out = EncodeExtKey(key) + FormatHDKeypath(m_path, /*apostrophe=*/m_apostrophe);
if (IsRange()) {
out += "/*";
- if (m_derive == DeriveType::HARDENED) out += '\'';
+ if (m_derive == DeriveType::HARDENED) out += m_apostrophe ? '\'' : 'h';
}
return true;
}
bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache) const override
{
- // For hardened derivation type, just return the typical string, nothing to normalize
if (m_derive == DeriveType::HARDENED) {
- out = ToString();
+ out = ToString(/*normalized=*/true);
+
return true;
}
// Step backwards to find the last hardened step in the path
@@ -830,6 +840,7 @@ protected:
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override {
CScript ret;
std::vector<XOnlyPubKey> xkeys;
+ xkeys.reserve(keys.size());
for (const auto& key : keys) xkeys.emplace_back(key);
if (m_sorted) std::sort(xkeys.begin(), xkeys.end());
ret << ToByteVector(xkeys[0]) << OP_CHECKSIG;
@@ -1048,15 +1059,27 @@ enum class ParseScriptContext {
P2TR, //!< Inside tr() (either internal key, or BIP342 script leaf)
};
-/** Parse a key path, being passed a split list of elements (the first element is ignored). */
-[[nodiscard]] bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, std::string& error)
+/**
+ * Parse a key path, being passed a split list of elements (the first element is ignored).
+ *
+ * @param[in] split BIP32 path string, using either ' or h for hardened derivation
+ * @param[out] out the key path
+ * @param[out] apostrophe only updated if hardened derivation is found
+ * @param[out] error parsing error message
+ * @returns false if parsing failed
+ **/
+[[nodiscard]] bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, bool& apostrophe, std::string& error)
{
for (size_t i = 1; i < split.size(); ++i) {
Span<const char> elem = split[i];
bool hardened = false;
- if (elem.size() > 0 && (elem[elem.size() - 1] == '\'' || elem[elem.size() - 1] == 'h')) {
- elem = elem.first(elem.size() - 1);
- hardened = true;
+ if (elem.size() > 0) {
+ const char last = elem[elem.size() - 1];
+ if (last == '\'' || last == 'h') {
+ elem = elem.first(elem.size() - 1);
+ hardened = true;
+ apostrophe = last == '\'';
+ }
}
uint32_t p;
if (!ParseUInt32(std::string(elem.begin(), elem.end()), &p)) {
@@ -1072,7 +1095,7 @@ enum class ParseScriptContext {
}
/** Parse a public key that excludes origin information. */
-std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
+std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, bool& apostrophe, std::string& error)
{
using namespace spanparsing;
@@ -1129,15 +1152,16 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
split.pop_back();
type = DeriveType::UNHARDENED;
} else if (split.back() == Span{"*'"}.first(2) || split.back() == Span{"*h"}.first(2)) {
+ apostrophe = split.back() == Span{"*'"}.first(2);
split.pop_back();
type = DeriveType::HARDENED;
}
- if (!ParseKeyPath(split, path, error)) return nullptr;
+ if (!ParseKeyPath(split, path, apostrophe, error)) return nullptr;
if (extkey.key.IsValid()) {
extpubkey = extkey.Neuter();
out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key);
}
- return std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type);
+ return std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type, apostrophe);
}
/** Parse a public key including origin information (if enabled). */
@@ -1150,7 +1174,11 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
error = "Multiple ']' characters found for a single pubkey";
return nullptr;
}
- if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], ctx, out, error);
+ // This is set if either the origin or path suffix contains a hardened derivation.
+ bool apostrophe = false;
+ if (origin_split.size() == 1) {
+ return ParsePubkeyInner(key_exp_index, origin_split[0], ctx, out, apostrophe, error);
+ }
if (origin_split[0].empty() || origin_split[0][0] != '[') {
error = strprintf("Key origin start '[ character expected but not found, got '%c' instead",
origin_split[0].empty() ? /** empty, implies split char */ ']' : origin_split[0][0]);
@@ -1171,10 +1199,10 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
static_assert(sizeof(info.fingerprint) == 4, "Fingerprint must be 4 bytes");
assert(fpr_bytes.size() == 4);
std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint);
- if (!ParseKeyPath(slash_split, info.path, error)) return nullptr;
- auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, error);
+ if (!ParseKeyPath(slash_split, info.path, apostrophe, error)) return nullptr;
+ auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, apostrophe, error);
if (!provider) return nullptr;
- return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider));
+ return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider), apostrophe);
}
std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
@@ -1182,7 +1210,7 @@ std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptCo
std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, false);
KeyOriginInfo info;
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
- return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
+ return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider), /*apostrophe=*/false);
}
return key_provider;
}
@@ -1195,7 +1223,7 @@ std::unique_ptr<PubkeyProvider> InferXOnlyPubkey(const XOnlyPubKey& xkey, ParseS
std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, true);
KeyOriginInfo info;
if (provider.GetKeyOriginByXOnly(xkey, info)) {
- return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
+ return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider), /*apostrophe=*/false);
}
return key_provider;
}
diff --git a/src/script/miniscript.h b/src/script/miniscript.h
index bb42bf3c92..7c1a87a7dc 100644
--- a/src/script/miniscript.h
+++ b/src/script/miniscript.h
@@ -1194,7 +1194,7 @@ public:
case Fragment::OR_I:
return subs[0] || subs[1];
case Fragment::THRESH:
- return std::count(subs.begin(), subs.end(), true) >= node.k;
+ return static_cast<uint32_t>(std::count(subs.begin(), subs.end(), true)) >= node.k;
default: // wrappers
assert(subs.size() == 1);
return subs[0];
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index fef3601887..7c6c282cc4 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -5,10 +5,11 @@
#include <script/sigcache.h>
+#include <common/system.h>
+#include <logging.h>
#include <pubkey.h>
#include <random.h>
#include <uint256.h>
-#include <util/system.h>
#include <cuckoocache.h>