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