예제 #1
0
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);
  }
    
}
예제 #2
0
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;
    }
  }
}
예제 #3
0
파일: eqtesting.cpp 프로젝트: shaih/HElib
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);
  }
}
예제 #4
0
// 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;
}
예제 #5
0
// Return in poly a polynomial with X^i encoded in all the slots
static void x2iInSlots(ZZX& poly, long i,
		       vector<ZZX>& xVec, const EncryptedArray& ea)
{
  xVec.resize(ea.size());
  ZZX x2i = ZZX(i,1);
  for (long j=0; j<(long)xVec.size(); j++) xVec[j] = x2i;
  ea.encode(poly, xVec);
}
예제 #6
0
void replicate(const EncryptedArray& ea, Ctxt& ctxt, long pos)
{
  long nSlots = ea.size();
  assert(pos >= 0 && pos < nSlots); 

  ZZX mask;
  ea.encodeUnitSelector(mask, pos);
  ctxt.multByConstant(mask);
  replicate0(ea, ctxt, pos);
}
예제 #7
0
파일: FHLD.cpp 프로젝트: ruescasd/FHLD
Ctxt select(Ctxt ctxt, int value, EncryptedArray ea, const FHEPubKey& publicKey) {
  PlaintextArray mask(ea);
  mask.encode(getVote(value, ea.size()));

  Ctxt maskCtxt(publicKey);
  ea.encrypt(maskCtxt, publicKey, mask);

  Ctxt ret(ctxt);
  ret.multiplyBy(maskCtxt);

  return ret;
}
예제 #8
0
void runningSums(const EncryptedArray& ea, Ctxt& ctxt)
{
  long n = ea.size();

  long shamt = 1;
  while (shamt < n) {
    Ctxt tmp = ctxt;
    ea.shift(tmp, shamt);
    ctxt += tmp; // ctxt = ctxt + (ctxt >> shamt)
    shamt = 2*shamt;
  }
}
예제 #9
0
파일: Vector.cpp 프로젝트: fionser/MDLHELib
NTL::ZZX Vector<long>::encode(const EncryptedArray &ea) const
{
    assert(this->size() <= ea.size());
    NTL::ZZX encoded;
    if (this->size() < ea.size()) {
        auto tmp(*this);
        tmp.resize(ea.size());
        ea.encode(encoded, tmp);
    } else {
        ea.encode(encoded, *this);
    }
    return encoded;
}
예제 #10
0
// selects range of slots [lo..hi)
static
void SelectRange(const EncryptedArray& ea, ZZX& mask, long lo, long hi)
{
  long nSlots = ea.size();

  assert(lo >= 0 && lo <= hi && hi <= nSlots);

  vector<long> maskArray;
  maskArray.resize(nSlots);
  for (long i = 0; i < nSlots; i++) maskArray[i] = 0;
  for (long i = lo; i < hi; i++) maskArray[i] = 1;
  
  ea.encode(mask, maskArray);
}
예제 #11
0
// 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);
}
예제 #12
0
// Returns the result as a vector of ciphertexts
void replicateAll(std::vector<Ctxt>& v, const EncryptedArray& ea,
       	          const Ctxt& ctxt, long recBound, RepAuxDim* repAuxPtr)
{
  v.resize(ea.size(), ctxt);
  ExplicitReplicator handler(v);
  replicateAll(ea, ctxt, &handler, recBound, repAuxPtr);
}
예제 #13
0
// 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());
}
예제 #14
0
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());
}
예제 #15
0
void replicate0(const EncryptedArray& ea, Ctxt& ctxt, long pos)
{
  long dim = ea.dimension();

  for (long d = 0; d < dim; d++) {
    if (!ea.nativeDimension(d)) {
      long shamt = -ea.coordinate(d, pos);
      ea.rotate1D(ctxt, d, shamt, true); // "don't care"
    }

    Ctxt ctxt_orig = ctxt; 

    long sz = ea.sizeOfDimension(d);
    long k = NumBits(sz);
    long e = 1;

    // now process bits k-2 down to 0
    for (long j = k-2; j >= 0; j--) {
      // e -> 2*e
      Ctxt tmp = ctxt;
      ea.rotate1D(tmp, d, e, true); // "don't care"
      ctxt += tmp;
      e = 2*e;
      
      long b = bit(sz, j); // bit j of sz
      // e -> e+b
      if (b) {
        ea.rotate1D(ctxt, d, 1, true); // "don't care"
        ctxt += ctxt_orig;
        e++;
      }
    }
  }
}
예제 #16
0
/**
 * @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);
  }
}
예제 #17
0
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;      
    }
  }
}
예제 #18
0
파일: FHLD.cpp 프로젝트: ruescasd/FHLD
vector<PlaintextArray> decryptVotes(vector<Ctxt> votes, EncryptedArray ea, const FHESecKey secretKey) {
  vector<PlaintextArray> ret;
  for(int i = 0; i < votes.size(); i++) {
    PlaintextArray p(ea);
    ea.decrypt(votes[i], secretKey, p);
    ret.push_back(p);
  }

  return ret;
}
예제 #19
0
파일: FHLD.cpp 프로젝트: ruescasd/FHLD
vector<Ctxt> encryptVotes(vector<PlaintextArray> votes, EncryptedArray ea, const FHEPubKey& publicKey) {
  vector<Ctxt> ret;
  for(int i = 0; i < votes.size(); i++) {
    Ctxt c(publicKey);
    ea.encrypt(c, publicKey, votes[i]);
    ret.push_back(c);
  }

  return ret;
}
예제 #20
0
// 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
  }
}
예제 #21
0
// selects range of slots [lo..hi) in dimension d
static
void SelectRangeDim(const EncryptedArray& ea, ZZX& mask, long lo, long hi,
                    long d)
{
  long nSlots = ea.size();

  assert(d >= 0 && d < ea.dimension());
  assert(lo >= 0 && lo <= hi && hi <= ea.sizeOfDimension(d));

  vector<long> maskArray;
  maskArray.resize(nSlots);
  for (long i = 0; i < nSlots; i++) {
    long c = ea.coordinate(d, i);
    if (c >= lo && c < hi) 
      maskArray[i] = 1;
    else
      maskArray[i] = 0;
  }
  
  ea.encode(mask, maskArray);
}
예제 #22
0
static void replicateOneBlock(const EncryptedArray& ea, Ctxt& ctxt, 
			      long pos, long blockSize, long d)
{
  long dSize = ea.sizeOfDimension(d);

  // Move this block to position 0. We can skip this step in
  // "good dimensions" of size divisible by the block size
  if (pos != 0 &&  (!ea.nativeDimension(d) || dSize % blockSize != 0) ) {
    ea.rotate1D(ctxt, d, -pos*blockSize, true);
  }

  long sz = dSize/blockSize; // how many blocks fit in this dimension

  if (sz == 1) return; // nothing to do, only one block in this dimension

  // do the actual replication using "shift and add"

  long k = NumBits(sz);
  long e = 1;
  Ctxt ctxt_orig = ctxt;

  // now process bits k-2 down to 0
  for (long j = k-2; j >= 0; j--) {
    // e -> 2*e
    Ctxt tmp = ctxt;
    ea.rotate1D(tmp, d, e*blockSize, /*don't-care-flag=*/true);
    ctxt += tmp;
    e = 2*e;
    
    long b = bit(sz, j); // bit j of sz
    // e -> e+b
    if (b) {
      ea.rotate1D(ctxt, d, 1*blockSize, /*don't-care-flag=*/true);
      ctxt += ctxt_orig;
      e++;
    }
  }
}
예제 #23
0
NTL_CLIENT

