Skip to content

Instantly share code, notes, and snippets.

@ianoxley
Created March 11, 2011 14:00
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save ianoxley/865912 to your computer and use it in GitHub Desktop.
Save ianoxley/865912 to your computer and use it in GitHub Desktop.
base58 encoding in Python
""" 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()
@BenGimli
Copy link

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?

@acarmisc
Copy link

@BenGimli num must be a number

@rootux
Copy link

rootux commented Jan 1, 2018

Here is a library that does that https://github.com/keis/base58

@john-shine
Copy link

alphabet is "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" not "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" if in Bitcoin

@blakev
Copy link

blakev commented Jun 10, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment