Page MenuHomePhabricator

base58.cpp
No OneTemporary

base58.cpp

// Copyright (c) 2014-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <base58.h>
#include <hash.h>
#include <uint256.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <limits>
/** All alphanumeric characters except for "0", "I", "O", and "l" */
static const char *pszBase58 =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
static const int8_t mapBase58[256] = {
-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, -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, -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, -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,
};
[[nodiscard]] static bool
DecodeBase58(const char *psz, std::vector<uint8_t> &vch, int max_ret_len) {
// Skip leading spaces.
while (*psz && IsSpace(*psz)) {
psz++;
}
// Skip and count leading '1's.
int zeroes = 0;
int length = 0;
while (*psz == '1') {
zeroes++;
if (zeroes > max_ret_len) {
return false;
}
psz++;
}
// Allocate enough space in big-endian base256 representation.
// log(58) / log(256), rounded up.
int size = strlen(psz) * 733 / 1000 + 1;
std::vector<uint8_t> b256(size);
// Process the characters.
// guarantee not out of range
static_assert(std::size(mapBase58) == 256,
"mapBase58.size() should be 256");
while (*psz && !IsSpace(*psz)) {
// Decode base58 character
int carry = mapBase58[(uint8_t)*psz];
// Invalid b58 character
if (carry == -1) {
return false;
}
int i = 0;
for (std::vector<uint8_t>::reverse_iterator it = b256.rbegin();
(carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {
carry += 58 * (*it);
*it = carry % 256;
carry /= 256;
}
assert(carry == 0);
length = i;
if (length + zeroes > max_ret_len) {
return false;
}
psz++;
}
// Skip trailing spaces.
while (IsSpace(*psz)) {
psz++;
}
if (*psz != 0) {
return false;
}
// Skip leading zeroes in b256.
std::vector<uint8_t>::iterator it = b256.begin() + (size - length);
// Copy result into output vector.
vch.reserve(zeroes + (b256.end() - it));
vch.assign(zeroes, 0x00);
while (it != b256.end()) {
vch.push_back(*(it++));
}
return true;
}
std::string EncodeBase58(Span<const uint8_t> input) {
// Skip & count leading zeroes.
int zeroes = 0;
int length = 0;
while (input.size() > 0 && input[0] == 0) {
input = input.subspan(1);
zeroes++;
}
// Allocate enough space in big-endian base58 representation.
// log(256) / log(58), rounded up.
int size = input.size() * 138 / 100 + 1;
std::vector<uint8_t> b58(size);
// Process the bytes.
while (input.size() > 0) {
int carry = input[0];
int i = 0;
// Apply "b58 = b58 * 256 + ch".
for (std::vector<uint8_t>::reverse_iterator it = b58.rbegin();
(carry != 0 || i < length) && (it != b58.rend()); it++, i++) {
carry += 256 * (*it);
*it = carry % 58;
carry /= 58;
}
assert(carry == 0);
length = i;
input = input.subspan(1);
}
// Skip leading zeroes in base58 result.
std::vector<uint8_t>::iterator it = b58.begin() + (size - length);
while (it != b58.end() && *it == 0) {
it++;
}
// Translate the result into a string.
std::string str;
str.reserve(zeroes + (b58.end() - it));
str.assign(zeroes, '1');
while (it != b58.end()) {
str += pszBase58[*(it++)];
}
return str;
}
bool DecodeBase58(const std::string &str, std::vector<uint8_t> &vchRet,
int max_ret_len) {
if (!ContainsNoNUL(str)) {
return false;
}
return DecodeBase58(str.c_str(), vchRet, max_ret_len);
}
std::string EncodeBase58Check(Span<const uint8_t> input) {
// add 4-byte hash check to the end
std::vector<uint8_t> vch(input.begin(), input.end());
uint256 hash = Hash(vch);
vch.insert(vch.end(), (uint8_t *)&hash, (uint8_t *)&hash + 4);
return EncodeBase58(vch);
}
[[nodiscard]] static bool DecodeBase58Check(const char *psz,
std::vector<uint8_t> &vchRet,
int max_ret_len) {
if (!DecodeBase58(psz, vchRet,
max_ret_len > std::numeric_limits<int>::max() - 4
? std::numeric_limits<int>::max()
: max_ret_len + 4) ||
(vchRet.size() < 4)) {
vchRet.clear();
return false;
}
// re-calculate the checksum, ensure it matches the included 4-byte checksum
uint256 hash = Hash(Span{vchRet}.first(vchRet.size() - 4));
if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) {
vchRet.clear();
return false;
}
vchRet.resize(vchRet.size() - 4);
return true;
}
bool DecodeBase58Check(const std::string &str, std::vector<uint8_t> &vchRet,
int max_ret) {
if (!ContainsNoNUL(str)) {
return false;
}
return DecodeBase58Check(str.c_str(), vchRet, max_ret);
}

File Metadata

Mime Type
text/x-c
Expires
Mon, Nov 25, 08:02 (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4550548
Default Alt Text
base58.cpp (6 KB)

Event Timeline