1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:37:35 +00:00

LibCrypto: Split BigInteger operations into an Algorithms class

Since the operations are already complicated and will become even more
so soon, let's split them into their own files. We can also integrate
the NumberTheory operations that would better fit there into this class
as well.

This commit doesn't change behaviors, but moves the allocation of some
variables into caller classes.
This commit is contained in:
DexesTTP 2021-05-10 20:55:25 +02:00 committed by Linus Groh
parent 0853d98420
commit 5963f6f9ff
13 changed files with 736 additions and 582 deletions

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
* Copyright (c) 2020-2021, Dex <dexes.ttp@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "UnsignedBigIntegerAlgorithms.h"
namespace Crypto {
/**
* Complexity: O(N^2) where N is the number of words in the larger number
* Division method:
* We loop over the bits of the divisor, attempting to subtract divisor<<i from the dividend.
* If the result is non-negative, it means that divisor*2^i "fits" in the dividend,
* so we set the ith bit in the quotient and reduce divisor<<i from the dividend.
* When we're done, what's left from the dividend is the remainder.
*/
FLATTEN void UnsignedBigIntegerAlgorithms::divide_without_allocation(
UnsignedBigInteger const& numerator,
UnsignedBigInteger const& denominator,
UnsignedBigInteger& temp_shift_result,
UnsignedBigInteger& temp_shift_plus,
UnsignedBigInteger& temp_shift,
UnsignedBigInteger& temp_minus,
UnsignedBigInteger& quotient,
UnsignedBigInteger& remainder)
{
quotient.set_to_0();
remainder.set_to(numerator);
// iterate all bits
for (int word_index = numerator.trimmed_length() - 1; word_index >= 0; --word_index) {
for (int bit_index = UnsignedBigInteger::BITS_IN_WORD - 1; bit_index >= 0; --bit_index) {
size_t shift_amount = word_index * UnsignedBigInteger::BITS_IN_WORD + bit_index;
shift_left_without_allocation(denominator, shift_amount, temp_shift_result, temp_shift_plus, temp_shift);
subtract_without_allocation(remainder, temp_shift, temp_minus);
if (!temp_minus.is_invalid()) {
remainder.set_to(temp_minus);
quotient.set_bit_inplace(shift_amount);
}
}
}
}
/**
* Complexity : O(N) where N is the number of digits in the numerator
* Division method :
* Starting from the most significant one, for each half-word of the numerator, combine it
* with the existing remainder if any, divide the combined number as a u32 operation and
* update the quotient / remainder as needed.
*/
FLATTEN void UnsignedBigIntegerAlgorithms::divide_u16_without_allocation(
UnsignedBigInteger const& numerator,
u32 denominator,
UnsignedBigInteger& quotient,
UnsignedBigInteger& remainder)
{
VERIFY(denominator < (1 << 16));
u32 remainder_word = 0;
auto numerator_length = numerator.trimmed_length();
quotient.set_to_0();
quotient.m_words.resize(numerator_length);
for (int word_index = numerator_length - 1; word_index >= 0; --word_index) {
auto word_high = numerator.m_words[word_index] >> 16;
auto word_low = numerator.m_words[word_index] & ((1 << 16) - 1);
auto number_to_divide_high = (remainder_word << 16) | word_high;
auto quotient_high = number_to_divide_high / denominator;
remainder_word = number_to_divide_high % denominator;
auto number_to_divide_low = remainder_word << 16 | word_low;
auto quotient_low = number_to_divide_low / denominator;
remainder_word = number_to_divide_low % denominator;
quotient.m_words[word_index] = (quotient_high << 16) | quotient_low;
}
remainder.set_to(remainder_word);
}
}