/** * 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); }
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; }
/* ************************************************************************* * 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 */
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; }
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; }
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 */ } } }
/** * 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; }
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; } }
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); }
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); }
/*------------------------------------------------------------------------*/ 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); }
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); }
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); }
/* 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; }
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; }
/* 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; }
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; }
/* 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(); }
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; }
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); }
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 = ∑ 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; } }
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; }