1use core::convert::Infallible;
36
37use crate::{
38 pac,
39 peripherals::HMAC,
40 reg_access::{AlignmentHelper, SocDependentEndianess},
41 system::{CryptoClockGuard, GenericPeripheralGuard, Peripheral as PeripheralEnable},
42};
43
44pub struct Hmac<'d> {
47 hmac: HMAC<'d>,
48 alignment_helper: AlignmentHelper<SocDependentEndianess>,
49 byte_written: usize,
50 next_command: NextCommand,
51 _guard: GenericPeripheralGuard<{ PeripheralEnable::Hmac as u8 }>,
52 _clock_guard: CryptoClockGuard,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub enum Error {
59 KeyPurposeMismatch,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq)]
66#[cfg_attr(feature = "defmt", derive(defmt::Format))]
67#[allow(clippy::enum_variant_names, reason = "peripheral is unstable")]
68pub enum HmacPurpose {
69 ToJtag = 6,
71 ToDs = 7,
74 ToUser = 8,
76 ToDsOrJtag = 5,
78}
79
80#[derive(Debug, Clone, Copy, PartialEq)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub enum KeyId {
84 Key0 = 0,
86 Key1 = 1,
88 Key2 = 2,
90 Key3 = 3,
92 Key4 = 4,
94 Key5 = 5,
96}
97
98enum NextCommand {
99 None,
100 MessageIng,
101 MessagePad,
102}
103
104impl<'d> Hmac<'d> {
105 pub fn new(hmac: HMAC<'d>) -> Self {
107 let clock_guard = CryptoClockGuard::new();
108 let guard = GenericPeripheralGuard::new();
109
110 Self {
111 hmac,
112 alignment_helper: AlignmentHelper::default(),
113 byte_written: 64,
114 next_command: NextCommand::None,
115 _guard: guard,
116 _clock_guard: clock_guard,
117 }
118 }
119
120 fn regs(&self) -> &pac::hmac::RegisterBlock {
121 self.hmac.register_block()
122 }
123
124 pub fn init(&mut self) {
130 self.regs().set_start().write(|w| w.set_start().set_bit());
131 self.alignment_helper.reset();
132 self.byte_written = 64;
133 self.next_command = NextCommand::None;
134 }
135
136 pub fn configure(&mut self, m: HmacPurpose, key_id: KeyId) -> nb::Result<(), Error> {
138 self.regs()
139 .set_para_purpose()
140 .write(|w| unsafe { w.purpose_set().bits(m as u8) });
141 self.regs()
142 .set_para_key()
143 .write(|w| unsafe { w.key_set().bits(key_id as u8) });
144 self.regs()
145 .set_para_finish()
146 .write(|w| w.set_para_end().set_bit());
147
148 if self.regs().query_error().read().query_check().bit_is_set() {
149 return Err(nb::Error::Other(Error::KeyPurposeMismatch));
150 }
151
152 Ok(())
153 }
154
155 pub fn update<'a>(&mut self, msg: &'a [u8]) -> nb::Result<&'a [u8], Infallible> {
159 if self.is_busy() {
160 return Err(nb::Error::WouldBlock);
161 }
162
163 self.next_command();
164
165 let remaining = self.write_data(msg).unwrap();
166
167 Ok(remaining)
168 }
169
170 pub fn finalize(&mut self, output: &mut [u8]) -> nb::Result<(), Infallible> {
172 if self.is_busy() {
173 return Err(nb::Error::WouldBlock);
174 }
175
176 self.next_command();
177
178 let msg_len = self.byte_written as u64;
179
180 nb::block!(self.write_data(&[0x80])).unwrap();
181 nb::block!(self.flush_data()).unwrap();
182 self.next_command();
183 debug_assert!(self.byte_written.is_multiple_of(4));
184
185 self.padding(msg_len);
186
187 if msg_len < 64 + 56 {
189 self.regs()
190 .one_block()
191 .write(|w| w.set_one_block().set_bit());
192
193 while self.is_busy() {}
194 }
195
196 self.alignment_helper.volatile_read_regset(
197 #[cfg(esp32s2)]
198 self.regs().rd_result_(0).as_ptr(),
199 #[cfg(not(esp32s2))]
200 self.regs().rd_result_mem(0).as_ptr(),
201 output,
202 core::cmp::min(output.len(), 32),
203 );
204
205 self.regs()
206 .set_result_finish()
207 .write(|w| w.set_result_end().set_bit());
208 self.byte_written = 64;
209 self.next_command = NextCommand::None;
210 Ok(())
211 }
212
213 fn is_busy(&mut self) -> bool {
214 self.regs().query_busy().read().busy_state().bit_is_set()
215 }
216
217 fn next_command(&mut self) {
218 match self.next_command {
219 NextCommand::MessageIng => {
220 self.regs()
221 .set_message_ing()
222 .write(|w| w.set_text_ing().set_bit());
223 }
224 NextCommand::MessagePad => {
225 self.regs()
226 .set_message_pad()
227 .write(|w| w.set_text_pad().set_bit());
228 }
229 NextCommand::None => {}
230 }
231 self.next_command = NextCommand::None;
232 }
233
234 fn write_data<'a>(&mut self, incoming: &'a [u8]) -> nb::Result<&'a [u8], Infallible> {
235 let (remaining, bound_reached) = self.alignment_helper.aligned_volatile_copy(
236 #[cfg(esp32s2)]
237 self.regs().wr_message_(0).as_ptr(),
238 #[cfg(not(esp32s2))]
239 self.regs().wr_message_mem(0).as_ptr(),
240 incoming,
241 64,
242 self.byte_written % 64,
243 );
244
245 self.byte_written = self
246 .byte_written
247 .wrapping_add(incoming.len() - remaining.len());
248
249 if bound_reached {
250 self.regs()
251 .set_message_one()
252 .write(|w| w.set_text_one().set_bit());
253
254 if remaining.len() >= 56 {
255 self.next_command = NextCommand::MessageIng;
256 } else {
257 self.next_command = NextCommand::MessagePad;
258 }
259 }
260
261 Ok(remaining)
262 }
263
264 fn flush_data(&mut self) -> nb::Result<(), Infallible> {
265 if self.is_busy() {
266 return Err(nb::Error::WouldBlock);
267 }
268
269 let flushed = self.alignment_helper.flush_to(
270 #[cfg(esp32s2)]
271 self.regs().wr_message_(0).as_ptr(),
272 #[cfg(not(esp32s2))]
273 self.regs().wr_message_mem(0).as_ptr(),
274 self.byte_written % 64,
275 );
276
277 self.byte_written = self.byte_written.wrapping_add(flushed);
278 if flushed > 0 && self.byte_written.is_multiple_of(64) {
279 self.regs()
280 .set_message_one()
281 .write(|w| w.set_text_one().set_bit());
282 while self.is_busy() {}
283 self.next_command = NextCommand::MessagePad;
284 }
285
286 Ok(())
287 }
288
289 fn padding(&mut self, msg_len: u64) {
290 let mod_cursor = self.byte_written % 64;
291
292 if mod_cursor > 56 {
294 let pad_len = 64 - mod_cursor;
295 self.alignment_helper.volatile_write(
296 #[cfg(esp32s2)]
297 self.regs().wr_message_(0).as_ptr(),
298 #[cfg(not(esp32s2))]
299 self.regs().wr_message_mem(0).as_ptr(),
300 0_u8,
301 pad_len,
302 mod_cursor,
303 );
304 self.regs()
305 .set_message_one()
306 .write(|w| w.set_text_one().set_bit());
307 self.byte_written = self.byte_written.wrapping_add(pad_len);
308 debug_assert!(self.byte_written.is_multiple_of(64));
309 while self.is_busy() {}
310 self.next_command = NextCommand::MessagePad;
311 self.next_command();
312 }
313
314 let mod_cursor = self.byte_written % 64;
315 let pad_len = 64 - mod_cursor - core::mem::size_of::<u64>();
316
317 self.alignment_helper.volatile_write(
318 #[cfg(esp32s2)]
319 self.regs().wr_message_(0).as_ptr(),
320 #[cfg(not(esp32s2))]
321 self.regs().wr_message_mem(0).as_ptr(),
322 0_u8,
323 pad_len,
324 mod_cursor,
325 );
326
327 self.byte_written = self.byte_written.wrapping_add(pad_len);
328
329 assert_eq!(self.byte_written % 64, 64 - core::mem::size_of::<u64>());
330
331 let len_mem = (msg_len * 8).to_be_bytes();
333
334 self.alignment_helper.aligned_volatile_copy(
335 #[cfg(esp32s2)]
336 self.regs().wr_message_(0).as_ptr(),
337 #[cfg(not(esp32s2))]
338 self.regs().wr_message_mem(0).as_ptr(),
339 &len_mem,
340 64,
341 64 - core::mem::size_of::<u64>(),
342 );
343 self.regs()
344 .set_message_one()
345 .write(|w| w.set_text_one().set_bit());
346
347 while self.is_busy() {}
348 }
349}