public static bool IsProbablePrime(this BigInteger input, int number_of_iterations) { //TODO could be paralel if (input == 2 || input == 3) { return(true); } if (input < 2 || input % 2 == 0) { return(false); } BigInteger power = input - 1; int trailing_count = 0; while ((power % 2 == 0) && (power != 0)) { power /= 2; trailing_count += 1; } RandomNumberGenerator random = new RNGCryptoServiceProvider(); for (int index_witness = 0; index_witness < number_of_iterations; index_witness++) { BigInteger witness = random.RandomPositiveBigIntegerBelow(input); if (ToolsMathBigIntegerPrime.IsCompositeByMillerRabinWitness(input, witness, trailing_count, power)) { return(false); } } return(true); }
/** * The fast generation of safe primes is implemented according to [CS00] * and M.J. Wiener's "Safe Prime Generation with a Combined Sieve". */ public static void mpz_sprime_test( BigInteger p, BigInteger q, long qsize, IFunction <Tuple <BigInteger, BigInteger>, bool> test, int mr_iterations) { long [] R_q = new long [SIEVE_SIZE]; long [] R_p = new long [SIEVE_SIZE]; int i = 0; int fail = 0; BigInteger tmp, y, pm1; BigInteger a = 2; /* Step 1. [CS00]: choose randomly an odd number $q$ of appropriate size */ do { q = mpz_srandom.mpz_srandomb(qsize); }while ((q.BitLength() < qsize) || (q.IsEven)); /* Compute $p = 2q + 1$. */ pm1 = q * 2; p = pm1 + 1; /* Initalize the sieves for testing divisability by small primes. */ for (i = 0; i < SIEVE_SIZE; i++) { tmp = new BigInteger(primes[i]); /* R_q[i] = q mod primes[i] */ y = q % tmp; R_q[i] = (long)y; /* R_p[i] = (2q+1) mod primes[i] */ y = p % tmp; R_p[i] = (long)y; } while (true) { /* Increase $q$ by 2 (incremental prime number generator). */ q = q = 2; /* Increase $p$ by 4 (actually compute $p = 2q + 1$). */ p = p + 4; pm1 = pm1 + 4; /* Use the sieve optimization procedure of Note 4.51(ii) [HAC]. */ for (i = 0, fail = 0; i < SIEVE_SIZE; i++) { /* Update the sieves. */ R_q[i] += 2; R_q[i] %= primes[i]; R_p[i] += 4; R_p[i] %= primes[i]; /* * Check whether R_q[i] or R_p[i] is zero. We cannot break this loop, * because we have to update our sieves completely for the next try. */ if ((R_q[i] == 0) || (R_p[i] == 0)) { fail = 1; } } if (0 < fail) { continue; } /* Additional tests? */ if (!test.Compute(new Tuple <BigInteger, BigInteger>(q, p))) { continue; } /* * Step 2. [CS00]: M.J. Wiener's "Combined Sieve" * Test whether either $q$ or $p$ are not divisable by any primes up to * some bound $B$. (We use the bound $B = 5000$ here.) */ for (i = 0; i < PRIMES_SIZE; i++) { if (mpz_congruent_ui_p(q, primes_m1d2[i], primes[i]) || mpz_congruent_ui_p(p, primes_m1d2[i], primes[i])) { break; } if (i >= SIEVE_SIZE) { if (mpz_congruent_ui_p(q, 0L, primes[i]) || mpz_congruent_ui_p(p, 0L, primes[i])) { break; } } else { Debug.Assert(!mpz_congruent_ui_p(q, 0L, primes[i])); Debug.Assert(!mpz_congruent_ui_p(p, 0L, primes[i])); } } if (i < PRIMES_SIZE) { continue; } /* Optimization: do a single test for $q$ first */ if (!q.IsProbablePrime(1)) { continue; } /* * Step 3. [CS00]: Test whether 2 is not a Miller-Rabin witness to the * compositeness of $q$. */ if (ToolsMathBigIntegerPrime.IsCompositeByMillerRabinWitness(q, a)) { continue; } /* Step 4. [CS00]: Test whether $2^q \equiv \pm 1 \pmod{p}$. */ y = a.ModPow(q, p); if ((y.CompareTo(1) != 0) && (y.CompareTo(0) != 0)) { continue; } /* * Step 5. [CS00]: Apply the Miller-Rabin test to $q$ a defined number * of times (maximum error probability $4^{-mr_iterations}$) using * randomly selected bases. */ if (q.IsProbablePrime(mr_iterations - 1)) { break; } } Debug.Assert(p.IsProbablePrime(mr_iterations)); Debug.Assert(q.IsProbablePrime(mr_iterations)); }