diff options
author | WuKong <rebirthmonkey@gmail.com> | 2015-09-04 09:25:34 +0200 |
---|---|---|
committer | WuKong <rebirthmonkey@gmail.com> | 2015-09-04 09:25:34 +0200 |
commit | 3baeb11a8fbcfcdbc31976d421f17b85503b3ecd (patch) | |
tree | 04891d88c1127148f1b390b5a24414e85b270aee /moon-abe/pbc-0.5.14/ecc | |
parent | 67c5b73910f5fc437429c356978081b252a59480 (diff) |
init attribute-based encryption
Change-Id: Iba1a3d722110abf747a0fba366f3ebc911d25b25
Diffstat (limited to 'moon-abe/pbc-0.5.14/ecc')
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/a_param.c | 2315 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/curve.c | 987 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/d_param.c | 1258 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/e_param.c | 1006 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/eta_T_3.c | 835 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/f_param.c | 599 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/g_param.c | 1435 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/hilbert.c | 539 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/mnt.c | 496 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/mpc.c | 122 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/mpc.h | 93 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/pairing.c | 283 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/param.c | 220 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/param.h | 23 | ||||
-rw-r--r-- | moon-abe/pbc-0.5.14/ecc/singular.c | 447 |
15 files changed, 10658 insertions, 0 deletions
diff --git a/moon-abe/pbc-0.5.14/ecc/a_param.c b/moon-abe/pbc-0.5.14/ecc/a_param.c new file mode 100644 index 00000000..6cf8dd96 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/a_param.c @@ -0,0 +1,2315 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> // for intptr_t +#include <stdlib.h> //for rand, pbc_malloc, pbc_free +#include <string.h> //for strcmp +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_fp.h" +#include "pbc_fieldquadratic.h" +#include "pbc_param.h" +#include "pbc_pairing.h" +#include "pbc_curve.h" +#include "pbc_random.h" +#include "pbc_memory.h" +#include "ecc/param.h" +#include "pbc_a_param.h" +#include "pbc_a1_param.h" + +typedef struct { + int exp2; + int exp1; + int sign1; + int sign0; + mpz_t r; // r = 2^exp2 + sign1 * 2^exp1 + sign0 * 1 + mpz_t q; // we work in E(F_q) (and E(F_q^2)) + mpz_t h; // r * h = q + 1 +} *a_param_ptr; + +typedef struct { + field_t Fq, Fq2, Eq; + int exp2, exp1; + int sign1; +} *a_pairing_data_ptr; + +static void a_out_str(FILE *stream, void *data) { + a_param_ptr p = data; + param_out_type(stream, "a"); + param_out_mpz(stream, "q", p->q); + param_out_mpz(stream, "h", p->h); + param_out_mpz(stream, "r", p->r); + param_out_int(stream, "exp2", p->exp2); + param_out_int(stream, "exp1", p->exp1); + param_out_int(stream, "sign1", p->sign1); + param_out_int(stream, "sign0", p->sign0); +} + +static void a_clear(void *data) { + a_param_ptr sp = data; + mpz_clear(sp->r); + mpz_clear(sp->q); + mpz_clear(sp->h); + pbc_free(data); +} + +static void phi_identity(element_ptr out, element_ptr in, pairing_ptr pairing) { + UNUSED_VAR(pairing); + element_set(out, in); +} + +static void compute_abc_tangent(element_ptr a, element_ptr b, element_ptr c, + element_ptr Vx, element_ptr Vy, element_ptr e0) { + //a = -slope_tangent(V.x, V.y); + //b = 1; + //c = -(V.y + aV.x); + //but we multiply by -2*V.y to avoid division so: + //a = -(3 Vx^2 + cc->a) + //b = 2 * Vy + //c = -(2 Vy^2 + a Vx); + element_square(a, Vx); + //element_mul_si(a, a, 3); + element_add(e0, a, a); + element_add(a, e0, a); + element_set1(b); + element_add(a, a, b); + element_neg(a, a); + + element_double(b, Vy); + + element_mul(e0, b, Vy); + element_mul(c, a, Vx); + element_add(c, c, e0); + element_neg(c, c); +} + +static void compute_abc_tangent_proj(element_ptr a, element_ptr b, element_ptr c, + element_ptr Vx, element_ptr Vy, + element_ptr z, element_ptr z2, element_ptr e0) { + //a = -(3x^2 + cca z^4) + //for this case cca = 1 + //b = 2 y z^3 + //c = -(2 y^2 + x a) + //a = z^2 a + element_square(a, z2); + element_square(b, Vx); + ////element_mul_si(b, b, 3); + element_double(e0, b); + element_add(b, e0, b); + element_add(a, a, b); + element_neg(a, a); + + ////element_mul_si(e0, Vy, 2); + element_double(e0, Vy); + element_mul(b, e0, z2); + element_mul(b, b, z); + + element_mul(c, Vx, a); + element_mul(a, a, z2); + element_mul(e0, e0, Vy); + element_add(c, c, e0); + element_neg(c, c); +} + +static void compute_abc_line(element_ptr a, element_ptr b, element_ptr c, + element_ptr Vx, element_ptr Vy, + element_ptr V1x, element_ptr V1y, + element_ptr e0) { + //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, so + //a = -(By - Ay) + //b = Bx - Ax + //c = -(Ay b + a Ax); + element_sub(a, Vy, V1y); + element_sub(b, V1x, Vx); + element_mul(c, Vx, V1y); + element_mul(e0, Vy, V1x); + element_sub(c, c, e0); +} + +struct pp_coeff_s { + element_t a; + element_t b; + element_t c; +}; +typedef struct pp_coeff_s pp_coeff_t[1]; +typedef struct pp_coeff_s *pp_coeff_ptr; + +static void pp_coeff_set(pp_coeff_ptr p, element_t a, element_t b, element_t c) { + element_init(p->a, a->field); + element_init(p->b, b->field); + element_init(p->c, c->field); + element_set(p->a, a); + element_set(p->b, b); + element_set(p->c, c); +} + +static void a_pairing_pp_init(pairing_pp_t p, element_ptr in1, pairing_t pairing) { + int i, n; + a_pairing_data_ptr ainfo = pairing->data; + p->data = pbc_malloc(sizeof(pp_coeff_t) * (ainfo->exp2 + 1)); + pp_coeff_t *coeff = (pp_coeff_t *) p->data; + element_t V, V1; + element_t a, b, c; + element_t e0; + element_ptr Vx, Vy; + element_ptr V1x, V1y; + + #define do_tangent() \ + compute_abc_tangent(a, b, c, Vx, Vy, e0); \ + pp_coeff_set(coeff[i], a, b, c); + + #define do_line() \ + compute_abc_line(a, b, c, Vx, Vy, V1x, V1y, e0); \ + pp_coeff_set(coeff[i], a, b, c); + + element_init(V, ainfo->Eq); + element_init(V1, ainfo->Eq); + element_set(V, in1); + Vx = curve_x_coord(V); + Vy = curve_y_coord(V); + V1x = curve_x_coord(V1); + V1y = curve_y_coord(V1); + element_init(e0, ainfo->Fq); + element_init(a, ainfo->Fq); + element_init(b, ainfo->Fq); + element_init(c, ainfo->Fq); + + n = ainfo->exp1; + for (i=0; i<n; i++) { + do_tangent(); + element_double(V, V); + } + + if (ainfo->sign1 < 0) { + element_neg(V1, V); + } else { + element_set(V1, V); + } + n = ainfo->exp2; + for (; i<n; i++) { + do_tangent(); + element_double(V, V); + } + + do_line(); + + element_clear(e0); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(V); + element_clear(V1); + #undef do_tangent + #undef do_line +} + +static void a_pairing_pp_clear(pairing_pp_t p) { + a_pairing_data_ptr ainfo = p->pairing->data; + pp_coeff_t *coeff = (pp_coeff_t *) p->data; + int i, n = ainfo->exp2 + 1; + for (i=0; i<n; i++) { + pp_coeff_ptr pp = coeff[i]; + element_clear(pp->a); + element_clear(pp->b); + element_clear(pp->c); + } + pbc_free(p->data); +} + +// Requires cofactor to be odd. +// Overwrites in and temp, out != in. +// Luckily this touchy routine is only used internally. +// TODO: rewrite to allow (out == in)? would simplify a_finalpow() +static void lucas_odd(element_ptr out, element_ptr in, element_ptr temp, mpz_t cofactor) { + 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); + int 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 + 1) / r is even + //(r should be odd and q + 1 is always even) + //thus v0 = V_k, v1 = V_{k+1} + //and V_{k-1} = P v0 - v1 + + //so U_k = (P V_k - 2 V_{k-1}) / (P^2 - 4) + // = (2 v1 - P v0) / (P^2 - 4) + + element_mul(in0, v0, t1); + element_double(v1, v1); + element_sub(v1, v1, in0); + + element_square(t1, t1); + element_sub(t1, t1, t0); + element_sub(t1, t1, t0); + element_div(v1, v1, t1); + + element_halve(v0, v0); + element_mul(v1, v1, in1); +} + +static inline void a_tateexp(element_ptr out, element_ptr in, element_ptr temp, mpz_t cofactor) { + element_ptr in1 = element_y(in); + //simpler but slower: + //element_pow_mpz(out, f, tateexp); + + //1. Exponentiate by q-1 + //which is equivalent to the following + + element_invert(temp, in); + element_neg(in1, in1); + element_mul(in, in, temp); + + //2. Exponentiate by (q+1)/r + + //Instead of: + // element_pow_mpz(out, in, cofactor); + //we use Lucas sequences (see "Compressed Pairings", Scott and Barreto) + lucas_odd(out, in, temp, cofactor); +} + +//computes a Qx + b Qy + c for type A pairing +static inline void a_miller_evalfn(element_ptr out, + element_ptr a, element_ptr b, element_ptr c, + element_ptr Qx, element_ptr Qy) { + //we'll map Q via (x,y) --> (-x, iy) + //hence Re(a Qx + b Qy + c) = -a Q'x + c and + //Im(a Qx + b Qy + c) = b Q'y + element_mul(element_y(out), a, Qx); + element_sub(element_x(out), c, element_y(out)); + element_mul(element_y(out), b, Qy); +} + +static void a_pairing_pp_apply(element_ptr out, element_ptr in2, pairing_pp_t p) { + //TODO: use proj coords here too to shave off a little time + element_ptr Qx = curve_x_coord(in2); + element_ptr Qy = curve_y_coord(in2); + element_t f, f0; + int i, n; + a_pairing_data_ptr ainfo = p->pairing->data; + pp_coeff_t *coeff = p->data; + element_init(f, ainfo->Fq2); + element_init(f0, ainfo->Fq2); + + element_set1(f); + n = ainfo->exp1; + for (i=0; i<n; i++) { + pp_coeff_ptr pp = coeff[i]; + element_square(f, f); + a_miller_evalfn(f0, pp->a, pp->b, pp->c, Qx, Qy); + element_mul(f, f, f0); + } + if (ainfo->sign1 < 0) { + element_invert(out, f); + } else { + element_set(out, f); + } + n = ainfo->exp2; + for (; i<n; i++) { + element_square(f, f); + pp_coeff_ptr pp = coeff[i]; + a_miller_evalfn(f0, pp->a, pp->b, pp->c, Qx, Qy); + element_mul(f, f, f0); + } + + element_mul(f, f, out); + { + pp_coeff_ptr pp = coeff[i]; + a_miller_evalfn(f0, pp->a, pp->b, pp->c, Qx, Qy); + element_mul(f, f, f0); + } + + a_tateexp(out, f, f0, p->pairing->phikonr); + + element_clear(f); + element_clear(f0); +} + +// in1, in2 are from E(F_q), out from F_q^2. +// Pairing via elliptic nets (see Stange). +static void a_pairing_ellnet(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + element_ptr x = curve_x_coord(in1); + element_ptr y = curve_y_coord(in1); + + element_ptr x2 = curve_x_coord(in2); + element_ptr y2 = curve_y_coord(in2); + + //we map (x2,y2) to (-x2, i y2) before pairing + //notation: cmi means c_{k-i}, ci means c_{k+i} + element_t cm3, cm2, cm1, c0, c1, c2, c3, c4; + element_t dm1, d0, d1; + element_t A, B, C; + + element_init_same_as(cm3, x); + element_init_same_as(cm2, x); + element_init_same_as(cm1, x); + element_init_same_as(c0, x); + element_init_same_as(c1, x); + element_init_same_as(c2, x); + element_init_same_as(c3, x); + element_init_same_as(c4, x); + element_init_same_as(C, x); + + element_init_same_as(dm1, out); + element_init_same_as(d0, out); + element_init_same_as(d1, out); + element_init_same_as(A, x); + element_init_same_as(B, out); + + // c1 = 2y + // c0 = 1 + // cm2 = -1 + // cm3 = -2y + element_double(c1, y); + element_set1(c0); + element_neg(cm3, c1); + element_neg(cm2, c0); + + // a = 1, b = 0 for Y^2 = X^3 + X + //hence c3 = c_{k+3} = c_4 = 4y(x^6 + 5(x^4 - x^2) - 1) + //use cm1, C, c2 as temp variables for now + element_square(cm1, x); + element_square(C, cm1); + element_sub(c2, C, cm1); + element_double(c3, c2); + element_double(c3, c3); + element_add(c3, c3, c2); + element_mul(c2, C, cm1); + element_add(c3, c3, c2); + element_add(c3, c3, cm2); + element_mul(c3, c3, c1); + element_double(c3, c3); + + // c2 = c_3 = 3x^4 + 6x^2 - 1 + element_double(cm1, cm1); + element_add(cm1, cm1, C); + element_double(C, cm1); + element_add(C, C, cm1); + element_add(c2, C, cm2); + + // c4 = c_5 = c_2^3 c_4 - c_3^3 = c1^3 c3 - c2^3 + element_square(C, c1); + element_mul(c4, C, c1); + element_mul(c4, c4, c3); + element_square(C, c2); + element_mul(C, C, c2); + element_sub(c4, c4, C); + + //compute A, B, d1 (which is d_2 since k = 1) + //(recall phi takes x2 to -x2, y2 to i y2) + element_add(A, x, x2); + element_double(C, x); + element_sub(C, C, x2); + element_square(cm1, A); + element_mul(cm1, C, cm1); + element_set(element_x(d1), y); + element_set(element_y(d1), y2); + element_square(d1, d1); + element_sub(element_x(d1), element_x(d1), cm1); + element_neg(B, d1); + element_invert(B, B); + element_invert(A, A); + element_mul(element_x(d1), y, A); + element_neg(element_x(d1), element_x(d1)); + element_mul(element_y(d1), y2, A); + element_square(d1, d1); + element_sub(element_x(d1), C, element_x(d1)); + element_neg(element_y(d1), element_y(d1)); + + // cm1 = 0 + // C = (2y)^-1 + element_set0(cm1); + element_invert(C, c1); + + element_set1(dm1); + element_set1(d0); + + element_t sm2, sm1; + element_t s0, s1, s2, s3; + element_t tm2, tm1; + element_t t0, t1, t2, t3; + element_t e0, e1; + element_t u, v; + + element_init_same_as(sm2, x); + element_init_same_as(sm1, x); + element_init_same_as(s0, x); + element_init_same_as(s1, x); + element_init_same_as(s2, x); + element_init_same_as(s3, x); + + element_init_same_as(tm2, x); + element_init_same_as(tm1, x); + element_init_same_as(t0, x); + element_init_same_as(t1, x); + element_init_same_as(t2, x); + element_init_same_as(t3, x); + + element_init_same_as(e0, x); + element_init_same_as(e1, x); + + element_init_same_as(u, d0); + element_init_same_as(v, d0); + + int m = mpz_sizeinbase(pairing->r, 2) - 2; + for (;;) { + element_square(sm2, cm2); + element_square(sm1, cm1); + element_square(s0, c0); + element_square(s1, c1); + element_square(s2, c2); + element_square(s3, c3); + + element_mul(tm2, cm3, cm1); + element_mul(tm1, cm2, c0); + element_mul(t0, cm1, c1); + element_mul(t1, c0, c2); + element_mul(t2, c1, c3); + element_mul(t3, c2, c4); + + element_square(u, d0); + element_mul(v, dm1, d1); + + if (mpz_tstbit(pairing->r, m)) { + //double-and-add + element_mul(e0, t0, sm2); + element_mul(e1, tm2, s0); + element_sub(cm3, e0, e1); + element_mul(cm3, cm3, C); + + element_mul(e0, t0, sm1); + element_mul(e1, tm1, s0); + element_sub(cm2, e0, e1); + + element_mul(e0, t1, sm1); + element_mul(e1, tm1, s1); + element_sub(cm1, e0, e1); + element_mul(cm1, cm1, C); + + element_mul(e0, t1, s0); + element_mul(e1, t0, s1); + element_sub(c0, e0, e1); + + element_mul(e0, t2, s0); + element_mul(e1, t0, s2); + element_sub(c1, e0, e1); + element_mul(c1, c1, C); + + element_mul(e0, t2, s1); + element_mul(e1, t1, s2); + element_sub(c2, e0, e1); + + element_mul(e0, t3, s1); + element_mul(e1, t1, s3); + element_sub(c3, e0, e1); + element_mul(c3, c3, C); + + element_mul(e0, t3, s2); + element_mul(e1, t2, s3); + element_sub(c4, e0, e1); + + element_mul(element_x(out), element_x(u), t0); + element_mul(element_y(out), element_y(u), t0); + element_mul(element_x(dm1), element_x(v), s0); + element_mul(element_y(dm1), element_y(v), s0); + element_sub(dm1, dm1, out); + + element_mul(element_x(out), element_x(u), t1); + element_mul(element_y(out), element_y(u), t1); + element_mul(element_x(d0), element_x(v), s1); + element_mul(element_y(d0), element_y(v), s1); + element_sub(d0, d0, out); + element_mul(element_x(d0), element_x(d0), A); + element_mul(element_y(d0), element_y(d0), A); + + element_mul(element_x(out), element_x(u), t2); + element_mul(element_y(out), element_y(u), t2); + element_mul(element_x(d1), element_x(v), s2); + element_mul(element_y(d1), element_y(v), s2); + element_sub(d1, d1, out); + element_mul(d1, d1, B); + } else { + //double + element_mul(e0, tm1, sm2); + element_mul(e1, tm2, sm1); + element_sub(cm3, e0, e1); + + element_mul(e0, t0, sm2); + element_mul(e1, tm2, s0); + element_sub(cm2, e0, e1); + element_mul(cm2, cm2, C); + + element_mul(e0, t0, sm1); + element_mul(e1, tm1, s0); + element_sub(cm1, e0, e1); + + element_mul(e0, t1, sm1); + element_mul(e1, tm1, s1); + element_sub(c0, e0, e1); + element_mul(c0, c0, C); + + element_mul(e0, t1, s0); + element_mul(e1, t0, s1); + element_sub(c1, e0, e1); + + element_mul(e0, t2, s0); + element_mul(e1, t0, s2); + element_sub(c2, e0, e1); + element_mul(c2, c2, C); + + element_mul(e0, t2, s1); + element_mul(e1, t1, s2); + element_sub(c3, e0, e1); + + element_mul(e0, t3, s1); + element_mul(e1, t1, s3); + element_sub(c4, e0, e1); + element_mul(c4, c4, C); + + element_mul(element_x(out), element_x(u), tm1); + element_mul(element_y(out), element_y(u), tm1); + element_mul(element_x(dm1), element_x(v), sm1); + element_mul(element_y(dm1), element_y(v), sm1); + element_sub(dm1, dm1, out); + + element_mul(element_x(out), element_x(u), t0); + element_mul(element_y(out), element_y(u), t0); + element_mul(element_x(d0), element_x(v), s0); + element_mul(element_y(d0), element_y(v), s0); + element_sub(d0, d0, out); + + element_mul(element_x(out), element_x(u), t1); + element_mul(element_y(out), element_y(u), t1); + element_mul(element_x(d1), element_x(v), s1); + element_mul(element_y(d1), element_y(v), s1); + element_sub(d1, d1, out); + element_mul(element_x(d1), element_x(d1), A); + element_mul(element_y(d1), element_y(d1), A); + } + if (!m) break; + m--; + } + // since c_k lies base field + // it gets killed by the final powering + //element_invert(c1, c1); + //element_mul(element_x(d1), element_x(d1), c1); + //element_mul(element_y(d1), element_y(d1), c1); + + a_tateexp(out, d1, d0, pairing->phikonr); + + element_clear(dm1); + element_clear(d0); + element_clear(d1); + + element_clear(cm3); + element_clear(cm2); + element_clear(cm1); + element_clear(c0); + element_clear(c1); + element_clear(c2); + element_clear(c3); + element_clear(c4); + + element_clear(sm2); + element_clear(sm1); + element_clear(s0); + element_clear(s1); + element_clear(s2); + element_clear(s3); + + element_clear(tm2); + element_clear(tm1); + element_clear(t0); + element_clear(t1); + element_clear(t2); + element_clear(t3); + + element_clear(e0); + element_clear(e1); + element_clear(A); + element_clear(B); + element_clear(C); + element_clear(u); + element_clear(v); +} + +struct ellnet_pp_st_s { + element_t sm1, s0, s1, s2; + element_t tm1, t0, t1, t2; +}; +typedef struct ellnet_pp_st_s ellnet_pp_st_t[1]; +typedef struct ellnet_pp_st_s *ellnet_pp_st_ptr; + +struct ellnet_pp_s { + element_t x; + element_t y; + ellnet_pp_st_t *seq; +}; +typedef struct ellnet_pp_s ellnet_pp_t[1]; +typedef struct ellnet_pp_s *ellnet_pp_ptr; + +static void a_pairing_ellnet_pp_init(pairing_pp_t p, element_ptr in1, pairing_t pairing) { + element_ptr x = curve_x_coord(in1); + element_ptr y = curve_y_coord(in1); + int i, rbits = mpz_sizeinbase(pairing->r, 2); + ellnet_pp_ptr pp = p->data = pbc_malloc(sizeof(ellnet_pp_t)); + pp->seq = pbc_malloc(sizeof(ellnet_pp_st_t) * rbits); + element_init_same_as(pp->x, x); + element_init_same_as(pp->y, y); + element_set(pp->x, x); + element_set(pp->y, y); + for (i=0; i<rbits; i++) { + ellnet_pp_st_ptr seq = pp->seq[i]; + element_init_same_as(seq->sm1, x); + element_init_same_as(seq->s0, x); + element_init_same_as(seq->s1, x); + element_init_same_as(seq->s2, x); + element_init_same_as(seq->tm1, x); + element_init_same_as(seq->t0, x); + element_init_same_as(seq->t1, x); + element_init_same_as(seq->t2, x); + } + + //we map (x2,y2) to (-x2, i y2) before pairing + //notation: cmi means c_{k-i}, ci means c_{k+i} + element_t cm3, cm2, cm1, c0, c1, c2, c3, c4; + element_t C; + + element_init_same_as(cm3, x); + element_init_same_as(cm2, x); + element_init_same_as(cm1, x); + element_init_same_as(c0, x); + element_init_same_as(c1, x); + element_init_same_as(c2, x); + element_init_same_as(c3, x); + element_init_same_as(c4, x); + element_init_same_as(C, x); + + // c1 = 2y + // c0 = 1 + // cm2 = -1 + // cm3 = -2y + element_double(c1, y); + element_set1(c0); + element_neg(cm3, c1); + element_neg(cm2, c0); + + // a = 1, b = 0 for Y^2 = X^3 + X + //hence c3 = c_{k+3} = c_4 = 4y(x^6 + 5(x^4 - x^2) - 1) + //use cm1, C, c2 as temp variables for now + element_square(cm1, x); + element_square(C, cm1); + element_sub(c2, C, cm1); + element_double(c3, c2); + element_double(c3, c3); + element_add(c3, c3, c2); + element_mul(c2, C, cm1); + element_add(c3, c3, c2); + element_add(c3, c3, cm2); + element_mul(c3, c3, c1); + element_double(c3, c3); + + // c2 = c_3 = 3x^4 + 6x^2 - 1 + element_double(cm1, cm1); + element_add(cm1, cm1, C); + element_double(C, cm1); + element_add(C, C, cm1); + element_add(c2, C, cm2); + + // c4 = c_5 = c_2^3 c_4 - c_3^3 = c1^3 c3 - c2^3 + element_square(C, c1); + element_mul(c4, C, c1); + element_mul(c4, c4, c3); + element_square(C, c2); + element_mul(C, C, c2); + element_sub(c4, c4, C); + + // cm1 = 0 + // C = (2y)^-1 + element_set0(cm1); + element_invert(C, c1); + + int k = 0; + element_t sm2, s3; + element_t tm2, t3; + element_ptr sm1, s0, s1, s2; + element_ptr tm1, t0, t1, t2; + element_t e0, e1; + + element_init_same_as(sm2, x); + element_init_same_as(s3, x); + + element_init_same_as(tm2, x); + element_init_same_as(t3, x); + + element_init_same_as(e0, x); + element_init_same_as(e1, x); + + int m = rbits - 2; + for (;;) { + ellnet_pp_st_ptr seq = pp->seq[k]; + sm1 = seq->sm1; + s0 = seq->s0; + s1 = seq->s1; + s2 = seq->s2; + tm1 = seq->tm1; + t0 = seq->t0; + t1 = seq->t1; + t2 = seq->t2; + + element_square(sm2, cm2); + element_square(sm1, cm1); + element_square(s0, c0); + element_square(s1, c1); + element_square(s2, c2); + element_square(s3, c3); + + element_mul(tm2, cm3, cm1); + element_mul(tm1, cm2, c0); + element_mul(t0, cm1, c1); + element_mul(t1, c0, c2); + element_mul(t2, c1, c3); + element_mul(t3, c2, c4); + + if (!m) break; + k++; + + if (mpz_tstbit(pairing->r, m)) { + //double-and-add + element_mul(e0, t0, sm2); + element_mul(e1, tm2, s0); + element_sub(cm3, e0, e1); + element_mul(cm3, cm3, C); + + element_mul(e0, t0, sm1); + element_mul(e1, tm1, s0); + element_sub(cm2, e0, e1); + + element_mul(e0, t1, sm1); + element_mul(e1, tm1, s1); + element_sub(cm1, e0, e1); + element_mul(cm1, cm1, C); + + element_mul(e0, t1, s0); + element_mul(e1, t0, s1); + element_sub(c0, e0, e1); + + element_mul(e0, t2, s0); + element_mul(e1, t0, s2); + element_sub(c1, e0, e1); + element_mul(c1, c1, C); + + element_mul(e0, t2, s1); + element_mul(e1, t1, s2); + element_sub(c2, e0, e1); + + element_mul(e0, t3, s1); + element_mul(e1, t1, s3); + element_sub(c3, e0, e1); + element_mul(c3, c3, C); + + element_mul(e0, t3, s2); + element_mul(e1, t2, s3); + element_sub(c4, e0, e1); + + } else { + //double + element_mul(e0, tm1, sm2); + element_mul(e1, tm2, sm1); + element_sub(cm3, e0, e1); + + element_mul(e0, t0, sm2); + element_mul(e1, tm2, s0); + element_sub(cm2, e0, e1); + element_mul(cm2, cm2, C); + + element_mul(e0, t0, sm1); + element_mul(e1, tm1, s0); + element_sub(cm1, e0, e1); + + element_mul(e0, t1, sm1); + element_mul(e1, tm1, s1); + element_sub(c0, e0, e1); + element_mul(c0, c0, C); + + element_mul(e0, t1, s0); + element_mul(e1, t0, s1); + element_sub(c1, e0, e1); + + element_mul(e0, t2, s0); + element_mul(e1, t0, s2); + element_sub(c2, e0, e1); + element_mul(c2, c2, C); + + element_mul(e0, t2, s1); + element_mul(e1, t1, s2); + element_sub(c3, e0, e1); + + element_mul(e0, t3, s1); + element_mul(e1, t1, s3); + element_sub(c4, e0, e1); + element_mul(c4, c4, C); + } + m--; + } + + element_clear(cm3); + element_clear(cm2); + element_clear(cm1); + element_clear(c0); + element_clear(c1); + element_clear(c2); + element_clear(c3); + element_clear(c4); + + element_clear(sm2); + element_clear(s3); + + element_clear(tm2); + element_clear(t3); + + element_clear(e0); + element_clear(e1); + element_clear(C); +} + +static void a_pairing_ellnet_pp_clear(pairing_pp_t p) { + ellnet_pp_ptr pp = p->data; + int i, rbits = mpz_sizeinbase(p->pairing->r, 2); + for (i=0; i<rbits; i++) { + ellnet_pp_st_ptr seq = pp->seq[i]; + element_clear(seq->sm1); + element_clear(seq->s0); + element_clear(seq->s1); + element_clear(seq->s2); + element_clear(seq->tm1); + element_clear(seq->t0); + element_clear(seq->t1); + element_clear(seq->t2); + } + element_clear(pp->x); + element_clear(pp->y); + pbc_free(pp->seq); + pbc_free(p->data); +} + +static void a_pairing_ellnet_pp_apply(element_ptr out, element_ptr in2, pairing_pp_t p) { + element_ptr x2 = curve_x_coord(in2); + element_ptr y2 = curve_y_coord(in2); + ellnet_pp_ptr pp = p->data; + int rbits = mpz_sizeinbase(p->pairing->r, 2); + int k = 0; + int m = rbits - 2; + element_t A, B; + element_t e0, e1; + element_t dm1, d0, d1; + element_t u, v; + + element_init_same_as(A, x2); + element_init_same_as(B, out); + element_init_same_as(e0, x2); + element_init_same_as(e1, x2); + element_init_same_as(dm1, out); + element_init_same_as(d0, out); + element_init_same_as(d1, out); + element_init_same_as(u, out); + element_init_same_as(v, out); + + element_add(A, pp->x, x2); + element_double(e0, pp->x); + element_sub(e0, e0, x2); + element_square(e1, A); + element_mul(e1, e0, e1); + element_set(element_x(d1), pp->y); + element_set(element_y(d1), y2); + element_square(d1, d1); + element_sub(element_x(d1), element_x(d1), e1); + element_neg(B, d1); + element_invert(B, B); + element_invert(A, A); + element_mul(element_x(d1), pp->y, A); + element_neg(element_x(d1), element_x(d1)); + element_mul(element_y(d1), y2, A); + element_square(d1, d1); + element_sub(element_x(d1), e0, element_x(d1)); + element_neg(element_y(d1), element_y(d1)); + + element_set1(dm1); + element_set1(d0); + for (;;) { + element_ptr sm1, s0, s1, s2; + element_ptr tm1, t0, t1, t2; + ellnet_pp_st_ptr seq = pp->seq[k]; + sm1 = seq->sm1; + s0 = seq->s0; + s1 = seq->s1; + s2 = seq->s2; + tm1 = seq->tm1; + t0 = seq->t0; + t1 = seq->t1; + t2 = seq->t2; + k++; + + element_square(u, d0); + element_mul(v, dm1, d1); + + if (mpz_tstbit(p->pairing->r, m)) { + //double-and-add + element_mul(element_x(out), element_x(u), t0); + element_mul(element_y(out), element_y(u), t0); + element_mul(element_x(dm1), element_x(v), s0); + element_mul(element_y(dm1), element_y(v), s0); + element_sub(dm1, dm1, out); + + element_mul(element_x(out), element_x(u), t1); + element_mul(element_y(out), element_y(u), t1); + element_mul(element_x(d0), element_x(v), s1); + element_mul(element_y(d0), element_y(v), s1); + element_sub(d0, d0, out); + element_mul(element_x(d0), element_x(d0), A); + element_mul(element_y(d0), element_y(d0), A); + + element_mul(element_x(out), element_x(u), t2); + element_mul(element_y(out), element_y(u), t2); + element_mul(element_x(d1), element_x(v), s2); + element_mul(element_y(d1), element_y(v), s2); + element_sub(d1, d1, out); + element_mul(d1, d1, B); + } else { + //double + element_mul(element_x(out), element_x(u), tm1); + element_mul(element_y(out), element_y(u), tm1); + element_mul(element_x(dm1), element_x(v), sm1); + element_mul(element_y(dm1), element_y(v), sm1); + element_sub(dm1, dm1, out); + + element_mul(element_x(out), element_x(u), t0); + element_mul(element_y(out), element_y(u), t0); + element_mul(element_x(d0), element_x(v), s0); + element_mul(element_y(d0), element_y(v), s0); + element_sub(d0, d0, out); + + element_mul(element_x(out), element_x(u), t1); + element_mul(element_y(out), element_y(u), t1); + element_mul(element_x(d1), element_x(v), s1); + element_mul(element_y(d1), element_y(v), s1); + element_sub(d1, d1, out); + element_mul(element_x(d1), element_x(d1), A); + element_mul(element_y(d1), element_y(d1), A); + } + if (!m) break; + m--; + } + a_tateexp(out, d1, d0, p->pairing->phikonr); + + element_clear(A); + element_clear(B); + element_clear(e0); + element_clear(e1); + element_clear(dm1); + element_clear(d0); + element_clear(d1); + element_clear(u); + element_clear(v); +} + +//in1, in2 are from E(F_q), out from F_q^2 +static void a_pairing_proj(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + a_pairing_data_ptr p = pairing->data; + element_t V, V1; + element_t z, z2; + element_t f, f0, f1; + element_t a, b, c; + element_t e0; + const element_ptr e1 = a, e2 = b, e3 = c; + int i, n; + element_ptr Vx, Vy; + element_ptr V1x, V1y; + element_ptr Qx = curve_x_coord(in2); + element_ptr Qy = curve_y_coord(in2); + + //could save a couple of inversions by avoiding + //this function and rewriting do_line() to handle projective coords + //convert V from weighted projective (Jacobian) to affine + //i.e. (X, Y, Z) --> (X/Z^2, Y/Z^3) + //also sets z to 1 + #define point_to_affine() \ + element_invert(z, z); \ + element_square(e0, z); \ + element_mul(Vx, Vx, e0); \ + element_mul(e0, e0, z); \ + element_mul(Vy, Vy, e0); \ + element_set1(z); \ + element_set1(z2); + + #define proj_double() { \ + /* e0 = 3x^2 + (cc->a) z^4 */ \ + /* for this case a = 1 */ \ + element_square(e0, Vx); \ + /*element_mul_si(e0, e0, 3);*/ \ + element_double(e1, e0); \ + element_add(e0, e1, e0); \ + element_square(e1, z2); \ + element_add(e0, e0, e1); \ + \ + /* z_out = 2 y z */ \ + element_mul(z, Vy, z); \ + /*element_mul_si(z, z, 2);*/ \ + element_double(z, z); \ + element_square(z2, z); \ + \ + /* e1 = 4 x y^2 */ \ + element_square(e2, Vy); \ + element_mul(e1, Vx, e2); \ + /*element_mul_si(e1, e1, 4);*/ \ + element_double(e1, e1); \ + element_double(e1, e1); \ + \ + /* x_out = e0^2 - 2 e1 */ \ + element_double(e3, e1); \ + element_square(Vx, e0); \ + element_sub(Vx, Vx, e3); \ + \ + /* e2 = 8y^4 */ \ + element_square(e2, e2); \ + /*element_mul_si(e2, e2, 8);*/ \ + element_double(e2, e2); \ + element_double(e2, e2); \ + element_double(e2, e2); \ + \ + /*y_out = e0(e1 - x_out) - e2*/\ + element_sub(e1, e1, Vx); \ + element_mul(e0, e0, e1); \ + element_sub(Vy, e0, e2); \ + } + + #define do_tangent() \ + compute_abc_tangent_proj(a, b, c, Vx, Vy, z, z2, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); + + #define do_line() \ + compute_abc_line(a, b, c, Vx, Vy, V1x, V1y, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); + + element_init(V, p->Eq); + element_init(V1, p->Eq); + element_set(V, in1); + + Vx = curve_x_coord(V); + Vy = curve_y_coord(V); + V1x = curve_x_coord(V1); + V1y = curve_y_coord(V1); + + element_init(f, p->Fq2); + element_init(f0, p->Fq2); + element_init(f1, p->Fq2); + element_set1(f); + element_init(a, p->Fq); + element_init(b, p->Fq); + element_init(c, p->Fq); + element_init(e0, p->Fq); + element_init(z, p->Fq); + element_init(z2, p->Fq); + element_set1(z); + element_set1(z2); + n = p->exp1; + for (i=0; i<n; i++) { + //f = f^2 g_V,V(Q) + //where g_V,V = tangent at V + element_square(f, f); + do_tangent(); + proj_double(); + } + point_to_affine(); + if (p->sign1 < 0) { + element_neg(V1, V); + element_invert(f1, f); + } else { + element_set(V1, V); + element_set(f1, f); + } + n = p->exp2; + for (; i<n; i++) { + element_square(f, f); + do_tangent(); + proj_double(); + } + + element_mul(f, f, f1); + point_to_affine(); + do_line(); + + a_tateexp(out, f, f0, pairing->phikonr); + + element_clear(f); + element_clear(f0); + element_clear(f1); + element_clear(z); + element_clear(z2); + element_clear(V); + element_clear(V1); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(e0); + #undef point_to_affine + #undef proj_double + #undef do_tangent + #undef do_line +} + +//in1, in2 are from E(F_q), out from F_q^2 +static void a_pairing_affine(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + a_pairing_data_ptr p = pairing->data; + element_t V, V1; + element_t f, f0, f1; + element_t a, b, c; + element_t e0; + int i, n; + element_ptr Qx = curve_x_coord(in2); + element_ptr Qy = curve_y_coord(in2); + element_ptr Vx, Vy; + element_ptr V1x, V1y; + + #define do_tangent() \ + compute_abc_tangent(a, b, c, Vx, Vy, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); + + #define do_line() \ + compute_abc_line(a, b, c, Vx, Vy, V1x, V1y, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); + + element_init(V, p->Eq); + element_init(V1, p->Eq); + Vx = curve_x_coord(V); + Vy = curve_y_coord(V); + + V1x = curve_x_coord(V1); + V1y = curve_y_coord(V1); + + element_set(V, in1); + element_init(f, p->Fq2); + element_init(f0, p->Fq2); + element_init(f1, p->Fq2); + element_set1(f); + element_init(a, p->Fq); + element_init(b, p->Fq); + element_init(c, p->Fq); + element_init(e0, p->Fq); + n = p->exp1; + for (i=0; i<n; i++) { + //f = f^2 g_V,V(Q) + //where g_V,V = tangent at V + element_square(f, f); + do_tangent(); + element_double(V, V); + } + if (p->sign1 < 0) { + element_neg(V1, V); + element_invert(f1, f); + } else { + element_set(V1, V); + element_set(f1, f); + } + n = p->exp2; + for (; i<n; i++) { + element_square(f, f); + do_tangent(); + element_double(V, V); + } + + element_mul(f, f, f1); + do_line(); + + a_tateexp(out, f, f0, pairing->phikonr); + + element_clear(f); + element_clear(f0); + element_clear(f1); + element_clear(V); + element_clear(V1); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(e0); + #undef do_tangent + #undef do_line +} + +// On Computing Products of Pairing +//in1, in2 are from E(F_q), out from F_q^2 +void a_pairings_affine(element_ptr out, element_t in1[], element_t in2[], + int n_prod, pairing_t pairing) { + a_pairing_data_ptr p = pairing->data; + element_t* V = pbc_malloc(sizeof(element_t)*n_prod); + element_t* V1 = pbc_malloc(sizeof(element_t)*n_prod); + element_t f, f0, f1; + element_t a, b, c; + element_t e0; + int i, j, n; + element_ptr Qx, Qy; + element_ptr Vx, Vy; + element_ptr V1x, V1y; + + #define do_tangents() \ + for(j=0; j<n_prod; j++){ \ + Vx = curve_x_coord(V[j]); \ + Vy = curve_y_coord(V[j]); \ + Qx = curve_x_coord(in2[j]); \ + Qy = curve_y_coord(in2[j]); \ + \ + compute_abc_tangent(a, b, c, Vx, Vy, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); \ + } + + #define do_lines() \ + for(j=0;j<n_prod;j++){ \ + Vx = curve_x_coord(V[j]); \ + Vy = curve_y_coord(V[j]); \ + V1x = curve_x_coord(V1[j]); \ + V1y = curve_y_coord(V1[j]); \ + Qx = curve_x_coord(in2[j]); \ + Qy = curve_y_coord(in2[j]); \ + \ + compute_abc_line(a, b, c, Vx, Vy, V1x, V1y, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); \ + } + + for(i=0; i<n_prod; i++){ + element_init(V[i],p->Eq); + element_init(V1[i],p->Eq); + element_set(V[i],in1[i]); + } + + + element_init(f, p->Fq2); + element_init(f0, p->Fq2); + element_init(f1, p->Fq2); + element_set1(f); + element_init(a, p->Fq); + element_init(b, p->Fq); + element_init(c, p->Fq); + element_init(e0, p->Fq); + n = p->exp1; + for (i=0; i<n; i++) { + //f = f^2 g_V,V(Q) + //where g_V,V = tangent at V + element_square(f, f); + do_tangents(); + element_multi_double(V, V, n_prod); //V_i = V_i + V_i for all i at one time. + } + if (p->sign1 < 0) { + for(j=0; j<n_prod; j++){ + element_neg(V1[j], V[j]); + } + element_invert(f1, f); + } else { + for(j=0; j<n_prod; j++){ + element_set(V1[j], V[j]); + } + element_set(f1, f); + } + n = p->exp2; + for (; i<n; i++) { + element_square(f, f); + do_tangents(); + element_multi_double(V, V, n_prod); + } + + element_mul(f, f, f1); + do_lines(); + + a_tateexp(out, f, f0, pairing->phikonr); + + element_clear(f); + element_clear(f0); + element_clear(f1); + for(j=0;j<n_prod;j++){ + element_clear(V[j]); + element_clear(V1[j]); + } + pbc_free(V); + pbc_free(V1); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(e0); + #undef do_tangents + #undef do_lines +} + +static void a_pairing_clear(pairing_t pairing) { + field_clear(pairing->GT); + + a_pairing_data_ptr p = pairing->data; + field_clear(p->Eq); + field_clear(p->Fq); + field_clear(p->Fq2); + pbc_free(p); + + mpz_clear(pairing->r); + mpz_clear(pairing->phikonr); + field_clear(pairing->Zr); +} + +static void a_pairing_option_set(pairing_t pairing, char *key, char *value) { + if (!strcmp(key, "method")) { + if (!strcmp(value, "miller")) { + pairing->map = a_pairing_proj; + pairing->pp_init = a_pairing_pp_init; + pairing->pp_clear = a_pairing_pp_clear; + pairing->pp_apply = a_pairing_pp_apply; + } else if (!strcmp(value, "miller-affine")) { + pairing->map = a_pairing_affine; + pairing->pp_init = a_pairing_pp_init; + pairing->pp_clear = a_pairing_pp_clear; + pairing->pp_apply = a_pairing_pp_apply; + } else if (!strcmp(value, "shipsey-stange")) { + pairing->map = a_pairing_ellnet; + pairing->pp_init = a_pairing_ellnet_pp_init; + pairing->pp_clear = a_pairing_ellnet_pp_clear; + pairing->pp_apply = a_pairing_ellnet_pp_apply; + } + } +} + +static void a_finalpow(element_t e) { + pairing_ptr pairing = e->field->pairing; + element_t t0, t1; + element_init_same_as(t0, e->data); + element_init_same_as(t1, e->data); + a_tateexp(t0, e->data, t1, pairing->phikonr); + element_set(e->data, t0); + element_clear(t0); + element_clear(t1); +} + +static void a_init_pairing(pairing_ptr pairing, void *data) { + a_param_ptr param = data; + element_t a, b; + a_pairing_data_ptr p; + + p = pairing->data = pbc_malloc(sizeof(*p)); + p->exp2 = param->exp2; + p->exp1 = param->exp1; + p->sign1 = param->sign1; + mpz_init(pairing->r); + mpz_set(pairing->r, param->r); + field_init_fp(pairing->Zr, pairing->r); + pairing->map = a_pairing_proj; + pairing->prod_pairings = a_pairings_affine; + + field_init_fp(p->Fq, param->q); + element_init(a, p->Fq); + element_init(b, p->Fq); + element_set1(a); + element_set0(b); + field_init_curve_ab(p->Eq, a, b, pairing->r, param->h); + element_clear(a); + element_clear(b); + + field_init_fi(p->Fq2, p->Fq); + + //k=2, hence phi_k(q) = q + 1, phikonr = (q+1)/r + mpz_init(pairing->phikonr); + mpz_set(pairing->phikonr, param->h); + + pairing->G1 = p->Eq; + pairing->G2 = pairing->G1; + pairing->phi = phi_identity; + pairing_GT_init(pairing, p->Fq2); + pairing->finalpow = a_finalpow; + + pairing->clear_func = a_pairing_clear; + pairing->option_set = a_pairing_option_set; + pairing->pp_init = a_pairing_pp_init; + pairing->pp_clear = a_pairing_pp_clear; + pairing->pp_apply = a_pairing_pp_apply; +} + +static void a_param_init(pbc_param_ptr par) { + static pbc_param_interface_t interface = {{ + a_clear, + a_init_pairing, + a_out_str, + }}; + par->api = interface; + a_param_ptr p = par->data = pbc_malloc(sizeof(*p)); + mpz_init(p->r); + mpz_init(p->q); + mpz_init(p->h); +} + +// Public interface for type A pairings: + +int pbc_param_init_a(pbc_param_ptr par, struct symtab_s *tab) { + a_param_init(par); + a_param_ptr p = par->data; + + int err = 0; + err += lookup_mpz(p->q, tab, "q"); + err += lookup_mpz(p->r, tab, "r"); + err += lookup_mpz(p->h, tab, "h"); + err += lookup_int(&p->exp2, tab, "exp2"); + err += lookup_int(&p->exp1, tab, "exp1"); + err += lookup_int(&p->sign1, tab, "sign1"); + err += lookup_int(&p->sign0, tab, "sign0"); + return err; +} + +void pbc_param_init_a_gen(pbc_param_ptr par, int rbits, int qbits) { + a_param_init(par); + a_param_ptr sp = par->data; + int found = 0; + + mpz_ptr q = sp->q; + mpz_ptr r = sp->r; + mpz_ptr h = sp->h; + + do { + int i; + mpz_set_ui(r, 0); + + if (rand() % 2) { + sp->exp2 = rbits - 1; + sp->sign1 = 1; + } else { + sp->exp2 = rbits; + sp->sign1 = -1; + } + mpz_setbit(r, sp->exp2); + + //use q as a temp variable + mpz_set_ui(q, 0); + sp->exp1 = (rand() % (sp->exp2 - 1)) + 1; + mpz_setbit(q, sp->exp1); + if (sp->sign1 > 0) { + mpz_add(r, r, q); + } else { + mpz_sub(r, r, q); + } + + if (rand() % 2) { + sp->sign0 = 1; + mpz_add_ui(r, r, 1); + } else { + sp->sign0 = -1; + mpz_sub_ui(r, r, 1); + } + if (!mpz_probab_prime_p(r, 10)) continue; + for (i=0; i<10; i++) { + int bit; + //use q as a temp variable + mpz_set_ui(q, 0); + bit = qbits - rbits - 4 + 1; + if (bit < 3) bit = 3; + mpz_setbit(q, bit); + pbc_mpz_random(h, q); + mpz_mul_ui(h, h, 12); + //finally q takes the value it should + mpz_mul(q, h, r); + mpz_sub_ui(q, q, 1); + if (mpz_probab_prime_p(q, 10)) { + found = 1; + break; + } + } + } while (!found); +} + +// Type A1 pairings: + +struct a1_param_s { + mpz_t p; + mpz_t n; + int l; +}; +typedef struct a1_param_s a1_param_t[1]; +typedef struct a1_param_s *a1_param_ptr; + +struct a1_pairing_data_s { + field_t Fp, Fp2, Ep; +}; +typedef struct a1_pairing_data_s a1_pairing_data_t[1]; +typedef struct a1_pairing_data_s *a1_pairing_data_ptr; + +static void a1_clear(void *data) { + a1_param_ptr param = data; + mpz_clear(param->p); + mpz_clear(param->n); + pbc_free(data); +} + +static void a1_out_str(FILE *stream, void *data) { + a1_param_ptr p = data; + param_out_type(stream, "a1"); + param_out_mpz(stream, "p", p->p); + param_out_mpz(stream, "n", p->n); + param_out_int(stream, "l", p->l); +} + +struct pp2_coeff_s { + element_t cx2; + element_t cy2; + element_t cxy; + element_t cx; + element_t cy; + element_t c; +}; +typedef struct pp2_coeff_s pp2_coeff_t[1]; +typedef struct pp2_coeff_s *pp2_coeff_ptr; + +static void pp2_coeff_set(pp2_coeff_ptr p, + element_t cx2, element_t cy2, element_t cxy, + element_t cx, element_t cy, element_t c) { + element_init(p->cx2, cx2->field); + element_init(p->cy2, cy2->field); + element_init(p->cxy, cxy->field); + element_init(p->cx, cx->field); + element_init(p->cy, cy->field); + element_init(p->c, c->field); + element_set(p->cx2, cx2); + element_set(p->cy2, cy2); + element_set(p->cxy, cxy); + element_set(p->cx, cx); + element_set(p->cy, cy); + element_set(p->c, c); +} + +static void a1_pairing_pp_clear(pairing_pp_t p) { + void **pp = p->data; + while (*pp) { + pbc_free(*pp); + pp++; + } + pbc_free(p->data); +} + +static void a1_pairing_pp_init(pairing_pp_t p, element_ptr in1, pairing_t pairing) { + int m; + element_ptr Px = curve_x_coord(in1); + element_ptr Py = curve_y_coord(in1); + a1_pairing_data_ptr a1info = pairing->data; + p->data = pbc_malloc(sizeof(void *) * mpz_sizeinbase(pairing->r, 2)); + void **pp = p->data; + element_t V; + element_t a, b, c; + element_t a2, b2, c2; + element_t e0, e1, e2; + element_ptr Vx, Vy; + + #define do_tangent() compute_abc_tangent(a, b, c, Vx, Vy, e0); + + #define do_line() compute_abc_line(a2, b2, c2, Vx, Vy, Px, Py, e0); + + element_init(V, a1info->Ep); + element_set(V, in1); + Vx = curve_x_coord(V); + Vy = curve_y_coord(V); + + element_init(a, a1info->Fp); + element_init(b, a1info->Fp); + element_init(c, a1info->Fp); + element_init(e0, a1info->Fp); + element_init(e1, a1info->Fp); + element_init(e2, a1info->Fp); + element_init(a2, a1info->Fp); + element_init(b2, a1info->Fp); + element_init(c2, a1info->Fp); + + m = mpz_sizeinbase(pairing->r, 2) - 2; + + for(;;) { + do_tangent(); + if (!m) break; + element_double(V, V); + + if (mpz_tstbit(pairing->r, m)) { + do_line(); + element_add(V, V, in1); + //preprocess two at once + //e0 = coeff of x + element_mul(e0, a, c2); + element_mul(e1, a2, c); + element_add(e0, e0, e1); + + //e1 = coeff of y + element_mul(e1, b2, c); + element_mul(e2, b, c2); + element_add(e1, e1, e2); + + //c = constant term + element_mul(c, c, c2); + + //c2 = coeff of xy + element_mul(c2, a, b2); + element_mul(e2, a2, b); + element_add(c2, c2, e2); + + //a = coeff of x^2 + element_mul(a, a, a2); + + //b = coeff of y^2 + element_mul(b, b, b2); + + *pp = pbc_malloc(sizeof(pp2_coeff_t)); + pp2_coeff_set(*pp, a, b, c2, e0, e1, c); + } else { + *pp = pbc_malloc(sizeof(pp_coeff_t)); + pp_coeff_set(*pp, a, b, c); + } + pp++; + m--; + } + *pp = pbc_malloc(sizeof(pp_coeff_t)); + pp_coeff_set(*pp, a, b, c); + pp++; + *pp = NULL; + + element_clear(a2); + element_clear(b2); + element_clear(c2); + element_clear(e2); + element_clear(e1); + element_clear(e0); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(V); + #undef do_tangent + #undef do_line +} + +static void a1_pairing_pp_apply(element_ptr out, element_ptr in2, pairing_pp_t p) { + void **pp = p->data; + a1_pairing_data_ptr a1info = p->pairing->data; + element_t f, f0; + element_t e0, e1; + int m; + element_ptr Qx = curve_x_coord(in2); + element_ptr Qy = curve_y_coord(in2); + element_t Qx2, Qy2, Qxy; + + #define do_tangent() \ + pp_coeff_ptr ppp = *pp; \ + a_miller_evalfn(f0, ppp->a, ppp->b, ppp->c, Qx, Qy); + + #define do_line() { \ + pp2_coeff_ptr ppp = *pp; \ + /*we'll map Q via (x,y) --> (-x, iy) */ \ + /*hence Qx^2 = x^2, Qy^2 = -y^2, Qx Qy = -ixy */\ + /*where x = Q'x, y = Q'y */ \ + \ + /* Re = cx2 x^2 - cy2 y^2 - cx x + c */ \ + /* Im = -cxy xy + cy y */ \ + element_mul(e0, ppp->cx2, Qx2); \ + element_mul(e1, ppp->cy2, Qy2); \ + element_sub(e0, e0, e1); \ + element_mul(e1, ppp->cx, Qx); \ + element_sub(e0, e0, e1); \ + element_add(element_x(f0), e0, ppp->c); \ + \ + element_mul(e0, ppp->cy, Qy); \ + element_mul(e1, ppp->cxy, Qxy); \ + element_sub(element_y(f0), e0, e1); \ + } + + element_init(f, out->field); + element_init(f0, out->field); + + element_set1(f); + + element_init(e0, a1info->Fp); + element_init(e1, a1info->Fp); + element_init(Qx2, a1info->Fp); + element_init(Qy2, a1info->Fp); + element_init(Qxy, a1info->Fp); + + element_square(Qx2, Qx); + element_square(Qy2, Qy); + element_mul(Qxy, Qx, Qy); + + m = mpz_sizeinbase(p->pairing->r, 2) - 2; + + while (m > 0) { + if (mpz_tstbit(p->pairing->r, m)) { + do_line(); + } else { + do_tangent(); + } + element_mul(f, f, f0); + pp++; + m--; + element_square(f, f); + } + do_tangent(); + element_mul(f, f, f0); + + //Tate exponentiation + //simpler but slower: + //element_pow_mpz(out, f, p->tateexp); + //use this trick instead: + element_invert(f0, f); + element_neg(element_y(f), element_y(f)); + element_mul(f, f, f0); + element_pow_mpz(out, f, p->pairing->phikonr); + + /* We could use this instead but p->h is small so this does not help much + a_tateexp(out, f, f0, p->h); + */ + + element_clear(Qx2); + element_clear(Qy2); + element_clear(Qxy); + element_clear(f); + element_clear(f0); + element_clear(e1); + element_clear(e0); + #undef do_tangent + #undef do_line +} + +// e0 is a temp var. +// Mixed coordinates. +static void compute_abc_line_proj(element_ptr a, element_ptr b, element_ptr c, + element_ptr Vx, element_ptr Vy, element_ptr z, element_ptr z2, + element_ptr V1x, element_ptr V1y, element_ptr e0) { + //temporally used to store Z1^3 + element_mul(c,z,z2); + //a = Y1-Y2*Z1^3 + element_mul(e0,V1y,c); + element_sub(a,Vy,e0); + //b = -(X1*Z1-X2*Z1^3) + element_mul(b,c,V1x); + element_mul(e0,Vx,z); + element_sub(b,b,e0); + //c = -(Y2*b+X2*a) + element_mul(c,b,V1y); + element_mul(e0,a,V1x); + element_add(c,c,e0); + element_neg(c,c); +} + +// in1, in2 are from E(F_q), out from F_q^2 +static void a1_pairing_proj(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + a1_pairing_data_ptr p = pairing->data; + element_t V; + element_t z, z2; + element_t f, f0; + element_t a, b, c; + element_t e0; + const element_ptr e1 = a, e2 = b, e3 = c; // used in point_to_affine() etc. + int m; + element_ptr Px = curve_x_coord(in1); + element_ptr Py = curve_y_coord(in1); + element_ptr Qx = curve_x_coord(in2); + element_ptr Qy = curve_y_coord(in2); + element_ptr Vx; + element_ptr Vy; + + #define point_to_affine() \ + element_invert(z, z); \ + element_square(e0, z); \ + element_mul(Vx, Vx, e0); \ + element_mul(e0, e0, z); \ + element_mul(Vy, Vy, e0); \ + element_set1(z); \ + element_set1(z2); + + //TODO: do I need to check if V=-in1? + //Where V=(Vx,Vy,z) and in1=(Px,Py,1), a mixed coordinates. + #define proj_add() { \ + /* H=X2*Z1^2-X1 */ \ + element_mul(e0,Px,z2); \ + element_sub(e0,e0,Vx); \ + /* H^2 */ \ + element_square(e1,e0); \ + /* r=Y2*Z1^3-Y1 */ \ + element_mul(e2,z,z2); \ + element_mul(e2,e2,Py); \ + element_sub(e2,e2,Vy); \ + \ + /* X3=r^2-H^3-2X1*H^2 */ \ + element_set(z2,Vx); /* use z2 to store X1 and update Vx=X3 */ \ + element_square(Vx,e2); \ + element_mul(e3,e0,e1); /* e3=H^3 */ \ + element_sub(Vx,Vx,e3); \ + element_double(e3,z2); \ + element_mul(e3,e3,e1); /* 2X1*H^2 */ \ + element_sub(Vx,Vx,e3); \ + /* Y3=r(X1*H^2-X3)-Y1*H^3 */ \ + element_mul(e3,z2,e1); \ + element_sub(e3,e3,Vx); \ + element_mul(e3,e3,e2); \ + element_mul(e2,e0,e1); /* e2 no longer used. */ \ + element_mul(e2,e2,Vy); \ + element_sub(Vy,e3,e2); \ + /* Z3=Z1*H */ \ + element_mul(z,z,e0); \ + element_square(z2,z); \ + } + + #define proj_double() { \ + /* e0 = 3x^2 + (cc->a) z^4 */ \ + /* for this case a = 1 */ \ + element_square(e0, Vx); \ + /* element_mul_si(e0, e0, 3); */ \ + element_double(e1, e0); \ + element_add(e0, e1, e0); \ + element_square(e1, z2); \ + element_add(e0, e0, e1); \ + \ + /* z_out = 2 y z */ \ + element_mul(z, Vy, z); \ + /* element_mul_si(z, z, 2); */ \ + element_double(z, z); \ + element_square(z2, z); \ + \ + /* e1 = 4 x y^2 */ \ + element_square(e2, Vy); \ + element_mul(e1, Vx, e2); \ + /* element_mul_si(e1, e1, 4); */ \ + element_double(e1, e1); \ + element_double(e1, e1); \ + \ + /* x_out = e0^2 - 2 e1 */ \ + element_double(e3, e1); \ + element_square(Vx, e0); \ + element_sub(Vx, Vx, e3); \ + \ + /* e2 = 8y^4 */ \ + element_square(e2, e2); \ + /* element_mul_si(e2, e2, 8); */ \ + element_double(e2, e2); \ + element_double(e2, e2); \ + element_double(e2, e2); \ + \ + /* y_out = e0(e1 - x_out) - e2 */ \ + element_sub(e1, e1, Vx); \ + element_mul(e0, e0, e1); \ + element_sub(Vy, e0, e2); \ + } + + #define do_tangent() { \ + compute_abc_tangent_proj(a, b, c, Vx, Vy, z, z2, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); \ + } + + #define do_line() { \ + compute_abc_line_proj(a, b, c, Vx, Vy, z, z2, Px, Py, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); \ + } + + element_init(V, p->Ep); + element_set(V, in1); + Vx = curve_x_coord(V); + Vy = curve_y_coord(V); + + element_init(f, p->Fp2); + element_init(f0, p->Fp2); + element_set1(f); + element_init(a, p->Fp); + element_init(b, p->Fp); + element_init(c, p->Fp); + element_init(e0, p->Fp); + element_init(z, p->Fp); + element_init(z2, p->Fp); + element_set1(z); + element_set1(z2); + + m = mpz_sizeinbase(pairing->r, 2) - 2; + //TODO: sliding NAF + for(;;) { + do_tangent(); + if (!m) break; + + proj_double(); //V=2V + if (mpz_tstbit(pairing->r, m)) { + // point_to_affine(); + do_line(); + proj_add(); //V=V+in1 + } + + m--; + element_square(f, f); + } + + // Tate exponentiation. + // Simpler but slower: + // element_pow_mpz(out, f, p->tateexp); + // Use this trick instead: + element_invert(f0, f); + element_neg(element_y(f), element_y(f)); + element_mul(f, f, f0); + element_pow_mpz(out, f, pairing->phikonr); + + /* We could use this instead but p->h is small so this does not help much + a_tateexp(out, f, f0, p->h); + */ + + element_clear(f); + element_clear(f0); + element_clear(z); + element_clear(z2); + element_clear(V); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(e0); + #undef point_to_affine + #undef proj_add + #undef proj_double + #undef do_tangent + #undef do_line +} + +//in1, in2 are from E(F_q), out from F_q^2 +static void a1_pairing(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + a1_pairing_data_ptr p = pairing->data; + element_t V; + element_t f, f0; + element_t a, b, c; + element_t e0; + int m; + element_ptr Px = curve_x_coord(in1); + element_ptr Py = curve_y_coord(in1); + element_ptr Qx = curve_x_coord(in2); + element_ptr Qy = curve_y_coord(in2); + element_ptr Vx; + element_ptr Vy; + + #define do_tangent() { \ + compute_abc_tangent(a, b, c, Vx, Vy, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); \ + } + + #define do_line() { \ + compute_abc_line(a, b, c, Vx, Vy, Px, Py, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); \ + } + + element_init(V, p->Ep); + element_set(V, in1); + Vx = curve_x_coord(V); + Vy = curve_y_coord(V); + + element_init(f, p->Fp2); + element_init(f0, p->Fp2); + element_set1(f); + element_init(a, p->Fp); + element_init(b, p->Fp); + element_init(c, p->Fp); + element_init(e0, p->Fp); + + m = mpz_sizeinbase(pairing->r, 2) - 2; + + //TODO: sliding NAF + for(;;) { + do_tangent(); + if (!m) break; + + element_double(V, V); + if (mpz_tstbit(pairing->r, m)) { + do_line(); + element_add(V, V, in1); + } + + m--; + element_square(f, f); + } + + // Tate exponentiation. + // Simpler but slower: + // element_pow_mpz(out, f, p->tateexp); + // Use this trick instead: + element_invert(f0, f); + element_neg(element_y(f), element_y(f)); + element_mul(f, f, f0); + element_pow_mpz(out, f, pairing->phikonr); + + /* We could use this instead but p->h is small so this does not help much + a_tateexp(out, f, f0, p->h); + */ + + element_clear(f); + element_clear(f0); + element_clear(V); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(e0); + #undef do_tangent + #undef do_line +} + +//in1, in2 are from E(F_q), out from F_q^2 +void a1_pairings_affine(element_ptr out, element_t in1[], element_t in2[], + int n_prod, pairing_t pairing) { + a1_pairing_data_ptr p = pairing->data; + element_t* V = pbc_malloc(sizeof(element_t)*n_prod); + element_t f, f0; + element_t a, b, c; + element_t e0; + int m, i; + element_ptr Px, Py; + element_ptr Qx, Qy; + element_ptr Vx, Vy; + + #define do_tangents() { \ + for(i=0; i<n_prod; i++){ \ + Vx = curve_x_coord(V[i]); \ + Vy = curve_y_coord(V[i]); \ + Qx = curve_x_coord(in2[i]); \ + Qy = curve_y_coord(in2[i]); \ + compute_abc_tangent(a, b, c, Vx, Vy, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); \ + } \ + } + + #define do_lines() { \ + for(i=0; i<n_prod; i++){ \ + Vx = curve_x_coord(V[i]); \ + Vy = curve_y_coord(V[i]); \ + Px = curve_x_coord(in1[i]); \ + Py = curve_y_coord(in1[i]); \ + Qx = curve_x_coord(in2[i]); \ + Qy = curve_y_coord(in2[i]); \ + compute_abc_line(a, b, c, Vx, Vy, Px, Py, e0); \ + a_miller_evalfn(f0, a, b, c, Qx, Qy); \ + element_mul(f, f, f0); \ + } \ + } + + for(i=0; i<n_prod; i++){ + element_init(V[i], p->Ep); + element_set(V[i], in1[i]); + } + element_init(f, p->Fp2); + element_init(f0, p->Fp2); + element_set1(f); + element_init(a, p->Fp); + element_init(b, p->Fp); + element_init(c, p->Fp); + element_init(e0, p->Fp); + + m = mpz_sizeinbase(pairing->r, 2) - 2; + + //TODO: sliding NAF + for(;;) { + do_tangents(); + if (!m) break; + element_multi_double(V, V, n_prod); + if (mpz_tstbit(pairing->r, m)) { + do_lines(); + element_multi_add(V, V, in1, n_prod); + } + + m--; + element_square(f, f); + } + + // Tate exponentiation. + // Simpler but slower: + // element_pow_mpz(out, f, p->tateexp); + // Use this trick instead: + element_invert(f0, f); + element_neg(element_y(f), element_y(f)); + element_mul(f, f, f0); + element_pow_mpz(out, f, pairing->phikonr); + + /* We could use this instead but p->h is small so this does not help much + a_tateexp(out, f, f0, p->h); + */ + + element_clear(f); + element_clear(f0); + for(i=0; i<n_prod; i++){ + element_clear(V[i]); + } + pbc_free(V); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(e0); + #undef do_tangents + #undef do_lines +} + +static void a1_pairing_clear(pairing_t pairing) { + field_clear(pairing->GT); + + a1_pairing_data_ptr p = pairing->data; + field_clear(p->Ep); + field_clear(p->Fp2); + field_clear(p->Fp); + pbc_free(p); + + mpz_clear(pairing->phikonr); + mpz_clear(pairing->r); + field_clear(pairing->Zr); +} + +static void a1_pairing_option_set(pairing_t pairing, char *key, char *value) { + if (!strcmp(key, "method")) { + if (!strcmp(value, "miller")) { + pairing->map = a1_pairing_proj; + pairing->pp_init = a1_pairing_pp_init; + pairing->pp_clear = a1_pairing_pp_clear; + pairing->pp_apply = a1_pairing_pp_apply; + } else if (!strcmp(value, "miller-affine")){ + pairing->map = a1_pairing; + pairing->pp_init = a1_pairing_pp_init; + pairing->pp_clear = a1_pairing_pp_clear; + pairing->pp_apply = a1_pairing_pp_apply; + } else if (!strcmp(value, "shipsey-stange")) { + pairing->map = a_pairing_ellnet; + pairing->pp_init = a_pairing_ellnet_pp_init; + pairing->pp_clear = a_pairing_ellnet_pp_clear; + pairing->pp_apply = a_pairing_ellnet_pp_apply; + } + } +} + +static void a1_init_pairing(pairing_t pairing, void *data) { + a1_param_ptr param = data; + element_t a, b; + mpz_init(pairing->r); + mpz_set(pairing->r, param->n); + field_init_fp(pairing->Zr, pairing->r); + + a1_pairing_data_ptr p; + + p = pairing->data = pbc_malloc(sizeof(a1_pairing_data_t)); + + //k=2, hence phi_k(q) = q + 1, phikonr = (q+1)/r + mpz_init(pairing->phikonr); + mpz_set_ui(pairing->phikonr, param->l); + + field_init_fp(p->Fp, param->p); + element_init(a, p->Fp); + element_init(b, p->Fp); + element_set1(a); + element_set0(b); + field_init_curve_ab(p->Ep, a, b, pairing->r, pairing->phikonr); + + // Turns out to be faster. + field_curve_use_random_solvefory(p->Ep); + + element_clear(a); + element_clear(b); + field_init_fi(p->Fp2, p->Fp); + + pairing->finalpow = a_finalpow; + pairing->G1 = pbc_malloc(sizeof(field_t)); + pairing->G2 = pairing->G1 = p->Ep; + pairing_GT_init(pairing, p->Fp2); + + pairing->map = a1_pairing_proj; //default uses projective coordinates. + pairing->phi = phi_identity; + pairing->prod_pairings = a1_pairings_affine; + + pairing->clear_func = a1_pairing_clear; + + pairing->pp_init = a1_pairing_pp_init; + pairing->pp_clear = a1_pairing_pp_clear; + pairing->pp_apply = a1_pairing_pp_apply; + pairing->option_set = a1_pairing_option_set; +} + +static void a1_init(pbc_param_t p) { + static pbc_param_interface_t interface = {{ + a1_clear, + a1_init_pairing, + a1_out_str, + }}; + p->api = interface; + a1_param_ptr param = p->data = pbc_malloc(sizeof(*param)); + mpz_init(param->p); + mpz_init(param->n); +} + +// Public interface: + +int pbc_param_init_a1(pbc_param_ptr par, struct symtab_s *tab) { + a1_init(par); + a1_param_ptr p = par->data; + + int err = 0; + err += lookup_mpz(p->p, tab, "p"); + err += lookup_mpz(p->n, tab, "n"); + err += lookup_int(&p->l, tab, "l"); + return err; +} + +void pbc_param_init_a1_gen(pbc_param_ptr par, mpz_t order) { + a1_init(par); + a1_param_ptr param = par->data; + // If order is even, ideally check all even l, not just multiples of 4 + // but I don't see a good reason for having an even order. + unsigned int l = 4; + mpz_t n; + mpz_ptr p = param->p; + mpz_init(n); + mpz_mul_ui(n, order, 4); + mpz_sub_ui(p, n, 1); + for (;;) { + if (mpz_probab_prime_p(p, 20)) { + break; + } + mpz_add(p, p, n); + l += 4; + } + param->l = l; + mpz_set(param->n, order); + mpz_clear(n); +} diff --git a/moon-abe/pbc-0.5.14/ecc/curve.c b/moon-abe/pbc-0.5.14/ecc/curve.c new file mode 100644 index 00000000..3bc1f020 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/curve.c @@ -0,0 +1,987 @@ +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> // for intptr_t +#include <stdlib.h> +#include <string.h> +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_multiz.h" +#include "pbc_poly.h" +#include "pbc_curve.h" +#include "pbc_memory.h" +#include "pbc_random.h" +#include "misc/darray.h" + +// Per-field data. +typedef struct { + field_ptr field; // The field where the curve is defined. + element_t a, b; // The curve is E: Y^2 = X^3 + a X + b. + // cofac == NULL means we're using the whole group of points. + // otherwise we're working in the subgroup of order #E / cofac, + // where #E is the number of points in E. + mpz_ptr cofac; + // A generator of E. + element_t gen_no_cofac; + // A generator of the subgroup. + element_t gen; + // A non-NULL quotient_cmp means we are working with the quotient group of + // order #E / quotient_cmp, and the points are actually coset + // representatives. Thus for a comparison, we must multiply by quotient_cmp + // before comparing. + mpz_ptr quotient_cmp; +} *curve_data_ptr; + +// Per-element data. Elements of this group are points on the elliptic curve. +typedef struct { + int inf_flag; // inf_flag == 1 means O, the point at infinity. + element_t x, y; // Otherwise we have the finite point (x, y). +} *point_ptr; + +static void curve_init(element_ptr e) { + curve_data_ptr cdp = e->field->data; + point_ptr p = e->data = pbc_malloc(sizeof(*p)); + element_init(p->x, cdp->field); + element_init(p->y, cdp->field); + p->inf_flag = 1; +} + +static void curve_clear(element_ptr e) { + point_ptr p = e->data; + element_clear(p->x); + element_clear(p->y); + pbc_free(e->data); +} + +static int curve_is_valid_point(element_ptr e) { + element_t t0, t1; + int result; + curve_data_ptr cdp = e->field->data; + point_ptr p = e->data; + + if (p->inf_flag) return 1; + + element_init(t0, cdp->field); + element_init(t1, cdp->field); + element_square(t0, p->x); + element_add(t0, t0, cdp->a); + element_mul(t0, t0, p->x); + element_add(t0, t0, cdp->b); + element_square(t1, p->y); + result = !element_cmp(t0, t1); + + element_clear(t0); + element_clear(t1); + return result; +} + +static void curve_invert(element_ptr c, element_ptr a) { + point_ptr r = c->data, p = a->data; + + if (p->inf_flag) { + r->inf_flag = 1; + return; + } + r->inf_flag = 0; + element_set(r->x, p->x); + element_neg(r->y, p->y); +} + +static void curve_set(element_ptr c, element_ptr a) { + point_ptr r = c->data, p = a->data; + if (p->inf_flag) { + r->inf_flag = 1; + return; + } + r->inf_flag = 0; + element_set(r->x, p->x); + element_set(r->y, p->y); +} + +static inline void double_no_check(point_ptr r, point_ptr p, element_ptr a) { + element_t lambda, e0, e1; + field_ptr f = r->x->field; + + element_init(lambda, f); + element_init(e0, f); + element_init(e1, f); + + //lambda = (3x^2 + a) / 2y + element_square(lambda, p->x); + element_mul_si(lambda, lambda, 3); + element_add(lambda, lambda, a); + + element_double(e0, p->y); + + element_invert(e0, e0); + element_mul(lambda, lambda, e0); + //x1 = lambda^2 - 2x + //element_add(e1, p->x, p->x); + element_double(e1, p->x); + element_square(e0, lambda); + element_sub(e0, e0, e1); + //y1 = (x - x1)lambda - y + element_sub(e1, p->x, e0); + element_mul(e1, e1, lambda); + element_sub(e1, e1, p->y); + + element_set(r->x, e0); + element_set(r->y, e1); + r->inf_flag = 0; + + element_clear(lambda); + element_clear(e0); + element_clear(e1); + return; +} + +static void curve_double(element_ptr c, element_ptr a) { + curve_data_ptr cdp = a->field->data; + point_ptr r = c->data, p = a->data; + if (p->inf_flag) { + r->inf_flag = 1; + return; + } + if (element_is0(p->y)) { + r->inf_flag = 1; + return; + } + double_no_check(r, p, cdp->a); +} + +static void curve_mul(element_ptr c, element_ptr a, element_ptr b) { + curve_data_ptr cdp = a->field->data; + point_ptr r = c->data, p = a->data, q = b->data; + + if (p->inf_flag) { + curve_set(c, b); + return; + } + if (q->inf_flag) { + curve_set(c, a); + return; + } + if (!element_cmp(p->x, q->x)) { + if (!element_cmp(p->y, q->y)) { + if (element_is0(p->y)) { + r->inf_flag = 1; + return; + } else { + double_no_check(r, p, cdp->a); + return; + } + } + //points are inverses of each other + r->inf_flag = 1; + return; + } else { + element_t lambda, e0, e1; + + element_init(lambda, cdp->field); + element_init(e0, cdp->field); + element_init(e1, cdp->field); + + //lambda = (y2-y1)/(x2-x1) + element_sub(e0, q->x, p->x); + element_invert(e0, e0); + element_sub(lambda, q->y, p->y); + element_mul(lambda, lambda, e0); + //x3 = lambda^2 - x1 - x2 + element_square(e0, lambda); + element_sub(e0, e0, p->x); + element_sub(e0, e0, q->x); + //y3 = (x1-x3)lambda - y1 + element_sub(e1, p->x, e0); + element_mul(e1, e1, lambda); + element_sub(e1, e1, p->y); + + element_set(r->x, e0); + element_set(r->y, e1); + r->inf_flag = 0; + + element_clear(lambda); + element_clear(e0); + element_clear(e1); + } +} + +//compute c_i=a_i+a_i at one time. +static void multi_double(element_ptr c[], element_ptr a[], int n) { + int i; + element_t* table = pbc_malloc(sizeof(element_t)*n); //a big problem? + element_t e0, e1, e2; + point_ptr q, r; + curve_data_ptr cdp = a[0]->field->data; + + q=a[0]->data; + element_init(e0,q->y->field); + element_init(e1,q->y->field); + element_init(e2,q->y->field); + + for(i=0; i<n; i++){ + q=a[i]->data; r=c[i]->data; + element_init(table[i],q->y->field); + + if (q->inf_flag) { + r->inf_flag = 1; + continue; + } + if (element_is0(q->y)) { + r->inf_flag = 1; + continue; + } + } + //to compute 1/2y multi. see Cohen's GTM139 Algorithm 10.3.4 + for(i=0; i<n; i++){ + q=a[i]->data; + element_double(table[i],q->y); + if(i>0) element_mul(table[i],table[i],table[i-1]); + } + element_invert(e2,table[n-1]); //ONLY ONE inv is required now. + for(i=n-1; i>0; i--){ + q=a[i]->data; + element_mul(table[i],table[i-1],e2); + element_mul(e2,e2,q->y); + element_double(e2,e2); //e2=e2*2y_j + } + element_set(table[0],e2); //e2 no longer used. + + for(i=0; i<n; i++){ + q=a[i]->data; + r=c[i]->data; + if(r->inf_flag) continue; + + //e2=lambda = (3x^2 + a) / 2y + element_square(e2, q->x); + element_mul_si(e2, e2, 3); + element_add(e2, e2, cdp->a); + + element_mul(e2, e2, table[i]); //Recall that table[i]=1/2y_i + //x1 = lambda^2 - 2x + element_double(e1, q->x); + element_square(e0, e2); + element_sub(e0, e0, e1); + //y1 = (x - x1)lambda - y + element_sub(e1, q->x, e0); + element_mul(e1, e1, e2); + element_sub(e1, e1, q->y); + element_set(r->x, e0); + element_set(r->y, e1); + r->inf_flag = 0; + } + + element_clear(e0); + element_clear(e1); + element_clear(e2); + for(i=0; i<n; i++){ + element_clear(table[i]); + } + pbc_free(table); +} + +//compute c_i=a_i+b_i at one time. +static void multi_add(element_ptr c[], element_ptr a[], element_ptr b[], int n){ + int i; + element_t* table = pbc_malloc(sizeof(element_t)*n); //a big problem? + point_ptr p, q, r; + element_t e0, e1, e2; + curve_data_ptr cdp = a[0]->field->data; + + p = a[0]->data; + q = b[0]->data; + element_init(e0, p->x->field); + element_init(e1, p->x->field); + element_init(e2, p->x->field); + + element_init(table[0], p->x->field); + element_sub(table[0], q->x, p->x); + for(i=1; i<n; i++){ + p = a[i]->data; + q = b[i]->data; + element_init(table[i], p->x->field); + element_sub(table[i], q->x, p->x); + element_mul(table[i], table[i], table[i-1]); + } + element_invert(e2, table[n-1]); + for(i=n-1; i>0; i--){ + p = a[i]->data; + q = b[i]->data; + element_mul(table[i], table[i-1], e2); + element_sub(e1, q->x, p->x); + element_mul(e2,e2,e1); //e2=e2*(x2_j-x1_j) + } + element_set(table[0],e2); //e2 no longer used. + + for(i=0; i<n; i++){ + p = a[i]->data; + q = b[i]->data; + r = c[i]->data; + if (p->inf_flag) { + curve_set(c[i], b[i]); + continue; + } + if (q->inf_flag) { + curve_set(c[i], a[i]); + continue; + } + if (!element_cmp(p->x, q->x)) { //a[i]=b[i] + if (!element_cmp(p->y, q->y)) { + if (element_is0(p->y)) { + r->inf_flag = 1; + continue; + } else { + double_no_check(r, p, cdp->a); + continue; + } + } + //points are inverses of each other + r->inf_flag = 1; + continue; + } else { + //lambda = (y2-y1)/(x2-x1) + element_sub(e2, q->y, p->y); + element_mul(e2, e2, table[i]); + //x3 = lambda^2 - x1 - x2 + element_square(e0, e2); + element_sub(e0, e0, p->x); + element_sub(e0, e0, q->x); + //y3 = (x1-x3)lambda - y1 + element_sub(e1, p->x, e0); + element_mul(e1, e1, e2); + element_sub(e1, e1, p->y); + element_set(r->x, e0); + element_set(r->y, e1); + r->inf_flag = 0; + } + } + element_clear(e0); + element_clear(e1); + element_clear(e2); + for(i=0; i<n; i++){ + element_clear(table[i]); + } + pbc_free(table); +} + + +static inline int point_cmp(point_ptr p, point_ptr q) { + if (p->inf_flag || q->inf_flag) { + return !(p->inf_flag && q->inf_flag); + } + return element_cmp(p->x, q->x) || element_cmp(p->y, q->y); +} + +static int curve_cmp(element_ptr a, element_ptr b) { + if (a == b) { + return 0; + } else { + // If we're working with a quotient group we must account for different + // representatives of the same coset. + curve_data_ptr cdp = a->field->data; + if (cdp->quotient_cmp) { + element_t e; + element_init_same_as(e, a); + element_div(e, a, b); + element_pow_mpz(e, e, cdp->quotient_cmp); + int result = !element_is1(e); + element_clear(e); + return result; + } + return point_cmp(a->data, b->data); + } +} + +static void curve_set1(element_ptr x) { + point_ptr p = x->data; + p->inf_flag = 1; +} + +static int curve_is1(element_ptr x) { + point_ptr p = x->data; + return p->inf_flag; +} + +static void curve_random_no_cofac_solvefory(element_ptr a) { + //TODO: with 0.5 probability negate y-coord + curve_data_ptr cdp = a->field->data; + point_ptr p = a->data; + element_t t; + + element_init(t, cdp->field); + p->inf_flag = 0; + do { + element_random(p->x); + element_square(t, p->x); + element_add(t, t, cdp->a); + element_mul(t, t, p->x); + element_add(t, t, cdp->b); + } while (!element_is_sqr(t)); + element_sqrt(p->y, t); + element_clear(t); +} + +static void curve_random_solvefory(element_ptr a) { + curve_data_ptr cdp = a->field->data; + curve_random_no_cofac_solvefory(a); + if (cdp->cofac) element_mul_mpz(a, a, cdp->cofac); +} + +static void curve_random_pointmul(element_ptr a) { + curve_data_ptr cdp = a->field->data; + mpz_t x; + mpz_init(x); + + pbc_mpz_random(x, a->field->order); + element_mul_mpz(a, cdp->gen, x); + mpz_clear(x); +} + +void field_curve_use_random_solvefory(field_ptr f) { + f->random = curve_random_solvefory; +} + +void curve_set_gen_no_cofac(element_ptr a) { + curve_data_ptr cdp = a->field->data; + element_set(a, cdp->gen_no_cofac); +} + +static int curve_sign(element_ptr e) { + point_ptr p = e->data; + if (p->inf_flag) return 0; + return element_sign(p->y); +} + +static void curve_from_hash(element_t a, void *data, int len) { + element_t t, t1; + point_ptr p = a->data; + curve_data_ptr cdp = a->field->data; + + element_init(t, cdp->field); + element_init(t1, cdp->field); + p->inf_flag = 0; + element_from_hash(p->x, data, len); + for(;;) { + element_square(t, p->x); + element_add(t, t, cdp->a); + element_mul(t, t, p->x); + element_add(t, t, cdp->b); + if (element_is_sqr(t)) break; + // Compute x <- x^2 + 1 and try again. + element_square(p->x, p->x); + element_set1(t); + element_add(p->x, p->x, t); + } + element_sqrt(p->y, t); + if (element_sgn(p->y) < 0) element_neg(p->y, p->y); + + if (cdp->cofac) element_mul_mpz(a, a, cdp->cofac); + + element_clear(t); + element_clear(t1); +} + +static size_t curve_out_str(FILE *stream, int base, element_ptr a) { + point_ptr p = a->data; + size_t result, status; + if (p->inf_flag) { + if (EOF == fputc('O', stream)) return 0; + return 1; + } + if (EOF == fputc('[', stream)) return 0; + result = element_out_str(stream, base, p->x); + if (!result) return 0; + if (EOF == fputs(", ", stream)) return 0; + status = element_out_str(stream, base, p->y); + if (!status) return 0; + if (EOF == fputc(']', stream)) return 0; + return result + status + 4; +} + +static int curve_snprint(char *s, size_t n, element_ptr a) { + point_ptr p = a->data; + size_t result = 0, left; + int status; + + #define clip_sub() { \ + result += status; \ + left = result >= n ? 0 : n - result; \ + } + + if (p->inf_flag) { + status = snprintf(s, n, "O"); + if (status < 0) return status; + return 1; + } + + status = snprintf(s, n, "["); + if (status < 0) return status; + clip_sub(); + status = element_snprint(s + result, left, p->x); + if (status < 0) return status; + clip_sub(); + status = snprintf(s + result, left, ", "); + if (status < 0) return status; + clip_sub(); + status = element_snprint(s + result, left, p->y); + if (status < 0) return status; + clip_sub(); + status = snprintf(s + result, left, "]"); + if (status < 0) return status; + return result + status; + #undef clip_sub +} + +static void curve_set_multiz(element_ptr a, multiz m) { + if (multiz_is_z(m)) { + if (multiz_is0(m)) { + element_set0(a); + return; + } + pbc_warn("bad multiz"); + return; + } else { + if (multiz_count(m) < 2) { + pbc_warn("multiz has too few coefficients"); + return; + } + point_ptr p = a->data; + p->inf_flag = 0; + element_set_multiz(p->x, multiz_at(m, 0)); + element_set_multiz(p->y, multiz_at(m, 1)); + } +} + +static int curve_set_str(element_ptr e, const char *s, int base) { + point_ptr p = e->data; + const char *cp = s; + element_set0(e); + while (*cp && isspace(*cp)) cp++; + if (*cp == 'O') { + return cp - s + 1; + } + p->inf_flag = 0; + if (*cp != '[') return 0; + cp++; + cp += element_set_str(p->x, cp, base); + while (*cp && isspace(*cp)) cp++; + if (*cp != ',') return 0; + cp++; + cp += element_set_str(p->y, cp, base); + if (*cp != ']') return 0; + + if (!curve_is_valid_point(e)) { + element_set0(e); + return 0; + } + return cp - s + 1; +} + +static void field_clear_curve(field_t f) { + curve_data_ptr cdp; + cdp = f->data; + element_clear(cdp->gen); + element_clear(cdp->gen_no_cofac); + if (cdp->cofac) { + mpz_clear(cdp->cofac); + pbc_free(cdp->cofac); + } + if (cdp->quotient_cmp) { + mpz_clear(cdp->quotient_cmp); + pbc_free(cdp->quotient_cmp); + } + element_clear(cdp->a); + element_clear(cdp->b); + pbc_free(cdp); +} + +static int curve_length_in_bytes(element_ptr x) { + point_ptr p = x->data; + return element_length_in_bytes(p->x) + element_length_in_bytes(p->y); +} + +static int curve_to_bytes(unsigned char *data, element_t e) { + point_ptr P = e->data; + int len; + len = element_to_bytes(data, P->x); + len += element_to_bytes(data + len, P->y); + return len; +} + +static int curve_from_bytes(element_t e, unsigned char *data) { + point_ptr P = e->data; + int len; + + P->inf_flag = 0; + len = element_from_bytes(P->x, data); + len += element_from_bytes(P->y, data + len); + //if point does not lie on curve, set it to O + if (!curve_is_valid_point(e)) { + element_set0(e); + } + return len; +} + +static void curve_out_info(FILE *out, field_t f) { + int len; + fprintf(out, "elliptic curve"); + if ((len = f->fixed_length_in_bytes)) { + fprintf(out, ", bits per coord = %d", len * 8 / 2); + } else { + fprintf(out, "variable-length"); + } +} + +static int odd_curve_is_sqr(element_ptr e) { + UNUSED_VAR(e); + return 1; +} + +//TODO: untested +static int even_curve_is_sqr(element_ptr e) { + mpz_t z; + element_t e1; + int result; + + mpz_init(z); + element_init(e1, e->field); + mpz_sub_ui(z, e->field->order, 1); + mpz_fdiv_q_2exp(z, z, 1); + element_pow_mpz(e1, e, z); + result = element_is1(e1); + + mpz_clear(z); + element_clear(e1); + return result; +} + +static int curve_item_count(element_ptr e) { + if (element_is0(e)) { + return 0; + } + return 2; +} + +static element_ptr curve_item(element_ptr e, int i) { + if (element_is0(e)) return NULL; + point_ptr P = e->data; + switch(i) { + case 0: + return P->x; + case 1: + return P->y; + default: + return NULL; + } +} + +static element_ptr curve_get_x(element_ptr e) { + point_ptr P = e->data; + return P->x; +} + +static element_ptr curve_get_y(element_ptr e) { + point_ptr P = e->data; + return P->y; +} + +void field_init_curve_ab(field_ptr f, element_ptr a, element_ptr b, mpz_t order, mpz_t cofac) { + /* + if (element_is0(a)) { + c->double_nocheck = cc_double_no_check_ais0; + } else { + c->double_nocheck = cc_double_no_check; + } + */ + curve_data_ptr cdp; + field_init(f); + mpz_set(f->order, order); + cdp = f->data = pbc_malloc(sizeof(*cdp)); + cdp->field = a->field; + element_init(cdp->a, cdp->field); + element_init(cdp->b, cdp->field); + element_set(cdp->a, a); + element_set(cdp->b, b); + + f->init = curve_init; + f->clear = curve_clear; + f->neg = f->invert = curve_invert; + f->square = f->doub = curve_double; + f->multi_doub = multi_double; + f->add = f->mul = curve_mul; + f->multi_add = multi_add; + f->mul_mpz = element_pow_mpz; + f->cmp = curve_cmp; + f->set0 = f->set1 = curve_set1; + f->is0 = f->is1 = curve_is1; + f->sign = curve_sign; + f->set = curve_set; + f->random = curve_random_pointmul; + //f->random = curve_random_solvefory; + f->from_hash = curve_from_hash; + f->out_str = curve_out_str; + f->snprint = curve_snprint; + f->set_multiz = curve_set_multiz; + f->set_str = curve_set_str; + f->field_clear = field_clear_curve; + if (cdp->field->fixed_length_in_bytes < 0) { + f->length_in_bytes = curve_length_in_bytes; + } else { + f->fixed_length_in_bytes = 2 * cdp->field->fixed_length_in_bytes; + } + f->to_bytes = curve_to_bytes; + f->from_bytes = curve_from_bytes; + f->out_info = curve_out_info; + f->item_count = curve_item_count; + f->item = curve_item; + f->get_x = curve_get_x; + f->get_y = curve_get_y; + + if (mpz_odd_p(order)) { + f->is_sqr = odd_curve_is_sqr; + } else { + f->is_sqr = even_curve_is_sqr; + } + + element_init(cdp->gen_no_cofac, f); + element_init(cdp->gen, f); + curve_random_no_cofac_solvefory(cdp->gen_no_cofac); + if (cofac) { + cdp->cofac = pbc_malloc(sizeof(mpz_t)); + mpz_init(cdp->cofac); + mpz_set(cdp->cofac, cofac); + element_mul_mpz(cdp->gen, cdp->gen_no_cofac, cofac); + } else{ + cdp->cofac = NULL; + element_set(cdp->gen, cdp->gen_no_cofac); + } + cdp->quotient_cmp = NULL; +} + +// Requires e to be a point on an elliptic curve. +int element_to_bytes_compressed(unsigned char *data, element_ptr e) { + point_ptr P = e->data; + int len; + len = element_to_bytes(data, P->x); + if (element_sign(P->y) > 0) { + data[len] = 1; + } else { + data[len] = 0; + } + len++; + return len; +} + +// Computes a point on the elliptic curve Y^2 = X^3 + a X + b given its +// x-coordinate. +// Requires a solution to exist. +static void point_from_x(point_ptr p, element_t x, element_t a, element_t b) { + element_t t; + + element_init(t, x->field); + p->inf_flag = 0; + element_square(t, x); + element_add(t, t, a); + element_mul(t, t, x); + element_add(t, t, b); + element_sqrt(p->y, t); + element_set(p->x, x); + + element_clear(t); +} + +void curve_from_x(element_ptr e, element_t x) { + curve_data_ptr cdp = e->field->data; + point_from_x(e->data, x, cdp->a, cdp->b); +} + +// Requires e to be a point on an elliptic curve. +int element_from_bytes_compressed(element_ptr e, unsigned char *data) { + curve_data_ptr cdp = e->field->data; + point_ptr P = e->data; + int len; + len = element_from_bytes(P->x, data); + point_from_x(P, P->x, cdp->a, cdp->b); + + if (data[len]) { + if (element_sign(P->y) < 0) element_neg(P->y, P->y); + } else if (element_sign(P->y) > 0) { + element_neg(P->y, P->y); + } + len++; + return len; +} + +int element_length_in_bytes_compressed(element_ptr e) { + point_ptr P = e->data; + return element_length_in_bytes(P->x) + 1; +} + +// Requires e to be a point on an elliptic curve. +int element_to_bytes_x_only(unsigned char *data, element_ptr e) { + point_ptr P = e->data; + int len; + len = element_to_bytes(data, P->x); + return len; +} + +// Requires e to be a point on an elliptic curve. +int element_from_bytes_x_only(element_ptr e, unsigned char *data) { + curve_data_ptr cdp = e->field->data; + point_ptr P = e->data; + int len; + len = element_from_bytes(P->x, data); + point_from_x(P, P->x, cdp->a, cdp->b); + return len; +} + +int element_length_in_bytes_x_only(element_ptr e) { + point_ptr P = e->data; + return element_length_in_bytes(P->x); +} + +inline element_ptr curve_x_coord(element_t e) { + return ((point_ptr) e->data)->x; +} + +inline element_ptr curve_y_coord(element_t e) { + return ((point_ptr) e->data)->y; +} + +inline element_ptr curve_a_coeff(element_t e) { + return ((curve_data_ptr) e->field->data)->a; +} + +inline element_ptr curve_b_coeff(element_t e) { + return ((curve_data_ptr) e->field->data)->b; +} + +inline element_ptr curve_field_a_coeff(field_t f) { + return ((curve_data_ptr) f->data)->a; +} + +inline element_ptr curve_field_b_coeff(field_t f) { + return ((curve_data_ptr) f->data)->b; +} + +void field_init_curve_ab_map(field_t cnew, field_t c, + fieldmap map, field_ptr mapdest, + mpz_t ordernew, mpz_t cofacnew) { + element_t a, b; + curve_data_ptr cdp = c->data; + + element_init(a, mapdest); + element_init(b, mapdest); + + map(a, cdp->a); + map(b, cdp->b); + + field_init_curve_ab(cnew, a, b, ordernew, cofacnew); + element_clear(a); + element_clear(b); +} + +// Existing points are invalidated as this mangles c. +void field_reinit_curve_twist(field_ptr c) { + curve_data_ptr cdp = c->data; + element_ptr nqr = field_get_nqr(cdp->field); + element_mul(cdp->a, cdp->a, nqr); + element_mul(cdp->a, cdp->a, nqr); + element_mul(cdp->b, cdp->b, nqr); + element_mul(cdp->b, cdp->b, nqr); + element_mul(cdp->b, cdp->b, nqr); + + // Recompute generators. + curve_random_no_cofac_solvefory(cdp->gen_no_cofac); + if (cdp->cofac) { + element_mul_mpz(cdp->gen, cdp->gen_no_cofac, cdp->cofac); + } else{ + element_set(cdp->gen, cdp->gen_no_cofac); + } +} + +// I could generalize this for all fields, but is there any point? +void field_curve_set_quotient_cmp(field_ptr c, mpz_t quotient_cmp) { + curve_data_ptr cdp = c->data; + cdp->quotient_cmp = pbc_malloc(sizeof(mpz_t)); + mpz_init(cdp->quotient_cmp); + mpz_set(cdp->quotient_cmp, quotient_cmp); +} + +// Requires j != 0, 1728. +void field_init_curve_j(field_ptr f, element_ptr j, mpz_t order, mpz_t cofac) { + element_t a, b; + element_init(a, j->field); + element_init(b, j->field); + + element_set_si(a, 1728); + element_sub(a, a, j); + element_invert(a, a); + element_mul(a, a, j); + + //b = 2 j / (1728 - j) + element_add(b, a, a); + //a = 3 j / (1728 - j) + element_add(a, a, b); + field_init_curve_ab(f, a, b, order, cofac); + + element_clear(a); + element_clear(b); +} + +void field_init_curve_b(field_ptr f, element_ptr b, mpz_t order, mpz_t cofac) { + element_t a; + element_init(a, b->field); + field_init_curve_ab(f, a, b, order, cofac); + + element_clear(a); +} + +// Compute trace of Frobenius at q^n given trace at q. +// See p.105 of Blake, Seroussi and Smart. +void pbc_mpz_trace_n(mpz_t res, mpz_t q, mpz_t trace, int n) { + int i; + mpz_t c0, c1, c2; + mpz_t t0; + + mpz_init(c0); + mpz_init(c1); + mpz_init(c2); + mpz_init(t0); + mpz_set_ui(c2, 2); + mpz_set(c1, trace); + for (i=2; i<=n; i++) { + mpz_mul(c0, trace, c1); + mpz_mul(t0, q, c2); + mpz_sub(c0, c0, t0); + mpz_set(c2, c1); + mpz_set(c1, c0); + } + mpz_set(res, c1); + mpz_clear(t0); + mpz_clear(c2); + mpz_clear(c1); + mpz_clear(c0); +} + +// Given q, t such that #E(F_q) = q - t + 1, compute #E(F_q^k). +void pbc_mpz_curve_order_extn(mpz_t res, mpz_t q, mpz_t t, int k) { + mpz_t z; + mpz_t tk; + mpz_init(z); + mpz_init(tk); + mpz_pow_ui(z, q, k); + mpz_add_ui(z, z, 1); + pbc_mpz_trace_n(tk, q, t, k); + mpz_sub(z, z, tk); + mpz_set(res, z); + mpz_clear(z); + mpz_clear(tk); +} + +void curve_set_si(element_t R, long int x, long int y) { + point_ptr p = R->data; + element_set_si(p->x, x); + element_set_si(p->y, y); + p->inf_flag = 0; +} diff --git a/moon-abe/pbc-0.5.14/ecc/d_param.c b/moon-abe/pbc-0.5.14/ecc/d_param.c new file mode 100644 index 00000000..8b7d6ac5 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/d_param.c @@ -0,0 +1,1258 @@ +// Type D pairings, aka MNT curves. + +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> // for intptr_t +#include <stdlib.h> +#include <string.h> +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_poly.h" +#include "pbc_hilbert.h" +#include "pbc_fp.h" +#include "pbc_fieldquadratic.h" +#include "pbc_mnt.h" +#include "pbc_curve.h" +#include "pbc_param.h" +#include "pbc_pairing.h" +#include "pbc_memory.h" +#include "pbc_d_param.h" +#include "ecc/param.h" + +struct d_param_s { + mpz_t q; // curve defined over F_q + mpz_t n; // has order n (= q - t + 1) in F_q + mpz_t h; // h * r = n, r is prime + mpz_t r; + mpz_t a, b; // curve equation is y^2 = x^3 + ax + b + int k; // embedding degree + mpz_t nk; // order of curve over F_q^k + mpz_t hk; // hk * r^2 = nk + mpz_t *coeff; // coefficients of polynomial used to extend F_q by k/2 + mpz_t nqr; // a quadratic nonresidue in F_q^d that lies in F_q +}; + +typedef struct d_param_s d_param_t[1]; +typedef struct d_param_s *d_param_ptr; + +// Per-pairing data. +typedef struct { + field_t Fq, Fqx, Fqd, Fqk; // The fields F_q, F_q[x], F_q^d, F_q^k. + field_t Eq, Etwist; // The curves E(F_q) and E'(F_q^d). + // Let v be the quadratic nonresidue used to construct F_q^k from F_q^d, + // namely Fqk = Fqd[sqrt(v)]. + element_t nqrinv, nqrinv2; // The constants v^-1 and v^-2. + mpz_t tateexp; // The Tate exponent, + // to standardize coset representatives. + int k; // The embedding degree, usually 6. + // Let x be the element used to build Fqd from Fq, i.e. Fqd = Fq[x]. + element_t xpowq, xpowq2; // x^q and x^{2q} in F_q^d. +} *pptr; + +static void d_clear(void *data) { + d_param_ptr param = data; + int d = param->k / 2; + int i; + mpz_clear(param->q); + mpz_clear(param->n); + mpz_clear(param->h); + mpz_clear(param->r); + mpz_clear(param->a); + mpz_clear(param->b); + mpz_clear(param->nk); + mpz_clear(param->hk); + mpz_clear(param->nqr); + for (i=0; i<d; i++) { + mpz_clear(param->coeff[i]); + } + pbc_free(param->coeff); + pbc_free(data); +} + +static void d_out_str(FILE *stream, void *data) { + d_param_ptr p = data; + int d = p->k / 2; + int i; + char s[8]; + param_out_type(stream, "d"); + param_out_mpz(stream, "q", p->q); + param_out_mpz(stream, "n", p->n); + param_out_mpz(stream, "h", p->h); + param_out_mpz(stream, "r", p->r); + param_out_mpz(stream, "a", p->a); + param_out_mpz(stream, "b", p->b); + param_out_int(stream, "k", p->k); + param_out_mpz(stream, "nk", p->nk); + param_out_mpz(stream, "hk", p->hk); + for (i=0; i<d; i++) { + sprintf(s, "coeff%d", i); + param_out_mpz(stream, s, p->coeff[i]); + } + param_out_mpz(stream, "nqr", p->nqr); +} + +// 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); +} + +// 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) { + int 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 = mpz_sizeinbase(q, 2) - 2; + + 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 +} + +// 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) { + int 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 = mpz_sizeinbase(q, 2) - 2; + + 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 void (*cc_miller_no_denom_fn)(element_t res, mpz_t q, element_t P, + element_ptr Qx, element_ptr Qy); + +static void d_pairing_option_set(pairing_t pairing, char *key, char *value) { + UNUSED_VAR(pairing); + if (!strcmp(key, "method")) { + if (!strcmp(value, "miller")) { + cc_miller_no_denom_fn = cc_miller_no_denom_proj; + } else if (!strcmp(value, "miller-affine")) { + cc_miller_no_denom_fn = cc_miller_no_denom_affine; + } + } +} + +// 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); + int 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); +} + +// 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 +} + +static void cc_finalpow(element_t e) { + cc_tatepower(e->data, e->data, e->field->pairing); +} + +static void cc_pairing(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + element_ptr Qbase = in2; + element_t Qx, Qy; + pptr p = pairing->data; + + element_init(Qx, p->Fqd); + element_init(Qy, p->Fqd); + // Twist: (x, y) --> (v^-1 x, v^-(3/2) y) + // where v is the quadratic nonresidue used to construct the twist. + element_mul(Qx, curve_x_coord(Qbase), p->nqrinv); + // v^-3/2 = v^-2 * v^1/2 + element_mul(Qy, curve_y_coord(Qbase), p->nqrinv2); + cc_miller_no_denom_fn(out, pairing->r, in1, Qx, Qy); + cc_tatepower(out, out, pairing); + element_clear(Qx); + element_clear(Qy); +} + + +//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) { + int m, 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 = mpz_sizeinbase(q, 2) - 2; + + 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 +} + + +void cc_pairings_affine(element_ptr out, element_t in1[], element_t in2[], + int n_prod, pairing_t pairing) { + element_ptr Qbase; + element_t* Qx = pbc_malloc(sizeof(element_t)*n_prod); + element_t* Qy = pbc_malloc(sizeof(element_t)*n_prod); + pptr p = pairing->data; + int i; + for(i=0; i<n_prod; i++){ + element_init(Qx[i], p->Fqd); + element_init(Qy[i], p->Fqd); + Qbase = in2[i]; + // Twist: (x, y) --> (v^-1 x, v^-(3/2) y) + // where v is the quadratic nonresidue used to construct the twist. + element_mul(Qx[i], curve_x_coord(Qbase), p->nqrinv); + // v^-3/2 = v^-2 * v^1/2 + element_mul(Qy[i], curve_y_coord(Qbase), p->nqrinv2); + } + cc_millers_no_denom_affine(out, pairing->r, in1, Qx, Qy, n_prod); + cc_tatepower(out, out, pairing); + + for(i=0; i<n_prod; i++){ + element_clear(Qx[i]); + element_clear(Qy[i]); + } + pbc_free(Qx); + pbc_free(Qy); +} + + +static int cc_is_almost_coddh(element_ptr a, element_ptr b, + element_ptr c, element_ptr d, + pairing_t pairing) { + int res = 0; + element_t t0, t1, t2; + element_t cx, cy; + element_t dx, dy; + pptr p = pairing->data; + + element_init(cx, p->Fqd); + element_init(cy, p->Fqd); + element_init(dx, p->Fqd); + element_init(dy, p->Fqd); + + element_init(t0, p->Fqk); + element_init(t1, p->Fqk); + element_init(t2, p->Fqk); + // Twist: (x, y) --> (v^-1 x, v^-(3/2) y) + // where v is the quadratic nonresidue used to construct the twist. + element_mul(cx, curve_x_coord(c), p->nqrinv); + element_mul(dx, curve_x_coord(d), p->nqrinv); + // v^-3/2 = v^-2 * v^1/2 + element_mul(cy, curve_y_coord(c), p->nqrinv2); + element_mul(dy, curve_y_coord(d), p->nqrinv2); + + cc_miller_no_denom_fn(t0, pairing->r, a, dx, dy); + cc_miller_no_denom_fn(t1, pairing->r, b, cx, cy); + cc_tatepower(t0, t0, pairing); + cc_tatepower(t1, t1, pairing); + element_mul(t2, t0, t1); + if (element_is1(t2)) res = 1; // We were given g, g^x, h, h^-x. + else { + // Cheaply check the other case. + element_invert(t1, t1); + element_mul(t2, t0, t1); + if (element_is1(t2)) res = 1; // We were given g, g^x, h, h^x. + } + element_clear(cx); + element_clear(cy); + element_clear(dx); + element_clear(dy); + element_clear(t0); + element_clear(t1); + element_clear(t2); + return res; +} + +struct pp_coeff_s { + element_t a; + element_t b; + element_t c; +}; +typedef struct pp_coeff_s pp_coeff_t[1]; +typedef struct pp_coeff_s *pp_coeff_ptr; + +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; + int 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 = mpz_sizeinbase(q, 2) - 2; + 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 +} + +static void d_pairing_pp_clear(pairing_pp_t p) { + // TODO: Better to store a sentinel value in p->data? + mpz_ptr q = p->pairing->r; + int m = mpz_sizeinbase(q, 2) + mpz_popcount(q) - 3; + int i; + pp_coeff_t *coeff = (pp_coeff_t *) p->data; + pp_coeff_ptr pp; + for (i=0; i<m; i++) { + pp = coeff[i]; + element_clear(pp->a); + element_clear(pp->b); + element_clear(pp->c); + } + pbc_free(p->data); +} + +static void d_pairing_pp_apply(element_ptr out, element_ptr in2, + pairing_pp_t p) { + mpz_ptr q = p->pairing->r; + pptr info = p->pairing->data; + int m = mpz_sizeinbase(q, 2) - 2; + pp_coeff_t *coeff = (pp_coeff_t *) p->data; + pp_coeff_ptr pp = coeff[0]; + element_ptr Qbase = in2; + element_t e0; + element_t Qx, Qy; + element_t v; + element_init_same_as(e0, out); + element_init_same_as(v, out); + element_init(Qx, info->Fqd); + element_init(Qy, info->Fqd); + + // Twist: (x, y) --> (v^-1 x, v^-(3/2) y) + // where v is the quadratic nonresidue used to construct the twist + element_mul(Qx, curve_x_coord(Qbase), info->nqrinv); + // v^-3/2 = v^-2 * v^1/2 + element_mul(Qy, curve_y_coord(Qbase), info->nqrinv2); + + element_set1(out); + for(;;) { + d_miller_evalfn(e0, pp->a, pp->b, pp->c, Qx, Qy); + element_mul(out, out, e0); + pp++; + + if (!m) break; + + if (mpz_tstbit(q, m)) { + d_miller_evalfn(e0, pp->a, pp->b, pp->c, Qx, Qy); + element_mul(out, out, e0); + pp++; + } + m--; + element_square(out, out); + } + cc_tatepower(out, out, p->pairing); + + element_clear(e0); + element_clear(Qx); + element_clear(Qy); + element_clear(v); +} + +static void d_pairing_clear(pairing_t pairing) { + field_clear(pairing->GT); + pptr p = pairing->data; + + if (p->k == 6) { + element_clear(p->xpowq); + element_clear(p->xpowq2); + mpz_clear(pairing->phikonr); + } else { + mpz_clear(p->tateexp); + } + + field_clear(p->Etwist); + field_clear(p->Eq); + element_clear(p->nqrinv); + element_clear(p->nqrinv2); + field_clear(p->Fqk); + field_clear(p->Fqd); + field_clear(p->Fqx); + field_clear(p->Fq); + field_clear(pairing->Zr); + mpz_clear(pairing->r); + pbc_free(p); +} + +static void d_init_pairing(pairing_ptr pairing, void *data) { + d_param_ptr param = data; + pptr p; + element_t a, b; + element_t irred; + int d = param->k / 2; + int i; + + if (param->k % 2) pbc_die("k must be even"); + + mpz_init(pairing->r); + mpz_set(pairing->r, param->r); + field_init_fp(pairing->Zr, pairing->r); + pairing->map = cc_pairing; + pairing->prod_pairings = cc_pairings_affine; + pairing->is_almost_coddh = cc_is_almost_coddh; + + p = pairing->data = pbc_malloc(sizeof(*p)); + field_init_fp(p->Fq, param->q); + element_init(a, p->Fq); + element_init(b, p->Fq); + element_set_mpz(a, param->a); + element_set_mpz(b, param->b); + field_init_curve_ab(p->Eq, a, b, pairing->r, param->h); + + field_init_poly(p->Fqx, p->Fq); + element_init(irred, p->Fqx); + poly_set_coeff1(irred, d); + for (i = 0; i < d; i++) { + element_set_mpz(element_item(irred, i), param->coeff[i]); + } + + field_init_polymod(p->Fqd, irred); + element_clear(irred); + + p->Fqd->nqr = pbc_malloc(sizeof(element_t)); + element_init(p->Fqd->nqr, p->Fqd); + element_set_mpz(((element_t *) p->Fqd->nqr->data)[0], param->nqr); + + field_init_quadratic(p->Fqk, p->Fqd); + + // Compute constants involved in the final powering. + if (param->k == 6) { + mpz_ptr q = param->q; + mpz_ptr z = pairing->phikonr; + mpz_init(z); + mpz_mul(z, q, q); + mpz_sub(z, z, q); + mpz_add_ui(z, z, 1); + mpz_divexact(z, z, pairing->r); + + element_ptr e = p->xpowq; + element_init(e, p->Fqd); + element_set1(((element_t *) e->data)[1]); + element_pow_mpz(e, e, q); + + element_init(p->xpowq2, p->Fqd); + element_square(p->xpowq2, e); + } else { + mpz_init(p->tateexp); + mpz_sub_ui(p->tateexp, p->Fqk->order, 1); + mpz_divexact(p->tateexp, p->tateexp, pairing->r); + } + + field_init_curve_ab_map(p->Etwist, p->Eq, element_field_to_polymod, p->Fqd, pairing->r, NULL); + field_reinit_curve_twist(p->Etwist); + + mpz_t ndonr; + mpz_init(ndonr); + // ndonr temporarily holds the trace. + mpz_sub(ndonr, param->q, param->n); + mpz_add_ui(ndonr, ndonr, 1); + // Negate it because we want the trace of the twist. + mpz_neg(ndonr, ndonr); + pbc_mpz_curve_order_extn(ndonr, param->q, ndonr, d); + mpz_divexact(ndonr, ndonr, param->r); + field_curve_set_quotient_cmp(p->Etwist, ndonr); + mpz_clear(ndonr); + + element_init(p->nqrinv, p->Fqd); + element_invert(p->nqrinv, field_get_nqr(p->Fqd)); + element_init(p->nqrinv2, p->Fqd); + element_square(p->nqrinv2, p->nqrinv); + + pairing->G1 = p->Eq; + pairing->G2 = p->Etwist; + + p->k = param->k; + pairing_GT_init(pairing, p->Fqk); + pairing->finalpow = cc_finalpow; + + // By default use affine coordinates. + cc_miller_no_denom_fn = cc_miller_no_denom_affine; + pairing->option_set = d_pairing_option_set; + pairing->pp_init = d_pairing_pp_init; + pairing->pp_clear = d_pairing_pp_clear; + pairing->pp_apply = d_pairing_pp_apply; + + pairing->clear_func = d_pairing_clear; + + element_clear(a); + element_clear(b); +} + +// Computes a curve and sets fp to the field it is defined over using the +// complex multiplication method, where cm holds the appropriate information +// (e.g. discriminant, field order). +static void compute_cm_curve(d_param_ptr param, pbc_cm_ptr cm) { + element_t hp, root; + field_t fp, fpx; + field_t cc; + + field_init_fp(fp, cm->q); + field_init_poly(fpx, fp); + element_init(hp, fpx); + + mpz_t *coefflist; + int n = pbc_hilbert(&coefflist, cm->D); + + // Temporarily set the coefficient of x^{n-1} to 1 so hp has degree n - 1, + // allowing us to use poly_coeff(). + poly_set_coeff1(hp, n - 1); + int i; + for (i = 0; i < n; i++) { + element_set_mpz(element_item(hp, i), coefflist[i]); + } + pbc_hilbert_free(coefflist, n); + + // TODO: Remove x = 0, 1728 roots. + // TODO: What if there are no roots? + //printf("hp "); + //element_out_str(stdout, 0, hp); + //printf("\n"); + + element_init(root, fp); + poly_findroot(root, hp); + //printf("root = "); + //element_out_str(stdout, 0, root); + //printf("\n"); + element_clear(hp); + field_clear(fpx); + + // The root is the j-invariant of the desired curve. + field_init_curve_j(cc, root, cm->n, NULL); + element_clear(root); + + // We may need to twist it. + { + // Pick a random point P and twist the curve if it has the wrong order. + element_t P; + element_init(P, cc); + element_random(P); + element_mul_mpz(P, P, cm->n); + if (!element_is0(P)) field_reinit_curve_twist(cc); + element_clear(P); + } + + mpz_set(param->q, cm->q); + mpz_set(param->n, cm->n); + mpz_set(param->h, cm->h); + mpz_set(param->r, cm->r); + element_to_mpz(param->a, curve_field_a_coeff(cc)); + element_to_mpz(param->b, curve_field_b_coeff(cc)); + param->k = cm->k; + { + mpz_t z; + mpz_init(z); + // Compute order of curve in F_q^k. + // n = q - t + 1 hence t = q - n + 1 + mpz_sub(z, param->q, param->n); + mpz_add_ui(z, z, 1); + pbc_mpz_trace_n(z, param->q, z, param->k); + mpz_pow_ui(param->nk, param->q, param->k); + mpz_sub_ui(z, z, 1); + mpz_sub(param->nk, param->nk, z); + mpz_mul(z, param->r, param->r); + mpz_divexact(param->hk, param->nk, z); + mpz_clear(z); + } + field_clear(cc); + field_clear(fp); +} + +static void d_param_init(pbc_param_ptr p) { + static pbc_param_interface_t interface = {{ + d_clear, + d_init_pairing, + d_out_str, + }}; + p->api = interface; + d_param_ptr param = p->data = pbc_malloc(sizeof(*param)); + mpz_init(param->q); + mpz_init(param->n); + mpz_init(param->h); + mpz_init(param->r); + mpz_init(param->a); + mpz_init(param->b); + mpz_init(param->nk); + mpz_init(param->hk); + param->k = 0; + param->coeff = NULL; + mpz_init(param->nqr); +} + +// Public interface: + +int pbc_param_init_d(pbc_param_ptr par, struct symtab_s *tab) { + d_param_init(par); + d_param_ptr p = par->data; + char s[80]; + int i, d; + + int err = 0; + err += lookup_mpz(p->q, tab, "q"); + err += lookup_mpz(p->n, tab, "n"); + err += lookup_mpz(p->h, tab, "h"); + err += lookup_mpz(p->r, tab, "r"); + err += lookup_mpz(p->a, tab, "a"); + err += lookup_mpz(p->b, tab, "b"); + err += lookup_int(&p->k, tab, "k"); + err += lookup_mpz(p->nk, tab, "nk"); + err += lookup_mpz(p->hk, tab, "hk"); + err += lookup_mpz(p->nqr, tab, "nqr"); + + d = p->k / 2; + p->coeff = pbc_realloc(p->coeff, sizeof(mpz_t) * d); + for (i=0; i<d; i++) { + sprintf(s, "coeff%d", i); + mpz_init(p->coeff[i]); + err += lookup_mpz(p->coeff[i], tab, s); + } + return err; +} + +void pbc_param_init_d_gen(pbc_param_ptr p, pbc_cm_ptr cm) { + d_param_init(p); + d_param_ptr param = p->data; + field_t Fq, Fqx, Fqd; + element_t irred, nqr; + int d = cm->k / 2; + int i; + + compute_cm_curve(param, cm); + + field_init_fp(Fq, param->q); + field_init_poly(Fqx, Fq); + element_init(irred, Fqx); + do { + poly_random_monic(irred, d); + } while (!poly_is_irred(irred)); + field_init_polymod(Fqd, irred); + + // Find a quadratic nonresidue of Fqd lying in Fq. + element_init(nqr, Fqd); + do { + element_random(((element_t *) nqr->data)[0]); + } while (element_is_sqr(nqr)); + + param->coeff = pbc_realloc(param->coeff, sizeof(mpz_t) * d); + + for (i=0; i<d; i++) { + mpz_init(param->coeff[i]); + element_to_mpz(param->coeff[i], element_item(irred, i)); + } + element_to_mpz(param->nqr, ((element_t *) nqr->data)[0]); + + element_clear(nqr); + element_clear(irred); + + field_clear(Fqx); + field_clear(Fqd); + field_clear(Fq); +} diff --git a/moon-abe/pbc-0.5.14/ecc/e_param.c b/moon-abe/pbc-0.5.14/ecc/e_param.c new file mode 100644 index 00000000..53f7217c --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/e_param.c @@ -0,0 +1,1006 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> // for intptr_t +#include <stdlib.h> //for rand, pbc_malloc, pbc_free +#include <string.h> //for strcmp +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_fp.h" +#include "pbc_param.h" +#include "pbc_pairing.h" +#include "pbc_curve.h" +#include "pbc_random.h" +#include "pbc_memory.h" +#include "pbc_e_param.h" +#include "ecc/param.h" + +struct e_param_s { + mpz_t q; // Curve is defined over F_q. + mpz_t r; // q = h r^2 + 1, r is prime. + mpz_t h; // h is 28 times some square. + mpz_t a, b; // Curve equation is Y^2 = X^3 + aX + b. + int exp2; + int exp1; + int sign1; + int sign0; +}; +typedef struct e_param_s e_param_t[1]; +typedef struct e_param_s *e_param_ptr; + +struct e_pairing_data_s { + field_t Fq, Eq; + int exp2, exp1; + int sign1, sign0; + element_t R; +}; +typedef struct e_pairing_data_s e_pairing_data_t[1]; +typedef struct e_pairing_data_s *e_pairing_data_ptr; + +static void e_clear(void *data) { + e_param_ptr ep = data; + mpz_clear(ep->q); + mpz_clear(ep->r); + mpz_clear(ep->h); + mpz_clear(ep->a); + mpz_clear(ep->b); + pbc_free(data); +} + +static void e_out_str(FILE *stream, void *data) { + e_param_ptr p = data; + param_out_type(stream, "e"); + param_out_mpz(stream, "q", p->q); + param_out_mpz(stream, "r", p->r); + param_out_mpz(stream, "h", p->h); + param_out_mpz(stream, "a", p->a); + param_out_mpz(stream, "b", p->b); + param_out_int(stream, "exp2", p->exp2); + param_out_int(stream, "exp1", p->exp1); + param_out_int(stream, "sign1", p->sign1); + param_out_int(stream, "sign0", p->sign0); +} + +static void e_miller_proj(element_t res, element_t P, + element_ptr QR, element_ptr R, + e_pairing_data_ptr p) { + //collate divisions + int n; + element_t v, vd; + element_t v1, vd1; + element_t Z, Z1; + element_t a, b, c; + const element_ptr cca = curve_a_coeff(P); + element_t e0, e1; + const element_ptr e2 = a, e3 = b; + element_t z, z2; + int i; + element_ptr Zx, Zy; + const element_ptr Px = curve_x_coord(P); + const element_ptr numx = curve_x_coord(QR); + const element_ptr numy = curve_y_coord(QR); + const element_ptr denomx = curve_x_coord(R); + const element_ptr denomy = curve_y_coord(R); + + //convert Z from weighted projective (Jacobian) to affine + //i.e. (X, Y, Z) --> (X/Z^2, Y/Z^3) + //also sets z to 1 + #define to_affine() { \ + element_invert(z, z); \ + element_square(e0, z); \ + element_mul(Zx, Zx, e0); \ + element_mul(e0, e0, z); \ + element_mul(Zy, Zy, e0); \ + element_set1(z); \ + element_set1(z2); \ + } + + #define proj_double() { \ + const element_ptr x = Zx; \ + const element_ptr y = Zy; \ + /* e0 = 3x^2 + (cc->a) z^4 */ \ + element_square(e0, x); \ + /* element_mul_si(e0, e0, 3); */ \ + element_double(e1, e0); \ + element_add(e0, e0, e1); \ + element_square(e1, z2); \ + element_mul(e1, e1, cca); \ + element_add(e0, e0, e1); \ + \ + /* z_out = 2 y z */ \ + element_mul(z, y, z); \ + /* element_mul_si(z, z, 2); */ \ + element_double(z, z); \ + element_square(z2, z); \ + \ + /* e1 = 4 x y^2 */ \ + element_square(e2, y); \ + element_mul(e1, x, e2); \ + /* element_mul_si(e1, e1, 4); */ \ + element_double(e1, e1); \ + element_double(e1, e1); \ + \ + /* x_out = e0^2 - 2 e1 */ \ + /* element_mul_si(e3, e1, 2); */ \ + element_double(e3, e1); \ + element_square(x, e0); \ + element_sub(x, x, e3); \ + \ + /* e2 = 8y^4 */ \ + element_square(e2, e2); \ + /* element_mul_si(e2, e2, 8); */ \ + element_double(e2, e2); \ + element_double(e2, e2); \ + element_double(e2, e2); \ + \ + /* y_out = e0(e1 - x_out) - e2 */ \ + element_sub(e1, e1, x); \ + element_mul(e0, e0, e1); \ + element_sub(y, e0, e2); \ + } + + #define do_tangent(e, edenom) { \ + /* 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, cca); \ + element_square(b, Zx); \ + /* element_mul_si(b, b, 3); */ \ + element_double(e0, b); \ + element_add(b, b, e0); \ + element_add(a, a, b); \ + element_neg(a, a); \ + \ + /* element_mul_si(e0, Zy, 2); */ \ + element_double(e0, Zy); \ + element_mul(b, e0, z2); \ + element_mul(b, b, z); \ + \ + element_mul(c, Zx, a); \ + element_mul(a, a, z2); \ + element_mul(e0, e0, Zy); \ + 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_vertical(e, edenom, Ax) { \ + element_mul(e0, numx, z2); \ + element_sub(e0, e0, Ax); \ + element_mul(e, e, e0); \ + \ + element_mul(e0, denomx, z2); \ + element_sub(e0, e0, Ax); \ + element_mul(edenom, edenom, e0); \ + } + + #define do_line(e, edenom, A, B) { \ + element_ptr Ax = curve_x_coord(A); \ + element_ptr Ay = curve_y_coord(A); \ + element_ptr Bx = curve_x_coord(B); \ + element_ptr By = curve_y_coord(B); \ + \ + element_sub(b, Bx, Ax); \ + element_sub(a, Ay, By); \ + element_mul(c, Ax, By); \ + element_mul(e0, Ay, Bx); \ + 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(z, res->field); + element_init(z2, res->field); + element_set1(z); + element_set1(z2); + + element_init(v, res->field); + element_init(vd, res->field); + element_init(v1, res->field); + element_init(vd1, res->field); + element_init(Z, P->field); + element_init(Z1, P->field); + + element_set(Z, P); + Zx = curve_x_coord(Z); + Zy = curve_y_coord(Z); + + element_set1(v); + element_set1(vd); + element_set1(v1); + element_set1(vd1); + + n = p->exp1; + for (i=0; i<n; i++) { + element_square(v, v); + element_square(vd, vd); + do_tangent(v, vd); + proj_double(); + do_vertical(vd, v, Zx); + } + to_affine(); + if (p->sign1 < 0) { + element_set(v1, vd); + element_set(vd1, v); + do_vertical(vd1, v1, Zx); + element_neg(Z1, Z); + } else { + element_set(v1, v); + element_set(vd1, vd); + element_set(Z1, Z); + } + n = p->exp2; + for (; i<n; i++) { + element_square(v, v); + element_square(vd, vd); + do_tangent(v, vd); + proj_double(); + do_vertical(vd, v, Zx); + } + to_affine(); + element_mul(v, v, v1); + element_mul(vd, vd, vd1); + do_line(v, vd, Z, Z1); + element_add(Z, Z, Z1); + do_vertical(vd, v, Zx); + + if (p->sign0 > 0) { + do_vertical(v, vd, Px); + } + + element_invert(vd, vd); + element_mul(res, v, vd); + + element_clear(v); + element_clear(vd); + element_clear(v1); + element_clear(vd1); + element_clear(z); + element_clear(z2); + element_clear(Z); + element_clear(Z1); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(e0); + element_clear(e1); + #undef to_affine + #undef proj_double + #undef do_tangent + #undef do_vertical + #undef do_line +} + +static void e_miller_affine(element_t res, element_t P, + element_ptr QR, element_ptr R, + e_pairing_data_ptr p) { + //collate divisions + int n; + element_t v, vd; + element_t v1, vd1; + element_t Z, Z1; + element_t a, b, c; + element_t e0, e1; + const element_ptr Px = curve_x_coord(P); + const element_ptr cca = curve_a_coeff(P); + element_ptr Zx, Zy; + int i; + const element_ptr numx = curve_x_coord(QR); + const element_ptr numy = curve_y_coord(QR); + const element_ptr denomx = curve_x_coord(R); + const element_ptr denomy = curve_y_coord(R); + + #define do_vertical(e, edenom, Ax) { \ + element_sub(e0, numx, Ax); \ + element_mul(e, e, e0); \ + \ + element_sub(e0, denomx, Ax); \ + 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; */ \ + /* Common curves: a2 = 0 (and cc->a is a_4), so */ \ + /* a = -(3 Ax^2 + cc->a) */ \ + /* b = 2 * Ay */ \ + /* c = -(2 Ay^2 + a Ax); */ \ + \ + 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(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, A, B) { \ + element_ptr Ax = curve_x_coord(A); \ + element_ptr Ay = curve_y_coord(A); \ + element_ptr Bx = curve_x_coord(B); \ + element_ptr By = curve_y_coord(B); \ + \ + element_sub(b, Bx, Ax); \ + element_sub(a, Ay, By); \ + element_mul(c, Ax, By); \ + element_mul(e0, Ay, Bx); \ + 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(v1, res->field); + element_init(vd1, res->field); + element_init(Z, P->field); + element_init(Z1, P->field); + + element_set(Z, P); + Zx = curve_x_coord(Z); + Zy = curve_y_coord(Z); + + element_set1(v); + element_set1(vd); + element_set1(v1); + element_set1(vd1); + + n = p->exp1; + for (i=0; i<n; i++) { + element_square(v, v); + element_square(vd, vd); + do_tangent(v, vd); + element_double(Z, Z); + do_vertical(vd, v, Zx); + } + if (p->sign1 < 0) { + element_set(v1, vd); + element_set(vd1, v); + do_vertical(vd1, v1, Zx); + element_neg(Z1, Z); + } else { + element_set(v1, v); + element_set(vd1, vd); + element_set(Z1, Z); + } + n = p->exp2; + for (; i<n; i++) { + element_square(v, v); + element_square(vd, vd); + do_tangent(v, vd); + element_double(Z, Z); + do_vertical(vd, v, Zx); + } + element_mul(v, v, v1); + element_mul(vd, vd, vd1); + do_line(v, vd, Z, Z1); + element_add(Z, Z, Z1); + do_vertical(vd, v, Zx); + + if (p->sign0 > 0) { + do_vertical(v, vd, Px); + } + + element_invert(vd, vd); + element_mul(res, v, vd); + + element_clear(v); + element_clear(vd); + element_clear(v1); + element_clear(vd1); + element_clear(Z); + element_clear(Z1); + element_clear(a); + element_clear(b); + element_clear(c); + element_clear(e0); + element_clear(e1); + #undef do_vertical + #undef do_tangent + #undef do_line +} + +static void (*e_miller_fn)(element_t res, element_t P, + element_ptr QR, element_ptr R, + e_pairing_data_ptr p); + +static void e_pairing(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + e_pairing_data_ptr p = pairing->data; + element_ptr Q = in2; + element_t QR; + element_init(QR, p->Eq); + element_add(QR, Q, p->R); + e_miller_fn(out, in1, QR, p->R, p); + element_pow_mpz(out, out, pairing->phikonr); + element_clear(QR); +} + +// in1, in2 are from E(F_q), out from F_q^2. +// Pairing via elliptic nets (see Stange). +static void e_pairing_ellnet(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + const element_ptr a = curve_a_coeff(in1); + const element_ptr b = curve_b_coeff(in1); + + element_ptr x = curve_x_coord(in1); + element_ptr y = curve_y_coord(in1); + + element_ptr x2 = curve_x_coord(in2); + element_ptr y2 = curve_y_coord(in2); + + //notation: cmi means c_{k-i}, ci means c_{k+i} + element_t cm3, cm2, cm1, c0, c1, c2, c3, c4; + element_t dm1, d0, d1; + element_t A, B, C; + + element_init_same_as(cm3, x); + element_init_same_as(cm2, x); + element_init_same_as(cm1, x); + element_init_same_as(c0, x); + element_init_same_as(c1, x); + element_init_same_as(c2, x); + element_init_same_as(c3, x); + element_init_same_as(c4, x); + element_init_same_as(C, x); + + element_init_same_as(dm1, out); + element_init_same_as(d0, out); + element_init_same_as(d1, out); + element_init_same_as(A, x); + element_init_same_as(B, out); + + // c1 = 2y + // cm3 = -2y + element_double(c1, y); + element_neg(cm3, c1); + + //use c0, cm1, cm2, C, c4 as temp variables for now + //compute c3, c2 + element_square(cm2, x); + element_square(C, cm2); + element_mul(cm1, b, x); + element_double(cm1, cm1); + element_square(c4, a); + + element_mul(c2, cm1, cm2); + element_double(c2, c2); + element_mul(c0, a, C); + element_add(c2, c2, c0); + element_mul(c0, c4, cm2); + element_sub(c2, c2, c0); + element_double(c0, c2); + element_double(c0, c0); + element_add(c2, c2, c0); + + element_mul(c0, cm1, a); + element_square(c3, b); + element_double(c3, c3); + element_double(c3, c3); + element_add(c0, c0, c3); + element_double(c0, c0); + element_mul(c3, a, c4); + element_add(c0, c0, c3); + element_sub(c2, c2, c0); + element_mul(c0, cm2, C); + element_add(c3, c0, c2); + element_mul(c3, c3, c1); + element_double(c3, c3); + + element_mul(c0, a, cm2); + element_add(c0, c0, cm1); + element_double(c0, c0); + element_add(c0, c0, C); + element_double(c2, c0); + element_add(c0, c0, c2); + element_sub(c2, c0, c4); + + // c0 = 1 + // cm2 = -1 + element_set1(c0); + element_neg(cm2, c0); + + // c4 = c_5 = c_2^3 c_4 - c_3^3 = c1^3 c3 - c2^3 + element_square(C, c1); + element_mul(c4, C, c1); + element_mul(c4, c4, c3); + element_square(C, c2); + element_mul(C, C, c2); + element_sub(c4, c4, C); + + //compute A, B, d1 (which is d_2 since k = 1) + element_sub(A, x, x2); + element_double(C, x); + element_add(C, C, x2); + element_square(cm1, A); + element_mul(cm1, C, cm1); + element_add(d1, y, y2); + element_square(d1, d1); + element_sub(B, cm1, d1); + element_invert(B, B); + element_invert(A, A); + + element_sub(d1, y, y2); + element_mul(d1, d1, A); + element_square(d1, d1); + element_sub(d1, C, d1); + + // cm1 = 0 + // C = (2y)^-1 + element_set0(cm1); + element_invert(C, c1); + + element_set1(dm1); + element_set1(d0); + + element_t sm2, sm1; + element_t s0, s1, s2, s3; + element_t tm2, tm1; + element_t t0, t1, t2, t3; + element_t e0, e1; + element_t u, v; + + element_init_same_as(sm2, x); + element_init_same_as(sm1, x); + element_init_same_as(s0, x); + element_init_same_as(s1, x); + element_init_same_as(s2, x); + element_init_same_as(s3, x); + + element_init_same_as(tm2, x); + element_init_same_as(tm1, x); + element_init_same_as(t0, x); + element_init_same_as(t1, x); + element_init_same_as(t2, x); + element_init_same_as(t3, x); + + element_init_same_as(e0, x); + element_init_same_as(e1, x); + + element_init_same_as(u, d0); + element_init_same_as(v, d0); + + int m = mpz_sizeinbase(pairing->r, 2) - 2; + for (;;) { + element_square(sm2, cm2); + element_square(sm1, cm1); + element_square(s0, c0); + element_square(s1, c1); + element_square(s2, c2); + element_square(s3, c3); + + element_mul(tm2, cm3, cm1); + element_mul(tm1, cm2, c0); + element_mul(t0, cm1, c1); + element_mul(t1, c0, c2); + element_mul(t2, c1, c3); + element_mul(t3, c2, c4); + + element_square(u, d0); + element_mul(v, dm1, d1); + + if (mpz_tstbit(pairing->r, m)) { + //double-and-add + element_mul(e0, t0, sm2); + element_mul(e1, tm2, s0); + element_sub(cm3, e0, e1); + element_mul(cm3, cm3, C); + + element_mul(e0, t0, sm1); + element_mul(e1, tm1, s0); + element_sub(cm2, e0, e1); + + element_mul(e0, t1, sm1); + element_mul(e1, tm1, s1); + element_sub(cm1, e0, e1); + element_mul(cm1, cm1, C); + + element_mul(e0, t1, s0); + element_mul(e1, t0, s1); + element_sub(c0, e0, e1); + + element_mul(e0, t2, s0); + element_mul(e1, t0, s2); + element_sub(c1, e0, e1); + element_mul(c1, c1, C); + + element_mul(e0, t2, s1); + element_mul(e1, t1, s2); + element_sub(c2, e0, e1); + + element_mul(e0, t3, s1); + element_mul(e1, t1, s3); + element_sub(c3, e0, e1); + element_mul(c3, c3, C); + + element_mul(e0, t3, s2); + element_mul(e1, t2, s3); + element_sub(c4, e0, e1); + + element_mul(out, u, t0); + element_mul(dm1, v, s0); + element_sub(dm1, dm1, out); + + element_mul(out, u, t1); + element_mul(d0, v, s1); + element_sub(d0, d0, out); + element_mul(d0, d0, A); + + element_mul(out, u, t2); + element_mul(d1, v, s2); + element_sub(d1, d1, out); + element_mul(d1, d1, B); + } else { + //double + element_mul(e0, tm1, sm2); + element_mul(e1, tm2, sm1); + element_sub(cm3, e0, e1); + + element_mul(e0, t0, sm2); + element_mul(e1, tm2, s0); + element_sub(cm2, e0, e1); + element_mul(cm2, cm2, C); + + element_mul(e0, t0, sm1); + element_mul(e1, tm1, s0); + element_sub(cm1, e0, e1); + + element_mul(e0, t1, sm1); + element_mul(e1, tm1, s1); + element_sub(c0, e0, e1); + element_mul(c0, c0, C); + + element_mul(e0, t1, s0); + element_mul(e1, t0, s1); + element_sub(c1, e0, e1); + + element_mul(e0, t2, s0); + element_mul(e1, t0, s2); + element_sub(c2, e0, e1); + element_mul(c2, c2, C); + + element_mul(e0, t2, s1); + element_mul(e1, t1, s2); + element_sub(c3, e0, e1); + + element_mul(e0, t3, s1); + element_mul(e1, t1, s3); + element_sub(c4, e0, e1); + element_mul(c4, c4, C); + + element_mul(out, u, tm1); + element_mul(dm1, v, sm1); + element_sub(dm1, dm1, out); + + element_mul(out, u, t0); + element_mul(d0, v, s0); + element_sub(d0, d0, out); + + element_mul(out, u, t1); + element_mul(d1, v, s1); + element_sub(d1, d1, out); + element_mul(d1, d1, A); + } + if (!m) break; + m--; + } + element_invert(c1, c1); + element_mul(d1, d1, c1); + + element_pow_mpz(out, d1, pairing->phikonr); + + element_clear(dm1); + element_clear(d0); + element_clear(d1); + + element_clear(cm3); + element_clear(cm2); + element_clear(cm1); + element_clear(c0); + element_clear(c1); + element_clear(c2); + element_clear(c3); + element_clear(c4); + + element_clear(sm2); + element_clear(sm1); + element_clear(s0); + element_clear(s1); + element_clear(s2); + element_clear(s3); + + element_clear(tm2); + element_clear(tm1); + element_clear(t0); + element_clear(t1); + element_clear(t2); + element_clear(t3); + + element_clear(e0); + element_clear(e1); + element_clear(A); + element_clear(B); + element_clear(C); + element_clear(u); + element_clear(v); +} + +static void phi_identity(element_ptr out, element_ptr in, pairing_ptr pairing) { + (void) pairing; + element_set(out, in); +} + +static void e_pairing_option_set(pairing_t pairing, char *key, char *value) { + //TODO: this affects every type E pairing! + UNUSED_VAR(pairing); + if (!strcmp(key, "method")) { + if (!strcmp(value, "miller")) { + pairing->map = e_pairing; + e_miller_fn = e_miller_proj; + } else if (!strcmp(value, "miller-affine")) { + pairing->map = e_pairing; + e_miller_fn = e_miller_affine; + } else if (!strcmp(value, "shipsey-stange")) { + pairing->map = e_pairing_ellnet; + } + } +} + +static void e_pairing_clear(pairing_t pairing) { + field_clear(pairing->GT); + e_pairing_data_ptr p = pairing->data; + field_clear(p->Fq); + field_clear(p->Eq); + element_clear(p->R); + pbc_free(p); + + mpz_clear(pairing->phikonr); + mpz_clear(pairing->r); + field_clear(pairing->Zr); +} + +static void e_finalpow(element_ptr e) { + element_pow_mpz(e->data, e->data, e->field->pairing->phikonr); +} + +static void e_init_pairing(pairing_t pairing, void *data) { + e_param_ptr param = data; + e_pairing_data_ptr p; + element_t a, b; + + mpz_init(pairing->r); + mpz_set(pairing->r, param->r); + field_init_fp(pairing->Zr, pairing->r); + pairing->map = e_pairing; + e_miller_fn = e_miller_proj; + + p = pairing->data = pbc_malloc(sizeof(e_pairing_data_t)); + p->exp2 = param->exp2; + p->exp1 = param->exp1; + p->sign1 = param->sign1; + p->sign0 = param->sign0; + field_init_fp(p->Fq, param->q); + element_init(a, p->Fq); + element_init(b, p->Fq); + element_set_mpz(a, param->a); + element_set_mpz(b, param->b); + field_init_curve_ab(p->Eq, a, b, pairing->r, param->h); + + //k=1, hence phikonr = (p-1)/r + mpz_init(pairing->phikonr); + mpz_sub_ui(pairing->phikonr, p->Fq->order, 1); + mpz_divexact(pairing->phikonr, pairing->phikonr, pairing->r); + + pairing->G2 = pairing->G1 = p->Eq; + pairing_GT_init(pairing, p->Fq); + pairing->finalpow = e_finalpow; + pairing->phi = phi_identity; + pairing->option_set = e_pairing_option_set; + pairing->clear_func = e_pairing_clear; + + element_init(p->R, p->Eq); + curve_set_gen_no_cofac(p->R); + + element_clear(a); + element_clear(b); +} + +static void e_init(pbc_param_ptr p) { + static pbc_param_interface_t interface = {{ + e_clear, + e_init_pairing, + e_out_str, + }}; + p->api = interface; + e_param_ptr ep = p->data = pbc_malloc(sizeof(*ep)); + mpz_init(ep->q); + mpz_init(ep->r); + mpz_init(ep->h); + mpz_init(ep->a); + mpz_init(ep->b); +} + +// Public interface: + +int pbc_param_init_e(pbc_param_ptr par, struct symtab_s *tab) { + e_init(par); + e_param_ptr p = par->data; + + int err = 0; + err += lookup_mpz(p->q, tab, "q"); + err += lookup_mpz(p->r, tab, "r"); + err += lookup_mpz(p->h, tab, "h"); + err += lookup_mpz(p->a, tab, "a"); + err += lookup_mpz(p->b, tab, "b"); + err += lookup_int(&p->exp2, tab, "exp2"); + err += lookup_int(&p->exp1, tab, "exp1"); + err += lookup_int(&p->sign1, tab, "sign1"); + err += lookup_int(&p->sign0, tab, "sign0"); + return err; +} + +void pbc_param_init_e_gen(pbc_param_t par, int rbits, int qbits) { + e_init(par); + e_param_ptr p = par->data; + //3 takes 2 bits to represent + int hbits = (qbits - 2) / 2 - rbits; + mpz_ptr q = p->q; + mpz_ptr r = p->r; + mpz_ptr h = p->h; + mpz_t n; + field_t Fq; + field_t cc; + element_t j; + int found = 0; + + //won't find any curves is hbits is too low + if (hbits < 3) hbits = 3; + + mpz_init(n); + + do { + int i; + mpz_set_ui(r, 0); + + if (rand() % 2) { + p->exp2 = rbits - 1; + p->sign1 = 1; + } else { + p->exp2 = rbits; + p->sign1 = -1; + } + mpz_setbit(r, p->exp2); + + p->exp1 = (rand() % (p->exp2 - 1)) + 1; + //use q as a temp variable + mpz_set_ui(q, 0); + mpz_setbit(q, p->exp1); + + if (p->sign1 > 0) { + mpz_add(r, r, q); + } else { + mpz_sub(r, r, q); + } + + if (rand() % 2) { + p->sign0 = 1; + mpz_add_ui(r, r, 1); + } else { + p->sign0 = -1; + mpz_sub_ui(r, r, 1); + } + if (!mpz_probab_prime_p(r, 10)) continue; + for (i=0; i<10; i++) { + //use q as a temp variable + mpz_set_ui(q, 0); + mpz_setbit(q, hbits + 1); + pbc_mpz_random(h, q); + mpz_mul(h, h, h); + mpz_mul_ui(h, h, 3); + //finally q takes the value it should + mpz_mul(n, r, r); + mpz_mul(n, n, h); + mpz_add_ui(q, n, 1); + if (mpz_probab_prime_p(q, 10)) { + found = 1; + break; + } + } + } while (!found); + /* + do { + mpz_set_ui(r, 0); + mpz_setbit(r, rbits); + pbc_mpz_random(r, r); + mpz_nextprime(r, r); + mpz_mul(n, r, r); + mpz_mul_ui(n, n, 3); + mpz_add_ui(q, n, 1); + } while (!mpz_probab_prime_p(q, 10)); + */ + + field_init_fp(Fq, q); + element_init(j, Fq); + element_set_si(j, 1); + field_init_curve_b(cc, j, n, NULL); + element_clear(j); + // We may need to twist it. + { + // Pick a random point P and twist the curve if P has the wrong order. + element_t P; + element_init(P, cc); + element_random(P); + element_mul_mpz(P, P, n); + if (!element_is0(P)) field_reinit_curve_twist(cc); + element_clear(P); + } + element_to_mpz(p->a, curve_field_a_coeff(cc)); + element_to_mpz(p->b, curve_field_b_coeff(cc)); + + mpz_clear(n); +} diff --git a/moon-abe/pbc-0.5.14/ecc/eta_T_3.c b/moon-abe/pbc-0.5.14/ecc/eta_T_3.c new file mode 100644 index 00000000..44396b76 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/eta_T_3.c @@ -0,0 +1,835 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_fp.h" +#include "pbc_memory.h" +#include "pbc_param.h" +#include "pbc_pairing.h" +#include "pbc_ternary_extension_field.h" +#include "param.h" + +typedef struct { /* private data of $GF(3^m)$ */ + unsigned int len; /* the number of native machine integers required to represent one GF(3^m) element */ + int m; /* the irreducible polynomial is $x^m + x^t + 2$ */ + int t; /* the irreducible polynomial is $x^m + x^t + 2$ */ + element_ptr p; /* $p$ is the irreducible polynomial. */ + mpz_t n; /* group order of $G_1$, $G_2$, $G_T$ */ + mpz_t n2; /* order(elliptic curve points) / order(G_1) */ +} params; + +struct pairing_data { + field_t gf3m, gf32m, gf36m; + mpz_t n2; // cofactor +}; +typedef struct pairing_data *pairing_data_ptr; + +#define PARAM(e) ((params *)e->field->data) +#define ITEM(e,x,y) (element_item(element_item(e,x),y)) +#define print(e) {printf(#e": "); element_out_str(stdout, 10, e); printf("\n");} + +struct point_s { // points on the elliptic curve $y^2=x^3-x+1$ + int isinf; + element_t x, y; +}; +typedef struct point_s *point_ptr; +typedef struct point_s point_t[1]; + +#define FIELD(e) ((field_ptr) e->field) +#define BASE(e) ((field_ptr) FIELD(e)->data) +#define DATA(e) ((point_ptr) e->data) + +static void point_set(element_t e, element_t a) { + point_ptr r = DATA(e), p = DATA(a); + r->isinf = p->isinf; + if (!p->isinf) { + element_set(r->x, p->x); + element_set(r->y, p->y); + } +} + +static void point_init(element_t e) { + field_ptr f = BASE(e); + e->data = pbc_malloc(sizeof(struct point_s)); + point_ptr p = DATA(e); + element_init(p->x, f); + element_init(p->y, f); + p->isinf = 1; +} + +static void point_clear(element_t e) { + point_ptr p = DATA(e); + element_clear(p->x); + element_clear(p->y); + pbc_free(p); +} + +/* return 1 if $a!=b$, 0 otherwise. */ +static int point_cmp(element_t a, element_t b) { + point_ptr pa = DATA(a), pb = DATA(b); + if (pa->isinf == pb->isinf) { + if (pa->isinf) + return 0; + else + return element_cmp(pa->x, pb->x) || element_cmp(pa->y, pb->y); + } else + return 1; +} + +static void point_set0(element_ptr e) { + DATA(e)->isinf = 1; +} + +static int point_is0(element_ptr e) { + return DATA(e)->isinf; +} + +static void point_random(element_t a) { + point_ptr p = DATA(a); + element_ptr x = p->x, y = p->y; + field_ptr f = x->field; + p->isinf = 0; + element_t t, t2, e1; + element_init(t, f); + element_init(e1, f); + element_set1(e1); + element_init(t2, f); + do { + element_random(x); + if (element_is0(x)) + continue; + element_cubic(t, x); // t == x^3 + element_sub(t, t, x); // t == x^3 - x + element_add(t, t, e1); // t == x^3 - x + 1 + element_sqrt(y, t); // y == sqrt(x^3 - x + 1) + element_mul(t2, y, y); // t2 == x^3 - x + 1 + } while (element_cmp(t2, t)); // t2 != t + + // make sure order of $a$ is order of $G_1$ + pairing_ptr pairing = FIELD(a)->pairing; + pairing_data_ptr dp = pairing->data; + element_pow_mpz(a, a, dp->n2); + + element_clear(t); + element_clear(t2); + element_clear(e1); +} + +static void point_add(element_t c, element_t a, element_t b) { + point_ptr p1 = DATA(a), p2 = DATA(b), p3 = DATA(c); + int inf1 = p1->isinf, inf2 = p2->isinf; + element_ptr x1 = p1->x, y1 = p1->y, x2 = p2->x, y2 = p2->y; + field_ptr f = FIELD(x1); + if (inf1) { + point_set(c, b); + return; + } + if (inf2) { + point_set(c, a); + return; + } + element_t v0, v1, v2, v3, v4, ny2; + element_init(v0, f); + element_init(v1, f); + element_init(v2, f); + element_init(v3, f); + element_init(v4, f); + element_init(ny2, f); + if (!element_cmp(x1, x2)) { // x1 == x2 + element_neg(ny2, y2); // ny2 == -y2 + if (!element_cmp(y1, ny2)) { + p3->isinf = 1; + goto end; + } + if (!element_cmp(y1, y2)) { // y1 == y2 + element_invert(v0, y1); // v0 == y1^{-1} + element_mul(v1, v0, v0); // v1 == [y1^{-1}]^2 + element_add(p3->x, v1, x1); // v1 == [y1^{-1}]^2 + x1 + element_cubic(v2, v0); // v2 == [y1^{-1}]^3 + element_add(v2, v2, y1); // v2 == [y1^{-1}]^3 + y1 + element_neg(p3->y, v2); // p3 == -([y1^{-1}]^3 + y1) + p3->isinf = 0; + goto end; + } + } + // $P1 \ne \pm P2$ + element_sub(v0, x2, x1); // v0 == x2-x1 + element_invert(v1, v0); // v1 == (x2-x1)^{-1} + element_sub(v0, y2, y1); // v0 == y2-y1 + element_mul(v2, v0, v1); // v2 == (y2-y1)/(x2-x1) + element_mul(v3, v2, v2); // v3 == [(y2-y1)/(x2-x1)]^2 + element_cubic(v4, v2); // v4 == [(y2-y1)/(x2-x1)]^3 + element_add(v0, x1, x2); // v0 == x1+x2 + element_sub(v3, v3, v0); // v3 == [(y2-y1)/(x2-x1)]^2 - (x1+x2) + element_add(v0, y1, y2); // v0 == y1+y2 + element_sub(v4, v0, v4); // v4 == (y1+y2) - [(y2-y1)/(x2-x1)]^3 + p3->isinf = 0; + element_set(p3->x, v3); + element_set(p3->y, v4); + end: element_clear(v0); + element_clear(v1); + element_clear(v2); + element_clear(v3); + element_clear(v4); + element_clear(ny2); +} + +static void point_invert(element_ptr e, element_ptr a) { + point_ptr r = DATA(e), p = DATA(a); + r->isinf = p->isinf; + if (!p->isinf) { + element_set(r->x, p->x); + element_neg(r->y, p->y); + } +} + +static size_t point_out_str(FILE *stream, int base, element_ptr a) { + point_ptr p = DATA(a); + size_t size = 0; + if (p->isinf) + return fprintf(stream, "O"); + else { + size += element_out_str(stream, base, p->x); + size += element_out_str(stream, base, p->y); + return size; + } +} + +static void point_field_clear(field_ptr f) { + UNUSED_VAR(f); +} + +void field_init_eta_T_3(field_t f, field_t base) { + field_init(f); + f->data = (void *) base; + f->init = point_init; + f->clear = point_clear; + f->random = point_random; + f->set = point_set; + f->cmp = point_cmp; + f->invert = f->neg = point_invert; + f->mul = f->add = point_add; + f->set1 = f->set0 = point_set0; + f->is1 = f->is0 = point_is0; + f->mul_mpz = f->pow_mpz; + f->out_str = point_out_str; + f->field_clear = point_field_clear; + f->name = "eta_T_3 point group"; +} + +/* computing of $(-t^2 +u*s -t*p -p^2)^3$ + * The algorithm is by J.Beuchat et.al, in the paper of "Algorithms and Arithmetic Operators for Computing + * the $eta_T$ Pairing in Characteristic Three", algorithm 4 in the appendix */ +static void algorithm4a(element_t S, element_t t, element_t u) { + field_ptr f = FIELD(t); + element_t e1, c0, c1, m0, v0, v2; + element_init(e1, f); + element_init(c0, f); + element_init(c1, f); + element_init(m0, f); + element_init(v0, f); + element_init(v2, f); + element_set1(e1); + element_cubic(c0, t); // c0 == t^3 + element_cubic(c1, u); + element_neg(c1, c1); // c1 == -u^3 + element_mul(m0, c0, c0); // m0 == c0^2 + element_neg(v0, m0); // v0 == -c0^2 + element_sub(v0, v0, c0); // v0 == -c0^2 -c0 + element_sub(v0, v0, e1); // v0 == -c0^2 -c0 -1 + element_set1(v2); + element_sub(v2, v2, c0); // v2 == 1 -c0 + // v1 == c1 + // S == [[v0, v1], [v2, f3m.zero()], [f3m.two(), f3m.zero()]] + element_set(ITEM(S,0,0), v0); + element_set(ITEM(S,0,1), c1); + element_set(ITEM(S,1,0), v2); + element_set0(ITEM(S,1,1)); + element_neg(ITEM(S,2,0), e1); + element_set0(ITEM(S,2,1)); + element_clear(e1); + element_clear(c0); + element_clear(c1); + element_clear(m0); + element_clear(v0); + element_clear(v2); +} + +static void algorithm5(element_t c, element_ptr xp, element_ptr yp, + element_ptr xq, element_ptr yq) { + params *p = PARAM(xp); + unsigned int re = p->m % 12; + field_ptr f = FIELD(xp) /*GF(3^m)*/, f6 = FIELD(c) /*GF(3^{6*m})*/; + element_t e1, xpp, ypp, xqq, yqq, t, nt, nt2, v1, v2, a1, a2, R, u, nu, S, S2; + element_init(e1, f); + element_init(xpp, f); + element_init(ypp, f); + element_init(xqq, f); + element_init(yqq, f); + element_init(t, f); + element_init(nt, f); + element_init(nt2, f); + element_init(v1, f); + element_init(v2, f); + element_init(a1, f6); + element_init(a2, f6); + element_init(R, f6); + element_init(u, f); + element_init(nu, f); + element_init(S, f6); + element_init(S2, f6); + element_set1(e1); + element_set(xpp, xp); + xp = xpp; // clone + element_add(xp, xp, e1); // xp == xp + b + element_set(ypp, yp); + yp = ypp; // clone + if (re == 1 || re == 11) + element_neg(yp, yp); // yp == -\mu*b*yp, \mu == 1 when re==1, or 11 + element_set(xqq, xq); + xq = xqq; // clone + element_cubic(xq, xq); // xq == xq^3 + element_set(yqq, yq); + yq = yqq; // clone + element_cubic(yq, yq); // yq == yq^3 + element_add(t, xp, xq); // t == xp+xq + element_neg(nt, t); // nt == -t + element_mul(nt2, t, nt); // nt2 == -t^2 + element_mul(v2, yp, yq); // v2 == yp*yq + element_mul(v1, yp, t); // v1 == yp*t + if (re == 7 || re == 11) { // \lambda == 1 + element_t nyp, nyq; + element_init(nyp, f); + element_init(nyq, f); + element_neg(nyp, yp); // nyp == -yp + element_neg(nyq, yq); // nyq == -yq + element_set(ITEM(a1,0,0), v1); + element_set(ITEM(a1,0,1), nyq); + element_set(ITEM(a1,1,0), nyp); + element_clear(nyp); + element_clear(nyq); + } else { // \lambda == -1 + element_neg(v1, v1); // v1 == -yp*t + element_set(ITEM(a1,0,0), v1); + element_set(ITEM(a1,0,1), yq); + element_set(ITEM(a1,1,0), yp); + } + // a2 == -t^2 +yp*yq*s -t*p -p^2 + element_set(ITEM(a2,0,0), nt2); + element_set(ITEM(a2,0,1), v2); + element_set(ITEM(a2,1,0), nt); + element_neg(ITEM(a2,2,0), e1); + element_mul(R, a1, a2); + int i; + for (i = 0; i < (p->m - 1) / 4; i++) { + element_cubic(R, R); + element_cubic(R, R); // R <= R^9 + element_cubic(xq, xq); + element_cubic(xq, xq); + element_sub(xq, xq, e1); // xq <= xq^9-b + element_cubic(yq, yq); + element_cubic(yq, yq); // yq <= yq^9 + element_add(t, xp, xq); // t == xp+xq + element_mul(u, yp, yq); // u == yp*yq + element_neg(nu, u); // nu == -yp*yq + algorithm4a(S, t, nu); // S == (-t^2 -u*s -t*p -p^2)^3 + element_cubic(xq, xq); + element_cubic(xq, xq); + element_sub(xq, xq, e1); // xq <= xq^9-b + element_cubic(yq, yq); + element_cubic(yq, yq); // yq <= yq^9 + element_add(t, xp, xq); // t == xp+xq + element_mul(u, yp, yq); // u == yp*yq + element_neg(nt, t); // nt == -t + element_mul(nt2, t, nt); // nt2 == -t^2 + // S2 = [[nt2, u], [nt, f3m.zero()], [f3m.two(), f3m.zero()]] + // S2 == -t^2 +u*s -t*p -p^2 + element_set(ITEM(S2,0,0), nt2); + element_set(ITEM(S2,0,1), u); + element_set(ITEM(S2,1,0), nt); + element_set0(ITEM(S2,1,1)); + element_neg(ITEM(S2,2,0), e1); + element_set0(ITEM(S2,2,1)); + element_mul(S, S, S2); + element_mul(R, R, S); + } + element_set(c, R); + element_clear(e1); + element_clear(xpp); + element_clear(ypp); + element_clear(xqq); + element_clear(yqq); + element_clear(t); + element_clear(nt); + element_clear(nt2); + element_clear(v1); + element_clear(v2); + element_clear(a1); + element_clear(a2); + element_clear(R); + element_clear(u); + element_clear(nu); + element_clear(S); + element_clear(S2); +} + +/* this is the algorithm 4 in the paper of J.Beuchat et.al, "Algorithms and Arithmetic Operators for Computing + * the $eta_T$ Pairing in Characteristic Three" */ +static void algorithm4(element_t c, element_ptr xp, element_ptr yp, + element_ptr xq, element_ptr yq) { + params *p = PARAM(xp); + unsigned int re = p->m % 12; + field_ptr f = FIELD(xp) /*GF(3^m)*/, f6 = FIELD(c) /*GF(3^{6*m})*/; + element_t e1, xpp, ypp, xqq, yqq, t, nt, nt2, v1, v2, a1, a2, R, u, S; + element_init(e1, f); + element_init(xpp, f); + element_init(ypp, f); + element_init(xqq, f); + element_init(yqq, f); + element_init(t, f); + element_init(nt, f); + element_init(nt2, f); + element_init(v1, f); + element_init(v2, f); + element_init(a1, f6); + element_init(a2, f6); + element_init(R, f6); + element_init(u, f); + element_init(S, f6); + element_set1(e1); + element_set(xpp, xp); + xp = xpp; // clone + element_add(xp, xp, e1); // xp == xp + b + element_set(ypp, yp); + yp = ypp; // clone + if (re == 1 || re == 11) + element_neg(yp, yp); // yp == -\mu*b*yp, \mu == 1 when re==1, or 11 + element_set(xqq, xq); + xq = xqq; // clone + element_cubic(xq, xq); // xq == xq^3 + element_set(yqq, yq); + yq = yqq; // clone + element_cubic(yq, yq); // yq == yq^3 + element_add(t, xp, xq); // t == xp+xq + element_neg(nt, t); // nt == -t + element_mul(nt2, t, nt); // nt2 == -t^2 + element_mul(v2, yp, yq); // v2 == yp*yq + element_mul(v1, yp, t); // v1 == yp*t + if (re == 7 || re == 11) { // \lambda == 1 + element_t nyp, nyq; + element_init(nyp, f); + element_init(nyq, f); + element_neg(nyp, yp); // nyp == -yp + element_neg(nyq, yq); // nyq == -yq + element_set(ITEM(a1,0,0), v1); + element_set(ITEM(a1,0,1), nyq); + element_set(ITEM(a1,1,0), nyp); + element_clear(nyp); + element_clear(nyq); + } else { // \lambda == -1 + element_neg(v1, v1); // v1 == -yp*t + element_set(ITEM(a1,0,0), v1); + element_set(ITEM(a1,0,1), yq); + element_set(ITEM(a1,1,0), yp); + } + // a2 == -t^2 +yp*yq*s -t*p -p^2 + element_set(ITEM(a2,0,0), nt2); + element_set(ITEM(a2,0,1), v2); + element_set(ITEM(a2,1,0), nt); + element_neg(ITEM(a2,2,0), e1); + element_mul(R, a1, a2); + int i; + for (i = 0; i < (p->m - 1) / 2; i++) { + element_cubic(R, R); + element_cubic(xq, xq); + element_cubic(xq, xq); + element_sub(xq, xq, e1); // xq <= xq^9-b + element_cubic(yq, yq); + element_cubic(yq, yq); + element_neg(yq, yq); // yq <= -yq^9 + element_add(t, xp, xq); // t == xp+xq + element_neg(nt, t); // nt == -t + element_mul(nt2, t, nt); // nt2 == -t^2 + element_mul(u, yp, yq); // u == yp*yq + element_set0(S); + element_set(ITEM(S,0,0), nt2); + element_set(ITEM(S,0,1), u); + element_set(ITEM(S,1,0), nt); + element_neg(ITEM(S,2,0), e1); + element_mul(R, R, S); + } + element_set(c, R); + element_clear(e1); + element_clear(xpp); + element_clear(ypp); + element_clear(xqq); + element_clear(yqq); + element_clear(t); + element_clear(nt); + element_clear(nt2); + element_clear(v1); + element_clear(v2); + element_clear(a1); + element_clear(a2); + element_clear(R); + element_clear(u); + element_clear(S); +} + +/* computation of $c <- U ^ {3^{3m} - 1}$ + * This is the algorithm 6 in the paper above. */ +static void algorithm6(element_t c, element_t u) { + element_ptr u0 = ITEM(u,0,0), u1 = ITEM(u,0,1), u2 = ITEM(u,1,0), u3 = + ITEM(u,1,1), u4 = ITEM(u,2,0), u5 = ITEM(u,2,1); + field_ptr f = FIELD(u0); /*GF(3^m)*/ + field_t f3; /*GF(3^{3*m})*/ + field_init_gf33m(f3, f); + element_t v0, v1, m0, m1, m2, a0, a1, i; + element_init(v0, f3); + element_init(v1, f3); + element_init(m0, f3); + element_init(m1, f3); + element_init(m2, f3); + element_init(a0, f3); + element_init(a1, f3); + element_init(i, f3); + element_set(element_item(v0, 0), u0); + element_set(element_item(v0, 1), u2); + element_set(element_item(v0, 2), u4); + element_set(element_item(v1, 0), u1); + element_set(element_item(v1, 1), u3); + element_set(element_item(v1, 2), u5); + element_mul(m0, v0, v0); + element_mul(m1, v1, v1); + element_mul(m2, v0, v1); + element_sub(a0, m0, m1); + element_add(a1, m0, m1); + element_invert(i, a1); + element_mul(v0, a0, i); + element_mul(v1, m2, i); + element_set(ITEM(c,0,0), element_item(v0, 0)); + element_set(ITEM(c,1,0), element_item(v0, 1)); + element_set(ITEM(c,2,0), element_item(v0, 2)); + element_set(ITEM(c,0,1), element_item(v1, 0)); + element_set(ITEM(c,1,1), element_item(v1, 1)); + element_set(ITEM(c,2,1), element_item(v1, 2)); + element_clear(v0); + element_clear(v1); + element_clear(m0); + element_clear(m1); + element_clear(m2); + element_clear(a0); + element_clear(a1); + element_clear(i); + field_clear(f3); +} + +/* computation of $c <- U ^ {3^m+1}$, $U \in T_2(F_{3^3M})$ + * This is the algorithm 7 in the paper above. */ +static void algorithm7(element_t c, element_t u) { + element_ptr u0 = ITEM(u,0,0), u1 = ITEM(u,0,1), u2 = ITEM(u,1,0), u3 = + ITEM(u,1,1), u4 = ITEM(u,2,0), u5 = ITEM(u,2,1); + field_ptr f = FIELD(u0); /*GF(3^m)*/ + params *p = PARAM(u0); + element_t a0, a1, a2, a3, a4, a5, a6, m0, m1, m2, m3, m4, m5, m6, m7, m8, + v0, v1, v2, v3, v4, v5, e1; + element_init(a0, f); + element_init(a1, f); + element_init(a2, f); + element_init(a3, f); + element_init(a4, f); + element_init(a5, f); + element_init(a6, f); + element_init(m0, f); + element_init(m1, f); + element_init(m2, f); + element_init(m3, f); + element_init(m4, f); + element_init(m5, f); + element_init(m6, f); + element_init(m7, f); + element_init(m8, f); + element_init(v0, f); + element_init(v1, f); + element_init(v2, f); + element_init(v3, f); + element_init(v4, f); + element_init(v5, f); + element_init(e1, f); + element_set1(e1); + element_add(a0, u0, u1); + element_add(a1, u2, u3); + element_sub(a2, u4, u5); + element_mul(m0, u0, u4); + element_mul(m1, u1, u5); + element_mul(m2, u2, u4); + element_mul(m3, u3, u5); + element_mul(m4, a0, a2); + element_mul(m5, u1, u2); + element_mul(m6, u0, u3); + element_mul(m7, a0, a1); + element_mul(m8, a1, a2); + element_add(a3, m5, m6); + element_sub(a3, a3, m7); + element_neg(a4, m2); + element_sub(a4, a4, m3); + element_sub(a5, m3, m2); + element_sub(a6, m1, m0); + element_add(a6, a6, m4); + if (p->m % 6 == 1) { + element_add(v0, m0, m1); + element_add(v0, v0, a4); + element_add(v0, e1, v0); + element_sub(v1, m5, m6); + element_add(v1, v1, a6); + element_sub(v2, a4, a3); + element_add(v3, m8, a5); + element_sub(v3, v3, a6); + element_add(v4, a3, a4); + element_neg(v4, v4); + element_add(v5, m8, a5); + } else { // p->m % 6 == 5 + element_add(v0, m0, m1); + element_sub(v0, v0, a4); + element_add(v0, e1, v0); + element_sub(v1, m6, m5); + element_add(v1, v1, a6); + element_set(v2, a3); + element_add(v3, m8, a5); + element_add(v3, v3, a6); + element_add(v4, a3, a4); + element_neg(v4, v4); + element_add(v5, m8, a5); + element_neg(v5, v5); + } + element_set(ITEM(c,0,0), v0); + element_set(ITEM(c,0,1), v1); + element_set(ITEM(c,1,0), v2); + element_set(ITEM(c,1,1), v3); + element_set(ITEM(c,2,0), v4); + element_set(ITEM(c,2,1), v5); + element_clear(a0); + element_clear(a1); + element_clear(a2); + element_clear(a3); + element_clear(a4); + element_clear(a5); + element_clear(a6); + element_clear(m0); + element_clear(m1); + element_clear(m2); + element_clear(m3); + element_clear(m4); + element_clear(m5); + element_clear(m6); + element_clear(m7); + element_clear(m8); + element_clear(v0); + element_clear(v1); + element_clear(v2); + element_clear(v3); + element_clear(v4); + element_clear(v5); + element_clear(e1); +} + +/* computing $c <- U^M, M=(3^{3m}-1)*(3^m+1)*(3^m+1-\mu*b*3^{(m+1)//2})$ + * This is the algorithm 8 in the paper above. */ +static void algorithm8(element_t c, element_t u) { + field_ptr f6 = FIELD(u), f = FIELD(ITEM(u,0,0)); + params *p = (params *) f->data; + element_t v, w; + element_init(v, f6); + element_init(w, f6); + algorithm6(v, u); + algorithm7(v, v); + element_set(w, v); + int i; + for (i = 0; i < (p->m + 1) / 2; i++) + element_cubic(w, w); + algorithm7(v, v); + if (p->m % 12 == 1 || p->m % 12 == 11) { // w <= w^{-\mu*b} + element_ptr e; + e = ITEM(w,0,1); + element_neg(e, e); + e = ITEM(w,1,1); + element_neg(e, e); + e = ITEM(w,2,1); + element_neg(e, e); + } + element_mul(c, v, w); + element_clear(v); + element_clear(w); +} + +/* computing the Eta_T bilinear pairing $c <- Eta_T pairing(P,R)$ */ +static void eta_T_pairing(element_ptr c, element_ptr P, element_ptr R, struct pairing_s *p) { + UNUSED_VAR(p); + if (DATA(P)->isinf || DATA(R)->isinf) + element_set1(c); + else { + element_ptr x1 = DATA(P)->x, y1 = DATA(P)->y, x2 = DATA(R)->x, y2 = + DATA(R)->y; + if((PARAM(x1)->m - 1) / 2 % 2 == 0) + algorithm5(c, x1, y1, x2, y2); + else + algorithm4(c, x1, y1, x2, y2); + algorithm8(c, c); + } +} + +static void eta_T_3_clear(params *p) { + mpz_clear(p->n); + mpz_clear(p->n2); + pbc_free(p); +} + +static void GT_random(element_ptr e) { + element_t a, b; + element_init(a, e->field->pairing->G1); + element_init(b, e->field->pairing->G1); + element_random(a); + element_random(b); + element_pairing(e, a, b); + element_clear(a); + element_clear(b); +} + +static void eta_T_3_pairing_clear(pairing_t pairing) { + mpz_clear(pairing->r); + field_clear(pairing->Zr); + field_clear(pairing->GT); + field_clear(pairing->G1); + pbc_free(pairing->G1); + pairing_data_ptr dp = pairing->data; + field_clear(dp->gf3m); + field_clear(dp->gf32m); + field_clear(dp->gf36m); + mpz_clear(dp->n2); + pbc_free(dp); +} + +static void eta_T_3_init_pairing(pairing_t pairing, params *p) { + mpz_init(pairing->r); + mpz_set(pairing->r, p->n); + field_init_fp(pairing->Zr, pairing->r); + + pairing_data_ptr dp = pbc_malloc(sizeof(*dp)); + mpz_init(dp->n2); + mpz_set(dp->n2, p->n2); + field_init_gf3m(dp->gf3m, p->m, p->t); + field_init_gf32m(dp->gf32m, dp->gf3m); + field_init_gf33m(dp->gf36m, dp->gf32m); + pairing_GT_init(pairing, dp->gf36m); + pairing->GT->name = "eta_T_3 group of roots of 1"; + pairing->GT->random = GT_random; + pairing->G2 = pairing->G1 = pbc_malloc(sizeof(field_t)); + field_init_eta_T_3(pairing->G1, dp->gf3m); + pairing->G1->pairing = pairing; + mpz_set(pairing->G1->order, p->n); + mpz_set(pairing->GT->order, p->n); + pairing->map = eta_T_pairing; + pairing->data = dp; + pairing->clear_func = eta_T_3_pairing_clear; +} + +static void eta_T_3_out_str(FILE *stream, params *p) { + param_out_type(stream, "i"); + param_out_int(stream, "m", p->m); + param_out_int(stream, "t", p->t); + param_out_mpz(stream, "n", p->n); + param_out_mpz(stream, "n2", p->n2); +} + +static void param_init(pbc_param_ptr p) { + static pbc_param_interface_t interface = {{ + (void (*)(void *))eta_T_3_clear, + (void (*)(pairing_t, void *))eta_T_3_init_pairing, + (void (*)(FILE *, void *))eta_T_3_out_str, + }}; + p->api = interface; + params *param = p->data = pbc_malloc(sizeof(*param)); + mpz_init(param->n); + mpz_init(param->n2); +} + +int pbc_param_init_i(pbc_param_ptr p, struct symtab_s *tab) { + param_init(p); + params *param = p->data; + int err = 0; + err += lookup_int(¶m->m, tab, "m"); + err += lookup_int(¶m->t, tab, "t"); + err += lookup_mpz(param->n, tab, "n"); + err += lookup_mpz(param->n2, tab, "n2"); + return err; +} + +void pbc_param_init_i_gen(pbc_param_ptr par, int group_size) { + param_init(par); + params *p = par->data; + if (group_size <= 150) { + p->m = 97; + p->t = 12; + mpz_set_str(p->n, "2726865189058261010774960798134976187171462721", 10); + mpz_set_str(p->n2, "7", 10); + } else if (group_size <= 206) { + p->m = 199; + p->t = 164; + mpz_set_str(p->n, "167725321489096000055336949742738378351010268990525380470313869", 10); + mpz_set_str(p->n2, "527874953560391326545598291952743", 10); + } else if (group_size <= 259) { + p->m = 235; + p->t = 26; + mpz_set_str(p->n, "1124316700897695330265827797088699345032488681307846555184025129863722718180241", 10); + mpz_set_str(p->n2, "11819693021332914275777073321995059", 10); + } else if (group_size <= 316) { + p->m = 385; + p->t = 22; + mpz_set_str(p->n, "140884762419712839999909157778648717913595360839856026704744558309545986970238264714753014287541", 10); + mpz_set_str(p->n2, "34899486997246711147841377458771182755186809219564106252058066150110543296498189654810187", 10); + } else if (group_size <= 376) { + p->m = 337; + p->t = 30; + mpz_set_str(p->n, "250796519030408069744426774377542635685621984993105288007781750196791322190409525696108840742205849171229571431053", 10); + mpz_set_str(p->n2, "245777055088325363697128811262733732423405120899", 10); + } else if (group_size <= 430) { + p->m = 373; + p->t = 198; + mpz_set_str(p->n, "2840685307599487500956683789051368080919805957805957356540760731597378326586402072132959867084691357708217739285576524329854284197", 10); + mpz_set_str(p->n2, "3256903458766749542151641063558247849550904613763", 10); + } else if (group_size <= 484) { + p->m = 395; + p->t = 338; + mpz_set_str(p->n, "80172097064154181257340545445945701478615643539554910656655431171167598268341527430200810544156625333601812351266052856520678455274751591367269291", 10); + mpz_set_str(p->n2, "3621365590261279902324876775553649595261567", 10); + } else if (group_size <= 552) { + p->m = 433; + p->t = 120; + mpz_set_str(p->n, "15699907553631673835088720676147779193076555382157913339177784853763686462870506492752576492212322736133645158157557950634628006965882177348385366381692092784577773463", 10); + mpz_set_str(p->n2, "24980791723059119877470531054938874784049", 10); + } else if (group_size <= 644) { + p->m = 467; + p->t = 48; + mpz_set_str(p->n, "108220469499363631995525712756135494735252733492048868417164002000654321383482753640072319529019505742300964525569770933946381504691909098938045089999753901375631613294579329433690943459352138231", 10); + mpz_set_str(p->n2, "60438898450096967424971813347", 10); + } else if (group_size <= 696) { + p->m = 503; + p->t = 104; + mpz_set_str(p->n, "545523657676112447260904563578912738373307867219686215849632469801471112426878939776725222290437653718473962733760874627315930933126581248465899651120481066111839081575164964589811985885719017214938514563804313", 10); + mpz_set_str(p->n2, "1799606423432800810122901025413", 10); + } else if (group_size <= 803) { + p->m = 509; + p->t = 358; + mpz_set_str(p->n, "102239946202586852409809887418093021457150612495255706614733003327526279081563687830782748305746187060264985869283524441819589592750998086186315250781067131293823177124077445718802216415539934838376431091001197641295264650596195201747790167311", 10); + mpz_set_str(p->n2, "7", 10); + } else if (group_size <= 892) { + p->m = 617; + p->t = 88; + mpz_set_str(p->n, "57591959284219511220590893724691916802833742568034971006633345422620650391172287893878655658086794200963521584019889327992536532560877385225451713282279597074750857647455565899702728629166541223955196002755787520206774906606158388947359746178875040401304783332742806641", 10); + mpz_set_str(p->n2, "42019638181715250622338241", 10); + } else + pbc_die("unsupported group size"); +} + diff --git a/moon-abe/pbc-0.5.14/ecc/f_param.c b/moon-abe/pbc-0.5.14/ecc/f_param.c new file mode 100644 index 00000000..2477ace1 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/f_param.c @@ -0,0 +1,599 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> // for intptr_t +#include <stdlib.h> +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_fp.h" +#include "pbc_fieldquadratic.h" +#include "pbc_param.h" +#include "pbc_pairing.h" +#include "pbc_poly.h" +#include "pbc_curve.h" +#include "pbc_memory.h" +#include "pbc_f_param.h" +#include "ecc/param.h" + +struct f_param_s { + mpz_t q; // Curve defined over F_q. + mpz_t r; // The order of the curve. + mpz_t b; // E: y^2 = x^3 + b + mpz_t beta; //beta is a quadratic nonresidue in Fq + //we use F_q^2 = F_q[sqrt(beta)] + mpz_t alpha0, alpha1; + //the polynomial x^6 + alpha0 + alpha1 sqrt(beta) + //is irreducible over F_q^2[x], so + //we can extend F_q^2 to F_q^12 using the + //sixth root of -(alpha0 + alpha1 sqrt(beta)) +}; +typedef struct f_param_s f_param_t[1]; +typedef struct f_param_s *f_param_ptr; + +// TODO: we never use phikonr so don't bother computing it, +// but one day other routines might need it +struct f_pairing_data_s { + field_t Fq, Fq2, Fq2x, Fq12; + field_t Eq, Etwist; + element_t negalpha; + element_t negalphainv; + mpz_t tateexp; + + //for tate exponentiation speedup: + //x^{q^k} for various k + element_t xpowq2, xpowq6, xpowq8; +}; +typedef struct f_pairing_data_s f_pairing_data_t[1]; +typedef struct f_pairing_data_s *f_pairing_data_ptr; + +static void f_clear(void *data) { + f_param_ptr fp = data; + mpz_clear(fp->q); + mpz_clear(fp->r); + mpz_clear(fp->b); + mpz_clear(fp->beta); + mpz_clear(fp->alpha0); + mpz_clear(fp->alpha1); + pbc_free(data); +} + +static void f_out_str(FILE *stream, void *data) { + f_param_ptr p = data; + param_out_type(stream, "f"); + param_out_mpz(stream, "q", p->q); + param_out_mpz(stream, "r", p->r); + param_out_mpz(stream, "b", p->b); + param_out_mpz(stream, "beta", p->beta); + param_out_mpz(stream, "alpha0", p->alpha0); + param_out_mpz(stream, "alpha1", p->alpha1); +} + +static void tryminusx(mpz_ptr q, mpz_ptr x) { + //36x4 - 36x3 + 24x2 - 6x + 1 + //= ((36(x - 1)x + 24)x - 6)x + 1 + mpz_sub_ui(q, x, 1); + mpz_mul(q, q, x); + mpz_mul_ui(q, q, 36); + mpz_add_ui(q, q, 24); + mpz_mul(q, q, x); + mpz_sub_ui(q, q, 6); + mpz_mul(q, q, x); + mpz_add_ui(q, q, 1); +} + +static void tryplusx(mpz_ptr q, mpz_ptr x) { + //36x4 + 36x3 + 24x2 + 6x + 1 + //= ((36(x + 1)x + 24)x + 6)x + 1 + mpz_add_ui(q, x, 1); + mpz_mul(q, q, x); + mpz_mul_ui(q, q, 36); + mpz_add_ui(q, q, 24); + mpz_mul(q, q, x); + mpz_add_ui(q, q, 6); + mpz_mul(q, q, x); + mpz_add_ui(q, q, 1); +} + +static void cc_miller_no_denom(element_t res, mpz_t q, element_t P, + element_ptr Qx, element_ptr Qy, element_t negalpha) { + int 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 = mpz_sizeinbase(q, 2) - 2; + + //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 +} + +static void f_tateexp(element_t out) { + element_t x, y, epow; + f_pairing_data_ptr p = out->field->pairing->data; + element_init(x, p->Fq12); + element_init(y, p->Fq12); + element_init(epow, p->Fq2); + + #define qpower(e1, e) { \ + element_set(element_item(e1, 0), element_item(out, 0)); \ + element_mul(element_item(e1, 1), element_item(out, 1), e); \ + element_square(epow, e); \ + element_mul(element_item(e1, 2), element_item(out, 2), epow); \ + element_mul(epow, epow, e); \ + element_mul(element_item(e1, 3), element_item(out, 3), epow); \ + element_mul(epow, epow, e); \ + element_mul(element_item(e1, 4), element_item(out, 4), epow); \ + element_mul(epow, epow, e); \ + element_mul(element_item(e1, 5), element_item(out, 5), epow); \ + } + + qpower(y, p->xpowq8); + qpower(x, p->xpowq6); + element_mul(y, y, x); + qpower(x, p->xpowq2); + element_mul(x, x, out); + element_invert(x, x); + element_mul(out, y, x); + + element_clear(epow); + element_clear(x); + element_clear(y); + element_pow_mpz(out, out, p->tateexp); + #undef qpower +} + +static void f_finalpow(element_t out) { + f_tateexp(out->data); +} + +static void f_pairing(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + element_ptr Qbase = in2; + element_t x, y; + f_pairing_data_ptr p = pairing->data; + + element_init(x, p->Fq2); + element_init(y, p->Fq2); + //map from twist: (x, y) --> (v^-2 x, v^-3 y) + //where v is the sixth root used to construct the twist + //i.e. v^6 = -alpha + //thus v^-2 = -alpha^-1 v^4 + //and v^-3 = -alpha^-1 v^3 + element_mul(x, curve_x_coord(Qbase), p->negalphainv); + element_mul(y, curve_y_coord(Qbase), p->negalphainv); + + cc_miller_no_denom(out, pairing->r, in1, x, y, p->negalpha); + + element_clear(x); + element_clear(y); + + f_tateexp(out); +} + +static void f_pairing_clear(pairing_t pairing) { + field_clear(pairing->GT); + f_pairing_data_ptr p = pairing->data; + element_clear(p->negalpha); + element_clear(p->negalphainv); + mpz_clear(p->tateexp); + element_clear(p->xpowq2); + element_clear(p->xpowq6); + element_clear(p->xpowq8); + field_clear(p->Etwist); + field_clear(p->Eq); + + field_clear(p->Fq12); + field_clear(p->Fq2x); + field_clear(p->Fq2); + field_clear(p->Fq); + pbc_free(p); + + mpz_clear(pairing->r); + field_clear(pairing->Zr); +} + +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); +} + +static void f_init(pbc_param_ptr p) { + static pbc_param_interface_t interface = {{ + f_clear, + f_init_pairing, + f_out_str, + }}; + p->api = interface; + f_param_ptr fp = p->data = pbc_malloc(sizeof(*fp)); + mpz_init(fp->q); + mpz_init(fp->r); + mpz_init(fp->b); + mpz_init(fp->beta); + mpz_init(fp->alpha0); + mpz_init(fp->alpha1); +} + +// Public interface: + +int pbc_param_init_f(pbc_param_ptr par, struct symtab_s *tab) { + f_init(par); + f_param_ptr p = par->data; + + int err = 0; + err += lookup_mpz(p->q, tab, "q"); + err += lookup_mpz(p->r, tab, "r"); + err += lookup_mpz(p->b, tab, "b"); + err += lookup_mpz(p->beta, tab, "beta"); + err += lookup_mpz(p->alpha0, tab, "alpha0"); + err += lookup_mpz(p->alpha1, tab, "alpha1"); + return err; +} + +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); +} diff --git a/moon-abe/pbc-0.5.14/ecc/g_param.c b/moon-abe/pbc-0.5.14/ecc/g_param.c new file mode 100644 index 00000000..75a08c57 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/g_param.c @@ -0,0 +1,1435 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> // for intptr_t +#include <stdlib.h> +#include <string.h> +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_poly.h" +#include "pbc_hilbert.h" +#include "pbc_fp.h" +#include "pbc_fieldquadratic.h" +#include "pbc_mnt.h" +#include "pbc_curve.h" +#include "pbc_param.h" +#include "pbc_pairing.h" +#include "pbc_memory.h" +#include "pbc_g_param.h" +#include "ecc/param.h" + +struct g_param_s { + mpz_t q; // Curve defined over F_q. + mpz_t n; // n = #E(F_q) (= q - t + 1) + mpz_t h; // h * r = n, r is prime + mpz_t r; + mpz_t a, b; // E: y^2 = x^3 + ax + b + + // k = 10 for these curves. + mpz_t nk; // #E(F_q^k) + mpz_t hk; // hk * r^2 = nk + mpz_t *coeff; //Coefficients of polynomial used to extend F_q by k/2 + mpz_t nqr; // Quadratic nonresidue in F_q^d that lies in F_q. +}; + +typedef struct g_param_s g_param_t[1]; +typedef struct g_param_s *g_param_ptr; + +struct mnt_pairing_data_s { + field_t Fq, Fqx, Fqd, Fqk; + field_t Eq, Etwist; + element_t nqrinv, nqrinv2; + element_t xpowq, xpowq2, xpowq3, xpowq4; +}; +typedef struct mnt_pairing_data_s mnt_pairing_data_t[1]; +typedef struct mnt_pairing_data_s *mnt_pairing_data_ptr; + +static void g_clear(void *data) { + g_param_ptr param = data; + int i; + mpz_clear(param->q); + mpz_clear(param->n); + mpz_clear(param->h); + mpz_clear(param->r); + mpz_clear(param->a); + mpz_clear(param->b); + mpz_clear(param->nk); + mpz_clear(param->hk); + mpz_clear(param->nqr); + for (i = 0; i < 5; i++) { + mpz_clear(param->coeff[i]); + } + pbc_free(param->coeff); + pbc_free(data); +} + +static void g_out_str(FILE *stream, void *data) { + g_param_ptr p = data; + int i; + char s[8]; + param_out_type(stream, "g"); + param_out_mpz(stream, "q", p->q); + param_out_mpz(stream, "n", p->n); + param_out_mpz(stream, "h", p->h); + param_out_mpz(stream, "r", p->r); + param_out_mpz(stream, "a", p->a); + param_out_mpz(stream, "b", p->b); + param_out_mpz(stream, "nk", p->nk); + param_out_mpz(stream, "hk", p->hk); + for (i=0; i<5; i++) { + sprintf(s, "coeff%d", i); + param_out_mpz(stream, s, p->coeff[i]); + } + param_out_mpz(stream, "nqr", p->nqr); +} + +static inline void d_miller_evalfn(element_t e0, + element_t a, element_t b, element_t c, + element_t Qx, element_t Qy) { + //a, b, c are in Fq + //point Q is (Qx, Qy * sqrt(nqr)) where nqr is used to construct + //the quadratic field extension Fqk of Fqd + 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); +} + +static void cc_miller_no_denom_proj(element_t res, mpz_t q, element_t P, + element_ptr Qx, element_ptr Qy) { + int 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 = mpz_sizeinbase(q, 2) - 2; + + 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 +} + +static void cc_miller_no_denom_affine(element_t res, mpz_t q, element_t P, + element_ptr Qx, element_ptr Qy) { + int 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(void) + { + 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'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); \ + \ + 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 = mpz_sizeinbase(q, 2) - 2; + + 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 +} + +// Requires cofactor is even. +// Requires in != out. +// Mangles in. +static void lucas_even(element_ptr out, element_ptr in, mpz_t cofactor) { + 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); + int 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); +} + +static void tatepower10(element_ptr out, element_ptr in, pairing_t pairing) { + mnt_pairing_data_ptr p = pairing->data; + element_t e0, e1, e2, e3; + element_init(e0, p->Fqk); + element_init(e1, p->Fqd); + 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; + //see thesis + #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); \ + polymod_const_mul(e2, inre[3], p->xpowq3); \ + element_add(e0re, e0re, e2); \ + polymod_const_mul(e2, inre[4], p->xpowq4); \ + 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); \ + polymod_const_mul(e2, inim[3], p->xpowq3); \ + element_add(e0im, e0im, e2); \ + polymod_const_mul(e2, inim[4], p->xpowq4); \ + 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); \ + polymod_const_mul(e2, inim[3], p->xpowq3); \ + element_sub(e0im, e0im, e2); \ + polymod_const_mul(e2, inim[4], p->xpowq4); \ + element_sub(e0im, e0im, e2); \ + element_sub(e0im0, e0im0, inim[0]); \ + } \ + } + 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); + lucas_even(out, e0, pairing->phikonr); + + element_clear(e0); + element_clear(e1); + element_clear(e2); + element_clear(e3); + #undef qpower +} + +static void (*cc_miller_no_denom_fn)(element_t res, mpz_t q, element_t P, + element_ptr Qx, element_ptr Qy); + +static void cc_pairing(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + element_ptr Qbase = in2; + element_t Qx, Qy; + mnt_pairing_data_ptr p = pairing->data; + + element_init(Qx, p->Fqd); + element_init(Qy, p->Fqd); + //map from twist: (x, y) --> (v^-1 x, v^-(3/2) y) + //where v is the quadratic nonresidue used to construct the twist + element_mul(Qx, curve_x_coord(Qbase), p->nqrinv); + //v^-3/2 = v^-2 * v^1/2 + element_mul(Qy, curve_y_coord(Qbase), p->nqrinv2); + cc_miller_no_denom_fn(out, pairing->r, in1, Qx, Qy); + tatepower10(out, out, pairing); + element_clear(Qx); + element_clear(Qy); +} + +static int cc_is_almost_coddh(element_ptr a, element_ptr b, + element_ptr c, element_ptr d, + pairing_t pairing) { + int res = 0; + element_t t0, t1, t2; + element_t cx, cy; + element_t dx, dy; + mnt_pairing_data_ptr p = pairing->data; + + element_init(cx, p->Fqd); + element_init(cy, p->Fqd); + element_init(dx, p->Fqd); + element_init(dy, p->Fqd); + + element_init(t0, p->Fqk); + element_init(t1, p->Fqk); + element_init(t2, p->Fqk); + //map from twist: (x, y) --> (v^-1 x, v^-(3/2) y) + //where v is the quadratic nonresidue used to construct the twist + element_mul(cx, curve_x_coord(c), p->nqrinv); + element_mul(dx, curve_x_coord(d), p->nqrinv); + //v^-3/2 = v^-2 * v^1/2 + element_mul(cy, curve_y_coord(c), p->nqrinv2); + element_mul(dy, curve_y_coord(d), p->nqrinv2); + + cc_miller_no_denom_fn(t0, pairing->r, a, dx, dy); + cc_miller_no_denom_fn(t1, pairing->r, b, cx, cy); + tatepower10(t0, t0, pairing); + tatepower10(t1, t1, pairing); + element_mul(t2, t0, t1); + if (element_is1(t2)) { + //g, g^x, h, h^-x case + res = 1; + } else { + element_invert(t1, t1); + element_mul(t2, t0, t1); + if (element_is1(t2)) { + //g, g^x, h, h^x case + res = 1; + } + } + element_clear(cx); + element_clear(cy); + element_clear(dx); + element_clear(dy); + element_clear(t0); + element_clear(t1); + element_clear(t2); + return res; +} + +struct pp_coeff_s { + element_t a; + element_t b; + element_t c; +}; +typedef struct pp_coeff_s pp_coeff_t[1]; +typedef struct pp_coeff_s *pp_coeff_ptr; + +static void g_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; + int m; + mnt_pairing_data_ptr 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++; \ + } + + //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); + #define do_tangent() { \ + 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(); \ + } + + //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); \ + 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 = mpz_sizeinbase(q, 2) - 2; + 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 +} + +static void g_pairing_pp_clear(pairing_pp_t p) { + //TODO: better to store a sentinel value in p->data? + mpz_ptr q = p->pairing->r; + int m = mpz_sizeinbase(q, 2) + mpz_popcount(q) - 3; + int i; + pp_coeff_t *coeff = (pp_coeff_t *) p->data; + pp_coeff_ptr pp; + for (i=0; i<m; i++) { + pp = coeff[i]; + element_clear(pp->a); + element_clear(pp->b); + element_clear(pp->c); + } + pbc_free(p->data); +} + +static void g_pairing_pp_apply(element_ptr out, element_ptr in2, pairing_pp_t p) { + mpz_ptr q = p->pairing->r; + mnt_pairing_data_ptr info = p->pairing->data; + int m = mpz_sizeinbase(q, 2) - 2; + pp_coeff_t *coeff = (pp_coeff_t *) p->data; + pp_coeff_ptr pp = coeff[0]; + element_ptr Qbase = in2; + element_t e0; + element_t Qx, Qy; + element_t v; + element_init_same_as(e0, out); + element_init_same_as(v, out); + element_init(Qx, info->Fqd); + element_init(Qy, info->Fqd); + + //map from twist: (x, y) --> (v^-1 x, v^-(3/2) y) + //where v is the quadratic nonresidue used to construct the twist + element_mul(Qx, curve_x_coord(Qbase), info->nqrinv); + //v^-3/2 = v^-2 * v^1/2 + element_mul(Qy, curve_y_coord(Qbase), info->nqrinv2); + + element_set1(out); + for(;;) { + d_miller_evalfn(e0, pp->a, pp->b, pp->c, Qx, Qy); + element_mul(out, out, e0); + pp++; + + if (!m) break; + + if (mpz_tstbit(q, m)) { + d_miller_evalfn(e0, pp->a, pp->b, pp->c, Qx, Qy); + element_mul(out, out, e0); + pp++; + } + m--; + element_square(out, out); + } + tatepower10(out, out, p->pairing); + + element_clear(e0); + element_clear(Qx); + element_clear(Qy); + element_clear(v); +} + +// in1, in2 are from E(F_q), out from F_q^2 +// Compute pairing via elliptic nets (see Stange). +static void g_pairing_ellnet(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + mnt_pairing_data_ptr p = pairing->data; + + const element_ptr a = curve_a_coeff(in1); + const element_ptr b = curve_b_coeff(in1); + + element_ptr x = curve_x_coord(in1); + element_ptr y = curve_y_coord(in1); + + element_ptr x2 = curve_x_coord(in2); + element_ptr y2 = curve_y_coord(in2); + + //we map (x2,y2) to (-x2, i y2) before pairing + //notation: cmi means c_{k-i}, ci means c_{k+i} + element_t cm3, cm2, cm1, c0, c1, c2, c3, c4; + element_t dm1, d0, d1; + element_t A, B, C; + + element_init_same_as(cm3, x); + element_init_same_as(cm2, x); + element_init_same_as(cm1, x); + element_init_same_as(c0, x); + element_init_same_as(c1, x); + element_init_same_as(c2, x); + element_init_same_as(c3, x); + element_init_same_as(c4, x); + element_init_same_as(C, x); + + element_init_same_as(dm1, out); + element_init_same_as(d0, out); + element_init_same_as(d1, out); + element_init_same_as(A, out); + element_init_same_as(B, out); + + // c1 = 2y + // cm3 = -2y + element_double(c1, y); + element_neg(cm3, c1); + + //use c0, cm1, cm2, C, c4 as temp variables for now + //compute c3, c2 + element_square(cm2, x); + element_square(C, cm2); + element_mul(cm1, b, x); + element_double(cm1, cm1); + element_square(c4, a); + + element_mul(c2, cm1, cm2); + element_double(c2, c2); + element_mul(c0, a, C); + element_add(c2, c2, c0); + element_mul(c0, c4, cm2); + element_sub(c2, c2, c0); + element_double(c0, c2); + element_double(c0, c0); + element_add(c2, c2, c0); + + element_mul(c0, cm1, a); + element_square(c3, b); + element_double(c3, c3); + element_double(c3, c3); + element_add(c0, c0, c3); + element_double(c0, c0); + element_mul(c3, a, c4); + element_add(c0, c0, c3); + element_sub(c2, c2, c0); + element_mul(c0, cm2, C); + element_add(c3, c0, c2); + element_mul(c3, c3, c1); + element_double(c3, c3); + + element_mul(c0, a, cm2); + element_add(c0, c0, cm1); + element_double(c0, c0); + element_add(c0, c0, C); + element_double(c2, c0); + element_add(c0, c0, c2); + element_sub(c2, c0, c4); + + // c0 = 1 + // cm2 = -1 + element_set1(c0); + element_neg(cm2, c0); + + // c4 = c_5 = c_2^3 c_4 - c_3^3 = c1^3 c3 - c2^3 + element_square(C, c1); + element_mul(c4, C, c1); + element_mul(c4, c4, c3); + element_square(C, c2); + element_mul(C, C, c2); + element_sub(c4, c4, C); + + //compute A, B, d1 + + element_mul(element_x(d0), x2, p->nqrinv); + element_neg(A, d0); + element_add(element_item(element_x(A), 0), element_item(element_x(A), 0), x); + + element_double(C, x); + element_add(element_item(element_x(d0), 0), element_item(element_x(d0), 0), C); + + element_square(dm1, A); + element_mul(dm1, d0, dm1); + + element_mul(element_y(d1), y2, p->nqrinv2); + element_set(element_item(element_x(d1), 0), y); + + element_square(d1, d1); + element_sub(d1, dm1, d1); + element_invert(B, d1); + + element_invert(A, A); + + element_mul(element_y(d1), y2, p->nqrinv2); + element_set0(element_x(d1)); + element_neg(element_item(element_x(d1), 0), y); + element_mul(d1, d1, A); + element_square(d1, d1); + element_sub(d1, d0, d1); + + // cm1 = 0 + // C = (2y)^-1 + element_set0(cm1); + element_invert(C, c1); + + element_set1(dm1); + element_set1(d0); + + element_t sm2, sm1; + element_t s0, s1, s2, s3; + element_t tm2, tm1; + element_t t0, t1, t2, t3; + element_t e0, e1; + element_t u, v; + + element_init_same_as(sm2, x); + element_init_same_as(sm1, x); + element_init_same_as(s0, x); + element_init_same_as(s1, x); + element_init_same_as(s2, x); + element_init_same_as(s3, x); + + element_init_same_as(tm2, x); + element_init_same_as(tm1, x); + element_init_same_as(t0, x); + element_init_same_as(t1, x); + element_init_same_as(t2, x); + element_init_same_as(t3, x); + + element_init_same_as(e0, x); + element_init_same_as(e1, x); + + element_init_same_as(u, d0); + element_init_same_as(v, d0); + + int m = mpz_sizeinbase(pairing->r, 2) - 2; + for (;;) { + element_square(sm2, cm2); + element_square(sm1, cm1); + element_square(s0, c0); + element_square(s1, c1); + element_square(s2, c2); + element_square(s3, c3); + + element_mul(tm2, cm3, cm1); + element_mul(tm1, cm2, c0); + element_mul(t0, cm1, c1); + element_mul(t1, c0, c2); + element_mul(t2, c1, c3); + element_mul(t3, c2, c4); + + element_square(u, d0); + element_mul(v, dm1, d1); + + if (mpz_tstbit(pairing->r, m)) { + //double-and-add + element_mul(e0, t0, sm2); + element_mul(e1, tm2, s0); + element_sub(cm3, e0, e1); + element_mul(cm3, cm3, C); + + element_mul(e0, t0, sm1); + element_mul(e1, tm1, s0); + element_sub(cm2, e0, e1); + + element_mul(e0, t1, sm1); + element_mul(e1, tm1, s1); + element_sub(cm1, e0, e1); + element_mul(cm1, cm1, C); + + element_mul(e0, t1, s0); + element_mul(e1, t0, s1); + element_sub(c0, e0, e1); + + element_mul(e0, t2, s0); + element_mul(e1, t0, s2); + element_sub(c1, e0, e1); + element_mul(c1, c1, C); + + element_mul(e0, t2, s1); + element_mul(e1, t1, s2); + element_sub(c2, e0, e1); + + element_mul(e0, t3, s1); + element_mul(e1, t1, s3); + element_sub(c3, e0, e1); + element_mul(c3, c3, C); + + element_mul(e0, t3, s2); + element_mul(e1, t2, s3); + element_sub(c4, e0, e1); + + polymod_const_mul(element_x(out), t0, element_x(u)); + polymod_const_mul(element_y(out), t0, element_y(u)); + polymod_const_mul(element_x(dm1), s0, element_x(v)); + polymod_const_mul(element_y(dm1), s0, element_y(v)); + element_sub(dm1, dm1, out); + + polymod_const_mul(element_x(out), t1, element_x(u)); + polymod_const_mul(element_y(out), t1, element_y(u)); + polymod_const_mul(element_x(d0), s1, element_x(v)); + polymod_const_mul(element_y(d0), s1, element_y(v)); + element_sub(d0, d0, out); + element_mul(d0, d0, A); + + polymod_const_mul(element_x(out), t2, element_x(u)); + polymod_const_mul(element_y(out), t2, element_y(u)); + polymod_const_mul(element_x(d1), s2, element_x(v)); + polymod_const_mul(element_y(d1), s2, element_y(v)); + element_sub(d1, d1, out); + element_mul(d1, d1, B); + } else { + //double + element_mul(e0, tm1, sm2); + element_mul(e1, tm2, sm1); + element_sub(cm3, e0, e1); + + element_mul(e0, t0, sm2); + element_mul(e1, tm2, s0); + element_sub(cm2, e0, e1); + element_mul(cm2, cm2, C); + + element_mul(e0, t0, sm1); + element_mul(e1, tm1, s0); + element_sub(cm1, e0, e1); + + element_mul(e0, t1, sm1); + element_mul(e1, tm1, s1); + element_sub(c0, e0, e1); + element_mul(c0, c0, C); + + element_mul(e0, t1, s0); + element_mul(e1, t0, s1); + element_sub(c1, e0, e1); + + element_mul(e0, t2, s0); + element_mul(e1, t0, s2); + element_sub(c2, e0, e1); + element_mul(c2, c2, C); + + element_mul(e0, t2, s1); + element_mul(e1, t1, s2); + element_sub(c3, e0, e1); + + element_mul(e0, t3, s1); + element_mul(e1, t1, s3); + element_sub(c4, e0, e1); + element_mul(c4, c4, C); + + polymod_const_mul(element_x(out), tm1, element_x(u)); + polymod_const_mul(element_y(out), tm1, element_y(u)); + polymod_const_mul(element_x(dm1), sm1, element_x(v)); + polymod_const_mul(element_y(dm1), sm1, element_y(v)); + element_sub(dm1, dm1, out); + + polymod_const_mul(element_x(out), t0, element_x(u)); + polymod_const_mul(element_y(out), t0, element_y(u)); + polymod_const_mul(element_x(d0), s0, element_x(v)); + polymod_const_mul(element_y(d0), s0, element_y(v)); + element_sub(d0, d0, out); + + polymod_const_mul(element_x(out), t1, element_x(u)); + polymod_const_mul(element_y(out), t1, element_y(u)); + polymod_const_mul(element_x(d1), s1, element_x(v)); + polymod_const_mul(element_y(d1), s1, element_y(v)); + element_sub(d1, d1, out); + element_mul(d1, d1, A); + } + if (!m) break; + m--; + } + // since c_k lies base field + // it gets killed by the final powering + //element_invert(c1, c1); + //element_mul(element_x(d1), element_x(d1), c1); + //element_mul(element_y(d1), element_y(d1), c1); + + tatepower10(out, d1, pairing); + + element_clear(dm1); + element_clear(d0); + element_clear(d1); + + element_clear(cm3); + element_clear(cm2); + element_clear(cm1); + element_clear(c0); + element_clear(c1); + element_clear(c2); + element_clear(c3); + element_clear(c4); + + element_clear(sm2); + element_clear(sm1); + element_clear(s0); + element_clear(s1); + element_clear(s2); + element_clear(s3); + + element_clear(tm2); + element_clear(tm1); + element_clear(t0); + element_clear(t1); + element_clear(t2); + element_clear(t3); + + element_clear(e0); + element_clear(e1); + element_clear(A); + element_clear(B); + element_clear(C); + element_clear(u); + element_clear(v); +} + +static void g_pairing_clear(pairing_t pairing) { + field_clear(pairing->GT); + mnt_pairing_data_ptr p = pairing->data; + + element_clear(p->xpowq); + element_clear(p->xpowq2); + element_clear(p->xpowq3); + element_clear(p->xpowq4); + mpz_clear(pairing->phikonr); + + field_clear(p->Etwist); + field_clear(p->Eq); + element_clear(p->nqrinv); + element_clear(p->nqrinv2); + field_clear(p->Fqk); + field_clear(p->Fqd); + field_clear(p->Fqx); + field_clear(p->Fq); + field_clear(pairing->Zr); + mpz_clear(pairing->r); + pbc_free(p); +} + +static void g_pairing_option_set(pairing_t pairing, char *key, char *value) { + UNUSED_VAR(pairing); + if (!strcmp(key, "method")) { + if (!strcmp(value, "miller")) { + cc_miller_no_denom_fn = cc_miller_no_denom_proj; + } else if (!strcmp(value, "miller-affine")) { + cc_miller_no_denom_fn = cc_miller_no_denom_affine; + } else if (!strcmp(value, "shipsey-stange")) { + pairing->map = g_pairing_ellnet; + } + } +} + +static void g_finalpow(element_ptr e) { + element_t t0; + element_init_same_as(t0, e->data); + tatepower10(t0, e->data, e->field->pairing); + element_set(e->data, t0); + element_clear(t0); +} + +// Computes a curve and sets fp to the field it is defined over using the +// complex multiplication method, where cm holds appropriate data +// (e.g. discriminant, field order). +static void compute_cm_curve(g_param_ptr param, pbc_cm_ptr cm) { + element_t hp, root; + field_t fp, fpx; + field_t cc; + + field_init_fp(fp, cm->q); + field_init_poly(fpx, fp); + element_init(hp, fpx); + + mpz_t *coefflist; + int n = pbc_hilbert(&coefflist, cm->D); + + // Temporarily set the coefficient of x^{n-1} to 1 so hp has degree n - 1, + // allowing us to use element_item(). + poly_set_coeff1(hp, n - 1); + int i; + for (i = 0; i < n; i++) { + element_set_mpz(element_item(hp, i), coefflist[i]); + } + pbc_hilbert_free(coefflist, n); + + //TODO: remove x = 0, 1728 roots + //TODO: what if there's no roots? + //printf("hp "); + //element_out_str(stdout, 0, hp); + //printf("\n"); + + element_init(root, fp); + poly_findroot(root, hp); + //printf("root = "); + //element_out_str(stdout, 0, root); + //printf("\n"); + element_clear(hp); + field_clear(fpx); + + //the root is the j-invariant of our desired curve + field_init_curve_j(cc, root, cm->n, NULL); + element_clear(root); + + //we may need to twist it however + { + // Pick a random point P and twist the curve if it has the wrong order. + element_t P; + element_init(P, cc); + element_random(P); + element_mul_mpz(P, P, cm->n); + if (!element_is0(P)) field_reinit_curve_twist(cc); + element_clear(P); + } + + mpz_set(param->q, cm->q); + mpz_set(param->n, cm->n); + mpz_set(param->h, cm->h); + mpz_set(param->r, cm->r); + element_to_mpz(param->a, curve_field_a_coeff(cc)); + element_to_mpz(param->b, curve_field_b_coeff(cc)); + { + mpz_t z; + mpz_init(z); + //compute order of curve in F_q^k + //n = q - t + 1 hence t = q - n + 1 + mpz_sub(z, param->q, param->n); + mpz_add_ui(z, z, 1); + pbc_mpz_trace_n(z, param->q, z, 10); + mpz_pow_ui(param->nk, param->q, 10); + mpz_sub_ui(z, z, 1); + mpz_sub(param->nk, param->nk, z); + mpz_mul(z, param->r, param->r); + mpz_divexact(param->hk, param->nk, z); + mpz_clear(z); + } + field_clear(cc); + field_clear(fp); +} + +static void g_init_pairing(pairing_t pairing, void *data) { + g_param_ptr param = data; + mnt_pairing_data_ptr p; + element_t a, b; + element_t irred; + int i; + + mpz_init(pairing->r); + mpz_set(pairing->r, param->r); + field_init_fp(pairing->Zr, pairing->r); + pairing->map = cc_pairing; + pairing->is_almost_coddh = cc_is_almost_coddh; + + p = pairing->data = pbc_malloc(sizeof(mnt_pairing_data_t)); + field_init_fp(p->Fq, param->q); + element_init(a, p->Fq); + element_init(b, p->Fq); + element_set_mpz(a, param->a); + element_set_mpz(b, param->b); + field_init_curve_ab(p->Eq, a, b, pairing->r, param->h); + + field_init_poly(p->Fqx, p->Fq); + element_init(irred, p->Fqx); + + // First set the coefficient of x^5 to 1 so we can call element_item() + // for the other coefficients. + poly_set_coeff1(irred, 5); + for (i=0; i<5; i++) { + element_set_mpz(element_item(irred, i), param->coeff[i]); + } + + field_init_polymod(p->Fqd, irred); + element_clear(irred); + + p->Fqd->nqr = pbc_malloc(sizeof(element_t)); + element_init(p->Fqd->nqr, p->Fqd); + element_set_mpz(((element_t *) p->Fqd->nqr->data)[0], param->nqr); + + field_init_quadratic(p->Fqk, p->Fqd); + + // Compute phi(k)/r = (q^4 - q^3 + ... + 1)/r. + { + element_ptr e = p->xpowq; + mpz_t z0; + mpz_ptr q = param->q; + mpz_ptr z = pairing->phikonr; + mpz_init(z); + mpz_init(z0); + mpz_set_ui(z, 1); + mpz_sub(z, z, q); + mpz_mul(z0, q, q); + mpz_add(z, z, z0); + mpz_mul(z0, z0, q); + mpz_sub(z, z, z0); + mpz_mul(z0, z0, q); + mpz_add(z, z, z0); + mpz_clear(z0); + mpz_divexact(z, z, pairing->r); + + element_init(e, p->Fqd); + element_init(p->xpowq2, p->Fqd); + element_init(p->xpowq3, p->Fqd); + element_init(p->xpowq4, p->Fqd); + element_set1(((element_t *) e->data)[1]); + element_pow_mpz(e, e, q); + + element_square(p->xpowq2, p->xpowq); + element_square(p->xpowq4, p->xpowq2); + element_mul(p->xpowq3, p->xpowq2, p->xpowq); + } + + field_init_curve_ab_map(p->Etwist, p->Eq, element_field_to_polymod, p->Fqd, pairing->r, NULL); + field_reinit_curve_twist(p->Etwist); + + element_init(p->nqrinv, p->Fqd); + element_invert(p->nqrinv, field_get_nqr(p->Fqd)); + element_init(p->nqrinv2, p->Fqd); + element_square(p->nqrinv2, p->nqrinv); + + mpz_t ndonr; + mpz_init(ndonr); + // ndonr temporarily holds the trace. + mpz_sub(ndonr, param->q, param->n); + mpz_add_ui(ndonr, ndonr, 1); + // Negate because we want the order of the twist. + mpz_neg(ndonr, ndonr); + pbc_mpz_curve_order_extn(ndonr, param->q, ndonr, 5); + 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->Fqk); + pairing->finalpow = g_finalpow; + + cc_miller_no_denom_fn = cc_miller_no_denom_affine; + pairing->option_set = g_pairing_option_set; + pairing->pp_init = g_pairing_pp_init; + pairing->pp_clear = g_pairing_pp_clear; + pairing->pp_apply = g_pairing_pp_apply; + + pairing->clear_func = g_pairing_clear; + + element_clear(a); + element_clear(b); +} + +static void g_init(pbc_param_ptr p) { + static pbc_param_interface_t interface = {{ + g_clear, + g_init_pairing, + g_out_str, + }}; + p->api = interface; + g_param_ptr param = p->data = pbc_malloc(sizeof(*param)); + mpz_init(param->q); + mpz_init(param->n); + mpz_init(param->h); + mpz_init(param->r); + mpz_init(param->a); + mpz_init(param->b); + mpz_init(param->nk); + mpz_init(param->hk); + param->coeff = NULL; + mpz_init(param->nqr); +} + +// Public interface: + +int pbc_param_init_g(pbc_param_ptr par, struct symtab_s *tab) { + g_init(par); + g_param_ptr p = par->data; + char s[80]; + + int err = 0; + err += lookup_mpz(p->q, tab, "q"); + err += lookup_mpz(p->n, tab, "n"); + err += lookup_mpz(p->h, tab, "h"); + err += lookup_mpz(p->r, tab, "r"); + err += lookup_mpz(p->a, tab, "a"); + err += lookup_mpz(p->b, tab, "b"); + err += lookup_mpz(p->nk, tab, "nk"); + err += lookup_mpz(p->hk, tab, "hk"); + err += lookup_mpz(p->nqr, tab, "nqr"); + + p->coeff = pbc_realloc(p->coeff, sizeof(mpz_t) * 5); + int i; + for (i = 0; i < 5; i++) { + sprintf(s, "coeff%d", i); + mpz_init(p->coeff[i]); + err += lookup_mpz(p->coeff[i], tab, s); + } + return err; +} + +void pbc_param_init_g_gen(pbc_param_t p, pbc_cm_ptr cm) { + g_init(p); + g_param_ptr param = p->data; + field_t Fq, Fqx, Fqd; + element_t irred, nqr; + int i; + + compute_cm_curve(param, cm); + + field_init_fp(Fq, param->q); + field_init_poly(Fqx, Fq); + element_init(irred, Fqx); + do { + poly_random_monic(irred, 5); + } while (!poly_is_irred(irred)); + field_init_polymod(Fqd, irred); + + // Find a quadratic nonresidue of Fqd lying in Fq. + element_init(nqr, Fqd); + do { + element_random(((element_t *) nqr->data)[0]); + } while (element_is_sqr(nqr)); + + param->coeff = pbc_realloc(param->coeff, sizeof(mpz_t) * 5); + + for (i=0; i<5; i++) { + mpz_init(param->coeff[i]); + element_to_mpz(param->coeff[i], element_item(irred, i)); + } + element_to_mpz(param->nqr, ((element_t *) nqr->data)[0]); + + element_clear(nqr); + element_clear(irred); + + field_clear(Fqx); + field_clear(Fqd); + field_clear(Fq); +} diff --git a/moon-abe/pbc-0.5.14/ecc/hilbert.c b/moon-abe/pbc-0.5.14/ecc/hilbert.c new file mode 100644 index 00000000..753e70e0 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/hilbert.c @@ -0,0 +1,539 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> // for intptr_t +#include <stdlib.h> //for pbc_malloc, pbc_free +#include <gmp.h> +#include <math.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_poly.h" +#include "pbc_hilbert.h" +#include "pbc_memory.h" + +#include "misc/darray.h" +#include "mpc.h" + +static mpf_t pi, eulere, recipeulere, epsilon, negepsilon; + +static void mpf_exp(mpf_t res, mpf_t pwr) { + mpf_t a; + mpf_t f0; + int i; + + mpf_init(a); mpf_set(a, pwr); + + mpf_init(f0); + + mpf_set(f0, a); + mpf_add_ui(res, a, 1); + + for (i=2;;i++) { + mpf_mul(f0, f0, a); + mpf_div_ui(f0, f0, i); + if (mpf_sgn(f0) > 0) { + if (mpf_cmp(f0, epsilon) < 0) break; + } else { + if (mpf_cmp(f0, negepsilon) > 0) break; + } + mpf_add(res, res, f0); + } + + mpf_clear(f0); + mpf_clear(a); +} + +static void mpc_cis(mpc_t res, mpf_t theta) { + mpf_t a; + + mpf_init(a); mpf_set(a, theta); + //res = exp(i a) + // = cos a + i sin a + //converges quickly near the origin + mpf_t f0; + mpf_ptr rx = mpc_re(res), ry = mpc_im(res); + int i; + int toggle = 1; + + mpf_init(f0); + + mpf_set(f0, a); + mpf_set_ui(rx, 1); + mpf_set(ry, f0); + i = 1; + for(;;) { + toggle = !toggle; + i++; + mpf_div_ui(f0, f0, i); + mpf_mul(f0, f0, a); + if (toggle) { + mpf_add(rx, rx, f0); + } else { + mpf_sub(rx, rx, f0); + } + + i++; + mpf_div_ui(f0, f0, i); + mpf_mul(f0, f0, a); + + if (toggle) { + mpf_add(ry, ry, f0); + } else { + mpf_sub(ry, ry, f0); + } + + if (mpf_sgn(f0) > 0) { + if (mpf_cmp(f0, epsilon) < 0) break; + } else { + if (mpf_cmp(f0, negepsilon) > 0) break; + } + } + + mpf_clear(f0); + mpf_clear(a); +} + +// Computes q = exp(2 pi i tau). +static void compute_q(mpc_t q, mpc_t tau) { + mpc_t z0; + mpf_t f0, f1; + mpf_ptr fp0; + unsigned long pwr; + + mpc_init(z0); + mpf_init(f0); + mpf_init(f1); + + //compute z0 = 2 pi i tau + mpc_set(z0, tau); + //first remove integral part of Re(tau) + //since exp(2 pi i) = 1 + //it seems |Re(tau)| < 1 anyway? + fp0 = mpc_re(z0); + mpf_trunc(f1, fp0); + mpf_sub(fp0, fp0, f1); + + mpc_mul_mpf(z0, z0, pi); + mpc_mul_ui(z0, z0, 2); + mpc_muli(z0, z0); + + //compute q = exp(z0); + //first write z0 = A + a + b i + //where A is a (negative) integer + //and a, b are in [-1, 1] + //compute e^A separately + fp0 = mpc_re(z0); + pwr = mpf_get_ui(fp0); + mpf_pow_ui(f0, recipeulere, pwr); + mpf_add_ui(fp0, fp0, pwr); + + mpf_exp(f1, mpc_re(z0)); + mpf_mul(f0, f1, f0); + mpc_cis(q, mpc_im(z0)); + + /* + old_mpc_exp(q, z0); + */ + mpc_mul_mpf(q, q, f0); + + mpc_clear(z0); + mpf_clear(f0); + mpf_clear(f1); +} + +// Computes z = Delta(q) (see Cohen). +static void compute_Delta(mpc_t z, mpc_t q) { + int d; + int n; + int power; + mpc_t z0, z1, z2; + + mpc_init(z0); + mpc_init(z1); + mpc_init(z2); + + mpc_set_ui(z0, 1); + d = -1; + for(n=1; n<100; n++) { + power = n *(3 * n - 1) / 2; + mpc_pow_ui(z1, q, power); + mpc_pow_ui(z2, q, n); + mpc_mul(z2, z2, z1); + mpc_add(z1, z1, z2); + if (d) { + mpc_sub(z0, z0, z1); + d = 0; + } else { + mpc_add(z0, z0, z1); + d = 1; + } + } + + mpc_pow_ui(z0, z0, 24); + mpc_mul(z, z0, q); + + mpc_clear(z0); + mpc_clear(z1); + mpc_clear(z2); +} + +// Computes z = h(tau) +// (called h() by Blake et al, f() by Cohen.) +static void compute_h(mpc_t z, mpc_t tau) { + mpc_t z0, z1, q; + mpc_init(q); + mpc_init(z0); + mpc_init(z1); + compute_q(q, tau); + mpc_mul(z0, q, q); + compute_Delta(z0, z0); + compute_Delta(z1, q); + mpc_div(z, z0, z1); + mpc_clear(q); + mpc_clear(z0); + mpc_clear(z1); +} + +// Computes j = j(tau). +static void compute_j(mpc_t j, mpc_t tau) { + mpc_t h; + mpc_t z0; + mpc_init(h); + mpc_init(z0); + compute_h(h, tau); + //mpc_mul_ui(z0, h, 256); + mpc_mul_2exp(z0, h, 8); + mpc_add_ui(z0, z0, 1); + mpc_pow_ui(z0, z0, 3); + mpc_div(j, z0, h); + mpc_clear(z0); + mpc_clear(h); +} + +static void compute_pi(int prec) { + //Chudnovsky brothers' Ramanujan formula + //http://www.cs.uwaterloo.ca/~alopez-o/math-faq/mathtext/node12.html + mpz_t k1, k2, k4, k5, d; + unsigned int k3 = 640320; + unsigned int k6 = 53360; + mpz_t z0, z1, z2; + mpq_t p, q; + mpf_t f1; + int toggle = 1; + int n; + //converges fast: each term gives over 47 bits + int nlimit = prec / 47 + 1; + + mpz_init(k1); + mpz_init(k2); + mpz_init(k4); + mpz_init(k5); + mpz_init(d); + mpz_init(z0); + mpz_init(z1); + mpz_init(z2); + mpq_init(q); + mpq_init(p); + mpf_init(f1); + + mpz_set_str(k1, "545140134", 10); + mpz_set_str(k2, "13591409", 10); + mpz_set_str(k4, "100100025", 10); + mpz_set_str(k5, "327843840", 10); + + mpz_mul(d, k4, k5); + mpz_mul_2exp(d, d, 3); + mpq_set_ui(p, 0, 1); + + for (n=0; n<nlimit; n++) { + mpz_fac_ui(z0, 6*n); + mpz_mul_ui(z1, k1, n); + mpz_add(z1, z1, k2); + mpz_mul(z0, z0, z1); + + mpz_fac_ui(z1, 3*n); + mpz_fac_ui(z2, n); + mpz_pow_ui(z2, z2, 3); + mpz_mul(z1, z1, z2); + mpz_pow_ui(z2, d, n); + mpz_mul(z1, z1, z2); + + mpz_set(mpq_numref(q), z0); + mpz_set(mpq_denref(q), z1); + mpq_canonicalize(q); + if (toggle) { + mpq_add(p, p, q); + } else { + mpq_sub(p, p, q); + } + toggle = !toggle; + } + mpq_inv(q, p); + mpz_mul_ui(mpq_numref(q), mpq_numref(q), k6); + mpq_canonicalize(q); + mpf_set_q(pi, q); + mpf_sqrt_ui(f1, k3); + mpf_mul(pi, pi, f1); + //mpf_out_str(stdout, 0, 14 * nlimit, pi); + //printf("\n"); + + mpz_clear(k1); + mpz_clear(k2); + mpz_clear(k4); + mpz_clear(k5); + mpz_clear(d); + mpz_clear(z0); + mpz_clear(z1); + mpz_clear(z2); + mpq_clear(q); + mpq_clear(p); + mpf_clear(f1); +} + +static void precision_init(int prec) { + int i; + mpf_t f0; + + mpf_set_default_prec(prec); + mpf_init2(epsilon, 2); + mpf_init2(negepsilon, 2); + mpf_init(recipeulere); + mpf_init(pi); + mpf_init(eulere); + + mpf_set_ui(epsilon, 1); + mpf_div_2exp(epsilon, epsilon, prec); + mpf_neg(negepsilon, epsilon); + + mpf_init(f0); + mpf_set_ui(eulere, 1); + mpf_set_ui(f0, 1); + for (i=1;; i++) { + mpf_div_ui(f0, f0, i); + if (mpf_cmp(f0, epsilon) < 0) { + break; + } + mpf_add(eulere, eulere, f0); + } + mpf_clear(f0); + + mpf_ui_div(recipeulere, 1, eulere); + + compute_pi(prec); +} + +static void precision_clear(void) { + mpf_clear(eulere); + mpf_clear(recipeulere); + mpf_clear(pi); + mpf_clear(epsilon); + mpf_clear(negepsilon); +} + +// See Cohen; my D is -D in his notation. +size_t pbc_hilbert(mpz_t **arr, int D) { + int a, b; + int t; + int B = floor(sqrt((double) D / 3.0)); + mpc_t alpha; + mpc_t j; + mpf_t sqrtD; + mpf_t f0; + darray_t Pz; + mpc_t z0, z1, z2; + double d = 1.0; + int h = 1; + int jcount = 1; + + // Compute required precision. + b = D % 2; + for (;;) { + t = (b*b + D) / 4; + a = b; + if (a <= 1) { + a = 1; + goto step535_4; + } +step535_3: + if (!(t % a)) { + jcount++; + if ((a == b) || (a*a == t) || !b) { + d += 1.0 / ((double) a); + h++; + } else { + d += 2.0 / ((double) a); + h+=2; + } + } +step535_4: + a++; + if (a * a <= t) { + goto step535_3; + } else { + b += 2; + if (b > B) break; + } + } + + //printf("modulus: %f\n", exp(3.14159265358979 * sqrt(D)) * d * 0.5); + d *= sqrt(D) * 3.14159265358979 / log(2); + precision_init(d + 34); + pbc_info("class number %d, %d bit precision", h, (int) d + 34); + + darray_init(Pz); + mpc_init(alpha); + mpc_init(j); + mpc_init(z0); + mpc_init(z1); + mpc_init(z2); + mpf_init(sqrtD); + mpf_init(f0); + + mpf_sqrt_ui(sqrtD, D); + b = D % 2; + h = 0; + for (;;) { + t = (b*b + D) / 4; + if (b > 1) { + a = b; + } else { + a = 1; + } +step3: + if (t % a) { +step4: + a++; + if (a * a <= t) goto step3; + } else { + // a, b, t/a are coeffs of an appropriate primitive reduced positive + // definite form. + // Compute j((-b + sqrt{-D})/(2a)). + h++; + pbc_info("[%d/%d] a b c = %d %d %d", h, jcount, a, b, t/a); + mpf_set_ui(f0, 1); + mpf_div_ui(f0, f0, 2 * a); + mpf_mul(mpc_im(alpha), sqrtD, f0); + mpf_mul_ui(f0, f0, b); + mpf_neg(mpc_re(alpha), f0); + + compute_j(j, alpha); +if (0) { + int i; + for (i=Pz->count - 1; i>=0; i--) { + printf("P %d = ", i); + mpc_out_str(stdout, 10, 4, Pz->item[i]); + printf("\n"); + } +} + if (a == b || a * a == t || !b) { + // P *= X - j + int i, n; + mpc_ptr p0; + p0 = (mpc_ptr) pbc_malloc(sizeof(mpc_t)); + mpc_init(p0); + mpc_neg(p0, j); + n = Pz->count; + if (n) { + mpc_set(z1, Pz->item[0]); + mpc_add(Pz->item[0], z1, p0); + for (i=1; i<n; i++) { + mpc_mul(z0, z1, p0); + mpc_set(z1, Pz->item[i]); + mpc_add(Pz->item[i], z1, z0); + } + mpc_mul(p0, p0, z1); + } + darray_append(Pz, p0); + } else { + // P *= X^2 - 2 Re(j) X + |j|^2 + int i, n; + mpc_ptr p0, p1; + p0 = (mpc_ptr) pbc_malloc(sizeof(mpc_t)); + p1 = (mpc_ptr) pbc_malloc(sizeof(mpc_t)); + mpc_init(p0); + mpc_init(p1); + // p1 = - 2 Re(j) + mpf_mul_ui(f0, mpc_re(j), 2); + mpf_neg(f0, f0); + mpf_set(mpc_re(p1), f0); + // p0 = |j|^2 + mpf_mul(f0, mpc_re(j), mpc_re(j)); + mpf_mul(mpc_re(p0), mpc_im(j), mpc_im(j)); + mpf_add(mpc_re(p0), mpc_re(p0), f0); + n = Pz->count; + if (!n) { + } else if (n == 1) { + mpc_set(z1, Pz->item[0]); + mpc_add(Pz->item[0], z1, p1); + mpc_mul(p1, z1, p1); + mpc_add(p1, p1, p0); + mpc_mul(p0, p0, z1); + } else { + mpc_set(z2, Pz->item[0]); + mpc_set(z1, Pz->item[1]); + mpc_add(Pz->item[0], z2, p1); + mpc_mul(z0, z2, p1); + mpc_add(Pz->item[1], z1, z0); + mpc_add(Pz->item[1], Pz->item[1], p0); + for (i=2; i<n; i++) { + mpc_mul(z0, z1, p1); + mpc_mul(alpha, z2, p0); + mpc_set(z2, z1); + mpc_set(z1, Pz->item[i]); + mpc_add(alpha, alpha, z0); + mpc_add(Pz->item[i], z1, alpha); + } + mpc_mul(z0, z2, p0); + mpc_mul(p1, p1, z1); + mpc_add(p1, p1, z0); + mpc_mul(p0, p0, z1); + } + darray_append(Pz, p1); + darray_append(Pz, p0); + } + goto step4; + } + b+=2; + if (b > B) break; + } + + // Round polynomial and assign. + int k = 0; + { + *arr = pbc_malloc(sizeof(mpz_t) * (Pz->count + 1)); + int i; + for (i=Pz->count - 1; i>=0; i--) { + if (mpf_sgn(mpc_re(Pz->item[i])) < 0) { + mpf_set_d(f0, -0.5); + } else { + mpf_set_d(f0, 0.5); + } + mpf_add(f0, f0, mpc_re(Pz->item[i])); + mpz_init((*arr)[k]); + mpz_set_f((*arr)[k], f0); + k++; + mpc_clear(Pz->item[i]); + pbc_free(Pz->item[i]); + } + mpz_init((*arr)[k]); + mpz_set_ui((*arr)[k], 1); + k++; + } + darray_clear(Pz); + mpc_clear(z0); + mpc_clear(z1); + mpc_clear(z2); + mpf_clear(f0); + mpf_clear(sqrtD); + mpc_clear(alpha); + mpc_clear(j); + + precision_clear(); + return k; +} + +void pbc_hilbert_free(mpz_t *arr, size_t n) { + size_t i; + + for (i = 0; i < n; i++) mpz_clear(arr[i]); + pbc_free(arr); +} diff --git a/moon-abe/pbc-0.5.14/ecc/mnt.c b/moon-abe/pbc-0.5.14/ecc/mnt.c new file mode 100644 index 00000000..230442fc --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/mnt.c @@ -0,0 +1,496 @@ +// Routines for finding: +// * MNT curves with embedding degree 6 +// * Freeman curves (which have embedding degree 10) + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> // for intptr_t +#include <gmp.h> +#include "pbc_mnt.h" +#include "pbc_memory.h" +#include "pbc_utils.h" +#include "misc/darray.h" + +struct pell_solution_s { + int count; + mpz_t minx; //minimal solution of x^2 - Dy^2 = 1 + mpz_t miny; + mpz_t *x; + mpz_t *y; +}; +typedef struct pell_solution_s pell_solution_t[1]; +typedef struct pell_solution_s *pell_solution_ptr; + +static void freempz(void *data) { + mpz_clear(data); + pbc_free(data); +} + +// Solves x^2 - Dy^2 = N where D not a square. +// For square D, we have (x+Dy)(x-Dy) = N so we look at the factors of N. +static void general_pell(pell_solution_t ps, mpz_t D, int N) { + // TODO: Use brute force for small D. + int i, sgnN = N > 0 ? 1 : -1; + intptr_t f, n; + + // Find square factors of N. + darray_t listf; + darray_init(listf); + + f = 1; + for (;;) { + n = f * f; + if (n > abs(N)) break; + if (!(abs(N) % n)) { + darray_append(listf, int_to_voidp(f)); + } + f++; + } + + //a0, twice_a0 don't change once initialized + //a1 is a_i every iteration + //P0, P1 become P_{i-1}, P_i every iteration + //similarly for Q0, Q1 + mpz_t a0, twice_a0, a1; + mpz_t P0, P1; + mpz_t Q0, Q1; + //variables to compute the convergents + mpz_t p0, p1, pnext; + mpz_t q0, q1, qnext; + + int d; + + darray_t listp, listq; + mpz_ptr zptr; + + mpz_init(a0); + mpz_init(twice_a0); + mpz_init(a1); + mpz_init(P0); mpz_init(P1); + mpz_init(Q0); mpz_init(Q1); + mpz_init(p0); mpz_init(p1); mpz_init(pnext); + mpz_init(q0); mpz_init(q1); mpz_init(qnext); + + darray_init(listp); + darray_init(listq); + + mpz_sqrt(a0, D); + mpz_set_ui(P0, 0); + mpz_set_ui(Q0, 1); + + mpz_set(P1, a0); + mpz_mul(Q1, a0, a0); + mpz_sub(Q1, D, Q1); + mpz_add(a1, a0, P1); + mpz_tdiv_q(a1, a1, Q1); + + mpz_add(twice_a0, a0, a0); + + mpz_set(p0, a0); + mpz_set_ui(q0, 1); + mpz_mul(p1, a0, a1); + mpz_add_ui(p1, p1, 1); + mpz_set(q1, a1); + + d = -1; + for(;;) { + if (d == sgnN) { + for (i=0; i<listf->count; i++) { + f = (intptr_t) listf->item[i]; + if (!mpz_cmp_ui(Q1, abs(N) / (f * f))) { +//element_printf("found %Zd, %Zd, %d\n", p0, q0, f); + zptr = (mpz_ptr) pbc_malloc(sizeof(mpz_t)); + mpz_init(zptr); + mpz_set(zptr, p0); + mpz_mul_ui(zptr, p0, f); + darray_append(listp, zptr); + zptr = (mpz_ptr) pbc_malloc(sizeof(mpz_t)); + mpz_init(zptr); + mpz_set(zptr, q0); + mpz_mul_ui(zptr, q0, f); + darray_append(listq, zptr); + } + } + } + + if (!mpz_cmp(twice_a0, a1) && d == 1) break; + //compute more of the continued fraction expansion + mpz_set(P0, P1); + mpz_mul(P1, a1, Q1); + mpz_sub(P1, P1, P0); + mpz_set(Q0, Q1); + mpz_mul(Q1, P1, P1); + mpz_sub(Q1, D, Q1); + mpz_divexact(Q1, Q1, Q0); + mpz_add(a1, a0, P1); + mpz_tdiv_q(a1, a1, Q1); + + //compute next convergent + mpz_mul(pnext, a1, p1); + mpz_add(pnext, pnext, p0); + mpz_set(p0, p1); + mpz_set(p1, pnext); + + mpz_mul(qnext, a1, q1); + mpz_add(qnext, qnext, q0); + mpz_set(q0, q1); + mpz_set(q1, qnext); + d = -d; + } + darray_clear(listf); + + mpz_init(ps->minx); + mpz_init(ps->miny); + mpz_set(ps->minx, p0); + mpz_set(ps->miny, q0); + n = listp->count; + ps->count = n; + if (n) { + ps->x = (mpz_t *) pbc_malloc(sizeof(mpz_t) * n); + ps->y = (mpz_t *) pbc_malloc(sizeof(mpz_t) * n); + for (i = 0; i < n; i++) { + mpz_init(ps->x[i]); + mpz_init(ps->y[i]); + mpz_set(ps->x[i], (mpz_ptr) listp->item[i]); + mpz_set(ps->y[i], (mpz_ptr) listq->item[i]); + } + } + + mpz_clear(a0); + mpz_clear(twice_a0); + mpz_clear(a1); + mpz_clear(P0); mpz_clear(P1); + mpz_clear(Q0); mpz_clear(Q1); + mpz_clear(p0); mpz_clear(p1); mpz_clear(pnext); + mpz_clear(q0); mpz_clear(q1); mpz_clear(qnext); + + darray_forall(listp, freempz); + darray_forall(listq, freempz); + darray_clear(listp); + darray_clear(listq); +} + +static void pell_solution_clear(pell_solution_t ps) { + int i, n = ps->count; + + if (n) { + for (i=0; i<n; i++) { + mpz_clear(ps->x[i]); + mpz_clear(ps->y[i]); + } + pbc_free(ps->x); + pbc_free(ps->y); + } + mpz_clear(ps->minx); + mpz_clear(ps->miny); +} + +void pbc_cm_init(pbc_cm_t cm) { + mpz_init(cm->q); + mpz_init(cm->r); + mpz_init(cm->h); + mpz_init(cm->n); +} + +void pbc_cm_clear(pbc_cm_t cm) { + mpz_clear(cm->q); + mpz_clear(cm->r); + mpz_clear(cm->h); + mpz_clear(cm->n); +} + +static int mnt_step2(int (*callback)(pbc_cm_t, void *), void *data, + unsigned int D, mpz_t U) { + int d; + mpz_t n, l, q; + mpz_t p; + mpz_t r, cofac; + + mpz_init(l); + mpz_mod_ui(l, U, 6); + if (!mpz_cmp_ui(l, 1)) { + mpz_sub_ui(l, U, 1); + d = 1; + } else if (!mpz_cmp_ui(l, 5)) { + mpz_add_ui(l, U, 1); + d = -1; + } else { + mpz_clear(l); + return 0; + } + + mpz_divexact_ui(l, l, 3); + mpz_init(q); + + mpz_mul(q, l, l); + mpz_add_ui(q, q, 1); + if (!mpz_probab_prime_p(q, 10)) { + mpz_clear(q); + mpz_clear(l); + return 0; + } + + mpz_init(n); + if (d < 0) { + mpz_sub(n, q, l); + } else { + mpz_add(n, q, l); + } + + mpz_init(p); + mpz_init(r); + mpz_init(cofac); + { + mpz_set_ui(cofac, 1); + mpz_set(r, n); + mpz_set_ui(p, 2); + if (!mpz_probab_prime_p(r, 10)) for(;;) { + if (mpz_divisible_p(r, p)) do { + mpz_mul(cofac, cofac, p); + mpz_divexact(r, r, p); + } while (mpz_divisible_p(r, p)); + if (mpz_probab_prime_p(r, 10)) break; + //TODO: use a table of primes instead? + mpz_nextprime(p, p); + if (mpz_sizeinbase(p, 2) > 16) { + //printf("has 16+ bit factor\n"); + mpz_clear(r); + mpz_clear(p); + mpz_clear(cofac); + mpz_clear(q); + mpz_clear(l); + mpz_clear(n); + return 0; + } + } + } + + pbc_cm_t cm; + pbc_cm_init(cm); + cm->k = 6; + cm->D = D; + mpz_set(cm->q, q); + mpz_set(cm->r, r); + mpz_set(cm->h, cofac); + mpz_set(cm->n, n); + int res = callback(cm, data); + pbc_cm_clear(cm); + + mpz_clear(cofac); + mpz_clear(r); + mpz_clear(p); + mpz_clear(q); + mpz_clear(l); + mpz_clear(n); + return res; +} + +int pbc_cm_search_d(int (*callback)(pbc_cm_t, void *), void *data, + unsigned int D, unsigned int bitlimit) { + mpz_t D3; + mpz_t t0, t1, t2; + + mpz_init(D3); + mpz_set_ui(D3, D * 3); + + if (mpz_perfect_square_p(D3)) { + // The only squares that differ by 8 are 1 and 9, + // which we get if U=V=1, D=3, but then l is not an integer. + mpz_clear(D3); + return 0; + } + + mpz_init(t0); + mpz_init(t1); + mpz_init(t2); + + pell_solution_t ps; + general_pell(ps, D3, -8); + + int i, n; + int res = 0; + n = ps->count; + if (n) for (;;) { + for (i=0; i<n; i++) { + //element_printf("%Zd, %Zd\n", ps->x[i], ps->y[i]); + res = mnt_step2(callback, data, D, ps->x[i]); + if (res) goto toobig; + //compute next solution as follows + //if p, q is current solution + //compute new solution p', q' via + //(p + q sqrt{3D})(t + u sqrt{3D}) = p' + q' sqrt(3D) + //where t, u is min. solution to Pell equation + mpz_mul(t0, ps->minx, ps->x[i]); + mpz_mul(t1, ps->miny, ps->y[i]); + mpz_mul(t1, t1, D3); + mpz_add(t0, t0, t1); + if (2 * mpz_sizeinbase(t0, 2) > bitlimit + 10) goto toobig; + mpz_mul(t2, ps->minx, ps->y[i]); + mpz_mul(t1, ps->miny, ps->x[i]); + mpz_add(t2, t2, t1); + mpz_set(ps->x[i], t0); + mpz_set(ps->y[i], t2); + } + } +toobig: + + pell_solution_clear(ps); + mpz_clear(t0); + mpz_clear(t1); + mpz_clear(t2); + mpz_clear(D3); + return res; +} + +static int freeman_step2(int (*callback)(pbc_cm_t, void *), void *data, + unsigned int D, mpz_t U) { + mpz_t n, x, q; + mpz_t p; + mpz_t r, cofac; + pbc_cm_t cm; + + mpz_init(x); + mpz_mod_ui(x, U, 15); + if (!mpz_cmp_ui(x, 5)) { + mpz_sub_ui(x, U, 5); + } else if (!mpz_cmp_ui(x, 10)) { + mpz_add_ui(x, U, 5); + } else { + pbc_die("should never reach here"); + mpz_clear(x); + return 0; + } + + mpz_divexact_ui(x, x, 15); + mpz_init(q); + mpz_init(r); + + //q = 25x^4 + 25x^3 + 25x^2 + 10x + 3 + mpz_mul(r, x, x); + mpz_add(q, x, x); + mpz_mul_ui(r, r, 5); + mpz_add(q, q, r); + mpz_mul(r, r, x); + mpz_add(q, q, r); + mpz_mul(r, r, x); + mpz_add(q, q, r); + mpz_mul_ui(q, q, 5); + mpz_add_ui(q, q, 3); + + if (!mpz_probab_prime_p(q, 10)) { + mpz_clear(q); + mpz_clear(r); + mpz_clear(x); + return 0; + } + + //t = 10x^2 + 5x + 3 + //n = q - t + 1 + mpz_init(n); + + mpz_mul_ui(n, x, 5); + mpz_mul(r, n, x); + mpz_add(r, r, r); + mpz_add(n, n, r); + mpz_sub(n, q, n); + mpz_sub_ui(n, n, 2); + + mpz_init(p); + mpz_init(cofac); + { + mpz_set_ui(cofac, 1); + mpz_set(r, n); + mpz_set_ui(p, 2); + if (!mpz_probab_prime_p(r, 10)) for(;;) { + if (mpz_divisible_p(r, p)) do { + mpz_mul(cofac, cofac, p); + mpz_divexact(r, r, p); + } while (mpz_divisible_p(r, p)); + if (mpz_probab_prime_p(r, 10)) break; + //TODO: use a table of primes instead? + mpz_nextprime(p, p); + if (mpz_sizeinbase(p, 2) > 16) { + //printf("has 16+ bit factor\n"); + mpz_clear(r); + mpz_clear(p); + mpz_clear(cofac); + mpz_clear(q); + mpz_clear(x); + mpz_clear(n); + return 0; + } + } + } + + pbc_cm_init(cm); + cm->k = 10; + cm->D = D; + mpz_set(cm->q, q); + mpz_set(cm->r, r); + mpz_set(cm->h, cofac); + mpz_set(cm->n, n); + int res = callback(cm, data); + pbc_cm_clear(cm); + + mpz_clear(cofac); + mpz_clear(r); + mpz_clear(p); + mpz_clear(q); + mpz_clear(x); + mpz_clear(n); + return res; +} + +int pbc_cm_search_g(int (*callback)(pbc_cm_t, void *), void *data, + unsigned int D, unsigned int bitlimit) { + int res = 0; + mpz_t D15; + mpz_t t0, t1, t2; + + mpz_init(D15); + mpz_set_ui(D15, D); + mpz_mul_ui(D15, D15, 15); + if (mpz_perfect_square_p(D15)) { + mpz_clear(D15); + return 0; + } + + mpz_init(t0); + mpz_init(t1); + mpz_init(t2); + + pell_solution_t ps; + general_pell(ps, D15, -20); + + int i, n; + n = ps->count; + if (n) for (;;) { + for (i=0; i<n; i++) { + res = freeman_step2(callback, data, D, ps->x[i]); + if (res) goto toobig; + // Compute next solution as follows: + // If p, q is current solution + // then compute new solution p', q' via + // (p + q sqrt{15D})(t + u sqrt{15D}) = p' + q' sqrt(15D) + // where t, u is min. solution to Pell equation + mpz_mul(t0, ps->minx, ps->x[i]); + mpz_mul(t1, ps->miny, ps->y[i]); + mpz_mul(t1, t1, D15); + mpz_add(t0, t0, t1); + if (2 * mpz_sizeinbase(t0, 2) > bitlimit + 10) goto toobig; + mpz_mul(t2, ps->minx, ps->y[i]); + mpz_mul(t1, ps->miny, ps->x[i]); + mpz_add(t2, t2, t1); + mpz_set(ps->x[i], t0); + mpz_set(ps->y[i], t2); + } + } +toobig: + + pell_solution_clear(ps); + mpz_clear(t0); + mpz_clear(t1); + mpz_clear(t2); + mpz_clear(D15); + return res; +} diff --git a/moon-abe/pbc-0.5.14/ecc/mpc.c b/moon-abe/pbc-0.5.14/ecc/mpc.c new file mode 100644 index 00000000..e5341f99 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/mpc.c @@ -0,0 +1,122 @@ +//GMP based complex floats +#include <stdio.h> +#include <gmp.h> +#include "mpc.h" + +//(a+bi)(c+di) = ac - bd + ((a+b)(c+d) - ac - bd)i +void mpc_mul(mpc_t res, mpc_t z0, mpc_t z1) +{ + mpf_t ac, bd, f0; + mpf_init(ac); + mpf_init(bd); + mpf_init(f0); + mpf_mul(ac, z0->a, z1->a); + mpf_mul(bd, z0->b, z1->b); + mpf_add(f0, z0->a, z0->b); + mpf_add(res->b, z1->a, z1->b); + mpf_mul(res->b, res->b, f0); + mpf_sub(res->b, res->b, ac); + mpf_sub(res->b, res->b, bd); + mpf_sub(res->a, ac, bd); + mpf_clear(f0); + mpf_clear(ac); + mpf_clear(bd); +} + +void mpc_mul_2exp(mpc_t res, mpc_t z, unsigned long int e) +{ + mpf_mul_2exp(res->a, z->a, e); + mpf_mul_2exp(res->b, z->b, e); +} + +//(a+bi)^2 = (a-b)(a+b) + 2abi +void mpc_sqr(mpc_t res, mpc_t z) +{ + mpf_t f0, f1; + mpf_init(f0); + mpf_init(f1); + mpf_add(f0, z->a, z->b); + mpf_sub(f1, z->a, z->b); + mpf_mul(f0, f0, f1); + mpf_mul(f1, z->a, z->b); + mpf_set(res->a, f0); + mpf_add(res->b, f1, f1); + mpf_clear(f0); + mpf_clear(f1); +} + +//1/(a+bi) = (1/(a^2 + b^2))(a-bi) +//naive. TODO: use one that is less prone to (over/under)flows/precision loss +void mpc_inv(mpc_t res, mpc_t z) +{ + mpf_t f0, f1; + mpf_init(f0); + mpf_init(f1); + mpf_mul(f0, z->a, z->a); + mpf_mul(f1, z->b, z->b); + mpf_add(f0, f0, f1); + mpf_ui_div(f0, 1, f0); + mpf_mul(res->a, z->a, f0); + mpf_neg(f0, f0); + mpf_mul(res->b, z->b, f0); + mpf_clear(f0); + mpf_clear(f1); +} + +void mpc_div(mpc_t res, mpc_t z0, mpc_t z1) +{ + mpc_t c0; + mpc_init(c0); + mpc_inv(c0, z1); + mpc_mul(res, z0, c0); + mpc_clear(c0); +} + +size_t mpc_out_str(FILE *stream, int base, size_t n_digits, mpc_t op) +{ + size_t result, status; + result = mpf_out_str(stream, base, n_digits, op->a); + if (!result) return 0; + if (mpf_sgn(op->b) >= 0) { + if (EOF == fputc('+', stream)) return 0; + result++; + } + status = mpf_out_str(stream, base, n_digits, op->b); + if (!status) return 0; + if (EOF == fputc('i', stream)) return 0; + return result + status + 1; +} + +void mpc_pow_ui(mpc_t res, mpc_t z, unsigned int n) +{ + unsigned int m; + mpc_t z0; + mpc_init(z0); + + //set m to biggest power of 2 less than n + for (m = 1; m <= n; m <<= 1); + m >>= 1; + + mpf_set_ui(z0->a, 1); + mpf_set_ui(z0->b, 0); + while (m) { + mpc_mul(z0, z0, z0); + if (m & n) { + mpc_mul(z0, z0, z); + } + m >>= 1; + } + mpc_set(res, z0); + mpc_clear(z0); +} + +void mpc_muli(mpc_t res, mpc_t z) +{ + //i(a+bi) = -b + ai + mpf_t f0; + mpf_init(f0); + mpf_neg(f0, z->b); + mpf_set(res->b, z->a); + mpf_set(res->a, f0); + mpf_clear(f0); +} diff --git a/moon-abe/pbc-0.5.14/ecc/mpc.h b/moon-abe/pbc-0.5.14/ecc/mpc.h new file mode 100644 index 00000000..3588586b --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/mpc.h @@ -0,0 +1,93 @@ +// Complex floats. +// Called mpc_t, these complex numbers are built on GMP's mpf_t type. + +// Requires: +// * stdio.h +// * gmp.h + +#ifndef __PBC_MPC_H__ +#define __PBC_MPC_H__ + +#pragma GCC visibility push(hidden) + +struct mpc_s { + mpf_t a; + mpf_t b; +}; +typedef struct mpc_s mpc_t[1]; +typedef struct mpc_s *mpc_ptr; + +static inline void mpc_init(mpc_ptr c) { + mpf_init(c->a); + mpf_init(c->b); +} + +static inline void mpc_clear(mpc_ptr c) { + mpf_clear(c->a); + mpf_clear(c->b); +} + +static inline mpf_ptr mpc_re(mpc_ptr c) { + return c->a; +} + +static inline mpf_ptr mpc_im(mpc_ptr c) { + return c->b; +} + +static inline void mpc_add(mpc_ptr res, mpc_ptr z0, mpc_ptr z1) { + mpf_add(res->a, z0->a, z1->a); + mpf_add(res->b, z0->b, z1->b); +} + +static inline void mpc_sub(mpc_ptr res, mpc_ptr z0, mpc_ptr z1) { + mpf_sub(res->a, z0->a, z1->a); + mpf_sub(res->b, z0->b, z1->b); +} + +static inline void mpc_neg(mpc_ptr res, mpc_ptr z) { + mpf_neg(res->a, z->a); + mpf_neg(res->b, z->b); +} + +static inline void mpc_conj(mpc_ptr res, mpc_ptr z) { + mpf_set(res->a, z->a); + mpf_neg(res->b, z->b); +} + +static inline void mpc_set(mpc_t res, mpc_t z) { + mpf_set(res->a, z->a); + mpf_set(res->b, z->b); +} + +static inline void mpc_set_ui(mpc_t res, unsigned long int n) { + mpf_set_ui(res->a, n); + mpf_set_ui(res->b, 0); +} + +static inline void mpc_add_ui(mpc_t res, mpc_t z, unsigned long int n) { + mpf_add_ui(res->a, z->a, n); +} + +static inline void mpc_mul_ui(mpc_t res, mpc_t z, unsigned long int n) { + mpf_mul_ui(res->a, z->a, n); + mpf_mul_ui(res->b, z->b, n); +} + +static inline void mpc_mul_mpf(mpc_t res, mpc_t z, mpf_t f) { + mpf_mul(res->a, z->a, f); + mpf_mul(res->b, z->b, f); +} + +void mpc_mul(mpc_t res, mpc_t z0, mpc_t z1); +void mpc_mul_2exp(mpc_t res, mpc_t z, unsigned long int); +void mpc_div(mpc_t res, mpc_t z0, mpc_t z1); +void mpc_muli(mpc_t res, mpc_t z); +void mpc_sqr(mpc_t res, mpc_t z); +void mpc_inv(mpc_t res, mpc_t z); +size_t mpc_out_str(FILE *stream, int base, size_t n_digits, mpc_t op); +void mpc_pow_ui(mpc_t res, mpc_t z, unsigned int n); + +#pragma GCC visibility pop + +#endif //__PBC_MPC_H__ diff --git a/moon-abe/pbc-0.5.14/ecc/pairing.c b/moon-abe/pbc-0.5.14/ecc/pairing.c new file mode 100644 index 00000000..48a9c8c6 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/pairing.c @@ -0,0 +1,283 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> // for intptr_t +#include <stdlib.h> +#include <string.h> +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_poly.h" +#include "pbc_curve.h" +#include "pbc_param.h" +#include "pbc_pairing.h" +#include "pbc_memory.h" + +static int generic_is_almost_coddh(element_ptr a, element_ptr b, + element_ptr c, element_ptr d, pairing_t pairing) { + int res = 0; + element_t t0, t1; + + element_init(t0, pairing->GT); + element_init(t1, pairing->GT); + element_pairing(t0, a, d); + element_pairing(t1, b, c); + if (!element_cmp(t0, t1)) { + res = 1; + } else { + element_mul(t0, t0, t1); + if (element_is1(t0)) res = 1; + } + element_clear(t0); + element_clear(t1); + return res; +} + +static void generic_prod_pairings(element_ptr out, element_t in1[], + element_t in2[], int n, pairing_t pairing) { + pairing->map(out, in1[0], in2[0], pairing); + element_t tmp; + element_init_same_as(tmp, out); + int i; + for(i = 1; i < n; i++) { + pairing->map(tmp, in1[i], in2[i], pairing); + element_mul(out, out, tmp); + } + element_clear(tmp); +} + +static void phi_warning(element_ptr out, element_ptr in, pairing_ptr pairing) { + UNUSED_VAR(out); + UNUSED_VAR(in); + UNUSED_VAR(pairing); + printf("Phi() not implemented for this pairing type yet!\n"); +} + +static void default_option_set(struct pairing_s *pairing, char *key, char *value) { + UNUSED_VAR(pairing); + UNUSED_VAR(key); + UNUSED_VAR(value); +} + +static void default_pp_init(pairing_pp_t p, element_ptr in1, pairing_t pairing) { + UNUSED_VAR(pairing); + p->data = (void *) in1; +} + +static void default_pp_apply(element_ptr out, element_ptr in2, pairing_pp_t p) { + p->pairing->map(out, p->data, in2, p->pairing); +} + +static void default_pp_clear(pairing_pp_t p) { + UNUSED_VAR(p); +} + +void pairing_init_pbc_param(pairing_t pairing, pbc_param_ptr p) { + pairing->option_set = default_option_set; + pairing->pp_init = default_pp_init; + pairing->pp_clear = default_pp_clear; + pairing->pp_apply = default_pp_apply; + pairing->is_almost_coddh = generic_is_almost_coddh; + pairing->phi = phi_warning; + pairing->prod_pairings = generic_prod_pairings; + p->api->init_pairing(pairing, p->data); + pairing->G1->pairing = pairing; + pairing->G2->pairing = pairing; + pairing->GT->pairing = pairing; +} + +int pairing_init_set_buf(pairing_t pairing, const char *input, size_t len) { + pbc_param_t par; + int res = pbc_param_init_set_buf(par, input, len); + if (res) { + pbc_error("error initializing pairing"); + return 1; + } + pairing_init_pbc_param(pairing, par); + pbc_param_clear(par); + return 0; +} + +int pairing_init_set_str(pairing_t pairing, const char *s) { + return pairing_init_set_buf(pairing, s, 0); +} + +void pairing_clear(pairing_t pairing) { + pairing->clear_func(pairing); +} + +// TODO: it's most likely better to add extra stuff to field_t +// so no new data structures are needed to create mulitplicative subgroups. +// Additionally the same code could be used with curve_t +// Will consider it later, especially if timings turn out bad + +static void gt_out_info(FILE *out, field_ptr f) { + gmp_fprintf(out, "roots of unity, order %Zd, ", f->order); + field_out_info(out, f->data); +} + +static void gt_from_hash(element_ptr e, void *data, int len) { + pairing_ptr pairing = e->field->pairing; + element_from_hash(e->data, data, len); + pairing->finalpow(e); +} + +static void gt_random(element_ptr e) { + pairing_ptr pairing = e->field->pairing; + element_random(e->data); + pairing->finalpow(e); +} + +// multiplicative subgroup of a field +static void mulg_field_clear(field_t f) { + UNUSED_VAR(f); +} + +static void mulg_init(element_ptr e) { + e->data = pbc_malloc(sizeof(element_t)); + field_ptr f = e->field->data; + element_init(e->data, f); + element_set1(e->data); +} + +static void mulg_clear(element_ptr e) { + element_clear(e->data); + pbc_free(e->data); +} + +static void mulg_set(element_ptr x, element_t a) { + element_set(x->data, a->data); +} + +static int mulg_cmp(element_ptr x, element_t a) { + return element_cmp(x->data, a->data); +} + +static size_t mulg_out_str(FILE *stream, int base, element_ptr e) { + return element_out_str(stream, base, e->data); +} + +static void mulg_set_multiz(element_ptr e, multiz m) { + return element_set_multiz(e->data, m); +} + +static int mulg_set_str(element_ptr e, const char *s, int base) { + return element_set_str(e->data, s, base); +} + +static int mulg_item_count(element_ptr e) { + return element_item_count(e->data); +} + +static element_ptr mulg_item(element_ptr e, int i) { + return element_item(e->data, i); +} + +static int mulg_to_bytes(unsigned char *data, element_ptr e) { + return element_to_bytes(data, e->data); +} + +static int mulg_from_bytes(element_ptr e, unsigned char *data) { + return element_from_bytes(e->data, data); +} + +static int mulg_length_in_bytes(element_ptr e) { + return element_length_in_bytes(e->data); +} + +static int mulg_snprint(char *s, size_t n, element_ptr e) { + return element_snprint(s, n, e->data); +} + +static void mulg_to_mpz(mpz_ptr z, element_ptr e) { + element_to_mpz(z, e->data); +} + +static void mulg_set1(element_t e) { + element_set1(e->data); +} + +static void mulg_mul(element_ptr x, element_t a, element_t b) { + element_mul(x->data, a->data, b->data); +} + +static void mulg_div(element_ptr x, element_t a, element_t b) { + element_div(x->data, a->data, b->data); +} + +static void mulg_invert(element_ptr x, element_t a) { + element_invert(x->data, a->data); +} + +static int mulg_is1(element_ptr x) { + return element_is1(x->data); +} + +static void mulg_pow_mpz(element_t x, element_t a, mpz_t n) { + element_pow_mpz(x->data, a->data, n); +} + +static void mulg_pp_init(element_pp_t p, element_t in) { + p->data = pbc_malloc(sizeof(element_pp_t)); + element_pp_init(p->data, in->data); +} + +static void mulg_pp_clear(element_pp_t p) { + element_pp_clear(p->data); + pbc_free(p->data); +} + +static void mulg_pp_pow(element_t out, mpz_ptr power, element_pp_t p) { + element_pp_pow(out->data, power, p->data); +} + +void pairing_GT_init(pairing_ptr pairing, field_t f) { + field_ptr gt = pairing->GT; + field_init(gt); + gt->data = f; + f->pairing = pairing; + mpz_set(gt->order, pairing->r); + gt->field_clear = mulg_field_clear; + gt->out_info = gt_out_info; + + gt->init = mulg_init; + gt->clear = mulg_clear; + gt->set = mulg_set; + gt->cmp = mulg_cmp; + + gt->out_str = mulg_out_str; + gt->set_multiz = mulg_set_multiz; + gt->set_str = mulg_set_str; + gt->to_bytes = mulg_to_bytes; + gt->from_bytes = mulg_from_bytes; + gt->length_in_bytes = mulg_length_in_bytes; + gt->fixed_length_in_bytes = f->fixed_length_in_bytes; + gt->to_mpz = mulg_to_mpz; + gt->snprint = mulg_snprint; + gt->item = mulg_item; + gt->item_count = mulg_item_count; + + // TODO: set gt->nqr to something? + // set is_sqr, sqrt to something? + + // additive notation + gt->set0 = mulg_set1; + gt->add = mulg_mul; + gt->sub = mulg_div; + gt->mul_mpz = mulg_pow_mpz; + gt->neg = mulg_invert; + gt->is0 = mulg_is1; + + // multiplicative notation + gt->set1 = mulg_set1; + gt->mul = mulg_mul; + gt->div = mulg_div; + gt->pow_mpz = mulg_pow_mpz; + gt->invert = mulg_invert; + gt->is1 = mulg_is1; + gt->pp_init = mulg_pp_init; + gt->pp_clear = mulg_pp_clear; + gt->pp_pow = mulg_pp_pow; + + gt->random = gt_random; + gt->from_hash = gt_from_hash; +} diff --git a/moon-abe/pbc-0.5.14/ecc/param.c b/moon-abe/pbc-0.5.14/ecc/param.c new file mode 100644 index 00000000..4fa25eef --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/param.c @@ -0,0 +1,220 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> // for intptr_t +#include <string.h> +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_memory.h" +#include "pbc_param.h" +#include "pbc_a_param.h" +#include "pbc_mnt.h" +#include "pbc_d_param.h" +#include "pbc_e_param.h" +#include "pbc_f_param.h" +#include "pbc_a1_param.h" +#include "pbc_g_param.h" +#include "pbc_i_param.h" + +#include "misc/symtab.h" +#include "ecc/param.h" + +// Parser that reads a bunch of strings and places them in a symbol table. +// TODO: Replace with Flex/Bison? + +enum { + token_none = 0, + token_langle, + token_langleslash, + token_rangle, + token_word, + token_eof, +}; + +struct token_s { + int type; + char *s; +}; +typedef struct token_s token_t[1]; +typedef struct token_s *token_ptr; + +// Reads next token from `input`. +// Returns 1 on reaching `end` (if not NULL) or '\0' is read, 0 otherwise. +static const char *token_get(token_t tok, const char *input, const char *end) { + char *buf; + int n = 32; + int i; + char c; + #define get() (((!end || input < end) && *input) ? (c = *input++, 0) : 1) + // Skip whitespace and comments. + for(;;) { + do { + if (get()) { + tok->type = token_eof; + return input; + } + } while (strchr(" \t\r\n", c)); + if (c == '#') { + do { + if (get()) { + tok->type = token_eof; + return input; + } + } while (c != '\n'); + } else break; + } + + tok->type = token_word; + pbc_free(tok->s); + buf = (char *) pbc_malloc(n); + i = 0; + for (;;) { + buf[i] = c; + i++; + if (i == n) { + n += 32; + buf = (char *) pbc_realloc(buf, n); + } + if (get() || strchr(" \t\r\n</>", c)) break; + } + buf[i] = 0; + tok->s = buf; + return input; + #undef get +} + +static void token_init(token_t tok) { + tok->type = token_none; + tok->s = NULL; +} + +static void token_clear(token_t tok) { + pbc_free(tok->s); +} + +static void read_symtab(symtab_t tab, const char *input, size_t limit) { + token_t tok; + const char *inputend = limit ? input + limit : NULL; + token_init(tok); + for (;;) { + input = token_get(tok, input, inputend); + if (tok->type != token_word) break; + char *key = pbc_strdup(tok->s); + input = token_get(tok, input, inputend); + if (tok->type != token_word) { + pbc_free(key); + break; + } + symtab_put(tab, pbc_strdup(tok->s), key); + pbc_free(key); + } + token_clear(tok); +} + +// These functions have hidden visibility (see header). + +void param_out_type(FILE *stream, char *s) { + fprintf(stream, "type %s\n", s); +} + +void param_out_mpz(FILE *stream, char *s, mpz_t z) { + fprintf(stream, "%s ", s); + mpz_out_str(stream, 0, z); + fprintf(stream, "\n"); +} + +void param_out_int(FILE *stream, char *s, int i) { + mpz_t z; + mpz_init(z); + + mpz_set_si(z, i); + param_out_mpz(stream, s, z); + mpz_clear(z); +} + +static const char *lookup(symtab_t tab, const char *key) { + if (!symtab_has(tab, key)) { + pbc_error("missing param: `%s'", key); + return NULL; + } + return symtab_at(tab, key); +} + +int lookup_mpz(mpz_t z, symtab_t tab, const char *key) { + const char *data = lookup(tab, key); + if (!data) { + pbc_error("missing param: `%s'", key); + return 1; + } + mpz_set_str(z, data, 0); + return 0; +} + +int lookup_int(int *n, symtab_t tab, const char *key) { + mpz_t z; + const char *data = lookup(tab, key); + if (!data) { + pbc_error("missing param: `%s'", key); + return 1; + } + mpz_init(z); + + mpz_set_str(z, data, 0); + *n = mpz_get_si(z); + mpz_clear(z); + + return 0; +} + +static int param_set_tab(pbc_param_t par, symtab_t tab) { + const char *s = lookup(tab, "type"); + + static struct { + char *s; + int (*fun)(pbc_param_ptr, symtab_t tab); + } funtab[] = { + { "a", pbc_param_init_a }, + { "d", pbc_param_init_d }, + { "e", pbc_param_init_e }, + { "f", pbc_param_init_f }, + { "g", pbc_param_init_g }, + { "a1", pbc_param_init_a1 }, + { "i", pbc_param_init_i }, + }; + + int res = 1; + if (s) { + unsigned int i; + for(i = 0; i < sizeof(funtab)/sizeof(*funtab); i++) { + if (!strcmp(s, funtab[i].s)) { + res = funtab[i].fun(par, tab); + if (res) pbc_error("bad pairing parameters"); + return res; + } + } + } + + pbc_error("unknown pairing type"); + return res; +} + +// Public functions: + +int pbc_param_init_set_str(pbc_param_t par, const char *input) { + symtab_t tab; + symtab_init(tab); + read_symtab(tab, input, 0); + int res = param_set_tab(par, tab); + symtab_forall_data(tab, pbc_free); + symtab_clear(tab); + return res; +} + +int pbc_param_init_set_buf(pbc_param_t par, const char *input, size_t len) { + symtab_t tab; + symtab_init(tab); + read_symtab(tab, input, len); + int res = param_set_tab(par, tab); + symtab_forall_data(tab, pbc_free); + symtab_clear(tab); + return res; +} diff --git a/moon-abe/pbc-0.5.14/ecc/param.h b/moon-abe/pbc-0.5.14/ecc/param.h new file mode 100644 index 00000000..36cbdd36 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/param.h @@ -0,0 +1,23 @@ +// Input/output routines common to all pairing parameters. + +// Requires: +// * param.h +// * stdio.h +// * gmp.h +#ifndef __PARAM_UTILS_H__ +#define __PARAM_UTILS_H__ + +#pragma GCC visibility push(hidden) + +void param_out_type(FILE *stream, char *s); +void param_out_mpz(FILE *stream, char *s, mpz_t z); +void param_out_int(FILE *stream, char *s, int i); +// TODO: Replace with a stdarg function, e.g. +// err = lookup("ZZi", "p", "n", "l", p->p, p->n, &p->l); +struct symtab_s; // let "include/pbc.h" not include "misc/symtab.h" +int lookup_int(int *n, struct symtab_s *tab, const char *key); +int lookup_mpz(mpz_t z, struct symtab_s *tab, const char *key); + +#pragma GCC visibility pop + +#endif //__PARAM_UTILS_H__ diff --git a/moon-abe/pbc-0.5.14/ecc/singular.c b/moon-abe/pbc-0.5.14/ecc/singular.c new file mode 100644 index 00000000..95f00410 --- /dev/null +++ b/moon-abe/pbc-0.5.14/ecc/singular.c @@ -0,0 +1,447 @@ +#include <stdarg.h> +#include <stdio.h> +#include <stdint.h> // for intptr_t +#include <stdlib.h> +#include <gmp.h> +#include "pbc_utils.h" +#include "pbc_field.h" +#include "pbc_curve.h" +#include "pbc_param.h" +#include "pbc_pairing.h" +#include "pbc_fp.h" +#include "pbc_memory.h" + +//TODO: Store as integer mod ring instead and convert at last minute? +struct point_s { + int inf_flag; + element_t x; + element_t y; +}; +typedef struct point_s *point_ptr; +typedef struct point_s point_t[1]; + +static void sn_init(element_ptr e) { + field_ptr f = e->field->data; + e->data = pbc_malloc(sizeof(point_t)); + point_ptr p = e->data; + element_init(p->x, f); + element_init(p->y, f); + p->inf_flag = 1; +} + +static void sn_clear(element_ptr e) { + point_ptr p = e->data; + element_clear(p->x); + element_clear(p->y); + pbc_free(e->data); +} + +static void sn_set0(element_ptr x) { + point_ptr p = x->data; + p->inf_flag = 1; +} + +static int sn_is0(element_ptr x) { + point_ptr p = x->data; + return p->inf_flag; +} + +//singular with node: y^2 = x^3 + x^2 +static void sn_random(element_t a) { + point_ptr p = a->data; + element_t t; + + element_init(t, p->x->field); + p->inf_flag = 0; + do { + element_random(p->x); + if (element_is0(p->x)) continue; + element_square(t, p->x); + element_add(t, t, p->x); + element_mul(t, t, p->x); + } while (!element_is_sqr(t)); + element_sqrt(p->y, t); + + element_clear(t); +} + +static inline void sn_double_no_check(point_ptr r, point_ptr p) { + element_t lambda, e0, e1; + + element_init(lambda, p->x->field); + element_init(e0, p->x->field); + element_init(e1, p->x->field); + //same point: double them + + //lambda = (3x^2 + 2x) / 2y + element_mul_si(lambda, p->x, 3); + element_set_si(e0, 2); + element_add(lambda, lambda, e0); + element_mul(lambda, lambda, p->x); + element_add(e0, p->y, p->y); + element_invert(e0, e0); + element_mul(lambda, lambda, e0); + //x1 = lambda^2 - 2x - 1 + element_add(e1, p->x, p->x); + element_square(e0, lambda); + element_sub(e0, e0, e1); + element_set_si(e1, 1); + element_sub(e0, e0, e1); + //y1 = (x - x1)lambda - y + element_sub(e1, p->x, e0); + element_mul(e1, e1, lambda); + element_sub(e1, e1, p->y); + + element_set(r->x, e0); + element_set(r->y, e1); + r->inf_flag = 0; + + element_clear(lambda); + element_clear(e0); + element_clear(e1); + return; +} + +static void sn_double(element_t c, element_t a) { + point_ptr r = c->data; + point_ptr p = a->data; + if (p->inf_flag) { + r->inf_flag = 1; + return; + } + if (element_is0(p->y)) { + r->inf_flag = 1; + return; + } + sn_double_no_check(r, p); +} + +static void sn_set(element_ptr c, element_ptr a) { + point_ptr r = c->data, p = a->data; + if (p->inf_flag) { + r->inf_flag = 1; + return; + } + r->inf_flag = 0; + element_set(r->x, p->x); + element_set(r->y, p->y); +} + +static void sn_add(element_t c, element_t a, element_t b) { + point_ptr r = c->data; + point_ptr p = a->data; + point_ptr q = b->data; + if (p->inf_flag) { + sn_set(c, b); + return; + } + if (q->inf_flag) { + sn_set(c, a); + return; + } + if (!element_cmp(p->x, q->x)) { + if (!element_cmp(p->y, q->y)) { + if (element_is0(p->y)) { + r->inf_flag = 1; + return; + } else { + sn_double_no_check(r, p); + return; + } + } + //points are inverses of each other + r->inf_flag = 1; + return; + } else { + element_t lambda, e0, e1; + + element_init(lambda, p->x->field); + element_init(e0, p->x->field); + element_init(e1, p->x->field); + + //lambda = (y2-y1)/(x2-x1) + element_sub(e0, q->x, p->x); + element_invert(e0, e0); + element_sub(lambda, q->y, p->y); + element_mul(lambda, lambda, e0); + //x3 = lambda^2 - x1 - x2 - 1 + element_square(e0, lambda); + element_sub(e0, e0, p->x); + element_sub(e0, e0, q->x); + element_set1(e1); + element_sub(e0, e0, e1); + //y3 = (x1-x3)lambda - y1 + element_sub(e1, p->x, e0); + element_mul(e1, e1, lambda); + element_sub(e1, e1, p->y); + + element_set(r->x, e0); + element_set(r->y, e1); + r->inf_flag = 0; + + element_clear(lambda); + element_clear(e0); + element_clear(e1); + } +} + +static void sn_invert(element_ptr c, element_ptr a) { + point_ptr r = c->data, p = a->data; + + if (p->inf_flag) { + r->inf_flag = 1; + return; + } + r->inf_flag = 0; + element_set(r->x, p->x); + element_neg(r->y, p->y); +} + +static void sn_field_clear(field_ptr c) { + UNUSED_VAR(c); +} + +/* TODO: Write a test program that uses these functions. + +// Nonsingular points on sn curves map to finite field elements via +// (x, y) --> (y + x)/(y - x) +// The reverse map is +// a --> (4a/(a-1)^2, 4a(a+1)/(a-1)^3) + +void sn_point_to_field(element_t out, point_ptr P) { + element_t e0, e1; + if (P->inf_flag) { + element_set1(out); + return; + } + element_init(e0, out->field); + element_init(e1, out->field); + element_add(e0, P->y, P->x); + element_sub(e1, P->y, P->x); + element_invert(e1, e1); + element_mul(out, e0, e1); + element_clear(e0); + element_clear(e1); +} + +static void sn_field_to_point(point_ptr P, element_t in) { + element_t e0, e1, e2; + + if (element_is1(in)) { + P->inf_flag = 1; + return; + } + element_init(e0, in->field); + element_init(e1, in->field); + element_init(e2, in->field); + + element_set1(e1); + element_sub(e0, in, e1); + element_invert(e0, e0); + + element_mul_si(e2, in, 4); + + element_add(P->y, in, e1); + + element_mul(e1, e0, e0); + element_mul(P->x, e1, e2); + element_mul(P->y, P->y, e2); + element_mul(P->y, P->y, e0); + element_mul(P->y, P->y, e1); + P->inf_flag = 0; + + element_clear(e0); + element_clear(e1); + element_clear(e2); +} +*/ + +static size_t sn_out_str(FILE *stream, int base, element_ptr a) { + point_ptr p = a->data; + size_t result, status; + if (p->inf_flag) { + if (EOF == fputc('O', stream)) return 0; + return 1; + } + result = element_out_str(stream, base, p->x); + if (!result) return 0; + if (EOF == fputc(' ', stream)) return 0; + status = element_out_str(stream, base, p->y); + if (!status) return 0; + return result + status + 1; +} + +void naive_generic_pow_mpz(element_ptr x, element_ptr a, mpz_ptr n); +void field_init_curve_singular_with_node(field_t c, field_t field) { + mpz_set(c->order, field->order); + c->data = (void *) field; + c->init = sn_init; + c->clear = sn_clear; + c->random = sn_random; + //c->from_x = cc_from_x; + //c->from_hash = cc_from_hash; + c->set = sn_set; + c->invert = c->neg = sn_invert; + c->square = c->doub = sn_double; + c->mul = c->add = sn_add; + c->set1 = c->set0 = sn_set0; + c->is1 = c->is0 = sn_is0; + c->mul_mpz = element_pow_mpz; + c->out_str = sn_out_str; + c->field_clear = sn_field_clear; +} + +//TODO: the following code is useless as the Tate pairing is degenerate on singular curves +static void sn_miller(element_t res, mpz_t q, element_t P, + element_ptr Qx, element_ptr Qy) { + //collate divisions + int m; + element_t v, vd; + element_t Z; + element_t a, b, c; + element_t e0, e1; + element_ptr Zx; + element_ptr Zy; + const element_ptr Px = curve_x_coord(P); + const element_ptr Py = curve_y_coord(P); + + #define do_vertical(e) \ + element_sub(e0, Qx, Zx); \ + element_mul(e, e, e0); + + //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 * (Zx + Zx + Zx + 2) + //b = 2 * Zy + //c = -(2 Zy^2 + a Zx); + #define do_tangent(e) \ + element_double(e0, Zx); \ + element_add(a, Zx, e0); \ + element_set_si(e0, 2); \ + element_add(a, a, e0); \ + element_mul(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, Qx); \ + element_mul(e1, b, Qy); \ + element_add(e0, e0, e1); \ + element_add(e0, e0, c); \ + element_mul(e, e, e0); + + //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(e) \ + element_sub(b, Px, Zx); \ + element_sub(a, Zy, Py); \ + element_mul(e0, b, Zy); \ + element_mul(c, a, Zx); \ + element_add(c, c, e0); \ + element_neg(c, c); \ + element_mul(e0, a, Qx); \ + element_mul(e1, b, Qy); \ + element_add(e0, e0, e1); \ + element_add(e0, e0, c); \ + element_mul(e, e, e0); + + element_init(a, Px->field); + element_init(b, Px->field); + element_init(c, Px->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); + m = mpz_sizeinbase(q, 2) - 2; + + while(m >= 0) { + element_mul(v, v, v); + element_mul(vd, vd, vd); + do_tangent(v); + element_double(Z, Z); + do_vertical(vd); + if (mpz_tstbit(q, m)) { + do_line(v); + element_add(Z, Z, P); + do_vertical(vd); + } + m--; + } + #undef do_tangent + #undef do_vertical + #undef do_line + + 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); +} + +struct sn_pairing_data_s { + field_t Fq, Eq; +}; +typedef struct sn_pairing_data_s sn_pairing_data_t[1]; +typedef struct sn_pairing_data_s *sn_pairing_data_ptr; + +static void sn_pairing(element_ptr out, element_ptr in1, element_ptr in2, + pairing_t pairing) { + sn_pairing_data_ptr p = pairing->data; + element_ptr Q = in2; + element_t e0; + element_t R, QR; + element_init(R, p->Eq); + element_init(QR, p->Eq); + element_random(R); + element_init(e0, out->field); + element_add(QR, Q, R); + sn_miller(out, pairing->r, in1, curve_x_coord(QR), curve_y_coord(QR)); + sn_miller(e0, pairing->r, in1, curve_x_coord(R), curve_y_coord(R)); + element_invert(e0, e0); + element_mul(out, out, e0); + //element_pow_mpz(out, out, p->tateexp); + element_clear(R); + element_clear(QR); +} + +void pairing_init_singular_with_node(pairing_t pairing, mpz_t q) { + sn_pairing_data_ptr p; + + mpz_init(pairing->r); + mpz_sub_ui(pairing->r, q, 1); + field_init_fp(pairing->Zr, pairing->r); + pairing->map = sn_pairing; + + p = pairing->data = pbc_malloc(sizeof(sn_pairing_data_t)); + field_init_fp(p->Fq, q); + field_init_curve_singular_with_node(p->Eq, p->Fq); + + //mpz_init(p->tateexp); + //mpz_sub_ui(p->tateexp, p->Fq->order, 1); + //mpz_divexact(p->tateexp, p->tateexp, pairing->r); + + pairing->G2 = pairing->G1 = p->Eq; + + pairing_GT_init(pairing, p->Fq); +} |