1- ''' Base58 encoding
1+ """ Base58 encoding
22
33Implementations of Base58 and Base58Check encodings that are compatible
44with the bitcoin network.
5- '''
5+ """
66
77# This module is based upon base58 snippets found scattered over many bitcoin
88# tools written in python. From what I gather the original source is from a
1111
1212from functools import lru_cache
1313from hashlib import sha256
14- from typing import Mapping , Union
14+ from typing import Dict , Tuple , Union
1515from math import log
1616
1717try :
1818 from gmpy2 import mpz
1919except ImportError :
2020 mpz = None
2121
22- __version__ = ' 2.1.1'
22+ __version__ = " 2.1.1"
2323
2424# 58 character alphabet used
25- BITCOIN_ALPHABET = \
26- b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
27- RIPPLE_ALPHABET = b'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz'
25+ BITCOIN_ALPHABET = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
26+ RIPPLE_ALPHABET = b"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"
2827XRP_ALPHABET = RIPPLE_ALPHABET
28+ _MPZ_ALPHABET = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
2929POWERS = {
30- 45 : {2 ** i : 45 ** (2 ** i ) for i in range (4 , 20 )},
31- 58 : {2 ** i : 58 ** (2 ** i ) for i in range (4 , 20 )}
32- }
30+ 45 : {2 ** i : 45 ** (2 ** i ) for i in range (4 , 20 )},
31+ 58 : {2 ** i : 58 ** (2 ** i ) for i in range (4 , 20 )},
32+ } # type: Dict[int, Dict[int, int]]
3333
3434# Retro compatibility
3535alphabet = BITCOIN_ALPHABET
3636
3737
3838def scrub_input (v : Union [str , bytes ]) -> bytes :
3939 if isinstance (v , str ):
40- v = v .encode (' ascii' )
40+ v = v .encode (" ascii" )
4141
4242 return v
4343
@@ -52,21 +52,20 @@ def _encode_int(i: int, base: int = 58, alphabet: bytes = BITCOIN_ALPHABET) -> b
5252 while i :
5353 i , idx = divmod (i , base )
5454 string .append (idx )
55- return string [::- 1 ]
55+ return bytes ( string [::- 1 ])
5656 else :
57- origlen0 = int (log (i , 58 ))// 2
57+ origlen0 = int (log (i , 58 )) // 2
5858 try :
5959 split_num = POWERS [base ][2 ** origlen0 ]
6060 except KeyError :
61- POWERS [base ][2 ** origlen0 ] = split_num = base ** origlen0
61+ POWERS [base ][2 ** origlen0 ] = split_num = base ** origlen0
6262 i1 , i0 = divmod (i , split_num )
6363
6464 v1 = _encode_int (i1 , base , alphabet )
6565 v0 = _encode_int (i0 , base , alphabet )
6666 newlen0 = len (v0 )
6767 if newlen0 < origlen0 :
68- v0 [:0 ] = b'\0 ' * (origlen0 - newlen0 )
69-
68+ v0 = b"\0 " * (origlen0 - newlen0 ) + v0
7069 return v1 + v0
7170
7271
@@ -77,7 +76,7 @@ def _mpz_encode(i: int, alphabet: bytes) -> bytes:
7776 base = len (alphabet )
7877
7978 raw : bytes = mpz (i ).digits (base ).encode ()
80- tr_bytes = bytes .maketrans ('' . join ([ mpz ( x ). digits ( base ) for x in range ( base )]). encode () , alphabet )
79+ tr_bytes = bytes .maketrans (_MPZ_ALPHABET [: base ] , alphabet )
8180 encoded : bytes = raw .translate (tr_bytes )
8281
8382 return encoded
@@ -92,49 +91,56 @@ def b58encode_int(
9291 if not i :
9392 if default_one :
9493 return alphabet [0 :1 ]
95- return b''
94+ return b""
9695 if mpz :
9796 return _mpz_encode (i , alphabet )
9897
9998 base = len (alphabet )
10099 raw_string = _encode_int (i , base , alphabet )
101- string = raw_string .translate (bytes .maketrans (bytearray (range (len (alphabet ))), alphabet ))
100+ string = raw_string .translate (
101+ bytes .maketrans (bytearray (range (len (alphabet ))), alphabet )
102+ )
102103
103104 return string
104105
105106
106- def b58encode (
107- v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET
108- ) -> bytes :
107+ def b58encode (v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET ) -> bytes :
109108 """
110109 Encode a string using Base58
111110 """
112111 v = scrub_input (v )
113112
114113 origlen = len (v )
115- v = v .lstrip (b' \0 ' )
114+ v = v .lstrip (b" \0 " )
116115 newlen = len (v )
117116
118- acc = int .from_bytes (v , byteorder = ' big' ) # first byte is most significant
117+ acc = int .from_bytes (v , byteorder = " big" ) # first byte is most significant
119118
120119 result = b58encode_int (acc , default_one = False , alphabet = alphabet )
121120 return alphabet [0 :1 ] * (origlen - newlen ) + result
122121
123122
124123@lru_cache ()
125- def _get_base58_decode_map (alphabet : bytes ,
126- autofix : bool ) -> Mapping [int , int ]:
124+ def _get_base58_decode_map (alphabet : bytes , autofix : bool ) -> Tuple [bytes , bytes ]:
127125 invmap = {char : index for index , char in enumerate (alphabet )}
128-
126+ base = len ( alphabet )
129127 if autofix :
130- groups = [b' 0Oo' , b' Il1' ]
128+ groups = [b" 0Oo" , b" Il1" ]
131129 for group in groups :
132130 pivots = [c for c in group if c in invmap ]
133131 if len (pivots ) == 1 :
134132 for alternative in group :
135133 invmap [alternative ] = invmap [pivots [0 ]]
136134
137- return invmap
135+ del_chars = bytes (bytearray (x for x in range (256 ) if x not in invmap ))
136+
137+ if mpz is not None :
138+ mpz_alphabet = "" .join ([mpz (x ).digits (base ) for x in invmap .values ()]).encode ()
139+ tr_bytes = bytes .maketrans (bytearray (invmap .keys ()), mpz_alphabet )
140+ return tr_bytes , del_chars
141+
142+ tr_bytes = bytes .maketrans (bytearray (invmap .keys ()), bytearray (invmap .values ()))
143+ return tr_bytes , del_chars
138144
139145
140146def _decode (data : bytes , min_split : int = 256 , base : int = 58 ) -> int :
@@ -147,39 +153,32 @@ def _decode(data: bytes, min_split: int = 256, base: int = 58) -> int:
147153 ret_int = base * ret_int + val
148154 return ret_int
149155 else :
150- split_len = 2 ** (len (data ).bit_length ()- 2 )
156+ split_len = 2 ** (len (data ).bit_length () - 2 )
151157 try :
152158 base_pow = POWERS [base ][split_len ]
153159 except KeyError :
154- POWERS [base ] = base_pow = base ** split_len
160+ POWERS [base ] = base_pow = base ** split_len
155161 return (base_pow * _decode (data [:- split_len ])) + _decode (data [- split_len :])
156162
157163
158164def b58decode_int (
159- v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET , * ,
160- autofix : bool = False
165+ v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET , * , autofix : bool = False
161166) -> int :
162167 """
163168 Decode a Base58 encoded string as an integer
164169 """
165- if b' ' not in alphabet :
170+ if b" " not in alphabet :
166171 v = v .rstrip ()
167172 v = scrub_input (v )
168173
169174 base = len (alphabet )
170- map = _get_base58_decode_map (alphabet , autofix = autofix )
171- if mpz :
172- tr_bytes = bytes .maketrans (bytearray (map .keys ()), '' .join ([mpz (x ).digits (base ) for x in map .values ()]).encode ())
173- else :
174- tr_bytes = bytes .maketrans (bytearray (map .keys ()), bytearray (map .values ()))
175- del_chars = bytes (bytearray (x for x in range (256 ) if x not in map ))
176-
175+ tr_bytes , del_chars = _get_base58_decode_map (alphabet , autofix = autofix )
177176 cv = v .translate (tr_bytes , delete = del_chars )
178177 if len (v ) != len (cv ):
179- err_char = chr (next (c for c in v if c not in map ))
178+ err_char = chr (next (c for c in v if c in del_chars ))
180179 raise ValueError ("Invalid character {!r}" .format (err_char ))
181180
182- if cv == b'' :
181+ if cv == b"" :
183182 return 0
184183
185184 if mpz :
@@ -192,8 +191,7 @@ def b58decode_int(
192191
193192
194193def b58decode (
195- v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET , * ,
196- autofix : bool = False
194+ v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET , * , autofix : bool = False
197195) -> bytes :
198196 """
199197 Decode a Base58 encoded string
@@ -210,9 +208,7 @@ def b58decode(
210208 return acc .to_bytes (origlen - newlen + (acc .bit_length () + 7 ) // 8 , "big" )
211209
212210
213- def b58encode_check (
214- v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET
215- ) -> bytes :
211+ def b58encode_check (v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET ) -> bytes :
216212 """
217213 Encode a string using Base58 with a 4 character checksum
218214 """
@@ -223,10 +219,9 @@ def b58encode_check(
223219
224220
225221def b58decode_check (
226- v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET , * ,
227- autofix : bool = False
222+ v : Union [str , bytes ], alphabet : bytes = BITCOIN_ALPHABET , * , autofix : bool = False
228223) -> bytes :
229- ''' Decode and verify the checksum of a Base58 encoded string'''
224+ """ Decode and verify the checksum of a Base58 encoded string"""
230225
231226 result = b58decode (v , alphabet = alphabet , autofix = autofix )
232227 result , check = result [:- 4 ], result [- 4 :]
0 commit comments