def test_p2wpkh_in_p2sh_gen_proof(self):
        coin = coins.by_name('Bitcoin')
        seed = bip39.seed(' '.join(['all'] * 12), '')
        keychain = Keychain(seed, [[coin.curve_name, [49 | HARDENED]], ["slip21", [b"SLIP-0019"]]])
        commitment_data = b""

        node = keychain.derive([49 | HARDENED, 0 | HARDENED, 0 | HARDENED, 1, 0])
        address = address_p2wpkh_in_p2sh(node.public_key(), coin)
        script_pubkey = scripts.output_derive_script(address, coin)
        ownership_id = ownership.get_identifier(script_pubkey, keychain)

        self.assertEqual(ownership_id, unhexlify("92caf0b8daf78f1d388dbbceaec34bd2dabc31b217e32343663667f6694a3f46"))

        proof, signature = ownership.generate_proof(
            node=node,
            script_type=InputScriptType.SPENDP2SHWITNESS,
            multisig=None,
            coin=coin,
            user_confirmed=False,
            ownership_ids=[ownership_id],
            script_pubkey=script_pubkey,
            commitment_data=commitment_data,
        )
        self.assertEqual(signature, unhexlify("3045022100a37330dca699725db613dd1b30059843d1248340642162a0adef114509c9849402201126c9044b998065d40b44fd2399b52c409794bbc3bfdd358cd5fb450c94316d"))
        self.assertEqual(proof, unhexlify("534c0019000192caf0b8daf78f1d388dbbceaec34bd2dabc31b217e32343663667f6694a3f4617160014e0cffbee1925a411844f44c3b8d81365ab51d03602483045022100a37330dca699725db613dd1b30059843d1248340642162a0adef114509c9849402201126c9044b998065d40b44fd2399b52c409794bbc3bfdd358cd5fb450c94316d012103a961687895a78da9aef98eed8e1f2a3e91cfb69d2f3cf11cbd0bb1773d951928"))
        self.assertFalse(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
    def test_p2pkh_gen_proof(self):
        coin = coins.by_name('Bitcoin')
        seed = bip39.seed(' '.join(['all'] * 12), 'TREZOR')
        keychain = Keychain(seed, [[coin.curve_name, [44 | HARDENED]], ["slip21", [b"SLIP-0019"]]])
        commitment_data = b""

        node = keychain.derive([44 | HARDENED, 0 | HARDENED, 0 | HARDENED, 1, 0])
        address = node.address(coin.address_type)
        script_pubkey = scripts.output_derive_script(address, coin)
        ownership_id = ownership.get_identifier(script_pubkey, keychain)
        self.assertEqual(ownership_id, unhexlify("ccc49ac5fede0efc80725fbda8b763d4e62a221c51cc5425076cffa7722c0bda"))

        proof, signature = ownership.generate_proof(
            node=node,
            script_type=InputScriptType.SPENDADDRESS,
            multisig=None,
            coin=coin,
            user_confirmed=False,
            ownership_ids=[ownership_id],
            script_pubkey=script_pubkey,
            commitment_data=commitment_data,
        )
        self.assertEqual(signature, unhexlify("304402206682f40a12f3609a308acb872888470a07760f2f4790ee4ff62665a39c02a5fc022026f3f38a7c2b2668c2eff9cc1e712c7f254926a482bae411ad18947eba9fd21c"))
        self.assertEqual(proof, unhexlify("534c00190001ccc49ac5fede0efc80725fbda8b763d4e62a221c51cc5425076cffa7722c0bda6a47304402206682f40a12f3609a308acb872888470a07760f2f4790ee4ff62665a39c02a5fc022026f3f38a7c2b2668c2eff9cc1e712c7f254926a482bae411ad18947eba9fd21c012102f63159e21fbcb54221ec993def967ad2183a9c243c8bff6e7d60f4d5ed3b386500"))
        self.assertFalse(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
    def test_p2wpkh_gen_proof(self):
        coin = coins.by_name('Bitcoin')
        seed = bip39.seed(' '.join(['all'] * 12), '')
        keychain = Keychain(seed, [[coin.curve_name, [84 | HARDENED]], ["slip21", [b"SLIP-0019"]]])
        commitment_data = b""

        node = keychain.derive([84 | HARDENED, 0 | HARDENED, 0 | HARDENED, 1, 0])
        address = address_p2wpkh(node.public_key(), coin)
        script_pubkey = scripts.output_derive_script(address, coin)
        ownership_id = ownership.get_identifier(script_pubkey, keychain)
        self.assertEqual(ownership_id, unhexlify("a122407efc198211c81af4450f40b235d54775efd934d16b9e31c6ce9bad5707"))

        proof, signature = ownership.generate_proof(
            node=node,
            script_type=InputScriptType.SPENDWITNESS,
            multisig=None,
            coin=coin,
            user_confirmed=False,
            ownership_ids=[ownership_id],
            script_pubkey=script_pubkey,
            commitment_data=commitment_data,
        )
        self.assertEqual(signature, unhexlify("3045022100e5eaf2cb0a473b4545115c7b85323809e75cb106175ace38129fd62323d73df30220363dbc7acb7afcda022b1f8d97acb8f47c42043cfe0595583aa26e30bc8b3bb5"))
        self.assertEqual(proof, unhexlify("534c00190001a122407efc198211c81af4450f40b235d54775efd934d16b9e31c6ce9bad57070002483045022100e5eaf2cb0a473b4545115c7b85323809e75cb106175ace38129fd62323d73df30220363dbc7acb7afcda022b1f8d97acb8f47c42043cfe0595583aa26e30bc8b3bb50121032ef68318c8f6aaa0adec0199c69901f0db7d3485eb38d9ad235221dc3d61154b"))
        self.assertFalse(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
    def test_slip77(self):
        seed = bip39.seed(
            "alcohol woman abuse must during monitor noble actual mixed trade anger aisle",
            "")
        keychain = Keychain(seed, [["slip21", b"SLIP-0077"], ["secp256k1"]])

        node = keychain.derive(
            [44 | HARDENED, 1 | HARDENED, 0 | HARDENED, 0, 0])
        coin = coins.by_name('Elements')
        pubkey_hash = addresses.ecdsa_hash_pubkey(node.public_key(), coin)
        script = scripts.output_script_p2pkh(pubkey_hash)

        private_key = keychain.derive_slip77_blinding_private_key(script)
        self.assertEqual(
            private_key,
            unhexlify(
                b"26f1dc2c52222394236d76e0809516255cfcca94069fd5187c0f090d18f42ad6"
            ))
        public_key = keychain.derive_slip77_blinding_public_key(script)
        self.assertEqual(
            public_key,
            unhexlify(
                b"03e84cd853fea825bd94f5d2d46580ae0d059c734707fa7a08f5e2f612a51c1acb"
            ))
        self.assertEqual(secp256k1.publickey(private_key), public_key)
    def test_preimage_testdata(self):

        seed = bip39.seed(
            'alcohol woman abuse must during monitor noble actual mixed trade anger aisle',
            '')
        coin = coins.by_name(self.tx.coin_name)
        bip143 = Bitcoin(self.tx, None, coin)
        bip143.hash143_add_input(self.inp1)
        bip143.hash143_add_input(self.inp2)

        for txo in [self.out1, self.out2]:
            txo_bin = TxOutputBinType()
            txo_bin.amount = txo.amount
            script_pubkey = output_derive_script(txo.address, coin)
            bip143.hash143_add_output(txo_bin, script_pubkey)

        keychain = Keychain(seed, [[coin.curve_name, []]])
        node = keychain.derive(self.inp2.address_n)

        # test data public key hash
        # only for input 2 - input 1 is not segwit
        result = bip143.hash143_preimage_hash(self.inp2, [node.public_key()],
                                              1)
        self.assertEqual(
            hexlify(result),
            b'2fa3f1351618b2532228d7182d3221d95c21fd3d496e7e22e9ded873cf022a8b'
        )
예제 #6
0
    def test_validate_path(self):
        n = [
            ["ed25519", 44 | HARDENED, 134 | HARDENED],
            ["secp256k1", 44 | HARDENED, 11 | HARDENED],
        ]
        k = Keychain(b"", n)

        correct = (
            ([44 | HARDENED, 134 | HARDENED], "ed25519"),
            ([44 | HARDENED, 11 | HARDENED], "secp256k1"),
            ([44 | HARDENED, 11 | HARDENED, 12], "secp256k1"),
        )
        for c in correct:
            self.assertEqual(None, k.validate_path(*c))

        fails = [
            ([44 | HARDENED, 134], "ed25519"),  # path does not match
            ([44 | HARDENED,
              134], "secp256k1"),  # curve and path does not match
            ([44 | HARDENED,
              134 | HARDENED], "nist256p"),  # curve not included
            ([44, 134], "ed25519"),  # path does not match (non-hardened items)
            ([44 | HARDENED, 134 | HARDENED,
              123], "ed25519"),  # non-hardened item in ed25519
            ([44 | HARDENED,
              13 | HARDENED], "secp256k1"),  # invalid second item
        ]
        for f in fails:
            with self.assertRaises(wire.DataError):
                k.validate_path(*f)
    def test_match_path(self):
        n = [
            ("ed25519", [44 | HARDENED, 134 | HARDENED]),
            ("secp256k1", [44 | HARDENED, 11 | HARDENED]),
        ]
        k = Keychain(b"", n)

        correct = (
            ([44 | HARDENED, 134 | HARDENED], "ed25519"),
            ([44 | HARDENED, 11 | HARDENED], "secp256k1"),
            ([44 | HARDENED, 11 | HARDENED, 12], "secp256k1"),
        )
        for path, curve in correct:
            i, suffix = k.match_path(path)
            ns_curve, ns = k.namespaces[i]
            self.assertEqual(curve, ns_curve)

        fails = [
            [44 | HARDENED, 134],  # path does not match
            [44, 134],  # path does not match (non-hardened items)
            [44 | HARDENED, 134 | HARDENED,
             123],  # non-hardened item in ed25519 ns
            [44 | HARDENED, 13 | HARDENED],  # invalid second item
        ]
        for f in fails:
            with self.assertRaises(wire.DataError):
                k.match_path(f)
    def test_p2sh_gen_proof(self):
        coin = coins.by_name('Bitcoin')
        seed = bip39.seed(' '.join(['all'] * 12), '')
        keychain = Keychain(seed, [[coin.curve_name, [48 | HARDENED]], ["slip21", [b"SLIP-0019"]]])
        commitment_data = b"TREZOR"

        nodes = []
        for index in range(1, 3):
            node = keychain.derive([48 | HARDENED, 0 | HARDENED, index | HARDENED])
            nodes.append(HDNodeType(
                depth=node.depth(),
                child_num=node.child_num(),
                fingerprint=node.fingerprint(),
                chain_code=node.chain_code(),
                public_key=node.public_key(),
            ))

        multisig = MultisigRedeemScriptType(
            nodes=nodes,
            address_n=[0, 0],
            signatures=[b"", b""],
            m=2,
        )

        pubkeys = multisig_get_pubkeys(multisig)
        address = address_multisig_p2sh(pubkeys, multisig.m, coin)
        script_pubkey = scripts.output_derive_script(address, coin)
        ownership_id = ownership.get_identifier(script_pubkey, keychain)
        ownership_ids = [b'\x00' * 32, ownership_id]
        self.assertEqual(ownership_id, unhexlify("ce4ee8298ad105c3495a1d2b620343133521ab34de2450deeb32eec39475fef4"))

        # Sign with the first key.
        _, signature = ownership.generate_proof(
            node=keychain.derive([48 | HARDENED, 0 | HARDENED, 1 | HARDENED, 0, 0]),
            script_type=InputScriptType.SPENDMULTISIG,
            multisig=multisig,
            coin=coin,
            user_confirmed=False,
            ownership_ids=ownership_ids,
            script_pubkey=script_pubkey,
            commitment_data=commitment_data,
        )
        self.assertEqual(signature, unhexlify("3045022100bc63486f167b911dc8ef2414c4bca6dcfac999797b67159957802a9c49c2179402201cec0d53fee78fcfde496e30be35bd855d93a5be89604c55dcfdbdc515fbb41a"))
        multisig.signatures[0] = signature

        # Sign with the third key.
        proof, signature = ownership.generate_proof(
            node=keychain.derive([48 | HARDENED, 0 | HARDENED, 2 | HARDENED, 0, 0]),
            script_type=InputScriptType.SPENDMULTISIG,
            multisig=multisig,
            coin=coin,
            user_confirmed=False,
            ownership_ids=ownership_ids,
            script_pubkey=script_pubkey,
            commitment_data=commitment_data,
        )
        self.assertEqual(signature, unhexlify("3045022100d9d5966eb7858cc1a600a9c05be252c1df11d662f319a107d04e219a27c1386c02200674523e50e89164d6d5683dfbe9a50594b08011e11c18813b56cf855755afde"))
        self.assertEqual(proof, unhexlify("534c001900020000000000000000000000000000000000000000000000000000000000000000ce4ee8298ad105c3495a1d2b620343133521ab34de2450deeb32eec39475fef4db00483045022100bc63486f167b911dc8ef2414c4bca6dcfac999797b67159957802a9c49c2179402201cec0d53fee78fcfde496e30be35bd855d93a5be89604c55dcfdbdc515fbb41a01483045022100d9d5966eb7858cc1a600a9c05be252c1df11d662f319a107d04e219a27c1386c02200674523e50e89164d6d5683dfbe9a50594b08011e11c18813b56cf855755afde014752210203ed6187880ae932660086e55d4561a57952dd200aa3ed2aa66b73e5723a0ce7210360e7f32fd3c8dee27a166f6614c598929699ee66acdcbda5fb24571bf2ae1ca052ae00"))
        self.assertFalse(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
    def test_p2wsh_gen_proof(self):
        coin = coins.by_name('Bitcoin')
        seed = bip39.seed(' '.join(['all'] * 12), '')
        keychain = Keychain(seed, [[coin.curve_name, [84 | HARDENED]], ["slip21", [b"SLIP-0019"]]])
        commitment_data = b"TREZOR"

        nodes = []
        for index in range(1, 4):
            node = keychain.derive([84 | HARDENED, 0 | HARDENED, index | HARDENED])
            nodes.append(HDNodeType(
                depth=node.depth(),
                child_num=node.child_num(),
                fingerprint=node.fingerprint(),
                chain_code=node.chain_code(),
                public_key=node.public_key(),
            ))

        multisig = MultisigRedeemScriptType(
            nodes=nodes,
            address_n=[0, 1],
            signatures=[b"", b"", b""],
            m=2,
        )

        pubkeys = multisig_get_pubkeys(multisig)
        address = address_multisig_p2wsh(pubkeys, multisig.m, coin.bech32_prefix)
        script_pubkey = scripts.output_derive_script(address, coin)
        ownership_id = ownership.get_identifier(script_pubkey, keychain)
        ownership_ids = [b'\x00' * 32, ownership_id, b'\x01' * 32]
        self.assertEqual(ownership_id, unhexlify("9c27411da79a23811856f897da890452ab9e17086038c4a3e70e9efa875cb3ef"))

        # Sign with the first key.
        _, signature = ownership.generate_proof(
            node=keychain.derive([84 | HARDENED, 0 | HARDENED, 1 | HARDENED, 0, 1]),
            script_type=InputScriptType.SPENDWITNESS,
            multisig=multisig,
            coin=coin,
            user_confirmed=False,
            ownership_ids=ownership_ids,
            script_pubkey=script_pubkey,
            commitment_data=commitment_data,
        )
        self.assertEqual(signature, unhexlify("304402207568cf003ff548c52ce8e3a46a1c1e681462ca8f1651b0c82f688d41280753b4022024f977fa96fd23cf71e35d4d3c5087c375fcf1b6eed6d11ab00d552817d39ba4"))
        multisig.signatures[0] = signature

        # Sign with the third key.
        proof, signature = ownership.generate_proof(
            node=keychain.derive([84 | HARDENED, 0 | HARDENED, 3 | HARDENED, 0, 1]),
            script_type=InputScriptType.SPENDWITNESS,
            multisig=multisig,
            coin=coin,
            user_confirmed=False,
            ownership_ids=ownership_ids,
            script_pubkey=script_pubkey,
            commitment_data=commitment_data,
        )
        self.assertEqual(signature, unhexlify("304402203c4fedba34aebd213aba5b5af1ae26240a10a05cfc1c5b75c629275aa21560bb02203b90b4079c20f792f4ec533c72af31435b1e5f648ca8302730c309690133a710"))
        self.assertEqual(proof, unhexlify("534c0019000300000000000000000000000000000000000000000000000000000000000000009c27411da79a23811856f897da890452ab9e17086038c4a3e70e9efa875cb3ef010101010101010101010101010101010101010101010101010101010101010100040047304402207568cf003ff548c52ce8e3a46a1c1e681462ca8f1651b0c82f688d41280753b4022024f977fa96fd23cf71e35d4d3c5087c375fcf1b6eed6d11ab00d552817d39ba40147304402203c4fedba34aebd213aba5b5af1ae26240a10a05cfc1c5b75c629275aa21560bb02203b90b4079c20f792f4ec533c72af31435b1e5f648ca8302730c309690133a71001695221022aff3e39acd2d510c661e097a9657962ad6bf75a977c2c905152d2eb2cd58c7b210241ec073f3bb3f701a87b78fbc5f7b4daec140b87da38303173eddd0860ac55e321030205585a3eb01cbebbbb7b9138f7796117cca8e30eba5cd143ff4e3e617d221553ae"))
        self.assertFalse(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
 def test_match_path_empty_namespace(self):
     k = Keychain(b"", [("secp256k1", [])])
     correct = (
         [],
         [1, 2, 3, 4],
         [44 | HARDENED, 11 | HARDENED],
         [44 | HARDENED, 11 | HARDENED, 12],
     )
     for c in correct:
         k.match_path(c)
예제 #11
0
async def validate_path(
    ctx: wire.Context,
    validate_func: Callable[..., bool],
    keychain: seed.Keychain,
    path: List[int],
    curve: str,
    **kwargs: Any,
) -> None:
    keychain.validate_path(path, curve)
    if not validate_func(path, **kwargs):
        await show_path_warning(ctx, path)
예제 #12
0
async def sign_tx(
    ctx: wire.Context, msg: EosSignTx, keychain: seed.Keychain
) -> EosSignedTx:
    if msg.chain_id is None:
        raise wire.DataError("No chain id")
    if msg.header is None:
        raise wire.DataError("No header")
    if msg.num_actions is None or msg.num_actions == 0:
        raise wire.DataError("No actions")

    await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n, CURVE)

    node = keychain.derive(msg.address_n)
    sha = HashWriter(sha256())
    await _init(ctx, sha, msg)
    await _actions(ctx, sha, msg.num_actions)
    writers.write_variant32(sha, 0)
    writers.write_bytes(sha, bytearray(32))

    digest = sha.get_digest()
    signature = secp256k1.sign(
        node.private_key(), digest, True, secp256k1.CANONICAL_SIG_EOS
    )

    return EosSignedTx(signature=base58_encode("SIG_", "K1", signature))
예제 #13
0
    def test_validate_path_special_ed25519(self):
        n = [
            ["ed25519-keccak", 44 | HARDENED, 134 | HARDENED],
        ]
        k = Keychain(b"", n)

        correct = (([44 | HARDENED, 134 | HARDENED], "ed25519-keccak"), )
        for c in correct:
            self.assertEqual(None, k.validate_path(*c))

        fails = [
            ([44 | HARDENED, 134 | HARDENED, 1], "ed25519-keccak"),
        ]
        for f in fails:
            with self.assertRaises(wire.DataError):
                k.validate_path(*f)
예제 #14
0
    def test_bip143_preimage_testdata(self):
        seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
        coin = coins.by_name(self.tx.coin_name)
        bip143 = Bitcoin(self.tx, None, coin)
        bip143.hash143_add_input(self.inp1)
        for txo in [self.out1, self.out2]:
            txo_bin = TxOutputBinType()
            txo_bin.amount = txo.amount
            script_pubkey = output_derive_script(txo.address, coin)
            bip143.hash143_add_output(txo_bin, script_pubkey)

        keychain = Keychain(seed, [[coin.curve_name, []]])
        node = keychain.derive(self.inp1.address_n)

        # test data public key hash
        result = bip143.hash143_preimage_hash(self.inp1, [node.public_key()], 1)
        self.assertEqual(hexlify(result), b'6e28aca7041720995d4acf59bbda64eef5d6f23723d23f2e994757546674bbd9')
예제 #15
0
def get_address_for_change(
    o: TxOutputType, coin: coininfo.CoinInfo, keychain: seed.Keychain
):
    try:
        input_script_type = helpers.CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES[o.script_type]
    except KeyError:
        raise SigningError(FailureType.DataError, "Invalid script type")
    node = keychain.derive(o.address_n, coin.curve_name)
    return addresses.get_address(input_script_type, coin, node, o.multisig)
    def test_p2wpkh_verify_proof(self):
        coin = coins.by_name('Bitcoin')
        seed = bip39.seed(' '.join(['all'] * 12), 'TREZOR')
        keychain = Keychain(seed, [["slip21", [b"SLIP-0019"]]])
        commitment_data = b""

        # Proof for "all all ... all" seed without passphrase.
        script_pubkey = unhexlify("0014b2f771c370ccf219cd3059cda92bdf7f00cf2103")
        proof = unhexlify("534c00190001a122407efc198211c81af4450f40b235d54775efd934d16b9e31c6ce9bad57070002483045022100e5eaf2cb0a473b4545115c7b85323809e75cb106175ace38129fd62323d73df30220363dbc7acb7afcda022b1f8d97acb8f47c42043cfe0595583aa26e30bc8b3bb50121032ef68318c8f6aaa0adec0199c69901f0db7d3485eb38d9ad235221dc3d61154b")
        self.assertTrue(ownership.verify_nonownership(proof, script_pubkey, commitment_data, keychain, coin))
예제 #17
0
async def get_public_key(ctx: wire.Context, msg: EosGetPublicKey,
                         keychain: Keychain) -> EosPublicKey:
    await paths.validate_path(ctx, validate_full_path, keychain, msg.address_n,
                              CURVE)

    node = keychain.derive(msg.address_n)
    wif, public_key = _get_public_key(node)
    if msg.show_display:
        await require_get_public_key(ctx, wif)
    return EosPublicKey(wif, public_key)
예제 #18
0
async def get_public_key(ctx, msg: BinanceGetPublicKey, keychain: Keychain):
    await paths.validate_path(ctx, helpers.validate_full_path, keychain,
                              msg.address_n, CURVE)
    node = keychain.derive(msg.address_n)
    pubkey = node.public_key()

    if msg.show_display:
        await layout.show_pubkey(ctx, pubkey)

    return BinancePublicKey(pubkey)
예제 #19
0
def get_address_for_change(o: TxOutputType, coin: coininfo.CoinInfo,
                           keychain: seed.Keychain):
    if o.script_type == OutputScriptType.PAYTOADDRESS:
        input_script_type = InputScriptType.SPENDADDRESS
    elif o.script_type == OutputScriptType.PAYTOMULTISIG:
        input_script_type = InputScriptType.SPENDMULTISIG
    elif o.script_type == OutputScriptType.PAYTOWITNESS:
        input_script_type = InputScriptType.SPENDWITNESS
    elif o.script_type == OutputScriptType.PAYTOP2SHWITNESS:
        input_script_type = InputScriptType.SPENDP2SHWITNESS
    else:
        raise SigningError(FailureType.DataError, "Invalid script type")
    node = keychain.derive(o.address_n, coin.curve_name)
    return addresses.get_address(input_script_type, coin, node, o.multisig)
    def test_send_native_invalid_address(self):

        coin = coins.by_name('Testnet')
        seed = bip39.seed(' '.join(['all'] * 12), '')

        inp1 = TxInputType(
            # 49'/1'/0'/0/0" - tb1qqzv60m9ajw8drqulta4ld4gfx0rdh82un5s65s
            address_n=[49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 0, 0],
            amount=12300000,
            prev_hash=unhexlify('09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a'),
            prev_index=0,
            script_type=InputScriptType.SPENDWITNESS,
            sequence=0xffffffff,
            multisig=None,
        )
        out1 = TxOutputType(
            address='TB1Q694CCP5QCC0UDMFWGP692U2S2HJPQ5H407URTU',  # Error: should be lower case
            script_type=OutputScriptType.PAYTOADDRESS,
            amount=12300000 - 11000 - 5000000,
            address_n=[],
            multisig=None,
        )
        tx = SignTx(coin_name='Testnet', version=None, lock_time=None, inputs_count=1, outputs_count=1)

        messages = [
            None,

            # check fee
            TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(inputs=[inp1])),

            helpers.UiConfirmForeignAddress(address_n=inp1.address_n),
            True,

            TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(outputs=[out1])),
            None
        ]

        ns = get_namespaces_for_coin(coin)
        keychain = Keychain(seed, ns)
        signer = bitcoin.Bitcoin(tx, keychain, coin).signer()
        for request, response in chunks(messages, 2):
            if response is None:
                with self.assertRaises(wire.DataError):
                    signer.send(request)
            else:
                self.assertEqual(signer.send(request), response)
예제 #21
0
    def test_validate_path_empty_namespace(self):
        k = Keychain(b"", [["secp256k1"]])
        correct = (
            ([], "secp256k1"),
            ([1, 2, 3, 4], "secp256k1"),
            ([44 | HARDENED, 11 | HARDENED], "secp256k1"),
            ([44 | HARDENED, 11 | HARDENED, 12], "secp256k1"),
        )
        for c in correct:
            self.assertEqual(None, k.validate_path(*c))

        with self.assertRaises(wire.DataError):
            k.validate_path([1, 2, 3, 4], "ed25519")
            k.validate_path([], "ed25519")
예제 #22
0
async def get_address(ctx, msg: BinanceGetAddress, keychain: Keychain):
    HRP = "bnb"

    await paths.validate_path(ctx, helpers.validate_full_path, keychain,
                              msg.address_n, CURVE)

    node = keychain.derive(msg.address_n)
    pubkey = node.public_key()
    address = helpers.address_from_public_key(pubkey, HRP)
    if msg.show_display:
        desc = address_n_to_str(msg.address_n)
        while True:
            if await show_address(ctx, address, desc=desc):
                break
            if await show_qr(ctx, address, desc=desc):
                break

    return BinanceAddress(address=address)
    def test_match_path_special_ed25519(self):
        n = [
            ("ed25519-keccak", [44 | HARDENED, 134 | HARDENED]),
        ]
        k = Keychain(b"", n)

        correct = ([44 | HARDENED, 134 | HARDENED], )
        for c in correct:
            k.match_path(c)

        fails = [
            [44 | HARDENED, 134 | HARDENED, 1],
        ]
        for f in fails:
            with self.assertRaises(wire.DataError):
                k.match_path(f)
예제 #24
0
async def sign_tx(ctx, envelope, keychain: Keychain):
    # create transaction message -> sign it -> create signature/pubkey message -> serialize all
    if envelope.msg_count > 1:
        raise wire.DataError("Multiple messages not supported.")
    await paths.validate_path(ctx, helpers.validate_full_path, keychain,
                              envelope.address_n, CURVE)

    node = keychain.derive(envelope.address_n)

    tx_req = BinanceTxRequest()

    msg = await ctx.call_any(
        tx_req,
        MessageType.BinanceCancelMsg,
        MessageType.BinanceOrderMsg,
        MessageType.BinanceTransferMsg,
    )

    if envelope.source is None or envelope.source < 0:
        raise wire.DataError("Source missing or invalid.")

    msg_json = helpers.produce_json_for_signing(envelope, msg)

    if isinstance(msg, BinanceTransferMsg):
        await layout.require_confirm_transfer(ctx, msg)
    elif isinstance(msg, BinanceOrderMsg):
        await layout.require_confirm_order(ctx, msg)
    elif isinstance(msg, BinanceCancelMsg):
        await layout.require_confirm_cancel(ctx, msg)
    else:
        raise ValueError("input message unrecognized, is of type " +
                         type(msg).__name__)

    signature_bytes = generate_content_signature(msg_json.encode(),
                                                 node.private_key())

    return BinanceSignedTx(signature=signature_bytes,
                           public_key=node.public_key())
async def get_ownership_id(ctx, msg: GetOwnershipId, keychain: Keychain,
                           coin: coininfo.CoinInfo) -> OwnershipId:
    await validate_path(
        ctx,
        addresses.validate_full_path,
        keychain,
        msg.address_n,
        coin.curve_name,
        coin=coin,
        script_type=msg.script_type,
    )

    if msg.script_type not in common.INTERNAL_INPUT_SCRIPT_TYPES:
        raise wire.DataError("Invalid script type")

    if msg.script_type in common.SEGWIT_INPUT_SCRIPT_TYPES and not coin.segwit:
        raise wire.DataError("Segwit not enabled on this coin")

    node = keychain.derive(msg.address_n)
    address = addresses.get_address(msg.script_type, coin, node, msg.multisig)
    script_pubkey = scripts.output_derive_script(address, coin)
    ownership_id = get_identifier(script_pubkey, keychain)

    return OwnershipId(ownership_id=ownership_id)
    def test_under_threshold(self):
        coin_bitcoin = coins.by_name('Bitcoin')

        ptx1 = TransactionType(version=1, lock_time=0, inputs_cnt=2, outputs_cnt=1, extra_data_len=0)
        pinp1 = TxInputType(script_sig=unhexlify('483045022072ba61305fe7cb542d142b8f3299a7b10f9ea61f6ffaab5dca8142601869d53c0221009a8027ed79eb3b9bc13577ac2853269323434558528c6b6a7e542be46e7e9a820141047a2d177c0f3626fc68c53610b0270fa6156181f46586c679ba6a88b34c6f4874686390b4d92e5769fbb89c8050b984f4ec0b257a0e5c4ff8bd3b035a51709503'),
                            prev_hash=unhexlify('c16a03f1cf8f99f6b5297ab614586cacec784c2d259af245909dedb0e39eddcf'),
                            prev_index=1,
                            script_type=None,
                            multisig=None,
                            sequence=None)
        pinp2 = TxInputType(script_sig=unhexlify('48304502200fd63adc8f6cb34359dc6cca9e5458d7ea50376cbd0a74514880735e6d1b8a4c0221008b6ead7fe5fbdab7319d6dfede3a0bc8e2a7c5b5a9301636d1de4aa31a3ee9b101410486ad608470d796236b003635718dfc07c0cac0cfc3bfc3079e4f491b0426f0676e6643a39198e8e7bdaffb94f4b49ea21baa107ec2e237368872836073668214'),
                            prev_hash=unhexlify('1ae39a2f8d59670c8fc61179148a8e61e039d0d9e8ab08610cb69b4a19453eaf'),
                            prev_index=1,
                            multisig=None,
                            script_type=None,
                            sequence=None)
        pout1 = TxOutputBinType(script_pubkey=unhexlify('76a91424a56db43cf6f2b02e838ea493f95d8d6047423188ac'),
                                amount=390000)

        inp1 = TxInputType(address_n=[0],  # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e
                           # amount=390000,
                           prev_hash=unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882'),
                           prev_index=0,
                           amount=None,
                           multisig=None,
                           script_type=None,
                           sequence=None)
        out1 = TxOutputType(address='1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1',
                            amount=390000 - 90000,  # fee increased to 90000, slightly less than the threshold
                            script_type=OutputScriptType.PAYTOADDRESS,
                            multisig=None,
                            address_n=[])
        tx = SignTx(coin_name=None, version=None, lock_time=None, inputs_count=1, outputs_count=1)

        messages = [
            None,

            TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(inputs=[inp1])),
            helpers.UiConfirmForeignAddress(address_n=inp1.address_n),
            True,
            TxRequest(request_type=TXMETA, details=TxRequestDetailsType(request_index=None, tx_hash=unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882')), serialized=EMPTY_SERIALIZED),
            TxAck(tx=ptx1),
            TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882')), serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(inputs=[pinp1])),
            TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=1, tx_hash=unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882')), serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(inputs=[pinp2])),
            TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=unhexlify('d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882')), serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(bin_outputs=[pout1])),
            TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(outputs=[out1])),
            helpers.UiConfirmOutput(out1, coin_bitcoin),
            True,
            helpers.UiConfirmTotal(300000 + 90000, 90000, coin_bitcoin),
            True,
            TxRequest(request_type=TXINPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=TxRequestSerializedType(serialized_tx=unhexlify('0100000001'))),
        ]

        seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')

        keychain = Keychain(seed, [[coin_bitcoin.curve_name]])
        signer = bitcoin.Bitcoin(tx, keychain, coin_bitcoin).signer()
        for request, response in chunks(messages, 2):
            res = signer.send(request)
            self.assertEqual(res, response)
