1 | use crate::{consts, sha256::compress256, sha512::compress512}; |
2 | use core::{fmt, slice::from_ref}; |
3 | use 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)] |
18 | pub struct Sha256VarCore { |
19 | state: consts::State256, |
20 | block_len: u64, |
21 | } |
22 | |
23 | impl HashMarker for Sha256VarCore {} |
24 | |
25 | impl BlockSizeUser for Sha256VarCore { |
26 | type BlockSize = U64; |
27 | } |
28 | |
29 | impl BufferKindUser for Sha256VarCore { |
30 | type BufferKind = Eager; |
31 | } |
32 | |
33 | impl 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 | |
41 | impl OutputSizeUser for Sha256VarCore { |
42 | type OutputSize = U32; |
43 | } |
44 | |
45 | impl 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 | |
71 | impl 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 | |
78 | impl 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)] |
90 | pub struct Sha512VarCore { |
91 | state: consts::State512, |
92 | block_len: u128, |
93 | } |
94 | |
95 | impl HashMarker for Sha512VarCore {} |
96 | |
97 | impl BlockSizeUser for Sha512VarCore { |
98 | type BlockSize = U128; |
99 | } |
100 | |
101 | impl BufferKindUser for Sha512VarCore { |
102 | type BufferKind = Eager; |
103 | } |
104 | |
105 | impl 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 | |
113 | impl OutputSizeUser for Sha512VarCore { |
114 | type OutputSize = U64; |
115 | } |
116 | |
117 | impl 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 | |
145 | impl 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 | |
152 | impl 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 | |