org.bouncycastle.pqc.legacy.math.linearalgebra.GF2nPolynomial Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on 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 Java 1.8 and later with debug enabled.
The newest version!
package org.bouncycastle.pqc.legacy.math.linearalgebra;
import org.bouncycastle.util.Arrays;
/**
* 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.
*
* @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.
*
* @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.
*
* @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.
*
* @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.
*
* @return the size (=maximum degree + 1) of this PolynomialGF2n.
*/
public final int size()
{
return size;
}
/**
* 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.
*
* @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.
*
* @param index the index
* @param elem the GF2nElement to store as coefficient index
*/
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.
*
* @param index the index
* @return the GF2nElement stored as coefficient index
*/
public final GF2nElement at(int index)
{
return coeff[index];
}
/**
* 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;
}
/**
* @return the hash code of this polynomial
*/
public int hashCode()
{
return getDegree() * 7 + Arrays.hashCode(coeff);
}
/**
* Adds the PolynomialGF2n b to this and returns the
* result in a new PolynomialGF2n.
*
* @param b -
* the PolynomialGF2n to add
* @return this + b
*/
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.
*
* @param s the scalar to multiply
* @return this x s
*/
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.
*
* @param b the PolynomialGF2n to multiply
* @return this * b
*/
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.
*
* @param b the PolynomialGF2n to multiply
* @param g the modul
* @return this * b mod g
*/
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.
*
* @param g -
* the modulus
* @return this % g
*/
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.
*
* @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].
*
* @param b the divisor
* @return the quotient and remainder of this / b
*/
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.
*
* @param b the divisor
* @return the remainder this % b
*/
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.
*
* @param b the divisor
* @return the quotient this / b
*/
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.
*
* @param g -
* a GF2nPolynomial
* @return gcd(this, g)
*/
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;
}
}