package org.bouncycastle.pqc.math.linearalgebra;

import java.security.SecureRandom;

import org.bouncycastle.crypto.CryptoServicesRegistrar;

This class describes operations with elements from the finite field F = GF(2^m). ( GF(2^m)= GF(2)[A] where A is a root of irreducible polynomial with degree m, each field element B has a polynomial basis representation, i.e. it is represented by a different binary polynomial of degree less than m, B = poly(A) ) All operations are defined only for field with 1< m <32. For the representation of field elements the map f: F->Z, poly(A)->poly(2) is used, where integers have the binary representation. For example: A^7+A^3+A+1 -> (00...0010001011)=139 Also for elements type Integer is used.
See Also:
  • PolynomialRingGF2
/** * This class describes operations with elements from the finite field F = * GF(2^m). ( GF(2^m)= GF(2)[A] where A is a root of irreducible polynomial with * degree m, each field element B has a polynomial basis representation, i.e. it * is represented by a different binary polynomial of degree less than m, B = * poly(A) ) All operations are defined only for field with 1&lt; m &lt;32. For the * representation of field elements the map f: F-&gt;Z, poly(A)-&gt;poly(2) is used, * where integers have the binary representation. For example: A^7+A^3+A+1 -&gt; * (00...0010001011)=139 Also for elements type Integer is used. * * @see PolynomialRingGF2 */
public class GF2mField { /* * degree - degree of the field polynomial - the field polynomial ring - * polynomial ring over the finite field GF(2) */ private int degree = 0; private int polynomial;
create a finite field GF(2^m)
Params:
  • degree – the degree of the field
/** * create a finite field GF(2^m) * * @param degree the degree of the field */
public GF2mField(int degree) { if (degree >= 32) { throw new IllegalArgumentException( " Error: the degree of field is too large "); } if (degree < 1) { throw new IllegalArgumentException( " Error: the degree of field is non-positive "); } this.degree = degree; polynomial = PolynomialRingGF2.getIrreduciblePolynomial(degree); }
create a finite field GF(2^m) with the fixed field polynomial
Params:
  • degree – the degree of the field
  • poly – the field polynomial
/** * create a finite field GF(2^m) with the fixed field polynomial * * @param degree the degree of the field * @param poly the field polynomial */
public GF2mField(int degree, int poly) { if (degree != PolynomialRingGF2.degree(poly)) { throw new IllegalArgumentException( " Error: the degree is not correct"); } if (!PolynomialRingGF2.isIrreducible(poly)) { throw new IllegalArgumentException( " Error: given polynomial is reducible"); } this.degree = degree; polynomial = poly; } public GF2mField(byte[] enc) { if (enc.length != 4) { throw new IllegalArgumentException( "byte array is not an encoded finite field"); } polynomial = LittleEndianConversions.OS2IP(enc); if (!PolynomialRingGF2.isIrreducible(polynomial)) { throw new IllegalArgumentException( "byte array is not an encoded finite field"); } degree = PolynomialRingGF2.degree(polynomial); } public GF2mField(GF2mField field) { degree = field.degree; polynomial = field.polynomial; }
return degree of the field
Returns:degree of the field
/** * return degree of the field * * @return degree of the field */
public int getDegree() { return degree; }
return the field polynomial
Returns:the field polynomial
/** * return the field polynomial * * @return the field polynomial */
public int getPolynomial() { return polynomial; }
return the encoded form of this field
Returns:the field in byte array form
/** * return the encoded form of this field * * @return the field in byte array form */
public byte[] getEncoded() { return LittleEndianConversions.I2OSP(polynomial); }
Return sum of two elements
Params:
  • a –
  • b –
Returns:a+b
/** * Return sum of two elements * * @param a * @param b * @return a+b */
public int add(int a, int b) { return a ^ b; }
Return product of two elements
Params:
  • a –
  • b –
Returns:a*b
/** * Return product of two elements * * @param a * @param b * @return a*b */
public int mult(int a, int b) { return PolynomialRingGF2.modMultiply(a, b, polynomial); }
compute exponentiation a^k
Params:
  • a – a field element a
  • k – k degree
Returns:a^k
/** * compute exponentiation a^k * * @param a a field element a * @param k k degree * @return a^k */
public int exp(int a, int k) { if (k == 0) { return 1; } if (a == 0) { return 0; } if (a == 1) { return 1; } int result = 1; if (k < 0) { a = inverse(a); k = -k; } while (k != 0) { if ((k & 1) == 1) { result = mult(result, a); } a = mult(a, a); k >>>= 1; } return result; }
compute the multiplicative inverse of a
Params:
  • a – a field element a
Returns:a-1
/** * compute the multiplicative inverse of a * * @param a a field element a * @return a<sup>-1</sup> */
public int inverse(int a) { int d = (1 << degree) - 2; return exp(a, d); }
compute the square root of an integer
Params:
  • a – a field element a
Returns:a1/2
/** * compute the square root of an integer * * @param a a field element a * @return a<sup>1/2</sup> */
public int sqRoot(int a) { for (int i = 1; i < degree; i++) { a = mult(a, a); } return a; }
create a random field element using PRNG sr
Params:
  • sr – SecureRandom
Returns:a random element
/** * create a random field element using PRNG sr * * @param sr SecureRandom * @return a random element */
public int getRandomElement(SecureRandom sr) { int result = RandUtils.nextInt(sr, 1 << degree); return result; }
create a random non-zero field element
Returns:a random element
/** * create a random non-zero field element * * @return a random element */
public int getRandomNonZeroElement() { return getRandomNonZeroElement(CryptoServicesRegistrar.getSecureRandom()); }
create a random non-zero field element using PRNG sr
Params:
  • sr – SecureRandom
Returns:a random non-zero element
/** * create a random non-zero field element using PRNG sr * * @param sr SecureRandom * @return a random non-zero element */
public int getRandomNonZeroElement(SecureRandom sr) { int controltime = 1 << 20; int count = 0; int result = RandUtils.nextInt(sr, 1 << degree); while ((result == 0) && (count < controltime)) { result = RandUtils.nextInt(sr, 1 << degree); count++; } if (count == controltime) { result = 1; } return result; }
Returns:true if e is encoded element of this field and false otherwise
/** * @return true if e is encoded element of this field and false otherwise */
public boolean isElementOfThisField(int e) { // e is encoded element of this field iff 0<= e < |2^m| if (degree == 31) { return e >= 0; } return e >= 0 && e < (1 << degree); } /* * help method for visual control */ public String elementToStr(int a) { String s = ""; for (int i = 0; i < degree; i++) { if (((byte)a & 0x01) == 0) { s = "0" + s; } else { s = "1" + s; } a >>>= 1; } return s; }
checks if given object is equal to this field.

The method returns false whenever the given object is not GF2m.

Params:
  • other – object
Returns:true or false
/** * checks if given object is equal to this field. * <p> * The method returns false whenever the given object is not GF2m. * * @param other object * @return true or false */
public boolean equals(Object other) { if ((other == null) || !(other instanceof GF2mField)) { return false; } GF2mField otherField = (GF2mField)other; if ((degree == otherField.degree) && (polynomial == otherField.polynomial)) { return true; } return false; } public int hashCode() { return polynomial; }
Returns a human readable form of this field.
Returns:a human readable form of this field.
/** * Returns a human readable form of this field. * * @return a human readable form of this field. */
public String toString() { String str = "Finite Field GF(2^" + degree + ") = " + "GF(2)[X]/<" + polyToString(polynomial) + "> "; return str; } private static String polyToString(int p) { String str = ""; if (p == 0) { str = "0"; } else { byte b = (byte)(p & 0x01); if (b == 1) { str = "1"; } p >>>= 1; int i = 1; while (p != 0) { b = (byte)(p & 0x01); if (b == 1) { str = str + "+x^" + i; } p >>>= 1; i++; } } return str; } }