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

org.bouncycastle.pqc.legacy.math.linearalgebra.GF2nONBField 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.security.SecureRandom;
import java.util.Random;
import java.util.Vector;


/**
 * This class implements the abstract class GF2nField for ONB
 * representation. It computes the fieldpolynomial, multiplication matrix and
 * one of its roots mONBRoot, (see for example Certicoms Whitepapers).
 * GF2nField is used by GF2nONBElement which implements the elements of this
 * field.
 *
 * @see GF2nField
 * @see GF2nONBElement
 */
public class GF2nONBField
    extends GF2nField
{

    // ///////////////////////////////////////////////////////////////////
    // Hashtable for irreducible normal polynomials //
    // ///////////////////////////////////////////////////////////////////

    // i*5 + 0 i*5 + 1 i*5 + 2 i*5 + 3 i*5 + 4
    /*
     * private static int[][] mNB = {{0, 0, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 0},
     * {1, 0, 0}, // i = 0 {2, 0, 0}, {1, 0, 0}, {1, 0, 0}, {4, 3, 1}, {1, 0,
     * 0}, // i = 1 {3, 0, 0}, {2, 0, 0}, {3, 0, 0}, {4, 3, 1}, {5, 0, 0}, // i =
     * 2 {1, 0, 0}, {5, 3, 1}, {3, 0, 0}, {3, 0, 0}, {5, 2, 1}, // i = 3 {3, 0,
     * 0}, {2, 0, 0}, {1, 0, 0}, {5, 0, 0}, {4, 3, 1}, // i = 4 {3, 0, 0}, {4,
     * 3, 1}, {5, 2, 1}, {1, 0, 0}, {2, 0, 0}, // i = 5 {1, 0, 0}, {3, 0, 0},
     * {7, 3, 2}, {10, 0, 0}, {7, 0, 0}, // i = 6 {2, 0, 0}, {9, 0, 0}, {6, 4,
     * 1}, {6, 5, 1}, {4, 0, 0}, // i = 7 {5, 4, 3}, {3, 0, 0}, {7, 0, 0}, {6,
     * 4, 3}, {5, 0, 0}, // i = 8 {4, 3, 1}, {1, 0, 0}, {5, 0, 0}, {5, 3, 2},
     * {9, 0, 0}, // i = 9 {4, 3, 2}, {6, 3, 1}, {3, 0, 0}, {6, 2, 1}, {9, 0,
     * 0}, // i = 10 {7, 0, 0}, {7, 4, 2}, {4, 0, 0}, {19, 0, 0}, {7, 4, 2}, //
     * i = 11 {1, 0, 0}, {5, 2, 1}, {29, 0, 0}, {1, 0, 0}, {4, 3, 1}, // i = 12
     * {18, 0, 0}, {3, 0, 0}, {5, 2, 1}, {9, 0, 0}, {6, 5, 2}, // i = 13 {5, 3,
     * 1}, {6, 0, 0}, {10, 9, 3}, {25, 0, 0}, {35, 0, 0}, // i = 14 {6, 3, 1},
     * {21, 0, 0}, {6, 5, 2}, {6, 5, 3}, {9, 0, 0}, // i = 15 {9, 4, 2}, {4, 0,
     * 0}, {8, 3, 1}, {7, 4, 2}, {5, 0, 0}, // i = 16 {8, 2, 1}, {21, 0, 0},
     * {13, 0, 0}, {7, 6, 2}, {38, 0, 0}, // i = 17 {27, 0, 0}, {8, 5, 1}, {21,
     * 0, 0}, {2, 0, 0}, {21, 0, 0}, // i = 18 {11, 0, 0}, {10, 9, 6}, {6, 0,
     * 0}, {11, 0, 0}, {6, 3, 1}, // i = 19 {15, 0, 0}, {7, 6, 1}, {29, 0, 0},
     * {9, 0, 0}, {4, 3, 1}, // i = 20 {4, 0, 0}, {15, 0, 0}, {9, 7, 4}, {17, 0,
     * 0}, {5, 4, 2}, // i = 21 {33, 0, 0}, {10, 0, 0}, {5, 4, 3}, {9, 0, 0},
     * {5, 3, 2}, // i = 22 {8, 7, 5}, {4, 2, 1}, {5, 2, 1}, {33, 0, 0}, {8, 0,
     * 0}, // i = 23 {4, 3, 1}, {18, 0, 0}, {6, 2, 1}, {2, 0, 0}, {19, 0, 0}, //
     * i = 24 {7, 6, 5}, {21, 0, 0}, {1, 0, 0}, {7, 2, 1}, {5, 0, 0}, // i = 25
     * {3, 0, 0}, {8, 3, 2}, {17, 0, 0}, {9, 8, 2}, {57, 0, 0}, // i = 26 {11,
     * 0, 0}, {5, 3, 2}, {21, 0, 0}, {8, 7, 1}, {8, 5, 3}, // i = 27 {15, 0, 0},
     * {10, 4, 1}, {21, 0, 0}, {5, 3, 2}, {7, 4, 2}, // i = 28 {52, 0, 0}, {71,
     * 0, 0}, {14, 0, 0}, {27, 0, 0}, {10, 9, 7}, // i = 29 {53, 0, 0}, {3, 0,
     * 0}, {6, 3, 2}, {1, 0, 0}, {15, 0, 0}, // i = 30 {62, 0, 0}, {9, 0, 0},
     * {6, 5, 2}, {8, 6, 5}, {31, 0, 0}, // i = 31 {5, 3, 2}, {18, 0, 0 }, {27,
     * 0, 0}, {7, 6, 3}, {10, 8, 7}, // i = 32 {9, 8, 3}, {37, 0, 0}, {6, 0, 0},
     * {15, 3, 2}, {34, 0, 0}, // i = 33 {11, 0, 0}, {6, 5, 2}, {1, 0, 0}, {8,
     * 5, 2}, {13, 0, 0}, // i = 34 {6, 0, 0}, {11, 3, 2}, {8, 0, 0}, {31, 0,
     * 0}, {4, 2, 1}, // i = 35 {3, 0, 0}, {7, 6, 1}, {81, 0, 0}, {56, 0, 0},
     * {9, 8, 7}, // i = 36 {24, 0, 0}, {11, 0, 0}, {7, 6, 5}, {6, 5, 2}, {6, 5,
     * 2}, // i = 37 {8, 7, 6}, {9, 0, 0}, {7, 2, 1}, {15, 0, 0}, {87, 0, 0}, //
     * i = 38 {8, 3, 2}, {3, 0, 0}, {9, 4, 2}, {9, 0, 0}, {34, 0, 0}, // i = 39
     * {5, 3, 2}, {14, 0, 0}, {55, 0, 0}, {8, 7, 1}, {27, 0, 0}, // i = 40 {9,
     * 5, 2}, {10, 9, 5}, {43, 0, 0}, {8, 6, 2}, {6, 0, 0}, // i = 41 {7, 0, 0},
     * {11, 10, 8}, {105, 0, 0}, {6, 5, 2}, {73, 0, 0}}; // i = 42
     */
    // /////////////////////////////////////////////////////////////////////
    // member variables
    // /////////////////////////////////////////////////////////////////////
    private static final int MAXLONG = 64;

    /**
     * holds the length of the array-representation of degree mDegree.
     */
    private int mLength;

    /**
     * holds the number of relevant bits in mONBPol[mLength-1].
     */
    private int mBit;

    /**
     * holds the type of mONB
     */
    private int mType;

    /**
     * holds the multiplication matrix
     */
    int[][] mMult;

    // /////////////////////////////////////////////////////////////////////
    // constructors
    // /////////////////////////////////////////////////////////////////////

    /**
     * constructs an instance of the finite field with 2deg
     * elements and characteristic 2.
     *
     * @param deg    -the extention degree of this field
     * @param random - a source of randomness for generating polynomials on the field.
     */
    public GF2nONBField(int deg, SecureRandom random)
        throws RuntimeException
    {
        super(random);

        if (deg < 3)
        {
            throw new IllegalArgumentException("k must be at least 3");
        }

        mDegree = deg;
        mLength = mDegree / MAXLONG;
        mBit = mDegree & (MAXLONG - 1);
        if (mBit == 0)
        {
            mBit = MAXLONG;
        }
        else
        {
            mLength++;
        }

        computeType();

        // only ONB-implementations for type 1 and type 2
        //
        if (mType < 3)
        {
            mMult = new int[mDegree][2];
            for (int i = 0; i < mDegree; i++)
            {
                mMult[i][0] = -1;
                mMult[i][1] = -1;
            }
            computeMultMatrix();
        }
        else
        {
            throw new RuntimeException("\nThe type of this field is "
                + mType);
        }
        computeFieldPolynomial();
        fields = new Vector();
        matrices = new Vector();
    }

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

    int getONBLength()
    {
        return mLength;
    }

    int getONBBit()
    {
        return mBit;
    }

    // /////////////////////////////////////////////////////////////////////
    // arithmetic
    // /////////////////////////////////////////////////////////////////////

    /**
     * Computes a random root of the given polynomial.
     *
     * @param polynomial a polynomial
     * @return a random root of the polynomial
     * @see "P1363 A.5.6, p103f"
     */
    protected GF2nElement getRandomRoot(GF2Polynomial polynomial)
    {
        // We are in B1!!!
        GF2nPolynomial c;
        GF2nPolynomial ut;
        GF2nElement u;
        GF2nPolynomial h;
        int hDegree;
        // 1. Set g(t) <- f(t)
        GF2nPolynomial g = new GF2nPolynomial(polynomial, this);
        int gDegree = g.getDegree();
        int i;

        // 2. while deg(g) > 1
        while (gDegree > 1)
        {
            do
            {
                // 2.1 choose random u (element of) GF(2^m)
                u = new GF2nONBElement(this, random);
                ut = new GF2nPolynomial(2, GF2nONBElement.ZERO(this));
                // 2.2 Set c(t) <- ut
                ut.set(1, u);
                c = new GF2nPolynomial(ut);
                // 2.3 For i from 1 to m-1 do
                for (i = 1; i <= mDegree - 1; i++)
                {
                    // 2.3.1 c(t) <- (c(t)^2 + ut) mod g(t)
                    c = c.multiplyAndReduce(c, g);
                    c = c.add(ut);
                }
                // 2.4 set h(t) <- GCD(c(t), g(t))
                h = c.gcd(g);
                // 2.5 if h(t) is constant or deg(g) = deg(h) then go to
                // step 2.1
                hDegree = h.getDegree();
                gDegree = g.getDegree();
            }
            while ((hDegree == 0) || (hDegree == gDegree));
            // 2.6 If 2deg(h) > deg(g) then set g(t) <- g(t)/h(t) ...
            if ((hDegree << 1) > gDegree)
            {
                g = g.quotient(h);
            }
            else
            {
                // ... else g(t) <- h(t)
                g = new GF2nPolynomial(h);
            }
            gDegree = g.getDegree();
        }
        // 3. Output g(0)
        return g.at(0);

    }

    /**
     * Computes the change-of-basis matrix for basis conversion according to
     * 1363. The result is stored in the lists fields and matrices.
     *
     * @param B1 the GF2nField to convert to
     * @see "P1363 A.7.3, p111ff"
     */
    protected void computeCOBMatrix(GF2nField B1)
    {
        // we are in B0 here!
        if (mDegree != B1.mDegree)
        {
            throw new IllegalArgumentException(
                "GF2nField.computeCOBMatrix: B1 has a "
                    + "different degree and thus cannot be coverted to!");
        }
        int i, j;
        GF2nElement[] gamma;
        GF2nElement u;
        GF2Polynomial[] COBMatrix = new GF2Polynomial[mDegree];
        for (i = 0; i < mDegree; i++)
        {
            COBMatrix[i] = new GF2Polynomial(mDegree);
        }

        // find Random Root
        do
        {
            // u is in representation according to B1
            u = B1.getRandomRoot(fieldPolynomial);
        }
        while (u.isZero());

        gamma = new GF2nPolynomialElement[mDegree];
        // build gamma matrix by squaring
        gamma[0] = (GF2nElement)u.clone();
        for (i = 1; i < mDegree; i++)
        {
            gamma[i] = gamma[i - 1].square();
        }
        // convert horizontal gamma matrix by vertical Bitstrings
        for (i = 0; i < mDegree; i++)
        {
            for (j = 0; j < mDegree; j++)
            {
                if (gamma[i].testBit(j))
                {
                    COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1);
                }
            }
        }

        fields.addElement(B1);
        matrices.addElement(COBMatrix);
        B1.fields.addElement(this);
        B1.matrices.addElement(invertMatrix(COBMatrix));
    }

    /**
     * Computes the field polynomial for a ONB according to IEEE 1363 A.7.2
     * (p110f).
     *
     * @see "P1363 A.7.2, p110f"
     */
    protected void computeFieldPolynomial()
    {
        if (mType == 1)
        {
            fieldPolynomial = new GF2Polynomial(mDegree + 1, "ALL");
        }
        else if (mType == 2)
        {
            // 1. q = 1
            GF2Polynomial q = new GF2Polynomial(mDegree + 1, "ONE");
            // 2. p = t+1
            GF2Polynomial p = new GF2Polynomial(mDegree + 1, "X");
            p.addToThis(q);
            GF2Polynomial r;
            int i;
            // 3. for i = 1 to (m-1) do
            for (i = 1; i < mDegree; i++)
            {
                // r <- q
                r = q;
                // q <- p
                q = p;
                // p = tq+r
                p = q.shiftLeft();
                p.addToThis(r);
            }
            fieldPolynomial = p;
        }
    }

    /**
     * Compute the inverse of a matrix a.
     *
     * @param a the matrix
     * @return a-1
     */
    int[][] invMatrix(int[][] a)
    {

        int[][] A = new int[mDegree][mDegree];
        A = a;
        int[][] inv = new int[mDegree][mDegree];

        for (int i = 0; i < mDegree; i++)
        {
            inv[i][i] = 1;
        }

        for (int i = 0; i < mDegree; i++)
        {
            for (int j = i; j < mDegree; j++)
            {
                A[mDegree - 1 - i][j] = A[i][i];
            }
        }
        return null;
    }

    private void computeType()
        throws RuntimeException
    {
        if ((mDegree & 7) == 0)
        {
            throw new RuntimeException(
                "The extension degree is divisible by 8!");
        }
        // checking for the type
        int s = 0;
        int k = 0;
        mType = 1;
        for (int d = 0; d != 1; mType++)
        {
            s = mType * mDegree + 1;
            if (IntegerFunctions.isPrime(s))
            {
                k = IntegerFunctions.order(2, s);
                d = IntegerFunctions.gcd(mType * mDegree / k, mDegree);
            }
        }
        mType--;
        if (mType == 1)
        {
            s = (mDegree << 1) + 1;
            if (IntegerFunctions.isPrime(s))
            {
                k = IntegerFunctions.order(2, s);
                int d = IntegerFunctions.gcd((mDegree << 1) / k, mDegree);
                if (d == 1)
                {
                    mType++;
                }
            }
        }
    }

    private void computeMultMatrix()
    {

        if ((mType & 7) != 0)
        {
            int p = mType * mDegree + 1;

            // compute sequence F[1] ... F[p-1] via A.3.7. of 1363.
            // F[0] will not be filled!
            //
            int[] F = new int[p];

            int u;
            if (mType == 1)
            {
                u = 1;
            }
            else if (mType == 2)
            {
                u = p - 1;
            }
            else
            {
                u = elementOfOrder(mType, p);
            }

            int w = 1;
            int n;
            for (int j = 0; j < mType; j++)
            {
                n = w;

                for (int i = 0; i < mDegree; i++)
                {
                    F[n] = i;
                    n = (n << 1) % p;
                    if (n < 0)
                    {
                        n += p;
                    }
                }
                w = u * w % p;
                if (w < 0)
                {
                    w += p;
                }
            }

            // building the matrix (mDegree * 2)
            //
            if (mType == 1)
            {
                for (int k = 1; k < p - 1; k++)
                {
                    if (mMult[F[k + 1]][0] == -1)
                    {
                        mMult[F[k + 1]][0] = F[p - k];
                    }
                    else
                    {
                        mMult[F[k + 1]][1] = F[p - k];
                    }
                }

                int m_2 = mDegree >> 1;
                for (int k = 1; k <= m_2; k++)
                {

                    if (mMult[k - 1][0] == -1)
                    {
                        mMult[k - 1][0] = m_2 + k - 1;
                    }
                    else
                    {
                        mMult[k - 1][1] = m_2 + k - 1;
                    }

                    if (mMult[m_2 + k - 1][0] == -1)
                    {
                        mMult[m_2 + k - 1][0] = k - 1;
                    }
                    else
                    {
                        mMult[m_2 + k - 1][1] = k - 1;
                    }
                }
            }
            else if (mType == 2)
            {
                for (int k = 1; k < p - 1; k++)
                {
                    if (mMult[F[k + 1]][0] == -1)
                    {
                        mMult[F[k + 1]][0] = F[p - k];
                    }
                    else
                    {
                        mMult[F[k + 1]][1] = F[p - k];
                    }
                }
            }
            else
            {
                throw new RuntimeException("only type 1 or type 2 implemented");
            }
        }
        else
        {
            throw new RuntimeException("bisher nur fuer Gausssche Normalbasen"
                + " implementiert");
        }
    }

    private int elementOfOrder(int k, int p)
    {
        Random random = new Random();
        int m = 0;
        while (m == 0)
        {
            m = random.nextInt();
            m %= p - 1;
            if (m < 0)
            {
                m += p - 1;
            }
        }

        int l = IntegerFunctions.order(m, p);

        while (l % k != 0 || l == 0)
        {
            while (m == 0)
            {
                m = random.nextInt();
                m %= p - 1;
                if (m < 0)
                {
                    m += p - 1;
                }
            }
            l = IntegerFunctions.order(m, p);
        }
        int r = m;

        l = k / l;

        for (int i = 2; i <= l; i++)
        {
            r *= m;
        }

        return r;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy