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