An often cited problem with verifying a bitcoin address is that the long string of letters and numbers is very hard to compare for a human being. This is relevant in the case of "hacker proof" hardware wallets where the user has to confirm that the address he copy/pasted from a site really is the address he wants to send the funds to.
I've considered simple color-coding, where the 25 byte address is converted into an image, which is experienced more as a whole instead of the letters, deciphered one-by-one when reading.
I just made a little script that encodes an address into a 12 by 12 pixel image. Each pixel is either red, green or blue. It basically just converts the address into a number, then converts this number into a base-3 number, and each pixel gets its color from the digit in the base three number (0 for red, 1 for green, 2 for blue). Here are some examples of random addresses converted into this image format:
1FbyYynZwHukrQZeAzPYb91KvbFkgp1kgN |
1LQxi4tDHca5ZAZW3HuBxof7Uxh54rTd9t | |
1AdN2my8NxvGcisPGYeQTAKdWJuUzNkQxG | |
124GJ3HCtYvaD2zDwJPKJLMTurWU1PdLic | |
14jMgd1vQ8Pi9H3eKjsxwnb2xo8DZLiezf | |
13xQfLkQ2q7xLDsEZfgv6weoZP98rmZnLx | |
14cZMQk89mRYQkDEj8Rn25AnGoBi5H6uer |
When uploading these pictures to imgur.com, their file names were lost (the filename had the address in it), but it was pretty quick just looking at the picture to see which were which. They are all distinct in various ways.
I'm sure there are ways to improve this algorithm though, so different patterns become more distinct.
Here's the script used to generate these images. By default the script will show the image encoding of the address contained in the address variable.
import Image
#base58 magic borrowed from Gavin Andresen's bitcointools (and modified slightly)
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)
def b58decode(v):
""" return the number representation of the base58-encoded string v
"""
long_value = 0
for (i, c) in enumerate(v[::-1]):
long_value += __b58chars.find(c) * (__b58base**i)
return long_value
def b3decode(num):
""" return the base 3 encoding of num as an array of numbers from 0 to 2
"""
array = []
base = 3
remainder = num
while remainder >= 2:
div, mod = divmod(remainder, base)
array.insert(0, mod)
remainder = div
return array
address = "1HB5XMLmzFVj8ALj6mfBsbifRoD4miY36v"
addresses = ["14cZMQk89mRYQkDEj8Rn25AnGoBi5H6uer", "13xQfLkQ2q7xLDsEZfgv6weoZP98rmZnLx", "14jMgd1vQ8Pi9H3eKjsxwnb2xo8DZLiezf", "124GJ3HCtYvaD2zDwJPKJLMTurWU1PdLic", "1AdN2my8NxvGcisPGYeQTAKdWJuUzNkQxG", "1LQxi4tDHca5ZAZW3HuBxof7Uxh54rTd9t", "1FbyYynZwHukrQZeAzPYb91KvbFkgp1kgN"]
width = 12
height = 11
image = Image.new("RGBA", (width, height))
pixels = image.load()
for (index, num) in enumerate(b3decode(b58decode(address))):
colors = [(255, 0, 0, 255), (0, 255, 0, 255), (0, 0, 255, 255)]
pixels[index % width, index / width] = colors[num]
image.resize((width*5, height*5), Image.NEAREST).show()
if False: #if this is run, it will save the image representation of the addresses contained in the "addresses" list to the current folder, using the file name ".png"
for addr in addresses:
for (index, num) in enumerate(b3decode(b58decode(addr))):
colors = [(255, 0, 0, 255), (0, 255, 0, 255), (0, 0, 255, 255)]
pixels[index % width, index / height] = colors[num]
image.resize((width*5, height*5), Image.NEAREST).save(addr+".png")
The resulting images are 12x11 pixels. Though the above images are 12x12 (with an empty bottom row since I didn't realize this until I had made these images).