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_invalid_address_enc() -> None: """Test whether address encoding fails on invalid input""" INVALID_ADDRESS_ENC: List[Tuple[str, int, int, str]] = [ ("MAINNET", 0, 20, "'MAINNET'"), ("mainnet", 0, 21, "invalid witness program length for witness version zero: "), ("mainnet", 17, 32, "invalid witness version: "), ("mainnet", 1, 1, "invalid witness program length for witness version zero: "), ( "mainnet", 16, 41, "invalid witness program length for witness version zero: ", ), ] network, version, length, err_msg = INVALID_ADDRESS_ENC[0] with pytest.raises(KeyError, match=err_msg): b32address_from_witness(version, "00" * length, network) for network, version, length, err_msg in INVALID_ADDRESS_ENC[1:]: with pytest.raises(ValueError, match=err_msg): b32address_from_witness(version, "00" * length, network)
def test_address_scriptPubKey(self): pubkey = "03 a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f" pubkey_hash = hash160(pubkey).hex() opcodes = [0, pubkey_hash] address_from_scriptPubKey(opcodes) opcodes2, _ = scriptPubKey_from_address(address_from_scriptPubKey(opcodes)) self.assertEqual(opcodes, opcodes2) opcodes = ['OP_DUP', 'OP_HASH160', pubkey_hash, 'OP_EQUALVERIFY', 'OP_CHECKSIG'] opcodes2, _ = scriptPubKey_from_address(address_from_scriptPubKey(opcodes)) self.assertEqual(opcodes, opcodes2) script_hash = hash160(encode(opcodes)).hex() opcodes = ['OP_HASH160',script_hash, 'OP_EQUAL'] opcodes2, _ = scriptPubKey_from_address(address_from_scriptPubKey(opcodes)) self.assertEqual(opcodes, opcodes2) script_hash = sha256(encode(opcodes)).hex() opcodes = [0, script_hash] opcodes2, _ = scriptPubKey_from_address(address_from_scriptPubKey(opcodes)) self.assertEqual(opcodes, opcodes2) # Unknown script opcodes = [16, pubkey_hash] self.assertRaises(ValueError, address_from_scriptPubKey, opcodes) #address_from_scriptPubKey(opcodes) # Unhandled witness version (16) wp = hash160(pubkey)[2:] addr = b32address_from_witness(16, wp) self.assertRaises(ValueError, scriptPubKey_from_address, addr)
def test_CLT() -> None: network = "mainnet" fed_pubkeys = [b"\x00" * 33, b"\x11" * 33, b"\x22" * 33] rec_pubkeys = [b"\x77" * 33, b"\x88" * 33, b"\x99" * 33] # fmt: off redeem_script = script.encode([ "OP_IF", 2, *fed_pubkeys, 3, "OP_CHECKMULTISIG", # noqa E131 "OP_ELSE", 500, "OP_CHECKLOCKTIMEVERIFY", "OP_DROP", # noqa E131 2, *rec_pubkeys, 3, "OP_CHECKMULTISIG", # noqa E131 "OP_ENDIF", ]) # fmt: on payload = sha256(redeem_script) scriptPubKey = ( "00207b5310339c6001f75614daa5083839fa54d46165f6c56025cc54d397a85a5708") assert scriptPubKey == p2wsh(redeem_script).hex() assert scriptPubKey == scriptPubKey_from_payload("p2wsh", payload).hex() address = b"bc1q0df3qvuuvqqlw4s5m2jsswpelf2dgct97mzkqfwv2nfe02z62uyq7n4zjj" assert address == address_from_scriptPubKey(scriptPubKey, network) assert address == b32address_from_witness(0, payload, network)
def test_exceptions() -> None: # invalid size: 11 bytes instead of 20 err_msg = "invalid size: " with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload("p2wpkh", "00" * 11) # invalid size: 33 bytes instead of 32 with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload("p2wsh", "00" * 33) err_msg = "unknown scriptPubKey type: " with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload("p2unkn", "00" * 32) err_msg = "unknown scriptPubKey: " with pytest.raises(ValueError, match=err_msg): scriptPubKey = [16, 20 * b"\x00"] address_from_scriptPubKey(scriptPubKey) # Unhandled witness version (16) err_msg = "unmanaged witness version: " address = b32address_from_witness(16, 20 * b"\x00") with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_address(address)
def test_p2wsh() -> None: # self-consistency pubkey = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" pubkey_hash = hash160(pubkey) redeem_script = scriptPubKey_from_payload("p2pkh", pubkey_hash) payload = sha256(redeem_script) scriptPubKey = script.encode([0, payload]) assert scriptPubKey == p2wsh(script.decode(redeem_script)) # to the scriptPubKey in two steps (through payload) script_type = "p2wsh" assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) # back from the scriptPubKey to the payload assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey) # bech32 address network = "mainnet" address = bech32address.p2wsh(redeem_script, network) assert address == address_from_scriptPubKey(scriptPubKey, network) wit_ver = 0 assert address == b32address_from_witness(wit_ver, payload, network) # back from the address to the scriptPubKey assert (scriptPubKey, network) == scriptPubKey_from_address(address) # p2sh-wrapped base58 address address = base58address.p2wsh_p2sh(redeem_script, network) assert address == b58address_from_witness(payload, network)
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_CLT(self): network = 'mainnet' vault_pubkeys = [b'\x00' * 33, b'\x11' * 33, b'\x22' * 33] recovery_pubkeys = [b'\x77' * 33, b'\x88' * 33, b'\x99' * 33] redeem_script = encode([ 'OP_IF', 2, *vault_pubkeys, 3, 'OP_CHECKMULTISIG', 'OP_ELSE', 500, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 2, *recovery_pubkeys, 3, 'OP_CHECKMULTISIG', 'OP_ENDIF' ]) payload = sha256(redeem_script) script = "00207b5310339c6001f75614daa5083839fa54d46165f6c56025cc54d397a85a5708" scriptPubKey = p2wsh(redeem_script) self.assertEqual(scriptPubKey.hex(), script) scriptPubKey = scriptPubKey_from_payload('p2wsh', payload) self.assertEqual(scriptPubKey.hex(), script) address = b"bc1q0df3qvuuvqqlw4s5m2jsswpelf2dgct97mzkqfwv2nfe02z62uyq7n4zjj" address2 = address_from_scriptPubKey(scriptPubKey, network) self.assertEqual(address, address2) address2 = bech32address.p2wsh(redeem_script, network) self.assertEqual(address, address2) address2 = b32address_from_witness(0, payload, network) self.assertEqual(address, address2)
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_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(): # 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_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_p2wsh(self): script_type = "p2wsh" # self-consistency pubkey = "02" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" pubkey_hash = hash160(pubkey) redeem_script = scriptPubKey_from_payload("p2pkh", pubkey_hash) payload = sha256(redeem_script) script = encode([0, payload]) # straight to the scriptPubKey scriptPubKey = p2wsh(decode(redeem_script)) self.assertEqual(scriptPubKey.hex(), script.hex()) # to the scriptPubKey in two steps (through payload) scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script.hex()) # back from the scriptPubKey to the payload script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) # data -> payload is not invertible (hash functions) # bech32 address network = "mainnet" address = bech32address.p2wsh(redeem_script, network) address2 = address_from_scriptPubKey(scriptPubKey, network) self.assertEqual(address, address2) address2 = b32address_from_witness(0, payload, network) self.assertEqual(address, address2) scriptPubKey2, network2 = scriptPubKey_from_address(address) self.assertEqual(scriptPubKey2, scriptPubKey) self.assertEqual(network2, network) # p2sh-wrapped base58 address address = base58address.p2wsh_p2sh(redeem_script, network) address2 = b58address_from_witness(payload, network) self.assertEqual(address, address2)
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_exceptions(self): # Invalid size: 11 bytes instead of 20 self.assertRaises(ValueError, scriptPubKey_from_payload, "00" * 11, "p2wpkh") # scriptPubKey_from_payload("00"*11, 'p2wpkh') # Invalid size: 33 bytes instead of 32 self.assertRaises(ValueError, scriptPubKey_from_payload, "00" * 33, "p2wsh") # scriptPubKey_from_payload("00"*33, 'p2wsh') # Unknown script script = [16, 20 * b"\x00"] self.assertRaises(ValueError, address_from_scriptPubKey, script) # address_from_scriptPubKey(script) # Unhandled witness version (16) addr = b32address_from_witness(16, 20 * b"\x00") self.assertRaises(ValueError, scriptPubKey_from_address, addr)
def test_CLT(self): vault_pubkeys = [b'\x00'*33, b'\x11'*33, b'\x22'*33] recovery_pubkeys = [b'\x77'*33, b'\x88'*33, b'\x99'*33] opcodes = [ 'OP_IF', 2, *vault_pubkeys, 3, 'OP_CHECKMULTISIG', 'OP_ELSE', 500, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 2, *recovery_pubkeys, 3, 'OP_CHECKMULTISIG', 'OP_ENDIF' ] witness_program = encode(opcodes) witness_hash = sha256(witness_program) script_pubkey = p2wsh_scriptPubKey(witness_hash) self.assertEqual(encode(script_pubkey).hex(), "00207b5310339c6001f75614daa5083839fa54d46165f6c56025cc54d397a85a5708") address = b32address_from_witness(0, witness_hash) self.assertEqual(address, b"bc1q0df3qvuuvqqlw4s5m2jsswpelf2dgct97mzkqfwv2nfe02z62uyq7n4zjj")
def test_CLT(): network = "mainnet" vault_pubkeys = [b"\x00" * 33, b"\x11" * 33, b"\x22" * 33] recovery_pubkeys = [b"\x77" * 33, b"\x88" * 33, b"\x99" * 33] redeem_script = encode( [ "OP_IF", 2, *vault_pubkeys, 3, "OP_CHECKMULTISIG", "OP_ELSE", 500, "OP_CHECKLOCKTIMEVERIFY", "OP_DROP", 2, *recovery_pubkeys, 3, "OP_CHECKMULTISIG", "OP_ENDIF", ] ) payload = sha256(redeem_script) script = "00207b5310339c6001f75614daa5083839fa54d46165f6c56025cc54d397a85a5708" scriptPubKey = p2wsh(redeem_script) assert scriptPubKey.hex() == script scriptPubKey = scriptPubKey_from_payload("p2wsh", payload) assert scriptPubKey.hex() == script address = ( "bc1q0df3qvuuvqqlw4s5m2jsswpelf2dgct97mzkqfwv2nfe02z62uyq7n4zjj" ).encode() address2 = address_from_scriptPubKey(scriptPubKey, network) assert address == address2 assert address == address2 address2 = b32address_from_witness(0, payload, network) assert address == address2
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")