bitcoin: 3x speedup for DecodeBase58Check
(compared to HEAD~2)
rewrite base_{decode,encode} based on 2fae7065e3/base58/__init__.py
This commit is contained in:
@@ -559,33 +559,26 @@ def base_encode(v: bytes, *, base: int) -> str:
|
|||||||
chars = __b58chars
|
chars = __b58chars
|
||||||
if base == 43:
|
if base == 43:
|
||||||
chars = __b43chars
|
chars = __b43chars
|
||||||
long_value = 0
|
|
||||||
power_of_base = 1
|
origlen = len(v)
|
||||||
for c in v[::-1]:
|
v = v.lstrip(b'\x00')
|
||||||
# naive but slow variant: long_value += (256**i) * c
|
newlen = len(v)
|
||||||
long_value += power_of_base * c
|
|
||||||
power_of_base <<= 8
|
num = int.from_bytes(v, byteorder='big')
|
||||||
result = bytearray()
|
string = b""
|
||||||
while long_value >= base:
|
while num:
|
||||||
div, mod = divmod(long_value, base)
|
num, idx = divmod(num, base)
|
||||||
result.append(chars[mod])
|
string = chars[idx:idx + 1] + string
|
||||||
long_value = div
|
|
||||||
result.append(chars[long_value])
|
result = chars[0:1] * (origlen - newlen) + string
|
||||||
# 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()
|
|
||||||
return result.decode('ascii')
|
return result.decode('ascii')
|
||||||
|
|
||||||
|
|
||||||
def base_decode(v: Union[bytes, str], *, base: int, length: int = None) -> Optional[bytes]:
|
def base_decode(v: Union[bytes, str], *, base: int) -> Optional[bytes]:
|
||||||
""" decode v into a string of len 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)
|
# assert_bytes(v)
|
||||||
v = to_bytes(v, 'ascii')
|
v = to_bytes(v, 'ascii')
|
||||||
if base not in (58, 43):
|
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:
|
if base == 43:
|
||||||
chars = __b43chars
|
chars = __b43chars
|
||||||
chars_inv = __b43chars_inv
|
chars_inv = __b43chars_inv
|
||||||
long_value = 0
|
|
||||||
power_of_base = 1
|
origlen = len(v)
|
||||||
for c in v[::-1]:
|
v = v.lstrip(chars[0:1])
|
||||||
try:
|
newlen = len(v)
|
||||||
digit = chars_inv[c]
|
|
||||||
except KeyError:
|
num = 0
|
||||||
raise BaseDecodeError('Forbidden character {} for base {}'.format(c, base))
|
try:
|
||||||
# naive but slow variant: long_value += digit * (base**i)
|
for char in v:
|
||||||
long_value += digit * power_of_base
|
num = num * base + chars_inv[char]
|
||||||
power_of_base *= base
|
except KeyError:
|
||||||
result = bytearray()
|
raise BaseDecodeError('Forbidden character {} for base {}'.format(char, base))
|
||||||
while long_value >= 256:
|
|
||||||
div, mod = divmod(long_value, 256)
|
return num.to_bytes(origlen - newlen + (num.bit_length() + 7) // 8, 'big')
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidChecksum(BaseDecodeError):
|
class InvalidChecksum(BaseDecodeError):
|
||||||
|
|||||||
Reference in New Issue
Block a user