#include "FHE.h"
#include "replicate.h"
#include "timing.h"

static bool check_replicate(const Ctxt& c1, const Ctxt& c0, long i,
			    const FHESecKey& sKey, const EncryptedArray& ea)
{
  PlaintextArray pa0(ea), pa1(ea);
  ea.decrypt(c0, sKey, pa0);
  ea.decrypt(c1, sKey, pa1);
  pa0.replicate(i);
  
  return pa1.equals(pa0); // returns true if replication succeeded
}
예제 #24
0
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);
}
예제 #25
0
// recursiveReplicateDim:
//   d = dimension
//   ea.sizeOfDimension(d)/2 <= extent <= ea.sizeOfDimension(d),
//     only positions [0..extent) are non-zero
//   1 <= 2^k <= extent: size of current interval
//   0 <= pos < ea.sizeOfDimension(d): relative position of first vector
//   0 <= limit < ea.sizeOfDimension(): max # of positions to process
//   dimProd: product of dimensions 0..d
//   recBound: recursion bound (controls noise) 
//
// SHAI: limit and extent are always the same, it seems
static
void recursiveReplicateDim(const EncryptedArray& ea, const Ctxt& ctxt, 
                           long d, long extent, long k, long pos, long limit,  
                           long dimProd, long recBound,
                           RepAuxDim& repAux,
                           ReplicateHandler *handler)
{
  if (pos >= limit) return;

  if (replicateVerboseFlag) { // DEBUG code
    cerr << "check: " << k; CheckCtxt(ctxt, "");
  }
  
  long dSize = ea.sizeOfDimension(d);
  long nSlots = ea.size();

  if (k == 0) { // last level in this dimension: blocks of size 2^k=1

    if ( extent >= dSize) { // nothing to do in this dimension
      replicateAllNextDim(ea, ctxt, d+1, dimProd, recBound, repAux, handler);
      return;
    } // SHAI: Will we ever have extent > dSize??

    // need to replicate to fill positions [ (1L << n) .. dSize-1 ]

    if (repAux.tab(d,0).null()) { // generate mask if not there already
      ZZX mask;
      SelectRangeDim(ea, mask, 0, dSize - extent, d);
      repAux.tab(d, 0).set_ptr(new DoubleCRT(mask, ea.getContext()));
    }

    Ctxt ctxt_tmp = ctxt;
    ctxt_tmp.multByConstant(*repAux.tab(d, 0));

    ea.rotate1D(ctxt_tmp, d, extent, /*don't-care-flag=*/true);
    ctxt_tmp += ctxt;
    replicateAllNextDim(ea, ctxt_tmp, d+1, dimProd, recBound, repAux, handler);
    return;
  }

  // If we need to stop early, call the handler
  if (handler->earlyStop(d, k, dimProd)) {
    handler->handle(ctxt);
    return;
  }

  k--;
  Ctxt ctxt_masked = ctxt;

  {   // artificial scope to miminize storage in the recursion
    { // another artificial scope (SHAI: this seems redundant)

      // generate mask at index k+1, if not there yet

      if (repAux.tab(d, k+1).null()) { // need to generate
        vector< long > maskArray(nSlots,0);
        for (long i = 0; i < nSlots; i++) {
          long c = ea.coordinate(d, i);
          if (c < extent && bit(c, k) == 0)
            maskArray[i] = 1;
        }
	// store this mask in the repAux table
        ZZX mask;
        ea.encode(mask, maskArray);
        repAux.tab(d, k+1).set_ptr(new DoubleCRT(mask, ea.getContext()));
      }

      // Apply mask to zero out slots in ctxt
      ctxt_masked.multByConstant(*repAux.tab(d, k+1));
    }

    Ctxt ctxt_left = ctxt_masked;
    ea.rotate1D(ctxt_left, d, 1L << k, /*don't-care-flag=*/true);
    ctxt_left += ctxt_masked;

    recursiveReplicateDim(ea, ctxt_left, d, extent, k, pos, limit, 
                          dimProd, recBound, 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.rotate1D(ctxt_masked, d, -(1L << k), /*don't-care-flag=*/true);
  ctxt_right += ctxt_masked;

  recursiveReplicateDim(ea, ctxt_right, d, extent, k, pos, limit, 
                        dimProd, recBound, repAux, handler);
}
예제 #26
0
파일: FHLD.cpp 프로젝트: ruescasd/FHLD
PlaintextArray decrypt(Ctxt ctxt, EncryptedArray ea, const FHESecKey secretKey) {
  PlaintextArray p(ea);
  ea.decrypt(ctxt, secretKey, p);

  return p;
}
예제 #27
0
파일: FHLD.cpp 프로젝트: ruescasd/FHLD
void show(Ctxt ctxt, EncryptedArray ea, const FHESecKey secretKey) {
  PlaintextArray p(ea);
  ea.decrypt(ctxt, secretKey, p);

  printVoteFull(p);
}
예제 #28
0
int main(int argc, char *argv[]) 
{
  ArgMapping amap;

  long m=53;
  amap.arg("m", m, "use specified value as modulus");

  long p=17;
  amap.arg("p", p, "plaintext base");

  long r=1;
  amap.arg("r", r,  "lifting");

  long levels=5;
  amap.arg("L", levels,  "levels");

  long nb_coeffs=5;
  amap.arg("n", nb_coeffs,  "nb coefficients to extract");

  amap.parse(argc, argv);

  cout << "\n\n******** generate parameters"
       << " m=" << m 
       << ", p=" << p
       << ", r=" << r
       << ", n=" << nb_coeffs
       << endl;

  setTimersOn();

  FHEcontext context(m, p, r);
  buildModChain(context, /*L=*/levels);
  // cout << context << endl;
  // context.zMStar.printout();
  // cout << endl;

  cout << "Generating keys and key-switching matrices... " << std::flush;
  FHESecKey secretKey(context);
  secretKey.GenSecKey(/*w=*/64);// A Hamming-weight-w secret key
  addFrbMatrices(secretKey); // compute key-switching matrices that we need
  add1DMatrices(secretKey); // compute key-switching matrices that we need
  const FHEPubKey& publicKey = secretKey;
  cout << "done\n";

  resetAllTimers();

  EncryptedArray ea = *(context.ea);
  ea.buildLinPolyMat(false);

  Ctxt ctxt(publicKey);
  NewPlaintextArray ptxt(ea);
  random(ea, ptxt);
  // ea.encrypt(ctxt, publicKey, ptxt);
  ea.skEncrypt(ctxt, secretKey, ptxt);


  cout << "Extracting " << nb_coeffs << " coefficients...";
  vector<Ctxt> coeffs;
  extractCoeffs(ea, coeffs, ctxt, nb_coeffs);
  cout << "done\n";

  vector<ZZX> ptxtDec;
  ea.decrypt(ctxt, secretKey, ptxtDec);

  for (long i=0; i<(long)coeffs.size(); i++) {
    if (!coeffs[i].isCorrect()) {
      cerr << " potential decryption error for "<<i<<"th coeffs " << endl;
      CheckCtxt(coeffs[i], "");
      exit(0);
    }
    vector<ZZX> pCoeffs;
    ea.decrypt(coeffs[i], secretKey, pCoeffs);

    assert(pCoeffs.size() == ptxtDec.size());

    for (int j = 0; j < pCoeffs.size(); ++j) {
      if (coeff(pCoeffs[j], 0) != coeff(ptxtDec[j], i)) {
        cerr << "error: extracted coefficient " << i << " from " 
          "slot " << j << " is " << coeff(pCoeffs[j], 0) << " instead of " << 
          coeff(ptxtDec[j], i) << endl;
        exit(0);
      }
    }

  }  
  cerr << "Extracted coefficient successfully verified!\n";
}
예제 #29
0
void replicateAllNextDim(const EncryptedArray& ea, const Ctxt& ctxt,
                         long d, long dimProd, long recBound,
                         RepAuxDim& repAux, ReplicateHandler *handler)

{
  assert(d >= 0);

  // If already fully replicated (or we need to stop early), call the handler
  if (d >= ea.dimension() || handler->earlyStop(d,/*k=*/-1,dimProd)) {
    handler->handle(ctxt);
    return;
  }
  
  long dSize = ea.sizeOfDimension(d);
  dimProd *= dSize; // product of all dimensions including this one

  long n = GreatestPowerOfTwo(dSize); // 2^n <= dSize
  long k = n;

  // We replicate 2^k-size blocks along this dimension, then call the
  // recursive procedure to handle the smaller subblocks. Consider for
  // example a 2D 5x2 cube, so the original slots are
  //
  //    ( s0 s2 s4 s6 s8 )
  //    ( s1 s3 s5 s7 s9 )
  //
  // Say that we start with k=2 in the 1st dimension (of size 5), we
  // will prepare floor(5/2)=2 ciphertexts as follows:
  //
  //    ( s0 s2 s0 s2 0 )   ( s4 s6 s4 s6 0 )
  //    ( s1 s3 s1 s3 0 )   ( s5 s7 s5 s7 0 )
  //
  // The call to recursiveReplicateDim (still with k=2) will first copy
  // s0/s1 and s4/s5 to the zero column at the end, then make a recursive
  // call with k=1 that will complete the replication along the current
  // dimension, resulting in the 4 ciphertexts
  // 
  //  (s0 s0 s0 s0 s0) (s2 s2 s2 s2 s2) (s4 s4 s4 s4 s4) (s6 s6 s6 s6 s6)
  //  (s1 s1 s1 s1 s1) (s3 s3 s3 s3 s3) (s5 s5 s5 s5 s5) (s7 s7 s7 s7 s7)
  //
  // Then a recursive call for the next dimension will complete the
  // replication of these entries, and a final step will deal with the
  // "leftover" positions s8 s9
  


  // The logic below cut the recursion depth by starting from smaller
  // blocks (by default size approx n rather than 2^n).
  // The inital block size is controlled by the recBound parameter:
  //   + recBound>0: blocks of size min(~n, 2^recBound). this ensures
  //     recursion depth <= recBound, and typically much smaller (~log n)
  //   + recBound=0: blocks of size 1 (no recursion)
  //   + recBound<0: blocks of size 2^n (full recursion)

  if (recBound >= 0) { // use heuristic recursion bound
    k = 0;
    if (dSize > 2 && dimProd*NumBits(dSize) > ea.size() / 8) {
      k = NumBits(NumBits(dSize))-1;
      if (k > n) k = n;
      if (k > recBound) k = recBound;
    }
  }
  else { // SHAI: I don't understand this else case
    k = -recBound;
    if (k > n) k = n;
  }

  long blockSize = 1L << k;        // blocks of size 2^k
  long numBlocks = dSize/blockSize;
  long extent = numBlocks * blockSize;

  // extent is an integral multiple of the block size, the recursive
  // call replicates only these slots, and then we have a separate
  // call for the leftover slots.

  Ctxt ctxt1 = ctxt;

  if (extent < dSize) { // select only the slots 0..extent-1 in this dimension
    if (repAux.tab1(d, 0).null()) { // generate mask if not already there
      ZZX mask;
      SelectRangeDim(ea, mask, 0, extent, d);
      repAux.tab1(d, 0).set_ptr(new DoubleCRT(mask, ea.getContext()));
      // store mask in 2nd table (tab1)
    }
    ctxt1.multByConstant(*repAux.tab1(d, 0)); // mult by mask to zero out slots
  }

  if (numBlocks == 1) { // just one block, call the recursive replication
    recursiveReplicateDim(ea, ctxt1, d, extent, k, 0, extent, 
                          dimProd, recBound, repAux, handler);
  }
  else { // replicate the slots in each block separately
    for (long pos = 0; pos < numBlocks; pos++) {
      Ctxt ctxt2 = ctxt1;
      // zero-out all the slots outside the current block
      SelectRangeDim(ea, ctxt2, pos*blockSize, (pos+1)*blockSize, d);

      // replicate the current block across this dimenssion using a
      // simple shift-and-add procedure.
      replicateOneBlock(ea, ctxt2, pos, blockSize, d);

      // now call the recursive replication to do the rest of the work
      recursiveReplicateDim(ea, ctxt2, d, extent, k, 0, extent, 
                            dimProd, recBound, repAux, handler);
    }
  }

  // If dSize is not an integral number of blocks, then we still need
  // to deal with the leftover slots.
  if (extent < dSize) {
    // zero-out the slots from before, leaving only the leftover slots
    ctxt1 = ctxt;
    if (repAux.tab1(d, 1).null()) { // generate mask if not already there
      ZZX mask;
      SelectRangeDim(ea, mask, extent, dSize, d);
      repAux.tab1(d, 1).set_ptr(new DoubleCRT(mask, ea.getContext()));
    }
    ctxt1.multByConstant(*repAux.tab1(d,1)); // mult by mask to zero out slots

    // move relevant slots to the beginning
    ea.rotate1D(ctxt1, d, -extent, /*don't-care-flag=*/true);

    // replicate the leftover block across this dimenssion using a
    // simple shift-and-add procedure.
    replicateOneBlock(ea, ctxt1, 0, blockSize, d);

    // now call the recursive replication to do the rest of the work
    recursiveReplicateDim(ea, ctxt1, d, extent, k, extent, dSize, 
                          dimProd, recBound, repAux, handler);
  }
}