core/sign_tx: Merge bip143 classes into signer classes.

pull/985/head
Andrew Kozlik 4 years ago committed by Andrew Kozlik
parent 6ad3baeab2
commit 22933587be

@ -14,7 +14,6 @@ from apps.wallet.sign_tx import (
multisig,
progress,
scripts,
segwit_bip143,
)
if not utils.BITCOIN_ONLY:
@ -52,7 +51,6 @@ async def sign_tx(ctx: wire.Context, msg: SignTx, keychain: seed.Keychain) -> Tx
multisig.MultisigError,
addresses.AddressError,
scripts.ScriptsError,
segwit_bip143.Bip143Error,
) as e:
raise wire.Error(*e.args)
if isinstance(req, TxRequest):

@ -20,7 +20,6 @@ from apps.wallet.sign_tx import (
multisig,
progress,
scripts,
segwit_bip143,
tx_weight,
writers,
)
@ -113,10 +112,12 @@ class Bitcoin:
self.h_confirmed = self.create_hash_writer() # not a real tx hash
# BIP-0143 transaction hashing
self.hash143 = self.create_hash143()
self.init_hash143()
def create_hash143(self) -> segwit_bip143.Bip143:
return segwit_bip143.Bip143()
def init_hash143(self) -> None:
self.h_prevouts = HashWriter(sha256())
self.h_sequence = HashWriter(sha256())
self.h_outputs = HashWriter(sha256())
def create_hash_writer(self) -> HashWriter:
return HashWriter(sha256())
@ -194,7 +195,7 @@ class Bitcoin:
self.wallet_path.add_input(txi)
self.multisig_fingerprint.add_input(txi)
writers.write_tx_input_check(self.h_confirmed, txi)
self.hash143.add_input(txi) # all inputs are included (non-segwit as well)
self.hash143_add_input(txi) # all inputs are included (non-segwit as well)
if not addresses.validate_full_path(txi.address_n, self.coin, txi.script_type):
await helpers.confirm_foreign_address(txi.address_n)
@ -231,7 +232,7 @@ class Bitcoin:
raise SigningError(FailureType.ActionCancelled, "Output cancelled")
writers.write_tx_output(self.h_confirmed, txo_bin)
self.hash143.add_output(txo_bin)
self.hash143_add_output(txo_bin)
self.total_out += txo_bin.amount
def on_negative_fee(self) -> None:
@ -267,12 +268,8 @@ class Bitcoin:
node = self.keychain.derive(txi.address_n, self.coin.curve_name)
public_key = node.public_key()
hash143_hash = self.hash143.preimage_hash(
self.coin,
self.tx,
txi,
addresses.ecdsa_hash_pubkey(public_key, self.coin),
self.get_hash_type(),
hash143_hash = self.hash143_preimage_hash(
txi, addresses.ecdsa_hash_pubkey(public_key, self.coin)
)
signature = ecdsa_sign(node, hash143_hash)
@ -438,7 +435,7 @@ class Bitcoin:
# Validations to perform on the UTXO when checking the previous transaction output amount.
pass
# TX Helpers
# Tx Helpers
# ===
def get_hash_type(self) -> int:
@ -472,7 +469,7 @@ class Bitcoin:
self.tx_req.serialized.signature_index = index
self.tx_req.serialized.signature = signature
# TX Outputs
# Tx Outputs
# ===
def output_derive_script(self, txo: TxOutputType) -> bytes:
@ -512,6 +509,71 @@ class Bitcoin:
txi, self.coin, self.get_hash_type(), pubkey, signature
)
# BIP-0143
# ===
def hash143_add_input(self, txi: TxInputType) -> None:
writers.write_bytes_reversed(
self.h_prevouts, txi.prev_hash, writers.TX_HASH_SIZE
)
writers.write_uint32(self.h_prevouts, txi.prev_index)
writers.write_uint32(self.h_sequence, txi.sequence)
def hash143_add_output(self, txo_bin: TxOutputBinType) -> None:
writers.write_tx_output(self.h_outputs, txo_bin)
def get_prevouts_hash(self) -> bytes:
return writers.get_tx_hash(self.h_prevouts, double=self.coin.sign_hash_double)
def get_sequence_hash(self) -> bytes:
return writers.get_tx_hash(self.h_sequence, double=self.coin.sign_hash_double)
def get_outputs_hash(self) -> bytes:
return writers.get_tx_hash(self.h_outputs, double=self.coin.sign_hash_double)
def hash143_preimage_hash(self, txi: TxInputType, pubkeyhash: bytes) -> bytes:
h_preimage = HashWriter(sha256())
# nVersion
writers.write_uint32(h_preimage, self.tx.version)
# hashPrevouts
writers.write_bytes_fixed(
h_preimage, self.get_prevouts_hash(), writers.TX_HASH_SIZE
)
# hashSequence
writers.write_bytes_fixed(
h_preimage, self.get_sequence_hash(), writers.TX_HASH_SIZE
)
# outpoint
writers.write_bytes_reversed(h_preimage, txi.prev_hash, writers.TX_HASH_SIZE)
writers.write_uint32(h_preimage, txi.prev_index)
# scriptCode
script_code = scripts.bip143_derive_script_code(txi, pubkeyhash)
writers.write_bytes_prefixed(h_preimage, script_code)
# amount
writers.write_uint64(h_preimage, txi.amount)
# nSequence
writers.write_uint32(h_preimage, txi.sequence)
# hashOutputs
writers.write_bytes_fixed(
h_preimage, self.get_outputs_hash(), writers.TX_HASH_SIZE
)
# nLockTime
writers.write_uint32(h_preimage, self.tx.lock_time)
# nHashType
writers.write_uint32(h_preimage, self.get_hash_type())
return writers.get_tx_hash(h_preimage, double=self.coin.sign_hash_double)
def input_is_segwit(txi: TxInputType) -> bool:
return txi.script_type in helpers.SEGWIT_INPUT_SCRIPT_TYPES

