Ejemplo n.º 1
0
    def test_two_changes(self, client):
        # see 87be0736f202f7c2bff0781b42bad3e0cdcb54761939da69ea793a3735552c56

        # tx: e5040e1bc1ae7667ffb9e5248e90b2fb93cd9150234151ce90e14ab2f5933bcd
        # input 0: 0.31 BTC
        inp1 = messages.TxInputType(
            address_n=parse_path("44'/1'/0'/0/0"),
            amount=31000000,
            prev_hash=TXHASH_e5040e,
            prev_index=0,
        )

        out1 = messages.TxOutputType(
            address="msj42CCGruhRsFrGATiUuh25dtxYtnpbTx",
            amount=30090000,
            script_type=messages.OutputScriptType.PAYTOADDRESS,
        )

        out_change1 = messages.TxOutputType(
            address_n=parse_path("44'/1'/0'/1/0"),
            amount=900000,
            script_type=messages.OutputScriptType.PAYTOADDRESS,
        )

        out_change2 = messages.TxOutputType(
            address_n=parse_path("44'/1'/0'/1/1"),
            amount=10000,
            script_type=messages.OutputScriptType.PAYTOADDRESS,
        )

        with client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    messages.ButtonRequest(code=B.ConfirmOutput),
                    request_output(1),
                    request_output(2),
                    messages.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_meta(TXHASH_e5040e),
                    request_input(0, TXHASH_e5040e),
                    request_output(0, TXHASH_e5040e),
                    request_output(1, TXHASH_e5040e),
                    request_input(0),
                    request_output(0),
                    request_output(1),
                    request_output(2),
                    request_output(0),
                    request_output(1),
                    request_output(2),
                    request_finished(),
                ]
            )

            btc.sign_tx(
                client,
                "Testnet",
                [inp1],
                [out1, out_change1, out_change2],
                prev_txes=TX_CACHE_TESTNET,
            )
Ejemplo n.º 2
0
def test_send_multisig_1(client: Client):
    # input: 338e2d02e0eaf8848e38925904e51546cf22e58db5b1860c4a0e72b69c56afe5

    nodes = [
        btc.get_public_node(
            client, parse_path(f"m/49h/1h/{i}h"), coin_name="Testnet"
        ).node
        for i in range(1, 4)
    ]
    # address: 2MuqUo9axjz6FfHjSqNMu8kbF1tCjisMrbt
    multisig = messages.MultisigRedeemScriptType(
        nodes=nodes, address_n=[1, 0], signatures=[b"", b"", b""], m=2
    )

    inp1 = messages.TxInputType(
        address_n=parse_path("m/49h/1h/1h/1/0"),
        prev_hash=TXHASH_338e2d,
        prev_index=0,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        multisig=multisig,
        amount=100_000,
    )

    out1 = messages.TxOutputType(
        address="mu85iAHLpF16VyijB2wn5fcZrjT2bvrhnL",
        amount=100_000 - 10_000,
        script_type=messages.OutputScriptType.PAYTOADDRESS,
    )

    expected_responses = [
        request_input(0),
        request_output(0),
        messages.ButtonRequest(code=B.ConfirmOutput),
        messages.ButtonRequest(code=B.SignTx),
        request_input(0),
        request_meta(TXHASH_338e2d),
        request_input(0, TXHASH_338e2d),
        request_output(0, TXHASH_338e2d),
        request_output(1, TXHASH_338e2d),
        request_input(0),
        request_output(0),
        request_input(0),
        request_finished(),
    ]

    with client:
        client.set_expected_responses(expected_responses)
        signatures, _ = btc.sign_tx(
            client, "Testnet", [inp1], [out1], prev_txes=TX_API_TESTNET
        )

    # store signature
    inp1.multisig.signatures[0] = signatures[0]
    # sign with third key
    inp1.address_n[2] = H_(3)

    with client:
        client.set_expected_responses(expected_responses)
        _, serialized_tx = btc.sign_tx(
            client, "Testnet", [inp1], [out1], prev_txes=TX_API_TESTNET
        )

    assert_tx_matches(
        serialized_tx,
        hash_link="https://tbtc1.trezor.io/api/tx/0d5d04bffd49287d122f509bebd196b1ecba7cbc5f945c28bf8a26dea66e65de",
        tx_hex="01000000000101e5af569cb6720e4a0c86b1b58de522cf4615e5045992388e84f8eae0022d8e330000000023220020cf28684ff8a6dda1a7a9704dde113ddfcf236558da5ce35ad3f8477474dbdaf7ffffffff01905f0100000000001976a914953e62552a88c235c0691ec74b362a6803a7d93e88ac040047304402203aba48b0a98194a505420633eeca5acd8244061899e0a414f1b0d2de1d721b0f022001b32486e7c443e25cdfdfb14dc183ba31f5329d0078a25f7eb74f7209f347bb014830450221009cbdf84db2585abddf79165340cc0b54037f13bbe5318ec3619d0de680ebbf5d02206a2ef69e154700202ac72330e936c073f8a86cec9443273f4d8739db1019d55a0169522103d54ab3c8b81cb7f8f8088df4c62c105e8acaa2fb53b180f6bc6f922faecf3fdc21036aa47994f3f18f0976d6073ca79997003c3fa29c4f93907998fefc1151b4529b2102a092580f2828272517c402da9461425c5032860ab40180e041fbbb88ea2a520453ae00000000",
    )
Ejemplo n.º 3
0
def test_attack_mixed_inputs(client: Client):
    TRUE_AMOUNT = 123_456_789
    FAKE_AMOUNT = 120_000_000

    inp1 = messages.TxInputType(
        address_n=parse_path("m/44h/1h/0h/0/0"),
        amount=31_000_000,
        prev_hash=TXHASH_e5040e,
        prev_index=0,
        script_type=messages.InputScriptType.SPENDADDRESS,
        sequence=0xFFFFFFFD,
    )
    inp2 = messages.TxInputType(
        address_n=parse_path("m/49h/1h/0h/1/0"),
        amount=TRUE_AMOUNT,
        prev_hash=TXHASH_20912f,
        prev_index=0,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        sequence=0xFFFFFFFD,
    )
    out1 = messages.TxOutputType(
        address="mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC",
        amount=31_000_000 + TRUE_AMOUNT - 3_456_789,
        script_type=messages.OutputScriptType.PAYTOADDRESS,
    )

    expected_responses = [
        request_input(0),
        request_input(1),
        request_output(0),
        messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput),
        messages.ButtonRequest(code=messages.ButtonRequestType.FeeOverThreshold),
        messages.ButtonRequest(code=messages.ButtonRequestType.SignTx),
        request_input(0),
        request_meta(TXHASH_e5040e),
        request_input(0, TXHASH_e5040e),
        request_output(0, TXHASH_e5040e),
        request_output(1, TXHASH_e5040e),
        request_input(1),
        request_meta(TXHASH_20912f),
        request_input(0, TXHASH_20912f),
        request_output(0, TXHASH_20912f),
        request_output(1, TXHASH_20912f),
        request_input(0),
        request_input(1),
        request_output(0),
        request_input(1),
        request_output(0),
        request_input(1),
        request_finished(),
    ]

    if client.features.model == "1":
        # T1 asks for first input for witness again
        expected_responses.insert(-2, request_input(0))

    with client:
        # Sign unmodified transaction.
        # "Fee over threshold" warning is displayed - fee is the whole TRUE_AMOUNT
        client.set_expected_responses(expected_responses)
        btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1],
            prev_txes=TX_API_TESTNET,
        )

    # In Phase 1 make the user confirm a lower value of the segwit input.
    inp2.amount = FAKE_AMOUNT

    if client.features.model == "1":
        # T1 fails as soon as it encounters the fake amount.
        expected_responses = (
            expected_responses[:4] + expected_responses[5:15] + [messages.Failure()]
        )
    else:
        expected_responses = (
            expected_responses[:4] + expected_responses[5:16] + [messages.Failure()]
        )

    with pytest.raises(TrezorFailure) as e, client:
        client.set_expected_responses(expected_responses)
        btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1],
            prev_txes=TX_API_TESTNET,
        )

    assert e.value.failure.message.endswith("Invalid amount specified")
