Below is the C code I just finished for the purpose described in OP.
#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;
}