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(); }
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)); } }