diff --git a/bech32.py b/bech32.py index 9b08176..eff96e5 100644 --- a/bech32.py +++ b/bech32.py @@ -41,25 +41,33 @@ def bech32_hrp_expand(hrp): return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp] -def bech32_verify_checksum(hrp, data): +def bech32_verify_checksum(hrp, data, segwit_version=0): """Verify a checksum given HRP and converted data characters.""" - return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1 + if segwit_version == 0: + const = 1 # Bech32 + else: + const = 0x2bc830a3 # Bech32m + return bech32_polymod(bech32_hrp_expand(hrp) + data) == const -def bech32_create_checksum(hrp, data): +def bech32_create_checksum(hrp, data, segwit_version=0): """Compute the checksum values given HRP and data.""" values = bech32_hrp_expand(hrp) + data - polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ 1 + if segwit_version == 0: + const = 1 # Bech32 + else: + const = 0x2bc830a3 # Bech32m + polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ const return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)] -def bech32_encode(hrp, data): +def bech32_encode(hrp, data, segwit_version=0): """Compute a Bech32 string given HRP and data values.""" - combined = data + bech32_create_checksum(hrp, data) + combined = data + bech32_create_checksum(hrp, data, segwit_version) return hrp + '1' + ''.join([CHARSET[d] for d in combined]) -def bech32_decode(bech): +def bech32_decode(bech, segwit_version_verify=False): """Validate a Bech32 string, and determine HRP and data.""" if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or (bech.lower() != bech and bech.upper() != bech)): @@ -72,7 +80,7 @@ def bech32_decode(bech): return (None, None) hrp = bech[:pos] data = [CHARSET.find(x) for x in bech[pos+1:]] - if not bech32_verify_checksum(hrp, data): + if not bech32_verify_checksum(hrp, data, data[0] if segwit_version_verify else 0): return (None, None) return (hrp, data[:-6]) diff --git a/examples.sh b/examples.sh index dd7368d..56e2abb 100755 --- a/examples.sh +++ b/examples.sh @@ -47,3 +47,5 @@ echo echo '### On mainnet, with fallback (p2wsh) address bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3' ./lightning-address.py encode $TIMESTAMP --description-hashed="$LONG_DESCRIPTION" --fallback=bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3 $(to_btc 24) $RHASH $PRIVKEY +echo '### On mainnet, with fallback (p2tr) address bc1pptdvg0d2nj99568qn6ssdy4cygnwuxgw2ukmnwgwz7jpqjz2kszse2s3lm' +./lightning-address.py encode $TIMESTAMP --description-hashed="$LONG_DESCRIPTION" --fallback=bc1pptdvg0d2nj99568qn6ssdy4cygnwuxgw2ukmnwgwz7jpqjz2kszse2s3lm $(to_btc 24) $RHASH $PRIVKEY diff --git a/lnaddr.py b/lnaddr.py index 2d88a87..1aae3d3 100755 --- a/lnaddr.py +++ b/lnaddr.py @@ -78,7 +78,7 @@ def encode_fallback(fallback, currency): """ Encode all supported fallback addresses. """ if currency == 'bc' or currency == 'tb': - fbhrp, witness = bech32_decode(fallback) + fbhrp, witness = bech32_decode(fallback, segwit_version_verify=True) if fbhrp: if fbhrp != currency: raise ValueError("Not a bech32 address for this currency") @@ -109,7 +109,7 @@ def parse_fallback(fallback, currency): addr=base58.b58encode_check(bytes([base58_prefix_map[currency][1]]) + fallback[5:].tobytes()) elif wver <= 16: - addr=bech32_encode(currency, bitarray_to_u5(fallback)) + addr=bech32_encode(currency, bitarray_to_u5(fallback), wver) else: return None else: