-
-
Save ianoxley/865912 to your computer and use it in GitHub Desktop.
""" base58 encoding / decoding functions """ | |
import unittest | |
alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' | |
base_count = len(alphabet) | |
def encode(num): | |
""" Returns num in a base58-encoded string """ | |
encode = '' | |
if (num < 0): | |
return '' | |
while (num >= base_count): | |
mod = num % base_count | |
encode = alphabet[mod] + encode | |
num = num / base_count | |
if (num): | |
encode = alphabet[num] + encode | |
return encode | |
def decode(s): | |
""" Decodes the base58-encoded string s into an integer """ | |
decoded = 0 | |
multi = 1 | |
s = s[::-1] | |
for char in s: | |
decoded += multi * alphabet.index(char) | |
multi = multi * base_count | |
return decoded | |
class Base58Tests(unittest.TestCase): | |
def test_alphabet_length(self): | |
self.assertEqual(58, len(alphabet)) | |
def test_encode_10002343_returns_Tgmc(self): | |
result = encode(10002343) | |
self.assertEqual('Tgmc', result) | |
def test_decode_Tgmc_returns_10002343(self): | |
decoded = decode('Tgmc') | |
self.assertEqual(10002343, decoded) | |
def test_encode_1000_returns_if(self): | |
result = encode(1000) | |
self.assertEqual('if', result) | |
def test_decode_if_returns_1000(self): | |
decoded = decode('if') | |
self.assertEqual(1000, decoded) | |
def test_encode_zero_returns_empty_string(self): | |
self.assertEqual('', encode(0)) | |
def test_encode_negative_number_returns_empty_string(self): | |
self.assertEqual('', encode(-100)) | |
if __name__ == '__main__': | |
unittest.main() |
You may remove this content if you find it not in context of your gist. But if a user simply wants to convert a string into a base-58 encoded function, he could use the following:
def encode(num):
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
####convert each digit into unicode
buffer = [ord(each[0]) for each in str(num)]
print 'Buffer:', buffer
digits = [0]; i= 0; j = 0;
while (i < len(buffer)): #loop for as many digits are present
j = 0
while (j < len(digits)):
digits[j] <<= 8
j += 1
digits[0] += buffer[i]
carry = 0; j = 0;
while(j < len(digits)):
digits[j] += carry
carry = (digits[j]/58) | 0
digits[j] %= 58;
j += 1
while(carry):
digits.append(carry%58)
carry = (carry/58) | 0
i += 1
print 'Digits:', digits
i = 0;
while (buffer[i] == 0 and i < len(buffer) - 1):
digits.push(0);
i += 1;
print digits
print 'Result:', [alphabet[each] for each in digits][::-1]
Inspirations from this URL: https://www.browserling.com/tools/base58-encode
Just learning python
When running this program, I get this error
encode = alphabet[num] + encode
TypeError: string indices must be integers
I'm using version 3.6
What am I missing?
@BenGimli num
must be a number
Here is a library that does that https://github.com/keis/base58
alphabet is "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" not "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" if in Bitcoin
A slight variation on the original uses a List instead of rebuilding strings, as well as type hints for Cython + Mypy:
from typing import List
ALPHA = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
def b58encode(num: int) -> str:
"""Converts a number into Base-58.
"""
encoded: List[str] = []
alpha_cnt: int = len(ALPHA)
if num < 0:
return ''
while num >= alpha_cnt:
mod = num % alpha_cnt
num //= alpha_cnt
encoded.append(ALPHA[mod])
if num > 0:
encoded.append(ALPHA[num])
return ''.join(encoded[::-1])
def b58decode(ins: str) -> int:
"""Converts a Base-58 encoded integer, as string, back to a number.
"""
multi: int = 1
decoded: int = 0
alpha_cnt: int = len(ALPHA)
for char in ins[::-1]:
decoded += multi * ALPHA.index(char)
multi *= alpha_cnt
return decoded
Thanks for the starting point, gave me something to think about as I worked through my problem at a bleary-eyed 0500h.
Here are the business-bitz of my re-factored version. Submitted for your entertainment as you might find something of interest i.e. the encode while loop.
Interesting tidbit: For a very long/large integer, the actual difference in length of the encoded value between base-58 and base-94 deviated only two or three characters. Hardly worth the hassles of enclosing punctuation as found in the 'toy' base-94 as supplied.
I added the alternate decoder version in case it helps someone else that stumbles upon this (sort of like you reminded me of the [::-1] construct).
Here are a couple of simple cross-pollinating tests that fit with the original base58 code.
At some point I might push this to ActiveState's cookbook. With your permission I will add your name in credit if/when that happens. Regardless, I have no interest in licensing terms for such simple scripts... I've already spent more time typing this paragraph than this portion of the subject is worth! So to whomever it is useful, cheers!