I tried looking through the Satoshi Client to grab the necessary code. It ended up being too difficult for me as my expertise is not in C or C variants. And the fact that the code use boost made it that much more difficult. Is their a code snippet out there that does not rely on any external libraries except for maybe the SHA256 hash function?

  • And just to clarify, this isn't validating that an address is one generated by any bitcoin client just that it is an address that could be a valid Bitcoin address derived from a public key. There are Bitcoin addresses that pass this test for which there is no private key and/or no public key. – Stephen Gornick Apr 15 '13 at 8:56
  • You can't validate that a private key exists for a public key. Therefore, complete validation of an address shouldn't be possible. – Charles Hoskinson Apr 18 '13 at 7:52

This isn't precisely what you asked for, but it should be a good starting point.


import re
import math
from Crypto.Hash import SHA256

def validate_bitcoin_address(self, value):
  value = value.strip()
  if re.match(r"[a-zA-Z1-9]{27,35}$", value) is None:
    raise ValueError("Contains illegal characters")
  version = get_bcaddress_version(value)
  if version != 0:
    raise ValueError("Not a standard bitcoin address")
  return value

__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)

def b58encode(v):
  """ encode v, which is a string of bytes, to base58.                                                                                                               

  long_value = 0L
  for (i, c) in enumerate(v[::-1]):
    long_value += (256**i) * ord(c)

  result = ''
  while long_value >= __b58base:
    div, mod = divmod(long_value, __b58base)
    result = __b58chars[mod] + result
    long_value = div
  result = __b58chars[long_value] + result

  # Bitcoin does a little leading-zero-compression:                                                                                                                  
  # leading 0-bytes in the input become leading-1s                                                                                                                   
  nPad = 0
  for c in v:
    if c == '\0': nPad += 1
    else: break

  return (__b58chars[0]*nPad) + result

def b58decode(v, length):
  """ decode v into a string of len bytes                                                                                                                            
  long_value = 0L
  for (i, c) in enumerate(v[::-1]):
    long_value += __b58chars.find(c) * (__b58base**i)

  result = ''
  while long_value >= 256:
    div, mod = divmod(long_value, 256)
    result = chr(mod) + result
    long_value = div
  result = chr(long_value) + result

  nPad = 0
  for c in v:
    if c == __b58chars[0]: nPad += 1
    else: break

  result = chr(0)*nPad + result
  if length is not None and len(result) != length:
    return None

  return result

def get_bcaddress_version(strAddress):
  """ Returns None if strAddress is invalid.  Otherwise returns integer version of address. """
  addr = b58decode(strAddress,25)
  if addr is None: return None
  version = addr[0]
  checksum = addr[-4:]
  vh160 = addr[:-4] # Version plus hash160 is what is checksummed                                                                                                    
  if h3[0:4] == checksum:
    return ord(version)
    raise ValueError("Bad checksum")

How I do it in php -

A) decode base58 to hex and pad with 0's on the left so it is 50 characterts long. B) The right most 8 characters is the checksum, the left most 42 are the extended ripemd160 (and should start with 00)

C) sha256(sha256(extended ripemd160)) - the first 8 characters of that should match the checksum from step B.

Not code, sorry, but that's how you do it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.