@ -14,7 +14,6 @@ from apps.common import coininfo, seed
from apps.wallet.sign_tx import addresses, helpers, multisig, progress, scripts, writers
from apps.wallet.sign_tx.bitcoin import Bitcoin
from apps.wallet.sign_tx.common import SigningError, ecdsa_sign
from apps.wallet.sign_tx.segwit_bip143 import Bip143
DECRED_SERIALIZE_FULL = const(0 << 16)
DECRED_SERIALIZE_NO_WITNESS = const(1 << 16)
@ -26,35 +25,6 @@ if False:
from typing import Union
class DecredPrefixHasher(Bip143):
"""
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.
"""
def __init__(self, tx: SignTx):
self.h_prefix = HashWriter(blake256())
writers.write_uint32(self.h_prefix, tx.version | DECRED_SERIALIZE_NO_WITNESS)
writers.write_varint(self.h_prefix, tx.inputs_count)
def add_input(self, txi: TxInputType) -> None:
writers.write_tx_input_decred(self.h_prefix, txi)
def add_output_count(self, tx: SignTx) -> None:
writers.write_varint(self.h_prefix, tx.outputs_count)
def add_output(self, txo_bin: TxOutputBinType) -> None:
writers.write_tx_output(self.h_prefix, txo_bin)
def add_locktime_expiry(self, tx: SignTx) -> None:
writers.write_uint32(self.h_prefix, tx.lock_time)
writers.write_uint32(self.h_prefix, tx.expiry)
def get_prefix_hash(self) -> bytes:
return self.h_prefix.get_digest()
class Decred(Bitcoin):
def __init__(
self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo
@ -62,23 +32,25 @@ class Decred(Bitcoin):
ensure(coin.decred)
super().__init__(tx, keychain, coin)
def create_hash143(self) -> Bip143:
return DecredPrefixHasher(self.tx) # pseudo BIP-0143 prefix hashing
self.write_tx_header(self.serialized_tx, self.tx, has_segwit=False)
writers.write_varint(self.serialized_tx, self.tx.inputs_count)
def init_hash143(self) -> None:
self.h_prefix = self.create_hash_writer()
writers.write_uint32(
self.h_prefix, self.tx.version | DECRED_SERIALIZE_NO_WITNESS
)
writers.write_varint(self.h_prefix, self.tx.inputs_count)
def create_hash_writer(self) -> HashWriter:
return HashWriter(blake256())
async def step1_process_inputs(self) -> None:
self.write_tx_header(self.serialized_tx, self.tx, has_segwit=False)
writers.write_varint(self.serialized_tx, self.tx.inputs_count)
await super().step1_process_inputs()
async def step2_confirm_outputs(self) -> None:
writers.write_varint(self.serialized_tx, self.tx.outputs_count)
self.hash143.add_output_count(self.tx)
writers.write_varint(self.h_prefix, self.tx.outputs_count)
await super().step2_confirm_outputs()
self.hash143.add_locktime_expiry(self.tx)
self.write_tx_footer(self.serialized_tx, self.tx)
self.write_tx_footer(self.h_prefix, self.tx)
async def process_input(self, i: int, txi: TxInputType) -> None:
await super().process_input(i, txi)
@ -95,14 +67,13 @@ class Decred(Bitcoin):
"Cannot send to output with script version != 0",
)
txo_bin.decred_script_version = txo.decred_script_version
writers.write_tx_output(self.serialized_tx, txo_bin)
await super().confirm_output(i, txo, txo_bin)
writers.write_tx_output(self.serialized_tx, txo_bin)
async def step4_serialize_inputs(self) -> None:
writers.write_varint(self.serialized_tx, self.tx.inputs_count)
prefix_hash = self.hash143.get_prefix_hash()
prefix_hash = self.h_prefix.get_digest()
for i_sign in range(self.tx.inputs_count):
progress.advance()
@ -179,6 +150,12 @@ class Decred(Bitcoin):
"Cannot use utxo that has script_version != 0",
)
def hash143_add_input(self, txi: TxInputType) -> None:
writers.write_tx_input_decred(self.h_prefix, txi)
def hash143_add_output(self, txo_bin: TxOutputBinType) -> None:
writers.write_tx_output(self.h_prefix, txo_bin)
def write_tx_input(self, w: writers.Writer, txi: TxInputType) -> None:
writers.write_tx_input_decred(w, txi)

