1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 15:38:11 +00:00

Merge branch 'release/2020-06'

This commit is contained in:
Tomas Susanka 2020-06-10 06:51:18 +00:00
commit 56fe5adcfc
60 changed files with 6216 additions and 3619 deletions

View File

@ -44,7 +44,7 @@
"3": 1537743641, "3": 1537743641,
"4": 1991772603 "4": 1991772603
}, },
"extra_data": false, "extra_data": true,
"timestamp": false, "timestamp": false,
"confidential_assets": null "confidential_assets": null
} }

View File

@ -519,13 +519,21 @@ STATIC mp_obj_t mod_trezorcrypto_monero_inv256_modm(size_t n_args,
assert_scalar(args[1 + off]); assert_scalar(args[1 + off]);
// bn_prime = curve order, little endian encoded // bn_prime = curve order, little endian encoded
bignum256 bn_prime = {.val = {0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8, bignum256 bn_prime = {.val = {0x1cf5d3ed, 0x9318d2, 0x1de73596, 0x1df3bd45,
0x14, 0x0, 0x0, 0x0, 0x1000}}; 0x14d, 0x0, 0x0, 0x0, 0x100000}};
bignum256 bn_x; bignum256 bn_x;
bignum256modm bm_x;
uint8_t raw_x[32];
memcpy(bm_x, MP_OBJ_C_SCALAR(args[1 + off]), sizeof(bignum256modm));
contract256_modm(raw_x, bm_x);
bn_read_le(raw_x, &bn_x);
memcpy(&bn_x.val, MP_OBJ_C_SCALAR(args[1 + off]), sizeof(bignum256modm));
bn_inverse(&bn_x, &bn_prime); bn_inverse(&bn_x, &bn_prime);
memcpy(MP_OBJ_SCALAR(res), bn_x.val, sizeof(bignum256modm));
bn_write_le(&bn_x, raw_x);
expand_raw256_modm(bm_x, raw_x);
memcpy(MP_OBJ_SCALAR(res), bm_x, sizeof(bignum256modm));
return res; return res;
} }

View File

@ -84,7 +84,6 @@ class Bitcoin:
# amounts # amounts
self.total_in = 0 # sum of input amounts self.total_in = 0 # sum of input amounts
self.bip143_in = 0 # sum of segwit 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)
@ -178,26 +177,15 @@ class Bitcoin:
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)
if input_is_segwit(txi): if txi.script_type not in helpers.INTERNAL_INPUT_SCRIPT_TYPES:
await self.process_segwit_input(txi)
elif input_is_nonsegwit(txi):
await self.process_nonsegwit_input(txi)
else:
raise wire.DataError("Wrong input script type") raise wire.DataError("Wrong input script type")
async def process_segwit_input(self, txi: TxInputType) -> None: prev_amount = await self.get_prevtx_output_value(txi.prev_hash, txi.prev_index)
await self.process_bip143_input(txi)
async def process_nonsegwit_input(self, txi: TxInputType) -> None: if txi.amount is not None and prev_amount != txi.amount:
self.total_in += await self.get_prevtx_output_value( raise wire.DataError("Invalid amount specified")
txi.prev_hash, txi.prev_index
)
async def process_bip143_input(self, txi: TxInputType) -> None: self.total_in += prev_amount
if not txi.amount:
raise wire.DataError("Expected input with amount")
self.bip143_in += txi.amount
self.total_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):
@ -229,13 +217,12 @@ class Bitcoin:
self.write_tx_input(self.serialized_tx, txi, script_sig) self.write_tx_input(self.serialized_tx, txi, script_sig)
def sign_bip143_input(self, txi: TxInputType) -> Tuple[bytes, bytes]: def sign_bip143_input(self, txi: TxInputType) -> Tuple[bytes, bytes]:
if txi.amount is None:
raise wire.DataError("Expected input with amount")
self.wallet_path.check_input(txi) self.wallet_path.check_input(txi)
self.multisig_fingerprint.check_input(txi) self.multisig_fingerprint.check_input(txi)
if txi.amount > self.bip143_in:
raise wire.ProcessError("Transaction has changed during signing")
self.bip143_in -= txi.amount
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( hash143_hash = self.hash143_preimage_hash(

View File

@ -4,7 +4,6 @@ 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
@ -19,17 +18,6 @@ _SIGHASH_FORKID = const(0x40)
class Bitcoinlike(Bitcoin): class Bitcoinlike(Bitcoin):
async def process_segwit_input(self, txi: TxInputType) -> None:
if not self.coin.segwit:
raise wire.DataError("Segwit not enabled on this coin")
await super().process_segwit_input(txi)
async def process_nonsegwit_input(self, txi: TxInputType) -> None:
if self.coin.force_bip143:
await self.process_bip143_input(txi)
else:
await super().process_nonsegwit_input(txi)
async def sign_nonsegwit_bip143_input(self, i_sign: int) -> None: async def sign_nonsegwit_bip143_input(self, i_sign: int) -> None:
txi = await helpers.request_tx_input(self.tx_req, i_sign, self.coin) txi = await helpers.request_tx_input(self.tx_req, i_sign, self.coin)
@ -83,11 +71,11 @@ class Bitcoinlike(Bitcoin):
await super().write_prev_tx_footer(w, tx, prev_hash) await super().write_prev_tx_footer(w, tx, prev_hash)
if self.coin.extra_data: if self.coin.extra_data:
ofs = 0 offset = 0
while ofs < tx.extra_data_len: while offset < tx.extra_data_len:
size = min(1024, tx.extra_data_len - ofs) size = min(1024, tx.extra_data_len - offset)
data = await helpers.request_tx_extra_data( data = await helpers.request_tx_extra_data(
self.tx_req, ofs, size, prev_hash self.tx_req, offset, size, prev_hash
) )
writers.write_bytes_unchecked(w, data) writers.write_bytes_unchecked(w, data)
ofs += len(data) offset += len(data)

View File

@ -199,6 +199,13 @@ def sanitize_sign_tx(tx: SignTx, coin: CoinInfo) -> SignTx:
raise wire.DataError("Timestamp must be set.") raise wire.DataError("Timestamp must be set.")
elif not coin.timestamp and tx.timestamp: elif not coin.timestamp and tx.timestamp:
raise wire.DataError("Timestamp not enabled on this coin.") raise wire.DataError("Timestamp not enabled on this coin.")
if coin.overwintered and tx.version_group_id is None:
raise wire.DataError("Version group ID must be set.")
elif not coin.overwintered:
if tx.version_group_id is not None:
raise wire.DataError("Version group ID not enabled on this coin.")
if tx.branch_id is not None:
raise wire.DataError("Branch ID not enabled on this coin.")
return tx return tx
@ -219,6 +226,13 @@ def sanitize_tx_meta(tx: TransactionType, coin: CoinInfo) -> TransactionType:
raise wire.DataError("Timestamp must be set.") raise wire.DataError("Timestamp must be set.")
elif not coin.timestamp and tx.timestamp: elif not coin.timestamp and tx.timestamp:
raise wire.DataError("Timestamp not enabled on this coin.") raise wire.DataError("Timestamp not enabled on this coin.")
if coin.overwintered and tx.version_group_id is None:
raise wire.DataError("Version group ID must be set.")
elif not coin.overwintered:
if tx.version_group_id is not None:
raise wire.DataError("Version group ID not enabled on this coin.")
if tx.branch_id is not None:
raise wire.DataError("Branch ID not enabled on this coin.")
return tx return tx
@ -228,6 +242,8 @@ def sanitize_tx_input(tx: TransactionType, coin: CoinInfo) -> TxInputType:
txi.script_type = InputScriptType.SPENDADDRESS txi.script_type = InputScriptType.SPENDADDRESS
if txi.sequence is None: if txi.sequence is None:
txi.sequence = 0xFFFFFFFF txi.sequence = 0xFFFFFFFF
if txi.prev_index is None:
raise wire.DataError("Missing prev_index field.")
if txi.prev_hash is None or len(txi.prev_hash) != TX_HASH_SIZE: if txi.prev_hash is None or len(txi.prev_hash) != TX_HASH_SIZE:
raise wire.DataError("Provided prev_hash is invalid.") raise wire.DataError("Provided prev_hash is invalid.")
if txi.multisig and txi.script_type not in MULTISIG_INPUT_SCRIPT_TYPES: if txi.multisig and txi.script_type not in MULTISIG_INPUT_SCRIPT_TYPES:
@ -239,8 +255,6 @@ def sanitize_tx_input(tx: TransactionType, coin: CoinInfo) -> TxInputType:
if txi.script_type in SEGWIT_INPUT_SCRIPT_TYPES: if txi.script_type in SEGWIT_INPUT_SCRIPT_TYPES:
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")
if txi.amount is None:
raise wire.DataError("Segwit input without amount")
return txi return txi
@ -250,8 +264,12 @@ def sanitize_tx_output(tx: TransactionType, coin: CoinInfo) -> TxOutputType:
raise wire.DataError("Multisig field provided but not expected.") raise wire.DataError("Multisig field provided but not expected.")
if txo.address_n and txo.script_type not in CHANGE_OUTPUT_SCRIPT_TYPES: if txo.address_n and txo.script_type not in CHANGE_OUTPUT_SCRIPT_TYPES:
raise wire.DataError("Output's address_n provided but not expected.") raise wire.DataError("Output's address_n provided but not expected.")
if txo.amount is None:
raise wire.DataError("Missing amount field.")
if txo.script_type == OutputScriptType.PAYTOOPRETURN: if txo.script_type == OutputScriptType.PAYTOOPRETURN:
# op_return output # op_return output
if txo.op_return_data is None:
raise wire.DataError("OP_RETURN output without op_return_data")
if txo.amount != 0: if txo.amount != 0:
raise wire.DataError("OP_RETURN output with non-zero amount") raise wire.DataError("OP_RETURN output with non-zero amount")
if txo.address or txo.address_n or txo.multisig: if txo.address or txo.address_n or txo.multisig:
@ -270,4 +288,8 @@ def sanitize_tx_output(tx: TransactionType, coin: CoinInfo) -> TxOutputType:
def sanitize_tx_binoutput(tx: TransactionType, coin: CoinInfo) -> TxOutputBinType: def sanitize_tx_binoutput(tx: TransactionType, coin: CoinInfo) -> TxOutputBinType:
txo_bin = tx.bin_outputs[0] txo_bin = tx.bin_outputs[0]
if txo_bin.amount is None:
raise wire.DataError("Missing amount field.")
if txo_bin.script_pubkey is None:
raise wire.DataError("Missing script_pubkey field.")
return txo_bin return txo_bin

View File

@ -52,10 +52,8 @@ class Overwintered(Bitcoinlike):
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:
write_uint32(self.serialized_tx, self.tx.expiry) # expiryHeight
write_bitcoin_varint(self.serialized_tx, 0) # nJoinSplit write_bitcoin_varint(self.serialized_tx, 0) # nJoinSplit
elif self.tx.version == 4: elif self.tx.version == 4:
write_uint32(self.serialized_tx, self.tx.expiry) # expiryHeight
write_uint64(self.serialized_tx, 0) # valueBalance write_uint64(self.serialized_tx, 0) # valueBalance
write_bitcoin_varint(self.serialized_tx, 0) # nShieldedSpend write_bitcoin_varint(self.serialized_tx, 0) # nShieldedSpend
write_bitcoin_varint(self.serialized_tx, 0) # nShieldedOutput write_bitcoin_varint(self.serialized_tx, 0) # nShieldedOutput
@ -65,9 +63,6 @@ class Overwintered(Bitcoinlike):
await helpers.request_tx_finish(self.tx_req) await helpers.request_tx_finish(self.tx_req)
async def process_nonsegwit_input(self, txi: TxInputType) -> None:
await self.process_bip143_input(txi)
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)
@ -78,6 +73,10 @@ class Overwintered(Bitcoinlike):
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
def write_tx_footer(self, w: Writer, tx: Union[SignTx, TransactionType]) -> None:
write_uint32(w, tx.lock_time)
write_uint32(w, tx.expiry) # expiryHeight
# ZIP-0143 / ZIP-0243 # ZIP-0143 / ZIP-0243
# === # ===

View File

@ -940,7 +940,7 @@ def by_name(name: str) -> CoinInfo:
decred=False, decred=False,
negative_fee=True, negative_fee=True,
curve_name='secp256k1', curve_name='secp256k1',
extra_data=False, extra_data=True,
timestamp=False, timestamp=False,
overwintered=True, overwintered=True,
confidential_assets=None, confidential_assets=None,

View File

@ -4,11 +4,12 @@ from trezor.utils import chunks
from trezor.crypto import bip39 from trezor.crypto import bip39
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.TxOutputBinType import TxOutputBinType
from trezor.messages.TxOutputType import TxOutputType from trezor.messages.TxOutputType import TxOutputType
from trezor.messages.TxRequest import TxRequest from trezor.messages.TxRequest import TxRequest
from trezor.messages.TxAck import TxAck from trezor.messages.TxAck import TxAck
from trezor.messages.TransactionType import TransactionType from trezor.messages.TransactionType import TransactionType
from trezor.messages.RequestType import TXINPUT, TXOUTPUT, TXFINISHED from trezor.messages.RequestType import TXINPUT, TXMETA, TXOUTPUT, TXFINISHED
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
from trezor.messages import InputScriptType from trezor.messages import InputScriptType
@ -42,6 +43,17 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
sequence=0xffffffff, sequence=0xffffffff,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=0, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('160014d16b8c0680c61fc6ed2e407455715055e41052f5'),
prev_hash=unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'),
prev_index=0,
script_type=None,
sequence=4294967295)
pout1 = TxOutputBinType(script_pubkey=unhexlify('00140099a7ecbd938ed1839f5f6bf6d50933c6db9d5c'),
amount=12300000)
pout2 = TxOutputBinType(script_pubkey=unhexlify('a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
amount=111145789)
out1 = TxOutputType( out1 = TxOutputType(
address='2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp', address='2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp',
amount=5000000, amount=5000000,
@ -68,6 +80,18 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
helpers.UiConfirmForeignAddress(address_n=inp1.address_n), helpers.UiConfirmForeignAddress(address_n=inp1.address_n),
True, True,
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])), TxAck(tx=TransactionType(outputs=[out1])),
@ -144,6 +168,17 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
sequence=0xffffffff, sequence=0xffffffff,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=0, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('160014d16b8c0680c61fc6ed2e407455715055e41052f5'),
prev_hash=unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'),
prev_index=0,
script_type=None,
sequence=4294967295)
pout1 = TxOutputBinType(script_pubkey=unhexlify('00140099a7ecbd938ed1839f5f6bf6d50933c6db9d5c'),
amount=12300000)
pout2 = TxOutputBinType(script_pubkey=unhexlify('a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
amount=111145789)
out1 = TxOutputType( out1 = TxOutputType(
address='2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp', address='2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp',
amount=5000000, amount=5000000,
@ -170,6 +205,18 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
helpers.UiConfirmForeignAddress(address_n=inp1.address_n), helpers.UiConfirmForeignAddress(address_n=inp1.address_n),
True, True,
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])), TxAck(tx=TransactionType(outputs=[out1])),
@ -243,6 +290,17 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
sequence=0xffffffff, sequence=0xffffffff,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=0, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('160014d16b8c0680c61fc6ed2e407455715055e41052f5'),
prev_hash=unhexlify('20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'),
prev_index=0,
script_type=None,
sequence=4294967295)
pout1 = TxOutputBinType(script_pubkey=unhexlify('00140099a7ecbd938ed1839f5f6bf6d50933c6db9d5c'),
amount=12300000)
pout2 = TxOutputBinType(script_pubkey=unhexlify('a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
amount=111145789)
out1 = TxOutputType( out1 = TxOutputType(
address='TB1Q694CCP5QCC0UDMFWGP692U2S2HJPQ5H407URTU', # Error: should be lower case address='TB1Q694CCP5QCC0UDMFWGP692U2S2HJPQ5H407URTU', # Error: should be lower case
script_type=OutputScriptType.PAYTOADDRESS, script_type=OutputScriptType.PAYTOADDRESS,
@ -262,6 +320,18 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
helpers.UiConfirmForeignAddress(address_n=inp1.address_n), helpers.UiConfirmForeignAddress(address_n=inp1.address_n),
True, True,
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])), TxAck(tx=TransactionType(outputs=[out1])),
None None

View File

@ -4,11 +4,12 @@ from trezor.utils import chunks
from trezor.crypto import bip39 from trezor.crypto import bip39
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.TxOutputBinType import TxOutputBinType
from trezor.messages.TxOutputType import TxOutputType from trezor.messages.TxOutputType import TxOutputType
from trezor.messages.TxRequest import TxRequest from trezor.messages.TxRequest import TxRequest
from trezor.messages.TxAck import TxAck from trezor.messages.TxAck import TxAck
from trezor.messages.TransactionType import TransactionType from trezor.messages.TransactionType import TransactionType
from trezor.messages.RequestType import TXINPUT, TXOUTPUT, TXFINISHED from trezor.messages.RequestType import TXINPUT, TXMETA, TXOUTPUT, TXFINISHED
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
from trezor.messages import InputScriptType from trezor.messages import InputScriptType
@ -43,6 +44,17 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
sequence=0xfffffffe, sequence=0xfffffffe,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=650645, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('483045022100d9615361c044e91f6dd7bb4455f3ad686cd5a663d7800bb74c448b2706500ccb022026bed24b81a501e8398411c5a9a793741d9bfe39617d51c363dde0a84f44f4f9012102659a6eefcc72d6f2eff92e57095388b17db0b06034946ecd44120e5e7a830ff4'),
prev_hash=unhexlify('1c92508b38239e5c10b23fb46dcf765ee2f3a95b835edbf0943ec21b21711160'),
prev_index=1,
script_type=None,
sequence=4294967293)
pout1 = TxOutputBinType(script_pubkey=unhexlify('0014b31dc2a236505a6cb9201fa0411ca38a254a7bf1'),
amount=12300000)
pout2 = TxOutputBinType(script_pubkey=unhexlify('76a91438cc090e4a4b2e458c33fe35af1c5c0094699ac288ac'),
amount=9887699777)
out1 = TxOutputType( out1 = TxOutputType(
address='2N4Q5FhU2497BryFfUgbqkAJE87aKDv3V3e', address='2N4Q5FhU2497BryFfUgbqkAJE87aKDv3V3e',
amount=5000000, amount=5000000,
@ -66,6 +78,18 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[inp1])), TxAck(tx=TransactionType(inputs=[inp1])),
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])), TxAck(tx=TransactionType(outputs=[out1])),
@ -144,6 +168,17 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
sequence=0xfffffffe, sequence=0xfffffffe,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=650645, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('483045022100d9615361c044e91f6dd7bb4455f3ad686cd5a663d7800bb74c448b2706500ccb022026bed24b81a501e8398411c5a9a793741d9bfe39617d51c363dde0a84f44f4f9012102659a6eefcc72d6f2eff92e57095388b17db0b06034946ecd44120e5e7a830ff4'),
prev_hash=unhexlify('1c92508b38239e5c10b23fb46dcf765ee2f3a95b835edbf0943ec21b21711160'),
prev_index=1,
script_type=None,
sequence=4294967293)
pout1 = TxOutputBinType(script_pubkey=unhexlify('0014b31dc2a236505a6cb9201fa0411ca38a254a7bf1'),
amount=12300000)
pout2 = TxOutputBinType(script_pubkey=unhexlify('76a91438cc090e4a4b2e458c33fe35af1c5c0094699ac288ac'),
amount=9887699777)
out1 = TxOutputType( out1 = TxOutputType(
address='2N4Q5FhU2497BryFfUgbqkAJE87aKDv3V3e', address='2N4Q5FhU2497BryFfUgbqkAJE87aKDv3V3e',
amount=5000000, amount=5000000,
@ -167,6 +202,18 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[inp1])), TxAck(tx=TransactionType(inputs=[inp1])),
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])), TxAck(tx=TransactionType(outputs=[out1])),

View File

