1use crate::{consts, sha256::compress256, sha512::compress512};
2use core::{fmt, slice::from_ref};
3use digest::{
4 block_buffer::Eager,
5 core_api::{
6 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, OutputSizeUser, TruncSide,
7 UpdateCore, VariableOutputCore,
8 },
9 typenum::{Unsigned, U128, U32, U64},
10 HashMarker, InvalidOutputSize, Output,
11};
12
13/// Core block-level SHA-256 hasher with variable output size.
14///
15/// Supports initialization only for 28 and 32 byte output sizes,
16/// i.e. 224 and 256 bits respectively.
17#[derive(Clone)]
18pub struct Sha256VarCore {
19 state: consts::State256,
20 block_len: u64,
21}
22
23impl HashMarker for Sha256VarCore {}
24
25impl BlockSizeUser for Sha256VarCore {
26 type BlockSize = U64;
27}
28
29impl BufferKindUser for Sha256VarCore {
30 type BufferKind = Eager;
31}
32
33impl UpdateCore for Sha256VarCore {
34 #[inline]
35 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
36 self.block_len += blocks.len() as u64;
37 compress256(&mut self.state, blocks);
38 }
39}
40
41impl OutputSizeUser for Sha256VarCore {
42 type OutputSize = U32;
43}
44
45impl VariableOutputCore for Sha256VarCore {
46 const TRUNC_SIDE: TruncSide = TruncSide::Left;
47
48 #[inline]
49 fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
50 let state = match output_size {
51 28 => consts::H256_224,
52 32 => consts::H256_256,
53 _ => return Err(InvalidOutputSize),
54 };
55 let block_len = 0;
56 Ok(Self { state, block_len })
57 }
58
59 #[inline]
60 fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
61 let bs = Self::BlockSize::U64;
62 let bit_len = 8 * (buffer.get_pos() as u64 + bs * self.block_len);
63 buffer.len64_padding_be(bit_len, |b| compress256(&mut self.state, from_ref(b)));
64
65 for (chunk, v) in out.chunks_exact_mut(4).zip(self.state.iter()) {
66 chunk.copy_from_slice(&v.to_be_bytes());
67 }
68 }
69}
70
71impl AlgorithmName for Sha256VarCore {
72 #[inline]
73 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 f.write_str(data:"Sha256")
75 }
76}
77
78impl fmt::Debug for Sha256VarCore {
79 #[inline]
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f.write_str(data:"Sha256VarCore { ... }")
82 }
83}
84
85/// Core block-level SHA-512 hasher with variable output size.
86///
87/// Supports initialization only for 28, 32, 48, and 64 byte output sizes,
88/// i.e. 224, 256, 384, and 512 bits respectively.
89#[derive(Clone)]
90pub struct Sha512VarCore {
91 state: consts::State512,
92 block_len: u128,
93}
94
95impl HashMarker for Sha512VarCore {}
96
97impl BlockSizeUser for Sha512VarCore {
98 type BlockSize = U128;
99}
100
101impl BufferKindUser for Sha512VarCore {
102 type BufferKind = Eager;
103}
104
105impl UpdateCore for Sha512VarCore {
106 #[inline]
107 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
108 self.block_len += blocks.len() as u128;
109 compress512(&mut self.state, blocks);
110 }
111}
112
113impl OutputSizeUser for Sha512VarCore {
114 type OutputSize = U64;
115}
116
117impl VariableOutputCore for Sha512VarCore {
118 const TRUNC_SIDE: TruncSide = TruncSide::Left;
119
120 #[inline]
121 fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
122 let state = match output_size {
123 28 => consts::H512_224,
124 32 => consts::H512_256,
125 48 => consts::H512_384,
126 64 => consts::H512_512,
127 _ => return Err(InvalidOutputSize),
128 };
129 let block_len = 0;
130 Ok(Self { state, block_len })
131 }
132
133 #[inline]
134 fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
135 let bs = Self::BlockSize::U64 as u128;
136 let bit_len = 8 * (buffer.get_pos() as u128 + bs * self.block_len);
137 buffer.len128_padding_be(bit_len, |b| compress512(&mut self.state, from_ref(b)));
138
139 for (chunk, v) in out.chunks_exact_mut(8).zip(self.state.iter()) {
140 chunk.copy_from_slice(&v.to_be_bytes());
141 }
142 }
143}
144
145impl AlgorithmName for Sha512VarCore {
146 #[inline]
147 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 f.write_str(data:"Sha512")
149 }
150}
151
152impl fmt::Debug for Sha512VarCore {
153 #[inline]
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 f.write_str(data:"Sha512VarCore { ... }")
156 }
157}
158