Base58是用于Bitcoin中使用的一种独特的编码方式,主要用于产生Bitcoin的钱包地址。相比Base64,Base58不使用数字"0",字母大写"O",字母大写"I",和字母小写"l",以及" “和”/"符号。
Base58 与 Base64 异同 相同
一般都用于URL,邮件文本,可见字符显示。 都会造成信息冗余,数据量增大,因此不会用于大数据传输编码。 区别
编码集不同,Base58 的编码集在 Base64 的字符集的基础上去掉了比较容易混淆的字符。 Base64 采用直接切割 bit 的方法(8->6),而 Base58 采用大数进制转换,效率更低,使用场景更少。
base58.h
代码语言:javascript复制#ifndef BASE58_H
#define BASE58_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
extern bool (*base58_sha256_impl)(void *, const void *, size_t);
extern bool base58_to_bin(void *, size_t *, const char *, size_t);
extern int base58_check(const void *, size_t, const char *, size_t);
extern bool base58_encode(char *, size_t *, const void *, size_t);
extern bool base58_check_encode(char *, size_t *, uint8_t, const void *, size_t);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // BASE58_H
base58.c
代码语言:javascript复制#ifndef WIN32
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif // WIN32
#include <string.h>
#include "base58.h"
bool (*base58_sha256_impl)(void *, const void *, size_t) = NULL;
static const int8_t base58_digits_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,
};
static const char base58_digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
typedef uint64_t base58_maxint_t;
typedef uint32_t base58_almostmaxint_t;
#define base58_almostmaxint_bits (sizeof(base58_almostmaxint_t) * 8)
static const base58_almostmaxint_t base58_almostmaxint_mask = ((((base58_maxint_t)1) << base58_almostmaxint_bits) - 1);
bool base58_to_bin(void *bin, size_t *bin_len, const char *b58_data, size_t data_len)
{
size_t binsz = *bin_len;
const unsigned char *b58u = (void *)b58_data;
unsigned char *binu = bin;
size_t outsz = (binsz sizeof(base58_almostmaxint_t) - 1) / sizeof(base58_almostmaxint_t);
base58_almostmaxint_t outi[outsz];
base58_maxint_t t;
base58_almostmaxint_t c;
size_t i, j;
uint8_t bytesleft = binsz % sizeof(base58_almostmaxint_t);
base58_almostmaxint_t zeromask = bytesleft ? (base58_almostmaxint_mask << (bytesleft * 8)) : 0;
unsigned int zero_count = 0;
if (!data_len)
{
data_len = strlen(b58_data);
}
for (i = 0; i < outsz; i)
{
outi[i] = 0;
}
// Leading zeros, just count
for (i = 0; i < data_len && b58u[i] == '1'; i)
{
zero_count;
}
for (; i < data_len; i)
{
if (b58u[i] & 0x80)
{
// Invalid base58 digit
return false;
}
if (base58_digits_map[b58u[i]] == -1)
{
// Invalid base58 digit
return false;
}
c = (unsigned)base58_digits_map[b58u[i]];
for (j = outsz; j--;)
{
t = ((base58_maxint_t)outi[j]) * 58 c;
c = t >> base58_almostmaxint_bits;
outi[j] = t & base58_almostmaxint_mask;
}
if (c)
{
// Output number too big (carry to the next int32)
return false;
}
if (outi[0] & zeromask)
{
// Output number too big (last int32 filled too far)
return false;
}
}
j = 0;
if (bytesleft)
{
for (i = bytesleft; i > 0; --i)
{
*(binu ) = (outi[0] >> (8 * (i - 1))) & 0xff;
}
j;
}
for (; j < outsz; j)
{
for (i = sizeof(*outi); i > 0; --i)
{
*(binu ) = (outi[j] >> (8 * (i - 1))) & 0xff;
}
}
// Count canonical base58 byte count
binu = bin;
for (i = 0; i < binsz; i)
{
if (binu[i])
{
break;
}
--*bin_len;
}
*bin_len = zero_count;
return true;
}
static bool my_dblsha256(void *hash, const void *data, size_t data_len)
{
uint8_t buffer[0x20];
return base58_sha256_impl(buffer, data, data_len) && base58_sha256_impl(hash, buffer, sizeof(buffer));
}
int base58_check(const void *bin, size_t binsz, const char *base58str, size_t b58sz)
{
unsigned char buffer[32];
const uint8_t *binc = bin;
unsigned int i;
if (binsz < 4)
{
return -4;
}
if (!my_dblsha256(buffer, bin, binsz - 4))
{
return -2;
}
if (memcmp(&binc[binsz - 4], buffer, 4))
{
return -1;
}
// Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str[-1])
for (i = 0; binc[i] == '