File: base58.py

package info (click to toggle)
python-ledger-bitcoin 0.4.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 720 kB
  • sloc: python: 9,357; makefile: 2
file content (79 lines) | stat: -rw-r--r-- 1,978 bytes parent folder | download
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]