1import unittest 2from util import * 3 4VER_MAIN_PUBLIC = 0x0488B21E 5VER_TEST_PUBLIC = 0x043587CF 6 7FLAG_KEY_PUBLIC = 0x1 8 9ADDRESS_TYPE_P2PKH = 0x01 10ADDRESS_TYPE_P2SH_P2WPKH = 0x02 11ADDRESS_TYPE_P2WPKH = 0x04 12 13ADDRESS_VERSION_P2PKH_MAINNET = 0x00 14ADDRESS_VERSION_P2PKH_TESTNET = 0x6F 15ADDRESS_VERSION_P2SH_MAINNET = 0x05 16ADDRESS_VERSION_P2SH_TESTNET = 0xC4 17 18NETWORK_BITCOIN_MAINNET = 0x01 19NETWORK_BITCOIN_TESTNET = 0x02 20NETWORK_LIQUID_MAINNET = 0x03 21NETWORK_LIQUID_REGTEST = 0x04 22 23 24# Vector from test_bip32.py. We only need an xpub to derive addresses. 25vec = { 26 27 'm/0H/1': { 28 # xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ 29 FLAG_KEY_PUBLIC: '0488B21E025C1BD648000000012A7857' 30 '631386BA23DACAC34180DD1983734E44' 31 '4FDBF774041578E9B6ADB37C1903501E' 32 '454BF00751F24B1B489AA925215D66AF' 33 '2234E3891C3B21A52BEDB3CD711C6F6E2AF7', 34 35 "address_legacy": '1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj', 36 37 # OP_DUP OP_HASH160 [pub_key_hash] OP_EQUALVERIFY OP_CHECKSIG 38 'scriptpubkey_legacy': '76a914bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe88ac', 39 40 "address_p2sh_segwit": '3DymAvEWH38HuzHZ3VwLus673bNZnYwNXu', 41 42 # OP_HASH160 [script_hash] OP_EQUAL 43 'scriptpubkey_p2sh_segwit': 'a91486cc442a97817c245ce90ed0d31d6dbcde3841f987', 44 45 "address_segwit": 'bc1qhm6697d9d2224vfyt8mj4kw03ncec7a7fdafvt', 46 47 ## OP_0 [pub_key_hash] 48 'scriptpubkey_segwit': '0014bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe', 49 }, 50 51 'm/1H/1': { 52 # tpubDApXh6cD2fZ7WjtgpHd8yrWyYaneiFuRZa7fVjMkgxsmC1QzoXW8cgx9zQFJ81Jx4deRGfRE7yXA9A3STsxXj4CKEZJHYgpMYikkas9DBTP 53 FLAG_KEY_PUBLIC: '043587CF025C1BD648000000012A7857' 54 '631386BA23DACAC34180DD1983734E44' 55 '4FDBF774041578E9B6ADB37C1903501E' 56 '454BF00751F24B1B489AA925215D66AF' 57 '2234E3891C3B21A52BEDB3CD711C6F6E2AF7', 58 59 "address_legacy": 'mxvewdhKCenLkYgNa8irv1UM2omEWPMdEE', 60 61 # OP_DUP OP_HASH160 [pub_key_hash] OP_EQUALVERIFY OP_CHECKSIG 62 'scriptpubkey_legacy': '76a914bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe88ac', 63 64 "address_p2sh_segwit": '2N5XyEfAXtVde7mv6idZDXp5NFwajYEj9TD', 65 66 # OP_HASH160 [script_hash] OP_EQUAL 67 'scriptpubkey_p2sh_segwit': 'a91486cc442a97817c245ce90ed0d31d6dbcde3841f987', 68 69 "address_segwit": 'tb1qhm6697d9d2224vfyt8mj4kw03ncec7a7rtx6hc', 70 71 ## OP_0 [pub_key_hash] 72 'scriptpubkey_segwit': '0014bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe', 73 } 74 75} 76 77class AddressTests(unittest.TestCase): 78 79 SERIALIZED_LEN = 4 + 1 + 4 + 4 + 32 + 33 80 81 def unserialize_key(self, buf, buf_len): 82 key_out = ext_key() 83 ret = bip32_key_unserialize(buf, buf_len, byref(key_out)) 84 return ret, key_out 85 86 def get_test_key(self, vec, path): 87 buf, buf_len = make_cbuffer(vec[path][FLAG_KEY_PUBLIC]) 88 ret, key_out = self.unserialize_key(buf, self.SERIALIZED_LEN) 89 self.assertEqual(ret, WALLY_OK) 90 91 return key_out 92 93 def test_address_vectors(self): 94 self.do_test_vector(vec, 'm/0H/1', NETWORK_BITCOIN_MAINNET) 95 self.do_test_vector(vec, 'm/1H/1', NETWORK_BITCOIN_TESTNET) # Testnet 96 97 def do_test_vector(self, vec, path, network): 98 key = self.get_test_key(vec, path) 99 100 # Address type flag is mandatory 101 version = ADDRESS_VERSION_P2PKH_MAINNET if network == NETWORK_BITCOIN_MAINNET else ADDRESS_VERSION_P2PKH_TESTNET 102 ret, new_addr = wally_bip32_key_to_address(key, 0, version) 103 self.assertEqual(ret, WALLY_EINVAL) 104 105 # Obtain legacy address (P2PKH) 106 ret, new_addr = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2PKH, version) 107 self.assertEqual(ret, WALLY_OK) 108 self.assertEqual(new_addr, vec[path]['address_legacy']) 109 110 # Obtain wrapped SegWit address (P2SH_P2WPKH) 111 version = ADDRESS_VERSION_P2SH_MAINNET if network == NETWORK_BITCOIN_MAINNET else ADDRESS_VERSION_P2SH_TESTNET 112 ret, new_addr = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2SH_P2WPKH, version) 113 self.assertEqual(ret, WALLY_OK) 114 self.assertEqual(new_addr, vec[path]['address_p2sh_segwit']) 115 116 # wally_bip32_key_to_address does not support bech32 native SegWit (P2WPKH) 117 ret, new_addr = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2WPKH, version) 118 self.assertEqual(ret, WALLY_EINVAL) 119 120 # Obtain native SegWit address (P2WPKH) 121 bech32_prefix = 'bc' if network == NETWORK_BITCOIN_MAINNET else 'tb' 122 ret, new_addr = wally_bip32_key_to_addr_segwit(key, utf8(bech32_prefix), 0) 123 self.assertEqual(ret, WALLY_OK) 124 self.assertEqual(new_addr, vec[path]['address_segwit']) 125 126 # Parse legacy address (P2PKH): 127 out, out_len = make_cbuffer('00' * (25)) 128 ret, written = wally_address_to_scriptpubkey(utf8(vec[path]['address_legacy']), network, out, out_len) 129 130 self.assertEqual(ret, WALLY_OK) 131 self.assertEqual(hexlify(out[0:written]), utf8(vec[path]['scriptpubkey_legacy'])) 132 133 # Get address for P2PKH scriptPubKey 134 ret, new_addr = wally_scriptpubkey_to_address(out, written, network) 135 self.assertEqual(ret, WALLY_OK) 136 self.assertEqual(new_addr, vec[path]['address_legacy']) 137 138 # Parse wrapped SegWit address (P2SH_P2WPKH): 139 out, out_len = make_cbuffer('00' * (25)) 140 ret, written = wally_address_to_scriptpubkey(utf8(vec[path]['address_p2sh_segwit']), network, out, out_len) 141 142 self.assertEqual(ret, WALLY_OK) 143 self.assertEqual(hexlify(out[0:written]), utf8(vec[path]['scriptpubkey_p2sh_segwit'])) 144 145 # Get address for P2SH scriptPubKey 146 ret, new_addr = wally_scriptpubkey_to_address(out, written, network) 147 self.assertEqual(ret, WALLY_OK) 148 self.assertEqual(new_addr, vec[path]['address_p2sh_segwit']) 149 150 # Parse native SegWit address (P2WPKH): 151 out, out_len = make_cbuffer('00' * (100)) 152 ret, written = wally_addr_segwit_to_bytes(utf8(vec[path]['address_segwit']), utf8(bech32_prefix), 0, out, out_len) 153 self.assertEqual(ret, WALLY_OK) 154 self.assertEqual(hexlify(out[0:written]), utf8(vec[path]['scriptpubkey_segwit'])) 155 156 def test_address_scriptpubkey_liquid(self): 157 """Check that addresses can be converted to and from scriptpubkeys for Liquid""" 158 for addr, scriptpubkey, network in [ 159 ('XYtnYoGoSeE9ouMEVi6mfeujhjT2VnJncA', 'a914ec51ffb65120594389733bf8625f542446d97f7987', NETWORK_LIQUID_REGTEST), 160 ('H5nswXhfo8AMt159sgA5FWT35De34hVR4o', 'a914f80278b2011573a2ac59c83fadf929b0fc57ad0187', NETWORK_LIQUID_MAINNET), 161 ]: 162 out, out_len = make_cbuffer('00' * (100)) 163 ret, written = wally_address_to_scriptpubkey(utf8(addr), network, out, out_len) 164 self.assertEqual(ret, WALLY_OK) 165 self.assertEqual(hexlify(out[0:written]), utf8(scriptpubkey)) 166 167 ret, new_addr = wally_scriptpubkey_to_address(out, written, network) 168 self.assertEqual(ret, WALLY_OK) 169 self.assertEqual(utf8(new_addr), utf8(addr)) 170 171 172if __name__ == '__main__': 173 unittest.main() 174