Beispiel #1
0
/**
 *  Stein's binary greatest common divisor algorithm
 */
void cpt_bin_gcd(mpz_t res, mpz_srcptr a, mpz_srcptr b)
{
	mpz_t x,y,p,r;
	mpz_init(x);
	mpz_init(y);
	mpz_init(r);
	mpz_abs(x,a);
	mpz_abs(y,b);
	if(mpz_cmp_si(x,0) == 0)
	{
		mpz_set(res,y);
		mpz_clear(x);
		mpz_clear(y);
		mpz_clear(r);
		return;
	}
	if(mpz_cmp_si(y,0) == 0)
	{
		mpz_set(res,x);
		mpz_clear(x);
		mpz_clear(y);
		mpz_clear(r);
		return;
	}
	mpz_init_set_si(p,1);
	while(mpz_even_p(x) && mpz_even_p(y))
	{
		mpz_divexact_ui(x,x,2);
		mpz_divexact_ui(y,y,2);
		mpz_mul_ui(p,p,2);
	}
	while(mpz_even_p(x))
		mpz_divexact_ui(x,x,2);
	while(mpz_even_p(y))
		mpz_divexact_ui(y,y,2);
	if(mpz_cmp(x,y) > 0)
		mpz_swap(x,y);
	while(mpz_cmp_si(x,0) > 0)
	{
		mpz_sub(r,y,x);
		while(mpz_cmp_si(r,0) && mpz_even_p(r))
			mpz_divexact_ui(r,r,2);
		if(mpz_cmp(r,x) >= 0)
			mpz_set(y,r);
		else
		{
			mpz_set(y,x);
			mpz_set(x,r);
		}
	}
	mpz_mul(res,p,y);
	mpz_clear(x);
	mpz_clear(y);
	mpz_clear(p);
	mpz_clear(r);
}
Beispiel #2
0
silvia_priv_key::silvia_priv_key(mpz_class p, mpz_class q)
{
	this->p = p;
	this->q = q;

	// Compute p' and q'
	p_prime = p - 1;
	mpz_divexact_ui(p_prime.get_mpz_t(), p_prime.get_mpz_t(), 2);

	q_prime = q - 1;
	mpz_divexact_ui(q_prime.get_mpz_t(), q_prime.get_mpz_t(), 2);
	
	// Compute n'
	n_prime = p_prime * q_prime;
}
static int div_2(void *a, void *b)
{
   LTC_ARGCHK(a != NULL);
   LTC_ARGCHK(b != NULL);
   mpz_divexact_ui(b, a, 2);
   return CRYPT_OK;
}
Beispiel #4
0
/* *************************************************************************
 * mpz_euler_prp: (also called a Solovay-Strassen pseudoprime)
 * An "Euler pseudoprime" to the base a is an odd composite number n with,
 * (a,n)=1 such that a^((n-1)/2)=(a/n) mod n [(a/n) is the Jacobi symbol]
 * *************************************************************************/
int mpz_euler_prp(mpz_t n, mpz_t a)
{
  mpz_t res;
  mpz_t exp;
  int ret = 0;

  if (mpz_cmp_ui(a, 2) < 0)
    return PRP_ERROR;

  if (mpz_cmp_ui(n, 2) < 0)
    return PRP_COMPOSITE;

  if (mpz_divisible_ui_p(n, 2))
  {
    if (mpz_cmp_ui(n, 2) == 0)
      return PRP_PRIME;
    else
      return PRP_COMPOSITE;
  }

  mpz_init_set_ui(res, 0);
  mpz_gcd(res, n, a);

  if (mpz_cmp_ui(res, 1) > 0)
  {
    mpz_clear(res);
    return PRP_COMPOSITE;
  }

  mpz_init_set(exp, n);

  mpz_sub_ui(exp, exp, 1); /* exp = n-1 */
  mpz_divexact_ui(exp, exp, 2); /* exp = (n-1)/2 */
  mpz_powm(res, a, exp, n);

  /* reuse exp to calculate jacobi(a,n) mod n */
  ret = mpz_jacobi(a,n);
  mpz_set(exp, n);
  if (ret == -1)
    mpz_sub_ui(exp, exp, 1);
  else if (ret == 1)
    mpz_add_ui(exp, exp, 1);
  mpz_mod(exp, exp, n);

  if (mpz_cmp(res, exp) == 0)
  {
    mpz_clear(res);
    mpz_clear(exp);
    return PRP_PRP;
  }
  else
  {
    mpz_clear(res);
    mpz_clear(exp);
    return PRP_COMPOSITE;
  }

}/* method mpz_euler_prp */
Beispiel #5
0
int jacobi(mpz_t aa, mpz_t nn) // Generalization of Legendre's symbol.
{
	mpz_t a, n, n2;
	mpz_init_set(a, aa);
	mpz_init_set(n, nn);
	mpz_init(n2);

	if (mpz_divisible_p(a, n))
		return 0; // (0/n) = 0

	int ans = 1;
	if (mpz_cmp_ui(a, 0) < 0) {
		mpz_neg(a, a); // (a/n) = (-a/n)*(-1/n)
		if (mpz_congruent_ui_p(n, 3, 4)) // if n%4 == 3
			ans = -ans; // (-1/n) = -1 if n = 3 (mod 4)
	}

	if (mpz_cmp_ui(a, 1) == 0) {
		mpz_clear(a);
		mpz_clear(n);
		mpz_clear(n2);

		return ans; // (1/n) = 1
	}

	while (mpz_cmp_ui(a, 0) != 0) {
		if (mpz_cmp_ui(a, 0) < 0) {
			mpz_neg(a, a); // (a/n) = (-a/n)*(-1/n)
			if (mpz_congruent_ui_p(n, 3, 4)) // if n%4 == 3
				ans = -ans; // (-1/n) = -1 if n = 3 ( mod 4 )
		}

		while (mpz_divisible_ui_p(a, 2)) {
			mpz_divexact_ui(a, a, 2); // a = a/2
			if (mpz_congruent_ui_p(n, 3, 8) || mpz_congruent_ui_p(n, 5, 8)) // n%8==3 || n%8==5
				ans = -ans;
		}

		mpz_swap(a, n); // (a,n) = (n,a)
		if (mpz_congruent_ui_p(a, 3, 4) && mpz_congruent_ui_p(n, 3, 4)) // a%4==3 && n%4==3
			ans = -ans;

		mpz_mod(a, a, n); // because (a/p) = (a%p / p ) and a%pi = (a%n)%pi if n % pi = 0
		mpz_cdiv_q_ui(n2, n, 2);
		if (mpz_cmp(a, n2) > 0) // a > n/2
			mpz_sub(a, a, n); // a = a-n
	}

	int cmp = mpz_cmp_ui(n, 1);
	mpz_clear(a);
	mpz_clear(n);
	mpz_clear(n2);

	if (cmp == 0)
		return ans;
	return 0;
}
Beispiel #6
0
int solovay_strassen(mpz_t n, int k)
{
	int i;
	for (i = 0; i < primes_count && mpz_cmp_si(n, primes[i]*primes[i]) >= 0; i++)
		if (mpz_divisible_ui_p(n, primes[i])) // Check if current prime divides n
			return 0;

	if (mpz_cmp_si(n, 2) < 0)
		return 0;
	if (mpz_cmp_si(n, 2) == 0)
		return 1;
	if (mpz_divisible_ui_p(n, 2))
		return 0;

	gmp_randstate_t RAND;
	gmp_randinit_default(RAND);

	mpz_t a, jac, mod, exp, n1;
	mpz_init(a);
	mpz_init(jac);
	mpz_init(mod);
	mpz_init(exp);
	mpz_init(n1);
	mpz_sub_ui(n1, n, 1);
	while (k > 0) {
		k--;
		mpz_urandomm(a, RAND, n1);
		mpz_add_ui(a, a, 1);

		int j = jacobi(a, n);
		if (j == -1) { // jac = n + jac(a,n)
			mpz_sub_ui(jac, n, 1);
		} else if (j == 1)
			mpz_set_si(jac, j);

		mpz_divexact_ui(exp, n1, 2); // exp = (n-1)/2
		mpz_powm(mod, a, exp, n); // mod = a^((n-1)/2) % n
		if (mpz_cmp_ui(jac, 0) == 0 || mpz_cmp(mod, jac) != 0) { // Is it a liar?
			mpz_clear(a);
			mpz_clear(jac);
			mpz_clear(mod);
			mpz_clear(exp);
			mpz_clear(n1);

			return 0;
		}
	}

	mpz_clear(a);
	mpz_clear(jac);
	mpz_clear(mod);
	mpz_clear(exp);
	mpz_clear(n1);

	return 1;
}
Beispiel #7
0
void
fmpz_divexact(fmpz_t f, const fmpz_t g, const fmpz_t h)
{
    fmpz c1 = *g;
    fmpz c2 = *h;

    if (fmpz_is_zero(h))
    {
        printf("Exception: division by zero in fmpz_divexact\n");
        abort();
    }

    if (!COEFF_IS_MPZ(c1))  /* g is small, h must be also or division isn't exact */
    {
        fmpz_set_si(f, c1 / c2);
    }
    else  /* g is large */
    {
        __mpz_struct * mpz_ptr = _fmpz_promote(f);

        if (!COEFF_IS_MPZ(c2))  /* h is small */
        {
            if (c2 > 0)  /* h > 0 */
            {
                mpz_divexact_ui(mpz_ptr, COEFF_TO_PTR(c1), c2);
                _fmpz_demote_val(f);  /* division by h may result in small value */
            }
            else
            {
                mpz_divexact_ui(mpz_ptr, COEFF_TO_PTR(c1), -c2);
                _fmpz_demote_val(f);  /* division by h may result in small value */

                fmpz_neg(f, f);
            }
        }
        else  /* both are large */
        {
            mpz_divexact(mpz_ptr, COEFF_TO_PTR(c1), COEFF_TO_PTR(c2));
            _fmpz_demote_val(f);  /* division by h may result in small value */
        }
    }
}
Beispiel #8
0
/**
 * Let D(x) be the divisor count of x.
 * D(t) = D(n/2))*D(n+1) if n is even.
 * D(t) = D(n)*D( (n+1)/2 ) if n odd.
 * where t is the n'th triangular number.
 */
