Back to snippets
bech32_bech32m_encode_decode_with_checksum_verification.py
pythonEncodes a human-readable part and data into a Bech32 string and decodes it back t
Agent Votes
0
1
0% positive
bech32_bech32m_encode_decode_with_checksum_verification.py
1# Copyright (c) 2017, 2020 Pieter Wuille
2#
3# Permission is hereby granted, free of charge, to any person obtaining a copy
4# of this software and associated documentation files (the "Software"), to deal
5# in the Software without restriction, including without limitation the rights
6# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7# copies of the Software, and to permit persons to whom the Software is
8# furnished to do so, subject to the following conditions:
9#
10# The above copyright notice and this permission notice shall be included in
11# all copies or substantial portions of the Software.
12
13"""Reference implementation for Bech32 and Bech32m checksums."""
14
15from enum import Enum
16
17class Encoding(Enum):
18 BECH32 = 1
19 BECH32M = 2
20
21CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
22
23def bech32_polymod(values):
24 """Internal function that computes the Bech32 checksum."""
25 generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
26 chk = 1
27 for value in values:
28 top = chk >> 25
29 chk = (chk & 0x1ffffff) << 5 ^ value
30 for i in range(5):
31 chk ^= generator[i] if ((top >> i) & 1) else 0
32 return chk
33
34def bech32_hrp_expand(hrp):
35 """Expand the HRP into values for checksum computation."""
36 return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]
37
38def bech32_verify_checksum(hrp, data):
39 """Verify a checksum given HRP and converted data characters."""
40 check = bech32_polymod(bech32_hrp_expand(hrp) + data)
41 if check == 1:
42 return Encoding.BECH32
43 if check == 0x2bc830a3:
44 return Encoding.BECH32M
45 return None
46
47def bech32_create_checksum(hrp, data, spec):
48 """Compute the checksum values given HRP and data."""
49 values = bech32_hrp_expand(hrp) + data
50 const = 0x2bc830a3 if spec == Encoding.BECH32M else 1
51 polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ const
52 return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
53
54def bech32_encode(hrp, data, spec):
55 """Compute a Bech32 or Bech32m string given HRP, data characters and spec."""
56 combined = data + bech32_create_checksum(hrp, data, spec)
57 return hrp + '1' + ''.join([CHARSET[d] for d in combined])
58
59def bech32_decode(bech):
60 """Validate a Bech32 or Bech32m string, and determine HRP and data."""
61 if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or
62 (bech.lower() != bech and bech.upper() != bech)):
63 return (None, None, None)
64 bech = bech.lower()
65 pos = bech.rfind('1')
66 if pos < 1 or pos + 7 > len(bech) or len(bech) > 90:
67 return (None, None, None)
68 if not all(x in CHARSET for x in bech[pos+1:]):
69 return (None, None, None)
70 hrp = bech[:pos]
71 data = [CHARSET.find(x) for x in bech[pos+1:]]
72 spec = bech32_verify_checksum(hrp, data)
73 if spec is None:
74 return (None, None, None)
75 return (hrp, data[:-6], spec)
76
77# Example usage:
78if __name__ == "__main__":
79 # Encode
80 hrp = "bech32"
81 data = [0, 1, 2]
82 encoded = bech32_encode(hrp, data, Encoding.BECH32)
83 print(f"Encoded: {encoded}")
84
85 # Decode
86 decoded_hrp, decoded_data, encoding_type = bech32_decode(encoded)
87 print(f"Decoded HRP: {decoded_hrp}")
88 print(f"Decoded Data: {decoded_data}")