summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2021-11-16 09:17:55 +0000
committerLinus Groh <mail@linusgroh.de>2021-11-16 10:06:53 +0000
commit58c6a156bf3e6dcf0e37a3a73ba6dd4365ce1203 (patch)
tree25a7ee6d30da8c3a5a5f37860d1cb054ab7deafd
parent014840eecae67a89b220ec1e33efbb01308d49d3 (diff)
downloadserenity-58c6a156bf3e6dcf0e37a3a73ba6dd4365ce1203.zip
LibCrypto: Fix subtracting two negative `SignedBigInteger`s
Currently, we get the following results -1 - -2 = -1 -2 - -1 = 1 Correct would be: -1 - -2 = 1 -2 - -1 = -1 This was already attempted to be fixed in 7ed8970, but that change was incorrect. This directly translates to LibJS BigInts having the same incorrect behavior - it even was tested.
-rw-r--r--Tests/LibCrypto/TestBigInteger.cpp9
-rw-r--r--Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp10
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-minus.js2
3 files changed, 17 insertions, 4 deletions
diff --git a/Tests/LibCrypto/TestBigInteger.cpp b/Tests/LibCrypto/TestBigInteger.cpp
index 36b3098b21..504fb4eab1 100644
--- a/Tests/LibCrypto/TestBigInteger.cpp
+++ b/Tests/LibCrypto/TestBigInteger.cpp
@@ -543,6 +543,15 @@ TEST_CASE(test_signed_subtraction_simple_subtraction_negative_result)
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 });
diff --git a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp
index 1ff34050a6..5299e7dd5e 100644
--- a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp
+++ b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp
@@ -109,11 +109,15 @@ FLATTEN SignedBigInteger SignedBigInteger::minus(const SignedBigInteger& other)
// -x - -y = y - x
if (m_unsigned_data < other.m_unsigned_data) {
// The result will be positive.
- return SignedBigInteger { other.m_unsigned_data.minus(m_unsigned_data), true };
+ return SignedBigInteger { other.m_unsigned_data.minus(m_unsigned_data) };
}
- // The result will be either zero, or negative.
// y - x = - (x - y)
- return SignedBigInteger { m_unsigned_data.minus(other.m_unsigned_data) };
+ if (m_unsigned_data > other.m_unsigned_data) {
+ // The result will be negative.
+ return SignedBigInteger { m_unsigned_data.minus(other.m_unsigned_data), true };
+ }
+ // Both operands have the same magnitude, the result is positive zero.
+ return SignedBigInteger { 0 };
}
FLATTEN SignedBigInteger SignedBigInteger::plus(const UnsignedBigInteger& other) const
diff --git a/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-minus.js b/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-minus.js
index 5d88f85ce2..033ef535dc 100644
--- a/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-minus.js
+++ b/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-minus.js
@@ -2,7 +2,7 @@ describe("minus behavior", () => {
test("the basics", () => {
expect(3n - 4n).toBe(-1n);
expect(3n - -4n).toBe(7n);
- expect(-3n - -4n).toBe(-1n);
+ expect(-3n - -4n).toBe(1n);
expect(-3n - 4n).toBe(-7n);
});
});