1 use core::hash::{Hash, Hasher};
2 use std::collections::HashMap;
3
assert_sufficiently_different(a: u64, b: u64, tolerance: i32)4 fn assert_sufficiently_different(a: u64, b: u64, tolerance: i32) {
5 let (same_byte_count, same_nibble_count) = count_same_bytes_and_nibbles(a, b);
6 assert!(same_byte_count <= tolerance, "{:x} vs {:x}: {:}", a, b, same_byte_count);
7 assert!(
8 same_nibble_count <= tolerance * 3,
9 "{:x} vs {:x}: {:}",
10 a,
11 b,
12 same_nibble_count
13 );
14 let flipped_bits = (a ^ b).count_ones();
15 assert!(
16 flipped_bits > 12 && flipped_bits < 52,
17 "{:x} and {:x}: {:}",
18 a,
19 b,
20 flipped_bits
21 );
22 for rotate in 0..64 {
23 let flipped_bits2 = (a ^ (b.rotate_left(rotate))).count_ones();
24 assert!(
25 flipped_bits2 > 10 && flipped_bits2 < 54,
26 "{:x} and {:x}: {:}",
27 a,
28 b.rotate_left(rotate),
29 flipped_bits2
30 );
31 }
32 }
33
count_same_bytes_and_nibbles(a: u64, b: u64) -> (i32, i32)34 fn count_same_bytes_and_nibbles(a: u64, b: u64) -> (i32, i32) {
35 let mut same_byte_count = 0;
36 let mut same_nibble_count = 0;
37 for byte in 0..8 {
38 let ba = (a >> (8 * byte)) as u8;
39 let bb = (b >> (8 * byte)) as u8;
40 if ba == bb {
41 same_byte_count += 1;
42 }
43 if ba & 0xF0u8 == bb & 0xF0u8 {
44 same_nibble_count += 1;
45 }
46 if ba & 0x0Fu8 == bb & 0x0Fu8 {
47 same_nibble_count += 1;
48 }
49 }
50 (same_byte_count, same_nibble_count)
51 }
52
gen_combinations(options: &[u32; 11], depth: u32, so_far: Vec<u32>, combinations: &mut Vec<Vec<u32>>)53 fn gen_combinations(options: &[u32; 11], depth: u32, so_far: Vec<u32>, combinations: &mut Vec<Vec<u32>>) {
54 if depth == 0 {
55 return;
56 }
57 for option in options {
58 let mut next = so_far.clone();
59 next.push(*option);
60 combinations.push(next.clone());
61 gen_combinations(options, depth - 1, next, combinations);
62 }
63 }
64
test_no_full_collisions<T: Hasher>(gen_hash: impl Fn() -> T)65 fn test_no_full_collisions<T: Hasher>(gen_hash: impl Fn() -> T) {
66 let options: [u32; 11] = [
67 0x00000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0xF0000000, 1, 2, 4, 8, 15,
68 ];
69 let mut combinations = Vec::new();
70 gen_combinations(&options, 7, Vec::new(), &mut combinations);
71 let mut map: HashMap<u64, Vec<u8>> = HashMap::new();
72 for combination in combinations {
73 use zerocopy::AsBytes;
74 let array = combination.as_slice().as_bytes().to_vec();
75 let mut hasher = gen_hash();
76 hasher.write(&array);
77 let hash = hasher.finish();
78 if let Some(value) = map.get(&hash) {
79 assert_eq!(
80 value, &array,
81 "Found a collision between {:x?} and {:x?}. Hash: {:x?}",
82 value, &array, &hash
83 );
84 } else {
85 map.insert(hash, array);
86 }
87 }
88 assert_eq!(21435887, map.len()); //11^7 + 11^6 ...
89 }
90
test_keys_change_output<T: Hasher>(constructor: impl Fn(u128, u128) -> T)91 fn test_keys_change_output<T: Hasher>(constructor: impl Fn(u128, u128) -> T) {
92 let mut a = constructor(1, 1);
93 let mut b = constructor(1, 2);
94 let mut c = constructor(2, 1);
95 let mut d = constructor(2, 2);
96 "test".hash(&mut a);
97 "test".hash(&mut b);
98 "test".hash(&mut c);
99 "test".hash(&mut d);
100 assert_sufficiently_different(a.finish(), b.finish(), 1);
101 assert_sufficiently_different(a.finish(), c.finish(), 1);
102 assert_sufficiently_different(a.finish(), d.finish(), 1);
103 assert_sufficiently_different(b.finish(), c.finish(), 1);
104 assert_sufficiently_different(b.finish(), d.finish(), 1);
105 assert_sufficiently_different(c.finish(), d.finish(), 1);
106 }
107
test_input_affect_every_byte<T: Hasher>(constructor: impl Fn(u128, u128) -> T)108 fn test_input_affect_every_byte<T: Hasher>(constructor: impl Fn(u128, u128) -> T) {
109 let base = hash_with(&0, constructor(0, 0));
110 for shift in 0..16 {
111 let mut alternatives = vec![];
112 for v in 0..256 {
113 let input = (v as u128) << (shift * 8);
114 let hasher = constructor(0, 0);
115 alternatives.push(hash_with(&input, hasher));
116 }
117 assert_each_byte_differs(shift, base, alternatives);
118 }
119 }
120
121 ///Ensures that for every bit in the output there is some value for each byte in the key that flips it.
test_keys_affect_every_byte<H: Hash, T: Hasher>(item: H, constructor: impl Fn(u128, u128) -> T)122 fn test_keys_affect_every_byte<H: Hash, T: Hasher>(item: H, constructor: impl Fn(u128, u128) -> T) {
123 let base = hash_with(&item, constructor(0, 0));
124 for shift in 0..16 {
125 let mut alternatives1 = vec![];
126 let mut alternatives2 = vec![];
127 for v in 0..256 {
128 let input = (v as u128) << (shift * 8);
129 let hasher1 = constructor(input, 0);
130 let hasher2 = constructor(0, input);
131 let h1 = hash_with(&item, hasher1);
132 let h2 = hash_with(&item, hasher2);
133 alternatives1.push(h1);
134 alternatives2.push(h2);
135 }
136 assert_each_byte_differs(shift, base, alternatives1);
137 assert_each_byte_differs(shift, base, alternatives2);
138 }
139 }
140
assert_each_byte_differs(num: u64, base: u64, alternatives: Vec<u64>)141 fn assert_each_byte_differs(num: u64, base: u64, alternatives: Vec<u64>) {
142 let mut changed_bits = 0_u64;
143 for alternative in alternatives {
144 changed_bits |= base ^ alternative
145 }
146 assert_eq!(
147 core::u64::MAX,
148 changed_bits,
149 "Bits changed: {:x} on num: {:?}. base {:x}",
150 changed_bits,
151 num,
152 base
153 );
154 }
155
test_finish_is_consistent<T: Hasher>(constructor: impl Fn(u128, u128) -> T)156 fn test_finish_is_consistent<T: Hasher>(constructor: impl Fn(u128, u128) -> T) {
157 let mut hasher = constructor(1, 2);
158 "Foo".hash(&mut hasher);
159 let a = hasher.finish();
160 let b = hasher.finish();
161 assert_eq!(a, b);
162 }
163
test_single_key_bit_flip<T: Hasher>(constructor: impl Fn(u128, u128) -> T)164 fn test_single_key_bit_flip<T: Hasher>(constructor: impl Fn(u128, u128) -> T) {
165 for bit in 0..128 {
166 let mut a = constructor(0, 0);
167 let mut b = constructor(0, 1 << bit);
168 let mut c = constructor(1 << bit, 0);
169 "1234".hash(&mut a);
170 "1234".hash(&mut b);
171 "1234".hash(&mut c);
172 assert_sufficiently_different(a.finish(), b.finish(), 2);
173 assert_sufficiently_different(a.finish(), c.finish(), 2);
174 assert_sufficiently_different(b.finish(), c.finish(), 2);
175 let mut a = constructor(0, 0);
176 let mut b = constructor(0, 1 << bit);
177 let mut c = constructor(1 << bit, 0);
178 "12345678".hash(&mut a);
179 "12345678".hash(&mut b);
180 "12345678".hash(&mut c);
181 assert_sufficiently_different(a.finish(), b.finish(), 2);
182 assert_sufficiently_different(a.finish(), c.finish(), 2);
183 assert_sufficiently_different(b.finish(), c.finish(), 2);
184 let mut a = constructor(0, 0);
185 let mut b = constructor(0, 1 << bit);
186 let mut c = constructor(1 << bit, 0);
187 "1234567812345678".hash(&mut a);
188 "1234567812345678".hash(&mut b);
189 "1234567812345678".hash(&mut c);
190 assert_sufficiently_different(a.finish(), b.finish(), 2);
191 assert_sufficiently_different(a.finish(), c.finish(), 2);
192 assert_sufficiently_different(b.finish(), c.finish(), 2);
193 }
194 }
195
test_all_bytes_matter<T: Hasher>(hasher: impl Fn() -> T)196 fn test_all_bytes_matter<T: Hasher>(hasher: impl Fn() -> T) {
197 let mut item = vec![0; 256];
198 let base_hash = hash(&item, &hasher);
199 for pos in 0..256 {
200 item[pos] = 255;
201 let hash = hash(&item, &hasher);
202 assert_ne!(base_hash, hash, "Position {} did not affect output", pos);
203 item[pos] = 0;
204 }
205 }
206
test_no_pair_collisions<T: Hasher>(hasher: impl Fn() -> T)207 fn test_no_pair_collisions<T: Hasher>(hasher: impl Fn() -> T) {
208 let base = [0_u64, 0_u64];
209 let base_hash = hash(&base, &hasher);
210 for bitpos1 in 0..64 {
211 let a = 1_u64 << bitpos1;
212 for bitpos2 in 0..bitpos1 {
213 let b = 1_u64 << bitpos2;
214 let aa = hash(&[a, a], &hasher);
215 let ab = hash(&[a, b], &hasher);
216 let ba = hash(&[b, a], &hasher);
217 let bb = hash(&[b, b], &hasher);
218 assert_sufficiently_different(base_hash, aa, 3);
219 assert_sufficiently_different(base_hash, ab, 3);
220 assert_sufficiently_different(base_hash, ba, 3);
221 assert_sufficiently_different(base_hash, bb, 3);
222 assert_sufficiently_different(aa, ab, 3);
223 assert_sufficiently_different(ab, ba, 3);
224 assert_sufficiently_different(ba, bb, 3);
225 assert_sufficiently_different(aa, ba, 3);
226 assert_sufficiently_different(ab, bb, 3);
227 assert_sufficiently_different(aa, bb, 3);
228 }
229 }
230 }
231
hash<H: Hash, T: Hasher>(b: &H, hash_builder: &dyn Fn() -> T) -> u64232 fn hash<H: Hash, T: Hasher>(b: &H, hash_builder: &dyn Fn() -> T) -> u64 {
233 let mut hasher = hash_builder();
234 b.hash(&mut hasher);
235 hasher.finish()
236 }
237
hash_with<H: Hash, T: Hasher>(b: &H, mut hasher: T) -> u64238 fn hash_with<H: Hash, T: Hasher>(b: &H, mut hasher: T) -> u64 {
239 b.hash(&mut hasher);
240 hasher.finish()
241 }
242
test_single_bit_flip<T: Hasher>(hasher: impl Fn() -> T)243 fn test_single_bit_flip<T: Hasher>(hasher: impl Fn() -> T) {
244 let size = 32;
245 let compare_value = hash(&0u32, &hasher);
246 for pos in 0..size {
247 let test_value = hash(&(1u32 << pos), &hasher);
248 assert_sufficiently_different(compare_value, test_value, 2);
249 }
250 let size = 64;
251 let compare_value = hash(&0u64, &hasher);
252 for pos in 0..size {
253 let test_value = hash(&(1u64 << pos), &hasher);
254 assert_sufficiently_different(compare_value, test_value, 2);
255 }
256 let size = 128;
257 let compare_value = hash(&0u128, &hasher);
258 for pos in 0..size {
259 let test_value = hash(&(1u128 << pos), &hasher);
260 dbg!(compare_value, test_value);
261 assert_sufficiently_different(compare_value, test_value, 2);
262 }
263 }
264
test_padding_doesnot_collide<T: Hasher>(hasher: impl Fn() -> T)265 fn test_padding_doesnot_collide<T: Hasher>(hasher: impl Fn() -> T) {
266 for c in 0..128u8 {
267 for string in ["", "\0", "\x01", "1234", "12345678", "1234567812345678"].iter() {
268 let mut short = hasher();
269 string.hash(&mut short);
270 let value = short.finish();
271 let mut padded = string.to_string();
272 for num in 1..=128 {
273 let mut long = hasher();
274 padded.push(c as char);
275 padded.hash(&mut long);
276 let (same_bytes, same_nibbles) = count_same_bytes_and_nibbles(value, long.finish());
277 assert!(
278 same_bytes <= 3,
279 "{} bytes of {} -> {:x} vs {:x}",
280 num,
281 c,
282 value,
283 long.finish()
284 );
285 assert!(
286 same_nibbles <= 8,
287 "{} bytes of {} -> {:x} vs {:x}",
288 num,
289 c,
290 value,
291 long.finish()
292 );
293 let flipped_bits = (value ^ long.finish()).count_ones();
294 assert!(flipped_bits > 10);
295 }
296 if string.len() > 0 {
297 let mut padded = string[1..].to_string();
298 padded.push(c as char);
299 for num in 2..=128 {
300 let mut long = hasher();
301 padded.push(c as char);
302 padded.hash(&mut long);
303 let (same_bytes, same_nibbles) = count_same_bytes_and_nibbles(value, long.finish());
304 assert!(
305 same_bytes <= 3,
306 "string {:?} + {} bytes of {} -> {:x} vs {:x}",
307 string,
308 num,
309 c,
310 value,
311 long.finish()
312 );
313 assert!(
314 same_nibbles <= 8,
315 "string {:?} + {} bytes of {} -> {:x} vs {:x}",
316 string,
317 num,
318 c,
319 value,
320 long.finish()
321 );
322 let flipped_bits = (value ^ long.finish()).count_ones();
323 assert!(flipped_bits > 10);
324 }
325 }
326 }
327 }
328 }
329
test_length_extension<T: Hasher>(hasher: impl Fn(u128, u128) -> T)330 fn test_length_extension<T: Hasher>(hasher: impl Fn(u128, u128) -> T) {
331 for key in 0..256 {
332 let h1 = hasher(key, key);
333 let v1 = hash_with(&[0_u8, 0, 0, 0, 0, 0, 0, 0], h1);
334 let h2 = hasher(key, key);
335 let v2 = hash_with(&[1_u8, 0, 0, 0, 0, 0, 0, 0, 0], h2);
336 assert_ne!(v1, v2);
337 }
338 }
339
test_sparse<T: Hasher>(hasher: impl Fn() -> T)340 fn test_sparse<T: Hasher>(hasher: impl Fn() -> T) {
341 use smallvec::SmallVec;
342
343 let mut buf = [0u8; 256];
344 let mut hashes = HashMap::new();
345 for idx_1 in 0..255_u8 {
346 for idx_2 in idx_1 + 1..=255_u8 {
347 for value_1 in [1, 2, 4, 8, 16, 32, 64, 128] {
348 for value_2 in [
349 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 16, 17, 18, 20, 24, 31, 32, 33, 48, 64, 96, 127, 128, 129,
350 192, 254, 255,
351 ] {
352 buf[idx_1 as usize] = value_1;
353 buf[idx_2 as usize] = value_2;
354 let hash_value = hash_with(&buf, &mut hasher());
355 let keys = hashes.entry(hash_value).or_insert(SmallVec::<[[u8; 4]; 1]>::new());
356 keys.push([idx_1, value_1, idx_2, value_2]);
357 buf[idx_1 as usize] = 0;
358 buf[idx_2 as usize] = 0;
359 }
360 }
361 }
362 }
363 hashes.retain(|_key, value| value.len() != 1);
364 assert_eq!(0, hashes.len(), "Collision with: {:?}", hashes);
365 }
366
367 #[cfg(test)]
368 mod fallback_tests {
369 use crate::fallback_hash::*;
370 use crate::hash_quality_test::*;
371
372 #[test]
fallback_single_bit_flip()373 fn fallback_single_bit_flip() {
374 test_single_bit_flip(|| AHasher::new_with_keys(0, 0))
375 }
376
377 #[test]
fallback_single_key_bit_flip()378 fn fallback_single_key_bit_flip() {
379 test_single_key_bit_flip(AHasher::new_with_keys)
380 }
381
382 #[test]
fallback_all_bytes_matter()383 fn fallback_all_bytes_matter() {
384 test_all_bytes_matter(|| AHasher::new_with_keys(0, 0));
385 }
386
387 #[test]
fallback_test_no_pair_collisions()388 fn fallback_test_no_pair_collisions() {
389 test_no_pair_collisions(|| AHasher::new_with_keys(0, 0));
390 }
391
392 #[test]
fallback_test_no_full_collisions()393 fn fallback_test_no_full_collisions() {
394 test_no_full_collisions(|| AHasher::new_with_keys(0, 0));
395 }
396
397 #[test]
fallback_keys_change_output()398 fn fallback_keys_change_output() {
399 test_keys_change_output(AHasher::new_with_keys);
400 }
401
402 #[test]
fallback_input_affect_every_byte()403 fn fallback_input_affect_every_byte() {
404 test_input_affect_every_byte(AHasher::new_with_keys);
405 }
406
407 #[test]
fallback_keys_affect_every_byte()408 fn fallback_keys_affect_every_byte() {
409 //For fallback second key is not used in every hash.
410 #[cfg(all(not(feature = "specialize"), feature = "folded_multiply"))]
411 test_keys_affect_every_byte(0, |a, b| AHasher::new_with_keys(a ^ b, a));
412 test_keys_affect_every_byte("", |a, b| AHasher::new_with_keys(a ^ b, a));
413 test_keys_affect_every_byte((0, 0), |a, b| AHasher::new_with_keys(a ^ b, a));
414 }
415
416 #[test]
fallback_finish_is_consistant()417 fn fallback_finish_is_consistant() {
418 test_finish_is_consistent(AHasher::test_with_keys)
419 }
420
421 #[test]
fallback_padding_doesnot_collide()422 fn fallback_padding_doesnot_collide() {
423 test_padding_doesnot_collide(|| AHasher::new_with_keys(0, 0));
424 test_padding_doesnot_collide(|| AHasher::new_with_keys(0, 2));
425 test_padding_doesnot_collide(|| AHasher::new_with_keys(2, 0));
426 test_padding_doesnot_collide(|| AHasher::new_with_keys(2, 2));
427 }
428
429 #[test]
fallback_length_extension()430 fn fallback_length_extension() {
431 test_length_extension(|a, b| AHasher::new_with_keys(a, b));
432 }
433
434 #[test]
test_no_sparse_collisions()435 fn test_no_sparse_collisions() {
436 test_sparse(|| AHasher::new_with_keys(0, 0));
437 test_sparse(|| AHasher::new_with_keys(1, 2));
438 }
439 }
440
441 ///Basic sanity tests of the cypto properties of aHash.
442 #[cfg(any(
443 all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
444 all(target_arch = "aarch64", target_feature = "aes", not(miri)),
445 all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)),
446 ))]
447 #[cfg(test)]
448 mod aes_tests {
449 use crate::aes_hash::*;
450 use crate::hash_quality_test::*;
451 use std::hash::{Hash, Hasher};
452
453 //This encrypts to 0.
454 const BAD_KEY2: u128 = 0x6363_6363_6363_6363_6363_6363_6363_6363;
455 //This decrypts to 0.
456 const BAD_KEY: u128 = 0x5252_5252_5252_5252_5252_5252_5252_5252;
457
458 #[test]
test_single_bit_in_byte()459 fn test_single_bit_in_byte() {
460 let mut hasher1 = AHasher::test_with_keys(0, 0);
461 8_u32.hash(&mut hasher1);
462 let mut hasher2 = AHasher::test_with_keys(0, 0);
463 0_u32.hash(&mut hasher2);
464 assert_sufficiently_different(hasher1.finish(), hasher2.finish(), 1);
465 }
466
467 #[test]
aes_single_bit_flip()468 fn aes_single_bit_flip() {
469 test_single_bit_flip(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY));
470 test_single_bit_flip(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2));
471 }
472
473 #[test]
aes_single_key_bit_flip()474 fn aes_single_key_bit_flip() {
475 test_single_key_bit_flip(AHasher::test_with_keys)
476 }
477
478 #[test]
aes_all_bytes_matter()479 fn aes_all_bytes_matter() {
480 test_all_bytes_matter(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY));
481 test_all_bytes_matter(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2));
482 }
483
484 #[test]
aes_test_no_pair_collisions()485 fn aes_test_no_pair_collisions() {
486 test_no_pair_collisions(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY));
487 test_no_pair_collisions(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2));
488 }
489
490 #[test]
ase_test_no_full_collisions()491 fn ase_test_no_full_collisions() {
492 test_no_full_collisions(|| AHasher::test_with_keys(12345, 67890));
493 }
494
495 #[test]
aes_keys_change_output()496 fn aes_keys_change_output() {
497 test_keys_change_output(AHasher::test_with_keys);
498 }
499
500 #[test]
aes_input_affect_every_byte()501 fn aes_input_affect_every_byte() {
502 test_input_affect_every_byte(AHasher::test_with_keys);
503 }
504
505 #[test]
aes_keys_affect_every_byte()506 fn aes_keys_affect_every_byte() {
507 #[cfg(not(feature = "specialize"))]
508 test_keys_affect_every_byte(0, AHasher::test_with_keys);
509 test_keys_affect_every_byte("", AHasher::test_with_keys);
510 test_keys_affect_every_byte((0, 0), AHasher::test_with_keys);
511 }
512
513 #[test]
aes_finish_is_consistant()514 fn aes_finish_is_consistant() {
515 test_finish_is_consistent(AHasher::test_with_keys)
516 }
517
518 #[test]
aes_padding_doesnot_collide()519 fn aes_padding_doesnot_collide() {
520 test_padding_doesnot_collide(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY));
521 test_padding_doesnot_collide(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2));
522 }
523
524 #[test]
aes_length_extension()525 fn aes_length_extension() {
526 test_length_extension(|a, b| AHasher::test_with_keys(a, b));
527 }
528
529 #[test]
aes_no_sparse_collisions()530 fn aes_no_sparse_collisions() {
531 test_sparse(|| AHasher::test_with_keys(0, 0));
532 test_sparse(|| AHasher::test_with_keys(1, 2));
533 }
534 }
535