@@ -1379,6 +1379,9 @@ template PrecomputedTransactionData::PrecomputedTransactionData(const CTransacti
13791379template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
13801380
13811381static const CHashWriter HASHER_TAPSIGHASH = TaggedHash(" TapSighash" );
1382+ static const CHashWriter HASHER_TAPLEAF = TaggedHash(" TapLeaf" );
1383+ static const CHashWriter HASHER_TAPBRANCH = TaggedHash(" TapBranch" );
1384+ static const CHashWriter HASHER_TAPTWEAK = TaggedHash(" TapTweak" );
13821385
13831386template <typename T>
13841387bool SignatureHashSchnorr (uint256& hash_out, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache)
@@ -1679,14 +1682,35 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
16791682 return true ;
16801683}
16811684
1682- static bool VerifyWitnessProgram (const CScriptWitness& witness, int witversion, const std::vector<unsigned char >& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror )
1685+ static bool VerifyTaprootCommitment (const std::vector< unsigned char >& control, const std::vector<unsigned char >& program, const CScript& script )
16831686{
1684- CScript exec_script; // !< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH)
1687+ const int path_len = (control.size () - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
1688+ const XOnlyPubKey p{uint256 (std::vector<unsigned char >(control.begin () + 1 , control.begin () + TAPROOT_CONTROL_BASE_SIZE))};
1689+ const XOnlyPubKey q{uint256 (program)};
1690+ uint256 tapleaf_hash = (CHashWriter (HASHER_TAPLEAF) << uint8_t (control[0 ] & TAPROOT_LEAF_MASK) << script).GetSHA256 ();
1691+ uint256 k = tapleaf_hash;
1692+ for (int i = 0 ; i < path_len; ++i) {
1693+ CHashWriter ss_branch{HASHER_TAPBRANCH};
1694+ Span<const unsigned char > node (control.data () + TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE);
1695+ if (std::lexicographical_compare (k.begin (), k.end (), node.begin (), node.end ())) {
1696+ ss_branch << k << node;
1697+ } else {
1698+ ss_branch << node << k;
1699+ }
1700+ k = ss_branch.GetSHA256 ();
1701+ }
1702+ k = (CHashWriter (HASHER_TAPTWEAK) << MakeSpan (p) << k).GetSHA256 ();
1703+ return q.CheckPayToContract (p, k, control[0 ] & 1 );
1704+ }
1705+
1706+ 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)
1707+ {
1708+ CScript exec_script; // !< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH; leaf script in P2TR)
16851709 Span<const valtype> stack{witness.stack };
16861710
16871711 if (witversion == 0 ) {
16881712 if (program.size () == WITNESS_V0_SCRIPTHASH_SIZE) {
1689- // Version 0 segregated witness program: SHA256(CScript) inside the program, CScript + inputs in witness
1713+ // BIP141 P2WSH: 32-byte witness v0 program (which encodes SHA256(script))
16901714 if (stack.size () == 0 ) {
16911715 return set_error (serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY);
16921716 }
@@ -1699,7 +1723,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
16991723 }
17001724 return ExecuteWitnessScript (stack, exec_script, flags, SigVersion::WITNESS_V0, checker, serror);
17011725 } else if (program.size () == WITNESS_V0_KEYHASH_SIZE) {
1702- // Special case for pay-to-pubkeyhash; signature + pubkey in witness
1726+ // BIP141 P2WPKH: 20-byte witness v0 program (which encodes Hash160(pubkey))
17031727 if (stack.size () != 2 ) {
17041728 return set_error (serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness
17051729 }
@@ -1708,11 +1732,41 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
17081732 } else {
17091733 return set_error (serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH);
17101734 }
1735+ } else if (witversion == 1 && program.size () == WITNESS_V1_TAPROOT_SIZE && !is_p2sh) {
1736+ // BIP341 Taproot: 32-byte non-P2SH witness v1 program (which encodes a P2C-tweaked pubkey)
1737+ if (!(flags & SCRIPT_VERIFY_TAPROOT)) return set_success (serror);
1738+ if (stack.size () == 0 ) return set_error (serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY);
1739+ if (stack.size () >= 2 && !stack.back ().empty () && stack.back ()[0 ] == ANNEX_TAG) {
1740+ // Drop annex (this is non-standard; see IsWitnessStandard)
1741+ SpanPopBack (stack);
1742+ }
1743+ if (stack.size () == 1 ) {
1744+ // Key path spending (stack size is 1 after removing optional annex)
1745+ if (!checker.CheckSchnorrSignature (stack.front (), program, SigVersion::TAPROOT, serror)) {
1746+ return false ; // serror is set
1747+ }
1748+ return set_success (serror);
1749+ } else {
1750+ // Script path spending (stack size is >1 after removing optional annex)
1751+ const valtype& control = SpanPopBack (stack);
1752+ const valtype& script_bytes = SpanPopBack (stack);
1753+ exec_script = CScript (script_bytes.begin (), script_bytes.end ());
1754+ if (control.size () < TAPROOT_CONTROL_BASE_SIZE || control.size () > TAPROOT_CONTROL_MAX_SIZE || ((control.size () - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0 ) {
1755+ return set_error (serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE);
1756+ }
1757+ if (!VerifyTaprootCommitment (control, program, exec_script)) {
1758+ return set_error (serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
1759+ }
1760+ if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) {
1761+ return set_error (serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION);
1762+ }
1763+ return set_success (serror);
1764+ }
17111765 } else {
17121766 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
17131767 return set_error (serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
17141768 }
1715- // Higher version witness scripts return true for future softfork compatibility
1769+ // Other version/size/p2sh combinations return true for future softfork compatibility
17161770 return true ;
17171771 }
17181772 // 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.
@@ -1758,7 +1812,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
17581812 // The scriptSig must be _exactly_ CScript(), otherwise we reintroduce malleability.
17591813 return set_error (serror, SCRIPT_ERR_WITNESS_MALLEATED);
17601814 }
1761- if (!VerifyWitnessProgram (*witness, witnessversion, witnessprogram, flags, checker, serror)) {
1815+ if (!VerifyWitnessProgram (*witness, witnessversion, witnessprogram, flags, checker, serror, /* is_p2sh */ false )) {
17621816 return false ;
17631817 }
17641818 // Bypass the cleanstack check at the end. The actual stack is obviously not clean
@@ -1803,7 +1857,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
18031857 // reintroduce malleability.
18041858 return set_error (serror, SCRIPT_ERR_WITNESS_MALLEATED_P2SH);
18051859 }
1806- if (!VerifyWitnessProgram (*witness, witnessversion, witnessprogram, flags, checker, serror)) {
1860+ if (!VerifyWitnessProgram (*witness, witnessversion, witnessprogram, flags, checker, serror, /* is_p2sh */ true )) {
18071861 return false ;
18081862 }
18091863 // Bypass the cleanstack check at the end. The actual stack is obviously not clean
0 commit comments