All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.pqc.legacy.math.linearalgebra.GF2nPolynomialElement Maven / Gradle / Ivy

Go to download

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.

The newest version!
package org.bouncycastle.pqc.legacy.math.linearalgebra;


import java.math.BigInteger;
import java.util.Random;


/**
 * This class implements elements of finite binary fields GF(2n)
 * using polynomial representation. For more information on the arithmetic see
 * for example IEEE Standard 1363 or  Certicom online-tutorial.
 *
 * @see "GF2nField"
 * @see GF2nPolynomialField
 * @see GF2nONBElement
 * @see GF2Polynomial
 */
public class GF2nPolynomialElement
    extends GF2nElement
{

    // pre-computed Bitmask for fast masking, bitMask[a]=0x1 << a
    private static final int[] bitMask = {0x00000001, 0x00000002, 0x00000004,
        0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080,
        0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000,
        0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000,
        0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000,
        0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000,
        0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x00000000};

    // the used GF2Polynomial which stores the coefficients
    private GF2Polynomial polynomial;

    /**
     * Create a new random GF2nPolynomialElement using the given field and
     * source of randomness.
     *
     * @param f    the GF2nField to use
     * @param rand the source of randomness
     */
    public GF2nPolynomialElement(GF2nPolynomialField f, Random rand)
    {
        mField = f;
        mDegree = mField.getDegree();
        polynomial = new GF2Polynomial(mDegree);
        randomize(rand);
    }

    /**
     * Creates a new GF2nPolynomialElement using the given field and Bitstring.
     *
     * @param f  the GF2nPolynomialField to use
     * @param bs the desired value as Bitstring
     */
    public GF2nPolynomialElement(GF2nPolynomialField f, GF2Polynomial bs)
    {
        mField = f;
        mDegree = mField.getDegree();
        polynomial = new GF2Polynomial(bs);
        polynomial.expandN(mDegree);
    }

    /**
     * Creates a new GF2nPolynomialElement using the given field f and
     * byte[] os as value. The conversion is done according to 1363.
     *
     * @param f  the GF2nField to use
     * @param os the octet string to assign to this GF2nPolynomialElement
     * @see "P1363 5.5.5 p23, OS2FEP/OS2BSP"
     */
    public GF2nPolynomialElement(GF2nPolynomialField f, byte[] os)
    {
        mField = f;
        mDegree = mField.getDegree();
        polynomial = new GF2Polynomial(mDegree, os);
        polynomial.expandN(mDegree);
    }

    /**
     * Creates a new GF2nPolynomialElement using the given field f and
     * int[] is as value.
     *
     * @param f  the GF2nField to use
     * @param is the integer string to assign to this GF2nPolynomialElement
     */
    public GF2nPolynomialElement(GF2nPolynomialField f, int[] is)
    {
        mField = f;
        mDegree = mField.getDegree();
        polynomial = new GF2Polynomial(mDegree, is);
        polynomial.expandN(f.mDegree);
    }

    /**
     * Creates a new GF2nPolynomialElement by cloning the given
     * GF2nPolynomialElement b.
     *
     * @param other the GF2nPolynomialElement to clone
     */
    public GF2nPolynomialElement(GF2nPolynomialElement other)
    {
        mField = other.mField;
        mDegree = other.mDegree;
        polynomial = new GF2Polynomial(other.polynomial);
    }

    // /////////////////////////////////////////////////////////////////////
    // pseudo-constructors
    // /////////////////////////////////////////////////////////////////////

    /**
     * Creates a new GF2nPolynomialElement by cloning this
     * GF2nPolynomialElement.
     *
     * @return a copy of this element
     */
    public Object clone()
    {
        return new GF2nPolynomialElement(this);
    }

    // /////////////////////////////////////////////////////////////////////
    // assignments
    // /////////////////////////////////////////////////////////////////////

    /**
     * Assigns the value 'zero' to this Polynomial.
     */
    void assignZero()
    {
        polynomial.assignZero();
    }

    /**
     * Create the zero element.
     *
     * @param f the finite field
     * @return the zero element in the given finite field
     */
    public static GF2nPolynomialElement ZERO(GF2nPolynomialField f)
    {
        GF2Polynomial polynomial = new GF2Polynomial(f.getDegree());
        return new GF2nPolynomialElement(f, polynomial);
    }

    /**
     * Create the one element.
     *
     * @param f the finite field
     * @return the one element in the given finite field
     */
    public static GF2nPolynomialElement ONE(GF2nPolynomialField f)
    {
        GF2Polynomial polynomial = new GF2Polynomial(f.getDegree(),
            new int[]{1});
        return new GF2nPolynomialElement(f, polynomial);
    }

    /**
     * Assigns the value 'one' to this Polynomial.
     */
    void assignOne()
    {
        polynomial.assignOne();
    }

    /**
     * Assign a random value to this GF2nPolynomialElement using the specified
     * source of randomness.
     *
     * @param rand the source of randomness
     */
    private void randomize(Random rand)
    {
        polynomial.expandN(mDegree);
        polynomial.randomize(rand);
    }

    // /////////////////////////////////////////////////////////////////////
    // comparison
    // /////////////////////////////////////////////////////////////////////

    /**
     * Checks whether this element is zero.
     *
     * @return true if this is the zero element
     */
    public boolean isZero()
    {
        return polynomial.isZero();
    }

    /**
     * Tests if the GF2nPolynomialElement has 'one' as value.
     *
     * @return true if this equals one (this == 1)
     */
    public boolean isOne()
    {
        return polynomial.isOne();
    }

    /**
     * Compare this element with another object.
     *
     * @param other the other object
     * @return true if the two objects are equal, false
     * otherwise
     */
    public boolean equals(Object other)
    {
        if (other == null || !(other instanceof GF2nPolynomialElement))
        {
            return false;
        }
        GF2nPolynomialElement otherElem = (GF2nPolynomialElement)other;

        if (mField != otherElem.mField)
        {
            if (!mField.getFieldPolynomial().equals(
                otherElem.mField.getFieldPolynomial()))
            {
                return false;
            }
        }

        return polynomial.equals(otherElem.polynomial);
    }

    /**
     * @return the hash code of this element
     */
    public int hashCode()
    {
        return mField.hashCode() + polynomial.hashCode();
    }

    // /////////////////////////////////////////////////////////////////////
    // access
    // /////////////////////////////////////////////////////////////////////

    /**
     * Returns the value of this GF2nPolynomialElement in a new Bitstring.
     *
     * @return the value of this GF2nPolynomialElement in a new Bitstring
     */
    private GF2Polynomial getGF2Polynomial()
    {
        return new GF2Polynomial(polynomial);
    }

    /**
     * Checks whether the indexed bit of the bit representation is set.
     *
     * @param index the index of the bit to test
     * @return true if the indexed bit is set
     */
    boolean testBit(int index)
    {
        return polynomial.testBit(index);
    }

    /**
     * Returns whether the rightmost bit of the bit representation is set. This
     * is needed for data conversion according to 1363.
     *
     * @return true if the rightmost bit of this element is set
     */
    public boolean testRightmostBit()
    {
        return polynomial.testBit(0);
    }

    /**
     * Compute the sum of this element and addend.
     *
     * @param addend the addend
     * @return this + other (newly created)
     */
    public GFElement add(GFElement addend)
        throws RuntimeException
    {
        GF2nPolynomialElement result = new GF2nPolynomialElement(this);
        result.addToThis(addend);
        return result;
    }

    /**
     * Compute this + addend (overwrite this).
     *
     * @param addend the addend
     */
    public void addToThis(GFElement addend)
        throws RuntimeException
    {
        if (!(addend instanceof GF2nPolynomialElement))
        {
            throw new RuntimeException();
        }
        if (!mField.equals(((GF2nPolynomialElement)addend).mField))
        {
            throw new RuntimeException();
        }
        polynomial.addToThis(((GF2nPolynomialElement)addend).polynomial);
    }

    /**
     * Returns this element + 'one".
     *
     * @return this + 'one'
     */
    public GF2nElement increase()
    {
        GF2nPolynomialElement result = new GF2nPolynomialElement(this);
        result.increaseThis();
        return result;
    }

    /**
     * Increases this element by 'one'.
     */
    public void increaseThis()
    {
        polynomial.increaseThis();
    }

    /**
     * Compute the product of this element and factor.
     *
     * @param factor the factor
     * @return this * factor (newly created)
     */
    public GFElement multiply(GFElement factor)
        throws RuntimeException
    {
        GF2nPolynomialElement result = new GF2nPolynomialElement(this);
        result.multiplyThisBy(factor);
        return result;
    }

    /**
     * Compute this * factor (overwrite this).
     *
     * @param factor the factor
     */
    public void multiplyThisBy(GFElement factor)
        throws RuntimeException
    {
        if (!(factor instanceof GF2nPolynomialElement))
        {
            throw new RuntimeException();
        }
        if (!mField.equals(((GF2nPolynomialElement)factor).mField))
        {
            throw new RuntimeException();
        }
        if (equals(factor))
        {
            squareThis();
            return;
        }
        polynomial = polynomial
            .multiply(((GF2nPolynomialElement)factor).polynomial);
        reduceThis();
    }

    /**
     * Compute the multiplicative inverse of this element.
     *
     * @return this-1 (newly created)
     * @throws ArithmeticException if this is the zero element.
     * @see GF2nPolynomialElement#invertMAIA
     * @see GF2nPolynomialElement#invertEEA
     * @see GF2nPolynomialElement#invertSquare
     */
    public GFElement invert()
        throws ArithmeticException
    {
        return invertMAIA();
    }

    /**
     * Calculates the multiplicative inverse of this and returns the
     * result in a new GF2nPolynomialElement.
     *
     * @return this^(-1)
     * @throws ArithmeticException if this equals zero
     */
    public GF2nPolynomialElement invertEEA()
        throws ArithmeticException
    {
        if (isZero())
        {
            throw new ArithmeticException();
        }
        GF2Polynomial b = new GF2Polynomial(mDegree + 32, "ONE");
        b.reduceN();
        GF2Polynomial c = new GF2Polynomial(mDegree + 32);
        c.reduceN();
        GF2Polynomial u = getGF2Polynomial();
        GF2Polynomial v = mField.getFieldPolynomial();
        GF2Polynomial h;
        int j;
        u.reduceN();
        while (!u.isOne())
        {
            u.reduceN();
            v.reduceN();
            j = u.getLength() - v.getLength();
            if (j < 0)
            {
                h = u;
                u = v;
                v = h;
                h = b;
                b = c;
                c = h;
                j = -j;
                c.reduceN(); // this increases the performance
            }
            u.shiftLeftAddThis(v, j);
            b.shiftLeftAddThis(c, j);
        }
        b.reduceN();
        return new GF2nPolynomialElement((GF2nPolynomialField)mField, b);
    }

    /**
     * Calculates the multiplicative inverse of this and returns the
     * result in a new GF2nPolynomialElement.
     *
     * @return this^(-1)
     * @throws ArithmeticException if this equals zero
     */
    public GF2nPolynomialElement invertSquare()
        throws ArithmeticException
    {
        GF2nPolynomialElement n;
        GF2nPolynomialElement u;
        int i, j, k, b;

        if (isZero())
        {
            throw new ArithmeticException();
        }
        // b = (n-1)
        b = mField.getDegree() - 1;
        // n = a
        n = new GF2nPolynomialElement(this);
        n.polynomial.expandN((mDegree << 1) + 32); // increase performance
        n.polynomial.reduceN();
        // k = 1
        k = 1;

        // for i = (r-1) downto 0 do, r=bitlength(b)
        for (i = IntegerFunctions.floorLog(b) - 1; i >= 0; i--)
        {
            // u = n
            u = new GF2nPolynomialElement(n);
            // for j = 1 to k do
            for (j = 1; j <= k; j++)
            {
                // u = u^2
                u.squareThisPreCalc();
            }
            // n = nu
            n.multiplyThisBy(u);
            // k = 2k
            k <<= 1;
            // if b(i)==1
            if ((b & bitMask[i]) != 0)
            {
                // n = n^2 * b
                n.squareThisPreCalc();
                n.multiplyThisBy(this);
                // k = k+1
                k += 1;
            }
        }

        // outpur n^2
        n.squareThisPreCalc();
        return n;
    }

    /**
     * Calculates the multiplicative inverse of this using the modified
     * almost inverse algorithm and returns the result in a new
     * GF2nPolynomialElement.
     *
     * @return this^(-1)
     * @throws ArithmeticException if this equals zero
     */
    public GF2nPolynomialElement invertMAIA()
        throws ArithmeticException
    {
        if (isZero())
        {
            throw new ArithmeticException();
        }
        GF2Polynomial b = new GF2Polynomial(mDegree, "ONE");
        GF2Polynomial c = new GF2Polynomial(mDegree);
        GF2Polynomial u = getGF2Polynomial();
        GF2Polynomial v = mField.getFieldPolynomial();
        GF2Polynomial h;
        while (true)
        {
            while (!u.testBit(0))
            { // x|u (x divides u)
                u.shiftRightThis(); // u = u / x
                if (!b.testBit(0))
                {
                    b.shiftRightThis();
                }
                else
                {
                    b.addToThis(mField.getFieldPolynomial());
                    b.shiftRightThis();
                }
            }
            if (u.isOne())
            {
                return new GF2nPolynomialElement((GF2nPolynomialField)mField,
                    b);
            }
            u.reduceN();
            v.reduceN();
            if (u.getLength() < v.getLength())
            {
                h = u;
                u = v;
                v = h;
                h = b;
                b = c;
                c = h;
            }
            u.addToThis(v);
            b.addToThis(c);
        }
    }

    /**
     * This method is used internally to map the square()-calls within
     * GF2nPolynomialElement to one of the possible squaring methods.
     *
     * @return this2 (newly created)
     * @see GF2nPolynomialElement#squarePreCalc
     */
    public GF2nElement square()
    {
        return squarePreCalc();
    }

    /**
     * This method is used internally to map the square()-calls within
     * GF2nPolynomialElement to one of the possible squaring methods.
     */
    public void squareThis()
    {
        squareThisPreCalc();
    }

    /**
     * Squares this GF2nPolynomialElement using GF2nField's squaring matrix.
     * This is supposed to be fast when using a polynomial (no tri- or
     * pentanomial) as fieldpolynomial. Use squarePreCalc when using a tri- or
     * pentanomial as fieldpolynomial instead.
     *
     * @return this2 (newly created)
     * @see GF2Polynomial#vectorMult
     * @see GF2nPolynomialElement#squarePreCalc
     * @see GF2nPolynomialElement#squareBitwise
     */
    public GF2nPolynomialElement squareMatrix()
    {
        GF2nPolynomialElement result = new GF2nPolynomialElement(this);
        result.squareThisMatrix();
        result.reduceThis();
        return result;
    }

    /**
     * Squares this GF2nPolynomialElement using GF2nFields squaring matrix. This
     * is supposed to be fast when using a polynomial (no tri- or pentanomial)
     * as fieldpolynomial. Use squarePreCalc when using a tri- or pentanomial as
     * fieldpolynomial instead.
     *
     * @see GF2Polynomial#vectorMult
     * @see GF2nPolynomialElement#squarePreCalc
     * @see GF2nPolynomialElement#squareBitwise
     */
    public void squareThisMatrix()
    {
        GF2Polynomial result = new GF2Polynomial(mDegree);
        for (int i = 0; i < mDegree; i++)
        {
            if (polynomial
                .vectorMult(((GF2nPolynomialField)mField).squaringMatrix[mDegree
                    - i - 1]))
            {
                result.setBit(i);

            }
        }
        polynomial = result;
    }

    /**
     * Squares this GF2nPolynomialElement by shifting left its Bitstring and
     * reducing. This is supposed to be the slowest method. Use squarePreCalc or
     * squareMatrix instead.
     *
     * @return this2 (newly created)
     * @see GF2nPolynomialElement#squareMatrix
     * @see GF2nPolynomialElement#squarePreCalc
     * @see GF2Polynomial#squareThisBitwise
     */
    public GF2nPolynomialElement squareBitwise()
    {
        GF2nPolynomialElement result = new GF2nPolynomialElement(this);
        result.squareThisBitwise();
        result.reduceThis();
        return result;
    }

    /**
     * Squares this GF2nPolynomialElement by shifting left its Bitstring and
     * reducing. This is supposed to be the slowest method. Use squarePreCalc or
     * squareMatrix instead.
     *
     * @see GF2nPolynomialElement#squareMatrix
     * @see GF2nPolynomialElement#squarePreCalc
     * @see GF2Polynomial#squareThisBitwise
     */
    public void squareThisBitwise()
    {
        polynomial.squareThisBitwise();
        reduceThis();
    }

    /**
     * Squares this GF2nPolynomialElement by using precalculated values and
     * reducing. This is supposed to de fastest when using a trinomial or
     * pentanomial as field polynomial. Use squareMatrix when using a ordinary
     * polynomial as field polynomial.
     *
     * @return this2 (newly created)
     * @see GF2nPolynomialElement#squareMatrix
     * @see GF2Polynomial#squareThisPreCalc
     */
    public GF2nPolynomialElement squarePreCalc()
    {
        GF2nPolynomialElement result = new GF2nPolynomialElement(this);
        result.squareThisPreCalc();
        result.reduceThis();
        return result;
    }

    /**
     * Squares this GF2nPolynomialElement by using precalculated values and
     * reducing. This is supposed to de fastest when using a tri- or pentanomial
     * as fieldpolynomial. Use squareMatrix when using a ordinary polynomial as
     * fieldpolynomial.
     *
     * @see GF2nPolynomialElement#squareMatrix
     * @see GF2Polynomial#squareThisPreCalc
     */
    public void squareThisPreCalc()
    {
        polynomial.squareThisPreCalc();
        reduceThis();
    }

    /**
     * Calculates this to the power of k and returns the result
     * in a new GF2nPolynomialElement.
     *
     * @param k the power
     * @return this^k in a new GF2nPolynomialElement
     */
    public GF2nPolynomialElement power(int k)
    {
        if (k == 1)
        {
            return new GF2nPolynomialElement(this);
        }

        GF2nPolynomialElement result = GF2nPolynomialElement
            .ONE((GF2nPolynomialField)mField);
        if (k == 0)
        {
            return result;
        }

        GF2nPolynomialElement x = new GF2nPolynomialElement(this);
        x.polynomial.expandN((x.mDegree << 1) + 32); // increase performance
        x.polynomial.reduceN();

        for (int i = 0; i < mDegree; i++)
        {
            if ((k & (1 << i)) != 0)
            {
                result.multiplyThisBy(x);
            }
            x.square();
        }

        return result;
    }

    /**
     * Compute the square root of this element and return the result in a new
     * {@link GF2nPolynomialElement}.
     *
     * @return this1/2 (newly created)
     */
    public GF2nElement squareRoot()
    {
        GF2nPolynomialElement result = new GF2nPolynomialElement(this);
        result.squareRootThis();
        return result;
    }

    /**
     * Compute the square root of this element.
     */
    public void squareRootThis()
    {
        // increase performance
        polynomial.expandN((mDegree << 1) + 32);
        polynomial.reduceN();
        for (int i = 0; i < mField.getDegree() - 1; i++)
        {
            squareThis();
        }
    }

    /**
     * Solves the quadratic equation z2 + z = this if
     * such a solution exists. This method returns one of the two possible
     * solutions. The other solution is z + 1. Use z.increase() to
     * compute this solution.
     *
     * @return a GF2nPolynomialElement representing one z satisfying the
     * equation z2 + z = this
     * @see "IEEE 1363, Annex A.4.7"
     */
    public GF2nElement solveQuadraticEquation()
        throws RuntimeException
    {
        if (isZero())
        {
            return ZERO((GF2nPolynomialField)mField);
        }

        if ((mDegree & 1) == 1)
        {
            return halfTrace();
        }

        // TODO this can be sped-up by precomputation of p and w's
        GF2nPolynomialElement z, w;
        do
        {
            // step 1.
            GF2nPolynomialElement p = new GF2nPolynomialElement(
                (GF2nPolynomialField)mField, new Random());
            // step 2.
            z = ZERO((GF2nPolynomialField)mField);
            w = (GF2nPolynomialElement)p.clone();
            // step 3.
            for (int i = 1; i < mDegree; i++)
            {
                // compute z = z^2 + w^2 * this
                // and w = w^2 + p
                z.squareThis();
                w.squareThis();
                z.addToThis(w.multiply(this));
                w.addToThis(p);
            }
        }
        while (w.isZero()); // step 4.

        if (!equals(z.square().add(z)))
        {
            throw new RuntimeException();
        }

        // step 5.
        return z;
    }

    /**
     * Returns the trace of this GF2nPolynomialElement.
     *
     * @return the trace of this GF2nPolynomialElement
     */
    public int trace()
    {
        GF2nPolynomialElement t = new GF2nPolynomialElement(this);
        int i;

        for (i = 1; i < mDegree; i++)
        {
            t.squareThis();
            t.addToThis(this);
        }

        if (t.isOne())
        {
            return 1;
        }
        return 0;
    }

    /**
     * Returns the half-trace of this GF2nPolynomialElement.
     *
     * @return a GF2nPolynomialElement representing the half-trace of this
     * GF2nPolynomialElement.
     */
    private GF2nPolynomialElement halfTrace()
        throws RuntimeException
    {
        if ((mDegree & 0x01) == 0)
        {
            throw new RuntimeException();
        }
        int i;
        GF2nPolynomialElement h = new GF2nPolynomialElement(this);

        for (i = 1; i <= ((mDegree - 1) >> 1); i++)
        {
            h.squareThis();
            h.squareThis();
            h.addToThis(this);
        }

        return h;
    }

    /**
     * Reduces this GF2nPolynomialElement modulo the field-polynomial.
     *
     * @see GF2Polynomial#reduceTrinomial
     * @see GF2Polynomial#reducePentanomial
     */
    private void reduceThis()
    {
        if (polynomial.getLength() > mDegree)
        { // really reduce ?
            if (((GF2nPolynomialField)mField).isTrinomial())
            { // fieldpolonomial
                // is trinomial
                int tc;
                try
                {
                    tc = ((GF2nPolynomialField)mField).getTc();
                }
                catch (RuntimeException NATExc)
                {
                    throw new RuntimeException(
                        "GF2nPolynomialElement.reduce: the field"
                            + " polynomial is not a trinomial");
                }
                if (((mDegree - tc) <= 32) // do we have to use slow
                    // bitwise reduction ?
                    || (polynomial.getLength() > (mDegree << 1)))
                {
                    reduceTrinomialBitwise(tc);
                    return;
                }
                polynomial.reduceTrinomial(mDegree, tc);
                return;
            }
            else if (((GF2nPolynomialField)mField).isPentanomial())
            { // fieldpolynomial
                // is
                // pentanomial
                int[] pc;
                try
                {
                    pc = ((GF2nPolynomialField)mField).getPc();
                }
                catch (RuntimeException NATExc)
                {
                    throw new RuntimeException(
                        "GF2nPolynomialElement.reduce: the field"
                            + " polynomial is not a pentanomial");
                }
                if (((mDegree - pc[2]) <= 32) // do we have to use slow
                    // bitwise reduction ?
                    || (polynomial.getLength() > (mDegree << 1)))
                {
                    reducePentanomialBitwise(pc);
                    return;
                }
                polynomial.reducePentanomial(mDegree, pc);
                return;
            }
            else
            { // fieldpolynomial is something else
                polynomial = polynomial.remainder(mField.getFieldPolynomial());
                polynomial.expandN(mDegree);
                return;
            }
        }
        if (polynomial.getLength() < mDegree)
        {
            polynomial.expandN(mDegree);
        }
    }

    /**
     * Reduce this GF2nPolynomialElement using the trinomial x^n + x^tc + 1 as
     * fieldpolynomial. The coefficients are reduced bit by bit.
     */
    private void reduceTrinomialBitwise(int tc)
    {
        int i;
        int k = mDegree - tc;
        for (i = polynomial.getLength() - 1; i >= mDegree; i--)
        {
            if (polynomial.testBit(i))
            {

                polynomial.xorBit(i);
                polynomial.xorBit(i - k);
                polynomial.xorBit(i - mDegree);

            }
        }
        polynomial.reduceN();
        polynomial.expandN(mDegree);
    }

    /**
     * Reduce this GF2nPolynomialElement using the pentanomial x^n + x^pc[2] +
     * x^pc[1] + x^pc[0] + 1 as fieldpolynomial. The coefficients are reduced
     * bit by bit.
     */
    private void reducePentanomialBitwise(int[] pc)
    {
        int i;
        int k = mDegree - pc[2];
        int l = mDegree - pc[1];
        int m = mDegree - pc[0];
        for (i = polynomial.getLength() - 1; i >= mDegree; i--)
        {
            if (polynomial.testBit(i))
            {
                polynomial.xorBit(i);
                polynomial.xorBit(i - k);
                polynomial.xorBit(i - l);
                polynomial.xorBit(i - m);
                polynomial.xorBit(i - mDegree);

            }
        }
        polynomial.reduceN();
        polynomial.expandN(mDegree);
    }

    // /////////////////////////////////////////////////////////////////////
    // conversion
    // /////////////////////////////////////////////////////////////////////

    /**
     * Returns a string representing this Bitstrings value using hexadecimal
     * radix in MSB-first order.
     *
     * @return a String representing this Bitstrings value.
     */
    public String toString()
    {
        return polynomial.toString(16);
    }

    /**
     * Returns a string representing this Bitstrings value using hexadecimal or
     * binary radix in MSB-first order.
     *
     * @param radix the radix to use (2 or 16, otherwise 2 is used)
     * @return a String representing this Bitstrings value.
     */
    public String toString(int radix)
    {
        return polynomial.toString(radix);
    }

    /**
     * Converts this GF2nPolynomialElement to a byte[] according to 1363.
     *
     * @return a byte[] representing the value of this GF2nPolynomialElement
     * @see "P1363 5.5.2 p22f BS2OSP, FE2OSP"
     */
    public byte[] toByteArray()
    {
        return polynomial.toByteArray();
    }

    /**
     * Converts this GF2nPolynomialElement to an integer according to 1363.
     *
     * @return a BigInteger representing the value of this
     * GF2nPolynomialElement
     * @see "P1363 5.5.1 p22 BS2IP"
     */
    public BigInteger toFlexiBigInt()
    {
        return polynomial.toFlexiBigInt();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy