diff --git a/Cargo.toml b/Cargo.toml index 522907a..7c2f214 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "gxhash" authors = ["Olivier Giniaux"] -version = "2.1.0" +version = "2.2.0" edition = "2021" description = "GxHash non-cryptographic algorithm" license = "MIT" diff --git a/README.md b/README.md index 8c0f9c5..0c101e8 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,6 @@ let mut hashset = GxHashSet::default(); hashset.insert("hello world"); ``` -> **Warning** -> This is a non-cryptographic hashing algorithm, thus it is not recommended to use it as a cryptographic algorithm (it is not a replacement for SHA). - ## Compatibility - ARM 64-bit using `NEON` intrinsics. - x86-64 bit using `SSE2` + `AES` intrinsics. @@ -40,6 +37,14 @@ hashset.insert("hello world"); > **Warning** > Other platforms are currently not supported (there is no fallback) +## Security +### DOS Resistance ✅ +Because GxHash is a seeded hashing algorithm, meaning that depending on the seed used, it will generate completely different hashes. The default `Hasher` (`GxHasher::default()`) randomizes the seed on creation, making it any `HashMap`/`HashSet` DOS resistant, as no attacker will be able to predict which hashes may collide without knowing the seed used. +### Multicollisions Resistance ✅ +GxHash uses a 128-bit internal state (and even 256-bit with the `avx2` feature). This makes GxHash [a widepipe construction](https://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction#Wide_pipe_construction) when generating hashes of size 64-bit or smaller, which had amongst other properties to be inherently more resistant to multicollision attacks. See [this paper](https://www.iacr.org/archive/crypto2004/31520306/multicollisions.pdf) for more details. +### Cryptographic Properties ❌ +GxHash is a non-cryptographic hashing algorithm, thus it is not recommended to use it as a cryptographic algorithm (it is not a replacement for SHA). It has not been assessed if GxHash is preimage resistant and wether how likely it is to be reversed. + ## Benchmarks Displayed numbers are throughput in Mibibytes of data hashed per second. Higher is better. To run the benchmarks: `cargo bench --bench throughput`. diff --git a/src/hasher.rs b/src/hasher.rs index 8449493..b101e30 100644 --- a/src/hasher.rs +++ b/src/hasher.rs @@ -1,20 +1,51 @@ use std::hash::{Hasher, BuildHasherDefault}; use std::collections::{HashMap, HashSet}; + +use rand::Rng; + use crate::gxhash::*; use crate::gxhash::platform::*; /// A `Hasher` for hashing an arbitrary stream of bytes. +/// # Features +/// - The fastest [`Hasher`] of its class1, for all input sizes +/// - Highly collision resitant +/// - DOS resistant thanks to seed randomization when using [`GxHasher::default()`] +/// +/// *1There might me faster alternatives, such as `fxhash` for very small input sizes, but that usually have low quality properties.* pub struct GxHasher(State); impl Default for GxHasher { + /// Create a new hasher with a random seed for DOS resistance. + /// + /// # Example + /// + /// ``` + /// use std::hash::Hasher; + /// use gxhash::GxHasher; + /// + /// let mut hasher = GxHasher::default(); + /// + /// hasher.write(b"Hello"); + /// hasher.write_u32(123); + /// hasher.write_u8(42); + /// + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` #[inline] fn default() -> GxHasher { - GxHasher(unsafe { create_empty() }) + let mut rng = rand::thread_rng(); + let seed: i64 = rng.gen::(); + GxHasher(unsafe { create_seed(seed) }) } } impl GxHasher { /// Creates a new hasher using the provided seed. + /// + /// # Warning ⚠️ + /// Hardcoding a seed may make your [`Hasher`] vulnerable to DOS attacks. + /// It is recommended to use [`GxHasher::default()`] to create a DOS resistant [`Hasher`]. /// /// # Example ///