]> git.proxmox.com Git - rustc.git/blame - src/libcore/hash/sip.rs
Imported Upstream version 1.9.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
JJ
10
11//! An implementation of SipHash 2-4.
12
e9174d1e
SL
13use prelude::v1::*;
14
c1a9b12d 15use ptr;
85aaf69f 16use super::Hasher;
1a4d82fc
JJ
17
18/// An implementation of SipHash 2-4.
19///
54a0048b 20/// See: https://131002.net/siphash/
1a4d82fc 21///
54a0048b
SL
22/// This is currently the default hashing function used by standard library
23/// (eg. `collections::HashMap` uses it by default).
1a4d82fc 24///
54a0048b
SL
25/// SipHash is a general-purpose hashing function: it runs at a good
26/// speed (competitive with Spooky and City) and permits strong _keyed_
27/// hashing. This lets you key your hashtables from a strong RNG, such as
28/// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
29///
30/// Although the SipHash algorithm is considered to be generally strong,
31/// it is not intended for cryptographic purposes. As such, all
32/// cryptographic uses of this implementation are _strongly discouraged_.
33#[derive(Debug)]
85aaf69f 34#[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc
JJ
35pub struct SipHasher {
36 k0: u64,
37 k1: u64,
c34b1796 38 length: usize, // how many bytes we've processed
c1a9b12d
SL
39 // v0, v2 and v1, v3 show up in pairs in the algorithm,
40 // and simd implementations of SipHash will use vectors
41 // of v02 and v13. By placing them in this order in the struct,
42 // the compiler can pick up on just a few simd optimizations by itself.
b039eaaf 43 v0: u64, // hash state
1a4d82fc 44 v2: u64,
c1a9b12d 45 v1: u64,
1a4d82fc
JJ
46 v3: u64,
47 tail: u64, // unprocessed bytes le
b039eaaf 48 ntail: usize, // how many bytes in tail are valid
1a4d82fc
JJ
49}
50
51// sadly, these macro definitions can't appear later,
52// because they're needed in the following defs;
53// this design could be improved.
54
55macro_rules! u8to64_le {
56 ($buf:expr, $i:expr) =>
57 ($buf[0+$i] as u64 |
58 ($buf[1+$i] as u64) << 8 |
59 ($buf[2+$i] as u64) << 16 |
60 ($buf[3+$i] as u64) << 24 |
61 ($buf[4+$i] as u64) << 32 |
62 ($buf[5+$i] as u64) << 40 |
63 ($buf[6+$i] as u64) << 48 |
64 ($buf[7+$i] as u64) << 56);
65 ($buf:expr, $i:expr, $len:expr) =>
66 ({
67 let mut t = 0;
c34b1796 68 let mut out = 0;
1a4d82fc
JJ
69 while t < $len {
70 out |= ($buf[t+$i] as u64) << t*8;
71 t += 1;
72 }
73 out
74 });
75}
76
c1a9b12d
SL
77/// Load a full u64 word from a byte stream, in LE order. Use
78/// `copy_nonoverlapping` to let the compiler generate the most efficient way
79/// to load u64 from a possibly unaligned address.
80///
81/// Unsafe because: unchecked indexing at i..i+8
82#[inline]
83unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
84 debug_assert!(i + 8 <= buf.len());
85 let mut data = 0u64;
b039eaaf 86 ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8);
c1a9b12d
SL
87 data.to_le()
88}
89
1a4d82fc
JJ
90macro_rules! rotl {
91 ($x:expr, $b:expr) =>
c34b1796 92 (($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
1a4d82fc
JJ
93}
94
95macro_rules! compress {
96 ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
97 ({
c34b1796 98 $v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
1a4d82fc 99 $v0 = rotl!($v0, 32);
c34b1796
AL
100 $v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
101 $v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
102 $v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
1a4d82fc
JJ
103 $v2 = rotl!($v2, 32);
104 })
105}
106
107impl SipHasher {
108 /// Creates a new `SipHasher` with the two initial keys set to 0.
109 #[inline]
85aaf69f 110 #[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc
JJ
111 pub fn new() -> SipHasher {
112 SipHasher::new_with_keys(0, 0)
113 }
114
115 /// Creates a `SipHasher` that is keyed off the provided keys.
116 #[inline]
85aaf69f 117 #[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc
JJ
118 pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
119 let mut state = SipHasher {
120 k0: key0,
121 k1: key1,
122 length: 0,
123 v0: 0,
124 v1: 0,
125 v2: 0,
126 v3: 0,
127 tail: 0,
128 ntail: 0,
129 };
130 state.reset();
131 state
132 }
133
d9579d0f 134 #[inline]
85aaf69f
SL
135 fn reset(&mut self) {
136 self.length = 0;
137 self.v0 = self.k0 ^ 0x736f6d6570736575;
138 self.v1 = self.k1 ^ 0x646f72616e646f6d;
139 self.v2 = self.k0 ^ 0x6c7967656e657261;
140 self.v3 = self.k1 ^ 0x7465646279746573;
141 self.ntail = 0;
142 }
e9174d1e 143}
85aaf69f 144
e9174d1e
SL
145#[stable(feature = "rust1", since = "1.0.0")]
146impl Hasher for SipHasher {
d9579d0f 147 #[inline]
1a4d82fc
JJ
148 fn write(&mut self, msg: &[u8]) {
149 let length = msg.len();
150 self.length += length;
151
85aaf69f 152 let mut needed = 0;
1a4d82fc
JJ
153
154 if self.ntail != 0 {
155 needed = 8 - self.ntail;
156 if length < needed {
b039eaaf 157 self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail;
1a4d82fc
JJ
158 self.ntail += length;
159 return
160 }
161
b039eaaf 162 let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail;
1a4d82fc
JJ
163
164 self.v3 ^= m;
165 compress!(self.v0, self.v1, self.v2, self.v3);
166 compress!(self.v0, self.v1, self.v2, self.v3);
167 self.v0 ^= m;
168
169 self.ntail = 0;
170 }
171
172 // Buffered tail is now flushed, process new input.
173 let len = length - needed;
1a4d82fc
JJ
174 let left = len & 0x7;
175
176 let mut i = needed;
c1a9b12d
SL
177 while i < len - left {
178 let mi = unsafe { load_u64_le(msg, i) };
1a4d82fc
JJ
179
180 self.v3 ^= mi;
181 compress!(self.v0, self.v1, self.v2, self.v3);
182 compress!(self.v0, self.v1, self.v2, self.v3);
183 self.v0 ^= mi;
184
185 i += 8;
186 }
187
188 self.tail = u8to64_le!(msg, i, left);
189 self.ntail = left;
190 }
1a4d82fc 191
d9579d0f 192 #[inline]
1a4d82fc
JJ
193 fn finish(&self) -> u64 {
194 let mut v0 = self.v0;
195 let mut v1 = self.v1;
196 let mut v2 = self.v2;
197 let mut v3 = self.v3;
198
199 let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
200
201 v3 ^= b;
202 compress!(v0, v1, v2, v3);
203 compress!(v0, v1, v2, v3);
204 v0 ^= b;
205
206 v2 ^= 0xff;
207 compress!(v0, v1, v2, v3);
208 compress!(v0, v1, v2, v3);
209 compress!(v0, v1, v2, v3);
210 compress!(v0, v1, v2, v3);
211
212 v0 ^ v1 ^ v2 ^ v3
213 }
214}
215
85aaf69f 216#[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc
JJ
217impl Clone for SipHasher {
218 #[inline]
219 fn clone(&self) -> SipHasher {
220 SipHasher {
221 k0: self.k0,
222 k1: self.k1,
223 length: self.length,
224 v0: self.v0,
225 v1: self.v1,
226 v2: self.v2,
227 v3: self.v3,
228 tail: self.tail,
229 ntail: self.ntail,
230 }
231 }
232}
233
85aaf69f 234#[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc
JJ
235impl Default for SipHasher {
236 fn default() -> SipHasher {
237 SipHasher::new()
238 }
239}