Polynomial f;
IntegerPolynomial fInt;
Polynomial g;
IntegerPolynomial gInt;
IntegerPolynomial fq;
Resultant rf;
Resultant rg;
BigIntEuclidean r;
int _2n1 = 2 * N + 1;
boolean primeCheck = params.primeCheck;
do
{
do
{
f = params.polyType== NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, new SecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, new SecureRandom());
fInt = f.toIntegerPolynomial();
}
while (primeCheck && fInt.resultant(_2n1).res.equals(ZERO));
fq = fInt.invertFq(q);
}
while (fq == null);
rf = fInt.resultant();
do
{
do
{
do
{
g = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, new SecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, new SecureRandom());
gInt = g.toIntegerPolynomial();
}
while (primeCheck && gInt.resultant(_2n1).res.equals(ZERO));
}
while (gInt.invertFq(q) == null);
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);
}