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