Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save bitkevin/5926549 to your computer and use it in GitHub Desktop.
Save bitkevin/5926549 to your computer and use it in GitHub Desktop.

bitcoin address validation

C

#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
 
const char *coin_err;
#define bail(s) { coin_err = s; return 0; }
 
int unbase58(const char *s, unsigned char *out) {
	static const char *tmpl = "123456789"
		"ABCDEFGHJKLMNPQRSTUVWXYZ"
		"abcdefghijkmnopqrstuvwxyz";
	int i, j, c;
	const char *p;
 
	memset(out, 0, 25);
	for (i = 0; s[i]; i++) {
		if (!(p = strchr(tmpl, s[i])))
			bail("bad char");
 
		c = p - tmpl;
		for (j = 25; j--; ) {
			c += 58 * out[j];
			out[j] = c % 256;
			c /= 256;
		}
 
		if (c) bail("address too long");
	}
 
	return 1;
}
 
int valid(const char *s) {
	unsigned char dec[32], d1[SHA256_DIGEST_LENGTH], d2[SHA256_DIGEST_LENGTH];
 
	coin_err = "";
	if (!unbase58(s, dec)) return 0;
 
	SHA256(SHA256(dec, 21, d1), SHA256_DIGEST_LENGTH, d2);
 
	if (memcmp(dec + 21, d2, 4))
		bail("bad digest");
 
	return 1;
}
 
int main (void) {
	const char *s[] = {
		"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",
		"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
		"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9",
		"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I",
		0 };
	int i;
	for (i = 0; s[i]; i++) {
		int status = valid(s[i]);
		printf("%s: %s\n", s[i], status ? "Ok" : coin_err);
	}
 
	return 0;
}

Perl

my @b58 = qw{
      1 2 3 4 5 6 7 8 9
    A B C D E F G H   J K L M N   P Q R S T U V W X Y Z
    a b c d e f g h i j k   m n o p q r s t u v w x y z
};
my %b58 = map { $b58[$_] => $_ } 0 .. 57;
 
sub unbase58 {
    use integer;
    my @out;
    for my $c ( map { $b58{$_} } shift =~ /./g ) {
        for (my $j = 25; $j--; ) {
            $c += 58 * ($out[$j] // 0);
            $out[$j] = $c % 256;
            $c /= 256;
        }
    }
    return @out;
}
 
sub check_bitcoin_address {
    # does nothing if the address is valid
    # dies otherwise
    use Digest::SHA qw(sha256);
    my @byte = unbase58 shift;
    die "wrong checksum" unless
    join('', map { chr } @byte[21..24]) eq
    substr sha256(sha256 pack 'C*', @byte[0..20]), 0, 4;
}

Perl 6

enum B58 <
      1 2 3 4 5 6 7 8 9
    A B C D E F G H   J K L M N   P Q R S T U V W X Y Z
    a b c d e f g h i j k   m n o p q r s t u v w x y z
>;
 
sub unbase58(Str $str) {
    my @out = 0 xx 25;
    for B58.enums.hash{$str.comb} {
        my $c = $_;
        for reverse ^25 {
            $c += 58 * @out[$_];
            @out[$_] = $c % 256;
            $c div= 256;
        }
    }
    return @out;
}
 
sub check-bitcoin-address($addr) {
    use Digest;
    my @byte = unbase58 $addr;
    !!! 'wrong checksum' unless @byte[21..24] ~~
    sha256(sha256 Buf.new: @byte[0..20]).subbuf(0, 4).list;
}

Python

from hashlib import sha256
 
digits58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
 
def decode_base58(bc, length):
    n = 0
    for char in bc:
        n = n * 58 + digits58.index(char)
    return n.to_bytes(length, 'big')
 
def check_bc(bc):
    bcbytes = decode_base58(bc, 25)
    return bcbytes[-4:] == sha256(sha256(bcbytes[:-4]).digest()).digest()[:4]
 
if __name__ == '__main__':
    bc = '1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'
    assert check_bc(bc)
    assert not check_bc( bc.replace('N', 'P', 1) )
    assert check_bc('1111111111111111111114oLvT2')
    assert check_bc("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j")

UNIX Shell

base58=({1..9} {A..H} {J..N} {P..Z} {a..k} {m..z})
bitcoinregex="^[$(printf "%s" "${base58[@]}")]{34}$"
 
decodeBase58() {
    local s=$1
    for i in {0..57}
    do s="${s//${base58[i]}/ $i}"
    done
    dc <<< "16o0d${s// /+58*}+f" 
}
 
checksum() {
    xxd -p -r <<<"$1" |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -binary |
    xxd -p -c 80 |
    head -c 8
}
 
checkBitcoinAddress() {
    if [[ "$1" =~ $bitcoinregex ]]
    then
        h=$(decodeBase58 "$1")
        checksum "00${h::${#h}-8}" |
        grep -qi "^${h: -8}$"
    else return 2
    fi
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment