]> git.lizzy.rs Git - rust.git/blob - src/libcore/hash/sip.rs
Rollup merge of #58595 - stjepang:make-duration-consts-associated, r=oli-obk
[rust.git] / src / libcore / hash / sip.rs
1 //! An implementation of SipHash.
2
3 #![allow(deprecated)] // the types in this module are deprecated
4
5 use marker::PhantomData;
6 use ptr;
7 use cmp;
8 use mem;
9
10 /// An implementation of SipHash 1-3.
11 ///
12 /// This is currently the default hashing function used by standard library
13 /// (e.g., `collections::HashMap` uses it by default).
14 ///
15 /// See: <https://131002.net/siphash>
16 #[unstable(feature = "hashmap_internals", issue = "0")]
17 #[rustc_deprecated(since = "1.13.0",
18                    reason = "use `std::collections::hash_map::DefaultHasher` instead")]
19 #[derive(Debug, Clone, Default)]
20 #[doc(hidden)]
21 pub struct SipHasher13 {
22     hasher: Hasher<Sip13Rounds>,
23 }
24
25 /// An implementation of SipHash 2-4.
26 ///
27 /// See: <https://131002.net/siphash/>
28 #[unstable(feature = "hashmap_internals", issue = "0")]
29 #[rustc_deprecated(since = "1.13.0",
30                    reason = "use `std::collections::hash_map::DefaultHasher` instead")]
31 #[derive(Debug, Clone, Default)]
32 struct SipHasher24 {
33     hasher: Hasher<Sip24Rounds>,
34 }
35
36 /// An implementation of SipHash 2-4.
37 ///
38 /// See: <https://131002.net/siphash/>
39 ///
40 /// SipHash is a general-purpose hashing function: it runs at a good
41 /// speed (competitive with Spooky and City) and permits strong _keyed_
42 /// hashing. This lets you key your hashtables from a strong RNG, such as
43 /// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
44 ///
45 /// Although the SipHash algorithm is considered to be generally strong,
46 /// it is not intended for cryptographic purposes. As such, all
47 /// cryptographic uses of this implementation are _strongly discouraged_.
48 #[stable(feature = "rust1", since = "1.0.0")]
49 #[rustc_deprecated(since = "1.13.0",
50                    reason = "use `std::collections::hash_map::DefaultHasher` instead")]
51 #[derive(Debug, Clone, Default)]
52 pub struct SipHasher(SipHasher24);
53
54 #[derive(Debug)]
55 struct Hasher<S: Sip> {
56     k0: u64,
57     k1: u64,
58     length: usize, // how many bytes we've processed
59     state: State, // hash State
60     tail: u64, // unprocessed bytes le
61     ntail: usize, // how many bytes in tail are valid
62     _marker: PhantomData<S>,
63 }
64
65 #[derive(Debug, Clone, Copy)]
66 #[repr(C)]
67 struct State {
68     // v0, v2 and v1, v3 show up in pairs in the algorithm,
69     // and simd implementations of SipHash will use vectors
70     // of v02 and v13. By placing them in this order in the struct,
71     // the compiler can pick up on just a few simd optimizations by itself.
72     v0: u64,
73     v2: u64,
74     v1: u64,
75     v3: u64,
76 }
77
78 macro_rules! compress {
79     ($state:expr) => ({
80         compress!($state.v0, $state.v1, $state.v2, $state.v3)
81     });
82     ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
83     ({
84         $v0 = $v0.wrapping_add($v1); $v1 = $v1.rotate_left(13); $v1 ^= $v0;
85         $v0 = $v0.rotate_left(32);
86         $v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2;
87         $v0 = $v0.wrapping_add($v3); $v3 = $v3.rotate_left(21); $v3 ^= $v0;
88         $v2 = $v2.wrapping_add($v1); $v1 = $v1.rotate_left(17); $v1 ^= $v2;
89         $v2 = $v2.rotate_left(32);
90     });
91 }
92
93 /// Loads an integer of the desired type from a byte stream, in LE order. Uses
94 /// `copy_nonoverlapping` to let the compiler generate the most efficient way
95 /// to load it from a possibly unaligned address.
96 ///
97 /// Unsafe because: unchecked indexing at i..i+size_of(int_ty)
98 macro_rules! load_int_le {
99     ($buf:expr, $i:expr, $int_ty:ident) =>
100     ({
101        debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
102        let mut data = 0 as $int_ty;
103        ptr::copy_nonoverlapping($buf.get_unchecked($i),
104                                 &mut data as *mut _ as *mut u8,
105                                 mem::size_of::<$int_ty>());
106        data.to_le()
107     });
108 }
109
110 /// Loads an u64 using up to 7 bytes of a byte slice.
111 ///
112 /// Unsafe because: unchecked indexing at start..start+len
113 #[inline]
114 unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
115     debug_assert!(len < 8);
116     let mut i = 0; // current byte index (from LSB) in the output u64
117     let mut out = 0;
118     if i + 3 < len {
119         out = load_int_le!(buf, start + i, u32) as u64;
120         i += 4;
121     }
122     if i + 1 < len {
123         out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8);
124         i += 2
125     }
126     if i < len {
127         out |= (*buf.get_unchecked(start + i) as u64) << (i * 8);
128         i += 1;
129     }
130     debug_assert_eq!(i, len);
131     out
132 }
133
134 impl SipHasher {
135     /// Creates a new `SipHasher` with the two initial keys set to 0.
136     #[inline]
137     #[stable(feature = "rust1", since = "1.0.0")]
138     #[rustc_deprecated(since = "1.13.0",
139                        reason = "use `std::collections::hash_map::DefaultHasher` instead")]
140     pub fn new() -> SipHasher {
141         SipHasher::new_with_keys(0, 0)
142     }
143
144     /// Creates a `SipHasher` that is keyed off the provided keys.
145     #[inline]
146     #[stable(feature = "rust1", since = "1.0.0")]
147     #[rustc_deprecated(since = "1.13.0",
148                        reason = "use `std::collections::hash_map::DefaultHasher` instead")]
149     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
150         SipHasher(SipHasher24 {
151             hasher: Hasher::new_with_keys(key0, key1)
152         })
153     }
154 }
155
156 impl SipHasher13 {
157     /// Creates a new `SipHasher13` with the two initial keys set to 0.
158     #[inline]
159     #[unstable(feature = "hashmap_internals", issue = "0")]
160     #[rustc_deprecated(since = "1.13.0",
161                        reason = "use `std::collections::hash_map::DefaultHasher` instead")]
162     pub fn new() -> SipHasher13 {
163         SipHasher13::new_with_keys(0, 0)
164     }
165
166     /// Creates a `SipHasher13` that is keyed off the provided keys.
167     #[inline]
168     #[unstable(feature = "hashmap_internals", issue = "0")]
169     #[rustc_deprecated(since = "1.13.0",
170                        reason = "use `std::collections::hash_map::DefaultHasher` instead")]
171     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
172         SipHasher13 {
173             hasher: Hasher::new_with_keys(key0, key1)
174         }
175     }
176 }
177
178 impl<S: Sip> Hasher<S> {
179     #[inline]
180     fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
181         let mut state = Hasher {
182             k0: key0,
183             k1: key1,
184             length: 0,
185             state: State {
186                 v0: 0,
187                 v1: 0,
188                 v2: 0,
189                 v3: 0,
190             },
191             tail: 0,
192             ntail: 0,
193             _marker: PhantomData,
194         };
195         state.reset();
196         state
197     }
198
199     #[inline]
200     fn reset(&mut self) {
201         self.length = 0;
202         self.state.v0 = self.k0 ^ 0x736f6d6570736575;
203         self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
204         self.state.v2 = self.k0 ^ 0x6c7967656e657261;
205         self.state.v3 = self.k1 ^ 0x7465646279746573;
206         self.ntail = 0;
207     }
208
209     // Specialized write function that is only valid for buffers with len <= 8.
210     // It's used to force inlining of write_u8 and write_usize, those would normally be inlined
211     // except for composite types (that includes slices and str hashing because of delimiter).
212     // Without this extra push the compiler is very reluctant to inline delimiter writes,
213     // degrading performance substantially for the most common use cases.
214     #[inline]
215     fn short_write(&mut self, msg: &[u8]) {
216         debug_assert!(msg.len() <= 8);
217         let length = msg.len();
218         self.length += length;
219
220         let needed = 8 - self.ntail;
221         let fill = cmp::min(length, needed);
222         if fill == 8 {
223             self.tail = unsafe { load_int_le!(msg, 0, u64) };
224         } else {
225             self.tail |= unsafe { u8to64_le(msg, 0, fill) } << (8 * self.ntail);
226             if length < needed {
227                 self.ntail += length;
228                 return;
229             }
230         }
231         self.state.v3 ^= self.tail;
232         S::c_rounds(&mut self.state);
233         self.state.v0 ^= self.tail;
234
235         // Buffered tail is now flushed, process new input.
236         self.ntail = length - needed;
237         self.tail = unsafe { u8to64_le(msg, needed, self.ntail) };
238     }
239 }
240
241 #[stable(feature = "rust1", since = "1.0.0")]
242 impl super::Hasher for SipHasher {
243     #[inline]
244     fn write(&mut self, msg: &[u8]) {
245         self.0.hasher.write(msg)
246     }
247
248     #[inline]
249     fn finish(&self) -> u64 {
250         self.0.hasher.finish()
251     }
252 }
253
254 #[unstable(feature = "hashmap_internals", issue = "0")]
255 impl super::Hasher for SipHasher13 {
256     #[inline]
257     fn write(&mut self, msg: &[u8]) {
258         self.hasher.write(msg)
259     }
260
261     #[inline]
262     fn finish(&self) -> u64 {
263         self.hasher.finish()
264     }
265 }
266
267 impl<S: Sip> super::Hasher for Hasher<S> {
268     // see short_write comment for explanation
269     #[inline]
270     fn write_usize(&mut self, i: usize) {
271         let bytes = unsafe {
272             ::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::<usize>())
273         };
274         self.short_write(bytes);
275     }
276
277     // see short_write comment for explanation
278     #[inline]
279     fn write_u8(&mut self, i: u8) {
280         self.short_write(&[i]);
281     }
282
283     #[inline]
284     fn write(&mut self, msg: &[u8]) {
285         let length = msg.len();
286         self.length += length;
287
288         let mut needed = 0;
289
290         if self.ntail != 0 {
291             needed = 8 - self.ntail;
292             self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail;
293             if length < needed {
294                 self.ntail += length;
295                 return
296             } else {
297                 self.state.v3 ^= self.tail;
298                 S::c_rounds(&mut self.state);
299                 self.state.v0 ^= self.tail;
300                 self.ntail = 0;
301             }
302         }
303
304         // Buffered tail is now flushed, process new input.
305         let len = length - needed;
306         let left = len & 0x7;
307
308         let mut i = needed;
309         while i < len - left {
310             let mi = unsafe { load_int_le!(msg, i, u64) };
311
312             self.state.v3 ^= mi;
313             S::c_rounds(&mut self.state);
314             self.state.v0 ^= mi;
315
316             i += 8;
317         }
318
319         self.tail = unsafe { u8to64_le(msg, i, left) };
320         self.ntail = left;
321     }
322
323     #[inline]
324     fn finish(&self) -> u64 {
325         let mut state = self.state;
326
327         let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
328
329         state.v3 ^= b;
330         S::c_rounds(&mut state);
331         state.v0 ^= b;
332
333         state.v2 ^= 0xff;
334         S::d_rounds(&mut state);
335
336         state.v0 ^ state.v1 ^ state.v2 ^ state.v3
337     }
338 }
339
340 impl<S: Sip> Clone for Hasher<S> {
341     #[inline]
342     fn clone(&self) -> Hasher<S> {
343         Hasher {
344             k0: self.k0,
345             k1: self.k1,
346             length: self.length,
347             state: self.state,
348             tail: self.tail,
349             ntail: self.ntail,
350             _marker: self._marker,
351         }
352     }
353 }
354
355 impl<S: Sip> Default for Hasher<S> {
356     /// Creates a `Hasher<S>` with the two initial keys set to 0.
357     #[inline]
358     fn default() -> Hasher<S> {
359         Hasher::new_with_keys(0, 0)
360     }
361 }
362
363 #[doc(hidden)]
364 trait Sip {
365     fn c_rounds(_: &mut State);
366     fn d_rounds(_: &mut State);
367 }
368
369 #[derive(Debug, Clone, Default)]
370 struct Sip13Rounds;
371
372 impl Sip for Sip13Rounds {
373     #[inline]
374     fn c_rounds(state: &mut State) {
375         compress!(state);
376     }
377
378     #[inline]
379     fn d_rounds(state: &mut State) {
380         compress!(state);
381         compress!(state);
382         compress!(state);
383     }
384 }
385
386 #[derive(Debug, Clone, Default)]
387 struct Sip24Rounds;
388
389 impl Sip for Sip24Rounds {
390     #[inline]
391     fn c_rounds(state: &mut State) {
392         compress!(state);
393         compress!(state);
394     }
395
396     #[inline]
397     fn d_rounds(state: &mut State) {
398         compress!(state);
399         compress!(state);
400         compress!(state);
401         compress!(state);
402     }
403 }