#if !defined __PMP_MULTILINEAR_HASHER_NAIVE_H__
#define __PMP_MULTILINEAR_HASHER_NAIVE_H__
#include "PMP_Multilinear_common_naive.h"
#define PMPML_LEVELS_MAX 8
#define PMPML_CHUNK_SIZE_MAX 128
class PMP_Multilinear_Hasher_Naive
{
private:
const random_data_for_MPSHF* curr_rd;
uint64_t hash_of_string_chunk( const uint32_t* coeff, uint64_t constTerm, const uint32_t* x ) const
{
int128_t ret = constTerm;
int128_t temp;
for ( int i=0; i<PMPML_CHUNK_SIZE; i++ )
{
temp = x[ i ];
temp = temp * coeff[ i ];
ret += temp;
}
ret = ret % PMPML_MAIN_PRIME;
return ret.template convert_to<uint64_t>();
}
uint64_t hash_of_beginning_of_string_chunk( const uint32_t* coeff, uint64_t constTerm, const uint32_t* x, uint32_t size ) const
{
int128_t ret = constTerm;
int128_t temp;
for ( int i=0; i<size; i++ )
{
temp = x[ i ];
temp = temp * coeff[ i ];
ret += temp;
}
ret = ret % PMPML_MAIN_PRIME;
return ret.template convert_to<uint64_t>();
}
uint64_t updated_string_chunk_hash_withElement32( const uint32_t coeff, uint32_t x, uint64_t iniHashVal ) const
{
int128_t ret = x;
ret = ret * coeff;
ret = ret + iniHashVal;
ret = ret % PMPML_MAIN_PRIME;
return ret.template convert_to<uint64_t>();
}
uint64_t hash_of_num_chunk( const uint32_t* coeff, uint64_t constTerm, const uint64_t* x ) const
{
int128_t ret = constTerm;
int128_t temp;
for ( int i=0; i<PMPML_CHUNK_SIZE; i++ )
{
temp = x[ i ];
temp *= coeff[ i ];
ret += temp;
}
ret = ret % PMPML_MAIN_PRIME;
return ret.template convert_to<uint64_t>();
}
void procesNextValue( int level, uint64_t value, uint64_t * allValues, uint32_t * cnts, uint32_t& flag ) const
{
for ( int i=level;;i++ )
{
allValues[ ( i << PMPML_CHUNK_SIZE_LOG2 ) + cnts[ i ] ] = value;
(cnts[ i ]) ++;
if ( cnts[ i ] != PMPML_CHUNK_SIZE )
break;
cnts[ i ] = 0;
value = hash_of_num_chunk( curr_rd[ i ].random_coeff, curr_rd[ i ].const_term, allValues + ( i << PMPML_CHUNK_SIZE_LOG2 ) );
if ( ( flag & ( 1 << i ) ) == 0 )
{
cnts[ i + 1] = 0;
flag |= 1 << i;
}
}
}
uint64_t finalize( int level, uint64_t * allValues, uint32_t * cnts, uint32_t& flag ) const
{
for ( int i=level;;i++ )
{
if ( ( ( flag & ( 1 << i ) ) == 0 ) && cnts[ i ] == 1 )
{
return allValues[ i << PMPML_CHUNK_SIZE_LOG2 ];
}
if ( cnts[ i ] )
{
for ( int j=cnts[ i ]; j<PMPML_CHUNK_SIZE; j++ )
( allValues + ( i << PMPML_CHUNK_SIZE_LOG2 ) )[ j ] = curr_rd[ i - 1 ].const_term;
if ( ( flag & ( 1 << i ) ) == 0 )
{
cnts[ i + 1] = 0;
flag |= 1 << i;
}
procesNextValue( i + 1,
hash_of_num_chunk( curr_rd[ i ].random_coeff,
curr_rd[ i ].const_term,
allValues + ( i << PMPML_CHUNK_SIZE_LOG2 ) ),
allValues, cnts, flag );
}
}
}
public:
uint32_t hash( const unsigned char* chars, uint32_t cnt ) const
{
uint64_t allValues[ PMPML_LEVELS * PMPML_CHUNK_SIZE ];
uint32_t cnts[ PMPML_LEVELS ];
uint32_t flag;
cnts[ 1 ] = 0;
flag = 0;
uint32_t i;
uint64_t tmp_hash;
for ( i=0; i<(cnt>>PMPML_CHUNK_SIZE_BYTES_LOG2); i++ )
{
tmp_hash = hash_of_string_chunk( curr_rd[ 0 ].random_coeff, curr_rd[ 0 ].const_term, ((const uint32_t*)(chars)) + ( i << PMPML_CHUNK_SIZE_LOG2 ) );
procesNextValue( 1, tmp_hash, allValues, cnts, flag );
}
uint32_t tailCnt = cnt & ( PMPML_CHUNK_SIZE_BYTES - 1 );
if ( tailCnt )
{
const unsigned char* tail = chars + ( (cnt>>PMPML_CHUNK_SIZE_BYTES_LOG2) << PMPML_CHUNK_SIZE_BYTES_LOG2 );
tmp_hash = hash_of_beginning_of_string_chunk( curr_rd[0].random_coeff, curr_rd[0].const_term, (const uint32_t*)tail, tailCnt >> PMPML_WORD_SIZE_BYTES_LOG2 );
static const uint32_t masks[ 4 ] = { 0x0, 0xFF, 0xFFFF, 0xFFFFFF };
static const uint32_t ones[ 4 ] = { 0x1, 0x100, 0x10000, 0x1000000 };
uint32_t temp = *( ((const uint32_t*)tail) + ( tailCnt >> PMPML_WORD_SIZE_BYTES_LOG2 ) );
temp &= masks[ tailCnt & ( PMPML_WORD_SIZE_BYTES - 1 ) ];
temp |= ones[ tailCnt & ( PMPML_WORD_SIZE_BYTES - 1 ) ];
tmp_hash = updated_string_chunk_hash_withElement32( curr_rd[ 0 ].random_coeff[ tailCnt >> PMPML_WORD_SIZE_BYTES_LOG2 ], temp, tmp_hash );
}
else
{
tmp_hash = ( curr_rd[ 0 ].random_coeff[0] + curr_rd[0].const_term ) % PMPML_MAIN_PRIME;
}
procesNextValue( 1, tmp_hash, allValues, cnts, flag );
tmp_hash = finalize( 1, allValues, cnts, flag );
if ( ( tmp_hash >> 32 ) == 0 )
return fmix32_short( (uint32_t)tmp_hash );
else
return (uint32_t)tmp_hash;
}
PMP_Multilinear_Hasher_Naive()
{
curr_rd = rd_for_MPSHF;
}
virtual ~PMP_Multilinear_Hasher_Naive()
{
if ( curr_rd != NULL && curr_rd != rd_for_MPSHF )
delete [] curr_rd;
}
void randomize( UniformRandomNumberGenerator& rng )
{
random_data_for_MPSHF * temp_curr_rd = new random_data_for_MPSHF[ PMPML_LEVELS ];
int i, j;
for ( i=0; i<PMPML_LEVELS; i++ )
for ( j=0; j<PMPML_CHUNK_SIZE; j++ )
{
do
{
temp_curr_rd[ i ].random_coeff[ j ] = rng.rand();
}
while ( !IS_VALID_COEFFICIENT( temp_curr_rd[ i ].random_coeff[ j ], i ) );
}
for ( i=0; i<PMPML_LEVELS; i++ )
{
uint64_t rv;
do
{
rv = rng.rand();
rv <<= 32;
rv |= rng.rand();
}
while ( rv == 0 );
rv = rv % PMPML_MAIN_PRIME;
temp_curr_rd[ i ].const_term = rv;
}
if ( curr_rd == rd_for_MPSHF )
curr_rd = temp_curr_rd;
else
{
if ( curr_rd != NULL )
delete [] curr_rd;
curr_rd = temp_curr_rd;
}
}
};
#endif