diff --git a/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp b/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp index cd83568abb..b682704a2e 100644 --- a/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp +++ b/Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp @@ -25,9 +25,45 @@ */ #include "UnsignedBigInteger.h" +#include 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(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 */ diff --git a/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h b/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h index d412bd41bf..dae419c9e6 100644 --- a/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h +++ b/Libraries/LibCrypto/BigInt/UnsignedBigInteger.h @@ -26,6 +26,7 @@ #pragma once #include +#include #include #include @@ -44,6 +45,7 @@ public: UnsignedBigInteger() {} + static UnsignedBigInteger from_base10(const String& str); static UnsignedBigInteger create_invalid(); const AK::Vector& 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"; diff --git a/Userland/test-crypto.cpp b/Userland/test-crypto.cpp index 39e0895daa..7496a3df07 100644 --- a/Userland/test-crypto.cpp +++ b/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 { 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 { 3806301393, 954919431, 3879607298, 721 }) { + PASS; + } else { + FAIL(Incorrect Result); + } + } + { + I_TEST((BigInteger | To String)); + auto result = Crypto::UnsignedBigInteger { Vector { 3806301393, 954919431, 3879607298, 721 } }.to_base10(); + if (result == "57195071295721390579057195715793") { + PASS; + } else { + FAIL(Incorrect Result); + } + } +}