/*======================================================================== Compute Factor Base: Function: Computes primes p up to B for which n is a square mod p, allocates memory and stores them in an array pointed to by factorBase. Additionally allocates and computes the primeSizes array. Returns: number of primes actually in the factor base ========================================================================*/ static void computeFactorBase(mpz_t n, unsigned long B,unsigned long multiplier) { UV p; UV primesinbase = 0; PRIME_ITERATOR(iter); if (factorBase) { Safefree(factorBase); factorBase = 0; } New(0, factorBase, B, unsigned int); factorBase[primesinbase++] = multiplier; if (multiplier != 2) factorBase[primesinbase++] = 2; prime_iterator_setprime(&iter, 3); for (p = 3; primesinbase < B; p = prime_iterator_next(&iter)) { if (mpz_kronecker_ui(n, p) == 1) factorBase[primesinbase++] = p; } prime_iterator_destroy(&iter); #ifdef LARGESTP gmp_printf("Largest prime less than %Zd\n",p); #endif /* Allocate and compute the number of bits required to store each prime */ New(0, primeSizes, B, unsigned char); for (p = 0; p < B; p++) primeSizes[p] = (unsigned char) floor( log(factorBase[p]) / log(2.0) - SIZE_FUDGE + 0.5 ); }
static unsigned long knuthSchroeppel(mpz_t n, unsigned long numPrimes) { unsigned int i, j, best_mult, knmod8; unsigned int maxprimes = (2*numPrimes <= 1000) ? 2*numPrimes : 1000; float best_score, contrib; float scores[NUMMULTS]; mpz_t temp; mpz_init(temp); for (i = 0; i < NUMMULTS; i++) { scores[i] = 0.5 * logf((float)multipliers[i]); mpz_mul_ui(temp, n, multipliers[i]); knmod8 = mpz_mod_ui(temp, temp, 8); switch (knmod8) { case 1: scores[i] -= 2 * M_LN2; break; case 5: scores[i] -= M_LN2; break; case 3: case 7: scores[i] -= 0.5 * M_LN2; break; default: break; } } { unsigned long prime, modp, knmodp; PRIME_ITERATOR(iter); for (i = 1; i < maxprimes; i++) { prime = prime_iterator_next(&iter); modp = mpz_mod_ui(temp, n, prime); contrib = logf((float)prime) / (float)(prime-1); for (j = 0; j < NUMMULTS; j++) { knmodp = (modp * multipliers[j]) % prime; if (knmodp == 0) { scores[j] -= contrib; } else { mpz_set_ui(temp, knmodp); if (mpz_kronecker_ui(temp, prime) == 1) scores[j] -= 2*contrib; } } } prime_iterator_destroy(&iter); } mpz_clear(temp); best_score = 1000.0; best_mult = 1; for (i = 0; i < NUMMULTS; i++) { float score = scores[i]; if (score < best_score) { best_score = score; best_mult = multipliers[i]; } } /* gmp_printf("%Zd mult %lu\n", n, best_mult); */ return best_mult; }
static UV largest_factor(UV n) { UV p = 2; PRIME_ITERATOR(iter); while (n >= p*p && !prime_iterator_isprime(&iter, n)) { while ( (n % p) == 0 && n >= p*p ) { n /= p; } p = prime_iterator_next(&iter); } prime_iterator_destroy(&iter); return n; }
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; }
int is_aks_prime(mpz_t n) { mpz_t *px, *py; int retval; UV i, s, r, a; UV starta = 1; int _verbose = get_verbose_level(); if (mpz_cmp_ui(n, 4) < 0) return (mpz_cmp_ui(n, 1) <= 0) ? 0 : 1; /* Just for performance: check small divisors: 2*3*5*7*11*13*17*19*23 */ if (mpz_gcd_ui(0, n, 223092870UL) != 1 && mpz_cmp_ui(n, 23) > 0) return 0; if (mpz_perfect_power_p(n)) return 0; #if AKS_VARIANT == AKS_VARIANT_V6 /* From the V6 AKS paper */ { mpz_t sqrtn, t; double log2n; UV limit, startr; PRIME_ITERATOR(iter); mpz_init(sqrtn); mpz_sqrt(sqrtn, n); log2n = mpz_log2(n); limit = (UV) floor( log2n * log2n ); if (_verbose>1) gmp_printf("# AKS checking order_r(%Zd) to %"UVuf"\n", n, (unsigned long) limit); /* Using a native r limits us to ~2000 digits in the worst case (r ~ log^5n) * but would typically work for 100,000+ digits (r ~ log^3n). This code is * far too slow to matter either way. Composite r is ok here, but it will * always end up prime, so save time and just check primes. */ retval = 0; /* Start order search at a good spot. Idea from Nemana and Venkaiah. */ startr = (mpz_sizeinbase(n,2)-1) * (mpz_sizeinbase(n,2)-1); startr = (startr < 1002) ? 2 : startr - 100; for (r = 2; /* */; r = prime_iterator_next(&iter)) { if (mpz_divisible_ui_p(n, r) ) /* r divides n. composite. */ { retval = 0; break; } if (mpz_cmp_ui(sqrtn, r) <= 0) /* no r <= sqrtn divides n. prime. */ { retval = 1; break; } if (r < startr) continue; if (mpz_order_ui(r, n, limit) > limit) { retval = 2; break; } } prime_iterator_destroy(&iter); mpz_clear(sqrtn); if (retval != 2) return retval; /* Since r is prime, phi(r) = r-1. */ s = (UV) floor( sqrt(r-1) * log2n ); } #elif AKS_VARIANT == AKS_VARIANT_BORNEMANN /* Bernstein + Voloch */ { UV slim; double c2, x; /* small t = few iters of big poly. big t = many iters of small poly */ double const t = (mpz_sizeinbase(n, 2) <= 64) ? 32 : 40; double const t1 = (1.0/((t+1)*log(t+1)-t*log(t))); double const dlogn = mpz_logn(n); mpz_t tmp; PRIME_ITERATOR(iter); mpz_init(tmp); prime_iterator_setprime(&iter, (UV) (t1*t1 * dlogn*dlogn) ); r = prime_iterator_next(&iter); while (!is_primitive_root_uiprime(n,r)) r = prime_iterator_next(&iter); prime_iterator_destroy(&iter); slim = (UV) (2*t*(r-1)); c2 = dlogn * floor(sqrt(r)); { /* Binary search for first s in [1,slim] where x >= 0 */ UV bi = 1; UV bj = slim; while (bi < bj) { s = bi + (bj-bi)/2; mpz_bin_uiui(tmp, r+s-1, s); x = mpz_logn(tmp) / c2 - 1.0; if (x < 0) bi = s+1; else bj = s; } s = bi-1; } s = (s+3) >> 1; /* Bornemann checks factors up to (s-1)^2, we check to max(r,s) */ /* slim = (s-1)*(s-1); */ slim = (r > s) ? r : s; if (_verbose > 1) printf("# aks trial to %"UVuf"\n", slim); if (_GMP_trial_factor(n, 2, slim) > 1) { mpz_clear(tmp); return 0; } mpz_sqrt(tmp, n); if (mpz_cmp_ui(tmp, slim) <= 0) { mpz_clear(tmp); return 1; } mpz_clear(tmp); } #elif AKS_VARIANT == AKS_VARIANT_BERN21 { /* Bernstein 2003, theorem 2.1 (simplified) */ UV q; double slim, scmp, x; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); r = s = 0; while (1) { /* todo: Check r|n and r >= sqrt(n) here instead of waiting */ if (mpz_cmp_ui(n, r) <= 0) break; r = prime_iterator_next(&iter); q = largest_factor(r-1); mpz_set_ui(t, r); mpz_powm_ui(t, n, (r-1)/q, t); if (mpz_cmp_ui(t, 1) <= 0) continue; scmp = 2 * floor(sqrt(r)) * mpz_log2(n); slim = 20 * (r-1); /* Check viability */ mpz_bin_uiui(t, q+slim-1, slim); if (mpz_log2(t) < scmp) continue; for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); if (mpz_log2(t) > scmp) break; } if (s < slim) break; } mpz_clear(t); mpz_clear(t2); prime_iterator_destroy(&iter); if (_GMP_trial_factor(n, 2, s) > 1) return 0; } #elif AKS_VARIANT == AKS_VARIANT_BERN22 { /* Bernstein 2003, theorem 2.2 (simplified) */ UV q; double slim, scmp, x; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); r = s = 0; while (1) { /* todo: Check r|n and r >= sqrt(n) here instead of waiting */ if (mpz_cmp_ui(n, r) <= 0) break; r = prime_iterator_next(&iter); if (!is_primitive_root_uiprime(n,r)) continue; q = r-1; /* Since r is prime, phi(r) = r-1 */ scmp = 2 * floor(sqrt(r-1)) * mpz_log2(n); slim = 20 * (r-1); /* Check viability */ mpz_bin_uiui(t, q+slim-1, slim); if (mpz_log2(t) < scmp) continue; for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); if (mpz_log2(t) > scmp) break; } if (s < slim) break; } mpz_clear(t); mpz_clear(t2); prime_iterator_destroy(&iter); if (_GMP_trial_factor(n, 2, s) > 1) return 0; } #elif AKS_VARIANT == AKS_VARIANT_BERN23 { /* Bernstein 2003, theorem 2.3 (simplified) */ UV q, d, limit; double slim, scmp, sbin, x, log2n; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); log2n = mpz_log2(n); limit = (UV) floor( log2n * log2n ); r = 2; s = 0; while (1) { /* todo: Check r|n and r >= sqrt(n) here instead of waiting */ if (mpz_cmp_ui(n, r) <= 0) break; r++; UV gcd = mpz_gcd_ui(NULL, n, r); if (gcd != 1) { mpz_clear(t); mpz_clear(t2); return 0; } UV v = mpz_order_ui(r, n, limit); if (v >= limit) continue; mpz_set_ui(t2, r); totient(t, t2); q = mpz_get_ui(t); UV phiv = q/v; /* printf("phi(%lu)/v = %lu/%lu = %lu\n", r, q, v, phiv); */ /* This is extremely inefficient. */ /* Choose an s value we'd be happy with */ slim = 20 * (r-1); /* Quick check to see if it could work with s=slim, d=1 */ mpz_bin_uiui(t, q+slim-1, slim); sbin = mpz_log2(t); if (sbin < 2*floor(sqrt(q))*log2n) continue; for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); sbin = mpz_log2(t); if (sbin < 2*floor(sqrt(q))*log2n) continue; /* d=1 */ /* Check each number dividing phi(r)/v */ for (d = 2; d < phiv; d++) { if ((phiv % d) != 0) continue; scmp = 2 * d * floor(sqrt(q/d)) * log2n; if (sbin < scmp) break; } /* if we did not exit early, this s worked for each d. This s wins. */ if (d >= phiv) break; } if (s < slim) break; } mpz_clear(t); mpz_clear(t2); prime_iterator_destroy(&iter); if (_GMP_trial_factor(n, 2, s) > 1) return 0; } #elif AKS_VARIANT == AKS_VARIANT_BERN41 { double const log2n = mpz_log2(n); /* Tuning: Initial 'r' selection */ double const r0 = 0.008 * log2n * log2n; /* Tuning: Try a larger 'r' if 's' looks very large */ UV const rmult = 8; UV slim; mpz_t tmp, tmp2; PRIME_ITERATOR(iter); mpz_init(tmp); mpz_init(tmp2); /* r has to be at least 3. */ prime_iterator_setprime(&iter, (r0 < 2) ? 2 : (UV) r0); r = prime_iterator_next(&iter); /* r must be a primitive root. For performance, skip if s looks too big. */ while ( !is_primitive_root_uiprime(n, r) || !bern41_acceptable(n, r, rmult*(r-1), tmp, tmp2) ) r = prime_iterator_next(&iter); prime_iterator_destroy(&iter); { /* Binary search for first s in [1,lim] where conditions met */ UV bi = 1; UV bj = rmult * (r-1); while (bi < bj) { s = bi + (bj-bi)/2; if (!bern41_acceptable(n,r,s,tmp,tmp2)) bi = s+1; else bj = s; } s = bj; /* Our S goes from 2 to s+1. */ starta = 2; s = s+1; } /* printf("chose r=%lu s=%lu d = %lu i = %lu j = %lu\n", r, s, d, i, j); */ /* Check divisibility to s(s-1) to cover both gcd conditions */ slim = s * (s-1); if (_verbose > 1) printf("# aks trial to %"UVuf"\n", slim); if (_GMP_trial_factor(n, 2, slim) > 1) { mpz_clear(tmp); mpz_clear(tmp2); return 0; } /* If we checked divisibility to sqrt(n), then it is prime. */ mpz_sqrt(tmp, n); if (mpz_cmp_ui(tmp, slim) <= 0) { mpz_clear(tmp); mpz_clear(tmp2); return 1; } /* Check b^(n-1) = 1 mod n for b in [2..s] */ if (_verbose > 1) printf("# aks checking fermat to %"UVuf"\n", s); mpz_sub_ui(tmp2, n, 1); for (i = 2; i <= s; i++) { mpz_set_ui(tmp, i); mpz_powm(tmp, tmp, tmp2, n); if (mpz_cmp_ui(tmp, 1) != 0) { mpz_clear(tmp); mpz_clear(tmp2); return 0; } } mpz_clear(tmp); mpz_clear(tmp2); } #endif if (_verbose) gmp_printf("# AKS %Zd. r = %"UVuf" s = %"UVuf"\n", n, (unsigned long) r, (unsigned long) s); /* Create the three polynomials we will use */ New(0, px, r, mpz_t); New(0, py, r, mpz_t); if ( !px || !py ) croak("allocation failure\n"); for (i = 0; i < r; i++) { mpz_init(px[i]); mpz_init(py[i]); } retval = 1; for (a = starta; a <= s; a++) { retval = test_anr(a, n, r, px, py); if (!retval) break; if (_verbose>1) { printf("."); fflush(stdout); } } if (_verbose>1) { printf("\n"); fflush(stdout); }; /* Free the polynomials */ for (i = 0; i < r; i++) { mpz_clear(px[i]); mpz_clear(py[i]); } Safefree(px); Safefree(py); return retval; }