void prime_iterator_setprime(prime_iterator *iter, UV n) {
  /* Is it inside the current segment? */
  if (    (iter->segment_mem != 0)
       && (n >= iter->segment_start)
       && (n <= iter->segment_start + 30*iter->segment_bytes - 1) ) {
    iter->p = n;
    return;
  }
  prime_iterator_destroy(iter);
  /* Is it inside the primary cache range? */
  if (n <= primary_limit) {
    iter->p = n;
    return;
  }
  /* Sieve this range */
  {
    UV lod, hid;
    lod = n/30;
    hid = lod + SEGMENT_SIZE;
    New(0, iter->segment_mem, SEGMENT_SIZE, unsigned char );
    iter->segment_start = lod * 30;
    iter->segment_bytes = SEGMENT_SIZE;
    if (!sieve_segment((unsigned char*)iter->segment_mem, lod, hid, primary_sieve, primary_limit))
      croak("Could not segment sieve");
    iter->p = n;
  }
}
Пример #2
0
/*========================================================================
   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 );
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}