#include "gf_complete.h" #include "gf_method.h" #include #include #include #define GF_POLY_COEF_MASK8 0xff #define GF_POLY_COEF_MASK16 0xffff #define GF_POLY_COEF_MASK32 0xffffffff #define GF_POLY_COEF_MASK64 0xffffffffffffffff #define LLUI (long long unsigned int) struct gf_poly_coef_s; typedef struct gf_poly_coef_s { uint64_t coef; uint64_t power; struct gf_poly_coef_s *next; } gf_poly_coef_t; typedef struct gf_poly_s { gf_poly_coef_t *leading_coef; uint64_t num_coefs; gf_t *coef_gf; int w; } gf_poly_t; static uint64_t gf_add(int w, uint64_t a, uint64_t b) { if (w == 8) { return (a & GF_POLY_COEF_MASK8) ^ (b & GF_POLY_COEF_MASK8); } else if (w == 16) { return (a & GF_POLY_COEF_MASK16) ^ (b & GF_POLY_COEF_MASK16); } else if (w == 32) { return (a & GF_POLY_COEF_MASK32) ^ (b & GF_POLY_COEF_MASK32); } else if (w == 64) { return (a & GF_POLY_COEF_MASK64) ^ (b & GF_POLY_COEF_MASK64); } } static uint64_t gf_mult(int w, gf_t* gf, uint64_t a, uint64_t b) { if (w <= 32) { return gf->multiply.w32(gf, a, b); } else if (w == 64) { return gf->multiply.w64(gf, a, b); } } static uint64_t gf_divide(int w, gf_t* gf, uint64_t a, uint64_t b) { if (w <= 32) { return gf->divide.w32(gf, a, b); } else if (w == 64) { return gf->divide.w64(gf, a, b); } } static uint64_t gf_inverse(int w, gf_t* gf, uint64_t a) { if (w <= 32) { return gf->inverse.w32(gf, a); } else if (w == 64) { return gf->inverse.w64(gf, a); } } gf_poly_t* gf_poly_init(int w, gf_t *gf) { gf_poly_t *gf_poly = (gf_poly_t*)malloc(sizeof(gf_poly_t)); if (gf_poly == NULL || gf == NULL) { return NULL; } gf_poly->leading_coef = NULL; gf_poly->num_coefs = 0; gf_poly->coef_gf = gf; gf_poly->w = w; return gf_poly; } void gf_poly_print(gf_poly_t *gf_poly, char *message) { gf_poly_coef_t *tmp; if (gf_poly == NULL) { fprintf(stderr, "0 * x^0\n"); return; } tmp = gf_poly->leading_coef; while (tmp != NULL) { printf("%llu * x^%llu", LLUI tmp->coef, LLUI tmp->power); tmp = tmp->next; if (tmp) { printf(" + "); } } if (message != NULL) { printf(": %s\n", message); } } gf_poly_t* gf_poly_copy(gf_poly_t *poly) { gf_poly_t *new_poly = (gf_poly_t*)malloc(sizeof(gf_poly_t)); gf_poly_coef_t *tmp = poly->leading_coef; if (new_poly == NULL) { return NULL; } new_poly->leading_coef = NULL; new_poly->num_coefs = 0; new_poly->coef_gf = poly->coef_gf; new_poly->w = poly->w; while (tmp != NULL) { gf_poly_add_coef(new_poly, tmp->coef, tmp->power); tmp = tmp->next; } return new_poly; } void gf_poly_clear(gf_poly_t* a) { while (a->leading_coef != NULL) { gf_poly_coef_t *tmp = a->leading_coef; a->leading_coef = tmp->next; free(tmp); } } void gf_poly_free(gf_poly_t **a) { gf_poly_clear(*a); free(*a); *a = NULL; } gf_poly_coef_t* gf_poly_create_node(uint64_t coef, uint64_t power) { gf_poly_coef_t* node = (gf_poly_coef_t*)malloc(sizeof(gf_poly_coef_t)); if (node == NULL) { return NULL; } node->coef = coef; node->power = power; node->next = NULL; return node; } int gf_poly_remove_node(gf_poly_t *gf_poly, uint64_t power) { gf_poly_coef_t* iter = gf_poly->leading_coef; if (iter->power == power) { gf_poly->leading_coef = iter->next; free(iter); return 0; } while (iter->next != NULL) { if (iter->next->power == power) { gf_poly_coef_t* tmp = iter->next; iter->next = iter->next->next; free(tmp); return 0; } iter = iter->next; } return -1; } int gf_poly_add_coef(gf_poly_t *gf_poly, uint64_t coef_val, uint64_t power) { gf_poly_coef_t* node; gf_poly_coef_t* iter = gf_poly->leading_coef; /* * The new node has the highest power, or there are no terms */ if (gf_poly->leading_coef == NULL || gf_poly->leading_coef->power < power) { node = gf_poly_create_node(coef_val, power); node->next = gf_poly->leading_coef; gf_poly->leading_coef = node; return 0; } /* * The new node is of the same power, add the coefs */ if (gf_poly->leading_coef->power == power) { gf_poly->leading_coef->coef = gf_add(gf_poly->w, gf_poly->leading_coef->coef, coef_val); if (gf_poly->leading_coef->coef == 0) { gf_poly_remove_node(gf_poly, power); } return 0; } while (iter->next != NULL) { if (iter->next->power == power) { iter->next->coef = gf_add(gf_poly->w, iter->next->coef, coef_val); if (iter->next->coef == 0) { gf_poly_remove_node(gf_poly, power); } return 0; } if (iter->next->power < power) { node = gf_poly_create_node(coef_val, power); node->next = iter->next; iter->next = node; return 0; } iter = iter->next; } /* * The power passed in is lower than any in the existing poly */ node = gf_poly_create_node(coef_val, power); iter->next = node; return 0; } /* * Compute a+b and store in a */ int gf_poly_add(gf_poly_t* a, gf_poly_t* b) { gf_poly_coef_t* iter = b->leading_coef; while (iter != NULL) { gf_poly_add_coef(a, iter->coef, iter->power); iter = iter->next; } return 0; } /* * Compute a*b and store in a */ int gf_poly_mult(gf_poly_t* a, gf_poly_t* b) { gf_poly_coef_t* a_iter = a->leading_coef; /* * Remove one node at a time from 'a', starting with * highest power. Multiply the removed (coef,power) * by every entry of 'b,' adding each product into 'a.' */ while (a_iter != NULL) { gf_poly_coef_t* tmp = a_iter; gf_poly_coef_t* b_iter = b->leading_coef; uint64_t a_power = a_iter->power; uint64_t a_coef = a_iter->coef; a_iter = a_iter->next; gf_poly_remove_node(a, tmp->power); while (b_iter != NULL) { uint64_t new_power = b_iter->power + a_power; uint64_t new_coef = gf_mult(a->w, a->coef_gf, b_iter->coef, a_coef); gf_poly_add_coef(a, new_coef, new_power); b_iter = b_iter->next; } } return 0; } /* * Compute a % b and store in a */ int gf_poly_reduce(gf_poly_t* a, gf_poly_t* b) { gf_poly_t* c = gf_poly_init(a->w, a->coef_gf); gf_poly_coef_t* a_iter = a->leading_coef; gf_poly_coef_t* b_iter = b->leading_coef; /* * Reduce until the degree of 'a' is less than * the degree of 'b.' At that point 'a' will * contain the remainder of a / b. */ while (a_iter && (a_iter->power >= b_iter->power)) { /* * Get the degree and leading coef of the current * 'b'. */ uint64_t reduce_power = a_iter->power - b_iter->power; uint64_t reduce_coef = gf_divide(a->w, a->coef_gf, a_iter->coef, b_iter->coef); /* * Create a poly that will get rid of leading power * of 'b' when added: c*x^(n-m)*b(x), where c * is the leading coef of 'a', n is the deg of 'a' * and m is the degree of 'b'. */ gf_poly_add_coef(c, reduce_coef, reduce_power); gf_poly_mult(c, b); /* * Add the newly created poly, which will reduce * a(x) by at least one term (leading term). */ gf_poly_add(a, c); gf_poly_clear(c); /* * Grab the new leading term of 'a' */ a_iter = a->leading_coef; } } /* * Get the GCD of a and b, return the result */ gf_poly_t* gf_poly_gcd(gf_poly_t* a, gf_poly_t* b) { gf_poly_t *r1, *r2; gf_poly_t* tmp_swp; if (a->leading_coef == NULL || b->leading_coef == NULL) { return NULL; } if (a->leading_coef->power > b->leading_coef->power) { r1 = a; r2 = b; } else { r1 = b; r2 = a; } while ( 1 ) { if (r2->leading_coef == NULL) { break; } if (r2->leading_coef->power == 0 && r2->leading_coef->coef <= 1) { break; } gf_poly_reduce(r1, r2); tmp_swp = r1; r1 = r2; r2 = tmp_swp; } return r1; } /* * The Ben-Or algorithm for determining irreducibility */ int gf_poly_is_irred(gf_poly_t* poly) { gf_poly_t *gcd; gf_poly_t *prod_of_irred; uint64_t prod_of_irred_power = ((unsigned long long) 1) << poly->w; int n = poly->leading_coef->power / 2; int i; int ret = 0; gf_poly_t *a = gf_poly_copy(poly); prod_of_irred = gf_poly_init(a->w, a->coef_gf); for (i = 1; i <= n; i++) { gf_poly_add_coef(prod_of_irred, 1, prod_of_irred_power); gf_poly_add_coef(prod_of_irred, 1, 1); gf_poly_reduce(prod_of_irred, a); gcd = gf_poly_gcd(a, prod_of_irred); /* * It is irreducible if it is not the product of * non-trivial factors (non-constant). Therefore, * the GCD of the poly and prod_of_irred should be * a constant (0 or 0-degree polynomial). */ if (gcd == NULL) { ret = -1; break; } else if (gcd->leading_coef->power != 0) { ret = -1; break; } else if (gcd->leading_coef->power == 0) { ret = 0; break; } else { ret = -1; break; } // Need if to avoid a overflow error if ((i + 1) <= n) { prod_of_irred_power *= prod_of_irred_power; } gf_poly_clear(prod_of_irred); } gf_poly_free(&a); return ret; } int is_suitible_s(int w, gf_t *gf, uint64_t s) { uint64_t num_elems = ((unsigned long long) 1) << w; uint64_t i = 2; uint64_t i_inv; for (; i < num_elems; i++) { i_inv = gf_inverse(w, gf, i); if ((i ^ i_inv) == s) { fprintf(stderr, "Bailed on %llu ^ %llu = %llu\n", LLUI i, LLUI i_inv, LLUI s); return -1; } if (i % 1000000000 == 0) fprintf(stderr, "Processed %llu\n", LLUI i); } return 0; } static void usage(char *cmd) { fprintf(stderr, "%s w S \n", cmd); fprintf(stderr, "\t will build a trinomial x^2+S*x+1\n"); fprintf(stderr, "OR\n"); fprintf(stderr, "%s w G coef1,power1 ... \n", cmd); fprintf(stderr, "\t will build a polynomial coef1^(power1) + ... + coefn^(powern)\n"); fprintf(stderr, "Example: ./gf_poly 8 - - - G 1,2 2,1 1,0\n"); fprintf(stderr, "\t will build a polynomial x^2+2*x+1 with coefs from GF(2^8)\n"); } /* * Find irred poly of form x^2+sx+1 * a_n*x^n + a_(n-1)*x^(n-1) + ... * * Terms are specified as: a_i,i a_j,j, ... where * i is the degree of the term and a_i is the coef * */ int main(int argc, char **argv) { gf_t gf; int ret; int w; int i; uint64_t irred_coef_s; gf_poly_t *irred_poly; char *term; bzero(&gf, sizeof(gf_t)); if (argc < 4) { usage(argv[0]); return -1; } w = atoi(argv[1]); ret = create_gf_from_argv(&gf, w, argc, argv, 3); if (ret <= 0) { fprintf(stderr, "Could not create a GF\n"); return -1; } irred_poly = gf_poly_init(w, &gf); i = ret + 1; if (strlen(argv[i]) > 1) { usage(argv[0]); exit(1); } if (argv[i][0] == 'S') { i++; irred_coef_s = (uint64_t)strtoull(argv[i], NULL, 10); /* * If this is a trinomial of the form x^2+s*x+1, then * we can do a quick pre-check to see if this may be * an irreducible polynomial. */ if (is_suitible_s(w, &gf, irred_coef_s) < 0) { fprintf(stderr, "%llu is not a suitable coeffient!\n", LLUI irred_coef_s); return -1; } else { fprintf(stderr, "%llu IS A suitable coeffient!\n", LLUI irred_coef_s); } gf_poly_add_coef(irred_poly, 1, 2); gf_poly_add_coef(irred_poly, irred_coef_s, 1); gf_poly_add_coef(irred_poly, 1, 0); } else if (argv[i][0] == 'G') { term = argv[++i]; while (term != NULL) { uint64_t coef = strtoull(strtok(term, ","), NULL, 10); uint64_t power = strtoull(strtok(NULL, ","), NULL, 10); gf_poly_add_coef(irred_poly, coef, power); if (i < argc) { term = argv[++i]; } else { break; } } } else { usage(argv[0]); exit(1); } gf_poly_print(irred_poly, " specified via the command line\n"); ret = gf_poly_is_irred(irred_poly); if (ret < 0) { gf_poly_print(irred_poly, " IS NOT irreducible\n"); } else { gf_poly_print(irred_poly, " IS irreducible\n"); } return 0; }