]> git.lizzy.rs Git - rust.git/blob - src/libcore/hash/sip.rs
Rollup merge of #34742 - abhijeetbhagat:master, r=steveklabnik
[rust.git] / src / libcore / hash / sip.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! An implementation of SipHash.
12
13 use prelude::v1::*;
14
15 use marker::PhantomData;
16 use ptr;
17
18 /// An implementation of SipHash 1-3.
19 ///
20 /// See: https://131002.net/siphash/
21 #[unstable(feature = "sip_hash_13", issue = "29754")]
22 #[derive(Debug, Clone, Default)]
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 = "sip_hash_13", issue = "29754")]
31 #[derive(Debug, Clone, Default)]
32 pub struct SipHasher24 {
33     hasher: Hasher<Sip24Rounds>,
34 }
35
36 /// An implementation of SipHash 2-4.
37 ///
38 /// See: https://131002.net/siphash/
39 ///
40 /// This is currently the default hashing function used by standard library
41 /// (eg. `collections::HashMap` uses it by default).
42 ///
43 /// SipHash is a general-purpose hashing function: it runs at a good
44 /// speed (competitive with Spooky and City) and permits strong _keyed_
45 /// hashing. This lets you key your hashtables from a strong RNG, such as
46 /// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
47 ///
48 /// Although the SipHash algorithm is considered to be generally strong,
49 /// it is not intended for cryptographic purposes. As such, all
50 /// cryptographic uses of this implementation are _strongly discouraged_.
51 #[stable(feature = "rust1", since = "1.0.0")]
52 #[derive(Debug, Clone, Default)]
53 pub struct SipHasher(SipHasher24);
54
55 #[derive(Debug)]
56 struct Hasher<S: Sip> {
57     k0: u64,
58     k1: u64,
59     length: usize, // how many bytes we've processed
60     state: State, // hash State
61     tail: u64, // unprocessed bytes le
62     ntail: usize, // how many bytes in tail are valid
63     _marker: PhantomData<S>,
64 }
65
66 #[derive(Debug, Clone, Copy)]
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 // sadly, these macro definitions can't appear later,
79 // because they're needed in the following defs;
80 // this design could be improved.
81
82 macro_rules! u8to64_le {
83     ($buf:expr, $i:expr) =>
84     ($buf[0+$i] as u64 |
85      ($buf[1+$i] as u64) << 8 |
86      ($buf[2+$i] as u64) << 16 |
87      ($buf[3+$i] as u64) << 24 |
88      ($buf[4+$i] as u64) << 32 |
89      ($buf[5+$i] as u64) << 40 |
90      ($buf[6+$i] as u64) << 48 |
91      ($buf[7+$i] as u64) << 56);
92     ($buf:expr, $i:expr, $len:expr) =>
93     ({
94         let mut t = 0;
95         let mut out = 0;
96         while t < $len {
97             out |= ($buf[t+$i] as u64) << t*8;
98             t += 1;
99         }
100         out
101     });
102 }
103
104 /// Load a full u64 word from a byte stream, in LE order. Use
105 /// `copy_nonoverlapping` to let the compiler generate the most efficient way
106 /// to load u64 from a possibly unaligned address.
107 ///
108 /// Unsafe because: unchecked indexing at i..i+8
109 #[inline]
110 unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
111     debug_assert!(i + 8 <= buf.len());
112     let mut data = 0u64;
113     ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8);
114     data.to_le()
115 }
116
117 macro_rules! rotl {
118     ($x:expr, $b:expr) =>
119     (($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
120 }
121
122 macro_rules! compress {
123     ($state:expr) => ({
124         compress!($state.v0, $state.v1, $state.v2, $state.v3)
125     });
126     ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
127     ({
128         $v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
129         $v0 = rotl!($v0, 32);
130         $v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
131         $v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
132         $v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
133         $v2 = rotl!($v2, 32);
134     });
135 }
136
137 impl SipHasher {
138     /// Creates a new `SipHasher` with the two initial keys set to 0.
139     #[inline]
140     #[stable(feature = "rust1", since = "1.0.0")]
141     pub fn new() -> SipHasher {
142         SipHasher::new_with_keys(0, 0)
143     }
144
145     /// Creates a `SipHasher` that is keyed off the provided keys.
146     #[inline]
147     #[stable(feature = "rust1", since = "1.0.0")]
148     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
149         SipHasher(SipHasher24::new_with_keys(key0, key1))
150     }
151 }
152
153
154 impl SipHasher13 {
155     /// Creates a new `SipHasher13` with the two initial keys set to 0.
156     #[inline]
157     #[unstable(feature = "sip_hash_13", issue = "29754")]
158     pub fn new() -> SipHasher13 {
159         SipHasher13::new_with_keys(0, 0)
160     }
161
162     /// Creates a `SipHasher13` that is keyed off the provided keys.
163     #[inline]
164     #[unstable(feature = "sip_hash_13", issue = "29754")]
165     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
166         SipHasher13 {
167             hasher: Hasher::new_with_keys(key0, key1)
168         }
169     }
170 }
171
172 impl SipHasher24 {
173     /// Creates a new `SipHasher24` with the two initial keys set to 0.
174     #[inline]
175     #[unstable(feature = "sip_hash_13", issue = "29754")]
176     pub fn new() -> SipHasher24 {
177         SipHasher24::new_with_keys(0, 0)
178     }
179
180     /// Creates a `SipHasher24` that is keyed off the provided keys.
181     #[inline]
182     #[unstable(feature = "sip_hash_13", issue = "29754")]
183     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 {
184         SipHasher24 {
185             hasher: Hasher::new_with_keys(key0, key1)
186         }
187     }
188 }
189
190 impl<S: Sip> Hasher<S> {
191     #[inline]
192     fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
193         let mut state = Hasher {
194             k0: key0,
195             k1: key1,
196             length: 0,
197             state: State {
198                 v0: 0,
199                 v1: 0,
200                 v2: 0,
201                 v3: 0,
202             },
203             tail: 0,
204             ntail: 0,
205             _marker: PhantomData,
206         };
207         state.reset();
208         state
209     }
210
211     #[inline]
212     fn reset(&mut self) {
213         self.length = 0;
214         self.state.v0 = self.k0 ^ 0x736f6d6570736575;
215         self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
216         self.state.v2 = self.k0 ^ 0x6c7967656e657261;
217         self.state.v3 = self.k1 ^ 0x7465646279746573;
218         self.ntail = 0;
219     }
220 }
221
222 #[stable(feature = "rust1", since = "1.0.0")]
223 impl super::Hasher for SipHasher {
224     #[inline]
225     fn write(&mut self, msg: &[u8]) {
226         self.0.write(msg)
227     }
228
229     #[inline]
230     fn finish(&self) -> u64 {
231         self.0.finish()
232     }
233 }
234
235 #[unstable(feature = "sip_hash_13", issue = "29754")]
236 impl super::Hasher for SipHasher13 {
237     #[inline]
238     fn write(&mut self, msg: &[u8]) {
239         self.hasher.write(msg)
240     }
241
242     #[inline]
243     fn finish(&self) -> u64 {
244         self.hasher.finish()
245     }
246 }
247
248 #[unstable(feature = "sip_hash_13", issue = "29754")]
249 impl super::Hasher for SipHasher24 {
250     #[inline]
251     fn write(&mut self, msg: &[u8]) {
252         self.hasher.write(msg)
253     }
254
255     #[inline]
256     fn finish(&self) -> u64 {
257         self.hasher.finish()
258     }
259 }
260
261 impl<S: Sip> super::Hasher for Hasher<S> {
262     #[inline]
263     fn write(&mut self, msg: &[u8]) {
264         let length = msg.len();
265         self.length += length;
266
267         let mut needed = 0;
268
269         if self.ntail != 0 {
270             needed = 8 - self.ntail;
271             if length < needed {
272                 self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail;
273                 self.ntail += length;
274                 return
275             }
276
277             let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail;
278
279             self.state.v3 ^= m;
280             S::c_rounds(&mut self.state);
281             self.state.v0 ^= m;
282
283             self.ntail = 0;
284         }
285
286         // Buffered tail is now flushed, process new input.
287         let len = length - needed;
288         let left = len & 0x7;
289
290         let mut i = needed;
291         while i < len - left {
292             let mi = unsafe { load_u64_le(msg, i) };
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         self.tail = u8to64_le!(msg, i, left);
302         self.ntail = left;
303     }
304
305     #[inline]
306     fn finish(&self) -> u64 {
307         let mut state = self.state;
308
309         let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
310
311         state.v3 ^= b;
312         S::c_rounds(&mut state);
313         state.v0 ^= b;
314
315         state.v2 ^= 0xff;
316         S::d_rounds(&mut state);
317
318         state.v0 ^ state.v1 ^ state.v2 ^ state.v3
319     }
320 }
321
322 impl<S: Sip> Clone for Hasher<S> {
323     #[inline]
324     fn clone(&self) -> Hasher<S> {
325         Hasher {
326             k0: self.k0,
327             k1: self.k1,
328             length: self.length,
329             state: self.state,
330             tail: self.tail,
331             ntail: self.ntail,
332             _marker: self._marker,
333         }
334     }
335 }
336
337 impl<S: Sip> Default for Hasher<S> {
338     #[inline]
339     fn default() -> Hasher<S> {
340         Hasher::new_with_keys(0, 0)
341     }
342 }
343
344 #[doc(hidden)]
345 trait Sip {
346     fn c_rounds(&mut State);
347     fn d_rounds(&mut State);
348 }
349
350 #[derive(Debug, Clone, Default)]
351 struct Sip13Rounds;
352
353 impl Sip for Sip13Rounds {
354     #[inline]
355     fn c_rounds(state: &mut State) {
356         compress!(state);
357     }
358
359     #[inline]
360     fn d_rounds(state: &mut State) {
361         compress!(state);
362         compress!(state);
363         compress!(state);
364     }
365 }
366
367 #[derive(Debug, Clone, Default)]
368 struct Sip24Rounds;
369
370 impl Sip for Sip24Rounds {
371     #[inline]
372     fn c_rounds(state: &mut State) {
373         compress!(state);
374         compress!(state);
375     }
376
377     #[inline]
378     fn d_rounds(state: &mut State) {
379         compress!(state);
380         compress!(state);
381         compress!(state);
382         compress!(state);
383     }
384 }