diff --git a/Libraries/LibCrypto/BigFraction/BigFraction.cpp b/Libraries/LibCrypto/BigFraction/BigFraction.cpp index 81b091d972a..69b32094c90 100644 --- a/Libraries/LibCrypto/BigFraction/BigFraction.cpp +++ b/Libraries/LibCrypto/BigFraction/BigFraction.cpp @@ -5,12 +5,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include "BigFraction.h" #include #include #include +#include #include -#include namespace Crypto { @@ -36,12 +35,11 @@ ErrorOr BigFraction::from_string(StringView sv) 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())); if (!sv.is_empty() && sv[0] == '-') fractional_part.negate(); - return BigFraction(move(integer_part)) + BigFraction(move(fractional_part), NumberTheory::Power("10"_bigint, move(fraction_length))); + return BigFraction(move(integer_part)) + BigFraction(move(fractional_part), "10"_bigint.pow(fraction_part_view.length())); } BigFraction BigFraction::operator+(BigFraction const& rhs) const @@ -129,7 +127,7 @@ BigFraction::BigFraction(double d) d -= digit * AK::pow(10.0, (double)current_pow); if (current_pow < 0) { ++decimal_places; - m_denominator.set_to(NumberTheory::Power("10"_bigint, UnsignedBigInteger { decimal_places })); + m_denominator.set_to("10"_bigint.pow(decimal_places)); } current_pow -= 1; } @@ -205,7 +203,7 @@ BigFraction BigFraction::rounded(unsigned rounding_threshold) const auto res = m_numerator.divided_by(m_denominator); BigFraction result { move(res.quotient) }; - auto const needed_power = NumberTheory::Power("10"_bigint, UnsignedBigInteger { rounding_threshold }); + auto const needed_power = "10"_bigint.pow(rounding_threshold); // We get one more digit to do proper rounding auto const fractional_value = res.remainder.multiplied_by(needed_power.multiplied_by("10"_bigint)).divided_by(m_denominator).quotient; diff --git a/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp b/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp index d366bd34bd1..589cfa9de8b 100644 --- a/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp +++ b/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp @@ -314,6 +314,26 @@ FLATTEN SignedDivisionResult SignedBigInteger::divided_by(SignedBigInteger const }; } +FLATTEN SignedBigInteger SignedBigInteger::pow(u32 exponent) const +{ + UnsignedBigInteger ep { exponent }; + SignedBigInteger base { *this }; + SignedBigInteger exp { 1 }; + + while (!(ep < 1)) { + if (ep.words()[0] % 2 == 1) + exp.set_to(exp.multiplied_by(base)); + + // ep = ep / 2; + ep.set_to(ep.shift_right(1)); + + // base = base * base + base.set_to(base.multiplied_by(base)); + } + + return exp; +} + FLATTEN SignedBigInteger SignedBigInteger::negated_value() const { auto result { *this }; diff --git a/Libraries/LibCrypto/BigInt/SignedBigInteger.h b/Libraries/LibCrypto/BigInt/SignedBigInteger.h index a8707d02ea7..bd036418d11 100644 --- a/Libraries/LibCrypto/BigInt/SignedBigInteger.h +++ b/Libraries/LibCrypto/BigInt/SignedBigInteger.h @@ -106,6 +106,7 @@ public: [[nodiscard]] SignedBigInteger shift_right(size_t num_bits) const; [[nodiscard]] SignedBigInteger multiplied_by(SignedBigInteger const& other) const; [[nodiscard]] SignedDivisionResult divided_by(SignedBigInteger const& divisor) const; + [[nodiscard]] SignedBigInteger pow(u32 exponent) const; [[nodiscard]] ErrorOr mod_power_of_two(size_t power_of_two) const; [[nodiscard]] ErrorOr try_shift_left(size_t num_bits) const; diff --git a/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp b/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp index aed8850487e..7a8f6818dcf 100644 --- a/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp +++ b/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp @@ -547,6 +547,26 @@ FLATTEN UnsignedDivisionResult UnsignedBigInteger::divided_by(UnsignedBigInteger return UnsignedDivisionResult { quotient, remainder }; } +FLATTEN UnsignedBigInteger UnsignedBigInteger::pow(u32 exponent) const +{ + UnsignedBigInteger ep { exponent }; + UnsignedBigInteger base { *this }; + UnsignedBigInteger exp { 1 }; + + while (!(ep < 1 )) { + if (ep.words()[0] % 2 == 1) + exp.set_to(exp.multiplied_by(base)); + + // ep = ep / 2; + ep.set_to(ep.shift_right(1)); + + // base = base * base + base.set_to(base.multiplied_by(base)); + } + + return exp; +} + FLATTEN UnsignedBigInteger UnsignedBigInteger::gcd(UnsignedBigInteger const& other) const { UnsignedBigInteger temp_a { *this }; diff --git a/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h b/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h index f626fc93efc..e4d63dedbfc 100644 --- a/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h +++ b/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h @@ -109,6 +109,7 @@ public: [[nodiscard]] UnsignedBigInteger as_n_bits(size_t n) const; [[nodiscard]] UnsignedBigInteger multiplied_by(UnsignedBigInteger const& other) const; [[nodiscard]] UnsignedDivisionResult divided_by(UnsignedBigInteger const& divisor) const; + [[nodiscard]] UnsignedBigInteger pow(u32 exponent) const; [[nodiscard]] UnsignedBigInteger gcd(UnsignedBigInteger const& other) const; [[nodiscard]] ErrorOr try_bitwise_not_fill_to_one_based_index(size_t) const; diff --git a/Libraries/LibCrypto/NumberTheory/ModularFunctions.h b/Libraries/LibCrypto/NumberTheory/ModularFunctions.h deleted file mode 100644 index 7a2e0924fc7..00000000000 --- a/Libraries/LibCrypto/NumberTheory/ModularFunctions.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2020, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace Crypto::NumberTheory { - -// Note: This function _will_ generate extremely huge numbers, and in doing so, -// it will allocate and free a lot of memory! -// Please use |ModularPower| if your use-case is modexp. -template -static IntegerType Power(IntegerType const& b, IntegerType const& e) -{ - IntegerType ep { e }; - IntegerType base { b }; - IntegerType exp { 1 }; - - while (!(ep < IntegerType { 1 })) { - if (ep.words()[0] % 2 == 1) - exp.set_to(exp.multiplied_by(base)); - - // ep = ep / 2; - ep.set_to(ep.shift_right(1)); - - // base = base * base - base.set_to(base.multiplied_by(base)); - } - - return exp; -} - -} diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index 1e22c9fd003..95c985f8bc7 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -1599,7 +1598,7 @@ ThrowCompletionOr left_shift(VM& vm, Value lhs, Value rhs) return vm.throw_completion(ErrorType::BigIntSizeExceeded); // 6.1.6.2.9 BigInt::leftShift ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-leftShift - auto multiplier_divisor = Crypto::SignedBigInteger { Crypto::NumberTheory::Power(Crypto::UnsignedBigInteger(2), rhs_bigint) }; + auto multiplier_divisor = Crypto::SignedBigInteger { Crypto::UnsignedBigInteger(2).pow(rhs_bigint.to_u64()) }; // 1. If y < 0ℤ, then if (rhs_numeric.as_bigint().big_integer().is_negative()) { @@ -2075,9 +2074,14 @@ ThrowCompletionOr exp(VM& vm, Value lhs, Value rhs) // 1. If exponent < 0ℤ, throw a RangeError exception. if (exponent.is_negative()) return vm.throw_completion(ErrorType::NegativeExponent); + + // AD-HOC: Prevent allocating huge amounts of memory. + if (exponent.unsigned_value().byte_length() > sizeof(u32)) + return vm.throw_completion(ErrorType::BigIntSizeExceeded); + // 2. If base is 0ℤ and exponent is 0ℤ, return 1ℤ. // 3. Return the BigInt value that represents ℝ(base) raised to the power ℝ(exponent). - return BigInt::create(vm, Crypto::NumberTheory::Power(base, exponent)); + return BigInt::create(vm, base.pow(exponent.to_u64())); } return vm.throw_completion(ErrorType::BigIntBadOperatorOtherType, "exponentiation"); }