// Same as above, but with affine coordinates. static void cc_miller_no_denom_affine(element_t res, mpz_t q, element_t P, element_ptr Qx, element_ptr Qy) { mp_bitcnt_t m; element_t v; element_t Z; element_t a, b, c; element_t t0; element_t e0; const element_ptr cca = curve_a_coeff(P); const element_ptr Px = curve_x_coord(P); const element_ptr Py = curve_y_coord(P); element_ptr Zx, Zy; /* TODO: when exactly is this not needed? void do_vertical() { mapbase(e0, Z->x); element_sub(e0, Qx, e0); element_mul(v, v, e0); } */ #define do_tangent() { \ /* a = -(3 Zx^2 + cc->a) */ \ /* b = 2 * Zy */ \ /* c = -(2 Zy^2 + a Zx); */ \ \ element_square(a, Zx); \ element_mul_si(a, a, 3); \ element_add(a, a, cca); \ element_neg(a, a); \ \ element_add(b, Zy, Zy); \ \ element_mul(t0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, t0); \ element_neg(c, c); \ \ d_miller_evalfn(e0, a, b, c, Qx, Qy); \ element_mul(v, v, e0); \ } #define do_line() { \ /* a = -(B.y - A.y) / (B.x - A.x); */ \ /* b = 1; */ \ /* c = -(A.y + a * A.x); */ \ /* but we multiply by B.x - A.x to avoid division. */ \ \ element_sub(b, Px, Zx); \ element_sub(a, Zy, Py); \ element_mul(t0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, t0); \ element_neg(c, c); \ \ d_miller_evalfn(e0, a, b, c, Qx, Qy); \ element_mul(v, v, e0); \ } element_init(a, Px->field); element_init(b, a->field); element_init(c, a->field); element_init(t0, a->field); element_init(e0, res->field); element_init(v, res->field); element_init(Z, P->field); element_set(Z, P); Zx = curve_x_coord(Z); Zy = curve_y_coord(Z); element_set1(v); m = (mp_bitcnt_t)mpz_sizeinbase(q, 2); m = (m > 2 ? m - 2 : 0); for(;;) { do_tangent(); if (!m) break; element_double(Z, Z); if (mpz_tstbit(q, m)) { do_line(); element_add(Z, Z, P); } m--; element_square(v, v); } element_set(res, v); element_clear(v); element_clear(Z); element_clear(a); element_clear(b); element_clear(c); element_clear(t0); element_clear(e0); #undef do_tangent #undef do_line }
static PyObject * GMPY_mpz_lucasv_mod(PyObject *self, PyObject *args) { /* Adaptation of algorithm found in http://joye.site88.net/papers/JQ96lucas.pdf * calculate v[k] (modulo n) of Lucas V sequence for p,q. * Note: p^2-4q=0 is not tested, not a proper Lucas sequence!! */ PympzObject *result = 0, *p, *q, *k, *n; size_t s = 0, j = 0; mpz_t vl, vh, ql, qh, tmp; if (PyTuple_Size(args) != 4) { TYPE_ERROR("lucasv_mod() requires 4 integer arguments"); return NULL; } /* Take advantage of the cache of mpz_t objects maintained by GMPY2 to * avoid memory allocations. */ mpz_inoc(vl); mpz_inoc(vh); mpz_inoc(ql); mpz_inoc(qh); mpz_inoc(tmp); p = Pympz_From_Integer(PyTuple_GET_ITEM(args, 0)); q = Pympz_From_Integer(PyTuple_GET_ITEM(args, 1)); k = Pympz_From_Integer(PyTuple_GET_ITEM(args, 2)); n = Pympz_From_Integer(PyTuple_GET_ITEM(args, 3)); if (!p || !q || !k || !n) { TYPE_ERROR("lucasv_mod() requires 4 integer arguments"); goto cleanup; } /* Check if p*p - 4*q == 0. */ mpz_mul(tmp, p->z, p->z); mpz_mul_ui(qh, q->z, 4); mpz_sub(tmp, tmp, qh); if (mpz_sgn(tmp) == 0) { VALUE_ERROR("invalid values for p,q in lucasv_mod()"); goto cleanup; } /* Check if k < 0. */ if (mpz_sgn(k->z) < 0) { VALUE_ERROR("invalid value for k in lucasv_mod()"); goto cleanup; } /* Check if n > 0. */ if (mpz_sgn(n->z) <= 0) { VALUE_ERROR("invalid value for n in lucasv_mod()"); goto cleanup; } mpz_set_si(vl, 2); mpz_set(vh, p->z); mpz_set_si(ql, 1); mpz_set_si(qh, 1); mpz_set_si(tmp,0); s = mpz_scan1(k->z, 0); for (j = mpz_sizeinbase(k->z,2)-1; j >= s+1; j--) { /* ql = ql*qh (mod n) */ mpz_mul(ql, ql, qh); mpz_mod(ql, ql, n->z); if (mpz_tstbit(k->z,j) == 1) { /* qh = ql*q */ mpz_mul(qh, ql, q->z); /* vl = vh*vl - p*ql (mod n) */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); /* vh = vh*vh - 2*qh (mod n) */ mpz_mul(vh, vh, vh); mpz_mul_si(tmp, qh, 2); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n->z); } else { /* qh = ql */ mpz_set(qh, ql); /* vh = vh*vl - p*ql (mod n) */ mpz_mul(vh, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vh, vh, tmp); mpz_mod(vh, vh, n->z); /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); } } /* ql = ql*qh */ mpz_mul(ql, ql, qh); /* qh = ql*q */ mpz_mul(qh, ql, q->z); /* vl = vh*vl - p*ql */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); /* ql = ql*qh */ mpz_mul(ql, ql, qh); for (j = 1; j <= s; j++) { /* vl = vl*vl - 2*ql (mod n) */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); mpz_mod(vl, vl, n->z); /* ql = ql*ql (mod n) */ mpz_mul(ql, ql, ql); mpz_mod(ql, ql, n->z); } if (!(result = (PympzObject*)Pympz_new())) goto cleanup; /* vl contains our return value */ mpz_mod(result->z, vl, n->z); cleanup: mpz_cloc(vl); mpz_cloc(vh); mpz_cloc(ql); mpz_cloc(qh); mpz_cloc(tmp); Py_XDECREF((PyObject*)p); Py_XDECREF((PyObject*)q); Py_XDECREF((PyObject*)k); Py_XDECREF((PyObject*)n); return (PyObject*)result; }
// scalar multiplication on Surf127_735. // key is 4 limb long. void KSmul(mpfq_p_127_735_field k, dst_KSpoint res, src_KSpoint P, mpz_t key, src_KSparam KS) { KSpoint Pm, Pp; mpfq_p_127_735_elt tmpy, tmpz, tmpt; mpfq_p_127_735_elt YY, ZZ, TT; KSpoint_struct *pm, *pp, *tmp; int i, l; if (mpz_cmp_ui(key, 0)==0) { // implement me! assert (0); } if (mpz_cmp_ui(key, 1)==0) { KScopy(k, res, P); return; } KSinit(k, Pm); KSinit(k, Pp); KScopy(k, Pm, P); KSdouble(k, Pp, Pm, KS); if (mpz_cmp_ui(key, 2)==0) { KScopy(k, res, Pp); KSclear(k, Pm); KSclear(k, Pp); return; } mpfq_p_127_735_init(k, &tmpy); mpfq_p_127_735_init(k, &tmpz); mpfq_p_127_735_init(k, &tmpt); mpfq_p_127_735_init(k, &YY); mpfq_p_127_735_init(k, &ZZ); mpfq_p_127_735_init(k, &TT); mpfq_p_127_735_mul(k, tmpy, P->y, P->z); mpfq_p_127_735_mul(k, tmpz, tmpy, P->t); mpfq_p_127_735_inv(k, tmpz, tmpz); mpfq_p_127_735_mul(k, tmpz, tmpz, P->x); mpfq_p_127_735_mul(k, TT, tmpz, tmpy); // x/t mpfq_p_127_735_mul(k, tmpy, P->z, P->t); mpfq_p_127_735_mul(k, YY, tmpz, tmpy); // x/y mpfq_p_127_735_mul(k, tmpy, P->y, P->t); mpfq_p_127_735_mul(k, ZZ, tmpz, tmpy); // x/z // initialize loop pm = Pm; pp = Pp; // loop l = mpz_sizeinbase(key, 2); assert (mpz_tstbit(key, l-1) == 1); for (i = l-2; i >= 0; --i) { int swap; swap = (mpz_tstbit(key, i) == 1); if (swap) { tmp = pp; pp = pm; pm = tmp; } // pseudo add(pm, pp) -> pp ; dble(pm) -> pm // Total: 32A + 16P + 9S KShadamard(k, pm); // 8A mpfq_p_127_735_mul(k, tmpy, pm->y, KS->y0p); mpfq_p_127_735_mul(k, tmpz, pm->z, KS->z0p); mpfq_p_127_735_mul(k, tmpt, pm->t, KS->t0p); // 3P KShadamard(k, pp); // 8A mpfq_p_127_735_mul(k, pp->x, pp->x, pm->x); mpfq_p_127_735_mul(k, pp->y, pp->y, tmpy); mpfq_p_127_735_mul(k, pp->z, pp->z, tmpz); mpfq_p_127_735_mul(k, pp->t, pp->t, tmpt); // 4P KShadamard(k, pp); // 8A mpfq_p_127_735_sqr(k, pp->x, pp->x); mpfq_p_127_735_sqr(k, pp->y, pp->y); mpfq_p_127_735_sqr(k, pp->z, pp->z); mpfq_p_127_735_sqr(k, pp->t, pp->t); // 4S mpfq_p_127_735_mul(k, pp->y, pp->y, YY); mpfq_p_127_735_mul(k, pp->z, pp->z, ZZ); mpfq_p_127_735_mul(k, pp->t, pp->t, TT); // 3P mpfq_p_127_735_sqr(k, pm->x, pm->x); // 1S mpfq_p_127_735_mul(k, pm->y, pm->y, tmpy); mpfq_p_127_735_mul(k, pm->z, pm->z, tmpz); mpfq_p_127_735_mul(k, pm->t, pm->t, tmpt); // 3P KShadamard(k, pm); // 8A mpfq_p_127_735_sqr(k, pm->x, pm->x); mpfq_p_127_735_sqr(k, pm->y, pm->y); mpfq_p_127_735_sqr(k, pm->z, pm->z); mpfq_p_127_735_sqr(k, pm->t, pm->t); // 4S mpfq_p_127_735_mul(k, pm->y, pm->y, KS->y0); mpfq_p_127_735_mul(k, pm->z, pm->z, KS->z0); mpfq_p_127_735_mul(k, pm->t, pm->t, KS->t0); // 3P if (swap) { tmp = pp; pp = pm; pm = tmp; } } KScopy(k, res, pm); KSclear(k, Pm); KSclear(k, Pp); mpfq_p_127_735_clear(k, &YY); mpfq_p_127_735_clear(k, &ZZ); mpfq_p_127_735_clear(k, &TT); mpfq_p_127_735_clear(k, &tmpy); mpfq_p_127_735_clear(k, &tmpz); mpfq_p_127_735_clear(k, &tmpt); }
int rsa_generate_keypair(struct rsa_public_key *pub, struct rsa_private_key *key, void *random_ctx, nettle_random_func *random, void *progress_ctx, nettle_progress_func *progress, unsigned n_size, unsigned e_size) { mpz_t p1; mpz_t q1; mpz_t phi; mpz_t tmp; if (e_size) { /* We should choose e randomly. Is the size reasonable? */ if ((e_size < 16) || (e_size >= n_size) ) return 0; } else { /* We have a fixed e. Check that it makes sense */ /* It must be odd */ if (!mpz_tstbit(pub->e, 0)) return 0; /* And 3 or larger */ if (mpz_cmp_ui(pub->e, 3) < 0) return 0; /* And size less than n */ if (mpz_sizeinbase(pub->e, 2) >= n_size) return 0; } if (n_size < RSA_MINIMUM_N_BITS) return 0; mpz_init(p1); mpz_init(q1); mpz_init(phi); mpz_init(tmp); /* Generate primes */ for (;;) { /* Generate p, such that gcd(p-1, e) = 1 */ for (;;) { nettle_random_prime(key->p, (n_size+1)/2, 1, random_ctx, random, progress_ctx, progress); mpz_sub_ui(p1, key->p, 1); /* If e was given, we must chose p such that p-1 has no factors in * common with e. */ if (e_size) break; mpz_gcd(tmp, pub->e, p1); if (mpz_cmp_ui(tmp, 1) == 0) break; else if (progress) progress(progress_ctx, 'c'); } if (progress) progress(progress_ctx, '\n'); /* Generate q, such that gcd(q-1, e) = 1 */ for (;;) { nettle_random_prime(key->q, n_size/2, 1, random_ctx, random, progress_ctx, progress); /* Very unlikely. */ if (mpz_cmp (key->q, key->p) == 0) continue; mpz_sub_ui(q1, key->q, 1); /* If e was given, we must chose q such that q-1 has no factors in * common with e. */ if (e_size) break; mpz_gcd(tmp, pub->e, q1); if (mpz_cmp_ui(tmp, 1) == 0) break; else if (progress) progress(progress_ctx, 'c'); } /* Now we have the primes. Is the product of the right size? */ mpz_mul(pub->n, key->p, key->q); assert (mpz_sizeinbase(pub->n, 2) == n_size); if (progress) progress(progress_ctx, '\n'); /* c = q^{-1} (mod p) */ if (mpz_invert(key->c, key->q, key->p)) /* This should succeed everytime. But if it doesn't, * we try again. */ break; else if (progress) progress(progress_ctx, '?'); } mpz_mul(phi, p1, q1); /* If we didn't have a given e, generate one now. */ if (e_size) { int retried = 0; for (;;) { nettle_mpz_random_size(pub->e, random_ctx, random, e_size); /* Make sure it's odd and that the most significant bit is * set */ mpz_setbit(pub->e, 0); mpz_setbit(pub->e, e_size - 1); /* Needs gmp-3, or inverse might be negative. */ if (mpz_invert(key->d, pub->e, phi)) break; if (progress) progress(progress_ctx, 'e'); retried = 1; } if (retried && progress) progress(progress_ctx, '\n'); } else { /* Must always succeed, as we already that e * doesn't have any common factor with p-1 or q-1. */ int res = mpz_invert(key->d, pub->e, phi); assert(res); } /* Done! Almost, we must compute the auxillary private values. */ /* a = d % (p-1) */ mpz_fdiv_r(key->a, key->d, p1); /* b = d % (q-1) */ mpz_fdiv_r(key->b, key->d, q1); /* c was computed earlier */ pub->size = key->size = (n_size + 7) / 8; assert(pub->size >= RSA_MINIMUM_N_OCTETS); mpz_clear(p1); mpz_clear(q1); mpz_clear(phi); mpz_clear(tmp); return 1; }
static int mpfr_rem1 (mpfr_ptr rem, long *quo, mpfr_rnd_t rnd_q, mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd) { mpfr_exp_t ex, ey; int compare, inex, q_is_odd, sign, signx = MPFR_SIGN (x); mpz_t mx, my, r; int tiny = 0; MPFR_ASSERTD (rnd_q == MPFR_RNDN || rnd_q == MPFR_RNDZ); if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x) || MPFR_IS_SINGULAR (y))) { if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y) || MPFR_IS_INF (x) || MPFR_IS_ZERO (y)) { /* for remquo, quo is undefined */ MPFR_SET_NAN (rem); MPFR_RET_NAN; } else /* either y is Inf and x is 0 or non-special, or x is 0 and y is non-special, in both cases the quotient is zero. */ { if (quo) *quo = 0; return mpfr_set (rem, x, rnd); } } /* now neither x nor y is NaN, Inf or zero */ mpz_init (mx); mpz_init (my); mpz_init (r); ex = mpfr_get_z_2exp (mx, x); /* x = mx*2^ex */ ey = mpfr_get_z_2exp (my, y); /* y = my*2^ey */ /* to get rid of sign problems, we compute it separately: quo(-x,-y) = quo(x,y), rem(-x,-y) = -rem(x,y) quo(-x,y) = -quo(x,y), rem(-x,y) = -rem(x,y) thus quo = sign(x/y)*quo(|x|,|y|), rem = sign(x)*rem(|x|,|y|) */ sign = (signx == MPFR_SIGN (y)) ? 1 : -1; mpz_abs (mx, mx); mpz_abs (my, my); q_is_odd = 0; /* divide my by 2^k if possible to make operations mod my easier */ { unsigned long k = mpz_scan1 (my, 0); ey += k; mpz_fdiv_q_2exp (my, my, k); } if (ex <= ey) { /* q = x/y = mx/(my*2^(ey-ex)) */ /* First detect cases where q=0, to avoid creating a huge number my*2^(ey-ex): if sx = mpz_sizeinbase (mx, 2) and sy = mpz_sizeinbase (my, 2), we have x < 2^(ex + sx) and y >= 2^(ey + sy - 1), thus if ex + sx <= ey + sy - 1 the quotient is 0 */ if (ex + (mpfr_exp_t) mpz_sizeinbase (mx, 2) < ey + (mpfr_exp_t) mpz_sizeinbase (my, 2)) { tiny = 1; mpz_set (r, mx); mpz_set_ui (mx, 0); } else { mpz_mul_2exp (my, my, ey - ex); /* divide mx by my*2^(ey-ex) */ /* since mx > 0 and my > 0, we can use mpz_tdiv_qr in all cases */ mpz_tdiv_qr (mx, r, mx, my); /* 0 <= |r| <= |my|, r has the same sign as mx */ } if (rnd_q == MPFR_RNDN) q_is_odd = mpz_tstbit (mx, 0); if (quo) /* mx is the quotient */ { mpz_tdiv_r_2exp (mx, mx, WANTED_BITS); *quo = mpz_get_si (mx); } } else /* ex > ey */ { if (quo) /* remquo case */ /* for remquo, to get the low WANTED_BITS more bits of the quotient, we first compute R = X mod Y*2^WANTED_BITS, where X and Y are defined below. Then the low WANTED_BITS of the quotient are floor(R/Y). */ mpz_mul_2exp (my, my, WANTED_BITS); /* 2^WANTED_BITS*Y */ else if (rnd_q == MPFR_RNDN) /* remainder case */ /* Let X = mx*2^(ex-ey) and Y = my. Then both X and Y are integers. Assume X = R mod Y, then x = X*2^ey = R*2^ey mod (Y*2^ey=y). To be able to perform the rounding, we need the least significant bit of the quotient, i.e., one more bit in the remainder, which is obtained by dividing by 2Y. */ mpz_mul_2exp (my, my, 1); /* 2Y */ mpz_set_ui (r, 2); mpz_powm_ui (r, r, ex - ey, my); /* 2^(ex-ey) mod my */ mpz_mul (r, r, mx); mpz_mod (r, r, my); if (quo) /* now 0 <= r < 2^WANTED_BITS*Y */ { mpz_fdiv_q_2exp (my, my, WANTED_BITS); /* back to Y */ mpz_tdiv_qr (mx, r, r, my); /* oldr = mx*my + newr */ *quo = mpz_get_si (mx); q_is_odd = *quo & 1; } else if (rnd_q == MPFR_RNDN) /* now 0 <= r < 2Y in the remainder case */ { mpz_fdiv_q_2exp (my, my, 1); /* back to Y */ /* least significant bit of q */ q_is_odd = mpz_cmpabs (r, my) >= 0; if (q_is_odd) mpz_sub (r, r, my); } /* now 0 <= |r| < |my|, and if needed, q_is_odd is the least significant bit of q */ } if (mpz_cmp_ui (r, 0) == 0) { inex = mpfr_set_ui (rem, 0, MPFR_RNDN); /* take into account sign of x */ if (signx < 0) mpfr_neg (rem, rem, MPFR_RNDN); } else { if (rnd_q == MPFR_RNDN) { /* FIXME: the comparison 2*r < my could be done more efficiently at the mpn level */ mpz_mul_2exp (r, r, 1); /* if tiny=1, we should compare r with my*2^(ey-ex) */ if (tiny) { if (ex + (mpfr_exp_t) mpz_sizeinbase (r, 2) < ey + (mpfr_exp_t) mpz_sizeinbase (my, 2)) compare = 0; /* r*2^ex < my*2^ey */ else { mpz_mul_2exp (my, my, ey - ex); compare = mpz_cmpabs (r, my); } } else compare = mpz_cmpabs (r, my); mpz_fdiv_q_2exp (r, r, 1); compare = ((compare > 0) || ((rnd_q == MPFR_RNDN) && (compare == 0) && q_is_odd)); /* if compare != 0, we need to subtract my to r, and add 1 to quo */ if (compare) { mpz_sub (r, r, my); if (quo && (rnd_q == MPFR_RNDN)) *quo += 1; } } /* take into account sign of x */ if (signx < 0) mpz_neg (r, r); inex = mpfr_set_z_2exp (rem, r, ex > ey ? ey : ex, rnd); } if (quo) *quo *= sign; mpz_clear (mx); mpz_clear (my); mpz_clear (r); return inex; }
//~ 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 genrsa(char* priv_out, char* pub_out) { /*TODO: How will the numbers chosen be of "similar bit length" ? */ mpz_t p, q, n, phi, decp, decq, e, d, c, m, t , m2, res, k, qinverseModP, exponent1, exponent2; gmp_randstate_t randomState; int isPrimeP = 0, isPrimeQ = 0, extraOctetAdded, numOctetsAdded = 0, totalLength = 0, levelLength = 0; int* pubKeyBuf = (int*)malloc(PUB_KEY_BUF_LEN* sizeof(int)); int* privKeyBuf = (int*)malloc(PRIV_KEY_BUF_LEN* sizeof(int)); int priv_key_ptr = PRIV_KEY_BUF_LEN - 1; int pub_key_ptr = PUB_KEY_BUF_LEN - 1; int len_e_octets = E_NUM_BITS / 8; //initialising random values mpz_init(p); mpz_init(qinverseModP); mpz_init(exponent1); mpz_init(exponent2); mpz_init(k); mpz_init(m); mpz_init(c); mpz_init(res); mpz_init(q); mpz_init(n); mpz_init(t); mpz_init(m2); mpz_init(decp); mpz_init(decq); mpz_init(phi); mpz_init(e); mpz_init(d); mpz_init_set_si(e, 65537L); mpz_init_set_si(m , 5L); mpz_init_set_si(m2 , 5L); //seeding random value gmp_randinit_default(randomState); gmp_randseed_ui(randomState, time(0)); int foundE = 0; while(!foundE) { //generatnig primes do { mpz_urandomb(p, randomState ,RSA_NUM_BITS); isPrimeP = mpz_probab_prime_p(p, 10); } while(!isPrimeP); do { mpz_urandomb(q, randomState ,RSA_NUM_BITS); isPrimeQ = mpz_probab_prime_p(q, 10); } while(!isPrimeQ); //p*q mpz_mul(n , p , q); //Assures that we have 1024 bit key if(mpz_tstbit(n, N_NUM_BITS - 1) == 0) continue; #if DEBUG mpz_out_str(NULL, 10, p); printf("\n"); mpz_out_str(NULL, 10, q); printf("\n"); mpz_out_str(NULL, 10, n); printf("\n"); mpz_out_str(NULL, 10, decp); printf("\n"); mpz_out_str(NULL, 10, decq); printf("\n"); #endif //p - 1 mpz_sub_ui(decp, p, 1); // q - 1 mpz_sub_ui(decq, q, 1); //Euler's totient function mpz_mul(phi, decp, decq); foundE = applyExtendedEuclid(e, phi, d); #if DEBUG mpz_out_str(NULL, 10, e); printf("\n"); mpz_out_str(NULL, 10, d); printf("\n"); #endif if(mpz_cmp_si(d, 0L) < 0) { mpz_add(d, phi, d); } } #if DEBUG printf("Positive D\n"); mpz_out_str(NULL, 10, d); printf("\n"); #endif //encrypt(m, e, c, n); // mpz_powm(res, m2 ,e, n); #if DEBUG printf("Cipher1\n"); mpz_out_str(NULL, 10, c); printf("Cipher2\n"); mpz_out_str(NULL, 10, res); printf("\n"); #endif // mpz_init_set(k, c); //encrypt(c, d, t, n); // mpz_powm(res, k ,d, n); #if DEBUG printf("dec\n"); mpz_out_str(NULL, 10, t); printf("\n"); //printf("dec 2\n"); //mpz_out_str(NULL, 10, res); #endif //Adding E { addEToPublicKeyBuffer(e, pubKeyBuf, &pub_key_ptr); totalLength = len_e_octets; numOctetsAdded = appendLengthToBuffer(len_e_octets, pubKeyBuf, &pub_key_ptr); totalLength+= numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, pubKeyBuf, &pub_key_ptr); totalLength++; extraOctetAdded = addMpz_tToBuffer(n, pubKeyBuf, &pub_key_ptr, N_NUM_BITS); totalLength = totalLength + (N_NUM_BITS/8) + extraOctetAdded ; numOctetsAdded = appendLengthToBuffer( ( (N_NUM_BITS/8) + extraOctetAdded ) , pubKeyBuf, &pub_key_ptr); totalLength+= numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, pubKeyBuf, &pub_key_ptr); totalLength++; numOctetsAdded = appendLengthToBuffer( totalLength , pubKeyBuf, &pub_key_ptr); totalLength+= numOctetsAdded; appendIdentifierOctet(TAG_SEQUENCE, CONSTRUCTED, UNIVERSAL, pubKeyBuf, &pub_key_ptr); totalLength++; //An octet of 00 is added always, since the content always has multiple of 8 bits, so unused bits is 0 addNullOctet(pubKeyBuf, &pub_key_ptr); totalLength++; numOctetsAdded = appendLengthToBuffer( totalLength , pubKeyBuf, &pub_key_ptr); totalLength+= numOctetsAdded; appendIdentifierOctet(TAG_BIT_STRING, PRIMITIVE, UNIVERSAL, pubKeyBuf, &pub_key_ptr); totalLength++; addUsualPublicKeyHeaders(pubKeyBuf, &pub_key_ptr, &totalLength); // The Key is contained within the pubKeyBuf at this stage writeKeyBuffer(pub_out, pubKeyBuf, pub_key_ptr +1, PUB_KEY_BUF_LEN); free(pubKeyBuf); } //printf("Total octets %d", totalLength); { totalLength = 0; mpz_invert (qinverseModP, q, p); //Adding q^-1 mod p extraOctetAdded = addMpz_tToBuffer(qinverseModP, privKeyBuf, &priv_key_ptr, RSA_NUM_BITS); levelLength = (RSA_NUM_BITS/8) + extraOctetAdded ; totalLength+= levelLength; numOctetsAdded = appendLengthToBuffer(levelLength, privKeyBuf, &priv_key_ptr); totalLength+=numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, privKeyBuf, &priv_key_ptr); totalLength++; mpz_mod(exponent1, d, decp); mpz_mod(exponent2, d, decq); //Adding exponent2 extraOctetAdded = addMpz_tToBuffer(exponent2, privKeyBuf, &priv_key_ptr, RSA_NUM_BITS); levelLength = (RSA_NUM_BITS/8) + extraOctetAdded ; totalLength+= levelLength; numOctetsAdded = appendLengthToBuffer(levelLength, privKeyBuf, &priv_key_ptr); totalLength+=numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, privKeyBuf, &priv_key_ptr); totalLength++; //Adding exponent1 extraOctetAdded = addMpz_tToBuffer(exponent1, privKeyBuf, &priv_key_ptr, RSA_NUM_BITS); levelLength = (RSA_NUM_BITS/8) + extraOctetAdded ; totalLength+= levelLength; numOctetsAdded = appendLengthToBuffer(levelLength, privKeyBuf, &priv_key_ptr); totalLength+=numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, privKeyBuf, &priv_key_ptr); totalLength++; //Adding prime2 extraOctetAdded = addMpz_tToBuffer(q, privKeyBuf, &priv_key_ptr, RSA_NUM_BITS); levelLength = (RSA_NUM_BITS/8) + extraOctetAdded ; totalLength+= levelLength; numOctetsAdded = appendLengthToBuffer(levelLength, privKeyBuf, &priv_key_ptr); totalLength+=numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, privKeyBuf, &priv_key_ptr); totalLength++; //Adding prime1 extraOctetAdded = addMpz_tToBuffer(p, privKeyBuf, &priv_key_ptr, RSA_NUM_BITS); levelLength = (RSA_NUM_BITS/8) + extraOctetAdded ; totalLength+= levelLength; numOctetsAdded = appendLengthToBuffer(levelLength, privKeyBuf, &priv_key_ptr); totalLength+=numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, privKeyBuf, &priv_key_ptr); totalLength++; //Adding d extraOctetAdded = addMpz_tToBuffer(d, privKeyBuf, &priv_key_ptr, N_NUM_BITS); levelLength = (N_NUM_BITS/8) + extraOctetAdded ; totalLength+= levelLength; numOctetsAdded = appendLengthToBuffer(levelLength, privKeyBuf, &priv_key_ptr); totalLength+=numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, privKeyBuf, &priv_key_ptr); totalLength++; //Adding e extraOctetAdded = addMpz_tToBuffer(e, privKeyBuf, &priv_key_ptr, E_NUM_BITS); levelLength = (E_NUM_BITS/8) + extraOctetAdded ; totalLength+= levelLength; numOctetsAdded = appendLengthToBuffer(levelLength, privKeyBuf, &priv_key_ptr); totalLength+=numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, privKeyBuf, &priv_key_ptr); totalLength++; //Adding n extraOctetAdded = addMpz_tToBuffer(n, privKeyBuf, &priv_key_ptr, N_NUM_BITS); levelLength = (N_NUM_BITS/8) + extraOctetAdded ; totalLength+= levelLength; numOctetsAdded = appendLengthToBuffer(levelLength, privKeyBuf, &priv_key_ptr); totalLength+=numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, privKeyBuf, &priv_key_ptr); totalLength++; //Appending version - 0 addNullOctet(privKeyBuf, &priv_key_ptr); totalLength++; numOctetsAdded = appendLengthToBuffer(1, privKeyBuf, &priv_key_ptr); totalLength+=numOctetsAdded; appendIdentifierOctet(TAG_INT, PRIMITIVE, UNIVERSAL, privKeyBuf, &priv_key_ptr); totalLength++; numOctetsAdded = appendLengthToBuffer(totalLength, privKeyBuf, &priv_key_ptr); appendIdentifierOctet(TAG_SEQUENCE, CONSTRUCTED, UNIVERSAL, privKeyBuf, &priv_key_ptr); writeKeyBuffer(priv_out, privKeyBuf, priv_key_ptr +1, PRIV_KEY_BUF_LEN); free(privKeyBuf); } //writeSampleFile(); //free this somewhere return 0; }
/* return in z a lower bound (for rnd = RNDD) or upper bound (for rnd = RNDU) of |zeta(s)|/2, using: log(|zeta(s)|/2) = (s-1)*log(2*Pi) + lngamma(1-s) + log(|sin(Pi*s/2)| * zeta(1-s)). Assumes s < 1/2 and s1 = 1-s exactly, thus s1 > 1/2. y and p are temporary variables. At input, p is Pi rounded down. The comments in the code are for rnd = RNDD. */ static void mpfr_reflection_overflow (mpfr_t z, mpfr_t s1, const mpfr_t s, mpfr_t y, mpfr_t p, mpfr_rnd_t rnd) { mpz_t sint; MPFR_ASSERTD (rnd == MPFR_RNDD || rnd == MPFR_RNDU); /* Since log is increasing, we want lower bounds on |sin(Pi*s/2)| and zeta(1-s). */ mpz_init (sint); mpfr_get_z (sint, s, MPFR_RNDD); /* sint = floor(s) */ /* We first compute a lower bound of |sin(Pi*s/2)|, which is a periodic function of period 2. Thus: if 2k < s < 2k+1, then |sin(Pi*s/2)| is increasing; if 2k-1 < s < 2k, then |sin(Pi*s/2)| is decreasing. These cases are distinguished by testing bit 0 of floor(s) as if represented in two's complement (or equivalently, as an unsigned integer mod 2): 0: sint = 0 mod 2, thus 2k < s < 2k+1 and |sin(Pi*s/2)| is increasing; 1: sint = 1 mod 2, thus 2k-1 < s < 2k and |sin(Pi*s/2)| is decreasing. Let's recall that the comments are for rnd = RNDD. */ if (mpz_tstbit (sint, 0) == 0) /* |sin(Pi*s/2)| is increasing: round down Pi*s to get a lower bound. */ { mpfr_mul (y, p, s, rnd); if (rnd == MPFR_RNDD) mpfr_nextabove (p); /* we will need p rounded above afterwards */ } else /* |sin(Pi*s/2)| is decreasing: round up Pi*s to get a lower bound. */ { if (rnd == MPFR_RNDD) mpfr_nextabove (p); mpfr_mul (y, p, s, MPFR_INVERT_RND(rnd)); } mpfr_div_2ui (y, y, 1, MPFR_RNDN); /* exact, rounding mode doesn't matter */ /* The rounding direction of sin depends on its sign. We have: if -4k-2 < s < -4k, then -2k-1 < s/2 < -2k, thus sin(Pi*s/2) < 0; if -4k < s < -4k+2, then -2k < s/2 < -2k+1, thus sin(Pi*s/2) > 0. These cases are distinguished by testing bit 1 of floor(s) as if represented in two's complement (or equivalently, as an unsigned integer mod 4): 0: sint = {0,1} mod 4, thus -2k < s/2 < -2k+1 and sin(Pi*s/2) > 0; 1: sint = {2,3} mod 4, thus -2k-1 < s/2 < -2k and sin(Pi*s/2) < 0. Let's recall that the comments are for rnd = RNDD. */ if (mpz_tstbit (sint, 1) == 0) /* -2k < s/2 < -2k+1; sin(Pi*s/2) > 0 */ { /* Round sin down to get a lower bound of |sin(Pi*s/2)|. */ mpfr_sin (y, y, rnd); } else /* -2k-1 < s/2 < -2k; sin(Pi*s/2) < 0 */ { /* Round sin up to get a lower bound of |sin(Pi*s/2)|. */ mpfr_sin (y, y, MPFR_INVERT_RND(rnd)); mpfr_abs (y, y, MPFR_RNDN); /* exact, rounding mode doesn't matter */ } mpz_clear (sint); /* now y <= |sin(Pi*s/2)| when rnd=RNDD, y >= |sin(Pi*s/2)| when rnd=RNDU */ mpfr_zeta_pos (z, s1, rnd); /* zeta(1-s) */ mpfr_mul (z, z, y, rnd); /* now z <= |sin(Pi*s/2)|*zeta(1-s) */ mpfr_log (z, z, rnd); /* now z <= log(|sin(Pi*s/2)|*zeta(1-s)) */ mpfr_lngamma (y, s1, rnd); mpfr_add (z, z, y, rnd); /* z <= lngamma(1-s) + log(|sin(Pi*s/2)|*zeta(1-s)) */ /* since s-1 < 0, we want to round log(2*pi) upwards */ mpfr_mul_2ui (y, p, 1, MPFR_INVERT_RND(rnd)); mpfr_log (y, y, MPFR_INVERT_RND(rnd)); mpfr_mul (y, y, s1, MPFR_INVERT_RND(rnd)); mpfr_sub (z, z, y, rnd); mpfr_exp (z, z, rnd); if (rnd == MPFR_RNDD) mpfr_nextbelow (p); /* restore original p */ }
void check_single (void) { mpz_t x; int limb, offset, initial; unsigned long bit; mpz_init (x); for (limb = 0; limb < 4; limb++) { for (offset = (limb==0 ? 0 : -2); offset <= 2; offset++) { for (initial = 0; initial >= -1; initial--) { mpz_set_si (x, (long) initial); bit = (unsigned long) limb*BITS_PER_MP_LIMB + offset; mpz_clrbit (x, bit); MPZ_CHECK_FORMAT (x); if (mpz_tstbit (x, bit) != 0) { printf ("check_single(): expected 0\n"); abort (); } mpz_setbit (x, bit); MPZ_CHECK_FORMAT (x); if (mpz_tstbit (x, bit) != 1) { printf ("check_single(): expected 1\n"); abort (); } mpz_clrbit (x, bit); MPZ_CHECK_FORMAT (x); if (mpz_tstbit (x, bit) != 0) { printf ("check_single(): expected 0\n"); abort (); } mpz_combit (x, bit); MPZ_CHECK_FORMAT (x); if (mpz_tstbit (x, bit) != 1) { printf ("check_single(): expected 1\n"); abort (); } mpz_combit (x, bit); MPZ_CHECK_FORMAT (x); if (mpz_tstbit (x, bit) != 0) { printf ("check_single(): expected 0\n"); abort (); } } } } mpz_clear (x); }
int quadratic_residue(mpz_t x,mpz_t q,mpz_t n) { int leg; mpz_t tmp,ofac,nr,t,r,c,b; unsigned int mod4; mp_bitcnt_t twofac=0,m,i,ix; mod4=mpz_tstbit(n,0); if(!mod4) // must be odd return 0; mod4+=2*mpz_tstbit(n,1); leg=mpz_legendre(q,n); if(leg!=1) return leg; mpz_init_set(tmp,n); if(mod4==3) // directly, x = q^(n+1)/4 mod n { printf("diretamente\n\n"); mpz_add_ui(tmp,tmp,1UL); mpz_tdiv_q_2exp(tmp,tmp,2); mpz_powm(x,q,tmp,n); gmp_printf("NUMERO X %Zd \n\n",x); mpz_clear(tmp); } else // Tonelli-Shanks { printf("Tonelli shanks!!!\n"); mpz_inits(ofac,t,r,c,b,NULL); // split n - 1 into odd number times power of 2 ofac*2^twofac mpz_sub_ui(tmp,tmp,1UL); twofac=mpz_scan1(tmp,twofac); // largest power of 2 divisor if(twofac) mpz_tdiv_q_2exp(ofac,tmp,twofac); // shift right // look for non-residue mpz_init_set_ui(nr,2UL); while(mpz_legendre(nr,n)!=-1) mpz_add_ui(nr,nr,1UL); mpz_powm(c,nr,ofac,n); // c = nr^ofac mod n mpz_add_ui(tmp,ofac,1UL); mpz_tdiv_q_2exp(tmp,tmp,1); mpz_powm(r,q,tmp,n); // r = q^(ofac+1)/2 mod n mpz_powm(t,q,ofac,n); mpz_mod(t,t,n); // t = q^ofac mod n if(mpz_cmp_ui(t,1UL)!=0) // if t = 1 mod n we're done { m=twofac; do { i=2; ix=1; while(ix<m) { // find lowest 0 < ix < m | t^2^ix = 1 mod n mpz_powm_ui(tmp,t,i,n); // repeatedly square t if(mpz_cmp_ui(tmp,1UL)==0) break; i<<=1; // i = 2, 4, 8, ... ix++; // ix is log2 i } mpz_powm_ui(b,c,1<<(m-ix-1),n); // b = c^2^(m-ix-1) mod n mpz_mul(r,r,b); mpz_mod(r,r,n); // r = r*b mod n mpz_mul(c,b,b); mpz_mod(c,c,n); // c = b^2 mod n mpz_mul(t,t,c); mpz_mod(t,t,n); // t = t b^2 mod n m=ix; }while(mpz_cmp_ui(t,1UL)!=0); // while t mod n != 1 } mpz_set(x,r); mpz_clears(tmp,ofac,nr,t,r,c,b,NULL); } return 1; }
static int big_bitp(object x, ufixnum p) { return mpz_tstbit(MP(x),p); }
static void d_pairing_pp_init(pairing_pp_t p, element_ptr in1, pairing_t pairing) { element_ptr P = in1; const element_ptr Px = curve_x_coord(P); const element_ptr Py = curve_y_coord(P); element_t Z; mp_bitcnt_t m; pptr info = pairing->data; element_t t0; element_t a, b, c; field_ptr Fq = info->Fq; pp_coeff_t *coeff; mpz_ptr q = pairing->r; pp_coeff_ptr pp; const element_ptr cca = curve_a_coeff(P); element_ptr Zx; element_ptr Zy; #define store_abc() { \ element_init(pp->a, Fq); \ element_init(pp->b, Fq); \ element_init(pp->c, Fq); \ element_set(pp->a, a); \ element_set(pp->b, b); \ element_set(pp->c, c); \ pp++; \ } #define do_tangent() { \ /* a = -slope_tangent(Z.x, Z.y); */ \ /* b = 1; */ \ /* c = -(Z.y + a * Z.x); */ \ /* but we multiply by 2*Z.y to avoid division. */ \ \ /* a = -Zx * (3 Zx + twicea_2) - a_4; */ \ /* Common curves: a2 = 0 (and cc->a is a_4), so */ \ /* a = -(3 Zx^2 + cc->a) */ \ /* b = 2 * Zy */ \ /* c = -(2 Zy^2 + a Zx); */ \ \ element_square(a, Zx); \ element_double(t0, a); \ element_add(a, a, t0); \ element_add(a, a, cca); \ element_neg(a, a); \ \ element_add(b, Zy, Zy); \ \ element_mul(t0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, t0); \ element_neg(c, c); \ \ store_abc(); \ } #define do_line() { \ /* a = -(B.y - A.y) / (B.x - A.x); */ \ /* b = 1; */ \ /* c = -(A.y + a * A.x); */ \ /* but we'll multiply by B.x - A.x to avoid division */ \ \ element_sub(b, Px, Zx); \ element_sub(a, Zy, Py); \ element_mul(t0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, t0); \ element_neg(c, c); \ \ store_abc(); \ } element_init(Z, P->field); element_set(Z, P); Zx = curve_x_coord(Z); Zy = curve_y_coord(Z); element_init(t0, Fq); element_init(a, Fq); element_init(b, Fq); element_init(c, Fq); m = (mp_bitcnt_t)mpz_sizeinbase(q, 2); m = (m > 2 ? m - 2 : 0); p->data = pbc_malloc(sizeof(pp_coeff_t) * 2 * m); coeff = (pp_coeff_t *) p->data; pp = coeff[0]; for(;;) { do_tangent(); if (!m) break; element_double(Z, Z); if (mpz_tstbit(q, m)) { do_line(); element_add(Z, Z, P); } m--; } element_clear(t0); element_clear(a); element_clear(b); element_clear(c); element_clear(Z); #undef store_abc #undef do_tangent #undef do_line }
//do many millers at one time with affine coordinates. static void cc_millers_no_denom_affine(element_t res, mpz_t q, element_t P[], element_t Qx[], element_t Qy[], int n_prod) { mp_bitcnt_t m; int i; element_t v; element_t a, b, c; element_t t0; element_t e0; const element_ptr cca = curve_a_coeff(P[0]); element_ptr Px, Py; element_t* Z = pbc_malloc(sizeof(element_t)*n_prod); element_ptr Zx, Zy; /* TODO: when exactly is this not needed? void do_vertical() { mapbase(e0, Z->x); element_sub(e0, Qx, e0); element_mul(v, v, e0); } */ #define do_tangents() { \ /* a = -(3 Zx^2 + cc->a) */ \ /* b = 2 * Zy */ \ /* c = -(2 Zy^2 + a Zx); */ \ for(i=0; i<n_prod; i++){ \ Px = curve_x_coord(P[i]); \ Py = curve_y_coord(P[i]); \ Zx = curve_x_coord(Z[i]); \ Zy = curve_y_coord(Z[i]); \ \ element_square(a, Zx); \ element_mul_si(a, a, 3); \ element_add(a, a, cca); \ element_neg(a, a); \ \ element_add(b, Zy, Zy); \ \ element_mul(t0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, t0); \ element_neg(c, c); \ \ d_miller_evalfn(e0, a, b, c, Qx[i], Qy[i]); \ element_mul(v, v, e0); \ } \ } #define do_lines() { \ /* a = -(B.y - A.y) / (B.x - A.x); */ \ /* b = 1; */ \ /* c = -(A.y + a * A.x); */ \ /* but we multiply by B.x - A.x to avoid division. */ \ for(i=0; i<n_prod; i++){ \ Px = curve_x_coord(P[i]); \ Py = curve_y_coord(P[i]); \ Zx = curve_x_coord(Z[i]); \ Zy = curve_y_coord(Z[i]); \ \ element_sub(b, Px, Zx); \ element_sub(a, Zy, Py); \ element_mul(t0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, t0); \ element_neg(c, c); \ \ d_miller_evalfn(e0, a, b, c, Qx[i], Qy[i]); \ element_mul(v, v, e0); \ } \ } Px= curve_x_coord(P[0]); //temporally used to initial a,b, c and etc. element_init(a, Px->field); element_init(b, a->field); element_init(c, a->field); element_init(t0, a->field); element_init(e0, res->field); element_init(v, res->field); for(i=0; i<n_prod; i++){ element_init(Z[i], P[i]->field); element_set(Z[i], P[i]); } element_set1(v); m = (mp_bitcnt_t)mpz_sizeinbase(q, 2); m = (m > 2 ? m - 2 : 0); for(;;) { do_tangents(); if (!m) break; element_multi_double(Z, Z, n_prod); //Z_i=Z_i+Z_i for all i. if (mpz_tstbit(q, m)) { do_lines(); element_multi_add(Z, Z, P, n_prod); //Z_i=Z_i+P_i for all i. } m--; element_square(v, v); } element_set(res, v); element_clear(v); for(i=0; i<n_prod; i++){ element_clear(Z[i]); } pbc_free(Z); element_clear(a); element_clear(b); element_clear(c); element_clear(t0); element_clear(e0); #undef do_tangents #undef do_lines }
// Requires cofactor is even. TODO: This seems to contradict a comment below. // Requires in != out. // Mangles in. static void lucas_even(element_ptr out, element_ptr in, mpz_t cofactor) { if (element_is1(in)) { element_set(out, in); return; } element_t temp; element_init_same_as(temp, out); element_ptr in0 = element_x(in); element_ptr in1 = element_y(in); element_ptr v0 = element_x(out); element_ptr v1 = element_y(out); element_ptr t0 = element_x(temp); element_ptr t1 = element_y(temp); size_t j; element_set_si(t0, 2); element_double(t1, in0); element_set(v0, t0); element_set(v1, t1); j = mpz_sizeinbase(cofactor, 2) - 1; for (;;) { if (!j) { element_mul(v1, v0, v1); element_sub(v1, v1, t1); element_square(v0, v0); element_sub(v0, v0, t0); break; } if (mpz_tstbit(cofactor, j)) { element_mul(v0, v0, v1); element_sub(v0, v0, t1); element_square(v1, v1); element_sub(v1, v1, t0); } else { element_mul(v1, v0, v1); element_sub(v1, v1, t1); element_square(v0, v0); element_sub(v0, v0, t0); } j--; } // Assume cofactor = (q^2 - q + 1) / r is odd // thus v1 = V_k, v0 = V_{k-1} // U = (P v1 - 2 v0) / (P^2 - 4) element_double(v0, v0); element_mul(in0, t1, v1); element_sub(in0, in0, v0); element_square(t1, t1); element_sub(t1, t1, t0); element_sub(t1, t1, t0); element_halve(v0, v1); element_div(v1, in0, t1); element_mul(v1, v1, in1); element_clear(temp); }
int mpfr_cbrt (mpfr_ptr y, mpfr_srcptr x, mp_rnd_t rnd_mode) { mpz_t m; mp_exp_t e, r, sh; mp_prec_t n, size_m, tmp; int inexact, negative; MPFR_SAVE_EXPO_DECL (expo); /* special values */ if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x))) { if (MPFR_IS_NAN (x)) { MPFR_SET_NAN (y); MPFR_RET_NAN; } else if (MPFR_IS_INF (x)) { MPFR_SET_INF (y); MPFR_SET_SAME_SIGN (y, x); MPFR_RET (0); } /* case 0: cbrt(+/- 0) = +/- 0 */ else /* x is necessarily 0 */ { MPFR_ASSERTD (MPFR_IS_ZERO (x)); MPFR_SET_ZERO (y); MPFR_SET_SAME_SIGN (y, x); MPFR_RET (0); } } /* General case */ MPFR_SAVE_EXPO_MARK (expo); mpz_init (m); e = mpfr_get_z_exp (m, x); /* x = m * 2^e */ if ((negative = MPFR_IS_NEG(x))) mpz_neg (m, m); r = e % 3; if (r < 0) r += 3; /* x = (m*2^r) * 2^(e-r) = (m*2^r) * 2^(3*q) */ MPFR_MPZ_SIZEINBASE2 (size_m, m); n = MPFR_PREC (y) + (rnd_mode == GMP_RNDN); /* we want 3*n-2 <= size_m + 3*sh + r <= 3*n i.e. 3*sh + size_m + r <= 3*n */ sh = (3 * (mp_exp_t) n - (mp_exp_t) size_m - r) / 3; sh = 3 * sh + r; if (sh >= 0) { mpz_mul_2exp (m, m, sh); e = e - sh; } else if (r > 0) { mpz_mul_2exp (m, m, r); e = e - r; } /* invariant: x = m*2^e, with e divisible by 3 */ /* we reuse the variable m to store the cube root, since it is not needed any more: we just need to know if the root is exact */ inexact = mpz_root (m, m, 3) == 0; MPFR_MPZ_SIZEINBASE2 (tmp, m); sh = tmp - n; if (sh > 0) /* we have to flush to 0 the last sh bits from m */ { inexact = inexact || ((mp_exp_t) mpz_scan1 (m, 0) < sh); mpz_div_2exp (m, m, sh); e += 3 * sh; } if (inexact) { if (negative) rnd_mode = MPFR_INVERT_RND (rnd_mode); if (rnd_mode == GMP_RNDU || (rnd_mode == GMP_RNDN && mpz_tstbit (m, 0))) inexact = 1, mpz_add_ui (m, m, 1); else inexact = -1; } /* either inexact is not zero, and the conversion is exact, i.e. inexact is not changed; or inexact=0, and inexact is set only when rnd_mode=GMP_RNDN and bit (n+1) from m is 1 */ inexact += mpfr_set_z (y, m, GMP_RNDN); MPFR_SET_EXP (y, MPFR_GET_EXP (y) + e / 3); if (negative) { MPFR_CHANGE_SIGN (y); inexact = -inexact; } mpz_clear (m); MPFR_SAVE_EXPO_FREE (expo); return mpfr_check_range (y, inexact, rnd_mode); }
void find_candidates(mpz_t num, mpz_t gmp_root) { num_cands = 0; mpz_add_ui(gmp_root, gmp_root, 1); size_t sieve_size = primes[B-1]*100; double *table = malloc(sizeof(double)*sieve_size); uint64_t root = mpz_get_ui(gmp_root); double approx = mpz_get_d(num); mpz_t tmp, tmp2; mpz_init(tmp); mpz_init(tmp2); mpz_set_ui(tmp, root); mpz_pow_ui(tmp, tmp, 2); mpz_sub(tmp, tmp, num); mpz_set(first_cands[0], tmp); unsigned int used_primes[B]; double used_log[B]; used_primes[0] = 2; used_log[0] = log_primes[0]; size_t next_prime = 1; size_t offsets[B][2]; uint64_t cand_offsets[B+1]; size_t next_cand = 1; // Find prime numbers that appear in the candidate series for(size_t p = 1; p < B; ++p) { unsigned int prime = primes[p]; mpz_set_ui(tmp2, prime); mpz_powm_ui(tmp, num, (prime-1)/2, tmp2); if(mpz_cmp_ui(tmp, 1)) // Skip non-quadratic residues continue; used_primes[next_prime] = prime; used_log[next_prime] = log_primes[p]; // Generate more exact candidates for(int i = next_cand; i < prime; ++i) { mpz_set_ui(tmp, root + i); mpz_pow_ui(tmp, tmp, 2); mpz_sub(tmp, tmp, num); mpz_set(first_cands[i], tmp); } next_cand = prime; // find offsets for them // TODO Shanks-tonelli unsigned int foo = tonelli_shanks(num, prime); printf("root for %u is %u and %u\n", prime, foo, prime-foo); size_t idx = 0; for(int i = 0; i < prime; ++i) { if(mpz_divisible_ui_p(first_cands[i], prime)) { offsets[next_prime][idx++] = i; if(idx == 2) break; } } assert(idx == 2); ++next_prime; } // sieve until we find more than B candidates, guarantees linear dependence size_t sieve_offset = 0; while(num_cands <= B) { for(size_t i = 0; i < sieve_size; ++i) { double d = root + i; d += sieve_offset; table[i] = log(d*d-approx); } // cross out even ones for(size_t i = mpz_tstbit(tmp, 1)^(sieve_offset & 1); i < sieve_size; i+=2) table[i] -= log_primes[0]; for(int p = 1; p < next_prime && num_cands <= B; ++p) { unsigned int prime = used_primes[p]; double log_prime = used_log[p]; // fprintf(stderr, "offsets[%d] are %d and %d\n", used_primes[p], offsets[p][0], offsets[p][1]); for(int x = 0; x < 2; ++x) { size_t off = (offsets[p][x] + sieve_offset + prime-1) % prime; for(int a = off; a < sieve_size; a += prime) { table[a] -= log_prime; if(table[a] > LIMIT) continue; cand_offsets[num_cands++] = root + a + sieve_offset; if(num_cands > B) break; } } } sieve_offset += sieve_size; } for(size_t i = 0; i < num_cands; ++i) { //fprintf(stderr, "%llu\n", cand_offsets[i]); // TODO REMOVE VERY SLOW STUFF mpz_set_ui(tmp, root + i); mpz_pow_ui(tmp, tmp, 2); mpz_sub(tmp, tmp, num); // mpz_out_str(stderr, 10, tmp); // fputc('\n', stderr); } fprintf(stderr, "%d used candidates\n", num_cands); free(table); mpz_clear(tmp); mpz_clear(tmp2); }
static void miller(element_t res, element_t P, element_t Q, element_t R, int n) { //collate divisions mp_bitcnt_t m; element_t v, vd; element_t Z; element_t a, b, c; element_t e0, e1; mpz_t q; element_ptr Zx, Zy; const element_ptr Px = curve_x_coord(P); const element_ptr Py = curve_y_coord(P); const element_ptr numx = curve_x_coord(Q); const element_ptr numy = curve_y_coord(Q); const element_ptr denomx = curve_x_coord(R); const element_ptr denomy = curve_y_coord(R); #define do_vertical(e, edenom) { \ element_sub(e0, numx, Zx); \ element_mul((e), (e), e0); \ \ element_sub(e0, denomx, Zx); \ element_mul((edenom), (edenom), e0); \ } #define do_tangent(e, edenom) { \ /*a = -slope_tangent(A.x, A.y); \ b = 1; \ c = -(A.y + a * A.x); \ but we multiply by 2*A.y to avoid division \ \ a = -Ax * (Ax + Ax + Ax + twicea_2) - a_4; \ This curve is special: \ a = -(3 Ax^2 + 2Ax) \ b = 2 * Ay \ c = -(2 Ay^2 + a Ax); */ \ \ if (element_is0(Zy)) { \ do_vertical((e), (edenom)); \ } else { \ element_square(a, Zx); \ element_mul_si(a, a, 3); \ element_add(a, a, Zx); \ element_add(a, a, Zx); \ element_neg(a, a); \ \ element_add(b, Zy, Zy); \ \ element_mul(e0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, e0); \ element_neg(c, c); \ \ element_mul(e0, a, numx); \ element_mul(e1, b, numy); \ element_add(e0, e0, e1); \ element_add(e0, e0, c); \ element_mul((e), (e), e0); \ \ element_mul(e0, a, denomx); \ element_mul(e1, b, denomy); \ element_add(e0, e0, e1); \ element_add(e0, e0, c); \ element_mul((edenom), (edenom), e0); \ } \ } #define do_line(e, edenom) { \ if (!element_cmp(Zx, Px)) { \ if (!element_cmp(Zy, Py)) { \ do_tangent((e), (edenom)); \ } else { \ do_vertical((e), (edenom)); \ } \ } else { \ element_sub(b, Px, Zx); \ element_sub(a, Zy, Py); \ element_mul(c, Zx, Py); \ element_mul(e0, Zy, Px); \ element_sub(c, c, e0); \ \ element_mul(e0, a, numx); \ element_mul(e1, b, numy); \ element_add(e0, e0, e1); \ element_add(e0, e0, c); \ element_mul((e), (e), e0); \ \ element_mul(e0, a, denomx); \ element_mul(e1, b, denomy); \ element_add(e0, e0, e1); \ element_add(e0, e0, c); \ element_mul((edenom), (edenom), e0); \ } \ } element_init(a, res->field); element_init(b, res->field); element_init(c, res->field); element_init(e0, res->field); element_init(e1, res->field); element_init(v, res->field); element_init(vd, res->field); element_init(Z, P->field); element_set(Z, P); Zx = curve_x_coord(Z); Zy = curve_y_coord(Z); element_set1(v); element_set1(vd); mpz_init(q); mpz_set_ui(q, n); m = (mp_bitcnt_t)mpz_sizeinbase(q, 2); m = (m > 2 ? m - 2 : 0); for (;;) { element_square(v, v); element_square(vd, vd); do_tangent(v, vd); element_double(Z, Z); do_vertical(vd, v); if (mpz_tstbit(q, m)) { do_line(v, vd); element_add(Z, Z, P); if (m) { do_vertical(vd, v); } } if (!m) break; m--; } mpz_clear(q); element_invert(vd, vd); element_mul(res, v, vd); element_clear(v); element_clear(vd); element_clear(Z); element_clear(a); element_clear(b); element_clear(c); element_clear(e0); element_clear(e1); #undef do_vertical #undef do_tangent #undef do_line }
int mpfr_grandom (mpfr_ptr rop1, mpfr_ptr rop2, gmp_randstate_t rstate, mpfr_rnd_t rnd) { int inex1, inex2, s1, s2; mpz_t x, y, xp, yp, t, a, b, s; mpfr_t sfr, l, r1, r2; mpfr_prec_t tprec, tprec0; inex2 = inex1 = 0; if (rop2 == NULL) /* only one output requested. */ { tprec0 = MPFR_PREC (rop1); } else { tprec0 = MAX (MPFR_PREC (rop1), MPFR_PREC (rop2)); } tprec0 += 11; /* We use "Marsaglia polar method" here (cf. George Marsaglia, Normal (Gaussian) random variables for supercomputers The Journal of Supercomputing, Volume 5, Number 1, 49–55 DOI: 10.1007/BF00155857). First we draw uniform x and y in [0,1] using mpz_urandomb (in fixed precision), and scale them to [-1, 1]. */ mpz_init (xp); mpz_init (yp); mpz_init (x); mpz_init (y); mpz_init (t); mpz_init (s); mpz_init (a); mpz_init (b); mpfr_init2 (sfr, MPFR_PREC_MIN); mpfr_init2 (l, MPFR_PREC_MIN); mpfr_init2 (r1, MPFR_PREC_MIN); if (rop2 != NULL) mpfr_init2 (r2, MPFR_PREC_MIN); mpz_set_ui (xp, 0); mpz_set_ui (yp, 0); for (;;) { tprec = tprec0; do { mpz_urandomb (xp, rstate, tprec); mpz_urandomb (yp, rstate, tprec); mpz_mul (a, xp, xp); mpz_mul (b, yp, yp); mpz_add (s, a, b); } while (mpz_sizeinbase (s, 2) > tprec * 2); /* x^2 + y^2 <= 2^{2tprec} */ for (;;) { /* FIXME: compute s as s += 2x + 2y + 2 */ mpz_add_ui (a, xp, 1); mpz_add_ui (b, yp, 1); mpz_mul (a, a, a); mpz_mul (b, b, b); mpz_add (s, a, b); if ((mpz_sizeinbase (s, 2) <= 2 * tprec) || ((mpz_sizeinbase (s, 2) == 2 * tprec + 1) && (mpz_scan1 (s, 0) == 2 * tprec))) goto yeepee; /* Extend by 32 bits */ mpz_mul_2exp (xp, xp, 32); mpz_mul_2exp (yp, yp, 32); mpz_urandomb (x, rstate, 32); mpz_urandomb (y, rstate, 32); mpz_add (xp, xp, x); mpz_add (yp, yp, y); tprec += 32; mpz_mul (a, xp, xp); mpz_mul (b, yp, yp); mpz_add (s, a, b); if (mpz_sizeinbase (s, 2) > tprec * 2) break; } } yeepee: /* FIXME: compute s with s -= 2x + 2y + 2 */ mpz_mul (a, xp, xp); mpz_mul (b, yp, yp); mpz_add (s, a, b); /* Compute the signs of the output */ mpz_urandomb (x, rstate, 2); s1 = mpz_tstbit (x, 0); s2 = mpz_tstbit (x, 1); for (;;) { /* s = xp^2 + yp^2 (loop invariant) */ mpfr_set_prec (sfr, 2 * tprec); mpfr_set_prec (l, tprec); mpfr_set_z (sfr, s, MPFR_RNDN); /* exact */ mpfr_mul_2si (sfr, sfr, -2 * tprec, MPFR_RNDN); /* exact */ mpfr_log (l, sfr, MPFR_RNDN); mpfr_neg (l, l, MPFR_RNDN); mpfr_mul_2si (l, l, 1, MPFR_RNDN); mpfr_div (l, l, sfr, MPFR_RNDN); mpfr_sqrt (l, l, MPFR_RNDN); mpfr_set_prec (r1, tprec); mpfr_mul_z (r1, l, xp, MPFR_RNDN); mpfr_div_2ui (r1, r1, tprec, MPFR_RNDN); /* exact */ if (s1) mpfr_neg (r1, r1, MPFR_RNDN); if (MPFR_CAN_ROUND (r1, tprec - 2, MPFR_PREC (rop1), rnd)) { if (rop2 != NULL) { mpfr_set_prec (r2, tprec); mpfr_mul_z (r2, l, yp, MPFR_RNDN); mpfr_div_2ui (r2, r2, tprec, MPFR_RNDN); /* exact */ if (s2) mpfr_neg (r2, r2, MPFR_RNDN); if (MPFR_CAN_ROUND (r2, tprec - 2, MPFR_PREC (rop2), rnd)) break; } else break; } /* Extend by 32 bits */ mpz_mul_2exp (xp, xp, 32); mpz_mul_2exp (yp, yp, 32); mpz_urandomb (x, rstate, 32); mpz_urandomb (y, rstate, 32); mpz_add (xp, xp, x); mpz_add (yp, yp, y); tprec += 32; mpz_mul (a, xp, xp); mpz_mul (b, yp, yp); mpz_add (s, a, b); } inex1 = mpfr_set (rop1, r1, rnd); if (rop2 != NULL) { inex2 = mpfr_set (rop2, r2, rnd); inex2 = mpfr_check_range (rop2, inex2, rnd); } inex1 = mpfr_check_range (rop1, inex1, rnd); if (rop2 != NULL) mpfr_clear (r2); mpfr_clear (r1); mpfr_clear (l); mpfr_clear (sfr); mpz_clear (b); mpz_clear (a); mpz_clear (s); mpz_clear (t); mpz_clear (y); mpz_clear (x); mpz_clear (yp); mpz_clear (xp); return INEX (inex1, inex2); }
/* assuming slaves (workers)) are all homogenous, let them all do the calculations regarding primes sieving, calculating the smoothness base and the modular roots */ int main(int argc, char **argv) { MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); MPI_Comm_size(MPI_COMM_WORLD, &mpi_group_size); int len; MPI_Get_processor_name(processor_name, &len); gettimeofday(&start_global, NULL); print_lib_version(); mpz_init(N); mpz_t B; mpz_init(B); unsigned long int uBase; int64_t nb_primes; modular_root_t *modular_roots; uint64_t i, j; if (argc < 2) { PRINT(my_rank, "usage: %s Number_to_factorize\n", argv[0]); exit(2); } if (mpz_init_set_str(N, argv[1], 10) == -1) { PRINT(my_rank, "Cannot load N %s\n", argv[1]); exit(2); } mpz_t sqrtN, rem; mpz_init(sqrtN); mpz_init(rem); mpz_sqrtrem(sqrtN, rem, N); if (mpz_cmp_ui(rem, 0) != 0) /* if not perfect square, calculate the ceiling */ mpz_add_ui(sqrtN, sqrtN, 1); else /* N is a perfect square, factored! */ { PRINT(my_rank, "\n<<<[FACTOR]>>> %s\n", mpz_get_str(NULL, 10, sqrtN)); return 0; } if (mpz_probab_prime_p(N, 10) > 0) /* don't bother factoring */ { PRINT(my_rank, "N:%s is prime\n", mpz_get_str(NULL, 10, N)); exit(0); } OPEN_LOG_FILE("freq"); //-------------------------------------------------------- // calculate the smoothness base for the given N //-------------------------------------------------------- get_smoothness_base(B, N); /* if N is too small, the program will surely fail, please consider a pen and paper instead */ uBase = mpz_get_ui(B); PRINT(my_rank, "n: %s\tBase: %s\n", mpz_get_str(NULL, 10, N), mpz_get_str(NULL, 10, B)); //-------------------------------------------------------- // sieve primes that are less than the smoothness base using Eratosthenes sieve //-------------------------------------------------------- START_TIMER(); nb_primes = sieve_primes_up_to((int64_t) (uBase)); PRINT(my_rank, "\tPrimes found %" PRId64 " [Smoothness Base %lu]\n", nb_primes, uBase); STOP_TIMER_PRINT_TIME("\tEratosthenes Sieving done"); //-------------------------------------------------------- // fill the primes array with primes to which n is a quadratic residue //-------------------------------------------------------- START_TIMER(); primes = calloc(nb_primes, sizeof(int64_t)); nb_qr_primes = fill_primes_with_quadratic_residue(primes, N); /*for(i=0; i<nb_qr_primes; i++) PRINT(my_rank, "%" PRId64 "\n", primes[i]);*/ PRINT(my_rank, "\tN-Quadratic primes found %" PRId64 "\n", nb_qr_primes); STOP_TIMER_PRINT_TIME("\tQuadratic prime filtering done"); //-------------------------------------------------------- // calculate modular roots //-------------------------------------------------------- START_TIMER(); modular_roots = calloc(nb_qr_primes, sizeof(modular_root_t)); mpz_t tmp, r1, r2; mpz_init(tmp); mpz_init(r1); mpz_init(r2); for (i = 0; i < nb_qr_primes; i++) { mpz_set_ui(tmp, (unsigned long) primes[i]); mpz_sqrtm(r1, N, tmp); /* calculate the modular root */ mpz_neg(r2, r1); /* -q mod n */ mpz_mod(r2, r2, tmp); modular_roots[i].root1 = mpz_get_ui(r1); modular_roots[i].root2 = mpz_get_ui(r2); } mpz_clear(tmp); mpz_clear(r1); mpz_clear(r2); STOP_TIMER_PRINT_TIME("Modular roots calculation done"); //-------------------------------------------------------- // ***** initialize the matrix ***** //-------------------------------------------------------- if (my_rank == 0) /* only the master have the matrix */ { START_TIMER(); init_matrix(&matrix, nb_qr_primes + NB_VECTORS_OFFSET, nb_qr_primes); mpz_init2(tmp_matrix_row, nb_qr_primes); STOP_TIMER_PRINT_TIME("Matrix initialized"); } //-------------------------------------------------------- // [Sieving] - everyones sieves including the master //-------------------------------------------------------- START_TIMER(); mpz_t x, sieving_index, next_sieving_index, relative_start, global_step; unsigned long ui_index, SIEVING_STEP = 50000; /* we sieve for 50000 elements at each loop */ int LOCAL_SIEVING_ROUNDS = 10; /* number of iterations a worker sieves before communicating results to the master */ unsigned long sieving_round = 0; unsigned long nb_big_rounds = 0; uint64_t p_pow; smooth_number_t *x_squared; x_squared = calloc(SIEVING_STEP, sizeof(smooth_number_t)); if (my_rank == 0) smooth_numbers = calloc(nb_qr_primes + NB_VECTORS_OFFSET, sizeof(smooth_number_t)); else temp_slaves_smooth_numbers = calloc(500, sizeof(smooth_number_t)); /* TODO: this is not properly correct, using a linkedlist is better to keep track of temporary * smooth numbers at the slaves nodes however it's pretty rare to find 500 smooth numbers in * 50000 * 10 interval. */ mpz_init_set(x, sqrtN); mpz_init(global_step); mpz_init(relative_start); mpz_init(sieving_index); mpz_init(next_sieving_index); mpz_t p; mpz_init(p); mpz_t str; mpz_init_set(str, sieving_index); PRINT(my_rank, "\n[%s] Sieving ...\n", processor_name); //-------------------------------------------------------- // Init before sieving //-------------------------------------------------------- for (i = 0; i < SIEVING_STEP; i++) { mpz_init(x_squared[i].value_x); mpz_init(x_squared[i].value_x_squared); mpz_init2(x_squared[i].factors_vect, nb_qr_primes); mpz_add_ui(x, x, 1); } int nb_smooth_per_round = 0; char s[512]; //-------------------------------------------------------- // WHILE smooth numbers found less than the primes in the smooth base + NB_VECTORS_OFFSET for master // Or master asked for more smooth numbers from slaves //-------------------------------------------------------- while (1) { mpz_set_ui(global_step, nb_big_rounds); /* calculates the coordinate where the workers start sieving from */ mpz_mul_ui(global_step, global_step, (unsigned long) mpi_group_size); mpz_mul_ui(global_step, global_step, SIEVING_STEP); mpz_mul_ui(global_step, global_step, LOCAL_SIEVING_ROUNDS); mpz_add(global_step, global_step, sqrtN); mpz_set_ui(relative_start, SIEVING_STEP); mpz_mul_ui(relative_start, relative_start, LOCAL_SIEVING_ROUNDS); mpz_mul_ui(relative_start, relative_start, (unsigned long) my_rank); mpz_add(relative_start, relative_start, global_step); mpz_set(sieving_index, relative_start); mpz_set(next_sieving_index, relative_start); for (sieving_round = 0; sieving_round < LOCAL_SIEVING_ROUNDS; /* each slave sieves for LOCAL_SIEVING_ROUNDS rounds */ sieving_round++) { nb_smooth_per_round = 0; mpz_set(x, next_sieving_index); /* sieve numbers from sieving_index to sieving_index + sieving_step */ mpz_set(sieving_index, next_sieving_index); if (my_rank == 0) { printf("\r"); printf( "\t\tSieving at: %s30 <--> Smooth numbers found: %" PRId64 "/%" PRId64 "", mpz_get_str(NULL, 10, sieving_index), nb_global_smooth_numbers_found, nb_qr_primes); fflush(stdout); } for (i = 0; i < SIEVING_STEP; i++) { mpz_set(x_squared[i].value_x, x); mpz_pow_ui(x_squared[i].value_x_squared, x, 2); /* calculate value_x_squared <- x²-n */ mpz_sub(x_squared[i].value_x_squared, x_squared[i].value_x_squared, N); mpz_clear(x_squared[i].factors_vect); mpz_init2(x_squared[i].factors_vect, nb_qr_primes); /* reconstruct a new fresh 0ed vector of size nb_qr_primes bits */ mpz_add_ui(x, x, 1); } mpz_set(next_sieving_index, x); //-------------------------------------------------------- // eliminate factors in the x_squared array, those who are 'destructed' to 1 are smooth //-------------------------------------------------------- for (i = 0; i < nb_qr_primes; i++) { mpz_set_ui(p, (unsigned long) primes[i]); mpz_set(x, sieving_index); /* get the first multiple of p that is directly larger that sieving_index * Quadratic SIEVING: all elements from this number and in positions multiples of root1 and root2 * are also multiples of p */ get_sieving_start_index(x, x, p, modular_roots[i].root1); mpz_set(str, x); mpz_sub(x, x, sieving_index); /* x contains index of first number that is divisible by p */ for (j = mpz_get_ui(x); j < SIEVING_STEP; j += primes[i]) { p_pow = mpz_remove(x_squared[j].value_x_squared, x_squared[j].value_x_squared, p); /* eliminate all factors of p */ if (p_pow & 1) /* mark bit if odd power of p exists in this x_squared[j] */ { mpz_setbit(x_squared[j].factors_vect, i); } if (mpz_cmp_ui(x_squared[j].value_x_squared, 1) == 0) { save_smooth_number(x_squared[j]); nb_smooth_per_round++; } /* sieve next element located p steps from here */ } /* same goes for root2 */ if (modular_roots[i].root2 == modular_roots[i].root1) continue; mpz_set(x, sieving_index); get_sieving_start_index(x, x, p, modular_roots[i].root2); mpz_set(str, x); mpz_sub(x, x, sieving_index); for (j = mpz_get_ui(x); j < SIEVING_STEP; j += primes[i]) { p_pow = mpz_remove(x_squared[j].value_x_squared, x_squared[j].value_x_squared, p); if (p_pow & 1) { mpz_setbit(x_squared[j].factors_vect, i); } if (mpz_cmp_ui(x_squared[j].value_x_squared, 1) == 0) { save_smooth_number(x_squared[j]); nb_smooth_per_round++; } } } } if (my_rank == 0) /* master gathers smooth numbers from slaves */ { gather_smooth_numbers(); notify_slaves(); } else /* slaves send their smooth numbers to master */ { send_smooth_numbers_to_master(); nb_global_smooth_numbers_found = get_server_notification(); } if (nb_global_smooth_numbers_found >= nb_qr_primes + NB_VECTORS_OFFSET) break; nb_big_rounds++; } STOP_TIMER_PRINT_TIME("\nSieving DONE"); if (my_rank == 0) { uint64_t t = 0; //-------------------------------------------------------- //the matrix ready, start Gauss elimination. The Matrix is filled on the call of save_smooth_number() //-------------------------------------------------------- START_TIMER(); gauss_elimination(&matrix); STOP_TIMER_PRINT_TIME("\nGauss elimination done"); uint64_t row_index = nb_qr_primes + NB_VECTORS_OFFSET - 1; /* last row in the matrix */ int nb_linear_relations = 0; mpz_t linear_relation_z, solution_z; mpz_init(linear_relation_z); mpz_init(solution_z); get_matrix_row(linear_relation_z, &matrix, row_index--); /* get the last few rows in the Gauss eliminated matrix*/ while (mpz_cmp_ui(linear_relation_z, 0) == 0) { nb_linear_relations++; get_matrix_row(linear_relation_z, &matrix, row_index--); } PRINT(my_rank, "\tLinear dependent relations found : %d\n", nb_linear_relations); //-------------------------------------------------------- // Factor //-------------------------------------------------------- //We use the last linear relation to reconstruct our solution START_TIMER(); PRINT(my_rank, "%s", "\nFactorizing..\n"); mpz_t solution_X, solution_Y; mpz_init(solution_X); mpz_init(solution_Y); /* we start testing from the first linear relation encountered in the matrix */ for (j = nb_linear_relations; j > 0; j--) { PRINT(my_rank, "Trying %d..\n", nb_linear_relations - j + 1); mpz_set_ui(solution_X, 1); mpz_set_ui(solution_Y, 1); get_identity_row(solution_z, &matrix, nb_qr_primes + NB_VECTORS_OFFSET - j + 1); for (i = 0; i < nb_qr_primes; i++) { if (mpz_tstbit(solution_z, i)) { mpz_mul(solution_X, solution_X, smooth_numbers[i].value_x); mpz_mod(solution_X, solution_X, N); /* reduce x to modulo N */ mpz_mul(solution_Y, solution_Y, smooth_numbers[i].value_x_squared); /*TODO: handling huge stuff here, there is no modulo N like in the solution_X case! * eliminate squares as long as you go*/ } } mpz_sqrt(solution_Y, solution_Y); mpz_mod(solution_Y, solution_Y, N); /* y = sqrt(MUL(xi²-n)) mod N */ mpz_sub(solution_X, solution_X, solution_Y); mpz_gcd(solution_X, solution_X, N); if (mpz_cmp(solution_X, N) != 0 && mpz_cmp_ui(solution_X, 1) != 0) /* factor can be 1 or N, try another relation */ break; } mpz_cdiv_q(solution_Y, N, solution_X); PRINT(my_rank, "\n>>>>>>>>>>> FACTORED %s =\n", mpz_get_str(NULL, 10, N)); PRINT( my_rank, "\tFactor 1: %s \n\tFactor 2: %s", mpz_get_str(NULL, 10, solution_X), mpz_get_str(NULL, 10, solution_Y)); sprintf(s, "\n>>>>>>>>>>> FACTORED %s =\n", mpz_get_str(NULL, 10, N)); APPEND_TO_LOG_FILE(s); sprintf(s, "\tFactor 1: %s \n\tFactor 2: %s", mpz_get_str(NULL, 10, solution_X), mpz_get_str(NULL, 10, solution_Y)); APPEND_TO_LOG_FILE(s); gettimeofday(&end_global, NULL); timersub(&end_global, &start_global, &elapsed); sprintf(s, "****** TOTAL TIME: %.3f ms\n", elapsed.tv_sec * 1000 + elapsed.tv_usec / (double) 1000); APPEND_TO_LOG_FILE(s); STOP_TIMER_PRINT_TIME("\nFactorizing done"); } PRINT(my_rank, "%s", "\nCleaning memory..\n"); /********************** clear the x_squared array **********************/ for (i = 0; i < SIEVING_STEP; i++) { mpz_clear(x_squared[i].value_x); mpz_clear(x_squared[i].value_x_squared); //free(x_squared[i].factors_exp); mpz_clear(x_squared[i].factors_vect); } free(x_squared); /********************** clear the x_squared array **********************/ free(modular_roots); /********************** clear the smooth_numbers array **********************/ if (my_rank == 0) { for (i = 0; i < nb_qr_primes + NB_VECTORS_OFFSET; i++) { mpz_clear(smooth_numbers[i].value_x); mpz_clear(smooth_numbers[i].value_x_squared); mpz_clear(smooth_numbers[i].factors_vect); //free(smooth_numbers[i].factors_exp); } free(smooth_numbers); } else { for (i = 0; i < 500; i++) { mpz_clear(temp_slaves_smooth_numbers[i].value_x); mpz_clear(temp_slaves_smooth_numbers[i].value_x_squared); mpz_clear(temp_slaves_smooth_numbers[i].factors_vect); } free(temp_slaves_smooth_numbers); } /********************** clear the smooth_numbers array **********************/ free(primes); /********************** clear mpz _t **********************/mpz_clear(B); mpz_clear(N); sqrtN, rem; mpz_clear(x); mpz_clear(sieving_index); mpz_clear(next_sieving_index); mpz_clear(p); mpz_clear(str); /********************** clear mpz _t **********************/ free_matrix(&matrix); gettimeofday(&end_global, NULL); timersub(&end_global, &start_global, &elapsed); PRINT(my_rank, "****** TOTAL TIME: %.3f ms\n", elapsed.tv_sec * 1000 + elapsed.tv_usec / (double) 1000); show_mem_usage(); MPI_Finalize(); return 0; }
/* This generates p,q params using the B.3.2.2 algorithm in FIPS 186-4. * * The hash function used is SHA384. * The exponent e used is the value in pub->e. */ int _rsa_generate_fips186_4_keypair(struct rsa_public_key *pub, struct rsa_private_key *key, unsigned seed_length, uint8_t * seed, void *progress_ctx, nettle_progress_func * progress, /* Desired size of modulo, in bits */ unsigned n_size) { mpz_t t, r, p1, q1, lcm; int ret; struct dss_params_validation_seeds cert; unsigned l = n_size / 2; FIPS_RULE(n_size == 2048 && seed_length != 14 * 2, 0, "seed length other than 28 bytes\n"); FIPS_RULE(n_size == 3072 && seed_length != 16 * 2, 0, "seed length other than 32 bytes\n"); FIPS_RULE(n_size != 2048 && n_size != 3072, 0, "unsupported size for modulus\n"); if (!mpz_tstbit(pub->e, 0)) { _gnutls_debug_log("Unacceptable e (it is even)\n"); return 0; } if (mpz_cmp_ui(pub->e, 65536) <= 0) { _gnutls_debug_log("Unacceptable e\n"); return 0; } mpz_init(p1); mpz_init(q1); mpz_init(lcm); mpz_init(t); mpz_init(r); mpz_set_ui(t, 1); mpz_mul_2exp(t, t, 256); if (mpz_cmp(pub->e, t) >= 0) { ret = 0; goto cleanup; } cert.pseed_length = sizeof(cert.pseed); ret = rsa_provable_prime(key->p, &cert.pseed_length, cert.pseed, l, seed_length, seed, pub->e, progress_ctx, progress); if (ret == 0) { goto cleanup; } mpz_set_ui(r, 1); mpz_mul_2exp(r, r, (l) - 100); do { cert.qseed_length = sizeof(cert.qseed); ret = rsa_provable_prime(key->q, &cert.qseed_length, cert.qseed, l, cert.pseed_length, cert.pseed, pub->e, progress_ctx, progress); if (ret == 0) { goto cleanup; } cert.pseed_length = cert.qseed_length; memcpy(cert.pseed, cert.qseed, cert.qseed_length); if (mpz_cmp(key->p, key->q) > 0) mpz_sub(t, key->p, key->q); else mpz_sub(t, key->q, key->p); } while (mpz_cmp(t, r) <= 0); memset(&cert, 0, sizeof(cert)); mpz_mul(pub->n, key->p, key->q); if (mpz_sizeinbase(pub->n, 2) != n_size) { ret = 0; goto cleanup; } /* c = q^{-1} (mod p) */ if (mpz_invert(key->c, key->q, key->p) == 0) { ret = 0; goto cleanup; } mpz_sub_ui(p1, key->p, 1); mpz_sub_ui(q1, key->q, 1); mpz_lcm(lcm, p1, q1); if (mpz_invert(key->d, pub->e, lcm) == 0) { ret = 0; goto cleanup; } /* check whether d > 2^(nlen/2) -- FIPS186-4 5.3.1 */ if (mpz_sizeinbase(key->d, 2) < n_size/2) { ret = 0; goto cleanup; } /* Done! Almost, we must compute the auxiliary private values. */ /* a = d % (p-1) */ mpz_fdiv_r(key->a, key->d, p1); /* b = d % (q-1) */ mpz_fdiv_r(key->b, key->d, q1); /* c was computed earlier */ pub->size = key->size = (n_size + 7) / 8; if (pub->size < RSA_MINIMUM_N_OCTETS) { ret = 0; goto cleanup; } ret = 1; cleanup: mpz_clear(p1); mpz_clear(q1); mpz_clear(lcm); mpz_clear(t); mpz_clear(r); return ret; }
static PyObject * GMPY_mpz_lucasv(PyObject *self, PyObject *args) { /* Adaptation of algorithm found in http://joye.site88.net/papers/JQ96lucas.pdf * calculate v[k] of Lucas V sequence for p,q. * Note: p^2-4q=0 is not tested, not a proper Lucas sequence!! */ MPZ_Object *result = 0, *p, *q, *k; size_t s = 0, j = 0; mpz_t vl, vh, ql, qh, tmp; if (PyTuple_Size(args) != 3) { TYPE_ERROR("lucasv() requires 3 integer arguments"); return NULL; } mpz_init(vl); mpz_init(vh); mpz_init(ql); mpz_init(qh); mpz_init(tmp); p = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL); q = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL); k = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 2), NULL); if (!p || !q || !k) { TYPE_ERROR("lucasv() requires 3 integer arguments"); goto cleanup; } /* Check if p*p - 4*q == 0. */ mpz_mul(tmp, p->z, p->z); mpz_mul_ui(qh, q->z, 4); mpz_sub(tmp, tmp, qh); if (mpz_sgn(tmp) == 0) { VALUE_ERROR("invalid values for p,q in lucasv()"); goto cleanup; } /* Check if k < 0. */ if (mpz_sgn(k->z) < 0) { VALUE_ERROR("invalid value for k in lucasv()"); goto cleanup; } mpz_set_si(vl, 2); mpz_set(vh, p->z); mpz_set_si(ql, 1); mpz_set_si(qh, 1); mpz_set_si(tmp,0); s = mpz_scan1(k->z, 0); for (j = mpz_sizeinbase(k->z,2)-1; j >= s+1; j--) { /* ql = ql*qh */ mpz_mul(ql, ql, qh); if (mpz_tstbit(k->z,j) == 1) { /* qh = ql*q */ mpz_mul(qh, ql, q->z); /* vl = vh*vl - p*ql */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); /* vh = vh*vh - 2*qh */ mpz_mul(vh, vh, vh); mpz_mul_si(tmp, qh, 2); mpz_sub(vh, vh, tmp); } else { /* qh = ql */ mpz_set(qh, ql); /* vh = vh*vl - p*ql */ mpz_mul(vh, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vh, vh, tmp); /* vl = vl*vl - 2*ql */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); } } /* ql = ql*qh */ mpz_mul(ql, ql, qh); /* qh = ql*q */ mpz_mul(qh, ql, q->z); /* vl = vh*vl - p*ql */ mpz_mul(vl, vh, vl); mpz_mul(tmp, ql, p->z); mpz_sub(vl, vl, tmp); /* ql = ql*qh */ mpz_mul(ql, ql, qh); for (j = 1; j <= s; j++) { /* vl = vl*vl - 2*ql */ mpz_mul(vl, vl, vl); mpz_mul_si(tmp, ql, 2); mpz_sub(vl, vl, tmp); /* ql = ql*ql */ mpz_mul(ql, ql, ql); } if (!(result = GMPy_MPZ_New(NULL))) goto cleanup; /* vl contains our return value */ mpz_set(result->z, vl); cleanup: mpz_clear(vl); mpz_clear(vh); mpz_clear(ql); mpz_clear(qh); mpz_clear(tmp); Py_XDECREF((PyObject*)p); Py_XDECREF((PyObject*)q); Py_XDECREF((PyObject*)k); return (PyObject*)result; }
/* For now we don't take into account go stop_asap and chkfilename */ int ecm_stage1_batch (mpz_t f, mpres_t x, mpres_t A, mpmod_t n, double B1, double *B1done, int batch, mpz_t s) { mp_limb_t d_1; mpz_t d_2; mpres_t x1, z1, x2, z2; unsigned long i; mpres_t t, u; int ret = ECM_NO_FACTOR_FOUND; MEMORY_TAG; mpres_init (x1, n); MEMORY_TAG; mpres_init (z1, n); MEMORY_TAG; mpres_init (x2, n); MEMORY_TAG; mpres_init (z2, n); MEMORY_TAG; mpres_init (t, n); MEMORY_TAG; mpres_init (u, n); if (batch == 2) { MEMORY_TAG; mpres_init (d_2, n); } MEMORY_UNTAG; /* initialize P */ mpres_set (x1, x, n); mpres_set_ui (z1, 1, n); /* P1 <- 1P */ /* Compute d=(A+2)/4 from A and d'=B*d thus d' = 2^(GMP_NUMB_BITS-2)*(A+2) */ if (batch == 1) { mpres_get_z (u, A, n); mpz_add_ui (u, u, 2); mpz_mul_2exp (u, u, GMP_NUMB_BITS - 2); mpres_set_z_for_gcd (u, u, n); /* reduces u mod n */ if (mpz_size (u) > 1) { mpres_get_z (u, A, n); outputf (OUTPUT_ERROR, "Error, d'=B*(A+2)/4 should fit in a mp_limb_t, A=%Zd\n", u); return ECM_ERROR; } d_1 = mpz_getlimbn (u, 0); } else { /* b = (A0+2)*B/4, where B=2^(k*GMP_NUMB_BITS) for MODMULN or REDC, B=2^GMP_NUMB_BITS for batch1, and B=1 otherwise */ mpres_add_ui (d_2, A, 2, n); mpres_div_2exp (d_2, d_2, 2, n); } /* Compute 2P : no need to duplicate P, the coordinates are simple. */ mpres_set_ui (x2, 9, n); if (batch == 1) /* here d = d_1 / GMP_NUMB_BITS */ { /* warning: mpres_set_ui takes an unsigned long which has only 32 bits on Windows, while d_1 might have 64 bits */ ASSERT_ALWAYS (mpz_size (u) == 1 && mpz_getlimbn (u, 0) == d_1); mpres_set_z (z2, u, n); mpres_div_2exp (z2, z2, GMP_NUMB_BITS, n); } else mpres_set (z2, d_2, n); mpres_mul_2exp (z2, z2, 6, n); mpres_add_ui (z2, z2, 8, n); /* P2 <- 2P = (9 : : 64d+8) */ /* invariant: if j represents the upper bits of s, then P1 = j*P and P2=(j+1)*P */ mpresn_pad (x1, n); mpresn_pad (z1, n); mpresn_pad (x2, n); mpresn_pad (z2, n); /* now perform the double-and-add ladder */ if (batch == 1) { for (i = mpz_sizeinbase (s, 2) - 1; i-- > 0;) { if (mpz_tstbit (s, i) == 0) /* (j,j+1) -> (2j,2j+1) */ /* P2 <- P1+P2 P1 <- 2*P1 */ dup_add_batch1 (x1, z1, x2, z2, t, u, d_1, n); else /* (j,j+1) -> (2j+1,2j+2) */ /* P1 <- P1+P2 P2 <- 2*P2 */ dup_add_batch1 (x2, z2, x1, z1, t, u, d_1, n); } } else /* batch = 2 */ { mpresn_pad (d_2, n); for (i = mpz_sizeinbase (s, 2) - 1; i-- > 0;) { if (mpz_tstbit (s, i) == 0) /* (j,j+1) -> (2j,2j+1) */ /* P2 <- P1+P2 P1 <- 2*P1 */ dup_add_batch2 (x1, z1, x2, z2, t, u, d_2, n); else /* (j,j+1) -> (2j+1,2j+2) */ /* P1 <- P1+P2 P2 <- 2*P2 */ dup_add_batch2 (x2, z2, x1, z1, t, u, d_2, n); } } *B1done=B1; mpresn_unpad (x1); mpresn_unpad (z1); if (!mpres_invert (u, z1, n)) /* Factor found? */ { mpres_gcd (f, z1, n); ret = ECM_FACTOR_FOUND_STEP1; } mpres_mul (x, x1, u, n); mpz_clear (x1); mpz_clear (z1); mpz_clear (x2); mpz_clear (z2); mpz_clear (t); mpz_clear (u); if (batch == 2) { mpz_clear (d_2); } return ret; }
/* If x^y is exactly representable (with maybe a larger precision than z), round it in z and return the (mpc) inexact flag in [0, 10]. If x^y is not exactly representable, return -1. If intermediate computations lead to numbers of more than maxprec bits, then abort and return -2 (in that case, to avoid loops, mpc_pow_exact should be called again with a larger value of maxprec). Assume one of Re(x) or Im(x) is non-zero, and y is non-zero (y is real). */ static int mpc_pow_exact (mpc_ptr z, mpc_srcptr x, mpfr_srcptr y, mpc_rnd_t rnd, mp_prec_t maxprec) { mp_exp_t ec, ed, ey, emin, emax; mpz_t my, a, b, c, d, u; unsigned long int t; int ret = -2; mpz_init (my); mpz_init (a); mpz_init (b); mpz_init (c); mpz_init (d); mpz_init (u); ey = mpfr_get_z_exp (my, y); /* normalize so that my is odd */ t = mpz_scan1 (my, 0); ey += t; mpz_tdiv_q_2exp (my, my, t); if (mpfr_zero_p (MPC_RE(x))) { mpz_set_ui (c, 0); ec = 0; } else ec = mpfr_get_z_exp (c, MPC_RE(x)); if (mpfr_zero_p (MPC_IM(x))) { mpz_set_ui (d, 0); ed = ec; } else { ed = mpfr_get_z_exp (d, MPC_IM(x)); if (mpfr_zero_p (MPC_RE(x))) ec = ed; } /* x = c*2^ec + I * d*2^ed */ /* equalize the exponents of x */ if (ec < ed) { mpz_mul_2exp (d, d, ed - ec); if (mpz_sizeinbase (d, 2) > maxprec) goto end; ed = ec; } else if (ed < ec) { mpz_mul_2exp (c, c, ec - ed); if (mpz_sizeinbase (c, 2) > maxprec) goto end; ec = ed; } /* now ec=ed and x = (c + I * d) * 2^ec */ /* divide by two if possible */ if (mpz_cmp_ui (c, 0) == 0) { t = mpz_scan1 (d, 0); mpz_tdiv_q_2exp (d, d, t); ec += t; } else if (mpz_cmp_ui (d, 0) == 0) { t = mpz_scan1 (c, 0); mpz_tdiv_q_2exp (c, c, t); ec += t; } else /* neither c nor d is zero */ { unsigned long v; t = mpz_scan1 (c, 0); v = mpz_scan1 (d, 0); if (v < t) t = v; mpz_tdiv_q_2exp (c, c, t); mpz_tdiv_q_2exp (d, d, t); ec += t; } /* now either one of c, d is odd */ while (ey < 0) { /* check if x is a square */ if (ec & 1) { mpz_mul_2exp (c, c, 1); mpz_mul_2exp (d, d, 1); ec --; } /* now ec is even */ if (mpc_perfect_square_p (a, b, c, d) == 0) break; mpz_swap (a, c); mpz_swap (b, d); ec /= 2; ey ++; } if (ey < 0) { ret = -1; /* not representable */ goto end; } /* Now ey >= 0, it thus suffices to check that x^my is representable. If my > 0, this is always true. If my < 0, we first try to invert (c+I*d)*2^ec. */ if (mpz_cmp_ui (my, 0) < 0) { /* If my < 0, 1 / (c + I*d) = (c - I*d)/(c^2 + d^2), thus a sufficient condition is that c^2 + d^2 is a power of two, assuming |c| <> |d|. Assume a prime p <> 2 divides c^2 + d^2, then if p does not divide c or d, 1 / (c + I*d) cannot be exact. If p divides both c and d, then we can write c = p*c', d = p*d', and 1 / (c + I*d) = 1/p * 1/(c' + I*d'). This shows that if 1/(c+I*d) is exact, then 1/(c' + I*d') is exact too, and we are back to the previous case. In conclusion, a necessary and sufficient condition is that c^2 + d^2 is a power of two. */ /* FIXME: we could first compute c^2+d^2 mod a limb for example */ mpz_mul (a, c, c); mpz_addmul (a, d, d); t = mpz_scan1 (a, 0); if (mpz_sizeinbase (a, 2) != 1 + t) /* a is not a power of two */ { ret = -1; /* not representable */ goto end; } /* replace (c,d) by (c/(c^2+d^2), -d/(c^2+d^2)) */ mpz_neg (d, d); ec = -ec - t; mpz_neg (my, my); } /* now ey >= 0 and my >= 0, and we want to compute [(c + I * d) * 2^ec] ^ (my * 2^ey). We first compute [(c + I * d) * 2^ec]^my, then square ey times. */ t = mpz_sizeinbase (my, 2) - 1; mpz_set (a, c); mpz_set (b, d); ed = ec; /* invariant: (a + I*b) * 2^ed = ((c + I*d) * 2^ec)^trunc(my/2^t) */ while (t-- > 0) { unsigned long v, w; /* square a + I*b */ mpz_mul (u, a, b); mpz_mul (a, a, a); mpz_submul (a, b, b); mpz_mul_2exp (b, u, 1); ed *= 2; if (mpz_tstbit (my, t)) /* multiply by c + I*d */ { mpz_mul (u, a, c); mpz_submul (u, b, d); /* ac-bd */ mpz_mul (b, b, c); mpz_addmul (b, a, d); /* bc+ad */ mpz_swap (a, u); ed += ec; } /* remove powers of two in (a,b) */ if (mpz_cmp_ui (a, 0) == 0) { w = mpz_scan1 (b, 0); mpz_tdiv_q_2exp (b, b, w); ed += w; } else if (mpz_cmp_ui (b, 0) == 0) { w = mpz_scan1 (a, 0); mpz_tdiv_q_2exp (a, a, w); ed += w; } else { w = mpz_scan1 (a, 0); v = mpz_scan1 (b, 0); if (v < w) w = v; mpz_tdiv_q_2exp (a, a, w); mpz_tdiv_q_2exp (b, b, w); ed += w; } if (mpz_sizeinbase (a, 2) > maxprec || mpz_sizeinbase (b, 2) > maxprec) goto end; } /* now a+I*b = (c+I*d)^my */ while (ey-- > 0) { unsigned long sa, sb; /* square a + I*b */ mpz_mul (u, a, b); mpz_mul (a, a, a); mpz_submul (a, b, b); mpz_mul_2exp (b, u, 1); ed *= 2; /* divide by largest 2^n possible, to avoid many loops for e.g., (2+2*I)^16777216 */ sa = mpz_scan1 (a, 0); sb = mpz_scan1 (b, 0); sa = (sa <= sb) ? sa : sb; mpz_tdiv_q_2exp (a, a, sa); mpz_tdiv_q_2exp (b, b, sa); ed += sa; if (mpz_sizeinbase (a, 2) > maxprec || mpz_sizeinbase (b, 2) > maxprec) goto end; } /* save emin, emax */ emin = mpfr_get_emin (); emax = mpfr_get_emax (); mpfr_set_emin (mpfr_get_emin_min ()); mpfr_set_emax (mpfr_get_emax_max ()); ret = mpfr_set_z (MPC_RE(z), a, MPC_RND_RE(rnd)); ret = MPC_INEX(ret, mpfr_set_z (MPC_IM(z), b, MPC_RND_IM(rnd))); mpfr_mul_2si (MPC_RE(z), MPC_RE(z), ed, MPC_RND_RE(rnd)); mpfr_mul_2si (MPC_IM(z), MPC_IM(z), ed, MPC_RND_IM(rnd)); /* restore emin, emax */ mpfr_set_emin (emin); mpfr_set_emax (emax); end: mpz_clear (my); mpz_clear (a); mpz_clear (b); mpz_clear (c); mpz_clear (d); mpz_clear (u); return ret; }
void check_random (int argc, char *argv[]) { mpz_t x, s0, s1, s2, s3, m; mp_size_t xsize; int i; int reps = 100000; int bit0, bit1, bit2, bit3; unsigned long int bitindex; const char *s = ""; if (argc == 2) reps = atoi (argv[1]); mpz_init (x); mpz_init (s0); mpz_init (s1); mpz_init (s2); mpz_init (s3); mpz_init (m); for (i = 0; i < reps; i++) { xsize = urandom () % (2 * SIZE) - SIZE; mpz_random2 (x, xsize); bitindex = urandom () % SIZE; mpz_set (s0, x); bit0 = mpz_tstbit (x, bitindex); mpz_setbit (x, bitindex); MPZ_CHECK_FORMAT (x); mpz_set (s1, x); bit1 = mpz_tstbit (x, bitindex); mpz_clrbit (x, bitindex); MPZ_CHECK_FORMAT (x); mpz_set (s2, x); bit2 = mpz_tstbit (x, bitindex); mpz_setbit (x, bitindex); MPZ_CHECK_FORMAT (x); mpz_set (s3, x); bit3 = mpz_tstbit (x, bitindex); #define FAIL(str) do { s = str; goto fail; } while (0) if (bit1 != 1) FAIL ("bit1 != 1"); if (bit2 != 0) FAIL ("bit2 != 0"); if (bit3 != 1) FAIL ("bit3 != 1"); if (bit0 == 0) { if (mpz_cmp (s0, s1) == 0 || mpz_cmp (s0, s2) != 0 || mpz_cmp (s0, s3) == 0) abort (); } else { if (mpz_cmp (s0, s1) != 0 || mpz_cmp (s0, s2) == 0 || mpz_cmp (s0, s3) != 0) abort (); } if (mpz_cmp (s1, s2) == 0 || mpz_cmp (s1, s3) != 0) abort (); if (mpz_cmp (s2, s3) == 0) abort (); mpz_ui_pow_ui (m, 2L, bitindex); MPZ_CHECK_FORMAT (m); mpz_ior (x, s2, m); MPZ_CHECK_FORMAT (x); if (mpz_cmp (x, s3) != 0) abort (); mpz_com (m, m); MPZ_CHECK_FORMAT (m); mpz_and (x, s1, m); MPZ_CHECK_FORMAT (x); if (mpz_cmp (x, s2) != 0) abort (); } mpz_clear (x); mpz_clear (s0); mpz_clear (s1); mpz_clear (s2); mpz_clear (s3); mpz_clear (m); return; fail: printf ("%s\n", s); printf ("bitindex = %lu\n", bitindex); printf ("x = "); mpz_out_str (stdout, -16, x); printf (" hex\n"); exit (1); }
void FixComplexKCM::emulate(TestCase * tc) { /* first we are going to format the entries */ mpz_class reIn = tc->getInputValue("ReIN"); mpz_class imIn = tc->getInputValue("ImIN"); /* Sign handling */ // Msb index counting from one bool reInNeg = ( signedInput && (mpz_tstbit(reIn.get_mpz_t(), input_width - 1) == 1) ); bool imInNeg = ( signedInput && (mpz_tstbit(imIn.get_mpz_t(), input_width - 1) == 1) ); // 2's complement -> absolute value unsigned representation if(reInNeg) { reIn = (mpz_class(1) << input_width) - reIn; } if(imInNeg) { imIn = (mpz_class(1) << input_width) - imIn; } //Cast to mp floating point number mpfr_t reIn_mpfr, imIn_mpfr; mpfr_init2(reIn_mpfr, input_width + 1); mpfr_init2(imIn_mpfr, input_width + 1); //Exact mpfr_set_z(reIn_mpfr, reIn.get_mpz_t(), GMP_RNDN); mpfr_set_z(imIn_mpfr, imIn.get_mpz_t(), GMP_RNDN); //Scaling : Exact mpfr_mul_2si(reIn_mpfr, reIn_mpfr, lsb_in, GMP_RNDN); mpfr_mul_2si(imIn_mpfr, imIn_mpfr, lsb_in, GMP_RNDN); mpfr_t re_prod, im_prod, crexim_prod, xrecim_prod; mpfr_t reOut, imOut; mpfr_inits2( 2 * input_width + 1, re_prod, im_prod, crexim_prod, xrecim_prod, NULL ); mpfr_inits2(5 * max(outputim_width, outputre_width) + 1, reOut, imOut, NULL); // c_r * x_r -> re_prod mpfr_mul(re_prod, reIn_mpfr, mpfr_constant_re, GMP_RNDN); // c_i * x_i -> im_prod mpfr_mul(im_prod, imIn_mpfr, mpfr_constant_im, GMP_RNDN); // c_r * x_i -> crexim_prod mpfr_mul(crexim_prod, mpfr_constant_re, imIn_mpfr, GMP_RNDN); // x_r * c_im -> xrecim_prod mpfr_mul(xrecim_prod, reIn_mpfr, mpfr_constant_im, GMP_RNDN); /* Input sign correction */ if(reInNeg) { //Exact mpfr_neg(re_prod, re_prod, GMP_RNDN); mpfr_neg(xrecim_prod, xrecim_prod, GMP_RNDN); } if(imInNeg) { //Exact mpfr_neg(im_prod, im_prod, GMP_RNDN); mpfr_neg(crexim_prod, crexim_prod, GMP_RNDN); } mpfr_sub(reOut, re_prod, im_prod, GMP_RNDN); mpfr_add(imOut, crexim_prod, xrecim_prod, GMP_RNDN); bool reOutNeg = (mpfr_sgn(reOut) < 0); bool imOutNeg = (mpfr_sgn(imOut) < 0); if(reOutNeg) { //Exact mpfr_abs(reOut, reOut, GMP_RNDN); } if(imOutNeg) { //Exact mpfr_abs(imOut, imOut, GMP_RNDN); } //Scale back (Exact) mpfr_mul_2si(reOut, reOut, -lsb_out, GMP_RNDN); mpfr_mul_2si(imOut, imOut, -lsb_out, GMP_RNDN); //Get bits vector mpz_class reUp, reDown, imUp, imDown, carry; mpfr_get_z(reUp.get_mpz_t(), reOut, GMP_RNDU); mpfr_get_z(reDown.get_mpz_t(), reOut, GMP_RNDD); mpfr_get_z(imDown.get_mpz_t(), imOut, GMP_RNDD); mpfr_get_z(imUp.get_mpz_t(), imOut, GMP_RNDU); carry = 0; //If result was negative, compute 2's complement if(reOutNeg) { reUp = (mpz_class(1) << outputre_width) - reUp; reDown = (mpz_class(1) << outputre_width) - reDown; } if(imOutNeg) { imUp = (mpz_class(1) << outputim_width) - imUp; imDown = (mpz_class(1) << outputim_width) - imDown; } //Handle border cases if(imUp > (mpz_class(1) << outputim_width) - 1 ) { imUp = 0; } if(reUp > (mpz_class(1) << outputre_width) - 1) { reUp = 0; } if(imDown > (mpz_class(1) << outputim_width) - 1 ) { imDown = 0; } if(reDown > (mpz_class(1) << outputre_width) - 1) { reDown = 0; } //Add expected results to corresponding outputs tc->addExpectedOutput("ReOut", reUp); tc->addExpectedOutput("ReOut", reDown); tc->addExpectedOutput("ImOut", imUp); tc->addExpectedOutput("ImOut", imDown); mpfr_clears( reOut, imOut, re_prod, im_prod, crexim_prod, xrecim_prod, reIn_mpfr, imIn_mpfr, NULL ); }
void *check_groups(void *thread_id) { int limite_inferior, limite_superior; bool adversario = false; Limites limites_grupo_actual; pthread_mutex_lock(&mutex_grupos); /* Revisamos el grupo para ver si hay algún adversario. * Recordar que una restricción de nuestra implementación es * que el adversario compromete la clave inmediatamente, lo que * significa que al encontrar un adversario podemos considerar * que la clave está comprometida y debemos dividir el grupo. */ if (grupos.size() == 0) { pthread_mutex_unlock(&mutex_grupos); pthread_mutex_lock(&mutex_thread_pool); /* El thread se encola a sí mismo, indicando que está disponible. */ thread_pool.push((unsigned long) thread_id); pthread_mutex_unlock(&mutex_thread_pool); pthread_exit(EXIT_SUCCESS); } limites_grupo_actual = grupos.front(); grupos.pop(); pthread_mutex_unlock(&mutex_grupos); limite_inferior = limites_grupo_actual.first; limite_superior = limites_grupo_actual.second; /* Si el grupo consiste en un solo usuario, significa que hemos * logrado identificar al adversario */ if (limite_inferior == limite_superior) { if (mpz_tstbit(usuarios, limite_inferior)) { pthread_mutex_lock(&mutex_identificados); identificados++; pthread_mutex_unlock(&mutex_identificados); } } else { /* Buscamos el adversario en el bitset, entre los rangos * limite_inferior y limite_superior. */ int index = mpz_scan1(usuarios, limite_inferior); if (index <= limite_superior && index >= 0) { adversario = true; } /* Adversario encontrado, dividir el grupo en dos subgrupos. * Revocamos clave antigua y asignamos dos nuevas */ if (adversario) { int avg_limites = avg(limite_superior, limite_inferior); Limites nuevos_limites = std::make_pair(limite_inferior, limite_inferior + avg_limites); pthread_mutex_lock(&mutex_grupos); grupos.push(nuevos_limites); nuevos_limites = std::make_pair(nuevos_limites.second + 1, limite_superior); grupos.push(nuevos_limites); pthread_mutex_unlock(&mutex_grupos); pthread_mutex_lock(&mutex_claves); claves += 1; pthread_mutex_unlock(&mutex_claves); } } pthread_mutex_lock(&mutex_thread_pool); /* El thread se encola a sí mismo, indicando que está disponible. */ thread_pool.push((unsigned long) thread_id); pthread_mutex_unlock(&mutex_thread_pool); pthread_exit(EXIT_SUCCESS); }
/** Perform a point multiplication @param k The scalar to multiply by @param G The base point @param R [out] Destination for kG @param modulus The modulus of the field the ECC curve is in @param map Boolean whether to map back to affine or not (1==map, 0 == leave in projective) @return CRYPT_OK on success */ int ecc_mulmod (mpz_t k, ecc_point * G, ecc_point * R, mpz_t a, mpz_t modulus, int map) { ecc_point *tG, *M[8]; int i, j, err, bitidx; int first, bitbuf, bitcpy, mode; if (k == NULL || G == NULL || R == NULL || modulus == NULL) return -1; /* alloc ram for window temps */ for (i = 0; i < 8; i++) { M[i] = ecc_new_point(); if (M[i] == NULL) { for (j = 0; j < i; j++) { ecc_del_point(M[j]); } return -1; } } /* make a copy of G incase R==G */ tG = ecc_new_point(); if (tG == NULL) { err = -1; goto done; } /* tG = G and convert to montgomery */ mpz_set (tG->x, G->x); mpz_set (tG->y, G->y); mpz_set (tG->z, G->z); /* calc the M tab, which holds kG for k==8..15 */ /* M[0] == 8G */ if ((err = ecc_projective_dbl_point (tG, M[0], a, modulus)) != 0) goto done; if ((err = ecc_projective_dbl_point (M[0], M[0], a, modulus)) != 0) goto done; if ((err = ecc_projective_dbl_point (M[0], M[0], a, modulus)) != 0) goto done; /* now find (8+k)G for k=1..7 */ for (j = 9; j < 16; j++) { if (ecc_projective_add_point(M[j-9], tG, M[j-8], a, modulus) != 0) goto done; } /* setup sliding window */ mode = 0; bitidx = mpz_size (k) * GMP_NUMB_BITS - 1; bitcpy = bitbuf = 0; first = 1; /* perform ops */ for (;;) { /* grab next digit as required */ if (bitidx == -1) { break; } /* grab the next msb from the ltiplicand */ i = mpz_tstbit (k, bitidx--); /* skip leading zero bits */ if (mode == 0 && i == 0) { continue; } /* if the bit is zero and mode == 1 then we double */ if (mode == 1 && i == 0) { if ((err = ecc_projective_dbl_point(R, R, a, modulus)) != 0) goto done; continue; } /* else we add it to the window */ bitbuf |= (i << (WINSIZE - ++bitcpy)); mode = 2; if (bitcpy == WINSIZE) { /* if this is the first window we do a simple copy */ if (first == 1) { /* R = kG [k = first window] */ mpz_set(R->x, M[bitbuf-8]->x); mpz_set(R->y, M[bitbuf-8]->y); mpz_set(R->z, M[bitbuf-8]->z); first = 0; } else { /* normal window */ /* ok window is filled so double as required and add */ /* double first */ for (j = 0; j < WINSIZE; j++) { if ((err = ecc_projective_dbl_point(R, R, a, modulus)) != 0) goto done; } /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */ if ((err = ecc_projective_add_point(R, M[bitbuf-8], R, a, modulus)) != 0) goto done; } /* empty window and reset */ bitcpy = bitbuf = 0; mode = 1; } } /* if bits remain then double/add */ if (mode == 2 && bitcpy > 0) { /* double then add */ for (j = 0; j < bitcpy; j++) { /* only double if we have had at least one add first */ if (first == 0) { if ((err = ecc_projective_dbl_point(R, R, a, modulus)) != 0) goto done; } bitbuf <<= 1; if ((bitbuf & (1 << WINSIZE)) != 0) { if (first == 1){ /* first add, so copy */ mpz_set(R->x, tG->x); mpz_set(R->y, tG->y); mpz_set(R->z, tG->z); first = 0; } else { /* then add */ if ((err = ecc_projective_add_point(R, tG, R, a, modulus)) != 0) goto done; } } } } /* map R back from projective space */ if (map) { err = ecc_map(R, modulus); } else { err = 0; } done: ecc_del_point(tG); for (i = 0; i < 8; i++) { ecc_del_point(M[i]); } return err; }
static void cc_miller_no_denom(element_t res, mpz_t q, element_t P, element_ptr Qx, element_ptr Qy, element_t negalpha) { mp_bitcnt_t m; element_t v; element_t Z; element_t a, b, c; element_t t0; element_t e0, e1; element_ptr Zx, Zy; const element_ptr Px = curve_x_coord(P); const element_ptr Py = curve_y_coord(P); #define do_term(i, j, k, flag) { \ element_ptr e2; \ e2 = element_item(e0, i); \ element_mul(e1, element_item(v, j), Qx); \ if (flag == 1) element_mul(e1, e1, negalpha); \ element_mul(element_x(e1), element_x(e1), a); \ element_mul(element_y(e1), element_y(e1), a); \ element_mul(e2, element_item(v, k), Qy); \ element_mul(element_x(e2), element_x(e2), b); \ element_mul(element_y(e2), element_y(e2), b); \ element_add(e2, e2, e1); \ if (flag == 2) element_mul(e2, e2, negalpha); \ element_mul(element_x(e1), element_x(element_item(v, i)), c); \ element_mul(element_y(e1), element_y(element_item(v, i)), c); \ element_add(e2, e2, e1); \ } // a, b, c lie in Fq // Qx, Qy lie in Fq^2 // Qx is coefficient of x^4 // Qy is coefficient of x^3 // // computes v *= (a Qx x^4 + b Qy x^3 + c) // // recall x^6 = -alpha thus // x^4 (u0 + u1 x^1 + ... + u5 x^5) = // u0 x^4 + u1 x^5 // - alpha u2 - alpha u3 x - alpha u4 x^2 - alpha u5 x^3 // and // x^4 (u0 + u1 x^1 + ... + u5 x^5) = // u0 x^3 + u1 x^4 + u2 x^5 // - alpha u3 - alpha u4 x - alpha u5 x^2 #define f_miller_evalfn() { \ do_term(0, 2, 3, 2); \ do_term(1, 3, 4, 2); \ do_term(2, 4, 5, 2); \ do_term(3, 5, 0, 1); \ do_term(4, 0, 1, 0); \ do_term(5, 1, 2, 0); \ element_set(v, e0); \ } /* element_ptr e1; e1 = element_item(e0, 4); element_mul(element_x(e1), element_x(Qx), a); element_mul(element_y(e1), element_y(Qx), a); e1 = element_item(e0, 3); element_mul(element_x(e1), element_x(Qy), b); element_mul(element_y(e1), element_y(Qy), b); element_set(element_x(element_item(e0, 0)), c); element_mul(v, v, e0); */ //a = -3 Zx^2 since cc->a is 0 for D = 3 //b = 2 * Zy //c = -(2 Zy^2 + a Zx); #define do_tangent() { \ element_square(a, Zx); \ element_mul_si(a, a, 3); \ element_neg(a, a); \ \ element_add(b, Zy, Zy); \ \ element_mul(t0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, t0); \ element_neg(c, c); \ \ f_miller_evalfn(); \ } //a = -(B.y - A.y) / (B.x - A.x); //b = 1; //c = -(A.y + a * A.x); //but we'll multiply by B.x - A.x to avoid division #define do_line() { \ element_sub(b, Px, Zx); \ element_sub(a, Zy, Py); \ element_mul(t0, b, Zy); \ element_mul(c, a, Zx); \ element_add(c, c, t0); \ element_neg(c, c); \ \ f_miller_evalfn(); \ } element_init(a, Px->field); element_init(b, a->field); element_init(c, a->field); element_init(t0, a->field); element_init(e0, res->field); element_init(e1, Qx->field); element_init(v, res->field); element_init(Z, P->field); element_set(Z, P); Zx = curve_x_coord(Z); Zy = curve_y_coord(Z); element_set1(v); m = (mp_bitcnt_t)mpz_sizeinbase(q, 2); m = (m > 2 ? m - 2 : 0); //TODO: sliding NAF for(;;) { do_tangent(); if (!m) break; element_double(Z, Z); if (mpz_tstbit(q, m)) { do_line(); element_add(Z, Z, P); } m--; element_square(v, v); } element_set(res, v); element_clear(v); element_clear(Z); element_clear(a); element_clear(b); element_clear(c); element_clear(t0); element_clear(e0); element_clear(e1); #undef do_term #undef f_miller_evalfn #undef do_tangent #undef do_line }
// x in Z_r, g, h in some group of order r // finds x such that g^x = h void element_dlog_pollard_rho(element_t x, element_t g, element_t h) { // see Blake, Seroussi and Smart // only one snark for this implementation int i, s = 20; field_ptr Zr = x->field, G = g->field; element_t asum; element_t bsum; element_t a[20]; element_t b[20]; element_t m[20]; element_t g0, snark; darray_t hole; int interval = 5; mpz_t counter; int found = 0; mpz_init(counter); element_init(g0, G); element_init(snark, G); element_init(asum, Zr); element_init(bsum, Zr); darray_init(hole); //set up multipliers for (i = 0; i < s; i++) { element_init(a[i], Zr); element_init(b[i], Zr); element_init(m[i], G); element_random(a[i]); element_random(b[i]); element_pow_zn(g0, g, a[i]); element_pow_zn(m[i], h, b[i]); element_mul(m[i], m[i], g0); } element_random(asum); element_random(bsum); element_pow_zn(g0, g, asum); element_pow_zn(snark, h, bsum); element_mul(snark, snark, g0); record(asum, bsum, snark, hole, counter); for (;;) { int len = element_length_in_bytes(snark); unsigned char *buf = pbc_malloc(len); unsigned char hash = 0; element_to_bytes(buf, snark); for (i = 0; i < len; i++) { hash += buf[i]; } i = hash % s; pbc_free(buf); element_mul(snark, snark, m[i]); element_add(asum, asum, a[i]); element_add(bsum, bsum, b[i]); for (i = 0; i < hole->count; i++) { snapshot_ptr ss = hole->item[i]; if (!element_cmp(snark, ss->snark)) { element_sub(bsum, bsum, ss->b); element_sub(asum, ss->a, asum); //answer is x such that x * bsum = asum //complications arise if gcd(bsum, r) > 1 //which can happen if r is not prime if (!mpz_probab_prime_p(Zr->order, 10)) { mpz_t za, zb, zd, zm; mpz_init(za); mpz_init(zb); mpz_init(zd); mpz_init(zm); element_to_mpz(za, asum); element_to_mpz(zb, bsum); mpz_gcd(zd, zb, Zr->order); mpz_divexact(zm, Zr->order, zd); mpz_divexact(zb, zb, zd); //if zd does not divide za there is no solution mpz_divexact(za, za, zd); mpz_invert(zb, zb, zm); mpz_mul(zb, za, zb); mpz_mod(zb, zb, zm); do { element_pow_mpz(g0, g, zb); if (!element_cmp(g0, h)) { element_set_mpz(x, zb); break; } mpz_add(zb, zb, zm); mpz_sub_ui(zd, zd, 1); } while (mpz_sgn(zd)); mpz_clear(zm); mpz_clear(za); mpz_clear(zb); mpz_clear(zd); } else { element_div(x, asum, bsum); } found = 1; break; } } if (found) break; mpz_add_ui(counter, counter, 1); if (mpz_tstbit(counter, interval)) { record(asum, bsum, snark, hole, counter); interval++; } } for (i = 0; i < s; i++) { element_clear(a[i]); element_clear(b[i]); element_clear(m[i]); } element_clear(g0); element_clear(snark); for (i = 0; i < hole->count; i++) { snapshot_ptr ss = hole->item[i]; element_clear(ss->a); element_clear(ss->b); element_clear(ss->snark); pbc_free(ss); } darray_clear(hole); element_clear(asum); element_clear(bsum); mpz_clear(counter); }
// Miller's algorithm, assuming we can ignore the denominator. We can do this // with careful group selection when the embedding degree is even. See thesis. // This version uses projective coordinates, which don't seem much faster. static void cc_miller_no_denom_proj(element_t res, mpz_t q, element_t P, element_ptr Qx, element_ptr Qy) { mp_bitcnt_t m; element_t v; element_t Z; element_t a, b, c; element_t t0, t1; element_ptr t2 = a, t3 = b, t4 = c; element_t e0; element_t z, z2; element_ptr Zx, Zy; const element_ptr curve_a = curve_a_coeff(P); const element_ptr Px = curve_x_coord(P); const element_ptr Py = curve_y_coord(P); #define proj_double() { \ /* t0 = 3x^2 + (curve_a) z^4 */ \ element_square(t0, Zx); \ /* element_mul_si(t0, t0, 3); */ \ element_double(t1, t0); \ element_add(t0, t0, t1); \ element_square(t1, z2); \ element_mul(t1, t1, curve_a); \ element_add(t0, t0, t1); \ \ /* z_out = 2 y z */ \ element_mul(z, Zy, z); \ /* element_mul_si(z, z, 2); */ \ element_double(z, z); \ element_square(z2, z); \ \ /* t1 = 4 x y^2 */ \ element_square(t2, Zy); \ element_mul(t1, Zx, t2); \ /* element_mul_si(t1, t1, 4); */ \ element_double(t1, t1); \ element_double(t1, t1); \ \ /* x_out = t0^2 - 2 t1 */ \ /* element_mul_si(t3, t1, 2); */ \ element_double(t3, t1); \ element_square(Zx, t0); \ element_sub(Zx, Zx, t3); \ \ /* t2 = 8y^4 */ \ element_square(t2, t2); \ /* element_mul_si(t2, t2, 8); */ \ element_double(t2, t2); \ element_double(t2, t2); \ element_double(t2, t2); \ \ /* y_out = t0(t1 - x_out) - t2 */ \ element_sub(t1, t1, Zx); \ element_mul(t0, t0, t1); \ element_sub(Zy, t0, t2); \ } #define proj_mixin() { \ /* t2 = Px z^2 */ \ element_mul(t2, z2, Px); \ \ /* t3 = Zx - t2 */ \ element_sub(t3, Zx, t2); \ \ /* t0 = Py z^3 */ \ element_mul(t0, z2, Py); \ element_mul(t0, t0, z); \ \ /* t1 = Zy - t0 */ \ element_sub(t1, Zy, t0); \ \ /* e7 = Zx + t2, use t2 to double for e7 */ \ element_add(t2, Zx, t2); \ \ /* e8 = Zy + t0, use t0 to double for e8 */ \ element_add(t0, Zy, t0); \ \ /* z = z t3 */ \ element_mul(z, z, t3); \ element_square(z2, z); \ \ /* Zx = t1^2 - e7 t3^2 */ \ /* t3 now holds t3^3, */ \ /* t4 holds e7 t3^2. */ \ element_square(t4, t3); \ element_mul(t3, t4, t3); \ element_square(Zx, t1); \ element_mul(t4, t2, t4); \ element_sub(Zx, Zx, t4); \ \ /* t4 = e7 t3^2 - 2 Zx */ \ element_sub(t4, t4, Zx); \ element_sub(t4, t4, Zx); \ \ /* Zy = (t4 t1 - e8 t3^3)/2 */ \ element_mul(t4, t4, t1); \ element_mul(t0, t0, t3); \ element_sub(t4, t4, t0); \ element_halve(Zy, t4); \ } #define do_tangent() { \ /* a = -(3x^2 + cca z^4) */ \ /* b = 2 y z^3 */ \ /* c = -(2 y^2 + x a) */ \ /* a = z^2 a */ \ element_square(a, z2); \ element_mul(a, a, curve_a); \ element_square(b, Zx); \ /* element_mul_si(b, b, 3); */ \ element_double(t0, b); \ element_add(b, b, t0); \ element_add(a, a, b); \ element_neg(a, a); \ \ element_mul(b, z, z2); \ element_mul(b, b, Zy); \ element_mul_si(b, b, 2); \ \ element_mul(c, Zx, a); \ element_mul(a, a, z2); \ element_square(t0, Zy); \ element_mul_si(t0, t0, 2); \ element_add(c, c, t0); \ element_neg(c, c); \ \ d_miller_evalfn(e0, a, b, c, Qx, Qy); \ element_mul(v, v, e0); \ } #define do_line() { \ /* a = -(Py z^3 - Zy) */ \ /* b = Px z^3 - Zx z */ \ /* c = Zx z Py - Zy Px; */ \ \ element_mul(t0, Zx, z); \ element_mul(t1, z2, z); \ \ element_mul(a, Py, t1); \ element_sub(a, Zy, a); \ \ element_mul(b, Px, t1); \ element_sub(b, b, t0); \ \ element_mul(t0, t0, Py); \ element_mul(c, Zy, Px); \ element_sub(c, t0, c); \ \ d_miller_evalfn(e0, a, b, c, Qx, Qy); \ element_mul(v, v, e0); \ } element_init(a, Px->field); element_init(b, a->field); element_init(c, a->field); element_init(t0, a->field); element_init(t1, a->field); element_init(e0, res->field); element_init(z, a->field); element_init(z2, a->field); element_set1(z); element_set1(z2); element_init(v, res->field); element_init(Z, P->field); element_set(Z, P); Zx = curve_x_coord(Z); Zy = curve_x_coord(Z); element_set1(v); m = (mp_bitcnt_t)mpz_sizeinbase(q, 2); m = (m > 2 ? m - 2 : 0); for(;;) { do_tangent(); if (!m) break; proj_double(); if (mpz_tstbit(q, m)) { do_line(); proj_mixin(); } m--; element_square(v, v); } element_set(res, v); element_clear(v); element_clear(Z); element_clear(a); element_clear(b); element_clear(c); element_clear(t0); element_clear(t1); element_clear(e0); element_clear(z); element_clear(z2); #undef proj_double #undef proj_mixin #undef do_tangent #undef do_line }