@ -111,6 +111,31 @@ def output_derive_script(txo: TxOutputType, coin: CoinInfo) -> bytes:
raise ScriptsError(FailureType.DataError, "Invalid address type")
# see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
# item 5 for details
def bip143_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.SPENDWITNESS
or txi.script_type == InputScriptType.SPENDP2SHWITNESS
or txi.script_type == InputScriptType.SPENDADDRESS
)
if p2pkh:
# for p2wpkh in p2sh or native p2wpkh
# the scriptCode is a classic p2pkh
return output_script_p2pkh(pubkeyhash)
else:
raise ScriptsError(
FailureType.DataError, "Unknown input script type for bip143 script code",
)
# P2PKH, P2SH
# ===
# https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki

@ -1,115 +0,0 @@
from trezor.crypto.hashlib import sha256
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, ensure
from apps.common.coininfo import CoinInfo
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
from apps.wallet.sign_tx.scripts import output_script_multisig, output_script_p2pkh
from apps.wallet.sign_tx.writers import (
TX_HASH_SIZE,
get_tx_hash,
write_bytes_fixed,
write_bytes_prefixed,
write_bytes_reversed,
write_tx_output,
write_uint32,
write_uint64,
)
class Bip143Error(ValueError):
pass
class Bip143:
def __init__(self) -> None:
self.h_prevouts = HashWriter(sha256())
self.h_sequence = HashWriter(sha256())
self.h_outputs = HashWriter(sha256())
def add_input(self, txi: TxInputType) -> None:
write_bytes_reversed(self.h_prevouts, txi.prev_hash, TX_HASH_SIZE)
write_uint32(self.h_prevouts, txi.prev_index)
write_uint32(self.h_sequence, txi.sequence)
def add_output_count(self, tx: SignTx) -> None:
pass
def add_output(self, txo_bin: TxOutputBinType) -> None:
write_tx_output(self.h_outputs, txo_bin)
def add_locktime_expiry(self, tx: SignTx) -> None:
pass
def get_prevouts_hash(self, coin: CoinInfo) -> bytes:
return get_tx_hash(self.h_prevouts, double=coin.sign_hash_double)
def get_sequence_hash(self, coin: CoinInfo) -> bytes:
return get_tx_hash(self.h_sequence, double=coin.sign_hash_double)
def get_outputs_hash(self, coin: CoinInfo) -> bytes:
return get_tx_hash(self.h_outputs, double=coin.sign_hash_double)
def get_prefix_hash(self) -> bytes:
pass
def preimage_hash(
self,
coin: CoinInfo,
tx: SignTx,
txi: TxInputType,
pubkeyhash: bytes,
sighash: int,
) -> bytes:
h_preimage = HashWriter(sha256())
ensure(not coin.overwintered)
write_uint32(h_preimage, tx.version) # nVersion
# hashPrevouts
write_bytes_fixed(h_preimage, self.get_prevouts_hash(coin), TX_HASH_SIZE)
# hashSequence
write_bytes_fixed(h_preimage, self.get_sequence_hash(coin), TX_HASH_SIZE)
write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE) # outpoint
write_uint32(h_preimage, txi.prev_index) # outpoint
script_code = derive_script_code(txi, pubkeyhash) # scriptCode
write_bytes_prefixed(h_preimage, script_code)
write_uint64(h_preimage, txi.amount) # amount
write_uint32(h_preimage, txi.sequence) # nSequence
# hashOutputs
write_bytes_fixed(h_preimage, self.get_outputs_hash(coin), TX_HASH_SIZE)
write_uint32(h_preimage, tx.lock_time) # nLockTime
write_uint32(h_preimage, sighash) # nHashType
return get_tx_hash(h_preimage, double=coin.sign_hash_double)
# see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
# item 5 for details
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.SPENDWITNESS
or txi.script_type == InputScriptType.SPENDP2SHWITNESS
or txi.script_type == InputScriptType.SPENDADDRESS
)
if p2pkh:
# for p2wpkh in p2sh or native p2wpkh
# the scriptCode is a classic p2pkh
return output_script_p2pkh(pubkeyhash)
else:
raise Bip143Error(
FailureType.DataError, "Unknown input script type for bip143 script code",
)

@ -15,7 +15,6 @@ from apps.wallet.sign_tx.bitcoinlike import Bitcoinlike
from apps.wallet.sign_tx.common import SigningError
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
from apps.wallet.sign_tx.scripts import output_script_multisig, output_script_p2pkh
from apps.wallet.sign_tx.segwit_bip143 import Bip143
from apps.wallet.sign_tx.writers import (
TX_HASH_SIZE,
get_tx_hash,
@ -34,167 +33,28 @@ if False:
OVERWINTERED = const(0x80000000)
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 SigningError(
FailureType.DataError, "Unknown input script type for zip143 script code"
)
class Zip143(Bip143):
def __init__(self, branch_id: int) -> None:
self.branch_id = branch_id
self.h_prevouts = HashWriter(blake2b(outlen=32, personal=b"ZcashPrevoutHash"))
self.h_sequence = HashWriter(blake2b(outlen=32, personal=b"ZcashSequencHash"))
self.h_outputs = HashWriter(blake2b(outlen=32, personal=b"ZcashOutputsHash"))
def get_prevouts_hash(self, coin: CoinInfo) -> bytes:
return get_tx_hash(self.h_prevouts)
def get_sequence_hash(self, coin: CoinInfo) -> bytes:
return get_tx_hash(self.h_sequence)
def get_outputs_hash(self, coin: CoinInfo) -> bytes:
return get_tx_hash(self.h_outputs)
def preimage_hash(
self,
coin: CoinInfo,
tx: SignTx,
txi: TxInputType,
pubkeyhash: bytes,
sighash: int,
) -> bytes:
h_preimage = HashWriter(
blake2b(
outlen=32, personal=b"ZcashSigHash" + struct.pack("<I", self.branch_id)
)
)
ensure(coin.overwintered)
ensure(tx.version == 3)
write_uint32(
h_preimage, tx.version | OVERWINTERED
) # 1. nVersion | fOverwintered
write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId
# 3. hashPrevouts
write_bytes_fixed(
h_preimage, bytearray(self.get_prevouts_hash(coin)), TX_HASH_SIZE
)
# 4. hashSequence
write_bytes_fixed(
h_preimage, bytearray(self.get_sequence_hash(coin)), TX_HASH_SIZE
)
# 5. hashOutputs
write_bytes_fixed(
h_preimage, bytearray(self.get_outputs_hash(coin)), TX_HASH_SIZE
)
# 6. hashJoinSplits
write_bytes_fixed(h_preimage, b"\x00" * TX_HASH_SIZE, TX_HASH_SIZE)
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, TX_HASH_SIZE) # 10a. outpoint
write_uint32(h_preimage, txi.prev_index)
script_code = derive_script_code(txi, pubkeyhash) # 10b. scriptCode
write_bytes_prefixed(h_preimage, script_code)
write_uint64(h_preimage, txi.amount) # 10c. value
write_uint32(h_preimage, txi.sequence) # 10d. nSequence
return get_tx_hash(h_preimage)
class Zip243(Zip143):
def preimage_hash(
self,
coin: CoinInfo,
tx: SignTx,
txi: TxInputType,
pubkeyhash: bytes,
sighash: int,
) -> bytes:
h_preimage = HashWriter(
blake2b(
outlen=32, personal=b"ZcashSigHash" + struct.pack("<I", self.branch_id)
)
)
ensure(coin.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
# 3. hashPrevouts
write_bytes_fixed(
h_preimage, bytearray(self.get_prevouts_hash(coin)), TX_HASH_SIZE
)
# 4. hashSequence
write_bytes_fixed(
h_preimage, bytearray(self.get_sequence_hash(coin)), TX_HASH_SIZE
)
# 5. hashOutputs
write_bytes_fixed(
h_preimage, bytearray(self.get_outputs_hash(coin)), TX_HASH_SIZE
)
zero_hash = b"\x00" * TX_HASH_SIZE
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 6. hashJoinSplits
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 7. hashShieldedSpends
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 8. hashShieldedOutputs
write_uint32(h_preimage, tx.lock_time) # 9. nLockTime
write_uint32(h_preimage, tx.expiry) # 10. expiryHeight
write_uint64(h_preimage, 0) # 11. valueBalance
write_uint32(h_preimage, sighash) # 12. nHashType
write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE) # 13a. outpoint
write_uint32(h_preimage, txi.prev_index)
script_code = derive_script_code(txi, pubkeyhash) # 13b. scriptCode
write_bytes_prefixed(h_preimage, script_code)
write_uint64(h_preimage, txi.amount) # 13c. value
write_uint32(h_preimage, txi.sequence) # 13d. nSequence
return get_tx_hash(h_preimage)
class Overwintered(Bitcoinlike):
def __init__(self, tx: SignTx, keychain: Keychain, coin: CoinInfo) -> None:
ensure(coin.overwintered)
super().__init__(tx, keychain, coin)
def create_hash143(self) -> Bip143:
if self.tx.version == 3:
branch_id = self.tx.branch_id or 0x5BA81B19 # Overwinter
return Zip143(branch_id) # ZIP-0143 transaction hashing
if not self.tx.branch_id:
self.tx.branch_id = 0x5BA81B19 # Overwinter
elif self.tx.version == 4:
branch_id = self.tx.branch_id or 0x76B809BB # Sapling
return Zip243(branch_id) # ZIP-0243 transaction hashing
if not self.tx.branch_id:
self.tx.branch_id = 0x76B809BB # Sapling
else:
raise SigningError(
FailureType.DataError,
"Unsupported version for overwintered transaction",
)
def init_hash143(self) -> None:
self.h_prevouts = HashWriter(blake2b(outlen=32, personal=b"ZcashPrevoutHash"))
self.h_sequence = HashWriter(blake2b(outlen=32, personal=b"ZcashSequencHash"))
self.h_outputs = HashWriter(blake2b(outlen=32, personal=b"ZcashOutputsHash"))
async def step7_finish(self) -> None:
self.write_tx_footer(self.serialized_tx, self.tx)
@ -227,3 +87,98 @@ class Overwintered(Bitcoinlike):
# nVersion | fOverwintered
write_uint32(w, tx.version | OVERWINTERED)
write_uint32(w, tx.version_group_id) # nVersionGroupId
# ZIP-0143 / ZIP-0243
# ===
def get_prevouts_hash(self) -> bytes:
return get_tx_hash(self.h_prevouts)
def get_sequence_hash(self) -> bytes:
return get_tx_hash(self.h_sequence)
def get_outputs_hash(self) -> bytes:
return get_tx_hash(self.h_outputs)
def hash143_preimage_hash(self, txi: TxInputType, pubkeyhash: bytes) -> bytes:
h_preimage = HashWriter(
blake2b(
outlen=32,
personal=b"ZcashSigHash" + struct.pack("<I", self.tx.branch_id),
)
)
# 1. nVersion | fOverwintered
write_uint32(h_preimage, self.tx.version | OVERWINTERED)
# 2. nVersionGroupId
write_uint32(h_preimage, self.tx.version_group_id)
# 3. hashPrevouts
write_bytes_fixed(h_preimage, self.get_prevouts_hash(), TX_HASH_SIZE)
# 4. hashSequence
write_bytes_fixed(h_preimage, self.get_sequence_hash(), TX_HASH_SIZE)
# 5. hashOutputs
write_bytes_fixed(h_preimage, self.get_outputs_hash(), TX_HASH_SIZE)
if self.tx.version == 3:
# 6. hashJoinSplits
write_bytes_fixed(h_preimage, b"\x00" * TX_HASH_SIZE, TX_HASH_SIZE)
# 7. nLockTime
write_uint32(h_preimage, self.tx.lock_time)
# 8. expiryHeight
write_uint32(h_preimage, self.tx.expiry)
# 9. nHashType
write_uint32(h_preimage, self.get_hash_type())
elif self.tx.version == 4:
zero_hash = b"\x00" * TX_HASH_SIZE
# 6. hashJoinSplits
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE)
# 7. hashShieldedSpends
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE)
# 8. hashShieldedOutputs
write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE)
# 9. nLockTime
write_uint32(h_preimage, self.tx.lock_time)
# 10. expiryHeight
write_uint32(h_preimage, self.tx.expiry)
# 11. valueBalance
write_uint64(h_preimage, 0)
# 12. nHashType
write_uint32(h_preimage, self.get_hash_type())
else:
raise SigningError(
FailureType.DataError,
"Unsupported version for overwintered transaction",
)
# 10a /13a. outpoint
write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE)
write_uint32(h_preimage, txi.prev_index)
# 10b / 13b. scriptCode
script_code = derive_script_code(txi, pubkeyhash)
write_bytes_prefixed(h_preimage, script_code)
# 10c / 13c. value
write_uint64(h_preimage, txi.amount)
# 10d / 13d. nSequence
write_uint32(h_preimage, txi.sequence)
return get_tx_hash(h_preimage)
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 SigningError(
FailureType.DataError, "Unknown input script type for zip143 script code"
)

