def test_hash_from_bech32() -> None: network = "testnet" wv = 0 wp = 20 * b"\x05" addr = b32address_from_witness(wv, wp, network) _, wp2, n_2, _ = witness_from_b32address(addr) assert n_2 == network assert wp2 == wp # witness program length (21) is not 20 or 32 addr = b"tb1qq5zs2pg9q5zs2pg9q5zs2pg9q5zs2pg9q5mpvsef" err_msg = "invalid witness program length for witness v0: " with pytest.raises(BTClibValueError, match=err_msg): witness_from_b32address(addr)
def test_p2wpkh(self): # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki # leading/trailing spaces should be tolerated pub = " 0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2" "815B16F81798" addr = b"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" self.assertEqual(addr, p2wpkh(pub)) addr = b"tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx" self.assertEqual(addr, p2wpkh(pub, "testnet")) # http://bitcoinscri.pt/pages/segwit_native_p2wpkh pub = "02 530c548d402670b13ad8887ff99c294e67fc18097d236d57880c69" "261b42def7" addr = b"bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck" self.assertEqual(addr, p2wpkh(pub)) _, wp, _, _ = witness_from_b32address(addr) self.assertEqual(bytes(wp), hash160(pub)) # Wrong size (65-bytes) for compressed SEC key uncompr_pub = bytes_from_point(point_from_octets(pub), compressed=False) self.assertRaises(ValueError, p2wpkh, uncompr_pub) # p2wpkh(uncompr_pub) # Wrong pubkey size: 34 instead of 33 self.assertRaises(ValueError, p2wpkh, pub + "00") # p2wpkh(pub + '00') # Witness program length (21) is not 20 self.assertRaises(ValueError, b32address_from_witness, 0, hash160(pub) + b"\x00")
def test_p2wpkh() -> None: # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki # leading/trailing spaces should be tolerated pub = " 02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" addr = b"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" assert addr == p2wpkh(pub) addr = b"tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx" assert addr == p2wpkh(pub, "testnet") # http://bitcoinscri.pt/pages/segwit_native_p2wpkh pub = "02 530c548d402670b13ad8887ff99c294e67fc18097d236d57880c69261b42def7" addr = b"bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck" assert addr == p2wpkh(pub) _, wp, _, _ = witness_from_b32address(addr) assert bytes(wp) == hash160(pub) uncompr_pub = bytes_from_point(point_from_octets(pub), compressed=False) err_msg = "not a private or compressed public key: " with pytest.raises(BTClibValueError, match=err_msg): p2wpkh(uncompr_pub) with pytest.raises(BTClibValueError, match=err_msg): p2wpkh(pub + "00") err_msg = "invalid witness program length for witness v0: " with pytest.raises(BTClibValueError, match=err_msg): b32address_from_witness(0, hash160(pub) + b"\x00")
def test_b32address_from_witness() -> None: # self-consistency addr = b"bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck" wv, wp, network, _ = witness_from_b32address(addr) assert b32address_from_witness(wv, wp, network) == addr # string input addr_str = "bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck" wv, wp, network, _ = witness_from_b32address(addr_str) assert b32address_from_witness(wv, wp, network) == addr_str.encode() wp_ints = [i for i in wp] wp_ints[0] = -1 with pytest.raises(ValueError, match="invalid value in _convertbits: "): _convertbits(wp_ints, 8, 5)
def test_b32address_from_witness(self): # self-consistency addr = b'bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck' wv, wp, network, _ = witness_from_b32address(addr) self.assertEqual(b32address_from_witness(wv, wp, network), addr) # invalid value -1 wp = [i for i in wp] # convert to List[int] wp[-1] = -1 # alter the last element with an invalid value self.assertRaises(ValueError, b32address_from_witness, wv, wp, network) #b32address_from_witness(wv, wp, network) # string input addr = 'bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck' wv, wp, network, _ = witness_from_b32address(addr) self.assertEqual(b32address_from_witness(wv, wp, network), addr.encode())
def test_invalid_address() -> None: """Test whether invalid addresses fail to decode""" INVALID_ADDRESS: List[Tuple[str, str]] = [ ( "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", "invalid value for network keyword 'p2w': ", ), ( "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", "invalid checksum in bech32 string: ", ), ("BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", "invalid witness version: "), ("bc1rw5uspcuh", "invalid witness program length for witness version zero: "), ( "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", "invalid witness program length for witness version zero: ", ), ( "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", "invalid witness program length for witness version zero: ", ), ( "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", "mixed case in bech32 string: ", ), ( "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", "zero padding of more than 4 bits in 8-to-5 conversion", ), ( "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", "non-zero padding in 8-to-5 conversion", ), ("bc1gmk9yu", "empty data in bech32 address: "), ( "bc1qqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqv0jstn5", "invalid bech32 address length: ", ), ] for a, err_msg in INVALID_ADDRESS: with pytest.raises(ValueError, match=err_msg): witness_from_b32address(a)
def test_valid_address(self): """Test whether valid addresses decode to the correct output""" for a, hexscript in VALID_BC_ADDRESS + VALID_TB_ADDRESS: self.assertTrue(has_segwit_prefix(a)) witvers, witprog, network, _ = witness_from_b32address(a) script_pubkey = [witvers, witprog] self.assertEqual(encode(script_pubkey).hex(), hexscript) address = b32address_from_witness(witvers, witprog, network) self.assertEqual(a.lower().strip(), address.decode('ascii'))
def test_hash_from_bech32(self): network = "testnet" wv = 0 wp = 20 * b"\x05" addr = b32address_from_witness(wv, wp, network) _, wp2, n2, _ = witness_from_b32address(addr) self.assertEqual(n2, network) self.assertEqual(wp2, wp) # witness program length (21) is not 20 or 32 addr = "tb1qq5zs2pg9q5zs2pg9q5zs2pg9q5zs2pg9q5mpvsef" self.assertRaises(ValueError, witness_from_b32address, addr)
def test_p2wsh_address(self): # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki pub = "02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" witness_script = [pub, 'OP_CHECKSIG'] witness_script_bytes = encode(witness_script) addr = b'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7' self.assertEqual(addr, p2wsh_address(witness_script_bytes, 'testnet')) _, wp, _, _ = witness_from_b32address(addr) self.assertEqual(bytes(wp), sha256(witness_script_bytes)) addr = b'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3' self.assertEqual(addr, p2wsh_address(witness_script_bytes)) _, wp, _, _ = witness_from_b32address(addr) self.assertEqual(bytes(wp), sha256(witness_script_bytes)) self.assertEqual(witness_from_b32address(addr)[1], sha256(witness_script_bytes)) # witness program length (35) is not 32 self.assertRaises(ValueError, b32address_from_witness, 0, witness_script_bytes[1:])
def test_address_from_wif() -> None: q = 0x19E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725 test_cases: List[Tuple[bool, str, str, str]] = [ ( False, "mainnet", "5J1geo9kcAUSM6GJJmhYRX1eZEjvos9nFyWwPstVziTVueRJYvW", "1LPM8SZ4RQDMZymUmVSiSSvrDfj1UZY9ig", ), ( True, "mainnet", "Kx621phdUCp6sgEXPSHwhDTrmHeUVrMkm6T95ycJyjyxbDXkr162", "1HJC7kFvXHepkSzdc8RX6khQKkAyntdfkB", ), ( False, "testnet", "91nKEXyJCPYaK9maw7bTJ7ZcCu6dy2gybvNtUWF1LTCYggzhZgy", "mzuJRVe3ERecM6F6V4R6GN9B5fKiPC9HxF", ), ( True, "testnet", "cNT1UjhUuGWN37hnmr754XxvPWwtAJTSq8bcCQ4pUrdxqxbA1iU1", "mwp9QoLuLK65XZUFKhPtvfujBjmgkZnmPx", ), ] for compressed, network, wif, address in test_cases: assert wif.encode() == wif_from_prvkey(q, network, compressed) assert prvkeyinfo_from_prvkey(wif) == (q, network, compressed) b58 = p2pkh(wif) assert b58 == address.encode() _, payload, net, is_script = h160_from_b58address(b58) assert net == network assert not is_script if compressed: b32 = p2wpkh(wif) assert (payload, network, is_script) == witness_from_b32address(b32)[1:] b = p2wpkh_p2sh(wif) _, payload2, net, is_script = h160_from_b58address(b) assert is_script assert (hash160(b"\x00\x14" + payload), network) == (payload2, net) else: err_msg = "not a private or compressed public key: " with pytest.raises(ValueError, match=err_msg): p2wpkh(wif) # type: ignore with pytest.raises(ValueError, match=err_msg): p2wpkh_p2sh(wif) # type: ignore
def test_p2wsh(): # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki pub = "02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D" "959F2815B16F81798" witness_script = [pub, "OP_CHECKSIG"] witness_script_bytes = encode(witness_script) addr = b"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7" assert addr == p2wsh(witness_script_bytes, "testnet") _, wp, _, _ = witness_from_b32address(addr) assert bytes(wp) == sha256(witness_script_bytes) addr = b"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3" assert addr == p2wsh(witness_script_bytes) _, wp, _, _ = witness_from_b32address(addr) assert bytes(wp) == sha256(witness_script_bytes) assert witness_from_b32address(addr)[1] == sha256(witness_script_bytes) errMsg = r"witness program length \(35\) is not 20 or 32" with pytest.raises(ValueError, match=errMsg): b32address_from_witness(0, witness_script_bytes)
def test_p2wsh() -> None: # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki pub = "02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" script_pubkey: List[ScriptToken] = [pub, "OP_CHECKSIG"] witness_script_bytes = script.serialize(script_pubkey) addr = b"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7" assert addr == p2wsh(witness_script_bytes, "testnet") _, wp, _, _ = witness_from_b32address(addr) assert bytes(wp) == sha256(witness_script_bytes) addr = b"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3" assert addr == p2wsh(witness_script_bytes) _, wp, _, _ = witness_from_b32address(addr) assert bytes(wp) == sha256(witness_script_bytes) assert witness_from_b32address(addr)[1] == sha256(witness_script_bytes) err_msg = "invalid witness program length for witness v0: " with pytest.raises(BTClibValueError, match=err_msg): b32address_from_witness(0, witness_script_bytes)
def test_valid_address(self): """Test whether valid addresses decode to the correct output""" VALID_BC_ADDRESS = [ [ "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", "0014751e76e8199196d454941c45d1b3a323f1433bd6", ], [ ("bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarva" "ry0c5xw7k7grplx"), ("5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d" "454941c45d1b3a323f1433bd6"), ], ["BC1SW50QA3JX3S", "6002751e"], [ "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", "5210751e76e8199196d454941c45d1b3a323", ], [ " bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", # extra leading space "5210751e76e8199196d454941c45d1b3a323", ], ] VALID_TB_ADDRESS = [ [ ("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0s" "l5k7"), ("00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329" "604903262"), ], [ ("tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrx" "h6hy"), ("0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165da" "b93e86433"), ], ] for a, hexscript in VALID_BC_ADDRESS + VALID_TB_ADDRESS: witvers, witprog, network, _ = witness_from_b32address(a) script_pubkey = [witvers, witprog] self.assertEqual(encode(script_pubkey).hex(), hexscript) address = b32address_from_witness(witvers, witprog, network) self.assertEqual(a.lower().strip(), address.decode("ascii"))
def test_valid_address() -> None: """Test whether valid addresses decode to the correct output""" valid_bc_addresses: List[Tuple[str, str]] = [ ( "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", "0014751e76e8199196d454941c45d1b3a323f1433bd6", ), ( "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6", ), ("BC1SW50QA3JX3S", "6002751e"), ( "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", "5210751e76e8199196d454941c45d1b3a323", ), ( " bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", # extra leading space "5210751e76e8199196d454941c45d1b3a323", ), ] valid_tb_addresses: List[Tuple[str, str]] = [ ( "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262", ), ( "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433", ), ] for address, hexscript in valid_bc_addresses + valid_tb_addresses: witvers, witprog, network, _ = witness_from_b32address(address) script_pubkey: List[ScriptToken] = [witvers, witprog] assert script.serialize(script_pubkey).hex() == hexscript addr = b32address_from_witness(witvers, witprog, network) assert address.lower().strip() == addr.decode("ascii")
def test_address_from_wif(self): # uncompressed mainnet wif1 = "5J1geo9kcAUSM6GJJmhYRX1eZEjvos9nFyWwPstVziTVueRJYvW" pubkey, network = pubkey_info_from_prvkey(wif1) b58 = p2pkh(pubkey) self.assertEqual(b58, b'1LPM8SZ4RQDMZymUmVSiSSvrDfj1UZY9ig') self.assertRaises(ValueError, p2wpkh, pubkey) self.assertRaises(ValueError, p2wpkh_p2sh, pubkey) # compressed mainnet wif2 = "Kx621phdUCp6sgEXPSHwhDTrmHeUVrMkm6T95ycJyjyxbDXkr162" pubkey, network = pubkey_info_from_prvkey(wif2) b58 = p2pkh(pubkey) self.assertEqual(b58, b'1HJC7kFvXHepkSzdc8RX6khQKkAyntdfkB') b32 = p2wpkh(pubkey) self.assertEqual(h160_from_b58address( b58)[1:], witness_from_b32address(b32)[1:]) h160 = h160_from_b58address(b58)[1] b = p2wpkh_p2sh(pubkey) self.assertEqual(hash160(b'\x00\x14' + h160), h160_from_b58address(b)[1]) self.assertEqual(prvkey_info_from_prvkey( wif1)[0], prvkey_info_from_prvkey(wif2)[0]) # uncompressed testnet wif1 = "91gGn1HgSap6CbU12F6z3pJri26xzp7Ay1VW6NHCoEayNXwRpu2" pubkey, network = pubkey_info_from_prvkey(wif1) b58 = p2pkh(pubkey, network, None) self.assertEqual(b58, b'mvgbzkCSgKbYgaeG38auUzR7otscEGi8U7') self.assertRaises(ValueError, p2wpkh, pubkey) self.assertRaises(ValueError, p2wpkh_p2sh, pubkey) # compressed testnet wif2 = "cMzLdeGd5vEqxB8B6VFQoRopQ3sLAAvEzDAoQgvX54xwofSWj1fx" pubkey, network = pubkey_info_from_prvkey(wif2) b58 = p2pkh(pubkey, network, None) self.assertEqual(b58, b'n1KSZGmQgB8iSZqv6UVhGkCGUbEdw8Lm3Q') b32 = p2wpkh(pubkey, network) self.assertEqual(h160_from_b58address( b58)[1:], witness_from_b32address(b32)[1:]) h160 = h160_from_b58address(b58)[1] b = p2wpkh_p2sh(pubkey, network) self.assertEqual(hash160(b'\x00\x14' + h160), h160_from_b58address(b)[1]) self.assertEqual(prvkey_info_from_prvkey( wif1)[0], prvkey_info_from_prvkey(wif2)[0]) # uncompressed mainnet, trailing/leading spaces in string wif1 = " 5J1geo9kcAUSM6GJJmhYRX1eZEjvos9nFyWwPstVziTVueRJYvW" pubkey, network = pubkey_info_from_prvkey(wif1) b58 = p2pkh(pubkey) self.assertEqual(b58, b'1LPM8SZ4RQDMZymUmVSiSSvrDfj1UZY9ig') self.assertRaises(ValueError, p2wpkh, pubkey) self.assertRaises(ValueError, p2wpkh_p2sh, pubkey) # compressed mainnet, trailing/leading spaces in string wif2 = "Kx621phdUCp6sgEXPSHwhDTrmHeUVrMkm6T95ycJyjyxbDXkr162 " pubkey, network = pubkey_info_from_prvkey(wif2) b58 = p2pkh(pubkey) self.assertEqual(b58, b'1HJC7kFvXHepkSzdc8RX6khQKkAyntdfkB') b32 = p2wpkh(pubkey) self.assertEqual(h160_from_b58address( b58)[1:], witness_from_b32address(b32)[1:]) h160 = h160_from_b58address(b58)[1] b = p2wpkh_p2sh(pubkey) self.assertEqual(hash160(b'\x00\x14' + h160), h160_from_b58address(b)[1])