From 95fad8302410bf57de688dbf67a316834068a9c7 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Wed, 8 Apr 2020 21:59:18 +0200 Subject: [PATCH] core/sign_tx: Derive Zip143 and DecredPrefixHasher from Bip143. --- core/src/apps/wallet/sign_tx/decred.py | 7 +-- core/src/apps/wallet/sign_tx/segwit_bip143.py | 51 +++++++++++-------- core/src/apps/wallet/sign_tx/zcash.py | 45 ++++++++-------- 3 files changed, 57 insertions(+), 46 deletions(-) diff --git a/core/src/apps/wallet/sign_tx/decred.py b/core/src/apps/wallet/sign_tx/decred.py index baa427e0a..76fa39dd9 100644 --- a/core/src/apps/wallet/sign_tx/decred.py +++ b/core/src/apps/wallet/sign_tx/decred.py @@ -13,6 +13,7 @@ from trezor.utils import HashWriter, ensure from apps.common import coininfo, seed from apps.wallet.sign_tx import addresses, helpers, multisig, progress, scripts, writers +from apps.wallet.sign_tx.segwit_bip143 import Bip143 from apps.wallet.sign_tx.signing import Bitcoin, SigningError, ecdsa_sign DECRED_SERIALIZE_FULL = const(0 << 16) @@ -25,7 +26,7 @@ if False: from typing import Union -class DecredPrefixHasher: +class DecredPrefixHasher(Bip143): """ While Decred does not have the exact same implementation as bip143/zip143, the semantics for using the prefix hash of transactions are close enough @@ -53,7 +54,7 @@ class DecredPrefixHasher: writers.write_uint32(self.h_prefix, tx.lock_time) writers.write_uint32(self.h_prefix, tx.expiry) - def prefix_hash(self) -> bytes: + def get_prefix_hash(self) -> bytes: return self.h_prefix.get_digest() @@ -110,7 +111,7 @@ class Decred(Bitcoin): async def phase2(self) -> None: self.tx_req.serialized = None - prefix_hash = self.hash143.prefix_hash() + prefix_hash = self.hash143.get_prefix_hash() for i_sign in range(self.tx.inputs_count): progress.advance() diff --git a/core/src/apps/wallet/sign_tx/segwit_bip143.py b/core/src/apps/wallet/sign_tx/segwit_bip143.py index e5f07a4ab..acafaa99e 100644 --- a/core/src/apps/wallet/sign_tx/segwit_bip143.py +++ b/core/src/apps/wallet/sign_tx/segwit_bip143.py @@ -37,9 +37,15 @@ class Bip143: def add_sequence(self, txi: TxInputType) -> None: write_uint32(self.h_sequence, txi.sequence) + def add_output_count(self, tx: SignTx) -> None: + pass + def add_output(self, txo_bin: TxOutputBinType) -> None: write_tx_output(self.h_outputs, txo_bin) + def add_locktime_expiry(self, tx: SignTx) -> None: + pass + def get_prevouts_hash(self, coin: CoinInfo) -> bytes: return get_tx_hash(self.h_prevouts, double=coin.sign_hash_double) @@ -49,6 +55,9 @@ class Bip143: def get_outputs_hash(self, coin: CoinInfo) -> bytes: return get_tx_hash(self.h_outputs, double=coin.sign_hash_double) + def get_prefix_hash(self) -> bytes: + pass + def preimage_hash( self, coin: CoinInfo, @@ -70,7 +79,7 @@ class Bip143: write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE) # outpoint write_uint32(h_preimage, txi.prev_index) # outpoint - script_code = self.derive_script_code(txi, pubkeyhash) # scriptCode + script_code = derive_script_code(txi, pubkeyhash) # scriptCode write_bytes_prefixed(h_preimage, script_code) write_uint64(h_preimage, txi.amount) # amount @@ -82,27 +91,27 @@ class Bip143: return get_tx_hash(h_preimage, double=coin.sign_hash_double) - # see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification - # item 5 for details - def derive_script_code(self, txi: TxInputType, pubkeyhash: bytes) -> bytearray: - if txi.multisig: - return output_script_multisig( - multisig_get_pubkeys(txi.multisig), txi.multisig.m - ) +# see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification +# item 5 for details +def derive_script_code(txi: TxInputType, pubkeyhash: bytes) -> bytearray: - p2pkh = ( - txi.script_type == InputScriptType.SPENDWITNESS - or txi.script_type == InputScriptType.SPENDP2SHWITNESS - or txi.script_type == InputScriptType.SPENDADDRESS + if txi.multisig: + return output_script_multisig( + multisig_get_pubkeys(txi.multisig), txi.multisig.m ) - if p2pkh: - # for p2wpkh in p2sh or native p2wpkh - # the scriptCode is a classic p2pkh - return output_script_p2pkh(pubkeyhash) - else: - raise Bip143Error( - FailureType.DataError, - "Unknown input script type for bip143 script code", - ) + p2pkh = ( + txi.script_type == InputScriptType.SPENDWITNESS + or txi.script_type == InputScriptType.SPENDP2SHWITNESS + or txi.script_type == InputScriptType.SPENDADDRESS + ) + if p2pkh: + # for p2wpkh in p2sh or native p2wpkh + # the scriptCode is a classic p2pkh + return output_script_p2pkh(pubkeyhash) + + else: + raise Bip143Error( + FailureType.DataError, "Unknown input script type for bip143 script code", + ) diff --git a/core/src/apps/wallet/sign_tx/zcash.py b/core/src/apps/wallet/sign_tx/zcash.py index e0d10cbe3..5884b7706 100644 --- a/core/src/apps/wallet/sign_tx/zcash.py +++ b/core/src/apps/wallet/sign_tx/zcash.py @@ -6,7 +6,6 @@ from trezor.messages import FailureType, InputScriptType from trezor.messages.SignTx import SignTx from trezor.messages.TransactionType import TransactionType from trezor.messages.TxInputType import TxInputType -from trezor.messages.TxOutputBinType import TxOutputBinType from trezor.utils import HashWriter, ensure from apps.common.coininfo import CoinInfo @@ -14,6 +13,7 @@ from apps.common.seed import Keychain from apps.wallet.sign_tx.bitcoinlike import Bitcoinlike from apps.wallet.sign_tx.multisig import multisig_get_pubkeys from apps.wallet.sign_tx.scripts import output_script_multisig, output_script_p2pkh +from apps.wallet.sign_tx.segwit_bip143 import Bip143 from apps.wallet.sign_tx.signing import SigningError from apps.wallet.sign_tx.writers import ( TX_HASH_SIZE, @@ -21,7 +21,6 @@ from apps.wallet.sign_tx.writers import ( write_bytes_fixed, write_bytes_prefixed, write_bytes_reversed, - write_tx_output, write_uint32, write_uint64, write_varint, @@ -55,30 +54,20 @@ def derive_script_code(txi: TxInputType, pubkeyhash: bytes) -> bytearray: ) -class Zip143: +class Zip143(Bip143): def __init__(self, branch_id: int) -> None: self.branch_id = branch_id 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 add_prevouts(self, txi: TxInputType) -> None: - write_bytes_reversed(self.h_prevouts, txi.prev_hash, TX_HASH_SIZE) - write_uint32(self.h_prevouts, txi.prev_index) - - def add_sequence(self, txi: TxInputType) -> None: - write_uint32(self.h_sequence, txi.sequence) - - def add_output(self, txo_bin: TxOutputBinType) -> None: - write_tx_output(self.h_outputs, txo_bin) - - def get_prevouts_hash(self) -> bytes: + def get_prevouts_hash(self, coin: CoinInfo) -> bytes: return get_tx_hash(self.h_prevouts) - def get_sequence_hash(self) -> bytes: + def get_sequence_hash(self, coin: CoinInfo) -> bytes: return get_tx_hash(self.h_sequence) - def get_outputs_hash(self) -> bytes: + def get_outputs_hash(self, coin: CoinInfo) -> bytes: return get_tx_hash(self.h_outputs) def preimage_hash( @@ -103,11 +92,17 @@ class Zip143: ) # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId # 3. hashPrevouts - write_bytes_fixed(h_preimage, bytearray(self.get_prevouts_hash()), TX_HASH_SIZE) + write_bytes_fixed( + h_preimage, bytearray(self.get_prevouts_hash(coin)), TX_HASH_SIZE + ) # 4. hashSequence - write_bytes_fixed(h_preimage, bytearray(self.get_sequence_hash()), TX_HASH_SIZE) + write_bytes_fixed( + h_preimage, bytearray(self.get_sequence_hash(coin)), TX_HASH_SIZE + ) # 5. hashOutputs - write_bytes_fixed(h_preimage, bytearray(self.get_outputs_hash()), TX_HASH_SIZE) + write_bytes_fixed( + h_preimage, bytearray(self.get_outputs_hash(coin)), TX_HASH_SIZE + ) # 6. hashJoinSplits write_bytes_fixed(h_preimage, b"\x00" * TX_HASH_SIZE, TX_HASH_SIZE) write_uint32(h_preimage, tx.lock_time) # 7. nLockTime @@ -153,11 +148,17 @@ class Zip243(Zip143): ) # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId # 3. hashPrevouts - write_bytes_fixed(h_preimage, bytearray(self.get_prevouts_hash()), TX_HASH_SIZE) + write_bytes_fixed( + h_preimage, bytearray(self.get_prevouts_hash(coin)), TX_HASH_SIZE + ) # 4. hashSequence - write_bytes_fixed(h_preimage, bytearray(self.get_sequence_hash()), TX_HASH_SIZE) + write_bytes_fixed( + h_preimage, bytearray(self.get_sequence_hash(coin)), TX_HASH_SIZE + ) # 5. hashOutputs - write_bytes_fixed(h_preimage, bytearray(self.get_outputs_hash()), TX_HASH_SIZE) + write_bytes_fixed( + h_preimage, bytearray(self.get_outputs_hash(coin)), TX_HASH_SIZE + ) zero_hash = b"\x00" * TX_HASH_SIZE write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 6. hashJoinSplits