@ -5,10 +5,11 @@ from trezor.crypto import bip39
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.TxRequest import TxRequest from trezor.messages.TxRequest import TxRequest
from trezor.messages.TxAck import TxAck from trezor.messages.TxAck import TxAck
from trezor.messages.TransactionType import TransactionType from trezor.messages.TransactionType import TransactionType
from trezor.messages.RequestType import TXINPUT, TXOUTPUT, TXFINISHED from trezor.messages.RequestType import TXINPUT, TXMETA, TXOUTPUT, TXFINISHED
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
from trezor.messages import InputScriptType from trezor.messages import InputScriptType
@ -42,6 +43,17 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
sequence=0xffffffff, sequence=0xffffffff,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=0, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('4730440220548e087d0426b20b8a571b03b9e05829f7558b80c53c12143e342f56ab29e51d02205b68cb7fb223981d4c999725ac1485a982c4259c4f50b8280f137878c232998a012102794a25b254a268e59a5869da57fbae2fadc6727cb3309321dab409b12b2fa17c'),
prev_hash=unhexlify('802cabf0843b945eabe136d7fc7c89f41021658abf56cba000acbce88c41143a'),
prev_index=0,
script_type=None,
sequence=4294967295)
pout1 = TxOutputBinType(script_pubkey=unhexlify('a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
amount=123456789)
pout2 = TxOutputBinType(script_pubkey=unhexlify('76a914b84bacdcd8f4cc59274a5bfb73f804ca10f7fd1488ac'),
amount=865519308)
out1 = TxOutputType( out1 = TxOutputType(
address='mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC', address='mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC',
amount=12300000, amount=12300000,
@ -65,6 +77,18 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[inp1])), TxAck(tx=TransactionType(inputs=[inp1])),
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])), TxAck(tx=TransactionType(outputs=[out1])),
@ -140,6 +164,17 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
sequence=0xffffffff, sequence=0xffffffff,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=0, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('4730440220548e087d0426b20b8a571b03b9e05829f7558b80c53c12143e342f56ab29e51d02205b68cb7fb223981d4c999725ac1485a982c4259c4f50b8280f137878c232998a012102794a25b254a268e59a5869da57fbae2fadc6727cb3309321dab409b12b2fa17c'),
prev_hash=unhexlify('802cabf0843b945eabe136d7fc7c89f41021658abf56cba000acbce88c41143a'),
prev_index=0,
script_type=None,
sequence=4294967295)
pout1 = TxOutputBinType(script_pubkey=unhexlify('a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
amount=123456789)
pout2 = TxOutputBinType(script_pubkey=unhexlify('76a914b84bacdcd8f4cc59274a5bfb73f804ca10f7fd1488ac'),
amount=865519308)
out1 = TxOutputType( out1 = TxOutputType(
address='mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC', address='mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC',
amount=12300000, amount=12300000,
@ -163,6 +198,18 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[inp1])), TxAck(tx=TransactionType(inputs=[inp1])),
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])), TxAck(tx=TransactionType(outputs=[out1])),
@ -232,8 +279,6 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
with self.assertRaises(StopIteration): with self.assertRaises(StopIteration):
signer.send(None) signer.send(None)
# see https://github.com/trezor/trezor-mcu/commit/6b615ce40567cc0da0b3b38ff668916aaae9dd4b#commitcomment-25505919
# for the rational behind this attack
def test_send_p2wpkh_in_p2sh_attack_amount(self): def test_send_p2wpkh_in_p2sh_attack_amount(self):
coin = coins.by_name('Testnet') coin = coins.by_name('Testnet')
@ -249,6 +294,17 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
sequence=0xffffffff, sequence=0xffffffff,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=0, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('4730440220548e087d0426b20b8a571b03b9e05829f7558b80c53c12143e342f56ab29e51d02205b68cb7fb223981d4c999725ac1485a982c4259c4f50b8280f137878c232998a012102794a25b254a268e59a5869da57fbae2fadc6727cb3309321dab409b12b2fa17c'),
prev_hash=unhexlify('802cabf0843b945eabe136d7fc7c89f41021658abf56cba000acbce88c41143a'),
prev_index=0,
script_type=None,
sequence=4294967295)
pout1 = TxOutputBinType(script_pubkey=unhexlify('a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
amount=123456789)
pout2 = TxOutputBinType(script_pubkey=unhexlify('76a914b84bacdcd8f4cc59274a5bfb73f804ca10f7fd1488ac'),
amount=865519308)
inpattack = TxInputType( inpattack = TxInputType(
# 49'/1'/0'/1/0" - 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX # 49'/1'/0'/1/0" - 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
address_n=[49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0], address_n=[49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0],
@ -282,58 +338,19 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[inpattack])), TxAck(tx=TransactionType(inputs=[inpattack])),
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])),
helpers.UiConfirmOutput(out1, coin),
True,
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out2])),
helpers.UiConfirmTotal(8, 0, coin),
True,
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None),
serialized=TxRequestSerializedType(
# returned serialized header
serialized_tx=unhexlify(
'01000000000101'),
)),
TxAck(tx=TransactionType(inputs=[inp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None),
serialized=TxRequestSerializedType(
# returned serialized inpattack
serialized_tx=unhexlify(
'37c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02'),
)),
# the out has to be cloned not to send the same object which was modified
TxAck(tx=TransactionType(outputs=[TxOutputType(**out1.__dict__)])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None),
serialized=TxRequestSerializedType(
# returned serialized out1
serialized_tx=unhexlify(
'08000000000000001976a91414fdede0ddc3be652a0ce1afbc1b509a55b6b94888ac'),
signature_index=None,
signature=None,
)),
TxAck(tx=TransactionType(outputs=[TxOutputType(**out2.__dict__)])),
# segwit
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None),
serialized=TxRequestSerializedType(
# returned serialized out2
serialized_tx=unhexlify(
'010000000000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
signature_index=None,
signature=None,
)),
TxAck(tx=TransactionType(inputs=[inp1])),
TxRequest(request_type=TXFINISHED, details=TxRequestDetailsType())
] ]
ns = get_namespaces_for_coin(coin) ns = get_namespaces_for_coin(coin)
@ -343,7 +360,7 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
messages_count = int(len(messages) / 2) messages_count = int(len(messages) / 2)
for request, response in chunks(messages, 2): for request, response in chunks(messages, 2):
if i == messages_count - 1: # last message should throw wire.Error if i == messages_count - 1: # last message should throw wire.Error
self.assertRaises(wire.ProcessError, signer.send, request) self.assertRaises(wire.DataError, signer.send, request)
else: else:
self.assertEqual(signer.send(request), response) self.assertEqual(signer.send(request), response)
i += 1 i += 1

View File

@ -4,11 +4,12 @@ from trezor.utils import chunks
from trezor.crypto import bip39 from trezor.crypto import bip39
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.TxOutputBinType import TxOutputBinType
from trezor.messages.TxOutputType import TxOutputType from trezor.messages.TxOutputType import TxOutputType
from trezor.messages.TxRequest import TxRequest from trezor.messages.TxRequest import TxRequest
from trezor.messages.TxAck import TxAck from trezor.messages.TxAck import TxAck
from trezor.messages.TransactionType import TransactionType from trezor.messages.TransactionType import TransactionType
from trezor.messages.RequestType import TXINPUT, TXOUTPUT, TXFINISHED from trezor.messages.RequestType import TXINPUT, TXMETA, TXOUTPUT, TXFINISHED
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
from trezor.messages import InputScriptType from trezor.messages import InputScriptType
@ -43,6 +44,17 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
sequence=0xfffffffe, sequence=0xfffffffe,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=650749, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('47304402201f8f57f708144c3a11da322546cb37bd385aa825d940c37e8016f0efd6ec3e9402202a41bc02c29e4f3f13efd4bededbcd4308a6393279111d614ee1f7635cf3e65701210371546a36bdf6bc82087301b3f6e759736dc8790150673d2e7e2715d2ad72f3a4'),
prev_hash=unhexlify('4f2f857f39ed1afe05542d058fb0be865a387446e32fc876d086203f483f61d1'),
prev_index=1,
script_type=None,
sequence=4294967294)
pout1 = TxOutputBinType(script_pubkey=unhexlify('a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
amount=123456789)
pout2 = TxOutputBinType(script_pubkey=unhexlify('76a91435528b20e9a793cf2c3a1cf9cff1f2127ad377da88ac'),
amount=9764242764)
out1 = TxOutputType( out1 = TxOutputType(
address='mvbu1Gdy8SUjTenqerxUaZyYjmvedc787y', address='mvbu1Gdy8SUjTenqerxUaZyYjmvedc787y',
amount=12300000, amount=12300000,
@ -66,6 +78,18 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[inp1])), TxAck(tx=TransactionType(inputs=[inp1])),
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])), TxAck(tx=TransactionType(outputs=[out1])),
@ -144,6 +168,17 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
sequence=0xfffffffe, sequence=0xfffffffe,
multisig=None, multisig=None,
) )
ptx1 = TransactionType(version=1, lock_time=650749, inputs_cnt=1, outputs_cnt=2, extra_data_len=0)
pinp1 = TxInputType(script_sig=unhexlify('47304402201f8f57f708144c3a11da322546cb37bd385aa825d940c37e8016f0efd6ec3e9402202a41bc02c29e4f3f13efd4bededbcd4308a6393279111d614ee1f7635cf3e65701210371546a36bdf6bc82087301b3f6e759736dc8790150673d2e7e2715d2ad72f3a4'),
prev_hash=unhexlify('4f2f857f39ed1afe05542d058fb0be865a387446e32fc876d086203f483f61d1'),
prev_index=1,
script_type=None,
sequence=4294967294)
pout1 = TxOutputBinType(script_pubkey=unhexlify('a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
amount=123456789)
pout2 = TxOutputBinType(script_pubkey=unhexlify('76a91435528b20e9a793cf2c3a1cf9cff1f2127ad377da88ac'),
amount=9764242764)
out1 = TxOutputType( out1 = TxOutputType(
address='mvbu1Gdy8SUjTenqerxUaZyYjmvedc787y', address='mvbu1Gdy8SUjTenqerxUaZyYjmvedc787y',
amount=12300000, amount=12300000,
@ -167,6 +202,18 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[inp1])), TxAck(tx=TransactionType(inputs=[inp1])),
TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=ptx1),
TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(inputs=[pinp1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout1])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=inp1.prev_hash), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(bin_outputs=[pout2])),
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED), TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
TxAck(tx=TransactionType(outputs=[out1])), TxAck(tx=TransactionType(outputs=[out1])),

View File

@ -46,6 +46,9 @@ typedef uint32_t b58_almostmaxint_t;
static const b58_almostmaxint_t b58_almostmaxint_mask = static const b58_almostmaxint_t b58_almostmaxint_mask =
((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1);
// Decodes a null-terminated Base58 string `b58` to binary and writes the result
// at the end of the buffer `bin` of size `*binszp`. On success `*binszp` is set
// to the number of valid bytes at the end of the buffer.
bool b58tobin(void *bin, size_t *binszp, const char *b58) { bool b58tobin(void *bin, size_t *binszp, const char *b58) {
size_t binsz = *binszp; size_t binsz = *binszp;
@ -108,20 +111,18 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58) {
} }
} }
// Count canonical base58 byte count // locate the most significant byte
binu = bin; binu = bin;
for (i = 0; i < binsz; ++i) { for (i = 0; i < binsz; ++i) {
if (binu[i]) { if (binu[i]) break;
}
// prepend the correct number of null-bytes
if (zerocount > i) { if (zerocount > i) {
/* result too large */ /* result too large */
return false; return false;
} }
*binszp = binsz - i + zerocount;
break;
}
--*binszp;
}
*binszp += zerocount;
return true; return true;
} }

File diff suppressed because it is too large Load Diff

View File

@ -28,141 +28,145 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "options.h" #include "options.h"
// bignum256 are 256 bits stored as 8*30 bit + 1*16 bit #define BN_LIMBS 9
// val[0] are lowest 30 bits, val[8] highest 16 bits #define BN_BITS_PER_LIMB 29
#define BN_BASE (1u << BN_BITS_PER_LIMB)
#define BN_LIMB_MASK ((1u << BN_BITS_PER_LIMB) - 1)
#define BN_EXTRA_BITS (32 - BN_BITS_PER_LIMB)
#define BN_BITS_LAST_LIMB (256 - (BN_LIMBS - 1) * BN_BITS_PER_LIMB)
// Represents the number sum([val[i] * 2**(29*i) for i in range(9))
typedef struct { typedef struct {
uint32_t val[9]; uint32_t val[BN_LIMBS];
} bignum256; } bignum256;
// read 4 big endian bytes into uint32 static inline uint32_t read_be(const uint8_t *data) {
uint32_t read_be(const uint8_t *data); return (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) |
(((uint32_t)data[2]) << 8) | (((uint32_t)data[3]));
}
// write 4 big endian bytes static inline void write_be(uint8_t *data, uint32_t x) {
void write_be(uint8_t *data, uint32_t x); data[0] = x >> 24;
data[1] = x >> 16;
data[2] = x >> 8;
data[3] = x;
}
// read 4 little endian bytes into uint32 static inline uint32_t read_le(const uint8_t *data) {
uint32_t read_le(const uint8_t *data); return (((uint32_t)data[3]) << 24) | (((uint32_t)data[2]) << 16) |
(((uint32_t)data[1]) << 8) | (((uint32_t)data[0]));
}
// write 4 little endian bytes static inline void write_le(uint8_t *data, uint32_t x) {
void write_le(uint8_t *data, uint32_t x); data[3] = x >> 24;
data[2] = x >> 16;
data[1] = x >> 8;
data[0] = x;
}
void bn_read_be(const uint8_t *in_number, bignum256 *out_number); void bn_read_be(const uint8_t *in_number, bignum256 *out_number);
void bn_write_be(const bignum256 *in_number, uint8_t *out_number); void bn_write_be(const bignum256 *in_number, uint8_t *out_number);
void bn_read_le(const uint8_t *in_number, bignum256 *out_number); void bn_read_le(const uint8_t *in_number, bignum256 *out_number);
void bn_write_le(const bignum256 *in_number, uint8_t *out_number); void bn_write_le(const bignum256 *in_number, uint8_t *out_number);
void bn_read_uint32(uint32_t in_number, bignum256 *out_number); void bn_read_uint32(uint32_t in_number, bignum256 *out_number);
void bn_read_uint64(uint64_t in_number, bignum256 *out_number); void bn_read_uint64(uint64_t in_number, bignum256 *out_number);
int bn_bitcount(const bignum256 *x);
static inline uint32_t bn_write_uint32(const bignum256 *in_number) { unsigned int bn_digitcount(const bignum256 *x);
return in_number->val[0] | (in_number->val[1] << 30); void bn_zero(bignum256 *x);
} void bn_one(bignum256 *x);
int bn_is_zero(const bignum256 *x);
static inline uint64_t bn_write_uint64(const bignum256 *in_number) { int bn_is_one(const bignum256 *x);
uint64_t tmp; int bn_is_less(const bignum256 *x, const bignum256 *y);
tmp = in_number->val[2]; int bn_is_equal(const bignum256 *x, const bignum256 *y);
tmp <<= 30; void bn_cmov(bignum256 *res, volatile uint32_t cond, const bignum256 *truecase,
tmp |= in_number->val[1];
tmp <<= 30;
tmp |= in_number->val[0];
return tmp;
}
// copies number a to b
static inline void bn_copy(const bignum256 *a, bignum256 *b) { *b = *a; }
int bn_bitcount(const bignum256 *a);
unsigned int bn_digitcount(const bignum256 *a);
void bn_zero(bignum256 *a);
int bn_is_zero(const bignum256 *a);
void bn_one(bignum256 *a);
static inline int bn_is_even(const bignum256 *a) {
return (a->val[0] & 1) == 0;
}
static inline int bn_is_odd(const bignum256 *a) { return (a->val[0] & 1) == 1; }
int bn_is_less(const bignum256 *a, const bignum256 *b);
int bn_is_equal(const bignum256 *a, const bignum256 *b);
void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase,
const bignum256 *falsecase); const bignum256 *falsecase);
void bn_cnegate(volatile uint32_t cond, bignum256 *x, const bignum256 *prime);
void bn_lshift(bignum256 *a); void bn_lshift(bignum256 *x);
void bn_rshift(bignum256 *x);
void bn_rshift(bignum256 *a); void bn_setbit(bignum256 *x, uint16_t i);
void bn_clearbit(bignum256 *x, uint16_t i);
void bn_setbit(bignum256 *a, uint8_t bit); uint32_t bn_testbit(const bignum256 *x, uint16_t i);
void bn_xor(bignum256 *res, const bignum256 *x, const bignum256 *y);
void bn_clearbit(bignum256 *a, uint8_t bit);
uint32_t bn_testbit(bignum256 *a, uint8_t bit);
void bn_xor(bignum256 *a, const bignum256 *b, const bignum256 *c);
void bn_mult_half(bignum256 *x, const bignum256 *prime); void bn_mult_half(bignum256 *x, const bignum256 *prime);
void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime); void bn_mult_k(bignum256 *x, uint8_t k, const bignum256 *prime);
void bn_mod(bignum256 *x, const bignum256 *prime); void bn_mod(bignum256 *x, const bignum256 *prime);
void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime); void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime);
void bn_fast_mod_old(bignum256 *x, const bignum256 *prime);
void bn_fast_mod(bignum256 *x, const bignum256 *prime); void bn_fast_mod(bignum256 *x, const bignum256 *prime);
void bn_power_mod(const bignum256 *x, const bignum256 *e,
const bignum256 *prime, bignum256 *res);
void bn_sqrt(bignum256 *x, const bignum256 *prime); void bn_sqrt(bignum256 *x, const bignum256 *prime);
uint32_t inverse_mod_power_two(uint32_t a, uint32_t n);
void bn_inverse(bignum256 *x, const bignum256 *prime); void bn_divide_base(bignum256 *x, const bignum256 *prime);
void bn_inverse_slow(bignum256 *x, const bignum256 *prime);
void bn_normalize(bignum256 *a); void bn_inverse_fast_1(bignum256 *x, const bignum256 *prime);
void bn_inverse_fast_2(bignum256 *x, const bignum256 *prime);
void bn_add(bignum256 *a, const bignum256 *b); void bn_inverse_fast_3(bignum256 *x, const bignum256 *prime);
void bn_inverse_old(bignum256 *x, const bignum256 *prime);
void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime); void bn_normalize(bignum256 *x);
void bn_add(bignum256 *x, const bignum256 *y);
void bn_addi(bignum256 *a, uint32_t b); void bn_addmod(bignum256 *x, const bignum256 *y, const bignum256 *prime);
void bn_addi(bignum256 *x, uint32_t y);
void bn_subi(bignum256 *a, uint32_t b, const bignum256 *prime); void bn_subi(bignum256 *x, uint32_t y, const bignum256 *prime);
void bn_subtractmod(const bignum256 *x, const bignum256 *y, bignum256 *res,
void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res,
const bignum256 *prime); const bignum256 *prime);
void bn_subtract(const bignum256 *x, const bignum256 *y, bignum256 *res);
void bn_long_division(bignum256 *x, uint32_t d, bignum256 *q, uint32_t *r);
void bn_divmod58(bignum256 *x, uint32_t *r);
void bn_divmod1000(bignum256 *x, uint32_t *r);
void bn_inverse(bignum256 *x, const bignum256 *prime);
size_t bn_format(const bignum256 *amount, const char *prefix,
const char *suffix, unsigned int decimals, int exponent,
bool trailing, char *output, size_t output_length);
void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res); // Returns (uint32_t) in_number
// Assumes in_number < 2**32
// Assumes in_number is normalized
static inline uint32_t bn_write_uint32(const bignum256 *in_number) {
return in_number->val[0] | (in_number->val[1] << BN_BITS_PER_LIMB);
}
void bn_divmod58(bignum256 *a, uint32_t *r); // Returns (uint64_t) in_number
// Assumes in_number < 2**64
// Assumes in_number is normalized
static inline uint64_t bn_write_uint64(const bignum256 *in_number) {
uint64_t acc;
acc = in_number->val[2];
acc <<= BN_BITS_PER_LIMB;
acc |= in_number->val[1];
acc <<= BN_BITS_PER_LIMB;
acc |= in_number->val[0];
return acc;
}
void bn_divmod1000(bignum256 *a, uint32_t *r); // y = x
static inline void bn_copy(const bignum256 *x, bignum256 *y) { *y = *x; }
size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, // Returns x % 2 == 0
unsigned int decimals, int exponent, bool trailing, char *out, static inline int bn_is_even(const bignum256 *x) {
size_t outlen); return (x->val[0] & 1) == 0;
}
// Returns x % 2 == 0
static inline int bn_is_odd(const bignum256 *x) { return (x->val[0] & 1) == 1; }
static inline size_t bn_format_uint64(uint64_t amount, const char *prefix, static inline size_t bn_format_uint64(uint64_t amount, const char *prefix,
const char *suffix, unsigned int decimals, const char *suffix, unsigned int decimals,
int exponent, bool trailing, char *out, int exponent, bool trailing, char *output,
size_t outlen) { size_t output_length) {
bignum256 amnt; bignum256 bn_amount;
bn_read_uint64(amount, &amnt); bn_read_uint64(amount, &bn_amount);
return bn_format(&amnt, prefix, suffix, decimals, exponent, trailing, out, return bn_format(&bn_amount, prefix, suffix, decimals, exponent, trailing,
outlen); output, output_length);
} }
#if USE_BN_PRINT #if USE_BN_PRINT
void bn_print(const bignum256 *a); void bn_print(const bignum256 *x);
void bn_print_raw(const bignum256 *a); void bn_print_raw(const bignum256 *x);
#endif #endif
#endif #endif

View File

@ -61,6 +61,7 @@ void point_add(const ecdsa_curve *curve, const curve_point *cp1,
return; return;
} }
// lambda = (y2 - y1) / (x2 - x1)
bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &curve->prime); bn_subtractmod(&(cp2->x), &(cp1->x), &inv, &curve->prime);
bn_inverse(&inv, &curve->prime); bn_inverse(&inv, &curve->prime);
bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &curve->prime); bn_subtractmod(&(cp2->y), &(cp1->y), &lambda, &curve->prime);
@ -101,6 +102,8 @@ void point_double(const ecdsa_curve *curve, curve_point *cp) {
// lambda = (3 x^2 + a) / (2 y) // lambda = (3 x^2 + a) / (2 y)
lambda = cp->y; lambda = cp->y;
bn_mult_k(&lambda, 2, &curve->prime); bn_mult_k(&lambda, 2, &curve->prime);
bn_fast_mod(&lambda, &curve->prime);
bn_mod(&lambda, &curve->prime);
bn_inverse(&lambda, &curve->prime); bn_inverse(&lambda, &curve->prime);
xr = cp->x; xr = cp->x;
@ -162,22 +165,6 @@ int point_is_negative_of(const curve_point *p, const curve_point *q) {
return !bn_is_equal(&(p->y), &(q->y)); return !bn_is_equal(&(p->y), &(q->y));
} }
// Negate a (modulo prime) if cond is 0xffffffff, keep it if cond is 0.
// The timing of this function does not depend on cond.
void conditional_negate(uint32_t cond, bignum256 *a, const bignum256 *prime) {
int j = 0;
uint32_t tmp = 1;
assert(a->val[8] < 0x20000);
for (j = 0; j < 8; j++) {
tmp += 0x3fffffff + 2 * prime->val[j] - a->val[j];
a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond);
tmp >>= 30;
}
tmp += 0x3fffffff + 2 * prime->val[j] - a->val[j];
a->val[j] = ((tmp & 0x3fffffff) & cond) | (a->val[j] & ~cond);
assert(a->val[8] < 0x20000);
}
typedef struct jacobian_curve_point { typedef struct jacobian_curve_point {
bignum256 x, y, z; bignum256 x, y, z;
} jacobian_curve_point; } jacobian_curve_point;
@ -187,9 +174,9 @@ static void generate_k_random(bignum256 *k, const bignum256 *prime) {
do { do {
int i = 0; int i = 0;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
k->val[i] = random32() & 0x3FFFFFFF; k->val[i] = random32() & ((1u << BN_BITS_PER_LIMB) - 1);
} }
k->val[8] = random32() & 0xFFFF; k->val[8] = random32() & ((1u << BN_BITS_LAST_LIMB) - 1);
// check that k is in range and not zero. // check that k is in range and not zero.
} while (bn_is_zero(k) || !bn_is_less(k, prime)); } while (bn_is_zero(k) || !bn_is_less(k, prime));
} }
@ -443,12 +430,12 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k,
uint32_t is_non_zero = 0; uint32_t is_non_zero = 0;
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
is_non_zero |= k->val[j]; is_non_zero |= k->val[j];
tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even); tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even);
a.val[j] = tmp & 0x3fffffff; a.val[j] = tmp & (BN_BASE - 1);
tmp >>= 30; tmp >>= BN_BITS_PER_LIMB;
} }
is_non_zero |= k->val[j]; is_non_zero |= k->val[j];
a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even); a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even);
assert((a.val[0] & 1) != 0); assert((a.val[0] & 1) != 0);
// special case 0*p: just return zero. We don't care about constant time. // special case 0*p: just return zero. We don't care about constant time.
@ -490,7 +477,7 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k,
// since a is odd. // since a is odd.
aptr = &a.val[8]; aptr = &a.val[8];
abits = *aptr; abits = *aptr;
ashift = 12; ashift = 256 - (BN_BITS_PER_LIMB * 8) - 4;
bits = abits >> ashift; bits = abits >> ashift;
sign = (bits >> 4) - 1; sign = (bits >> 4) - 1;
bits ^= sign; bits ^= sign;
@ -513,7 +500,7 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k,
// leaks no private information to a side-channel. // leaks no private information to a side-channel.
bits = abits << (-ashift); bits = abits << (-ashift);
abits = *(--aptr); abits = *(--aptr);
ashift += 30; ashift += BN_BITS_PER_LIMB;
bits |= abits >> ashift; bits |= abits >> ashift;
} else { } else {
bits = abits >> ashift; bits = abits >> ashift;
@ -525,13 +512,13 @@ void point_multiply(const ecdsa_curve *curve, const bignum256 *k,
// negate last result to make signs of this round and the // negate last result to make signs of this round and the
// last round equal. // last round equal.
conditional_negate(sign ^ nsign, &jres.z, prime); bn_cnegate((sign ^ nsign) & 1, &jres.z, prime);
// add odd factor // add odd factor
point_jacobian_add(&pmult[bits >> 1], &jres, curve); point_jacobian_add(&pmult[bits >> 1], &jres, curve);
sign = nsign; sign = nsign;
} }
conditional_negate(sign, &jres.z, prime); bn_cnegate(sign & 1, &jres.z, prime);
jacobian_to_curve(&jres, res, prime); jacobian_to_curve(&jres, res, prime);
memzero(&a, sizeof(a)); memzero(&a, sizeof(a));
memzero(&jres, sizeof(jres)); memzero(&jres, sizeof(jres));
@ -560,12 +547,12 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k,
uint32_t is_non_zero = 0; uint32_t is_non_zero = 0;
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
is_non_zero |= k->val[j]; is_non_zero |= k->val[j];
tmp += 0x3fffffff + k->val[j] - (curve->order.val[j] & is_even); tmp += (BN_BASE - 1) + k->val[j] - (curve->order.val[j] & is_even);
a.val[j] = tmp & 0x3fffffff; a.val[j] = tmp & (BN_BASE - 1);
tmp >>= 30; tmp >>= BN_BITS_PER_LIMB;
} }
is_non_zero |= k->val[j]; is_non_zero |= k->val[j];
a.val[j] = tmp + 0xffff + k->val[j] - (curve->order.val[j] & is_even); a.val[j] = tmp + 0xffffff + k->val[j] - (curve->order.val[j] & is_even);
assert((a.val[0] & 1) != 0); assert((a.val[0] & 1) != 0);
// special case 0*G: just return zero. We don't care about constant time. // special case 0*G: just return zero. We don't care about constant time.
@ -603,7 +590,8 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k,
// shift a by 4 places. // shift a by 4 places.
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
a.val[j] = (a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << 26); a.val[j] =
(a.val[j] >> 4) | ((a.val[j + 1] & 0xf) << (BN_BITS_PER_LIMB - 4));
} }
a.val[j] >>= 4; a.val[j] >>= 4;
// a = old(a)>>(4*i) // a = old(a)>>(4*i)
@ -614,12 +602,12 @@ void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k,
lowbits &= 15; lowbits &= 15;
// negate last result to make signs of this round and the // negate last result to make signs of this round and the
// last round equal. // last round equal.
conditional_negate((lowbits & 1) - 1, &jres.y, prime); bn_cnegate(~lowbits & 1, &jres.y, prime);
// add odd factor // add odd factor
point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, curve); point_jacobian_add(&curve->cp[i][lowbits >> 1], &jres, curve);
} }
conditional_negate(((a.val[0] >> 4) & 1) - 1, &jres.y, prime); bn_cnegate(~(a.val[0] >> 4) & 1, &jres.y, prime);
jacobian_to_curve(&jres, res, prime); jacobian_to_curve(&jres, res, prime);
memzero(&a, sizeof(a)); memzero(&a, sizeof(a));
memzero(&jres, sizeof(jres)); memzero(&jres, sizeof(jres));

View File

@ -102,6 +102,8 @@ bool decode_block(const char* block, size_t size, char* res)
uint64_t order = 1; uint64_t order = 1;
for (size_t i = size - 1; i < size; --i) for (size_t i = size - 1; i < size; --i)
{ {
if (block[i] & 0x80)
return false; // Invalid symbol
int digit = reverse_alphabet(block[i]); int digit = reverse_alphabet(block[i]);
if (digit < 0) if (digit < 0)
return false; // Invalid symbol return false; // Invalid symbol

View File

@ -24,30 +24,31 @@
#include "nist256p1.h" #include "nist256p1.h"
const ecdsa_curve nist256p1 = { const ecdsa_curve nist256p1 = {
/* .prime */ {/*.val =*/{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, /* .prime */ {/*.val =*/{0x1fffffff, 0x1fffffff, 0x1fffffff, 0x000001ff,
0x1000, 0x3fffc000, 0xffff}}, 0x00000000, 0x00000000, 0x00040000, 0x1fe00000,
0xffffff}},
/* G */ /* G */
{/*.x =*/{/*.val =*/{0x1898c296, 0x1284e517, 0x1eb33a0f, 0xdf604b, {/*.x =*/{/*.val =*/{0x1898c296, 0x0509ca2e, 0x1acce83d, 0x06fb025b,
0x2440f277, 0x339b958e, 0x4247f8b, 0x347cb84b, 0x040f2770, 0x1372b1d2, 0x091fe2f3, 0x1e5c2588,
0x6b17}}, 0x6b17d1}},
/*.y =*/{/*.val =*/{0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da, /*.y =*/{/*.val =*/{0x17bf51f5, 0x1db20341, 0x0c57b3b2, 0x1c66aed6,
0xf9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86, 0x19e162bc, 0x15a53e07, 0x1e6e3b9f, 0x1c5fc34f,
0x4fe3}}}, 0x4fe342}}},
/* order */ /* order */
{/*.val =*/{0x3c632551, 0xee72b0b, 0x3179e84f, 0x39beab69, 0x3fffffbc, {/*.val =*/{0x1c632551, 0x1dce5617, 0x05e7a13c, 0x0df55b4e, 0x1ffffbce,
0x3fffffff, 0xfff, 0x3fffc000, 0xffff}}, 0x1fffffff, 0x0003ffff, 0x1fe00000, 0xffffff}},
/* order_half */ /* order_half */
{/*.val =*/{0x3e3192a8, 0x27739585, 0x38bcf427, 0x1cdf55b4, 0x3fffffde, {/*.val =*/{0x1e3192a8, 0x0ee72b0b, 0x02f3d09e, 0x06faada7, 0x1ffffde7,
0x3fffffff, 0x7ff, 0x3fffe000, 0x7fff}}, 0x1fffffff, 0x0001ffff, 0x1ff00000, 0x7fffff}},
/* a */ -3, /* a */ -3,
/* b */ /* b */
{/*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, {/*.val =*/{0x07d2604b, 0x1e71e1f1, 0x14ec3d8e, 0x1a0d6198, 0x086bc651,
0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6}} 0x1eaabb4c, 0x0f9ecfae, 0x1b154752, 0x005ac635}}
#if USE_PRECOMPUTED_CP #if USE_PRECOMPUTED_CP
, ,

File diff suppressed because it is too large Load Diff

View File

@ -24,24 +24,25 @@
#include "secp256k1.h" #include "secp256k1.h"
const ecdsa_curve secp256k1 = { const ecdsa_curve secp256k1 = {
/* .prime */ {/*.val =*/{0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, /* .prime */ {/*.val =*/{0x1ffffc2f, 0x1ffffff7, 0x1fffffff, 0x1fffffff,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
0xffff}}, 0xffffff}},
/* G */ /* G */
{/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, {/*.x =*/{/*.val =*/{0x16f81798, 0x0f940ad8, 0x138a3656, 0x17f9b65b,
0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}}, 0x10b07029, 0x114ae743, 0x0eb15681, 0x0fdf3b97,
/*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x79be66}},
0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, /*.y =*/{/*.val =*/{0x1b10d4b8, 0x023e847f, 0x01550667, 0x0f68914d,
0x483a}}}, 0x108a8fd1, 0x1dfe0708, 0x11957693, 0x0ee4d478,
0x483ada}}},
/* order */ /* order */
{/*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, {/*.val =*/{0x10364141, 0x1e92f466, 0x12280eef, 0x1db9cd5e, 0x1fffebaa,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}}, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0xffffff}},
/* order_half */ /* order_half */
{/*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, {/*.val =*/{0x081b20a0, 0x1f497a33, 0x09140777, 0x0edce6af, 0x1ffff5d5,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}}, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x7fffff}},
/* a */ 0, /* a */ 0,

File diff suppressed because it is too large Load Diff

1028
crypto/tests/test_bignum.py Executable file

File diff suppressed because it is too large Load Diff

View File

