void totalSums(const EncryptedArray& ea, Ctxt& ctxt) { long n = ea.size(); if (n == 1) return; Ctxt orig = ctxt; long k = NumBits(n); long e = 1; for (long i = k-2; i >= 0; i--) { Ctxt tmp1 = ctxt; ea.rotate(tmp1, e); ctxt += tmp1; // ctxt = ctxt + (ctxt >>> e) e = 2*e; if (bit(n, i)) { Ctxt tmp2 = orig; ea.rotate(tmp2, e); ctxt += tmp2; // ctxt = ctxt + (orig >>> e) // NOTE: we could have also computed // ctxt = (ctxt >>> e) + orig, however, // this would give us greater depth/noise e += 1; } } }
void replicateAllOrig(const EncryptedArray& ea, const Ctxt& ctxt, ReplicateHandler *handler, RepAux* repAuxPtr) { long nSlots = ea.size(); long n = GreatestPowerOfTwo(nSlots); // 2^n <= nSlots Ctxt ctxt1 = ctxt; if ((1L << n) < nSlots) SelectRange(ea, ctxt1, 0, 1L << n); RepAux repAux; if (repAuxPtr==NULL) repAuxPtr = &repAux; recursiveReplicate(ea, ctxt1, n, n, 0, 1L << n, *repAuxPtr, handler); if ((1L << n) < nSlots) { ctxt1 = ctxt; SelectRange(ea, ctxt1, 1L << n, nSlots); ea.rotate(ctxt1, -(1L << n)); recursiveReplicate(ea, ctxt1, n, n, 1L << n, nSlots, *repAuxPtr, handler); } }
void benchmark(const EncryptedArray & ea, const FHEPubKey & pk, const FHESecKey & sk, const MDL::Matrix<long>& data) { const long BATCH_SIZE = 5000; MDL::Timer encTimer, evalTimer; MDL::EncVector mu(pk), sigma(pk); for (long part = 0; part *BATCH_SIZE < data.rows(); part++) { long from = std::min<long>(part * BATCH_SIZE, data.rows()); long to = std::min<long>(from + BATCH_SIZE, data.rows()); encTimer.start(); auto ctxts = encrypt(data, pk, ea, from, to); encTimer.end(); evalTimer.start(); auto sum = summation(ctxts); mu += sum.first; sigma += sum.second; evalTimer.end(); } evalTimer.start(); auto mu_mu = mu.covariance(ea, data.cols()); NTL::ZZX N; std::vector<long> n(ea.size(), data.rows()); ea.encode(N, n); sigma.multByConstant(N); for (size_t col = 0; col < data.cols(); col++) { ea.rotate(mu_mu[col], col * data.cols()); sigma -= mu_mu[col]; } evalTimer.end(); MDL::Vector<long> mat; sigma.unpack(mat, sk, ea, true); for (int i = 0; i < data.cols(); i++) { for (int j = 0; j < data.cols(); j++) { std::cout << mat[i * data.cols() + j] << " "; } std::cout << std::endl; } printf("Covariance of %zd data, enc %f, eval %f\n", data.rows(), encTimer.second(), evalTimer.second()); }
static void recursiveReplicate(const EncryptedArray& ea, const Ctxt& ctxt, long n, long k, long pos, long limit, RepAux& repAux, ReplicateHandler *handler) { if (pos >= limit) return; if (replicateVerboseFlag) { // DEBUG code cerr << "check: " << k; CheckCtxt(ctxt, ""); } long nSlots = ea.size(); if (k == 0) { if ( (1L << n) >= nSlots) { handler->handle(ctxt); return; } // need to replicate to fill positions [ (1L << n) .. nSlots ) if (repAux.tab(0).null()) { // need to generate mask ZZX mask; SelectRange(ea, mask, 0, nSlots - (1L << n)); repAux.tab(0).set_ptr(new DoubleCRT(mask, ea.getContext())); } Ctxt ctxt_tmp = ctxt; ctxt_tmp.multByConstant(*repAux.tab(0)); ea.rotate(ctxt_tmp, 1L << n); ctxt_tmp += ctxt; handler->handle(ctxt_tmp); return; } k--; Ctxt ctxt_masked = ctxt; { // artificial scope to miminize storage in // the recursion { // another artificial scope // mask should be at index k+1 if (repAux.tab(k+1).null()) { // need to generate mask vector< long > maskArray; maskArray.resize(nSlots); for (long i = 0; i < (1L << n); i++) maskArray[i] = 1- bit(i, k); // the reverse of bit k of i for (long i = (1L << n); i < nSlots; i++) maskArray[i] = 0; ZZX mask; ea.encode(mask, maskArray); repAux.tab(k+1).set_ptr(new DoubleCRT(mask, ea.getContext())); } ctxt_masked.multByConstant(*repAux.tab(k+1)); } Ctxt ctxt_left = ctxt_masked; ea.rotate(ctxt_left, 1L << k); ctxt_left += ctxt_masked; recursiveReplicate(ea, ctxt_left, n, k, pos, limit, repAux, handler); } pos += (1L << k); if (pos >= limit) return; Ctxt ctxt_right = ctxt; ctxt_right -= ctxt_masked; ctxt_masked = ctxt_right; // reuse ctxt_masked as a temp ea.rotate(ctxt_masked, -(1L << k)); ctxt_right += ctxt_masked; recursiveReplicate(ea, ctxt_right, n, k, pos, limit, repAux, handler); }