// Use packed bootstrapping, so we can bootstrap all in just one go. void packedRecrypt(const CtPtrs& cPtrs, const std::vector<zzX>& unpackConsts, const EncryptedArray& ea) { FHEPubKey& pKey = (FHEPubKey&)cPtrs[0]->getPubKey(); // Allocate temporary ciphertexts for the recryption int nPacked = divc(cPtrs.size(), ea.getDegree()); // ceil(totoalNum/d) std::vector<Ctxt> cts(nPacked, Ctxt(pKey)); repack(CtPtrs_vectorCt(cts), cPtrs, ea); // pack ciphertexts // cout << "@"<< lsize(cts)<<std::flush; for (Ctxt& c: cts) { // then recrypt them c.reducePtxtSpace(2); // we only have recryption data for binary ctxt #ifdef DEBUG_PRINTOUT ZZX ptxt; decryptAndPrint((cout<<" before recryption "), c, *dbgKey, *dbgEa); dbgKey->Decrypt(ptxt, c); c.DummyEncrypt(ptxt); decryptAndPrint((cout<<" after recryption "), c, *dbgKey, *dbgEa); #else pKey.reCrypt(c); #endif } unpack(cPtrs, CtPtrs_vectorCt(cts), ea, unpackConsts); }
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); } }
// incrementalZeroTest sets each res[i], for i=0..n-1, to // a ciphertext in which each slot is 0 or 1 according // to whether or not bits 0..i of corresponding slot in ctxt // is zero (1 if not zero, 0 if zero). // It is assumed that res and each res[i] is already initialized // by the caller. // Complexity: O(d + n log d) smart automorphisms // O(n d) void incrementalZeroTest(Ctxt* res[], const EncryptedArray& ea, const Ctxt& ctxt, long n) { FHE_TIMER_START; long nslots = ea.size(); long d = ea.getDegree(); // compute linearized polynomial coefficients vector< vector<ZZX> > Coeff; Coeff.resize(n); for (long i = 0; i < n; i++) { // coeffients for mask on bits 0..i // L[j] = X^j for j = 0..i, L[j] = 0 for j = i+1..d-1 vector<ZZX> L; L.resize(d); for (long j = 0; j <= i; j++) SetCoeff(L[j], j); vector<ZZX> C; ea.buildLinPolyCoeffs(C, L); Coeff[i].resize(d); for (long j = 0; j < d; j++) { // Coeff[i][j] = to the encoding that has C[j] in all slots // FIXME: maybe encrtpted array should have this functionality // built in vector<ZZX> T; T.resize(nslots); for (long s = 0; s < nslots; s++) T[s] = C[j]; ea.encode(Coeff[i][j], T); } } vector<Ctxt> Conj(d, ctxt); // initialize Cong[j] to ctxt^{2^j} for (long j = 0; j < d; j++) { Conj[j].smartAutomorph(1L << j); } for (long i = 0; i < n; i++) { res[i]->clear(); for (long j = 0; j < d; j++) { Ctxt tmp = Conj[j]; tmp.multByConstant(Coeff[i][j]); *res[i] += tmp; } // *res[i] now has 0..i in each slot // next, we raise to the power 2^d-1 fastPower(*res[i], d); } FHE_TIMER_STOP; }
// Apply the same linear transformation to all the slots. // C is the output of ea.buildLinPolyCoeffs void applyLinPoly1(const EncryptedArray& ea, Ctxt& ctxt, const vector<ZZX>& C) { assert(&ea.getContext() == &ctxt.getContext()); long d = ea.getDegree(); assert(d == lsize(C)); long nslots = ea.size(); vector<ZZX> encodedC(d); for (long j = 0; j < d; j++) { vector<ZZX> v(nslots); for (long i = 0; i < nslots; i++) v[i] = C[j]; ea.encode(encodedC[j], v); } applyLinPolyLL(ctxt, encodedC, ea.getDegree()); }
/** * @brief Extract coefficients from ciphertext polynomial * @param coeffs extracted coefficients * @param ctxt ciphertext * @param n extract "n" lowest degree coefficients */ void extractCoeffs(EncryptedArray& ea, vector<Ctxt>& coeffs, Ctxt& ctxt, long n) { long d = ea.getDegree(); if (d < n) n = d; coeffs.clear(); vector<Ctxt> conj; for (int coeff = 0; coeff < n; ++coeff) { vector<ZZX> LM(d); LM[coeff] = ZZX(0, 1); // "building" the linearized-polynomial coefficients vector<ZZX> C(d); ea.buildLinPolyCoeffs(C, LM); coeffs.push_back(ctxt); applyLinPoly1(ea, coeffs[coeff], C, conj); } }