/* * Copyright (c) 2021, Peter Bocan * Copyright (c) 2025, Manuel Zahariev * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include static Crypto::UnsignedBigInteger bigint_fibonacci(size_t n) { Crypto::UnsignedBigInteger num1(0); Crypto::UnsignedBigInteger num2(1); for (size_t i = 0; i < n; ++i) { Crypto::UnsignedBigInteger t = num1.plus(num2); num2 = num1; num1 = t; } return num1; } static Crypto::SignedBigInteger bigint_signed_fibonacci(size_t n) { Crypto::SignedBigInteger num1(0); Crypto::SignedBigInteger num2(1); for (size_t i = 0; i < n; ++i) { Crypto::SignedBigInteger t = num1.plus(num2); num2 = num1; num1 = t; } return num1; } TEST_CASE(test_bigint_fib500) { Vector result { 315178285, 505575602, 1883328078, 125027121, 3649625763, 347570207, 74535262, 3832543808, 2472133297, 1600064941, 65273441 }; EXPECT_EQ(bigint_fibonacci(500).words(), result); } BENCHMARK_CASE(bench_bigint_fib100000) { auto res = bigint_fibonacci(100000); (void)res; } TEST_CASE(test_unsigned_bigint_addition_initialization) { Crypto::UnsignedBigInteger num1; Crypto::UnsignedBigInteger num2(70); Crypto::UnsignedBigInteger num3 = num1.plus(num2); bool pass = (num3 == num2); pass &= (num1 == Crypto::UnsignedBigInteger(0)); EXPECT(pass); } TEST_CASE(test_unsigned_bigint_addition_borrow_with_zero) { Crypto::UnsignedBigInteger num1({ UINT32_MAX - 3, UINT32_MAX }); Crypto::UnsignedBigInteger num2({ UINT32_MAX - 2, 0 }); Vector expected_result { 4294967289, 0, 1 }; EXPECT_EQ(num1.plus(num2).words(), expected_result); } TEST_CASE(test_unsigned_bigint_basic_add_to_accumulator) { Crypto::UnsignedBigInteger num1(10); Crypto::UnsignedBigInteger num2(70); Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2); EXPECT_EQ(num1.words(), Vector { 80 }); } TEST_CASE(test_unsigned_bigint_basic_add_to_empty_accumulator) { Crypto::UnsignedBigInteger num1 {}; Crypto::UnsignedBigInteger num2(10); Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2); EXPECT_EQ(num1.words(), Vector { 10 }); } TEST_CASE(test_unsigned_bigint_basic_add_to_smaller_accumulator) { Crypto::UnsignedBigInteger num1(10); Crypto::UnsignedBigInteger num2({ 10, 10 }); Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2); Vector expected_result { 20, 10 }; EXPECT_EQ(num1.words(), expected_result); } TEST_CASE(test_unsigned_bigint_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); Vector expected_result { 2, 0, 1 }; EXPECT_EQ(num1.words(), expected_result); } TEST_CASE(test_unsigned_bigint_add_to_accumulator_with_leading_zero) { Crypto::UnsignedBigInteger num1(1); Crypto::UnsignedBigInteger num2({ 1, 0 }); Crypto::UnsignedBigIntegerAlgorithms::add_into_accumulator_without_allocation(num1, num2); EXPECT_EQ(num1.words(), Vector { 2 }); } TEST_CASE(test_unsigned_bigint_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); Vector expected_result { 0, 1, 0, 0 }; EXPECT_EQ(num1.words(), expected_result); } TEST_CASE(test_unsigned_bigint_simple_subtraction) { Crypto::UnsignedBigInteger num1(80); Crypto::UnsignedBigInteger num2(70); EXPECT_EQ(TRY_OR_FAIL(num1.minus(num2)), Crypto::UnsignedBigInteger(10)); } TEST_CASE(test_unsigned_bigint_simple_subtraction_invalid) { Crypto::UnsignedBigInteger num1(50); Crypto::UnsignedBigInteger num2(70); EXPECT(num1.minus(num2).is_error()); } TEST_CASE(test_unsigned_bigint_simple_subtraction_with_borrow) { Crypto::UnsignedBigInteger num1(UINT32_MAX); Crypto::UnsignedBigInteger num2(1); Crypto::UnsignedBigInteger num3 = num1.plus(num2); Crypto::UnsignedBigInteger result = TRY_OR_FAIL(num3.minus(num2)); EXPECT_EQ(result, num1); } TEST_CASE(test_unsigned_bigint_subtraction_with_large_numbers) { Crypto::UnsignedBigInteger num1 = bigint_fibonacci(343); Crypto::UnsignedBigInteger num2 = bigint_fibonacci(218); Crypto::UnsignedBigInteger result = TRY_OR_FAIL(num1.minus(num2)); Vector expected_result { 811430588, 2958904896, 1130908877, 2830569969, 3243275482, 3047460725, 774025231, 7990 }; EXPECT_EQ(result.plus(num2), num1); EXPECT_EQ(result.words(), expected_result); } TEST_CASE(test_unsigned_bigint_subtraction_with_large_numbers2) { Crypto::UnsignedBigInteger num1(Vector { 1483061863, 446680044, 1123294122, 191895498, 3347106536, 16, 0, 0, 0 }); Crypto::UnsignedBigInteger num2(Vector { 4196414175, 1117247942, 1123294122, 191895498, 3347106536, 16 }); ErrorOr result = num1.minus(num2); // this test only verifies that we don't crash on an assertion } TEST_CASE(test_unsigned_bigint_subtraction_regression_1) { auto num = Crypto::UnsignedBigInteger { 1 }.shift_left(256); Vector expected_result { 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 0 }; EXPECT_EQ(TRY_OR_FAIL(num.minus(1)).words(), expected_result); } TEST_CASE(test_unsigned_bigint_simple_multiplication) { Crypto::UnsignedBigInteger num1(8); Crypto::UnsignedBigInteger num2(251); Crypto::UnsignedBigInteger result = num1.multiplied_by(num2); EXPECT_EQ(result.words(), Vector { 2008 }); } TEST_CASE(test_unsigned_bigint_multiplication_with_big_numbers1) { Crypto::UnsignedBigInteger num1 = bigint_fibonacci(200); Crypto::UnsignedBigInteger num2(12345678); Crypto::UnsignedBigInteger result = num1.multiplied_by(num2); Vector expected_result { 669961318, 143970113, 4028714974, 3164551305, 1589380278, 2 }; EXPECT_EQ(result.words(), expected_result); } TEST_CASE(test_unsigned_bigint_multiplication_with_big_numbers2) { Crypto::UnsignedBigInteger num1 = bigint_fibonacci(200); Crypto::UnsignedBigInteger num2 = bigint_fibonacci(341); Crypto::UnsignedBigInteger result = num1.multiplied_by(num2); Vector expected_result { 3017415433, 2741793511, 1957755698, 3731653885, 3154681877, 785762127, 3200178098, 4260616581, 529754471, 3632684436, 1073347813, 2516430 }; EXPECT_EQ(result.words(), expected_result); } TEST_CASE(test_unsigned_bigint_simple_division) { Crypto::UnsignedBigInteger num1(27194); Crypto::UnsignedBigInteger num2(251); auto result = num1.divided_by(num2); Crypto::UnsignedDivisionResult expected = { Crypto::UnsignedBigInteger(108), Crypto::UnsignedBigInteger(86) }; EXPECT_EQ(result.quotient, expected.quotient); EXPECT_EQ(result.remainder, expected.remainder); } TEST_CASE(test_unsigned_bigint_division_with_big_numbers) { Crypto::UnsignedBigInteger num1 = bigint_fibonacci(386); Crypto::UnsignedBigInteger num2 = bigint_fibonacci(238); auto result = num1.divided_by(num2); Crypto::UnsignedDivisionResult expected = { Crypto::UnsignedBigInteger(Vector { 2300984486, 2637503534, 2022805584, 107 }), Crypto::UnsignedBigInteger(Vector { 1483061863, 446680044, 1123294122, 191895498, 3347106536, 16, 0, 0, 0 }) }; EXPECT_EQ(result.quotient, expected.quotient); EXPECT_EQ(result.remainder, expected.remainder); } TEST_CASE(test_unsigned_bigint_division_combined_test) { auto num1 = bigint_fibonacci(497); auto num2 = bigint_fibonacci(238); auto div_result = num1.divided_by(num2); EXPECT_EQ(div_result.quotient.multiplied_by(num2).plus(div_result.remainder), num1); } TEST_CASE(test_unsigned_bigint_base10_from_string) { auto result = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(10, "57195071295721390579057195715793"sv)); Vector expected_result { 3806301393, 954919431, 3879607298, 721 }; EXPECT_EQ(result.words(), expected_result); Vector invalid_base10_number_strings { "1A"sv, "1:"sv, "Z1"sv, "1/"sv }; for (auto invalid_base10_number_string : invalid_base10_number_strings) EXPECT_EQ(Crypto::UnsignedBigInteger::from_base(10, invalid_base10_number_string).is_error(), true); } TEST_CASE(test_unsigned_bigint_base10_to_string) { auto bigint = Crypto::UnsignedBigInteger { Vector { 3806301393, 954919431, 3879607298, 721 } }; auto result = MUST(bigint.to_base(10)); EXPECT_EQ(result, "57195071295721390579057195715793"); } TEST_CASE(test_bigint_import_big_endian_decode_encode_roundtrip) { u8 random_bytes[128]; u8 target_buffer[128]; fill_with_random(random_bytes); auto encoded = Crypto::UnsignedBigInteger::import_data(random_bytes, 128); encoded.export_data({ target_buffer, 128 }); EXPECT(memcmp(target_buffer, random_bytes, 128) == 0); } TEST_CASE(test_bigint_import_big_endian_encode_decode_roundtrip) { u8 target_buffer[128]; auto encoded = "12345678901234567890"_bigint; auto size = encoded.export_data({ target_buffer, 128 }); auto decoded = Crypto::UnsignedBigInteger::import_data(target_buffer, size); EXPECT_EQ(encoded, decoded); } TEST_CASE(test_bigint_big_endian_import) { auto number = Crypto::UnsignedBigInteger::import_data("hello"sv); EXPECT_EQ(number, "448378203247"_bigint); } TEST_CASE(test_bigint_big_endian_export) { auto number = "448378203247"_bigint; char exported[8] { 0 }; auto exported_length = number.export_data({ exported, 8 }, true); EXPECT_EQ(exported_length, 5u); EXPECT(memcmp(exported + 3, "hello", 5) == 0); } TEST_CASE(test_bigint_one_based_index_of_highest_set_bit) { auto num1 = "1234567"_bigint; auto num2 = "1234567"_bigint; EXPECT_EQ("0"_bigint.one_based_index_of_highest_set_bit(), 0u); EXPECT_EQ("1"_bigint.one_based_index_of_highest_set_bit(), 1u); EXPECT_EQ("7"_bigint.one_based_index_of_highest_set_bit(), 3u); EXPECT_EQ("4294967296"_bigint.one_based_index_of_highest_set_bit(), 33u); } TEST_CASE(test_signed_bigint_bitwise_not_fill_to_one_based_index) { EXPECT_EQ("0"_bigint.bitwise_not_fill_to_one_based_index(0), "0"_bigint); EXPECT_EQ("0"_bigint.bitwise_not_fill_to_one_based_index(1), "1"_bigint); EXPECT_EQ("0"_bigint.bitwise_not_fill_to_one_based_index(2), "3"_bigint); EXPECT_EQ("0"_bigint.bitwise_not_fill_to_one_based_index(4), "15"_bigint); EXPECT_EQ("0"_bigint.bitwise_not_fill_to_one_based_index(32), "4294967295"_bigint); EXPECT_EQ("0"_bigint.bitwise_not_fill_to_one_based_index(33), "8589934591"_bigint); } TEST_CASE(test_bigint_bitwise_or) { auto num1 = "1234567"_bigint; auto num2 = "1234567"_bigint; EXPECT_EQ(num1.bitwise_or(num2), num1); } TEST_CASE(test_bigint_bitwise_or_different_lengths) { auto num1 = "1234567"_bigint; auto num2 = "123456789012345678901234567890"_bigint; auto expected = "123456789012345678901234622167"_bigint; auto result = num1.bitwise_or(num2); EXPECT_EQ(result, expected); } TEST_CASE(test_signed_bigint_bitwise_or) { auto num1 = "-1234567"_sbigint; auto num2 = "1234567"_sbigint; EXPECT_EQ(num1.bitwise_or(num1), num1); EXPECT_EQ(num1.bitwise_or(num2), "-1"_sbigint); EXPECT_EQ(num2.bitwise_or(num1), "-1"_sbigint); EXPECT_EQ(num2.bitwise_or(num2), num2); EXPECT_EQ("0"_sbigint.bitwise_or("-1"_sbigint), "-1"_sbigint); } TEST_CASE(test_bigint_bitwise_and) { auto num1 = "1234567"_bigint; auto num2 = "1234561"_bigint; EXPECT_EQ(num1.bitwise_and(num2), "1234561"_bigint); } TEST_CASE(test_bigint_bitwise_and_different_lengths) { auto num1 = "1234567"_bigint; auto num2 = "123456789012345678901234567890"_bigint; EXPECT_EQ(num1.bitwise_and(num2), "1180290"_bigint); } TEST_CASE(test_signed_bigint_bitwise_not) { EXPECT_EQ("3"_sbigint.bitwise_not(), "-4"_sbigint); EXPECT_EQ("-1"_sbigint.bitwise_not(), "0"_sbigint); } TEST_CASE(test_signed_bigint_bitwise_and) { auto num1 = "-1234567"_sbigint; auto num2 = "1234567"_sbigint; EXPECT_EQ(num1.bitwise_and(num1), num1); EXPECT_EQ(num1.bitwise_and(num2), "1"_sbigint); EXPECT_EQ(num2.bitwise_and(num1), "1"_sbigint); EXPECT_EQ(num2.bitwise_and(num2), num2); EXPECT_EQ("-3"_sbigint.bitwise_and("-2"_sbigint), "-4"_sbigint); } TEST_CASE(test_bigint_bitwise_xor) { auto num1 = "1234567"_bigint; auto num2 = "1234561"_bigint; EXPECT_EQ(num1.bitwise_xor(num2), 6); } TEST_CASE(test_bigint_bitwise_xor_different_lengths) { auto num1 = "1234567"_bigint; auto num2 = "123456789012345678901234567890"_bigint; EXPECT_EQ(num1.bitwise_xor(num2), "123456789012345678901233441877"_bigint); } TEST_CASE(test_signed_bigint_bitwise_xor) { auto num1 = "-3"_sbigint; auto num2 = "1"_sbigint; EXPECT_EQ(num1.bitwise_xor(num1), "0"_sbigint); EXPECT_EQ(num1.bitwise_xor(num2), "-4"_sbigint); EXPECT_EQ(num2.bitwise_xor(num1), "-4"_sbigint); EXPECT_EQ(num2.bitwise_xor(num2), "0"_sbigint); } TEST_CASE(test_bigint_shift_left) { Crypto::UnsignedBigInteger const num(Vector { 0x22222222, 0xffffffff }); size_t const tests = 8; AK::Tuple> results[] = { { 0, { 0x22222222, 0xffffffff } }, { 8, { 0x22222200, 0xffffff22, 0x000000ff } }, { 16, { 0x22220000, 0xffff2222, 0x0000ffff } }, { 32, { 0x00000000, 0x22222222, 0xffffffff } }, { 36, { 0x00000000, 0x22222220, 0xfffffff2, 0x0000000f } }, { 40, { 0x00000000, 0x22222200, 0xffffff22, 0x000000ff } }, { 64, { 0x00000000, 0x00000000, 0x22222222, 0xffffffff } }, { 68, { 0x00000000, 0x00000000, 0x22222220, 0xfffffff2, 0x0000000f } }, }; for (size_t i = 0; i < tests; ++i) EXPECT_EQ(num.shift_left(results[i].get<0>()).words(), results[i].get<1>()); } TEST_CASE(test_bigint_shift_right) { Crypto::UnsignedBigInteger const num1(Vector { 0x100, 0x20, 0x4, 0x2, 0x1 }); size_t const tests1 = 11; AK::Tuple> 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 { 0x44444444, 0xffffffff }); AK::Tuple> 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) { Vector expected_result { 315178285, 505575602, 1883328078, 125027121, 3649625763, 347570207, 74535262, 3832543808, 2472133297, 1600064941, 65273441 }; auto result = bigint_signed_fibonacci(500); EXPECT_EQ(result.unsigned_value().words(), expected_result); } BENCHMARK_CASE(bench_signed_bigint_fib100000) { auto res = bigint_signed_fibonacci(100000); (void)res; } TEST_CASE(test_signed_addition_edgecase_borrow_with_zero) { Crypto::SignedBigInteger num1 { Crypto::UnsignedBigInteger { { UINT32_MAX - 3, UINT32_MAX } }, false }; Crypto::SignedBigInteger num2 { Crypto::UnsignedBigInteger { UINT32_MAX - 2 }, false }; Vector expected_result { 4294967289, 0, 1 }; EXPECT_EQ(num1.plus(num2).unsigned_value().words(), expected_result); } TEST_CASE(test_signed_addition_edgecase_addition_to_other_sign) { Crypto::SignedBigInteger num1 = INT32_MAX; Crypto::SignedBigInteger num2 = num1; num2.negate(); EXPECT_EQ(num1.plus(num2), Crypto::SignedBigInteger { 0 }); } TEST_CASE(test_signed_subtraction_simple_subtraction_positive_result) { Crypto::SignedBigInteger num1(80); Crypto::SignedBigInteger num2(70); EXPECT_EQ(num1.minus(num2), Crypto::SignedBigInteger(10)); } TEST_CASE(test_signed_subtraction_simple_subtraction_negative_result) { Crypto::SignedBigInteger num1(50); Crypto::SignedBigInteger num2(70); EXPECT_EQ(num1.minus(num2), Crypto::SignedBigInteger { -20 }); } TEST_CASE(test_signed_subtraction_both_negative) { Crypto::SignedBigInteger num1(-50); Crypto::SignedBigInteger num2(-70); EXPECT_EQ(num1.minus(num2), Crypto::SignedBigInteger { 20 }); EXPECT_EQ(num2.minus(num1), Crypto::SignedBigInteger { -20 }); } TEST_CASE(test_signed_subtraction_simple_subtraction_with_borrow) { Crypto::SignedBigInteger num1(Crypto::UnsignedBigInteger { UINT32_MAX }); Crypto::SignedBigInteger num2(1); Crypto::SignedBigInteger num3 = num1.plus(num2); Crypto::SignedBigInteger result = num2.minus(num3); num1.negate(); EXPECT_EQ(result, num1); } TEST_CASE(test_signed_subtraction_with_large_numbers) { Crypto::SignedBigInteger num1 = bigint_signed_fibonacci(343); Crypto::SignedBigInteger num2 = bigint_signed_fibonacci(218); Crypto::SignedBigInteger result = num2.minus(num1); auto expected = Crypto::UnsignedBigInteger { Vector { 811430588, 2958904896, 1130908877, 2830569969, 3243275482, 3047460725, 774025231, 7990 } }; EXPECT_EQ(result.plus(num1), num2); EXPECT_EQ(result.unsigned_value(), expected); } TEST_CASE(test_signed_subtraction_with_large_numbers_check_for_assertion) { Crypto::SignedBigInteger num1(Crypto::UnsignedBigInteger { Vector { 1483061863, 446680044, 1123294122, 191895498, 3347106536, 16, 0, 0, 0 } }); Crypto::SignedBigInteger num2(Crypto::UnsignedBigInteger { Vector { 4196414175, 1117247942, 1123294122, 191895498, 3347106536, 16 } }); Crypto::SignedBigInteger result = num1.minus(num2); // this test only verifies that we don't crash on an assertion } TEST_CASE(test_signed_multiplication_with_negative_number) { Crypto::SignedBigInteger num1(8); Crypto::SignedBigInteger num2(-251); Crypto::SignedBigInteger result = num1.multiplied_by(num2); EXPECT_EQ(result, Crypto::SignedBigInteger { -2008 }); } TEST_CASE(test_signed_multiplication_with_big_number) { Crypto::SignedBigInteger num1 = bigint_signed_fibonacci(200); Crypto::SignedBigInteger num2(-12345678); Crypto::SignedBigInteger result = num1.multiplied_by(num2); Vector expected_result { 669961318, 143970113, 4028714974, 3164551305, 1589380278, 2 }; EXPECT_EQ(result.unsigned_value().words(), expected_result); EXPECT(result.is_negative()); } TEST_CASE(test_signed_multiplication_with_two_big_numbers) { Crypto::SignedBigInteger num1 = bigint_signed_fibonacci(200); Crypto::SignedBigInteger num2 = bigint_signed_fibonacci(341); num1.negate(); Crypto::SignedBigInteger result = num1.multiplied_by(num2); Vector expected_results { 3017415433, 2741793511, 1957755698, 3731653885, 3154681877, 785762127, 3200178098, 4260616581, 529754471, 3632684436, 1073347813, 2516430 }; EXPECT_EQ(result.unsigned_value().words(), expected_results); EXPECT(result.is_negative()); } TEST_CASE(test_negative_zero_is_not_allowed) { Crypto::SignedBigInteger zero(Crypto::UnsignedBigInteger(0), true); EXPECT(!zero.is_negative()); zero.negate(); EXPECT(!zero.is_negative()); Crypto::SignedBigInteger positive_five(Crypto::UnsignedBigInteger(5), false); Crypto::SignedBigInteger negative_five(Crypto::UnsignedBigInteger(5), true); zero = positive_five.plus(negative_five); EXPECT(zero.unsigned_value().is_zero()); EXPECT(!zero.is_negative()); } TEST_CASE(test_i32_limits) { Crypto::SignedBigInteger min { AK::NumericLimits::min() }; EXPECT(min.is_negative()); EXPECT(min.unsigned_value().to_u64() == static_cast(AK::NumericLimits::max()) + 1); Crypto::SignedBigInteger max { AK::NumericLimits::max() }; EXPECT(!max.is_negative()); EXPECT(max.unsigned_value().to_u64() == AK::NumericLimits::max()); } TEST_CASE(double_comparisons) { #define EXPECT_LESS_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt) #define EXPECT_GREATER_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleLessThanBigInt) #define EXPECT_EQUAL_TO(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleEqualsBigInt) { Crypto::SignedBigInteger zero { 0 }; EXPECT_EQUAL_TO(zero, 0.0); EXPECT_EQUAL_TO(zero, -0.0); } { Crypto::SignedBigInteger one { 1 }; EXPECT_EQUAL_TO(one, 1.0); EXPECT_GREATER_THAN(one, -1.0); EXPECT_GREATER_THAN(one, 0.5); EXPECT_GREATER_THAN(one, -0.5); EXPECT_LESS_THAN(one, 1.000001); one.negate(); auto const& negative_one = one; EXPECT_EQUAL_TO(negative_one, -1.0); EXPECT_LESS_THAN(negative_one, 1.0); EXPECT_LESS_THAN(one, 0.5); EXPECT_LESS_THAN(one, -0.5); EXPECT_GREATER_THAN(one, -1.5); EXPECT_LESS_THAN(one, 1.000001); EXPECT_GREATER_THAN(one, -1.000001); } { double double_infinity = HUGE_VAL; VERIFY(isinf(double_infinity)); Crypto::SignedBigInteger one { 1 }; EXPECT_LESS_THAN(one, double_infinity); EXPECT_GREATER_THAN(one, -double_infinity); } { double double_max_value = NumericLimits::max(); double double_below_max_value = nextafter(double_max_value, 0.0); VERIFY(double_below_max_value < double_max_value); VERIFY(double_below_max_value < (double_max_value - 1.0)); auto max_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); auto max_value_plus_one = max_value_in_bigint.plus(Crypto::SignedBigInteger { 1 }); auto max_value_minus_one = max_value_in_bigint.minus(Crypto::SignedBigInteger { 1 }); auto below_max_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); EXPECT_EQUAL_TO(max_value_in_bigint, double_max_value); EXPECT_LESS_THAN(max_value_minus_one, double_max_value); EXPECT_GREATER_THAN(max_value_plus_one, double_max_value); EXPECT_LESS_THAN(below_max_value_in_bigint, double_max_value); EXPECT_GREATER_THAN(max_value_in_bigint, double_below_max_value); EXPECT_GREATER_THAN(max_value_minus_one, double_below_max_value); EXPECT_GREATER_THAN(max_value_plus_one, double_below_max_value); EXPECT_EQUAL_TO(below_max_value_in_bigint, double_below_max_value); } { double double_min_value = NumericLimits::lowest(); double double_above_min_value = nextafter(double_min_value, 0.0); VERIFY(double_above_min_value > double_min_value); VERIFY(double_above_min_value > (double_min_value + 1.0)); auto min_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); auto min_value_plus_one = min_value_in_bigint.plus(Crypto::SignedBigInteger { 1 }); auto min_value_minus_one = min_value_in_bigint.minus(Crypto::SignedBigInteger { 1 }); auto above_min_value_in_bigint = TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); EXPECT_EQUAL_TO(min_value_in_bigint, double_min_value); EXPECT_LESS_THAN(min_value_minus_one, double_min_value); EXPECT_GREATER_THAN(min_value_plus_one, double_min_value); EXPECT_GREATER_THAN(above_min_value_in_bigint, double_min_value); EXPECT_LESS_THAN(min_value_in_bigint, double_above_min_value); EXPECT_LESS_THAN(min_value_minus_one, double_above_min_value); EXPECT_LESS_THAN(min_value_plus_one, double_above_min_value); EXPECT_EQUAL_TO(above_min_value_in_bigint, double_above_min_value); } { double just_above_255 = bit_cast(0x406fe00000000001ULL); double just_below_255 = bit_cast(0x406fdfffffffffffULL); double double_255 = 255.0; Crypto::SignedBigInteger bigint_255 { 255 }; EXPECT_EQUAL_TO(bigint_255, double_255); EXPECT_GREATER_THAN(bigint_255, just_below_255); EXPECT_LESS_THAN(bigint_255, just_above_255); } #undef EXPECT_LESS_THAN #undef EXPECT_GREATER_THAN #undef EXPECT_EQUAL_TO } TEST_CASE(to_double) { #define EXPECT_TO_EQUAL_DOUBLE(bigint, double_value) \ EXPECT_EQ((bigint).to_double(Crypto::UnsignedBigInteger::RoundingMode::RoundTowardZero), double_value) EXPECT_TO_EQUAL_DOUBLE(Crypto::UnsignedBigInteger(0), 0.0); // Make sure we don't get negative zero! EXPECT_EQ(signbit(Crypto::UnsignedBigInteger(0).to_double()), 0); { Crypto::SignedBigInteger zero { 0 }; EXPECT(!zero.is_negative()); EXPECT_TO_EQUAL_DOUBLE(zero, 0.0); EXPECT_EQ(signbit(zero.to_double()), 0); zero.negate(); EXPECT(!zero.is_negative()); EXPECT_TO_EQUAL_DOUBLE(zero, 0.0); EXPECT_EQ(signbit(zero.to_double()), 0); } EXPECT_TO_EQUAL_DOUBLE(Crypto::UnsignedBigInteger(9682), 9682.0); EXPECT_TO_EQUAL_DOUBLE(Crypto::SignedBigInteger(-9660), -9660.0); double double_max_value = NumericLimits::max(); double infinity = INFINITY; EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), double_max_value); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), double_max_value); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv)), double_max_value); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), infinity); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), -double_max_value); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-ffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), -double_max_value); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"sv)), -double_max_value); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(16, "-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)), -infinity); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "ffffffffffffffff"sv)), 18446744073709549568.0); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800"sv)), 18446744073709549568.0); EXPECT_TO_EQUAL_DOUBLE( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff8ff"sv)), 18446744073709549568.0); EXPECT_TO_EQUAL_DOUBLE(TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(10, "1234567890123456789"sv)), 1234567890123456800.0); EXPECT_TO_EQUAL_DOUBLE(TRY_OR_FAIL(Crypto::SignedBigInteger::from_base(10, "2345678901234567890"sv)), 2345678901234567680.0); EXPECT_EQ( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 2305843009213693696.0); EXPECT_EQ( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff00"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::RoundTowardZero), 2305843009213693696.0); EXPECT_EQ( TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "1fffffffffffff80"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 2305843009213693952.0); EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000001"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740992.0); EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000002"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740994.0); // 2^53 = 20000000000000, +3 Rounds up because of tiesRoundToEven EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000003"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740996.0); // +4 is exactly 9007199254740996 EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000004"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740996.0); // +5 rounds down because of tiesRoundToEven EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000005"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740996.0); EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "20000000000006"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), 9007199254740998.0); EXPECT_EQ(TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(10, "98382635059784269824"sv)).to_double(Crypto::UnsignedBigInteger::RoundingMode::IEEERoundAndTiesToEvenMantissa), bit_cast(0x4415555555555555ULL)); #undef EXPECT_TO_EQUAL_DOUBLE } TEST_CASE(bigint_from_double) { { Crypto::UnsignedBigInteger from_zero { 0.0 }; EXPECT(from_zero.is_zero()); } #define SURVIVES_ROUND_TRIP_UNSIGNED(double_value) \ { \ Crypto::UnsignedBigInteger bigint { (double_value) }; \ EXPECT_EQ(bigint.to_double(), (double_value)); \ } SURVIVES_ROUND_TRIP_UNSIGNED(0.0); SURVIVES_ROUND_TRIP_UNSIGNED(1.0); SURVIVES_ROUND_TRIP_UNSIGNED(100000.0); SURVIVES_ROUND_TRIP_UNSIGNED(1000000000000.0); SURVIVES_ROUND_TRIP_UNSIGNED(10000000000000000000.0); SURVIVES_ROUND_TRIP_UNSIGNED(NumericLimits::max()); SURVIVES_ROUND_TRIP_UNSIGNED(bit_cast(0x4340000000000002ULL)); SURVIVES_ROUND_TRIP_UNSIGNED(bit_cast(0x4340000000000001ULL)); SURVIVES_ROUND_TRIP_UNSIGNED(bit_cast(0x4340000000000000ULL)); // Failed on last bits of mantissa SURVIVES_ROUND_TRIP_UNSIGNED(bit_cast(0x7EDFFFFFFFFFFFFFULL)); SURVIVES_ROUND_TRIP_UNSIGNED(bit_cast(0x7ed5555555555555ULL)); SURVIVES_ROUND_TRIP_UNSIGNED(bit_cast(0x7EDCBA9876543210ULL)); // Has exactly exponent of 32 SURVIVES_ROUND_TRIP_UNSIGNED(bit_cast(0x41f22f74e0000000ULL)); #define SURVIVES_ROUND_TRIP_SIGNED(double_value) \ { \ Crypto::SignedBigInteger bigint_positive { (double_value) }; \ EXPECT_EQ(bigint_positive.to_double(), (double_value)); \ Crypto::SignedBigInteger bigint_negative { -(double_value) }; \ EXPECT_EQ(bigint_negative.to_double(), -(double_value)); \ EXPECT(bigint_positive != bigint_negative); \ bigint_positive.negate(); \ EXPECT(bigint_positive == bigint_negative); \ } { // Negative zero should be converted to positive zero double const negative_zero = bit_cast(0x8000000000000000); // However it should give a bit exact +0.0 Crypto::SignedBigInteger from_negative_zero { negative_zero }; EXPECT(from_negative_zero.is_zero()); EXPECT(!from_negative_zero.is_negative()); double result = from_negative_zero.to_double(); EXPECT_EQ(result, 0.0); EXPECT_EQ(bit_cast(result), 0ULL); } SURVIVES_ROUND_TRIP_SIGNED(1.0); SURVIVES_ROUND_TRIP_SIGNED(100000.0); SURVIVES_ROUND_TRIP_SIGNED(-1000000000000.0); SURVIVES_ROUND_TRIP_SIGNED(10000000000000000000.0); SURVIVES_ROUND_TRIP_SIGNED(NumericLimits::max()); SURVIVES_ROUND_TRIP_SIGNED(NumericLimits::lowest()); SURVIVES_ROUND_TRIP_SIGNED(bit_cast(0x4340000000000002ULL)); SURVIVES_ROUND_TRIP_SIGNED(bit_cast(0x4340000000000001ULL)); SURVIVES_ROUND_TRIP_SIGNED(bit_cast(0x4340000000000000ULL)); SURVIVES_ROUND_TRIP_SIGNED(bit_cast(0x7EDFFFFFFFFFFFFFULL)); SURVIVES_ROUND_TRIP_SIGNED(bit_cast(0x7ed5555555555555ULL)); SURVIVES_ROUND_TRIP_SIGNED(bit_cast(0x7EDCBA9876543210ULL)); #undef SURVIVES_ROUND_TRIP_SIGNED #undef SURVIVES_ROUND_TRIP_UNSIGNED } TEST_CASE(unsigned_bigint_double_comparisons) { #define EXPECT_LESS_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt) #define EXPECT_GREATER_THAN(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleLessThanBigInt) #define EXPECT_EQUAL_TO(bigint, double_value) EXPECT_EQ(bigint.compare_to_double(double_value), Crypto::UnsignedBigInteger::CompareResult::DoubleEqualsBigInt) { Crypto::UnsignedBigInteger zero { 0 }; EXPECT_EQUAL_TO(zero, 0.0); EXPECT_EQUAL_TO(zero, -0.0); } { Crypto::UnsignedBigInteger one { 1 }; EXPECT_EQUAL_TO(one, 1.0); EXPECT_GREATER_THAN(one, -1.0); EXPECT_GREATER_THAN(one, 0.5); EXPECT_GREATER_THAN(one, -0.5); EXPECT_LESS_THAN(one, 1.000001); } { double double_infinity = HUGE_VAL; VERIFY(isinf(double_infinity)); Crypto::UnsignedBigInteger one { 1 }; EXPECT_LESS_THAN(one, double_infinity); EXPECT_GREATER_THAN(one, -double_infinity); } { double double_max_value = NumericLimits::max(); double double_below_max_value = nextafter(double_max_value, 0.0); VERIFY(double_below_max_value < double_max_value); VERIFY(double_below_max_value < (double_max_value - 1.0)); auto max_value_in_bigint = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); auto max_value_plus_one = max_value_in_bigint.plus(Crypto::UnsignedBigInteger { 1 }); auto max_value_minus_one = TRY_OR_FAIL(max_value_in_bigint.minus(Crypto::UnsignedBigInteger { 1 })); auto below_max_value_in_bigint = TRY_OR_FAIL(Crypto::UnsignedBigInteger::from_base(16, "fffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"sv)); EXPECT_EQUAL_TO(max_value_in_bigint, double_max_value); EXPECT_LESS_THAN(max_value_minus_one, double_max_value); EXPECT_GREATER_THAN(max_value_plus_one, double_max_value); EXPECT_LESS_THAN(below_max_value_in_bigint, double_max_value); EXPECT_GREATER_THAN(max_value_in_bigint, double_below_max_value); EXPECT_GREATER_THAN(max_value_minus_one, double_below_max_value); EXPECT_GREATER_THAN(max_value_plus_one, double_below_max_value); EXPECT_EQUAL_TO(below_max_value_in_bigint, double_below_max_value); } { double just_above_255 = bit_cast(0x406fe00000000001ULL); double just_below_255 = bit_cast(0x406fdfffffffffffULL); double double_255 = 255.0; Crypto::UnsignedBigInteger bigint_255 { 255 }; EXPECT_EQUAL_TO(bigint_255, double_255); EXPECT_GREATER_THAN(bigint_255, just_below_255); EXPECT_LESS_THAN(bigint_255, just_above_255); } #undef EXPECT_LESS_THAN #undef EXPECT_GREATER_THAN #undef EXPECT_EQUAL_TO } namespace AK { template<> struct Formatter : Formatter { ErrorOr format(FormatBuilder& builder, Crypto::UnsignedBigInteger::CompareResult const& compare_result) { switch (compare_result) { case Crypto::UnsignedBigInteger::CompareResult::DoubleEqualsBigInt: return builder.put_string("Equals"sv); case Crypto::UnsignedBigInteger::CompareResult::DoubleLessThanBigInt: return builder.put_string("LessThan"sv); case Crypto::UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt: return builder.put_string("GreaterThan"sv); default: return builder.put_string("???"sv); } } }; }