+/**************************************************************
+ *
+ * fmodule.c
+ *
+ * Factoring utilities.
+ *
+ * Updates:
+ * 13 Apr 98 REC - creation
+ *
+ * c. 1998 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"
+#include "fmodule.h"
+#include "ellmont.h"
+
+#define NUM_PRIMES 6542 /* PrimePi[2^16]. */
+#define GENERAL_MOD 0
+#define FERMAT_MOD 1
+#define MERSENNE_MOD (-1)
+#define D 100 /* A decimation parameter for stage-2 ECM factoring. */
+
+/* compiler options */
+
+#ifdef _WIN32
+#pragma warning( disable : 4127 4706 ) /* disable conditional is constant warning */
+#endif
+
+
+/* global variables */
+
+extern int pr[NUM_PRIMES]; /* Primes array from tools.c. */
+
+unsigned short factors[NUM_PRIMES], exponents[NUM_PRIMES];
+int modmode = GENERAL_MOD;
+int curshorts = 0;
+static giant t1 = NULL, t2 = NULL, t3 = NULL, t4 = NULL;
+static giant An = NULL, Ad = NULL;
+static point_mont pt1, pt2;
+point_mont pb[D+2];
+giant xzb[D+2];
+
+static int verbosity = 0;
+
+/**************************************************************
+ *
+ * Functions
+ *
+ **************************************************************/
+
+int
+init_fmodule(int shorts) {
+ curshorts = shorts;
+ pb[0] = NULL; /* To guarantee proper ECM initialization. */
+ t1 = newgiant(shorts);
+ t2 = newgiant(shorts);
+ t3 = newgiant(shorts);
+ t4 = newgiant(shorts);
+ An = newgiant(shorts);
+ Ad = newgiant(shorts);
+ pt1 = new_point_mont(shorts);
+ pt2 = new_point_mont(shorts);
+}
+
+void
+verbose(int state)
+/* Call verbose(1) for output during factoring processes,
+ call verbose(0) to silence all that.
+ */
+{
+ verbosity = state;
+}
+
+void
+dot(void)
+{
+ printf(".");
+ fflush(stdout);
+}
+
+void
+set_mod_mode(int mode)
+/* Call this with mode := 1, 0, -1, for Fermat-mod, general mod, and Mersenne mod,
+ respectively; the point being that the special cases of
+ Fermat- and Mersenne-mod are much faster than
+ general mod. If all mods will be with respect to a number-to-be-factored,
+ of the form N = 2^m + 1, use Fermat mod; while if N = 2^m-1, use Mersenne mod.
+ */
+{
+ modmode = mode;
+}
+
+void
+special_modg(
+ giant N,
+ giant t
+)
+{
+ switch (modmode)
+ {
+ case MERSENNE_MOD:
+ mersennemod(bitlen(N), t);
+ break;
+ case FERMAT_MOD:
+ fermatmod(bitlen(N)-1, t);
+ break;
+ default:
+ modg(N, t);
+ break;
+ }
+}
+
+unsigned short *
+prime_list() {
+ return(&factors[0]);
+}
+
+unsigned short *
+exponent_list() {
+ return(&exponents[0]);
+}
+
+int
+sieve(giant N, int sievelim)
+/* Returns number of N's prime factors < min(sievelim, 2^16),
+ with N reduced accordingly by said factors.
+ The n-th entry of factors[] becomes the n-th prime
+ factor of N, with corresponding exponent
+ becoming the n-th element of exponents[].
+ */
+{ int j, pcount, rem;
+ unsigned short pri;
+
+ pcount = 0;
+ exponents[0] = 0;
+ for (j=0; j < NUM_PRIMES; j++)
+ {
+ pri = pr[j];
+ if(pri > sievelim) break;
+ do {
+ gtog(N, t1);
+ rem = idivg(pri, t1);
+ if(rem == 0) {
+ ++exponents[pcount];
+ gtog(t1, N);
+ }
+ } while(rem == 0);
+ if(exponents[pcount] > 0) {
+ factors[pcount] = pr[j];
+ ++pcount;
+ exponents[pcount] = 0;
+ }
+ }
+ return(pcount);
+}
+
+int
+pollard_rho(giant N, giant fact, int steps, int abort)
+/* Perform Pollard-rho x:= 3; loop(x:= x^2 + 2), a total of steps times.
+ Parameter fact will be a nontrivial factor found, in which case
+ N is also modified as: N := N/fact.
+ The function returns 0 if no nontrivial factor found, else returns 1.
+ The abort parameter, when set, causes the factorer to exit on the
+ first nontrivial factor found (the requisite GCD is checked
+ every 1000 steps). If abort := 0, the full number
+ of steps are always performed, then one solitary GCD is taken,
+ before exit.
+ */
+{
+ int j, found = 0;
+
+ itog(3, t1);
+ gtog(t1, t2);
+ itog(1, fact);
+ for(j=0; j < steps; j++) {
+ squareg(t1); iaddg(2, t1); special_modg(N, t1);
+ squareg(t2); iaddg(2, t2); special_modg(N, t2);
+ squareg(t2); iaddg(2, t2); special_modg(N, t2);
+ gtog(t2, t3); subg(t1,t3); mulg(t3, fact); special_modg(N, fact);
+ if(((j % 1000 == 999) && abort) || (j == steps-1)) {
+ if(verbosity) dot();
+ gcdg(N, fact);
+ if(!isone(fact)) {
+ found = (gcompg(N, fact) == 0) ? 0 : 1;
+ break;
+ }
+ }
+ }
+ if(verbosity) { printf("\n"); fflush(stdout); }
+ if(found) {
+ divg(fact, N);
+ return(1);
+ }
+ itog(1, fact);
+ return(0);
+}
+
+int
+pollard_pminus1(giant N, giant fact, int lim, int abort)
+/* Perform Pollard-(p-1); where we test
+
+ GCD[N, 3^P - 1],
+
+ where P is an accumulation of primes <= min(lim, 2^16),
+ to appropriate powers.
+ Parameter fact will be a nontrivial factor found, in which case
+ N is also modified as: N := N/fact.
+ The function returns 0 if no nontrivial factor found, else returns 1.
+ The abort parameter, when set, causes the factorer to exit on the
+ first nontrivial factor found (the requisite GCD is checked
+ every 100 steps). If abort := 0, the full number
+ of steps are always performed, then one solitary GCD is taken,
+ before exit.
+ */
+{ int cnt, j, k, pri, found = 0;
+
+ itog(3, fact);
+ for (j=0; j< NUM_PRIMES; j++)
+ {
+ pri = pr[j];
+ if((pri > lim) || (j == NUM_PRIMES-1) || (abort && (j % 100 == 99))) {
+ if(verbosity) dot();
+ gtog(fact, t1);
+ itog(1, t2);
+ subg(t2, t1);
+ special_modg(N, t1);
+ gcdg(N, t1);
+ if(!isone(t1)) {
+ found = (gcompg(N, t1) == 0) ? 0 : 1;
+ break;
+ }
+ if(pri > lim) break;
+ }
+ if(pri < 19) { cnt = 20-pri; /* Smaller primes get higher powers. */
+ } else if(pri < 100) {
+ cnt = 2;
+ } else cnt = 1;
+ for (k=0; k< cnt; k++)
+ {
+ powermod(fact, pri, N);
+ }
+ }
+ if(verbosity) { printf("\n"); fflush(stdout); }
+ if(found) {
+ gtog(t1, fact);
+ divg(fact, N);
+ return(1);
+ }
+ itog(1, fact);
+ return(0);
+}
+
+int
+ecm(giant N, giant fact, int S, unsigned int B, unsigned int C)
+/* Perform elliptic curve method (ECM), with:
+ Brent seed parameter = S
+ Stage-one limit = B
+ Stage-two limit = C
+ This function:
+ returns 1 if nontrivial factor is found in stage 1 of ECM;
+ returns 2 if nontrivial factor is found in stage 2 of ECM;
+ returns 0 otherwise.
+ In the positive return, parameter fact is the factor and N := N/fact.
+ */
+{ unsigned int pri, q;
+ int j, cnt, count, k;
+
+ if(verbosity) {
+ printf("Finding curve and point, B = %u, C = %u, seed = %d...", B, C, S);
+ fflush(stdout);
+ }
+ find_curve_point_brent(pt1, S, An, Ad, N);
+ if(verbosity) {
+ printf("\n");
+ printf("Commencing stage 1 of ECM...\n");
+ fflush(stdout);
+ }
+
+ q = pr[NUM_PRIMES-1];
+ count = 0;
+ for(j=0; ; j++) {
+ if(j < NUM_PRIMES) {
+ pri = pr[j];
+ } else {
+ q += 2;
+ if(primeq(q)) pri = q;
+ else continue;
+ }
+ if(verbosity) if((++count) % 100 == 0) dot();
+ if(pri > B) break;
+ if(pri < 19) { cnt = 20-pri;
+ } else if(pri < 100) {
+ cnt = 2;
+ } else cnt = 1;
+ for(k = 0; k < cnt; k++)
+ ell_mul_int_brent(pt1, pri, An, Ad, N);
+ }
+ k = 19;
+ while (k<B)
+ {
+ if (primeq(k))
+ {
+ ell_mul_int_brent(pt1, k, An, Ad, N);
+ if (k<100)
+ ell_mul_int_brent(pt1, k, An, Ad, N);
+ if (cnt++ %100==0)
+ dot();
+ }
+ k += 2;
+ }
+ if(verbosity) { printf("\n"); fflush(stdout); }
+
+/* Next, test stage-1 attempt. */
+ gtog(pt1->z, fact);
+ gcdg(N, fact);
+ if((!isone(fact)) && (gcompg(N, fact) != 0)) {
+ divg(fact, N);
+ return(1);
+ }
+ if(B >= C) { /* No stage 2 planned. */
+ itog(1, fact);
+ return(0);
+ }
+
+/* Commence second stage of ECM. */
+ if(verbosity) {
+ printf("\n");
+ printf("Commencing stage 2 of ECM...\n");
+ fflush(stdout);
+ }
+ if(pb[0] == NULL) {
+ for(k=0; k < D+2; k++) {
+ pb[k] = new_point_mont(curshorts);
+ xzb[k] = newgiant(curshorts);
+
+ }
+ }
+ k = ((int)B)/D;
+ ptop_mont(pt1, pb[0]);
+ ell_mul_int_brent(pb[0], k*D+1 , An, Ad, N);
+ ptop_mont(pt1, pb[D+1]);
+ ell_mul_int_brent(pb[D+1], (k+2)*D+1 , An, Ad, N);
+
+ for (j=1; j <= D; j++)
+ {
+ ptop_mont(pt1, pb[j]);
+ ell_mul_int_brent(pb[j], 2*j , An, Ad, N);
+ gtog(pb[j]->z, xzb[j]);
+ mulg(pb[j]->x, xzb[j]);
+ special_modg(N, xzb[j]);
+ }
+ itog(1, fact);
+ count = 0;
+ while (1) {
+ if(verbosity) if((++count) % 10 == 0) dot();
+ gtog(pb[0]->z, xzb[0]);
+ mulg(pb[0]->x, xzb[0]);
+ special_modg(N, xzb[0]);
+ mulg(pb[0]->z, fact);
+ special_modg(N, fact); /* Accumulate. */
+ for (j = 1; j < D; j++) {
+ if (!primeq(k*D+1+2*j)) continue;
+/* Next, accumulate (xa - xb)(za + zb) - xa za + xb zb. */
+ gtog(pb[0]->x, t1);
+ subg(pb[j]->x, t1);
+ gtog(pb[0]->z, t2);
+ addg(pb[j]->z, t2);
+ mulg(t1, t2);
+ special_modg(N, t1);
+ subg(xzb[0], t2);
+ addg(xzb[j], t2);
+ special_modg(N, t2);
+ mulg(t2, fact);
+ special_modg(N, fact);
+ }
+ k += 2;
+ if(k*D > C)
+ break;
+ ptop_mont(pb[D+1], pt2);
+ ell_odd_brent(pb[D], pb[D+1], pb[0], N);
+ ptop_mont(pt2, pb[0]);
+ }
+ if(verbosity) { printf("\n"); fflush(stdout); }
+
+ gcdg(N, fact);
+ if((!isone(fact)) && (gcompg(N, fact) != 0)) {
+ divg(fact, N);
+ return(2); /* Return value of 2 for stage-2 success! */
+ }
+ itog(1, fact);
+ return(0);
+}
+
+