diff --git a/src/ripple/protocol/impl/b58_utils.h b/src/ripple/protocol/impl/b58_utils.h index c3bb0c03750..1e7519f0eb0 100644 --- a/src/ripple/protocol/impl/b58_utils.h +++ b/src/ripple/protocol/impl/b58_utils.h @@ -21,6 +21,7 @@ #define RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED #include +#include #include #include @@ -71,12 +72,12 @@ carrying_add(std::uint64_t a, std::uint64_t b) // (i.e a[0] is the 2^0 coefficient, a[n] is the 2^(64*n) coefficient) // panics if overflows (this is a specialized adder for b58 decoding. // it should never overflow). -inline void +[[nodiscard]] inline TokenCodecErrc inplace_bigint_add(std::span a, std::uint64_t b) { if (a.size() <= 1) { - ripple::LogicError("Input span too small for inplace_bigint_add"); + return TokenCodecErrc::inputTooSmall; } std::uint64_t carry; @@ -86,28 +87,29 @@ inplace_bigint_add(std::span a, std::uint64_t b) { if (!carry) { - return; + return TokenCodecErrc::success; } std::tie(v, carry) = carrying_add(v, 1); } if (carry) { - LogicError("Overflow in inplace_bigint_add"); + return TokenCodecErrc::overflowAdd; } + return TokenCodecErrc::success; } -inline void +[[nodiscard]] inline TokenCodecErrc inplace_bigint_mul(std::span a, std::uint64_t b) { if (a.empty()) { - LogicError("Empty span passed to inplace_bigint_mul"); + return TokenCodecErrc::inputTooSmall; } auto const last_index = a.size() - 1; if (a[last_index] != 0) { - LogicError("Non-zero element in inplace_bigint_mul last index"); + return TokenCodecErrc::inputTooLarge; } std::uint64_t carry = 0; @@ -116,7 +118,9 @@ inplace_bigint_mul(std::span a, std::uint64_t b) std::tie(coeff, carry) = carrying_mul(coeff, b, carry); } a[last_index] = carry; + return TokenCodecErrc::success; } + // divide a "big uint" value inplace and return the mod // numerator is stored so smallest coefficients come first [[nodiscard]] inline std::uint64_t @@ -166,11 +170,7 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) b58_10_to_b58_be(std::uint64_t input) { constexpr std::uint64_t B_58_10 = 430804206899405824; // 58^10; - if (input >= B_58_10) - { - LogicError("Input to b58_10_to_b58_be equals or exceeds 58^10."); - } - + assert(input < B_58_10); constexpr std::size_t resultSize = 10; std::array result{}; int i = 0; diff --git a/src/ripple/protocol/impl/token_errors.h b/src/ripple/protocol/impl/token_errors.h index 59b09974149..23a46bd1c5e 100644 --- a/src/ripple/protocol/impl/token_errors.h +++ b/src/ripple/protocol/impl/token_errors.h @@ -32,6 +32,7 @@ enum class TokenCodecErrc { mismatchedTokenType, mismatchedChecksum, invalidEncodingChar, + overflowAdd, unknown, }; } diff --git a/src/ripple/protocol/impl/tokens.cpp b/src/ripple/protocol/impl/tokens.cpp index 8445eec38ca..a166ac733cd 100644 --- a/src/ripple/protocol/impl/tokens.cpp +++ b/src/ripple/protocol/impl/tokens.cpp @@ -467,6 +467,11 @@ b256_to_b58_be(std::span input, std::span out) { continue; } + static constexpr std::uint64_t B_58_10 = 430804206899405824; // 58^10; + if (base_58_10_coeff[i] >= B_58_10) + { + return Unexpected(TokenCodecErrc::inputTooLarge); + } std::array const b58_be = ripple::b58_fast::detail::b58_10_to_b58_be(base_58_10_coeff[i]); std::size_t to_skip = 0; @@ -565,10 +570,23 @@ b58_to_b256_be(std::string_view input, std::span out) for (int i = 1; i < num_b_58_10_coeffs; ++i) { std::uint64_t const c = b_58_10_coeff[i]; - ripple::b58_fast::detail::inplace_bigint_mul( - std::span(&result[0], cur_result_size + 1), B_58_10); - ripple::b58_fast::detail::inplace_bigint_add( - std::span(&result[0], cur_result_size + 1), c); + + { + auto code = ripple::b58_fast::detail::inplace_bigint_mul( + std::span(&result[0], cur_result_size + 1), B_58_10); + if (code != TokenCodecErrc::success) + { + return Unexpected(code); + } + } + { + auto code = ripple::b58_fast::detail::inplace_bigint_add( + std::span(&result[0], cur_result_size + 1), c); + if (code != TokenCodecErrc::success) + { + return Unexpected(code); + } + } if (result[cur_result_size] != 0) { cur_result_size += 1; diff --git a/src/test/basics/base58_test.cpp b/src/test/basics/base58_test.cpp index 6f3d495d7a9..8b79d2729d7 100644 --- a/src/test/basics/base58_test.cpp +++ b/src/test/basics/base58_test.cpp @@ -177,6 +177,7 @@ class base58_test : public beast::unit_test::suite constexpr std::size_t iters = 100000; auto eng = randEngine(); std::uniform_int_distribution dist; + std::uniform_int_distribution dist1(1); for (int i = 0; i < iters; ++i) { std::uint64_t const d = dist(eng); @@ -209,12 +210,31 @@ class base58_test : public beast::unit_test::suite auto const refAdd = boostBigInt + d; - b58_fast::detail::inplace_bigint_add( + auto const result = b58_fast::detail::inplace_bigint_add( std::span(bigInt.data(), bigInt.size()), d); + BEAST_EXPECT(result == TokenCodecErrc::success); auto const foundAdd = multiprecision_utils::toBoostMP(bigInt); BEAST_EXPECT(refAdd == foundAdd); } for (int i = 0; i < iters; ++i) + { + std::uint64_t const d = dist1(eng); + // Force overflow + std::vector bigInt( + 5, std::numeric_limits::max()); + + auto const boostBigInt = multiprecision_utils::toBoostMP( + std::span(bigInt.data(), bigInt.size())); + + auto const refAdd = boostBigInt + d; + + auto const result = b58_fast::detail::inplace_bigint_add( + std::span(bigInt.data(), bigInt.size()), d); + BEAST_EXPECT(result == TokenCodecErrc::overflowAdd); + auto const foundAdd = multiprecision_utils::toBoostMP(bigInt); + BEAST_EXPECT(refAdd != foundAdd); + } + for (int i = 0; i < iters; ++i) { std::uint64_t const d = dist(eng); auto bigInt = multiprecision_utils::randomBigInt(/* minSize */ 2); @@ -226,11 +246,29 @@ class base58_test : public beast::unit_test::suite auto const refMul = boostBigInt * d; - b58_fast::detail::inplace_bigint_mul( + auto const result = b58_fast::detail::inplace_bigint_mul( std::span(bigInt.data(), bigInt.size()), d); + BEAST_EXPECT(result == TokenCodecErrc::success); auto const foundMul = multiprecision_utils::toBoostMP(bigInt); BEAST_EXPECT(refMul == foundMul); } + for (int i = 0; i < iters; ++i) + { + std::uint64_t const d = dist1(eng); + // Force overflow + std::vector bigInt( + 5, std::numeric_limits::max()); + auto const boostBigInt = multiprecision_utils::toBoostMP( + std::span(bigInt.data(), bigInt.size())); + + auto const refMul = boostBigInt * d; + + auto const result = b58_fast::detail::inplace_bigint_mul( + std::span(bigInt.data(), bigInt.size()), d); + BEAST_EXPECT(result == TokenCodecErrc::inputTooLarge); + auto const foundMul = multiprecision_utils::toBoostMP(bigInt); + BEAST_EXPECT(refMul != foundMul); + } } void