@ -131,8 +131,8 @@ START_TEST(test_bignum_read_be) {
bn_read_be(input, &a); bn_read_be(input, &a);
bignum256 b = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, bignum256 b = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b,
0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}}; 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}};
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
ck_assert_int_eq(a.val[i], b.val[i]); ck_assert_int_eq(a.val[i], b.val[i]);
@ -141,8 +141,8 @@ START_TEST(test_bignum_read_be) {
END_TEST END_TEST
START_TEST(test_bignum_write_be) { START_TEST(test_bignum_write_be) {
bignum256 a = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, bignum256 a = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b,
0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}}; 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}};
uint8_t tmp[32]; uint8_t tmp[32];
bn_write_be(&a, tmp); bn_write_be(&a, tmp);
@ -156,10 +156,10 @@ START_TEST(test_bignum_write_be) {
END_TEST END_TEST
START_TEST(test_bignum_is_equal) { START_TEST(test_bignum_is_equal) {
bignum256 a = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, bignum256 a = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b,
0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}}; 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}};
bignum256 b = {{0x286d8bd5, 0x380c7c17, 0x3c6a2ec1, 0x2d787ef5, 0x14437cd3, bignum256 b = {{0x086d8bd5, 0x1018f82f, 0x11a8bb07, 0x0bc3f7af, 0x0437cd3b,
0x25a043f8, 0x1dd5263f, 0x33a162c3, 0x0000c55e}}; 0x14087f0a, 0x15498fe5, 0x10b161bb, 0xc55ece}};
bignum256 c = {{ bignum256 c = {{
0, 0,
}}; }};
@ -339,6 +339,13 @@ END_TEST
START_TEST(test_bignum_write_uint32) { START_TEST(test_bignum_write_uint32) {
bignum256 a; bignum256 a;
// lowest 29 bits set
bn_read_be(
fromhex(
"000000000000000000000000000000000000000000000000000000001fffffff"),
&a);
ck_assert_int_eq(bn_write_uint32(&a), 0x1fffffff);
// lowest 30 bits set // lowest 30 bits set
bn_read_be( bn_read_be(
fromhex( fromhex(
@ -637,8 +644,8 @@ START_TEST(test_bignum_format) {
"0000000000000000000000000000000000000000000000000000000000000000"), "0000000000000000000000000000000000000000000000000000000000000000"),
&a); &a);
r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf));
ck_assert_int_eq(r, 3); ck_assert_int_eq(r, 1);
ck_assert_str_eq(buf, "0.0"); ck_assert_str_eq(buf, "0");
bn_read_be( bn_read_be(
fromhex( fromhex(
@ -757,8 +764,8 @@ START_TEST(test_bignum_format) {
"0000000000000000000000000000000000000000000000000000000000989680"), "0000000000000000000000000000000000000000000000000000000000989680"),
&a); &a);
r = bn_format(&a, NULL, NULL, 7, 0, false, buf, sizeof(buf)); r = bn_format(&a, NULL, NULL, 7, 0, false, buf, sizeof(buf));
ck_assert_int_eq(r, 3); ck_assert_int_eq(r, 1);
ck_assert_str_eq(buf, "1.0"); ck_assert_str_eq(buf, "1");
bn_read_be( bn_read_be(
fromhex( fromhex(
@ -805,10 +812,10 @@ START_TEST(test_bignum_format) {
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3bbb00"),
&a); &a);
r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf)); r = bn_format(&a, NULL, NULL, 8, 0, false, buf, sizeof(buf));
ck_assert_int_eq(r, 72); ck_assert_int_eq(r, 70);
ck_assert_str_eq(buf, ck_assert_str_eq(buf,
"11579208923731619542357098500868790785326998466564056403945" "11579208923731619542357098500868790785326998466564056403945"
"75840079131.0"); "75840079131");
bn_read_be( bn_read_be(
fromhex( fromhex(
@ -825,9 +832,9 @@ START_TEST(test_bignum_format) {
"fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"), "fffffffffffffffffffffffffffffffffffffffffffffffff7e52fe5afe40000"),
&a); &a);
r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf)); r = bn_format(&a, NULL, NULL, 18, 0, false, buf, sizeof(buf));
ck_assert_int_eq(r, 62); ck_assert_int_eq(r, 60);
ck_assert_str_eq( ck_assert_str_eq(
buf, "115792089237316195423570985008687907853269984665640564039457.0"); buf, "115792089237316195423570985008687907853269984665640564039457");
bn_read_be( bn_read_be(
fromhex( fromhex(
@ -875,7 +882,69 @@ START_TEST(test_bignum_format) {
memset(buf, 'a', sizeof(buf)); memset(buf, 'a', sizeof(buf));
r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 30); r = bn_format(&a, "prefix", "suffix", 10, 0, false, buf, 30);
ck_assert_int_eq(r, 0); ck_assert_int_eq(r, 0);
ck_assert_str_eq(buf, "prefix198552.9216486895suffix"); ck_assert_str_eq(buf, "");
}
END_TEST
START_TEST(test_bignum_sqrt) {
uint32_t quadratic_residua[] = {
1, 2, 4, 8, 9, 11, 15, 16, 17, 18, 19, 21, 22, 25, 29,
30, 31, 32, 34, 35, 36, 38, 39, 42, 43, 44, 47, 49, 50, 58,
59, 60, 61, 62, 64, 65, 67, 68, 69, 70, 71, 72, 76, 78, 81,
83, 84, 86, 88, 91, 94, 98, 99, 100, 103, 107, 111, 115, 116, 118,
120, 121, 122, 123, 124, 127, 128, 130, 131, 134, 135, 136, 137, 138, 139,
140, 142, 144, 149, 152, 153, 156, 159, 161, 162, 165, 166, 167, 168, 169,
171, 172, 176, 181, 182, 185, 187, 188, 189, 191, 193, 196, 197, 198, 200,
205, 206, 209, 214, 219, 222, 223, 225, 229, 230, 231, 232, 233, 236, 237,
239, 240, 242, 244, 246, 248, 254, 255, 256, 259, 260, 261, 262, 265, 267,
268, 269, 270, 272, 274, 275, 276, 277, 278, 279, 280, 281, 284, 285, 287,
288, 289, 291, 293, 298, 299, 303, 304, 306, 311, 312, 315, 318, 319, 322,
323, 324, 327, 330, 331, 332, 334, 336, 337, 338, 339, 341, 342, 344, 349,
351, 352, 353, 357, 359, 361, 362, 364, 365, 370, 371, 373, 374, 375, 376,
378, 379, 382, 383, 385, 386, 387, 389, 392, 394, 395, 396, 399, 400, 409,
410, 412, 418, 421, 423, 425, 428, 429, 431, 435, 438, 439, 441, 443, 444,
445, 446, 450, 453, 458, 460, 461, 462, 463, 464, 465, 466, 467, 471, 472,
473, 474, 475, 478, 479, 480, 481, 484, 485, 487, 488, 489, 492, 493, 496,
503, 505, 508, 510, 511, 512, 517, 518, 519, 520, 521, 522, 523, 524, 525,
527, 529, 530, 531, 533, 534, 536, 537, 538, 539, 540, 541, 544, 545, 547,
548, 549, 550, 551, 552, 553, 554, 556, 557, 558, 560, 562, 563, 565, 568,
570, 571, 574, 576, 578, 582, 585, 586, 587, 589, 595, 596, 597, 598, 599,
603, 606, 607, 608, 609, 612, 613, 619, 621, 622, 623, 624, 625, 630, 633,
636, 638, 639, 644, 645, 646, 648, 649, 651, 653, 654, 660, 662, 663, 664,
665, 668, 671, 672, 673, 674, 676, 678, 679, 681, 682, 684, 688, 689, 698,
702, 704, 705, 706, 707, 714, 715, 718, 722, 723, 724, 725, 728, 729, 730,
731, 733, 735, 737, 740, 741, 742, 746, 747, 748, 750, 751, 752, 753, 755,
756, 758, 759, 761, 763, 764, 766, 769, 770, 771, 772, 774, 775, 778, 781,
784, 785, 788, 789, 790, 791, 792, 797, 798, 799, 800, 813, 815, 817, 818,
819, 820, 823, 824, 833, 836, 841, 842, 846, 849, 850, 851, 856, 857, 858,
862, 865, 870, 875, 876, 878, 882, 885, 886, 887, 888, 890, 891, 892, 893,
895, 899, 900, 903, 906, 907, 911, 913, 915, 916, 919, 920, 921, 922, 924,
926, 927, 928, 930, 931, 932, 934, 937, 939, 942, 943, 944, 946, 948, 949,
950, 951, 953, 956, 958, 960, 961, 962, 963, 968, 970, 971, 974, 975, 976,
977, 978, 984, 986, 987, 992, 995, 999};
bignum256 a, b;
bn_zero(&a);
b = a;
bn_sqrt(&b, &secp256k1.prime);
ck_assert_int_eq(bn_is_equal(&a, &b), 1);
bn_one(&a);
b = a;
bn_sqrt(&b, &secp256k1.prime);
ck_assert_int_eq(bn_is_equal(&a, &b), 1);
// test some quadratic residua
for (size_t i = 0; i < sizeof(quadratic_residua) / sizeof(*quadratic_residua);
i++) {
bn_read_uint32(quadratic_residua[i], &a);
b = a;
bn_sqrt(&b, &secp256k1.prime);
bn_multiply(&b, &b, &secp256k1.prime);
bn_mod(&b, &secp256k1.prime);
ck_assert_int_eq(bn_is_equal(&a, &b), 1);
}
} }
END_TEST END_TEST
@ -1102,12 +1171,16 @@ START_TEST(test_bignum_divmod) {
uint32_t r; uint32_t r;
int i; int i;
bignum256 a = {{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, bignum256 a;
0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}};
uint32_t ar[] = {15, 14, 55, 29, 44, 24, 53, 49, 18, 55, 2, 28, 5, 4, 12, uint32_t ar[] = {15, 14, 55, 29, 44, 24, 53, 49, 18, 55, 2, 28, 5, 4, 12,
43, 18, 37, 28, 14, 30, 46, 12, 11, 17, 10, 10, 13, 24, 45, 43, 18, 37, 28, 14, 30, 46, 12, 11, 17, 10, 10, 13, 24, 45,
4, 33, 44, 42, 2, 46, 34, 43, 45, 28, 21, 18, 13, 17}; 4, 33, 44, 42, 2, 46, 34, 43, 45, 28, 21, 18, 13, 17};
bn_read_be(
fromhex(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
&a);
i = 0; i = 0;
while (!bn_is_zero(&a) && i < 44) { while (!bn_is_zero(&a) && i < 44) {
bn_divmod58(&a, &r); bn_divmod58(&a, &r);
@ -1116,12 +1189,15 @@ START_TEST(test_bignum_divmod) {
} }
ck_assert_int_eq(i, 44); ck_assert_int_eq(i, 44);
bignum256 b = {{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, bignum256 b;
0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}};
uint32_t br[] = {935, 639, 129, 913, 7, 584, 457, 39, 564, uint32_t br[] = {935, 639, 129, 913, 7, 584, 457, 39, 564,
640, 665, 984, 269, 853, 907, 687, 8, 985, 640, 665, 984, 269, 853, 907, 687, 8, 985,
570, 423, 195, 316, 237, 89, 792, 115}; 570, 423, 195, 316, 237, 89, 792, 115};
bn_read_be(
fromhex(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
&b);
i = 0; i = 0;
while (!bn_is_zero(&b) && i < 26) { while (!bn_is_zero(&b) && i < 26) {
bn_divmod1000(&b, &r); bn_divmod1000(&b, &r);
@ -5904,7 +5980,8 @@ static void test_codepoints_curve(const ecdsa_curve *curve) {
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
bn_zero(&a); bn_zero(&a);
a.val[(4 * i) / 30] = (uint32_t)(2 * j + 1) << (4 * i % 30); a.val[(4 * i) / BN_BITS_PER_LIMB] = (uint32_t)(2 * j + 1)
<< (4 * i % BN_BITS_PER_LIMB);
bn_normalize(&a); bn_normalize(&a);
// note that this is not a trivial test. We add 64 curve // note that this is not a trivial test. We add 64 curve
// points in the table to get that particular curve point. // points in the table to get that particular curve point.
@ -8670,6 +8747,7 @@ Suite *test_suite(void) {
tcase_add_test(tc, test_bignum_is_less); tcase_add_test(tc, test_bignum_is_less);
tcase_add_test(tc, test_bignum_format); tcase_add_test(tc, test_bignum_format);
tcase_add_test(tc, test_bignum_format_uint64); tcase_add_test(tc, test_bignum_format_uint64);
tcase_add_test(tc, test_bignum_sqrt);
suite_add_tcase(s, tc); suite_add_tcase(s, tc);
tc = tcase_create("base32"); tc = tcase_create("base32");

View File

@ -80,14 +80,29 @@ random_iters = int(os.environ.get("ITERS", 1))
DIR = os.path.abspath(os.path.dirname(__file__)) DIR = os.path.abspath(os.path.dirname(__file__))
lib = c.cdll.LoadLibrary(os.path.join(DIR, "libtrezor-crypto.so")) lib = c.cdll.LoadLibrary(os.path.join(DIR, "libtrezor-crypto.so"))
BIGNUM = c.c_uint32 * 9
class curve_info(c.Structure): class curve_info(c.Structure):
_fields_ = [("bip32_name", c.c_char_p), ("params", c.c_void_p)] _fields_ = [("bip32_name", c.c_char_p), ("params", c.c_void_p)]
lib.get_curve_by_name.restype = c.POINTER(curve_info) class curve_point(c.Structure):
_fields_ = [("x", BIGNUM), ("y", BIGNUM)]
BIGNUM = c.c_uint32 * 9
class ecdsa_curve(c.Structure):
_fields_ = [
("prime", BIGNUM),
("G", curve_point),
("order", BIGNUM),
("order_half", BIGNUM),
("a", c.c_int),
("b", BIGNUM),
]
lib.get_curve_by_name.restype = c.POINTER(curve_info)
class Random(random.Random): class Random(random.Random):
@ -106,15 +121,15 @@ def int2bn(x, bn_type=BIGNUM):
b = bn_type() b = bn_type()
b._int = x b._int = x
for i in range(len(b)): for i in range(len(b)):
b[i] = x % (1 << 30) b[i] = x % (1 << 29)
x = x >> 30 x = x >> 29
return b return b
def bn2int(b): def bn2int(b):
x = 0 x = 0
for i in range(len(b)): for i in range(len(b)):
x += b[i] << (30 * i) x += b[i] << (29 * i)
return x return x
@ -130,7 +145,7 @@ def curve(request):
curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params curve_ptr = lib.get_curve_by_name(bytes(name, "ascii")).contents.params
assert curve_ptr, "curve {} not found".format(name) assert curve_ptr, "curve {} not found".format(name)
curve_obj = curves[name] curve_obj = curves[name]
curve_obj.ptr = c.c_void_p(curve_ptr) curve_obj.ptr = c.cast(curve_ptr, c.POINTER(ecdsa_curve))
curve_obj.p = curve_obj.curve.p() # shorthand curve_obj.p = curve_obj.curve.p() # shorthand
return curve_obj return curve_obj
@ -148,176 +163,6 @@ def point(request):
return curve_obj return curve_obj
def test_inverse(curve, r):
x = r.randrange(1, curve.p)
y = int2bn(x)
lib.bn_inverse(y, int2bn(curve.p))
y = bn2int(y)
y_ = ecdsa.numbertheory.inverse_mod(x, curve.p)
assert y == y_
def test_is_less(curve, r):
x = r.randrange(0, curve.p)
y = r.randrange(0, curve.p)
x_ = int2bn(x)
y_ = int2bn(y)
res = lib.bn_is_less(x_, y_)
assert res == (x < y)
res = lib.bn_is_less(y_, x_)
assert res == (y < x)
def test_is_equal(curve, r):
x = r.randrange(0, curve.p)
y = r.randrange(0, curve.p)
x_ = int2bn(x)
y_ = int2bn(y)
assert lib.bn_is_equal(x_, y_) == (x == y)
assert lib.bn_is_equal(x_, x_) == 1
assert lib.bn_is_equal(y_, y_) == 1
def test_is_zero(curve, r):
x = r.randrange(0, curve.p)
assert lib.bn_is_zero(int2bn(x)) == (not x)
def test_simple_comparisons():
assert lib.bn_is_zero(int2bn(0)) == 1
assert lib.bn_is_zero(int2bn(1)) == 0
assert lib.bn_is_less(int2bn(0), int2bn(0)) == 0
assert lib.bn_is_less(int2bn(1), int2bn(0)) == 0
assert lib.bn_is_less(int2bn(0), int2bn(1)) == 1
assert lib.bn_is_equal(int2bn(0), int2bn(0)) == 1
assert lib.bn_is_equal(int2bn(1), int2bn(0)) == 0
assert lib.bn_is_equal(int2bn(0), int2bn(1)) == 0
def test_mult_half(curve, r):
x = r.randrange(0, 2 * curve.p)
y = int2bn(x)
lib.bn_mult_half(y, int2bn(curve.p))
y = bn2int(y)
if y >= curve.p:
y -= curve.p
half = ecdsa.numbertheory.inverse_mod(2, curve.p)
assert y == (x * half) % curve.p
def test_subtractmod(curve, r):
x = r.randrange(0, 2 ** 256)
y = r.randrange(0, 2 ** 256)
z = int2bn(0)
lib.bn_subtractmod(int2bn(x), int2bn(y), z, int2bn(curve.p))
z = bn2int(z)
z_ = x + 2 * curve.p - y
assert z == z_
def test_subtract2(r):
x = r.randrange(0, 2 ** 256)
y = r.randrange(0, 2 ** 256)
x, y = max(x, y), min(x, y)
z = int2bn(0)
lib.bn_subtract(int2bn(x), int2bn(y), z)
z = bn2int(z)
z_ = x - y
assert z == z_
def test_add(curve, r):
x = r.randrange(0, 2 ** 256)
y = r.randrange(0, 2 ** 256)
z_ = x + y
z = int2bn(x)
lib.bn_add(z, int2bn(y))
z = bn2int(z)
assert z == z_
def test_addmod(curve, r):
x = r.randrange(0, 2 ** 256)
y = r.randrange(0, 2 ** 256)
z_ = (x + y) % curve.p
z = int2bn(x)
lib.bn_addmod(z, int2bn(y), int2bn(curve.p))
z = bn2int(z)
if z >= curve.p:
z = z - curve.p
assert z == z_
def test_multiply(curve, r):
k = r.randrange(0, 2 * curve.p)
x = r.randrange(0, 2 * curve.p)
z = (k * x) % curve.p
k = int2bn(k)
z_ = int2bn(x)
p_ = int2bn(curve.p)
lib.bn_multiply(k, z_, p_)
z_ = bn2int(z_)
assert z_ < 2 * curve.p
if z_ >= curve.p:
z_ = z_ - curve.p
assert z_ == z
def test_multiply1(curve, r):
k = r.randrange(0, 2 * curve.p)
x = r.randrange(0, 2 * curve.p)
kx = k * x
res = int2bn(0, bn_type=(c.c_uint32 * 18))
lib.bn_multiply_long(int2bn(k), int2bn(x), res)
res = bn2int(res)
assert res == kx
def test_multiply2(curve, r):
x = int2bn(0)
s = r.randrange(0, 2 ** 526)
res = int2bn(s, bn_type=(c.c_uint32 * 18))
prime = int2bn(curve.p)
lib.bn_multiply_reduce(x, res, prime)
x = bn2int(x) % curve.p
x_ = s % curve.p
assert x == x_
def test_fast_mod(curve, r):
x = r.randrange(0, 128 * curve.p)
y = int2bn(x)
lib.bn_fast_mod(y, int2bn(curve.p))
y = bn2int(y)
assert y < 2 * curve.p
if y >= curve.p:
y -= curve.p
assert x % curve.p == y
def test_mod(curve, r):
x = r.randrange(0, 2 * curve.p)
y = int2bn(x)
lib.bn_mod(y, int2bn(curve.p))
assert bn2int(y) == x % curve.p
def test_mod_specific(curve):
p = curve.p
for x in [0, 1, 2, p - 2, p - 1, p, p + 1, p + 2, 2 * p - 2, 2 * p - 1]:
y = int2bn(x)
lib.bn_mod(y, int2bn(curve.p))
assert bn2int(y) == x % p
POINT = BIGNUM * 2 POINT = BIGNUM * 2
@ -340,6 +185,16 @@ def from_JACOBIAN(p):
return (bn2int(p[0]), bn2int(p[1]), bn2int(p[2])) return (bn2int(p[0]), bn2int(p[1]), bn2int(p[2]))
def test_curve_parameters(curve):
assert curve.curve.p() == bn2int(curve.ptr.contents.prime)
assert curve.generator.x() == bn2int(curve.ptr.contents.G.x)
assert curve.generator.y() == bn2int(curve.ptr.contents.G.y)
assert curve.order == bn2int(curve.ptr.contents.order)
assert curve.order // 2 == bn2int(curve.ptr.contents.order_half)
assert curve.curve.a() == curve.ptr.contents.a
assert curve.curve.b() == bn2int(curve.ptr.contents.b)
def test_point_multiply(curve, r): def test_point_multiply(curve, r):
p = r.randpoint(curve) p = r.randpoint(curve)
k = r.randrange(0, 2 ** 256) k = r.randrange(0, 2 ** 256)
@ -385,15 +240,6 @@ def test_point_to_jacobian(curve, r):
assert q == (p.x(), p.y()) assert q == (p.x(), p.y())
def test_cond_negate(curve, r):
x = r.randrange(0, curve.p)
a = int2bn(x)
lib.conditional_negate(0, a, int2bn(curve.p))
assert bn2int(a) == x
lib.conditional_negate(-1, a, int2bn(curve.p))
assert bn2int(a) == 2 * curve.p - x
def test_jacobian_add(curve, r): def test_jacobian_add(curve, r):
p1 = r.randpoint(curve) p1 = r.randpoint(curve)
p2 = r.randpoint(curve) p2 = r.randpoint(curve)

View File

@ -39,7 +39,8 @@ int main(int argc, char **argv) {
curve_point checkresult; curve_point checkresult;
bignum256 a; bignum256 a;
bn_zero(&a); bn_zero(&a);
a.val[(4 * i) / 30] = ((uint32_t)2 * j + 1) << ((4 * i) % 30); a.val[(4 * i) / BN_BITS_PER_LIMB] = ((uint32_t)2 * j + 1)
<< ((4 * i) % BN_BITS_PER_LIMB);
bn_normalize(&a); bn_normalize(&a);
point_multiply(curve, &a, &curve->G, &checkresult); point_multiply(curve, &a, &curve->G, &checkresult);
assert(point_is_equal(&checkresult, &ng)); assert(point_is_equal(&checkresult, &ng));

View File

@ -68,7 +68,7 @@ static uint8_t hash_prevouts[32], hash_sequence[32], hash_outputs[32];
static uint8_t decred_hash_prefix[32]; static uint8_t decred_hash_prefix[32];
#endif #endif
static uint8_t hash_check[32]; static uint8_t hash_check[32];
static uint64_t to_spend, authorized_bip143_in, spending, change_spend; static uint64_t to_spend, spending, change_spend;
static uint32_t version = 1; static uint32_t version = 1;
static uint32_t lock_time = 0; static uint32_t lock_time = 0;
static uint32_t expiry = 0; static uint32_t expiry = 0;
@ -489,6 +489,28 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin,
memcpy(&root, _root, sizeof(HDNode)); memcpy(&root, _root, sizeof(HDNode));
version = msg->version; version = msg->version;
lock_time = msg->lock_time; lock_time = msg->lock_time;
if (coin->overwintered && !msg->has_version_group_id) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Version group ID must be set."));
signing_abort();
return;
}
if (!coin->overwintered) {
if (msg->has_version_group_id) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Version group ID not enabled on this coin."));
signing_abort();
return;
}
if (msg->has_branch_id) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Branch ID not enabled on this coin."));
signing_abort();
return;
}
}
#if !BITCOIN_ONLY #if !BITCOIN_ONLY
expiry = (coin->decred || coin->overwintered) ? msg->expiry : 0; expiry = (coin->decred || coin->overwintered) ? msg->expiry : 0;
timestamp = coin->timestamp ? msg->timestamp : 0; timestamp = coin->timestamp ? msg->timestamp : 0;
@ -529,7 +551,6 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin,
to_spend = 0; to_spend = 0;
spending = 0; spending = 0;
change_spend = 0; change_spend = 0;
authorized_bip143_in = 0;
memzero(&input, sizeof(TxInputType)); memzero(&input, sizeof(TxInputType));
memzero(&resp, sizeof(TxRequest)); memzero(&resp, sizeof(TxRequest));
@ -653,17 +674,6 @@ static bool signing_validate_input(const TxInputType *txinput) {
return false; return false;
} }
#if !BITCOIN_ONLY
if (coin->force_bip143 || coin->overwintered) {
if (!txinput->has_amount) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Expected input with amount"));
signing_abort();
return false;
}
}
#endif
if (is_segwit_input_script_type(txinput)) { if (is_segwit_input_script_type(txinput)) {
if (!coin->has_segwit) { if (!coin->has_segwit) {
fsm_sendFailure(FailureType_Failure_DataError, fsm_sendFailure(FailureType_Failure_DataError,
@ -671,12 +681,6 @@ static bool signing_validate_input(const TxInputType *txinput) {
signing_abort(); signing_abort();
return false; return false;
} }
if (!txinput->has_amount) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Segwit input without amount"));
signing_abort();
return false;
}
} }
return true; return true;
@ -1138,19 +1142,18 @@ static bool signing_sign_segwit_input(TxInputType *txinput) {
uint8_t hash[32] = {0}; uint8_t hash[32] = {0};
if (is_segwit_input_script_type(txinput)) { if (is_segwit_input_script_type(txinput)) {
if (!txinput->has_amount) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Segwit input without amount"));
signing_abort();
return false;
}
if (!compile_input_script_sig(txinput)) { if (!compile_input_script_sig(txinput)) {
fsm_sendFailure(FailureType_Failure_ProcessError, fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to compile input")); _("Failed to compile input"));
signing_abort(); signing_abort();
return false; return false;
} }
if (txinput->amount > authorized_bip143_in) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Transaction has changed during signing"));
signing_abort();
return false;
}
authorized_bip143_in -= txinput->amount;
signing_hash_bip143(txinput, hash); signing_hash_bip143(txinput, hash);
@ -1259,9 +1262,10 @@ void signing_txack(TransactionType *tx) {
} }
#endif #endif
memcpy(&input, tx->inputs, sizeof(TxInputType));
if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG ||
tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) {
memcpy(&input, tx->inputs, sizeof(TxInputType));
#if !ENABLE_SEGWIT_NONSEGWIT_MIXING #if !ENABLE_SEGWIT_NONSEGWIT_MIXING
// don't mix segwit and non-segwit inputs // don't mix segwit and non-segwit inputs
if (idx1 > 0 && to.is_segwit == true) { if (idx1 > 0 && to.is_segwit == true) {
@ -1273,30 +1277,12 @@ void signing_txack(TransactionType *tx) {
} }
#endif #endif
#if !BITCOIN_ONLY if (!coin->force_bip143 && !coin->overwintered) {
if (coin->force_bip143 || coin->overwintered) {
if (to_spend + tx->inputs[0].amount < to_spend) {
fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow"));
signing_abort();
return;
}
to_spend += tx->inputs[0].amount;
authorized_bip143_in += tx->inputs[0].amount;
phase1_request_next_input();
} else
#endif
{
// remember the first non-segwit input -- this is the first input // remember the first non-segwit input -- this is the first input
// we need to sign during phase2 // we need to sign during phase2
if (next_nonsegwit_input == 0xffffffff) next_nonsegwit_input = idx1; if (next_nonsegwit_input == 0xffffffff) next_nonsegwit_input = idx1;
send_req_2_prev_meta();
} }
} else if (is_segwit_input_script_type(&tx->inputs[0])) { } else if (is_segwit_input_script_type(&tx->inputs[0])) {
if (to_spend + tx->inputs[0].amount < to_spend) {
fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow"));
signing_abort();
return;
}
if (!to.is_segwit) { if (!to.is_segwit) {
tx_weight += TXSIZE_SEGWIT_OVERHEAD + to.inputs_len; tx_weight += TXSIZE_SEGWIT_OVERHEAD + to.inputs_len;
} }
@ -1314,15 +1300,13 @@ void signing_txack(TransactionType *tx) {
#else #else
to.is_segwit = true; to.is_segwit = true;
#endif #endif
to_spend += tx->inputs[0].amount;
authorized_bip143_in += tx->inputs[0].amount;
phase1_request_next_input();
} else { } else {
fsm_sendFailure(FailureType_Failure_DataError, fsm_sendFailure(FailureType_Failure_DataError,
_("Wrong input script type")); _("Wrong input script type"));
signing_abort(); signing_abort();
return; return;
} }
send_req_2_prev_meta();
return; return;
case STAGE_REQUEST_2_PREV_META: case STAGE_REQUEST_2_PREV_META:
if (tx->outputs_cnt <= input.prev_index) { if (tx->outputs_cnt <= input.prev_index) {
@ -1355,6 +1339,26 @@ void signing_txack(TransactionType *tx) {
signing_abort(); signing_abort();
return; return;
} }
if (coin->overwintered && !tx->has_version_group_id) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Version group ID must be set."));
signing_abort();
return;
}
if (!coin->overwintered) {
if (tx->has_version_group_id) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Version group ID not enabled on this coin."));
signing_abort();
return;
}
if (tx->has_branch_id) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Branch ID not enabled on this coin."));
signing_abort();
return;
}
}
if (tx->inputs_cnt + tx->outputs_cnt < tx->inputs_cnt) { if (tx->inputs_cnt + tx->outputs_cnt < tx->inputs_cnt) {
fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow"));
signing_abort(); signing_abort();
@ -1412,6 +1416,12 @@ void signing_txack(TransactionType *tx) {
return; return;
} }
if (idx2 == input.prev_index) { if (idx2 == input.prev_index) {
if (input.has_amount && input.amount != tx->bin_outputs[0].amount) {
fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid amount specified"));
signing_abort();
return;
}
if (to_spend + tx->bin_outputs[0].amount < to_spend) { if (to_spend + tx->bin_outputs[0].amount < to_spend) {
fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow"));
signing_abort(); signing_abort();
@ -1596,13 +1606,12 @@ void signing_txack(TransactionType *tx) {
signing_abort(); signing_abort();
return; return;
} }
if (tx->inputs[0].amount > authorized_bip143_in) { if (!tx->inputs[0].has_amount) {
fsm_sendFailure(FailureType_Failure_DataError, fsm_sendFailure(FailureType_Failure_DataError,
_("Transaction has changed during signing")); _("Expected input with amount"));
signing_abort(); signing_abort();
return; return;
} }
authorized_bip143_in -= tx->inputs[0].amount;
uint8_t hash[32] = {0}; uint8_t hash[32] = {0};
#if !BITCOIN_ONLY #if !BITCOIN_ONLY

View File

@ -711,8 +711,7 @@ uint32_t tx_serialize_footer_hash(TxStruct *tx) {
#if !BITCOIN_ONLY #if !BITCOIN_ONLY
if (tx->overwintered) { if (tx->overwintered) {
hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4);
hasher_Update(&(tx->hasher), (const uint8_t *)"\x00", 1); // nJoinSplit return 8;
return 9;
} }
if (tx->is_decred) { if (tx->is_decred) {
hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4);

View File

@ -1022,7 +1022,13 @@ class TestMsgSigntx:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"field, value", "field, value",
(("extra_data", b"hello world"), ("expiry", 9), ("timestamp", 42)), (
("extra_data", b"hello world"),
("expiry", 9),
("timestamp", 42),
("version_group_id", 69),
("branch_id", 13),
),
) )
@pytest.mark.skip_ui @pytest.mark.skip_ui
def test_prevtx_forbidden_fields(self, client, field, value): def test_prevtx_forbidden_fields(self, client, field, value):
@ -1045,7 +1051,10 @@ class TestMsgSigntx:
client, "Bitcoin", [inp0], [out1], prev_txes={TXHASH_157041: prev_tx} client, "Bitcoin", [inp0], [out1], prev_txes={TXHASH_157041: prev_tx}
) )
@pytest.mark.parametrize("field, value", (("expiry", 9), ("timestamp", 42))) @pytest.mark.parametrize(
"field, value",
(("expiry", 9), ("timestamp", 42), ("version_group_id", 69), ("branch_id", 13)),
)
@pytest.mark.skip_ui @pytest.mark.skip_ui
def test_signtx_forbidden_fields(self, client, field, value): def test_signtx_forbidden_fields(self, client, field, value):
inp0 = proto.TxInputType( inp0 = proto.TxInputType(
@ -1167,5 +1176,5 @@ class TestMsgSigntx:
TrezorFailure, match="Multisig field provided but not expected." TrezorFailure, match="Multisig field provided but not expected."
): ):
btc.sign_tx( btc.sign_tx(
client, "Testnet", [inp1], [out1, out2], prev_txes=TxCache("Testnet") client, "Testnet", [inp1], [out1, out2], prev_txes=TX_CACHE_TESTNET
) )

View File

@ -21,7 +21,7 @@ from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import H_, parse_path from trezorlib.tools import H_, parse_path
from ..tx_cache import TxCache from ..tx_cache import TxCache
from .signtx import request_finished, request_input, request_output from .signtx import request_finished, request_input, request_meta, request_output
B = proto.ButtonRequestType B = proto.ButtonRequestType
TX_API = TxCache("Bcash") TX_API = TxCache("Bcash")
@ -65,6 +65,9 @@ class TestMsgSigntxBch:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_bc37c2),
request_input(0, TXHASH_bc37c2),
request_output(0, TXHASH_bc37c2),
request_output(0), request_output(0),
request_output(1), request_output(1),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
@ -110,7 +113,15 @@ class TestMsgSigntxBch:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_502e85),
request_input(0, TXHASH_502e85),
request_output(0, TXHASH_502e85),
request_output(1, TXHASH_502e85),
request_input(1), request_input(1),
request_meta(TXHASH_502e85),
request_input(0, TXHASH_502e85),
request_output(0, TXHASH_502e85),
request_output(1, TXHASH_502e85),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -155,7 +166,15 @@ class TestMsgSigntxBch:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_502e85),
request_input(0, TXHASH_502e85),
request_output(0, TXHASH_502e85),
request_output(1, TXHASH_502e85),
request_input(1), request_input(1),
request_meta(TXHASH_502e85),
request_input(0, TXHASH_502e85),
request_output(0, TXHASH_502e85),
request_output(1, TXHASH_502e85),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -174,81 +193,6 @@ class TestMsgSigntxBch:
== "01000000022c06cf6f215c5cbfd7caa8e71b1b32630cabf1f816a4432815b037b277852e50000000006a47304402207a2a955f1cb3dc5f03f2c82934f55654882af4e852e5159639f6349e9386ec4002205fb8419dce4e648eae8f67bc4e369adfb130a87d2ea2d668f8144213b12bb457412103174c61e9c5362507e8061e28d2c0ce3d4df4e73f3535ae0b12f37809e0f92d2dffffffff2c06cf6f215c5cbfd7caa8e71b1b32630cabf1f816a4432815b037b277852e50010000006a473044022062151cf960b71823bbe68c7ed2c2a93ad1b9706a30255fddb02fcbe056d8c26102207bad1f0872bc5f0cfaf22e45c925c35d6c1466e303163b75cb7688038f1a5541412102595caf9aeb6ffdd0e82b150739a83297358b9a77564de382671056ad9e5b8c58ffffffff0170861d00000000001976a91434e9cec317896e818619ab7dc99d2305216ff4af88ac00000000" == "01000000022c06cf6f215c5cbfd7caa8e71b1b32630cabf1f816a4432815b037b277852e50000000006a47304402207a2a955f1cb3dc5f03f2c82934f55654882af4e852e5159639f6349e9386ec4002205fb8419dce4e648eae8f67bc4e369adfb130a87d2ea2d668f8144213b12bb457412103174c61e9c5362507e8061e28d2c0ce3d4df4e73f3535ae0b12f37809e0f92d2dffffffff2c06cf6f215c5cbfd7caa8e71b1b32630cabf1f816a4432815b037b277852e50010000006a473044022062151cf960b71823bbe68c7ed2c2a93ad1b9706a30255fddb02fcbe056d8c26102207bad1f0872bc5f0cfaf22e45c925c35d6c1466e303163b75cb7688038f1a5541412102595caf9aeb6ffdd0e82b150739a83297358b9a77564de382671056ad9e5b8c58ffffffff0170861d00000000001976a91434e9cec317896e818619ab7dc99d2305216ff4af88ac00000000"
) )
def test_attack_amount(self, client):
inp1 = proto.TxInputType(
address_n=parse_path("44'/145'/0'/1/0"),
# bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw
amount=300,
prev_hash=TXHASH_502e85,
prev_index=0,
script_type=proto.InputScriptType.SPENDADDRESS,
)
inp2 = proto.TxInputType(
address_n=parse_path("44'/145'/0'/0/1"),
# bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4
amount=70,
prev_hash=TXHASH_502e85,
prev_index=1,
script_type=proto.InputScriptType.SPENDADDRESS,
)
out1 = proto.TxOutputType(
address="bitcoincash:qq6wnnkrz7ykaqvxrx4hmjvayvzjzml54uyk76arx4",
amount=200,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
# test if passes without modifications
with client:
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx),
request_input(0),
request_input(1),
request_output(0),
request_finished(),
]
)
btc.sign_tx(client, "Bcash", [inp1, inp2], [out1], prev_txes=TX_API)
run_attack = True
def attack_processor(msg):
nonlocal run_attack
if run_attack and msg.tx.inputs and msg.tx.inputs[0] == inp1:
# 300 is lowered to 280 at the first run
# the user confirms 280 but the transaction
# is spending 300 => larger fee without the user knowing
msg.tx.inputs[0].amount = 280
run_attack = False
return msg
# now fails
client.set_filter(proto.TxAck, attack_processor)
with client:
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx),
request_input(0),
request_input(1),
proto.Failure(),
]
)
with pytest.raises(
TrezorFailure, match="Transaction has changed during signing"
):
btc.sign_tx(client, "Bcash", [inp1, inp2], [out1], prev_txes=TX_API)
def test_attack_change_input(self, client): def test_attack_change_input(self, client):
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("44'/145'/10'/0/0"), address_n=parse_path("44'/145'/10'/0/0"),
@ -287,6 +231,9 @@ class TestMsgSigntxBch:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_bc37c2),
request_input(0, TXHASH_bc37c2),
request_output(0, TXHASH_bc37c2),
request_output(0), request_output(0),
request_output(1), request_output(1),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
@ -353,6 +300,10 @@ class TestMsgSigntxBch:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_f68caf),
request_input(0, TXHASH_f68caf),
request_output(0, TXHASH_f68caf),
request_output(1, TXHASH_f68caf),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -410,6 +361,9 @@ class TestMsgSigntxBch:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_8b6db9),
request_input(0, TXHASH_8b6db9),
request_output(0, TXHASH_8b6db9),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -444,6 +398,9 @@ class TestMsgSigntxBch:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_8b6db9),
request_input(0, TXHASH_8b6db9),
request_output(0, TXHASH_8b6db9),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),

