diff --git a/src/binana/templatehash.json b/src/binana/templatehash.json new file mode 100644 index 0000000000000..02446d95e5321 --- /dev/null +++ b/src/binana/templatehash.json @@ -0,0 +1,9 @@ +{ + "binana": [2025, 1, 0], + "deployment": "TEMPLATEHASH", + "scriptverify": true, + "scriptverify_discourage": true, + "opcodes": { + "TEMPLATEHASH": "0xbb" + } +} diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 0e67b9940c995..d0626c1639a1e 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1377,6 +1377,20 @@ bool EvalScript(std::vector >& stack, const CScript& break; } + case OP_TEMPLATEHASH: + { + // OP_TEMPLATEHASH is only available in Tapscript. Note this is the exact same error + // returned in the default case, which would be the one hit by OP_SUCCESS187 before + // the introduction of OP_TEMPLATEHASH. + if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) { + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + } + + const uint256 template_hash{checker.GetTemplateHash(execdata)}; + stack.push_back({template_hash.begin(), template_hash.end()}); + } + break; + default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } @@ -1698,6 +1712,7 @@ template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTr const HashWriter HASHER_TAPSIGHASH{TaggedHash("TapSighash")}; const HashWriter HASHER_TAPLEAF{TaggedHash("TapLeaf")}; const HashWriter HASHER_TAPBRANCH{TaggedHash("TapBranch")}; +const HashWriter HASHER_TEMPLATEHASH{TaggedHash("TemplateHash")}; static bool HandleMissingData(MissingDataBehavior mdb) { @@ -2059,6 +2074,28 @@ bool GenericTransactionSignatureChecker::CheckDefaultCheckTemplateVerifyHash( return HandleMissingData(m_mdb); } } + +template +uint256 GenericTransactionSignatureChecker::GetTemplateHash(ScriptExecutionData& execdata) const +{ + assert(txdata && txdata->m_bip341_taproot_ready); + assert(execdata.m_annex_init); + + HashWriter ss{HASHER_TEMPLATEHASH}; + ss << txTo->version; + ss << txTo->nLockTime; + ss << txdata->m_sequences_single_hash; + ss << txdata->m_outputs_single_hash; + const uint8_t annex_present = (execdata.m_annex_present ? 1 : 0); + ss << annex_present; + ss << nIn; + if (execdata.m_annex_present) { + ss << execdata.m_annex_hash; + } + + return ss.GetSHA256(); +} + // explicit instantiation template class GenericTransactionSignatureChecker; template class GenericTransactionSignatureChecker; diff --git a/src/script/interpreter.h b/src/script/interpreter.h index a7abf4cab6ac7..00555ea144628 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -316,6 +316,11 @@ class BaseSignatureChecker return false; } + virtual uint256 GetTemplateHash(ScriptExecutionData& execdata) const + { + return {}; + } + virtual ~BaseSignatureChecker() = default; }; @@ -353,6 +358,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; bool CheckDefaultCheckTemplateVerifyHash(const Span& hash) const override; + uint256 GetTemplateHash(ScriptExecutionData& execdata) const override; }; using TransactionSignatureChecker = GenericTransactionSignatureChecker; @@ -384,6 +390,11 @@ class DeferringSignatureChecker : public BaseSignatureChecker { return m_checker.CheckSequence(nSequence); } + + uint256 GetTemplateHash(ScriptExecutionData& execdata) const override + { + return m_checker.GetTemplateHash(execdata); + } }; /** Compute the BIP341 tapleaf hash from leaf version & script. */ diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt index 8e27d68fa9301..a2484741a11f2 100644 --- a/src/test/fuzz/CMakeLists.txt +++ b/src/test/fuzz/CMakeLists.txt @@ -118,6 +118,7 @@ add_executable(fuzz string.cpp strprintf.cpp system.cpp + templatehash.cpp timeoffsets.cpp torcontrol.cpp transaction.cpp diff --git a/src/test/fuzz/templatehash.cpp b/src/test/fuzz/templatehash.cpp new file mode 100644 index 0000000000000..da6de0e4966b5 --- /dev/null +++ b/src/test/fuzz/templatehash.cpp @@ -0,0 +1,189 @@ +// Copyright (c) 2009-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include