Miller-Rabin’s method checks how likely it is that a given number is prime or non-prime. Thus, this primality test is probabilistic in nature.
Concepts to know before proceeding with Miller-Rabin’s primarlity test.
If p is a prime number then for any integer a, the below Fermat’s test always hold true
a p - 1 = 1 ( mod p ) for all a ∈ { 1, 2, . . . , p − 1 } i.e it basically means that if we divide a p - 1 by p we would get a remainder of 1.
or
a p - 1 - 1 = 0 ( mod p )
Example 1: Say p = 5 and a = 2, then 2 5-1 = 2 4 = 16 % 5 = 1
Example 2: Say p = 7 and a = 3, then 3 7-1 = 3 6 = 729 % 7 = 1
Thus a prime number would always pass Fermat’s test.
But the reverse is not true.
There are some composite numbers that also pass the Fermat’s test a p - 1 - 1 = 0 ( mod p ) for all values of a i.e a ∈ { 1, 2, . . . , p − 1 } .
Such composite numbers are called Carmichael numbers.
The first seven Carmichael numbers are 561, 1105, 1729, 2465, 2821, 6601, and 8911; and there are infinitely many such Carmichael numbers.
Conclusion : A passed Fermat’s primality test would not tell us with certanity if a number is prime.
Some essential concepts
Equation for factorizing difference of squares is
x2 - y2 = ( x + y ) . ( x - y )
Powers
Fermat’s equation for checking if a number p is prime is :
a p - 1 - 1 = 0 ( mod p ) for all a ∈ { 1, 2, . . . , p − 1 }.
As p is odd, we can write it as p - 1 = 2 r . d, ( d being odd ) so that we could factorize the equation using the difference of squares.
Thus we get the below equations
=> ( a 2 r - 1 . d - 1 ) . ( a 2 r - 1 . d + 1 ) = 0 ( mod p )
If 2 r - 1 is even, it could be written as 2 r - 1 = 2 . 2 r - 2 , thus we can further factorize the above equation as below else we stop factorizing
=> ( a 2 r - 2 . d - 1 ) . ( a 2 r - 2 . d + 1 ) . ( a 2 r - 1 . d + 1 ) = 0 ( mod p )
If we keep factorizing 2 r - 2 , eventaully it would become 2 1 , which would give us the below equation
=> ( a 2 1 . d - 1 ) … ( a 2 r - 2 . d + 1 ) . ( a 2 r - 1 . d + 1 ) = 0 ( mod p )
=> ( a d - 1 ) . ( a d + 1 ) … ( a 2 r - 2 . d + 1 ) . ( a 2 r - 1 . d + 1 ) = 0 ( mod p )
So this equation tells us that the number p ( which we are assuming to be prime ) has to divide atleast one of the terms on the L.H.S. But if p is not prime, then it need not divide a term on the L.H.S
Thus Miller-Rabin’s primality test check the below two conditions
Example : Check if p = 221 is prime or not.
p - 1 = 220 = 2 2 . 55 . Thus we have r = 2 and d = 55.
Iteration 1 : Random base a = 174
Iteration 2 : Random base a = 120
Note: If we have to find 4 mod 5, we do the below
4 mod 5 = 4
4 mod 5 = ( 5 - 1 ) mod 5 = -1 mod 5
The above could be written as 4 mod 5 = -1 mod 5
So we could generalize,
If ( a ) mod p = - 1 mod p, then ( a ) mod p = ( p - 1 ) mod p.
From the above deductions we can come up with the below algorithm
Miller-Rabin’s (single test) algorithm
Check_If_Prime ( p )
Example to get an idea of the probability of getting the correct answer:
Consider p = 15, then for a = 1, 2, 3, . . . , 14
We get the values of a p − 1 - 1 % p as = [ 0, 3, 8, 0, 9, 5, 3, 3, 5, 9, 0, 8, 3, 0 ]
Thus for a ∈ { 1, 4, 11, 14 } we have a p - 1 - 1 = 0 ( mod p )
So only for 4 out of 14 numbers conform a p - 1 - 1 = 0 ( mod p ).
Conclusion :
If we choose another random value for a from 1 … ( p - 1 ) the probability of Miller-Rabin’s test going wrong would go down from ( 1 / 4 ) to ( 1 / 4 ) * ( 1 / 4 ) i.e ( 1 / 16 ). Thus if we use 10 values of a the chance of going wrong would decrease from ( 1 / 4 ) to ( 1 / 4 ) 10
Implementation of Miller-Rabin’s primality test
import random
# p is the number to check, a is the base, d is odd, r is the power
def Check_If_Composite (p, a, d, r) :
# If the below is true, then the number is likely to be prime.
# Condition 1: If ( a ^ d ) = 1 ( mod p ) i.e find out if ( a ^ d ) % p = 1
# Condition 2: If ( a ^ ( ( 2 ^ 0 ) . d ) = - 1 ( mod p )
# i.e find out if ( a ^ d ) = -1 (mod p) which is same as finding out if ( a ^ d ) % p = p - 1
remainder = pow (a, d, p)
if (remainder == 1 or remainder == p - 1) :
return False
# Note : Remainder is already calulated above. It is (a ^ d) % p.
# Below loop would calulate if (a ^ (( 2 ^ t ).d)) == -1 (mod p) for some 1 <= t <= r-1
# And ( a ^ d ) = -1 (mod p) is same as ( a ^ d ) % p = p - 1
# Example ( a ^ d . a ^ d) % p = (a ^ 2.d) mod p
for t in range (1, r) :
if ((remainder * remainder) % p == p - 1) :
return False
return True
def Check_If_Prime (p, iterations) :
if (p == 2 or p == 3) :
return True
# p is even
if (p % 2 == 0) :
return False
# p - 1 has to be even as p is odd
d = p - 1
r = 0
while ((d % 2) == 0) :
d = int ( d / 2 )
r += 1
for i in range ( iterations + 1 ) :
# Choose a random a ∈ { 1, 2, . . . , p − 1 }.
a = random.randrange ( 2, p )
# If it is definitely composite, then it is not prime.
if ( Check_If_Composite(p, a, d, r) == True ) :
return False
return True
def main():
tests = int(input("How many numbers to check : "))
for i in range(tests):
p = int(input("Check if prime : "))
if (Check_If_Prime(p, 5) == True):
print("Yes")
else:
print("No")
if __name__ == "__main__" :
main()
Output
How many numbers to check : 10
Check if prime : 13
Yes
Check if prime : 221
No
Check if prime : 743
Yes
Check if prime : 751
Yes
Check if prime : 1067
No
Check if prime : 1069
Yes
Check if prime : 3571
Yes
Check if prime : 3251
Yes
Check if prime : 3409
No
Check if prime : 741
No
#include<iostream>
using namespace std;
typedef unsigned long long ULL;
// Evaluates ( a * b ) mod p. This is needed when a * b exceeds the sizeof of ULL;
ULL Modular_Mul (ULL a, ULL b, ULL p) {
ULL result = 0;
a = a % p;
while ( b > 0 ) {
if ( b & 1 ) {
result = ( result + a ) % p;
}
a = ( 2 * a ) % p;
b /= 2;
}
return result % p;
}
// Below function evaluates ( base ^ power ) mod p
ULL Modular_Expo (ULL base, ULL power, ULL p) {
ULL result = 1;
while ( power > 0 ) {
if ( power & 1 ) {
// Instead of evaluating the result as result = ( result * base ) % p
// do the multiplication under modulo
result = Modular_Mul(result, base, p);
}
// Instead of evaluating base as base = ( base * base ) % p
// do the multiplication of base under modulo
base = Modular_Mul(base, base, p);
power >>= 1; // power = power / 2
}
return result % p;
}
// p is the number to check, a is the base, d is odd, r is the power
bool Check_If_Composite (ULL p, ULL a, ULL d, ULL r) {
// If the below is true, then the number is likely to be prime.
// Condition 1: If ( a ^ d ) = 1 ( mod p ) i.e find out if ( a ^ d ) % p = 1
// Condition 2: If ( a ^ ( ( 2 ^ 0 ) . d ) = - 1 ( mod p )
// i.e find out if ( a ^ d ) = -1 (mod p) which is same as finding out if ( a ^ d ) % p = p - 1
ULL remainder = Modular_Expo(a, d, p);
if (remainder == 1 or remainder == p - 1)
return false;
// Note : Remainder is already calulated above. It is (a ^ d) % p.
// Below loop would calulate if (a ^ (( 2 ^ t ).d)) == -1 (mod p) for some 1 <= t <= r-1
// And ( a ^ d ) = -1 (mod p) is same as ( a ^ d ) % p = p - 1
// Example ( a ^ d . a ^ d) % p = (a ^ 2.d) mod p */
for (int t = 1; t < r; t++) {
remainder = Modular_Mul (remainder, remainder, p);
if (remainder == p - 1) {
return false;
}
}
return true;
}
bool Check_If_Prime (ULL p, int iterations) {
if (p == 2 or p == 3)
return true;
// p is even
if (p % 2 == 0)
return false;
// p - 1 has to be even as p is odd
ULL d = p - 1;
ULL r = 0;
while ( (d & 1) == 0 ) {
d >>= 1;
r++;
}
for (int i = 0; i <= iterations; i++) {
// Choose a random a ∈ { 1, 2, . . . , p − 1 }.
ULL a = 2 + rand() % (p - 2);
// If it is definitely composite, then it is not prime.
if ( Check_If_Composite(p, a, d, r) == true ) {
return false;
}
}
return true;
}
int main() {
int tests;
cout << "How many numbers to check: ";
cin >> tests;
ULL p;
for (int i = 0; i < tests; i++) {
cout << "Check : ";
cin >> p;
if (Check_If_Prime(p, 5))
cout << "Yes" << endl;
else
cout << "No" << endl;
}
return 0;
}
Output
How many numbers to check: 10
Check : 13
Yes
Check : 221
No
Check : 741
No
Check : 743
Yes
Check : 751
Yes
Check : 1067
No
Check : 1069
Yes
Check : 3571
Yes
Check : 3251
Yes
Check : 3407
Yes
import java.util.Scanner;
import java.util.Random;
class CheckPrime {
// Evaluates ( a * b ) mod p. This is needed when a * b exceeds the sizeof of int;
int Modular_Mul (int a, int b, int p) {
int result = 0;
a = a % p;
while ( b > 0 ) {
if ( b % 2 == 1 ) {
result = ( result + a ) % p;
}
a = ( 2 * a ) % p;
b /= 2;
}
return result % p;
}
// Below function evaluates ( base ^ power ) mod p
int Modular_Expo (int base, int power, int p) {
int result = 1;
while ( power > 0 ) {
if ( power % 2 == 1 ) {
// Instead of evaluating the result as result = ( result * base ) % p
// do the multiplication under modulo
result = Modular_Mul(result, base, p);
}
// Instead of evaluating base as base = ( base * base ) % p
// do the multiplication of base under modulo
base = Modular_Mul(base, base, p);
power >>= 1; // power = power / 2
}
return result % p;
}
// p is the number to check, a is the base, d is odd, r is the power
boolean Check_If_Composite (int p, int a, int d, int r) {
// If the below is true, then the number is likely to be prime.
// Condition 1: If ( a ^ d ) = 1 ( mod p ) i.e find out if ( a ^ d ) % p = 1
// Condition 2: If ( a ^ ( ( 2 ^ 0 ) . d ) = - 1 ( mod p )
// i.e find out if ( a ^ d ) = -1 (mod p) which is same as finding out if ( a ^ d ) % p = p - 1
int remainder = Modular_Expo (a, d, p);
if (remainder == 1 || remainder == p - 1)
return false;
// Note : Remainder is already calulated above. It is (a ^ d) % p.
// Below loop would calulate if (a ^ (( 2 ^ t ).d)) == -1 (mod p) for some 1 <= t <= r-1
// And ( a ^ d ) = -1 (mod p) is same as ( a ^ d ) % p = p - 1
// Example ( a ^ d . a ^ d) % p = (a ^ 2.d) mod p */
for (int t = 1; t < r; t++) {
remainder = Modular_Mul (remainder, remainder, p);
if (remainder == p - 1) {
return false;
}
}
return true;
}
boolean Check_If_Prime (int p, int iterations) {
if (p == 2 || p == 3)
return true;
// p is even
if (p % 2 == 0)
return false;
// p - 1 has to be even as p is odd
int d = p - 1;
int r = 0;
while ( (d & 1) == 0 ) {
d >>= 1;
r++;
}
Random rand = new Random();
for (int i = 0; i <= iterations; i++) {
// Choose a random a ∈ { 1, 2, . . . , p − 1 }.
int a = rand.nextInt ( p - 1 ) + 2;
// If it is definitely composite, then it is not prime.
if ( Check_If_Composite(p, a, d, r) ) {
return false;
}
}
return true;
}
public static void main (String[] args) {
Scanner sc= new Scanner(System.in);
System.out.print("How many numbers to check: ");
int tests = sc.nextInt();
CheckPrime obj = new CheckPrime();
int p;
for (int i = 0; i < tests; i++) {
System.out.print("Check if prime : ");
p = sc.nextInt();
if (obj.Check_If_Prime(p, 5))
System.out.println("Yes");
else
System.out.println("No");
}
}
}
Output
How many numbers to check: 10
Check if prime : 13
Yes
Check if prime : 221
No
Check if prime : 741
No
Check if prime : 743
Yes
Check if prime : 751
Yes
Check if prime : 1067
No
Check if prime : 1069
Yes
Check if prime : 3571
Yes
Check if prime : 3251
Yes
Check if prime : 3407
Yes