/// <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>
        /// 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;
        }
        private void SubAndTest()
        {
            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);
            a.SubAnd(b, 2047);
            i1.Subtract(i2);
            i1.ModPositive(2048);

            if (!Compare.AreEqual(a.ToIntegerPolynomial().Coeffs, i1.Coeffs))
                throw new Exception("LongPolynomial2 SubAnd test failed!");
        }
        private void Mult2AndTest()
        {
            IntegerPolynomial i1 = new IntegerPolynomial(new int[] { 1368, 2047, 672, 871, 1662, 1352, 1099, 1608 });
            LongPolynomial2 i2 = new LongPolynomial2(i1);
            i2.Mult2And(2047);
            i1.Multiply(2);
            i1.ModPositive(2048);

            if (!Compare.AreEqual(i1.Coeffs, i2.ToIntegerPolynomial().Coeffs))
                throw new Exception("LongPolynomial2 Mult2And test failed!");
        }