예제 #27
0
    def test_slip21(self):
        seed = bip39.seed(' '.join(['all'] * 12), '')
        node1 = Slip21Node(seed)
        node2 = node1.clone()
        keychain = Keychain(seed, [["slip21", b"SLIP-0021"]])

        # Key(m)
        KEY_M = unhexlify(
            b"dbf12b44133eaab506a740f6565cc117228cbf1dd70635cfa8ddfdc9af734756"
        )
        self.assertEqual(node1.key(), KEY_M)

        # Key(m/"SLIP-0021")
        KEY_M_SLIP0021 = unhexlify(
            b"1d065e3ac1bbe5c7fad32cf2305f7d709dc070d672044a19e610c77cdf33de0d"
        )
        node1.derive_path([b"SLIP-0021"])
        self.assertEqual(node1.key(), KEY_M_SLIP0021)
        self.assertIsNone(keychain.validate_path([b"SLIP-0021"], "slip21"))
        self.assertEqual(
            keychain.derive([b"SLIP-0021"], "slip21").key(), KEY_M_SLIP0021)

        # Key(m/"SLIP-0021"/"Master encryption key")
        KEY_M_SLIP0021_MEK = unhexlify(
            b"ea163130e35bbafdf5ddee97a17b39cef2be4b4f390180d65b54cf05c6a82fde"
        )
        node1.derive_path([b"Master encryption key"])
        self.assertEqual(node1.key(), KEY_M_SLIP0021_MEK)
        self.assertIsNone(
            keychain.validate_path([b"SLIP-0021", b"Master encryption key"],
                                   "slip21"))
        self.assertEqual(
            keychain.derive([b"SLIP-0021", b"Master encryption key"],
                            "slip21").key(), KEY_M_SLIP0021_MEK)

        # Key(m/"SLIP-0021"/"Authentication key")
        KEY_M_SLIP0021_AK = unhexlify(
            b"47194e938ab24cc82bfa25f6486ed54bebe79c40ae2a5a32ea6db294d81861a6"
        )
        node2.derive_path([b"SLIP-0021", b"Authentication key"])
        self.assertEqual(node2.key(), KEY_M_SLIP0021_AK)
        self.assertIsNone(
            keychain.validate_path([b"SLIP-0021", b"Authentication key"],
                                   "slip21"))
        self.assertEqual(
            keychain.derive([b"SLIP-0021", b"Authentication key"],
                            "slip21").key(), KEY_M_SLIP0021_AK)

        # Forbidden paths.
        with self.assertRaises(wire.DataError):
            self.assertFalse(keychain.validate_path([], "slip21"))
        with self.assertRaises(wire.DataError):
            self.assertFalse(
                keychain.validate_path([b"SLIP-9999", b"Authentication key"],
                                       "slip21"))
        with self.assertRaises(wire.DataError):
            keychain.derive([b"SLIP-9999", b"Authentication key"],
                            "slip21").key()
    def test_send_p2wpkh_in_p2sh(self):

        coin = coins.by_name('Groestlcoin Testnet')
        seed = bip39.seed(' '.join(['all'] * 12), '')

        inp1 = TxInputType(
            # 49'/1'/0'/1/0" - 2N1LGaGg836mqSQqiuUBLfcyGBhyZYBtBZ7
            address_n=[49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0],
            amount=123456789,
            prev_hash=unhexlify(
                '09a48bce2f9d5c6e4f0cb9ea1b32d0891855e8acfe5334f9ebd72b9ad2de60cf'
            ),
            prev_index=0,
            script_type=InputScriptType.SPENDP2SHWITNESS,
            sequence=0xfffffffe,
            multisig=None,
        )
        out1 = TxOutputType(
            address='mvbu1Gdy8SUjTenqerxUaZyYjmvedc787y',
            amount=12300000,
            script_type=OutputScriptType.PAYTOADDRESS,
            address_n=[],
            multisig=None,
        )
        out2 = TxOutputType(
            address='2N1LGaGg836mqSQqiuUBLfcyGBhyZYBtBZ7',
            script_type=OutputScriptType.PAYTOADDRESS,
            amount=123456789 - 11000 - 12300000,
            address_n=[],
            multisig=None,
        )
        tx = SignTx(coin_name='Groestlcoin Testnet',
                    version=None,
                    lock_time=650756,
                    inputs_count=1,
                    outputs_count=2)

        messages = [
            None,

            # check fee
            TxRequest(request_type=TXINPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=None),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(inputs=[inp1])),
            TxRequest(request_type=TXOUTPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=None),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(outputs=[out1])),
            helpers.UiConfirmOutput(out1, coin),
            True,
            TxRequest(request_type=TXOUTPUT,
                      details=TxRequestDetailsType(request_index=1,
                                                   tx_hash=None),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(outputs=[out2])),
            helpers.UiConfirmOutput(out2, coin),
            True,
            helpers.UiConfirmNonDefaultLocktime(tx.lock_time),
            True,
            helpers.UiConfirmTotal(123445789 + 11000, 11000, coin),
            True,

            # sign tx
            TxRequest(
                request_type=TXINPUT,
                details=TxRequestDetailsType(request_index=0, tx_hash=None),
                serialized=TxRequestSerializedType(
                    # returned serialized header
                    serialized_tx=unhexlify('01000000000101'), )),
            TxAck(tx=TransactionType(inputs=[inp1])),
            TxRequest(
                request_type=TXOUTPUT,
                details=TxRequestDetailsType(request_index=0, tx_hash=None),
                serialized=TxRequestSerializedType(
                    # returned serialized inp1
                    serialized_tx=unhexlify(
                        'cf60ded29a2bd7ebf93453feace8551889d0321beab90c4f6e5c9d2fce8ba4090000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5feffffff02'
                    ), )),
            TxAck(tx=TransactionType(outputs=[out1])),
            TxRequest(
                request_type=TXOUTPUT,
                details=TxRequestDetailsType(request_index=1, tx_hash=None),
                serialized=TxRequestSerializedType(
                    # returned serialized out1
                    serialized_tx=unhexlify(
                        'e0aebb00000000001976a914a579388225827d9f2fe9014add644487808c695d88ac'
                    ),
                    signature_index=None,
                    signature=None,
                )),
            TxAck(tx=TransactionType(outputs=[out2])),

            # segwit
            TxRequest(
                request_type=TXINPUT,
                details=TxRequestDetailsType(request_index=0, tx_hash=None),
                serialized=TxRequestSerializedType(
                    # returned serialized out2
                    serialized_tx=unhexlify(
                        '3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'
                    ),
                    signature_index=None,
                    signature=None,
                )),
            TxAck(tx=TransactionType(inputs=[inp1])),
            TxRequest(
                request_type=TXFINISHED,
                details=TxRequestDetailsType(),
                serialized=TxRequestSerializedType(
                    serialized_tx=unhexlify(
                        '02483045022100b7ce2972bcbc3a661fe320ba901e680913b2753fcb47055c9c6ba632fc4acf81022001c3cfd6c2fe92eb60f5176ce0f43707114dd7223da19c56f2df89c13c2fef80012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7904ee0900'
                    ),
                    signature_index=0,
                    signature=unhexlify(
                        '3045022100b7ce2972bcbc3a661fe320ba901e680913b2753fcb47055c9c6ba632fc4acf81022001c3cfd6c2fe92eb60f5176ce0f43707114dd7223da19c56f2df89c13c2fef80'
                    ),
                )),
        ]

        ns = get_namespaces_for_coin(coin)
        keychain = Keychain(seed, ns)
        signer = bitcoinlike.Bitcoinlike(tx, keychain, coin).signer()
        for request, response in chunks(messages, 2):
            self.assertEqual(signer.send(request), response)
        with self.assertRaises(StopIteration):
            signer.send(None)
