/// <summary> /// Multiplies the polynomial by another, taking the indices mod N. /// <para>Does not change this polynomial but returns the result as a new polynomial. /// Both polynomials must have the same number of coefficients. /// This method uses the <a href="http://en.wikipedia.org/wiki/Schönhage–Strassen_algorithm"/> /// Schönhage–Strassen algorithm.</para> /// </summary> /// /// <param name="Factor">Multiplication factor</param> /// /// <returns>Multiplied polynomial</returns> /// /// <exception cref="CryptoAsymmetricException">Thrown if the two polynomials differ in the number of coefficients</exception> public BigDecimalPolynomial Multiply(BigIntPolynomial Factor) { if (Factor.Coeffs.Length != Coeffs.Length) { throw new CryptoAsymmetricException("BigDecimalPolynomial:Multiply", "Number of coefficients must be the same!", new FormatException()); } BigIntPolynomial poly1 = new BigIntPolynomial(Coeffs.Length); for (int i = 0; i < Coeffs.Length; i++) { poly1.Coeffs[i] = Coeffs[i].UnScaledValue; } int scale = Coeffs[0].Scale; BigIntPolynomial cBigInt = poly1.MultBig(Factor); BigDecimalPolynomial c = new BigDecimalPolynomial(cBigInt.Coeffs.Length); for (int i = 0; i < c.Coeffs.Length; i++) { c.Coeffs[i] = new BigDecimal(cBigInt.Coeffs[i], scale); } return(c); }
/// <summary> /// Multiplies the polynomial by an <c>IntegerPolynomial</c>, /// taking the indices mod <c>N</c>. /// </summary> /// /// <param name="Factor">A polynomial factor</param> /// /// <returns>The product of the two polynomials</returns> public BigIntPolynomial Multiply(BigIntPolynomial Factor) { BigIntPolynomial c = m_f1.Multiply(Factor); c = m_f2.Multiply(c); c.Add(m_f3.Multiply(Factor)); return(c); }
private BigIntPolynomial MultRecursive(BigIntPolynomial Factor) { // Karatsuba multiplication BigInteger[] a = Coeffs; BigInteger[] b = Factor.Coeffs; int n = Factor.Coeffs.Length; if (n <= 1) { BigInteger[] c = (BigInteger[])Coeffs.Clone(); for (int i = 0; i < Coeffs.Length; i++) { c[i] = c[i].Multiply(Factor.Coeffs[0]); } return(new BigIntPolynomial(c)); } else { int n1 = n / 2; BigIntPolynomial a1 = new BigIntPolynomial(a.CopyOf(n1)); BigIntPolynomial a2 = new BigIntPolynomial(a.CopyOfRange(n1, n)); BigIntPolynomial b1 = new BigIntPolynomial(b.CopyOf(n1)); BigIntPolynomial b2 = new BigIntPolynomial(b.CopyOfRange(n1, n)); BigIntPolynomial A = (BigIntPolynomial)a1.Clone(); A.Add(a2); BigIntPolynomial B = (BigIntPolynomial)b1.Clone(); B.Add(b2); BigIntPolynomial c1 = a1.MultRecursive(b1); BigIntPolynomial c2 = a2.MultRecursive(b2); BigIntPolynomial c3 = A.MultRecursive(B); c3.Subtract(c1); c3.Subtract(c2); BigIntPolynomial c = new BigIntPolynomial(2 * n - 1); for (int i = 0; i < c1.Coeffs.Length; i++) { c.Coeffs[i] = c1.Coeffs[i]; } for (int i = 0; i < c3.Coeffs.Length; i++) { c.Coeffs[n1 + i] = c.Coeffs[n1 + i].Add(c3.Coeffs[i]); } for (int i = 0; i < c2.Coeffs.Length; i++) { c.Coeffs[2 * n1 + i] = c.Coeffs[2 * n1 + i].Add(c2.Coeffs[i]); } return(c); } }
/// <summary> /// Rounds all coefficients to the nearest integer /// </summary> /// /// <returns>A new polynomial with <c>BigInteger</c> coefficients</returns> public BigIntPolynomial Round() { int N = Coeffs.Length; BigIntPolynomial p = new BigIntPolynomial(N); for (int i = 0; i < N; i++) { p.Coeffs[i] = Coeffs[i].SetScale(0, RoundingModes.HalfEven).ToBigInteger(); } return(p); }
/// <summary> /// Adds another polynomial which can have a different number of coefficients. /// </summary> /// /// <param name="B">The polynomial to add</param> public void Add(BigIntPolynomial B) { if (B.Coeffs.Length > Coeffs.Length) { int N = Coeffs.Length; Coeffs = Coeffs.CopyOf(B.Coeffs.Length); for (int i = N; i < Coeffs.Length; i++) Coeffs[i] = BigInteger.Zero; } for (int i = 0; i < B.Coeffs.Length; i++) Coeffs[i] = Coeffs[i].Add(B.Coeffs[i]); }
/// <summary> /// Multiplies the polynomial by a <c>BigIntPolynomial</c>, taking the indices mod N. Does not /// change this polynomial but returns the result as a new polynomial. /// <para>Both polynomials must have the same number of coefficients.</para> /// </summary> /// /// <param name="Factor">The polynomial to multiply by</param> /// /// <returns>The product of the two polynomials</returns> public BigIntPolynomial Multiply(BigIntPolynomial Factor) { BigInteger[] b = Factor.Coeffs; if (b.Length != m_N) { throw new CryptoAsymmetricException("SparseTernaryPolynomial:Multiply", "Number of coefficients must be the same!", new FormatException()); } BigInteger[] c = new BigInteger[m_N]; for (int i = 0; i < m_N; i++) { c[i] = BigInteger.Zero; } for (int i = 0; i < m_ones.Length; i++) { int j = m_N - 1 - m_ones[i]; for (int k = m_N - 1; k >= 0; k--) { c[k] = c[k].Add(b[j]); j--; if (j < 0) { j = m_N - 1; } } } for (int i = 0; i < m_negOnes.Length; i++) { int j = m_N - 1 - m_negOnes[i]; for (int k = m_N - 1; k >= 0; k--) { c[k] = c[k].Subtract(b[j]); j--; if (j < 0) { j = m_N - 1; } } } return(new BigIntPolynomial(c)); }
/// <summary> /// Test the validity of the BigIntPolynomial implementation /// </summary> /// /// <returns>State</returns> public string Test() { try { BigIntPolynomial a = new BigIntPolynomial(new IntegerPolynomial(new int[] { 4, -1, 9, 2, 1, -5, 12, -7, 0, -9, 5 })); BigIntPolynomial b = new BigIntPolynomial(new IntegerPolynomial(new int[] { -6, 0, 0, 13, 3, -2, -4, 10, 11, 2, -1 })); BigIntPolynomial expected = new BigIntPolynomial(new IntegerPolynomial(new int[] { 2, -189, 77, 124, -29, 0, -75, 124, -49, 267, 34 })); if (!Compare.AreEqual(expected.Coeffs, a.MultSmall(b).Coeffs)) throw new Exception("BigIntPolynomial known value test failed!"); OnProgress(new TestEventArgs("Passed round 1 BigIntPolynomial known value")); if (!Compare.AreEqual(expected.Coeffs, a.MultBig(b).Coeffs)) throw new Exception("BigIntPolynomial known value test failed!"); OnProgress(new TestEventArgs("Passed round 2 BigIntPolynomial known value")); Random rng = new Random(); BigInteger[] aCoeffs = new BigInteger[10 + rng.Next(50)]; BigInteger[] bCoeffs = new BigInteger[aCoeffs.Length]; for (int i = 0; i < 3; i++) { for (int j = 0; j < aCoeffs.Length; j++) { byte[] aArr = new byte[600 + rng.Next(100)]; rng.NextBytes(aArr); aCoeffs[j] = new BigInteger(aArr); byte[] bArr = new byte[600 + rng.Next(100)]; rng.NextBytes(bArr); bCoeffs[j] = new BigInteger(bArr); } a = new BigIntPolynomial(aCoeffs); b = new BigIntPolynomial(bCoeffs); if (!Compare.AreEqual(a.MultSmall(b).Coeffs, a.MultBig(b).Coeffs)) throw new Exception("BigIntPolynomial coefficient comparison test failed!"); } OnProgress(new TestEventArgs("Passed BigIntPolynomial coefficient comparison")); return SUCCESS; } catch (Exception Ex) { string message = Ex.Message == null ? "" : Ex.Message; throw new Exception(FAILURE + message); } }
/// <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> /// Adds another polynomial which can have a different number of coefficients. /// </summary> /// /// <param name="B">The polynomial to add</param> public void Add(BigIntPolynomial B) { if (B.Coeffs.Length > Coeffs.Length) { int N = Coeffs.Length; Coeffs = Coeffs.CopyOf(B.Coeffs.Length); for (int i = N; i < Coeffs.Length; i++) { Coeffs[i] = BigInteger.Zero; } } for (int i = 0; i < B.Coeffs.Length; i++) { Coeffs[i] = Coeffs[i].Add(B.Coeffs[i]); } }
/** tests mult(IntegerPolynomial) and mult(BigIntPolynomial) */ private void MultTest() { CSPRng rng = new CSPRng(); SparseTernaryPolynomial p1 = SparseTernaryPolynomial.GenerateRandom(1000, 500, 500, rng); IntegerPolynomial p2 = PolynomialGeneratorForTesting.generateRandom(1000); IntegerPolynomial prod1 = p1.Multiply(p2); prod1 = p1.Multiply(p2); IntegerPolynomial prod2 = p1.Multiply(p2); if (!Compare.Equals(prod1, prod2)) throw new Exception("SparseTernaryPolynomial multiplication test failed!"); BigIntPolynomial p3 = new BigIntPolynomial(p2); BigIntPolynomial prod3 = p1.Multiply(p3); if (!Compare.Equals(new BigIntPolynomial(prod1), prod3)) throw new Exception("SparseTernaryPolynomial multiplication test failed!"); }
/// <summary> /// Multiplies the polynomial by another, taking the indices mod N. /// <para>Does not change this polynomial but returns the result as a new polynomial. /// Both polynomials must have the same number of coefficients. /// This method is designed for smaller polynomials and uses /// <a href="http://en.wikipedia.org/wiki/Karatsuba_algorithm">Karatsuba multiplication</a>.</para> /// </summary> /// /// <param name="Factor">he polynomial to multiply by</param> /// /// <returns>The product polynomial</returns> /// /// <exception cref="CryptoAsymmetricException">Throws if the two polynomials have a different number of coefficients</exception> public BigIntPolynomial MultSmall(BigIntPolynomial Factor) { int N = Coeffs.Length; if (Factor.Coeffs.Length != N) { throw new CryptoAsymmetricException("BigIntPolynomial:Multiply", "Number of coefficients must be the same!", new FormatException()); } BigIntPolynomial c = MultRecursive(Factor); if (c.Coeffs.Length > N) { for (int k = N; k < c.Coeffs.Length; k++) { c.Coeffs[k - N] = c.Coeffs[k - N].Add(c.Coeffs[k]); } c.Coeffs = c.Coeffs.CopyOf(N); } return(c); }
private int[] ToIntArray(BigIntPolynomial A, int K) { int N = A.Coeffs.Length; int sign = A.Coeffs[A.Degree()].Signum(); int[] aInt = new int[N * K]; for (int i = N - 1; i >= 0; i--) { int[] cArr = SchonhageStrassen.ToIntArray(A.Coeffs[i].Abs()); if (A.Coeffs[i].Signum() * sign < 0) { SubShifted(aInt, cArr, i * K); } else { AddShifted(aInt, cArr, i * K); } } return(aInt); }
/// <summary> /// Compare this big integer polynomial to another for equality /// </summary> /// /// <param name="Obj">Object to compare</param> /// /// <returns>True if equal, otherwise false</returns> public override bool Equals(Object Obj) { if (this == Obj) { return(true); } if (Obj == null) { return(false); } BigIntPolynomial other = (BigIntPolynomial)Obj; for (int i = 0; i < Coeffs.Length; i++) { if (!Coeffs[i].Equals(other.Coeffs[i])) { return(false); } } return(true); }
/// <summary> /// Test the validity of the BigDecimalPolynomial implementation /// </summary> /// /// <returns>State</returns> public string Test() { try { BigDecimalPolynomial a = CreateBigDecimalPolynomial(new int[] { 4, -1, 9, 2, 1, -5, 12, -7, 0, -9, 5 }); BigIntPolynomial b = new BigIntPolynomial(new IntegerPolynomial(new int[] { -6, 0, 0, 13, 3, -2, -4, 10, 11, 2, -1 })); BigDecimalPolynomial c = a.Multiply(b); if(!Compare.AreEqual(c.Coeffs, CreateBigDecimalPolynomial(new int[] { 2, -189, 77, 124, -29, 0, -75, 124, -49, 267, 34 }).Coeffs)) throw new Exception("The BigDecimalPolynomial test failed!"); // multiply a polynomial by its inverse modulo 2048 and check that the result is 1 IntegerPolynomial d, dInv; CSPRng rng = new CSPRng(); do { d = DenseTernaryPolynomial.GenerateRandom(1001, 333, 334, rng); dInv = d.InvertFq(2048); } while (dInv == null); d.Mod(2048); BigDecimalPolynomial e = CreateBigDecimalPolynomial(d.Coeffs); BigIntPolynomial f = new BigIntPolynomial(dInv); IntegerPolynomial g = new IntegerPolynomial(e.Multiply(f).Round()); g.ModPositive(2048); if (!g.EqualsOne()) throw new Exception("The BigDecimalPolynomial test failed!"); OnProgress(new TestEventArgs("Passed BigDecimalPolynomial tests")); return SUCCESS; } catch (Exception Ex) { string message = Ex.Message == null ? "" : Ex.Message; throw new Exception(FAILURE + message); } }
/// <summary> /// Stores the Rho and resultant values /// </summary> /// /// <param name="Rho">A polynomial such that <c>res = rho*this + t*(x^n-1) for some integer t</c></param> /// <param name="Res">A polynomial with <c>x^n-1</c> </param> public Resultant(BigIntPolynomial Rho, BigInteger Res) { this.Rho = Rho; this.Res = Res; }
/// <summary> /// Rounds all coefficients to the nearest integer /// </summary> /// /// <returns>A new polynomial with <c>BigInteger</c> coefficients</returns> public BigIntPolynomial Round() { int N = Coeffs.Length; BigIntPolynomial p = new BigIntPolynomial(N); for (int i = 0; i < N; i++) p.Coeffs[i] = Coeffs[i].SetScale(0, RoundingModes.HalfEven).ToBigInteger(); return p; }
/// <summary> /// Multiplies the polynomial by another, taking the indices mod N. /// <para>Does not change this polynomial but returns the result as a new polynomial. /// Both polynomials must have the same number of coefficients. /// This method uses the <a href="http://en.wikipedia.org/wiki/Schönhage–Strassen_algorithm"/> /// Schönhage–Strassen algorithm.</para> /// </summary> /// /// <param name="Factor">Multiplication factor</param> /// /// <returns>Multiplied polynomial</returns> /// /// <exception cref="NTRUException">Thrown if the two polynomials differ in the number of coefficients</exception> public BigDecimalPolynomial Multiply(BigIntPolynomial Factor) { if (Factor.Coeffs.Length != Coeffs.Length) throw new CryptoAsymmetricException("BigDecimalPolynomial:Multiply", "Number of coefficients must be the same!", new FormatException()); BigIntPolynomial poly1 = new BigIntPolynomial(Coeffs.Length); for (int i = 0; i < Coeffs.Length; i++) poly1.Coeffs[i] = Coeffs[i].UnScaledValue; int scale = Coeffs[0].Scale; BigIntPolynomial cBigInt = poly1.MultBig(Factor); BigDecimalPolynomial c = new BigDecimalPolynomial(cBigInt.Coeffs.Length); for (int i = 0; i < c.Coeffs.Length; i++) c.Coeffs[i] = new BigDecimal(cBigInt.Coeffs[i], scale); return c; }
/// <summary> /// Multiplies the polynomial by a <c>BigIntPolynomial</c>, taking the indices mod N. Does not /// change this polynomial but returns the result as a new polynomial. /// <para>Both polynomials must have the same number of coefficients.</para> /// </summary> /// /// <param name="Factor">The polynomial to multiply by</param> /// /// <returns>The product of the two polynomials</returns> public BigIntPolynomial Multiply(BigIntPolynomial Factor) { BigInteger[] b = Factor.Coeffs; if (b.Length != _N) throw new CryptoAsymmetricException("SparseTernaryPolynomial:Multiply", "Number of coefficients must be the same!", new FormatException()); BigInteger[] c = new BigInteger[_N]; for (int i = 0; i < _N; i++) c[i] = BigInteger.Zero; for (int i = 0; i < _ones.Length; i++) { int j = _N - 1 - _ones[i]; for (int k = _N - 1; k >= 0; k--) { c[k] = c[k].Add(b[j]); j--; if (j < 0) j = _N - 1; } } for (int i = 0; i < _negOnes.Length; i++) { int j = _N - 1 - _negOnes[i]; for (int k = _N - 1; k >= 0; k--) { c[k] = c[k].Subtract(b[j]); j--; if (j < 0) j = _N - 1; } } return new BigIntPolynomial(c); }
private int[] ToIntArray(BigIntPolynomial A, int K) { int N = A.Coeffs.Length; int sign = A.Coeffs[A.Degree()].Signum(); int[] aInt = new int[N * K]; for (int i = N - 1; i >= 0; i--) { int[] cArr = SchonhageStrassen.ToIntArray(A.Coeffs[i].Abs()); if (A.Coeffs[i].Signum() * sign < 0) SubShifted(aInt, cArr, i * K); else AddShifted(aInt, cArr, i * K); } return aInt; }
private BigIntPolynomial MultRecursive(BigIntPolynomial Factor) { // Karatsuba multiplication BigInteger[] a = Coeffs; BigInteger[] b = Factor.Coeffs; int n = Factor.Coeffs.Length; if (n <= 1) { BigInteger[] c = (BigInteger[])Coeffs.Clone(); for (int i = 0; i < Coeffs.Length; i++) c[i] = c[i].Multiply(Factor.Coeffs[0]); return new BigIntPolynomial(c); } else { int n1 = n / 2; BigIntPolynomial a1 = new BigIntPolynomial(a.CopyOf(n1)); BigIntPolynomial a2 = new BigIntPolynomial(a.CopyOfRange(n1, n)); BigIntPolynomial b1 = new BigIntPolynomial(b.CopyOf(n1)); BigIntPolynomial b2 = new BigIntPolynomial(b.CopyOfRange(n1, n)); BigIntPolynomial A = (BigIntPolynomial)a1.Clone(); A.Add(a2); BigIntPolynomial B = (BigIntPolynomial)b1.Clone(); B.Add(b2); BigIntPolynomial c1 = a1.MultRecursive(b1); BigIntPolynomial c2 = a2.MultRecursive(b2); BigIntPolynomial c3 = A.MultRecursive(B); c3.Subtract(c1); c3.Subtract(c2); BigIntPolynomial c = new BigIntPolynomial(2 * n - 1); for (int i = 0; i < c1.Coeffs.Length; i++) c.Coeffs[i] = c1.Coeffs[i]; for (int i = 0; i < c3.Coeffs.Length; i++) c.Coeffs[n1 + i] = c.Coeffs[n1 + i].Add(c3.Coeffs[i]); for (int i = 0; i < c2.Coeffs.Length; i++) c.Coeffs[2 * n1 + i] = c.Coeffs[2 * n1 + i].Add(c2.Coeffs[i]); return c; } }
/// <summary> /// Multiplies the polynomial by another, taking the indices mod N. /// <para>Does not change this polynomial but returns the result as a new polynomial. /// Both polynomials must have the same number of coefficients. /// This method is designed for large polynomials and uses Schönhage-Strassen multiplication /// in combination with <a href="http://en.wikipedia.org/wiki/Kronecker_substitution">Kronecker substitution</a>. /// See <a href="http://math.stackexchange.com/questions/58946/karatsuba-vs-schonhage-strassen-for-multiplication-of-polynomials#58955">here</a> for details.</para> /// </summary> /// /// <param name="Factor">The polynomial to multiply by</param> /// /// <returns>The product polynomial</returns> public BigIntPolynomial MultBig(BigIntPolynomial Factor) { int N = Coeffs.Length; // determine #bits needed per coefficient int logMinDigits = 32 - IntUtils.NumberOfLeadingZeros(N - 1); int maxLengthA = 0; for (int i = 0; i < Coeffs.Length; i++) { BigInteger coeff = Coeffs[i]; maxLengthA = Math.Max(maxLengthA, coeff.BitLength); } int maxLengthB = 0; for (int i = 0; i < Factor.Coeffs.Length; i++) { BigInteger coeff = Factor.Coeffs[i]; maxLengthB = Math.Max(maxLengthB, coeff.BitLength); } int k = logMinDigits + maxLengthA + maxLengthB + 1; // in bits k = (k + 31) / 32; // in ints // encode each polynomial into an int[] int aDeg = Degree(); int bDeg = Factor.Degree(); if (aDeg < 0 || bDeg < 0) { return(new BigIntPolynomial(N)); // return zero } int[] aInt = ToIntArray(this, k); int[] bInt = ToIntArray(Factor, k); int[] cInt = SchonhageStrassen.Multiply(aInt, bInt); // decode poly coefficients from the product BigInteger _2k = BigInteger.One.ShiftLeft(k * 32); BigIntPolynomial cPoly = new BigIntPolynomial(N); for (int i = 0; i < 2 * N - 1; i++) { int[] coeffInt = cInt.CopyOfRange(i * k, (i + 1) * k); BigInteger coeff = SchonhageStrassen.ToBigInteger(coeffInt); if (coeffInt[k - 1] < 0) { // if coeff > 2^(k-1) coeff = coeff.Subtract(_2k); // add 2^k to cInt which is the same as subtracting coeff bool carry = false; int cIdx = (i + 1) * k; do { cInt[cIdx]++; carry = cInt[cIdx] == 0; cIdx++; } while (carry); } cPoly.Coeffs[i % N] = cPoly.Coeffs[i % N].Add(coeff); } int aSign = Coeffs[aDeg].Signum(); int bSign = Factor.Coeffs[bDeg].Signum(); if (aSign * bSign < 0) { for (int i = 0; i < N; i++) { cPoly.Coeffs[i] = cPoly.Coeffs[i].Negate(); } } return(cPoly); }
/// <summary> /// Multiplies the polynomial by another, taking the indices mod N. /// <para>Does not change this polynomial but returns the result as a new polynomial. /// Both polynomials must have the same number of coefficients. /// This method is designed for large polynomials and uses Schönhage-Strassen multiplication /// in combination with <a href="http://en.wikipedia.org/wiki/Kronecker_substitution">Kronecker substitution</a>. /// See <a href="http://math.stackexchange.com/questions/58946/karatsuba-vs-schonhage-strassen-for-multiplication-of-polynomials#58955">here</a> for details.</para> /// </summary> /// /// <param name="Factor">The polynomial to multiply by</param> /// /// <returns>The product polynomial</returns> public BigIntPolynomial MultBig(BigIntPolynomial Factor) { int N = Coeffs.Length; // determine #bits needed per coefficient int logMinDigits = 32 - IntUtils.NumberOfLeadingZeros(N - 1); int maxLengthA = 0; for (int i = 0; i < Coeffs.Length; i++) { BigInteger coeff = Coeffs[i]; maxLengthA = Math.Max(maxLengthA, coeff.BitLength); } int maxLengthB = 0; for (int i = 0; i < Factor.Coeffs.Length; i++) { BigInteger coeff = Factor.Coeffs[i]; maxLengthB = Math.Max(maxLengthB, coeff.BitLength); } int k = logMinDigits + maxLengthA + maxLengthB + 1; // in bits k = (k + 31) / 32; // in ints // encode each polynomial into an int[] int aDeg = Degree(); int bDeg = Factor.Degree(); if (aDeg < 0 || bDeg < 0) return new BigIntPolynomial(N); // return zero int[] aInt = ToIntArray(this, k); int[] bInt = ToIntArray(Factor, k); int[] cInt = SchonhageStrassen.Multiply(aInt, bInt); // decode poly coefficients from the product BigInteger _2k = BigInteger.One.ShiftLeft(k * 32); BigIntPolynomial cPoly = new BigIntPolynomial(N); for (int i = 0; i < 2 * N - 1; i++) { int[] coeffInt = cInt.CopyOfRange(i * k, (i + 1) * k); BigInteger coeff = SchonhageStrassen.ToBigInteger(coeffInt); if (coeffInt[k - 1] < 0) { // if coeff > 2^(k-1) coeff = coeff.Subtract(_2k); // add 2^k to cInt which is the same as subtracting coeff bool carry = false; int cIdx = (i + 1) * k; do { cInt[cIdx]++; carry = cInt[cIdx] == 0; cIdx++; } while (carry); } cPoly.Coeffs[i % N] = cPoly.Coeffs[i % N].Add(coeff); } int aSign = Coeffs[aDeg].Signum(); int bSign = Factor.Coeffs[bDeg].Signum(); if (aSign * bSign < 0) { for (int i = 0; i < N; i++) cPoly.Coeffs[i] = cPoly.Coeffs[i].Negate(); } return cPoly; }
/// <summary> /// Multiplies the polynomial by an <c>IntegerPolynomial</c>, /// taking the indices mod <c>N</c>. /// </summary> /// /// <param name="Factor">A polynomial factor</param> /// /// <returns>The product of the two polynomials</returns> public BigIntPolynomial Multiply(BigIntPolynomial Factor) { BigIntPolynomial c = _f1.Multiply(Factor); c = _f2.Multiply(c); c.Add(_f3.Multiply(Factor)); return c; }
/// <summary> /// Instantiate the class /// </summary> /// /// <param name="Rho">Rho code</param> /// <param name="Res">Resultant</param> /// <param name="Modulus">Modulus</param> public ModularResultant(BigIntPolynomial Rho, BigInteger Res, BigInteger Modulus) : base(Rho, Res) { this.m_modulus = Modulus; }
/// <summary> /// Constructs a <c>IntegerPolynomial</c> from a <c>BigIntPolynomial</c>. The two polynomials are independent of each other /// </summary> /// /// <param name="P">The original polynomial</param> public IntegerPolynomial(BigIntPolynomial P) { Coeffs = new int[P.Coeffs.Length]; for (int i = 0; i < P.Coeffs.Length; i++) Coeffs[i] = P.Coeffs[i].ToInt32(); }
// 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!"); }
/// <summary> /// Multiplies the polynomial with another, taking the indices mod N /// </summary> /// /// <param name="Factor">The polynomial factor</param> /// /// <returns>Multiplied polynomial</returns> public BigIntPolynomial Multiply(BigIntPolynomial Factor) { return new BigIntPolynomial(this).MultSmall(Factor); }
/// <summary> /// Multiplies the polynomial by another, taking the indices mod N. /// <para>Does not change this polynomial but returns the result as a new polynomial. /// Both polynomials must have the same number of coefficients. /// This method is designed for smaller polynomials and uses /// <a href="http://en.wikipedia.org/wiki/Karatsuba_algorithm">Karatsuba multiplication</a>.</para> /// </summary> /// /// <param name="Factor">he polynomial to multiply by</param> /// /// <returns>The product polynomial</returns> /// /// <exception cref="CryptoAsymmetricException">Throws if the two polynomials have a different number of coefficients</exception> public BigIntPolynomial MultSmall(BigIntPolynomial Factor) { int N = Coeffs.Length; if (Factor.Coeffs.Length != N) throw new CryptoAsymmetricException("BigIntPolynomial:Multiply", "Number of coefficients must be the same!", new FormatException()); BigIntPolynomial c = MultRecursive(Factor); if (c.Coeffs.Length > N) { for (int k = N; k < c.Coeffs.Length; k++) c.Coeffs[k - N] = c.Coeffs[k - N].Add(c.Coeffs[k]); c.Coeffs = c.Coeffs.CopyOf(N); } return c; }
/// <summary> /// Instantiate the class /// </summary> /// /// <param name="Rho">Rho code</param> /// <param name="Res">Resultant</param> /// <param name="Modulus">Modulus</param> public ModularResultant(BigIntPolynomial Rho, BigInteger Res, BigInteger Modulus) : base(Rho, Res) { this._modulus = Modulus; }