Skip to content

Commit b58be13

Browse files
committed
Replace DecodeBase58/EncodeBase58 with direct implementation.
This removes the bignum/OpenSSL dependency. The base58 transformation code is also moved to a separate .cpp file.
1 parent 4a102fa commit b58be13

File tree

3 files changed

+101
-93
lines changed

3 files changed

+101
-93
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ libbitcoin_wallet_a_SOURCES = \
121121
$(BITCOIN_CORE_H)
122122

123123
libbitcoin_common_a_SOURCES = \
124+
base58.cpp \
124125
allocators.cpp \
125126
chainparams.cpp \
126127
core.cpp \

src/base58.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright (c) 2014 The Bitcoin developers
2+
// Distributed under the MIT/X11 software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <assert.h>
6+
#include <stdint.h>
7+
#include <string.h>
8+
#include <vector>
9+
#include <string>
10+
11+
/* All alphanumeric characters except for "0", "I", "O", and "l" */
12+
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
13+
14+
bool DecodeBase58(const char *psz, std::vector<unsigned char>& vch) {
15+
// Skip leading spaces.
16+
while (*psz && isspace(*psz))
17+
psz++;
18+
// Skip and count leading '1's.
19+
int zeroes = 0;
20+
while (*psz == '1') {
21+
zeroes++;
22+
psz++;
23+
}
24+
// Allocate enough space in big-endian base256 representation.
25+
std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
26+
// Process the characters.
27+
while (*psz && !isspace(*psz)) {
28+
// Decode base58 character
29+
const char *ch = strchr(pszBase58, *psz);
30+
if (ch == NULL)
31+
return false;
32+
// Apply "b256 = b256 * 58 + ch".
33+
int carry = ch - pszBase58;
34+
for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
35+
carry += 58 * (*it);
36+
*it = carry % 256;
37+
carry /= 256;
38+
}
39+
assert(carry == 0);
40+
psz++;
41+
}
42+
// Skip trailing spaces.
43+
while (isspace(*psz))
44+
psz++;
45+
if (*psz != 0)
46+
return false;
47+
// Skip leading zeroes in b256.
48+
std::vector<unsigned char>::iterator it = b256.begin();
49+
while (it != b256.end() && *it == 0)
50+
it++;
51+
// Copy result into output vector.
52+
vch.reserve(zeroes + (b256.end() - it));
53+
vch.assign(zeroes, 0x00);
54+
while (it != b256.end())
55+
vch.push_back(*(it++));
56+
return true;
57+
}
58+
59+
std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) {
60+
// Skip & count leading zeroes.
61+
int zeroes = 0;
62+
while (pbegin != pend && *pbegin == 0) {
63+
pbegin++;
64+
zeroes++;
65+
}
66+
// Allocate enough space in big-endian base58 representation.
67+
std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
68+
// Process the bytes.
69+
while (pbegin != pend) {
70+
int carry = *pbegin;
71+
// Apply "b58 = b58 * 256 + ch".
72+
for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
73+
carry += 256 * (*it);
74+
*it = carry % 58;
75+
carry /= 58;
76+
}
77+
assert(carry == 0);
78+
pbegin++;
79+
}
80+
// Skip leading zeroes in base58 result.
81+
std::vector<unsigned char>::iterator it = b58.begin();
82+
while (it != b58.end() && *it == 0)
83+
it++;
84+
// Translate the result into a string.
85+
std::string str;
86+
str.reserve(zeroes + (b58.end() - it));
87+
str.assign(zeroes, '1');
88+
while (it != b58.end())
89+
str += pszBase58[*(it++)];
90+
return str;
91+
}

src/base58.h

Lines changed: 9 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#ifndef BITCOIN_BASE58_H
1515
#define BITCOIN_BASE58_H
1616

17-
#include "bignum.h"
1817
#include "chainparams.h"
1918
#include "hash.h"
2019
#include "key.h"
@@ -27,51 +26,11 @@
2726
#include <boost/variant/apply_visitor.hpp>
2827
#include <boost/variant/static_visitor.hpp>
2928

