1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-03-03 16:56:07 +00:00

chore(core): In apps.bitcoin move BIP143 hashing back to a separate class.

This commit is contained in:
Andrew Kozlik 2020-09-08 14:12:43 +02:00 committed by Andrew Kozlik
parent 443e0c101e
commit 5fc491c597
8 changed files with 241 additions and 186 deletions

View File

@ -15,6 +15,7 @@ from ..common import BIP32_WALLET_DEPTH, SIGHASH_ALL, ecdsa_sign
from ..ownership import verify_nonownership from ..ownership import verify_nonownership
from ..verification import SignatureVerifier from ..verification import SignatureVerifier
from . import approvers, helpers, progress from . import approvers, helpers, progress
from .hash143 import Hash143
from .matchcheck import MultisigFingerprintChecker, WalletPathChecker from .matchcheck import MultisigFingerprintChecker, WalletPathChecker
if False: if False:
@ -114,19 +115,22 @@ class Bitcoin:
self.h_inputs = None # type: Optional[bytes] self.h_inputs = None # type: Optional[bytes]
# BIP-0143 transaction hashing # BIP-0143 transaction hashing
self.init_hash143() self.hash143 = self.create_hash143()
progress.init(self.tx.inputs_count, self.tx.outputs_count) 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())
def create_hash143(self) -> Hash143:
return Hash143()
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
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.hash143_add_input(txi) # all inputs are included (non-segwit as well) self.hash143.add_input(txi) # all inputs are included (non-segwit as well)
writers.write_tx_input_check(self.h_approved, txi) writers.write_tx_input_check(self.h_approved, txi)
if input_is_segwit(txi): if input_is_segwit(txi):
@ -229,7 +233,7 @@ class Bitcoin:
await self.approver.add_external_output(txo, script_pubkey) await self.approver.add_external_output(txo, script_pubkey)
self.write_tx_output(self.h_approved, txo, script_pubkey) self.write_tx_output(self.h_approved, txo, script_pubkey)
self.hash143_add_output(txo, script_pubkey) self.hash143.add_output(txo, script_pubkey)
async def get_tx_digest( async def get_tx_digest(
self, self,
@ -240,7 +244,14 @@ class Bitcoin:
script_pubkey: bytes, script_pubkey: bytes,
) -> bytes: ) -> bytes:
if txi.witness: if txi.witness:
return self.hash143_preimage_hash(txi, public_keys, threshold) return self.hash143.preimage_hash(
txi,
public_keys,
threshold,
self.tx,
self.coin,
self.get_sighash_type(txi),
)
else: else:
digest, _, _ = await self.get_legacy_tx_digest(i, script_pubkey) digest, _, _ = await self.get_legacy_tx_digest(i, script_pubkey)
return digest return digest
@ -304,7 +315,9 @@ class Bitcoin:
else: else:
public_keys = [public_key] public_keys = [public_key]
threshold = 1 threshold = 1
hash143_hash = self.hash143_preimage_hash(txi, public_keys, threshold) hash143_hash = self.hash143.preimage_hash(
txi, public_keys, threshold, self.tx, self.coin, self.get_sighash_type(txi)
)
signature = ecdsa_sign(node, hash143_hash) signature = ecdsa_sign(node, hash143_hash)
@ -478,16 +491,16 @@ class Bitcoin:
# the fork ID value. # the fork ID value.
return self.get_sighash_type(txi) & 0xFF return self.get_sighash_type(txi) & 0xFF
@staticmethod
def write_tx_input( def write_tx_input(
self,
w: writers.Writer, w: writers.Writer,
txi: Union[TxInput, PrevInput], txi: Union[TxInput, PrevInput],
script: bytes, script: bytes,
) -> None: ) -> None:
writers.write_tx_input(w, txi, script) writers.write_tx_input(w, txi, script)
@staticmethod
def write_tx_output( def write_tx_output(
self,
w: writers.Writer, w: writers.Writer,
txo: Union[TxOutput, PrevOutput], txo: Union[TxOutput, PrevOutput],
script_pubkey: bytes, script_pubkey: bytes,
@ -574,74 +587,6 @@ class Bitcoin:
signature, signature,
) )
# BIP-0143
# ===
def init_hash143(self) -> None:
self.h_prevouts = HashWriter(sha256())
self.h_sequence = HashWriter(sha256())
self.h_outputs = HashWriter(sha256())
def hash143_add_input(self, txi: TxInput) -> None:
writers.write_bytes_reversed(
self.h_prevouts, txi.prev_hash, writers.TX_HASH_SIZE
)
writers.write_uint32(self.h_prevouts, txi.prev_index)
writers.write_uint32(self.h_sequence, txi.sequence)
def hash143_add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
writers.write_tx_output(self.h_outputs, txo, script_pubkey)
def hash143_preimage_hash(
self, txi: TxInput, public_keys: List[bytes], threshold: int
) -> bytes:
h_preimage = HashWriter(sha256())
# nVersion
writers.write_uint32(h_preimage, self.tx.version)
# hashPrevouts
prevouts_hash = writers.get_tx_hash(
self.h_prevouts, double=self.coin.sign_hash_double
)
writers.write_bytes_fixed(h_preimage, prevouts_hash, writers.TX_HASH_SIZE)
# hashSequence
sequence_hash = writers.get_tx_hash(
self.h_sequence, double=self.coin.sign_hash_double
)
writers.write_bytes_fixed(h_preimage, sequence_hash, writers.TX_HASH_SIZE)
# outpoint
writers.write_bytes_reversed(h_preimage, txi.prev_hash, writers.TX_HASH_SIZE)
writers.write_uint32(h_preimage, txi.prev_index)
# scriptCode
script_code = scripts.bip143_derive_script_code(
txi, public_keys, threshold, self.coin
)
writers.write_bytes_prefixed(h_preimage, script_code)
# amount
writers.write_uint64(h_preimage, txi.amount)
# nSequence
writers.write_uint32(h_preimage, txi.sequence)
# hashOutputs
outputs_hash = writers.get_tx_hash(
self.h_outputs, double=self.coin.sign_hash_double
)
writers.write_bytes_fixed(h_preimage, outputs_hash, writers.TX_HASH_SIZE)
# nLockTime
writers.write_uint32(h_preimage, self.tx.lock_time)
# nHashType
writers.write_uint32(h_preimage, self.get_sighash_type(txi))
return writers.get_tx_hash(h_preimage, double=self.coin.sign_hash_double)
def input_is_segwit(txi: TxInput) -> bool: def input_is_segwit(txi: TxInput) -> bool:
return txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES or ( return txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES or (

View File

@ -49,7 +49,14 @@ class Bitcoinlike(Bitcoin):
script_pubkey: bytes, script_pubkey: bytes,
) -> bytes: ) -> bytes:
if self.coin.force_bip143: if self.coin.force_bip143:
return self.hash143_preimage_hash(txi, public_keys, threshold) return self.hash143.preimage_hash(
txi,
public_keys,
threshold,
self.tx,
self.coin,
self.get_sighash_type(txi),
)
else: else:
return await super().get_tx_digest( return await super().get_tx_digest(
i, txi, public_keys, threshold, script_pubkey i, txi, public_keys, threshold, script_pubkey

View File

@ -12,6 +12,7 @@ from .. import multisig, scripts, writers
from ..common import ecdsa_hash_pubkey, ecdsa_sign from ..common import ecdsa_hash_pubkey, ecdsa_sign
from . import approvers, helpers, progress from . import approvers, helpers, progress
from .bitcoin import Bitcoin from .bitcoin import Bitcoin
from .hash143 import Hash143
DECRED_SERIALIZE_FULL = const(0 << 16) DECRED_SERIALIZE_FULL = const(0 << 16)
DECRED_SERIALIZE_NO_WITNESS = const(1 << 16) DECRED_SERIALIZE_NO_WITNESS = const(1 << 16)
@ -33,6 +34,17 @@ if False:
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
class DecredHash(Hash143):
def __init__(self, h_prefix: HashWriter) -> None:
self.h_prefix = h_prefix
def add_input(self, txi: TxInput) -> None:
Decred.write_tx_input(self.h_prefix, txi, bytes())
def add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
Decred.write_tx_output(self.h_prefix, txo, script_pubkey)
class Decred(Bitcoin): class Decred(Bitcoin):
def __init__( def __init__(
self, self,
@ -42,21 +54,22 @@ class Decred(Bitcoin):
approver: approvers.Approver, approver: approvers.Approver,
) -> None: ) -> None:
ensure(coin.decred) ensure(coin.decred)
self.h_prefix = HashWriter(blake256())
writers.write_uint32(self.h_prefix, tx.version | DECRED_SERIALIZE_NO_WITNESS)
write_bitcoin_varint(self.h_prefix, tx.inputs_count)
super().__init__(tx, keychain, coin, approver) super().__init__(tx, keychain, coin, approver)
self.write_tx_header(self.serialized_tx, self.tx, witness_marker=True) self.write_tx_header(self.serialized_tx, self.tx, witness_marker=True)
write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count) write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count)
def init_hash143(self) -> None:
self.h_prefix = self.create_hash_writer()
writers.write_uint32(
self.h_prefix, self.tx.version | DECRED_SERIALIZE_NO_WITNESS
)
write_bitcoin_varint(self.h_prefix, self.tx.inputs_count)
def create_hash_writer(self) -> HashWriter: def create_hash_writer(self) -> HashWriter:
return HashWriter(blake256()) return HashWriter(blake256())
def create_hash143(self) -> Hash143:
return DecredHash(self.h_prefix)
async def step2_approve_outputs(self) -> None: async def step2_approve_outputs(self) -> None:
write_bitcoin_varint(self.serialized_tx, self.tx.outputs_count) write_bitcoin_varint(self.serialized_tx, self.tx.outputs_count)
write_bitcoin_varint(self.h_prefix, self.tx.outputs_count) write_bitcoin_varint(self.h_prefix, self.tx.outputs_count)
@ -148,14 +161,8 @@ class Decred(Bitcoin):
if txo_bin.decred_script_version != 0: if txo_bin.decred_script_version != 0:
raise wire.ProcessError("Cannot use utxo that has script_version != 0") raise wire.ProcessError("Cannot use utxo that has script_version != 0")
def hash143_add_input(self, txi: TxInput) -> None: @staticmethod
self.write_tx_input(self.h_prefix, txi, bytes())
def hash143_add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
self.write_tx_output(self.h_prefix, txo, script_pubkey)
def write_tx_input( def write_tx_input(
self,
w: writers.Writer, w: writers.Writer,
txi: Union[TxInput, PrevInput], txi: Union[TxInput, PrevInput],
script: bytes, script: bytes,
@ -165,8 +172,8 @@ class Decred(Bitcoin):
writers.write_uint8(w, txi.decred_tree or 0) writers.write_uint8(w, txi.decred_tree or 0)
writers.write_uint32(w, txi.sequence) writers.write_uint32(w, txi.sequence)
@staticmethod
def write_tx_output( def write_tx_output(
self,
w: writers.Writer, w: writers.Writer,
txo: Union[TxOutput, PrevOutput], txo: Union[TxOutput, PrevOutput],
script_pubkey: bytes, script_pubkey: bytes,

View File

@ -0,0 +1,85 @@
from trezor.crypto.hashlib import sha256
from trezor.messages.PrevTx import PrevTx
from trezor.messages.SignTx import SignTx
from trezor.messages.TxInput import TxInput
from trezor.messages.TxOutput import TxOutput
from trezor.utils import HashWriter
from apps.common import coininfo
from .. import scripts, writers
if False:
from typing import List, Union
# BIP-0143 hash
class Hash143:
def __init__(self) -> None:
self.h_prevouts = HashWriter(sha256())
self.h_sequence = HashWriter(sha256())
self.h_outputs = HashWriter(sha256())
def add_input(self, txi: TxInput) -> None:
writers.write_bytes_reversed(
self.h_prevouts, txi.prev_hash, writers.TX_HASH_SIZE
)
writers.write_uint32(self.h_prevouts, txi.prev_index)
writers.write_uint32(self.h_sequence, txi.sequence)
def add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
writers.write_tx_output(self.h_outputs, txo, script_pubkey)
def preimage_hash(
self,
txi: TxInput,
public_keys: List[bytes],
threshold: int,
tx: Union[SignTx, PrevTx],
coin: coininfo.CoinInfo,
sighash_type: int,
) -> bytes:
h_preimage = HashWriter(sha256())
# nVersion
writers.write_uint32(h_preimage, tx.version)
# hashPrevouts
prevouts_hash = writers.get_tx_hash(
self.h_prevouts, double=coin.sign_hash_double
)
writers.write_bytes_fixed(h_preimage, prevouts_hash, writers.TX_HASH_SIZE)
# hashSequence
sequence_hash = writers.get_tx_hash(
self.h_sequence, double=coin.sign_hash_double
)
writers.write_bytes_fixed(h_preimage, sequence_hash, writers.TX_HASH_SIZE)
# outpoint
writers.write_bytes_reversed(h_preimage, txi.prev_hash, writers.TX_HASH_SIZE)
writers.write_uint32(h_preimage, txi.prev_index)
# scriptCode
script_code = scripts.bip143_derive_script_code(
txi, public_keys, threshold, coin
)
writers.write_bytes_prefixed(h_preimage, script_code)
# amount
writers.write_uint64(h_preimage, txi.amount)
# nSequence
writers.write_uint32(h_preimage, txi.sequence)
# hashOutputs
outputs_hash = writers.get_tx_hash(self.h_outputs, double=coin.sign_hash_double)
writers.write_bytes_fixed(h_preimage, outputs_hash, writers.TX_HASH_SIZE)
# nLockTime
writers.write_uint32(h_preimage, tx.lock_time)
# nHashType
writers.write_uint32(h_preimage, sighash_type)
return writers.get_tx_hash(h_preimage, double=coin.sign_hash_double)

View File

@ -26,14 +26,80 @@ from ..writers import (
) )
from . import approvers, helpers from . import approvers, helpers
from .bitcoinlike import Bitcoinlike from .bitcoinlike import Bitcoinlike
from .hash143 import Hash143
if False: if False:
from apps.common import coininfo
from typing import List, Union from typing import List, Union
from ..writers import Writer from ..writers import Writer
OVERWINTERED = const(0x80000000) OVERWINTERED = const(0x80000000)
class Zip243Hash(Hash143):
def __init__(self) -> None:
self.h_prevouts = HashWriter(blake2b(outlen=32, personal=b"ZcashPrevoutHash"))
self.h_sequence = HashWriter(blake2b(outlen=32, personal=b"ZcashSequencHash"))
self.h_outputs = HashWriter(blake2b(outlen=32, personal=b"ZcashOutputsHash"))
def preimage_hash(
self,
txi: TxInput,
public_keys: List[bytes],
threshold: int,
tx: Union[SignTx, PrevTx],
coin: coininfo.CoinInfo,
sighash_type: int,
) -> bytes:
h_preimage = HashWriter(
blake2b(
outlen=32,
personal=b"ZcashSigHash" + struct.pack("<I", tx.branch_id),
)
)
assert tx.version_group_id is not None
assert tx.expiry is not None
zero_hash = b"\x00" * TX_HASH_SIZE
# 1. nVersion | fOverwintered
write_uint32(h_preimage, tx.version | OVERWINTERED)
# 2. nVersionGroupId
write_uint32(h_preimage, tx.version_group_id)
# 3. hashPrevouts
write_bytes_fixed(h_preimage, get_tx_hash(self.h_prevouts), TX_HASH_SIZE)
# 4. hashSequence
write_bytes_fixed(h_preimage, get_tx_hash(self.h_sequence), TX_HASH_SIZE)
# 5. hashOutputs
write_bytes_fixed(h_preimage, get_tx_hash(self.h_outputs), TX_HASH_SIZE)
# 6. hashJoinSplits
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE)
# 7. hashShieldedSpends
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE)
# 8. hashShieldedOutputs
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE)
# 9. nLockTime
write_uint32(h_preimage, tx.lock_time)
# 10. expiryHeight
write_uint32(h_preimage, tx.expiry)
# 11. valueBalance
write_uint64(h_preimage, 0)
# 12. nHashType
write_uint32(h_preimage, sighash_type)
# 13a. outpoint
write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE)
write_uint32(h_preimage, txi.prev_index)
# 13b. scriptCode
script_code = derive_script_code(txi, public_keys, threshold, coin)
write_bytes_prefixed(h_preimage, script_code)
# 13c. value
write_uint64(h_preimage, txi.amount)
# 13d. nSequence
write_uint32(h_preimage, txi.sequence)
return get_tx_hash(h_preimage)
class Zcashlike(Bitcoinlike): class Zcashlike(Bitcoinlike):
def __init__( def __init__(
self, self,
@ -48,6 +114,9 @@ class Zcashlike(Bitcoinlike):
if self.tx.version != 4: if self.tx.version != 4:
raise wire.DataError("Unsupported transaction version.") raise wire.DataError("Unsupported transaction version.")
def create_hash143(self) -> Hash143:
return Zip243Hash()
async def step7_finish(self) -> None: async def step7_finish(self) -> None:
self.write_tx_footer(self.serialized_tx, self.tx) self.write_tx_footer(self.serialized_tx, self.tx)
@ -69,7 +138,9 @@ class Zcashlike(Bitcoinlike):
threshold: int, threshold: int,
script_pubkey: bytes, script_pubkey: bytes,
) -> bytes: ) -> bytes:
return self.hash143_preimage_hash(txi, public_keys, threshold) return self.hash143.preimage_hash(
txi, public_keys, threshold, self.tx, self.coin, self.get_sighash_type(txi)
)
def write_tx_header( def write_tx_header(
self, w: Writer, tx: Union[SignTx, PrevTx], witness_marker: bool self, w: Writer, tx: Union[SignTx, PrevTx], witness_marker: bool
@ -90,70 +161,9 @@ class Zcashlike(Bitcoinlike):
if tx.version >= 3: if tx.version >= 3:
write_uint32(w, tx.expiry) # expiryHeight write_uint32(w, tx.expiry) # expiryHeight
# ZIP-0143 / ZIP-0243
# ===
def init_hash143(self) -> None:
self.h_prevouts = HashWriter(blake2b(outlen=32, personal=b"ZcashPrevoutHash"))
self.h_sequence = HashWriter(blake2b(outlen=32, personal=b"ZcashSequencHash"))
self.h_outputs = HashWriter(blake2b(outlen=32, personal=b"ZcashOutputsHash"))
def hash143_preimage_hash(
self, txi: TxInput, public_keys: List[bytes], threshold: int
) -> bytes:
h_preimage = HashWriter(
blake2b(
outlen=32,
personal=b"ZcashSigHash" + struct.pack("<I", self.tx.branch_id),
)
)
assert self.tx.version_group_id is not None assert self.tx.version_group_id is not None
assert self.tx.expiry is not None assert self.tx.expiry is not None
# 1. nVersion | fOverwintered
write_uint32(h_preimage, self.tx.version | OVERWINTERED)
# 2. nVersionGroupId
write_uint32(h_preimage, self.tx.version_group_id)
# 3. hashPrevouts
write_bytes_fixed(h_preimage, get_tx_hash(self.h_prevouts), TX_HASH_SIZE)
# 4. hashSequence
write_bytes_fixed(h_preimage, get_tx_hash(self.h_sequence), TX_HASH_SIZE)
# 5. hashOutputs
write_bytes_fixed(h_preimage, get_tx_hash(self.h_outputs), TX_HASH_SIZE)
zero_hash = b"\x00" * TX_HASH_SIZE
# 6. hashJoinSplits
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE)
# 7. hashShieldedSpends
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE)
# 8. hashShieldedOutputs
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE)
# 9. nLockTime
write_uint32(h_preimage, self.tx.lock_time)
# 10. expiryHeight
write_uint32(h_preimage, self.tx.expiry)
# 11. valueBalance
write_uint64(h_preimage, 0)
# 12. nHashType
write_uint32(h_preimage, self.get_sighash_type(txi))
# 10a /13a. outpoint
write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE)
write_uint32(h_preimage, txi.prev_index)
# 10b / 13b. scriptCode
script_code = derive_script_code(txi, public_keys, threshold, self.coin)
write_bytes_prefixed(h_preimage, script_code)
# 10c / 13c. value
write_uint64(h_preimage, txi.amount)
# 10d / 13d. nSequence
write_uint32(h_preimage, txi.sequence)
return get_tx_hash(h_preimage)
def derive_script_code( def derive_script_code(
txi: TxInput, public_keys: List[bytes], threshold: int, coin: CoinInfo txi: TxInput, public_keys: List[bytes], threshold: int, coin: CoinInfo

View File

@ -1,8 +1,8 @@
from common import * from common import *
from apps.bitcoin.common import SIGHASH_ALL
from apps.bitcoin.scripts import output_derive_script from apps.bitcoin.scripts import output_derive_script
from apps.bitcoin.sign_tx.approvers import BasicApprover from apps.bitcoin.sign_tx.bitcoin import Hash143
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.keychain import Keychain from apps.common.keychain import Keychain
@ -48,17 +48,17 @@ class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
def test_prevouts(self): def test_prevouts(self):
coin = coins.by_name(self.tx.coin_name) coin = coins.by_name(self.tx.coin_name)
bip143 = Bitcoin(self.tx, None, coin, BasicApprover(self.tx, coin)) bip143 = Hash143()
bip143.hash143_add_input(self.inp1) bip143.add_input(self.inp1)
bip143.hash143_add_input(self.inp2) bip143.add_input(self.inp2)
prevouts_hash = get_tx_hash(bip143.h_prevouts, double=coin.sign_hash_double) prevouts_hash = get_tx_hash(bip143.h_prevouts, double=coin.sign_hash_double)
self.assertEqual(hexlify(prevouts_hash), b'96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37') self.assertEqual(hexlify(prevouts_hash), b'96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37')
def test_sequence(self): def test_sequence(self):
coin = coins.by_name(self.tx.coin_name) coin = coins.by_name(self.tx.coin_name)
bip143 = Bitcoin(self.tx, None, coin, BasicApprover(self.tx, coin)) bip143 = Hash143()
bip143.hash143_add_input(self.inp1) bip143.add_input(self.inp1)
bip143.hash143_add_input(self.inp2) bip143.add_input(self.inp2)
sequence_hash = get_tx_hash(bip143.h_sequence, double=coin.sign_hash_double) sequence_hash = get_tx_hash(bip143.h_sequence, double=coin.sign_hash_double)
self.assertEqual(hexlify(sequence_hash), b'52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b') self.assertEqual(hexlify(sequence_hash), b'52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b')
@ -66,12 +66,12 @@ class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '') seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
coin = coins.by_name(self.tx.coin_name) coin = coins.by_name(self.tx.coin_name)
bip143 = Bitcoin(self.tx, None, coin, BasicApprover(self.tx, coin)) bip143 = Hash143()
for txo in [self.out1, self.out2]: for txo in [self.out1, self.out2]:
script_pubkey = output_derive_script(txo.address, coin) script_pubkey = output_derive_script(txo.address, coin)
txo_bin = PrevOutput(amount=txo.amount, script_pubkey=script_pubkey) txo_bin = PrevOutput(amount=txo.amount, script_pubkey=script_pubkey)
bip143.hash143_add_output(txo_bin, script_pubkey) bip143.add_output(txo_bin, script_pubkey)
outputs_hash = get_tx_hash(bip143.h_outputs, double=coin.sign_hash_double) outputs_hash = get_tx_hash(bip143.h_outputs, double=coin.sign_hash_double)
self.assertEqual(hexlify(outputs_hash), b'863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5') self.assertEqual(hexlify(outputs_hash), b'863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5')
@ -80,21 +80,21 @@ class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '') seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
coin = coins.by_name(self.tx.coin_name) coin = coins.by_name(self.tx.coin_name)
bip143 = Bitcoin(self.tx, None, coin, BasicApprover(self.tx, coin)) bip143 = Hash143()
bip143.hash143_add_input(self.inp1) bip143.add_input(self.inp1)
bip143.hash143_add_input(self.inp2) bip143.add_input(self.inp2)
for txo in [self.out1, self.out2]: for txo in [self.out1, self.out2]:
script_pubkey = output_derive_script(txo.address, coin) script_pubkey = output_derive_script(txo.address, coin)
txo_bin = PrevOutput(amount=txo.amount, script_pubkey=script_pubkey) txo_bin = PrevOutput(amount=txo.amount, script_pubkey=script_pubkey)
bip143.hash143_add_output(txo_bin, script_pubkey) bip143.add_output(txo_bin, script_pubkey)
keychain = Keychain(seed, coin.curve_name, [[]]) keychain = Keychain(seed, coin.curve_name, [[]])
node = keychain.derive(self.inp2.address_n) 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, [node.public_key()], 1) result = bip143.preimage_hash(self.inp2, [node.public_key()], 1, self.tx, coin, SIGHASH_ALL)
self.assertEqual(hexlify(result), b'2fa3f1351618b2532228d7182d3221d95c21fd3d496e7e22e9ded873cf022a8b') self.assertEqual(hexlify(result), b'2fa3f1351618b2532228d7182d3221d95c21fd3d496e7e22e9ded873cf022a8b')

