mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 23:48:12 +00:00
chore(core): In apps.bitcoin allow get_tx_digest() to be used for original transactions.
This commit is contained in:
parent
b636e959f5
commit
7c2d690e45
@ -239,21 +239,22 @@ class Bitcoin:
|
|||||||
self,
|
self,
|
||||||
i: int,
|
i: int,
|
||||||
txi: TxInput,
|
txi: TxInput,
|
||||||
|
tx: Union[SignTx, PrevTx],
|
||||||
|
hash143: Hash143,
|
||||||
|
h_approved: HashWriter,
|
||||||
public_keys: List[bytes],
|
public_keys: List[bytes],
|
||||||
threshold: int,
|
threshold: int,
|
||||||
script_pubkey: bytes,
|
script_pubkey: bytes,
|
||||||
|
tx_hash: Optional[bytes] = None,
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
if txi.witness:
|
if txi.witness:
|
||||||
return self.hash143.preimage_hash(
|
return hash143.preimage_hash(
|
||||||
txi,
|
txi, public_keys, threshold, tx, self.coin, self.get_sighash_type(txi),
|
||||||
public_keys,
|
|
||||||
threshold,
|
|
||||||
self.tx,
|
|
||||||
self.coin,
|
|
||||||
self.get_sighash_type(txi),
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
digest, _, _ = await self.get_legacy_tx_digest(i, script_pubkey)
|
digest, _, _ = await self.get_legacy_tx_digest(
|
||||||
|
i, tx, h_approved, script_pubkey, tx_hash
|
||||||
|
)
|
||||||
return digest
|
return digest
|
||||||
|
|
||||||
async def verify_external_input(
|
async def verify_external_input(
|
||||||
@ -276,7 +277,14 @@ class Bitcoin:
|
|||||||
verifier.ensure_hash_type(self.get_hash_type(txi))
|
verifier.ensure_hash_type(self.get_hash_type(txi))
|
||||||
|
|
||||||
tx_digest = await self.get_tx_digest(
|
tx_digest = await self.get_tx_digest(
|
||||||
i, txi, verifier.public_keys, verifier.threshold, script_pubkey
|
i,
|
||||||
|
txi,
|
||||||
|
self.tx,
|
||||||
|
self.hash143,
|
||||||
|
self.h_approved,
|
||||||
|
verifier.public_keys,
|
||||||
|
verifier.threshold,
|
||||||
|
script_pubkey,
|
||||||
)
|
)
|
||||||
verifier.verify(tx_digest)
|
verifier.verify(tx_digest)
|
||||||
|
|
||||||
@ -347,25 +355,32 @@ class Bitcoin:
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def get_legacy_tx_digest(
|
async def get_legacy_tx_digest(
|
||||||
self, index: int, script_pubkey: Optional[bytes] = None
|
self,
|
||||||
|
index: int,
|
||||||
|
tx: Union[SignTx, PrevTx],
|
||||||
|
h_approved: HashWriter,
|
||||||
|
script_pubkey: Optional[bytes] = None,
|
||||||
|
tx_hash: Optional[bytes] = None,
|
||||||
) -> Tuple[bytes, TxInput, Optional[bip32.HDNode]]:
|
) -> Tuple[bytes, TxInput, Optional[bip32.HDNode]]:
|
||||||
|
|
||||||
# the transaction digest which gets signed for this input
|
# the transaction digest which gets signed for this input
|
||||||
h_sign = self.create_hash_writer()
|
h_sign = self.create_hash_writer()
|
||||||
# should come out the same as h_approved, checked before signing the digest
|
# should come out the same as h_approved, checked before signing the digest
|
||||||
h_check = self.create_hash_writer()
|
h_check = self.create_hash_writer()
|
||||||
|
|
||||||
self.write_tx_header(h_sign, self.tx, witness_marker=False)
|
self.write_tx_header(h_sign, tx, witness_marker=False)
|
||||||
write_bitcoin_varint(h_sign, self.tx.inputs_count)
|
write_bitcoin_varint(h_sign, tx.inputs_count)
|
||||||
|
|
||||||
for i in range(self.tx.inputs_count):
|
for i in range(tx.inputs_count):
|
||||||
# STAGE_REQUEST_4_INPUT in legacy
|
# STAGE_REQUEST_4_INPUT in legacy
|
||||||
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
|
txi = await helpers.request_tx_input(self.tx_req, i, self.coin, tx_hash)
|
||||||
writers.write_tx_input_check(h_check, txi)
|
writers.write_tx_input_check(h_check, txi)
|
||||||
# Only the previous UTXO's scriptPubKey is included in h_sign.
|
# Only the previous UTXO's scriptPubKey is included in h_sign.
|
||||||
if i == index:
|
if i == index:
|
||||||
txi_sign = txi
|
txi_sign = txi
|
||||||
node = None
|
node = None
|
||||||
if not script_pubkey:
|
if not script_pubkey:
|
||||||
|
if isinstance(tx, SignTx):
|
||||||
self.wallet_path.check_input(txi)
|
self.wallet_path.check_input(txi)
|
||||||
self.multisig_fingerprint.check_input(txi)
|
self.multisig_fingerprint.check_input(txi)
|
||||||
node = self.keychain.derive(txi.address_n)
|
node = self.keychain.derive(txi.address_n)
|
||||||
@ -390,27 +405,29 @@ class Bitcoin:
|
|||||||
else:
|
else:
|
||||||
self.write_tx_input(h_sign, txi, bytes())
|
self.write_tx_input(h_sign, txi, bytes())
|
||||||
|
|
||||||
write_bitcoin_varint(h_sign, self.tx.outputs_count)
|
write_bitcoin_varint(h_sign, tx.outputs_count)
|
||||||
|
|
||||||
for i in range(self.tx.outputs_count):
|
for i in range(tx.outputs_count):
|
||||||
# STAGE_REQUEST_4_OUTPUT in legacy
|
# STAGE_REQUEST_4_OUTPUT in legacy
|
||||||
txo = await helpers.request_tx_output(self.tx_req, i, self.coin)
|
txo = await helpers.request_tx_output(self.tx_req, i, self.coin, tx_hash)
|
||||||
script_pubkey = self.output_derive_script(txo)
|
script_pubkey = self.output_derive_script(txo)
|
||||||
self.write_tx_output(h_check, txo, script_pubkey)
|
self.write_tx_output(h_check, txo, script_pubkey)
|
||||||
self.write_tx_output(h_sign, txo, script_pubkey)
|
self.write_tx_output(h_sign, txo, script_pubkey)
|
||||||
|
|
||||||
writers.write_uint32(h_sign, self.tx.lock_time)
|
writers.write_uint32(h_sign, tx.lock_time)
|
||||||
writers.write_uint32(h_sign, self.get_sighash_type(txi_sign))
|
writers.write_uint32(h_sign, self.get_sighash_type(txi_sign))
|
||||||
|
|
||||||
# check that the inputs were the same as those streamed for approval
|
# check that the inputs were the same as those streamed for approval
|
||||||
if self.h_approved.get_digest() != h_check.get_digest():
|
if h_approved.get_digest() != h_check.get_digest():
|
||||||
raise wire.ProcessError("Transaction has changed during signing")
|
raise wire.ProcessError("Transaction has changed during signing")
|
||||||
|
|
||||||
tx_digest = writers.get_tx_hash(h_sign, double=self.coin.sign_hash_double)
|
tx_digest = writers.get_tx_hash(h_sign, double=self.coin.sign_hash_double)
|
||||||
return tx_digest, txi_sign, node
|
return tx_digest, txi_sign, node
|
||||||
|
|
||||||
async def sign_nonsegwit_input(self, i: int) -> None:
|
async def sign_nonsegwit_input(self, i: int) -> None:
|
||||||
tx_digest, txi, node = await self.get_legacy_tx_digest(i)
|
tx_digest, txi, node = await self.get_legacy_tx_digest(
|
||||||
|
i, self.tx, self.h_approved
|
||||||
|
)
|
||||||
assert node is not None
|
assert node is not None
|
||||||
|
|
||||||
# compute the signature from the tx digest
|
# compute the signature from the tx digest
|
||||||
|
@ -9,10 +9,11 @@ from apps.common.writers import write_bitcoin_varint
|
|||||||
|
|
||||||
from .. import multisig, writers
|
from .. import multisig, writers
|
||||||
from . import helpers
|
from . import helpers
|
||||||
from .bitcoin import Bitcoin, input_is_nonsegwit
|
from .bitcoin import Bitcoin, Hash143, input_is_nonsegwit
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import List, Union
|
from typing import List, Optional, Union
|
||||||
|
from trezor.utils import HashWriter
|
||||||
|
|
||||||
_SIGHASH_FORKID = const(0x40)
|
_SIGHASH_FORKID = const(0x40)
|
||||||
|
|
||||||
@ -44,22 +45,21 @@ class Bitcoinlike(Bitcoin):
|
|||||||
self,
|
self,
|
||||||
i: int,
|
i: int,
|
||||||
txi: TxInput,
|
txi: TxInput,
|
||||||
|
tx: Union[SignTx, PrevTx],
|
||||||
|
hash143: Hash143,
|
||||||
|
h_approved: HashWriter,
|
||||||
public_keys: List[bytes],
|
public_keys: List[bytes],
|
||||||
threshold: int,
|
threshold: int,
|
||||||
script_pubkey: bytes,
|
script_pubkey: bytes,
|
||||||
|
tx_hash: Optional[bytes] = None,
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
if self.coin.force_bip143:
|
if self.coin.force_bip143:
|
||||||
return self.hash143.preimage_hash(
|
return hash143.preimage_hash(
|
||||||
txi,
|
txi, public_keys, threshold, tx, self.coin, self.get_sighash_type(txi),
|
||||||
public_keys,
|
|
||||||
threshold,
|
|
||||||
self.tx,
|
|
||||||
self.coin,
|
|
||||||
self.get_sighash_type(txi),
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return await super().get_tx_digest(
|
return await super().get_tx_digest(
|
||||||
i, txi, public_keys, threshold, script_pubkey
|
i, txi, tx, hash143, h_approved, public_keys, threshold, script_pubkey
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_sighash_type(self, txi: TxInput) -> int:
|
def get_sighash_type(self, txi: TxInput) -> int:
|
||||||
|
@ -8,6 +8,8 @@ from trezor.messages.RequestType import (
|
|||||||
TXFINISHED,
|
TXFINISHED,
|
||||||
TXINPUT,
|
TXINPUT,
|
||||||
TXMETA,
|
TXMETA,
|
||||||
|
TXORIGINPUT,
|
||||||
|
TXORIGOUTPUT,
|
||||||
TXOUTPUT,
|
TXOUTPUT,
|
||||||
)
|
)
|
||||||
from trezor.messages.SignTx import SignTx
|
from trezor.messages.SignTx import SignTx
|
||||||
@ -29,7 +31,7 @@ from ..writers import TX_HASH_SIZE
|
|||||||
from . import layout
|
from . import layout
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import Any, Awaitable
|
from typing import Any, Awaitable, Optional
|
||||||
|
|
||||||
|
|
||||||
# Machine instructions
|
# Machine instructions
|
||||||
@ -170,8 +172,12 @@ def request_tx_extra_data( # type: ignore
|
|||||||
return ack.tx.extra_data_chunk
|
return ack.tx.extra_data_chunk
|
||||||
|
|
||||||
|
|
||||||
def request_tx_input(tx_req: TxRequest, i: int, coin: CoinInfo) -> Awaitable[TxInput]: # type: ignore
|
def request_tx_input(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: Optional[bytes] = None) -> Awaitable[TxInput]: # type: ignore
|
||||||
assert tx_req.details is not None
|
assert tx_req.details is not None
|
||||||
|
if tx_hash:
|
||||||
|
tx_req.request_type = TXORIGINPUT
|
||||||
|
tx_req.details.tx_hash = tx_hash
|
||||||
|
else:
|
||||||
tx_req.request_type = TXINPUT
|
tx_req.request_type = TXINPUT
|
||||||
tx_req.details.request_index = i
|
tx_req.details.request_index = i
|
||||||
ack = yield TxAckInput, tx_req
|
ack = yield TxAckInput, tx_req
|
||||||
@ -189,8 +195,12 @@ def request_tx_prev_input(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: by
|
|||||||
return sanitize_tx_prev_input(ack.tx.input, coin)
|
return sanitize_tx_prev_input(ack.tx.input, coin)
|
||||||
|
|
||||||
|
|
||||||
def request_tx_output(tx_req: TxRequest, i: int, coin: CoinInfo) -> Awaitable[TxOutput]: # type: ignore
|
def request_tx_output(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: Optional[bytes] = None) -> Awaitable[TxOutput]: # type: ignore
|
||||||
assert tx_req.details is not None
|
assert tx_req.details is not None
|
||||||
|
if tx_hash:
|
||||||
|
tx_req.request_type = TXORIGOUTPUT
|
||||||
|
tx_req.details.tx_hash = tx_hash
|
||||||
|
else:
|
||||||
tx_req.request_type = TXOUTPUT
|
tx_req.request_type = TXOUTPUT
|
||||||
tx_req.details.request_index = i
|
tx_req.details.request_index = i
|
||||||
ack = yield TxAckOutput, tx_req
|
ack = yield TxAckOutput, tx_req
|
||||||
|
@ -30,7 +30,7 @@ from .hash143 import Hash143
|
|||||||
|
|
||||||
if False:
|
if False:
|
||||||
from apps.common import coininfo
|
from apps.common import coininfo
|
||||||
from typing import List, Union
|
from typing import List, Optional, Union
|
||||||
from ..writers import Writer
|
from ..writers import Writer
|
||||||
|
|
||||||
OVERWINTERED = const(0x80000000)
|
OVERWINTERED = const(0x80000000)
|
||||||
@ -134,12 +134,16 @@ class Zcashlike(Bitcoinlike):
|
|||||||
self,
|
self,
|
||||||
i: int,
|
i: int,
|
||||||
txi: TxInput,
|
txi: TxInput,
|
||||||
|
tx: Union[SignTx, PrevTx],
|
||||||
|
hash143: Hash143,
|
||||||
|
h_approved: HashWriter,
|
||||||
public_keys: List[bytes],
|
public_keys: List[bytes],
|
||||||
threshold: int,
|
threshold: int,
|
||||||
script_pubkey: bytes,
|
script_pubkey: bytes,
|
||||||
|
tx_hash: Optional[bytes] = None,
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
return self.hash143.preimage_hash(
|
return hash143.preimage_hash(
|
||||||
txi, public_keys, threshold, self.tx, self.coin, self.get_sighash_type(txi)
|
txi, public_keys, threshold, tx, self.coin, self.get_sighash_type(txi)
|
||||||
)
|
)
|
||||||
|
|
||||||
def write_tx_header(
|
def write_tx_header(
|
||||||
|
Loading…
Reference in New Issue
Block a user