#[must_use]
pub fn sha1(data: &[u8]) -> [u8; 20] {
let mut h0 = 0x67452301_u32;
let mut h1 = 0xefcdab89_u32;
let mut h2 = 0x98badcfe_u32;
let mut h3 = 0x10325476_u32;
let mut h4 = 0xc3d2e1f0_u32;
let bit_len = (data.len() as u64) * 8;
let mut msg = data.to_vec();
msg.push(0x80);
while (msg.len() % 64) != 56 {
msg.push(0);
}
msg.extend_from_slice(&bit_len.to_be_bytes());
for chunk in msg.chunks_exact(64) {
let mut w = [0_u32; 80];
for (i, word) in w.iter_mut().enumerate().take(16) {
let offset = i * 4;
*word = u32::from_be_bytes([
chunk[offset],
chunk[offset + 1],
chunk[offset + 2],
chunk[offset + 3],
]);
}
for i in 16..80 {
w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
}
let mut a = h0;
let mut b = h1;
let mut c = h2;
let mut d = h3;
let mut e = h4;
for (i, wi) in w.iter().enumerate() {
let (f, k) = if i < 20 {
((b & c) | ((!b) & d), 0x5a827999)
} else if i < 40 {
(b ^ c ^ d, 0x6ed9eba1)
} else if i < 60 {
((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
} else {
(b ^ c ^ d, 0xca62c1d6)
};
let temp = a
.rotate_left(5)
.wrapping_add(f)
.wrapping_add(e)
.wrapping_add(k)
.wrapping_add(*wi);
e = d;
d = c;
c = b.rotate_left(30);
b = a;
a = temp;
}
h0 = h0.wrapping_add(a);
h1 = h1.wrapping_add(b);
h2 = h2.wrapping_add(c);
h3 = h3.wrapping_add(d);
h4 = h4.wrapping_add(e);
}
let mut out = [0_u8; 20];
out[0..4].copy_from_slice(&h0.to_be_bytes());
out[4..8].copy_from_slice(&h1.to_be_bytes());
out[8..12].copy_from_slice(&h2.to_be_bytes());
out[12..16].copy_from_slice(&h3.to_be_bytes());
out[16..20].copy_from_slice(&h4.to_be_bytes());
out
}