Ejemplo n.º 4
0
    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 (
            serialized_tx.hex()
            == "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_sign_tx(client: Client):
    # NOTE: FAKE input tx

    commitment_data = b"\x0fwww.example.com" + (1).to_bytes(
        ROUND_ID_LEN, "big")

    with client:
        client.use_pin_sequence([PIN])
        btc.authorize_coinjoin(
            client,
            coordinator="www.example.com",
            max_rounds=2,
            max_coordinator_fee_rate=50_000_000,  # 0.5 %
            max_fee_per_kvbyte=3500,
            n=parse_path("m/84h/1h/0h"),
            coin_name="Testnet",
            script_type=messages.InputScriptType.SPENDWITNESS,
        )

    client.call(messages.LockDevice())

    with client:
        client.set_expected_responses(
            [messages.PreauthorizedRequest, messages.OwnershipProof])
        btc.get_ownership_proof(
            client,
            "Testnet",
            parse_path("m/84h/1h/0h/1/0"),
            script_type=messages.InputScriptType.SPENDWITNESS,
            user_confirmation=True,
            commitment_data=commitment_data,
            preauthorized=True,
        )

    with client:
        client.set_expected_responses(
            [messages.PreauthorizedRequest, messages.OwnershipProof])
        btc.get_ownership_proof(
            client,
            "Testnet",
            parse_path("m/84h/1h/0h/1/5"),
            script_type=messages.InputScriptType.SPENDWITNESS,
            user_confirmation=True,
            commitment_data=commitment_data,
            preauthorized=True,
        )

    inputs = [
        messages.TxInputType(
            # seed "alcohol woman abuse must during monitor noble actual mixed trade anger aisle"
            # 84'/1'/0'/0/0
            # tb1qnspxpr2xj9s2jt6qlhuvdnxw6q55jvygcf89r2
            amount=100_000,
            prev_hash=TXHASH_e5b7e2,
            prev_index=0,
            script_type=messages.InputScriptType.EXTERNAL,
            script_pubkey=bytes.fromhex(
                "00149c02608d469160a92f40fdf8c6ccced029493088"),
            ownership_proof=bytearray.fromhex(
                "534c001901016b2055d8190244b2ed2d46513c40658a574d3bc2deb6969c0535bb818b44d2c40002483045022100a6c7d59b453efa7b4abc9bc724a94c5655ae986d5924dc29d28bcc2b859cbace022047d2bc4422a47f7b044bd6cdfbf63fe1a0ecbf11393f4c0bf8565f867a5ced16012103505f0d82bbdd251511591b34f36ad5eea37d3220c2b81a1189084431ddb3aa3d"
            ),
            commitment_data=commitment_data,
        ),
        messages.TxInputType(
            address_n=parse_path("m/84h/1h/0h/1/0"),
            amount=7_289_000,
            prev_hash=FAKE_TXHASH_f982c0,
            prev_index=1,
            script_type=messages.InputScriptType.SPENDWITNESS,
        ),
    ]
Ejemplo n.º 6
0
    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, _) = self.client.sign_tx('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) = self.client.sign_tx('Bitcoin', [
                 inp3,
             ], [
                 out1,
             ])

        assert hexlify(
            signatures2[0]
        ) == b'3045022100f5428fe0531b3095675b40d87cab607ee036fac823b22e8dcec35b65aff6e52b022032129b4577ff923d321a1c70db5a6cec5bcc142cb2c51901af8b989cced23e0d'

        # Accepted by network: tx 8382a2b2e3ec8788800c1d46d285dfa9dd4051edddd75982fad166b9273e5ac6
        assert hexlify(
            serialized_tx
        ) == b'010000000152ba4dfcde9c4bed88f55479cdea03e711ae586e9a89352a98230c4cdf1a09c601000000fdfe0000483045022100985cc1ba316d140eb4b2d4028d8cd1c451f87bff8ff679858732e516ad04cd3402207af6edda99972af0baa7702a3b7448517c8242e7bca669f6861771cdd16ee05801483045022100f5428fe0531b3095675b40d87cab607ee036fac823b22e8dcec35b65aff6e52b022032129b4577ff923d321a1c70db5a6cec5bcc142cb2c51901af8b989cced23e0d014c6952210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a790253aeffffffff01a0860100000000001976a91412e8391ad256dcdc023365978418d658dfecba1c88ac00000000'
    def test_send_decred_change(self, client):
        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 client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_meta(TXHASH_5e6e35),
                    request_input(0, TXHASH_5e6e35),
                    request_output(0, TXHASH_5e6e35),
                    request_input(1),
                    request_meta(TXHASH_ccf95b),
                    request_input(0, TXHASH_ccf95b),
                    request_output(0, TXHASH_ccf95b),
                    request_output(1, TXHASH_ccf95b),
                    request_input(2),
                    request_meta(TXHASH_f395ef),
                    request_input(0, TXHASH_f395ef),
                    request_output(0, TXHASH_f395ef),
                    request_output(1, TXHASH_f395ef),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    request_output(1),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_input(1),
                    request_input(2),
                    request_finished(),
                ]
            )
            _, serialized_tx = btc.sign_tx(
                client,
                "Decred Testnet",
                [inp1, inp2, inp3],
                [out1, out2],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex()
            == "010000000370b95980a47b9bcb4ec2c2b450888a53179b1a5fdb23f5023cc533a300356e5e0000000000ffffffff74bc93bcfce18aff2e522d6822817522e2815a00175b2eae59ef20d20f5bf9cc0100000000ffffffff13317ab453832deabd684d2302eed42580c28ba3e715db66a731a8723eef95f30000000000ffffffff02d86c341d0000000000001976a9143eb656115197956125365348c542e37b6d3d259988ac00e1f5050000000000001976a9143ee6f9d662e7be18373d80e5eb44627014c2bf6688ac000000000000000003000000000000000000000000ffffffff6a47304402200e50a6d43c462045917792e7d03b4354900c3baccb7abef66f556a32b12f2ca6022031ae94fdf2a41dd6ed2e081faf0f8f1c64411a1b46eb26f7f35d94402b2bde110121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0000000000000000000000000ffffffff6a47304402204894c2f8e76c4645d2df600cdd01443aeb48807b72150c4bc10eebd126529532022054cd37462a3f0ddb85c75b4e874ab0c2aad7eebcff3e6c1ac20e1c16babe36720121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0000000000000000000000000ffffffff6b4830450221009f1ba584023da8aafd57374e83be68f1a097b906967ec9e50736f31bfc7989f102204a190fc2885e394572b5c2ced046657b1dd07abdb19144e21e78987968c7f17601210294e3e5e77e22eea0e4c0d30d89beb4db7f69b4bf1ae709e411d6a06618b8f852"
        )
Ejemplo n.º 8
0
    def test_nonzero_opreturn(self):
        self.setup_mnemonic_nopin_nopassphrase()

        # tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
        # input 0: 0.0039 BTC

        inp1 = proto.TxInputType(
            address_n=[0],  # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
            # amount=390000,
            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])

            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")
Ejemplo n.º 9
0
    def test_opreturn(self):
        self.setup_mnemonic_nopin_nopassphrase()

        # tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
        # input 0: 0.0039 BTC

        inp1 = proto.TxInputType(
            address_n=[0],  # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
            # amount=390000,
            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),
            ])
            (signatures, serialized_tx) = btc.sign_tx(self.client, "Bitcoin",
                                                      [inp1], [out1, out2])

        assert (
            serialized_tx.hex() ==
            "010000000182488650ef25a58fef6788bd71b8212038d7f2bbe4750bc7bcb44701e85ef6d5000000006a4730440220187b7b9c340a32fc8445418ad11fb3827d2e8bac7d730e1c9ad800353e7ba62f02206c0c5820ba8882c82923a39aee8d36d6d32e13daed73f7a3d6199de5f8e7ddfd0121023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43dffffffff0260cc0500000000001976a914de9b2a8da088824e8fe51debea566617d851537888ac00000000000000001c6a1a74657374206f6620746865206f705f72657475726e206461746100000000"
        )
Ejemplo n.º 10
0
    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,
            )
Ejemplo n.º 11
0
    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"
                )
Ejemplo n.º 12
0
    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"
        )
Ejemplo n.º 13
0
    def test_two_two(self, client):
        # tx: c6be22d34946593bcad1d2b013e12f74159e69574ffea21581dad115572e031c
        # input 1: 0.0010 BTC
        # tx: 58497a7757224d1ff1941488d23087071103e5bf855f4c1c44e5c8d9d82ca46e
        # input 1: 0.0011 BTC

        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,
        )

        with client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_input(1),
                    request_output(0),
                    messages.ButtonRequest(code=B.ConfirmOutput),
                    request_output(1),
                    messages.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_meta(TXHASH_c6be22),
                    request_input(0, TXHASH_c6be22),
                    request_output(0, TXHASH_c6be22),
                    request_output(1, TXHASH_c6be22),
                    request_input(1),
                    request_meta(TXHASH_58497a),
                    request_input(0, TXHASH_58497a),
                    request_output(0, TXHASH_58497a),
                    request_output(1, TXHASH_58497a),
                    request_input(0),
                    request_input(1),
                    request_output(0),
                    request_output(1),
                    request_input(0),
                    request_input(1),
                    request_output(0),
                    request_output(1),
                    request_output(0),
                    request_output(1),
                    request_finished(),
                ]
            )
            _, serialized_tx = btc.sign_tx(
                client,
                "Bitcoin",
                [inp1, inp2],
                [out1, out2],
                prev_txes=TX_CACHE_MAINNET,
            )

        # Accepted by network: tx c63e24ed820c5851b60c54613fbc4bcb37df6cd49b4c96143e99580a472f79fb
        # The transaction was produced before Trezor implemented BIP-66, so the signature
        # is now different and txhash doesn't match what is on the blockchain.
        assert (
            tx_hash(serialized_tx).hex()
            == "6f9775545830731a316a4c2a39515b1890e9c8ab0f9e21e7c6a6ca2c1499116d"
        )
Ejemplo n.º 14
0
    def test_one_three_fee(self, client):
        # tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
        # input 0: 0.0039 BTC

        inp1 = messages.TxInputType(
            address_n=parse_path("44'/0'/0'/0/0"),
            amount=390000,
            prev_hash=TXHASH_d5f65e,
            prev_index=0,
        )

        out1 = messages.TxOutputType(
            address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1",
            amount=390000 - 80000 - 12000 - 10000,
            script_type=messages.OutputScriptType.PAYTOADDRESS,
        )

        out2 = messages.TxOutputType(
            address="13uaUYn6XAooo88QvAqAVsiVvr2mAXutqP",
            amount=12000,
            script_type=messages.OutputScriptType.PAYTOADDRESS,
        )

        out3 = messages.TxOutputType(
            address_n=parse_path("44'/0'/0'/1/0"),
            amount=80000,
            script_type=messages.OutputScriptType.PAYTOADDRESS,
        )

        with client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    messages.ButtonRequest(code=B.ConfirmOutput),
                    request_output(1),
                    messages.ButtonRequest(code=B.ConfirmOutput),
                    request_output(2),
                    messages.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_meta(TXHASH_d5f65e),
                    request_input(0, TXHASH_d5f65e),
                    request_input(1, TXHASH_d5f65e),
                    request_output(0, TXHASH_d5f65e),
                    request_input(0),
                    request_output(0),
                    request_output(1),
                    request_output(2),
                    request_output(0),
                    request_output(1),
                    request_output(2),
                    request_finished(),
                ]
            )
            _, serialized_tx = btc.sign_tx(
                client,
                "Bitcoin",
                [inp1],
                [out1, out2, out3],
                prev_txes=TX_CACHE_MAINNET,
            )

        assert (
            tx_hash(serialized_tx).hex()
            == "fedbba83b115725a713c2b1a13db09fd33de582132d520a3f6ff72503ca5da61"
        )
Ejemplo n.º 15
0
    def test_multisig_mismatch_inputs_single(self, client):
        # m/84'/1'/0' for "alcohol woman abuse ..." seed.
        node_int = deserialize(
            "Vpub5kFDCYhiYuAzjk7TBQPNFffbexHF7iAd8AVVgHQKUany7e6NQvthgk86d7DfH57DY2dwBK4PyVTDDaS1r2gjkdyJyUYGoV9qNujGSrW9Dpe"
        )

        # m/84'/1'/0' for "all all ... all" seed.
        node_ext = deserialize(
            "Vpub5jR76XyyhBaQXPSRf3PBeY3gF914d9sf7DWFVhMESEQMCdNv35XiVvp8gZsFXAv222VPHLNnAEXxMPG8DPiSuhAXfEydBf55LTLBGHCDzH2"
        )

        # tb1qpzmgzpcumztvmpu3q27wwdggqav26j9dgks92pvnne2lz9ferxgssmhzlq
        multisig_in = proto.MultisigRedeemScriptType(
            nodes=[node_int, node_ext], address_n=[0, 0], signatures=[b"", b""], m=1
        )

        multisig_out = proto.MultisigRedeemScriptType(
            nodes=[node_int, node_ext], address_n=[1, 0], signatures=[b"", b""], m=1
        )

        inp1 = proto.TxInputType(
            address_n=parse_path("84'/1'/0'/0/0"),
            amount=12300000,
            prev_hash=TXHASH_091446,
            prev_index=0,
            script_type=proto.InputScriptType.SPENDWITNESS,
        )

        inp2 = proto.TxInputType(
            address_n=parse_path("84'/1'/0'/0/0"),
            prev_hash=TXHASH_a345b8,
            prev_index=0,
            script_type=proto.InputScriptType.SPENDWITNESS,
            multisig=multisig_in,
            amount=100,
        )

        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,
            multisig=multisig_out,
            amount=12300000 + 100 - 5000000 - 10000,
        )

        with client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_input(1),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    request_output(1),
                    # Ensure that the multisig output is not identified as a change output.
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_input(1),
                    request_output(0),
                    request_output(1),
                    request_input(0),
                    request_input(1),
                    request_finished(),
                ]
            )

            _, serialized_tx = btc.sign_tx(
                client, "Testnet", [inp1, inp2], [out1, out2], prev_txes=TX_API
            )

        assert (
            serialized_tx.hex()
            == "010000000001028a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090000000000ffffffff48e37c58a68ab4899400dc0950a661817ea7bac3e4556044c685b35957b845a30000000000ffffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987f43c6f0000000000220020733ecfbbe7e47a74dde6c7645b60cdf627e90a585cde7733bc7fdaf9fe30b37402473044022037dc98b16be542a6e3e1ab32007a74192c43f2498170cc5e1dffb6847e3663e402206715102d0eb59e6461a97c78eb40a8679a04a8921fdafef25f0d3d16cc65de39012103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f8620300473044022070a24bcb00041cbed465f1f546bc59e1e353a6e182393932d5ba96e20bc32ef702202ddc76a97c01465692d5b0a0a61d653f64b9ea833af1810022110fd4d505ff950147512103505f0d82bbdd251511591b34f36ad5eea37d3220c2b81a1189084431ddb3aa3d2103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f86252ae00000000"
        )
