7#include <botan/base58.h>
9#include <botan/bigint.h>
10#include <botan/exceptn.h>
11#include <botan/hash.h>
12#include <botan/internal/ct_utils.h>
13#include <botan/internal/divide.h>
14#include <botan/internal/int_utils.h>
15#include <botan/internal/loadstor.h>
16#include <botan/internal/mul128.h>
22uint32_t sha256_d_checksum(
const uint8_t input[],
size_t input_length) {
25 std::vector<uint8_t> checksum(32);
27 sha256->update(input, input_length);
28 sha256->final(checksum);
30 sha256->update(checksum);
31 sha256->final(checksum);
36char lookup_base58_char(uint8_t x) {
50 return static_cast<char>(x + offset);
53consteval word base58_conversion_radix() {
54 if constexpr(
sizeof(
word) == 8) {
56 return 430804206899405824U;
63consteval size_t base58_conversion_radix_digits() {
64 if constexpr(
sizeof(
word) == 8) {
71constexpr std::pair<uint8_t, word> divmod_58(
word x) {
80 if constexpr(
sizeof(
word) == 4) {
81 const uint64_t magic = 2369637129;
82 const uint64_t z = magic * x;
85 const uint64_t magic = 5088756985850910791;
89 q =
static_cast<word>(hi >> 3);
92 const uint8_t r =
static_cast<uint8_t
>(x - q * 58);
93 return std::make_pair(r, q);
97 constexpr word radix = base58_conversion_radix();
98 constexpr size_t radix_digits = base58_conversion_radix_digits();
101 std::vector<uint8_t> digits;
103 while(v.is_nonzero()) {
107 for(
size_t i = 0; i != radix_digits; ++i) {
108 const auto [r58, q58] = divmod_58(r);
109 digits.push_back(r58);
116 while(!digits.empty() && digits.back() == 0) {
122 for(
const uint8_t d : digits) {
123 result.push_back(lookup_base58_char(d));
126 for(
size_t i = 0; i != leading_zeros; ++i) {
127 result.push_back(
'1');
130 return std::string(result.rbegin(), result.rend());
133template <
typename T,
typename Z>
134size_t count_leading_zeros(
const T input[],
size_t input_length, Z zero) {
135 size_t leading_zeros = 0;
137 while(leading_zeros < input_length && input[leading_zeros] == zero) {
141 return leading_zeros;
144uint8_t base58_value_of(
char input) {
157 constexpr uint64_t v_lo =
make_uint64(0,
'1',
'A',
'J',
'P',
'a',
'm', 0);
158 constexpr uint64_t v_range =
make_uint64(0, 9, 8, 5, 11, 11, 14, 0);
160 const uint8_t x =
static_cast<uint8_t
>(input);
161 const uint64_t x8 = x * 0x0101010101010101;
173 constexpr uint64_t val_v_const =
make_uint64(0, 0xCF, 0xC8, 0xC7, 0xC6, 0xC0, 0xBF, 0);
174 const uint64_t val_v = val_v_const ^ (
static_cast<uint64_t
>(0xFF - x) << 56);
182 const BigInt v(input, input_length);
183 return base58_encode(v, count_leading_zeros(input, input_length, 0));
187 BigInt v(input, input_length);
189 v += sha256_d_checksum(input, input_length);
190 return base58_encode(v, count_leading_zeros(input, input_length, 0));
193std::vector<uint8_t>
base58_decode(
const char input[],
size_t input_length) {
194 const size_t leading_zeros = count_leading_zeros(input, input_length,
'1');
196 std::vector<uint8_t> digits;
198 for(
size_t i = leading_zeros; i != input_length; ++i) {
199 const char c = input[i];
201 if(c ==
' ' || c ==
'\n') {
205 const uint8_t idx = base58_value_of(c);
211 digits.push_back(idx);
216 constexpr word radix1 = 58;
217 constexpr word radix2 = 58 * 58;
218 constexpr word radix3 = 58 * 58 * 58;
219 constexpr word radix4 = 58 * 58 * 58 * 58;
221 std::span<uint8_t> remaining{digits};
223 while(remaining.size() >= 4) {
224 const word accum = radix3 * remaining[0] + radix2 * remaining[1] + radix1 * remaining[2] + remaining[3];
227 remaining = remaining.subspan(4);
230 while(!remaining.empty()) {
233 remaining = remaining.subspan(1);
240 std::vector<uint8_t> dec =
base58_decode(input, input_length);
246 const uint32_t computed_checksum = sha256_d_checksum(dec.data(), dec.size() - 4);
249 if(checksum != computed_checksum) {
253 dec.resize(dec.size() - 4);
#define BOTAN_DEBUG_ASSERT(expr)
T serialize(size_t len) const
static constexpr Mask< T > is_gt(T x, T y)
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
constexpr uint64_t make_uint64(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4, uint8_t i5, uint8_t i6, uint8_t i7)
std::vector< uint8_t > base58_check_decode(const char input[], size_t input_length)
constexpr T swar_in_range(T v, T lower, T upper)
std::string base58_encode(const uint8_t input[], size_t input_length)
constexpr size_t index_of_first_set_byte(T v)
std::string base58_check_encode(const uint8_t input[], size_t input_length)
void ct_divide_word(const BigInt &x, word y, BigInt &q_out, word &r_out)
std::vector< uint8_t > base58_decode(const char input[], size_t input_length)
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
constexpr void mul64x64_128(uint64_t a, uint64_t b, uint64_t *lo, uint64_t *hi)
constexpr auto load_be(ParamTs &&... params)