You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#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
}