factor.c   [plain text]


/**************************************************************
 *
 *	factor.c
 *
 *	General purpose factoring program
 *
 *	Updates:
 *		18 May 97   REC - invoked new, fast divide functions
 *		26 Apr 97	RDW - fixed tabs and unix EOL
 *		20 Apr 97	RDW - conversion to TC4.5
 *
 *	c. 1997 Perfectly Scientific, Inc.
 *	All Rights Reserved.
 *
 *
 *************************************************************/

/* include files */

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#ifdef _WIN32 

#include <process.h>

#endif

#include <string.h>
#include "giants.h"


/* definitions */

#define D 100
#define NUM_PRIMES 6542 /* PrimePi[2^16]. */


/* compiler options */

#ifdef _WIN32
#pragma warning( disable : 4127 4706 ) /* disable conditional is constant warning */
#endif


/* global variables */

extern giant 	scratch2;
int 			pr[NUM_PRIMES];
giant 			xr = NULL, xs = NULL, zs = NULL, zr = NULL, xorg = NULL,
				zorg = NULL, t1 = NULL, t2 = NULL, t3 = NULL, N = NULL,
				gg = NULL, An = NULL, Ad = NULL;
giant 			xb[D+2], zb[D+2], xzb[D+2];
int 			modmode = 0, Q, modcount = 0;


/* function prototypes */

void		ell_even(giant x1, giant z1, giant x2, giant z2, giant An,
						giant Ad, giant N);
void		ell_odd(giant x1, giant z1, giant x2, giant z2, giant xor,
						giant zor, giant N);
void		ell_mul(giant xx, giant zz, int n, giant An, giant Ad, giant N);
int 		least_2(int n);
void		dot(void);
int			psi_rand();


/**************************************************************
 *
 *	Functions
 *
 **************************************************************/


int			
psi_rand(
	void
)
{
	unsigned short	hi;
	unsigned short	low;
	time_t			tp;
	int				result;

	time(&tp);
	low = (unsigned short)rand();
	hi = (unsigned short)rand();
	result = ((hi << 16) | low) ^ ((int)tp);

	return (result & 0x7fffffff);
}


void
set_random_seed(
	void
)
{
	/* Start the random number generator at a new position. */
	time_t		tp;

	time(&tp);
	srand((int)tp + (int)getpid());
}


int
isprime(
	int 	odd
)
{
	int 	j;
	int 	p;

	for (j=1; ; j++)
	{
		p = pr[j];
		if (p*p > odd)
			return(1);
		if (odd % p == 0)
			return(0);
	}
}


int
primeq(
	int				p
)
{
	register int	j=3;

	if ((p&1)==0)
		return ((p==2)?1:0);
	if (j>=p)
		return (1);
	while ((p%j)!=0)
	{
		j+=2;
		if (j*j>p)
			return(1);
	}
	return(0);
}


void
s_modg(
	giant		N,
	giant		t
)
{
	++modcount;
	switch (modmode)
	{
		case 0:
			modg(N, t);
			break;
		case -1:
			mersennemod(Q, t);
			break;
		case 1:
			fermatmod(Q, t);
			break;
	}
}


void
reset_mod(
	giant 	x,
	giant 	N
)
/* Perform a divide (by the discovered factor) and switch back
   to non-Fermat-non-Mersenne (i.e. normal) mod mode. */
{
	divg(x, N);
	modmode = 0;
}

void
ell_even(
	giant 	x1,
	giant 	z1,
	giant 	x2,
	giant 	z2,
	giant 	An,
	giant 	Ad,
	giant 	N
)
{
	gtog(x1, t1);
	addg(z1, t1);
	squareg(t1);
	s_modg(N, t1);
	gtog(x1, t2);
	subg(z1, t2);
	squareg(t2);
	s_modg(N, t2);
	gtog(t1, t3);
	subg(t2, t3);
	gtog(t2, x2);
	mulg(t1, x2);
	gshiftleft(2, x2);
	s_modg(N, x2);
	mulg(Ad, x2);
	s_modg(N, x2);
	mulg(Ad, t2);
	gshiftleft(2, t2);
	s_modg(N, t2);
	gtog(t3, t1);
	mulg(An, t1);
	s_modg(N, t1);
	addg(t1, t2);
	mulg(t3, t2);
	s_modg(N, t2);
	gtog(t2,z2);
}


void
ell_odd(
	giant 	x1,
	giant 	z1,
	giant 	x2,
	giant 	z2,
	giant 	xor,
	giant 	zor,
	giant 	N
)
{
	gtog(x1, t1);
	subg(z1, t1);
	gtog(x2, t2);
	addg(z2, t2);
	mulg(t1, t2);
	s_modg(N, t2);
	gtog(x1, t1);
	addg(z1, t1);
	gtog(x2, t3);
	subg(z2, t3);
	mulg(t3, t1);
	s_modg(N, t1);
	gtog(t2, x2);
	addg(t1, x2);
	squareg(x2);
	s_modg(N, x2);
	gtog(t2, z2);
	subg(t1, z2);
	squareg(z2);
	s_modg(N, z2);
	mulg(zor, x2);
	s_modg(N, x2);
	mulg(xor, z2);
	s_modg(N, z2);
}


