/Users/eugenesiegel/btc/bitcoin/src/base58.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 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 <cassert> | 
| 13 |  | #include <cstring> | 
| 14 |  |  | 
| 15 |  | #include <limits> | 
| 16 |  |  | 
| 17 |  | using util::ContainsNoNUL; | 
| 18 |  |  | 
| 19 |  | /** All alphanumeric characters except for "0", "I", "O", and "l" */ | 
| 20 |  | static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | 
| 21 |  | static 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, | 
| 27 |  |     22,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, | 
| 29 |  |     47,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 |  | }; | 
| 39 |  |  | 
| 40 |  | [[nodiscard]] static bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len) | 
| 41 | 0 | { | 
| 42 |  |     // Skip leading spaces. | 
| 43 | 0 |     while (*psz && IsSpace(*psz)) | 
| 44 | 0 |         psz++; | 
| 45 |  |     // Skip and count leading '1's. | 
| 46 | 0 |     int zeroes = 0; | 
| 47 | 0 |     int length = 0; | 
| 48 | 0 |     while (*psz == '1') { | 
| 49 | 0 |         zeroes++; | 
| 50 | 0 |         if (zeroes > max_ret_len) return false; | 
| 51 | 0 |         psz++; | 
| 52 | 0 |     } | 
| 53 |  |     // Allocate enough space in big-endian base256 representation. | 
| 54 | 0 |     int size = strlen(psz) * 733 /1000 + 1; // log(58) / log(256), rounded up. | 
| 55 | 0 |     std::vector<unsigned char> b256(size); | 
| 56 |  |     // Process the characters. | 
| 57 | 0 |     static_assert(std::size(mapBase58) == 256, "mapBase58.size() should be 256"); // guarantee not out of range | 
| 58 | 0 |     while (*psz && !IsSpace(*psz)) { | 
| 59 |  |         // Decode base58 character | 
| 60 | 0 |         int carry = mapBase58[(uint8_t)*psz]; | 
| 61 | 0 |         if (carry == -1)  // Invalid b58 character | 
| 62 | 0 |             return false; | 
| 63 | 0 |         int i = 0; | 
| 64 | 0 |         for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) { | 
| 65 | 0 |             carry += 58 * (*it); | 
| 66 | 0 |             *it = carry % 256; | 
| 67 | 0 |             carry /= 256; | 
| 68 | 0 |         } | 
| 69 | 0 |         assert(carry == 0); | 
| 70 | 0 |         length = i; | 
| 71 | 0 |         if (length + zeroes > max_ret_len) return false; | 
| 72 | 0 |         psz++; | 
| 73 | 0 |     } | 
| 74 |  |     // Skip trailing spaces. | 
| 75 | 0 |     while (IsSpace(*psz)) | 
| 76 | 0 |         psz++; | 
| 77 | 0 |     if (*psz != 0) | 
| 78 | 0 |         return false; | 
| 79 |  |     // Skip leading zeroes in b256. | 
| 80 | 0 |     std::vector<unsigned char>::iterator it = b256.begin() + (size - length); | 
| 81 |  |     // Copy result into output vector. | 
| 82 | 0 |     vch.reserve(zeroes + (b256.end() - it)); | 
| 83 | 0 |     vch.assign(zeroes, 0x00); | 
| 84 | 0 |     while (it != b256.end()) | 
| 85 | 0 |         vch.push_back(*(it++)); | 
| 86 | 0 |     return true; | 
| 87 | 0 | } | 
| 88 |  |  | 
| 89 |  | std::string EncodeBase58(std::span<const unsigned char> input) | 
| 90 | 0 | { | 
| 91 |  |     // Skip & count leading zeroes. | 
| 92 | 0 |     int zeroes = 0; | 
| 93 | 0 |     int length = 0; | 
| 94 | 0 |     while (input.size() > 0 && input[0] == 0) { | 
| 95 | 0 |         input = input.subspan(1); | 
| 96 | 0 |         zeroes++; | 
| 97 | 0 |     } | 
| 98 |  |     // Allocate enough space in big-endian base58 representation. | 
| 99 | 0 |     int size = input.size() * 138 / 100 + 1; // log(256) / log(58), rounded up. | 
| 100 | 0 |     std::vector<unsigned char> b58(size); | 
| 101 |  |     // Process the bytes. | 
| 102 | 0 |     while (input.size() > 0) { | 
| 103 | 0 |         int carry = input[0]; | 
| 104 | 0 |         int i = 0; | 
| 105 |  |         // Apply "b58 = b58 * 256 + ch". | 
| 106 | 0 |         for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) { | 
| 107 | 0 |             carry += 256 * (*it); | 
| 108 | 0 |             *it = carry % 58; | 
| 109 | 0 |             carry /= 58; | 
| 110 | 0 |         } | 
| 111 |  | 
 | 
| 112 | 0 |         assert(carry == 0); | 
| 113 | 0 |         length = i; | 
| 114 | 0 |         input = input.subspan(1); | 
| 115 | 0 |     } | 
| 116 |  |     // Skip leading zeroes in base58 result. | 
| 117 | 0 |     std::vector<unsigned char>::iterator it = b58.begin() + (size - length); | 
| 118 | 0 |     while (it != b58.end() && *it == 0) | 
| 119 | 0 |         it++; | 
| 120 |  |     // Translate the result into a string. | 
| 121 | 0 |     std::string str; | 
| 122 | 0 |     str.reserve(zeroes + (b58.end() - it)); | 
| 123 | 0 |     str.assign(zeroes, '1'); | 
| 124 | 0 |     while (it != b58.end()) | 
| 125 | 0 |         str += pszBase58[*(it++)]; | 
| 126 | 0 |     return str; | 
| 127 | 0 | } | 
| 128 |  |  | 
| 129 |  | bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len) | 
| 130 | 0 | { | 
| 131 | 0 |     if (!ContainsNoNUL(str)) { | 
| 132 | 0 |         return false; | 
| 133 | 0 |     } | 
| 134 | 0 |     return DecodeBase58(str.c_str(), vchRet, max_ret_len); | 
| 135 | 0 | } | 
| 136 |  |  | 
| 137 |  | std::string EncodeBase58Check(std::span<const unsigned char> input) | 
| 138 | 0 | { | 
| 139 |  |     // add 4-byte hash check to the end | 
| 140 | 0 |     std::vector<unsigned char> vch(input.begin(), input.end()); | 
| 141 | 0 |     uint256 hash = Hash(vch); | 
| 142 | 0 |     vch.insert(vch.end(), hash.data(), hash.data() + 4); | 
| 143 | 0 |     return EncodeBase58(vch); | 
| 144 | 0 | } | 
| 145 |  |  | 
| 146 |  | [[nodiscard]] static bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len) | 
| 147 | 0 | { | 
| 148 | 0 |     if (!DecodeBase58(psz, vchRet, max_ret_len > std::numeric_limits<int>::max() - 4 ? std::numeric_limits<int>::max() : max_ret_len + 4) || | 
| 149 | 0 |         (vchRet.size() < 4)) { | 
| 150 | 0 |         vchRet.clear(); | 
| 151 | 0 |         return false; | 
| 152 | 0 |     } | 
| 153 |  |     // re-calculate the checksum, ensure it matches the included 4-byte checksum | 
| 154 | 0 |     uint256 hash = Hash(std::span{vchRet}.first(vchRet.size() - 4)); | 
| 155 | 0 |     if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) { | 
| 156 | 0 |         vchRet.clear(); | 
| 157 | 0 |         return false; | 
| 158 | 0 |     } | 
| 159 | 0 |     vchRet.resize(vchRet.size() - 4); | 
| 160 | 0 |     return true; | 
| 161 | 0 | } | 
| 162 |  |  | 
| 163 |  | bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret) | 
| 164 | 0 | { | 
| 165 | 0 |     if (!ContainsNoNUL(str)) { | 
| 166 | 0 |         return false; | 
| 167 | 0 |     } | 
| 168 | 0 |     return DecodeBase58Check(str.c_str(), vchRet, max_ret); | 
| 169 | 0 | } |