From e0b4e3964c8e451d1e9563412ebf0759b9f2d564 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Mon, 6 Feb 2023 21:04:49 +1000 Subject: [PATCH 1/8] script/interpreter: Add KeyVersion Introduce `KeyVersion` in preparation for defining new behaviours via BIP 342's "unknown public key type" upgrade mechanism. --- src/script/interpreter.cpp | 29 +++++++++++++---------------- src/script/interpreter.h | 18 +++++++++++------- src/script/sign.cpp | 4 ++-- src/test/fuzz/miniscript.cpp | 2 +- src/test/fuzz/signature_checker.cpp | 2 +- src/test/miniscript_tests.cpp | 2 +- src/test/script_tests.cpp | 2 +- 7 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 9ae7164fe83e8..36f501a180c4f 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -366,7 +366,7 @@ static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, Scr 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)) { + if (success && !checker.CheckSchnorrSignature(sig, KeyVersion::TAPROOT, pubkey, sigversion, execdata, serror)) { return false; // serror is set } } else { @@ -1583,21 +1583,17 @@ static bool HandleMissingData(MissingDataBehavior mdb) } template -bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb) +bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, KeyVersion keyversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb) { - uint8_t ext_flag, key_version; + uint8_t ext_flag; + assert(keyversion == KeyVersion::TAPROOT); switch (sigversion) { case SigVersion::TAPROOT: ext_flag = 0; - // key_version is not used and left uninitialized. + // keyversion is not used. 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); @@ -1663,7 +1659,7 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons if (sigversion == SigVersion::TAPSCRIPT) { assert(execdata.m_tapleaf_hash_init); ss << execdata.m_tapleaf_hash; - ss << key_version; + ss << uint8_t(keyversion); assert(execdata.m_codeseparator_pos_init); ss << execdata.m_codeseparator_pos; } @@ -1778,18 +1774,19 @@ bool GenericTransactionSignatureChecker::CheckECDSASignature(const std::vecto } template -bool GenericTransactionSignatureChecker::CheckSchnorrSignature(Span sig, Span pubkey_in, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const +bool GenericTransactionSignatureChecker::CheckSchnorrSignature(Span sig, KeyVersion pubkeyver, Span pubkey, SigVersion sigversion, 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); + assert(pubkey.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}; + XOnlyPubKey pubkey_xonly{pubkey}; uint8_t hashtype = SIGHASH_DEFAULT; if (sig.size() == 65) { @@ -1798,10 +1795,10 @@ bool GenericTransactionSignatureChecker::CheckSchnorrSignature(Spantxdata) return HandleMissingData(m_mdb); - if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, *this->txdata, m_mdb)) { + if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, pubkeyver, *this->txdata, m_mdb)) { return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE); } - if (!VerifySchnorrSignature(sig, pubkey, sighash)) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG); + if (!VerifySchnorrSignature(sig, pubkey_xonly, sighash)) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG); return true; } @@ -2039,7 +2036,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, 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)) { + if (!checker.CheckSchnorrSignature(stack.front(), KeyVersion::TAPROOT, program, SigVersion::TAPROOT, execdata, serror)) { return false; // serror is set } return set_success(serror); diff --git a/src/script/interpreter.h b/src/script/interpreter.h index a067a6c1fd330..199a1aa19e2f7 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -9,6 +9,7 @@ #include #include #include +#include #include