10#include <xrpl/basics/Expected.h>
11#include <xrpl/basics/safe_cast.h>
12#include <xrpl/beast/utility/instrumentation.h>
13#include <xrpl/protocol/detail/b58_utils.h>
14#include <xrpl/protocol/detail/token_errors.h>
15#include <xrpl/protocol/digest.h>
16#include <xrpl/protocol/tokens.h>
18#include <boost/container/small_vector.hpp>
19#include <boost/endian/conversion.hpp>
125 "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz";
136template <
class Hasher>
137static typename Hasher::result_type
142 return static_cast<typename Hasher::result_type
>(h);
145template <
class Hasher,
class T, std::
size_t N,
class = std::enable_if_t<sizeof(T) == 1>>
146static typename Hasher::result_type
149 return digest<Hasher>(v.
data(), v.
size());
153template <
class Hasher,
class... Args>
154static typename Hasher::result_type
157 return digest<Hasher>(digest<Hasher>(args...));
172 auto const h = digest2<sha256_hasher>(message, size);
180 return b58_fast::encodeBase58Token(type, token, size);
190 return b58_fast::decodeBase58Token(s, type);
203 auto pbegin =
reinterpret_cast<unsigned char const*
>(message);
204 auto const pend = pbegin + size;
208 while (pbegin != pend && *pbegin == 0)
214 auto const b58begin =
reinterpret_cast<unsigned char*
>(temp);
215 auto const b58end = b58begin + temp_size;
219 while (pbegin != pend)
223 for (
auto iter = b58end; iter != b58begin; --iter)
225 carry += 256 * (iter[-1]);
226 iter[-1] = carry % 58;
229 XRPL_ASSERT(carry == 0,
"xrpl::b58_ref::detail::encodeBase58 : zero carry");
234 auto iter = b58begin;
235 while (iter != b58end && *iter == 0)
240 str.
reserve(zeroes + (b58end - iter));
242 while (iter != b58end)
250 auto psz =
reinterpret_cast<unsigned char const*
>(s.
c_str());
251 auto remain = s.
size();
273 for (
auto iter = b256.
rbegin(); iter != b256.
rend(); ++iter)
279 XRPL_ASSERT(carry == 0,
"xrpl::b58_ref::detail::decodeBase58 : zero carry");
287 result.
assign(zeroes, 0x00);
288 while (iter != b256.
end())
299 auto const expanded = 1 + size + 4;
304 auto const bufsize = expanded * 3;
306 boost::container::small_vector<std::uint8_t, 1024> buf(bufsize);
310 buf[0] = safe_cast<std::underlying_type_t<TokenType>>(type);
313 checksum(buf.data() + 1 + size, buf.data(), 1 + size);
328 if (type != safe_cast<TokenType>(
static_cast<std::uint8_t>(ret[0])))
338 return ret.
substr(1, ret.
size() - 1 - guard.size());
348B58Result<std::span<std::uint8_t>>
353 if (input.
size() > 38)
355 return Unexpected(TokenCodecErrc::inputTooLarge);
360 for (
auto const& c : col)
371 auto const input_zeros = count_leading_zeros(input);
372 input = input.
subspan(input_zeros);
380 for (
int i = 0; i < base_2_64_coeff_buf.size(); ++i)
382 if (i * 8 >= input.
size())
386 auto const src_i_end = input.
size() - (i * 8);
389 std::memcpy(&base_2_64_coeff_buf[num_coeff], &input[src_i_end - 8], 8);
390 boost::endian::big_to_native_inplace(base_2_64_coeff_buf[num_coeff]);
395 for (
int bi = 0; bi < src_i_end; ++bi)
400 base_2_64_coeff_buf[num_coeff] = be;
404 return std::span(base_2_64_coeff_buf.data(), num_coeff);
414 while (cur_2_64_end > 0)
416 base_58_10_coeff[num_58_10_coeffs] = xrpl::b58_fast::detail::inplace_bigint_div_rem(
417 base_2_64_coeff.
subspan(0, cur_2_64_end), B_58_10);
418 num_58_10_coeffs += 1;
419 if (base_2_64_coeff[cur_2_64_end - 1] == 0)
432 bool skip_zeros =
true;
433 auto out_index = input_zeros;
434 for (
int i = num_58_10_coeffs - 1; i >= 0; --i)
436 if (skip_zeros && base_58_10_coeff[i] == 0)
441 if (base_58_10_coeff[i] >= B_58_10)
443 return Unexpected(TokenCodecErrc::inputTooLarge);
446 xrpl::b58_fast::detail::b58_10_to_b58_be(base_58_10_coeff[i]);
451 to_skip = count_leading_zeros(b58_be_s);
453 if (
out.size() < ((i + 1) * 10) - to_skip)
455 return Unexpected(TokenCodecErrc::outputTooSmall);
458 for (
auto b58_coeff : b58_be_s.subspan(to_skip))
465 return out.subspan(0, out_index);
469B58Result<std::span<std::uint8_t>>
476 if (input.
size() > 52)
478 return Unexpected(TokenCodecErrc::inputTooLarge);
482 return Unexpected(TokenCodecErrc::outputTooSmall);
485 auto count_leading_zeros = [&](
auto const& col) ->
std::size_t {
487 for (
auto const& c : col)
498 auto const input_zeros = count_leading_zeros(input);
504 auto [num_full_coeffs, partial_coeff_len] = xrpl::b58_fast::detail::div_rem(input.
size(), 10);
505 auto const num_partial_coeffs = (partial_coeff_len != 0u) ? 1 : 0;
506 auto const num_b_58_10_coeffs = num_full_coeffs + num_partial_coeffs;
508 num_b_58_10_coeffs <= b_58_10_coeff.size(),
509 "xrpl::b58_fast::detail::b58_to_b256_be : maximum coeff");
510 for (
unsigned char const c : input.substr(0, partial_coeff_len))
515 return Unexpected(TokenCodecErrc::invalidEncodingChar);
517 b_58_10_coeff[0] *= 58;
518 b_58_10_coeff[0] += cur_val;
520 for (
int i = 0; i < 10; ++i)
522 for (
int j = 0; j < num_full_coeffs; ++j)
524 unsigned char const c = input[partial_coeff_len + (j * 10) + i];
528 return Unexpected(TokenCodecErrc::invalidEncodingChar);
530 b_58_10_coeff[num_partial_coeffs + j] *= 58;
531 b_58_10_coeff[num_partial_coeffs + j] += cur_val;
539 result[0] = b_58_10_coeff[0];
541 for (
int i = 1; i < num_b_58_10_coeffs; ++i)
546 auto code = xrpl::b58_fast::detail::inplace_bigint_mul(
547 std::span(&result[0], cur_result_size + 1), B_58_10);
548 if (code != TokenCodecErrc::success)
554 auto code = xrpl::b58_fast::detail::inplace_bigint_add(
555 std::span(&result[0], cur_result_size + 1), c);
556 if (code != TokenCodecErrc::success)
561 if (result[cur_result_size] != 0)
563 cur_result_size += 1;
567 auto cur_out_i = input_zeros;
572 auto skip_zero =
true;
574 for (
int i = 0; i < 8; ++i)
589 if ((cur_out_i + (8 * (cur_result_size - 1))) >
out.size())
591 return Unexpected(TokenCodecErrc::outputTooSmall);
594 for (
int i = cur_result_size - 2; i >= 0; --i)
597 boost::endian::native_to_big_inplace(c);
598 memcpy(&out[cur_out_i], &c, 8);
602 return out.subspan(0, cur_out_i);
606B58Result<std::span<std::uint8_t>>
608 TokenType token_type,
614 if (input.
size() > tmpBufSize - 5)
616 return Unexpected(TokenCodecErrc::inputTooLarge);
620 return Unexpected(TokenCodecErrc::inputTooSmall);
626 size_t const checksum_i = input.
size() + 1;
628 checksum(buf.data() + checksum_i, buf.data(), checksum_i);
630 return detail::b256_to_b58_be(b58Span, out);
637B58Result<std::span<std::uint8_t>>
641 auto const decodeResult = detail::b58_to_b256_be(s,
std::span(tmpBuf.data(), tmpBuf.size()));
646 auto const ret = decodeResult.value();
650 return Unexpected(TokenCodecErrc::inputTooSmall);
654 return Unexpected(TokenCodecErrc::mismatchedTokenType);
658 checksum(guard.data(), ret.data(), ret.size() - guard.size());
659 if (!
std::equal(guard.rbegin(), guard.rend(), ret.rbegin()))
661 return Unexpected(TokenCodecErrc::mismatchedChecksum);
664 std::size_t const outSize = ret.size() - 1 - guard.size();
665 if (outBuf.
size() < outSize)
666 return Unexpected(TokenCodecErrc::outputTooSmall);
668 std::copy(ret.begin() + 1, ret.begin() + outSize + 1, outBuf.
begin());
669 return outBuf.
subspan(0, outSize);
685 auto r = b58_fast::encodeBase58Token(type, inSp, outSp);
688 sr.
resize(r.value().size());
700 auto r = b58_fast::decodeBase58Token(type, s, outSp);
703 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 temp_size)
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.
Unexpected(E(&)[N]) -> Unexpected< E const * >
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
static constexpr char const * alphabetForward
static Hasher::result_type digest2(Args const &... args)
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)
static constexpr std::array< int, 256 > const alphabetReverse