/// <summary>
 /// Creates a new GF2nPolynomialElement using the given field <c>Gf</c> and int[] <c>Is</c> as value
 /// </summary>
 /// 
 /// <param name="Gf">The GF2nField to use</param>
 /// <param name="Is">The integer string to assign to this GF2nPolynomialElement</param>
 public GF2nPolynomialElement(GF2nPolynomialField Gf, int[] Is)
 {
     mField = Gf;
     mDegree = mField.Degree;
     polynomial = new GF2Polynomial(mDegree, Is);
     polynomial.ExpandN(Gf.Degree);
 }
 /// <summary>
 /// Creates a new GF2nPolynomialElement using the given field <c>f</c> and byte[] <c>os</c> as value. 
 /// <para>The conversion is done according to 1363.</para>
 /// </summary>
 /// 
 /// <param name="Gf">The GF2nField to use</param>
 /// <param name="Os">The octet string to assign to this GF2nPolynomialElement</param>
 public GF2nPolynomialElement(GF2nPolynomialField Gf, byte[] Os)
 {
     mField = Gf;
     mDegree = mField.Degree;
     polynomial = new GF2Polynomial(mDegree, Os);
     polynomial.ExpandN(mDegree);
 }
 /// <summary>
 /// Creates a new GF2nPolynomialElement using the given field and Bitstring
 /// </summary>
 /// 
 /// <param name="Gf">The GF2nPolynomialField to use</param>
 /// <param name="Gp">The desired value as Bitstring</param>
 public GF2nPolynomialElement(GF2nPolynomialField Gf, GF2Polynomial Gp)
 {
     mField = Gf;
     mDegree = mField.Degree;
     polynomial = new GF2Polynomial(Gp);
     polynomial.ExpandN(mDegree);
 }
        /// <summary>
        /// Converts the given element in representation according to this field to a new element in 
        /// representation according to B1 using the change-of-basis matrix calculated by computeCOBMatrix.
        /// </summary>
        /// 
        /// <param name="Elem">The GF2nElement to convert</param>
        /// <param name="Basis">The basis to convert <c>Elem</c> to</param>
        /// 
        /// <returns>Returns <c>Elem</c> converted to a new element representation according to <c>basis</c></returns>
        public GF2nElement Convert(GF2nElement Elem, GF2nField Basis)
        {
            if (Basis == this)
                return (GF2nElement)Elem.Clone();
            if (FieldPoly.Equals(Basis.FieldPoly))
                return (GF2nElement)Elem.Clone();
            if (DegreeN != Basis.DegreeN)
                throw new Exception("GF2nField.Convert: B1 has a different degree and thus cannot be coverted to!");

            int i;
            GF2Polynomial[] COBMatrix;
            i = Fields.IndexOf(Basis);

            if (i == -1)
            {
                ComputeCOBMatrix(Basis);
                i = Fields.IndexOf(Basis);
            }
            COBMatrix = (GF2Polynomial[])Matrices[i];

            GF2nElement elemCopy = (GF2nElement)Elem.Clone();
            if (elemCopy is GF2nONBElement)
                ((GF2nONBElement)elemCopy).ReverseOrder();

            GF2Polynomial bs = new GF2Polynomial(DegreeN, elemCopy.ToFlexiBigInt());
            bs.ExpandN(DegreeN);
            GF2Polynomial result = new GF2Polynomial(DegreeN);
            for (i = 0; i < DegreeN; i++)
            {
                if (bs.VectorMult(COBMatrix[i]))
                    result.SetBit(DegreeN - 1 - i);
            }

            if (Basis is GF2nPolynomialField)
            {
                return new GF2nPolynomialElement((GF2nPolynomialField)Basis, result);
            }
            else if (Basis is GF2nONBField)
            {
                GF2nONBElement res = new GF2nONBElement((GF2nONBField)Basis, result.ToFlexiBigInt());
                res.ReverseOrder();

                return res;
            }
            else
            {
                throw new Exception("GF2nField.convert: B1 must be an instance of GF2nPolynomialField or GF2nONBField!");
            }
        }
        /// <summary>
        /// Reduces this GF2nPolynomialElement modulo the field-polynomial
        /// </summary>
        private void ReduceThis()
        {
            if (polynomial.Length > mDegree)
            { // really reduce ?
                if (((GF2nPolynomialField)mField).IsTrinomial)
                { // fieldpolonomial
                    // is trinomial
                    int tc;
                    try
                    {
                        tc = ((GF2nPolynomialField)mField).Tc;
                    }
                    catch (Exception NATExc)
                    {
                        throw new Exception("GF2nPolynomialElement.Reduce: the field polynomial is not a trinomial!");
                    }
                    // do we have to use slow bitwise reduction ?
                    if (((mDegree - tc) <= 32) || (polynomial.Length > (mDegree << 1)))
                    {
                        ReduceTrinomialBitwise(tc);
                        return;
                    }
                    polynomial.ReduceTrinomial(mDegree, tc);

                    return;
                }
                else if (((GF2nPolynomialField)mField).IsPentanomial) // fieldpolynomial is pentanomial
                {
                    int[] pc;
                    try
                    {
                        pc = ((GF2nPolynomialField)mField).Pc;
                    }
                    catch (Exception NATExc)
                    {
                        throw new Exception("GF2nPolynomialElement.Reduce: the field polynomial is not a pentanomial!");
                    }
                    // do we have to use slow bitwise reduction ?
                    if (((mDegree - pc[2]) <= 32) || (polynomial.Length > (mDegree << 1)))
                    {
                        ReducePentanomialBitwise(pc);
                        return;
                    }
                    polynomial.ReducePentanomial(mDegree, pc);

                    return;
                }
                else
                { // fieldpolynomial is something else
                    polynomial = polynomial.Remainder(mField.FieldPolynomial);
                    polynomial.ExpandN(mDegree);

                    return;
                }
            }

            if (polynomial.Length < mDegree)
                polynomial.ExpandN(mDegree);
        }
        /// <summary>
        /// Returns the absolute quotient of <c>this</c> divided by <c>G</c> in a new GF2Polynomial
        /// </summary>
        /// 
        /// <param name="G">A GF2Polynomial != 0</param>
        /// 
        /// <returns>Returns a new GF2Polynomial |_ <c>this</c> / <c>G</c></returns>
        public GF2Polynomial Quotient(GF2Polynomial G)
        {
            // a div b = q / r
            GF2Polynomial q = new GF2Polynomial(_length);
            GF2Polynomial a = new GF2Polynomial(this);
            GF2Polynomial b = new GF2Polynomial(G);
            GF2Polynomial j;
            int i;

            if (b.IsZero())
                throw new Exception();

            a.ReduceN();
            b.ReduceN();
            if (a._length < b._length)
                return new GF2Polynomial(0);

            i = a._length - b._length;
            q.ExpandN(i + 1);

            while (i >= 0)
            {
                j = b.ShiftLeft(i);
                a.SubtractFromThis(j);
                a.ReduceN();
                q.XorBit(i);
                i = a._length - b._length;
            }

            return q;
        }
        /// <summary>
        /// Multiplies this GF2Polynomial with <c>B</c> and returns the result in a new GF2Polynomial. 
        /// This method does not reduce the result in GF(2^N).
        /// This method uses Karatzuba multiplication.
        /// </summary>
        /// 
        /// <param name="B"> GF2Polynomial</param>
        /// 
        /// <returns>Returns a new GF2Polynomial (<c>this</c> * <c>B</c>)</returns>
        public GF2Polynomial Multiply(GF2Polynomial B)
        {
            int n = Math.Max(_length, B._length);
            ExpandN(n);
            B.ExpandN(n);

            return KaraMult(B);
        }
        /// <summary>
        /// Divides <c>this</c> by <c>G</c> and returns the quotient and remainder in a new GF2Polynomial[2], quotient in [0], remainder in [1]
        /// </summary>
        /// 
        /// <param name="G">A GF2Polynomial != 0</param>
        /// 
        /// <returns>Returns a new GF2Polynomial[2] containing quotient and remainder</returns>
        public GF2Polynomial[] Divide(GF2Polynomial G)
        {
            // a div b = q / r
            GF2Polynomial[] result = new GF2Polynomial[2];
            GF2Polynomial q = new GF2Polynomial(_length);
            GF2Polynomial a = new GF2Polynomial(this);
            GF2Polynomial b = new GF2Polynomial(G);
            GF2Polynomial j;
            int i;

            if (b.IsZero())
                throw new Exception();

            a.ReduceN();
            b.ReduceN();

            if (a._length < b._length)
            {
                result[0] = new GF2Polynomial(0);
                result[1] = a;
                return result;
            }

            i = a._length - b._length;
            q.ExpandN(i + 1);

            while (i >= 0)
            {
                j = b.ShiftLeft(i);
                a.SubtractFromThis(j);
                a.ReduceN();
                q.XorBit(i);
                i = a._length - b._length;
            }

            result[0] = q;
            result[1] = a;

            return result;
        }