Skip to content

Commit 805a79a

Browse files
jl2012sipa
authored andcommitted
Implement Tapscript script validation rules (BIP 342)
This adds a new `SigVersion::TAPSCRIPT`, makes the necessary interpreter changes to make it implement BIP342, and uses them for leaf version 0xc0 in Taproot script path spends.
1 parent c79c575 commit 805a79a

File tree

6 files changed

+234
-19
lines changed

6 files changed

+234
-19
lines changed

src/script/interpreter.cpp

Lines changed: 168 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -342,13 +342,10 @@ class ConditionStack {
342342
};
343343
}
344344

345-
/** Helper for OP_CHECKSIG and OP_CHECKSIGVERIFY
346-
*
347-
* A return value of false means the script fails entirely. When true is returned, the
348-
* fSuccess variable indicates whether the signature check itself succeeded.
349-
*/
350-
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)
345+
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)
351346
{
347+
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0);
348+
352349
// Subset of script starting at the most recent codeseparator
353350
CScript scriptCode(pbegincodehash, pend);
354351

@@ -371,6 +368,66 @@ static bool EvalChecksig(const valtype& vchSig, const valtype& vchPubKey, CScrip
371368
return true;
372369
}
373370

371+
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
372+
{
373+
assert(sigversion == SigVersion::TAPSCRIPT);
374+
375+
/*
376+
* The following validation sequence is consensus critical. Please note how --
377+
* upgradable public key versions precede other rules;
378+
* the script execution fails when using empty signature with invalid public key;
379+
* the script execution fails when using non-empty invalid signature.
380+
*/
381+
success = !sig.empty();
382+
if (success) {
383+
// Implement the sigops/witnesssize ratio test.
384+
// Passing with an upgradable public key version is also counted.
385+
assert(execdata.m_validation_weight_left_init);
386+
execdata.m_validation_weight_left -= VALIDATION_WEIGHT_PER_SIGOP_PASSED;
387+
if (execdata.m_validation_weight_left < 0) {
388+
return set_error(serror, SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT);
389+
}
390+
}
391+
if (pubkey.size() == 0) {
392+
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
393+
} else if (pubkey.size() == 32) {
394+
if (success && !checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata)) {
395+
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
396+
}
397+
} else {
398+
/*
399+
* New public key version softforks should be defined before this `else` block.
400+
* Generally, the new code should not do anything but failing the script execution. To avoid
401+
* consensus bugs, it should not modify any existing values (including success).
402+
*/
403+
if ((flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE) != 0) {
404+
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE);
405+
}
406+
}
407+
408+
return true;
409+
}
410+
411+
/** Helper for OP_CHECKSIG, OP_CHECKSIGVERIFY, and (in Tapscript) OP_CHECKSIGADD.
412+
*
413+
* A return value of false means the script fails entirely. When true is returned, the
414+
* fSuccess variable indicates whether the signature check itself succeeded.
415+
*/
416+
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)
417+
{
418+
switch (sigversion) {
419+
case SigVersion::BASE:
420+
case SigVersion::WITNESS_V0:
421+
return EvalChecksigPreTapscript(sig, pubkey, pbegincodehash, pend, flags, checker, sigversion, serror, success);
422+
case SigVersion::TAPSCRIPT:
423+
return EvalChecksigTapscript(sig, pubkey, execdata, flags, checker, sigversion, serror, success);
424+
case SigVersion::TAPROOT:
425+
// Key path spending in Taproot has no script, so this is unreachable.
426+
break;
427+
}
428+
assert(false);
429+
}
430+
374431
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
375432
{
376433
static const CScriptNum bnZero(0);
@@ -381,6 +438,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
381438
// static const valtype vchZero(0);
382439
static const valtype vchTrue(1, 1);
383440

441+
// sigversion cannot be TAPROOT here, as it admits no script execution.
442+
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0 || sigversion == SigVersion::TAPSCRIPT);
443+
384444
CScript::const_iterator pc = script.begin();
385445
CScript::const_iterator pend = script.end();
386446
CScript::const_iterator pbegincodehash = script.begin();
@@ -389,15 +449,18 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
389449
ConditionStack vfExec;
390450
std::vector<valtype> altstack;
391451
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
392-
if (script.size() > MAX_SCRIPT_SIZE)
452+
if ((sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) && script.size() > MAX_SCRIPT_SIZE) {
393453
return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);
454+
}
394455
int nOpCount = 0;
395456
bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0;
457+
uint32_t opcode_pos = 0;
458+
execdata.m_codeseparator_pos = 0xFFFFFFFFUL;
459+
execdata.m_codeseparator_pos_init = true;
396460