View File

@ -1,8 +1,8 @@
from common import * from common import *
from apps.bitcoin.common import SIGHASH_ALL
from apps.bitcoin.scripts import output_derive_script from apps.bitcoin.scripts import output_derive_script
from apps.bitcoin.sign_tx.approvers import BasicApprover from apps.bitcoin.sign_tx.bitcoin import Hash143
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.keychain import Keychain from apps.common.keychain import Keychain
@ -40,27 +40,27 @@ class TestSegwitBip143(unittest.TestCase):
def test_bip143_prevouts(self): def test_bip143_prevouts(self):
coin = coins.by_name(self.tx.coin_name) coin = coins.by_name(self.tx.coin_name)
bip143 = Bitcoin(self.tx, None, coin, BasicApprover(self.tx, coin)) bip143 = Hash143()
bip143.hash143_add_input(self.inp1) bip143.add_input(self.inp1)
prevouts_hash = get_tx_hash(bip143.h_prevouts, double=coin.sign_hash_double) prevouts_hash = get_tx_hash(bip143.h_prevouts, double=coin.sign_hash_double)
self.assertEqual(hexlify(prevouts_hash), b'b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a') self.assertEqual(hexlify(prevouts_hash), b'b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a')
def test_bip143_sequence(self): def test_bip143_sequence(self):
coin = coins.by_name(self.tx.coin_name) coin = coins.by_name(self.tx.coin_name)
bip143 = Bitcoin(self.tx, None, coin, BasicApprover(self.tx, coin)) bip143 = Hash143()
bip143.hash143_add_input(self.inp1) bip143.add_input(self.inp1)
sequence_hash = get_tx_hash(bip143.h_sequence, double=coin.sign_hash_double) sequence_hash = get_tx_hash(bip143.h_sequence, double=coin.sign_hash_double)
self.assertEqual(hexlify(sequence_hash), b'18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198') self.assertEqual(hexlify(sequence_hash), b'18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198')
def test_bip143_outputs(self): def test_bip143_outputs(self):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '') seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
coin = coins.by_name(self.tx.coin_name) coin = coins.by_name(self.tx.coin_name)
bip143 = Bitcoin(self.tx, None, coin, BasicApprover(self.tx, coin)) bip143 = Hash143()
for txo in [self.out1, self.out2]: for txo in [self.out1, self.out2]:
script_pubkey = output_derive_script(txo.address, coin) script_pubkey = output_derive_script(txo.address, coin)
txo_bin = PrevOutput(amount=txo.amount, script_pubkey=script_pubkey) txo_bin = PrevOutput(amount=txo.amount, script_pubkey=script_pubkey)
bip143.hash143_add_output(txo_bin, script_pubkey) bip143.add_output(txo_bin, script_pubkey)
outputs_hash = get_tx_hash(bip143.h_outputs, double=coin.sign_hash_double) outputs_hash = get_tx_hash(bip143.h_outputs, double=coin.sign_hash_double)
self.assertEqual(hexlify(outputs_hash), b'de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83') self.assertEqual(hexlify(outputs_hash), b'de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83')
@ -68,18 +68,18 @@ class TestSegwitBip143(unittest.TestCase):
def test_bip143_preimage_testdata(self): def test_bip143_preimage_testdata(self):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '') seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
coin = coins.by_name(self.tx.coin_name) coin = coins.by_name(self.tx.coin_name)
bip143 = Bitcoin(self.tx, None, coin, BasicApprover(self.tx, coin)) bip143 = Hash143()
bip143.hash143_add_input(self.inp1) bip143.add_input(self.inp1)
for txo in [self.out1, self.out2]: for txo in [self.out1, self.out2]:
script_pubkey = output_derive_script(txo.address, coin) script_pubkey = output_derive_script(txo.address, coin)
txo_bin = PrevOutput(amount=txo.amount, script_pubkey=script_pubkey) txo_bin = PrevOutput(amount=txo.amount, script_pubkey=script_pubkey)
bip143.hash143_add_output(txo_bin, script_pubkey) bip143.add_output(txo_bin, script_pubkey)
keychain = Keychain(seed, coin.curve_name, [[]]) keychain = Keychain(seed, coin.curve_name, [[]])
node = keychain.derive(self.inp1.address_n) node = keychain.derive(self.inp1.address_n)
# test data public key hash # test data public key hash
result = bip143.hash143_preimage_hash(self.inp1, [node.public_key()], 1) result = bip143.preimage_hash(self.inp1, [node.public_key()], 1, self.tx, coin, SIGHASH_ALL)
self.assertEqual(hexlify(result), b'6e28aca7041720995d4acf59bbda64eef5d6f23723d23f2e994757546674bbd9') self.assertEqual(hexlify(result), b'6e28aca7041720995d4acf59bbda64eef5d6f23723d23f2e994757546674bbd9')

