Example #1
0
/* 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) {
Example #2
0
/* 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) {