From b558cb5a42269c626bbe32327c4c2cacd460e6c1 Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sat, 21 Mar 2026 14:43:00 -0400 Subject: [PATCH 1/3] I think these NIST FIPS-180 2 approved tests for SHA1 are a nice touch. https://www.nist.gov/itl/ssd/software-quality-group/nsrl-test-data --- Cargo.lock | 1 + sha1/Cargo.toml | 1 + sha1/tests/mod.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index f981de29e..840a2d2f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -290,6 +290,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest", + "hex", "hex-literal", ] diff --git a/sha1/Cargo.toml b/sha1/Cargo.toml index 34c078b61..882d19e8d 100644 --- a/sha1/Cargo.toml +++ b/sha1/Cargo.toml @@ -21,6 +21,7 @@ cpufeatures = "0.3" [dev-dependencies] digest = { version = "0.11", features = ["dev"] } +hex = "0.4.3" hex-literal = "1" [features] diff --git a/sha1/tests/mod.rs b/sha1/tests/mod.rs index 92858ae3f..a46b086d2 100644 --- a/sha1/tests/mod.rs +++ b/sha1/tests/mod.rs @@ -1,10 +1,24 @@ use digest::dev::{feed_rand_16mib, fixed_reset_test}; use hex_literal::hex; use sha1::{Digest, Sha1}; +use std::fs; +use std::path::Path; +use std::time::{SystemTime, UNIX_EPOCH}; digest::new_test!(sha1_kat, Sha1, fixed_reset_test); digest::hash_serialization_test!(sha1_serialization, Sha1); +fn sha1_hex(bytes: &[u8]) -> String { + let mut hasher = Sha1::new(); + hasher.update(bytes); + hex::encode(hasher.finalize()) +} + +fn sha1_file_hex(path: impl AsRef) -> std::io::Result { + let bytes = fs::read(path)?; + Ok(sha1_hex(&bytes)) +} + #[test] fn sha1_rand() { let mut h = Sha1::new(); @@ -14,3 +28,63 @@ fn sha1_rand() { hex!("7e565a25a8b123e9881addbcedcd927b23377a78"), ); } + +/// +/// Test vectors from https://www.nist.gov/itl/ssd/software-quality-group/nsrl-test-data for SHA-1. +/// + +/// A file containing the ASCII string "abc" results in a 160 bit message digest of +/// a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d. +#[test] +fn abc_file_has_expected_sha1_digest() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time should be after the unix epoch") + .as_nanos(); + let path = std::env::temp_dir().join(format!("tester-sha1-{unique}.txt")); + + fs::write(&path, b"abc").expect("should write test file"); + let digest = sha1_file_hex(&path).expect("should hash test file"); + + let _ = fs::remove_file(&path); + + assert_eq!(digest, "a9993e364706816aba3e25717850c26c9cd0d89d"); +} + +/// A file containing the ASCII string "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +/// results in a 160-bit message digest of 84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1. +#[test] +fn long_test_vector_file_has_expected_sha1_digest() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time should be after the unix epoch") + .as_nanos(); + let path = std::env::temp_dir().join(format!("tester-sha1-{unique}.txt")); + let contents = b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + + fs::write(&path, contents).expect("should write test file"); + let digest = sha1_file_hex(&path).expect("should hash test file"); + + let _ = fs::remove_file(&path); + + assert_eq!(digest, "84983e441c3bd26ebaae4aa1f95129e5e54670f1"); +} + +/// A file containing the binary-coded form of the ASCII string which consists of 1,000,000 repetitions of the character "a" results +/// in a SHA-1 message digest of 34aa973c d4c4daa4 f61eeb2b dbad2731 6534016f. +#[test] +fn one_million_a_file_has_expected_sha1_digest() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time should be after the unix epoch") + .as_nanos(); + let path = std::env::temp_dir().join(format!("tester-sha1-{unique}.txt")); + let contents = vec![b'a'; 1_000_000]; + + fs::write(&path, contents).expect("should write test file"); + let digest = sha1_file_hex(&path).expect("should hash test file"); + + let _ = fs::remove_file(&path); + + assert_eq!(digest, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); +} From 1fc74b93c31aa1967c14ca0dc03e7794b46f90dc Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sat, 21 Mar 2026 14:53:02 -0400 Subject: [PATCH 2/3] fixing typo --- sha1/tests/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sha1/tests/mod.rs b/sha1/tests/mod.rs index a46b086d2..74f9dfb8f 100644 --- a/sha1/tests/mod.rs +++ b/sha1/tests/mod.rs @@ -34,7 +34,7 @@ fn sha1_rand() { /// /// A file containing the ASCII string "abc" results in a 160 bit message digest of -/// a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d. +/// a9993e364706816aba3e25717850c26c9cd0d89d #[test] fn abc_file_has_expected_sha1_digest() { let unique = SystemTime::now() @@ -52,7 +52,7 @@ fn abc_file_has_expected_sha1_digest() { } /// A file containing the ASCII string "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" -/// results in a 160-bit message digest of 84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1. +/// results in a 160-bit message digest of 84983e441c3bd26ebaae4aa1f95129e5e54670f1. #[test] fn long_test_vector_file_has_expected_sha1_digest() { let unique = SystemTime::now() @@ -71,7 +71,7 @@ fn long_test_vector_file_has_expected_sha1_digest() { } /// A file containing the binary-coded form of the ASCII string which consists of 1,000,000 repetitions of the character "a" results -/// in a SHA-1 message digest of 34aa973c d4c4daa4 f61eeb2b dbad2731 6534016f. +/// in a SHA-1 message digest of 34aa973cd4c4daa4f61eeb2bdbad27316534016f. #[test] fn one_million_a_file_has_expected_sha1_digest() { let unique = SystemTime::now() From 11053276a9d026a99544f613dab071ad77a4177a Mon Sep 17 00:00:00 2001 From: Mike Mulchrone Date: Sat, 21 Mar 2026 15:16:33 -0400 Subject: [PATCH 3/3] I have a feeling it was an error with MacOS and the way the value was being constructed --- sha1/tests/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sha1/tests/mod.rs b/sha1/tests/mod.rs index 74f9dfb8f..e1fd8433b 100644 --- a/sha1/tests/mod.rs +++ b/sha1/tests/mod.rs @@ -79,9 +79,9 @@ fn one_million_a_file_has_expected_sha1_digest() { .expect("system time should be after the unix epoch") .as_nanos(); let path = std::env::temp_dir().join(format!("tester-sha1-{unique}.txt")); - let contents = vec![b'a'; 1_000_000]; + let bytes: Vec = std::iter::repeat(b'a').take(1_000_000).collect(); - fs::write(&path, contents).expect("should write test file"); + fs::write(&path, bytes).expect("should write test file"); let digest = sha1_file_hex(&path).expect("should hash test file"); let _ = fs::remove_file(&path);