base58

Like base64, but without these characters: +/0OIl

This is the definition of base58 as used by the open source decentralized cryptographic peer-to-peer currency system bitcoin. (there is apparently a different version of base58 used by Flickr)

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

  • Don't want 0OIl characters that look the same in some fonts and could be used to create visually identical looking account numbers.
  • A string with non-alphanumeric characters is not as easily accepted as an account number.
  • E-mail usually won't line-break if 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 modified the previous sample to name "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