fnv0 1.1.0

FNV0/1/1a 32/64/128-bit hash functions
Documentation
// FNV hash for Rust
//
// Written by Radim Kolar <hsn@sendmail.cz> 2024
//
// SPDX-License-Identifier: CC0-1.0 OR Unlicense

pub const FNV0_32_INIT : u32 = 0;
pub const FNV1_32_INIT : u32 = 0x811c9dc5;
pub const FNV1A_32_INIT : u32 = FNV1_32_INIT;

pub const FNV0_64_INIT : u64 = 0;
pub const FNV1_64_INIT : u64 = 0xcbf29ce484222325;
pub const FNV1A_64_INIT : u64 = FNV1_64_INIT;

pub const FNV0_128_INIT : u128 = 0;
pub const FNV1_128_INIT: u128 = 0x6c62272e07bb014262b821756295c58d;
pub const FNV1A_128_INIT : u128 = FNV1_128_INIT;

pub const FNV_128_PRIME: u128 = 0x1000000000000000000013b;
pub const FNV_64_PRIME: u64 = 0x100000001b3;
pub const FNV_32_PRIME: u32 = 0x01000193;

proc_strarray::str_array!(FNV_BASIS, r#"chongo <Landon Curt Noll> /\../\"#, 32);

/*
# FNV prime
An FNV prime is a prime number and is determined as follows:

For a given integer s such that 4 < s < 11, let n = 2^s and t = [(5 + n) / 12];
then the n-bit FNV prime is the smallest prime number p that is of the form

256^t + 2^8 + b

such that:
* 0 < b < 2^8
* the number of one-bits in the binary representation of b is either 4 or 5
* p mod (2^40 - 2^24 - 1) > 2^24 + 2^8 + 7

FNV primes matching the above constraints tend to have better dispersion
properties. They improve the polynomial feedback characteristic when
an FNV prime multiplies an intermediate hash value. As such, the hash values
produced are more scattered throughout the n-bit hash space.
*/

pub fn fnv_32(buf: &[u8], hval: u32) -> u32
{
   let mut hash = hval;
   /*
    * FNV-1 hash each octet in the buffer
    */
   for byte in buf {
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
      hash = hash.wrapping_mul(FNV_32_PRIME);
      /* xor the bottom with the current octet */
      hash ^= *byte as u32;
   }
   /* return our new hash value */
   hash
}

pub fn fnv_32a(buf: &[u8], hval: u32) -> u32
{
   let mut hash = hval;
   /*
    * FNV-1a hash each octet in the buffer
    */
   for byte in buf {
      /* xor the bottom with the current octet */
      hash ^= *byte as u32;
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
      hash = hash.wrapping_mul(FNV_32_PRIME);
   }
   /* return our new hash value */
   hash
}


pub fn fnv_64(buf: &[u8], hval: u64) -> u64
{
   let mut hash = hval;
   /*
    * FNV-1 hash each octet in the buffer
    */
   for byte in buf {
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
      hash = hash.wrapping_mul(FNV_64_PRIME);
      /* xor the bottom with the current octet */
      hash ^= *byte as u64;
   }
   /* return our new hash value */
   hash
}

pub fn fnv_64a(buf: &[u8], hval: u64) -> u64
{
   let mut hash = hval;
   /*
    * FNV-1 hash each octet in the buffer
    */
   for byte in buf {
      /* xor the bottom with the current octet */
      hash ^= *byte as u64;
      /* multiply by the 64 bit FNV magic prime mod 2^64 */
      hash = hash.wrapping_mul(FNV_64_PRIME);
   }
   /* return our new hash value */
   hash
}


pub fn fnv_128(buf: &[u8], hval: u128) -> u128
{
   let mut hash = hval;
   /*
    * FNV-1 hash each octet in the buffer
    */
   for byte in buf {
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
      hash = hash.wrapping_mul(FNV_128_PRIME);
      /* xor the bottom with the current octet */
      hash ^= *byte as u128;
   }
   /* return our new hash value */
   hash
}

pub fn fnv_128a(buf: &[u8], hval: u128) -> u128
{
   let mut hash = hval;
   /*
    * FNV-1 hash each octet in the buffer
    */
   for byte in buf {
      /* xor the bottom with the current octet */
      hash ^= *byte as u128;
      /* multiply by the 128 bit FNV magic prime mod 2^128 */
      hash = hash.wrapping_mul(FNV_128_PRIME);
   }
   /* return our new hash value */
   hash
}


#[cfg(test)]
#[path = "offset_basis_tests.rs"]
mod offset_bassis_tests;

#[cfg(test)]
#[path = "testsuite.rs"]
mod fnv_test;