NTL_CLIENT #include "FHE.h" #include "timing.h" #include "EncryptedArray.h" #include <cstdio> // Map all non-zero slots to 1, leaving zero slots as zero. // Assumes that r=1, and that all the slot contain elements from GF(p^d). // // We compute x^{p^d-1} = x^{(1+p+...+p^{d-1})*(p-1)} by setting y=x^{p-1} // and then outputting y * y^p * ... * y^{p^{d-1}}, with exponentiation to // powers of p done via Frobenius. // FIXME: the computation of the "norm" y * y^p * ... * y^{p^{d-1}} // can be done using O(log d) automorphisms, rather than O(d). void mapTo01(const EncryptedArray& ea, Ctxt& ctxt) { long p = ctxt.getPtxtSpace(); if (p != ea.getPAlgebra().getP()) // ptxt space is p^r for r>1 throw helib::LogicError("mapTo01 not implemented for r>1"); if (p>2) ctxt.power(p-1); // set y = x^{p-1} long d = ea.getDegree(); if (d>1) { // compute the product of the d automorphisms std::vector<Ctxt> v(d, ctxt); for (long i=1; i<d; i++) v[i].frobeniusAutomorph(i); totalProduct(ctxt, v); } }
// Apply a permutation network to a ciphertext void PermNetwork::applyToCtxt(Ctxt& c, const EncryptedArray& ea) const { const PAlgebra& al = ea.getPAlgebra(); // Apply the layers, one at a time for (long i=0; i<layers.length(); i++) { const PermNetLayer& lyr = layers[i]; if (lyr.isID) continue; // this layer is the identity permutation // This layer is shifted via powers of g^e mod m long g2e = PowerMod(al.ZmStarGen(lyr.genIdx), lyr.e, al.getM()); Vec<long> unused = lyr.shifts; // copy to a new vector vector<long> mask(lyr.shifts.length()); // buffer to hold masks Ctxt sum(c.getPubKey(), c.getPtxtSpace()); // an empty ciphertext long shamt = 0; bool frst = true; while (true) { pair<long,bool> ret=makeMask(mask, unused, shamt); // compute mask if (ret.second) { // non-empty mask Ctxt tmp = c; ZZX maskPoly; ea.encode(maskPoly, mask); // encode mask as polynomial tmp.multByConstant(maskPoly); // multiply by mask if (shamt!=0) // rotate if the shift amount is nonzero tmp.smartAutomorph(PowerMod(g2e, shamt, al.getM())); if (frst) { sum = tmp; frst = false; } else sum += tmp; } if (ret.first >= 0) shamt = unused[ret.first]; // next shift amount to use else break; // unused is all-zero, done with this layer } c = sum; // update the cipehrtext c before the next layer } }