]> git.proxmox.com Git - rustc.git/blob - vendor/siphasher/src/sip.rs
New upstream version 1.49.0+dfsg1
[rustc.git] / vendor / siphasher / src / 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.
12
13 use core::cmp;
14 use core::hash;
15 use core::marker::PhantomData;
16 use core::mem;
17 use core::ptr;
18
19 /// An implementation of SipHash 1-3.
20 ///
21 /// See: <https://131002.net/siphash/>
22 #[derive(Debug, Clone, Copy, Default)]
23 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24 pub struct SipHasher13 {
25 hasher: Hasher<Sip13Rounds>,
26 }
27
28 /// An implementation of SipHash 2-4.
29 ///
30 /// See: <https://131002.net/siphash/>
31 #[derive(Debug, Clone, Copy, Default)]
32 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33 pub struct SipHasher24 {
34 hasher: Hasher<Sip24Rounds>,
35 }
36
37 /// An implementation of SipHash 2-4.
38 ///
39 /// See: <https://131002.net/siphash/>
40 ///
41 /// SipHash is a general-purpose hashing function: it runs at a good
42 /// speed (competitive with Spooky and City) and permits strong _keyed_
43 /// hashing. This lets you key your hashtables from a strong RNG, such as
44 /// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
45 ///
46 /// Although the SipHash algorithm is considered to be generally strong,
47 /// it is not intended for cryptographic purposes. As such, all
48 /// cryptographic uses of this implementation are _strongly discouraged_.
49 #[derive(Debug, Clone, Copy, Default)]
50 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
51 pub struct SipHasher(SipHasher24);
52
53 #[derive(Debug, Clone, Copy)]
54 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
55 struct Hasher<S: Sip> {
56 k0: u64,
57 k1: u64,
58 length: usize, // how many bytes we've processed
59 state: State, // hash State
60 tail: u64, // unprocessed bytes le
61 ntail: usize, // how many bytes in tail are valid
62 _marker: PhantomData<S>,
63 }
64
65 #[derive(Debug, Clone, Copy)]
66 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67 struct State {
68 // v0, v2 and v1, v3 show up in pairs in the algorithm,
69 // and simd implementations of SipHash will use vectors
70 // of v02 and v13. By placing them in this order in the struct,
71 // the compiler can pick up on just a few simd optimizations by itself.
72 v0: u64,
73 v2: u64,
74 v1: u64,
75 v3: u64,
76 }
77
78 macro_rules! compress {
79 ($state:expr) => {{
80 compress!($state.v0, $state.v1, $state.v2, $state.v3)
81 }};
82 ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{
83 $v0 = $v0.wrapping_add($v1);
84 $v1 = $v1.rotate_left(13);
85 $v1 ^= $v0;
86 $v0 = $v0.rotate_left(32);
87 $v2 = $v2.wrapping_add($v3);
88 $v3 = $v3.rotate_left(16);
89 $v3 ^= $v2;
90 $v0 = $v0.wrapping_add($v3);
91 $v3 = $v3.rotate_left(21);
92 $v3 ^= $v0;
93 $v2 = $v2.wrapping_add($v1);
94 $v1 = $v1.rotate_left(17);
95 $v1 ^= $v2;
96 $v2 = $v2.rotate_left(32);
97 }};
98 }
99
100 /// Loads an integer of the desired type from a byte stream, in LE order. Uses
101 /// `copy_nonoverlapping` to let the compiler generate the most efficient way
102 /// to load it from a possibly unaligned address.
103 ///
104 /// Unsafe because: unchecked indexing at `i..i+size_of(int_ty)`
105 macro_rules! load_int_le {
106 ($buf:expr, $i:expr, $int_ty:ident) => {{
107 debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
108 let mut data = 0 as $int_ty;
109 ptr::copy_nonoverlapping(
110 $buf.get_unchecked($i),
111 &mut data as *mut _ as *mut u8,
112 mem::size_of::<$int_ty>(),
113 );
114 data.to_le()
115 }};
116 }
117
118 /// Loads a u64 using up to 7 bytes of a byte slice. It looks clumsy but the
119 /// `copy_nonoverlapping` calls that occur (via `load_int_le!`) all have fixed
120 /// sizes and avoid calling `memcpy`, which is good for speed.
121 ///
122 /// Unsafe because: unchecked indexing at start..start+len
123 #[inline]
124 unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
125 debug_assert!(len < 8);
126 let mut i = 0; // current byte index (from LSB) in the output u64
127 let mut out = 0;
128 if i + 3 < len {
129 out = load_int_le!(buf, start + i, u32) as u64;
130 i += 4;
131 }
132 if i + 1 < len {
133 out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8);
134 i += 2
135 }
136 if i < len {
137 out |= (*buf.get_unchecked(start + i) as u64) << (i * 8);
138 i += 1;
139 }
140 debug_assert_eq!(i, len);
141 out
142 }
143
144 impl SipHasher {
145 /// Creates a new `SipHasher` with the two initial keys set to 0.
146 #[inline]
147 pub fn new() -> SipHasher {
148 SipHasher::new_with_keys(0, 0)
149 }
150
151 /// Creates a `SipHasher` that is keyed off the provided keys.
152 #[inline]
153 pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
154 SipHasher(SipHasher24::new_with_keys(key0, key1))
155 }
156
157 /// Get the keys used by this hasher
158 pub fn keys(&self) -> (u64, u64) {
159 (self.0.hasher.k0, self.0.hasher.k1)
160 }
161 }
162
163 impl SipHasher13 {
164 /// Creates a new `SipHasher13` with the two initial keys set to 0.
165 #[inline]
166 pub fn new() -> SipHasher13 {
167 SipHasher13::new_with_keys(0, 0)
168 }
169
170 /// Creates a `SipHasher13` that is keyed off the provided keys.
171 #[inline]
172 pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
173 SipHasher13 {
174 hasher: Hasher::new_with_keys(key0, key1),
175 }
176 }
177
178 /// Get the keys used by this hasher
179 pub fn keys(&self) -> (u64, u64) {
180 (self.hasher.k0, self.hasher.k1)
181 }
182 }
183
184 impl SipHasher24 {
185 /// Creates a new `SipHasher24` with the two initial keys set to 0.
186 #[inline]
187 pub fn new() -> SipHasher24 {
188 SipHasher24::new_with_keys(0, 0)
189 }
190
191 /// Creates a `SipHasher24` that is keyed off the provided keys.
192 #[inline]
193 pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 {
194 SipHasher24 {
195 hasher: Hasher::new_with_keys(key0, key1),
196 }
197 }
198
199 /// Get the keys used by this hasher
200 pub fn keys(&self) -> (u64, u64) {
201 (self.hasher.k0, self.hasher.k1)
202 }
203 }
204
205 impl<S: Sip> Hasher<S> {
206 #[inline]
207 fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> {
208 let mut state = Hasher {
209 k0: key0,
210 k1: key1,
211 length: 0,
212 state: State {
213 v0: 0,
214 v1: 0,
215 v2: 0,
216 v3: 0,
217 },
218 tail: 0,
219 ntail: 0,
220 _marker: PhantomData,
221 };
222 state.reset();
223 state
224 }
225
226 #[inline]
227 fn reset(&mut self) {
228 self.length = 0;
229 self.state.v0 = self.k0 ^ 0x736f6d6570736575;
230 self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
231 self.state.v2 = self.k0 ^ 0x6c7967656e657261;
232 self.state.v3 = self.k1 ^ 0x7465646279746573;
233 self.ntail = 0;
234 }
235
236 // A specialized write function for values with size <= 8.
237 //
238 // The hashing of multi-byte integers depends on endianness. E.g.:
239 // - little-endian: `write_u32(0xDDCCBBAA)` == `write([0xAA, 0xBB, 0xCC, 0xDD])`
240 // - big-endian: `write_u32(0xDDCCBBAA)` == `write([0xDD, 0xCC, 0xBB, 0xAA])`
241 //
242 // This function does the right thing for little-endian hardware. On
243 // big-endian hardware `x` must be byte-swapped first to give the right
244 // behaviour. After any byte-swapping, the input must be zero-extended to
245 // 64-bits. The caller is responsible for the byte-swapping and
246 // zero-extension.
247 #[inline]
248 fn short_write<T>(&mut self, _x: T, x: u64) {
249 let size = mem::size_of::<T>();
250 self.length += size;
251
252 // The original number must be zero-extended, not sign-extended.
253 debug_assert!(if size < 8 { x >> (8 * size) == 0 } else { true });
254
255 // The number of bytes needed to fill `self.tail`.
256 let needed = 8 - self.ntail;
257
258 self.tail |= x << (8 * self.ntail);
259 if size < needed {
260 self.ntail += size;
261 return;
262 }
263
264 // `self.tail` is full, process it.
265 self.state.v3 ^= self.tail;
266 S::c_rounds(&mut self.state);
267 self.state.v0 ^= self.tail;
268
269 self.ntail = size - needed;
270 self.tail = if needed < 8 { x >> (8 * needed) } else { 0 };
271 }
272 }
273
274 impl hash::Hasher for SipHasher {
275 #[inline]
276 fn write(&mut self, msg: &[u8]) {
277 self.0.write(msg)
278 }
279
280 #[inline]
281 fn finish(&self) -> u64 {
282 self.0.finish()
283 }
284 }
285
286 impl hash::Hasher for SipHasher13 {
287 #[inline]
288 fn write(&mut self, msg: &[u8]) {
289 self.hasher.write(msg)
290 }
291
292 #[inline]
293 fn finish(&self) -> u64 {
294 self.hasher.finish()
295 }
296 }
297
298 impl hash::Hasher for SipHasher24 {
299 #[inline]
300 fn write(&mut self, msg: &[u8]) {
301 self.hasher.write(msg)
302 }
303
304 #[inline]
305 fn finish(&self) -> u64 {
306 self.hasher.finish()
307 }
308 }
309
310 impl<S: Sip> hash::Hasher for Hasher<S> {
311 #[inline]
312 fn write_usize(&mut self, i: usize) {
313 self.short_write(i, i.to_le() as u64);
314 }
315
316 #[inline]
317 fn write_u8(&mut self, i: u8) {
318 self.short_write(i, i as u64);
319 }
320
321 #[inline]
322 fn write_u32(&mut self, i: u32) {
323 self.short_write(i, i.to_le() as u64);
324 }
325
326 #[inline]
327 fn write_u64(&mut self, i: u64) {
328 self.short_write(i, i.to_le() as u64);
329 }
330
331 #[inline]
332 fn write(&mut self, msg: &[u8]) {
333 let length = msg.len();
334 self.length += length;
335
336 let mut needed = 0;
337
338 if self.ntail != 0 {
339 needed = 8 - self.ntail;
340 self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail);
341 if length < needed {
342 self.ntail += length;
343 return;
344 } else {
345 self.state.v3 ^= self.tail;
346 S::c_rounds(&mut self.state);
347 self.state.v0 ^= self.tail;
348 self.ntail = 0;
349 }
350 }
351
352 // Buffered tail is now flushed, process new input.
353 let len = length - needed;
354 let left = len & 0x7;
355
356 let mut i = needed;
357 while i < len - left {
358 let mi = unsafe { load_int_le!(msg, i, u64) };
359
360 self.state.v3 ^= mi;
361 S::c_rounds(&mut self.state);
362 self.state.v0 ^= mi;
363
364 i += 8;
365 }
366
367 self.tail = unsafe { u8to64_le(msg, i, left) };
368 self.ntail = left;
369 }
370
371 #[inline]
372 fn finish(&self) -> u64 {
373 let mut state = self.state;
374
375 let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
376
377 state.v3 ^= b;
378 S::c_rounds(&mut state);
379 state.v0 ^= b;
380
381 state.v2 ^= 0xff;
382 S::d_rounds(&mut state);
383
384 state.v0 ^ state.v1 ^ state.v2 ^ state.v3
385 }
386 }
387
388 impl<S: Sip> Default for Hasher<S> {
389 /// Creates a `Hasher<S>` with the two initial keys set to 0.
390 #[inline]
391 fn default() -> Hasher<S> {
392 Hasher::new_with_keys(0, 0)
393 }
394 }
395
396 #[doc(hidden)]
397 trait Sip {
398 fn c_rounds(_: &mut State);
399 fn d_rounds(_: &mut State);
400 }
401
402 #[derive(Debug, Clone, Copy, Default)]
403 struct Sip13Rounds;
404
405 impl Sip for Sip13Rounds {
406 #[inline]
407 fn c_rounds(state: &mut State) {
408 compress!(state);
409 }
410
411 #[inline]
412 fn d_rounds(state: &mut State) {
413 compress!(state);
414 compress!(state);
415 compress!(state);
416 }
417 }
418
419 #[derive(Debug, Clone, Copy, Default)]
420 struct Sip24Rounds;
421
422 impl Sip for Sip24Rounds {
423 #[inline]
424 fn c_rounds(state: &mut State) {
425 compress!(state);
426 compress!(state);
427 }
428
429 #[inline]
430 fn d_rounds(state: &mut State) {
431 compress!(state);
432 compress!(state);
433 compress!(state);
434 compress!(state);
435 }
436 }