void PlainTraceVec(vec_ZZ_p& S, const ZZ_pX& ff) { if (deg(ff) <= 0) LogicError("TraceVec: bad args"); ZZ_pX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; ZZ acc, t; ZZ_p t1; S[0] = n; for (k = 1; k < n; k++) { mul(acc, rep(f.rep[n-k]), k); for (i = 1; i < k; i++) { mul(t, rep(f.rep[n-i]), rep(S[k-i])); add(acc, acc, t); } conv(t1, acc); negate(S[k], t1); } }
void CharPolyMod(zz_pX& g, const zz_pX& a, const zz_pX& ff) { zz_pX f = ff; MakeMonic(f); long n = deg(f); if (n <= 0 || deg(a) >= n) Error("CharPoly: bad args"); if (IsZero(a)) { clear(g); SetCoeff(g, n); return; } if (n > 90 || (zz_p::PrimeCnt() <= 1 && n > 45)) { zz_pX h; MinPolyMod(h, a, f); if (deg(h) == n) { g = h; return; } } if (zz_p::modulus() < n+1) { HessCharPoly(g, a, f); return; } vec_zz_p u(INIT_SIZE, n+1), v(INIT_SIZE, n+1); zz_pX h, h1; negate(h, a); long i; for (i = 0; i <= n; i++) { u[i] = i; add(h1, h, u[i]); resultant(v[i], f, h1); } interpolate(g, u, v); }
void PlainTraceVec(vec_zz_p& S, const zz_pX& ff) { if (deg(ff) <= 0) Error("TraceVec: bad args"); zz_pX f; f = ff; MakeMonic(f); long n = deg(f); S.SetLength(n); if (n == 0) return; long k, i; zz_p acc, t; const zz_p *fp = f.rep.elts();; zz_p *sp = S.elts(); sp[0] = n; for (k = 1; k < n; k++) { mul(acc, fp[n-k], k); for (i = 1; i < k; i++) { mul(t, fp[n-i], rep(sp[k-i])); add(acc, acc, t); } negate(sp[k], acc); } }
/////////////////////////////////////////////////////////////////////////// // PURPOSE: // Given syndrome ssWithoutEvens of BCH code with design distance d, // finds sparse vector (with no more than // (d-1)/2 ones) with that syndrome // (note that syndrome as well sparse vector // representation are defined at BCHSyndromeCompute above). // 'answer' returns positions of ones in the resulting vector. // These positions are elements of GF2E (i.e., we view the vector // as a vector whose positions are indexed by elements of GF2E). // Returns false if no such vector exists, true otherwise // The input syndrome is assumed to not have even powers, i.e., // has (d-1)/2 elements, such as the syndrome computed by BCHSyndromeCompute. // // ASSUMPTIONS: // Let m=GF2E::degree() (i.e., the field is GF(2^m)). // This algorithm assumes that d is odd, greater than 1, and less than 2^m. // (else BCH codes don't make sense). // Assumes input is of length (d-1)/2. // // ALGORITHM USED: // Implements BCH decoding based on Euclidean algorithm; // For the explanation of the algorithm, see // Syndrome Encoding and Decoding of BCH Codes in Sublinear Time // (Excerpted from Fuzzy Extractors: // How to Generate Strong Keys from Biometrics and Other Noisy Data) // by Yevgeniy Dodis, Rafail Ostrovsky, Leonid Reyzin and Adam Smith // or Theorem 18.7 of Victor Shoup's "A Computational Introduction to // Number Theory and Algebra" (first edition, 2005), or // pp. 170-173 of "Introduction to Coding Theory" by Jurgen Bierbrauer. // // // RUNNING TIME: // If the output has e elements (i.e., the length of the output vector // is e; note that e <= (d-1)/2), then // the running time is O(d^2 + e^2 + e^{\log_2 3} m) operations in GF(2^m), // each of which takes time O(m^{\log_2 3}) in NTL. Note that // \log_2 3 is approximately 1.585. // bool BCHSyndromeDecode(vec_GF2E &answer, const vec_GF2E & ssWithoutEvens, long d) { long i; vec_GF2E ss; // This takes O(d) operation in GF(2^m) InterpolateEvens(ss, ssWithoutEvens); GF2EX r1, r2, r3, v1, v2, v3, q, temp; GF2EX *Rold, *Rcur, *Rnew, *Vold, *Vcur, *Vnew, *tempPointer; // Use pointers to avoid moving polynomials around // An assignment of polynomials requires copying the coefficient vector; // we will not assign polynomials, but will swap pointers instead Rold = &r1; Rcur = &r2; Rnew = &r3; Vold = &v1; Vcur = &v2; Vnew = &v3; SetCoeff(*Rold, d-1, 1); // Rold holds z^{d-1} // Rcur=S(z)/z where S is the syndrome poly, Rcur = \sum S_j z^{j-1} // Note that because we index arrays from 0, S_j is stored in ss[j-1] for (i=0; i<d-1; i++) SetCoeff (*Rcur, i, ss[i]); // Vold is already 0 -- no need to initialize // Initialize Vcur to 1 SetCoeff(*Vcur, 0, 1); // Vcur = 1 // Now run Euclid, but stop as soon as degree of Rcur drops below // (d-1)/2 // This will take O(d^2) operations in GF(2^m) long t = (d-1)/2; while (deg(*Rcur) >= t) { // Rold = Rcur*q + Rnew DivRem(q, *Rnew, *Rold, *Rcur); // Vnew = Vold - qVcur) mul(temp, q, *Vcur); sub (*Vnew, *Vold, temp); // swap everything tempPointer = Rold; Rold = Rcur; Rcur = Rnew; Rnew = tempPointer; tempPointer = Vold; Vold = Vcur; Vcur = Vnew; Vnew = tempPointer; } // At the end of the loop, sigma(z) is Vcur // (up to a constant factor, which doesn't matter, // since we care about roots of sigma). // The roots of sigma(z) are inverses of the points we // are interested in. // We will check that 0 is not // a root of Vcur (else its inverse won't exist, and hence // the right polynomial doesn't exist). if (IsZero(ConstTerm(*Vcur))) return false; // Need sigma to be monic for FindRoots MakeMonic(*Vcur); // check if sigma(z) has distinct roots if not, return false // this will take O(e^{\log_2 3} m) operations in GF(2^m), // where e is the degree of sigma(z) if (CheckIfDistinctRoots(*Vcur) == false) return false; // find roots of sigma(z) // this will take O(e^2 + e^{\log_2 3} m) operations in GF(2^m), // where e is the degree of sigma(z) answer = FindRoots(*Vcur); // take inverses of roots of sigma(z) for (i = 0; i < answer.length(); ++i) answer[i] = inv(answer[i]); // It is now necessary to verify if the resulting vector // has the correct syndrome: it is possible that it does // not even though the polynomial sigma(z) factors // completely // This takes O(de) operations in GF(2^m) vec_GF2E test; BCHSyndromeCompute (test, answer, d); return (test==ssWithoutEvens); }