def test_no_anonymity(client):
    # Test CoinJoin transaction giving the user's outputs no gain in anonymity.

    with client:
        btc.authorize_coinjoin(
            client,
            coordinator="www.example.com",
            max_total_fee=5005,
            fee_per_anonymity=5000000,  # 0.005 %
            n=parse_path("m/84'/1'/0'"),
            coin_name="Testnet",
            script_type=messages.InputScriptType.SPENDWITNESS,
        )

    inp1 = messages.TxInputType(
        # seed "alcohol woman abuse must during monitor noble actual mixed trade anger aisle"
        # 84'/1'/0'/0/0
        # tb1qnspxpr2xj9s2jt6qlhuvdnxw6q55jvygcf89r2
        amount=100000,
        prev_hash=TXHASH_e5b7e2,
        prev_index=0,
        script_type=messages.InputScriptType.EXTERNAL,
        ownership_proof=bytearray.fromhex(
            "534c001900016b2055d8190244b2ed2d46513c40658a574d3bc2deb6969c0535bb818b44d2c40002483045022100d4ad0374c922848c71d913fba59c81b9075e0d33e884d953f0c4b4806b8ffd0c022024740e6717a2b6a5aa03148c3a28b02c713b4e30fc8aeae67fa69eb20e8ddcd9012103505f0d82bbdd251511591b34f36ad5eea37d3220c2b81a1189084431ddb3aa3d"
        ),
    )
    inp2 = messages.TxInputType(
        address_n=parse_path("84'/1'/0'/1/0"),
        amount=7289000,
        prev_hash=TXHASH_65b811,
        prev_index=1,
        script_type=messages.InputScriptType.SPENDWITNESS,
    )

    # Other's coinjoined output.
    out1 = messages.TxOutputType(
        address="tb1qk7j3ahs2v6hrv4v282cf0tvxh0vqq7rpt3zcml",
        amount=30000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Other's coinjoined output.
    out2 = messages.TxOutputType(
        address="tb1q9cqhdr9ydetjzrct6tyeuccws9505hl96azwxk",
        amount=30000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Our coinjoined output.
    out3 = messages.TxOutputType(
        address_n=parse_path("84'/1'/0'/1/1"),
        amount=50000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Our coinjoined output.
    out4 = messages.TxOutputType(
        address_n=parse_path("84'/1'/0'/1/2"),
        amount=50000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Our change output.
    out5 = messages.TxOutputType(
        address_n=parse_path("84'/1'/0'/1/2"),
        amount=7289000 - 50000 - 50000 - 10 - 5000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Other's change output.
    out6 = messages.TxOutputType(
        address="tb1q9cqhdr9ydetjzrct6tyeuccws9505hl96azwxk",
        amount=100000 - 30000 - 30000 - 6 - 5000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Coordinator's output.
    out7 = messages.TxOutputType(
        address="mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q",
        amount=16,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )

    with pytest.raises(TrezorFailure, match="No anonymity gain"):
        btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1, out2, out3, out4, out5, out6, out7],
            prev_txes=TX_CACHE_TESTNET,
            preauthorized=True,
        )
Ejemplo n.º 17
0
    def test_15_of_15(self):
        self.setup_mnemonic_nopin_nopassphrase()
        """
        pubs = []
        for x in range(15):
            pubs.append(hexlify(self.client.get_public_node([x]).node.public_key))
        """

        # 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=unhexlify(
                    '6189e3febb5a21cee8b725aa1ef04ffce7e609448446d3a8d6f483c634ef5315'
                ),
                prev_index=1,
                script_type=proto.InputScriptType.SPENDMULTISIG,
                multisig=multisig,
            )

            with self.client:
                (sig,
                 serialized_tx) = self.client.sign_tx('Bitcoin', [
                     inp1,
                 ], [
                     out1,
                 ])
                signatures[x] = sig[0]

        # Accepted as tx id dd320786d1f58c095be0509dc56b277b6de8f2fb5517f519c6e6708414e3300b
        assert hexlify(
            serialized_tx
        ) == b'01000000011553ef34c683f4d6a8d346844409e6e7fc4ff01eaa25b7e8ce215abbfee3896101000000fd43060048304502210098e23085ad7282de988bf98afa1e9add9c9830009132f8902a9fa4624d5dc98b0220733216e70ab67791aa64be5c83d2050cb4ed9ff7eda2a1acc35da024d2ab2a670147304402201f8c11fb6e90fd616e484986e9451929797eba039882a9abcc203210948060b9022044da031530de7d9747d3c5a8e7cec04b04b7af495c9120b854ce7362af7fa05a01483045022100ea67c70186acef019bdf1551881bf38e6f88186501b64d3a756a2ce18e4ba18002201c35110325653e21e448b60053a4b5dda46b61096faf701a1faca61fcde91f00014730440220315598992f156d2f9d7b4275395fa067aa61ea95829fa17730885c86df4de70d02203eda9ade1656e2198c668603b17e197acb0969ed183ab0841303ea261205618901473044022060fdd6621edde9b8cf6776bc4eef26ace9b57514d725b7214ba11d333520a30e022044c30744f94484aec0f896233c5613a3256878ec0379f566226906b6d1b6061401483045022100b1d907e3574f60f7834c7e9f2e367998ce0461dad7d742d84ef8917d713f41f902203b3ac54f7bb2f7fb8685f582d2a94f7213a37cb508acffe29090cc06ae01588b01483045022100e3bf90ff3ad6395e42f46002f253f94ca0e8ffaa0620f2ceb4fa21493abdca4d02201d4c28b10b740bb2dc4b3695b4205c18f8c0dad2bb69540eb8a36576463cd5280147304402202cfaf9fab7dc1c9f0c3c23bd46bd6d5cea0664d914139fc9add80766ce998808022012db2802c07853e4cbe147afdf0b47e60bdcbcd31f9df19e04c177ed9aa66c6d0147304402207cbc2d83f351eee5ee91df26bb0c7e1cb07fe328cbbcdb0bb9656d37922c497302201b3435d4c71ffd1b34d45892f2a487bd79c8c7f57cc04373287642bb9610cb840147304402202dc3eab30ccb06553703e794212f43ee9a659f5e787a8374e9ea0bf6de0def7402201a70e970c21a807783313ed102bf4f0a3406ac7c84f94bc8194c5e209464d7230147304402206b04530c190c46a879d7771a6ad53acd33547e0d7fd320d5ad0b5b1fdeb5d4c202207b812be81c3419daadc942cca0c55aa32c7759fa7566c6dc35f030ca87a1c5be01483045022100ce523dddd6eef73d5ae7c44c870466e1ac5a7a77d43475e8def024af68977a1e022028be0276435bfa2ea887d6cf89fa829f96c1c7a55edc57bb3fd667d523fd3bf601473044022019410b20ebcd8eb3ee7ec1eff6bf0f9cbfaea82116811c61f3cf24af7e4434b1022009e5823f3349f695be09ae40754185300d8442a22715ddb5ffa17c4213140e7201483045022100964ef26a9074c3cdafffcfbe4bd445933f8c842ba11fd887922adcf7fabe0c82022023055d94c75ab223c767fbaa825c917e9beecbc7d5758cccf20d886c63d4b72a0147304402207aa3a98197697d258a8baae681f0b4c0ee682982f4205534e6c95a37dabaddd60220517a7ed5c03da2f242e17ccfdae0d81d6f454d7f9ea931fc62df6c0eab922186014d01025f21023230848585885f63803a0a8aecdd6538792d5c539215c91698e315bf0253b43d210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a621038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e32103477b9f0f34ae85434ce795f0c5e1e90c9420e5b5fad084d7cce9a487b94a79022103fe91eca10602d7dad4c9dab2b2a0858f71e25a219a6940749ce7a48118480dae210234716c01c2dd03fa7ee302705e2b8fbd1311895d94b1dca15e62eedea9b0968f210341fb2ead334952cf60f4481ba435c4693d0be649be01d2cfe9b02018e483e7bd2102dad8b2bce360a705c16e74a50a36459b4f8f4b78f9cd67def29d54ef6f7c7cf9210222dbe3f5f197a34a1d50e2cbe2a1085cac2d605c9e176f9a240e0fd0c669330d2103fb41afab56c9cdb013fda63d777d4938ddc3cb2ad939712da688e3ed333f95982102435f177646bdc717cb3211bf46656ca7e8d642726144778c9ce816b8b8c36ccf2102158d8e20095364031d923c7e9f7f08a14b1be1ddee21fe1a5431168e31345e5521026259794892428ca0818c8fb61d2d459ddfe20e57f50803c7295e6f4e2f5586652102815f910a8689151db627e6e262e0a2075ad5ec2993a6bc1b876a9d420923d681210318f54647f645ff01bd49fedc0219343a6a22d3ea3180a3c3d3097e4b888a8db45faeffffffff0110270000000000001976a9144a087d89f8ad16ca029c675b037c02fd1c5f9aec88ac00000000'
def test_sign_tx(client):
    with client:
        client.use_pin_sequence([PIN])
        btc.authorize_coinjoin(
            client,
            coordinator="www.example.com",
            max_total_fee=10010,
            fee_per_anonymity=5000000,  # 0.005 %
            n=parse_path("m/84'/1'/0'"),
            coin_name="Testnet",
            script_type=messages.InputScriptType.SPENDWITNESS,
        )

    client.call(messages.LockDevice())

    with client:
        client.set_expected_responses(
            [messages.PreauthorizedRequest(), messages.OwnershipProof()]
        )
        btc.get_ownership_proof(
            client,
            "Testnet",
            parse_path("84'/1'/0'/1/0"),
            script_type=messages.InputScriptType.SPENDWITNESS,
            user_confirmation=True,
            commitment_data=b"www.example.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
            preauthorized=True,
        )

    with client:
        client.set_expected_responses(
            [messages.PreauthorizedRequest(), messages.OwnershipProof()]
        )
        btc.get_ownership_proof(
            client,
            "Testnet",
            parse_path("84'/1'/0'/1/5"),
            script_type=messages.InputScriptType.SPENDWITNESS,
            user_confirmation=True,
            commitment_data=b"www.example.com" + (1).to_bytes(ROUND_ID_LEN, "big"),
            preauthorized=True,
        )

    inp1 = messages.TxInputType(
        # seed "alcohol woman abuse must during monitor noble actual mixed trade anger aisle"
        # 84'/1'/0'/0/0
        # tb1qnspxpr2xj9s2jt6qlhuvdnxw6q55jvygcf89r2
        amount=100000,
        prev_hash=TXHASH_e5b7e2,
        prev_index=0,
        script_type=messages.InputScriptType.EXTERNAL,
        ownership_proof=bytearray.fromhex(
            "534c001900016b2055d8190244b2ed2d46513c40658a574d3bc2deb6969c0535bb818b44d2c40002483045022100d4ad0374c922848c71d913fba59c81b9075e0d33e884d953f0c4b4806b8ffd0c022024740e6717a2b6a5aa03148c3a28b02c713b4e30fc8aeae67fa69eb20e8ddcd9012103505f0d82bbdd251511591b34f36ad5eea37d3220c2b81a1189084431ddb3aa3d"
        ),
    )
    inp2 = messages.TxInputType(
        address_n=parse_path("84'/1'/0'/1/0"),
        amount=7289000,
        prev_hash=TXHASH_65b811,
        prev_index=1,
        script_type=messages.InputScriptType.SPENDWITNESS,
    )

    # Other's coinjoined output.
    out1 = messages.TxOutputType(
        address="tb1qk7j3ahs2v6hrv4v282cf0tvxh0vqq7rpt3zcml",
        amount=50000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Our coinjoined output.
    out2 = messages.TxOutputType(
        address_n=parse_path("84'/1'/0'/1/1"),
        amount=50000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Our change output.
    out3 = messages.TxOutputType(
        address_n=parse_path("84'/1'/0'/1/2"),
        amount=7289000 - 50000 - 5 - 5000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Other's change output.
    out4 = messages.TxOutputType(
        address="tb1q9cqhdr9ydetjzrct6tyeuccws9505hl96azwxk",
        amount=100000 - 50000 - 5 - 5000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )
    # Coordinator's output.
    out5 = messages.TxOutputType(
        address="mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q",
        amount=10,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
    )

    with client:
        client.set_expected_responses(
            [
                messages.PreauthorizedRequest(),
                request_input(0),
                request_input(1),
                request_meta(TXHASH_65b811),
                request_input(0, TXHASH_65b811),
                request_output(0, TXHASH_65b811),
                request_output(1, TXHASH_65b811),
                request_output(0),
                request_output(1),
                request_output(2),
                request_output(3),
                request_output(4),
                request_input(0),
                request_meta(TXHASH_e5b7e2),
                request_input(0, TXHASH_e5b7e2),
                request_output(0, TXHASH_e5b7e2),
                request_output(1, TXHASH_e5b7e2),
                request_input(0),
                request_input(1),
                request_output(0),
                request_output(1),
                request_output(2),
                request_output(3),
                request_output(4),
                request_input(1),
                request_finished(),
            ]
        )
        _, serialized_tx = btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1, out2, out3, out4, out5],
            prev_txes=TX_CACHE_TESTNET,
            preauthorized=True,
        )

    assert (
        serialized_tx.hex()
        == "010000000001028abbd1cf69e00fbf60fa3ba475dccdbdba4a859ffa6bfd1ee820a75b1be2b7e50000000000ffffffff7b010c5faeb41cc5c253121b6bf69bf1a7c5867cd7f2d91569fea0ecd311b8650100000000ffffffff0550c3000000000000160014b7a51ede0a66ae36558a3ab097ad86bbd800786150c3000000000000160014167dae080bca35c9ea49c0c8335dcc4b252a1d70cb616e00000000001600141d03a4d2167961b853d6cadfeab08e4937c5dfe8c3af0000000000001600142e01768ca46e57210f0bd2c99e630e8168fa5fe50a000000000000001976a914a579388225827d9f2fe9014add644487808c695d88ac00024730440220694105071db8c6c8ba3d385d01694b6f7c17546327ab26d4c53a6503fee301e202202dd310c23a195a6cebc904b91ebd15d782e6dacd08670a72ade2795e7d3ff4ec012103505647c017ff2156eb6da20fae72173d3b681a1d0a629f95f49e884db300689f00000000"
    )

    # Test for a second time.
    btc.sign_tx(
        client,
        "Testnet",
        [inp1, inp2],
        [out1, out2, out3, out4, out5],
        prev_txes=TX_CACHE_TESTNET,
        preauthorized=True,
    )

    # Test for a third time, fees should exceed max_total_fee.
    with pytest.raises(TrezorFailure, match="Fees exceed authorized limit"):
        btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1, out2, out3, out4, out5],
            prev_txes=TX_CACHE_TESTNET,
            preauthorized=True,
        )
        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 client:
                client.set_expected_responses(
                    [
                        request_input(0),
                        request_meta(TXHASH_3f7c39),
                        request_input(0, TXHASH_3f7c39),
                        request_output(0, TXHASH_3f7c39),
                        request_output(1, TXHASH_3f7c39),
                        request_input(1),
                        request_meta(TXHASH_16da18),
                        request_input(0, TXHASH_16da18),
                        request_output(0, TXHASH_16da18),
                        request_output(1, TXHASH_16da18),
                        request_output(0),
                        request_output(1),
                        proto.ButtonRequest(code=B.ConfirmOutput),
                        proto.ButtonRequest(code=B.SignTx),
                        request_input(0),
                        request_input(1),
                        request_finished(),
                    ]
                )
                signature, serialized_tx = btc.sign_tx(
                    client,
                    "Decred Testnet",
                    [inp1, inp2],
                    [out1, out2],
                    prev_txes=TX_API,
                )

            signatures[0][index] = signature[0]
            signatures[1][index] = signature[1]
            return serialized_tx
Ejemplo n.º 20
0
    def test_send_both(self, client):
        inp1 = proto.TxInputType(
            address_n=parse_path("49'/1'/0'/1/0"),
            # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
            amount=111145789,
            prev_hash=TXHASH_091446,
            prev_index=1,
            script_type=proto.InputScriptType.SPENDP2SHWITNESS,
        )
        inp2 = proto.TxInputType(
            address_n=parse_path("84'/1'/0'/1/0"),
            amount=7289000,
            prev_hash=TXHASH_65b811,
            prev_index=1,
            script_type=proto.InputScriptType.SPENDWITNESS,
        )
        out1 = proto.TxOutputType(
            address="tb1q54un3q39sf7e7tlfq99d6ezys7qgc62a6rxllc",
            amount=12300000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )
        out2 = proto.TxOutputType(
            # address_n=parse_path("44'/1'/0'/0/0"),
            # script_type=proto.OutputScriptType.PAYTOP2SHWITNESS,
            address="2N6UeBoqYEEnybg4cReFYDammpsyDw8R2Mc",
            script_type=proto.OutputScriptType.PAYTOADDRESS,
            amount=45600000,
        )
        out3 = proto.TxOutputType(
            address="mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q",
            amount=111145789 + 7289000 - 11000 - 12300000 - 45600000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_input(1),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    request_output(1),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    request_output(2),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_input(1),
                    request_output(0),
                    request_output(1),
                    request_output(2),
                    request_input(0),
                    request_input(1),
                    request_finished(),
                ]
            )
            _, serialized_tx = btc.sign_tx(
                client, "Testnet", [inp1, inp2], [out1, out2, out3], prev_txes=TX_API
            )

        assert (
            serialized_tx.hex()
            == "010000000001028a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090100000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff7b010c5faeb41cc5c253121b6bf69bf1a7c5867cd7f2d91569fea0ecd311b8650100000000ffffffff03e0aebb0000000000160014a579388225827d9f2fe9014add644487808c695d00cdb7020000000017a91491233e24a9bf8dbb19c1187ad876a9380c12e787870d859b03000000001976a914a579388225827d9f2fe9014add644487808c695d88ac02483045022100ead79ee134f25bb585b48aee6284a4bb14e07f03cc130253e83450d095515e5202201e161e9402c8b26b666f2b67e5b668a404ef7e57858ae9a6a68c3837e65fdc69012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7902463043021f585c54a84dc7326fa60e22729accd41153c7dd4725bd4c8f751aa3a8cd8d6a0220631bfd83fc312cc6d5d129572a25178696d81eaf50c8c3f16c6121be4f4c029d012103505647c017ff2156eb6da20fae72173d3b681a1d0a629f95f49e884db300689f00000000"
        )
Ejemplo n.º 21
0
PREV_TXES = {PREV_HASH: PREV_TX}

pytestmark = pytest.mark.skip_t1


def case(id, *args, altcoin=False):
    if altcoin:
        marks = pytest.mark.altcoin
    else:
        marks = ()
    return pytest.param(*args, id=id, marks=marks)


inputs = [
    messages.TxInputType(
        address_n=parse_path("m/84h/1h/0h/0/0"),
        amount=12_300_000,
        prev_hash=PREV_HASH,
        prev_index=0,
        script_type=messages.InputScriptType.SPENDWITNESS,
    )
]

outputs = [
    messages.TxOutputType(
        address="2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp",
        amount=5_000_000,
        script_type=messages.OutputScriptType.PAYTOADDRESS,
    ),
    messages.TxOutputType(
        address="tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu",
Ejemplo n.º 22
0
    def test_send_multisig_1(self, client):
        nodes = [
            btc.get_public_node(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=TXHASH_9c3192,
            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 client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_input(0),
                    request_finished(),
                ]
            )
            signatures, _ = btc.sign_tx(
                client, "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)
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_input(0),
                    request_finished(),
                ]
            )
            _, serialized_tx = btc.sign_tx(
                client, "Testnet", [inp1], [out1], prev_txes=TX_API
            )

        assert (
            serialized_tx.hex()
            == "01000000000101be0210025c5be68a473f6a38bf53b53bc88d5c46567616026dc056e72b92319c01000000232200208d398cfb58a1d9cdb59ccbce81559c095e8c6f4a3e64966ca385078d9879f95effffffff01887d180000000000220020c5f4a0a4ea7c0392efe0a9670a73264cffa90b19107cd8a8e9750ff93c77fdfb0400483045022100dd6342c65197af27d7894d8b8b88b16b568ee3b5ebfdc55fdfb7caa9650e3b4c02200c7074a5bcb0068f63d9014c7cd2b0490aba75822d315d41aad444e9b86adf5201483045022100e7e6c2d21109512ba0609e93903e84bfb7731ac3962ee2c1cad54a7a30ff99a20220421497930226c39fc3834e8d6da3fc876516239518b0e82e2dc1e3c46271a17c01695221021630971f20fa349ba940a6ba3706884c41579cd760c89901374358db5dd545b92102f2ff4b353702d2bb03d4c494be19d77d0ab53d16161b53fbcaf1afeef4ad0cb52103e9b6b1c691a12ce448f1aedbbd588e064869c79fbd760eae3b8cd8a5f1a224db53ae00000000"
        )
Ejemplo n.º 23
0
    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 (
            serialized_tx.hex()
            == "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"
                )
Ejemplo n.º 24
0
    def test_send_multisig_2(self, client):
        nodes = [
            btc.get_public_node(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=TXHASH_f41cbe,
            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 client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_input(0),
                    request_finished(),
                ]
            )
            signatures, _ = btc.sign_tx(
                client, "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)
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_input(0),
                    request_finished(),
                ]
            )
            _, serialized_tx = btc.sign_tx(
                client, "Testnet", [inp1], [out1], prev_txes=TX_API
            )

        assert (
            serialized_tx.hex()
            == "010000000001012812fe3916f228cda6c7b57d5464541265a63ad118f430a805eeec8bddbe1cf40000000000ffffffff01a0791800000000002200201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a10400473044022001b7f4f21a8ddcd5e0faaaee3b95515bf8b84f2a7cbfdf66996c64123617a5cf02202fc6a776a7225420dbca759ad4ac83a61d15bf8d2883b6bf1aa31de7437f9b6e0147304402206c4125c1189a3b3e93a77cdf54c60c0538b80e5a03ec74e6ac776dfa77706ee4022035be14de76259b9d8a24863131a06a65b95df02f7d3ace90d52b37e8d94b167f0169522103bab8ecdd9ae2c51a0dc858f4c751b27533143bf6013ba1725ba8a4ecebe7de8c21027d5e55696c875308b03f2ca3d8637f51d3e35da9456a5187aa14b3de8a89534f2103b78eabaea8b3a4868be4f4bb96d6f66973f7081faa7f1cafba321444611c241e53ae00000000"
        )
Ejemplo n.º 25
0
    def test_2_of_3(self):
        self.setup_mnemonic_allallall()
        nodes = [
            btc.get_public_node(self.client,
                                parse_path("48'/0'/%d'" % index)).node
            for index in range(1, 4)
        ]

        multisig = proto.MultisigRedeemScriptType(nodes=nodes,
                                                  address_n=[0, 0],
                                                  signatures=[b"", b"", b""],
                                                  m=2)
        # Let's go to sign with key 1
        inp1 = proto.TxInputType(
            address_n=parse_path("48'/0'/1'/0/0"),
            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],
                                         prev_txes=TX_API)

        assert (
            signatures1[0].hex() ==
            "3044022052f4a3dc5ca3e86ed66abb1e2b4d9b9ace7d96f5615944beea19e58280847c2902201bd3ff32a38366a4eed0373e27da26ebc0d2a4c2bbeffd83e8a60e313d95b9e3"
        )

        # ---------------------------------------
        # Let's do second signature using 3rd key

        multisig = proto.MultisigRedeemScriptType(
            nodes=nodes,
            address_n=[0, 0],
            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=parse_path("48'/0'/3'/0/0"),
            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],
                                                     prev_txes=TX_API)

        assert (
            signatures2[0].hex() ==
            "304402203828fd48540811be6a1b12967e7012587c46e6f05c78d42471e7b25c06bc7afc0220749274bc1aa698335b00400c5ba946a70b6b46c711324fbc4989279737a57f49"
        )

        assert (
            serialized_tx.hex() ==
            "010000000152ba4dfcde9c4bed88f55479cdea03e711ae586e9a89352a98230c4cdf1a09c601000000fc00473044022052f4a3dc5ca3e86ed66abb1e2b4d9b9ace7d96f5615944beea19e58280847c2902201bd3ff32a38366a4eed0373e27da26ebc0d2a4c2bbeffd83e8a60e313d95b9e30147304402203828fd48540811be6a1b12967e7012587c46e6f05c78d42471e7b25c06bc7afc0220749274bc1aa698335b00400c5ba946a70b6b46c711324fbc4989279737a57f49014c6952210203ed6187880ae932660086e55d4561a57952dd200aa3ed2aa66b73e5723a0ce7210360e7f32fd3c8dee27a166f6614c598929699ee66acdcbda5fb24571bf2ae1ca021037c4c7e5d3293ab0f97771dcfdf83caadab341f427f54713da8b2c590a834f03b53aeffffffff01a0860100000000001976a91412e8391ad256dcdc023365978418d658dfecba1c88ac00000000"
        )
Ejemplo n.º 26
0
    def test_send_multisig_3_change(self, client):
        nodes = [
            btc.get_public_node(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=TXHASH_c93480,
            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 client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_input(0),
                    request_finished(),
                ]
            )
            signatures, _ = btc.sign_tx(
                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)
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_input(0),
                    request_finished(),
                ]
            )
            _, serialized_tx = btc.sign_tx(
                client, "Testnet", [inp1], [out1], prev_txes=TX_API
            )

        assert (
            serialized_tx.hex()
            == "01000000000101fc7901dd033f8c02da14f3ac916b6498036b80b4a0b4dc124e02c2bb408034c90000000000ffffffff01b87518000000000017a914536250d41937e5b641082447580ff6a8e46c122a870400473044022003c26107a5a47f1f900ef8aa758977530cd13ea37a33971abae8d75cac2f9f34022039e2b8c2c1d0c24ff4fc026652e1f27ad8e3ed6c9bf485f61d9aa691cb57830801483045022100963b0dc0ab46e963a66ab6e69e5e41bac6c4fedc127cac12c560b029d54fe87402205b3bcdcf313dccd78e5dce0540e7d3c8cc1bf83f13c1f9f01811eb791fd35c8101695221039dba3a72f5dc3cad17aa924b5a03c34561465f997d0cb15993f2ca2c0be771c42103cd39f3f08bbd508dce4d307d57d0c70c258c285878bfda579fa260acc738c25d2102cd631ba95beca1d64766f5540885092d0bb384a3c13b6c3a5334d0ebacf51b9553ae00000000"
        )
