void decryptAndPrint(ostream& s, const Ctxt& ctxt, const FHESecKey& sk, const EncryptedArray& ea, long flags) { const FHEcontext& context = ctxt.getContext(); xdouble noiseEst = sqrt(ctxt.getNoiseVar()); xdouble modulus = xexp(context.logOfProduct(ctxt.getPrimeSet())); vector<ZZX> ptxt; ZZX p, pp; sk.Decrypt(p, ctxt, pp); s << "plaintext space mod "<<ctxt.getPtxtSpace() << ", level="<<ctxt.findBaseLevel() << ", \n |noise|=q*" << (coeffsL2Norm(pp)/modulus) << ", |noiseEst|=q*" << (noiseEst/modulus) <<endl; if (flags & FLAG_PRINT_ZZX) { s << " before mod-p reduction="; printZZX(s,pp) <<endl; } if (flags & FLAG_PRINT_POLY) { s << " after mod-p reduction="; printZZX(s,p) <<endl; } if (flags & FLAG_PRINT_VEC) { ea.decode(ptxt, p); if (ea.getAlMod().getTag() == PA_zz_p_tag && ctxt.getPtxtSpace() != ea.getAlMod().getPPowR()) { long g = GCD(ctxt.getPtxtSpace(), ea.getAlMod().getPPowR()); for (long i=0; i<ea.size(); i++) PolyRed(ptxt[i], g, true); } s << " decoded to "; if (deg(p) < 40) // just pring the whole thing s << ptxt << endl; else if (ptxt.size()==1) // a single slot printZZX(s, ptxt[0]) <<endl; else { // print first and last slots printZZX(s, ptxt[0],20) << "--"; printZZX(s, ptxt[ptxt.size()-1], 20) <<endl; } } }
void checkCiphertext(const Ctxt& ctxt, const ZZX& ptxt, const FHESecKey& sk) { const FHEcontext& context = ctxt.getContext(); /* IndexSet base = baseSetOf(ctxt); double addedNoise = log(ctxt.modSwitchAddedNoiseVar()); Ctxt tmp = ctxt; tmp.modDownToSet(base); double totalNoise = log(tmp.getNoiseVar()); cout << " @@@ log(added-noise)="<<addedNoise << ", log(total-noise)="<<totalNoise<<endl; */ cout << " ln(q)="<< context.logOfProduct(ctxt.getPrimeSet()) << ", ln(nVar)/2="<< log(ctxt.getNoiseVar())/2; // << ", ln(nMag)="<< log(ctxt.getNoiseMag()); ZZX res; // sk.Decrypt(res, ctxt); ZZX f; sk.Decrypt(res, ctxt, f); cout << ", ln(mxPtxtCoef)=" << log(largestCoeff(f)); // ensure we reduce the same way on both PolyRed((ZZX&)res,res,ctxt.getPtxtSpace(),true); PolyRed((ZZX&)ptxt,ptxt,ctxt.getPtxtSpace(),true); if (res != ptxt) { cout << ", failed\n"; for (long i=0; i<=deg(ptxt); i++) if (coeff(res,i)!=coeff(ptxt,i)) { cout << "first mismatch in coeff "<<i<<": " << coeff(res,i)<<"!="<<coeff(ptxt,i)<<"\n"; break; } cout << "Timing information:\n"; printAllTimers(); cout << "\n"; exit(0); } else cout << ", succeeded\n"; }
void adjustLevelForMult(Ctxt& c1, const char name1[], const ZZX& p1, Ctxt& c2, const char name2[], const ZZX& p2, const FHESecKey& sk) { const FHEcontext& context = c1.getContext(); // The highest possible level for this multiplication is the // intersection of the two primeSets, without the special primes. IndexSet primes = c1.getPrimeSet() & c2.getPrimeSet(); primes.remove(context.specialPrimes); assert (!empty(primes)); // double phim = (double) context.zMstar.phiM(); // double factor = c_m*sqrt(log(phim))*4; xdouble n1,n2,d1,d2; xdouble dvar1 = c1.modSwitchAddedNoiseVar(); xdouble dvar2 = c2.modSwitchAddedNoiseVar(); // xdouble dmag1 = c1.modSwitchAddedNoiseMag(c_m); // xdouble dmag2 = c2.modSwitchAddedNoiseMag(c_m); // cout << " ** log(dvar1)=" << log(dvar1) // << ", log(dvar2)=" << log(dvar2) <<endl; double logF1, logF2; xdouble n1var, n2var, modSize; // n1mag, n2mag, // init to large number xdouble noiseVarRatio=xexp(2*(context.logOfProduct(context.ctxtPrimes) + context.logOfProduct(context.specialPrimes))); // xdouble noiseMagRatio=noiseVarRatio; // Find the level that minimizes the noise-to-modulus ratio bool oneLevelMore = false; for (IndexSet levelDown = primes; !empty(levelDown); levelDown.remove(levelDown.last())) { // compute noise variane/magnitude after mod-switchign to this level logF1 = context.logOfProduct(c1.getPrimeSet() / levelDown); n1var = c1.getNoiseVar()/xexp(2*logF1); logF2 = context.logOfProduct(c2.getPrimeSet() / levelDown); n2var = c2.getNoiseVar()/xexp(2*logF2); // compute modulus/noise ratio at this level modSize = xexp(context.logOfProduct(levelDown)); xdouble nextNoiseVarRatio = sqrt((n1var+dvar1)*(n2var+dvar2))/modSize; if (nextNoiseVarRatio < 2*noiseVarRatio || oneLevelMore) { noiseVarRatio = nextNoiseVarRatio; primes = levelDown; // record the currently best prime set n1 = n1var; d1=dvar1; n2 = n2var; d2=dvar2; } oneLevelMore = (n1var > dvar1 || n2var > dvar2); } if (primes < c1.getPrimeSet()) { cout << " ** " << c1.getPrimeSet()<<"=>"<<primes << endl; cout << " n1var="<<n1<<", d1var="<<d1<<endl;; c1.modDownToSet(primes); cout << name1 << ".mDown:"; checkCiphertext(c1, p1, sk); } if (primes < c2.getPrimeSet()) { cout << " ** " << c2.getPrimeSet()<<"=>"<<primes << endl; cout << " n2var="<<n2<<", d2var="<<d2<<endl;; c2.modDownToSet(primes); cout << name2 << ".mDown:"; checkCiphertext(c2, p2, sk); } }