1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-25 07:48:10 +00:00

core/sign_tx: Implement support for signed external inputs.

This commit is contained in:
Andrew Kozlik 2020-06-20 17:28:21 +02:00 committed by Andrew Kozlik
parent 78f14d286e
commit d48a372ca7
11 changed files with 233 additions and 89 deletions

View File

@ -110,22 +110,22 @@ def output_derive_script(address: str, coin: CoinInfo) -> bytes:
# see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification # see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
# item 5 for details # item 5 for details
def bip143_derive_script_code(txi: TxInputType, pubkeyhash: bytes) -> bytearray: def bip143_derive_script_code(
txi: TxInputType, public_keys: List[bytes], threshold: int, coin: CoinInfo
if txi.multisig: ) -> bytearray:
return output_script_multisig( if len(public_keys) > 1:
multisig_get_pubkeys(txi.multisig), txi.multisig.m return output_script_multisig(public_keys, threshold)
)
p2pkh = ( p2pkh = (
txi.script_type == InputScriptType.SPENDWITNESS txi.script_type == InputScriptType.SPENDWITNESS
or txi.script_type == InputScriptType.SPENDP2SHWITNESS or txi.script_type == InputScriptType.SPENDP2SHWITNESS
or txi.script_type == InputScriptType.SPENDADDRESS or txi.script_type == InputScriptType.SPENDADDRESS
or txi.script_type == InputScriptType.EXTERNAL
) )
if p2pkh: if p2pkh:
# for p2wpkh in p2sh or native p2wpkh # for p2wpkh in p2sh or native p2wpkh
# the scriptCode is a classic p2pkh # the scriptCode is a classic p2pkh
return output_script_p2pkh(pubkeyhash) return output_script_p2pkh(common.ecdsa_hash_pubkey(public_keys[0], coin))
else: else:
raise wire.DataError("Unknown input script type for bip143 script code") raise wire.DataError("Unknown input script type for bip143 script code")

View File

@ -3,7 +3,7 @@ from micropython import const
from trezor import wire from trezor import wire
from trezor.crypto.hashlib import sha256 from trezor.crypto.hashlib import sha256
from trezor.messages import InputScriptType from trezor.messages import InputScriptType, OutputScriptType
from trezor.messages.SignTx import SignTx from trezor.messages.SignTx import SignTx
from trezor.messages.TransactionType import TransactionType from trezor.messages.TransactionType import TransactionType
from trezor.messages.TxInputType import TxInputType from trezor.messages.TxInputType import TxInputType
@ -18,12 +18,13 @@ from apps.common import coininfo, seed
from apps.common.writers import write_bitcoin_varint from apps.common.writers import write_bitcoin_varint
from .. import addresses, common, multisig, scripts, writers from .. import addresses, common, multisig, scripts, writers
from ..common import ecdsa_hash_pubkey, ecdsa_sign from ..common import ecdsa_sign
from ..verification import SignatureVerifier
from . import helpers, progress, tx_weight from . import helpers, progress, tx_weight
from .matchcheck import MultisigFingerprintChecker, WalletPathChecker from .matchcheck import MultisigFingerprintChecker, WalletPathChecker
if False: if False:
from typing import Set, Optional, Tuple, Union from typing import List, Optional, Set, Tuple, Union
from trezor.crypto.bip32 import HDNode from trezor.crypto.bip32 import HDNode
# Default signature hash type in Bitcoin which signs all inputs and all outputs of the transaction. # Default signature hash type in Bitcoin which signs all inputs and all outputs of the transaction.
@ -42,8 +43,6 @@ _MAX_SERIALIZED_CHUNK_SIZE = const(2048)
class Bitcoin: class Bitcoin:
async def signer(self) -> None: async def signer(self) -> None:
progress.init(self.tx.inputs_count, self.tx.outputs_count)
# Add inputs to hash143 and h_confirmed and compute the sum of input amounts # Add inputs to hash143 and h_confirmed and compute the sum of input amounts
# by requesting each previous transaction and checking its output amounts. # by requesting each previous transaction and checking its output amounts.
await self.step1_process_inputs() await self.step1_process_inputs()
@ -55,17 +54,20 @@ class Bitcoin:
# Check fee, confirm lock_time and total. # Check fee, confirm lock_time and total.
await self.step3_confirm_tx() await self.step3_confirm_tx()
# Verify external inputs which have already been signed.
await self.step4_verify_external_inputs()
# Check that inputs are unchanged. Serialize inputs and sign the non-segwit ones. # Check that inputs are unchanged. Serialize inputs and sign the non-segwit ones.
await self.step4_serialize_inputs() await self.step5_serialize_inputs()
# Serialize outputs. # Serialize outputs.
await self.step5_serialize_outputs() await self.step6_serialize_outputs()
# Sign segwit inputs and serialize witness data. # Sign segwit inputs and serialize witness data.
await self.step6_sign_segwit_inputs() await self.step7_sign_segwit_inputs()
# Write footer and send remaining data. # Write footer and send remaining data.
await self.step7_finish() await self.step8_finish()
def __init__( def __init__(
self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo
@ -83,8 +85,12 @@ class Bitcoin:
# set of indices of inputs which are segwit # set of indices of inputs which are segwit
self.segwit = set() # type: Set[int] self.segwit = set() # type: Set[int]
# set of indices of inputs which are external
self.external = set() # type: Set[int]
# amounts # amounts
self.total_in = 0 # sum of input amounts self.total_in = 0 # sum of input amounts
self.external_in = 0 # sum of external input amounts
self.total_out = 0 # sum of output amounts self.total_out = 0 # sum of output amounts
self.change_out = 0 # change output amount self.change_out = 0 # change output amount
self.weight = tx_weight.TxWeightCalculator(tx.inputs_count, tx.outputs_count) self.weight = tx_weight.TxWeightCalculator(tx.inputs_count, tx.outputs_count)
@ -98,24 +104,36 @@ class Bitcoin:
# h_confirmed is used to make sure that the inputs and outputs streamed for # h_confirmed is used to make sure that the inputs and outputs streamed for
# confirmation in Steps 1 and 2 are the same as the ones streamed for signing # confirmation in Steps 1 and 2 are the same as the ones streamed for signing
# legacy inputs in Step 4. # legacy inputs in Step 5.
self.h_confirmed = self.create_hash_writer() # not a real tx hash self.h_confirmed = self.create_hash_writer() # not a real tx hash
# h_external is used to make sure that the signed external inputs streamed for
# confirmation in Step 1 are the same as the ones streamed for verification
# in Step 3.
self.h_external = self.create_hash_writer()
# BIP-0143 transaction hashing # BIP-0143 transaction hashing
self.init_hash143() self.init_hash143()
progress.init(self.tx.inputs_count, self.tx.outputs_count)
def create_hash_writer(self) -> HashWriter: def create_hash_writer(self) -> HashWriter:
return HashWriter(sha256()) return HashWriter(sha256())
async def step1_process_inputs(self) -> None: async def step1_process_inputs(self) -> None:
for i in range(self.tx.inputs_count): for i in range(self.tx.inputs_count):
# STAGE_REQUEST_1_INPUT in legacy # STAGE_REQUEST_1_INPUT in legacy
progress.advance()
txi = await helpers.request_tx_input(self.tx_req, i, self.coin) txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
self.weight.add_input(txi) self.weight.add_input(txi)
if input_is_segwit(txi): if input_is_segwit(txi):
self.segwit.add(i) self.segwit.add(i)
await self.process_input(txi)
if input_is_external(txi):
self.external.add(i)
await self.process_external_input(txi)
else:
progress.advance()
await self.process_internal_input(txi)
async def step2_confirm_outputs(self) -> None: async def step2_confirm_outputs(self) -> None:
for i in range(self.tx.outputs_count): for i in range(self.tx.outputs_count):
@ -136,40 +154,80 @@ class Bitcoin:
await helpers.confirm_feeoverthreshold(fee, self.coin) await helpers.confirm_feeoverthreshold(fee, self.coin)
if self.tx.lock_time > 0: if self.tx.lock_time > 0:
await helpers.confirm_nondefault_locktime(self.tx.lock_time) await helpers.confirm_nondefault_locktime(self.tx.lock_time)
await helpers.confirm_total(self.total_in - self.change_out, fee, self.coin) await helpers.confirm_total(
self.total_in - self.external_in - self.change_out, fee, self.coin
)
async def step4_serialize_inputs(self) -> None: async def step4_verify_external_inputs(self) -> None:
# should come out the same as h_external, checked before continuing
h_check = self.create_hash_writer()
for i in sorted(self.external):
progress.advance()
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
writers.write_tx_input_check(h_check, txi)
prev_amount, script_pubkey = await self.get_prevtx_output(
txi.prev_hash, txi.prev_index
)
if prev_amount != txi.amount:
raise wire.DataError("Invalid amount specified")
verifier = SignatureVerifier(
script_pubkey, txi.script_sig, txi.witness, self.coin
)
verifier.ensure_hash_type(self.get_hash_type(txi))
tx_digest = await self.get_tx_digest(
i, txi, verifier.public_keys, verifier.threshold, script_pubkey
)
verifier.verify(tx_digest)
# check that the inputs were the same as those streamed for confirmation
if self.h_external.get_digest() != h_check.get_digest():
raise wire.ProcessError("Transaction has changed during signing")
async def step5_serialize_inputs(self) -> None:
self.write_tx_header(self.serialized_tx, self.tx, bool(self.segwit)) self.write_tx_header(self.serialized_tx, self.tx, bool(self.segwit))
write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count) write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count)
for i in range(self.tx.inputs_count): for i in range(self.tx.inputs_count):
progress.advance() progress.advance()
if i in self.segwit: if i in self.external:
await self.serialize_external_input(i)
elif i in self.segwit:
await self.serialize_segwit_input(i) await self.serialize_segwit_input(i)
else: else:
await self.sign_nonsegwit_input(i) await self.sign_nonsegwit_input(i)
async def step5_serialize_outputs(self) -> None: async def step6_serialize_outputs(self) -> None:
write_bitcoin_varint(self.serialized_tx, self.tx.outputs_count) write_bitcoin_varint(self.serialized_tx, self.tx.outputs_count)
for i in range(self.tx.outputs_count): for i in range(self.tx.outputs_count):
progress.advance() progress.advance()
await self.serialize_output(i) await self.serialize_output(i)
async def step6_sign_segwit_inputs(self) -> None: async def step7_sign_segwit_inputs(self) -> None:
any_segwit = bool(self.segwit) if not self.segwit:
progress.advance(self.tx.inputs_count)
return
for i in range(self.tx.inputs_count): for i in range(self.tx.inputs_count):
progress.advance() progress.advance()
if i in self.segwit: if i in self.segwit:
if i in self.external:
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
self.serialized_tx.extend(txi.witness)
else:
await self.sign_segwit_input(i) await self.sign_segwit_input(i)
elif any_segwit: else:
# add empty witness for non-segwit inputs # add empty witness for non-segwit inputs
self.serialized_tx.append(0) self.serialized_tx.append(0)
async def step7_finish(self) -> None: async def step8_finish(self) -> None:
self.write_tx_footer(self.serialized_tx, self.tx) self.write_tx_footer(self.serialized_tx, self.tx)
await helpers.request_tx_finish(self.tx_req) await helpers.request_tx_finish(self.tx_req)
async def process_input(self, txi: TxInputType) -> None: async def process_internal_input(self, txi: TxInputType) -> None:
self.wallet_path.add_input(txi) self.wallet_path.add_input(txi)
self.multisig_fingerprint.add_input(txi) self.multisig_fingerprint.add_input(txi)
writers.write_tx_input_check(self.h_confirmed, txi) writers.write_tx_input_check(self.h_confirmed, txi)
@ -190,6 +248,16 @@ class Bitcoin:
self.total_in += prev_amount self.total_in += prev_amount
async def process_external_input(self, txi: TxInputType) -> None:
if txi.amount is None:
raise wire.DataError("Expected input with amount")
writers.write_tx_input_check(self.h_external, txi)
writers.write_tx_input_check(self.h_confirmed, txi)
self.hash143_add_input(txi) # all inputs are included (non-segwit as well)
self.total_in += txi.amount
self.external_in += txi.amount
async def confirm_output(self, txo: TxOutputType, script_pubkey: bytes) -> None: async def confirm_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
if self.change_out == 0 and self.output_is_change(txo): if self.change_out == 0 and self.output_is_change(txo):
# output is change and does not need confirmation # output is change and does not need confirmation
@ -201,9 +269,30 @@ class Bitcoin:
self.hash143_add_output(txo, script_pubkey) self.hash143_add_output(txo, script_pubkey)
self.total_out += txo.amount self.total_out += txo.amount
async def get_tx_digest(
self,
i: int,
txi: TxInputType,
public_keys: List[bytes],
threshold: int,
script_pubkey: bytes,
) -> bytes:
if txi.witness:
return self.hash143_preimage_hash(txi, public_keys, threshold)
else:
digest, _, _ = await self.get_legacy_tx_digest(i, script_pubkey)
return digest
def on_negative_fee(self) -> None: def on_negative_fee(self) -> None:
raise wire.NotEnoughFunds("Not enough funds") raise wire.NotEnoughFunds("Not enough funds")
async def serialize_external_input(self, i: int) -> None:
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
if not input_is_external(txi):
raise wire.ProcessError("Transaction has changed during signing")
self.write_tx_input(self.serialized_tx, txi, txi.script_sig)
async def serialize_segwit_input(self, i: int) -> None: async def serialize_segwit_input(self, i: int) -> None:
# STAGE_REQUEST_SEGWIT_INPUT in legacy # STAGE_REQUEST_SEGWIT_INPUT in legacy
txi = await helpers.request_tx_input(self.tx_req, i, self.coin) txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
@ -228,9 +317,14 @@ class Bitcoin:
node = self.keychain.derive(txi.address_n) node = self.keychain.derive(txi.address_n)
public_key = node.public_key() public_key = node.public_key()
hash143_hash = self.hash143_preimage_hash(
txi, ecdsa_hash_pubkey(public_key, self.coin) if txi.multisig:
) public_keys = multisig.multisig_get_pubkeys(txi.multisig)
threshold = txi.multisig.m
else:
public_keys = [public_key]
threshold = 1
hash143_hash = self.hash143_preimage_hash(txi, public_keys, threshold)
signature = ecdsa_sign(node, hash143_hash) signature = ecdsa_sign(node, hash143_hash)
@ -313,7 +407,7 @@ class Bitcoin:
writers.write_uint32(h_sign, self.tx.lock_time) writers.write_uint32(h_sign, self.tx.lock_time)
writers.write_uint32(h_sign, self.get_sighash_type(txi_sign)) writers.write_uint32(h_sign, self.get_sighash_type(txi_sign))
# check the control digests # check that the inputs were the same as those streamed for confirmation
if self.h_confirmed.get_digest() != h_check.get_digest(): if self.h_confirmed.get_digest() != h_check.get_digest():
raise wire.ProcessError("Transaction has changed during signing") raise wire.ProcessError("Transaction has changed during signing")
@ -506,10 +600,12 @@ class Bitcoin:
writers.write_uint32(self.h_prevouts, txi.prev_index) writers.write_uint32(self.h_prevouts, txi.prev_index)
writers.write_uint32(self.h_sequence, txi.sequence) writers.write_uint32(self.h_sequence, txi.sequence)
def hash143_add_output(self, txo: TxOutputType, script_pubkey) -> None: def hash143_add_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
writers.write_tx_output(self.h_outputs, txo, script_pubkey) writers.write_tx_output(self.h_outputs, txo, script_pubkey)
def hash143_preimage_hash(self, txi: TxInputType, pubkeyhash: bytes) -> bytes: def hash143_preimage_hash(
self, txi: TxInputType, public_keys: List[bytes], threshold: int
) -> bytes:
h_preimage = HashWriter(sha256()) h_preimage = HashWriter(sha256())
# nVersion # nVersion
@ -532,7 +628,9 @@ class Bitcoin:
writers.write_uint32(h_preimage, txi.prev_index) writers.write_uint32(h_preimage, txi.prev_index)
# scriptCode # scriptCode
script_code = scripts.bip143_derive_script_code(txi, pubkeyhash) script_code = scripts.bip143_derive_script_code(
txi, public_keys, threshold, self.coin
)
writers.write_bytes_prefixed(h_preimage, script_code) writers.write_bytes_prefixed(h_preimage, script_code)
# amount # amount
@ -557,8 +655,16 @@ class Bitcoin:
def input_is_segwit(txi: TxInputType) -> bool: def input_is_segwit(txi: TxInputType) -> bool:
return txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES return txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES or (
txi.script_type == InputScriptType.EXTERNAL and txi.witness is not None
)
def input_is_nonsegwit(txi: TxInputType) -> bool: def input_is_nonsegwit(txi: TxInputType) -> bool:
return txi.script_type in common.NONSEGWIT_INPUT_SCRIPT_TYPES return txi.script_type in common.NONSEGWIT_INPUT_SCRIPT_TYPES or (
txi.script_type == InputScriptType.EXTERNAL and txi.witness is None
)
def input_is_external(txi: TxInputType) -> bool:
return txi.script_type == InputScriptType.EXTERNAL

