src/apps/wallet/sign_tx: refactor Zcash, add WIP ZIP243; use ensure instead of assert where possible

pull/25/head
Pavol Rusnak 6 years ago
parent b2327c37b7
commit e16a8fc8c9
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D

@ -6,6 +6,7 @@ import ustruct as struct
from micropython import const
from trezor import log
from trezor.utils import ensure
_CBOR_TYPE_MASK = const(0xE0)
_CBOR_INFO_BITS = const(0x1F)
@ -167,7 +168,7 @@ class Raw:
class IndefiniteLengthArray:
def __init__(self, array):
assert isinstance(array, list)
ensure(isinstance(array, list))
self.array = array

@ -22,7 +22,6 @@ class CoinInfo:
segwit: bool,
fork_id: int,
force_bip143: bool,
version_group_id: int,
bip115: bool,
decred: bool,
curve_name: str,
@ -42,7 +41,6 @@ class CoinInfo:
self.segwit = segwit
self.fork_id = fork_id
self.force_bip143 = force_bip143
self.version_group_id = version_group_id
self.bip115 = bip115
self.decred = decred
self.curve_name = curve_name
@ -82,7 +80,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -103,7 +100,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -124,7 +120,6 @@ COINS = [
segwit=False,
fork_id=0,
force_bip143=True,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -145,7 +140,6 @@ COINS = [
segwit=False,
fork_id=0,
force_bip143=True,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -166,7 +160,6 @@ COINS = [
segwit=True,
fork_id=79,
force_bip143=True,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -187,7 +180,6 @@ COINS = [
segwit=True,
fork_id=79,
force_bip143=True,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -208,7 +200,6 @@ COINS = [
segwit=False,
fork_id=42,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -229,7 +220,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -250,7 +240,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -271,7 +260,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=True,
curve_name='secp256k1-decred',
@ -292,7 +280,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=True,
curve_name='secp256k1-decred',
@ -313,7 +300,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -334,7 +320,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -355,7 +340,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -376,7 +360,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -397,7 +380,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -418,7 +400,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -439,7 +420,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1-groestl',
@ -460,7 +440,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1-groestl',
@ -481,7 +460,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=0x02e7d970,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -502,7 +480,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -523,7 +500,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -544,7 +520,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -565,7 +540,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -586,7 +560,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -607,7 +580,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -628,7 +600,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -649,7 +620,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1-smart',
@ -670,7 +640,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1-smart',
@ -691,7 +660,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -712,7 +680,6 @@ COINS = [
segwit=True,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -733,7 +700,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=0x03c48270,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -754,7 +720,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=0x03c48270,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -775,7 +740,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -796,7 +760,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=False,
decred=False,
curve_name='secp256k1',
@ -817,7 +780,6 @@ COINS = [
segwit=False,
fork_id=None,
force_bip143=False,
version_group_id=None,
bip115=True,
decred=False,
curve_name='secp256k1',

@ -22,7 +22,6 @@ class CoinInfo:
segwit: bool,
fork_id: int,
force_bip143: bool,
version_group_id: int,
bip115: bool,
decred: bool,
curve_name: str,
@ -42,7 +41,6 @@ class CoinInfo:
self.segwit = segwit
self.fork_id = fork_id
self.force_bip143 = force_bip143
self.version_group_id = version_group_id
self.bip115 = bip115
self.decred = decred
self.curve_name = curve_name
@ -88,7 +86,6 @@ ATTRIBUTES = (
("segwit", bool),
("fork_id", black_repr),
("force_bip143", bool),
("version_group_id", hexfmt),
("bip115", bool),
("decred", bool),
("curve_name", lambda r: repr(r.replace("_", "-"))),

@ -1,3 +1,6 @@
from trezor.utils import ensure
def empty_bytearray(preallocate: int) -> bytearray:
"""
Returns bytearray that won't allocate for at least `preallocate` bytes.
@ -9,20 +12,20 @@ def empty_bytearray(preallocate: int) -> bytearray:
def write_uint8(w: bytearray, n: int) -> int:
assert 0 <= n <= 0xFF
ensure(0 <= n <= 0xFF)
w.append(n)
return 1
def write_uint16_le(w: bytearray, n: int) -> int:
assert 0 <= n <= 0xFFFF
ensure(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
ensure(0 <= n <= 0xFFFFFFFF)
w.append(n & 0xFF)
w.append((n >> 8) & 0xFF)
w.append((n >> 16) & 0xFF)
@ -31,7 +34,7 @@ def write_uint32_le(w: bytearray, n: int) -> int:
def write_uint32_be(w: bytearray, n: int) -> int:
assert 0 <= n <= 0xFFFFFFFF
ensure(0 <= n <= 0xFFFFFFFF)
w.append((n >> 24) & 0xFF)
w.append((n >> 16) & 0xFF)
w.append((n >> 8) & 0xFF)
@ -40,7 +43,7 @@ def write_uint32_be(w: bytearray, n: int) -> int:
def write_uint64_le(w: bytearray, n: int) -> int:
assert 0 <= n <= 0xFFFFFFFFFFFFFFFF
ensure(0 <= n <= 0xFFFFFFFFFFFFFFFF)
w.append(n & 0xFF)
w.append((n >> 8) & 0xFF)
w.append((n >> 16) & 0xFF)
@ -53,7 +56,7 @@ def write_uint64_le(w: bytearray, n: int) -> int:
def write_uint64_be(w: bytearray, n: int) -> int:
assert 0 <= n <= 0xFFFFFFFFFFFFFFFF
ensure(0 <= n <= 0xFFFFFFFFFFFFFFFF)
w.append((n >> 56) & 0xFF)
w.append((n >> 48) & 0xFF)
w.append((n >> 40) & 0xFF)

@ -3,7 +3,7 @@ from trezor.crypto.hashlib import sha256
from trezor.messages import FailureType
from trezor.messages.HDNodePathType import HDNodePathType
from trezor.messages.MultisigRedeemScriptType import MultisigRedeemScriptType
from trezor.utils import HashWriter
from trezor.utils import HashWriter, ensure
from apps.wallet.sign_tx.writers import write_bytes, write_uint32
@ -19,7 +19,7 @@ class MultisigFingerprint:
def add(self, multisig: MultisigRedeemScriptType):
fp = multisig_fingerprint(multisig)
assert fp is not None
ensure(fp is not None)
if self.fingerprint is None:
self.fingerprint = fp
elif self.fingerprint != fp:
@ -27,7 +27,7 @@ class MultisigFingerprint:
def matches(self, multisig: MultisigRedeemScriptType):
fp = multisig_fingerprint(multisig)
assert fp is not None
ensure(fp is not None)
if self.mismatch is False and self.fingerprint == fp:
return True
else:

@ -1,4 +1,5 @@
from trezor.messages.MultisigRedeemScriptType import MultisigRedeemScriptType
from trezor.utils import ensure
from apps.common.coininfo import CoinInfo
from apps.common.writers import empty_bytearray
@ -56,7 +57,7 @@ def script_replay_protection_bip115(
) -> bytearray:
if block_hash is None or block_height is None:
return bytearray()
assert len(block_hash) == 32
ensure(len(block_hash) == 32)
s = bytearray(33)
s[0] = 0x20 # 32 bytes for block hash
s[1:33] = block_hash # block hash

@ -3,7 +3,7 @@ from trezor.messages import FailureType, InputScriptType
from trezor.messages.SignTx import SignTx
from trezor.messages.TxInputType import TxInputType
from trezor.messages.TxOutputBinType import TxOutputBinType
from trezor.utils import HashWriter
from trezor.utils import HashWriter, ensure
from apps.common.coininfo import CoinInfo
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
@ -58,7 +58,7 @@ class Bip143:
) -> bytes:
h_preimage = HashWriter(sha256)
assert not tx.overwintered
ensure(not tx.overwintered)
write_uint32(h_preimage, tx.version) # nVersion
write_bytes(h_preimage, bytearray(self.get_prevouts_hash(coin))) # hashPrevouts

@ -21,15 +21,16 @@ from apps.wallet.sign_tx.decred_prefix_hasher import (
)
from apps.wallet.sign_tx.helpers import *
from apps.wallet.sign_tx.multisig import *
from apps.wallet.sign_tx.overwinter_zip143 import ( # noqa:F401
OVERWINTERED,
Zip143,
Zip143Error,
)
from apps.wallet.sign_tx.scripts import *
from apps.wallet.sign_tx.segwit_bip143 import Bip143, Bip143Error # noqa:F401
from apps.wallet.sign_tx.tx_weight_calculator import *
from apps.wallet.sign_tx.writers import *
from apps.wallet.sign_tx.zcash import ( # noqa:F401
OVERWINTERED,
ZcashError,
Zip143,
Zip243,
)
# the number of bip32 levels used in a wallet (chain and address)
_BIP32_WALLET_DEPTH = const(2)
@ -379,7 +380,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode):
write_uint32(
h_sign, tx.version | OVERWINTERED
) # nVersion | fOverwintered
write_uint32(h_sign, coin.version_group_id) # nVersionGroupId
write_uint32(h_sign, tx.version_group_id) # nVersionGroupId
else:
write_uint32(h_sign, tx.version) # nVersion
@ -560,7 +561,7 @@ async def get_prevtx_output_value(
if tx.overwintered:
write_uint32(txh, tx.version | OVERWINTERED) # nVersion | fOverwintered
write_uint32(txh, coin.version_group_id) # nVersionGroupId
write_uint32(txh, tx.version_group_id) # nVersionGroupId
elif coin.decred:
write_uint32(txh, tx.version | DECRED_SERIALIZE_NO_WITNESS)
else:
@ -629,7 +630,7 @@ def get_tx_header(coin: CoinInfo, tx: SignTx, segwit: bool = False):
w_txi = bytearray()
if tx.overwintered:
write_uint32(w_txi, tx.version | OVERWINTERED) # nVersion | fOverwintered
write_uint32(w_txi, coin.version_group_id) # nVersionGroupId
write_uint32(w_txi, tx.version_group_id) # nVersionGroupId
else:
write_uint32(w_txi, tx.version) # nVersion
if segwit:

@ -1,6 +1,7 @@
from trezor.crypto.hashlib import sha256
from trezor.messages.TxInputType import TxInputType
from trezor.messages.TxOutputBinType import TxOutputBinType
from trezor.utils import ensure
from apps.common.writers import (
write_bytes,
@ -59,7 +60,7 @@ def write_tx_output(w, o: TxOutputBinType):
def write_op_push(w, n: int):
assert n >= 0 and n <= 0xFFFFFFFF
ensure(n >= 0 and n <= 0xFFFFFFFF)
if n < 0x4C:
w.append(n & 0xFF)
elif n < 0xFF:
@ -78,7 +79,7 @@ def write_op_push(w, n: int):
def write_varint(w, n: int):
assert n >= 0 and n <= 0xFFFFFFFF
ensure(n >= 0 and n <= 0xFFFFFFFF)
if n < 253:
w.append(n & 0xFF)
elif n < 0x10000:
@ -94,7 +95,7 @@ def write_varint(w, n: int):
def write_scriptnum(w, n: int):
assert n >= 0 and n <= 0xFFFFFFFF
ensure(n >= 0 and n <= 0xFFFFFFFF)
if n < 0x100:
w.append(1)
w.append(n & 0xFF)

@ -5,7 +5,7 @@ from trezor.messages import FailureType, InputScriptType
from trezor.messages.SignTx import SignTx
from trezor.messages.TxInputType import TxInputType
from trezor.messages.TxOutputBinType import TxOutputBinType
from trezor.utils import HashWriter
from trezor.utils import HashWriter, ensure
from apps.common.coininfo import CoinInfo
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
@ -23,10 +23,27 @@ from apps.wallet.sign_tx.writers import (
OVERWINTERED = const(0x80000000)
class Zip143Error(ValueError):
class ZcashError(ValueError):
pass
def derive_script_code(txi: TxInputType, pubkeyhash: bytes) -> bytearray:
if txi.multisig:
return output_script_multisig(
multisig_get_pubkeys(txi.multisig), txi.multisig.m
)
p2pkh = txi.script_type == InputScriptType.SPENDADDRESS
if p2pkh:
return output_script_p2pkh(pubkeyhash)
else:
raise ZcashError(
FailureType.DataError, "Unknown input script type for zip143 script code"
)
class Zip143:
def __init__(self):
self.h_prevouts = HashWriter(blake2b, outlen=32, personal=b"ZcashPrevoutHash")
@ -62,14 +79,15 @@ class Zip143:
) -> bytes:
h_preimage = HashWriter(
blake2b, outlen=32, personal=b"ZcashSigHash\x19\x1b\xa8\x5b"
) # BRANCH_ID = 0x5ba81b19
) # BRANCH_ID = 0x5ba81b19 / Overwinter
assert tx.overwintered
ensure(tx.overwintered)
ensure(tx.version == 3)
write_uint32(
h_preimage, tx.version | OVERWINTERED
) # 1. nVersion | fOverwintered
write_uint32(h_preimage, coin.version_group_id) # 2. nVersionGroupId
write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId
write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # 3. hashPrevouts
write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # 4. hashSequence
write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # 5. hashOutputs
@ -81,7 +99,7 @@ class Zip143:
write_bytes_reversed(h_preimage, txi.prev_hash) # 10a. outpoint
write_uint32(h_preimage, txi.prev_index)
script_code = self.derive_script_code(txi, pubkeyhash) # 10b. scriptCode
script_code = derive_script_code(txi, pubkeyhash) # 10b. scriptCode
write_varint(h_preimage, len(script_code))
write_bytes(h_preimage, script_code)
@ -91,21 +109,47 @@ class Zip143:
return get_tx_hash(h_preimage)
# see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
# item 5 for details
def derive_script_code(self, txi: TxInputType, pubkeyhash: bytes) -> bytearray:
if txi.multisig:
return output_script_multisig(
multisig_get_pubkeys(txi.multisig), txi.multisig.m
)
class Zip243(Zip143):
def __init__(self):
super().__init__()
def preimage_hash(
self,
coin: CoinInfo,
tx: SignTx,
txi: TxInputType,
pubkeyhash: bytes,
sighash: int,
) -> bytes:
h_preimage = HashWriter(
blake2b, outlen=32, personal=b"ZcashSigHash\xbb\x09\xb8\x76"
) # BRANCH_ID = 0x76b809bb / Sapling
ensure(tx.overwintered)
ensure(tx.version == 4)
write_uint32(
h_preimage, tx.version | OVERWINTERED
) # 1. nVersion | fOverwintered
write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId
write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # 3. hashPrevouts
write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # 4. hashSequence
write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # 5. hashOutputs
write_bytes(h_preimage, b"\x00" * 32) # 6. hashJoinSplits
write_uint32(h_preimage, tx.lock_time) # 7. nLockTime
write_uint32(h_preimage, tx.expiry) # 8. expiryHeight
write_uint32(h_preimage, sighash) # 9. nHashType
write_bytes_reversed(h_preimage, txi.prev_hash) # 10a. outpoint
write_uint32(h_preimage, txi.prev_index)
p2pkh = txi.script_type == InputScriptType.SPENDADDRESS
if p2pkh:
return output_script_p2pkh(pubkeyhash)
script_code = derive_script_code(txi, pubkeyhash) # 10b. scriptCode
write_varint(h_preimage, len(script_code))
write_bytes(h_preimage, script_code)
else:
raise Zip143Error(
FailureType.DataError,
"Unknown input script type for zip143 script code",
)
write_uint64(h_preimage, txi.amount) # 10c. value
write_uint32(h_preimage, txi.sequence) # 10d. nSequence
return get_tx_hash(h_preimage)

@ -15,6 +15,7 @@ class SignTx(p.MessageType):
lock_time: int = None,
expiry: int = None,
overwintered: bool = None,
version_group_id: int = None,
) -> None:
self.outputs_count = outputs_count
self.inputs_count = inputs_count
@ -23,6 +24,7 @@ class SignTx(p.MessageType):
self.lock_time = lock_time
self.expiry = expiry
self.overwintered = overwintered
self.version_group_id = version_group_id
@classmethod
def get_fields(cls):
@ -34,4 +36,5 @@ class SignTx(p.MessageType):
5: ('lock_time', p.UVarintType, 0), # default=0
6: ('expiry', p.UVarintType, 0),
7: ('overwintered', p.BoolType, 0),
8: ('version_group_id', p.UVarintType, 0),
}

@ -28,6 +28,7 @@ class TransactionType(p.MessageType):
extra_data_len: int = None,
expiry: int = None,
overwintered: bool = None,
version_group_id: int = None,
) -> None:
self.version = version
self.inputs = inputs if inputs is not None else []
@ -40,6 +41,7 @@ class TransactionType(p.MessageType):
self.extra_data_len = extra_data_len
self.expiry = expiry
self.overwintered = overwintered
self.version_group_id = version_group_id
@classmethod
def get_fields(cls):
@ -55,4 +57,5 @@ class TransactionType(p.MessageType):
9: ('extra_data_len', p.UVarintType, 0),
10: ('expiry', p.UVarintType, 0),
11: ('overwintered', p.BoolType, 0),
12: ('version_group_id', p.UVarintType, 0),
}

@ -0,0 +1,184 @@
from common import *
from trezor.messages import InputScriptType
from trezor.messages.SignTx import SignTx
from trezor.messages.TxInputType import TxInputType
from trezor.messages.TxOutputBinType import TxOutputBinType
from apps.common import coins
from apps.wallet.sign_tx.zcash import Zip143
# test vectors inspired from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0143.py
class TestZcashZip143(unittest.TestCase):
VECTORS = [
{
"expiry": 71895707,
"inputs": [
{
"amount": 35268204,
"prevout": [
"702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76",
4025613248,
],
"pubkeyhash": "4d9cafb657677f2321fc538e367767dbdf551539",
"script_type": InputScriptType.SPENDADDRESS,
"sequence": 1999822371,
}
],
"lock_time": 452079490,
"outputs": [
{"script_pubkey": "06535251635252", "amount": 1246336469307855}
],
"version": 3,
"version_group_id": 0x3C48270,
"hash_type": 1,
"prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688",
"sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a",
"outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992",
"preimage_hash": b"287146efaa30b3c1c7bd1a72308c46205712e6944780fdc5a7f91f477fddd55b",
},
{
"expiry": 231041495,
"inputs": [
{
"amount": 39263472,
"prevout": [
"76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2",
1547817817,
],
"pubkeyhash": "9f5d230603ce57a0e8b31a8c9b6c983ad5b00cd5",
"script_type": InputScriptType.SPENDADDRESS,
"sequence": 3973122135,
},
{
"amount": 57533728,
"prevout": [
"cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483",
3053054889,
],
"pubkeyhash": "b5e71ef1df5ed3a2589607ca58ed19634f07fb4f",
"script_type": InputScriptType.SPENDADDRESS,
"sequence": 3932380530,
},
],
"lock_time": 3087412294,
"outputs": [
{"script_pubkey": "03ac6552", "amount": 546412698509744},
{"script_pubkey": "00", "amount": 166856241017532},
],
"version": 3,
"version_group_id": 0x3C48270,
"hash_type": 1,
"prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b",
"sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e",
"outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1",
"preimage_hash": b"b71358954aca8ffe1d3f1b5707ed6c082ed2b35e35e293b897bfc12ae7c85396",
},
{
"expiry": 186996458,
"inputs": [
{
"amount": 14267260,
"prevout": [
"6c6fae359f645c276891c0dcab3faf187700c082dc477740fb3f2cd7bb59fb35",
1290359941,
],
"script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "0873d1baed6c8696e4bd2b26755692b4d8050086",
"sequence": 1230917966,
}
],
"lock_time": 1520002857,
"outputs": [],
"version": 3,
"version_group_id": 0x3C48270,
"hash_type": 1,
"prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd",
"sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc",
"outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824",
"preimage_hash": b"19ea4ce2467cb5cdcc4562ce81b22006f1fb55189ea93ccc7a3bc78ff5d97a93",
},
{
"expiry": 254788522,
"inputs": [
{
"amount": 36100600,
"prevout": [
"e818f9057c5abaaa2e5c15b94945cd424c28a5fa385dadfe4907b274d842707d",
1517971891,
],
"script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "80b6c35a9b2efd77dbfd5d5d3bb1fd03ff40f182",
"sequence": 3833577708,
},
{
"amount": 71238918,
"prevout": [
"7350d1014670212efe81fb7c73e8450df814ef6232f7490f63ccf07480f884a6",
687648622,
],
"script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "fb8c27a442afe0f0b39a3875823c4893fe8f8550",
"sequence": 4190617831,
},
],
"lock_time": 1557067344,
"outputs": [
{"script_pubkey": "076a53655151516a", "amount": 470086065540185}
],
"version": 3,
"version_group_id": 0x3C48270,
"hash_type": 1,
"prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898",
"sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23",
"outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a",
"preimage_hash": b"d0b92233e185a69f320f18bfacff7e5dcc5f0ed02af2f3ecf59359853e105e59",
},
]
def test_zip143(self):
coin = coins.by_name("Zcash")
for v in self.VECTORS:
tx = SignTx(
coin_name="Zcash",
inputs_count=len(v["inputs"]),
outputs_count=len(v["outputs"]),
version=v["version"],
lock_time=v["lock_time"],
expiry=v["expiry"],
overwintered=(v["version"] >= 3),
version_group_id=v["version_group_id"],
)
zip143 = Zip143()
for i in v["inputs"]:
txi = TxInputType()
txi.amount = i["amount"]
txi.prev_hash = unhexlify(i["prevout"][0])
txi.prev_index = i["prevout"][1]
txi.script_type = i["script_type"]
txi.sequence = i["sequence"]
zip143.add_prevouts(txi)
zip143.add_sequence(txi)
for o in v["outputs"]:
txo = TxOutputBinType()
txo.amount = o["amount"]
txo.script_pubkey = unhexlify(o["script_pubkey"])
zip143.add_output(txo)
self.assertEqual(hexlify(zip143.get_prevouts_hash()), v["prevouts_hash"])
self.assertEqual(hexlify(zip143.get_sequence_hash()), v["sequence_hash"])
self.assertEqual(hexlify(zip143.get_outputs_hash()), v["outputs_hash"])
self.assertEqual(
hexlify(
zip143.preimage_hash(
coin, tx, txi, unhexlify(i["pubkeyhash"]), v["hash_type"]
)
),
v["preimage_hash"],
)
if __name__ == "__main__":
unittest.main()

@ -0,0 +1,184 @@
from common import *
from trezor.messages import InputScriptType
from trezor.messages.SignTx import SignTx
from trezor.messages.TxInputType import TxInputType
from trezor.messages.TxOutputBinType import TxOutputBinType
from apps.common import coins
from apps.wallet.sign_tx.zcash import Zip243
# test vectors inspired from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0243.py
class TestZcashZip243(unittest.TestCase):
VECTORS = [
{
"expiry": 71895707,
"inputs": [
{
"amount": 35268204,
"prevout": [
"702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76",
4025613248,
],
"pubkeyhash": "4d9cafb657677f2321fc538e367767dbdf551539",
"script_type": InputScriptType.SPENDADDRESS,
"sequence": 1999822371,
}
],
"lock_time": 452079490,
"outputs": [
{"script_pubkey": "06535251635252", "amount": 1246336469307855}
],
"version": 4,
"version_group_id": 0x892F2085,
"hash_type": 1,
"prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688",
"sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a",
"outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992",
"preimage_hash": b"80b3cdfbefc9cea6818e148b5af6133dfac7d9ff8435b256ef1958b906b3647f",
},
{
"expiry": 231041495,
"inputs": [
{
"amount": 39263472,
"prevout": [
"76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2",
1547817817,
],
"pubkeyhash": "9f5d230603ce57a0e8b31a8c9b6c983ad5b00cd5",
"script_type": InputScriptType.SPENDADDRESS,
"sequence": 3973122135,
},
{
"amount": 57533728,
"prevout": [
"cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483",
3053054889,
],
"pubkeyhash": "b5e71ef1df5ed3a2589607ca58ed19634f07fb4f",
"script_type": InputScriptType.SPENDADDRESS,
"sequence": 3932380530,
},
],
"lock_time": 3087412294,
"outputs": [
{"script_pubkey": "03ac6552", "amount": 546412698509744},
{"script_pubkey": "00", "amount": 166856241017532},
],
"version": 4,
"version_group_id": 0x892F2085,
"hash_type": 1,
"prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b",
"sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e",
"outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1",
"preimage_hash": b"25769ee5a943f0e1fd165c2b049de2732ea88f059658f63932f12b16087337fd",
},
{
"expiry": 186996458,
"inputs": [
{
"amount": 14267260,
"prevout": [
"6c6fae359f645c276891c0dcab3faf187700c082dc477740fb3f2cd7bb59fb35",
1290359941,
],
"script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "0873d1baed6c8696e4bd2b26755692b4d8050086",
"sequence": 1230917966,
}
],
"lock_time": 1520002857,
"outputs": [],
"version": 4,
"version_group_id": 0x892F2085,
"hash_type": 1,
"prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd",
"sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc",
"outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824",
"preimage_hash": b"e2d5a735f8f4c3f6e382405a214daa520a7f80200c177d8daafe1c0344db9dd3",
},
{
"expiry": 254788522,
"inputs": [
{
"amount": 36100600,
"prevout": [
"e818f9057c5abaaa2e5c15b94945cd424c28a5fa385dadfe4907b274d842707d",
1517971891,
],
"script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "80b6c35a9b2efd77dbfd5d5d3bb1fd03ff40f182",
"sequence": 3833577708,
},
{
"amount": 71238918,
"prevout": [
"7350d1014670212efe81fb7c73e8450df814ef6232f7490f63ccf07480f884a6",
687648622,
],
"script_type": InputScriptType.SPENDADDRESS,
"pubkeyhash": "fb8c27a442afe0f0b39a3875823c4893fe8f8550",
"sequence": 4190617831,
},
],
"lock_time": 1557067344,
"outputs": [
{"script_pubkey": "076a53655151516a", "amount": 470086065540185}
],
"version": 4,
"version_group_id": 0x892F2085,
"hash_type": 1,
"prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898",
"sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23",
"outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a",
"preimage_hash": b"74908bfb31d1ce68f1b82c12e96fb7799669293d92da84a689a1dd1f9ed74d8d",
},
]
def test_zip243(self):
coin = coins.by_name("Zcash")
for v in self.VECTORS:
tx = SignTx(
coin_name="Zcash",
inputs_count=len(v["inputs"]),
outputs_count=len(v["outputs"]),
version=v["version"],
lock_time=v["lock_time"],
expiry=v["expiry"],
overwintered=(v["version"] >= 3),
version_group_id=v["version_group_id"],
)
zip243 = Zip243()
for i in v["inputs"]:
txi = TxInputType()
txi.amount = i["amount"]
txi.prev_hash = unhexlify(i["prevout"][0])
txi.prev_index = i["prevout"][1]
txi.script_type = i["script_type"]
txi.sequence = i["sequence"]
zip243.add_prevouts(txi)
zip243.add_sequence(txi)
for o in v["outputs"]:
txo = TxOutputBinType()
txo.amount = o["amount"]
txo.script_pubkey = unhexlify(o["script_pubkey"])
zip243.add_output(txo)
self.assertEqual(hexlify(zip243.get_prevouts_hash()), v["prevouts_hash"])
self.assertEqual(hexlify(zip243.get_sequence_hash()), v["sequence_hash"])
self.assertEqual(hexlify(zip243.get_outputs_hash()), v["outputs_hash"])
self.assertEqual(
hexlify(
zip243.preimage_hash(
coin, tx, txi, unhexlify(i["pubkeyhash"]), v["hash_type"]
)
),
v["preimage_hash"],
)
if __name__ == "__main__":
unittest.main()

@ -1 +1 @@
Subproject commit 41e4a84b5b01d03e980f84fab29c8f0b0ec948f5
Subproject commit ea0262266d9c42315617e9abbcf0b539c373ebc6
Loading…
Cancel
Save