gov.sandia.cognition.hash.HashFunctionUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cognitive-foundry Show documentation
Show all versions of cognitive-foundry Show documentation
A single jar with all the Cognitive Foundry components.
/*
* File: HashFunctionUtil.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright Jan 26, 2011, Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the U.S. Government.
* Export of this program may require a license from the United States
* Government. See CopyrightHistory.txt for complete details.
*
*/
package gov.sandia.cognition.hash;
import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationType;
/**
* Static class with helper functions for hash codes
* @author Kevin R. Dixon
* @since 3.4.2
*/
public class HashFunctionUtil
{
/**
* Converts an int into a 4-byte array in Big Endian order
* (most-significant byte in slot 0)
* @param value
* Integer to convert
* @return
* 4-byte array in Big Endian order (most-significant byte in slot 0)
*/
public static byte[] toByteArray(
int value )
{
byte[] output = new byte[4];
toByteArray(value, output);
return output;
}
/**
* Converts an int into a 4-byte array in Big Endian order
* (most-significant byte in slot 0)
* @param value
* Integer to convert
* @param output
* 4-byte array to store the int
*/
public static void toByteArray(
int value,
byte[] output )
{
if( output.length != 4 )
{
throw new IllegalArgumentException(
"Expected output array of length 4, got length = " + output.length );
}
output[0] = (byte)(value >>> 24);
output[1] = (byte)(value >>> 16);
output[2] = (byte)(value >>> 8);
output[3] = (byte)(value);
}
/**
* Converts a long into an 8-byte array in Big Endian order
* (most-significant byte in slot 0)
* @param value
* long to convert
* @return
* 8-byte array to store the long
*/
public static byte[] toByteArray(
long value )
{
byte[] output = new byte[8];
toByteArray(value, output);
return output;
}
/**
* Converts a long into an 8-byte array in Big Endian order
* (most-significant byte in slot 0)
* @param value
* long to convert
* @param output
* 8-byte array to store the long
*/
public static void toByteArray(
long value,
byte[] output )
{
if( output.length != 8 )
{
throw new IllegalArgumentException(
"Expected output array of length 8, got length = " + output.length );
}
output[0] = (byte)(value >>> 56);
output[1] = (byte)(value >>> 48);
output[2] = (byte)(value >>> 40);
output[3] = (byte)(value >>> 32);
output[4] = (byte)(value >>> 24);
output[5] = (byte)(value >>> 16);
output[6] = (byte)(value >>> 8);
output[7] = (byte)(value);
}
/**
* Cascades the hash codes
* @param hash
* HashFunction used to compute the results
* @param ordered
* true for ordered hash, false for unordered
* @param inputs
* Inputs to compute the hash of
* @return
* Cascaded hash function of the inputs
*/
public static byte[] combineHash(
HashFunction hash,
boolean ordered,
byte[] ... inputs )
{
byte[] seed = hash.getDefaultSeed();
byte[] output = new byte[ hash.length() ];
byte[] total = new byte[ hash.length() ];
for( int n = 0; n < inputs.length; n++ )
{
if( ordered )
{
for( int i = 0; i < seed.length; i++ )
{
seed[i]++;
}
}
// Use the previous output as the seed into the next hash
hash.evaluateInto(inputs[n], output, seed );
for( int i = 0; i < output.length; i++ )
{
total[i] += output[i];
}
}
return total;
}
/**
* Computes the salted hash of the given inputs, that is, we concatenate
* the inputs together and compute the hash of the concatenated bytes.
* @param hash
* HashFunction that computes the hash
* @param inputs
* Ordered inputs to the hash function
* @return
* Output into which we place the output (salted hash)
*/
public static byte[] salt(
final HashFunction hash,
final byte[] ... inputs )
{
byte[] output = new byte[ hash.length() ];
saltInto( output, hash, inputs );
return output;
}
/**
* Computes the salted hash of the given inputs, that is, we concatenate
* the inputs together and compute the hash of the concatenated bytes.
* @param output
* Output into which we place the output (salted hash)
* @param hash
* HashFunction that computes the hash
* @param inputs
* Ordered inputs to the hash function
*/
public static void saltInto(
final byte[] output,
final HashFunction hash,
final byte[] ... inputs )
{
// Combine the inputs together
int length = 0;
for( int i = 0; i < inputs.length; i++ )
{
length += inputs[i].length;
}
// We just concatenate the inputs together
final byte[] saltedInput = new byte[ length ];
int offset = 0;
for( int i = 0; i < inputs.length; i++ )
{
final int il = inputs[i].length;
System.arraycopy(inputs[i], 0, saltedInput, offset, il );
offset += il;
}
hash.evaluateInto(saltedInput, output);
}
/**
* Char table for convenience
*/
static final char[] HEX_CHAR_TABLE = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
/**
* Converts the given int to a Big Endian hex string
* @param input
* Input to convert
* @return
* hex string (8 chars)
*/
public static String toHexString(
int input )
{
// Java's Integer.toHexString doesn't put the leading zero if needed,
// so we have to do it ourselves... sigh.
char[] hex = new char[ 8 ];
int index = 0;
for( int i = 0; i < 4; i++ )
{
// If we didn't do the 24-8*i, then we'd end up with a
// Little Endian result... gross.
final int b = (input >>> (24-8*i)) & 0xFF;
hex[index++] = HEX_CHAR_TABLE[b >>> 4];
hex[index++] = HEX_CHAR_TABLE[b & 0xF];
}
String result = null;
try
{
result = new String(hex);
}
catch (Exception e)
{
throw new RuntimeException( e );
}
return result;
}
/**
* Converts the given long to a Big Endian hex string
* @param input
* Input to convert
* @return
* hex string (16 chars)
*/
public static String toHexString(
long input )
{
// Java's Integer.toHexString doesn't put the leading zero if needed,
// so we have to do it ourselves... sigh.
char[] hex = new char[ 16 ];
int index = 0;
for( int i = 0; i < 8; i++ )
{
// If we didn't do the 24-8*i, then we'd end up with a
// Little Endian result... gross.
final int b = (int) ((input >>> (56-8*i)) & 0xFF);
hex[index++] = HEX_CHAR_TABLE[b >>> 4];
hex[index++] = HEX_CHAR_TABLE[b & 0xF];
}
String result = null;
try
{
result = new String(hex);
}
catch (Exception e)
{
throw new RuntimeException( e );
}
return result;
}
/**
* Converts a byte array to a lower-case Hex string
* @param bytes
* byte array to convert
* @return
* String representing the byte array
*/
public static String toHexString(
byte[] bytes )
{
char[] hex = new char[ 2*bytes.length];
int index = 0;
for( int i = 0; i < bytes.length; i++ )
{
final int b = (bytes[i] & 0xFF);
hex[index++] = HEX_CHAR_TABLE[b >>> 4];
hex[index++] = HEX_CHAR_TABLE[b & 0xF];
}
String result = null;
try
{
result = new String(hex);
}
catch (Exception e)
{
throw new RuntimeException( e );
}
return result;
}
/**
* Returns the hex value of the given character
* @param hexChar
* Hex character, such as '0' or 'A'
* @return
* The value of the hex character.
*/
public static byte valueOf(
char hexChar )
{
hexChar = Character.toLowerCase(hexChar);
for( byte i = 0; i < HEX_CHAR_TABLE.length; i++ )
{
if( hexChar == HEX_CHAR_TABLE[i] )
{
return i;
}
}
throw new IllegalArgumentException( hexChar + " is not a hex char" );
}
/**
* Converts the hex-string back into an array of bytes
* @param hexString
* Hex string, such as "0123456789ABCDEF", where each byte is represented
* by two characters
* @return
* Byte representation of the hex string, will be half the length of string
*/
public static byte[] fromHexString(
String hexString )
{
// It takes two chars to represent a single byte
final int sl = hexString.length();
if( (sl % 2) != 0 )
{
throw new IllegalArgumentException( "hexString must be even length" );
}
byte[] bytes = new byte[ sl/2 ];
for( int i = 0; i < sl; i += 2 )
{
final int j = i/2;
byte high = valueOf(hexString.charAt(i));
byte low = valueOf(hexString.charAt(i+1));
byte value = (byte) (((high & 0xf) << 4) | (low & 0xf));
bytes[j] = value;
}
return bytes;
}
/**
* Converts the 4-byte array to a Big Endian int.
* @param data
* 4-byte array to convert
* @return
* Big Endian int representation of the byte array
*/
public static int toInteger(
final byte[] data )
{
if( data.length != 4 )
{
throw new IllegalArgumentException(
"data must be of length 4" );
}
return toInteger(data,0);
}
/**
* Converts the 4 bytes in the given array starting at "offset"
* to a Big Endian int.
* @param data
* Array to convert
* @param offset
* Offset into the array
* @return
* Big Endian int representation of the byte array at offset
*/
public static int toInteger(
final byte[] data,
final int offset )
{
return ((data[offset ] & 0xff) << 24)
| ((data[offset+1] & 0xff) << 16)
| ((data[offset+2] & 0xff) << 8)
| ((data[offset+3] & 0xff) );
}
/**
* Converts the 8-byte value to a Big Endian long
* @param data
* byte array to convert
* @return
* Long of the given byte array
*/
public static long toLong(
final byte[] data )
{
if( data.length != 8 )
{
throw new IllegalArgumentException(
"data must be of length 8" );
}
return toLong( data, 0 );
}
/**
* Converts the 8-byte value at "offset" to a Big Endian long
* @param data
* byte array to convert
* @param offset
* Offset into the byte array
* @return
* Long at the given offset
*/
public static long toLong(
final byte[] data,
final int offset )
{
return ((data[offset ] & 0xffL) << 56)
| ((data[offset+1] & 0xffL) << 48)
| ((data[offset+2] & 0xffL) << 40)
| ((data[offset+3] & 0xffL) << 32)
| ((data[offset+4] & 0xffL) << 24)
| ((data[offset+5] & 0xffL) << 16)
| ((data[offset+6] & 0xffL) << 8)
| ((data[offset+7] & 0xffL) );
}
/**
* Determines if a number is prime or not
* @param num
* Number to determine if it's a prime number or not
* @return
* True if prime, false if not
*/
@PublicationReference(
author="Snort IDS",
title="sfhashfcn.c",
type= PublicationType.Misc,
year=2012,
url="http://www.rajivchakravorty.com/source-code/.tmp/snort-html/sfhashfcn_8c-source.html",
notes= {
"Not an efficient implementation.",
"My improvements make the algorithm O(sqrt(n/2)), instead of O(n), but it still sucks"
}
)
public static boolean isPrime(
long num )
{
// TODO: Implement the AKS primality test using the library
// http://www-ti.informatik.uni-tuebingen.de/~reinhard/krypto/AKSTest/AKSTest.java
if( num == 2 )
{
return true;
}
else if( num == 3 )
{
return true;
}
// See if the number is even
else if( (num % 2) == 0 )
{
return false;
}
else if( (num % 3) == 0 )
{
return false;
}
// We only need to go up to the square root to check factors
// and not check even numbers, so we can increment by 2
long max = (long) Math.floor(Math.sqrt(num));
for( long i = 5; i <= max; i += 6 )
{
if( (num % i) == 0 )
{
return false;
}
else if( (num % (i+2)) == 0 )
{
return false;
}
}
return true;
}
/**
* Returns the next-greater prime, sort of like "ceil" but for primes.
* @param num
* Number to return the next-greater prime number of
* @return
* Prime number such that it is greater than or equal to "num"
*/
@PublicationReference(
author="Snort IDS",
title="sfhashfcn.c",
type= PublicationType.Misc,
year=2012,
url="http://www.rajivchakravorty.com/source-code/.tmp/snort-html/sfhashfcn_8c-source.html",
notes= "Not an efficient implementation."
)
public static long nextPrime(
long num )
{
while( !isPrime(num) )
{
num++;
}
return num;
}
}