base58 is like base64, but without these characters: +/0OIl

See Also

ycl string base encode/decode mod
Encodes and decodes bytes using the given list of encoding characters. Includes convenience functions to do bitcoin, ripple, and flickr encoding and decoding.


base58 is used in the bitcoin system, and there is apparently a different version of base58 used by Flickr.

The rationale behind the use of base58, at least for bitcoin, is:

  • Characters like 0 and O, or I and l are too similar in some fonts and could be used to create account numbers that are hard to distinguish visually.
  • A string with non-alphanumeric characters is not as easily accepted as an account number.
  • E-mail content isn't broken into lines where there's no punctuation to break at.
  • Doubleclicking selects the whole number as one word if it's all alphanumeric.

The alphabet used is: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz.

JMN 2011-06-28: Does anyone know if there are existing Tcl implementations of base58 as used by bitcoin?

AK - 2011-06-28 17:41:27

I do not know of any implementation. If one is made by whoever I would strongly recommend to submit the code to Tcllib for inclusion, as it already has base64, base32, ascii85, uu, yEnc, etc. I.e. a base58 implementation would fit right in.

aspect: this came up in the Tcl Chatroom so I did a quick implementation. base58 is not so good for encoding binary chunks, as it doesn't correspond neatly to a length in bits. This version base58-encodes an integer:

proc base58 {hex} {
  set alphabet 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
  set result {}; scan $hex %llx int; set alen [string length $alphabet]
  while {$int} {
    set result [string index $alphabet [expr {$int%$alen}]]$result
    set int [expr {$int/$alen}]
  set result

AvL: I changed the name of the previous example to "base58", fixed a reversal bug and made it take a hexadecimal string to match later usage samples on this page.

For bitcoin-related use, here's another snippet that extracts the address from a scriptPub:

package require sha256
set scriptPubKey "76a9146ccf14fa32539e2d148a3b39d87ae0e7c6f17b5988ac"

if {[regexp {^76a914([0-9a-f]{40})88ac$} $scriptPubKey _ xpub]} {
   set xpub 00$xpub
   set bpub [binary format H* $xpub]
   set sha [sha2::sha256 [sha2::sha256 -bin $bpub]]
   set num 1[base58 $xpub[string range $sha 0 7]]

Maybe we ought to open a separate page for bitcoin-stuff in Tcl, once it becomes more than just base58 and a usage sample.

An example usage to generate unique identifiers a la youtube might be:

package require md5
string range [base58 [md5::md5 -hex myidentifier]] 0 11

Whether your identifiers are sufficiently unique is a matter for you to decide .. Note that the only rationale for including md5 is to make the distribution more uniform and obscure the source of identifiers. The md5 output is also being truncated to a number between 0 and 58**12, or:

tclsh8.5 [~]list [expr log(58**12)/log(2)] bits
70.29577194153087 bits