Ejemplo n.º 1
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);
}
Ejemplo n.º 2
0
// A recursive function to compute, for an n-size array, the 2^n products
//     products[j] = \prod_{i s.t. j_i=1} array[i]
//                   \times \prod_{i s.t. j_i=0}(a-array[i])
// It is assume that 'products' size <= 2^n, else only 1st 2^n entries are set
static void
recursiveProducts(const CtPtrs& products, const CtPtrs_slice& array)
{
  long nBits = lsize(array);
  long N = lsize(products);
  if (nBits==0 || N==0) return; // nothing to do

  if (N > (1L << nBits)) N = (1L << nBits);
  else if (N < (1L << (nBits-1)))
    nBits = NTL::NumBits(N-1); // Ensure nBits <= ceil(log2(N))

  if (N<=2) { // edge condition
    *products[0] = *array[0];
    products[0]->negate();
    products[0]->addConstant(ZZ(1)); // out[0] = 1-in
    if (N>1)
      *products[1] = *array[0];    // out[1] = in
  }
  // optimization for n=2: a single multiplication instead of 4
  else if (N<=4) {
    *products[0] = *array[1];          // x1
    products[0]->multiplyBy(*array[0]);// x1 x0

    *products[1] = *array[0];          // x0
    *products[1] -= *products[0];      // x0 - x1 x0 = (1-x1)x0

    *products[2] = *array[1];          // x1
    *products[2] -= *products[0];      // x1 - x1 x0 = x1(1-x0)

    if (N>3)
      *products[3] = *products[0];     // x1 x0

    products[0]->addConstant(ZZ(1));  // 1 +x1 x0
    *products[0] -= *array[1];         // 1 +x1 x0 -x1
    *products[0] -= *array[0]   ;      // 1 +x1 x0 -x1 -x0 = (1-x1)(1-x0)
  }
  else { // split the array into two parts;
    // first part is highest pow(2) < n, second part is what is left

    long n1 = 1L << (NTL::NumBits(nBits)-1); // largest power of two <= n
    if (nBits<=n1) n1 = n1/2;                // largest power of two < n
    long k = 1L << n1;         // size of first part
    long l = 1L << (nBits-n1); // size of second part

    const Ctxt* ct = array.ptr2nonNull(); // find some non-null Ctxt
    std::vector<Ctxt> products1(k, Ctxt(ZeroCtxtLike, *ct));
    std::vector<Ctxt> products2(l, Ctxt(ZeroCtxtLike, *ct));

    // compute first part of the array
    recursiveProducts(CtPtrs_vectorCt(products1), CtPtrs_slice(array,0, n1));

    // recursive call on second part of array
    recursiveProducts(CtPtrs_vectorCt(products2), CtPtrs_slice(array,n1,nBits-n1));

    // multiplication to get all subset products
    NTL_EXEC_RANGE(lsize(products), first, last)
    for(long ii=first; ii<last; ii++) {
      long j = ii / k;
      long i = ii - j*k;
      *products[ii] = products1[i];
      products[ii]->multiplyBy(products2[j]);
    }
    NTL_EXEC_RANGE_END
  }
}