#include "codecrypt.h" using namespace ccr; int polynomial::degree() const { int r = -1; for (uint i = 0; i < size(); ++i) if (item (i) ) r = i; return r; } void polynomial::strip() { resize (degree() + 1); } bool polynomial::zero() const { for (uint i = 0; i < size(); ++i) if (item (i) ) return false; return true; } bool polynomial::one() const { if (degree() != 0) return false; return item (0) == 1; } void polynomial::add (const polynomial&f, gf2m&fld) { int df = f.degree(); if (df > degree() ) resize (df + 1); for (int i = 0; i <= df; ++i) item (i) = fld.add (item (i), f[i]); } void polynomial::add_mult (const polynomial&f, uint mult, gf2m&fld) { int df = f.degree(); if (df > degree() ) resize (df + 1); for (int i = 0; i <= df; ++i) item (i) = fld.add (item (i), fld.mult (mult, f[i]) ); } void polynomial::mod (const polynomial&f, gf2m&fld) { int df = f.degree(); if (df < 0) { //mod 0 -> 0 clear(); return; } int d; uint hi = fld.inv (f[df]); // while there's place to substract, reduce by x^(d-df)-multiply of f for (d = degree(); d >= df; --d) if (item (d) ) { uint t = fld.mult (item (d), hi); for (int i = 0; i <= df; ++i) item (i + d - df) = fld.add (item (i + d - df), fld.mult (t, f[i]) ); } strip(); } void polynomial::mult (const polynomial&b, gf2m&fld) { polynomial a = *this; clear(); uint i, j; int da, db; da = a.degree(); db = b.degree(); if ( (da < 0) || (db < 0) ) { //multiply by zero clear(); return; } resize (da + db + 1, 0); for (i = 0; i <= da; ++i) if (a[i]) for (j = 0; j <= db; ++j) item (i + j) = fld.add (item (i + j), fld.mult (a[i], b[j]) ); } polynomial polynomial::gcd (polynomial b, gf2m&fld) { polynomial a = *this; //eukleides if (a.degree() < 0) return b; for (;;) { if (b.zero() ) return a; a.mod (b, fld); if (a.zero() ) return b; b.mod (a, fld); } //unreachable return polynomial(); } bool polynomial::is_irreducible (gf2m&fld) const { //Ben-Or irreducibility test polynomial xi; //x^(2^i) in our case polynomial xmodf, t; xmodf.resize (2); //precompute (x mod f) although it is usually just x xmodf[0] = 0; xmodf[1] = 1; //x xi = xmodf; xmodf.mod (*this, fld); //mod f uint d = degree(); for (uint i = 1; i <= d / 2; ++i) { for (uint j = 0; j < fld.m; ++j) { t = xi; t.mult (xi, fld); t.mod (*this, fld); xi.swap (t); } t = xi; t.add (xmodf, fld); t = t.gcd (*this, fld); if (t.degree() > 0) //gcd(f,x^2^i - x mod f) != const return false; } return true; } void polynomial::generate_random_irreducible (uint s, gf2m&fld, prng& rng) { resize (s + 1); item (s) = 1; //degree s item (0) = 1 + rng.random (fld.n - 1); for (uint i = 1; i < s; ++i) item (i) = rng.random (fld.n); while (!is_irreducible (fld) ) { uint pos = rng.random (s); item (pos) = pos == 0 ? (1 + rng.random (fld.n - 1) ) : rng.random (fld.n); } } bool polynomial::compute_square_root_matrix (vector&r, gf2m&fld) { // step 1, generate a square matrix of squares mod poly. int d = degree(); if (d < 0) return false; vectorl; l.resize (d); polynomial col, t; for (int i = 0; i < d; ++i) { col.clear(); col.resize (i + 1, 0); col[i] = 1; t = col; col.mult (t, fld); col.mod (*this, fld); col.resize (d, 0); l[i] = col; } // step 2, gauss-jordan inverse to unit matrix r.resize (d); for (int i = 0; i < d; ++i) { r[i].clear(); r[i].resize (d, 0); r[i][i] = 1; } #define add_row_mult(from,to,coeff) \ for(int c=0;c= 0; --i) { for (j = 0; j < i; ++j) { a = l[i][j]; if (a == 0) continue; add_row_mult (i, j, a); } } return true; } uint polynomial::eval (uint x, gf2m&fld) const { uint r = 0; //horner for (int i = degree(); i >= 0; --i) r = fld.add (item (i), fld.mult (r, x) ); return r; } void polynomial::compute_goppa_check_matrix (matrix&r, gf2m&fld) { if (degree() < 0) return; //wrongly initialized polynomial uint t = degree(); vector > vd, h; uint i, j, k; //construction from Barreto's slides with maximal support L=[0..fld.n) vd.resize (fld.n); for (i = 0; i < fld.n; ++i) { vd[i].resize (t); vd[i][0] = fld.inv (eval (i, fld) ); } //compute support powers for (j = 0; j < fld.n; ++j) for (i = 1; i < t; ++i) vd[j][i] = fld.mult (vd[j][i-1], j); //multiply by goppa coefficients (compute t*vd) h.resize (fld.n); for (i = 0; i < fld.n; ++i) { h[i].resize (t, 0); for (j = 0; j < t; ++j) //computing the element h[i][j] for (k = 0; k <= j; ++k) //k = column index of t h[i][j] = fld.add (h[i][j], fld.mult (item (t - j + k), vd[i][k]) ); } //now convert to binary r.resize (fld.n); for (i = 0; i < fld.n; ++i) { r[i].resize (fld.m * t); for (j = 0; j < fld.m * t; ++j) r[i][j] = (h[i][j/fld.m] >> (j % fld.m) ) & 1; } } void polynomial::make_monic (gf2m&fld) { int d = degree(); if (d < 0) return; uint m = fld.inv (item (d) ); for (uint i = 0; i <= d; ++i) item (i) = fld.mult (item (i), m); } void polynomial::shift (uint n) { if (degree() < 0) return; insert (begin(), n, 0); } void polynomial::square (gf2m&fld) { polynomial a = *this; this->mult (a, fld); } void polynomial::sqrt (vector& sqInv, gf2m&fld) { polynomial a = *this; clear(); uint s=sqInv.size(); resize (s, 0); for (uint i = 0; i < s; ++i) { for (uint j = 0; j < s; ++j) { if (j >= a.size() ) break; if (i >= sqInv[j].size() ) continue; item (i) = fld.add (item (i), fld.mult (sqInv[j][i], a[j]) ); } } strip(); for (uint i = 0; i < size(); ++i) item (i) = fld.sq_root (item (i) ); } void polynomial::div (polynomial&p, polynomial&m, gf2m&fld) { polynomial r0, r1, s0, s1, s2, q1, q2; r0 = m; r1 = p; r1.mod (m, fld); s0.clear(); s1 = *this; s1.mod (m, fld); while (r1.degree() >= 0) { r0.divmod (r1, q1, q2, fld); r0.swap (r1); r1.swap (q2); s2 = s0; q1.mult (s1, fld); q1.mod (m, fld); s2.add (q1, fld); s0.swap (s1); s1.swap (s2); } *this = s0; if (r0.degree() >= 0) { uint m = fld.inv (r0[r0.degree() ]); for (uint i = 0; i < size(); ++i) item (i) = fld.mult (item (i), m); } } void polynomial::divmod (polynomial&d, polynomial&res, polynomial&rem, gf2m&fld) { int degd = d.degree(); if (degd < 0) return; uint headInv = fld.inv (d[degd]); rem = *this; res.clear(); int t; while ( (t = rem.degree() ) >= degd) { int rp = t - degd; if (res.size() < rp + 1) res.resize (rp + 1, 0); res[rp] = fld.mult (headInv, rem[t]); for (uint i = 0; i <= degd; ++i) rem[i+rp] = fld.add (rem[i+rp], fld.mult (res[rp], d[i]) ); } } void polynomial::inv (polynomial&m, gf2m&fld) { polynomial a = *this; this->resize (1); item (0) = 1; div (a, m, fld); } void polynomial::mod_to_fracton (polynomial&a, polynomial&b, polynomial&m, gf2m&fld) { int deg = m.degree() / 2; polynomial a0, a1, b0, b1, t1, t2; a0 = m; a1 = *this; a1.mod (m, fld); b0.resize (1, 0); b1.resize (1, 1); while (a1.degree() > deg) { a0.divmod (a1, t1, t2, fld); a0.swap (a1); a1.swap (t2); t1.mult (b1, fld); t1.mod (m, fld); t1.add (b0, fld); b0.swap (b1); b1.swap (t1); } a = a1; b = b1; }