private void MultTest() { IntegerPolynomial i1 = new IntegerPolynomial(new int[] { 1368, 2047, 672, 871, 1662, 1352, 1099, 1608 }); IntegerPolynomial i2 = new IntegerPolynomial(new int[] { 1729, 1924, 806, 179, 1530, 1381, 1695, 60 }); LongPolynomial2 a = new LongPolynomial2(i1); LongPolynomial2 b = new LongPolynomial2(i2); IntegerPolynomial c1 = i1.Multiply(i2, 2048); IntegerPolynomial c2 = a.Multiply(b).ToIntegerPolynomial(); if (!Compare.AreEqual(c1.Coeffs, c2.Coeffs)) throw new Exception("LongPolynomial2 multiply test failed!"); // test 10 random polynomials Random rng = new Random(); for (int i = 0; i < 10; i++) { int N = 2 + rng.Next(2000); i1 = (IntegerPolynomial)PolynomialGeneratorForTesting.GenerateRandom(N, 2048); i2 = (IntegerPolynomial)PolynomialGeneratorForTesting.GenerateRandom(N, 2048); a = new LongPolynomial2(i1); b = new LongPolynomial2(i2); c1 = i1.Multiply(i2); c1.ModPositive(2048); c2 = a.Multiply(b).ToIntegerPolynomial(); if (!Compare.AreEqual(c1.Coeffs, c2.Coeffs)) throw new Exception("LongPolynomial2 multiply test failed!"); } }
/// <summary> /// Read a Public Key from a Stream /// </summary> /// /// <param name="KeyStream">An input stream containing an encoded key</param> /// /// <exception cref="CryptoAsymmetricException">Thrown if the key could not be loaded</exception> public NTRUPublicKey(Stream KeyStream) { try { _N = IntUtils.ReadShort(KeyStream); _Q = IntUtils.ReadShort(KeyStream); _H = IntegerPolynomial.FromBinary(KeyStream, N, Q); } catch (Exception ex) { throw new CryptoAsymmetricException("NTRUPublicKey:CTor", "The Public key could not be loaded!", ex); } }
/// <summary> /// Constructs a <c>LongPolynomial2</c> from a <c>IntegerPolynomial</c>. The two polynomials are independent of each other. /// </summary> /// <param name="P">The original polynomial. Coefficients must be between 0 and 2047.</param> public LongPolynomial2(IntegerPolynomial P) { _numCoeffs = P.Coeffs.Length; Coeffs = new long[(_numCoeffs + 1) / 2]; int idx = 0; for (int pIdx = 0; pIdx < _numCoeffs; ) { int c0 = P.Coeffs[pIdx++]; while (c0 < 0) c0 += 2048; long c1 = pIdx < _numCoeffs ? P.Coeffs[pIdx++] : 0; while (c1 < 0) c1 += 2048; Coeffs[idx] = c0 + (c1 << 24); idx++; } }
/// <summary> /// Constructs a <c>LongPolynomial5</c> from a <c>IntegerPolynomial</c>. The two polynomials are independent of each other. /// </summary> /// /// <param name="P">The original polynomial. Coefficients must be between 0 and 2047.</param> public LongPolynomial5(IntegerPolynomial P) { _numCoeffs = P.Coeffs.Length; _coeffs = new long[(_numCoeffs + 4) / 5]; int cIdx = 0; int shift = 0; for (int i = 0; i < _numCoeffs; i++) { _coeffs[cIdx] |= ((long)P.Coeffs[i]) << shift; shift += 12; if (shift >= 60) { shift = 0; cIdx++; } } }
/// <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> /// Resultant of this polynomial with <c>x^n-1 mod p</c>. /// </summary> /// /// <param name="P">P value</param> /// /// <returns>Returns <c>(rho, res)</c> satisfying <c>res = rho*this + t*(x^n-1) mod p</c> for some integer <c>t</c>.</returns> public ModularResultant Resultant(int P) { // Add a coefficient as the following operations involve polynomials of degree deg(f)+1 int[] fcoeffs = Coeffs.CopyOf(Coeffs.Length + 1); IntegerPolynomial f = new IntegerPolynomial(fcoeffs); int N = fcoeffs.Length; IntegerPolynomial a = new IntegerPolynomial(N); a.Coeffs[0] = -1; a.Coeffs[N - 1] = 1; IntegerPolynomial b = new IntegerPolynomial(f.Coeffs); IntegerPolynomial v1 = new IntegerPolynomial(N); IntegerPolynomial v2 = new IntegerPolynomial(N); v2.Coeffs[0] = 1; int da = N - 1; int db = b.Degree(); int ta = da; int c = 0; int r = 1; while (db > 0) { c = Invert(b.Coeffs[db], P); c = (c * a.Coeffs[da]) % P; a.MultShiftSub(b, c, da - db, P); v1.MultShiftSub(v2, c, da - db, P); da = a.Degree(); if (da < db) { r *= Pow(b.Coeffs[db], ta - da, P); r %= P; if (ta % 2 == 1 && db % 2 == 1) r = (-r) % P; IntegerPolynomial temp = a; a = b; b = temp; int tempdeg = da; da = db; temp = v1; v1 = v2; v2 = temp; ta = db; db = tempdeg; } } r *= Pow(b.Coeffs[0], da, P); r %= P; c = Invert(b.Coeffs[0], P); v2.Multiply(c); v2.Mod(P); v2.Multiply(r); v2.Mod(P); // drop the highest coefficient so #coeffs matches the original input v2.Coeffs = v2.Coeffs.CopyOf(v2.Coeffs.Length - 1); return new ModularResultant(new BigIntPolynomial(v2), BigInteger.ValueOf(r), BigInteger.ValueOf(P)); }
/// <summary> /// Subtracts another polynomial which must not have more coefficients than <c>this</c> polynomial. /// </summary> /// /// <param name="B">The polynomial to subtract</param> public void Subtract(IntegerPolynomial B) { for (int i = 0; i < B.Coeffs.Length; i++) Coeffs[i] -= B.Coeffs[i]; }
/// <summary> /// Multiplies the polynomial with another, taking the values mod modulus and the indices mod N /// </summary> /// /// <param name="Factor">The polynomial factor</param> /// <param name="Modulus">The Modulus</param> /// /// <returns>Multiplied polynomial</returns> public new IntegerPolynomial Multiply(IntegerPolynomial Factor, int Modulus) { // even on 32-bit systems, LongPolynomial5 multiplies faster than IntegerPolynomial if (Modulus == 2048) { IntegerPolynomial poly2Pos = Factor.Clone(); poly2Pos.ModPositive(2048); LongPolynomial5 poly5 = new LongPolynomial5(poly2Pos); return poly5.Multiply(this).ToIntegerPolynomial(); } else { return base.Multiply(Factor, Modulus); } }
private void GenerateFQ(IRandom Rng, out IPolynomial t, out IntegerPolynomial fq, out IntegerPolynomial fp) { int N = _ntruParams.N; int q = _ntruParams.Q; int df = _ntruParams.DF; int df1 = _ntruParams.DF1; int df2 = _ntruParams.DF2; int df3 = _ntruParams.DF3; bool fastFp = _ntruParams.FastFp; bool sparse = _ntruParams.Sparse; TernaryPolynomialType polyType = _ntruParams.PolyType; fp = null; // choose a random f that is invertible mod 3 and q while (true) { IntegerPolynomial f; // choose random t, calculate f and fp if (fastFp) { // if fastFp=true, f is always invertible mod 3 if (polyType == TernaryPolynomialType.SIMPLE) t = PolynomialGenerator.GenerateRandomTernary(N, df, df, sparse, Rng); else t = ProductFormPolynomial.GenerateRandom(N, df1, df2, df3, df3, Rng); f = t.ToIntegerPolynomial(); f.Multiply(3); f.Coeffs[0] += 1; } else { if (polyType == TernaryPolynomialType.SIMPLE) t = PolynomialGenerator.GenerateRandomTernary(N, df, df - 1, sparse, Rng); else t = ProductFormPolynomial.GenerateRandom(N, df1, df2, df3, df3 - 1, Rng); f = t.ToIntegerPolynomial(); fp = f.InvertF3(); if (fp == null) continue; } fq = f.InvertFq(q); if (fq != null) break; } }
/// <summary> /// Constructs a new private key from a polynomial /// </summary> /// /// <param name="T">The polynomial which determines the key: if <c>FastFp=true</c>, <c>f=1+3T</c>; otherwise, <c>f=T</c></param> /// <param name="FP">Fp the inverse of <c>f</c></param> /// <param name="N">The number of polynomial coefficients</param> /// <param name="Q">The big q modulus</param> /// <param name="Sparse">Sparse whether the polynomial <c>T</c> is sparsely or densely populated</param> /// <param name="FastFp">FastFp whether <c>FP=1</c></param> /// <param name="PolyType">PolyType type of the polynomial <c>T</c></param> internal NTRUPrivateKey(IPolynomial T, IntegerPolynomial FP, int N, int Q, bool Sparse, bool FastFp, TernaryPolynomialType PolyType) { _T = T; _FP = FP; _N = N; _Q = Q; _sparse = Sparse; _fastFp = FastFp; _polyType = PolyType; }
/// <summary> /// Constructs a <c>DenseTernaryPolynomial</c> from a <c>IntegerPolynomial</c>. /// <para>The two polynomials are independent of each other.</para> /// </summary> /// /// <param name="IntPoly">The original polynomial></param> public SparseTernaryPolynomial(IntegerPolynomial IntPoly) : this(IntPoly.Coeffs) { }
/// <summary> /// Multiplies the polynomial by an <c>IntegerPolynomial</c>, /// taking the coefficient values mod <c>modulus</c> and the indices mod <c>N</c>. /// </summary> /// /// <param name="Factor">A polynomial factor</param> /// <param name="Modulus">The modulus to apply</param> /// /// <returns>The product of the two polynomials</returns> public IntegerPolynomial Multiply(IntegerPolynomial Factor, int Modulus) { IntegerPolynomial c = Multiply(Factor); c.Mod(Modulus); return c; }
/// <remarks> /// Computes this-b*c*(x^k) mod p and stores the result in this polynomial. /// </remarks> private void MultShiftSub(IntegerPolynomial B, int C, int K, int P) { int N = Coeffs.Length; for (int i = K; i < N; i++) Coeffs[i] = (Coeffs[i] - B.Coeffs[i - K] * C) % P; }
/// <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; } }
/// <summary> /// Computes 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> /// /// <returns>Returns <c>null</c> if the polynomial is not invertible.</returns> private IntegerPolynomial InvertF2() { int N = Coeffs.Length; int k = 0; IntegerPolynomial b = new IntegerPolynomial(N + 1); b.Coeffs[0] = 1; IntegerPolynomial c = new IntegerPolynomial(N + 1); IntegerPolynomial f = new IntegerPolynomial(Coeffs.CopyOf(N + 1)); f.Mod2(); // set g(x) = x^N − 1 IntegerPolynomial g = new IntegerPolynomial(N + 1); g.Coeffs[0] = 1; g.Coeffs[N] = 1; while (true) { while (f.Coeffs[0] == 0) { for (int i = 1; i <= N; i++) { f.Coeffs[i - 1] = f.Coeffs[i]; // f(x) = f(x) / x c.Coeffs[N + 1 - i] = c.Coeffs[N - i]; // c(x) = c(x) * x } f.Coeffs[N] = 0; c.Coeffs[0] = 0; k++; if (f.EqualsZero()) return null; // not invertible } if (f.EqualsOne()) break; if (f.Degree() < g.Degree()) { // exchange f and g IntegerPolynomial temp = f; f = g; g = temp; // exchange b and c temp = b; b = c; c = temp; } f.Add(g); f.Mod2(); b.Add(c); b.Mod2(); } if (b.Coeffs[N] != 0) return null; // Fq(x) = x^(N-k) * b(x) IntegerPolynomial Fq = new IntegerPolynomial(N); int j = 0; k %= N; for (int i = N - 1; i >= 0; i--) { j = i - k; if (j < 0) j += N; Fq.Coeffs[j] = b.Coeffs[i]; } return Fq; }
private IntegerPolynomial MultRecursive(IntegerPolynomial Factor) { int[] a = Coeffs; int[] b = Factor.Coeffs; int n = Factor.Coeffs.Length; if (n <= 32) { int cn = 2 * n - 1; IntegerPolynomial c = new IntegerPolynomial(new int[cn]); for (int k = 0; k < cn; k++) { for (int i = Math.Max(0, k - n + 1); i <= Math.Min(k, n - 1); i++) c.Coeffs[k] += b[i] * a[k - i]; } return c; } else { int n1 = n / 2; IntegerPolynomial a1 = new IntegerPolynomial(a.CopyOf(n1)); IntegerPolynomial a2 = new IntegerPolynomial(a.CopyOfRange(n1, n)); IntegerPolynomial b1 = new IntegerPolynomial(b.CopyOf(n1)); IntegerPolynomial b2 = new IntegerPolynomial(b.CopyOfRange(n1, n)); // make a copy of a1 that is the same length as a2 IntegerPolynomial A = new IntegerPolynomial(a1.Coeffs.CopyOf(a2.Coeffs.Length)); A.Add(a2); // make a copy of b1 that is the same length as b2 IntegerPolynomial B = new IntegerPolynomial(b1.Coeffs.CopyOf(b2.Coeffs.Length)); B.Add(b2); IntegerPolynomial c1 = a1.MultRecursive(b1); IntegerPolynomial c2 = a2.MultRecursive(b2); IntegerPolynomial c3 = A.MultRecursive(B); c3.Subtract(c1); c3.Subtract(c2); IntegerPolynomial c = new IntegerPolynomial(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] += c3.Coeffs[i]; for (int i = 0; i < c2.Coeffs.Length; i++) c.Coeffs[2 * n1 + i] += c2.Coeffs[i]; return c; } }
/// <summary> /// Constructs a new public key from a polynomial /// </summary> /// /// <param name="H">The polynomial <c>H</c> which determines the key</param> /// <param name="N">The number of coefficients in the polynomial <c>H</c></param> /// <param name="Q">The "big" NtruEncrypt modulus</param> internal NTRUPublicKey(IntegerPolynomial H, int N, int Q) { _H = H; _N = N; _Q = Q; }
/// <summary> /// Constructs a <c>BigIntPolynomial</c> from a <c>IntegerPolynomial</c>. The two polynomials are /// independent of each other. /// </summary> /// /// <param name="P">The original polynomial</param> public BigIntPolynomial(IntegerPolynomial P) { Coeffs = new BigInteger[P.Coeffs.Length]; for (int i = 0; i < Coeffs.Length; i++) Coeffs[i] = BigInteger.ValueOf(P.Coeffs[i]); }
/// <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 IntegerPolynomial Multiply(IntegerPolynomial Factor) { IntegerPolynomial c = _f1.Multiply(Factor); c = _f2.Multiply(c); c.Add(_f3.Multiply(Factor)); return c; }
/// <summary> /// Generates a seed for the Blinding Polynomial Generation Function /// </summary> /// /// <param name="Message">The plain-text message</param> /// <param name="PubKey">The public key</param> /// <param name="Bits">Bits of random data</param> /// /// <returns>A byte array containing a seed value</returns> private byte[] GetSeed(byte[] Message, IntegerPolynomial PubKey, byte[] Bits) { byte[] oid = _encParams.OId; byte[] hTrunc = PubKey.ToBinaryTrunc(_encParams.Q, _encParams.PkLen / 8); // sData = OID|m|b|hTrunc byte[] sData = new byte[oid.Length + Message.Length + Bits.Length + hTrunc.Length]; Array.Copy(oid, 0, sData, 0, oid.Length); int start = oid.Length; Array.Copy(Message, 0, sData, start, Message.Length); start += Message.Length; Array.Copy(Bits, 0, sData, start, Bits.Length); start += Bits.Length; Array.Copy(hTrunc, 0, sData, start, hTrunc.Length); return sData; }
/// <summary> /// Subtracts another polynomial which can have a different number of coefficients, /// and takes the coefficient values mod <c>modulus</c>. /// </summary> /// /// <param name="B">The polynomial to subtract</param> /// <param name="Modulus">The modulus</param> private void Subtract(IntegerPolynomial B, int Modulus) { Subtract(B); Mod(Modulus); }
/// <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 IntegerPolynomial Multiply(IntegerPolynomial Factor) { int[] b = Factor.Coeffs; if (b.Length != _N) throw new CryptoAsymmetricException("SparseTernaryPolynomial:Multiply", "Number of coefficients must be the same!", new FormatException()); int[] c = new int[_N]; for (int i = 0; i < _ones.Length; i++) { int j = _N - 1 - _ones[i]; for (int k = _N - 1; k >= 0; k--) { c[k] += 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] -= b[j]; j--; if (j < 0) j = _N - 1; } } return new IntegerPolynomial(c); }
/// <summary> /// Decrypts an integer polynomial /// </summary> /// /// <param name="E">Encrypted polynomial</param> /// <param name="PrivT">A polynomial such that if <c>fastFp=true</c>, <c>f=1+3*priv_t</c>; otherwise, <c>f=priv_t</c></param> /// <param name="PrivFp">Fp</param> /// /// <returns>Derypted polynomial</returns> private IntegerPolynomial Decrypt(IntegerPolynomial E, IPolynomial PrivT, IntegerPolynomial PrivFp) { int q = _encParams.Q; IntegerPolynomial a; if (_encParams.FastFp) { a = PrivT.Multiply(E, q); a.Multiply(3); a.Add(E); } else { a = PrivT.Multiply(E, q); } a.Center0(q); a.Mod3(); IntegerPolynomial c = _encParams.FastFp ? a : new DenseTernaryPolynomial(a).Multiply(PrivFp, 3); c.Center0(3); return c; }
/// <summary> /// Adds another polynomial /// </summary> /// <param name="B">The polynomial to add</param> //p public void Add(IntegerPolynomial B) { for (int i = 0; i < B.Coeffs.Length; i++) Coeffs[i] += B.Coeffs[i]; }
/// <summary> /// An implementation of MGF-TP-1 from P1363.1 section 8.4.1.1. /// </summary> /// /// <param name="Seed">The seed value</param> /// <param name="N">N paramater</param> /// <param name="MinCallsMask">Minimum Calls Mask</param> /// <param name="HashSeed">Whether to hash the seed</param> /// /// <returns></returns> private IntegerPolynomial MGF(byte[] Seed, int N, int MinCallsMask, bool HashSeed) { int hashLen = _dgtEngine.DigestSize; using (MemoryStream writer = new MemoryStream(MinCallsMask * hashLen)) { byte[] Z = HashSeed ? _dgtEngine.ComputeHash(Seed) : Seed; int counter = 0; while (counter < MinCallsMask) { byte[] data = new byte[Z.Length + 4]; Buffer.BlockCopy(Z, 0, data, 0, Z.Length); Buffer.BlockCopy(IntUtils.IntToBytes(counter), 0, data, Z.Length, 4); byte[] hash = _dgtEngine.ComputeHash(data); writer.Write(hash, 0, hash.Length); counter++; } IntegerPolynomial i = new IntegerPolynomial(N); while (true) { int cur = 0; byte[] buffer = writer.ToArray(); for (int j = 0; j < buffer.Length; j++) { int O = (int)buffer[j] & 0xFF; if (O >= 243) // 243 = 3^5 continue; for (int terIdx = 0; terIdx < 4; terIdx++) { int rem3 = O % 3; i.Coeffs[cur] = rem3 == 2 ? -1 : rem3; // reduce to [-1..1] cur++; if (cur == N) return i; O = (O - rem3) / 3; } i.Coeffs[cur] = O == 2 ? -1 : O; // reduce to [-1..1] cur++; if (cur == N) return i; } if (cur >= N) return i; // reset the memory writer.SetLength(0); writer.SetLength(hashLen); // get the hash byte[] hash = _dgtEngine.ComputeHash(ArrayUtils.Concat(Z, IntUtils.IntToBytes(counter))); writer.Write(hash, 0, hash.Length); counter++; } } }
/// <summary> /// Adds another polynomial which must not have more coefficients than <c>this</c> /// polynomial, and takes the coefficient values mod <c>modulus</c>. /// </summary> /// /// <param name="B">The polynomial to add</param> /// <param name="Modulus">The modulus</param> public void Add(IntegerPolynomial B, int Modulus) { Add(B); Mod(Modulus); }
private void Initialize() { // Initializes fp from t if (_fastFp) { _FP = new IntegerPolynomial(N); _FP.Coeffs[0] = 1; } else { _FP = T.ToIntegerPolynomial().InvertF3(); } }
/// <summary> /// Computes the inverse mod 3. /// <para>Returns <c>null</c> if the polynomial is not invertible. /// 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> /// /// <returns>A new polynomial, or <c>null</c> if no inverse exists</returns> public IntegerPolynomial InvertF3() { int N = Coeffs.Length; int k = 0; IntegerPolynomial b = new IntegerPolynomial(N + 1); b.Coeffs[0] = 1; IntegerPolynomial c = new IntegerPolynomial(N + 1); IntegerPolynomial f = new IntegerPolynomial(N + 1); f.Coeffs = Coeffs.CopyOf(N + 1); f.ModPositive(3); // set g(x) = x^N − 1 IntegerPolynomial g = new IntegerPolynomial(N + 1); g.Coeffs[0] = -1; g.Coeffs[N] = 1; while (true) { while (f.Coeffs[0] == 0) { for (int i = 1; i <= N; i++) { f.Coeffs[i - 1] = f.Coeffs[i]; // f(x) = f(x) / x c.Coeffs[N + 1 - i] = c.Coeffs[N - i]; // c(x) = c(x) * x } f.Coeffs[N] = 0; c.Coeffs[0] = 0; k++; if (f.EqualsZero()) return null; // not invertible } if (f.EqualsAbsOne()) break; if (f.Degree() < g.Degree()) { // exchange f and g IntegerPolynomial temp = f; f = g; g = temp; // exchange b and c temp = b; b = c; c = temp; } if (f.Coeffs[0] == g.Coeffs[0]) { f.Subtract(g, 3); b.Subtract(c, 3); } else { f.Add(g, 3); b.Add(c, 3); } } if (b.Coeffs[N] != 0) return null; // Fp(x) = [+-] x^(N-k) * b(x) IntegerPolynomial Fp = new IntegerPolynomial(N); int j = 0; k %= N; for (int i = N - 1; i >= 0; i--) { j = i - k; if (j < 0) j += N; Fp.Coeffs[j] = f.Coeffs[0] * b.Coeffs[i]; } Fp.EnsurePositive(3); return Fp; }
/// <summary> /// Generates a new encryption key pair /// </summary> /// /// <param name="RngF">The random number generator to use for generating the secret polynomial f</param> /// <param name="RngG">The random number generator to use for generating the secret polynomial g</param> /// /// <returns>A key pair</returns> private IAsymmetricKeyPair GenerateKeyPair(IRandom RngF, IRandom RngG) { int N = _ntruParams.N; int q = _ntruParams.Q; bool fastFp = _ntruParams.FastFp; bool sparse = _ntruParams.Sparse; TernaryPolynomialType polyType = _ntruParams.PolyType; IPolynomial t = null; IntegerPolynomial fq = null; IntegerPolynomial fp = null; IntegerPolynomial g = null; if (ParallelUtils.IsParallel && _isParallel) { Action[] gA = new Action[] { new Action(()=> g = GenerateG(RngG)), new Action(()=> GenerateFQ(RngF, out t, out fq, out fp)) }; Parallel.Invoke(gA); } else { // Choose a random g that is invertible mod q. g = GenerateG(RngG); // choose a random f that is invertible mod 3 and q GenerateFQ(RngF, out t, out fq, out fp); } // if fastFp=true, fp=1 if (fastFp) { fp = new IntegerPolynomial(N); fp.Coeffs[0] = 1; } IntegerPolynomial h = g.Multiply(fq, q); h.Mult3(q); h.EnsurePositive(q); NTRUPrivateKey priv = new NTRUPrivateKey(t, fp, N, q, sparse, fastFp, polyType); NTRUPublicKey pub = new NTRUPublicKey(h, N, q); return new NTRUKeyPair(pub, priv); }
/// <summary> /// Multiplies the polynomial with another, taking the indices mod N /// </summary> /// <param name="Factor">The polynomial factor</param> /// /// <returns>Multiplied polynomial</returns> public IntegerPolynomial Multiply(IntegerPolynomial Factor) { int N = Coeffs.Length; if (Factor.Coeffs.Length != N) throw new CryptoAsymmetricException("IntegerPolynomial:Multiply", "Number of coefficients must be the same!", new FormatException()); IntegerPolynomial c = MultRecursive(Factor); if (c.Coeffs.Length > N) { for (int k = N; k < c.Coeffs.Length; k++) c.Coeffs[k - N] += c.Coeffs[k]; c.Coeffs = c.Coeffs.CopyOf(N); } return c; }