mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-21 23:18:13 +00:00
src/apps/wallet: add support for zcash overwinter
This commit is contained in:
parent
4d1b2f0ca5
commit
dfd02821af
@ -167,7 +167,7 @@ COINS = [
|
||||
segwit=False,
|
||||
fork_id=None,
|
||||
force_bip143=False,
|
||||
version_group_id=63210096,
|
||||
version_group_id=0x03c48270,
|
||||
),
|
||||
CoinInfo(
|
||||
coin_name='Zcash Testnet',
|
||||
@ -182,7 +182,7 @@ COINS = [
|
||||
segwit=False,
|
||||
fork_id=None,
|
||||
force_bip143=False,
|
||||
version_group_id=63210096,
|
||||
version_group_id=0x03c48270,
|
||||
),
|
||||
CoinInfo(
|
||||
coin_name='Bgold',
|
||||
|
@ -105,7 +105,7 @@ def sanitize_sign_tx(tx: SignTx) -> SignTx:
|
||||
tx.inputs_count = tx.inputs_count if tx.inputs_count is not None else 0
|
||||
tx.outputs_count = tx.outputs_count if tx.outputs_count is not None else 0
|
||||
tx.coin_name = tx.coin_name if tx.coin_name is not None else 'Bitcoin'
|
||||
tx.decred_expiry = tx.decred_expiry if tx.decred_expiry is not None else 0
|
||||
tx.expiry = tx.expiry if tx.expiry is not None else 0
|
||||
tx.overwintered = tx.overwintered if tx.overwintered is not None else False
|
||||
return tx
|
||||
|
||||
@ -116,7 +116,7 @@ def sanitize_tx_meta(tx: TransactionType) -> TransactionType:
|
||||
tx.inputs_cnt = tx.inputs_cnt if tx.inputs_cnt is not None else 0
|
||||
tx.outputs_cnt = tx.outputs_cnt if tx.outputs_cnt is not None else 0
|
||||
tx.extra_data_len = tx.extra_data_len if tx.extra_data_len is not None else 0
|
||||
tx.decred_expiry = tx.decred_expiry if tx.decred_expiry is not None else 0
|
||||
tx.expiry = tx.expiry if tx.expiry is not None else 0
|
||||
tx.overwintered = tx.overwintered if tx.overwintered is not None else False
|
||||
return tx
|
||||
|
||||
|
@ -3,6 +3,7 @@ from trezor.messages.SignTx import SignTx
|
||||
from trezor.messages import InputScriptType, FailureType
|
||||
from trezor.utils import HashWriter
|
||||
|
||||
from apps.common.coininfo import CoinInfo
|
||||
from apps.wallet.sign_tx.writers import *
|
||||
from apps.wallet.sign_tx.scripts import output_script_p2pkh, output_script_multisig
|
||||
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
|
||||
@ -38,10 +39,15 @@ class Bip143:
|
||||
def get_outputs_hash(self) -> bytes:
|
||||
return get_tx_hash(self.h_outputs, True)
|
||||
|
||||
def preimage_hash(self, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int) -> bytes:
|
||||
def preimage_hash(self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int) -> bytes:
|
||||
h_preimage = HashWriter(sha256)
|
||||
|
||||
write_uint32(h_preimage, tx.version) # nVersion
|
||||
if tx.overwintered:
|
||||
write_uint32(h_preimage, tx.version | 0x80000000) # nVersion | fOverwintered
|
||||
write_uint32(h_preimage, coin.version_group_id) # nVersionGroupId
|
||||
else:
|
||||
write_uint32(h_preimage, tx.version) # nVersion
|
||||
|
||||
write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # hashPrevouts
|
||||
write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # hashSequence
|
||||
write_bytes_rev(h_preimage, txi.prev_hash) # outpoint
|
||||
@ -56,6 +62,8 @@ class Bip143:
|
||||
|
||||
write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # hashOutputs
|
||||
write_uint32(h_preimage, tx.lock_time) # nLockTime
|
||||
if tx.overwintered:
|
||||
write_uint32(h_preimage, tx.expiry) # expiryHeight
|
||||
write_uint32(h_preimage, sighash) # nHashType
|
||||
|
||||
return get_tx_hash(h_preimage, True)
|
||||
|
@ -97,7 +97,7 @@ async def check_tx_fee(tx: SignTx, root: bip32.HDNode):
|
||||
|
||||
elif txi.script_type in (InputScriptType.SPENDADDRESS,
|
||||
InputScriptType.SPENDMULTISIG):
|
||||
if coin.force_bip143:
|
||||
if coin.force_bip143 or tx.overwintered:
|
||||
if not txi.amount:
|
||||
raise SigningError(FailureType.DataError,
|
||||
'BIP 143 input without amount')
|
||||
@ -107,7 +107,7 @@ async def check_tx_fee(tx: SignTx, root: bip32.HDNode):
|
||||
else:
|
||||
segwit[i] = False
|
||||
total_in += await get_prevtx_output_value(
|
||||
tx_req, txi.prev_hash, txi.prev_index)
|
||||
coin, tx_req, txi.prev_hash, txi.prev_index)
|
||||
|
||||
else:
|
||||
raise SigningError(FailureType.DataError,
|
||||
@ -194,12 +194,12 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
||||
w_txi = bytearray_with_cap(
|
||||
7 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4)
|
||||
if i_sign == 0: # serializing first input => prepend headers
|
||||
write_bytes(w_txi, get_tx_header(tx, True))
|
||||
write_bytes(w_txi, get_tx_header(coin, tx, True))
|
||||
write_tx_input(w_txi, txi_sign)
|
||||
tx_ser.serialized_tx = w_txi
|
||||
tx_req.serialized = tx_ser
|
||||
|
||||
elif coin.force_bip143:
|
||||
elif coin.force_bip143 or tx.overwintered:
|
||||
# STAGE_REQUEST_SEGWIT_INPUT
|
||||
txi_sign = await request_tx_input(tx_req, i_sign)
|
||||
input_check_wallet_path(txi_sign, wallet_path)
|
||||
@ -214,7 +214,7 @@ 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()
|
||||
bip143_hash = bip143.preimage_hash(
|
||||
tx, txi_sign, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin))
|
||||
coin, tx, txi_sign, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin))
|
||||
|
||||
# if multisig, check if singing with a key that is included in multisig
|
||||
if txi_sign.multisig:
|
||||
@ -230,7 +230,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
||||
w_txi_sign = bytearray_with_cap(
|
||||
5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4)
|
||||
if i_sign == 0: # serializing first input => prepend headers
|
||||
write_bytes(w_txi_sign, get_tx_header(tx))
|
||||
write_bytes(w_txi_sign, get_tx_header(coin, tx))
|
||||
write_tx_input(w_txi_sign, txi_sign)
|
||||
tx_ser.serialized_tx = w_txi_sign
|
||||
|
||||
@ -242,7 +242,12 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
||||
# same as h_first, checked before signing the digest
|
||||
h_second = HashWriter(sha256)
|
||||
|
||||
write_uint32(h_sign, tx.version)
|
||||
if tx.overwintered:
|
||||
write_uint32(h_sign, tx.version | 0x80000000) # nVersion | fOverwintered
|
||||
write_uint32(h_sign, coin.version_group_id) # nVersionGroupId
|
||||
else:
|
||||
write_uint32(h_sign, tx.version) # nVersion
|
||||
|
||||
write_varint(h_sign, tx.inputs_count)
|
||||
|
||||
for i in range(tx.inputs_count):
|
||||
@ -281,6 +286,8 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
||||
write_tx_output(h_sign, txo_bin)
|
||||
|
||||
write_uint32(h_sign, tx.lock_time)
|
||||
if tx.overwintered:
|
||||
write_uint32(h_sign, tx.expiry)
|
||||
|
||||
write_uint32(h_sign, get_hash_type(coin))
|
||||
|
||||
@ -304,7 +311,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
||||
w_txi_sign = bytearray_with_cap(
|
||||
5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4)
|
||||
if i_sign == 0: # serializing first input => prepend headers
|
||||
write_bytes(w_txi_sign, get_tx_header(tx))
|
||||
write_bytes(w_txi_sign, get_tx_header(coin, tx))
|
||||
write_tx_input(w_txi_sign, txi_sign)
|
||||
tx_ser.serialized_tx = w_txi_sign
|
||||
|
||||
@ -349,7 +356,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
||||
key_sign = node_derive(root, txi.address_n)
|
||||
key_sign_pub = key_sign.public_key()
|
||||
bip143_hash = bip143.preimage_hash(
|
||||
tx, txi, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin))
|
||||
coin, tx, txi, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin))
|
||||
|
||||
signature = ecdsa_sign(key_sign, bip143_hash)
|
||||
if txi.multisig:
|
||||
@ -370,11 +377,13 @@ 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)
|
||||
|
||||
await request_tx_finish(tx_req)
|
||||
|
||||
|
||||
async def get_prevtx_output_value(tx_req: TxRequest, prev_hash: bytes, prev_index: int) -> int:
|
||||
async def get_prevtx_output_value(coin: CoinInfo, tx_req: TxRequest, prev_hash: bytes, prev_index: int) -> int:
|
||||
total_out = 0 # sum of output amounts
|
||||
|
||||
# STAGE_REQUEST_2_PREV_META
|
||||
@ -382,7 +391,12 @@ async def get_prevtx_output_value(tx_req: TxRequest, prev_hash: bytes, prev_inde
|
||||
|
||||
txh = HashWriter(sha256)
|
||||
|
||||
write_uint32(txh, tx.version)
|
||||
if tx.overwintered:
|
||||
write_uint32(txh, tx.version | 0x80000000) # nVersion | fOverwintered
|
||||
write_uint32(txh, coin.version_group_id) # nVersionGroupId
|
||||
else:
|
||||
write_uint32(txh, tx.version) # nVersion
|
||||
|
||||
write_varint(txh, tx.inputs_cnt)
|
||||
|
||||
for i in range(tx.inputs_cnt):
|
||||
@ -428,9 +442,13 @@ def get_hash_type(coin: CoinInfo) -> int:
|
||||
return hashtype
|
||||
|
||||
|
||||
def get_tx_header(tx: SignTx, segwit: bool = False):
|
||||
def get_tx_header(coin: CoinInfo, tx: SignTx, segwit: bool = False):
|
||||
w_txi = bytearray()
|
||||
write_uint32(w_txi, tx.version)
|
||||
if tx.overwintered:
|
||||
write_uint32(w_txi, tx.version | 0x80000000) # nVersion | fOverwintered
|
||||
write_uint32(w_txi, coin.version_group_id) # nVersionGroupId
|
||||
else:
|
||||
write_uint32(w_txi, tx.version) # nVersion
|
||||
if segwit:
|
||||
write_varint(w_txi, 0x00) # segwit witness marker
|
||||
write_varint(w_txi, 0x01) # segwit witness flag
|
||||
|
@ -10,7 +10,7 @@ class SignTx(p.MessageType):
|
||||
3: ('coin_name', p.UnicodeType, 0), # default='Bitcoin'
|
||||
4: ('version', p.UVarintType, 0), # default=1
|
||||
5: ('lock_time', p.UVarintType, 0), # default=0
|
||||
6: ('decred_expiry', p.UVarintType, 0),
|
||||
6: ('expiry', p.UVarintType, 0),
|
||||
7: ('overwintered', p.BoolType, 0),
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ class SignTx(p.MessageType):
|
||||
coin_name: str = None,
|
||||
version: int = None,
|
||||
lock_time: int = None,
|
||||
decred_expiry: int = None,
|
||||
expiry: int = None,
|
||||
overwintered: bool = None
|
||||
) -> None:
|
||||
self.outputs_count = outputs_count
|
||||
@ -29,5 +29,5 @@ class SignTx(p.MessageType):
|
||||
self.coin_name = coin_name
|
||||
self.version = version
|
||||
self.lock_time = lock_time
|
||||
self.decred_expiry = decred_expiry
|
||||
self.expiry = expiry
|
||||
self.overwintered = overwintered
|
||||
|
@ -19,7 +19,7 @@ class SimpleSignTx(p.MessageType):
|
||||
4: ('coin_name', p.UnicodeType, 0), # default='Bitcoin'
|
||||
5: ('version', p.UVarintType, 0), # default=1
|
||||
6: ('lock_time', p.UVarintType, 0), # default=0
|
||||
7: ('decred_expiry', p.UVarintType, 0),
|
||||
7: ('expiry', p.UVarintType, 0),
|
||||
8: ('overwintered', p.BoolType, 0),
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ class SimpleSignTx(p.MessageType):
|
||||
coin_name: str = None,
|
||||
version: int = None,
|
||||
lock_time: int = None,
|
||||
decred_expiry: int = None,
|
||||
expiry: int = None,
|
||||
overwintered: bool = None
|
||||
) -> None:
|
||||
self.inputs = inputs if inputs is not None else []
|
||||
@ -40,5 +40,5 @@ class SimpleSignTx(p.MessageType):
|
||||
self.coin_name = coin_name
|
||||
self.version = version
|
||||
self.lock_time = lock_time
|
||||
self.decred_expiry = decred_expiry
|
||||
self.expiry = expiry
|
||||
self.overwintered = overwintered
|
||||
|
@ -21,7 +21,7 @@ class TransactionType(p.MessageType):
|
||||
7: ('outputs_cnt', p.UVarintType, 0),
|
||||
8: ('extra_data', p.BytesType, 0),
|
||||
9: ('extra_data_len', p.UVarintType, 0),
|
||||
10: ('decred_expiry', p.UVarintType, 0),
|
||||
10: ('expiry', p.UVarintType, 0),
|
||||
11: ('overwintered', p.BoolType, 0),
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ class TransactionType(p.MessageType):
|
||||
outputs_cnt: int = None,
|
||||
extra_data: bytes = None,
|
||||
extra_data_len: int = None,
|
||||
decred_expiry: int = None,
|
||||
expiry: int = None,
|
||||
overwintered: bool = None
|
||||
) -> None:
|
||||
self.version = version
|
||||
@ -48,5 +48,5 @@ class TransactionType(p.MessageType):
|
||||
self.outputs_cnt = outputs_cnt
|
||||
self.extra_data = extra_data
|
||||
self.extra_data_len = extra_data_len
|
||||
self.decred_expiry = decred_expiry
|
||||
self.expiry = expiry
|
||||
self.overwintered = overwintered
|
||||
|
@ -29,10 +29,11 @@ for c in coins:
|
||||
name = 'bitcoin_testnet'
|
||||
data = json.load(open('../../vendor/trezor-common/defs/coins/%s.json' % name, 'r'))
|
||||
for n in fields:
|
||||
if n == 'xpub_magic':
|
||||
print(' %s=0x%08x,' % (n, data[n]))
|
||||
if n in ['xpub_magic', 'version_group_id']:
|
||||
v = '0x%08x' % data[n] if data[n] is not None else 'None'
|
||||
else:
|
||||
print(' %s=%s,' % (n, repr(data[n])))
|
||||
v = repr(data[n])
|
||||
print(' %s=%s,' % (n, v))
|
||||
print(' ),')
|
||||
|
||||
print(']')
|
||||
|
2
vendor/trezor-common
vendored
2
vendor/trezor-common
vendored
@ -1 +1 @@
|
||||
Subproject commit 0f7118bb3d27c3c51a89c776c1b083db91f50541
|
||||
Subproject commit 018eebac7e64ed082486d746d78d279fe815c65d
|
Loading…
Reference in New Issue
Block a user