Skip to content

Commit

Permalink
Add OP_INTERNALKEY for Tapscript
Browse files Browse the repository at this point in the history
Testing is minimal, but so is the code.
  • Loading branch information
reardencode committed Jan 8, 2024
1 parent 0327dd3 commit eb3cba0
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 2 deletions.
18 changes: 17 additions & 1 deletion src/script/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,17 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
}
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);
if (flags & SCRIPT_VERIFY_DISCOURAGE_LNHANCE) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS);
}

stack.emplace_back(execdata.m_internal_key.begin(), execdata.m_internal_key.end());
break;
}

default:
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
Expand Down Expand Up @@ -1922,6 +1933,9 @@ 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
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
if ((flags & SCRIPT_VERIFY_LNHANCE) && opcode == OP_INTERNALKEY) {
continue;
}
// New opcodes will be listed here. May use a different sigversion to modify existing opcodes.
if (IsOpSuccess(opcode)) {
if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) {
Expand Down Expand Up @@ -1982,7 +1996,6 @@ uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint25

static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, const std::vector<unsigned char>& 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)};
Expand Down Expand Up @@ -2050,6 +2063,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);
Expand Down
4 changes: 4 additions & 0 deletions src/script/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,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).
Expand Down
2 changes: 2 additions & 0 deletions src/script/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ std::string GetOpName(opcodetype opcode)
// Opcode added by BIP 342 (Tapscript)
case OP_CHECKSIGADD : return "OP_CHECKSIGADD";

case OP_INTERNALKEY : return "OP_INTERNALKEY";

case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";

default:
Expand Down
1 change: 1 addition & 0 deletions src/script/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ enum opcodetype

// Opcode added by BIP 342 (Tapscript)
OP_CHECKSIGADD = 0xba,
OP_INTERNALKEY = 0xbb,

OP_INVALIDOPCODE = 0xff,
};
Expand Down
8 changes: 8 additions & 0 deletions src/test/data/tx_valid.json
Original file line number Diff line number Diff line change
Expand Up @@ -668,5 +668,13 @@
"0200000002d58631133c4d4f6188abbd0fa0a7aa64bfde05ce4297e3349b38599ceebaf2e20000000001510000000082b77fb944a40756a6341ee425c85d5850f2acbe6d51a7bcd211929a764b8ec8000000000100000000000ae80300000000000017a914d63e77972529f4db5b32efaa4e06f66ae0b5dc0987d00700000000000017a91488b6705f8c9568c52b55ed712c257f84f64a49f587b80b00000000000017a9142be57e9a179f8d9ff8f33a788d4b54512ea9e36087a00f00000000000017a91429261b4f65796f618908de9f51669014e2e2e04f87881300000000000017a914e3a1e1d24cbba3ca9369248082988bad3ceafcfb87701700000000000017a91403801b0a9591f3b5a00a5ea60fb34dc12b4a691187581b00000000000017a91465248bc2c732db2d88db0b0d677c1514b101025b87401f00000000000017a91420021e3dc4e80c7192c1a3cd04026d22d0f8d38287282300000000000017a914df27596dbff2028791bd7692846e65d16d8fed0d87102700000000000017a9142ed128e911cab04d3277d3635f79d5e3d7e6f4c48700000000",
"CLEANSTACK,DISCOURAGE_LNHANCE"],

["Test OP_INTERNALKEY"],
[[["e2f2baee9c59389b34e39742ce05debf64aaa7a00fbdab88614f4d3c133186d5",
0,
"1 0x20 0x15887b8f5cc1e8d98ffa7af368d0159cfbee6de780d012f7379ba12d363900e3",
155000]],
"02000000000101d58631133c4d4f6188abbd0fa0a7aa64bfde05ce4297e3349b38599ceebaf2e20000000000ffffffff01f0490200000000002251202ca3bc76489a54904ad2507005789afc1e6b362b451be89f69de39ddf9ba8abf0223bb2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac08721c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac000000000",
"DISCOURAGE_LNHANCE"],

["Make diffs cleaner by leaving a comment here without comma at the end"]
]
3 changes: 3 additions & 0 deletions src/test/transaction_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ bool CheckTxScripts(const CTransaction& tx, const std::map<COutPoint, CScript>&

unsigned int TrimFlags(unsigned int flags)
{
// !LNHANCE requires !DISCOURGE_OP_SUCCESS
if (!(flags & SCRIPT_VERIFY_LNHANCE)) flags &= ~(unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS;

// WITNESS requires P2SH
if (!(flags & SCRIPT_VERIFY_P2SH)) flags &= ~(unsigned int)SCRIPT_VERIFY_WITNESS;

Expand Down
2 changes: 1 addition & 1 deletion test/functional/test_framework/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -925,4 +925,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)

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 >= 0xbc and o <= 0xfe)

0 comments on commit eb3cba0

Please sign in to comment.