def test_missing_pubkey(self): self.setup_mnemonic_nopin_nopassphrase() # key1 = self.client.get_public_node([1]) # key2 = self.client.get_public_node([2]) # key3 = self.client.get_public_node([3]) # pubkeys: # 0338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6 # 038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3 # 03477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a7902 # multisig address: 3E7GDtuHqnqPmDgwH59pVC7AvySiSkbibz # xpub: # print(bip32.serialize(self.client.get_public_node([]).node)) # xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy node = bip32.deserialize( "xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy" ) multisig = proto.MultisigRedeemScriptType( pubkeys=[ proto.HDNodePathType(node=node, address_n=[1]), proto.HDNodePathType(node=node, address_n=[2]), proto.HDNodePathType(node=node, address_n=[3]), ], signatures=[b"", b"", b""], m=2, ) # Let's go to sign with key 10, which is NOT in pubkeys inp1 = proto.TxInputType( address_n=[10], prev_hash=TXHASH_c6091a, prev_index=1, script_type=proto.InputScriptType.SPENDMULTISIG, multisig=multisig, ) out1 = proto.TxOutputType( address="12iyMbUb4R2K3gre4dHSrbu5azG5KaqVss", amount=100000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with pytest.raises(CallException) as exc: btc.sign_tx(self.client, "Bitcoin", [inp1], [out1], prev_txes=TX_API) assert exc.value.args[0] == proto.FailureType.DataError assert exc.value.args[1].endswith("Pubkey not found in multisig script")
def test_timestamp_included(client): # tx: 3bf506c81ce84eda891679ddc797d162c17c60b15d6c0ac23be5e31369e7235f # input 0: 0.01 CPC # tx: f3a6e6411f1b2dffd76d2729bae8e056f8f9ecf8996d3f428e75a6f23f2c5e8c # input 0: 0.02 CPC inp1 = messages.TxInputType( address_n=parse_path("m/44'/289'/0'/0/0"), prev_hash=TXHASH_3bf506, prev_index=0 ) inp2 = messages.TxInputType( address_n=parse_path("m/44'/289'/0'/0/0"), prev_hash=TXHASH_f3a6e6, prev_index=1 ) out1 = messages.TxOutputType( address="CUGi8RGPWxbHM6FxF4eMEfqmQ6Bs5VjCdr", amount=3000000 - 20000, script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: details = messages.SignTx(version=1, timestamp=0x5BCF5C66) _, timestamp_tx = btc.sign_tx( client, "Capricoin", [inp1, inp2], [out1], details=details, prev_txes=tx_cache("Capricoin"), ) # Accepted by network https://insight.capricoin.org/tx/1bf227e6e24fe1f8ac98849fe06a2c5b77762e906fcf7e82787675f7f3a10bb8 accepted_txhex = "01000000665ccf5b025f23e76913e3e53bc20a6c5db1607cc162d197c7dd791689da4ee81cc806f53b000000006b483045022100fce7ccbeb9524f36d118ebcfebcb133a05c236c4478e2051cfd5c9632920aee602206921b7be1a81f30cce3d8e7dba4597fc16a2761c42321c49d65eeacdfe3781250121021fcf98aee04939ec7df5762f426dc2d1db8026e3a73c3bbe44749dacfbb61230ffffffff8c5e2c3ff2a6758e423f6d99f8ecf9f856e0e8ba29276dd7ff2d1b1f41e6a6f3010000006a473044022015d967166fe9f89fbed8747328b1c4658aa1d7163e731c5fd5908feafe08e9a6022028af30801098418bd298cc60b143c52c48466f5791256721304b6eba4fdf0b3c0121021fcf98aee04939ec7df5762f426dc2d1db8026e3a73c3bbe44749dacfbb61230ffffffff01a0782d00000000001976a914818437acfd15780debd31f3fd21d4ca678bb36d188ac00000000" assert timestamp_tx.hex() == accepted_txhex
def test_15_of_15(self): self.setup_mnemonic_nopin_nopassphrase() """ pubs = [] for x in range(15): pubs.append(self.client.get_public_node([x]).node.public_key.hex())) """ # xpub: # print(bip32.serialize(self.client.get_public_node([]).node)) # xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy node = bip32.deserialize( "xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy" ) pubs = [] for x in range(15): pubs.append(proto.HDNodePathType(node=node, address_n=[x])) # redeeemscript # 5f21023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43d210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a79022103fe91eca10602d7dad4c9dab2b2a0858f71e25a219a6940749ce7a48118480dae210234716c01c2dd03fa7ee302705e2b8fbd1311895d94b1dca15e62eedea9b0968f210341fb2ead334952cf60f4481ba435c4693d0be649be01d2cfe9b02018e483e7bd2102dad8b2bce360a705c16e74a50a36459b4f8f4b78f9cd67def29d54ef6f7c7cf9210222dbe3f5f197a34a1d50e2cbe2a1085cac2d605c9e176f9a240e0fd0c669330d2103fb41afab56c9cdb013fda63d777d4938ddc3cb2ad939712da688e3ed333f95982102435f177646bdc717cb3211bf46656ca7e8d642726144778c9ce816b8b8c36ccf2102158d8e20095364031d923c7e9f7f08a14b1be1ddee21fe1a5431168e31345e5521026259794892428ca0818c8fb61d2d459ddfe20e57f50803c7295e6f4e2f5586652102815f910a8689151db627e6e262e0a2075ad5ec2993a6bc1b876a9d420923d681210318f54647f645ff01bd49fedc0219343a6a22d3ea3180a3c3d3097e4b888a8db45fae # multisig address # 3QaKF8zobqcqY8aS6nxCD5ZYdiRfL3RCmU signatures = [b""] * 15 out1 = proto.TxOutputType( address="17kTB7qSk3MupQxWdiv5ZU3zcrZc2Azes1", amount=10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) for x in range(15): multisig = proto.MultisigRedeemScriptType( pubkeys=pubs, signatures=signatures, m=15 ) inp1 = proto.TxInputType( address_n=[x], prev_hash=bytes.fromhex( "6189e3febb5a21cee8b725aa1ef04ffce7e609448446d3a8d6f483c634ef5315" ), prev_index=1, script_type=proto.InputScriptType.SPENDMULTISIG, multisig=multisig, ) with self.client: sig, serialized_tx = btc.sign_tx( self.client, "Bitcoin", [inp1], [out1], prev_txes=TX_API ) signatures[x] = sig[0] # Accepted as tx id dd320786d1f58c095be0509dc56b277b6de8f2fb5517f519c6e6708414e3300b assert ( serialized_tx.hex() == "01000000011553ef34c683f4d6a8d346844409e6e7fc4ff01eaa25b7e8ce215abbfee3896101000000fd43060048304502210098e23085ad7282de988bf98afa1e9add9c9830009132f8902a9fa4624d5dc98b0220733216e70ab67791aa64be5c83d2050cb4ed9ff7eda2a1acc35da024d2ab2a670147304402201f8c11fb6e90fd616e484986e9451929797eba039882a9abcc203210948060b9022044da031530de7d9747d3c5a8e7cec04b04b7af495c9120b854ce7362af7fa05a01483045022100ea67c70186acef019bdf1551881bf38e6f88186501b64d3a756a2ce18e4ba18002201c35110325653e21e448b60053a4b5dda46b61096faf701a1faca61fcde91f00014730440220315598992f156d2f9d7b4275395fa067aa61ea95829fa17730885c86df4de70d02203eda9ade1656e2198c668603b17e197acb0969ed183ab0841303ea261205618901473044022060fdd6621edde9b8cf6776bc4eef26ace9b57514d725b7214ba11d333520a30e022044c30744f94484aec0f896233c5613a3256878ec0379f566226906b6d1b6061401483045022100b1d907e3574f60f7834c7e9f2e367998ce0461dad7d742d84ef8917d713f41f902203b3ac54f7bb2f7fb8685f582d2a94f7213a37cb508acffe29090cc06ae01588b01483045022100e3bf90ff3ad6395e42f46002f253f94ca0e8ffaa0620f2ceb4fa21493abdca4d02201d4c28b10b740bb2dc4b3695b4205c18f8c0dad2bb69540eb8a36576463cd5280147304402202cfaf9fab7dc1c9f0c3c23bd46bd6d5cea0664d914139fc9add80766ce998808022012db2802c07853e4cbe147afdf0b47e60bdcbcd31f9df19e04c177ed9aa66c6d0147304402207cbc2d83f351eee5ee91df26bb0c7e1cb07fe328cbbcdb0bb9656d37922c497302201b3435d4c71ffd1b34d45892f2a487bd79c8c7f57cc04373287642bb9610cb840147304402202dc3eab30ccb06553703e794212f43ee9a659f5e787a8374e9ea0bf6de0def7402201a70e970c21a807783313ed102bf4f0a3406ac7c84f94bc8194c5e209464d7230147304402206b04530c190c46a879d7771a6ad53acd33547e0d7fd320d5ad0b5b1fdeb5d4c202207b812be81c3419daadc942cca0c55aa32c7759fa7566c6dc35f030ca87a1c5be01483045022100ce523dddd6eef73d5ae7c44c870466e1ac5a7a77d43475e8def024af68977a1e022028be0276435bfa2ea887d6cf89fa829f96c1c7a55edc57bb3fd667d523fd3bf601473044022019410b20ebcd8eb3ee7ec1eff6bf0f9cbfaea82116811c61f3cf24af7e4434b1022009e5823f3349f695be09ae40754185300d8442a22715ddb5ffa17c4213140e7201483045022100964ef26a9074c3cdafffcfbe4bd445933f8c842ba11fd887922adcf7fabe0c82022023055d94c75ab223c767fbaa825c917e9beecbc7d5758cccf20d886c63d4b72a0147304402207aa3a98197697d258a8baae681f0b4c0ee682982f4205534e6c95a37dabaddd60220517a7ed5c03da2f242e17ccfdae0d81d6f454d7f9ea931fc62df6c0eab922186014d01025f21023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43d210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a79022103fe91eca10602d7dad4c9dab2b2a0858f71e25a219a6940749ce7a48118480dae210234716c01c2dd03fa7ee302705e2b8fbd1311895d94b1dca15e62eedea9b0968f210341fb2ead334952cf60f4481ba435c4693d0be649be01d2cfe9b02018e483e7bd2102dad8b2bce360a705c16e74a50a36459b4f8f4b78f9cd67def29d54ef6f7c7cf9210222dbe3f5f197a34a1d50e2cbe2a1085cac2d605c9e176f9a240e0fd0c669330d2103fb41afab56c9cdb013fda63d777d4938ddc3cb2ad939712da688e3ed333f95982102435f177646bdc717cb3211bf46656ca7e8d642726144778c9ce816b8b8c36ccf2102158d8e20095364031d923c7e9f7f08a14b1be1ddee21fe1a5431168e31345e5521026259794892428ca0818c8fb61d2d459ddfe20e57f50803c7295e6f4e2f5586652102815f910a8689151db627e6e262e0a2075ad5ec2993a6bc1b876a9d420923d681210318f54647f645ff01bd49fedc0219343a6a22d3ea3180a3c3d3097e4b888a8db45faeffffffff0110270000000000001976a9144a087d89f8ad16ca029c675b037c02fd1c5f9aec88ac00000000" )
def test_two_zero_signature(self): self.setup_mnemonic_nopin_nopassphrase() inp1 = proto.TxInputType( address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e # amount=390000, prev_hash=TXHASH_d5f65e, prev_index=0, ) # Following address_n has been mined by 'test_mine_zero_signature' out1 = proto.TxOutputType( address_n=[16518], amount=390000 - 10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) _, serialized_tx = btc.sign_tx( self.client, "Bitcoin", [inp1], [out1], prev_txes=tx_cache("Bitcoin") ) siglen = serialized_tx[44] # TREZOR must strip leading zero from signature assert siglen == 66
def test_send_decred(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( # TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz address_n=parse_path("m/44'/1'/0'/0/0"), prev_hash=TXHASH_e16248, prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, decred_tree=0, ) out1 = proto.TxOutputType( address="TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz", amount=190000000, script_type=proto.OutputScriptType.PAYTOADDRESS, decred_script_version=0, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_e16248), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_e16248, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_e16248, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_e16248, request_index=1 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.FeeOverThreshold), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Decred Testnet", [inp1], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "0100000001edd579e9462ee0e80127a817e0500d4f942a4cf8f2d6530e0c0a9ab3f04862e10100000000ffffffff01802b530b0000000000001976a914819d291a2f7fbf770e784bfd78b5ce92c58e95ea88ac000000000000000001000000000000000000000000ffffffff6a473044022009e394c7dec76ab6988270b467839b1462ad781556bce37383b76e026418ce6302204f7f6ef535d2986b095d7c96232a0990a0b9ce3004894b39c167bb18e5833ac30121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0" )
def test_send_native_change(self, client): inp1 = proto.TxInputType( address_n=parse_path("84'/1'/0'/0/0"), amount=12300000, prev_hash=bytes.fromhex( "09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a" ), prev_index=0, script_type=proto.InputScriptType.SPENDWITNESS, ) out1 = proto.TxOutputType( address="2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp", amount=5000000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("84'/1'/0'/1/0"), script_type=proto.OutputScriptType.PAYTOWITNESS, amount=12300000 - 11000 - 5000000, ) with client: client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) _, serialized_tx = btc.sign_tx(client, "Testnet", [inp1], [out1, out2], prev_txes=TX_API) assert ( serialized_tx.hex() == "010000000001018a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090000000000ffffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987a8386f0000000000160014cc8067093f6f843d6d3e22004a4290cd0c0f336b024730440220067675423ca6a0be3ddd5e13da00a9433775041e5cebc838873d2686f1d2840102201a5819e0312e6451d6b6180689101bce995685a51524cc4c3a5383f7bdab979a012103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f86200000000" )
def test_send_p2sh(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("49'/156'/0'/1/0"), amount=123456789, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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 self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250000000017160014b5355d001e720d8f4513da00ff2bba4dcf9d39fcffffffff02e0aebb00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac3df39f06000000001976a914a8f757819ec6779409f45788f7b4a0e8f51ec50488ac02473044022073fcbf2876f073f78923ab427f14de5b2a0fbeb313a9b2b650b3567061f242a702202f45fc22c501108ff6222afe3aca7da9d8c7dc860f9cda335bef31fa184e7bef412102ecea08b559fc5abd009acf77cfae13fa8a3b1933e3e031956c65c12cec8ca3e300000000" )
def test_send_bch_multisig_change(self, client): nodes = [ btc.get_public_node(client, parse_path("48'/145'/%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'/145'/3'/0/0"), multisig=getmultisig(0, 0), amount=48490, prev_hash=TXHASH_8b6db9, prev_index=0, script_type=proto.InputScriptType.SPENDMULTISIG, ) out1 = proto.TxOutputType( address="bitcoincash:qqq8gx2j76nw4dfefumxmdwvtf2tpsjznusgsmzex9", amount=24000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("48'/145'/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(), ]) (signatures1, serialized_tx) = btc.sign_tx(client, "Bcash", [inp1], [out1, out2], prev_txes=TX_API) assert ( signatures1[0].hex() == "3045022100a05f77bb39515c21c43e6c4ba401f39ed5d409dc3cfcd90f9a8345a08cc4bc8202205faf8f3b0775748278495324fdd60f370460452e4995e546450209ec4804a0f3" ) inp1 = proto.TxInputType( address_n=parse_path("48'/145'/1'/0/0"), multisig=getmultisig(0, 0, [b"", b"", signatures1[0]]), # bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw amount=48490, prev_hash=TXHASH_8b6db9, 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(), ]) (signatures1, serialized_tx) = btc.sign_tx(client, "Bcash", [inp1], [out1, out2], prev_txes=TX_API) assert ( signatures1[0].hex() == "3044022006f239ef1f065a70873ab9d2c81a623a04ec7a37a0ec5299d3c585668f441f49022032b2f9ef13bc61230d14f6d79b9ad1bbebdf47b95e4757e9af1b1dcdf520d3ab" ) assert ( serialized_tx.hex() == "0100000001a07660b10df9868df9393c9cf8962bc34f48cb2cea53b0865d2324bab8b96d8b00000000fdfd0000473044022006f239ef1f065a70873ab9d2c81a623a04ec7a37a0ec5299d3c585668f441f49022032b2f9ef13bc61230d14f6d79b9ad1bbebdf47b95e4757e9af1b1dcdf520d3ab41483045022100a05f77bb39515c21c43e6c4ba401f39ed5d409dc3cfcd90f9a8345a08cc4bc8202205faf8f3b0775748278495324fdd60f370460452e4995e546450209ec4804a0f3414c69522102f8ca0d9665af03de32a7c19a167a4f6e97e4e0ed9505f75d11f7a45ab60b1f4d2103263d87cefd687bc15b4ef7801f9f538267b66d46f18e9fccc41d54071cfdd1ce210388568bf42f02298308eb6fa2fa4b446d544600253b4409be27e2c0c1a71c424853aeffffffff02c05d0000000000001976a91400741952f6a6eab5394f366db5cc5a54b0c2429f88acc05d00000000000017a91478574751407449b97f8054be2e40e684ad07d3738700000000" )
def test_send_p2sh_witness_change(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("49'/156'/0'/1/0"), amount=123456789, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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 self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) _, serialized_tx = btc.sign_tx(self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API) assert ( serialized_tx.hex() == "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250000000017160014b5355d001e720d8f4513da00ff2bba4dcf9d39fcffffffff02e0aebb00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac3df39f060000000017a9140cd03822b799a452c106d1b3771844a067b17f118702483045022100d79b33384c686d8dd40ad5f84f46691d30994992c1cb42e934c2a625d86cb2f902206859805a9a98ba140b71a9d4b9a6b8df94a9424f9c40f3bd804149fd6e278d63412102ecea08b559fc5abd009acf77cfae13fa8a3b1933e3e031956c65c12cec8ca3e300000000" )
def test_send_bch_change(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/145'/0'/0/0"), # bitcoincash:qr08q88p9etk89wgv05nwlrkm4l0urz4cyl36hh9sv amount=1995344, prev_hash=bytes.fromhex( "bc37c28dfb467d2ecb50261387bf752a3977d7e5337915071bb4151e6b711a78" ), prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=parse_path("44'/145'/0'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address="bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4", amount=73452, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Bcash", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "0100000001781a716b1e15b41b07157933e5d777392a75bf87132650cb2e7d46fb8dc237bc000000006a473044022061aee4f17abe044d5df8c52c9ffd3b84e5a29743517e488b20ecf1ae0b3e4d3a02206bb84c55e407f3b684ff8d9bea0a3409cfd865795a19d10b3d3c31f12795c34a412103a020b36130021a0f037c1d1a02042e325c0cb666d6478c1afdcd9d913b9ef080ffffffff0272ee1c00000000001976a914b1401fce7e8bf123c88a0467e0ed11e3b9fbef5488acec1e0100000000001976a914d51eca49695cdf47e7f4b55507893e3ad53fe9d888ac00000000" )
def test_2_of_3(self): self.setup_mnemonic_nopin_nopassphrase() # key1 = self.client.get_public_node([1]) # key2 = self.client.get_public_node([2]) # key3 = self.client.get_public_node([3]) # xpub: # print(bip32.serialize(self.client.get_public_node([]).node)) # xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy # pubkeys: # xpub/1: 0338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6 # xpub/2: 038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3 # xpub/3: 03477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a7902 # redeem script: # 52210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a790253ae # multisig address: 3E7GDtuHqnqPmDgwH59pVC7AvySiSkbibz # tx: c6091adf4c0c23982a35899a6e58ae11e703eacd7954f588ed4b9cdefc4dba52 # input 1: 0.001 BTC node = bip32.deserialize( "xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy" ) multisig = proto.MultisigRedeemScriptType( pubkeys=[ proto.HDNodePathType(node=node, address_n=[1]), proto.HDNodePathType(node=node, address_n=[2]), proto.HDNodePathType(node=node, address_n=[3]), ], signatures=[b"", b"", b""], m=2, ) # Let's go to sign with key 1 inp1 = proto.TxInputType( address_n=[1], prev_hash=TXHASH_c6091a, prev_index=1, script_type=proto.InputScriptType.SPENDMULTISIG, multisig=multisig, ) out1 = proto.TxOutputType( address="12iyMbUb4R2K3gre4dHSrbu5azG5KaqVss", amount=100000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_c6091a), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_c6091a ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_c6091a ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=TXHASH_c6091a ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) # Now we have first signature (signatures1, _) = btc.sign_tx(self.client, "Bitcoin", [inp1], [out1]) assert ( hexlify(signatures1[0]) == b"3045022100985cc1ba316d140eb4b2d4028d8cd1c451f87bff8ff679858732e516ad04cd3402207af6edda99972af0baa7702a3b7448517c8242e7bca669f6861771cdd16ee058" ) # --------------------------------------- # Let's do second signature using 3rd key multisig = proto.MultisigRedeemScriptType( pubkeys=[ proto.HDNodePathType(node=node, address_n=[1]), proto.HDNodePathType(node=node, address_n=[2]), proto.HDNodePathType(node=node, address_n=[3]), ], signatures=[ signatures1[0], b"", b"", ], # Fill signature from previous signing process m=2, ) # Let's do a second signature with key 3 inp3 = proto.TxInputType( address_n=[3], prev_hash=TXHASH_c6091a, prev_index=1, script_type=proto.InputScriptType.SPENDMULTISIG, multisig=multisig, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_c6091a), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_c6091a ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_c6091a ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=TXHASH_c6091a ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) (signatures2, serialized_tx) = btc.sign_tx( self.client, "Bitcoin", [inp3], [out1] ) assert ( hexlify(signatures2[0]) == b"3045022100f5428fe0531b3095675b40d87cab607ee036fac823b22e8dcec35b65aff6e52b022032129b4577ff923d321a1c70db5a6cec5bcc142cb2c51901af8b989cced23e0d" ) # Accepted by network: tx 8382a2b2e3ec8788800c1d46d285dfa9dd4051edddd75982fad166b9273e5ac6 assert ( hexlify(serialized_tx) == b"010000000152ba4dfcde9c4bed88f55479cdea03e711ae586e9a89352a98230c4cdf1a09c601000000fdfe0000483045022100985cc1ba316d140eb4b2d4028d8cd1c451f87bff8ff679858732e516ad04cd3402207af6edda99972af0baa7702a3b7448517c8242e7bca669f6861771cdd16ee05801483045022100f5428fe0531b3095675b40d87cab607ee036fac823b22e8dcec35b65aff6e52b022032129b4577ff923d321a1c70db5a6cec5bcc142cb2c51901af8b989cced23e0d014c6952210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a790253aeffffffff01a0860100000000001976a91412e8391ad256dcdc023365978418d658dfecba1c88ac00000000" )
def test_one_one_fee_sapling(self): self.setup_mnemonic_allallall() # prevout: 339c3e78610e229f65ebc3fa722016fcb9fbde7bc196d2d876604f5257ada19c:0 # input 1: 2.9999 KMD inp1 = proto.TxInputType( address_n=parse_path( "m/Komodo/0h/0/0" ), # RDvyC66RQf7HKkUB5zyLKJhitV4ibzkKF5 amount=299990000, prev_hash=TXHASH_339c3e, prev_index=0, ) out1 = proto.TxOutputType( address="RDvyC66RQf7HKkUB5zyLKJhitV4ibzkKF5", amount=299990000 - 10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) details = proto.SignTx( version=4, overwintered=True, version_group_id=0x892F2085, branch_id=0x76B809BB, lock_time=0x5C5CE16B, ) _, serialized_tx = btc.sign_tx( self.client, "Komodo", [inp1], [out1], details=details, prev_txes=TX_API ) # Accepted by network: tx 92b45f54cb7c3cdfc4a88dbf088dfcc7c1417ad0955f02712e136da7fd5343d6 assert ( serialized_tx.hex() == "0400008085202f89019ca1ad57524f6076d8d296c17bdefbb9fc162072fac3eb659f220e61783e9c33000000006a47304402206972af8ff4dec4074da9edb1a741114bebda9e686bb411dd6f388aafd81f0af2022060a05d0ea66d5b8632868b6a6d377ad1a8941385d628be4631b31cc246014b8501210235ad92bb4efda1e6794890f248fa26aab75906bd496c07a6a8532b62a5bd80f7ffffffff01e054e111000000001976a91433058d6bb20e9297fc0a518e2e0262e854496a6c88ac6be15c5c000000000000000000000000000000" )
def test_attack_amount(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/145'/0'/1/0"), # bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw amount=300, prev_hash=bytes.fromhex( "502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c" ), 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=bytes.fromhex( "502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c" ), 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 self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) btc.sign_tx(self.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 self.client.set_filter(proto.TxAck, attack_processor) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.Failure(), ] ) with pytest.raises(CallException) as exc: btc.sign_tx( self.client, "Bcash", [inp1, inp2], [out1], prev_txes=TX_API ) assert exc.value.args[0] in ( proto.FailureType.ProcessError, proto.FailureType.DataError, ) assert exc.value.args[1].endswith("Transaction has changed during signing")
def test_send_p2sh_change(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("49'/1'/0'/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX amount=123456789, prev_hash=bytes.fromhex( "20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337" ), prev_index=0, script_type=proto.InputScriptType.SPENDP2SHWITNESS, ) out1 = proto.TxOutputType( address="tb1qqzv60m9ajw8drqulta4ld4gfx0rdh82un5s65s", amount=12300000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("49'/1'/0'/1/0"), script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, amount=123456789 - 11000 - 12300000, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Testnet", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001600140099a7ecbd938ed1839f5f6bf6d50933c6db9d5c3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100bd3d8b8ad35c094e01f6282277300e575f1021678fc63ec3f9945d6e35670da3022052e26ef0dd5f3741c9d5939d1dec5464c15ab5f2c85245e70a622df250d4eb7c012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000" )
def test_send_multisig_4_change(self): self.setup_mnemonic_allallall() nodes = [ btc.get_public_node(self.client, parse_path("49'/1'/%d'" % index)) for index in range(1, 4) ] multisig = proto.MultisigRedeemScriptType( nodes=[deserialize(n.xpub) for n in nodes], address_n=[1, 1], signatures=[b"", b"", b""], m=2, ) multisig2 = proto.MultisigRedeemScriptType( nodes=[deserialize(n.xpub) for n in nodes], address_n=[1, 2], signatures=[b"", b"", b""], m=2, ) inp1 = proto.TxInputType( address_n=parse_path("49'/1'/1'/1/1"), prev_hash=bytes.fromhex( "31bc1c88ce6ae337a6b3057a16d5bad0b561ad1dfc047d0a7fbb8814668f91e5" ), prev_index=0, script_type=proto.InputScriptType.SPENDP2SHWITNESS, multisig=multisig, amount=1603000, ) out1 = proto.TxOutputType( address_n=parse_path("49'/1'/1'/1/2"), amount=1602000, multisig=multisig2, script_type=proto.OutputScriptType.PAYTOWITNESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) signatures, _ = btc.sign_tx( self.client, "Testnet", [inp1], [out1], prev_txes=TX_API ) # store signature inp1.multisig.signatures[0] = signatures[0] # sign with third key inp1.address_n[2] = H_(3) out1.address_n[2] = H_(3) self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Testnet", [inp1], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "01000000000101e5918f661488bb7f0a7d04fc1dad61b5d0bad5167a05b3a637e36ace881cbc310000000023220020fa6c73de618ec134eeec0c16f6dd04d46d4347e9a4fd0a95fd7938403a4949f9ffffffff01d071180000000000220020bcea2324dacbcde5a9db90cc26b8df9cbc72010e05cb68cf034df6f0e05239a2040047304402206bbddb45f12e31e77610fd85b50a83bad4426433b1c4860b1c5ddc0a69f803720220087b0607daab14830f4b4941f16b953b38e606ad70029bac24af7267f93c4242014730440220551a0cb6b0d5b3fa0cfd0b07bb5d751494b827b1c6a08702186696cfbc18278302204f37c382876c4117cca656654599b508f2d55fc3b083dc938e3cd8491b29719601695221036a5ec3abd10501409092246fe59c6d7a15fff1a933479483c3ba98b866c5b9742103559be875179d44e438db2c74de26e0bc9842cbdefd16018eae8a2ed989e474722103067b56aad037cd8b5f569b21f9025b76470a72dc69457813d2b76e98dc0cd01a53ae00000000" )
def test_send_multisig_3_change(self): self.setup_mnemonic_allallall() nodes = [ btc.get_public_node(self.client, parse_path("84'/1'/%d'" % index)) for index in range(1, 4) ] multisig = proto.MultisigRedeemScriptType( nodes=[deserialize(n.xpub) for n in nodes], address_n=[1, 0], signatures=[b"", b"", b""], m=2, ) multisig2 = proto.MultisigRedeemScriptType( nodes=[deserialize(n.xpub) for n in nodes], address_n=[1, 1], signatures=[b"", b"", b""], m=2, ) inp1 = proto.TxInputType( address_n=parse_path("84'/1'/1'/1/0"), prev_hash=bytes.fromhex( "c9348040bbc2024e12dcb4a0b4806b0398646b91acf314da028c3f03dd0179fc" ), prev_index=0, script_type=proto.InputScriptType.SPENDWITNESS, multisig=multisig, amount=1604000, ) out1 = proto.TxOutputType( address_n=parse_path("84'/1'/1'/1/1"), amount=1603000, multisig=multisig2, script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) signatures, _ = btc.sign_tx( self.client, "Testnet", [inp1], [out1], prev_txes=TX_API ) # store signature inp1.multisig.signatures[0] = signatures[0] # sign with third key inp1.address_n[2] = H_(3) out1.address_n[2] = H_(3) self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Testnet", [inp1], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "01000000000101fc7901dd033f8c02da14f3ac916b6498036b80b4a0b4dc124e02c2bb408034c90000000000ffffffff01b87518000000000017a914536250d41937e5b641082447580ff6a8e46c122a870400473044022003c26107a5a47f1f900ef8aa758977530cd13ea37a33971abae8d75cac2f9f34022039e2b8c2c1d0c24ff4fc026652e1f27ad8e3ed6c9bf485f61d9aa691cb57830801483045022100963b0dc0ab46e963a66ab6e69e5e41bac6c4fedc127cac12c560b029d54fe87402205b3bcdcf313dccd78e5dce0540e7d3c8cc1bf83f13c1f9f01811eb791fd35c8101695221039dba3a72f5dc3cad17aa924b5a03c34561465f997d0cb15993f2ca2c0be771c42103cd39f3f08bbd508dce4d307d57d0c70c258c285878bfda579fa260acc738c25d2102cd631ba95beca1d64766f5540885092d0bb384a3c13b6c3a5334d0ebacf51b9553ae00000000" )
def test_send_multisig_2(self): self.setup_mnemonic_allallall() nodes = [ btc.get_public_node(self.client, parse_path("84'/1'/%d'" % index)) for index in range(1, 4) ] multisig = proto.MultisigRedeemScriptType( nodes=[deserialize(n.xpub) for n in nodes], address_n=[0, 1], signatures=[b"", b"", b""], m=2, ) inp1 = proto.TxInputType( address_n=parse_path("84'/1'/2'/0/1"), prev_hash=bytes.fromhex( "f41cbedd8becee05a830f418d13aa665125464547db5c7a6cd28f21639fe1228" ), prev_index=0, script_type=proto.InputScriptType.SPENDWITNESS, multisig=multisig, amount=1605000, ) out1 = proto.TxOutputType( address="tb1qr6xa5v60zyt3ry9nmfew2fk5g9y3gerkjeu6xxdz7qga5kknz2ssld9z2z", amount=1604000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) signatures, _ = btc.sign_tx( self.client, "Testnet", [inp1], [out1], prev_txes=TX_API ) # store signature inp1.multisig.signatures[1] = signatures[0] # sign with first key inp1.address_n[2] = H_(1) self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Testnet", [inp1], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "010000000001012812fe3916f228cda6c7b57d5464541265a63ad118f430a805eeec8bddbe1cf40000000000ffffffff01a0791800000000002200201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a10400473044022001b7f4f21a8ddcd5e0faaaee3b95515bf8b84f2a7cbfdf66996c64123617a5cf02202fc6a776a7225420dbca759ad4ac83a61d15bf8d2883b6bf1aa31de7437f9b6e0147304402206c4125c1189a3b3e93a77cdf54c60c0538b80e5a03ec74e6ac776dfa77706ee4022035be14de76259b9d8a24863131a06a65b95df02f7d3ace90d52b37e8d94b167f0169522103bab8ecdd9ae2c51a0dc858f4c751b27533143bf6013ba1725ba8a4ecebe7de8c21027d5e55696c875308b03f2ca3d8637f51d3e35da9456a5187aa14b3de8a89534f2103b78eabaea8b3a4868be4f4bb96d6f66973f7081faa7f1cafba321444611c241e53ae00000000" )
def test_attack_change_input(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/145'/10'/0/0"), amount=1995344, prev_hash=bytes.fromhex( "bc37c28dfb467d2ecb50261387bf752a3977d7e5337915071bb4151e6b711a78" ), prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=parse_path("44'/145'/10'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address="bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4", 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 not run_attack: run_attack = True else: msg.tx.inputs[0].address_n[2] = H_(1) return msg self.client.set_filter(proto.TxAck, attack_processor) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.Failure(code=proto.FailureType.ProcessError), ] ) with pytest.raises(CallException): btc.sign_tx( self.client, "Bcash", [inp1], [out1, out2], prev_txes=TX_API )
def test_one_one_rewards_claim(self, client): # prevout: 7b28bd91119e9776f0d4ebd80e570165818a829bbf4477cd1afe5149dbcd34b1:0 # input 1: 10.9997 KMD inp1 = proto.TxInputType( # R9HgJZo6JBKmPvhm7whLSR8wiHyZrEDVRi address_n=parse_path("44'/141'/0'/0/0"), amount=1099970000, prev_hash=TXHASH_7b28bd, prev_index=0, ) out1 = proto.TxOutputType( address="R9HgJZo6JBKmPvhm7whLSR8wiHyZrEDVRi", amount=1099970000 - 10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) # kmd interest, vout sum > vin sum out2 = proto.TxOutputType( address="R9HgJZo6JBKmPvhm7whLSR8wiHyZrEDVRi", amount=79605, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with client: client.set_expected_responses([ 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), proto.ButtonRequest(code=B.ConfirmOutput), request_output(1), proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.SignTx), proto.ButtonRequest(code=B.SignTx), request_input(0), request_output(0), request_output(1), request_finished(), ]) details = proto.SignTx( version=4, version_group_id=0x892F2085, branch_id=0x76B809BB, lock_time=0x5D2AF1F2, ) _, serialized_tx = btc.sign_tx( client, "Komodo", [inp1], [out1, out2], details=details, prev_txes=TX_API, ) # Accepted by network: tx c775678ceb18277729b427c7acf2f8ce63ac02fc2366f47ce08a3f443ff0e059 assert ( serialized_tx.hex() == "0400008085202f8901b134cddb4951fe1acd7744bf9b828a816501570ed8ebd4f076979e1191bd287b000000006a4730440220483a58f5be3a147c773c663008c992a7fcea4d03bdf4c1d4bc0535c0d98ddf0602207b19d69140dd00c7a94f048c712aeaed55dfd27f581c7212d9cc5e476fe1dc9f012102a87aef7b1a8f676e452d6240767699719cd58b0261c822472c25df146938bca5ffffffff02c00e9041000000001976a91400178fa0b6fc253a3a402ee2cadd8a7bfec08f6388acf5360100000000001976a91400178fa0b6fc253a3a402ee2cadd8a7bfec08f6388acf2f12a5d000000000000000000000000000000" )
def test_send_bch_multisig_wrongchange(self): self.setup_mnemonic_allallall() xpubs = [] for n in map( lambda index: btc.get_public_node( self.client, parse_path("48'/145'/%d'" % index) ), range(1, 4), ): xpubs.append(n.xpub) def getmultisig(chain, nr, signatures=[b"", b"", b""], xpubs=xpubs): return proto.MultisigRedeemScriptType( nodes=[deserialize(xpub) for xpub in xpubs], address_n=[chain, nr], signatures=signatures, m=2, ) correcthorse = proto.HDNodeType( depth=1, fingerprint=0, child_num=0, chain_code=bytes.fromhex( "0000000000000000000000000000000000000000000000000000000000000000" ), public_key=bytes.fromhex( "0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71" ), ) sig = bytes.fromhex( "304402207274b5a4d15e75f3df7319a375557b0efba9b27bc63f9f183a17da95a6125c94022000efac57629f1522e2d3958430e2ef073b0706cfac06cce492651b79858f09ae" ) inp1 = proto.TxInputType( address_n=parse_path("48'/145'/1'/1/0"), multisig=getmultisig(1, 0, [b"", sig, b""]), # bitcoincash:pp6kcpkhua7789g2vyj0qfkcux3yvje7euhyhltn0a amount=24000, prev_hash=bytes.fromhex( "f68caf10df12d5b07a34601d88fa6856c6edcbf4d05ebef3486510ae1c293d5f" ), prev_index=1, script_type=proto.InputScriptType.SPENDMULTISIG, ) out1 = proto.TxOutputType( address_n=parse_path("48'/145'/1'/1/1"), multisig=proto.MultisigRedeemScriptType( pubkeys=[ proto.HDNodePathType(node=deserialize(xpubs[0]), address_n=[1, 1]), proto.HDNodePathType(node=correcthorse, address_n=[]), proto.HDNodePathType(node=correcthorse, address_n=[]), ], signatures=[b"", b"", b""], m=2, ), script_type=proto.OutputScriptType.PAYTOMULTISIG, amount=23000, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) (signatures1, serialized_tx) = btc.sign_tx( self.client, "Bcash", [inp1], [out1], prev_txes=TX_API ) assert ( signatures1[0].hex() == "304402201badcdcafef4855ed58621f95935efcbc72068510472140f4ec5e252faa0af93022003310a43488288f70aedee96a5af2643a255268a6858cda9ae3001ea5e3c7557" ) assert ( serialized_tx.hex() == "01000000015f3d291cae106548f3be5ed0f4cbedc65668fa881d60347ab0d512df10af8cf601000000fc0047304402201badcdcafef4855ed58621f95935efcbc72068510472140f4ec5e252faa0af93022003310a43488288f70aedee96a5af2643a255268a6858cda9ae3001ea5e3c75574147304402207274b5a4d15e75f3df7319a375557b0efba9b27bc63f9f183a17da95a6125c94022000efac57629f1522e2d3958430e2ef073b0706cfac06cce492651b79858f09ae414c69522102245739b55787a27228a4fe78b3a324366cc645fbaa708cad45da351a334341192102debbdcb0b6970d5ade84a50fdbda1c701cdde5c9925d9b6cd8e05a9a15dbef352102ffe5fa04547b2b0c3cfbc21c08a1ddfb147025fee10274cdcd5c1bdeee88eae253aeffffffff01d85900000000000017a914a23eb2a1ed4003d357770120f5c370e199ee55468700000000" )
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_send_bch_multisig_change(self): self.setup_mnemonic_allallall() xpubs = [] for n in map( lambda index: btc.get_public_node( self.client, parse_path("48'/145'/%d'" % index) ), range(1, 4), ): xpubs.append(n.xpub) def getmultisig(chain, nr, signatures=[b"", b"", b""], xpubs=xpubs): return proto.MultisigRedeemScriptType( nodes=[deserialize(xpub) for xpub in xpubs], address_n=[chain, nr], signatures=signatures, m=2, ) inp1 = proto.TxInputType( address_n=parse_path("48'/145'/3'/0/0"), multisig=getmultisig(0, 0), amount=48490, prev_hash=bytes.fromhex( "8b6db9b8ba24235d86b053ea2ccb484fc32b96f89c3c39f98d86f90db16076a0" ), prev_index=0, script_type=proto.InputScriptType.SPENDMULTISIG, ) out1 = proto.TxOutputType( address="bitcoincash:qqq8gx2j76nw4dfefumxmdwvtf2tpsjznusgsmzex9", amount=24000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("48'/145'/3'/1/0"), multisig=getmultisig(1, 0), script_type=proto.OutputScriptType.PAYTOMULTISIG, amount=24000, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) (signatures1, serialized_tx) = btc.sign_tx( self.client, "Bcash", [inp1], [out1, out2], prev_txes=TX_API ) assert ( signatures1[0].hex() == "3045022100a05f77bb39515c21c43e6c4ba401f39ed5d409dc3cfcd90f9a8345a08cc4bc8202205faf8f3b0775748278495324fdd60f370460452e4995e546450209ec4804a0f3" ) inp1 = proto.TxInputType( address_n=parse_path("48'/145'/1'/0/0"), multisig=getmultisig(0, 0, [b"", b"", signatures1[0]]), # bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw amount=48490, prev_hash=bytes.fromhex( "8b6db9b8ba24235d86b053ea2ccb484fc32b96f89c3c39f98d86f90db16076a0" ), prev_index=0, script_type=proto.InputScriptType.SPENDMULTISIG, ) out2.address_n[2] = H_(1) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) (signatures1, serialized_tx) = btc.sign_tx( self.client, "Bcash", [inp1], [out1, out2], prev_txes=TX_API ) assert ( signatures1[0].hex() == "3044022006f239ef1f065a70873ab9d2c81a623a04ec7a37a0ec5299d3c585668f441f49022032b2f9ef13bc61230d14f6d79b9ad1bbebdf47b95e4757e9af1b1dcdf520d3ab" ) assert ( serialized_tx.hex() == "0100000001a07660b10df9868df9393c9cf8962bc34f48cb2cea53b0865d2324bab8b96d8b00000000fdfd0000473044022006f239ef1f065a70873ab9d2c81a623a04ec7a37a0ec5299d3c585668f441f49022032b2f9ef13bc61230d14f6d79b9ad1bbebdf47b95e4757e9af1b1dcdf520d3ab41483045022100a05f77bb39515c21c43e6c4ba401f39ed5d409dc3cfcd90f9a8345a08cc4bc8202205faf8f3b0775748278495324fdd60f370460452e4995e546450209ec4804a0f3414c69522102f8ca0d9665af03de32a7c19a167a4f6e97e4e0ed9505f75d11f7a45ab60b1f4d2103263d87cefd687bc15b4ef7801f9f538267b66d46f18e9fccc41d54071cfdd1ce210388568bf42f02298308eb6fa2fa4b446d544600253b4409be27e2c0c1a71c424853aeffffffff02c05d0000000000001976a91400741952f6a6eab5394f366db5cc5a54b0c2429f88acc05d00000000000017a91478574751407449b97f8054be2e40e684ad07d3738700000000" )
def test_send_btg_multisig_change(self): self.setup_mnemonic_allallall() xpubs = [] for n in map( lambda index: btc.get_public_node( self.client, parse_path("44'/156'/%d'" % index)), range(1, 4), ): xpubs.append(n.xpub) def getmultisig(chain, nr, signatures=[b"", b"", b""], xpubs=xpubs): return proto.MultisigRedeemScriptType( pubkeys=list( map( lambda xpub: proto.HDNodePathType( node=deserialize(xpub), address_n=[chain, nr]), xpubs, )), signatures=signatures, m=2, ) inp1 = proto.TxInputType( address_n=parse_path("44'/156'/3'/0/0"), multisig=getmultisig(0, 0), # 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R amount=48490, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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("44'/156'/3'/1/0"), multisig=getmultisig(1, 0), script_type=proto.OutputScriptType.PAYTOMULTISIG, amount=24000, ) with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) signatures, serialized_tx = btc.sign_tx(self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API) assert ( signatures[0].hex() == "3045022100b1594f3b186d0dedbf61e53a1c407b1e0747098b7375941df85af045040f578e022013ba1893eb9e2fd854dd07073a83b261cf4beba76f66b07742e462b4088a7e4a" ) inp1 = proto.TxInputType( address_n=parse_path("44'/156'/1'/0/0"), multisig=getmultisig(0, 0, [b"", b"", signatures[0]]), # 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R amount=48490, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), prev_index=0, script_type=proto.InputScriptType.SPENDMULTISIG, ) out2.address_n[2] = H_(1) with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) signatures, serialized_tx = btc.sign_tx(self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API) assert ( signatures[0].hex() == "3044022006da8dbd14e6656ac8dcb956f4c0498574e88680eaeceb2cbafd8d2b2329d8cc02200972d076d444c5ff8f2ab18e14d8249ab661cb9c53335039bedcde037a40d747" ) assert ( serialized_tx.hex() == "010000000185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b522500000000fdfd0000473044022006da8dbd14e6656ac8dcb956f4c0498574e88680eaeceb2cbafd8d2b2329d8cc02200972d076d444c5ff8f2ab18e14d8249ab661cb9c53335039bedcde037a40d74741483045022100b1594f3b186d0dedbf61e53a1c407b1e0747098b7375941df85af045040f578e022013ba1893eb9e2fd854dd07073a83b261cf4beba76f66b07742e462b4088a7e4a414c69522102290e6649574d17938c1ecb959ae92954f9ee48e1bd5b73f35ea931a3ab8a6087210379e0107b173e2c143426760627128c5eea3f862e8df92f3c2558eeeae4e347842103ff1746ca7dcf9e5c2eea9a73779b7c5bafed549f45cf3638a94cdf1e89c7f28f53aeffffffff02c05d0000000000001976a914ea5f904d195079a350b534db4446433b3cec222e88acc05d00000000000017a91445e917e46815d2b38d3f1cf072e63dd4f3b7a7e38700000000" )
def test_send_bch_nochange(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/145'/0'/1/0"), # bitcoincash:qzc5q87w069lzg7g3gzx0c8dz83mn7l02scej5aluw amount=1896050, prev_hash=bytes.fromhex( "502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c" ), prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) inp2 = proto.TxInputType( address_n=parse_path("44'/145'/0'/0/1"), # bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4 amount=73452, prev_hash=bytes.fromhex( "502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c" ), prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address="bitcoincash:qq6wnnkrz7ykaqvxrx4hmjvayvzjzml54uyk76arx4", amount=1934960, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Bcash", [inp1, inp2], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "01000000022c06cf6f215c5cbfd7caa8e71b1b32630cabf1f816a4432815b037b277852e50000000006a47304402207a2a955f1cb3dc5f03f2c82934f55654882af4e852e5159639f6349e9386ec4002205fb8419dce4e648eae8f67bc4e369adfb130a87d2ea2d668f8144213b12bb457412103174c61e9c5362507e8061e28d2c0ce3d4df4e73f3535ae0b12f37809e0f92d2dffffffff2c06cf6f215c5cbfd7caa8e71b1b32630cabf1f816a4432815b037b277852e50010000006a473044022062151cf960b71823bbe68c7ed2c2a93ad1b9706a30255fddb02fcbe056d8c26102207bad1f0872bc5f0cfaf22e45c925c35d6c1466e303163b75cb7688038f1a5541412102595caf9aeb6ffdd0e82b150739a83297358b9a77564de382671056ad9e5b8c58ffffffff0170861d00000000001976a91434e9cec317896e818619ab7dc99d2305216ff4af88ac00000000" )
def test_send_bitcoin_gold_nochange(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/156'/0'/1/0"), amount=1896050, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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=bytes.fromhex( "db77c2461b840e6edbe7f9280043184a98e020d9795c1b65cb7cef2551a8fb18" ), prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=1934960, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) _, serialized_tx = btc.sign_tx(self.client, "Bgold", [inp1, inp2], [out1], prev_txes=TX_API) assert ( serialized_tx.hex() == "010000000285c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b5225000000006b483045022100928852076c9fab160c07564cd54691af1cbc37fb28f0b7bee7299c7925ef62f0022058856387afecc6508f2f04ecdfd292a13026a5b2107ebdd2cc789bdf8820d552412102a6c3998d0d4e5197ff41aab5c53580253b3b91f583f4c31f7624be7dc83ce15fffffffff18fba85125ef7ccb651b5c79d920e0984a18430028f9e7db6e0e841b46c277db010000006b483045022100faa2f4f01cc95e680349a093923aae0aa2ea01429873555aa8a84bf630ef33a002204c3f4bf567e2d20540c0f71dc278481d6ccb6b95acda2a2f87ce521c79d6b872412102d54a7e5733b1635e5e9442943f48179b1700206b2d1925250ba10f1c86878be8ffffffff0170861d00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac00000000" )
def test_send_dash_dip2_input(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/5'/0'/0/0"), # dash:XdTw4G5AWW4cogGd7ayybyBNDbuB45UpgH amount=4095000260, prev_hash=bytes.fromhex( "15575a1c874bd60a819884e116c42e6791c8283ce1fc3b79f0d18531a61bbb8a" ), prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=parse_path("44'/5'/0'/1/0"), amount=4000000000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address="XrEFMNkxeipYHgEQKiJuqch8XzwrtfH5fm", amount=95000000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=inp1.prev_hash), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=inp1.prev_hash ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=inp1.prev_hash ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=inp1.prev_hash ), ), proto.TxRequest( request_type=proto.RequestType.TXEXTRADATA, details=proto.TxRequestDetailsType( extra_data_len=39, extra_data_offset=0, tx_hash=inp1.prev_hash, ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Dash", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "01000000018abb1ba63185d1f0793bfce13c28c891672ec416e18498810ad64b871c5a5715010000006b483045022100f0442b6d9c7533cd6f74afa993b280ed9475276d69df4dac631bc3b5591ba71b022051daf125372c1c477681bbd804a6445d8ff6840901854fb0b485b1c6c7866c44012102936f80cac2ba719ddb238646eb6b78a170a55a52a9b9f08c43523a4a6bd5c896ffffffff0200286bee000000001976a914fd61dd017dad1f505c0511142cc9ac51ef3a5beb88acc095a905000000001976a914aa7a6a1f43dfc34d17e562ce1845b804b73fc31e88ac00000000" )
def test_send_btg_multisig_change(self): self.setup_mnemonic_allallall() xpubs = [] for n in map( lambda index: btc.get_public_node( self.client, parse_path("48'/156'/%d'" % index) ), range(1, 4), ): xpubs.append(n.xpub) def getmultisig(chain, nr, signatures=[b"", b"", b""], xpubs=xpubs): return proto.MultisigRedeemScriptType( nodes=[deserialize(xpub) for xpub in xpubs], 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=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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 self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) signatures, serialized_tx = btc.sign_tx( self.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=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), prev_index=0, script_type=proto.InputScriptType.SPENDMULTISIG, ) out2.address_n[2] = H_(1) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) signatures, serialized_tx = btc.sign_tx( self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API ) assert ( signatures[0].hex() == "30440220614f9a18695365a2edba0d930404a77cae970d3430ad86c5b5239a96fd54bf84022030bc76a322e3b2b1c987622b5eb6da23ac1e6c905ee9b3b6405a4e4edd5bbb87" ) assert ( serialized_tx.hex() == "010000000185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b522500000000fdfd00004730440220614f9a18695365a2edba0d930404a77cae970d3430ad86c5b5239a96fd54bf84022030bc76a322e3b2b1c987622b5eb6da23ac1e6c905ee9b3b6405a4e4edd5bbb8741483045022100d954f341ddd3ec96e4bc6cdb90f2df9b2032723f85e4a0187346dd743130bfca0220105ce08b795c70dc09a55569d7874bff684a877219ec2fc37c88cdffe12f332c414c695221035a8db79c0ef57a202664a3da60ca41e8865c6d86ed0aafc03f8e75173341b58021037fba152d8fca660cc49973d8bc9421ff49a75b44ea200873d70d3990f763ed4c210348cbcbd93e069416e0d5db93e86b5698852d9fd54502ad0bed9722fa83f90e4b53aeffffffff02c05d0000000000001976a914ea5f904d195079a350b534db4446433b3cec222e88acc05d00000000000017a914623c803f7fb654dac8dda7786fbf9bc38cd867f48700000000" )
def test_send_dash(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/5'/0'/0/0"), # dash:XdTw4G5AWW4cogGd7ayybyBNDbuB45UpgH amount=1000000000, prev_hash=bytes.fromhex( "5579eaa64b2a0233e7d8d037f5a5afc957cedf48f1c4067e9e33ca6df22ab04f" ), prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address="XpTc36DPAeWmaueNBA9JqCg2GC8XDLKSYe", amount=999999000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=inp1.prev_hash), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=inp1.prev_hash ), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=inp1.prev_hash ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=inp1.prev_hash ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=inp1.prev_hash ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Dash", [inp1], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "01000000014fb02af26dca339e7e06c4f148dfce57c9afa5f537d0d8e733022a4ba6ea7955010000006a4730440220387be4d1e4b5e355614091416373e99e1a3532b8cc9a8629368060aff2681bdb02200a0c4a5e9eb2ce6adb6c2e01ec8f954463dcc04f531ed8a89a2b40019d5aeb0b012102936f80cac2ba719ddb238646eb6b78a170a55a52a9b9f08c43523a4a6bd5c896ffffffff0118c69a3b000000001976a9149710d6545407e78c326aa8c8ae386ec7f883b0af88ac00000000" )
def test_send_multisig_1(self): self.setup_mnemonic_allallall() nodes = map( lambda index: btc.get_public_node( self.client, parse_path("49'/156'/%d'" % index) ), range(1, 4), ) multisig = proto.MultisigRedeemScriptType( nodes=[deserialize(n.xpub) for n in 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=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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 self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) signatures, _ = btc.sign_tx( self.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) self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Bgold", [inp1], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250100000023220020ea9ec48498c451286c2ebaf9e19255e2873b0fb517d67b2f2005298c7e437829ffffffff01887d1800000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac0400473044022077cb8b2a534f79328810ca8c330539ae9ffa086c359ddb7da11026557b04eef202201d95be0dd1da0aa01720953e52d5dabffd19a998d1490c13a21b8e52e4ead2e041483045022100e41cbd6a501ba8fe6f65554420e23e950d35af0da9b052da54a087463b0717ca02206c695c8d1f74f9535b5d89a2fd1f9326a0ef20e5400137f1e1daeee992b62b594169522103279aea0b253b144d1b2bb8532280001a996dcddd04f86e5e13df1355032cbc1321032c6465c956c0879663fa8be974c912d229c179a5cdedeb29611a1bec1f951eb22103494480a4b72101cbd2eadac8e18c7a3a7589a7f576bf46b8971c38c51e5eceeb53ae00000000" )
def test_one_one_fee_overwinter(self): self.setup_mnemonic_allallall() # prevout: aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc:1 # input 1: 3.0 TAZ inp1 = proto.TxInputType( address_n=parse_path( "m/Zcash Testnet/0h/0/0" ), # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu amount=300000000, prev_hash=TXHASH_aaf51e, prev_index=1, ) out1 = proto.TxOutputType( address="tmJ1xYxP8XNTtCoDgvdmQPSrxh5qZJgy65Z", amount=300000000 - 1940, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) details = proto.SignTx( version=3, overwintered=True, version_group_id=0x3C48270, branch_id=0x5BA81B19, ) _, serialized_tx = btc.sign_tx( self.client, "Zcash Testnet", [inp1], [out1], details=details, prev_txes=TX_API, ) # Accepted by network: tx eda9b772c47f0c29310759960e0081c98707aa67a0a2738bcc71439fcf360675 assert ( serialized_tx.hex() == "030000807082c40301dc754d63eff4698ee321476872519c53f14cfe58c9425c7ee464c206461ef5aa010000006a47304402207e45f303b4e42be824513855eb21653e1d2749cd94dcd0f0613d3f85d4efd1e20220699ffbdbcad889af7ede5ce9febf7a5ef8f5619b2464824529974c400cffaebc0121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff016c9be111000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac000000000000000000" )
def test_multisig(index): address_n, multisig = create_multisig(index, "m/0/0", signatures[0]) inp1 = proto.TxInputType( address_n=address_n, # TchpthUkRys1VQWgnQyLJNaA4MLBjVmRL2c multisig=multisig, prev_hash=TXHASH_3f7c39, prev_index=1, script_type=proto.InputScriptType.SPENDMULTISIG, decred_tree=0, ) address_n, multisig = create_multisig(index, "m/0/1", signatures[1]) inp2 = proto.TxInputType( address_n=address_n, # TcnfDEfMhkM3oLWqiq9v9GmYgLK7qfjitKG multisig=multisig, prev_hash=TXHASH_16da18, prev_index=0, script_type=proto.InputScriptType.SPENDMULTISIG, decred_tree=0, ) address_n, multisig = create_multisig(index, "m/1/0") out1 = proto.TxOutputType( address_n=address_n, # TcrrURA3Bzj4isGU48PdSP9SDoU5oCpjEcb multisig=multisig, amount=99900000, script_type=proto.OutputScriptType.PAYTOMULTISIG, decred_script_version=0, ) out2 = proto.TxOutputType( address="TsWjioPrP8E1TuTMmTrVMM2BA4iPrjQXBpR", amount=300000000, script_type=proto.OutputScriptType.PAYTOADDRESS, decred_script_version=0, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_3f7c39), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_3f7c39, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_3f7c39, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_3f7c39, request_index=1 ), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_16da18), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_16da18, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_16da18, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_16da18, request_index=1 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) signature, serialized_tx = btc.sign_tx( self.client, "Decred Testnet", [inp1, inp2], [out1, out2], prev_txes=TX_API, ) signatures[0][index] = signature[0] signatures[1][index] = signature[1] return serialized_tx
def test_attack_change_input_address(self): # This unit test attempts to modify input address after the Trezor checked # that it matches the change output self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("49'/1'/0'/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX amount=123456789, prev_hash=bytes.fromhex( "20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337" ), prev_index=0, script_type=proto.InputScriptType.SPENDP2SHWITNESS, ) out1 = proto.TxOutputType( address="mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC", amount=12300000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("49'/1'/12'/1/0"), script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, amount=123456789 - 11000 - 12300000, ) # Test if the transaction can be signed normally with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) _, serialized_tx = btc.sign_tx(self.client, "Testnet", [inp1], [out1, out2], prev_txes=TX_API) assert ( serialized_tx.hex() == "0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001976a91414fdede0ddc3be652a0ce1afbc1b509a55b6b94888ac3df39f060000000017a9142f98413cb83ff8b3eaf1926192e68973cbd68a3a8702473044022013cbce7c575337ca05dbe03b5920a0805b510cd8dfd3180bd7c5d01cec6439cd0220050001be4bcefb585caf973caae0ffec682347f2127cc22f26efd93ee54fd852012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000" ) run_attack = True def attack_processor(msg): nonlocal run_attack if run_attack and msg.tx.inputs and msg.tx.inputs[0] == inp1: run_attack = False msg.tx.inputs[0].address_n[2] = H_(12) return msg # Now run the attack, must trigger the exception self.client.set_filter(proto.TxAck, attack_processor) with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.Failure(code=proto.FailureType.ProcessError), ]) with pytest.raises(CallException) as exc: btc.sign_tx(self.client, "Testnet", [inp1], [out1, out2], prev_txes=TX_API) assert exc.value.args[0] == proto.FailureType.ProcessError if TREZOR_VERSION == 1: assert exc.value.args[1].endswith("Failed to compile input") else: assert exc.value.args[1].endswith( "Transaction has changed during signing")
def test_one_one_fee_sapling(self): self.setup_mnemonic_allallall() # prevout: e3820602226974b1dd87b7113cc8aea8c63e5ae29293991e7bfa80c126930368:0 # input 1: 3.0 TAZ inp1 = proto.TxInputType( address_n=parse_path( "m/Zcash Testnet/0h/0/0" ), # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu amount=300000000, prev_hash=TXHASH_e38206, prev_index=0, ) out1 = proto.TxOutputType( address="tmJ1xYxP8XNTtCoDgvdmQPSrxh5qZJgy65Z", amount=300000000 - 1940, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) details = proto.SignTx( version=4, overwintered=True, version_group_id=0x892F2085, branch_id=0x76B809BB, ) _, serialized_tx = btc.sign_tx( self.client, "Zcash Testnet", [inp1], [out1], details=details, prev_txes=TX_API, ) # Accepted by network: tx 0cef132c1d6d67f11cfa48f7fca3209da29cf872ac782354bedb686e61a17a78 assert ( serialized_tx.hex() == "0400008085202f890168039326c180fa7b1e999392e25a3ec6a8aec83c11b787ddb1746922020682e3000000006b483045022100f28298891f48706697a6f898ac18e39ce2c7cebe547b585d51cc22d80b1b21a602201a807b8a18544832d95d1e3ada82c0617bc6d97d3f24d1fb4801ac396647aa880121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff016c9be111000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac00000000000000000000000000000000000000" )
def test_send_multisig_1(self): self.setup_mnemonic_allallall() nodes = [ btc.get_public_node(self.client, parse_path("49'/1'/%d'" % index)) for index in range(1, 4) ] multisig = proto.MultisigRedeemScriptType( nodes=[deserialize(n.xpub) for n in nodes], address_n=[0, 0], signatures=[b"", b"", b""], m=2, ) inp1 = proto.TxInputType( address_n=parse_path("49'/1'/1'/0/0"), prev_hash=bytes.fromhex( "9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be" ), prev_index=1, script_type=proto.InputScriptType.SPENDP2SHWITNESS, multisig=multisig, amount=1610436, ) out1 = proto.TxOutputType( address="tb1qch62pf820spe9mlq49ns5uexfnl6jzcezp7d328fw58lj0rhlhasge9hzy", amount=1605000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) signatures, _ = btc.sign_tx( self.client, "Testnet", [inp1], [out1], prev_txes=TX_API ) # store signature inp1.multisig.signatures[0] = signatures[0] # sign with third key inp1.address_n[2] = H_(3) self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Testnet", [inp1], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "01000000000101be0210025c5be68a473f6a38bf53b53bc88d5c46567616026dc056e72b92319c01000000232200208d398cfb58a1d9cdb59ccbce81559c095e8c6f4a3e64966ca385078d9879f95effffffff01887d180000000000220020c5f4a0a4ea7c0392efe0a9670a73264cffa90b19107cd8a8e9750ff93c77fdfb0400483045022100dd6342c65197af27d7894d8b8b88b16b568ee3b5ebfdc55fdfb7caa9650e3b4c02200c7074a5bcb0068f63d9014c7cd2b0490aba75822d315d41aad444e9b86adf5201483045022100e7e6c2d21109512ba0609e93903e84bfb7731ac3962ee2c1cad54a7a30ff99a20220421497930226c39fc3834e8d6da3fc876516239518b0e82e2dc1e3c46271a17c01695221021630971f20fa349ba940a6ba3706884c41579cd760c89901374358db5dd545b92102f2ff4b353702d2bb03d4c494be19d77d0ab53d16161b53fbcaf1afeef4ad0cb52103e9b6b1c691a12ce448f1aedbbd588e064869c79fbd760eae3b8cd8a5f1a224db53ae00000000" )
def test_send_multisig_1(self): self.setup_mnemonic_allallall() nodes = [ btc.get_public_node(self.client, parse_path("49'/1'/%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'/1'/1'/1/0"), prev_hash=bytes.fromhex( "9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be" ), prev_index=1, script_type=proto.InputScriptType.SPENDP2SHWITNESS, multisig=multisig, amount=1610436, ) out1 = proto.TxOutputType( address="mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC", amount=1605000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) signatures, _ = btc.sign_tx(self.client, "Testnet", [inp1], [out1], prev_txes=TX_API) # store signature inp1.multisig.signatures[0] = signatures[0] # sign with third key inp1.address_n[2] = H_(3) self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) _, serialized_tx = btc.sign_tx(self.client, "Testnet", [inp1], [out1], prev_txes=TX_API) assert ( serialized_tx.hex() == "01000000000101be0210025c5be68a473f6a38bf53b53bc88d5c46567616026dc056e72b92319c0100000023220020cf28684ff8a6dda1a7a9704dde113ddfcf236558da5ce35ad3f8477474dbdaf7ffffffff01887d1800000000001976a91414fdede0ddc3be652a0ce1afbc1b509a55b6b94888ac040047304402203fc3fbe6cd6250d82ace4a585debc07587c07d2efc8bb56558c91e1f810fe65402206025bd9a4e80960f617b6e5bfdd568e34aa085d093471b7976e6b14c2a2402a7014730440220327abf491a57964d75c67fad204eb782fa74aa4abde40e5ad30fb0b7696102b7022049e31f2302417be0a87e2f818b93a862a7e67d4178b7cbeee680264f0882113f0169522103d54ab3c8b81cb7f8f8088df4c62c105e8acaa2fb53b180f6bc6f922faecf3fdc21036aa47994f3f18f0976d6073ca79997003c3fa29c4f93907998fefc1151b4529b2102a092580f2828272517c402da9461425c5032860ab40180e041fbbb88ea2a520453ae00000000" )
def test_attack_change_outputs(self): # This unit test attempts to modify data sent during ping-pong of streaming signing. # Because device is asking for human confirmation only during first pass (first input), # device must detect that data has been modified during other passes and fail to sign # such modified data (which has not been confirmed by the user). # Test firstly prepare normal transaction and send it to device. Then it send the same # transaction again, but change amount of output 1 during signing the second input. self.setup_mnemonic_nopin_nopassphrase() inp1 = proto.TxInputType( address_n=[1], # 1CK7SJdcb8z9HuvVft3D91HLpLC6KSsGb # amount=100000, prev_hash=TXHASH_c6be22, prev_index=1, ) inp2 = proto.TxInputType( address_n=[2], # 15AeAhtNJNKyowK8qPHwgpXkhsokzLtUpG # amount=110000, prev_hash=TXHASH_58497a, prev_index=1, ) out1 = proto.TxOutputType( address="15Jvu3nZNP7u2ipw2533Q9VVgEu2Lu9F2B", amount=210000 - 100000 - 10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=[3], # 1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5 amount=100000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2.force_confirm = True # Test if the transaction can be signed normally _, serialized_tx = check_sign_tx( self.client, "Bitcoin", [inp1, inp2], [out1, out2], unknown_path=True ) # Accepted by network: tx c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb assert ( serialized_tx.hex() == "01000000021c032e5715d1da8115a2fe4f57699e15742fe113b0d2d1ca3b594649d322bec6010000006b483045022100f773c403b2f85a5c1d6c9c4ad69c43de66930fff4b1bc818eb257af98305546a0220443bde4be439f276a6ce793664b463580e210ec6c9255d68354449ac0443c76501210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6ffffffff6ea42cd8d9c8e5441c4c5f85bfe50311078730d2881494f11f4d2257777a4958010000006b48304502210090cff1c1911e771605358a8cddd5ae94c7b60cc96e50275908d9bf9d6367c79f02202bfa72e10260a146abd59d0526e1335bacfbb2b4401780e9e3a7441b0480c8da0121038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3ffffffff02a0860100000000001976a9142f4490d5263906e4887ca2996b9e207af3e7824088aca0860100000000001976a914812c13d97f9159e54e326b481b8f88a73df8507a88ac00000000" ) run_attack = False def attack_processor(msg): nonlocal run_attack if msg.tx.outputs and msg.tx.outputs[0] == out2: if not run_attack: run_attack = True else: # Sign output with another amount msg.tx.outputs[0].amount = 9999999 return msg # Set up attack processors self.client.set_filter(proto.TxAck, attack_processor) with pytest.raises(CallException) as exc: btc.sign_tx( self.client, "Bitcoin", [inp1, inp2], [out1, out2], prev_txes=tx_cache("Bitcoin"), ) assert exc.value.args[0] in ( proto.FailureType.ProcessError, proto.FailureType.DataError, ) assert exc.value.args[1].endswith("Transaction has changed during signing")
def test_send_p2sh_change(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("49'/1'/0'/1/0"), # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX amount=123456789, prev_hash=bytes.fromhex( "20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337" ), prev_index=0, script_type=proto.InputScriptType.SPENDP2SHWITNESS, ) out1 = proto.TxOutputType( address="mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC", amount=12300000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("49'/1'/0'/1/0"), script_type=proto.OutputScriptType.PAYTOP2SHWITNESS, amount=123456789 - 11000 - 12300000, ) with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) _, serialized_tx = btc.sign_tx(self.client, "Testnet", [inp1], [out1, out2], prev_txes=TX_API) assert ( serialized_tx.hex() == "0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001976a91414fdede0ddc3be652a0ce1afbc1b509a55b6b94888ac3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100ccd253bfdf8a5593cd7b6701370c531199f0f05a418cd547dfc7da3f21515f0f02203fa08a0753688871c220648f9edadbdb98af42e5d8269364a326572cf703895b012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000" )
def test_attack_change_input_address(self): # This unit test attempts to modify input address after the Trezor checked # that it matches the change output self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/1'/4'/0/0"), # moUJnmge8SRXuediK7bW6t4YfrPqbE6hD7 prev_hash=TXHASH_d2dcda, prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address="mwue7mokpBRAsJtHqEMcRPanYBmsSmYKvY", amount=100000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("44'/1'/4'/1/0"), amount=123400000 - 5000 - 100000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) # Test if the transaction can be signed normally _, serialized_tx = check_sign_tx(self.client, "Testnet", [inp1], [out1, out2]) assert ( serialized_tx.hex() == "0100000001243e15b53cc553d93ec4e27e16984adc3d885ef107c613a7577fea47f5dadcd2010000006b483045022100eedaadde3a771967beee39f1daa9e9450f72fccdec63488a96d71eeae4224b4002203a22be3c1677d3451c93a49550b69e8f8fc06328823c7e0f633dde13d67ef96b01210364430c9122948e525e2f1c6d88f00f47679274f0810fd8c63754954f310995c1ffffffff02a0860100000000001976a914b3cc67f3349974d0f1b50e9bb5dfdf226f888fa088ac18555907000000001976a914f80fb232a1e54b1fa732bc120cae72eabd7fcf6888ac00000000" ) run_attack = False def attack_processor(msg): nonlocal run_attack if msg.tx.inputs and msg.tx.inputs[0] == inp1: if not run_attack: run_attack = True else: msg.tx.inputs[0].address_n[2] = H_(12) return msg self.client.set_filter(proto.TxAck, attack_processor) # Now run the attack, must trigger the exception with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_d2dcda), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d2dcda ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d2dcda ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=TXHASH_d2dcda ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.Failure(code=proto.FailureType.ProcessError), ] ) # Now run the attack, must trigger the exception with pytest.raises(CallException) as exc: btc.sign_tx( self.client, "Testnet", [inp1], [out1, out2], prev_txes=tx_cache("Testnet"), ) assert exc.value.args[0] == proto.FailureType.ProcessError if TREZOR_VERSION == 1: assert exc.value.args[1].endswith("Failed to compile input") else: assert exc.value.args[1].endswith( "Transaction has changed during signing" )
def sign_tx(hw_session: HwSessionInfo, utxos_to_spend: List[wallet_common.UtxoType], tx_outputs: List[wallet_common.TxOutputType], tx_fee): """ Creates a signed transaction. :param hw_session: :param utxos_to_spend: list of utxos to send :param tx_outputs: list of transaction outputs :param tx_fee: transaction fee :return: tuple (serialized tx, total transaction amount in satoshis) """ def load_prev_txes(tx_api, skip_cache: bool = False): txes = {} tx_api.skip_cache = skip_cache for utxo in utxos_to_spend: prev_hash = bytes.fromhex(utxo.txid) if prev_hash not in txes: tx = tx_api[prev_hash] txes[prev_hash] = tx return txes insight_network = 'insight_polis' if hw_session.app_config.is_testnet(): insight_network += '_testnet' polis_network = hw_session.app_config.polis_network c_name = hw_session.app_config.hw_coin_name coin = coins.by_name[c_name] url = hw_session.app_config.get_tx_api_url() coin['bitcore'].clear() coin['bitcore'].append(url) tx_api = MyTxApiInsight(coin, '', hw_session.polisd_intf, hw_session.app_config.tx_cache_dir) client = hw_session.hw_client inputs = [] outputs = [] inputs_amount = 0 for utxo_index, utxo in enumerate(utxos_to_spend): if not utxo.bip32_path: raise Exception('No BIP32 path for UTXO ' + utxo.txid) address_n = polis_utils.bip32_path_string_to_n(utxo.bip32_path) it = trezor_proto.TxInputType(address_n=address_n, prev_hash=binascii.unhexlify(utxo.txid), prev_index=int(utxo.output_index)) inputs.append(it) inputs_amount += utxo.satoshis outputs_amount = 0 for out in tx_outputs: outputs_amount += out.satoshis if out.address[0] in polis_utils.get_chain_params( polis_network).B58_PREFIXES_SCRIPT_ADDRESS: stype = trezor_proto.OutputScriptType.PAYTOSCRIPTHASH logging.debug('Transaction type: PAYTOSCRIPTHASH' + str(stype)) elif out.address[0] in polis_utils.get_chain_params( polis_network).B58_PREFIXES_PUBKEY_ADDRESS: stype = trezor_proto.OutputScriptType.PAYTOADDRESS logging.debug('Transaction type: PAYTOADDRESS ' + str(stype)) else: raise Exception('Invalid prefix of the destination address.') if out.bip32_path: address_n = polis_utils.bip32_path_string_to_n(out.bip32_path) else: address_n = None ot = trezor_proto.TxOutputType( address=out.address if address_n is None else None, address_n=address_n, amount=out.satoshis, script_type=stype) outputs.append(ot) if outputs_amount + tx_fee != inputs_amount: raise Exception( 'Transaction validation failure: inputs + fee != outputs') try: for skip_cache in (False, True): txes = load_prev_txes(tx_api, skip_cache) try: signed = btc.sign_tx(client, hw_session.app_config.hw_coin_name, inputs, outputs, prev_txes=txes) return signed[1], inputs_amount except exceptions.Cancelled: raise except Exception as e: if skip_cache: raise log.exception( 'Exception occurred while signing transaction. Turning off the transaction cache ' 'and retrying...') raise Exception('Internal error: transaction not signed') except exceptions.Cancelled: raise CancelException('Cancelled')
def check_sign_tx( client, coin_name, inputs, outputs, fee_too_high=False, failure=None, unknown_path=False, ): __tracebackhide__ = True expected_responses = [] txes = tx_cache(coin_name) t = proto.RequestType b = proto.ButtonRequestType def tx_request(request_type, **kwargs): if kwargs: details = proto.TxRequestDetailsType(**kwargs) else: details = None return proto.TxRequest(request_type=request_type, details=details) def btn(code): return proto.ButtonRequest(code=code) for i, inp in enumerate(inputs): expected_responses.append(tx_request(t.TXINPUT, request_index=i)) if unknown_path and TREZOR_VERSION != 1: expected_responses.append(btn(b.UnknownDerivationPath)) expected_responses.append(tx_request(t.TXMETA, tx_hash=inp.prev_hash)) if inp.script_type in ( proto.InputScriptType.SPENDP2SHWITNESS, proto.InputScriptType.SPENDWITNESS, ): continue prev_tx = txes[inp.prev_hash] for pi in range(len(prev_tx.inputs)): r = tx_request(t.TXINPUT, request_index=pi, tx_hash=inp.prev_hash) expected_responses.append(r) for po in range(len(prev_tx.bin_outputs)): r = tx_request(t.TXOUTPUT, request_index=po, tx_hash=inp.prev_hash) expected_responses.append(r) for i, outp in enumerate(outputs): expected_responses.append(tx_request(t.TXOUTPUT, request_index=i)) if outp.address is not None or hasattr(outp, "force_confirm"): expected_responses.append(btn(b.ConfirmOutput)) if fee_too_high: expected_responses.append(btn(b.FeeOverThreshold)) if failure is not None: expected_responses.append(proto.Failure(code=failure)) else: expected_responses.append(btn(b.SignTx)) input_requests = [ tx_request(t.TXINPUT, request_index=i) for i in range(len(inputs)) ] output_requests = [ tx_request(t.TXOUTPUT, request_index=i) for i in range(len(outputs)) ] # No idea why the flow is like this. But it is. for _ in range(len(inputs)): expected_responses.extend(input_requests) expected_responses.extend(output_requests) # and once more for good measure expected_responses.extend(output_requests) expected_responses.append(tx_request(t.TXFINISHED)) with client: client.set_expected_responses(expected_responses) return btc.sign_tx(client, coin_name, inputs, outputs, prev_txes=txes)
def sign_tx(self, tx): # Get this devices master key fingerprint master_key = btc.get_public_node(self.client, [0]) master_fp = get_xpub_fingerprint(master_key.xpub) # Do multiple passes for multisig passes = 1 p = 0 while p < passes: # Prepare inputs inputs = [] to_ignore = [ ] # Note down which inputs whose signatures we're going to ignore for input_num, (psbt_in, txin) in py_enumerate( list(zip(tx.inputs, tx.tx.vin))): txinputtype = proto.TxInputType() # Set the input stuff txinputtype.prev_hash = ser_uint256(txin.prevout.hash)[::-1] txinputtype.prev_index = txin.prevout.n txinputtype.sequence = txin.nSequence # Detrermine spend type scriptcode = b'' if psbt_in.non_witness_utxo: utxo = psbt_in.non_witness_utxo.vout[txin.prevout.n] txinputtype.script_type = proto.InputScriptType.SPENDADDRESS scriptcode = utxo.scriptPubKey txinputtype.amount = psbt_in.non_witness_utxo.vout[ txin.prevout.n].nValue elif psbt_in.witness_utxo: utxo = psbt_in.witness_utxo # Check if the output is p2sh if psbt_in.witness_utxo.is_p2sh(): txinputtype.script_type = proto.InputScriptType.SPENDP2SHWITNESS else: txinputtype.script_type = proto.InputScriptType.SPENDWITNESS scriptcode = psbt_in.witness_utxo.scriptPubKey txinputtype.amount = psbt_in.witness_utxo.nValue # Set the script if psbt_in.witness_script: scriptcode = psbt_in.witness_script elif psbt_in.redeem_script: scriptcode = psbt_in.redeem_script def ignore_input(): txinputtype.address_n = [0x80000000] inputs.append(txinputtype) to_ignore.append(input_num) # Check for multisig is_ms, multisig = parse_multisig(scriptcode) if is_ms: # Add to txinputtype txinputtype.multisig = multisig if psbt_in.non_witness_utxo: if utxo.is_p2sh: txinputtype.script_type = proto.InputScriptType.SPENDMULTISIG else: # Cannot sign bare multisig, ignore it ignore_input() continue elif not is_ms and psbt_in.non_witness_utxo and not utxo.is_p2pkh: # Cannot sign unknown spk, ignore it ignore_input() continue elif not is_ms and psbt_in.witness_utxo and psbt_in.witness_script: # Cannot sign unknown witness script, ignore it ignore_input() continue # Find key to sign with found = False our_keys = 0 for key in psbt_in.hd_keypaths.keys(): keypath = psbt_in.hd_keypaths[key] if keypath[ 0] == master_fp and key not in psbt_in.partial_sigs: if not found: txinputtype.address_n = keypath[1:] found = True our_keys += 1 # Determine if we need to do more passes to sign everything if our_keys > passes: passes = our_keys if not found: # This input is not one of ours ignore_input() continue # append to inputs inputs.append(txinputtype) # address version byte if self.is_testnet: p2pkh_version = b'\x6f' p2sh_version = b'\xc4' bech32_hrp = 'tb' else: p2pkh_version = b'\x00' p2sh_version = b'\x05' bech32_hrp = 'bc' # prepare outputs outputs = [] for out in tx.tx.vout: txoutput = proto.TxOutputType() txoutput.amount = out.nValue txoutput.script_type = proto.OutputScriptType.PAYTOADDRESS if out.is_p2pkh(): txoutput.address = to_address(out.scriptPubKey[3:23], p2pkh_version) elif out.is_p2sh(): txoutput.address = to_address(out.scriptPubKey[2:22], p2sh_version) else: wit, ver, prog = out.is_witness() if wit: txoutput.address = bech32.encode(bech32_hrp, ver, prog) else: raise TypeError("Output is not an address") # append to outputs outputs.append(txoutput) # Prepare prev txs prevtxs = {} for psbt_in in tx.inputs: if psbt_in.non_witness_utxo: prev = psbt_in.non_witness_utxo t = proto.TransactionType() t.version = prev.nVersion t.lock_time = prev.nLockTime for vin in prev.vin: i = proto.TxInputType() i.prev_hash = ser_uint256(vin.prevout.hash)[::-1] i.prev_index = vin.prevout.n i.script_sig = vin.scriptSig i.sequence = vin.nSequence t.inputs.append(i) for vout in prev.vout: o = proto.TxOutputBinType() o.amount = vout.nValue o.script_pubkey = vout.scriptPubKey t.bin_outputs.append(o) logging.debug(psbt_in.non_witness_utxo.hash) prevtxs[ser_uint256( psbt_in.non_witness_utxo.sha256)[::-1]] = t # Sign the transaction tx_details = proto.SignTx() tx_details.version = tx.tx.nVersion tx_details.lock_time = tx.tx.nLockTime if self.is_testnet: signed_tx = btc.sign_tx(self.client, "Testnet", inputs, outputs, tx_details, prevtxs) else: signed_tx = btc.sign_tx(self.client, "Bitcoin", inputs, outputs, tx_details, prevtxs) # Each input has one signature for input_num, (psbt_in, sig) in py_enumerate( list(zip(tx.inputs, signed_tx[0]))): if input_num in to_ignore: continue for pubkey in psbt_in.hd_keypaths.keys(): fp = psbt_in.hd_keypaths[pubkey][0] if fp == master_fp and pubkey not in psbt_in.partial_sigs: psbt_in.partial_sigs[pubkey] = sig + b'\x01' break p += 1 return {'psbt': tx.serialize()}
def test_nonzero_opreturn(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/0'/10'/0/5"), prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = proto.TxOutputType( op_return_data=b"test of the op_return data", amount=10000, script_type=proto.OutputScriptType.PAYTOOPRETURN, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d5f65e ), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=TXHASH_d5f65e ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d5f65e ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.Failure(), ] ) with pytest.raises(CallException) as exc: btc.sign_tx(self.client, "Bitcoin", [inp1], [out1], prev_txes=TX_API) if TREZOR_VERSION == 1: assert exc.value.args[0] == proto.FailureType.ProcessError assert exc.value.args[1].endswith("Failed to compile output") else: assert exc.value.args[0] == proto.FailureType.DataError assert exc.value.args[1].endswith( "OP_RETURN output with non-zero amount" )
def test_send_bch_multisig_wrongchange(self, client): nodes = [ btc.get_public_node(client, parse_path("48'/145'/%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) correcthorse = proto.HDNodeType( depth=1, fingerprint=0, child_num=0, chain_code=bytes.fromhex( "0000000000000000000000000000000000000000000000000000000000000000" ), public_key=bytes.fromhex( "0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71" ), ) sig = bytes.fromhex( "304402207274b5a4d15e75f3df7319a375557b0efba9b27bc63f9f183a17da95a6125c94022000efac57629f1522e2d3958430e2ef073b0706cfac06cce492651b79858f09ae" ) inp1 = proto.TxInputType( address_n=parse_path("48'/145'/1'/1/0"), multisig=getmultisig(1, 0, [b"", sig, b""]), # bitcoincash:pp6kcpkhua7789g2vyj0qfkcux3yvje7euhyhltn0a amount=24000, prev_hash=TXHASH_f68caf, prev_index=1, script_type=proto.InputScriptType.SPENDMULTISIG, ) out1 = proto.TxOutputType( address_n=parse_path("48'/145'/1'/1/1"), multisig=proto.MultisigRedeemScriptType( pubkeys=[ proto.HDNodePathType(node=nodes[0], address_n=[1, 1]), proto.HDNodePathType(node=correcthorse, address_n=[]), proto.HDNodePathType(node=correcthorse, address_n=[]), ], signatures=[b"", b"", b""], m=2, ), script_type=proto.OutputScriptType.PAYTOMULTISIG, amount=23000, ) 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_finished(), ]) (signatures1, serialized_tx) = btc.sign_tx(client, "Bcash", [inp1], [out1], prev_txes=TX_API) assert ( signatures1[0].hex() == "304402201badcdcafef4855ed58621f95935efcbc72068510472140f4ec5e252faa0af93022003310a43488288f70aedee96a5af2643a255268a6858cda9ae3001ea5e3c7557" ) assert ( serialized_tx.hex() == "01000000015f3d291cae106548f3be5ed0f4cbedc65668fa881d60347ab0d512df10af8cf601000000fc0047304402201badcdcafef4855ed58621f95935efcbc72068510472140f4ec5e252faa0af93022003310a43488288f70aedee96a5af2643a255268a6858cda9ae3001ea5e3c75574147304402207274b5a4d15e75f3df7319a375557b0efba9b27bc63f9f183a17da95a6125c94022000efac57629f1522e2d3958430e2ef073b0706cfac06cce492651b79858f09ae414c69522102245739b55787a27228a4fe78b3a324366cc645fbaa708cad45da351a334341192102debbdcb0b6970d5ade84a50fdbda1c701cdde5c9925d9b6cd8e05a9a15dbef352102ffe5fa04547b2b0c3cfbc21c08a1ddfb147025fee10274cdcd5c1bdeee88eae253aeffffffff01d85900000000000017a914a23eb2a1ed4003d357770120f5c370e199ee55468700000000" )
def test_opreturn(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/0'/0'/0/2"), prev_hash=TXHASH_d5f65e, prev_index=0 ) out1 = proto.TxOutputType( address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1", amount=390000 - 10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( op_return_data=b"test of the op_return data", amount=0, script_type=proto.OutputScriptType.PAYTOOPRETURN, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d5f65e ), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=TXHASH_d5f65e ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d5f65e ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Bitcoin", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "010000000182488650ef25a58fef6788bd71b8212038d7f2bbe4750bc7bcb44701e85ef6d5000000006b483045022100bc36e1227b334e856c532bbef86d30a96823a5f2461738f4dbf969dfbcf1b40b022078c5353ec9a4bce2bb05bd1ec466f2ab379c1aad926e208738407bba4e09784b012103330236b68aa6fdcaca0ea72e11b360c84ed19a338509aa527b678a7ec9076882ffffffff0260cc0500000000001976a914de9b2a8da088824e8fe51debea566617d851537888ac00000000000000001c6a1a74657374206f6620746865206f705f72657475726e206461746100000000" )
def test_attack_change_input(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/156'/1000'/0/0"), # 1MH9KKcvdCTY44xVDC2k3fjBbX5Cz29N1q amount=1995344, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=parse_path("44'/156'/1000'/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 self.client.set_filter(proto.TxAck, attack_processor) with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.Failure(code=proto.FailureType.ProcessError), ]) with pytest.raises(CallException): btc.sign_tx(self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API)
def test_lots_of_change(self, client): # Tests if device implements prompting for multiple change addresses correctly # tx: c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb # index 1: 0.0010 BTC # tx: 39a29e954977662ab3879c66fb251ef753e0912223a83d1dcb009111d28265e5 # index 1: 0.0254 BTC inp1 = messages.TxInputType( address_n=parse_path("44h/0h/1h/0/0"), amount=100000, prev_hash=TXHASH_c63e24, prev_index=1, ) inp2 = messages.TxInputType( address_n=parse_path("44h/0h/1h/0/1"), amount=2540000, prev_hash=TXHASH_39a29e, prev_index=1, ) outputs = [ messages.TxOutputType( address="1NwN6UduuVkJi6sw3gSiKZaCY5rHgVXC2h", amount=500000, script_type=messages.OutputScriptType.PAYTOADDRESS, ) ] cnt = 20 for i in range(cnt): out = messages.TxOutputType( address_n=parse_path(f"44h/0h/1h/1/{i}"), amount=(100000 + 2540000 - 500000 - 39000) // cnt, script_type=messages.OutputScriptType.PAYTOADDRESS, ) outputs.append(out) request_change_outputs = [request_output(i + 1) for i in range(cnt)] with client: client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), ] + request_change_outputs + [ messages.ButtonRequest(code=B.SignTx), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_c63e24), request_input(0, TXHASH_c63e24), request_input(1, TXHASH_c63e24), request_output(0, TXHASH_c63e24), request_output(1, TXHASH_c63e24), request_input(1), request_meta(TXHASH_39a29e), request_input(0, TXHASH_39a29e), request_output(0, TXHASH_39a29e), request_output(1, TXHASH_39a29e), request_input(0), request_input(1), request_output(0), ] + request_change_outputs + [request_input(0), request_input(1), request_output(0)] + request_change_outputs + [request_output(0)] + request_change_outputs + [request_finished()]) _, serialized_tx = btc.sign_tx(client, "Bitcoin", [inp1, inp2], outputs, prev_txes=TX_CACHE_MAINNET) assert ( tx_hash(serialized_tx).hex() == "fae68e4a3a4b0540eb200e2218a6d8465eac469788ccb236e0d5822d105ddde9")
def test_send_p2sh(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("49'/156'/0'/1/0"), amount=123456789, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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 self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) _, serialized_tx = btc.sign_tx(self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API) assert ( serialized_tx.hex() == "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250000000017160014b5355d001e720d8f4513da00ff2bba4dcf9d39fcffffffff02e0aebb00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac3df39f06000000001976a914a8f757819ec6779409f45788f7b4a0e8f51ec50488ac02473044022073fcbf2876f073f78923ab427f14de5b2a0fbeb313a9b2b650b3567061f242a702202f45fc22c501108ff6222afe3aca7da9d8c7dc860f9cda335bef31fa184e7bef412102ecea08b559fc5abd009acf77cfae13fa8a3b1933e3e031956c65c12cec8ca3e300000000" )
def test_attack_change_outputs(self, client): inp1 = messages.TxInputType( address_n=parse_path("44h/0h/0h/0/0"), amount=100000, prev_hash=TXHASH_c6be22, prev_index=1, ) inp2 = messages.TxInputType( address_n=parse_path("44h/0h/0h/0/1"), amount=110000, prev_hash=TXHASH_58497a, prev_index=1, ) out1 = messages.TxOutputType( address="15Jvu3nZNP7u2ipw2533Q9VVgEu2Lu9F2B", amount=210000 - 100000 - 10000, script_type=messages.OutputScriptType.PAYTOADDRESS, ) out2 = messages.TxOutputType( address_n=parse_path("44h/0h/0h/1/0"), amount=100000, script_type=messages.OutputScriptType.PAYTOADDRESS, ) # Test if the transaction can be signed normally _, serialized_tx = btc.sign_tx(client, "Bitcoin", [inp1, inp2], [out1, out2], prev_txes=TX_CACHE_MAINNET) assert ( tx_hash(serialized_tx).hex() == "4601b738e1b0f8a7ff9ca5adf0c896fa39dfe8b8ead7ad0d716c98167e8a5d11") run_attack = False def attack_processor(msg): nonlocal run_attack if msg.tx.outputs and msg.tx.outputs[0] == out2: if not run_attack: run_attack = True else: # Sign output with another amount msg.tx.outputs[0].amount = 9999999 return msg # Set up attack processors client.set_filter(messages.TxAck, attack_processor) with pytest.raises(TrezorFailure, match="Transaction has changed during signing"): btc.sign_tx( client, "Bitcoin", [inp1, inp2], [out1, out2], prev_txes=TX_CACHE_MAINNET, )
def test_send_multisig_1(self): self.setup_mnemonic_allallall() nodes = map( lambda index: btc.get_public_node( self.client, parse_path("999'/1'/%d'" % index)), range(1, 4), ) multisig = proto.MultisigRedeemScriptType( pubkeys=list( map( lambda n: proto.HDNodePathType(node=deserialize(n.xpub), address_n=[2, 0]), nodes, )), signatures=[b"", b"", b""], m=2, ) inp1 = proto.TxInputType( address_n=parse_path("999'/1'/1'/2/0"), prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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 self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) signatures, _ = btc.sign_tx(self.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) self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) _, serialized_tx = btc.sign_tx(self.client, "Bgold", [inp1], [out1], prev_txes=TX_API) assert ( serialized_tx.hex() == "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b522501000000232200201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a1ffffffff01887d1800000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac0400483045022100e728485c8337f9a09ebbf36edc0fef10f8bcf5c1ba601b7d8ba43a9250a898f002206b9e3401c297f9ab9afb7f1be59bb342db53b5b65aff7c557e3109679697df0f41473044022062ea69ecdc07d0dadc1971fbda50a629a56dd30f431db26327428f4992601ce602204a1c8ab9c7d81c36cb6f819109a26f9baaa9607b8d37bff5e24eee6fab4a04e441695221038e81669c085a5846e68e03875113ddb339ecbb7cb11376d4163bca5dc2e2a0c1210348c5c3be9f0e6cf1954ded1c0475beccc4d26aaa9d0cce2dd902538ff1018a112103931140ebe0fbbb7df0be04ed032a54e9589e30339ba7bbb8b0b71b15df1294da53ae00000000" )
def test_attack_change_input_address(self, client): inp1 = messages.TxInputType( address_n=parse_path("44'/1'/4'/0/0"), # moUJnmge8SRXuediK7bW6t4YfrPqbE6hD7 prev_hash=TXHASH_d2dcda, amount=123400000, prev_index=1, script_type=messages.InputScriptType.SPENDADDRESS, ) out1 = messages.TxOutputType( address="mwue7mokpBRAsJtHqEMcRPanYBmsSmYKvY", amount=100000, script_type=messages.OutputScriptType.PAYTOADDRESS, ) out2 = messages.TxOutputType( address_n=parse_path("44'/1'/4'/1/0"), amount=123400000 - 5000 - 100000, script_type=messages.OutputScriptType.PAYTOADDRESS, ) # Test if the transaction can be signed normally _, serialized_tx = btc.sign_tx(client, "Testnet", [inp1], [out1, out2], prev_txes=TX_CACHE_TESTNET) assert ( serialized_tx.hex() == "0100000001243e15b53cc553d93ec4e27e16984adc3d885ef107c613a7577fea47f5dadcd2010000006b483045022100eedaadde3a771967beee39f1daa9e9450f72fccdec63488a96d71eeae4224b4002203a22be3c1677d3451c93a49550b69e8f8fc06328823c7e0f633dde13d67ef96b01210364430c9122948e525e2f1c6d88f00f47679274f0810fd8c63754954f310995c1ffffffff02a0860100000000001976a914b3cc67f3349974d0f1b50e9bb5dfdf226f888fa088ac18555907000000001976a914f80fb232a1e54b1fa732bc120cae72eabd7fcf6888ac00000000" ) attack_count = 2 def attack_processor(msg): nonlocal attack_count if msg.tx.inputs and msg.tx.inputs[0] == inp1: if attack_count > 0: attack_count -= 1 else: msg.tx.inputs[0].address_n[2] = H_(12) return msg client.set_filter(messages.TxAck, attack_processor) # Now run the attack, must trigger the exception with client: client.set_expected_responses([ request_input(0), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), request_output(1), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_d2dcda), request_input(0, TXHASH_d2dcda), request_output(0, TXHASH_d2dcda), request_output(1, TXHASH_d2dcda), request_input(0), messages.Failure(code=messages.FailureType.ProcessError), ]) # Now run the attack, must trigger the exception with pytest.raises(TrezorFailure) as exc: btc.sign_tx( client, "Testnet", [inp1], [out1, out2], prev_txes=TX_CACHE_TESTNET, ) assert exc.value.code == messages.FailureType.ProcessError if client.features.model == "1": assert exc.value.message.endswith("Failed to compile input") else: assert exc.value.message.endswith( "Transaction has changed during signing")
def test_send_native(self, client): inp1 = proto.TxInputType( address_n=parse_path("84'/1'/0'/0/0"), amount=12300000, prev_hash=bytes.fromhex( "09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a" ), prev_index=0, script_type=proto.InputScriptType.SPENDWITNESS, ) out1 = proto.TxOutputType( address="2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp", amount=5000000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address="tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu", script_type=proto.OutputScriptType.PAYTOADDRESS, amount=12300000 - 11000 - 5000000, ) with client: client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ]) _, serialized_tx = btc.sign_tx(client, "Testnet", [inp1], [out1, out2], prev_txes=TX_API) assert ( serialized_tx.hex() == "010000000001018a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090000000000ffffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987a8386f0000000000160014d16b8c0680c61fc6ed2e407455715055e41052f502473044022073ce72dcf2f6e42eeb44adbe7d5038cf3763f168d1c04bd8b873a19b53331f51022016b051725731e7f53a567021bcd9c370727f551c81e857ebae7c128472119652012103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f86200000000" )
def sign_tx(hw_session: HWSessionBase, rt_data: AppRuntimeData, utxos_to_spend: List[wallet_common.UtxoType], tx_outputs: List[wallet_common.TxOutputType], tx_fee): """ Creates a signed transaction. :param hw_session: :param utxos_to_spend: list of utxos to send :param tx_outputs: list of transaction outputs :param tx_fee: transaction fee :return: tuple (serialized tx, total transaction amount in satoshis) """ def load_prev_txes(tx_api_, skip_cache_: bool = False): txes_ = {} tx_api_.skip_cache = skip_cache_ for utxo_ in utxos_to_spend: prev_hash_bin = bytes.fromhex(utxo_.txid) if prev_hash_bin not in txes_: tx = tx_api_.get_tx(utxo_.txid) txes_[prev_hash_bin] = tx return txes_ insight_network = 'insight_dash' if rt_data.is_testnet: insight_network += '_testnet' dash_network = rt_data.dash_network tx_api = MyTxApiInsight(rt_data.dashd_intf, rt_data.tx_cache_dir) client = hw_session.hw_client inputs = [] outputs = [] inputs_amount = 0 for utxo_index, utxo in enumerate(utxos_to_spend): if not utxo.bip32_path: raise Exception('No BIP32 path for UTXO ' + utxo.txid) address_n = dash_utils.bip32_path_string_to_n(utxo.bip32_path) it = trezor_proto.TxInputType(address_n=address_n, amount=utxo.satoshis, prev_hash=binascii.unhexlify(utxo.txid), prev_index=int(utxo.output_index)) inputs.append(it) inputs_amount += utxo.satoshis outputs_amount = 0 for out in tx_outputs: outputs_amount += out.satoshis if out.address[0] in dash_utils.get_chain_params( dash_network).B58_PREFIXES_SCRIPT_ADDRESS: stype = trezor_proto.OutputScriptType.PAYTOSCRIPTHASH logging.debug('Transaction type: PAYTOSCRIPTHASH' + str(stype)) elif out.address[0] in dash_utils.get_chain_params( dash_network).B58_PREFIXES_PUBKEY_ADDRESS: stype = trezor_proto.OutputScriptType.PAYTOADDRESS logging.debug('Transaction type: PAYTOADDRESS ' + str(stype)) else: raise Exception('Invalid prefix of the destination address.') if out.bip32_path: address_n = dash_utils.bip32_path_string_to_n(out.bip32_path) else: address_n = None ot = trezor_proto.TxOutputType( address=out.address if address_n is None else None, address_n=address_n, amount=out.satoshis, script_type=stype) outputs.append(ot) if outputs_amount + tx_fee != inputs_amount: raise Exception( 'Transaction validation failure: inputs + fee != outputs') try: for skip_cache in (False, True): txes = load_prev_txes(tx_api, skip_cache) try: signed = btc.sign_tx(client, rt_data.hw_coin_name, inputs, outputs, prev_txes=txes) return signed[1], inputs_amount except exceptions.Cancelled: raise except Exception: if skip_cache: raise log.exception( 'Exception occurred while signing transaction. Turning off the transaction cache ' 'and retrying...') raise Exception('Internal error: transaction not signed') except exceptions.Cancelled: raise CancelException('Cancelled') except exceptions.TrezorFailure as e: if e.failure.message == 'Device not initialized': raise HwNotInitialized(e.failure.message) else: raise
def test_attack_change_input(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/156'/11'/0/0"), amount=1995344, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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 self.client.set_filter(proto.TxAck, attack_processor) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.Failure(code=proto.FailureType.ProcessError), ] ) with pytest.raises(CallException): btc.sign_tx( self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API )
def test_attack_change_outputs(self): # This unit test attempts to modify data sent during ping-pong of streaming signing. # Because device is asking for human confirmation only during first pass (first input), # device must detect that data has been modified during other passes and fail to sign # such modified data (which has not been confirmed by the user). # Test firstly prepare normal transaction and send it to device. Then it send the same # transaction again, but change amount of output 1 during signing the second input. self.setup_mnemonic_nopin_nopassphrase() inp1 = proto.TxInputType( address_n=[1], # 1CK7SJdcb8z9HuvVft3D91HLpLC6KSsGb # amount=100000, prev_hash=TXHASH_c6be22, prev_index=1, ) inp2 = proto.TxInputType( address_n=[2], # 15AeAhtNJNKyowK8qPHwgpXkhsokzLtUpG # amount=110000, prev_hash=TXHASH_58497a, prev_index=1, ) out1 = proto.TxOutputType( address="15Jvu3nZNP7u2ipw2533Q9VVgEu2Lu9F2B", amount=210000 - 100000 - 10000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=[3], # 1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5 amount=100000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) global run_attack run_attack = False def attack_processor(req, msg): global run_attack if req.details.tx_hash is not None: return msg if req.details.request_index != 1: return msg if req.request_type != proto.RequestType.TXOUTPUT: return msg if not run_attack: run_attack = True return msg msg.outputs[0].amount = 9999999 # Sign output with another amount return msg # Test if the transaction can be signed normally (_, serialized_tx) = btc.sign_tx(self.client, "Bitcoin", [inp1, inp2], [out1, out2]) # Accepted by network: tx c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb assert ( hexlify(serialized_tx) == b"01000000021c032e5715d1da8115a2fe4f57699e15742fe113b0d2d1ca3b594649d322bec6010000006b483045022100f773c403b2f85a5c1d6c9c4ad69c43de66930fff4b1bc818eb257af98305546a0220443bde4be439f276a6ce793664b463580e210ec6c9255d68354449ac0443c76501210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6ffffffff6ea42cd8d9c8e5441c4c5f85bfe50311078730d2881494f11f4d2257777a4958010000006b48304502210090cff1c1911e771605358a8cddd5ae94c7b60cc96e50275908d9bf9d6367c79f02202bfa72e10260a146abd59d0526e1335bacfbb2b4401780e9e3a7441b0480c8da0121038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3ffffffff02a0860100000000001976a9142f4490d5263906e4887ca2996b9e207af3e7824088aca0860100000000001976a914812c13d97f9159e54e326b481b8f88a73df8507a88ac00000000" ) # Now run the attack, must trigger the exception with pytest.raises(CallException) as exc: btc.sign_tx( self.client, "Bitcoin", [inp1, inp2], [out1, out2], debug_processor=attack_processor, ) assert exc.value.args[0] in ( proto.FailureType.ProcessError, proto.FailureType.DataError, ) assert exc.value.args[1].endswith( "Transaction has changed during signing")
def test_send_bitcoin_gold_change(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/156'/0'/0/0"), amount=1995344, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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 self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "010000000185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b5225000000006b483045022100963904da0731b71ce468afd45366dd80fbff566ec0d39c1161ab85d17459c7ca02202f5c24a7a7272d98b14a3f5bc000c7cde8ac0eb773f20f4c3131518186cc98854121023bd0ec4022d12d0106c5b7308a25572953ba1951f576f691354a7b147ee0cc1fffffffff0272ee1c00000000001976a9141c82b9c11f193ad82413caadc0955730572b50ae88acec1e0100000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac00000000" )
def check_sign_tx(client, coin_name, inputs, outputs, fee_too_high=False, failure=None): __tracebackhide__ = True expected_responses = [] txes = tx_api[coin_name] t = proto.RequestType b = proto.ButtonRequestType def tx_request(request_type, **kwargs): if kwargs: details = proto.TxRequestDetailsType(**kwargs) else: details = None return proto.TxRequest(request_type=request_type, details=details) def btn(code): return proto.ButtonRequest(code=code) for i, inp in enumerate(inputs): expected_responses += [ tx_request(t.TXINPUT, request_index=i), tx_request(t.TXMETA, tx_hash=inp.prev_hash), ] if inp.script_type in ( proto.InputScriptType.SPENDP2SHWITNESS, proto.InputScriptType.SPENDWITNESS, ): continue prev_hash = hexlify(inp.prev_hash).decode() prev_tx = txes.get_tx(prev_hash) for pi in range(len(prev_tx.inputs)): r = tx_request(t.TXINPUT, request_index=pi, tx_hash=inp.prev_hash) expected_responses.append(r) for po in range(len(prev_tx.bin_outputs)): r = tx_request(t.TXOUTPUT, request_index=po, tx_hash=inp.prev_hash) expected_responses.append(r) for i, outp in enumerate(outputs): expected_responses.append(tx_request(t.TXOUTPUT, request_index=i)) if outp.address is not None or hasattr(outp, "force_confirm"): expected_responses.append(btn(b.ConfirmOutput)) if fee_too_high: expected_responses.append(btn(b.FeeOverThreshold)) if failure is not None: expected_responses.append(proto.Failure(code=failure)) else: expected_responses.append(btn(b.SignTx)) input_requests = [ tx_request(t.TXINPUT, request_index=i) for i in range(len(inputs)) ] output_requests = [ tx_request(t.TXOUTPUT, request_index=i) for i in range(len(outputs)) ] # No idea why the flow is like this. But it is. for _ in range(len(inputs)): expected_responses.extend(input_requests) expected_responses.extend(output_requests) # and once more for good measure expected_responses.extend(output_requests) expected_responses.append(tx_request(t.TXFINISHED)) with client: client.set_expected_responses(expected_responses) return btc.sign_tx(client, coin_name, inputs, outputs)
def test_send_p2sh_witness_change(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("49'/156'/0'/1/0"), amount=123456789, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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 self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API ) assert ( serialized_tx.hex() == "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250000000017160014b5355d001e720d8f4513da00ff2bba4dcf9d39fcffffffff02e0aebb00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac3df39f060000000017a9140cd03822b799a452c106d1b3771844a067b17f118702483045022100d79b33384c686d8dd40ad5f84f46691d30994992c1cb42e934c2a625d86cb2f902206859805a9a98ba140b71a9d4b9a6b8df94a9424f9c40f3bd804149fd6e278d63412102ecea08b559fc5abd009acf77cfae13fa8a3b1933e3e031956c65c12cec8ca3e300000000" )
def test_attack_change_input_address(self): # This unit test attempts to modify input address after the Trezor checked # that it matches the change output self.setup_mnemonic_allallall() self.client.set_tx_api(tx_api["Testnet"]) inp1 = proto.TxInputType( address_n=parse_path("44'/1'/4'/0/0"), # moUJnmge8SRXuediK7bW6t4YfrPqbE6hD7 prev_hash=TXHASH_d2dcda, prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address="mwue7mokpBRAsJtHqEMcRPanYBmsSmYKvY", amount=100000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address_n=parse_path("44'/1'/12345'/1/0"), amount=123400000 - 5000 - 100000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) global run_attack run_attack = True def attack_processor(req, msg): global run_attack if req.details.tx_hash is not None: return msg if req.request_type != proto.RequestType.TXINPUT: return msg if req.details.request_index != 0: return msg if not run_attack: return msg msg.inputs[0].address_n[2] = H_(12345) run_attack = False return msg # Test if the transaction can be signed normally (_, serialized_tx) = btc.sign_tx(self.client, "Testnet", [inp1], [out1, out2]) assert ( hexlify(serialized_tx) == b"0100000001243e15b53cc553d93ec4e27e16984adc3d885ef107c613a7577fea47f5dadcd2010000006a47304402207d517dcb6b823bba4d252da096795a7f914d0c477aee26e554ba61653c45608a02202cba1e805c586c830472f399510be5d42c2fcfd67b8a6b0690cbe8a3e6e475e801210364430c9122948e525e2f1c6d88f00f47679274f0810fd8c63754954f310995c1ffffffff02a0860100000000001976a914b3cc67f3349974d0f1b50e9bb5dfdf226f888fa088ac18555907000000001976a91485a3f5b0d23cdd61f5f8e1eb8c9ca0890dd15a9788ac00000000" ) # Now run the attack, must trigger the exception with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_d2dcda), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d2dcda), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d2dcda), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_d2dcda), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest( code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.Failure(code=proto.FailureType.ProcessError), ]) # Now run the attack, must trigger the exception with pytest.raises(CallException) as exc: btc.sign_tx( self.client, "Testnet", [inp1], [out1, out2], debug_processor=attack_processor, ) assert exc.value.args[0] == proto.FailureType.ProcessError if TREZOR_VERSION == 1: assert exc.value.args[1].endswith("Failed to compile input") else: assert exc.value.args[1].endswith( "Transaction has changed during signing")
def test_send_bitcoin_gold_nochange(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/156'/0'/1/0"), amount=1896050, prev_hash=bytes.fromhex( "25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985" ), 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=bytes.fromhex( "db77c2461b840e6edbe7f9280043184a98e020d9795c1b65cb7cef2551a8fb18" ), prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=1934960, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Bgold", [inp1, inp2], [out1], prev_txes=TX_API ) assert ( serialized_tx.hex() == "010000000285c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b5225000000006b483045022100928852076c9fab160c07564cd54691af1cbc37fb28f0b7bee7299c7925ef62f0022058856387afecc6508f2f04ecdfd292a13026a5b2107ebdd2cc789bdf8820d552412102a6c3998d0d4e5197ff41aab5c53580253b3b91f583f4c31f7624be7dc83ce15fffffffff18fba85125ef7ccb651b5c79d920e0984a18430028f9e7db6e0e841b46c277db010000006b483045022100faa2f4f01cc95e680349a093923aae0aa2ea01429873555aa8a84bf630ef33a002204c3f4bf567e2d20540c0f71dc278481d6ccb6b95acda2a2f87ce521c79d6b872412102d54a7e5733b1635e5e9442943f48179b1700206b2d1925250ba10f1c86878be8ffffffff0170861d00000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac00000000" )
def test_send_decred_change(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( # TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz address_n=parse_path("m/44'/1'/0'/0/0"), prev_hash=TXHASH_5e6e35, prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, decred_tree=0, ) inp2 = proto.TxInputType( # TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz address_n=parse_path("m/44'/1'/0'/0/0"), prev_hash=TXHASH_ccf95b, prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, decred_tree=0, ) inp3 = proto.TxInputType( # Tskt39YEvzoJ5KBDH4f1auNzG3jViVjZ2RV address_n=parse_path("m/44'/1'/0'/0/1"), prev_hash=TXHASH_f395ef, prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, decred_tree=0, ) out1 = proto.TxOutputType( address="TsWjioPrP8E1TuTMmTrVMM2BA4iPrjQXBpR", amount=489975000, script_type=proto.OutputScriptType.PAYTOADDRESS, decred_script_version=0, ) out2 = proto.TxOutputType( # TsaSFRwfN9muW5F6ZX36iSksc9hruiC5F97 address_n=parse_path("m/44'/1'/0'/1/0"), amount=100000000, script_type=proto.OutputScriptType.PAYTOADDRESS, decred_script_version=0, ) with self.client: self.client.set_expected_responses( [ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_5e6e35), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_5e6e35, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_5e6e35, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_ccf95b), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_ccf95b, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_ccf95b, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_ccf95b, request_index=1 ), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=2), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_f395ef), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_f395ef, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_f395ef, request_index=0 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( tx_hash=TXHASH_f395ef, request_index=1 ), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=2), ), proto.TxRequest(request_type=proto.RequestType.TXFINISHED), ] ) _, serialized_tx = btc.sign_tx( self.client, "Decred Testnet", [inp1, inp2, inp3], [out1, out2], prev_txes=TX_API, ) assert ( serialized_tx.hex() == "010000000370b95980a47b9bcb4ec2c2b450888a53179b1a5fdb23f5023cc533a300356e5e0000000000ffffffff74bc93bcfce18aff2e522d6822817522e2815a00175b2eae59ef20d20f5bf9cc0100000000ffffffff13317ab453832deabd684d2302eed42580c28ba3e715db66a731a8723eef95f30000000000ffffffff02d86c341d0000000000001976a9143eb656115197956125365348c542e37b6d3d259988ac00e1f5050000000000001976a9143ee6f9d662e7be18373d80e5eb44627014c2bf6688ac000000000000000003000000000000000000000000ffffffff6a47304402200e50a6d43c462045917792e7d03b4354900c3baccb7abef66f556a32b12f2ca6022031ae94fdf2a41dd6ed2e081faf0f8f1c64411a1b46eb26f7f35d94402b2bde110121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0000000000000000000000000ffffffff6a47304402204894c2f8e76c4645d2df600cdd01443aeb48807b72150c4bc10eebd126529532022054cd37462a3f0ddb85c75b4e874ab0c2aad7eebcff3e6c1ac20e1c16babe36720121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0000000000000000000000000ffffffff6b4830450221009f1ba584023da8aafd57374e83be68f1a097b906967ec9e50736f31bfc7989f102204a190fc2885e394572b5c2ced046657b1dd07abdb19144e21e78987968c7f17601210294e3e5e77e22eea0e4c0d30d89beb4db7f69b4bf1ae709e411d6a06618b8f852" )