xref: /plan9/sys/src/libsec/port/probably_prime.c (revision 08d24c93b03ab85c8ecf95f25385e4d988cc5e8e)
180ee5cbfSDavid du Colombier #include "os.h"
280ee5cbfSDavid du Colombier #include <mp.h>
380ee5cbfSDavid du Colombier #include <libsec.h>
480ee5cbfSDavid du Colombier 
5*08d24c93SDavid du Colombier /*
6*08d24c93SDavid du Colombier  * Miller-Rabin probabilistic primality testing
7*08d24c93SDavid du Colombier  *	Knuth (1981) Seminumerical Algorithms, p.379
8*08d24c93SDavid du Colombier  *	Menezes et al () Handbook, p.39
9*08d24c93SDavid du Colombier  * 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep
10*08d24c93SDavid du Colombier  */
1180ee5cbfSDavid du Colombier int
probably_prime(mpint * n,int nrep)1280ee5cbfSDavid du Colombier probably_prime(mpint *n, int nrep)
1380ee5cbfSDavid du Colombier {
14*08d24c93SDavid du Colombier 	int j, k, rep, nbits, isprime;
1580ee5cbfSDavid du Colombier 	mpint *nm1, *q, *x, *y, *r;
1680ee5cbfSDavid du Colombier 
1780ee5cbfSDavid du Colombier 	if(n->sign < 0)
1880ee5cbfSDavid du Colombier 		sysfatal("negative prime candidate");
1980ee5cbfSDavid du Colombier 
2080ee5cbfSDavid du Colombier 	if(nrep <= 0)
2180ee5cbfSDavid du Colombier 		nrep = 18;
2280ee5cbfSDavid du Colombier 
2380ee5cbfSDavid du Colombier 	k = mptoi(n);
24*08d24c93SDavid du Colombier 	if(k == 2)		/* 2 is prime */
2580ee5cbfSDavid du Colombier 		return 1;
26*08d24c93SDavid du Colombier 	if(k < 2)		/* 1 is not prime */
2780ee5cbfSDavid du Colombier 		return 0;
28*08d24c93SDavid du Colombier 	if((n->p[0] & 1) == 0)	/* even is not prime */
2980ee5cbfSDavid du Colombier 		return 0;
3080ee5cbfSDavid du Colombier 
31*08d24c93SDavid du Colombier 	/* test against small prime numbers */
3280ee5cbfSDavid du Colombier 	if(smallprimetest(n) < 0)
3380ee5cbfSDavid du Colombier 		return 0;
3480ee5cbfSDavid du Colombier 
35*08d24c93SDavid du Colombier 	/* fermat test, 2^n mod n == 2 if p is prime */
3680ee5cbfSDavid du Colombier 	x = uitomp(2, nil);
3780ee5cbfSDavid du Colombier 	y = mpnew(0);
3880ee5cbfSDavid du Colombier 	mpexp(x, n, n, y);
3980ee5cbfSDavid du Colombier 	k = mptoi(y);
4080ee5cbfSDavid du Colombier 	if(k != 2){
4180ee5cbfSDavid du Colombier 		mpfree(x);
4280ee5cbfSDavid du Colombier 		mpfree(y);
4380ee5cbfSDavid du Colombier 		return 0;
4480ee5cbfSDavid du Colombier 	}
4580ee5cbfSDavid du Colombier 
4680ee5cbfSDavid du Colombier 	nbits = mpsignif(n);
4780ee5cbfSDavid du Colombier 	nm1 = mpnew(nbits);
48*08d24c93SDavid du Colombier 	mpsub(n, mpone, nm1);	/* nm1 = n - 1 */
4980ee5cbfSDavid du Colombier 	k = mplowbits0(nm1);
5080ee5cbfSDavid du Colombier 	q = mpnew(0);
51*08d24c93SDavid du Colombier 	mpright(nm1, k, q);	/* q = (n-1)/2**k */
5280ee5cbfSDavid du Colombier 
5380ee5cbfSDavid du Colombier 	for(rep = 0; rep < nrep; rep++){
54*08d24c93SDavid du Colombier 		for(;;){
55*08d24c93SDavid du Colombier 			/* find x = random in [2, n-2] */
5680ee5cbfSDavid du Colombier 		 	r = mprand(nbits, prng, nil);
5780ee5cbfSDavid du Colombier 		 	mpmod(r, nm1, x);
5880ee5cbfSDavid du Colombier 		 	mpfree(r);
59*08d24c93SDavid du Colombier 		 	if(mpcmp(x, mpone) > 0)
60*08d24c93SDavid du Colombier 		 		break;
61*08d24c93SDavid du Colombier 		}
6280ee5cbfSDavid du Colombier 
63*08d24c93SDavid du Colombier 		/* y = x**q mod n */
6480ee5cbfSDavid du Colombier 		mpexp(x, q, n, y);
6580ee5cbfSDavid du Colombier 
6680ee5cbfSDavid du Colombier 		if(mpcmp(y, mpone) == 0 || mpcmp(y, nm1) == 0)
67*08d24c93SDavid du Colombier 		 	continue;
6880ee5cbfSDavid du Colombier 
69*08d24c93SDavid du Colombier 		for(j = 1;; j++){
70*08d24c93SDavid du Colombier 		 	if(j >= k) {
71*08d24c93SDavid du Colombier 		 		isprime = 0;
7280ee5cbfSDavid du Colombier 		 		goto done;
73*08d24c93SDavid du Colombier 		 	}
74*08d24c93SDavid du Colombier 		 	mpmul(y, y, x);
75*08d24c93SDavid du Colombier 		 	mpmod(x, n, y);	/* y = y*y mod n */
76*08d24c93SDavid du Colombier 		 	if(mpcmp(y, nm1) == 0)
77*08d24c93SDavid du Colombier 		 		break;
7880ee5cbfSDavid du Colombier 		 	if(mpcmp(y, mpone) == 0){
7980ee5cbfSDavid du Colombier 		 		isprime = 0;
8080ee5cbfSDavid du Colombier 		 		goto done;
8180ee5cbfSDavid du Colombier 		 	}
8280ee5cbfSDavid du Colombier 		}
8380ee5cbfSDavid du Colombier 	}
84*08d24c93SDavid du Colombier 	isprime = 1;
8580ee5cbfSDavid du Colombier done:
8680ee5cbfSDavid du Colombier 	mpfree(y);
8780ee5cbfSDavid du Colombier 	mpfree(x);
8880ee5cbfSDavid du Colombier 	mpfree(q);
8980ee5cbfSDavid du Colombier 	mpfree(nm1);
9080ee5cbfSDavid du Colombier 	return isprime;
9180ee5cbfSDavid du Colombier }
92