http://rosettacode.org/wiki/Bitcoin/address_validation
could be buggy, though!
I actually link to this page in OP already. The solutions there are very buggy indeed.
It was the Bitcointalk forum that inspired us to create Bitcointalksearch.org - Bitcointalk is an excellent site that should be the default page for anybody dealing in cryptocurrency, since it is a virtual gold-mine of data. However, our experience and user feedback led us create our site; Bitcointalk's search is slow, and difficult to get the results you need, because you need to log in first to find anything useful - furthermore, there are rate limiters for their search functionality.
The aim of our project is to create a faster website that yields more results and faster without having to create an account and eliminate the need to log in - your personal data, therefore, will never be in jeopardy since we are not asking for any of your data and you don't need to provide them to use our site with all of its capabilities.
We created this website with the sole purpose of users being able to search quickly and efficiently in the field of cryptocurrency so they will have access to the latest and most accurate information and thereby assisting the crypto-community at large.
SHA256(SHA256(000000000000000000000000000000000000000000)) =
94a00911c4da27f9271727ffa7a14d8d5588fc0fff9964340ec4065f387e622b
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
SHA256(SHA256(000000000000000000000000000000000000000001)) =
9d35b5b9d5befcf2d6b89994f7f64279b0645d5d4a5f1a6fa2dcc615bbed04ef
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
/* Based on libbase58, see https://github.com/luke-jr/libbase58 for reference.*/
/* Attempts to convert the binary input to a Base58 format and returns true */
/* on success. */
static bool generate_bitcoin_address(const unsigned char *payload, char type, char *b58, size_t *b58sz) {
unsigned char address[25];
address[0] = ( type == '1' ? 0 :
type == '3' ? 5 : 111);
memcpy(address+1, payload, 20);
unsigned char d1[SHA256_DIGEST_LENGTH], d2[SHA256_DIGEST_LENGTH];
SHA256(SHA256(address, 21, d1), SHA256_DIGEST_LENGTH, d2);
memcpy(address+21, d2, 4);
{
static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
const uint8_t *bin = (const uint8_t *) address;
int carry;
ssize_t i, j, high, zcount = 0;
size_t size;
size_t uzcount = 0;
while (uzcount < 25 && !bin[uzcount]) ++uzcount;
zcount = uzcount;
size = (25 - zcount) * 138 / 100 + 1;
uint8_t buf[ ((25 - 0) * 138 / 100 + 1) ];
memset(buf, 0, size);
for (i = zcount, high = size - 1; i < 25; ++i, high = j) {
for (carry = bin[i], j = size - 1; (j > high) || carry; --j) {
carry += 256 * buf[j];
buf[j] = carry % 58;
carry /= 58;
}
}
for (j = 0; j < (ssize_t) size && !buf[j]; ++j);
if (*b58sz <= zcount + size - j) {
*b58sz = zcount + size - j + 1;
return false;
}
if (zcount) memset(b58, '1', zcount);
for (i = zcount; j < (ssize_t) size; ++i, ++j) b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
*b58sz = i + 1;
}
return true;
}
#include
#include
#include
#include
#include
#include
/* Based on libbase58, see https://github.com/luke-jr/libbase58 for reference.*/
/* Returns the version of a valid Bitcoin address or a negative value if the */
/* address is invalid. */
int validate_bitcoin_address(const char *address) {
static const int8_t b58digits_map[] = {
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
};
unsigned char addrbin[25];
size_t addrbinsz = sizeof(addrbin);
void *bin = (void *) addrbin;
size_t *binszp = &addrbinsz;
const char *b58 = address;
size_t b58sz = strlen(address);
{
const unsigned char *b58u = (void *) b58;
unsigned char *binu = bin;
uint32_t outi[(25 + 3) / 4];
size_t outisz=(25 + 3) / 4;
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = 25 % 4;
uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0;
unsigned zerocount = 0;
if (!b58sz) b58sz = strlen(b58);
memset(outi, 0, sizeof(outi));
/* Leading zeros, just count */
for (i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount;
for ( ; i < b58sz; ++i) {
if (b58u[i] & 0x80) return -1; /* High-bit set on invalid digit */
if (b58digits_map[b58u[i]] == -1) return -2; /* Invalid base58 digit */
c = (unsigned)b58digits_map[b58u[i]];
for (j = outisz; j--; ) {
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
}
if (c) return -3; /* Output number too big (carry to the next int32) */
if (outi[0] & zeromask) return -4; /* Output number too big (last int32 filled too far) */
}
j = 0;
switch (bytesleft) {
case 3: *(binu++) = (outi[0] & 0xff0000) >> 16;
case 2: *(binu++) = (outi[0] & 0xff00) >> 8;
case 1: *(binu++) = (outi[0] & 0xff); ++j;
default: break;
}
for (; j < outisz; ++j) {
*(binu++) = (outi[j] >> 0x18) & 0xff;
*(binu++) = (outi[j] >> 0x10) & 0xff;
*(binu++) = (outi[j] >> 8) & 0xff;
*(binu++) = (outi[j] >> 0) & 0xff;
}
binu = bin; /* Count canonical base58 byte count */
for (i = 0; i < 25; ++i) {
if (binu[i]) break;
--*binszp;
}
*binszp += zerocount;
}
if (addrbinsz != 25) return -5;
if (addrbin[0] != 0 && addrbin[0] != 5) return -6;
{
unsigned char d1[SHA256_DIGEST_LENGTH], d2[SHA256_DIGEST_LENGTH];
SHA256(SHA256(addrbin, 21, d1), SHA256_DIGEST_LENGTH, d2);
if (memcmp(addrbin + 21, d2, 4)) return -7;
}
return addrbin[0];
}
int main( int argc, char * argv [] ) {
int i;
for (i = 1; i < argc; ++i ) {
bool valid = (validate_bitcoin_address(argv[i]) >= 0);
printf( "%s is %s\n", argv[i], valid ? "VALID." : "INVALID!");
}
return 0;
}
SHA256(SHA256(000000000000000000000000000000000000000000)) =
94a00911c4da27f9271727ffa7a14d8d5588fc0fff9964340ec4065f387e622b
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
SHA256(SHA256(000000000000000000000000000000000000000001)) =
9d35b5b9d5befcf2d6b89994f7f64279b0645d5d4a5f1a6fa2dcc615bbed04ef
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1