| package org.bouncycastle.pqc.math.linearalgebra; |
| |
| |
| /** |
| * This class implements vectors over the finite field |
| * <tt>GF(2<sup>m</sup>)</tt> for small <tt>m</tt> (i.e., |
| * <tt>1<m<32</tt>). 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 <tt>GF(2<sup>m</sup>)</tt> of the given |
| * length and element array. |
| * |
| * @param field the finite field <tt>GF(2<sup>m</sup>)</tt> |
| * @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 <tt>this + addend</tt> |
| * @throws ArithmeticException if the other vector is not defined over the same field as |
| * this vector. |
| * <p> |
| * 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 <tt>this*p = p*this</tt> |
| */ |
| 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 + vector.hashCode(); |
| 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(); |
| } |
| |
| } |