package org.bouncycastle.pqc.math.linearalgebra;

This class describes some operations with matrices over finite field GF(2m) with small m (1< m <32).
See Also:
  • Matrix
/** * This class describes some operations with matrices over finite field <i>GF(2<sup>m</sup>)</i> * with small <i>m</i> (1&lt; m &lt;32). * * @see Matrix */
public class GF2mMatrix extends Matrix {
finite field GF(2^m)
/** * finite field GF(2^m) */
protected GF2mField field;
For the matrix representation the array of type int[][] is used, thus every element of the array keeps one element of the matrix (element from finite field GF(2^m))
/** * For the matrix representation the array of type int[][] is used, thus * every element of the array keeps one element of the matrix (element from * finite field GF(2^m)) */
protected int[][] matrix;
Constructor.
Params:
  • field – a finite field GF(2^m)
  • enc – byte[] matrix in byte array form
/** * Constructor. * * @param field a finite field GF(2^m) * @param enc byte[] matrix in byte array form */
public GF2mMatrix(GF2mField field, byte[] enc) { this.field = field; // decode matrix int d = 8; int count = 1; while (field.getDegree() > d) { count++; d += 8; } if (enc.length < 5) { throw new IllegalArgumentException( " Error: given array is not encoded matrix over GF(2^m)"); } this.numRows = ((enc[3] & 0xff) << 24) ^ ((enc[2] & 0xff) << 16) ^ ((enc[1] & 0xff) << 8) ^ (enc[0] & 0xff); int n = count * this.numRows; if ((this.numRows <= 0) || (((enc.length - 4) % n) != 0)) { throw new IllegalArgumentException( " Error: given array is not encoded matrix over GF(2^m)"); } this.numColumns = (enc.length - 4) / n; matrix = new int[this.numRows][this.numColumns]; count = 4; for (int i = 0; i < this.numRows; i++) { for (int j = 0; j < this.numColumns; j++) { for (int jj = 0; jj < d; jj += 8) { matrix[i][j] ^= (enc[count++] & 0x000000ff) << jj; } if (!this.field.isElementOfThisField(matrix[i][j])) { throw new IllegalArgumentException( " Error: given array is not encoded matrix over GF(2^m)"); } } } }
Copy constructor.
Params:
/** * Copy constructor. * * @param other another {@link GF2mMatrix} */
public GF2mMatrix(GF2mMatrix other) { numRows = other.numRows; numColumns = other.numColumns; field = other.field; matrix = new int[numRows][]; for (int i = 0; i < numRows; i++) { matrix[i] = IntUtils.clone(other.matrix[i]); } }
Constructor.
Params:
  • field – a finite field GF(2^m)
  • matrix – the matrix as int array. Only the reference is copied.
/** * Constructor. * * @param field a finite field GF(2^m) * @param matrix the matrix as int array. Only the reference is copied. */
protected GF2mMatrix(GF2mField field, int[][] matrix) { this.field = field; this.matrix = matrix; numRows = matrix.length; numColumns = matrix[0].length; }
Returns:a byte array encoding of this matrix
/** * @return a byte array encoding of this matrix */
public byte[] getEncoded() { int d = 8; int count = 1; while (field.getDegree() > d) { count++; d += 8; } byte[] bf = new byte[this.numRows * this.numColumns * count + 4]; bf[0] = (byte)(this.numRows & 0xff); bf[1] = (byte)((this.numRows >>> 8) & 0xff); bf[2] = (byte)((this.numRows >>> 16) & 0xff); bf[3] = (byte)((this.numRows >>> 24) & 0xff); count = 4; for (int i = 0; i < this.numRows; i++) { for (int j = 0; j < this.numColumns; j++) { for (int jj = 0; jj < d; jj += 8) { bf[count++] = (byte)(matrix[i][j] >>> jj); } } } return bf; }
Check if this is the zero matrix (i.e., all entries are zero).
Returns:true if this is the zero matrix
/** * Check if this is the zero matrix (i.e., all entries are zero). * * @return <tt>true</tt> if this is the zero matrix */
public boolean isZero() { for (int i = 0; i < numRows; i++) { for (int j = 0; j < numColumns; j++) { if (matrix[i][j] != 0) { return false; } } } return true; }
Compute the inverse of this matrix.
Returns:the inverse of this matrix (newly created).
/** * Compute the inverse of this matrix. * * @return the inverse of this matrix (newly created). */
public Matrix computeInverse() { if (numRows != numColumns) { throw new ArithmeticException("Matrix is not invertible."); } // clone this matrix int[][] tmpMatrix = new int[numRows][numRows]; for (int i = numRows - 1; i >= 0; i--) { tmpMatrix[i] = IntUtils.clone(matrix[i]); } // initialize inverse matrix as unit matrix int[][] invMatrix = new int[numRows][numRows]; for (int i = numRows - 1; i >= 0; i--) { invMatrix[i][i] = 1; } // simultaneously compute Gaussian reduction of tmpMatrix and unit // matrix for (int i = 0; i < numRows; i++) { // if diagonal element is zero if (tmpMatrix[i][i] == 0) { boolean foundNonZero = false; // find a non-zero element in the same column for (int j = i + 1; j < numRows; j++) { if (tmpMatrix[j][i] != 0) { // found it, swap rows ... foundNonZero = true; swapColumns(tmpMatrix, i, j); swapColumns(invMatrix, i, j); // ... and quit searching j = numRows; continue; } } // if no non-zero element was found if (!foundNonZero) { // the matrix is not invertible throw new ArithmeticException("Matrix is not invertible."); } } // normalize i-th row int coef = tmpMatrix[i][i]; int invCoef = field.inverse(coef); multRowWithElementThis(tmpMatrix[i], invCoef); multRowWithElementThis(invMatrix[i], invCoef); // normalize all other rows for (int j = 0; j < numRows; j++) { if (j != i) { coef = tmpMatrix[j][i]; if (coef != 0) { int[] tmpRow = multRowWithElement(tmpMatrix[i], coef); int[] tmpInvRow = multRowWithElement(invMatrix[i], coef); addToRow(tmpRow, tmpMatrix[j]); addToRow(tmpInvRow, invMatrix[j]); } } } } return new GF2mMatrix(field, invMatrix); } private static void swapColumns(int[][] matrix, int first, int second) { int[] tmp = matrix[first]; matrix[first] = matrix[second]; matrix[second] = tmp; } private void multRowWithElementThis(int[] row, int element) { for (int i = row.length - 1; i >= 0; i--) { row[i] = field.mult(row[i], element); } } private int[] multRowWithElement(int[] row, int element) { int[] result = new int[row.length]; for (int i = row.length - 1; i >= 0; i--) { result[i] = field.mult(row[i], element); } return result; }
Add one row to another.
Params:
  • fromRow – the addend
  • toRow – the row to add to
/** * Add one row to another. * * @param fromRow the addend * @param toRow the row to add to */
private void addToRow(int[] fromRow, int[] toRow) { for (int i = toRow.length - 1; i >= 0; i--) { toRow[i] = field.add(fromRow[i], toRow[i]); } } public Matrix rightMultiply(Matrix a) { throw new RuntimeException("Not implemented."); } public Matrix rightMultiply(Permutation perm) { throw new RuntimeException("Not implemented."); } public Vector leftMultiply(Vector vector) { throw new RuntimeException("Not implemented."); } public Vector rightMultiply(Vector vector) { throw new RuntimeException("Not implemented."); }
Checks if given object is equal to this matrix. The method returns false whenever the given object is not a matrix over GF(2^m).
Params:
  • other – object
Returns:true or false
/** * Checks if given object is equal to this matrix. The method returns false * whenever the given object is not a matrix over GF(2^m). * * @param other object * @return true or false */
public boolean equals(Object other) { if (other == null || !(other instanceof GF2mMatrix)) { return false; } GF2mMatrix otherMatrix = (GF2mMatrix)other; if ((!this.field.equals(otherMatrix.field)) || (otherMatrix.numRows != this.numColumns) || (otherMatrix.numColumns != this.numColumns)) { return false; } for (int i = 0; i < this.numRows; i++) { for (int j = 0; j < this.numColumns; j++) { if (this.matrix[i][j] != otherMatrix.matrix[i][j]) { return false; } } } return true; } public int hashCode() { int hash = (this.field.hashCode() * 31 + numRows) * 31 + numColumns; for (int i = 0; i < this.numRows; i++) { for (int j = 0; j < this.numColumns; j++) { hash = hash * 31 + matrix[i][j]; } } return hash; } public String toString() { String str = this.numRows + " x " + this.numColumns + " Matrix over " + this.field.toString() + ": \n"; for (int i = 0; i < this.numRows; i++) { for (int j = 0; j < this.numColumns; j++) { str = str + this.field.elementToStr(matrix[i][j]) + " : "; } str = str + "\n"; } return str; } }