예제 #29
0
    def test_send_p2wpkh_in_p2sh_attack_amount(self):

        coin = coins.by_name('Testnet')
        seed = bip39.seed(' '.join(['all'] * 12), '')

        inp1 = TxInputType(
            # 49'/1'/0'/1/0" - 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
            address_n=[49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0],
            amount=10,
            prev_hash=unhexlify(
                '20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'
            ),
            prev_index=0,
            script_type=InputScriptType.SPENDP2SHWITNESS,
            sequence=0xffffffff,
            multisig=None,
        )
        ptx1 = TransactionType(version=1,
                               lock_time=0,
                               inputs_cnt=1,
                               outputs_cnt=2,
                               extra_data_len=0)
        pinp1 = TxInputType(
            script_sig=unhexlify(
                '4730440220548e087d0426b20b8a571b03b9e05829f7558b80c53c12143e342f56ab29e51d02205b68cb7fb223981d4c999725ac1485a982c4259c4f50b8280f137878c232998a012102794a25b254a268e59a5869da57fbae2fadc6727cb3309321dab409b12b2fa17c'
            ),
            prev_hash=unhexlify(
                '802cabf0843b945eabe136d7fc7c89f41021658abf56cba000acbce88c41143a'
            ),
            prev_index=0,
            script_type=None,
            sequence=4294967295)
        pout1 = TxOutputBinType(script_pubkey=unhexlify(
            'a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
                                amount=123456789)
        pout2 = TxOutputBinType(script_pubkey=unhexlify(
            '76a914b84bacdcd8f4cc59274a5bfb73f804ca10f7fd1488ac'),
                                amount=865519308)

        inpattack = TxInputType(
            # 49'/1'/0'/1/0" - 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
            address_n=[49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0],
            amount=9,  # modified!
            prev_hash=unhexlify(
                '20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'
            ),
            prev_index=0,
            script_type=InputScriptType.SPENDP2SHWITNESS,
            sequence=0xffffffff,
            multisig=None,
        )
        out1 = TxOutputType(
            address='mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC',
            amount=8,
            script_type=OutputScriptType.PAYTOADDRESS,
            address_n=[],
            multisig=None,
        )
        out2 = TxOutputType(
            address_n=[49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0],
            script_type=OutputScriptType.PAYTOP2SHWITNESS,
            amount=1,
            address=None,
            multisig=None,
        )
        tx = SignTx(coin_name='Testnet',
                    version=None,
                    lock_time=None,
                    inputs_count=1,
                    outputs_count=2)

        messages = [
            None,

            # check fee
            TxRequest(request_type=TXINPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=None),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(inputs=[inpattack])),
            TxRequest(request_type=TXMETA,
                      details=TxRequestDetailsType(request_index=None,
                                                   tx_hash=inp1.prev_hash),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=ptx1),
            TxRequest(request_type=TXINPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=inp1.prev_hash),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(inputs=[pinp1])),
            TxRequest(request_type=TXOUTPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=inp1.prev_hash),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(bin_outputs=[pout1])),
            TxRequest(request_type=TXOUTPUT,
                      details=TxRequestDetailsType(request_index=1,
                                                   tx_hash=inp1.prev_hash),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(bin_outputs=[pout2])),
            TxRequest(request_type=TXOUTPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=None),
                      serialized=EMPTY_SERIALIZED),
        ]

        ns = get_namespaces_for_coin(coin)
        keychain = Keychain(seed, ns)
        signer = bitcoin.Bitcoin(tx, keychain, coin).signer()
        i = 0
        messages_count = int(len(messages) / 2)
        for request, response in chunks(messages, 2):
            if i == messages_count - 1:  # last message should throw wire.Error
                self.assertRaises(wire.DataError, signer.send, request)
            else:
                self.assertEqual(signer.send(request), response)
            i += 1
        with self.assertRaises(StopIteration):
            signer.send(None)
