Example #1
0
void buildModChain(FHEcontext &context, long nLevels, long nDgts)
{
#ifdef NO_HALF_SIZE_PRIME
    long nPrimes = nLevels;
#else
    long nPrimes = (nLevels+1)/2;
    // The first prime should be of half the size. The code below tries to find
    // a prime q0 of this size where q0-1 is divisible by 2^k * m for some k>1.
    // Then if the plaintext space is a power of two it tries to choose the
    // second prime q1 so that q0*q1 = 1 mod ptxtSpace. All the other primes are
    // chosen so that qi-1 is divisible by 2^k * m for as large k as possible.
    long twoM;
    if (ALT_CRT)
        twoM = 2;
    else
        twoM = 2 * context.zMStar.getM();

    long bound = (1L << (context.bitsPerLevel-1));
    while (twoM < bound/(2*context.bitsPerLevel))
        twoM *= 2; // divisible by 2^k * m  for a larger k

    bound = bound - (bound % twoM) +1; // = 1 mod 2m
    long q0 = context.AddPrime(bound, twoM, false, !ALT_CRT);
    // add next prime to chain

    assert(q0 != 0);
    nPrimes--;
#endif

    // Choose the next primes as large as possible
    if (nPrimes>0) AddPrimesByNumber(context, nPrimes);

    // calculate the size of the digits

    if (nDgts > nPrimes) nDgts = nPrimes; // sanity checks
    if (nDgts <= 0) nDgts = 1;
    context.digits.resize(nDgts); // allocate space

    IndexSet s1;
    double sizeSoFar = 0.0;
    double maxDigitSize = 0.0;
    if (nDgts>1) { // we break ciphetext into a few digits when key-switching
        double dsize = context.logOfProduct(context.ctxtPrimes)/nDgts; // estimate
        double target = dsize-(context.bitsPerLevel/3.0);
        long idx = context.ctxtPrimes.first();
        for (long i=0; i<nDgts-1; i++) { // compute next digit
            IndexSet s;
            while (idx <= context.ctxtPrimes.last() && (empty(s)||sizeSoFar<target)) {
                s.insert(idx);
                sizeSoFar += log((double)context.ithPrime(idx));
                idx = context.ctxtPrimes.next(idx);
            }
            assert (!empty(s));
            context.digits[i] = s;
            s1.insert(s);
            double thisDigitSize = context.logOfProduct(s);
            if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize;
            target += dsize;
        }
        IndexSet s = context.ctxtPrimes / s1; // all the remaining primes
        if (!empty(s)) {
            context.digits[nDgts-1] = s;
            double thisDigitSize = context.logOfProduct(s);
            if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize;
        }
        else { // If last digit is empty, remove it
            nDgts--;
            context.digits.resize(nDgts);
        }
    }
    else {
        maxDigitSize = context.logOfProduct(context.ctxtPrimes);
        context.digits[0] = context.ctxtPrimes;
    }

    // Add primes to the chain for the P factor of key-switching
    long p2r = (context.rcData.alMod)? context.rcData.alMod->getPPowR()
               : context.alMod.getPPowR();
    double sizeOfSpecialPrimes
        = maxDigitSize + log(nDgts/32.0)/2 + log(context.stdev *2)
          + log((double)p2r);

    AddPrimesBySize(context, sizeOfSpecialPrimes, true);
}
Example #2
0
void buildModChain(FHEcontext &context, long nLevels, long nDgts,long extraBits)
{
#ifdef NO_HALF_SIZE_PRIME
  long nPrimes = nLevels;
#else
  long nPrimes = (nLevels+1)/2;
  // The first prime should be of half the size. The code below tries to find
  // a prime q0 of this size where q0-1 is divisible by 2^k * m for some k>1.

  long twoM = 2 * context.zMStar.getM();
  long bound = (1L << (context.bitsPerLevel-1));
  while (twoM < bound/(2*context.bitsPerLevel))
    twoM *= 2; // divisible by 2^k * m  for a larger k

  bound = bound - (bound % twoM) +1; // = 1 mod 2m
  long q0 = context.AddPrime(bound, twoM, false); 
  // add next prime to chain
  
  assert(q0 != 0);
  nPrimes--;
#endif

  // Choose the next primes as large as possible
  if (nPrimes>0) AddPrimesByNumber(context, nPrimes);

  // calculate the size of the digits

  if (nDgts > nPrimes) nDgts = nPrimes; // sanity checks
  if (nDgts <= 0) nDgts = 1;
  context.digits.resize(nDgts); // allocate space

  IndexSet s1;
  double sizeSoFar = 0.0;
  double maxDigitSize = 0.0;
  if (nDgts>1) { // we break ciphetext into a few digits when key-switching
    double dsize = context.logOfProduct(context.ctxtPrimes)/nDgts; // estimate

    // A hack: we break the current digit after the total size of all digits
    // so far "almost reaches" the next multiple of dsize, upto 1/3 of a level
    double target = dsize-(context.bitsPerLevel/3.0);
    long idx = context.ctxtPrimes.first();
    for (long i=0; i<nDgts-1; i++) { // set all digits but the last
      IndexSet s;
      while (idx <= context.ctxtPrimes.last() && (empty(s)||sizeSoFar<target)) {
        s.insert(idx);
	sizeSoFar += log((double)context.ithPrime(idx));
	idx = context.ctxtPrimes.next(idx);
      }
      assert (!empty(s));
      context.digits[i] = s;
      s1.insert(s);
      double thisDigitSize = context.logOfProduct(s);
      if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize;
      target += dsize;
    }
    // The ctxt primes that are left (if any) form the last digit
    IndexSet s = context.ctxtPrimes / s1;
    if (!empty(s)) {
      context.digits[nDgts-1] = s;
      double thisDigitSize = context.logOfProduct(s);
      if (maxDigitSize < thisDigitSize) maxDigitSize = thisDigitSize;
    }
    else { // If last digit is empty, remove it
      nDgts--;
      context.digits.resize(nDgts);
    }
  }
  else { // only one digit
    maxDigitSize = context.logOfProduct(context.ctxtPrimes);
    context.digits[0] = context.ctxtPrimes;
  }

  // Add special primes to the chain for the P factor of key-switching
  long p2r = context.alMod.getPPowR();
  double sizeOfSpecialPrimes
    = maxDigitSize + log(nDgts) + log(context.stdev *2)
      + log((double)p2r) + (extraBits*log(2.0));

  AddPrimesBySize(context, sizeOfSpecialPrimes, true);
}