Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Rails 3 bitcoin address validator. Validator syntaxis: validates :address, :bitcoin_address => true, :presence => true
require 'digest'
class BitcoinAddressValidator < ActiveModel::EachValidator
def validate_each(record, field, value)
unless value.blank? || valid_bitcoin_address?(value)
record.errors[field] << "Bitcoin address is invalid"
B58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
B58Base = B58Chars.length
def valid_bitcoin_address?(address)
(address =~ /^[a-zA-Z1-9]{33,35}$/) and version(address)
def version(address)
decoded = b58_decode(address, 25)
version = decoded[0, 1]
checksum = decoded[-4, decoded.length]
vh160 = decoded[0, decoded.length - 4]
hashed = ( << ( << vh160).digest).digest
hashed[0, 4] == checksum ? version[0] : nil
def b58_decode(value, length)
long_value = 0
index = 0
result = ""
value.reverse.each_char do |c|
long_value += B58Chars.index(c) * (B58Base ** index)
index += 1
while long_value >= 256 do
div, mod = long_value.divmod 256
result = mod.chr + result
long_value = div
result = long_value.chr + result
if result.length < length
result = 0.chr * (length - result.length) + result

This comment has been minimized.

Copy link

@chrhansen chrhansen commented Aug 31, 2013

Seems the validator needs a check for first character is either 1 or 3. I can delete the first number (1 or 3) of a valid address and it will still pass the validator even though the address now begins with say, 4 or 8. Also, it's not allowing addresses less than 33 characters. A bitcoin address could be down to 27 characters.
Let me know if I misunderstood something.


This comment has been minimized.

Copy link

@christiangenco christiangenco commented Jan 10, 2014

My simpler revision:

(doesn't calculate checksum)


This comment has been minimized.

Copy link

@crabvk crabvk commented Aug 12, 2015

Validator syntaxis: validates :address, :bitcoin_address => true, presence => true

':presence => true' (and 'allow_blank: true' also) does not make sense here because of 'value.blank?' condition in your 'validate_each'. Anyway, blank string is not valid bitcoin address. Have to remove this.

Also "fake_address\n3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy\nwhat_the" is matched for the regex. Should use \A and \z instead of ^ and $.

There is a good bitcoin address validator in bitcoin-ruby gem

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