1mod rapid_const;
31mod rapid_hasher;
32mod state;
33pub(crate) mod seeding;
34mod mix_np;
35mod seed;
36mod read_np;
37
38#[doc(inline)]
39pub use rapid_hasher::*;
40#[doc(inline)]
41pub use state::*;
42#[doc(inline)]
43use seed::*;
44
45#[cfg(test)]
46mod tests {
47 extern crate std;
48
49 use std::hash::{BuildHasher, Hash, Hasher};
50 use std::collections::BTreeSet;
51 use rand::Rng;
52 use crate::inner::mix_np::rapid_mix_np;
53 use super::seed::{DEFAULT_RAPID_SECRETS, DEFAULT_SEED};
54 use super::rapid_const::{rapidhash_rs, rapidhash_rs_seeded};
55
56 type RapidHasher = super::RapidHasher<'static, true, true, true, false>;
57 type SeedableState = super::SeedableState<'static, true, true, true, false>;
58
59 #[derive(Hash)]
60 struct Object {
61 string: &'static str,
62 }
63
64 #[cfg(target_endian = "little")]
66 #[test]
67 fn derive_hash_works() {
68 #[cfg(not(feature = "nightly"))]
69 const EXPECTED: u64 = 7608958509739739138;
70
71 #[cfg(feature = "nightly")]
72 const EXPECTED: u64 = 8977256838778740407;
73
74 let object = Object { string: "hello world" };
75 let mut hasher = RapidHasher::default();
76 object.hash(&mut hasher);
77 assert_eq!(hasher.finish(), EXPECTED);
78
79 let mut hasher = RapidHasher::default();
80 hasher.write(object.string.as_bytes());
81 #[cfg(not(feature = "nightly"))] {
82 hasher.write_u8(0xFF);
83 }
84 assert_eq!(hasher.finish(), EXPECTED);
85 }
86
87 #[test]
91 fn all_sizes() {
92 let mut hashes = BTreeSet::new();
93
94 for size in 0..=1024 {
95 let mut data = std::vec![0; size];
96 rand::rng().fill(data.as_mut_slice());
97
98 let hash1 = rapidhash_rs(&data);
99 let mut hasher = RapidHasher::default();
100 hasher.write(&data);
101 let hash2 = hasher.finish();
102
103 assert_eq!(hash1, hash2, "Failed on size {}", size);
104 assert!(!hashes.contains(&hash1), "Duplicate for size {}", size);
105
106 hashes.insert(hash1);
107 }
108 }
109
110 #[test]
115 fn flip_bit_trial() {
116 use rand::Rng;
117
118 let mut flips = std::vec![];
119
120 for len in 1..=512 {
121 let mut data = std::vec![0; len];
122 rand::rng().fill(&mut data[..]);
123
124 let hash = rapidhash_rs(&data);
125 for byte in 0..len {
126 for bit in 0..8 {
127 let mut data = data.clone();
128 data[byte] ^= 1 << bit;
129 let new_hash = rapidhash_rs(&data);
130 assert_ne!(hash, new_hash, "Flipping byte {} bit {} did not change hash for input len {}", byte, bit, len);
131 let xor = hash ^ new_hash;
132 let flipped = xor.count_ones() as u64;
133 assert!(xor.count_ones() >= 8, "Flipping bit {byte}:{bit} changed only {flipped} bits");
134
135 flips.push(flipped);
136 }
137 }
138 }
139
140 let average = flips.iter().sum::<u64>() as f64 / flips.len() as f64;
141 assert!(average > 31.95 && average < 32.05, "Did not flip an average of half the bits. average: {average}, expected: 32.0");
142 }
143
144 fn streaming_hash(data: &[u8]) -> u64 {
146 let mut hasher = RapidHasher::default();
147 for byte in data {
148 hasher.write_u8(*byte);
149 }
150 hasher.finish()
151 }
152
153 #[test]
157 fn sponge_buffer_stability() {
158 use std::collections::HashSet;
159
160 fn manual_string_hash(data: &[u8]) -> u64 {
162 let mut hasher = crate::inner::SeedableState::<'static, false, true, false, false>::fixed().build_hasher();
164 for byte in data {
165 hasher.write_u8(*byte);
166 }
167 hasher.write_u8(0xFF); hasher.finish()
169 }
170
171 let mut hashes = HashSet::new();
172
173 for len in 1..=64 {
174 for byte in 0u8..=255 {
175 let data = std::vec![byte; len];
177
178 let hash1 = manual_string_hash(&data);
179 let hash2 = manual_string_hash(&data);
180 assert_eq!(hash1, hash2, "Mismatch for length {}", len);
181
182 assert!(!hashes.contains(&hash1), "Duplicate hash at length {}", len);
183 hashes.insert(hash1);
184 }
185 }
186 }
187
188 #[test]
195 fn flip_bit_trial_streaming() {
196 use rand::Rng;
197
198 let mut flips = std::vec![];
199
200 for len in 1..=300 {
201 let mut data = std::vec![0; len];
202 rand::rng().fill(&mut data[..]);
203
204 let hash = streaming_hash(&data);
205 for byte in 0..len {
206 for bit in 0..8 {
207 let mut data = data.clone();
208 data[byte] ^= 1 << bit;
209
210 let new_hash = streaming_hash(&data);
212 assert_ne!(hash, new_hash, "Flipping bit {byte}:{bit} for input len {len} did not change hash");
213
214 let xor = hash ^ new_hash;
216 let flipped = xor.count_ones() as u64;
217 assert!(xor.count_ones() >= 8, "Flipping bit {byte}:{bit} for input len {len} changed only {flipped} bits");
218 flips.push(flipped);
219 }
220 }
221 }
222
223 let average = flips.iter().sum::<u64>() as f64 / flips.len() as f64;
225 assert!(average > 31.95 && average < 32.05, "Did not flip an average of half the bits. average: {average}, expected: 32.0");
226 }
227
228 #[cfg(target_endian = "little")]
230 #[test]
231 fn compare_to_c() {
232 use rand::Rng;
233 use rapidhash_c::rapidhashcc_rs;
234
235 for len in 0..=512 {
236 let mut data = std::vec![0; len];
237 rand::rng().fill(&mut data[..]);
238
239 for byte in 0..len {
240 for bit in 0..8 {
241 let mut data = data.clone();
242 data[byte] ^= 1 << bit;
243
244 let rust_hash = rapidhash_rs_seeded(&data, &DEFAULT_RAPID_SECRETS);
245 let mut c_hash = rapidhashcc_rs(&data, DEFAULT_SEED);
246 c_hash = rapid_mix_np::<false>(c_hash, DEFAULT_RAPID_SECRETS.secrets[1]);
248 assert_eq!(rust_hash, c_hash, "Mismatch with input {} byte {} bit {}", len, byte, bit);
249
250 let mut rust_hasher = SeedableState::fixed().build_hasher();
251 rust_hasher.write(&data);
252 let rust_hasher_hash = rust_hasher.finish();
253 assert_eq!(rust_hash, rust_hasher_hash, "Hasher mismatch with input {} byte {} bit {}", len, byte, bit);
254 }
255 }
256 }
257 }
258
259 #[test]
260 fn disambiguation_check() {
261 use std::vec::Vec;
262
263 let hasher = SeedableState::default();
264
265 let a = [std::vec![1], std::vec![2, 3]];
266 let b = [std::vec![1, 2], std::vec![3]];
267 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
268
269 let a = [std::vec![], std::vec![1]];
270 let b = [std::vec![1], std::vec![]];
271 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
272
273 let a: [Vec<Vec<u64>>; 2] = [std::vec![], std::vec![std::vec![]]];
274 let b: [Vec<Vec<u64>>; 2] = [std::vec![std::vec![]], std::vec![]];
275 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
276
277 let a = ["abc", "def"];
278 let b = ["fed", "abc"];
279 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
280
281 let a = ["abc", "def"];
282 let b = ["abcd", "ef"];
283 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
284
285 let a = [1u8, 2];
286 let b = [2u8, 1];
287 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
288
289 let a = [1u16, 2];
290 let b = [2u16, 1];
291 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
292
293 let a = [1u32, 2];
294 let b = [2u32, 1];
295 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
296
297 let a = [1u64, 2];
298 let b = [2u64, 1];
299 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
300
301 let a = [1u128, 2];
302 let b = [2u128, 1];
303 assert_ne!(hasher.hash_one(a), hasher.hash_one(b));
304 }
305}