|
|
|
@ -20,11 +20,13 @@
|
|
|
|
|
|
|
|
|
|
"""Reference implementation for Bech32 and segwit addresses."""
|
|
|
|
|
|
|
|
|
|
if False:
|
|
|
|
|
from typing import List, Optional, Tuple
|
|
|
|
|
|
|
|
|
|
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bech32_polymod(values):
|
|
|
|
|
def bech32_polymod(values: List[int]) -> int:
|
|
|
|
|
"""Internal function that computes the Bech32 checksum."""
|
|
|
|
|
generator = [0x3B6A57B2, 0x26508E6D, 0x1EA119FA, 0x3D4233DD, 0x2A1462B3]
|
|
|
|
|
chk = 1
|
|
|
|
@ -36,30 +38,30 @@ def bech32_polymod(values):
|
|
|
|
|
return chk
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bech32_hrp_expand(hrp):
|
|
|
|
|
def bech32_hrp_expand(hrp: str) -> List[int]:
|
|
|
|
|
"""Expand the HRP into values for checksum computation."""
|
|
|
|
|
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: str, data: List[int]) -> bool:
|
|
|
|
|
"""Verify a checksum given HRP and converted data characters."""
|
|
|
|
|
return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bech32_create_checksum(hrp, data):
|
|
|
|
|
def bech32_create_checksum(hrp: str, data: List[int]) -> List[int]:
|
|
|
|
|
"""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
|
|
|
|
|
return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bech32_encode(hrp, data):
|
|
|
|
|
def bech32_encode(hrp: str, data: List[int]) -> str:
|
|
|
|
|
"""Compute a Bech32 string given HRP and data values."""
|
|
|
|
|
combined = data + bech32_create_checksum(hrp, data)
|
|
|
|
|
return hrp + "1" + "".join([CHARSET[d] for d in combined])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bech32_decode(bech):
|
|
|
|
|
def bech32_decode(bech: str) -> Tuple[Optional[str], Optional[List[int]]]:
|
|
|
|
|
"""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
|
|
|
|
@ -78,7 +80,9 @@ def bech32_decode(bech):
|
|
|
|
|
return (hrp, data[:-6])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def convertbits(data, frombits, tobits, pad=True):
|
|
|
|
|
def convertbits(
|
|
|
|
|
data: List[int], frombits: int, tobits: int, pad: bool = True
|
|
|
|
|
) -> List[int]:
|
|
|
|
|
"""General power-of-2 base conversion."""
|
|
|
|
|
acc = 0
|
|
|
|
|
bits = 0
|
|
|
|
@ -87,7 +91,7 @@ def convertbits(data, frombits, tobits, pad=True):
|
|
|
|
|
max_acc = (1 << (frombits + tobits - 1)) - 1
|
|
|
|
|
for value in data:
|
|
|
|
|
if value < 0 or (value >> frombits):
|
|
|
|
|
return None
|
|
|
|
|
raise ValueError
|
|
|
|
|
acc = ((acc << frombits) | value) & max_acc
|
|
|
|
|
bits += frombits
|
|
|
|
|
while bits >= tobits:
|
|
|
|
@ -97,17 +101,17 @@ def convertbits(data, frombits, tobits, pad=True):
|
|
|
|
|
if bits:
|
|
|
|
|
ret.append((acc << (tobits - bits)) & maxv)
|
|
|
|
|
elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
|
|
|
|
|
return None
|
|
|
|
|
raise ValueError
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def decode(hrp, addr):
|
|
|
|
|
def decode(hrp: str, addr: str) -> Tuple[Optional[int], Optional[List[int]]]:
|
|
|
|
|
"""Decode a segwit address."""
|
|
|
|
|
hrpgot, data = bech32_decode(addr)
|
|
|
|
|
if hrpgot != hrp:
|
|
|
|
|
if data is None or hrpgot != hrp:
|
|
|
|
|
return (None, None)
|
|
|
|
|
decoded = convertbits(data[1:], 5, 8, False)
|
|
|
|
|
if decoded is None or len(decoded) < 2 or len(decoded) > 40:
|
|
|
|
|
if len(decoded) < 2 or len(decoded) > 40:
|
|
|
|
|
return (None, None)
|
|
|
|
|
if data[0] > 16:
|
|
|
|
|
return (None, None)
|
|
|
|
@ -116,7 +120,7 @@ def decode(hrp, addr):
|
|
|
|
|
return (data[0], decoded)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def encode(hrp, witver, witprog):
|
|
|
|
|
def encode(hrp: str, witver: int, witprog: List[int]) -> Optional[str]:
|
|
|
|
|
"""Encode a segwit address."""
|
|
|
|
|
ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5))
|
|
|
|
|
if decode(hrp, ret) == (None, None):
|
|
|
|
|