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(); } }