summaryrefslogtreecommitdiffstats
path: root/moon-abe/pbc-0.5.14/arith/poly.c
diff options
context:
space:
mode:
Diffstat (limited to 'moon-abe/pbc-0.5.14/arith/poly.c')
-rw-r--r--moon-abe/pbc-0.5.14/arith/poly.c1724
1 files changed, 0 insertions, 1724 deletions
diff --git a/moon-abe/pbc-0.5.14/arith/poly.c b/moon-abe/pbc-0.5.14/arith/poly.c
deleted file mode 100644
index bd2dad33..00000000
--- a/moon-abe/pbc-0.5.14/arith/poly.c
+++ /dev/null
@@ -1,1724 +0,0 @@
-#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;
-}