Skip to main content

xxhash/
xxhash.rs

1#![no_std]
2#![allow(unexpected_cfgs)]
3
4//! xxHash — extremely fast non-cryptographic hash algorithm.
5//!
6//! Provides four variants:
7//!
8//! | Struct | Bits | Description |
9//! |--------|------|-------------|
10//! | [`Xxh3_64`] | 64 | Recommended — XXH3 algorithm, faster on modern CPUs |
11//! | [`Xxh3_128`] | 128 | Recommended — XXH3 algorithm, 128-bit output |
12//! | [`Xxh32`] | 32 | Classic xxHash (XXH32) |
13//! | [`Xxh64`] | 64 | Classic xxHash (XXH64) |
14//!
15//! **Prefer [`Xxh3_64`] or [`Xxh3_128`] for new code.** XXH3 is the modern
16//! variant: ~2x faster on large inputs and >3x faster on small inputs
17//! compared to the classic XXH64, with better hash quality.
18//!
19//! All types implement the [`Checksum`] trait.
20//!
21//! # Const one-shot hashing
22//!
23//! Use the free functions [`xxh32`], [`xxh64`], [`xxh3_64`], and
24//! [`xxh3_128`] for `const`-compatible one-shot hashing:
25//!
26//! ```rust
27//! use xxhash::xxh3_64;
28//!
29//! const HASH: u64 = xxh3_64(b"hello");
30//! assert_eq!(HASH, 0x9555E8555C62DCFD);
31//! ```
32//!
33//! # Examples
34//!
35//! ## One-shot hashing (via trait)
36//!
37//! ```rust
38//! use xxhash::{Xxh3_64, Checksum};
39//!
40//! let hash: u64 = Xxh3_64::checksum(b"hello world");
41//! ```
42//!
43//! ## Incremental hashing
44//!
45//! ```rust
46//! use xxhash::{Xxh3_128, Checksum};
47//!
48//! let mut hasher = Xxh3_128::new();
49//! hasher.update(b"hello ");
50//! hasher.update(b"world");
51//! let hash: u128 = hasher.sum();
52//! ```
53//!
54//! ## Seeded hashing
55//!
56//! ```rust
57//! use xxhash::{Xxh3_64, Checksum};
58//!
59//! let mut hasher = Xxh3_64::with_seed(42);
60//! hasher.update(b"data");
61//! let hash: u64 = hasher.sum();
62//! ```
63//!
64//! ## XXH3 with a custom secret
65//!
66//! ```rust
67//! use xxhash::{Xxh3_64, Checksum};
68//!
69//! let secret = [0xAB; 192];
70//! let mut hasher = Xxh3_64::with_secret(secret);
71//! hasher.update(b"data");
72//! let hash: u64 = hasher.sum();
73//! ```
74
75use core::fmt;
76
77#[cfg(target_arch = "aarch64")]
78#[path = "xxh3_neon.rs"]
79mod xxh3_neon;
80
81#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
82#[path = "xxh3_avx2.rs"]
83mod xxh3_avx2;
84
85#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
86#[path = "xxh3_avx512.rs"]
87mod xxh3_avx512;
88
89#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
90#[path = "xxh3_wasm_simd128.rs"]
91mod xxh3_wasm_simd128;
92
93mod xxh3;
94mod xxh32;
95mod xxh64;
96
97mod sealed {
98    pub trait Sealed {}
99    impl Sealed for u32 {}
100    impl Sealed for u64 {}
101    impl Sealed for u128 {}
102}
103
104/// Trait for types that can be used as xxHash outputs.
105///
106/// This trait is sealed and only implemented for `u32`, `u64`, and `u128`.
107pub trait ChecksumOutput: sealed::Sealed + Copy + Clone + fmt::Debug + PartialEq + 'static {}
108
109impl ChecksumOutput for u32 {}
110impl ChecksumOutput for u64 {}
111impl ChecksumOutput for u128 {}
112
113/// A trait for computing checksums.
114///
115/// Types implementing this trait can compute a hash incrementally via
116/// [`update`](Checksum::update) and [`sum`](Checksum::sum), or in a single
117/// call via [`checksum`](Checksum::checksum).
118pub trait Checksum {
119    /// The type of the resulting checksum value.
120    type Output: ChecksumOutput;
121
122    /// Create a new checksum instance with default settings (seed = 0,
123    /// default secret for XXH3 variants).
124    fn new() -> Self;
125
126    /// Compute the checksum of `data` in a single call.
127    fn checksum(data: &[u8]) -> Self::Output
128    where
129        Self: Sized,
130    {
131        let mut hasher = Self::new();
132        hasher.update(data);
133        hasher.sum()
134    }
135
136    /// Feed additional data into the checksum.
137    fn update(&mut self, data: &[u8]);
138
139    /// Finalize and return the computed checksum value.
140    fn sum(self) -> Self::Output;
141}
142
143pub use xxh3::{Xxh3_64, Xxh3_128, xxh3_64, xxh3_128};
144pub use xxh32::{Xxh32, xxh32};
145pub use xxh64::{Xxh64, xxh64};
146
147#[cfg(test)]
148mod test_helpers {
149    extern crate alloc;
150
151    /// Fills a buffer with pseudorandom data, exactly matching the C reference's
152    /// `XSUM_fillTestBuffer` from `xsum_sanity_check.c`.
153    ///
154    /// The PRNG uses:
155    /// - `byteGen` initialized to `PRIME32` (0x9E3779B1)
156    /// - Each iteration: `buf[i] = byteGen >> 56; byteGen *= PRIME64` where
157    ///   `PRIME64` is the C test file's constant 0x9E3779B185EBCA8D (not the
158    ///   hash PRIME64_1 constant).
159    pub(crate) fn fill_test_buffer(len: usize) -> alloc::vec::Vec<u8> {
160        const C_PRIME32: u64 = 0x9E3779B1;
161        const C_PRIME64: u64 = 0x9E3779B185EBCA8D;
162
163        let mut buf = alloc::vec::Vec::with_capacity(len);
164        let mut byte_gen = C_PRIME32;
165        for _ in 0..len {
166            buf.push((byte_gen >> 56) as u8);
167            byte_gen = byte_gen.wrapping_mul(C_PRIME64);
168        }
169        buf
170    }
171}