111 lines
2.9 KiB
Python
111 lines
2.9 KiB
Python
from pybtc.functions.hash import double_sha256
|
|
from pybtc.crypto import __decode_base58__, __encode_base58__
|
|
|
|
b58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
|
base32charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
|
|
base32charset_upcase = "QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L"
|
|
|
|
int_base32_map = dict()
|
|
base32_int_map = dict()
|
|
|
|
for n, i in enumerate(base32charset):
|
|
int_base32_map[i] = n
|
|
base32_int_map[n] = ord(i)
|
|
for n, i in enumerate(base32charset_upcase):
|
|
int_base32_map[i] = n
|
|
|
|
|
|
def rebasebits(data, frombits, tobits, pad=True):
|
|
"""General power-of-2 base conversion."""
|
|
acc = 0
|
|
bits = 0
|
|
ret = bytearray()
|
|
append = ret.append
|
|
maxv = (1 << tobits) - 1
|
|
max_acc = (1 << (frombits + tobits - 1)) - 1
|
|
for value in data:
|
|
if value < 0 or (value >> frombits):
|
|
raise ValueError("invalid bytes")
|
|
acc = ((acc << frombits) | value) & max_acc
|
|
bits += frombits
|
|
while bits >= tobits:
|
|
bits -= tobits
|
|
append((acc >> bits) & maxv)
|
|
if pad:
|
|
if bits:
|
|
append((acc << (tobits - bits)) & maxv)
|
|
elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
|
|
raise ValueError("invalid padding")
|
|
return ret
|
|
|
|
|
|
def rebase_5_to_8(data, pad = True):
|
|
return rebasebits(data, 5, 8, pad)
|
|
|
|
|
|
def rebase_8_to_5(data, pad = True):
|
|
return rebasebits(data, 8, 5, pad)
|
|
|
|
|
|
def rebase_32_to_5(data):
|
|
if isinstance(data, bytes):
|
|
data = data.decode()
|
|
b = bytearray()
|
|
append = b.append
|
|
try:
|
|
[append(int_base32_map[i]) for i in data]
|
|
except:
|
|
raise Exception("Non base32 characters")
|
|
return b
|
|
|
|
|
|
def rebase_5_to_32(data, bytes = True):
|
|
r = bytearray()
|
|
append = r.append
|
|
[append(base32_int_map[i]) for i in data]
|
|
return r.decode() if not bytes else r
|
|
|
|
|
|
def bech32_polymod(values):
|
|
"""Internal function that computes the Bech32 checksum."""
|
|
generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
|
|
chk = 1
|
|
for value in values:
|
|
top = chk >> 25
|
|
chk = (chk & 0x1ffffff) << 5 ^ value
|
|
for i in range(5):
|
|
chk ^= generator[i] if ((top >> i) & 1) else 0
|
|
return chk ^ 1
|
|
|
|
|
|
def encode_base58(b):
|
|
|
|
"""Encode bytes to a base58-encoded string"""
|
|
# Convert big-endian bytes to integer
|
|
if not b:
|
|
return ''
|
|
if not isinstance(b, bytes):
|
|
raise ValueError("encode_base58 bytes required")
|
|
|
|
return __encode_base58__(b)
|
|
|
|
|
|
def decode_base58(s):
|
|
"""Decode a base58-encoding string, returning bytes"""
|
|
if not s:
|
|
return b''
|
|
if not isinstance(s, str):
|
|
raise ValueError("decode_base58 string required")
|
|
return __decode_base58__(s)
|
|
|
|
|
|
def encode_base58_with_checksum(b):
|
|
return encode_base58(b"%s%s" % (b, double_sha256(b)[:4]))
|
|
|
|
|
|
def decode_base58_with_checksum(s):
|
|
b = decode_base58(s)
|
|
if double_sha256(b[:-4])[:4] != b[-4:]:
|
|
raise Exception("invalid checksum")
|
|
return b[:-4]
|