/* Select the 2, 4, or 6 numbers we will try to factor. */ static void choose_m(mpz_t* mlist, long D, mpz_t u, mpz_t v, mpz_t N, mpz_t t, mpz_t Nminus1) { int i; mpz_add_ui(Nminus1, N, 1); mpz_add(mlist[0], Nminus1, u); mpz_sub(mlist[1], Nminus1, u); for (i = 2; i < 6; i++) mpz_set_ui(mlist[i], 0); if (D == -3) { /* If reading Cohen, be sure to see the errata for page 474. */ mpz_mul_si(t, v, 3); mpz_add(t, t, u); mpz_tdiv_q_2exp(t, t, 1); mpz_add(mlist[2], Nminus1, t); mpz_sub(mlist[3], Nminus1, t); mpz_mul_si(t, v, -3); mpz_add(t, t, u); mpz_tdiv_q_2exp(t, t, 1); mpz_add(mlist[4], Nminus1, t); mpz_sub(mlist[5], Nminus1, t); } else if (D == -4) { mpz_mul_ui(t, v, 2); mpz_add(mlist[2], Nminus1, t); mpz_sub(mlist[3], Nminus1, t); } /* m must not be prime */ for (i = 0; i < 6; i++) if (mpz_sgn(mlist[i]) && _GMP_is_prob_prime(mlist[i])) mpz_set_ui(mlist[i], 0); }
/* Select the 2, 4, or 6 numbers we will try to factor. */ static void choose_m(mpz_t* mlist, long D, mpz_t u, mpz_t v, mpz_t N, mpz_t t, mpz_t Nplus1) { int i, j; mpz_add_ui(Nplus1, N, 1); mpz_sub(mlist[0], Nplus1, u); /* N+1-u */ mpz_add(mlist[1], Nplus1, u); /* N+1+u */ for (i = 2; i < 6; i++) mpz_set_ui(mlist[i], 0); if (D == -3) { /* If reading Cohen, be sure to see the errata for page 474. */ mpz_mul_si(t, v, 3); mpz_add(t, t, u); mpz_tdiv_q_2exp(t, t, 1); mpz_sub(mlist[2], Nplus1, t); /* N+1-(u+3v)/2 */ mpz_add(mlist[3], Nplus1, t); /* N+1+(u+3v)/2 */ mpz_mul_si(t, v, -3); mpz_add(t, t, u); mpz_tdiv_q_2exp(t, t, 1); mpz_sub(mlist[4], Nplus1, t); /* N+1-(u-3v)/2 */ mpz_add(mlist[5], Nplus1, t); /* N+1+(u-3v)/2 */ } else if (D == -4) { mpz_mul_ui(t, v, 2); mpz_sub(mlist[2], Nplus1, t); /* N+1-2v */ mpz_add(mlist[3], Nplus1, t); /* N+1+2v */ } /* m must not be prime */ for (i = 0; i < 6; i++) if (mpz_sgn(mlist[i]) && _GMP_is_prob_prime(mlist[i])) mpz_set_ui(mlist[i], 0); /* Sort the m values so we test the smallest first */ for (i = 0; i < 5; i++) if (mpz_sgn(mlist[i])) for (j = i+1; j < 6; j++) if (mpz_sgn(mlist[j]) && mpz_cmp(mlist[i],mlist[j]) > 0) mpz_swap( mlist[i], mlist[j] ); }
/* Recursive routine to prove via ECPP */ static int ecpp_down(int i, mpz_t Ni, int facstage, IV* dlist, mpz_t* sfacs, int* nsfacs, char** prooftextptr) { mpz_t a, b, u, v, m, q, minfactor, sqrtn, mD, t, t2; mpz_t mlist[6]; UV nm1a; IV np1lp, np1lq; struct ec_affine_point P; int k, dnum, nidigits, facresult, curveresult, downresult, stage, D; int verbose = get_verbose_level(); nidigits = mpz_sizeinbase(Ni, 10); k = _GMP_is_prob_prime(Ni); if (k == 0) return 0; if (k == 2) { /* No need to put anything in the proof */ if (verbose) printf("%*sN[%d] (%d dig) PRIME\n", i, "", i, nidigits); return 2; } downresult = 0; if (verbose) { printf("%*sN[%d] (%d dig)", i, "", i, nidigits); if (facstage > 1) printf(" FS %d", facstage); fflush(stdout); } mpz_init(a); mpz_init(b); mpz_init(u); mpz_init(v); mpz_init(m); mpz_init(q); mpz_init(mD); mpz_init(minfactor); mpz_init(sqrtn); mpz_init(t); mpz_init(t2); mpz_init(P.x);mpz_init(P.y); for (k = 0; k < 6; k++) mpz_init(mlist[k]); /* Any factors q found must be strictly > minfactor. * See Atkin and Morain, 1992, section 6.4 */ mpz_root(minfactor, Ni, 4); mpz_add_ui(minfactor, minfactor, 1); mpz_mul(minfactor, minfactor, minfactor); mpz_sqrt(sqrtn, Ni); for (stage = (i == 0) ? facstage : 1; stage <= facstage; stage++) { int next_stage = (stage > 1) ? stage : 1; for (dnum = 0; dlist[dnum] != 0; dnum++) { int poly_type; /* just for debugging/verbose */ int poly_degree; D = -dlist[dnum]; if (D > 1) continue; /* Marked for skip */ if (D == 1) { /* n-1 test */ mpz_sub_ui(m, Ni, 1); /* m = N-1 */ mpz_sub_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ facresult = check_for_factor2(q, m, t2, t, stage, sfacs, nsfacs, 0); if (facresult <= 0) continue; if (verbose) { printf(" n-1\n"); fflush(stdout); } downresult = ecpp_down(i+1, q, next_stage, dlist, sfacs, nsfacs, prooftextptr); if (downresult == 0) /* composite */ goto end_down; if (downresult == 1) { /* nothing found at this stage */ if (verbose) { printf("%*sN[%d] (%d dig)", i, "", i, nidigits); if (facstage > 1) printf(" FS %d", facstage); fflush(stdout); } continue; } if (verbose) { printf("%*sN[%d] (%d dig) n-1", i, "", i, nidigits); fflush(stdout); } curveresult = _GMP_primality_bls_3(Ni, q, &nm1a); if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if ( ! curveresult ) { /* This ought not happen */ dlist[dnum] = -2; /* skip this D value from now on */ if (verbose) gmp_printf("\n Could not prove n-1 with N = %Zd\n", D, Ni); downresult = 0; continue; } goto end_down; } if (D == -1) { /* n+1 test */ mpz_add_ui(m, Ni, 1); /* m = N+1 */ mpz_add_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ facresult = check_for_factor2(q, m, t2, t, stage, sfacs, nsfacs, 0); if (facresult <= 0) continue; if (verbose) { printf(" n+1\n"); fflush(stdout); } downresult = ecpp_down(i+1, q, next_stage, dlist, sfacs, nsfacs, prooftextptr); if (downresult == 0) /* composite */ goto end_down; if (downresult == 1) { /* nothing found at this stage */ if (verbose) { printf("%*sN[%d] (%d dig)", i, "", i, nidigits); if (facstage > 1) printf(" FS %d", facstage); fflush(stdout); } continue; } if (verbose) { printf("%*sN[%d] (%d dig) n-1", i, "", i, nidigits); fflush(stdout); } curveresult = _GMP_primality_bls_15(Ni, q, &np1lp, &np1lq); if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if ( ! curveresult ) { /* This ought not happen */ dlist[dnum] = -2; /* skip this D value from now on */ if (verbose) gmp_printf("\n Could not prove n-1 with N = %Zd\n", D, Ni); downresult = 0; continue; } goto end_down; } if ( (-D % 4) != 3 && (-D % 16) != 4 && (-D % 16) != 8 ) croak("Invalid discriminant '%d' in list\n", D); /* D must also be squarefree in odd divisors, but assume it. */ /* Make sure we can get a class polynomial for this D. */ poly_degree = poly_class_poly(D, NULL, &poly_type); if (poly_degree == 0) continue; /* We'll save time in the long run by not looking at big polys once * we've found a good path from the start. TODO: Needs more tuning. */ if (stage == 0 && i >= 0 && poly_degree > 2) break; if (facstage == 1) { if (i > 2 && nidigits < 1100 && poly_degree > 24) break; if (i > 3 && nidigits < 950 && poly_degree > 15) break; if (i > 4 && nidigits < 800 && poly_degree > 11) break; if (i > 8 && nidigits < 700 && poly_degree > 9) break; if (i > 16 && nidigits < 600 && poly_degree > 8) break; } mpz_set_si(mD, D); /* (D/N) must be 1, and we have to have a u,v solution */ if (mpz_jacobi(mD, Ni) != 1) continue; if ( ! modified_cornacchia(u, v, mD, Ni) ) continue; if (verbose > 1) { printf(" %d", D); fflush(stdout); } choose_m(mlist, D, u, v, Ni, t, t2); for (k = 0; k < 6; k++) { facresult = check_for_factor2(q, mlist[k], minfactor, t, stage, sfacs, nsfacs, poly_degree); /* -1 = couldn't find, 0 = no big factors, 1 = found */ if (facresult <= 0) continue; mpz_set(m, mlist[k]); if (verbose) { printf(" %d (%s %d)\n", D, (poly_type == 1) ? "Hilbert" : "Weber", poly_degree); fflush(stdout); } /* Great, now go down. */ downresult = ecpp_down(i+1, q, next_stage, dlist, sfacs, nsfacs, prooftextptr); if (downresult == 0) /* composite */ goto end_down; if (downresult == 1) { /* nothing found at this stage */ if (verbose) { printf("%*sN[%d] (%d dig)", i, "", i, nidigits); if (facstage > 1) printf(" FS %d", facstage); fflush(stdout); } continue; } /* Awesome, we found the q chain and are in STAGE 2 */ if (verbose) { printf("%*sN[%d] (%d dig) %d (%s %d)", i, "", i, nidigits, D, (poly_type == 1) ? "Hilbert" : "Weber", poly_degree); fflush(stdout); } curveresult = find_curve(a, b, P.x, P.y, D, m, q, Ni); if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if (curveresult == 1) { /* Oh no! We can't find a point on the curve. Something is right * messed up, and we've wasted a lot of time. Sigh. */ dlist[dnum] = -2; /* skip this D value from now on */ if (verbose) gmp_printf("\n Invalidated D = %d with N = %Zd\n", D, Ni); downresult = 0; continue; } /* We found it was composite or proved it */ goto end_down; } /* k loop for D */ } /* D */ } /* fac stage */ /* Nothing at this level */ downresult = 1; if (verbose) { printf(" ---\n"); fflush(stdout); } end_down: if (downresult == 2) { if (0 && verbose > 1) { if (D == 1) { gmp_printf("\n"); gmp_printf("Type BLS3\n"); gmp_printf("N %Zd\n", Ni); gmp_printf("Q %Zd\n", q); gmp_printf("A %lu\n", (unsigned long) nm1a); gmp_printf("\n"); fflush(stdout); } else if (D == -1) { gmp_printf("\n"); gmp_printf("Type BLS15\n"); gmp_printf("N %Zd\n", Ni); gmp_printf("Q %Zd\n", q); gmp_printf("LP %ld\n", (signed long) np1lp); gmp_printf("LQ %ld\n", (signed long) np1lq); gmp_printf("\n"); fflush(stdout); } else { gmp_printf("\n"); gmp_printf("Type ECPP\n"); gmp_printf("N %Zd\n", Ni); gmp_printf("A %Zd\n", a); gmp_printf("B %Zd\n", b); gmp_printf("M %Zd\n", m); gmp_printf("Q %Zd\n", q); gmp_printf("X %Zd\n", P.x); gmp_printf("Y %Zd\n", P.y); gmp_printf("\n"); fflush(stdout); } } /* Prepend our proof to anything that exists. */ if (prooftextptr != 0) { char *proofstr, *proofptr; int curprooflen = (*prooftextptr == 0) ? 0 : strlen(*prooftextptr); if (D == 1) { int myprooflen = 20 + 2*(4 + mpz_sizeinbase(Ni, 10)) + 1*21; New(0, proofstr, myprooflen + curprooflen + 1, char); proofptr = proofstr; proofptr += gmp_sprintf(proofptr, "Type BLS3\nN %Zd\nQ %Zd\nA %"UVuf"\n", Ni, q, nm1a); } else if (D == -1) {
/* Set up for clever FPS, where the reduced n is remembered each time */ static int check_for_factor(mpz_t f, mpz_t inputn, mpz_t fmin, mpz_t n, long stage) { int success; /* Use this so we don't modify their input value */ mpz_set(n, inputn); if (mpz_cmp(n, fmin) <= 0) return 0; if (stage == 1) { /* simple trial division */ while (mpz_divisible_ui_p(n, 2)) mpz_divexact_ui(n, n, 2); while (mpz_divisible_ui_p(n, 3)) mpz_divexact_ui(n, n, 3); if (mpz_gcd_ui(NULL, n, 2850092245UL) != 1) { while (mpz_divisible_ui_p(n, 5)) mpz_divexact_ui(n, n, 5); while (mpz_divisible_ui_p(n, 7)) mpz_divexact_ui(n, n, 7); while (mpz_divisible_ui_p(n, 11)) mpz_divexact_ui(n, n, 11); while (mpz_divisible_ui_p(n, 13)) mpz_divexact_ui(n, n, 13); while (mpz_divisible_ui_p(n, 17)) mpz_divexact_ui(n, n, 17); while (mpz_divisible_ui_p(n, 19)) mpz_divexact_ui(n, n, 19); while (mpz_divisible_ui_p(n, 41)) mpz_divexact_ui(n, n, 41); while (mpz_divisible_ui_p(n, 43)) mpz_divexact_ui(n, n, 43); } if (mpz_gcd_ui(NULL, n, 2392308223UL) != 1) { while (mpz_divisible_ui_p(n, 23)) mpz_divexact_ui(n, n, 23); while (mpz_divisible_ui_p(n, 29)) mpz_divexact_ui(n, n, 29); while (mpz_divisible_ui_p(n, 31)) mpz_divexact_ui(n, n, 31); while (mpz_divisible_ui_p(n, 37)) mpz_divexact_ui(n, n, 37); while (mpz_divisible_ui_p(n, 53)) mpz_divexact_ui(n, n, 53); while (mpz_divisible_ui_p(n, 59)) mpz_divexact_ui(n, n, 59); } } success = 1; while (success) { if (mpz_cmp(n, fmin) <= 0) return 0; if (_GMP_is_prob_prime(n)) { mpz_set(f, n); return (mpz_cmp(f, fmin) > 0); } success = 0; if (stage == 1) { /* We should probably do something like B1 = 10 * ndigits */ UV B1 = (mpz_sizeinbase(n, 2) > 1200) ? 6000 : 3000; if (!success) success = _GMP_pminus1_factor(n, f, B1, 10*B1); } else if (stage == 2) { if (!success) success = _GMP_pminus1_factor(n, f, 10000, 200000); if (!success) success = _GMP_ecm_factor_projective(n, f, 250, 4); } else if (stage == 3) { if (!success) success = _GMP_pminus1_factor(n, f, 40000, 800000); if (!success) success = _GMP_ecm_factor_projective(n, f, 500, 4); } else if (stage == 4) { if (!success) success = _GMP_pminus1_factor(n, f, 100000, 5000000); if (!success) success = _GMP_ecm_factor_projective(n, f, 1000, 10); } else if (stage >= 5) { UV B = 4000 * (stage-4) * (stage-4) * (stage-4); if (!success) success = _GMP_ecm_factor_projective(n, f, B, 20); } if (success) { if (mpz_cmp_ui(f, 1) == 0 || mpz_cmp(f, n) == 0) { gmp_printf("factoring %Zd resulted in factor %Zd\n", n, f); croak("internal error in ECPP factoring"); } /* Is the factor f what we want? */ if ( mpz_cmp(f, fmin) > 0 && _GMP_is_prob_prime(f) ) return 1; /* Divide out f */ mpz_divexact(n, n, f); } } /* n is larger than fmin and not prime */ mpz_set(f, n); return -1; }
static int check_for_factor2(mpz_t f, mpz_t inputn, mpz_t fmin, mpz_t n, int stage, mpz_t* sfacs, int* nsfacs, int degree) { int success, sfaci; UV B1; /* Use this so we don't modify their input value */ mpz_set(n, inputn); if (mpz_cmp(n, fmin) <= 0) return 0; #if 0 { /* Straightforward trial division up to 3000. */ PRIME_ITERATOR(iter); UV tf; UV const trial_limit = 3000; for (tf = 2; tf < trial_limit; tf = prime_iterator_next(&iter)) { if (mpz_cmp_ui(n, tf*tf) < 0) break; while (mpz_divisible_ui_p(n, tf)) mpz_divexact_ui(n, n, tf); } prime_iterator_destroy(&iter); } #else /* Utilize GMP's fast gcd algorithms. Trial to 224737 with two gcds. */ mpz_tdiv_q_2exp(n, n, mpz_scan1(n, 0)); while (mpz_divisible_ui_p(n, 3)) mpz_divexact_ui(n, n, 3); while (mpz_divisible_ui_p(n, 5)) mpz_divexact_ui(n, n, 5); if (mpz_cmp(n, fmin) <= 0) return 0; mpz_gcd(f, n, _gcd_small); while (mpz_cmp_ui(f, 1) > 0) { mpz_divexact(n, n, f); mpz_gcd(f, n, _gcd_small); } if (mpz_cmp(n, fmin) <= 0) return 0; mpz_gcd(f, n, _gcd_large); while (mpz_cmp_ui(f, 1) > 0) { mpz_divexact(n, n, f); mpz_gcd(f, n, _gcd_large); } /* Quick stage 1 n-1 using a single big powm + gcd. */ if (stage == 0) { if (mpz_cmp(n, fmin) <= 0) return 0; mpz_set_ui(f, 2); mpz_powm(f, f, _lcm_small, n); mpz_sub_ui(f, f, 1); mpz_gcd(f, f, n); if (mpz_cmp_ui(f, 1) != 0 && mpz_cmp(f, n) != 0) { mpz_divexact(n, n, f); if (mpz_cmp(f, n) > 0) mpz_set(n, f); } } #endif sfaci = 0; success = 1; while (success) { UV nsize = mpz_sizeinbase(n, 2); if (mpz_cmp(n, fmin) <= 0) return 0; if (_GMP_is_prob_prime(n)) { mpz_set(f, n); return (mpz_cmp(f, fmin) > 0); } success = 0; B1 = 300 + 3 * nsize; if (degree <= 2) B1 += nsize; /* D1 & D2 are cheap to prove. Encourage. */ if (degree <= 0) B1 += nsize; /* N-1 and N+1 are really cheap. */ if (degree > 20 && stage <= 1) B1 -= nsize; /* Less time on big polys. */ if (degree > 40) B1 -= nsize/2; /* Less time on big polys. */ if (stage >= 1) { #ifdef USE_LIBECM /* TODO: Tune stage 1 (PM1?) */ /* TODO: LIBECM in other stages */ if (!success) { ecm_params params; ecm_init(params); params->method = ECM_ECM; mpz_set_ui(params->B2, 10*B1); mpz_set_ui(params->sigma, 0); success = ecm_factor(f, n, B1/4, params); ecm_clear(params); if (mpz_cmp(f, n) == 0) success = 0; } #else if (!success) success = _GMP_pminus1_factor(n, f, B1, 6*B1); if (!success) success = _GMP_pplus1_factor(n, f, 0, B1/8, B1/8); if (!success && nsize < 500) success = _GMP_pbrent_factor(n, f, nsize, 1024-nsize); #endif } /* Try any factors found in previous stage 2+ calls */ while (!success && sfaci < *nsfacs) { if (mpz_divisible_p(n, sfacs[sfaci])) { mpz_set(f, sfacs[sfaci]); success = 1; } sfaci++; } if (stage > 1 && !success) { if (stage == 2) { if (!success) success = _GMP_pbrent_factor(n, f, nsize-1, 8192); if (!success) success = _GMP_pminus1_factor(n, f, 6*B1, 60*B1); /* p+1 with different initial point and searching farther */ if (!success) success = _GMP_pplus1_factor(n, f, 1, B1/2, B1/2); if (!success) success = _GMP_ecm_factor_projective(n, f, 250, 3); } else if (stage == 3) { if (!success) success = _GMP_pbrent_factor(n, f, nsize+1, 16384); if (!success) success = _GMP_pminus1_factor(n, f, 60*B1, 600*B1); /* p+1 with a third initial point and searching farther */ if (!success) success = _GMP_pplus1_factor(n, f, 2, 1*B1, 1*B1); if (!success) success = _GMP_ecm_factor_projective(n, f, B1/4, 4); } else if (stage == 4) { if (!success) success = _GMP_pminus1_factor(n, f, 300*B1, 300*20*B1); if (!success) success = _GMP_ecm_factor_projective(n, f, B1/2, 4); } else if (stage >= 5) { UV B = B1 * (stage-4) * (stage-4) * (stage-4); if (!success) success = _GMP_ecm_factor_projective(n, f, B, 8+stage); } } if (success) { if (mpz_cmp_ui(f, 1) == 0 || mpz_cmp(f, n) == 0) { gmp_printf("factoring %Zd resulted in factor %Zd\n", n, f); croak("internal error in ECPP factoring"); } /* Add the factor to the saved factors list */ if (stage > 1 && *nsfacs < MAX_SFACS) { /* gmp_printf(" ***** adding factor %Zd ****\n", f); */ mpz_init_set(sfacs[*nsfacs], f); nsfacs[0]++; } /* Is the factor f what we want? */ if ( mpz_cmp(f, fmin) > 0 && _GMP_is_prob_prime(f) ) return 1; /* Divide out f */ mpz_divexact(n, n, f); } } /* n is larger than fmin and not prime */ mpz_set(f, n); return -1; }
/* Recursive routine to prove via ECPP */ static int ecpp_down(int i, mpz_t Ni, int facstage, int *pmaxH, int* dilist, mpz_t* sfacs, int* nsfacs, char** prooftextptr) { mpz_t a, b, u, v, m, q, minfactor, sqrtn, mD, t, t2; mpz_t mlist[6]; mpz_t qlist[6]; UV nm1a; IV np1lp, np1lq; struct ec_affine_point P; int k, dindex, pindex, nidigits, facresult, curveresult, downresult, stage, D; int verbose = get_verbose_level(); nidigits = mpz_sizeinbase(Ni, 10); downresult = _GMP_is_prob_prime(Ni); if (downresult == 0) return 0; if (downresult == 2) { if (mpz_sizeinbase(Ni,2) <= 64) { /* No need to put anything in the proof */ if (verbose) printf("%*sN[%d] (%d dig) PRIME\n", i, "", i, nidigits); return 2; } downresult = 1; } if (i == 0 && facstage == 2 && miller_rabin_random(Ni, 2, 0) == 0) { gmp_printf("\n\n**** BPSW counter-example found? ****\n**** N = %Zd ****\n\n", Ni); return 0; } VERBOSE_PRINT_N(i, nidigits, *pmaxH, facstage); mpz_init(a); mpz_init(b); mpz_init(u); mpz_init(v); mpz_init(m); mpz_init(q); mpz_init(mD); mpz_init(minfactor); mpz_init(sqrtn); mpz_init(t); mpz_init(t2); mpz_init(P.x);mpz_init(P.y); for (k = 0; k < 6; k++) { mpz_init(mlist[k]); mpz_init(qlist[k]); } /* Any factors q found must be strictly > minfactor. * See Atkin and Morain, 1992, section 6.4 */ mpz_root(minfactor, Ni, 4); mpz_add_ui(minfactor, minfactor, 1); mpz_mul(minfactor, minfactor, minfactor); mpz_sqrt(sqrtn, Ni); stage = 0; if (nidigits > 700) stage = 1; /* Too rare to find them */ if (i == 0 && facstage > 1) stage = facstage; for ( ; stage <= facstage; stage++) { int next_stage = (stage > 1) ? stage : 1; for (dindex = -1; dindex < 0 || dilist[dindex] != 0; dindex++) { int poly_type; /* just for debugging/verbose */ int poly_degree; int allq = (nidigits < 400); /* Do all q values together, or not */ if (dindex == -1) { /* n-1 and n+1 tests */ int nm1_success = 0; int np1_success = 0; const char* ptype = ""; mpz_sub_ui(m, Ni, 1); mpz_sub_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ nm1_success = check_for_factor(u, m, t2, t, stage, sfacs, nsfacs, 0); mpz_add_ui(m, Ni, 1); mpz_add_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ np1_success = check_for_factor(v, m, t2, t, stage, sfacs, nsfacs, 0); /* If both successful, pick smallest */ if (nm1_success > 0 && np1_success > 0) { if (mpz_cmp(u, v) <= 0) np1_success = 0; else nm1_success = 0; } if (nm1_success > 0) { ptype = "n-1"; mpz_set(q, u); D = 1; } else if (np1_success > 0) { ptype = "n+1"; mpz_set(q, v); D = -1; } else continue; if (verbose) { printf(" %s\n", ptype); fflush(stdout); } downresult = ecpp_down(i+1, q, next_stage, pmaxH, dilist, sfacs, nsfacs, prooftextptr); if (downresult == 0) goto end_down; /* composite */ if (downresult == 1) { /* nothing found at this stage */ VERBOSE_PRINT_N(i, nidigits, *pmaxH, facstage); continue; } if (verbose) { printf("%*sN[%d] (%d dig) %s", i, "", i, nidigits, ptype); fflush(stdout); } curveresult = (nm1_success > 0) ? _GMP_primality_bls_3(Ni, q, &nm1a) : _GMP_primality_bls_15(Ni, q, &np1lp, &np1lq); if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if ( ! curveresult ) { /* This ought not happen */ if (verbose) gmp_printf("\n Could not prove %s with N = %Zd\n", ptype, Ni); downresult = 1; continue; } goto end_down; } pindex = dilist[dindex]; if (pindex < 0) continue; /* We marked this for skip */ /* Get the values for D, degree, and poly type */ poly_degree = poly_class_poly_num(pindex, &D, NULL, &poly_type); if (poly_degree == 0) croak("Unknown value in dilist[%d]: %d\n", dindex, pindex); if ( (-D % 4) != 3 && (-D % 16) != 4 && (-D % 16) != 8 ) croak("Invalid discriminant '%d' in list\n", D); /* D must also be squarefree in odd divisors, but assume it. */ /* Make sure we can get a class polynomial for this D. */ if (poly_degree > 16 && stage == 0) { if (verbose) printf(" [1]"); break; } /* Make the continue-search vs. backtrack decision */ if (*pmaxH > 0 && poly_degree > *pmaxH) break; mpz_set_si(mD, D); /* (D/N) must be 1, and we have to have a u,v solution */ if (mpz_jacobi(mD, Ni) != 1) continue; if ( ! modified_cornacchia(u, v, mD, Ni) ) continue; if (verbose > 1) { printf(" %d", D); fflush(stdout); } /* We're going to factor all the values for this discriminant then pick * the smallest. This adds a little time, but it means we go down * faster. This makes smaller proofs, and might even save time. */ choose_m(mlist, D, u, v, Ni, t, t2); if (allq) { int x, y; /* We have 0 to 6 m values. Try to factor them, put in qlist. */ for (k = 0; k < 6; k++) { mpz_set_ui(qlist[k], 0); if (mpz_sgn(mlist[k])) { facresult = check_for_factor(qlist[k], mlist[k], minfactor, t, stage, sfacs, nsfacs, poly_degree); /* -1 = couldn't find, 0 = no big factors, 1 = found */ if (facresult <= 0) mpz_set_ui(qlist[k], 0); } } /* Sort any q values by size, so we work on the smallest first */ for (x = 0; x < 5; x++) if (mpz_sgn(qlist[x])) for (y = x+1; y < 6; y++) if (mpz_sgn(qlist[y]) && mpz_cmp(qlist[x],qlist[y]) > 0) { mpz_swap( qlist[x], qlist[y] ); mpz_swap( mlist[x], mlist[y] ); } } /* Try to make a proof with the first (smallest) q value. * Repeat for others if we have to. */ for (k = 0; k < 6; k++) { int maxH = *pmaxH; int minH = (nidigits <= 240) ? 7 : (nidigits+39)/40; if (allq) { if (mpz_sgn(qlist[k]) == 0) continue; mpz_set(m, mlist[k]); mpz_set(q, qlist[k]); } else { if (mpz_sgn(mlist[k]) == 0) continue; mpz_set(m, mlist[k]); facresult = check_for_factor(q, m, minfactor, t, stage, sfacs, nsfacs, poly_degree); if (facresult <= 0) continue; } if (verbose) { printf(" %d (%s %d)\n", D, poly_class_type_name(poly_type), poly_degree); fflush(stdout); } if (maxH == 0) { maxH = minH-1 + poly_degree; if (facstage > 1) /* We worked hard to get here, */ maxH = 2*maxH + 10; /* try hard to make use of it. */ } else if (maxH > minH && maxH > (poly_degree+2)) { maxH--; } /* Great, now go down. */ downresult = ecpp_down(i+1, q, next_stage, &maxH, dilist, sfacs, nsfacs, prooftextptr); /* Nothing found, look at more polys in the future */ if (downresult == 1 && *pmaxH > 0) *pmaxH = maxH; if (downresult == 0) goto end_down; /* composite */ if (downresult == 1) { /* nothing found at this stage */ VERBOSE_PRINT_N(i, nidigits, *pmaxH, facstage); continue; } /* Awesome, we found the q chain and are in STAGE 2 */ if (verbose) { printf("%*sN[%d] (%d dig) %d (%s %d)", i, "", i, nidigits, D, poly_class_type_name(poly_type), poly_degree); fflush(stdout); } /* Try with only one or two roots, then 8 if that didn't work. */ /* TODO: This should be done using a root iterator in find_curve() */ curveresult = find_curve(a, b, P.x, P.y, D, pindex, m, q, Ni, 1); if (curveresult == 1) { if (verbose) { printf(" [redo roots]"); fflush(stdout); } curveresult = find_curve(a, b, P.x, P.y, D, pindex, m, q, Ni, 8); } if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if (curveresult == 1) { /* Something is wrong. Very likely the class poly coefficients are incorrect. We've wasted lots of time, and need to try again. */ dilist[dindex] = -2; /* skip this D value from now on */ if (verbose) gmp_printf("\n Invalidated D = %d with N = %Zd\n", D, Ni); downresult = 1; continue; } /* We found it was composite or proved it */ goto end_down; } /* k loop for D */ } /* D */ } /* fac stage */ /* Nothing at this level */ if (downresult != 1) croak("ECPP internal error: downresult is %d at end\n", downresult); if (verbose) { if (*pmaxH > 0) printf(" (max %d)", *pmaxH); printf(" ---\n"); fflush(stdout); } if (*pmaxH > 0) *pmaxH = *pmaxH + 2; end_down: if (downresult == 2) { if (0 && verbose > 1) { gmp_printf("\n"); if (D == 1) { gmp_printf("Type BLS3\nN %Zd\nQ %Zd\nA %"UVuf"\n", Ni, q, nm1a); } else if (D == -1) { gmp_printf("Type BLS15\nN %Zd\nQ %Zd\nLP %"IVdf"\nLQ %"IVdf"\n", Ni, q, np1lp, np1lq); } else { gmp_printf("Type ECPP\nN %Zd\nA %Zd\nB %Zd\nM %Zd\nQ %Zd\nX %Zd\nY %Zd\n", Ni, a, b, m, q, P.x, P.y); } gmp_printf("\n"); fflush(stdout); } /* Prepend our proof to anything that exists. */ if (prooftextptr != 0) { char *proofstr, *proofptr; int curprooflen = (*prooftextptr == 0) ? 0 : strlen(*prooftextptr); if (D == 1) { int myprooflen = 20 + 2*(4 + mpz_sizeinbase(Ni, 10)) + 1*21; New(0, proofstr, myprooflen + curprooflen + 1, char); proofptr = proofstr; proofptr += gmp_sprintf(proofptr, "Type BLS3\nN %Zd\nQ %Zd\n", Ni,q); proofptr += sprintf(proofptr, "A %"UVuf"\n", nm1a); } else if (D == -1) {