예제 #30
0
    def test_send_p2wpkh_in_p2sh(self):

        coin = coins.by_name('Testnet')
        seed = bip39.seed(' '.join(['all'] * 12), '')

        inp1 = TxInputType(
            # 49'/1'/0'/1/0" - 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
            address_n=[49 | 0x80000000, 1 | 0x80000000, 0 | 0x80000000, 1, 0],
            amount=123456789,
            prev_hash=unhexlify(
                '20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337'
            ),
            prev_index=0,
            script_type=InputScriptType.SPENDP2SHWITNESS,
            sequence=0xffffffff,
            multisig=None,
        )
        ptx1 = TransactionType(version=1,
                               lock_time=0,
                               inputs_cnt=1,
                               outputs_cnt=2,
                               extra_data_len=0)
        pinp1 = TxInputType(
            script_sig=unhexlify(
                '4730440220548e087d0426b20b8a571b03b9e05829f7558b80c53c12143e342f56ab29e51d02205b68cb7fb223981d4c999725ac1485a982c4259c4f50b8280f137878c232998a012102794a25b254a268e59a5869da57fbae2fadc6727cb3309321dab409b12b2fa17c'
            ),
            prev_hash=unhexlify(
                '802cabf0843b945eabe136d7fc7c89f41021658abf56cba000acbce88c41143a'
            ),
            prev_index=0,
            script_type=None,
            sequence=4294967295)
        pout1 = TxOutputBinType(script_pubkey=unhexlify(
            'a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'),
                                amount=123456789)
        pout2 = TxOutputBinType(script_pubkey=unhexlify(
            '76a914b84bacdcd8f4cc59274a5bfb73f804ca10f7fd1488ac'),
                                amount=865519308)

        out1 = TxOutputType(
            address='mhRx1CeVfaayqRwq5zgRQmD7W5aWBfD5mC',
            amount=12300000,
            script_type=OutputScriptType.PAYTOADDRESS,
            address_n=[],
            multisig=None,
        )
        out2 = TxOutputType(
            address='2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX',
            script_type=OutputScriptType.PAYTOADDRESS,
            amount=123456789 - 11000 - 12300000,
            address_n=[],
            multisig=None,
        )
        tx = SignTx(coin_name='Testnet',
                    version=None,
                    lock_time=None,
                    inputs_count=1,
                    outputs_count=2)

        messages = [
            None,

            # check fee
            TxRequest(request_type=TXINPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=None),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(inputs=[inp1])),
            TxRequest(request_type=TXMETA,
                      details=TxRequestDetailsType(request_index=None,
                                                   tx_hash=inp1.prev_hash),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=ptx1),
            TxRequest(request_type=TXINPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=inp1.prev_hash),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(inputs=[pinp1])),
            TxRequest(request_type=TXOUTPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=inp1.prev_hash),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(bin_outputs=[pout1])),
            TxRequest(request_type=TXOUTPUT,
                      details=TxRequestDetailsType(request_index=1,
                                                   tx_hash=inp1.prev_hash),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(bin_outputs=[pout2])),
            TxRequest(request_type=TXOUTPUT,
                      details=TxRequestDetailsType(request_index=0,
                                                   tx_hash=None),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(outputs=[out1])),
            helpers.UiConfirmOutput(out1, coin),
            True,
            TxRequest(request_type=TXOUTPUT,
                      details=TxRequestDetailsType(request_index=1,
                                                   tx_hash=None),
                      serialized=EMPTY_SERIALIZED),
            TxAck(tx=TransactionType(outputs=[out2])),
            helpers.UiConfirmOutput(out2, coin),
            True,
            helpers.UiConfirmTotal(123445789 + 11000, 11000, coin),
            True,

            # sign tx
            TxRequest(
                request_type=TXINPUT,
                details=TxRequestDetailsType(request_index=0, tx_hash=None),
                serialized=TxRequestSerializedType(
                    # returned serialized header
                    serialized_tx=unhexlify('01000000000101'), )),
            TxAck(tx=TransactionType(inputs=[inp1])),
            TxRequest(
                request_type=TXOUTPUT,
                details=TxRequestDetailsType(request_index=0, tx_hash=None),
                serialized=TxRequestSerializedType(
                    # returned serialized inp1
                    serialized_tx=unhexlify(
                        '37c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02'
                    ), )),
            TxAck(tx=TransactionType(outputs=[out1])),
            TxRequest(
                request_type=TXOUTPUT,
                details=TxRequestDetailsType(request_index=1, tx_hash=None),
                serialized=TxRequestSerializedType(
                    # returned serialized out1
                    serialized_tx=unhexlify(
                        'e0aebb00000000001976a91414fdede0ddc3be652a0ce1afbc1b509a55b6b94888ac'
                    ),
                    signature_index=None,
                    signature=None,
                )),
            TxAck(tx=TransactionType(outputs=[out2])),

            # segwit
            TxRequest(
                request_type=TXINPUT,
                details=TxRequestDetailsType(request_index=0, tx_hash=None),
                serialized=TxRequestSerializedType(
                    # returned serialized out2
                    serialized_tx=unhexlify(
                        '3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca87'
                    ),
                    signature_index=None,
                    signature=None,
                )),
            TxAck(tx=TransactionType(inputs=[inp1])),
            TxRequest(
                request_type=TXFINISHED,
                details=TxRequestDetailsType(),
                serialized=TxRequestSerializedType(
                    serialized_tx=unhexlify(
                        '02483045022100ccd253bfdf8a5593cd7b6701370c531199f0f05a418cd547dfc7da3f21515f0f02203fa08a0753688871c220648f9edadbdb98af42e5d8269364a326572cf703895b012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000'
                    ),
                    signature_index=0,
                    signature=unhexlify(
                        '3045022100ccd253bfdf8a5593cd7b6701370c531199f0f05a418cd547dfc7da3f21515f0f02203fa08a0753688871c220648f9edadbdb98af42e5d8269364a326572cf703895b'
                    ),
                )),
        ]

        ns = get_namespaces_for_coin(coin)
        keychain = Keychain(seed, ns)
        signer = bitcoin.Bitcoin(tx, keychain, coin).signer()
        for request, response in chunks(messages, 2):
            self.assertEqual(signer.send(request), response)
        with self.assertRaises(StopIteration):
            signer.send(None)