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