30-
/* All alphanumeric characters except for "0", "I", "O", and "l" */
31-
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
32-
3329
/**
34-
* Encode a byte sequence as a base58-encoded string
30+
* Encode a byte sequence as a base58-encoded string.
31+
* pbegin and pend cannot be NULL, unless both are.
3532
*/
36-
inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
37-
{
38-
CAutoBN_CTX pctx;
39-
CBigNum bn58 = 58;
40-
CBigNum bn0 = 0;
41-
42-
// Convert big endian data to little endian - the extra zero at the end will
43-
// ensure bignum interprets it as a positive number */
44-
std::vector<unsigned char> vchTmp(pend-pbegin+1, 0);
45-
reverse_copy(pbegin, pend, vchTmp.begin());
46-
47-
// Convert little endian data to bignum
48-
CBigNum bn;
49-
bn.setvch(vchTmp);
50-
51-
// Convert bignum to std::string
52-
std::string str;
53-
// The expected size increase from base58 conversion is approximately 137%,
54-
// but use 138% to be safe
55-
str.reserve((pend - pbegin) * 138 / 100 + 1);
56-
CBigNum dv;
57-
CBigNum rem;
58-
while (bn > bn0)
59-
{
60-
if (!BN_div(&dv, &rem, &bn, &bn58, pctx))
61-
throw bignum_error("EncodeBase58 : BN_div failed");
62-
bn = dv;
63-
unsigned int c = rem.getulong();
64-
str += pszBase58[c];
65-
}
66-
67-
// Leading zeroes encoded as base58 zeros
68-
for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)
69-
str += pszBase58[0];
70-
71-
// Convert little endian std::string to big endian
72-
reverse(str.begin(), str.end());
73-
return str;
74-
}
33+
std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend);
7534

7635
/**
7736
* Encode a byte vector as a base58-encoded string
@@ -82,58 +41,15 @@ inline std::string EncodeBase58(const std::vector<unsigned char>& vch)
8241
}
8342

8443
/**
85-
* Decode a base58-encoded string (psz) into a byte vector (vchRet)
86-
* return true if decoding is successful
44+
* Decode a base58-encoded string (psz) into a byte vector (vchRet).
45+
* return true if decoding is successful.
46+
* psz cannot be NULL.
8747
*/
88-
inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
89-
{
90-
CAutoBN_CTX pctx;
91-
vchRet.clear();
92-
CBigNum bn58 = 58;
93-
CBigNum bn = 0;
94-
CBigNum bnChar;
95-
while (isspace(*psz))
96-
psz++;
97-
98-
// Convert big endian string to bignum
99-
for (const char* p = psz; *p; p++)
100-
{
101-
const char* p1 = strchr(pszBase58, *p);
102-
if (p1 == NULL)
103-
{
104-
while (isspace(*p))
105-
p++;
106-
if (*p != '\0')
107-
return false;
108-
break;
109-
}
110-
bnChar.setulong(p1 - pszBase58);
111-
if (!BN_mul(&bn, &bn, &bn58, pctx))
112-
throw bignum_error("DecodeBase58 : BN_mul failed");
113-
bn += bnChar;
114-
}
115-
116-
// Get bignum as little endian data
117-
std::vector<unsigned char> vchTmp = bn.getvch();
118-
119-
// Trim off the sign byte if present
120-
if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80)
121-
vchTmp.erase(vchTmp.end()-1);
122-
123-
// Restore leading zeros
124-
int nLeadingZeros = 0;
125-
for (const char* p = psz; *p == pszBase58[0]; p++)
126-
nLeadingZeros++;
127-
vchRet.assign(nLeadingZeros + vchTmp.size(), 0);
128-
129-
// Convert little endian data to big endian
130-
reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size());
131-
return true;
132-
}
48+
bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet);
13349

13450
/**
135-
* Decode a base58-encoded string (str) into a byte vector (vchRet)
136-
* return true if decoding is successful
51+
* Decode a base58-encoded string (str) into a byte vector (vchRet).
52+
* return true if decoding is successful.
13753
*/
13854
inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
13955
{

0 commit comments

Comments
 (0)