SCIP 1.28
Exercise 1.28. One variant of the Fermat test that cannot be fooled is called the Miller-Rabin test
(Miller 1976; Rabin 1980). This starts from an alternate form of Fermat's Little Theorem, which
states that if n is a prime number and a is any positive integer less than n, then a raised to the (n -
1)st power is congruent to 1 modulo n. To test the primality of a number n by the Miller-Rabin test,
we pick a random number a which less than n and raise a to the (n - 1)st power modulo n using the expmod
procedure. However, whenever we perform the squaring step in expmod, we check to see if we
have discovered a ``nontrivial square root of 1 modulo n,'' that is, a number not equal to 1 or n - 1
whose square is equal to 1 modulo n. It is possible to prove that if such a nontrivial square root of 1
exists, then n is not prime. It is also possible to prove that if n is an odd number that is not prime,
then, for at least half the numbers a which less than n, computing an-1 in this way will reveal a nontrivial square
root of 1 modulo n. (This is why the Miller-Rabin test cannot be fooled.) Modify the expmod
procedure to signal if it discovers a nontrivial square root of 1, and use this to implement the MillerRabin
test with a procedure analogous to fermat-test. Check your procedure by testing various
known primes and non-primes. Hint: One convenient way to make expmod signal is to have it
return 0.
(defun square(x)
(* x x))
(defun even?(x)
(= (mod x 2) 0))
(defun non-trivial-sqrt? (x n)
(and (not (= x 1))
(not (= x (- n 1)))
(= (mod (square x) n) 1)))
(defun zero-if-non-trivial-sqrt(x n)
(if (non-trivial-sqrt? x n) 0 x))
(defun mrt-expmod (base exp m)
(cond ((= exp 0) 1)
((even? exp) (mod
(square
(zero-if-non-trivial-sqrt
(mrt-expmod base (/ exp 2) m) m)) m))
( (mod (* base (mrt-expmod base (- exp 1) m)) m))))
(defun miller-rabin-test-all (n)
(defun try-it (a)
(cond ((= a n) t)
((= (mrt-expmod a (- n 1) n) 1) (try-it (+ a 1)))
(nil)))
(try-it 1))
CL-USER 138 > (miller-rabin-test-all 561)
NIL
CL-USER 139 > (miller-rabin-test-all 1105)
NIL
CL-USER 140 > (miller-rabin-test-all 1729)
NIL
CL-USER 141 > (miller-rabin-test-all 2465)
NIL
CL-USER 142 > (miller-rabin-test-all 2821)
NIL
CL-USER 143 > (miller-rabin-test-all 6601)
NIL
CL-USER 144 > (miller-rabin-test-all 1)
T
CL-USER 145 > (miller-rabin-test-all 2)
T
CL-USER 146 > (miller-rabin-test-all 3)
T
CL-USER 147 > (miller-rabin-test-all 4)
NIL
CL-USER 148 > (miller-rabin-test-all 5)
T
CL-USER 149 > (miller-rabin-test-all 6)
NIL
CL-USER 150 > (miller-rabin-test-all 7)
T
CL-USER 151 > (miller-rabin-test-all 8)
NIL
CL-USER 152 > (miller-rabin-test-all 9)
NIL
Edit and test in LispWorks 7.0.0 Professional edition.