org.bouncycastle.pqc.math.linearalgebra.GF2mVector Maven / Gradle / Ivy
Show all versions of bcprov-jdk15to18 Show documentation
package org.bouncycastle.pqc.math.linearalgebra;
import org.bouncycastle.util.Arrays;
/**
* This class implements vectors over the finite field
* GF(2m) for small m (i.e.,
* 1<m<32). It extends the abstract class {@link Vector}.
*/
public class GF2mVector
extends Vector
{
/**
* the finite field this vector is defined over
*/
private GF2mField field;
/**
* the element array
*/
private int[] vector;
/**
* creates the vector over GF(2^m) of given length and with elements from
* array v (beginning at the first bit)
*
* @param field finite field
* @param v array with elements of vector
*/
public GF2mVector(GF2mField field, byte[] v)
{
this.field = new GF2mField(field);
// decode vector
int d = 8;
int count = 1;
while (field.getDegree() > d)
{
count++;
d += 8;
}
if ((v.length % count) != 0)
{
throw new IllegalArgumentException(
"Byte array is not an encoded vector over the given finite field.");
}
length = v.length / count;
vector = new int[length];
count = 0;
for (int i = 0; i < vector.length; i++)
{
for (int j = 0; j < d; j += 8)
{
vector[i] |= (v[count++] & 0xff) << j;
}
if (!field.isElementOfThisField(vector[i]))
{
throw new IllegalArgumentException(
"Byte array is not an encoded vector over the given finite field.");
}
}
}
/**
* Create a new vector over GF(2m) of the given
* length and element array.
*
* @param field the finite field GF(2m)
* @param vector the element array
*/
public GF2mVector(GF2mField field, int[] vector)
{
this.field = field;
length = vector.length;
for (int i = vector.length - 1; i >= 0; i--)
{
if (!field.isElementOfThisField(vector[i]))
{
throw new ArithmeticException(
"Element array is not specified over the given finite field.");
}
}
this.vector = IntUtils.clone(vector);
}
/**
* Copy constructor.
*
* @param other another {@link GF2mVector}
*/
public GF2mVector(GF2mVector other)
{
field = new GF2mField(other.field);
length = other.length;
vector = IntUtils.clone(other.vector);
}
/**
* @return the finite field this vector is defined over
*/
public GF2mField getField()
{
return field;
}
/**
* @return int[] form of this vector
*/
public int[] getIntArrayForm()
{
return IntUtils.clone(vector);
}
/**
* @return a byte array encoding of this vector
*/
public byte[] getEncoded()
{
int d = 8;
int count = 1;
while (field.getDegree() > d)
{
count++;
d += 8;
}
byte[] res = new byte[vector.length * count];
count = 0;
for (int i = 0; i < vector.length; i++)
{
for (int j = 0; j < d; j += 8)
{
res[count++] = (byte)(vector[i] >>> j);
}
}
return res;
}
/**
* @return whether this is the zero vector (i.e., all elements are zero)
*/
public boolean isZero()
{
for (int i = vector.length - 1; i >= 0; i--)
{
if (vector[i] != 0)
{
return false;
}
}
return true;
}
/**
* Add another vector to this vector. Method is not yet implemented.
*
* @param addend the other vector
* @return this + addend
* @throws ArithmeticException if the other vector is not defined over the same field as
* this vector.
*
* TODO: implement this method
*/
public Vector add(Vector addend)
{
throw new RuntimeException("not implemented");
}
/**
* Multiply this vector with a permutation.
*
* @param p the permutation
* @return this*p = p*this
*/
public Vector multiply(Permutation p)
{
int[] pVec = p.getVector();
if (length != pVec.length)
{
throw new ArithmeticException(
"permutation size and vector size mismatch");
}
int[] result = new int[length];
for (int i = 0; i < pVec.length; i++)
{
result[i] = vector[pVec[i]];
}
return new GF2mVector(field, result);
}
/**
* Compare this vector with another object.
*
* @param other the other object
* @return the result of the comparison
*/
public boolean equals(Object other)
{
if (!(other instanceof GF2mVector))
{
return false;
}
GF2mVector otherVec = (GF2mVector)other;
if (!field.equals(otherVec.field))
{
return false;
}
return IntUtils.equals(vector, otherVec.vector);
}
/**
* @return the hash code of this vector
*/
public int hashCode()
{
int hash = this.field.hashCode();
hash = hash * 31 + Arrays.hashCode(vector);
return hash;
}
/**
* @return a human readable form of this vector
*/
public String toString()
{
StringBuffer buf = new StringBuffer();
for (int i = 0; i < vector.length; i++)
{
for (int j = 0; j < field.getDegree(); j++)
{
int r = j & 0x1f;
int bitMask = 1 << r;
int coeff = vector[i] & bitMask;
if (coeff != 0)
{
buf.append('1');
}
else
{
buf.append('0');
}
}
buf.append(' ');
}
return buf.toString();
}
}