• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::convert::*;
2 #[cfg(feature = "specialize")]
3 use crate::fallback_hash::MULTIPLE;
4 use crate::operations::*;
5 use crate::RandomState;
6 use core::hash::Hasher;
7 use crate::random_state::PI;
8 
9 /// A `Hasher` for hashing an arbitrary stream of bytes.
10 ///
11 /// Instances of [`AHasher`] represent state that is updated while hashing data.
12 ///
13 /// Each method updates the internal state based on the new data provided. Once
14 /// all of the data has been provided, the resulting hash can be obtained by calling
15 /// `finish()`
16 ///
17 /// [Clone] is also provided in case you wish to calculate hashes for two different items that
18 /// start with the same data.
19 ///
20 #[derive(Debug, Clone)]
21 pub struct AHasher {
22     enc: u128,
23     sum: u128,
24     key: u128,
25 }
26 
27 impl AHasher {
28     /// Creates a new hasher keyed to the provided keys.
29     ///
30     /// Normally hashers are created via `AHasher::default()` for fixed keys or `RandomState::new()` for randomly
31     /// generated keys and `RandomState::with_seeds(a,b)` for seeds that are set and can be reused. All of these work at
32     /// map creation time (and hence don't have any overhead on a per-item bais).
33     ///
34     /// This method directly creates the hasher instance and performs no transformation on the provided seeds. This may
35     /// be useful where a HashBuilder is not desired, such as for testing purposes.
36     ///
37     /// # Example
38     ///
39     /// ```
40     /// use std::hash::Hasher;
41     /// use ahash::AHasher;
42     ///
43     /// let mut hasher = AHasher::new_with_keys(1234, 5678);
44     ///
45     /// hasher.write_u32(1989);
46     /// hasher.write_u8(11);
47     /// hasher.write_u8(9);
48     /// hasher.write(b"Huh?");
49     ///
50     /// println!("Hash is {:x}!", hasher.finish());
51     /// ```
52     #[inline]
new_with_keys(key1: u128, key2: u128) -> Self53     pub fn new_with_keys(key1: u128, key2: u128) -> Self {
54         let pi: [u128; 2] = PI.convert();
55         let key1 = key1 ^ pi[0];
56         let key2 = key2 ^ pi[1];
57         Self {
58             enc: key1,
59             sum: key2,
60             key: key1 ^ key2,
61         }
62     }
63 
64     #[allow(unused)] // False positive
test_with_keys(key1: u128, key2: u128) -> Self65     pub(crate) fn test_with_keys(key1: u128, key2: u128) -> Self {
66         Self {
67             enc: key1,
68             sum: key2,
69             key: key1 ^ key2,
70         }
71     }
72 
73 
74     #[inline]
from_random_state(rand_state: &RandomState) -> Self75     pub(crate) fn from_random_state(rand_state: &RandomState) -> Self {
76         let key1 = [rand_state.k0, rand_state.k1].convert();
77         let key2 = [rand_state.k2, rand_state.k3].convert();
78         Self {
79             enc: key1,
80             sum: key2,
81             key: key1 ^ key2,
82         }
83     }
84 
85     #[inline(always)]
add_in_length(&mut self, length: u64)86     fn add_in_length(&mut self, length: u64) {
87         //This will be scrambled by the next AES round.
88         let mut enc: [u64; 2] = self.enc.convert();
89         enc[0] = enc[0].wrapping_add(length);
90         self.enc = enc.convert();
91     }
92 
93     #[inline(always)]
hash_in(&mut self, new_value: u128)94     fn hash_in(&mut self, new_value: u128) {
95         self.enc = aesenc(self.enc, new_value);
96         self.sum = shuffle_and_add(self.sum, new_value);
97     }
98 
99     #[inline(always)]
hash_in_2(&mut self, v1: u128, v2: u128)100     fn hash_in_2(&mut self, v1: u128, v2: u128) {
101         self.enc = aesenc(self.enc, v1);
102         self.sum = shuffle_and_add(self.sum, v1);
103         self.enc = aesenc(self.enc, v2);
104         self.sum = shuffle_and_add(self.sum, v2);
105     }
106 
107     #[inline]
108     #[cfg(feature = "specialize")]
short_finish(&self) -> u64109     fn short_finish(&self) -> u64 {
110         let combined = aesdec(self.sum, self.enc);
111         let result: [u64; 2] = aesenc(combined, combined).convert();
112         result[0]
113     }
114 }
115 
116 /// Provides [Hasher] methods to hash all of the primitive types.
117 ///
118 /// [Hasher]: core::hash::Hasher
119 impl Hasher for AHasher {
120     #[inline]
write_u8(&mut self, i: u8)121     fn write_u8(&mut self, i: u8) {
122         self.write_u64(i as u64);
123     }
124 
125     #[inline]
write_u16(&mut self, i: u16)126     fn write_u16(&mut self, i: u16) {
127         self.write_u64(i as u64);
128     }
129 
130     #[inline]
write_u32(&mut self, i: u32)131     fn write_u32(&mut self, i: u32) {
132         self.write_u64(i as u64);
133     }
134 
135     #[inline]
write_u128(&mut self, i: u128)136     fn write_u128(&mut self, i: u128) {
137         self.hash_in(i);
138     }
139 
140     #[inline]
141     #[cfg(any(target_pointer_width = "64", target_pointer_width = "32", target_pointer_width = "16"))]
write_usize(&mut self, i: usize)142     fn write_usize(&mut self, i: usize) {
143         self.write_u64(i as u64);
144     }
145 
146     #[inline]
147     #[cfg(target_pointer_width = "128")]
write_usize(&mut self, i: usize)148     fn write_usize(&mut self, i: usize) {
149         self.write_u128(i as u128);
150     }
151 
152     #[inline]
write_u64(&mut self, i: u64)153     fn write_u64(&mut self, i: u64) {
154         self.write_u128(i as u128);
155     }
156 
157     #[inline]
158     #[allow(clippy::collapsible_if)]
write(&mut self, input: &[u8])159     fn write(&mut self, input: &[u8]) {
160         let mut data = input;
161         let length = data.len();
162         self.add_in_length(length as u64);
163         //A 'binary search' on sizes reduces the number of comparisons.
164         if data.len() <= 8 {
165             let value = read_small(data);
166             self.hash_in(value.convert());
167         } else {
168             if data.len() > 32 {
169                 if data.len() > 64 {
170                     let tail = data.read_last_u128x4();
171                     let mut current: [u128; 4] = [self.key; 4];
172                     current[0] = aesenc(current[0], tail[0]);
173                     current[1] = aesenc(current[1], tail[1]);
174                     current[2] = aesenc(current[2], tail[2]);
175                     current[3] = aesenc(current[3], tail[3]);
176                     let mut sum: [u128; 2] = [self.key, self.key];
177                     sum[0] = add_by_64s(sum[0].convert(), tail[0].convert()).convert();
178                     sum[1] = add_by_64s(sum[1].convert(), tail[1].convert()).convert();
179                     sum[0] = shuffle_and_add(sum[0], tail[2]);
180                     sum[1] = shuffle_and_add(sum[1], tail[3]);
181                     while data.len() > 64 {
182                         let (blocks, rest) = data.read_u128x4();
183                         current[0] = aesenc(current[0], blocks[0]);
184                         current[1] = aesenc(current[1], blocks[1]);
185                         current[2] = aesenc(current[2], blocks[2]);
186                         current[3] = aesenc(current[3], blocks[3]);
187                         sum[0] = shuffle_and_add(sum[0], blocks[0]);
188                         sum[1] = shuffle_and_add(sum[1], blocks[1]);
189                         sum[0] = shuffle_and_add(sum[0], blocks[2]);
190                         sum[1] = shuffle_and_add(sum[1], blocks[3]);
191                         data = rest;
192                     }
193                     self.hash_in_2(aesenc(current[0], current[1]), aesenc(current[2], current[3]));
194                     self.hash_in(add_by_64s(sum[0].convert(), sum[1].convert()).convert());
195                 } else {
196                     //len 33-64
197                     let (head, _) = data.read_u128x2();
198                     let tail = data.read_last_u128x2();
199                     self.hash_in_2(head[0], head[1]);
200                     self.hash_in_2(tail[0], tail[1]);
201                 }
202             } else {
203                 if data.len() > 16 {
204                     //len 17-32
205                     self.hash_in_2(data.read_u128().0, data.read_last_u128());
206                 } else {
207                     //len 9-16
208                     let value: [u64; 2] = [data.read_u64().0, data.read_last_u64()];
209                     self.hash_in(value.convert());
210                 }
211             }
212         }
213     }
214     #[inline]
finish(&self) -> u64215     fn finish(&self) -> u64 {
216         let combined = aesdec(self.sum, self.enc);
217         let result: [u64; 2] = aesenc(aesenc(combined, self.key), combined).convert();
218         result[0]
219     }
220 }
221 
222 #[cfg(feature = "specialize")]
223 pub(crate) struct AHasherU64 {
224     pub(crate) buffer: u64,
225     pub(crate) pad: u64,
226 }
227 
228 /// A specialized hasher for only primitives under 64 bits.
229 #[cfg(feature = "specialize")]
230 impl Hasher for AHasherU64 {
231     #[inline]
finish(&self) -> u64232     fn finish(&self) -> u64 {
233         let rot = (self.pad & 63) as u32;
234         self.buffer.rotate_left(rot)
235     }
236 
237     #[inline]
write(&mut self, _bytes: &[u8])238     fn write(&mut self, _bytes: &[u8]) {
239         unreachable!("Specialized hasher was called with a different type of object")
240     }
241 
242     #[inline]
write_u8(&mut self, i: u8)243     fn write_u8(&mut self, i: u8) {
244         self.write_u64(i as u64);
245     }
246 
247     #[inline]
write_u16(&mut self, i: u16)248     fn write_u16(&mut self, i: u16) {
249         self.write_u64(i as u64);
250     }
251 
252     #[inline]
write_u32(&mut self, i: u32)253     fn write_u32(&mut self, i: u32) {
254         self.write_u64(i as u64);
255     }
256 
257     #[inline]
write_u64(&mut self, i: u64)258     fn write_u64(&mut self, i: u64) {
259         self.buffer = folded_multiply(i ^ self.buffer, MULTIPLE);
260     }
261 
262     #[inline]
write_u128(&mut self, _i: u128)263     fn write_u128(&mut self, _i: u128) {
264         unreachable!("Specialized hasher was called with a different type of object")
265     }
266 
267     #[inline]
write_usize(&mut self, _i: usize)268     fn write_usize(&mut self, _i: usize) {
269         unreachable!("Specialized hasher was called with a different type of object")
270     }
271 }
272 
273 #[cfg(feature = "specialize")]
274 pub(crate) struct AHasherFixed(pub AHasher);
275 
276 /// A specialized hasher for fixed size primitives larger than 64 bits.
277 #[cfg(feature = "specialize")]
278 impl Hasher for AHasherFixed {
279     #[inline]
finish(&self) -> u64280     fn finish(&self) -> u64 {
281         self.0.short_finish()
282     }
283 
284     #[inline]
write(&mut self, bytes: &[u8])285     fn write(&mut self, bytes: &[u8]) {
286         self.0.write(bytes)
287     }
288 
289     #[inline]
write_u8(&mut self, i: u8)290     fn write_u8(&mut self, i: u8) {
291         self.write_u64(i as u64);
292     }
293 
294     #[inline]
write_u16(&mut self, i: u16)295     fn write_u16(&mut self, i: u16) {
296         self.write_u64(i as u64);
297     }
298 
299     #[inline]
write_u32(&mut self, i: u32)300     fn write_u32(&mut self, i: u32) {
301         self.write_u64(i as u64);
302     }
303 
304     #[inline]
write_u64(&mut self, i: u64)305     fn write_u64(&mut self, i: u64) {
306         self.0.write_u64(i);
307     }
308 
309     #[inline]
write_u128(&mut self, i: u128)310     fn write_u128(&mut self, i: u128) {
311         self.0.write_u128(i);
312     }
313 
314     #[inline]
write_usize(&mut self, i: usize)315     fn write_usize(&mut self, i: usize) {
316         self.0.write_usize(i);
317     }
318 }
319 
320 #[cfg(feature = "specialize")]
321 pub(crate) struct AHasherStr(pub AHasher);
322 
323 /// A specialized hasher for strings
324 /// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec)
325 #[cfg(feature = "specialize")]
326 impl Hasher for AHasherStr {
327     #[inline]
finish(&self) -> u64328     fn finish(&self) -> u64 {
329         let result : [u64; 2] = self.0.enc.convert();
330         result[0]
331     }
332 
333     #[inline]
write(&mut self, bytes: &[u8])334     fn write(&mut self, bytes: &[u8]) {
335         if bytes.len() > 8 {
336             self.0.write(bytes);
337             self.0.enc = aesdec(self.0.sum, self.0.enc);
338             self.0.enc = aesenc(aesenc(self.0.enc, self.0.key), self.0.enc);
339         } else {
340             self.0.add_in_length(bytes.len() as u64);
341             let value = read_small(bytes).convert();
342             self.0.sum = shuffle_and_add(self.0.sum, value);
343             self.0.enc = aesdec(self.0.sum, self.0.enc);
344             self.0.enc = aesenc(aesenc(self.0.enc, self.0.key), self.0.enc);
345         }
346     }
347 
348     #[inline]
write_u8(&mut self, _i: u8)349     fn write_u8(&mut self, _i: u8) {}
350 
351     #[inline]
write_u16(&mut self, _i: u16)352     fn write_u16(&mut self, _i: u16) {}
353 
354     #[inline]
write_u32(&mut self, _i: u32)355     fn write_u32(&mut self, _i: u32) {}
356 
357     #[inline]
write_u64(&mut self, _i: u64)358     fn write_u64(&mut self, _i: u64) {}
359 
360     #[inline]
write_u128(&mut self, _i: u128)361     fn write_u128(&mut self, _i: u128) {}
362 
363     #[inline]
write_usize(&mut self, _i: usize)364     fn write_usize(&mut self, _i: usize) {}
365 }
366 
367 #[cfg(test)]
368 mod tests {
369     use super::*;
370     use crate::convert::Convert;
371     use crate::operations::aesenc;
372     use crate::RandomState;
373     use std::hash::{BuildHasher, Hasher};
374     #[test]
test_sanity()375     fn test_sanity() {
376         let mut hasher = RandomState::with_seeds(1, 2, 3, 4).build_hasher();
377         hasher.write_u64(0);
378         let h1 = hasher.finish();
379         hasher.write(&[1, 0, 0, 0, 0, 0, 0, 0]);
380         let h2 = hasher.finish();
381         assert_ne!(h1, h2);
382     }
383 
384     #[cfg(feature = "compile-time-rng")]
385     #[test]
test_builder()386     fn test_builder() {
387         use std::collections::HashMap;
388         use std::hash::BuildHasherDefault;
389 
390         let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
391         map.insert(1, 3);
392     }
393 
394     #[cfg(feature = "compile-time-rng")]
395     #[test]
test_default()396     fn test_default() {
397         let hasher_a = AHasher::default();
398         let a_enc: [u64; 2] = hasher_a.enc.convert();
399         let a_sum: [u64; 2] = hasher_a.sum.convert();
400         assert_ne!(0, a_enc[0]);
401         assert_ne!(0, a_enc[1]);
402         assert_ne!(0, a_sum[0]);
403         assert_ne!(0, a_sum[1]);
404         assert_ne!(a_enc[0], a_enc[1]);
405         assert_ne!(a_sum[0], a_sum[1]);
406         assert_ne!(a_enc[0], a_sum[0]);
407         assert_ne!(a_enc[1], a_sum[1]);
408         let hasher_b = AHasher::default();
409         let b_enc: [u64; 2] = hasher_b.enc.convert();
410         let b_sum: [u64; 2] = hasher_b.sum.convert();
411         assert_eq!(a_enc[0], b_enc[0]);
412         assert_eq!(a_enc[1], b_enc[1]);
413         assert_eq!(a_sum[0], b_sum[0]);
414         assert_eq!(a_sum[1], b_sum[1]);
415     }
416 
417     #[test]
test_hash()418     fn test_hash() {
419         let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
420         let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
421         result = aesenc(value.convert(), result.convert()).convert();
422         result = aesenc(result.convert(), result.convert()).convert();
423         let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
424         let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
425         result2 = aesenc(value2.convert(), result2.convert()).convert();
426         result2 = aesenc(result2.convert(), result.convert()).convert();
427         let result: [u8; 16] = result.convert();
428         let result2: [u8; 16] = result2.convert();
429         assert_ne!(hex::encode(result), hex::encode(result2));
430     }
431 
432     #[test]
test_conversion()433     fn test_conversion() {
434         let input: &[u8] = "dddddddd".as_bytes();
435         let bytes: u64 = as_array!(input, 8).convert();
436         assert_eq!(bytes, 0x6464646464646464);
437     }
438 }
439 
440