Refactor b58tobin to be more easily reconfigured for using different integer sizes

This commit is contained in:
Luke Dashjr
2016-03-23 09:12:05 +00:00
parent ae5fe61864
commit 8a92496475

View File

@@ -32,24 +32,31 @@ static const int8_t b58digits_map[] = {
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1, 47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
}; };
typedef uint64_t b58_maxint_t;
typedef uint32_t b58_almostmaxint_t;
#define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8)
static const b58_almostmaxint_t b58_almostmaxint_mask = ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1);
bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
{ {
size_t binsz = *binszp; size_t binsz = *binszp;
const unsigned char *b58u = (void*)b58; const unsigned char *b58u = (void*)b58;
unsigned char *binu = bin; unsigned char *binu = bin;
size_t outisz = (binsz + 3) / 4; size_t outisz = (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t);
uint32_t outi[outisz]; b58_almostmaxint_t outi[outisz];
uint64_t t; b58_maxint_t t;
uint32_t c; b58_almostmaxint_t c;
size_t i, j; size_t i, j;
uint8_t bytesleft = binsz % 4; uint8_t bytesleft = binsz % sizeof(b58_almostmaxint_t);
uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; b58_almostmaxint_t zeromask = bytesleft ? (b58_almostmaxint_mask << (bytesleft * 8)) : 0;
unsigned zerocount = 0; unsigned zerocount = 0;
if (!b58sz) if (!b58sz)
b58sz = strlen(b58); b58sz = strlen(b58);
memset(outi, 0, outisz * sizeof(*outi)); for (i = 0; i < outisz; ++i) {
outi[i] = 0;
}
// Leading zeros, just count // Leading zeros, just count
for (i = 0; i < b58sz && b58u[i] == '1'; ++i) for (i = 0; i < b58sz && b58u[i] == '1'; ++i)
@@ -66,9 +73,9 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
c = (unsigned)b58digits_map[b58u[i]]; c = (unsigned)b58digits_map[b58u[i]];
for (j = outisz; j--; ) for (j = outisz; j--; )
{ {
t = ((uint64_t)outi[j]) * 58 + c; t = ((b58_maxint_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32; c = t >> b58_almostmaxint_bits;
outi[j] = t & 0xffffffff; outi[j] = t & b58_almostmaxint_mask;
} }
if (c) if (c)
// Output number too big (carry to the next int32) // Output number too big (carry to the next int32)
@@ -79,24 +86,18 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
} }
j = 0; j = 0;
switch (bytesleft) { if (bytesleft) {
case 3: for (i = bytesleft; i > 0; --i) {
*(binu++) = (outi[0] & 0xff0000) >> 16; *(binu++) = (outi[0] >> (8 * (i - 1))) & 0xff;
case 2: }
*(binu++) = (outi[0] & 0xff00) >> 8; ++j;
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
default:
break;
} }
for (; j < outisz; ++j) for (; j < outisz; ++j)
{ {
*(binu++) = (outi[j] >> 0x18) & 0xff; for (i = sizeof(*outi); i > 0; --i) {
*(binu++) = (outi[j] >> 0x10) & 0xff; *(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff;
*(binu++) = (outi[j] >> 8) & 0xff; }
*(binu++) = (outi[j] >> 0) & 0xff;
} }
// Count canonical base58 byte count // Count canonical base58 byte count