View File

@ -4,6 +4,7 @@ from micropython import const
from trezor import wire from trezor import wire
from trezor.messages.SignTx import SignTx from trezor.messages.SignTx import SignTx
from trezor.messages.TransactionType import TransactionType from trezor.messages.TransactionType import TransactionType
from trezor.messages.TxInputType import TxInputType
from apps.common.writers import write_bitcoin_varint from apps.common.writers import write_bitcoin_varint
@ -12,7 +13,7 @@ from . import helpers
from .bitcoin import Bitcoin, input_is_nonsegwit from .bitcoin import Bitcoin, input_is_nonsegwit
if False: if False:
from typing import Union from typing import List, Union
_SIGHASH_FORKID = const(0x40) _SIGHASH_FORKID = const(0x40)
@ -41,6 +42,21 @@ class Bitcoinlike(Bitcoin):
else: else:
await super().sign_nonsegwit_input(i_sign) await super().sign_nonsegwit_input(i_sign)
async def get_tx_digest(
self,
i: int,
txi: TxInputType,
public_keys: List[bytes],
threshold: int,
script_pubkey: bytes,
) -> bytes:
if self.coin.force_bip143:
return self.hash143_preimage_hash(txi, public_keys, threshold)
else:
return await super().get_tx_digest(
i, txi, public_keys, threshold, script_pubkey
)
def on_negative_fee(self) -> None: def on_negative_fee(self) -> None:
# some coins require negative fees for reward TX # some coins require negative fees for reward TX
if not self.coin.negative_fee: if not self.coin.negative_fee:

View File

@ -57,17 +57,20 @@ class Decred(Bitcoin):
self.write_tx_footer(self.serialized_tx, self.tx) self.write_tx_footer(self.serialized_tx, self.tx)
self.write_tx_footer(self.h_prefix, self.tx) self.write_tx_footer(self.h_prefix, self.tx)
async def process_input(self, txi: TxInputType) -> None: async def process_internal_input(self, txi: TxInputType) -> None:
await super().process_input(txi) await super().process_internal_input(txi)
# Decred serializes inputs early. # Decred serializes inputs early.
self.write_tx_input(self.serialized_tx, txi, bytes()) self.write_tx_input(self.serialized_tx, txi, bytes())
async def process_external_input(self, txi: TxInputType) -> None:
raise wire.DataError("External inputs not supported")
async def confirm_output(self, txo: TxOutputType, script_pubkey: bytes) -> None: async def confirm_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
await super().confirm_output(txo, script_pubkey) await super().confirm_output(txo, script_pubkey)
self.write_tx_output(self.serialized_tx, txo, script_pubkey) self.write_tx_output(self.serialized_tx, txo, script_pubkey)
async def step4_serialize_inputs(self) -> None: async def step5_serialize_inputs(self) -> None:
write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count) write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count)
prefix_hash = self.h_prefix.get_digest() prefix_hash = self.h_prefix.get_digest()
@ -125,13 +128,13 @@ class Decred(Bitcoin):
self.write_tx_input_witness(self.serialized_tx, txi_sign, script_sig) self.write_tx_input_witness(self.serialized_tx, txi_sign, script_sig)
self.set_serialized_signature(i_sign, signature) self.set_serialized_signature(i_sign, signature)
async def step5_serialize_outputs(self) -> None: async def step6_serialize_outputs(self) -> None:
pass pass
async def step6_sign_segwit_inputs(self) -> None: async def step7_sign_segwit_inputs(self) -> None:
pass pass
async def step7_finish(self) -> None: async def step8_finish(self) -> None:
await helpers.request_tx_finish(self.tx_req) await helpers.request_tx_finish(self.tx_req)
def check_prevtx_output(self, txo_bin: TxOutputBinType) -> None: def check_prevtx_output(self, txo_bin: TxOutputBinType) -> None:

