forked from gordon/libbase58
-
Notifications
You must be signed in to change notification settings - Fork 1
/
base58.hpp
189 lines (168 loc) · 5 KB
/
base58.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <algorithm>
#include <memory>
static const int8_t b58digits_map[128] = {
-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,
};
inline bool b58tobin(void *bin /* out */ , size_t *binszp /* in - out */ , const char *b58 /* in */ , size_t b58sz /* in */ )
{
size_t binsz = *binszp;
const unsigned char *b58u = (const unsigned char *)b58;
unsigned char *binu = (unsigned char *)bin;
size_t outsz = (binsz + 3) / 4;
std::shared_ptr<uint32_t[]> out(new uint32_t[outsz]());
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = bytesleft == 0 ? 0 : (0xffffffff << (bytesleft * 8));
unsigned int zerocount = 0;
if (!b58sz)
b58sz = strlen(b58);
// Leading zeros, just count
for (i = 0; i < b58sz && b58u[i] == '1'; i++)
zerocount++;
for ( ; i < b58sz; i++)
{
if (b58u[i] & 0x80)
{
// High-bit set on invalid digit
return false;
}
if (b58digits_map[b58u[i]] == -1)
{
// Invalid base58 digit
return false;
}
c = (unsigned short)b58digits_map[b58u[i]];
for (j = outsz - 1; j + 1 > 0; j--)
{
t = out[j] * 58ULL + c;
c = (t >> 32) & 0x3fULL;
out[j] = t & 0xffffffffULL;
}
if (c)
{
// Output number too big (carry to the next int32)
return false;
}
if (out[0] & zeromask)
{
// Output number too big (last int32 filled too far)
return false;
}
}
j = 0;
switch (bytesleft)
{
case 3:
*(binu++) = *((uint8_t*)&out[0] + 2);
/* Fall Through */
case 2:
*(binu++) = *((uint8_t*)&out[0] + 1);
/* Fall Through */
case 1:
*(binu++) = *(uint8_t*)&out[0];
j++;
break;
default:
break;
}
for (; j < outsz; j++)
{
std::reverse((char *)(&out[0] + j), (char *)(&out[0] + j) + 4);
*(uint32_t *)binu = out[j];
binu = binu + 4;
}
//size of the result binary,modified that way that the number of leading zeroes in it replaced by the count of leading '1' symbols in given string.
binu = (unsigned char *)bin;
for (i = 0; i < binsz; i++)
{
if (binu[i])
break;
(*binszp)--;
}
*binszp = *binszp + zerocount;
return true;
}
static const char b58digits_ordered[59] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
inline bool b58enc(char* b58 /* out */ , size_t *b58sz /* in - out */ , const void *data /* in */ , size_t binsz /* in */ )
{
const uint8_t *bin = (const uint8_t *)data;
int carry;
long i, j, high, zcount = 0;
while (zcount < binsz && !bin[zcount])
zcount++;
const unsigned int size = (binsz - zcount) * 138 / 100 + 1; //latter is a smth like a logarithm of 256 to base 58 , but not exactly.
std::shared_ptr<unsigned char[]> buf(new unsigned char[size]());
high = size - 1;
for (i = zcount; i < binsz; i++)
{
carry = bin[i]; j = size - 1;
while( carry || j > high )
{
carry = carry + 256 * buf[j];
buf[j--] = carry % 58; //as you all know 'int fifty_cent() { int j = 0; return j-- ; }' has a zero value
carry /= 58;
}
high = j;
}
for (j = 0; j < size && !buf[j]; j++);
if (*b58sz < zcount + size - j + 1)
{
*b58sz = zcount + size - j + 1;
return false;
}
if (zcount)
memset(b58, '1', zcount);
for (i = zcount; j < size; i++, j++)
b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
*b58sz = i + 1;
return true;
}
inline std::pair<int, std::string> b58decode(const std::string &b58) {
if (b58.size() > LONG_MAX >> 4) return std::pair<int, std::string> (-7, std::string());
size_t decodedSize = b58.size() << 3;;
unsigned char *bc = new unsigned char[decodedSize]();
bool ok = b58tobin((void *)bc, &decodedSize, b58.c_str(), b58.length());
if (ok) {
ok = b58tobin((void *)bc, &decodedSize, b58.c_str(), b58.length());
auto pr = std::pair<int, std::string>(1, std::string((char *)bc, decodedSize));
delete[] bc;
return pr;
}
else
{
delete[] bc;
return std::pair<int, std::string>(-8, std::string());
}
}
template <typename T>
inline std::pair<int, std::string> b58encode(const T &chvect) {
if (chvect.size() > LONG_MAX >> 4) return std::pair<int, std::string>(-7, std::string());
size_t b58Size = chvect.size() << 3;
char *b58c = new char[b58Size];
bool ok = b58enc(b58c, &b58Size, (void *)chvect.data(), chvect.size());
if (ok) {
auto pr = std::pair<int, std::string>(1, std::string(b58c));
delete[] b58c;
return pr;
}
else
{
delete[] b58c;
return std::pair<int, std::string>(-8, std::string());
}
}