/// <summary> /// Makes a copy of the polynomial that is independent of the original. /// </summary> /// <returns>The cloned polynomial</returns> public LongPolynomial2 Clone() { LongPolynomial2 p = new LongPolynomial2((long[])Coeffs.Clone()); p._numCoeffs = _numCoeffs; return p; }
/// <summary> /// Makes a copy of the polynomial that is independent of the original. /// </summary> /// <returns>The cloned polynomial</returns> public LongPolynomial2 Clone() { LongPolynomial2 p = new LongPolynomial2((long[])Coeffs.Clone()); p._numCoeffs = _numCoeffs; return(p); }
/// <summary> /// Subtracts another polynomial which must have the same number of coefficients, /// and applies an AND mask to the upper and lower halves of each coefficients. /// </summary> /// /// <param name="B">Another polynomial</param> /// <param name="Mask">A bit mask less than 2048 to apply to each 11-bit coefficient</param> public void SubAnd(LongPolynomial2 B, int Mask) { long longMask = (((long)Mask) << 24) + Mask; for (int i = 0; i < B.Coeffs.Length; i++) { Coeffs[i] = (0x0800000800000L + Coeffs[i] - B.Coeffs[i]) & longMask; } }
private void Subtract(LongPolynomial2 B) { // Subtracts another polynomial which can have a different number of coefficients if (B.Coeffs.Length > Coeffs.Length) { Coeffs = Coeffs.CopyOf(B.Coeffs.Length); } for (int i = 0; i < B.Coeffs.Length; i++) { Coeffs[i] = (0x0800000800000L + Coeffs[i] - B.Coeffs[i]) & 0x7FF0007FFL; } }
private void Add(LongPolynomial2 B) { // Adds another polynomial which can have a different number of coefficients. if (B.Coeffs.Length > Coeffs.Length) { Coeffs = Coeffs.CopyOf(B.Coeffs.Length); } for (int i = 0; i < B.Coeffs.Length; i++) { Coeffs[i] = (Coeffs[i] + B.Coeffs[i]) & 0x7FF0007FFL; } }
/// <summary> /// Multiplies the polynomial with another, taking the indices mod N and the values mod 2048. /// </summary> /// /// <param name="Factor">The polynomial factor</param> public LongPolynomial2 Multiply(LongPolynomial2 Factor) { int N = Coeffs.Length; if (Factor.Coeffs.Length != N || _numCoeffs != Factor._numCoeffs) { throw new NTRUException("LongPolynomial2:Multiply", "Number of coefficients must be the same!", new FormatException()); } LongPolynomial2 c = MultRecursive(Factor); if (c.Coeffs.Length > N) { if (_numCoeffs % 2 == 0) { for (int k = N; k < c.Coeffs.Length; k++) { c.Coeffs[k - N] = (c.Coeffs[k - N] + c.Coeffs[k]) & 0x7FF0007FFL; } c.Coeffs = c.Coeffs.CopyOf(N); } else { for (int k = N; k < c.Coeffs.Length; k++) { c.Coeffs[k - N] = c.Coeffs[k - N] + (c.Coeffs[k - 1] >> 24); c.Coeffs[k - N] = c.Coeffs[k - N] + ((c.Coeffs[k] & 2047) << 24); c.Coeffs[k - N] &= 0x7FF0007FFL; } c.Coeffs = c.Coeffs.CopyOf(N); c.Coeffs[c.Coeffs.Length - 1] &= 2047; } } c = new LongPolynomial2(c.Coeffs); c._numCoeffs = _numCoeffs; return(c); }
private void Subtract(LongPolynomial2 B) { // Subtracts another polynomial which can have a different number of coefficients if (B.Coeffs.Length > Coeffs.Length) Coeffs = Coeffs.CopyOf(B.Coeffs.Length); for (int i = 0; i < B.Coeffs.Length; i++) Coeffs[i] = (0x0800000800000L + Coeffs[i] - B.Coeffs[i]) & 0x7FF0007FFL; }
private LongPolynomial2 MultRecursive(LongPolynomial2 Poly2) { // Karatsuba multiplication long[] a = Coeffs; long[] b = Poly2.Coeffs; int n = Poly2.Coeffs.Length; if (n <= 32) { int cn = 2 * n; LongPolynomial2 c = new LongPolynomial2(new long[cn]); for (int k = 0; k < cn; k++) { for (int i = Math.Max(0, k - n + 1); i <= Math.Min(k, n - 1); i++) { long c0 = a[k - i] * b[i]; long cu = c0 & 0x7FF000000L + (c0 & 2047); long co = IntUtils.URShift(c0, 48) & 2047; c.Coeffs[k] = (c.Coeffs[k] + cu) & 0x7FF0007FFL; c.Coeffs[k + 1] = (c.Coeffs[k + 1] + co) & 0x7FF0007FFL; } } return c; } else { int n1 = n / 2; LongPolynomial2 a1 = new LongPolynomial2(a.CopyOf(n1)); LongPolynomial2 a2 = new LongPolynomial2(a.CopyOfRange(n1, n)); LongPolynomial2 b1 = new LongPolynomial2(b.CopyOf(n1)); LongPolynomial2 b2 = new LongPolynomial2(b.CopyOfRange(n1, n)); LongPolynomial2 A = a1.Clone(); A.Add(a2); LongPolynomial2 B = b1.Clone(); B.Add(b2); LongPolynomial2 c1 = a1.MultRecursive(b1); LongPolynomial2 c2 = a2.MultRecursive(b2); LongPolynomial2 c3 = A.MultRecursive(B); c3.Subtract(c1); c3.Subtract(c2); LongPolynomial2 c = new LongPolynomial2(2 * n); for (int i = 0; i < c1.Coeffs.Length; i++) c.Coeffs[i] = c1.Coeffs[i] & 0x7FF0007FFL; for (int i = 0; i < c3.Coeffs.Length; i++) c.Coeffs[n1 + i] = (c.Coeffs[n1 + i] + c3.Coeffs[i]) & 0x7FF0007FFL; for (int i = 0; i < c2.Coeffs.Length; i++) c.Coeffs[2 * n1 + i] = (c.Coeffs[2 * n1 + i] + c2.Coeffs[i]) & 0x7FF0007FFL; return c; } }
private void Add(LongPolynomial2 B) { // Adds another polynomial which can have a different number of coefficients. if (B.Coeffs.Length > Coeffs.Length) Coeffs = Coeffs.CopyOf(B.Coeffs.Length); for (int i = 0; i < B.Coeffs.Length; i++) Coeffs[i] = (Coeffs[i] + B.Coeffs[i]) & 0x7FF0007FFL; }
/// <summary> /// Subtracts another polynomial which must have the same number of coefficients, /// and applies an AND mask to the upper and lower halves of each coefficients. /// </summary> /// /// <param name="B">Another polynomial</param> /// <param name="Mask">A bit mask less than 2048 to apply to each 11-bit coefficient</param> public void SubAnd(LongPolynomial2 B, int Mask) { long longMask = (((long)Mask) << 24) + Mask; for (int i = 0; i < B.Coeffs.Length; i++) Coeffs[i] = (0x0800000800000L + Coeffs[i] - B.Coeffs[i]) & longMask; }
/// <summary> /// Multiplies the polynomial with another, taking the indices mod N and the values mod 2048. /// </summary> /// /// <param name="Factor">The polynomial factor</param> public LongPolynomial2 Multiply(LongPolynomial2 Factor) { int N = Coeffs.Length; if (Factor.Coeffs.Length != N || _numCoeffs != Factor._numCoeffs) throw new NTRUException("LongPolynomial2:Multiply", "Number of coefficients must be the same!", new FormatException()); LongPolynomial2 c = MultRecursive(Factor); if (c.Coeffs.Length > N) { if (_numCoeffs % 2 == 0) { for (int k = N; k < c.Coeffs.Length; k++) c.Coeffs[k - N] = (c.Coeffs[k - N] + c.Coeffs[k]) & 0x7FF0007FFL; c.Coeffs = c.Coeffs.CopyOf(N); } else { for (int k = N; k < c.Coeffs.Length; k++) { c.Coeffs[k - N] = c.Coeffs[k - N] + (c.Coeffs[k - 1] >> 24); c.Coeffs[k - N] = c.Coeffs[k - N] + ((c.Coeffs[k] & 2047) << 24); c.Coeffs[k - N] &= 0x7FF0007FFL; } c.Coeffs = c.Coeffs.CopyOf(N); c.Coeffs[c.Coeffs.Length - 1] &= 2047; } } c = new LongPolynomial2(c.Coeffs); c._numCoeffs = _numCoeffs; return c; }
/// <summary> /// Computes the inverse mod <c>q</c> from the inverse mod 2. /// <para>The algorithm is described in <a href="http://www.securityinnovation.com/uploads/Crypto/NTRUTech014.pdf"> /// Almost Inverses and Fast NTRU Key Generation</a>.</para> /// </summary> /// /// <param name="Fq">Fq value</param> /// <param name="Q">Q value</param> /// /// <returns>The inverse of this polynomial mod q</returns> private IntegerPolynomial Mod2ToModq(IntegerPolynomial Fq, int Q) { if (SystemUtils.Is64Bit() && Q == 2048) { LongPolynomial2 thisLong = new LongPolynomial2(this); LongPolynomial2 FqLong = new LongPolynomial2(Fq); int v = 2; while (v < Q) { v *= 2; LongPolynomial2 temp = FqLong.Clone(); temp.Mult2And(v - 1); FqLong = thisLong.Multiply(FqLong).Multiply(FqLong); temp.SubAnd(FqLong, v - 1); FqLong = temp; } return FqLong.ToIntegerPolynomial(); } else { int v = 2; while (v < Q) { v *= 2; IntegerPolynomial temp = Fq.Clone(); temp.Mult2(v); Fq = Multiply(Fq, v).Multiply(Fq, v); temp.Subtract(Fq, v); Fq = temp; } return Fq; } }
private LongPolynomial2 MultRecursive(LongPolynomial2 Poly2) { // Karatsuba multiplication long[] a = Coeffs; long[] b = Poly2.Coeffs; int n = Poly2.Coeffs.Length; if (n <= 32) { int cn = 2 * n; LongPolynomial2 c = new LongPolynomial2(new long[cn]); for (int k = 0; k < cn; k++) { for (int i = Math.Max(0, k - n + 1); i <= Math.Min(k, n - 1); i++) { long c0 = a[k - i] * b[i]; long cu = c0 & 0x7FF000000L + (c0 & 2047); long co = IntUtils.URShift(c0, 48) & 2047; c.Coeffs[k] = (c.Coeffs[k] + cu) & 0x7FF0007FFL; c.Coeffs[k + 1] = (c.Coeffs[k + 1] + co) & 0x7FF0007FFL; } } return(c); } else { int n1 = n / 2; LongPolynomial2 a1 = new LongPolynomial2(a.CopyOf(n1)); LongPolynomial2 a2 = new LongPolynomial2(a.CopyOfRange(n1, n)); LongPolynomial2 b1 = new LongPolynomial2(b.CopyOf(n1)); LongPolynomial2 b2 = new LongPolynomial2(b.CopyOfRange(n1, n)); LongPolynomial2 A = a1.Clone(); A.Add(a2); LongPolynomial2 B = b1.Clone(); B.Add(b2); LongPolynomial2 c1 = a1.MultRecursive(b1); LongPolynomial2 c2 = a2.MultRecursive(b2); LongPolynomial2 c3 = A.MultRecursive(B); c3.Subtract(c1); c3.Subtract(c2); LongPolynomial2 c = new LongPolynomial2(2 * n); for (int i = 0; i < c1.Coeffs.Length; i++) { c.Coeffs[i] = c1.Coeffs[i] & 0x7FF0007FFL; } for (int i = 0; i < c3.Coeffs.Length; i++) { c.Coeffs[n1 + i] = (c.Coeffs[n1 + i] + c3.Coeffs[i]) & 0x7FF0007FFL; } for (int i = 0; i < c2.Coeffs.Length; i++) { c.Coeffs[2 * n1 + i] = (c.Coeffs[2 * n1 + i] + c2.Coeffs[i]) & 0x7FF0007FFL; } return(c); } }