View File

@ -18,10 +18,10 @@ import pytest
from trezorlib import btc, messages as proto from trezorlib import btc, messages as proto
from trezorlib.exceptions import TrezorFailure from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import H_, parse_path from trezorlib.tools import H_, btc_hash, parse_path
from ..tx_cache import TxCache from ..tx_cache import TxCache
from .signtx import request_finished, request_input, request_output from .signtx import request_finished, request_input, request_meta, request_output
B = proto.ButtonRequestType B = proto.ButtonRequestType
TX_API = TxCache("Bgold") TX_API = TxCache("Bgold")
@ -32,12 +32,6 @@ TXHASH_25526b = bytes.fromhex(
TXHASH_db77c2 = bytes.fromhex( TXHASH_db77c2 = bytes.fromhex(
"db77c2461b840e6edbe7f9280043184a98e020d9795c1b65cb7cef2551a8fb18" "db77c2461b840e6edbe7f9280043184a98e020d9795c1b65cb7cef2551a8fb18"
) )
TXHASH_e5040e = bytes.fromhex(
"e5040e1bc1ae7667ffb9e5248e90b2fb93cd9150234151ce90e14ab2f5933bcd"
)
TXHASH_65b811 = bytes.fromhex(
"65b811d3eca0fe6915d9f2d77c86c5a7f19bf66b1b1253c2c51cb4ae5f0c017b"
)
# All data taken from T1 # All data taken from T1
@ -46,7 +40,7 @@ class TestMsgSigntxBitcoinGold:
def test_send_bitcoin_gold_change(self, client): def test_send_bitcoin_gold_change(self, client):
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("44'/156'/0'/0/0"), address_n=parse_path("44'/156'/0'/0/0"),
amount=1995344, amount=1252382934,
prev_hash=TXHASH_25526b, prev_hash=TXHASH_25526b,
prev_index=0, prev_index=0,
script_type=proto.InputScriptType.SPENDADDRESS, script_type=proto.InputScriptType.SPENDADDRESS,
@ -58,13 +52,17 @@ class TestMsgSigntxBitcoinGold:
) )
out2 = proto.TxOutputType( out2 = proto.TxOutputType(
address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe",
amount=73452, amount=1252382934 - 1896050 - 1000,
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
) )
with client: with client:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_25526b),
request_input(0, TXHASH_25526b),
request_output(0, TXHASH_25526b),
request_output(1, TXHASH_25526b),
request_output(0), request_output(0),
request_output(1), request_output(1),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
@ -80,14 +78,14 @@ class TestMsgSigntxBitcoinGold:
) )
assert ( assert (
serialized_tx.hex() btc_hash(serialized_tx)[::-1].hex()
== "010000000185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b5225000000006b483045022100963904da0731b71ce468afd45366dd80fbff566ec0d39c1161ab85d17459c7ca02202f5c24a7a7272d98b14a3f5bc000c7cde8ac0eb773f20f4c3131518186cc98854121023bd0ec4022d12d0106c5b7308a25572953ba1951f576f691354a7b147ee0cc1fffffffff0272ee1c00000000001976a9141c82b9c11f193ad82413caadc0955730572b50ae88acec1e0100000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac00000000" == "39a0716c361610724c7c40916baa20808cbdd7538b6c38689ce80cb73e7f51d1"
) )
def test_send_bitcoin_gold_nochange(self, client): def test_send_bitcoin_gold_nochange(self, client):
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("44'/156'/0'/1/0"), address_n=parse_path("44'/156'/0'/1/0"),
amount=1896050, amount=1252382934,
prev_hash=TXHASH_25526b, prev_hash=TXHASH_25526b,
prev_index=0, prev_index=0,
script_type=proto.InputScriptType.SPENDADDRESS, script_type=proto.InputScriptType.SPENDADDRESS,
@ -95,21 +93,29 @@ class TestMsgSigntxBitcoinGold:
inp2 = proto.TxInputType( inp2 = proto.TxInputType(
address_n=parse_path("44'/156'/0'/0/1"), address_n=parse_path("44'/156'/0'/0/1"),
# 1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3 # 1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3
amount=73452, amount=38448607,
prev_hash=TXHASH_db77c2, prev_hash=TXHASH_db77c2,
prev_index=1, prev_index=0,
script_type=proto.InputScriptType.SPENDADDRESS, script_type=proto.InputScriptType.SPENDADDRESS,
) )
out1 = proto.TxOutputType( out1 = proto.TxOutputType(
address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe",
amount=1934960, amount=1252382934 + 38448607 - 1000,
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
) )
with client: with client:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_25526b),
request_input(0, TXHASH_25526b),
request_output(0, TXHASH_25526b),
request_output(1, TXHASH_25526b),
request_input(1), request_input(1),
request_meta(TXHASH_db77c2),
request_input(0, TXHASH_db77c2),
request_input(1, TXHASH_db77c2),
request_output(0, TXHASH_db77c2),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -124,14 +130,14 @@ class TestMsgSigntxBitcoinGold:
) )
assert ( assert (
serialized_tx.hex() btc_hash(serialized_tx)[::-1].hex()
== "010000000285c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b5225000000006b483045022100928852076c9fab160c07564cd54691af1cbc37fb28f0b7bee7299c7925ef62f0022058856387afecc6508f2f04ecdfd292a13026a5b2107ebdd2cc789bdf8820d552412102a6c3998d0d4e5197ff41aab5c53580253b3b91f583f4c31f7624be7dc83ce15fffffffff18fba85125ef7ccb651b5c79d920e0984a18430028f9e7db6e0e841b46c277db010000006b483045022100faa2f4f01cc95e680349a093923aae0aa2ea01429873555aa8a84bf630ef33a002204c3f4bf567e2d20540c0f71dc278481d6ccb6b95acda2a2f87ce521c79d6b872412102d54a7e5733b1635e5e9442943f48179b1700206b2d1925250ba10f1c86878be8ffffffff0170861d00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac00000000" == "ac9d452b900eb747d3137e1f3044bb0f46efaeb6e0fc8c27b02d1d08d238a904"
) )
def test_attack_change_input(self, client): def test_attack_change_input(self, client):
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("44'/156'/11'/0/0"), address_n=parse_path("44'/156'/11'/0/0"),
amount=1995344, amount=1252382934,
prev_hash=TXHASH_25526b, prev_hash=TXHASH_25526b,
prev_index=0, prev_index=0,
script_type=proto.InputScriptType.SPENDADDRESS, script_type=proto.InputScriptType.SPENDADDRESS,
@ -143,7 +149,7 @@ class TestMsgSigntxBitcoinGold:
) )
out2 = proto.TxOutputType( out2 = proto.TxOutputType(
address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe",
amount=73452, amount=1252382934 - 1896050 - 1000,
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
) )
@ -165,6 +171,10 @@ class TestMsgSigntxBitcoinGold:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_25526b),
request_input(0, TXHASH_25526b),
request_output(0, TXHASH_25526b),
request_output(1, TXHASH_25526b),
request_output(0), request_output(0),
request_output(1), request_output(1),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
@ -194,7 +204,7 @@ class TestMsgSigntxBitcoinGold:
address_n=parse_path("48'/156'/3'/0/0"), address_n=parse_path("48'/156'/3'/0/0"),
multisig=getmultisig(0, 0), multisig=getmultisig(0, 0),
# 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R # 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R
amount=48490, amount=1252382934,
prev_hash=TXHASH_25526b, prev_hash=TXHASH_25526b,
prev_index=0, prev_index=0,
script_type=proto.InputScriptType.SPENDMULTISIG, script_type=proto.InputScriptType.SPENDMULTISIG,
@ -208,12 +218,16 @@ class TestMsgSigntxBitcoinGold:
address_n=parse_path("48'/156'/3'/1/0"), address_n=parse_path("48'/156'/3'/1/0"),
multisig=getmultisig(1, 0), multisig=getmultisig(1, 0),
script_type=proto.OutputScriptType.PAYTOMULTISIG, script_type=proto.OutputScriptType.PAYTOMULTISIG,
amount=24000, amount=1252382934 - 24000 - 1000,
) )
with client: with client:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_25526b),
request_input(0, TXHASH_25526b),
request_output(0, TXHASH_25526b),
request_output(1, TXHASH_25526b),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -230,13 +244,13 @@ class TestMsgSigntxBitcoinGold:
assert ( assert (
signatures[0].hex() signatures[0].hex()
== "3045022100d954f341ddd3ec96e4bc6cdb90f2df9b2032723f85e4a0187346dd743130bfca0220105ce08b795c70dc09a55569d7874bff684a877219ec2fc37c88cdffe12f332c" == "30440220271c46ef3d7c37bd499804128623da3aa0014f3b4447dd39c4573b23c4537f6902205329167b9eb48427af62b04bf5138295f4c38613f6ba955934d15c499bff0d8a"
) )
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("48'/156'/1'/0/0"), address_n=parse_path("48'/156'/1'/0/0"),
multisig=getmultisig(0, 0, [b"", b"", signatures[0]]), multisig=getmultisig(0, 0, [b"", b"", signatures[0]]),
amount=48490, amount=1252382934,
prev_hash=TXHASH_25526b, prev_hash=TXHASH_25526b,
prev_index=0, prev_index=0,
script_type=proto.InputScriptType.SPENDMULTISIG, script_type=proto.InputScriptType.SPENDMULTISIG,
@ -247,6 +261,10 @@ class TestMsgSigntxBitcoinGold:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_25526b),
request_input(0, TXHASH_25526b),
request_output(0, TXHASH_25526b),
request_output(1, TXHASH_25526b),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -263,17 +281,17 @@ class TestMsgSigntxBitcoinGold:
assert ( assert (
signatures[0].hex() signatures[0].hex()
== "30440220614f9a18695365a2edba0d930404a77cae970d3430ad86c5b5239a96fd54bf84022030bc76a322e3b2b1c987622b5eb6da23ac1e6c905ee9b3b6405a4e4edd5bbb87" == "3045022100bdf8c4bd14217c183612c7e8f79691f6479bcb35aa403f77d70182f58633ac6e02205b10a79b7894bb40248a120c8fcb7096a46950593e4c5b48a20bc5ebe53d85fa"
) )
assert ( assert (
serialized_tx.hex() btc_hash(serialized_tx)[::-1].hex()
== "010000000185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b522500000000fdfd00004730440220614f9a18695365a2edba0d930404a77cae970d3430ad86c5b5239a96fd54bf84022030bc76a322e3b2b1c987622b5eb6da23ac1e6c905ee9b3b6405a4e4edd5bbb8741483045022100d954f341ddd3ec96e4bc6cdb90f2df9b2032723f85e4a0187346dd743130bfca0220105ce08b795c70dc09a55569d7874bff684a877219ec2fc37c88cdffe12f332c414c695221035a8db79c0ef57a202664a3da60ca41e8865c6d86ed0aafc03f8e75173341b58021037fba152d8fca660cc49973d8bc9421ff49a75b44ea200873d70d3990f763ed4c210348cbcbd93e069416e0d5db93e86b5698852d9fd54502ad0bed9722fa83f90e4b53aeffffffff02c05d0000000000001976a914ea5f904d195079a350b534db4446433b3cec222e88acc05d00000000000017a914623c803f7fb654dac8dda7786fbf9bc38cd867f48700000000" == "b45ba21b69e1e1c6ad79f5408fe70d92fb861742d239cb6a952213f60c253e40"
) )
def test_send_p2sh(self, client): def test_send_p2sh(self, client):
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("49'/156'/0'/1/0"), address_n=parse_path("49'/156'/0'/1/0"),
amount=123456789, amount=1252382934,
prev_hash=TXHASH_25526b, prev_hash=TXHASH_25526b,
prev_index=0, prev_index=0,
script_type=proto.InputScriptType.SPENDP2SHWITNESS, script_type=proto.InputScriptType.SPENDP2SHWITNESS,
@ -286,12 +304,16 @@ class TestMsgSigntxBitcoinGold:
out2 = proto.TxOutputType( out2 = proto.TxOutputType(
address="GZFLExxrvWFuFT1xRzhfwQWSE2bPDedBfn", address="GZFLExxrvWFuFT1xRzhfwQWSE2bPDedBfn",
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
amount=123456789 - 11000 - 12300000, amount=1252382934 - 11000 - 12300000,
) )
with client: with client:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_25526b),
request_input(0, TXHASH_25526b),
request_output(0, TXHASH_25526b),
request_output(1, TXHASH_25526b),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -309,14 +331,14 @@ class TestMsgSigntxBitcoinGold:
) )
assert ( assert (
serialized_tx.hex() btc_hash(serialized_tx)[::-1].hex()
== "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250000000017160014b5355d001e720d8f4513da00ff2bba4dcf9d39fcffffffff02e0aebb00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac3df39f06000000001976a914a8f757819ec6779409f45788f7b4a0e8f51ec50488ac02473044022073fcbf2876f073f78923ab427f14de5b2a0fbeb313a9b2b650b3567061f242a702202f45fc22c501108ff6222afe3aca7da9d8c7dc860f9cda335bef31fa184e7bef412102ecea08b559fc5abd009acf77cfae13fa8a3b1933e3e031956c65c12cec8ca3e300000000" == "d5732fc8a594ae3b7ba695d7b276b2186f8572b0eb157120e0ba35d3511c6060"
) )
def test_send_p2sh_witness_change(self, client): def test_send_p2sh_witness_change(self, client):
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("49'/156'/0'/1/0"), address_n=parse_path("49'/156'/0'/1/0"),
amount=123456789, amount=1252382934,
prev_hash=TXHASH_25526b, prev_hash=TXHASH_25526b,
prev_index=0, prev_index=0,
script_type=proto.InputScriptType.SPENDP2SHWITNESS, script_type=proto.InputScriptType.SPENDP2SHWITNESS,
@ -329,12 +351,16 @@ class TestMsgSigntxBitcoinGold:
out2 = proto.TxOutputType( out2 = proto.TxOutputType(
address_n=parse_path("49'/156'/0'/1/0"), address_n=parse_path("49'/156'/0'/1/0"),
script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, script_type=proto.OutputScriptType.PAYTOP2SHWITNESS,
amount=123456789 - 11000 - 12300000, amount=1252382934 - 11000 - 12300000,
) )
with client: with client:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_25526b),
request_input(0, TXHASH_25526b),
request_output(0, TXHASH_25526b),
request_output(1, TXHASH_25526b),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -351,8 +377,8 @@ class TestMsgSigntxBitcoinGold:
) )
assert ( assert (
serialized_tx.hex() btc_hash(serialized_tx)[::-1].hex()
== "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250000000017160014b5355d001e720d8f4513da00ff2bba4dcf9d39fcffffffff02e0aebb00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac3df39f060000000017a9140cd03822b799a452c106d1b3771844a067b17f118702483045022100d79b33384c686d8dd40ad5f84f46691d30994992c1cb42e934c2a625d86cb2f902206859805a9a98ba140b71a9d4b9a6b8df94a9424f9c40f3bd804149fd6e278d63412102ecea08b559fc5abd009acf77cfae13fa8a3b1933e3e031956c65c12cec8ca3e300000000" == "eed4ef86a408602e35ae416591f349847db38cdaddef1429a9bb0e39520d100d"
) )
@pytest.mark.multisig @pytest.mark.multisig
@ -370,15 +396,15 @@ class TestMsgSigntxBitcoinGold:
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("49'/156'/1'/1/0"), address_n=parse_path("49'/156'/1'/1/0"),
prev_hash=TXHASH_25526b, prev_hash=TXHASH_25526b,
prev_index=1, prev_index=0,
script_type=proto.InputScriptType.SPENDP2SHWITNESS, script_type=proto.InputScriptType.SPENDP2SHWITNESS,
multisig=multisig, multisig=multisig,
amount=1610436, amount=1252382934,
) )
out1 = proto.TxOutputType( out1 = proto.TxOutputType(
address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe",
amount=1605000, amount=1252382934 - 1000,
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
) )
@ -386,6 +412,10 @@ class TestMsgSigntxBitcoinGold:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_25526b),
request_input(0, TXHASH_25526b),
request_output(0, TXHASH_25526b),
request_output(1, TXHASH_25526b),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -405,6 +435,10 @@ class TestMsgSigntxBitcoinGold:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_25526b),
request_input(0, TXHASH_25526b),
request_output(0, TXHASH_25526b),
request_output(1, TXHASH_25526b),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -419,30 +453,30 @@ class TestMsgSigntxBitcoinGold:
) )
assert ( assert (
serialized_tx.hex() btc_hash(serialized_tx)[::-1].hex()
== "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250100000023220020ea9ec48498c451286c2ebaf9e19255e2873b0fb517d67b2f2005298c7e437829ffffffff01887d1800000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac0400473044022077cb8b2a534f79328810ca8c330539ae9ffa086c359ddb7da11026557b04eef202201d95be0dd1da0aa01720953e52d5dabffd19a998d1490c13a21b8e52e4ead2e041483045022100e41cbd6a501ba8fe6f65554420e23e950d35af0da9b052da54a087463b0717ca02206c695c8d1f74f9535b5d89a2fd1f9326a0ef20e5400137f1e1daeee992b62b594169522103279aea0b253b144d1b2bb8532280001a996dcddd04f86e5e13df1355032cbc1321032c6465c956c0879663fa8be974c912d229c179a5cdedeb29611a1bec1f951eb22103494480a4b72101cbd2eadac8e18c7a3a7589a7f576bf46b8971c38c51e5eceeb53ae00000000" == "efa5b21916ac7ea5316c38b2d7d5520d80cbe563c58304f956ea6ddb241001d1"
) )
def test_send_mixed_inputs(self, client): def test_send_mixed_inputs(self, client):
# First is non-segwit, second is segwit. # First is non-segwit, second is segwit.
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("44'/156'/0'/0/0"), address_n=parse_path("44'/156'/11'/0/0"),
amount=31000000, amount=38448607,
prev_hash=TXHASH_e5040e, prev_hash=TXHASH_db77c2,
prev_index=0, prev_index=0,
script_type=proto.InputScriptType.SPENDADDRESS,
) )
inp2 = proto.TxInputType( inp2 = proto.TxInputType(
address_n=parse_path("84'/156'/0'/1/0"), address_n=parse_path("49'/156'/0'/1/0"),
amount=7289000, amount=1252382934,
prev_hash=TXHASH_65b811, prev_hash=TXHASH_25526b,
prev_index=1, prev_index=0,
script_type=proto.InputScriptType.SPENDWITNESS, script_type=proto.InputScriptType.SPENDP2SHWITNESS,
) )
out1 = proto.TxOutputType( out1 = proto.TxOutputType(
address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe",
amount=31000000 + 7289000 - 1000, amount=38448607 + 1252382934 - 1000,
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
) )
@ -452,6 +486,6 @@ class TestMsgSigntxBitcoinGold:
) )
assert ( assert (
serialized_tx.hex() btc_hash(serialized_tx)[::-1].hex()
== "01000000000102cd3b93f5b24ae190ce5141235091cd93fbb2908e24e5b9ff6776aec11b0e04e5000000006a473044022061e94392fa4c0a4bf510bf713c23a37c6c5f6f4dbe5c116e86cff23a93c578e9022026661d2ffb1102d07b7c1631270152441fa171d91108b75a7b9a2cc36ca7db6c4121023bd0ec4022d12d0106c5b7308a25572953ba1951f576f691354a7b147ee0cc1fffffffff7b010c5faeb41cc5c253121b6bf69bf1a7c5867cd7f2d91569fea0ecd311b8650100000000ffffffff01803a4802000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac0002483045022100e39d9bff8350b9ba20cb2ed88e82d7568a83184616acdc16bd1adb4005c5a471022066ff36084e896a69a91a0fad01721f20f2bb42b41e20be35e72fc3729ac7ace74121030b75ccac9add5f82a4c61fe34e791a2f2eda61b544bce4f6fa3d403bb0de748400000000" == "2c64109fba890657e37f0782efda29bbc277dfd521658f185d302ddffcacffd2"
) )

