All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.pqc.math.linearalgebra.GF2Vector Maven / Gradle / Ivy

The newest version!
package org.bouncycastle.pqc.math.linearalgebra;

import java.security.SecureRandom;

/**
 * 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 Vector */ public class GF2Vector extends Vector { /** * holds the elements of this vector */ private int[] v; /** * 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. * * @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. * * @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. * * @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. * * @param other another {@link GF2Vector} */ public GF2Vector(GF2Vector other) { this.length = other.length; this.v = IntUtils.clone(other.v); } /** * 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. * * @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. * * @return the encoded vector */ public byte[] getEncoded() { int byteLen = (length + 7) >> 3; return LittleEndianConversions.toByteArray(v, byteLen); } /** * @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. * * @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; } /** * @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. * * @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. * * @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. * * @param other another GF2Vector * @return this + other * @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. * * @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("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. * * @param setJ the set of indices of elements to extract * @return the new {@link GF2Vector} * [this_setJ[0], this_setJ[1], ..., this_setJ[#setJ-1]] */ 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. * * @param k the number of elements to extract * @return a new {@link GF2Vector} consisting of the first k * 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. * * @param k the number of elements to extract * @return a new {@link GF2Vector} consisting of the last k * 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. * * @param field the finite field GF(2m) * @return the converted vector over GF(2m) */ 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. * * @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); } /** * @return the hash code of this vector */ public int hashCode() { int hash = length; hash = hash * 31 + v.hashCode(); return hash; } /** * @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(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy