Base58Check encoding in Python

The previous post began by saying “Bitcoin’s Wallet Import Format (WIF) is essentially Base58 encoding with a checksum.” More specifically, WIF uses Base58Check encoding.

This post will fill in the missing details and show how to carry out computing Base58Check in Python. There are multiple ways to stub your toe doing this because it involves encoding issues. You have to compute hash functions, which are conceptually easy, but you get into issues of converting strings into bytes, byte order, endianness, etc. And in Python, the output of a hash isn’t a number or a string, but a object that you have to “digest” one way or another. Then there’s getting the syntax just right to do the Base58 encoding.

This post will step through this tutorial exmaple.

***

The example says to take the SHA256 hash of

    800C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D

and get

    8147786C4D15106333BF278D71DADAF1079EF2D2440A4DDE37D747DED5403592

OK, here we go:

>>> from hashlib import sha256
>>> s = "800C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D"
>>> d = bytes.fromhex(s)
>>> sha256(d).hexdigest().upper()
'8147786C4D15106333BF278D71DADAF1079EF2D2440A4DDE37D747DED5403592'

This matches what we were supposed to get.

Next the sample says to hash the result again. We have to hash the bytes of the first hash, not the string representation.

>>> sha256(sha256(d).digest()).hexdigest().upper()
'507A5B8DFED0FC6FE8801743720CEDEC06AA5C6FCA72B07C49964492FB98A714'

The output matches what the example says we should get.

Now we’re supposed to take the first 4 bytes (represented by the first 8 hex characters) and stick them on the end of the address we stored as s above.

s += '507A5B8D'

And finally we’re supposed to convert the result to Base58.

>>> from base58 import b58encode
>>> b58encode(bytes.fromhex(s))
b'5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ'

This matches the result in the example.

Leave a Reply

Your email address will not be published. Required fields are marked *