1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
# Partially copy-pasted from python-bitcoinlib:
# https://github.com/petertodd/python-bitcoinlib/blob/master/bitcoin/base58.py
"""Base58 encoding and decoding"""
import binascii
from . import hashes
B58_DIGITS = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
def encode(b: bytes) -> str:
"""Encode bytes to a base58-encoded string"""
# Convert big-endian bytes to integer
n = int("0x0" + binascii.hexlify(b).decode("utf8"), 16)
# Divide that integer into bas58
chars = []
while n > 0:
n, r = divmod(n, 58)
chars.append(B58_DIGITS[r])
result = "".join(chars[::-1])
pad = 0
for c in b:
if c == 0:
pad += 1
else:
break
return B58_DIGITS[0] * pad + result
def decode(s: str) -> bytes:
"""Decode a base58-encoding string, returning bytes"""
if not s:
return b""
# Convert the string to an integer
n = 0
for c in s:
n *= 58
if c not in B58_DIGITS:
raise ValueError("Character %r is not a valid base58 character" % c)
digit = B58_DIGITS.index(c)
n += digit
# Convert the integer to bytes
h = "%x" % n
if len(h) % 2:
h = "0" + h
res = binascii.unhexlify(h.encode("utf8"))
# Add padding back.
pad = 0
for c in s[:-1]:
if c == B58_DIGITS[0]:
pad += 1
else:
break
return b"\x00" * pad + res
def encode_check(b: bytes) -> str:
"""Encode bytes to a base58-encoded string with a checksum"""
return encode(b + hashes.double_sha256(b)[0:4])
def decode_check(s: str) -> bytes:
"""Decode a base58-encoding string with checksum check.
Returns bytes without checksum
"""
b = decode(s)
checksum = hashes.double_sha256(b[:-4])[:4]
if b[-4:] != checksum:
raise ValueError(
"Checksum mismatch: expected %r, calculated %r" % (b[-4:], checksum)
)
return b[:-4]
|