Skip to content

Commit 04f2073

Browse files
dgryskigraydon
authored andcommitted
core::hash -- add a hash::streaming interface and associated siphash implementation.
1 parent 082d831 commit 04f2073

File tree

1 file changed

+194
-11
lines changed

1 file changed

+194
-11
lines changed

src/libcore/hash.rs

+194-11
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pure fn hash_bytes_keyed(buf: &[const u8], k0: u64, k1: u64) -> u64 {
3232

3333
#macro([#rotl(x,b), (x << b) | (x >> (64 - b))]);
3434

35-
#macro([#compress(), {
35+
#macro([#compress(v0,v1,v2,v3), {
3636
v0 += v1; v1 = #rotl(v1, 13); v1 ^= v0; v0 = #rotl(v0, 32);
3737
v2 += v3; v3 = #rotl(v3, 16); v3 ^= v2;
3838
v0 += v3; v3 = #rotl(v3, 21); v3 ^= v0;
@@ -47,8 +47,8 @@ pure fn hash_bytes_keyed(buf: &[const u8], k0: u64, k1: u64) -> u64 {
4747
while i < end {
4848
let m = #u8to64_le(buf, i);
4949
v3 ^= m;
50-
#compress();
51-
#compress();
50+
#compress(v0,v1,v2,v3);
51+
#compress(v0,v1,v2,v3);
5252
v0 ^= m;
5353
i += 8;
5454
}
@@ -64,19 +64,182 @@ pure fn hash_bytes_keyed(buf: &[const u8], k0: u64, k1: u64) -> u64 {
6464
if left > 6 { b |= buf[i + 6] as u64 << 48; }
6565

6666
v3 ^= b;
67-
#compress();
68-
#compress();
67+
#compress(v0,v1,v2,v3);
68+
#compress(v0,v1,v2,v3);
6969
v0 ^= b;
7070

7171
v2 ^= 0xff;
72-
#compress();
73-
#compress();
74-
#compress();
75-
#compress();
72+
73+
#compress(v0,v1,v2,v3);
74+
#compress(v0,v1,v2,v3);
75+
#compress(v0,v1,v2,v3);
76+
#compress(v0,v1,v2,v3);
7677

7778
ret v0 ^ v1 ^ v2 ^ v3;
7879
}
7980

81+
82+
iface streaming {
83+
fn input(~[u8]);
84+
fn input_str(~str);
85+
fn result() -> ~[u8];
86+
fn result_str() -> ~str;
87+
fn reset();
88+
}
89+
90+
fn siphash(key0 : u64, key1 : u64) -> streaming {
91+
type sipstate = {
92+
k0 : u64,
93+
k1 : u64,
94+
mut length : uint, // how many bytes we've processed
95+
mut v0 : u64, // hash state
96+
mut v1 : u64,
97+
mut v2 : u64,
98+
mut v3 : u64,
99+
tail : ~[mut u8]/8, // unprocessed bytes
100+
mut ntail : uint, // how many bytes in tail are valid
101+
};
102+
103+
fn add_input(st : sipstate, msg : ~[u8]) {
104+
let length = vec::len(msg);
105+
st.length += length;
106+
107+
let mut needed = 0u;
108+
109+
if st.ntail != 0 {
110+
needed = 8 - st.ntail;
111+
112+
if length < needed {
113+
114+
let mut t = 0;
115+
while t < length {
116+
st.tail[st.ntail+t] = msg[t];
117+
t += 1;
118+
}
119+
st.ntail += length;
120+
121+
ret;
122+
}
123+
124+
let mut t = 0;
125+
while t < needed {
126+
st.tail[st.ntail+t] = msg[t];
127+
t += 1;
128+
}
129+
130+
let m = #u8to64_le(st.tail, 0);
131+
132+
st.v3 ^= m;
133+
#compress(st.v0, st.v1, st.v2, st.v3);
134+
#compress(st.v0, st.v1, st.v2, st.v3);
135+
st.v0 ^= m;
136+
137+
st.ntail = 0;
138+
}
139+
140+
let len = length - needed;
141+
let end = len & (!0x7);
142+
let left = len & 0x7;
143+
144+
let mut i = needed;
145+
while i < end {
146+
let mi = #u8to64_le(msg, i);
147+
148+
st.v3 ^= mi;
149+
#compress(st.v0, st.v1, st.v2, st.v3);
150+
#compress(st.v0, st.v1, st.v2, st.v3);
151+
st.v0 ^= mi;
152+
153+
i += 8;
154+
}
155+
156+
let mut t = 0u;
157+
while t < left {
158+
st.tail[t] = msg[i+t];
159+
t += 1
160+
}
161+
st.ntail = left;
162+
}
163+
164+
fn mk_result(st : sipstate) -> ~[u8] {
165+
166+
let mut v0 = st.v0;
167+
let mut v1 = st.v1;
168+
let mut v2 = st.v2;
169+
let mut v3 = st.v3;
170+
171+
let mut b : u64 = (st.length as u64 & 0xff) << 56;
172+
173+
if st.ntail > 0 { b |= st.tail[0] as u64 << 0; }
174+
if st.ntail > 1 { b |= st.tail[1] as u64 << 8; }
175+
if st.ntail > 2 { b |= st.tail[2] as u64 << 16; }
176+
if st.ntail > 3 { b |= st.tail[3] as u64 << 24; }
177+
if st.ntail > 4 { b |= st.tail[4] as u64 << 32; }
178+
if st.ntail > 5 { b |= st.tail[5] as u64 << 40; }
179+
if st.ntail > 6 { b |= st.tail[6] as u64 << 48; }
180+
181+
v3 ^= b;
182+
#compress(v0, v1, v2, v3);
183+
#compress(v0, v1, v2, v3);
184+
v0 ^= b;
185+
186+
v2 ^= 0xff;
187+
#compress(v0, v1, v2, v3);
188+
#compress(v0, v1, v2, v3);
189+
#compress(v0, v1, v2, v3);
190+
#compress(v0, v1, v2, v3);
191+
192+
let h = v0 ^ v1 ^ v2 ^ v3;
193+
194+
ret ~[
195+
(h >> 0) as u8,
196+
(h >> 8) as u8,
197+
(h >> 16) as u8,
198+
(h >> 24) as u8,
199+
(h >> 32) as u8,
200+
(h >> 40) as u8,
201+
(h >> 48) as u8,
202+
(h >> 56) as u8,
203+
];
204+
}
205+
206+
impl of streaming for sipstate {
207+
fn reset() {
208+
self.length = 0;
209+
self.v0 = self.k0 ^ 0x736f6d6570736575;
210+
self.v1 = self.k1 ^ 0x646f72616e646f6d;
211+
self.v2 = self.k0 ^ 0x6c7967656e657261;
212+
self.v3 = self.k1 ^ 0x7465646279746573;
213+
self.ntail = 0;
214+
}
215+
fn input(msg: ~[u8]) { add_input(self, msg); }
216+
fn input_str(msg: ~str) { add_input(self, str::bytes(msg)); }
217+
fn result() -> ~[u8] { ret mk_result(self); }
218+
fn result_str() -> ~str {
219+
let r = mk_result(self);
220+
let mut s = ~"";
221+
for vec::each(r) |b| { s += uint::to_str(b as uint, 16u); }
222+
ret s;
223+
}
224+
}
225+
226+
let st = {
227+
k0 : key0,
228+
k1 : key1,
229+
mut length : 0u,
230+
mut v0 : 0u64,
231+
mut v1 : 0u64,
232+
mut v2 : 0u64,
233+
mut v3 : 0u64,
234+
tail : ~[mut 0u8,0,0,0,0,0,0,0]/8,
235+
mut ntail : 0u,
236+
};
237+
238+
let sh = st as streaming;
239+
sh.reset();
240+
ret sh;
241+
}
242+
80243
#[test]
81244
fn test_siphash() {
82245
let vecs : [[u8]/8]/64 = [
@@ -150,14 +313,34 @@ fn test_siphash() {
150313
let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64;
151314
let mut buf : ~[u8] = ~[];
152315
let mut t = 0;
316+
let stream_inc = siphash(k0,k1);
317+
let stream_full = siphash(k0,k1);
318+
319+
fn to_hex_str(r:[u8]/8) -> ~str {
320+
let mut s = ~"";
321+
for vec::each(r) |b| { s += uint::to_str(b as uint, 16u); }
322+
ret s;
323+
}
324+
153325
while t < 64 {
154326
#debug("siphash test %?", t);
155327
let vec = #u8to64_le(vecs[t], 0);
156328
let out = hash_bytes_keyed(buf, k0, k1);
157329
#debug("got %?, expected %?", out, vec);
158330
assert vec == out;
331+
332+
stream_full.reset();
333+
stream_full.input(buf);
334+
let f = stream_full.result_str();
335+
let i = stream_inc.result_str();
336+
let v = to_hex_str(vecs[t]);
337+
#debug["%d: (%s) => inc=%s full=%s", t, v, i, f];
338+
339+
assert f == i && f == v;
340+
159341
buf += ~[t as u8];
342+
stream_inc.input(~[t as u8]);
343+
160344
t += 1;
161345
}
162-
163-
}
346+
}

0 commit comments

Comments
 (0)