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' )
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)
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)
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))
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)
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')
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))
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)
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)
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)
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")
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)
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)
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)
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)
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)