public override void PerformTest() { BigIntEuclidean r = BigIntEuclidean.Calculate(BigInteger.ValueOf(120), BigInteger.ValueOf(23)); Assert.AreEqual(BigInteger.ValueOf(-9), r.x); Assert.AreEqual(BigInteger.ValueOf(47), r.y); Assert.AreEqual(BigInteger.ValueOf(1), r.gcd); r = BigIntEuclidean.Calculate(BigInteger.ValueOf(126), BigInteger.ValueOf(231)); Assert.AreEqual(BigInteger.ValueOf(2), r.x); Assert.AreEqual(BigInteger.ValueOf(-1), r.y); Assert.AreEqual(BigInteger.ValueOf(21), r.gcd); }
/// <summary> /// Calculates a <c>rho</c> modulo <c>m1*m2</c> from two resultants whose /// <c>rho</c>s are modulo <c>m1</c> and <c>m2</c>. /// <para><c>res</c> is set to <c>null</c>.</para> /// </summary> /// /// <param name="ModRes1">M1 resultant</param> /// <param name="ModRes2">M2 resultant</param> /// /// <returns><c>Rho</c> modulo <c>modRes1.modulus * modRes2.modulus</c>, and <c>null</c> for <c>res</c></returns> public static ModularResultant CombineRho(ModularResultant ModRes1, ModularResultant ModRes2) { BigInteger mod1 = ModRes1.m_modulus; BigInteger mod2 = ModRes2.m_modulus; BigInteger prod = mod1.Multiply(mod2); BigIntEuclidean er = BigIntEuclidean.Calculate(mod2, mod1); BigIntPolynomial rho1 = ModRes1.Rho.Clone(); rho1.Multiply(er.X.Multiply(mod2)); BigIntPolynomial rho2 = ModRes2.Rho.Clone(); rho2.Multiply(er.Y.Multiply(mod1)); rho1.Add(rho2); rho1.Mod(prod); return(new ModularResultant(rho1, null, prod)); }
/// <summary> /// BigIntEuclidean tests /// </summary> /// /// <returns>State</returns> public string Test() { try { BigIntEuclidean r = BigIntEuclidean.Calculate(BigInteger.ValueOf(120), BigInteger.ValueOf(23)); if (!BigInteger.ValueOf(-9).Equals(r.X)) { throw new Exception("BigIntEuclidean failed r.X!"); } if (!BigInteger.ValueOf(47).Equals(r.Y)) { throw new Exception("BigIntEuclidean failed r.Y!"); } if (!BigInteger.ValueOf(1).Equals(r.GCD)) { throw new Exception("BigIntEuclidean failed r.GCD!"); } OnProgress(new TestEventArgs("Passed round 1 X, Y and GCD value comparisons")); r = BigIntEuclidean.Calculate(BigInteger.ValueOf(126), BigInteger.ValueOf(231)); if (!BigInteger.ValueOf(2).Equals(r.X)) { throw new Exception("BigIntEuclidean failed r.X!"); } if (!BigInteger.ValueOf(-1).Equals(r.Y)) { throw new Exception("BigIntEuclidean failed r.Y!"); } if (!BigInteger.ValueOf(21).Equals(r.GCD)) { throw new Exception("BigIntEuclidean failed r.GCD!"); } OnProgress(new TestEventArgs("Passed round 2 X, Y and GCD value comparisons")); return(SUCCESS); } catch (Exception Ex) { string message = Ex.Message == null ? "" : Ex.Message; throw new Exception(FAILURE + message); } }
/** * 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)); }
/** * Resultant of this polynomial with <code>x^n-1</code> using a probabilistic algorithm. * <p> * Unlike EESS, this implementation does not compute all resultants modulo primes * such that their product exceeds the maximum possible resultant, but rather stops * when <code>NUM_EQUAL_RESULTANTS</code> consecutive modular resultants are equal.<br> * This means the return value may be incorrect. Experiments show this happens in * about 1 out of 100 cases when <code>N=439</code> and <code>NUM_EQUAL_RESULTANTS=2</code>, * so the likelyhood of leaving the loop too early is <code>(1/100)^(NUM_EQUAL_RESULTANTS-1)</code>. * <p> * Because of the above, callers must verify the output and try a different polynomial if necessary. * * @return <code>(rho, res)</code> satisfying <code>res = rho*this + t*(x^n-1)</code> for some integer <code>t</code>. */ public Resultant Resultant() { int N = coeffs.Length; // Compute resultants modulo prime numbers. Continue until NUM_EQUAL_RESULTANTS consecutive modular resultants are equal. LinkedList <ModularResultant> modResultants = new LinkedList <ModularResultant>(); BigInteger pProd = Constants.BIGINT_ONE; BigInteger res = Constants.BIGINT_ONE; int numEqual = 1; // number of consecutive modular resultants equal to each other PrimeGenerator primes = new PrimeGenerator(); BigInteger pProd2; BigInteger pProd2n; while (true) { BigInteger prime = primes.nextPrime(); ModularResultant crr = Resultant(prime.IntValue); modResultants.AddLast(crr); //Was just add in Java BigInteger temp = pProd.Multiply(prime); BigIntEuclidean er = BigIntEuclidean.Calculate(prime, pProd); BigInteger resPrev = res; res = res.Multiply(er.x.Multiply(prime)); BigInteger res2 = crr.Res.Multiply(er.y.Multiply(pProd)); res = res.Add(res2).Mod(temp); pProd = temp; pProd2 = pProd.Divide(BigInteger.ValueOf(2)); pProd2n = pProd2.Negate(); if (res.CompareTo(pProd2) > 0) { res = res.Subtract(pProd); } else if (res.CompareTo(pProd2n) < 0) { res = res.Add(pProd); } if (res.Equals(resPrev)) { numEqual++; if (numEqual >= NUM_EQUAL_RESULTANTS) { break; } } else { numEqual = 1; } } // Combine modular rho's to obtain the final rho. // For efficiency, first combine all pairs of small resultants to bigger resultants, // then combine pairs of those, etc. until only one is left. while (modResultants.Count > 1) { ModularResultant modRes1 = modResultants.First.Value; modResultants.RemoveFirst(); ModularResultant modRes2 = modResultants.First.Value; modResultants.RemoveFirst(); ModularResultant modRes3 = ModularResultant.CombineRho(modRes1, modRes2); modResultants.AddLast(modRes3); } BigIntPolynomial rhoP = modResultants.First.Value.Rho; pProd2 = pProd.Divide(BigInteger.ValueOf(2)); pProd2n = pProd2.Negate(); if (res.CompareTo(pProd2) > 0) { res = res.Subtract(pProd); } if (res.CompareTo(pProd2n) < 0) { res = res.Add(pProd); } for (int i = 0; i < N; i++) { BigInteger c = rhoP.coeffs[i]; if (c.CompareTo(pProd2) > 0) { rhoP.coeffs[i] = c.Subtract(pProd); } if (c.CompareTo(pProd2n) < 0) { rhoP.coeffs[i] = c.Add(pProd); } } return(new Resultant(rhoP, res)); }