mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-24 15:28:10 +00:00
core/sign_tx: Implement support for signed external inputs.
This commit is contained in:
parent
78f14d286e
commit
d48a372ca7
@ -110,22 +110,22 @@ def output_derive_script(address: str, coin: CoinInfo) -> bytes:
|
|||||||
|
|
||||||
# see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
|
# see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
|
||||||
# item 5 for details
|
# item 5 for details
|
||||||
def bip143_derive_script_code(txi: TxInputType, pubkeyhash: bytes) -> bytearray:
|
def bip143_derive_script_code(
|
||||||
|
txi: TxInputType, public_keys: List[bytes], threshold: int, coin: CoinInfo
|
||||||
if txi.multisig:
|
) -> bytearray:
|
||||||
return output_script_multisig(
|
if len(public_keys) > 1:
|
||||||
multisig_get_pubkeys(txi.multisig), txi.multisig.m
|
return output_script_multisig(public_keys, threshold)
|
||||||
)
|
|
||||||
|
|
||||||
p2pkh = (
|
p2pkh = (
|
||||||
txi.script_type == InputScriptType.SPENDWITNESS
|
txi.script_type == InputScriptType.SPENDWITNESS
|
||||||
or txi.script_type == InputScriptType.SPENDP2SHWITNESS
|
or txi.script_type == InputScriptType.SPENDP2SHWITNESS
|
||||||
or txi.script_type == InputScriptType.SPENDADDRESS
|
or txi.script_type == InputScriptType.SPENDADDRESS
|
||||||
|
or txi.script_type == InputScriptType.EXTERNAL
|
||||||
)
|
)
|
||||||
if p2pkh:
|
if p2pkh:
|
||||||
# for p2wpkh in p2sh or native p2wpkh
|
# for p2wpkh in p2sh or native p2wpkh
|
||||||
# the scriptCode is a classic p2pkh
|
# the scriptCode is a classic p2pkh
|
||||||
return output_script_p2pkh(pubkeyhash)
|
return output_script_p2pkh(common.ecdsa_hash_pubkey(public_keys[0], coin))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise wire.DataError("Unknown input script type for bip143 script code")
|
raise wire.DataError("Unknown input script type for bip143 script code")
|
||||||
|
@ -3,7 +3,7 @@ from micropython import const
|
|||||||
|
|
||||||
from trezor import wire
|
from trezor import wire
|
||||||
from trezor.crypto.hashlib import sha256
|
from trezor.crypto.hashlib import sha256
|
||||||
from trezor.messages import InputScriptType
|
from trezor.messages import InputScriptType, OutputScriptType
|
||||||
from trezor.messages.SignTx import SignTx
|
from trezor.messages.SignTx import SignTx
|
||||||
from trezor.messages.TransactionType import TransactionType
|
from trezor.messages.TransactionType import TransactionType
|
||||||
from trezor.messages.TxInputType import TxInputType
|
from trezor.messages.TxInputType import TxInputType
|
||||||
@ -18,12 +18,13 @@ from apps.common import coininfo, seed
|
|||||||
from apps.common.writers import write_bitcoin_varint
|
from apps.common.writers import write_bitcoin_varint
|
||||||
|
|
||||||
from .. import addresses, common, multisig, scripts, writers
|
from .. import addresses, common, multisig, scripts, writers
|
||||||
from ..common import ecdsa_hash_pubkey, ecdsa_sign
|
from ..common import ecdsa_sign
|
||||||
|
from ..verification import SignatureVerifier
|
||||||
from . import helpers, progress, tx_weight
|
from . import helpers, progress, tx_weight
|
||||||
from .matchcheck import MultisigFingerprintChecker, WalletPathChecker
|
from .matchcheck import MultisigFingerprintChecker, WalletPathChecker
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import Set, Optional, Tuple, Union
|
from typing import List, Optional, Set, Tuple, Union
|
||||||
from trezor.crypto.bip32 import HDNode
|
from trezor.crypto.bip32 import HDNode
|
||||||
|
|
||||||
# Default signature hash type in Bitcoin which signs all inputs and all outputs of the transaction.
|
# Default signature hash type in Bitcoin which signs all inputs and all outputs of the transaction.
|
||||||
@ -42,8 +43,6 @@ _MAX_SERIALIZED_CHUNK_SIZE = const(2048)
|
|||||||
|
|
||||||
class Bitcoin:
|
class Bitcoin:
|
||||||
async def signer(self) -> None:
|
async def signer(self) -> None:
|
||||||
progress.init(self.tx.inputs_count, self.tx.outputs_count)
|
|
||||||
|
|
||||||
# Add inputs to hash143 and h_confirmed and compute the sum of input amounts
|
# Add inputs to hash143 and h_confirmed and compute the sum of input amounts
|
||||||
# by requesting each previous transaction and checking its output amounts.
|
# by requesting each previous transaction and checking its output amounts.
|
||||||
await self.step1_process_inputs()
|
await self.step1_process_inputs()
|
||||||
@ -55,17 +54,20 @@ class Bitcoin:
|
|||||||
# Check fee, confirm lock_time and total.
|
# Check fee, confirm lock_time and total.
|
||||||
await self.step3_confirm_tx()
|
await self.step3_confirm_tx()
|
||||||
|
|
||||||
|
# Verify external inputs which have already been signed.
|
||||||
|
await self.step4_verify_external_inputs()
|
||||||
|
|
||||||
# Check that inputs are unchanged. Serialize inputs and sign the non-segwit ones.
|
# Check that inputs are unchanged. Serialize inputs and sign the non-segwit ones.
|
||||||
await self.step4_serialize_inputs()
|
await self.step5_serialize_inputs()
|
||||||
|
|
||||||
# Serialize outputs.
|
# Serialize outputs.
|
||||||
await self.step5_serialize_outputs()
|
await self.step6_serialize_outputs()
|
||||||
|
|
||||||
# Sign segwit inputs and serialize witness data.
|
# Sign segwit inputs and serialize witness data.
|
||||||
await self.step6_sign_segwit_inputs()
|
await self.step7_sign_segwit_inputs()
|
||||||
|
|
||||||
# Write footer and send remaining data.
|
# Write footer and send remaining data.
|
||||||
await self.step7_finish()
|
await self.step8_finish()
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo
|
self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo
|
||||||
@ -83,8 +85,12 @@ class Bitcoin:
|
|||||||
# set of indices of inputs which are segwit
|
# set of indices of inputs which are segwit
|
||||||
self.segwit = set() # type: Set[int]
|
self.segwit = set() # type: Set[int]
|
||||||
|
|
||||||
|
# set of indices of inputs which are external
|
||||||
|
self.external = set() # type: Set[int]
|
||||||
|
|
||||||
# amounts
|
# amounts
|
||||||
self.total_in = 0 # sum of input amounts
|
self.total_in = 0 # sum of input amounts
|
||||||
|
self.external_in = 0 # sum of external input amounts
|
||||||
self.total_out = 0 # sum of output amounts
|
self.total_out = 0 # sum of output amounts
|
||||||
self.change_out = 0 # change output amount
|
self.change_out = 0 # change output amount
|
||||||
self.weight = tx_weight.TxWeightCalculator(tx.inputs_count, tx.outputs_count)
|
self.weight = tx_weight.TxWeightCalculator(tx.inputs_count, tx.outputs_count)
|
||||||
@ -98,24 +104,36 @@ class Bitcoin:
|
|||||||
|
|
||||||
# h_confirmed is used to make sure that the inputs and outputs streamed for
|
# h_confirmed is used to make sure that the inputs and outputs streamed for
|
||||||
# confirmation in Steps 1 and 2 are the same as the ones streamed for signing
|
# confirmation in Steps 1 and 2 are the same as the ones streamed for signing
|
||||||
# legacy inputs in Step 4.
|
# legacy inputs in Step 5.
|
||||||
self.h_confirmed = self.create_hash_writer() # not a real tx hash
|
self.h_confirmed = self.create_hash_writer() # not a real tx hash
|
||||||
|
|
||||||
|
# h_external is used to make sure that the signed external inputs streamed for
|
||||||
|
# confirmation in Step 1 are the same as the ones streamed for verification
|
||||||
|
# in Step 3.
|
||||||
|
self.h_external = self.create_hash_writer()
|
||||||
|
|
||||||
# BIP-0143 transaction hashing
|
# BIP-0143 transaction hashing
|
||||||
self.init_hash143()
|
self.init_hash143()
|
||||||
|
|
||||||
|
progress.init(self.tx.inputs_count, self.tx.outputs_count)
|
||||||
|
|
||||||
def create_hash_writer(self) -> HashWriter:
|
def create_hash_writer(self) -> HashWriter:
|
||||||
return HashWriter(sha256())
|
return HashWriter(sha256())
|
||||||
|
|
||||||
async def step1_process_inputs(self) -> None:
|
async def step1_process_inputs(self) -> None:
|
||||||
for i in range(self.tx.inputs_count):
|
for i in range(self.tx.inputs_count):
|
||||||
# STAGE_REQUEST_1_INPUT in legacy
|
# STAGE_REQUEST_1_INPUT in legacy
|
||||||
progress.advance()
|
|
||||||
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
|
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
|
||||||
self.weight.add_input(txi)
|
self.weight.add_input(txi)
|
||||||
if input_is_segwit(txi):
|
if input_is_segwit(txi):
|
||||||
self.segwit.add(i)
|
self.segwit.add(i)
|
||||||
await self.process_input(txi)
|
|
||||||
|
if input_is_external(txi):
|
||||||
|
self.external.add(i)
|
||||||
|
await self.process_external_input(txi)
|
||||||
|
else:
|
||||||
|
progress.advance()
|
||||||
|
await self.process_internal_input(txi)
|
||||||
|
|
||||||
async def step2_confirm_outputs(self) -> None:
|
async def step2_confirm_outputs(self) -> None:
|
||||||
for i in range(self.tx.outputs_count):
|
for i in range(self.tx.outputs_count):
|
||||||
@ -136,40 +154,80 @@ class Bitcoin:
|
|||||||
await helpers.confirm_feeoverthreshold(fee, self.coin)
|
await helpers.confirm_feeoverthreshold(fee, self.coin)
|
||||||
if self.tx.lock_time > 0:
|
if self.tx.lock_time > 0:
|
||||||
await helpers.confirm_nondefault_locktime(self.tx.lock_time)
|
await helpers.confirm_nondefault_locktime(self.tx.lock_time)
|
||||||
await helpers.confirm_total(self.total_in - self.change_out, fee, self.coin)
|
await helpers.confirm_total(
|
||||||
|
self.total_in - self.external_in - self.change_out, fee, self.coin
|
||||||
|
)
|
||||||
|
|
||||||
async def step4_serialize_inputs(self) -> None:
|
async def step4_verify_external_inputs(self) -> None:
|
||||||
|
# should come out the same as h_external, checked before continuing
|
||||||
|
h_check = self.create_hash_writer()
|
||||||
|
|
||||||
|
for i in sorted(self.external):
|
||||||
|
progress.advance()
|
||||||
|
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
|
||||||
|
writers.write_tx_input_check(h_check, txi)
|
||||||
|
prev_amount, script_pubkey = await self.get_prevtx_output(
|
||||||
|
txi.prev_hash, txi.prev_index
|
||||||
|
)
|
||||||
|
if prev_amount != txi.amount:
|
||||||
|
raise wire.DataError("Invalid amount specified")
|
||||||
|
|
||||||
|
verifier = SignatureVerifier(
|
||||||
|
script_pubkey, txi.script_sig, txi.witness, self.coin
|
||||||
|
)
|
||||||
|
|
||||||
|
verifier.ensure_hash_type(self.get_hash_type(txi))
|
||||||
|
|
||||||
|
tx_digest = await self.get_tx_digest(
|
||||||
|
i, txi, verifier.public_keys, verifier.threshold, script_pubkey
|
||||||
|
)
|
||||||
|
verifier.verify(tx_digest)
|
||||||
|
|
||||||
|
# check that the inputs were the same as those streamed for confirmation
|
||||||
|
if self.h_external.get_digest() != h_check.get_digest():
|
||||||
|
raise wire.ProcessError("Transaction has changed during signing")
|
||||||
|
|
||||||
|
async def step5_serialize_inputs(self) -> None:
|
||||||
self.write_tx_header(self.serialized_tx, self.tx, bool(self.segwit))
|
self.write_tx_header(self.serialized_tx, self.tx, bool(self.segwit))
|
||||||
write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count)
|
write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count)
|
||||||
|
|
||||||
for i in range(self.tx.inputs_count):
|
for i in range(self.tx.inputs_count):
|
||||||
progress.advance()
|
progress.advance()
|
||||||
if i in self.segwit:
|
if i in self.external:
|
||||||
|
await self.serialize_external_input(i)
|
||||||
|
elif i in self.segwit:
|
||||||
await self.serialize_segwit_input(i)
|
await self.serialize_segwit_input(i)
|
||||||
else:
|
else:
|
||||||
await self.sign_nonsegwit_input(i)
|
await self.sign_nonsegwit_input(i)
|
||||||
|
|
||||||
async def step5_serialize_outputs(self) -> None:
|
async def step6_serialize_outputs(self) -> None:
|
||||||
write_bitcoin_varint(self.serialized_tx, self.tx.outputs_count)
|
write_bitcoin_varint(self.serialized_tx, self.tx.outputs_count)
|
||||||
for i in range(self.tx.outputs_count):
|
for i in range(self.tx.outputs_count):
|
||||||
progress.advance()
|
progress.advance()
|
||||||
await self.serialize_output(i)
|
await self.serialize_output(i)
|
||||||
|
|
||||||
async def step6_sign_segwit_inputs(self) -> None:
|
async def step7_sign_segwit_inputs(self) -> None:
|
||||||
any_segwit = bool(self.segwit)
|
if not self.segwit:
|
||||||
|
progress.advance(self.tx.inputs_count)
|
||||||
|
return
|
||||||
|
|
||||||
for i in range(self.tx.inputs_count):
|
for i in range(self.tx.inputs_count):
|
||||||
progress.advance()
|
progress.advance()
|
||||||
if i in self.segwit:
|
if i in self.segwit:
|
||||||
await self.sign_segwit_input(i)
|
if i in self.external:
|
||||||
elif any_segwit:
|
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
|
||||||
|
self.serialized_tx.extend(txi.witness)
|
||||||
|
else:
|
||||||
|
await self.sign_segwit_input(i)
|
||||||
|
else:
|
||||||
# add empty witness for non-segwit inputs
|
# add empty witness for non-segwit inputs
|
||||||
self.serialized_tx.append(0)
|
self.serialized_tx.append(0)
|
||||||
|
|
||||||
async def step7_finish(self) -> None:
|
async def step8_finish(self) -> None:
|
||||||
self.write_tx_footer(self.serialized_tx, self.tx)
|
self.write_tx_footer(self.serialized_tx, self.tx)
|
||||||
await helpers.request_tx_finish(self.tx_req)
|
await helpers.request_tx_finish(self.tx_req)
|
||||||
|
|
||||||
async def process_input(self, txi: TxInputType) -> None:
|
async def process_internal_input(self, txi: TxInputType) -> None:
|
||||||
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)
|
||||||
@ -190,6 +248,16 @@ class Bitcoin:
|
|||||||
|
|
||||||
self.total_in += prev_amount
|
self.total_in += prev_amount
|
||||||
|
|
||||||
|
async def process_external_input(self, txi: TxInputType) -> None:
|
||||||
|
if txi.amount is None:
|
||||||
|
raise wire.DataError("Expected input with amount")
|
||||||
|
|
||||||
|
writers.write_tx_input_check(self.h_external, txi)
|
||||||
|
writers.write_tx_input_check(self.h_confirmed, txi)
|
||||||
|
self.hash143_add_input(txi) # all inputs are included (non-segwit as well)
|
||||||
|
self.total_in += txi.amount
|
||||||
|
self.external_in += txi.amount
|
||||||
|
|
||||||
async def confirm_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
|
async def confirm_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
|
||||||
if self.change_out == 0 and self.output_is_change(txo):
|
if self.change_out == 0 and self.output_is_change(txo):
|
||||||
# output is change and does not need confirmation
|
# output is change and does not need confirmation
|
||||||
@ -201,9 +269,30 @@ class Bitcoin:
|
|||||||
self.hash143_add_output(txo, script_pubkey)
|
self.hash143_add_output(txo, script_pubkey)
|
||||||
self.total_out += txo.amount
|
self.total_out += txo.amount
|
||||||
|
|
||||||
|
async def get_tx_digest(
|
||||||
|
self,
|
||||||
|
i: int,
|
||||||
|
txi: TxInputType,
|
||||||
|
public_keys: List[bytes],
|
||||||
|
threshold: int,
|
||||||
|
script_pubkey: bytes,
|
||||||
|
) -> bytes:
|
||||||
|
if txi.witness:
|
||||||
|
return self.hash143_preimage_hash(txi, public_keys, threshold)
|
||||||
|
else:
|
||||||
|
digest, _, _ = await self.get_legacy_tx_digest(i, script_pubkey)
|
||||||
|
return digest
|
||||||
|
|
||||||
def on_negative_fee(self) -> None:
|
def on_negative_fee(self) -> None:
|
||||||
raise wire.NotEnoughFunds("Not enough funds")
|
raise wire.NotEnoughFunds("Not enough funds")
|
||||||
|
|
||||||
|
async def serialize_external_input(self, i: int) -> None:
|
||||||
|
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
|
||||||
|
if not input_is_external(txi):
|
||||||
|
raise wire.ProcessError("Transaction has changed during signing")
|
||||||
|
|
||||||
|
self.write_tx_input(self.serialized_tx, txi, txi.script_sig)
|
||||||
|
|
||||||
async def serialize_segwit_input(self, i: int) -> None:
|
async def serialize_segwit_input(self, i: int) -> None:
|
||||||
# STAGE_REQUEST_SEGWIT_INPUT in legacy
|
# STAGE_REQUEST_SEGWIT_INPUT in legacy
|
||||||
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
|
txi = await helpers.request_tx_input(self.tx_req, i, self.coin)
|
||||||
@ -228,9 +317,14 @@ class Bitcoin:
|
|||||||
|
|
||||||
node = self.keychain.derive(txi.address_n)
|
node = self.keychain.derive(txi.address_n)
|
||||||
public_key = node.public_key()
|
public_key = node.public_key()
|
||||||
hash143_hash = self.hash143_preimage_hash(
|
|
||||||
txi, ecdsa_hash_pubkey(public_key, self.coin)
|
if txi.multisig:
|
||||||
)
|
public_keys = multisig.multisig_get_pubkeys(txi.multisig)
|
||||||
|
threshold = txi.multisig.m
|
||||||
|
else:
|
||||||
|
public_keys = [public_key]
|
||||||
|
threshold = 1
|
||||||
|
hash143_hash = self.hash143_preimage_hash(txi, public_keys, threshold)
|
||||||
|
|
||||||
signature = ecdsa_sign(node, hash143_hash)
|
signature = ecdsa_sign(node, hash143_hash)
|
||||||
|
|
||||||
@ -313,7 +407,7 @@ class Bitcoin:
|
|||||||
writers.write_uint32(h_sign, self.tx.lock_time)
|
writers.write_uint32(h_sign, self.tx.lock_time)
|
||||||
writers.write_uint32(h_sign, self.get_sighash_type(txi_sign))
|
writers.write_uint32(h_sign, self.get_sighash_type(txi_sign))
|
||||||
|
|
||||||
# check the control digests
|
# check that the inputs were the same as those streamed for confirmation
|
||||||
if self.h_confirmed.get_digest() != h_check.get_digest():
|
if self.h_confirmed.get_digest() != h_check.get_digest():
|
||||||
raise wire.ProcessError("Transaction has changed during signing")
|
raise wire.ProcessError("Transaction has changed during signing")
|
||||||
|
|
||||||
@ -506,10 +600,12 @@ class Bitcoin:
|
|||||||
writers.write_uint32(self.h_prevouts, txi.prev_index)
|
writers.write_uint32(self.h_prevouts, txi.prev_index)
|
||||||
writers.write_uint32(self.h_sequence, txi.sequence)
|
writers.write_uint32(self.h_sequence, txi.sequence)
|
||||||
|
|
||||||
def hash143_add_output(self, txo: TxOutputType, script_pubkey) -> None:
|
def hash143_add_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
|
||||||
writers.write_tx_output(self.h_outputs, txo, script_pubkey)
|
writers.write_tx_output(self.h_outputs, txo, script_pubkey)
|
||||||
|
|
||||||
def hash143_preimage_hash(self, txi: TxInputType, pubkeyhash: bytes) -> bytes:
|
def hash143_preimage_hash(
|
||||||
|
self, txi: TxInputType, public_keys: List[bytes], threshold: int
|
||||||
|
) -> bytes:
|
||||||
h_preimage = HashWriter(sha256())
|
h_preimage = HashWriter(sha256())
|
||||||
|
|
||||||
# nVersion
|
# nVersion
|
||||||
@ -532,7 +628,9 @@ class Bitcoin:
|
|||||||
writers.write_uint32(h_preimage, txi.prev_index)
|
writers.write_uint32(h_preimage, txi.prev_index)
|
||||||
|
|
||||||
# scriptCode
|
# scriptCode
|
||||||
script_code = scripts.bip143_derive_script_code(txi, pubkeyhash)
|
script_code = scripts.bip143_derive_script_code(
|
||||||
|
txi, public_keys, threshold, self.coin
|
||||||
|
)
|
||||||
writers.write_bytes_prefixed(h_preimage, script_code)
|
writers.write_bytes_prefixed(h_preimage, script_code)
|
||||||
|
|
||||||
# amount
|
# amount
|
||||||
@ -557,8 +655,16 @@ class Bitcoin:
|
|||||||
|
|
||||||
|
|
||||||
def input_is_segwit(txi: TxInputType) -> bool:
|
def input_is_segwit(txi: TxInputType) -> bool:
|
||||||
return txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES
|
return txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES or (
|
||||||
|
txi.script_type == InputScriptType.EXTERNAL and txi.witness is not None
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def input_is_nonsegwit(txi: TxInputType) -> bool:
|
def input_is_nonsegwit(txi: TxInputType) -> bool:
|
||||||
return txi.script_type in common.NONSEGWIT_INPUT_SCRIPT_TYPES
|
return txi.script_type in common.NONSEGWIT_INPUT_SCRIPT_TYPES or (
|
||||||
|
txi.script_type == InputScriptType.EXTERNAL and txi.witness is None
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def input_is_external(txi: TxInputType) -> bool:
|
||||||
|
return txi.script_type == InputScriptType.EXTERNAL
|
||||||
|
@ -4,6 +4,7 @@ from micropython import const
|
|||||||
from trezor import wire
|
from trezor import wire
|
||||||
from trezor.messages.SignTx import SignTx
|
from trezor.messages.SignTx import SignTx
|
||||||
from trezor.messages.TransactionType import TransactionType
|
from trezor.messages.TransactionType import TransactionType
|
||||||
|
from trezor.messages.TxInputType import TxInputType
|
||||||
|
|
||||||
from apps.common.writers import write_bitcoin_varint
|
from apps.common.writers import write_bitcoin_varint
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ from . import helpers
|
|||||||
from .bitcoin import Bitcoin, input_is_nonsegwit
|
from .bitcoin import Bitcoin, input_is_nonsegwit
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import Union
|
from typing import List, Union
|
||||||
|
|
||||||
_SIGHASH_FORKID = const(0x40)
|
_SIGHASH_FORKID = const(0x40)
|
||||||
|
|
||||||
@ -41,6 +42,21 @@ class Bitcoinlike(Bitcoin):
|
|||||||
else:
|
else:
|
||||||
await super().sign_nonsegwit_input(i_sign)
|
await super().sign_nonsegwit_input(i_sign)
|
||||||
|
|
||||||
|
async def get_tx_digest(
|
||||||
|
self,
|
||||||
|
i: int,
|
||||||
|
txi: TxInputType,
|
||||||
|
public_keys: List[bytes],
|
||||||
|
threshold: int,
|
||||||
|
script_pubkey: bytes,
|
||||||
|
) -> bytes:
|
||||||
|
if self.coin.force_bip143:
|
||||||
|
return self.hash143_preimage_hash(txi, public_keys, threshold)
|
||||||
|
else:
|
||||||
|
return await super().get_tx_digest(
|
||||||
|
i, txi, public_keys, threshold, script_pubkey
|
||||||
|
)
|
||||||
|
|
||||||
def on_negative_fee(self) -> None:
|
def on_negative_fee(self) -> None:
|
||||||
# some coins require negative fees for reward TX
|
# some coins require negative fees for reward TX
|
||||||
if not self.coin.negative_fee:
|
if not self.coin.negative_fee:
|
||||||
|
@ -57,17 +57,20 @@ class Decred(Bitcoin):
|
|||||||
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)
|
self.write_tx_footer(self.h_prefix, self.tx)
|
||||||
|
|
||||||
async def process_input(self, txi: TxInputType) -> None:
|
async def process_internal_input(self, txi: TxInputType) -> None:
|
||||||
await super().process_input(txi)
|
await super().process_internal_input(txi)
|
||||||
|
|
||||||
# Decred serializes inputs early.
|
# Decred serializes inputs early.
|
||||||
self.write_tx_input(self.serialized_tx, txi, bytes())
|
self.write_tx_input(self.serialized_tx, txi, bytes())
|
||||||
|
|
||||||
|
async def process_external_input(self, txi: TxInputType) -> None:
|
||||||
|
raise wire.DataError("External inputs not supported")
|
||||||
|
|
||||||
async def confirm_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
|
async def confirm_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
|
||||||
await super().confirm_output(txo, script_pubkey)
|
await super().confirm_output(txo, script_pubkey)
|
||||||
self.write_tx_output(self.serialized_tx, txo, script_pubkey)
|
self.write_tx_output(self.serialized_tx, txo, script_pubkey)
|
||||||
|
|
||||||
async def step4_serialize_inputs(self) -> None:
|
async def step5_serialize_inputs(self) -> None:
|
||||||
write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count)
|
write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count)
|
||||||
|
|
||||||
prefix_hash = self.h_prefix.get_digest()
|
prefix_hash = self.h_prefix.get_digest()
|
||||||
@ -125,13 +128,13 @@ class Decred(Bitcoin):
|
|||||||
self.write_tx_input_witness(self.serialized_tx, txi_sign, script_sig)
|
self.write_tx_input_witness(self.serialized_tx, txi_sign, script_sig)
|
||||||
self.set_serialized_signature(i_sign, signature)
|
self.set_serialized_signature(i_sign, signature)
|
||||||
|
|
||||||
async def step5_serialize_outputs(self) -> None:
|
async def step6_serialize_outputs(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def step6_sign_segwit_inputs(self) -> None:
|
async def step7_sign_segwit_inputs(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def step7_finish(self) -> None:
|
async def step8_finish(self) -> None:
|
||||||
await helpers.request_tx_finish(self.tx_req)
|
await helpers.request_tx_finish(self.tx_req)
|
||||||
|
|
||||||
def check_prevtx_output(self, txo_bin: TxOutputBinType) -> None:
|
def check_prevtx_output(self, txo_bin: TxOutputBinType) -> None:
|
||||||
|
@ -220,7 +220,7 @@ def sanitize_tx_input(tx: TransactionType, coin: CoinInfo) -> TxInputType:
|
|||||||
raise wire.DataError("Input's address_n provided but not expected.")
|
raise wire.DataError("Input's address_n provided but not expected.")
|
||||||
if not coin.decred and txi.decred_tree is not None:
|
if not coin.decred and txi.decred_tree is not None:
|
||||||
raise wire.DataError("Decred details provided but Decred coin not specified.")
|
raise wire.DataError("Decred details provided but Decred coin not specified.")
|
||||||
if txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES:
|
if txi.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES or txi.witness is not None:
|
||||||
if not coin.segwit:
|
if not coin.segwit:
|
||||||
raise wire.DataError("Segwit not enabled on this coin")
|
raise wire.DataError("Segwit not enabled on this coin")
|
||||||
return txi
|
return txi
|
||||||
|
@ -12,9 +12,9 @@ def init(inputs: int, outputs: int) -> None:
|
|||||||
report()
|
report()
|
||||||
|
|
||||||
|
|
||||||
def advance() -> None:
|
def advance(i: int = 1) -> None:
|
||||||
global _progress
|
global _progress
|
||||||
_progress += 1
|
_progress += i
|
||||||
report()
|
report()
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ from apps.common.coininfo import CoinInfo
|
|||||||
from apps.common.seed import Keychain
|
from apps.common.seed import Keychain
|
||||||
from apps.common.writers import write_bitcoin_varint
|
from apps.common.writers import write_bitcoin_varint
|
||||||
|
|
||||||
from ..multisig import multisig_get_pubkeys
|
from ..common import ecdsa_hash_pubkey
|
||||||
from ..scripts import output_script_multisig, output_script_p2pkh
|
from ..scripts import output_script_multisig, output_script_p2pkh
|
||||||
from ..writers import (
|
from ..writers import (
|
||||||
TX_HASH_SIZE,
|
TX_HASH_SIZE,
|
||||||
@ -28,7 +28,7 @@ from . import helpers
|
|||||||
from .bitcoinlike import Bitcoinlike
|
from .bitcoinlike import Bitcoinlike
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
from typing import Union
|
from typing import List, Union
|
||||||
from ..writers import Writer
|
from ..writers import Writer
|
||||||
|
|
||||||
OVERWINTERED = const(0x80000000)
|
OVERWINTERED = const(0x80000000)
|
||||||
@ -48,7 +48,7 @@ class Overwintered(Bitcoinlike):
|
|||||||
else:
|
else:
|
||||||
raise wire.DataError("Unsupported version for overwintered transaction")
|
raise wire.DataError("Unsupported version for overwintered transaction")
|
||||||
|
|
||||||
async def step7_finish(self) -> None:
|
async def step8_finish(self) -> None:
|
||||||
self.write_tx_footer(self.serialized_tx, self.tx)
|
self.write_tx_footer(self.serialized_tx, self.tx)
|
||||||
|
|
||||||
if self.tx.version == 3:
|
if self.tx.version == 3:
|
||||||
@ -66,6 +66,16 @@ class Overwintered(Bitcoinlike):
|
|||||||
async def sign_nonsegwit_input(self, i_sign: int) -> None:
|
async def sign_nonsegwit_input(self, i_sign: int) -> None:
|
||||||
await self.sign_nonsegwit_bip143_input(i_sign)
|
await self.sign_nonsegwit_bip143_input(i_sign)
|
||||||
|
|
||||||
|
async def get_tx_digest(
|
||||||
|
self,
|
||||||
|
i: int,
|
||||||
|
txi: TxInputType,
|
||||||
|
public_keys: List[bytes],
|
||||||
|
threshold: int,
|
||||||
|
script_pubkey: bytes,
|
||||||
|
) -> bytes:
|
||||||
|
return self.hash143_preimage_hash(txi, public_keys, threshold)
|
||||||
|
|
||||||
def write_tx_header(
|
def write_tx_header(
|
||||||
self, w: Writer, tx: Union[SignTx, TransactionType], witness_marker: bool
|
self, w: Writer, tx: Union[SignTx, TransactionType], witness_marker: bool
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -90,7 +100,9 @@ class Overwintered(Bitcoinlike):
|
|||||||
self.h_sequence = HashWriter(blake2b(outlen=32, personal=b"ZcashSequencHash"))
|
self.h_sequence = HashWriter(blake2b(outlen=32, personal=b"ZcashSequencHash"))
|
||||||
self.h_outputs = HashWriter(blake2b(outlen=32, personal=b"ZcashOutputsHash"))
|
self.h_outputs = HashWriter(blake2b(outlen=32, personal=b"ZcashOutputsHash"))
|
||||||
|
|
||||||
def hash143_preimage_hash(self, txi: TxInputType, pubkeyhash: bytes) -> bytes:
|
def hash143_preimage_hash(
|
||||||
|
self, txi: TxInputType, public_keys: List[bytes], threshold: int
|
||||||
|
) -> bytes:
|
||||||
h_preimage = HashWriter(
|
h_preimage = HashWriter(
|
||||||
blake2b(
|
blake2b(
|
||||||
outlen=32,
|
outlen=32,
|
||||||
@ -142,7 +154,7 @@ class Overwintered(Bitcoinlike):
|
|||||||
write_uint32(h_preimage, txi.prev_index)
|
write_uint32(h_preimage, txi.prev_index)
|
||||||
|
|
||||||
# 10b / 13b. scriptCode
|
# 10b / 13b. scriptCode
|
||||||
script_code = derive_script_code(txi, pubkeyhash)
|
script_code = derive_script_code(txi, public_keys, threshold, self.coin)
|
||||||
write_bytes_prefixed(h_preimage, script_code)
|
write_bytes_prefixed(h_preimage, script_code)
|
||||||
|
|
||||||
# 10c / 13c. value
|
# 10c / 13c. value
|
||||||
@ -154,16 +166,15 @@ class Overwintered(Bitcoinlike):
|
|||||||
return get_tx_hash(h_preimage)
|
return get_tx_hash(h_preimage)
|
||||||
|
|
||||||
|
|
||||||
def derive_script_code(txi: TxInputType, pubkeyhash: bytes) -> bytearray:
|
def derive_script_code(
|
||||||
|
txi: TxInputType, public_keys: List[bytes], threshold: int, coin: CoinInfo
|
||||||
|
) -> bytearray:
|
||||||
|
if len(public_keys) > 1:
|
||||||
|
return output_script_multisig(public_keys, threshold)
|
||||||
|
|
||||||
if txi.multisig:
|
p2pkh = txi.script_type in (InputScriptType.SPENDADDRESS, InputScriptType.EXTERNAL)
|
||||||
return output_script_multisig(
|
|
||||||
multisig_get_pubkeys(txi.multisig), txi.multisig.m
|
|
||||||
)
|
|
||||||
|
|
||||||
p2pkh = txi.script_type == InputScriptType.SPENDADDRESS
|
|
||||||
if p2pkh:
|
if p2pkh:
|
||||||
return output_script_p2pkh(pubkeyhash)
|
return output_script_p2pkh(ecdsa_hash_pubkey(public_keys[0], coin))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise wire.DataError("Unknown input script type for zip143 script code")
|
raise wire.DataError("Unknown input script type for zip143 script code")
|
||||||
|
@ -4,6 +4,7 @@ from apps.bitcoin.scripts import output_derive_script
|
|||||||
from apps.bitcoin.sign_tx.bitcoin import Bitcoin
|
from apps.bitcoin.sign_tx.bitcoin import Bitcoin
|
||||||
from apps.bitcoin.writers import get_tx_hash
|
from apps.bitcoin.writers import get_tx_hash
|
||||||
from apps.common import coins
|
from apps.common import coins
|
||||||
|
from apps.common.seed import Keychain
|
||||||
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
|
||||||
@ -89,10 +90,13 @@ class TestSegwitBip143NativeP2WPKH(unittest.TestCase):
|
|||||||
script_pubkey = output_derive_script(txo.address, coin)
|
script_pubkey = output_derive_script(txo.address, coin)
|
||||||
bip143.hash143_add_output(txo_bin, script_pubkey)
|
bip143.hash143_add_output(txo_bin, script_pubkey)
|
||||||
|
|
||||||
|
keychain = Keychain(seed, [[coin.curve_name, []]])
|
||||||
|
node = keychain.derive(self.inp2.address_n)
|
||||||
|
|
||||||
# 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.hash143_preimage_hash(self.inp2, unhexlify('1d0f172a0ecb48aee1be1f2687d2963ae33f71a1'))
|
result = bip143.hash143_preimage_hash(self.inp2, [node.public_key()], 1)
|
||||||
self.assertEqual(hexlify(result), b'c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670')
|
self.assertEqual(hexlify(result), b'2fa3f1351618b2532228d7182d3221d95c21fd3d496e7e22e9ded873cf022a8b')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -4,6 +4,7 @@ from apps.bitcoin.scripts import output_derive_script
|
|||||||
from apps.bitcoin.sign_tx.bitcoin import Bitcoin
|
from apps.bitcoin.sign_tx.bitcoin import Bitcoin
|
||||||
from apps.bitcoin.writers import get_tx_hash
|
from apps.bitcoin.writers import get_tx_hash
|
||||||
from apps.common import coins
|
from apps.common import coins
|
||||||
|
from apps.common.seed import Keychain
|
||||||
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
|
||||||
@ -75,9 +76,12 @@ class TestSegwitBip143(unittest.TestCase):
|
|||||||
script_pubkey = output_derive_script(txo.address, coin)
|
script_pubkey = output_derive_script(txo.address, coin)
|
||||||
bip143.hash143_add_output(txo_bin, script_pubkey)
|
bip143.hash143_add_output(txo_bin, script_pubkey)
|
||||||
|
|
||||||
|
keychain = Keychain(seed, [[coin.curve_name, []]])
|
||||||
|
node = keychain.derive(self.inp1.address_n)
|
||||||
|
|
||||||
# test data public key hash
|
# test data public key hash
|
||||||
result = bip143.hash143_preimage_hash(self.inp1, unhexlify('79091972186c449eb1ded22b78e40d009bdf0089'))
|
result = bip143.hash143_preimage_hash(self.inp1, [node.public_key()], 1)
|
||||||
self.assertEqual(hexlify(result), b'64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6')
|
self.assertEqual(hexlify(result), b'6e28aca7041720995d4acf59bbda64eef5d6f23723d23f2e994757546674bbd9')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -25,7 +25,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
"702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76",
|
"702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76",
|
||||||
4025613248,
|
4025613248,
|
||||||
],
|
],
|
||||||
"pubkeyhash": "4d9cafb657677f2321fc538e367767dbdf551539",
|
"pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"sequence": 1999822371,
|
"sequence": 1999822371,
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
"prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688",
|
"prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688",
|
||||||
"sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a",
|
"sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a",
|
||||||
"outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992",
|
"outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992",
|
||||||
"preimage_hash": b"287146efaa30b3c1c7bd1a72308c46205712e6944780fdc5a7f91f477fddd55b",
|
"preimage_hash": b"fed855ea5fcec81928fa35d39b8582c6e026a0bf52cebeed4445a7fc7d730280",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expiry": 231041495,
|
"expiry": 231041495,
|
||||||
@ -51,7 +51,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
"76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2",
|
"76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2",
|
||||||
1547817817,
|
1547817817,
|
||||||
],
|
],
|
||||||
"pubkeyhash": "9f5d230603ce57a0e8b31a8c9b6c983ad5b00cd5",
|
"pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"sequence": 3973122135,
|
"sequence": 3973122135,
|
||||||
},
|
},
|
||||||
@ -61,7 +61,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
"cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483",
|
"cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483",
|
||||||
3053054889,
|
3053054889,
|
||||||
],
|
],
|
||||||
"pubkeyhash": "b5e71ef1df5ed3a2589607ca58ed19634f07fb4f",
|
"pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d",
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"sequence": 3932380530,
|
"sequence": 3932380530,
|
||||||
},
|
},
|
||||||
@ -77,7 +77,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
"prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b",
|
"prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b",
|
||||||
"sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e",
|
"sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e",
|
||||||
"outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1",
|
"outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1",
|
||||||
"preimage_hash": b"b71358954aca8ffe1d3f1b5707ed6c082ed2b35e35e293b897bfc12ae7c85396",
|
"preimage_hash": b"1c6f563d2f16002f4c59bec5e7d56ed298315630c1d7e9a431b89e6f81026a02",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expiry": 186996458,
|
"expiry": 186996458,
|
||||||
@ -89,7 +89,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
1290359941,
|
1290359941,
|
||||||
],
|
],
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"pubkeyhash": "0873d1baed6c8696e4bd2b26755692b4d8050086",
|
"pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
|
||||||
"sequence": 1230917966,
|
"sequence": 1230917966,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -101,7 +101,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
"prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd",
|
"prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd",
|
||||||
"sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc",
|
"sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc",
|
||||||
"outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824",
|
"outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824",
|
||||||
"preimage_hash": b"19ea4ce2467cb5cdcc4562ce81b22006f1fb55189ea93ccc7a3bc78ff5d97a93",
|
"preimage_hash": b"7159247daa16cc7e683f03ebf968314ce03324028ac138468a7b76c77e551fe8",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expiry": 254788522,
|
"expiry": 254788522,
|
||||||
@ -113,7 +113,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
1517971891,
|
1517971891,
|
||||||
],
|
],
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"pubkeyhash": "80b6c35a9b2efd77dbfd5d5d3bb1fd03ff40f182",
|
"pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
|
||||||
"sequence": 3833577708,
|
"sequence": 3833577708,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -123,7 +123,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
687648622,
|
687648622,
|
||||||
],
|
],
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"pubkeyhash": "fb8c27a442afe0f0b39a3875823c4893fe8f8550",
|
"pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d",
|
||||||
"sequence": 4190617831,
|
"sequence": 4190617831,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -137,7 +137,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
"prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898",
|
"prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898",
|
||||||
"sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23",
|
"sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23",
|
||||||
"outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a",
|
"outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a",
|
||||||
"preimage_hash": b"d0b92233e185a69f320f18bfacff7e5dcc5f0ed02af2f3ecf59359853e105e59",
|
"preimage_hash": b"16b24c5d599107efb41cbc6cb0127094878bab1e0d33d734cfccce58e07b3386",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ class TestZcashZip143(unittest.TestCase):
|
|||||||
self.assertEqual(hexlify(get_tx_hash(zip143.h_sequence)), v["sequence_hash"])
|
self.assertEqual(hexlify(get_tx_hash(zip143.h_sequence)), v["sequence_hash"])
|
||||||
self.assertEqual(hexlify(get_tx_hash(zip143.h_outputs)), v["outputs_hash"])
|
self.assertEqual(hexlify(get_tx_hash(zip143.h_outputs)), v["outputs_hash"])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
hexlify(zip143.hash143_preimage_hash(txi, unhexlify(i["pubkeyhash"]))),
|
hexlify(zip143.hash143_preimage_hash(txi, [unhexlify(i["pubkey"])], 1)),
|
||||||
v["preimage_hash"],
|
v["preimage_hash"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
"702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76",
|
"702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76",
|
||||||
4025613248,
|
4025613248,
|
||||||
],
|
],
|
||||||
"pubkeyhash": "4d9cafb657677f2321fc538e367767dbdf551539",
|
"pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"sequence": 1999822371,
|
"sequence": 1999822371,
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
"prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688",
|
"prevouts_hash": b"bd4318eecf841a0cf01c2be532cf4bc3303e881e2aface159f1882f153152688",
|
||||||
"sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a",
|
"sequence_hash": b"9ac6a31952ff626bf5a0a30d3d8ac63a0d4298d33d7bc38854bfa5860695e30a",
|
||||||
"outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992",
|
"outputs_hash": b"d0cadf116b4441f5e1e17814908dee509ec262a79f3c88f7f3389e8200658992",
|
||||||
"preimage_hash": b"53a12bca557c27defa366c2b4c0e46ede01f81ef3dd3aa3750db62a5505c1d06",
|
"preimage_hash": b"f8772c6ecf9d903698fb8c51cd7b99605af298478989945936935da65e064695",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expiry": 231041495,
|
"expiry": 231041495,
|
||||||
@ -51,7 +51,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
"76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2",
|
"76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de2",
|
||||||
1547817817,
|
1547817817,
|
||||||
],
|
],
|
||||||
"pubkeyhash": "9f5d230603ce57a0e8b31a8c9b6c983ad5b00cd5",
|
"pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"sequence": 3973122135,
|
"sequence": 3973122135,
|
||||||
},
|
},
|
||||||
@ -61,7 +61,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
"cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483",
|
"cccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483",
|
||||||
3053054889,
|
3053054889,
|
||||||
],
|
],
|
||||||
"pubkeyhash": "b5e71ef1df5ed3a2589607ca58ed19634f07fb4f",
|
"pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d",
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"sequence": 3932380530,
|
"sequence": 3932380530,
|
||||||
},
|
},
|
||||||
@ -77,7 +77,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
"prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b",
|
"prevouts_hash": b"8e286c6c0dde3119271c9c1398ef46614b0253c502b00a3691cec2e9047da35b",
|
||||||
"sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e",
|
"sequence_hash": b"58477fd9ecd5faf3e08159e0ab5fdaab66cab364d081498ddcef41de0af3624e",
|
||||||
"outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1",
|
"outputs_hash": b"c518797fc6f2c08fc22aa3f66122047b360e1db4df5c3feb28573c00cdf45fa1",
|
||||||
"preimage_hash": b"d1bc60986cc5c4d57f91002e48459a50f72bdb96b8f5889cf8f467a7d968b97c",
|
"preimage_hash": b"0eb47dc51d89cc52378fc182242f78ebd3609544a365d2270c23b4052f301025",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expiry": 186996458,
|
"expiry": 186996458,
|
||||||
@ -89,7 +89,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
1290359941,
|
1290359941,
|
||||||
],
|
],
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"pubkeyhash": "0873d1baed6c8696e4bd2b26755692b4d8050086",
|
"pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
|
||||||
"sequence": 1230917966,
|
"sequence": 1230917966,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -101,7 +101,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
"prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd",
|
"prevouts_hash": b"445bc6328cd33b3c86259953dd674bded341ff1e1104dc21856919e9761036dd",
|
||||||
"sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc",
|
"sequence_hash": b"42e1d5c2636f165afaa954afa6d7a50779eb145e947bf668f1a40dd771c711fc",
|
||||||
"outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824",
|
"outputs_hash": b"869eda84eecf7257f9979a4848bbf52f4969a5736594ab7ba41452e7bb906824",
|
||||||
"preimage_hash": b"7536cdb202a30bf09c45e1a2f775c4efd41b9e67557b62abe12b64d367a2316e",
|
"preimage_hash": b"7f6b5439a64b20faf6f9f9460bc75c333c4799e9b04c80c26a79b8e801b8b6e1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expiry": 254788522,
|
"expiry": 254788522,
|
||||||
@ -113,7 +113,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
1517971891,
|
1517971891,
|
||||||
],
|
],
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"pubkeyhash": "80b6c35a9b2efd77dbfd5d5d3bb1fd03ff40f182",
|
"pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
|
||||||
"sequence": 3833577708,
|
"sequence": 3833577708,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -123,7 +123,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
687648622,
|
687648622,
|
||||||
],
|
],
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"pubkeyhash": "fb8c27a442afe0f0b39a3875823c4893fe8f8550",
|
"pubkey": "02c651a011009e2c7e7b3ed2068857ca0a47cba35b73e06c32e3c06ef3aa67621d",
|
||||||
"sequence": 4190617831,
|
"sequence": 4190617831,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -137,7 +137,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
"prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898",
|
"prevouts_hash": b"509abdfafcc75265037f1ce6a4658ac9ecadd7b82378c3fbaeb48ab437ff6898",
|
||||||
"sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23",
|
"sequence_hash": b"2b13f671cd1a9aa04c1e250eef74a316d7d2b049360d20604514ddc2dfacfd23",
|
||||||
"outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a",
|
"outputs_hash": b"4f01b8785e80779290aa86c16b24952f9b7f8bc09da44e68f760ab1920ab8f2a",
|
||||||
"preimage_hash": b"df1359c0aacc05e88ae6bbecfc54fef50bd31f21f543c49f95a321dd835263be",
|
"preimage_hash": b"46152b79ebeba4089d05724e33d4a5e6d6ea9e3a2fe777af6644318ba93a1ca0",
|
||||||
},
|
},
|
||||||
# "Test vector 3" from https://github.com/zcash/zips/blob/master/zip-0243.rst
|
# "Test vector 3" from https://github.com/zcash/zips/blob/master/zip-0243.rst
|
||||||
{
|
{
|
||||||
@ -150,7 +150,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
"script_type": InputScriptType.SPENDADDRESS,
|
"script_type": InputScriptType.SPENDADDRESS,
|
||||||
"pubkeyhash": "507173527b4c3318a2aecd793bf1cfed705950cf",
|
"pubkey": "03c6d9cc725bb7e19c026df03bf693ee1171371a8eaf25f04b7a58f6befabcd38c",
|
||||||
"sequence": 0xfffffffe,
|
"sequence": 0xfffffffe,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -171,7 +171,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
"prevouts_hash": b"fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f11",
|
"prevouts_hash": b"fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f11",
|
||||||
"sequence_hash": b"6c80d37f12d89b6f17ff198723e7db1247c4811d1a695d74d930f99e98418790",
|
"sequence_hash": b"6c80d37f12d89b6f17ff198723e7db1247c4811d1a695d74d930f99e98418790",
|
||||||
"outputs_hash": b"d2b04118469b7810a0d1cc59568320aad25a84f407ecac40b4f605a4e6868454",
|
"outputs_hash": b"d2b04118469b7810a0d1cc59568320aad25a84f407ecac40b4f605a4e6868454",
|
||||||
"preimage_hash": b"f3148f80dfab5e573d5edfe7a850f5fd39234f80b5429d3a57edcc11e34c585b",
|
"preimage_hash": b"6c210ce6417539d4aa9546f6184e33ca89224ac4559d2a9c4cf090b646692bd9",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -208,7 +208,7 @@ class TestZcashZip243(unittest.TestCase):
|
|||||||
self.assertEqual(hexlify(get_tx_hash(zip243.h_prevouts)), v["prevouts_hash"])
|
self.assertEqual(hexlify(get_tx_hash(zip243.h_prevouts)), v["prevouts_hash"])
|
||||||
self.assertEqual(hexlify(get_tx_hash(zip243.h_sequence)), v["sequence_hash"])
|
self.assertEqual(hexlify(get_tx_hash(zip243.h_sequence)), v["sequence_hash"])
|
||||||
self.assertEqual(hexlify(get_tx_hash(zip243.h_outputs)), v["outputs_hash"])
|
self.assertEqual(hexlify(get_tx_hash(zip243.h_outputs)), v["outputs_hash"])
|
||||||
self.assertEqual(hexlify(zip243.hash143_preimage_hash(txi, unhexlify(i["pubkeyhash"]))), v["preimage_hash"])
|
self.assertEqual(hexlify(zip243.hash143_preimage_hash(txi, [unhexlify(i["pubkey"])], 1)), v["preimage_hash"])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
Reference in New Issue
Block a user