Ejemplo n.º 27
0
def test_attack_change_input_address(client: Client):
    # Simulates an attack where the user is coerced into unknowingly
    # transferring funds from one account to another one of their accounts,
    # potentially resulting in privacy issues.

    inp1 = messages.TxInputType(
        address_n=parse_path("m/49h/1h/0h/1/0"),
        # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
        amount=123_456_789,
        prev_hash=TXHASH_20912f,
        prev_index=0,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
    )
    out1 = messages.TxOutputType(
        address="mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC",
        amount=12_300_000,
        script_type=messages.OutputScriptType.PAYTOADDRESS,
    )
    out2 = messages.TxOutputType(
        address_n=parse_path("m/49h/1h/12h/1/0"),
        script_type=messages.OutputScriptType.PAYTOP2SHWITNESS,
        amount=123_456_789 - 11_000 - 12_300_000,
    )

    # Test if the transaction can be signed normally.
    with client:
        client.set_expected_responses(
            [
                request_input(0),
                request_output(0),
                # The user is required to confirm transfer to another account.
                messages.ButtonRequest(code=B.ConfirmOutput),
                request_output(1),
                messages.ButtonRequest(code=B.ConfirmOutput),
                messages.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_meta(TXHASH_20912f),
                request_input(0, TXHASH_20912f),
                request_output(0, TXHASH_20912f),
                request_output(1, TXHASH_20912f),
                request_input(0),
                request_output(0),
                request_output(1),
                request_input(0),
                request_finished(),
            ]
        )
        _, serialized_tx = btc.sign_tx(
            client, "Testnet", [inp1], [out1, out2], prev_txes=TX_API_TESTNET
        )

    # Transaction does not exist on the blockchain, not using assert_tx_matches()
    assert (
        serialized_tx.hex()
        == "0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001976a91414fdede0ddc3be652a0ce1afbc1b509a55b6b94888ac3df39f060000000017a9142f98413cb83ff8b3eaf1926192e68973cbd68a3a8702473044022013cbce7c575337ca05dbe03b5920a0805b510cd8dfd3180bd7c5d01cec6439cd0220050001be4bcefb585caf973caae0ffec682347f2127cc22f26efd93ee54fd852012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000"
    )

    attack_count = 2

    def attack_processor(msg):
        nonlocal attack_count

        if attack_count > 0 and msg.tx.inputs and msg.tx.inputs[0] == inp1:
            attack_count -= 1
            msg.tx.inputs[0].address_n[2] = H_(12)

        return msg

    # Now run the attack, must trigger the exception
    with client:
        client.set_filter(messages.TxAck, attack_processor)
        with pytest.raises(TrezorFailure):
            btc.sign_tx(
                client, "Testnet", [inp1], [out1, out2], prev_txes=TX_API_TESTNET
            )
Ejemplo n.º 28
0
    def test_send_multisig_4_change(self, client):
        nodes = [
            btc.get_public_node(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=TXHASH_31bc1c,
            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 client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_input(0),
                    request_finished(),
                ]
            )
            signatures, _ = btc.sign_tx(
                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)
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_input(0),
                    request_finished(),
                ]
            )
            _, serialized_tx = btc.sign_tx(
                client, "Testnet", [inp1], [out1], prev_txes=TX_API
            )

        assert (
            serialized_tx.hex()
            == "01000000000101e5918f661488bb7f0a7d04fc1dad61b5d0bad5167a05b3a637e36ace881cbc310000000023220020fa6c73de618ec134eeec0c16f6dd04d46d4347e9a4fd0a95fd7938403a4949f9ffffffff01d071180000000000220020bcea2324dacbcde5a9db90cc26b8df9cbc72010e05cb68cf034df6f0e05239a2040047304402206bbddb45f12e31e77610fd85b50a83bad4426433b1c4860b1c5ddc0a69f803720220087b0607daab14830f4b4941f16b953b38e606ad70029bac24af7267f93c4242014730440220551a0cb6b0d5b3fa0cfd0b07bb5d751494b827b1c6a08702186696cfbc18278302204f37c382876c4117cca656654599b508f2d55fc3b083dc938e3cd8491b29719601695221036a5ec3abd10501409092246fe59c6d7a15fff1a933479483c3ba98b866c5b9742103559be875179d44e438db2c74de26e0bc9842cbdefd16018eae8a2ed989e474722103067b56aad037cd8b5f569b21f9025b76470a72dc69457813d2b76e98dc0cd01a53ae00000000"
        )
Ejemplo n.º 29
0
    def test_one_one_rewards_claim(self, client):
        # prevout: 7b28bd91119e9776f0d4ebd80e570165818a829bbf4477cd1afe5149dbcd34b1:0
        # input 1: 10.9997 KMD

        inp1 = proto.TxInputType(
            address_n=parse_path(
                "44'/141'/0'/0/0"),  # R9HgJZo6JBKmPvhm7whLSR8wiHyZrEDVRi
            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:
            er = [
                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),
            ]
            if client.features.model != "1":  # extra screen for lock_time
                er += [
                    proto.ButtonRequest(code=proto.ButtonRequestType.SignTx)
                ]
            er += [
                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),
            ]
            client.set_expected_responses(er)

            details = proto.SignTx(
                version=4,
                overwintered=True,
                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"
        )
