| package org.bouncycastle.pqc.math.linearalgebra; |
| |
| /** |
| * This class represents polynomial rings <tt>GF(2^m)[X]/p(X)</tt> for |
| * <tt>m<32</tt>. If <tt>p(X)</tt> is irreducible, the polynomial ring |
| * is in fact an extension field of <tt>GF(2^m)</tt>. |
| */ |
| public class PolynomialRingGF2m |
| { |
| |
| /** |
| * the finite field this polynomial ring is defined over |
| */ |
| private GF2mField field; |
| |
| /** |
| * the reduction polynomial |
| */ |
| private PolynomialGF2mSmallM p; |
| |
| /** |
| * the squaring matrix for this polynomial ring (given as the array of its |
| * row vectors) |
| */ |
| protected PolynomialGF2mSmallM[] sqMatrix; |
| |
| /** |
| * the matrix for computing square roots in this polynomial ring (given as |
| * the array of its row vectors). This matrix is computed as the inverse of |
| * the squaring matrix. |
| */ |
| protected PolynomialGF2mSmallM[] sqRootMatrix; |
| |
| /** |
| * Constructor. |
| * |
| * @param field the finite field |
| * @param p the reduction polynomial |
| */ |
| public PolynomialRingGF2m(GF2mField field, PolynomialGF2mSmallM p) |
| { |
| this.field = field; |
| this.p = p; |
| computeSquaringMatrix(); |
| computeSquareRootMatrix(); |
| } |
| |
| /** |
| * @return the squaring matrix for this polynomial ring |
| */ |
| public PolynomialGF2mSmallM[] getSquaringMatrix() |
| { |
| return sqMatrix; |
| } |
| |
| /** |
| * @return the matrix for computing square roots for this polynomial ring |
| */ |
| public PolynomialGF2mSmallM[] getSquareRootMatrix() |
| { |
| return sqRootMatrix; |
| } |
| |
| /** |
| * Compute the squaring matrix for this polynomial ring, using the base |
| * field and the reduction polynomial. |
| */ |
| private void computeSquaringMatrix() |
| { |
| int numColumns = p.getDegree(); |
| sqMatrix = new PolynomialGF2mSmallM[numColumns]; |
| for (int i = 0; i < numColumns >> 1; i++) |
| { |
| int[] monomCoeffs = new int[(i << 1) + 1]; |
| monomCoeffs[i << 1] = 1; |
| sqMatrix[i] = new PolynomialGF2mSmallM(field, monomCoeffs); |
| } |
| for (int i = numColumns >> 1; i < numColumns; i++) |
| { |
| int[] monomCoeffs = new int[(i << 1) + 1]; |
| monomCoeffs[i << 1] = 1; |
| PolynomialGF2mSmallM monomial = new PolynomialGF2mSmallM(field, |
| monomCoeffs); |
| sqMatrix[i] = monomial.mod(p); |
| } |
| } |
| |
| /** |
| * Compute the matrix for computing square roots in this polynomial ring by |
| * inverting the squaring matrix. |
| */ |
| private void computeSquareRootMatrix() |
| { |
| int numColumns = p.getDegree(); |
| |
| // clone squaring matrix |
| PolynomialGF2mSmallM[] tmpMatrix = new PolynomialGF2mSmallM[numColumns]; |
| for (int i = numColumns - 1; i >= 0; i--) |
| { |
| tmpMatrix[i] = new PolynomialGF2mSmallM(sqMatrix[i]); |
| } |
| |
| // initialize square root matrix as unit matrix |
| sqRootMatrix = new PolynomialGF2mSmallM[numColumns]; |
| for (int i = numColumns - 1; i >= 0; i--) |
| { |
| sqRootMatrix[i] = new PolynomialGF2mSmallM(field, i); |
| } |
| |
| // simultaneously compute Gaussian reduction of squaring matrix and unit |
| // matrix |
| for (int i = 0; i < numColumns; i++) |
| { |
| // if diagonal element is zero |
| if (tmpMatrix[i].getCoefficient(i) == 0) |
| { |
| boolean foundNonZero = false; |
| // find a non-zero element in the same row |
| for (int j = i + 1; j < numColumns; j++) |
| { |
| if (tmpMatrix[j].getCoefficient(i) != 0) |
| { |
| // found it, swap columns ... |
| foundNonZero = true; |
| swapColumns(tmpMatrix, i, j); |
| swapColumns(sqRootMatrix, i, j); |
| // ... and quit searching |
| j = numColumns; |
| continue; |
| } |
| } |
| // if no non-zero element was found |
| if (!foundNonZero) |
| { |
| // the matrix is not invertible |
| throw new ArithmeticException( |
| "Squaring matrix is not invertible."); |
| } |
| } |
| |
| // normalize i-th column |
| int coef = tmpMatrix[i].getCoefficient(i); |
| int invCoef = field.inverse(coef); |
| tmpMatrix[i].multThisWithElement(invCoef); |
| sqRootMatrix[i].multThisWithElement(invCoef); |
| |
| // normalize all other columns |
| for (int j = 0; j < numColumns; j++) |
| { |
| if (j != i) |
| { |
| coef = tmpMatrix[j].getCoefficient(i); |
| if (coef != 0) |
| { |
| PolynomialGF2mSmallM tmpSqColumn = tmpMatrix[i] |
| .multWithElement(coef); |
| PolynomialGF2mSmallM tmpInvColumn = sqRootMatrix[i] |
| .multWithElement(coef); |
| tmpMatrix[j].addToThis(tmpSqColumn); |
| sqRootMatrix[j].addToThis(tmpInvColumn); |
| } |
| } |
| } |
| } |
| } |
| |
| private static void swapColumns(PolynomialGF2mSmallM[] matrix, int first, |
| int second) |
| { |
| PolynomialGF2mSmallM tmp = matrix[first]; |
| matrix[first] = matrix[second]; |
| matrix[second] = tmp; |
| } |
| |
| } |