View File

@ -23,6 +23,7 @@ from ..tx_cache import TxCache
B = proto.ButtonRequestType B = proto.ButtonRequestType
TX_API = TxCache("Groestlcoin") TX_API = TxCache("Groestlcoin")
TX_API_TESTNET = TxCache("Groestlcoin Testnet")
TXHASH_cb74c8 = bytes.fromhex( TXHASH_cb74c8 = bytes.fromhex(
"cb74c8478c5814742c87cffdb4a21231869888f8042fb07a90e015a9db1f9d4a" "cb74c8478c5814742c87cffdb4a21231869888f8042fb07a90e015a9db1f9d4a"
@ -101,7 +102,12 @@ class TestMsgSigntxGRS:
) )
details = proto.SignTx(lock_time=650756) details = proto.SignTx(lock_time=650756)
_, serialized_tx = btc.sign_tx( _, serialized_tx = btc.sign_tx(
client, "Groestlcoin Testnet", [inp1], [out1, out2], details=details client,
"Groestlcoin Testnet",
[inp1],
[out1, out2],
details=details,
prev_txes=TX_API_TESTNET,
) )
assert ( assert (
serialized_tx.hex() serialized_tx.hex()
@ -130,7 +136,12 @@ class TestMsgSigntxGRS:
) )
details = proto.SignTx(lock_time=650756) details = proto.SignTx(lock_time=650756)
_, serialized_tx = btc.sign_tx( _, serialized_tx = btc.sign_tx(
client, "Groestlcoin Testnet", [inp1], [out1, out2], details=details client,
"Groestlcoin Testnet",
[inp1],
[out1, out2],
details=details,
prev_txes=TX_API_TESTNET,
) )
assert ( assert (
serialized_tx.hex() serialized_tx.hex()
@ -158,7 +169,12 @@ class TestMsgSigntxGRS:
) )
details = proto.SignTx(lock_time=650713) details = proto.SignTx(lock_time=650713)
_, serialized_tx = btc.sign_tx( _, serialized_tx = btc.sign_tx(
client, "Groestlcoin Testnet", [inp1], [out1, out2], details=details client,
"Groestlcoin Testnet",
[inp1],
[out1, out2],
details=details,
prev_txes=TX_API_TESTNET,
) )
assert ( assert (
serialized_tx.hex() serialized_tx.hex()
@ -186,7 +202,12 @@ class TestMsgSigntxGRS:
) )
details = proto.SignTx(lock_time=650713) details = proto.SignTx(lock_time=650713)
_, serialized_tx = btc.sign_tx( _, serialized_tx = btc.sign_tx(
client, "Groestlcoin Testnet", [inp1], [out1, out2], details=details client,
"Groestlcoin Testnet",
[inp1],
[out1, out2],
details=details,
prev_txes=TX_API_TESTNET,
) )
assert ( assert (
serialized_tx.hex() serialized_tx.hex()

View File

@ -20,7 +20,13 @@ from trezorlib import btc, messages as proto
from trezorlib.tools import parse_path from trezorlib.tools import parse_path
from ..tx_cache import TxCache from ..tx_cache import TxCache
from .signtx import request_finished, request_input, request_output from .signtx import (
request_extra_data,
request_finished,
request_input,
request_meta,
request_output,
)
B = proto.ButtonRequestType B = proto.ButtonRequestType
TX_API = TxCache("Komodo") TX_API = TxCache("Komodo")
@ -54,22 +60,24 @@ class TestMsgSigntxKomodo:
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
) )
trezor_core = client.features.model != "1"
with client: with client:
er = [ client.set_expected_responses(
[
request_input(0), request_input(0),
request_meta(TXHASH_2807c),
request_input(0, TXHASH_2807c),
request_output(0, TXHASH_2807c),
request_extra_data(0, 11, TXHASH_2807c),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
] (trezor_core, proto.ButtonRequest(code=B.SignTx)),
if client.features.model != "1": # extra screen for lock_time
er += [proto.ButtonRequest(code=B.SignTx)]
er += [
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
request_input(0), request_input(0),
request_output(0), request_output(0),
request_finished(), request_finished(),
] ]
)
client.set_expected_responses(er)
details = proto.SignTx( details = proto.SignTx(
version=4, version=4,
@ -112,24 +120,27 @@ class TestMsgSigntxKomodo:
script_type=proto.OutputScriptType.PAYTOADDRESS, script_type=proto.OutputScriptType.PAYTOADDRESS,
) )
trezor_core = client.features.model != "1"
with client: with client:
er = [ client.set_expected_responses(
[
request_input(0), request_input(0),
request_meta(TXHASH_7b28bd),
request_input(0, TXHASH_7b28bd),
request_output(0, TXHASH_7b28bd),
request_extra_data(0, 11, TXHASH_7b28bd),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
] (trezor_core, proto.ButtonRequest(code=B.SignTx)),
if client.features.model != "1": # extra screen for lock_time
er += [proto.ButtonRequest(code=B.SignTx)]
er += [
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
request_input(0), request_input(0),
request_output(0), request_output(0),
request_output(1), request_output(1),
request_finished(), request_finished(),
] ]
client.set_expected_responses(er) )
details = proto.SignTx( details = proto.SignTx(
version=4, version=4,

View File

@ -142,7 +142,7 @@ def test_segwit_non_segwit_segwit_inputs(client):
) )
inp3 = messages.TxInputType( inp3 = messages.TxInputType(
address_n=parse_path("84'/1'/0'/0/0"), address_n=parse_path("84'/1'/0'/0/0"),
amount=123123, amount=1603000,
prev_hash=TXHASH_31bc1c, prev_hash=TXHASH_31bc1c,
prev_index=0, prev_index=0,
script_type=messages.InputScriptType.SPENDWITNESS, script_type=messages.InputScriptType.SPENDWITNESS,
@ -169,11 +169,11 @@ def test_segwit_non_segwit_segwit_inputs(client):
) )
assert ( assert (
signatures[2].hex() signatures[2].hex()
== "30450221008aa7c6ea2b017701145c8b062e05c35259d271ea3009229776b9ef6e17a823da022004a11059927dcc21ff3f0e9441e36e91b4e0db879d102ea6a26f84a8a5d6d35c" == "3045022100f2d398ac6bc702cfa4f7eb3d2579a233f1d7c920c45a14329a741db6c24fde8f02203b1f6aed5671eece8ba5b5c05ec0330a43c0914b8ff606945cb8cf9e164ec88f"
) )
assert ( assert (
serialized_tx.hex() serialized_tx.hex()
== "010000000001037b010c5faeb41cc5c253121b6bf69bf1a7c5867cd7f2d91569fea0ecd311b8650100000000ffffffffcd3b93f5b24ae190ce5141235091cd93fbb2908e24e5b9ff6776aec11b0e04e5000000006a4730440220566602a3794e29a5082feb2efd9ce0299455d0c4a31f76d4abafdcc0fed1cde502200ae36cb0563cf4792fd8a10026ec7c94028ca61a5b6903108af3343278ad29bb0121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffffe5918f661488bb7f0a7d04fc1dad61b5d0bad5167a05b3a637e36ace881cbc310000000000ffffffff01803a480200000000160014a579388225827d9f2fe9014add644487808c695d02473044022001187697b2ae95206eb18751701b6a3efd4c2da89cc9d8f0365e8ede7582c8ff0220282a2c127da57e82aecf0f421f7b8d5781205232b3429dd25d2b85aa1e48b741012103505647c017ff2156eb6da20fae72173d3b681a1d0a629f95f49e884db300689f00024830450221008aa7c6ea2b017701145c8b062e05c35259d271ea3009229776b9ef6e17a823da022004a11059927dcc21ff3f0e9441e36e91b4e0db879d102ea6a26f84a8a5d6d35c012103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f86200000000" == "010000000001037b010c5faeb41cc5c253121b6bf69bf1a7c5867cd7f2d91569fea0ecd311b8650100000000ffffffffcd3b93f5b24ae190ce5141235091cd93fbb2908e24e5b9ff6776aec11b0e04e5000000006a4730440220566602a3794e29a5082feb2efd9ce0299455d0c4a31f76d4abafdcc0fed1cde502200ae36cb0563cf4792fd8a10026ec7c94028ca61a5b6903108af3343278ad29bb0121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffffe5918f661488bb7f0a7d04fc1dad61b5d0bad5167a05b3a637e36ace881cbc310000000000ffffffff01803a480200000000160014a579388225827d9f2fe9014add644487808c695d02473044022001187697b2ae95206eb18751701b6a3efd4c2da89cc9d8f0365e8ede7582c8ff0220282a2c127da57e82aecf0f421f7b8d5781205232b3429dd25d2b85aa1e48b741012103505647c017ff2156eb6da20fae72173d3b681a1d0a629f95f49e884db300689f0002483045022100f2d398ac6bc702cfa4f7eb3d2579a233f1d7c920c45a14329a741db6c24fde8f02203b1f6aed5671eece8ba5b5c05ec0330a43c0914b8ff606945cb8cf9e164ec88f012103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f86200000000"
) )
@ -195,10 +195,7 @@ def test_non_segwit_segwit_non_segwit_inputs(client):
script_type=messages.InputScriptType.SPENDWITNESS, script_type=messages.InputScriptType.SPENDWITNESS,
) )
inp3 = messages.TxInputType( inp3 = messages.TxInputType(
address_n=parse_path("44'/1'/1'/0/0"), address_n=parse_path("44'/1'/1'/0/0"), prev_hash=TXHASH_2bac7a, prev_index=0,
amount=1,
prev_hash=TXHASH_2bac7a,
prev_index=0,
) )
out1 = messages.TxOutputType( out1 = messages.TxOutputType(
address="tb1q54un3q39sf7e7tlfq99d6ezys7qgc62a6rxllc", address="tb1q54un3q39sf7e7tlfq99d6ezys7qgc62a6rxllc",

View File

@ -100,13 +100,13 @@ def test_invalid_prev_hash_attack(client, prev_hash):
# prepare input with a valid prev-hash # prepare input with a valid prev-hash
inp1 = messages.TxInputType( inp1 = messages.TxInputType(
address_n=tools.parse_path("m/44h/0h/0h/0/0"), address_n=tools.parse_path("m/44h/0h/0h/0/0"),
amount=123456789, amount=100000000,
prev_hash=b"\x00" * 32, prev_hash=TXHASH_157041,
prev_index=0, prev_index=0,
script_type=messages.InputScriptType.SPENDP2SHWITNESS, script_type=messages.InputScriptType.SPENDP2SHWITNESS,
) )
out1 = messages.TxOutputType( out1 = messages.TxOutputType(
address="mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC", address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1",
amount=12300000, amount=12300000,
script_type=messages.OutputScriptType.PAYTOADDRESS, script_type=messages.OutputScriptType.PAYTOADDRESS,
) )
@ -130,7 +130,7 @@ def test_invalid_prev_hash_attack(client, prev_hash):
with client, pytest.raises(TrezorFailure) as e: with client, pytest.raises(TrezorFailure) as e:
client.set_filter(messages.TxAck, attack_filter) client.set_filter(messages.TxAck, attack_filter)
btc.sign_tx(client, "Testnet", [inp1], [out1]) btc.sign_tx(client, "Bitcoin", [inp1], [out1], prev_txes=TxCache("Bitcoin"))
# check that injection was performed # check that injection was performed
assert counter == 0 assert counter == 0

View File

@ -21,7 +21,7 @@ from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import H_, parse_path from trezorlib.tools import H_, parse_path
from ..tx_cache import TxCache from ..tx_cache import TxCache
from .signtx import request_finished, request_input, request_output from .signtx import request_finished, request_input, request_meta, request_output
B = proto.ButtonRequestType B = proto.ButtonRequestType
TX_API = TxCache("Testnet") TX_API = TxCache("Testnet")
@ -32,6 +32,12 @@ TXHASH_20912f = bytes.fromhex(
TXHASH_9c3192 = bytes.fromhex( TXHASH_9c3192 = bytes.fromhex(
"9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be" "9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be"
) )
TXHASH_dee13c = bytes.fromhex(
"dee13c469e7ab28108a1ce470d74cb40896d9bb459951bdf590ca6a495293a02"
)
TXHASH_e5040e = bytes.fromhex(
"e5040e1bc1ae7667ffb9e5248e90b2fb93cd9150234151ce90e14ab2f5933bcd"
)
class TestMsgSigntxSegwit: class TestMsgSigntxSegwit:
@ -58,6 +64,10 @@ class TestMsgSigntxSegwit:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_20912f),
request_input(0, TXHASH_20912f),
request_output(0, TXHASH_20912f),
request_output(1, TXHASH_20912f),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -102,6 +112,10 @@ class TestMsgSigntxSegwit:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_20912f),
request_input(0, TXHASH_20912f),
request_output(0, TXHASH_20912f),
request_output(1, TXHASH_20912f),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -128,7 +142,7 @@ class TestMsgSigntxSegwit:
inp1 = proto.TxInputType( inp1 = proto.TxInputType(
address_n=parse_path("m/49'/1'/0'/0/0"), address_n=parse_path("m/49'/1'/0'/0/0"),
amount=2 ** 32 + 1, amount=2 ** 32 + 1,
prev_hash=b"\xff" * 32, prev_hash=TXHASH_dee13c,
prev_index=0, prev_index=0,
script_type=proto.InputScriptType.SPENDP2SHWITNESS, script_type=proto.InputScriptType.SPENDP2SHWITNESS,
) )
@ -141,6 +155,8 @@ class TestMsgSigntxSegwit:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_dee13c),
request_output(0, TXHASH_dee13c),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -150,10 +166,12 @@ class TestMsgSigntxSegwit:
request_finished(), request_finished(),
] ]
) )
_, serialized_tx = btc.sign_tx(client, "Testnet", [inp1], [out1]) _, serialized_tx = btc.sign_tx(
client, "Testnet", [inp1], [out1], prev_txes=TX_API
)
assert ( assert (
serialized_tx.hex() serialized_tx.hex()
== "01000000000101ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000171600140099a7ecbd938ed1839f5f6bf6d50933c6db9d5cffffffff01010000000100000017a914097c569095163e84475d07aa95a1f736df895b7b8702483045022100cb9d3aa7a8064702e6b61c20c7fb9cb672c69d3786cf5efef8ad6d90136ca7d8022065119ff6c6e6e6960e6508fc5360359bb269bb25ef8d90019decaa0a050cc45a0121033add1f0e8e3c3136f7428dd4a4de1057380bd311f5b0856e2269170b4ffa65bf00000000" == "01000000000101023a2995a4a60c59df1b9559b49b6d8940cb740d47cea10881b27a9e463ce1de00000000171600140099a7ecbd938ed1839f5f6bf6d50933c6db9d5cffffffff01010000000100000017a914097c569095163e84475d07aa95a1f736df895b7b8702483045022100965aa8897c7cd5f0bff830481ed5259bf662ed0415ab497a6a152a3c335eb0a1022060acbbbada909b6575ac6f19382a6bdf4cab2fa1c5421aa66677806f380ddb870121033add1f0e8e3c3136f7428dd4a4de1057380bd311f5b0856e2269170b4ffa65bf00000000"
) )
@pytest.mark.multisig @pytest.mark.multisig
@ -188,6 +206,10 @@ class TestMsgSigntxSegwit:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_9c3192),
request_input(0, TXHASH_9c3192),
request_output(0, TXHASH_9c3192),
request_output(1, TXHASH_9c3192),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -207,6 +229,10 @@ class TestMsgSigntxSegwit:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_9c3192),
request_input(0, TXHASH_9c3192),
request_output(0, TXHASH_9c3192),
request_output(1, TXHASH_9c3192),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -250,6 +276,10 @@ class TestMsgSigntxSegwit:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_20912f),
request_input(0, TXHASH_20912f),
request_output(0, TXHASH_20912f),
request_output(1, TXHASH_20912f),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -288,6 +318,10 @@ class TestMsgSigntxSegwit:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_20912f),
request_input(0, TXHASH_20912f),
request_output(0, TXHASH_20912f),
request_output(1, TXHASH_20912f),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -305,3 +339,82 @@ class TestMsgSigntxSegwit:
assert exc.value.message.endswith( assert exc.value.message.endswith(
"Transaction has changed during signing" "Transaction has changed during signing"
) )
def test_attack_mixed_inputs(self, client):
TRUE_AMOUNT = 123456789
FAKE_AMOUNT = 123
inp1 = proto.TxInputType(
address_n=parse_path("44'/1'/0'/0/0"),
amount=31000000,
prev_hash=TXHASH_e5040e,
prev_index=0,
script_type=proto.InputScriptType.SPENDADDRESS,
sequence=0xFFFFFFFD,
)
inp2 = proto.TxInputType(
address_n=parse_path("49'/1'/0'/1/0"),
amount=TRUE_AMOUNT,
prev_hash=TXHASH_20912f,
prev_index=0,
script_type=proto.InputScriptType.SPENDP2SHWITNESS,
sequence=0xFFFFFFFD,
)
out1 = proto.TxOutputType(
address="mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC",
amount=30998000,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
expected_responses = [
request_input(0),
request_meta(TXHASH_e5040e),
request_input(0, TXHASH_e5040e),
request_output(0, TXHASH_e5040e),
request_output(1, TXHASH_e5040e),
request_input(1),
request_meta(TXHASH_20912f),
request_input(0, TXHASH_20912f),
request_output(0, TXHASH_20912f),
request_output(1, TXHASH_20912f),
request_output(0),
proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
proto.ButtonRequest(code=proto.ButtonRequestType.FeeOverThreshold),
proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
request_input(0),
request_input(1),
request_output(0),
request_input(1),
request_output(0),
request_input(1),
request_finished(),
]
if client.features.model == "1":
# T1 asks for first input for witness again
expected_responses.insert(-2, request_input(0))
with client:
# Sign unmodified transaction.
# "Fee over threshold" warning is displayed - fee is the whole TRUE_AMOUNT
client.set_expected_responses(expected_responses)
btc.sign_tx(
client, "Testnet", [inp1, inp2], [out1], prev_txes=TX_API,
)
# In Phase 1 make the user confirm a lower value of the segwit input.
inp2.amount = FAKE_AMOUNT
if client.features.model == "1":
# T1 fails as soon as it encounters the fake amount.
expected_responses = expected_responses[:9] + [proto.Failure()]
else:
expected_responses = expected_responses[:10] + [proto.Failure()]
with pytest.raises(TrezorFailure) as e, client:
client.set_expected_responses(expected_responses)
btc.sign_tx(
client, "Testnet", [inp1, inp2], [out1], prev_txes=TX_API,
)
assert e.value.failure.message.endswith("Invalid amount specified")

View File

@ -21,7 +21,7 @@ from trezorlib.tools import H_, parse_path
from ..bip32 import deserialize from ..bip32 import deserialize
from ..tx_cache import TxCache from ..tx_cache import TxCache
from .signtx import request_finished, request_input, request_output from .signtx import request_finished, request_input, request_meta, request_output
B = proto.ButtonRequestType B = proto.ButtonRequestType
TX_API = TxCache("Testnet") TX_API = TxCache("Testnet")
@ -79,6 +79,10 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_20912f),
request_input(0, TXHASH_20912f),
request_output(0, TXHASH_20912f),
request_output(1, TXHASH_20912f),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -123,6 +127,10 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_20912f),
request_input(0, TXHASH_20912f),
request_output(0, TXHASH_20912f),
request_output(1, TXHASH_20912f),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -165,6 +173,10 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_091446),
request_input(0, TXHASH_091446),
request_output(0, TXHASH_091446),
request_output(1, TXHASH_091446),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -208,6 +220,10 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_091446),
request_input(0, TXHASH_091446),
request_output(0, TXHASH_091446),
request_output(1, TXHASH_091446),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -266,7 +282,15 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_091446),
request_input(0, TXHASH_091446),
request_output(0, TXHASH_091446),
request_output(1, TXHASH_091446),
request_input(1), request_input(1),
request_meta(TXHASH_65b811),
request_input(0, TXHASH_65b811),
request_output(0, TXHASH_65b811),
request_output(1, TXHASH_65b811),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -327,6 +351,10 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_9c3192),
request_input(0, TXHASH_9c3192),
request_output(0, TXHASH_9c3192),
request_output(1, TXHASH_9c3192),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -346,6 +374,10 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_9c3192),
request_input(0, TXHASH_9c3192),
request_output(0, TXHASH_9c3192),
request_output(1, TXHASH_9c3192),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -398,6 +430,9 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_f41cbe),
request_input(0, TXHASH_f41cbe),
request_output(0, TXHASH_f41cbe),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -417,6 +452,9 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_f41cbe),
request_input(0, TXHASH_f41cbe),
request_output(0, TXHASH_f41cbe),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -476,6 +514,9 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_c93480),
request_input(0, TXHASH_c93480),
request_output(0, TXHASH_c93480),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
request_input(0), request_input(0),
@ -495,6 +536,9 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_c93480),
request_input(0, TXHASH_c93480),
request_output(0, TXHASH_c93480),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
request_input(0), request_input(0),
@ -553,6 +597,9 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_31bc1c),
request_input(0, TXHASH_31bc1c),
request_output(0, TXHASH_31bc1c),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
request_input(0), request_input(0),
@ -572,6 +619,9 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_31bc1c),
request_input(0, TXHASH_31bc1c),
request_output(0, TXHASH_31bc1c),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
request_input(0), request_input(0),
@ -645,7 +695,14 @@ class TestMsgSigntxSegwitNative:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_091446),
request_input(0, TXHASH_091446),
request_output(0, TXHASH_091446),
request_output(1, TXHASH_091446),
request_input(1), request_input(1),
request_meta(TXHASH_a345b8),
request_input(0, TXHASH_a345b8),
request_output(0, TXHASH_a345b8),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),

