aboutsummaryrefslogtreecommitdiffstats
path: root/moon-abe/pbc-0.5.14/arith/multiz.c
diff options
context:
space:
mode:
Diffstat (limited to 'moon-abe/pbc-0.5.14/arith/multiz.c')
-rw-r--r--moon-abe/pbc-0.5.14/arith/multiz.c589
1 files changed, 589 insertions, 0 deletions
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);
+}