View File

@ -220,7 +220,7 @@ def sanitize_tx_input(tx: TransactionType, coin: CoinInfo) -> TxInputType:
raise wire.DataError("Input's address_n provided but not expected.") raise wire.DataError("Input's address_n provided but not expected.")
if not coin.decred and txi.decred_tree is not None: if not coin.decred and txi.decred_tree is not None:
raise wire.DataError("Decred details provided but Decred coin not specified.") raise wire.DataError("Decred details provided but Decred coin not specified.")
if txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES: if txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES or txi.witness is not None:
if not coin.segwit: if not coin.segwit:
raise wire.DataError("Segwit not enabled on this coin") raise wire.DataError("Segwit not enabled on this coin")
return txi return txi

View File

@ -12,9 +12,9 @@ def init(inputs: int, outputs: int) -> None:
report() report()
def advance() -> None: def advance(i: int = 1) -> None:
global _progress global _progress
_progress += 1 _progress += i
report() report()

View File

@ -13,7 +13,7 @@ from apps.common.coininfo import CoinInfo
from apps.common.seed import Keychain from apps.common.seed import Keychain
from apps.common.writers import write_bitcoin_varint from apps.common.writers import write_bitcoin_varint
from ..multisig import multisig_get_pubkeys from ..common import ecdsa_hash_pubkey
from ..scripts import output_script_multisig, output_script_p2pkh from ..scripts import output_script_multisig, output_script_p2pkh
from ..writers import ( from ..writers import (
TX_HASH_SIZE, TX_HASH_SIZE,
@ -28,7 +28,7 @@ from . import helpers
from .bitcoinlike import Bitcoinlike from .bitcoinlike import Bitcoinlike
if False: if False:
from typing import Union from typing import List, Union
from ..writers import Writer from ..writers import Writer
OVERWINTERED = const(0x80000000) OVERWINTERED = const(0x80000000)
@ -48,7 +48,7 @@ class Overwintered(Bitcoinlike):
else: else:
raise wire.DataError("Unsupported version for overwintered transaction") raise wire.DataError("Unsupported version for overwintered transaction")
async def step7_finish(self) -> None: async def step8_finish(self) -> None:
self.write_tx_footer(self.serialized_tx, self.tx) self.write_tx_footer(self.serialized_tx, self.tx)
if self.tx.version == 3: if self.tx.version == 3:
@ -66,6 +66,16 @@ class Overwintered(Bitcoinlike):
async def sign_nonsegwit_input(self, i_sign: int) -> None: async def sign_nonsegwit_input(self, i_sign: int) -> None:
await self.sign_nonsegwit_bip143_input(i_sign) await self.sign_nonsegwit_bip143_input(i_sign)
async def get_tx_digest(
self,
i: int,
txi: TxInputType,
public_keys: List[bytes],
threshold: int,
script_pubkey: bytes,
) -> bytes:
return self.hash143_preimage_hash(txi, public_keys, threshold)
def write_tx_header( def write_tx_header(
self, w: Writer, tx: Union[SignTx, TransactionType], witness_marker: bool self, w: Writer, tx: Union[SignTx, TransactionType], witness_marker: bool
) -> None: ) -> None:
@ -90,7 +100,9 @@ class Overwintered(Bitcoinlike):
self.h_sequence = HashWriter(blake2b(outlen=32, personal=b"ZcashSequencHash")) self.h_sequence = HashWriter(blake2b(outlen=32, personal=b"ZcashSequencHash"))
self.h_outputs = HashWriter(blake2b(outlen=32, personal=b"ZcashOutputsHash")) self.h_outputs = HashWriter(blake2b(outlen=32, personal=b"ZcashOutputsHash"))
def hash143_preimage_hash(self, txi: TxInputType, pubkeyhash: bytes) -> bytes: def hash143_preimage_hash(
self, txi: TxInputType, public_keys: List[bytes], threshold: int
) -> bytes:
h_preimage = HashWriter( h_preimage = HashWriter(
blake2b( blake2b(
outlen=32, outlen=32,
@ -142,7 +154,7 @@ class Overwintered(Bitcoinlike):
write_uint32(h_preimage, txi.prev_index) write_uint32(h_preimage, txi.prev_index)
# 10b / 13b. scriptCode # 10b / 13b. scriptCode
script_code = derive_script_code(txi, pubkeyhash) script_code = derive_script_code(txi, public_keys, threshold, self.coin)
write_bytes_prefixed(h_preimage, script_code) write_bytes_prefixed(h_preimage, script_code)
# 10c / 13c. value # 10c / 13c. value
@ -154,16 +166,15 @@ class Overwintered(Bitcoinlike):
return get_tx_hash(h_preimage) return get_tx_hash(h_preimage)
def derive_script_code(txi: TxInputType, pubkeyhash: bytes) -> bytearray: def derive_script_code(
txi: TxInputType, public_keys: List[bytes], threshold: int, coin: CoinInfo
) -> bytearray:
if len(public_keys) > 1:
return output_script_multisig(public_keys, threshold)
if txi.multisig: p2pkh = txi.script_type in (InputScriptType.SPENDADDRESS, InputScriptType.EXTERNAL)
return output_script_multisig(
multisig_get_pubkeys(txi.multisig), txi.multisig.m
)
p2pkh = txi.script_type == InputScriptType.SPENDADDRESS
if p2pkh: if p2pkh:
return output_script_p2pkh(pubkeyhash) return output_script_p2pkh(ecdsa_hash_pubkey(public_keys[0], coin))
else: else:
raise wire.DataError("Unknown input script type for zip143 script code") raise wire.DataError("Unknown input script type for zip143 script code")

View File

@ -4,6 +4,7 @@ from apps.bitcoin.scripts import output_derive_script
from apps.bitcoin.sign_tx.bitcoin import Bitcoin from apps.bitcoin.sign_tx.bitcoin import Bitcoin
from apps.bitcoin.writers import get_tx_hash from apps.bitcoin.writers import get_tx_hash
from apps.common import coins from apps.common import coins
from apps.common.seed import Keychain
from trezor.messages.SignTx import SignTx from trezor.messages.SignTx import SignTx
from trezor.messages.TxInputType import TxInputType from trezor.messages.TxInputType import TxInputType
from trezor.messages.TxOutputType import TxOutputType from trezor.messages.TxOutputType import TxOutputType
@ -89,10 +90,13 @@ class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
script_pubkey = output_derive_script(txo.address, coin) script_pubkey = output_derive_script(txo.address, coin)
bip143.hash143_add_output(txo_bin, script_pubkey) bip143.hash143_add_output(txo_bin, script_pubkey)
keychain = Keychain(seed, [[coin.curve_name, []]])
node = keychain.derive(self.inp2.address_n)
# test data public key hash # test data public key hash
# only for input 2 - input 1 is not segwit # only for input 2 - input 1 is not segwit
result = bip143.hash143_preimage_hash(self.inp2, unhexlify('1d0f172a0ecb48aee1be1f2687d2963ae33f71a1')) result = bip143.hash143_preimage_hash(self.inp2, [node.public_key()], 1)
self.assertEqual(hexlify(result), b'c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670') self.assertEqual(hexlify(result), b'2fa3f1351618b2532228d7182d3221d95c21fd3d496e7e22e9ded873cf022a8b')
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -4,6 +4,7 @@ from apps.bitcoin.scripts import output_derive_script
from apps.bitcoin.sign_tx.bitcoin import Bitcoin from apps.bitcoin.sign_tx.bitcoin import Bitcoin
from apps.bitcoin.writers import get_tx_hash from apps.bitcoin.writers import get_tx_hash
from apps.common import coins from apps.common import coins
from apps.common.seed import Keychain
from trezor.messages.SignTx import SignTx from trezor.messages.SignTx import SignTx
from trezor.messages.TxInputType import TxInputType from trezor.messages.TxInputType import TxInputType
from trezor.messages.TxOutputType import TxOutputType from trezor.messages.TxOutputType import TxOutputType
@ -75,9 +76,12 @@ class TestSegwitBip143(unittest.TestCase):
script_pubkey = output_derive_script(txo.address, coin) script_pubkey = output_derive_script(txo.address, coin)
bip143.hash143_add_output(txo_bin, script_pubkey) bip143.hash143_add_output(txo_bin, script_pubkey)
keychain = Keychain(seed, [[coin.curve_name, []]])
node = keychain.derive(self.inp1.address_n)
# test data public key hash # test data public key hash
result = bip143.hash143_preimage_hash(self.inp1, unhexlify('79091972186c449eb1ded22b78e40d009bdf0089')) result = bip143.hash143_preimage_hash(self.inp1, [node.public_key()], 1)
self.assertEqual(hexlify(result), b'64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6') self.assertEqual(hexlify(result), b'6e28aca7041720995d4acf59bbda64eef5d6f23723d23f2e994757546674bbd9')
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -25,7 +25,7 @@ class TestZcashZip143(unittest.TestCase):
"702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76", "702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76",
4025613248, 4025613248,
], ],
"pubkeyhash": "4d9cafb657677f2321fc538e367767dbdf551539", "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"sequence": 1999822371, "sequence": 1999822371,
} }
@ -40,7 +40,7 @@ class TestZcashZip143(unittest.TestCase):
"prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688", "prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688",
"sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a", "sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a",
"outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992", "outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992",
"preimage_hash": b"287146efaa30b3c1c7bd1a72308c46205712e6944780fdc5a7f91f477fddd55b", "preimage_hash": b"fed855ea5fcec81928fa35d39b8582c6e026a0bf52cebeed4445a7fc7d730280",
}, },
{ {
"expiry": 231041495, "expiry": 231041495,
@ -51,7 +51,7 @@ class TestZcashZip143(unittest.TestCase):
"76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2", "76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2",
1547817817, 1547817817,
], ],
"pubkeyhash": "9f5d230603ce57a0e8b31a8c9b6c983ad5b00cd5", "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"sequence": 3973122135, "sequence": 3973122135,
}, },
@ -61,7 +61,7 @@ class TestZcashZip143(unittest.TestCase):
"cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483", "cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483",
3053054889, 3053054889,
], ],
"pubkeyhash": "b5e71ef1df5ed3a2589607ca58ed19634f07fb4f", "pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d",
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"sequence": 3932380530, "sequence": 3932380530,
}, },
@ -77,7 +77,7 @@ class TestZcashZip143(unittest.TestCase):
"prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b", "prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b",
"sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e", "sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e",
"outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1", "outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1",
"preimage_hash": b"b71358954aca8ffe1d3f1b5707ed6c082ed2b35e35e293b897bfc12ae7c85396", "preimage_hash": b"1c6f563d2f16002f4c59bec5e7d56ed298315630c1d7e9a431b89e6f81026a02",
}, },
{ {
"expiry": 186996458, "expiry": 186996458,
@ -89,7 +89,7 @@ class TestZcashZip143(unittest.TestCase):
1290359941, 1290359941,
], ],
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "0873d1baed6c8696e4bd2b26755692b4d8050086", "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
"sequence": 1230917966, "sequence": 1230917966,
} }
], ],
@ -101,7 +101,7 @@ class TestZcashZip143(unittest.TestCase):
"prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd", "prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd",
"sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc", "sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc",
"outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824", "outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824",
"preimage_hash": b"19ea4ce2467cb5cdcc4562ce81b22006f1fb55189ea93ccc7a3bc78ff5d97a93", "preimage_hash": b"7159247daa16cc7e683f03ebf968314ce03324028ac138468a7b76c77e551fe8",
}, },
{ {
"expiry": 254788522, "expiry": 254788522,
@ -113,7 +113,7 @@ class TestZcashZip143(unittest.TestCase):
1517971891, 1517971891,
], ],
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "80b6c35a9b2efd77dbfd5d5d3bb1fd03ff40f182", "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
"sequence": 3833577708, "sequence": 3833577708,
}, },
{ {
@ -123,7 +123,7 @@ class TestZcashZip143(unittest.TestCase):
687648622, 687648622,
], ],
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "fb8c27a442afe0f0b39a3875823c4893fe8f8550", "pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d",
"sequence": 4190617831, "sequence": 4190617831,
}, },
], ],
@ -137,7 +137,7 @@ class TestZcashZip143(unittest.TestCase):
"prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898", "prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898",
"sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23", "sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23",
"outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a", "outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a",
"preimage_hash": b"d0b92233e185a69f320f18bfacff7e5dcc5f0ed02af2f3ecf59359853e105e59", "preimage_hash": b"16b24c5d599107efb41cbc6cb0127094878bab1e0d33d734cfccce58e07b3386",
}, },
] ]
@ -175,7 +175,7 @@ class TestZcashZip143(unittest.TestCase):
self.assertEqual(hexlify(get_tx_hash(zip143.h_sequence)), v["sequence_hash"]) self.assertEqual(hexlify(get_tx_hash(zip143.h_sequence)), v["sequence_hash"])
self.assertEqual(hexlify(get_tx_hash(zip143.h_outputs)), v["outputs_hash"]) self.assertEqual(hexlify(get_tx_hash(zip143.h_outputs)), v["outputs_hash"])
self.assertEqual( self.assertEqual(
hexlify(zip143.hash143_preimage_hash(txi, unhexlify(i["pubkeyhash"]))), hexlify(zip143.hash143_preimage_hash(txi, [unhexlify(i["pubkey"])], 1)),
v["preimage_hash"], v["preimage_hash"],
) )

