1#![deny(missing_docs)]
13#![allow(deprecated)]
14#![allow(clippy::double_parens)]
15#![allow(clippy::identity_op)]
16#![allow(dead_code)]
17
18use core::cmp;
19use core::fmt;
20use core::hash;
21use core::str;
22
23pub use self::fake::*;
24
25pub trait SimdExt {
26 fn simd_eq(self, rhs: Self) -> Self;
27}
28
29impl SimdExt for u32x4 {
30 fn simd_eq(self, rhs: Self) -> Self {
31 if self == rhs {
32 u32x4(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff)
33 } else {
34 u32x4(0, 0, 0, 0)
35 }
36 }
37}
38
39mod fake {
40 use core::ops::{Add, BitAnd, BitOr, BitXor, Shl, Shr, Sub};
41
42 #[derive(Clone, Copy, PartialEq, Eq)]
43 #[allow(non_camel_case_types)]
44 pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
45
46 impl Add for u32x4 {
47 type Output = u32x4;
48
49 fn add(self, rhs: u32x4) -> u32x4 {
50 u32x4(
51 self.0.wrapping_add(rhs.0),
52 self.1.wrapping_add(rhs.1),
53 self.2.wrapping_add(rhs.2),
54 self.3.wrapping_add(rhs.3),
55 )
56 }
57 }
58
59 impl Sub for u32x4 {
60 type Output = u32x4;
61
62 fn sub(self, rhs: u32x4) -> u32x4 {
63 u32x4(
64 self.0.wrapping_sub(rhs.0),
65 self.1.wrapping_sub(rhs.1),
66 self.2.wrapping_sub(rhs.2),
67 self.3.wrapping_sub(rhs.3),
68 )
69 }
70 }
71
72 impl BitAnd for u32x4 {
73 type Output = u32x4;
74
75 fn bitand(self, rhs: u32x4) -> u32x4 {
76 u32x4(
77 self.0 & rhs.0,
78 self.1 & rhs.1,
79 self.2 & rhs.2,
80 self.3 & rhs.3,
81 )
82 }
83 }
84
85 impl BitOr for u32x4 {
86 type Output = u32x4;
87
88 fn bitor(self, rhs: u32x4) -> u32x4 {
89 u32x4(
90 self.0 | rhs.0,
91 self.1 | rhs.1,
92 self.2 | rhs.2,
93 self.3 | rhs.3,
94 )
95 }
96 }
97
98 impl BitXor for u32x4 {
99 type Output = u32x4;
100
101 fn bitxor(self, rhs: u32x4) -> u32x4 {
102 u32x4(
103 self.0 ^ rhs.0,
104 self.1 ^ rhs.1,
105 self.2 ^ rhs.2,
106 self.3 ^ rhs.3,
107 )
108 }
109 }
110
111 impl Shl<usize> for u32x4 {
112 type Output = u32x4;
113
114 fn shl(self, amt: usize) -> u32x4 {
115 u32x4(self.0 << amt, self.1 << amt, self.2 << amt, self.3 << amt)
116 }
117 }
118
119 impl Shl<u32x4> for u32x4 {
120 type Output = u32x4;
121
122 fn shl(self, rhs: u32x4) -> u32x4 {
123 u32x4(
124 self.0 << rhs.0,
125 self.1 << rhs.1,
126 self.2 << rhs.2,
127 self.3 << rhs.3,
128 )
129 }
130 }
131
132 impl Shr<usize> for u32x4 {
133 type Output = u32x4;
134
135 fn shr(self, amt: usize) -> u32x4 {
136 u32x4(self.0 >> amt, self.1 >> amt, self.2 >> amt, self.3 >> amt)
137 }
138 }
139
140 impl Shr<u32x4> for u32x4 {
141 type Output = u32x4;
142
143 fn shr(self, rhs: u32x4) -> u32x4 {
144 u32x4(
145 self.0 >> rhs.0,
146 self.1 >> rhs.1,
147 self.2 >> rhs.2,
148 self.3 >> rhs.3,
149 )
150 }
151 }
152
153 #[derive(Clone, Copy)]
154 #[allow(non_camel_case_types)]
155 pub struct u64x2(pub u64, pub u64);
156
157 impl Add for u64x2 {
158 type Output = u64x2;
159
160 fn add(self, rhs: u64x2) -> u64x2 {
161 u64x2(self.0.wrapping_add(rhs.0), self.1.wrapping_add(rhs.1))
162 }
163 }
164}
165
166pub const DIGEST_LENGTH: usize = 20;
168
169#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
171pub struct Sha1 {
172 state: Sha1State,
173 blocks: Blocks,
174 len: u64,
175}
176
177struct Blocks {
178 len: u32,
179 block: [u8; 64],
180}
181
182#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)]
183struct Sha1State {
184 state: [u32; 5],
185}
186
187#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy, Default)]
198pub struct Digest {
199 data: Sha1State,
200}
201
202const DEFAULT_STATE: Sha1State = Sha1State {
203 state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
204};
205
206#[inline(always)]
207fn as_block(input: &[u8]) -> &[u8; 64] {
208 unsafe {
209 assert_eq!(input.len(), 64);
210 let arr: &[u8; 64] = &*(input.as_ptr() as *const [u8; 64]);
211 arr
212 }
213}
214
215impl Default for Sha1 {
216 fn default() -> Sha1 {
217 Sha1::new()
218 }
219}
220
221impl Sha1 {
222 pub fn new() -> Sha1 {
226 Sha1 {
227 state: DEFAULT_STATE,
228 len: 0,
229 blocks: Blocks {
230 len: 0,
231 block: [0; 64],
232 },
233 }
234 }
235
236 pub fn from<D: AsRef<[u8]>>(data: D) -> Sha1 {
241 let mut rv = Sha1::new();
242 rv.update(data.as_ref());
243 rv
244 }
245
246 pub fn update(&mut self, data: &[u8]) {
248 let len = &mut self.len;
249 let state = &mut self.state;
250 self.blocks.input(data, |block| {
251 *len += block.len() as u64;
252 state.process(block);
253 })
254 }
255
256 pub fn digest(&self) -> Digest {
258 let mut state = self.state;
259 let bits = (self.len + (self.blocks.len as u64)) * 8;
260 let extra = [
261 (bits >> 56) as u8,
262 (bits >> 48) as u8,
263 (bits >> 40) as u8,
264 (bits >> 32) as u8,
265 (bits >> 24) as u8,
266 (bits >> 16) as u8,
267 (bits >> 8) as u8,
268 (bits >> 0) as u8,
269 ];
270 let mut last = [0; 128];
271 let blocklen = self.blocks.len as usize;
272 last[..blocklen].clone_from_slice(&self.blocks.block[..blocklen]);
273 last[blocklen] = 0x80;
274
275 if blocklen < 56 {
276 last[56..64].clone_from_slice(&extra);
277 state.process(as_block(&last[0..64]));
278 } else {
279 last[120..128].clone_from_slice(&extra);
280 state.process(as_block(&last[0..64]));
281 state.process(as_block(&last[64..128]));
282 }
283
284 Digest { data: state }
285 }
286}
287
288impl Digest {
289 pub fn bytes(&self) -> [u8; DIGEST_LENGTH] {
291 [
292 (self.data.state[0] >> 24) as u8,
293 (self.data.state[0] >> 16) as u8,
294 (self.data.state[0] >> 8) as u8,
295 (self.data.state[0] >> 0) as u8,
296 (self.data.state[1] >> 24) as u8,
297 (self.data.state[1] >> 16) as u8,
298 (self.data.state[1] >> 8) as u8,
299 (self.data.state[1] >> 0) as u8,
300 (self.data.state[2] >> 24) as u8,
301 (self.data.state[2] >> 16) as u8,
302 (self.data.state[2] >> 8) as u8,
303 (self.data.state[2] >> 0) as u8,
304 (self.data.state[3] >> 24) as u8,
305 (self.data.state[3] >> 16) as u8,
306 (self.data.state[3] >> 8) as u8,
307 (self.data.state[3] >> 0) as u8,
308 (self.data.state[4] >> 24) as u8,
309 (self.data.state[4] >> 16) as u8,
310 (self.data.state[4] >> 8) as u8,
311 (self.data.state[4] >> 0) as u8,
312 ]
313 }
314}
315
316impl Blocks {
317 fn input<F>(&mut self, mut input: &[u8], mut f: F)
318 where
319 F: FnMut(&[u8; 64]),
320 {
321 if self.len > 0 {
322 let len = self.len as usize;
323 let amt = cmp::min(input.len(), self.block.len() - len);
324 self.block[len..len + amt].clone_from_slice(&input[..amt]);
325 if len + amt == self.block.len() {
326 f(&self.block);
327 self.len = 0;
328 input = &input[amt..];
329 } else {
330 self.len += amt as u32;
331 return;
332 }
333 }
334 assert_eq!(self.len, 0);
335 for chunk in input.chunks(64) {
336 if chunk.len() == 64 {
337 f(as_block(chunk))
338 } else {
339 self.block[..chunk.len()].clone_from_slice(chunk);
340 self.len = chunk.len() as u32;
341 }
342 }
343 }
344}
345
346const K0: u32 = 0x5A827999u32;
348const K1: u32 = 0x6ED9EBA1u32;
349const K2: u32 = 0x8F1BBCDCu32;
350const K3: u32 = 0xCA62C1D6u32;
351
352#[inline]
354fn sha1_first(w0: u32x4) -> u32 {
355 w0.0
356}
357
358#[inline]
360fn sha1_first_add(e: u32, w0: u32x4) -> u32x4 {
361 let u32x4(a, b, c, d) = w0;
362 u32x4(e.wrapping_add(a), b, c, d)
363}
364
365fn sha1msg1(a: u32x4, b: u32x4) -> u32x4 {
367 let u32x4(_, _, w2, w3) = a;
368 let u32x4(w4, w5, _, _) = b;
369 a ^ u32x4(w2, w3, w4, w5)
370}
371
372fn sha1msg2(a: u32x4, b: u32x4) -> u32x4 {
374 let u32x4(x0, x1, x2, x3) = a;
375 let u32x4(_, w13, w14, w15) = b;
376
377 let w16 = (x0 ^ w13).rotate_left(1);
378 let w17 = (x1 ^ w14).rotate_left(1);
379 let w18 = (x2 ^ w15).rotate_left(1);
380 let w19 = (x3 ^ w16).rotate_left(1);
381
382 u32x4(w16, w17, w18, w19)
383}
384
385#[inline]
387fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 {
388 sha1_first_add(sha1_first(abcd).rotate_left(30), msg)
389}
390
391fn sha1_digest_round_x4(abcd: u32x4, work: u32x4, i: i8) -> u32x4 {
394 const K0V: u32x4 = u32x4(K0, K0, K0, K0);
395 const K1V: u32x4 = u32x4(K1, K1, K1, K1);
396 const K2V: u32x4 = u32x4(K2, K2, K2, K2);
397 const K3V: u32x4 = u32x4(K3, K3, K3, K3);
398
399 match i {
400 0 => sha1rnds4c(abcd, work + K0V),
401 1 => sha1rnds4p(abcd, work + K1V),
402 2 => sha1rnds4m(abcd, work + K2V),
403 3 => sha1rnds4p(abcd, work + K3V),
404 _ => panic!("unknown icosaround index"),
405 }
406}
407
408fn sha1rnds4c(abcd: u32x4, msg: u32x4) -> u32x4 {
410 let u32x4(mut a, mut b, mut c, mut d) = abcd;
411 let u32x4(t, u, v, w) = msg;
412 let mut e = 0u32;
413
414 macro_rules! bool3ary_202 {
415 ($a:expr, $b:expr, $c:expr) => {
416 ($c ^ ($a & ($b ^ $c)))
417 };
418 } e = e
421 .wrapping_add(a.rotate_left(5))
422 .wrapping_add(bool3ary_202!(b, c, d))
423 .wrapping_add(t);
424 b = b.rotate_left(30);
425
426 d = d
427 .wrapping_add(e.rotate_left(5))
428 .wrapping_add(bool3ary_202!(a, b, c))
429 .wrapping_add(u);
430 a = a.rotate_left(30);
431
432 c = c
433 .wrapping_add(d.rotate_left(5))
434 .wrapping_add(bool3ary_202!(e, a, b))
435 .wrapping_add(v);
436 e = e.rotate_left(30);
437
438 b = b
439 .wrapping_add(c.rotate_left(5))
440 .wrapping_add(bool3ary_202!(d, e, a))
441 .wrapping_add(w);
442 d = d.rotate_left(30);
443
444 u32x4(b, c, d, e)
445}
446
447fn sha1rnds4p(abcd: u32x4, msg: u32x4) -> u32x4 {
449 let u32x4(mut a, mut b, mut c, mut d) = abcd;
450 let u32x4(t, u, v, w) = msg;
451 let mut e = 0u32;
452
453 macro_rules! bool3ary_150 {
454 ($a:expr, $b:expr, $c:expr) => {
455 ($a ^ $b ^ $c)
456 };
457 } e = e
460 .wrapping_add(a.rotate_left(5))
461 .wrapping_add(bool3ary_150!(b, c, d))
462 .wrapping_add(t);
463 b = b.rotate_left(30);
464
465 d = d
466 .wrapping_add(e.rotate_left(5))
467 .wrapping_add(bool3ary_150!(a, b, c))
468 .wrapping_add(u);
469 a = a.rotate_left(30);
470
471 c = c
472 .wrapping_add(d.rotate_left(5))
473 .wrapping_add(bool3ary_150!(e, a, b))
474 .wrapping_add(v);
475 e = e.rotate_left(30);
476
477 b = b
478 .wrapping_add(c.rotate_left(5))
479 .wrapping_add(bool3ary_150!(d, e, a))
480 .wrapping_add(w);
481 d = d.rotate_left(30);
482
483 u32x4(b, c, d, e)
484}
485
486fn sha1rnds4m(abcd: u32x4, msg: u32x4) -> u32x4 {
488 let u32x4(mut a, mut b, mut c, mut d) = abcd;
489 let u32x4(t, u, v, w) = msg;
490 let mut e = 0u32;
491
492 macro_rules! bool3ary_232 {
493 ($a:expr, $b:expr, $c:expr) => {
494 ($a & $b) ^ ($a & $c) ^ ($b & $c)
495 };
496 } e = e
499 .wrapping_add(a.rotate_left(5))
500 .wrapping_add(bool3ary_232!(b, c, d))
501 .wrapping_add(t);
502 b = b.rotate_left(30);
503
504 d = d
505 .wrapping_add(e.rotate_left(5))
506 .wrapping_add(bool3ary_232!(a, b, c))
507 .wrapping_add(u);
508 a = a.rotate_left(30);
509
510 c = c
511 .wrapping_add(d.rotate_left(5))
512 .wrapping_add(bool3ary_232!(e, a, b))
513 .wrapping_add(v);
514 e = e.rotate_left(30);
515
516 b = b
517 .wrapping_add(c.rotate_left(5))
518 .wrapping_add(bool3ary_232!(d, e, a))
519 .wrapping_add(w);
520 d = d.rotate_left(30);
521
522 u32x4(b, c, d, e)
523}
524
525impl Sha1State {
526 fn process(&mut self, block: &[u8; 64]) {
527 let mut words = [0u32; 16];
528 for (i, word) in words.iter_mut().enumerate() {
529 let off = i * 4;
530 *word = (block[off + 3] as u32)
531 | ((block[off + 2] as u32) << 8)
532 | ((block[off + 1] as u32) << 16)
533 | ((block[off] as u32) << 24);
534 }
535 macro_rules! schedule {
536 ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {
537 sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3)
538 };
539 }
540
541 macro_rules! rounds4 {
542 ($h0:ident, $h1:ident, $wk:expr, $i:expr) => {
543 sha1_digest_round_x4($h0, sha1_first_half($h1, $wk), $i)
544 };
545 }
546
547 let mut h0 = u32x4(self.state[0], self.state[1], self.state[2], self.state[3]);
549 let mut w0 = u32x4(words[0], words[1], words[2], words[3]);
550 let mut h1 = sha1_digest_round_x4(h0, sha1_first_add(self.state[4], w0), 0);
551 let mut w1 = u32x4(words[4], words[5], words[6], words[7]);
552 h0 = rounds4!(h1, h0, w1, 0);
553 let mut w2 = u32x4(words[8], words[9], words[10], words[11]);
554 h1 = rounds4!(h0, h1, w2, 0);
555 let mut w3 = u32x4(words[12], words[13], words[14], words[15]);
556 h0 = rounds4!(h1, h0, w3, 0);
557 let mut w4 = schedule!(w0, w1, w2, w3);
558 h1 = rounds4!(h0, h1, w4, 0);
559
560 w0 = schedule!(w1, w2, w3, w4);
562 h0 = rounds4!(h1, h0, w0, 1);
563 w1 = schedule!(w2, w3, w4, w0);
564 h1 = rounds4!(h0, h1, w1, 1);
565 w2 = schedule!(w3, w4, w0, w1);
566 h0 = rounds4!(h1, h0, w2, 1);
567 w3 = schedule!(w4, w0, w1, w2);
568 h1 = rounds4!(h0, h1, w3, 1);
569 w4 = schedule!(w0, w1, w2, w3);
570 h0 = rounds4!(h1, h0, w4, 1);
571
572 w0 = schedule!(w1, w2, w3, w4);
574 h1 = rounds4!(h0, h1, w0, 2);
575 w1 = schedule!(w2, w3, w4, w0);
576 h0 = rounds4!(h1, h0, w1, 2);
577 w2 = schedule!(w3, w4, w0, w1);
578 h1 = rounds4!(h0, h1, w2, 2);
579 w3 = schedule!(w4, w0, w1, w2);
580 h0 = rounds4!(h1, h0, w3, 2);
581 w4 = schedule!(w0, w1, w2, w3);
582 h1 = rounds4!(h0, h1, w4, 2);
583
584 w0 = schedule!(w1, w2, w3, w4);
586 h0 = rounds4!(h1, h0, w0, 3);
587 w1 = schedule!(w2, w3, w4, w0);
588 h1 = rounds4!(h0, h1, w1, 3);
589 w2 = schedule!(w3, w4, w0, w1);
590 h0 = rounds4!(h1, h0, w2, 3);
591 w3 = schedule!(w4, w0, w1, w2);
592 h1 = rounds4!(h0, h1, w3, 3);
593 w4 = schedule!(w0, w1, w2, w3);
594 h0 = rounds4!(h1, h0, w4, 3);
595
596 let e = sha1_first(h1).rotate_left(30);
597 let u32x4(a, b, c, d) = h0;
598
599 self.state[0] = self.state[0].wrapping_add(a);
600 self.state[1] = self.state[1].wrapping_add(b);
601 self.state[2] = self.state[2].wrapping_add(c);
602 self.state[3] = self.state[3].wrapping_add(d);
603 self.state[4] = self.state[4].wrapping_add(e);
604 }
605}
606
607impl PartialEq for Blocks {
608 fn eq(&self, other: &Blocks) -> bool {
609 (self.len, &self.block[..]).eq(&(other.len, &other.block[..]))
610 }
611}
612
613impl Ord for Blocks {
614 fn cmp(&self, other: &Blocks) -> cmp::Ordering {
615 (self.len, &self.block[..]).cmp(&(other.len, &other.block[..]))
616 }
617}
618
619impl PartialOrd for Blocks {
620 fn partial_cmp(&self, other: &Blocks) -> Option<cmp::Ordering> {
621 Some(self.cmp(other))
622 }
623}
624
625impl Eq for Blocks {}
626
627impl hash::Hash for Blocks {
628 fn hash<H: hash::Hasher>(&self, state: &mut H) {
629 self.len.hash(state);
630 self.block.hash(state);
631 }
632}
633
634impl Clone for Blocks {
635 fn clone(&self) -> Blocks {
636 Blocks { ..*self }
637 }
638}
639
640#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
642pub struct DigestParseError(());
643
644impl fmt::Display for DigestParseError {
645 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
646 write!(f, "not a valid sha1 hash")
647 }
648}
649
650impl str::FromStr for Digest {
651 type Err = DigestParseError;
652
653 fn from_str(s: &str) -> Result<Digest, DigestParseError> {
654 if s.len() != 40 {
655 return Err(DigestParseError(()));
656 }
657 let mut rv: Digest = Default::default();
658 for idx in 0..5 {
659 rv.data.state[idx] = u32::from_str_radix(&s[idx * 8..idx * 8 + 8], 16)
660 .map_err(|_| DigestParseError(()))?;
661 }
662 Ok(rv)
663 }
664}
665
666impl fmt::Display for Digest {
667 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
668 for i in self.data.state.iter() {
669 write!(f, "{:08x}", i)?;
670 }
671 Ok(())
672 }
673}
674
675impl fmt::Debug for Digest {
676 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
677 write!(f, "Digest {{ \"{}\" }}", self)
678 }
679}