1use digest::Digest;
64use cryptoutil::{write_u32_be, read_u32v_be, add_bytes_to_bits, FixedBuffer, FixedBuffer64, StandardPadding};
65use simd::u32x4;
66
67const STATE_LEN: usize = 5;
68const BLOCK_LEN: usize = 16;
69
70const K0: u32 = 0x5A827999u32;
71const K1: u32 = 0x6ED9EBA1u32;
72const K2: u32 = 0x8F1BBCDCu32;
73const K3: u32 = 0xCA62C1D6u32;
74
75#[inline]
77pub fn sha1_first(w0: u32x4) -> u32 {
78 w0.0
79}
80
81#[inline]
83pub fn sha1_first_add(e: u32, w0: u32x4) -> u32x4 {
84 let u32x4(a, b, c, d) = w0;
85 u32x4(e.wrapping_add(a), b, c, d)
86}
87
88fn sha1msg1(a: u32x4, b: u32x4) -> u32x4 {
90 let u32x4(_, _, w2, w3) = a;
91 let u32x4(w4, w5, _, _) = b;
92 a ^ u32x4(w2, w3, w4, w5)
93}
94
95fn sha1msg2(a: u32x4, b: u32x4) -> u32x4 {
97 let u32x4(x0, x1, x2, x3) = a;
98 let u32x4(_, w13, w14, w15) = b;
99
100 let w16 = (x0 ^ w13).rotate_left(1);
101 let w17 = (x1 ^ w14).rotate_left(1);
102 let w18 = (x2 ^ w15).rotate_left(1);
103 let w19 = (x3 ^ w16).rotate_left(1);
104
105 u32x4(w16, w17, w18, w19)
106}
107
108pub fn sha1_schedule_x4(v0: u32x4, v1: u32x4, v2: u32x4, v3: u32x4) -> u32x4 {
110 sha1msg2(sha1msg1(v0, v1) ^ v2, v3)
111}
112
113#[inline]
115pub fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 {
116 sha1_first_add(sha1_first(abcd).rotate_left(30), msg)
117}
118
119pub fn sha1_digest_round_x4(abcd: u32x4, work: u32x4, i: i8) -> u32x4 {
122 const K0V: u32x4 = u32x4(K0, K0, K0, K0);
123 const K1V: u32x4 = u32x4(K1, K1, K1, K1);
124 const K2V: u32x4 = u32x4(K2, K2, K2, K2);
125 const K3V: u32x4 = u32x4(K3, K3, K3, K3);
126
127 match i {
128 0 => sha1rnds4c(abcd, work + K0V),
129 1 => sha1rnds4p(abcd, work + K1V),
130 2 => sha1rnds4m(abcd, work + K2V),
131 3 => sha1rnds4p(abcd, work + K3V),
132 _ => panic!("unknown icosaround index")
133 }
134}
135
136fn sha1rnds4c(abcd: u32x4, msg: u32x4) -> u32x4 {
138 let u32x4(mut a, mut b, mut c, mut d) = abcd;
139 let u32x4(t, u, v, w) = msg;
140 let mut e = 0u32;
141
142 macro_rules! bool3ary_202 {
143 ($a:expr, $b:expr, $c:expr) => (($c ^ ($a & ($b ^ $c))))
144 } e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_202!(b, c, d)).wrapping_add(t);
147 b = b.rotate_left(30);
148
149 d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_202!(a, b, c)).wrapping_add(u);
150 a = a.rotate_left(30);
151
152 c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_202!(e, a, b)).wrapping_add(v);
153 e = e.rotate_left(30);
154
155 b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_202!(d, e, a)).wrapping_add(w);
156 d = d.rotate_left(30);
157
158 u32x4(b, c, d, e)
159}
160
161fn sha1rnds4p(abcd: u32x4, msg: u32x4) -> u32x4 {
163 let u32x4(mut a, mut b, mut c, mut d) = abcd;
164 let u32x4(t, u, v, w) = msg;
165 let mut e = 0u32;
166
167 macro_rules! bool3ary_150 {
168 ($a:expr, $b:expr, $c:expr) => (($a ^ $b ^ $c))
169 } e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_150!(b, c, d)).wrapping_add(t);
172 b = b.rotate_left(30);
173
174 d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_150!(a, b, c)).wrapping_add(u);
175 a = a.rotate_left(30);
176
177 c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_150!(e, a, b)).wrapping_add(v);
178 e = e.rotate_left(30);
179
180 b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_150!(d, e, a)).wrapping_add(w);
181 d = d.rotate_left(30);
182
183 u32x4(b, c, d, e)
184}
185
186fn sha1rnds4m(abcd: u32x4, msg: u32x4) -> u32x4 {
188 let u32x4(mut a, mut b, mut c, mut d) = abcd;
189 let u32x4(t, u, v, w) = msg;
190 let mut e = 0u32;
191
192 macro_rules! bool3ary_232 {
193 ($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
194 } e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_232!(b, c, d)).wrapping_add(t);
197 b = b.rotate_left(30);
198
199 d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_232!(a, b, c)).wrapping_add(u);
200 a = a.rotate_left(30);
201
202 c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_232!(e, a, b)).wrapping_add(v);
203 e = e.rotate_left(30);
204
205 b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_232!(d, e, a)).wrapping_add(w);
206 d = d.rotate_left(30);
207
208 u32x4(b, c, d, e)
209}
210
211pub fn sha1_digest_block_u32(state: &mut [u32; 5], block: &[u32; 16]) {
213
214 macro_rules! schedule {
215 ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => (
216 sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3)
217 )
218 }
219
220 macro_rules! rounds4 {
221 ($h0:ident, $h1:ident, $wk:expr, $i:expr) => (
222 sha1_digest_round_x4($h0, sha1_first_half($h1, $wk), $i)
223 )
224 }
225
226 let mut h0 = u32x4(state[0],
228 state[1],
229 state[2],
230 state[3]);
231 let mut w0 = u32x4(block[0],
232 block[1],
233 block[2],
234 block[3]);
235 let mut h1 = sha1_digest_round_x4(h0, sha1_first_add(state[4], w0), 0);
236 let mut w1 = u32x4(block[4],
237 block[5],
238 block[6],
239 block[7]);
240 h0 = rounds4!(h1, h0, w1, 0);
241 let mut w2 = u32x4(block[8],
242 block[9],
243 block[10],
244 block[11]);
245 h1 = rounds4!(h0, h1, w2, 0);
246 let mut w3 = u32x4(block[12],
247 block[13],
248 block[14],
249 block[15]);
250 h0 = rounds4!(h1, h0, w3, 0);
251 let mut w4 = schedule!(w0, w1, w2, w3);
252 h1 = rounds4!(h0, h1, w4, 0);
253
254 w0 = schedule!(w1, w2, w3, w4);
256 h0 = rounds4!(h1, h0, w0, 1);
257 w1 = schedule!(w2, w3, w4, w0);
258 h1 = rounds4!(h0, h1, w1, 1);
259 w2 = schedule!(w3, w4, w0, w1);
260 h0 = rounds4!(h1, h0, w2, 1);
261 w3 = schedule!(w4, w0, w1, w2);
262 h1 = rounds4!(h0, h1, w3, 1);
263 w4 = schedule!(w0, w1, w2, w3);
264 h0 = rounds4!(h1, h0, w4, 1);
265
266 w0 = schedule!(w1, w2, w3, w4);
268 h1 = rounds4!(h0, h1, w0, 2);
269 w1 = schedule!(w2, w3, w4, w0);
270 h0 = rounds4!(h1, h0, w1, 2);
271 w2 = schedule!(w3, w4, w0, w1);
272 h1 = rounds4!(h0, h1, w2, 2);
273 w3 = schedule!(w4, w0, w1, w2);
274 h0 = rounds4!(h1, h0, w3, 2);
275 w4 = schedule!(w0, w1, w2, w3);
276 h1 = rounds4!(h0, h1, w4, 2);
277
278 w0 = schedule!(w1, w2, w3, w4);
280 h0 = rounds4!(h1, h0, w0, 3);
281 w1 = schedule!(w2, w3, w4, w0);
282 h1 = rounds4!(h0, h1, w1, 3);
283 w2 = schedule!(w3, w4, w0, w1);
284 h0 = rounds4!(h1, h0, w2, 3);
285 w3 = schedule!(w4, w0, w1, w2);
286 h1 = rounds4!(h0, h1, w3, 3);
287 w4 = schedule!(w0, w1, w2, w3);
288 h0 = rounds4!(h1, h0, w4, 3);
289
290 let e = sha1_first(h1).rotate_left(30);
291 let u32x4(a, b, c, d) = h0;
292
293 state[0] = state[0].wrapping_add(a);
294 state[1] = state[1].wrapping_add(b);
295 state[2] = state[2].wrapping_add(c);
296 state[3] = state[3].wrapping_add(d);
297 state[4] = state[4].wrapping_add(e);
298}
299
300pub fn sha1_digest_block(state: &mut [u32; 5], block: &[u8]) {
349 assert_eq!(block.len(), BLOCK_LEN*4);
350 let mut block2 = [0u32; BLOCK_LEN];
351 read_u32v_be(&mut block2[..], block);
352 sha1_digest_block_u32(state, &block2);
353}
354
355fn add_input(st: &mut Sha1, msg: &[u8]) {
356 assert!((!st.computed));
357 st.length_bits = add_bytes_to_bits(st.length_bits, msg.len() as u64);
359 let st_h = &mut st.h;
360 st.buffer.input(msg, |d: &[u8]| { sha1_digest_block(st_h, d); });
361}
362
363fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
364 if !st.computed {
365 let st_h = &mut st.h;
366 st.buffer.standard_padding(8, |d: &[u8]| { sha1_digest_block(&mut *st_h, d) });
367 write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 );
368 write_u32_be(st.buffer.next(4), st.length_bits as u32);
369 sha1_digest_block(st_h, st.buffer.full_buffer());
370
371 st.computed = true;
372 }
373
374 write_u32_be(&mut rs[0..4], st.h[0]);
375 write_u32_be(&mut rs[4..8], st.h[1]);
376 write_u32_be(&mut rs[8..12], st.h[2]);
377 write_u32_be(&mut rs[12..16], st.h[3]);
378 write_u32_be(&mut rs[16..20], st.h[4]);
379}
380
381#[derive(Clone, Copy)]
383pub struct Sha1 {
384 h: [u32; STATE_LEN],
385 length_bits: u64,
386 buffer: FixedBuffer64,
387 computed: bool,
388}
389
390impl Sha1 {
391 pub fn new() -> Sha1 {
393 let mut st = Sha1 {
394 h: [0u32; STATE_LEN],
395 length_bits: 0u64,
396 buffer: FixedBuffer64::new(),
397 computed: false,
398 };
399 st.reset();
400 st
401 }
402}
403
404impl Digest for Sha1 {
405 fn reset(&mut self) {
406 self.length_bits = 0;
407 self.h[0] = 0x67452301u32;
408 self.h[1] = 0xEFCDAB89u32;
409 self.h[2] = 0x98BADCFEu32;
410 self.h[3] = 0x10325476u32;
411 self.h[4] = 0xC3D2E1F0u32;
412 self.buffer.reset();
413 self.computed = false;
414 }
415 fn input(&mut self, msg: &[u8]) { add_input(self, msg); }
416 fn result(&mut self, out: &mut [u8]) { mk_result(self, out) }
417 fn output_bits(&self) -> usize { 160 }
418 fn block_size(&self) -> usize { 64 }
419}
420
421#[cfg(test)]
422mod tests {
423 use cryptoutil::test::test_digest_1million_random;
424 use digest::Digest;
425 use sha1::Sha1;
426
427 #[derive(Clone)]
428 struct Test {
429 input: &'static str,
430 output: Vec<u8>,
431 output_str: &'static str,
432 }
433
434 #[test]
435 fn test() {
436 let tests = vec![
437 Test {
439 input: "abc",
440 output: vec![
441 0xA9u8, 0x99u8, 0x3Eu8, 0x36u8,
442 0x47u8, 0x06u8, 0x81u8, 0x6Au8,
443 0xBAu8, 0x3Eu8, 0x25u8, 0x71u8,
444 0x78u8, 0x50u8, 0xC2u8, 0x6Cu8,
445 0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8,
446 ],
447 output_str: "a9993e364706816aba3e25717850c26c9cd0d89d"
448 },
449 Test {
450 input:
451 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
452 output: vec![
453 0x84u8, 0x98u8, 0x3Eu8, 0x44u8,
454 0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8,
455 0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8,
456 0xF9u8, 0x51u8, 0x29u8, 0xE5u8,
457 0xE5u8, 0x46u8, 0x70u8, 0xF1u8,
458 ],
459 output_str: "84983e441c3bd26ebaae4aa1f95129e5e54670f1"
460 },
461 Test {
463 input: "The quick brown fox jumps over the lazy dog",
464 output: vec![
465 0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8,
466 0x7au8, 0x2du8, 0x28u8, 0xfcu8,
467 0xedu8, 0x84u8, 0x9eu8, 0xe1u8,
468 0xbbu8, 0x76u8, 0xe7u8, 0x39u8,
469 0x1bu8, 0x93u8, 0xebu8, 0x12u8,
470 ],
471 output_str: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
472 },
473 Test {
474 input: "The quick brown fox jumps over the lazy cog",
475 output: vec![
476 0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8,
477 0xd2u8, 0x5eu8, 0x1bu8, 0x3au8,
478 0xfau8, 0xd3u8, 0xe8u8, 0x5au8,
479 0x0bu8, 0xd1u8, 0x7du8, 0x9bu8,
480 0x10u8, 0x0du8, 0xb4u8, 0xb3u8,
481 ],
482 output_str: "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3",
483 },
484 ];
485
486 let mut out = [0u8; 20];
489
490 let mut sh = Box::new(Sha1::new());
491 for t in tests.iter() {
492 (*sh).input_str(t.input);
493 sh.result(&mut out);
494 assert!(t.output[..] == out[..]);
495
496 let out_str = (*sh).result_str();
497 assert_eq!(out_str.len(), 40);
498 assert!(&out_str[..] == t.output_str);
499
500 sh.reset();
501 }
502
503
504 for t in tests.iter() {
506 let len = t.input.len();
507 let mut left = len;
508 while left > 0 {
509 let take = (left + 1) / 2;
510 (*sh).input_str(&t.input[len - left..take + len - left]);
511 left = left - take;
512 }
513 sh.result(&mut out);
514 assert!(t.output[..] == out[..]);
515
516 let out_str = (*sh).result_str();
517 assert_eq!(out_str.len(), 40);
518 assert!(&out_str[..] == t.output_str);
519
520 sh.reset();
521 }
522 }
523
524 #[test]
525 fn test_1million_random_sha1() {
526 let mut sh = Sha1::new();
527 test_digest_1million_random(
528 &mut sh,
529 64,
530 "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
531 }
532}
533
534#[cfg(all(test, feature = "with-bench"))]
535mod bench {
536 use test::Bencher;
537 use digest::Digest;
538 use sha1::{STATE_LEN, BLOCK_LEN};
539 use sha1::{Sha1, sha1_digest_block_u32};
540
541 #[bench]
542 pub fn sha1_block(bh: & mut Bencher) {
543 let mut state = [0u32; STATE_LEN];
544 let words = [1u32; BLOCK_LEN];
545 bh.iter( || {
546 sha1_digest_block_u32(&mut state, &words);
547 });
548 bh.bytes = 64u64;
549 }
550
551 #[bench]
552 pub fn sha1_10(bh: & mut Bencher) {
553 let mut sh = Sha1::new();
554 let bytes = [1u8; 10];
555 bh.iter( || {
556 sh.input(&bytes);
557 });
558 bh.bytes = bytes.len() as u64;
559 }
560
561 #[bench]
562 pub fn sha1_1k(bh: & mut Bencher) {
563 let mut sh = Sha1::new();
564 let bytes = [1u8; 1024];
565 bh.iter( || {
566 sh.input(&bytes);
567 });
568 bh.bytes = bytes.len() as u64;
569 }
570
571 #[bench]
572 pub fn sha1_64k(bh: & mut Bencher) {
573 let mut sh = Sha1::new();
574 let bytes = [1u8; 65536];
575 bh.iter( || {
576 sh.input(&bytes);
577 });
578 bh.bytes = bytes.len() as u64;
579 }
580
581}