summaryrefslogtreecommitdiffstats
path: root/moon-abe/pbc-0.5.14/arith
diff options
context:
space:
mode:
Diffstat (limited to 'moon-abe/pbc-0.5.14/arith')
-rw-r--r--moon-abe/pbc-0.5.14/arith/dlog.c187
-rw-r--r--moon-abe/pbc-0.5.14/arith/fasterfp.c546
-rw-r--r--moon-abe/pbc-0.5.14/arith/fastfp.c382
-rw-r--r--moon-abe/pbc-0.5.14/arith/field.c889
-rw-r--r--moon-abe/pbc-0.5.14/arith/fieldquadratic.c692
-rw-r--r--moon-abe/pbc-0.5.14/arith/fp.c49
-rw-r--r--moon-abe/pbc-0.5.14/arith/init_random.c18
-rw-r--r--moon-abe/pbc-0.5.14/arith/init_random.win32.c52
-rw-r--r--moon-abe/pbc-0.5.14/arith/montfp.c596
-rw-r--r--moon-abe/pbc-0.5.14/arith/multiz.c589
-rw-r--r--moon-abe/pbc-0.5.14/arith/naivefp.c270
-rw-r--r--moon-abe/pbc-0.5.14/arith/poly.c1724
-rw-r--r--moon-abe/pbc-0.5.14/arith/random.c87
-rw-r--r--moon-abe/pbc-0.5.14/arith/ternary_extension_field.c950
-rw-r--r--moon-abe/pbc-0.5.14/arith/tinyfp.c304
-rw-r--r--moon-abe/pbc-0.5.14/arith/z.c263
16 files changed, 7598 insertions, 0 deletions
diff --git a/moon-abe/pbc-0.5.14/arith/dlog.c b/moon-abe/pbc-0.5.14/arith/dlog.c
new file mode 100644
index 00000000..f77df1b7
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/dlog.c
@@ -0,0 +1,187 @@
+// Brute force and Pollard rho discrete log algorithms.
+
+#include <stdarg.h>
+#include <stdint.h> // for intptr_t
+#include <stdio.h>
+#include <gmp.h>
+#include "pbc_utils.h"
+#include "pbc_field.h"
+#include "pbc_memory.h"
+#include "misc/darray.h"
+
+struct snapshot_s {
+ element_t a;
+ element_t b;
+ element_t snark;
+};
+typedef struct snapshot_s *snapshot_ptr;
+
+static void record(element_t asum, element_t bsum, element_t snark,
+ darray_t hole, mpz_t counter) {
+ snapshot_ptr ss = pbc_malloc(sizeof(struct snapshot_s));
+ element_init_same_as(ss->a, asum);
+ element_init_same_as(ss->b, bsum);
+ element_init_same_as(ss->snark, snark);
+ element_set(ss->a, asum);
+ element_set(ss->b, bsum);
+ element_set(ss->snark, snark);
+ darray_append(hole, ss);
+ element_printf("snark %Zd: %B\n", counter, snark);
+}
+
+// g, h in some group of order r
+// finds x such that g^x = h
+// will hang if no such x exists
+// x in some field_t that set_mpz makes sense for
+void element_dlog_brute_force(element_t x, element_t g, element_t h) {
+ element_t g0;
+ mpz_t count;
+
+ mpz_init(count);
+ element_init_same_as(g0, g);
+
+ element_set(g0, g);
+ mpz_set_ui(count, 1);
+ while (element_cmp(g0, h)) {
+ element_mul(g0, g0, g);
+//element_printf("g0^%Zd = %B\n", count, g0);
+ mpz_add_ui(count, count, 1);
+ }
+ element_set_mpz(x, count);
+ mpz_clear(count);
+ element_clear(g0);
+}
+
+// x in Z_r, g, h in some group of order r
+// finds x such that g^x = h
+void element_dlog_pollard_rho(element_t x, element_t g, element_t h) {
+// see Blake, Seroussi and Smart
+// only one snark for this implementation
+ int i, s = 20;
+ field_ptr Zr = x->field, G = g->field;
+ element_t asum;
+ element_t bsum;
+ element_t a[s];
+ element_t b[s];
+ element_t m[s];
+ element_t g0, snark;
+ darray_t hole;
+ int interval = 5;
+ mpz_t counter;
+ int found = 0;
+
+ mpz_init(counter);
+ element_init(g0, G);
+ element_init(snark, G);
+ element_init(asum, Zr);
+ element_init(bsum, Zr);
+ darray_init(hole);
+ //set up multipliers
+ for (i = 0; i < s; i++) {
+ element_init(a[i], Zr);
+ element_init(b[i], Zr);
+ element_init(m[i], G);
+ element_random(a[i]);
+ element_random(b[i]);
+ element_pow_zn(g0, g, a[i]);
+ element_pow_zn(m[i], h, b[i]);
+ element_mul(m[i], m[i], g0);
+ }
+
+ element_random(asum);
+ element_random(bsum);
+ element_pow_zn(g0, g, asum);
+ element_pow_zn(snark, h, bsum);
+ element_mul(snark, snark, g0);
+
+ record(asum, bsum, snark, hole, counter);
+ for (;;) {
+ int len = element_length_in_bytes(snark);
+ unsigned char *buf = pbc_malloc(len);
+ unsigned char hash = 0;
+
+ element_to_bytes(buf, snark);
+ for (i = 0; i < len; i++) {
+ hash += buf[i];
+ }
+ i = hash % s;
+ pbc_free(buf);
+
+ element_mul(snark, snark, m[i]);
+ element_add(asum, asum, a[i]);
+ element_add(bsum, bsum, b[i]);
+
+ for (i = 0; i < hole->count; i++) {
+ snapshot_ptr ss = hole->item[i];
+ if (!element_cmp(snark, ss->snark)) {
+ element_sub(bsum, bsum, ss->b);
+ element_sub(asum, ss->a, asum);
+ //answer is x such that x * bsum = asum
+ //complications arise if gcd(bsum, r) > 1
+ //which can happen if r is not prime
+ if (!mpz_probab_prime_p(Zr->order, 10)) {
+ mpz_t za, zb, zd, zm;
+
+ mpz_init(za);
+ mpz_init(zb);
+ mpz_init(zd);
+ mpz_init(zm);
+
+ element_to_mpz(za, asum);
+ element_to_mpz(zb, bsum);
+ mpz_gcd(zd, zb, Zr->order);
+ mpz_divexact(zm, Zr->order, zd);
+ mpz_divexact(zb, zb, zd);
+ //if zd does not divide za there is no solution
+ mpz_divexact(za, za, zd);
+ mpz_invert(zb, zb, zm);
+ mpz_mul(zb, za, zb);
+ mpz_mod(zb, zb, zm);
+ do {
+ element_pow_mpz(g0, g, zb);
+ if (!element_cmp(g0, h)) {
+ element_set_mpz(x, zb);
+ break;
+ }
+ mpz_add(zb, zb, zm);
+ mpz_sub_ui(zd, zd, 1);
+ } while (mpz_sgn(zd));
+ mpz_clear(zm);
+ mpz_clear(za);
+ mpz_clear(zb);
+ mpz_clear(zd);
+ } else {
+ element_div(x, asum, bsum);
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (found) break;
+
+ mpz_add_ui(counter, counter, 1);
+ if (mpz_tstbit(counter, interval)) {
+ record(asum, bsum, snark, hole, counter);
+ interval++;
+ }
+ }
+
+ for (i = 0; i < s; i++) {
+ element_clear(a[i]);
+ element_clear(b[i]);
+ element_clear(m[i]);
+ }
+ element_clear(g0);
+ element_clear(snark);
+ for (i = 0; i < hole->count; i++) {
+ snapshot_ptr ss = hole->item[i];
+ element_clear(ss->a);
+ element_clear(ss->b);
+ element_clear(ss->snark);
+ pbc_free(ss);
+ }
+ darray_clear(hole);
+ element_clear(asum);
+ element_clear(bsum);
+ mpz_clear(counter);
+}
diff --git a/moon-abe/pbc-0.5.14/arith/fasterfp.c b/moon-abe/pbc-0.5.14/arith/fasterfp.c
new file mode 100644
index 00000000..5ce8243a
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/fasterfp.c
@@ -0,0 +1,546 @@
+// Naive implementation of F_p.
+// It uses lowlevel GMP routines (mpn_* functions) like fastfp.c, but also
+// has a flag for the value 0, avoiding many memsets.
+//
+// I'm thinking of using the flag to also represent 1, -1,
+// but that complicates the logic even more, and I believe I need more
+// control than GMP is willing to give in order to avoid expensive
+// checks for 1, -1 everywhere.
+//
+// NOTE: does not work for moduli of the form:
+// 2^(something * 8 * sizeof(mp_limb_t))
+// See comments in add, double code.
+// (This kind of integer mod ring deserves its own implementation anyway.)
+
+#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_random.h"
+#include "pbc_fp.h"
+#include "pbc_memory.h"
+
+struct fp_field_data_s {
+ size_t limbs;
+ size_t bytes;
+ mp_limb_t *primelimbs;
+};
+typedef struct fp_field_data_s fp_field_data_t[1];
+typedef struct fp_field_data_s *fp_field_data_ptr;
+
+struct data_s {
+ int flag;
+ mp_limb_t *d;
+};
+typedef struct data_s *dataptr;
+
+static void fp_init(element_ptr e) {
+ fp_field_data_ptr p = e->field->data;
+ dataptr dp = e->data = pbc_malloc(sizeof(struct data_s));
+ dp->flag = 0;
+ dp->d = pbc_malloc(p->bytes);
+}
+
+static void fp_clear(element_ptr e) {
+ dataptr dp = e->data;
+ pbc_free(dp->d);
+ pbc_free(e->data);
+}
+
+//assumes z is nonzero
+static inline void from_mpz(element_ptr e, mpz_ptr z) {
+ fp_field_data_ptr p = e->field->data;
+ size_t count;
+ dataptr dp = e->data;
+ mpz_export(dp->d, &count, -1, sizeof(mp_limb_t), 0, 0, z);
+ memset((void *) (((unsigned char *) dp->d) + count * sizeof(mp_limb_t)),
+ 0, (p->limbs - count) * sizeof(mp_limb_t));
+}
+
+static void fp_set_mpz(element_ptr e, mpz_ptr z) {
+ dataptr dp = e->data;
+ if (!mpz_sgn(z)) {
+ dp->flag = 0;
+ } else {
+ mpz_t tmp;
+ mpz_init(tmp);
+ mpz_mod(tmp, z, e->field->order);
+ from_mpz(e, tmp);
+ mpz_clear(tmp);
+ dp->flag = 2;
+ }
+}
+
+static void fp_set_si(element_ptr e, signed long int op) {
+ dataptr dp = e->data;
+ if (!op) {
+ dp->flag = 0;
+ } else {
+ const fp_field_data_ptr p = e->field->data;
+ const size_t t = p->limbs;
+ if (op < 0) {
+ mpn_sub_1(dp->d, p->primelimbs, t, -op);
+ } else {
+ dp->d[0] = op;
+ memset(&dp->d[1], 0, sizeof(mp_limb_t) * (t - 1));
+ }
+ dp->flag = 2;
+ }
+}
+
+static void fp_to_mpz(mpz_ptr z, element_ptr e) {
+ dataptr dp = e->data;
+ if (!dp->flag) {
+ mpz_set_ui(z, 0);
+ } else {
+ fp_field_data_ptr p = e->field->data;
+ mpz_import(z, p->limbs, -1, sizeof(mp_limb_t), 0, 0, dp->d);
+ }
+}
+
+static void fp_set0(element_ptr e) {
+ dataptr dp = e->data;
+ dp->flag = 0;
+}
+
+static void fp_set1(element_ptr e) {
+ fp_field_data_ptr p = e->field->data;
+ dataptr dp = e->data;
+ dp->flag = 2;
+ memset(&dp->d[1], 0, p->bytes - sizeof(mp_limb_t));
+ dp->d[0] = 1;
+}
+
+static int fp_is1(element_ptr e) {
+ dataptr dp = e->data;
+ if (!dp->flag) return 0;
+ else {
+ fp_field_data_ptr p = e->field->data;
+ size_t i, t = p->limbs;
+ if (dp->d[0] != 1) return 0;
+ for (i = 1; i < t; i++) if (dp->d[i]) return 0;
+ return 1;
+ }
+}
+
+static int fp_is0(element_ptr e) {
+ dataptr dp = e->data;
+ return !dp->flag;
+}
+
+static size_t fp_out_str(FILE * stream, int base, element_ptr e) {
+ size_t result;
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, e);
+ result = mpz_out_str(stream, base, z);
+ mpz_clear(z);
+ return result;
+}
+
+static void fp_set(element_ptr c, element_ptr a) {
+ dataptr ad = a->data;
+ dataptr cd = c->data;
+ if (a == c) return;
+ if (!ad->flag) {
+ cd->flag = 0;
+ } else {
+ fp_field_data_ptr p = a->field->data;
+
+ //Assembly is faster here, but I don't want to stoop to that level.
+ //Instead of calling slower memcpy, wrap stuff so that GMP assembly
+ //gets called.
+ /*
+ memcpy(cd->d, ad->d, p->bytes);
+ */
+ mpz_t z1, z2;
+ z1->_mp_d = cd->d;
+ z2->_mp_d = ad->d;
+ z1->_mp_size = z1->_mp_alloc = z2->_mp_size = z2->_mp_alloc = p->limbs;
+ mpz_set(z1, z2);
+
+ cd->flag = 2;
+ }
+}
+
+static void fp_add(element_ptr c, element_ptr a, element_ptr b) {
+ dataptr ad = a->data, bd = b->data;
+
+ if (!ad->flag) {
+ fp_set(c, b);
+ } else if (!bd->flag) {
+ fp_set(c, a);
+ } else {
+ dataptr cd = c->data;
+ fp_field_data_ptr p = a->field->data;
+ const size_t t = p->limbs;
+ mp_limb_t carry;
+ carry = mpn_add_n(cd->d, ad->d, bd->d, t);
+
+ if (carry) {
+ //assumes result of following sub is not zero,
+ //i.e. modulus cannot be 2^(n * bits_per_limb)
+ mpn_sub_n(cd->d, cd->d, p->primelimbs, t);
+ cd->flag = 2;
+ } else {
+ int i = mpn_cmp(cd->d, p->primelimbs, t);
+ if (!i) {
+ cd->flag = 0;
+ } else {
+ cd->flag = 2;
+ if (i > 0) {
+ mpn_sub_n(cd->d, cd->d, p->primelimbs, t);
+ }
+ }
+ }
+ }
+}
+
+static void fp_double(element_ptr c, element_ptr a) {
+ dataptr ad = a->data, cd = c->data;
+ if (!ad->flag) {
+ cd->flag = 0;
+ } else {
+ fp_field_data_ptr p = c->field->data;
+ const size_t t = p->limbs;
+ if (mpn_lshift(cd->d, ad->d, t, 1)) {
+ cd->flag = 2;
+ //again, assumes result is not zero:
+ mpn_sub_n(cd->d, cd->d, p->primelimbs, t);
+ } else {
+ int i = mpn_cmp(cd->d, p->primelimbs, t);
+ if (!i) {
+ cd->flag = 0;
+ } else {
+ cd->flag = 2;
+ if (i > 0) {
+ mpn_sub_n(cd->d, cd->d, p->primelimbs, t);
+ }
+ }
+ }
+ }
+}
+
+static void fp_halve(element_ptr c, element_ptr a) {
+ dataptr ad = a->data, cd = c->data;
+ if (!ad->flag) {
+ cd->flag = 0;
+ } else {
+ fp_field_data_ptr p = c->field->data;
+ const size_t t = p->limbs;
+ int carry = 0;
+ mp_limb_t *alimb = ad->d;
+ mp_limb_t *climb = cd->d;
+ if (alimb[0] & 1) {
+ carry = mpn_add_n(climb, alimb, p->primelimbs, t);
+ } else fp_set(c, a);
+
+ mpn_rshift(climb, climb, t, 1);
+ if (carry) climb[t - 1] |= ((mp_limb_t) 1) << (sizeof(mp_limb_t) * 8 - 1);
+ }
+}
+
+static void fp_neg(element_ptr c, element_ptr a) {
+ dataptr ad = a->data, cd = c->data;
+ if (!ad->flag) cd->flag = 0;
+ else {
+ fp_field_data_ptr p = a->field->data;
+ mpn_sub_n(cd->d, p->primelimbs, ad->d, p->limbs);
+ cd->flag = 2;
+ }
+}
+
+static void fp_sub(element_ptr c, element_ptr a, element_ptr b) {
+ dataptr ad = a->data, bd = b->data;
+
+ if (!ad->flag) {
+ fp_neg(c, b);
+ } else if (!bd->flag) {
+ fp_set(c, a);
+ } else {
+ fp_field_data_ptr p = c->field->data;
+ size_t t = p->limbs;
+ dataptr cd = c->data;
+ int i = mpn_cmp(ad->d, bd->d, t);
+
+ if (i == 0) {
+ cd->flag = 0;
+ } else {
+ cd->flag = 2;
+ mpn_sub_n(cd->d, ad->d, bd->d, t);
+ if (i < 0) {
+ mpn_add_n(cd->d, cd->d, p->primelimbs, t);
+ }
+ }
+ }
+}
+
+static void fp_mul(element_ptr c, element_ptr a, element_ptr b) {
+ dataptr ad = a->data, bd = b->data;
+ dataptr cd = c->data;
+
+ if (!ad->flag || !bd->flag) {
+ cd->flag = 0;
+ } else {
+ fp_field_data_ptr p = c->field->data;
+ size_t t = p->limbs;
+ //mp_limb_t tmp[3 * t + 1];
+ //mp_limb_t *qp = &tmp[2 * t];
+ mp_limb_t tmp[2 * t];
+ mp_limb_t qp[t + 1];
+ //static mp_limb_t tmp[2 * 100];
+ //static mp_limb_t qp[100 + 1];
+
+ mpn_mul_n(tmp, ad->d, bd->d, t);
+
+ mpn_tdiv_qr(qp, cd->d, 0, tmp, 2 * t, p->primelimbs, t);
+ cd->flag = 2;
+ }
+}
+
+static void fp_square(element_ptr c, element_ptr a) {
+ const fp_field_data_ptr p = c->field->data;
+ mpz_t z1, z2;
+ size_t diff;
+ dataptr ad = a->data;
+ dataptr cd = c->data;
+
+ if (!ad->flag) {
+ cd->flag = 0;
+ } else {
+ cd->flag = 2;
+ z1->_mp_d = cd->d;
+ z1->_mp_size = z1->_mp_alloc = p->limbs;
+ if (c == a) {
+ mpz_powm_ui(z1, z1, 2, c->field->order);
+ } else {
+ z2->_mp_d = ad->d;
+ z2->_mp_size = z2->_mp_alloc = p->limbs;
+ mpz_powm_ui(z1, z2, 2, c->field->order);
+ }
+
+ diff = p->limbs - z1->_mp_size;
+ if (diff) memset(&z1->_mp_d[z1->_mp_size], 0, diff * sizeof(mp_limb_t));
+
+ //mpn_sqr_n() might make the code below faster than the code above
+ //but GMP doesn't expose this function
+ /*
+ const fp_field_data_ptr p = c->field->data;
+ const size_t t = p->limbs;
+ mp_limb_t tmp[2 * t];
+ mp_limb_t qp[t + 1];
+
+ mpn_mul_n(tmp, ad->d, ad->d, t);
+
+ mpn_tdiv_qr(qp, cd->d, 0, tmp, 2 * t, p->primelimbs, t);
+ */
+ }
+}
+
+static void fp_mul_si(element_ptr c, element_ptr a, signed long int op) {
+ dataptr ad = a->data;
+ dataptr cd = c->data;
+
+ if (!ad->flag || !op) {
+ cd->flag = 0;
+ } else {
+ cd->flag = 2;
+ fp_field_data_ptr p = a->field->data;
+ size_t t = p->limbs;
+ mp_limb_t tmp[t + 1];
+ mp_limb_t qp[2];
+
+ tmp[t] = mpn_mul_1(tmp, ad->d, t, labs(op));
+ mpn_tdiv_qr(qp, cd->d, 0, tmp, t + 1, p->primelimbs, t);
+ if (op < 0) { //TODO: don't need to check c != 0 this time
+ fp_neg(c, c);
+ }
+ }
+}
+
+static void fp_pow_mpz(element_ptr c, element_ptr a, mpz_ptr op) {
+ dataptr ad = a->data;
+ dataptr cd = c->data;
+ if (!ad->flag) cd->flag = 0;
+ else {
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, a);
+ mpz_powm(z, z, op, a->field->order);
+ from_mpz(c, z);
+ mpz_clear(z);
+ cd->flag = 2;
+ }
+}
+
+static void fp_invert(element_ptr c, element_ptr a) {
+ //assumes a is invertible
+ dataptr cd = c->data;
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, a);
+ mpz_invert(z, z, a->field->order);
+ from_mpz(c, z);
+ mpz_clear(z);
+ cd->flag = 2;
+}
+
+static void fp_random(element_ptr a) {
+ dataptr ad = a->data;
+ mpz_t z;
+ mpz_init(z);
+ pbc_mpz_random(z, a->field->order);
+ if (mpz_sgn(z)) {
+ from_mpz(a, z);
+ ad->flag = 2;
+ } else {
+ ad->flag = 0;
+ }
+ mpz_clear(z);
+}
+
+static void fp_from_hash(element_ptr a, void *data, int len) {
+ mpz_t z;
+
+ mpz_init(z);
+ pbc_mpz_from_hash(z, a->field->order, data, len);
+ fp_set_mpz(a, z);
+ mpz_clear(z);
+}
+
+static int fp_cmp(element_ptr a, element_ptr b) {
+ dataptr ad = a->data, bd = b->data;
+ if (!ad->flag) {
+ return bd->flag;
+ } else {
+ fp_field_data_ptr p = a->field->data;
+ return mpn_cmp(ad->d, bd->d, p->limbs);
+ //return memcmp(ad->d, bd->d, p->limbs);
+ }
+}
+
+static int fp_sgn_odd(element_ptr a) {
+ dataptr ad = a->data;
+ if (!ad->flag) return 0;
+ return ad->d[0] & 1 ? 1 : -1;
+}
+
+static int fp_sgn_even(element_ptr a) {
+ fp_field_data_ptr p = a->field->data;
+ dataptr ad = a->data;
+ if (!ad->flag) return 0;
+ mp_limb_t sum[p->limbs];
+
+ int carry = mpn_add_n(sum, ad->d, ad->d, p->limbs);
+ if (carry) return 1;
+ return mpn_cmp(sum, p->primelimbs, p->limbs);
+}
+
+
+static int fp_is_sqr(element_ptr a) {
+ dataptr ad = a->data;
+ int res;
+ mpz_t z;
+ mpz_init(z);
+ //0 is a square
+ if (!ad->flag) return 1;
+ fp_to_mpz(z, a);
+ res = mpz_legendre(z, a->field->order) == 1;
+ mpz_clear(z);
+ return res;
+}
+
+static int fp_to_bytes(unsigned char *data, element_t a) {
+ dataptr ad = a->data;
+ int n = a->field->fixed_length_in_bytes;
+ if (!ad->flag) {
+ memset(data, 0, n);
+ } else {
+ mpz_t z;
+
+ mpz_init(z);
+ fp_to_mpz(z, a);
+ pbc_mpz_out_raw_n(data, n, z);
+ mpz_clear(z);
+ }
+ return n;
+}
+
+static int fp_from_bytes(element_t a, unsigned char *data) {
+ dataptr ad = a->data;
+ int n;
+ mpz_t z;
+
+ mpz_init(z);
+
+ n = a->field->fixed_length_in_bytes;
+ mpz_import(z, n, 1, 1, 1, 0, data);
+ if (!mpz_sgn(z)) ad->flag = 0;
+ else {
+ ad->flag = 2;
+ from_mpz(a, z);
+ }
+ mpz_clear(z);
+ return n;
+}
+
+static void fp_out_info(FILE* str, field_ptr f) {
+ element_fprintf(str, "GF(%Zd): zero flag + mpn", f->order);
+}
+
+static void fp_field_clear(field_t f) {
+ fp_field_data_ptr p = f->data;
+ pbc_free(p->primelimbs);
+ pbc_free(p);
+}
+
+void field_init_faster_fp(field_ptr f, mpz_t prime) {
+ PBC_ASSERT(!mpz_fits_ulong_p(prime), "modulus too small");
+ fp_field_data_ptr p;
+ field_init(f);
+ f->init = fp_init;
+ f->clear = fp_clear;
+ f->set_si = fp_set_si;
+ f->set_mpz = fp_set_mpz;
+ f->out_str = fp_out_str;
+ f->add = fp_add;
+ f->sub = fp_sub;
+ f->set = fp_set;
+ f->mul = fp_mul;
+ f->mul_si = fp_mul_si;
+ f->square = fp_square;
+ f->doub = fp_double;
+ f->halve = fp_halve;
+ f->pow_mpz = fp_pow_mpz;
+ f->neg = fp_neg;
+ f->cmp = fp_cmp;
+ f->sign = mpz_odd_p(prime) ? fp_sgn_odd : fp_sgn_even;
+ f->invert = fp_invert;
+ f->random = fp_random;
+ f->from_hash = fp_from_hash;
+ f->is1 = fp_is1;
+ f->is0 = fp_is0;
+ f->set0 = fp_set0;
+ f->set1 = fp_set1;
+ f->is_sqr = fp_is_sqr;
+ f->sqrt = element_tonelli;
+ f->field_clear = fp_field_clear;
+ f->to_bytes = fp_to_bytes;
+ f->from_bytes = fp_from_bytes;
+ f->to_mpz = fp_to_mpz;
+
+ f->out_info = fp_out_info;
+
+ p = f->data = pbc_malloc(sizeof(fp_field_data_t));
+ p->limbs = mpz_size(prime);
+ p->bytes = p->limbs * sizeof(mp_limb_t);
+ p->primelimbs = pbc_malloc(p->bytes);
+ mpz_export(p->primelimbs, &p->limbs, -1, sizeof(mp_limb_t), 0, 0, prime);
+
+ mpz_set(f->order, prime);
+ f->fixed_length_in_bytes = (mpz_sizeinbase(prime, 2) + 7) / 8;
+}
diff --git a/moon-abe/pbc-0.5.14/arith/fastfp.c b/moon-abe/pbc-0.5.14/arith/fastfp.c
new file mode 100644
index 00000000..13c6fb87
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/fastfp.c
@@ -0,0 +1,382 @@
+// Naive implementation of F_p.
+// Uses lowlevel GMP routines (mpn_* functions).
+//
+// Within an element_t, ''data'' field of element holds pointer to array of
+// mp_limb_t, which is allocated on init and freed on clear.
+// Its size is fixed and determined by the number of limbs in the modulus.
+// This simplifies code but is inefficient for storing values like 0 and 1.
+
+#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_random.h"
+#include "pbc_fp.h"
+#include "pbc_memory.h"
+
+struct fp_field_data_s {
+ size_t limbs;
+ size_t bytes;
+ mp_limb_t *primelimbs;
+};
+typedef struct fp_field_data_s fp_field_data_t[1];
+typedef struct fp_field_data_s *fp_field_data_ptr;
+
+static void fp_init(element_ptr e) {
+ fp_field_data_ptr p = e->field->data;
+ e->data = pbc_malloc(p->bytes);
+ memset(e->data, 0, p->bytes);
+ // e->data = pbc_calloc(sizeof(mp_limb_t), p->limbs);
+}
+
+static void fp_clear(element_ptr e) {
+ pbc_free(e->data);
+}
+
+static inline void from_mpz(element_ptr e, mpz_ptr z) {
+ fp_field_data_ptr p = e->field->data;
+ size_t count;
+ mpz_export(e->data, &count, -1, sizeof(mp_limb_t), 0, 0, z);
+ memset((void *) (((unsigned char *) e->data) + count * sizeof(mp_limb_t)), 0,
+ (p->limbs - count) * sizeof(mp_limb_t));
+}
+
+static void fp_set_mpz(element_ptr e, mpz_ptr z) {
+ mpz_t tmp;
+ mpz_init(tmp);
+ mpz_mod(tmp, z, e->field->order);
+ from_mpz(e, tmp);
+ mpz_clear(tmp);
+}
+
+static void fp_set_si(element_ptr e, signed long int op) {
+ const fp_field_data_ptr p = e->field->data;
+ const size_t t = p->limbs;
+ mp_limb_t *d = e->data;
+ if (op < 0) {
+ mpn_sub_1(d, p->primelimbs, t, -op);
+ } else {
+ d[0] = op;
+ memset(&d[1], 0, sizeof(mp_limb_t) * (t - 1));
+ }
+}
+
+static void fp_to_mpz(mpz_ptr z, element_ptr a) {
+ fp_field_data_ptr p = a->field->data;
+ mpz_import(z, p->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data);
+}
+
+static void fp_set0(element_ptr e) {
+ fp_field_data_ptr p = e->field->data;
+ memset(e->data, 0, p->bytes);
+}
+
+static void fp_set1(element_ptr e) {
+ fp_field_data_ptr p = e->field->data;
+ mp_limb_t *d = e->data;
+ memset(&d[1], 0, p->bytes - sizeof(mp_limb_t));
+ d[0] = 1;
+}
+
+static int fp_is1(element_ptr e) {
+ fp_field_data_ptr p = e->field->data;
+ size_t i, t = p->limbs;
+ mp_limb_t *d = e->data;
+ if (d[0] != 1) return 0;
+ for (i = 1; i < t; i++) if (d[i]) return 0;
+ return 1;
+}
+
+static int fp_is0(element_ptr e) {
+ fp_field_data_ptr p = e->field->data;
+ size_t i, t = p->limbs;
+ mp_limb_t *d = e->data;
+ for (i = 0; i < t; i++) if (d[i]) return 0;
+ return 1;
+}
+
+static size_t fp_out_str(FILE * stream, int base, element_ptr e) {
+ size_t result;
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, e);
+ result = mpz_out_str(stream, base, z);
+ mpz_clear(z);
+ return result;
+}
+
+static void fp_add(element_ptr r, element_ptr a, element_ptr b) {
+ fp_field_data_ptr p = r->field->data;
+ const size_t t = p->limbs;
+ mp_limb_t carry;
+ carry = mpn_add_n(r->data, a->data, b->data, t);
+
+ if (carry || mpn_cmp(r->data, p->primelimbs, t) >= 0) {
+ mpn_sub_n(r->data, r->data, p->primelimbs, t);
+ }
+}
+
+static void fp_double(element_ptr r, element_ptr a) {
+ fp_field_data_ptr p = r->field->data;
+ const size_t t = p->limbs;
+ if (mpn_lshift(r->data, a->data, t, 1)
+ || mpn_cmp(r->data, p->primelimbs, t) >= 0) {
+ mpn_sub_n(r->data, r->data, p->primelimbs, t);
+ }
+}
+
+static void fp_set(element_ptr c, element_ptr a) {
+ fp_field_data_ptr p = a->field->data;
+ if (c == a) return;
+
+ // Assembly is faster here, but I don't want to stoop to that level.
+ // Instead of calling slower memcpy, wrap stuff so that GMP assembly
+ // gets called.
+ /*
+ memcpy(c->data, a->data, p->bytes);
+ */
+ mpz_t z1, z2;
+ z1->_mp_d = c->data;
+ z2->_mp_d = a->data;
+ z1->_mp_size = z1->_mp_alloc = z2->_mp_size = z2->_mp_alloc = p->limbs;
+ mpz_set(z1, z2);
+}
+
+static void fp_halve(element_ptr r, element_ptr a) {
+ fp_field_data_ptr p = r->field->data;
+ const size_t t = p->limbs;
+ int carry = 0;
+ mp_limb_t *alimb = a->data;
+ mp_limb_t *rlimb = r->data;
+ if (alimb[0] & 1) carry = mpn_add_n(rlimb, alimb, p->primelimbs, t);
+ else fp_set(r, a);
+
+ mpn_rshift(rlimb, rlimb, t, 1);
+ if (carry) rlimb[t - 1] |= ((mp_limb_t) 1) << (sizeof(mp_limb_t) * 8 - 1);
+}
+
+static void fp_sub(element_ptr r, element_ptr a, element_ptr b) {
+ fp_field_data_ptr p = r->field->data;
+ size_t t = p->limbs;
+ if (mpn_sub_n(r->data, a->data, b->data, t)) {
+ mpn_add_n(r->data, r->data, p->primelimbs, t);
+ }
+}
+
+static void fp_mul(element_ptr c, element_ptr a, element_ptr b) {
+ fp_field_data_ptr p = c->field->data;
+ size_t t = p->limbs;
+ //mp_limb_t tmp[3 * t + 1];
+ //mp_limb_t *qp = &tmp[2 * t];
+ mp_limb_t tmp[2 * t];
+ mp_limb_t qp[t + 1];
+ //static mp_limb_t tmp[2 * 100];
+ //static mp_limb_t qp[100 + 1];
+
+ mpn_mul_n(tmp, a->data, b->data, t);
+
+ mpn_tdiv_qr(qp, c->data, 0, tmp, 2 * t, p->primelimbs, t);
+}
+
+static void fp_square(element_ptr c, element_ptr a) {
+ const fp_field_data_ptr r = c->field->data;
+ mpz_t z1, z2;
+ size_t diff;
+
+ z1->_mp_d = c->data;
+ z1->_mp_size = z1->_mp_alloc = r->limbs;
+ if (c == a) {
+ mpz_powm_ui(z1, z1, 2, c->field->order);
+ } else {
+ z2->_mp_d = a->data;
+ z2->_mp_size = z2->_mp_alloc = r->limbs;
+ mpz_powm_ui(z1, z2, 2, c->field->order);
+ }
+
+ diff = r->limbs - z1->_mp_size;
+ if (diff) memset(&z1->_mp_d[z1->_mp_size], 0, diff * sizeof(mp_limb_t));
+
+ //mpn_sqr_n() might make the code below faster than the code above
+ //but GMP doesn't expose this function
+ /*
+ const fp_field_data_ptr r = c->field->data;
+ const size_t t = r->limbs;
+ mp_limb_t tmp[2 * t];
+ mp_limb_t qp[t + 1];
+
+ mpn_mul_n(tmp, a->data, a->data, t);
+
+ mpn_tdiv_qr(qp, c->data, 0, tmp, 2 * t, r->primelimbs, t);
+ */
+}
+
+static void fp_neg(element_ptr n, element_ptr a) {
+ if (fp_is0(a)) {
+ fp_set0(n);
+ } else {
+ fp_field_data_ptr p = a->field->data;
+ mpn_sub_n(n->data, p->primelimbs, a->data, p->limbs);
+ }
+}
+
+static void fp_mul_si(element_ptr e, element_ptr a, signed long int op) {
+ fp_field_data_ptr p = e->field->data;
+ size_t t = p->limbs;
+ mp_limb_t tmp[t + 1];
+ mp_limb_t qp[2];
+
+ tmp[t] = mpn_mul_1(tmp, a->data, t, labs(op));
+ mpn_tdiv_qr(qp, e->data, 0, tmp, t + 1, p->primelimbs, t);
+ if (op < 0) {
+ fp_neg(e, e);
+ }
+}
+
+static void fp_pow_mpz(element_ptr c, element_ptr a, mpz_ptr op) {
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, a);
+ mpz_powm(z, z, op, c->field->order);
+ from_mpz(c, z);
+ mpz_clear(z);
+}
+
+static void fp_invert(element_ptr e, element_ptr a) {
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, a);
+ mpz_invert(z, z, e->field->order);
+ from_mpz(e, z);
+ mpz_clear(z);
+}
+
+static void fp_random(element_ptr a) {
+ mpz_t z;
+ mpz_init(z);
+ pbc_mpz_random(z, a->field->order);
+ from_mpz(a, z);
+ mpz_clear(z);
+}
+
+static void fp_from_hash(element_ptr a, void *data, int len) {
+ mpz_t z;
+
+ mpz_init(z);
+ pbc_mpz_from_hash(z, a->field->order, data, len);
+ fp_set_mpz(a, z);
+ mpz_clear(z);
+}
+
+static int fp_cmp(element_ptr a, element_ptr b) {
+ fp_field_data_ptr p = a->field->data;
+ return mpn_cmp(a->data, b->data, p->limbs);
+ //return memcmp(a->data, b->data, p->limbs);
+}
+
+static int fp_sgn_odd(element_ptr a) {
+ if (fp_is0(a)) return 0;
+ mp_limb_t *lp = a->data;
+ return lp[0] & 1 ? 1 : -1;
+}
+
+static int fp_sgn_even(element_ptr a) {
+ fp_field_data_ptr p = a->field->data;
+ if (fp_is0(a)) return 0;
+ mp_limb_t sum[p->limbs];
+
+ int carry = mpn_add_n(sum, a->data, a->data, p->limbs);
+ if (carry) return 1;
+ return mpn_cmp(sum, p->primelimbs, p->limbs);
+}
+
+static int fp_is_sqr(element_ptr a) {
+ int res;
+ mpz_t z;
+ mpz_init(z);
+ //0 is a square
+ if (fp_is0(a)) return 1;
+ fp_to_mpz(z, a);
+ res = mpz_legendre(z, a->field->order) == 1;
+ mpz_clear(z);
+ return res;
+}
+
+static int fp_to_bytes(unsigned char *data, element_t e) {
+ mpz_t z;
+ int n;
+
+ mpz_init(z);
+ fp_to_mpz(z, e);
+ n = e->field->fixed_length_in_bytes;
+ pbc_mpz_out_raw_n(data, n, z);
+ mpz_clear(z);
+ return n;
+}
+
+static int fp_from_bytes(element_t e, unsigned char *data) {
+ int n;
+ mpz_t z;
+
+ mpz_init(z);
+
+ n = e->field->fixed_length_in_bytes;
+ mpz_import(z, n, 1, 1, 1, 0, data);
+ fp_set_mpz(e, z);
+ mpz_clear(z);
+ return n;
+}
+
+static void fp_field_clear(field_t f) {
+ fp_field_data_ptr p = f->data;
+ pbc_free(p->primelimbs);
+ pbc_free(p);
+}
+
+void field_init_fast_fp(field_ptr f, mpz_t prime) {
+ PBC_ASSERT(!mpz_fits_ulong_p(prime), "modulus too small");
+ fp_field_data_ptr p;
+ field_init(f);
+ f->init = fp_init;
+ f->clear = fp_clear;
+ f->set_si = fp_set_si;
+ f->set_mpz = fp_set_mpz;
+ f->out_str = fp_out_str;
+ f->add = fp_add;
+ f->sub = fp_sub;
+ f->set = fp_set;
+ f->mul = fp_mul;
+ f->mul_si = fp_mul_si;
+ f->square = fp_square;
+ f->doub = fp_double;
+ f->halve = fp_halve;
+ f->pow_mpz = fp_pow_mpz;
+ f->neg = fp_neg;
+ f->cmp = fp_cmp;
+ f->sign = mpz_odd_p(prime) ? fp_sgn_odd : fp_sgn_even;
+ f->invert = fp_invert;
+ f->random = fp_random;
+ f->from_hash = fp_from_hash;
+ f->is1 = fp_is1;
+ f->is0 = fp_is0;
+ f->set0 = fp_set0;
+ f->set1 = fp_set1;
+ f->is_sqr = fp_is_sqr;
+ f->sqrt = element_tonelli;
+ f->field_clear = fp_field_clear;
+ f->to_bytes = fp_to_bytes;
+ f->from_bytes = fp_from_bytes;
+ f->to_mpz = fp_to_mpz;
+
+ p = f->data = pbc_malloc(sizeof(fp_field_data_t));
+ p->limbs = mpz_size(prime);
+ p->bytes = p->limbs * sizeof(mp_limb_t);
+ p->primelimbs = pbc_malloc(p->bytes);
+ mpz_export(p->primelimbs, &p->limbs, -1, sizeof(mp_limb_t), 0, 0, prime);
+
+ mpz_set(f->order, prime);
+ f->fixed_length_in_bytes = (mpz_sizeinbase(prime, 2) + 7) / 8;
+}
diff --git a/moon-abe/pbc-0.5.14/arith/field.c b/moon-abe/pbc-0.5.14/arith/field.c
new file mode 100644
index 00000000..af94e37f
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/field.c
@@ -0,0 +1,889 @@
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdint.h> // for intptr_t
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // for memcmp()
+#include <gmp.h>
+#include "pbc_utils.h"
+#include "pbc_field.h"
+#include "pbc_multiz.h"
+#include "pbc_memory.h"
+
+// returns recommended window size. n is exponent.
+static int optimal_pow_window_size(mpz_ptr n) {
+ int exp_bits;
+
+ exp_bits = mpz_sizeinbase(n, 2);
+
+ // try to minimize 2^k + n/(k+1).
+ return exp_bits > 9065 ? 8 :
+ exp_bits > 3529 ? 7 :
+ exp_bits > 1324 ? 6 :
+ exp_bits > 474 ? 5 :
+ exp_bits > 157 ? 4 :
+ exp_bits > 47 ? 3 :
+ 2;
+}
+
+/* builds k-bit lookup window for base a */
+static element_t *build_pow_window(element_ptr a, int k) {
+ int s;
+ int lookup_size;
+ element_t *lookup;
+
+ if (k < 1) return NULL; // no window
+
+ /* build 2^k lookup table. lookup[i] = x^i. */
+ /* TODO: a more careful word-finding algorithm would allow
+ * us to avoid calculating even lookup entries > 2
+ */
+ lookup_size = 1 << k;
+ lookup = pbc_malloc(lookup_size * sizeof(element_t));
+ element_init(lookup[0], a->field);
+ element_set1(lookup[0]);
+ for (s = 1; s < lookup_size; s++) {
+ element_init(lookup[s], a->field);
+ element_mul(lookup[s], lookup[s - 1], a);
+ }
+
+ return lookup;
+}
+
+static void clear_pow_window(int k, element_t * lookup) {
+ int s;
+ int lookup_size = 1 << k;
+
+ for (s = 0; s < lookup_size; s++) {
+ element_clear(lookup[s]);
+ }
+ pbc_free(lookup);
+}
+
+/*
+ * left-to-right exponentiation with k-bit window.
+ * NB. must have k >= 1.
+ */
+static void element_pow_wind(element_ptr x, mpz_ptr n,
+ int k, element_t * a_lookup) {
+ int s;
+ int bit;
+
+ int inword; // boolean: currently reading word?
+ int word = 0; // the word to look up. 0<word<base
+ int wbits = 0; // # of bits so far in word. wbits<=k.
+
+ element_t result;
+
+ // early abort if raising to power 0
+ if (!mpz_sgn(n)) {
+ element_set1(x);
+ return;
+ }
+
+ element_init(result, x->field);
+ element_set1(result);
+
+ for (inword = 0, s = mpz_sizeinbase(n, 2) - 1; s >= 0; s--) {
+ element_square(result, result);
+ bit = mpz_tstbit(n, s);
+
+ if (!inword && !bit)
+ continue; // keep scanning. note continue.
+
+ if (!inword) { // was scanning, just found word
+ inword = 1; // so, start new word
+ word = 1;
+ wbits = 1;
+ } else {
+ word = (word << 1) + bit;
+ wbits++; // continue word
+ }
+
+ if (wbits == k || s == 0) {
+ element_mul(result, result, a_lookup[word]);
+ inword = 0;
+ }
+ }
+
+ element_set(x, result);
+ element_clear(result);
+}
+
+static void generic_pow_mpz(element_ptr x, element_ptr a, mpz_ptr n) {
+ int k;
+ element_t *a_lookup;
+
+ if (mpz_is0(n)) {
+ element_set1(x);
+ return;
+ }
+
+ k = optimal_pow_window_size(n);
+ a_lookup = build_pow_window(a, k);
+ element_pow_wind(x, n, k, a_lookup);
+ clear_pow_window(k, a_lookup);
+}
+
+/* TODO: Allow fields to choose this exponentiation routine so we can compare.
+static void naive_generic_pow_mpz(element_ptr x, element_ptr a, mpz_ptr n) {
+ int s;
+
+ element_t result;
+
+ if (mpz_is0(n)) {
+ element_set1(x);
+ return;
+ }
+
+ element_init(result, x->field);
+ element_set1(result);
+
+ for (s = mpz_sizeinbase(n, 2) - 1; s >= 0; s--) {
+ element_square(result, result);
+ if (mpz_tstbit(n, s)) {
+ element_mul(result, result, a);
+ }
+ }
+ element_set(x, result);
+ element_clear(result);
+}
+*/
+
+void element_pow2_mpz(element_ptr x, element_ptr a1, mpz_ptr n1,
+ element_ptr a2, mpz_ptr n2) {
+ int s, s1, s2;
+ int b1, b2;
+
+ element_t result, a1a2;
+
+ if (mpz_is0(n1) && mpz_is0(n2)) {
+ element_set1(x);
+ return;
+ }
+
+ element_init(result, x->field);
+ element_set1(result);
+
+ element_init(a1a2, x->field);
+ element_mul(a1a2, a1, a2);
+
+ s1 = mpz_sizeinbase(n1, 2) - 1;
+ s2 = mpz_sizeinbase(n2, 2) - 1;
+ for (s = (s1 > s2) ? s1 : s2; s >= 0; s--) {
+ element_mul(result, result, result);
+ b1 = mpz_tstbit(n1, s);
+ b2 = mpz_tstbit(n2, s);
+ if (b1 && b2) {
+ element_mul(result, result, a1a2);
+ } else if (b1) {
+ element_mul(result, result, a1);
+ } else if (b2) {
+ element_mul(result, result, a2);
+ }
+ }
+
+ element_set(x, result);
+ element_clear(result);
+ element_clear(a1a2);
+}
+
+void element_pow3_mpz(element_ptr x, element_ptr a1, mpz_ptr n1,
+ element_ptr a2, mpz_ptr n2,
+ element_ptr a3, mpz_ptr n3) {
+ int s, s1, s2, s3;
+ int b;
+ int i;
+
+ element_t result;
+ element_t lookup[8];
+
+ if (mpz_is0(n1) && mpz_is0(n2) && mpz_is0(n3)) {
+ element_set1(x);
+ return;
+ }
+
+ element_init(result, x->field);
+ element_set1(result);
+
+ for (i = 0; i < 8; i++)
+ element_init(lookup[i], x->field);
+
+ // build lookup table.
+ element_set1(lookup[0]);
+ element_set(lookup[1], a1);
+ element_set(lookup[2], a2);
+ element_set(lookup[4], a3);
+ element_mul(lookup[3], a1, a2);
+ element_mul(lookup[5], a1, a3);
+ element_mul(lookup[6], a2, a3);
+ element_mul(lookup[7], lookup[6], a1);
+
+ // calculate largest exponent bitsize
+ s1 = mpz_sizeinbase(n1, 2) - 1;
+ s2 = mpz_sizeinbase(n2, 2) - 1;
+ s3 = mpz_sizeinbase(n3, 2) - 1;
+ s = (s1 > s2) ? ((s1 > s3) ? s1 : s3)
+ : ((s2 > s3) ? s2 : s3);
+
+ for (; s >= 0; s--) {
+ element_mul(result, result, result);
+ b = (mpz_tstbit(n1, s))
+ + (mpz_tstbit(n2, s) << 1)
+ + (mpz_tstbit(n3, s) << 2);
+ element_mul(result, result, lookup[b]);
+ }
+
+ element_set(x, result);
+ element_clear(result);
+ for (i = 0; i < 8; i++)
+ element_clear(lookup[i]);
+}
+
+struct element_base_table {
+ int k;
+ int bits;
+ int num_lookups;
+ element_t **table;
+};
+
+/* build k-bit base table for n-bit exponentiation w/ base a */
+static void *element_build_base_table(element_ptr a, int bits, int k) {
+ struct element_base_table *base_table;
+ element_t multiplier;
+ int i, j;
+ int lookup_size;
+
+ element_t *lookup;
+
+ // pbc_info("building %d bits %d k", bits, k);
+ lookup_size = 1 << k;
+
+ base_table = pbc_malloc(sizeof(struct element_base_table));
+ base_table->num_lookups = bits / k + 1;
+ base_table->k = k;
+ base_table->bits = bits;
+ base_table->table =
+ pbc_malloc(base_table->num_lookups * sizeof(element_t *));
+
+ element_init(multiplier, a->field);
+ element_set(multiplier, a);
+
+ for (i = 0; i < base_table->num_lookups; i++) {
+ lookup = pbc_malloc(lookup_size * sizeof(element_t));
+ element_init(lookup[0], a->field);
+ element_set1(lookup[0]);
+ for (j = 1; j < lookup_size; j++) {
+ element_init(lookup[j], a->field);
+ element_mul(lookup[j], multiplier, lookup[j - 1]);
+ }
+ element_mul(multiplier, multiplier, lookup[lookup_size - 1]);
+ base_table->table[i] = lookup;
+ }
+
+ element_clear(multiplier);
+ return base_table;
+}
+
+/*
+ * exponentiation using aggressive base lookup table
+ * must have k >= 1.
+ */
+static void element_pow_base_table(element_ptr x, mpz_ptr power,
+ struct element_base_table *base_table) {
+ int word; /* the word to look up. 0<word<base */
+ int row, s; /* row and col in base table */
+ int num_lookups;
+
+ element_t result;
+ mpz_t n;
+ mpz_init_set(n, power);
+
+ // Early abort if raising to power 0.
+ if (!mpz_sgn(n)) {
+ element_set1(x);
+ return;
+ }
+ if (mpz_cmp(n, x->field->order) > 0) {
+ mpz_mod(n, n, x->field->order);
+ }
+
+ element_init(result, x->field);
+ element_set1(result);
+
+ num_lookups = mpz_sizeinbase(n, 2) / base_table->k + 1;
+
+ for (row = 0; row < num_lookups; row++) {
+ word = 0;
+ for (s = 0; s < base_table->k; s++) {
+ word |= mpz_tstbit(n, base_table->k * row + s) << s;
+ }
+ if (word > 0) {
+ element_mul(result, result, base_table->table[row][word]);
+ }
+ }
+
+ element_set(x, result);
+ element_clear(result);
+ mpz_clear(n);
+}
+
+static void default_element_pp_init(element_pp_t p, element_t in) {
+ p->data =
+ element_build_base_table(in, mpz_sizeinbase(in->field->order, 2), 5);
+}
+
+static void default_element_pp_pow(element_t out, mpz_ptr power, element_pp_t p) {
+ element_pow_base_table(out, power, p->data);
+}
+
+static void default_element_pp_clear(element_pp_t p) {
+ struct element_base_table *base_table = p->data;
+ int lookup_size = 1 << base_table->k;
+ element_t *lookup;
+ int i, j;
+
+ element_t **epp = base_table->table;
+
+ for (i = 0; i < base_table->num_lookups; i++) {
+ lookup = epp[i];
+ for (j = 0; j < lookup_size; j++) {
+ element_clear(lookup[j]);
+ }
+ pbc_free(lookup);
+ }
+ pbc_free(epp);
+
+ pbc_free(base_table);
+}
+
+void field_set_nqr(field_ptr f, element_t nqr) {
+ if (!f->nqr) {
+ f->nqr = pbc_malloc(sizeof(element_t));
+ element_init(f->nqr, f);
+ }
+ element_set(f->nqr, nqr);
+}
+
+void field_gen_nqr(field_ptr f) {
+ f->nqr = pbc_malloc(sizeof(element_t));
+ element_init(f->nqr, f);
+ do {
+ element_random(f->nqr);
+ } while (element_is_sqr(f->nqr));
+}
+
+element_ptr field_get_nqr(field_ptr f) {
+ if (!f->nqr) field_gen_nqr(f);
+ return f->nqr;
+}
+
+static void generic_square(element_ptr r, element_ptr a) {
+ element_mul(r, a, a);
+}
+static void generic_mul_mpz(element_ptr r, element_ptr a, mpz_ptr z) {
+ element_t e0;
+ element_init(e0, r->field);
+ element_set_mpz(e0, z);
+ element_mul(r, a, e0);
+ element_clear(e0);
+}
+
+static void generic_mul_si(element_ptr r, element_ptr a, signed long int n) {
+ element_t e0;
+ element_init(e0, r->field);
+ element_set_si(e0, n);
+ element_mul(r, a, e0);
+ element_clear(e0);
+}
+
+static void generic_double(element_ptr r, element_ptr a) {
+ element_add(r, a, a);
+}
+
+static void generic_halve(element_ptr r, element_ptr a) {
+ element_t e0;
+ element_init(e0, r->field);
+ element_set_si(e0, 2);
+ element_invert(e0, e0);
+ element_mul(r, a, e0);
+ element_clear(e0);
+}
+
+static void zero_to_mpz(mpz_t z, element_ptr a) {
+ UNUSED_VAR(a);
+ mpz_set_ui(z, 0);
+}
+
+static void zero_set_mpz(element_ptr a, mpz_t z) {
+ UNUSED_VAR(z);
+ element_set0(a);
+}
+
+static void zero_random(element_ptr a) {
+ element_set0(a);
+}
+
+static void generic_set_si(element_ptr a, long int si) {
+ mpz_t z;
+ mpz_init(z);
+ mpz_set_si(z, si);
+ element_set_mpz(a, z);
+ mpz_clear(z);
+}
+
+static void generic_set_multiz(element_ptr a, multiz m) {
+ mpz_t z;
+ mpz_init(z);
+ multiz_to_mpz(z, m);
+ element_set_mpz(a, z);
+ mpz_clear(z);
+}
+
+static void generic_sub(element_ptr c, element_ptr a, element_ptr b) {
+ if (c != a) {
+ element_neg(c, b);
+ element_add(c, c, a);
+ } else {
+ element_t tmp;
+ element_init(tmp, a->field);
+ element_neg(tmp, b);
+ element_add(c, tmp, a);
+ element_clear(tmp);
+ }
+}
+
+static void generic_div(element_ptr c, element_ptr a, element_ptr b) {
+ if (c != a) {
+ element_invert(c, b);
+ element_mul(c, c, a);
+ } else {
+ element_t tmp;
+ element_init(tmp, a->field);
+ element_invert(tmp, b);
+ element_mul(c, tmp, a);
+ element_clear(tmp);
+ }
+}
+
+static void generic_add_ui(element_ptr c, element_ptr a,
+ unsigned long int b) {
+ element_t e;
+ mpz_t z;
+ element_init(e, c->field);
+ mpz_init(z);
+ mpz_set_ui(z, b);
+ element_set_mpz(e, z);
+ element_add(c, a, e);
+ mpz_clear(z);
+ element_clear(e);
+}
+
+static int generic_cmp(element_ptr a, element_ptr b) {
+ int result;
+ unsigned char *buf1, *buf2;
+ int len;
+ if (a == b) return 0;
+ len = element_length_in_bytes(a);
+ if (len != element_length_in_bytes(b)) return 1;
+ buf1 = pbc_malloc(len);
+ buf2 = pbc_malloc(len);
+ element_to_bytes(buf1, a);
+ element_to_bytes(buf2, b);
+ result = memcmp(buf1, buf2, len);
+ pbc_free(buf1);
+ pbc_free(buf2);
+ return result;
+}
+
+static int generic_is0(element_ptr a) {
+ int result;
+ element_t b;
+ element_init(b, a->field);
+ result = !element_cmp(a, b); // element_cmp returns 0 if 'a' and 'b' are the same, nonzero otherwise. generic_is0 returns true if 'a' is 0.
+ element_clear(b);
+ return result;
+}
+
+static int generic_is1(element_ptr a) {
+ int result;
+ element_t b;
+ element_init(b, a->field);
+ element_set1(b);
+ result = !element_cmp(a, b); // element_cmp returns 0 if 'a' and 'b' are the same, nonzero otherwise. generic_is1 returns true if 'a' is 1.
+ element_clear(b);
+ return result;
+}
+
+static void generic_out_info(FILE * out, field_ptr f) {
+ element_fprintf(out, "unknown field %p, order = %Zd", f, f->order);
+}
+
+static int generic_item_count(element_ptr e) {
+ UNUSED_VAR(e);
+ return 0;
+}
+
+static element_ptr generic_item(element_ptr e, int i) {
+ UNUSED_VAR(e);
+ UNUSED_VAR(i);
+ return NULL;
+}
+
+static element_ptr generic_get_x(element_ptr e) {
+ return element_item(e, 0);
+}
+
+static element_ptr generic_get_y(element_ptr e) {
+ return element_item(e, 1);
+}
+
+static int default_element_snprint(char *s, size_t n, element_t e) {
+ UNUSED_VAR(e);
+ if (n == 1) {
+ s[0] = '0';
+ } else if (n >= 2) {
+ s[0] = '?';
+ s[1] = '\0';
+ }
+ return 1;
+}
+
+static int default_element_set_str(element_t e, const char *s, int base) {
+ UNUSED_VAR(s);
+ UNUSED_VAR(base);
+ element_set0(e);
+ return 0;
+}
+
+static void warn_field_clear(field_ptr f) {
+ pbc_warn("field %p has no clear function", f);
+}
+
+void field_out_info(FILE* out, field_ptr f) {
+ f->out_info(out, f);
+}
+
+void field_init(field_ptr f) {
+ // should be called by each field_init_*
+ f->nqr = NULL;
+ mpz_init(f->order);
+
+ // this should later be set
+ f->field_clear = warn_field_clear;
+
+ // and this to something more helpful
+ f->out_info = generic_out_info;
+
+ // many of these can usually be optimized for particular fields
+ // provided for developer's convenience
+ f->halve = generic_halve;
+ f->doub = generic_double;
+ f->square = generic_square;
+ f->mul_mpz = generic_mul_mpz;
+ f->mul_si = generic_mul_si;
+ f->cmp = generic_cmp;
+ f->sub = generic_sub;
+ f->div = generic_div;
+ f->add_ui = generic_add_ui;
+
+ // default: converts all elements to integer 0
+ // reads all integers as 0
+ // random always outputs 0
+ f->to_mpz = zero_to_mpz;
+ f->set_mpz = zero_set_mpz;
+ f->set_multiz = generic_set_multiz;
+ f->random = zero_random;
+ f->set_si = generic_set_si;
+ f->is1 = generic_is1;
+ f->is0 = generic_is0;
+
+ // By default, an element has no components.
+ f->item_count = generic_item_count;
+ f->item = generic_item;
+ f->get_x = generic_get_x;
+ f->get_y = generic_get_y;
+
+ // these are fast, thanks to Hovav
+ f->pow_mpz = generic_pow_mpz;
+ f->pp_init = default_element_pp_init;
+ f->pp_clear = default_element_pp_clear;
+ f->pp_pow = default_element_pp_pow;
+
+ f->snprint = default_element_snprint;
+ f->set_str = default_element_set_str;
+ f->pairing = NULL;
+}
+
+void field_clear(field_ptr f) {
+ if (f->nqr) {
+ element_clear(f->nqr);
+ pbc_free(f->nqr);
+ }
+ mpz_clear(f->order);
+ f->field_clear(f);
+}
+
+void pbc_mpz_out_raw_n(unsigned char *data, int n, mpz_t z) {
+ size_t count;
+ if (mpz_sgn(z)) {
+ count = (mpz_sizeinbase(z, 2) + 7) / 8;
+ mpz_export(&data[n - count], NULL, 1, 1, 1, 0, z);
+ memset(data, 0, n - count);
+ } else {
+ memset(data, 0, n);
+ }
+}
+
+//for short hashes H, do
+// buf = H || 0 || H || 1 || H || ...
+//before calling mpz_import
+void pbc_mpz_from_hash(mpz_t z, mpz_t limit,
+ unsigned char *data, unsigned int len) {
+ size_t i = 0, n, count = (mpz_sizeinbase(limit, 2) + 7) / 8;
+ unsigned char buf[count];
+ unsigned char counter = 0;
+ int done = 0;
+ for (;;) {
+ if (len >= count - i) {
+ n = count - i;
+ done = 1;
+ } else n = len;
+ memcpy(buf + i, data, n);
+ i += n;
+ if (done) break;
+ buf[i] = counter;
+ counter++;
+ i++;
+ if (i == count) break;
+ }
+ PBC_ASSERT(i == count, "did not read whole buffer");
+ mpz_import(z, count, 1, 1, 1, 0, buf);
+ while (mpz_cmp(z, limit) > 0) {
+ mpz_tdiv_q_2exp(z, z, 1);
+ }
+}
+
+// Square root algorithm for Fp.
+// TODO: What happens if this is run on other kinds of fields?
+void element_tonelli(element_ptr x, element_ptr a) {
+ int s;
+ int i;
+ mpz_t e;
+ mpz_t t, t0;
+ element_t ginv, e0;
+ element_ptr nqr;
+
+ mpz_init(t);
+ mpz_init(e);
+ mpz_init(t0);
+ element_init(ginv, a->field);
+ element_init(e0, a->field);
+ nqr = field_get_nqr(a->field);
+
+ element_invert(ginv, nqr);
+
+ //let q be the order of the field
+ //q - 1 = 2^s t, t odd
+ mpz_sub_ui(t, a->field->order, 1);
+ s = mpz_scan1(t, 0);
+ mpz_tdiv_q_2exp(t, t, s);
+ mpz_set_ui(e, 0);
+ for (i = 2; i <= s; i++) {
+ mpz_sub_ui(t0, a->field->order, 1);
+ mpz_tdiv_q_2exp(t0, t0, i);
+ element_pow_mpz(e0, ginv, e);
+ element_mul(e0, e0, a);
+ element_pow_mpz(e0, e0, t0);
+ if (!element_is1(e0)) mpz_setbit(e, i - 1);
+ }
+ element_pow_mpz(e0, ginv, e);
+ element_mul(e0, e0, a);
+ mpz_add_ui(t, t, 1);
+ mpz_tdiv_q_2exp(t, t, 1);
+ mpz_tdiv_q_2exp(e, e, 1);
+
+ // (suggested by Hovav Shacham) replace next three lines with
+ // element_pow2_mpz(x, e0, t, nqr, e);
+ // once sliding windows are implemented for pow2.
+ element_pow_mpz(e0, e0, t);
+ element_pow_mpz(x, nqr, e);
+ element_mul(x, x, e0);
+
+ mpz_clear(t);
+ mpz_clear(e);
+ mpz_clear(t0);
+ element_clear(ginv);
+ element_clear(e0);
+}
+
+// Like mpz_set_str except returns number of bytes read and allows trailing
+// junk. This simplifies code for parsing elements like "[123, 456]".
+// TODO: Handle 0x, 0X and 0 conventions for hexadecimal and octal.
+int pbc_mpz_set_str(mpz_t z, const char *s, int base) {
+ int b, i = 0;
+ mpz_set_ui(z, 0);
+ if (!base) b = 10;
+ else if (base < 2 || base > 36) return 0;
+ else b = base;
+
+ for (;;) {
+ int j;
+ char c = s[i];
+ if (!c) break;
+ if (isspace(c)) {
+ i++;
+ continue;
+ }
+ if (isdigit(c)) {
+ j = c - '0';
+ } else if (c >= 'A' && c <= 'Z') {
+ j = c - 'A';
+ } else if (c >= 'a' && c <= 'z') {
+ j = c - 'a';
+ } else break;
+
+ if (j >= b) break;
+
+ mpz_mul_ui(z, z, b);
+ mpz_add_ui(z, z, j);
+ i++;
+ }
+ return i;
+}
+
+// Divides `n` with primes up to `limit`. For each factor found,
+// call `fun`. If the callback returns nonzero, then aborts and returns 1.
+// Otherwise returns 0.
+int pbc_trial_divide(int (*fun)(mpz_t factor,
+ unsigned int multiplicity,
+ void *scope_ptr),
+ void *scope_ptr,
+ mpz_t n,
+ mpz_ptr limit) {
+ mpz_t p, m;
+ mpz_t fac;
+ unsigned int mul;
+
+ mpz_init(fac);
+ mpz_init(p);
+ mpz_init(m);
+ mpz_set(m ,n);
+ mpz_set_ui(p, 2);
+
+ while (mpz_cmp_ui(m, 1)) {
+ if (mpz_probab_prime_p(m, 10)) {
+ mpz_set(p, m);
+ }
+ if (limit && mpz_cmp(p, limit) > 0) {
+ mpz_set(p, m);
+ }
+ if (mpz_divisible_p(m, p)) {
+ mul = 0;
+ mpz_set(fac, p);
+ do {
+ mpz_divexact(m, m, p);
+ mul++;
+ } while (mpz_divisible_p(m, p));
+ if (fun(fac, mul, scope_ptr)) {
+ mpz_clear(fac);
+ mpz_clear(m);
+ mpz_clear(p);
+ return 1;
+ }
+ }
+ mpz_nextprime(p, p);
+ }
+
+ mpz_clear(fac);
+ mpz_clear(m);
+ mpz_clear(p);
+ return 0;
+}
+
+// For each digit of 'n', call fun(). If it returns 1, then return 1 and
+// abort. Otherwise return 0.
+int pbc_mpz_trickle(int (*fun)(char), int base, mpz_t n) {
+ // TODO: Support different bases.
+ if (!base) base = 10;
+ if (base < 2 || base > 10) {
+ pbc_warn("only bases 2 to 10 supported");
+ return 1;
+ }
+ mpz_t d, z, q;
+ mpz_init(d);
+ mpz_init(z);
+ mpz_init(q);
+ mpz_set(z, n);
+ int res;
+ int len;
+ mpz_ui_pow_ui(d, base, len = mpz_sizeinbase(z, base));
+ if (mpz_cmp(d, z) > 0) {
+ len--;
+ mpz_divexact_ui(d, d, base);
+ }
+ while (mpz_cmp_ui(z, base) >= 0) {
+ mpz_fdiv_qr(q, z, z, d);
+ res = fun('0' + mpz_get_ui(q));
+ if (res) goto clean;
+ mpz_divexact_ui(d, d, base);
+ len--;
+ }
+ while (len) {
+ res = fun('0');
+ if (res) goto clean;
+ len--;
+ }
+ res = fun('0' + mpz_get_ui(z));
+clean:
+ mpz_clear(q);
+ mpz_clear(z);
+ mpz_clear(d);
+ return res;
+}
+
+void element_multi_double(element_t n[], element_t a[], int m) {
+ element_ptr *temp1 = pbc_malloc(sizeof(*temp1)*m);
+ element_ptr *temp2 = pbc_malloc(sizeof(*temp2)*m);
+ int i;
+
+ for(i=0; i<m; i++) {
+ PBC_ASSERT_MATCH2(n[i], a[i]);
+ temp1[i] = n[i];
+ temp2[i] = a[i];
+ }
+ n[0]->field->multi_doub(temp1, temp2, m);
+ pbc_free(temp1);
+ pbc_free(temp2);
+}
+
+void element_multi_add(element_t n[], element_t a[],element_t b[], int m) {
+ size_t size = sizeof(element_ptr)*m;
+ element_ptr *temp1 = pbc_malloc(size);
+ element_ptr *temp2 = pbc_malloc(size);
+ element_ptr *temp3 = pbc_malloc(size);
+
+ int i;
+ for(i=0; i<m; i++){
+ PBC_ASSERT_MATCH3(n[i], a[i], b[i]);
+ temp1[i] = n[i];
+ temp2[i] = a[i];
+ temp3[i] = b[i];
+ }
+
+ n[0]->field->multi_add(temp1, temp2, temp3, m);
+ pbc_free(temp1);
+ pbc_free(temp2);
+ pbc_free(temp3);
+}
+
+element_ptr element_new(field_ptr f) {
+ element_ptr e = pbc_malloc(sizeof(*e));
+ element_init(e, f);
+ return e;
+}
+
+void element_free(element_ptr e) {
+ element_clear(e);
+ pbc_free(e);
+}
diff --git a/moon-abe/pbc-0.5.14/arith/fieldquadratic.c b/moon-abe/pbc-0.5.14/arith/fieldquadratic.c
new file mode 100644
index 00000000..bfb46027
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/fieldquadratic.c
@@ -0,0 +1,692 @@
+// Quadratic extension fields.
+//
+// The fq_ functions are for general quadratic extensions.
+// The fi_ functions are faster versions of some of these functions specialized
+// for fields extended by sqrt(-1).
+// TODO: Instead of lazily generating a quadratic nonresidue, in this case
+// we can use sqrt(base field nqr) as the nqr of the extension.
+
+#include <ctype.h>
+#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_multiz.h"
+#include "pbc_fieldquadratic.h"
+#include "pbc_memory.h"
+
+// Per-element data.
+typedef struct {
+ // Elements have the form x + ya, where a is the square root of a quadratic
+ // nonresidue in the base field.
+ element_t x;
+ element_t y;
+} *eptr;
+
+// Per-field data: we use ''data'' as a field_ptr to the base field.
+
+// Return the quadratic nonresidue used to build this field.
+// Should only be called from routines used exclusively by the generic quadratic
+// extension code.
+static inline element_ptr fq_nqr(field_ptr f) {
+ return field_get_nqr((field_ptr) f->data);
+}
+
+static void fq_init(element_ptr e) {
+ eptr p = e->data = pbc_malloc(sizeof(*p));
+ field_ptr f = e->field->data;
+ element_init(p->x, f);
+ element_init(p->y, f);
+}
+
+static void fq_clear(element_ptr e) {
+ eptr p = e->data;
+ element_clear(p->x);
+ element_clear(p->y);
+ pbc_free(e->data);
+}
+
+static void fq_set_si(element_ptr e, signed long int i) {
+ eptr p = e->data;
+ element_set_si(p->x, i);
+ element_set0(p->y);
+}
+
+static void fq_set_mpz(element_ptr e, mpz_t z) {
+ eptr p = e->data;
+ element_set_mpz(p->x, z);
+ element_set0(p->y);
+}
+
+// Projection: attempts to convert Re(e) to mpz.
+static void fq_to_mpz(mpz_t z, element_ptr e) {
+ eptr p = e->data;
+ element_to_mpz(z, p->x);
+}
+
+static void fq_set0(element_ptr e) {
+ eptr p = e->data;
+ element_set0(p->x);
+ element_set0(p->y);
+}
+
+static void fq_set1(element_ptr e) {
+ eptr p = e->data;
+ element_set1(p->x);
+ element_set0(p->y);
+}
+
+static int fq_is0(element_ptr e) {
+ eptr p = e->data;
+ return element_is0(p->x) && element_is0(p->y);
+}
+
+static int fq_is1(element_ptr e) {
+ eptr p = e->data;
+ return element_is1(p->x) && element_is0(p->y);
+}
+
+static size_t fq_out_str(FILE *stream, int base, element_ptr e) {
+ size_t result = 4, status;
+ eptr p = e->data;
+ 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;
+}
+
+static int fq_snprint(char *s, size_t n, element_ptr e) {
+ eptr p = e->data;
+ size_t result = 0, left;
+ int status;
+
+ #define clip_sub() { \
+ result += status; \
+ left = result >= n ? 0 : n - result; \
+ }
+
+ 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 fq_set_multiz(element_ptr e, multiz m) {
+ eptr p = e->data;
+ if (multiz_is_z(m)) {
+ element_set_multiz(p->x, m);
+ element_set0(p->y);
+ return;
+ }
+ element_set_multiz(p->x, multiz_at(m, 0));
+ if (2 > multiz_count(m)) element_set0(p->y);
+ else element_set_multiz(p->y, multiz_at(m, 1));
+}
+
+static int fq_set_str(element_ptr e, const char *s, int base) {
+ const char *cp = s;
+ element_set0(e);
+ while (*cp && isspace(*cp)) cp++;
+ if (*cp++ != '[') return 0;
+ eptr p = e->data;
+ cp += element_set_str(p->x, cp, base);
+ while (*cp && isspace(*cp)) cp++;
+ if (*cp++ != ',') return 0;
+ cp += element_set_str(p->y, cp, base);
+ if (*cp++ != ']') return 0;
+ return cp - s;
+}
+
+static int fq_sign(element_ptr n) {
+ int res;
+ eptr r = n->data;
+ res = element_sign(r->x);
+ if (!res) return element_sign(r->y);
+ return res;
+}
+
+static void fq_add(element_ptr n, element_ptr a, element_ptr b) {
+ eptr p = a->data;
+ eptr q = b->data;
+ eptr r = n->data;
+ element_add(r->x, p->x, q->x);
+ element_add(r->y, p->y, q->y);
+}
+
+static void fq_double(element_ptr n, element_ptr a) {
+ eptr p = a->data;
+ eptr r = n->data;
+ element_double(r->x, p->x);
+ element_double(r->y, p->y);
+}
+
+static void fq_sub(element_ptr n, element_ptr a, element_ptr b) {
+ eptr p = a->data;
+ eptr q = b->data;
+ eptr r = n->data;
+ element_sub(r->x, p->x, q->x);
+ element_sub(r->y, p->y, q->y);
+}
+
+static void fq_set(element_ptr n, element_ptr a) {
+ eptr p = a->data;
+ eptr r = n->data;
+ element_set(r->x, p->x);
+ element_set(r->y, p->y);
+}
+
+static void fq_mul(element_ptr n, element_ptr a, element_ptr b) {
+ eptr p = a->data;
+ eptr q = b->data;
+ eptr r = n->data;
+
+ element_ptr nqr = fq_nqr(n->field);
+ element_t e0, e1, e2;
+
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ element_init(e2, e0->field);
+ /* naive:
+ element_mul(e0, p->x, q->x);
+ element_mul(e1, p->y, q->y);
+ element_mul(e1, e1, nqr);
+ element_add(e0, e0, e1);
+ element_mul(e1, p->x, q->y);
+ element_mul(e2, p->y, q->x);
+ element_add(e1, e1, e2);
+ element_set(r->x, e0);
+ element_set(r->y, e1);
+ */
+ // Karatsuba:
+ element_add(e0, p->x, p->y);
+ element_add(e1, q->x, q->y);
+ element_mul(e2, e0, e1);
+ element_mul(e0, p->x, q->x);
+ element_mul(e1, p->y, q->y);
+ element_mul(r->x, e1, nqr);
+ element_add(r->x, r->x, e0);
+ element_sub(e2, e2, e0);
+ element_sub(r->y, e2, e1);
+
+ element_clear(e0);
+ element_clear(e1);
+ element_clear(e2);
+}
+
+static void fq_mul_mpz(element_ptr n, element_ptr a, mpz_ptr z) {
+ eptr p = a->data;
+ eptr r = n->data;
+ element_mul_mpz(r->x, p->x, z);
+ element_mul_mpz(r->y, p->y, z);
+}
+
+static void fq_mul_si(element_ptr n, element_ptr a, signed long int z) {
+ eptr p = a->data;
+ eptr r = n->data;
+ element_mul_si(r->x, p->x, z);
+ element_mul_si(r->y, p->y, z);
+}
+
+static void fq_square(element_ptr n, element_ptr a) {
+ eptr p = a->data;
+ eptr r = n->data;
+ element_ptr nqr = fq_nqr(n->field);
+ element_t e0, e1;
+
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ element_square(e0, p->x);
+ element_square(e1, p->y);
+ element_mul(e1, e1, nqr);
+ element_add(e0, e0, e1);
+ element_mul(e1, p->x, p->y);
+ //TODO: which is faster?
+ //element_add(e1, e1, e1);
+ element_double(e1, e1);
+ element_set(r->x, e0);
+ element_set(r->y, e1);
+ element_clear(e0);
+ element_clear(e1);
+}
+
+static void fq_neg(element_ptr n, element_ptr a) {
+ eptr p = a->data;
+ eptr r = n->data;
+ element_neg(r->x, p->x);
+ element_neg(r->y, p->y);
+}
+
+static void fq_random(element_ptr e) {
+ eptr p = e->data;
+ element_random(p->x);
+ element_random(p->y);
+}
+
+static int fq_cmp(element_ptr a, element_ptr b) {
+ eptr p = a->data;
+ eptr q = b->data;
+ return element_cmp(p->x, q->x) || element_cmp(p->y, q->y);
+}
+
+static void fq_invert(element_ptr n, element_ptr a) {
+ eptr p = a->data;
+ eptr r = n->data;
+ element_ptr nqr = fq_nqr(n->field);
+ element_t e0, e1;
+
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ element_square(e0, p->x);
+ element_square(e1, p->y);
+ element_mul(e1, e1, nqr);
+ element_sub(e0, e0, e1);
+ element_invert(e0, e0);
+ element_mul(r->x, p->x, e0);
+ element_neg(e0, e0);
+ element_mul(r->y, p->y, e0);
+
+ element_clear(e0);
+ element_clear(e1);
+}
+
+static void fq_from_hash(element_ptr n, void *data, int len) {
+ eptr r = n->data;
+ int k = len / 2;
+ element_from_hash(r->x, data, k);
+ element_from_hash(r->y, (char *)data + k, len - k);
+}
+
+static int fq_length_in_bytes(element_ptr e) {
+ eptr p = e->data;
+ return element_length_in_bytes(p->x) + element_length_in_bytes(p->y);
+}
+
+static int fq_to_bytes(unsigned char *data, element_t e) {
+ eptr p = e->data;
+ int len;
+ len = element_to_bytes(data, p->x);
+ len += element_to_bytes(data + len, p->y);
+ return len;
+}
+
+static int fq_from_bytes(element_t e, unsigned char *data) {
+ eptr p = e->data;
+ int len;
+ len = element_from_bytes(p->x, data);
+ len += element_from_bytes(p->y, data + len);
+ return len;
+}
+
+static int fq_is_sqr(element_ptr e) {
+ //x + y sqrt(nqr) is a square iff x^2 - nqr y^2 is (in the base field)
+ eptr p = e->data;
+ element_t e0, e1;
+ element_ptr nqr = fq_nqr(e->field);
+ int result;
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ element_square(e0, p->x);
+ element_square(e1, p->y);
+ element_mul(e1, e1, nqr);
+ element_sub(e0, e0, e1);
+ result = element_is_sqr(e0);
+ element_clear(e0);
+ element_clear(e1);
+ return result;
+}
+
+static void fq_sqrt(element_ptr n, element_ptr e) {
+ eptr p = e->data;
+ eptr r = n->data;
+ element_ptr nqr = fq_nqr(n->field);
+ element_t e0, e1, e2;
+
+ //if (a+b sqrt(nqr))^2 = x+y sqrt(nqr) then
+ //2a^2 = x +- sqrt(x^2 - nqr y^2)
+ //(take the sign which allows a to exist)
+ //and 2ab = y
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ element_init(e2, e0->field);
+ element_square(e0, p->x);
+ element_square(e1, p->y);
+ element_mul(e1, e1, nqr);
+ element_sub(e0, e0, e1);
+ element_sqrt(e0, e0);
+ //e0 = sqrt(x^2 - nqr y^2)
+ element_add(e1, p->x, e0);
+ element_set_si(e2, 2);
+ element_invert(e2, e2);
+ element_mul(e1, e1, e2);
+ //e1 = (x + sqrt(x^2 - nqr y^2))/2
+ if (!element_is_sqr(e1)) {
+ element_sub(e1, e1, e0);
+ //e1 should be a square
+ }
+ element_sqrt(e0, e1);
+ element_add(e1, e0, e0);
+ element_invert(e1, e1);
+ element_mul(r->y, p->y, e1);
+ element_set(r->x, e0);
+ element_clear(e0);
+ element_clear(e1);
+ element_clear(e2);
+}
+
+static int fq_item_count(element_ptr e) {
+ UNUSED_VAR(e);
+ return 2;
+}
+
+static element_ptr fq_item(element_ptr e, int i) {
+ eptr p = e->data;
+ switch(i) {
+ case 0:
+ return p->x;
+ case 1:
+ return p->y;
+ default:
+ return NULL;
+ }
+}
+
+static void field_clear_fq(field_ptr f) {
+ UNUSED_VAR(f);
+ //f->order gets cleared automatically
+}
+
+static void fq_out_info(FILE *out, field_ptr f) {
+ field_ptr fbase = f->data;
+ element_fprintf(out, "extension x^2 + %B, base field: ", fq_nqr(f));
+ field_out_info(out, fbase);
+}
+
+// Specialized versions of some of the above for the case K[i].
+
+static void fi_mul(element_ptr n, element_ptr a, element_ptr b) {
+ eptr p = a->data;
+ eptr q = b->data;
+ eptr r = n->data;
+ element_t e0, e1, e2;
+
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ element_init(e2, e0->field);
+ /* Naive method:
+ element_mul(e0, p->x, q->x);
+ element_mul(e1, p->y, q->y);
+ element_sub(e0, e0, e1);
+ element_mul(e1, p->x, q->y);
+ element_mul(e2, p->y, q->x);
+ element_add(e1, e1, e2);
+ element_set(r->x, e0);
+ element_set(r->y, e1);
+ */
+ // Karatsuba multiplicaiton:
+ element_add(e0, p->x, p->y);
+ element_add(e1, q->x, q->y);
+ element_mul(e2, e0, e1);
+ element_mul(e0, p->x, q->x);
+ element_sub(e2, e2, e0);
+ element_mul(e1, p->y, q->y);
+ element_sub(r->x, e0, e1);
+ element_sub(r->y, e2, e1);
+
+ element_clear(e0);
+ element_clear(e1);
+ element_clear(e2);
+}
+
+static void fi_square(element_ptr n, element_ptr a) {
+ eptr p = a->data;
+ eptr r = n->data;
+ element_t e0, e1;
+
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ // Re(n) = x^2 - y^2 = (x+y)(x-y)
+ element_add(e0, p->x, p->y);
+ element_sub(e1, p->x, p->y);
+ element_mul(e0, e0, e1);
+ // Im(n) = 2xy
+ element_mul(e1, p->x, p->y);
+ element_add(e1, e1, e1);
+ element_set(r->x, e0);
+ element_set(r->y, e1);
+ element_clear(e0);
+ element_clear(e1);
+}
+
+static void fi_invert(element_ptr n, element_ptr a) {
+ eptr p = a->data;
+ eptr r = n->data;
+ element_t e0, e1;
+
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ element_square(e0, p->x);
+ element_square(e1, p->y);
+ element_add(e0, e0, e1);
+ element_invert(e0, e0);
+ element_mul(r->x, p->x, e0);
+ element_neg(e0, e0);
+ element_mul(r->y, p->y, e0);
+
+ element_clear(e0);
+ element_clear(e1);
+}
+
+static int fi_is_sqr(element_ptr e) {
+ // x + yi is a square <=> x^2 + y^2 is (in the base field).
+
+ // Proof: (=>) if x+yi = (a+bi)^2, then a^2 - b^2 = x, 2ab = y,
+ // thus (a^2 + b^2)^2 = (a^2 - b^2)^2 + (2ab)^2 = x^2 + y^2
+
+ // (<=) Suppose A^2 = x^2 + y^2. If there exist a, b satisfying:
+ // a^2 = (+-A + x)/2, b^2 = (+-A - x)/2
+ // then (a + bi)^2 = x + yi.
+ //
+ // We show that exactly one of (A + x)/2, (-A + x)/2 is a quadratic residue
+ // (thus a, b do exist). Suppose not. Then the product (x^2 - A^2) / 4 is
+ // some quadratic residue, a contradiction since this would imply x^2 - A^2 =
+ // -y^2 is also a quadratic residue, but we know -1 is not a quadratic
+ // residue. QED.
+ eptr p = e->data;
+ element_t e0, e1;
+ int result;
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ element_square(e0, p->x);
+ element_square(e1, p->y);
+ element_add(e0, e0, e1);
+ result = element_is_sqr(e0);
+ element_clear(e0);
+ element_clear(e1);
+ return result;
+}
+
+static void fi_sqrt(element_ptr n, element_ptr e) {
+ eptr p = e->data;
+ eptr r = n->data;
+ element_t e0, e1, e2;
+
+ // If (a+bi)^2 = x+yi then 2a^2 = x +- sqrt(x^2 + y^2)
+ // where we choose the sign so that a exists, and 2ab = y.
+ // Thus 2b^2 = - (x -+ sqrt(x^2 + y^2)).
+ element_init(e0, p->x->field);
+ element_init(e1, e0->field);
+ element_init(e2, e0->field);
+ element_square(e0, p->x);
+ element_square(e1, p->y);
+ element_add(e0, e0, e1);
+ element_sqrt(e0, e0);
+ // e0 = sqrt(x^2 + y^2)
+ element_add(e1, p->x, e0);
+ element_set_si(e2, 2);
+ element_invert(e2, e2);
+ element_mul(e1, e1, e2);
+ // e1 = (x + sqrt(x^2 + y^2))/2
+ if (!element_is_sqr(e1)) {
+ element_sub(e1, e1, e0);
+ // e1 should be a square.
+ }
+ element_sqrt(e0, e1);
+ element_add(e1, e0, e0);
+ element_invert(e1, e1);
+ element_mul(r->y, p->y, e1);
+ element_set(r->x, e0);
+ element_clear(e0);
+ element_clear(e1);
+ element_clear(e2);
+}
+
+static void fi_out_info(FILE *out, field_ptr f) {
+ field_ptr fbase = f->data;
+ fprintf(out, "extension x^2 + 1, base field: ");
+ field_out_info(out, fbase);
+}
+
+static void field_clear_fi(field_ptr f) {
+ UNUSED_VAR(f);
+}
+
+// All the above should be static.
+
+void element_field_to_quadratic(element_ptr r, element_ptr a) {
+ eptr p = r->data;
+ element_set(p->x, a);
+ element_set0(p->y);
+}
+
+void element_field_to_fi(element_ptr a, element_ptr b) {
+ element_field_to_quadratic(a, b);
+}
+
+static element_ptr fq_get_x(element_ptr a) {
+ return ((eptr) a->data)->x;
+}
+
+static element_ptr fq_get_y(element_ptr a) {
+ return ((eptr) a->data)->y;
+}
+
+void field_init_quadratic(field_ptr f, field_ptr fbase) {
+ field_init(f);
+
+ f->field_clear = field_clear_fq;
+ f->data = fbase;
+
+ f->init = fq_init;
+ f->clear = fq_clear;
+ f->set_si = fq_set_si;
+ f->set_mpz = fq_set_mpz;
+ f->to_mpz = fq_to_mpz;
+ f->out_str = fq_out_str;
+ f->snprint = fq_snprint;
+ f->set_multiz = fq_set_multiz;
+ f->set_str = fq_set_str;
+ f->sign = fq_sign;
+ f->add = fq_add;
+ f->sub = fq_sub;
+ f->set = fq_set;
+ f->mul = fq_mul;
+ f->mul_mpz = fq_mul_mpz;
+ f->mul_si = fq_mul_si;
+ f->square = fq_square;
+ f->doub = fq_double;
+ f->neg = fq_neg;
+ f->cmp = fq_cmp;
+ f->invert = fq_invert;
+ f->random = fq_random;
+ f->from_hash = fq_from_hash;
+ f->is1 = fq_is1;
+ f->is0 = fq_is0;
+ f->set0 = fq_set0;
+ f->set1 = fq_set1;
+ f->is_sqr = fq_is_sqr;
+ f->sqrt = fq_sqrt;
+ f->to_bytes = fq_to_bytes;
+ f->from_bytes = fq_from_bytes;
+ f->out_info = fq_out_info;
+ f->item_count = fq_item_count;
+ f->item = fq_item;
+ f->get_x = fq_get_x;
+ f->get_y = fq_get_y;
+
+ mpz_mul(f->order, fbase->order, fbase->order);
+ if (fbase->fixed_length_in_bytes < 0) {
+ f->length_in_bytes = fq_length_in_bytes;
+ f->fixed_length_in_bytes = -1;
+ } else {
+ f->fixed_length_in_bytes = 2 * fbase->fixed_length_in_bytes;
+ }
+}
+
+void field_init_fi(field_ptr f, field_ptr fbase) {
+ field_init(f);
+ f->field_clear = field_clear_fi;
+ f->data = fbase;
+ f->init = fq_init;
+ f->clear = fq_clear;
+ f->set_si = fq_set_si;
+ f->set_mpz = fq_set_mpz;
+ f->to_mpz = fq_to_mpz;
+ f->out_str = fq_out_str;
+ f->snprint = fq_snprint;
+ f->set_multiz = fq_set_multiz;
+ f->set_str = fq_set_str;
+ f->sign = fq_sign;
+ f->add = fq_add;
+ f->sub = fq_sub;
+ f->set = fq_set;
+ f->mul = fi_mul;
+ f->mul_mpz = fq_mul_mpz;
+ f->mul_si = fq_mul_si;
+ f->square = fi_square;
+ f->doub = fq_double;
+ f->neg = fq_neg;
+ f->cmp = fq_cmp;
+ f->invert = fi_invert;
+ f->random = fq_random;
+ f->from_hash = fq_from_hash;
+ f->is1 = fq_is1;
+ f->is0 = fq_is0;
+ f->set0 = fq_set0;
+ f->set1 = fq_set1;
+ f->is_sqr = fi_is_sqr;
+ f->sqrt = fi_sqrt;
+ f->to_bytes = fq_to_bytes;
+ f->from_bytes = fq_from_bytes;
+ f->out_info = fi_out_info;
+ f->item_count = fq_item_count;
+ f->item = fq_item;
+ f->get_x = fq_get_x;
+ f->get_y = fq_get_y;
+
+ mpz_mul(f->order, fbase->order, fbase->order);
+ if (fbase->fixed_length_in_bytes < 0) {
+ f->length_in_bytes = fq_length_in_bytes;
+ f->fixed_length_in_bytes = -1;
+ } else {
+ f->fixed_length_in_bytes = 2 * fbase->fixed_length_in_bytes;
+ }
+}
diff --git a/moon-abe/pbc-0.5.14/arith/fp.c b/moon-abe/pbc-0.5.14/arith/fp.c
new file mode 100644
index 00000000..e0127a8e
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/fp.c
@@ -0,0 +1,49 @@
+// F_p initialization.
+//
+// Specific implementations of F_p are found in naivefp.c, fastfp.c, fasterfp.c
+// and montfp.c. For pairing-based cryptosystems, montfp.c is the fastest.
+// I keep all versions around for testing, and also to show off the modularity
+// of the code.
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h> // for intptr_t
+#include <gmp.h>
+#include <string.h>
+#include "pbc_utils.h"
+#include "pbc_field.h"
+#include "pbc_fp.h"
+
+// By default, use the montfp.c implementation of F_p. After
+// pbc_tweak_use_fp(), future field_init_fp calls will use the specified
+// implementation. This is useful for benchmarking and testing.
+static void (*option_fpinit) (field_ptr f, mpz_t prime) = field_init_mont_fp;
+
+void pbc_tweak_use_fp(char *s) {
+ if (!strcmp(s, "naive")) {
+ option_fpinit = field_init_naive_fp;
+ } else if (!strcmp(s, "fast")) {
+ option_fpinit = field_init_fast_fp;
+ } else if (!strcmp(s, "faster")) {
+ option_fpinit = field_init_faster_fp;
+ } else if (!strcmp(s, "mont")) {
+ option_fpinit = field_init_mont_fp;
+ } else {
+ pbc_error("no such Fp implementation: %s", s);
+ }
+}
+
+void field_init_fp(field_ptr f, mpz_t modulus) {
+ if (mpz_fits_ulong_p(modulus)) {
+ // If this case mattered, I'd have written a F_p implementation specialized
+ // for moduli that fits into machine words.
+ field_init_naive_fp(f, modulus);
+ } else {
+ if (mpz_odd_p(modulus)) {
+ option_fpinit(f, modulus);
+ } else {
+ // montfp.c only supports odd moduli.
+ field_init_faster_fp(f, modulus);
+ }
+ }
+}
diff --git a/moon-abe/pbc-0.5.14/arith/init_random.c b/moon-abe/pbc-0.5.14/arith/init_random.c
new file mode 100644
index 00000000..bd040a38
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/init_random.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <stdint.h> // for intptr_t
+#include <stdlib.h>
+#include <gmp.h>
+#include "pbc_utils.h"
+#include "pbc_random.h"
+
+void pbc_init_random(void) {
+ FILE *fp;
+ fp = fopen("/dev/urandom", "rb");
+ if (!fp) {
+ pbc_warn("could not open /dev/urandom, using deterministic random number generator");
+ pbc_random_set_deterministic(0);
+ } else {
+ pbc_random_set_file("/dev/urandom");
+ fclose(fp);
+ }
+}
diff --git a/moon-abe/pbc-0.5.14/arith/init_random.win32.c b/moon-abe/pbc-0.5.14/arith/init_random.win32.c
new file mode 100644
index 00000000..ec7f8732
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/init_random.win32.c
@@ -0,0 +1,52 @@
+// Win32 Compatibility Code added by Yulian Kalev and Stefan Georg Weber.
+#include <stdio.h>
+#include <stdint.h> // for intptr_t
+#include <stdlib.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <gmp.h>
+#include "pbc_random.h"
+#include "pbc_utils.h"
+#include "pbc_memory.h"
+
+static void win32_mpz_random(mpz_t r, mpz_t limit, void *data) {
+ UNUSED_VAR (data);
+ HCRYPTPROV phProv;
+ unsigned int error;
+ if (!CryptAcquireContext(&phProv,NULL,NULL,PROV_RSA_FULL,0)) {
+ error = GetLastError();
+ if (error == 0x80090016) { //need to create a new keyset
+ if (!CryptAcquireContext(&phProv,NULL,NULL,PROV_RSA_FULL,CRYPT_NEWKEYSET)) {
+ pbc_error("Couldn't create CryptContext: %x", (int)GetLastError());
+ return;
+ }
+ } else {
+ pbc_error("Couldn't create CryptContext: %x", error);
+ return;
+ }
+ }
+ int n, bytecount, leftover;
+ unsigned char *bytes;
+ mpz_t z;
+ mpz_init(z);
+ n = mpz_sizeinbase(limit, 2);
+ bytecount = (n + 7) / 8;
+ leftover = n % 8;
+ bytes = (unsigned char *) pbc_malloc(bytecount);
+ for (;;) {
+ CryptGenRandom(phProv,bytecount,(byte *)bytes);
+ if (leftover) {
+ *bytes = *bytes % (1 << leftover);
+ }
+ mpz_import(z, bytecount, 1, 1, 0, 0, bytes);
+ if (mpz_cmp(z, limit) < 0) break;
+ }
+ CryptReleaseContext(phProv,0);
+ mpz_set(r, z);
+ mpz_clear(z);
+ pbc_free(bytes);
+}
+
+void pbc_init_random(void) {
+ pbc_random_set_function(win32_mpz_random, NULL);
+}
diff --git a/moon-abe/pbc-0.5.14/arith/montfp.c b/moon-abe/pbc-0.5.14/arith/montfp.c
new file mode 100644
index 00000000..c79bb72b
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/montfp.c
@@ -0,0 +1,596 @@
+// F_p using Montgomery representation.
+//
+// Let b = 256^sizeof(mp_limb_t).
+// Let R = b^t be the smallest power of b greater than the modulus p.
+// Then x is stored as xR (mod p).
+// Addition: same as naive implementation.
+// Multipication: Montgomery reduction.
+// Code assumes the modulus p is odd.
+//
+// TODO: mul_2exp(x, p->bytes * 8) could be replaced with
+// faster code that messes with GMP internals
+
+#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_random.h"
+#include "pbc_fp.h"
+#include "pbc_memory.h"
+
+// Per-field data.
+typedef struct {
+ size_t limbs; // Number of limbs per element.
+ size_t bytes; // Number of bytes per element.
+ mp_limb_t *primelimbs; // Points to an array of limbs holding the modulus.
+ mp_limb_t negpinv; // -p^-1 mod b
+ mp_limb_t *R; // R mod p
+ mp_limb_t *R3; // R^3 mod p
+} *fptr;
+
+// Per-element data.
+typedef struct {
+ char flag; // flag == 0 means the element is zero.
+ mp_limb_t *d; // Otherwise d points to an array holding the element.
+} *eptr;
+
+// Copies limbs of z into dst and zeroes any leading limbs, where n is the
+// total number of limbs.
+// Requires z to have at most n limbs.
+static inline void set_limbs(mp_limb_t *dst, mpz_t z, size_t n) {
+ size_t count;
+ mpz_export(dst, &count, -1, sizeof(mp_limb_t), 0, 0, z);
+ memset((void *) (((unsigned char *) dst) + count * sizeof(mp_limb_t)),
+ 0, (n - count) * sizeof(mp_limb_t));
+}
+
+static void fp_init(element_ptr e) {
+ fptr p = e->field->data;
+ eptr ep = e->data = pbc_malloc(sizeof(*ep));
+ ep->flag = 0;
+ ep->d = pbc_malloc(p->bytes);
+}
+
+static void fp_clear(element_ptr e) {
+ eptr ep = e->data;
+ pbc_free(ep->d);
+ pbc_free(e->data);
+}
+
+static void fp_set_mpz(element_ptr e, mpz_ptr z) {
+ fptr p = e->field->data;
+ eptr ep = e->data;
+ if (!mpz_sgn(z)) ep->flag = 0;
+ else {
+ mpz_t tmp;
+ mpz_init(tmp);
+ mpz_mul_2exp(tmp, z, p->bytes * 8);
+ mpz_mod(tmp, tmp, e->field->order);
+ if (!mpz_sgn(tmp)) ep->flag = 0;
+ else {
+ set_limbs(ep->d, tmp, p->limbs);
+ ep->flag = 2;
+ }
+ mpz_clear(tmp);
+ }
+}
+
+static void fp_set_si(element_ptr e, signed long int op) {
+ fptr p = e->field->data;
+ eptr ep = e->data;
+ if (!op) ep->flag = 0;
+ else {
+ mpz_t tmp;
+ mpz_init(tmp);
+ // TODO: Could be optimized.
+ mpz_set_si(tmp, op);
+ mpz_mul_2exp(tmp, tmp, p->bytes * 8);
+ mpz_mod(tmp, tmp, e->field->order);
+ if (!mpz_sgn(tmp)) ep->flag = 0;
+ else {
+ set_limbs(ep->d, tmp, p->limbs);
+ ep->flag = 2;
+ }
+ mpz_clear(tmp);
+ }
+}
+
+// Montgomery reduction.
+// Algorithm II.4 from Blake, Seroussi and Smart.
+static void mont_reduce(mp_limb_t *x, mp_limb_t *y, fptr p) {
+ size_t t = p->limbs;
+ size_t i;
+ mp_limb_t flag = 0;
+ for (i = 0; i < t; i++) {
+ mp_limb_t u = y[i] * p->negpinv;
+ mp_limb_t carry = mpn_addmul_1(&y[i], p->primelimbs, t, u);
+ //mpn_add_1(&y[i+t], &y[i+t], t - i + 1, carry);
+ flag += mpn_add_1(&y[i + t], &y[i + t], t - i, carry);
+ }
+ if (flag || mpn_cmp(&y[t], p->primelimbs, t) >= 0) {
+ mpn_sub_n(x, &y[t], p->primelimbs, t);
+ } else {
+ // TODO: GMP set might be faster.
+ memcpy(x, &y[t], t * sizeof(mp_limb_t));
+ }
+}
+
+static void fp_to_mpz(mpz_ptr z, element_ptr e) {
+ eptr ep = e->data;
+ if (!ep->flag) mpz_set_ui(z, 0);
+ else {
+ // x is stored as xR.
+ // We must divide out R to convert to standard representation.
+ fptr p = e->field->data;
+ mp_limb_t tmp[2 * p->limbs];
+
+ memcpy(tmp, ep->d, p->limbs * sizeof(mp_limb_t));
+ memset(&tmp[p->limbs], 0, p->limbs * sizeof(mp_limb_t));
+ _mpz_realloc(z, p->limbs);
+ mont_reduce(z->_mp_d, tmp, p);
+ // Remove leading zero limbs.
+ for (z->_mp_size = p->limbs; !z->_mp_d[z->_mp_size - 1]; z->_mp_size--);
+ }
+}
+
+static void fp_set0(element_ptr e) {
+ eptr ep = e->data;
+ ep->flag = 0;
+}
+
+static void fp_set1(element_ptr e) {
+ fptr p = e->field->data;
+ eptr ep = e->data;
+ ep->flag = 2;
+ memcpy(ep->d, p->R, p->bytes);
+}
+
+static int fp_is1(element_ptr e) {
+ eptr ep = e->data;
+ if (!ep->flag) return 0;
+ else {
+ fptr p = e->field->data;
+ return !mpn_cmp(ep->d, p->R, p->limbs);
+ }
+}
+
+static int fp_is0(element_ptr e) {
+ eptr ep = e->data;
+ return !ep->flag;
+}
+
+static size_t fp_out_str(FILE * stream, int base, element_ptr e) {
+ size_t result;
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, e);
+ result = mpz_out_str(stream, base, z);
+ mpz_clear(z);
+ return result;
+}
+
+static int fp_snprint(char *s, size_t n, element_ptr e) {
+ int result;
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, e);
+ result = gmp_snprintf(s, n, "%Zd", z);
+ mpz_clear(z);
+ return result;
+}
+
+static int fp_set_str(element_ptr e, const char *s, int base) {
+ mpz_t z;
+ mpz_init(z);
+ int result = pbc_mpz_set_str(z, s, base);
+ mpz_mod(z, z, e->field->order);
+ fp_set_mpz(e, z);
+ mpz_clear(z);
+ return result;
+}
+
+static void fp_set(element_ptr c, element_ptr a) {
+ eptr ad = a->data;
+ eptr cd = c->data;
+ if (a == c) return;
+ if (!ad->flag) cd->flag = 0;
+ else {
+ fptr p = a->field->data;
+
+ // Assembly is faster, but I don't want to stoop to that level.
+ // Instead of memcpy(), we rewrite so GMP assembly ends up being invoked.
+ /*
+ memcpy(cd->d, ad->d, p->bytes);
+ */
+ mpz_t z1, z2;
+ z1->_mp_d = cd->d;
+ z2->_mp_d = ad->d;
+ z1->_mp_size = z1->_mp_alloc = z2->_mp_size = z2->_mp_alloc = p->limbs;
+ mpz_set(z1, z2);
+
+ cd->flag = 2;
+ }
+}
+
+static void fp_add(element_ptr c, element_ptr a, element_ptr b) {
+ eptr ad = a->data, bd = b->data;
+
+ if (!ad->flag) {
+ fp_set(c, b);
+ } else if (!bd->flag) {
+ fp_set(c, a);
+ } else {
+ eptr cd = c->data;
+ fptr p = a->field->data;
+ const size_t t = p->limbs;
+ mp_limb_t carry;
+ carry = mpn_add_n(cd->d, ad->d, bd->d, t);
+
+ if (carry) {
+ // Assumes result of following sub is not zero,
+ // i.e. modulus cannot be 2^(n * bits_per_limb).
+ mpn_sub_n(cd->d, cd->d, p->primelimbs, t);
+ cd->flag = 2;
+ } else {
+ int i = mpn_cmp(cd->d, p->primelimbs, t);
+ if (!i) {
+ cd->flag = 0;
+ } else {
+ cd->flag = 2;
+ if (i > 0) {
+ mpn_sub_n(cd->d, cd->d, p->primelimbs, t);
+ }
+ }
+ }
+ }
+}
+
+static void fp_double(element_ptr c, element_ptr a) {
+ eptr ad = a->data, cd = c->data;
+ if (!ad->flag) {
+ cd->flag = 0;
+ } else {
+ fptr p = c->field->data;
+ const size_t t = p->limbs;
+ if (mpn_lshift(cd->d, ad->d, t, 1)) {
+ cd->flag = 2;
+ // Again, assumes result is not zero.
+ mpn_sub_n(cd->d, cd->d, p->primelimbs, t);
+ } else {
+ int i = mpn_cmp(cd->d, p->primelimbs, t);
+ if (!i) {
+ cd->flag = 0;
+ } else {
+ cd->flag = 2;
+ if (i > 0) {
+ mpn_sub_n(cd->d, cd->d, p->primelimbs, t);
+ }
+ }
+ }
+ }
+}
+
+static void fp_halve(element_ptr c, element_ptr a) {
+ eptr ad = a->data, cd = c->data;
+ if (!ad->flag) {
+ cd->flag = 0;
+ } else {
+ fptr p = c->field->data;
+ const size_t t = p->limbs;
+ int carry = 0;
+ mp_limb_t *alimb = ad->d;
+ mp_limb_t *climb = cd->d;
+ if (alimb[0] & 1) {
+ carry = mpn_add_n(climb, alimb, p->primelimbs, t);
+ } else fp_set(c, a);
+
+ mpn_rshift(climb, climb, t, 1);
+ if (carry) climb[t - 1] |= ((mp_limb_t) 1) << (sizeof(mp_limb_t) * 8 - 1);
+ }
+}
+
+static void fp_neg(element_ptr c, element_ptr a) {
+ eptr ad = a->data, cd = c->data;
+ if (!ad->flag) cd->flag = 0;
+ else {
+ fptr p = a->field->data;
+ mpn_sub_n(cd->d, p->primelimbs, ad->d, p->limbs);
+ cd->flag = 2;
+ }
+}
+
+static void fp_sub(element_ptr c, element_ptr a, element_ptr b) {
+ eptr ad = a->data, bd = b->data;
+
+ if (!ad->flag) {
+ fp_neg(c, b);
+ } else if (!bd->flag) {
+ fp_set(c, a);
+ } else {
+ fptr p = c->field->data;
+ size_t t = p->limbs;
+ eptr cd = c->data;
+ int i = mpn_cmp(ad->d, bd->d, t);
+
+ if (i == 0) {
+ cd->flag = 0;
+ } else {
+ cd->flag = 2;
+ mpn_sub_n(cd->d, ad->d, bd->d, t);
+ if (i < 0) {
+ mpn_add_n(cd->d, cd->d, p->primelimbs, t);
+ }
+ }
+ }
+}
+
+// Montgomery multiplication.
+// See Blake, Seroussi and Smart.
+static inline void mont_mul(mp_limb_t *c, mp_limb_t *a, mp_limb_t *b,
+ fptr p) {
+ // Instead of right shifting every iteration
+ // I allocate more room for the z array.
+ size_t i, t = p->limbs;
+ mp_limb_t z[2 * t + 1];
+ mp_limb_t u = (a[0] * b[0]) * p->negpinv;
+ mp_limb_t v = z[t] = mpn_mul_1(z, b, t, a[0]);
+ z[t] += mpn_addmul_1(z, p->primelimbs, t, u);
+ z[t + 1] = z[t] < v; // Handle overflow.
+ for (i = 1; i < t; i++) {
+ u = (z[i] + a[i] * b[0]) * p->negpinv;
+ v = z[t + i] += mpn_addmul_1(z + i, b, t, a[i]);
+ z[t + i] += mpn_addmul_1(z + i, p->primelimbs, t, u);
+ z[t + i + 1] = z[t + i] < v;
+ }
+ if (z[t * 2] || mpn_cmp(z + t, p->primelimbs, t) >= 0) {
+ mpn_sub_n(c, z + t, p->primelimbs, t);
+ } else {
+ memcpy(c, z + t, t * sizeof(mp_limb_t));
+ // Doesn't seem to make a difference:
+ /*
+ mpz_t z1, z2;
+ z1->_mp_d = c;
+ z2->_mp_d = z + t;
+ z1->_mp_size = z1->_mp_alloc = z2->_mp_size = z2->_mp_alloc = t;
+ mpz_set(z1, z2);
+ */
+ }
+}
+
+static void fp_mul(element_ptr c, element_ptr a, element_ptr b) {
+ eptr ad = a->data, bd = b->data;
+ eptr cd = c->data;
+
+ if (!ad->flag || !bd->flag) {
+ cd->flag = 0;
+ } else {
+ fptr p = c->field->data;
+ mont_mul(cd->d, ad->d, bd->d, p);
+ cd->flag = 2;
+ }
+}
+
+static void fp_pow_mpz(element_ptr c, element_ptr a, mpz_ptr op) {
+ // Alternative: rewrite GMP mpz_powm().
+ fptr p = a->field->data;
+ eptr ad = a->data;
+ eptr cd = c->data;
+ if (!ad->flag) cd->flag = 0;
+ else {
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, a);
+ mpz_powm(z, z, op, a->field->order);
+ mpz_mul_2exp(z, z, p->bytes * 8);
+ mpz_mod(z, z, a->field->order);
+ set_limbs(cd->d, z, p->limbs);
+ mpz_clear(z);
+ cd->flag = 2;
+ }
+}
+
+// Inversion is slower than in a naive Fp implementation because of an extra
+// multiplication.
+// Requires nonzero a.
+static void fp_invert(element_ptr c, element_ptr a) {
+ eptr ad = a->data;
+ eptr cd = c->data;
+ fptr p = a->field->data;
+ mp_limb_t tmp[p->limbs];
+ mpz_t z;
+
+ mpz_init(z);
+
+ // Copy the limbs into a regular mpz_t so we can invert using the standard
+ // mpz_invert().
+ mpz_import(z, p->limbs, -1, sizeof(mp_limb_t), 0, 0, ad->d);
+ mpz_invert(z, z, a->field->order);
+ set_limbs(tmp, z, p->limbs);
+
+ // Normalize.
+ mont_mul(cd->d, tmp, p->R3, p);
+ cd->flag = 2;
+ mpz_clear(z);
+}
+
+static void fp_random(element_ptr a) {
+ fptr p = a->field->data;
+ eptr ad = a->data;
+ mpz_t z;
+ mpz_init(z);
+ pbc_mpz_random(z, a->field->order);
+ if (mpz_sgn(z)) {
+ mpz_mul_2exp(z, z, p->bytes * 8);
+ mpz_mod(z, z, a->field->order);
+ set_limbs(ad->d, z, p->limbs);
+ ad->flag = 2;
+ } else {
+ ad->flag = 0;
+ }
+ mpz_clear(z);
+}
+
+static void fp_from_hash(element_ptr a, void *data, int len) {
+ mpz_t z;
+
+ mpz_init(z);
+ pbc_mpz_from_hash(z, a->field->order, data, len);
+ fp_set_mpz(a, z);
+ mpz_clear(z);
+}
+
+static int fp_cmp(element_ptr a, element_ptr b) {
+ eptr ad = a->data, bd = b->data;
+ if (!ad->flag) return bd->flag;
+ else {
+ fptr p = a->field->data;
+ return mpn_cmp(ad->d, bd->d, p->limbs);
+ //return memcmp(ad->d, bd->d, p->limbs);
+ }
+}
+
+static int fp_sgn_odd(element_ptr a) {
+ eptr ad = a->data;
+ if (!ad->flag) return 0;
+ else {
+ mpz_t z;
+ mpz_init(z);
+ int res;
+ fp_to_mpz(z, a);
+ res = mpz_odd_p(z) ? 1 : -1;
+ mpz_clear(z);
+ return res;
+ }
+}
+
+static int fp_is_sqr(element_ptr a) {
+ eptr ad = a->data;
+ int res;
+ mpz_t z;
+ mpz_init(z);
+ // 0 is a square.
+ if (!ad->flag) return 1;
+ fp_to_mpz(z, a);
+ res = mpz_legendre(z, a->field->order) == 1;
+ mpz_clear(z);
+ return res;
+}
+
+static int fp_to_bytes(unsigned char *data, element_t a) {
+ mpz_t z;
+ int n = a->field->fixed_length_in_bytes;
+
+ mpz_init(z);
+ fp_to_mpz(z, a);
+ pbc_mpz_out_raw_n(data, n, z);
+ mpz_clear(z);
+ return n;
+}
+
+static int fp_from_bytes(element_t a, unsigned char *data) {
+ fptr p = a->field->data;
+ eptr ad = a->data;
+ int n;
+ mpz_t z;
+
+ mpz_init(z);
+
+ n = a->field->fixed_length_in_bytes;
+ mpz_import(z, n, 1, 1, 1, 0, data);
+ if (!mpz_sgn(z)) ad->flag = 0;
+ else {
+ ad->flag = 2;
+ mpz_mul_2exp(z, z, p->bytes * 8);
+ mpz_mod(z, z, a->field->order);
+ set_limbs(ad->d, z, p->limbs);
+ }
+ mpz_clear(z);
+ return n;
+}
+
+static void fp_field_clear(field_t f) {
+ fptr p = f->data;
+ pbc_free(p->primelimbs);
+ pbc_free(p->R);
+ pbc_free(p->R3);
+ pbc_free(p);
+}
+
+// The only public functions. All the above should be static.
+
+static void fp_out_info(FILE * out, field_ptr f) {
+ element_fprintf(out, "GF(%Zd): Montgomery representation", f->order);
+}
+
+void field_init_mont_fp(field_ptr f, mpz_t prime) {
+ PBC_ASSERT(!mpz_fits_ulong_p(prime), "modulus too small");
+ fptr p;
+ field_init(f);
+ f->init = fp_init;
+ f->clear = fp_clear;
+ f->set_si = fp_set_si;
+ f->set_mpz = fp_set_mpz;
+ f->out_str = fp_out_str;
+ f->snprint = fp_snprint;
+ f->set_str = fp_set_str;
+ f->add = fp_add;
+ f->sub = fp_sub;
+ f->set = fp_set;
+ f->mul = fp_mul;
+ f->doub = fp_double;
+ f->halve = fp_halve;
+ f->pow_mpz = fp_pow_mpz;
+ f->neg = fp_neg;
+ f->sign = fp_sgn_odd;
+ f->cmp = fp_cmp;
+ f->invert = fp_invert;
+ f->random = fp_random;
+ f->from_hash = fp_from_hash;
+ f->is1 = fp_is1;
+ f->is0 = fp_is0;
+ f->set0 = fp_set0;
+ f->set1 = fp_set1;
+ f->is_sqr = fp_is_sqr;
+ f->sqrt = element_tonelli;
+ f->field_clear = fp_field_clear;
+ f->to_bytes = fp_to_bytes;
+ f->from_bytes = fp_from_bytes;
+ f->to_mpz = fp_to_mpz;
+ f->out_info = fp_out_info;
+
+ // Initialize per-field data specific to this implementation.
+ p = f->data = pbc_malloc(sizeof(*p));
+ p->limbs = mpz_size(prime);
+ p->bytes = p->limbs * sizeof(mp_limb_t);
+ p->primelimbs = pbc_malloc(p->bytes);
+ mpz_export(p->primelimbs, &p->limbs, -1, sizeof(mp_limb_t), 0, 0, prime);
+
+ mpz_set(f->order, prime);
+ f->fixed_length_in_bytes = (mpz_sizeinbase(prime, 2) + 7) / 8;
+
+ // Compute R, R3 and negpinv.
+ mpz_t z;
+ mpz_init(z);
+
+ p->R = pbc_malloc(p->bytes);
+ p->R3 = pbc_malloc(p->bytes);
+ mpz_setbit(z, p->bytes * 8);
+ mpz_mod(z, z, prime);
+ set_limbs(p->R, z, p->limbs);
+
+ mpz_powm_ui(z, z, 3, prime);
+ set_limbs(p->R3, z, p->limbs);
+
+ mpz_set_ui(z, 0);
+
+ // Algorithm II.5 in Blake, Seroussi and Smart is better but this suffices
+ // since we're only doing it once.
+ mpz_setbit(z, p->bytes * 8);
+ mpz_invert(z, prime, z);
+ p->negpinv = -mpz_get_ui(z);
+ mpz_clear(z);
+}
diff --git a/moon-abe/pbc-0.5.14/arith/multiz.c b/moon-abe/pbc-0.5.14/arith/multiz.c
new file mode 100644
index 00000000..6c8b43cc
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/multiz.c
@@ -0,0 +1,589 @@
+// Multinomials over Z.
+// e.g. [[1, 2], 3, [4, [5, 6]]] means
+// (1 + 2y) + 3 x + (4 + (5 + 6z)y)x^2
+// Convenient interchange format for different groups, rings, and fields.
+
+// TODO: Canonicalize, e.g. [[1]], 0, 0] --> 1.
+
+#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_multiz.h"
+#include "pbc_random.h"
+#include "pbc_fp.h"
+#include "pbc_memory.h"
+#include "misc/darray.h"
+
+// Per-element data.
+struct multiz_s {
+ // Either it's an mpz, or a list of mpzs.
+ char type;
+ union {
+ mpz_t z;
+ darray_t a;
+ };
+};
+
+enum {
+ T_MPZ,
+ T_ARR,
+};
+
+static multiz multiz_new_empty_list(void) {
+ multiz ep = pbc_malloc(sizeof(*ep));
+ ep->type = T_ARR;
+ darray_init(ep->a);
+ return ep;
+}
+
+void multiz_append(element_ptr x, element_ptr e) {
+ multiz l = x->data;
+ darray_append(l->a, e->data);
+}
+
+static multiz multiz_new(void) {
+ multiz ep = pbc_malloc(sizeof(*ep));
+ ep->type = T_MPZ;
+ mpz_init(ep->z);
+ return ep;
+}
+
+static void f_init(element_ptr e) {
+ e->data = multiz_new();
+}
+
+static void multiz_free(multiz ep) {
+ switch(ep->type) {
+ case T_MPZ:
+ mpz_clear(ep->z);
+ break;
+ default:
+ PBC_ASSERT(T_ARR == ep->type, "no such type");
+ darray_forall(ep->a, (void(*)(void*))multiz_free);
+ darray_clear(ep->a);
+ break;
+ }
+ pbc_free(ep);
+}
+
+static void f_clear(element_ptr e) {
+ multiz_free(e->data);
+}
+
+element_ptr multiz_new_list(element_ptr e) {
+ element_ptr x = pbc_malloc(sizeof(*x));
+ element_init_same_as(x, e);
+ multiz_free(x->data);
+ x->data = multiz_new_empty_list();
+ multiz_append(x, e);
+ return x;
+}
+
+static void f_set_si(element_ptr e, signed long int op) {
+ multiz_free(e->data);
+ f_init(e);
+ multiz ep = e->data;
+ mpz_set_si(ep->z, op);
+}
+
+static void f_set_mpz(element_ptr e, mpz_ptr z) {
+ multiz_free(e->data);
+ f_init(e);
+ multiz ep = e->data;
+ mpz_set(ep->z, z);
+}
+
+static void f_set0(element_ptr e) {
+ multiz_free(e->data);
+ f_init(e);
+}
+
+static void f_set1(element_ptr e) {
+ multiz_free(e->data);
+ f_init(e);
+ multiz ep = e->data;
+ mpz_set_ui(ep->z, 1);
+}
+
+static size_t multiz_out_str(FILE *stream, int base, multiz ep) {
+ switch(ep->type) {
+ case T_MPZ:
+ return mpz_out_str(stream, base, ep->z);
+ default:
+ PBC_ASSERT(T_ARR == ep->type, "no such type");
+ fputc('[', stream);
+ size_t res = 1;
+ int n = darray_count(ep->a);
+ int i;
+ for(i = 0; i < n; i++) {
+ if (i) res += 2, fputs(", ", stream);
+ res += multiz_out_str(stream, base, darray_at(ep->a, i));
+ }
+ fputc(']', stream);
+ res++;
+ return res;
+ }
+}
+
+static size_t f_out_str(FILE *stream, int base, element_ptr e) {
+ return multiz_out_str(stream, base, e->data);
+}
+
+void multiz_to_mpz(mpz_ptr z, multiz ep) {
+ while(ep->type == T_ARR) ep = darray_at(ep->a, 0);
+ PBC_ASSERT(T_MPZ == ep->type, "no such type");
+ mpz_set(z, ep->z);
+}
+
+static void f_to_mpz(mpz_ptr z, element_ptr a) {
+ multiz_to_mpz(z, a->data);
+}
+
+static int multiz_sgn(multiz ep) {
+ while(ep->type == T_ARR) ep = darray_at(ep->a, 0);
+ PBC_ASSERT(T_MPZ == ep->type, "no such type");
+ return mpz_sgn(ep->z);
+}
+
+static int f_sgn(element_ptr a) {
+ return multiz_sgn(a->data);
+}
+
+static void add_to_x(void *data,
+ multiz x,
+ void (*fun)(mpz_t, const mpz_t, void *scope_ptr),
+ void *scope_ptr);
+
+static multiz multiz_new_unary(const multiz y,
+ void (*fun)(mpz_t, const mpz_t, void *scope_ptr), void *scope_ptr) {
+ multiz x = pbc_malloc(sizeof(*x));
+ switch(y->type) {
+ case T_MPZ:
+ x->type = T_MPZ;
+ mpz_init(x->z);
+ fun(x->z, y->z, scope_ptr);
+ break;
+ default:
+ PBC_ASSERT(T_ARR == ep->type, "no such type");
+ x->type = T_ARR;
+ darray_init(x->a);
+ darray_forall4(y->a,
+ (void(*)(void*,void*,void*,void*))add_to_x,
+ x,
+ fun,
+ scope_ptr);
+ break;
+ }
+ return x;
+}
+
+static void add_to_x(void *data,
+ multiz x,
+ void (*fun)(mpz_t, const mpz_t, void *scope_ptr),
+ void *scope_ptr) {
+ darray_append(x->a, multiz_new_unary(data, fun, scope_ptr));
+}
+
+static void mpzset(mpz_t dst, const mpz_t src, void *scope_ptr) {
+ UNUSED_VAR(scope_ptr);
+ mpz_set(dst, src);
+}
+
+static multiz multiz_clone(multiz y) {
+ return multiz_new_unary(y, (void(*)(mpz_t, const mpz_t, void *))mpzset, NULL);
+}
+
+static multiz multiz_new_bin(const multiz a, const multiz b,
+ void (*fun)(mpz_t, const mpz_t, const mpz_t)) {
+ if (T_MPZ == a->type) {
+ if (T_MPZ == b->type) {
+ multiz x = multiz_new();
+ fun(x->z, a->z, b->z);
+ return x;
+ } else {
+ multiz x = multiz_clone(b);
+ multiz z = x;
+ PBC_ASSERT(T_ARR == z->type, "no such type");
+ while(z->type == T_ARR) z = darray_at(z->a, 0);
+ fun(z->z, a->z, z->z);
+ return x;
+ }
+ } else {
+ PBC_ASSERT(T_ARR == a->type, "no such type");
+ if (T_MPZ == b->type) {
+ multiz x = multiz_clone(a);
+ multiz z = x;
+ PBC_ASSERT(T_ARR == z->type, "no such type");
+ while(z->type == T_ARR) z = darray_at(z->a, 0);
+ fun(z->z, b->z, z->z);
+ return x;
+ } else {
+ PBC_ASSERT(T_ARR == b->type, "no such type");
+ int m = darray_count(a->a);
+ int n = darray_count(b->a);
+ int min = m < n ? m : n;
+ int max = m > n ? m : n;
+ multiz x = multiz_new_empty_list();
+ int i;
+ for(i = 0; i < min; i++) {
+ multiz z = multiz_new_bin(darray_at(a->a, i), darray_at(b->a, i), fun);
+ darray_append(x->a, z);
+ }
+ multiz zero = multiz_new();
+ for(; i < max; i++) {
+ multiz z = multiz_new_bin(m > n ? darray_at(a->a, i) : zero,
+ n > m ? darray_at(b->a, i) : zero,
+ fun);
+ darray_append(x->a, z);
+ }
+ multiz_free(zero);
+ return x;
+ }
+ }
+}
+static multiz multiz_new_add(const multiz a, const multiz b) {
+ return multiz_new_bin(a, b, mpz_add);
+}
+
+static void f_add(element_ptr n, element_ptr a, element_ptr b) {
+ multiz delme = n->data;
+ n->data = multiz_new_add(a->data, b->data);
+ multiz_free(delme);
+}
+
+static multiz multiz_new_sub(const multiz a, const multiz b) {
+ return multiz_new_bin(a, b, mpz_sub);
+}
+static void f_sub(element_ptr n, element_ptr a, element_ptr b) {
+ multiz delme = n->data;
+ n->data = multiz_new_sub(a->data, b->data);
+ multiz_free(delme);
+}
+
+static void mpzmul(mpz_t x, const mpz_t y, const mpz_t z) {
+ mpz_mul(x, y, z);
+}
+
+static multiz multiz_new_mul(const multiz a, const multiz b) {
+ if (T_MPZ == a->type) {
+ // Multiply each coefficient of b by a->z.
+ return multiz_new_unary(b, (void(*)(mpz_t, const mpz_t, void *))mpzmul, a->z);
+ } else {
+ PBC_ASSERT(T_ARR == a->type, "no such type");
+ if (T_MPZ == b->type) {
+ // Multiply each coefficient of a by b->z.
+ return multiz_new_unary(a, (void(*)(mpz_t, const mpz_t, void *))mpzmul, b->z);
+ } else {
+ PBC_ASSERT(T_ARR == b->type, "no such type");
+ int m = darray_count(a->a);
+ int n = darray_count(b->a);
+ int max = m + n - 1;
+ multiz x = multiz_new_empty_list();
+ int i;
+ multiz zero = multiz_new();
+ for(i = 0; i < max; i++) {
+ multiz z = multiz_new();
+ int j;
+ for (j = 0; j <= i; j++) {
+ multiz y = multiz_new_mul(j < m ? darray_at(a->a, j) : zero,
+ i - j < n ? darray_at(b->a, i - j) : zero);
+ multiz t = multiz_new_add(z, y);
+ multiz_free(y);
+ multiz_free(z);
+ z = t;
+ }
+ darray_append(x->a, z);
+ }
+ multiz_free(zero);
+ return x;
+ }
+ }
+}
+static void f_mul(element_ptr n, element_ptr a, element_ptr b) {
+ multiz delme = n->data;
+ n->data = multiz_new_mul(a->data, b->data);
+ multiz_free(delme);
+}
+
+static void f_mul_mpz(element_ptr n, element_ptr a, mpz_ptr z) {
+ multiz delme = n->data;
+ n->data = multiz_new_unary(a->data, (void(*)(mpz_t, const mpz_t, void *))mpzmul, z);
+ multiz_free(delme);
+}
+
+static void mulsi(mpz_t x, const mpz_t y, signed long *i) {
+ mpz_mul_si(x, y, *i);
+}
+
+static void f_mul_si(element_ptr n, element_ptr a, signed long int z) {
+ multiz delme = n->data;
+ n->data = multiz_new_unary(a->data, (void(*)(mpz_t, const mpz_t, void *))mulsi, &z);
+ multiz_free(delme);
+}
+
+static void mpzneg(mpz_t dst, const mpz_t src, void *scope_ptr) {
+ UNUSED_VAR(scope_ptr);
+ mpz_neg(dst, src);
+}
+
+static multiz multiz_new_neg(multiz z) {
+ return multiz_new_unary(z, (void(*)(mpz_t, const mpz_t, void *))mpzneg, NULL);
+}
+
+static void f_set(element_ptr n, element_ptr a) {
+ multiz delme = n->data;
+ n->data = multiz_clone(a->data);
+ multiz_free(delme);
+}
+
+static void f_neg(element_ptr n, element_ptr a) {
+ multiz delme = n->data;
+ n->data = multiz_new_neg(a->data);
+ multiz_free(delme);
+}
+
+static void f_div(element_ptr c, element_ptr a, element_ptr b) {
+ mpz_t d;
+ mpz_init(d);
+ element_to_mpz(d, b);
+ multiz delme = c->data;
+ c->data = multiz_new_unary(a->data, (void(*)(mpz_t, const mpz_t, void *))mpz_tdiv_q, d);
+ mpz_clear(d);
+ multiz_free(delme);
+}
+
+// Doesn't make sense if order is infinite.
+static void f_random(element_ptr n) {
+ multiz delme = n->data;
+ f_init(n);
+ multiz_free(delme);
+}
+
+static void f_from_hash(element_ptr n, void *data, int len) {
+ mpz_t z;
+ mpz_init(z);
+ mpz_import(z, len, -1, 1, -1, 0, data);
+ f_set_mpz(n, z);
+ mpz_clear(z);
+}
+
+static int f_is1(element_ptr n) {
+ multiz ep = n->data;
+ return ep->type == T_MPZ && !mpz_cmp_ui(ep->z, 1);
+}
+
+int multiz_is0(multiz m) {
+ return m->type == T_MPZ && mpz_is0(m->z);
+}
+
+static int f_is0(element_ptr n) {
+ return multiz_is0(n->data);
+}
+
+static int f_item_count(element_ptr e) {
+ multiz z = e->data;
+ if (T_MPZ == z->type) return 0;
+ return darray_count(z->a);
+}
+
+// TODO: Redesign multiz so this doesn't leak.
+static element_ptr f_item(element_ptr e, int i) {
+ multiz z = e->data;
+ if (T_MPZ == z->type) return NULL;
+ element_ptr r = malloc(sizeof(*r));
+ r->field = e->field;
+ r->data = darray_at(z->a, i);
+ return r;
+}
+
+// Usual meaning when both are integers.
+// Otherwise, compare coefficients.
+static int multiz_cmp(multiz a, multiz b) {
+ if (T_MPZ == a->type) {
+ if (T_MPZ == b->type) {
+ // Simplest case: both are integers.
+ return mpz_cmp(a->z, b->z);
+ }
+ // Leading coefficient of b.
+ while(T_ARR == b->type) b = darray_last(b->a);
+ PBC_ASSERT(T_MPZ == b->type, "no such type");
+ return -mpz_sgn(b->z);
+ }
+ PBC_ASSERT(T_ARR == a->type, "no such type");
+ if (T_MPZ == b->type) {
+ // Leading coefficient of a.
+ while(T_ARR == a->type) a = darray_last(a->a);
+ PBC_ASSERT(T_MPZ == a->type, "no such type");
+ return mpz_sgn(a->z);
+ }
+ PBC_ASSERT(T_ARR == b->type, "no such type");
+ int m = darray_count(a->a);
+ int n = darray_count(b->a);
+ if (m > n) {
+ // Leading coefficient of a.
+ while(T_ARR == a->type) a = darray_last(a->a);
+ PBC_ASSERT(T_MPZ == a->type, "no such type");
+ return mpz_sgn(a->z);
+ }
+ if (n > m) {
+ // Leading coefficient of b.
+ while(T_ARR == b->type) b = darray_last(b->a);
+ PBC_ASSERT(T_MPZ == b->type, "no such type");
+ return -mpz_sgn(b->z);
+ }
+ for(n--; n >= 0; n--) {
+ int i = multiz_cmp(darray_at(a->a, n), darray_at(b->a, n));
+ if (i) return i;
+ }
+ return 0;
+}
+static int f_cmp(element_ptr x, element_ptr y) {
+ return multiz_cmp(x->data, y->data);
+}
+
+static void f_field_clear(field_t f) { UNUSED_VAR (f); }
+
+// OpenSSL convention:
+// 4 bytes containing length
+// followed by number in big-endian, most-significant bit set if negative
+// (prepending null byte if necessary)
+// Positive numbers also the same as mpz_out_raw.
+static int z_to_bytes(unsigned char *data, element_t e) {
+ mpz_ptr z = e->data;
+ size_t msb = mpz_sizeinbase(z, 2);
+ size_t n = 4;
+ size_t i;
+
+ if (!(msb % 8)) {
+ data[4] = 0;
+ n++;
+ }
+ if (mpz_sgn(z) < 0) {
+ mpz_export(data + n, NULL, 1, 1, 1, 0, z);
+ data[4] |= 128;
+ } else {
+ mpz_export(data + n, NULL, 1, 1, 1, 0, z);
+ }
+ n += (msb + 7) / 8 - 4;
+ for (i=0; i<4; i++) {
+ data[i] = (n >> 8 * (3 - i));
+ }
+ n += 4;
+
+ return n;
+}
+
+static int z_from_bytes(element_t e, unsigned char *data) {
+ unsigned char *ptr;
+ size_t i, n;
+ mpz_ptr z = e->data;
+ mpz_t z1;
+ int neg = 0;
+
+ mpz_init(z1);
+ mpz_set_ui(z, 0);
+
+ ptr = data;
+ n = 0;
+ for (i=0; i<4; i++) {
+ n += ((unsigned int) *ptr) << 8 * (3 - i);
+ ptr++;
+ }
+ if (data[4] & 128) {
+ neg = 1;
+ data[4] &= 127;
+ }
+ for (i=0; i<n; i++) {
+ mpz_set_ui(z1, *ptr);
+ mpz_mul_2exp(z1, z1, 8 * (n - 1 - i));
+ ptr++;
+ mpz_add(z, z, z1);
+ }
+ mpz_clear(z1);
+ if (neg) mpz_neg(z, z);
+ return n;
+}
+
+static int z_length_in_bytes(element_ptr a) {
+ return (mpz_sizeinbase(a->data, 2) + 7) / 8 + 4;
+}
+
+static void f_out_info(FILE *out, field_ptr f) {
+ UNUSED_VAR(f);
+ fprintf(out, "Z multinomials");
+}
+
+static int f_set_str(element_ptr e, const char *s, int base) {
+ // TODO: Square brackets.
+ mpz_t z;
+ mpz_init(z);
+ int result = pbc_mpz_set_str(z, s, base);
+ f_set_mpz(e, z);
+ mpz_clear(z);
+ return result;
+}
+
+static void f_set_multiz(element_ptr e, multiz m) {
+ multiz delme = e->data;
+ e->data = multiz_clone(m);
+ multiz_free(delme);
+}
+
+void field_init_multiz(field_ptr f) {
+ field_init(f);
+ f->init = f_init;
+ f->clear = f_clear;
+ f->set_si = f_set_si;
+ f->set_mpz = f_set_mpz;
+ f->set_multiz = f_set_multiz;
+ f->set_str = f_set_str;
+ f->out_str = f_out_str;
+ f->sign = f_sgn;
+ f->add = f_add;
+ f->sub = f_sub;
+ f->set = f_set;
+ f->mul = f_mul;
+ f->mul_mpz = f_mul_mpz;
+ f->mul_si = f_mul_si;
+ f->neg = f_neg;
+ f->cmp = f_cmp;
+ f->div = f_div;
+ f->random = f_random;
+ f->from_hash = f_from_hash;
+ f->is1 = f_is1;
+ f->is0 = f_is0;
+ f->set0 = f_set0;
+ f->set1 = f_set1;
+ f->field_clear = f_field_clear;
+ f->to_bytes = z_to_bytes;
+ f->from_bytes = z_from_bytes;
+ f->to_mpz = f_to_mpz;
+ f->length_in_bytes = z_length_in_bytes;
+ f->item = f_item;
+ f->item_count = f_item_count;
+
+ f->out_info = f_out_info;
+
+ mpz_set_ui(f->order, 0);
+ f->data = NULL;
+ f->fixed_length_in_bytes = -1;
+}
+
+int multiz_is_z(multiz m) {
+ return T_MPZ == m->type;
+}
+
+int multiz_count(multiz m) {
+ if (T_ARR != m->type) return -1;
+ return darray_count(m->a);
+}
+
+multiz multiz_at(multiz m, int i) {
+ PBC_ASSERT(T_ARR == m->type, "wrong type");
+ PBC_ASSERT(darray_count(m->a) > i, "out of bounds");
+ return darray_at(m->a, i);
+}
diff --git a/moon-abe/pbc-0.5.14/arith/naivefp.c b/moon-abe/pbc-0.5.14/arith/naivefp.c
new file mode 100644
index 00000000..ceb1b7fb
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/naivefp.c
@@ -0,0 +1,270 @@
+// Naive implementation of F_p.
+// Little more than wrappers around GMP mpz functions.
+
+#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_random.h"
+#include "pbc_fp.h"
+#include "pbc_memory.h"
+
+static void zp_init(element_ptr e) {
+ e->data = pbc_malloc(sizeof(mpz_t));
+ mpz_init(e->data);
+}
+
+static void zp_clear(element_ptr e) {
+ mpz_clear(e->data);
+ pbc_free(e->data);
+}
+
+static void zp_set_si(element_ptr e, signed long int op) {
+ mpz_set_si(e->data, op);
+ mpz_mod(e->data, e->data, e->field->order);
+}
+
+static void zp_set_mpz(element_ptr e, mpz_ptr z) {
+ mpz_set(e->data, z);
+ mpz_mod(e->data, e->data, e->field->order);
+}
+
+static void zp_set0(element_ptr e) {
+ mpz_set_si(e->data, 0);
+}
+
+static void zp_set1(element_ptr e) {
+ mpz_set_si(e->data, 1);
+}
+
+static size_t zp_out_str(FILE * stream, int base, element_ptr e) {
+ return mpz_out_str(stream, base, e->data);
+}
+
+static int zp_snprint(char *s, size_t n, element_ptr e) {
+ return gmp_snprintf(s, n, "%Zd", e->data);
+}
+
+static int zp_set_str(element_ptr e, const char *s, int base) {
+ int result = pbc_mpz_set_str(e->data, s, base);
+ mpz_mod(e->data, e->data, e->field->order);
+ return result;
+}
+
+static int zp_sgn_odd(element_ptr a) {
+ mpz_ptr z = a->data;
+
+ return mpz_is0(z) ? 0 : (mpz_odd_p(z) ? 1 : -1);
+}
+
+static int zp_sgn_even(element_ptr a) {
+ mpz_t z;
+ mpz_init(z);
+ int res;
+
+ if (mpz_is0(a->data)) {
+ res = 0;
+ } else {
+ mpz_add(z, a->data, a->data);
+ res = mpz_cmp(z, a->field->order);
+ }
+ mpz_clear(z);
+ return res;
+}
+
+static void zp_add(element_ptr n, element_ptr a, element_ptr b) {
+ /*
+ mpz_add(n->data, a->data, b->data);
+ mpz_mod(n->data, n->data, n->field->order);
+ */
+ //This seems faster:
+ mpz_add(n->data, a->data, b->data);
+ if (mpz_cmp(n->data, n->field->order) >= 0) {
+ mpz_sub(n->data, n->data, n->field->order);
+ }
+}
+
+static void zp_sub(element_ptr n, element_ptr a, element_ptr b) {
+ //mpz_sub(n->data, a->data, b->data);
+ //mpz_mod(n->data, n->data, n->field->order);
+ mpz_sub(n->data, a->data, b->data);
+ if (mpz_sgn((mpz_ptr) n->data) < 0) {
+ mpz_add(n->data, n->data, n->field->order);
+ }
+}
+
+static void zp_square(element_ptr c, element_ptr a) {
+ /*
+ mpz_mul(c->data, a->data, a->data);
+ mpz_mod(c->data, c->data, c->field->order);
+ */
+ mpz_powm_ui(c->data, a->data, 2, c->field->order);
+
+ /*
+ const mpz_ptr prime = c->field->order;
+ const size_t t = prime->_mp_size;
+ const mpz_ptr p = a->data;
+ const mpz_ptr r = c->data;
+ mp_limb_t tmp[2 * t];
+ mp_limb_t qp[t + 1];
+
+ mpn_mul_n(tmp, p->_mp_d, p->_mp_d, t);
+
+ mpn_tdiv_qr(qp, r->_mp_d, 0, tmp, 2 * t, prime->_mp_d, t);
+ */
+}
+
+static void zp_double(element_ptr n, element_ptr a) {
+ //mpz_add(n->data, a->data, a->data);
+ mpz_mul_2exp(n->data, a->data, 1);
+ if (mpz_cmp(n->data, n->field->order) >= 0) {
+ mpz_sub(n->data, n->data, n->field->order);
+ }
+}
+
+static void zp_halve(element_ptr n, element_ptr a) {
+ mpz_ptr z = a->data;
+ if (mpz_odd_p(z)) {
+ mpz_add(n->data, z, a->field->order);
+ mpz_tdiv_q_2exp(n->data, n->data, 1);
+ } else {
+ mpz_tdiv_q_2exp(n->data, a->data, 1);
+ }
+}
+
+static void zp_mul(element_ptr n, element_ptr a, element_ptr b) {
+ mpz_mul(n->data, a->data, b->data);
+ mpz_mod(n->data, n->data, n->field->order);
+}
+
+static void zp_mul_mpz(element_ptr n, element_ptr a, mpz_ptr z) {
+ mpz_mul(n->data, a->data, z);
+ mpz_mod(n->data, n->data, n->field->order);
+}
+
+static void zp_mul_si(element_ptr n, element_ptr a, signed long int z) {
+ mpz_mul_si(n->data, a->data, z);
+ mpz_mod(n->data, n->data, n->field->order);
+}
+
+static void zp_pow_mpz(element_ptr n, element_ptr a, mpz_ptr z) {
+ mpz_powm(n->data, a->data, z, n->field->order);
+}
+
+static void zp_set(element_ptr n, element_ptr a) {
+ mpz_set(n->data, a->data);
+}
+
+static void zp_neg(element_ptr n, element_ptr a) {
+ if (mpz_is0(a->data)) {
+ mpz_set_ui(n->data, 0);
+ } else {
+ mpz_sub(n->data, n->field->order, a->data);
+ }
+}
+
+static void zp_invert(element_ptr n, element_ptr a) {
+ mpz_invert(n->data, a->data, n->field->order);
+}
+
+static void zp_random(element_ptr n) {
+ pbc_mpz_random(n->data, n->field->order);
+}
+
+static void zp_from_hash(element_ptr n, void *data, int len) {
+ pbc_mpz_from_hash(n->data, n->field->order, data, len);
+}
+
+static int zp_is1(element_ptr n) {
+ return !mpz_cmp_ui((mpz_ptr) n->data, 1);
+}
+
+static int zp_is0(element_ptr n) {
+ return mpz_is0(n->data);
+}
+
+static int zp_cmp(element_ptr a, element_ptr b) {
+ return mpz_cmp((mpz_ptr) a->data, (mpz_ptr) b->data);
+}
+
+static int zp_is_sqr(element_ptr a) {
+ //0 is a square
+ if (mpz_is0(a->data)) return 1;
+ return mpz_legendre(a->data, a->field->order) == 1;
+}
+
+static void zp_field_clear(field_t f) {
+ UNUSED_VAR(f);
+}
+
+static int zp_to_bytes(unsigned char *data, element_t e) {
+ int n;
+
+ n = e->field->fixed_length_in_bytes;
+
+ pbc_mpz_out_raw_n(data, n, e->data);
+ return n;
+}
+
+static int zp_from_bytes(element_t e, unsigned char *data) {
+ mpz_ptr z = e->data;
+ int n;
+ n = e->field->fixed_length_in_bytes;
+ mpz_import(z, n, 1, 1, 1, 0, data);
+ return n;
+}
+
+static void zp_to_mpz(mpz_ptr z, element_ptr a) {
+ mpz_set(z, a->data);
+}
+
+static void zp_out_info(FILE * out, field_ptr f) {
+ element_fprintf(out, "GF(%Zd), GMP wrapped", f->order);
+}
+
+void field_init_naive_fp(field_ptr f, mpz_t prime) {
+ field_init(f);
+ f->init = zp_init;
+ f->clear = zp_clear;
+ f->set_si = zp_set_si;
+ f->set_mpz = zp_set_mpz;
+ f->out_str = zp_out_str;
+ f->snprint = zp_snprint;
+ f->set_str = zp_set_str;
+ f->sign = mpz_odd_p(prime) ? zp_sgn_odd : zp_sgn_even;
+ f->add = zp_add;
+ f->sub = zp_sub;
+ f->set = zp_set;
+ f->square = zp_square;
+ f->doub = zp_double;
+ f->halve = zp_halve;
+ f->mul = zp_mul;
+ f->mul_mpz = zp_mul_mpz;
+ f->mul_si = zp_mul_si;
+ f->pow_mpz = zp_pow_mpz;
+ f->neg = zp_neg;
+ f->cmp = zp_cmp;
+ f->invert = zp_invert;
+ f->random = zp_random;
+ f->from_hash = zp_from_hash;
+ f->is1 = zp_is1;
+ f->is0 = zp_is0;
+ f->set0 = zp_set0;
+ f->set1 = zp_set1;
+ f->is_sqr = zp_is_sqr;
+ f->sqrt = element_tonelli;
+ f->field_clear = zp_field_clear;
+ f->to_bytes = zp_to_bytes;
+ f->from_bytes = zp_from_bytes;
+ f->to_mpz = zp_to_mpz;
+
+ f->out_info = zp_out_info;
+
+ mpz_set(f->order, prime);
+ f->data = NULL;
+ f->fixed_length_in_bytes = (mpz_sizeinbase(prime, 2) + 7) / 8;
+}
diff --git a/moon-abe/pbc-0.5.14/arith/poly.c b/moon-abe/pbc-0.5.14/arith/poly.c
new file mode 100644
index 00000000..bd2dad33
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/poly.c
@@ -0,0 +1,1724 @@
+#include <ctype.h>
+#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_multiz.h"
+#include "pbc_poly.h"
+#include "pbc_memory.h"
+#include "misc/darray.h"
+
+// == Polynomial rings ==
+//
+// Per-field data:
+typedef struct {
+ field_ptr field; // Ring where coefficients live.
+ fieldmap mapbase; // Map element from underlying field to constant term.
+} *pfptr;
+
+// Per-element data:
+//TODO: Would we ever need any field besides coeff?
+typedef struct {
+ // The coefficients are held in a darray which is resized as needed.
+ // The last array entry represents the leading coefficient and should be
+ // nonzero. An empty darray represents 0.
+ darray_t coeff;
+} *peptr;
+
+// == Polynomial modulo rings ==
+//
+// Per-field data:
+typedef struct {
+ field_ptr field; // Base field.
+ fieldmap mapbase; // Similar to mapbase above.
+ int n; // Degree of extension.
+ element_t poly; // Polynomial of degree n.
+ element_t *xpwr; // x^n,...,x^{2n-2} mod poly
+} *mfptr;
+// Per-element data: just a pointer to an array of element_t. This array always
+// has size n.
+
+// Add or remove coefficients until there are exactly n of them. Any new
+// coefficients are initialized to zero, which violates the invariant that the
+// leading coefficient must be nonzero. Thus routines calling this function
+// must check for this and fix the polynomial if necessary, e.g. by calling
+// poly_remove_leading_zeroes().
+static void poly_alloc(element_ptr e, int n) {
+ pfptr pdp = e->field->data;
+ peptr p = e->data;
+ element_ptr e0;
+ int k = p->coeff->count;
+ while (k < n) {
+ e0 = pbc_malloc(sizeof(element_t));
+ element_init(e0, pdp->field);
+ darray_append(p->coeff, e0);
+ k++;
+ }
+ while (k > n) {
+ k--;
+ e0 = darray_at(p->coeff, k);
+ element_clear(e0);
+ pbc_free(e0);
+ darray_remove_last(p->coeff);
+ }
+}
+
+static void poly_init(element_ptr e) {
+ peptr p = e->data = pbc_malloc(sizeof(*p));
+ darray_init(p->coeff);
+}
+
+static void poly_clear(element_ptr e) {
+ peptr p = e->data;
+
+ poly_alloc(e, 0);
+ darray_clear(p->coeff);
+ pbc_free(e->data);
+}
+
+// Some operations may zero a leading coefficient, which will cause other
+// routines to fail. After such an operation, this function should be called,
+// as it strips all leading zero coefficients and frees the memory they
+// occupied, reestablishing the guarantee that the last element of the array
+// is nonzero.
+static void poly_remove_leading_zeroes(element_ptr e) {
+ peptr p = e->data;
+ int n = p->coeff->count - 1;
+ while (n >= 0) {
+ element_ptr e0 = p->coeff->item[n];
+ if (!element_is0(e0)) return;
+ element_clear(e0);
+ pbc_free(e0);
+ darray_remove_last(p->coeff);
+ n--;
+ }
+}
+
+static void poly_set0(element_ptr e) {
+ poly_alloc(e, 0);
+}
+
+static void poly_set1(element_ptr e) {
+ peptr p = e->data;
+ element_ptr e0;
+
+ poly_alloc(e, 1);
+ e0 = p->coeff->item[0];
+ element_set1(e0);
+}
+
+static int poly_is0(element_ptr e) {
+ peptr p = e->data;
+ return !p->coeff->count;
+}
+
+static int poly_is1(element_ptr e) {
+ peptr p = e->data;
+ if (p->coeff->count == 1) {
+ return element_is1(p->coeff->item[0]);
+ }
+ return 0;
+}
+
+static void poly_set_si(element_ptr e, signed long int op) {
+ peptr p = e->data;
+ element_ptr e0;
+
+ poly_alloc(e, 1);
+ e0 = p->coeff->item[0];
+ element_set_si(e0, op);
+ poly_remove_leading_zeroes(e);
+}
+
+static void poly_set_mpz(element_ptr e, mpz_ptr op) {
+ peptr p = e->data;
+
+ poly_alloc(e, 1);
+ element_set_mpz(p->coeff->item[0], op);
+ poly_remove_leading_zeroes(e);
+}
+
+static void poly_set_multiz(element_ptr e, multiz op) {
+ if (multiz_is_z(op)) {
+ // TODO: Remove unnecessary copy.
+ mpz_t z;
+ mpz_init(z);
+ multiz_to_mpz(z, op);
+ poly_set_mpz(e, z);
+ mpz_clear(z);
+ return;
+ }
+ peptr p = e->data;
+ int n = multiz_count(op);
+ poly_alloc(e, n);
+ int i;
+ for(i = 0; i < n; i++) {
+ element_set_multiz(p->coeff->item[i], multiz_at(op, i));
+ }
+ poly_remove_leading_zeroes(e);
+}
+
+static void poly_set(element_ptr dst, element_ptr src) {
+ peptr psrc = src->data;
+ peptr pdst = dst->data;
+ int i;
+
+ poly_alloc(dst, psrc->coeff->count);
+ for (i=0; i<psrc->coeff->count; i++) {
+ element_set(pdst->coeff->item[i], psrc->coeff->item[i]);
+ }
+}
+
+static int poly_coeff_count(element_ptr e) {
+ return ((peptr) e->data)->coeff->count;
+}
+
+static element_ptr poly_coeff(element_ptr e, int n) {
+ peptr ep = e->data;
+ PBC_ASSERT(n < poly_coeff_count(e), "coefficient out of range");
+ return (element_ptr) ep->coeff->item[n];
+}
+
+static int poly_sgn(element_ptr f) {
+ int res = 0;
+ int i;
+ int n = poly_coeff_count(f);
+ for (i=0; i<n; i++) {
+ res = element_sgn(poly_coeff(f, i));
+ if (res) break;
+ }
+ return res;
+}
+
+static void poly_add(element_ptr sum, element_ptr f, element_ptr g) {
+ int i, n, n1;
+ element_ptr big;
+
+ n = poly_coeff_count(f);
+ n1 = poly_coeff_count(g);
+ if (n > n1) {
+ big = f;
+ n = n1;
+ n1 = poly_coeff_count(f);
+ } else {
+ big = g;
+ }
+
+ poly_alloc(sum, n1);
+ for (i=0; i<n; i++) {
+ element_add(poly_coeff(sum, i), poly_coeff(f, i), poly_coeff(g, i));
+ }
+ for (; i<n1; i++) {
+ element_set(poly_coeff(sum, i), poly_coeff(big, i));
+ }
+ poly_remove_leading_zeroes(sum);
+}
+
+static void poly_sub(element_ptr diff, element_ptr f, element_ptr g) {
+ int i, n, n1;
+ element_ptr big;
+
+ n = poly_coeff_count(f);
+ n1 = poly_coeff_count(g);
+ if (n > n1) {
+ big = f;
+ n = n1;
+ n1 = poly_coeff_count(f);
+ } else {
+ big = g;
+ }
+
+ poly_alloc(diff, n1);
+ for (i=0; i<n; i++) {
+ element_sub(poly_coeff(diff, i), poly_coeff(f, i), poly_coeff(g, i));
+ }
+ for (; i<n1; i++) {
+ if (big == f) {
+ element_set(poly_coeff(diff, i), poly_coeff(big, i));
+ } else {
+ element_neg(poly_coeff(diff, i), poly_coeff(big, i));
+ }
+ }
+ poly_remove_leading_zeroes(diff);
+}
+
+static void poly_neg(element_ptr f, element_ptr g) {
+ peptr pf = f->data;
+ peptr pg = g->data;
+ int i, n;
+
+ n = pg->coeff->count;
+ poly_alloc(f, n);
+ for (i=0; i<n; i++) {
+ element_neg(pf->coeff->item[i], pg->coeff->item[i]);
+ }
+}
+
+static void poly_double(element_ptr f, element_ptr g) {
+ peptr pf = f->data;
+ peptr pg = g->data;
+ int i, n;
+
+ n = pg->coeff->count;
+ poly_alloc(f, n);
+ for (i=0; i<n; i++) {
+ element_double(pf->coeff->item[i], pg->coeff->item[i]);
+ }
+}
+
+static void poly_mul_mpz(element_ptr f, element_ptr g, mpz_ptr z) {
+ peptr pf = f->data;
+ peptr pg = g->data;
+ int i, n;
+
+ n = pg->coeff->count;
+ poly_alloc(f, n);
+ for (i=0; i<n; i++) {
+ element_mul_mpz(pf->coeff->item[i], pg->coeff->item[i], z);
+ }
+}
+
+static void poly_mul_si(element_ptr f, element_ptr g, signed long int z) {
+ peptr pf = f->data;
+ peptr pg = g->data;
+ int i, n;
+
+ n = pg->coeff->count;
+ poly_alloc(f, n);
+ for (i=0; i<n; i++) {
+ element_mul_si(pf->coeff->item[i], pg->coeff->item[i], z);
+ }
+}
+
+static void poly_mul(element_ptr r, element_ptr f, element_ptr g) {
+ peptr pprod;
+ peptr pf = f->data;
+ peptr pg = g->data;
+ pfptr pdp = r->field->data;
+ int fcount = pf->coeff->count;
+ int gcount = pg->coeff->count;
+ int i, j, n;
+ element_t prod;
+ element_t e0;
+
+ if (!fcount || !gcount) {
+ element_set0(r);
+ return;
+ }
+ element_init(prod, r->field);
+ pprod = prod->data;
+ n = fcount + gcount - 1;
+ poly_alloc(prod, n);
+ element_init(e0, pdp->field);
+ for (i=0; i<n; i++) {
+ element_ptr x = pprod->coeff->item[i];
+ element_set0(x);
+ for (j=0; j<=i; j++) {
+ if (j < fcount && i - j < gcount) {
+ element_mul(e0, pf->coeff->item[j], pg->coeff->item[i - j]);
+ element_add(x, x, e0);
+ }
+ }
+ }
+ poly_remove_leading_zeroes(prod);
+ element_set(r, prod);
+ element_clear(e0);
+ element_clear(prod);
+}
+
+static void polymod_random(element_ptr e) {
+ element_t *coeff = e->data;
+ int i, n = polymod_field_degree(e->field);
+
+ for (i=0; i<n; i++) {
+ element_random(coeff[i]);
+ }
+}
+
+static void polymod_from_hash(element_ptr e, void *data, int len) {
+ // TODO: Improve this.
+ element_t *coeff = e->data;
+ int i, n = polymod_field_degree(e->field);
+ for (i=0; i<n; i++) {
+ element_from_hash(coeff[i], data, len);
+ }
+}
+
+static size_t poly_out_str(FILE *stream, int base, element_ptr e) {
+ int i;
+ int n = poly_coeff_count(e);
+ size_t result = 2, status;
+
+ /*
+ if (!n) {
+ if (EOF == fputs("[0]", stream)) return 0;
+ return 3;
+ }
+ */
+ if (EOF == fputc('[', stream)) return 0;
+ for (i=0; i<n; i++) {
+ if (i) {
+ if (EOF == fputs(", ", stream)) return 0;
+ result += 2;
+ }
+ status = element_out_str(stream, base, poly_coeff(e, i));
+ if (!status) return 0;
+ result += status;
+ }
+ if (EOF == fputc(']', stream)) return 0;
+ return result;
+}
+
+static int poly_snprint(char *s, size_t size, element_ptr e) {
+ int i;
+ int n = poly_coeff_count(e);
+ size_t result = 0, left;
+ int status;
+
+ #define clip_sub() { \
+ result += status; \
+ left = result >= size ? 0 : size - result; \
+ }
+
+ status = snprintf(s, size, "[");
+ if (status < 0) return status;
+ clip_sub();
+
+ for (i=0; i<n; i++) {
+ if (i) {
+ status = snprintf(s + result, left, ", ");
+ if (status < 0) return status;
+ clip_sub();
+ }
+ status = element_snprint(s + result, left, poly_coeff(e, i));
+ 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 poly_div(element_ptr quot, element_ptr rem,
+ element_ptr a, element_ptr b) {
+ peptr pq, pr;
+ pfptr pdp = a->field->data;
+ element_t q, r;
+ element_t binv, e0;
+ element_ptr qe;
+ int m, n;
+ int i, k;
+
+ if (element_is0(b)) pbc_die("division by zero");
+ n = poly_degree(b);
+ m = poly_degree(a);
+ if (n > m) {
+ element_set(rem, a);
+ element_set0(quot);
+ return;
+ }
+ element_init(r, a->field);
+ element_init(q, a->field);
+ element_init(binv, pdp->field);
+ element_init(e0, pdp->field);
+ pq = q->data;
+ pr = r->data;
+ element_set(r, a);
+ k = m - n;
+ poly_alloc(q, k + 1);
+ element_invert(binv, poly_coeff(b, n));
+ while (k >= 0) {
+ qe = pq->coeff->item[k];
+ element_mul(qe, binv, pr->coeff->item[m]);
+ for (i=0; i<=n; i++) {
+ element_mul(e0, qe, poly_coeff(b, i));
+ element_sub(pr->coeff->item[i + k], pr->coeff->item[i + k], e0);
+ }
+ k--;
+ m--;
+ }
+ poly_remove_leading_zeroes(r);
+ element_set(quot, q);
+ element_set(rem, r);
+
+ element_clear(q);
+ element_clear(r);
+ element_clear(e0);
+ element_clear(binv);
+}
+
+static void poly_invert(element_ptr res, element_ptr f, element_ptr m) {
+ element_t q, r0, r1, r2;
+ element_t b0, b1, b2;
+ element_t inv;
+
+ element_init(b0, res->field);
+ element_init(b1, res->field);
+ element_init(b2, res->field);
+ element_init(q, res->field);
+ element_init(r0, res->field);
+ element_init(r1, res->field);
+ element_init(r2, res->field);
+ element_init(inv, poly_base_field(res));
+ element_set0(b0);
+ element_set1(b1);
+ element_set(r0, m);
+ element_set(r1, f);
+
+ for (;;) {
+ poly_div(q, r2, r0, r1);
+ if (element_is0(r2)) break;
+ element_mul(b2, b1, q);
+ element_sub(b2, b0, b2);
+ element_set(b0, b1);
+ element_set(b1, b2);
+ element_set(r0, r1);
+ element_set(r1, r2);
+ }
+ element_invert(inv, poly_coeff(r1, 0));
+ poly_const_mul(res, inv, b1);
+ element_clear(inv);
+ element_clear(q);
+ element_clear(r0);
+ element_clear(r1);
+ element_clear(r2);
+ element_clear(b0);
+ element_clear(b1);
+ element_clear(b2);
+}
+
+static void poly_to_polymod_truncate(element_ptr e, element_ptr f) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i;
+ int n;
+ n = poly_coeff_count(f);
+ if (n > p->n) n = p->n;
+
+ for (i=0; i<n; i++) {
+ element_set(coeff[i], poly_coeff(f, i));
+ }
+ for (; i<p->n; i++) {
+ element_set0(coeff[i]);
+ }
+}
+
+static void polymod_to_poly(element_ptr f, element_ptr e) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+ poly_alloc(f, n);
+ for (i=0; i<n; i++) {
+ element_set(poly_coeff(f, i), coeff[i]);
+ }
+ poly_remove_leading_zeroes(f);
+}
+
+static void polymod_invert(element_ptr r, element_ptr e) {
+ mfptr p = r->field->data;
+ element_ptr minpoly = p->poly;
+ element_t f, r1;
+
+ element_init(f, minpoly->field);
+ element_init(r1, minpoly->field);
+ polymod_to_poly(f, e);
+
+ poly_invert(r1, f, p->poly);
+
+ poly_to_polymod_truncate(r, r1);
+
+ element_clear(f);
+ element_clear(r1);
+}
+
+static int poly_cmp(element_ptr f, element_ptr g) {
+ int i;
+ int n = poly_coeff_count(f);
+ int n1 = poly_coeff_count(g);
+ if (n != n1) return 1;
+ for (i=0; i<n; i++) {
+ if (element_cmp(poly_coeff(f, i), poly_coeff(g, i))) return 1;
+ }
+ return 0;
+}
+
+static void field_clear_poly(field_ptr f) {
+ pfptr p = f->data;
+ pbc_free(p);
+}
+
+// 2 bytes hold the number of terms, then the terms follow.
+// Bad for sparse polynomials.
+static int poly_length_in_bytes(element_t p) {
+ int count = poly_coeff_count(p);
+ int result = 2;
+ int i;
+ for (i=0; i<count; i++) {
+ result += element_length_in_bytes(poly_coeff(p, i));
+ }
+ return result;
+}
+
+static int poly_to_bytes(unsigned char *buf, element_t p) {
+ int count = poly_coeff_count(p);
+ int result = 2;
+ int i;
+ buf[0] = (unsigned char) count;
+ buf[1] = (unsigned char) (count >> 8);
+ for (i=0; i<count; i++) {
+ result += element_to_bytes(&buf[result], poly_coeff(p, i));
+ }
+ return result;
+}
+
+static int poly_from_bytes(element_t p, unsigned char *buf) {
+ int result = 2;
+ int count = buf[0] + buf[1] * 256;
+ int i;
+ poly_alloc(p, count);
+ for (i=0; i<count; i++) {
+ result += element_from_bytes(poly_coeff(p, i), &buf[result]);
+ }
+ return result;
+}
+
+// Is this useful? This returns to_mpz(constant term).
+static void poly_to_mpz(mpz_t z, element_ptr e) {
+ if (!poly_coeff_count(e)) {
+ mpz_set_ui(z, 0);
+ } else {
+ element_to_mpz(z, poly_coeff(e, 0));
+ }
+}
+
+static void poly_out_info(FILE *str, field_ptr f) {
+ pfptr p = f->data;
+ fprintf(str, "Polynomial ring over ");
+ field_out_info(str, p->field);
+}
+
+static void field_clear_polymod(field_ptr f) {
+ mfptr p = f->data;
+ int i, n = p->n;
+
+ for (i=0; i<n; i++) {
+ element_clear(p->xpwr[i]);
+ }
+ pbc_free(p->xpwr);
+
+ element_clear(p->poly);
+ pbc_free(f->data);
+}
+
+static int polymod_is_sqr(element_ptr e) {
+ int res;
+ mpz_t z;
+ element_t e0;
+
+ element_init(e0, e->field);
+ mpz_init(z);
+ mpz_sub_ui(z, e->field->order, 1);
+ mpz_divexact_ui(z, z, 2);
+
+ element_pow_mpz(e0, e, z);
+ res = element_is1(e0);
+ element_clear(e0);
+ mpz_clear(z);
+ return res;
+}
+
+// Find a square root in a polynomial modulo ring using Cantor-Zassenhaus aka
+// Legendre's method.
+static void polymod_sqrt(element_ptr res, element_ptr a) {
+ // TODO: Use a faster method? See Bernstein.
+ field_t kx;
+ element_t f;
+ element_t r, s;
+ element_t e0;
+ mpz_t z;
+
+ field_init_poly(kx, a->field);
+ mpz_init(z);
+ element_init(f, kx);
+ element_init(r, kx);
+ element_init(s, kx);
+ element_init(e0, a->field);
+
+ poly_alloc(f, 3);
+ element_set1(poly_coeff(f, 2));
+ element_neg(poly_coeff(f, 0), a);
+
+ mpz_sub_ui(z, a->field->order, 1);
+ mpz_divexact_ui(z, z, 2);
+ for (;;) {
+ int i;
+ element_ptr x;
+ element_ptr e1, e2;
+
+ poly_alloc(r, 2);
+ element_set1(poly_coeff(r, 1));
+ x = poly_coeff(r, 0);
+ element_random(x);
+ element_mul(e0, x, x);
+ if (!element_cmp(e0, a)) {
+ element_set(res, x);
+ break;
+ }
+ element_set1(s);
+ //TODO: this can be optimized greatly
+ //since we know r has the form ax + b
+ for (i = mpz_sizeinbase(z, 2) - 1; i >=0; i--) {
+ element_mul(s, s, s);
+ if (poly_degree(s) == 2) {
+ e1 = poly_coeff(s, 0);
+ e2 = poly_coeff(s, 2);
+ element_mul(e0, e2, a);
+ element_add(e1, e1, e0);
+ poly_alloc(s, 2);
+ poly_remove_leading_zeroes(s);
+ }
+ if (mpz_tstbit(z, i)) {
+ element_mul(s, s, r);
+ if (poly_degree(s) == 2) {
+ e1 = poly_coeff(s, 0);
+ e2 = poly_coeff(s, 2);
+ element_mul(e0, e2, a);
+ element_add(e1, e1, e0);
+ poly_alloc(s, 2);
+ poly_remove_leading_zeroes(s);
+ }
+ }
+ }
+ if (poly_degree(s) < 1) continue;
+ element_set1(e0);
+ e1 = poly_coeff(s, 0);
+ e2 = poly_coeff(s, 1);
+ element_add(e1, e1, e0);
+ element_invert(e0, e2);
+ element_mul(e0, e0, e1);
+ element_mul(e2, e0, e0);
+ if (!element_cmp(e2, a)) {
+ element_set(res, e0);
+ break;
+ }
+ }
+
+ mpz_clear(z);
+ element_clear(f);
+ element_clear(r);
+ element_clear(s);
+ element_clear(e0);
+ field_clear(kx);
+}
+
+static int polymod_to_bytes(unsigned char *data, element_t f) {
+ mfptr p = f->field->data;
+ element_t *coeff = f->data;
+ int i, n = p->n;
+ int len = 0;
+ for (i=0; i<n; i++) {
+ len += element_to_bytes(data + len, coeff[i]);
+ }
+ return len;
+}
+
+static int polymod_length_in_bytes(element_t f) {
+ mfptr p = f->field->data;
+ element_t *coeff = f->data;
+ int i, n = p->n;
+ int res = 0;
+
+ for (i=0; i<n; i++) {
+ res += element_length_in_bytes(coeff[i]);
+ }
+
+ return res;
+}
+
+static int polymod_from_bytes(element_t f, unsigned char *data) {
+ mfptr p = f->field->data;
+ element_t *coeff = f->data;
+ int i, n = p->n;
+ int len = 0;
+
+ for (i=0; i<n; i++) {
+ len += element_from_bytes(coeff[i], data + len);
+ }
+ return len;
+}
+
+static void polymod_init(element_t e) {
+ int i;
+ mfptr p = e->field->data;
+ int n = p->n;
+ element_t *coeff;
+ coeff = e->data = pbc_malloc(sizeof(element_t) * n);
+
+ for (i=0; i<n; i++) {
+ element_init(coeff[i], p->field);
+ }
+}
+
+static void polymod_clear(element_t e) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ element_clear(coeff[i]);
+ }
+ pbc_free(e->data);
+}
+
+static void polymod_set_si(element_t e, signed long int x) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+ element_set_si(coeff[0], x);
+ for (i=1; i<n; i++) {
+ element_set0(coeff[i]);
+ }
+}
+
+static void polymod_set_mpz(element_t e, mpz_t z) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+ element_set_mpz(coeff[0], z);
+ for (i=1; i<n; i++) {
+ element_set0(coeff[i]);
+ }
+}
+
+static void polymod_set(element_t e, element_t f) {
+ mfptr p = e->field->data;
+ element_t *dst = e->data, *src = f->data;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ element_set(dst[i], src[i]);
+ }
+}
+
+static void polymod_neg(element_t e, element_t f) {
+ mfptr p = e->field->data;
+ element_t *dst = e->data, *src = f->data;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ element_neg(dst[i], src[i]);
+ }
+}
+
+static int polymod_cmp(element_ptr f, element_ptr g) {
+ mfptr p = f->field->data;
+ element_t *c1 = f->data, *c2 = g->data;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ if (element_cmp(c1[i], c2[i])) return 1;
+ }
+ return 0;
+}
+
+static void polymod_add(element_t r, element_t e, element_t f) {
+ mfptr p = r->field->data;
+ element_t *dst = r->data, *s1 = e->data, *s2 = f->data;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ element_add(dst[i], s1[i], s2[i]);
+ }
+}
+
+static void polymod_double(element_t r, element_t f) {
+ mfptr p = r->field->data;
+ element_t *dst = r->data, *s1 = f->data;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ element_double(dst[i], s1[i]);
+ }
+}
+
+static void polymod_sub(element_t r, element_t e, element_t f) {
+ mfptr p = r->field->data;
+ element_t *dst = r->data, *s1 = e->data, *s2 = f->data;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ element_sub(dst[i], s1[i], s2[i]);
+ }
+}
+
+static void polymod_mul_mpz(element_t e, element_t f, mpz_ptr z) {
+ mfptr p = e->field->data;
+ element_t *dst = e->data, *src = f->data;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ element_mul_mpz(dst[i], src[i], z);
+ }
+}
+
+static void polymod_mul_si(element_t e, element_t f, signed long int z) {
+ mfptr p = e->field->data;
+ element_t *dst = e->data, *src = f->data;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ element_mul_si(dst[i], src[i], z);
+ }
+}
+
+// Karatsuba multiplication for degree 2 polynomials.
+static void kar_poly_2(element_t *dst, element_t c3, element_t c4, element_t *s1, element_t *s2, element_t *scratch) {
+ element_ptr c01, c02, c12;
+
+ c12 = scratch[0];
+ c02 = scratch[1];
+ c01 = scratch[2];
+
+ element_add(c3, s1[0], s1[1]);
+ element_add(c4, s2[0], s2[1]);
+ element_mul(c01, c3, c4);
+ element_add(c3, s1[0], s1[2]);
+ element_add(c4, s2[0], s2[2]);
+ element_mul(c02, c3, c4);
+ element_add(c3, s1[1], s1[2]);
+ element_add(c4, s2[1], s2[2]);
+ element_mul(c12, c3, c4);
+
+ element_mul(dst[1], s1[1], s2[1]);
+
+ // Constant term.
+ element_mul(dst[0], s1[0], s2[0]);
+
+ // Coefficient of x^4.
+ element_mul(c4, s1[2], s2[2]);
+
+ // Coefficient of x^3.
+ element_add(c3, dst[1], c4);
+ element_sub(c3, c12, c3);
+
+ // Coefficient of x^2.
+ element_add(dst[2], c4, dst[0]);
+ element_sub(c02, c02, dst[2]);
+ element_add(dst[2], dst[1], c02);
+
+ // Coefficient of x.
+ element_sub(c01, c01, dst[0]);
+ element_sub(dst[1], c01, dst[1]);
+}
+
+// Degree 3, 6 polynomial moduli have dedicated routines for multiplication.
+static void polymod_mul_degree3(element_ptr res, element_ptr e, element_ptr f) {
+ mfptr p = res->field->data;
+ element_t *dst = res->data, *s1 = e->data, *s2 = f->data;
+ element_t c3, c4;
+ element_t p0;
+
+ element_init(p0, res->field);
+ element_init(c3, p->field);
+ element_init(c4, p->field);
+
+ kar_poly_2(dst, c3, c4, s1, s2, p0->data);
+
+ polymod_const_mul(p0, c3, p->xpwr[0]);
+ element_add(res, res, p0);
+ polymod_const_mul(p0, c4, p->xpwr[1]);
+ element_add(res, res, p0);
+
+ element_clear(p0);
+ element_clear(c3);
+ element_clear(c4);
+}
+
+static void polymod_mul_degree6(element_ptr res, element_ptr e, element_ptr f) {
+ mfptr p = res->field->data;
+ element_t *dst = res->data, *s0, *s1 = e->data, *s2 = f->data;
+ element_t *a0, *a1, *b0, *b1;
+ element_t p0, p1, p2, p3;
+
+ a0 = s1;
+ a1 = &s1[3];
+ b0 = s2;
+ b1 = &s2[3];
+
+ element_init(p0, res->field);
+ element_init(p1, res->field);
+ element_init(p2, res->field);
+ element_init(p3, res->field);
+
+ s0 = p0->data;
+ s1 = p1->data;
+ s2 = p2->data;
+ element_add(s0[0], a0[0], a1[0]);
+ element_add(s0[1], a0[1], a1[1]);
+ element_add(s0[2], a0[2], a1[2]);
+
+ element_add(s1[0], b0[0], b1[0]);
+ element_add(s1[1], b0[1], b1[1]);
+ element_add(s1[2], b0[2], b1[2]);
+
+ kar_poly_2(s2, s2[3], s2[4], s0, s1, p3->data);
+ kar_poly_2(s0, s0[3], s0[4], a0, b0, p3->data);
+ kar_poly_2(s1, s1[3], s1[4], a1, b1, p3->data);
+
+ element_set(dst[0], s0[0]);
+ element_set(dst[1], s0[1]);
+ element_set(dst[2], s0[2]);
+
+ element_sub(dst[3], s0[3], s0[0]);
+ element_sub(dst[3], dst[3], s1[0]);
+ element_add(dst[3], dst[3], s2[0]);
+
+ element_sub(dst[4], s0[4], s0[1]);
+ element_sub(dst[4], dst[4], s1[1]);
+ element_add(dst[4], dst[4], s2[1]);
+
+ element_sub(dst[5], s2[2], s0[2]);
+ element_sub(dst[5], dst[5], s1[2]);
+
+ // Start reusing part of s0 as scratch space(!)
+ element_sub(s0[0], s2[3], s0[3]);
+ element_sub(s0[0], s0[0], s1[3]);
+ element_add(s0[0], s0[0], s1[0]);
+
+ element_sub(s0[1], s2[4], s0[4]);
+ element_sub(s0[1], s0[1], s1[4]);
+ element_add(s0[1], s0[1], s1[1]);
+
+ polymod_const_mul(p3, s0[0], p->xpwr[0]);
+ element_add(res, res, p3);
+ polymod_const_mul(p3, s0[1], p->xpwr[1]);
+ element_add(res, res, p3);
+ polymod_const_mul(p3, s1[2], p->xpwr[2]);
+ element_add(res, res, p3);
+ polymod_const_mul(p3, s1[3], p->xpwr[3]);
+ element_add(res, res, p3);
+ polymod_const_mul(p3, s1[4], p->xpwr[4]);
+ element_add(res, res, p3);
+
+ element_clear(p0);
+ element_clear(p1);
+ element_clear(p2);
+ element_clear(p3);
+}
+
+// General polynomial modulo ring multiplication.
+static void polymod_mul(element_ptr res, element_ptr e, element_ptr f) {
+ mfptr p = res->field->data;
+ int n = p->n;
+ element_t *dst;
+ element_t *s1 = e->data, *s2 = f->data;
+ element_t prod, p0, c0;
+ int i, j;
+ element_t *high; // Coefficients of x^n, ..., x^{2n-2}.
+
+ high = pbc_malloc(sizeof(element_t) * (n - 1));
+ for (i=0; i<n-1; i++) {
+ element_init(high[i], p->field);
+ element_set0(high[i]);
+ }
+ element_init(prod, res->field);
+ dst = prod->data;
+ element_init(p0, res->field);
+ element_init(c0, p->field);
+
+ for (i=0; i<n; i++) {
+ int ni = n - i;
+ for (j=0; j<ni; j++) {
+ element_mul(c0, s1[i], s2[j]);
+ element_add(dst[i + j], dst[i + j], c0);
+ }
+ for (;j<n; j++) {
+ element_mul(c0, s1[i], s2[j]);
+ element_add(high[j - ni], high[j - ni], c0);
+ }
+ }
+
+ for (i=0; i<n-1; i++) {
+ polymod_const_mul(p0, high[i], p->xpwr[i]);
+ element_add(prod, prod, p0);
+ element_clear(high[i]);
+ }
+ pbc_free(high);
+
+ element_set(res, prod);
+ element_clear(prod);
+ element_clear(p0);
+ element_clear(c0);
+}
+
+static void polymod_square_degree3(element_ptr res, element_ptr e) {
+ // TODO: Investigate if squaring is significantly cheaper than
+ // multiplication. If so convert to Karatsuba.
+ element_t *dst = res->data;
+ element_t *src = e->data;
+ mfptr p = res->field->data;
+ element_t p0;
+ element_t c0, c2;
+ element_ptr c1, c3;
+
+ element_init(p0, res->field);
+ element_init(c0, p->field);
+ element_init(c2, p->field);
+
+ c3 = p0->data;
+ c1 = c3 + 1;
+
+ element_mul(c3, src[0], src[1]);
+ element_mul(c1, src[0], src[2]);
+ element_square(dst[0], src[0]);
+
+ element_mul(c2, src[1], src[2]);
+ element_square(c0, src[2]);
+ element_square(dst[2], src[1]);
+
+ element_add(dst[1], c3, c3);
+
+ element_add(c1, c1, c1);
+ element_add(dst[2], dst[2], c1);
+
+ polymod_const_mul(p0, c0, p->xpwr[1]);
+ element_add(res, res, p0);
+
+ element_add(c2, c2, c2);
+ polymod_const_mul(p0, c2, p->xpwr[0]);
+ element_add(res, res, p0);
+
+ element_clear(p0);
+ element_clear(c0);
+ element_clear(c2);
+}
+
+static void polymod_square(element_ptr res, element_ptr e) {
+ element_t *dst;
+ element_t *src = e->data;
+ mfptr p = res->field->data;
+ int n = p->n;
+ element_t prod, p0, c0;
+ int i, j;
+ element_t *high; // Coefficients of x^n,...,x^{2n-2}.
+
+ high = pbc_malloc(sizeof(element_t) * (n - 1));
+ for (i=0; i<n-1; i++) {
+ element_init(high[i], p->field);
+ element_set0(high[i]);
+ }
+
+ element_init(prod, res->field);
+ dst = prod->data;
+ element_init(p0, res->field);
+ element_init(c0, p->field);
+
+ for (i=0; i<n; i++) {
+ int twicei = 2 * i;
+ element_square(c0, src[i]);
+ if (twicei < n) {
+ element_add(dst[twicei], dst[twicei], c0);
+ } else {
+ element_add(high[twicei - n], high[twicei - n], c0);
+ }
+
+ for (j=i+1; j<n-i; j++) {
+ element_mul(c0, src[i], src[j]);
+ element_add(c0, c0, c0);
+ element_add(dst[i + j], dst[i + j], c0);
+ }
+ for (;j<n; j++) {
+ element_mul(c0, src[i], src[j]);
+ element_add(c0, c0, c0);
+ element_add(high[i + j - n], high[i + j - n], c0);
+ }
+ }
+
+ for (i=0; i<n-1; i++) {
+ polymod_const_mul(p0, high[i], p->xpwr[i]);
+ element_add(prod, prod, p0);
+ element_clear(high[i]);
+ }
+ pbc_free(high);
+
+ element_set(res, prod);
+ element_clear(prod);
+ element_clear(p0);
+ element_clear(c0);
+}
+
+static int polymod_is0(element_ptr e) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+
+ for (i=0; i<n; i++) {
+ if (!element_is0(coeff[i])) return 0;
+ }
+ return 1;
+}
+
+static int polymod_is1(element_ptr e) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+
+ if (!element_is1(coeff[0])) return 0;
+ for (i=1; i<n; i++) {
+ if (!element_is0(coeff[i])) return 0;
+ }
+ return 1;
+}
+
+static void polymod_set0(element_ptr e) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+
+ for (i=0; i<n; i++) {
+ element_set0(coeff[i]);
+ }
+}
+
+static void polymod_set1(element_ptr e) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+
+ element_set1(coeff[0]);
+ for (i=1; i<n; i++) {
+ element_set0(coeff[i]);
+ }
+}
+
+static int polymod_sgn(element_ptr e) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int res = 0;
+ int i, n = p->n;
+ for (i=0; i<n; i++) {
+ res = element_sgn(coeff[i]);
+ if (res) break;
+ }
+ return res;
+}
+
+static size_t polymod_out_str(FILE *stream, int base, element_ptr e) {
+ size_t result = 2, status;
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+
+ if (EOF == fputc('[', stream)) return 0;
+ for (i=0; i<n; i++) {
+ if (i) {
+ if (EOF == fputs(", ", stream)) return 0;
+ result += 2;
+ }
+ status = element_out_str(stream, base, coeff[i]);
+ if (!status) return 0;
+ result += status;
+ }
+ if (EOF == fputc(']', stream)) return 0;
+ return result;
+}
+
+static int polymod_snprint(char *s, size_t size, element_ptr e) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+ size_t result = 0, left;
+ int status;
+
+ #define clip_sub(void) { \
+ result += status; \
+ left = result >= size ? 0 : size - result; \
+ }
+
+ status = snprintf(s, size, "[");
+ if (status < 0) return status;
+ clip_sub();
+
+ for (i=0; i<n; i++) {
+ if (i) {
+ status = snprintf(s + result, left, ", ");
+ if (status < 0) return status;
+ clip_sub();
+ }
+ status = element_snprint(s + result, left, coeff[i]);
+ 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 polymod_set_multiz(element_ptr e, multiz m) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+ if (multiz_is_z(m)) {
+ element_set_multiz(coeff[0], m);
+ for (i = 1; i < n; i++) element_set0(coeff[i]);
+ return;
+ }
+ int max = multiz_count(m);
+ for (i = 0; i < n; i++) {
+ if (i >= max) element_set0(coeff[i]);
+ else element_set_multiz(coeff[i], multiz_at(m, i));
+ }
+}
+
+static int polymod_set_str(element_ptr e, const char *s, int base) {
+ mfptr p = e->field->data;
+ element_t *coeff = e->data;
+ int i, n = p->n;
+ const char *cp = s;
+ element_set0(e);
+ while (*cp && isspace(*cp)) cp++;
+ if (*cp++ != '[') return 0;
+ for (i=0; i<n; i++) {
+ cp += element_set_str(coeff[i], cp, base);
+ while (*cp && isspace(*cp)) cp++;
+ if (i<n-1 && *cp++ != ',') return 0;
+ }
+ if (*cp++ != ']') return 0;
+ return cp - s;
+}
+
+static int polymod_coeff_count(element_ptr e) {
+ UNUSED_VAR(e);
+ mfptr p = e->field->data;
+ return p->n;
+}
+
+static element_ptr polymod_coeff(element_ptr e, int i) {
+ element_t *coeff = e->data;
+ return coeff[i];
+}
+
+static void polymod_to_mpz(mpz_t z, element_ptr e) {
+ element_to_mpz(z, polymod_coeff(e, 0));
+}
+
+// Compute x^n,...,x^{2n-2} mod poly.
+static void compute_x_powers(field_ptr field, element_ptr poly) {
+ mfptr p = field->data;
+ element_t p0;
+ element_ptr pwrn;
+ element_t *coeff, *coeff1;
+ int i, j;
+ int n = p->n;
+ element_t *xpwr;
+
+ xpwr = p->xpwr;
+
+ element_init(p0, field);
+ for (i=0; i<n; i++) {
+ element_init(xpwr[i], field);
+ }
+ pwrn = xpwr[0];
+ poly_to_polymod_truncate(pwrn, poly);
+ element_neg(pwrn, pwrn);
+
+ for (i=1; i<n; i++) {
+ coeff = xpwr[i-1]->data;
+ coeff1 = xpwr[i]->data;
+
+ element_set0(coeff1[0]);
+ for (j=1; j<n; j++) {
+ element_set(coeff1[j], coeff[j - 1]);
+ }
+ polymod_const_mul(p0, coeff[n - 1], pwrn);
+ element_add(xpwr[i], xpwr[i], p0);
+ }
+ element_clear(p0);
+}
+
+static void polymod_out_info(FILE *str, field_ptr f) {
+ mfptr p = f->data;
+ element_fprintf(str, "Extension, poly = %B, base field = ", p->poly);
+ field_out_info(str, p->field);
+}
+
+// Sets d = gcd(f, g).
+static void poly_gcd(element_ptr d, element_ptr f, element_ptr g) {
+ element_t a, b, q, r;
+ element_init(a, d->field);
+ element_init(b, d->field);
+ element_init(q, d->field);
+ element_init(r, d->field);
+
+ element_set(a, f);
+ element_set(b, g);
+ for(;;) {
+ //TODO: don't care about q
+ poly_div(q, r, a, b);
+ if (element_is0(r)) break;
+ element_set(a, b);
+ element_set(b, r);
+ }
+ element_set(d, b);
+ element_clear(a);
+ element_clear(b);
+ element_clear(q);
+ element_clear(r);
+}
+
+// Sets f = c g where c is the inverse of the leading coefficient of g.
+static void poly_make_monic(element_t f, element_t g) {
+ int n = poly_coeff_count(g);
+ int i;
+ element_ptr e0;
+ poly_alloc(f, n);
+ if (!n) return;
+
+ e0 = poly_coeff(f, n - 1);
+ element_invert(e0, poly_coeff(g, n - 1));
+ for (i=0; i<n-1; i++) {
+ element_mul(poly_coeff(f, i), poly_coeff(g, i), e0);
+ }
+ element_set1(e0);
+}
+
+// The above should be static.
+
+void field_init_poly(field_ptr f, field_ptr base_field) {
+ field_init(f);
+ pfptr p = f->data = pbc_malloc(sizeof(*p));
+ p->field = base_field;
+ p->mapbase = element_field_to_poly;
+ f->field_clear = field_clear_poly;
+ f->init = poly_init;
+ f->clear = poly_clear;
+ f->set_si = poly_set_si;
+ f->set_multiz = poly_set_multiz;
+ f->set_mpz = poly_set_mpz;
+ f->to_mpz = poly_to_mpz;
+ f->out_str = poly_out_str;
+ f->snprint = poly_snprint;
+ f->set = poly_set;
+ f->sign = poly_sgn;
+ f->add = poly_add;
+ f->doub = poly_double;
+ f->is0 = poly_is0;
+ f->is1 = poly_is1;
+ f->set0 = poly_set0;
+ f->set1 = poly_set1;
+ f->sub = poly_sub;
+ f->neg = poly_neg;
+ f->mul = poly_mul;
+ f->mul_mpz = poly_mul_mpz;
+ f->mul_si = poly_mul_si;
+ f->cmp = poly_cmp;
+ f->out_info = poly_out_info;
+ f->item_count = poly_coeff_count;
+ f->item = poly_coeff;
+
+ f->to_bytes = poly_to_bytes;
+ f->from_bytes = poly_from_bytes;
+ f->fixed_length_in_bytes = -1;
+ f->length_in_bytes = poly_length_in_bytes;
+}
+
+void poly_set_coeff(element_ptr e, element_ptr a, int n) {
+ peptr p = e->data;
+ if (p->coeff->count < n + 1) {
+ poly_alloc(e, n + 1);
+ }
+ element_ptr e0 = p->coeff->item[n];
+ element_set(e0, a);
+ if (p->coeff->count == n + 1 && element_is0(a)) poly_remove_leading_zeroes(e);
+}
+
+void poly_set_coeff0(element_ptr e, int n) {
+ peptr p = e->data;
+ if (n < p->coeff->count) {
+ element_set0(p->coeff->item[n]);
+ if (n == p->coeff->count - 1) poly_remove_leading_zeroes(e);
+ }
+}
+
+void poly_set_coeff1(element_ptr e, int n) {
+ peptr p = e->data;
+ if (p->coeff->count < n + 1) {
+ poly_alloc(e, n + 1);
+ }
+ element_set1(p->coeff->item[n]);
+}
+
+void poly_setx(element_ptr f) {
+ poly_alloc(f, 2);
+ element_set1(poly_coeff(f, 1));
+ element_set0(poly_coeff(f, 0));
+}
+
+void poly_const_mul(element_ptr res, element_ptr a, element_ptr poly) {
+ int i, n = poly_coeff_count(poly);
+ poly_alloc(res, n);
+ for (i=0; i<n; i++) {
+ element_mul(poly_coeff(res, i), a, poly_coeff(poly, i));
+ }
+ poly_remove_leading_zeroes(res);
+}
+
+void poly_random_monic(element_ptr f, int deg) {
+ int i;
+ poly_alloc(f, deg + 1);
+ for (i=0; i<deg; i++) {
+ element_random(poly_coeff(f, i));
+ }
+ element_set1(poly_coeff(f, i));
+}
+
+int polymod_field_degree(field_t f) {
+ mfptr p = f->data;
+ return p->n;
+}
+
+void field_init_polymod(field_ptr f, element_ptr poly) {
+ pfptr pdp = poly->field->data;
+ field_init(f);
+ mfptr p = f->data = pbc_malloc(sizeof(*p));
+ p->field = pdp->field;
+ p->mapbase = element_field_to_poly;
+ element_init(p->poly, poly->field);
+ element_set(p->poly, poly);
+ int n = p->n = poly_degree(p->poly);
+ f->field_clear = field_clear_polymod;
+ f->init = polymod_init;
+ f->clear = polymod_clear;
+ f->set_si = polymod_set_si;
+ f->set_mpz = polymod_set_mpz;
+ f->out_str = polymod_out_str;
+ f->snprint = polymod_snprint;
+ f->set_multiz = polymod_set_multiz;
+ f->set_str = polymod_set_str;
+ f->set = polymod_set;
+ f->sign = polymod_sgn;
+ f->add = polymod_add;
+ f->doub = polymod_double;
+ f->sub = polymod_sub;
+ f->neg = polymod_neg;
+ f->is0 = polymod_is0;
+ f->is1 = polymod_is1;
+ f->set0 = polymod_set0;
+ f->set1 = polymod_set1;
+ f->cmp = polymod_cmp;
+ f->to_mpz = polymod_to_mpz;
+ f->item_count = polymod_coeff_count;
+ f->item = polymod_coeff;
+ switch(n) {
+ case 3:
+ f->mul = polymod_mul_degree3;
+ f->square = polymod_square_degree3;
+ break;
+ case 6:
+ f->mul = polymod_mul_degree6;
+ f->square = polymod_square;
+ break;
+ default:
+ f->mul = polymod_mul;
+ f->square = polymod_square;
+ break;
+ }
+
+ f->mul_mpz = polymod_mul_mpz;
+ f->mul_si = polymod_mul_si;
+ f->random = polymod_random;
+ f->from_hash = polymod_from_hash;
+ f->invert = polymod_invert;
+ f->is_sqr = polymod_is_sqr;
+ f->sqrt = polymod_sqrt;
+ f->to_bytes = polymod_to_bytes;
+ f->from_bytes = polymod_from_bytes;
+ f->out_info = polymod_out_info;
+
+ if (pdp->field->fixed_length_in_bytes < 0) {
+ f->fixed_length_in_bytes = -1;
+ f->length_in_bytes = polymod_length_in_bytes;
+ } else {
+ f->fixed_length_in_bytes = pdp->field->fixed_length_in_bytes * poly_degree(poly);
+ }
+ mpz_pow_ui(f->order, p->field->order, n);
+
+ p->xpwr = pbc_malloc(sizeof(element_t) * n);
+ compute_x_powers(f, poly);
+}
+
+field_ptr poly_base_field(element_t f) {
+ return ((pfptr) f->field->data)->field;
+}
+
+void polymod_const_mul(element_ptr res, element_ptr a, element_ptr e) {
+ // a lies in R, e in R[x].
+ element_t *coeff = e->data, *dst = res->data;
+ int i, n = polymod_field_degree(e->field);
+
+ for (i=0; i<n; i++) {
+ element_mul(dst[i], coeff[i], a);
+ }
+}
+
+struct checkgcd_scope_var {
+ mpz_ptr z, deg;
+ field_ptr basef;
+ element_ptr xpow, x, f, g;
+};
+
+// Returns 0 if gcd(x^q^{n/d} - x, f) = 1, 1 otherwise.
+static int checkgcd(mpz_ptr fac, unsigned int mul, struct checkgcd_scope_var *v) {
+ UNUSED_VAR(mul);
+ mpz_divexact(v->z, v->deg, fac);
+ mpz_pow_ui(v->z, v->basef->order, mpz_get_ui(v->z));
+ element_pow_mpz(v->xpow, v->x, v->z);
+ element_sub(v->xpow, v->xpow, v->x);
+ if (element_is0(v->xpow)) return 1;
+ polymod_to_poly(v->g, v->xpow);
+ poly_gcd(v->g, v->f, v->g);
+ return poly_degree(v->g) != 0;
+}
+
+// Returns 1 if polynomial is irreducible, 0 otherwise.
+// A polynomial f(x) is irreducible in F_q[x] if and only if:
+// (1) f(x) | x^{q^n} - x, and
+// (2) gcd(f(x), x^{q^{n/d}} - x) = 1 for all primes d | n.
+// (Recall GF(p) is the splitting field for x^p - x.)
+int poly_is_irred(element_ptr f) {
+ int res = 0;
+ element_t xpow, x, g;
+ field_ptr basef = poly_base_field(f);
+ field_t rxmod;
+
+ // 0, units are not irreducibles.
+ // Assume coefficients are from a field.
+ if (poly_degree(f) <= 0) return 0;
+ // Degree 1 polynomials are always irreducible.
+ if (poly_degree(f) == 1) return 1;
+
+ field_init_polymod(rxmod, f);
+ element_init(xpow, rxmod);
+ element_init(x, rxmod);
+ element_init(g, f->field);
+ element_set1(polymod_coeff(x, 1));
+
+ // The degree fits in an unsigned int but I'm lazy and want to use my
+ // mpz trial division code.
+ mpz_t deg, z;
+ mpz_init(deg);
+ mpz_init(z);
+ mpz_set_ui(deg, poly_degree(f));
+
+ struct checkgcd_scope_var v = {.z = z, .deg = deg, .basef = basef,
+ .xpow = xpow, .x = x, .f = f, .g = g};
+ if (!pbc_trial_divide((int(*)(mpz_t,unsigned,void*))checkgcd, &v, deg, NULL)) {
+ // By now condition (2) has been satisfied. Check (1).
+ mpz_pow_ui(z, basef->order, poly_degree(f));
+ element_pow_mpz(xpow, x, z);
+ element_sub(xpow, xpow, x);
+ if (element_is0(xpow)) res = 1;
+ }
+
+ mpz_clear(deg);
+ mpz_clear(z);
+ element_clear(g);
+ element_clear(xpow);
+ element_clear(x);
+ field_clear(rxmod);
+ return res;
+}
+
+void element_field_to_poly(element_ptr f, element_ptr g) {
+ poly_alloc(f, 1);
+ element_set(poly_coeff(f, 0), g);
+ poly_remove_leading_zeroes(f);
+}
+
+void element_field_to_polymod(element_ptr f, element_ptr g) {
+ mfptr p = f->field->data;
+ element_t *coeff = f->data;
+ int i, n = p->n;
+ element_set(coeff[0], g);
+ for (i=1; i<n; i++) {
+ element_set0(coeff[i]);
+ }
+}
+
+// Returns 0 when a root exists and sets root to one of the roots.
+int poly_findroot(element_ptr root, element_ptr poly) {
+ // Compute gcd(x^q - x, poly).
+ field_t fpxmod;
+ element_t p, x, r, fac, g;
+ mpz_t q;
+
+ mpz_init(q);
+ mpz_set(q, poly_base_field(poly)->order);
+
+ field_init_polymod(fpxmod, poly);
+ element_init(p, fpxmod);
+ element_init(x, fpxmod);
+ element_init(g, poly->field);
+ element_set1(((element_t *) x->data)[1]);
+pbc_info("findroot: degree %d...", poly_degree(poly));
+ element_pow_mpz(p, x, q);
+ element_sub(p, p, x);
+
+ polymod_to_poly(g, p);
+ element_clear(p);
+ poly_gcd(g, g, poly);
+ poly_make_monic(g, g);
+ element_clear(x);
+ field_clear(fpxmod);
+
+ if (!poly_degree(g)) {
+ printf("no roots!\n");
+ mpz_clear(q);
+ element_clear(g);
+ return -1;
+ }
+
+ // Cantor-Zassenhaus algorithm.
+ element_init(fac, g->field);
+ element_init(x, g->field);
+ element_set_si(x, 1);
+ mpz_sub_ui(q, q, 1);
+ mpz_divexact_ui(q, q, 2);
+ element_init(r, g->field);
+ for (;;) {
+ if (poly_degree(g) == 1) break; // Found a root!
+step_random:
+ poly_random_monic(r, 1);
+ // TODO: evaluate at g instead of bothering with gcd
+ poly_gcd(fac, r, g);
+
+ if (poly_degree(fac) > 0) {
+ poly_make_monic(g, fac);
+ } else {
+ field_init_polymod(fpxmod, g);
+ int n;
+ element_init(p, fpxmod);
+
+ poly_to_polymod_truncate(p, r);
+pbc_info("findroot: degree %d...", poly_degree(g));
+ element_pow_mpz(p, p, q);
+
+ polymod_to_poly(r, p);
+ element_clear(p);
+ field_clear(fpxmod);
+
+ element_add(r, r, x);
+ poly_gcd(fac, r, g);
+ n = poly_degree(fac);
+ if (n > 0 && n < poly_degree(g)) {
+ poly_make_monic(g, fac);
+ } else {
+ goto step_random;
+ }
+ }
+ }
+pbc_info("findroot: found root");
+ element_neg(root, poly_coeff(g, 0));
+ element_clear(r);
+ mpz_clear(q);
+ element_clear(x);
+ element_clear(g);
+ element_clear(fac);
+ return 0;
+}
diff --git a/moon-abe/pbc-0.5.14/arith/random.c b/moon-abe/pbc-0.5.14/arith/random.c
new file mode 100644
index 00000000..68228b3f
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/random.c
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <stdint.h> // for intptr_t
+#include <stdlib.h>
+#include <gmp.h>
+#include "pbc_random.h"
+#include "pbc_utils.h"
+#include "pbc_memory.h"
+
+void pbc_init_random(void);
+
+// Must use pointer due to lack of gmp_randstate_ptr.
+static gmp_randstate_t *get_rs(void) {
+ static int rs_is_ready;
+ static gmp_randstate_t rs;
+ if (!rs_is_ready) {
+ gmp_randinit_default(rs);
+ rs_is_ready = 1;
+ }
+ return &rs;
+}
+
+static void deterministic_mpz_random(mpz_t z, mpz_t limit, void *data) {
+ UNUSED_VAR (data);
+ mpz_urandomm(z, *get_rs(), limit);
+}
+
+static void file_mpz_random(mpz_t r, mpz_t limit, void *data) {
+ char *filename = (char *) data;
+ FILE *fp;
+ int n, bytecount, leftover;
+ unsigned char *bytes;
+ mpz_t z;
+ mpz_init(z);
+ fp = fopen(filename, "rb");
+ if (!fp) return;
+ n = mpz_sizeinbase(limit, 2);
+ bytecount = (n + 7) / 8;
+ leftover = n % 8;
+ bytes = (unsigned char *) pbc_malloc(bytecount);
+ for (;;) {
+ if (!fread(bytes, 1, bytecount, fp)) {
+ pbc_warn("error reading source of random bits");
+ return;
+ }
+ if (leftover) {
+ *bytes = *bytes % (1 << leftover);
+ }
+ mpz_import(z, bytecount, 1, 1, 0, 0, bytes);
+ if (mpz_cmp(z, limit) < 0) break;
+ }
+ fclose(fp);
+ mpz_set(r, z);
+ mpz_clear(z);
+ pbc_free(bytes);
+}
+
+static void (*current_mpz_random)(mpz_t, mpz_t, void *);
+static void *current_random_data;
+static int random_function_ready = 0;
+
+void pbc_random_set_function(void (*fun)(mpz_t, mpz_t, void *), void *data) {
+ current_mpz_random = fun;
+ current_random_data = data;
+ random_function_ready = 1;
+}
+
+void pbc_mpz_random(mpz_t z, mpz_t limit) {
+ if (!random_function_ready) pbc_init_random();
+ current_mpz_random(z, limit, current_random_data);
+}
+
+void pbc_mpz_randomb(mpz_t z, unsigned int bits) {
+ mpz_t limit;
+ mpz_init(limit);
+ mpz_setbit(limit, bits);
+ pbc_mpz_random(z, limit);
+ mpz_clear(limit);
+}
+
+void pbc_random_set_deterministic(unsigned int seed) {
+ gmp_randseed_ui(*get_rs(), seed);
+ pbc_random_set_function(deterministic_mpz_random, NULL);
+}
+
+void pbc_random_set_file(char *filename) {
+ pbc_random_set_function(file_mpz_random, filename);
+}
diff --git a/moon-abe/pbc-0.5.14/arith/ternary_extension_field.c b/moon-abe/pbc-0.5.14/arith/ternary_extension_field.c
new file mode 100644
index 00000000..3c79e3bd
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/ternary_extension_field.c
@@ -0,0 +1,950 @@
+/* $GF(3^m) = GF(3)[x]/(x^m + x^t + 2)$
+ $GF(3^{2*m}) = GF(3^m)[x]/(x^2 + 1)$
+ $GF(3^{3*m}) = GF(3^m)[x]/(x^3 - x -1)$
+ $GF(3^{6*m}) = GF(3^{2*m})[x]/(x^3 - x -1)$
+
+ The "gf3_*" functions are for $GF(3)$.
+ The "gf3m_*" functions are for $GF(3^m)$.
+ The "gf32m_*" functions are for $GF(3^{2*m})$.
+ The "gf33m_*" functions are for $GF(3^{3*m})$ and $GF(3^{6*m})$.
+
+ (gf3m field_t).data is a pointer of struct params
+ (gf3m element_t).data is a pointer of unsigned long
+ (gf32m element_t).data is gf32m_ptr
+ (gf33m element_t).data is gf33m_ptr */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <gmp.h>
+#include "pbc_utils.h"
+#include "pbc_memory.h"
+#include "pbc_field.h"
+
+typedef unsigned long gf3;
+
+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 */
+ unsigned int m; /* the irreducible polynomial is $x^m + x^t + 2$ */
+ unsigned int t; /* the irreducible polynomial is $x^m + x^t + 2$ */
+ element_ptr p; /* $p$ is the irreducible polynomial. */
+} params;
+
+typedef struct {
+ element_t _0, _1;
+} gf32m_s;
+
+typedef gf32m_s *gf32m_ptr;
+
+typedef struct {
+ element_t _0, _1, _2;
+} gf33m_s;
+
+typedef gf33m_s *gf33m_ptr;
+
+#define W (sizeof(unsigned long)*8) /* number of GF(3) elements in one processor integer */
+#define PARAM(e) ((params *)e->field->data)
+#define LEN(e) (PARAM(e)->len)
+#define SIZE(e) (LEN(e) * 2 * sizeof(unsigned long))
+#define DATA1(e) ((unsigned long*)e->data)
+#define DATA2(e) ((unsigned long*)e->data + LEN(e))
+#define GF32M(e) ((gf32m_s *)e->data)
+#define GF33M(e) ((gf33m_s *)e->data)
+#define BASE(e) ((field_ptr)e->field->data)
+#define print(e) {printf(#e": "); element_out_str(stdout, 10, e); printf("\n");}
+
+static size_t gf3m_out_str(FILE *stream, int base, element_t e) {
+ if (base != 10 && base != 16)
+ pbc_die("only support base 10 and base 16");
+ size_t size = 0;
+ unsigned i;
+ unsigned long *d = DATA1(e);
+ for (i = 0; i < LEN(e) * 2; i++) {
+ if (base == 16)
+ size += fprintf(stream, "0x%lx,", d[i]);
+ else
+ size += fprintf(stream, "%lu,", d[i]);
+ }
+ return size;
+}
+
+/* $a <- 0$ */
+static void gf3m_zero(element_t a) {
+ memset(a->data, 0, SIZE(a));
+}
+
+static void gf3m_init(element_t e) {
+ e->data = pbc_malloc(SIZE(e));
+ gf3m_zero(e);
+}
+
+static void gf3m_clear(element_t e) {
+ pbc_free(e->data);
+}
+
+/* $e <- a$ */
+static void gf3m_assign(element_t e, element_t a) {
+ memcpy(e->data, a->data, SIZE(a));
+}
+
+/* $a <- a/x$. $len$ is the number of elements in $a$ */
+static void shift_down(unsigned int len, unsigned long a[]) {
+ unsigned long h = 0;
+ const unsigned long x = 1ul << (W - 1);
+ int i;
+ for (i = len - 1; i >= 0; i--) {
+ unsigned long l = a[i] & 1;
+ a[i] >>= 1;
+ if (h)
+ a[i] |= x;
+ h = l;
+ }
+}
+
+/* $e <- e/x$ */
+static void gf3m_shift_down(element_t e) {
+ shift_down(LEN(e), DATA1(e));
+ shift_down(LEN(e), DATA2(e));
+}
+
+/* $a <- a*x$. $len$ is the number of elements in $a$ */
+static void shift_up(unsigned int len, unsigned long a[]) {
+ unsigned long l = 0;
+ const unsigned long x = 1ul << (W - 1), y = x - 1;
+ unsigned i;
+ for (i = 0; i < len; i++) {
+ unsigned long h = a[i] & x;
+ a[i] = ((a[i] & y) << 1) | l;
+ l = h ? 1 : 0;
+ }
+}
+
+/* $e <- e*x$ */
+static void gf3m_shift_up(element_t e) {
+ shift_up(LEN(e), DATA1(e));
+ shift_up(LEN(e), DATA2(e));
+}
+
+/* return the coefficient of $x^pos$ in $e$ */
+static unsigned gf3m_get(element_t e, unsigned pos) {
+ unsigned long *a1 = DATA1(e), *a2 = DATA2(e);
+ unsigned x = pos / W;
+ unsigned long y = 1ul << (pos % W), v1 = a1[x] & y, v2 = a2[x] & y;
+ return v1 ? 1 : (v2 ? 2 : 0);
+}
+
+/* set the coefficient of $x^pos$ as 1 */
+static void gf3m_set(element_t e, unsigned pos, unsigned value) {
+ unsigned long *a = DATA1(e);
+ /* assert value == 0, 1 or 2 */
+ if (value == 2)
+ a = DATA2(e);
+ if (value)
+ a[pos / W] |= 1ul << (pos % W);
+}
+
+/* $e <- a+b$ */
+static void gf3m_add(element_t e, element_t a, element_t b) {
+ unsigned long *e1 = DATA1(e), *e2 = DATA2(e), *a1 = DATA1(a),
+ *a2 = DATA2(a), *b1 = DATA1(b), *b2 = DATA2(b);
+ unsigned i;
+ for (i = 0; i < LEN(e); i++, e1++, e2++, a1++, a2++, b1++, b2++) {
+ unsigned long t = (*a1 | *a2) & (*b1 | *b2), c1 = t ^ (*a1 | *b1), c2 =
+ t ^ (*a2 | *b2);
+ *e1 = c1;
+ *e2 = c2;
+ }
+}
+
+/* $e <- x-y$ */
+static void gf3m_sub(element_t e, element_t a, element_t b) {
+ unsigned long *e1 = DATA1(e), *e2 = DATA2(e), *a1 = DATA1(a),
+ *a2 = DATA2(a), *b1 = DATA2(b), *b2 = DATA1(b);
+ unsigned i;
+ for (i = 0; i < LEN(e); i++, e1++, e2++, a1++, a2++, b1++, b2++) {
+ unsigned long t = (*a1 | *a2) & (*b1 | *b2), c1 = t ^ (*a1 | *b1), c2 =
+ t ^ (*a2 | *b2);
+ *e1 = c1;
+ *e2 = c2;
+ }
+}
+
+/* return 0 if $a == b$ in $GF(3^m)$, 1 otherwise. */
+static int gf3m_cmp(element_t a, element_t b) {
+ unsigned long *pa = DATA1(a), *pb = DATA1(b);
+ unsigned i;
+ for (i = 0; i < LEN(a) * 2; i++, pa++, pb++)
+ if (*pa != *pb)
+ return 1;
+ return 0;
+}
+
+/* $a <- 1$ */
+static void gf3m_one(element_t a) {
+ gf3m_zero(a);
+ *DATA1(a) = 1;
+}
+
+static int gf3m_is0(element_t e) {
+ unsigned i;
+ for (i = 0; i < LEN(e) * 2; i++)
+ if (DATA1(e)[i])
+ return 0;
+ return 1;
+}
+
+static int gf3m_is1(element_t e) {
+ unsigned i;
+ if (DATA1(e)[0] != 1)
+ return 0;
+ for (i = 1; i < LEN(e) * 2; i++)
+ if (DATA1(e)[i])
+ return 0;
+ return 1;
+}
+
+/* set $a$ to be a random element in $GF(3^m)$ */
+static void gf3m_random(element_t a) {
+ /* TODO: use uniform distribution? */
+ params *c = PARAM(a);
+ unsigned rm = c->m % W;
+ const unsigned long i1 = ~0ul;
+ unsigned long i2 = (1ul << rm) - 1;
+ unsigned long *a1 = DATA1(a), *a2 = DATA2(a);
+ unsigned i;
+ for (i = 0; i < c->len - 1; i++, a1++, a2++) { /* TODO: if $RAND_MAX < i1$ ? */
+ *a1 = rand() & i1;
+ *a2 = rand() & i1 & ~(*a1); /* assuring there is no bit that a1[x] & a2[x] == 1 */
+ }
+ unsigned long x = rm ? i2 : i1;
+ *a1 = rand() & x;
+ *a2 = rand() & x & ~(*a1);
+}
+
+static void swap(unsigned long *a, unsigned long *b) {
+ *a ^= *b;
+ *b ^= *a;
+ *a ^= *b;
+}
+
+/* $y <- (-x)$ */
+static void gf3m_neg(element_t y, element_t x) {
+ unsigned long *a1 = DATA1(x), *a2 = DATA2(x), *c1 = DATA1(y),
+ *c2 = DATA2(y);
+ if (a1 == c1) {
+ unsigned i;
+ for (i = 0; i < LEN(y); i++, a1++, a2++)
+ swap(a1, a2);
+ } else {
+ memcpy(c1, a2, SIZE(y) / 2);
+ memcpy(c2, a1, SIZE(y) / 2);
+ }
+}
+
+/* doing reduction
+ * The function returns the value of $a$ modulo $the irreducible trinomial$.
+ * $degree$ equals the degree of $a$.
+ * $2*len$ is the number of elements in $a$ */
+static void gf3m_reduct(element_t e, unsigned len, unsigned degree) {
+ // the $len$ argument exists because sometimes $len != p->len$
+ params *p = PARAM(e);
+ unsigned old = p->len;
+ p->len = len;
+ element_t px;
+ element_init(px, e->field);
+ gf3m_set(px, degree, 1);
+ gf3m_set(px, degree - p->m + p->t, 1);
+ gf3m_set(px, degree - p->m, 2);
+ while (degree >= p->m) {
+ unsigned v = gf3m_get(e, degree);
+ if (v == 1)
+ gf3m_sub(e, e, px);
+ else if (v == 2)
+ gf3m_add(e, e, px);
+ degree--;
+ gf3m_shift_down(px);
+ }
+ element_clear(px);
+ p->len = old;
+}
+
+/* doing multiplication of $n \in \{0,1,2\}$ and $a$ in $GF(3^m)$
+ * The function sets $e <- n * a$. */
+static void gf3m_f1(element_t e, unsigned n, element_t a) {
+ /* assert $e$ is not $a$ */
+ if (n == 0)
+ memset(DATA1(e), 0, SIZE(e));
+ else if (n == 1)
+ memcpy(DATA1(e), DATA1(a), SIZE(e));
+ else {
+ memcpy(DATA1(e), DATA2(a), SIZE(e) / 2);
+ memcpy(DATA2(e), DATA1(a), SIZE(e) / 2);
+ }
+}
+
+/* $e <- e*x mod p(x)$ */
+static void gf3m_f2(element_t e) {
+ params *p = PARAM(e);
+ gf3m_shift_up(e);
+ unsigned v = gf3m_get(e, p->m);
+ if (v == 1)
+ gf3m_sub(e, e, p->p);
+ else if (v == 2)
+ gf3m_add(e, e, p->p);
+}
+
+/* doing multiplication in GF(3^m)
+ * The function sets $e == a*b \in GF(3^m)$ */
+static void gf3m_mult(element_t e, element_ptr a, element_t b) {
+ params *p = PARAM(a);
+ element_t aa, t, c;
+ element_init(aa, a->field);
+ element_set(aa, a);
+ a = aa; // clone $a$
+ element_init(t, a->field);
+ element_init(c, a->field);
+ unsigned i;
+ for (i = 0; i < p->m; i++) {
+ unsigned v = gf3m_get(b, i);
+ gf3m_f1(t, v, a); /* t == b[i]*a in GF(3^m) */
+ gf3m_add(c, c, t); /* c += b[i]*a in GF(3^m) */
+ gf3m_f2(a); /* a == a*x in GF(3^m) */
+ }
+ element_set(e, c);
+ element_clear(t);
+ element_clear(c);
+ element_clear(aa);
+}
+
+/* $e <- x^3$ */
+static void gf3m_cubic(element_t e, element_t x) {
+ /* TODO: faster algorithm */
+ params *p = PARAM(x);
+ unsigned old = p->len;
+ unsigned len = (3 * p->m - 2 + W - 1) / W; /* length of $b1 */
+ p->len = len;
+ element_t a;
+ element_init(a, x->field);
+ unsigned i;
+ for (i = 0; i < p->m; i++) {
+ p->len = old;
+ unsigned v = gf3m_get(x, i);
+ p->len = len;
+ gf3m_set(a, 3 * i, v);
+ }
+ gf3m_reduct(a, len, 3 * p->m - 3);
+ p->len = old;
+ memcpy(DATA1(e), DATA1(a), SIZE(e) / 2);
+ memcpy(DATA2(e), DATA1(a) + len, SIZE(e) / 2);
+ element_clear(a);
+}
+
+/* multiplication modulo 3 of two elements in GF(3)
+ * for example, $mult(2,2) == 1$, and $mult(1,2) == 2$ */
+static unsigned gf3_mult(unsigned a, unsigned b) {
+ static const unsigned l[] = { 0, 1, 2, 0, 1 };
+ return l[a * b];
+}
+
+static void gf3m_swap(element_t a, element_t b) {
+ unsigned long *p = DATA1(a);
+ a->data = b->data;
+ b->data = p;
+}
+
+/* computing the inversion of an element $a$ in GF(3^m), i.e., $e <- a^{-1}$
+ The algorithm is by Tim Kerins, Emanuel Popovici and William Marnane
+ in the paper of "Algorithms and Architectures for use in FPGA",
+ Lecture Notes in Computer Science, 2004, Volume 3203/2004, 74-83.
+ Note that $U$ must have an extra bit, i.e, (_m + W - 1) // W == (_m + W) // W */
+static void gf3m_invert(element_t e, element_t a) {
+ struct field_s *f = a->field;
+ params *p = PARAM(a);
+ unsigned lenA = p->len;
+ unsigned lenS = (3 * p->m + W - 1) / W;
+ p->len = lenS;
+ element_t S, R, t, U, V, t2;
+ element_init(S, f);
+ element_init(R, f);
+ element_init(t, f);
+ memcpy(DATA1(S), DATA1(p->p), lenA * sizeof(unsigned long)); /* S = p(x) */
+ memcpy(DATA1(S) + lenS, DATA1(p->p) + lenA, lenA * sizeof(unsigned long));
+ memcpy(DATA1(R), DATA1(a), lenA * sizeof(unsigned long)); /* R = _clone(a) */
+ memcpy(DATA1(R) + lenS, DATA1(a) + lenA, lenA * sizeof(unsigned long));
+ p->len = lenA;
+ element_init(U, f);
+ gf3m_one(U);
+ element_init(V, f);
+ element_init(t2, f);
+ unsigned d = 0, i, r_m, s_m, q, x;
+ for (i = 0; i < p->m * 2; i++) {
+ p->len = lenS;
+ r_m = gf3m_get(R, p->m), s_m = gf3m_get(S, p->m);
+ if (r_m == 0) {
+ gf3m_shift_up(R); /* R = xR */
+ p->len = lenA;
+ gf3m_f2(U); /* U = xU mod p */
+ d++;
+ } else {
+ q = gf3_mult(r_m, s_m);
+ gf3m_f1(t, q, R);
+ gf3m_sub(S, S, t); /* S = S-qR */
+ gf3m_shift_up(S); /* S = xS */
+ p->len = lenA;
+ gf3m_f1(t2, q, U);
+ gf3m_sub(V, V, t2); /* V = V-qU */
+ if (d == 0) {
+ gf3m_swap(S, R);
+ gf3m_swap(U, V);
+ gf3m_f2(U); /* U = xU mod p*/
+ d++;
+ } else {
+ x = gf3m_get(U, 0);
+ if (x == 1) /* assuring x|U */
+ gf3m_add(U, U, p->p);
+ else if (x == 2)
+ gf3m_sub(U, U, p->p);
+ gf3m_shift_down(U); /* divide U by $x$ */
+ d--;
+ }
+ }
+ }
+ p->len = lenS;
+ r_m = gf3m_get(R, p->m); /* assume r_m is not zero */
+ p->len = lenA;
+ if (r_m == 2)
+ gf3m_neg(U, U);
+ memcpy(e->data, U->data, lenA * 2 * sizeof(unsigned long));
+ element_clear(S);
+ element_clear(R);
+ element_clear(U);
+ element_clear(V);
+ element_clear(t);
+ element_clear(t2);
+}
+
+static void gf3m_sqrt(element_t e, element_t a) {
+ field_ptr f = e->field;
+ mpz_t t;
+ mpz_init(t); // t == (field_order + 1) / 4
+ mpz_set(t, f->order);
+ mpz_add_ui(t, t, 1);
+ mpz_tdiv_q_2exp(t, t, 2);
+ element_pow_mpz(e, a, t);
+ mpz_clear(t);
+}
+
+int gf3m_to_bytes(unsigned char *d, element_ptr e) {
+ unsigned long *a = DATA1(e), *b = DATA2(e);
+ unsigned long i, j;
+ for (i = 0; i < LEN(e); i++, a++, b++) {
+ for (j = 0; j < sizeof(unsigned long) * 8; j += 8) {
+ *(d++) = (unsigned char) ((*a) >> j);
+ *(d++) = (unsigned char) ((*b) >> j);
+ }
+ }
+ return SIZE(e);
+}
+
+int gf3m_from_bytes(element_ptr e, unsigned char *d) {
+ unsigned long *a = DATA1(e), *b = DATA2(e);
+ unsigned i;
+ int j;
+ for (i = 0; i < LEN(e); i++, a++, b++, d += sizeof(unsigned long) * 2) {
+ *a = 0, *b = 0;
+ j = 2 * sizeof(unsigned long) - 2;
+ while (j >= 0) {
+ *a <<= 8, *b <<= 8;
+ *a += d[j];
+ *b += d[j + 1];
+ j -= 2;
+ }
+ }
+ return SIZE(e);
+}
+
+static void field_clear_gf3m(field_t f) {
+ params *p = f->data;
+ gf3m_clear(p->p);
+ pbc_free(p->p);
+ pbc_free(p);
+}
+
+/* initialize the finite field as $GF(3^m)$, whose irreducible polynomial is with the degree of $m$ */
+void field_init_gf3m(field_t f, unsigned m, unsigned t) {
+ params *p = pbc_malloc(sizeof(*p));
+ p->len = (m + (W - 1) + 1) / W; /* extra one bit for $_p$ */
+ p->m = m;
+ p->t = t;
+ p->p = pbc_malloc(sizeof(*(p->p)));
+ p->p->field = f;
+ p->p->data = pbc_malloc(2 * sizeof(unsigned long) * p->len);
+ memset(p->p->data, 0, 2 * sizeof(unsigned long) * p->len);
+ unsigned long *p1 = p->p->data, *p2 = p1 + p->len;
+ p2[0] = 1; /* _p == x^m+x^t+2 */
+ unsigned int p_t = p->t;
+ p1[p_t / W] |= 1ul << (p_t % W);
+ p1[m / W] |= 1ul << (m % W);
+
+ field_init(f);
+ f->field_clear = field_clear_gf3m;
+ f->init = gf3m_init;
+ f->clear = gf3m_clear;
+ f->set = gf3m_assign;
+ f->set0 = gf3m_zero;
+ f->set1 = gf3m_one;
+ f->is0 = gf3m_is0;
+ f->is1 = gf3m_is1;
+ f->add = gf3m_add;
+ f->sub = gf3m_sub;
+ f->mul = gf3m_mult;
+ f->cubic = gf3m_cubic;
+ f->invert = gf3m_invert;
+ f->neg = gf3m_neg;
+ f->random = gf3m_random;
+ f->cmp = gf3m_cmp;
+ f->sqrt = gf3m_sqrt;
+ f->from_bytes = gf3m_from_bytes;
+ f->to_bytes = gf3m_to_bytes;
+ f->out_str = gf3m_out_str;
+ f->fixed_length_in_bytes = 2 * sizeof(unsigned long) * p->len;
+ f->data = p;
+ f->name = "GF(3^m)";
+
+ mpz_set_ui(f->order, 3);
+ mpz_pow_ui(f->order, f->order, p->m);
+}
+
+static size_t gf32m_out_str(FILE *stream, int base, element_t e) {
+ UNUSED_VAR(base);
+ element_ptr e0 = GF32M(e)->_0, e1 = GF32M(e)->_1;
+ size_t size = 0;
+ size += element_out_str(stream, base, e0);
+ size += element_out_str(stream, base, e1);
+ return size;
+}
+
+static void gf32m_init(element_t e) {
+ e->data = pbc_malloc(sizeof(gf32m_s));
+ gf32m_ptr p = (gf32m_ptr) e->data;
+ field_ptr base = BASE(e);
+ element_init(p->_0, base);
+ element_init(p->_1, base);
+}
+
+static void gf32m_clear(element_t e) {
+ gf32m_ptr p = (gf32m_ptr) e->data;
+ element_clear(p->_0);
+ element_clear(p->_1);
+ pbc_free(e->data);
+}
+
+static void gf32m_set0(element_t e) {
+ element_ptr e0 = GF32M(e)->_0, e1 = GF32M(e)->_1;
+ element_set0(e0);
+ element_set0(e1);
+}
+
+static void gf32m_set1(element_t e) {
+ element_ptr e0 = GF32M(e)->_0, e1 = GF32M(e)->_1;
+ element_set1(e0);
+ element_set0(e1);
+}
+
+static int gf32m_item_count(element_t e) {
+ UNUSED_VAR(e);
+ return 2;
+}
+
+static element_ptr gf32m_item(element_t a, int i) {
+ element_ptr a0 = GF32M(a)->_0, a1 = GF32M(a)->_1;
+ return i == 0 ? a0 : a1;
+}
+
+static void gf32m_assign(element_t e, element_t a) {
+ element_ptr a0 = GF32M(a)->_0, a1 = GF32M(a)->_1, e0 = GF32M(e)->_0, e1 =
+ GF32M(e)->_1;
+ element_set(e0, a0);
+ element_set(e1, a1);
+}
+
+static void gf32m_random(element_t e) {
+ element_ptr e0 = GF32M(e)->_0, e1 = GF32M(e)->_1;
+ element_random(e0);
+ element_random(e1);
+}
+
+/* return 0 if $a == b$, 1 otherwise */
+static int gf32m_cmp(element_t a, element_t b) {
+ element_ptr a0 = GF32M(a)->_0, a1 = GF32M(a)->_1, b0 = GF32M(b)->_0, b1 =
+ GF32M(b)->_1;
+ return element_cmp(a0, b0) || element_cmp(a1, b1);
+}
+
+/* $c <- a+b$ */
+static void gf32m_add(element_t c, element_t a, element_t b) {
+ element_ptr a0 = GF32M(a)->_0, a1 = GF32M(a)->_1, b0 = GF32M(b)->_0, b1 =
+ GF32M(b)->_1, c0 = GF32M(c)->_0, c1 = GF32M(c)->_1;
+ element_add(c0, a0, b0);
+ element_add(c1, a1, b1);
+}
+
+/* $c <- a-b$ */
+static void gf32m_sub(element_t c, element_t a, element_t b) {
+ element_ptr a0 = GF32M(a)->_0, a1 = GF32M(a)->_1, b0 = GF32M(b)->_0, b1 =
+ GF32M(b)->_1, c0 = GF32M(c)->_0, c1 = GF32M(c)->_1;
+ element_sub(c0, a0, b0);
+ element_sub(c1, a1, b1);
+}
+
+/* $c <- (-a)$ */
+static void gf32m_neg(element_t c, element_t a) {
+ element_ptr a0 = GF32M(a)->_0, a1 = GF32M(a)->_1, c0 = GF32M(c)->_0, c1 =
+ GF32M(c)->_1;
+ element_neg(c0, a0);
+ element_neg(c1, a1);
+}
+
+/* $e<- a*b$ */
+static void gf32m_mult(element_t e, element_t a, element_t b) {
+ element_ptr a0 = GF32M(a)->_0, a1 = GF32M(a)->_1, b0 = GF32M(b)->_0, b1 =
+ GF32M(b)->_1, e0 = GF32M(e)->_0, e1 = GF32M(e)->_1;
+ field_ptr base = BASE(a);
+ element_t a0b0, a1b1, t0, t1, c1;
+ element_init(a0b0, base);
+ element_init(a1b1, base);
+ element_init(t0, base);
+ element_init(t1, base);
+ element_init(c1, base);
+ element_mul(a0b0, a0, b0);
+ element_mul(a1b1, a1, b1);
+ element_add(t0, a1, a0);
+ element_add(t1, b1, b0);
+ element_mul(c1, t0, t1); // c1 == (a1+a0)*(b1+b0)
+ element_sub(c1, c1, a1b1);
+ element_sub(c1, c1, a0b0);
+ element_ptr c0 = a0b0;
+ element_sub(c0, c0, a1b1); // c0 == a0*b0 - a1*b1
+ element_set(e0, c0);
+ element_set(e1, c1);
+ element_clear(a0b0);
+ element_clear(a1b1);
+ element_clear(t0);
+ element_clear(t1);
+ element_clear(c1);
+}
+
+/* $e <- a^3$ */
+static void gf32m_cubic(element_t e, element_t a) {
+ element_ptr a0 = GF32M(a)->_0, a1 = GF32M(a)->_1, e0 = GF32M(e)->_0, e1 =
+ GF32M(e)->_1;
+ field_ptr base = BASE(a);
+ element_t c0, c1;
+ element_init(c0, base);
+ element_init(c1, base);
+ element_cubic(c0, a0);
+ element_cubic(c1, a1);
+ element_neg(c1, c1); // c1 == -(a1^3)
+ element_set(e0, c0);
+ element_set(e1, c1);
+ element_clear(c0);
+ element_clear(c1);
+}
+
+void field_clear_gf32m(field_t f) {
+ UNUSED_VAR(f);
+}
+
+/* initialize the finite field as $base_field[x]/(x^2 + 1)$, whose base field is $b$ */
+void field_init_gf32m(field_t f, field_t b) {
+ field_init(f);
+ f->data = b;
+ f->field_clear = field_clear_gf32m;
+ f->init = gf32m_init;
+ f->clear = gf32m_clear;
+ f->set = gf32m_assign;
+ f->set0 = gf32m_set0;
+ f->set1 = gf32m_set1;
+ f->random = gf32m_random;
+ f->cmp = gf32m_cmp;
+ f->add = gf32m_add;
+ f->sub = gf32m_sub;
+ f->neg = gf32m_neg;
+ f->mul = gf32m_mult;
+ f->cubic = gf32m_cubic;
+ f->item_count = gf32m_item_count;
+ f->item = gf32m_item;
+ f->out_str = gf32m_out_str;
+ mpz_pow_ui(f->order, b->order, 2);
+ f->name = "GF(3^{2*m})";
+}
+
+static size_t gf33m_out_str(FILE *stream, int base, element_t e) {
+ UNUSED_VAR(base);
+ element_ptr e0 = GF33M(e)->_0, e1 = GF33M(e)->_1, e2 = GF33M(e)->_2;
+ size_t size = 0;
+ size += element_out_str(stream, base, e0);
+ size += element_out_str(stream, base, e1);
+ size += element_out_str(stream, base, e2);
+ return size;
+}
+
+static void gf33m_init(element_t e) {
+ e->data = pbc_malloc(sizeof(gf33m_s));
+ gf33m_ptr p = (gf33m_ptr) e->data;
+ field_ptr base = BASE(e);
+ element_init(p->_0, base);
+ element_init(p->_1, base);
+ element_init(p->_2, base);
+}
+
+static void gf33m_clear(element_t e) {
+ gf33m_ptr p = (gf33m_ptr) e->data;
+ element_clear(p->_0);
+ element_clear(p->_1);
+ element_clear(p->_2);
+ pbc_free(e->data);
+}
+
+static void gf33m_set0(element_t e) {
+ element_ptr e0 = GF33M(e)->_0, e1 = GF33M(e)->_1, e2 = GF33M(e)->_2;
+ element_set0(e0);
+ element_set0(e1);
+ element_set0(e2);
+}
+
+static void gf33m_set1(element_t e) {
+ element_ptr e0 = GF33M(e)->_0, e1 = GF33M(e)->_1, e2 = GF33M(e)->_2;
+ element_set1(e0);
+ element_set0(e1);
+ element_set0(e2);
+}
+
+static int gf33m_item_count(element_t e) {
+ UNUSED_VAR(e);
+ return 3;
+}
+
+static element_ptr gf33m_item(element_t a, int i) {
+ element_ptr a0 = GF33M(a)->_0, a1 = GF33M(a)->_1, a2 = GF33M(a)->_2;
+ return i == 0 ? a0 : (i == 1 ? a1 : a2);
+}
+
+static void gf33m_assign(element_t e, element_t a) {
+ element_ptr a0 = GF33M(a)->_0, a1 = GF33M(a)->_1, a2 = GF33M(a)->_2, e0 =
+ GF33M(e)->_0, e1 = GF33M(e)->_1, e2 = GF33M(e)->_2;
+ element_set(e0, a0);
+ element_set(e1, a1);
+ element_set(e2, a2);
+}
+
+static void gf33m_random(element_t e) {
+ element_ptr e0 = GF33M(e)->_0, e1 = GF33M(e)->_1, e2 = GF33M(e)->_2;
+ element_random(e0);
+ element_random(e1);
+ element_random(e2);
+}
+
+/* return 0 if $a == b$, 1 otherwise */
+static int gf33m_cmp(element_t a, element_t b) {
+ element_ptr a0 = GF33M(a)->_0, a1 = GF33M(a)->_1, a2 = GF33M(a)->_2, b0 =
+ GF33M(b)->_0, b1 = GF33M(b)->_1, b2 = GF33M(b)->_2;
+ return element_cmp(a0, b0) || element_cmp(a1, b1) || element_cmp(a2, b2);
+}
+
+/* $c <- a+b$ */
+static void gf33m_add(element_t c, element_t a, element_t b) {
+ element_ptr a0 = GF33M(a)->_0, a1 = GF33M(a)->_1, a2 = GF33M(a)->_2, b0 =
+ GF33M(b)->_0, b1 = GF33M(b)->_1, b2 = GF33M(b)->_2, c0 =
+ GF33M(c)->_0, c1 = GF33M(c)->_1, c2 = GF33M(c)->_2;
+ element_add(c0, a0, b0);
+ element_add(c1, a1, b1);
+ element_add(c2, a2, b2);
+}
+
+/* $c <- a-b$ */
+static void gf33m_sub(element_t c, element_t a, element_t b) {
+ element_ptr a0 = GF33M(a)->_0, a1 = GF33M(a)->_1, a2 = GF33M(a)->_2, b0 =
+ GF33M(b)->_0, b1 = GF33M(b)->_1, b2 = GF33M(b)->_2, c0 =
+ GF33M(c)->_0, c1 = GF33M(c)->_1, c2 = GF33M(c)->_2;
+ element_sub(c0, a0, b0);
+ element_sub(c1, a1, b1);
+ element_sub(c2, a2, b2);
+}
+
+/* $c <- a*b$ */
+static void gf33m_mult(element_t e, element_t a, element_t b) {
+ element_ptr a0 = GF33M(a)->_0, a1 = GF33M(a)->_1, a2 = GF33M(a)->_2, b0 =
+ GF33M(b)->_0, b1 = GF33M(b)->_1, b2 = GF33M(b)->_2, e0 =
+ GF33M(e)->_0, e1 = GF33M(e)->_1, e2 = GF33M(e)->_2;
+ field_ptr base = BASE(e);
+ element_t t0, t1, c1, a0b0, a1b1, a2b2;
+ element_init(t0, base);
+ element_init(t1, base);
+ element_init(c1, base);
+ element_init(a0b0, base);
+ element_init(a1b1, base);
+ element_init(a2b2, base);
+ element_mul(a0b0, a0, b0);
+ element_mul(a1b1, a1, b1);
+ element_mul(a2b2, a2, b2);
+ element_ptr d0 = a0b0;
+ element_add(t0, a1, a0);
+ element_add(t1, b1, b0);
+ element_t d1;
+ element_init(d1, base);
+ element_mul(d1, t0, t1);
+ element_sub(d1, d1, a1b1);
+ element_sub(d1, d1, a0b0);
+ element_add(t0, a2, a0);
+ element_add(t1, b2, b0);
+ element_t d2;
+ element_init(d2, base);
+ element_mul(d2, t0, t1);
+ element_add(d2, d2, a1b1);
+ element_sub(d2, d2, a2b2);
+ element_sub(d2, d2, a0b0);
+ element_add(t0, a2, a1);
+ element_add(t1, b2, b1);
+ element_t d3;
+ element_init(d3, base);
+ element_mul(d3, t0, t1);
+ element_sub(d3, d3, a2b2);
+ element_sub(d3, d3, a1b1);
+ element_ptr d4 = a2b2;
+ element_add(t0, d0, d3);
+ element_ptr c0 = t0;
+ element_add(c1, d1, d3);
+ element_add(c1, c1, d4);
+ element_add(t1, d2, d4);
+ element_ptr c2 = t1;
+ element_set(e0, c0);
+ element_set(e1, c1);
+ element_set(e2, c2);
+ element_clear(t0);
+ element_clear(t1);
+ element_clear(c1);
+ element_clear(a0b0);
+ element_clear(a1b1);
+ element_clear(a2b2);
+ element_clear(d1);
+ element_clear(d2);
+ element_clear(d3);
+}
+
+/* $e <- a^3$ */
+static void gf33m_cubic(element_t e, element_t a) {
+ field_ptr base = BASE(a);
+ element_ptr a0 = GF33M(a)->_0, a1 = GF33M(a)->_1, a2 = GF33M(a)->_2, e0 =
+ GF33M(e)->_0, e1 = GF33M(e)->_1, e2 = GF33M(e)->_2;
+ element_t a03, a13, a23;
+ element_init(a03, base);
+ element_init(a13, base);
+ element_init(a23, base);
+ element_cubic(a03, a0);
+ element_cubic(a13, a1);
+ element_cubic(a23, a2);
+ element_add(a03, a03, a13);
+ element_add(a03, a03, a23);
+ element_ptr c0 = a03;
+ element_sub(a13, a13, a23);
+ element_ptr c1 = a13;
+ element_ptr c2 = a23;
+ element_set(e0, c0);
+ element_set(e1, c1);
+ element_set(e2, c2);
+ element_clear(a03);
+ element_clear(a13);
+ element_clear(a23);
+}
+
+/* $e <- a^{-1}$ */
+static void gf33m_invert(element_t e, element_t a) {
+ element_ptr a0 = GF33M(a)->_0, a1 = GF33M(a)->_1, a2 = GF33M(a)->_2, e0 =
+ GF33M(e)->_0, e1 = GF33M(e)->_1, e2 = GF33M(e)->_2;
+ field_ptr base = BASE(e);
+ element_t a02, a12, a22;
+ element_init(a02, base);
+ element_init(a12, base);
+ element_init(a22, base);
+ element_mul(a02, a0, a0);
+ element_mul(a12, a1, a1);
+ element_mul(a22, a2, a2);
+ element_t v0;
+ element_init(v0, base);
+ element_sub(v0, a0, a2); // v0 == a0-a2
+ element_t delta;
+ element_init(delta, base);
+ element_mul(delta, v0, a02); // delta = (a0-a2)*(a0^2), free
+ element_sub(v0, a1, a0); // v0 == a1-a0
+ element_t c0;
+ element_init(c0, base);
+ element_mul(c0, v0, a12); // c0 == (a1-a0)*(a1^2)
+ element_add(delta, delta, c0); // delta = (a0-a2)*(a0^2) + (a1-a0)*(a1^2)
+ element_sub(v0, a2, v0); // v0 == a2-(a1-a0) = a0-a1+a2
+ element_t c1;
+ element_init(c1, base);
+ element_mul(c1, v0, a22); // c1 == (a0-a1+a2)*(a2^2)
+ element_add(delta, delta, c1); // delta = (a0-a2)*(a0^2) + (a1-a0)*(a1^2) + (a0-a1+a2)*(a2^2)
+ element_invert(delta, delta); // delta = [(a0-a2)*(a0^2) + (a1-a0)*(a1^2) + (a0-a1+a2)*(a2^2)] ^ {-1}
+ element_add(v0, a02, a22); // v0 == a0^2+a2^2
+ element_t c2;
+ element_init(c2, base);
+ element_mul(c2, a0, a2); // c2 == a0*a2
+ element_sub(c0, v0, c2); // c0 == a0^2+a2^2-a0*a2
+ element_add(v0, a1, a2); // v0 == a1+a2
+ element_t c3;
+ element_init(c3, base);
+ element_mul(c3, a1, v0); // c3 == a1*(a1+a2)
+ element_sub(c0, c0, c3); // c0 == a0^2+a2^2-a0*a2-a1*(a1+a2)
+ element_mul(c0, c0, delta); // c0 *= delta
+ element_mul(c1, a0, a1); // c1 == a0*a1
+ element_sub(c1, a22, c1); // c1 == a2^2-a0*a1
+ element_mul(c1, c1, delta); // c1 *= delta
+ element_sub(c2, a12, c2); // c2 == a1^2-a0*a2
+ element_sub(c2, c2, a22); // c2 == a1^2-a0*a2-a2^2
+ element_mul(c2, c2, delta); // c2 *= delta
+ element_set(e0, c0);
+ element_set(e1, c1);
+ element_set(e2, c2);
+ element_clear(a02);
+ element_clear(a12);
+ element_clear(a22);
+ element_clear(v0);
+ element_clear(delta);
+ element_clear(c0);
+ element_clear(c1);
+ element_clear(c2);
+ element_clear(c3);
+}
+
+void field_clear_gf33m(field_t f) {
+ UNUSED_VAR(f);
+}
+
+/* initialize the finite field as $base_field[x]/(x^3 - x - 1)$, whose base field is $b$ */
+void field_init_gf33m(field_t f, field_t b) {
+ field_init(f);
+ f->data = b;
+ f->field_clear = field_clear_gf33m;
+ f->init = gf33m_init;
+ f->clear = gf33m_clear;
+ f->set = gf33m_assign;
+ f->set0 = gf33m_set0;
+ f->set1 = gf33m_set1;
+ f->random = gf33m_random;
+ f->cmp = gf33m_cmp;
+ f->add = gf33m_add;
+ f->sub = gf33m_sub;
+ f->mul = gf33m_mult;
+ f->cubic = gf33m_cubic;
+ f->invert = gf33m_invert;
+ f->item_count = gf33m_item_count;
+ f->item = gf33m_item;
+ f->out_str = gf33m_out_str;
+ mpz_pow_ui(f->order, b->order, 3);
+ f->name = "GF(3^{3*m})";
+}
+
diff --git a/moon-abe/pbc-0.5.14/arith/tinyfp.c b/moon-abe/pbc-0.5.14/arith/tinyfp.c
new file mode 100644
index 00000000..50e883e1
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/tinyfp.c
@@ -0,0 +1,304 @@
+// F_p for small p, i.e. at most sizeof(long) bytes long.
+// Assumes long long is at least twice long.
+
+// TODO: Fix outstanding bugs and use in PBC.
+
+#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_random.h"
+#include "pbc_fp.h"
+#include "pbc_memory.h"
+
+// Mostly wrappers. We use GMP routines for pow_mpz and invert.
+
+static void fp_init(element_ptr e) {
+ unsigned long *p = e->data = pbc_malloc(sizeof(unsigned long));
+ *p = 0;
+}
+
+static void fp_clear(element_ptr e) {
+ pbc_free(e->data);
+}
+
+static void fp_set_mpz(element_ptr e, mpz_ptr z) {
+ mpz_t r;
+ mpz_init(r);
+ unsigned long *p = e->field->data;
+ unsigned long *l = e->data;
+ mpz_fdiv_r_ui(r, z, *p);
+ *l = mpz_get_ui(r);
+ mpz_clear(r);
+}
+
+static void fp_set_si(element_ptr e, signed long int op) {
+ unsigned long int *d = e->data;
+ unsigned long *p = e->field->data;
+ if (op < 0) {
+ *d = (-op) % *p;
+ *d = *p - *d;
+ } else {
+ *d = op % *p;
+ }
+}
+
+static void fp_to_mpz(mpz_ptr z, element_ptr e) {
+ unsigned long int *l = e->data;
+ mpz_set_ui(z, *l);
+}
+
+static void fp_set0(element_ptr e) {
+ unsigned long int *l = e->data;
+ *l = 0;
+}
+
+static void fp_set1(element_ptr e) {
+ unsigned long int *l = e->data;
+ *l = 1;
+}
+
+static int fp_is1(element_ptr e) {
+ unsigned long int *l = e->data;
+ return *l == 1;
+}
+
+static int fp_is0(element_ptr e) {
+ unsigned long int *l = e->data;
+ return *l == 0;
+}
+
+static size_t fp_out_str(FILE *stream, int base, element_ptr e) {
+ size_t result;
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, e);
+ result = mpz_out_str(stream, base, z);
+ mpz_clear(z);
+ return result;
+}
+
+static void fp_add(element_ptr c, element_ptr a, element_ptr b) {
+ unsigned long *prime = a->field->data;
+ unsigned long *p = a->data;
+ unsigned long *q = b->data;
+ unsigned long *r = c->data;
+ unsigned long l0;
+ l0 = *p + *q;
+ if (l0 < *p) {
+ //overflow
+ l0 -= *prime;
+ }
+ *r = l0 % *prime;
+}
+
+static void fp_double(element_ptr c, element_ptr a) {
+ unsigned long *prime = a->field->data;
+ unsigned long *p = a->data;
+ unsigned long *r = c->data;
+ *r = 2 * *p;
+ if (*r < *p) {
+ //overflow
+ *r -= *prime;
+ }
+ *r = *r % *prime;
+}
+
+static void fp_sub(element_ptr c, element_ptr a, element_ptr b) {
+ unsigned long *prime = a->field->data;
+ unsigned long *p = a->data;
+ unsigned long *q = b->data;
+ unsigned long *r = c->data;
+
+ if (*p >= *q) {
+ *r = *p - *q;
+ } else {
+ *r = *prime - *q + *p;
+ }
+}
+
+static void fp_mul(element_ptr c, element_ptr a, element_ptr b) {
+ unsigned long *prime = a->field->data;
+ unsigned long *p = a->data;
+ unsigned long *q = b->data;
+ unsigned long long ll;
+ unsigned long *r = c->data;
+
+ ll = *p * *q;
+ *r = ll % *prime;
+}
+
+static void fp_square(element_ptr c, element_ptr a) {
+ fp_mul(c, a, a);
+}
+
+static void fp_neg(element_ptr c, element_ptr a) {
+ unsigned long *prime = a->field->data;
+ unsigned long *r = c->data;
+ unsigned long *p = a->data;
+ if (*p) {
+ *r = *prime - *p;
+ } else {
+ *r = 0;
+ }
+}
+
+static void fp_mul_si(element_ptr c, element_ptr a, signed long int op) {
+ unsigned long *prime = a->field->data;
+ unsigned long *p = a->data;
+ unsigned long long ll;
+ unsigned long *r = c->data;
+
+ ll = *p * op;
+ *r = ll % *prime;
+}
+
+static void fp_pow_mpz(element_ptr c, element_ptr a, mpz_ptr op) {
+ unsigned long *r = c->data;
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, a);
+ mpz_powm(z, z, op, a->field->order);
+ *r = mpz_get_ui(z);
+ mpz_clear(z);
+}
+
+static void fp_set(element_ptr c, element_ptr a) {
+ unsigned long *p = a->data;
+ unsigned long *r = c->data;
+ *r = *p;
+}
+
+static void fp_invert(element_ptr c, element_ptr a) {
+ unsigned long *r = c->data;
+ mpz_t z;
+ mpz_init(z);
+ fp_to_mpz(z, a);
+ mpz_invert(z, z, a->field->order);
+ *r = mpz_get_ui(z);
+ mpz_clear(z);
+}
+
+static void fp_random(element_ptr c) {
+ unsigned long *r = c->data;
+ mpz_t z;
+ mpz_init(z);
+ pbc_mpz_random(z, c->field->order);
+ *r = mpz_get_ui(z);
+ mpz_clear(z);
+}
+
+static void fp_from_hash(element_ptr n, void *data, int len) {
+ mpz_t z;
+
+ mpz_init(z);
+ mpz_import(z, len, -1, 1, -1, 0, data);
+ fp_set_mpz(n, z);
+ mpz_clear(z);
+}
+
+static int fp_cmp(element_ptr a, element_ptr b) {
+ unsigned long *p = a->data;
+ unsigned long *q = b->data;
+ return *p != *q;
+}
+
+static int fp_sgn_odd(element_ptr a) {
+ unsigned long *p = a->data;
+ if (!*p) return 0;
+ return *p & 1 ? 1 : -1;
+}
+
+static int fp_is_sqr(element_ptr a) {
+ int res;
+ mpz_t z;
+ mpz_init(z);
+ //0 is a square
+ if (fp_is0(a)) return 1;
+ fp_to_mpz(z, a);
+ res = mpz_legendre(z, a->field->order) == 1;
+ mpz_clear(z);
+ return res;
+}
+
+static int fp_to_bytes(unsigned char *data, element_t e) {
+ unsigned long *p = e->data;
+ unsigned long l = *p;
+ int i, n = e->field->fixed_length_in_bytes;
+ for (i = 0; i < n; i++) {
+ data[n - i - 1] = (unsigned char) l;
+ l >>= 8;
+ }
+ return n;
+}
+
+static int fp_from_bytes(element_t e, unsigned char *data) {
+ unsigned char *ptr = data;
+ unsigned long *p = e->data;
+ int i, n = e->field->fixed_length_in_bytes;
+ *p = 0;
+ for (i=0; i<n; i++) {
+ *p <<= 8;
+ *p += *ptr;
+ ptr++;
+ }
+ return n;
+}
+
+static void fp_field_clear(field_t f) {
+ pbc_free(f->data);
+}
+
+void field_init_tiny_fp(field_ptr f, mpz_t prime) {
+ unsigned long *p;
+
+ PBC_ASSERT(mpz_fits_ulong_p(prime), "modulus too big");
+
+ field_init(f);
+ f->init = fp_init;
+ f->clear = fp_clear;
+ f->set_si = fp_set_si;
+ f->set_mpz = fp_set_mpz;
+ f->out_str = fp_out_str;
+ f->add = fp_add;
+ f->sub = fp_sub;
+ f->set = fp_set;
+ f->mul = fp_mul;
+ f->mul_si = fp_mul_si;
+ f->square = fp_square;
+ f->doub = fp_double;
+ f->pow_mpz = fp_pow_mpz;
+ f->neg = fp_neg;
+ f->cmp = fp_cmp;
+ f->sign = fp_sgn_odd;
+ f->invert = fp_invert;
+ f->random = fp_random;
+ f->from_hash = fp_from_hash;
+ f->is1 = fp_is1;
+ f->is0 = fp_is0;
+ f->set0 = fp_set0;
+ f->set1 = fp_set1;
+ f->is_sqr = fp_is_sqr;
+ f->sqrt = element_tonelli;
+ f->field_clear = fp_field_clear;
+ f->to_bytes = fp_to_bytes;
+ f->from_bytes = fp_from_bytes;
+ f->to_mpz = fp_to_mpz;
+
+ p = f->data = pbc_malloc(sizeof(long));
+ *p = mpz_get_ui(prime);
+ {
+ unsigned long int l = 255;
+ f->fixed_length_in_bytes = 1;
+ while (l < *p) {
+ f->fixed_length_in_bytes++;
+ l <<= 8;
+ l += 255;
+ }
+ }
+ mpz_set(f->order, prime);
+}
diff --git a/moon-abe/pbc-0.5.14/arith/z.c b/moon-abe/pbc-0.5.14/arith/z.c
new file mode 100644
index 00000000..ff5a4a97
--- /dev/null
+++ b/moon-abe/pbc-0.5.14/arith/z.c
@@ -0,0 +1,263 @@
+// The ring Z.
+//
+// Wrappers around GMP mpz functions.
+#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_z.h"
+#include "pbc_random.h"
+#include "pbc_fp.h"
+#include "pbc_memory.h"
+
+static void z_init(element_ptr e) {
+ e->data = pbc_malloc(sizeof(mpz_t));
+ mpz_init(e->data);
+}
+
+static void z_clear(element_ptr e) {
+ mpz_clear(e->data);
+ pbc_free(e->data);
+}
+
+static void z_set_si(element_ptr e, signed long int op) {
+ mpz_set_si(e->data, op);
+}
+
+static void z_set_mpz(element_ptr e, mpz_ptr z) {
+ mpz_set(e->data, z);
+}
+
+static void z_set0(element_ptr e) {
+ mpz_set_ui(e->data, 0);
+}
+
+static void z_set1(element_ptr e) {
+ mpz_set_ui(e->data, 1);
+}
+
+static size_t z_out_str(FILE *stream, int base, element_ptr e) {
+ return mpz_out_str(stream, base, e->data);
+}
+
+static int z_sgn(element_ptr a) {
+ mpz_ptr z = a->data;
+ return mpz_sgn(z);
+}
+
+static void z_add(element_ptr n, element_ptr a, element_ptr b) {
+ mpz_add(n->data, a->data, b->data);
+}
+
+static void z_sub(element_ptr n, element_ptr a, element_ptr b) {
+ mpz_sub(n->data, a->data, b->data);
+}
+
+static void z_square(element_ptr c, element_ptr a) {
+ mpz_mul(c->data, a->data, a->data);
+}
+
+static void z_double(element_ptr n, element_ptr a) {
+ mpz_mul_2exp(n->data, a->data, 1);
+}
+
+static void z_halve(element_ptr n, element_ptr a) {
+ mpz_tdiv_q_2exp(n->data, a->data, -1);
+}
+
+static void z_mul(element_ptr n, element_ptr a, element_ptr b) {
+ mpz_mul(n->data, a->data, b->data);
+}
+
+static void z_mul_mpz(element_ptr n, element_ptr a, mpz_ptr z) {
+ mpz_mul(n->data, a->data, z);
+}
+
+static void z_mul_si(element_ptr n, element_ptr a, signed long int z) {
+ mpz_mul_si(n->data, a->data, z);
+}
+
+static void z_pow_mpz(element_ptr n, element_ptr a, mpz_ptr z) {
+ mpz_pow_ui(n->data, a->data, mpz_get_ui(z));
+}
+
+static void z_set(element_ptr n, element_ptr a) {
+ mpz_set(n->data, a->data);
+}
+
+static void z_neg(element_ptr n, element_ptr a) {
+ mpz_neg(n->data, a->data);
+}
+
+static void z_invert(element_ptr n, element_ptr a) {
+ if (!mpz_cmpabs_ui(a->data, 1)) {
+ mpz_set(n->data, a->data);
+ } else mpz_set_ui(n->data, 0);
+}
+
+static void z_div(element_ptr c, element_ptr a, element_ptr b) {
+ mpz_tdiv_q(c->data, a->data, b->data);
+}
+
+//(doesn't make sense if order is infinite)
+static void z_random(element_ptr n) {
+ mpz_set_ui(n->data, 0);
+}
+
+static void z_from_hash(element_ptr n, void *data, int len) {
+ mpz_import(n->data, len, -1, 1, -1, 0, data);
+}
+
+static int z_is1(element_ptr n) {
+ return !mpz_cmp_ui((mpz_ptr) n->data, 1);
+}
+
+static int z_is0(element_ptr n) {
+ return mpz_is0(n->data);
+}
+
+static int z_cmp(element_ptr a, element_ptr b) {
+ return mpz_cmp((mpz_ptr) a->data, (mpz_ptr) b->data);
+}
+
+static int z_is_sqr(element_ptr a) {
+ return mpz_perfect_power_p(a->data);
+}
+
+static void z_sqrt(element_ptr c, element_ptr a) {
+ mpz_sqrt(c->data, a->data);
+}
+
+static void z_field_clear(field_t f) {
+ UNUSED_VAR (f);
+}
+
+// OpenSSL convention:
+// 4 bytes containing length
+// followed by number in big-endian, most-significant bit set if negative
+// (prepending null byte if necessary)
+// Positive numbers also the same as mpz_out_raw.
+static int z_to_bytes(unsigned char *data, element_t e) {
+ mpz_ptr z = e->data;
+ size_t msb = mpz_sizeinbase(z, 2);
+ size_t n = 4;
+ size_t i;
+
+ if (!(msb % 8)) {
+ data[4] = 0;
+ n++;
+ }
+ if (mpz_sgn(z) < 0) {
+ mpz_export(data + n, NULL, 1, 1, 1, 0, z);
+ data[4] |= 128;
+ } else {
+ mpz_export(data + n, NULL, 1, 1, 1, 0, z);
+ }
+ n += (msb + 7) / 8 - 4;
+ for (i=0; i<4; i++) {
+ data[i] = (n >> 8 * (3 - i));
+ }
+ n += 4;
+
+ return n;
+}
+
+static int z_from_bytes(element_t e, unsigned char *data) {
+ unsigned char *ptr;
+ size_t i, n;
+ mpz_ptr z = e->data;
+ mpz_t z1;
+ int neg = 0;
+
+ mpz_init(z1);
+ mpz_set_ui(z, 0);
+
+ ptr = data;
+ n = 0;
+ for (i=0; i<4; i++) {
+ n += ((unsigned int) *ptr) << 8 * (3 - i);
+ ptr++;
+ }
+ if (data[4] & 128) {
+ neg = 1;
+ data[4] &= 127;
+ }
+ for (i=0; i<n; i++) {
+ mpz_set_ui(z1, *ptr);
+ mpz_mul_2exp(z1, z1, 8 * (n - 1 - i));
+ ptr++;
+ mpz_add(z, z, z1);
+ }
+ mpz_clear(z1);
+ if (neg) mpz_neg(z, z);
+ return n;
+}
+
+static void z_to_mpz(mpz_ptr z, element_ptr a) {
+ mpz_set(z, a->data);
+}
+
+static int z_length_in_bytes(element_ptr a) {
+ return (mpz_sizeinbase(a->data, 2) + 7) / 8 + 4;
+}
+
+static void z_out_info(FILE *out, field_ptr f) {
+ UNUSED_VAR(f);
+ fprintf(out, "Z: wrapped GMP");
+}
+
+static int z_set_str(element_ptr e, const char *s, int base) {
+ mpz_t z;
+ mpz_init(z);
+ int result = pbc_mpz_set_str(z, s, base);
+ z_set_mpz(e, z);
+ mpz_clear(z);
+ return result;
+}
+
+void field_init_z(field_ptr f) {
+ field_init(f);
+ f->init = z_init;
+ f->clear = z_clear;
+ f->set_si = z_set_si;
+ f->set_mpz = z_set_mpz;
+ f->set_str = z_set_str;
+ f->out_str = z_out_str;
+ f->sign = z_sgn;
+ f->add = z_add;
+ f->sub = z_sub;
+ f->set = z_set;
+ f->square = z_square;
+ f->doub = z_double;
+ f->halve = z_halve;
+ f->mul = z_mul;
+ f->mul_mpz = z_mul_mpz;
+ f->mul_si = z_mul_si;
+ f->pow_mpz = z_pow_mpz;
+ f->neg = z_neg;
+ f->cmp = z_cmp;
+ f->invert = z_invert;
+ f->div = z_div;
+ f->random = z_random;
+ f->from_hash = z_from_hash;
+ f->is1 = z_is1;
+ f->is0 = z_is0;
+ f->set0 = z_set0;
+ f->set1 = z_set1;
+ f->is_sqr = z_is_sqr;
+ f->sqrt = z_sqrt;
+ f->field_clear = z_field_clear;
+ f->to_bytes = z_to_bytes;
+ f->from_bytes = z_from_bytes;
+ f->to_mpz = z_to_mpz;
+ f->length_in_bytes = z_length_in_bytes;
+
+ f->out_info = z_out_info;
+
+ mpz_set_ui(f->order, 0);
+ f->data = NULL;
+ f->fixed_length_in_bytes = -1;
+}