1use crate::constants::CRYPTO_HASH_SHA256_BYTES;
26use crate::sha2_impl::sha2_hasher;
27use crate::types::*;
28
29#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
30mod sha256_aarch64;
31
32pub type Digest = StackByteArray<CRYPTO_HASH_SHA256_BYTES>;
34
35const BLOCK_BYTES: usize = 64;
36
37const IV: [u32; 8] = [
38 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
39];
40
41#[inline]
48fn compress(state: &mut [u32; 8], blocks: &[[u8; BLOCK_BYTES]]) {
49 #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
50 if let Some(sha2) = crate::aarch64::Sha2::new() {
51 sha256_aarch64::compress(sha2, state, blocks);
52 return;
53 }
54 sha2::block_api::compress256(state, blocks);
55}
56
57sha2_hasher! {
58 pub struct Sha256;
66 algorithm: "SHA-256",
67 word: u32,
68 word_bytes: 4,
69 length: u64,
70 length_bytes: 8,
71 block_bytes: BLOCK_BYTES,
72 digest_bytes: CRYPTO_HASH_SHA256_BYTES,
73 iv: IV,
74 compress: compress,
75}
76
77#[cfg(all(test, feature = "alloc"))]
78mod tests {
79 use sha2::Digest as _;
80
81 use super::*;
82 use crate::test_prelude::*;
83 use crate::utils::test_util::hex;
84
85 #[test]
88 fn test_sha256_known_answers() {
89 assert_eq!(
90 Sha256::compute_to_vec(b""),
91 hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
92 );
93 assert_eq!(
94 Sha256::compute_to_vec(b"abc"),
95 hex("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
96 );
97 assert_eq!(
98 Sha256::compute_to_vec(b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"),
99 hex("248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1")
100 );
101 }
102
103 #[test]
106 fn test_sha256_matches_sha2_for_all_lengths_and_chunkings() {
107 let message: Vec<u8> = (0..600u32).map(|i| (i * 31 % 251) as u8).collect();
108 for len in (0..200).chain([255, 256, 257, 511, 512, 513, 599, 600]) {
109 let expected = sha2::Sha256::digest(&message[..len]).to_vec();
110 assert_eq!(
111 Sha256::compute_to_vec(&message[..len]),
112 expected,
113 "len {len}"
114 );
115
116 let mut hasher = Sha256::new();
117 let mut offset = 0;
118 for chunk in [1usize, 7, 63, 64, 65, 100, 3].iter().cycle() {
119 if offset >= len {
120 break;
121 }
122 let end = (offset + chunk).min(len);
123 hasher.update(&message[offset..end]);
124 offset = end;
125 }
126 assert_eq!(hasher.finalize_to_vec(), expected, "chunked len {len}");
127 }
128 }
129
130 #[test]
135 fn test_empty_and_exact_fill_updates_match_sha2() {
136 const B: usize = BLOCK_BYTES;
137 let message: Vec<u8> = (0..3 * B as u32).map(|i| (i * 31 % 251) as u8).collect();
138 for len in [B, B + 1, 2 * B, 2 * B + 1, 3 * B - 1, 3 * B] {
139 let message = &message[..len];
140 let mut cuts: Vec<usize> = [0, 1, B, 2 * B, 3 * B - 1, len]
141 .into_iter()
142 .filter(|&cut| cut <= len)
143 .collect();
144 cuts.dedup();
145 let mut hasher = Sha256::new();
146 hasher.update(b"");
147 for window in cuts.windows(2) {
148 hasher.update(&message[window[0]..window[1]]);
149 hasher.update(b"");
150 }
151 assert_eq!(
152 hasher.finalize_to_vec(),
153 sha2::Sha256::digest(message).to_vec(),
154 "len {len}"
155 );
156 }
157 }
158
159 #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
162 #[test]
163 fn test_hw_compress_matches_portable() {
164 let Some(sha2) = crate::aarch64::Sha2::new() else {
165 return;
166 };
167 let blocks: Vec<[u8; 64]> = (0..40u32)
168 .map(|b| {
169 core::array::from_fn(|i| (b * 64 + i as u32).wrapping_mul(2654435761) as u8 >> 1)
170 })
171 .collect();
172 for n in 0..=blocks.len() {
173 let mut expected = IV;
174 let mut actual = IV;
175 sha2::block_api::compress256(&mut expected, &blocks[..n]);
176 sha256_aarch64::compress(sha2, &mut actual, &blocks[..n]);
177 assert_eq!(actual, expected, "{n} blocks");
178 }
179 }
180}