1use core::marker::PhantomData;
2
3use crate::traits::aligned::{Aligned, A4};
4use block_buffer::{BlockBuffer, Eager};
5use digest::{FixedOutput, Output, OutputSizeUser};
6
7use crate::{
8 peripherals::hashcrypt::Hashcrypt,
9 traits::{
10 digest::generic_array::{
11 typenum::{U20, U32, U64},
12 GenericArray,
13 },
14 digest::{Update },
15 },
16 typestates::init_state::Enabled,
17};
18
19type BlockSize = U64;
21mod sealed {
27 use crate::traits::digest::generic_array::ArrayLength;
28 pub trait OutputSize: ArrayLength<u8> {}
29
30 impl OutputSize for super::U20 {}
31 impl OutputSize for super::U32 {}
32}
33
34use sealed::OutputSize;
35
36pub struct Sha<'a, Size: OutputSize> {
37 buffer: Aligned<A4, BlockBuffer<BlockSize, Eager>>,
38 inner: &'a mut Hashcrypt<Enabled>,
39 len: u64,
40 size: PhantomData<Size>,
41}
42
43pub type Sha1<'a> = Sha<'a, U20>;
44pub type Sha256<'a> = Sha<'a, U32>;
45
46impl<'a, Size: OutputSize> Sha<'a, Size> {
47 pub fn new(hashcrypt: &'a mut Hashcrypt<Enabled>) -> Self {
48 let mut sha = Self {
49 buffer: Aligned(Default::default()),
50 inner: hashcrypt,
51 len: 0,
52 size: PhantomData,
53 };
54 sha.reset();
55 sha
56 }
57
58 pub fn into_inner(self) -> &'a mut Hashcrypt<Enabled> {
59 self.inner
60 }
61
62 pub fn reset(&mut self) {
63 self.buffer = Aligned(Default::default());
64 self.len = 0;
65
66 self.inner.ctrl.write(|w| w.new_hash().start());
70 match Size::to_usize() {
71 20 => self
72 .inner
73 .ctrl
74 .write(|w| w.new_hash().start().mode().sha1()),
75 32 => self
76 .inner
77 .ctrl
78 .write(|w| w.new_hash().start().mode().sha2_256()),
79 _ => unreachable!(),
80 }
81 }
82}
83
84impl<'a, Size: OutputSize> From<&'a mut Hashcrypt<Enabled>> for Sha<'a, Size> {
85 fn from(hashcrypt: &'a mut Hashcrypt<Enabled>) -> Self {
86 Sha::new(hashcrypt)
87 }
88}
89
90impl<Size: OutputSize> OutputSizeUser for Sha<'_, Size> {
93 type OutputSize = Size;
94}
95
96impl<Size: OutputSize> FixedOutput for Sha<'_, Size> {
97 fn finalize_into(mut self, out: &mut Output<Self>) {
98 self.finish();
99 for i in 0..Size::to_usize() / 4 {
101 out.as_mut_slice()[4 * i..4 * i + 4]
102 .copy_from_slice(&self.inner.raw.digest0[i].read().bits().to_be_bytes());
103 }
104 }
105}
106
107impl<Size: OutputSize> Update for Sha<'_, Size> {
108 fn update(&mut self, data: &[u8]) {
109 self.update(data.as_ref());
110 }
111}
112
113impl<Size: OutputSize> Sha<'_, Size> {
116 fn update(&mut self, data: &[u8]) {
117 self.len += (data.len() as u64) << 3;
119 let peripheral = &mut self.inner;
122 self.buffer.digest_blocks(data, |data| {
123 for b in data {
124 Self::process_block(peripheral, b)
125 }
126 });
127 }
128
129 fn process_block(peripheral: &mut Hashcrypt<Enabled>, input: &GenericArray<u8, BlockSize>) {
131 let input: Aligned<A4, GenericArray<u8, BlockSize>> = Aligned(*input);
133 let addr: u32 = &input[0] as *const _ as _;
134 assert_eq!(addr & 0x3, 0);
135 while peripheral.raw.status.read().waiting().is_not_waiting() {
136 continue;
137 }
138 peripheral.raw.memaddr.write(|w| unsafe { w.bits(addr) });
139 peripheral
140 .raw
141 .memctrl
142 .write(|w| unsafe { w.master().enabled().count().bits(1) });
143 }
144
145 fn finish(&mut self) {
146 let peripheral = &mut self.inner;
147 let l = self.len;
148 self.buffer
149 .len64_padding_be(l, |block| Self::process_block(peripheral, block));
150 while peripheral.raw.status.read().digest().is_not_ready() {
151 continue;
152 }
153 }
154}
155
156impl<Size: OutputSize> digest::Reset for Sha<'_, Size> {
157 fn reset(&mut self) {
158 self.reset();
159 }
160}