diff --git a/Tests/LibCrypto/TestBigInteger.cpp b/Tests/LibCrypto/TestBigInteger.cpp index 92e3e03194..25ff9ad0ec 100644 --- a/Tests/LibCrypto/TestBigInteger.cpp +++ b/Tests/LibCrypto/TestBigInteger.cpp @@ -234,9 +234,13 @@ TEST_CASE(test_unsigned_bigint_division_combined_test) TEST_CASE(test_unsigned_bigint_base10_from_string) { - auto result = Crypto::UnsignedBigInteger::from_base(10, "57195071295721390579057195715793"sv); + auto result = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(10, "57195071295721390579057195715793"sv)); Vector expected_result { 3806301393, 954919431, 3879607298, 721 }; EXPECT_EQ(result.words(), expected_result); + + Vector invalid_base10_number_strings { "1A"sv, "1:"sv, "Z1"sv, "1/"sv }; + for (auto invalid_base10_number_string : invalid_base10_number_strings) + EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(10, invalid_base10_number_string).is_error(), true); } TEST_CASE(test_unsigned_bigint_base10_to_string) @@ -701,11 +705,11 @@ EXPECT_EQUAL_TO(zero, -0.0); double double_below_max_value = nextafter(double_max_value, 0.0); VERIFY(double_below_max_value < double_max_value); VERIFY(double_below_max_value < (double_max_value - 1.0)); - auto max_value_in_bigint = Crypto::SignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv); + auto max_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); auto max_value_plus_one = max_value_in_bigint.plus(Crypto::SignedBigInteger { 1 }); auto max_value_minus_one = max_value_in_bigint.minus(Crypto::SignedBigInteger { 1 }); - auto below_max_value_in_bigint = Crypto::SignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv); + auto below_max_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); EXPECT_EQUAL_TO(max_value_in_bigint, double_max_value); EXPECT_LESS_THAN(max_value_minus_one, double_max_value); @@ -723,11 +727,11 @@ EXPECT_EQUAL_TO(zero, -0.0); double double_above_min_value = nextafter(double_min_value, 0.0); VERIFY(double_above_min_value > double_min_value); VERIFY(double_above_min_value > (double_min_value + 1.0)); - auto min_value_in_bigint = Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv); + auto min_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); auto min_value_plus_one = min_value_in_bigint.plus(Crypto::SignedBigInteger { 1 }); auto min_value_minus_one = min_value_in_bigint.minus(Crypto::SignedBigInteger { 1 }); - auto above_min_value_in_bigint = Crypto::SignedBigInteger::from_base(16, "-fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv); + auto above_min_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); EXPECT_EQUAL_TO(min_value_in_bigint, double_min_value); EXPECT_LESS_THAN(min_value_minus_one, double_min_value); @@ -785,89 +789,89 @@ TEST_CASE(to_double) double infinity = INFINITY; EXPECT_TO_EQUAL_DOUBLE( - Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), double_max_value); EXPECT_TO_EQUAL_DOUBLE( - Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), double_max_value); EXPECT_TO_EQUAL_DOUBLE( - Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv)), double_max_value); EXPECT_TO_EQUAL_DOUBLE( - Crypto::UnsignedBigInteger::from_base(16, "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), infinity); EXPECT_TO_EQUAL_DOUBLE( - Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv), + TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), -double_max_value); EXPECT_TO_EQUAL_DOUBLE( - Crypto::SignedBigInteger::from_base(16, "-ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv), + TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), -double_max_value); EXPECT_TO_EQUAL_DOUBLE( - Crypto::SignedBigInteger::from_base(16, "-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv), + TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv)), -double_max_value); EXPECT_TO_EQUAL_DOUBLE( - Crypto::SignedBigInteger::from_base(16, "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv), + TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), -infinity); EXPECT_TO_EQUAL_DOUBLE( - Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffff"sv), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffff"sv)), 18446744073709549568.0); EXPECT_TO_EQUAL_DOUBLE( - Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800"sv), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800"sv)), 18446744073709549568.0); EXPECT_TO_EQUAL_DOUBLE( - Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff8ff"sv), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff8ff"sv)), 18446744073709549568.0); - EXPECT_TO_EQUAL_DOUBLE(Crypto::SignedBigInteger::from_base(10, "1234567890123456789"sv), + EXPECT_TO_EQUAL_DOUBLE(TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(10, "1234567890123456789"sv)), 1234567890123456800.0); - EXPECT_TO_EQUAL_DOUBLE(Crypto::SignedBigInteger::from_base(10, "2345678901234567890"sv), + EXPECT_TO_EQUAL_DOUBLE(TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(10, "2345678901234567890"sv)), 2345678901234567680.0); EXPECT_EQ( - Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 2305843009213693696.0); EXPECT_EQ( - Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::RoundTowardZero), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::RoundTowardZero), 2305843009213693696.0); EXPECT_EQ( - Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff80"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), + TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff80"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 2305843009213693952.0); - EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000001"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), + EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000001"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740992.0); - EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000002"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), + EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000002"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740994.0); // 2^53 = 20000000000000, +3 Rounds up because of tiesRoundToEven - EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000003"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), + EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000003"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740996.0); // +4 is exactly 9007199254740996 - EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000004"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), + EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000004"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740996.0); // +5 rounds down because of tiesRoundToEven - EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000005"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), + EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000005"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740996.0); - EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(16, "20000000000006"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), + EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000006"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740998.0); - EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(10, "98382635059784269824"sv).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), + EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(10, "98382635059784269824"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), bit_cast(0x4415555555555555ULL)); #undef EXPECT_TO_EQUAL_DOUBLE @@ -982,11 +986,11 @@ TEST_CASE(unsigned_bigint_double_comparisons) double double_below_max_value = nextafter(double_max_value, 0.0); VERIFY(double_below_max_value < double_max_value); VERIFY(double_below_max_value < (double_max_value - 1.0)); - auto max_value_in_bigint = Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv); + auto max_value_in_bigint = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); auto max_value_plus_one = max_value_in_bigint.plus(Crypto::UnsignedBigInteger { 1 }); auto max_value_minus_one = max_value_in_bigint.minus(Crypto::UnsignedBigInteger { 1 }); - auto below_max_value_in_bigint = Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv); + auto below_max_value_in_bigint = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); EXPECT_EQUAL_TO(max_value_in_bigint, double_max_value); EXPECT_LESS_THAN(max_value_minus_one, double_max_value); diff --git a/Userland/Applications/Calculator/main.cpp b/Userland/Applications/Calculator/main.cpp index 246ea6acb4..1796f767f9 100644 --- a/Userland/Applications/Calculator/main.cpp +++ b/Userland/Applications/Calculator/main.cpp @@ -59,8 +59,9 @@ ErrorOr serenity_main(Main::Arguments arguments) auto clipboard = GUI::Clipboard::the().fetch_data_and_type(); if (clipboard.mime_type == "text/plain") { if (!clipboard.data.is_empty()) { - auto const number = StringView(clipboard.data); - widget->set_typed_entry(Crypto::BigFraction(number)); + auto number_or_error = Crypto::BigFraction::from_string(StringView(clipboard.data)); + if (!number_or_error.is_error()) + widget->set_typed_entry(number_or_error.release_value()); } } })); diff --git a/Userland/Libraries/LibCrypto/BigFraction/BigFraction.cpp b/Userland/Libraries/LibCrypto/BigFraction/BigFraction.cpp index 97c2382def..40c6972682 100644 --- a/Userland/Libraries/LibCrypto/BigFraction/BigFraction.cpp +++ b/Userland/Libraries/LibCrypto/BigFraction/BigFraction.cpp @@ -25,20 +25,18 @@ BigFraction::BigFraction(SignedBigInteger value) { } -BigFraction::BigFraction(StringView sv) +ErrorOr BigFraction::from_string(StringView sv) { - // FIXME: This constructor is definitely fallible, errors should also be propagated - // from both signed and unsigned version of from_base. auto maybe_dot_index = sv.find('.'); auto integer_part_view = sv.substring_view(0, maybe_dot_index.value_or(sv.length())); auto fraction_part_view = maybe_dot_index.has_value() ? sv.substring_view(1 + *maybe_dot_index) : "0"sv; - auto integer_part = SignedBigInteger::from_base(10, integer_part_view); - auto fractional_part = SignedBigInteger::from_base(10, fraction_part_view); + auto integer_part = TRY(SignedBigInteger::from_base(10, integer_part_view)); + auto fractional_part = TRY(SignedBigInteger::from_base(10, fraction_part_view)); auto fraction_length = UnsignedBigInteger(static_cast(fraction_part_view.length())); - *this = BigFraction(move(integer_part)) + BigFraction(move(fractional_part), NumberTheory::Power("10"_bigint, move(fraction_length))); + return BigFraction(move(integer_part)) + BigFraction(move(fractional_part), NumberTheory::Power("10"_bigint, move(fraction_length))); } BigFraction BigFraction::operator+(BigFraction const& rhs) const diff --git a/Userland/Libraries/LibCrypto/BigFraction/BigFraction.h b/Userland/Libraries/LibCrypto/BigFraction/BigFraction.h index 682fe9431d..aaa18a85c2 100644 --- a/Userland/Libraries/LibCrypto/BigFraction/BigFraction.h +++ b/Userland/Libraries/LibCrypto/BigFraction/BigFraction.h @@ -14,7 +14,7 @@ namespace Crypto { class BigFraction { // FIXME Make the whole API more error-friendly. This includes: // - Propagating errors from BigIntegers - // - Returns errors from both BigFraction(StringView) and BigFraction(numerator, denominator); + // - Returns errors from BigFraction(numerator, denominator); // - Duplicate fallible operators with a error-friendly version public: @@ -27,9 +27,10 @@ public: BigFraction& operator=(Crypto::BigFraction const&) = default; BigFraction& operator=(Crypto::BigFraction&&) = default; - explicit BigFraction(StringView); explicit BigFraction(double); + static ErrorOr from_string(StringView); + BigFraction operator+(BigFraction const&) const; BigFraction operator-(BigFraction const&) const; BigFraction operator*(BigFraction const&) const; diff --git a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp index 1aca97dfc3..14b70a8c39 100644 --- a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp +++ b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp @@ -35,7 +35,7 @@ size_t SignedBigInteger::export_data(Bytes data, bool remove_leading_zeros) cons return m_unsigned_data.export_data(bytes_view, remove_leading_zeros) + 1; } -SignedBigInteger SignedBigInteger::from_base(u16 N, StringView str) +ErrorOr SignedBigInteger::from_base(u16 N, StringView str) { auto sign = false; if (str.length() > 1) { @@ -47,8 +47,8 @@ SignedBigInteger SignedBigInteger::from_base(u16 N, StringView str) if (maybe_sign == '+') str = str.substring_view(1); } - auto unsigned_data = UnsignedBigInteger::from_base(N, str); - return { move(unsigned_data), sign }; + auto unsigned_data = TRY(UnsignedBigInteger::from_base(N, str)); + return SignedBigInteger { move(unsigned_data), sign }; } ErrorOr SignedBigInteger::to_base(u16 N) const diff --git a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h index f6100d8bc5..532bc7ed46 100644 --- a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h +++ b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.h @@ -63,7 +63,7 @@ public: size_t export_data(Bytes, bool remove_leading_zeros = false) const; - [[nodiscard]] static SignedBigInteger from_base(u16 N, StringView str); + [[nodiscard]] static ErrorOr from_base(u16 N, StringView str); [[nodiscard]] ErrorOr to_base(u16 N) const; [[nodiscard]] ByteString to_base_deprecated(u16 N) const; @@ -171,5 +171,5 @@ struct AK::Formatter : AK::Formatter UnsignedBigInteger::from_base(u16 N, StringView str) { VERIFY(N <= 36); UnsignedBigInteger result; UnsignedBigInteger base { N }; - for (auto& c : str) { + for (auto const& c : str) { if (c == '_') continue; - result = result.multiplied_by(base).plus(parse_ascii_base36_digit(c)); + if (!is_ascii_base36_digit(c)) + return Error::from_string_literal("Invalid Base36 digit"); + auto digit = parse_ascii_base36_digit(c); + if (digit >= N) + return Error::from_string_literal("Base36 digit out of range"); + + result = result.multiplied_by(base).plus(digit); } return result; } diff --git a/Userland/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h b/Userland/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h index 2df4652ec5..ac817f7a93 100644 --- a/Userland/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h +++ b/Userland/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h @@ -63,7 +63,7 @@ public: size_t export_data(Bytes, bool remove_leading_zeros = false) const; - [[nodiscard]] static UnsignedBigInteger from_base(u16 N, StringView str); + [[nodiscard]] static ErrorOr from_base(u16 N, StringView str); [[nodiscard]] ErrorOr to_base(u16 N) const; [[nodiscard]] ByteString to_base_deprecated(u16 N) const; @@ -161,5 +161,5 @@ struct AK::Formatter : Formatter { inline Crypto::UnsignedBigInteger operator""_bigint(char const* string, size_t length) { - return Crypto::UnsignedBigInteger::from_base(10, { string, length }); + return MUST(Crypto::UnsignedBigInteger::from_base(10, { string, length })); } diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 6706599c69..db4b5da00c 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -273,12 +273,12 @@ Bytecode::CodeGenerationErrorOr BigIntLiteral::generate_bytecode(Bytecode: auto integer = [&] { if (m_value[0] == '0' && m_value.length() >= 3) if (m_value[1] == 'x' || m_value[1] == 'X') - return Crypto::SignedBigInteger::from_base(16, m_value.substring(2, m_value.length() - 3)); + return MUST(Crypto::SignedBigInteger::from_base(16, m_value.substring(2, m_value.length() - 3))); if (m_value[1] == 'o' || m_value[1] == 'O') - return Crypto::SignedBigInteger::from_base(8, m_value.substring(2, m_value.length() - 3)); + return MUST(Crypto::SignedBigInteger::from_base(8, m_value.substring(2, m_value.length() - 3))); if (m_value[1] == 'b' || m_value[1] == 'B') - return Crypto::SignedBigInteger::from_base(2, m_value.substring(2, m_value.length() - 3)); - return Crypto::SignedBigInteger::from_base(10, m_value.substring(0, m_value.length() - 1)); + return MUST(Crypto::SignedBigInteger::from_base(2, m_value.substring(2, m_value.length() - 3))); + return MUST(Crypto::SignedBigInteger::from_base(10, m_value.substring(0, m_value.length() - 1))); }(); generator.emit(integer); diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index 7046483ead..077d7b4254 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -673,7 +673,7 @@ double string_to_number(StringView string) // 4. Return StringNumericValue of literal. if (result->base != 10) { - auto bigint = Crypto::UnsignedBigInteger::from_base(result->base, result->literal); + auto bigint = MUST(Crypto::UnsignedBigInteger::from_base(result->base, result->literal)); return bigint.to_double(); } @@ -842,7 +842,7 @@ static Optional string_to_bigint(VM& vm, StringView string) // 4. Let mv be the MV of literal. // 5. Assert: mv is an integer. - auto bigint = Crypto::SignedBigInteger::from_base(result->base, result->literal); + auto bigint = MUST(Crypto::SignedBigInteger::from_base(result->base, result->literal)); if (result->is_negative && (bigint != BIGINT_ZERO)) bigint.negate(); diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp index 4febb9e293..ca1d70021d 100644 --- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp +++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp @@ -936,7 +936,8 @@ private: auto string_view = TRY(Bindings::throw_dom_exception_if_needed(vm, [&string]() { return string->utf8_string_view(); })); - return JS::BigInt::create(vm, ::Crypto::SignedBigInteger::from_base(10, string_view.substring_view(0, string_view.length() - 1))); + auto bigint = MUST(::Crypto::SignedBigInteger::from_base(10, string_view.substring_view(0, string_view.length() - 1))); + return JS::BigInt::create(vm, bigint); } };