Merge 3caee16946 into merged_master (Bitcoin PR #19953)

Taproot :D
This commit is contained in:
Andrew Poelstra 2020-12-01 02:54:57 +00:00
commit e765fc93ea
45 changed files with 3034 additions and 139 deletions

View file

@ -350,13 +350,10 @@ public:
};
}
/** Helper for OP_CHECKSIG and OP_CHECKSIGVERIFY
*
* A return value of false means the script fails entirely. When true is returned, the
* fSuccess variable indicates whether the signature check itself succeeded.
*/
static bool EvalChecksig(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
{
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0);
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
@ -371,7 +368,7 @@ static bool EvalChecksig(const valtype& vchSig, const valtype& vchPubKey, CScrip
//serror is set
return false;
}
fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
fSuccess = checker.CheckECDSASignature(vchSig, vchPubKey, scriptCode, sigversion);
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size())
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
@ -379,7 +376,67 @@ static bool EvalChecksig(const valtype& vchSig, const valtype& vchPubKey, CScrip
return true;
}
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
{
assert(sigversion == SigVersion::TAPSCRIPT);
/*
* The following validation sequence is consensus critical. Please note how --
* upgradable public key versions precede other rules;
* the script execution fails when using empty signature with invalid public key;
* the script execution fails when using non-empty invalid signature.
*/
success = !sig.empty();
if (success) {
// Implement the sigops/witnesssize ratio test.
// Passing with an upgradable public key version is also counted.
assert(execdata.m_validation_weight_left_init);
execdata.m_validation_weight_left -= VALIDATION_WEIGHT_PER_SIGOP_PASSED;
if (execdata.m_validation_weight_left < 0) {
return set_error(serror, SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT);
}
}
if (pubkey.size() == 0) {
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
} else if (pubkey.size() == 32) {
if (success && !checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata, serror)) {
return false; // serror is set
}
} else {
/*
* New public key version softforks should be defined before this `else` block.
* Generally, the new code should not do anything but failing the script execution. To avoid
* consensus bugs, it should not modify any existing values (including `success`).
*/
if ((flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE) != 0) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE);
}
}
return true;
}
/** Helper for OP_CHECKSIG, OP_CHECKSIGVERIFY, and (in Tapscript) OP_CHECKSIGADD.
*
* A return value of false means the script fails entirely. When true is returned, the
* success variable indicates whether the signature check itself succeeded.
*/
static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
{
switch (sigversion) {
case SigVersion::BASE:
case SigVersion::WITNESS_V0:
return EvalChecksigPreTapscript(sig, pubkey, pbegincodehash, pend, flags, checker, sigversion, serror, success);
case SigVersion::TAPSCRIPT:
return EvalChecksigTapscript(sig, pubkey, execdata, flags, checker, sigversion, serror, success);
case SigVersion::TAPROOT:
// Key path spending in Taproot has no script, so this is unreachable.
break;
}
assert(false);
}
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
@ -389,6 +446,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
static const valtype vchZero(0);
static const valtype vchTrue(1, 1);
// sigversion cannot be TAPROOT here, as it admits no script execution.
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0 || sigversion == SigVersion::TAPSCRIPT);
CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end();
CScript::const_iterator pbegincodehash = script.begin();
@ -397,15 +457,18 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
ConditionStack vfExec;
std::vector<valtype> altstack;
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
if (script.size() > MAX_SCRIPT_SIZE)
if ((sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) && script.size() > MAX_SCRIPT_SIZE) {
return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);
}
int nOpCount = 0;
bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0;
uint32_t opcode_pos = 0;
execdata.m_codeseparator_pos = 0xFFFFFFFFUL;
execdata.m_codeseparator_pos_init = true;
try
{
while (pc < pend)
{
for (; pc < pend; ++opcode_pos) {
bool fExec = vfExec.all_true();
//
@ -416,9 +479,12 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE)
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
// Note how OP_RESERVED does not count towards the opcode limit.
if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT)
return set_error(serror, SCRIPT_ERR_OP_COUNT);
if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) {
// Note how OP_RESERVED does not count towards the opcode limit.
if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) {
return set_error(serror, SCRIPT_ERR_OP_COUNT);
}
}
// ELEMENTS:
// commented out opcodes are re-enabled in Elements
@ -580,6 +646,15 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
if (stack.size() < 1)
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
valtype& vch = stacktop(-1);
// Tapscript requires minimal IF/NOTIF inputs as a consensus rule.
if (sigversion == SigVersion::TAPSCRIPT) {
// The input argument to the OP_IF and OP_NOTIF opcodes must be either
// exactly 0 (the empty vector) or exactly 1 (the one-byte vector with value 1).
if (vch.size() > 1 || (vch.size() == 1 && vch[0] != 1)) {
return set_error(serror, SCRIPT_ERR_TAPSCRIPT_MINIMALIF);
}
}
// Under witness v0 rules it is only a policy rule, enabled through SCRIPT_VERIFY_MINIMALIF.
if (sigversion == SigVersion::WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) {
if (vch.size() > 1)
return set_error(serror, SCRIPT_ERR_MINIMALIF);
@ -1279,6 +1354,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
// Hash starts after the code separator
pbegincodehash = pc;
execdata.m_codeseparator_pos = opcode_pos;
}
break;
@ -1293,7 +1369,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
valtype& vchPubKey = stacktop(-1);
bool fSuccess = true;
if (!EvalChecksig(vchSig, vchPubKey, pbegincodehash, pend, flags, checker, sigversion, serror, fSuccess)) return false;
if (!EvalChecksig(vchSig, vchPubKey, pbegincodehash, pend, execdata, flags, checker, sigversion, serror, fSuccess)) return false;
popstack(stack);
popstack(stack);
stack.push_back(fSuccess ? vchTrue : vchFalse);
@ -1307,9 +1383,32 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
}
break;
case OP_CHECKSIGADD:
{
// OP_CHECKSIGADD is only available in Tapscript
if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
// (sig num pubkey -- num)
if (stack.size() < 3) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
const valtype& sig = stacktop(-3);
const CScriptNum num(stacktop(-2), fRequireMinimal);
const valtype& pubkey = stacktop(-1);
bool success = true;
if (!EvalChecksig(sig, pubkey, pbegincodehash, pend, execdata, flags, checker, sigversion, serror, success)) return false;
popstack(stack);
popstack(stack);
popstack(stack);
stack.push_back((num + (success ? 1 : 0)).getvch());
}
break;
case OP_CHECKMULTISIG:
case OP_CHECKMULTISIGVERIFY:
{
if (sigversion == SigVersion::TAPSCRIPT) return set_error(serror, SCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG);
// ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
int i = 1;
@ -1367,7 +1466,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
}
// Check signature
bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
bool fOk = checker.CheckECDSASignature(vchSig, vchPubKey, scriptCode, sigversion);
if (fOk) {
isig++;
@ -1528,6 +1627,12 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
return set_success(serror);
}
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
ScriptExecutionData execdata;
return EvalScript(stack, script, flags, checker, sigversion, execdata, serror);
}
namespace {
/**
@ -1678,36 +1783,184 @@ uint256 GetOutputsSHA256(const T& txTo)
return ss.GetSHA256();
}
/** Compute the (single) SHA256 of the concatenation of all amounts spent by a tx. */
uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txout : outputs_spent) {
ss << txout.nValue;
}
return ss.GetSHA256();
}
/** Compute the (single) SHA256 of the concatenation of all scriptPubKeys spent by a tx. */
uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txout : outputs_spent) {
ss << txout.scriptPubKey;
}
return ss.GetSHA256();
}
} // namespace
template <class T>
void PrecomputedTransactionData::Init(const T& txTo)
void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent_outputs)
{
assert(!m_ready);
assert(!m_spent_outputs_ready);
// Cache is calculated only for transactions with witness
if (txTo.HasWitness()) {
hashPrevouts = SHA256Uint256(GetPrevoutsSHA256(txTo));
hashSequence = SHA256Uint256(GetSequencesSHA256(txTo));
hashIssuance = SHA256Uint256(GetIssuanceSHA256(txTo));
hashOutputs = SHA256Uint256(GetOutputsSHA256(txTo));
m_spent_outputs = std::move(spent_outputs);
if (!m_spent_outputs.empty()) {
assert(m_spent_outputs.size() == txTo.vin.size());
m_spent_outputs_ready = true;
}
m_ready = true;
// Determine which precomputation-impacting features this transaction uses.
bool uses_bip143_segwit = false;
bool uses_bip341_taproot = false;
for (size_t inpos = 0; inpos < txTo.vin.size(); ++inpos) {
if (inpos < txTo.witness.vtxinwit.size() && !txTo.witness.vtxinwit[inpos].scriptWitness.IsNull()) {
if (m_spent_outputs_ready && m_spent_outputs[inpos].scriptPubKey.size() == 2 + WITNESS_V1_TAPROOT_SIZE &&
m_spent_outputs[inpos].scriptPubKey[0] == OP_1) {
// Treat every witness-bearing spend with 34-byte scriptPubKey that starts with OP_1 as a Taproot
// spend. This only works if spent_outputs was provided as well, but if it wasn't, actual validation
// will fail anyway. Note that this branch may trigger for scriptPubKeys that aren't actually segwit
// but in that case validation will fail as SCRIPT_ERR_WITNESS_UNEXPECTED anyway.
uses_bip341_taproot = true;
} else {
// Treat every spend that's not known to native witness v1 as a Witness v0 spend. This branch may
// also be taken for unknown witness versions, but it is harmless, and being precise would require
// P2SH evaluation to find the redeemScript.
uses_bip143_segwit = true;
}
}
if (uses_bip341_taproot && uses_bip143_segwit) break; // No need to scan further if we already need all.
}
if (uses_bip143_segwit || uses_bip341_taproot) {
// Computations shared between both sighash schemes.
m_prevouts_single_hash = GetPrevoutsSHA256(txTo);
m_sequences_single_hash = GetSequencesSHA256(txTo);
m_outputs_single_hash = GetOutputsSHA256(txTo);
}
if (uses_bip143_segwit) {
hashPrevouts = SHA256Uint256(m_prevouts_single_hash);
hashSequence = SHA256Uint256(m_sequences_single_hash);
hashIssuance = SHA256Uint256(GetIssuanceSHA256(txTo));
hashOutputs = SHA256Uint256(m_outputs_single_hash);
m_bip143_segwit_ready = true;
}
if (uses_bip341_taproot) {
m_spent_amounts_single_hash = GetSpentAmountsSHA256(m_spent_outputs);
m_spent_scripts_single_hash = GetSpentScriptsSHA256(m_spent_outputs);
m_bip341_taproot_ready = true;
}
}
template <class T>
PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
{
Init(txTo);
Init(txTo, {});
}
// explicit instantiation
template void PrecomputedTransactionData::Init(const CTransaction& txTo);
template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo);
template void PrecomputedTransactionData::Init(const CTransaction& txTo, std::vector<CTxOut>&& spent_outputs);
template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo, std::vector<CTxOut>&& spent_outputs);
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
static const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
static const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf");
static const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch");
static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak");
template<typename T>
bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache)
{
uint8_t ext_flag, key_version;
switch (sigversion) {
case SigVersion::TAPROOT:
ext_flag = 0;
// key_version is not used and left uninitialized.
break;
case SigVersion::TAPSCRIPT:
ext_flag = 1;
// key_version must be 0 for now, representing the current version of
// 32-byte public keys in the tapscript signature opcode execution.
// An upgradable public key version (with a size not 32-byte) may
// request a different key_version with a new sigversion.
key_version = 0;
break;
default:
assert(false);
}
assert(in_pos < tx_to.vin.size());
assert(cache.m_bip341_taproot_ready && cache.m_spent_outputs_ready);
CHashWriter ss = HASHER_TAPSIGHASH;
// Epoch
static constexpr uint8_t EPOCH = 0;
ss << EPOCH;
// Hash type
const uint8_t output_type = (hash_type == SIGHASH_DEFAULT) ? SIGHASH_ALL : (hash_type & SIGHASH_OUTPUT_MASK); // Default (no sighash byte) is equivalent to SIGHASH_ALL
const uint8_t input_type = hash_type & SIGHASH_INPUT_MASK;
if (!(hash_type <= 0x03 || (hash_type >= 0x81 && hash_type <= 0x83))) return false;
ss << hash_type;
// Transaction level data
ss << tx_to.nVersion;
ss << tx_to.nLockTime;
if (input_type != SIGHASH_ANYONECANPAY) {
ss << cache.m_prevouts_single_hash;
ss << cache.m_spent_amounts_single_hash;
ss << cache.m_spent_scripts_single_hash;
ss << cache.m_sequences_single_hash;
}
if (output_type == SIGHASH_ALL) {
ss << cache.m_outputs_single_hash;
}
// Data about the input/prevout being spent
assert(execdata.m_annex_init);
const bool have_annex = execdata.m_annex_present;
const uint8_t spend_type = (ext_flag << 1) + (have_annex ? 1 : 0); // The low bit indicates whether an annex is present.
ss << spend_type;
if (input_type == SIGHASH_ANYONECANPAY) {
ss << tx_to.vin[in_pos].prevout;
ss << cache.m_spent_outputs[in_pos];
ss << tx_to.vin[in_pos].nSequence;
} else {
ss << in_pos;
}
if (have_annex) {
ss << execdata.m_annex_hash;
}
// Data about the output (if only one).
if (output_type == SIGHASH_SINGLE) {
if (in_pos >= tx_to.vout.size()) return false;
CHashWriter sha_single_output(SER_GETHASH, 0);
sha_single_output << tx_to.vout[in_pos];
ss << sha_single_output.GetSHA256();
}
// Additional data for BIP 342 signatures
if (sigversion == SigVersion::TAPSCRIPT) {
assert(execdata.m_tapleaf_hash_init);
ss << execdata.m_tapleaf_hash;
ss << key_version;
assert(execdata.m_codeseparator_pos_init);
ss << execdata.m_codeseparator_pos;
}
hash_out = ss.GetSHA256();
return true;
}
template <class T>
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
@ -1718,7 +1971,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
uint256 hashSequence;
uint256 hashIssuance;
uint256 hashOutputs;
const bool cacheready = cache && cache->m_ready;
const bool cacheready = cache && cache->m_bip143_segwit_ready;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
hashPrevouts = cacheready ? cache->hashPrevouts : SHA256Uint256(GetPrevoutsSHA256(txTo));
@ -1792,13 +2045,19 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
}
template <class T>
bool GenericTransactionSignatureChecker<T>::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
bool GenericTransactionSignatureChecker<T>::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
{
return pubkey.Verify(sighash, vchSig);
}
template <class T>
bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
bool GenericTransactionSignatureChecker<T>::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const
{
return pubkey.VerifySchnorr(sighash, sig);
}
template <class T>
bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
@ -1813,12 +2072,40 @@ bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
if (!VerifySignature(vchSig, pubkey, sighash))
if (!VerifyECDSASignature(vchSig, pubkey, sighash))
return false;
return true;
}
template <class T>
bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey_in, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror) const
{
assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT);
// Schnorr signatures have 32-byte public keys. The caller is responsible for enforcing this.
assert(pubkey_in.size() == 32);
// Note that in Tapscript evaluation, empty signatures are treated specially (invalid signature that does not
// abort script execution). This is implemented in EvalChecksigTapscript, which won't invoke
// CheckSchnorrSignature in that case. In other contexts, they are invalid like every other signature with
// size different from 64 or 65.
if (sig.size() != 64 && sig.size() != 65) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_SIZE);
XOnlyPubKey pubkey{pubkey_in};
uint8_t hashtype = SIGHASH_DEFAULT;
if (sig.size() == 65) {
hashtype = SpanPopBack(sig);
if (hashtype == SIGHASH_DEFAULT) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE);
}
uint256 sighash;
assert(this->txdata);
if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, *this->txdata)) {
return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE);
}
if (!VerifySchnorrSignature(sig, pubkey, sighash)) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG);
return true;
}
template <class T>
bool GenericTransactionSignatureChecker<T>::CheckLockTime(const CScriptNum& nLockTime) const
{
@ -1907,17 +2194,39 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
template class GenericTransactionSignatureChecker<CTransaction>;
template class GenericTransactionSignatureChecker<CMutableTransaction>;
static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptError* serror)
static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
{
std::vector<valtype> stack{stack_span.begin(), stack_span.end()};
if (sigversion == SigVersion::TAPSCRIPT) {
// OP_SUCCESSx processing overrides everything, including stack element size limits
CScript::const_iterator pc = scriptPubKey.begin();
while (pc < scriptPubKey.end()) {
opcodetype opcode;
if (!scriptPubKey.GetOp(pc, opcode)) {
// Note how this condition would not be reached if an unknown OP_SUCCESSx was found
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
// New opcodes will be listed here. May use a different sigversion to modify existing opcodes.
if (IsOpSuccess(opcode)) {
if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS);
}
return set_success(serror);
}
}
// Tapscript enforces initial stack size limits (altstack is empty here)
if (stack.size() > MAX_STACK_SIZE) return set_error(serror, SCRIPT_ERR_STACK_SIZE);
}
// Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack
for (const valtype& elem : stack) {
if (elem.size() > MAX_SCRIPT_ELEMENT_SIZE) return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
}
// Run the script interpreter.
if (!EvalScript(stack, scriptPubKey, flags, checker, sigversion, serror)) return false;
if (!EvalScript(stack, scriptPubKey, flags, checker, sigversion, execdata, serror)) return false;
// Scripts inside witness implicitly require cleanstack behaviour
if (stack.size() != 1) return set_error(serror, SCRIPT_ERR_CLEANSTACK);
@ -1925,40 +2234,104 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
return true;
}
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, const std::vector<unsigned char>& program, const CScript& script, uint256& tapleaf_hash)
{
CScript scriptPubKey;
const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
const XOnlyPubKey p{uint256(std::vector<unsigned char>(control.begin() + 1, control.begin() + TAPROOT_CONTROL_BASE_SIZE))};
const XOnlyPubKey q{uint256(program)};
tapleaf_hash = (CHashWriter(HASHER_TAPLEAF) << uint8_t(control[0] & TAPROOT_LEAF_MASK) << script).GetSHA256();
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);
if (std::lexicographical_compare(k.begin(), k.end(), node.begin(), node.end())) {
ss_branch << k << node;
} else {
ss_branch << node << k;
}
k = ss_branch.GetSHA256();
}
k = (CHashWriter(HASHER_TAPTWEAK) << MakeSpan(p) << k).GetSHA256();
return q.CheckPayToContract(p, k, control[0] & 1);
}
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};
ScriptExecutionData execdata;
if (witversion == 0) {
if (program.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
// Version 0 segregated witness program: SHA256(CScript) inside the program, CScript + inputs in witness
// BIP141 P2WSH: 32-byte witness v0 program (which encodes SHA256(script))
if (stack.size() == 0) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY);
}
const valtype& script_bytes = SpanPopBack(stack);
scriptPubKey = CScript(script_bytes.begin(), script_bytes.end());
uint256 hashScriptPubKey;
CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) {
exec_script = CScript(script_bytes.begin(), script_bytes.end());
uint256 hash_exec_script;
CSHA256().Write(&exec_script[0], exec_script.size()).Finalize(hash_exec_script.begin());
if (memcmp(hash_exec_script.begin(), program.data(), 32)) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
}
return ExecuteWitnessScript(stack, scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror);
return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::WITNESS_V0, checker, execdata, serror);
} else if (program.size() == WITNESS_V0_KEYHASH_SIZE) {
// Special case for pay-to-pubkeyhash; signature + pubkey in witness
// BIP141 P2WPKH: 20-byte witness v0 program (which encodes Hash160(pubkey))
if (stack.size() != 2) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness
}
scriptPubKey << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG;
return ExecuteWitnessScript(stack, scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror);
exec_script << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG;
return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::WITNESS_V0, checker, execdata, serror);
} else {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH);
}
} else if (witversion == 1 && program.size() == WITNESS_V1_TAPROOT_SIZE && !is_p2sh) {
// BIP341 Taproot: 32-byte non-P2SH witness v1 program (which encodes a P2C-tweaked pubkey)
if (!(flags & SCRIPT_VERIFY_TAPROOT)) return set_success(serror);
if (stack.size() == 0) return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY);
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
// Drop annex (this is non-standard; see IsWitnessStandard)
const valtype& annex = SpanPopBack(stack);
execdata.m_annex_hash = (CHashWriter(SER_GETHASH, 0) << annex).GetSHA256();
execdata.m_annex_present = true;
} else {
execdata.m_annex_present = false;
}
execdata.m_annex_init = true;
if (stack.size() == 1) {
// Key path spending (stack size is 1 after removing optional annex)
if (!checker.CheckSchnorrSignature(stack.front(), program, SigVersion::TAPROOT, execdata, serror)) {
return false; // serror is set
}
return set_success(serror);
} else {
// Script path spending (stack size is >1 after removing optional annex)
const valtype& control = SpanPopBack(stack);
const valtype& script_bytes = SpanPopBack(stack);
exec_script = CScript(script_bytes.begin(), script_bytes.end());
if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > TAPROOT_CONTROL_MAX_SIZE || ((control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) {
return set_error(serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE);
}
if (!VerifyTaprootCommitment(control, program, exec_script, execdata.m_tapleaf_hash)) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
}
execdata.m_tapleaf_hash_init = true;
if ((control[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
// Tapscript (leaf version 0xc0)
execdata.m_validation_weight_left = ::GetSerializeSize(witness.stack, PROTOCOL_VERSION) + VALIDATION_WEIGHT_OFFSET;
execdata.m_validation_weight_left_init = true;
return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::TAPSCRIPT, checker, execdata, serror);
}
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION);
}
return set_success(serror);
}
} else {
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
}
// Higher version witness scripts return true for future softfork compatibility
// Other version/size/p2sh combinations return true for future softfork compatibility
return true;
}
// There is intentionally no return statement here, to be able to use "control reaches end of non-void function" warnings to detect gaps in the logic above.
@ -2004,7 +2377,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
// The scriptSig must be _exactly_ CScript(), otherwise we reintroduce malleability.
return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED);
}
if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror)) {
if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror, /* is_p2sh */ false)) {
return false;
}
// Bypass the cleanstack check at the end. The actual stack is obviously not clean
@ -2049,7 +2422,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
// reintroduce malleability.
return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED_P2SH);
}
if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror)) {
if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror, /* is_p2sh */ true)) {
return false;
}
// Bypass the cleanstack check at the end. The actual stack is obviously not clean