Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2014-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <base58.h>7#include <hash.h>8#include <uint256.h>9#include <util/strencodings.h>10#include <util/string.h>12#include <cassert>13#include <cstring>15#include <limits>17using util::ContainsNUL;19/** All alphanumeric characters except for "0", "I", "O", and "l" */20static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";21static const int8_t mapBase58[256] = {22-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,-1,-1,-1,-1,-1,24-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,25-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,26-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,2722,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,28-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,2947,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,30-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,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};40[[nodiscard]] static bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len)41{42// Skip leading spaces.43while (*psz && IsSpace(*psz))44psz++;45// Skip and count leading '1's.46int zeroes = 0;47int length = 0;48while (*psz == '1') {49zeroes++;50if (zeroes > max_ret_len) return false;51psz++;52}53// Allocate enough space in big-endian base256 representation.54int size = strlen(psz) * 733 /1000 + 1; // log(58) / log(256), rounded up.55std::vector<unsigned char> b256(size);56// Process the characters.57static_assert(std::size(mapBase58) == 256, "mapBase58.size() should be 256"); // guarantee not out of range58while (*psz && !IsSpace(*psz)) {59// Decode base58 character60int carry = mapBase58[(uint8_t)*psz];61if (carry == -1) // Invalid b58 character62return false;63int i = 0;64for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {65carry += 58 * (*it);66*it = carry % 256;67carry /= 256;68}69assert(carry == 0);70length = i;71if (length + zeroes > max_ret_len) return false;72psz++;73}74// Skip trailing spaces.75while (IsSpace(*psz))76psz++;77if (*psz != 0)78return false;79// Skip leading zeroes in b256.80std::vector<unsigned char>::iterator it = b256.begin() + (size - length);81// Copy result into output vector.82vch.reserve(zeroes + (b256.end() - it));83vch.assign(zeroes, 0x00);84while (it != b256.end())85vch.push_back(*(it++));86return true;87}89std::string EncodeBase58(std::span<const unsigned char> input)90{91// Skip & count leading zeroes.92int zeroes = 0;93int length = 0;94while (input.size() > 0 && input[0] == 0) {95input = input.subspan(1);96zeroes++;97}98// Allocate enough space in big-endian base58 representation.99int size = input.size() * 138 / 100 + 1; // log(256) / log(58), rounded up.100std::vector<unsigned char> b58(size);101// Process the bytes.102while (input.size() > 0) {103int carry = input[0];104int i = 0;105// Apply "b58 = b58 * 256 + ch".106for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) {107carry += 256 * (*it);108*it = carry % 58;109carry /= 58;110}112assert(carry == 0);113length = i;114input = input.subspan(1);115}116// Skip leading zeroes in base58 result.117std::vector<unsigned char>::iterator it = b58.begin() + (size - length);118while (it != b58.end() && *it == 0)119it++;120// Translate the result into a string.121std::string str;122str.reserve(zeroes + (b58.end() - it));123str.assign(zeroes, '1');124while (it != b58.end())125str += pszBase58[*(it++)];126return str;127}129bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len)130{131if (ContainsNUL(str)) {132return false;133}134return DecodeBase58(str.c_str(), vchRet, max_ret_len);135}137std::string EncodeBase58Check(std::span<const unsigned char> input)138{139// add 4-byte hash check to the end140std::vector<unsigned char> vch(input.begin(), input.end());141uint256 hash = Hash(vch);142vch.insert(vch.end(), hash.data(), hash.data() + 4);143return EncodeBase58(vch);144}146[[nodiscard]] static bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len)147{148if (!DecodeBase58(psz, vchRet, max_ret_len > std::numeric_limits<int>::max() - 4 ? std::numeric_limits<int>::max() : max_ret_len + 4) ||149(vchRet.size() < 4)) {150vchRet.clear();151return false;152}153// re-calculate the checksum, ensure it matches the included 4-byte checksum154uint256 hash = Hash(std::span{vchRet}.first(vchRet.size() - 4));155if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) {156vchRet.clear();157return false;158}159vchRet.resize(vchRet.size() - 4);160return true;161}163bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret)164{165if (ContainsNUL(str)) {166return false;167}168return DecodeBase58Check(str.c_str(), vchRet, max_ret);169}