// Compute the L-infinity distance between two vectors double calcMaxDiff(const vector<cx_double>& v1, const vector<cx_double>& v2){ if(lsize(v1)!=lsize(v2)) NTL::Error("Vector sizes differ.\nFAILED\n"); double maxDiff = 0.0; for (long i=0; i<lsize(v1); i++) { double diffAbs = std::abs(v1[i]-v2[i]); if (diffAbs > maxDiff) maxDiff = diffAbs; } return maxDiff; }
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]); }
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 }
/*--------------------------------------------------------------- | lget_ln | | get from list, listnode - return the nth list item, the | listnode is returned instead of the data, non-destructive ---------------------------------------------------------------*/ LNODEID lget_ln ( LISTID lid, unsigned int n ) { int i; LIST * l; LISTNODE * ln; l = (LIST *)lid; CKLMAGIC(l); if ((n<1)||(n>lsize(l))) { return NULL; } ln = l->top; i = 1; while (i!=n) { CKMAGIC(ln); ln = ln->next; i++; } CKLMAGIC(l); return (LNODEID)ln; }
NTL_CLIENT // Sample a degree-(n-1) poly, with only Hwt nonzero coefficients void sampleHWt(zzX &poly, long n, long Hwt) { if (n<=0) n=lsize(poly); if (n<=0) return; if (Hwt>=n) { #ifdef DEBUG_PRINTOUT std::cerr << "Hwt="<<Hwt<<">=n="<<n<<", is this ok?\n"; #endif Hwt = n-1; } poly.SetLength(n); // allocate space for (long i=0; i<n; i++) poly[i] = 0; long i=0; while (i<Hwt) { // continue until exactly Hwt nonzero coefficients long u = NTL::RandomBnd(n); // The next coefficient to choose if (poly[u]==0) { // if we didn't choose it already long b = NTL::RandomBits_long(2)&2; // b random in {0,2} poly[u] = b-1; // random in {-1,1} i++; // count another nonzero coefficient } } }
/*--------------------------------------------------------------- | lget_n | | get from list, index - return the nth list item, | non-destructive ---------------------------------------------------------------*/ void * lget_n ( LISTID lid, unsigned int n ) { int i; LIST * l; LISTNODE * ln; l = (LIST *)lid; CKLMAGIC(l); if ((n<1)||(n>lsize(l))) { return NULL; } ln = l->top; i = 1; while (ln && (i!=n)) { CKMAGIC(ln); ln = ln->next; i++; } if (ln) { CKLMAGIC(l); return ln->data; } else { CKLMAGIC(l); return NULL; } }
// Sample a degree-(n-1) poly, with -1/0/+1 coefficients. // Each coefficients is +-1 with probability prob/2 each, // and 0 with probability 1-prob. By default, pr[nonzero]=1/2. void sampleSmall(zzX &poly, long n, double prob) { if (n<=0) n=lsize(poly); if (n<=0) return; assert(prob>3.05e-5 && prob<=1); // prob must be in [2^{-15},1/2] poly.SetLength(n); constexpr long bitSize=16; constexpr long hiMask = (1<<(bitSize-1)); // top bit = 2^15 constexpr long loMask = hiMask-1; // bottom 15 bits long threshold = round(hiMask*prob); // threshold/2^15 = Pr[nonzero] NTL_EXEC_RANGE(n, first, last) for (long i=first; i<last; i++) { long u = NTL::RandomBits_long(bitSize); // a random 16-bit number long uLo = u & loMask; // bottom 15 bits long uHi = u & hiMask; // top bit // with probability threshold/2^15, choose between +-1 if (uLo<threshold) { // compare low 15 bits to threshold poly[i] = (uHi>>(bitSize-2))-1; // topBit*2 - 1 \in {+-1} } // with probability 1-prob, set to zero else poly[i] = 0;
// A counterpart of tableLookup. The input is an encrypted table T[] // and an array of encrypted bits I[], holding the binary representation // of an index i into T. This function increments by one the entry T[i]. void tableWriteIn(const CtPtrs& table, const CtPtrs& idx, std::vector<zzX>* unpackSlotEncoding) { FHE_TIMER_START; const Ctxt* ct = table.ptr2nonNull(); // find some non-null Ctxt long size = lsize(table); if (size==0) return; std::vector<Ctxt> products(size, Ctxt(ZeroCtxtLike, *ct)); CtPtrs_vectorCt pWrap(products); // A wrapper // Compute all products of ecnrypted bits =: b_i computeAllProducts(pWrap, idx, unpackSlotEncoding); // incrememnt each entry of T[i] by products[i] NTL_EXEC_RANGE(lsize(table), first, last) for(long i=first; i<last; i++) *table[i] += products[i]; NTL_EXEC_RANGE_END }
// The input is a plaintext table T[] and an array of encrypted bits // I[], holding the binary representation of an index i into T. // The output is the encrypted value T[i]. void tableLookup(Ctxt& out, const vector<zzX>& table, const CtPtrs& idx, std::vector<zzX>* unpackSlotEncoding) { FHE_TIMER_START; out.clear(); vector<Ctxt> products(lsize(table), out); // to hold subset products of idx CtPtrs_vectorCt pWrap(products); // A wrapper // Compute all products of ecnrypted bits =: b_i computeAllProducts(pWrap, idx, unpackSlotEncoding); // Compute the sum b_i * T[i] NTL_EXEC_RANGE(lsize(table), first, last) for(long i=first; i<last; i++) products[i].multByConstant(table[i]); // p[i] = p[i]*T[i] NTL_EXEC_RANGE_END for(long i=0; i<lsize(table); i++) out += products[i]; }
// Apply different transformations to different slots. Cvec is a vector of // length ea.size(), with each entry the output of ea.buildLinPolyCoeffs void applyLinPolyMany(const EncryptedArray& ea, Ctxt& ctxt, const vector< vector<ZZX> >& Cvec) { assert(&ea.getContext() == &ctxt.getContext()); long d = ea.getDegree(); long nslots = ea.size(); assert(nslots == lsize(Cvec)); for (long i = 0; i < nslots; i++) assert(d == lsize(Cvec[i])); vector<ZZX> encodedC(d); for (long j = 0; j < d; j++) { vector<ZZX> v(nslots); for (long i = 0; i < nslots; i++) v[i] = Cvec[i][j]; ea.encode(encodedC[j], v); } applyLinPolyLL(ctxt, encodedC, ea.getDegree()); }
/*------------------------------------------------------------ | lcat | | catenate - catenate l2 to l1, return pointer to l1. ------------------------------------------------------------*/ LISTID lcat ( LISTID lid1, LISTID lid2 ) { CKLMAGIC(((LIST *)lid1)); CKLMAGIC(((LIST *)lid2)); while (lsize(lid2)) { ladd ( lid1, lrmv_n(lid2,1) ); } CKLMAGIC(((LIST *)lid1)); CKLMAGIC(((LIST *)lid2)); return lid1; }
/* combine hunk lists a and b, while adjusting b for offset changes in a/ this deletes a and b and returns the resultant list. */ static struct flist *combine(struct flist *a, struct flist *b) { struct flist *c = NULL; struct frag *bh, *ct; int offset = 0, post; if (a && b) c = lalloc((lsize(a) + lsize(b)) * 2); if (c) { for (bh = b->head; bh != b->tail; bh++) { /* save old hunks */ offset = gather(c, a, bh->start, offset); /* discard replaced hunks */ post = discard(a, bh->end, offset); /* insert new hunk */ ct = c->tail; ct->start = bh->start - offset; ct->end = bh->end - post; ct->len = bh->len; ct->data = bh->data; c->tail++; offset = post; } /* hold on to tail from a */ memcpy(c->tail, a->head, sizeof(struct frag) * lsize(a)); c->tail += lsize(a); } lfree(a); lfree(b); return c; }
// Compute the max relative difference between two vectors double calcMaxRelDiff(const vector<cx_double>& v1, const vector<cx_double>& v2) { if(lsize(v1)!=lsize(v2)) NTL::Error("Vector sizes differ.\nFAILED\n"); // Compute the largest-magnitude value in the vector double maxAbs = 0.0; for (auto& x : v1) { if (std::abs(x) > maxAbs) maxAbs = std::abs(x); } if (maxAbs<1e-10) maxAbs = 1e-10; double maxDiff = 0.0; for (long i=0; i<lsize(v1); i++) { double relDiff = std::abs(v1[i]-v2[i]) / maxAbs; if (relDiff > maxDiff) maxDiff = relDiff; } return maxDiff; }
// For an n-size array, compute the 2^n products // products[j] = \prod_{i s.t. j_i=1} array[i] // \times \prod_{i s.t. j_i=0}(a-array[i]) void computeAllProducts(/*Output*/CtPtrs& products, /*Index*/const CtPtrs& array, std::vector<zzX>* unpackSlotEncoding) { FHE_TIMER_START; long nBits = array.size(); if (lsize(products)>0) { long nBits2 = NTL::NumBits(lsize(products)-1); // ceil(log_2(size)) if (nBits>nBits2) nBits=nBits2; // ignore extra bits in 'array' } if (nBits<1) return; // do nothing assert(nBits <= 16); // Output cannot be bigger than 2^16 if (lsize(products)==0) // try to set the output size products.resize(1L << nBits, &array); for (long i=0; i<lsize(products); i++) products[i]->clear(); // Check that we have enough levels, try to bootstrap otherwise assert(array.ptr2nonNull() != nullptr); long bpl = array.ptr2nonNull()->getContext().BPL(); if (findMinBitCapacity(array) < (NTL::NumBits(nBits)+1)*bpl) { const Ctxt* ct = array.ptr2nonNull(); // find some non-null Ctxt assert(unpackSlotEncoding!=nullptr); assert(ct!=nullptr); assert(ct->getPubKey().isBootstrappable()); packedRecrypt(array, *unpackSlotEncoding, *(ct->getContext().ea), /*belowLevel=*/nBits +3); } if (findMinBitCapacity(array) < (NTL::NumBits(nBits)+1)*bpl) throw std::logic_error("not enough levels for table lookup"); // Call the recursive function that copmutes the products recursiveProducts(products, CtPtrs_slice(array,0,nBits)); }
void applyLinPolyLL(Ctxt& ctxt, const vector<P>& encodedC, long d) { assert(d == lsize(encodedC)); ctxt.cleanUp(); // not sure, but this may be a good idea Ctxt tmp(ctxt); ctxt.multByConstant(encodedC[0]); for (long j = 1; j < d; j++) { Ctxt tmp1(tmp); tmp1.frobeniusAutomorph(j); tmp1.multByConstant(encodedC[j]); ctxt += tmp1; } }
void basicString::findLongestSpecificWord(const vector<string>& text,const string& notChar) { auto iter = std::max_element(text.begin(), text.end(), [&](const string& lhs, const string& rhs) ->bool { string::size_type lsize(0), rsize(0); if (lhs.find_first_of(notChar) == string::npos) lsize = lhs.size(); if (rhs.find_first_of(notChar) == string::npos) rsize = rhs.size(); return lsize < rsize; }); if (iter != text.end()) std::cout << "Longest word without specific character is :" << *iter << std::endl; else std::cout << "input text is empty" << std::endl; }
// Returns in gens a generating set for Zm* /<p>, and in ords the // order of these generators. Return value is the order of p in Zm*. long findGenerators(vector<long>& gens, vector<long>& ords, long m, long p) { gens.clear(); ords.clear(); // Compute the generators for (Z/mZ)^* vector<long> classes(m); vector<long> orders(m); for (long i=0; i<m; i++) { // initially each element in its own class if (GCD(i,m)!=1) classes[i] = 0; // i is not in (Z/mZ)^* else classes[i] = i; } // Start building a representation of (Z/mZ)^*, first use the generator p conjClasses(classes,p % m,m); // merge classes that have a factor of p // The order of p is the size of the equivalence class of 1 #if 0 long ordP = std::count(classes.begin(), classes.end(), 1); // count(from,to,val) returns # of elements in (from,to) with value=val #else long ordP = 0; for (long i = 0; i < lsize(classes); i++) if (classes[i] == 1) ordP++; #endif // Compute orders in (Z/mZ)^*/<p> while comparing to (Z/mZ)^* while (true) { compOrder(orders,classes,true,m); // if the orders of i in Zm* /<p> and Zm* are not the same, then // order[i] contains the order in Zm* /<p> with negative sign long idx = argmax(orders, >AbsVal); // find the element with largest order long largest = orders[idx]; if (abs(largest) == 1) break; // Trivial group, we are done // store generator with same order as in (Z/mZ)^* gens.push_back(idx); ords.push_back(largest); conjClasses(classes,idx,m); // merge classes that have a factor of idx } return ordP; }
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; }
// mod-switch up to add the primes in s \setminus primeSet, after this call we // have s<=primeSet. s must contain either all special primes or none of them. void Ctxt::modUpToSet(const IndexSet &s) { // FHE_TIMER_START; IndexSet setDiff = s/primeSet; // set minus (primes in s but not in primeSet) if (empty(setDiff)) return; // nothing to do, no primes are added // scale up all the parts to use also the primes in setDiff double f = 0.0; for (long i=0; i<lsize(parts); i++) { // addPrimesAndScale returns the logarithm of the product of added primes, // all calls should return the same value = log(prod. of primes in setDiff) f = parts[i].addPrimesAndScale(setDiff); } // The variance estimate grows by a factor of exp(f)^2 = exp(2f) noiseVar *= xexp(2*f); primeSet.insert(setDiff); // add setDiff to primeSet assert(verifyPrimeSet()); // sanity-check: ensure primeSet is still valid // FHE_TIMER_STOP; }
// A recursive function to compute, for an n-size array, the 2^n products // products[j] = \prod_{i s.t. j_i=1} array[i] // \times \prod_{i s.t. j_i=0}(a-array[i]) // It is assume that 'products' size <= 2^n, else only 1st 2^n entries are set static void recursiveProducts(const CtPtrs& products, const CtPtrs_slice& array) { long nBits = lsize(array); long N = lsize(products); if (nBits==0 || N==0) return; // nothing to do if (N > (1L << nBits)) N = (1L << nBits); else if (N < (1L << (nBits-1))) nBits = NTL::NumBits(N-1); // Ensure nBits <= ceil(log2(N)) if (N<=2) { // edge condition *products[0] = *array[0]; products[0]->negate(); products[0]->addConstant(ZZ(1)); // out[0] = 1-in if (N>1) *products[1] = *array[0]; // out[1] = in } // optimization for n=2: a single multiplication instead of 4 else if (N<=4) { *products[0] = *array[1]; // x1 products[0]->multiplyBy(*array[0]);// x1 x0 *products[1] = *array[0]; // x0 *products[1] -= *products[0]; // x0 - x1 x0 = (1-x1)x0 *products[2] = *array[1]; // x1 *products[2] -= *products[0]; // x1 - x1 x0 = x1(1-x0) if (N>3) *products[3] = *products[0]; // x1 x0 products[0]->addConstant(ZZ(1)); // 1 +x1 x0 *products[0] -= *array[1]; // 1 +x1 x0 -x1 *products[0] -= *array[0] ; // 1 +x1 x0 -x1 -x0 = (1-x1)(1-x0) } else { // split the array into two parts; // first part is highest pow(2) < n, second part is what is left long n1 = 1L << (NTL::NumBits(nBits)-1); // largest power of two <= n if (nBits<=n1) n1 = n1/2; // largest power of two < n long k = 1L << n1; // size of first part long l = 1L << (nBits-n1); // size of second part const Ctxt* ct = array.ptr2nonNull(); // find some non-null Ctxt std::vector<Ctxt> products1(k, Ctxt(ZeroCtxtLike, *ct)); std::vector<Ctxt> products2(l, Ctxt(ZeroCtxtLike, *ct)); // compute first part of the array recursiveProducts(CtPtrs_vectorCt(products1), CtPtrs_slice(array,0, n1)); // recursive call on second part of array recursiveProducts(CtPtrs_vectorCt(products2), CtPtrs_slice(array,n1,nBits-n1)); // multiplication to get all subset products NTL_EXEC_RANGE(lsize(products), first, last) for(long ii=first; ii<last; ii++) { long j = ii / k; long i = ii - j*k; *products[ii] = products1[i]; products[ii]->multiplyBy(products2[j]); } NTL_EXEC_RANGE_END } }
int main(int argc, char *argv[]) { ArgMapping amap; amap.arg("noPrint", noPrint, "suppress printouts"); long m=16; amap.arg("m", m, "cyclotomic index"); amap.note("e.g., m=1024, m=2047"); long r=8; amap.arg("r", r, "bit of precision"); amap.parse(argc, argv); if (!noPrint) { vector<long> f; factorize(f,m); cout << "r="<<r<<", factoring "<<m<<" gives ["; for (unsigned long i=0; i<f.size(); i++) cout << f[i] << " "; cout << "]\n"; } FHEcontext context(m, /*p=*/-1, r); buildModChain(context, 5, 2); const EncryptedArrayCx& ea = context.ea->getCx(); if (!noPrint) ea.getPAlgebra().printout(); #ifdef DEBUG_PRINTOUT vector<cx_double> vc1; ea.random(vc1); cout << "random complex vc1="; printVec(cout,vc1,8)<<endl; vector<double> vd; ea.random(vd); cout << "random real vd="; printVec(cout,vd,8)<<endl; #endif vector<double> vl; ea.random(vl); vl[1] = -1; // ensure that this is not the zero vector #ifdef DEBUG_PRINTOUT cout << "random int v="; printVec(cout,vl,8)<<endl; #endif zzX poly; double factor = ea.encode(poly, vl, 1.0); if (!noPrint) { ZZX poly2; convert(poly2, poly); cout << " encoded into a degree-"<<NTL::deg(poly2)<<" polynomial\n"; } vector<double> vd2; ea.decode(vd2, poly, factor); #ifdef DEBUG_PRINTOUT cout << " decoded into vd2="; printVec(cout,vd2,8)<<endl; #endif assert(lsize(vl)==lsize(vd2)); double maxDiff = 0.0; for (long i=0; i<lsize(vl); i++) { double diffAbs = std::abs(vl[i]-vd2[i]); if (diffAbs > maxDiff) maxDiff = diffAbs; } cout << ((maxDiff>0.1)? "BAD?" : "GOOD?") << " max |v-vd2|_{infty}="<<maxDiff << endl; return 0; }
void TestIt(long p, long r, long c, long _k, long w, long L, Vec<long>& mvec, Vec<long>& gens, Vec<long>& ords, long useCache) { if (lsize(mvec)<1) { // use default values mvec.SetLength(3); gens.SetLength(3); ords.SetLength(3); mvec[0] = 7; mvec[1] = 3; mvec[2] = 221; gens[0] = 3979; gens[1] = 3095; gens[2] = 3760; ords[0] = 6; ords[1] = 2; ords[2] = -8; } if (!noPrint) cout << "*** TestIt" << (dry? " (dry run):" : ":") << " p=" << p << ", r=" << r << ", c=" << c << ", k=" << _k << ", w=" << w << ", L=" << L << ", mvec=" << mvec << ", " << ", useCache = " << useCache << endl; setTimersOn(); setDryRun(false); // Need to get a "real context" to test ThinEvalMap // mvec is supposed to include the prime-power factorization of m long nfactors = mvec.length(); for (long i = 0; i < nfactors; i++) for (long j = i+1; j < nfactors; j++) assert(GCD(mvec[i], mvec[j]) == 1); // multiply all the prime powers to get m itself long m = computeProd(mvec); assert(GCD(p, m) == 1); // build a context with these generators and orders vector<long> gens1, ords1; convert(gens1, gens); convert(ords1, ords); FHEcontext context(m, p, r, gens1, ords1); buildModChain(context, L, c); if (!noPrint) { context.zMStar.printout(); // print structure of Zm* /(p) to cout cout << endl; } long d = context.zMStar.getOrdP(); long phim = context.zMStar.getPhiM(); long nslots = phim/d; setDryRun(dry); // Now we can set the dry-run flag if desired FHESecKey secretKey(context); const FHEPubKey& publicKey = secretKey; secretKey.GenSecKey(w); // A Hamming-weight-w secret key addSome1DMatrices(secretKey); // compute key-switching matrices that we need addFrbMatrices(secretKey); // compute key-switching matrices that we need // GG defines the plaintext space Z_p[X]/GG(X) ZZX GG; GG = context.alMod.getFactorsOverZZ()[0]; EncryptedArray ea(context, GG); zz_p::init(context.alMod.getPPowR()); Vec<zz_p> val0(INIT_SIZE, nslots); for (auto& x: val0) random(x); vector<ZZX> val1; val1.resize(nslots); for (long i = 0; i < nslots; i++) { val1[i] = conv<ZZX>(conv<ZZ>(rep(val0[i]))); } Ctxt ctxt(publicKey); ea.encrypt(ctxt, publicKey, val1); resetAllTimers(); FHE_NTIMER_START(ALL); // Compute homomorphically the transformation that takes the // coefficients packed in the slots and produces the polynomial // corresponding to cube if (!noPrint) CheckCtxt(ctxt, "init"); if (!noPrint) cout << "build ThinEvalMap\n"; ThinEvalMap map(ea, /*minimal=*/false, mvec, /*invert=*/false, /*build_cache=*/false); // compute the transformation to apply if (!noPrint) cout << "apply ThinEvalMap\n"; if (useCache) map.upgrade(); map.apply(ctxt); // apply the transformation to ctxt if (!noPrint) CheckCtxt(ctxt, "ThinEvalMap"); if (!noPrint) cout << "check results\n"; if (!noPrint) cout << "build ThinEvalMap\n"; ThinEvalMap imap(ea, /*minimal=*/false, mvec, /*invert=*/true, /*build_cache=*/false); // compute the transformation to apply if (!noPrint) cout << "apply ThinEvalMap\n"; if (useCache) imap.upgrade(); imap.apply(ctxt); // apply the transformation to ctxt if (!noPrint) { CheckCtxt(ctxt, "ThinEvalMap"); cout << "check results\n"; } #if 1 /* create dirty version of ctxt */ Vec<zz_pX> dirty_val0; dirty_val0.SetLength(nslots); for (long i = 0; i < nslots; i++) { random(dirty_val0[i], d); SetCoeff(dirty_val0[i], 0, val0[i]); } vector<ZZX> dirty_val1; dirty_val1.resize(nslots); for (long i = 0; i < nslots; i++) { dirty_val1[i] = conv<ZZX>(dirty_val0[i]); } Ctxt dirty_ctxt(publicKey); ea.encrypt(dirty_ctxt, publicKey, dirty_val1); EvalMap dirty_map(ea, /*minimal=*/false, mvec, /*invert=*/false, /*build_cache=*/false); dirty_map.apply(dirty_ctxt); imap.apply(dirty_ctxt); #endif vector<ZZX> val2; ea.decrypt(ctxt, secretKey, val2); if (val1 == val2) cout << "ThinEvalMap: GOOD\n"; else cout << "ThinEvalMap: BAD\n"; #if 1 vector<ZZX> dirty_val2; ea.decrypt(dirty_ctxt, secretKey, dirty_val2); if (val1 == dirty_val2) cout << "ThinEvalMap: GOOD\n"; else cout << "ThinEvalMap: BAD\n"; #endif FHE_NTIMER_STOP(ALL); if (!noPrint) { cout << "\n*********\n"; printAllTimers(); cout << endl; } }
void testBasicArith(const FHEPubKey& publicKey, const FHESecKey& secretKey, const EncryptedArrayCx& ea, double epsilon) { if (verbose) cout << "Test Arithmetic "; // Test objects Ctxt c1(publicKey), c2(publicKey), c3(publicKey); vector<cx_double> vd; vector<cx_double> vd1, vd2, vd3; ea.random(vd1); ea.random(vd2); // test encoding of shorter vectors vd1.resize(vd1.size()-2); ea.encrypt(c1, publicKey, vd1, /*size=*/1.0); vd1.resize(vd1.size()+2, 0.0); ea.encrypt(c2, publicKey, vd2, /*size=*/1.0); // Test - Multiplication c1 *= c2; for (long i=0; i<lsize(vd1); i++) vd1[i] *= vd2[i]; ZZX poly; ea.random(vd3); ea.encode(poly, vd3, /*size=*/1.0); c1.addConstant(poly); // vd1*vd2 + vd3 for (long i=0; i<lsize(vd1); i++) vd1[i] += vd3[i]; // Test encoding, encryption of a single number double xx = NTL::RandomLen_long(16)/double(1L<<16); // random in [0,1] ea.encryptOneNum(c2, publicKey, xx); c1 += c2; for (auto& x : vd1) x += xx; // Test - Multiply by a mask vector<long> mask(lsize(vd1), 1); for (long i=0; i*(i+1)<lsize(mask); i++) { mask[i*i] = 0; mask[i*(i+1)] = -1; } ea.encode(poly,mask, /*size=*/1.0); c1.multByConstant(poly); // mask*(vd1*vd2 + vd3) for (long i=0; i<lsize(vd1); i++) vd1[i] *= mask[i]; // Test - Addition ea.random(vd3); ea.encrypt(c3, publicKey, vd3, /*size=*/1.0); c1 += c3; for (long i=0; i<lsize(vd1); i++) vd1[i] += vd3[i]; c1.negate(); c1.addConstant(to_ZZ(1)); for (long i=0; i<lsize(vd1); i++) vd1[i] = 1.0 - vd1[i]; // Diff between approxNums HE scheme and plaintext floating ea.decrypt(c1, secretKey, vd); #ifdef DEBUG_PRINTOUT printVec(cout<<"res=", vd, 10)<<endl; printVec(cout<<"vec=", vd1, 10)<<endl; #endif if (verbose) cout << "(max |res-vec|_{infty}="<< calcMaxDiff(vd, vd1) << "): "; if (cx_equals(vd, vd1, conv<double>(epsilon*c1.getPtxtMag()))) cout << "GOOD\n"; else { cout << "BAD:\n"; std::cout << " max(vd)="<<largestCoeff(vd) << ", max(vd1)="<<largestCoeff(vd1) << ", maxDiff="<<calcMaxDiff(vd,vd1) << endl<<endl; } }
int main(int argc, char *argv[]) { argmap_t argmap; argmap["m"] = "0"; argmap["p"] = "2"; argmap["r"] = "1"; if (!parseArgs(argc, argv, argmap)) usage(); unsigned long m = atoi(argmap["m"]); if (!m) usage(); unsigned long p = atoi(argmap["p"]); unsigned long r = atoi(argmap["r"]); cout << "m = " << m << ", p = " << p << ", r = " << r << endl; vector<long> f; factorize(f,m); cout << "factoring "<<m<<" gives ["; for (unsigned long i=0; i<f.size(); i++) cout << f[i] << " "; cout << "]\n"; PAlgebra al(m, p); al.printout(); cout << "\n"; PAlgebraMod almod(al, r); almod.genMaskTable(); FHEcontext context(m, p, r); buildModChain(context, 5, 2); stringstream s1; writeContextBase(s1, context); s1 << context; string s2 = s1.str(); cout << s2 << endl; stringstream s3(s2); unsigned long m1, p1, r1; readContextBase(s3, m1, p1, r1); FHEcontext c1(m1, p1, r1); s3 >> c1; if (context == c1) cout << "equal\n"; else cout << "not equal\n"; return 0; #if 0 PAlgebraModTwo al2(al); PAlgebraMod2r al2r(r,al2); if (false) { long nslots = al.NSlots(); long ngens = al.numOfGens(); for (long i = 0; i < nslots; i++) { const int* v = al.dLog(al.ith_rep(i)); cout << i << " "; for (long j = 0; j < ngens; j++) cout << v[j] << " "; cout << "\n"; } return 0; } // GF2X::HexOutput = 1; // compact hexadecimal printout // cout << "Phi_m(X) = " << al.PhimX() << endl; // vec_GF2X Fs = al2.Factors(); // cout << "Factors = " << Fs << endl; // GF2X Q = Fs[0]; // for (long i=1; i<Fs.length(); i++) Q *= Fs[i]; // cout << "mult of factors = " << Q << endl; GF2X G; // G is the AES polynomial, G(X)= X^8 +X^4 +X^3 +X +1 SetCoeff(G,8); SetCoeff(G,4); SetCoeff(G,3); SetCoeff(G,1); SetCoeff(G,0); // GF2X G; SetCoeff(G,4); SetCoeff(G,1); SetCoeff(G,0); // X^4 +X +1 // cout << "G = " << G << ", deg(G)=" << deg(G) << endl; vector<GF2X> maps; al2.mapToSlots(maps, G); // cout << "maps = ["; // for (unsigned long i=0; i<maps.size(); i++) // cout << maps[i] << " "; // cout << "]\n"; GF2X X; SetX(X); // The polynomial X GF2X ptxt; // plaintext has X in all the slots cout << "embedding X in plaintext slots... "; al2.embedInAllSlots(ptxt, X, maps); cout << "done\n"; // cout << "ptxt = " << ptxt << endl; // Debugging printout: p modulo all the factors // vector<GF2X> crt; // al2.CRT_decompose(crt,ptxt); // cout << "ptxt mod factors = ["; // for (unsigned long i=0; i<crt.size(); i++) cout << crt[i] << " "; // cout << "]\n"; // Decode the plaintext back to a vector of elements, // and check that they are all equal to X vector<GF2X> alphas; cout << "decoding plaintext slots... "; al2.decodePlaintext(alphas, ptxt, G, maps); cout << "done\n"; // cout << "alphas = ["; // for (unsigned long i=0; i<alphas.size(); i++) // cout << alphas[i] << " "; // cout << "]\n"; cout << "comparing " << alphas.size() << " plaintext slots to X... "; for (unsigned long i=0; i<alphas.size(); i++) if (alphas[i] != X) { cout << "\n alphas["<<i<<"] = "<<alphas[i]<<" != X\n\n"; exit(0); } cout << "all tests completed successfully\n\n"; // encode and decode random polynomials for (unsigned long i=0; i<alphas.size(); i++) random(alphas[i], 8); // random degree-7 polynomial mod 2 cout << "embedding random GF(2^8) elements in plaintext slots... "; al2.embedInSlots(ptxt, alphas, maps); cout << "done\n"; // Compute p^2 mod Phi_m(X) and also p(X^2) mod Phi_m(X) and // verify that they both decode to a vector of X^2 in all the slots cout << "squaring and decoding plaintext slots... "; X *= X; // X^2 // GF2X ptxt2; // SqrMod(ptxt2,ptxt,al2.PhimXMod()); // ptxt2 = ptxt^2 mod Phi_m(X) CompMod(ptxt, ptxt, X, al2.PhimXMod()); // ptxt = ptxt(X^2) mod Phi_m(X) // // sanity chack: these should be the same mod 2 (but not mod 2^r) // if (ptxt != ptxt2) cout << "ptxt^2 != ptxt(X^2) mod Phi_m(X)\n"; vector<GF2X> betas; al2.decodePlaintext(betas, ptxt, G, maps); cout << "done\n"; if (alphas.size() != betas.size()) Error("wrong number of slots decoded"); cout << "comparing decoded plaintext slots... "; for (unsigned long i=0; i<alphas.size(); i++) { SqrMod(alphas[i],alphas[i],G); // should get alpha[i]^2 mod G if (alphas[i] != betas[i]) { cout << "\n alphas["<<i<<"] = "<<alphas[i] <<" != " << "betas["<<i<<"] = " << betas[i] << "\n\n"; exit(0); } } cout << "all tests completed successfully\n\n"; // return 0; al2r.restoreContext(); vector<zz_pX> maps1; zz_pX X1; SetX(X1); cerr << "HERE1\n"; al2r.mapToSlots(maps1, X1); cerr << "HERE1a\n"; vector<zz_pX> alphas1; alphas1.resize(maps.size()); for (long i = 0; i < lsize(alphas1); i++) random(alphas1[i], 1); zz_pX ptxt1; cerr << "HERE2\n"; al2r.embedInSlots(ptxt1, alphas1, maps1); cerr << "HERE3\n"; vector<zz_pX> betas1; al2r.decodePlaintext(betas1, ptxt1, X1, maps1); assert(alphas1 == betas1); return 0; #endif }
/*Edit file function-------------------------------------------------*/ void Editfile(list_ref list) { char stdinline[4096]; int stdincount; for (stdincount = 0;; ++stdincount) { //print program basename printf("%s: ", Exec_Name); //change this before submitting //get string from file char *linepos = fgets(stdinline, sizeof (stdinline), stdin); //if EOF break and put EOF key if (linepos == NULL) { printf("^D\n"); break; } //chomp newline char *nlinepos = strchr(stdinline, '\n'); if (nlinepos != NULL) *nlinepos = '\0'; //echo print to terminal if (want_echo) printf("%s", stdinline); //check for a line of all spaces bool space = SpaceCheck(stdinline); //check for badline //if a line of all spaces then go to next iteration if (space) { stdincount--; continue; //if not newline terminated or empty string then badline } else if (linepos == NULL || stdinline[0] == '\0') { Badline(Exec_Name, stdinline); //goodline so check for commands and lines } else { char *inputline; //used for commands that require an argument switch (stdinline[0]) { case '#': continue; break; case '$': Com$(list); break; case '*': viewlist(list); break; case '.': ComDot(list); break; case '0': Com0(list); break; case '<': ComL(list); break; case '>': ComR(list); break; case '@': debugdump_list(list); break; case 'a': ComA(list, inputline, stdinline); break; case 'd': if (lsize(list) > 0) delete_list(list); break; case 'i': ComI(list, inputline, stdinline); break; case 'r': break; case 'w': break; default: Badline(Exec_Name, stdinline); break; } } } }