mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:37:43 +00:00
LibCrypto: Small fixes in BigInteger & test-crypto
This commit is contained in:
parent
8ad48cca29
commit
d008a38f93
3 changed files with 121 additions and 122 deletions
|
@ -29,6 +29,41 @@
|
||||||
|
|
||||||
namespace Crypto {
|
namespace Crypto {
|
||||||
|
|
||||||
|
UnsignedBigInteger UnsignedBigInteger::create_invalid()
|
||||||
|
{
|
||||||
|
UnsignedBigInteger invalid(0);
|
||||||
|
invalid.invalidate();
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: in great need of optimisation
|
||||||
|
UnsignedBigInteger UnsignedBigInteger::import_data(const u8* ptr, size_t length)
|
||||||
|
{
|
||||||
|
UnsignedBigInteger integer { 0 };
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; ++i) {
|
||||||
|
auto part = UnsignedBigInteger { ptr[length - i - 1] }.shift_left(8 * i);
|
||||||
|
integer = integer.plus(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
return integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UnsignedBigInteger::export_data(AK::ByteBuffer& data)
|
||||||
|
{
|
||||||
|
UnsignedBigInteger copy { *this };
|
||||||
|
|
||||||
|
size_t size = trimmed_length() * sizeof(u32);
|
||||||
|
size_t i = 0;
|
||||||
|
for (; i < size; ++i) {
|
||||||
|
if (copy.length() == 0)
|
||||||
|
break;
|
||||||
|
data[size - i - 1] = copy.m_words[0] & 0xff;
|
||||||
|
copy = copy.divided_by(256).quotient;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
UnsignedBigInteger UnsignedBigInteger::from_base10(const String& str)
|
UnsignedBigInteger UnsignedBigInteger::from_base10(const String& str)
|
||||||
{
|
{
|
||||||
UnsignedBigInteger result;
|
UnsignedBigInteger result;
|
||||||
|
@ -61,9 +96,14 @@ String UnsignedBigInteger::to_base10() const
|
||||||
return builder.to_string();
|
return builder.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnsignedBigInteger::operator!=(const UnsignedBigInteger& other) const
|
size_t UnsignedBigInteger::trimmed_length() const
|
||||||
{
|
{
|
||||||
return !(*this == other);
|
size_t num_leading_zeroes = 0;
|
||||||
|
for (int i = length() - 1; i >= 0; --i, ++num_leading_zeroes) {
|
||||||
|
if (m_words[i] != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return length() - num_leading_zeroes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,6 +181,32 @@ UnsignedBigInteger UnsignedBigInteger::minus(const UnsignedBigInteger& other) co
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnsignedBigInteger UnsignedBigInteger::shift_left(size_t num_bits) const
|
||||||
|
{
|
||||||
|
// We can only do shift operations on individual words
|
||||||
|
// where the shift amount is <= size of word (32).
|
||||||
|
// But we do know how to shift by a multiple of word size (e.g 64=32*2)
|
||||||
|
// So we first shift the result by how many whole words fit in 'num_bits'
|
||||||
|
UnsignedBigInteger temp_result = shift_left_by_n_words(num_bits / UnsignedBigInteger::BITS_IN_WORD);
|
||||||
|
|
||||||
|
// And now we shift by the leftover amount of bits
|
||||||
|
num_bits %= UnsignedBigInteger::BITS_IN_WORD;
|
||||||
|
|
||||||
|
UnsignedBigInteger result(temp_result);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < temp_result.length(); ++i) {
|
||||||
|
u32 current_word_of_temp_result = temp_result.shift_left_get_one_word(num_bits, i);
|
||||||
|
result.m_words[i] = current_word_of_temp_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shifting the last word can produce a carry
|
||||||
|
u32 carry_word = temp_result.shift_left_get_one_word(num_bits, temp_result.length());
|
||||||
|
if (carry_word != 0) {
|
||||||
|
result = result.plus(UnsignedBigInteger(carry_word).shift_left_by_n_words(temp_result.length()));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complexity: O(N^2) where N is the number of words in the larger number
|
* Complexity: O(N^2) where N is the number of words in the larger number
|
||||||
* Multiplcation method:
|
* Multiplcation method:
|
||||||
|
@ -210,30 +276,48 @@ void UnsignedBigInteger::set_bit_inplace(size_t bit_index)
|
||||||
m_words[word_index] |= (1 << inner_word_index);
|
m_words[word_index] |= (1 << inner_word_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedBigInteger UnsignedBigInteger::shift_left(size_t num_bits) const
|
bool UnsignedBigInteger::operator==(const UnsignedBigInteger& other) const
|
||||||
{
|
{
|
||||||
// We can only do shift operations on individual words
|
auto length = trimmed_length();
|
||||||
// where the shift amount is <= size of word (32).
|
|
||||||
// But we do know how to shift by a multiple of word size (e.g 64=32*2)
|
|
||||||
// So we first shift the result by how many whole words fit in 'num_bits'
|
|
||||||
UnsignedBigInteger temp_result = shift_left_by_n_words(num_bits / UnsignedBigInteger::BITS_IN_WORD);
|
|
||||||
|
|
||||||
// And now we shift by the leftover amount of bits
|
if (length != other.trimmed_length()) {
|
||||||
num_bits %= UnsignedBigInteger::BITS_IN_WORD;
|
return false;
|
||||||
|
|
||||||
UnsignedBigInteger result(temp_result);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < temp_result.length(); ++i) {
|
|
||||||
u32 current_word_of_temp_result = temp_result.shift_left_get_one_word(num_bits, i);
|
|
||||||
result.m_words[i] = current_word_of_temp_result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shifting the last word can produce a carry
|
if (is_invalid() != other.is_invalid()) {
|
||||||
u32 carry_word = temp_result.shift_left_get_one_word(num_bits, temp_result.length());
|
return false;
|
||||||
if (carry_word != 0) {
|
|
||||||
result = result.plus(UnsignedBigInteger(carry_word).shift_left_by_n_words(temp_result.length()));
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
return !__builtin_memcmp(m_words.data(), other.words().data(), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnsignedBigInteger::operator!=(const UnsignedBigInteger& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnsignedBigInteger::operator<(const UnsignedBigInteger& other) const
|
||||||
|
{
|
||||||
|
auto length = trimmed_length();
|
||||||
|
auto other_length = other.trimmed_length();
|
||||||
|
|
||||||
|
if (length < other_length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > other_length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = length - 1; i >= 0; --i) {
|
||||||
|
if (m_words[i] == other.m_words[i])
|
||||||
|
continue;
|
||||||
|
return m_words[i] < other.m_words[i];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE UnsignedBigInteger UnsignedBigInteger::shift_left_by_n_words(const size_t number_of_words) const
|
ALWAYS_INLINE UnsignedBigInteger UnsignedBigInteger::shift_left_by_n_words(const size_t number_of_words) const
|
||||||
|
@ -272,88 +356,4 @@ ALWAYS_INLINE u32 UnsignedBigInteger::shift_left_get_one_word(const size_t num_b
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnsignedBigInteger::operator==(const UnsignedBigInteger& other) const
|
|
||||||
{
|
|
||||||
auto length = trimmed_length();
|
|
||||||
|
|
||||||
if (length != other.trimmed_length()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_invalid() != other.is_invalid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !__builtin_memcmp(m_words.data(), other.words().data(), length);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UnsignedBigInteger::operator<(const UnsignedBigInteger& other) const
|
|
||||||
{
|
|
||||||
auto length = trimmed_length();
|
|
||||||
auto other_length = other.trimmed_length();
|
|
||||||
|
|
||||||
if (length < other_length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length > other_length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int i = length - 1; i >= 0; --i) {
|
|
||||||
if (m_words[i] == other.m_words[i])
|
|
||||||
continue;
|
|
||||||
return m_words[i] < other.m_words[i];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t UnsignedBigInteger::trimmed_length() const
|
|
||||||
{
|
|
||||||
size_t num_leading_zeroes = 0;
|
|
||||||
for (int i = length() - 1; i >= 0; --i, ++num_leading_zeroes) {
|
|
||||||
if (m_words[i] != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return length() - num_leading_zeroes;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnsignedBigInteger UnsignedBigInteger::create_invalid()
|
|
||||||
{
|
|
||||||
UnsignedBigInteger invalid(0);
|
|
||||||
invalid.invalidate();
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: in great need of optimisation
|
|
||||||
UnsignedBigInteger UnsignedBigInteger::import_data(const u8* ptr, size_t length)
|
|
||||||
{
|
|
||||||
UnsignedBigInteger integer { 0 };
|
|
||||||
|
|
||||||
for (size_t i = 0; i < length; ++i) {
|
|
||||||
auto part = UnsignedBigInteger { ptr[length - i - 1] }.shift_left(8 * i);
|
|
||||||
integer = integer.plus(part);
|
|
||||||
}
|
|
||||||
|
|
||||||
return integer;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t UnsignedBigInteger::export_data(AK::ByteBuffer& data)
|
|
||||||
{
|
|
||||||
UnsignedBigInteger copy { *this };
|
|
||||||
|
|
||||||
size_t size = trimmed_length() * sizeof(u32);
|
|
||||||
size_t i = 0;
|
|
||||||
for (; i < size; ++i) {
|
|
||||||
if (copy.length() == 0)
|
|
||||||
break;
|
|
||||||
data[size - i - 1] = copy.m_words[0] & 0xff;
|
|
||||||
copy = copy.divided_by(256).quotient;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,13 +41,12 @@ public:
|
||||||
UnsignedBigInteger(u32 x) { m_words.append(x); }
|
UnsignedBigInteger(u32 x) { m_words.append(x); }
|
||||||
|
|
||||||
explicit UnsignedBigInteger(AK::Vector<u32, STARTING_WORD_SIZE>&& words)
|
explicit UnsignedBigInteger(AK::Vector<u32, STARTING_WORD_SIZE>&& words)
|
||||||
: m_words(words)
|
: m_words(move(words))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedBigInteger() { }
|
UnsignedBigInteger() {}
|
||||||
|
|
||||||
static UnsignedBigInteger from_base10(const String& str);
|
|
||||||
static UnsignedBigInteger create_invalid();
|
static UnsignedBigInteger create_invalid();
|
||||||
|
|
||||||
static UnsignedBigInteger import_data(const AK::StringView& data) { return import_data((const u8*)data.characters_without_null_termination(), data.length()); }
|
static UnsignedBigInteger import_data(const AK::StringView& data) { return import_data((const u8*)data.characters_without_null_termination(), data.length()); }
|
||||||
|
@ -60,31 +59,31 @@ public:
|
||||||
return export_data(buffer);
|
return export_data(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UnsignedBigInteger from_base10(const String& str);
|
||||||
|
String to_base10() const;
|
||||||
|
|
||||||
const AK::Vector<u32, STARTING_WORD_SIZE>& words() const { return m_words; }
|
const AK::Vector<u32, STARTING_WORD_SIZE>& words() const { return m_words; }
|
||||||
|
|
||||||
|
void invalidate() { m_is_invalid = true; }
|
||||||
|
|
||||||
|
bool is_invalid() const { return m_is_invalid; }
|
||||||
|
|
||||||
|
size_t length() const { return m_words.size(); }
|
||||||
|
// The "trimmed length" is the number of words after trimming leading zeroed words
|
||||||
|
size_t trimmed_length() const;
|
||||||
|
|
||||||
UnsignedBigInteger plus(const UnsignedBigInteger& other) const;
|
UnsignedBigInteger plus(const UnsignedBigInteger& other) const;
|
||||||
UnsignedBigInteger minus(const UnsignedBigInteger& other) const;
|
UnsignedBigInteger minus(const UnsignedBigInteger& other) const;
|
||||||
UnsignedBigInteger multiplied_by(const UnsignedBigInteger& other) const;
|
|
||||||
UnsignedBigInteger shift_left(size_t num_bits) const;
|
UnsignedBigInteger shift_left(size_t num_bits) const;
|
||||||
|
UnsignedBigInteger multiplied_by(const UnsignedBigInteger& other) const;
|
||||||
UnsignedDivisionResult divided_by(const UnsignedBigInteger& divisor) const;
|
UnsignedDivisionResult divided_by(const UnsignedBigInteger& divisor) const;
|
||||||
|
|
||||||
void set_bit_inplace(size_t bit_index);
|
void set_bit_inplace(size_t bit_index);
|
||||||
|
|
||||||
size_t length() const { return m_words.size(); }
|
|
||||||
|
|
||||||
// The "trimmed length" is the number of words after trimming leading zeroed words
|
|
||||||
size_t trimmed_length() const;
|
|
||||||
|
|
||||||
bool operator==(const UnsignedBigInteger& other) const;
|
bool operator==(const UnsignedBigInteger& other) const;
|
||||||
bool operator!=(const UnsignedBigInteger& other) 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:
|
private:
|
||||||
ALWAYS_INLINE UnsignedBigInteger shift_left_by_n_words(const size_t number_of_words) const;
|
ALWAYS_INLINE UnsignedBigInteger shift_left_by_n_words(const size_t number_of_words) const;
|
||||||
ALWAYS_INLINE u32 shift_left_get_one_word(const size_t num_bits, const size_t result_word_index) const;
|
ALWAYS_INLINE u32 shift_left_get_one_word(const size_t num_bits, const size_t result_word_index) const;
|
||||||
|
|
|
@ -1341,7 +1341,7 @@ void bigint_subtraction()
|
||||||
PASS;
|
PASS;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
I_TEST((BigInteger | Subtraction Regerssion 1));
|
I_TEST((BigInteger | Subtraction Regression 1));
|
||||||
auto num = Crypto::UnsignedBigInteger { 1 }.shift_left(256);
|
auto num = Crypto::UnsignedBigInteger { 1 }.shift_left(256);
|
||||||
if (num.minus(1).words() == Vector<u32> { 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 0 }) {
|
if (num.minus(1).words() == Vector<u32> { 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 0 }) {
|
||||||
PASS;
|
PASS;
|
||||||
|
@ -1354,7 +1354,7 @@ void bigint_subtraction()
|
||||||
void bigint_multiplication()
|
void bigint_multiplication()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
I_TEST((BigInteger | Simple Multipliction));
|
I_TEST((BigInteger | Simple Multiplication));
|
||||||
Crypto::UnsignedBigInteger num1(8);
|
Crypto::UnsignedBigInteger num1(8);
|
||||||
Crypto::UnsignedBigInteger num2(251);
|
Crypto::UnsignedBigInteger num2(251);
|
||||||
Crypto::UnsignedBigInteger result = num1.multiplied_by(num2);
|
Crypto::UnsignedBigInteger result = num1.multiplied_by(num2);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue