Skip to content

Commit 8f5909e

Browse files
Fix Base58 encoding/decoding
1 parent e641f3d commit 8f5909e

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

ciphers/base58.py

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
2+
3+
4+
def base58_encode(data: bytes) -> str:
5+
"""Encodes data in Base58.
6+
7+
Args:
8+
data (bytes): Data to be encoded.
9+
10+
Returns:
11+
str: Base58 encoded string.
12+
"""
13+
num = int.from_bytes(data, "big")
14+
encoded = ""
15+
while num > 0:
16+
num, rem = divmod(num, 58)
17+
encoded = BASE58_ALPHABET[rem] + encoded
18+
19+
# Add '1' for each leading 0 byte
20+
n = 0
21+
for byte in data:
22+
if byte == 0:
23+
n += 1
24+
else:
25+
break
26+
return "1" * n + encoded
27+
28+
29+
def base58_decode(s: str) -> bytes:
30+
"""Decodes Base58 encoded string back to bytes.
31+
32+
Args:
33+
s (str): Base58 encoded string.
34+
35+
Returns:
36+
bytes: Decoded data.
37+
38+
Raises:
39+
ValueError: If the string contains invalid Base58 characters.
40+
"""
41+
num = 0
42+
for char in s:
43+
if char not in BASE58_ALPHABET:
44+
error_message = f"Invalid character '{char}' in Base58 string"
45+
raise ValueError(error_message)
46+
num *= 58
47+
num += BASE58_ALPHABET.index(char)
48+
49+
# Convert the number to bytes
50+
combined = num.to_bytes((num.bit_length() + 7) // 8, "big")
51+
52+
# Add leading zeros
53+
num_leading_zeros = len(s) - len(s.lstrip("1"))
54+
return b"\x00" * num_leading_zeros + combined
55+
56+
57+
if __name__ == "__main__":
58+
import doctest
59+
60+
doctest.testmod()

0 commit comments

Comments
 (0)