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