KGC_TEST/miracl/source/factor.c

1702 lines
46 KiB
C

/*
* Program to factor Integers
*
* Current parameters assume a large 32-bit address space is available.
*
* This program is cobbled together from the implementations of various
* factoring algorithms better described in:-
*
* brute.c/cpp - brute force division by small primes
* brent.c/cpp - Pollard Rho method as improved by Brent
* pollard.c/cpp - Pollard (p-1) method
* williams.c/cpp - Williams (p+1) method
* lenstra.c/cpp - Lenstra's Elliptic Curve method
* qsieve.c/cpp - The Multiple polynomial quadratic sieve
*
* Note that the .cpp C++ implementations are easier to follow
*
* NOTE: The quadratic sieve program requires a lot of memory for
* bigger numbers. It may fail if you system cannot provide the memory
* requested.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "miracl.h"
#define LIMIT 15000
#define BTRIES 1000
#define MULT 2310 /* 2*3*5*7*11 */
#define NEXT 13 /* .. next prime */
#define mr_min(a,b) ((a) < (b)? (a) : (b))
static big *fu;
static BOOL *cp,*plus,*minus;
big n;
FILE *output;
static BOOL suppress=FALSE;
static int PADDING;
static miracl *mip;
void brute(void)
{ /* find factors by brute force division */
big x,y;
int m,p;
gprime(LIMIT);
x=mirvar(0);
y=mirvar(0);
m=0;
p=mip->PRIMES[0];
forever
{ /* try division by each prime in turn */
if (subdiv(n,p,y)==0)
{ /* factor found */
copy(y,n);
if (!suppress) printf("PRIME FACTOR ");
fprintf(output,"%d\n",p);
if (size(n)==1) exit(0);
continue;
}
if (size(y)<=p)
{ /* must be prime */
if (!suppress) printf("PRIME FACTOR ");
cotnum(n,output);
exit(0);
}
p=mip->PRIMES[++m];
if (p==0) break;
}
if (isprime(n))
{
if (!suppress) printf("PRIME FACTOR ");
cotnum(n,output);
exit(0);
}
mr_free(x);
mr_free(y);
gprime(0);
}
void brent(void)
{ /* factoring program using Brents method */
long k,r,i,m,iter;
big x,y,ys,z,q,c3,t;
x=mirvar(0);
y=mirvar(0);
ys=mirvar(0);
z=mirvar(0);
q=mirvar(0);
c3=mirvar(3);
t=mirvar(0);
m=10;
r=1;
iter=0;
do
{
if (!suppress) printf("iterations=%5ld",iter);
convert(1,q);
do
{
copy(y,x);
for (i=1;i<=r;i++)
mad(y,y,c3,n,n,y);
k=0;
do
{
iter++;
if (iter>BTRIES)
{
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
}
mr_free(t);
mr_free(x);
mr_free(y);
mr_free(ys);
mr_free(z);
mr_free(q);
mr_free(c3);
return;
}
if (iter%10==0) if (!suppress)
{
printf("\b\b\b\b\b%5ld",iter);
fflush(stdout);
}
copy(y,ys);
for (i=1;i<=mr_min(m,r-k);i++)
{
mad(y,y,c3,n,n,y);
subtract(y,x,z);
mad(z,q,q,n,n,q);
}
egcd(q,n,z);
k+=m;
} while (k<r && size(z)==1);
r*=2;
} while (size(z)==1);
if (mr_compare(z,n)==0) do
{ /* back-track */
mad(ys,ys,c3,n,n,ys);
subtract(ys,x,z);
} while (egcd(z,n,z)==1);
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
}
forever
{
if (isprime(z))
{
if (!suppress) printf("PRIME FACTOR ");
cotnum(z,output);
}
else
{ /* if end of factorisation - pass it on... */
if (mr_compare(z,n)==0) return;
/* you will have to come back to it */
if (!suppress) printf("COMPOSITE FACTOR ");
else printf("& ");
cotnum(z,output);
}
divide(n,z,n);
divide(y,n,n);
copy(n,t);
divide(t,z,z);
if (size(t)==0) continue;
break;
}
if (size(n)==1) exit(0);
} while (!isprime(n));
if (!suppress) printf("PRIME FACTOR ");
cotnum(n,output);
exit(0);
}
void marks(long start)
{ /* mark non-primes in this interval. Note *
* that those < NEXT are dealt with already */
int i,pr,j,k;
for (j=1;j<=MULT/2;j+=2) plus[j]=minus[j]=TRUE;
for (i=0;;i++)
{ /* mark in both directions */
pr=mip->PRIMES[i];
if (pr<NEXT) continue;
if ((long)pr*pr>start) break;
k=pr-start%pr;
for (j=k;j<=MULT/2;j+=pr)
plus[j]=FALSE;
k=start%pr;
for (j=k;j<=MULT/2;j+=pr)
minus[j]=FALSE;
}
}
void pollard(int lim1,long lim2)
{ /* factoring program using Pollards (p-1) method */
long i,p,pa,interval;
int phase,m,pos,btch,iv;
big t,b,bw,bvw,bd,bp,q;
t=mirvar(0);
b=mirvar(0);
q=mirvar(0);
bw=mirvar(0);
bvw=mirvar(0);
bd=mirvar(0);
bp=mirvar(0);
gprime(lim1);
for (m=1;m<=MULT/2;m+=2)
if (igcd(MULT,m)==1)
{
fu[m]=mirvar(0);
cp[m]=TRUE;
}
else cp[m]=FALSE;
phase=1;
p=0;
btch=50;
i=0;
convert(3,b);
if (!suppress) printf("phase 1 - trying all primes less than %d\n",lim1);
if (!suppress) printf("prime= %8ld",p);
forever
{
if (phase==1)
{ /* looking for all factors of (p-1) < lim1 */
p=mip->PRIMES[i];
if (mip->PRIMES[i+1]==0)
{
phase=2;
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
printf("phase 2 - trying last prime less than %ld\n"
,lim2);
printf("prime= %8ld",p);
}
power(b,8,n,bw);
convert(1,t);
copy(b,bp);
copy(b,fu[1]);
for (m=3;m<=MULT/2;m+=2)
{ /* store fu[m] = b^(m*m) */
mad(t,bw,bw,n,n,t);
mad(bp,t,t,n,n,bp);
if (cp[m]) copy(bp,fu[m]);
}
power(b,MULT,n,t);
power(t,MULT,n,t);
mad(t,t,t,n,n,bd); /* bd=b^(2*MULT*MULT) */
iv=p/MULT;
if (p%MULT>MULT/2) iv++;
interval=(long)iv*MULT;
p=interval+1;
marks(interval);
power(t,2*iv-1,n,bw);
power(t,iv,n,bvw);
power(bvw,iv,n,bvw); /* bvw = b^(MULT*MULT*iv*iv) */
subtract(bvw,fu[p%MULT],q);
btch*=100;
i++;
continue;
}
pa=p;
while ((lim1/p) > pa) pa*=p;
power(b,(int)pa,n,b);
decr(b,1,q);
}
else
{ /* looking for last PRIME FACTOR of (p-1) < lim2 */
p+=2;
pos=p%MULT;
if (pos>MULT/2)
{ /* increment giant step */
iv++;
interval=(long)iv*MULT;
p=interval+1;
marks(interval);
pos=1;
mad(bw,bd,bd,n,n,bw);
mad(bvw,bw,bw,n,n,bvw);
}
if (!cp[pos]) continue;
/* if neither interval+/-pos is prime, don't bother */
if (!plus[pos] && !minus[pos]) continue;
subtract(bvw,fu[pos],t);
mad(q,t,t,n,n,q); /* batching gcds */
}
if (i++%btch==0)
{ /* try for a solution */
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b%8ld",p);
fflush(stdout);
}
egcd(q,n,t);
if (size(t)==1)
{
if (p>lim2)
{
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
}
break;
}
else continue;
}
if (mr_compare(t,n)==0)
{
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
printf("degenerate case\n");
}
break;
}
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
if (isprime(t)) printf("PRIME FACTOR ");
else printf("COMPOSITE FACTOR ");
}
else if (!isprime(t)) printf("& ");
cotnum(t,output);
divide(n,t,n);
if (isprime(n))
{
if (!suppress) printf("PRIME FACTOR ");
cotnum(n,output);
exit(0);
}
break;
}
}
gprime(0);
mr_free(t);
mr_free(b);
mr_free(q);
mr_free(bw);
mr_free(bvw);
mr_free(bd);
mr_free(bp);
for (m=1;m<=MULT/2;m+=2)
if (igcd(MULT,m)==1) mr_free(fu[m]);
}
void williams(int lim1,long lim2,int ntrys)
{ /* factoring program using Williams (p+1) method */
int k,phase,m,nt,iv,pos,btch;
long i,p,pa,interval;
big b,q,fp,fvw,fd,fn,t;
b=mirvar(0);
q=mirvar(0);
t=mirvar(0);
fp=mirvar(0);
fvw=mirvar(0);
fd=mirvar(0);
fn=mirvar(0);
gprime(lim1);
for (m=1;m<=MULT/2;m+=2)
if (igcd(MULT,m)==1)
{
fu[m]=mirvar(0);
cp[m]=TRUE;
}
else cp[m]=FALSE;
for (nt=0,k=3;k<10;k++)
{ /* try more than once for p+1 condition (may be p-1) */
convert(k,b); /* try b=3,4,5.. */
convert((k*k-4),t);
if (egcd(t,n,t)!=1) continue; /* check (b*b-4,n)!=0 */
nt++;
phase=1;
p=0;
btch=50;
i=0;
if (!suppress) printf("phase 1 - trying all primes less than %d\n",lim1);
if (!suppress) printf("prime= %8ld",p);
forever
{ /* main loop */
if (phase==1)
{ /* looking for all factors of p+1 < lim1 */
p=mip->PRIMES[i];
if (mip->PRIMES[i+1]==0)
{ /* now change gear */
phase=2;
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
printf("phase 2 - trying last prime less than %ld\n"
,lim2);
printf("prime= %8ld",p);
}
copy(b,fu[1]);
copy(b,fp);
mad(b,b,b,n,n,fd);
decr(fd,2,fd);
negify(b,t);
mad(fd,b,t,n,n,fn);
for (m=5;m<=MULT/2;m+=2)
{ /* store fu[m] = Vm(b) */
negify(fp,t);
mad(fn,fd,t,n,n,t);
copy(fn,fp);
copy(t,fn);
if (!cp[m]) continue;
copy(t,fu[m]);
}
convert(MULT,t);
lucas(b,t,n,fp,fd);
iv=p/MULT;
if (p%MULT>MULT/2) iv++;
interval=(long)iv*MULT;
p=interval+1;
marks(interval);
convert(iv,t);
lucas(fd,t,n,fp,fvw);
negify(fp,fp);
subtract(fvw,fu[p%MULT],q);
btch*=100;
i++;
continue;
}
pa=p;
while ((lim1/p) > pa) pa*=p;
convert((int)pa,t);
lucas(b,t,n,fp,q);
copy(q,b);
decr(q,2,q);
}
else
{ /* phase 2 - looking for last large PRIME FACTOR of (p+1) */
p+=2;
pos=p%MULT;
if (pos>MULT/2)
{ /* increment giant step */
iv++;
interval=(long)iv*MULT;
p=interval+1;
marks(interval);
pos=1;
copy(fvw,t);
mad(fvw,fd,fp,n,n,fvw);
negify(t,fp);
}
if (!cp[pos]) continue;
/* if neither interval+/-pos is prime, don't bother */
if (!plus[pos] && !minus[pos]) continue;
subtract(fvw,fu[pos],t);
mad(q,t,t,n,n,q); /* batching gcds */
}
if (i++%btch==0)
{ /* try for a solution */
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b%8ld",p);
fflush(stdout);
}
egcd(q,n,t);
if (size(t)==1)
{
if (p>lim2)
{
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
}
break;
}
else continue;
}
if (mr_compare(t,n)==0)
{
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
printf("degenerate case\n");
}
break;
}
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
if (isprime(t)) printf("PRIME FACTOR ");
else printf("COMPOSITE FACTOR ");
}
else if (!isprime(t)) printf("& ");
cotnum(t,output);
divide(n,t,n);
if (isprime(n))
{
if (!suppress) printf("PRIME FACTOR ");
cotnum(n,output);
exit(0);
}
nt=ntrys;
break;
}
}
if (nt>=ntrys) break;
}
gprime(0);
mr_free(b);
mr_free(q);
mr_free(t);
mr_free(fp);
mr_free(fvw);
mr_free(fd);
mr_free(fn);
for (m=1;m<=MULT/2;m+=2)
if (igcd(MULT,m)==1) mr_free(fu[m]);
}
static big ak,t,ww,s1,d1,s2,d2;
void duplication(big sum,big diff,big x,big z)
{ /* double a point on the curve P(x,z)=2.P(x1,z1) */
nres_modmult(sum,sum,t);
nres_modmult(diff,diff,z);
nres_modmult(t,z,x); /* x = sum^2.diff^2 */
nres_modsub(t,z,t); /* t = sum^2-diff^2 */
nres_modmult(ak,t,ww);
nres_modadd(z,ww,z); /* z = ak*t +diff^2 */
nres_modmult(z,t,z); /* z = z.t */
}
void addition(big xd,big zd,big sm1,big df1,big sm2,big df2,big x,big z)
{ /* add two points on the curve P(x,z)=P(x1,z1)+P(x2,z2) *
* given their difference P(xd,zd) */
nres_modmult(df2,sm1,x);
nres_modmult(df1,sm2,z);
nres_modadd(z,x,t);
nres_modsub(z,x,z);
nres_modmult(t,t,x);
nres_modmult(x,zd,x); /* x = zd.[df1.sm2+sm1.df2]^2 */
nres_modmult(z,z,z);
nres_modmult(z,xd,z); /* z = xd.[df1.sm2-sm1.df2]^2 */
}
void ellipse(big x,big z,int r,big x1,big z1,big x2,big z2)
{ /* calculate point r.P(x,z) on curve */
int k,rr;
k=1;
rr=r;
copy(x,x1);
copy(z,z1);
nres_modadd(x1,z1,s1);
nres_modsub(x1,z1,d1);
duplication(s1,d1,x2,z2); /* generate 2.P */
while ((rr/=2)>1) k*=2;
while (k>0)
{ /* use binary method */
nres_modadd(x1,z1,s1); /* form sums and differences */
nres_modsub(x1,z1,d1); /* x+z and x-z for P1 and P2 */
nres_modadd(x2,z2,s2);
nres_modsub(x2,z2,d2);
if ((r&k)==0)
{ /* double P(x1,z1) mP to 2mP */
addition(x,z,s1,d1,s2,d2,x2,z2);
duplication(s1,d1,x1,z1);
}
else
{ /* double P(x2,z2) (m+1)P to (2m+2)P */
addition(x,z,s1,d1,s2,d2,x1,z1);
duplication(s2,d2,x2,z2);
}
k/=2;
}
}
int lenstra(int lim1,long lim2,int nc,int kurve,int ncurves)
{ /* factoring program using Lenstras Elliptic Curve method */
int phase,m,iv,pos,btch,u,v,ncr;
long i,p,pa,interval;
big q,x,z,a,x1,z1,x2,z2,xt,zt,fvw;
q=mirvar(0);
x=mirvar(0);
z=mirvar(0);
a=mirvar(0);
x1=mirvar(0);
z1=mirvar(0);
x2=mirvar(0);
z2=mirvar(0);
s1=mirvar(0);
d1=mirvar(0);
s2=mirvar(0);
d2=mirvar(0);
ak=mirvar(0);
xt=mirvar(0);
zt=mirvar(0);
fvw=mirvar(0);
t=mirvar(0);
ww=mirvar(0);
gprime(lim1);
for (m=1;m<=MULT/2;m+=2)
if (igcd(MULT,m)==1)
{
fu[m]=mirvar(0);
cp[m]=TRUE;
}
else cp[m]=FALSE;
prepare_monty(n);
/* try a new curve */
/* generating an elliptic curve */
ncr=nc;
u=kurve*kurve-5;
v=4*kurve;
convert(u,x); nres(x,x);
convert(v,z); nres(z,z);
nres_modsub(z,x,a); /* a=v-u */
copy(x,t);
nres_modmult(x,x,x);
nres_modmult(x,t,x); /* x=u^3 */
copy(z,t);
nres_modmult(z,z,z);
nres_modmult(z,t,z); /* z=v^3 */
copy(a,t);
nres_modmult(t,t,t);
nres_modmult(t,a,t); /* t=(v-u)^3 */
convert(3*u,a); nres(a,a);
convert(v,ak); nres(ak,ak);
nres_modadd(a,ak,a);
nres_modmult(t,a,t); /* t=(v-u)^3.(3u+v) */
convert(u,a); nres(a,a);
copy(a,ak);
nres_modmult(a,a,a);
nres_modmult(a,ak,a); /* a=u^3 */
convert(v,ak); nres(ak,ak);
nres_modmult(a,ak,a); /* a=u^3.v */
nres_premult(a,16,a);
nres_moddiv(t,a,ak); /* ak=(v-u)^3.(3u+v)/16u^3v */
phase=1;
p=0;
i=0;
btch=50;
if (!suppress) printf("curve %3d phase 1 - trying all primes less than %d\n",nc,lim1);
if (!suppress) printf("prime= %8ld",p);
ncr++;
forever
{ /* main loop */
if (phase==1)
{
p=mip->PRIMES[i];
if (mip->PRIMES[i+1]==0)
{ /* now change gear */
phase=2;
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
printf(" phase 2 - trying last prime less than %ld\n",
lim2);
printf("prime= %8ld",p);
}
copy(x,xt);
copy(z,zt);
nres_modadd(x,z,s2);
nres_modsub(x,z,d2); /* P = (s2,d2) */
duplication(s2,d2,x,z);
nres_modadd(x,z,s1);
nres_modsub(x,z,d1); /* 2.P = (s1,d1) */
nres_moddiv(x1,z1,fu[1]); /* fu[1] = x1/z1 */
addition(x1,z1,s1,d1,s2,d2,x2,z2); /* 3.P = (x2,z2) */
for (m=5;m<=MULT/2;m+=2)
{ /* calculate m.P = (x,z) and store fu[m] = x/z */
nres_modadd(x2,z2,s2);
nres_modsub(x2,z2,d2);
addition(x1,z1,s2,d2,s1,d1,x,z);
copy(x2,x1);
copy(z2,z1);
copy(x,x2);
copy(z,z2);
if (!cp[m]) continue;
copy(z2,fu[m]);
nres_moddiv(x2,fu[m],fu[m]);
}
ellipse(xt,zt,MULT,x,z,x2,z2);
nres_modadd(x,z,xt);
nres_modsub(x,z,zt); /* MULT.P = (xt,zt) */
iv=(int)(p/MULT);
if (p%MULT>MULT/2) iv++;
interval=(long)iv*MULT;
p=interval+1;
marks(interval);
ellipse(x,z,iv,x1,z1,x2,z2); /* (x1,z1) = iv.MULT.P */
nres_moddiv(x1,z1,fvw); /* fvw = x1/z1 */
nres_modsub(fvw,fu[p%MULT],q);
btch*=100;
i++;
continue;
}
pa=p;
while ((lim1/p) > pa) pa*=p;
ellipse(x,z,(int)pa,x1,z1,x2,z2);
copy(x1,x);
copy(z1,z);
copy(z,q);
}
else
{ /* phase 2 - looking for last large PRIME FACTOR of (p+1+d) */
p+=2;
pos=(int)(p%MULT);
if (pos>MULT/2)
{ /* increment giant step */
iv++;
interval=(long)iv*MULT;
p=interval+1;
marks(interval);
pos=1;
nres_moddiv(x2,z2,fvw);
nres_modadd(x2,z2,s2);
nres_modsub(x2,z2,d2);
addition(x1,z1,s2,d2,xt,zt,x,z);
copy(x2,x1);
copy(z2,z1);
copy(x,x2);
copy(z,z2);
}
if (!cp[pos]) continue;
/* if neither interval +/- pos is prime, don't bother */
if (!plus[pos] && !minus[pos]) continue;
nres_modsub(fvw,fu[pos],t);
nres_modmult(q,t,q);
}
if (i++%btch==0)
{ /* try for a solution */
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b%8ld",p);
fflush(stdout);
}
egcd(q,n,t);
if (size(t)==1)
{
if (p>lim2)
{
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
fflush(stdout);
}
break;
}
else continue;
}
if (mr_compare(t,n)==0)
{
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
printf("degenerate case\n");
}
break;
}
if (!suppress)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
if (isprime(t)) printf("PRIME FACTOR ");
else printf("COMPOSITE FACTOR ");
}
else if (!isprime(t)) printf("& ");
cotnum(t,output);
divide(n,t,n);
if (isprime(n))
{
if (!suppress) printf("PRIME FACTOR ");
cotnum(n,output);
exit(0);
}
ncr=ncurves+1;
break;
}
}
gprime(0);
mr_free(ww);
mr_free(t);
mr_free(q);
mr_free(x);
mr_free(z);
mr_free(a);
mr_free(x1);
mr_free(z1);
mr_free(x2);
mr_free(z2);
mr_free(s1);
mr_free(d1);
mr_free(s2);
mr_free(d2);
mr_free(ak);
mr_free(xt);
mr_free(zt);
mr_free(fvw);
for (m=1;m<=MULT/2;m+=2)
if (igcd(MULT,m)==1) mr_free(fu[m]);
return ncr;
}
void do_lenstra(int lim1,long lim2,int ncurves)
{
int nc=1;
int kurve=5;
for (nc=1;nc<=ncurves;)
{
kurve++;
nc=lenstra(lim1,lim2,nc,kurve,ncurves);
}
}
#define SSIZE 100000 /* Maximum sieve size */
static big NN,TT,DD,RR,VV,PP,XX,YY,DG,IG,AA,BB;
static big *x,*y,*z,*w;
static unsigned int **EE,**G;
static int *epr,*r1,*r2,*rp,*b,*pr,*e,*hash;
static unsigned char *logp,*sieve;
static int mm,mlf,jj,nbts,nlp,lp,hmod,hmod2;
static BOOL partial;
int knuth(int mm,int *epr,big N,big D)
{ /* Input number to be factored N and find best multiplier k *
* for use over a factor base epr[] of size mm. Set D=k.N. */
double dp,fks,top;
BOOL found;
int i,j,bk,nk,kk,r,p;
static int K[]={0,1,2,3,5,6,7,10,11,13,14,15,17,0};
top=(-10.0e0);
found=FALSE;
nk=0;
bk=0;
epr[0]=1;
epr[1]=2;
do
{ /* search for best Knuth-Schroepel multiplier */
kk=K[++nk];
if (kk==0)
{ /* finished */
kk=K[bk];
found=TRUE;
}
premult(N,kk,D);
fks=log(2.0e0)/(2.0e0);
r=remain(D,8);
if (r==1) fks*=(4.0e0);
if (r==5) fks*=(2.0e0);
fks-=log((double)kk)/(2.0e0);
i=0;
j=1;
while (j<mm)
{ /* select small primes */
p=mip->PRIMES[++i];
r=remain(D,p);
if (spmd(r,(p-1)/2,p)<=1)
{ /* use only if Jacobi symbol = 0 or 1 */
epr[++j]=p;
dp=(double)p;
if (kk%p==0) fks+=log(dp)/dp;
else fks+=2*log(dp)/(dp-1.0e0);
}
}
if (fks>top)
{ /* find biggest fks */
top=fks;
bk=nk;
}
} while (!found);
return kk;
}
BOOL factored(long lptr,big T)
{ /* factor quadratic residue */
BOOL facted;
int i,j,r,st;
partial=FALSE;
facted=FALSE;
for (j=1;j<=mm;j++)
{ /* now attempt complete factorisation of T */
r=(int)(lptr%epr[j]);
if (r<0) r+=epr[j];
if (r!=r1[j] && r!=r2[j]) continue;
while (subdiv(T,epr[j],XX)==0)
{ /* cast out epr[j] */
e[j]++;
copy(XX,T);
}
st=size(T);
if (st==1)
{
facted=TRUE;
break;
}
if (size(XX)<=epr[j])
{ /* st is prime < epr[mm]^2 */
if (st>=MR_TOOBIG || (st/epr[mm])>(1+mlf/50)) break;
if (st<=epr[mm])
for (i=j;i<=mm;i++)
if (st==epr[i])
{
e[i]++;
facted=TRUE;
break;
}
if (facted) break;
lp=st; /* factored with large prime */
partial=TRUE;
facted=TRUE;
break;
}
}
return facted;
}
BOOL gotcha(void)
{ /* use new factorisation */
int r,j,i,k,n,rb,had,hp;
unsigned int t;
BOOL found;
found=TRUE;
if (partial)
{ /* check partial factorisation for usefulness */
had=lp%hmod;
forever
{ /* hash search for matching large prime */
hp=hash[had];
if (hp<0)
{ /* failed to find match */
found=FALSE;
break;
}
if (pr[hp]==lp) break; /* hash hit! */
had=(had+(hmod2-lp%hmod2))%hmod;
}
if (!found && nlp>=mlf) return FALSE;
}
copy(PP,XX);
convert(1,YY);
for (k=1;k<=mm;k++)
{ /* build up square part in YY *
* reducing e[k] to 0s and 1s */
if (e[k]<2) continue;
r=e[k]/2;
e[k]%=2;
expint(epr[k],r,TT);
multiply(TT,YY,YY);
}
/* debug only
cotnum(XX,stdout);
cotnum(YY,stdout);
if (e[0]==1) printf("-1");
else printf("1");
for (k=1;k<=mm;k++)
{
if (e[k]==0) continue;
printf(".%d",epr[k]);
}
if (partial) printf(".%d\n",lp);
else printf("\n");
*/
if (partial)
{ /* factored with large prime */
if (!found)
{ /* store new partial factorization */
hash[had]=nlp;
pr[nlp]=lp;
copy(XX,z[nlp]);
copy(YY,w[nlp]);
for (n=0,rb=0,j=0;j<=mm;j++)
{
G[nlp][n]|=((e[j]&1)<<rb);
if (++rb==nbts) n++,rb=0;
}
nlp++;
}
if (found)
{ /* match found so use as factorization */
if (!suppress)
{
printf("\b\b\b\b\b\b*");
fflush(stdout);
}
mad(XX,z[hp],XX,NN,NN,XX);
mad(YY,w[hp],YY,NN,NN,YY);
for (n=0,rb=0,j=0;j<=mm;j++)
{
t=(G[hp][n]>>rb);
e[j]+=(t&1);
if (e[j]==2)
{
premult(YY,epr[j],YY);
divide(YY,NN,NN);
e[j]=0;
}
if (++rb==nbts) n++,rb=0;
}
premult(YY,lp,YY);
divide(YY,NN,NN);
}
}
else if (!suppress)
{
printf("\b\b\b\b\b\b ");
fflush(stdout);
}
if (found)
{
for (k=mm;k>=0;k--)
{ /* use new factorization in search for solution */
if (e[k]%2==0) continue;
if (b[k]<0)
{ /* no solution this time */
found=FALSE;
break;
}
i=b[k];
mad(XX,x[i],XX,NN,NN,XX); /* This is very inefficient - */
mad(YY,y[i],YY,NN,NN,YY); /* There must be a better way! */
for (n=0,rb=0,j=0;j<=mm;j++)
{ /* Gaussian elimination */
t=(EE[i][n]>>rb);
e[j]+=(t&1);
if (++rb==nbts) n++,rb=0;
}
}
for (j=0;j<=mm;j++)
{ /* update YY */
if (e[j]<2) continue;
convert(epr[j],TT);
power(TT,e[j]/2,NN,TT);
mad(YY,TT,YY,NN,NN,YY);
}
if (!found)
{ /* store details in E, x and y for later */
b[k]=jj;
copy(XX,x[jj]);
copy(YY,y[jj]);
for (n=0,rb=0,j=0;j<=mm;j++)
{
EE[jj][n]|=((e[j]&1)<<rb);
if (++rb==nbts) n++,rb=0;
}
jj++;
if (!suppress) printf("%5d",jj);
}
}
if (found)
{ /* check for false alarm */
if (!suppress) printf("\ntrying...\n");
add(XX,YY,TT);
if (mr_compare(XX,YY)==0 || mr_compare(TT,NN)==0) found=FALSE;
if (!found) if(!suppress) printf("working... %5d",jj);
}
return found;
}
int initv(int d)
{ /* initialize big numbers and arrays */
int i,j,pak,k,maxp;
double dp;
NN=mirvar(0);
TT=mirvar(0);
DD=mirvar(0);
RR=mirvar(0);
VV=mirvar(0);
PP=mirvar(0);
XX=mirvar(0);
YY=mirvar(0);
DG=mirvar(0);
IG=mirvar(0);
AA=mirvar(0);
BB=mirvar(0);
nbts=8*sizeof(int);
copy(n,NN);
/* determine mm - optimal size of factor base */
if (d<8) mm=d;
else mm=25;
if (d>20) mm=(d*d*d*d)/4096;
/* only half the primes (on average) wil be used, so generate twice as
many (+ a bit for luck) */
dp=(double)2*(double)(mm+100); /* number of primes to generate */
maxp=(int)(dp*(log(dp*log(dp)))); /* Rossers upper bound */
gprime(maxp);
epr=(int *)mr_alloc(mm+1,sizeof(int));
k=knuth(mm,epr,NN,DD);
if (nroot(DD,2,RR))
{
if (!suppress)
{
printf("%dN is a perfect square!\n",k);
if (isprime(RR)) printf("PRIME FACTOR ");
else printf("COMPOSITE FACTOR ");
}
else if (!isprime(RR)) printf("& ");
cotnum(RR,output);
divide(NN,RR,NN);
if (!suppress)
{
if (isprime(NN)) printf("PRIME FACTOR ");
else printf("COMPOSITE FACTOR ");
}
else if (!isprime(NN)) printf("& ");
cotnum(NN,output);
return (-1);
}
if(!suppress)
{
printf("using multiplier k= %d and %d small primes as factor base\n",k,mm);
}
gprime(0); /* reclaim PRIMES space */
mlf=2*mm;
/* now get space for arrays */
r1=(int *)mr_alloc((mm+1),sizeof(int));
r2=(int *)mr_alloc((mm+1),sizeof(int));
rp=(int *)mr_alloc((mm+1),sizeof(int));
b=(int *)mr_alloc((mm+1),sizeof(int));
e=(int *)mr_alloc((mm+1),sizeof(int));
logp=(unsigned char *)mr_alloc(mm+1,1);
pr=(int *)mr_alloc((mlf+1),sizeof(int));
hash=(int *)mr_alloc((2*mlf+1),sizeof(int));
sieve=(unsigned char *)mr_alloc(SSIZE+1,1);
x=(big *)mr_alloc(mm+1,sizeof(big *));
y=(big *)mr_alloc(mm+1,sizeof(big *));
z=(big *)mr_alloc(mlf+1,sizeof(big *));
w=(big *)mr_alloc(mlf+1,sizeof(big *));
for (i=0;i<=mm;i++)
{
x[i]=mirvar(0);
y[i]=mirvar(0);
}
for (i=0;i<=mlf;i++)
{
z[i]=mirvar(0);
w[i]=mirvar(0);
}
EE=(unsigned int **)mr_alloc(mm+1,sizeof(int *));
G=(unsigned int **)mr_alloc(mlf+1,sizeof(int *));
pak=1+mm/(MR_IBITS);
for (i=0;i<=mm;i++)
{
b[i]=(-1);
EE[i]=(unsigned int *)mr_alloc(pak,sizeof(int));
}
mip->ERCON=TRUE;
for (i=0;i<=mlf;i++)
{
G[i]=(unsigned int *)mr_alloc(pak,sizeof(int));
if (G[i]==NULL)
{ /* Out of space - try a quick fix */
mlf=mm;
for (j=mm+1;j<i;j++) mr_free(G[j]);
break;
}
}
mip->ERCON=FALSE;
mip->ERNUM=0;
return 1;
}
int qsieve(int d)
{ /* factoring via quadratic sieve */
unsigned int i,j,a,*SV;
unsigned char logpi;
int k,S,r,s1,s2,s,NS,logm,ptr,threshold,epri;
long M,la,lptr;
if (initv(d)<0) exit(0);
hmod=2*mlf+1; /* set up hash table */
convert(hmod,TT);
while (!isprime(TT)) decr(TT,2,TT);
hmod=size(TT);
hmod2=hmod-2;
for (k=0;k<hmod;k++) hash[k]=(-1);
M=50*(long)mm;
NS=(int)(M/SSIZE);
if (M%SSIZE!=0) NS++;
M=SSIZE*(long)NS;
logm=0;
la=M;
while ((la/=2)>0) logm++; /* logm = log(M) */
rp[0]=logp[0]=0;
for (k=1;k<=mm;k++)
{ /* find root mod each prime, and approx log of each prime */
r=subdiv(DD,epr[k],TT);
rp[k]=sqrmp(r,epr[k]);
logp[k]=0;
r=epr[k];
while((r/=2)>0) logp[k]++;
}
r=subdiv(DD,8,TT); /* take special care of 2 */
if (r==5) logp[1]++;
if (r==1) logp[1]+=2;
threshold=logm+logb2(RR)-2*logp[mm];
jj=0;
nlp=0;
premult(DD,2,DG);
nroot(DG,2,DG);
lgconv(M,TT);
divide(DG,TT,DG);
nroot(DG,2,DG);
if (subdiv(DG,2,TT)==0) incr(DG,1,DG);
if (subdiv(DG,4,TT)==1) incr(DG,2,DG);
if (!suppress) printf("working... 0");
forever
{ /* try a new polynomial */
r=mip->NTRY;
mip->NTRY=1; /* speed up search for prime */
do
{ /* looking for suitable prime DG = 3 mod 4 */
do {
incr(DG,4,DG);
} while(!isprime(DG));
decr(DG,1,TT);
subdiv(TT,2,TT);
powmod(DD,TT,DG,TT); /* check D is quad residue */
} while (size(TT)!=1);
mip->NTRY=r;
incr(DG,1,TT);
subdiv(TT,4,TT);
powmod(DD,TT,DG,BB);
negify(DD,TT);
mad(BB,BB,TT,DG,TT,TT);
negify(TT,TT);
premult(BB,2,AA);
xgcd(AA,DG,AA,AA,AA);
mad(AA,TT,TT,DG,DG,AA);
multiply(AA,DG,TT);
add(BB,TT,BB); /* BB^2 = DD mod DG^2 */
multiply(DG,DG,AA); /* AA = DG*DG */
xgcd(DG,DD,IG,IG,IG); /* IG = 1/DG mod DD */
r1[0]=r2[0]=0;
for (k=1;k<=mm;k++)
{ /* find roots of quadratic mod each prime */
s=subdiv(BB,epr[k],TT);
r=subdiv(AA,epr[k],TT);
r=invers(r,epr[k]); /* r = 1/AA mod p */
s1=(epr[k]-s+rp[k]);
s2=(epr[k]-s+epr[k]-rp[k]);
r1[k]=smul(s1,r,epr[k]);
r2[k]=smul(s2,r,epr[k]);
}
for (ptr=(-NS);ptr<NS;ptr++)
{ /* sieve over next period */
la=(long)ptr*SSIZE;
SV=(unsigned int *)sieve;
for (i=0;i<SSIZE/sizeof(int);i++) *SV++=0;
for (k=1;k<=mm;k++)
{ /* sieving with each prime */
epri=epr[k];
logpi=logp[k];
r=(int)(la%epr[k]);
s1=(r1[k]-r)%epri;
if (s1<0) s1+=epri;
s2=(r2[k]-r)%epri;
if (s2<0) s2+=epri;
/* these loops are time-critical */
for (j=s1;j<SSIZE;j+=epri) sieve[j]+=logpi;
if (s1==s2) continue;
for (j=s2;j<SSIZE;j+=epri) sieve[j]+=logpi;
}
for (a=0;a<SSIZE;a++)
{ /* main loop - look for fully factored residues */
if (sieve[a]<threshold) continue;
lptr=la+a;
lgconv(lptr,TT);
S=0;
multiply(AA,TT,TT); /* TT = AAx + BB */
add(TT,BB,TT);
mad(TT,IG,TT,DD,DD,PP); /* PP = (AAx + BB)/G */
if (size(PP)<0) add(PP,DD,PP);
mad(PP,PP,PP,DD,DD,VV); /* VV = PP^2 mod kN */
absol(TT,TT);
if (mr_compare(TT,RR)<0) S=1; /* check for -ve VV */
if (S==1) subtract(DD,VV,VV);
copy(VV,TT);
e[0]=S;
for (k=1;k<=mm;k++) e[k]=0;
if (!factored(lptr,TT)) continue;
if (gotcha())
{ /* factors found! */
egcd(TT,NN,PP);
if (!suppress)
{
if (isprime(PP)) printf("PRIME FACTOR ");
else printf("COMPOSITE FACTOR ");
}
else if (!isprime(PP)) printf("& ");
cotnum(PP,output);
divide(NN,PP,NN);
if (!suppress)
{
if (isprime(NN)) printf("PRIME FACTOR ");
else printf("COMPOSITE FACTOR ");
}
else if (!isprime(NN)) printf("& ");
cotnum(NN,output);
exit(0);
}
}
}
}
}
/* Code to parse formula in command line
This code isn't mine, but its public domain
Shamefully I forget the source
NOTE: It may be necessary on some platforms to change the operators * and #
*/
#if defined(unix)
#define TIMES '.'
#define RAISE '^'
#else
#define TIMES '*'
#define RAISE '#'
#endif
int digits(void)
{ /* size of n */
int d;
t=mirvar(0);
d=0;
copy(n,t);
while (size(t)!=0)
{
subdiv(t,10,t);
d++;
}
mr_free(t);
return d;
}
static char *s;
void eval_power (big oldn,big n,char op)
{
if (op) power(oldn,size(n),n,n);
}
void eval_product (big oldn,big n,char op)
{
switch (op)
{
case TIMES:
multiply(n,oldn,n);
break;
case '/':
copy(oldn,t);
divide(t,n,t);
copy(t,n);
break;
case '%':
copy(oldn,t);
divide(t,n,n);
copy(t,n);
}
}
void eval_sum (big oldn,big n,char op)
{
switch (op)
{
case '+':
add(n,oldn,n);
break;
case '-':
subtract(oldn,n,n);
}
}
void eval (void)
{
big oldn[3];
big n;
int i;
char oldop[3];
char op;
char minus;
n=mirvar(0);
for (i=0;i<3;i++)
{
oldop[i]=0;
oldn[i]=mirvar(0);
}
LOOP:
while (*s==' ')
s++;
if (*s=='-') /* Unary minus */
{
s++;
minus=1;
}
else
minus=0;
while (*s==' ')
s++;
if (*s=='(' || *s=='[' || *s=='{') /* Number is subexpression */
{
s++;
eval ();
copy(t,n);
}
else /* Number is decimal value */
{
for (i=0;s[i]>='0' && s[i]<='9';i++)
;
if (!i) /* No digits found */
{
printf ("Error - invalid number\n");
exit (20);
}
op=s[i];
s[i]=0;
lgconv(atol(s),n);
s+=i;
*s=op;
}
if (minus) negify(n,n);
do
op=*s++;
while (op==' ');
if (op==0 || op==')' || op==']' || op=='}')
{
eval_power (oldn[2],n,oldop[2]);
eval_product (oldn[1],n,oldop[1]);
eval_sum (oldn[0],n,oldop[0]);
copy(n,t);
mr_free(n);
for (i=0;i<2;i++) mr_free(oldn[i]);
return;
}
else
{
if (op==RAISE)
{
eval_power (oldn[2],n,oldop[2]);
copy(n,oldn[2]);
oldop[2]=RAISE;
}
else
{
if (op==TIMES || op=='/' || op=='%')
{
eval_power (oldn[2],n,oldop[2]);
oldop[2]=0;
eval_product (oldn[1],n,oldop[1]);
copy(n,oldn[1]);
oldop[1]=op;
}
else
{
if (op=='+' || op=='-')
{
eval_power (oldn[2],n,oldop[2]);
oldop[2]=0;
eval_product (oldn[1],n,oldop[1]);
oldop[1]=0;
eval_sum (oldn[0],n,oldop[0]);
copy(n,oldn[0]);
oldop[0]=op;
}
else /* Error - invalid operator */
{
printf ("Error - invalid operator\n");
exit (20);
}
}
}
}
goto LOOP;
}
int main(int argc,char **argv)
{
FILE *ifile;
int ip,b,d=250;
argv++;argc--;
if (argc<1)
{
printf("Incorrect Usage\n");
printf("factor <number>\n");
printf("OR\n");
printf("factor -f <formula>\n");
printf("e.g. factor 999999999999999999999999999999999999999999999999999997\n");
#if defined(unix)
printf("or factor -f 10^100-19\n\n");
#else
printf("or factor -f 10#100-19\n\n");
#endif
printf("To suppress the commentary, use flag -s\n");
printf("To input from a file, use flag -i <filename>\n");
printf("To output to a file, use flag -o <filename>\n");
printf("To set max. number size, set -dn, where n is number of decimal digits\n");
printf("(Default is -d150). Must be first flag and before number.\n");
#if defined(unix)
printf("e.g. factor -d200 -f 10^200-1 -s -o factors.dat\n\n");
#else
printf("e.g. factor -d200 -f 10#200-1 -s -o factors.dat\n\n");
#endif
printf("Freeware from Certivox, Dublin, Ireland\n");
printf("Full C source code and MIRACL multiprecision library available\n");
printf("Email to mscott@indigo.ie for details\n");
return 0;
}
b=(d*45)/100;
#ifndef MR_NOFULLWIDTH
mip=mirsys(-b,0);
#else
mip=mirsys(-b,MAXBASE);
#endif
mip->NTRY=100;
n=mirvar(0);
ip=0;
output=stdout;
while (ip<argc)
{
if (strncmp(argv[ip],"-d",2)==0)
{
d=atoi(argv[ip++]+2);
mr_free(n);
mirexit();
if (d<20) d=20;
b=(d*45)/100;
#ifndef MR_NOFULLWIDTH
mip=mirsys(-b,0);
#else
mip=mirsys(-b,MAXBASE);
#endif
mip->NTRY=100;
n=mirvar(0);
continue;
}
if (strcmp(argv[ip],"-f")==0)
{
ip++;
s=argv[ip++];
t=mirvar(0);
eval();
copy(t,n);
mr_free(t);
cotnum(n,stdout);
continue;
}
if (strcmp(argv[ip],"-s")==0)
{
ip++;
suppress=TRUE;
continue;
}
if (strcmp(argv[ip],"-i")==0)
{
ip++;
ifile=fopen(argv[ip++],"rt");
if (ifile==NULL) break;
cinnum(n,ifile);
cotnum(n,stdout);
continue;
}
if (strcmp(argv[ip],"-o")==0)
{
ip++;
output=fopen(argv[ip++],"wt");
continue;
}
cinstr(n,argv[ip++]);
}
if (size(n)==0)
{
printf("No number to factor!\n");
return 0;
}
if (size(n)<0)
{
printf("Positive numbers only!\n");
return 0;
}
if (isprime(n))
{
cotnum(n,output);
printf("this number is prime!\n");
return 0;
}
if (!suppress) printf("first trying brute force division by small primes\n");
brute();
if (!suppress) printf("now trying %d iterations of brent's method\n",BTRIES);
brent();
fu= (big *)mr_alloc((1+MULT/2),sizeof(big));
cp=(BOOL *)mr_alloc((1+MULT/2),sizeof(BOOL));
plus=(BOOL *)mr_alloc((1+MULT/2),sizeof(BOOL));
minus=(BOOL *)mr_alloc((1+MULT/2),sizeof(BOOL));
if (digits()>25)
{
if (!suppress) printf("now trying william's (p+1) method\n");
williams(10000,1000000L,1);
if (!suppress) printf("now trying pollard's (p-1) method\n");
pollard(100000,5000000L);
}
if (digits()>35)
{
if (!suppress) printf("now trying lenstra's method using 10 curves\n");
do_lenstra(20000,2000000L,10);
if (digits()>64)
{
if (!suppress) printf("now trying 80 more curves\n");
do_lenstra(20000,2000000L,80);
}
if (digits()>72)
{
if (!suppress) printf("trying 300 last curves\n");
do_lenstra(50000,5000000,300);
}
}
mr_free(minus);
mr_free(plus);
mr_free(cp);
mr_free(fu);
if (digits()<110)
{
if (!suppress) printf("finally - the multiple polynomial quadratic sieve - with large prime (*)\n");
qsieve(digits());
}
if (!suppress) printf("I give up \nCOMPOSITE FACTOR ");
else printf("& ");
cotnum(n,output);
return 0;
}