int count_divisors_of_triangular_num(const mpz_t nth) {
	int count;
	mpz_t n1, n2;
	mpz_init(n1);
	mpz_init(n2);

	if(mpz_even_p(nth)){
		mpz_divexact_ui(n1,nth,2);
		mpz_add_ui(n2,nth,1);

	} else {
		mpz_set(n1,nth);
		mpz_add_ui(n2,nth,1);
		mpz_divexact_ui(n2,n2,2);
	}

	count = mpz_count_divisors(n1) * mpz_count_divisors(n2);
	mpz_clear(n1);
	mpz_clear(n2);
	return count;
}
Beispiel #9
0
void init_ecpp_gcds(void) {
  if (_gcdinit == 0) {
    mpz_init(_gcd_small);
    mpz_init(_gcd_large);
    _GMP_pn_primorial(_gcd_small,  3000);
    _GMP_pn_primorial(_gcd_large, 20000);
    mpz_divexact(_gcd_large, _gcd_large, _gcd_small);
    mpz_divexact_ui(_gcd_small, _gcd_small, 2*3*5);
    mpz_init(_lcm_small);
    _GMP_lcm_of_consecutive_integers(300, _lcm_small);
    _gcdinit = 1;
  }
}
Beispiel #10
0
void tiny_compute_C(QS_t * qs_inf, poly_t * poly_inf)
{
   unsigned long A = poly_inf->A;
   unsigned long B = poly_inf->B;
   mpz_t * C = &poly_inf->C;
   mpz_t * mpz_n = &qs_inf->mpz_n;
   
   if ((long) B < 0L) B = -B;
   mpz_set_ui(*C, B);
   mpz_mul_ui(*C, *C, B);
   mpz_sub(*C, *C, *mpz_n);
   mpz_divexact_ui(*C, *C, A);
} 
Beispiel #11
0
Datei: pp.c Projekt: hvds/seq
void new_pp(pp_pp* pp, int prime, int power) {
	int i, set;
	mpz_t reduced_denom;
	mpx_support* xsup;

	if (prime > MAX_P) {
		fprintf(stderr, "prime %d exceeds max %d\n", prime, MAX_P);
		exit(1);
	}
	pp->p = prime;
	pp->pp = power;
	if (pp->p == pp->pp)
		inverse_table(pp->p);
	pp_pushlist(pp);
	ZINIT(&pp->total, "pp_%d.total", pp->pp);
	ZINIT(&pp->denominator, "pp_%d.denominator", pp->pp);
	ZINIT(&pp->min_discard, "pp_%d.min_discard", pp->pp);
	QINIT(&pp->spare, "pp_%d.spare", pp->pp);

	/* required denominator is the lcm of (power, S) where S contains those
	 * pp such that pp * power <= k.
	 */
	ZINIT(&reduced_denom, "new_pp reduced_denom");
	set = 0;
	/* start from pplist[1], because we've already been inserted at [0] */
	for (i = 1; i < pplistsize; ++i) {
		if (pplist[i]->pp * power <= k0) {
			mpz_mul_ui(pp->denominator, pplist[i]->denominator,
					power / mpz_gcd_ui(NULL, pplist[i]->denominator, power));
			set = 1;
			break;
		}
	}
	if (!set) {
		/* power == 1 */
		if (power != 1) {
			fprintf(stderr, "new_pp: did not find denominator for %d\n", power);
			exit(1);
		}
		mpz_set_ui(pp->denominator, 1);
	}
	mpz_divexact_ui(reduced_denom, pp->denominator, power);
	pp->invdenom = invfast(mod_ui(reduced_denom, pp->p), pp->p);
	ZCLEAR(&reduced_denom, "new_pp reduced_denom");

	xsup = mpx_support_z(pp->denominator);
	pp->valnumsize = xsup->size;
	pp->adder = xsup->adder;
	pp->cmper = xsup->cmper;
	pp_grow(pp, MINPPSET);
}
Beispiel #12
0
/*------------------------------------------------------------------------*/
static void
init_ad_sieve(sieve_t *sieve, poly_search_t *poly)
{
	uint32 i, j, p;

	sieve->num_primes = 0;
	sieve->num_primes_alloc = 100;
	sieve->primes = (sieve_prime_t *)xmalloc(sizeof(sieve_prime_t) *
						sieve->num_primes_alloc);
	sieve->sieve_array = (uint8 *)xmalloc(sizeof(uint8) *
						SIEVE_ARRAY_SIZE);

	mpz_divexact_ui(poly->tmp1, poly->gmp_high_coeff_begin,
			(mp_limb_t)HIGH_COEFF_MULTIPLIER);
	for (i = p = 0; i < PRECOMPUTED_NUM_PRIMES; i++) {
		uint32 power;
		uint8 log_val;

		p += prime_delta[i];
		if (p > HIGH_COEFF_PRIME_LIMIT)
			break;

		log_val = floor(log(p) / M_LN2 + 0.5);
		power = p;
		for (j = 0; j < HIGH_COEFF_POWER_LIMIT; j++) {
			uint32 r = mpz_cdiv_ui(poly->tmp1, (mp_limb_t)power);

			if (sieve->num_primes >= sieve->num_primes_alloc) {
				sieve->num_primes_alloc *= 2;
				sieve->primes = (sieve_prime_t *)xrealloc(
					sieve->primes,
					sieve->num_primes_alloc *
						sizeof(sieve_prime_t));
			}

			sieve->primes[sieve->num_primes].p = power;
			sieve->primes[sieve->num_primes].r = r;
			sieve->primes[sieve->num_primes].log_val = log_val;
			sieve->num_primes++;

			if ((uint32)(-1) / power < p)
				break;

			power *= p;
		}
	}

	sieve->curr_offset = 0;
	sieve_ad_block(sieve, poly);
}
Beispiel #13
0
void init_ecpp_gcds(UV nsize) {
  if (_gcdinit == 0) {
    mpz_init(_gcd_small);
    mpz_init(_gcd_large);
    _GMP_pn_primorial(_gcd_small,  3000);
    /* This is never re-adjusted -- first number proved sets the size */
    nsize *= 20;
    if      (nsize < 20000) nsize = 20000;
    else if (nsize > 500000) nsize = 500000;
    _GMP_pn_primorial(_gcd_large, nsize);
    mpz_divexact(_gcd_large, _gcd_large, _gcd_small);
    mpz_divexact_ui(_gcd_small, _gcd_small, 2*3*5);
    _gcdinit = 1;
  }
}
void
check_random (int argc, char *argv[])
{
  gmp_randstate_ptr rands = RANDS;
  int    reps = 5000;
  mpz_t  a, q, got;
  int    i, qneg;
  unsigned long  d;

  if (argc == 2)
    reps = atoi (argv[1]);

  mpz_init (a);
  mpz_init (q);
  mpz_init (got);

  for (i = 0; i < reps; i++)
    {
      d = (unsigned long) urandom();
      mpz_erandomb (q, rands, 512);
      mpz_mul_ui (a, q, d);

      for (qneg = 0; qneg <= 1; qneg++)
        {
          mpz_divexact_ui (got, a, d);
          MPZ_CHECK_FORMAT (got);
          if (mpz_cmp (got, q) != 0)
            {
              printf    ("mpz_divexact_ui wrong\n");
              mpz_trace ("    a", a);
              printf    ("    d=%lu\n", d);
              mpz_trace ("    q", q);
              mpz_trace ("  got", got);
              abort ();
            }

          mpz_neg (q, q);
          mpz_neg (a, a);
        }

    }

  mpz_clear (a);
  mpz_clear (q);
  mpz_clear (got);
}
void init_data(SGLVData *op){
	//~ Note: 'op' is supposed to be already initialised (see main.c)
	mpz_t  X, Y, tmp_exp;
	mpz_inits (X, Y, tmp_exp, NULL);
	
	//~ p = 2^256-1539
	mpz_setbit (p, 256);
	mpz_sub_ui (p, p, 1539);
	//~ Curve is y^2 = x^3 + 5 
	//~ mpz_set_ui (ca, 0);  // Already set to ZERO through the initialisation
	mpz_set_ui (cb, 5);
	mpz_set_str (X, "66043340678279369258981193985450715448372246692524118399919799979198175326756", 10);
	mpz_set_str (Y, "52931614173969837860927627620185828149756459753631369661231760168280520196499", 10);
	//~ Point P
	mpz_set (op->PP[0].X , X);
	mpz_set (op->PP[0].Y , Y);
	//~ 5 is a generator of Fp and beta is an element of order 3
	mpz_set_ui (beta, 5);
	mpz_sub_ui (tmp_exp, p, 1); 
	mpz_divexact_ui (tmp_exp, tmp_exp, 3);
	mpz_powm (beta, beta, tmp_exp, p);
	
	//~ Order of P
	mpz_set_str (op->efp, "115792089237316195423570985008687907852920869663551026044856920202296625078603", 10);
	//~ Integer part of square root of efp
	mpz_set_str (op->refp, "340282366920938463463374607431768211455", 10);
	//~ Root of  phi^2+phi+1 = 0 mod #E(Fp)
	mpz_set_str (op->phi, "86115113571596370384202877098459685148505633832452548870570058599719872579953", 10);
	
	init_glvRData(op);
	 
	if (is_on_curve_aff(op->PP, ca, cb)) {
		printf("P OK\n");
		print_affPoint(op->PP);
	}
	else
		printf("P not OK\n");
	
	mpz_clears (X, Y, tmp_exp, NULL);
}
Beispiel #16
0
void burns::get(mpz_t X, const vector<uint64>& x) const
{
	mpz_t Mi;
	mpz_init(Mi);
	
	mpz_set_ui(X, 0);
	for(int i=0; i < size(); i++)
	{
		const monty& m = mb.field(i);
		
		// Mi = M / m_i
		mpz_divexact_ui(Mi, M, m.modulus());
		
		uint64 y = m.get(m.mul(x[i], mrc[i]));
		
		// X += Mi y
		mpz_addmul_ui(X, Mi, y);
	}
	mpz_clear(Mi);

	// Reduce mod M
	mpz_mod(X, X, M);
}
Beispiel #17
0
/* returns 0 on success		*/
int
gen_consts (int numb, int nail, int limb)
{
  mpz_t x, mask, y, last;
  unsigned long a, b;
  unsigned long ofl, ofe;

  printf ("/* This file is automatically generated by gen-fac.c */\n\n");
  printf ("#if GMP_NUMB_BITS != %d\n", numb);
  printf ("Error , error this data is for %d GMP_NUMB_BITS only\n", numb);
  printf ("#endif\n");
#if 0
  printf ("#if GMP_LIMB_BITS != %d\n", limb);
  printf ("Error , error this data is for %d GMP_LIMB_BITS only\n", limb);
  printf ("#endif\n");
#endif

  printf
    ("/* This table is 0!,1!,2!,3!,...,n! where n! has <= GMP_NUMB_BITS bits */\n");
  printf
    ("#define ONE_LIMB_FACTORIAL_TABLE CNST_LIMB(0x1),CNST_LIMB(0x1");
  mpz_init_set_ui (x, 1);
  mpz_init (last);
  for (b = 2;; b++)
    {
      mpz_mul_ui (x, x, b);	/* so b!=a       */
      if (mpz_sizeinbase (x, 2) > numb)
	break;
      printf ("),CNST_LIMB(0x");
      mpz_out_str (stdout, 16, x);
    }
  printf (")\n");

  printf
    ("\n/* This table is 0!,1!,2!/2,3!/2,...,n!/2^sn where n!/2^sn is an */\n");
  printf
    ("/* odd integer for each n, and n!/2^sn has <= GMP_NUMB_BITS bits */\n");
  printf
    ("#define ONE_LIMB_ODD_FACTORIAL_TABLE CNST_LIMB(0x1),CNST_LIMB(0x1),CNST_LIMB(0x1");
  mpz_set_ui (x, 1);
  for (b = 3;; b++)
    {
      for (a = b; (a & 1) == 0; a >>= 1);
      mpz_swap (last, x);
      mpz_mul_ui (x, last, a);
      if (mpz_sizeinbase (x, 2) > numb)
	break;
      printf ("),CNST_LIMB(0x");
      mpz_out_str (stdout, 16, x);
    }
  printf (")\n");
  printf
    ("#define ODD_FACTORIAL_TABLE_MAX CNST_LIMB(0x");
  mpz_out_str (stdout, 16, last);
  printf (")\n");

  ofl = b - 1;
  printf
    ("#define ODD_FACTORIAL_TABLE_LIMIT (%lu)\n", ofl);
  mpz_init2 (mask, numb + 1);
  mpz_setbit (mask, numb);
  mpz_sub_ui (mask, mask, 1);
  printf
    ("\n/* Previous table, continued, values modulo 2^GMP_NUMB_BITS */\n");
  printf
    ("#define ONE_LIMB_ODD_FACTORIAL_EXTTABLE CNST_LIMB(0x");
  mpz_and (x, x, mask);
  mpz_out_str (stdout, 16, x);
  mpz_init (y);
  mpz_bin_uiui (y, b, b/2);
  b++;
  for (;; b++)
    {
      for (a = b; (a & 1) == 0; a >>= 1);
      if (a == b) {
	mpz_divexact_ui (y, y, a/2+1);
	mpz_mul_ui (y, y, a);
      } else
	mpz_mul_2exp (y, y, 1);
      if (mpz_sizeinbase (y, 2) > numb)
	break;
      mpz_mul_ui (x, x, a);
      mpz_and (x, x, mask);
      printf ("),CNST_LIMB(0x");
      mpz_out_str (stdout, 16, x);
    }
  printf (")\n");
  ofe = b - 1;
  printf
    ("#define ODD_FACTORIAL_EXTTABLE_LIMIT (%lu)\n", ofe);

  printf
    ("\n/* This table is 1!!,3!!,...,(2n+1)!! where (2n+1)!! has <= GMP_NUMB_BITS bits */\n");
  printf
    ("#define ONE_LIMB_ODD_DOUBLEFACTORIAL_TABLE CNST_LIMB(0x1");
  mpz_set_ui (x, 1);
  for (b = 3;; b+=2)
    {
      mpz_swap (last, x);
      mpz_mul_ui (x, last, b);
      if (mpz_sizeinbase (x, 2) > numb)
	break;
      printf ("),CNST_LIMB(0x");
      mpz_out_str (stdout, 16, x);
    }
  printf (")\n");
  printf
    ("#define ODD_DOUBLEFACTORIAL_TABLE_MAX CNST_LIMB(0x");
  mpz_out_str (stdout, 16, last);
  printf (")\n");

  printf
    ("#define ODD_DOUBLEFACTORIAL_TABLE_LIMIT (%lu)\n", b - 2);

  printf
    ("\n/* This table x_1, x_2,... contains values s.t. x_n^n has <= GMP_NUMB_BITS bits */\n");
  printf
    ("#define NTH_ROOT_NUMB_MASK_TABLE (GMP_NUMB_MASK");
  for (b = 2;b <= 8; b++)
    {
      mpz_root (x, mask, b);
      printf ("),CNST_LIMB(0x");
      mpz_out_str (stdout, 16, x);
    }
  printf (")\n");

  mpz_add_ui (mask, mask, 1);
  printf
    ("\n/* This table contains inverses of odd factorials, modulo 2^GMP_NUMB_BITS */\n");
  printf
    ("\n/* It begins with (2!/2)^-1=1 */\n");
  printf
    ("#define ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE CNST_LIMB(0x1");
  mpz_set_ui (x, 1);
  for (b = 3;b <= ofe - 2; b++)
    {
      for (a = b; (a & 1) == 0; a >>= 1);
      mpz_mul_ui (x, x, a);
      mpz_invert (y, x, mask);
      printf ("),CNST_LIMB(0x");
      mpz_out_str (stdout, 16, y);
    }
  printf (")\n");

  ofe = (ofe / 16 + 1) * 16;

  printf
    ("\n/* This table contains 2n-popc(2n) for small n */\n");
  printf
    ("\n/* It begins with 2-1=1 (n=1) */\n");
  printf
    ("#define TABLE_2N_MINUS_POPC_2N 1");
  for (b = 4; b <= ofe; b += 2)
    {
      mpz_set_ui (x, b);
      printf (",%lu",b - mpz_popcount (x));
    }
  printf ("\n");
  printf
    ("#define TABLE_LIMIT_2N_MINUS_POPC_2N %lu\n", ofe + 1);


  ofl = (ofl + 1) / 2;
  printf
    ("#define ODD_CENTRAL_BINOMIAL_OFFSET (%lu)\n", ofl);
  printf
    ("\n/* This table contains binomial(2k,k)/2^t */\n");
  printf
    ("\n/* It begins with ODD_CENTRAL_BINOMIAL_TABLE_MIN */\n");
  printf
    ("#define ONE_LIMB_ODD_CENTRAL_BINOMIAL_TABLE ");
  for (b = ofl;; b++)
    {
      mpz_bin_uiui (x, 2 * b, b);
      mpz_remove_twos (x);
      if (mpz_sizeinbase (x, 2) > numb)
	break;
      if (b != ofl)
	printf ("),");
      printf("CNST_LIMB(0x");
      mpz_out_str (stdout, 16, x);
    }
  printf (")\n");

  ofe = b - 1;
  printf
    ("#define ODD_CENTRAL_BINOMIAL_TABLE_LIMIT (%lu)\n", ofe);

  printf
    ("\n/* This table contains the inverses of elements in the previous table. */\n");
  printf
    ("#define ONE_LIMB_ODD_CENTRAL_BINOMIAL_INVERSE_TABLE CNST_LIMB(0x");
  for (b = ofl; b <= ofe; b++)
    {
      mpz_bin_uiui (x, 2 * b, b);
      mpz_remove_twos (x);
      mpz_invert (x, x, mask);
      mpz_out_str (stdout, 16, x);
      if (b != ofe)
	printf ("),CNST_LIMB(0x");
    }
  printf (")\n");

  printf
    ("\n/* This table contains the values t in the formula binomial(2k,k)/2^t */\n");
  printf
    ("#define CENTRAL_BINOMIAL_2FAC_TABLE ");
  for (b = ofl; b <= ofe; b++)
    {
      mpz_bin_uiui (x, 2 * b, b);
      printf ("%d", mpz_remove_twos (x));
      if (b != ofe)
	printf (",");
    }
  printf ("\n");

  return 0;
}
/*
   Add two ECC points
   @param P        The point to add
   @param Q        The point to add
   @param R        [out] The destination of the double
   @param a        Curve's a value
   @param modulus  The modulus of the field the ECC curve is in
   @return 0 on success
*/
int
ecc_projective_add_point (ecc_point * P, ecc_point * Q, ecc_point * R,
                              mpz_t a, mpz_t modulus)
{
  mpz_t t1, t2, x, y, z;
  int err;

  if (P == NULL || Q == NULL || R == NULL || modulus == NULL)
    return -1;

  if ((err = mp_init_multi (&t1, &t2, &x, &y, &z, NULL)) != 0)
    {
      return err;
    }

  /* Check if P == Q and do doubling in that case 
   * If Q == -P then P+Q=point at infinity
   */
  if ((mpz_cmp (P->x, Q->x) == 0) &&
      (mpz_cmp (P->z, Q->z) == 0))
    {
      /* x and z coordinates match. Check if P->y = Q->y, or P->y = -Q->y
       */
      if (mpz_cmp (P->y, Q->y) == 0)
        {
          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
          return ecc_projective_dbl_point (P, R, a, modulus);
        }
      
      mpz_sub (t1, modulus, Q->y);
      if (mpz_cmp (P->y, t1) == 0)
        {
          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
          mpz_set_ui(R->x, 1);
          mpz_set_ui(R->y, 1);
          mpz_set_ui(R->z, 0);
          return 0;
        }
    }


  mpz_set (x, P->x);
  mpz_set (y, P->y);
  mpz_set (z, P->z);

  /* if Z is one then these are no-operations */
  if (mpz_cmp_ui (Q->z, 1) != 0)
    {
      /* T1 = Z' * Z' */
      mpz_mul (t1, Q->z, Q->z);
      mpz_mod (t1, t1, modulus);
      /* X = X * T1 */
      mpz_mul (x, x, t1);
      mpz_mod (x, x, modulus);
      /* T1 = Z' * T1 */
      mpz_mul (t1, t1, Q->z);
      mpz_mod (t1, t1, modulus);
      /* Y = Y * T1 */
      mpz_mul (y, y, t1);
      mpz_mod (y, y, modulus);
    }

  /* T1 = Z*Z */
  mpz_mul (t1, z, z);
  mpz_mod (t1, t1, modulus);
  /* T2 = X' * T1 */
  mpz_mul (t2, t1, Q->x);
  mpz_mod (t2, t2, modulus);
  /* T1 = Z * T1 */
  mpz_mul (t1, t1, z);
  mpz_mod (t1, t1, modulus);
  /* T1 = Y' * T1 */
  mpz_mul (t1, t1, Q->y);
  mpz_mod (t1, t1, modulus);

  /* Y = Y - T1 */
  mpz_sub (y, y, t1);
  if (mpz_cmp_ui (y, 0) < 0)
    {
      mpz_add (y, y, modulus);
    }
  /* T1 = 2T1 */
  mpz_add (t1, t1, t1);
  if (mpz_cmp (t1, modulus) >= 0)
    {
      mpz_sub (t1, t1, modulus);
    }
  /* T1 = Y + T1 */
  mpz_add (t1, t1, y);
  if (mpz_cmp (t1, modulus) >= 0)
    {
      mpz_sub (t1, t1, modulus);
    }
  /* X = X - T2 */
  mpz_sub (x, x, t2);
  if (mpz_cmp_ui (x, 0) < 0)
    {
      mpz_add (x, x, modulus);
    }
  /* T2 = 2T2 */
  mpz_add (t2, t2, t2);
  if (mpz_cmp (t2, modulus) >= 0)
    {
      mpz_sub (t2, t2, modulus);
    }
  /* T2 = X + T2 */
  mpz_add (t2, t2, x);
  if (mpz_cmp (t2, modulus) >= 0)
    {
      mpz_sub (t2, t2, modulus);
    }

  /* if Z' != 1 */
  if (mpz_cmp_ui (Q->z, 1) != 0)
    {
      /* Z = Z * Z' */
      mpz_mul (z, z, Q->z);
      mpz_mod (z, z, modulus);
    }

  /* Z = Z * X */
  mpz_mul (z, z, x);
  mpz_mod (z, z, modulus);

  /* T1 = T1 * X  */
  mpz_mul (t1, t1, x);
  mpz_mod (t1, t1, modulus);
  /* X = X * X */
  mpz_mul (x, x, x);
  mpz_mod (x, x, modulus);
  /* T2 = T2 * x */
  mpz_mul (t2, t2, x);
  mpz_mod (t2, t2, modulus);
  /* T1 = T1 * X  */
  mpz_mul (t1, t1, x);
  mpz_mod (t1, t1, modulus);

  /* X = Y*Y */
  mpz_mul (x, y, y);
  mpz_mod (x, x, modulus);
  /* X = X - T2 */
  mpz_sub (x, x, t2);
  if (mpz_cmp_ui (x, 0) < 0)
    {
      mpz_add (x, x, modulus);
    }

  /* T2 = T2 - X */
  mpz_sub (t2, t2, x);
  if (mpz_cmp_ui (t2, 0) < 0)
    {
      mpz_add (t2, t2, modulus);
    }
  /* T2 = T2 - X */
  mpz_sub (t2, t2, x);
  if (mpz_cmp_ui (t2, 0) < 0)
    {
      mpz_add (t2, t2, modulus);
    }
  /* T2 = T2 * Y */
  mpz_mul (t2, t2, y);
  mpz_mod (t2, t2, modulus);
  /* Y = T2 - T1 */
  mpz_sub (y, t2, t1);
  if (mpz_cmp_ui (y, 0) < 0)
    {
      mpz_add (y, y, modulus);
    }
  /* Y = Y/2 */
  if (mpz_odd_p (y))
    {
      mpz_add (y, y, modulus);
    }
  mpz_divexact_ui (y, y, 2);

  mpz_set (R->x, x);
  mpz_set (R->y, y);
  mpz_set (R->z, z);

  err = 0;

  mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
  return err;
}
/*
 * isprime : is this number prime ?
 * this use the Miller-Rabin method. The algorithm can be found at Wikipedia
 * return 1 (yes) and 0 (no)
 */
