mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibCrypto: Remove the concept of invalid big integers
This concept is rarely used in codebase and very much error-prone if you forget to check it. Instead, make it so that operations that would produce invalid integers return an error instead.
This commit is contained in:
parent
14387e5411
commit
5f1a30197c
Notes:
github-actions[bot]
2025-04-28 10:06:55 +00:00
Author: https://github.com/devgianlu
Commit: 5f1a30197c
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4482
Reviewed-by: https://github.com/gmta ✅
12 changed files with 34 additions and 109 deletions
|
@ -23,16 +23,6 @@ FLATTEN void UnsignedBigIntegerAlgorithms::bitwise_or_without_allocation(
|
||||||
UnsignedBigInteger const& right,
|
UnsignedBigInteger const& right,
|
||||||
UnsignedBigInteger& output)
|
UnsignedBigInteger& output)
|
||||||
{
|
{
|
||||||
// If either of the BigInts are invalid, the output is just the other one.
|
|
||||||
if (left.is_invalid()) {
|
|
||||||
output.set_to(right);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (right.is_invalid()) {
|
|
||||||
output.set_to(left);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnsignedBigInteger const *shorter, *longer;
|
UnsignedBigInteger const *shorter, *longer;
|
||||||
if (left.length() < right.length()) {
|
if (left.length() < right.length()) {
|
||||||
shorter = &left;
|
shorter = &left;
|
||||||
|
@ -62,16 +52,6 @@ FLATTEN void UnsignedBigIntegerAlgorithms::bitwise_and_without_allocation(
|
||||||
UnsignedBigInteger const& right,
|
UnsignedBigInteger const& right,
|
||||||
UnsignedBigInteger& output)
|
UnsignedBigInteger& output)
|
||||||
{
|
{
|
||||||
// If either of the BigInts are invalid, the output is just the other one.
|
|
||||||
if (left.is_invalid()) {
|
|
||||||
output.set_to(right);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (right.is_invalid()) {
|
|
||||||
output.set_to(left);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnsignedBigInteger const *shorter, *longer;
|
UnsignedBigInteger const *shorter, *longer;
|
||||||
if (left.length() < right.length()) {
|
if (left.length() < right.length()) {
|
||||||
shorter = &left;
|
shorter = &left;
|
||||||
|
@ -101,16 +81,6 @@ FLATTEN void UnsignedBigIntegerAlgorithms::bitwise_xor_without_allocation(
|
||||||
UnsignedBigInteger const& right,
|
UnsignedBigInteger const& right,
|
||||||
UnsignedBigInteger& output)
|
UnsignedBigInteger& output)
|
||||||
{
|
{
|
||||||
// If either of the BigInts are invalid, the output is just the other one.
|
|
||||||
if (left.is_invalid()) {
|
|
||||||
output.set_to(right);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (right.is_invalid()) {
|
|
||||||
output.set_to(left);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnsignedBigInteger const *shorter, *longer;
|
UnsignedBigInteger const *shorter, *longer;
|
||||||
if (left.length() < right.length()) {
|
if (left.length() < right.length()) {
|
||||||
shorter = &left;
|
shorter = &left;
|
||||||
|
@ -137,12 +107,6 @@ FLATTEN ErrorOr<void> UnsignedBigIntegerAlgorithms::bitwise_not_fill_to_one_base
|
||||||
size_t index,
|
size_t index,
|
||||||
UnsignedBigInteger& output)
|
UnsignedBigInteger& output)
|
||||||
{
|
{
|
||||||
// If the value is invalid, the output value is invalid as well.
|
|
||||||
if (right.is_invalid()) {
|
|
||||||
output.invalidate();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
output.set_to_0();
|
output.set_to_0();
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -68,7 +68,7 @@ void UnsignedBigIntegerAlgorithms::extended_GCD_without_allocation(
|
||||||
while (gcd < temp_1) {
|
while (gcd < temp_1) {
|
||||||
add_into_accumulator_without_allocation(gcd, b);
|
add_into_accumulator_without_allocation(gcd, b);
|
||||||
}
|
}
|
||||||
subtract_without_allocation(gcd, temp_1, temp_r);
|
MUST(subtract_without_allocation(gcd, temp_1, temp_r));
|
||||||
gcd.set_to(temp_2);
|
gcd.set_to(temp_2);
|
||||||
|
|
||||||
// (old_s, s) := (s, old_s − quotient × s)
|
// (old_s, s) := (s, old_s − quotient × s)
|
||||||
|
@ -77,7 +77,7 @@ void UnsignedBigIntegerAlgorithms::extended_GCD_without_allocation(
|
||||||
while (x < temp_1) {
|
while (x < temp_1) {
|
||||||
add_into_accumulator_without_allocation(x, b);
|
add_into_accumulator_without_allocation(x, b);
|
||||||
}
|
}
|
||||||
subtract_without_allocation(x, temp_1, temp_s);
|
MUST(subtract_without_allocation(x, temp_1, temp_s));
|
||||||
x.set_to(temp_2);
|
x.set_to(temp_2);
|
||||||
|
|
||||||
// (old_t, t) := (t, old_t − quotient × t)
|
// (old_t, t) := (t, old_t − quotient × t)
|
||||||
|
@ -86,7 +86,7 @@ void UnsignedBigIntegerAlgorithms::extended_GCD_without_allocation(
|
||||||
while (y < temp_1) {
|
while (y < temp_1) {
|
||||||
add_into_accumulator_without_allocation(y, b);
|
add_into_accumulator_without_allocation(y, b);
|
||||||
}
|
}
|
||||||
subtract_without_allocation(y, temp_1, temp_t);
|
MUST(subtract_without_allocation(y, temp_1, temp_t));
|
||||||
y.set_to(temp_2);
|
y.set_to(temp_2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ void UnsignedBigIntegerAlgorithms::montgomery_modular_power_with_minimal_allocat
|
||||||
// Note : Since we were using "almost montgomery" multiplications, we aren't guaranteed to be under the modulo already.
|
// Note : Since we were using "almost montgomery" multiplications, we aren't guaranteed to be under the modulo already.
|
||||||
// So, if we're here, we need to respect the modulo.
|
// So, if we're here, we need to respect the modulo.
|
||||||
// We can, however, start by trying to subtract the modulo, just in case we're close.
|
// We can, however, start by trying to subtract the modulo, just in case we're close.
|
||||||
subtract_without_allocation(zz, modulo, result);
|
MUST(subtract_without_allocation(zz, modulo, result));
|
||||||
|
|
||||||
if (modulo < zz) {
|
if (modulo < zz) {
|
||||||
// Note: This branch shouldn't happen in theory (as noted in https://github.com/rust-num/num-bigint/blob/master/src/biguint/monty.rs#L210)
|
// Note: This branch shouldn't happen in theory (as noted in https://github.com/rust-num/num-bigint/blob/master/src/biguint/monty.rs#L210)
|
||||||
|
|
|
@ -73,14 +73,13 @@ void UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(Unsig
|
||||||
/**
|
/**
|
||||||
* Complexity: O(N) where N is the number of words in the larger number
|
* Complexity: O(N) where N is the number of words in the larger number
|
||||||
*/
|
*/
|
||||||
void UnsignedBigIntegerAlgorithms::subtract_without_allocation(
|
ErrorOr<void> UnsignedBigIntegerAlgorithms::subtract_without_allocation(
|
||||||
UnsignedBigInteger const& left,
|
UnsignedBigInteger const& left,
|
||||||
UnsignedBigInteger const& right,
|
UnsignedBigInteger const& right,
|
||||||
UnsignedBigInteger& output)
|
UnsignedBigInteger& output)
|
||||||
{
|
{
|
||||||
if (left < right) {
|
if (left < right) {
|
||||||
output.invalidate();
|
return Error::from_string_literal("Invalid subtraction: left < right");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 borrow = 0;
|
u8 borrow = 0;
|
||||||
|
@ -103,6 +102,8 @@ void UnsignedBigIntegerAlgorithms::subtract_without_allocation(
|
||||||
|
|
||||||
// This assertion should not fail, because we verified that *this>=other at the beginning of the function
|
// This assertion should not fail, because we verified that *this>=other at the beginning of the function
|
||||||
VERIFY(borrow == 0);
|
VERIFY(borrow == 0);
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ class UnsignedBigIntegerAlgorithms {
|
||||||
public:
|
public:
|
||||||
static void add_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
static void add_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
||||||
static void add_into_accumulator_without_allocation(UnsignedBigInteger& accumulator, UnsignedBigInteger const& value);
|
static void add_into_accumulator_without_allocation(UnsignedBigInteger& accumulator, UnsignedBigInteger const& value);
|
||||||
static void subtract_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
static ErrorOr<void> subtract_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
||||||
static void bitwise_or_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
static void bitwise_or_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
||||||
static void bitwise_and_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
static void bitwise_and_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
||||||
static void bitwise_xor_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
static void bitwise_xor_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& output);
|
||||||
|
|
|
@ -109,23 +109,23 @@ FLATTEN SignedBigInteger SignedBigInteger::minus(SignedBigInteger const& other)
|
||||||
// x - y = - (y - x)
|
// x - y = - (y - x)
|
||||||
if (m_unsigned_data < other.m_unsigned_data) {
|
if (m_unsigned_data < other.m_unsigned_data) {
|
||||||
// The result will be negative.
|
// The result will be negative.
|
||||||
return { other.m_unsigned_data.minus(m_unsigned_data), true };
|
return { MUST(other.m_unsigned_data.minus(m_unsigned_data)), true };
|
||||||
}
|
}
|
||||||
|
|
||||||
// The result will be either zero, or positive.
|
// The result will be either zero, or positive.
|
||||||
return SignedBigInteger { m_unsigned_data.minus(other.m_unsigned_data) };
|
return SignedBigInteger { MUST(m_unsigned_data.minus(other.m_unsigned_data)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both operands are negative.
|
// Both operands are negative.
|
||||||
// -x - -y = y - x
|
// -x - -y = y - x
|
||||||
if (m_unsigned_data < other.m_unsigned_data) {
|
if (m_unsigned_data < other.m_unsigned_data) {
|
||||||
// The result will be positive.
|
// The result will be positive.
|
||||||
return SignedBigInteger { other.m_unsigned_data.minus(m_unsigned_data) };
|
return SignedBigInteger { MUST(other.m_unsigned_data.minus(m_unsigned_data)) };
|
||||||
}
|
}
|
||||||
// y - x = - (x - y)
|
// y - x = - (x - y)
|
||||||
if (m_unsigned_data > other.m_unsigned_data) {
|
if (m_unsigned_data > other.m_unsigned_data) {
|
||||||
// The result will be negative.
|
// The result will be negative.
|
||||||
return SignedBigInteger { m_unsigned_data.minus(other.m_unsigned_data), true };
|
return SignedBigInteger { MUST(m_unsigned_data.minus(other.m_unsigned_data)), true };
|
||||||
}
|
}
|
||||||
// Both operands have the same magnitude, the result is positive zero.
|
// Both operands have the same magnitude, the result is positive zero.
|
||||||
return SignedBigInteger { 0 };
|
return SignedBigInteger { 0 };
|
||||||
|
@ -135,9 +135,9 @@ FLATTEN SignedBigInteger SignedBigInteger::plus(UnsignedBigInteger const& other)
|
||||||
{
|
{
|
||||||
if (m_sign) {
|
if (m_sign) {
|
||||||
if (other < m_unsigned_data)
|
if (other < m_unsigned_data)
|
||||||
return { m_unsigned_data.minus(other), true };
|
return { MUST(m_unsigned_data.minus(other)), true };
|
||||||
|
|
||||||
return { other.minus(m_unsigned_data), false };
|
return { MUST(other.minus(m_unsigned_data)), false };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { m_unsigned_data.plus(other), false };
|
return { m_unsigned_data.plus(other), false };
|
||||||
|
@ -149,9 +149,9 @@ FLATTEN SignedBigInteger SignedBigInteger::minus(UnsignedBigInteger const& other
|
||||||
return { m_unsigned_data.plus(m_unsigned_data), true };
|
return { m_unsigned_data.plus(m_unsigned_data), true };
|
||||||
|
|
||||||
if (other < m_unsigned_data)
|
if (other < m_unsigned_data)
|
||||||
return { m_unsigned_data.minus(other), false };
|
return { MUST(m_unsigned_data.minus(other)), false };
|
||||||
|
|
||||||
return { other.minus(m_unsigned_data), true };
|
return { MUST(other.minus(m_unsigned_data)), true };
|
||||||
}
|
}
|
||||||
|
|
||||||
FLATTEN SignedBigInteger SignedBigInteger::bitwise_not() const
|
FLATTEN SignedBigInteger SignedBigInteger::bitwise_not() const
|
||||||
|
@ -190,16 +190,16 @@ FLATTEN SignedBigInteger SignedBigInteger::bitwise_or(SignedBigInteger const& ot
|
||||||
// This saves one ~.
|
// This saves one ~.
|
||||||
if (is_negative() && !other.is_negative()) {
|
if (is_negative() && !other.is_negative()) {
|
||||||
size_t index = unsigned_value().one_based_index_of_highest_set_bit();
|
size_t index = unsigned_value().one_based_index_of_highest_set_bit();
|
||||||
return { unsigned_value().minus(1).bitwise_and(other.unsigned_value().bitwise_not_fill_to_one_based_index(index)).plus(1), true };
|
return { MUST(unsigned_value().minus(1)).bitwise_and(other.unsigned_value().bitwise_not_fill_to_one_based_index(index)).plus(1), true };
|
||||||
}
|
}
|
||||||
|
|
||||||
// -(A | -B) == ~A & (B - 1) + 1
|
// -(A | -B) == ~A & (B - 1) + 1
|
||||||
if (!is_negative() && other.is_negative()) {
|
if (!is_negative() && other.is_negative()) {
|
||||||
size_t index = other.unsigned_value().one_based_index_of_highest_set_bit();
|
size_t index = other.unsigned_value().one_based_index_of_highest_set_bit();
|
||||||
return { unsigned_value().bitwise_not_fill_to_one_based_index(index).bitwise_and(other.unsigned_value().minus(1)).plus(1), true };
|
return { unsigned_value().bitwise_not_fill_to_one_based_index(index).bitwise_and(MUST(other.unsigned_value().minus(1))).plus(1), true };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { unsigned_value().minus(1).bitwise_and(other.unsigned_value().minus(1)).plus(1), true };
|
return { MUST(unsigned_value().minus(1)).bitwise_and(MUST(other.unsigned_value().minus(1))).plus(1), true };
|
||||||
}
|
}
|
||||||
|
|
||||||
FLATTEN SignedBigInteger SignedBigInteger::bitwise_and(SignedBigInteger const& other) const
|
FLATTEN SignedBigInteger SignedBigInteger::bitwise_and(SignedBigInteger const& other) const
|
||||||
|
@ -237,7 +237,7 @@ FLATTEN SignedBigInteger SignedBigInteger::bitwise_and(SignedBigInteger const& o
|
||||||
// -A & -B == -( (A - 1) | (B - 1) + 1)
|
// -A & -B == -( (A - 1) | (B - 1) + 1)
|
||||||
// So we can compute the bitwise and by returning a negative number with magnitude (A - 1) | (B - 1) + 1.
|
// So we can compute the bitwise and by returning a negative number with magnitude (A - 1) | (B - 1) + 1.
|
||||||
// This is better than the naive (~A + 1) & (~B + 1) because it needs just one O(n) scan for the or instead of 2 for the ~s.
|
// This is better than the naive (~A + 1) & (~B + 1) because it needs just one O(n) scan for the or instead of 2 for the ~s.
|
||||||
return { unsigned_value().minus(1).bitwise_or(other.unsigned_value().minus(1)).plus(1), true };
|
return { MUST(unsigned_value().minus(1)).bitwise_or(MUST(other.unsigned_value().minus(1))).plus(1), true };
|
||||||
}
|
}
|
||||||
|
|
||||||
FLATTEN SignedBigInteger SignedBigInteger::bitwise_xor(SignedBigInteger const& other) const
|
FLATTEN SignedBigInteger SignedBigInteger::bitwise_xor(SignedBigInteger const& other) const
|
||||||
|
@ -333,9 +333,6 @@ void SignedBigInteger::set_bit_inplace(size_t bit_index)
|
||||||
|
|
||||||
bool SignedBigInteger::operator==(SignedBigInteger const& other) const
|
bool SignedBigInteger::operator==(SignedBigInteger const& other) const
|
||||||
{
|
{
|
||||||
if (is_invalid() != other.is_invalid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_unsigned_data == 0 && other.m_unsigned_data == 0)
|
if (m_unsigned_data == 0 && other.m_unsigned_data == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
@ -92,13 +92,6 @@ public:
|
||||||
m_sign = other.m_sign;
|
m_sign = other.m_sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
void invalidate()
|
|
||||||
{
|
|
||||||
m_unsigned_data.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool is_invalid() const { return m_unsigned_data.is_invalid(); }
|
|
||||||
|
|
||||||
// These get + 1 byte for the sign.
|
// These get + 1 byte for the sign.
|
||||||
[[nodiscard]] size_t length() const { return m_unsigned_data.length() + 1; }
|
[[nodiscard]] size_t length() const { return m_unsigned_data.length() + 1; }
|
||||||
[[nodiscard]] size_t trimmed_length() const { return m_unsigned_data.trimmed_length() + 1; }
|
[[nodiscard]] size_t trimmed_length() const { return m_unsigned_data.trimmed_length() + 1; }
|
||||||
|
|
|
@ -179,7 +179,6 @@ u64 UnsignedBigInteger::to_u64() const
|
||||||
|
|
||||||
double UnsignedBigInteger::to_double(UnsignedBigInteger::RoundingMode rounding_mode) const
|
double UnsignedBigInteger::to_double(UnsignedBigInteger::RoundingMode rounding_mode) const
|
||||||
{
|
{
|
||||||
VERIFY(!is_invalid());
|
|
||||||
auto highest_bit = one_based_index_of_highest_set_bit();
|
auto highest_bit = one_based_index_of_highest_set_bit();
|
||||||
if (highest_bit == 0)
|
if (highest_bit == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -342,14 +341,12 @@ double UnsignedBigInteger::to_double(UnsignedBigInteger::RoundingMode rounding_m
|
||||||
void UnsignedBigInteger::set_to_0()
|
void UnsignedBigInteger::set_to_0()
|
||||||
{
|
{
|
||||||
m_words.clear_with_capacity();
|
m_words.clear_with_capacity();
|
||||||
m_is_invalid = false;
|
|
||||||
m_cached_trimmed_length = {};
|
m_cached_trimmed_length = {};
|
||||||
m_cached_hash = 0;
|
m_cached_hash = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnsignedBigInteger::set_to(UnsignedBigInteger::Word other)
|
void UnsignedBigInteger::set_to(UnsignedBigInteger::Word other)
|
||||||
{
|
{
|
||||||
m_is_invalid = false;
|
|
||||||
m_words.resize_and_keep_capacity(1);
|
m_words.resize_and_keep_capacity(1);
|
||||||
m_words[0] = other;
|
m_words[0] = other;
|
||||||
m_cached_trimmed_length = {};
|
m_cached_trimmed_length = {};
|
||||||
|
@ -358,7 +355,6 @@ void UnsignedBigInteger::set_to(UnsignedBigInteger::Word other)
|
||||||
|
|
||||||
void UnsignedBigInteger::set_to(UnsignedBigInteger const& other)
|
void UnsignedBigInteger::set_to(UnsignedBigInteger const& other)
|
||||||
{
|
{
|
||||||
m_is_invalid = other.m_is_invalid;
|
|
||||||
m_words.resize_and_keep_capacity(other.m_words.size());
|
m_words.resize_and_keep_capacity(other.m_words.size());
|
||||||
__builtin_memcpy(m_words.data(), other.m_words.data(), other.m_words.size() * sizeof(u32));
|
__builtin_memcpy(m_words.data(), other.m_words.data(), other.m_words.size() * sizeof(u32));
|
||||||
m_cached_trimmed_length = {};
|
m_cached_trimmed_length = {};
|
||||||
|
@ -424,11 +420,11 @@ FLATTEN UnsignedBigInteger UnsignedBigInteger::plus(UnsignedBigInteger const& ot
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FLATTEN UnsignedBigInteger UnsignedBigInteger::minus(UnsignedBigInteger const& other) const
|
FLATTEN ErrorOr<UnsignedBigInteger> UnsignedBigInteger::minus(UnsignedBigInteger const& other) const
|
||||||
{
|
{
|
||||||
UnsignedBigInteger result;
|
UnsignedBigInteger result;
|
||||||
|
|
||||||
UnsignedBigIntegerAlgorithms::subtract_without_allocation(*this, other, result);
|
TRY(UnsignedBigIntegerAlgorithms::subtract_without_allocation(*this, other, result));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -577,9 +573,6 @@ void UnsignedBigInteger::set_bit_inplace(size_t bit_index)
|
||||||
|
|
||||||
bool UnsignedBigInteger::operator==(UnsignedBigInteger const& other) const
|
bool UnsignedBigInteger::operator==(UnsignedBigInteger const& other) const
|
||||||
{
|
{
|
||||||
if (is_invalid() != other.is_invalid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto length = trimmed_length();
|
auto length = trimmed_length();
|
||||||
|
|
||||||
if (length != other.trimmed_length())
|
if (length != other.trimmed_length())
|
||||||
|
@ -771,9 +764,6 @@ UnsignedBigInteger::CompareResult UnsignedBigInteger::compare_to_double(double v
|
||||||
|
|
||||||
ErrorOr<void> AK::Formatter<Crypto::UnsignedBigInteger>::format(FormatBuilder& fmtbuilder, Crypto::UnsignedBigInteger const& value)
|
ErrorOr<void> AK::Formatter<Crypto::UnsignedBigInteger>::format(FormatBuilder& fmtbuilder, Crypto::UnsignedBigInteger const& value)
|
||||||
{
|
{
|
||||||
if (value.is_invalid())
|
|
||||||
return fmtbuilder.put_string("invalid"sv);
|
|
||||||
|
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
for (int i = value.length() - 1; i >= 0; --i)
|
for (int i = value.length() - 1; i >= 0; --i)
|
||||||
TRY(builder.try_appendff("{}|", value.words()[i]));
|
TRY(builder.try_appendff("{}|", value.words()[i]));
|
||||||
|
|
|
@ -83,16 +83,8 @@ public:
|
||||||
void set_to(Word other);
|
void set_to(Word other);
|
||||||
void set_to(UnsignedBigInteger const& other);
|
void set_to(UnsignedBigInteger const& other);
|
||||||
|
|
||||||
void invalidate()
|
|
||||||
{
|
|
||||||
m_is_invalid = true;
|
|
||||||
m_cached_trimmed_length = {};
|
|
||||||
m_cached_hash = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool is_zero() const;
|
[[nodiscard]] bool is_zero() const;
|
||||||
[[nodiscard]] bool is_odd() const { return m_words.size() && (m_words[0] & 1); }
|
[[nodiscard]] bool is_odd() const { return m_words.size() && (m_words[0] & 1); }
|
||||||
[[nodiscard]] bool is_invalid() const { return m_is_invalid; }
|
|
||||||
|
|
||||||
[[nodiscard]] size_t length() const { return m_words.size(); }
|
[[nodiscard]] size_t length() const { return m_words.size(); }
|
||||||
// The "trimmed length" is the number of words after trimming leading zeroed words
|
// The "trimmed length" is the number of words after trimming leading zeroed words
|
||||||
|
@ -107,7 +99,7 @@ public:
|
||||||
size_t one_based_index_of_highest_set_bit() const;
|
size_t one_based_index_of_highest_set_bit() const;
|
||||||
|
|
||||||
[[nodiscard]] UnsignedBigInteger plus(UnsignedBigInteger const& other) const;
|
[[nodiscard]] UnsignedBigInteger plus(UnsignedBigInteger const& other) const;
|
||||||
[[nodiscard]] UnsignedBigInteger minus(UnsignedBigInteger const& other) const;
|
[[nodiscard]] ErrorOr<UnsignedBigInteger> minus(UnsignedBigInteger const& other) const;
|
||||||
[[nodiscard]] UnsignedBigInteger bitwise_or(UnsignedBigInteger const& other) const;
|
[[nodiscard]] UnsignedBigInteger bitwise_or(UnsignedBigInteger const& other) const;
|
||||||
[[nodiscard]] UnsignedBigInteger bitwise_and(UnsignedBigInteger const& other) const;
|
[[nodiscard]] UnsignedBigInteger bitwise_and(UnsignedBigInteger const& other) const;
|
||||||
[[nodiscard]] UnsignedBigInteger bitwise_xor(UnsignedBigInteger const& other) const;
|
[[nodiscard]] UnsignedBigInteger bitwise_xor(UnsignedBigInteger const& other) const;
|
||||||
|
@ -153,10 +145,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable u32 m_cached_hash { 0 };
|
mutable u32 m_cached_hash { 0 };
|
||||||
|
|
||||||
// Used to indicate a negative result, or a result of an invalid operation
|
|
||||||
bool m_is_invalid { false };
|
|
||||||
|
|
||||||
mutable Optional<size_t> m_cached_trimmed_length;
|
mutable Optional<size_t> m_cached_trimmed_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -179,10 +167,7 @@ inline Crypto::UnsignedBigInteger operator""_bigint(char const* string, size_t l
|
||||||
|
|
||||||
inline Crypto::UnsignedBigInteger operator""_bigint(unsigned long long value)
|
inline Crypto::UnsignedBigInteger operator""_bigint(unsigned long long value)
|
||||||
{
|
{
|
||||||
auto result = Crypto::UnsignedBigInteger { static_cast<u64>(value) };
|
return Crypto::UnsignedBigInteger { static_cast<u64>(value) };
|
||||||
VERIFY(!result.is_invalid());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Crypto::UnsignedBigInteger operator""_bigint(long double value)
|
inline Crypto::UnsignedBigInteger operator""_bigint(long double value)
|
||||||
|
@ -190,8 +175,5 @@ inline Crypto::UnsignedBigInteger operator""_bigint(long double value)
|
||||||
VERIFY(value >= 0);
|
VERIFY(value >= 0);
|
||||||
VERIFY(value < static_cast<long double>(NumericLimits<double>::max()));
|
VERIFY(value < static_cast<long double>(NumericLimits<double>::max()));
|
||||||
|
|
||||||
auto result = Crypto::UnsignedBigInteger { static_cast<double>(value) };
|
return Crypto::UnsignedBigInteger { static_cast<double>(value) };
|
||||||
VERIFY(!result.is_invalid());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ GC::Ref<BigInt> BigInt::create(VM& vm, Crypto::SignedBigInteger big_integer)
|
||||||
BigInt::BigInt(Crypto::SignedBigInteger big_integer)
|
BigInt::BigInt(Crypto::SignedBigInteger big_integer)
|
||||||
: m_big_integer(move(big_integer))
|
: m_big_integer(move(big_integer))
|
||||||
{
|
{
|
||||||
VERIFY(!m_big_integer.is_invalid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<String> BigInt::to_string() const
|
ErrorOr<String> BigInt::to_string() const
|
||||||
|
|
|
@ -965,7 +965,7 @@ Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResu
|
||||||
auto d1 = x.remainder.unsigned_value();
|
auto d1 = x.remainder.unsigned_value();
|
||||||
|
|
||||||
// 7. Let d2 be r2 – x.
|
// 7. Let d2 be r2 – x.
|
||||||
auto d2 = increment.minus(x.remainder.unsigned_value());
|
auto d2 = MUST(increment.minus(x.remainder.unsigned_value()));
|
||||||
|
|
||||||
// 8. If d1 < d2, return r1.
|
// 8. If d1 < d2, return r1.
|
||||||
if (d1 < d2)
|
if (d1 < d2)
|
||||||
|
|
|
@ -127,7 +127,7 @@ TEST_CASE(test_unsigned_bigint_simple_subtraction)
|
||||||
Crypto::UnsignedBigInteger num1(80);
|
Crypto::UnsignedBigInteger num1(80);
|
||||||
Crypto::UnsignedBigInteger num2(70);
|
Crypto::UnsignedBigInteger num2(70);
|
||||||
|
|
||||||
EXPECT_EQ(num1.minus(num2), Crypto::UnsignedBigInteger(10));
|
EXPECT_EQ(TRY_OR_FAIL(num1.minus(num2)), Crypto::UnsignedBigInteger(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(test_unsigned_bigint_simple_subtraction_invalid)
|
TEST_CASE(test_unsigned_bigint_simple_subtraction_invalid)
|
||||||
|
@ -135,7 +135,7 @@ TEST_CASE(test_unsigned_bigint_simple_subtraction_invalid)
|
||||||
Crypto::UnsignedBigInteger num1(50);
|
Crypto::UnsignedBigInteger num1(50);
|
||||||
Crypto::UnsignedBigInteger num2(70);
|
Crypto::UnsignedBigInteger num2(70);
|
||||||
|
|
||||||
EXPECT(num1.minus(num2).is_invalid());
|
EXPECT(num1.minus(num2).is_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(test_unsigned_bigint_simple_subtraction_with_borrow)
|
TEST_CASE(test_unsigned_bigint_simple_subtraction_with_borrow)
|
||||||
|
@ -143,7 +143,7 @@ TEST_CASE(test_unsigned_bigint_simple_subtraction_with_borrow)
|
||||||
Crypto::UnsignedBigInteger num1(UINT32_MAX);
|
Crypto::UnsignedBigInteger num1(UINT32_MAX);
|
||||||
Crypto::UnsignedBigInteger num2(1);
|
Crypto::UnsignedBigInteger num2(1);
|
||||||
Crypto::UnsignedBigInteger num3 = num1.plus(num2);
|
Crypto::UnsignedBigInteger num3 = num1.plus(num2);
|
||||||
Crypto::UnsignedBigInteger result = num3.minus(num2);
|
Crypto::UnsignedBigInteger result = TRY_OR_FAIL(num3.minus(num2));
|
||||||
EXPECT_EQ(result, num1);
|
EXPECT_EQ(result, num1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ TEST_CASE(test_unsigned_bigint_subtraction_with_large_numbers)
|
||||||
{
|
{
|
||||||
Crypto::UnsignedBigInteger num1 = bigint_fibonacci(343);
|
Crypto::UnsignedBigInteger num1 = bigint_fibonacci(343);
|
||||||
Crypto::UnsignedBigInteger num2 = bigint_fibonacci(218);
|
Crypto::UnsignedBigInteger num2 = bigint_fibonacci(218);
|
||||||
Crypto::UnsignedBigInteger result = num1.minus(num2);
|
Crypto::UnsignedBigInteger result = TRY_OR_FAIL(num1.minus(num2));
|
||||||
|
|
||||||
Vector<u32> expected_result {
|
Vector<u32> expected_result {
|
||||||
811430588, 2958904896, 1130908877, 2830569969, 3243275482,
|
811430588, 2958904896, 1130908877, 2830569969, 3243275482,
|
||||||
|
@ -165,7 +165,7 @@ TEST_CASE(test_unsigned_bigint_subtraction_with_large_numbers2)
|
||||||
{
|
{
|
||||||
Crypto::UnsignedBigInteger num1(Vector<u32> { 1483061863, 446680044, 1123294122, 191895498, 3347106536, 16, 0, 0, 0 });
|
Crypto::UnsignedBigInteger num1(Vector<u32> { 1483061863, 446680044, 1123294122, 191895498, 3347106536, 16, 0, 0, 0 });
|
||||||
Crypto::UnsignedBigInteger num2(Vector<u32> { 4196414175, 1117247942, 1123294122, 191895498, 3347106536, 16 });
|
Crypto::UnsignedBigInteger num2(Vector<u32> { 4196414175, 1117247942, 1123294122, 191895498, 3347106536, 16 });
|
||||||
Crypto::UnsignedBigInteger result = num1.minus(num2);
|
ErrorOr<Crypto::UnsignedBigInteger> result = num1.minus(num2);
|
||||||
// this test only verifies that we don't crash on an assertion
|
// this test only verifies that we don't crash on an assertion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ TEST_CASE(test_unsigned_bigint_subtraction_regression_1)
|
||||||
4294967295, 4294967295, 4294967295, 4294967295, 4294967295,
|
4294967295, 4294967295, 4294967295, 4294967295, 4294967295,
|
||||||
4294967295, 4294967295, 4294967295, 0
|
4294967295, 4294967295, 4294967295, 0
|
||||||
};
|
};
|
||||||
EXPECT_EQ(num.minus(1).words(), expected_result);
|
EXPECT_EQ(TRY_OR_FAIL(num.minus(1)).words(), expected_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(test_unsigned_bigint_simple_multiplication)
|
TEST_CASE(test_unsigned_bigint_simple_multiplication)
|
||||||
|
@ -934,7 +934,6 @@ TEST_CASE(bigint_from_double)
|
||||||
{
|
{
|
||||||
Crypto::UnsignedBigInteger from_zero { 0.0 };
|
Crypto::UnsignedBigInteger from_zero { 0.0 };
|
||||||
EXPECT(from_zero.is_zero());
|
EXPECT(from_zero.is_zero());
|
||||||
EXPECT(!from_zero.is_invalid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SURVIVES_ROUND_TRIP_UNSIGNED(double_value) \
|
#define SURVIVES_ROUND_TRIP_UNSIGNED(double_value) \
|
||||||
|
@ -1040,7 +1039,7 @@ TEST_CASE(unsigned_bigint_double_comparisons)
|
||||||
VERIFY(double_below_max_value < (double_max_value - 1.0));
|
VERIFY(double_below_max_value < (double_max_value - 1.0));
|
||||||
auto max_value_in_bigint = TRY_OR_FAIL(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_plus_one = max_value_in_bigint.plus(Crypto::UnsignedBigInteger { 1 });
|
||||||
auto max_value_minus_one = max_value_in_bigint.minus(Crypto::UnsignedBigInteger { 1 });
|
auto max_value_minus_one = TRY_OR_FAIL(max_value_in_bigint.minus(Crypto::UnsignedBigInteger { 1 }));
|
||||||
|
|
||||||
auto below_max_value_in_bigint = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv));
|
auto below_max_value_in_bigint = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue