]> git.proxmox.com Git - rustc.git/blame - src/libcore/hash/sip.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / libcore / hash / sip.rs
CommitLineData
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 15use marker::PhantomData;
c1a9b12d 16use 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)]
24pub 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)]
34pub 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)]
56pub struct SipHasher(SipHasher24);
57
58#[derive(Debug)]
59struct 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)]
70struct 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
85macro_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]
113unsafe 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
120macro_rules! rotl {
121 ($x:expr, $b:expr) =>
c34b1796 122 (($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
1a4d82fc
JJ
123}
124
125macro_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
140impl 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
158impl 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
178impl 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
198impl<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
231impl 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
244impl 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
257impl 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
269impl<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 330impl<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 345impl<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)]
354trait Sip {
355 fn c_rounds(&mut State);
356 fn d_rounds(&mut State);
357}
358
359#[derive(Debug, Clone, Default)]
360struct Sip13Rounds;
361
362impl 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)]
377struct Sip24Rounds;
378
379impl 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}