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
///