// BenOr algorithm // Why not return true or false? - of course C was written by the dinosours and booleans did not exist // during that era. :/ int getReducibilty(unsigned long val) { bits temp = bits_initlong(val); int degree = poly_degree(temp); bits one = bits_initlong(1l); int i = 1; for(; i <= degree/2; i++) { bits b = poly_reduceExp(temp, i); bits g = poly_gcd(temp, b); if (!eq(one, g)) return 1; } return 0; }
u_int32_t is_irreducible(mpzpoly_t poly, u_int32_t p) { /* this uses Proposition 3.4.4 of H. Cohen, "A Course in Computational Algebraic Number Theory". The tests below are much simpler than trying to factor 'poly' */ u_int32_t i; poly_t f, tmp; poly_reduce_mod_p(f, poly, p); poly_make_monic(f, f, p); /* in practice, the degree of f will be 8 or less, and we want to compute GCDs for all prime numbers that divide the degree. For this limited range the loop below avoids duplicated code */ for (i = 2; i < f->degree; i++) { if (f->degree % i) continue; /* for degree d, compute x^(p^(d/i)) - x */ poly_xpow_pd(tmp, p, f->degree / i, f); if (tmp->degree == 0) { tmp->degree = 1; tmp->coef[1] = p - 1; } else { tmp->coef[1] = mp_modsub_1(tmp->coef[1], (u_int32_t)1, p); poly_fix_degree(tmp); } /* this must be relatively prime to f */ poly_gcd(tmp, f, p); if (tmp->degree > 0 || tmp->coef[0] != 1) { return 0; } } /* final test: x^(p^d) mod f must equal x */ poly_xpow_pd(tmp, p, f->degree, f); if (tmp->degree == 1 && tmp->coef[0] == 0 && tmp->coef[1] == 1) return 1; return 0; }
// retourne le degré du plus petit facteur int poly_degppf(poly_t g) { int i, d, res; poly_t *u, p, r, s; d = poly_deg(g); u = malloc(d * sizeof (poly_t *)); for (i = 0; i < d; ++i) u[i] = poly_alloc(d + 1); poly_sqmod_init(g, u); p = poly_alloc(d - 1); poly_set_deg(p, 1); poly_set_coeff(p, 1, gf_unit()); r = poly_alloc(d - 1); res = d; for (i = 1; i <= (d / 2) * gf_extd(); ++i) { poly_sqmod(r, p, u, d); // r = x^(2^i) mod g if ((i % gf_extd()) == 0) { // donc 2^i = (2^m)^j (m deg d'extension) poly_addto_coeff(r, 1, gf_unit()); poly_calcule_deg(r); // le degré peut changer s = poly_gcd(g, r); if (poly_deg(s) > 0) { poly_free(s); res = i / gf_extd(); break; } poly_free(s); poly_addto_coeff(r, 1, gf_unit()); poly_calcule_deg(r); // le degré peut changer } // on se sert de s pour l'échange s = p; p = r; r = s; } poly_free(p); poly_free(r); for (i = 0; i < d; ++i) { poly_free(u[i]); } free(u); return res; }
// Returns the degree of the smallest factor int poly_degppf(poly_t g) { int i, d, res; poly_t *u, p, r, s; d = poly_deg(g); u = malloc(d * sizeof (poly_t *)); for (i = 0; i < d; ++i) u[i] = poly_alloc(d + 1); poly_sqmod_init(g, u); p = poly_alloc(d - 1); poly_set_deg(p, 1); poly_set_coeff(p, 1, gf_unit()); r = poly_alloc(d - 1); res = d; for (i = 1; i <= (d / 2) * gf_extd(); ++i) { poly_sqmod(r, p, u, d); // r = x^(2^i) mod g if ((i % gf_extd()) == 0) { // so 2^i = (2^m)^j (m ext. degree) poly_addto_coeff(r, 1, gf_unit()); poly_calcule_deg(r); // The degree may change s = poly_gcd(g, r); if (poly_deg(s) > 0) { poly_free(s); res = i / gf_extd(); break; } poly_free(s); poly_addto_coeff(r, 1, gf_unit()); poly_calcule_deg(r); // The degree may change } // No need for the exchange s s = p; p = r; r = s; } poly_free(p); poly_free(r); for (i = 0; i < d; ++i) { poly_free(u[i]); } free(u); return res; }
/*------------------------------------------------------------------*/ u_int32_t poly_get_zeros(u_int32_t *zeros, mpzpoly_t _f, u_int32_t p, u_int32_t count_only) { /* Find all roots of multiplicity 1 for polynomial _f, when the coefficients of _f are reduced mod p. The leading coefficient of _f mod p is returned Make count_only nonzero if only the number of roots and not their identity matters; this is much faster */ poly_t g, f; u_int32_t i, j, num_zeros; /* reduce the coefficients mod p */ poly_reduce_mod_p(f, _f, p); /* bail out if the polynomial is zero */ if (f->degree == 0) return 0; /* pull out roots of zero. We do this early to avoid having to handle degree-1 polynomials in later code */ num_zeros = 0; if (f->coef[0] == 0) { for (i = 1; i <= f->degree; i++) { if (f->coef[i]) break; } for (j = i; i <= f->degree; i++) { f->coef[i - j] = f->coef[i]; } f->degree = i - j - 1; zeros[num_zeros++] = 0; } /* handle trivial cases */ if (f->degree == 0) { return num_zeros; } else if (f->degree == 1) { u_int32_t w = f->coef[1]; if (count_only) return num_zeros + 1; if (w != 1) { w = mp_modinv_1(w, p); zeros[num_zeros++] = mp_modmul_1(p - f->coef[0], w, p); } else { zeros[num_zeros++] = (f->coef[0] == 0 ? 0 : p - f->coef[0]); } return num_zeros; } /* the rest of the algorithm assumes p is odd, which will not work for p=2. Fortunately, in that case there are only two possible roots, 0 and 1. The above already tried 0, so try 1 here */ if (p == 2) { u_int32_t parity = 0; for (i = 0; i <= f->degree; i++) parity ^= f->coef[i]; if (parity == 0) zeros[num_zeros++] = 1; return num_zeros; } /* Compute g = gcd(f, x^(p-1) - 1). The result is a polynomial that is the product of all the linear factors of f. A given factor only occurs once in this polynomial */ poly_xpow(g, 0, p-1, f, p); g->coef[0] = mp_modsub_1(g->coef[0], 1, p); poly_fix_degree(g); poly_gcd(g, f, p); /* no linear factors, no service */ if (g->degree < 1 || count_only) return num_zeros + g->degree; /* isolate the linear factors */ get_zeros_rec(zeros, 0, &num_zeros, g, p); return num_zeros; }
/*------------------------------------------------------------------*/ static void get_zeros_rec(u_int32_t *zeros, u_int32_t shift, u_int32_t *num_zeros, poly_t f, u_int32_t p) { /* get the zeros of a poly, f, that is known to split completely over Z/pZ. Many thanks to Bob Silverman for a neat implementation of Cantor-Zassenhaus splitting */ poly_t g, xpow; u_int32_t degree1, degree2; /* base cases of the recursion: we can find the roots of linear and quadratic polynomials immediately */ if (f->degree == 1) { u_int32_t w = f->coef[1]; if (w != 1) { w = mp_modinv_1(w, p); zeros[(*num_zeros)++] = mp_modmul_1(p - f->coef[0],w,p); } else { zeros[(*num_zeros)++] = (f->coef[0] == 0 ? 0 : p - f->coef[0]); } return; } else if (f->degree == 2) { /* if f is a quadratic polynomial, then it will always have two distinct nonzero roots or else we wouldn't have gotten to this point. The two roots are the solution of a general quadratic equation, mod p */ u_int32_t d = mp_modmul_1(f->coef[0], f->coef[2], p); u_int32_t root1 = p - f->coef[1]; u_int32_t root2 = root1; u_int32_t ainv = mp_modinv_1( mp_modadd_1(f->coef[2], f->coef[2], p), p); d = mp_modsub_1(mp_modmul_1(f->coef[1], f->coef[1], p), mp_modmul_1(4, d, p), p); d = mp_modsqrt_1(d, p); root1 = mp_modadd_1(root1, d, p); root2 = mp_modsub_1(root2, d, p); zeros[(*num_zeros)++] = mp_modmul_1(root1, ainv, p); zeros[(*num_zeros)++] = mp_modmul_1(root2, ainv, p); return; } /* For an increasing sequence of integers 's', compute the polynomial gcd((x-s)^(p-1)/2 - 1, f). If the result is not g = 1 or g = f, this is a nontrivial splitting of f. References require choosing s randomly, but however s is chosen there is a 50% chance that it will split f. Since only 0 <= s < p is valid, we choose each s in turn; choosing random s allows the possibility that the same s gets chosen twice (mod p), which would waste time */ while (shift < p) { poly_xpow(xpow, shift, (p-1)/2, f, p); poly_cp(g, xpow); g->coef[0] = mp_modsub_1(g->coef[0], 1, p); poly_fix_degree(g); poly_gcd(g, f, p); if (g->degree > 0) break; shift++; } /* f was split; repeat the splitting process on the two halves of f. The linear factors of f are either somewhere in x^((p-1)/2) - 1, in x^((p-1)/2) + 1, or 'shift' itself is a linear factor. Test each of these possibilities in turn. In the first two cases, begin trying values of s strictly greater than have been tried thus far */ degree1 = g->degree; get_zeros_rec(zeros, shift + 1, num_zeros, g, p); poly_cp(g, xpow); g->coef[0] = mp_modadd_1(g->coef[0], 1, p); poly_fix_degree(g); poly_gcd(g, f, p); degree2 = g->degree; if (degree2 > 0) get_zeros_rec(zeros, shift + 1, num_zeros, g, p); if (degree1 + degree2 < f->degree) zeros[(*num_zeros)++] = (shift == 0 ? 0 : p - shift); }