Bitcoin ABC  0.29.2
P2P Digital Currency
base58.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <base58.h>
6 
7 #include <hash.h>
8 #include <uint256.h>
9 #include <util/strencodings.h>
10 #include <util/string.h>
11 
12 #include <cassert>
13 #include <cstdint>
14 #include <cstring>
15 #include <limits>
16 
18 static const char *pszBase58 =
19  "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
20 static const int8_t mapBase58[256] = {
21  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7,
24  8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18,
25  19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1,
26  -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48,
27  49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34  -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 };
36 
37 [[nodiscard]] static bool
38 DecodeBase58(const char *psz, std::vector<uint8_t> &vch, int max_ret_len) {
39  // Skip leading spaces.
40  while (*psz && IsSpace(*psz)) {
41  psz++;
42  }
43  // Skip and count leading '1's.
44  int zeroes = 0;
45  int length = 0;
46  while (*psz == '1') {
47  zeroes++;
48  if (zeroes > max_ret_len) {
49  return false;
50  }
51  psz++;
52  }
53  // Allocate enough space in big-endian base256 representation.
54  // log(58) / log(256), rounded up.
55  int size = strlen(psz) * 733 / 1000 + 1;
56  std::vector<uint8_t> b256(size);
57  // Process the characters.
58  // guarantee not out of range
59  static_assert(std::size(mapBase58) == 256,
60  "mapBase58.size() should be 256");
61  while (*psz && !IsSpace(*psz)) {
62  // Decode base58 character
63  int carry = mapBase58[(uint8_t)*psz];
64  // Invalid b58 character
65  if (carry == -1) {
66  return false;
67  }
68  int i = 0;
69  for (std::vector<uint8_t>::reverse_iterator it = b256.rbegin();
70  (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {
71  carry += 58 * (*it);
72  *it = carry % 256;
73  carry /= 256;
74  }
75  assert(carry == 0);
76  length = i;
77  if (length + zeroes > max_ret_len) {
78  return false;
79  }
80  psz++;
81  }
82  // Skip trailing spaces.
83  while (IsSpace(*psz)) {
84  psz++;
85  }
86  if (*psz != 0) {
87  return false;
88  }
89  // Skip leading zeroes in b256.
90  std::vector<uint8_t>::iterator it = b256.begin() + (size - length);
91 
92  // Copy result into output vector.
93  vch.reserve(zeroes + (b256.end() - it));
94  vch.assign(zeroes, 0x00);
95  while (it != b256.end()) {
96  vch.push_back(*(it++));
97  }
98  return true;
99 }
100 
101 std::string EncodeBase58(Span<const uint8_t> input) {
102  // Skip & count leading zeroes.
103  int zeroes = 0;
104  int length = 0;
105  while (input.size() > 0 && input[0] == 0) {
106  input = input.subspan(1);
107  zeroes++;
108  }
109  // Allocate enough space in big-endian base58 representation.
110  // log(256) / log(58), rounded up.
111  int size = input.size() * 138 / 100 + 1;
112  std::vector<uint8_t> b58(size);
113  // Process the bytes.
114  while (input.size() > 0) {
115  int carry = input[0];
116  int i = 0;
117  // Apply "b58 = b58 * 256 + ch".
118  for (std::vector<uint8_t>::reverse_iterator it = b58.rbegin();
119  (carry != 0 || i < length) && (it != b58.rend()); it++, i++) {
120  carry += 256 * (*it);
121  *it = carry % 58;
122  carry /= 58;
123  }
124 
125  assert(carry == 0);
126  length = i;
127  input = input.subspan(1);
128  }
129  // Skip leading zeroes in base58 result.
130  std::vector<uint8_t>::iterator it = b58.begin() + (size - length);
131  while (it != b58.end() && *it == 0) {
132  it++;
133  }
134  // Translate the result into a string.
135  std::string str;
136  str.reserve(zeroes + (b58.end() - it));
137  str.assign(zeroes, '1');
138  while (it != b58.end()) {
139  str += pszBase58[*(it++)];
140  }
141  return str;
142 }
143 
144 bool DecodeBase58(const std::string &str, std::vector<uint8_t> &vchRet,
145  int max_ret_len) {
146  if (!ValidAsCString(str)) {
147  return false;
148  }
149  return DecodeBase58(str.c_str(), vchRet, max_ret_len);
150 }
151 
153  // add 4-byte hash check to the end
154  std::vector<uint8_t> vch(input.begin(), input.end());
155  uint256 hash = Hash(vch);
156  vch.insert(vch.end(), (uint8_t *)&hash, (uint8_t *)&hash + 4);
157  return EncodeBase58(vch);
158 }
159 
160 [[nodiscard]] static bool DecodeBase58Check(const char *psz,
161  std::vector<uint8_t> &vchRet,
162  int max_ret_len) {
163  if (!DecodeBase58(psz, vchRet,
164  max_ret_len > std::numeric_limits<int>::max() - 4
165  ? std::numeric_limits<int>::max()
166  : max_ret_len + 4) ||
167  (vchRet.size() < 4)) {
168  vchRet.clear();
169  return false;
170  }
171  // re-calculate the checksum, ensure it matches the included 4-byte checksum
172  uint256 hash = Hash(Span{vchRet}.first(vchRet.size() - 4));
173  if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) {
174  vchRet.clear();
175  return false;
176  }
177  vchRet.resize(vchRet.size() - 4);
178  return true;
179 }
180 
181 bool DecodeBase58Check(const std::string &str, std::vector<uint8_t> &vchRet,
182  int max_ret) {
183  if (!ValidAsCString(str)) {
184  return false;
185  }
186  return DecodeBase58Check(str.c_str(), vchRet, max_ret);
187 }
std::string EncodeBase58(Span< const uint8_t > input)
Why base-58 instead of standard base-64 encoding?
Definition: base58.cpp:101
std::string EncodeBase58Check(Span< const uint8_t > input)
Encode a byte span into a base58-encoded string, including checksum.
Definition: base58.cpp:152
static bool DecodeBase58(const char *psz, std::vector< uint8_t > &vch, int max_ret_len)
Definition: base58.cpp:38
static bool DecodeBase58Check(const char *psz, std::vector< uint8_t > &vchRet, int max_ret_len)
Definition: base58.cpp:160
static const char * pszBase58
All alphanumeric characters except for "0", "I", "O", and "l".
Definition: base58.cpp:18
static const int8_t mapBase58[256]
Definition: base58.cpp:20
constexpr std::size_t size() const noexcept
Definition: span.h:209
constexpr C * end() const noexcept
Definition: span.h:200
constexpr C * begin() const noexcept
Definition: span.h:199
CONSTEXPR_IF_NOT_DEBUG Span< C > first(std::size_t count) const noexcept
Definition: span.h:227
CONSTEXPR_IF_NOT_DEBUG Span< C > subspan(std::size_t offset) const noexcept
Definition: span.h:218
256-bit opaque blob.
Definition: uint256.h:129
uint256 Hash(const T &in1)
Compute the 256-bit hash of an object.
Definition: hash.h:74
constexpr bool IsSpace(char c) noexcept
Tests if the given character is a whitespace character.
Definition: strencodings.h:104
bool ValidAsCString(const std::string &str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
Definition: string.h:80
assert(!tx.IsCoinBase())