sha2/
block_api.rs

1use crate::consts;
2use core::fmt;
3use digest::{
4    HashMarker, InvalidOutputSize, Output,
5    array::Array,
6    block_api::{
7        AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, Eager, OutputSizeUser,
8        TruncSide, UpdateCore, VariableOutputCore,
9    },
10    crypto_common::hazmat::{DeserializeStateError, SerializableState, SerializedState},
11    typenum::{U32, U40, U64, U80, U128, Unsigned},
12};
13
14pub use crate::{sha256::compress256, sha512::compress512};
15
16/// Core block-level SHA-256 hasher with variable output size.
17///
18/// Supports initialization only for 28 and 32 byte output sizes,
19/// i.e. 224 and 256 bits respectively.
20#[derive(Clone)]
21pub struct Sha256VarCore {
22    state: consts::State256,
23    block_len: u64,
24}
25
26impl HashMarker for Sha256VarCore {}
27
28impl BlockSizeUser for Sha256VarCore {
29    type BlockSize = U64;
30}
31
32impl BufferKindUser for Sha256VarCore {
33    type BufferKind = Eager;
34}
35
36impl UpdateCore for Sha256VarCore {
37    #[inline]
38    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
39        self.block_len += blocks.len() as u64;
40        let blocks = Array::cast_slice_to_core(blocks);
41        compress256(&mut self.state, blocks);
42    }
43}
44
45impl OutputSizeUser for Sha256VarCore {
46    type OutputSize = U32;
47}
48
49impl VariableOutputCore for Sha256VarCore {
50    const TRUNC_SIDE: TruncSide = TruncSide::Left;
51
52    #[inline]
53    fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
54        let state = match output_size {
55            28 => consts::H256_224,
56            32 => consts::H256_256,
57            _ => return Err(InvalidOutputSize),
58        };
59        let block_len = 0;
60        Ok(Self { state, block_len })
61    }
62
63    #[inline]
64    fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
65        let bs = Self::BlockSize::U64;
66        let bit_len = 8 * (buffer.get_pos() as u64 + bs * self.block_len);
67        buffer.len64_padding_be(bit_len, |b| compress256(&mut self.state, &[b.0]));
68
69        for (chunk, v) in out.chunks_exact_mut(4).zip(self.state.iter()) {
70            chunk.copy_from_slice(&v.to_be_bytes());
71        }
72    }
73}
74
75impl AlgorithmName for Sha256VarCore {
76    #[inline]
77    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        f.write_str("Sha256")
79    }
80}
81
82impl fmt::Debug for Sha256VarCore {
83    #[inline]
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        f.write_str("Sha256VarCore { ... }")
86    }
87}
88
89impl Drop for Sha256VarCore {
90    fn drop(&mut self) {
91        #[cfg(feature = "zeroize")]
92        {
93            use digest::zeroize::Zeroize;
94            self.state.zeroize();
95            self.block_len.zeroize();
96        }
97    }
98}
99
100#[cfg(feature = "zeroize")]
101impl digest::zeroize::ZeroizeOnDrop for Sha256VarCore {}
102
103impl SerializableState for Sha256VarCore {
104    type SerializedStateSize = U40;
105
106    fn serialize(&self) -> SerializedState<Self> {
107        let mut serialized_state = SerializedState::<Self>::default();
108
109        for (val, chunk) in self.state.iter().zip(serialized_state.chunks_exact_mut(4)) {
110            chunk.copy_from_slice(&val.to_le_bytes());
111        }
112
113        serialized_state[32..].copy_from_slice(&self.block_len.to_le_bytes());
114        serialized_state
115    }
116
117    fn deserialize(
118        serialized_state: &SerializedState<Self>,
119    ) -> Result<Self, DeserializeStateError> {
120        let (serialized_state, serialized_block_len) = serialized_state.split::<U32>();
121
122        let mut state = consts::State256::default();
123        for (val, chunk) in state.iter_mut().zip(serialized_state.chunks_exact(4)) {
124            *val = u32::from_le_bytes(chunk.try_into().unwrap());
125        }
126
127        let block_len = u64::from_le_bytes(*serialized_block_len.as_ref());
128
129        Ok(Self { state, block_len })
130    }
131}
132
133/// Core block-level SHA-512 hasher with variable output size.
134///
135/// Supports initialization only for 28, 32, 48, and 64 byte output sizes,
136/// i.e. 224, 256, 384, and 512 bits respectively.
137#[derive(Clone)]
138pub struct Sha512VarCore {
139    state: consts::State512,
140    block_len: u128,
141}
142
143impl HashMarker for Sha512VarCore {}
144
145impl BlockSizeUser for Sha512VarCore {
146    type BlockSize = U128;
147}
148
149impl BufferKindUser for Sha512VarCore {
150    type BufferKind = Eager;
151}
152
153impl UpdateCore for Sha512VarCore {
154    #[inline]
155    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
156        self.block_len += blocks.len() as u128;
157        let blocks = Array::cast_slice_to_core(blocks);
158        compress512(&mut self.state, blocks);
159    }
160}
161
162impl OutputSizeUser for Sha512VarCore {
163    type OutputSize = U64;
164}
165
166impl VariableOutputCore for Sha512VarCore {
167    const TRUNC_SIDE: TruncSide = TruncSide::Left;
168
169    #[inline]
170    fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
171        let state = match output_size {
172            28 => consts::H512_224,
173            32 => consts::H512_256,
174            48 => consts::H512_384,
175            64 => consts::H512_512,
176            _ => return Err(InvalidOutputSize),
177        };
178        let block_len = 0;
179        Ok(Self { state, block_len })
180    }
181
182    #[inline]
183    fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
184        let bs = Self::BlockSize::U64 as u128;
185        let bit_len = 8 * (buffer.get_pos() as u128 + bs * self.block_len);
186        buffer.len128_padding_be(bit_len, |b| compress512(&mut self.state, &[b.0]));
187
188        for (chunk, v) in out.chunks_exact_mut(8).zip(self.state.iter()) {
189            chunk.copy_from_slice(&v.to_be_bytes());
190        }
191    }
192}
193
194impl AlgorithmName for Sha512VarCore {
195    #[inline]
196    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        f.write_str("Sha512")
198    }
199}
200
201impl fmt::Debug for Sha512VarCore {
202    #[inline]
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        f.write_str("Sha512VarCore { ... }")
205    }
206}
207
208impl Drop for Sha512VarCore {
209    fn drop(&mut self) {
210        #[cfg(feature = "zeroize")]
211        {
212            use digest::zeroize::Zeroize;
213            self.state.zeroize();
214            self.block_len.zeroize();
215        }
216    }
217}
218#[cfg(feature = "zeroize")]
219impl digest::zeroize::ZeroizeOnDrop for Sha512VarCore {}
220
221impl SerializableState for Sha512VarCore {
222    type SerializedStateSize = U80;
223
224    fn serialize(&self) -> SerializedState<Self> {
225        let mut serialized_state = SerializedState::<Self>::default();
226
227        for (val, chunk) in self.state.iter().zip(serialized_state.chunks_exact_mut(8)) {
228            chunk.copy_from_slice(&val.to_le_bytes());
229        }
230
231        serialized_state[64..].copy_from_slice(&self.block_len.to_le_bytes());
232
233        serialized_state
234    }
235
236    fn deserialize(
237        serialized_state: &SerializedState<Self>,
238    ) -> Result<Self, DeserializeStateError> {
239        let (serialized_state, serialized_block_len) = serialized_state.split::<U64>();
240
241        let mut state = consts::State512::default();
242        for (val, chunk) in state.iter_mut().zip(serialized_state.chunks_exact(8)) {
243            *val = u64::from_le_bytes(chunk.try_into().unwrap());
244        }
245
246        let block_len = u128::from_le_bytes(*serialized_block_len.as_ref());
247
248        Ok(Self { state, block_len })
249    }
250}