Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
base58.cpp
Go to the documentation of this file.
1// Copyright (c) 2014-present 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 <algorithm>
13#include <cassert>
14#include <cstdint>
15#include <cstring>
16
17#include <limits>
18
20
22static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
23static const int8_t mapBase58[256] = {
24 -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
25 -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
26 -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
27 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
28 -1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
29 22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
30 -1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
31 47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
32 -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,
34 -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
35 -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
36 -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
37 -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
38 -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
39 -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
40};
41
42[[nodiscard]] static bool DecodeBase58Raw(std::string_view str, std::vector<unsigned char>& vch, int max_ret_len)
43{
44 const char* psz = str.data();
45 const char* const end = str.data() + str.size();
46 // Skip leading spaces.
47 while (psz != end && IsSpace(*psz))
48 psz++;
49 // Skip and count leading '1's.
50 int zeroes = 0;
51 int length = 0;
52 while (psz != end && *psz == '1') {
53 zeroes++;
54 if (zeroes > max_ret_len) return false;
55 psz++;
56 }
57 // Allocate enough space in big-endian base256 representation.
58 const size_t size{static_cast<size_t>(std::min<uint64_t>(
59 uint64_t(end - psz) * 733 / 1000 + 1, // log(58) / log(256), rounded up.
60 uint64_t(std::max(max_ret_len - zeroes, 0)) + 1))};
61 std::vector<unsigned char> b256(size);
62 // Process the characters.
63 static_assert(std::size(mapBase58) == 256, "mapBase58.size() should be 256"); // guarantee not out of range
64 while (psz != end && !IsSpace(*psz)) {
65 // Decode base58 character
66 int carry{mapBase58[uint8_t(*psz)]};
67 if (carry == -1) // Invalid b58 character
68 return false;
69 int i = 0;
70 for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (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) return false;
78 psz++;
79 }
80 // Skip trailing spaces.
81 while (psz != end && IsSpace(*psz))
82 psz++;
83 if (psz != end)
84 return false;
85 // Skip leading zeroes in b256.
86 std::vector<unsigned char>::iterator it = b256.begin() + (size - length);
87 // Copy result into output vector.
88 vch.reserve(zeroes + (b256.end() - it));
89 vch.assign(zeroes, 0x00);
90 while (it != b256.end())
91 vch.push_back(*(it++));
92 return true;
93}
94
95std::string EncodeBase58(std::span<const unsigned char> input)
96{
97 // Skip & count leading zeroes.
98 int zeroes = 0;
99 int length = 0;
100 while (input.size() > 0 && input[0] == 0) {
101 input = input.subspan(1);
102 zeroes++;
103 }
104 // Allocate enough space in big-endian base58 representation.
105 int size = input.size() * 138 / 100 + 1; // log(256) / log(58), rounded up.
106 std::vector<unsigned char> b58(size);
107 // Process the bytes.
108 while (input.size() > 0) {
109 int carry = input[0];
110 int i = 0;
111 // Apply "b58 = b58 * 256 + ch".
112 for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) {
113 carry += 256 * (*it);
114 *it = carry % 58;
115 carry /= 58;
116 }
117
118 assert(carry == 0);
119 length = i;
120 input = input.subspan(1);
121 }
122 // Skip leading zeroes in base58 result.
123 std::vector<unsigned char>::iterator it = b58.begin() + (size - length);
124 while (it != b58.end() && *it == 0)
125 it++;
126 // Translate the result into a string.
127 std::string str;
128 str.reserve(zeroes + (b58.end() - it));
129 str.assign(zeroes, '1');
130 while (it != b58.end())
131 str += pszBase58[*(it++)];
132 return str;
133}
134
135bool DecodeBase58(std::string_view str, std::vector<unsigned char>& vchRet, int max_ret_len)
136{
137 if (ContainsNUL(str)) {
138 return false;
139 }
140 return DecodeBase58Raw(str, vchRet, max_ret_len);
141}
142
143std::string EncodeBase58Check(std::span<const unsigned char> input)
144{
145 // add 4-byte hash check to the end
146 std::vector<unsigned char> vch(input.begin(), input.end());
147 uint256 hash = Hash(vch);
148 vch.insert(vch.end(), hash.data(), hash.data() + 4);
149 return EncodeBase58(vch);
150}
151
152[[nodiscard]] static bool DecodeBase58CheckRaw(std::string_view str, std::vector<unsigned char>& vchRet, int max_ret_len)
153{
154 if (!DecodeBase58Raw(str, vchRet, max_ret_len > std::numeric_limits<int>::max() - 4 ? std::numeric_limits<int>::max() : max_ret_len + 4) ||
155 (vchRet.size() < 4)) {
156 vchRet.clear();
157 return false;
158 }
159 // re-calculate the checksum, ensure it matches the included 4-byte checksum
160 uint256 hash = Hash(std::span{vchRet}.first(vchRet.size() - 4));
161 if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) {
162 vchRet.clear();
163 return false;
164 }
165 vchRet.resize(vchRet.size() - 4);
166 return true;
167}
168
169bool DecodeBase58Check(std::string_view str, std::vector<unsigned char>& vchRet, int max_ret)
170{
171 if (ContainsNUL(str)) {
172 return false;
173 }
174 return DecodeBase58CheckRaw(str, vchRet, max_ret);
175}
std::string EncodeBase58(std::span< const unsigned char > input)
Encode a byte span as a base58-encoded string.
Definition base58.cpp:95
bool DecodeBase58(std::string_view str, std::vector< unsigned char > &vchRet, int max_ret_len)
Decode a base58-encoded string (str) into a byte vector (vchRet).
Definition base58.cpp:135
static bool DecodeBase58CheckRaw(std::string_view str, std::vector< unsigned char > &vchRet, int max_ret_len)
Definition base58.cpp:152
bool DecodeBase58Check(std::string_view str, std::vector< unsigned char > &vchRet, int max_ret)
Decode a base58-encoded string (str) that includes a checksum into a byte vector (vchRet),...
Definition base58.cpp:169
static const char * pszBase58
All alphanumeric characters except for "0", "I", "O", and "l".
Definition base58.cpp:22
static const int8_t mapBase58[256]
Definition base58.cpp:23
std::string EncodeBase58Check(std::span< const unsigned char > input)
Encode a byte span into a base58-encoded string, including checksum.
Definition base58.cpp:143
static bool DecodeBase58Raw(std::string_view str, std::vector< unsigned char > &vch, int max_ret_len)
Definition base58.cpp:42
Base58 and Base58Check encoding and decoding.
constexpr const unsigned char * data() const
Definition uint256.h:98
256-bit opaque blob.
Definition uint256.h:196
uint256 Hash(const T &in1)
Compute the 256-bit hash of an object.
Definition hash.h:83
bool ContainsNUL(std::string_view str) noexcept
Check if a string contains any embedded NUL (\0) characters.
Definition string.h:238
Utilities for converting data from/to strings.
constexpr bool IsSpace(char c) noexcept
Tests if the given character is a whitespace character.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
assert(!tx.IsCoinBase())