Miller Rabin primality test

This commit is contained in:
2025-12-24 13:45:44 +01:00
parent d32a7d0f81
commit 0aa0fa2aa3
4 changed files with 41 additions and 10 deletions

View File

@@ -1,4 +1,4 @@
module ModularArithmeticUtils (modExp, modMul, legendre) where module ModularArithmeticUtils (modExp, modMul, legendre, factorOutTwos) where
import Data.Bits (testBit, shiftR) import Data.Bits (testBit, shiftR)
@@ -17,3 +17,11 @@ modMul a b m = (a * b) `mod` m
-- (a/p) in {-1, 0, 1} -- (a/p) in {-1, 0, 1}
legendre :: Integer -> Integer -> Integer legendre :: Integer -> Integer -> Integer
legendre a p = modExp a ((p - 1) `div` 2) p legendre a p = modExp a ((p - 1) `div` 2) p
-- Factor p-1 as q * 2^s, where q is odd
factorOutTwos :: Integer -> (Integer, Integer)
factorOutTwos n = go n 0
where
go x s
| even x = go (x `div` 2) (s + 1)
| otherwise = (x, s)

View File

@@ -10,6 +10,9 @@ file: `TonelliShanks.hs`
### Fermat's prime test ### Fermat's prime test
file: `fermat-prime-test.hs` file: `fermat-prime-test.hs`
### Miller Rabin's prime test
file: `miller-rabin-prime-test.hs`
## factorization algorithms ## factorization algorithms
### Fermat's factorization ### Fermat's factorization

View File

@@ -1,14 +1,6 @@
module TonelliShanks (tonelliShanks) where module TonelliShanks (tonelliShanks) where
import ModularArithmeticUtils (modExp, modMul, legendre) import ModularArithmeticUtils (modExp, modMul, legendre, factorOutTwos)
-- Factor p-1 as q * 2^s, where q is odd
factorOutTwos :: Integer -> (Integer, Integer)
factorOutTwos n = go n 0
where
go x s
| even x = go (x `div` 2) (s + 1)
| otherwise = (x, s)
-- Tonelli-Shanks algorithm: find x such that x^2 = n (mod p) -- Tonelli-Shanks algorithm: find x such that x^2 = n (mod p)
-- Returns Just x if it exists, Nothing otherwise. -- Returns Just x if it exists, Nothing otherwise.

View File

@@ -0,0 +1,28 @@
import System.Random (randomRIO)
import ModularArithmeticUtils (modExp, factorOutTwos)
millerRabinWitness :: Integer -> Integer -> Integer -> Integer -> Bool
millerRabinWitness n a d s =
let x0 = modExp a d n
in x0 == 1 || x0 == n - 1 || loop x0 (s - 1)
where
loop _ 0 = False
loop x r =
let x' = (x * x) `mod` n
in x' == n - 1 || loop x' (r - 1)
millerRabin :: Integer -> Integer -> IO Bool
millerRabin n k
| n < 2 = return False
| n == 2 = return True
| even n = return False
| otherwise = do
let (d, s) = factorOutTwos (n - 1)
go k d s
where
go 0 _ _ = return True
go i d s = do
a <- randomRIO (2, n - 2)
if millerRabinWitness n a d s
then go (i - 1) d s
else return False