397461
try
398462
{
399-
while (pc < pend)
400-
{
463+
for (; pc < pend; ++opcode_pos) {
401464
bool fExec = vfExec.all_true();
402465

403466
//
@@ -408,9 +471,12 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
408471
if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE)
409472
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
410473

411-
// Note how OP_RESERVED does not count towards the opcode limit.
412-
if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT)
413-
return set_error(serror, SCRIPT_ERR_OP_COUNT);
474+
if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) {
475+
// Note how OP_RESERVED does not count towards the opcode limit.
476+
if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) {
477+
return set_error(serror, SCRIPT_ERR_OP_COUNT);
478+
}
479+
}
414480

415481
if (opcode == OP_CAT ||
416482
opcode == OP_SUBSTR ||
@@ -568,6 +634,15 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
568634
if (stack.size() < 1)
569635
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
570636
valtype& vch = stacktop(-1);
637+
// Tapscript requires minimal IF/NOTIF inputs as a consensus rule.
638+
if (sigversion == SigVersion::TAPSCRIPT) {
639+
// The input argument to the OP_IF and OP_NOTIF opcodes must be either
640+
// exactly 0 (the empty vector) or exactly 1 (the one-byte vector with value 1).
641+
if (vch.size() > 1 || (vch.size() == 1 && vch[0] != 1)) {
642+
return set_error(serror, SCRIPT_ERR_TAPSCRIPT_MINIMALIF);
643+
}
644+
}
645+
// Under witness v0 rules it is only a policy rule, enabled through SCRIPT_VERIFY_MINIMALIF.
571646
if (sigversion == SigVersion::WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) {
572647
if (vch.size() > 1)
573648
return set_error(serror, SCRIPT_ERR_MINIMALIF);
@@ -1001,6 +1076,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
10011076

10021077
// Hash starts after the code separator
10031078
pbegincodehash = pc;
1079+
execdata.m_codeseparator_pos = opcode_pos;
10041080
}
10051081
break;
10061082

@@ -1015,7 +1091,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
10151091
valtype& vchPubKey = stacktop(-1);
10161092

10171093
bool fSuccess = true;
1018-
if (!EvalChecksig(vchSig, vchPubKey, pbegincodehash, pend, flags, checker, sigversion, serror, fSuccess)) return false;
1094+
if (!EvalChecksig(vchSig, vchPubKey, pbegincodehash, pend, execdata, flags, checker, sigversion, serror, fSuccess)) return false;
10191095
popstack(stack);
10201096
popstack(stack);
10211097
stack.push_back(fSuccess ? vchTrue : vchFalse);
@@ -1029,9 +1105,32 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
10291105
}
10301106
break;
10311107

1108+
case OP_CHECKSIGADD:
1109+
{
1110+
// OP_CHECKSIGADD is only available in Tapscript
1111+
if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
1112+
1113+
// (sig num pubkey -- num)
1114+
if (stack.size() < 3) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
1115+
1116+
const valtype& sig = stacktop(-3);
1117+
const CScriptNum num(stacktop(-2), fRequireMinimal);
1118+
const valtype& pubkey = stacktop(-1);
1119+
1120+
bool success = true;
1121+
if (!EvalChecksig(sig, pubkey, pbegincodehash, pend, execdata, flags, checker, sigversion, serror, success)) return false;
1122+
popstack(stack);
1123+
popstack(stack);
1124+
popstack(stack);
1125+
stack.push_back((num + (success ? 1 : 0)).getvch());
1126+
}
1127+
break;
1128+
10321129
case OP_CHECKMULTISIG:
10331130
case OP_CHECKMULTISIGVERIFY:
10341131
{
1132+
if (sigversion == SigVersion::TAPSCRIPT) return set_error(serror, SCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG);
1133+
10351134
// ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
10361135

10371136
int i = 1;
@@ -1390,13 +1489,16 @@ static const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch");
13901489
static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak");
13911490

13921491
template<typename T>
1393-
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)
1492+
bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, uint8_t key_version, const PrecomputedTransactionData& cache)
13941493
{
13951494
uint8_t ext_flag;
13961495
switch (sigversion) {
13971496
case SigVersion::TAPROOT:
13981497
ext_flag = 0;
13991498
break;
1499+
case SigVersion::TAPSCRIPT:
1500+
ext_flag = 1;
1501+
break;
14001502
default:
14011503
assert(false);
14021504
}
@@ -1452,6 +1554,18 @@ bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata
14521554
ss << sha_single_output.GetSHA256();
14531555
}
14541556

1557+
// Additional data for BIP 342 signatures
1558+
if (sigversion == SigVersion::TAPSCRIPT) {
1559+
assert(execdata.m_tapleaf_hash_init);
1560+
ss << execdata.m_tapleaf_hash;
1561+
// Key_version must be 0 for now, representing the current version of
1562+
// public keys in the tapscript signature opcode execution.
1563+
assert(key_version == 0);
1564+
ss << key_version;
1565+
assert(execdata.m_codeseparator_pos_init);
1566+
ss << execdata.m_codeseparator_pos;
1567+
}
1568+
14551569
hash_out = ss.GetSHA256();
14561570
return true;
14571571
}
@@ -1561,9 +1675,13 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto
15611675
template <class T>
15621676
bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey_in, SigVersion sigversion, const ScriptExecutionData& execdata) const
15631677
{
1564-
assert(sigversion == SigVersion::TAPROOT);
1678+
assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT);
15651679
// Schnorr signatures have 32-byte public keys. The caller is responsible for enforcing this.
15661680
assert(pubkey_in.size() == 32);
1681+
// Note that in Tapscript evaluation, empty signatures are treated specially (invalid signature that does not
1682+
// abort script execution). This is implemented in EvalChecksigTapscript, which won't invoke
1683+
// CheckSchnorrSignature in that case. In other contexts, they are invalid like every other signature with
1684+
// size different from 64 or 65.
15671685
if (sig.size() != 64 && sig.size() != 65) return false;
15681686

15691687
XOnlyPubKey pubkey{pubkey_in};
@@ -1575,7 +1693,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const uns
15751693
}
15761694
uint256 sighash;
15771695
assert(this->txdata);
1578-
if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, *this->txdata)) return false;
1696+
if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, /* key_version */ 0x00, *this->txdata)) return false;
15791697
return VerifySchnorrSignature(sig, pubkey, sighash);
15801698
}
15811699

@@ -1671,6 +1789,30 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
16711789
{
16721790
std::vector<valtype> stack{stack_span.begin(), stack_span.end()};
16731791

1792+
if (sigversion == SigVersion::TAPSCRIPT) {
1793+
// OP_SUCCESSx processing overrides everything, including stack element size limits
1794+
CScript::const_iterator pc = scriptPubKey.begin();
1795+
while (pc < scriptPubKey.end()) {
1796+
opcodetype opcode;
1797+
if (!scriptPubKey.GetOp(pc, opcode)) {
1798+
// Note how this condition would not be reached if an unknown OP_SUCCESSx was found
1799+
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
1800+
}
1801+
// New opcodes will be listed here. May use a different sigversion to modify existing opcodes.
1802+
if (IsOpSuccess(opcode)) {
1803+
if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) {
1804+
return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS);
1805+
}
1806+
return set_success(serror);
1807+
}
1808+
}
1809+
1810+
// Tapscript enforces initial stack size limits (altstack is empty here)
1811+
if (stack.size() > MAX_STACK_SIZE) {
1812+
return set_error(serror, SCRIPT_ERR_STACK_SIZE);
1813+
}
1814+
}
1815+
16741816
// Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack
16751817
for (const valtype& elem : stack) {
16761818
if (elem.size() > MAX_SCRIPT_ELEMENT_SIZE) return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
@@ -1685,12 +1827,13 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
16851827
return true;
16861828
}
16871829

1688-
static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, const std::vector<unsigned char>& program, const CScript& script)
1830+
static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, const std::vector<unsigned char>& program, const CScript& script, uint256* tapleaf_hash)
16891831
{
16901832
const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
16911833
const XOnlyPubKey p{uint256(std::vector<unsigned char>(control.begin() + 1, control.begin() + TAPROOT_CONTROL_BASE_SIZE))};
16921834
const XOnlyPubKey q{uint256(program)};
16931835
uint256 k = (CHashWriter(HASHER_TAPLEAF) << uint8_t(control[0] & TAPROOT_LEAF_MASK) << script).GetSHA256();
1836+
if (tapleaf_hash) *tapleaf_hash = k;
16941837
for (int i = 0; i < path_len; ++i) {
16951838
CHashWriter ss_branch{HASHER_TAPBRANCH};
16961839
Span<const unsigned char> node(control.data() + TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE);
@@ -1762,9 +1905,16 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
17621905
if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > TAPROOT_CONTROL_MAX_SIZE || ((control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) {
17631906
return set_error(serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE);
17641907
}
1765-
if (!VerifyTaprootCommitment(control, program, exec_script)) {
1908+
if (!VerifyTaprootCommitment(control, program, exec_script, &execdata.m_tapleaf_hash)) {
17661909
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
17671910
}
1911+
execdata.m_tapleaf_hash_init = true;
1912+
if ((control[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
1913+
// Tapscript (leaf version 0xc0)
1914+
execdata.m_validation_weight_left = ::GetSerializeSize(witness.stack, PROTOCOL_VERSION) + VALIDATION_WEIGHT_OFFSET;
1915+
execdata.m_validation_weight_left_init = true;
1916+
return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::TAPSCRIPT, checker, execdata, serror);
1917+
}
17681918
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) {
17691919
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION);
17701920
}

0 commit comments

Comments
 (0)