示例#1
0
文件: powerful.cpp 项目: shaih/HElib
PowerfulTranslationIndexes::PowerfulTranslationIndexes(const Vec<long>& mv):
  mvec(mv) // copy the vector of factors
{
  // mvec contains the prime-power factorization of m = \prod_{i=1}^k mi
  long nfactors = mvec.length();  // = k
  m = computeProd(mvec);          // compute m itself

  // phivec holds phi(mi) for all factors mi
  phivec.SetLength(nfactors);
  for (long i = 0; i < nfactors; i++) phivec[i] = phi_N(mvec[i]);
  phim = computeProd(phivec);     // phi(m) = prod_i phi(mi)

  computeDivVec(divvec, m, mvec); // divvec[i] = m/mi

  computeInvVec(invvec, divvec, mvec); // invvec[i] = (m/mi)^{-1} mod mi

  // Let (i_1,...,i_k) be the representation of i in base
  // (m/m1,...,m/mk), namely i = i_1 (m/m_1)+...+i_k (m/m_k) mod m.
  // Then polyToCubeMap[i] is the lexicographic index of the tuple
  // (i_1,...,i_k) in the cube with dimensions (m_1, ..., m_k).
  // cubeToPolyMap is the inverse map, polyToCubeMap[cubeToPolyMap[j]]=j.
  longSig.initSignature(mvec);
  shortSig.initSignature(phivec);
  computePowerToCubeMap(polyToCubeMap, cubeToPolyMap, m, mvec, invvec, longSig);

  // shortSig is a CubeSignature for (phi(m_1),..., phi(m_k)), and longSig
  // is a CubeSignature for (m_1, ..., m_k). shortToLongMap[i] maps an
  // index i wrt shortSig to an index i' wrt longSig so that both indexes
  // correspond to the same tuple (i_1,...,i_k).
  computeShortToLongMap(shortToLongMap, shortSig, longSig);

  cycVec.SetLength(nfactors);
  for (long d = 0; d < nfactors; d++) cycVec[d] = Cyclotomic(mvec[d]);

  phimX = Cyclotomic(m);
}
示例#2
0
long FindM(long k, long L, long c, long p, long d, long s, long chosen_m, bool verbose)
{
    // get a lower-bound on the parameter N=phi(m):
    // 1. Each level in the modulus chain corresponds to pSize=p2Size/2
    //    bits (where we have one prime of this size, and all the others are of
    //    size p2Size).
    //    When using DoubleCRT, we need 2m to divide q-1 for every prime q.
    // 2. With L levels, the largest modulus for "fresh ciphertexts" has size
    //          Q0 ~ p^{L+1} ~ 2^{(L+1)*pSize}
    // 3. We break each ciphertext into upto c digits, do each digit is as large
    //    as    D=2^{(L+1)*pSize/c}
    // 4. The added noise variance term from the key-switching operation is
    //    c*N*sigma^2*D^2, and this must be mod-switched down to w*N (so it is
    //    on par with the added noise from modulus-switching). Hence the ratio
    //    P that we use for mod-switching must satisfy c*N*sigma^2*D^2/P^2<w*N,
    //    or    P > sqrt(c/w) * sigma * 2^{(L+1)*pSize/c}
    // 5. With this extra P factor, the key-switching matrices are defined
    //    relative to a modulus of size
    //          Q0 = q0*P ~ sqrt{c/w} sigma 2^{(L+1)*pSize*(1+1/c)}
    // 6. To get k-bit security we need N>log(Q0/sigma)(k+110)/7.2, i.e. roughly
    //          N > (L+1)*pSize*(1+1/c)(k+110) / 7.2

    // Compute a bound on m, and make sure that it is not too large
    double cc = 1.0+(1.0/(double)c);
    double dN = ceil((L+1)*FHE_pSize*cc*(k+110)/7.2);
    long N = NTL_SP_BOUND;
    if (N > dN) N = dN;
    else {
        cerr << "Cannot support a bound of " << dN;
        Error(", aborting.\n");
    }

    long m = 0;
    size_t i=0;

    // find the first m satisfying phi(m)>=N and d | ord(p) in Z_m^*
    // and phi(m)/ord(p) >= s
    if (chosen_m) {
        if (GCD(p, chosen_m) == 1) {
            long ordP = multOrd(p, chosen_m);
            if (d == 0 || ordP % d == 0) {
                // chosen_m is OK
                m = chosen_m;
            }
        }
    }
    else if (p==2) { // use pre-computed table, divisors of 2^n-1 for some n's

        static long ms[][4] = {  // pre-computed values of [phi(m),m,d]
            //phi(m), m, ord(2),c_m*1000 (not used anymore)
            { 1176,  1247, 28,  3736}, // gens=5(42)
            { 2880,  3133, 24,  3254}, // gens=6(60), 7(!2)
            { 4050,  4051, 50, 0},     // gens=130(81)
            { 4096,  4369, 16,  3422}, // gens=129(16),3(!16)
            { 4704,  4859, 28, 0},     // gens=7(42),3(!4)
            { 5292,  5461, 14,  4160}, // gens=3(126),509(3)
            { 5760,  8435, 24,  8935}, // gens=58(60),1686(2),11(!2)
            { 7500,  7781, 50, 0},     // gens=353(30),3(!5)
            { 8190,  8191, 13,  1273}, // gens=39(630)
            { 9900, 10261, 30, 0},     // gens=3(330)
            {10752, 11441, 48,  3607}, // gens=7(112),5(!2)
            {10800, 11023, 45, 0},     // gens=270(24),2264(2),3(!5)
            {12000, 13981, 20,  2467}, // gens=10(30),23(10),3(!2)
            {11520, 15665, 24, 14916}, // gens=6(60),177(4),7(!2)
            {14112, 14351, 18, 0},     // gens=7(126),3(!4)
            {15004, 15709, 22,  3867}, // gens=5(682)
            {18000, 18631, 25,  4208}, // gens=17(120),1177(6)
            {15360, 20485, 24, 12767}, // gens=6(80),242(4),7(2)
            {16384, 21845, 16, 12798}, // gens=129(16),273(4),3(!16)
            {17280 ,21931, 24, 18387}, // gens=6(60),467(6),11(!2)
            {19200, 21607, 40, 35633}, // gens=13(120),2789(2),3(!2)
            {21168, 27305, 28, 15407}, // gens=6(126),781(6)
            {23040, 23377, 48,  5292}, // gens=35(240),5(!2)
            {23310, 23311, 45, 0},     // gens=489(518)
            {24576, 24929, 48,  5612}, // gens=12(256),5(!2)
            {27000, 32767, 15, 20021}, // gens=3(150),873(6),6945(2)
            {31104, 31609, 72,  5149}, // gens=11(216),5(!2)
            {43690, 43691, 34, 0},     // gens=69(1285)
            {49500, 49981, 30, 0},     // gens=3(1650)
            {46080, 53261, 24, 33409}, // gens=3(240),242(4),7(!2)
            {54000, 55831, 25, 0},     // gens=22(360),3529(6)
            {49140, 57337, 39,  2608}, // gens=39(630),40956(2)
            {51840, 59527, 72, 21128}, // gens=58(60),1912(6),7(!2)
            {61680, 61681, 40,  1273}, // gens=33(771),17(!2)
            {65536, 65537, 32,  1273}, // gens=2(32),3(!2048)
            {75264, 82603, 56, 36484}, // gens=3(336),24294(2),7(!2)
            {84672, 92837, 56, 38520}  // gens=18(126),1886(6),3(!2)
        };
        for (i=0; i<sizeof(ms)/sizeof(long[4]); i++) {
            if (ms[i][0] < N || GCD(p, ms[i][1]) != 1) continue;
            long ordP = multOrd(p, ms[i][1]);
            long nSlots = ms[i][0]/ordP;
            if (d != 0 && ordP % d != 0) continue;
            if (nSlots < s) continue;

            m = ms[i][1];
            break;
        }
    }

    // If m is not set yet, just set it close to N. This may be a lousy
    // choice of m for this p, since you will get a small number of slots.

    if (m==0) {
        // search only for odd values of m, to make phi(m) a little closer to m
        for (long candidate=N|1; candidate<10*N; candidate+=2) {
            if (GCD(p,candidate)!=1) continue;

            long ordP = multOrd(p,candidate); // the multiplicative order of p mod m
            if (d>1 && ordP%d!=0 ) continue;
            if (ordP > 100) continue;  // order too big, we will get very few slots

            long n = phi_N(candidate); // compute phi(m)
            if (n < N) continue;       // phi(m) too small

            m = candidate;  // all tests passed, return this value of m
            break;
        }
    }

    if (verbose) {
        cerr << "*** Bound N="<<N<<", choosing m="<<m <<", phi(m)="<< phi_N(m)
             << endl;
    }

    return m;
}
示例#3
0
文件: EvalMap.cpp 项目: shaih/HElib
ThinEvalMap::ThinEvalMap(const EncryptedArray& _ea, 
                 bool minimal,
                 const Vec<long>& mvec, 
                 bool _invert,
                 bool build_cache)

  : ea(_ea), invert(_invert)
{
  const FHEcontext& context = ea.getContext();
  const PAlgebra& zMStar = ea.getPAlgebra();
  
  long p = zMStar.getP();
  long d = zMStar.getOrdP();

  // FIXME: we should check that ea was initilized with 
  // G == factors[0], but this is a slight pain to check
  // currently

  // NOTE: this code is derived from a more general setting, and
  // could certainly be greatly simplified

  nfactors = mvec.length();
  //OLD: assert(nfactors > 0);
  helib::assertTrue(nfactors > 0, "Invalid argument: mvec must have positive length");

  for (long i = 0; i < nfactors; i++) {
    for (long j = i+1; j < nfactors; j++) {
      helib::assertEq(GCD(mvec[i], mvec[j]), 1l, "Invalid argument: mvec must have pairwise-disjoint entries");
    }
  }

  long m = computeProd(mvec);
  //OLD: assert(m == long(zMStar.getM()));
  helib::assertEq(m, (long)zMStar.getM(), "Invalid argument: mvec's product does not match ea's m");

  Vec<long> phivec(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++)  phivec[i] = phi_N(mvec[i]);
  long phim = computeProd(phivec);

  Vec<long> dprodvec(INIT_SIZE, nfactors+1);
  dprodvec[nfactors] = 1;
  
  for (long i = nfactors-1; i >= 0; i--)
    dprodvec[i] = dprodvec[i+1] *
      multOrd(PowerMod(p % mvec[i], dprodvec[i+1], mvec[i]), mvec[i]);

  Vec<long> dvec(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++)
    dvec[i] = dprodvec[i] / dprodvec[i+1];

  long nslots = phim/d;
  //OLD: assert(d == dprodvec[0]);
  helib::assertEq(d, dprodvec[0], "d must match the first entry of dprodvec");
  //OLD: assert(nslots == long(zMStar.getNSlots()));
  helib::assertEq(nslots, (long)zMStar.getNSlots(), "Invalid argument: mismatch of number of slots");

  long inertPrefix = 0;
  for (long i = 0; i < nfactors && dvec[i] == 1; i++) {
    inertPrefix++;
  }

  if (inertPrefix != nfactors-1)
    throw helib::LogicError("ThinEvalMap: case not handled: bad inertPrefix");

  Vec< Vec<long> > local_reps(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++)
    init_representatives(local_reps[i], i, mvec, zMStar);

  Vec<long> crtvec(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++) 
    crtvec[i] = (m/mvec[i]) * InvMod((m/mvec[i]) % mvec[i], mvec[i]);

  Vec<long> redphivec(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++)
    redphivec[i] = phivec[i]/dvec[i];

  CubeSignature redphisig(redphivec);

  Vec< shared_ptr<CubeSignature> > sig_sequence;
  sig_sequence.SetLength(nfactors+1);
  sig_sequence[nfactors] = shared_ptr<CubeSignature>(new CubeSignature(phivec));

  Vec<long> reduced_phivec = phivec;

  for (long dim = nfactors-1; dim >= 0; dim--) {
    reduced_phivec[dim] /= dvec[dim];
    sig_sequence[dim] = 
      shared_ptr<CubeSignature>(new CubeSignature(reduced_phivec));
  }

  matvec.SetLength(nfactors);

  if (invert) {
     long dim = nfactors - 1;
     unique_ptr<MatMul1D> mat1_data;
     mat1_data.reset(buildThinStep1Matrix(ea, sig_sequence[dim],
		     local_reps[dim], dim, m/mvec[dim]));
     matvec[dim].reset(new MatMul1DExec(*mat1_data, minimal));
  }
  else {
     long dim = nfactors - 1;
     unique_ptr<MatMul1D> mat1_data;
     mat1_data.reset(buildThinStep2Matrix(ea, sig_sequence[dim],
		     local_reps[dim], dim, m/mvec[dim], invert, /*inflate=*/true));
     matvec[dim].reset(new MatMul1DExec(*mat1_data, minimal));
  }

  for (long dim=nfactors-2; dim>=0; --dim) {
    unique_ptr<MatMul1D> mat_data;

    mat_data.reset(buildThinStep2Matrix(ea, sig_sequence[dim], local_reps[dim],
				       dim, m/mvec[dim], invert));
    matvec[dim].reset(new MatMul1DExec(*mat_data, minimal));
  }

  if (build_cache) upgrade();
}
示例#4
0
EvalMap::EvalMap(const EncryptedArray& _ea, const Vec<long>& mvec, bool _invert,
                 bool normal_basis)

  : ea(_ea), invert(_invert)
{
  const FHEcontext& context = ea.getContext();
  const PAlgebra& zMStar = context.zMStar;
  
  long p = zMStar.getP();
  long d = zMStar.getOrdP();

  // FIXME: we should check that ea was initilized with 
  // G == factors[0], but this is a slight pain to check
  // currently

  // NOTE: this code is derived from a more general setting, and
  // could certainly be greatly simplified

  nfactors = mvec.length();
  assert(nfactors > 0);

  for (long i = 0; i < nfactors; i++)
    for (long j = i+1; j < nfactors; j++)
      assert(GCD(mvec[i], mvec[j]) == 1);

  long m = computeProd(mvec);
  assert(m == long(zMStar.getM()));

  Vec<long> phivec(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++)  phivec[i] = phi_N(mvec[i]);
  long phim = computeProd(phivec);

  Vec<long> dprodvec(INIT_SIZE, nfactors+1);
  dprodvec[nfactors] = 1;
  
  for (long i = nfactors-1; i >= 0; i--)
    dprodvec[i] = dprodvec[i+1] *
      multOrd(PowerMod(p % mvec[i], dprodvec[i+1], mvec[i]), mvec[i]);

  Vec<long> dvec(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++)
    dvec[i] = dprodvec[i] / dprodvec[i+1];

  long nslots = phim/d;
  assert(d == dprodvec[0]);
  assert(nslots == long(zMStar.getNSlots()));

  long inertPrefix = 0;
  for (long i = 0; i < nfactors && dvec[i] == 1; i++) {
    inertPrefix++;
  }

  if (inertPrefix != nfactors-1)
    Error("EvalMap: case not handled: bad inertPrefix");

  Vec< Vec<long> > local_reps(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++)
    init_representatives(local_reps[i], i, mvec, zMStar);

  Vec<long> crtvec(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++) 
    crtvec[i] = (m/mvec[i]) * InvMod((m/mvec[i]) % mvec[i], mvec[i]);

  Vec<long> redphivec(INIT_SIZE, nfactors);
  for (long i = 0; i < nfactors; i++)
    redphivec[i] = phivec[i]/dvec[i];

  CubeSignature redphisig(redphivec);

  Vec< shared_ptr<CubeSignature> > sig_sequence;
  sig_sequence.SetLength(nfactors+1);
  sig_sequence[nfactors] = shared_ptr<CubeSignature>(new CubeSignature(phivec));

  Vec<long> reduced_phivec = phivec;

  for (long dim = nfactors-1; dim >= 0; dim--) {
    reduced_phivec[dim] /= dvec[dim];
    sig_sequence[dim] = 
      shared_ptr<CubeSignature>(new CubeSignature(reduced_phivec));
  }

  long dim = nfactors - 1;
  mat1.reset(buildStep1Matrix(ea, sig_sequence[dim],
       	          local_reps[dim], dim, m/mvec[dim], invert, normal_basis));

  matvec.SetLength(nfactors-1);
  for (dim=nfactors-2; dim>=0; --dim) {
    matvec[dim].reset(buildStep2Matrix(ea, sig_sequence[dim], local_reps[dim],
				       dim, m/mvec[dim], invert));
  }
}