mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-02-03 03:11:17 +00:00
core/sign_tx: Merge bip143 classes into signer classes.
This commit is contained in:
parent
6ad3baeab2
commit
22933587be
@ -14,7 +14,6 @@ from apps.wallet.sign_tx import (
|
|||||||
multisig,
|
multisig,
|
||||||
progress,
|
progress,
|
||||||
scripts,
|
scripts,
|
||||||
segwit_bip143,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not utils.BITCOIN_ONLY:
|
if not utils.BITCOIN_ONLY:
|
||||||
@ -52,7 +51,6 @@ async def sign_tx(ctx: wire.Context, msg: SignTx, keychain: seed.Keychain) -> Tx
|
|||||||
multisig.MultisigError,
|
multisig.MultisigError,
|
||||||
addresses.AddressError,
|
addresses.AddressError,
|
||||||
scripts.ScriptsError,
|
scripts.ScriptsError,
|
||||||
segwit_bip143.Bip143Error,
|
|
||||||
) as e:
|
) as e:
|
||||||
raise wire.Error(*e.args)
|
raise wire.Error(*e.args)
|
||||||
if isinstance(req, TxRequest):
|
if isinstance(req, TxRequest):
|
||||||
|
@ -20,7 +20,6 @@ from apps.wallet.sign_tx import (
|
|||||||
multisig,
|
multisig,
|
||||||
progress,
|
progress,
|
||||||
scripts,
|
scripts,
|
||||||
segwit_bip143,
|
|
||||||
tx_weight,
|
tx_weight,
|
||||||
writers,
|
writers,
|
||||||
)
|
)
|
||||||
@ -113,10 +112,12 @@ class Bitcoin:
|
|||||||
self.h_confirmed = self.create_hash_writer() # not a real tx hash
|
self.h_confirmed = self.create_hash_writer() # not a real tx hash
|
||||||
|
|
||||||
# BIP-0143 transaction hashing
|
# BIP-0143 transaction hashing
|
||||||
self.hash143 = self.create_hash143()
|
self.init_hash143()
|
||||||
|
|
||||||
def create_hash143(self) -> segwit_bip143.Bip143:
|
def init_hash143(self) -> None:
|
||||||
return segwit_bip143.Bip143()
|
self.h_prevouts = HashWriter(sha256())
|
||||||
|
self.h_sequence = HashWriter(sha256())
|
||||||
|
self.h_outputs = HashWriter(sha256())
|
||||||
|
|
||||||
def create_hash_writer(self) -> HashWriter:
|
def create_hash_writer(self) -> HashWriter:
|
||||||
return HashWriter(sha256())
|
return HashWriter(sha256())
|
||||||
@ -194,7 +195,7 @@ class Bitcoin:
|
|||||||
self.wallet_path.add_input(txi)
|
self.wallet_path.add_input(txi)
|
||||||
self.multisig_fingerprint.add_input(txi)
|
self.multisig_fingerprint.add_input(txi)
|
||||||
writers.write_tx_input_check(self.h_confirmed, 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):
|
if not addresses.validate_full_path(txi.address_n, self.coin, txi.script_type):
|
||||||
await helpers.confirm_foreign_address(txi.address_n)
|
await helpers.confirm_foreign_address(txi.address_n)
|
||||||
@ -231,7 +232,7 @@ class Bitcoin:
|
|||||||
raise SigningError(FailureType.ActionCancelled, "Output cancelled")
|
raise SigningError(FailureType.ActionCancelled, "Output cancelled")
|
||||||
|
|
||||||
writers.write_tx_output(self.h_confirmed, txo_bin)
|
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
|
self.total_out += txo_bin.amount
|
||||||
|
|
||||||
def on_negative_fee(self) -> None:
|
def on_negative_fee(self) -> None:
|
||||||
@ -267,12 +268,8 @@ class Bitcoin:
|
|||||||
|
|
||||||
node = self.keychain.derive(txi.address_n, self.coin.curve_name)
|
node = self.keychain.derive(txi.address_n, self.coin.curve_name)
|
||||||
public_key = node.public_key()
|
public_key = node.public_key()
|
||||||
hash143_hash = self.hash143.preimage_hash(
|
hash143_hash = self.hash143_preimage_hash(
|
||||||
self.coin,
|
txi, addresses.ecdsa_hash_pubkey(public_key, self.coin)
|
||||||
self.tx,
|
|
||||||
txi,
|
|
||||||
addresses.ecdsa_hash_pubkey(public_key, self.coin),
|
|
||||||
self.get_hash_type(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
signature = ecdsa_sign(node, hash143_hash)
|
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.
|
# Validations to perform on the UTXO when checking the previous transaction output amount.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# TX Helpers
|
# Tx Helpers
|
||||||
# ===
|
# ===
|
||||||
|
|
||||||
def get_hash_type(self) -> int:
|
def get_hash_type(self) -> int:
|
||||||
@ -472,7 +469,7 @@ class Bitcoin:
|
|||||||
self.tx_req.serialized.signature_index = index
|
self.tx_req.serialized.signature_index = index
|
||||||
self.tx_req.serialized.signature = signature
|
self.tx_req.serialized.signature = signature
|
||||||
|
|
||||||
# TX Outputs
|
# Tx Outputs
|
||||||
# ===
|
# ===
|
||||||
|
|
||||||
def output_derive_script(self, txo: TxOutputType) -> bytes:
|
def output_derive_script(self, txo: TxOutputType) -> bytes:
|
||||||
@ -512,6 +509,71 @@ class Bitcoin:
|
|||||||
txi, self.coin, self.get_hash_type(), pubkey, signature
|
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:
|
def input_is_segwit(txi: TxInputType) -> bool:
|
||||||
return txi.script_type in helpers.SEGWIT_INPUT_SCRIPT_TYPES
|
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 import addresses, helpers, multisig, progress, scripts, writers
|
||||||
from apps.wallet.sign_tx.bitcoin import Bitcoin
|
from apps.wallet.sign_tx.bitcoin import Bitcoin
|
||||||
from apps.wallet.sign_tx.common import SigningError, ecdsa_sign
|
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_FULL = const(0 << 16)
|
||||||
DECRED_SERIALIZE_NO_WITNESS = const(1 << 16)
|
DECRED_SERIALIZE_NO_WITNESS = const(1 << 16)
|
||||||
@ -26,35 +25,6 @@ if False:
|
|||||||
from typing import Union
|
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):
|
class Decred(Bitcoin):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo
|
self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo
|
||||||
@ -62,23 +32,25 @@ class Decred(Bitcoin):
|
|||||||
ensure(coin.decred)
|
ensure(coin.decred)
|
||||||
super().__init__(tx, keychain, coin)
|
super().__init__(tx, keychain, coin)
|
||||||
|
|
||||||
def create_hash143(self) -> Bip143:
|
self.write_tx_header(self.serialized_tx, self.tx, has_segwit=False)
|
||||||
return DecredPrefixHasher(self.tx) # pseudo BIP-0143 prefix hashing
|
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:
|
def create_hash_writer(self) -> HashWriter:
|
||||||
return HashWriter(blake256())
|
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:
|
async def step2_confirm_outputs(self) -> None:
|
||||||
writers.write_varint(self.serialized_tx, self.tx.outputs_count)
|
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()
|
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.serialized_tx, self.tx)
|
||||||
|
self.write_tx_footer(self.h_prefix, self.tx)
|
||||||
|
|
||||||
async def process_input(self, i: int, txi: TxInputType) -> None:
|
async def process_input(self, i: int, txi: TxInputType) -> None:
|
||||||
await super().process_input(i, txi)
|
await super().process_input(i, txi)
|
||||||
@ -95,14 +67,13 @@ class Decred(Bitcoin):
|
|||||||
"Cannot send to output with script version != 0",
|
"Cannot send to output with script version != 0",
|
||||||
)
|
)
|
||||||
txo_bin.decred_script_version = txo.decred_script_version
|
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)
|
await super().confirm_output(i, txo, txo_bin)
|
||||||
|
writers.write_tx_output(self.serialized_tx, txo_bin)
|
||||||
|
|
||||||
async def step4_serialize_inputs(self) -> None:
|
async def step4_serialize_inputs(self) -> None:
|
||||||
writers.write_varint(self.serialized_tx, self.tx.inputs_count)
|
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):
|
for i_sign in range(self.tx.inputs_count):
|
||||||
progress.advance()
|
progress.advance()
|
||||||
@ -179,6 +150,12 @@ class Decred(Bitcoin):
|
|||||||
"Cannot use utxo that has script_version != 0",
|
"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:
|
def write_tx_input(self, w: writers.Writer, txi: TxInputType) -> None:
|
||||||
writers.write_tx_input_decred(w, txi)
|
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")
|
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
|
# P2PKH, P2SH
|
||||||
# ===
|
# ===
|
||||||
# https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
|
# 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.common import SigningError
|
||||||
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
|
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.scripts import output_script_multisig, output_script_p2pkh
|
||||||
from apps.wallet.sign_tx.segwit_bip143 import Bip143
|
|
||||||
from apps.wallet.sign_tx.writers import (
|
from apps.wallet.sign_tx.writers import (
|
||||||
TX_HASH_SIZE,
|
TX_HASH_SIZE,
|
||||||
get_tx_hash,
|
get_tx_hash,
|
||||||
@ -34,167 +33,28 @@ if False:
|
|||||||
OVERWINTERED = const(0x80000000)
|
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):
|
class Overwintered(Bitcoinlike):
|
||||||
def __init__(self, tx: SignTx, keychain: Keychain, coin: CoinInfo) -> None:
|
def __init__(self, tx: SignTx, keychain: Keychain, coin: CoinInfo) -> None:
|
||||||
ensure(coin.overwintered)
|
ensure(coin.overwintered)
|
||||||
super().__init__(tx, keychain, coin)
|
super().__init__(tx, keychain, coin)
|
||||||
|
|
||||||
def create_hash143(self) -> Bip143:
|
|
||||||
if self.tx.version == 3:
|
if self.tx.version == 3:
|
||||||
branch_id = self.tx.branch_id or 0x5BA81B19 # Overwinter
|
if not self.tx.branch_id:
|
||||||
return Zip143(branch_id) # ZIP-0143 transaction hashing
|
self.tx.branch_id = 0x5BA81B19 # Overwinter
|
||||||
elif self.tx.version == 4:
|
elif self.tx.version == 4:
|
||||||
branch_id = self.tx.branch_id or 0x76B809BB # Sapling
|
if not self.tx.branch_id:
|
||||||
return Zip243(branch_id) # ZIP-0243 transaction hashing
|
self.tx.branch_id = 0x76B809BB # Sapling
|
||||||
else:
|
else:
|
||||||
raise SigningError(
|
raise SigningError(
|
||||||
FailureType.DataError,
|
FailureType.DataError,
|
||||||
"Unsupported version for overwintered transaction",
|
"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:
|
async def step7_finish(self) -> None:
|
||||||
self.write_tx_footer(self.serialized_tx, self.tx)
|
self.write_tx_footer(self.serialized_tx, self.tx)
|
||||||
|
|
||||||
@ -227,3 +87,98 @@ class Overwintered(Bitcoinlike):
|
|||||||
# nVersion | fOverwintered
|
# nVersion | fOverwintered
|
||||||
write_uint32(w, tx.version | OVERWINTERED)
|
write_uint32(w, tx.version | OVERWINTERED)
|
||||||
write_uint32(w, tx.version_group_id) # nVersionGroupId
|
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 common import *
|
||||||
|
|
||||||
from apps.wallet.sign_tx.scripts import output_derive_script
|
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 apps.common import coins
|
||||||
from trezor.messages.SignTx import SignTx
|
from trezor.messages.SignTx import SignTx
|
||||||
from trezor.messages.TxInputType import TxInputType
|
from trezor.messages.TxInputType import TxInputType
|
||||||
from trezor.messages.TxOutputType import TxOutputType
|
from trezor.messages.TxOutputType import TxOutputType
|
||||||
|
from trezor.messages.TxOutputBinType import TxOutputBinType
|
||||||
from trezor.messages import InputScriptType
|
from trezor.messages import InputScriptType
|
||||||
from trezor.messages import OutputScriptType
|
from trezor.messages import OutputScriptType
|
||||||
from trezor.crypto import bip32, bip39
|
from trezor.crypto import bip39
|
||||||
|
|
||||||
|
|
||||||
class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
|
class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
|
||||||
@ -43,55 +44,51 @@ class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
|
|||||||
address_n=[])
|
address_n=[])
|
||||||
|
|
||||||
def test_prevouts(self):
|
def test_prevouts(self):
|
||||||
|
|
||||||
bip143 = Bip143()
|
|
||||||
bip143.add_input(self.inp1)
|
|
||||||
bip143.add_input(self.inp2)
|
|
||||||
coin = coins.by_name(self.tx.coin_name)
|
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):
|
def test_sequence(self):
|
||||||
|
|
||||||
bip143 = Bip143()
|
|
||||||
bip143.add_input(self.inp1)
|
|
||||||
bip143.add_input(self.inp2)
|
|
||||||
coin = coins.by_name(self.tx.coin_name)
|
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):
|
def test_outputs(self):
|
||||||
|
|
||||||
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
|
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
|
||||||
coin = coins.by_name(self.tx.coin_name)
|
coin = coins.by_name(self.tx.coin_name)
|
||||||
|
bip143 = Bitcoin(self.tx, None, coin)
|
||||||
bip143 = Bip143()
|
|
||||||
|
|
||||||
for txo in [self.out1, self.out2]:
|
for txo in [self.out1, self.out2]:
|
||||||
txo_bin = TxOutputBinType()
|
txo_bin = TxOutputBinType()
|
||||||
txo_bin.amount = txo.amount
|
txo_bin.amount = txo.amount
|
||||||
txo_bin.script_pubkey = output_derive_script(txo, coin)
|
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')
|
b'863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5')
|
||||||
|
|
||||||
def test_preimage_testdata(self):
|
def test_preimage_testdata(self):
|
||||||
|
|
||||||
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
|
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
|
||||||
coin = coins.by_name(self.tx.coin_name)
|
coin = coins.by_name(self.tx.coin_name)
|
||||||
|
bip143 = Bitcoin(self.tx, None, coin)
|
||||||
bip143 = Bip143()
|
bip143.hash143_add_input(self.inp1)
|
||||||
bip143.add_input(self.inp1)
|
bip143.hash143_add_input(self.inp2)
|
||||||
bip143.add_input(self.inp2)
|
|
||||||
|
|
||||||
for txo in [self.out1, self.out2]:
|
for txo in [self.out1, self.out2]:
|
||||||
txo_bin = TxOutputBinType()
|
txo_bin = TxOutputBinType()
|
||||||
txo_bin.amount = txo.amount
|
txo_bin.amount = txo.amount
|
||||||
txo_bin.script_pubkey = output_derive_script(txo, coin)
|
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
|
# test data public key hash
|
||||||
# only for input 2 - input 1 is not segwit
|
# 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')
|
self.assertEqual(hexlify(result), b'c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670')
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
from common import *
|
from common import *
|
||||||
|
|
||||||
from apps.wallet.sign_tx.scripts import output_derive_script
|
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 apps.common import coins
|
||||||
from trezor.messages.SignTx import SignTx
|
from trezor.messages.SignTx import SignTx
|
||||||
from trezor.messages.TxInputType import TxInputType
|
from trezor.messages.TxInputType import TxInputType
|
||||||
from trezor.messages.TxOutputType import TxOutputType
|
from trezor.messages.TxOutputType import TxOutputType
|
||||||
|
from trezor.messages.TxOutputBinType import TxOutputBinType
|
||||||
from trezor.messages import InputScriptType
|
from trezor.messages import InputScriptType
|
||||||
from trezor.messages import OutputScriptType
|
from trezor.messages import OutputScriptType
|
||||||
from trezor.crypto import bip32, bip39
|
from trezor.crypto import bip39
|
||||||
|
|
||||||
|
|
||||||
class TestSegwitBip143(unittest.TestCase):
|
class TestSegwitBip143(unittest.TestCase):
|
||||||
@ -35,50 +36,44 @@ class TestSegwitBip143(unittest.TestCase):
|
|||||||
address_n=[])
|
address_n=[])
|
||||||
|
|
||||||
def test_bip143_prevouts(self):
|
def test_bip143_prevouts(self):
|
||||||
|
|
||||||
bip143 = Bip143()
|
|
||||||
bip143.add_input(self.inp1)
|
|
||||||
coin = coins.by_name(self.tx.coin_name)
|
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):
|
def test_bip143_sequence(self):
|
||||||
|
|
||||||
bip143 = Bip143()
|
|
||||||
bip143.add_input(self.inp1)
|
|
||||||
coin = coins.by_name(self.tx.coin_name)
|
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):
|
def test_bip143_outputs(self):
|
||||||
|
|
||||||
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
|
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
|
||||||
coin = coins.by_name(self.tx.coin_name)
|
coin = coins.by_name(self.tx.coin_name)
|
||||||
|
bip143 = Bitcoin(self.tx, None, coin)
|
||||||
bip143 = Bip143()
|
|
||||||
|
|
||||||
for txo in [self.out1, self.out2]:
|
for txo in [self.out1, self.out2]:
|
||||||
txo_bin = TxOutputBinType()
|
txo_bin = TxOutputBinType()
|
||||||
txo_bin.amount = txo.amount
|
txo_bin.amount = txo.amount
|
||||||
txo_bin.script_pubkey = output_derive_script(txo, coin)
|
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')
|
b'de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83')
|
||||||
|
|
||||||
def test_bip143_preimage_testdata(self):
|
def test_bip143_preimage_testdata(self):
|
||||||
|
|
||||||
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
|
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
|
||||||
coin = coins.by_name(self.tx.coin_name)
|
coin = coins.by_name(self.tx.coin_name)
|
||||||
|
bip143 = Bitcoin(self.tx, None, coin)
|
||||||
bip143 = Bip143()
|
bip143.hash143_add_input(self.inp1)
|
||||||
bip143.add_input(self.inp1)
|
|
||||||
for txo in [self.out1, self.out2]:
|
for txo in [self.out1, self.out2]:
|
||||||
txo_bin = TxOutputBinType()
|
txo_bin = TxOutputBinType()
|
||||||
txo_bin.amount = txo.amount
|
txo_bin.amount = txo.amount
|
||||||
txo_bin.script_pubkey = output_derive_script(txo, coin)
|
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
|
# 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')
|
self.assertEqual(hexlify(result), b'64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6')
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ from trezor.messages.TxOutputBinType import TxOutputBinType
|
|||||||
from apps.common import coins
|
from apps.common import coins
|
||||||
|
|
||||||
if not utils.BITCOIN_ONLY:
|
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
|
# 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"],
|
expiry=v["expiry"],
|
||||||
version_group_id=v["version_group_id"],
|
version_group_id=v["version_group_id"],
|
||||||
)
|
)
|
||||||
zip143 = Zip143(0x5ba81b19) # Overwinter
|
|
||||||
|
zip143 = Overwintered(tx, None, coin)
|
||||||
|
|
||||||
for i in v["inputs"]:
|
for i in v["inputs"]:
|
||||||
txi = TxInputType()
|
txi = TxInputType()
|
||||||
txi.amount = i["amount"]
|
txi.amount = i["amount"]
|
||||||
@ -161,22 +163,18 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
txi.prev_index = i["prevout"][1]
|
txi.prev_index = i["prevout"][1]
|
||||||
txi.script_type = i["script_type"]
|
txi.script_type = i["script_type"]
|
||||||
txi.sequence = i["sequence"]
|
txi.sequence = i["sequence"]
|
||||||
zip143.add_input(txi)
|
zip143.hash143_add_input(txi)
|
||||||
for o in v["outputs"]:
|
for o in v["outputs"]:
|
||||||
txo = TxOutputBinType()
|
txo = TxOutputBinType()
|
||||||
txo.amount = o["amount"]
|
txo.amount = o["amount"]
|
||||||
txo.script_pubkey = unhexlify(o["script_pubkey"])
|
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_prevouts_hash()), v["prevouts_hash"])
|
||||||
self.assertEqual(hexlify(zip143.get_sequence_hash(coin)), v["sequence_hash"])
|
self.assertEqual(hexlify(zip143.get_sequence_hash()), v["sequence_hash"])
|
||||||
self.assertEqual(hexlify(zip143.get_outputs_hash(coin)), v["outputs_hash"])
|
self.assertEqual(hexlify(zip143.get_outputs_hash()), v["outputs_hash"])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
hexlify(
|
hexlify(zip143.hash143_preimage_hash(txi, unhexlify(i["pubkeyhash"]))),
|
||||||
zip143.preimage_hash(
|
|
||||||
coin, tx, txi, unhexlify(i["pubkeyhash"]), v["hash_type"]
|
|
||||||
)
|
|
||||||
),
|
|
||||||
v["preimage_hash"],
|
v["preimage_hash"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -6,8 +6,7 @@ from trezor.messages.TxOutputBinType import TxOutputBinType
|
|||||||
|
|
||||||
from apps.common import coins
|
from apps.common import coins
|
||||||
|
|
||||||
if not utils.BITCOIN_ONLY:
|
from apps.wallet.sign_tx.zcash import Overwintered
|
||||||
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
|
# 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"],
|
expiry=v["expiry"],
|
||||||
version_group_id=v["version_group_id"],
|
version_group_id=v["version_group_id"],
|
||||||
)
|
)
|
||||||
zip243 = Zip243(0x76b809bb) # Sapling
|
|
||||||
|
zip243 = Overwintered(tx, None, coin)
|
||||||
|
|
||||||
for i in v["inputs"]:
|
for i in v["inputs"]:
|
||||||
txi = TxInputType()
|
txi = TxInputType()
|
||||||
txi.amount = i["amount"]
|
txi.amount = i["amount"]
|
||||||
@ -195,24 +196,17 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
txi.prev_index = i["prevout"][1]
|
txi.prev_index = i["prevout"][1]
|
||||||
txi.script_type = i["script_type"]
|
txi.script_type = i["script_type"]
|
||||||
txi.sequence = i["sequence"]
|
txi.sequence = i["sequence"]
|
||||||
zip243.add_input(txi)
|
zip243.hash143_add_input(txi)
|
||||||
for o in v["outputs"]:
|
for o in v["outputs"]:
|
||||||
txo = TxOutputBinType()
|
txo = TxOutputBinType()
|
||||||
txo.amount = o["amount"]
|
txo.amount = o["amount"]
|
||||||
txo.script_pubkey = unhexlify(o["script_pubkey"])
|
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_prevouts_hash()), v["prevouts_hash"])
|
||||||
self.assertEqual(hexlify(zip243.get_sequence_hash(coin)), v["sequence_hash"])
|
self.assertEqual(hexlify(zip243.get_sequence_hash()), v["sequence_hash"])
|
||||||
self.assertEqual(hexlify(zip243.get_outputs_hash(coin)), v["outputs_hash"])
|
self.assertEqual(hexlify(zip243.get_outputs_hash()), v["outputs_hash"])
|
||||||
self.assertEqual(
|
self.assertEqual(hexlify(zip243.hash143_preimage_hash(txi, unhexlify(i["pubkeyhash"]))), v["preimage_hash"])
|
||||||
hexlify(
|
|
||||||
zip243.preimage_hash(
|
|
||||||
coin, tx, txi, unhexlify(i["pubkeyhash"]), v["hash_type"]
|
|
||||||
)
|
|
||||||
),
|
|
||||||
v["preimage_hash"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
Reference in New Issue
Block a user