summaryrefslogtreecommitdiffstats
path: root/moon-abe/pbc-0.5.14/ecc
diff options
context:
space:
mode:
authorRuan HE <ruan.he@orange.com>2015-09-04 07:35:06 +0000
committerGerrit Code Review <gerrit@172.30.200.206>2015-09-04 07:35:06 +0000
commitca6aa8198d2335f8c326c3dd4d26bf5899064214 (patch)
tree6274a2d971fc0cac0896efe8583927d0190e3d20 /moon-abe/pbc-0.5.14/ecc
parent92fd2dbfb672d7b2b1cdfd5dd5cf89f7716b3e12 (diff)
parent3baeb11a8fbcfcdbc31976d421f17b85503b3ecd (diff)
Merge "init attribute-based encryption"
Diffstat (limited to 'moon-abe/pbc-0.5.14/ecc')
-rw-r--r--moon-abe/pbc-0.5.14/ecc/a_param.c2315
-rw-r--r--moon-abe/pbc-0.5.14/ecc/curve.c987
-rw-r--r--moon-abe/pbc-0.5.14/ecc/d_param.c1258
-rw-r--r--moon-abe/pbc-0.5.14/ecc/e_param.c1006
-rw-r--r--moon-abe/pbc-0.5.14/ecc/eta_T_3.c835
-rw-r--r--moon-abe/pbc-0.5.14/ecc/f_param.c599
-rw-r--r--moon-abe/pbc-0.5.14/ecc/g_param.c1435
-rw-r--r--moon-abe/pbc-0.5.14/ecc/hilbert.c539
-rw-r--r--moon-abe/pbc-0.5.14/ecc/mnt.c496
-rw-r--r--moon-abe/pbc-0.5.14/ecc/mpc.c122
-rw-r--r--moon-abe/pbc-0.5.14/ecc/mpc.h93
-rw-r--r--moon-abe/pbc-0.5.14/ecc/pairing.c283
-rw-r--r--moon-abe/pbc-0.5.14/ecc/param.c220
-rw-r--r--moon-abe/pbc-0.5.14/ecc/param.h23
-rw-r--r--moon-abe/pbc-0.5.14/ecc/singular.c447
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(&param->m, tab, "m");
+ err += lookup_int(&param->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);
+}