From d48a372ca75d04d209c4d8811d66d61b139f0139 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sat, 20 Jun 2020 17:28:21 +0200 Subject: [PATCH] core/sign_tx: Implement support for signed external inputs. --- core/src/apps/bitcoin/scripts.py | 14 +- core/src/apps/bitcoin/sign_tx/bitcoin.py | 168 ++++++++++++++---- core/src/apps/bitcoin/sign_tx/bitcoinlike.py | 18 +- core/src/apps/bitcoin/sign_tx/decred.py | 15 +- core/src/apps/bitcoin/sign_tx/helpers.py | 2 +- core/src/apps/bitcoin/sign_tx/progress.py | 4 +- core/src/apps/bitcoin/sign_tx/zcash.py | 37 ++-- ...pps.bitcoin.segwit.bip143.native_p2wpkh.py | 8 +- ...ps.bitcoin.segwit.bip143.p2wpkh_in_p2sh.py | 8 +- core/tests/test_apps.bitcoin.zcash.zip143.py | 22 +-- core/tests/test_apps.bitcoin.zcash.zip243.py | 26 +-- 11 files changed, 233 insertions(+), 89 deletions(-) diff --git a/core/src/apps/bitcoin/scripts.py b/core/src/apps/bitcoin/scripts.py index d16c60f662..498afcc0bd 100644 --- a/core/src/apps/bitcoin/scripts.py +++ b/core/src/apps/bitcoin/scripts.py @@ -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 # item 5 for details -def bip143_derive_script_code(txi: TxInputType, pubkeyhash: bytes) -> bytearray: - - if txi.multisig: - return output_script_multisig( - multisig_get_pubkeys(txi.multisig), txi.multisig.m - ) +def bip143_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) p2pkh = ( txi.script_type == InputScriptType.SPENDWITNESS or txi.script_type == InputScriptType.SPENDP2SHWITNESS or txi.script_type == InputScriptType.SPENDADDRESS + or txi.script_type == InputScriptType.EXTERNAL ) if p2pkh: # for p2wpkh in p2sh or native p2wpkh # the scriptCode is a classic p2pkh - return output_script_p2pkh(pubkeyhash) + return output_script_p2pkh(common.ecdsa_hash_pubkey(public_keys[0], coin)) else: raise wire.DataError("Unknown input script type for bip143 script code") diff --git a/core/src/apps/bitcoin/sign_tx/bitcoin.py b/core/src/apps/bitcoin/sign_tx/bitcoin.py index 98a7edd162..3a8a487cb7 100644 --- a/core/src/apps/bitcoin/sign_tx/bitcoin.py +++ b/core/src/apps/bitcoin/sign_tx/bitcoin.py @@ -3,7 +3,7 @@ from micropython import const from trezor import wire 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.TransactionType import TransactionType 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 .. 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 .matchcheck import MultisigFingerprintChecker, WalletPathChecker if False: - from typing import Set, Optional, Tuple, Union + from typing import List, Optional, Set, Tuple, Union from trezor.crypto.bip32 import HDNode # 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: 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 # by requesting each previous transaction and checking its output amounts. await self.step1_process_inputs() @@ -55,17 +54,20 @@ class Bitcoin: # Check fee, confirm lock_time and total. 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. - await self.step4_serialize_inputs() + await self.step5_serialize_inputs() # Serialize outputs. - await self.step5_serialize_outputs() + await self.step6_serialize_outputs() # 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. - await self.step7_finish() + await self.step8_finish() def __init__( self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo @@ -83,8 +85,12 @@ class Bitcoin: # set of indices of inputs which are segwit self.segwit = set() # type: Set[int] + # set of indices of inputs which are external + self.external = set() # type: Set[int] + # 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.change_out = 0 # change output amount 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 # 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 + # 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 self.init_hash143() + progress.init(self.tx.inputs_count, self.tx.outputs_count) + def create_hash_writer(self) -> HashWriter: return HashWriter(sha256()) async def step1_process_inputs(self) -> None: for i in range(self.tx.inputs_count): # STAGE_REQUEST_1_INPUT in legacy - progress.advance() txi = await helpers.request_tx_input(self.tx_req, i, self.coin) self.weight.add_input(txi) if input_is_segwit(txi): 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: for i in range(self.tx.outputs_count): @@ -136,40 +154,80 @@ class Bitcoin: await helpers.confirm_feeoverthreshold(fee, self.coin) if self.tx.lock_time > 0: 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)) write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count) for i in range(self.tx.inputs_count): 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) else: 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) for i in range(self.tx.outputs_count): progress.advance() await self.serialize_output(i) - async def step6_sign_segwit_inputs(self) -> None: - any_segwit = bool(self.segwit) + async def step7_sign_segwit_inputs(self) -> None: + if not self.segwit: + progress.advance(self.tx.inputs_count) + return + for i in range(self.tx.inputs_count): progress.advance() if i in self.segwit: - await self.sign_segwit_input(i) - elif any_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) + else: # add empty witness for non-segwit inputs 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) 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.multisig_fingerprint.add_input(txi) writers.write_tx_input_check(self.h_confirmed, txi) @@ -190,6 +248,16 @@ class Bitcoin: 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: if self.change_out == 0 and self.output_is_change(txo): # output is change and does not need confirmation @@ -201,9 +269,30 @@ class Bitcoin: self.hash143_add_output(txo, script_pubkey) 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: 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: # STAGE_REQUEST_SEGWIT_INPUT in legacy 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) 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) @@ -313,7 +407,7 @@ class Bitcoin: writers.write_uint32(h_sign, self.tx.lock_time) 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(): 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_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) - 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()) # nVersion @@ -532,7 +628,9 @@ class Bitcoin: writers.write_uint32(h_preimage, txi.prev_index) # 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) # amount @@ -557,8 +655,16 @@ class Bitcoin: 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: - 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 diff --git a/core/src/apps/bitcoin/sign_tx/bitcoinlike.py b/core/src/apps/bitcoin/sign_tx/bitcoinlike.py index 770583beee..233aced72d 100644 --- a/core/src/apps/bitcoin/sign_tx/bitcoinlike.py +++ b/core/src/apps/bitcoin/sign_tx/bitcoinlike.py @@ -4,6 +4,7 @@ from micropython import const from trezor import wire from trezor.messages.SignTx import SignTx from trezor.messages.TransactionType import TransactionType +from trezor.messages.TxInputType import TxInputType from apps.common.writers import write_bitcoin_varint @@ -12,7 +13,7 @@ from . import helpers from .bitcoin import Bitcoin, input_is_nonsegwit if False: - from typing import Union + from typing import List, Union _SIGHASH_FORKID = const(0x40) @@ -41,6 +42,21 @@ class Bitcoinlike(Bitcoin): else: 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: # some coins require negative fees for reward TX if not self.coin.negative_fee: diff --git a/core/src/apps/bitcoin/sign_tx/decred.py b/core/src/apps/bitcoin/sign_tx/decred.py index af2f02f209..d34325e00c 100644 --- a/core/src/apps/bitcoin/sign_tx/decred.py +++ b/core/src/apps/bitcoin/sign_tx/decred.py @@ -57,17 +57,20 @@ class Decred(Bitcoin): self.write_tx_footer(self.serialized_tx, self.tx) self.write_tx_footer(self.h_prefix, self.tx) - async def process_input(self, txi: TxInputType) -> None: - await super().process_input(txi) + async def process_internal_input(self, txi: TxInputType) -> None: + await super().process_internal_input(txi) # Decred serializes inputs early. 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: await super().confirm_output(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) 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.set_serialized_signature(i_sign, signature) - async def step5_serialize_outputs(self) -> None: + async def step6_serialize_outputs(self) -> None: pass - async def step6_sign_segwit_inputs(self) -> None: + async def step7_sign_segwit_inputs(self) -> None: pass - async def step7_finish(self) -> None: + async def step8_finish(self) -> None: await helpers.request_tx_finish(self.tx_req) def check_prevtx_output(self, txo_bin: TxOutputBinType) -> None: diff --git a/core/src/apps/bitcoin/sign_tx/helpers.py b/core/src/apps/bitcoin/sign_tx/helpers.py index 799c27a876..6258c133b6 100644 --- a/core/src/apps/bitcoin/sign_tx/helpers.py +++ b/core/src/apps/bitcoin/sign_tx/helpers.py @@ -220,7 +220,7 @@ def sanitize_tx_input(tx: TransactionType, coin: CoinInfo) -> TxInputType: raise wire.DataError("Input's address_n provided but not expected.") if not coin.decred and txi.decred_tree is not None: 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: raise wire.DataError("Segwit not enabled on this coin") return txi diff --git a/core/src/apps/bitcoin/sign_tx/progress.py b/core/src/apps/bitcoin/sign_tx/progress.py index 0971c6ddf6..1cd8003a92 100644 --- a/core/src/apps/bitcoin/sign_tx/progress.py +++ b/core/src/apps/bitcoin/sign_tx/progress.py @@ -12,9 +12,9 @@ def init(inputs: int, outputs: int) -> None: report() -def advance() -> None: +def advance(i: int = 1) -> None: global _progress - _progress += 1 + _progress += i report() diff --git a/core/src/apps/bitcoin/sign_tx/zcash.py b/core/src/apps/bitcoin/sign_tx/zcash.py index bf66350dd5..59ecc1380e 100644 --- a/core/src/apps/bitcoin/sign_tx/zcash.py +++ b/core/src/apps/bitcoin/sign_tx/zcash.py @@ -13,7 +13,7 @@ from apps.common.coininfo import CoinInfo from apps.common.seed import Keychain 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 ..writers import ( TX_HASH_SIZE, @@ -28,7 +28,7 @@ from . import helpers from .bitcoinlike import Bitcoinlike if False: - from typing import Union + from typing import List, Union from ..writers import Writer OVERWINTERED = const(0x80000000) @@ -48,7 +48,7 @@ class Overwintered(Bitcoinlike): else: 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) if self.tx.version == 3: @@ -66,6 +66,16 @@ class Overwintered(Bitcoinlike): async def sign_nonsegwit_input(self, i_sign: int) -> None: 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( self, w: Writer, tx: Union[SignTx, TransactionType], witness_marker: bool ) -> None: @@ -90,7 +100,9 @@ class Overwintered(Bitcoinlike): 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: TxInputType, pubkeyhash: bytes) -> bytes: + def hash143_preimage_hash( + self, txi: TxInputType, public_keys: List[bytes], threshold: int + ) -> bytes: h_preimage = HashWriter( blake2b( outlen=32, @@ -142,7 +154,7 @@ class Overwintered(Bitcoinlike): write_uint32(h_preimage, txi.prev_index) # 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) # 10c / 13c. value @@ -154,16 +166,15 @@ class Overwintered(Bitcoinlike): 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: - return output_script_multisig( - multisig_get_pubkeys(txi.multisig), txi.multisig.m - ) - - p2pkh = txi.script_type == InputScriptType.SPENDADDRESS + p2pkh = txi.script_type in (InputScriptType.SPENDADDRESS, InputScriptType.EXTERNAL) if p2pkh: - return output_script_p2pkh(pubkeyhash) + return output_script_p2pkh(ecdsa_hash_pubkey(public_keys[0], coin)) else: raise wire.DataError("Unknown input script type for zip143 script code") diff --git a/core/tests/test_apps.bitcoin.segwit.bip143.native_p2wpkh.py b/core/tests/test_apps.bitcoin.segwit.bip143.native_p2wpkh.py index 1a53e42a0e..75f0d333d8 100644 --- a/core/tests/test_apps.bitcoin.segwit.bip143.native_p2wpkh.py +++ b/core/tests/test_apps.bitcoin.segwit.bip143.native_p2wpkh.py @@ -4,6 +4,7 @@ from apps.bitcoin.scripts import output_derive_script from apps.bitcoin.sign_tx.bitcoin import Bitcoin from apps.bitcoin.writers import get_tx_hash from apps.common import coins +from apps.common.seed import Keychain from trezor.messages.SignTx import SignTx from trezor.messages.TxInputType import TxInputType from trezor.messages.TxOutputType import TxOutputType @@ -89,10 +90,13 @@ class TestSegwitBip143NativeP2WPKH(unittest.TestCase): script_pubkey = output_derive_script(txo.address, coin) 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 # only for input 2 - input 1 is not segwit - result = bip143.hash143_preimage_hash(self.inp2, unhexlify('1d0f172a0ecb48aee1be1f2687d2963ae33f71a1')) - self.assertEqual(hexlify(result), b'c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670') + result = bip143.hash143_preimage_hash(self.inp2, [node.public_key()], 1) + self.assertEqual(hexlify(result), b'2fa3f1351618b2532228d7182d3221d95c21fd3d496e7e22e9ded873cf022a8b') if __name__ == '__main__': diff --git a/core/tests/test_apps.bitcoin.segwit.bip143.p2wpkh_in_p2sh.py b/core/tests/test_apps.bitcoin.segwit.bip143.p2wpkh_in_p2sh.py index ca88a09611..7f8b6f0d68 100644 --- a/core/tests/test_apps.bitcoin.segwit.bip143.p2wpkh_in_p2sh.py +++ b/core/tests/test_apps.bitcoin.segwit.bip143.p2wpkh_in_p2sh.py @@ -4,6 +4,7 @@ from apps.bitcoin.scripts import output_derive_script from apps.bitcoin.sign_tx.bitcoin import Bitcoin from apps.bitcoin.writers import get_tx_hash from apps.common import coins +from apps.common.seed import Keychain from trezor.messages.SignTx import SignTx from trezor.messages.TxInputType import TxInputType from trezor.messages.TxOutputType import TxOutputType @@ -75,9 +76,12 @@ class TestSegwitBip143(unittest.TestCase): script_pubkey = output_derive_script(txo.address, coin) 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 - result = bip143.hash143_preimage_hash(self.inp1, unhexlify('79091972186c449eb1ded22b78e40d009bdf0089')) - self.assertEqual(hexlify(result), b'64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6') + result = bip143.hash143_preimage_hash(self.inp1, [node.public_key()], 1) + self.assertEqual(hexlify(result), b'6e28aca7041720995d4acf59bbda64eef5d6f23723d23f2e994757546674bbd9') if __name__ == '__main__': diff --git a/core/tests/test_apps.bitcoin.zcash.zip143.py b/core/tests/test_apps.bitcoin.zcash.zip143.py index 31612cf0ef..856ec27daf 100644 --- a/core/tests/test_apps.bitcoin.zcash.zip143.py +++ b/core/tests/test_apps.bitcoin.zcash.zip143.py @@ -25,7 +25,7 @@ class TestZcashZip143(unittest.TestCase): "702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76", 4025613248, ], - "pubkeyhash": "4d9cafb657677f2321fc538e367767dbdf551539", + "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c", "script_type": InputScriptType.SPENDADDRESS, "sequence": 1999822371, } @@ -40,7 +40,7 @@ class TestZcashZip143(unittest.TestCase): "prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688", "sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a", "outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992", - "preimage_hash": b"287146efaa30b3c1c7bd1a72308c46205712e6944780fdc5a7f91f477fddd55b", + "preimage_hash": b"fed855ea5fcec81928fa35d39b8582c6e026a0bf52cebeed4445a7fc7d730280", }, { "expiry": 231041495, @@ -51,7 +51,7 @@ class TestZcashZip143(unittest.TestCase): "76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2", 1547817817, ], - "pubkeyhash": "9f5d230603ce57a0e8b31a8c9b6c983ad5b00cd5", + "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c", "script_type": InputScriptType.SPENDADDRESS, "sequence": 3973122135, }, @@ -61,7 +61,7 @@ class TestZcashZip143(unittest.TestCase): "cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483", 3053054889, ], - "pubkeyhash": "b5e71ef1df5ed3a2589607ca58ed19634f07fb4f", + "pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d", "script_type": InputScriptType.SPENDADDRESS, "sequence": 3932380530, }, @@ -77,7 +77,7 @@ class TestZcashZip143(unittest.TestCase): "prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b", "sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e", "outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1", - "preimage_hash": b"b71358954aca8ffe1d3f1b5707ed6c082ed2b35e35e293b897bfc12ae7c85396", + "preimage_hash": b"1c6f563d2f16002f4c59bec5e7d56ed298315630c1d7e9a431b89e6f81026a02", }, { "expiry": 186996458, @@ -89,7 +89,7 @@ class TestZcashZip143(unittest.TestCase): 1290359941, ], "script_type": InputScriptType.SPENDADDRESS, - "pubkeyhash": "0873d1baed6c8696e4bd2b26755692b4d8050086", + "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c", "sequence": 1230917966, } ], @@ -101,7 +101,7 @@ class TestZcashZip143(unittest.TestCase): "prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd", "sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc", "outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824", - "preimage_hash": b"19ea4ce2467cb5cdcc4562ce81b22006f1fb55189ea93ccc7a3bc78ff5d97a93", + "preimage_hash": b"7159247daa16cc7e683f03ebf968314ce03324028ac138468a7b76c77e551fe8", }, { "expiry": 254788522, @@ -113,7 +113,7 @@ class TestZcashZip143(unittest.TestCase): 1517971891, ], "script_type": InputScriptType.SPENDADDRESS, - "pubkeyhash": "80b6c35a9b2efd77dbfd5d5d3bb1fd03ff40f182", + "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c", "sequence": 3833577708, }, { @@ -123,7 +123,7 @@ class TestZcashZip143(unittest.TestCase): 687648622, ], "script_type": InputScriptType.SPENDADDRESS, - "pubkeyhash": "fb8c27a442afe0f0b39a3875823c4893fe8f8550", + "pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d", "sequence": 4190617831, }, ], @@ -137,7 +137,7 @@ class TestZcashZip143(unittest.TestCase): "prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898", "sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23", "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_outputs)), v["outputs_hash"]) self.assertEqual( - hexlify(zip143.hash143_preimage_hash(txi, unhexlify(i["pubkeyhash"]))), + hexlify(zip143.hash143_preimage_hash(txi, [unhexlify(i["pubkey"])], 1)), v["preimage_hash"], ) diff --git a/core/tests/test_apps.bitcoin.zcash.zip243.py b/core/tests/test_apps.bitcoin.zcash.zip243.py index 9cd2bf30db..4e6a7d964d 100644 --- a/core/tests/test_apps.bitcoin.zcash.zip243.py +++ b/core/tests/test_apps.bitcoin.zcash.zip243.py @@ -25,7 +25,7 @@ class TestZcashZip243(unittest.TestCase): "702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76", 4025613248, ], - "pubkeyhash": "4d9cafb657677f2321fc538e367767dbdf551539", + "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c", "script_type": InputScriptType.SPENDADDRESS, "sequence": 1999822371, } @@ -40,7 +40,7 @@ class TestZcashZip243(unittest.TestCase): "prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688", "sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a", "outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992", - "preimage_hash": b"53a12bca557c27defa366c2b4c0e46ede01f81ef3dd3aa3750db62a5505c1d06", + "preimage_hash": b"f8772c6ecf9d903698fb8c51cd7b99605af298478989945936935da65e064695", }, { "expiry": 231041495, @@ -51,7 +51,7 @@ class TestZcashZip243(unittest.TestCase): "76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2", 1547817817, ], - "pubkeyhash": "9f5d230603ce57a0e8b31a8c9b6c983ad5b00cd5", + "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c", "script_type": InputScriptType.SPENDADDRESS, "sequence": 3973122135, }, @@ -61,7 +61,7 @@ class TestZcashZip243(unittest.TestCase): "cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483", 3053054889, ], - "pubkeyhash": "b5e71ef1df5ed3a2589607ca58ed19634f07fb4f", + "pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d", "script_type": InputScriptType.SPENDADDRESS, "sequence": 3932380530, }, @@ -77,7 +77,7 @@ class TestZcashZip243(unittest.TestCase): "prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b", "sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e", "outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1", - "preimage_hash": b"d1bc60986cc5c4d57f91002e48459a50f72bdb96b8f5889cf8f467a7d968b97c", + "preimage_hash": b"0eb47dc51d89cc52378fc182242f78ebd3609544a365d2270c23b4052f301025", }, { "expiry": 186996458, @@ -89,7 +89,7 @@ class TestZcashZip243(unittest.TestCase): 1290359941, ], "script_type": InputScriptType.SPENDADDRESS, - "pubkeyhash": "0873d1baed6c8696e4bd2b26755692b4d8050086", + "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c", "sequence": 1230917966, } ], @@ -101,7 +101,7 @@ class TestZcashZip243(unittest.TestCase): "prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd", "sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc", "outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824", - "preimage_hash": b"7536cdb202a30bf09c45e1a2f775c4efd41b9e67557b62abe12b64d367a2316e", + "preimage_hash": b"7f6b5439a64b20faf6f9f9460bc75c333c4799e9b04c80c26a79b8e801b8b6e1", }, { "expiry": 254788522, @@ -113,7 +113,7 @@ class TestZcashZip243(unittest.TestCase): 1517971891, ], "script_type": InputScriptType.SPENDADDRESS, - "pubkeyhash": "80b6c35a9b2efd77dbfd5d5d3bb1fd03ff40f182", + "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c", "sequence": 3833577708, }, { @@ -123,7 +123,7 @@ class TestZcashZip243(unittest.TestCase): 687648622, ], "script_type": InputScriptType.SPENDADDRESS, - "pubkeyhash": "fb8c27a442afe0f0b39a3875823c4893fe8f8550", + "pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d", "sequence": 4190617831, }, ], @@ -137,7 +137,7 @@ class TestZcashZip243(unittest.TestCase): "prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898", "sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23", "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 { @@ -150,7 +150,7 @@ class TestZcashZip243(unittest.TestCase): 1, ], "script_type": InputScriptType.SPENDADDRESS, - "pubkeyhash": "507173527b4c3318a2aecd793bf1cfed705950cf", + "pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c", "sequence": 0xfffffffe, } ], @@ -171,7 +171,7 @@ class TestZcashZip243(unittest.TestCase): "prevouts_hash": b"fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f11", "sequence_hash": b"6c80d37f12d89b6f17ff198723e7db1247c4811d1a695d74d930f99e98418790", "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_sequence)), v["sequence_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__":