From 5378e12ba2e34aafe5b90407d399d9279ac3f638 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Fri, 26 Jun 2020 09:37:30 +0200 Subject: [PATCH] core/bitcoin: Clarify hash_type vs. sighash_type terminology. --- core/src/apps/bitcoin/scripts.py | 28 ++++++++++---------- core/src/apps/bitcoin/sign_tx/bitcoin.py | 19 ++++++++----- core/src/apps/bitcoin/sign_tx/bitcoinlike.py | 4 +-- core/src/apps/bitcoin/sign_tx/zcash.py | 4 +-- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/core/src/apps/bitcoin/scripts.py b/core/src/apps/bitcoin/scripts.py index 1570e3664..d16c60f66 100644 --- a/core/src/apps/bitcoin/scripts.py +++ b/core/src/apps/bitcoin/scripts.py @@ -137,10 +137,10 @@ def bip143_derive_script_code(txi: TxInputType, pubkeyhash: bytes) -> bytearray: def input_script_p2pkh_or_p2sh( - pubkey: bytes, signature: bytes, sighash: int + pubkey: bytes, signature: bytes, hash_type: int ) -> bytearray: w = empty_bytearray(5 + len(signature) + 1 + 5 + len(pubkey)) - append_signature(w, signature, sighash) + append_signature(w, signature, hash_type) append_pubkey(w, pubkey) return w @@ -264,10 +264,10 @@ def input_script_p2wsh_in_p2sh(script_hash: bytes) -> bytearray: # === -def witness_p2wpkh(signature: bytes, pubkey: bytes, sighash: int) -> bytearray: +def witness_p2wpkh(signature: bytes, pubkey: bytes, hash_type: int) -> bytearray: w = empty_bytearray(1 + 5 + len(signature) + 1 + 5 + len(pubkey)) write_bitcoin_varint(w, 0x02) # num of segwit items, in P2WPKH it's always 2 - write_signature_prefixed(w, signature, sighash) + write_signature_prefixed(w, signature, hash_type) write_bytes_prefixed(w, pubkey) return w @@ -297,7 +297,7 @@ def witness_p2wsh( multisig: MultisigRedeemScriptType, signature: bytes, signature_index: int, - sighash: int, + hash_type: int, ) -> bytearray: # get other signatures, stretch with None to the number of the pubkeys signatures = multisig.signatures + [None] * ( @@ -321,7 +321,7 @@ def witness_p2wsh( # length of the result total_length = 1 + 1 # number of items, OP_FALSE for s in signatures: - total_length += 1 + len(s) + 1 # length, signature, sighash + total_length += 1 + len(s) + 1 # length, signature, hash_type total_length += 1 + redeem_script_length # length, script w = empty_bytearray(total_length) @@ -333,7 +333,7 @@ def witness_p2wsh( write_bitcoin_varint(w, 0) for s in signatures: - write_signature_prefixed(w, s, sighash) # size of the witness included + write_signature_prefixed(w, s, hash_type) # size of the witness included # redeem script write_bitcoin_varint(w, redeem_script_length) @@ -379,7 +379,7 @@ def input_script_multisig( multisig: MultisigRedeemScriptType, signature: bytes, signature_index: int, - sighash: int, + hash_type: int, coin: CoinInfo, ) -> bytearray: signatures = multisig.signatures # other signatures @@ -396,7 +396,7 @@ def input_script_multisig( if utils.BITCOIN_ONLY or not coin.decred: total_length += 1 # OP_FALSE for s in signatures: - total_length += 1 + len(s) + 1 # length, signature, sighash + total_length += 1 + len(s) + 1 # length, signature, hash_type total_length += 1 + redeem_script_length # length, script w = empty_bytearray(total_length) @@ -409,7 +409,7 @@ def input_script_multisig( for s in signatures: if len(s): - append_signature(w, s, sighash) + append_signature(w, s, hash_type) # redeem script write_op_push(w, redeem_script_length) @@ -519,16 +519,16 @@ def output_script_paytoopreturn(data: bytes) -> bytearray: # === -def write_signature_prefixed(w: Writer, signature: bytes, sighash: int) -> None: +def write_signature_prefixed(w: Writer, signature: bytes, hash_type: int) -> None: write_bitcoin_varint(w, len(signature) + 1) write_bytes_unchecked(w, signature) - w.append(sighash) + w.append(hash_type) -def append_signature(w: Writer, signature: bytes, sighash: int) -> None: +def append_signature(w: Writer, signature: bytes, hash_type: int) -> None: write_op_push(w, len(signature) + 1) write_bytes_unchecked(w, signature) - w.append(sighash) + w.append(hash_type) def append_pubkey(w: Writer, pubkey: bytes) -> None: diff --git a/core/src/apps/bitcoin/sign_tx/bitcoin.py b/core/src/apps/bitcoin/sign_tx/bitcoin.py index d271c54de..58cdf2b6c 100644 --- a/core/src/apps/bitcoin/sign_tx/bitcoin.py +++ b/core/src/apps/bitcoin/sign_tx/bitcoin.py @@ -250,12 +250,12 @@ class Bitcoin: signature_index = multisig.multisig_pubkey_index(txi.multisig, public_key) self.serialized_tx.extend( scripts.witness_p2wsh( - txi.multisig, signature, signature_index, self.get_hash_type() + txi.multisig, signature, signature_index, self.get_hash_type(txi) ) ) else: self.serialized_tx.extend( - scripts.witness_p2wpkh(signature, public_key, self.get_hash_type()) + scripts.witness_p2wpkh(signature, public_key, self.get_hash_type(txi)) ) async def sign_nonsegwit_input(self, i_sign: int) -> None: @@ -307,7 +307,7 @@ class Bitcoin: self.write_tx_output(h_sign, txo, script_pubkey) writers.write_uint32(h_sign, self.tx.lock_time) - writers.write_uint32(h_sign, self.get_hash_type()) + writers.write_uint32(h_sign, self.get_sighash_type(txi_sign)) # check the control digests if self.h_confirmed.get_digest() != h_check.get_digest(): @@ -382,9 +382,16 @@ class Bitcoin: # Tx Helpers # === - def get_hash_type(self) -> int: + def get_sighash_type(self, txi: TxInputType) -> int: return _SIGHASH_ALL + def get_hash_type(self, txi: TxInputType) -> int: + """ Return the nHashType flags.""" + # The nHashType is the 8 least significant bits of the sighash type. + # Some coins set the 24 most significant bits of the sighash type to + # the fork ID value. + return self.get_sighash_type(txi) & 0xFF + def write_tx_input( self, w: writers.Writer, txi: TxInputType, script: bytes ) -> None: @@ -470,7 +477,7 @@ class Bitcoin: txi.script_type, txi.multisig, self.coin, - self.get_hash_type(), + self.get_hash_type(txi), pubkey, signature, ) @@ -535,7 +542,7 @@ class Bitcoin: writers.write_uint32(h_preimage, self.tx.lock_time) # nHashType - writers.write_uint32(h_preimage, self.get_hash_type()) + writers.write_uint32(h_preimage, self.get_sighash_type(txi)) return writers.get_tx_hash(h_preimage, double=self.coin.sign_hash_double) diff --git a/core/src/apps/bitcoin/sign_tx/bitcoinlike.py b/core/src/apps/bitcoin/sign_tx/bitcoinlike.py index 7b57c265a..770583bee 100644 --- a/core/src/apps/bitcoin/sign_tx/bitcoinlike.py +++ b/core/src/apps/bitcoin/sign_tx/bitcoinlike.py @@ -46,8 +46,8 @@ class Bitcoinlike(Bitcoin): if not self.coin.negative_fee: super().on_negative_fee() - def get_hash_type(self) -> int: - hashtype = super().get_hash_type() + def get_sighash_type(self, txi: TxInputType) -> int: + hashtype = super().get_sighash_type(txi) if self.coin.fork_id is not None: hashtype |= (self.coin.fork_id << 8) | _SIGHASH_FORKID return hashtype diff --git a/core/src/apps/bitcoin/sign_tx/zcash.py b/core/src/apps/bitcoin/sign_tx/zcash.py index bfe905278..bf66350dd 100644 --- a/core/src/apps/bitcoin/sign_tx/zcash.py +++ b/core/src/apps/bitcoin/sign_tx/zcash.py @@ -117,7 +117,7 @@ class Overwintered(Bitcoinlike): # 8. expiryHeight write_uint32(h_preimage, self.tx.expiry) # 9. nHashType - write_uint32(h_preimage, self.get_hash_type()) + write_uint32(h_preimage, self.get_sighash_type(txi)) elif self.tx.version == 4: zero_hash = b"\x00" * TX_HASH_SIZE # 6. hashJoinSplits @@ -133,7 +133,7 @@ class Overwintered(Bitcoinlike): # 11. valueBalance write_uint64(h_preimage, 0) # 12. nHashType - write_uint32(h_preimage, self.get_hash_type()) + write_uint32(h_preimage, self.get_sighash_type(txi)) else: raise wire.DataError("Unsupported version for overwintered transaction")