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