/* * implementation of * Agrawal, Kayal, and Saxena's * deterministic polytime primality test * * Copyright © 2002 Bart Massey. * All Rights Reserved. See the file COPYING in this directory * for licensing information. * * Bart Massey 2002/8/16 */ /* The algorithm (from page 4 of the original abstract) * * Input: integer n > 1 * 1. if ( n is of the form a ** b , b > 1 ) output COMPOSITE; * 2. r = 2; * 3. while(r < n) { * 4. if ( gcd(n,r) =/= 1 ) output COMPOSITE; * 5. if (r is prime) * 6. let q be the largest prime factor of r - 1; * 7. if (q >= 4 sqrt(r) log(n)) and ((n ** ((r-1)/q)) =/= 1) (mod r)) * 8. break; * 9. r = r + 1; * 10. } * 11. for a = 1 to 2 sqrt(r) log(n) * 12. if ( (x - a) ** n =/= x**n - a (mod x**r - 1, n) ) output COMPOSITE; * 13. output PRIME; */ load "numbers.5c"; import Numbers; load "polynomial.5c"; import Polynomial; /* Returns the largest factor of n, computed the dumbest way. */ int max_factor(int n) { int factor = 1; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { factor = i; n /= factor; } } return factor; } /* * returns true iff n is of the form * a ** b for some integers a > 1, b > 1. */ bool is_xn(int n) { /* Could just do prime powers, but this is about as cheap and easier. */ int b = 2; real a = exp(log(n) / b); while (a > 1.9) { if (floor(a) ** b == n || ceil(a) ** b == n) return true; a = exp(log(n) / ++b); } return false; } /* * The polytime algorithm below is painfully slow * in the small case. It's only a constant, but * a big-deal one. */ bool is_small_prime(int n) { if (n < 2) abort("small prime test below 2"); global int small = 50; if (n >= small) return false; global bool[*] init_sieve() { bool[small] sieve = {true ...}; int k = 2; while (k < small) { for (int i = k + k; i < small; i += k) sieve[i] = false; k++; while(k < small && !sieve[k]) k++; } return sieve; } global bool[small] sieve = init_sieve(); return sieve[n]; } bool is_prime(int n) { if (n < 2) abort("prime test below 2"); if (is_small_prime(n)) return true; if (is_xn(n)) return false; int r; for (r = 2; r < n; r++) { if (gcd(n, r) != 1) return false; if (!is_prime(r)) continue; int q = max_factor(r - 1); if (q ** 2 >= 16 * r * (log2(n) ** 2) && bigpowmod(n, ((r - 1) / q), r) != 1) break; } int[r + 1] m1 = {-1, 0...}; m1[r] = 1; polynomial mn = m1; mn[0] = -n; for (int a = 1; a ** 2 <= 4 * r * (log2(n) ** 2); a++) { bool eqn(polynomial m) { polynomial lhs = power_mod((polynomial){-a, 1}, n, m); int[n + 1] rhsp = {-a, 0...}; rhsp[n] = 1; polynomial rhs = div_mod(rhsp, m).rem; return lhs == rhs; } if (eqn(m1) && eqn(mn)) return false; } return true; } autoload MillerRabin; void test_is_prime() { for (int i = 2; i < 1000; i++) { if (is_prime(i) == MillerRabin::composite(i, 24)) { string msg; if (MillerRabin::composite(i, 24)) msg = sprintf("%d: false prime\n"); else msg = sprintf("%d: false composite\n"); abort(msg); } if (true || i % 100 == 0) printf("tested to %d\n", i); } } test_is_prime();