diff options
Diffstat (limited to 'moon-abe/pbc-0.5.14/arith/fieldquadratic.c')
-rw-r--r-- | moon-abe/pbc-0.5.14/arith/fieldquadratic.c | 692 |
1 files changed, 692 insertions, 0 deletions
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; + } +} |