# This file is part of the Trezor project. # # Copyright (C) 2012-2019 SatoshiLabs and contributors # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License version 3 # as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the License along with this library. # If not, see . import pytest from trezorlib import btc, messages as proto from trezorlib.exceptions import TrezorFailure from trezorlib.tools import H_, parse_path from ..tx_cache import TxCache from .signtx import request_finished, request_input, request_output B = proto.ButtonRequestType TX_API = TxCache("Bgold") TXHASH_25526b = bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ) TXHASH_db77c2 = bytes.fromhex( "db77c2461b840e6edbe7f9280043184a98e020d9795c1b65cb7cef2551a8fb18" ) TXHASH_e5040e = bytes.fromhex( "e5040e1bc1ae7667ffb9e5248e90b2fb93cd9150234151ce90e14ab2f5933bcd" ) TXHASH_65b811 = bytes.fromhex( "65b811d3eca0fe6915d9f2d77c86c5a7f19bf66b1b1253c2c51cb4ae5f0c017b" ) # All data taken from T1 @pytest.mark.altcoin class TestMsgSigntxBitcoinGold: def test_send_bitcoin_gold_change(self, client): inp1 = proto.TxInputType( address_n=parse_path("44'/156'/0'/0/0"), amount=1995344, prev_hash=TXHASH_25526b, prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=parse_path("44'/156'/0'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=73452, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with client: client.set_expected_responses( [ request_input(0), request_output(0), request_output(1), proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), request_output(1), request_finished(), ] ) _, serialized_tx = btc.sign_tx( client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "010000000185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b5225000000006b483045022100963904da0731b71ce468afd45366dd80fbff566ec0d39c1161ab85d17459c7ca02202f5c24a7a7272d98b14a3f5bc000c7cde8ac0eb773f20f4c3131518186cc98854121023bd0ec4022d12d0106c5b7308a25572953ba1951f576f691354a7b147ee0cc1fffffffff0272ee1c00000000001976a9141c82b9c11f193ad82413caadc0955730572b50ae88acec1e0100000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac00000000" ) def test_send_bitcoin_gold_nochange(self, client): inp1 = proto.TxInputType( address_n=parse_path("44'/156'/0'/1/0"), amount=1896050, prev_hash=TXHASH_25526b, prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) inp2 = proto.TxInputType( address_n=parse_path("44'/156'/0'/0/1"), # 1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3 amount=73452, prev_hash=TXHASH_db77c2, prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=1934960, script_type=proto.OutputScriptType.PAYTOADDRESS, ) 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(), ] ) _, serialized_tx = btc.sign_tx( client, "Bgold", [inp1, inp2], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "010000000285c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b5225000000006b483045022100928852076c9fab160c07564cd54691af1cbc37fb28f0b7bee7299c7925ef62f0022058856387afecc6508f2f04ecdfd292a13026a5b2107ebdd2cc789bdf8820d552412102a6c3998d0d4e5197ff41aab5c53580253b3b91f583f4c31f7624be7dc83ce15fffffffff18fba85125ef7ccb651b5c79d920e0984a18430028f9e7db6e0e841b46c277db010000006b483045022100faa2f4f01cc95e680349a093923aae0aa2ea01429873555aa8a84bf630ef33a002204c3f4bf567e2d20540c0f71dc278481d6ccb6b95acda2a2f87ce521c79d6b872412102d54a7e5733b1635e5e9442943f48179b1700206b2d1925250ba10f1c86878be8ffffffff0170861d00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac00000000" ) def test_attack_change_input(self, client): inp1 = proto.TxInputType( address_n=parse_path("44'/156'/11'/0/0"), amount=1995344, prev_hash=TXHASH_25526b, prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=parse_path("44'/156'/11'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=73452, script_type=proto.OutputScriptType.PAYTOADDRESS, ) run_attack = False def attack_processor(msg): nonlocal run_attack if msg.tx.inputs and msg.tx.inputs[0] == inp1: if run_attack: msg.tx.inputs[0].address_n[2] = H_(1) else: run_attack = True return msg client.set_filter(proto.TxAck, attack_processor) with client: client.set_expected_responses( [ request_input(0), request_output(0), request_output(1), proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.SignTx), request_input(0), proto.Failure(code=proto.FailureType.ProcessError), ] ) with pytest.raises(TrezorFailure): btc.sign_tx(client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API) @pytest.mark.multisig def test_send_btg_multisig_change(self, client): nodes = [ btc.get_public_node(client, parse_path("48'/156'/%d'" % i)).node for i in range(1, 4) ] def getmultisig(chain, nr, signatures=[b"", b"", b""], nodes=nodes): return proto.MultisigRedeemScriptType( nodes=nodes, address_n=[chain, nr], signatures=signatures, m=2 ) inp1 = proto.TxInputType( address_n=parse_path("48'/156'/3'/0/0"), multisig=getmultisig(0, 0), # 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R amount=48490, prev_hash=TXHASH_25526b, prev_index=0, script_type=proto.InputScriptType.SPENDMULTISIG, ) out1 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=24000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("48'/156'/3'/1/0"), multisig=getmultisig(1, 0), script_type=proto.OutputScriptType.PAYTOMULTISIG, amount=24000, ) with client: client.set_expected_responses( [ request_input(0), request_output(0), proto.ButtonRequest(code=B.ConfirmOutput), request_output(1), proto.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), request_output(1), request_finished(), ] ) signatures, serialized_tx = btc.sign_tx( client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API ) assert ( signatures[0].hex() == "3045022100d954f341ddd3ec96e4bc6cdb90f2df9b2032723f85e4a0187346dd743130bfca0220105ce08b795c70dc09a55569d7874bff684a877219ec2fc37c88cdffe12f332c" ) inp1 = proto.TxInputType( address_n=parse_path("48'/156'/1'/0/0"), multisig=getmultisig(0, 0, [b"", b"", signatures[0]]), amount=48490, prev_hash=TXHASH_25526b, prev_index=0, script_type=proto.InputScriptType.SPENDMULTISIG, ) out2.address_n[2] = H_(1) with client: client.set_expected_responses( [ request_input(0), request_output(0), proto.ButtonRequest(code=B.ConfirmOutput), request_output(1), proto.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), request_output(1), request_finished(), ] ) signatures, serialized_tx = btc.sign_tx( client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API ) assert ( signatures[0].hex() == "30440220614f9a18695365a2edba0d930404a77cae970d3430ad86c5b5239a96fd54bf84022030bc76a322e3b2b1c987622b5eb6da23ac1e6c905ee9b3b6405a4e4edd5bbb87" ) assert ( serialized_tx.hex() == "010000000185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b522500000000fdfd00004730440220614f9a18695365a2edba0d930404a77cae970d3430ad86c5b5239a96fd54bf84022030bc76a322e3b2b1c987622b5eb6da23ac1e6c905ee9b3b6405a4e4edd5bbb8741483045022100d954f341ddd3ec96e4bc6cdb90f2df9b2032723f85e4a0187346dd743130bfca0220105ce08b795c70dc09a55569d7874bff684a877219ec2fc37c88cdffe12f332c414c695221035a8db79c0ef57a202664a3da60ca41e8865c6d86ed0aafc03f8e75173341b58021037fba152d8fca660cc49973d8bc9421ff49a75b44ea200873d70d3990f763ed4c210348cbcbd93e069416e0d5db93e86b5698852d9fd54502ad0bed9722fa83f90e4b53aeffffffff02c05d0000000000001976a914ea5f904d195079a350b534db4446433b3cec222e88acc05d00000000000017a914623c803f7fb654dac8dda7786fbf9bc38cd867f48700000000" ) def test_send_p2sh(self, client): inp1 = proto.TxInputType( address_n=parse_path("49'/156'/0'/1/0"), amount=123456789, prev_hash=TXHASH_25526b, prev_index=0, script_type=proto.InputScriptType.SPENDP2SHWITNESS, ) out1 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=12300000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address="GZFLExxrvWFuFT1xRzhfwQWSE2bPDedBfn", script_type=proto.OutputScriptType.PAYTOADDRESS, amount=123456789 - 11000 - 12300000, ) with client: client.set_expected_responses( [ request_input(0), request_output(0), proto.ButtonRequest(code=B.ConfirmOutput), request_output(1), proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), request_output(1), request_input(0), request_finished(), ] ) _, serialized_tx = btc.sign_tx( client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250000000017160014b5355d001e720d8f4513da00ff2bba4dcf9d39fcffffffff02e0aebb00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac3df39f06000000001976a914a8f757819ec6779409f45788f7b4a0e8f51ec50488ac02473044022073fcbf2876f073f78923ab427f14de5b2a0fbeb313a9b2b650b3567061f242a702202f45fc22c501108ff6222afe3aca7da9d8c7dc860f9cda335bef31fa184e7bef412102ecea08b559fc5abd009acf77cfae13fa8a3b1933e3e031956c65c12cec8ca3e300000000" ) def test_send_p2sh_witness_change(self, client): inp1 = proto.TxInputType( address_n=parse_path("49'/156'/0'/1/0"), amount=123456789, prev_hash=TXHASH_25526b, prev_index=0, script_type=proto.InputScriptType.SPENDP2SHWITNESS, ) out1 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=12300000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("49'/156'/0'/1/0"), script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, amount=123456789 - 11000 - 12300000, ) with client: client.set_expected_responses( [ request_input(0), request_output(0), proto.ButtonRequest(code=B.ConfirmOutput), request_output(1), proto.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), request_output(1), request_input(0), request_finished(), ] ) _, serialized_tx = btc.sign_tx( client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250000000017160014b5355d001e720d8f4513da00ff2bba4dcf9d39fcffffffff02e0aebb00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac3df39f060000000017a9140cd03822b799a452c106d1b3771844a067b17f118702483045022100d79b33384c686d8dd40ad5f84f46691d30994992c1cb42e934c2a625d86cb2f902206859805a9a98ba140b71a9d4b9a6b8df94a9424f9c40f3bd804149fd6e278d63412102ecea08b559fc5abd009acf77cfae13fa8a3b1933e3e031956c65c12cec8ca3e300000000" ) @pytest.mark.multisig def test_send_multisig_1(self, client): nodes = [ btc.get_public_node(client, parse_path("49'/156'/%d'" % i)).node for i in range(1, 4) ] multisig = proto.MultisigRedeemScriptType( nodes=nodes, address_n=[1, 0], signatures=[b"", b"", b""], m=2 ) inp1 = proto.TxInputType( address_n=parse_path("49'/156'/1'/1/0"), prev_hash=TXHASH_25526b, prev_index=1, script_type=proto.InputScriptType.SPENDP2SHWITNESS, multisig=multisig, amount=1610436, ) out1 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=1605000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with client: client.set_expected_responses( [ request_input(0), request_output(0), proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), request_input(0), request_finished(), ] ) signatures, _ = btc.sign_tx( client, "Bgold", [inp1], [out1], prev_txes=TX_API ) # store signature inp1.multisig.signatures[0] = signatures[0] # sign with third key inp1.address_n[2] = H_(3) client.set_expected_responses( [ request_input(0), request_output(0), proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), request_input(0), request_finished(), ] ) _, serialized_tx = btc.sign_tx( client, "Bgold", [inp1], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250100000023220020ea9ec48498c451286c2ebaf9e19255e2873b0fb517d67b2f2005298c7e437829ffffffff01887d1800000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac0400473044022077cb8b2a534f79328810ca8c330539ae9ffa086c359ddb7da11026557b04eef202201d95be0dd1da0aa01720953e52d5dabffd19a998d1490c13a21b8e52e4ead2e041483045022100e41cbd6a501ba8fe6f65554420e23e950d35af0da9b052da54a087463b0717ca02206c695c8d1f74f9535b5d89a2fd1f9326a0ef20e5400137f1e1daeee992b62b594169522103279aea0b253b144d1b2bb8532280001a996dcddd04f86e5e13df1355032cbc1321032c6465c956c0879663fa8be974c912d229c179a5cdedeb29611a1bec1f951eb22103494480a4b72101cbd2eadac8e18c7a3a7589a7f576bf46b8971c38c51e5eceeb53ae00000000" ) def test_send_mixed_inputs(self, client): # First is non-segwit, second is segwit. inp1 = proto.TxInputType( address_n=parse_path("44'/156'/0'/0/0"), amount=31000000, prev_hash=TXHASH_e5040e, prev_index=0, ) inp2 = proto.TxInputType( address_n=parse_path("84'/156'/0'/1/0"), amount=7289000, prev_hash=TXHASH_65b811, prev_index=1, script_type=proto.InputScriptType.SPENDWITNESS, ) out1 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=31000000 + 7289000 - 1000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with client: _, serialized_tx = btc.sign_tx( client, "Bgold", [inp1, inp2], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "01000000000102cd3b93f5b24ae190ce5141235091cd93fbb2908e24e5b9ff6776aec11b0e04e5000000006a473044022061e94392fa4c0a4bf510bf713c23a37c6c5f6f4dbe5c116e86cff23a93c578e9022026661d2ffb1102d07b7c1631270152441fa171d91108b75a7b9a2cc36ca7db6c4121023bd0ec4022d12d0106c5b7308a25572953ba1951f576f691354a7b147ee0cc1fffffffff7b010c5faeb41cc5c253121b6bf69bf1a7c5867cd7f2d91569fea0ecd311b8650100000000ffffffff01803a4802000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac0002483045022100e39d9bff8350b9ba20cb2ed88e82d7568a83184616acdc16bd1adb4005c5a471022066ff36084e896a69a91a0fad01721f20f2bb42b41e20be35e72fc3729ac7ace74121030b75ccac9add5f82a4c61fe34e791a2f2eda61b544bce4f6fa3d403bb0de748400000000" )