本文整理汇总了C++中Ctxt::getPtxtSpace方法的典型用法代码示例。如果您正苦于以下问题:C++ Ctxt::getPtxtSpace方法的具体用法?C++ Ctxt::getPtxtSpace怎么用?C++ Ctxt::getPtxtSpace使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Ctxt
的用法示例。
在下文中一共展示了Ctxt::getPtxtSpace方法的13个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: mapTo01
NTL_CLIENT
#include "FHE.h"
#include "timing.h"
#include "EncryptedArray.h"
#include <cstdio>
// Map all non-zero slots to 1, leaving zero slots as zero.
// Assumes that r=1, and that all the slot contain elements from GF(p^d).
//
// We compute x^{p^d-1} = x^{(1+p+...+p^{d-1})*(p-1)} by setting y=x^{p-1}
// and then outputting y * y^p * ... * y^{p^{d-1}}, with exponentiation to
// powers of p done via Frobenius.
// FIXME: the computation of the "norm" y * y^p * ... * y^{p^{d-1}}
// can be done using O(log d) automorphisms, rather than O(d).
void mapTo01(const EncryptedArray& ea, Ctxt& ctxt)
{
long p = ctxt.getPtxtSpace();
if (p != ea.getPAlgebra().getP()) // ptxt space is p^r for r>1
throw helib::LogicError("mapTo01 not implemented for r>1");
if (p>2)
ctxt.power(p-1); // set y = x^{p-1}
long d = ea.getDegree();
if (d>1) { // compute the product of the d automorphisms
std::vector<Ctxt> v(d, ctxt);
for (long i=1; i<d; i++)
v[i].frobeniusAutomorph(i);
totalProduct(ctxt, v);
}
}
示例2: tmp
// This procedure assumes that k*(2^e +1) > deg(poly) > k*(2^e -1),
// and that babyStep contains >= k + (deg(poly) mod k) powers
static void
degPowerOfTwo(Ctxt& ret, const ZZX& poly, long k,
DynamicCtxtPowers& babyStep, DynamicCtxtPowers& giantStep)
{
if (deg(poly)<=babyStep.size()) { // Edge condition, use simple eval
simplePolyEval(ret, poly, babyStep);
return;
}
long n = deg(poly)/k; // We assume n=2^e or n=2^e -1
n = 1L << NextPowerOfTwo(n); // round up to n=2^e
ZZX r = trunc(poly, (n-1)*k); // degree <= k(2^e-1)-1
ZZX q = RightShift(poly, (n-1)*k); // 0 < degree < 2k
SetCoeff(r, (n-1)*k); // monic, degree == k(2^e-1)
q -= 1;
PatersonStockmeyer(ret, r, k, n/2, 0, babyStep, giantStep);
Ctxt tmp(ret.getPubKey(), ret.getPtxtSpace());
simplePolyEval(tmp, q, babyStep); // evaluate q
// multiply by X^{k(n-1)} with minimum depth
for (long i=1; i<n; i*=2) {
tmp.multiplyBy(giantStep.getPower(i));
}
ret += tmp;
}
示例3: assert
// Constructor
Ctxt::Ctxt(ZeroCtxtLike_type, const Ctxt& ctxt):
context(ctxt.getPubKey().getContext()), pubKey(ctxt.getPubKey()),
ptxtSpace(ctxt.getPtxtSpace()),
noiseVar(to_xdouble(0.0))
{
// same body as previous constructor
if (ptxtSpace<=0) ptxtSpace = pubKey.getPtxtSpace();
else assert (GCD(ptxtSpace, pubKey.getPtxtSpace()) > 1); // sanity check
primeSet=context.ctxtPrimes;
}
示例4: decryptAndPrint
void decryptAndPrint(ostream& s, const Ctxt& ctxt, const FHESecKey& sk,
const EncryptedArray& ea, long flags)
{
const FHEcontext& context = ctxt.getContext();
xdouble noiseEst = sqrt(ctxt.getNoiseVar());
xdouble modulus = xexp(context.logOfProduct(ctxt.getPrimeSet()));
vector<ZZX> ptxt;
ZZX p, pp;
sk.Decrypt(p, ctxt, pp);
s << "plaintext space mod "<<ctxt.getPtxtSpace()
<< ", level="<<ctxt.findBaseLevel()
<< ", \n |noise|=q*" << (coeffsL2Norm(pp)/modulus)
<< ", |noiseEst|=q*" << (noiseEst/modulus)
<<endl;
if (flags & FLAG_PRINT_ZZX) {
s << " before mod-p reduction=";
printZZX(s,pp) <<endl;
}
if (flags & FLAG_PRINT_POLY) {
s << " after mod-p reduction=";
printZZX(s,p) <<endl;
}
if (flags & FLAG_PRINT_VEC) {
ea.decode(ptxt, p);
if (ea.getAlMod().getTag() == PA_zz_p_tag
&& ctxt.getPtxtSpace() != ea.getAlMod().getPPowR()) {
long g = GCD(ctxt.getPtxtSpace(), ea.getAlMod().getPPowR());
for (long i=0; i<ea.size(); i++)
PolyRed(ptxt[i], g, true);
}
s << " decoded to ";
if (deg(p) < 40) // just pring the whole thing
s << ptxt << endl;
else if (ptxt.size()==1) // a single slot
printZZX(s, ptxt[0]) <<endl;
else { // print first and last slots
printZZX(s, ptxt[0],20) << "--";
printZZX(s, ptxt[ptxt.size()-1], 20) <<endl;
}
}
}
示例5: extractDigits
void extractDigits(vector<Ctxt>& digits, const Ctxt& c, long r)
{
const FHEcontext& context = c.getContext();
long rr = c.effectiveR();
if (r<=0 || r>rr) r = rr; // how many digits to extract
long p = context.zMStar.getP();
ZZX x2p;
if (p>3) {
buildDigitPolynomial(x2p, p, r);
}
Ctxt tmp(c.getPubKey(), c.getPtxtSpace());
digits.resize(r, tmp); // allocate space
#ifdef DEBUG_PRINTOUT
fprintf(stderr, "***\n");
#endif
for (long i=0; i<r; i++) {
tmp = c;
for (long j=0; j<i; j++) {
if (p==2) digits[j].square();
else if (p==3) digits[j].cube();
else polyEval(digits[j], x2p, digits[j]);
// "in spirit" digits[j] = digits[j]^p
#ifdef DEBUG_PRINTOUT
fprintf(stderr, "%5ld", digits[j].bitCapacity());
#endif
tmp -= digits[j];
tmp.divideByP();
}
digits[i] = tmp; // needed in the next round
#ifdef DEBUG_PRINTOUT
if (dbgKey) {
double ratio =
log(embeddingLargestCoeff(digits[i], *dbgKey)/digits[i].getNoiseBound())/log(2.0);
fprintf(stderr, "%5ld [%f]", digits[i].bitCapacity(), ratio);
if (ratio > 0) fprintf(stderr, " BAD-BOUND");
fprintf(stderr, "\n");
}
else {
fprintf(stderr, "%5ld\n", digits[i].bitCapacity());
}
#endif
}
#ifdef DEBUG_PRINTOUT
fprintf(stderr, "***\n");
#endif
}
示例6: checkCiphertext
void checkCiphertext(const Ctxt& ctxt, const ZZX& ptxt, const FHESecKey& sk)
{
const FHEcontext& context = ctxt.getContext();
/*
IndexSet base = baseSetOf(ctxt);
double addedNoise = log(ctxt.modSwitchAddedNoiseVar());
Ctxt tmp = ctxt;
tmp.modDownToSet(base);
double totalNoise = log(tmp.getNoiseVar());
cout << " @@@ log(added-noise)="<<addedNoise
<< ", log(total-noise)="<<totalNoise<<endl;
*/
cout << " ln(q)="<< context.logOfProduct(ctxt.getPrimeSet())
<< ", ln(nVar)/2="<< log(ctxt.getNoiseVar())/2;
// << ", ln(nMag)="<< log(ctxt.getNoiseMag());
ZZX res;
// sk.Decrypt(res, ctxt);
ZZX f;
sk.Decrypt(res, ctxt, f);
cout << ", ln(mxPtxtCoef)=" << log(largestCoeff(f));
// ensure we reduce the same way on both
PolyRed((ZZX&)res,res,ctxt.getPtxtSpace(),true);
PolyRed((ZZX&)ptxt,ptxt,ctxt.getPtxtSpace(),true);
if (res != ptxt) {
cout << ", failed\n";
for (long i=0; i<=deg(ptxt); i++) if (coeff(res,i)!=coeff(ptxt,i)) {
cout << "first mismatch in coeff "<<i<<": "
<< coeff(res,i)<<"!="<<coeff(ptxt,i)<<"\n";
break;
}
cout << "Timing information:\n";
printAllTimers();
cout << "\n";
exit(0);
}
else cout << ", succeeded\n";
}
示例7: applyToCtxt
// Apply a permutation network to a ciphertext
// FIXME: Do we need to also give an EncryptedArray object as paramter?
void PermNetwork::applyToCtxt(Ctxt& c) const
{
const PAlgebra& al = c.getContext().zMStar;
EncryptedArray ea(c.getContext());
// Use G(X)=X for this ea object, this works since we only have 0/1 entries
// Apply the layers, one at a time
for (long i=0; i<layers.length(); i++) {
const PermNetLayer& lyr = layers[i];
if (lyr.isID) continue; // this layer is the identity permutation
// This layer is shifted via powers of g^e mod m
long g2e = PowerMod(al.ZmStarGen(lyr.genIdx), lyr.e, al.getM());
Vec<long> unused = lyr.shifts; // copy to a new vector
vector<long> mask(lyr.shifts.length()); // buffer to hold masks
Ctxt sum(c.getPubKey(), c.getPtxtSpace()); // an empty ciphertext
long shamt = 0;
bool frst = true;
while (true) {
pair<long,bool> ret=makeMask(mask, unused, shamt); // compute mask
if (ret.second) { // non-empty mask
Ctxt tmp = c;
ZZX maskPoly;
ea.encode(maskPoly, mask); // encode mask as polynomial
tmp.multByConstant(maskPoly); // multiply by mask
if (shamt!=0) // rotate if the shift amount is nonzero
tmp.smartAutomorph(PowerMod(g2e, shamt, al.getM()));
if (frst) {
sum = tmp;
frst = false;
}
else
sum += tmp;
}
if (ret.first >= 0)
shamt = unused[ret.first]; // next shift amount to use
else break; // unused is all-zero, done with this layer
}
c = sum; // update the cipehrtext c before the next layer
}
}
示例8: fastPower
// computes ctxt^{2^d-1} using a method that takes
// O(log d) automorphisms and multiplications
void fastPower(Ctxt& ctxt, long d)
{
assert(ctxt.getPtxtSpace()==2);
if (d <= 1) return;
Ctxt orig = ctxt;
long k = NumBits(d);
long e = 1;
for (long i = k-2; i >= 0; i--) {
Ctxt tmp1 = ctxt;
tmp1.smartAutomorph(1L << e);
ctxt.multiplyBy(tmp1);
e = 2*e;
if (bit(d, i)) {
ctxt.smartAutomorph(2);
ctxt.multiplyBy(orig);
e += 1;
}
}
}
示例9: apply
static void apply(const EncryptedArrayDerived<type>& ea,
Ctxt& ctxt, const PlaintextMatrixBaseInterface& mat)
{
assert(&ea == &mat.getEA().getDerived(type()));
assert(&ea.getContext() == &ctxt.getContext());
RBak bak; bak.save(); ea.getTab().restoreContext();
// Get the derived type
const PlaintextMatrixInterface<type>& mat1 =
dynamic_cast< const PlaintextMatrixInterface<type>& >( mat );
ctxt.cleanUp(); // not sure, but this may be a good idea
Ctxt res(ctxt.getPubKey(), ctxt.getPtxtSpace()); // fresh encryption of zero
long nslots = ea.size();
long d = ea.getDegree();
RX entry;
vector<RX> diag;
diag.resize(nslots);
// Process the diagonals one at a time
for (long i = 0; i < nslots; i++) { // process diagonal i
bool zDiag = true; // is this a zero diagonal?
long nzLast = -1; // index of last non-zero entry on this diagonal
// Compute constants for each entry on this diagonal
for (long j = 0; j < nslots; j++) { // process entry j
bool zEntry = mat1.get(entry, mcMod(j-i, nslots), j); // callback
assert(zEntry || deg(entry) < d);
if (!zEntry && IsZero(entry)) zEntry = true; // check for zero
if (!zEntry) { // non-zero diagonal entry
zDiag = false; // diagonal is non-zero
// clear entries between last nonzero entry and this one
for (long jj = nzLast+1; jj < j; jj++) clear(diag[jj]);
nzLast = j;
diag[j] = entry;
}
}
if (zDiag) continue; // zero diagonal, continue
// clear trailing zero entries
for (long jj = nzLast+1; jj < nslots; jj++) clear(diag[jj]);
// Now we have the constants for all the diagonal entries, encode the
// diagonal as a single polynomial with these constants in the slots
ZZX cpoly;
ea.encode(cpoly, diag);
// rotate by i, multiply by the polynomial, then add to the result
Ctxt shCtxt = ctxt;
ea.rotate(shCtxt, i); // rotate by i
shCtxt.multByConstant(cpoly);
res += shCtxt;
}
ctxt = res;
}
示例10: extendExtractDigits
void extendExtractDigits(vector<Ctxt>& digits, const Ctxt& c, long r, long e)
{
const FHEcontext& context = c.getContext();
long p = context.zMStar.getP();
ZZX x2p;
if (p>3) {
buildDigitPolynomial(x2p, p, r);
}
// we should pre-compute this table
// for i = 0..r-1, entry i is G_{e+r-i} in Chen and Han
Vec<ZZX> G;
G.SetLength(r);
for (long i: range(r)) {
compute_magic_poly(G[i], p, e+r-i);
}
vector<Ctxt> digits0;
Ctxt tmp(c.getPubKey(), c.getPtxtSpace());
digits.resize(r, tmp); // allocate space
digits0.resize(r, tmp);
#ifdef DEBUG_PRINTOUT
fprintf(stderr, "***\n");
#endif
for (long i: range(r)) {
tmp = c;
for (long j: range(i)) {
if (digits[j].capacity() >= digits0[j].capacity()) {
// optimization: digits[j] is better than digits0[j],
// so just use it
tmp -= digits[j];
#ifdef DEBUG_PRINTOUT
fprintf(stderr, "%5ld*", digits[j].bitCapacity());
#endif
}
else {
if (p==2) digits0[j].square();
else if (p==3) digits0[j].cube();
else polyEval(digits0[j], x2p, digits0[j]); // "in spirit" digits0[j] = digits0[j]^p
tmp -= digits0[j];
#ifdef DEBUG_PRINTOUT
fprintf(stderr, "%5ld ", digits0[j].bitCapacity());
#endif
}
tmp.divideByP();
}
digits0[i] = tmp; // needed in the next round
polyEval(digits[i], G[i], tmp);
#ifdef DEBUG_PRINTOUT
if (dbgKey) {
double ratio =
log(embeddingLargestCoeff(digits[i], *dbgKey)/digits[i].getNoiseBound())/log(2.0);
fprintf(stderr, "%5ld --- %5ld", digits0[i].bitCapacity(), digits[i].bitCapacity());
fprintf(stderr, " [%f]", ratio);
if (ratio > 0) fprintf(stderr, " BAD-BOUND");
fprintf(stderr, "\n");
}
else {
fprintf(stderr, "%5ld --- %5ld\n", digits0[i].bitCapacity(), digits[i].bitCapacity());
}
#endif
}
}
示例11: reCrypt
// bootstrap a ciphertext to reduce noise
void FHEPubKey::reCrypt(Ctxt &ctxt)
{
FHE_TIMER_START;
// Some sanity checks for dummy ciphertext
long ptxtSpace = ctxt.getPtxtSpace();
if (ctxt.isEmpty()) return;
if (ctxt.parts.size()==1 && ctxt.parts[0].skHandle.isOne()) {
// Dummy encryption, just ensure that it is reduced mod p
ZZX poly = to_ZZX(ctxt.parts[0]);
for (long i=0; i<poly.rep.length(); i++)
poly[i] = to_ZZ( rem(poly[i],ptxtSpace) );
poly.normalize();
ctxt.DummyEncrypt(poly);
return;
}
assert(recryptKeyID>=0); // check that we have bootstrapping data
long p = getContext().zMStar.getP();
long r = getContext().alMod.getR();
long p2r = getContext().alMod.getPPowR();
// the bootstrapping key is encrypted relative to plaintext space p^{e-e'+r}.
long e = getContext().rcData.e;
long ePrime = getContext().rcData.ePrime;
long p2ePrime = power_long(p,ePrime);
long q = power_long(p,e)+1;
assert(e>=r);
#ifdef DEBUG_PRINTOUT
cerr << "reCrypt: p="<<p<<", r="<<r<<", e="<<e<<" ePrime="<<ePrime
<< ", q="<<q<<endl;
#endif
// can only bootstrap ciphertext with plaintext-space dividing p^r
assert(p2r % ptxtSpace == 0);
FHE_NTIMER_START(preProcess);
// Make sure that this ciphertxt is in canonical form
if (!ctxt.inCanonicalForm()) ctxt.reLinearize();
// Mod-switch down if needed
IndexSet s = ctxt.getPrimeSet() / getContext().specialPrimes; // set minus
if (s.card()>2) { // leave only bottom two primes
long frst = s.first();
long scnd = s.next(frst);
IndexSet s2(frst,scnd);
s.retain(s2); // retain only first two primes
}
ctxt.modDownToSet(s);
// key-switch to the bootstrapping key
ctxt.reLinearize(recryptKeyID);
// "raw mod-switch" to the bootstrapping mosulus q=p^e+1.
vector<ZZX> zzParts; // the mod-switched parts, in ZZX format
double noise = ctxt.rawModSwitch(zzParts, q);
noise = sqrt(noise);
// Add multiples of p2r and q to make the zzParts divisible by p^{e'}
long maxU=0;
for (long i=0; i<(long)zzParts.size(); i++) {
// make divisible by p^{e'}
long newMax = makeDivisible(zzParts[i].rep, p2ePrime, p2r, q,
getContext().rcData.alpha);
zzParts[i].normalize(); // normalize after working directly on the rep
if (maxU < newMax) maxU = newMax;
}
// Check that the estimated noise is still low
if (noise + maxU*p2r*(skHwts[recryptKeyID]+1) > q/2)
cerr << " * noise/q after makeDivisible = "
<< ((noise + maxU*p2r*(skHwts[recryptKeyID]+1))/q) << endl;
for (long i=0; i<(long)zzParts.size(); i++)
zzParts[i] /= p2ePrime; // divide by p^{e'}
// Multiply the post-processed cipehrtext by the encrypted sKey
#ifdef DEBUG_PRINTOUT
cerr << "+ Before recryption ";
decryptAndPrint(cerr, recryptEkey, *dbgKey, *dbgEa, printFlag);
#endif
double p0size = to_double(coeffsL2Norm(zzParts[0]));
double p1size = to_double(coeffsL2Norm(zzParts[1]));
ctxt = recryptEkey;
ctxt.multByConstant(zzParts[1], p1size*p1size);
ctxt.addConstant(zzParts[0], p0size*p0size);
#ifdef DEBUG_PRINTOUT
cerr << "+ Before linearTrans1 ";
decryptAndPrint(cerr, ctxt, *dbgKey, *dbgEa, printFlag);
#endif
FHE_NTIMER_STOP(preProcess);
// Move the powerful-basis coefficients to the plaintext slots
FHE_NTIMER_START(LinearTransform1);
//.........这里部分代码省略.........
示例12: polyEval
// Main entry point: Evaluate a cleartext polynomial on an encrypted input
void polyEval(Ctxt& ret, ZZX poly, const Ctxt& x, long k)
// Note: poly is passed by value, so caller keeps the original
{
if (deg(poly)<=2) { // nothing to optimize here
if (deg(poly)<1) { // A constant
ret.clear();
ret.addConstant(coeff(poly, 0));
} else { // A linear or quadratic polynomial
DynamicCtxtPowers babyStep(x, deg(poly));
simplePolyEval(ret, poly, babyStep);
}
return;
}
// How many baby steps: set k~sqrt(n/2), rounded up/down to a power of two
// FIXME: There may be some room for optimization here: it may be possible
// to choose k as something other than a power of two and still maintain
// optimal depth, in principle we can try all possible values of k between
// two consecutive powers of two and choose the one that gives the least
// number of multiplies, conditioned on minimum depth.
if (k<=0) {
long kk = (long) sqrt(deg(poly)/2.0);
k = 1L << NextPowerOfTwo(kk);
// heuristic: if k>>kk then use a smaler power of two
if ((k==16 && deg(poly)>167) || (k>16 && k>(1.44*kk)))
k /= 2;
}
#ifdef DEBUG_PRINTOUT
cerr << " k="<<k;
#endif
long n = divc(deg(poly),k); // n = ceil(deg(p)/k), deg(p) >= k*n
DynamicCtxtPowers babyStep(x, k);
const Ctxt& x2k = babyStep.getPower(k);
// Special case when deg(p)>k*(2^e -1)
if (n==(1L << NextPowerOfTwo(n))) { // n is a power of two
DynamicCtxtPowers giantStep(x2k, n/2);
degPowerOfTwo(ret, poly, k, babyStep, giantStep);
return;
}
// If n is not a power of two, ensure that poly is monic and that
// its degree is divisible by k, then call the recursive procedure
const ZZ p = to_ZZ(x.getPtxtSpace());
ZZ top = LeadCoeff(poly);
ZZ topInv; // the inverse mod p of the top coefficient of poly (if any)
bool divisible = (n*k == deg(poly)); // is the degree divisible by k?
long nonInvertibe = InvModStatus(topInv, top, p);
// 0 if invertible, 1 if not
// FIXME: There may be some room for optimization below: instead of
// adding a term X^{n*k} we can add X^{n'*k} for some n'>n, so long
// as n' is smaller than the next power of two. We could save a few
// multiplications since giantStep[n'] may be easier to compute than
// giantStep[n] when n' has fewer 1's than n in its binary expansion.
ZZ extra = ZZ::zero(); // extra!=0 denotes an added term extra*X^{n*k}
if (!divisible || nonInvertibe) { // need to add a term
top = to_ZZ(1); // new top coefficient is one
topInv = top; // also the new inverse is one
// set extra = 1 - current-coeff-of-X^{n*k}
extra = SubMod(top, coeff(poly,n*k), p);
SetCoeff(poly, n*k); // set the top coefficient of X^{n*k} to one
}
long t = IsZero(extra)? divc(n,2) : n;
DynamicCtxtPowers giantStep(x2k, t);
if (!IsOne(top)) {
poly *= topInv; // Multiply by topInv to make into a monic polynomial
for (long i=0; i<=n*k; i++) rem(poly[i], poly[i], p);
poly.normalize();
}
recursivePolyEval(ret, poly, k, babyStep, giantStep);
if (!IsOne(top)) {
ret.multByConstant(top);
}
if (!IsZero(extra)) { // if we added a term, now is the time to subtract back
Ctxt topTerm = giantStep.getPower(n);
topTerm.multByConstant(extra);
ret -= topTerm;
}
}
示例13: res
void EncryptedArrayDerived<type>::mat_mul(Ctxt& ctxt, const PlaintextBlockMatrixBaseInterface& mat) const
{
FHE_TIMER_START;
assert(this == &mat.getEA().getDerived(type()));
assert(&context == &ctxt.getContext());
RBak bak; bak.save(); tab.restoreContext();
const PlaintextBlockMatrixInterface<type>& mat1 =
dynamic_cast< const PlaintextBlockMatrixInterface<type>& >( mat );
ctxt.cleanUp(); // not sure, but this may be a good idea
Ctxt res(ctxt.getPubKey(), ctxt.getPtxtSpace());
// a new ciphertext, encrypting zero
long nslots = size();
long d = getDegree();
mat_R entry;
entry.SetDims(d, d);
vector<RX> entry1;
entry1.resize(d);
vector< vector<RX> > diag;
diag.resize(nslots);
for (long j = 0; j < nslots; j++) diag[j].resize(d);
for (long i = 0; i < nslots; i++) {
// process diagonal i
bool zDiag = true;
long nzLast = -1;
for (long j = 0; j < nslots; j++) {
bool zEntry = mat1.get(entry, mcMod(j-i, nslots), j);
assert(zEntry || (entry.NumRows() == d && entry.NumCols() == d));
// get(...) returns true if the entry is empty, false otherwise
if (!zEntry && IsZero(entry)) zEntry=true; // zero is an empty entry too
if (!zEntry) { // non-empty entry
zDiag = false; // mark diagonal as non-empty
// clear entries between last nonzero entry and this one
for (long jj = nzLast+1; jj < j; jj++) {
for (long k = 0; k < d; k++)
clear(diag[jj][k]);
}
nzLast = j;
// recode entry as a vector of polynomials
for (long k = 0; k < d; k++) conv(entry1[k], entry[k]);
// compute the lin poly coeffs
buildLinPolyCoeffs(diag[j], entry1);
}
}
if (zDiag) continue; // zero diagonal, continue
// clear trailing zero entries
for (long jj = nzLast+1; jj < nslots; jj++) {
for (long k = 0; k < d; k++)
clear(diag[jj][k]);
}
// now diag[j] contains the lin poly coeffs
Ctxt shCtxt = ctxt;
rotate(shCtxt, i);
// apply the linearlized polynomial
for (long k = 0; k < d; k++) {
// compute the constant
bool zConst = true;
vector<RX> cvec;
cvec.resize(nslots);
for (long j = 0; j < nslots; j++) {
cvec[j] = diag[j][k];
if (!IsZero(cvec[j])) zConst = false;
}
if (zConst) continue;
ZZX cpoly;
encode(cpoly, cvec);
// FIXME: record the encoded polynomial for future use
Ctxt shCtxt1 = shCtxt;
shCtxt1.frobeniusAutomorph(k);
shCtxt1.multByConstant(cpoly);
res += shCtxt1;
//.........这里部分代码省略.........