package org.bouncycastle.pqc.math.linearalgebra;


This class implements polynomials over GF2nElements.
See Also:
  • GF2nElement
/** * This class implements polynomials over GF2nElements. * * @see GF2nElement */
public class GF2nPolynomial { private GF2nElement[] coeff; // keeps the coefficients of this polynomial private int size; // the size of this polynomial
Creates a new PolynomialGF2n of size deg and elem as coefficients.
Params:
  • deg – - the maximum degree + 1
  • elem – - a GF2nElement
/** * Creates a new PolynomialGF2n of size <i>deg</i> and elem as * coefficients. * * @param deg - * the maximum degree + 1 * @param elem - * a GF2nElement */
public GF2nPolynomial(int deg, GF2nElement elem) { size = deg; coeff = new GF2nElement[size]; for (int i = 0; i < size; i++) { coeff[i] = (GF2nElement)elem.clone(); } }
Creates a new PolynomialGF2n of size deg.
Params:
  • deg – the maximum degree + 1
/** * Creates a new PolynomialGF2n of size <i>deg</i>. * * @param deg the maximum degree + 1 */
private GF2nPolynomial(int deg) { size = deg; coeff = new GF2nElement[size]; }
Creates a new PolynomialGF2n by cloning the given PolynomialGF2n a.
Params:
  • a – the PolynomialGF2n to clone
/** * Creates a new PolynomialGF2n by cloning the given PolynomialGF2n <i>a</i>. * * @param a the PolynomialGF2n to clone */
public GF2nPolynomial(GF2nPolynomial a) { int i; coeff = new GF2nElement[a.size]; size = a.size; for (i = 0; i < size; i++) { coeff[i] = (GF2nElement)a.coeff[i].clone(); } }
Creates a new PolynomialGF2n from the given Bitstring polynomial over the GF2nField B1.
Params:
  • polynomial – the Bitstring to use
  • B1 – the field
/** * Creates a new PolynomialGF2n from the given Bitstring <i>polynomial</i> * over the GF2nField <i>B1</i>. * * @param polynomial the Bitstring to use * @param B1 the field */
public GF2nPolynomial(GF2Polynomial polynomial, GF2nField B1) { size = B1.getDegree() + 1; coeff = new GF2nElement[size]; int i; if (B1 instanceof GF2nONBField) { for (i = 0; i < size; i++) { if (polynomial.testBit(i)) { coeff[i] = GF2nONBElement.ONE((GF2nONBField)B1); } else { coeff[i] = GF2nONBElement.ZERO((GF2nONBField)B1); } } } else if (B1 instanceof GF2nPolynomialField) { for (i = 0; i < size; i++) { if (polynomial.testBit(i)) { coeff[i] = GF2nPolynomialElement .ONE((GF2nPolynomialField)B1); } else { coeff[i] = GF2nPolynomialElement .ZERO((GF2nPolynomialField)B1); } } } else { throw new IllegalArgumentException( "PolynomialGF2n(Bitstring, GF2nField): B1 must be " + "an instance of GF2nONBField or GF2nPolynomialField!"); } } public final void assignZeroToElements() { int i; for (i = 0; i < size; i++) { coeff[i].assignZero(); } }
Returns the size (=maximum degree + 1) of this PolynomialGF2n. This is not the degree, use getDegree instead.
Returns:the size (=maximum degree + 1) of this PolynomialGF2n.
/** * Returns the size (=maximum degree + 1) of this PolynomialGF2n. This is * not the degree, use getDegree instead. * * @return the size (=maximum degree + 1) of this PolynomialGF2n. */
public final int size() { return size; }
Returns the degree of this PolynomialGF2n.
Returns:the degree of this PolynomialGF2n.
/** * Returns the degree of this PolynomialGF2n. * * @return the degree of this PolynomialGF2n. */
public final int getDegree() { int i; for (i = size - 1; i >= 0; i--) { if (!coeff[i].isZero()) { return i; } } return -1; }
Enlarges the size of this PolynomialGF2n to k + 1.
Params:
  • k – the new maximum degree
/** * Enlarges the size of this PolynomialGF2n to <i>k</i> + 1. * * @param k the new maximum degree */
public final void enlarge(int k) { if (k <= size) { return; } int i; GF2nElement[] res = new GF2nElement[k]; System.arraycopy(coeff, 0, res, 0, size); GF2nField f = coeff[0].getField(); if (coeff[0] instanceof GF2nPolynomialElement) { for (i = size; i < k; i++) { res[i] = GF2nPolynomialElement.ZERO((GF2nPolynomialField)f); } } else if (coeff[0] instanceof GF2nONBElement) { for (i = size; i < k; i++) { res[i] = GF2nONBElement.ZERO((GF2nONBField)f); } } size = k; coeff = res; } public final void shrink() { int i = size - 1; while (coeff[i].isZero() && (i > 0)) { i--; } i++; if (i < size) { GF2nElement[] res = new GF2nElement[i]; System.arraycopy(coeff, 0, res, 0, i); coeff = res; size = i; } }
Sets the coefficient at index to elem.
Params:
  • index – the index
  • elem – the GF2nElement to store as coefficient index
/** * Sets the coefficient at <i>index</i> to <i>elem</i>. * * @param index the index * @param elem the GF2nElement to store as coefficient <i>index</i> */
public final void set(int index, GF2nElement elem) { if (!(elem instanceof GF2nPolynomialElement) && !(elem instanceof GF2nONBElement)) { throw new IllegalArgumentException( "PolynomialGF2n.set f must be an " + "instance of either GF2nPolynomialElement or GF2nONBElement!"); } coeff[index] = (GF2nElement)elem.clone(); }
Returns the coefficient at index.
Params:
  • index – the index
Returns:the GF2nElement stored as coefficient index
/** * Returns the coefficient at <i>index</i>. * * @param index the index * @return the GF2nElement stored as coefficient <i>index</i> */
public final GF2nElement at(int index) { return coeff[index]; }
Returns true if all coefficients equal zero.
Returns:true if all coefficients equal zero.
/** * Returns true if all coefficients equal zero. * * @return true if all coefficients equal zero. */
public final boolean isZero() { int i; for (i = 0; i < size; i++) { if (coeff[i] != null) { if (!coeff[i].isZero()) { return false; } } } return true; } public final boolean equals(Object other) { if (other == null || !(other instanceof GF2nPolynomial)) { return false; } GF2nPolynomial otherPol = (GF2nPolynomial)other; if (getDegree() != otherPol.getDegree()) { return false; } int i; for (i = 0; i < size; i++) { if (!coeff[i].equals(otherPol.coeff[i])) { return false; } } return true; }
Returns:the hash code of this polynomial
/** * @return the hash code of this polynomial */
public int hashCode() { return getDegree() + coeff.hashCode(); }
Adds the PolynomialGF2n b to this and returns the result in a new PolynomialGF2n.
Params:
  • b – - the PolynomialGF2n to add
Returns:this + b
/** * Adds the PolynomialGF2n <tt>b</tt> to <tt>this</tt> and returns the * result in a new <tt>PolynomialGF2n</tt>. * * @param b - * the <tt>PolynomialGF2n</tt> to add * @return <tt>this + b</tt> */
public final GF2nPolynomial add(GF2nPolynomial b) { GF2nPolynomial result; if (size() >= b.size()) { result = new GF2nPolynomial(size()); int i; for (i = 0; i < b.size(); i++) { result.coeff[i] = (GF2nElement)coeff[i].add(b.coeff[i]); } for (; i < size(); i++) { result.coeff[i] = coeff[i]; } } else { result = new GF2nPolynomial(b.size()); int i; for (i = 0; i < size(); i++) { result.coeff[i] = (GF2nElement)coeff[i].add(b.coeff[i]); } for (; i < b.size(); i++) { result.coeff[i] = b.coeff[i]; } } return result; }
Multiplies the scalar s to each coefficient of this PolynomialGF2n and returns the result in a new PolynomialGF2n.
Params:
  • s – the scalar to multiply
Returns:this x s
/** * Multiplies the scalar <i>s</i> to each coefficient of this * PolynomialGF2n and returns the result in a new PolynomialGF2n. * * @param s the scalar to multiply * @return <i>this</i> x <i>s</i> */
public final GF2nPolynomial scalarMultiply(GF2nElement s) { GF2nPolynomial result = new GF2nPolynomial(size()); int i; for (i = 0; i < size(); i++) { result.coeff[i] = (GF2nElement)coeff[i].multiply(s); // result[i] // = // a[i]*s } return result; }
Multiplies this by b and returns the result in a new PolynomialGF2n.
Params:
  • b – the PolynomialGF2n to multiply
Returns:this * b
/** * Multiplies <i>this</i> by <i>b</i> and returns the result in a new * PolynomialGF2n. * * @param b the PolynomialGF2n to multiply * @return <i>this</i> * <i>b</i> */
public final GF2nPolynomial multiply(GF2nPolynomial b) { int i, j; int aDegree = size(); int bDegree = b.size(); if (aDegree != bDegree) { throw new IllegalArgumentException( "PolynomialGF2n.multiply: this and b must " + "have the same size!"); } GF2nPolynomial result = new GF2nPolynomial((aDegree << 1) - 1); for (i = 0; i < size(); i++) { for (j = 0; j < b.size(); j++) { if (result.coeff[i + j] == null) { result.coeff[i + j] = (GF2nElement)coeff[i] .multiply(b.coeff[j]); } else { result.coeff[i + j] = (GF2nElement)result.coeff[i + j] .add(coeff[i].multiply(b.coeff[j])); } } } return result; }
Multiplies this by b, reduces the result by g and returns it in a new PolynomialGF2n.
Params:
  • b – the PolynomialGF2n to multiply
  • g – the modul
Returns:this * b mod g
/** * Multiplies <i>this</i> by <i>b</i>, reduces the result by <i>g</i> and * returns it in a new PolynomialGF2n. * * @param b the PolynomialGF2n to multiply * @param g the modul * @return <i>this</i> * <i>b</i> mod <i>g</i> */
public final GF2nPolynomial multiplyAndReduce(GF2nPolynomial b, GF2nPolynomial g) { return multiply(b).reduce(g); }
Reduces this by g and returns the result in a new PolynomialGF2n.
Params:
  • g – - the modulus
Returns:this % g
/** * Reduces <i>this</i> by <i>g</i> and returns the result in a new * PolynomialGF2n. * * @param g - * the modulus * @return <i>this</i> % <i>g</i> */
public final GF2nPolynomial reduce(GF2nPolynomial g) throws RuntimeException, ArithmeticException { return remainder(g); // return this % g }
Shifts left this by amount and stores the result in this PolynomialGF2n.
Params:
  • amount – the amount to shift the coefficients
/** * Shifts left <i>this</i> by <i>amount</i> and stores the result in * <i>this</i> PolynomialGF2n. * * @param amount the amount to shift the coefficients */
public final void shiftThisLeft(int amount) { if (amount > 0) { int i; int oldSize = size; GF2nField f = coeff[0].getField(); enlarge(size + amount); for (i = oldSize - 1; i >= 0; i--) { coeff[i + amount] = coeff[i]; } if (coeff[0] instanceof GF2nPolynomialElement) { for (i = amount - 1; i >= 0; i--) { coeff[i] = GF2nPolynomialElement .ZERO((GF2nPolynomialField)f); } } else if (coeff[0] instanceof GF2nONBElement) { for (i = amount - 1; i >= 0; i--) { coeff[i] = GF2nONBElement.ZERO((GF2nONBField)f); } } } } public final GF2nPolynomial shiftLeft(int amount) { if (amount <= 0) { return new GF2nPolynomial(this); } GF2nPolynomial result = new GF2nPolynomial(size + amount, coeff[0]); result.assignZeroToElements(); for (int i = 0; i < size; i++) { result.coeff[i + amount] = coeff[i]; } return result; }
Divides this by b and stores the result in a new PolynomialGF2n[2], quotient in result[0] and remainder in result[1].
Params:
  • b – the divisor
Returns:the quotient and remainder of this / b
/** * Divides <i>this</i> by <i>b</i> and stores the result in a new * PolynomialGF2n[2], quotient in result[0] and remainder in result[1]. * * @param b the divisor * @return the quotient and remainder of <i>this</i> / <i>b</i> */
public final GF2nPolynomial[] divide(GF2nPolynomial b) { GF2nPolynomial[] result = new GF2nPolynomial[2]; GF2nPolynomial a = new GF2nPolynomial(this); a.shrink(); GF2nPolynomial shift; GF2nElement factor; int bDegree = b.getDegree(); GF2nElement inv = (GF2nElement)b.coeff[bDegree].invert(); if (a.getDegree() < bDegree) { result[0] = new GF2nPolynomial(this); result[0].assignZeroToElements(); result[0].shrink(); result[1] = new GF2nPolynomial(this); result[1].shrink(); return result; } result[0] = new GF2nPolynomial(this); result[0].assignZeroToElements(); int i = a.getDegree() - bDegree; while (i >= 0) { factor = (GF2nElement)a.coeff[a.getDegree()].multiply(inv); shift = b.scalarMultiply(factor); shift.shiftThisLeft(i); a = a.add(shift); a.shrink(); result[0].coeff[i] = (GF2nElement)factor.clone(); i = a.getDegree() - bDegree; } result[1] = a; result[0].shrink(); return result; }
Divides this by b and stores the remainder in a new PolynomialGF2n.
Params:
  • b – the divisor
Returns:the remainder this % b
/** * Divides <i>this</i> by <i>b</i> and stores the remainder in a new * PolynomialGF2n. * * @param b the divisor * @return the remainder <i>this</i> % <i>b</i> */
public final GF2nPolynomial remainder(GF2nPolynomial b) throws RuntimeException, ArithmeticException { GF2nPolynomial[] result = new GF2nPolynomial[2]; result = divide(b); return result[1]; }
Divides this by b and stores the quotient in a new PolynomialGF2n.
Params:
  • b – the divisor
Returns:the quotient this / b
/** * Divides <i>this</i> by <i>b</i> and stores the quotient in a new * PolynomialGF2n. * * @param b the divisor * @return the quotient <i>this</i> / <i>b</i> */
public final GF2nPolynomial quotient(GF2nPolynomial b) throws RuntimeException, ArithmeticException { GF2nPolynomial[] result = new GF2nPolynomial[2]; result = divide(b); return result[0]; }
Computes the greatest common divisor of this and g and returns the result in a new PolynomialGF2n.
Params:
  • g – - a GF2nPolynomial
Returns:gcd(this, g)
/** * Computes the greatest common divisor of <i>this</i> and <i>g</i> and * returns the result in a new PolynomialGF2n. * * @param g - * a GF2nPolynomial * @return gcd(<i>this</i>, <i>g</i>) */
public final GF2nPolynomial gcd(GF2nPolynomial g) { GF2nPolynomial a = new GF2nPolynomial(this); GF2nPolynomial b = new GF2nPolynomial(g); a.shrink(); b.shrink(); GF2nPolynomial c; GF2nPolynomial result; GF2nElement alpha; while (!b.isZero()) { c = a.remainder(b); a = b; b = c; } alpha = a.coeff[a.getDegree()]; result = a.scalarMultiply((GF2nElement)alpha.invert()); return result; } }