void BluesteinFFT(zz_pX& x, long n, const zz_p& root, const zz_pX& powers, const Vec<mulmod_precon_t>& powers_aux, const fftRep& Rb) { // FHE_TIMER_START; if (IsZero(x)) return; if (n<=0) { clear(x); return; } long p = zz_p::modulus(); long dx = deg(x); for (long i=0; i<=dx; i++) { x[i].LoopHole() = MulModPrecon(rep(x[i]), rep(powers[i]), p, powers_aux[i]); } x.normalize(); long k = NextPowerOfTwo(2*n-1); fftRep& Ra = Cmodulus::getScratch_fftRep(k); TofftRep(Ra, x, k); mul(Ra,Ra,Rb); // multiply in FFT representation FromfftRep(x, Ra, n-1, 2*(n-1)); // then convert back dx = deg(x); for (long i=0; i<=dx; i++) { x[i].LoopHole() = MulModPrecon(rep(x[i]), rep(powers[i]), p, powers_aux[i]); } x.normalize(); }
static void LocalCyclicReduce(zz_pX& x, const zz_pX& a, long m) // computes x = a mod X^m-1 { long n = deg(a); long i, j; zz_p accum; if (n < m) { x = a; return; } if (&x != &a) x.rep.SetLength(m); for (i = 0; i < m; i++) { accum = a.rep[i]; for (j = i + m; j <= n; j += m) add(accum, accum, a.rep[j]); x.rep[i] = accum; } if (&x == &a) x.rep.SetLength(m); x.normalize(); }
static void LocalCopyReverse(zz_pX& x, const zz_pX& a, long lo, long hi) // x[0..hi-lo] = reverse(a[lo..hi]), with zero fill // input may not alias output { long i, j, n, m; n = hi-lo+1; m = a.rep.length(); x.rep.SetLength(n); const zz_p* ap = a.rep.elts(); zz_p* xp = x.rep.elts(); for (i = 0; i < n; i++) { j = hi-i; if (j < 0 || j >= m) clear(xp[i]); else xp[i] = ap[j]; } x.normalize(); }
void RightShift(zz_pX& x, const zz_pX& a, long n) { if (IsZero(a)) { clear(x); return; } if (n < 0) { if (n < -NTL_MAX_LONG) Error("overflow in RightShift"); LeftShift(x, a, -n); return; } long da = deg(a); long i; if (da < n) { clear(x); return; } if (&x != &a) x.rep.SetLength(da-n+1); for (i = 0; i <= da-n; i++) x.rep[i] = a.rep[i+n]; if (&x == &a) x.rep.SetLength(da-n+1); x.normalize(); }
void InnerProduct(zz_pX& x, const vec_zz_p& v, long low, long high, const vec_zz_pX& H, long n, vec_zz_p& t) { zz_p s; long i, j; zz_p *tp = t.elts(); for (j = 0; j < n; j++) clear(tp[j]); long p = zz_p::modulus(); double pinv = zz_p::ModulusInverse(); high = min(high, v.length()-1); for (i = low; i <= high; i++) { const vec_zz_p& h = H[i-low].rep; long m = h.length(); zz_p w = (v[i]); long W = rep(w); mulmod_precon_t Wpinv = PrepMulModPrecon(W, p, pinv); // ((double) W)*pinv; const zz_p *hp = h.elts(); for (j = 0; j < m; j++) { long S = MulModPrecon(rep(hp[j]), W, p, Wpinv); S = AddMod(S, rep(tp[j]), p); tp[j].LoopHole() = S; } } x.rep = t; x.normalize(); }
void recursiveEval(const CubeSlice<zz_p>& s, const Vec< copied_ptr<FFTHelper> >& multiEvalPoints, long d, zz_pX& tmp1, Vec<zz_p>& tmp2) { long numDims = s.getNumDims(); //OLD: assert(numDims > 0); helib::assertTrue(numDims > 0, "CubeSlice s has negative dimension number"); if (numDims > 1) { long dim0 = s.getDim(0); for (long i = 0; i < dim0; i++) recursiveEval(CubeSlice<zz_p>(s, i), multiEvalPoints, d+1, tmp1, tmp2); } long posBnd = s.getProd(1); for (long pos = 0; pos < posBnd; pos++) { getHyperColumn(tmp1.rep, s, pos); tmp1.normalize(); multiEvalPoints[d]->FFT(tmp1, tmp2); setHyperColumn(tmp2, s, pos); } }
void diff(zz_pX& x, const zz_pX& a) { long n = deg(a); long i; if (n <= 0) { clear(x); return; } if (&x != &a) x.rep.SetLength(n); for (i = 0; i <= n-1; i++) { mul(x.rep[i], a.rep[i+1], i+1); } if (&x == &a) x.rep.SetLength(n); x.normalize(); }
void ShiftSub(zz_pX& U, const zz_pX& V, long n) // assumes input does not alias output { if (IsZero(V)) return; long du = deg(U); long dv = deg(V); long d = max(du, n+dv); U.rep.SetLength(d+1); long i; for (i = du+1; i <= d; i++) clear(U.rep[i]); for (i = 0; i <= dv; i++) sub(U.rep[i+n], U.rep[i+n], V.rep[i]); U.normalize(); }
// This routine recursively reduces each hypercolumn // in dimension d (viewed as a coeff vector) by Phi_{m_d}(X) // If one starts with a cube of dimension (m_1, ..., m_k), // one ends up with a cube that is effectively of dimension // phi(m_1, ..., m_k). Viewed as an element of the ring // F_p[X_1,...,X_k]/(Phi_{m_1}(X_1), ..., Phi_{m_k}(X_k)), // the cube remains unchanged. static void recursiveReduce(const CubeSlice<zz_p>& s, const Vec<zz_pXModulus>& cycVec, long d, zz_pX& tmp1, zz_pX& tmp2) { long numDims = s.getNumDims(); //OLD: assert(numDims > 0); helib::assertTrue(numDims > 0l, "CubeSlice s has negative number of dimensions"); long deg0 = deg(cycVec[d]); long posBnd = s.getProd(1); for (long pos = 0; pos < posBnd; pos++) { getHyperColumn(tmp1.rep, s, pos); tmp1.normalize(); // tmp2 may not be normalized, so clear it first clear(tmp2); rem(tmp2, tmp1, cycVec[d]); // now pad tmp2.rep with zeros to length deg0... // tmp2 may not be normalized long len = tmp2.rep.length(); tmp2.rep.SetLength(deg0); for (long i = len; i < deg0; i++) tmp2.rep[i] = 0; setHyperColumn(tmp2.rep, s, pos); } if (numDims == 1) return; for (long i = 0; i < deg0; i++) recursiveReduce(CubeSlice<zz_p>(s, i), cycVec, d+1, tmp1, tmp2); }
void recursiveEval(const CubeSlice<zz_p>& s, const Vec< Vec<zz_p> >& multiEvalPoints, long d, zz_pX& tmp1, Vec<zz_p>& tmp2) { long numDims = s.getNumDims(); assert(numDims > 0); if (numDims > 1) { long dim0 = s.getDim(0); for (long i = 0; i < dim0; i++) recursiveEval(CubeSlice<zz_p>(s, i), multiEvalPoints, d+1, tmp1, tmp2); } long posBnd = s.getProd(1); for (long pos = 0; pos < posBnd; pos++) { getHyperColumn(tmp1.rep, s, pos); tmp1.normalize(); eval(tmp2, tmp1, multiEvalPoints[d]); setHyperColumn(tmp2, s, pos); } }
void Cmodulus::iFFT(zz_pX &x, const vec_long& y)const { FHE_TIMER_START; zz_pBak bak; bak.save(); context.restore(); if (zMStar->getPow2()) { // special case when m is a power of 2 long k = zMStar->getPow2(); long phim = (1L << (k-1)); long p = zz_p::modulus(); const zz_p *ipowers_p = (*ipowers).rep.elts(); const mulmod_precon_t *ipowers_aux_p = ipowers_aux.elts(); const long *yp = y.elts(); vec_long& tmp = Cmodulus::getScratch_vec_long(); tmp.SetLength(phim); long *tmp_p = tmp.elts(); #ifdef FHE_OPENCL AltFFTRev1(tmp_p, yp, k-1, *altFFTInfo); #else FFTRev1(tmp_p, yp, k-1, *zz_pInfo->p_info); #endif x.rep.SetLength(phim); zz_p *xp = x.rep.elts(); for (long i = 0; i < phim; i++) xp[i].LoopHole() = MulModPrecon(tmp_p[i], rep(ipowers_p[i]), p, ipowers_aux_p[i]); x.normalize(); return; } zz_p rt; long m = getM(); // convert input to zpx format, initializing only the coeffs i s.t. (i,m)=1 x.rep.SetLength(m); long i,j; for (i=j=0; i<m; i++) if (zMStar->inZmStar(i)) x.rep[i].LoopHole() = y[j++]; // DIRT: y[j] already reduced x.normalize(); conv(rt, rInv); // convert rInv to zp format BluesteinFFT(x, m, rt, *ipowers, ipowers_aux, *iRb); // call the FFT routine // reduce the result mod (Phi_m(X),q) and copy to the output polynomial x { FHE_NTIMER_START(iFFT_division); rem(x, x, *phimx); // out %= (Phi_m(X),q) } // normalize zz_p mm_inv; conv(mm_inv, m_inv); x *= mm_inv; }