def witness_from_address(b32addr: String) -> Tuple[int, bytes, str]: "Return the witness from a bech32 native SegWit address." if isinstance(b32addr, str): b32addr = b32addr.strip() # the following check was originally in b32decode # but it does not pertain there if len(b32addr) > 90: raise BTClibValueError( f"invalid bech32 address length: {len(b32addr)} > 90") hrp, data = b32decode(b32addr) # check that it is a known SegWit address type network = network_from_key_value("hrp", hrp) if network is None: raise BTClibValueError(f"invalid hrp: {hrp}") if len(data) == 0: raise BTClibValueError(f"empty data in bech32 address: {b32addr!r}") wit_ver = data[0] wit_prg = bytes(power_of_2_base_conversion(data[1:], 5, 8, False)) return wit_ver, check_witness(wit_ver, wit_prg), network
def test_bech32_insertion_issue() -> None: """Test documented bech32 insertion issue. https://github.com/sipa/bech32/issues/51 https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-November/017443.html https://gist.github.com/sipa/a9845b37c1b298a7301c33a04090b2eb https://gist.github.com/sipa/a9845b37c1b298a7301c33a04090b2eb https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-October/018236.html https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-December/018292.html https://gist.github.com/sipa/14c248c288c3880a3b191f978a34508e """ strings = ("ii2134hk2xmat79tp", "eyg5bsz1l2mrq5ypl40hp") for string in strings: for i in range(20): b32decode(string[:-1] + i * "q" + string[-1:])
def test_valid_checksum(self): """Test validation of valid checksums.""" for test in VALID_CHECKSUM: _, _ = b32decode(test) pos = test.rfind('1') test = test[:pos + 1] + chr(ord(test[pos + 1]) ^ 1) + test[pos + 2:] self.assertRaises(ValueError, b32decode, test)
def test_bechs32_checksum() -> None: "Test bech32 checksum." for test in VALID_CHECKSUM: b32decode(test) b32decode(test.encode("ascii")) pos = test.rfind("1") test = test[:pos + 1] + chr(ord(test[pos + 1]) ^ 1) + test[pos + 2:] with pytest.raises(BTClibValueError): b32decode(test) for addr, err_msg in INVALID_CHECKSUM: with pytest.raises(BTClibValueError, match=err_msg): b32decode(addr)
def test_bech32() -> None: "Test bech32 checksum." valid_checksum = [ "A12UEL5L", "a12uel5l", "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", "?1ezyfcl", # the next one would have been invalid with the 90 char limit "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx", ] for test in valid_checksum: b32decode(test) b32decode(test.encode("ascii")) assert b32encode(*b32decode(test)).decode() == test.lower() pos = test.rfind("1") test = test[:pos + 1] + chr(ord(test[pos + 1]) ^ 1) + test[pos + 2:] with pytest.raises(BTClibValueError): b32decode(test) invalid_checksum = [ ["\x20" + " 1nwldj5", r"HRP character out of range: *"], ["\x7F" + "1axkwrx", r"HRP character out of range: *"], ["\x80" + "1eym55h", r"HRP character out of range: *"], ["pzry9x0s0muk", r"no separator character: *"], ["1pzry9x0s0muk", r"empty HRP: *"], ["x1b4n0q5v", r"invalid data character: *"], ["li1dgmt3", r"too short checksum: *"], # Invalid character in checksum ["de1lg7wt\xff", r"invalid character in checksum: *"], # checksum calculated with uppercase form of HRP ["A1G7SGD8", r"invalid checksum: *"], ["10a06t8", r"empty HRP: *"], ["1qzzfhee", r"empty HRP: *"], ] for addr, err_msg in invalid_checksum: with pytest.raises(BTClibValueError, match=err_msg): b32decode(addr)