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; }
// The function compOrder(orders, classes,flag,m) computes the order of elements // of the quotient group, relative to current equivalent classes. If flag==1 // then also check if the order is the same as in (Z/mZ)^* and store the order // with negative sign if not. static void compOrder(vector<long>& orders, vector<long>& classes, bool flag, long m) { orders[0] = 0; orders[1] = 1; for (long i=2; i<m; i++) { if (classes[i] <= 1) { // ignore i not in Z_m^* and order-0 elements orders[i] = (classes[i]==1)? 1 : 0; continue; } // If not comparing order with (Z/mZ)^*, only compute the order of pivots if (!flag && classes[i]<i){ // not a pivot orders[i] = orders[classes[i]]; continue; } // For an element i>1, the order is at least 2 long j = MulMod(i, i, m); long ord = 2; while (classes[j] != 1) { j = MulMod(j, i, m); // next element in <i> ord++; // count how many steps until we reach 1 } // When we get here we have classes[j]==1, so if j!=1 it means that the // order of i in the quotient group is smaller than its order in the // entire group Z_m^*. If the flag is set then we store orders[i] = -ord. if (flag && j != 1) ord = -ord; // order in Z_m^* is larger than ord orders[i] = ord; } }
static void conjClasses(vector<unsigned long>& classes, unsigned long g, unsigned long m) { for (unsigned long i=0; i<m; i++) { if (classes[i]==0) continue; // i \notin (Z/mZ)^* if (classes[i]<i) { // i is not a pivot, updated its pivot classes[i] = classes[classes[i]]; continue; } // If i is a pivot, update other pivots to point to it unsigned long ii = i; unsigned long gg = g; unsigned long jj = MulMod(ii, gg, m); while (classes[jj] != i) { classes[classes[jj]]= i; // Merge the equivalence classes of j and i // Note: if classes[j]!=j then classes[j] will be updated later, // when we get to i=j and use the code for "i not pivot". jj = MulMod(jj, g, m); } } }
void PaillierParty::secretShare() { ZZ beta = getRandomInNStar(m_n); std::vector<ZZ> coefficients; coefficients.push_back(MulMod(beta,m_m,m_n*m_m)); for (uint32_t i=1; i < m_numOfParties; i++) { coefficients.push_back(getRandomInNStar(m_n*m_m)); } ZZ_p::init(m_n*m_m); ZZ_pX polynomial; for (uint32_t i=0; i < m_numOfParties; i++) { SetCoeff(polynomial, i, conv<ZZ_p>(coefficients[i])); } for (auto &party : m_parties) { ZZ result = rep(eval(polynomial,ZZ_p(party.first))); sendZZTo(result,party.second); } ZZ_p s_i = eval(polynomial,ZZ_p(m_partyId)); for (auto &party : m_parties) { ZZ value; receiveZZFrom(value,party.second); ZZ_p coefficient = conv<ZZ_p>(value); s_i = s_i + coefficient; } m_share = rep(s_i); m_pubKey = MulMod(MulMod(m_a,beta,m_n),m_m,m_n); }
// Sets the prime defining the field for the curve and stores certain values void Icart::setPrime(ZZ* p) { //ZZ_p::init(*p); // Icart hash function uses 1/3 root, which is equivalent to (2p-1)/3 exp = MulMod( SubMod( MulMod(ZZ(2), *p, *p), ZZ(1), *p), InvMod(ZZ(3),*p), *p); // Store inverse values to be used later ts = inv(ZZ_p(27)); th = inv(ZZ_p(3)); }
/* * Must guarantee c+c DO NOT OVERFLOW!!!(both a, b, c are INTEGERS) * $a or $b may be negative, however $c must be positive */ template<class T> T PowMod( T a, T b, T c) { T r=Mod((T)1,c); a=Mod(a,c); while(b != 0) { if(b & 1) r=MulMod(r, a, c); a = MulMod( a, a, c); b >>= 1; } return r; }
void Shares::addShares(map<string, ZZ> newShares){ for(auto i : newShares){ ZZ tmp = MulMod(i.second, shares[i.first], groupModulus); shares[i.first] = tmp; } nbrShares++; }
void InnerProduct(zz_p& x, const vec_zz_p& a, const vec_zz_p& b, long offset) { if (offset < 0) LogicError("InnerProduct: negative offset"); if (NTL_OVERFLOW(offset, 1, 0)) ResourceError("InnerProduct: offset too big"); long n = min(a.length(), b.length()+offset); long i; long accum, t; long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); const zz_p *ap = a.elts(); const zz_p *bp = b.elts(); accum = 0; for (i = offset; i < n; i++) { t = MulMod(rep(ap[i]), rep(bp[i-offset]), p, pinv); accum = AddMod(accum, t, p); } x.LoopHole() = accum; }
// Apply F(X)->F(X^k) followed by re-liearization. The automorphism is possibly // evaluated via a sequence of steps, to ensure that we can re-linearize the // result of every step. void Ctxt::smartAutomorph(long k) { FHE_TIMER_START; // Special case: if *this is empty then do nothing if (this->isEmpty()) return; long m = context.zMStar.getM(); k = mcMod(k, m); // Sanity check: verify that k \in Zm* assert (context.zMStar.inZmStar(k)); long keyID=getKeyID(); if (!inCanonicalForm(keyID)) { // Re-linearize the input, if needed reLinearize(keyID); assert (inCanonicalForm(keyID)); // ensure that re-linearization succeeded } assert (pubKey.isReachable(k,keyID)); // reachable from 1 while (k != 1) { const KeySwitch& matrix = pubKey.getNextKSWmatrix(k,keyID); long amt = matrix.fromKey.getPowerOfX(); automorph(amt); reLinearize(keyID); k = MulMod(k, InvMod(amt,m), m); } FHE_TIMER_STOP; }
void build(zz_pXArgument& A, const zz_pX& h, const zz_pXModulus& F, long m) { if (m <= 0 || deg(h) >= F.n) Error("build: bad args"); if (m > F.n) m = F.n; long i; if (zz_pXArgBound > 0) { double sz = 1; sz = sz*F.n; sz = sz+6; sz = sz*(sizeof (long)); sz = sz/1024; m = min(m, long(zz_pXArgBound/sz)); m = max(m, 1); } zz_pXMultiplier M; build(M, h, F); A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], M, F); }
YASHE YASHE::readFromFile(std::string filename) { YASHE output; std::ifstream ifs(filename); boost::archive::text_iarchive ia(ifs); ia >> output; NTL::ZZ_p::init(output.cModulus); output.cycloMod = NTL::ZZ_pXModulus(NTL::conv<NTL::ZZ_pX>(output.cycloModX)); { NTL::ZZ_pPush push(output.bigModulus); // switch to multiplication modulus // make another modulus for fast multiplication output.bigCycloMod = NTL::ZZ_pXModulus(NTL::conv<NTL::ZZ_pX>(output.cycloModX)); } { NTL::ZZ_pPush push(output.bigPModulus); // switch to plain text modulus // Factor the cyclotomic polynomial modulo t // for batch encryption NTL::ZZ_pXModulus pModulusX; NTL::build(pModulusX, NTL::conv<NTL::ZZ_pX>(output.cycloModX)); output.crtElements.resize(output.factors.size()); NTL::ZZ_pX fInv, fInvInv; for (long i = 0; i < output.factors.size(); i++) { div(fInv, NTL::conv<NTL::ZZ_pX>(output.cycloModX), output.factors[i]); rem(fInvInv, fInv, output.factors[i]); InvMod(fInvInv, fInvInv, output.factors[i]); output.crtElements[i] = MulMod(fInv, fInvInv, pModulusX); } } return output; }
void MinPolyMod(zz_pX& hh, const zz_pX& g, const zz_pXModulus& F, long m) { zz_pX h, h1; long n = F.n; if (m < 1 || m > n) Error("MinPoly: bad args"); /* probabilistically compute min-poly */ ProbMinPolyMod(h, g, F, m); if (deg(h) == m) { hh = h; return; } CompMod(h1, h, g, F); if (IsZero(h1)) { hh = h; return; } /* not completely successful...must iterate */ long i; zz_pX h2, h3; zz_pXMultiplier H1; vec_zz_p R(INIT_SIZE, n); for (;;) { R.SetLength(n); for (i = 0; i < n; i++) random(R[i]); build(H1, h1, F); UpdateMap(R, R, H1, F); DoMinPolyMod(h2, g, F, m-deg(h), R); mul(h, h, h2); if (deg(h) == m) { hh = h; return; } CompMod(h3, h2, g, F); MulMod(h1, h3, H1, F); if (IsZero(h1)) { hh = h; return; } } }
static void BuildMatrix(vec_GF2XVec& M, long n, const GF2EX& g, const GF2EXModulus& F, long verbose) { long i, j, m; GF2EX h; M.SetLength(n); for (i = 0; i < n; i++) M[i].SetSize(n, 2*GF2E::WordLength()); set(h); for (j = 0; j < n; j++) { if (verbose && j % 10 == 0) cerr << "+"; m = deg(h); for (i = 0; i < n; i++) { if (i <= m) M[i][j] = rep(h.rep[i]); else clear(M[i][j]); } if (j < n-1) MulMod(h, h, g, F); } for (i = 0; i < n; i++) add(M[i][i], M[i][i], 1); }
// Compute the mapping between linear array and a hypercube corresponding /// to a single generator tree void ComputeOneGenMapping(Permut& genMap, const OneGeneratorTree& T) { Vec<long> dims(INIT_SIZE, T.getNleaves()); Vec<long> coefs(INIT_SIZE,T.getNleaves()); for (long i=T.getNleaves()-1, leaf=T.lastLeaf(); i>=0; i--, leaf=T.prevLeaf(leaf)) { dims[i] = T[leaf].getData().size; coefs[i] = T[leaf].getData().e; } // A representation of an integer with digits from dims Vec<long> rep(INIT_SIZE, T.getNleaves()); for (long i=0; i<rep.length(); i++) rep[i]=0; // initialize to zero // initialize to all zero long sz = T[0].getData().size; genMap.SetLength(sz); for (long i=0; i<sz; i++) genMap[i]=0; // compute the permutation for (long i=1; i<sz; i++) { addOne(rep, dims); // representation of i in base dims for (long j=0; j<coefs.length(); j++) { long tmp = MulMod(rep[j], coefs[j], sz); genMap[i] = AddMod(genMap[i], tmp, sz); } } }
void build(ZZ_pXArgument& A, const ZZ_pX& h, const ZZ_pXModulus& F, long m) { if (m <= 0 || deg(h) >= F.n) LogicError("build: bad args"); if (m > F.n) m = F.n; long i; if (ZZ_pXArgBound > 0) { double sz = ZZ_p::storage(); sz = sz*F.n; sz = sz + NTL_VECTOR_HEADER_SIZE + sizeof(vec_ZZ_p); sz = sz/1024; m = min(m, long(ZZ_pXArgBound/sz)); m = max(m, 1); } ZZ_pXMultiplier M; build(M, h, F); A.H.SetLength(m+1); set(A.H[0]); A.H[1] = h; for (i = 2; i <= m; i++) MulMod(A.H[i], A.H[i-1], M, F); }
void CompMod(ZZ_pX& x, const ZZ_pX& g, const ZZ_pXArgument& A, const ZZ_pXModulus& F) { if (deg(g) <= 0) { x = g; return; } ZZ_pX s, t; ZZVec scratch(F.n, ZZ_p::ExtendedModulusSize()); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; ZZ_pXMultiplier M; build(M, A.H[m], F); InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; }
void CompMod(zz_pX& x, const zz_pX& g, const zz_pXArgument& A, const zz_pXModulus& F) { if (deg(g) <= 0) { x = g; return; } zz_pX s, t; vec_zz_p scratch(INIT_SIZE, F.n); long m = A.H.length() - 1; long l = ((g.rep.length()+m-1)/m) - 1; zz_pXMultiplier M; build(M, A.H[m], F); InnerProduct(t, g.rep, l*m, l*m + m - 1, A.H, F.n, scratch); for (long i = l-1; i >= 0; i--) { InnerProduct(s, g.rep, i*m, i*m + m - 1, A.H, F.n, scratch); MulMod(t, t, M, F); add(t, t, s); } x = t; }
long CRT(vec_ZZ& gg, ZZ& a, const vec_zz_p& G) { long n = gg.length(); if (G.length() != n) Error("CRT: vector length mismatch"); long p = zz_p::modulus(); ZZ new_a; mul(new_a, a, p); long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long p1; p1 = p >> 1; ZZ a1; RightShift(a1, a, 1); long p_odd = (p & 1); long modified = 0; long h; ZZ g; long i; for (i = 0; i < n; i++) { if (!CRTInRange(gg[i], a)) { modified = 1; rem(g, gg[i], a); if (g > a1) sub(g, g, a); } else g = gg[i]; h = rem(g, p); h = SubMod(rep(G[i]), h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!p_odd && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } gg[i] = g; } a = new_a; return modified; }
NTL_START_IMPL long IterIrredTest(const GF2X& f) { long df = deg(f); if (df <= 0) return 0; if (df == 1) return 1; GF2XModulus F; build(F, f); GF2X h; SetX(h); SqrMod(h, h, F); long i, d, limit, limit_sqr; GF2X g, X, t, prod; SetX(X); i = 0; g = h; d = 1; limit = 2; limit_sqr = limit*limit; set(prod); while (2*d <= df) { add(t, g, X); MulMod(prod, prod, t, F); i++; if (i == limit_sqr) { GCD(t, f, prod); if (!IsOne(t)) return 0; set(prod); limit++; limit_sqr = limit*limit; i = 0; } d = d + 1; if (2*d <= deg(f)) { SqrMod(g, g, F); } } if (i > 0) { GCD(t, f, prod); if (!IsOne(t)) return 0; } return 1; }
NTL::ZZ_pX YASHE::keyGen() { /** * The secret key is computed as * * f' <- X_key * f = (t*f' + 1) mod q * secretKey = f * * Secret keys are randomly generated until * an invertible key f^-1 is found */ NTL::ZZ_pX secretKey, secretKeyInv; long inverseStatus; do { secretKey = pModulus * randomKeyPoly() + 1; inverseStatus = InvModStatus(secretKeyInv, secretKey, cycloMod); } while (inverseStatus == 1); /** * The public key is computed by * * g <- X_key * h = (t*g*f^-1) mod q * publicKey = h */ publicKey = MulMod(randomKeyPoly(), secretKeyInv, cycloMod); publicKey *= pModulus; /** * The evaluation key is computed by * * e, s <- X_err * gamma = (powersOfRadix(f) + e + h*s) mod q * evaluationKey = gamma */ std::vector<NTL::ZZ_pX> evalKey; powersOfRadix(evalKey, secretKey); evalKeyMult.resize(decompSize); for (long i = 0; i < decompSize; i++) { evalKey[i] += randomErrPoly(); evalKey[i] += MulMod(publicKey, randomErrPoly(), cycloMod); NTL::build(evalKeyMult[i], evalKey[i], cycloMod); } return secretKey; }
void mul_aux(vec_zz_p& x, const mat_zz_p& A, const vec_zz_p& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) LogicError("matrix mul: dimension mismatch"); x.SetLength(n); zz_p* xp = x.elts(); long p = zz_p::modulus(); mulmod_t pinv = zz_p::ModulusInverse(); long i, k; long acc, tmp; const zz_p* bp = b.elts(); if (n <= 1) { for (i = 0; i < n; i++) { acc = 0; const zz_p* ap = A[i].elts(); for (k = 0; k < l; k++) { tmp = MulMod(rep(ap[k]), rep(bp[k]), p, pinv); acc = AddMod(acc, tmp, p); } xp[i].LoopHole() = acc; } } else { Vec<mulmod_precon_t>::Watcher watch_precon_vec(precon_vec); precon_vec.SetLength(l); mulmod_precon_t *bpinv = precon_vec.elts(); for (k = 0; k < l; k++) bpinv[k] = PrepMulModPrecon(rep(bp[k]), p, pinv); for (i = 0; i < n; i++) { acc = 0; const zz_p* ap = A[i].elts(); for (k = 0; k < l; k++) { tmp = MulModPrecon(rep(ap[k]), rep(bp[k]), p, bpinv[k]); acc = AddMod(acc, tmp, p); } xp[i].LoopHole() = acc; } } }
long FHEPubKey::Encrypt(Ctxt &ctxt, const ZZX& ptxt, long ptxtSpace) const { FHE_TIMER_START; assert(this == &ctxt.pubKey); if (ptxtSpace != pubEncrKey.ptxtSpace) { // plaintext-space mistamtch ptxtSpace = GCD(ptxtSpace, pubEncrKey.ptxtSpace); if (ptxtSpace <= 1) Error("Plaintext-space mismatch on encryption"); } // choose a random small scalar r and a small random error vector e, // then set ctxt = r*pubEncrKey + ptstSpace*e + (ptxt,0) DoubleCRT e(context, context.ctxtPrimes); DoubleCRT r(context, context.ctxtPrimes); r.sampleSmall(); // generate a random encryption of zero from the public encryption key ctxt = pubEncrKey; // already an encryption of zero, just not a random one for (size_t i=0; i<ctxt.parts.size(); i++) { // add noise to all the parts ctxt.parts[i] *= r; e.sampleGaussian(); e *= ptxtSpace; ctxt.parts[i] += e; } // add in the plaintext // FIXME: This relies on the first part to be with respect to 1 if (ptxtSpace==2) ctxt.parts[0] += ptxt; else { // The general case of ptxtSpace>2: for a ciphertext // relative to modulus Q, we add ptxt * Q mod ptxtSpace. long QmodP = rem(context.productOfPrimes(ctxt.primeSet), ptxtSpace); ctxt.parts[0] += MulMod(ptxt,QmodP,ptxtSpace); // MulMod from module NumbTh } // FIXME: the above relies on the first part, ctxt[0], to have handle to 1 // fill in the other ciphertext data members ctxt.ptxtSpace = ptxtSpace; // We have <skey,ctxt>= r*<skey,pkey> +p*(e0+e1*s) +m, where VAR(<skey,pkey>) // is recorded in pubEncrKey.noiseVar, VAR(ei)=sigma^2*phi(m), VAR(s) is // determined by the secret-key Hamming weight (skHwt), and VAR(r)=phi(m)/2. // Hence the total expected size squared is bounded by // E(X^2) <= pubEncrKey.noiseVar*phi(m)/2 // + p^2*sigma^2*phi(m)*(skHwt+1) + p^2 long hwt = skHwts[0]; xdouble phim = to_xdouble(context.zMStar.getPhiM()); xdouble sigma2 = context.stdev * context.stdev; xdouble p2 = to_xdouble(ptxtSpace) * to_xdouble(ptxtSpace); ctxt.noiseVar = pubEncrKey.noiseVar*phim/2 + p2*sigma2*phim*(hwt+1) + p2; FHE_TIMER_STOP; return ptxtSpace; }
void InitFFTPrimeInfo(FFTPrimeInfo& info, long q, long w, long bigtab) { double qinv = 1/((double) q); long mr = CalcMaxRoot(q); info.q = q; info.qinv = qinv; info.zz_p_context = 0; info.RootTable.SetLength(mr+1); info.RootInvTable.SetLength(mr+1); info.TwoInvTable.SetLength(mr+1); info.TwoInvPreconTable.SetLength(mr+1); long *rt = &info.RootTable[0]; long *rit = &info.RootInvTable[0]; long *tit = &info.TwoInvTable[0]; mulmod_precon_t *tipt = &info.TwoInvPreconTable[0]; long j; long t; rt[mr] = w; for (j = mr-1; j >= 0; j--) rt[j] = MulMod(rt[j+1], rt[j+1], q); rit[mr] = InvMod(w, q); for (j = mr-1; j >= 0; j--) rit[j] = MulMod(rit[j+1], rit[j+1], q); t = InvMod(2, q); tit[0] = 1; for (j = 1; j <= mr; j++) tit[j] = MulMod(tit[j-1], t, q); for (j = 0; j <= mr; j++) tipt[j] = PrepMulModPrecon(tit[j], q, qinv); info.bigtab = bigtab; }
ZZ PaillierParty::decrypt(const std::map<uint32_t,ZZ> &partialCiphers, const std::vector<ZZ> &pubKeys) { ZZ sum(0); for (auto &pubKey : pubKeys) { sum = AddMod(sum,pubKey,m_n); } ZZ phi = MulMod(m_a,sum,m_n); ZZ prod(1); for (auto &partialCipher: partialCiphers) { uint32_t partyId = partialCipher.first; prod = MulMod(prod,PowerMod(partialCipher.second, 2*m_lagrangeBasis[partyId],m_field),m_field); } ZZ LResult = L_function(prod); ZZ combinedShare = InvMod(MulMod(4*m_delta*m_delta,phi,m_n),m_n); return MulMod(LResult, combinedShare, m_n); }
unsigned long PAlgebra::exponentiate(const vector<unsigned long>& exps, bool onlySameOrd) const { unsigned long t = 1; unsigned long n = min(exps.size(),gens.size()); for (unsigned long i=0; i<n; i++) { if (onlySameOrd && !SameOrd(i)) continue; unsigned long g = PowerMod(gens[i] ,exps[i], m); t = MulMod(t, g, m); } return t; }
static void ProcessTable(GF2X& f, vec_pair_GF2X_long& factors, const GF2XModulus& F, long limit, const vec_GF2X& tbl, long d, long verbose) { if (limit == 0) return; if (verbose) cerr << "+"; GF2X t1; if (limit == 1) { GCD(t1, f, tbl[0]); if (deg(t1) > 0) { AddFactor(factors, t1, d, verbose); div(f, f, t1); } return; } long i; t1 = tbl[0]; for (i = 1; i < limit; i++) MulMod(t1, t1, tbl[i], F); GCD(t1, f, t1); if (deg(t1) == 0) return; div(f, f, t1); GF2X t2; i = 0; d = d - limit + 1; while (2*d <= deg(t1)) { GCD(t2, tbl[i], t1); if (deg(t2) > 0) { AddFactor(factors, t2, d, verbose); div(t1, t1, t2); } i++; d++; } if (deg(t1) > 0) AddFactor(factors, t1, deg(t1), verbose); }
/** * A message is a polynomial of degree <= d modulo t. * The encryption is calculated as follows: * * c = (floor(q/t) * (m mod t) + e + publicKey*s) mod q * * With s, e <- X_err */ YASHE_CT YASHE::encrypt(long message) { NTL::ZZ_pX output; output.SetLength(maxDegree + 1); output[0] = NTL::ZZ_p(message % pModulus); output *= modulusRatio; output += randomErrPoly(); output += MulMod(randomErrPoly(), publicKey, cycloMod); return YASHE_CT(output, this); }
// return multiplicative order of p modulo m, or 0 if GCD(p, m) != 1 long multOrd(long p, long m) { if (GCD(p, m) != 1) return 0; p = p % m; long ord = 1; long val = p; while (val != 1) { ord++; val = MulMod(val, p, m); } return ord; }
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; }
void YASHE::roundDecrypt(NTL::ZZ& output, const NTL::ZZ_pX& a, const NTL::ZZ_pX& b) { NTL::ZZ_pX product = MulMod(a, b, cycloMod); NTL::ZZ quotient, remainder; DivRem(output, remainder, pModulus * rep(product[0]), cModulus); // Rounding using remainder if (remainder * 2 > cModulus) { output += 1; } }