mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-06 16:34:22 +01:00
tests: give feature_taproot access to sighash preimages
This commit is contained in:
parent
5140825096
commit
a5bde018b4
2 changed files with 54 additions and 22 deletions
|
@ -25,8 +25,9 @@ from test_framework.script import (
|
||||||
CScript,
|
CScript,
|
||||||
CScriptNum,
|
CScriptNum,
|
||||||
CScriptOp,
|
CScriptOp,
|
||||||
|
hash256,
|
||||||
LEAF_VERSION_TAPSCRIPT,
|
LEAF_VERSION_TAPSCRIPT,
|
||||||
LegacySignatureHash,
|
LegacySignatureMsg,
|
||||||
LOCKTIME_THRESHOLD,
|
LOCKTIME_THRESHOLD,
|
||||||
MAX_SCRIPT_ELEMENT_SIZE,
|
MAX_SCRIPT_ELEMENT_SIZE,
|
||||||
OP_0,
|
OP_0,
|
||||||
|
@ -70,8 +71,9 @@ from test_framework.script import (
|
||||||
SIGHASH_NONE,
|
SIGHASH_NONE,
|
||||||
SIGHASH_SINGLE,
|
SIGHASH_SINGLE,
|
||||||
SIGHASH_ANYONECANPAY,
|
SIGHASH_ANYONECANPAY,
|
||||||
SegwitV0SignatureHash,
|
SegwitV0SignatureMsg,
|
||||||
TaprootSignatureHash,
|
TaggedHash,
|
||||||
|
TaprootSignatureMsg,
|
||||||
is_op_success,
|
is_op_success,
|
||||||
taproot_construct,
|
taproot_construct,
|
||||||
)
|
)
|
||||||
|
@ -194,8 +196,8 @@ def default_controlblock(ctx):
|
||||||
"""Default expression for "controlblock": combine leafversion, negflag, pubkey_internal, merklebranch."""
|
"""Default expression for "controlblock": combine leafversion, negflag, pubkey_internal, merklebranch."""
|
||||||
return bytes([get(ctx, "leafversion") + get(ctx, "negflag")]) + get(ctx, "pubkey_internal") + get(ctx, "merklebranch")
|
return bytes([get(ctx, "leafversion") + get(ctx, "negflag")]) + get(ctx, "pubkey_internal") + get(ctx, "merklebranch")
|
||||||
|
|
||||||
def default_sighash(ctx):
|
def default_sigmsg(ctx):
|
||||||
"""Default expression for "sighash": depending on mode, compute BIP341, BIP143, or legacy sighash."""
|
"""Default expression for "sigmsg": depending on mode, compute BIP341, BIP143, or legacy sigmsg."""
|
||||||
tx = get(ctx, "tx")
|
tx = get(ctx, "tx")
|
||||||
idx = get(ctx, "idx")
|
idx = get(ctx, "idx")
|
||||||
hashtype = get(ctx, "hashtype_actual")
|
hashtype = get(ctx, "hashtype_actual")
|
||||||
|
@ -208,18 +210,30 @@ def default_sighash(ctx):
|
||||||
codeseppos = get(ctx, "codeseppos")
|
codeseppos = get(ctx, "codeseppos")
|
||||||
leaf_ver = get(ctx, "leafversion")
|
leaf_ver = get(ctx, "leafversion")
|
||||||
script = get(ctx, "script_taproot")
|
script = get(ctx, "script_taproot")
|
||||||
return TaprootSignatureHash(tx, utxos, hashtype, idx, scriptpath=True, script=script, leaf_ver=leaf_ver, codeseparator_pos=codeseppos, annex=annex)
|
return TaprootSignatureMsg(tx, utxos, hashtype, idx, scriptpath=True, script=script, leaf_ver=leaf_ver, codeseparator_pos=codeseppos, annex=annex)
|
||||||
else:
|
else:
|
||||||
return TaprootSignatureHash(tx, utxos, hashtype, idx, scriptpath=False, annex=annex)
|
return TaprootSignatureMsg(tx, utxos, hashtype, idx, scriptpath=False, annex=annex)
|
||||||
elif mode == "witv0":
|
elif mode == "witv0":
|
||||||
# BIP143 signature hash
|
# BIP143 signature hash
|
||||||
scriptcode = get(ctx, "scriptcode")
|
scriptcode = get(ctx, "scriptcode")
|
||||||
utxos = get(ctx, "utxos")
|
utxos = get(ctx, "utxos")
|
||||||
return SegwitV0SignatureHash(scriptcode, tx, idx, hashtype, utxos[idx].nValue)
|
return SegwitV0SignatureMsg(scriptcode, tx, idx, hashtype, utxos[idx].nValue)
|
||||||
else:
|
else:
|
||||||
# Pre-segwit signature hash
|
# Pre-segwit signature hash
|
||||||
scriptcode = get(ctx, "scriptcode")
|
scriptcode = get(ctx, "scriptcode")
|
||||||
return LegacySignatureHash(scriptcode, tx, idx, hashtype)[0]
|
return LegacySignatureMsg(scriptcode, tx, idx, hashtype)[0]
|
||||||
|
|
||||||
|
def default_sighash(ctx):
|
||||||
|
"""Default expression for "sighash": depending on mode, compute tagged hash or dsha256 of sigmsg."""
|
||||||
|
msg = get(ctx, "sigmsg")
|
||||||
|
mode = get(ctx, "mode")
|
||||||
|
if mode == "taproot":
|
||||||
|
return TaggedHash("TapSighash", msg)
|
||||||
|
else:
|
||||||
|
if msg is None:
|
||||||
|
return (1).to_bytes(32, 'little')
|
||||||
|
else:
|
||||||
|
return hash256(msg)
|
||||||
|
|
||||||
def default_tweak(ctx):
|
def default_tweak(ctx):
|
||||||
"""Default expression for "tweak": None if a leaf is specified, tap[0] otherwise."""
|
"""Default expression for "tweak": None if a leaf is specified, tap[0] otherwise."""
|
||||||
|
@ -340,6 +354,8 @@ DEFAULT_CONTEXT = {
|
||||||
"key_tweaked": default_key_tweaked,
|
"key_tweaked": default_key_tweaked,
|
||||||
# The tweak to use (None for script path spends, the actual tweak for key path spends).
|
# The tweak to use (None for script path spends, the actual tweak for key path spends).
|
||||||
"tweak": default_tweak,
|
"tweak": default_tweak,
|
||||||
|
# The sigmsg value (preimage of sighash)
|
||||||
|
"sigmsg": default_sigmsg,
|
||||||
# The sighash value (32 bytes)
|
# The sighash value (32 bytes)
|
||||||
"sighash": default_sighash,
|
"sighash": default_sighash,
|
||||||
# The information about the chosen script path spend (TaprootLeafInfo object).
|
# The information about the chosen script path spend (TaprootLeafInfo object).
|
||||||
|
|
|
@ -619,16 +619,15 @@ def FindAndDelete(script, sig):
|
||||||
r += script[last_sop_idx:]
|
r += script[last_sop_idx:]
|
||||||
return CScript(r)
|
return CScript(r)
|
||||||
|
|
||||||
def LegacySignatureHash(script, txTo, inIdx, hashtype):
|
def LegacySignatureMsg(script, txTo, inIdx, hashtype):
|
||||||
"""Consensus-correct SignatureHash
|
"""Preimage of the signature hash, if it exists.
|
||||||
|
|
||||||
Returns (hash, err) to precisely match the consensus-critical behavior of
|
Returns either (None, err) to indicate error (which translates to sighash 1),
|
||||||
the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity)
|
or (msg, None).
|
||||||
"""
|
"""
|
||||||
HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
|
||||||
|
|
||||||
if inIdx >= len(txTo.vin):
|
if inIdx >= len(txTo.vin):
|
||||||
return (HASH_ONE, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin)))
|
return (None, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin)))
|
||||||
txtmp = CTransaction(txTo)
|
txtmp = CTransaction(txTo)
|
||||||
|
|
||||||
for txin in txtmp.vin:
|
for txin in txtmp.vin:
|
||||||
|
@ -645,7 +644,7 @@ def LegacySignatureHash(script, txTo, inIdx, hashtype):
|
||||||
elif (hashtype & 0x1f) == SIGHASH_SINGLE:
|
elif (hashtype & 0x1f) == SIGHASH_SINGLE:
|
||||||
outIdx = inIdx
|
outIdx = inIdx
|
||||||
if outIdx >= len(txtmp.vout):
|
if outIdx >= len(txtmp.vout):
|
||||||
return (HASH_ONE, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout)))
|
return (None, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout)))
|
||||||
|
|
||||||
tmp = txtmp.vout[outIdx]
|
tmp = txtmp.vout[outIdx]
|
||||||
txtmp.vout = []
|
txtmp.vout = []
|
||||||
|
@ -665,15 +664,27 @@ def LegacySignatureHash(script, txTo, inIdx, hashtype):
|
||||||
s = txtmp.serialize_without_witness()
|
s = txtmp.serialize_without_witness()
|
||||||
s += struct.pack(b"<I", hashtype)
|
s += struct.pack(b"<I", hashtype)
|
||||||
|
|
||||||
hash = hash256(s)
|
return (s, None)
|
||||||
|
|
||||||
return (hash, None)
|
def LegacySignatureHash(*args, **kwargs):
|
||||||
|
"""Consensus-correct SignatureHash
|
||||||
|
|
||||||
|
Returns (hash, err) to precisely match the consensus-critical behavior of
|
||||||
|
the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity)
|
||||||
|
"""
|
||||||
|
|
||||||
|
HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||||
|
msg, err = LegacySignatureMsg(*args, **kwargs)
|
||||||
|
if msg is None:
|
||||||
|
return (HASH_ONE, err)
|
||||||
|
else:
|
||||||
|
return (hash256(msg), err)
|
||||||
|
|
||||||
# TODO: Allow cached hashPrevouts/hashSequence/hashOutputs to be provided.
|
# TODO: Allow cached hashPrevouts/hashSequence/hashOutputs to be provided.
|
||||||
# Performance optimization probably not necessary for python tests, however.
|
# Performance optimization probably not necessary for python tests, however.
|
||||||
# Note that this corresponds to sigversion == 1 in EvalScript, which is used
|
# Note that this corresponds to sigversion == 1 in EvalScript, which is used
|
||||||
# for version 0 witnesses.
|
# for version 0 witnesses.
|
||||||
def SegwitV0SignatureHash(script, txTo, inIdx, hashtype, amount):
|
def SegwitV0SignatureMsg(script, txTo, inIdx, hashtype, amount):
|
||||||
|
|
||||||
hashPrevouts = 0
|
hashPrevouts = 0
|
||||||
hashSequence = 0
|
hashSequence = 0
|
||||||
|
@ -711,8 +722,10 @@ def SegwitV0SignatureHash(script, txTo, inIdx, hashtype, amount):
|
||||||
ss += ser_uint256(hashOutputs)
|
ss += ser_uint256(hashOutputs)
|
||||||
ss += struct.pack("<i", txTo.nLockTime)
|
ss += struct.pack("<i", txTo.nLockTime)
|
||||||
ss += struct.pack("<I", hashtype)
|
ss += struct.pack("<I", hashtype)
|
||||||
|
return ss
|
||||||
|
|
||||||
return hash256(ss)
|
def SegwitV0SignatureHash(*args, **kwargs):
|
||||||
|
return hash256(SegwitV0SignatureMsg(*args, **kwargs))
|
||||||
|
|
||||||
class TestFrameworkScript(unittest.TestCase):
|
class TestFrameworkScript(unittest.TestCase):
|
||||||
def test_bn2vch(self):
|
def test_bn2vch(self):
|
||||||
|
@ -742,7 +755,7 @@ class TestFrameworkScript(unittest.TestCase):
|
||||||
for value in values:
|
for value in values:
|
||||||
self.assertEqual(CScriptNum.decode(CScriptNum.encode(CScriptNum(value))), value)
|
self.assertEqual(CScriptNum.decode(CScriptNum.encode(CScriptNum(value))), value)
|
||||||
|
|
||||||
def TaprootSignatureHash(txTo, spent_utxos, hash_type, input_index = 0, scriptpath = False, script = CScript(), codeseparator_pos = -1, annex = None, leaf_ver = LEAF_VERSION_TAPSCRIPT):
|
def TaprootSignatureMsg(txTo, spent_utxos, hash_type, input_index = 0, scriptpath = False, script = CScript(), codeseparator_pos = -1, annex = None, leaf_ver = LEAF_VERSION_TAPSCRIPT):
|
||||||
assert (len(txTo.vin) == len(spent_utxos))
|
assert (len(txTo.vin) == len(spent_utxos))
|
||||||
assert (input_index < len(txTo.vin))
|
assert (input_index < len(txTo.vin))
|
||||||
out_type = SIGHASH_ALL if hash_type == 0 else hash_type & 3
|
out_type = SIGHASH_ALL if hash_type == 0 else hash_type & 3
|
||||||
|
@ -783,7 +796,10 @@ def TaprootSignatureHash(txTo, spent_utxos, hash_type, input_index = 0, scriptpa
|
||||||
ss += bytes([0])
|
ss += bytes([0])
|
||||||
ss += struct.pack("<i", codeseparator_pos)
|
ss += struct.pack("<i", codeseparator_pos)
|
||||||
assert len(ss) == 175 - (in_type == SIGHASH_ANYONECANPAY) * 49 - (out_type != SIGHASH_ALL and out_type != SIGHASH_SINGLE) * 32 + (annex is not None) * 32 + scriptpath * 37
|
assert len(ss) == 175 - (in_type == SIGHASH_ANYONECANPAY) * 49 - (out_type != SIGHASH_ALL and out_type != SIGHASH_SINGLE) * 32 + (annex is not None) * 32 + scriptpath * 37
|
||||||
return TaggedHash("TapSighash", ss)
|
return ss
|
||||||
|
|
||||||
|
def TaprootSignatureHash(*args, **kwargs):
|
||||||
|
return TaggedHash("TapSighash", TaprootSignatureMsg(*args, **kwargs))
|
||||||
|
|
||||||
def taproot_tree_helper(scripts):
|
def taproot_tree_helper(scripts):
|
||||||
if len(scripts) == 0:
|
if len(scripts) == 0:
|
||||||
|
|
Loading…
Add table
Reference in a new issue