You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/src/apps/bitcoin/sign_tx/sig_hasher.py

182 lines
5.1 KiB

from typing import TYPE_CHECKING
from ..writers import (
TX_HASH_SIZE,
write_bytes_fixed,
write_bytes_reversed,
write_uint32,
write_uint64,
)
if TYPE_CHECKING:
from typing import Protocol, Sequence
from trezor.messages import PrevTx, SignTx, TxInput, TxOutput
from apps.common import coininfo
from ..common import SigHashType
class SigHasher(Protocol):
def add_input(self, txi: TxInput, script_pubkey: bytes) -> None: ...
def add_output(self, txo: TxOutput, script_pubkey: bytes) -> None: ...
def hash143(
self,
txi: TxInput,
public_keys: Sequence[bytes | memoryview],
threshold: int,
tx: SignTx | PrevTx,
coin: coininfo.CoinInfo,
hash_type: int,
) -> bytes: ...
def hash341(
self,
i: int,
tx: SignTx | PrevTx,
sighash_type: SigHashType,
) -> bytes: ...
def hash_zip244(
self,
txi: TxInput | None,
script_pubkey: bytes | None,
) -> bytes: ...
# BIP-0143 hash
class BitcoinSigHasher:
def __init__(self) -> None:
from trezor.crypto.hashlib import sha256
from trezor.utils import HashWriter
self.h_prevouts = HashWriter(sha256())
self.h_amounts = HashWriter(sha256())
self.h_scriptpubkeys = HashWriter(sha256())
self.h_sequences = HashWriter(sha256())
self.h_outputs = HashWriter(sha256())
def add_input(self, txi: TxInput, script_pubkey: bytes) -> None:
from ..writers import write_bytes_prefixed
write_bytes_reversed(self.h_prevouts, txi.prev_hash, TX_HASH_SIZE)
write_uint32(self.h_prevouts, txi.prev_index)
write_uint64(self.h_amounts, txi.amount)
write_bytes_prefixed(self.h_scriptpubkeys, script_pubkey)
write_uint32(self.h_sequences, txi.sequence)
def add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
from ..writers import write_tx_output
write_tx_output(self.h_outputs, txo, script_pubkey)
def hash143(
self,
txi: TxInput,
public_keys: Sequence[bytes | memoryview],
threshold: int,
tx: SignTx | PrevTx,
coin: coininfo.CoinInfo,
hash_type: int,
) -> bytes:
from trezor.crypto.hashlib import sha256
from trezor.utils import HashWriter
from .. import scripts
from ..writers import get_tx_hash
h_preimage = HashWriter(sha256())
# nVersion
write_uint32(h_preimage, tx.version)
# hashPrevouts
prevouts_hash = get_tx_hash(self.h_prevouts, double=coin.sign_hash_double)
write_bytes_fixed(h_preimage, prevouts_hash, TX_HASH_SIZE)
# hashSequence
sequence_hash = get_tx_hash(self.h_sequences, double=coin.sign_hash_double)
write_bytes_fixed(h_preimage, sequence_hash, TX_HASH_SIZE)
# outpoint
write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE)
write_uint32(h_preimage, txi.prev_index)
# scriptCode
scripts.write_bip143_script_code_prefixed(
h_preimage, txi, public_keys, threshold, coin
)
# amount
write_uint64(h_preimage, txi.amount)
# nSequence
write_uint32(h_preimage, txi.sequence)
# hashOutputs
outputs_hash = get_tx_hash(self.h_outputs, double=coin.sign_hash_double)
write_bytes_fixed(h_preimage, outputs_hash, TX_HASH_SIZE)
# nLockTime
write_uint32(h_preimage, tx.lock_time)
# nHashType
write_uint32(h_preimage, hash_type)
return get_tx_hash(h_preimage, double=coin.sign_hash_double)
def hash341(
self,
i: int,
tx: SignTx | PrevTx,
sighash_type: SigHashType,
) -> bytes:
from ..common import tagged_hashwriter
from ..writers import write_uint8
h_sigmsg = tagged_hashwriter(b"TapSighash")
# sighash epoch 0
write_uint8(h_sigmsg, 0)
# nHashType
write_uint8(h_sigmsg, sighash_type & 0xFF)
# nVersion
write_uint32(h_sigmsg, tx.version)
# nLockTime
write_uint32(h_sigmsg, tx.lock_time)
# sha_prevouts
write_bytes_fixed(h_sigmsg, self.h_prevouts.get_digest(), TX_HASH_SIZE)
# sha_amounts
write_bytes_fixed(h_sigmsg, self.h_amounts.get_digest(), TX_HASH_SIZE)
# sha_scriptpubkeys
write_bytes_fixed(h_sigmsg, self.h_scriptpubkeys.get_digest(), TX_HASH_SIZE)
# sha_sequences
write_bytes_fixed(h_sigmsg, self.h_sequences.get_digest(), TX_HASH_SIZE)
# sha_outputs
write_bytes_fixed(h_sigmsg, self.h_outputs.get_digest(), TX_HASH_SIZE)
# spend_type 0 (no tapscript message extension, no annex)
write_uint8(h_sigmsg, 0)
# input_index
write_uint32(h_sigmsg, i)
return h_sigmsg.get_digest()
def hash_zip244(
self,
txi: TxInput | None,
script_pubkey: bytes | None,
) -> bytes:
raise NotImplementedError