public void testResultant() { SecureRandom random = new SecureRandom(); NTRUSigningKeyGenerationParameters parameters = NTRUSigningKeyGenerationParameters.APR2011_439; IntegerPolynomial a = DenseTernaryPolynomial.GenerateRandom(parameters.N, parameters.d, parameters.d, random); Resultant r = a.Resultant(); if (r.Rho.GetCoeffs().Length > parameters.N) { BigInteger[] trimmedArray = new BigInteger[parameters.N]; Array.Copy(r.Rho.GetCoeffs(), trimmedArray, parameters.N); r.Rho.coeffs = trimmedArray; } verifyResultant(a, r); a = new IntegerPolynomial(new int[] { 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, -1, -1, 0, -1, 1, -1, 0, -1, 0, -1, -1, -1, 0, 0, 0, 1, 1, -1, -1, -1, 0, -1, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 1, 1, -1, 0, 1, -1, 0, 1, 0, 1, 0, -1, -1, 0, 1, 0, -1, 1, 1, 1, 1, 0, 0, -1, -1, 1, 0, 0, -1, -1, 0, -1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 1, 0, 1, -1, 0, 0, 1, 1, 1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, -1, -1, 0, -1, -1, -1, 0, -1, -1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, -1, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, 1, 1, 0, 0, -1, 1, 0, 0, 0, -1, 1, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 1, 1, 0, 0, -1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, -1, 0, 1, 0, -1, -1, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 1, -1, 1, -1, -1, 1, -1, 0, 1, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, -1, 0, 1, -1, 0, 0, 1, 1, 0, 0, 1, 1, 0, -1, 0, -1, 1, -1, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 1, -1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, -1, -1, 0, 0, -1, 0, 1, 1, -1, 1, -1, 0, 0, 0, 1 }); r = a.Resultant(); if (r.Rho.GetCoeffs().Length > a.coeffs.Length) { BigInteger[] trimmedArray = new BigInteger[a.coeffs.Length]; Array.Copy(r.Rho.GetCoeffs(), trimmedArray, a.coeffs.Length); r.Rho.coeffs = trimmedArray; } verifyResultant(a, r); }
// verifies that res=rho*a mod x^n-1 mod p private void VerifyResultant(IntegerPolynomial a, Resultant r, int p) { BigIntPolynomial b = new BigIntPolynomial(a).MultSmall(r.Rho); b.Mod(BigInteger.ValueOf(p)); for (int j = 1; j < b.Coeffs.Length - 1; j++) { if (!Compare.Equals(BigInteger.Zero, b.Coeffs[j])) { throw new Exception("IntegerPolynomialTest VerifyResultant test failed!"); } } if (r.Res.Equals(BigInteger.Zero)) { if (!Compare.Equals(BigInteger.Zero, b.Coeffs[0].Subtract(b.Coeffs[b.Coeffs.Length - 1]))) { throw new Exception("IntegerPolynomialTest VerifyResultant test failed!"); } } else { if (!Compare.Equals(BigInteger.Zero, (b.Coeffs[0].Subtract(b.Coeffs[b.Coeffs.Length - 1]).Subtract(r.Res).Mod(BigInteger.ValueOf(p))))) { throw new Exception("IntegerPolynomialTest VerifyResultant test failed!"); } } if (!Compare.Equals(BigInteger.Zero, b.Coeffs[0].Subtract(r.Res).Subtract(b.Coeffs[b.Coeffs.Length - 1].Negate()).Mod(BigInteger.ValueOf(p)))) { throw new Exception("IntegerPolynomialTest VerifyResultant test failed!"); } }
// verifies that res=rho*a mod x^n-1 private void verifyResultant(IntegerPolynomial a, Resultant r) { BigIntPolynomial b = new BigIntPolynomial(a).Multiply(r.Rho); BigInteger[] bCoeffs = b.GetCoeffs(); for (int j = 1; j < bCoeffs.Length - 1; j++) { Assert.AreEqual(BigInteger.Zero, bCoeffs[j]); } if (r.Res.Equals(BigInteger.Zero)) { Assert.AreEqual(BigInteger.Zero, bCoeffs[0].Subtract(bCoeffs[bCoeffs.Length - 1])); } else { Assert.AreEqual(BigInteger.Zero, (bCoeffs[0].Subtract(bCoeffs[bCoeffs.Length - 1]).Mod(r.Res))); } Assert.AreEqual(bCoeffs[0].Subtract(r.Res), bCoeffs[bCoeffs.Length - 1].Negate()); }
/** * Creates a NtruSign basis consisting of polynomials <code>f, g, F, G, h</code>.<br/> * If <code>KeyGenAlg=FLOAT</code>, the basis may not be valid and this method must be rerun if that is the case.<br/> * @see #generateBoundedBasis() */ private FGBasis generateBasis() { int N = param.N; int q = param.q; int d = param.d; int d1 = param.d1; int d2 = param.d2; int d3 = param.d3; BasisType basisType = param.basisType; IPolynomial f; IntegerPolynomial fInt; IPolynomial g; IntegerPolynomial gInt; IntegerPolynomial fq; Resultant rf; Resultant rg; BigIntEuclidean r; int _2n1 = 2 * N + 1; bool primeCheck = param.primeCheck; Random rng = new Random(); do { do { if (param.polyType == TernaryPolynomialType.SIMPLE) { f = DenseTernaryPolynomial.GenerateRandom(N, d + 1, d); } else { f = ProductFormPolynomial.GenerateRandom(N, d1, d2, d3 + 1, d3); } fInt = f.ToIntegerPolynomial(); } while (primeCheck && fInt.Resultant(_2n1).Res.Equals(BigInteger.Zero)); fq = fInt.InvertFq(q); } while (fq == null); rf = fInt.Resultant(); do { do { do { if (param.polyType == TernaryPolynomialType.SIMPLE) { g = DenseTernaryPolynomial.GenerateRandom(N, d + 1, d); } else { g = ProductFormPolynomial.GenerateRandom(N, d1, d2, d3 + 1, d3); } gInt = g.ToIntegerPolynomial(); } while (primeCheck && gInt.Resultant(_2n1).Res.Equals(BigInteger.Zero)); } while (!gInt.IsInvertiblePow2()); rg = gInt.Resultant(); r = BigIntEuclidean.Calculate(rf.Res, rg.Res); } while (!r.GCD.Equals(BigInteger.One)); BigIntPolynomial A = rf.Rho.Clone(); A.Multiply(r.X.Multiply(BigInteger.ValueOf(q))); BigIntPolynomial B = rg.Rho.Clone(); B.Multiply(r.Y.Multiply(BigInteger.ValueOf(-q))); BigIntPolynomial C; if (param.keyGenAlg == KeyGenAlg.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.Multiply(fRev); t.Add(g.Multiply(gRev)); Resultant rt = t.Resultant(); C = fRev.Multiply(B); // fRev.mult(B) is actually faster than new SparseTernaryPolynomial(fRev).mult(B), possibly due to cache locality? C.Add(gRev.Multiply(A)); C = C.MultBig(rt.Rho); C.Divide(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.Divide(new BigDecimal(rf.Res), B.GetMaxCoeffLength() + 1 + log10N); BigDecimalPolynomial gInv = rg.Rho.Divide(new BigDecimal(rg.Res), A.GetMaxCoeffLength() + 1 + log10N); BigDecimalPolynomial Cdec = fInv.Multiply(B); Cdec.Add(gInv.Multiply(A)); Cdec.Halve(); C = Cdec.Round(); } BigIntPolynomial F = B.Clone(); F.Subtract(f.Multiply(C)); BigIntPolynomial G = A.Clone(); G.Subtract(g.Multiply(C)); IntegerPolynomial FInt = new IntegerPolynomial(F); IntegerPolynomial GInt = new IntegerPolynomial(G); minimizeFG(fInt, gInt, FInt, GInt, N); IPolynomial fPrime; IntegerPolynomial h; if (basisType == BasisType.STANDARD) { fPrime = FInt; h = g.Multiply(fq, q); } else { fPrime = g; h = FInt.Multiply(fq, q); } h.ModPositive(q); return(new FGBasis(f, fPrime, h, FInt, GInt, param.q, param.polyType, param.basisType, param.keyNormBoundSq)); }