10#include <xrpl/protocol/tokens.h>
12#include <xrpl/basics/safe_cast.h>
13#include <xrpl/beast/utility/instrumentation.h>
14#include <xrpl/protocol/detail/b58_utils.h>
15#include <xrpl/protocol/detail/token_errors.h>
16#include <xrpl/protocol/digest.h>
18#include <boost/container/small_vector.hpp>
19#include <boost/endian/conversion.hpp>
127 "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz";
138template <
class Hasher>
139static Hasher::result_type
144 return static_cast<Hasher::result_type
>(h);
147template <
class Hasher,
class T, std::
size_t N>
148static Hasher::result_type
150 requires(
sizeof(T) == 1)
156template <
class Hasher,
class... Args>
157static Hasher::result_type
184 return b58_fast::encodeBase58Token(type, token, size);
194 return b58_fast::decodeBase58Token(s, type);
207 auto pbegin =
reinterpret_cast<unsigned char const*
>(message);
208 auto const pend = pbegin + size;
212 while (pbegin != pend && *pbegin == 0)
218 auto const b58begin =
reinterpret_cast<unsigned char*
>(temp);
219 auto const b58end = b58begin + tempSize;
223 while (pbegin != pend)
227 for (
auto iter = b58end; iter != b58begin; --iter)
229 carry += 256 * (iter[-1]);
230 iter[-1] = carry % 58;
233 XRPL_ASSERT(carry == 0,
"xrpl::b58_ref::detail::encodeBase58 : zero carry");
238 auto iter = b58begin;
239 while (iter != b58end && *iter == 0)
244 str.
reserve(zeroes + (b58end - iter));
246 while (iter != b58end)
254 auto psz =
reinterpret_cast<unsigned char const*
>(s.
c_str());
255 auto remain = s.
size();
283 XRPL_ASSERT(carry == 0,
"xrpl::b58_ref::detail::decodeBase58 : zero carry");
291 result.assign(zeroes, 0x00);
292 while (iter != b256.
end())
293 result.push_back(*(iter++));
303 auto const expanded = 1 + size + 4;
308 auto const bufsize = expanded * 3;
310 boost::container::small_vector<std::uint8_t, 1024> buf(bufsize);
317 checksum(buf.data() + 1 + size, buf.data(), 1 + size);
352B58Result<std::span<std::uint8_t>>
357 if (input.
size() > 38)
362 auto countLeadingZeros = [](std::span<std::uint8_t const>
const& col) -> std::size_t {
363 std::size_t
count = 0;
364 for (
auto const& c : col)
375 auto const inputZeros = countLeadingZeros(input);
376 input = input.
subspan(inputZeros);
380 std::array<std::uint64_t, 5> base264CoeffBuf{};
381 std::span<std::uint64_t>
const base264Coeff = [&]() -> std::span<std::uint64_t> {
383 std::size_t numCoeff = 0;
384 for (
int i = 0; i < base264CoeffBuf.
size(); ++i)
386 if (i * 8 >= input.
size())
390 auto const srcIEnd = input.
size() - (i * 8);
393 std::memcpy(&base264CoeffBuf[numCoeff], &input[srcIEnd - 8], 8);
394 boost::endian::big_to_native_inplace(base264CoeffBuf[numCoeff]);
398 std::uint64_t be = 0;
399 for (
int bi = 0; bi < srcIEnd; ++bi)
404 base264CoeffBuf[numCoeff] = be;
408 return std::span(base264CoeffBuf.
data(), numCoeff);
413 std::array<std::uint64_t, 6> base5810Coeff{};
414 constexpr std::uint64_t kB5810 = 430804206899405824;
415 std::size_t num5810Coeffs = 0;
416 std::size_t cur264End = base264Coeff.
size();
418 while (cur264End > 0)
420 base5810Coeff[num5810Coeffs] =
421 xrpl::b58_fast::detail::inplaceBigintDivRem(base264Coeff.
subspan(0, cur264End), kB5810);
423 if (base264Coeff[cur264End - 1] == 0)
436 bool skipZeros =
true;
437 auto outIndex = inputZeros;
438 for (
int i = num5810Coeffs - 1; i >= 0; --i)
440 if (skipZeros && base5810Coeff[i] == 0)
444 static constexpr std::uint64_t kB5810 = 430804206899405824;
445 if (base5810Coeff[i] >= kB5810)
449 std::array<std::uint8_t, 10>
const b58Be =
450 xrpl::b58_fast::detail::b5810ToB58Be(base5810Coeff[i]);
451 std::size_t toSkip = 0;
452 std::span<std::uint8_t const>
const b58BeS{b58Be.
data(), b58Be.
size()};
455 toSkip = countLeadingZeros(b58BeS);
457 if (out.
size() < ((i + 1) * 10) - toSkip)
462 for (
auto b58Coeff : b58BeS.
subspan(toSkip))
469 return out.
subspan(0, outIndex);
473B58Result<std::span<std::uint8_t>>
474b58ToB256Be(std::string_view input, std::span<std::uint8_t> out)
480 if (input.
size() > 52)
489 auto countLeadingZeros = [&](
auto const& col) -> std::size_t {
490 std::size_t
count = 0;
491 for (
auto const& c : col)
502 auto const inputZeros = countLeadingZeros(input);
507 std::array<std::uint64_t, 6> b5810Coeff{};
508 auto [num_full_coeffs, partial_coeff_len] = xrpl::b58_fast::detail::divRem(input.
size(), 10);
509 auto const numPartialCoeffs = (partial_coeff_len != 0u) ? 1 : 0;
510 auto const numB5810Coeffs = num_full_coeffs + numPartialCoeffs;
512 numB5810Coeffs <= b5810Coeff.
size(),
513 "xrpl::b58_fast::detail::b58_to_b256_be : maximum coeff");
514 for (
unsigned char const c : input.
substr(0, partial_coeff_len))
522 b5810Coeff[0] += curVal;
524 for (
int i = 0; i < 10; ++i)
526 for (
int j = 0; j < num_full_coeffs; ++j)
528 unsigned char const c = input[partial_coeff_len + (j * 10) + i];
534 b5810Coeff[numPartialCoeffs + j] *= 58;
535 b5810Coeff[numPartialCoeffs + j] += curVal;
539 constexpr std::uint64_t kB5810 = 430804206899405824;
542 std::array<std::uint64_t, 5> result{};
543 result[0] = b5810Coeff[0];
544 std::size_t curResultSize = 1;
545 for (
int i = 1; i < numB5810Coeffs; ++i)
547 std::uint64_t
const c = b5810Coeff[i];
550 auto code = xrpl::b58_fast::detail::inplaceBigintMul(
551 std::span(&result[0], curResultSize + 1), kB5810);
552 if (code != TokenCodecErrc::Success)
558 auto code = xrpl::b58_fast::detail::inplaceBigintAdd(
559 std::span(&result[0], curResultSize + 1), c);
560 if (code != TokenCodecErrc::Success)
565 if (result[curResultSize] != 0)
571 auto curOutI = inputZeros;
575 std::uint64_t
const c = result[curResultSize - 1];
576 auto skipZero =
true;
578 for (
int i = 0; i < 8; ++i)
580 std::uint8_t
const b = (c >> (8 * (7 - i))) & 0xff;
593 if ((curOutI + (8 * (curResultSize - 1))) > out.
size())
598 for (
int i = curResultSize - 2; i >= 0; --i)
601 boost::endian::native_to_big_inplace(c);
602 memcpy(&out[curOutI], &c, 8);
606 return out.
subspan(0, curOutI);
610B58Result<std::span<std::uint8_t>>
613 std::span<std::uint8_t const> input,
614 std::span<std::uint8_t> out)
616 static constexpr std::size_t kTmpBufSize = 128;
617 std::array<std::uint8_t, kTmpBufSize> buf{};
618 if (input.
size() > kTmpBufSize - 5)
627 buf[0] =
static_cast<std::uint8_t
>(tokenType);
630 size_t const checksumI = input.
size() + 1;
633 std::span<std::uint8_t const>
const b58Span(buf.
data(), input.
size() + 5);
634 return detail::b256ToB58Be(b58Span, out);
641B58Result<std::span<std::uint8_t>>
642decodeBase58Token(TokenType type, std::string_view s, std::span<std::uint8_t> outBuf)
644 std::array<std::uint8_t, 64> tmpBuf{};
645 auto const decodeResult = detail::b58ToB256Be(s, std::span(tmpBuf.
data(), tmpBuf.
size()));
650 auto const ret = decodeResult.value();
657 if (type !=
static_cast<TokenType>(
static_cast<std::uint8_t
>(ret[0])))
661 std::array<std::uint8_t, 4> guard{};
668 std::size_t
const outSize = ret.size() - 1 - guard.
size();
669 if (outBuf.
size() < outSize)
672 std::copy(ret.begin() + 1, ret.begin() + outSize + 1, outBuf.
begin());
673 return outBuf.
subspan(0, outSize);
676[[nodiscard]] std::string
687 std::span<std::uint8_t>
const outSp(
reinterpret_cast<std::uint8_t*
>(sr.
data()), sr.
size());
688 std::span<std::uint8_t const>
const inSp(
reinterpret_cast<std::uint8_t const*
>(token), size);
689 auto r = b58_fast::encodeBase58Token(type, inSp, outSp);
692 sr.
resize(r.value().size());
696[[nodiscard]] std::string
703 std::span<std::uint8_t>
const outSp(
reinterpret_cast<std::uint8_t*
>(sr.
data()), sr.
size());
704 auto r = b58_fast::decodeBase58Token(type, s, outSp);
707 sr.
resize(r.value().size());
std::string decodeBase58(std::string const &s)
std::string encodeBase58(void const *message, std::size_t size, void *temp, std::size_t tempSize)
std::string encodeBase58Token(TokenType type, void const *token, std::size_t size)
std::string decodeBase58Token(std::string const &s, TokenType type)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static void checksum(void *out, void const *message, std::size_t size)
Calculate a 4-byte checksum of the data.
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
static constexpr std::array< int, 256 > const kAlphabetReverse
constexpr Dest safeCast(Src s) noexcept
static Hasher::result_type digest2(Args const &... args)
static constexpr char const * kAlphabetForward
std::string encodeBase58Token(TokenType type, void const *token, std::size_t size)
Encode data in Base58Check format using XRPL alphabet.
std::string decodeBase58Token(std::string const &s, TokenType type)