aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/descriptor.cpp9
-rw-r--r--src/script/interpreter.cpp8
-rw-r--r--src/script/interpreter.h1
-rw-r--r--src/script/keyorigin.h19
-rw-r--r--src/script/sign.cpp19
-rw-r--r--src/script/sign.h80
-rw-r--r--src/script/signingprovider.cpp14
-rw-r--r--src/script/signingprovider.h3
-rw-r--r--src/script/standard.cpp41
-rw-r--r--src/script/standard.h18
10 files changed, 56 insertions, 156 deletions
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 621a1b9fd6..30f929664f 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -631,7 +631,7 @@ public:
out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
}
- output_scripts = MakeScripts(pubkeys, MakeSpan(subscripts), out);
+ output_scripts = MakeScripts(pubkeys, Span{subscripts}, out);
return true;
}
@@ -851,6 +851,7 @@ protected:
builder.Finalize(xpk);
WitnessV1Taproot output = builder.GetOutput();
out.tr_spenddata[output].Merge(builder.GetSpendData());
+ out.pubkeys.emplace(keys[0].GetID(), keys[0]);
return Vector(GetScriptForDestination(output));
}
bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override
@@ -973,10 +974,10 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
}
KeyPath path;
DeriveType type = DeriveType::NO;
- if (split.back() == MakeSpan("*").first(1)) {
+ if (split.back() == Span{"*"}.first(1)) {
split.pop_back();
type = DeriveType::UNHARDENED;
- } else if (split.back() == MakeSpan("*'").first(2) || split.back() == MakeSpan("*h").first(2)) {
+ } else if (split.back() == Span{"*'"}.first(2) || split.back() == Span{"*h"}.first(2)) {
split.pop_back();
type = DeriveType::HARDENED;
}
@@ -1251,7 +1252,7 @@ std::unique_ptr<PubkeyProvider> InferXOnlyPubkey(const XOnlyPubKey& xkey, ParseS
std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
{
if (ctx == ParseScriptContext::P2TR && script.size() == 34 && script[0] == 32 && script[33] == OP_CHECKSIG) {
- XOnlyPubKey key{Span<const unsigned char>{script.data() + 1, script.data() + 33}};
+ XOnlyPubKey key{Span{script}.subspan(1, 32)};
return std::make_unique<PKDescriptor>(InferXOnlyPubkey(key, ctx, provider));
}
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index eafa9840d7..6433ba1b58 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1483,7 +1483,7 @@ template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo,
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
-static const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
+const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf");
const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch");
@@ -1858,7 +1858,7 @@ uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint25
uint256 k = tapleaf_hash;
for (int i = 0; i < path_len; ++i) {
CHashWriter ss_branch{HASHER_TAPBRANCH};
- Span<const unsigned char> node(control.data() + TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE);
+ Span node{Span{control}.subspan(TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE)};
if (std::lexicographical_compare(k.begin(), k.end(), node.begin(), node.end())) {
ss_branch << k << node;
} else {
@@ -1874,7 +1874,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
assert(control.size() >= TAPROOT_CONTROL_BASE_SIZE);
assert(program.size() >= uint256::size());
//! The internal pubkey (x-only, so no Y coordinate parity).
- const XOnlyPubKey p{Span<const unsigned char>{control.data() + 1, control.data() + TAPROOT_CONTROL_BASE_SIZE}};
+ const XOnlyPubKey p{Span{control}.subspan(1, TAPROOT_CONTROL_BASE_SIZE - 1)};
//! The output pubkey (taken from the scriptPubKey).
const XOnlyPubKey q{program};
// Compute the Merkle root from the leaf and the provided path.
@@ -1886,7 +1886,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
{
CScript exec_script; //!< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH; leaf script in P2TR)
- Span<const valtype> stack{witness.stack};
+ Span stack{witness.stack};
ScriptExecutionData execdata;
if (witversion == 0) {
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index ab49e84577..513eaaf94c 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -229,6 +229,7 @@ static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32;
static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128;
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT;
+extern const CHashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it.
extern const CHashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
extern const CHashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
diff --git a/src/script/keyorigin.h b/src/script/keyorigin.h
index 210395d177..c779872be2 100644
--- a/src/script/keyorigin.h
+++ b/src/script/keyorigin.h
@@ -18,6 +18,25 @@ struct KeyOriginInfo
return std::equal(std::begin(a.fingerprint), std::end(a.fingerprint), std::begin(b.fingerprint)) && a.path == b.path;
}
+ friend bool operator<(const KeyOriginInfo& a, const KeyOriginInfo& b)
+ {
+ // Compare the fingerprints lexicographically
+ int fpr_cmp = memcmp(a.fingerprint, b.fingerprint, 4);
+ if (fpr_cmp < 0) {
+ return true;
+ } else if (fpr_cmp > 0) {
+ return false;
+ }
+ // Compare the sizes of the paths, shorter is "less than"
+ if (a.path.size() < b.path.size()) {
+ return true;
+ } else if (a.path.size() > b.path.size()) {
+ return false;
+ }
+ // Paths same length, compare them lexicographically
+ return a.path < b.path;
+ }
+
SERIALIZE_METHODS(KeyOriginInfo, obj) { READWRITE(obj.fingerprint, obj.path); }
void clear()
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index b912b00365..d33c847d98 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -5,9 +5,11 @@
#include <script/sign.h>
+#include <consensus/amount.h>
#include <key.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
+#include <script/keyorigin.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <uint256.h>
@@ -16,16 +18,16 @@
typedef std::vector<unsigned char> valtype;
-MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn)
- : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn, MissingDataBehavior::FAIL),
+MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, int hash_type)
+ : txTo{tx}, nIn{input_idx}, nHashType{hash_type}, amount{amount}, checker{txTo, nIn, amount, MissingDataBehavior::FAIL},
m_txdata(nullptr)
{
}
-MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData* txdata, int nHashTypeIn)
- : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn),
- checker(txdata ? MutableTransactionSignatureChecker(txTo, nIn, amount, *txdata, MissingDataBehavior::FAIL) :
- MutableTransactionSignatureChecker(txTo, nIn, amount, MissingDataBehavior::FAIL)),
+MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, const PrecomputedTransactionData* txdata, int hash_type)
+ : txTo{tx}, nIn{input_idx}, nHashType{hash_type}, amount{amount},
+ checker{txdata ? MutableTransactionSignatureChecker{txTo, nIn, amount, *txdata, MissingDataBehavior::FAIL} :
+ MutableTransactionSignatureChecker{txTo, nIn, amount, MissingDataBehavior::FAIL}},
m_txdata(txdata)
{
}
@@ -80,7 +82,8 @@ bool MutableTransactionSignatureCreator::CreateSchnorrSig(const SigningProvider&
uint256 hash;
if (!SignatureHashSchnorr(hash, execdata, *txTo, nIn, nHashType, sigversion, *m_txdata, MissingDataBehavior::FAIL)) return false;
sig.resize(64);
- if (!key.SignSchnorr(hash, sig, merkle_root, nullptr)) return false;
+ // Use uint256{} as aux_rnd for now.
+ if (!key.SignSchnorr(hash, sig, merkle_root, {})) return false;
if (nHashType) sig.push_back(nHashType);
return true;
}
@@ -165,7 +168,7 @@ static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatu
// <xonly pubkey> OP_CHECKSIG
if (script.size() == 34 && script[33] == OP_CHECKSIG && script[0] == 0x20) {
- XOnlyPubKey pubkey(MakeSpan(script).subspan(1, 32));
+ XOnlyPubKey pubkey{Span{script}.subspan(1, 32)};
std::vector<unsigned char> sig;
if (CreateTaprootScriptSig(creator, sigdata, provider, sig, pubkey, leaf_hash, sigversion)) {
result = Vector(std::move(sig));
diff --git a/src/script/sign.h b/src/script/sign.h
index 6d3479c143..7e3d5e80e4 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -12,8 +12,6 @@
#include <script/interpreter.h>
#include <script/keyorigin.h>
#include <script/standard.h>
-#include <span.h>
-#include <streams.h>
class CKey;
class CKeyID;
@@ -45,8 +43,8 @@ class MutableTransactionSignatureCreator : public BaseSignatureCreator {
const PrecomputedTransactionData* m_txdata;
public:
- MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn);
- MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData* txdata, int nHashTypeIn);
+ MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, int hash_type);
+ MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, const PrecomputedTransactionData* txdata, int hash_type);
const BaseSignatureChecker& Checker() const override { return checker; }
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
bool CreateSchnorrSig(const SigningProvider& provider, std::vector<unsigned char>& sig, const XOnlyPubKey& pubkey, const uint256* leaf_hash, const uint256* merkle_root, SigVersion sigversion) const override;
@@ -84,80 +82,6 @@ struct SignatureData {
void MergeSignatureData(SignatureData sigdata);
};
-// Takes a stream and multiple arguments and serializes them as if first serialized into a vector and then into the stream
-// The resulting output into the stream has the total serialized length of all of the objects followed by all objects concatenated with each other.
-template<typename Stream, typename... X>
-void SerializeToVector(Stream& s, const X&... args)
-{
- WriteCompactSize(s, GetSerializeSizeMany(s.GetVersion(), args...));
- SerializeMany(s, args...);
-}
-
-// Takes a stream and multiple arguments and unserializes them first as a vector then each object individually in the order provided in the arguments
-template<typename Stream, typename... X>
-void UnserializeFromVector(Stream& s, X&... args)
-{
- size_t expected_size = ReadCompactSize(s);
- size_t remaining_before = s.size();
- UnserializeMany(s, args...);
- size_t remaining_after = s.size();
- if (remaining_after + expected_size != remaining_before) {
- throw std::ios_base::failure("Size of value was not the stated size");
- }
-}
-
-// Deserialize HD keypaths into a map
-template<typename Stream>
-void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
-{
- // Make sure that the key is the size of pubkey + 1
- if (key.size() != CPubKey::SIZE + 1 && key.size() != CPubKey::COMPRESSED_SIZE + 1) {
- throw std::ios_base::failure("Size of key was not the expected size for the type BIP32 keypath");
- }
- // Read in the pubkey from key
- CPubKey pubkey(key.begin() + 1, key.end());
- if (!pubkey.IsFullyValid()) {
- throw std::ios_base::failure("Invalid pubkey");
- }
- if (hd_keypaths.count(pubkey) > 0) {
- throw std::ios_base::failure("Duplicate Key, pubkey derivation path already provided");
- }
-
- // Read in key path
- uint64_t value_len = ReadCompactSize(s);
- if (value_len % 4 || value_len == 0) {
- throw std::ios_base::failure("Invalid length for HD key path");
- }
-
- KeyOriginInfo keypath;
- s >> keypath.fingerprint;
- for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) {
- uint32_t index;
- s >> index;
- keypath.path.push_back(index);
- }
-
- // Add to map
- hd_keypaths.emplace(pubkey, std::move(keypath));
-}
-
-// Serialize HD keypaths to a stream from a map
-template<typename Stream>
-void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, uint8_t type)
-{
- for (auto keypath_pair : hd_keypaths) {
- if (!keypath_pair.first.IsValid()) {
- throw std::ios_base::failure("Invalid CPubKey being serialized");
- }
- SerializeToVector(s, type, MakeSpan(keypath_pair.first));
- WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t));
- s << keypath_pair.second.fingerprint;
- for (const auto& path : keypath_pair.second.path) {
- s << path;
- }
- }
-}
-
/** Produce a script signature using a generic signature creator. */
bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata);
diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp
index b80fbe22ce..17f97fa30c 100644
--- a/src/script/signingprovider.cpp
+++ b/src/script/signingprovider.cpp
@@ -190,8 +190,8 @@ bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemS
CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)
{
- // Only supports destinations which map to single public keys, i.e. P2PKH,
- // P2WPKH, and P2SH-P2WPKH.
+ // Only supports destinations which map to single public keys:
+ // P2PKH, P2WPKH, P2SH-P2WPKH, P2TR
if (auto id = std::get_if<PKHash>(&dest)) {
return ToKeyID(*id);
}
@@ -208,5 +208,15 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination&
}
}
}
+ if (auto output_key = std::get_if<WitnessV1Taproot>(&dest)) {
+ TaprootSpendData spenddata;
+ CPubKey pub;
+ if (store.GetTaprootSpendData(*output_key, spenddata)
+ && !spenddata.internal_key.IsNull()
+ && spenddata.merkle_root.IsNull()
+ && store.GetPubKeyByXOnly(spenddata.internal_key, pub)) {
+ return pub.GetID();
+ }
+ }
return CKeyID();
}
diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h
index fbce61c6a9..b8b3e03dd3 100644
--- a/src/script/signingprovider.h
+++ b/src/script/signingprovider.h
@@ -8,12 +8,11 @@
#include <key.h>
#include <pubkey.h>
+#include <script/keyorigin.h>
#include <script/script.h>
#include <script/standard.h>
#include <sync.h>
-struct KeyOriginInfo;
-
/** An interface to be implemented by keystores that support signing. */
class SigningProvider
{
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 67a79a157c..d9656c781d 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -266,47 +266,6 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
assert(false);
}
-// TODO: from v23 ("addresses" and "reqSigs" deprecated) "ExtractDestinations" should be removed
-bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
-{
- addressRet.clear();
- std::vector<valtype> vSolutions;
- typeRet = Solver(scriptPubKey, vSolutions);
- if (typeRet == TxoutType::NONSTANDARD) {
- return false;
- } else if (typeRet == TxoutType::NULL_DATA) {
- // This is data, not addresses
- return false;
- }
-
- if (typeRet == TxoutType::MULTISIG)
- {
- nRequiredRet = vSolutions.front()[0];
- for (unsigned int i = 1; i < vSolutions.size()-1; i++)
- {
- CPubKey pubKey(vSolutions[i]);
- if (!pubKey.IsValid())
- continue;
-
- CTxDestination address = PKHash(pubKey);
- addressRet.push_back(address);
- }
-
- if (addressRet.empty())
- return false;
- }
- else
- {
- nRequiredRet = 1;
- CTxDestination address;
- if (!ExtractDestination(scriptPubKey, address))
- return false;
- addressRet.push_back(address);
- }
-
- return true;
-}
-
namespace {
class CScriptVisitor
{
diff --git a/src/script/standard.h b/src/script/standard.h
index 78492733db..a8e57231bf 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -176,28 +176,12 @@ TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned c
/**
* Parse a standard scriptPubKey for the destination address. Assigns result to
- * the addressRet parameter and returns true if successful. For multisig
- * scripts, instead use ExtractDestinations. Currently only works for P2PK,
+ * the addressRet parameter and returns true if successful. Currently only works for P2PK,
* P2PKH, P2SH, P2WPKH, and P2WSH scripts.
*/
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
/**
- * Parse a standard scriptPubKey with one or more destination addresses. For
- * multisig scripts, this populates the addressRet vector with the pubkey IDs
- * and nRequiredRet with the n required to spend. For other destinations,
- * addressRet is populated with a single value and nRequiredRet is set to 1.
- * Returns true if successful.
- *
- * Note: this function confuses destinations (a subset of CScripts that are
- * encodable as an address) with key identifiers (of keys involved in a
- * CScript), and its use should be phased out.
- *
- * TODO: from v23 ("addresses" and "reqSigs" deprecated) "ExtractDestinations" should be removed
- */
-bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
-
-/**
* Generate a Bitcoin scriptPubKey for the given CTxDestination. Returns a P2PKH
* script for a CKeyID destination, a P2SH script for a CScriptID, and an empty
* script for CNoDestination.