View File

@ -5,11 +5,11 @@ from trezor.messages.TxInput import TxInput
from trezor.messages.PrevOutput import PrevOutput from trezor.messages.PrevOutput import PrevOutput
from apps.common import coins from apps.common import coins
from apps.bitcoin.common import SIGHASH_ALL
from apps.bitcoin.writers import get_tx_hash from apps.bitcoin.writers import get_tx_hash
from apps.bitcoin.sign_tx.approvers import BasicApprover
if not utils.BITCOIN_ONLY: if not utils.BITCOIN_ONLY:
from apps.bitcoin.sign_tx.zcash import Zcashlike from apps.bitcoin.sign_tx.zcash import Zip243Hash
# test vectors inspired from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0243.py # test vectors inspired from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0243.py
@ -191,7 +191,7 @@ class TestZcashZip243(unittest.TestCase):
branch_id=v["branch_id"], branch_id=v["branch_id"],
) )
zip243 = Zcashlike(tx, None, coin, BasicApprover(tx, coin)) zip243 = Zip243Hash()
for i in v["inputs"]: for i in v["inputs"]:
txi = TxInput( txi = TxInput(
@ -201,18 +201,19 @@ class TestZcashZip243(unittest.TestCase):
script_type = i["script_type"], script_type = i["script_type"],
sequence = i["sequence"], sequence = i["sequence"],
) )
zip243.hash143_add_input(txi) zip243.add_input(txi)
for o in v["outputs"]: for o in v["outputs"]:
txo = PrevOutput( txo = PrevOutput(
amount = o["amount"], amount = o["amount"],
script_pubkey = unhexlify(o["script_pubkey"]), script_pubkey = unhexlify(o["script_pubkey"]),
) )
zip243.hash143_add_output(txo, txo.script_pubkey) zip243.add_output(txo, txo.script_pubkey)
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["pubkey"])], 1)), v["preimage_hash"]) self.assertEqual(hexlify(zip243.preimage_hash(txi, [unhexlify(i["pubkey"])], 1, tx, coin, SIGHASH_ALL)), v["preimage_hash"])
if __name__ == "__main__": if __name__ == "__main__":