소스 검색

LibCrypto: Add a += operation to UnsignedBigIntegerAlgorithms

This new operation is immediately used in several existing algorithms.
DexesTTP 4 년 전
부모
커밋
5071989545

+ 1 - 2
Userland/Libraries/LibCrypto/BigInt/Algorithms/BitwiseOperations.cpp

@@ -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);
     }
 }
 

+ 5 - 11
Userland/Libraries/LibCrypto/BigInt/Algorithms/ModularInverse.cpp

@@ -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

+ 2 - 2
Userland/Libraries/LibCrypto/BigInt/Algorithms/ModularPower.cpp

@@ -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);
 

+ 1 - 3
Userland/Libraries/LibCrypto/BigInt/Algorithms/Multiplication.cpp

@@ -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);
         }
     }
 }

+ 37 - 22
Userland/Libraries/LibCrypto/BigInt/Algorithms/SimpleOperations.cpp

@@ -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();
+
+    // If needed, resize the accumulator so it can fit the value.
+    accumulator.resize_with_leading_zeros(value_length);
+    auto final_length = accumulator.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;
+    // 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);
     }
 }
 

+ 3 - 2
Userland/Libraries/LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h

@@ -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:

+ 10 - 2
Userland/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp

@@ -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;
 }

+ 1 - 0
Userland/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h

@@ -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;

+ 2 - 3
Userland/Libraries/LibCrypto/NumberTheory/ModularFunctions.cpp

@@ -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);
 

+ 89 - 0
Userland/Utilities/test-crypto.cpp

@@ -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()