Example #1
0
bool IndexSet::disjointFrom(const IndexSet& s) const
{
  // quick tests for some common cases
  if (card() == 0 || s.card() == 0
      || last() < s.first() || s.last() < first()) return true;

  for (long i = s.first(); i <= s.last(); i = s.next(i))
    if (contains(i)) return false;
  return true;
}
Example #2
0
void IndexSet::remove(const IndexSet& s) {
  if (this == &s) { clear(); return; }
  if (s.card() == 0) return;
  if (card() == 0) return;

  for (long i = s.first(); i <= s.last(); i = s.next(i)) remove(i);
  // NOTE: traversal order should not matter here
}
Example #3
0
// Sanity-check: Check that prime-set is "valid", i.e. that it 
// contains either all the special primes or none of them
bool Ctxt::verifyPrimeSet() const
{
  IndexSet s = primeSet & context.specialPrimes; // special primes in primeSet
  if (!empty(s) && s!=context.specialPrimes) return false;

  s = primeSet / s;                              // ctxt primes in primeSet
  return (s.isInterval() && s.first()<=1 && !empty(s));
}
Example #4
0
void IndexSet::insert(const IndexSet& s) {
  if (this == &s) return;
  if (s.card() == 0) return;
  if (card() == 0) {
    *this = s;
    return;
  }

  for (long i = s.last(); i >= s.first(); i = s.prev(i)) insert(i);
  // NOTE: traversal done from high to low so as to trigger at 
  // at most one resize

}
Example #5
0
DoubleCRT::DoubleCRT(const ZZX& poly, const FHEcontext &_context, const IndexSet& s)
: context(_context), map(new DoubleCRTHelper(_context))
{
  assert(s.last() < context.numPrimes());

  map.insert(s);
  if (dryRun) return;

  // convert the integer polynomial to FFT representation modulo the primes
  for (long i = s.first(); i <= s.last(); i = s.next(i)) {
    const Cmodulus &pi = context.ithModulus(i);
    pi.FFT(map[i], poly); // reduce mod pi and store FFT image
  }
}
Example #6
0
// Expand index set by s1, and multiply by \prod{q \in s1}. s1 is assumed to
// be disjoint from the current index set. Returns the logarithm of product.
double DoubleCRT::addPrimesAndScale(const IndexSet& s1)
{
  if (empty(s1)) return 0.0; // nothing to do
  assert(empty(s1 & map.getIndexSet())); // s1 is disjoint from *this

  // compute factor to scale existing rows
  ZZ factor = to_ZZ(1);
  double logFactor = 0.0;
  for (long i = s1.first(); i <= s1.last(); i = s1.next(i)) {
    long qi = context.ithPrime(i);
    factor *= qi;
    logFactor += log((double)qi);
  }

  // scale existing rows
  long phim = context.zMStar.getPhiM();
  const IndexSet& iSet = map.getIndexSet();
  for (long i = iSet.first(); i <= iSet.last(); i = iSet.next(i)) {
    long qi = context.ithPrime(i);
    long f = rem(factor, qi);     // f = factor % qi
    vec_long& row = map[i];
    // scale row by a factor of f modulo qi
    mulmod_precon_t bninv = PrepMulModPrecon(f, qi, 1.0/(double)qi);
    for (long j=0; j<phim; j++) 
      row[j] = MulModPrecon(row[j], f, qi, bninv);
  }

  // insert new rows and fill them with zeros
  map.insert(s1);  // add new rows to the map
  for (long i = s1.first(); i <= s1.last(); i = s1.next(i)) {
    vec_long& row = map[i];
    for (long j=0; j<phim; j++) row[j] = 0;
  }

  return logFactor;
}
Example #7
0
// If the IndexSet is omitted, default to all the primes in the chain
void PowerfulDCRT::ZZXtoPowerful(Vec<ZZ>& out, const ZZX& poly,
				 IndexSet set) const
{
  if (empty(set))
    set = IndexSet(0, pConvVec.length()-1);

  zz_pBak bak; bak.save(); // backup NTL's current modulus

  ZZ product = conv<ZZ>(1L);
  for (long i = set.first(); i <= set.last(); i = set.next(i)) {
    pConvVec[i].restoreModulus();
    long newPrime = zz_p::modulus();
    zz_pX oneRowPoly;
    conv(oneRowPoly, poly);  // reduce mod p and convert to zz_pX

    HyperCube<zz_p> oneRowPwrfl(indexes.shortSig);
    pConvVec[i].polyToPowerful(oneRowPwrfl, oneRowPoly);
    if (i == set.first()) // just copy
      conv(out, oneRowPwrfl.getData());
    else                  // CRT
      intVecCRT(out, product, oneRowPwrfl.getData(), newPrime); // in NumbTh
    product *= newPrime;
  }
}
Example #8
0
DoubleCRT::DoubleCRT(const ZZX& poly)
: context(*activeContext), map(new DoubleCRTHelper(*activeContext))
{
  IndexSet s = IndexSet(0, context.numPrimes()-1);
  // FIXME: maybe the default index set should be determined by context?

  map.insert(s);
  if (dryRun) return;

  // convert the integer polynomial to FFT representation modulo the primes
  for (long i = s.first(); i <= s.last(); i = s.next(i)) {
    const Cmodulus &pi = context.ithModulus(i);
    pi.FFT(map[i], poly); // reduce mod pi and store FFT image
  }
}
Example #9
0
DoubleCRT::DoubleCRT(const FHEcontext &_context, const IndexSet& s)
: context(_context), map(new DoubleCRTHelper(_context))
{
  assert(s.last() < context.numPrimes());

  map.insert(s);
  if (dryRun) return;

  long phim = context.zMStar.getPhiM();

  for (long i = s.first(); i <= s.last(); i = s.next(i)) {
    vec_long& row = map[i];
    for (long j = 0; j < phim; j++) row[j] = 0;
  }
}
Example #10
0
// expand index set by s1.
// it is assumed that s1 is disjoint from the current index set.
void DoubleCRT::addPrimes(const IndexSet& s1)
{
  if (empty(s1)) return; // nothing to do
  assert( disjoint(s1,map.getIndexSet()) ); // s1 is disjoint from *this

  ZZX poly;
  toPoly(poly); // recover in coefficient representation

  map.insert(s1);  // add new rows to the map
  if (dryRun) return;

  // fill in new rows
  for (long i = s1.first(); i <= s1.last(); i = s1.next(i)) {
    context.ithModulus(i).FFT(map[i], poly); // reduce mod p_i and store FFT image
  }
}
Example #11
0
DoubleCRT::DoubleCRT(const FHEcontext &_context)
: context(_context), map(new DoubleCRTHelper(_context))
{
  IndexSet s = IndexSet(0, context.numPrimes()-1);
  // FIXME: maybe the default index set should be determined by context?

  map.insert(s);
  if (dryRun) return;

  long phim = context.zMStar.getPhiM();

  for (long i = s.first(); i <= s.last(); i = s.next(i)) {
    vec_long& row = map[i];
    for (long j = 0; j < phim; j++) row[j] = 0;
  }
}
Example #12
0
void SingleCRT::addPrimes(const IndexSet& s1)
{
  assert(card(s1 & map.getIndexSet()) == 0);

  ZZX poly, poly1;
  toPoly(poly); // recover in coefficient representation

  map.insert(s1);  // add new rows to the map

  // fill in new rows
  for (long i = s1.first(); i <= s1.last(); i = s1.next(i)) {
    ZZ pi = to_ZZ(context.ithPrime(i));

    poly1 = poly;
    PolyRed(poly1,pi,true); // the flag true means reduce to [0,pi-1)
    map[i] = poly;
  }
}
Example #13
0
File: Ctxt.cpp Project: 2080/HElib
NTL_CLIENT