View File

@ -17,10 +17,17 @@
import pytest import pytest
from trezorlib import btc, messages as proto from trezorlib import btc, messages as proto
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path from trezorlib.tools import parse_path
from ..tx_cache import TxCache from ..tx_cache import TxCache
from .signtx import request_finished, request_input, request_output from .signtx import (
request_extra_data,
request_finished,
request_input,
request_meta,
request_output,
)
B = proto.ButtonRequestType B = proto.ButtonRequestType
TX_API = TxCache("Zcash Testnet") TX_API = TxCache("Zcash Testnet")
@ -58,6 +65,11 @@ class TestMsgSigntxZcash:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_aaf51e),
request_input(0, TXHASH_aaf51e),
request_output(0, TXHASH_aaf51e),
request_output(1, TXHASH_aaf51e),
request_extra_data(0, 1, TXHASH_aaf51e),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -107,6 +119,12 @@ class TestMsgSigntxZcash:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_e38206),
request_input(0, TXHASH_e38206),
request_input(1, TXHASH_e38206),
request_output(0, TXHASH_e38206),
request_output(1, TXHASH_e38206),
request_extra_data(0, 1, TXHASH_e38206),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx),
@ -133,3 +151,29 @@ class TestMsgSigntxZcash:
serialized_tx.hex() serialized_tx.hex()
== "0400008085202f890168039326c180fa7b1e999392e25a3ec6a8aec83c11b787ddb1746922020682e3000000006b483045022100f28298891f48706697a6f898ac18e39ce2c7cebe547b585d51cc22d80b1b21a602201a807b8a18544832d95d1e3ada82c0617bc6d97d3f24d1fb4801ac396647aa880121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff016c9be111000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac00000000000000000000000000000000000000" == "0400008085202f890168039326c180fa7b1e999392e25a3ec6a8aec83c11b787ddb1746922020682e3000000006b483045022100f28298891f48706697a6f898ac18e39ce2c7cebe547b585d51cc22d80b1b21a602201a807b8a18544832d95d1e3ada82c0617bc6d97d3f24d1fb4801ac396647aa880121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff016c9be111000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac00000000000000000000000000000000000000"
) )
@pytest.mark.skip_ui
def test_version_group_id_missing(self, client):
inp1 = proto.TxInputType(
# tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu
address_n=parse_path("m/44h/1h/0h/0/0"),
amount=300000000,
prev_hash=TXHASH_e38206,
prev_index=0,
)
out1 = proto.TxOutputType(
address="tmJ1xYxP8XNTtCoDgvdmQPSrxh5qZJgy65Z",
amount=300000000 - 1940,
script_type=proto.OutputScriptType.PAYTOADDRESS,
)
details = proto.SignTx(version=4)
with pytest.raises(TrezorFailure, match="Version group ID must be set."):
btc.sign_tx(
client,
"Zcash Testnet",
[inp1],
[out1],
details=details,
prev_txes=TX_API,
)

View File

@ -293,6 +293,10 @@ class TestMultisig:
client.set_expected_responses( client.set_expected_responses(
[ [
request_input(0), request_input(0),
request_meta(TXHASH_fbbff7),
request_input(0, TXHASH_fbbff7),
request_output(0, TXHASH_fbbff7),
request_output(1, TXHASH_fbbff7),
request_output(0), request_output(0),
proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.ConfirmOutput),
request_output(1), request_output(1),
@ -307,7 +311,11 @@ class TestMultisig:
with pytest.raises(TrezorFailure) as exc: with pytest.raises(TrezorFailure) as exc:
btc.sign_tx( btc.sign_tx(
client, "Testnet", [input_real], [output_payee, output_change] client,
"Testnet",
[input_real],
[output_payee, output_change],
prev_txes=TxCache("Testnet"),
) )
# must not produce this tx: # must not produce this tx:
# 01000000000101396e2c107427f9eaece56a37539983adb8efd52b067c3d4567805fc8f3f7bffb01000000171600147a876a07b366f79000b441335f2907f777a0280bffffffff02e8030000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac703a0f000000000017a914a1261837f1b40e84346b1504ffe294e402965f2687024830450221009ff835e861be4e36ca1f2b6224aee2f253dfb9f456b13e4b1724bb4aaff4c9c802205e10679c2ead85743119f468cba5661f68b7da84dd2d477a7215fef98516f1f9012102af12ddd0d55e4fa2fcd084148eaf5b0b641320d0431d63d1e9a90f3cbd0d540700000000 # 01000000000101396e2c107427f9eaece56a37539983adb8efd52b067c3d4567805fc8f3f7bffb01000000171600147a876a07b366f79000b441335f2907f777a0280bffffffff02e8030000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac703a0f000000000017a914a1261837f1b40e84346b1504ffe294e402965f2687024830450221009ff835e861be4e36ca1f2b6224aee2f253dfb9f456b13e4b1724bb4aaff4c9c802205e10679c2ead85743119f468cba5661f68b7da84dd2d477a7215fef98516f1f9012102af12ddd0d55e4fa2fcd084148eaf5b0b641320d0431d63d1e9a90f3cbd0d540700000000

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 1896050,
"script_pubkey": "76a914b1401fce7e8bf123c88a0467e0ed11e3b9fbef5488ac"
},
{
"amount": 73452,
"script_pubkey": "76a914d51eca49695cdf47e7f4b55507893e3ad53fe9d888ac"
}
],
"inputs": [
{
"prev_hash": "bc37c28dfb467d2ecb50261387bf752a3977d7e5337915071bb4151e6b711a78",
"prev_index": 0,
"script_sig": "473044022061aee4f17abe044d5df8c52c9ffd3b84e5a29743517e488b20ecf1ae0b3e4d3a02206bb84c55e407f3b684ff8d9bea0a3409cfd865795a19d10b3d3c31f12795c34a412103a020b36130021a0f037c1d1a02042e325c0cb666d6478c1afdcd9d913b9ef080",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,18 @@
{
"bin_outputs": [
{
"amount": 48490,
"script_pubkey": "a91411c1566006ab2b8e8c8d981055b090ecdefa977187"
}
],
"inputs": [
{
"prev_hash": "5f72ec264d961dfdd460a9cc22743c795127b129d40be8087244d93b3f7eee11",
"prev_index": 0,
"script_sig": "00483045022100e87e3ae6ac22ccbaa8a5800b2bbd81aad9ff56e0fc6993953635fd9ee85e49f102204922bebd2ebdb4f80099c22dd9cb8f99961df8b768cc3cb834cffe1cf11777d14147304402206d134d84bbb865b48b901eb22dc1b653a0c2a1614035a6fe30885620edca4f280220256aeaa7efdc7449faaebf4f022a281b8c1ac8335e2292e13e9244baeb04787f414c69522102c5b28669799aba9cd3b6e3fadd9f15009c82a00b3bbf070741de4666b898ee0c21033b8b5f77354be75eba4c98cf4a32d471a827261228aa2ed7d32c67eec7e150562103cfe16448d9d112d5b965dbe338eec6221006a386727512c3a1f704d4604c494653ae",
"sequence": 4294967294
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,18 @@
{
"bin_outputs": [
{
"amount": 1995344,
"script_pubkey": "76a914de701ce12e576395c863e9377c76dd7efe0c55c188ac"
}
],
"inputs": [
{
"prev_hash": "8d566ad80d5f1d3887d3acddb35b980641919e6efa7c3a3a78413e56f95ea516",
"prev_index": 1,
"script_sig": "483045022100860b4c43649f86ee603c13791646af4736c50b532e1fc905c53d73ddd3754f3902206a301113f27b0d10622b333eb914751eed8af7f5534e0e4ee01176668674f259412102e227a30cc2aa732090af6667086b1665cbe6dbde71aab95ada5a518a4c2fdb6e",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 24000,
"script_pubkey": "76a91400741952f6a6eab5394f366db5cc5a54b0c2429f88ac"
},
{
"amount": 24000,
"script_pubkey": "a914756c06d7e77de3950a6124f026d8e1a2464b3ecf87"
}
],
"inputs": [
{
"prev_hash": "8b6db9b8ba24235d86b053ea2ccb484fc32b96f89c3c39f98d86f90db16076a0",
"prev_index": 0,
"script_sig": "00483045022100f1153636371ba1f84389460e1265a8fa296569bc18e117c31f4e8f0fc0650c01022022932cc84766ff0c0f65ed9633ad311ae90d4c8fe71f5e1890b1e8f74dd516fa41483045022100bcb1a7134a13025a06052546ee1c6ac3640a0abd2d130190ed13ed7fcb43e9cd02207c381478e2ee123c850425bfbf6d3c691230eb37e333832cb32a1ed3f2cd9e85414c69522102fcf63419c319ce1a42d69120a3599d6da8c5dd4caf2888220eccde5a1ff7c5d021036d7d5ef79370b7fabe2c058698a20219e97fc70868e65ecdd6b37cc18e8a88bd2103505dc649dab8cd1655a4c0daf0ec5f955881c9d7011478ea881fac11cab1e49953ae",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 1252382934,
"script_pubkey": "76a9140cb60a52559620e5de9a297612d49f55f7fd14ea88ac"
},
{
"amount": 0,
"script_pubkey": "6a24aa21a9eddb3ac2bba12721c8db157ba6b522196093d3a27a8083591a2b785a230a1d254f"
}
],
"inputs": [
{
"prev_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"prev_index": 4294967295,
"script_sig": "03b4e407005a2d4e4f4d50212068747470733a2f2f6769746875622e636f6d2f6a6f7368756179616275742f7a2d6e6f6d70",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,24 @@
{
"bin_outputs": [
{
"amount": 38448607,
"script_pubkey": "76a914b79bbff2766286a99129642d70912c6a4223c62b88ac"
}
],
"inputs": [
{
"prev_hash": "52fb172f86926a89a16edf55bc9baec3929149b7cd2d2389be3c7d08d744d300",
"prev_index": 1,
"script_sig": "4830450221008bff524a092086372a19b924f41fa7fa2a5523bf42a4801b9503fcdfff2094e8022000f223a032bd0d7fee31d5663cd5cf86b82533bda6871366d519a68deae1042341210222c6760cc54de6fd7f2a40207a13137d497c7cdb472376523700d8ea88275a96",
"sequence": 4294967295
},
{
"prev_hash": "371eb4feaa4085b378bb825f3c1b457867c24211ee838584b1adac226bba654b",
"prev_index": 0,
"script_sig": "47304402206aee1d853479782029755dd3c360dbd963e6390da12ddf2c2c38314692510385022040c9c01253a77bc33ac11ce0e8c187ab4f2d78346c0b222a87b1f00fea6b212941210222c6760cc54de6fd7f2a40207a13137d497c7cdb472376523700d8ea88275a96",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 123456789,
"script_pubkey": "a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87"
},
{
"amount": 9764242764,
"script_pubkey": "76a91435528b20e9a793cf2c3a1cf9cff1f2127ad377da88ac"
}
],
"inputs": [
{
"prev_hash": "4f2f857f39ed1afe05542d058fb0be865a387446e32fc876d086203f483f61d1",
"prev_index": 1,
"script_sig": "47304402201f8f57f708144c3a11da322546cb37bd385aa825d940c37e8016f0efd6ec3e9402202a41bc02c29e4f3f13efd4bededbcd4308a6393279111d614ee1f7635cf3e65701210371546a36bdf6bc82087301b3f6e759736dc8790150673d2e7e2715d2ad72f3a4",
"sequence": 4294967294
}
],
"lock_time": 650749,
"version": 1
}

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 12300000,
"script_pubkey": "0014b31dc2a236505a6cb9201fa0411ca38a254a7bf1"
},
{
"amount": 9887699777,
"script_pubkey": "76a91438cc090e4a4b2e458c33fe35af1c5c0094699ac288ac"
}
],
"inputs": [
{
"prev_hash": "1c92508b38239e5c10b23fb46dcf765ee2f3a95b835edbf0943ec21b21711160",
"prev_index": 1,
"script_sig": "483045022100d9615361c044e91f6dd7bb4455f3ad686cd5a663d7800bb74c448b2706500ccb022026bed24b81a501e8398411c5a9a793741d9bfe39617d51c363dde0a84f44f4f9012102659a6eefcc72d6f2eff92e57095388b17db0b06034946ecd44120e5e7a830ff4",
"sequence": 4294967293
}
],
"lock_time": 650645,
"version": 1
}

View File

@ -0,0 +1,21 @@
{
"bin_outputs": [
{
"amount": 1099980000,
"script_pubkey": "76a91400178fa0b6fc253a3a402ee2cadd8a7bfec08f6388ac"
}
],
"branch_id": 1991772603,
"inputs": [
{
"prev_hash": "340d478f0c5750057d5f5028db8c10993578849e63f5cf8500e33ddefcd5334f",
"prev_index": 0,
"script_sig": "483045022100d29433faed373d23883ace59acda117a67d6e8e3e99bc767b96a183a840b4aec0220258baef0d63360324f2a455299b2695ae2fa727a5969a25a604c22086e36c6e9012102a87aef7b1a8f676e452d6240767699719cd58b0261c822472c25df146938bca5",
"sequence": 4294967295
}
],
"extra_data": "0000000000000000000000",
"lock_time": 0,
"version": 4,
"version_group_id": 2301567109
}

View File

@ -0,0 +1,21 @@
{
"bin_outputs": [
{
"amount": 1099970000,
"script_pubkey": "76a91400178fa0b6fc253a3a402ee2cadd8a7bfec08f6388ac"
}
],
"branch_id": 1991772603,
"inputs": [
{
"prev_hash": "2807c5b126ec8e2b078cab0f12e4c8b4ce1d7724905f8ebef8dca26b0c8e0f1d",
"prev_index": 0,
"script_sig": "4730440220158c970ca2fc6bcc33026eb5366f0342f63b35d178f7efb334b1df78fe90b67202207bc4ff69f67cf843b08564a5adc77bf5593e28ab4d5104911824ac13fe885d8f012102a87aef7b1a8f676e452d6240767699719cd58b0261c822472c25df146938bca5",
"sequence": 4294967295
}
],
"extra_data": "0000000000000000000000",
"lock_time": 1563046072,
"version": 4,
"version_group_id": 2301567109
}

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 12300000,
"script_pubkey": "00140099a7ecbd938ed1839f5f6bf6d50933c6db9d5c"
},
{
"amount": 111145789,
"script_pubkey": "a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87"
}
],
"inputs": [
{
"prev_hash": "20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337",
"prev_index": 0,
"script_sig": "160014d16b8c0680c61fc6ed2e407455715055e41052f5",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 123456789,
"script_pubkey": "a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87"
},
{
"amount": 865519308,
"script_pubkey": "76a914b84bacdcd8f4cc59274a5bfb73f804ca10f7fd1488ac"
}
],
"inputs": [
{
"prev_hash": "802cabf0843b945eabe136d7fc7c89f41021658abf56cba000acbce88c41143a",
"prev_index": 0,
"script_sig": "4730440220548e087d0426b20b8a571b03b9e05829f7558b80c53c12143e342f56ab29e51d02205b68cb7fb223981d4c999725ac1485a982c4259c4f50b8280f137878c232998a012102794a25b254a268e59a5869da57fbae2fadc6727cb3309321dab409b12b2fa17c",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,18 @@
{
"bin_outputs": [
{
"amount": 1603000,
"script_pubkey": "a914a8655acf68f785125561158b0f4db9b5d004404787"
}
],
"inputs": [
{
"prev_hash": "c9348040bbc2024e12dcb4a0b4806b0398646b91acf314da028c3f03dd0179fc",
"prev_index": 0,
"script_sig": "",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 5000000,
"script_pubkey": "a9147a55d61848e77ca266e79a39bfc85c580a6426c987"
},
{
"amount": 7289000,
"script_pubkey": "0014d16b8c0680c61fc6ed2e407455715055e41052f5"
}
],
"inputs": [
{
"prev_hash": "09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a",
"prev_index": 0,
"script_sig": "",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 11924164,
"script_pubkey": "76a914b6fc54e2f7c490ba20c686f532bfb02230656dbf88ac"
},
{
"amount": 1610436,
"script_pubkey": "a91463ff81a0110ab929bd1d44befa32b081839bbece87"
}
],
"inputs": [
{
"prev_hash": "fbbf0824193fc4e4bb410276345cc235d530563d0da63ecc8d0fecf483c01e5e",
"prev_index": 1,
"script_sig": "47304402206d881393370f90ed0d74121b840794c62701a3fb98f2b14c45cbdc3869f7085802201a884b10eb1a5af026635d266e9b4514a9639b78d0a25cf7ebc579bca254fc7301210307c080981397c49589f3a8eb61e58d654ed1c2aa2fe049149c9757e4ba2a6ba8",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,18 @@
{
"bin_outputs": [
{
"amount": 100,
"script_pubkey": "002008b681071cd896cd879102bce735080758ad48ad45a05505939e55f115391991"
}
],
"inputs": [
{
"prev_hash": "5a67c3318c1636e192924c30ca849dec057892acdce5931b504dc453248d681e",
"prev_index": 0,
"script_sig": "",
"sequence": 4294967293
}
],
"lock_time": 1583125,
"version": 2
}

View File

@ -0,0 +1,18 @@
{
"bin_outputs": [
{
"amount": 1604000,
"script_pubkey": "00201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a1"
}
],
"inputs": [
{
"prev_hash": "f41cbedd8becee05a830f418d13aa665125464547db5c7a6cd28f21639fe1228",
"prev_index": 0,
"script_sig": "",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,9 @@
{
"bin_outputs": [
{
"amount": 4294967297,
"script_pubkey": "4d7920686f76657263726166742069732066756c6c206f662065656c732e"
}
],
"version": 1
}

View File

@ -0,0 +1,18 @@
{
"bin_outputs": [
{
"amount": 1605000,
"script_pubkey": "0020c5f4a0a4ea7c0392efe0a9670a73264cffa90b19107cd8a8e9750ff93c77fdfb"
}
],
"inputs": [
{
"prev_hash": "9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be",
"prev_index": 1,
"script_sig": "2200201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a1",
"sequence": 4294967295
}
],
"lock_time": 0,
"version": 1
}

View File

@ -0,0 +1,22 @@
{
"bin_outputs": [
{
"amount": 3199834,
"script_pubkey": "a9146794cf0b05c69d8e1942a8f9eeaf59a0847dafda87"
},
{
"amount": 1000000,
"script_pubkey": "a914bbc6a47c8984cf60fd1f0eb753291458b5b42aa687"
}
],
"inputs": [
{
"prev_hash": "0e4194441d68c26d3bbc3646d7ad7bc0435cc7c85ac7f39d22587cb4f6959a69",
"prev_index": 15,
"script_sig": "160014e09c199e2cbcd552f0e58acfb933b3f4f426781f",
"sequence": 4294967294
}
],
"lock_time": 1667005,
"version": 2
}

View File

@ -0,0 +1,25 @@
{
"bin_outputs": [
{
"amount": 417937001,
"script_pubkey": "76a914f5ea91f798002a6520f19da514f354b1c37b30d188ac"
},
{
"amount": 300000000,
"script_pubkey": "76a914a579388225827d9f2fe9014add644487808c695d88ac"
}
],
"inputs": [
{
"prev_hash": "01d175a5421206439525542f83d168577e92d59e8283e8862e236a1461d5938a",
"prev_index": 2,
"script_sig": "473044022053a63f730e449f2d6c687ac53e9be627c4241614c041f458da2c4f91143179c802206ade1de030fc5fc77c4a88ccc79daedd28a79bfaf9e24533727a6fb81cbe4bd801210201d494a45f36f545443bafd1a9050b02f448dd236bb4ce2602f83978980b98f2",
"sequence": 4294967294
}
],
"expiry": 234352,
"extra_data": "00",
"lock_time": 234321,
"version": 3,
"version_group_id": 63210096
}

View File

@ -0,0 +1,31 @@
{
"bin_outputs": [
{
"amount": 300000000,
"script_pubkey": "76a914a579388225827d9f2fe9014add644487808c695d88ac"
},
{
"amount": 1251648,
"script_pubkey": "76a91474374446b18916decd3292384ea73006ebd268ba88ac"
}
],
"inputs": [
{
"prev_hash": "4e8e8c5a5524cb8b20d05aefd5b1fd004d6c8c584e3e314876f13edb5ba0eead",
"prev_index": 0,
"script_sig": "473044022064e1e5f957308fcc91f7b174113c8e3cb8060b1404ae823ab3f77f313d5b557b02204b2afcde9ef8b61f5e85192c38fb82307d077ec91d2c8249aa69e19967df8c0c01210201d494a45f36f545443bafd1a9050b02f448dd236bb4ce2602f83978980b98f2",
"sequence": 4294967294
},
{
"prev_hash": "7afab9216fee6763ffbd6a412d46d68c480220af093c9becee6f79d41b954b13",
"prev_index": 0,
"script_sig": "47304402207f63a484ee75900ce2b0e2a5f0d52f2cfb5d1475588576f645c20ecf5e04659a02205c9b614ca846b0cb9ff4a72ca8482c9aed542282b9ee8eaa70a5f472408f3f04012103e974b89ace172f24bb25f8137d19c4205c5cf6bb6505454230ea172f54152d08",
"sequence": 4294967294
}
],
"expiry": 261318,
"extra_data": "00",
"lock_time": 261287,
"version": 3,
"version_group_id": 63210096
}

View File

@ -241,20 +241,19 @@
"test_msg_signtx.py-test_testnet_one_two_fee": "cfd5c83510c044c456622298138e222aee135a6df607bb6e5603228535f0762f", "test_msg_signtx.py-test_testnet_one_two_fee": "cfd5c83510c044c456622298138e222aee135a6df607bb6e5603228535f0762f",
"test_msg_signtx.py-test_two_changes": "77ac9a437f9ba258577d17528eca1c0c60791fbc273d9cf046ce193bbd9e5e56", "test_msg_signtx.py-test_two_changes": "77ac9a437f9ba258577d17528eca1c0c60791fbc273d9cf046ce193bbd9e5e56",
"test_msg_signtx.py-test_two_two": "57707ecbcb77f670148c6076724b3da2e880d27ecf86e29135af4a5aeef6fdbc", "test_msg_signtx.py-test_two_two": "57707ecbcb77f670148c6076724b3da2e880d27ecf86e29135af4a5aeef6fdbc",
"test_msg_signtx_bcash.py-test_attack_amount": "05cb99d3f9b862c448d07934af46d07f0bc4775c7aef4b113f137932870370bb",
"test_msg_signtx_bcash.py-test_attack_change_input": "a03ee0471deeb54d51b73c0fde08795ab0ba8c37daec2d43f5637e705420b435", "test_msg_signtx_bcash.py-test_attack_change_input": "a03ee0471deeb54d51b73c0fde08795ab0ba8c37daec2d43f5637e705420b435",
"test_msg_signtx_bcash.py-test_send_bch_change": "a03ee0471deeb54d51b73c0fde08795ab0ba8c37daec2d43f5637e705420b435", "test_msg_signtx_bcash.py-test_send_bch_change": "a03ee0471deeb54d51b73c0fde08795ab0ba8c37daec2d43f5637e705420b435",
"test_msg_signtx_bcash.py-test_send_bch_multisig_change": "b607b039e864dc9c5f616ee6f5b780184552ff5c6b8e984ccc8eed133b3d36dd", "test_msg_signtx_bcash.py-test_send_bch_multisig_change": "b607b039e864dc9c5f616ee6f5b780184552ff5c6b8e984ccc8eed133b3d36dd",
"test_msg_signtx_bcash.py-test_send_bch_multisig_wrongchange": "8d5c2c06f8d3dd75a03bdf6ecff865e81f8748e4ef5394d75ade3e50512ea087", "test_msg_signtx_bcash.py-test_send_bch_multisig_wrongchange": "8d5c2c06f8d3dd75a03bdf6ecff865e81f8748e4ef5394d75ade3e50512ea087",
"test_msg_signtx_bcash.py-test_send_bch_nochange": "3895b874e18582ea77dea2d10ea44906fce4e67e3b7ce3118f5c959fc428d037", "test_msg_signtx_bcash.py-test_send_bch_nochange": "3895b874e18582ea77dea2d10ea44906fce4e67e3b7ce3118f5c959fc428d037",
"test_msg_signtx_bcash.py-test_send_bch_oldaddr": "4a832b4cec5ae0108b8f2155a08156dbbb9ce82403af98532d6ccd89e65d70e3", "test_msg_signtx_bcash.py-test_send_bch_oldaddr": "4a832b4cec5ae0108b8f2155a08156dbbb9ce82403af98532d6ccd89e65d70e3",
"test_msg_signtx_bgold.py-test_attack_change_input": "de2fe54950938864480fd40866db18a73565fdc9de2f7867ab7e0a8ae7f65ce4", "test_msg_signtx_bgold.py-test_attack_change_input": "8e127323823058532b7960ef9507aa24c38c9f22055015d86fdf8132124fb727",
"test_msg_signtx_bgold.py-test_send_bitcoin_gold_change": "de2fe54950938864480fd40866db18a73565fdc9de2f7867ab7e0a8ae7f65ce4", "test_msg_signtx_bgold.py-test_send_bitcoin_gold_change": "8e127323823058532b7960ef9507aa24c38c9f22055015d86fdf8132124fb727",
"test_msg_signtx_bgold.py-test_send_bitcoin_gold_nochange": "65a3fa31182748333a44e8cedcee653d7532428126d6df1ef3514424adcb10f1", "test_msg_signtx_bgold.py-test_send_bitcoin_gold_nochange": "6a5adba8117be6e07405372866bf2ac4054d86f2cffb63d64fa0db1f8f3de500",
"test_msg_signtx_bgold.py-test_send_btg_multisig_change": "4ed4962fa425498e4d7ae158d1233b01319dfa071edcb2d71f2f4d4e57c4b4fd", "test_msg_signtx_bgold.py-test_send_btg_multisig_change": "6a210a01310014a61c7df66558d48a5503b8e8b5644c404b193cefc94bb7dadb",
"test_msg_signtx_bgold.py-test_send_mixed_inputs": "ed137c7c45d1bd9f2e73b4ca6ea0eff63b601e8ad73d79a90aefd2046e2d51b2", "test_msg_signtx_bgold.py-test_send_mixed_inputs": "6a5adba8117be6e07405372866bf2ac4054d86f2cffb63d64fa0db1f8f3de500",
"test_msg_signtx_bgold.py-test_send_multisig_1": "d049b3b25042c732ce26a253e7de49581adc83003713860924b8d951cb46de0c", "test_msg_signtx_bgold.py-test_send_multisig_1": "0a611e9cc266a5aec9017373cec013756b1715da3bf9d08281194b20ebad72d2",
"test_msg_signtx_bgold.py-test_send_p2sh": "ddd48151ce1d74ade0b9858cbcdba316581991ec92c2ef54b5893e3aae75f995", "test_msg_signtx_bgold.py-test_send_p2sh": "7f481a8cd3474b05cf38aab47592bc754751af7e0f009677fdda95ddaa7b07ca",
"test_msg_signtx_bgold.py-test_send_p2sh_witness_change": "02e44d4c1072eb774486210f885b1bee53acfb3b7fd787207b9f955853fef055", "test_msg_signtx_bgold.py-test_send_p2sh_witness_change": "02e44d4c1072eb774486210f885b1bee53acfb3b7fd787207b9f955853fef055",
"test_msg_signtx_dash.py-test_send_dash": "291f1a3ace22877641494a1a470a1a4a8dab6e363fc4402dadaeb52c1288c72b", "test_msg_signtx_dash.py-test_send_dash": "291f1a3ace22877641494a1a470a1a4a8dab6e363fc4402dadaeb52c1288c72b",
"test_msg_signtx_dash.py-test_send_dash_dip2_input": "cf7fc7e6fe3a9e4063e743da6fc44c27dac013917bc00cfc63d13a183c091d91", "test_msg_signtx_dash.py-test_send_dash_dip2_input": "cf7fc7e6fe3a9e4063e743da6fc44c27dac013917bc00cfc63d13a183c091d91",
@ -271,6 +270,7 @@
"test_msg_signtx_komodo.py-test_one_one_rewards_claim": "e53f221fda81469027e39e21877a81a8fafbffbece0a45aeda12aae8873b0464", "test_msg_signtx_komodo.py-test_one_one_rewards_claim": "e53f221fda81469027e39e21877a81a8fafbffbece0a45aeda12aae8873b0464",
"test_msg_signtx_peercoin.py::test_timestamp_included": "825b9bdf5238c5c6415a254a6bae4b2bd9df8fc5cb31f66f0c20145cb4e60bbb", "test_msg_signtx_peercoin.py::test_timestamp_included": "825b9bdf5238c5c6415a254a6bae4b2bd9df8fc5cb31f66f0c20145cb4e60bbb",
"test_msg_signtx_segwit.py-test_attack_change_input_address": "5ae71202c062ef7942626a80a4ceeb8d8c4ea5065a97f0de6a97505e9cb82c2c", "test_msg_signtx_segwit.py-test_attack_change_input_address": "5ae71202c062ef7942626a80a4ceeb8d8c4ea5065a97f0de6a97505e9cb82c2c",
"test_msg_signtx_segwit.py-test_attack_mixed_inputs": "1ae5200c6ce74cefae77ab1cfd6e032d0660aa4d106b8c54e092856f656f1e39",
"test_msg_signtx_segwit.py-test_send_multisig_1": "958a0741070e057dcb889b2000e5487d391bc513e4a5d86193a355261c5f361b", "test_msg_signtx_segwit.py-test_send_multisig_1": "958a0741070e057dcb889b2000e5487d391bc513e4a5d86193a355261c5f361b",
"test_msg_signtx_segwit.py-test_send_p2sh": "ca593e31e919b9e920289b13e4c70b9607f34b93d06ace69835e3d08ecf046c8", "test_msg_signtx_segwit.py-test_send_p2sh": "ca593e31e919b9e920289b13e4c70b9607f34b93d06ace69835e3d08ecf046c8",
"test_msg_signtx_segwit.py-test_send_p2sh_change": "562c7ee5a2e264c9f93387dd165403dab32bb305a4c3a6143a902c4a4c9e5950", "test_msg_signtx_segwit.py-test_send_p2sh_change": "562c7ee5a2e264c9f93387dd165403dab32bb305a4c3a6143a902c4a4c9e5950",