|
|
|
|
@ -559,33 +559,26 @@ def base_encode(v: bytes, *, base: int) -> str:
|
|
|
|
|
chars = __b58chars |
|
|
|
|
if base == 43: |
|
|
|
|
chars = __b43chars |
|
|
|
|
long_value = 0 |
|
|
|
|
power_of_base = 1 |
|
|
|
|
for c in v[::-1]: |
|
|
|
|
# naive but slow variant: long_value += (256**i) * c |
|
|
|
|
long_value += power_of_base * c |
|
|
|
|
power_of_base <<= 8 |
|
|
|
|
result = bytearray() |
|
|
|
|
while long_value >= base: |
|
|
|
|
div, mod = divmod(long_value, base) |
|
|
|
|
result.append(chars[mod]) |
|
|
|
|
long_value = div |
|
|
|
|
result.append(chars[long_value]) |
|
|
|
|
# Bitcoin does a little leading-zero-compression: |
|
|
|
|
# leading 0-bytes in the input become leading-1s |
|
|
|
|
nPad = 0 |
|
|
|
|
for c in v: |
|
|
|
|
if c == 0x00: |
|
|
|
|
nPad += 1 |
|
|
|
|
else: |
|
|
|
|
break |
|
|
|
|
result.extend([chars[0]] * nPad) |
|
|
|
|
result.reverse() |
|
|
|
|
|
|
|
|
|
origlen = len(v) |
|
|
|
|
v = v.lstrip(b'\x00') |
|
|
|
|
newlen = len(v) |
|
|
|
|
|
|
|
|
|
num = int.from_bytes(v, byteorder='big') |
|
|
|
|
string = b"" |
|
|
|
|
while num: |
|
|
|
|
num, idx = divmod(num, base) |
|
|
|
|
string = chars[idx:idx + 1] + string |
|
|
|
|
|
|
|
|
|
result = chars[0:1] * (origlen - newlen) + string |
|
|
|
|
return result.decode('ascii') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def base_decode(v: Union[bytes, str], *, base: int, length: int = None) -> Optional[bytes]: |
|
|
|
|
""" decode v into a string of len bytes.""" |
|
|
|
|
def base_decode(v: Union[bytes, str], *, base: int) -> Optional[bytes]: |
|
|
|
|
""" decode v into a string of len bytes. |
|
|
|
|
|
|
|
|
|
based on the work of David Keijser in https://github.com/keis/base58 |
|
|
|
|
""" |
|
|
|
|
# assert_bytes(v) |
|
|
|
|
v = to_bytes(v, 'ascii') |
|
|
|
|
if base not in (58, 43): |
|
|
|
|
@ -595,33 +588,19 @@ def base_decode(v: Union[bytes, str], *, base: int, length: int = None) -> Optio
|
|
|
|
|
if base == 43: |
|
|
|
|
chars = __b43chars |
|
|
|
|
chars_inv = __b43chars_inv |
|
|
|
|
long_value = 0 |
|
|
|
|
power_of_base = 1 |
|
|
|
|
for c in v[::-1]: |
|
|
|
|
try: |
|
|
|
|
digit = chars_inv[c] |
|
|
|
|
except KeyError: |
|
|
|
|
raise BaseDecodeError('Forbidden character {} for base {}'.format(c, base)) |
|
|
|
|
# naive but slow variant: long_value += digit * (base**i) |
|
|
|
|
long_value += digit * power_of_base |
|
|
|
|
power_of_base *= base |
|
|
|
|
result = bytearray() |
|
|
|
|
while long_value >= 256: |
|
|
|
|
div, mod = divmod(long_value, 256) |
|
|
|
|
result.append(mod) |
|
|
|
|
long_value = div |
|
|
|
|
result.append(long_value) |
|
|
|
|
nPad = 0 |
|
|
|
|
for c in v: |
|
|
|
|
if c == chars[0]: |
|
|
|
|
nPad += 1 |
|
|
|
|
else: |
|
|
|
|
break |
|
|
|
|
result.extend(b'\x00' * nPad) |
|
|
|
|
if length is not None and len(result) != length: |
|
|
|
|
return None |
|
|
|
|
result.reverse() |
|
|
|
|
return bytes(result) |
|
|
|
|
|
|
|
|
|
origlen = len(v) |
|
|
|
|
v = v.lstrip(chars[0:1]) |
|
|
|
|
newlen = len(v) |
|
|
|
|
|
|
|
|
|
num = 0 |
|
|
|
|
try: |
|
|
|
|
for char in v: |
|
|
|
|
num = num * base + chars_inv[char] |
|
|
|
|
except KeyError: |
|
|
|
|
raise BaseDecodeError('Forbidden character {} for base {}'.format(char, base)) |
|
|
|
|
|
|
|
|
|
return num.to_bytes(origlen - newlen + (num.bit_length() + 7) // 8, 'big') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidChecksum(BaseDecodeError): |
|
|
|
|
|