#include "FHEContext.h"
#include "Ctxt.h"
#include "FHE.h"
#include "timing.h"


// Sanity-check: Check that prime-set is "valid", i.e. that it 
// contains either all the special primes or none of them
bool Ctxt::verifyPrimeSet() const
{
  IndexSet s = primeSet & context.specialPrimes; // special primes in primeSet
  if (!empty(s) && s!=context.specialPrimes) return false;

  s = primeSet / s;                              // ctxt primes in primeSet
  return (s.isInterval() && s.first()<=1 && !empty(s));
}
Example #14
0
// Copy only the primes in s \intersect other.getIndexSet()
void DoubleCRT::partialCopy(const DoubleCRT& other, const IndexSet& _s)
{
   if (&context != &other.context) 
      Error("DoubleCRT::partialCopy: incompatible contexts");

   // set the primes of *this to s \intersect other.getIndexSet()
   IndexSet s = _s;
   s.retain(other.getIndexSet());
   map.remove(getIndexSet() / s);
   map.insert(s / getIndexSet());

   long phim = context.zMStar.getPhiM();
   for (long i = s.first(); i <= s.last(); i = s.next(i)) {
     vec_long& row = map[i];
     const vec_long& other_row = other.map[i];
     for (long j = 0; j < phim; j++)
       row[j] = other_row[j];
   }
}
Example #15
0
//FIXME: both the reduction from powerful to the individual primes and
//  the CRT back to poly can be made more efficient
void PowerfulDCRT::powerfulToZZX(ZZX& poly, const Vec<ZZ>& powerful,
				 IndexSet set) const
{
  zz_pBak bak; bak.save(); // backup NTL's current modulus

  if (empty(set)) set = IndexSet(0, pConvVec.length()-1);

  clear(poly);
  //  poly.SetLength(powerful.length());
  ZZ product = conv<ZZ>(1L);
  for (long i = set.first(); i <= set.last(); i = set.next(i)) {
    pConvVec[i].restoreModulus();
    //    long newPrime = zz_p::modulus();

    HyperCube<zz_p> oneRowPwrfl(indexes.shortSig);
    conv(oneRowPwrfl.getData(), powerful); // reduce and convert to Vec<zz_p>

    zz_pX oneRowPoly;
    pConvVec[i].powerfulToPoly(oneRowPoly, oneRowPwrfl);
    CRT(poly, product, oneRowPoly);                   // NTL :-)
  }
  poly.normalize();
}
Example #16
0
bool IndexSet::contains(const IndexSet& s) const {
  for (long i = s.first(); i <= s.last(); i = s.next(i))
    if (!contains(i)) return false;
  return true;
}
Example #17
0
void FHEcontext::productOfPrimes(ZZ& p, const IndexSet& s) const
{
    p = 1;
    for (long i = s.first(); i <= s.last(); i = s.next(i))
        p *= ithPrime(i);
}
Example #18
0
// bootstrap a ciphertext to reduce noise
void FHEPubKey::reCrypt(Ctxt &ctxt)
{
  FHE_TIMER_START;

  // Some sanity checks for dummy ciphertext
  long ptxtSpace = ctxt.getPtxtSpace();
  if (ctxt.isEmpty()) return;
  if (ctxt.parts.size()==1 && ctxt.parts[0].skHandle.isOne()) {
    // Dummy encryption, just ensure that it is reduced mod p
    ZZX poly = to_ZZX(ctxt.parts[0]);
    for (long i=0; i<poly.rep.length(); i++)
      poly[i] = to_ZZ( rem(poly[i],ptxtSpace) );
    poly.normalize();
    ctxt.DummyEncrypt(poly);
    return;
  }

  assert(recryptKeyID>=0); // check that we have bootstrapping data

  long p = getContext().zMStar.getP();
  long r = getContext().alMod.getR();
  long p2r = getContext().alMod.getPPowR();

  // the bootstrapping key is encrypted relative to plaintext space p^{e-e'+r}.
  long e = getContext().rcData.e;
  long ePrime = getContext().rcData.ePrime;
  long p2ePrime = power_long(p,ePrime);
  long q = power_long(p,e)+1;
  assert(e>=r);

#ifdef DEBUG_PRINTOUT
  cerr << "reCrypt: p="<<p<<", r="<<r<<", e="<<e<<" ePrime="<<ePrime
       << ", q="<<q<<endl;
#endif

  // can only bootstrap ciphertext with plaintext-space dividing p^r
  assert(p2r % ptxtSpace == 0);

  FHE_NTIMER_START(preProcess);

  // Make sure that this ciphertxt is in canonical form
  if (!ctxt.inCanonicalForm()) ctxt.reLinearize();

  // Mod-switch down if needed
  IndexSet s = ctxt.getPrimeSet() / getContext().specialPrimes; // set minus
  if (s.card()>2) { // leave only bottom two primes
    long frst = s.first();
    long scnd = s.next(frst);
    IndexSet s2(frst,scnd);
    s.retain(s2); // retain only first two primes
  }
  ctxt.modDownToSet(s);

  // key-switch to the bootstrapping key
  ctxt.reLinearize(recryptKeyID);

  // "raw mod-switch" to the bootstrapping mosulus q=p^e+1.
  vector<ZZX> zzParts; // the mod-switched parts, in ZZX format
  double noise = ctxt.rawModSwitch(zzParts, q);
  noise = sqrt(noise);

  // Add multiples of p2r and q to make the zzParts divisible by p^{e'}
  long maxU=0;
  for (long i=0; i<(long)zzParts.size(); i++) {
    // make divisible by p^{e'}
    long newMax = makeDivisible(zzParts[i].rep, p2ePrime, p2r, q,
				getContext().rcData.alpha);
    zzParts[i].normalize();   // normalize after working directly on the rep
    if (maxU < newMax)  maxU = newMax;
  }

  // Check that the estimated noise is still low
  if (noise + maxU*p2r*(skHwts[recryptKeyID]+1) > q/2) 
    cerr << " * noise/q after makeDivisible = "
	 << ((noise + maxU*p2r*(skHwts[recryptKeyID]+1))/q) << endl;

  for (long i=0; i<(long)zzParts.size(); i++)
    zzParts[i] /= p2ePrime;   // divide by p^{e'}

  // Multiply the post-processed cipehrtext by the encrypted sKey
#ifdef DEBUG_PRINTOUT
  cerr << "+ Before recryption ";
  decryptAndPrint(cerr, recryptEkey, *dbgKey, *dbgEa, printFlag);
#endif

  double p0size = to_double(coeffsL2Norm(zzParts[0]));
  double p1size = to_double(coeffsL2Norm(zzParts[1]));
  ctxt = recryptEkey;
  ctxt.multByConstant(zzParts[1], p1size*p1size);
  ctxt.addConstant(zzParts[0], p0size*p0size);

#ifdef DEBUG_PRINTOUT
  cerr << "+ Before linearTrans1 ";
  decryptAndPrint(cerr, ctxt, *dbgKey, *dbgEa, printFlag);
#endif
  FHE_NTIMER_STOP(preProcess);

  // Move the powerful-basis coefficients to the plaintext slots
  FHE_NTIMER_START(LinearTransform1);
  ctxt.getContext().rcData.firstMap->apply(ctxt);
  FHE_NTIMER_STOP(LinearTransform1);

#ifdef DEBUG_PRINTOUT
  cerr << "+ After linearTrans1 ";
  decryptAndPrint(cerr, ctxt, *dbgKey, *dbgEa, printFlag);
#endif

  // Extract the digits e-e'+r-1,...,e-e' (from fully packed slots)
  extractDigitsPacked(ctxt, e-ePrime, r, ePrime,
		      context.rcData.unpackSlotEncoding);

#ifdef DEBUG_PRINTOUT
  cerr << "+ Before linearTrans2 ";
  decryptAndPrint(cerr, ctxt, *dbgKey, *dbgEa, printFlag);
#endif

  // Move the slots back to powerful-basis coefficients
  FHE_NTIMER_START(LinearTransform2);
  ctxt.getContext().rcData.secondMap->apply(ctxt);
  FHE_NTIMER_STOP(LinearTransform2);
}