mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibCrypto: Added BigInteger 'division by u16' operator
This commit is contained in:
parent
0efd58bf6d
commit
8aeccf4f02
Notes:
sideshowbarker
2024-07-19 07:00:57 +09:00
Author: https://github.com/Dexesttp Commit: https://github.com/SerenityOS/serenity/commit/8aeccf4f024 Pull-request: https://github.com/SerenityOS/serenity/pull/2064
3 changed files with 67 additions and 13 deletions
|
@ -52,14 +52,17 @@ UnsignedBigInteger UnsignedBigInteger::import_data(const u8* ptr, size_t length)
|
|||
size_t UnsignedBigInteger::export_data(AK::ByteBuffer& data)
|
||||
{
|
||||
UnsignedBigInteger copy { *this };
|
||||
UnsignedBigInteger quotient;
|
||||
UnsignedBigInteger remainder;
|
||||
|
||||
size_t size = trimmed_length() * sizeof(u32);
|
||||
size_t i = 0;
|
||||
for (; i < size; ++i) {
|
||||
if (copy.length() == 0)
|
||||
if (copy.trimmed_length() == 0)
|
||||
break;
|
||||
data[size - i - 1] = copy.m_words[0] & 0xff;
|
||||
copy = copy.divided_by(256).quotient;
|
||||
divide_u16_without_allocation(copy, 256, quotient, remainder);
|
||||
copy.set_to(quotient);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
@ -79,12 +82,14 @@ String UnsignedBigInteger::to_base10() const
|
|||
{
|
||||
StringBuilder builder;
|
||||
UnsignedBigInteger temp(*this);
|
||||
UnsignedBigInteger quotient;
|
||||
UnsignedBigInteger remainder;
|
||||
|
||||
while (temp != UnsignedBigInteger { 0 }) {
|
||||
auto div_result = temp.divided_by({ 10 });
|
||||
ASSERT(div_result.remainder.words()[0] < 10);
|
||||
builder.append(static_cast<char>(div_result.remainder.words()[0] + '0'));
|
||||
temp = div_result.quotient;
|
||||
divide_u16_without_allocation(temp, 10, quotient, remainder);
|
||||
ASSERT(remainder.words()[0] < 10);
|
||||
builder.append(static_cast<char>(remainder.words()[0] + '0'));
|
||||
temp.set_to(quotient);
|
||||
}
|
||||
|
||||
auto reversed_string = builder.to_string();
|
||||
|
@ -102,6 +107,13 @@ void UnsignedBigInteger::set_to_0()
|
|||
m_is_invalid = false;
|
||||
}
|
||||
|
||||
void UnsignedBigInteger::set_to(u32 other)
|
||||
{
|
||||
m_is_invalid = false;
|
||||
m_words.clear_with_capacity();
|
||||
m_words.append(other);
|
||||
}
|
||||
|
||||
void UnsignedBigInteger::set_to(const UnsignedBigInteger& other)
|
||||
{
|
||||
m_is_invalid = other.m_is_invalid;
|
||||
|
@ -168,6 +180,13 @@ FLATTEN UnsignedDivisionResult UnsignedBigInteger::divided_by(const UnsignedBigI
|
|||
UnsignedBigInteger quotient;
|
||||
UnsignedBigInteger remainder;
|
||||
|
||||
// If we actually have a u16-compatible divisor, short-circuit to the
|
||||
// less computationally-intensive "divide_u16_without_allocation" method.
|
||||
if (divisor.trimmed_length() == 1 && divisor.m_words[0] < (1 << 16)) {
|
||||
divide_u16_without_allocation(*this, divisor.m_words[0], quotient, remainder);
|
||||
return UnsignedDivisionResult { quotient, remainder };
|
||||
}
|
||||
|
||||
UnsignedBigInteger temp_shift_result;
|
||||
UnsignedBigInteger temp_shift_plus;
|
||||
UnsignedBigInteger temp_shift;
|
||||
|
@ -434,6 +453,41 @@ FLATTEN void UnsignedBigInteger::divide_without_allocation(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 UnsignedBigInteger::divide_u16_without_allocation(
|
||||
const UnsignedBigInteger& numerator,
|
||||
u32 denominator,
|
||||
UnsignedBigInteger& quotient,
|
||||
UnsignedBigInteger& remainder)
|
||||
{
|
||||
ASSERT(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);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void UnsignedBigInteger::shift_left_by_n_words(
|
||||
const UnsignedBigInteger& number,
|
||||
const size_t number_of_words,
|
||||
|
|
|
@ -65,6 +65,7 @@ public:
|
|||
const AK::Vector<u32, STARTING_WORD_SIZE>& words() const { return m_words; }
|
||||
|
||||
void set_to_0();
|
||||
void set_to(u32 other);
|
||||
void set_to(const UnsignedBigInteger& other);
|
||||
void invalidate() { m_is_invalid = true; }
|
||||
|
||||
|
@ -87,6 +88,7 @@ public:
|
|||
static void shift_left_without_allocation(const UnsignedBigInteger& number, size_t bits_to_shift_by, UnsignedBigInteger& temp_result, UnsignedBigInteger& temp_plus, UnsignedBigInteger& output);
|
||||
static void multiply_without_allocation(const UnsignedBigInteger& left, const UnsignedBigInteger& right, UnsignedBigInteger& temp_shift_result, UnsignedBigInteger& temp_shift_plus, UnsignedBigInteger& temp_shift, UnsignedBigInteger& temp_plus, UnsignedBigInteger& output);
|
||||
static void divide_without_allocation(const UnsignedBigInteger& numerator, const UnsignedBigInteger& denominator, UnsignedBigInteger& temp_shift_result, UnsignedBigInteger& temp_shift_plus, UnsignedBigInteger& temp_shift, UnsignedBigInteger& temp_minus, UnsignedBigInteger& quotient, UnsignedBigInteger& remainder);
|
||||
static void divide_u16_without_allocation(const UnsignedBigInteger& numerator, u32 denominator, UnsignedBigInteger& quotient, UnsignedBigInteger& remainder);
|
||||
|
||||
bool operator==(const UnsignedBigInteger& other) const;
|
||||
bool operator!=(const UnsignedBigInteger& other) const;
|
||||
|
|
|
@ -39,7 +39,6 @@ static auto ModularInverse(const UnsignedBigInteger& a_, const UnsignedBigIntege
|
|||
return { 1 };
|
||||
|
||||
UnsignedBigInteger one { 1 };
|
||||
UnsignedBigInteger two { 2 };
|
||||
UnsignedBigInteger temp_1;
|
||||
UnsignedBigInteger temp_2;
|
||||
UnsignedBigInteger temp_3;
|
||||
|
@ -82,11 +81,11 @@ static auto ModularInverse(const UnsignedBigInteger& a_, const UnsignedBigIntege
|
|||
}
|
||||
|
||||
// u /= 2
|
||||
UnsignedBigInteger::divide_without_allocation(u, two, temp_1, temp_2, temp_3, temp_4, temp_quotient, temp_remainder);
|
||||
UnsignedBigInteger::divide_u16_without_allocation(u, 2, temp_quotient, temp_remainder);
|
||||
u.set_to(temp_quotient);
|
||||
|
||||
// d /= 2
|
||||
UnsignedBigInteger::divide_without_allocation(d, two, temp_1, temp_2, temp_3, temp_4, temp_quotient, temp_remainder);
|
||||
UnsignedBigInteger::divide_u16_without_allocation(d, 2, temp_quotient, temp_remainder);
|
||||
d.set_to(temp_quotient);
|
||||
}
|
||||
}
|
||||
|
@ -107,11 +106,11 @@ static auto ModularInverse(const UnsignedBigInteger& a_, const UnsignedBigIntege
|
|||
}
|
||||
|
||||
// v /= 2
|
||||
UnsignedBigInteger::divide_without_allocation(v, two, temp_1, temp_2, temp_3, temp_4, temp_quotient, temp_remainder);
|
||||
UnsignedBigInteger::divide_u16_without_allocation(v, 2, temp_quotient, temp_remainder);
|
||||
v.set_to(temp_quotient);
|
||||
|
||||
// x /= 2
|
||||
UnsignedBigInteger::divide_without_allocation(x, two, temp_1, temp_2, temp_3, temp_4, temp_quotient, temp_remainder);
|
||||
UnsignedBigInteger::divide_u16_without_allocation(x, 2, temp_quotient, temp_remainder);
|
||||
x.set_to(temp_quotient);
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +128,6 @@ static auto ModularPower(const UnsignedBigInteger& b, const UnsignedBigInteger&
|
|||
UnsignedBigInteger ep { e };
|
||||
UnsignedBigInteger base { b };
|
||||
UnsignedBigInteger exp { 1 };
|
||||
UnsignedBigInteger two { 2 };
|
||||
|
||||
UnsignedBigInteger temp_1;
|
||||
UnsignedBigInteger temp_2;
|
||||
|
@ -151,7 +149,7 @@ static auto ModularPower(const UnsignedBigInteger& b, const UnsignedBigInteger&
|
|||
}
|
||||
|
||||
// ep = ep / 2;
|
||||
UnsignedBigInteger::divide_without_allocation(ep, two, temp_1, temp_2, temp_3, temp_4, temp_quotient, temp_remainder);
|
||||
UnsignedBigInteger::divide_u16_without_allocation(ep, 2, temp_quotient, temp_remainder);
|
||||
ep.set_to(temp_quotient);
|
||||
|
||||
// base = (base * base) % m;
|
||||
|
|
Loading…
Reference in a new issue