void
ell_mul(
	giant 			xx,
	giant 			zz,
	int 			n,
	giant 			An,
	giant 			Ad,
	giant 			N
)
{
	unsigned int 	c = (unsigned int)0x80000000;

	if (n==1)
		return;
	if (n==2)
	{
		ell_even(xx, zz, xx, zz, An, Ad, N);
		return;
	}
	gtog(xx, xorg);
	gtog(zz, zorg);
	ell_even(xx, zz, xs, zs, An, Ad, N);

	while((c&n) == 0)
	{
		c >>= 1;
	}

	c>>=1;
	do
	{
		if (c&n)
		{
			ell_odd(xs, zs, xx, zz, xorg, zorg, N);
			ell_even(xs, zs, xs, zs, An, Ad, N);
		}
		else
		{
			ell_odd(xx, zz, xs, zs, xorg, zorg, N);
			ell_even(xx, zz, xx, zz, An, Ad, N);
		}
		c >>= 1;
	} while(c);
}



/* From R. P. Brent, priv. comm. 1996:
Let s > 5 be a pseudo-random seed (called $\sigma$ in the Tech. Report),

	u/v = (s^2 - 5)/(4s)

Then starting point is (x_1, y_1) where

	x_1 = (u/v)^3
and
	a = (v-u)^3(3u+v)/(4u^3 v) - 2
*/

void
choose12(
	giant 	x,
	giant 	z,
	int 	k,
	giant 	An,
	giant 	Ad,
	giant 	N
)
{
	itog(k, zs);
	gtog(zs, xs);
	squareg(xs);
	itog(5, t2);
	subg(t2, xs);
	s_modg(N, xs);
	addg(zs, zs);
	addg(zs, zs);
	s_modg(N, zs);
	gtog(xs, x);
	squareg(x);
	s_modg(N, x);
	mulg(xs, x);
	s_modg(N, x);
	gtog(zs, z);
	squareg(z);
	s_modg(N, z);
	mulg(zs, z);
	s_modg(N, z);

	/* Now for A. */
	gtog(zs, t2);
	subg(xs, t2);
	gtog(t2, t3);
	squareg(t2);
	s_modg(N, t2);
	mulg(t3, t2);
	s_modg(N, t2);  /* (v-u)^3. */
	gtog(xs, t3);
	addg(t3, t3);
	addg(xs, t3);
	addg(zs, t3);
	s_modg(N, t3);
	mulg(t3, t2);
	s_modg(N, t2);  /* (v-u)^3 (3u+v). */
	gtog(zs, t3);
	mulg(xs, t3);
	s_modg(N, t3);
	squareg(xs);
	s_modg(N, xs);
	mulg(xs, t3);
	s_modg(N, t3);
	addg(t3, t3);
	addg(t3, t3);
	s_modg(N, t3);
	gtog(t3, Ad);
	gtog(t2, An);  /* An/Ad is now A + 2. */
}


void
ensure(
	int	q
)
{
	int 	nsh, j;

	N = newgiant(INFINITY);
	if(!q)
	{
		gread(N,stdin);
		q = bitlen(N) + 1;
	}
	nsh = q/4; /* Allowing (easily) enough space per giant,
					since N is about 2^q, which is q bits, or
				   q/16 shorts.  But squaring, etc. is allowed,
					so we need at least q/8, and we choose q/4
					to be conservative. */
	if (!xr)
		xr = newgiant(nsh);
	if (!zr)
		zr = newgiant(nsh);
	if (!xs)
		xs = newgiant(nsh);
	if (!zs)
		zs = newgiant(nsh);
	if (!xorg)
		xorg = newgiant(nsh);
	if (!zorg)
		zorg = newgiant(nsh);
	if (!t1)
		t1 = newgiant(nsh);
	if (!t2)
		t2 = newgiant(nsh);
	if (!t3)
		t3 = newgiant(nsh);
	if (!gg)
		gg = newgiant(nsh);
	if (!An)
		An = newgiant(nsh);
	if (!Ad)
		Ad = newgiant(nsh);
	for (j=0;j<D+2;j++)
	{
		xb[j] = newgiant(nsh);
		zb[j] = newgiant(nsh);
		xzb[j] = newgiant(nsh);
	}
}

int
bigprimeq(
	giant 	x
)
{
	itog(1, t1);
	gtog(x, t2);
	subg(t1, t2);
	itog(5, t1);
	powermodg(t1, t2, x);
	if (isone(t1))
		return(1);
	return(0);
}