Ejemplo n.º 30
0
class TestMultisigChange(TrezorTest):
    node_ext1 = bip32.deserialize(
        "tpubDADHV9u9Y6gkggintTdMjJE3be58zKNLhpxBQyuEM6Pwx3sN9JVLmMCMN4DNVwL9AKec27z5TaWcWuHzMXiGAtcra5DjwWbvppGX4gaEGVN"
    )
    # m/1 => 02c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e
    # m/2 => 0375b9dfaad928ce1a7eed88df7c084e67d99e9ab74332419458a9a45779706801

    node_ext2 = bip32.deserialize(
        "tpubDADHV9u9Y6gkhWXBmDJ6TUhZajLWjvKukRe2w9FfhdbQpUux8Z8jnPHNAZqFRgHPg9sR7YR93xThM32M7NfRu8S5WyDtext7S62sqxeJNkd"
    )
    # m/1 => 0388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1
    # m/2 => 03a04f945d5a3685729dde697d574076de4bdf38e904f813b22a851548e1110fc0

    node_ext3 = bip32.deserialize(
        "tpubDADHV9u9Y6gkmM5ohWRGTswrc6fr7soH7e2D2ic5a86PDUaHc5Ln9EbER69cEr5bDZPa7EXguJ1MhWVzPZpZWVdG5fvoF3hfirXvRbpCCBg"
    )
    # m/1 => 02e0c21e2a7cf00b94c5421725acff97f9826598b91f2340c5ddda730caca7d648
    # m/2 => 03928301ffb8c0d7a364b794914c716ba3107cc78a6fe581028b0d8638b22e8573

    node_int = bip32.deserialize(
        "tpubDADHV9u9Y6gke2Vw3rWE8KRXmeK8PTtsF5B3Cqjo6h3SoiyRtzxjnDVG1knxrqB8BpP1dMAd6MR3Ps5UXibiFDtQuWVPXLkJ3HvttZYbH12"
    )
    # m/1 => 03f91460d79e4e463d7d90cb75254bcd62b515a99a950574c721efdc5f711dff35
    # m/2 => 038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3

    # ext1 + ext2 + int
    #   redeemscript (2 of 3): 522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c1210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653ae
    #   multisig address: 3Gj7y1FdTppx2JEDqYqAEZFnKCA4GRysKF
    #   tx: d1d08ea63255af4ad16b098e9885a252632086fa6be53301521d05253ce8a73d
    #   input 0: 0.001 BTC

    # ext1 + int + ext2
    #   redeemscript (2 of 3): 522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a6210388460dc439f4c8f5bcfc268c36e11b4375cad5c3535c336cfdf8c32c3afad5c153ae
    #   multisig address: 3QsvfB6d1LzYcpm8xyhS1N1HBRrzHTgLHB
    #   tx: a6e2829d089cee47e481b1a753a53081b40738cc87e38f1d9b23ab57d9ad4396
    #   input 0: 0.001 BTC

    # ext1 + ext3 + int
    #   redeemscript (2 of 3): 522102c0d0c5fee952620757c6128dbf327c996cd72ed3358d15d6518a1186099bc15e2102e0c21e2a7cf00b94c5421725acff97f9826598b91f2340c5ddda730caca7d648210338d78612e990f2eea0c426b5e48a8db70b9d7ed66282b3b26511e0b1c75515a653ae
    #   multisig address: 37LvC1Q5CyKbMbKMncEJdXxqGhHxrBEgPE
    #   tx: e4bc1ae5e5007a08f2b3926fe11c66612e8f73c6b00c69c7027213b84d259be3
    #   input 1: 0.001 BTC

    multisig_in1 = proto.MultisigRedeemScriptType(
        nodes=[node_ext2, node_ext1, node_int],
        address_n=[0, 0],
        signatures=[b"", b"", b""],
        m=2,
    )

    multisig_in2 = proto.MultisigRedeemScriptType(
        nodes=[node_ext1, node_ext2, node_int],
        address_n=[0, 1],
        signatures=[b"", b"", b""],
        m=2,
    )

    multisig_in3 = proto.MultisigRedeemScriptType(
        nodes=[node_ext1, node_ext3, node_int],
        address_n=[0, 1],
        signatures=[b"", b"", b""],
        m=2,
    )

    # 2N9W4z9AhAPaHghtqVQPbaTAGHdbrhKeBQw
    inp1 = proto.TxInputType(
        address_n=[H_(45), 0, 0, 0],
        prev_hash=bytes.fromhex(
            "16c6c8471b8db7a628f2b2bb86bfeefae1766463ce8692438c7fd3fce3f43ce5"
        ),
        prev_index=1,
        script_type=proto.InputScriptType.SPENDMULTISIG,
        multisig=multisig_in1,
    )

    # 2NDBG6QXQLtnQ3jRGkrqo53BiCeXfQXLdj4
    inp2 = proto.TxInputType(
        address_n=[H_(45), 0, 0, 1],
        prev_hash=bytes.fromhex(
            "d80c34ee14143a8bf61125102b7ef594118a3796cad670fa8ee15080ae155318"
        ),
        prev_index=0,
        script_type=proto.InputScriptType.SPENDMULTISIG,
        multisig=multisig_in2,
    )

    # 2MvwPWfp2XPU3S1cMwgEMKBPUw38VP5SBE4
    inp3 = proto.TxInputType(
        address_n=[H_(45), 0, 0, 1],
        prev_hash=bytes.fromhex(
            "b0946dc27ba308a749b11afecc2018980af18f79e89ad6b080b58220d856f739"
        ),
        prev_index=0,
        script_type=proto.InputScriptType.SPENDMULTISIG,
        multisig=multisig_in3,
    )

    def _responses(self, inp1, inp2, change=0):
        resp = [
            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.TXINPUT,
                details=proto.TxRequestDetailsType(request_index=1),
            ),
            proto.TxRequest(
                request_type=proto.RequestType.TXMETA,
                details=proto.TxRequestDetailsType(tx_hash=inp2.prev_hash),
            ),
            proto.TxRequest(
                request_type=proto.RequestType.TXINPUT,
                details=proto.TxRequestDetailsType(request_index=0,
                                                   tx_hash=inp2.prev_hash),
            ),
            proto.TxRequest(
                request_type=proto.RequestType.TXOUTPUT,
                details=proto.TxRequestDetailsType(request_index=0,
                                                   tx_hash=inp2.prev_hash),
            ),
            proto.TxRequest(
                request_type=proto.RequestType.TXOUTPUT,
                details=proto.TxRequestDetailsType(request_index=1,
                                                   tx_hash=inp2.prev_hash),
            ),
            proto.TxRequest(
                request_type=proto.RequestType.TXOUTPUT,
                details=proto.TxRequestDetailsType(request_index=0),
            ),
        ]
        if change != 1:
            resp.append(
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput))
        resp.append(
            proto.TxRequest(
                request_type=proto.RequestType.TXOUTPUT,
                details=proto.TxRequestDetailsType(request_index=1),
            ))
        if change != 2:
            resp.append(
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput))
        resp += [
            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.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.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.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),
        ]
        return resp

    # both outputs are external
    def test_external_external(self):
        self.setup_mnemonic_nopin_nopassphrase()

        out1 = proto.TxOutputType(
            address="muevUcG1Bb8eM2nGUGhqmeujHRX7YXjSEu",
            amount=40000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        out2 = proto.TxOutputType(
            address="mwdrpMVSJxxsM8f8xbnCHn9ERaRT1NG1UX",
            amount=44000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_expected_responses(
                self._responses(self.inp1, self.inp2))
            _, serialized_tx = btc.sign_tx(
                self.client,
                "Testnet",
                [self.inp1, self.inp2],
                [out1, out2],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0100000002e53cf4e3fcd37f8c439286ce636476e1faeebf86bbb2f228a6b78d1b47c8c61601000000b400473044022064f13801744a6c21b694f62cdb5d834e852f13ecf85ed4d0a56ba279571c24e3022010fab4cb05bdd7b24c8376dda4f62a418548eea6eb483e58675fa06e0d5c642c014c69522103dc07026aacb5918dac4e09f9da8290d0ae22161699636c22cace78082116a7792103e70db185fad69c2971f0107a42930e5d82a9ed3a11b922a96fdfc4124b63e54c2103f3fe007a1e34ac76c1a2528e9149f90f9f93739929797afab6a8e18d682fa71053aeffffffff185315ae8050e18efa70d6ca96378a1194f57e2b102511f68b3a1414ee340cd800000000b4004730440220727b2522268f913acd213c507d7801b146e5b6cef666ad44b769c26d6c762e4d022021c0c2e9e8298dee2a490d956f7ab1b2d3160c1e37a50cc6d19a5e62eb484fc9014c6952210297ad8a5df42f9e362ef37d9a4ddced89d8f7a143690649aa0d0ff049c7daca842103ed1fd93989595d7ad4b488efd05a22c0239482c9a20923f2f214a38e54f6c41a2103f91460d79e4e463d7d90cb75254bcd62b515a99a950574c721efdc5f711dff3553aeffffffff02005a6202000000001976a9149b139230e4fe91c05a37ec334dc8378f3dbe377088ac00639f02000000001976a914b0d05a10926a7925508febdbab9a5bd4cda8c8f688ac00000000"
        )

    # first external, second internal
    def test_external_internal(self):
        self.setup_mnemonic_nopin_nopassphrase()

        out1 = proto.TxOutputType(
            address="muevUcG1Bb8eM2nGUGhqmeujHRX7YXjSEu",
            amount=40000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        out2 = proto.TxOutputType(
            address_n=parse_path("45'/0/1/1"),
            amount=44000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_expected_responses(
                self._responses(self.inp1, self.inp2, change=2))
            _, serialized_tx = btc.sign_tx(
                self.client,
                "Testnet",
                [self.inp1, self.inp2],
                [out1, out2],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0100000002e53cf4e3fcd37f8c439286ce636476e1faeebf86bbb2f228a6b78d1b47c8c61601000000b400473044022064f13801744a6c21b694f62cdb5d834e852f13ecf85ed4d0a56ba279571c24e3022010fab4cb05bdd7b24c8376dda4f62a418548eea6eb483e58675fa06e0d5c642c014c69522103dc07026aacb5918dac4e09f9da8290d0ae22161699636c22cace78082116a7792103e70db185fad69c2971f0107a42930e5d82a9ed3a11b922a96fdfc4124b63e54c2103f3fe007a1e34ac76c1a2528e9149f90f9f93739929797afab6a8e18d682fa71053aeffffffff185315ae8050e18efa70d6ca96378a1194f57e2b102511f68b3a1414ee340cd800000000b4004730440220727b2522268f913acd213c507d7801b146e5b6cef666ad44b769c26d6c762e4d022021c0c2e9e8298dee2a490d956f7ab1b2d3160c1e37a50cc6d19a5e62eb484fc9014c6952210297ad8a5df42f9e362ef37d9a4ddced89d8f7a143690649aa0d0ff049c7daca842103ed1fd93989595d7ad4b488efd05a22c0239482c9a20923f2f214a38e54f6c41a2103f91460d79e4e463d7d90cb75254bcd62b515a99a950574c721efdc5f711dff3553aeffffffff02005a6202000000001976a9149b139230e4fe91c05a37ec334dc8378f3dbe377088ac00639f02000000001976a914b0d05a10926a7925508febdbab9a5bd4cda8c8f688ac00000000"
        )

    # first internal, second external
    def test_internal_external(self):
        self.setup_mnemonic_nopin_nopassphrase()

        out1 = proto.TxOutputType(
            address_n=parse_path("45'/0/1/0"),
            amount=40000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        out2 = proto.TxOutputType(
            address="mwdrpMVSJxxsM8f8xbnCHn9ERaRT1NG1UX",
            amount=44000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_expected_responses(
                self._responses(self.inp1, self.inp2, change=1))
            _, serialized_tx = btc.sign_tx(
                self.client,
                "Testnet",
                [self.inp1, self.inp2],
                [out1, out2],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0100000002e53cf4e3fcd37f8c439286ce636476e1faeebf86bbb2f228a6b78d1b47c8c61601000000b400473044022064f13801744a6c21b694f62cdb5d834e852f13ecf85ed4d0a56ba279571c24e3022010fab4cb05bdd7b24c8376dda4f62a418548eea6eb483e58675fa06e0d5c642c014c69522103dc07026aacb5918dac4e09f9da8290d0ae22161699636c22cace78082116a7792103e70db185fad69c2971f0107a42930e5d82a9ed3a11b922a96fdfc4124b63e54c2103f3fe007a1e34ac76c1a2528e9149f90f9f93739929797afab6a8e18d682fa71053aeffffffff185315ae8050e18efa70d6ca96378a1194f57e2b102511f68b3a1414ee340cd800000000b4004730440220727b2522268f913acd213c507d7801b146e5b6cef666ad44b769c26d6c762e4d022021c0c2e9e8298dee2a490d956f7ab1b2d3160c1e37a50cc6d19a5e62eb484fc9014c6952210297ad8a5df42f9e362ef37d9a4ddced89d8f7a143690649aa0d0ff049c7daca842103ed1fd93989595d7ad4b488efd05a22c0239482c9a20923f2f214a38e54f6c41a2103f91460d79e4e463d7d90cb75254bcd62b515a99a950574c721efdc5f711dff3553aeffffffff02005a6202000000001976a9149b139230e4fe91c05a37ec334dc8378f3dbe377088ac00639f02000000001976a914b0d05a10926a7925508febdbab9a5bd4cda8c8f688ac00000000"
        )

    # both outputs are external
    def test_multisig_external_external(self):
        self.setup_mnemonic_nopin_nopassphrase()

        out1 = proto.TxOutputType(
            address="2N2aFoogGntQFFwdUVPfRmutXD22ThcNTsR",
            amount=40000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        out2 = proto.TxOutputType(
            address="2NFJjQcU8mw4Z3ywpbek8HL1VoJ27GDrkHw",
            amount=44000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_expected_responses(
                self._responses(self.inp1, self.inp2))
            _, serialized_tx = btc.sign_tx(
                self.client,
                "Testnet",
                [self.inp1, self.inp2],
                [out1, out2],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0100000002e53cf4e3fcd37f8c439286ce636476e1faeebf86bbb2f228a6b78d1b47c8c61601000000b400473044022059394e0dfcb2d2f4a6108703f801545ca5a820c0ac6a1859d0a3854813de55fa02207b6a57d70b82932ff58163336c461653a2dc82c78ed8157159e5178ac7325390014c69522103dc07026aacb5918dac4e09f9da8290d0ae22161699636c22cace78082116a7792103e70db185fad69c2971f0107a42930e5d82a9ed3a11b922a96fdfc4124b63e54c2103f3fe007a1e34ac76c1a2528e9149f90f9f93739929797afab6a8e18d682fa71053aeffffffff185315ae8050e18efa70d6ca96378a1194f57e2b102511f68b3a1414ee340cd800000000b40047304402205a911685f5b974b2fc4a19d5ce056218773a4d20b5eaae2c2f9594929308182002201e03449f5a8813ec19f408bf1b6f4f334886d6fcf9920e300fd7678ef0724f81014c6952210297ad8a5df42f9e362ef37d9a4ddced89d8f7a143690649aa0d0ff049c7daca842103ed1fd93989595d7ad4b488efd05a22c0239482c9a20923f2f214a38e54f6c41a2103f91460d79e4e463d7d90cb75254bcd62b515a99a950574c721efdc5f711dff3553aeffffffff02005a62020000000017a91466528dd543f94d162c8111d2ec248d25ba9b90948700639f020000000017a914f1fc92c0aed1712911c70a2e09ac15ff0922652f8700000000"
        )

    # inputs match, change matches (first is change)
    def test_multisig_change_match_first(self):
        self.setup_mnemonic_nopin_nopassphrase()

        multisig_out1 = proto.MultisigRedeemScriptType(
            nodes=[self.node_ext2, self.node_ext1, self.node_int],
            address_n=[1, 0],
            signatures=[b"", b"", b""],
            m=2,
        )

        out1 = proto.TxOutputType(
            address_n=[H_(45), 0, 1, 0],
            multisig=multisig_out1,
            amount=40000000,
            script_type=proto.OutputScriptType.PAYTOMULTISIG,
        )

        out2 = proto.TxOutputType(
            address="2NFJjQcU8mw4Z3ywpbek8HL1VoJ27GDrkHw",
            amount=44000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_expected_responses(
                self._responses(self.inp1, self.inp2, change=1))
            _, serialized_tx = btc.sign_tx(
                self.client,
                "Testnet",
                [self.inp1, self.inp2],
                [out1, out2],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0100000002e53cf4e3fcd37f8c439286ce636476e1faeebf86bbb2f228a6b78d1b47c8c61601000000b400473044022059394e0dfcb2d2f4a6108703f801545ca5a820c0ac6a1859d0a3854813de55fa02207b6a57d70b82932ff58163336c461653a2dc82c78ed8157159e5178ac7325390014c69522103dc07026aacb5918dac4e09f9da8290d0ae22161699636c22cace78082116a7792103e70db185fad69c2971f0107a42930e5d82a9ed3a11b922a96fdfc4124b63e54c2103f3fe007a1e34ac76c1a2528e9149f90f9f93739929797afab6a8e18d682fa71053aeffffffff185315ae8050e18efa70d6ca96378a1194f57e2b102511f68b3a1414ee340cd800000000b40047304402205a911685f5b974b2fc4a19d5ce056218773a4d20b5eaae2c2f9594929308182002201e03449f5a8813ec19f408bf1b6f4f334886d6fcf9920e300fd7678ef0724f81014c6952210297ad8a5df42f9e362ef37d9a4ddced89d8f7a143690649aa0d0ff049c7daca842103ed1fd93989595d7ad4b488efd05a22c0239482c9a20923f2f214a38e54f6c41a2103f91460d79e4e463d7d90cb75254bcd62b515a99a950574c721efdc5f711dff3553aeffffffff02005a62020000000017a91466528dd543f94d162c8111d2ec248d25ba9b90948700639f020000000017a914f1fc92c0aed1712911c70a2e09ac15ff0922652f8700000000"
        )

    # inputs match, change matches (second is change)
    def test_multisig_change_match_second(self):
        self.setup_mnemonic_nopin_nopassphrase()

        multisig_out2 = proto.MultisigRedeemScriptType(
            nodes=[self.node_ext1, self.node_ext2, self.node_int],
            address_n=[1, 1],
            signatures=[b"", b"", b""],
            m=2,
        )

        out1 = proto.TxOutputType(
            address="2N2aFoogGntQFFwdUVPfRmutXD22ThcNTsR",
            amount=40000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        out2 = proto.TxOutputType(
            address_n=[H_(45), 0, 1, 1],
            multisig=multisig_out2,
            amount=44000000,
            script_type=proto.OutputScriptType.PAYTOMULTISIG,
        )

        with self.client:
            self.client.set_expected_responses(
                self._responses(self.inp1, self.inp2, change=2))
            _, serialized_tx = btc.sign_tx(
                self.client,
                "Testnet",
                [self.inp1, self.inp2],
                [out1, out2],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0100000002e53cf4e3fcd37f8c439286ce636476e1faeebf86bbb2f228a6b78d1b47c8c61601000000b400473044022059394e0dfcb2d2f4a6108703f801545ca5a820c0ac6a1859d0a3854813de55fa02207b6a57d70b82932ff58163336c461653a2dc82c78ed8157159e5178ac7325390014c69522103dc07026aacb5918dac4e09f9da8290d0ae22161699636c22cace78082116a7792103e70db185fad69c2971f0107a42930e5d82a9ed3a11b922a96fdfc4124b63e54c2103f3fe007a1e34ac76c1a2528e9149f90f9f93739929797afab6a8e18d682fa71053aeffffffff185315ae8050e18efa70d6ca96378a1194f57e2b102511f68b3a1414ee340cd800000000b40047304402205a911685f5b974b2fc4a19d5ce056218773a4d20b5eaae2c2f9594929308182002201e03449f5a8813ec19f408bf1b6f4f334886d6fcf9920e300fd7678ef0724f81014c6952210297ad8a5df42f9e362ef37d9a4ddced89d8f7a143690649aa0d0ff049c7daca842103ed1fd93989595d7ad4b488efd05a22c0239482c9a20923f2f214a38e54f6c41a2103f91460d79e4e463d7d90cb75254bcd62b515a99a950574c721efdc5f711dff3553aeffffffff02005a62020000000017a91466528dd543f94d162c8111d2ec248d25ba9b90948700639f020000000017a914f1fc92c0aed1712911c70a2e09ac15ff0922652f8700000000"
        )

    # inputs match, change mismatches (second tries to be change but isn't)
    def test_multisig_mismatch_change(self):
        self.setup_mnemonic_nopin_nopassphrase()

        multisig_out2 = proto.MultisigRedeemScriptType(
            nodes=[self.node_ext1, self.node_int, self.node_ext3],
            address_n=[1, 0],
            signatures=[b"", b"", b""],
            m=2,
        )

        out1 = proto.TxOutputType(
            address="2N2aFoogGntQFFwdUVPfRmutXD22ThcNTsR",
            amount=40000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        out2 = proto.TxOutputType(
            address_n=[H_(45), 0, 1, 0],
            multisig=multisig_out2,
            amount=44000000,
            script_type=proto.OutputScriptType.PAYTOMULTISIG,
        )

        with self.client:
            self.client.set_expected_responses(
                self._responses(self.inp1, self.inp2))
            _, serialized_tx = btc.sign_tx(
                self.client,
                "Testnet",
                [self.inp1, self.inp2],
                [out1, out2],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0100000002e53cf4e3fcd37f8c439286ce636476e1faeebf86bbb2f228a6b78d1b47c8c61601000000b40047304402207f9992cc0230527faf54ec6bd233307db82bc8fac039dcee418bc6feb4e96a3a02206bb4cb157ad27c123277328a877572563a45d70b844d9ab07cc42238112f8c2a014c69522103dc07026aacb5918dac4e09f9da8290d0ae22161699636c22cace78082116a7792103e70db185fad69c2971f0107a42930e5d82a9ed3a11b922a96fdfc4124b63e54c2103f3fe007a1e34ac76c1a2528e9149f90f9f93739929797afab6a8e18d682fa71053aeffffffff185315ae8050e18efa70d6ca96378a1194f57e2b102511f68b3a1414ee340cd800000000b400473044022078a41bfa87d72d6ba810d84bf568b5a29acf8b851ba6c3a8dbff079b34a7feb0022037b770c776db0b6c883c38a684a121b90a59ed1958774cbf64de70e53e29639f014c6952210297ad8a5df42f9e362ef37d9a4ddced89d8f7a143690649aa0d0ff049c7daca842103ed1fd93989595d7ad4b488efd05a22c0239482c9a20923f2f214a38e54f6c41a2103f91460d79e4e463d7d90cb75254bcd62b515a99a950574c721efdc5f711dff3553aeffffffff02005a62020000000017a91466528dd543f94d162c8111d2ec248d25ba9b90948700639f020000000017a914e6a3e2fbadb7f559f8d20c46aceae78c96fcf1d18700000000"
        )

    # inputs mismatch, change matches with first input
    def test_multisig_mismatch_inputs(self):
        self.setup_mnemonic_nopin_nopassphrase()

        multisig_out1 = proto.MultisigRedeemScriptType(
            nodes=[self.node_ext2, self.node_ext1, self.node_int],
            address_n=[1, 0],
            signatures=[b"", b"", b""],
            m=2,
        )

        out1 = proto.TxOutputType(
            address_n=[H_(45), 0, 1, 0],
            multisig=multisig_out1,
            amount=40000000,
            script_type=proto.OutputScriptType.PAYTOMULTISIG,
        )

        out2 = proto.TxOutputType(
            address="2NFJjQcU8mw4Z3ywpbek8HL1VoJ27GDrkHw",
            amount=65000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_expected_responses(
                self._responses(self.inp1, self.inp3))
            _, serialized_tx = btc.sign_tx(
                self.client,
                "Testnet",
                [self.inp1, self.inp3],
                [out1, out2],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0100000002e53cf4e3fcd37f8c439286ce636476e1faeebf86bbb2f228a6b78d1b47c8c61601000000b500483045022100d907b9339951c96ef4515ef7aff8b3c28c4c8c5875d7421aa1de9f3a94e3508302205cdc311a6c91dfbb74f1a9a940a994a65dbfb0cf6dedcaaaeee839e0b8fd016d014c69522103dc07026aacb5918dac4e09f9da8290d0ae22161699636c22cace78082116a7792103e70db185fad69c2971f0107a42930e5d82a9ed3a11b922a96fdfc4124b63e54c2103f3fe007a1e34ac76c1a2528e9149f90f9f93739929797afab6a8e18d682fa71053aeffffffff39f756d82082b580b0d69ae8798ff10a981820ccfe1ab149a708a37bc26d94b000000000b500483045022100fdad4a47d15f47cc364fe0cbed11b1ced1f9ef210bc1bd413ec4384f630c63720220752e4f09ea4e5e6623f5ebe89b3983ec6e5702f63f9bce696f10b2d594d23532014c6952210297ad8a5df42f9e362ef37d9a4ddced89d8f7a143690649aa0d0ff049c7daca842103b6321a1194e5cc47b6b7edc3f67a096e6f71ccb72440f84f390b6e98df0ea8ec2103f91460d79e4e463d7d90cb75254bcd62b515a99a950574c721efdc5f711dff3553aeffffffff02005a62020000000017a91466528dd543f94d162c8111d2ec248d25ba9b90948740d2df030000000017a914f1fc92c0aed1712911c70a2e09ac15ff0922652f8700000000"
        )