Sindbad~EG File Manager
/* Arithmetic mod m, where m is a bignum */
/* Strong pseudoprime test */
/*
3.7.90 first draft
5.21.91 completed
1.14.93 corrected space allocation errors in pseudoprime
11.18.93 added heap.h
5.3.94 modified for Windows
1.29.98 last modified for Microsoft Visual C++
4.6.04 rewrote pseudoprime following CLRS p. 891
Moved primality_test into this file from nfactor.c
4.6.04 corrected primality_test, where the test for being less than 25 billion
up to now presumed 16-bit digits. Removed display_progress from primality_test.
Rewrote primality_test to call rand() so it is the Miller-Rabin primality test.
*/
#include <stdlib.h>
#include <time.h>
#include <string.h> /* memset */
#include <assert.h>
#define BIGNUMS_DLL
#include "export.h"
#include "heap.h"
#include "bignum.h"
/* in modular arithmetic mod m, we arrange that all bignums have
m.ln + 1 digits allocated, so that they can be used as quotients
for receiving answers from bigdivide by m. */
#define MAKEMOD(m,u) (u).val = getspace((m).ln + 2)
/*________________________________________________________________*/
MEXPORT_BIGNUMS void mod2(bignum m, bignum u, bignum *ansp)
/* reduce u mod m */
/* ansp->val must have m.ln +1 digits allocated */
{ int test;
bignum q;
digit ansdigit;
if( m.ln == 1) /* m is really just a digit */
{if( u.ln == 1 && (u.val[0] < m.val[0] ))
{ ansp->ln = 1;
ansp->val[0] = u.val[0];
return;
}
if( u.ln == 1 )
{ ansp->ln = 1;
ansp->val[0] = u.val[0] % m.val[0];
return;
}
/* if we get here then m has only one digit but u has more than one */
{ divide_by_digit(u,m.val[0],&q,&ansdigit);
ansp->ln = 1;
ansp->val[0] = ansdigit;
freespace(q.val);
return;
}
}
test = compare(u,m);
if( test < 0)
{ ansp->ln = u.ln;
memcpy(ansp->val,u.val,u.ln*sizeof(digit));
return;
}
if(test == 0)
{ ansp->ln = 1;
ansp->val[0] = 0;
return;
}
else
{ MAKEMOD(m,q);
bigdivide2(u,m,&q,ansp); /* assumes divisor is less than dividend */
freespace(q.val);
}
return;
}
/*____________________________________________________________*/
MEXPORT_BIGNUMS void mod(bignum m, bignum u, bignum *ansp)
/* reduce u mod m returning in freshly allocated space */
{
MAKEMOD(m, *ansp);
mod2(m,u,ansp);
}
/*___________________________________________________________________*/
MEXPORT_BIGNUMS void bigplusmod2(bignum m, bignum a, bignum b, bignum *ans)
/* compute a+b mod m, where 0 <= a < m and 0 <= b < m */
/* assume *ans has m.ln + 1 digits available */
{ bigplus2(a,b,ans);
if( compare(m,*ans) != 1)
bigminus2(*ans,m,ans);
return;
}
/*____________________________________________________________________*/
MEXPORT_BIGNUMS void bigplusmod(bignum m, bignum a, bignum b, bignum *ans)
/* compute a+b mod m, where 0 <= a < m and 0 <= b < m */
/* allocate space for the answer */
{ MAKEMOD(m,*ans);
bigplusmod2(m,a,b,ans);
}
/*___________________________________________________________________*/
MEXPORT_BIGNUMS void bigmultmod2(bignum m, bignum a, bignum b, bignum *ans)
/* compute a*b mod m for 0 <= a,b < m */
/* assumes space already allocated for the answer */
/* bigmultmod(m,a,a,&a) is ok */
{ bignum temp;
bigmult(a,b,&temp);
mod2(m,temp,ans);
freespace(temp.val);
}
/*___________________________________________________________________*/
MEXPORT_BIGNUMS void bigmultmod(bignum m, bignum a, bignum b, bignum *ans)
/* allocates space for the answer */
{ MAKEMOD(m,*ans);
bigmultmod2(m,a,b,ans);
}
/*___________________________________________________________________*/
/* compute u^x mod m where u, x and m are bignums */
/* assuming 0 <= u < m */
/* Algorithm 3.3, page 34 of Bressoud, Factorization and Primality Testing */
/* adapted to the realities of bignum arithmetic; two variables neven and
nodd are used instead of one variable n, to avoid copying; space is
for the answer, workspace is freed before returning; nonzero return
value signals error, either out of space or attempt to compute 0^0 mod m.
Unlike most bignum algorithms, the one that puts the answer in
specified storage is defined in terms of the one that allocates storage.
*/
MEXPORT_BIGNUMS void modexp2(bignum m, bignum u, bignum x, bignum *ansp)
/* puts the answer in preallocated space */
{ bignum ans;
modexp(m,u,x,&ans); /* allocates space for the answer */
ansp->ln = ans.ln;
memcpy(ansp->val,ans.val,ans.ln * sizeof(digit));
freespace(ans.val);
}
/*______________________________________________________________*/
MEXPORT_BIGNUMS void modexp(bignum m, bignum u, bignum x, bignum *ansp)
{ bignum a; /* local copy of u */
bignum b; /* local copy of x */
int ctr;
bignum neven,nodd; /* workspace */
MAKEMOD(m,a);
assert(u.ln <= m.ln);
a.ln = u.ln;
memcpy(a.val,u.val,a.ln * sizeof(digit)); /* make a copy of u */
if( x.ln == 1 && x.val[0] == 0) /* x = 0, so fail unless a= 0 also */
{ if (a.ln == 1 && a.val[0] == 0)
assert(0); /*error, 0^0 mod m */
else { a.ln = 1; a.val[0] = 1; return;}
}
/* Now x isn't zero and a < m ; make b a copy of x */
b.val = getspace(x.ln + 1); b.ln = x.ln;
memcpy(b.val,x.val,x.ln *sizeof(digit));
MAKEMOD(m,neven); /* set up workspace */
MAKEMOD(m,nodd);
neven.ln = 1; neven.val[0] = 1; /* initialize n= (bignum) 1 */
ctr = 0;
while (b.ln != 1 || b.val[0] != 0 ) /* while b != 0 */
{ if (b.val[0] & 1) /* if b is odd */
{ if( ctr & 1)
bigmultmod2(m,nodd,a,&neven);
else
bigmultmod2(m,neven,a,&nodd);
++ctr;
}
right_shift(b,1,&b); /* b = (integer)(b/2) */
bigmultmod2(m,a,a,&a); /* a = a*a mod m */
}
if (ctr & 1) /* ctr is odd, so answer is in nodd */
{
ansp->ln = nodd.ln;
ansp->val = nodd.val;
freespace(neven.val);
}
else /* ctr is even, so answer is in neven */
{
ansp->ln = neven.ln;
ansp->val = neven.val;
freespace(nodd.val);
}
}
/*____________________________________________________________________*/
static int pseudoprime(bignum n, bignum x)
/* apply strong pseudoprime test to n using x as the base.
n is assumed to be odd.
After CLRS page 891; compare also Knuth vol. 2 page 379.
Return value 1 means passed the test, is a pseudoprime.
Return value 0 means flunked the test, is definitely composite.
*/
{ unsigned j;
int i = 0;
int offset=0;
unsigned k = 0;
bignum q,y,temp;
q.val = getspace(n.ln + 2); /* the 2 extra is needed because q is used
below to hold a quotient from bigdivide2, which requires
2 extra quotient digits */
temp.val = getspace(2*n.ln + 2);
memcpy(q.val,n.val, n.ln * sizeof(digit));
q.ln = n.ln;
--q.val[0]; /* q = n-1, since n is odd */
while (q.val[0] == 0) /* take out k factors of 2 */
{ ++q.val;
++offset; /* keep track of it so we can free q.val correctly */
k+= NN;
--q.ln;
}
while((q.val[0] & (1 << i)) == 0)
++i;
right_shift(q,i,&q);
k += i; /* now n = 1 + 2^k q where q is odd */
if(q.ln == 1 && q.val[0] == 1) /* n = 1 + 2^k */
{ MAKEMOD(n,y);
y.ln = x.ln; /* make y a copy of x without calling modexp */
memcpy(y.val,x.val,y.ln *sizeof(digit));
}
else
modexp(n,x,q,&y); /* (Step P2) y = x^q mod n */
q.val -= offset;
/* Now q.val points to n.ln + 2 digits of valid space again */
for(j=0;j<k;j++)
{ int flag = 0; // set it if y == n-1 or y == 1
if(y.ln == n.ln) /* then check if y == n-1 */
{ for(i=y.ln-1; i >= 0; --i)
{ if (y.val[i] != n.val[i])
break;
}
if(i==0 && y.val[0] +1 == n.val[0]) /* then y == n-1 */
flag = 1;
}
if(y.ln == 1 && y.val[0] == 1)
flag = 1; // y is 1
bigmult2(y,y,&temp); /* two lines for y = y* mod n */
bigdivide2(temp,n,&q,&y);
if(!flag && y.ln==1 && y.val[0]==1)
goto fail; // y is a nontrivial square root of 1 mod n, so n is composite
}
if(y.ln == 1 && y.val[0] == 1)
goto pass;
fail:
freespace(temp.val);
freespace(y.val);
freespace(q.val);
return 0; /* definitely not prime, flunks the test */
pass:
freespace(temp.val);
freespace(y.val);
freespace(q.val);
return 1; /* pass the test */
}
/*___________________________________________________________________*/
#define NPSEUDOPRIMETESTS 20
static unsigned tests[] = {2,3,5};
/* The following is the Miller-Rabin primality test.
The chance of it saying that a composite number is prime
is less that (1/2)^ N PSEUDOPRIMETESTS, i.e. less than
one in a million with NPSEUDOPRIMETESTS set to 20.
Compare CLRS page 891.
*/
MEXPORT_BIGNUMS int primality_test(bignum b)
/* return 0 if
(a) it's less than 25 billion, passes the strong pseudoprime test for
2,3,5, and isn't 151*171*28351
(b) it passes the strong pseudoprime test for
the first NPSEUDOPRIMETESTS odd integers
Return 1 if definitely composite, i.e. flunks the test
*/
{ bignum x;
int i,prime;
unsigned j;
x.val = getspace(b.ln);
if(b.ln == 1 || (b.ln == 2 && b.val[1] <= 6)) /* b < 25 billion appx */
{ for(i=0;i<3;i++)
{ x.val[0] = tests[i];
if(!pseudoprime(b,x))
return 1; /* flunks the test, definitely composite */
}
if( b.ln == 1 && b.val[0] == 3215031751UL)
{ /* 3215031751 is the one number < 25 billion that passes the
primality test, see Bressoud page 78 */
return 1; /* composite, factors are 151, 171, 28351 */
}
return 0; /* definitely prime */
}
/* Now the number is more than 25 billion */
srand((unsigned)time(NULL));
for(i=0;i<= NPSEUDOPRIMETESTS ;i++)
{ x.ln = b.ln -1; // at least 1
for(j=0;j<x.ln;j++)
{ unsigned t1 = rand();
unsigned t2 = rand();
x.val[j] = t1 << 16 | t2;
/* t1 and t2 are between 0 and RAND_MAX, which is 0x7fff,
the largest 16-bit signed integer. So these digits aren't
quite random because they always have bits 15 and 31 zero.
But they're random enough.
*/
}
if(x.val[x.ln-1] == 0)
x.val[x.ln-1] = 1; /* force it to be nonzero and have x.ln digits */
prime = pseudoprime(b,x);
/* pseudoprime returns 1 if it passes the test */
if(!prime)
return 1;
}
freespace(x.val);
return 0; /* passes the test for 2 and the first 100 odd integers */
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists