|
|
|
@ -2,7 +2,7 @@ from micropython import const
|
|
|
|
|
|
|
|
|
|
from trezor.crypto import base58, bip32, cashaddr, der
|
|
|
|
|
from trezor.crypto.curve import secp256k1
|
|
|
|
|
from trezor.crypto.hashlib import sha256
|
|
|
|
|
from trezor.crypto.hashlib import blake256, sha256
|
|
|
|
|
from trezor.messages import OutputScriptType
|
|
|
|
|
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
|
|
|
|
|
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
|
|
|
|
@ -13,6 +13,12 @@ from apps.common.coininfo import CoinInfo
|
|
|
|
|
from apps.common.writers import empty_bytearray
|
|
|
|
|
from apps.wallet.sign_tx import progress
|
|
|
|
|
from apps.wallet.sign_tx.addresses import *
|
|
|
|
|
from apps.wallet.sign_tx.decred_prefix_hasher import (
|
|
|
|
|
DECRED_SERIALIZE_NO_WITNESS,
|
|
|
|
|
DECRED_SERIALIZE_WITNESS_SIGNING,
|
|
|
|
|
DECRED_SIGHASHALL,
|
|
|
|
|
DecredPrefixHasher,
|
|
|
|
|
)
|
|
|
|
|
from apps.wallet.sign_tx.helpers import *
|
|
|
|
|
from apps.wallet.sign_tx.multisig import *
|
|
|
|
|
from apps.wallet.sign_tx.overwinter_zip143 import ( # noqa:F401
|
|
|
|
@ -59,7 +65,10 @@ async def check_tx_fee(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
# tx, as the SignTx info is streamed only once
|
|
|
|
|
h_first = HashWriter(sha256) # not a real tx hash
|
|
|
|
|
|
|
|
|
|
if tx.overwintered:
|
|
|
|
|
if coin.decred:
|
|
|
|
|
hash143 = DecredPrefixHasher(tx) # pseudo bip143 prefix hashing
|
|
|
|
|
tx_ser = TxRequestSerializedType()
|
|
|
|
|
elif tx.overwintered:
|
|
|
|
|
hash143 = Zip143() # zip143 transaction hashing
|
|
|
|
|
else:
|
|
|
|
|
hash143 = Bip143() # bip143 transaction hashing
|
|
|
|
@ -130,6 +139,17 @@ async def check_tx_fee(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
else:
|
|
|
|
|
raise SigningError(FailureType.DataError, "Wrong input script type")
|
|
|
|
|
|
|
|
|
|
if coin.decred:
|
|
|
|
|
w_txi = empty_bytearray(8 if i == 0 else 0 + 9 + len(txi.prev_hash))
|
|
|
|
|
if i == 0: # serializing first input => prepend headers
|
|
|
|
|
write_bytes(w_txi, get_tx_header(coin, tx))
|
|
|
|
|
write_tx_input_decred(w_txi, txi)
|
|
|
|
|
tx_ser.serialized_tx = w_txi
|
|
|
|
|
tx_req.serialized = tx_ser
|
|
|
|
|
|
|
|
|
|
if coin.decred:
|
|
|
|
|
hash143.add_output_count(tx)
|
|
|
|
|
|
|
|
|
|
for o in range(tx.outputs_count):
|
|
|
|
|
# STAGE_REQUEST_3_OUTPUT
|
|
|
|
|
txo = await request_tx_output(tx_req, o)
|
|
|
|
@ -143,6 +163,22 @@ async def check_tx_fee(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
elif not await confirm_output(txo, coin):
|
|
|
|
|
raise SigningError(FailureType.ActionCancelled, "Output cancelled")
|
|
|
|
|
|
|
|
|
|
if coin.decred:
|
|
|
|
|
if txo.decred_script_version is not None and txo.decred_script_version != 0:
|
|
|
|
|
raise SigningError(
|
|
|
|
|
FailureType.ActionCancelled,
|
|
|
|
|
"Cannot send to output with script version != 0",
|
|
|
|
|
)
|
|
|
|
|
txo_bin.decred_script_version = txo.decred_script_version
|
|
|
|
|
|
|
|
|
|
w_txo_bin = empty_bytearray(4 + 8 + 2 + 4 + len(txo_bin.script_pubkey))
|
|
|
|
|
if o == 0: # serializing first output => prepend outputs count
|
|
|
|
|
write_varint(w_txo_bin, tx.outputs_count)
|
|
|
|
|
write_tx_output(w_txo_bin, txo_bin)
|
|
|
|
|
tx_ser.serialized_tx = w_txo_bin
|
|
|
|
|
tx_req.serialized = tx_ser
|
|
|
|
|
hash143.set_last_output_bytes(w_txo_bin)
|
|
|
|
|
|
|
|
|
|
write_tx_output(h_first, txo_bin)
|
|
|
|
|
hash143.add_output(txo_bin)
|
|
|
|
|
total_out += txo_bin.amount
|
|
|
|
@ -159,6 +195,9 @@ async def check_tx_fee(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
if not await confirm_total(total_in - change_out, fee, coin):
|
|
|
|
|
raise SigningError(FailureType.ActionCancelled, "Total cancelled")
|
|
|
|
|
|
|
|
|
|
if coin.decred:
|
|
|
|
|
hash143.add_locktime_expiry(tx)
|
|
|
|
|
|
|
|
|
|
return h_first, hash143, segwit, total_in, wallet_path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -183,6 +222,9 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
tx_req.details = TxRequestDetailsType()
|
|
|
|
|
tx_req.serialized = None
|
|
|
|
|
|
|
|
|
|
if coin.decred:
|
|
|
|
|
prefix_hash = hash143.prefix_hash()
|
|
|
|
|
|
|
|
|
|
for i_sign in range(tx.inputs_count):
|
|
|
|
|
progress.advance()
|
|
|
|
|
txi_sign = None
|
|
|
|
@ -234,7 +276,11 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
key_sign = node_derive(root, txi_sign.address_n)
|
|
|
|
|
key_sign_pub = key_sign.public_key()
|
|
|
|
|
hash143_hash = hash143.preimage_hash(
|
|
|
|
|
coin, tx, txi_sign, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin)
|
|
|
|
|
coin,
|
|
|
|
|
tx,
|
|
|
|
|
txi_sign,
|
|
|
|
|
ecdsa_hash_pubkey(key_sign_pub, coin),
|
|
|
|
|
get_hash_type(coin),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# if multisig, check if singing with a key that is included in multisig
|
|
|
|
@ -259,6 +305,70 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
|
|
|
|
|
tx_req.serialized = tx_ser
|
|
|
|
|
|
|
|
|
|
elif coin.decred:
|
|
|
|
|
txi_sign = await request_tx_input(tx_req, i_sign)
|
|
|
|
|
|
|
|
|
|
input_check_wallet_path(txi_sign, wallet_path)
|
|
|
|
|
|
|
|
|
|
key_sign = node_derive(root, txi_sign.address_n)
|
|
|
|
|
key_sign_pub = key_sign.public_key()
|
|
|
|
|
|
|
|
|
|
if txi_sign.script_type == InputScriptType.SPENDMULTISIG:
|
|
|
|
|
prev_pkscript = output_script_multisig(
|
|
|
|
|
multisig_get_pubkeys(txi_sign.multisig), txi_sign.multisig.m
|
|
|
|
|
)
|
|
|
|
|
elif txi_sign.script_type == InputScriptType.SPENDADDRESS:
|
|
|
|
|
prev_pkscript = output_script_p2pkh(
|
|
|
|
|
ecdsa_hash_pubkey(key_sign_pub, coin)
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError("Unknown input script type")
|
|
|
|
|
|
|
|
|
|
h_witness = HashWriter(blake256)
|
|
|
|
|
write_uint32(h_witness, tx.version | DECRED_SERIALIZE_WITNESS_SIGNING)
|
|
|
|
|
write_varint(h_witness, tx.inputs_count)
|
|
|
|
|
|
|
|
|
|
for ii in range(tx.inputs_count):
|
|
|
|
|
if ii == i_sign:
|
|
|
|
|
write_varint(h_witness, len(prev_pkscript))
|
|
|
|
|
write_bytes(h_witness, prev_pkscript)
|
|
|
|
|
else:
|
|
|
|
|
write_varint(h_witness, 0)
|
|
|
|
|
|
|
|
|
|
witness_hash = get_tx_hash(
|
|
|
|
|
h_witness, double=coin.sign_hash_double, reverse=False
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
h_sign = HashWriter(blake256)
|
|
|
|
|
write_uint32(h_sign, DECRED_SIGHASHALL)
|
|
|
|
|
write_bytes(h_sign, prefix_hash)
|
|
|
|
|
write_bytes(h_sign, witness_hash)
|
|
|
|
|
|
|
|
|
|
sig_hash = get_tx_hash(h_sign, double=coin.sign_hash_double)
|
|
|
|
|
signature = ecdsa_sign(key_sign, sig_hash)
|
|
|
|
|
tx_ser.signature_index = i_sign
|
|
|
|
|
tx_ser.signature = signature
|
|
|
|
|
|
|
|
|
|
# serialize input with correct signature
|
|
|
|
|
txi_sign.script_sig = input_derive_script(
|
|
|
|
|
coin, txi_sign, key_sign_pub, signature
|
|
|
|
|
)
|
|
|
|
|
w_txi_sign = empty_bytearray(
|
|
|
|
|
8 + 4 + len(hash143.get_last_output_bytes())
|
|
|
|
|
if i_sign == 0
|
|
|
|
|
else 0 + 16 + 4 + len(txi_sign.script_sig)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if i_sign == 0:
|
|
|
|
|
write_bytes(w_txi_sign, hash143.get_last_output_bytes())
|
|
|
|
|
write_uint32(w_txi_sign, tx.lock_time)
|
|
|
|
|
write_uint32(w_txi_sign, tx.expiry)
|
|
|
|
|
write_varint(w_txi_sign, tx.inputs_count)
|
|
|
|
|
|
|
|
|
|
write_tx_input_decred_witness(w_txi_sign, txi_sign)
|
|
|
|
|
tx_ser.serialized_tx = w_txi_sign
|
|
|
|
|
tx_req.serialized = tx_ser
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
# hash of what we are signing with this input
|
|
|
|
|
h_sign = HashWriter(sha256)
|
|
|
|
@ -292,7 +402,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
)
|
|
|
|
|
elif txi_sign.script_type == InputScriptType.SPENDADDRESS:
|
|
|
|
|
txi_sign.script_sig = output_script_p2pkh(
|
|
|
|
|
ecdsa_hash_pubkey(key_sign_pub)
|
|
|
|
|
ecdsa_hash_pubkey(key_sign_pub, coin)
|
|
|
|
|
)
|
|
|
|
|
if coin.bip115:
|
|
|
|
|
txi_sign.script_sig += script_replay_protection_bip115(
|
|
|
|
@ -355,6 +465,9 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
|
|
|
|
|
tx_req.serialized = tx_ser
|
|
|
|
|
|
|
|
|
|
if coin.decred:
|
|
|
|
|
return await request_tx_finish(tx_req)
|
|
|
|
|
|
|
|
|
|
for o in range(tx.outputs_count):
|
|
|
|
|
progress.advance()
|
|
|
|
|
# STAGE_REQUEST_5_OUTPUT
|
|
|
|
@ -396,7 +509,11 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
key_sign = node_derive(root, txi.address_n)
|
|
|
|
|
key_sign_pub = key_sign.public_key()
|
|
|
|
|
hash143_hash = hash143.preimage_hash(
|
|
|
|
|
coin, tx, txi, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin)
|
|
|
|
|
coin,
|
|
|
|
|
tx,
|
|
|
|
|
txi,
|
|
|
|
|
ecdsa_hash_pubkey(key_sign_pub, coin),
|
|
|
|
|
get_hash_type(coin),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
signature = ecdsa_sign(key_sign, hash143_hash)
|
|
|
|
@ -420,6 +537,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
|
|
|
|
tx_req.serialized = tx_ser
|
|
|
|
|
|
|
|
|
|
write_uint32(tx_ser.serialized_tx, tx.lock_time)
|
|
|
|
|
|
|
|
|
|
if tx.overwintered:
|
|
|
|
|
write_uint32(tx_ser.serialized_tx, tx.expiry) # expiryHeight
|
|
|
|
|
write_varint(tx_ser.serialized_tx, 0) # nJoinSplit
|
|
|
|
@ -435,11 +553,16 @@ async def get_prevtx_output_value(
|
|
|
|
|
# STAGE_REQUEST_2_PREV_META
|
|
|
|
|
tx = await request_tx_meta(tx_req, prev_hash)
|
|
|
|
|
|
|
|
|
|
txh = HashWriter(sha256)
|
|
|
|
|
if coin.decred:
|
|
|
|
|
txh = HashWriter(blake256)
|
|
|
|
|
else:
|
|
|
|
|
txh = HashWriter(sha256)
|
|
|
|
|
|
|
|
|
|
if tx.overwintered:
|
|
|
|
|
write_uint32(txh, tx.version | OVERWINTERED) # nVersion | fOverwintered
|
|
|
|
|
write_uint32(txh, coin.version_group_id) # nVersionGroupId
|
|
|
|
|
elif coin.decred:
|
|
|
|
|
write_uint32(txh, tx.version | DECRED_SERIALIZE_NO_WITNESS)
|
|
|
|
|
else:
|
|
|
|
|
write_uint32(txh, tx.version) # nVersion
|
|
|
|
|
|
|
|
|
@ -448,7 +571,10 @@ async def get_prevtx_output_value(
|
|
|
|
|
for i in range(tx.inputs_cnt):
|
|
|
|
|
# STAGE_REQUEST_2_PREV_INPUT
|
|
|
|
|
txi = await request_tx_input(tx_req, i, prev_hash)
|
|
|
|
|
write_tx_input(txh, txi)
|
|
|
|
|
if coin.decred:
|
|
|
|
|
write_tx_input_decred(txh, txi)
|
|
|
|
|
else:
|
|
|
|
|
write_tx_input(txh, txi)
|
|
|
|
|
|
|
|
|
|
write_varint(txh, tx.outputs_cnt)
|
|
|
|
|
|
|
|
|
@ -458,10 +584,19 @@ async def get_prevtx_output_value(
|
|
|
|
|
write_tx_output(txh, txo_bin)
|
|
|
|
|
if o == prev_index:
|
|
|
|
|
total_out += txo_bin.amount
|
|
|
|
|
if (
|
|
|
|
|
coin.decred
|
|
|
|
|
and txo_bin.decred_script_version is not None
|
|
|
|
|
and txo_bin.decred_script_version != 0
|
|
|
|
|
):
|
|
|
|
|
raise SigningError(
|
|
|
|
|
FailureType.ProcessError,
|
|
|
|
|
"Cannot use utxo that has script_version != 0",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
write_uint32(txh, tx.lock_time)
|
|
|
|
|
|
|
|
|
|
if tx.overwintered:
|
|
|
|
|
if tx.overwintered or coin.decred:
|
|
|
|
|
write_uint32(txh, tx.expiry)
|
|
|
|
|
|
|
|
|
|
ofs = 0
|
|
|
|
@ -626,7 +761,7 @@ def input_derive_script(
|
|
|
|
|
return input_script_p2wsh_in_p2sh(witness_script_hash)
|
|
|
|
|
|
|
|
|
|
# p2wpkh in p2sh
|
|
|
|
|
return input_script_p2wpkh_in_p2sh(ecdsa_hash_pubkey(pubkey))
|
|
|
|
|
return input_script_p2wpkh_in_p2sh(ecdsa_hash_pubkey(pubkey, coin))
|
|
|
|
|
|
|
|
|
|
elif i.script_type == InputScriptType.SPENDWITNESS:
|
|
|
|
|
# native p2wpkh or p2wsh
|
|
|
|
@ -636,7 +771,7 @@ def input_derive_script(
|
|
|
|
|
# p2sh multisig
|
|
|
|
|
signature_index = multisig_pubkey_index(i.multisig, pubkey)
|
|
|
|
|
return input_script_multisig(
|
|
|
|
|
i.multisig, signature, signature_index, get_hash_type(coin)
|
|
|
|
|
i.multisig, signature, signature_index, get_hash_type(coin), coin
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|