mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-01 09:35:52 -05:00
Add OP_INTERNALKEY for Tapscript
Testing is minimal, but so is the code.
This commit is contained in:
parent
2a07c4662d
commit
85206c238d
8 changed files with 44 additions and 4 deletions
|
@ -113,7 +113,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI
|
||||||
SCRIPT_VERIFY_CONST_SCRIPTCODE |
|
SCRIPT_VERIFY_CONST_SCRIPTCODE |
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
|
||||||
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
|
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE};
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE |
|
||||||
|
SCRIPT_VERIFY_INTERNALKEY};
|
||||||
|
|
||||||
/** For convenience, standard but not mandatory verify flags. */
|
/** 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};
|
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
|
||||||
|
|
|
@ -1213,6 +1213,15 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_INTERNALKEY: {
|
||||||
|
// OP_INTERNALKEY is only available in Tapscript
|
||||||
|
if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
||||||
|
// Always present in Tapscript
|
||||||
|
assert(execdata.m_internal_key);
|
||||||
|
stack.emplace_back(execdata.m_internal_key->begin(), execdata.m_internal_key->end());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
||||||
}
|
}
|
||||||
|
@ -1798,6 +1807,12 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
|
||||||
// Note how this condition would not be reached if an unknown OP_SUCCESSx was found
|
// Note how this condition would not be reached if an unknown OP_SUCCESSx was found
|
||||||
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
||||||
}
|
}
|
||||||
|
if (opcode == OP_INTERNALKEY) {
|
||||||
|
if (flags & SCRIPT_VERIFY_DISCOURAGE_INTERNALKEY)
|
||||||
|
return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS);
|
||||||
|
if (flags & SCRIPT_VERIFY_INTERNALKEY) continue;
|
||||||
|
return set_success(serror);
|
||||||
|
}
|
||||||
// New opcodes will be listed here. May use a different sigversion to modify existing opcodes.
|
// New opcodes will be listed here. May use a different sigversion to modify existing opcodes.
|
||||||
if (IsOpSuccess(opcode)) {
|
if (IsOpSuccess(opcode)) {
|
||||||
if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) {
|
if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) {
|
||||||
|
@ -1856,12 +1871,13 @@ uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint25
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, const std::vector<unsigned char>& program, const uint256& tapleaf_hash)
|
static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, const std::vector<unsigned char>& program, const uint256& tapleaf_hash, std::optional<XOnlyPubKey>& internal_key)
|
||||||
{
|
{
|
||||||
assert(control.size() >= TAPROOT_CONTROL_BASE_SIZE);
|
assert(control.size() >= TAPROOT_CONTROL_BASE_SIZE);
|
||||||
assert(program.size() >= uint256::size());
|
assert(program.size() >= uint256::size());
|
||||||
//! The internal pubkey (x-only, so no Y coordinate parity).
|
//! The internal pubkey (x-only, so no Y coordinate parity).
|
||||||
const XOnlyPubKey p{Span{control}.subspan(1, TAPROOT_CONTROL_BASE_SIZE - 1)};
|
const XOnlyPubKey p{Span{control}.subspan(1, TAPROOT_CONTROL_BASE_SIZE - 1)};
|
||||||
|
internal_key = p;
|
||||||
//! The output pubkey (taken from the scriptPubKey).
|
//! The output pubkey (taken from the scriptPubKey).
|
||||||
const XOnlyPubKey q{program};
|
const XOnlyPubKey q{program};
|
||||||
// Compute the Merkle root from the leaf and the provided path.
|
// Compute the Merkle root from the leaf and the provided path.
|
||||||
|
@ -1927,7 +1943,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
|
||||||
return set_error(serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE);
|
return set_error(serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE);
|
||||||
}
|
}
|
||||||
execdata.m_tapleaf_hash = ComputeTapleafHash(control[0] & TAPROOT_LEAF_MASK, script);
|
execdata.m_tapleaf_hash = ComputeTapleafHash(control[0] & TAPROOT_LEAF_MASK, script);
|
||||||
if (!VerifyTaprootCommitment(control, program, execdata.m_tapleaf_hash)) {
|
if (!VerifyTaprootCommitment(control, program, execdata.m_tapleaf_hash, execdata.m_internal_key)) {
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
||||||
}
|
}
|
||||||
execdata.m_tapleaf_hash_init = true;
|
execdata.m_tapleaf_hash_init = true;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <script/script_error.h> // IWYU pragma: export
|
#include <script/script_error.h> // IWYU pragma: export
|
||||||
#include <span.h>
|
#include <span.h>
|
||||||
|
#include <pubkey.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
@ -143,6 +144,12 @@ enum : uint32_t {
|
||||||
// Making unknown public key versions (in BIP 342 scripts) non-standard
|
// Making unknown public key versions (in BIP 342 scripts) non-standard
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
|
||||||
|
|
||||||
|
// Executing OP_INTERNALKEY
|
||||||
|
SCRIPT_VERIFY_INTERNALKEY = (1U << 21),
|
||||||
|
|
||||||
|
// Making OP_INTERNALKEY non-standard
|
||||||
|
SCRIPT_VERIFY_DISCOURAGE_INTERNALKEY = (1U << 22),
|
||||||
|
|
||||||
// Constants to point to the highest flag in use. Add new flags above this line.
|
// Constants to point to the highest flag in use. Add new flags above this line.
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_END_MARKER
|
SCRIPT_VERIFY_END_MARKER
|
||||||
|
@ -221,6 +228,9 @@ struct ScriptExecutionData
|
||||||
|
|
||||||
//! The hash of the corresponding output
|
//! The hash of the corresponding output
|
||||||
std::optional<uint256> m_output_hash;
|
std::optional<uint256> m_output_hash;
|
||||||
|
|
||||||
|
//! The taproot internal key. */
|
||||||
|
std::optional<XOnlyPubKey> m_internal_key = std::nullopt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Signature hash sizes */
|
/** Signature hash sizes */
|
||||||
|
|
|
@ -149,6 +149,8 @@ std::string GetOpName(opcodetype opcode)
|
||||||
// Opcode added by BIP 342 (Tapscript)
|
// Opcode added by BIP 342 (Tapscript)
|
||||||
case OP_CHECKSIGADD : return "OP_CHECKSIGADD";
|
case OP_CHECKSIGADD : return "OP_CHECKSIGADD";
|
||||||
|
|
||||||
|
case OP_INTERNALKEY : return "OP_INTERNALKEY";
|
||||||
|
|
||||||
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -207,6 +207,7 @@ enum opcodetype
|
||||||
|
|
||||||
// Opcode added by BIP 342 (Tapscript)
|
// Opcode added by BIP 342 (Tapscript)
|
||||||
OP_CHECKSIGADD = 0xba,
|
OP_CHECKSIGADD = 0xba,
|
||||||
|
OP_INTERNALKEY = 0xcb,
|
||||||
|
|
||||||
OP_INVALIDOPCODE = 0xff,
|
OP_INVALIDOPCODE = 0xff,
|
||||||
};
|
};
|
||||||
|
|
|
@ -520,5 +520,13 @@
|
||||||
[[["1111111111111111111111111111111111111111111111111111111111111111", 0, "0x00 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6", 5000000]],
|
[[["1111111111111111111111111111111111111111111111111111111111111111", 0, "0x00 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6", 5000000]],
|
||||||
"0100000000010111111111111111111111111111111111111111111111111111111111111111110000000000ffffffff0130244c0000000000fd02014cdc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac02483045022100c1a4a6581996a7fdfea77d58d537955a5655c1d619b6f3ab6874f28bb2e19708022056402db6fede03caae045a3be616a1a2d0919a475ed4be828dc9ff21f24063aa01210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179800000000", "NONE"],
|
"0100000000010111111111111111111111111111111111111111111111111111111111111111110000000000ffffffff0130244c0000000000fd02014cdc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac02483045022100c1a4a6581996a7fdfea77d58d537955a5655c1d619b6f3ab6874f28bb2e19708022056402db6fede03caae045a3be616a1a2d0919a475ed4be828dc9ff21f24063aa01210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179800000000", "NONE"],
|
||||||
|
|
||||||
|
["Test OP_INTERNALKEY"],
|
||||||
|
[[["e2f2baee9c59389b34e39742ce05debf64aaa7a00fbdab88614f4d3c133186d5",
|
||||||
|
0,
|
||||||
|
"1 0x20 0xa9e62de0f9782710f702214fc81c0f0f90fb3537987b3685caad6d52db305447",
|
||||||
|
155000]],
|
||||||
|
"02000000000101d58631133c4d4f6188abbd0fa0a7aa64bfde05ce4297e3349b38599ceebaf2e20000000000ffffffff01f0490200000000002251202ca3bc76489a54904ad2507005789afc1e6b362b451be89f69de39ddf9ba8abf0223cb2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac08721c050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac000000000",
|
||||||
|
"DISCOURAGE_INTERNALKEY"],
|
||||||
|
|
||||||
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
||||||
]
|
]
|
||||||
|
|
|
@ -65,6 +65,8 @@ static std::map<std::string, unsigned int> mapFlagNames = {
|
||||||
{std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE},
|
{std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE},
|
||||||
{std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS},
|
{std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS},
|
||||||
{std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION},
|
{std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION},
|
||||||
|
{std::string("INTERNALKEY"), (unsigned int)SCRIPT_VERIFY_INTERNALKEY},
|
||||||
|
{std::string("DISCOURAGE_INTERNALKEY"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_INTERNALKEY},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned int ParseScriptFlags(std::string strFlags)
|
unsigned int ParseScriptFlags(std::string strFlags)
|
||||||
|
|
|
@ -924,4 +924,4 @@ def taproot_construct(pubkey, scripts=None, treat_internal_as_infinity=False):
|
||||||
return TaprootInfo(CScript([OP_1, tweaked]), pubkey, negated + 0, tweak, leaves, h, tweaked)
|
return TaprootInfo(CScript([OP_1, tweaked]), pubkey, negated + 0, tweak, leaves, h, tweaked)
|
||||||
|
|
||||||
def is_op_success(o):
|
def is_op_success(o):
|
||||||
return o == 0x50 or o == 0x62 or o == 0x89 or o == 0x8a or o == 0x8d or o == 0x8e or (o >= 0x7e and o <= 0x81) or (o >= 0x83 and o <= 0x86) or (o >= 0x95 and o <= 0x99) or (o >= 0xbb and o <= 0xfe)
|
return o == 0x50 or o == 0x62 or o == 0x89 or o == 0x8a or o == 0x8d or o == 0x8e or (o >= 0x7e and o <= 0x81) or (o >= 0x83 and o <= 0x86) or (o >= 0x95 and o <= 0x99) or (o >= 0xbb and o <= 0xca) or (o >= 0xcc and o <= 0xfe)
|
||||||
|
|
Loading…
Add table
Reference in a new issue