Ver código fonte

LibCrypto: Add base-10 string de/serialization methods for bigint

Itamar 5 anos atrás
pai
commit
2125a4debb

+ 36 - 0
Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp

@@ -25,9 +25,45 @@
  */
 
 #include "UnsignedBigInteger.h"
+#include <AK/StringBuilder.h>
 
 namespace Crypto {
 
+UnsignedBigInteger UnsignedBigInteger::from_base10(const String& str)
+{
+    UnsignedBigInteger result;
+    for (auto& c : str) {
+        result = result.multiply({ 10 }).add(c - '0');
+    }
+    return result;
+}
+
+String UnsignedBigInteger::to_base10() const
+{
+    StringBuilder builder;
+    UnsignedBigInteger temp(*this);
+
+    while (temp != UnsignedBigInteger { 0 }) {
+        auto div_result = temp.divide({ 10 });
+        ASSERT(div_result.remainder.words()[0] < 10);
+        builder.append(static_cast<char>(div_result.remainder.words()[0] + '0'));
+        temp = div_result.quotient;
+    }
+
+    auto reversed_string = builder.to_string();
+    builder.clear();
+    for (int i = reversed_string.length() - 1; i >= 0; --i) {
+        builder.append(reversed_string[i]);
+    }
+
+    return builder.to_string();
+}
+
+bool UnsignedBigInteger::operator!=(const UnsignedBigInteger& other) const
+{
+    return !(*this == other);
+}
+
 /**
  * Complexity: O(N) where N is the number of words in the larger number
  */

+ 7 - 1
Libraries/LibCrypto/BigInt/UnsignedBigInteger.h

@@ -26,6 +26,7 @@
 
 #pragma once
 #include <AK/LogStream.h>
+#include <AK/String.h>
 #include <AK/Types.h>
 #include <AK/Vector.h>
 
@@ -44,6 +45,7 @@ public:
 
     UnsignedBigInteger() {}
 
+    static UnsignedBigInteger from_base10(const String& str);
     static UnsignedBigInteger create_invalid();
 
     const AK::Vector<u32>& words() const { return m_words; }
@@ -63,11 +65,14 @@ public:
     size_t trimmed_length() const;
 
     bool operator==(const UnsignedBigInteger& other) const;
+    bool operator!=(const UnsignedBigInteger& other) const;
     bool operator<(const UnsignedBigInteger& other) const;
 
     void invalidate() { m_is_invalid = true; }
     bool is_invalid() const { return m_is_invalid; }
 
+    String to_base10() const;
+
 private:
     UnsignedBigInteger shift_left_by_n_words(const size_t number_of_words) const;
     u32 shift_left_get_one_word(const size_t num_bits, const size_t result_word_index) const;
@@ -86,7 +91,8 @@ struct UnsignedDivisionResult {
 
 }
 
-inline const LogStream& operator<<(const LogStream& stream, const Crypto::UnsignedBigInteger value)
+inline const LogStream&
+operator<<(const LogStream& stream, const Crypto::UnsignedBigInteger value)
 {
     if (value.is_invalid()) {
         stream << "Invalid BigInt";

+ 24 - 1
Userland/test-crypto.cpp

@@ -307,6 +307,7 @@ void bigint_addition_edgecases();
 void bigint_subtraction();
 void bigint_multiplication();
 void bigint_division();
+void bigint_base10();
 
 int aes_cbc_tests()
 {
@@ -803,6 +804,7 @@ int bigint_tests()
     bigint_subtraction();
     bigint_multiplication();
     bigint_division();
+    bigint_base10();
     return 0;
 }
 
@@ -933,7 +935,6 @@ void bigint_multiplication()
         Crypto::UnsignedBigInteger num1(8);
         Crypto::UnsignedBigInteger num2(251);
         Crypto::UnsignedBigInteger result = num1.multiply(num2);
-        dbg() << "result: " << result;
         if (result.words() == Vector<u32> { 2008 }) {
             PASS;
         } else {
@@ -1004,3 +1005,25 @@ void bigint_division()
         }
     }
 }
+
+void bigint_base10()
+{
+    {
+        I_TEST((BigInteger | From String));
+        auto result = Crypto::UnsignedBigInteger::from_base10("57195071295721390579057195715793");
+        if (result.words() == Vector<u32> { 3806301393, 954919431, 3879607298, 721 }) {
+            PASS;
+        } else {
+            FAIL(Incorrect Result);
+        }
+    }
+    {
+        I_TEST((BigInteger | To String));
+        auto result = Crypto::UnsignedBigInteger { Vector<u32> { 3806301393, 954919431, 3879607298, 721 } }.to_base10();
+        if (result == "57195071295721390579057195715793") {
+            PASS;
+        } else {
+            FAIL(Incorrect Result);
+        }
+    }
+}