LibCrypto: Add a += operation to UnsignedBigIntegerAlgorithms

This new operation is immediately used in several existing algorithms.
This commit is contained in:
DexesTTP 2021-05-12 10:47:21 +02:00 committed by Linus Groh
parent f4e6f58cc6
commit 5071989545
Notes: sideshowbarker 2024-07-18 18:13:44 +09:00
10 changed files with 151 additions and 47 deletions

View File

@ -199,8 +199,7 @@ FLATTEN void UnsignedBigIntegerAlgorithms::shift_left_without_allocation(
temp_plus.set_to_0();
temp_plus.m_words.append(carry_word);
shift_left_by_n_words(temp_plus, temp_result.length(), temp_result);
add_without_allocation(output, temp_result, temp_plus);
output.set_to(temp_plus);
add_into_accumulator_without_allocation(output, temp_result);
}
}

View File

@ -16,7 +16,6 @@ void UnsignedBigIntegerAlgorithms::modular_inverse_without_allocation(
UnsignedBigInteger& temp_2,
UnsignedBigInteger& temp_3,
UnsignedBigInteger& temp_4,
UnsignedBigInteger& temp_plus,
UnsignedBigInteger& temp_minus,
UnsignedBigInteger& temp_quotient,
UnsignedBigInteger& temp_d,
@ -30,8 +29,7 @@ void UnsignedBigIntegerAlgorithms::modular_inverse_without_allocation(
temp_u.set_to(a);
if (a.words()[0] % 2 == 0) {
// u += b
add_without_allocation(temp_u, b, temp_plus);
temp_u.set_to(temp_plus);
add_into_accumulator_without_allocation(temp_u, b);
}
temp_v.set_to(b);
@ -47,14 +45,12 @@ void UnsignedBigIntegerAlgorithms::modular_inverse_without_allocation(
temp_u.set_to(temp_minus);
// d += x
add_without_allocation(temp_d, temp_x, temp_plus);
temp_d.set_to(temp_plus);
add_into_accumulator_without_allocation(temp_d, temp_x);
while (temp_u.words()[0] % 2 == 0) {
if (temp_d.words()[0] % 2 == 1) {
// d += b
add_without_allocation(temp_d, b, temp_plus);
temp_d.set_to(temp_plus);
add_into_accumulator_without_allocation(temp_d, b);
}
// u /= 2
@ -72,14 +68,12 @@ void UnsignedBigIntegerAlgorithms::modular_inverse_without_allocation(
temp_v.set_to(temp_minus);
// x += d
add_without_allocation(temp_x, temp_d, temp_plus);
temp_x.set_to(temp_plus);
add_into_accumulator_without_allocation(temp_x, temp_d);
while (temp_v.words()[0] % 2 == 0) {
if (temp_x.words()[0] % 2 == 1) {
// x += b
add_without_allocation(temp_x, b, temp_plus);
temp_x.set_to(temp_plus);
add_into_accumulator_without_allocation(temp_x, b);
}
// v /= 2

View File

@ -26,7 +26,7 @@ void UnsignedBigIntegerAlgorithms::destructive_modular_power_without_allocation(
while (!(ep < 1)) {
if (ep.words()[0] % 2 == 1) {
// exp = (exp * base) % m;
multiply_without_allocation(exp, base, temp_1, temp_2, temp_3, temp_4, temp_multiply);
multiply_without_allocation(exp, base, temp_1, temp_2, temp_3, temp_multiply);
divide_without_allocation(temp_multiply, m, temp_1, temp_2, temp_3, temp_4, temp_quotient, temp_remainder);
exp.set_to(temp_remainder);
}
@ -36,7 +36,7 @@ void UnsignedBigIntegerAlgorithms::destructive_modular_power_without_allocation(
ep.set_to(temp_quotient);
// base = (base * base) % m;
multiply_without_allocation(base, base, temp_1, temp_2, temp_3, temp_4, temp_multiply);
multiply_without_allocation(base, base, temp_1, temp_2, temp_3, temp_multiply);
divide_without_allocation(temp_multiply, m, temp_1, temp_2, temp_3, temp_4, temp_quotient, temp_remainder);
base.set_to(temp_remainder);

View File

@ -23,7 +23,6 @@ FLATTEN void UnsignedBigIntegerAlgorithms::multiply_without_allocation(
UnsignedBigInteger& temp_shift_result,
UnsignedBigInteger& temp_shift_plus,
UnsignedBigInteger& temp_shift,
UnsignedBigInteger& temp_plus,
UnsignedBigInteger& output)
{
output.set_to_0();
@ -39,8 +38,7 @@ FLATTEN void UnsignedBigIntegerAlgorithms::multiply_without_allocation(
// output += (right << shift_amount);
shift_left_without_allocation(right, shift_amount, temp_shift_result, temp_shift_plus, temp_shift);
add_without_allocation(output, temp_shift, temp_plus);
output.set_to(temp_plus);
add_into_accumulator_without_allocation(output, temp_shift);
}
}
}

View File

@ -20,36 +20,51 @@ void UnsignedBigIntegerAlgorithms::add_without_allocation(
const UnsignedBigInteger* const longer = (left.length() > right.length()) ? &left : &right;
const UnsignedBigInteger* const shorter = (longer == &right) ? &left : &right;
u8 carry = 0;
output.set_to(*longer);
add_into_accumulator_without_allocation(output, *shorter);
}
output.set_to_0();
output.m_words.resize_and_keep_capacity(longer->length());
/**
* Complexity: O(N) where N is the number of words in the larger number
*/
void UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(UnsignedBigInteger& accumulator, UnsignedBigInteger const& value)
{
auto value_length = value.trimmed_length();
for (size_t i = 0; i < shorter->length(); ++i) {
u32 word_addition_result = shorter->m_words[i] + longer->m_words[i];
u8 carry_out = 0;
// if there was a carry, the result will be smaller than any of the operands
if (word_addition_result + carry < shorter->m_words[i]) {
carry_out = 1;
// If needed, resize the accumulator so it can fit the value.
accumulator.resize_with_leading_zeros(value_length);
auto final_length = accumulator.length();
// Add the words of the value into the accumulator, rippling any carry as we go
UnsignedBigInteger::Word last_carry_for_word = 0;
for (size_t i = 0; i < value_length; ++i) {
UnsignedBigInteger::Word current_carry_for_word = 0;
if (Checked<UnsignedBigInteger::Word>::addition_would_overflow(value.m_words[i], accumulator.m_words[i])) {
current_carry_for_word = 1;
}
if (carry) {
word_addition_result++;
UnsignedBigInteger::Word word_addition_result = value.m_words[i] + accumulator.m_words[i];
if (Checked<UnsignedBigInteger::Word>::addition_would_overflow(word_addition_result, last_carry_for_word)) {
current_carry_for_word = 1;
}
carry = carry_out;
output.m_words[i] = word_addition_result;
word_addition_result += last_carry_for_word;
last_carry_for_word = current_carry_for_word;
accumulator.m_words[i] = word_addition_result;
}
for (size_t i = shorter->length(); i < longer->length(); ++i) {
u32 word_addition_result = longer->m_words[i] + carry;
carry = 0;
if (word_addition_result < longer->m_words[i]) {
carry = 1;
// Ripple the carry over the remaining words in the accumulator until either there is no carry left or we run out of words
while (last_carry_for_word && final_length > value_length) {
UnsignedBigInteger::Word current_carry_for_word = 0;
if (Checked<UnsignedBigInteger::Word>::addition_would_overflow(accumulator.m_words[value_length], last_carry_for_word)) {
current_carry_for_word = 1;
}
output.m_words[i] = word_addition_result;
accumulator.m_words[value_length] += last_carry_for_word;
last_carry_for_word = current_carry_for_word;
value_length++;
}
if (carry) {
output.m_words.append(carry);
if (last_carry_for_word) {
// Note : The accumulator couldn't add the carry directly, so we reached its end
accumulator.m_words.append(last_carry_for_word);
}
}

View File

@ -13,18 +13,19 @@ namespace Crypto {
class UnsignedBigIntegerAlgorithms {
public:
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 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_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_not_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger& output);
static void shift_left_without_allocation(UnsignedBigInteger const& number, size_t bits_to_shift_by, UnsignedBigInteger& temp_result, UnsignedBigInteger& temp_plus, UnsignedBigInteger& output);
static void multiply_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& temp_shift_result, UnsignedBigInteger& temp_shift_plus, UnsignedBigInteger& temp_shift, UnsignedBigInteger& temp_plus, UnsignedBigInteger& output);
static void multiply_without_allocation(UnsignedBigInteger const& left, UnsignedBigInteger const& right, UnsignedBigInteger& temp_shift_result, UnsignedBigInteger& temp_shift_plus, UnsignedBigInteger& temp_shift, UnsignedBigInteger& output);
static void 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);
static void divide_u16_without_allocation(UnsignedBigInteger const& numerator, UnsignedBigInteger::Word denominator, UnsignedBigInteger& quotient, UnsignedBigInteger& remainder);
static void destructive_GCD_without_allocation(UnsignedBigInteger& temp_a, UnsignedBigInteger& temp_b, UnsignedBigInteger& temp_1, UnsignedBigInteger& temp_2, UnsignedBigInteger& temp_3, UnsignedBigInteger& temp_4, UnsignedBigInteger& temp_quotient, UnsignedBigInteger& temp_remainder, UnsignedBigInteger& output);
static void modular_inverse_without_allocation(UnsignedBigInteger const& a_, UnsignedBigInteger const& b, UnsignedBigInteger& temp_1, UnsignedBigInteger& temp_2, UnsignedBigInteger& temp_3, UnsignedBigInteger& temp_4, UnsignedBigInteger& temp_plus, UnsignedBigInteger& temp_minus, UnsignedBigInteger& temp_quotient, UnsignedBigInteger& temp_d, UnsignedBigInteger& temp_u, UnsignedBigInteger& temp_v, UnsignedBigInteger& temp_x, UnsignedBigInteger& result);
static void modular_inverse_without_allocation(UnsignedBigInteger const& a_, UnsignedBigInteger const& b, UnsignedBigInteger& temp_1, UnsignedBigInteger& temp_2, UnsignedBigInteger& temp_3, UnsignedBigInteger& temp_4, UnsignedBigInteger& temp_minus, UnsignedBigInteger& temp_quotient, UnsignedBigInteger& temp_d, UnsignedBigInteger& temp_u, UnsignedBigInteger& temp_v, UnsignedBigInteger& temp_x, UnsignedBigInteger& result);
static void destructive_modular_power_without_allocation(UnsignedBigInteger& ep, UnsignedBigInteger& base, UnsignedBigInteger const& m, UnsignedBigInteger& temp_1, UnsignedBigInteger& temp_2, UnsignedBigInteger& temp_3, UnsignedBigInteger& temp_4, UnsignedBigInteger& temp_multiply, UnsignedBigInteger& temp_quotient, UnsignedBigInteger& temp_remainder, UnsignedBigInteger& result);
private:

View File

@ -144,6 +144,15 @@ void UnsignedBigInteger::clamp_to_trimmed_length()
m_words.resize(length);
}
void UnsignedBigInteger::resize_with_leading_zeros(size_t new_length)
{
size_t old_length = length();
if (old_length < new_length) {
m_words.resize_and_keep_capacity(new_length);
__builtin_memset(&m_words.data()[old_length], 0, (new_length - old_length) * sizeof(u32));
}
}
FLATTEN UnsignedBigInteger UnsignedBigInteger::plus(const UnsignedBigInteger& other) const
{
UnsignedBigInteger result;
@ -215,9 +224,8 @@ FLATTEN UnsignedBigInteger UnsignedBigInteger::multiplied_by(const UnsignedBigIn
UnsignedBigInteger temp_shift_result;
UnsignedBigInteger temp_shift_plus;
UnsignedBigInteger temp_shift;
UnsignedBigInteger temp_plus;
UnsignedBigIntegerAlgorithms::multiply_without_allocation(*this, other, temp_shift_result, temp_shift_plus, temp_shift, temp_plus, result);
UnsignedBigIntegerAlgorithms::multiply_without_allocation(*this, other, temp_shift_result, temp_shift_plus, temp_shift, result);
return result;
}

View File

@ -65,6 +65,7 @@ public:
size_t trimmed_length() const;
void clamp_to_trimmed_length();
void resize_with_leading_zeros(size_t num_words);
UnsignedBigInteger plus(const UnsignedBigInteger& other) const;
UnsignedBigInteger minus(const UnsignedBigInteger& other) const;

View File

@ -20,7 +20,6 @@ UnsignedBigInteger ModularInverse(const UnsignedBigInteger& a_, const UnsignedBi
UnsignedBigInteger temp_2;
UnsignedBigInteger temp_3;
UnsignedBigInteger temp_4;
UnsignedBigInteger temp_plus;
UnsignedBigInteger temp_minus;
UnsignedBigInteger temp_quotient;
UnsignedBigInteger temp_d;
@ -29,7 +28,7 @@ UnsignedBigInteger ModularInverse(const UnsignedBigInteger& a_, const UnsignedBi
UnsignedBigInteger temp_x;
UnsignedBigInteger result;
UnsignedBigIntegerAlgorithms::modular_inverse_without_allocation(a_, b, temp_1, temp_2, temp_3, temp_4, temp_plus, temp_minus, temp_quotient, temp_d, temp_u, temp_v, temp_x, result);
UnsignedBigIntegerAlgorithms::modular_inverse_without_allocation(a_, b, temp_1, temp_2, temp_3, temp_4, temp_minus, temp_quotient, temp_d, temp_u, temp_v, temp_x, result);
return result;
}
@ -93,7 +92,7 @@ UnsignedBigInteger LCM(const UnsignedBigInteger& a, const UnsignedBigInteger& b)
// output = (a / gcd_output) * b
UnsignedBigIntegerAlgorithms::divide_without_allocation(a, gcd_output, temp_1, temp_2, temp_3, temp_4, temp_quotient, temp_remainder);
UnsignedBigIntegerAlgorithms::multiply_without_allocation(temp_quotient, b, temp_1, temp_2, temp_3, temp_4, output);
UnsignedBigIntegerAlgorithms::multiply_without_allocation(temp_quotient, b, temp_1, temp_2, temp_3, output);
dbgln_if(NT_DEBUG, "quot: {} rem: {} out: {}", temp_quotient, temp_remainder, output);

View File

@ -12,6 +12,7 @@
#include <LibCrypto/ASN1/ASN1.h>
#include <LibCrypto/Authentication/GHash.h>
#include <LibCrypto/Authentication/HMAC.h>
#include <LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h>
#include <LibCrypto/BigInt/SignedBigInteger.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
#include <LibCrypto/Checksum/Adler32.h>
@ -2244,6 +2245,94 @@ static void bigint_addition_edgecases()
FAIL(Incorrect Result);
}
}
{
I_TEST((BigInteger | Basic add to accumulator));
Crypto::UnsignedBigInteger num1(10);
Crypto::UnsignedBigInteger num2(70);
Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2);
if (num1.words() == Vector<u32> { 80 }) {
PASS;
} else {
FAIL(Incorrect Result);
}
}
{
I_TEST((BigInteger | Add to empty accumulator));
Crypto::UnsignedBigInteger num1({});
Crypto::UnsignedBigInteger num2(10);
Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2);
if (num1.words() == Vector<u32> { 10 }) {
PASS;
} else {
FAIL(Incorrect Result);
}
}
{
I_TEST((BigInteger | Add to smaller accumulator));
Crypto::UnsignedBigInteger num1(10);
Crypto::UnsignedBigInteger num2({ 10, 10 });
Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2);
if (num1.words() == Vector<u32> { 20, 10 }) {
PASS;
} else {
FAIL(Incorrect Result);
}
}
{
I_TEST((BigInteger | Add to accumulator with carry));
Crypto::UnsignedBigInteger num1(UINT32_MAX - 1);
Crypto::UnsignedBigInteger num2(2);
Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2);
if (num1.words() == Vector<u32> { 0, 1 }) {
PASS;
} else {
FAIL(Incorrect Result);
}
}
{
I_TEST((BigInteger | Add to accumulator with multiple carries));
Crypto::UnsignedBigInteger num1({ UINT32_MAX - 2, UINT32_MAX - 1 });
Crypto::UnsignedBigInteger num2({ 5, 1 });
Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2);
if (num1.words() == Vector<u32> { 2, 0, 1 }) {
PASS;
} else {
FAIL(Incorrect Result);
}
}
{
I_TEST((BigInteger | Add to accumulator with multiple carry levels));
Crypto::UnsignedBigInteger num1({ UINT32_MAX - 2, UINT32_MAX });
Crypto::UnsignedBigInteger num2(5);
Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2);
if (num1.words() == Vector<u32> { 2, 0, 1 }) {
PASS;
} else {
FAIL(Incorrect Result);
}
}
{
I_TEST((BigInteger | Add to accumulator with leading zero));
Crypto::UnsignedBigInteger num1(1);
Crypto::UnsignedBigInteger num2({ 1, 0 });
Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2);
if (num1.words() == Vector<u32> { 2 }) {
PASS;
} else {
FAIL(Incorrect Result);
}
}
{
I_TEST((BigInteger | Add to accumulator with carry and leading zero));
Crypto::UnsignedBigInteger num1({ UINT32_MAX, 0, 0, 0 });
Crypto::UnsignedBigInteger num2({ 1, 0 });
Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2);
if (num1.words() == Vector<u32> { 0, 1, 0, 0 }) {
PASS;
} else {
FAIL(Incorrect Result);
}
}
}
static void bigint_subtraction()