www.pudn.com > calc.rar > mpqsieve.c


/* mpqsieve.c */ 
/* 
 * Multiple Quadratic sieve method of factoring. 
 * Based on "The multiple polynomial quadratic sieve ", by R.D. Silverman, 
 * Mathematics of Computation, 48, 1987, 329-339. 
 */ 
 
#include  
#include  
#include "integer.h" 
#include "fun.h" 
 
MPI *MPQS1(MPI *N) 
/* 
 * The packed array version of MPQS(), done with a lot of help from Peter Adams. 
 */ 
{ 
	register unsigned int z; 
	unsigned int gap, h, i, j, t; 
	unsigned long a, a1, b, b1, l1, l2, r, e, k; 
	unsigned int TEST_ROWS; 
	unsigned int factored = 0, flag, found = 0; 
	unsigned int FBASE, TOLERANCE; 
	unsigned int CNUF; 
	unsigned long SRANGE, SSRANGE; 
	unsigned int *logn, *logQ; 
	unsigned long *r1, *r2, *soln, **M1, **M2, n; 
	unsigned int *exponents, *CTR; 
	MPI *N0, *X1, *X2, *X3, *X4, *D, *H0, *H1, *H2, *HH, *SAVE1, *Y; 
	MPI *B, *A, *Q, *Tmp, **H, **cofactor, *ROOT2N, *OVER2, *ROOTN; 
	MPI *P1, *P2, *T, *G, *srange, *xx, *hh; 
	int *INDEX, s; 
	long x, y, L, L1, L2, *base; 
	unsigned int m1cols, m2cols, m1bitcols, m2bitcols, index, ctr; 
 
	G = NULL; 
	n = LENGTHI(N); 
	printf("N = ");PRINTI(N);printf(" has %lu digits\n", n); 
	/* FBASE = no of odd primes in factor base.  */ 
	if (n <= 20) 
	{ 
		FBASE = 150; SRANGE = 5000; TOLERANCE = 10; 
	} 
	else if (n > 20 && n <= 25) 
	{ 
		FBASE = 150; SRANGE = 10000; TOLERANCE = 15; 
	} 
	else if (n > 25 && n <= 30) 
	{ 
		FBASE = 250; SRANGE = 15000; TOLERANCE = 20; 
	} 
	else if (n > 30 && n <= 35) 
	{ 
		FBASE = 400; SRANGE = 15000; TOLERANCE = 20; 
	} 
	else if (n > 35 && n <= 40) 
	{ 
		FBASE = 500; SRANGE = 25000; TOLERANCE = 20; 
	} 
	else if (n > 40 && n <= 45) 
	{ 
		FBASE = 900; SRANGE = 50000; TOLERANCE = 20; 
	} 
	else if (n > 45 && n <= 50) 
	{ 
		FBASE = 1200; SRANGE = 100000; TOLERANCE = 22; 
	} 
	else /* n > 50 */ 
	{ 
		if (n > 61) 
		{ 
			printf("Number of digits > 60.\n"); 
			return(NULL); 
		} 
		FBASE = 3000; SRANGE = 180000; TOLERANCE = 22; 
	} 
	printf("FBASE = %u:", FBASE); 
	printf(" sieve_range = %lu:", SRANGE); 
	printf(" tolerance  = %u:\n", TOLERANCE); 
	ROOTN = BIG_MTHROOT(N, 2); 
	TEST_ROWS = FBASE + 2; 
	INDEX = (int *)mmalloc((USL)((TEST_ROWS) * sizeof(int))); 
	INTSETI(INDEX, (USL)TEST_ROWS, -1); 
	CTR = (unsigned int *)ccalloc(TEST_ROWS, sizeof(unsigned int)); 
	m1cols = (FBASE + 2); 
	m1bitcols = m1cols/O32 + 1; 
	M1 = idim2(TEST_ROWS, m1bitcols); 
	H = (MPI **)mmalloc((USL)((TEST_ROWS) * sizeof(MPI *))); 
	cofactor = (MPI **)mmalloc((USL)((TEST_ROWS) * sizeof(MPI *))); 
	base = (long *)mmalloc((USL)((FBASE + 2) * sizeof(long))); 
	base[0] = 2; base[FBASE + 1] = -1; 
	soln = (unsigned long *)mmalloc((USL)((FBASE + 1) * sizeof(unsigned long))); 
 	/* soln[i] is a solution of x*x=n (mod base[i], 1 <= i <= FBASE. */ 
	QERATOSTHENES(N, (USL *)base, soln, FBASE); 
	CNUF = BINARYB(N) / 2 + binary(SRANGE)- (TOLERANCE * binary((USL)(base[FBASE])) / 10); 
	r1 = (unsigned long *)mmalloc((USL)((FBASE + 1) * sizeof(unsigned long))); 
	r2 = (unsigned long *)mmalloc((USL)((FBASE + 1) * sizeof(unsigned long))); 
	/* we will sieve over -SRANGE <= x <= SRANGE. */ 
	X1 = MULT_I(N, 2L); 
	ROOT2N = BIG_MTHROOT(X1, 2); 
	FREEMPI(X1); 
	SSRANGE = (USL)2 * SRANGE; 
	logQ = (unsigned int *)mmalloc((USL)(((unsigned int)SSRANGE + 1) * sizeof(unsigned int))); 
	logn = (unsigned int *)mmalloc((USL)((FBASE + 1) * sizeof(unsigned int))); 
 	/* Table lookup: logn[i] = binary((USL)(base[i])), 1 <= i <= FBASE. */ 
	k = N->V[0]; 
	if (k % 8 == 1) 
		logn[0] = 3; 
	if (k % 8 == 5) 
		logn[0] = 2; 
	if (k % 4 == 3) 
		logn[0] = 1; 
	for (i = 1; i <= FBASE; i++) 
		logn[i] = binary((USL)(base[i])); 
	h = 0; 
	srange = CHANGE(SRANGE); 
	X3 = INT0(ROOT2N, srange); /* bug site */ 
	FREEMPI(srange); 
	OVER2 = BIG_MTHROOT(X3, 2); 
	FREEMPI(X3); 
 
	/* calculating the polynomial Q(x) = A*x*x + 2*B*x + C */ 
	Tmp = CHANGE((USL)(base[FBASE])); 
	if (RSV(OVER2, Tmp) <= 0) 
	{ 
		T = OVER2; 
		OVER2 = ADD0_I(Tmp, (USL)1); 
		FREEMPI(T); 
	} 
	FREEMPI(Tmp); 
	while (factored < TEST_ROWS) 
	{ 
	printf("changing polynomial\n"); 
	if (h) 
	{ 
		Tmp = OVER2; 
		hh = CHANGE(h); 
		OVER2 = ADD0I(OVER2, hh); /* bugsite */ 
		FREEMPI(hh); 
		FREEMPI(Tmp); 
	} 
	D = PINCH_PRIME(OVER2, N, base, FBASE, &gap); 
/* 
	D = PROB_PRIME(OVER2, N, &gap); 
*/ 
	h += gap + 2; 
	X1 = INT0_(D, (USL)4); 
	N0 = MOD0(N, D); 
	H0 = MPOWER(N0, X1, D); 
	FREEMPI(X1); 
	H1 = MULTM(N0, H0, D); 
	FREEMPI(N0); 
	A = MULTI(D, D); 
	X1 = ADD0_I(D, (USL)1); 
	X2 = INT0_(X1, (USL)2); 
	FREEMPI(X1); 
	Y = MULTM(X2, H0, D); 
	FREEMPI(H0); 
	FREEMPI(X2); 
	X1 = MULTI(H1, H1); 
	X2 = SUBI(N, X1); 
	FREEMPI(X1); 
	X3 = INT(X2, D); 
	FREEMPI(X2); 
	Tmp = MOD(X3, D); 
	FREEMPI(X3); 
	H2 = MULTM(Y, Tmp, D); 
	FREEMPI(Y); 
	FREEMPI(Tmp); 
	X4 = MULTI(H2, D); 
	FREEMPI(H2); 
	B = ADD0I(H1, X4); 
	FREEMPI(H1); 
	FREEMPI(X4); 
	SAVE1 = INVERSEM(D, N); /* 1/(D) (mod N) */ 
/* 
	printf("A = "); 
	PRINTI(A); 
	X1 = MULTI(B, B); 
	printf(", B = "); 
	PRINTI(B); 
	X2 = SUBI(X1, N); 
	C = INT(X2, A); 
	X3 = MOD(X2, A); 
	FREEMPI(X1); 
	FREEMPI(X2); 
	FREEMPI(X3); 
	printf(", C = "); 
	PRINTI(C); 
	printf("\n"); 
*/ 
/* C is freed later */ 
/* 
printf("calculating the two roots r1[i], r2[i] (mod base[i]) of Q(x)= 0\n"); 
*/ 
	r = (B->V[0]) % (USL)2 ? (USL)0 : (USL)1; 
	for (i = 1; i <= FBASE; i++) 
	{ 
/* 
printf("mod base[%u], A, B, C = :%lu, %lu, %lu\n",i, MOD_(A,(USL)(base[i])), MOD_(B,(USL)(base[i])), MOD_(C,(USL)(base[i]))); 
*/ 
		b = MOD0_(B, (USL)(base[i])); 
		b1 = MINUSm(b, (USL)(base[i])); 
		a = MOD0_(A, (USL)(base[i])); 
		a1 = INVERSEm(a, (USL)(base[i])); 
	r1[i] = MULTm(ADDm(b1, soln[i], (USL)(base[i])), a1, (USL)(base[i])); 
		r2[i] = MULTm(ADDm(b1, MINUSm(soln[i], (USL)(base[i])), (USL)(base[i])), a1, (USL)(base[i])); 
/* 
		printf("a=%lu,a1 = %lu, b1 = %lu\n",a, a1, b1); 
		printf("soln[%u] = %lu\n", i, soln[i]); 
		printf("r1[%u] = %lu, r2[%u] = %lu ",i, r1[i], i,r2[i]); 
		printf("base[%u] = %lu\n", i, base[i]); 
*/ 
	} 
/* 
printf("finished calculating the two roots r1, r2 (mod base[i]) of Q(x)= 0\n"); 
*/ 
 
	/* sieving over the range -SRANGE <= x <= SRANGE */ 
	INTSETUI(logQ, (USL)SSRANGE + 1, 0); 
	L = SRANGE % (USL)2 == r ? -SRANGE : -SRANGE + 1; 
	for (y = L + SRANGE; y <= SSRANGE; y += 2) 
		logQ[y] += logn[0]; 
	for (i = 1; i <= FBASE; i++) 
	{ 
		l1 = (SRANGE + r1[i]) / (USL)(base[i]); 
		l2 = (SRANGE + r2[i]) / (USL)(base[i]); 
		L1 = r1[i] -(long)(l1 * (USL)(base[i])); 
		L2 = r2[i] - (long)(l2 * (USL)(base[i])); 
/* 
printf("base=%ld,r1=%lu,r2=%lu,l1=%lu,l2=%lu,L1=%ld,L2=%ld\n",base[i],r1[i],r2[i],l1,l2,L1,L2); 
*/ 
		for (y = L1 + SRANGE; y <= SSRANGE; y += base[i]) 
			logQ[y] += logn[i]; 
		for (y = L2 + SRANGE; y <= SSRANGE; y += base[i]) 
			logQ[y] += logn[i]; 
	} 
/* Scanning the values logQ[x] to see if any exceed CNUF */ 
	for (y = 0; y <=  SSRANGE; y++) 
	{ 
		if (logQ[y] >= CNUF) 
		{ 
			x = y - SRANGE; 
			xx = CHANGEL(x);/* bugsite */ 
			X1 = MULTI(A, xx); 
			FREEMPI(xx); 
			X2 = ADDI(X1, B); 
			X3 = MOD(X2, N); 
			H[factored] = MULTM(X3, SAVE1, N); 
			HH = MULTM(H[factored], H[factored], N); 
			if (RSV(X2, ROOTN) <= 0) 
				Q = SUBI(HH, N); /* Q->S = -1 */ 
			else 
				Q = COPYI(HH); /* Q->S = 1 */ 
			FREEMPI(HH); 
			FREEMPI(X1); 
			FREEMPI(X2); 
			FREEMPI(X3); 
			cofactor[factored] = FACTORQ1(Q, factored, (USL *)base, M1, FBASE, x, r1, r2, r, INDEX, CTR); 
		        /* this factors Q over the factor base, 
        		    updates M1[factored][] and returns the cofactor. */ 
			t = EQONEI(cofactor[factored]); 
			FREEMPI(cofactor[factored]); 
			if (t) 
			{ 
				printf("Q[%u] = ",factored);PRINTI(Q);printf("\n"); 
				cofactor[factored] = Q; 
				factored++;	 
			} 
			else 
			{ 
				FREEMPI(H[factored]); 
				FREEMPI(Q); 
			}	 
			if (factored == TEST_ROWS) 
				break; 
		}	 
	} 
	FREEMPI(SAVE1); 
	FREEMPI(A); 
	FREEMPI(B); 
	FREEMPI(D); 
	} 
/* 
	printf("INDEX = "); 
	for (i = 0; i < TEST_ROWS; i++) 
		printf("%d,", INDEX[i]); 
	printf("\n"); 
	printf("CTR = "); 
	for (i = 0; i < TEST_ROWS; i++) 
		printf("%u,", CTR[i]); 
	printf("\n"); 
	printf("The packed array M1 is:\n"); 
	printf("array M1 is:\n"); 
	for (i = 0; i < TEST_ROWS; i++) 
	{ 
		for (j = 0; j = 0; s--) 
	{ 
		flag = 1; 
		for (j = 0; j < m1bitcols; j++) 
			if (M1[s][j]) 
			{ 
				flag = 0; 
				break; 
			} 
		if (flag == 0) 
			continue; 
/* found a zero row, initialize exponent sums to zero */ 
		INTSETUI(exponents, (USL)FBASE + 1, 0); 
		P1 = ONEI(); 
		for (e = 0; e < TEST_ROWS; e++) 
		{ 
	/* 
			f = (M2[s][e>>5] & ((USL)1<<(31-(e&31))))?1:0; 
	*/ 
			if (get_element(M2,s,e)) 
			{ 
				T = MULTM(P1, H[e], N); 
				FREEMPI(P1); 
				P1 = T; 
				EXP_UPDATE(cofactor[e], (USL *)base, FBASE, exponents); 
			} 
		} 
		P2 = ONEI(); 
		for (j = 0; j <= FBASE; j++) 
		{ 
			if (exponents[j]) 
			{ 
				Y = CHANGE((USL)(base[j])); 
			T = MPOWER_M(Y,(unsigned long)(exponents[j] / 2), N); 
				FREEMPI(Y); 
				Tmp = P2; 
				P2 = MULTM(T, P2, N); 
				FREEMPI(T); 
				FREEMPI(Tmp); 
			} 
		} 
		T = SUBI(P1, P2); 
		G = GCD(T, N); 
		FREEMPI(T); 
		printf("P1 = "); PRINTI(P1);printf("\n"); 
		printf("P2 = "); PRINTI(P2);printf("\n"); 
		printf("GCD(P2 - P1, N) = "); PRINTI(G);printf("\n"); 
		FREEMPI(P1); 
		FREEMPI(P2); 
		if (!EQONEI(G) && !EQUALI(G, N)) 
		{ 
			printf("FOUND A NON_TRIVIAL FACTOR:  "); PRINTI(G);printf("\n"); 
			found = 1; 
			break; 
		} 
		FREEMPI(G); 
	} 
	printf("N = "); PRINTI(N);printf("\n"); 
	FREEMPI(ROOTN); 
	FREEMPI(ROOT2N); 
	FREEMPI(OVER2); 
	ffree((char *)base, (FBASE + 2) * sizeof(long)); 
	ffree((char *)soln, (FBASE + 1) * sizeof(unsigned long)); 
	ffree((char *)r1, (FBASE + 1) * sizeof(unsigned long)); 
	ffree((char *)r2, (FBASE + 1) * sizeof(unsigned long)); 
	ffree((char *)logn, (FBASE + 1) * sizeof(unsigned int)); 
	ffree((char *)logQ, (SSRANGE + 1) * sizeof(unsigned int)); 
	for (i = 0; i < factored; i++) 
		FREEMPI(H[i]); 
	ffree((char *)H, (TEST_ROWS) * sizeof(MPI *)); 
	for (i = 0; i < TEST_ROWS; i++) 
		FREEMPI(cofactor[i]); 
	ffree((char *)cofactor, (TEST_ROWS) * sizeof(MPI *)); 
	ffree((char *)INDEX, (TEST_ROWS) * sizeof(int)); 
	ffree((char *)CTR, (TEST_ROWS) * sizeof(unsigned int)); 
	ffree((char *)exponents, (FBASE + 1) * sizeof(unsigned int)); 
	ifree2(M1, TEST_ROWS, m1bitcols); 
	ifree2(M2, TEST_ROWS, m2bitcols); 
	if (found) 
		return (G); 
	else 
		return (NULL); 
}