int
isprime(mpz_t p)
{
    gmp_randstate_t st;         /* random init stat */
    mpz_t           a,
                    d,
                    tmp,
                    x;
    int             i,
                    ret,
                    j;
    unsigned long   s;

    ret = 1;

    /*
     * ensure that p is odd and greater than 3 
     */
    if (mpz_cmp_ui(p, 3) <= 0 || !mpz_tstbit(p, 0))
        return 0;

    /*
     * put p in the 2^s.d form
     */
    mpz_init(d);
    mpz_sub_ui(d, p, 1);        /* d = p-1 */
    s = 0;

    do {
        s++;
        mpz_divexact_ui(d, d, 2);
    } while (mpz_divisible_ui_p(d, 2));
    /*
     * now we have p as 2^s.d
     */

    gmp_randinit_default(st);
    gmp_randseed_ui(st, time(NULL));
    mpz_init(a);
    mpz_init(x);
    mpz_init(tmp);
    mpz_sub_ui(tmp, p, 1);      /* tmp = p - 1 */

    for (i = 0; i < ACCURACY; i++) {
        /*
         * generate a as 2 <= a <= n-2 
         */
        do {
            mpz_urandomm(a, st, tmp);   /* a will be between 0 and * tmp-1 
                                         * inclusive */
        } while (mpz_cmp_ui(a, 2) < 0);

        mpz_powm(x, a, d, p);   /* do x = a^d mod p */

        /*
         * if x == 1 or x == p-1 
         */
        if (!mpz_cmp_ui(x, 1) || !mpz_cmp(x, tmp))
            continue;

        for (j = 1; j < s; j++) {
            mpz_powm_ui(x, x, 2, p);    /* do x = x^2 mod p */
            if (!mpz_cmp_ui(x, 1)
                || !mpz_cmp(x, tmp))    /* x == 1 */
                break;
        }

        if (mpz_cmp(x, tmp) || !mpz_cmp_ui(x, 1)) {     /* x != p-1 */
            ret = 0;
            break;
        }
    }

    /*
     * Free Ressources
     */
    gmp_randclear(st);
    mpz_clear(a);
    mpz_clear(d);
    mpz_clear(tmp);

    return ret;
}
Beispiel #20
0
static PyObject *
GMPY_mpz_is_euler_prp(PyObject *self, PyObject *args)
{
    MPZ_Object *a, *n;
    PyObject *result = 0;
    mpz_t res, exp;
    int ret;

    if (PyTuple_Size(args) != 2) {
        TYPE_ERROR("is_euler_prp() requires 2 integer arguments");
        return NULL;
    }

    n = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL);
    a = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL);
    if (!a || !n) {
        TYPE_ERROR("is_euler_prp() requires 2 integer arguments");
        goto cleanup;
    }

    mpz_init(res);
    mpz_init(exp);

    /* Require a >= 2. */
    if (mpz_cmp_ui(a->z, 2) < 0) {
        VALUE_ERROR("is_euler_prp() requires 'a' greater than or equal to 2");
        goto cleanup;
    }

    /* Require n > 0. */
    if (mpz_sgn(n->z) <= 0) {
        VALUE_ERROR("is_euler_prp() requires 'n' be greater than 0");
        goto cleanup;
    }

    /* Check for n == 1 */
    if (mpz_cmp_ui(n->z, 1) == 0) {
        result = Py_False;
        goto cleanup;
    }

    /* Handle n even. */
    if (mpz_divisible_ui_p(n->z, 2)) {
        if (mpz_cmp_ui(n->z, 2) == 0)
            result = Py_True;
        else
            result = Py_False;
        goto cleanup;
    }

    /* Check gcd(a,b) */
    mpz_gcd(res, n->z, a->z);
    if (mpz_cmp_ui(res, 1) > 0) {
        VALUE_ERROR("is_euler_prp() requires gcd(n,a) == 1");
        goto cleanup;
    }

    mpz_set(exp, n->z);
    mpz_sub_ui(exp, exp, 1);
    mpz_divexact_ui(exp, exp, 2);
    mpz_powm(res, a->z, exp, n->z);

    /* reuse exp to calculate jacobi(a,n) mod n */
    ret = mpz_jacobi(a->z,n->z);
    mpz_set(exp, n->z);
    if (ret == -1)
        mpz_sub_ui(exp, exp, 1);
    else if (ret == 1)
        mpz_add_ui(exp, exp, 1);
    mpz_mod(exp, exp, n->z);

    if (mpz_cmp(res, exp) == 0)
        result = Py_True;
    else
        result = Py_False;

  cleanup:
    Py_XINCREF(result);
    mpz_clear(res);
    mpz_clear(exp);
    Py_XDECREF((PyObject*)a);
    Py_XDECREF((PyObject*)n);
    return result;
}
Beispiel #21
0
/* 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;
}
Beispiel #22
0
int
main(void)
{
    int i, result;
    flint_rand_t state;

    printf("divexact_ui....");
    fflush(stdout);

    flint_randinit(state);

    for (i = 0; i < 100000; i++)
    {
        fmpz_t a, c;
        mpz_t e, f, g;
        ulong n;

        fmpz_init(a);
        fmpz_init(c);
        mpz_init(e);
        mpz_init(f);
        mpz_init(g);

        fmpz_randtest(a, state, 200);
        n = n_randtest_not_zero(state);
        fmpz_mul_ui(c, a, n);

        fmpz_get_mpz(e, c);

        fmpz_divexact_ui(a, c, n);
        mpz_divexact_ui(f, e, n);

        fmpz_get_mpz(g, a);

        result = (mpz_cmp(f, g) == 0);
        if (!result)
        {
            printf("FAIL1\n");
            gmp_printf("n = %lu, e = %Zd, f = %Zd, g = %Zd\n", n, e, f, g);
            abort();
        }

        fmpz_clear(a);
        fmpz_clear(c);
        mpz_clear(e);
        mpz_clear(f);
        mpz_clear(g);
    }

    /* Test aliasing of a and c */
    for (i = 0; i < 100000; i++)
    {
        fmpz_t a, c;
        mpz_t d, f, g;
        ulong n;

        fmpz_init(a);
        fmpz_init(c);
        mpz_init(d);
        mpz_init(f);
        mpz_init(g);

        fmpz_randtest(a, state, 200);
        n = n_randtest_not_zero(state);
        fmpz_mul_ui(c, a, n);

        fmpz_get_mpz(d, c);

        fmpz_divexact_ui(c, c, n);
        mpz_divexact_ui(f, d, n);

        fmpz_get_mpz(g, c);

        result = (mpz_cmp(f, g) == 0);
        if (!result)
        {
            printf("FAIL:\n");
            gmp_printf("d = %Zd, n = %lu, f = %Zd, g = %Zd\n", d, n, f, g);
            abort();
        }

        fmpz_clear(a);
        fmpz_clear(c);
        mpz_clear(d);
        mpz_clear(f);
        mpz_clear(g);
    }

    flint_randclear(state);
    _fmpz_cleanup();
    printf("PASS\n");
    return 0;
}
// A quadratic sieve implementation for integers up to 100 bits. N must be composite.
mpz_class quadratic_sieve(mpz_class &N) {
	std::vector<uint32_t> factor_base;

	mpz_class sqrt_N = sqrt(N);
	//const unsigned long sqrt_N_long = sqrt_N.get_ui();

	// Set the smoothness bound.
	uint32_t B;
	{
		// Approximation of the natural logarithm of N.
		float log_N = mpz_sizeinbase(N.get_mpz_t(), 2) * log(2);

		// The optimal smoothness bound is exp((0.5 + o(1)) * sqrt(log(n)*log(log(n)))).
		B = (uint32_t)ceil(exp(0.56 * sqrt(log_N * log(log_N)))) + 300;
	}

	// Generate the factor base using a sieve.
	{
		char *sieve = new char[B + 1];
		memset(sieve, 1, B + 1);
		for(unsigned long p = 2; p <= B; ++p) {
			if(!sieve[p])
				continue;

			if(mpz_legendre(N.get_mpz_t(), mpz_class(p).get_mpz_t()) == 1)
				factor_base.push_back(p);

			for(unsigned long i = p; i <= B; i += p)
				sieve[i] = 0;
		}
		delete[] sieve;
	}

	std::vector<uint32_t> X;
	float *Y = new float[SIEVE_CHUNK];

	std::vector<std::vector<uint32_t> > smooth;

	int fails = 0;

	// The sieve boundary.
	uint32_t min_x = 0;
	uint32_t max_x = SIEVE_CHUNK;

	// Calculate sieve index (where to start the sieve) for each factor base number.
	uint32_t **fb_indexes = new uint32_t*[2];
	fb_indexes[0] = new uint32_t[factor_base.size()];
	fb_indexes[1] = new uint32_t[factor_base.size()];
	for(uint32_t p = 0; p < factor_base.size(); ++p) {
		// At what indexes do we start this sieve? Solve the congruence x^2 = n (mod p) to find out.
		// Results in two solutions, so we do two sieve iterations for each prime in the factor base.
		uint32_t idxs[2];
		mpz_class temp = N % mpz_class(factor_base[p]);
		tonelli_shanks(temp.get_ui(), factor_base[p], idxs);

		temp = idxs[0] - sqrt_N;
		temp = ((temp % factor_base[p]) + factor_base[p]) % factor_base[p];
		fb_indexes[0][p] = temp.get_ui();

		temp = idxs[1] - sqrt_N;
		temp = ((temp % factor_base[p]) + factor_base[p]) % factor_base[p];
		fb_indexes[1][p] = temp.get_ui();
	}

	float last_estimate = 0;
	uint32_t next_estimate = 1;

	// Sieve new chunks until we have enough smooth numbers.
	while(smooth.size() < (factor_base.size() + 20)) {
		// Generate our Y vector for the sieve, containing log approximations that fit in machine words.
		for(uint32_t t = 1; t < SIEVE_CHUNK; ++t) {
			// Calculating a log estimate is expensive, so don't do it for every Y[t].
			if(next_estimate <= (t + min_x)) {
				mpz_class y = (sqrt_N + t + min_x) * (sqrt_N + t + min_x) - N;

				// To estimate the 2 logarithm, just count the number of bits that v takes up.
				last_estimate = mpz_sizeinbase(y.get_mpz_t(), 2);

				// The higher t gets, the less the logarithm of Y[t] changes.
				next_estimate = next_estimate * 1.8 + 1;
			}

			Y[t] = last_estimate;
		}

		// Perform the actual sieve.
		for(uint32_t p = 0; p < factor_base.size(); ++p) {
			float lg = log(factor_base[p]) / log(2);

			for(uint32_t t = 0; t < 2; ++t) {
				while(fb_indexes[t][p] < max_x) {
					Y[fb_indexes[t][p] - min_x] -= lg;
					fb_indexes[t][p] += factor_base[p];
				}

				// p = 2 only has one modular root.
				if(factor_base[p] == 2)
					break;
			}
		}

		// Factor all values whose logarithms were reduced to approximately zero using trial division.
		{
			float threshold = log(factor_base.back()) / log(2);
			for(uint32_t i = 0; i < SIEVE_CHUNK; ++i) {
				if(fabs(Y[i]) < threshold) {
					mpz_class y = (sqrt_N + i + min_x) * (sqrt_N + i + min_x) - N;
					smooth.push_back(std::vector<uint32_t>());

					for(uint32_t p = 0; p < factor_base.size(); ++p) {
						while(mpz_divisible_ui_p(y.get_mpz_t(), factor_base[p])) {
							mpz_divexact_ui(y.get_mpz_t(), y.get_mpz_t(), factor_base[p]);
							smooth.back().push_back(p);
						}
					}

					if(y == 1) {
						// This V was indeed B-smooth.
						X.push_back(i + min_x);
						
						// Break out of trial division loop if we've found enou	gh smooth numbers.
						if(smooth.size() >= (factor_base.size() + 20))
							break;
					} else {
						// This V was apparently not B-smooth, remove it.
						smooth.pop_back();
						++fails;
					}
				}
			}
		}

		min_x += SIEVE_CHUNK;
		max_x += SIEVE_CHUNK;
	}

	uint64_t **matrix = new uint64_t*[factor_base.size()];

	// The amount of words needed to accomodate a row in the augmented matrix.
	int row_words = (smooth.size() + sizeof(uint64_t)) / sizeof(uint64_t);

	for(uint32_t i = 0; i < factor_base.size(); ++i) {
		matrix[i] = new uint64_t[row_words];
		memset(matrix[i], 0, row_words * sizeof(uint64_t));
	}

	for(uint32_t s = 0; s < smooth.size(); ++s) {
		// For each factor in the smooth number, add the factor to the corresponding element in the matrix.
		for(uint32_t p = 0; p < smooth[s].size(); ++p)
			toggle_bit(s, matrix[smooth[s][p]]);
	}

	// Gauss elimination. The dimension of the augmented matrix is factor_base.size() x (smooth.size() + 1).
	{
		uint32_t i = 0, j = 0;
		while(i < factor_base.size() && j < (smooth.size() + 1)) {
			uint32_t maxi = i;

			// Find pivot element.
			for(uint32_t k = i + 1; k < factor_base.size(); ++k) {
				if(get_bit(j, matrix[k]) == 1) {
					maxi = k;
					break;
				}
			}
			if(get_bit(j, matrix[maxi]) == 1) {
				std::swap(matrix[i], matrix[maxi]);
				
				for(uint32_t u = i + 1; u < factor_base.size(); ++u) {
					if(get_bit(j, matrix[u]) == 1) {
						for(int32_t w = 0; w < row_words; ++w)
							matrix[u][w] ^= matrix[i][w];
					}
				}
				++i;
			}
			++j;
		}
	}

	mpz_class a;
	mpz_class b;

	// A copy of matrix that we'll perform back-substitution on.
	uint64_t **back_matrix = new uint64_t*[factor_base.size()];
	for(uint32_t i = 0; i < factor_base.size(); ++i)
		back_matrix[i] = new uint64_t[row_words];

	uint32_t *x = new uint32_t[smooth.size()];

	uint32_t *combination = new uint32_t[factor_base.size()];

	// Loop until we've found a non-trivial factor.
	do {
		// Copy the gauss eliminated matrix.
		for(uint32_t i = 0; i < factor_base.size(); ++i)
			memcpy(back_matrix[i], matrix[i], row_words * sizeof(uint64_t));

		// Clear the x vector.
		memset(x, 0, smooth.size() * sizeof(uint32_t));

		// Perform back-substitution on our matrix that's now in row echelon form to get x.
		{
			int32_t i = factor_base.size() - 1;

			while(i >= 0) {
				// Count non-zero elements in current row.
				int32_t count = 0;
				int32_t current = -1;
				for(uint32_t c = 0; c < smooth.size(); ++c) {
					count += get_bit(c, back_matrix[i]);
					current = get_bit(c, back_matrix[i]) ? c : current;
				}

				// Empty row, advance to next.
				if(count == 0) {
					--i;
					continue;
				}

				// The system is underdetermined and we can choose x[current] freely.
				// To avoid the trivial solution we avoid always setting it to 0.
				uint32_t val = count > 1 ? rand() % 2 : get_bit(smooth.size(), back_matrix[i]);

				x[current] = val;

				for(int32_t u = 0; u <= i; ++u) {
					if(get_bit(current, back_matrix[u]) == 1) {
						if(val == 1)
							toggle_bit(smooth.size(), back_matrix[u]);
						unset_bit(current, back_matrix[u]);
					}
				}

				if(count == 1)
					--i;
			}
		}

		a = 1;
		b = 1;

		// The way to combine the factor base to get our square.
		memset(combination, 0, sizeof(uint32_t) * factor_base.size());
		for(uint32_t i = 0; i < smooth.size(); ++i) {
			if(x[i] == 1) {
				for(uint32_t p = 0; p < smooth[i].size(); ++p)
					++combination[smooth[i][p]];
				b *= (X[i] + sqrt_N);
			}
		}

		for(uint32_t p = 0; p < factor_base.size(); ++p) {
			for(uint32_t i = 0; i < (combination[p] / 2); ++i)
				a *= factor_base[p];
		}

		// If a = +/- b (mod N) we found a trivial factor, run the loop again to find a new a and b.
	} while(a % N == b % N || a % N == (- b) % N + N);

	b -= a;

	mpz_class factor;
	mpz_gcd(factor.get_mpz_t(), b.get_mpz_t(), N.get_mpz_t());

	for(uint32_t i = 0; i < factor_base.size(); ++i) {
		delete[] matrix[i];
		delete[] back_matrix[i];
	}

	delete[] combination;
	delete[] Y;
	delete[] fb_indexes[0];
	delete[] fb_indexes[1];
	delete[] fb_indexes;
	delete[] matrix;
	delete[] back_matrix;
	delete[] x;

	return factor;
}
Beispiel #24
0
/* p-adic logarithm */
void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) {
    /*  Compute the p-adic logarithm of a,
        which is supposed to be congruent to 1 mod p

        Algorithm:
         1. we raise a at the power p^(v-1) (for a suitable v) in order
            to make it closer to 1
         2. we write the new a as a product
              1/a = (1 - a_0*p^v) (1 - a_1*p^(2*v) (1 - a_2*p^(4*v) ...
            with 0 <= a_i < p^(v*2^i).
         3. we compute each log(1 - a_i*p^(v*2^i)) using Taylor expansion
            and a binary spliting strategy.                                */

    unsigned long i, v, e, N, saveN, Np, tmp, trunc, step;
    double den = log(p);
    mpz_t f, arg, trunc_mod, h, hpow, mpz_tmp, mpz_tmp2, d, inv, mod2;
    mpz_t *num, *denom;

    mpz_init(mpz_tmp);
    mpz_init(mpz_tmp2);
    mpz_init(arg);
    mpz_set_ui(ans, 0);

    mpz_fdiv_r_ui(mpz_tmp, a, p);
    mpz_set(arg, a);

    /* First we make the argument closer to 1 by raising it to the p^(v-1) */
    if (prec < p) {
        v = 0; e = 1;
    } else {
        v = (unsigned long)(log(prec)/den);  // v here is v-1
        e = pow(p,v);
        mpz_mul_ui(mpz_tmp, modulo, e);
        mpz_powm_ui(arg, arg, e, mpz_tmp);
        prec += v;
    }

    /* Where do we need to truncate the Taylor expansion */
    N = prec+v; N /= ++v;                 // note the ++v
    Np = N;
    den *= v;
    while(1) {
        tmp = Np + (unsigned long)(log(N)/den);
        if (tmp == N) break;
        N = tmp;
    }

    /* We allocate memory and initialize variables */
    mpz_init(f); mpz_init(mod2);
    mpz_init(h); mpz_init(hpow);
    mpz_init(d); mpz_init(inv);
    sig_block();
    num = (mpz_t*)malloc(N*sizeof(mpz_t));
    denom = (mpz_t*)malloc(N*sizeof(mpz_t));
    sig_unblock();
    for (i = 0; i < N; i++) {
        mpz_init(num[i]);
        mpz_init(denom[i]);
    }

    trunc = v << 1;
    mpz_init(trunc_mod);
    mpz_ui_pow_ui(trunc_mod, p, trunc);
    while(1) {
        /* We compute f = 1 - a_i*p^((v+1)*2^i)
           trunc_mod is p^((v+1)*2^(i+1)) */
        mpz_fdiv_r(f, arg, trunc_mod);

        if (mpz_cmp_ui(f, 1) != 0) {

            mpz_ui_sub(f, 2, f);
            mpz_mul(arg, arg, f);

            /* We compute the Taylor expansion of log(f)
               For now, computations are carried out over the rationals */
            for (i = 0; i < N; i++) {
                mpz_set_ui(num[i], 1);
                mpz_set_ui(denom[i], i+1);
            }
            step = 1;
            mpz_ui_sub(h, 1, f);   // we write f = 1 - h, i.e. h = a_i*p^(2^i)
            mpz_set(hpow, h);
            while(step < N) {
                for (i = 0; i < N - step; i += step << 1) {
                    mpz_mul(mpz_tmp2, hpow, num[i+step]);
                    mpz_mul(mpz_tmp, mpz_tmp2, denom[i]);
                    mpz_mul(num[i], num[i], denom[i+step]);
                    mpz_add(num[i], num[i], mpz_tmp);
                    mpz_mul(denom[i], denom[i], denom[i+step]);
                }
                step <<= 1;
                mpz_mul(hpow, hpow, hpow);
            }

            /* We simplify the fraction */
            Np = N; tmp = 0;
            while(Np > 0) { Np /= p; tmp += Np; }
            mpz_ui_pow_ui(d, p, tmp);
            mpz_divexact(mpz_tmp, num[0], d);
            mpz_divexact(denom[0], denom[0], d);

            mpz_divexact_ui(h, h, e);
            mpz_mul(mpz_tmp, h, mpz_tmp);

            /* We coerce the result from Q to Zp */
            mpz_gcdext(d, inv, NULL, denom[0], modulo);
            mpz_mul(mpz_tmp, mpz_tmp, inv);

            /* We add this contribution to log(f) */
            mpz_add(ans, ans, mpz_tmp);

        }

        if (trunc > prec) break;

        /* We update the variables for the next step */
        mpz_mul(trunc_mod, trunc_mod, trunc_mod);
        trunc <<= 1;
        for (i = N >> 1; i < N; i++) {
            mpz_clear(num[i]);
            mpz_clear(denom[i]);
        }
        N >>= 1;
    }

    mpz_fdiv_r(ans, ans, modulo);

    /* We clear memory */
    mpz_clear(arg);
    mpz_clear(f);
    mpz_clear(trunc_mod);
    mpz_clear(h);
    mpz_clear(hpow);
    mpz_clear(mpz_tmp);
    mpz_clear(d);
    mpz_clear(inv);
    mpz_clear(mod2);
    for (i = 0; i < N; i++) {
        mpz_clear(num[i]);
        mpz_clear(denom[i]);
    }
    sig_block();
    free(num);
    free(denom);
    sig_unblock();
}
Beispiel #25
0
unsigned int sieve(
	mpz_t n,
	unsigned int* factor_base,
	unsigned int base_dim,
	pair* solutions,
	unsigned int** exponents,
	mpz_t* As,
	unsigned int poly_val_num,
	unsigned int max_fact,
	unsigned int intervals
	) {

	unsigned int i;

	unsigned int** expo2;
	init_matrix(&expo2, intervals, base_dim);
	word** is_used_expo2;
	init_matrix_l(&is_used_expo2, 1, (intervals / N_BITS) + 1);
	for(i = 0; i < ((intervals / N_BITS) + 1); ++i) {
		set_matrix_l(is_used_expo2, 0, i, 0);
	}

	mpz_t n_root;
	mpz_t intermed;
	mpz_init(n_root);
	mpz_init(intermed);
	mpz_sqrt(n_root, n);

	unsigned char go_on = 1;

	unsigned int fact_count = 0;
	unsigned int j, k;
	mpz_t* evaluated_poly;

	init_vector_mpz(&evaluated_poly, poly_val_num);

	word** is_used;
	init_matrix_l(&is_used, 1, (poly_val_num / N_BITS) + 1);
	for(i = 0; i < ((poly_val_num / N_BITS) + 1); ++i) {
		set_matrix_l(is_used, 0, i, 0);
	}

	max_fact += base_dim;

	// Trovo poly_val_num valori del polinomio (A + s)^2 - n, variando A
	for(i = 0; i < poly_val_num; ++i) {
		mpz_add_ui(intermed, n_root, i);
		mpz_mul(intermed, intermed, intermed);
		mpz_sub(evaluated_poly[i], intermed, n);
		
		mpz_add_ui(As[i], n_root, i);
	}

	// Per ogni primo nella base di fattori
	for(i = 0; i < base_dim && go_on; ++i) {

		// Provo tutte le possibili fattorizzazioni nella base di fattori
		for(j = solutions[i].sol1; j < poly_val_num && go_on; j += factor_base[i]) {

			// Divido e salvo l'esponente va bene
			while(mpz_divisible_ui_p(evaluated_poly[j], factor_base[i])) {
				
				// Se non sono mai stati usati gli esponenti
				if(get_k_i(is_used, 0, j) == 0) {
					for(k = 0; k < base_dim; ++k)
						set_matrix(exponents, j, k, 0);
					set_k_i(is_used, 0, j, 1);
				}
				
				set_matrix(exponents, j, i, get_matrix(exponents, j, i) + 1); // ++exponents[j][i];
				mpz_divexact_ui(evaluated_poly[j], evaluated_poly[j], factor_base[i]);	
			}
			
			if(mpz_cmp_ui(evaluated_poly[j], 1) == 0) {
				++fact_count;
				if(fact_count >= max_fact) {
					go_on = 0;
				}
			}
		}

		// Faccio la stessa cosa con entrambe le soluzioni, a meno che non stia usando 2
		if(factor_base[i] != 2) {
			for(j = solutions[i].sol2; j < poly_val_num && go_on; j += factor_base[i]) {

				while(mpz_divisible_ui_p(evaluated_poly[j], factor_base[i])) {
					
					// Se non sono mai stati usati gli esponenti
					if(get_k_i(is_used, 0, j) == 0) {
						for(k = 0; k < base_dim; ++k)
							set_matrix(exponents, j, k, 0);
						set_k_i(is_used, 0, j, 1);
					}

					set_matrix(exponents, j, i, get_matrix(exponents, j, i) + 1); // ++exponents[j][i];
					mpz_divexact_ui(evaluated_poly[j], evaluated_poly[j], factor_base[i]);
				}

				if(mpz_cmp_ui(evaluated_poly[j], 1) == 0) {
					++fact_count;
					if(fact_count >= max_fact) {
						go_on = 0;
					}
				}
			}
		}
	}

	mpz_clear(n_root);
	mpz_clear(intermed);

	remove_not_factorized(exponents, evaluated_poly, As, poly_val_num, base_dim);

	// finalize_vector_mpz(&evaluated_poly, poly_val_num);
	// Si noti che questa istruzione apparentemente innocua porta all'uscita di demoni dal naso del programmatore

	return fact_count;
}
/*
   Add two ECC points
   @param P        The point to add
   @param Q        The point to add
   @param R        [out] The destination of the double
   @param a        Curve's a value
   @param modulus  The modulus of the field the ECC curve is in
   @return         GNUTLS_E_SUCCESS on success
*/
int
ecc_projective_add_point (ecc_point * P, ecc_point * Q, ecc_point * R,
                              mpz_t a, mpz_t modulus)
{
  /* Using "(m)add-2004-hmv" algorithm
   * It costs 12M + 4S + half. */
  mpz_t t1, t2, x, y, z;
  int err;

  if (P == NULL || Q == NULL || R == NULL || modulus == NULL)
    return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;

  /* check for neutral points */
  if ( (err = ecc_projective_isneutral(Q, modulus)) == 0 ) {
    /* P + Q = P + neutral = P */

    mpz_set (R->x, P->x);
    mpz_set (R->y, P->y);
    mpz_set (R->z, P->z);

    return GNUTLS_E_SUCCESS;
  } else if (err < 0) {
    return err;
  }

  if ( (err = ecc_projective_isneutral(P, modulus)) == 0 ) {
    /* P + Q = neutral + Q = Q */

    mpz_set (R->x, Q->x);
    mpz_set (R->y, Q->y);
    mpz_set (R->z, Q->z);

    return GNUTLS_E_SUCCESS;
  } else if (err < 0) {
    return err;
  }

  if ((err = mp_init_multi (&t1, &t2, &x, &y, &z, NULL)) != 0)
    {
      return err;
    }

  /* Check if P == Q and do doubling in that case
   * If Q == -P then P + Q = neutral element
   */
  if ((mpz_cmp (P->x, Q->x) == 0) &&
      (mpz_cmp (P->z, Q->z) == 0))
    {
      /* x and z coordinates match. Check if P->y = Q->y, or P->y = -Q->y
       */
      if (mpz_cmp (P->y, Q->y) == 0)
        {
          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
          return ecc_projective_dbl_point (P, R, a, modulus);
        }

      mpz_sub (t1, modulus, Q->y);
      if (mpz_cmp (P->y, t1) == 0)
        {
          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
          mpz_set_ui(R->x, 1);
          mpz_set_ui(R->y, 1);
          mpz_set_ui(R->z, 0);
          return GNUTLS_E_SUCCESS;
        }
    }


  mpz_set (x, P->x);
  mpz_set (y, P->y);
  mpz_set (z, P->z);

  /* if Z is one then these are no-operations */
  if (mpz_cmp_ui (Q->z, 1) != 0)
    {
      /* T1 = Z' * Z' */
      mpz_mul (t1, Q->z, Q->z);
      mpz_mod (t1, t1, modulus);
      /* X = X * T1 */
      mpz_mul (x, x, t1);
      mpz_mod (x, x, modulus);
      /* T1 = Z' * T1 */
      mpz_mul (t1, t1, Q->z);
      mpz_mod (t1, t1, modulus);
      /* Y = Y * T1 */
      mpz_mul (y, y, t1);
      mpz_mod (y, y, modulus);
    }

  /* T1 = Z*Z */
  mpz_mul (t1, z, z);
  mpz_mod (t1, t1, modulus);
  /* T2 = X' * T1 */
  mpz_mul (t2, t1, Q->x);
  mpz_mod (t2, t2, modulus);
  /* T1 = Z * T1 */
  mpz_mul (t1, t1, z);
  mpz_mod (t1, t1, modulus);
  /* T1 = Y' * T1 */
  mpz_mul (t1, t1, Q->y);
  mpz_mod (t1, t1, modulus);

  /* Y = Y - T1 */
  mpz_sub (y, y, t1);
  if (mpz_cmp_ui (y, 0) < 0)
    {
      mpz_add (y, y, modulus);
    }
  /* T1 = 2T1 */
  mpz_add (t1, t1, t1);
  if (mpz_cmp (t1, modulus) >= 0)
    {
      mpz_sub (t1, t1, modulus);
    }
  /* T1 = Y + T1 */
  mpz_add (t1, t1, y);
  if (mpz_cmp (t1, modulus) >= 0)
    {
      mpz_sub (t1, t1, modulus);
    }
  /* X = X - T2 */
  mpz_sub (x, x, t2);
  if (mpz_cmp_ui (x, 0) < 0)
    {
      mpz_add (x, x, modulus);
    }
  /* T2 = 2T2 */
  mpz_add (t2, t2, t2);
  if (mpz_cmp (t2, modulus) >= 0)
    {
      mpz_sub (t2, t2, modulus);
    }
  /* T2 = X + T2 */
  mpz_add (t2, t2, x);
  if (mpz_cmp (t2, modulus) >= 0)
    {
      mpz_sub (t2, t2, modulus);
    }

  /* if Z' != 1 */
  if (mpz_cmp_ui (Q->z, 1) != 0)
    {
      /* Z = Z * Z' */
      mpz_mul (z, z, Q->z);
      mpz_mod (z, z, modulus);
    }

  /* Z = Z * X */
  mpz_mul (z, z, x);
  mpz_mod (z, z, modulus);

  /* T1 = T1 * X  */
  mpz_mul (t1, t1, x);
  mpz_mod (t1, t1, modulus);
  /* X = X * X */
  mpz_mul (x, x, x);
  mpz_mod (x, x, modulus);
  /* T2 = T2 * x */
  mpz_mul (t2, t2, x);
  mpz_mod (t2, t2, modulus);
  /* T1 = T1 * X  */
  mpz_mul (t1, t1, x);
  mpz_mod (t1, t1, modulus);

  /* X = Y*Y */
  mpz_mul (x, y, y);
  mpz_mod (x, x, modulus);
  /* X = X - T2 */
  mpz_sub (x, x, t2);
  if (mpz_cmp_ui (x, 0) < 0)
    {
      mpz_add (x, x, modulus);
    }

  /* T2 = T2 - X */
  mpz_sub (t2, t2, x);
  if (mpz_cmp_ui (t2, 0) < 0)
    {
      mpz_add (t2, t2, modulus);
    }
  /* T2 = T2 - X */
  mpz_sub (t2, t2, x);
  if (mpz_cmp_ui (t2, 0) < 0)
    {
      mpz_add (t2, t2, modulus);
    }
  /* T2 = T2 * Y */
  mpz_mul (t2, t2, y);
  mpz_mod (t2, t2, modulus);
  /* Y = T2 - T1 */
  mpz_sub (y, t2, t1);
  if (mpz_cmp_ui (y, 0) < 0)
    {
      mpz_add (y, y, modulus);
    }
  /* Y = Y/2 */
  if (mpz_odd_p (y))
    {
      mpz_add (y, y, modulus);
    }
  mpz_divexact_ui (y, y, 2);

  mpz_set (R->x, x);
  mpz_set (R->y, y);
  mpz_set (R->z, z);

  err = GNUTLS_E_SUCCESS;

  mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
  return err;
}
Beispiel #27
0
static PyObject *
GMPy_MPZ_is_aprcl_prime(PyObject *self, PyObject *other)
{
  mpz_t N;
  s64_t T, U;
  int i, j, H, I, J, K, P, Q, W, X;
  int IV, InvX, LEVELnow, NP, PK, PL, PM, SW, VK, TestedQs, TestingQs;
  int QQ, T1, T3, U1, U3, V1, V3;
  int break_this = 0;
  MPZ_Object *tempx;

  if (!(tempx = GMPy_MPZ_From_Integer(other, NULL))) {
    TYPE_ERROR("is_aprcl_prime() requires 'mpz' argument");
    return NULL;
  }

  mpz_init(N);
  mpz_set(N, tempx->z);
  Py_DECREF(tempx);

  /* make sure the input is >= 2 and odd */
  if (mpz_cmp_ui(N, 2) < 0)
    Py_RETURN_FALSE;

  if (mpz_divisible_ui_p(N, 2)) {
    if (mpz_cmp_ui(N, 2) == 0)
      Py_RETURN_TRUE;
    else
      Py_RETURN_FALSE;
  }

  /* only three small exceptions for this implementation */
  /* with this set of P and Q primes */
  if (mpz_cmp_ui(N, 3) == 0)
    Py_RETURN_TRUE;
  if (mpz_cmp_ui(N, 7) == 0)
    Py_RETURN_TRUE;
  if (mpz_cmp_ui(N, 11) == 0)
    Py_RETURN_TRUE;

  /* If the input number is larger than 7000 decimal digits
     we will just return whether it is a BPSW (probable) prime */
  NumberLength = mpz_sizeinbase(N, 10);
  if (NumberLength > 7000) {
      VALUE_ERROR("value too large to test");
      return NULL;
  }

  allocate_vars();

  mpz_set(TestNbr, N);
  mpz_set_si(biS, 0);

  j = PK = PL = PM = 0;
  for (J = 0; J < PWmax; J++) {
    /* aiJX[J] = 0; */
    mpz_set_ui(aiJX[J], 0);
  }
  break_this = 0;
/* GetPrimes2Test : */
  for (i = 0; i < LEVELmax; i++) {
    /* biS[0] = 2; */
    mpz_set_ui(biS, 2);

    for (j = 0; j < aiNQ[i]; j++) {
      Q = aiQ[j];
      if (aiT[i]%(Q-1) != 0)
        continue;
      U = aiT[i] * Q;
      do {
        U /= Q;
        /* MultBigNbrByLong(biS, Q, biS, NumberLength); */
        mpz_mul_ui(biS, biS, Q);
      } while (U % Q == 0);

      // Exit loop if S^2 > N.
      if (CompareSquare(biS, TestNbr) > 0) {
        /* break GetPrimes2Test; */
        break_this = 1;
        break;
      }
    } /* End for j */

    if (break_this) break;
  } /* End for i */

  if (i == LEVELmax)
  { /* too big */
    free_vars();
    VALUE_ERROR("value too large to test");
    return NULL;
  }
  LEVELnow = i;
  TestingQs = j;
  T = aiT[LEVELnow];
  NP = aiNP[LEVELnow];

MainStart:
  for (;;)
  {
    for (i = 0; i < NP; i++)
    {
      P = aiP[i];
      if (T%P != 0) continue;

      SW = TestedQs = 0;
      /* Q = W = (int) BigNbrModLong(TestNbr, P * P); */
      Q = W = mpz_fdiv_ui(TestNbr, P * P);
      for (J = P - 2; J > 0; J--)
      {
        W = (W * Q) % (P * P);
      }
      if (P > 2 && W != 1)
      {
        SW = 1;
      }
      for (;;)
      {
        for (j = TestedQs; j <= TestingQs; j++)
        {
          Q = aiQ[j] - 1;
          /* G = aiG[j]; */
          K = 0;
          while (Q % P == 0)
          {
            K++;
            Q /= P;
          }
          Q = aiQ[j];
          if (K == 0)
          {
            continue;
          }

          PM = 1;
          for (I = 1; I < K; I++)
          {
            PM = PM * P;
          }
          PL = (P - 1) * PM;
          PK = P * PM;
          for (I = 0; I < PK; I++)
          {
            /* aiJ0[I] = aiJ1[I] = 0; */
            mpz_set_ui(aiJ0[I], 0);
            mpz_set_ui(aiJ1[I], 0);
          }
          if (P > 2)
          {
            JacobiSum(0, P, PL, Q);
          }
          else
          {
            if (K != 1)
            {
              JacobiSum(0, P, PL, Q);
              for (I = 0; I < PK; I++)
              {
                /* aiJW[I] = 0; */
                mpz_set_ui(aiJW[I], 0);
              }
              if (K != 2)
              {
                for (I = 0; I < PM; I++)
                {
                  /* aiJW[I] = aiJ0[I]; */
                  mpz_set(aiJW[I], aiJ0[I]);
                }
                JacobiSum(1, P, PL, Q);
                for (I = 0; I < PM; I++)
                {
                  /* aiJS[I] = aiJ0[I]; */
                  mpz_set(aiJS[I], aiJ0[I]);
                }
                JS_JW(PK, PL, PM, P);
                for (I = 0; I < PM; I++)
                {
                  /* aiJ1[I] = aiJS[I]; */
                  mpz_set(aiJ1[I], aiJS[I]);
                }
                JacobiSum(2, P, PL, Q);
                for (I = 0; I < PK; I++)
                {
                  /* aiJW[I] = 0; */
                  mpz_set_ui(aiJW[I], 0);
                }
                for (I = 0; I < PM; I++)
                {
                  /* aiJS[I] = aiJ0[I]; */
                  mpz_set(aiJS[I], aiJ0[I]);
                }
                JS_2(PK, PL, PM, P);
                for (I = 0; I < PM; I++)
                {
                  /* aiJ2[I] = aiJS[I]; */
                  mpz_set(aiJ2[I], aiJS[I]);
                }
              }
            }
          }
          /* aiJ00[0] = aiJ01[0] = 1; */
          mpz_set_ui(aiJ00[0], 1);
          mpz_set_ui(aiJ01[0], 1);
          for (I = 1; I < PK; I++)
          {
            /* aiJ00[I] = aiJ01[I] = 0; */
            mpz_set_ui(aiJ00[I], 0);
            mpz_set_ui(aiJ01[I], 0);
          }
          /* VK = (int) BigNbrModLong(TestNbr, PK); */
          VK = mpz_fdiv_ui(TestNbr, PK);
          for (I = 1; I < PK; I++)
          {
            if (I % P != 0)
            {
              U1 = 1;
              U3 = I;
              V1 = 0;
              V3 = PK;
              while (V3 != 0)
              {
                QQ = U3 / V3;
                T1 = U1 - V1 * QQ;
                T3 = U3 - V3 * QQ;
                U1 = V1;
                U3 = V3;
                V1 = T1;
                V3 = T3;
              }
              aiInv[I] = (U1 + PK) % PK;
            }
            else
            {
              aiInv[I] = 0;
            }
          }
          if (P != 2)
          {
            for (IV = 0; IV <= 1; IV++)
            {
              for (X = 1; X < PK; X++)
              {
                for (I = 0; I < PK; I++)
                {
                  /* aiJS[I] = aiJ0[I]; */
                  mpz_set(aiJS[I], aiJ0[I]);
                }
                if (X % P == 0)
                {
                  continue;
                }
                if (IV == 0)
                {
                  /* LongToBigNbr(X, biExp, NumberLength); */
                  mpz_set_ui(biExp, X);
                }
                else
                {
                  /* LongToBigNbr(VK * X / PK, biExp, NumberLength); */
                  mpz_set_ui(biExp, (VK * X) / PK);
                  if ((VK * X) / PK == 0)
                  {
                    continue;
                  }
                }
                JS_E(PK, PL, PM, P);
                for (I = 0; I < PK; I++)
                {
                  /* aiJW[I] = 0; */
                  mpz_set_ui(aiJW[I], 0);
                }
                InvX = aiInv[X];
                for (I = 0; I < PK; I++)
                {
                  J = (I * InvX) % PK;
                  /* AddBigNbrModN(aiJW[J], aiJS[I], aiJW[J], TestNbr, NumberLength); */
                  mpz_add(aiJW[J], aiJW[J], aiJS[I]);
                }
                NormalizeJW(PK, PL, PM, P);
                if (IV == 0)
                {
                  for (I = 0; I < PK; I++)
                  {
                    /* aiJS[I] = aiJ00[I]; */
                    mpz_set(aiJS[I], aiJ00[I]);
                  }
                }
                else
                {
                  for (I = 0; I < PK; I++)
                  {
                    /* aiJS[I] = aiJ01[I]; */
                    mpz_set(aiJS[I], aiJ01[I]);
                  }
                }
                JS_JW(PK, PL, PM, P);
                if (IV == 0)
                {
                  for (I = 0; I < PK; I++)
                  {
                    /* aiJ00[I] = aiJS[I]; */
                    mpz_set(aiJ00[I], aiJS[I]);
                  }
                }
                else
                {
                  for (I = 0; I < PK; I++)
                  {
                    /* aiJ01[I] = aiJS[I]; */
                    mpz_set(aiJ01[I], aiJS[I]);
                  }
                }
              } /* end for X */
            } /* end for IV */
          }
          else
          {
            if (K == 1)
            {
              /* MultBigNbrByLongModN(1, Q, aiJ00[0], TestNbr, NumberLength); */
              mpz_set_ui(aiJ00[0], Q);
              /* aiJ01[0] = 1; */
              mpz_set_ui(aiJ01[0], 1);
            }
            else
            {
              if (K == 2)
              {
                if (VK == 1)
                {
                  /* aiJ01[0] = 1; */
                  mpz_set_ui(aiJ01[0], 1);
                }
                /* aiJS[0] = aiJ0[0]; */
                /* aiJS[1] = aiJ0[1]; */
                mpz_set(aiJS[0], aiJ0[0]);
                mpz_set(aiJS[1], aiJ0[1]);
                JS_2(PK, PL, PM, P);
                if (VK == 3)
                {
                  /* aiJ01[0] = aiJS[0]; */
                  /* aiJ01[1] = aiJS[1]; */
                  mpz_set(aiJ01[0], aiJS[0]);
                  mpz_set(aiJ01[1], aiJS[1]);
                }
                /* MultBigNbrByLongModN(aiJS[0], Q, aiJ00[0], TestNbr, NumberLength); */
                mpz_mul_ui(aiJ00[0], aiJS[0], Q);
                /* MultBigNbrByLongModN(aiJS[1], Q, aiJ00[1], TestNbr, NumberLength); */
                mpz_mul_ui(aiJ00[1], aiJS[1], Q);
              }
              else
              {
                for (IV = 0; IV <= 1; IV++)
                {
                  for (X = 1; X < PK; X += 2)
                  {
                    for (I = 0; I <= PM; I++)
                    {
                      /* aiJS[I] = aiJ1[I]; */
                      mpz_set(aiJS[I], aiJ1[I]);
                    }
                    if (X % 8 == 5 || X % 8 == 7)
                    {
                      continue;
                    }
                    if (IV == 0)
                    {
                      /* LongToBigNbr(X, biExp, NumberLength); */
                      mpz_set_ui(biExp, X);
                    }
                    else
                    {
                      /* LongToBigNbr(VK * X / PK, biExp, NumberLength); */
                      mpz_set_ui(biExp, VK * X / PK);
                      if (VK * X / PK == 0)
                      {
                        continue;
                      }
                    }
                    JS_E(PK, PL, PM, P);
                    for (I = 0; I < PK; I++)
                    {
                      /* aiJW[I] = 0; */
                      mpz_set_ui(aiJW[I], 0);
                    }
                    InvX = aiInv[X];
                    for (I = 0; I < PK; I++)
                    {
                      J = I * InvX % PK;
                      /* AddBigNbrModN(aiJW[J], aiJS[I], aiJW[J], TestNbr, NumberLength); */
                      mpz_add(aiJW[J], aiJW[J], aiJS[I]);
                    }
                    NormalizeJW(PK, PL, PM, P);
                    if (IV == 0)
                    {
                      for (I = 0; I < PK; I++)
                      {
                        /* aiJS[I] = aiJ00[I]; */
                        mpz_set(aiJS[I], aiJ00[I]);
                      }
                    }
                    else
                    {
                      for (I = 0; I < PK; I++)
                      {
                        /* aiJS[I] = aiJ01[I]; */
                        mpz_set(aiJS[I], aiJ01[I]);
                      }
                    }
                    NormalizeJS(PK, PL, PM, P);
                    JS_JW(PK, PL, PM, P);
                    if (IV == 0)
                    {
                      for (I = 0; I < PK; I++)
                      {
                        /* aiJ00[I] = aiJS[I]; */
                        mpz_set(aiJ00[I], aiJS[I]);
                      }
                    }
                    else
                    {
                      for (I = 0; I < PK; I++)
                      {
                        /* aiJ01[I] = aiJS[I]; */
                        mpz_set(aiJ01[I], aiJS[I]);
                      }
                    }
                  } /* end for X */
                  if (IV == 0 || VK % 8 == 1 || VK % 8 == 3)
                  {
                    continue;
                  }
                  for (I = 0; I < PM; I++)
                  {
                    /* aiJW[I] = aiJ2[I]; */
                    /* aiJS[I] = aiJ01[I]; */
                    mpz_set(aiJW[I], aiJ2[I]);
                    mpz_set(aiJS[I], aiJ01[I]);
                  }
                  for (; I < PK; I++)
                  {
                    /* aiJW[I] = aiJS[I] = 0; */
                    mpz_set_ui(aiJW[I], 0);
                    mpz_set_ui(aiJS[I], 0);
                  }
                  JS_JW(PK, PL, PM, P);
                  for (I = 0; I < PM; I++)
                  {
                    /* aiJ01[I] = aiJS[I]; */
                    mpz_set(aiJ01[I], aiJS[I]);
                  }
                } /* end for IV */
              }
            }
          }
          for (I = 0; I < PL; I++)
          {
            /* aiJS[I] = aiJ00[I]; */
            mpz_set(aiJS[I], aiJ00[I]);
          }
          for (; I < PK; I++)
          {
            /* aiJS[I] = 0; */
            mpz_set_ui(aiJS[I], 0);
          }
          /* DivBigNbrByLong(TestNbr, PK, biExp, NumberLength); */
          mpz_fdiv_q_ui(biExp, TestNbr, PK);
          JS_E(PK, PL, PM, P);
          for (I = 0; I < PK; I++)
          {
            /* aiJW[I] = 0; */
            mpz_set_ui(aiJW[I], 0);
          }
          for (I = 0; I < PL; I++)
          {
            for (J = 0; J < PL; J++)
            {
              /* MontgomeryMult(aiJS[I], aiJ01[J], biTmp); */
              /* AddBigNbrModN(biTmp, aiJW[(I + J) % PK], aiJW[(I + J) % PK], TestNbr, NumberLength); */
              mpz_mul(biTmp, aiJS[I], aiJ01[J]);
              mpz_add(aiJW[(I + J) % PK], biTmp, aiJW[(I + J) % PK]);
            }
          }
          NormalizeJW(PK, PL, PM, P);
/* MatchingRoot : */
          do
          {
            H = -1;
            W = 0;
            for (I = 0; I < PL; I++)
            {
              if (mpz_cmp_ui(aiJW[I], 0) != 0)/* (!BigNbrIsZero(aiJW[I])) */
              {
                /* if (H == -1 && BigNbrAreEqual(aiJW[I], 1)) */
                if (H == -1 && (mpz_cmp_ui(aiJW[I], 1) == 0))
                {
                  H = I;
                }
                else
                {
                  H = -2;
                  /* AddBigNbrModN(aiJW[I], MontgomeryMultR1, biTmp, TestNbr, NumberLength); */
                  mpz_add_ui(biTmp, aiJW[I], 1);
                  mpz_mod(biTmp, biTmp, TestNbr);
                  if (mpz_cmp_ui(biTmp, 0) == 0) /* (BigNbrIsZero(biTmp)) */
                  {
                    W++;
                  }
                }
              }
            }
            if (H >= 0)
            {
              /* break MatchingRoot; */
              break;
            }
            if (W != P - 1)
            {
              /* Not prime */
              free_vars();
              Py_RETURN_FALSE;
            }
            for (I = 0; I < PM; I++)
            {
              /* AddBigNbrModN(aiJW[I], 1, biTmp, TestNbr, NumberLength); */
              mpz_add_ui(biTmp, aiJW[I], 1);
              mpz_mod(biTmp, biTmp, TestNbr);
              if (mpz_cmp_ui(biTmp, 0) == 0) /* (BigNbrIsZero(biTmp)) */
              {
                break;
              }
            }
            if (I == PM)
            {
              /* Not prime */
              free_vars();
              Py_RETURN_FALSE;
            }
            for (J = 1; J <= P - 2; J++)
            {
              /* AddBigNbrModN(aiJW[I + J * PM], 1, biTmp, TestNbr, NumberLength); */
              mpz_add_ui(biTmp, aiJW[I + J * PM], 1);
              mpz_mod(biTmp, biTmp, TestNbr);
              if (mpz_cmp_ui(biTmp, 0) != 0)/* (!BigNbrIsZero(biTmp)) */
              {
                /* Not prime */
                free_vars();
                Py_RETURN_FALSE;
              }
            }
            H = I + PL;
          }
          while (0);

          if (SW == 1 || H % P == 0)
          {
            continue;
          }
          if (P != 2)
          {
            SW = 1;
            continue;
          }
          if (K == 1)
          {
            if ((mpz_get_ui(TestNbr) & 3) == 1)
            {
              SW = 1;
            }
            continue;
          }

          // if (Q^((N-1)/2) mod N != N-1), N is not prime.

          /* MultBigNbrByLongModN(1, Q, biTmp, TestNbr, NumberLength); */
          mpz_set_ui(biTmp, Q);
          mpz_mod(biTmp, biTmp, TestNbr);

          mpz_sub_ui(biT, TestNbr, 1); /* biT = n-1 */
          mpz_divexact_ui(biT, biT, 2); /* biT = (n-1)/2 */
          mpz_powm(biR, biTmp, biT, TestNbr); /* biR = Q^((n-1)/2) mod n */
          mpz_add_ui(biTmp, biR, 1);
          mpz_mod(biTmp, biTmp, TestNbr);

          if (mpz_cmp_ui(biTmp, 0) != 0)/* (!BigNbrIsZero(biTmp)) */
          {
            /* Not prime */
            free_vars();
            Py_RETURN_FALSE;
          }
          SW = 1;
        } /* end for j */
        if (SW == 0)
        {
          TestedQs = TestingQs + 1;
          if (TestingQs < aiNQ[LEVELnow] - 1)
          {
            TestingQs++;
            Q = aiQ[TestingQs];
            U = T * Q;
            do
            {
              /* MultBigNbrByLong(biS, Q, biS, NumberLength); */
              mpz_mul_ui(biS, biS, Q);
              U /= Q;
            }
            while (U % Q == 0);

            continue; /* Retry */
          }
          LEVELnow++;
          if (LEVELnow == LEVELmax)
          {
            free_vars();
            // return mpz_bpsw_prp(N); /* Cannot tell */
            VALUE_ERROR("maximum levels reached");
            return NULL;
          }
          T = aiT[LEVELnow];
          NP = aiNP[LEVELnow];
          /* biS = 2; */
          mpz_set_ui(biS, 2);
          for (J = 0; J <= aiNQ[LEVELnow]; J++)
          {
            Q = aiQ[J];
            if (T%(Q-1) != 0) continue;
            U = T * Q;
            do
            {
              /* MultBigNbrByLong(biS, Q, biS, NumberLength); */
              mpz_mul_ui(biS, biS, Q);
              U /= Q;
            }
            while (U % Q == 0);
            if (CompareSquare(biS, TestNbr) > 0)
            {
              TestingQs = J;
              /* continue MainStart; */ /* Retry from the beginning */
              goto MainStart;
            }
          } /* end for J */
          free_vars();
          VALUE_ERROR("internal failure");
          return NULL;
        } /* end if */
        break;
      } /* end for (;;) */
    } /* end for i */

    // Final Test

    /* biR = 1 */
    mpz_set_ui(biR, 1);
    /* biN <- TestNbr mod biS */ /* Compute N mod S */
    mpz_fdiv_r(biN, TestNbr, biS);

    for (U = 1; U <= T; U++)
    {
      /* biR <- (biN * biR) mod biS */
      mpz_mul(biR, biN, biR);
      mpz_mod(biR, biR, biS);
      if (mpz_cmp_ui(biR, 1) == 0) /* biR == 1 */
      {
        /* Number is prime */
        free_vars();
        Py_RETURN_TRUE;
      }
      if (mpz_divisible_p(TestNbr, biR) && mpz_cmp(biR, TestNbr) < 0) /* biR < N and biR | TestNbr */
      {
        /* Number is composite */
        free_vars();
        Py_RETURN_FALSE;
      }
    } /* End for U */
    /* This should never be reached. */
    free_vars();
    SYSTEM_ERROR("Internal error: APR-CL error with final test.");
    return NULL;
  }
}
//~ Note: Here, (N, T, c) = (1, 0, 0)
//~ Also, 'rop' is supposed to be already initialised (see glv_scalar.h)
void build_glvScalar(GLVScalar *rop, mpz_t k3, mpz_t aa, mpz_t bb, mpz_t Na){
	
	int j;
	mpz_t x1, x2, y1, y2, k1, k2;
	mpz_inits (x1, x2, y1, y2, k1, k2, NULL);


	mpz_mul (x1, k3, aa);
	mpz_mul (x2, k3, bb);
	mpz_neg (x2, x2);

	mpz_fdiv_q (y1, x1, Na);
	mpz_fdiv_q (y2, x2, Na);
	
	
	mpz_mul (x1, bb, y2);
	mpz_mul (k1, aa, y1);
	mpz_sub (k1, k1, x1);
	mpz_sub (k1, k3, k1);
	
	mpz_mul (x2, aa, y2);
	mpz_mul (k2, bb, y1);
	mpz_add (k2, k2, x2);
	mpz_neg (k2, k2);
	
	

	j = 0;
	while((mpz_cmp_ui (k1, 0)!=0) || (mpz_cmp_ui (k2, 0)!=0)){
		if(mpz_tstbit (k1, 0)) rop->tk1[j] = 1;
		if(mpz_tstbit (k2, 0)) rop->tk2[j] = 1;
		
		if((rop->tk1[j]==1) && (rop->tk2[j]==1)){
			if(mpz_tstbit (k1, 1)) rop->tk1[j] = -1;
			if(mpz_tstbit (k2, 1)) rop->tk2[j] = -1;
		}
		else if(rop->tk1[j] != rop->tk2[j]){
			if(mpz_tstbit (k1, 1) != mpz_tstbit (k2, 1)){
				rop->tk1[j] = -(rop->tk1[j]); 
				rop->tk2[j] = -(rop->tk2[j]);
			}
		}
		
		if(rop->tk1[j] == 1)
			mpz_sub_ui (k1, k1, 1);
		else if(rop->tk1[j] == -1)
			mpz_add_ui (k1, k1, 1);
		
		//~ Correspond to shiftRight(1)
		mpz_clrbit (k1, 0);
		mpz_divexact_ui (k1, k1, 2);
		
		if(rop->tk2[j] == 1)
			mpz_sub_ui (k2, k2, 1);
		else if(rop->tk2[j] == -1)
			mpz_add_ui (k2, k2, 1);
		
		//~ Correspond to shiftRight(1)
		mpz_clrbit (k2, 0);
		mpz_divexact_ui (k2, k2, 2);
		
		j +=1;
	}
	j -=1;

	rop->j = j;

	mpz_clears (x1, x2, y1, y2, k1, k2, NULL);
}
Beispiel #29
0
int executeSumCalculation(mpz_t num)
{
	mpz_t sum, squareRoot, sqrtRem, st;
	mpz_t range, rem;
	int i;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
	unsigned long long termCount;
	int err;
	SUM_THREAD_CONTEXT contexts[SUM_THREADS_PER_CALC];

	mpz_init(squareRoot);
	mpz_init(sqrtRem);
	mpz_init(range);
	mpz_init(rem);

	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&cond, NULL);
	termCount = 0;

	//The sum starts at 1 because 1 is a factor of any number
	mpz_init_set_ui(sum, 1);

	//We know that exactly 1 factor of every pair of factors will
	//appear before the square root.
	mpz_sqrtrem(squareRoot, sqrtRem, num);

	//Check if the the number is a square
	if (mpz_cmp_ui(sqrtRem, 0) != 0)
	{
		//Emulate ceil
		mpz_add_ui(squareRoot, squareRoot, 1);
	}

	//Factor starts at 2
	mpz_init_set_ui(st, 2);

	//Compute range
	mpz_mod_ui(rem, squareRoot, SUM_THREADS_PER_CALC);
	mpz_sub(squareRoot, squareRoot, rem);
	mpz_divexact_ui(range, squareRoot, SUM_THREADS_PER_CALC);

	for (i = 0; i < SUM_THREADS_PER_CALC; i++)
	{
		mpz_init_set(contexts[i].st, st);
		mpz_init_set(contexts[i].factor, st);
		mpz_init(contexts[i].otherfactor);
		mpz_add(st, st, range);
		if (i == 0)
		{
			mpz_sub_ui(st, st, 2);
		}
		mpz_init_set(contexts[i].end, st);
		if (i == 0)
		{
			mpz_add(contexts[i].end, contexts[i].end, rem);
			mpz_add(st, st, rem);
		}

		mpz_init_set(contexts[i].num, num);
		contexts[i].sum = &sum;
		contexts[i].termCount = &termCount;
		contexts[i].termMutex = &mutex;
		contexts[i].termVar = &cond;

		printf("Assigning work to sum thread %d\n", i);

		err = pthread_create(&contexts[i].id, NULL, SumThread, &contexts[i]);
		if (err != 0)
			return -1;
	}

	fflush(stdout);

	for (;;)
	{
		pthread_mutex_lock(&mutex);

		printf("%llu sum threads complete\n", termCount);
		fflush(stdout);

		if (termCount == SUM_THREADS_PER_CALC)
		{
			pthread_mutex_unlock(&mutex);
			break;
		}

		if (mpz_cmp(sum, num) > 0)
		{
			printf("sum is too large; terminating children\n");
			fflush(stdout);
			pthread_mutex_unlock(&mutex);
			break;
		}

		pthread_cond_wait(&cond, &mutex);

		pthread_mutex_unlock(&mutex);
	}

	for (i = 0; i < SUM_THREADS_PER_CALC; i++)
	{
		void *ret;

		pthread_cancel(contexts[i].id);

		pthread_join(contexts[i].id, &ret);

		mpz_clear(contexts[i].st);
		mpz_clear(contexts[i].num);
		mpz_clear(contexts[i].factor);
		mpz_clear(contexts[i].end);
		mpz_clear(contexts[i].otherfactor);
	}

	mpz_clear(squareRoot);
	mpz_clear(sqrtRem);
	mpz_clear(range);
	mpz_clear(rem);
	mpz_clear(st);

	if (mpz_cmp(sum, num) == 0)
	{
		mpz_clear(sum);
		return 1;
	}
	else
	{
		mpz_clear(sum);
		return 0;
	}
}
Beispiel #30
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;
}