void PAlgebraModDerived<type>::decodePlaintext( vector<RX>& alphas, const RX& ptxt, const MappingData<type>& mappingData) const { long nSlots = zMStar.getNSlots(); if (isDryRun()) { alphas.assign(nSlots, RX::zero()); return; } // First decompose p into CRT components vector<RX> CRTcomps(nSlots); // allocate space for CRT component CRT_decompose(CRTcomps, ptxt); // CRTcomps[i] = p mod facors[i] if (mappingData.degG==1) { alphas = CRTcomps; return; } alphas.resize(nSlots); REBak bak; bak.save(); mappingData.contextForG.restore(); for (long i=0; i<nSlots; i++) { REX te; conv(te, CRTcomps[i]); // lift i'th CRT componnet to mod G(X) te %= mappingData.rmaps[i]; // reduce CRTcomps[i](Y) mod Qi(Y), over (Z_2[X]/G(X)) // the free term (no Y component) should be our answer (as a poly(X)) alphas[i] = rep(ConstTerm(te)); } }
void PAlgebraModDerived<type>:: buildLinPolyCoeffs(vector<RX>& C, const vector<RX>& L, const MappingData<type>& mappingData) const { REBak bak; bak.save(); mappingData.contextForG.restore(); long d = RE::degree(); long p = zMStar.getP(); assert(lsize(L) == d); vec_RE LL; LL.SetLength(d); for (long i = 0; i < d; i++) conv(LL[i], L[i]); vec_RE CC; ::buildLinPolyCoeffs(CC, LL, p, r); C.resize(d); for (long i = 0; i < d; i++) C[i] = rep(CC[i]); }
template<class type> void EncryptedArrayDerived<type>::buildLinPolyCoeffs(vector<RX>& C, const vector<RX>& L) const { FHE_TIMER_START; RBak bak; bak.save(); restoreContext(); // the NTL context for mod p^r REBak ebak; ebak.save(); restoreContextForG(); // The NTL context for mod G do { typename Lazy< Mat<RE> >::Builder builder(linPolyMatrix); if (!builder()) break; long p = tab.getZMStar().getP(); long r = tab.getR(); Mat<RE> M1; // build d x d matrix, d is taken from the surrent NTL context for G buildLinPolyMatrix(M1, p); Mat<RE> M2; ppInvert(M2, M1, p, r); // invert modulo prime-power p^r UniquePtr< Mat<RE> > ptr; ptr.make(M2); builder.move(ptr); } while (0); Vec<RE> CC, LL; convert(LL, L); mul(CC, LL, *linPolyMatrix); convert(C, CC); }
void PAlgebraModDerived<type>::mapToFt(RX& w, const RX& G,unsigned long t,const RX* rF1) const { if (isDryRun()) { w = RX::zero(); return; } long i = zMStar.indexOfRep(t); if (i < 0) { clear(w); return; } if (rF1==NULL) { // Compute the representation "from scratch" // special case if (G == factors[i]) { SetX(w); return; } //special case if (deg(G) == 1) { w = -ConstTerm(G); return; } // the general case: currently only works when r == 1 assert(r == 1); REBak bak; bak.save(); RE::init(factors[i]); // work with the extension field GF_p[X]/Ft(X) REX Ga; conv(Ga, G); // G as a polynomial over the extension field vec_RE roots; FindRoots(roots, Ga); // Find roots of G in this field RE* first = &roots[0]; RE* last = first + roots.length(); RE* smallest = min_element(first, last); // make a canonical choice w=rep(*smallest); return; } // if rF1 is set, then use it instead, setting w = rF1(X^t) mod Ft(X) RXModulus Ft(factors[i]); // long tInv = InvMod(t,m); RX X2t = PowerXMod(t,Ft); // X2t = X^t mod Ft w = CompMod(*rF1,X2t,Ft); // w = F1(X2t) mod Ft /* Debugging sanity-check: G(w)=0 in the extension field (Z/2Z)[X]/Ft(X) RE::init(factors[i]); REX Ga; conv(Ga, G); // G as a polynomial over the extension field RE ra; conv(ra, w); // w is an element in the extension field eval(ra,Ga,ra); // ra = Ga(ra) if (!IsZero(ra)) {// check that Ga(w)=0 in this extension field cout << "rF1(X^t) mod Ft(X) != root of G mod Ft, t=" << t << endl; exit(0); }*******************************************************************/ }
void EncryptedArrayDerived<type>::initNormalBasisMatrix() const { do { typename Lazy< Pair< Mat<R>, Mat<R> > >::Builder builder(normalBasisMatrices); if (!builder()) break; RBak bak; bak.save(); restoreContext(); REBak ebak; ebak.save(); restoreContextForG(); long d = RE::degree(); long p = tab.getZMStar().getP(); long r = tab.getR(); // compute change of basis matrix CB mat_R CB; CB.SetDims(d, d); RE normal_element; RE H; bool got_it = false; H = power(conv<RE>(RX(1, 1)), p); do { NTL::random(normal_element); RE pow; pow = normal_element; VectorCopy(CB[0], rep(pow), d); for (long i = 1; i < d; i++) { pow = eval(rep(pow), H); VectorCopy(CB[i], rep(pow), d); } Mat<ZZ> CB1; conv(CB1, CB); { zz_pBak bak1; bak1.save(); zz_p::init(p); Mat<zz_p> CB2; conv(CB2, CB1); got_it = determinant(CB2) != 0; } } while (!got_it); Mat<R> CBi; ppInvert(CBi, CB, p, r); UniquePtr< Pair< Mat<R>, Mat<R> > > ptr; ptr.make(CB, CBi); builder.move(ptr); } while(0); }
void PAlgebraModDerived<type>::mapToSlots(MappingData<type>& mappingData, const RX& G) const { assert(deg(G) > 0 && zMStar.getOrdP() % deg(G) == 0); assert(LeadCoeff(G) == 1); mappingData.G = G; mappingData.degG = deg(mappingData.G); long nSlots = zMStar.getNSlots(); long m = zMStar.getM(); mappingData.maps.resize(nSlots); mapToF1(mappingData.maps[0],mappingData.G); // mapping from base-G to base-F1 for (long i=1; i<nSlots; i++) mapToFt(mappingData.maps[i], mappingData.G, zMStar.ith_rep(i), &(mappingData.maps[0])); REBak bak; bak.save(); RE::init(mappingData.G); mappingData.contextForG.save(); if (deg(mappingData.G)==1) return; mappingData.rmaps.resize(nSlots); if (G == factors[0]) { // an important special case for (long i = 0; i < nSlots; i++) { long t = zMStar.ith_rep(i); long tInv = InvMod(t, m); RX ct_rep; PowerXMod(ct_rep, tInv, G); RE ct; conv(ct, ct_rep); REX Qi; SetCoeff(Qi, 1, 1); SetCoeff(Qi, 0, -ct); mappingData.rmaps[i] = Qi; } } else { // the general case: currently only works when r == 1 assert(r == 1); vec_REX FRts; for (long i=0; i<nSlots; i++) { // We need to lift Fi from R[Y] to (R[X]/G(X))[Y] REX Qi; long t, tInv=0; if (i == 0) { conv(Qi,factors[i]); FRts=EDF(Qi, FrobeniusMap(Qi), deg(Qi)/deg(G)); // factor Fi over GF(p)[X]/G(X) } else { t = zMStar.ith_rep(i); tInv = InvMod(t, m); } // need to choose the right factor, the one that gives us back X long j; for (j=0; j<FRts.length(); j++) { // lift maps[i] to (R[X]/G(X))[Y] and reduce mod j'th factor of Fi REX FRtsj; if (i == 0) FRtsj = FRts[j]; else { REX X2tInv = PowerXMod(tInv, FRts[j]); IrredPolyMod(FRtsj, X2tInv, FRts[j]); } // FRtsj is the jth factor of factors[i] over the extension field. // For j > 0, we save some time by computing it from the jth factor // of factors[0] via a minimal polynomial computation. REX GRti; conv(GRti, mappingData.maps[i]); GRti %= FRtsj; if (IsX(rep(ConstTerm(GRti)))) { // is GRti == X? Qi = FRtsj; // If so, we found the right factor break; } // If this does not happen then move to the next factor of Fi } assert(j < FRts.length()); mappingData.rmaps[i] = Qi; } } }