View File

@ -25,7 +25,7 @@ class TestZcashZip243(unittest.TestCase):
"702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76", "702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76",
4025613248, 4025613248,
], ],
"pubkeyhash": "4d9cafb657677f2321fc538e367767dbdf551539", "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"sequence": 1999822371, "sequence": 1999822371,
} }
@ -40,7 +40,7 @@ class TestZcashZip243(unittest.TestCase):
"prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688", "prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688",
"sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a", "sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a",
"outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992", "outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992",
"preimage_hash": b"53a12bca557c27defa366c2b4c0e46ede01f81ef3dd3aa3750db62a5505c1d06", "preimage_hash": b"f8772c6ecf9d903698fb8c51cd7b99605af298478989945936935da65e064695",
}, },
{ {
"expiry": 231041495, "expiry": 231041495,
@ -51,7 +51,7 @@ class TestZcashZip243(unittest.TestCase):
"76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2", "76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2",
1547817817, 1547817817,
], ],
"pubkeyhash": "9f5d230603ce57a0e8b31a8c9b6c983ad5b00cd5", "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"sequence": 3973122135, "sequence": 3973122135,
}, },
@ -61,7 +61,7 @@ class TestZcashZip243(unittest.TestCase):
"cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483", "cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483",
3053054889, 3053054889,
], ],
"pubkeyhash": "b5e71ef1df5ed3a2589607ca58ed19634f07fb4f", "pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d",
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"sequence": 3932380530, "sequence": 3932380530,
}, },
@ -77,7 +77,7 @@ class TestZcashZip243(unittest.TestCase):
"prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b", "prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b",
"sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e", "sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e",
"outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1", "outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1",
"preimage_hash": b"d1bc60986cc5c4d57f91002e48459a50f72bdb96b8f5889cf8f467a7d968b97c", "preimage_hash": b"0eb47dc51d89cc52378fc182242f78ebd3609544a365d2270c23b4052f301025",
}, },
{ {
"expiry": 186996458, "expiry": 186996458,
@ -89,7 +89,7 @@ class TestZcashZip243(unittest.TestCase):
1290359941, 1290359941,
], ],
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "0873d1baed6c8696e4bd2b26755692b4d8050086", "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
"sequence": 1230917966, "sequence": 1230917966,
} }
], ],
@ -101,7 +101,7 @@ class TestZcashZip243(unittest.TestCase):
"prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd", "prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd",
"sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc", "sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc",
"outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824", "outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824",
"preimage_hash": b"7536cdb202a30bf09c45e1a2f775c4efd41b9e67557b62abe12b64d367a2316e", "preimage_hash": b"7f6b5439a64b20faf6f9f9460bc75c333c4799e9b04c80c26a79b8e801b8b6e1",
}, },
{ {
"expiry": 254788522, "expiry": 254788522,
@ -113,7 +113,7 @@ class TestZcashZip243(unittest.TestCase):
1517971891, 1517971891,
], ],
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "80b6c35a9b2efd77dbfd5d5d3bb1fd03ff40f182", "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
"sequence": 3833577708, "sequence": 3833577708,
}, },
{ {
@ -123,7 +123,7 @@ class TestZcashZip243(unittest.TestCase):
687648622, 687648622,
], ],
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "fb8c27a442afe0f0b39a3875823c4893fe8f8550", "pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d",
"sequence": 4190617831, "sequence": 4190617831,
}, },
], ],
@ -137,7 +137,7 @@ class TestZcashZip243(unittest.TestCase):
"prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898", "prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898",
"sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23", "sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23",
"outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a", "outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a",
"preimage_hash": b"df1359c0aacc05e88ae6bbecfc54fef50bd31f21f543c49f95a321dd835263be", "preimage_hash": b"46152b79ebeba4089d05724e33d4a5e6d6ea9e3a2fe777af6644318ba93a1ca0",
}, },
# "Test vector 3" from https://github.com/zcash/zips/blob/master/zip-0243.rst # "Test vector 3" from https://github.com/zcash/zips/blob/master/zip-0243.rst
{ {
@ -150,7 +150,7 @@ class TestZcashZip243(unittest.TestCase):
1, 1,
], ],
"script_type": InputScriptType.SPENDADDRESS, "script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "507173527b4c3318a2aecd793bf1cfed705950cf", "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
"sequence": 0xfffffffe, "sequence": 0xfffffffe,
} }
], ],
@ -171,7 +171,7 @@ class TestZcashZip243(unittest.TestCase):
"prevouts_hash": b"fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f11", "prevouts_hash": b"fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f11",
"sequence_hash": b"6c80d37f12d89b6f17ff198723e7db1247c4811d1a695d74d930f99e98418790", "sequence_hash": b"6c80d37f12d89b6f17ff198723e7db1247c4811d1a695d74d930f99e98418790",
"outputs_hash": b"d2b04118469b7810a0d1cc59568320aad25a84f407ecac40b4f605a4e6868454", "outputs_hash": b"d2b04118469b7810a0d1cc59568320aad25a84f407ecac40b4f605a4e6868454",
"preimage_hash": b"f3148f80dfab5e573d5edfe7a850f5fd39234f80b5429d3a57edcc11e34c585b", "preimage_hash": b"6c210ce6417539d4aa9546f6184e33ca89224ac4559d2a9c4cf090b646692bd9",
}, },
] ]
@ -208,7 +208,7 @@ class TestZcashZip243(unittest.TestCase):
self.assertEqual(hexlify(get_tx_hash(zip243.h_prevouts)), v["prevouts_hash"]) self.assertEqual(hexlify(get_tx_hash(zip243.h_prevouts)), v["prevouts_hash"])
self.assertEqual(hexlify(get_tx_hash(zip243.h_sequence)), v["sequence_hash"]) self.assertEqual(hexlify(get_tx_hash(zip243.h_sequence)), v["sequence_hash"])
self.assertEqual(hexlify(get_tx_hash(zip243.h_outputs)), v["outputs_hash"]) self.assertEqual(hexlify(get_tx_hash(zip243.h_outputs)), v["outputs_hash"])
self.assertEqual(hexlify(zip243.hash143_preimage_hash(txi, unhexlify(i["pubkeyhash"]))), v["preimage_hash"]) self.assertEqual(hexlify(zip243.hash143_preimage_hash(txi, [unhexlify(i["pubkey"])], 1)), v["preimage_hash"])
if __name__ == "__main__": if __name__ == "__main__":