diff --git a/src/ripple/protocol/impl/b58_utils.h b/src/ripple/protocol/impl/b58_utils.h index bbbf09751f9..9955887e398 100644 --- a/src/ripple/protocol/impl/b58_utils.h +++ b/src/ripple/protocol/impl/b58_utils.h @@ -51,24 +51,24 @@ div_rem(std::uint64_t a, std::uint64_t b) [[nodiscard]] inline std::tuple carrying_mul(std::uint64_t a, std::uint64_t b, std::uint64_t carry) { - unsigned __int128 x = a; - unsigned __int128 y = b; - unsigned __int128 c = x * y + carry; - return {c & 0xffffffffffffffff, c >> 64}; + unsigned __int128 const x = a; + unsigned __int128 const y = b; + unsigned __int128 const c = x * y + carry; + return {c & 0xffff'ffff'ffff'ffff, c >> 64}; } [[nodiscard]] inline std::tuple carrying_add(std::uint64_t a, std::uint64_t b) { - unsigned __int128 x = a; - unsigned __int128 y = b; - unsigned __int128 c = x + y; - return {c & 0xffffffffffffffff, c >> 64}; + unsigned __int128 const x = a; + unsigned __int128 const y = b; + unsigned __int128 const c = x + y; + return {c & 0xffff'ffff'ffff'ffff, c >> 64}; } // Add a u64 to a "big uint" value inplace. -// The bitint value is stored with the smallest coefficients first -// (i.e a[0] is the 2^0 coefficient, a[n] is the 2^n coefficient) +// The bigint value is stored with the smallest coefficients first +// (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 @@ -124,16 +124,16 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) { auto to_u128 = [](std::uint64_t high, std::uint64_t low) -> unsigned __int128 { - unsigned __int128 result = high; - unsigned __int128 low128 = low; - return ((result << 64) | low128); + unsigned __int128 const high128 = high; + unsigned __int128 const low128 = low; + return ((high128 << 64) | low128); }; auto div_rem_64 = [](unsigned __int128 num, std::uint64_t denom) -> std::tuple { - unsigned __int128 denom128 = denom; - unsigned __int128 d = num / denom128; - unsigned __int128 r = num % denom128; + unsigned __int128 const denom128 = denom; + unsigned __int128 const d = num / denom128; + unsigned __int128 const r = num - (denom128 * d); return {static_cast(d), static_cast(r)}; }; @@ -143,7 +143,7 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) div_rem(numerator[last_index], divisor); for (int i = last_index - 1; i >= 0; --i) { - unsigned __int128 cur_num = to_u128(prev_rem, numerator[i]); + unsigned __int128 const cur_num = to_u128(prev_rem, numerator[i]); std::tie(numerator[i], prev_rem) = div_rem_64(cur_num, divisor); } return prev_rem; @@ -151,6 +151,7 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) // convert from base 58^10 to base 58 // put largest coeffs first +// the `_be` suffix stands for "big endian" [[nodiscard]] inline std::array b58_10_to_b58_be(std::uint64_t input) { @@ -173,4 +174,4 @@ b58_10_to_b58_be(std::uint64_t input) #endif } // namespace ripple -#endif // B58_UTILS_H_ +#endif // RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED diff --git a/src/ripple/protocol/impl/token_errors.h b/src/ripple/protocol/impl/token_errors.h index e41e3b723e2..59b09974149 100644 --- a/src/ripple/protocol/impl/token_errors.h +++ b/src/ripple/protocol/impl/token_errors.h @@ -24,15 +24,15 @@ namespace ripple { enum class TokenCodecErrc { - Success = 0, - InputTooLarge, - InputTooSmall, - BadB58Character, - OutputTooSmall, - MismatchedTokenType, - MismatchedChecksum, - InvalidEncodingChar, - Unknown, + success = 0, + inputTooLarge, + inputTooSmall, + badB58Character, + outputTooSmall, + mismatchedTokenType, + mismatchedChecksum, + invalidEncodingChar, + unknown, }; } @@ -60,23 +60,23 @@ class TokenCodecErrcCategory : public std::error_category { switch (static_cast(c)) { - case TokenCodecErrc::Success: + case TokenCodecErrc::success: return "conversion successful"; - case TokenCodecErrc::InputTooLarge: + case TokenCodecErrc::inputTooLarge: return "input too large"; - case TokenCodecErrc::InputTooSmall: + case TokenCodecErrc::inputTooSmall: return "input too small"; - case TokenCodecErrc::BadB58Character: + case TokenCodecErrc::badB58Character: return "bad base 58 character"; - case TokenCodecErrc::OutputTooSmall: + case TokenCodecErrc::outputTooSmall: return "output too small"; - case TokenCodecErrc::MismatchedTokenType: + case TokenCodecErrc::mismatchedTokenType: return "mismatched token type"; - case TokenCodecErrc::MismatchedChecksum: + case TokenCodecErrc::mismatchedChecksum: return "mismatched checksum"; - case TokenCodecErrc::InvalidEncodingChar: + case TokenCodecErrc::invalidEncodingChar: return "invalid encoding char"; - case TokenCodecErrc::Unknown: + case TokenCodecErrc::unknown: return "unknown"; default: return "unknown"; diff --git a/src/ripple/protocol/impl/tokens.cpp b/src/ripple/protocol/impl/tokens.cpp index ed21ecb7d06..149d1f76799 100644 --- a/src/ripple/protocol/impl/tokens.cpp +++ b/src/ripple/protocol/impl/tokens.cpp @@ -16,6 +16,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== +// +/* The base58 encoding & decoding routines in the b58_ref namespace are taken + * from Bitcoin but have been modified from the original. + * + * Copyright (c) 2014 The Bitcoin Core developers + * Distributed under the MIT software license, see the accompanying + * file COPYING or http://www.opensource.org/licenses/mit-license.php. + */ #include @@ -264,6 +272,8 @@ decodeBase58Token(std::string const& s, TokenType type) } // namespace b58_ref #ifndef _MSC_VER +// The algorithms use gcc's int128 (fast MS version will have to wait, in the +// meantime MS falls back to the slow code) namespace b58_fast { namespace detail { B58Result> @@ -274,10 +284,11 @@ b256_to_b58(std::span input, std::span out) // log(2^(38*8),58^10)) ~= 5.18. So 6 coeff are enough if (input.size() > 38) { - return Unexpected(TokenCodecErrc::InputTooLarge); + return Unexpected(TokenCodecErrc::inputTooLarge); }; - auto count_leading_zeros = [&](auto const& col) -> std::size_t { + auto count_leading_zeros = + [](std::span const& col) -> std::size_t { std::size_t count = 0; for (auto const& c : col) { @@ -293,15 +304,14 @@ b256_to_b58(std::span input, std::span out) auto const input_zeros = count_leading_zeros(input); input = input.subspan(input_zeros); - std::array base_58_10_coeff{}; std::array base_2_64_coeff_buf{}; std::span const base_2_64_coeff = [&]() -> std::span { - // convert from input from big endian to native u64, lowest coeff first + // convert input from big endian to native u64, lowest coeff first std::size_t num_coeff = 0; - for (int i = 0; i < 5; ++i) + for (int i = 0; i < base_2_64_coeff_buf.size(); ++i) { - if (i * 8 > input.size()) + if (i * 8 >= input.size()) { break; } @@ -328,6 +338,7 @@ b256_to_b58(std::span input, std::span out) return std::span(base_2_64_coeff_buf.data(), num_coeff); }(); + std::array base_58_10_coeff{}; constexpr std::uint64_t B_58_10 = 430804206899405824; // 58^10; std::size_t num_58_10_coeffs = 0; std::size_t cur_2_64_end = base_2_64_coeff.size(); @@ -360,7 +371,7 @@ b256_to_b58(std::span input, std::span out) { continue; } - auto const b58_be = + 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; std::span b58_be_s{b58_be.data(), b58_be.size()}; @@ -370,7 +381,7 @@ b256_to_b58(std::span input, std::span out) skip_zeros = false; if (out.size() < (i + 1) * 10 - to_skip) { - return Unexpected(TokenCodecErrc::OutputTooSmall); + return Unexpected(TokenCodecErrc::outputTooSmall); } } for (auto b58_coeff : b58_be_s.subspan(to_skip)) @@ -394,11 +405,11 @@ b58_to_b256(std::string_view input, std::span out) // log(2^(38*8),58) ~= 51.9 if (input.size() > 52) { - return Unexpected(TokenCodecErrc::InputTooLarge); + return Unexpected(TokenCodecErrc::inputTooLarge); }; if (out.size() < 8) { - return Unexpected(TokenCodecErrc::OutputTooSmall); + return Unexpected(TokenCodecErrc::outputTooSmall); } auto count_leading_zeros = [&](auto const& col) -> std::size_t { @@ -430,7 +441,7 @@ b58_to_b256(std::string_view input, std::span out) auto cur_val = ::ripple::alphabetReverse[c]; if (cur_val < 0) { - return Unexpected(TokenCodecErrc::InvalidEncodingChar); + return Unexpected(TokenCodecErrc::invalidEncodingChar); } b_58_10_coeff[0] *= 58; b_58_10_coeff[0] += cur_val; @@ -443,7 +454,7 @@ b58_to_b256(std::string_view input, std::span out) auto cur_val = ::ripple::alphabetReverse[c]; if (cur_val < 0) { - return Unexpected(TokenCodecErrc::InvalidEncodingChar); + return Unexpected(TokenCodecErrc::invalidEncodingChar); } b_58_10_coeff[num_partial_coeffs + j] *= 58; b_58_10_coeff[num_partial_coeffs + j] += cur_val; @@ -458,7 +469,7 @@ b58_to_b256(std::string_view input, std::span out) std::size_t cur_result_size = 1; for (int i = 1; i < num_b_58_10_coeffs; ++i) { - auto c = b_58_10_coeff[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( @@ -493,7 +504,7 @@ b58_to_b256(std::string_view input, std::span out) } if ((cur_out_i + 8 * (cur_result_size - 1)) > out.size()) { - return Unexpected(TokenCodecErrc::OutputTooSmall); + return Unexpected(TokenCodecErrc::outputTooSmall); } for (int i = cur_result_size - 2; i >= 0; --i) @@ -518,11 +529,11 @@ encodeBase58Token( std::array buf; if (input.size() > tmpBufSize - 5) { - return Unexpected(TokenCodecErrc::InputTooLarge); + return Unexpected(TokenCodecErrc::inputTooLarge); } if (input.size() == 0) { - return Unexpected(TokenCodecErrc::InputTooSmall); + return Unexpected(TokenCodecErrc::inputTooSmall); } // buf[0] = static_cast(token_type); @@ -556,23 +567,23 @@ decodeBase58Token( // Reject zero length tokens if (ret.size() < 6) - return Unexpected(TokenCodecErrc::InputTooSmall); + return Unexpected(TokenCodecErrc::inputTooSmall); // The type must match. if (type != static_cast(static_cast(ret[0]))) - return Unexpected(TokenCodecErrc::MismatchedTokenType); + return Unexpected(TokenCodecErrc::mismatchedTokenType); // And the checksum must as well. std::array guard; checksum(guard.data(), ret.data(), ret.size() - guard.size()); if (!std::equal(guard.rbegin(), guard.rend(), ret.rbegin())) { - return Unexpected(TokenCodecErrc::MismatchedChecksum); + return Unexpected(TokenCodecErrc::mismatchedChecksum); } std::size_t const outSize = ret.size() - 1 - guard.size(); if (outBuf.size() < outSize) - return Unexpected(TokenCodecErrc::OutputTooSmall); + return Unexpected(TokenCodecErrc::outputTooSmall); // Skip the leading type byte and the trailing checksum. std::copy(ret.begin() + 1, ret.begin() + outSize + 1, outBuf.begin()); return outBuf.subspan(0, outSize); diff --git a/src/ripple/protocol/tokens.h b/src/ripple/protocol/tokens.h index d2a60af1379..3af856c1f33 100644 --- a/src/ripple/protocol/tokens.h +++ b/src/ripple/protocol/tokens.h @@ -72,7 +72,7 @@ encodeBase58Token(TokenType type, void const* token, std::size_t size); decodeBase58Token(std::string const& s, TokenType type); namespace b58_ref { -// Use the reference version is not using gcc extensions (int128 in particular) +// The reference version does not use gcc extensions (int128 in particular) [[nodiscard]] std::string encodeBase58Token(TokenType type, void const* token, std::size_t size); diff --git a/src/test/basics/base58_test.cpp b/src/test/basics/base58_test.cpp index 4f6c5a66f0c..086bc053dbb 100644 --- a/src/test/basics/base58_test.cpp +++ b/src/test/basics/base58_test.cpp @@ -75,8 +75,9 @@ tokenTypeAndSize(int i) -> std::tuple case 8: return {FamilySeed, 16}; default: - assert(0); - return {AccountPublic, 33}; + throw std::invalid_argument( + "Invalid token selection passed to tokenTypeAndSize() " + "in " __FILE__); } } @@ -101,7 +102,7 @@ randomB256TestData(std::span d) return {tokType, d.subspan(0, tokSize)}; } -inline auto +inline void printAsChar(std::span a, std::span b) { auto asString = [](std::span s) { @@ -115,7 +116,7 @@ printAsChar(std::span a, std::span b) std::cerr << "\n\n" << sa << "\n" << sb << "\n"; } -inline auto +inline void printAsInt(std::span a, std::span b) { auto asString = [](std::span s) -> std::string { @@ -171,11 +172,9 @@ class base58_test : public beast::unit_test::suite { testcase("b58_multiprecision"); - // Generate a random boost multiprecision - // Import the bytes into using namespace boost::multiprecision; - constexpr std::size_t iters = 1000000; + constexpr std::size_t iters = 100000; auto eng = randEngine(); std::uniform_int_distribution dist; for (int i = 0; i < iters; ++i) @@ -246,8 +245,8 @@ class base58_test : public beast::unit_test::suite std::array, 2> b256Result; for (int i = 0; i < 2; ++i) { - auto const outBuf = - std::span(b58ResultBuf[i].data(), b58ResultBuf[i].size()); + std::span const outBuf{ + b58ResultBuf[i].data(), b58ResultBuf[i].size()}; if (i == 0) { auto const r = @@ -282,8 +281,8 @@ class base58_test : public beast::unit_test::suite for (int i = 0; i < 2; ++i) { - auto const outBuf = - std::span(b256ResultBuf[i].data(), b256ResultBuf[i].size()); + std::span const outBuf{ + b256ResultBuf[i].data(), b256ResultBuf[i].size()}; if (i == 0) { std::string const in( @@ -338,7 +337,7 @@ class base58_test : public beast::unit_test::suite } else { - auto const s = ripple::b58_ref::encodeBase58Token( + std::string const s = ripple::b58_ref::encodeBase58Token( tokType, b256Data.data(), b256Data.size()); BEAST_EXPECT(s.size()); b58Result[i] = outBuf.subspan(0, s.size()); @@ -359,8 +358,8 @@ class base58_test : public beast::unit_test::suite for (int i = 0; i < 2; ++i) { - auto const outBuf = - std::span(b256ResultBuf[i].data(), b256ResultBuf[i].size()); + std::span const outBuf{ + b256ResultBuf[i].data(), b256ResultBuf[i].size()}; if (i == 0) { std::string const in( @@ -416,7 +415,7 @@ class base58_test : public beast::unit_test::suite } // test with random data - constexpr std::size_t iters = 1000000; + constexpr std::size_t iters = 100000; for (int i = 0; i < iters; ++i) { std::array b256DataBuf; @@ -438,4 +437,4 @@ BEAST_DEFINE_TESTSUITE(base58, ripple_basics, ripple); } // namespace test } // namespace ripple -#endif +#endif // _MSC_VER