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; }
static int check_for_factor(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 /* Use this to really encourage n-1 / n+1 proof types */ if (degree <= 0) { if (stage == 1) return -1; if (stage == 0) stage = 1; } #endif /* 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, f, n); } 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, f, n); } sfaci = 0; success = 1; while (success) { UV nsize = mpz_sizeinbase(n, 2); const int do_pm1 = 1; const int do_pp1 = 1; const int do_pbr = 0; const int do_ecm = 0; if (mpz_cmp(n, fmin) <= 0) return 0; if (is_bpsw_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. */ if (degree <= 0) B1 += 2*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 == 0) { /* A relatively small performance hit, makes slightly smaller proofs. */ if (nsize < 900 && degree <= 2) B1 *= 1.8; /* We need to try a bit harder for the large sizes :( */ if (nsize > 1400) B1 *= 2; if (nsize > 2000) B1 *= 2; if (!success) success = _GMP_pminus1_factor(n, f, 100+B1/8, 100+B1); } else if (stage >= 1) { /* P-1 */ if ((!success && do_pm1)) success = _GMP_pminus1_factor(n, f, B1, 6*B1); /* Pollard's Rho */ if ((!success && do_pbr && nsize < 500)) success = _GMP_pbrent_factor(n, f, nsize % 53, 1000-nsize); /* P+1 */ if ((!success && do_pp1)) { UV ppB = (nsize < 2000) ? B1/4 : B1/16; success = _GMP_pplus1_factor(n, f, 0, ppB, ppB); } if ((!success && do_ecm)) success = _GMP_ecm_factor_projective(n, f, 400, 2000, 1); #ifdef USE_LIBECM /* TODO: LIBECM in other stages */ /* Note: this will be substantially slower than our code for small sizes * and the small B1/B2 values we're using. */ if (!success && degree <= 2 && nsize > 600) { 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; if (success) { printf("ECM FOUND FACTOR\n"); } } #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, 2500, 8); } 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, B1*4, 5); } 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, B1*8, 4); } else if (stage >= 5) { UV B = B1 * (stage-4) * (stage-4) * (stage-4); if (!success) success = _GMP_ecm_factor_projective(n, f, B, 10*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 && is_bpsw_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; }