mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-10 10:09:14 +00:00
LibCrypto: Add support for shift_right more than one word
- Before: UnsignedBigInteger::shift_right( n ) trigger index verification error for n>31. An assumption of num_bits<UnsignedBigInteger::BITS_IN_WORD was being made - After: shift_right( n ) works correctly for n>31. NOTE: "bonus" change; not necessary for fixing BigFraction::to_double
This commit is contained in:
parent
add380d6e2
commit
05cfbdd6fb
Notes:
github-actions[bot]
2025-03-23 18:34:34 +00:00
Author: https://github.com/manuel-za
Commit: 05cfbdd6fb
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3174
Reviewed-by: https://github.com/alimpfard
Reviewed-by: https://github.com/trflynn89
2 changed files with 74 additions and 2 deletions
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
|
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
|
||||||
* Copyright (c) 2020-2021, Dex♪ <dexes.ttp@gmail.com>
|
* Copyright (c) 2020-2021, Dex♪ <dexes.ttp@gmail.com>
|
||||||
|
* Copyright (c) 2025, Manuel Zahariev <manuel@duck.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -221,13 +222,49 @@ FLATTEN ErrorOr<void> UnsignedBigIntegerAlgorithms::try_shift_left_without_alloc
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complexity : O(N) where N is the number of words in the number
|
||||||
|
*/
|
||||||
FLATTEN void UnsignedBigIntegerAlgorithms::shift_right_without_allocation(
|
FLATTEN void UnsignedBigIntegerAlgorithms::shift_right_without_allocation(
|
||||||
UnsignedBigInteger const& number,
|
UnsignedBigInteger const& number,
|
||||||
size_t num_bits,
|
size_t num_bits,
|
||||||
UnsignedBigInteger& output)
|
UnsignedBigInteger& output)
|
||||||
{
|
{
|
||||||
output.m_words.resize_and_keep_capacity(number.length() - (num_bits / UnsignedBigInteger::BITS_IN_WORD));
|
size_t const bit_shift = num_bits % UnsignedBigInteger::BITS_IN_WORD;
|
||||||
Ops::shift_right(number.words_span(), num_bits, output.words_span());
|
size_t const bit_shift_complement = UnsignedBigInteger::BITS_IN_WORD - bit_shift;
|
||||||
|
size_t const zero_based_index_of_highest_set_bit_in_hiword = (number.one_based_index_of_highest_set_bit() - 1) % UnsignedBigInteger::BITS_IN_WORD;
|
||||||
|
|
||||||
|
// true if the high word will be zeroed as a result of the shift
|
||||||
|
bool const hiword_zero = (bit_shift > zero_based_index_of_highest_set_bit_in_hiword);
|
||||||
|
size_t const word_shift = num_bits / UnsignedBigInteger::BITS_IN_WORD + (hiword_zero ? 1 : 0);
|
||||||
|
|
||||||
|
if (word_shift >= number.length()) { // all non-zero digits have been shifted right; result is zero
|
||||||
|
output.set_to_0();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shift_right_by_n_words(number, word_shift, output);
|
||||||
|
|
||||||
|
if (bit_shift == 0) // shifting right by an exact number of words)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t const output_length = output.length();
|
||||||
|
size_t number_index = number.length() - 1;
|
||||||
|
|
||||||
|
UnsignedBigInteger::Word carry = 0;
|
||||||
|
|
||||||
|
if (hiword_zero) {
|
||||||
|
carry = number.words().at(number_index) << bit_shift_complement;
|
||||||
|
--number_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < output_length; ++i) {
|
||||||
|
size_t const output_index = output_length - i - 1; // downto index 0
|
||||||
|
|
||||||
|
output.m_words[output_index] = ((number.m_words.at(number_index) >> bit_shift)) | carry;
|
||||||
|
carry = (number.m_words.at(number_index) << bit_shift_complement);
|
||||||
|
--number_index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnsignedBigIntegerAlgorithms::shift_left_by_n_words(
|
void UnsignedBigIntegerAlgorithms::shift_left_by_n_words(
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/Tuple.h>
|
||||||
#include <LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h>
|
#include <LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h>
|
||||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||||
|
@ -570,6 +571,40 @@ TEST_CASE(test_signed_bigint_bitwise_xor)
|
||||||
EXPECT_EQ(num2.bitwise_xor(num2), "0"_sbigint);
|
EXPECT_EQ(num2.bitwise_xor(num2), "0"_sbigint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE(test_bigint_shift_right)
|
||||||
|
{
|
||||||
|
Crypto::UnsignedBigInteger const num1(Vector<u32> { 0x100, 0x20, 0x4, 0x2, 0x1 });
|
||||||
|
|
||||||
|
size_t const tests1 = 11;
|
||||||
|
AK::Tuple<size_t, Vector<u32>> results1[] = {
|
||||||
|
{ 8, { 0x20000001, 0x04000000, 0x02000000, 0x01000000 } },
|
||||||
|
{ 16, { 0x00200000, 0x00040000, 0x00020000, 0x00010000 } }, // shift by exact number of words
|
||||||
|
{ 32, { 0x00000020, 0x00000004, 0x00000002, 0x00000001 } }, // shift by exact number of words
|
||||||
|
{ 36, { 0x40000002, 0x20000000, 0x10000000 } },
|
||||||
|
{ 64, { 0x00000004, 0x00000002, 0x00000001 } }, // shift by exact number of words
|
||||||
|
{ 72, { 0x02000000, 0x01000000 } },
|
||||||
|
{ 80, { 0x00020000, 0x00010000 } },
|
||||||
|
{ 88, { 0x00000200, 0x00000100 } },
|
||||||
|
{ 128, { 0x00000001 } }, // shifted to most significant digit
|
||||||
|
{ 129, {} }, // all digits have been shifted right
|
||||||
|
{ 160, {} },
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t const tests2 = 2;
|
||||||
|
Crypto::UnsignedBigInteger const num2(Vector<u32> { 0x44444444, 0xffffffff });
|
||||||
|
|
||||||
|
AK::Tuple<size_t, Vector<u32>> results2[] = {
|
||||||
|
{ 1, { 0xa2222222, 0x7fffffff } },
|
||||||
|
{ 2, { 0xd1111111, 0x3fffffff } },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < tests1; ++i)
|
||||||
|
EXPECT_EQ(num1.shift_right(results1[i].get<0>()).words(), results1[i].get<1>());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < tests2; ++i)
|
||||||
|
EXPECT_EQ(num2.shift_right(results2[i].get<0>()).words(), results2[i].get<1>());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE(test_signed_bigint_fibo500)
|
TEST_CASE(test_signed_bigint_fibo500)
|
||||||
{
|
{
|
||||||
Vector<u32> expected_result {
|
Vector<u32> expected_result {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue