public bool RabinMillerTest(int certainty, Random random) { Debug.Assert(certainty > 0); Debug.Assert(BitLength > 2); Debug.Assert(TestBit(0)); // let n = 1 + d . 2^s BigInteger n = this; int s = n.GetLowestSetBitMaskFirst(-1 << 1); Debug.Assert(s >= 1); BigInteger r = n.ShiftRight(s); // NOTE: Avoid conversion to/from Montgomery form and check for R/-R as result instead BigInteger montRadix = One.ShiftLeft(32 * n.magnitude.Length).Remainder(n); BigInteger minusMontRadix = n.Subtract(montRadix); do { BigInteger a; do { a = new BigInteger(n.BitLength, random); } while (a.sign == 0 || a.CompareTo(n) >= 0 || a.IsEqualMagnitude(montRadix) || a.IsEqualMagnitude(minusMontRadix)); BigInteger y = ModPowMonty(a, r, n, false); if (!y.Equals(montRadix)) { int j = 0; while (!y.Equals(minusMontRadix)) { if (++j == s) return false; y = ModPowMonty(y, Two, n, false); if (y.Equals(montRadix)) return false; } } certainty -= 2; // composites pass for only 1/4 possible 'a' } while (certainty > 0); return true; }