orion/hazardous/hash/sha2/
sha256.rs1use crate::errors::UnknownCryptoError;
63
64#[cfg(feature = "safe_api")]
65use std::io;
66
67pub const SHA256_BLOCKSIZE: usize = 64;
69pub const SHA256_OUTSIZE: usize = 32;
71const N_CONSTS: usize = 64;
73
74construct_public! {
75 (Digest, test_digest, SHA256_OUTSIZE, SHA256_OUTSIZE)
81}
82
83impl_from_trait!(Digest, SHA256_OUTSIZE);
84
85use super::sha2_core::{State, Variant, Word};
86use super::w32::WordU32;
87
88#[derive(Clone)]
89pub(crate) struct V256;
91
92impl Variant<WordU32, N_CONSTS> for V256 {
93 #[rustfmt::skip]
94 #[allow(clippy::unreadable_literal)]
95 const K: [WordU32; N_CONSTS] = [
97 WordU32(0x428a2f98), WordU32(0x71374491), WordU32(0xb5c0fbcf), WordU32(0xe9b5dba5),
98 WordU32(0x3956c25b), WordU32(0x59f111f1), WordU32(0x923f82a4), WordU32(0xab1c5ed5),
99 WordU32(0xd807aa98), WordU32(0x12835b01), WordU32(0x243185be), WordU32(0x550c7dc3),
100 WordU32(0x72be5d74), WordU32(0x80deb1fe), WordU32(0x9bdc06a7), WordU32(0xc19bf174),
101 WordU32(0xe49b69c1), WordU32(0xefbe4786), WordU32(0x0fc19dc6), WordU32(0x240ca1cc),
102 WordU32(0x2de92c6f), WordU32(0x4a7484aa), WordU32(0x5cb0a9dc), WordU32(0x76f988da),
103 WordU32(0x983e5152), WordU32(0xa831c66d), WordU32(0xb00327c8), WordU32(0xbf597fc7),
104 WordU32(0xc6e00bf3), WordU32(0xd5a79147), WordU32(0x06ca6351), WordU32(0x14292967),
105 WordU32(0x27b70a85), WordU32(0x2e1b2138), WordU32(0x4d2c6dfc), WordU32(0x53380d13),
106 WordU32(0x650a7354), WordU32(0x766a0abb), WordU32(0x81c2c92e), WordU32(0x92722c85),
107 WordU32(0xa2bfe8a1), WordU32(0xa81a664b), WordU32(0xc24b8b70), WordU32(0xc76c51a3),
108 WordU32(0xd192e819), WordU32(0xd6990624), WordU32(0xf40e3585), WordU32(0x106aa070),
109 WordU32(0x19a4c116), WordU32(0x1e376c08), WordU32(0x2748774c), WordU32(0x34b0bcb5),
110 WordU32(0x391c0cb3), WordU32(0x4ed8aa4a), WordU32(0x5b9cca4f), WordU32(0x682e6ff3),
111 WordU32(0x748f82ee), WordU32(0x78a5636f), WordU32(0x84c87814), WordU32(0x8cc70208),
112 WordU32(0x90befffa), WordU32(0xa4506ceb), WordU32(0xbef9a3f7), WordU32(0xc67178f2),
113 ];
114
115 #[rustfmt::skip]
116 #[allow(clippy::unreadable_literal)]
117 const H0: [WordU32; 8] = [
119 WordU32(0x6a09e667), WordU32(0xbb67ae85), WordU32(0x3c6ef372), WordU32(0xa54ff53a),
120 WordU32(0x510e527f), WordU32(0x9b05688c), WordU32(0x1f83d9ab), WordU32(0x5be0cd19),
121 ];
122
123 fn big_sigma_0(x: WordU32) -> WordU32 {
125 (x.rotate_right(2)) ^ x.rotate_right(13) ^ x.rotate_right(22)
126 }
127
128 fn big_sigma_1(x: WordU32) -> WordU32 {
130 (x.rotate_right(6)) ^ x.rotate_right(11) ^ x.rotate_right(25)
131 }
132
133 fn small_sigma_0(x: WordU32) -> WordU32 {
135 (x.rotate_right(7)) ^ x.rotate_right(18) ^ (x >> WordU32(3))
136 }
137
138 fn small_sigma_1(x: WordU32) -> WordU32 {
140 (x.rotate_right(17)) ^ x.rotate_right(19) ^ (x >> WordU32(10))
141 }
142}
143
144#[derive(Clone, Debug)]
145pub struct Sha256 {
147 pub(crate) _state: State<WordU32, V256, SHA256_BLOCKSIZE, SHA256_OUTSIZE, N_CONSTS>,
148}
149
150impl Default for Sha256 {
151 fn default() -> Self {
152 Self::new()
153 }
154}
155
156impl Sha256 {
157 pub fn new() -> Self {
159 Self {
160 _state: State::<WordU32, V256, SHA256_BLOCKSIZE, SHA256_OUTSIZE, N_CONSTS>::_new(),
161 }
162 }
163
164 pub fn reset(&mut self) {
166 self._state._reset();
167 }
168
169 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
170 pub fn update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
172 self._state._update(data)
173 }
174
175 pub(crate) fn _finalize_internal(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
177 self._state._finalize(dest)
178 }
179
180 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
181 pub fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
183 let mut digest = [0u8; SHA256_OUTSIZE];
184 self._finalize_internal(&mut digest)?;
185
186 Ok(Digest::from(digest))
187 }
188
189 #[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
190 pub fn digest(data: &[u8]) -> Result<Digest, UnknownCryptoError> {
192 let mut ctx = Self::new();
193 ctx.update(data)?;
194 ctx.finalize()
195 }
196}
197
198impl crate::hazardous::mac::hmac::HmacHashFunction for Sha256 {
199 const _BLOCKSIZE: usize = SHA256_BLOCKSIZE;
201
202 const _OUTSIZE: usize = SHA256_OUTSIZE;
204
205 fn _new() -> Self {
207 Self::new()
208 }
209
210 fn _update(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
212 self.update(data)
213 }
214
215 fn _finalize(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
217 self._finalize_internal(dest)
218 }
219
220 fn _digest(data: &[u8], dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
222 let mut ctx = Self::new();
223 ctx.update(data)?;
224 ctx._finalize_internal(dest)
225 }
226
227 #[cfg(test)]
228 fn compare_state_to_other(&self, other: &Self) {
229 self._state.compare_state_to_other(&other._state);
230 }
231}
232
233#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
234#[cfg(feature = "safe_api")]
252impl io::Write for Sha256 {
253 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
264 self.update(bytes).map_err(io::Error::other)?;
265 Ok(bytes.len())
266 }
267
268 fn flush(&mut self) -> Result<(), io::Error> {
270 Ok(())
271 }
272}
273
274#[cfg(test)]
276mod public {
277 use super::*;
278
279 #[test]
280 fn test_default_equals_new() {
281 let new = Sha256::new();
282 let default = Sha256::default();
283 new._state.compare_state_to_other(&default._state);
284 }
285
286 #[test]
287 #[cfg(feature = "safe_api")]
288 fn test_debug_impl() {
289 let initial_state = Sha256::new();
290 let debug = format!("{:?}", initial_state);
291 let expected = "Sha256 { _state: State { working_state: [***OMITTED***], buffer: [***OMITTED***], leftover: 0, message_len: [WordU32(0), WordU32(0)], is_finalized: false } }";
292 assert_eq!(debug, expected);
293 }
294
295 mod test_streaming_interface {
296 use super::*;
297 use crate::test_framework::incremental_interface::*;
298
299 impl TestableStreamingContext<Digest> for Sha256 {
300 fn reset(&mut self) -> Result<(), UnknownCryptoError> {
301 self.reset();
302 Ok(())
303 }
304
305 fn update(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
306 self.update(input)
307 }
308
309 fn finalize(&mut self) -> Result<Digest, UnknownCryptoError> {
310 self.finalize()
311 }
312
313 fn one_shot(input: &[u8]) -> Result<Digest, UnknownCryptoError> {
314 Sha256::digest(input)
315 }
316
317 fn verify_result(expected: &Digest, input: &[u8]) -> Result<(), UnknownCryptoError> {
318 let actual: Digest = Self::one_shot(input)?;
319
320 if &actual == expected {
321 Ok(())
322 } else {
323 Err(UnknownCryptoError)
324 }
325 }
326
327 fn compare_states(state_1: &Sha256, state_2: &Sha256) {
328 state_1._state.compare_state_to_other(&state_2._state);
329 }
330 }
331
332 #[test]
333 fn default_consistency_tests() {
334 let initial_state: Sha256 = Sha256::new();
335
336 let test_runner = StreamingContextConsistencyTester::<Digest, Sha256>::new(
337 initial_state,
338 SHA256_BLOCKSIZE,
339 );
340 test_runner.run_all_tests();
341 }
342
343 #[quickcheck]
344 #[cfg(feature = "safe_api")]
345 fn prop_input_to_consistency(data: Vec<u8>) -> bool {
348 let initial_state: Sha256 = Sha256::new();
349
350 let test_runner = StreamingContextConsistencyTester::<Digest, Sha256>::new(
351 initial_state,
352 SHA256_BLOCKSIZE,
353 );
354 test_runner.run_all_tests_property(&data);
355 true
356 }
357 }
358
359 #[cfg(feature = "safe_api")]
360 mod test_io_impls {
361 use crate::hazardous::hash::sha2::sha256::Sha256;
362 use std::io::Write;
363
364 #[quickcheck]
365 fn prop_hasher_write_same_as_update(data: Vec<u8>) -> bool {
366 let mut hasher_a = Sha256::new();
367 let mut hasher_b = hasher_a.clone();
368
369 hasher_a.update(&data).unwrap();
370 hasher_b.write_all(&data).unwrap();
371
372 hasher_b.flush().unwrap();
374 hasher_a._state.compare_state_to_other(&hasher_b._state);
375
376 let hash_a = hasher_a.finalize().unwrap();
377 let hash_b = hasher_b.finalize().unwrap();
378
379 hasher_b.flush().unwrap();
381 hasher_a._state.compare_state_to_other(&hasher_b._state);
382
383 hash_a == hash_b
384 }
385 }
386}
387
388#[cfg(test)]
390mod private {
391 use super::*;
392
393 mod test_increment_mlen {
394 use super::*;
395
396 #[test]
397 fn test_mlen_increase_values() {
398 let mut context = Sha256::default();
399
400 context._state.increment_mlen(&WordU32::from(1u32));
401 assert_eq!(context._state.message_len[0], WordU32::from(0u32));
402 assert_eq!(context._state.message_len[1], WordU32::from(8u32));
403
404 context._state.increment_mlen(&WordU32::from(17u32));
405 assert_eq!(context._state.message_len[0], WordU32::from(0u32));
406 assert_eq!(context._state.message_len[1], WordU32::from(144u32));
407
408 context._state.increment_mlen(&WordU32::from(12u32));
409 assert_eq!(context._state.message_len[0], WordU32::from(0u32));
410 assert_eq!(context._state.message_len[1], WordU32::from(240u32));
411
412 context._state.increment_mlen(&WordU32::from(u32::MAX / 8));
414 assert_eq!(context._state.message_len[0], WordU32::from(1u32));
415 assert_eq!(context._state.message_len[1], WordU32::from(232u32));
416 }
417
418 #[test]
419 #[should_panic]
420 fn test_panic_on_second_overflow() {
421 let mut context = Sha256::default();
422 context._state.message_len = [WordU32::MAX, WordU32::from(u32::MAX - 7)];
423 context._state.increment_mlen(&WordU32::from(1u32));
426 }
427 }
428}