mirror of
https://github.com/cculianu/Fulcrum.git
synced 2026-08-18 13:09:12 +02:00
166 lines
4.7 KiB
C++
166 lines
4.7 KiB
C++
// 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 "utilstrencodings.h"
|
|
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wconversion"
|
|
#pragma clang diagnostic ignored "-Wold-style-cast"
|
|
#endif
|
|
|
|
namespace bitcoin {
|
|
/** All alphanumeric characters except for "0", "I", "O", and "l" */
|
|
static const char *pszBase58 =
|
|
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
|
|
bool DecodeBase58(const char *psz, std::vector<uint8_t> &vch) {
|
|
// Skip leading spaces.
|
|
while (*psz && IsSpace(*psz)) {
|
|
psz++;
|
|
}
|
|
// Skip and count leading '1's.
|
|
int zeroes = 0;
|
|
int length = 0;
|
|
while (*psz == '1') {
|
|
zeroes++;
|
|
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.
|
|
while (*psz && !IsSpace(*psz)) {
|
|
// Decode base58 character
|
|
const char *ch = strchr(pszBase58, *psz);
|
|
if (ch == nullptr) {
|
|
return false;
|
|
}
|
|
// Apply "b256 = b256 * 58 + ch".
|
|
int carry = ch - pszBase58;
|
|
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;
|
|
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);
|
|
while (it != b256.end() && *it == 0)
|
|
it++;
|
|
// 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(const uint8_t *pbegin, const uint8_t *pend) {
|
|
// Skip & count leading zeroes.
|
|
int zeroes = 0;
|
|
int length = 0;
|
|
while (pbegin != pend && *pbegin == 0) {
|
|
pbegin++;
|
|
zeroes++;
|
|
}
|
|
// Allocate enough space in big-endian base58 representation.
|
|
// log(256) / log(58), rounded up.
|
|
int size = (pend - pbegin) * 138 / 100 + 1;
|
|
std::vector<uint8_t> b58(size);
|
|
// Process the bytes.
|
|
while (pbegin != pend) {
|
|
int carry = *pbegin;
|
|
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;
|
|
pbegin++;
|
|
}
|
|
// 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;
|
|
}
|
|
|
|
std::string EncodeBase58(const std::vector<uint8_t> &vch) {
|
|
return EncodeBase58(&vch[0], &vch[0] + vch.size());
|
|
}
|
|
|
|
bool DecodeBase58(const std::string &str, std::vector<uint8_t> &vchRet) {
|
|
return DecodeBase58(str.c_str(), vchRet);
|
|
}
|
|
|
|
std::string EncodeBase58Check(const std::vector<uint8_t> &vchIn) {
|
|
// add 4-byte hash check to the end
|
|
std::vector<uint8_t> vch(vchIn);
|
|
uint256 hash = Hash(vch.begin(), vch.end());
|
|
vch.insert(vch.end(), (uint8_t *)&hash, (uint8_t *)&hash + 4);
|
|
return EncodeBase58(vch);
|
|
}
|
|
|
|
bool DecodeBase58Check(const char *psz, std::vector<uint8_t> &vchRet) {
|
|
if (!DecodeBase58(psz, vchRet) || (vchRet.size() < 4)) {
|
|
vchRet.clear();
|
|
return false;
|
|
}
|
|
// re-calculate the checksum, insure it matches the included 4-byte checksum
|
|
uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
|
|
if (memcmp(&hash, &vchRet.end()[-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) {
|
|
return DecodeBase58Check(str.c_str(), vchRet);
|
|
}
|
|
|
|
} // end namespace bitcoin
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic pop
|
|
#endif
|