2019-02-28 22:54:37 +01:00
|
|
|
from lbrynet.schema.constants import ADDRESS_CHECKSUM_LENGTH
|
2018-09-17 22:31:44 +02:00
|
|
|
from lbrynet.schema.hashing import double_sha256
|
|
|
|
from lbrynet.schema.error import InvalidAddress
|
2018-09-17 22:13:30 +02:00
|
|
|
|
|
|
|
|
|
|
|
alphabet = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
|
|
|
|
|
|
|
|
|
|
|
def scrub_input(v):
|
|
|
|
if isinstance(v, str) and not isinstance(v, bytes):
|
|
|
|
v = v.encode('ascii')
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
def b58encode_int(i, default_one=True):
|
|
|
|
'''Encode an integer using Base58'''
|
|
|
|
if not i and default_one:
|
|
|
|
return alphabet[0:1]
|
|
|
|
string = b""
|
|
|
|
while i:
|
|
|
|
i, idx = divmod(i, 58)
|
|
|
|
string = alphabet[idx:idx+1] + string
|
|
|
|
return string
|
|
|
|
|
|
|
|
|
|
|
|
def b58encode(v):
|
|
|
|
'''Encode a string using Base58'''
|
|
|
|
|
|
|
|
v = scrub_input(v)
|
|
|
|
|
|
|
|
nPad = len(v)
|
|
|
|
v = v.lstrip(b'\0')
|
|
|
|
nPad -= len(v)
|
|
|
|
|
|
|
|
p, acc = 1, 0
|
2018-11-23 05:24:21 +01:00
|
|
|
for c in reversed(v):
|
2018-09-17 22:13:30 +02:00
|
|
|
acc += p * c
|
|
|
|
p = p << 8
|
|
|
|
|
|
|
|
result = b58encode_int(acc, default_one=False)
|
|
|
|
|
|
|
|
return alphabet[0:1] * nPad + result
|
|
|
|
|
|
|
|
|
|
|
|
def b58decode_int(v):
|
|
|
|
'''Decode a Base58 encoded string as an integer'''
|
|
|
|
|
|
|
|
v = scrub_input(v)
|
|
|
|
|
|
|
|
decimal = 0
|
|
|
|
for char in v:
|
|
|
|
decimal = decimal * 58 + alphabet.index(char)
|
|
|
|
return decimal
|
|
|
|
|
|
|
|
|
|
|
|
def b58decode(v):
|
|
|
|
'''Decode a Base58 encoded string'''
|
|
|
|
|
|
|
|
v = scrub_input(v)
|
|
|
|
|
|
|
|
origlen = len(v)
|
|
|
|
v = v.lstrip(alphabet[0:1])
|
|
|
|
newlen = len(v)
|
|
|
|
|
|
|
|
acc = b58decode_int(v)
|
|
|
|
|
|
|
|
result = []
|
|
|
|
while acc > 0:
|
|
|
|
acc, mod = divmod(acc, 256)
|
|
|
|
result.append(mod)
|
|
|
|
|
2018-11-23 05:24:21 +01:00
|
|
|
return b'\0' * (origlen - newlen) + bytes(reversed(result))
|
2018-09-17 22:13:30 +02:00
|
|
|
|
|
|
|
|
|
|
|
def validate_b58_checksum(addr_bytes):
|
|
|
|
addr_without_checksum = addr_bytes[:-ADDRESS_CHECKSUM_LENGTH]
|
|
|
|
addr_checksum = addr_bytes[-ADDRESS_CHECKSUM_LENGTH:]
|
|
|
|
if double_sha256(addr_without_checksum)[:ADDRESS_CHECKSUM_LENGTH] != addr_checksum:
|
|
|
|
raise InvalidAddress("Invalid address checksum")
|
|
|
|
|
|
|
|
|
|
|
|
def b58decode_strip_checksum(v):
|
|
|
|
addr_bytes = b58decode(v)
|
|
|
|
validate_b58_checksum(addr_bytes)
|
|
|
|
return addr_bytes[:-ADDRESS_CHECKSUM_LENGTH]
|
|
|
|
|
|
|
|
|
|
|
|
def b58encode_with_checksum(addr_bytes):
|
|
|
|
addr_checksum = double_sha256(addr_bytes)[:ADDRESS_CHECKSUM_LENGTH]
|
|
|
|
return b58encode(addr_bytes + addr_checksum)
|