--- /dev/null
+/**************************************************************
+ *
+ * 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;
+}
+