static void recursiveInterpolateMod(ZZX& poly, const vec_long& x, vec_long& y, const vec_zz_p& xmod, vec_zz_p& ymod, long p, long p2e) { if (p2e<=1) { // recursion edge condition, mod-1 poly = 0 clear(poly); return; } // convert y input to zz_p for (long j=0; j<y.length(); j++) ymod[j] = to_zz_p(y[j] % p); // a polynomial p_i s.t. p_i(x[j]) = i'th p-base digit of poly(x[j]) zz_pX polyMod; interpolate(polyMod, xmod, ymod); // interpolation modulo p ZZX polyTmp; conv(polyTmp, polyMod); // convert to ZZX // update ytmp by subtracting the new digit, then dividing by p for (long j=0; j<y.length(); j++) { y[j] -= polyEvalMod(polyTmp,x[j],p2e); // mod p^e if (y[j]<0) y[j] += p2e; // if (y[j] % p != 0) { // cerr << "@@error (p2^e="<<p2e<<"): y["<<j<<"] not divisible by "<<p<< endl; // exit(0); // } y[j] /= p; } // maybe it's worth optimizing above by using multi-point evaluation // recursive call to get the solution of poly'(x)=y mod p^{e-1} recursiveInterpolateMod(poly, x, y, xmod, ymod, p, p2e/p); // return poly = p*poly' + polyTmp poly *= p; poly += polyTmp; }
NTL_CLIENT #include <algorithm> // defines count(...), min(...) #include <iostream> #include "NumbTh.h" #include "PAlgebra.h" // Generate the representation of Z[X]/(Phi_m(X),2) for the odd integer m void PAlgebraModTwo::init(unsigned m) { if (m == zmStar.M()) return; // nothign to do ((PAlgebra&)zmStar).init(m); // initialize the structure of (Z/mZ)*, if needed if (zmStar.M()==0 || zmStar.NSlots()==0) return; // error in zmStar unsigned nSlots = zmStar.NSlots(); // Next compute the factors Ft of Phi_m(X) mod 2, for all t \in T // GF2X PhimXmod = to_GF2X(zmStar.PhimX()); // Phi_m(X) mod 2 PhimXmod = to_GF2X(zmStar.PhimX()); // Phi_m(X) mod 2 EDF(factors, PhimXmod, zmStar.OrdTwo()); // equal-degree factorization // It is left to order the factors according to their representatives GF2XModulus F1(factors[0]); // We arbitrarily choose factors[0] as F1 for (unsigned i=1; i<nSlots; i++) { unsigned t = zmStar.ith_rep(i); // Ft is minimal polynomial of x^{1/t} mod F1 unsigned tInv = rep(inv(to_zz_p(t))); // tInv = t^{-1} mod m GF2X X2tInv = PowerXMod(tInv,F1); // X2tInv = X^{1/t} mod F1 IrredPolyMod(factors[i], X2tInv, F1); } /* Debugging sanity-check #1: we should have Ft= GCD(F1(X^t),Phi_m(X)) GF2XModulus Pm2(PhimXmod); for (i=1; i<nSlots; i++) { unsigned t = T[i]; GF2X X2t = PowerXMod(t,PhimXmod); // X2t = X^t mod Phi_m(X) GF2X Ft = GCD(CompMod(F1,X2t,Pm2),Pm2); if (Ft != factors[i]) { cout << "Ft != F1(X^t) mod Phi_m(X), t=" << t << endl; exit(0); } }*******************************************************************/ // Compute the CRT coefficients for the Ft's crtCoeffs.SetLength(nSlots); for (unsigned i=0; i<nSlots; i++) { GF2X te = PhimXmod / factors[i]; // \prod_{j\ne i} Fj te %= factors[i]; // \prod_{j\ne i} Fj mod Fi InvMod(crtCoeffs[i], te, factors[i]);// \prod_{j\ne i} Fj^{-1} mod Fi } }
// Interpolate the integer polynomial such that poly(x[i] mod p)=y[i] (mod p^e) // It is assumed that the points x[i] are all distinct modulo p void interpolateMod(ZZX& poly, const vec_long& x, const vec_long& y, long p, long e) { poly = ZZX::zero(); // initialize to zero long p2e = power_long(p,e); // p^e vec_long ytmp(INIT_SIZE, y.length()); // A temporary writable copy for (long j=0; j<y.length(); j++) { ytmp[j] = y[j] % p2e; if (ytmp[j] < 0) ytmp[j] += p2e; } zz_pBak bak; bak.save(); // Set the current modulus to p zz_p::init(p); vec_zz_p xmod(INIT_SIZE, x.length()); // convert to zz_p for (long j=0; j<x.length(); j++) xmod[j] = to_zz_p(x[j] % p); vec_zz_p ymod(INIT_SIZE, y.length()); // scratch space recursiveInterpolateMod(poly, x, ytmp, xmod, ymod, p, p2e); }