mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 15:38:11 +00:00
src/apps/wallet/sign_tx: re-enable Decred
This commit is contained in:
parent
de12ad705c
commit
2277a9c754
@ -1,6 +1,6 @@
|
||||
# generated from coininfo.py.mako
|
||||
# do not edit manually!
|
||||
from trezor.crypto.base58 import groestl512d_32, sha256d_32
|
||||
from trezor.crypto.base58 import blake256_32, groestl512d_32, sha256d_32
|
||||
|
||||
|
||||
class CoinInfo:
|
||||
@ -48,6 +48,9 @@ class CoinInfo:
|
||||
if curve_name == "secp256k1-groestl":
|
||||
self.b58_hash = groestl512d_32
|
||||
self.sign_hash_double = False
|
||||
elif curve_name == "secp256k1-decred":
|
||||
self.b58_hash = blake256_32
|
||||
self.sign_hash_double = False
|
||||
else:
|
||||
self.b58_hash = sha256d_32
|
||||
self.sign_hash_double = True
|
||||
|
@ -1,6 +1,6 @@
|
||||
# generated from coininfo.py.mako
|
||||
# do not edit manually!
|
||||
from trezor.crypto.base58 import groestl512d_32, sha256d_32
|
||||
from trezor.crypto.base58 import blake256_32, groestl512d_32, sha256d_32
|
||||
|
||||
|
||||
class CoinInfo:
|
||||
@ -48,6 +48,9 @@ class CoinInfo:
|
||||
if curve_name == "secp256k1-groestl":
|
||||
self.b58_hash = groestl512d_32
|
||||
self.sign_hash_double = False
|
||||
elif curve_name == "secp256k1-decred":
|
||||
self.b58_hash = blake256_32
|
||||
self.sign_hash_double = False
|
||||
else:
|
||||
self.b58_hash = sha256d_32
|
||||
self.sign_hash_double = True
|
||||
|
@ -1,13 +1,16 @@
|
||||
from ubinascii import hexlify
|
||||
|
||||
from trezor.crypto.hashlib import sha256
|
||||
from trezor.crypto.hashlib import blake256, sha256
|
||||
from trezor.utils import HashWriter
|
||||
|
||||
from apps.wallet.sign_tx.signing import write_varint
|
||||
|
||||
|
||||
def message_digest(coin, message):
|
||||
h = HashWriter(sha256)
|
||||
if coin.decred:
|
||||
h = HashWriter(blake256)
|
||||
else:
|
||||
h = HashWriter(sha256)
|
||||
write_varint(h, len(coin.signed_message_header))
|
||||
h.extend(coin.signed_message_header)
|
||||
write_varint(h, len(message))
|
||||
|
@ -14,6 +14,13 @@ def write_uint8(w: bytearray, n: int) -> int:
|
||||
return 1
|
||||
|
||||
|
||||
def write_uint16_le(w: bytearray, n: int) -> int:
|
||||
assert 0 <= n <= 0xFFFF
|
||||
w.append(n & 0xFF)
|
||||
w.append((n >> 8) & 0xFF)
|
||||
return 2
|
||||
|
||||
|
||||
def write_uint32_le(w: bytearray, n: int) -> int:
|
||||
assert 0 <= n <= 0xFFFFFFFF
|
||||
w.append(n & 0xFF)
|
||||
|
@ -9,6 +9,7 @@ from apps.common import address_type
|
||||
from apps.common.coininfo import CoinInfo
|
||||
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys, multisig_pubkey_index
|
||||
from apps.wallet.sign_tx.scripts import (
|
||||
blake256_ripemd160_digest,
|
||||
output_script_multisig,
|
||||
output_script_native_p2wpkh_or_p2wsh,
|
||||
sha256_ripemd160_digest,
|
||||
@ -65,7 +66,7 @@ def get_address(
|
||||
return address_multisig_p2wsh(pubkeys, multisig.m, coin.bech32_prefix)
|
||||
|
||||
# native p2wpkh
|
||||
return address_p2wpkh(node.public_key(), coin.bech32_prefix)
|
||||
return address_p2wpkh(node.public_key(), coin)
|
||||
|
||||
elif (
|
||||
script_type == InputScriptType.SPENDP2SHWITNESS
|
||||
@ -92,7 +93,10 @@ def address_multisig_p2sh(pubkeys: bytes, m: int, coin: CoinInfo):
|
||||
FailureType.ProcessError, "Multisig not enabled on this coin"
|
||||
)
|
||||
redeem_script = output_script_multisig(pubkeys, m)
|
||||
redeem_script_hash = sha256_ripemd160_digest(redeem_script)
|
||||
if coin.decred:
|
||||
redeem_script_hash = blake256_ripemd160_digest(redeem_script)
|
||||
else:
|
||||
redeem_script_hash = sha256_ripemd160_digest(redeem_script)
|
||||
return address_p2sh(redeem_script_hash, coin)
|
||||
|
||||
|
||||
@ -127,7 +131,7 @@ def address_p2sh(redeem_script_hash: bytes, coin: CoinInfo) -> str:
|
||||
|
||||
|
||||
def address_p2wpkh_in_p2sh(pubkey: bytes, coin: CoinInfo) -> str:
|
||||
pubkey_hash = ecdsa_hash_pubkey(pubkey)
|
||||
pubkey_hash = ecdsa_hash_pubkey(pubkey, coin)
|
||||
redeem_script = output_script_native_p2wpkh_or_p2wsh(pubkey_hash)
|
||||
redeem_script_hash = sha256_ripemd160_digest(redeem_script)
|
||||
return address_p2sh(redeem_script_hash, coin)
|
||||
@ -139,9 +143,9 @@ def address_p2wsh_in_p2sh(witness_script_hash: bytes, coin: CoinInfo) -> str:
|
||||
return address_p2sh(redeem_script_hash, coin)
|
||||
|
||||
|
||||
def address_p2wpkh(pubkey: bytes, hrp: str) -> str:
|
||||
pubkeyhash = ecdsa_hash_pubkey(pubkey)
|
||||
address = bech32.encode(hrp, _BECH32_WITVER, pubkeyhash)
|
||||
def address_p2wpkh(pubkey: bytes, coin: CoinInfo) -> str:
|
||||
pubkeyhash = ecdsa_hash_pubkey(pubkey, coin)
|
||||
address = bech32.encode(coin.bech32_prefix, _BECH32_WITVER, pubkeyhash)
|
||||
if address is None:
|
||||
raise AddressError(FailureType.ProcessError, "Invalid address")
|
||||
return address
|
||||
@ -173,13 +177,17 @@ def address_to_cashaddr(address: str, coin: CoinInfo) -> str:
|
||||
return cashaddr.encode(coin.cashaddr_prefix, version, data)
|
||||
|
||||
|
||||
def ecdsa_hash_pubkey(pubkey: bytes) -> bytes:
|
||||
def ecdsa_hash_pubkey(pubkey: bytes, coin: CoinInfo) -> bytes:
|
||||
if pubkey[0] == 0x04:
|
||||
ensure(len(pubkey) == 65) # uncompressed format
|
||||
elif pubkey[0] == 0x00:
|
||||
ensure(len(pubkey) == 1) # point at infinity
|
||||
else:
|
||||
ensure(len(pubkey) == 33) # compresssed format
|
||||
|
||||
if coin.decred:
|
||||
return blake256_ripemd160_digest(pubkey)
|
||||
|
||||
h = sha256(pubkey).digest()
|
||||
h = ripemd160(h).digest()
|
||||
return h
|
||||
|
65
src/apps/wallet/sign_tx/decred_prefix_hasher.py
Normal file
65
src/apps/wallet/sign_tx/decred_prefix_hasher.py
Normal file
@ -0,0 +1,65 @@
|
||||
from micropython import const
|
||||
|
||||
from trezor.crypto.hashlib import blake256
|
||||
from trezor.messages.SignTx import SignTx
|
||||
from trezor.messages.TxInputType import TxInputType
|
||||
from trezor.messages.TxOutputBinType import TxOutputBinType
|
||||
from trezor.utils import HashWriter
|
||||
|
||||
from apps.wallet.sign_tx.writers import (
|
||||
write_tx_input_decred,
|
||||
write_tx_output,
|
||||
write_uint32,
|
||||
write_varint,
|
||||
)
|
||||
|
||||
DECRED_SERIALIZE_FULL = const(0 << 16)
|
||||
DECRED_SERIALIZE_NO_WITNESS = const(1 << 16)
|
||||
DECRED_SERIALIZE_WITNESS_SIGNING = const(3 << 16)
|
||||
|
||||
DECRED_SIGHASHALL = const(1)
|
||||
|
||||
|
||||
class DecredPrefixHasher:
|
||||
"""
|
||||
While Decred does not have the exact same implementation as bip143/zip143,
|
||||
the semantics for using the prefix hash of transactions are close enough
|
||||
that a pseudo-bip143 class can be used to store the prefix hash during the
|
||||
check_fee stage of transaction signature to then reuse it at the sign_tx
|
||||
stage without having to request the inputs again.
|
||||
"""
|
||||
|
||||
def __init__(self, tx: SignTx):
|
||||
self.h_prefix = HashWriter(blake256)
|
||||
self.last_output_bytes = None
|
||||
write_uint32(self.h_prefix, tx.version | DECRED_SERIALIZE_NO_WITNESS)
|
||||
write_varint(self.h_prefix, tx.inputs_count)
|
||||
|
||||
def add_prevouts(self, txi: TxInputType):
|
||||
write_tx_input_decred(self.h_prefix, txi)
|
||||
|
||||
def add_sequence(self, txi: TxInputType):
|
||||
pass
|
||||
|
||||
def add_output_count(self, tx: SignTx):
|
||||
write_varint(self.h_prefix, tx.outputs_count)
|
||||
|
||||
def add_output(self, txo_bin: TxOutputBinType):
|
||||
write_tx_output(self.h_prefix, txo_bin)
|
||||
|
||||
def set_last_output_bytes(self, w_txo_bin: bytearray):
|
||||
"""
|
||||
This is required because the last serialized output obtained in
|
||||
`check_fee` will only be sent to the client in `sign_tx`
|
||||
"""
|
||||
self.last_output_bytes = w_txo_bin
|
||||
|
||||
def get_last_output_bytes(self):
|
||||
return self.last_output_bytes
|
||||
|
||||
def add_locktime_expiry(self, tx: SignTx):
|
||||
write_uint32(self.h_prefix, tx.lock_time)
|
||||
write_uint32(self.h_prefix, tx.expiry)
|
||||
|
||||
def prefix_hash(self) -> bytes:
|
||||
return self.h_prefix.get_digest()
|
@ -1,6 +1,7 @@
|
||||
from trezor.crypto.hashlib import ripemd160, sha256
|
||||
from trezor.crypto.hashlib import blake256, ripemd160, sha256
|
||||
from trezor.messages.MultisigRedeemScriptType import MultisigRedeemScriptType
|
||||
|
||||
from apps.common.coininfo import CoinInfo
|
||||
from apps.common.writers import empty_bytearray
|
||||
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
|
||||
from apps.wallet.sign_tx.writers import (
|
||||
@ -192,6 +193,7 @@ def input_script_multisig(
|
||||
signature: bytes,
|
||||
signature_index: int,
|
||||
sighash: int,
|
||||
coin: CoinInfo,
|
||||
):
|
||||
signatures = multisig.signatures # other signatures
|
||||
if len(signatures[signature_index]) > 0:
|
||||
@ -199,10 +201,12 @@ def input_script_multisig(
|
||||
signatures[signature_index] = signature # our signature
|
||||
|
||||
w = bytearray()
|
||||
# Starts with OP_FALSE because of an old OP_CHECKMULTISIG bug, which
|
||||
# consumes one additional item on the stack:
|
||||
# https://bitcoin.org/en/developer-guide#standard-transactions
|
||||
w.append(0x00)
|
||||
|
||||
if not coin.decred:
|
||||
# Starts with OP_FALSE because of an old OP_CHECKMULTISIG bug, which
|
||||
# consumes one additional item on the stack:
|
||||
# https://bitcoin.org/en/developer-guide#standard-transactions
|
||||
w.append(0x00)
|
||||
|
||||
for s in signatures:
|
||||
if len(s):
|
||||
@ -267,3 +271,9 @@ def sha256_ripemd160_digest(b: bytes) -> bytes:
|
||||
h = sha256(b).digest()
|
||||
h = ripemd160(h).digest()
|
||||
return h
|
||||
|
||||
|
||||
def blake256_ripemd160_digest(b: bytes) -> bytes:
|
||||
h = blake256(b).digest()
|
||||
h = ripemd160(h).digest()
|
||||
return h
|
||||
|
@ -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:
|
||||
|
@ -5,10 +5,13 @@ from trezor.messages.TxOutputBinType import TxOutputBinType
|
||||
from apps.common.writers import (
|
||||
write_bytes,
|
||||
write_bytes_reversed,
|
||||
write_uint8,
|
||||
write_uint16_le,
|
||||
write_uint32_le,
|
||||
write_uint64_le,
|
||||
)
|
||||
|
||||
write_uint16 = write_uint16_le
|
||||
write_uint32 = write_uint32_le
|
||||
write_uint64 = write_uint64_le
|
||||
|
||||
@ -32,8 +35,25 @@ def write_tx_input_check(w, i: TxInputType):
|
||||
write_uint32(w, i.amount or 0)
|
||||
|
||||
|
||||
def write_tx_input_decred(w, i: TxInputType):
|
||||
write_bytes_reversed(w, i.prev_hash)
|
||||
write_uint32(w, i.prev_index or 0)
|
||||
write_uint8(w, i.decred_tree or 0)
|
||||
write_uint32(w, i.sequence)
|
||||
|
||||
|
||||
def write_tx_input_decred_witness(w, i: TxInputType):
|
||||
write_uint64(w, i.amount or 0)
|
||||
write_uint32(w, 0) # block height fraud proof
|
||||
write_uint32(w, 0xFFFFFFFF) # block index fraud proof
|
||||
write_varint(w, len(i.script_sig))
|
||||
write_bytes(w, i.script_sig)
|
||||
|
||||
|
||||
def write_tx_output(w, o: TxOutputBinType):
|
||||
write_uint64(w, o.amount)
|
||||
if o.decred_script_version is not None:
|
||||
write_uint16(w, o.decred_script_version)
|
||||
write_varint(w, len(o.script_pubkey))
|
||||
write_bytes(w, o.script_pubkey)
|
||||
|
||||
|
@ -51,7 +51,7 @@ async def verify_message(ctx, msg):
|
||||
elif script_type == SPENDP2SHWITNESS:
|
||||
addr = address_p2wpkh_in_p2sh(pubkey, coin)
|
||||
elif script_type == SPENDWITNESS:
|
||||
addr = address_p2wpkh(pubkey, coin.bech32_prefix)
|
||||
addr = address_p2wpkh(pubkey, coin)
|
||||
else:
|
||||
raise wire.ProcessError("Invalid signature")
|
||||
|
||||
|
@ -71,6 +71,12 @@ def groestl512d_32(data: bytes) -> bytes:
|
||||
return groestl512(groestl512(data).digest()).digest()[:4]
|
||||
|
||||
|
||||
def blake256_32(data: bytes) -> bytes:
|
||||
from .hashlib import blake256
|
||||
|
||||
return blake256(blake256(data).digest()).digest()[:4]
|
||||
|
||||
|
||||
def encode_check(data: bytes, digestfunc=sha256d_32) -> str:
|
||||
"""
|
||||
Convert bytes to base58 encoded string, append checksum.
|
||||
|
@ -41,7 +41,7 @@ class TestAddress(unittest.TestCase):
|
||||
coin = coins.by_name('Testnet')
|
||||
address = address_p2wpkh(
|
||||
unhexlify('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'),
|
||||
coin.bech32_prefix
|
||||
coin
|
||||
)
|
||||
self.assertEqual(address, 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx')
|
||||
|
||||
|
@ -60,15 +60,15 @@ class TestAddressGRS(unittest.TestCase):
|
||||
root = bip32.from_seed(seed, coin.curve_name)
|
||||
|
||||
node = node_derive(root, [84 | 0x80000000, 17 | 0x80000000, 0 | 0x80000000, 1, 0])
|
||||
address = address_p2wpkh(node.public_key(), coin.bech32_prefix)
|
||||
address = address_p2wpkh(node.public_key(), coin)
|
||||
self.assertEqual(address, 'grs1qzfpwn55tvkxcw0xwfa0g8k2gtlzlgkcq3z000e')
|
||||
|
||||
node = node_derive(root, [84 | 0x80000000, 17 | 0x80000000, 0 | 0x80000000, 1, 1])
|
||||
address = address_p2wpkh(node.public_key(), coin.bech32_prefix)
|
||||
address = address_p2wpkh(node.public_key(), coin)
|
||||
self.assertEqual(address, 'grs1qxsgwl66tx7tsuwfm4kk5c5dh6tlfpr4qjqg6gg')
|
||||
|
||||
node = node_derive(root, [84 | 0x80000000, 17 | 0x80000000, 0 | 0x80000000, 0, 0])
|
||||
address = address_p2wpkh(node.public_key(), coin.bech32_prefix)
|
||||
address = address_p2wpkh(node.public_key(), coin)
|
||||
self.assertEqual(address, 'grs1qw4teyraux2s77nhjdwh9ar8rl9dt7zww8r6lne')
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user