Certifying that M_127 is prime
Let
Is
We can just look up what is known: the Wikipedia article on Mersenne prime links to OEIS A000043, “primes p such that 2^p - 1 is prime”, a list which contains
So yes,
But if someone doesn’t want to rely on published knowledge or a computer algebra system like Wolfram Alpha, could we convince them that
Think about that for a moment: if you want to convince someone that a number is not prime, all you have to do is give them a nontrivial factor. But how can you give a certificate that a number is not prime?
(In the days before the AKS primality test aka
In 1975, Vaughan Pratt (the same Pratt in “Knuth–Morris–Pratt” and “Pratt parser”) found a way, which relies on the Lucas primality test:
Lucas' theorem: Suppose we have an integer
such that:
, and for every prime factor of Then
is prime.
(Such an
We assume that the person we’re trying to convince understands the theorem above, and is good at computation and/or can use computers/calculators for simple straightforward calculations (like multiplication, exponentiation, and modular arithmetic), but does not trust complicated algorithms implemented inside computer algebra systems that would take a long time to read and verify.
So first we get the factorization of
import math
s = [2, 3, 3, 3, 7, 7, 19, 43, 73, 127, 337, 5419, 92737, 649657, 77158673929]
l1 = math.prod(s)
l2 = 2**127 - 2
print(l1)
print(l2)
print(l1 == l2)
Then, to prove that
Let’s try to find one, with brute force. Here,
import math
n = 2**127 - 1
s = [2, 3, 3, 3, 7, 7, 19, 43, 73, 127, 337, 5419, 92737, 649657, 77158673929]
assert math.prod(s) == n - 1
witness = None
for a in range(1, n):
if (pow(a, n - 1, mod=n) == 1 and
all(pow(a, (n - 1)//q, mod=n) != 1 for q in s)):
witness = a
break
print(witness)
This prints
This is a certificate to convince our sceptical friend: all we need to give them is the above list of prime factors of
But wait, says our friend: how do I know that you aren’t trying to trick me by giving some large composite numbers in the list of “prime” factors: how do I know that (say) 77158673929 is actually prime?
The answer is that we can certify it (recursively) in the same way!
This is the idea behind Pratt’s primality certificate. For this example, let’s find a complete certificate. For the purposes of this blog post, we’ll not bother with a factoring algorithm here, and hard-code every factorization we’ll need, obtained from elsewhere (it does not matter, as everything will be verified by our friend):
import math
def witness(n, factors):
for a in range(1, n):
if (pow(a, n - 1, mod=n) == 1 and
all(pow(a, (n - 1)//q, mod=n) != 1 for q in factors)):
return a
def certificate(n):
factors = known_factors[n-1]
assert math.prod(factors) == n - 1
a = witness(n, factors)
if not a: return None
certificates = [certificate(q) for q in factors]
return {'p': n, 'witness': a, 'primes': certificates}
known_factors = {
1: [],
2: [2],
4: [2, 2],
6: [2, 3],
10: [2, 5],
18: [2, 3, 3],
22: [2, 11],
42: [2, 3, 7],
72: [2, 2, 2, 3, 3],
126: [2, 3, 3, 7],
336: [2, 2, 2, 2, 3, 7],
1288: [2, 2, 2, 7, 23],
5418: [2, 3, 3, 7, 43],
92736: [2, 2, 2, 2, 2, 2, 3, 3, 7, 23],
174762: [2, 3, 3, 7, 19, 73],
649656: [2, 2, 2, 3, 3, 7, 1289],
699052: [2, 2, 174763],
77158673928: [2, 2, 2, 3, 3, 3, 7, 73, 699053],
170141183460469231731687303715884105726: [2, 3, 3, 3, 7, 7, 19, 43, 73, 127, 337, 5419, 92737, 649657, 77158673929],
}
n = 2**127 - 1
printed = set()
def cprint(cert, indent):
p = cert['p']
print(indent, p)
if p in printed or p < 1000: return
printed.add(p)
print(indent, '-> Witness', cert['witness'], 'with primes:')
for qc in cert['primes']:
cprint(qc, indent + ' ')
cprint(certificate(n), '')
The (large) output of the program above amounts to a verifiable certificate that
170141183460469231731687303715884105727
-> Witness 43 with primes:
2
3
3
3
7
7
19
43
73
127
337
5419
-> Witness 3 with primes:
2
3
3
7
43
92737
-> Witness 5 with primes:
2
2
2
2
2
2
3
3
7
23
649657
-> Witness 5 with primes:
2
2
2
3
3
7
1289
-> Witness 6 with primes:
2
2
2
7
23
77158673929
-> Witness 11 with primes:
2
2
2
3
3
3
7
73
699053
-> Witness 2 with primes:
2
2
174763
-> Witness 17 with primes:
2
3
3
7
19
73
In the output above, our friend can verify that any particular number
Further work: turn this into an interactive webpage, where clicking on any prime will show a certificate of primality for it.