#![allow(dead_code)]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::{string::String, vec, vec::Vec};
#[deprecated(
since = "1.0.0",
note = "SHA-1 is cryptographically broken. Use sha2 crate for production."
)]
pub struct Sha1;
#[allow(deprecated)]
impl Sha1 {
pub fn hash(input: &str) -> String {
let payload = input.as_bytes();
let mut h0 = 0x67452301u32;
let mut h1 = 0xEFCDAB89u32;
let mut h2 = 0x98BADCFEu32;
let mut h3 = 0x10325476u32;
let mut h4 = 0xC3D2E1F0u32;
let ml = (payload.len() as u64) * 8;
let mut message = payload.to_vec();
message.push(0x80);
while (message.len() * 8) % 512 != 448 {
message.push(0);
}
message.extend_from_slice(&ml.to_be_bytes());
for chunk in message.chunks(64) {
let mut words = vec![0u32; 80];
#[allow(clippy::needless_range_loop)]
for i in 0..16 {
let start = i * 4;
words[i] = u32::from_be_bytes([
chunk[start],
chunk[start + 1],
chunk[start + 2],
chunk[start + 3],
]);
}
for i in 16..80 {
words[i] = (words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16])
.rotate_left(1);
}
let (mut a, mut b, mut c, mut d, mut e) = (h0, h1, h2, h3, h4);
#[allow(clippy::needless_range_loop)]
for i in 0..80 {
let (f, k) = match i {
0..=19 => ((b & c) | ((!b) & d), 0x5A827999u32),
20..=39 => (b ^ c ^ d, 0x6ED9EBA1u32),
40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDCu32),
60..=79 => (b ^ c ^ d, 0xCA62C1D6u32),
_ => unreachable!(),
};
let temp = a
.rotate_left(5)
.wrapping_add(f)
.wrapping_add(e)
.wrapping_add(k)
.wrapping_add(words[i]);
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);
}
format!(
"{:08x}{:08x}{:08x}{:08x}{:08x}",
h0, h1, h2, h3, h4
)
}
pub fn verify(input: &str, expected_hash: &str) -> bool {
Self::hash(input) == expected_hash
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[allow(deprecated)]
fn test_sha1_empty() {
let hash = Sha1::hash("");
assert_eq!(hash, "da39a3ee5e6b4b0d3255bfef95601890afd80709");
}
#[test]
#[allow(deprecated)]
fn test_sha1_hello() {
let hash = Sha1::hash("hello");
assert_eq!(hash, "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d");
}
#[test]
#[allow(deprecated)]
fn test_sha1_abc() {
let hash = Sha1::hash("abc");
assert_eq!(hash, "a9993e364706816aba3e25717850c26c9cd0d89d");
}
#[test]
#[allow(deprecated)]
fn test_sha1_verify() {
assert!(Sha1::verify("hello", "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"));
assert!(!Sha1::verify("hello", "wrong_hash"));
}
}