org.bouncycastle.pqc.math.linearalgebra.GF2nONBField Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-jdk15on Show documentation
Show all versions of bcprov-ext-jdk15on Show documentation
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 JDK 1.5 to JDK 1.8. Note: this package includes the NTRU encryption algorithms.
The newest version!
package org.bouncycastle.pqc.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;
}
}