@ -1,14 +1,15 @@
from common import *
from apps.wallet.sign_tx.scripts import output_derive_script
from apps.wallet.sign_tx.segwit_bip143 import *
from apps.wallet.sign_tx.bitcoin import Bitcoin
from apps.common import coins
from trezor.messages.SignTx import SignTx
from trezor.messages.TxInputType import TxInputType
from trezor.messages.TxOutputType import TxOutputType
from trezor.messages.TxOutputBinType import TxOutputBinType
from trezor.messages import InputScriptType
from trezor.messages import OutputScriptType
from trezor.crypto import bip32, bip39
from trezor.crypto import bip39
class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
@ -43,55 +44,51 @@ class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
address_n=[])
def test_prevouts(self):
bip143 = Bip143()
bip143.add_input(self.inp1)
bip143.add_input(self.inp2)
coin = coins.by_name(self.tx.coin_name)
self.assertEqual(hexlify(bip143.get_prevouts_hash(coin)), b'96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37')
bip143 = Bitcoin(self.tx, None, coin)
bip143.hash143_add_input(self.inp1)
bip143.hash143_add_input(self.inp2)
self.assertEqual(hexlify(bip143.get_prevouts_hash()), b'96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37')
def test_sequence(self):
bip143 = Bip143()
bip143.add_input(self.inp1)
bip143.add_input(self.inp2)
coin = coins.by_name(self.tx.coin_name)
self.assertEqual(hexlify(bip143.get_sequence_hash(coin)), b'52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b')
bip143 = Bitcoin(self.tx, None, coin)
bip143.hash143_add_input(self.inp1)
bip143.hash143_add_input(self.inp2)
self.assertEqual(hexlify(bip143.get_sequence_hash()), b'52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b')
def test_outputs(self):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
coin = coins.by_name(self.tx.coin_name)
bip143 = Bip143()
bip143 = Bitcoin(self.tx, None, coin)
for txo in [self.out1, self.out2]:
txo_bin = TxOutputBinType()
txo_bin.amount = txo.amount
txo_bin.script_pubkey = output_derive_script(txo, coin)
bip143.add_output(txo_bin)
bip143.hash143_add_output(txo_bin)
self.assertEqual(hexlify(bip143.get_outputs_hash(coin)),
self.assertEqual(hexlify(bip143.get_outputs_hash()),
b'863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5')
def test_preimage_testdata(self):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
coin = coins.by_name(self.tx.coin_name)
bip143 = Bip143()
bip143.add_input(self.inp1)
bip143.add_input(self.inp2)
bip143 = Bitcoin(self.tx, None, coin)
bip143.hash143_add_input(self.inp1)
bip143.hash143_add_input(self.inp2)
for txo in [self.out1, self.out2]:
txo_bin = TxOutputBinType()
txo_bin.amount = txo.amount
txo_bin.script_pubkey = output_derive_script(txo, coin)
bip143.add_output(txo_bin)
bip143.hash143_add_output(txo_bin)
# test data public key hash
# only for input 2 - input 1 is not segwit
result = bip143.preimage_hash(coin, self.tx, self.inp2, unhexlify('1d0f172a0ecb48aee1be1f2687d2963ae33f71a1'), 0x01)
result = bip143.hash143_preimage_hash(self.inp2, unhexlify('1d0f172a0ecb48aee1be1f2687d2963ae33f71a1'))
self.assertEqual(hexlify(result), b'c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670')

@ -1,14 +1,15 @@
from common import *
from apps.wallet.sign_tx.scripts import output_derive_script
from apps.wallet.sign_tx.segwit_bip143 import *
from apps.wallet.sign_tx.bitcoin import Bitcoin
from apps.common import coins
from trezor.messages.SignTx import SignTx
from trezor.messages.TxInputType import TxInputType
from trezor.messages.TxOutputType import TxOutputType
from trezor.messages.TxOutputBinType import TxOutputBinType
from trezor.messages import InputScriptType
from trezor.messages import OutputScriptType
from trezor.crypto import bip32, bip39
from trezor.crypto import bip39
class TestSegwitBip143(unittest.TestCase):
@ -35,50 +36,44 @@ class TestSegwitBip143(unittest.TestCase):
address_n=[])
def test_bip143_prevouts(self):
bip143 = Bip143()
bip143.add_input(self.inp1)
coin = coins.by_name(self.tx.coin_name)
self.assertEqual(hexlify(bip143.get_prevouts_hash(coin)), b'b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a')
bip143 = Bitcoin(self.tx, None, coin)
bip143.hash143_add_input(self.inp1)
self.assertEqual(hexlify(bip143.get_prevouts_hash()), b'b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a')
def test_bip143_sequence(self):
bip143 = Bip143()
bip143.add_input(self.inp1)
coin = coins.by_name(self.tx.coin_name)
self.assertEqual(hexlify(bip143.get_sequence_hash(coin)), b'18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198')
bip143 = Bitcoin(self.tx, None, coin)
bip143.hash143_add_input(self.inp1)
self.assertEqual(hexlify(bip143.get_sequence_hash()), b'18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198')
def test_bip143_outputs(self):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
coin = coins.by_name(self.tx.coin_name)
bip143 = Bip143()
bip143 = Bitcoin(self.tx, None, coin)
for txo in [self.out1, self.out2]:
txo_bin = TxOutputBinType()
txo_bin.amount = txo.amount
txo_bin.script_pubkey = output_derive_script(txo, coin)
bip143.add_output(txo_bin)
bip143.hash143_add_output(txo_bin)
self.assertEqual(hexlify(bip143.get_outputs_hash(coin)),
self.assertEqual(hexlify(bip143.get_outputs_hash()),
b'de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83')
def test_bip143_preimage_testdata(self):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
coin = coins.by_name(self.tx.coin_name)
bip143 = Bip143()
bip143.add_input(self.inp1)
bip143 = Bitcoin(self.tx, None, coin)
bip143.hash143_add_input(self.inp1)
for txo in [self.out1, self.out2]:
txo_bin = TxOutputBinType()
txo_bin.amount = txo.amount
txo_bin.script_pubkey = output_derive_script(txo, coin)
bip143.add_output(txo_bin)
bip143.hash143_add_output(txo_bin)
# test data public key hash
result = bip143.preimage_hash(coin, self.tx, self.inp1, unhexlify('79091972186c449eb1ded22b78e40d009bdf0089'), 0x01)
result = bip143.hash143_preimage_hash(self.inp1, unhexlify('79091972186c449eb1ded22b78e40d009bdf0089'))
self.assertEqual(hexlify(result), b'64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6')

@ -7,7 +7,7 @@ from trezor.messages.TxOutputBinType import TxOutputBinType
from apps.common import coins
if not utils.BITCOIN_ONLY:
from apps.wallet.sign_tx.zcash import Zip143
from apps.wallet.sign_tx.zcash import Overwintered
# test vectors inspired from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0143.py
@ -153,7 +153,9 @@ class TestZcashZip143(unittest.TestCase):
expiry=v["expiry"],
version_group_id=v["version_group_id"],
)
zip143 = Zip143(0x5ba81b19) # Overwinter
zip143 = Overwintered(tx, None, coin)
for i in v["inputs"]:
txi = TxInputType()
txi.amount = i["amount"]
@ -161,22 +163,18 @@ class TestZcashZip143(unittest.TestCase):
txi.prev_index = i["prevout"][1]
txi.script_type = i["script_type"]
txi.sequence = i["sequence"]
zip143.add_input(txi)
zip143.hash143_add_input(txi)
for o in v["outputs"]:
txo = TxOutputBinType()
txo.amount = o["amount"]
txo.script_pubkey = unhexlify(o["script_pubkey"])
zip143.add_output(txo)
zip143.hash143_add_output(txo)
self.assertEqual(hexlify(zip143.get_prevouts_hash(coin)), v["prevouts_hash"])
self.assertEqual(hexlify(zip143.get_sequence_hash(coin)), v["sequence_hash"])
self.assertEqual(hexlify(zip143.get_outputs_hash(coin)), v["outputs_hash"])
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"]
)
),
hexlify(zip143.hash143_preimage_hash(txi, unhexlify(i["pubkeyhash"]))),
v["preimage_hash"],
)

@ -6,8 +6,7 @@ from trezor.messages.TxOutputBinType import TxOutputBinType
from apps.common import coins
if not utils.BITCOIN_ONLY:
from apps.wallet.sign_tx.zcash import Zip243
from apps.wallet.sign_tx.zcash import Overwintered
# test vectors inspired from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0243.py
@ -187,7 +186,9 @@ class TestZcashZip243(unittest.TestCase):
expiry=v["expiry"],
version_group_id=v["version_group_id"],
)
zip243 = Zip243(0x76b809bb) # Sapling
zip243 = Overwintered(tx, None, coin)
for i in v["inputs"]:
txi = TxInputType()
txi.amount = i["amount"]
@ -195,24 +196,17 @@ class TestZcashZip243(unittest.TestCase):
txi.prev_index = i["prevout"][1]
txi.script_type = i["script_type"]
txi.sequence = i["sequence"]
zip243.add_input(txi)
zip243.hash143_add_input(txi)
for o in v["outputs"]:
txo = TxOutputBinType()
txo.amount = o["amount"]
txo.script_pubkey = unhexlify(o["script_pubkey"])
zip243.add_output(txo)
zip243.hash143_add_output(txo)
self.assertEqual(hexlify(zip243.get_prevouts_hash(coin)), v["prevouts_hash"])
self.assertEqual(hexlify(zip243.get_sequence_hash(coin)), v["sequence_hash"])
self.assertEqual(hexlify(zip243.get_outputs_hash(coin)), v["outputs_hash"])
self.assertEqual(
hexlify(
zip243.preimage_hash(
coin, tx, txi, unhexlify(i["pubkeyhash"]), v["hash_type"]
)
),
v["preimage_hash"],
)
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.hash143_preimage_hash(txi, unhexlify(i["pubkeyhash"]))), v["preimage_hash"])
if __name__ == "__main__":

Loading…
Cancel
Save