mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-08 10:31:50 -05:00
Compare commits
2 commits
d041e5879f
...
cdc90108e7
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cdc90108e7 | ||
![]() |
6ffdabd4a0 |
5 changed files with 35 additions and 33 deletions
|
@ -656,7 +656,7 @@ def spenders_taproot_active():
|
|||
# These are primarily tested through the test vectors implemented in libsecp256k1, and in src/tests/key_tests.cpp.
|
||||
# Some things are tested programmatically as well here.
|
||||
|
||||
tap = taproot_construct(pubs[0])
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT)
|
||||
# Test with key with bit flipped.
|
||||
add_spender(spenders, "sig/key", tap=tap, key=secs[0], failure={"key_tweaked": bitflipper(default_key_tweaked)}, **ERR_SIG_SCHNORR)
|
||||
# Test with sighash with bit flipped.
|
||||
|
@ -699,11 +699,11 @@ def spenders_taproot_active():
|
|||
|
||||
# Implement a test case that detects validation logic which maps invalid public keys to the
|
||||
# point at infinity in the tweaking logic.
|
||||
tap = taproot_construct(invalid_pub, [("true", CScript([OP_1]))], treat_internal_as_infinity=True)
|
||||
tap = taproot_construct(invalid_pub, LEAF_VERSION_TAPSCRIPT, [("true", CScript([OP_1]))], treat_internal_as_infinity=True)
|
||||
add_spender(spenders, "output/invalid_x", tap=tap, key_tweaked=tap.tweak, failure={"leaf": "true", "inputs": []}, **ERR_WITNESS_PROGRAM_MISMATCH)
|
||||
|
||||
# Do the same thing without invalid point, to make sure there is no mistake in the test logic.
|
||||
tap = taproot_construct(pubs[0], [("true", CScript([OP_1]))])
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, [("true", CScript([OP_1]))])
|
||||
add_spender(spenders, "output/invalid_x_mock", tap=tap, key=secs[0], leaf="true", inputs=[])
|
||||
|
||||
# == Tests for signature hashing ==
|
||||
|
@ -718,12 +718,12 @@ def spenders_taproot_active():
|
|||
common = {"annex": annex, "hashtype": hashtype, "standard": no_annex}
|
||||
|
||||
# Pure pubkey
|
||||
tap = taproot_construct(pubs[0])
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT)
|
||||
add_spender(spenders, "sighash/purepk", tap=tap, key=secs[0], **common, **SIGHASH_BITFLIP, **ERR_SIG_SCHNORR)
|
||||
|
||||
# Pubkey/P2PK script combination
|
||||
scripts = [("s0", CScript(random_checksig_style(pubs[1])))]
|
||||
tap = taproot_construct(pubs[0], scripts)
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
add_spender(spenders, "sighash/keypath_hashtype_%x" % hashtype, tap=tap, key=secs[0], **common, **SIGHASH_BITFLIP, **ERR_SIG_SCHNORR)
|
||||
add_spender(spenders, "sighash/scriptpath_hashtype_%x" % hashtype, tap=tap, leaf="s0", key=secs[1], **common, **SINGLE_SIG, **SIGHASH_BITFLIP, **ERR_SIG_SCHNORR)
|
||||
|
||||
|
@ -745,7 +745,7 @@ def spenders_taproot_active():
|
|||
# pushes (e.g. `OP_PUSH1 1` instead of `OP_1`), we set a minimum data size of 2 bytes.
|
||||
]
|
||||
random.shuffle(scripts)
|
||||
tap = taproot_construct(pubs[0], scripts)
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
add_spender(spenders, "sighash/pk_codesep", tap=tap, leaf="pk_codesep", key=secs[1], **common, **SINGLE_SIG, **SIGHASH_BITFLIP, **ERR_SIG_SCHNORR)
|
||||
add_spender(spenders, "sighash/codesep_pk", tap=tap, leaf="codesep_pk", key=secs[1], codeseppos=0, **common, **SINGLE_SIG, **SIGHASH_BITFLIP, **ERR_SIG_SCHNORR)
|
||||
add_spender(spenders, "sighash/branched_codesep/left", tap=tap, leaf="branched_codesep", key=secs[0], codeseppos=3, **common, inputs=[getter("sign"), b'\x01'], **SIGHASH_BITFLIP, **ERR_SIG_SCHNORR)
|
||||
|
@ -785,7 +785,7 @@ def spenders_taproot_active():
|
|||
("csa_neg", CScript([OP_2, pubs[2], OP_CHECKSIGADD, OP_2, OP_EQUAL]))
|
||||
]
|
||||
random.shuffle(scripts)
|
||||
tap = taproot_construct(pubs[3], scripts)
|
||||
tap = taproot_construct(pubs[3], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
# Empty signatures
|
||||
add_spender(spenders, "siglen/empty_keypath", tap=tap, key=secs[3], hashtype=hashtype, failure={"sign": b""}, **ERR_SIG_SIZE)
|
||||
add_spender(spenders, "siglen/empty_csv", tap=tap, key=secs[2], leaf="csv", hashtype=hashtype, **SINGLE_SIG, failure={"sign": b""}, **ERR_CHECKSIGVERIFY)
|
||||
|
@ -825,7 +825,7 @@ def spenders_taproot_active():
|
|||
prog += bytes([0 for _ in range(witlen - 32)])
|
||||
return CScript([CScriptOp.encode_op_n(witver), prog])
|
||||
scripts = [("s0", CScript([pubs[0], OP_CHECKSIG])), ("dummy", CScript([OP_RETURN]))]
|
||||
tap = taproot_construct(pubs[1], scripts)
|
||||
tap = taproot_construct(pubs[1], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
if not p2sh and witver == 1 and witlen == 32:
|
||||
add_spender(spenders, "applic/keypath", p2sh=p2sh, spk_mutate_pre_p2sh=mutate, tap=tap, key=secs[1], **SIGHASH_BITFLIP, **ERR_SIG_SCHNORR)
|
||||
add_spender(spenders, "applic/scriptpath", p2sh=p2sh, leaf="s0", spk_mutate_pre_p2sh=mutate, tap=tap, key=secs[0], **SINGLE_SIG, failure={"leaf": "dummy"}, **ERR_OP_RETURN)
|
||||
|
@ -861,7 +861,7 @@ def spenders_taproot_active():
|
|||
# Add 127 nodes on top of that tree, so that "128deep" and "129deep" end up at their designated depths.
|
||||
for _ in range(127):
|
||||
scripts = [scripts, random.choice(PARTNER_MERKLE_FN)]
|
||||
tap = taproot_construct(pubs[0], scripts)
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
# Test that spends with a depth of 128 work, but 129 doesn't (even with a tree with weird Merkle branches in it).
|
||||
add_spender(spenders, "spendpath/merklelimit", tap=tap, leaf="128deep", **SINGLE_SIG, key=secs[0], failure={"leaf": "129deep"}, **ERR_CONTROLBLOCK_SIZE)
|
||||
# Test that flipping the negation bit invalidates spends.
|
||||
|
@ -878,7 +878,7 @@ def spenders_taproot_active():
|
|||
add_spender(spenders, "spendpath/trunclongcontrol", tap=tap, leaf="128deep", **SINGLE_SIG, key=secs[0], failure={"controlblock": lambda ctx: default_merklebranch(ctx)[0:random.randrange(1, 32)]}, **ERR_CONTROLBLOCK_SIZE)
|
||||
|
||||
scripts = [("s", CScript([pubs[0], OP_CHECKSIG]))]
|
||||
tap = taproot_construct(pubs[1], scripts)
|
||||
tap = taproot_construct(pubs[1], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
# Test that adding garbage to the control block invalidates it.
|
||||
add_spender(spenders, "spendpath/padshortcontrol", tap=tap, leaf="s", **SINGLE_SIG, key=secs[0], failure={"controlblock": lambda ctx: default_controlblock(ctx) + random.randbytes(random.randrange(1, 32))}, **ERR_CONTROLBLOCK_SIZE)
|
||||
# Test that truncating the control block invalidates it.
|
||||
|
@ -997,7 +997,7 @@ def spenders_taproot_active():
|
|||
for j in range(100000):
|
||||
scripts.append((None, CScript([OP_RETURN, random.randrange(100000)])))
|
||||
random.shuffle(scripts)
|
||||
tap = taproot_construct(pubs[0], scripts)
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
common = {
|
||||
"hashtype": hashtype,
|
||||
"key": secs[1],
|
||||
|
@ -1106,7 +1106,7 @@ def spenders_taproot_active():
|
|||
scripts = [("s", fn(n, pubkey)[0])]
|
||||
for _ in range(merkledepth):
|
||||
scripts = [scripts, random.choice(PARTNER_MERKLE_FN)]
|
||||
tap = taproot_construct(pubs[0], scripts)
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
standard = annex is None and dummylen <= 80 and len(pubkey) == 32
|
||||
add_spender(spenders, "tapscript/sigopsratio_%i" % fn_num, tap=tap, leaf="s", annex=annex, hashtype=hashtype, key=secs[1], inputs=[getter("sign"), random.randbytes(dummylen)], standard=standard, failure={"inputs": [getter("sign"), random.randbytes(dummylen - 1)]}, **ERR_SIGOPS_RATIO)
|
||||
|
||||
|
@ -1128,7 +1128,7 @@ def spenders_taproot_active():
|
|||
("1001push_unkver", CScript([OP_0] * 1001), leafver),
|
||||
]
|
||||
random.shuffle(scripts)
|
||||
tap = taproot_construct(pubs[0], scripts)
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
add_spender(spenders, "unkver/bare", standard=False, tap=tap, leaf="bare_unkver", failure={"leaf": "bare_c0"}, **ERR_CLEANSTACK)
|
||||
add_spender(spenders, "unkver/return", standard=False, tap=tap, leaf="return_unkver", failure={"leaf": "return_c0"}, **ERR_OP_RETURN)
|
||||
add_spender(spenders, "unkver/undecodable", standard=False, tap=tap, leaf="undecodable_unkver", failure={"leaf": "undecodable_c0"}, **ERR_UNDECODABLE)
|
||||
|
@ -1158,7 +1158,7 @@ def spenders_taproot_active():
|
|||
("1001push_nop", CScript([OP_0] * 1001 + [OP_NOP])),
|
||||
]
|
||||
random.shuffle(scripts)
|
||||
tap = taproot_construct(pubs[0], scripts)
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
add_spender(spenders, "opsuccess/bare", standard=False, tap=tap, leaf="bare_success", failure={"leaf": "bare_nop"}, **ERR_CLEANSTACK)
|
||||
add_spender(spenders, "opsuccess/unexecif", standard=False, tap=tap, leaf="unexecif_success", failure={"leaf": "unexecif_nop"}, **ERR_CLEANSTACK)
|
||||
add_spender(spenders, "opsuccess/return", standard=False, tap=tap, leaf="return_success", failure={"leaf": "return_nop"}, **ERR_OP_RETURN)
|
||||
|
@ -1177,13 +1177,13 @@ def spenders_taproot_active():
|
|||
("normal", CScript([OP_RETURN, opcode] + [OP_NOP] * 75)),
|
||||
("op_success", CScript([OP_RETURN, CScriptOp(0x50)]))
|
||||
]
|
||||
tap = taproot_construct(pubs[0], scripts)
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
add_spender(spenders, "alwaysvalid/notsuccessx", tap=tap, leaf="op_success", inputs=[], standard=False, failure={"leaf": "normal"}) # err_msg differs based on opcode
|
||||
|
||||
# == Test case for https://github.com/bitcoin/bitcoin/issues/24765 ==
|
||||
|
||||
zero_fn = lambda h: bytes([0 for _ in range(32)])
|
||||
tap = taproot_construct(pubs[0], [("leaf", CScript([pubs[1], OP_CHECKSIG, pubs[1], OP_CHECKSIGADD, OP_2, OP_EQUAL])), zero_fn])
|
||||
tap = taproot_construct(pubs[0], LEAF_VERSION_TAPSCRIPT, [("leaf", CScript([pubs[1], OP_CHECKSIG, pubs[1], OP_CHECKSIGADD, OP_2, OP_EQUAL])), zero_fn])
|
||||
add_spender(spenders, "case24765", tap=tap, leaf="leaf", inputs=[getter("sign"), getter("sign")], key=secs[1], no_fail=True)
|
||||
|
||||
# == Legacy tests ==
|
||||
|
@ -1220,7 +1220,7 @@ def spenders_taproot_nonstandard():
|
|||
("future_leaf", CScript([pub, OP_CHECKSIG]), 0xc2),
|
||||
("op_success", CScript([pub, OP_CHECKSIG, OP_0, OP_IF, CScriptOp(0x50), OP_ENDIF])),
|
||||
]
|
||||
tap = taproot_construct(pub, scripts)
|
||||
tap = taproot_construct(pub, LEAF_VERSION_TAPSCRIPT, scripts)
|
||||
|
||||
# Test that features like annex, leaf versions, or OP_SUCCESS are valid but non-standard
|
||||
add_spender(spenders, "inactive/scriptpath_valid_unkleaf", key=sec, tap=tap, leaf="future_leaf", standard=False, inputs=[getter("sign")])
|
||||
|
@ -1565,7 +1565,7 @@ class TaprootTest(BitcoinTestFramework):
|
|||
[("1", CScript([pubs[58], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT), ("2", CScript([pubs[59], OP_CHECKSIG]), LEAF_VERSION_TAPSCRIPT)]
|
||||
],
|
||||
]
|
||||
taps = [taproot_construct(inner_keys[i], script_lists[i]) for i in range(len(inner_keys))]
|
||||
taps = [taproot_construct(inner_keys[i], LEAF_VERSION_TAPSCRIPT, script_lists[i]) for i in range(len(inner_keys))]
|
||||
|
||||
# Require negated taps[0]
|
||||
assert taps[0].negflag
|
||||
|
|
|
@ -19,6 +19,7 @@ from .script import (
|
|||
hash256,
|
||||
sha256,
|
||||
taproot_construct,
|
||||
LEAF_VERSION_TAPSCRIPT
|
||||
)
|
||||
from .util import assert_equal
|
||||
from test_framework.script_util import (
|
||||
|
@ -56,7 +57,7 @@ def create_deterministic_address_bcrt1_p2tr_op_true(explicit_internal_key=None):
|
|||
Returns a tuple with the generated address and the TaprootInfo object.
|
||||
"""
|
||||
internal_key = explicit_internal_key or (1).to_bytes(32, 'big')
|
||||
taproot_info = taproot_construct(internal_key, [("only-path", CScript([OP_TRUE]))])
|
||||
taproot_info = taproot_construct(internal_key, LEAF_VERSION_TAPSCRIPT, [("only-path", CScript([OP_TRUE]))])
|
||||
address = output_key_to_p2tr(taproot_info.output_pubkey)
|
||||
if explicit_internal_key is None:
|
||||
assert_equal(address, 'bcrt1p9yfmy5h72durp7zrhlw9lf7jpwjgvwdg0jr0lqmmjtgg83266lqsekaqka')
|
||||
|
|
|
@ -856,7 +856,7 @@ def TaprootSignatureMsg(txTo, spent_utxos, hash_type, input_index=0, *, scriptpa
|
|||
def TaprootSignatureHash(*args, **kwargs):
|
||||
return TaggedHash("TapSighash", TaprootSignatureMsg(*args, **kwargs))
|
||||
|
||||
def taproot_tree_helper(scripts):
|
||||
def taproot_tree_helper(scripts, leaf_version):
|
||||
if len(scripts) == 0:
|
||||
return ([], bytes())
|
||||
if len(scripts) == 1:
|
||||
|
@ -864,30 +864,29 @@ def taproot_tree_helper(scripts):
|
|||
script = scripts[0]
|
||||
assert not callable(script)
|
||||
if isinstance(script, list):
|
||||
return taproot_tree_helper(script)
|
||||
return taproot_tree_helper(script, leaf_version)
|
||||
assert isinstance(script, tuple)
|
||||
version = LEAF_VERSION_TAPSCRIPT
|
||||
name = script[0]
|
||||
code = script[1]
|
||||
if len(script) == 3:
|
||||
version = script[2]
|
||||
assert version & 1 == 0
|
||||
leaf_version = script[2]
|
||||
assert leaf_version & 1 == 0
|
||||
assert isinstance(code, bytes)
|
||||
h = TaggedHash("TapLeaf", bytes([version]) + ser_string(code))
|
||||
h = TaggedHash("TapLeaf", bytes([leaf_version]) + ser_string(code))
|
||||
if name is None:
|
||||
return ([], h)
|
||||
return ([(name, version, code, bytes(), h)], h)
|
||||
return ([(name, leaf_version, code, bytes(), h)], h)
|
||||
elif len(scripts) == 2 and callable(scripts[1]):
|
||||
# Two entries, and the right one is a function
|
||||
left, left_h = taproot_tree_helper(scripts[0:1])
|
||||
left, left_h = taproot_tree_helper(scripts[0:1], leaf_version)
|
||||
right_h = scripts[1](left_h)
|
||||
left = [(name, version, script, control + right_h, leaf) for name, version, script, control, leaf in left]
|
||||
right = []
|
||||
else:
|
||||
# Two or more entries: descend into each side
|
||||
split_pos = len(scripts) // 2
|
||||
left, left_h = taproot_tree_helper(scripts[0:split_pos])
|
||||
right, right_h = taproot_tree_helper(scripts[split_pos:])
|
||||
left, left_h = taproot_tree_helper(scripts[0:split_pos], leaf_version)
|
||||
right, right_h = taproot_tree_helper(scripts[split_pos:], leaf_version)
|
||||
left = [(name, version, script, control + right_h, leaf) for name, version, script, control, leaf in left]
|
||||
right = [(name, version, script, control + left_h, leaf) for name, version, script, control, leaf in right]
|
||||
if right_h < left_h:
|
||||
|
@ -910,7 +909,7 @@ TaprootInfo = namedtuple("TaprootInfo", "scriptPubKey,internal_pubkey,negflag,tw
|
|||
# - merklebranch: the merkle branch to use for this leaf (32*N bytes)
|
||||
TaprootLeafInfo = namedtuple("TaprootLeafInfo", "script,version,merklebranch,leaf_hash")
|
||||
|
||||
def taproot_construct(pubkey, scripts=None, treat_internal_as_infinity=False):
|
||||
def taproot_construct(pubkey, leaf_version, scripts=None, treat_internal_as_infinity=False):
|
||||
"""Construct a tree of Taproot spending conditions
|
||||
|
||||
pubkey: a 32-byte xonly pubkey for the internal pubkey (bytes)
|
||||
|
@ -927,7 +926,7 @@ def taproot_construct(pubkey, scripts=None, treat_internal_as_infinity=False):
|
|||
if scripts is None:
|
||||
scripts = []
|
||||
|
||||
ret, h = taproot_tree_helper(scripts)
|
||||
ret, h = taproot_tree_helper(scripts, leaf_version)
|
||||
tweak = TaggedHash("TapTweak", pubkey + h)
|
||||
if treat_internal_as_infinity:
|
||||
tweaked, negated = compute_xonly_pubkey(tweak)
|
||||
|
|
|
@ -36,6 +36,7 @@ from test_framework.messages import (
|
|||
ser_compact_size,
|
||||
)
|
||||
from test_framework.script import (
|
||||
LEAF_VERSION_TAPSCRIPT,
|
||||
CScript,
|
||||
OP_1,
|
||||
OP_NOP,
|
||||
|
@ -445,7 +446,7 @@ def getnewdestination(address_type='bech32m'):
|
|||
scriptpubkey = key_to_p2wpkh_script(pubkey)
|
||||
address = key_to_p2wpkh(pubkey)
|
||||
elif address_type == 'bech32m':
|
||||
tap = taproot_construct(compute_xonly_pubkey(key.get_bytes())[0])
|
||||
tap = taproot_construct(compute_xonly_pubkey(key.get_bytes())[0], LEAF_VERSION_TAPSCRIPT)
|
||||
pubkey = tap.output_pubkey
|
||||
scriptpubkey = tap.scriptPubKey
|
||||
address = output_key_to_p2tr(pubkey)
|
||||
|
|
|
@ -20,6 +20,7 @@ from test_framework.script import (
|
|||
OP_CHECKSIGADD,
|
||||
OP_NUMEQUAL,
|
||||
taproot_construct,
|
||||
LEAF_VERSION_TAPSCRIPT
|
||||
)
|
||||
from test_framework.segwit_addr import encode_segwit_address
|
||||
|
||||
|
@ -179,7 +180,7 @@ def multi_a(k, hex_keys, sort=False):
|
|||
|
||||
def compute_taproot_address(pubkey, scripts):
|
||||
"""Compute the address for a taproot output with given inner key and scripts."""
|
||||
return output_key_to_p2tr(taproot_construct(pubkey, scripts).output_pubkey)
|
||||
return output_key_to_p2tr(taproot_construct(pubkey, LEAF_VERSION_TAPSCRIPT, scripts).output_pubkey)
|
||||
|
||||
def compute_raw_taproot_address(pubkey):
|
||||
return encode_segwit_address("bcrt", 1, pubkey)
|
||||
|
|
Loading…
Add table
Reference in a new issue