rg = gInt.resultant();
r = BigIntEuclidean.calculate(rf.res, rg.res);
}
while (!r.gcd.equals(ONE));
BigIntPolynomial A = (BigIntPolynomial)rf.rho.clone();
A.mult(r.x.multiply(BigInteger.valueOf(q)));
BigIntPolynomial B = (BigIntPolynomial)rg.rho.clone();
B.mult(r.y.multiply(BigInteger.valueOf(-q)));
BigIntPolynomial C;
if (params.keyGenAlg == NTRUSigningKeyGenerationParameters.KEY_GEN_ALG_RESULTANT)
{
int[] fRevCoeffs = new int[N];
int[] gRevCoeffs = new int[N];
fRevCoeffs[0] = fInt.coeffs[0];
gRevCoeffs[0] = gInt.coeffs[0];
for (int i = 1; i < N; i++)
{
fRevCoeffs[i] = fInt.coeffs[N - i];
gRevCoeffs[i] = gInt.coeffs[N - i];
}
IntegerPolynomial fRev = new IntegerPolynomial(fRevCoeffs);
IntegerPolynomial gRev = new IntegerPolynomial(gRevCoeffs);
IntegerPolynomial t = f.mult(fRev);
t.add(g.mult(gRev));
Resultant rt = t.resultant();
C = fRev.mult(B); // fRev.mult(B) is actually faster than new SparseTernaryPolynomial(fRev).mult(B), possibly due to cache locality?
C.add(gRev.mult(A));
C = C.mult(rt.rho);
C.div(rt.res);
}
else
{ // KeyGenAlg.FLOAT
// calculate ceil(log10(N))
int log10N = 0;
for (int i = 1; i < N; i *= 10)
{
log10N++;
}
// * Cdec needs to be accurate to 1 decimal place so it can be correctly rounded;
// * fInv loses up to (#digits of longest coeff of B) places in fInv.mult(B);
// * multiplying fInv by B also multiplies the rounding error by a factor of N;
// so make #decimal places of fInv the sum of the above.
BigDecimalPolynomial fInv = rf.rho.div(new BigDecimal(rf.res), B.getMaxCoeffLength() + 1 + log10N);
BigDecimalPolynomial gInv = rg.rho.div(new BigDecimal(rg.res), A.getMaxCoeffLength() + 1 + log10N);
BigDecimalPolynomial Cdec = fInv.mult(B);
Cdec.add(gInv.mult(A));
Cdec.halve();
C = Cdec.round();
}
BigIntPolynomial F = (BigIntPolynomial)B.clone();
F.sub(f.mult(C));
BigIntPolynomial G = (BigIntPolynomial)A.clone();
G.sub(g.mult(C));
IntegerPolynomial FInt = new IntegerPolynomial(F);
IntegerPolynomial GInt = new IntegerPolynomial(G);
minimizeFG(fInt, gInt, FInt, GInt, N);