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/bitcoinlike.py

102 lines
3.4 KiB

from micropython import const
from trezor import wire
from trezor.messages.PrevTx import PrevTx
from trezor.messages.SignTx import SignTx
from trezor.messages.TxInput import TxInput
from apps.common.writers import write_bitcoin_varint
from .. import multisig, writers
from ..common import input_is_nonsegwit
from . import helpers
from .bitcoin import Bitcoin
if False:
from .tx_info import OriginalTxInfo, TxInfo
_SIGHASH_FORKID = const(0x40)
class Bitcoinlike(Bitcoin):
async def sign_nonsegwit_bip143_input(self, i_sign: int) -> None:
txi = await helpers.request_tx_input(self.tx_req, i_sign, self.coin)
if not input_is_nonsegwit(txi):
raise wire.ProcessError("Transaction has changed during signing")
public_key, signature = self.sign_bip143_input(txi)
# if multisig, do a sanity check to ensure we are signing with a key that is included in the multisig
if txi.multisig:
multisig.multisig_pubkey_index(txi.multisig, public_key)
# serialize input with correct signature
script_sig = self.input_derive_script(txi, public_key, signature)
self.write_tx_input(self.serialized_tx, txi, script_sig)
self.set_serialized_signature(i_sign, signature)
async def sign_nonsegwit_input(self, i_sign: int) -> None:
if self.coin.force_bip143:
await self.sign_nonsegwit_bip143_input(i_sign)
else:
await super().sign_nonsegwit_input(i_sign)
async def get_tx_digest(
self,
i: int,
txi: TxInput,
tx_info: TxInfo | OriginalTxInfo,
public_keys: list[bytes],
threshold: int,
script_pubkey: bytes,
tx_hash: bytes | None = None,
) -> bytes:
if self.coin.force_bip143:
return tx_info.hash143.preimage_hash(
txi,
public_keys,
threshold,
tx_info.tx,
self.coin,
self.get_sighash_type(txi),
)
else:
return await super().get_tx_digest(
i, txi, tx_info, public_keys, threshold, script_pubkey
)
def get_sighash_type(self, txi: TxInput) -> 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
def write_tx_header(
self,
w: writers.Writer,
tx: SignTx | PrevTx,
witness_marker: bool,
) -> None:
writers.write_uint32(w, tx.version) # nVersion
if self.coin.timestamp:
assert tx.timestamp is not None # checked in sanitize_*
writers.write_uint32(w, tx.timestamp)
if witness_marker:
write_bitcoin_varint(w, 0x00) # segwit witness marker
write_bitcoin_varint(w, 0x01) # segwit witness flag
async def write_prev_tx_footer(
self, w: writers.Writer, tx: PrevTx, prev_hash: bytes
) -> None:
await super().write_prev_tx_footer(w, tx, prev_hash)
if self.coin.extra_data:
offset = 0
while offset < tx.extra_data_len:
size = min(1024, tx.extra_data_len - offset)
data = await helpers.request_tx_extra_data(
self.tx_req, offset, size, prev_hash
)
writers.write_bytes_unchecked(w, data)
offset += len(data)