diff options
author | Pieter Wuille <pieter@wuille.net> | 2020-09-11 14:33:52 -0700 |
---|---|---|
committer | Pieter Wuille <pieter@wuille.net> | 2020-10-12 17:18:15 -0700 |
commit | 330de894a9a48515d9a473448b6c67adc3d188be (patch) | |
tree | 0634f0d38e9d8c0fd668c850aa6c701872ba3b8d /src/script/interpreter.cpp | |
parent | 8bbed4b7acf4c76eaea8c0e10f3cbf6ba4e53809 (diff) |
Use ScriptExecutionData to pass through annex hash
Instead of recomputing the annex hash every time a signature is verified, compute it
once and cache it in a new ScriptExecutionData structure.
Diffstat (limited to 'src/script/interpreter.cpp')
-rw-r--r-- | src/script/interpreter.cpp | 38 |
1 files changed, 25 insertions, 13 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 07cc525f50..a9d28c25d2 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -371,7 +371,7 @@ 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) +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); @@ -1159,6 +1159,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 { /** @@ -1384,7 +1390,7 @@ static const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch"); static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak"); template<typename T> -bool SignatureHashSchnorr(uint256& hash_out, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache) +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; switch (sigversion) { @@ -1423,8 +1429,8 @@ bool SignatureHashSchnorr(uint256& hash_out, const T& tx_to, uint32_t in_pos, ui } // Data about the input/prevout being spent - const auto& witstack = tx_to.vin[in_pos].scriptWitness.stack; - bool have_annex = witstack.size() > 1 && witstack.back().size() > 0 && witstack.back()[0] == ANNEX_TAG; + 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) { @@ -1435,7 +1441,7 @@ bool SignatureHashSchnorr(uint256& hash_out, const T& tx_to, uint32_t in_pos, ui ss << in_pos; } if (have_annex) { - ss << (CHashWriter(SER_GETHASH, 0) << witstack.back()).GetSHA256(); + ss << execdata.m_annex_hash; } // Data about the output (if only one). @@ -1553,7 +1559,7 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto } template <class T> -bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey_in, SigVersion sigversion, ScriptError* serror) const +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); // Schnorr signatures have 32-byte public keys. The caller is responsible for enforcing this. @@ -1569,7 +1575,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const uns } uint256 sighash; assert(this->txdata); - if (!SignatureHashSchnorr(sighash, *txTo, nIn, hashtype, sigversion, *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); @@ -1664,7 +1670,7 @@ 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()}; @@ -1674,7 +1680,7 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS } // 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); @@ -1707,6 +1713,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, { 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) { @@ -1721,14 +1728,14 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, if (memcmp(hash_exec_script.begin(), program.data(), 32)) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); } - return ExecuteWitnessScript(stack, exec_script, 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) { // 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 } exec_script << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG; - return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::WITNESS_V0, checker, serror); + return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::WITNESS_V0, checker, execdata, serror); } else { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH); } @@ -1738,11 +1745,16 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, 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) - SpanPopBack(stack); + 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, serror)) { + if (!checker.CheckSchnorrSignature(stack.front(), program, SigVersion::TAPROOT, execdata, serror)) { return false; // serror is set } return set_success(serror); |