void
dot(
	void
)
{
	printf(".");
	fflush(stdout);
}

/**************************************************************
 *
 *	Main Function
 *
 **************************************************************/

main(
	int	argc,
	char 	*argv[]
)
{
	int 	j, k, C, nshorts, cnt, count,
			limitbits = 0, pass, npr, rem;
	long	B;
	int 	randmode = 0;

	if (!strcmp(argv[argc-1], "-r"))
	{
		randmode = 1;
		if (argc > 4)
		  /* This segment only takes effect in random mode. */
			limitbits = atoi(argv[argc-2]);
	}
	else
	{
		randmode = 0;
	}

	modmode = 0;
	if (argc > 2)
	{
		modmode = atoi(argv[1]);
		Q = atoi(argv[2]);
	}
	if (modmode==0)
		Q = 0;
	ensure(Q);
	if (modmode)
	{
		itog(1, N);
		gshiftleft(Q, N);
		itog(modmode, t1);
		addg(t1, N);
	}
	pr[0] = 2;
	for (k=0, npr=1;; k++)
	{
		if (primeq(3+2*k))
		{
			pr[npr++] = 3+2*k;
			if (npr >= NUM_PRIMES)
				break;
		}
	}

	if (randmode == 0)
	{
		printf("Sieving...\n");
		fflush(stdout);
		for (j=0; j < NUM_PRIMES; j++)
		{
			gtog(N, t1);
			rem = idivg(pr[j], t1);
			if (rem == 0)
			{
				printf("%d ", pr[j]);
				gtog(t1, N);
				if (isone(N))
				{
					printf("\n");
					exit(0);
				}
				else
				{
					printf("* ");
					fflush(stdout);
				}
				--j;
			}
		}

		if (bigprimeq(N))
		{
			gout(N);
			exit(0);
		}

		printf("\n");
		printf("Commencing Pollard rho...\n");
		fflush(stdout);
		itog(1, gg);
		itog(3, t1); itog(3, t2);

		for (j=0; j < 15000; j++)
		{
			if((j%100) == 0)
			{
				dot();
				gcdg(N, gg);
				if (!isone(gg))
					break;
			}
			squareg(t1);
			iaddg(2, t1);
			s_modg(N, t1);
			squareg(t2);
			iaddg(2, t2);
			s_modg(N, t2);
			squareg(t2);
			iaddg(2, t2);
			s_modg(N, t2);
			gtog(t2, t3);
			subg(t1, t3);
			t3->sign = abs(t3->sign);
			mulg(t3, gg);
			s_modg(N, gg);
		}
		gcdg(N, gg);

		if ((gcompg(N,gg) != 0) && (!isone(gg)))
		{
			fprintf(stdout,"\n");
			gout(gg);
			reset_mod(gg, N);
			if (isone(N))
			{
				printf("\n");
				exit(0);
			}
			else
			{
				printf("* ");
				fflush(stdout);
			}
			if (bigprimeq(N))
			{
				gout(N);
				exit(0);
			}
		}

		printf("\n");
		printf("Commencing Pollard (p-1)...\n");
		fflush(stdout);
		itog(1, gg);
		itog(3, t1);
		for (j=0; j< NUM_PRIMES; j++)
		{
			cnt = (int)(8*log(2.0)/log(1.0*pr[j]));
			if (cnt < 2)
				cnt = 1;
			for (k=0; k< cnt; k++)
			{
				powermod(t1, pr[j], N);
			}
			itog(1, t2);
			subg(t1, t2);
			mulg(t2, gg);
			s_modg(N, gg);

			if (j % 100 == 0)
			{
				dot();
				gcdg(N, gg);
				if	(!isone(gg))
					break;
			}
		}
		gcdg(N, gg);
		if ((gcompg(N,gg) != 0) && (!isone(gg)))
		{
			fprintf(stdout,"\n");
			gout(gg);
			reset_mod(gg, N);
			if (isone(N))
			{
				printf("\n");
				exit(0);
			}
			else
			{
				printf("* ");
				fflush(stdout);
			}
			if (bigprimeq(N))
			{
				gout(N);
				exit(0);
			}
		}
	} /* This is the end of (randmode == 0) */

	printf("\n");
	printf("Commencing ECM...\n");
	fflush(stdout);

	if (randmode)
		set_random_seed();
	pass = 0;
	while (++pass)
	{
		if (randmode == 0)
		{
			if (pass <= 3)
			{
				B = 1000;
			}
			else if (pass <= 10)
			{
				B = 10000;
			}
			else if (pass <= 100)
			{
				B = 100000L;
			} else
			{
				B = 1000000L;
			}
		}
		else
		{
			B = 2000000L;
		}
		C = 50*((int)B);

		/* Next, choose curve with order divisible by 16 and choose
		 *	a point (xr/zr) on said curve.
		 */

		/* Order-div-12 case. 
		 * cnt = 8020345;   Brent's parameter for stage one discovery
		 * of 27-digit factor of F_13.
		 */

		cnt = psi_rand(); /* cnt = 8020345; */
		choose12(xr, zr, cnt, An, Ad, N);
		printf("Choosing curve %d, with s = %d, B = %d, C = %d:\n", pass,cnt, B, C);   fflush(stdout);
		cnt = 0;
		nshorts = 1;
		count = 0;
		for (j=0;j<nshorts;j++)
		{
			ell_mul(xr, zr, 1<<16, An, Ad, N);
			ell_mul(xr, zr, 3*3*3*3*3*3*3*3*3*3*3, An, Ad, N);
			ell_mul(xr, zr, 5*5*5*5*5*5*5, An, Ad, N);
			ell_mul(xr, zr, 7*7*7*7*7*7, An, Ad, N);
			ell_mul(xr, zr, 11*11*11*11, An, Ad, N);
			ell_mul(xr, zr, 13*13*13*13, An, Ad, N);
			ell_mul(xr, zr, 17*17*17, An, Ad, N);
		}
		k = 19;
		while (k<B)
		{
			if (isprime(k))
			{
				ell_mul(xr, zr, k, An, Ad, N);
				if (k<100)
					ell_mul(xr, zr, k, An, Ad, N);
				if (cnt++ %100==0)
					dot();
			}
			k += 2;
		}
		count = 0;

		gtog(zr, gg);
		gcdg(N, gg);
		if ((!isone(gg))&&(bitlen(gg)>limitbits))
		{
			fprintf(stdout,"\n");
			gwriteln(gg, stdout);
			fflush(stdout);
			reset_mod(gg, N);
			if (isone(N))
			{
				printf("\n");
				exit(0);
			}
			else
			{
				printf("* ");
				fflush(stdout);
			}
			if (bigprimeq(N))
			{
				 gout(N);
				 exit(0);
			}
			continue;
		}
		else
		{
			printf("\n");
			fflush(stdout);
		}

		/* Continue;  Invoke, to test Stage 1 only. */
		k = ((int)B)/D;
		gtog(xr, xb[0]);
		gtog(zr, zb[0]);
		ell_mul(xb[0], zb[0], k*D+1 , An, Ad, N);
		gtog(xr, xb[D+1]);
		gtog(zr, zb[D+1]);
		ell_mul(xb[D+1], zb[D+1], (k+2)*D+1 , An, Ad, N);

		for (j=1; j <= D; j++)
		{
			gtog(xr, xb[j]);
			gtog(zr, zb[j]);
			ell_mul(xb[j], zb[j], 2*j , An, Ad, N);
			gtog(zb[j], xzb[j]);
			mulg(xb[j], xzb[j]);
			s_modg(N, xzb[j]);
		}
		modcount = 0;
		printf("\nCommencing second stage, curve %d...\n",pass); fflush(stdout);
		count = 0;
		itog(1, gg);

		while (1)
		{
			gtog(zb[0], xzb[0]);
			mulg(xb[0], xzb[0]);
			s_modg(N, xzb[0]);
			mulg(zb[0], gg);
			s_modg(N,gg); /* Accumulate. */
			for (j = 1; j < D; j++)
			{
				if (!isprime(k*D+1+ 2*j))
					continue;

				/* Next, accumulate (xa - xb)(za + zb) - xa za + xb zb. */
				gtog(xb[0], t1);
				subg(xb[j], t1);
				gtog(zb[0], t2);
				addg(zb[j], t2);
				mulg(t1, t2);
				s_modg(N, t1);
				subg(xzb[0], t2);
				addg(xzb[j], t2);
				s_modg(N, t2);
				--modcount;
				mulg(t2, gg);
				s_modg(N, gg);
				if((++count)%1000==0)
					dot();
			}

			k += 2;
			if(k*D > C)
				break;
			gtog(xb[D+1], xs);
			gtog(zb[D+1], zs);
			ell_odd(xb[D], zb[D], xb[D+1], zb[D+1], xb[0], zb[0], N);
			gtog(xs, xb[0]);
			gtog(zs, zb[0]);
		}

		gcdg(N, gg);
		if((!isone(gg))&&(bitlen(gg)>limitbits))
		{
			fprintf(stdout,"\n");
			gwriteln(gg, stdout);
			fflush(stdout);
			reset_mod(gg, N);
			if (isone(N))
			{
				printf("\n");
				exit(0);
			}
			else
			{
				printf("* ");
				fflush(stdout);
			}
			if (bigprimeq(N))
			{
				gout(N);
				exit(0);
			}
			continue;
		}

		printf("\n");
		fflush(stdout);
	}

	return 0;
}