/// <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 NTRUException("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 = _f1.Multiply(Factor); c = _f2.Multiply(c); c.Add(_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 != _N) { throw new NTRUException("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)); }
/// <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> /// 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._modulus; BigInteger mod2 = ModRes2._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> /// 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="NTRUException">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 NTRUException("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> /// 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); }
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> /// 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="NTRUException">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 NTRUException("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> /// 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> /// 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; }
/// <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 NTRUException("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); }
/// <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> /// 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(); }
/// <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 NTRUException("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; }
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; } }
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> /// 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> /// 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; }