void FindRoot(GF2E& root, const GF2EX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { GF2EXModulus F; GF2EX h, h1, f; GF2E r; f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoot: bad args"); if (deg(f) == 0) Error("FindRoot: bad args"); while (deg(f) > 1) { build(F, f); random(r); clear(h); SetCoeff(h, 1, r); TraceMap(h, h, F); GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } root = ConstTerm(f); }
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>::embedInSlots(RX& H, const vector<RX>& alphas, const MappingData<type>& mappingData) const { long nSlots = zMStar.getNSlots(); assert(lsize(alphas) == nSlots); for (long i = 0; i < nSlots; i++) assert(deg(alphas[i]) < mappingData.degG); vector<RX> crt(nSlots); // alloate space for CRT components // The i'th CRT component is (H mod F_t) = alphas[i](maps[i]) mod F_t, // where with t=T[i]. if (IsX(mappingData.G)) { // special case...no need for CompMod, which is // is not optimized for zero for (long i=0; i<nSlots; i++) // crt[i] = alpha(maps[i]) mod Ft crt[i] = ConstTerm(alphas[i]); } else { // general case... for (long i=0; i<nSlots; i++) // crt[i] = alpha(maps[i]) mod Ft CompMod(crt[i], alphas[i], mappingData.maps[i], factors[i]); } CRT_reconstruct(H,crt); // interpolate to get p }
static void IrredCombine(ZZ_pEX& x, const ZZ_pEX& f, const ZZ_pEX& g) { if (deg(f) < deg(g)) { IrredCombine(x, g, f); return; } // deg(f) >= deg(g)...not necessary, but maybe a little more // time & space efficient long df = deg(f); long dg = deg(g); long m = df*dg; vec_ZZ_pEX h(INIT_SIZE, dg); long i; for (i = 0; i < dg; i++) h[i].SetMaxLength(df); h.SetLength(1); set(h[0]); vec_ZZ_pE a; a.SetLength(2*m); for (i = 0; i < 2*m; i++) { a[i] = ConstTerm(h[0]); if (i < 2*m-1) MulByXPlusY(h, f, g); } MinPolySeq(x, a, m); }
void PAlgebraModDerived<type>::embedInAllSlots(RX& H, const RX& alpha, const MappingData<type>& mappingData) const { if (isDryRun()) { H = RX::zero(); return; } FHE_TIMER_START; long nSlots = zMStar.getNSlots(); vector<RX> crt(nSlots); // alloate space for CRT components // The i'th CRT component is (H mod F_t) = alpha(maps[i]) mod F_t, // where with t=T[i]. if (IsX(mappingData.G) || deg(alpha) <= 0) { // special case...no need for CompMod, which is // is not optimized for this case for (long i=0; i<nSlots; i++) // crt[i] = alpha(maps[i]) mod Ft crt[i] = ConstTerm(alpha); } else { // general case... for (long i=0; i<nSlots; i++) // crt[i] = alpha(maps[i]) mod Ft CompMod(crt[i], alpha, mappingData.maps[i], factors[i]); } CRT_reconstruct(H,crt); // interpolate to get H FHE_TIMER_STOP; }
static void RecFindRoots(vec_GF2E& x, const GF2EX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); x[k] = ConstTerm(f); return; } GF2EX h; GF2E r; { GF2EXModulus F; build(F, f); do { random(r); clear(h); SetCoeff(h, 1, r); TraceMap(h, h, F); GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); }
static void ZZ_pX_InvMod_newton_unram(struct ZZ_pX &x, const struct ZZ_pX &a, const struct ZZ_pXModulus &F, const struct ZZ_pContext &cpn, const struct ZZ_pContext &cp) { //int j; cp.restore(); ZZ_pX *amodp = new ZZ_pX(); ZZ_pX *xmodp = new ZZ_pX(); ZZ_pX *fmodp = new ZZ_pX(); ZZ_pX_conv_modulus(*amodp, a, cp); ZZ_pX_conv_modulus(*fmodp, F.val(), cp); InvMod(*xmodp, *amodp, *fmodp); //cout << "xmodp: " << *xmodp << "\namodp: " << *amodp << "\nfmodp: " << *fmodp << "\n"; cpn.restore(); ZZ_pX *minusa = new ZZ_pX(); ZZ_pX *xn = new ZZ_pX(); ZZ_pX_conv_modulus(*xn, *xmodp, cpn); NTL::negate(*minusa, a); while (1 > 0) { // x_n = 2*x_{n-1} - a*x_{n-1}^2 = (2 - a*x_{n-1})*x_{n-1} MulMod(x, *minusa, *xn, F); SetCoeff(x, 0, ConstTerm(x) + 2); MulMod(x, x, *xn, F); if (x == *xn) break; *xn = x; //cout << "x: " << x << "\nxn: " << *xn << "\n"; //cin >> j; } delete amodp; delete xmodp; delete fmodp; delete minusa; delete xn; }
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); }*******************************************************************/ }
long simplePolyEval(const ZZX& poly, DynamicPtxtPowers& babyStep, long mod) { assert (deg(poly)<=(long)babyStep.size());// ensure that we have enough powers long ret = rem(ConstTerm(poly), mod); for (long i=0; i<deg(poly); i++) { long coeff = rem(poly[i+1], mod); // f_{i+1} long tmp = babyStep[i]; // X^{i+1} tmp = MulMod(tmp, coeff, mod); // f_{i+1} X^{i+1} ret = AddMod(ret, tmp, mod); } return ret; }
static void ZZ_pX_InvMod_newton_ram(struct ZZ_pX &x, const struct ZZ_pX &a, const struct ZZ_pXModulus &F, const struct ZZ_pContext &cpn) { //int j; cpn.restore(); ZZ_pX *minusa = new ZZ_pX(); ZZ_pX *xn = new ZZ_pX(); SetCoeff(*xn, 0, inv(ConstTerm(a))); NTL::negate(*minusa, a); while (1 > 0) { // x_n = 2*x_{n-1} - a*x_{n-1}^2 = (2 - a*x_{n-1})*x_{n-1} MulMod(x, *minusa, *xn, F); SetCoeff(x, 0, ConstTerm(x) + 2); MulMod(x, x, *xn, F); //cout << "x: " << x << "\nxn: " << *xn << "\n"; if (x == *xn) break; *xn = x; //cin >> j; } delete minusa; delete xn; }
void FrobeniusMap(GF2EX& h, const GF2EXModulus& F) { long n = deg(F); long d = GF2E::degree(); if (n == 1) { h = ConstTerm(F); return; } if (UseComposeFrobenius(d, n)) ComposeFrobeniusMap(h, F); else PlainFrobeniusMap(h, F); }
void from_ulong(unsigned long ul, zz_pX& x) { static zz_pX t_to_i; static long p; static zz_p c; // get current field characteristic t_to_i = 1; c = ConstTerm(t_to_i); p = c.modulus(); // convert base-p number ul to polynomial x = 0; while (ul != 0) { x += (ul%p)*t_to_i; t_to_i <<= 1; ul /= p; } }
void PAlgebraModDerived<type>::embedInSlots(RX& H, const vector<RX>& alphas, const MappingData<type>& mappingData) const { if (isDryRun()) { H = RX::zero(); return; } FHE_TIMER_START; long nSlots = zMStar.getNSlots(); assert(lsize(alphas) == nSlots); for (long i = 0; i < nSlots; i++) assert(deg(alphas[i]) < mappingData.degG); vector<RX> crt(nSlots); // alloate space for CRT components // The i'th CRT component is (H mod F_t) = alphas[i](maps[i]) mod F_t, // where with t=T[i]. if (IsX(mappingData.G)) { // special case...no need for CompMod, which is // is not optimized for this case for (long i=0; i<nSlots; i++) // crt[i] = alpha(maps[i]) mod Ft crt[i] = ConstTerm(alphas[i]); } else { // general case...still try to avoid CompMod when possible, // which is the common case for encoding masks for (long i=0; i<nSlots; i++) { // crt[i] = alpha(maps[i]) mod Ft if (deg(alphas[i]) <= 0) crt[i] = alphas[i]; else CompMod(crt[i], alphas[i], mappingData.maps[i], factors[i]); } } CRT_reconstruct(H,crt); // interpolate to get p FHE_TIMER_STOP; }
void FindRoot(ZZ_pE& root, const ZZ_pEX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { ZZ_pEXModulus F; ZZ_pEX h, h1, f; ZZ_pEX r; f = ff; if (!IsOne(LeadCoeff(f))) LogicError("FindRoot: bad args"); if (deg(f) == 0) LogicError("FindRoot: bad args"); while (deg(f) > 1) { build(F, f); random(r, deg(F)); if (IsOdd(ZZ_pE::cardinality())) { PowerMod(h, r, RightShift(ZZ_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); }
static void RecFindRoots(vec_ZZ_pE& x, const ZZ_pEX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } ZZ_pEX h; ZZ_pEX r; { ZZ_pEXModulus F; build(F, f); do { random(r, deg(F)); if (IsOdd(ZZ_pE::cardinality())) { PowerMod(h, r, RightShift(ZZ_pE::cardinality(), 1), F); sub(h, h, 1); } else { AbsTraceMap(h, r, F); } GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); }
void FindRoot(ZZ_p& root, const ZZ_pX& ff) // finds a root of ff. // assumes that ff is monic and splits into distinct linear factors { ZZ_pXModulus F; ZZ_pX h, h1, f; ZZ_p r; ZZ p1; f = ff; if (!IsOne(LeadCoeff(f))) Error("FindRoot: bad args"); if (deg(f) == 0) Error("FindRoot: bad args"); RightShift(p1, ZZ_p::modulus(), 1); h1 = 1; while (deg(f) > 1) { build(F, f); random(r); PowerXPlusAMod(h, r, p1, F); sub(h, h, h1); GCD(h, h, f); if (deg(h) > 0 && deg(h) < deg(f)) { if (deg(h) > deg(f)/2) div(f, f, h); else f = h; } } negate(root, ConstTerm(f)); }
// Simple evaluation sum f_i * X^i, assuming that babyStep has enough powers static void simplePolyEval(Ctxt& ret, const ZZX& poly, DynamicCtxtPowers& babyStep) { ret.clear(); if (deg(poly)<0) return; // the zero polynomial always returns zero assert (deg(poly)<=babyStep.size()); // ensure that we have enough powers ZZ coef; ZZ p = to_ZZ(babyStep[0].getPtxtSpace()); for (long i=1; i<=deg(poly); i++) { rem(coef, coeff(poly,i),p); if (coef > p/2) coef -= p; Ctxt tmp = babyStep.getPower(i); // X^i tmp.multByConstant(coef); // f_i X^i ret += tmp; } // Add the free term rem(coef, ConstTerm(poly), p); if (coef > p/2) coef -= p; ret.addConstant(coef); // if (verbose) checkPolyEval(ret, babyStep[0], poly); }
static void RecFindRoots(vec_ZZ_p& x, const ZZ_pX& f) { if (deg(f) == 0) return; if (deg(f) == 1) { long k = x.length(); x.SetLength(k+1); negate(x[k], ConstTerm(f)); return; } ZZ_pX h; ZZ_p r; ZZ p1; RightShift(p1, ZZ_p::modulus(), 1); { ZZ_pXModulus F; build(F, f); do { random(r); PowerXPlusAMod(h, r, p1, F); add(h, h, -1); GCD(h, h, f); } while (deg(h) <= 0 || deg(h) == deg(f)); } RecFindRoots(x, h); div(h, f, h); RecFindRoots(x, h); }
long IsX(const ZZX& a) { return deg(a) == 1 && IsOne(LeadCoeff(a)) && IsZero(ConstTerm(a)); }
/////////////////////////////////////////////////////////////////////////// // PURPOSE: // Given syndrome ssWithoutEvens of BCH code with design distance d, // finds sparse vector (with no more than // (d-1)/2 ones) with that syndrome // (note that syndrome as well sparse vector // representation are defined at BCHSyndromeCompute above). // 'answer' returns positions of ones in the resulting vector. // These positions are elements of GF2E (i.e., we view the vector // as a vector whose positions are indexed by elements of GF2E). // Returns false if no such vector exists, true otherwise // The input syndrome is assumed to not have even powers, i.e., // has (d-1)/2 elements, such as the syndrome computed by BCHSyndromeCompute. // // ASSUMPTIONS: // Let m=GF2E::degree() (i.e., the field is GF(2^m)). // This algorithm assumes that d is odd, greater than 1, and less than 2^m. // (else BCH codes don't make sense). // Assumes input is of length (d-1)/2. // // ALGORITHM USED: // Implements BCH decoding based on Euclidean algorithm; // For the explanation of the algorithm, see // Syndrome Encoding and Decoding of BCH Codes in Sublinear Time // (Excerpted from Fuzzy Extractors: // How to Generate Strong Keys from Biometrics and Other Noisy Data) // by Yevgeniy Dodis, Rafail Ostrovsky, Leonid Reyzin and Adam Smith // or Theorem 18.7 of Victor Shoup's "A Computational Introduction to // Number Theory and Algebra" (first edition, 2005), or // pp. 170-173 of "Introduction to Coding Theory" by Jurgen Bierbrauer. // // // RUNNING TIME: // If the output has e elements (i.e., the length of the output vector // is e; note that e <= (d-1)/2), then // the running time is O(d^2 + e^2 + e^{\log_2 3} m) operations in GF(2^m), // each of which takes time O(m^{\log_2 3}) in NTL. Note that // \log_2 3 is approximately 1.585. // bool BCHSyndromeDecode(vec_GF2E &answer, const vec_GF2E & ssWithoutEvens, long d) { long i; vec_GF2E ss; // This takes O(d) operation in GF(2^m) InterpolateEvens(ss, ssWithoutEvens); GF2EX r1, r2, r3, v1, v2, v3, q, temp; GF2EX *Rold, *Rcur, *Rnew, *Vold, *Vcur, *Vnew, *tempPointer; // Use pointers to avoid moving polynomials around // An assignment of polynomials requires copying the coefficient vector; // we will not assign polynomials, but will swap pointers instead Rold = &r1; Rcur = &r2; Rnew = &r3; Vold = &v1; Vcur = &v2; Vnew = &v3; SetCoeff(*Rold, d-1, 1); // Rold holds z^{d-1} // Rcur=S(z)/z where S is the syndrome poly, Rcur = \sum S_j z^{j-1} // Note that because we index arrays from 0, S_j is stored in ss[j-1] for (i=0; i<d-1; i++) SetCoeff (*Rcur, i, ss[i]); // Vold is already 0 -- no need to initialize // Initialize Vcur to 1 SetCoeff(*Vcur, 0, 1); // Vcur = 1 // Now run Euclid, but stop as soon as degree of Rcur drops below // (d-1)/2 // This will take O(d^2) operations in GF(2^m) long t = (d-1)/2; while (deg(*Rcur) >= t) { // Rold = Rcur*q + Rnew DivRem(q, *Rnew, *Rold, *Rcur); // Vnew = Vold - qVcur) mul(temp, q, *Vcur); sub (*Vnew, *Vold, temp); // swap everything tempPointer = Rold; Rold = Rcur; Rcur = Rnew; Rnew = tempPointer; tempPointer = Vold; Vold = Vcur; Vcur = Vnew; Vnew = tempPointer; } // At the end of the loop, sigma(z) is Vcur // (up to a constant factor, which doesn't matter, // since we care about roots of sigma). // The roots of sigma(z) are inverses of the points we // are interested in. // We will check that 0 is not // a root of Vcur (else its inverse won't exist, and hence // the right polynomial doesn't exist). if (IsZero(ConstTerm(*Vcur))) return false; // Need sigma to be monic for FindRoots MakeMonic(*Vcur); // check if sigma(z) has distinct roots if not, return false // this will take O(e^{\log_2 3} m) operations in GF(2^m), // where e is the degree of sigma(z) if (CheckIfDistinctRoots(*Vcur) == false) return false; // find roots of sigma(z) // this will take O(e^2 + e^{\log_2 3} m) operations in GF(2^m), // where e is the degree of sigma(z) answer = FindRoots(*Vcur); // take inverses of roots of sigma(z) for (i = 0; i < answer.length(); ++i) answer[i] = inv(answer[i]); // It is now necessary to verify if the resulting vector // has the correct syndrome: it is possible that it does // not even though the polynomial sigma(z) factors // completely // This takes O(de) operations in GF(2^m) vec_GF2E test; BCHSyndromeCompute (test, answer, d); return (test==ssWithoutEvens); }
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; } } }