void ComputeTraceVec(const zz_pXModulus& F) { vec_zz_p& S = *((vec_zz_p *) &F.tracevec); if (S.length() > 0) return; if (!F.UseFFT) { PlainTraceVec(S, F.f); return; } long i; long n = F.n; fftRep R; zz_pX P, g; g.rep.SetLength(n-1); for (i = 1; i < n; i++) mul(g.rep[n-i-1], F.f.rep[n-i], i); g.normalize(); TofftRep(R, g, F.l); mul(R, R, F.HRep); FromfftRep(P, R, n-2, 2*n-4); S.SetLength(n); S[0] = n; for (i = 1; i < n; i++) negate(S[i], coeff(P, n-1-i)); }
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(); }
void mul(zz_pXMatrix& A, zz_pXMatrix& B, zz_pXMatrix& C) // A = B*C, B and C are destroyed { long db = deg(B(1,1)); long dc = deg(C(1,1)); long da = db + dc; long k = NextPowerOfTwo(da+1); fftRep B00, B01, B10, B11, C0, C1, T1, T2; TofftRep(B00, B(0,0), k); B(0,0).kill(); TofftRep(B01, B(0,1), k); B(0,1).kill(); TofftRep(B10, B(1,0), k); B(1,0).kill(); TofftRep(B11, B(1,1), k); B(1,1).kill(); TofftRep(C0, C(0,0), k); C(0,0).kill(); TofftRep(C1, C(1,0), k); C(1,0).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromfftRep(A(0,0), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromfftRep(A(1,0), T1, 0, da); TofftRep(C0, C(0,1), k); C(0,1).kill(); TofftRep(C1, C(1,1), k); C(1,1).kill(); mul(T1, B00, C0); mul(T2, B01, C1); add(T1, T1, T2); FromfftRep(A(0,1), T1, 0, da); mul(T1, B10, C0); mul(T2, B11, C1); add(T1, T1, T2); FromfftRep(A(1,1), T1, 0, da); }
void rem(zz_pX& r, const zz_pX& a, const zz_pXModulus1& ff) { if (!ff.specialLogic) { rem(r, a, ff.fm); return; } long m = ff.m; long n = ff.n; long k = ff.k; long k1 = ff.k1; const fftRep& R0 = ff.R0; const fftRep& R1 = ff.R1; if (deg(a) < n) { r = a; return; } zz_pX P2, P3; fftRep R2, R3; TofftRep(R2, a, k, n, m-1); mul(R2, R2, R0); FromfftRep(P3, R2, m-1-n, 2*(m-1-n)); long l = 1L << k1; TofftRep(R3, P3, k1); mul(R3, R3, R1); FromfftRep(P3, R3, 0, n-1); LocalCyclicReduce(P2, a, l); trunc(P2, P2, n); sub(P2, P2, P3); r = P2; }
void FFTSqrTrunc(zz_pX& x, const zz_pX& a, long n) { if (IsZero(a)) { clear(x); return; } long d = 2*deg(a); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); fftRep R1(INIT_SIZE, k); TofftRep(R1, a, k); mul(R1, R1, R1); FromfftRep(x, R1, 0, n-1); }
void FFTMulTrunc(zz_pX& x, const zz_pX& a, const zz_pX& b, long n) { if (IsZero(a) || IsZero(b)) { clear(x); return; } long d = deg(a) + deg(b); if (n > d + 1) n = d + 1; long k = NextPowerOfTwo(d + 1); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep(R1, a, k); TofftRep(R2, b, k); mul(R1, R1, R2); FromfftRep(x, R1, 0, n-1); }
void BuildFromRoots(zz_pX& x, const vec_zz_p& a) { long n = a.length(); if (n == 0) { set(x); return; } long k0 = NextPowerOfTwo(NTL_zz_pX_MUL_CROSSOVER)-1; long crossover = 1L << k0; if (n <= NTL_zz_pX_MUL_CROSSOVER) { x.rep.SetMaxLength(n+1); x.rep = a; IterBuild(&x.rep[0], n); x.rep.SetLength(n+1); SetCoeff(x, n); return; } long k = NextPowerOfTwo(n); long m = 1L << k; long i, j; long l, width; zz_pX b(INIT_SIZE, m+1); b.rep = a; b.rep.SetLength(m+1); for (i = n; i < m; i++) clear(b.rep[i]); set(b.rep[m]); fftRep R1(INIT_SIZE, k), R2(INIT_SIZE, k); zz_p t1, one; set(one); vec_zz_p G(INIT_SIZE, crossover), H(INIT_SIZE, crossover); zz_p *g = G.elts(); zz_p *h = H.elts(); zz_p *tmp; for (i = 0; i < m; i+= crossover) { for (j = 0; j < crossover; j++) negate(g[j], b.rep[i+j]); if (k0 > 0) { for (j = 0; j < crossover; j+=2) { mul(t1, g[j], g[j+1]); add(g[j+1], g[j], g[j+1]); g[j] = t1; } } for (l = 1; l < k0; l++) { width = 1L << l; for (j = 0; j < crossover; j += 2*width) mul(&h[j], &g[j], &g[j+width], width); tmp = g; g = h; h = tmp; } for (j = 0; j < crossover; j++) b.rep[i+j] = g[j]; } for (l = k0; l < k; l++) { width = 1L << l; for (i = 0; i < m; i += 2*width) { t1 = b.rep[i+width]; set(b.rep[i+width]); TofftRep(R1, b, l+1, i, i+width); b.rep[i+width] = t1; t1 = b.rep[i+2*width]; set(b.rep[i+2*width]); TofftRep(R2, b, l+1, i+width, i+2*width); b.rep[i+2*width] = t1; mul(R1, R1, R2); FromfftRep(&b.rep[i], R1, 0, 2*width-1); sub(b.rep[i], b.rep[i], one); } } x.rep.SetLength(n+1); long delta = m-n; for (i = 0; i <= n; i++) x.rep[i] = b.rep[i+delta]; // no need to normalize }
void mul(zz_pX& U, zz_pX& V, const zz_pXMatrix& M) // (U, V)^T = M*(U, V)^T { long d = deg(U) - deg(M(1,1)); long k = NextPowerOfTwo(d - 1); // When the GCD algorithm is run on polynomials of degree n, n-1, // where n is a power of two, then d-1 is likely to be a power of two. // It would be more natural to set k = NextPowerOfTwo(d+1), but this // would be much less efficient in this case. long n = (1L << k); long xx; zz_p a0, a1, b0, b1, c0, d0, u0, u1, v0, v1, nu0, nu1, nv0; zz_p t1, t2; if (n == d-1) xx = 1; else if (n == d) xx = 2; else xx = 3; switch (xx) { case 1: GetCoeff(a0, M(0,0), 0); GetCoeff(a1, M(0,0), 1); GetCoeff(b0, M(0,1), 0); GetCoeff(b1, M(0,1), 1); GetCoeff(c0, M(1,0), 0); GetCoeff(d0, M(1,1), 0); GetCoeff(u0, U, 0); GetCoeff(u1, U, 1); GetCoeff(v0, V, 0); GetCoeff(v1, V, 1); mul(t1, (a0), (u0)); mul(t2, (b0), (v0)); add(t1, t1, t2); nu0 = t1; mul(t1, (a1), (u0)); mul(t2, (a0), (u1)); add(t1, t1, t2); mul(t2, (b1), (v0)); add(t1, t1, t2); mul(t2, (b0), (v1)); add(t1, t1, t2); nu1 = t1; mul(t1, (c0), (u0)); mul(t2, (d0), (v0)); add (t1, t1, t2); nv0 = t1; break; case 2: GetCoeff(a0, M(0,0), 0); GetCoeff(b0, M(0,1), 0); GetCoeff(u0, U, 0); GetCoeff(v0, V, 0); mul(t1, (a0), (u0)); mul(t2, (b0), (v0)); add(t1, t1, t2); nu0 = t1; break; case 3: break; } fftRep RU(INIT_SIZE, k), RV(INIT_SIZE, k), R1(INIT_SIZE, k), R2(INIT_SIZE, k); TofftRep(RU, U, k); TofftRep(RV, V, k); TofftRep(R1, M(0,0), k); mul(R1, R1, RU); TofftRep(R2, M(0,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromfftRep(U, R1, 0, d); TofftRep(R1, M(1,0), k); mul(R1, R1, RU); TofftRep(R2, M(1,1), k); mul(R2, R2, RV); add(R1, R1, R2); FromfftRep(V, R1, 0, d-1); // now fix-up results switch (xx) { case 1: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d-1, u0); SetCoeff(U, 0, nu0); GetCoeff(u1, U, 1); sub(u1, u1, nu1); SetCoeff(U, d, u1); SetCoeff(U, 1, nu1); GetCoeff(v0, V, 0); sub(v0, v0, nv0); SetCoeff(V, d-1, v0); SetCoeff(V, 0, nv0); break; case 2: GetCoeff(u0, U, 0); sub(u0, u0, nu0); SetCoeff(U, d, u0); SetCoeff(U, 0, nu0); break; } }