package org.bouncycastle.pqc.math.linearalgebra;

import java.security.SecureRandom;

import org.bouncycastle.util.Arrays;

This class implements the abstract class Vector for the case of vectors over the finite field GF(2).
For the vector representation the array of type int[] is used, thus one element of the array holds 32 elements of the vector.
See Also:
  • Vector
/** * This class implements the abstract class <tt>Vector</tt> for the case of * vectors over the finite field GF(2). <br> * For the vector representation the array of type int[] is used, thus one * element of the array holds 32 elements of the vector. * * @see Vector */
public class GF2Vector extends Vector {
holds the elements of this vector
/** * holds the elements of this vector */
private int[] v;
Construct the zero vector of the given length.
Params:
  • length – the length of the vector
/** * Construct the zero vector of the given length. * * @param length the length of the vector */
public GF2Vector(int length) { if (length < 0) { throw new ArithmeticException("Negative length."); } this.length = length; v = new int[(length + 31) >> 5]; }
Construct a random GF2Vector of the given length.
Params:
  • length – the length of the vector
  • sr – the source of randomness
/** * Construct a random GF2Vector of the given length. * * @param length the length of the vector * @param sr the source of randomness */
public GF2Vector(int length, SecureRandom sr) { this.length = length; int size = (length + 31) >> 5; v = new int[size]; // generate random elements for (int i = size - 1; i >= 0; i--) { v[i] = sr.nextInt(); } // erase unused bits int r = length & 0x1f; if (r != 0) { // erase unused bits v[size - 1] &= (1 << r) - 1; } }
Construct a random GF2Vector of the given length with the specified number of non-zero coefficients.
Params:
  • length – the length of the vector
  • t – the number of non-zero coefficients
  • sr – the source of randomness
/** * Construct a random GF2Vector of the given length with the specified * number of non-zero coefficients. * * @param length the length of the vector * @param t the number of non-zero coefficients * @param sr the source of randomness */
public GF2Vector(int length, int t, SecureRandom sr) { if (t > length) { throw new ArithmeticException( "The hamming weight is greater than the length of vector."); } this.length = length; int size = (length + 31) >> 5; v = new int[size]; int[] help = new int[length]; for (int i = 0; i < length; i++) { help[i] = i; } int m = length; for (int i = 0; i < t; i++) { int j = RandUtils.nextInt(sr, m); setBit(help[j]); m--; help[j] = help[m]; } }
Construct a GF2Vector of the given length and with elements from the given array. The array is copied and unused bits are masked out.
Params:
  • length – the length of the vector
  • v – the element array
/** * Construct a GF2Vector of the given length and with elements from the * given array. The array is copied and unused bits are masked out. * * @param length the length of the vector * @param v the element array */
public GF2Vector(int length, int[] v) { if (length < 0) { throw new ArithmeticException("negative length"); } this.length = length; int size = (length + 31) >> 5; if (v.length != size) { throw new ArithmeticException("length mismatch"); } this.v = IntUtils.clone(v); int r = length & 0x1f; if (r != 0) { // erase unused bits this.v[size - 1] &= (1 << r) - 1; } }
Copy constructor.
Params:
/** * Copy constructor. * * @param other another {@link GF2Vector} */
public GF2Vector(GF2Vector other) { this.length = other.length; this.v = IntUtils.clone(other.v); }
Construct a new GF2Vector of the given length and with the given element array. The array is not changed and only a reference to the array is stored. No length checking is performed either.
Params:
  • v – the element array
  • length – the length of the vector
/** * Construct a new {@link GF2Vector} of the given length and with the given * element array. The array is not changed and only a reference to the array * is stored. No length checking is performed either. * * @param v the element array * @param length the length of the vector */
protected GF2Vector(int[] v, int length) { this.v = v; this.length = length; }
Construct a new GF2Vector with the given length out of the encoded vector.
Params:
  • length – the length of the vector
  • encVec – the encoded vector
Returns:the decoded vector
/** * Construct a new GF2Vector with the given length out of the encoded * vector. * * @param length the length of the vector * @param encVec the encoded vector * @return the decoded vector */
public static GF2Vector OS2VP(int length, byte[] encVec) { if (length < 0) { throw new ArithmeticException("negative length"); } int byteLen = (length + 7) >> 3; if (encVec.length > byteLen) { throw new ArithmeticException("length mismatch"); } return new GF2Vector(length, LittleEndianConversions.toIntArray(encVec)); }
Encode this vector as byte array.
Returns:the encoded vector
/** * Encode this vector as byte array. * * @return the encoded vector */
public byte[] getEncoded() { int byteLen = (length + 7) >> 3; return LittleEndianConversions.toByteArray(v, byteLen); }
Returns:the int array representation of this vector
/** * @return the int array representation of this vector */
public int[] getVecArray() { return v; }
Return the Hamming weight of this vector, i.e., compute the number of units of this vector.
Returns:the Hamming weight of this vector
/** * Return the Hamming weight of this vector, i.e., compute the number of * units of this vector. * * @return the Hamming weight of this vector */
public int getHammingWeight() { int weight = 0; for (int i = 0; i < v.length; i++) { int e = v[i]; for (int j = 0; j < 32; j++) { int b = e & 1; if (b != 0) { weight++; } e >>>= 1; } } return weight; }
Returns:whether this is the zero vector (i.e., all elements are zero)
/** * @return whether this is the zero vector (i.e., all elements are zero) */
public boolean isZero() { for (int i = v.length - 1; i >= 0; i--) { if (v[i] != 0) { return false; } } return true; }
Return the value of the bit of this vector at the specified index.
Params:
  • index – the index
Returns:the value of the bit (0 or 1)
/** * Return the value of the bit of this vector at the specified index. * * @param index the index * @return the value of the bit (0 or 1) */
public int getBit(int index) { if (index >= length) { throw new IndexOutOfBoundsException(); } int q = index >> 5; int r = index & 0x1f; return (v[q] & (1 << r)) >>> r; }
Set the coefficient at the given index to 1. If the index is out of bounds, do nothing.
Params:
  • index – the index of the coefficient to set
/** * Set the coefficient at the given index to 1. If the index is out of * bounds, do nothing. * * @param index the index of the coefficient to set */
public void setBit(int index) { if (index >= length) { throw new IndexOutOfBoundsException(); } v[index >> 5] |= 1 << (index & 0x1f); }
Adds another GF2Vector to this vector.
Params:
  • other – another GF2Vector
Throws:
Returns:this + other
/** * Adds another GF2Vector to this vector. * * @param other another GF2Vector * @return <tt>this + other</tt> * @throws ArithmeticException if the other vector is not a GF2Vector or has another * length. */
public Vector add(Vector other) { if (!(other instanceof GF2Vector)) { throw new ArithmeticException("vector is not defined over GF(2)"); } GF2Vector otherVec = (GF2Vector)other; if (length != otherVec.length) { throw new ArithmeticException("length mismatch"); } int[] vec = IntUtils.clone(((GF2Vector)other).v); for (int i = vec.length - 1; i >= 0; i--) { vec[i] ^= v[i]; } return new GF2Vector(length, vec); }
Multiply this vector with a permutation.
Params:
  • p – the permutation
Returns:this*p = p*this
/** * 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("length mismatch"); } GF2Vector result = new GF2Vector(length); for (int i = 0; i < pVec.length; i++) { int e = v[pVec[i] >> 5] & (1 << (pVec[i] & 0x1f)); if (e != 0) { result.v[i >> 5] |= 1 << (i & 0x1f); } } return result; }
Return a new vector consisting of the elements of this vector with the indices given by the set setJ.
Params:
  • setJ – the set of indices of elements to extract
Returns:the new GF2Vector [this_setJ[0], this_setJ[1], ..., this_setJ[#setJ-1]]
/** * Return a new vector consisting of the elements of this vector with the * indices given by the set <tt>setJ</tt>. * * @param setJ the set of indices of elements to extract * @return the new {@link GF2Vector} * <tt>[this_setJ[0], this_setJ[1], ..., this_setJ[#setJ-1]]</tt> */
public GF2Vector extractVector(int[] setJ) { int k = setJ.length; if (setJ[k - 1] > length) { throw new ArithmeticException("invalid index set"); } GF2Vector result = new GF2Vector(k); for (int i = 0; i < k; i++) { int e = v[setJ[i] >> 5] & (1 << (setJ[i] & 0x1f)); if (e != 0) { result.v[i >> 5] |= 1 << (i & 0x1f); } } return result; }
Return a new vector consisting of the first k elements of this vector.
Params:
  • k – the number of elements to extract
Returns:a new GF2Vector consisting of the first k elements of this vector
/** * Return a new vector consisting of the first <tt>k</tt> elements of this * vector. * * @param k the number of elements to extract * @return a new {@link GF2Vector} consisting of the first <tt>k</tt> * elements of this vector */
public GF2Vector extractLeftVector(int k) { if (k > length) { throw new ArithmeticException("invalid length"); } if (k == length) { return new GF2Vector(this); } GF2Vector result = new GF2Vector(k); int q = k >> 5; int r = k & 0x1f; System.arraycopy(v, 0, result.v, 0, q); if (r != 0) { result.v[q] = v[q] & ((1 << r) - 1); } return result; }
Return a new vector consisting of the last k elements of this vector.
Params:
  • k – the number of elements to extract
Returns:a new GF2Vector consisting of the last k elements of this vector
/** * Return a new vector consisting of the last <tt>k</tt> elements of this * vector. * * @param k the number of elements to extract * @return a new {@link GF2Vector} consisting of the last <tt>k</tt> * elements of this vector */
public GF2Vector extractRightVector(int k) { if (k > length) { throw new ArithmeticException("invalid length"); } if (k == length) { return new GF2Vector(this); } GF2Vector result = new GF2Vector(k); int q = (length - k) >> 5; int r = (length - k) & 0x1f; int length = (k + 31) >> 5; int ind = q; // if words have to be shifted if (r != 0) { // process all but last word for (int i = 0; i < length - 1; i++) { result.v[i] = (v[ind++] >>> r) | (v[ind] << (32 - r)); } // process last word result.v[length - 1] = v[ind++] >>> r; if (ind < v.length) { result.v[length - 1] |= v[ind] << (32 - r); } } else { // no shift necessary System.arraycopy(v, q, result.v, 0, length); } return result; }
Rewrite this vector as a vector over GF(2m) with t elements.
Params:
  • field – the finite field GF(2m)
Returns:the converted vector over GF(2m)
/** * Rewrite this vector as a vector over <tt>GF(2<sup>m</sup>)</tt> with * <tt>t</tt> elements. * * @param field the finite field <tt>GF(2<sup>m</sup>)</tt> * @return the converted vector over <tt>GF(2<sup>m</sup>)</tt> */
public GF2mVector toExtensionFieldVector(GF2mField field) { int m = field.getDegree(); if ((length % m) != 0) { throw new ArithmeticException("conversion is impossible"); } int t = length / m; int[] result = new int[t]; int count = 0; for (int i = t - 1; i >= 0; i--) { for (int j = field.getDegree() - 1; j >= 0; j--) { int q = count >>> 5; int r = count & 0x1f; int e = (v[q] >>> r) & 1; if (e == 1) { result[i] ^= 1 << j; } count++; } } return new GF2mVector(field, result); }
Check if the given object is equal to this vector.
Params:
  • other – vector
Returns:the result of the comparison
/** * Check if the given object is equal to this vector. * * @param other vector * @return the result of the comparison */
public boolean equals(Object other) { if (!(other instanceof GF2Vector)) { return false; } GF2Vector otherVec = (GF2Vector)other; return (length == otherVec.length) && IntUtils.equals(v, otherVec.v); }
Returns:the hash code of this vector
/** * @return the hash code of this vector */
public int hashCode() { int hash = length; hash = hash * 31 + Arrays.hashCode(v); return hash; }
Returns:a human readable form of this vector
/** * @return a human readable form of this vector */
public String toString() { StringBuffer buf = new StringBuffer(); for (int i = 0; i < length; i++) { if ((i != 0) && ((i & 0x1f) == 0)) { buf.append(' '); } int q = i >> 5; int r = i & 0x1f; int bit = v[q] & (1 << r); if (bit == 0) { buf.append('0'); } else { buf.append('1'); } } return buf.toString(); } }