// The final powering, where we standardize the coset representative. static void cc_tatepower(element_ptr out, element_ptr in, pairing_t pairing) { pptr p = pairing->data; #define qpower(sign) { \ polymod_const_mul(e2, inre[1], p->xpowq); \ element_set(e0re, e2); \ polymod_const_mul(e2, inre[2], p->xpowq2); \ element_add(e0re, e0re, e2); \ element_add(e0re0, e0re0, inre[0]); \ \ if (sign > 0) { \ polymod_const_mul(e2, inim[1], p->xpowq); \ element_set(e0im, e2); \ polymod_const_mul(e2, inim[2], p->xpowq2); \ element_add(e0im, e0im, e2); \ element_add(e0im0, e0im0, inim[0]); \ } else { \ polymod_const_mul(e2, inim[1], p->xpowq); \ element_neg(e0im, e2); \ polymod_const_mul(e2, inim[2], p->xpowq2); \ element_sub(e0im, e0im, e2); \ element_sub(e0im0, e0im0, inim[0]); \ } \ } if (p->k == 6) { // See thesis, section 6.9, "The Final Powering", which gives a formula // for the first step of the final powering when Fq6 has been implemented // as a quadratic extension on top of a cubic extension. element_t e0, e2, e3; element_init(e0, p->Fqk); element_init(e2, p->Fqd); element_init(e3, p->Fqk); element_ptr e0re = element_x(e0); element_ptr e0im = element_y(e0); element_ptr e0re0 = ((element_t *) e0re->data)[0]; element_ptr e0im0 = ((element_t *) e0im->data)[0]; element_t *inre = element_x(in)->data; element_t *inim = element_y(in)->data; // Expressions in the formula are similar, hence the following function. qpower(1); element_set(e3, e0); element_set(e0re, element_x(in)); element_neg(e0im, element_y(in)); element_mul(e3, e3, e0); qpower(-1); element_mul(e0, e0, in); element_invert(e0, e0); element_mul(in, e3, e0); element_set(e0, in); // We use Lucas sequences to complete the final powering. lucas_even(out, e0, pairing->phikonr); element_clear(e0); element_clear(e2); element_clear(e3); } else { element_pow_mpz(out, in, p->tateexp); } #undef qpower }
// Define l = aX + bY + c where a, b, c are in Fq. // Compute e0 = l(Q) specialized for the case when Q has the form // (Qx, Qy * sqrt(v)) where Qx, Qy are in Fqd and v is the quadratic nonresidue // used to construct the quadratic field extension Fqk of Fqd. static inline void d_miller_evalfn(element_t e0, element_t a, element_t b, element_t c, element_t Qx, element_t Qy) { element_ptr re_out = element_x(e0); element_ptr im_out = element_y(e0); int i; int d = polymod_field_degree(re_out->field); for (i = 0; i < d; i++) { element_mul(element_item(re_out, i), element_item(Qx, i), a); element_mul(element_item(im_out, i), element_item(Qy, i), b); } element_add(element_item(re_out, 0), element_item(re_out, 0), c); }
void pbc_param_init_f_gen(pbc_param_t p, int bits) { f_init(p); f_param_ptr fp = p->data; //36 is a 6-bit number int xbit = (bits - 6) / 4; //TODO: use binary search to find smallest appropriate x mpz_t x, t; mpz_ptr q = fp->q; mpz_ptr r = fp->r; mpz_ptr b = fp->b; field_t Fq, Fq2, Fq2x; element_t e1; element_t f; field_t c; element_t P; mpz_init(x); mpz_init(t); mpz_setbit(x, xbit); for (;;) { mpz_mul(t, x, x); mpz_mul_ui(t, t, 6); mpz_add_ui(t, t, 1); tryminusx(q, x); mpz_sub(r, q, t); mpz_add_ui(r, r, 1); if (mpz_probab_prime_p(q, 10) && mpz_probab_prime_p(r, 10)) break; tryplusx(q, x); mpz_sub(r, q, t); mpz_add_ui(r, r, 1); if (mpz_probab_prime_p(q, 10) && mpz_probab_prime_p(r, 10)) break; mpz_add_ui(x, x, 1); } field_init_fp(Fq, q); element_init(e1, Fq); for (;;) { element_random(e1); field_init_curve_b(c, e1, r, NULL); element_init(P, c); element_random(P); element_mul_mpz(P, P, r); if (element_is0(P)) break; element_clear(P); field_clear(c); } element_to_mpz(b, e1); element_clear(e1); field_init_quadratic(Fq2, Fq); element_to_mpz(fp->beta, field_get_nqr(Fq)); field_init_poly(Fq2x, Fq2); element_init(f, Fq2x); // Find an irreducible polynomial of the form f = x^6 + alpha. // Call poly_set_coeff1() first so we can use element_item() for the other // coefficients. poly_set_coeff1(f, 6); for (;;) { element_random(element_item(f, 0)); if (poly_is_irred(f)) break; } //extend F_q^2 using f = x^6 + alpha //see if sextic twist contains a subgroup of order r //if not, it's the wrong twist: replace alpha with alpha^5 { field_t ctest; element_t Ptest; mpz_t z0, z1; mpz_init(z0); mpz_init(z1); element_init(e1, Fq2); element_set_mpz(e1, fp->b); element_mul(e1, e1, element_item(f, 0)); element_neg(e1, e1); field_init_curve_b(ctest, e1, r, NULL); element_init(Ptest, ctest); element_random(Ptest); //I'm not sure what the #E'(F_q^2) is, but //it definitely divides n_12 = #E(F_q^12). It contains a //subgroup of order r if and only if //(n_12 / r^2)P != O for some (in fact most) P in E'(F_q^6) mpz_pow_ui(z0, q, 12); mpz_add_ui(z0, z0, 1); pbc_mpz_trace_n(z1, q, t, 12); mpz_sub(z1, z0, z1); mpz_mul(z0, r, r); mpz_divexact(z1, z1, z0); element_mul_mpz(Ptest, Ptest, z1); if (element_is0(Ptest)) { mpz_set_ui(z0, 5); element_pow_mpz(element_item(f, 0), element_item(f, 0), z0); } element_clear(e1); element_clear(Ptest); field_clear(ctest); mpz_clear(z0); mpz_clear(z1); } element_to_mpz(fp->alpha0, element_x(element_item(f, 0))); element_to_mpz(fp->alpha1, element_y(element_item(f, 0))); element_clear(f); field_clear(Fq2x); field_clear(Fq2); field_clear(Fq); mpz_clear(t); mpz_clear(x); }
static void f_init_pairing(pairing_t pairing, void *data) { f_param_ptr param = data; f_pairing_data_ptr p; element_t irred; element_t e0, e1, e2; p = pairing->data = pbc_malloc(sizeof(f_pairing_data_t)); mpz_init(pairing->r); mpz_set(pairing->r, param->r); field_init_fp(pairing->Zr, pairing->r); field_init_fp(p->Fq, param->q); p->Fq->nqr = pbc_malloc(sizeof(element_t)); element_init(p->Fq->nqr, p->Fq); element_set_mpz(p->Fq->nqr, param->beta); field_init_quadratic(p->Fq2, p->Fq); field_init_poly(p->Fq2x, p->Fq2); element_init(irred, p->Fq2x); // Call poly_set_coeff1() first so we can use element_item() for the other // coefficients. poly_set_coeff1(irred, 6); element_init(p->negalpha, p->Fq2); element_init(p->negalphainv, p->Fq2); element_set_mpz(element_x(p->negalpha), param->alpha0); element_set_mpz(element_y(p->negalpha), param->alpha1); element_set(element_item(irred, 0), p->negalpha); field_init_polymod(p->Fq12, irred); element_neg(p->negalpha, p->negalpha); element_invert(p->negalphainv, p->negalpha); element_clear(irred); element_init(e0, p->Fq); element_init(e1, p->Fq); element_init(e2, p->Fq2); // Initialize the curve Y^2 = X^3 + b. element_set_mpz(e1, param->b); field_init_curve_ab(p->Eq, e0, e1, pairing->r, NULL); // Initialize the curve Y^2 = X^3 - alpha0 b - alpha1 sqrt(beta) b. element_set_mpz(e0, param->alpha0); element_neg(e0, e0); element_mul(element_x(e2), e0, e1); element_set_mpz(e0, param->alpha1); element_neg(e0, e0); element_mul(element_y(e2), e0, e1); element_clear(e0); element_init(e0, p->Fq2); field_init_curve_ab(p->Etwist, e0, e2, pairing->r, NULL); element_clear(e0); element_clear(e1); element_clear(e2); mpz_t ndonr; mpz_init(ndonr); // ndonr temporarily holds the trace. mpz_sub(ndonr, param->q, param->r); mpz_add_ui(ndonr, ndonr, 1); // TODO: We can use a smaller quotient_cmp, but I have to figure out // BN curves again. pbc_mpz_curve_order_extn(ndonr, param->q, ndonr, 12); mpz_divexact(ndonr, ndonr, param->r); mpz_divexact(ndonr, ndonr, param->r); field_curve_set_quotient_cmp(p->Etwist, ndonr); mpz_clear(ndonr); pairing->G1 = p->Eq; pairing->G2 = p->Etwist; pairing_GT_init(pairing, p->Fq12); pairing->finalpow = f_finalpow; pairing->map = f_pairing; pairing->clear_func = f_pairing_clear; mpz_init(p->tateexp); /* unoptimized tate exponent mpz_pow_ui(p->tateexp, param->q, 12); mpz_sub_ui(p->tateexp, p->tateexp, 1); mpz_divexact(p->tateexp, p->tateexp, param->r); */ mpz_ptr z = p->tateexp; mpz_mul(z, param->q, param->q); mpz_sub_ui(z, z, 1); mpz_mul(z, z, param->q); mpz_mul(z, z, param->q); mpz_add_ui(z, z, 1); mpz_divexact(z, z, param->r); element_init(p->xpowq2, p->Fq2); element_init(p->xpowq6, p->Fq2); element_init(p->xpowq8, p->Fq2); element_t xpowq; element_init(xpowq, p->Fq12); //there are smarter ways since we know q = 1 mod 6 //and that x^6 = -alpha //but this is fast enough element_set1(element_item(xpowq, 1)); element_pow_mpz(xpowq, xpowq, param->q); element_pow_mpz(xpowq, xpowq, param->q); element_set(p->xpowq2, element_item(xpowq, 1)); element_pow_mpz(xpowq, xpowq, param->q); element_pow_mpz(xpowq, xpowq, param->q); element_pow_mpz(xpowq, xpowq, param->q); element_pow_mpz(xpowq, xpowq, param->q); element_set(p->xpowq6, element_item(xpowq, 1)); element_pow_mpz(xpowq, xpowq, param->q); element_pow_mpz(xpowq, xpowq, param->q); element_set(p->xpowq8, element_item(xpowq, 1)); element_clear(xpowq); }
// 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); }
void KSET0(element_t out){ element_set0(out); element_ptr re_out = element_x(out); element_set0(element_item(re_out,0)); }