mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-05-28 19:58:45 +00:00
core/sign_tx: Factor out get_legacy_tx_digest() from sign_nonsegwit_input().
This commit is contained in:
parent
61e2d4d5e5
commit
78f14d286e
@ -23,7 +23,8 @@ from . import helpers, progress, tx_weight
|
|||||||
from .matchcheck import MultisigFingerprintChecker, WalletPathChecker
|
from .matchcheck import MultisigFingerprintChecker, WalletPathChecker
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import Set, Tuple, Union
|
from typing import Set, Optional, Tuple, Union
|
||||||
|
from trezor.crypto.bip32 import HDNode
|
||||||
|
|
||||||
# Default signature hash type in Bitcoin which signs all inputs and all outputs of the transaction.
|
# Default signature hash type in Bitcoin which signs all inputs and all outputs of the transaction.
|
||||||
_SIGHASH_ALL = const(0x01)
|
_SIGHASH_ALL = const(0x01)
|
||||||
@ -258,8 +259,10 @@ class Bitcoin:
|
|||||||
scripts.witness_p2wpkh(signature, public_key, self.get_hash_type(txi))
|
scripts.witness_p2wpkh(signature, public_key, self.get_hash_type(txi))
|
||||||
)
|
)
|
||||||
|
|
||||||
async def sign_nonsegwit_input(self, i_sign: int) -> None:
|
async def get_legacy_tx_digest(
|
||||||
# hash of what we are signing with this input
|
self, index: int, script_pubkey: Optional[bytes] = None
|
||||||
|
) -> Tuple[bytes, TxInputType, Optional[HDNode]]:
|
||||||
|
# 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_confirmed, checked before signing the digest
|
# should come out the same as h_confirmed, checked before signing the digest
|
||||||
h_check = self.create_hash_writer()
|
h_check = self.create_hash_writer()
|
||||||
@ -271,31 +274,32 @@ class Bitcoin:
|
|||||||
# 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)
|
||||||
writers.write_tx_input_check(h_check, txi)
|
writers.write_tx_input_check(h_check, txi)
|
||||||
if i == i_sign:
|
# Only the previous UTXO's scriptPubKey is included in h_sign.
|
||||||
self.wallet_path.check_input(txi)
|
if i == index:
|
||||||
self.multisig_fingerprint.check_input(txi)
|
|
||||||
# NOTE: wallet_path is checked in write_tx_input_check()
|
|
||||||
node = self.keychain.derive(txi.address_n)
|
|
||||||
key_sign_pub = node.public_key()
|
|
||||||
# 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, key_sign_pub)
|
|
||||||
|
|
||||||
# For the signing process the previous UTXO's scriptPubKey is included in h_sign.
|
|
||||||
if txi.script_type == InputScriptType.SPENDMULTISIG:
|
|
||||||
script_pubkey = scripts.output_script_multisig(
|
|
||||||
multisig.multisig_get_pubkeys(txi.multisig), txi.multisig.m,
|
|
||||||
)
|
|
||||||
elif txi.script_type == InputScriptType.SPENDADDRESS:
|
|
||||||
script_pubkey = scripts.output_script_p2pkh(
|
|
||||||
addresses.ecdsa_hash_pubkey(key_sign_pub, self.coin)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise wire.ProcessError("Unknown transaction type")
|
|
||||||
txi_sign = txi
|
txi_sign = txi
|
||||||
|
node = None
|
||||||
|
if not script_pubkey:
|
||||||
|
self.wallet_path.check_input(txi)
|
||||||
|
self.multisig_fingerprint.check_input(txi)
|
||||||
|
node = self.keychain.derive(txi.address_n)
|
||||||
|
key_sign_pub = node.public_key()
|
||||||
|
if txi.multisig:
|
||||||
|
# Sanity check to ensure we are signing with a key that is included in the multisig.
|
||||||
|
multisig.multisig_pubkey_index(txi.multisig, key_sign_pub)
|
||||||
|
|
||||||
|
if txi.script_type == InputScriptType.SPENDMULTISIG:
|
||||||
|
script_pubkey = scripts.output_script_multisig(
|
||||||
|
multisig.multisig_get_pubkeys(txi.multisig), txi.multisig.m,
|
||||||
|
)
|
||||||
|
elif txi.script_type == InputScriptType.SPENDADDRESS:
|
||||||
|
script_pubkey = scripts.output_script_p2pkh(
|
||||||
|
addresses.ecdsa_hash_pubkey(key_sign_pub, self.coin)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise wire.ProcessError("Unknown transaction type")
|
||||||
|
self.write_tx_input(h_sign, txi, script_pubkey)
|
||||||
else:
|
else:
|
||||||
script_pubkey = bytes()
|
self.write_tx_input(h_sign, txi, bytes())
|
||||||
self.write_tx_input(h_sign, txi, script_pubkey)
|
|
||||||
|
|
||||||
write_bitcoin_varint(h_sign, self.tx.outputs_count)
|
write_bitcoin_varint(h_sign, self.tx.outputs_count)
|
||||||
|
|
||||||
@ -313,16 +317,21 @@ class Bitcoin:
|
|||||||
if self.h_confirmed.get_digest() != h_check.get_digest():
|
if self.h_confirmed.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)
|
||||||
|
return tx_digest, txi_sign, node
|
||||||
|
|
||||||
|
async def sign_nonsegwit_input(self, i: int) -> None:
|
||||||
|
tx_digest, txi, node = await self.get_legacy_tx_digest(i)
|
||||||
|
assert node is not None
|
||||||
|
|
||||||
# compute the signature from the tx digest
|
# compute the signature from the tx digest
|
||||||
signature = ecdsa_sign(
|
signature = ecdsa_sign(node, tx_digest)
|
||||||
node, writers.get_tx_hash(h_sign, double=self.coin.sign_hash_double)
|
|
||||||
)
|
|
||||||
|
|
||||||
# serialize input with correct signature
|
# serialize input with correct signature
|
||||||
gc.collect()
|
gc.collect()
|
||||||
script_sig = self.input_derive_script(txi_sign, key_sign_pub, signature)
|
script_sig = self.input_derive_script(txi, node.public_key(), signature)
|
||||||
self.write_tx_input(self.serialized_tx, txi_sign, script_sig)
|
self.write_tx_input(self.serialized_tx, txi, script_sig)
|
||||||
self.set_serialized_signature(i_sign, signature)
|
self.set_serialized_signature(i, signature)
|
||||||
|
|
||||||
async def serialize_output(self, i: int) -> None:
|
async def serialize_output(self, i: int) -> None:
|
||||||
# STAGE_REQUEST_5_OUTPUT in legacy
|
# STAGE_REQUEST_5_OUTPUT in legacy
|
||||||
|
Loading…
Reference in New Issue
Block a user