[corelib BigInt] Fix implementation of BigInt.modInverse (fixes issue #37008).
A negative result was wrongly returned as a positive value.
Since positive values are preferred, the implementation now adds the modulus
enough times to make the result positive.
Change-Id: I87a2ceb359345846740a749ab6b46b1d45e7ba21
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/103664
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
diff --git a/pkg/dev_compiler/tool/input_sdk/patch/core_patch.dart b/pkg/dev_compiler/tool/input_sdk/patch/core_patch.dart
index a8103b3..0524ed38 100644
--- a/pkg/dev_compiler/tool/input_sdk/patch/core_patch.dart
+++ b/pkg/dev_compiler/tool/input_sdk/patch/core_patch.dart
@@ -2316,6 +2316,7 @@
_rsh(uDigits, maxUsed, 1, uDigits);
if (ac) {
if (((aDigits[0] & 1) == 1) || ((bDigits[0] & 1) == 1)) {
+ // a += y
if (aIsNegative) {
if ((aDigits[maxUsed] != 0) ||
(_compareDigits(aDigits, maxUsed, yDigits, maxUsed)) > 0) {
@@ -2327,6 +2328,7 @@
} else {
_absAdd(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
}
+ // b -= x
if (bIsNegative) {
_absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
} else if ((bDigits[maxUsed] != 0) ||
@@ -2339,6 +2341,7 @@
}
_rsh(aDigits, abcdUsed, 1, aDigits);
} else if ((bDigits[0] & 1) == 1) {
+ // b -= x
if (bIsNegative) {
_absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
} else if ((bDigits[maxUsed] != 0) ||
@@ -2355,6 +2358,7 @@
_rsh(vDigits, maxUsed, 1, vDigits);
if (ac) {
if (((cDigits[0] & 1) == 1) || ((dDigits[0] & 1) == 1)) {
+ // c += y
if (cIsNegative) {
if ((cDigits[maxUsed] != 0) ||
(_compareDigits(cDigits, maxUsed, yDigits, maxUsed) > 0)) {
@@ -2366,6 +2370,7 @@
} else {
_absAdd(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
}
+ // d -= x
if (dIsNegative) {
_absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
} else if ((dDigits[maxUsed] != 0) ||
@@ -2378,6 +2383,7 @@
}
_rsh(cDigits, abcdUsed, 1, cDigits);
} else if ((dDigits[0] & 1) == 1) {
+ // d -= x
if (dIsNegative) {
_absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
} else if ((dDigits[maxUsed] != 0) ||
@@ -2391,8 +2397,10 @@
_rsh(dDigits, abcdUsed, 1, dDigits);
}
if (_compareDigits(uDigits, maxUsed, vDigits, maxUsed) >= 0) {
+ // u -= v
_absSub(uDigits, maxUsed, vDigits, maxUsed, uDigits);
if (ac) {
+ // a -= c
if (aIsNegative == cIsNegative) {
var a_cmp_c = _compareDigits(aDigits, abcdUsed, cDigits, abcdUsed);
if (a_cmp_c > 0) {
@@ -2405,6 +2413,7 @@
_absAdd(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
}
}
+ // b -= d
if (bIsNegative == dIsNegative) {
var b_cmp_d = _compareDigits(bDigits, abcdUsed, dDigits, abcdUsed);
if (b_cmp_d > 0) {
@@ -2417,8 +2426,10 @@
_absAdd(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
}
} else {
+ // v -= u
_absSub(vDigits, maxUsed, uDigits, maxUsed, vDigits);
if (ac) {
+ // c -= a
if (cIsNegative == aIsNegative) {
var c_cmp_a = _compareDigits(cDigits, abcdUsed, aDigits, abcdUsed);
if (c_cmp_a > 0) {
@@ -2431,6 +2442,7 @@
_absAdd(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
}
}
+ // d -= b
if (dIsNegative == bIsNegative) {
var d_cmp_b = _compareDigits(dDigits, abcdUsed, bDigits, abcdUsed);
if (d_cmp_b > 0) {
@@ -2462,25 +2474,18 @@
}
if (dIsNegative) {
- if ((dDigits[maxUsed] != 0) ||
+ while ((dDigits[maxUsed] != 0) ||
(_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ // d += x, d still negative
_absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
- if ((dDigits[maxUsed] != 0) ||
- (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
- _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
- } else {
- _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
- dIsNegative = false;
- }
- } else {
- _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
- dIsNegative = false;
}
- } else if ((dDigits[maxUsed] != 0) ||
- (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
- _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
- if ((dDigits[maxUsed] != 0) ||
- (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ // d += x
+ _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+ dIsNegative = false;
+ } else {
+ while ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) >= 0)) {
+ // d -= x
_absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
}
}
diff --git a/runtime/lib/bigint_patch.dart b/runtime/lib/bigint_patch.dart
index 2046284..19c1919 100644
--- a/runtime/lib/bigint_patch.dart
+++ b/runtime/lib/bigint_patch.dart
@@ -1986,6 +1986,7 @@
_rsh(uDigits, maxUsed, 1, uDigits);
if (ac) {
if (((aDigits[0] & 1) == 1) || ((bDigits[0] & 1) == 1)) {
+ // a += y
if (aIsNegative) {
if ((aDigits[maxUsed] != 0) ||
(_compareDigits(aDigits, maxUsed, yDigits, maxUsed)) > 0) {
@@ -1997,6 +1998,7 @@
} else {
_absAdd(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
}
+ // b -= x
if (bIsNegative) {
_absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
} else if ((bDigits[maxUsed] != 0) ||
@@ -2009,6 +2011,7 @@
}
_rsh(aDigits, abcdUsed, 1, aDigits);
} else if ((bDigits[0] & 1) == 1) {
+ // b -= x
if (bIsNegative) {
_absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
} else if ((bDigits[maxUsed] != 0) ||
@@ -2025,6 +2028,7 @@
_rsh(vDigits, maxUsed, 1, vDigits);
if (ac) {
if (((cDigits[0] & 1) == 1) || ((dDigits[0] & 1) == 1)) {
+ // c += y
if (cIsNegative) {
if ((cDigits[maxUsed] != 0) ||
(_compareDigits(cDigits, maxUsed, yDigits, maxUsed) > 0)) {
@@ -2036,6 +2040,7 @@
} else {
_absAdd(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
}
+ // d -= x
if (dIsNegative) {
_absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
} else if ((dDigits[maxUsed] != 0) ||
@@ -2048,6 +2053,7 @@
}
_rsh(cDigits, abcdUsed, 1, cDigits);
} else if ((dDigits[0] & 1) == 1) {
+ // d -= x
if (dIsNegative) {
_absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
} else if ((dDigits[maxUsed] != 0) ||
@@ -2061,8 +2067,10 @@
_rsh(dDigits, abcdUsed, 1, dDigits);
}
if (_compareDigits(uDigits, maxUsed, vDigits, maxUsed) >= 0) {
+ // u -= v
_absSub(uDigits, maxUsed, vDigits, maxUsed, uDigits);
if (ac) {
+ // a -= c
if (aIsNegative == cIsNegative) {
var a_cmp_c = _compareDigits(aDigits, abcdUsed, cDigits, abcdUsed);
if (a_cmp_c > 0) {
@@ -2075,6 +2083,7 @@
_absAdd(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
}
}
+ // b -= d
if (bIsNegative == dIsNegative) {
var b_cmp_d = _compareDigits(bDigits, abcdUsed, dDigits, abcdUsed);
if (b_cmp_d > 0) {
@@ -2087,8 +2096,10 @@
_absAdd(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
}
} else {
+ // v -= u
_absSub(vDigits, maxUsed, uDigits, maxUsed, vDigits);
if (ac) {
+ // c -= a
if (cIsNegative == aIsNegative) {
var c_cmp_a = _compareDigits(cDigits, abcdUsed, aDigits, abcdUsed);
if (c_cmp_a > 0) {
@@ -2101,6 +2112,7 @@
_absAdd(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
}
}
+ // d -= b
if (dIsNegative == bIsNegative) {
var d_cmp_b = _compareDigits(dDigits, abcdUsed, bDigits, abcdUsed);
if (d_cmp_b > 0) {
@@ -2132,25 +2144,18 @@
}
if (dIsNegative) {
- if ((dDigits[maxUsed] != 0) ||
+ while ((dDigits[maxUsed] != 0) ||
(_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ // d += x, d still negative
_absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
- if ((dDigits[maxUsed] != 0) ||
- (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
- _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
- } else {
- _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
- dIsNegative = false;
- }
- } else {
- _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
- dIsNegative = false;
}
- } else if ((dDigits[maxUsed] != 0) ||
- (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
- _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
- if ((dDigits[maxUsed] != 0) ||
- (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ // d += x
+ _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+ dIsNegative = false;
+ } else {
+ while ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) >= 0)) {
+ // d -= x
_absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
}
}
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index 998f42b..d0a1215 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -2352,6 +2352,7 @@
_rsh(uDigits, maxUsed, 1, uDigits);
if (ac) {
if (((aDigits[0] & 1) == 1) || ((bDigits[0] & 1) == 1)) {
+ // a += y
if (aIsNegative) {
if ((aDigits[maxUsed] != 0) ||
(_compareDigits(aDigits, maxUsed, yDigits, maxUsed)) > 0) {
@@ -2363,6 +2364,7 @@
} else {
_absAdd(aDigits, abcdUsed, yDigits, maxUsed, aDigits);
}
+ // b -= x
if (bIsNegative) {
_absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
} else if ((bDigits[maxUsed] != 0) ||
@@ -2375,6 +2377,7 @@
}
_rsh(aDigits, abcdUsed, 1, aDigits);
} else if ((bDigits[0] & 1) == 1) {
+ // b -= x
if (bIsNegative) {
_absAdd(bDigits, abcdUsed, xDigits, maxUsed, bDigits);
} else if ((bDigits[maxUsed] != 0) ||
@@ -2391,6 +2394,7 @@
_rsh(vDigits, maxUsed, 1, vDigits);
if (ac) {
if (((cDigits[0] & 1) == 1) || ((dDigits[0] & 1) == 1)) {
+ // c += y
if (cIsNegative) {
if ((cDigits[maxUsed] != 0) ||
(_compareDigits(cDigits, maxUsed, yDigits, maxUsed) > 0)) {
@@ -2402,6 +2406,7 @@
} else {
_absAdd(cDigits, abcdUsed, yDigits, maxUsed, cDigits);
}
+ // d -= x
if (dIsNegative) {
_absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
} else if ((dDigits[maxUsed] != 0) ||
@@ -2414,6 +2419,7 @@
}
_rsh(cDigits, abcdUsed, 1, cDigits);
} else if ((dDigits[0] & 1) == 1) {
+ // d -= x
if (dIsNegative) {
_absAdd(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
} else if ((dDigits[maxUsed] != 0) ||
@@ -2427,8 +2433,10 @@
_rsh(dDigits, abcdUsed, 1, dDigits);
}
if (_compareDigits(uDigits, maxUsed, vDigits, maxUsed) >= 0) {
+ // u -= v
_absSub(uDigits, maxUsed, vDigits, maxUsed, uDigits);
if (ac) {
+ // a -= c
if (aIsNegative == cIsNegative) {
var a_cmp_c = _compareDigits(aDigits, abcdUsed, cDigits, abcdUsed);
if (a_cmp_c > 0) {
@@ -2441,6 +2449,7 @@
_absAdd(aDigits, abcdUsed, cDigits, abcdUsed, aDigits);
}
}
+ // b -= d
if (bIsNegative == dIsNegative) {
var b_cmp_d = _compareDigits(bDigits, abcdUsed, dDigits, abcdUsed);
if (b_cmp_d > 0) {
@@ -2453,8 +2462,10 @@
_absAdd(bDigits, abcdUsed, dDigits, abcdUsed, bDigits);
}
} else {
+ // v -= u
_absSub(vDigits, maxUsed, uDigits, maxUsed, vDigits);
if (ac) {
+ // c -= a
if (cIsNegative == aIsNegative) {
var c_cmp_a = _compareDigits(cDigits, abcdUsed, aDigits, abcdUsed);
if (c_cmp_a > 0) {
@@ -2467,6 +2478,7 @@
_absAdd(cDigits, abcdUsed, aDigits, abcdUsed, cDigits);
}
}
+ // d -= b
if (dIsNegative == bIsNegative) {
var d_cmp_b = _compareDigits(dDigits, abcdUsed, bDigits, abcdUsed);
if (d_cmp_b > 0) {
@@ -2498,25 +2510,18 @@
}
if (dIsNegative) {
- if ((dDigits[maxUsed] != 0) ||
+ while ((dDigits[maxUsed] != 0) ||
(_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ // d += x, d still negative
_absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
- if ((dDigits[maxUsed] != 0) ||
- (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
- _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
- } else {
- _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
- dIsNegative = false;
- }
- } else {
- _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
- dIsNegative = false;
}
- } else if ((dDigits[maxUsed] != 0) ||
- (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
- _absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
- if ((dDigits[maxUsed] != 0) ||
- (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) > 0)) {
+ // d += x
+ _absSub(xDigits, maxUsed, dDigits, maxUsed, dDigits);
+ dIsNegative = false;
+ } else {
+ while ((dDigits[maxUsed] != 0) ||
+ (_compareDigits(dDigits, maxUsed, xDigits, maxUsed) >= 0)) {
+ // d -= x
_absSub(dDigits, abcdUsed, xDigits, maxUsed, dDigits);
}
}
diff --git a/tests/corelib_2/bigint_test.dart b/tests/corelib_2/bigint_test.dart
index 01dea1f..0b5b8c5 100644
--- a/tests/corelib_2/bigint_test.dart
+++ b/tests/corelib_2/bigint_test.dart
@@ -222,6 +222,15 @@
test(mediumNumber, new BigInt.from(137), new BigInt.from(77));
test(new BigInt.from(137), mediumNumber, new BigInt.from(540686667207353));
test(bigNumber, new BigInt.from(137), new BigInt.from(128));
+ var x = BigInt.parse(
+ "28ea16430c1f1072754aa5ebbfda0d790605a507c6c9758e88697b0b5dd9e74c",
+ radix: 16);
+ var m = BigInt.parse(
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ radix: 16);
+ var r = BigInt.parse("95929095851002583825372225918533539673793386278"
+ "360575987103577151530201707061", radix: 10);
+ test(x, m, r);
}
testGcd() {