diff --git a/src/Makefile.test.include b/src/Makefile.test.include index a8a52e3ca5b6..3da34c91b43b 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -19,6 +19,7 @@ JSON_TEST_FILES = \ test/data/bip341_wallet_vectors.json \ test/data/base58_encode_decode.json \ test/data/blockfilters.json \ + test/data/ctvhash.json \ test/data/key_io_valid.json \ test/data/key_io_invalid.json \ test/data/script_tests.json \ @@ -88,6 +89,7 @@ BITCOIN_TESTS =\ test/compilerbug_tests.cpp \ test/compress_tests.cpp \ test/crypto_tests.cpp \ + test/ctvhash_tests.cpp \ test/cuckoocache_tests.cpp \ test/dbwrapper_tests.cpp \ test/denialofservice_tests.cpp \ diff --git a/src/addresstype.cpp b/src/addresstype.cpp index f199d1b47944..258f25cf9b32 100644 --- a/src/addresstype.cpp +++ b/src/addresstype.cpp @@ -94,6 +94,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) case TxoutType::MULTISIG: case TxoutType::NULL_DATA: case TxoutType::NONSTANDARD: + case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY: addressRet = CNoDestination(scriptPubKey); return false; } // no default case, so the compiler can warn about missing cases diff --git a/src/consensus/params.h b/src/consensus/params.h index 25f53eb62077..6a8acb7e4c61 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -32,6 +32,7 @@ constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_ enum DeploymentPos : uint16_t { DEPLOYMENT_TESTDUMMY, DEPLOYMENT_TAPROOT, // Deployment of Schnorr/Taproot (BIPs 340-342) + DEPLOYMENT_LNHANCE, // Deployment of CTV/CSFS/IK/PC (BIPs 119, 348, 349, 442) // NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp MAX_VERSION_BITS_DEPLOYMENTS }; diff --git a/src/deploymentinfo.cpp b/src/deploymentinfo.cpp index 185a7dcb54ce..a3e28ec00cff 100644 --- a/src/deploymentinfo.cpp +++ b/src/deploymentinfo.cpp @@ -17,6 +17,10 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.name =*/ "taproot", /*.gbt_force =*/ true, }, + { + /*.name =*/ "lnhance", + /*.gbt_force =*/ true, + }, }; std::string DeploymentName(Consensus::BuriedDeployment dep) diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index 26c261eba272..bdfa3dc849a7 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -103,6 +103,12 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021 consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021 + // + // Deployment of CTV/CSFS/IK/PC (BIPs 119, 348, 349, 442) + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].bit = 3; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].min_activation_height = 0; // No activation delay consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000063c4ebd298db40af57541800"); consensus.defaultAssumeValid = uint256S("0x000000000000000000026811d149d4d261995ec5b3f64f439a0a10e1a464af9a"); // 824000 @@ -222,6 +228,12 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay + // Deployment of CTV/CSFS/IK/PC (BIPs 119, 348, 349, 442) + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].bit = 3; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].min_activation_height = 0; // No activation delay + consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000c59b14e264ba6c15db9"); consensus.defaultAssumeValid = uint256S("0x000000000001323071f38f21ea5aae529ece491eadaccce506a59bcc2d968917"); // 2550000 @@ -359,6 +371,12 @@ class SigNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay + // Deployment of CTV/CSFS/IK/PC (BIPs 119, 348, 349, 442) + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].bit = 3; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].min_activation_height = 0; // No activation delay + // message start is defined as the first 4 bytes of the sha256d of the block script HashWriter h{}; h << consensus.signet_challenge; @@ -435,6 +453,12 @@ class CRegTestParams : public CChainParams consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay + // Deployment of CTV/CSFS/IK/PC (BIPs 119, 348, 349, 442) + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].bit = 3; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_LNHANCE].min_activation_height = 0; + consensus.nMinimumChainWork = uint256{}; consensus.defaultAssumeValid = uint256{}; diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index d08ec4fb7f75..73049891ed69 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -202,6 +202,11 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) { return false; } + } else if (whichType == TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY) { + // after activation, only allow bare with no scriptsig. + // pre-activation disallowing enforced via discouraged logic in the + // interpreter. + if (tx.vin[i].scriptSig.size() != 0) return false; } } diff --git a/src/policy/policy.h b/src/policy/policy.h index 6a7980c312c9..1cbcbeaf058e 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -113,7 +113,9 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI SCRIPT_VERIFY_CONST_SCRIPTCODE | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION | SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS | - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE}; + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE | + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY | + SCRIPT_VERIFY_LNHANCE}; /** For convenience, standard but not mandatory verify flags. */ static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS}; diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 11e1b4abb51a..e1781aea63d6 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -217,12 +217,12 @@ bool XOnlyPubKey::IsFullyValid() const return secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data()); } -bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span sigbytes) const +bool XOnlyPubKey::VerifySchnorr(const Span msg, Span sigbytes) const { assert(sigbytes.size() == 64); secp256k1_xonly_pubkey pubkey; if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data())) return false; - return secp256k1_schnorrsig_verify(secp256k1_context_static, sigbytes.data(), msg.begin(), 32, &pubkey); + return secp256k1_schnorrsig_verify(secp256k1_context_static, sigbytes.data(), msg.data(), msg.size(), &pubkey); } static const HashWriter HASHER_TAPTWEAK{TaggedHash("TapTweak")}; diff --git a/src/pubkey.h b/src/pubkey.h index 15d7e7bc07db..4103ca951d1d 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -258,7 +258,7 @@ class XOnlyPubKey * * sigbytes must be exactly 64 bytes. */ - bool VerifySchnorr(const uint256& msg, Span sigbytes) const; + bool VerifySchnorr(const Span msg, Span sigbytes) const; /** Compute the Taproot tweak as specified in BIP341, with *this as internal * key: diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 0211a8a10675..7cab281b96aa 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1315,6 +1315,7 @@ UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT); SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY); SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_LNHANCE); return softforks; } } // anon namespace diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 634be2f7fb9d..bc949edb9e21 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -556,6 +556,8 @@ static RPCHelpMan decodescript() case TxoutType::SCRIPTHASH: case TxoutType::WITNESS_UNKNOWN: case TxoutType::WITNESS_V1_TAPROOT: + // don't wrap CTV because P2SH CTV is a hash cycle + case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY: // Should not be wrapped return false; } // no default case, so the compiler can warn about missing cases @@ -598,6 +600,8 @@ static RPCHelpMan decodescript() case TxoutType::WITNESS_V0_KEYHASH: case TxoutType::WITNESS_V0_SCRIPTHASH: case TxoutType::WITNESS_V1_TAPROOT: + // don't wrap CTV because P2SH CTV is a hash cycle + case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY: // Should not be wrapped return false; } // no default case, so the compiler can warn about missing cases diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index c969ce45f124..d96bd8ce36b7 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -343,6 +343,48 @@ static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPu return true; } +static bool EvalChecksigFromStack(const valtype& sig, const valtype& msg, const valtype& pubkey_in, ScriptExecutionData& execdata, unsigned int flags, SigVersion sigversion, ScriptError* serror, bool& success) +{ + assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0 || sigversion == SigVersion::TAPSCRIPT); + /* + * The following validation sequence is consensus critical. Please note how -- + * upgradable public key versions precede other rules; + * the script execution fails when using empty signature with invalid public key; + * the script execution fails when using non-empty invalid signature. + */ + success = !sig.empty(); + if (success && sigversion == SigVersion::TAPSCRIPT) { + // Implement the sigops/witnesssize ratio test. + // Passing with an upgradable public key version is also counted. + assert(execdata.m_validation_weight_left_init); + execdata.m_validation_weight_left -= VALIDATION_WEIGHT_PER_SIGOP_PASSED; + if (execdata.m_validation_weight_left < 0) { + return set_error(serror, SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT); + } + } + if (pubkey_in.size() == 0) { + return set_error(serror, SCRIPT_ERR_PUBKEYTYPE); + } else if (pubkey_in.size() == 32) { + if (!success) return true; + if (sig.size() != 64) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_SIZE); + + XOnlyPubKey pubkey{pubkey_in}; + + if (!pubkey.VerifySchnorr(msg, sig)) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG); + } else { + /* + * New public key version softforks should be defined before this `else` block. + * Generally, the new code should not do anything but failing the script execution. To avoid + * consensus bugs, it should not modify any existing values (including `success`). + */ + if ((flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE) != 0) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE); + } + } + + return true; +} + static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success) { assert(sigversion == SigVersion::TAPSCRIPT); @@ -451,6 +493,17 @@ bool EvalScript(std::vector >& stack, const CScript& if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) { return set_error(serror, SCRIPT_ERR_OP_COUNT); } + + // Redefined OP_SUCCESS opcodes are only available in tapscript + switch(opcode) { + case OP_CHECKSIGFROMSTACK: + case OP_INTERNALKEY: + case OP_PAIRCOMMIT: + if (fExec) { + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + } + break; + } } if (opcode == OP_CAT || @@ -591,7 +644,42 @@ bool EvalScript(std::vector >& stack, const CScript& break; } - case OP_NOP1: case OP_NOP4: case OP_NOP5: + case OP_CHECKTEMPLATEVERIFY: + { + if (flags & SCRIPT_VERIFY_DISCOURAGE_LNHANCE) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); + } + + // if flags not enabled; treat as a NOP4 + if (!(flags & SCRIPT_VERIFY_LNHANCE)) { + break; + } + + if (stack.size() < 1) { + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + + // If the argument was not 32 bytes, treat as OP_NOP4: + switch (stack.back().size()) { + case 32: + { + const Span hash{stack.back()}; + if (!checker.CheckDefaultCheckTemplateVerifyHash(hash)) { + return set_error(serror, SCRIPT_ERR_TEMPLATE_MISMATCH); + } + break; + } + default: + // future upgrade can add semantics for this opcode with different length args + // so discourage use when applicable + if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); + } + } + } + break; + + case OP_NOP1: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) @@ -1213,6 +1301,55 @@ bool EvalScript(std::vector >& stack, const CScript& } break; + // OP_INTERNALKEY is only available in tapscript + // DISCOURAGE for OP_INTERNALKEY is handled in OP_SUCCESS handling + case OP_INTERNALKEY: + { + stack.emplace_back(execdata.m_internal_key.begin(), execdata.m_internal_key.end()); + } + break; + + // OP_CHECKSIGFROMSTACK is only available in tapscript + // DISCOURAGE for OP_CHECKSIGFROMSTACK is handled in OP_SUCCESS handling + case OP_CHECKSIGFROMSTACK: + { + // (sig message pubkey) + if (stack.size() < 3) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + const valtype& vchSigIn = stacktop(-3); + const valtype& vchMsg = stacktop(-2); + const valtype& vchPubKey = stacktop(-1); + + bool fSuccess = true; + if (!EvalChecksigFromStack(vchSigIn, vchMsg, vchPubKey, execdata, flags, sigversion, serror, fSuccess)) return false; + + popstack(stack); + popstack(stack); + popstack(stack); + stack.push_back(fSuccess ? vchTrue : vchFalse); + } + break; + + // OP_PAIRCOMMIT is only available in tapscript + // DISCOURAGE for OP_PAIRCOMMIT is handled in OP_SUCCESS handling + case OP_PAIRCOMMIT: + { + // (x1 x2 -- hash) + if (stack.size() < 2) { + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + const valtype& vch1 = stacktop(-2); + const valtype& vch2 = stacktop(-1); + + uint256 hash = PairCommitHash(vch1, vch2); + + popstack(stack); + popstack(stack); + stack.emplace_back(hash.begin(), hash.end()); + } + break; + default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } @@ -1377,6 +1514,18 @@ uint256 GetSpentAmountsSHA256(const std::vector& outputs_spent) HashWriter ss{}; for (const auto& txout : outputs_spent) { ss << txout.nValue; + + } + return ss.GetSHA256(); +} + +/** Compute the (single) SHA256 of the concatenation of all scriptSigs in a tx. */ +template +uint256 GetScriptSigsSHA256(const T& txTo) +{ + HashWriter ss{}; + for (const auto& in : txTo.vin) { + ss << in.scriptSig; } return ss.GetSHA256(); } @@ -1391,9 +1540,63 @@ uint256 GetSpentScriptsSHA256(const std::vector& outputs_spent) return ss.GetSHA256(); } +/* Not Exported, just convenience */ +template +uint256 GetDefaultCheckTemplateVerifyHashWithScript(const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash, + const uint256& scriptSig_hash, const uint32_t input_index) { + auto h = HashWriter{} + << tx.nVersion + << tx.nLockTime + << scriptSig_hash + << uint32_t(tx.vin.size()) + << sequences_hash + << uint32_t(tx.vout.size()) + << outputs_hash + << input_index; + return h.GetSHA256(); +} + +template +uint256 GetDefaultCheckTemplateVerifyHashEmptyScript(const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash, + const uint32_t input_index) { + auto h = HashWriter{} + << tx.nVersion + << tx.nLockTime + << uint32_t(tx.vin.size()) + << sequences_hash + << uint32_t(tx.vout.size()) + << outputs_hash + << input_index; + return h.GetSHA256(); +} } // namespace +template +uint256 GetDefaultCheckTemplateVerifyHash(const TxType& tx, uint32_t input_index) { + return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequencesSHA256(tx), input_index); +} + +template +static bool NoScriptSigs(const TxType& tx) +{ + return std::all_of(tx.vin.begin(), tx.vin.end(), [](const CTxIn& c) { return c.scriptSig.empty(); }); +} + +template +uint256 GetDefaultCheckTemplateVerifyHash(const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash, + const uint32_t input_index) { + return NoScriptSigs(tx) ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) : + GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index); +} + +template +uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash, + const uint32_t input_index); +template +uint256 GetDefaultCheckTemplateVerifyHash(const CMutableTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash, + const uint32_t input_index); + template void PrecomputedTransactionData::Init(const T& txTo, std::vector&& spent_outputs, bool force) { @@ -1405,6 +1608,8 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector&& spent m_spent_outputs_ready = true; } + // TODO: Improve this heuristic + bool uses_bip119_ctv = true; // Determine which precomputation-impacting features this transaction uses. bool uses_bip143_segwit = force; bool uses_bip341_taproot = force; @@ -1427,11 +1632,16 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector&& spent if (uses_bip341_taproot && uses_bip143_segwit) break; // No need to scan further if we already need all. } - if (uses_bip143_segwit || uses_bip341_taproot) { + if (uses_bip143_segwit || uses_bip341_taproot || uses_bip119_ctv) { // Computations shared between both sighash schemes. m_prevouts_single_hash = GetPrevoutsSHA256(txTo); m_sequences_single_hash = GetSequencesSHA256(txTo); m_outputs_single_hash = GetOutputsSHA256(txTo); + + // 0 hash used to signal if we should skip scriptSigs + // when re-computing for different indexes. + m_scriptSigs_single_hash = NoScriptSigs(txTo) ? uint256{} : GetScriptSigsSHA256(txTo); + m_bip119_ctv_ready = true; } if (uses_bip143_segwit) { hashPrevouts = SHA256Uint256(m_prevouts_single_hash); @@ -1461,6 +1671,12 @@ 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_PAIRCOMMIT{TaggedHash("PairCommit")}; + +uint256 PairCommitHash(const std::vector& x1, const std::vector& x2) +{ + return (HashWriter{HASHER_PAIRCOMMIT} << x1 << x2).GetSHA256(); +} static bool HandleMissingData(MissingDataBehavior mdb) { @@ -1781,6 +1997,22 @@ bool GenericTransactionSignatureChecker::CheckSequence(const CScriptNum& nSeq return true; } +template +bool GenericTransactionSignatureChecker::CheckDefaultCheckTemplateVerifyHash(const Span& hash) const +{ + // Should already be checked before calling... + assert(hash.size() == 32); + if (txdata && txdata->m_bip119_ctv_ready) { + assert(txTo != nullptr); + uint256 hash_tmpl = txdata->m_scriptSigs_single_hash.IsNull() ? + GetDefaultCheckTemplateVerifyHashEmptyScript(*txTo, txdata->m_outputs_single_hash, txdata->m_sequences_single_hash, nIn) : + GetDefaultCheckTemplateVerifyHashWithScript(*txTo, txdata->m_outputs_single_hash, txdata->m_sequences_single_hash, + txdata->m_scriptSigs_single_hash, nIn); + return std::equal(hash_tmpl.begin(), hash_tmpl.end(), hash.data()); + } else { + return HandleMissingData(m_mdb); + } +} // explicit instantiation template class GenericTransactionSignatureChecker; template class GenericTransactionSignatureChecker; @@ -1799,6 +2031,20 @@ static bool ExecuteWitnessScript(const Span& stack_span, const CS return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } // New opcodes will be listed here. May use a different sigversion to modify existing opcodes. + switch (opcode) { + case OP_CHECKSIGFROMSTACK: + case OP_INTERNALKEY: + case OP_PAIRCOMMIT: { + if (flags & SCRIPT_VERIFY_DISCOURAGE_LNHANCE) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_LNHANCE); + } + if (flags & SCRIPT_VERIFY_LNHANCE) { + // Skip IsOpSuccess check for these opcodes + continue; + } + break; + } + } if (IsOpSuccess(opcode)) { if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) { return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS); @@ -1858,7 +2104,6 @@ uint256 ComputeTaprootMerkleRoot(Span control, const uint25 static bool VerifyTaprootCommitment(const std::vector& control, const std::vector& program, const uint256& tapleaf_hash) { - assert(control.size() >= TAPROOT_CONTROL_BASE_SIZE); assert(program.size() >= uint256::size()); //! The internal pubkey (x-only, so no Y coordinate parity). const XOnlyPubKey p{Span{control}.subspan(1, TAPROOT_CONTROL_BASE_SIZE - 1)}; @@ -1926,6 +2171,9 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > TAPROOT_CONTROL_MAX_SIZE || ((control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) { return set_error(serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE); } + assert(control.size() >= TAPROOT_CONTROL_BASE_SIZE); + execdata.m_internal_key = uint256{Span{control}.subspan(1, TAPROOT_CONTROL_BASE_SIZE - 1)}; + execdata.m_internal_key_init = true; execdata.m_tapleaf_hash = ComputeTapleafHash(control[0] & TAPROOT_LEAF_MASK, script); if (!VerifyTaprootCommitment(control, program, execdata.m_tapleaf_hash)) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 836c2e7982a2..7d3ceaa9891a 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -143,6 +143,15 @@ enum : uint32_t { // Making unknown public key versions (in BIP 342 scripts) non-standard SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20), + // CHECKTEMPLATEVERIFY, CHECKSIGFROMSTACK, INTERNALKEY validation (BIP-119, xxx, yyy) + SCRIPT_VERIFY_LNHANCE = (1U << 21), + + // discourage upgradable OP_CHECKTEMPLATEVERIFY hashes + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY = (1U << 22), + + // discourage OP_CHECKTEMPLATEVERIFY, OP_CHECKSIGFROMSTACK, OP_INTERNALKEY + SCRIPT_VERIFY_DISCOURAGE_LNHANCE = (1U << 23), + // Constants to point to the highest flag in use. Add new flags above this line. // SCRIPT_VERIFY_END_MARKER @@ -152,6 +161,9 @@ bool CheckSignatureEncoding(const std::vector &vchSig, unsigned i struct PrecomputedTransactionData { + // Order of fields is packed below (uint256 is 32 bytes, vector is 24 bytes + // (3 ptrs), ready flags (1 byte each). + // BIP341 precomputed data. // These are single-SHA256, see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-16. uint256 m_prevouts_single_hash; @@ -159,15 +171,25 @@ struct PrecomputedTransactionData uint256 m_outputs_single_hash; uint256 m_spent_amounts_single_hash; uint256 m_spent_scripts_single_hash; - //! Whether the 5 fields above are initialized. - bool m_bip341_taproot_ready = false; + + // BIP119 precomputed data (single SHA256). + uint256 m_scriptSigs_single_hash; // BIP143 precomputed data (double-SHA256). uint256 hashPrevouts, hashSequence, hashOutputs; - //! Whether the 3 fields above are initialized. - bool m_bip143_segwit_ready = false; + // BIP341 cached outputs. std::vector m_spent_outputs; + + //! Whether the bip341 fields above are initialized. + bool m_bip341_taproot_ready = false; + + //! Whether the bip119 fields above are initialized. + bool m_bip119_ctv_ready = false; + + //! Whether the bip143 fields above are initialized. + bool m_bip143_segwit_ready = false; + //! Whether m_spent_outputs is initialized. bool m_spent_outputs_ready = false; @@ -187,6 +209,14 @@ struct PrecomputedTransactionData explicit PrecomputedTransactionData(const T& tx); }; +/* Standard Template Hash Declarations */ +template +uint256 GetDefaultCheckTemplateVerifyHash(const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash, + const uint32_t input_index); + +/* PairCommit Declarations */ +uint256 PairCommitHash(const std::vector& x1, const std::vector& x2); + enum class SigVersion { BASE = 0, //!< Bare scripts and BIP16 P2SH-wrapped redeemscripts @@ -202,6 +232,10 @@ struct ScriptExecutionData //! The tapleaf hash. uint256 m_tapleaf_hash; + //! Whether m_internal_key is initialized. + bool m_internal_key_init = false; + uint256 m_internal_key; + //! Whether m_codeseparator_pos is initialized. bool m_codeseparator_pos_init = false; //! Opcode position of the last executed OP_CODESEPARATOR (or 0xFFFFFFFF if none executed). @@ -265,6 +299,11 @@ class BaseSignatureChecker return false; } + virtual bool CheckDefaultCheckTemplateVerifyHash(const Span& hash) const + { + return false; + } + virtual ~BaseSignatureChecker() {} }; @@ -301,6 +340,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; + bool CheckDefaultCheckTemplateVerifyHash(const Span& hash) const override; }; using TransactionSignatureChecker = GenericTransactionSignatureChecker; diff --git a/src/script/script.cpp b/src/script/script.cpp index 80e8d26bcfb9..95d2387c2109 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -138,7 +138,7 @@ std::string GetOpName(opcodetype opcode) case OP_NOP1 : return "OP_NOP1"; case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY"; case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY"; - case OP_NOP4 : return "OP_NOP4"; + case OP_CHECKTEMPLATEVERIFY : return "OP_CHECKTEMPLATEVERIFY"; case OP_NOP5 : return "OP_NOP5"; case OP_NOP6 : return "OP_NOP6"; case OP_NOP7 : return "OP_NOP7"; @@ -149,6 +149,11 @@ std::string GetOpName(opcodetype opcode) // Opcode added by BIP 342 (Tapscript) case OP_CHECKSIGADD : return "OP_CHECKSIGADD"; + // Tapscript expansion + case OP_INTERNALKEY : return "OP_INTERNALKEY"; + case OP_CHECKSIGFROMSTACK : return "OP_CHECKSIGFROMSTACK"; + case OP_PAIRCOMMIT : return "OP_PAIRCOMMIT"; + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; default: @@ -204,6 +209,13 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const return subscript.GetSigOpCount(true); } +bool CScript::IsPayToBareDefaultCheckTemplateVerifyHash() const +{ + // Extra-fast test for pay-to-bare-default-check-template-verify-hash CScripts: + return (this->size() == 34 && + (*this)[0] == 0x20 && + (*this)[33] == OP_CHECKTEMPLATEVERIFY); +} bool CScript::IsPayToScriptHash() const { // Extra-fast test for pay-to-script-hash CScripts: diff --git a/src/script/script.h b/src/script/script.h index 66d63fae89e1..677daad31f91 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -197,7 +197,8 @@ enum opcodetype OP_NOP2 = OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY = 0xb2, OP_NOP3 = OP_CHECKSEQUENCEVERIFY, - OP_NOP4 = 0xb3, + OP_CHECKTEMPLATEVERIFY = 0xb3, + OP_NOP4 = OP_CHECKTEMPLATEVERIFY, OP_NOP5 = 0xb4, OP_NOP6 = 0xb5, OP_NOP7 = 0xb6, @@ -208,6 +209,11 @@ enum opcodetype // Opcode added by BIP 342 (Tapscript) OP_CHECKSIGADD = 0xba, + // Tapscript expansion + OP_INTERNALKEY = 0xcb, + OP_CHECKSIGFROMSTACK = 0xcc, + OP_PAIRCOMMIT = 0xcd, + OP_INVALIDOPCODE = 0xff, }; @@ -533,6 +539,7 @@ class CScript : public CScriptBase */ unsigned int GetSigOpCount(const CScript& scriptSig) const; + bool IsPayToBareDefaultCheckTemplateVerifyHash() const; bool IsPayToScriptHash() const; bool IsPayToWitnessScriptHash() const; bool IsWitnessProgram(int& version, std::vector& program) const; diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index fadc04262c31..f6f543f55c45 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -25,6 +25,8 @@ std::string ScriptErrorString(const ScriptError serror) return "Script failed an OP_CHECKSIGVERIFY operation"; case SCRIPT_ERR_NUMEQUALVERIFY: return "Script failed an OP_NUMEQUALVERIFY operation"; + case SCRIPT_ERR_TEMPLATE_MISMATCH: + return "Script failed an OP_CHECKTEMPLATEVERIFY operation"; case SCRIPT_ERR_SCRIPT_SIZE: return "Script is too big"; case SCRIPT_ERR_PUSH_SIZE: @@ -79,6 +81,8 @@ std::string ScriptErrorString(const ScriptError serror) return "OP_SUCCESSx reserved for soft-fork upgrades"; case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE: return "Public key version reserved for soft-fork upgrades"; + case SCRIPT_ERR_DISCOURAGE_LNHANCE: + return "LNHANCE opcodes are discouraged before activation"; case SCRIPT_ERR_PUBKEYTYPE: return "Public key is neither compressed or uncompressed"; case SCRIPT_ERR_CLEANSTACK: diff --git a/src/script/script_error.h b/src/script/script_error.h index 44e68fe0fae3..89dac1ba1b3a 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -29,6 +29,7 @@ typedef enum ScriptError_t SCRIPT_ERR_CHECKMULTISIGVERIFY, SCRIPT_ERR_CHECKSIGVERIFY, SCRIPT_ERR_NUMEQUALVERIFY, + SCRIPT_ERR_TEMPLATE_MISMATCH, /* Logical/Format/Canonical errors */ SCRIPT_ERR_BAD_OPCODE, @@ -59,6 +60,7 @@ typedef enum ScriptError_t SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE, + SCRIPT_ERR_DISCOURAGE_LNHANCE, /* segregated witness */ SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH, diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 22ac062a633a..79712b4719ac 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -412,6 +412,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator case TxoutType::NONSTANDARD: case TxoutType::NULL_DATA: case TxoutType::WITNESS_UNKNOWN: + case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY: return false; case TxoutType::PUBKEY: if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false; diff --git a/src/script/solver.cpp b/src/script/solver.cpp index 3dfa9cd6ba30..f8389cdeda1d 100644 --- a/src/script/solver.cpp +++ b/src/script/solver.cpp @@ -28,6 +28,7 @@ std::string GetTxnOutputType(TxoutType t) case TxoutType::WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash"; case TxoutType::WITNESS_V1_TAPROOT: return "witness_v1_taproot"; case TxoutType::WITNESS_UNKNOWN: return "witness_unknown"; + case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY: return "bare_default_ctv_hash"; } // no default case, so the compiler can warn about missing cases assert(false); } @@ -150,6 +151,10 @@ TxoutType Solver(const CScript& scriptPubKey, std::vector witnessprogram; if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { diff --git a/src/script/solver.h b/src/script/solver.h index dc8f4c357d53..8dbcc8105385 100644 --- a/src/script/solver.h +++ b/src/script/solver.h @@ -30,6 +30,7 @@ enum class TxoutType { WITNESS_V0_SCRIPTHASH, WITNESS_V0_KEYHASH, WITNESS_V1_TAPROOT, + TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY, WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above }; diff --git a/src/test/ctvhash_tests.cpp b/src/test/ctvhash_tests.cpp new file mode 100644 index 000000000000..0827aa6ed621 --- /dev/null +++ b/src/test/ctvhash_tests.cpp @@ -0,0 +1,199 @@ +// Copyright (c) 2013-2021 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