]> git.lizzy.rs Git - rust.git/blob - src/libcore/hash/sip.rs
Auto merge of #22541 - Manishearth:rollup, r=Gankro
[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 // ignore-lexer-test FIXME #15883
12
13 //! An implementation of SipHash 2-4.
14
15 use prelude::*;
16 use default::Default;
17
18 use super::Hasher;
19 #[cfg(stage0)]
20 use super::Writer;
21
22 /// An implementation of SipHash 2-4.
23 ///
24 /// See: http://131002.net/siphash/
25 ///
26 /// Consider this as a main "general-purpose" hash for all hashtables: it
27 /// runs at good speed (competitive with spooky and city) and permits
28 /// strong _keyed_ hashing. Key your hashtables from a strong RNG,
29 /// such as `rand::Rng`.
30 ///
31 /// Although the SipHash algorithm is considered to be cryptographically
32 /// strong, this implementation has not been reviewed for such purposes.
33 /// As such, all cryptographic uses of this implementation are strongly
34 /// discouraged.
35 #[stable(feature = "rust1", since = "1.0.0")]
36 pub struct SipHasher {
37     k0: u64,
38     k1: u64,
39     length: uint, // how many bytes we've processed
40     v0: u64,      // hash state
41     v1: u64,
42     v2: u64,
43     v3: u64,
44     tail: u64, // unprocessed bytes le
45     ntail: uint,  // how many bytes in tail are valid
46 }
47
48 // sadly, these macro definitions can't appear later,
49 // because they're needed in the following defs;
50 // this design could be improved.
51
52 macro_rules! u8to64_le {
53     ($buf:expr, $i:expr) =>
54     ($buf[0+$i] as u64 |
55      ($buf[1+$i] as u64) << 8 |
56      ($buf[2+$i] as u64) << 16 |
57      ($buf[3+$i] as u64) << 24 |
58      ($buf[4+$i] as u64) << 32 |
59      ($buf[5+$i] as u64) << 40 |
60      ($buf[6+$i] as u64) << 48 |
61      ($buf[7+$i] as u64) << 56);
62     ($buf:expr, $i:expr, $len:expr) =>
63     ({
64         let mut t = 0;
65         let mut out = 0u64;
66         while t < $len {
67             out |= ($buf[t+$i] as u64) << t*8;
68             t += 1;
69         }
70         out
71     });
72 }
73
74 macro_rules! rotl {
75     ($x:expr, $b:expr) =>
76     (($x << $b) | ($x >> (64 - $b)))
77 }
78
79 macro_rules! compress {
80     ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
81     ({
82         $v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0;
83         $v0 = rotl!($v0, 32);
84         $v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2;
85         $v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0;
86         $v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2;
87         $v2 = rotl!($v2, 32);
88     })
89 }
90
91 impl SipHasher {
92     /// Creates a new `SipHasher` with the two initial keys set to 0.
93     #[inline]
94     #[stable(feature = "rust1", since = "1.0.0")]
95     pub fn new() -> SipHasher {
96         SipHasher::new_with_keys(0, 0)
97     }
98
99     /// Creates a `SipHasher` that is keyed off the provided keys.
100     #[inline]
101     #[stable(feature = "rust1", since = "1.0.0")]
102     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
103         let mut state = SipHasher {
104             k0: key0,
105             k1: key1,
106             length: 0,
107             v0: 0,
108             v1: 0,
109             v2: 0,
110             v3: 0,
111             tail: 0,
112             ntail: 0,
113         };
114         state.reset();
115         state
116     }
117
118     /// Returns the computed hash.
119     #[unstable(feature = "hash")]
120     #[deprecated(since = "1.0.0", reason = "renamed to finish")]
121     pub fn result(&self) -> u64 { self.finish() }
122
123     fn reset(&mut self) {
124         self.length = 0;
125         self.v0 = self.k0 ^ 0x736f6d6570736575;
126         self.v1 = self.k1 ^ 0x646f72616e646f6d;
127         self.v2 = self.k0 ^ 0x6c7967656e657261;
128         self.v3 = self.k1 ^ 0x7465646279746573;
129         self.ntail = 0;
130     }
131
132     fn write(&mut self, msg: &[u8]) {
133         let length = msg.len();
134         self.length += length;
135
136         let mut needed = 0;
137
138         if self.ntail != 0 {
139             needed = 8 - self.ntail;
140             if length < needed {
141                 self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail;
142                 self.ntail += length;
143                 return
144             }
145
146             let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail;
147
148             self.v3 ^= m;
149             compress!(self.v0, self.v1, self.v2, self.v3);
150             compress!(self.v0, self.v1, self.v2, self.v3);
151             self.v0 ^= m;
152
153             self.ntail = 0;
154         }
155
156         // Buffered tail is now flushed, process new input.
157         let len = length - needed;
158         let end = len & (!0x7);
159         let left = len & 0x7;
160
161         let mut i = needed;
162         while i < end {
163             let mi = u8to64_le!(msg, i);
164
165             self.v3 ^= mi;
166             compress!(self.v0, self.v1, self.v2, self.v3);
167             compress!(self.v0, self.v1, self.v2, self.v3);
168             self.v0 ^= mi;
169
170             i += 8;
171         }
172
173         self.tail = u8to64_le!(msg, i, left);
174         self.ntail = left;
175     }
176 }
177
178 #[cfg(stage0)]
179 impl Writer for SipHasher {
180     #[inline]
181     fn write(&mut self, msg: &[u8]) {
182         self.write(msg)
183     }
184 }
185
186 #[stable(feature = "rust1", since = "1.0.0")]
187 impl Hasher for SipHasher {
188     #[cfg(stage0)]
189     type Output = u64;
190
191     #[cfg(stage0)]
192     fn reset(&mut self) {
193         self.reset();
194     }
195
196     #[inline]
197     #[cfg(not(stage0))]
198     fn write(&mut self, msg: &[u8]) {
199         self.write(msg)
200     }
201
202     fn finish(&self) -> u64 {
203         let mut v0 = self.v0;
204         let mut v1 = self.v1;
205         let mut v2 = self.v2;
206         let mut v3 = self.v3;
207
208         let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
209
210         v3 ^= b;
211         compress!(v0, v1, v2, v3);
212         compress!(v0, v1, v2, v3);
213         v0 ^= b;
214
215         v2 ^= 0xff;
216         compress!(v0, v1, v2, v3);
217         compress!(v0, v1, v2, v3);
218         compress!(v0, v1, v2, v3);
219         compress!(v0, v1, v2, v3);
220
221         v0 ^ v1 ^ v2 ^ v3
222     }
223 }
224
225 #[stable(feature = "rust1", since = "1.0.0")]
226 impl Clone for SipHasher {
227     #[inline]
228     fn clone(&self) -> SipHasher {
229         SipHasher {
230             k0: self.k0,
231             k1: self.k1,
232             length: self.length,
233             v0: self.v0,
234             v1: self.v1,
235             v2: self.v2,
236             v3: self.v3,
237             tail: self.tail,
238             ntail: self.ntail,
239         }
240     }
241 }
242
243 #[stable(feature = "rust1", since = "1.0.0")]
244 impl Default for SipHasher {
245     fn default() -> SipHasher {
246         SipHasher::new()
247     }
248 }