package org.bouncycastle.pqc.math.linearalgebra;
/**
* This class is a utility class for manipulating byte arrays.
*/
public final class ByteUtils
{
private static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* Default constructor (private)
*/
private ByteUtils()
{
// empty
}
/**
* Compare two byte arrays (perform null checks beforehand).
*
* @param left the first byte array
* @param right the second byte array
* @return the result of the comparison
*/
public static boolean equals(byte[] left, byte[] right)
{
if (left == null)
{
return right == null;
}
if (right == null)
{
return false;
}
if (left.length != right.length)
{
return false;
}
boolean result = true;
for (int i = left.length - 1; i >= 0; i--)
{
result &= left[i] == right[i];
}
return result;
}
/**
* Compare two two-dimensional byte arrays. No null checks are performed.
*
* @param left the first byte array
* @param right the second byte array
* @return the result of the comparison
*/
public static boolean equals(byte[][] left, byte[][] right)
{
if (left.length != right.length)
{
return false;
}
boolean result = true;
for (int i = left.length - 1; i >= 0; i--)
{
result &= ByteUtils.equals(left[i], right[i]);
}
return result;
}
/**
* Compare two three-dimensional byte arrays. No null checks are performed.
*
* @param left the first byte array
* @param right the second byte array
* @return the result of the comparison
*/
public static boolean equals(byte[][][] left, byte[][][] right)
{
if (left.length != right.length)
{
return false;
}
boolean result = true;
for (int i = left.length - 1; i >= 0; i--)
{
if (left[i].length != right[i].length)
{
return false;
}
for (int j = left[i].length - 1; j >= 0; j--)
{
result &= ByteUtils.equals(left[i][j], right[i][j]);
}
}
return result;
}
/**
* Computes a hashcode based on the contents of a one-dimensional byte array
* rather than its identity.
*
* @param array the array to compute the hashcode of
* @return the hashcode
*/
public static int deepHashCode(byte[] array)
{
int result = 1;
for (int i = 0; i < array.length; i++)
{
result = 31 * result + array[i];
}
return result;
}
/**
* Computes a hashcode based on the contents of a two-dimensional byte array
* rather than its identity.
*
* @param array the array to compute the hashcode of
* @return the hashcode
*/
public static int deepHashCode(byte[][] array)
{
int result = 1;
for (int i = 0; i < array.length; i++)
{
result = 31 * result + deepHashCode(array[i]);
}
return result;
}
/**
* Computes a hashcode based on the contents of a three-dimensional byte
* array rather than its identity.
*
* @param array the array to compute the hashcode of
* @return the hashcode
*/
public static int deepHashCode(byte[][][] array)
{
int result = 1;
for (int i = 0; i < array.length; i++)
{
result = 31 * result + deepHashCode(array[i]);
}
return result;
}
/**
* Return a clone of the given byte array (performs null check beforehand).
*
* @param array the array to clone
* @return the clone of the given array, or <tt>null</tt> if the array is
* <tt>null</tt>
*/
public static byte[] clone(byte[] array)
{
if (array == null)
{
return null;
}
byte[] result = new byte[array.length];
System.arraycopy(array, 0, result, 0, array.length);
return result;
}
/**
* Convert a string containing hexadecimal characters to a byte-array.
*
* @param s a hex string
* @return a byte array with the corresponding value
*/
public static byte[] fromHexString(String s)
{
char[] rawChars = s.toUpperCase().toCharArray();
int hexChars = 0;
for (int i = 0; i < rawChars.length; i++)
{
if ((rawChars[i] >= '0' && rawChars[i] <= '9')
|| (rawChars[i] >= 'A' && rawChars[i] <= 'F'))
{
hexChars++;
}
}
byte[] byteString = new byte[(hexChars + 1) >> 1];
int pos = hexChars & 1;
for (int i = 0; i < rawChars.length; i++)
{
if (rawChars[i] >= '0' && rawChars[i] <= '9')
{
byteString[pos >> 1] <<= 4;
byteString[pos >> 1] |= rawChars[i] - '0';
}
else if (rawChars[i] >= 'A' && rawChars[i] <= 'F')
{
byteString[pos >> 1] <<= 4;
byteString[pos >> 1] |= rawChars[i] - 'A' + 10;
}
else
{
continue;
}
pos++;
}
return byteString;
}
/**
* Convert a byte array to the corresponding hexstring.
*
* @param input the byte array to be converted
* @return the corresponding hexstring
*/
public static String toHexString(byte[] input)
{
String result = "";
for (int i = 0; i < input.length; i++)
{
result += HEX_CHARS[(input[i] >>> 4) & 0x0f];
result += HEX_CHARS[(input[i]) & 0x0f];
}
return result;
}
/**
* Convert a byte array to the corresponding hex string.
*
* @param input the byte array to be converted
* @param prefix the prefix to put at the beginning of the hex string
* @param seperator a separator string
* @return the corresponding hex string
*/
public static String toHexString(byte[] input, String prefix,
String seperator)
{
String result = new String(prefix);
for (int i = 0; i < input.length; i++)
{
result += HEX_CHARS[(input[i] >>> 4) & 0x0f];
result += HEX_CHARS[(input[i]) & 0x0f];
if (i < input.length - 1)
{
result += seperator;
}
}
return result;
}
/**
* Convert a byte array to the corresponding bit string.
*
* @param input the byte array to be converted
* @return the corresponding bit string
*/
public static String toBinaryString(byte[] input)
{
String result = "";
int i;
for (i = 0; i < input.length; i++)
{
int e = input[i];
for (int ii = 0; ii < 8; ii++)
{
int b = (e >>> ii) & 1;
result += b;
}
if (i != input.length - 1)
{
result += " ";
}
}
return result;
}
/**
* Compute the bitwise XOR of two arrays of bytes. The arrays have to be of
* same length. No length checking is performed.
*
* @param x1 the first array
* @param x2 the second array
* @return x1 XOR x2
*/
public static byte[] xor(byte[] x1, byte[] x2)
{
byte[] out = new byte[x1.length];
for (int i = x1.length - 1; i >= 0; i--)
{
out[i] = (byte)(x1[i] ^ x2[i]);
}
return out;
}
/**
* Concatenate two byte arrays. No null checks are performed.
*
* @param x1 the first array
* @param x2 the second array
* @return (x2||x1) (little-endian order, i.e. x1 is at lower memory
* addresses)
*/
public static byte[] concatenate(byte[] x1, byte[] x2)
{
byte[] result = new byte[x1.length + x2.length];
System.arraycopy(x1, 0, result, 0, x1.length);
System.arraycopy(x2, 0, result, x1.length, x2.length);
return result;
}
/**
* Convert a 2-dimensional byte array into a 1-dimensional byte array by
* concatenating all entries.
*
* @param array a 2-dimensional byte array
* @return the concatenated input array
*/
public static byte[] concatenate(byte[][] array)
{
int rowLength = array[0].length;
byte[] result = new byte[array.length * rowLength];
int index = 0;
for (int i = 0; i < array.length; i++)
{
System.arraycopy(array[i], 0, result, index, rowLength);
index += rowLength;
}
return result;
}
/**
* Split a byte array <tt>input</tt> into two arrays at <tt>index</tt>,
* i.e. the first array will have the lower <tt>index</tt> bytes, the
* second one the higher <tt>input.length - index</tt> bytes.
*
* @param input the byte array to be split
* @param index the index where the byte array is split
* @return the splitted input array as an array of two byte arrays
* @throws ArrayIndexOutOfBoundsException if <tt>index</tt> is out of bounds
*/
public static byte[][] split(byte[] input, int index)
throws ArrayIndexOutOfBoundsException
{
if (index > input.length)
{
throw new ArrayIndexOutOfBoundsException();
}
byte[][] result = new byte[2][];
result[0] = new byte[index];
result[1] = new byte[input.length - index];
System.arraycopy(input, 0, result[0], 0, index);
System.arraycopy(input, index, result[1], 0, input.length - index);
return result;
}
/**
* Generate a subarray of a given byte array.
*
* @param input the input byte array
* @param start the start index
* @param end the end index
* @return a subarray of <tt>input</tt>, ranging from <tt>start</tt>
* (inclusively) to <tt>end</tt> (exclusively)
*/
public static byte[] subArray(byte[] input, int start, int end)
{
byte[] result = new byte[end - start];
System.arraycopy(input, start, result, 0, end - start);
return result;
}
/**
* Generate a subarray of a given byte array.
*
* @param input the input byte array
* @param start the start index
* @return a subarray of <tt>input</tt>, ranging from <tt>start</tt> to
* the end of the array
*/
public static byte[] subArray(byte[] input, int start)
{
return subArray(input, start, input.length);
}
/**
* Rewrite a byte array as a char array
*
* @param input -
* the byte array
* @return char array
*/
public static char[] toCharArray(byte[] input)
{
char[] result = new char[input.length];
for (int i = 0; i < input.length; i++)
{
result[i] = (char)input[i];
}
return result;
}
}