Merge pull request #2528 from caleb-garrett/hash
STM32 Hash Accelerator
This commit is contained in:
		
						commit
						8c82d1bcbc
					
				| @ -1056,6 +1056,7 @@ fn main() { | |||||||
|         (("dac", "CH1"), quote!(crate::dac::DacDma1)), |         (("dac", "CH1"), quote!(crate::dac::DacDma1)), | ||||||
|         (("dac", "CH2"), quote!(crate::dac::DacDma2)), |         (("dac", "CH2"), quote!(crate::dac::DacDma2)), | ||||||
|         (("timer", "UP"), quote!(crate::timer::UpDma)), |         (("timer", "UP"), quote!(crate::timer::UpDma)), | ||||||
|  |         (("hash", "IN"), quote!(crate::hash::Dma)), | ||||||
|         (("timer", "CH1"), quote!(crate::timer::Ch1Dma)), |         (("timer", "CH1"), quote!(crate::timer::Ch1Dma)), | ||||||
|         (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), |         (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), | ||||||
|         (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), |         (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), | ||||||
|  | |||||||
							
								
								
									
										545
									
								
								embassy-stm32/src/hash/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										545
									
								
								embassy-stm32/src/hash/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,545 @@ | |||||||
|  | //! Hash generator (HASH)
 | ||||||
|  | use core::cmp::min; | ||||||
|  | #[cfg(hash_v2)] | ||||||
|  | use core::future::poll_fn; | ||||||
|  | use core::marker::PhantomData; | ||||||
|  | #[cfg(hash_v2)] | ||||||
|  | use core::ptr; | ||||||
|  | #[cfg(hash_v2)] | ||||||
|  | use core::task::Poll; | ||||||
|  | 
 | ||||||
|  | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||||
|  | use embassy_sync::waitqueue::AtomicWaker; | ||||||
|  | use stm32_metapac::hash::regs::*; | ||||||
|  | 
 | ||||||
|  | use crate::dma::NoDma; | ||||||
|  | #[cfg(hash_v2)] | ||||||
|  | use crate::dma::Transfer; | ||||||
|  | use crate::interrupt::typelevel::Interrupt; | ||||||
|  | use crate::peripherals::HASH; | ||||||
|  | use crate::rcc::sealed::RccPeripheral; | ||||||
|  | use crate::{interrupt, pac, peripherals, Peripheral}; | ||||||
|  | 
 | ||||||
|  | #[cfg(hash_v1)] | ||||||
|  | const NUM_CONTEXT_REGS: usize = 51; | ||||||
|  | #[cfg(hash_v3)] | ||||||
|  | const NUM_CONTEXT_REGS: usize = 103; | ||||||
|  | #[cfg(any(hash_v2, hash_v4))] | ||||||
|  | const NUM_CONTEXT_REGS: usize = 54; | ||||||
|  | 
 | ||||||
|  | const HASH_BUFFER_LEN: usize = 132; | ||||||
|  | const DIGEST_BLOCK_SIZE: usize = 128; | ||||||
|  | 
 | ||||||
|  | static HASH_WAKER: AtomicWaker = AtomicWaker::new(); | ||||||
|  | 
 | ||||||
|  | /// HASH interrupt handler.
 | ||||||
|  | pub struct InterruptHandler<T: Instance> { | ||||||
|  |     _phantom: PhantomData<T>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||||||
|  |     unsafe fn on_interrupt() { | ||||||
|  |         let bits = T::regs().sr().read(); | ||||||
|  |         if bits.dinis() { | ||||||
|  |             T::regs().imr().modify(|reg| reg.set_dinie(false)); | ||||||
|  |             HASH_WAKER.wake(); | ||||||
|  |         } | ||||||
|  |         if bits.dcis() { | ||||||
|  |             T::regs().imr().modify(|reg| reg.set_dcie(false)); | ||||||
|  |             HASH_WAKER.wake(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ///Hash algorithm selection
 | ||||||
|  | #[derive(Clone, Copy, PartialEq)] | ||||||
|  | pub enum Algorithm { | ||||||
|  |     /// SHA-1 Algorithm
 | ||||||
|  |     SHA1 = 0, | ||||||
|  | 
 | ||||||
|  |     #[cfg(any(hash_v1, hash_v2, hash_v4))] | ||||||
|  |     /// MD5 Algorithm
 | ||||||
|  |     MD5 = 1, | ||||||
|  | 
 | ||||||
|  |     /// SHA-224 Algorithm
 | ||||||
|  |     SHA224 = 2, | ||||||
|  | 
 | ||||||
|  |     /// SHA-256 Algorithm
 | ||||||
|  |     SHA256 = 3, | ||||||
|  | 
 | ||||||
|  |     #[cfg(hash_v3)] | ||||||
|  |     /// SHA-384 Algorithm
 | ||||||
|  |     SHA384 = 12, | ||||||
|  | 
 | ||||||
|  |     #[cfg(hash_v3)] | ||||||
|  |     /// SHA-512/224 Algorithm
 | ||||||
|  |     SHA512_224 = 13, | ||||||
|  | 
 | ||||||
|  |     #[cfg(hash_v3)] | ||||||
|  |     /// SHA-512/256 Algorithm
 | ||||||
|  |     SHA512_256 = 14, | ||||||
|  | 
 | ||||||
|  |     #[cfg(hash_v3)] | ||||||
|  |     /// SHA-256 Algorithm
 | ||||||
|  |     SHA512 = 15, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Input data width selection
 | ||||||
|  | #[repr(u8)] | ||||||
|  | #[derive(Clone, Copy)] | ||||||
|  | pub enum DataType { | ||||||
|  |     ///32-bit data, no data is swapped.
 | ||||||
|  |     Width32 = 0, | ||||||
|  |     ///16-bit data, each half-word is swapped.
 | ||||||
|  |     Width16 = 1, | ||||||
|  |     ///8-bit data, all bytes are swapped.
 | ||||||
|  |     Width8 = 2, | ||||||
|  |     ///1-bit data, all bits are swapped.
 | ||||||
|  |     Width1 = 3, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Stores the state of the HASH peripheral for suspending/resuming
 | ||||||
|  | /// digest calculation.
 | ||||||
|  | pub struct Context { | ||||||
|  |     first_word_sent: bool, | ||||||
|  |     buffer: [u8; HASH_BUFFER_LEN], | ||||||
|  |     buflen: usize, | ||||||
|  |     algo: Algorithm, | ||||||
|  |     format: DataType, | ||||||
|  |     imr: u32, | ||||||
|  |     str: u32, | ||||||
|  |     cr: u32, | ||||||
|  |     csr: [u32; NUM_CONTEXT_REGS], | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// HASH driver.
 | ||||||
|  | pub struct Hash<'d, T: Instance, D = NoDma> { | ||||||
|  |     _peripheral: PeripheralRef<'d, T>, | ||||||
|  |     #[allow(dead_code)] | ||||||
|  |     dma: PeripheralRef<'d, D>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'d, T: Instance, D> Hash<'d, T, D> { | ||||||
|  |     /// Instantiates, resets, and enables the HASH peripheral.
 | ||||||
|  |     pub fn new( | ||||||
|  |         peripheral: impl Peripheral<P = T> + 'd, | ||||||
|  |         dma: impl Peripheral<P = D> + 'd, | ||||||
|  |         _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||||||
|  |     ) -> Self { | ||||||
|  |         HASH::enable_and_reset(); | ||||||
|  |         into_ref!(peripheral, dma); | ||||||
|  |         let instance = Self { | ||||||
|  |             _peripheral: peripheral, | ||||||
|  |             dma: dma, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         T::Interrupt::unpend(); | ||||||
|  |         unsafe { T::Interrupt::enable() }; | ||||||
|  | 
 | ||||||
|  |         instance | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Starts computation of a new hash and returns the saved peripheral state.
 | ||||||
|  |     pub fn start(&mut self, algorithm: Algorithm, format: DataType) -> Context { | ||||||
|  |         // Define a context for this new computation.
 | ||||||
|  |         let mut ctx = Context { | ||||||
|  |             first_word_sent: false, | ||||||
|  |             buffer: [0; HASH_BUFFER_LEN], | ||||||
|  |             buflen: 0, | ||||||
|  |             algo: algorithm, | ||||||
|  |             format: format, | ||||||
|  |             imr: 0, | ||||||
|  |             str: 0, | ||||||
|  |             cr: 0, | ||||||
|  |             csr: [0; NUM_CONTEXT_REGS], | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         // Set the data type in the peripheral.
 | ||||||
|  |         T::regs().cr().modify(|w| w.set_datatype(ctx.format as u8)); | ||||||
|  | 
 | ||||||
|  |         // Select the algorithm.
 | ||||||
|  |         #[cfg(hash_v1)] | ||||||
|  |         if ctx.algo == Algorithm::MD5 { | ||||||
|  |             T::regs().cr().modify(|w| w.set_algo(true)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         #[cfg(hash_v2)] | ||||||
|  |         { | ||||||
|  |             // Select the algorithm.
 | ||||||
|  |             let mut algo0 = false; | ||||||
|  |             let mut algo1 = false; | ||||||
|  |             if ctx.algo == Algorithm::MD5 || ctx.algo == Algorithm::SHA256 { | ||||||
|  |                 algo0 = true; | ||||||
|  |             } | ||||||
|  |             if ctx.algo == Algorithm::SHA224 || ctx.algo == Algorithm::SHA256 { | ||||||
|  |                 algo1 = true; | ||||||
|  |             } | ||||||
|  |             T::regs().cr().modify(|w| w.set_algo0(algo0)); | ||||||
|  |             T::regs().cr().modify(|w| w.set_algo1(algo1)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         #[cfg(any(hash_v3, hash_v4))] | ||||||
|  |         T::regs().cr().modify(|w| w.set_algo(ctx.algo as u8)); | ||||||
|  | 
 | ||||||
|  |         T::regs().cr().modify(|w| w.set_init(true)); | ||||||
|  | 
 | ||||||
|  |         // Store and return the state of the peripheral.
 | ||||||
|  |         self.store_context(&mut ctx); | ||||||
|  |         ctx | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Restores the peripheral state using the given context,
 | ||||||
|  |     /// then updates the state with the provided data.
 | ||||||
|  |     /// Peripheral state is saved upon return.
 | ||||||
|  |     pub fn update_blocking(&mut self, ctx: &mut Context, input: &[u8]) { | ||||||
|  |         let mut data_waiting = input.len() + ctx.buflen; | ||||||
|  |         if data_waiting < DIGEST_BLOCK_SIZE || (data_waiting < ctx.buffer.len() && !ctx.first_word_sent) { | ||||||
|  |             // There isn't enough data to digest a block, so append it to the buffer.
 | ||||||
|  |             ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); | ||||||
|  |             ctx.buflen += input.len(); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Restore the peripheral state.
 | ||||||
|  |         self.load_context(&ctx); | ||||||
|  | 
 | ||||||
|  |         let mut ilen_remaining = input.len(); | ||||||
|  |         let mut input_start = 0; | ||||||
|  | 
 | ||||||
|  |         // Handle first block.
 | ||||||
|  |         if !ctx.first_word_sent { | ||||||
|  |             let empty_len = ctx.buffer.len() - ctx.buflen; | ||||||
|  |             let copy_len = min(empty_len, ilen_remaining); | ||||||
|  |             // Fill the buffer.
 | ||||||
|  |             if copy_len > 0 { | ||||||
|  |                 ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[0..copy_len]); | ||||||
|  |                 ctx.buflen += copy_len; | ||||||
|  |                 ilen_remaining -= copy_len; | ||||||
|  |                 input_start += copy_len; | ||||||
|  |             } | ||||||
|  |             self.accumulate_blocking(ctx.buffer.as_slice()); | ||||||
|  |             data_waiting -= ctx.buflen; | ||||||
|  |             ctx.buflen = 0; | ||||||
|  |             ctx.first_word_sent = true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if data_waiting < DIGEST_BLOCK_SIZE { | ||||||
|  |             // There isn't enough data remaining to process another block, so store it.
 | ||||||
|  |             ctx.buffer[0..ilen_remaining].copy_from_slice(&input[input_start..input_start + ilen_remaining]); | ||||||
|  |             ctx.buflen += ilen_remaining; | ||||||
|  |         } else { | ||||||
|  |             // First ingest the data in the buffer.
 | ||||||
|  |             let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; | ||||||
|  |             if empty_len > 0 { | ||||||
|  |                 let copy_len = min(empty_len, ilen_remaining); | ||||||
|  |                 ctx.buffer[ctx.buflen..ctx.buflen + copy_len] | ||||||
|  |                     .copy_from_slice(&input[input_start..input_start + copy_len]); | ||||||
|  |                 ctx.buflen += copy_len; | ||||||
|  |                 ilen_remaining -= copy_len; | ||||||
|  |                 input_start += copy_len; | ||||||
|  |             } | ||||||
|  |             self.accumulate_blocking(&ctx.buffer[0..DIGEST_BLOCK_SIZE]); | ||||||
|  |             ctx.buflen = 0; | ||||||
|  | 
 | ||||||
|  |             // Move any extra data to the now-empty buffer.
 | ||||||
|  |             let leftovers = ilen_remaining % 64; | ||||||
|  |             if leftovers > 0 { | ||||||
|  |                 ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); | ||||||
|  |                 ctx.buflen += leftovers; | ||||||
|  |                 ilen_remaining -= leftovers; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Hash the remaining data.
 | ||||||
|  |             self.accumulate_blocking(&input[input_start..input_start + ilen_remaining]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Save the peripheral context.
 | ||||||
|  |         self.store_context(ctx); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Restores the peripheral state using the given context,
 | ||||||
|  |     /// then updates the state with the provided data.
 | ||||||
|  |     /// Peripheral state is saved upon return.
 | ||||||
|  |     #[cfg(hash_v2)] | ||||||
|  |     pub async fn update(&mut self, ctx: &mut Context, input: &[u8]) | ||||||
|  |     where | ||||||
|  |         D: crate::hash::Dma<T>, | ||||||
|  |     { | ||||||
|  |         let data_waiting = input.len() + ctx.buflen; | ||||||
|  |         if data_waiting < DIGEST_BLOCK_SIZE { | ||||||
|  |             // There isn't enough data to digest a block, so append it to the buffer.
 | ||||||
|  |             ctx.buffer[ctx.buflen..ctx.buflen + input.len()].copy_from_slice(input); | ||||||
|  |             ctx.buflen += input.len(); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Restore the peripheral state.
 | ||||||
|  |         self.load_context(&ctx); | ||||||
|  | 
 | ||||||
|  |         // Enable multiple DMA transfers.
 | ||||||
|  |         T::regs().cr().modify(|w| w.set_mdmat(true)); | ||||||
|  | 
 | ||||||
|  |         let mut ilen_remaining = input.len(); | ||||||
|  |         let mut input_start = 0; | ||||||
|  | 
 | ||||||
|  |         // First ingest the data in the buffer.
 | ||||||
|  |         let empty_len = DIGEST_BLOCK_SIZE - ctx.buflen; | ||||||
|  |         if empty_len > 0 { | ||||||
|  |             let copy_len = min(empty_len, ilen_remaining); | ||||||
|  |             ctx.buffer[ctx.buflen..ctx.buflen + copy_len].copy_from_slice(&input[input_start..input_start + copy_len]); | ||||||
|  |             ctx.buflen += copy_len; | ||||||
|  |             ilen_remaining -= copy_len; | ||||||
|  |             input_start += copy_len; | ||||||
|  |         } | ||||||
|  |         self.accumulate(&ctx.buffer[..DIGEST_BLOCK_SIZE]).await; | ||||||
|  |         ctx.buflen = 0; | ||||||
|  | 
 | ||||||
|  |         // Move any extra data to the now-empty buffer.
 | ||||||
|  |         let leftovers = ilen_remaining % DIGEST_BLOCK_SIZE; | ||||||
|  |         if leftovers > 0 { | ||||||
|  |             assert!(ilen_remaining >= leftovers); | ||||||
|  |             ctx.buffer[0..leftovers].copy_from_slice(&input[input.len() - leftovers..input.len()]); | ||||||
|  |             ctx.buflen += leftovers; | ||||||
|  |             ilen_remaining -= leftovers; | ||||||
|  |         } else { | ||||||
|  |             ctx.buffer | ||||||
|  |                 .copy_from_slice(&input[input.len() - DIGEST_BLOCK_SIZE..input.len()]); | ||||||
|  |             ctx.buflen += DIGEST_BLOCK_SIZE; | ||||||
|  |             ilen_remaining -= DIGEST_BLOCK_SIZE; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Hash the remaining data.
 | ||||||
|  |         self.accumulate(&input[input_start..input_start + ilen_remaining]).await; | ||||||
|  | 
 | ||||||
|  |         // Save the peripheral context.
 | ||||||
|  |         self.store_context(ctx); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Computes a digest for the given context.
 | ||||||
|  |     /// The digest buffer must be large enough to accomodate a digest for the selected algorithm.
 | ||||||
|  |     /// The largest returned digest size is 128 bytes for SHA-512.
 | ||||||
|  |     /// Panics if the supplied digest buffer is too short.
 | ||||||
|  |     pub fn finish_blocking(&mut self, mut ctx: Context, digest: &mut [u8]) -> usize { | ||||||
|  |         // Restore the peripheral state.
 | ||||||
|  |         self.load_context(&ctx); | ||||||
|  | 
 | ||||||
|  |         // Hash the leftover bytes, if any.
 | ||||||
|  |         self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]); | ||||||
|  |         ctx.buflen = 0; | ||||||
|  | 
 | ||||||
|  |         //Start the digest calculation.
 | ||||||
|  |         T::regs().str().write(|w| w.set_dcal(true)); | ||||||
|  | 
 | ||||||
|  |         // Block waiting for digest.
 | ||||||
|  |         while !T::regs().sr().read().dcis() {} | ||||||
|  | 
 | ||||||
|  |         // Return the digest.
 | ||||||
|  |         let digest_words = match ctx.algo { | ||||||
|  |             Algorithm::SHA1 => 5, | ||||||
|  |             #[cfg(any(hash_v1, hash_v2, hash_v4))] | ||||||
|  |             Algorithm::MD5 => 4, | ||||||
|  |             Algorithm::SHA224 => 7, | ||||||
|  |             Algorithm::SHA256 => 8, | ||||||
|  |             #[cfg(hash_v3)] | ||||||
|  |             Algorithm::SHA384 => 12, | ||||||
|  |             #[cfg(hash_v3)] | ||||||
|  |             Algorithm::SHA512_224 => 7, | ||||||
|  |             #[cfg(hash_v3)] | ||||||
|  |             Algorithm::SHA512_256 => 8, | ||||||
|  |             #[cfg(hash_v3)] | ||||||
|  |             Algorithm::SHA512 => 16, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         let digest_len_bytes = digest_words * 4; | ||||||
|  |         // Panics if the supplied digest buffer is too short.
 | ||||||
|  |         if digest.len() < digest_len_bytes { | ||||||
|  |             panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let mut i = 0; | ||||||
|  |         while i < digest_words { | ||||||
|  |             let word = T::regs().hr(i).read(); | ||||||
|  |             digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); | ||||||
|  |             i += 1; | ||||||
|  |         } | ||||||
|  |         digest_len_bytes | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Computes a digest for the given context.
 | ||||||
|  |     /// The digest buffer must be large enough to accomodate a digest for the selected algorithm.
 | ||||||
|  |     /// The largest returned digest size is 128 bytes for SHA-512.
 | ||||||
|  |     /// Panics if the supplied digest buffer is too short.
 | ||||||
|  |     #[cfg(hash_v2)] | ||||||
|  |     pub async fn finish(&mut self, mut ctx: Context, digest: &mut [u8]) -> usize | ||||||
|  |     where | ||||||
|  |         D: crate::hash::Dma<T>, | ||||||
|  |     { | ||||||
|  |         // Restore the peripheral state.
 | ||||||
|  |         self.load_context(&ctx); | ||||||
|  | 
 | ||||||
|  |         // Must be cleared prior to the last DMA transfer.
 | ||||||
|  |         T::regs().cr().modify(|w| w.set_mdmat(false)); | ||||||
|  | 
 | ||||||
|  |         // Hash the leftover bytes, if any.
 | ||||||
|  |         self.accumulate(&ctx.buffer[0..ctx.buflen]).await; | ||||||
|  |         ctx.buflen = 0; | ||||||
|  | 
 | ||||||
|  |         // Wait for completion.
 | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             // Check if already done.
 | ||||||
|  |             let bits = T::regs().sr().read(); | ||||||
|  |             if bits.dcis() { | ||||||
|  |                 return Poll::Ready(()); | ||||||
|  |             } | ||||||
|  |             // Register waker, then enable interrupts.
 | ||||||
|  |             HASH_WAKER.register(cx.waker()); | ||||||
|  |             T::regs().imr().modify(|reg| reg.set_dcie(true)); | ||||||
|  |             // Check for completion.
 | ||||||
|  |             let bits = T::regs().sr().read(); | ||||||
|  |             if bits.dcis() { | ||||||
|  |                 Poll::Ready(()) | ||||||
|  |             } else { | ||||||
|  |                 Poll::Pending | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await; | ||||||
|  | 
 | ||||||
|  |         // Return the digest.
 | ||||||
|  |         let digest_words = match ctx.algo { | ||||||
|  |             Algorithm::SHA1 => 5, | ||||||
|  |             #[cfg(any(hash_v1, hash_v2, hash_v4))] | ||||||
|  |             Algorithm::MD5 => 4, | ||||||
|  |             Algorithm::SHA224 => 7, | ||||||
|  |             Algorithm::SHA256 => 8, | ||||||
|  |             #[cfg(hash_v3)] | ||||||
|  |             Algorithm::SHA384 => 12, | ||||||
|  |             #[cfg(hash_v3)] | ||||||
|  |             Algorithm::SHA512_224 => 7, | ||||||
|  |             #[cfg(hash_v3)] | ||||||
|  |             Algorithm::SHA512_256 => 8, | ||||||
|  |             #[cfg(hash_v3)] | ||||||
|  |             Algorithm::SHA512 => 16, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         let digest_len_bytes = digest_words * 4; | ||||||
|  |         // Panics if the supplied digest buffer is too short.
 | ||||||
|  |         if digest.len() < digest_len_bytes { | ||||||
|  |             panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let mut i = 0; | ||||||
|  |         while i < digest_words { | ||||||
|  |             let word = T::regs().hr(i).read(); | ||||||
|  |             digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); | ||||||
|  |             i += 1; | ||||||
|  |         } | ||||||
|  |         digest_len_bytes | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Push data into the hash core.
 | ||||||
|  |     fn accumulate_blocking(&mut self, input: &[u8]) { | ||||||
|  |         // Set the number of valid bits.
 | ||||||
|  |         let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; | ||||||
|  |         T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); | ||||||
|  | 
 | ||||||
|  |         let mut i = 0; | ||||||
|  |         while i < input.len() { | ||||||
|  |             let mut word: [u8; 4] = [0; 4]; | ||||||
|  |             let copy_idx = min(i + 4, input.len()); | ||||||
|  |             word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); | ||||||
|  |             T::regs().din().write_value(u32::from_ne_bytes(word)); | ||||||
|  |             i += 4; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Push data into the hash core.
 | ||||||
|  |     #[cfg(hash_v2)] | ||||||
|  |     async fn accumulate(&mut self, input: &[u8]) | ||||||
|  |     where | ||||||
|  |         D: crate::hash::Dma<T>, | ||||||
|  |     { | ||||||
|  |         // Ignore an input length of 0.
 | ||||||
|  |         if input.len() == 0 { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Set the number of valid bits.
 | ||||||
|  |         let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; | ||||||
|  |         T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); | ||||||
|  | 
 | ||||||
|  |         // Configure DMA to transfer input to hash core.
 | ||||||
|  |         let dma_request = self.dma.request(); | ||||||
|  |         let dst_ptr = T::regs().din().as_ptr(); | ||||||
|  |         let mut num_words = input.len() / 4; | ||||||
|  |         if input.len() % 4 > 0 { | ||||||
|  |             num_words += 1; | ||||||
|  |         } | ||||||
|  |         let src_ptr = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); | ||||||
|  |         let dma_transfer = | ||||||
|  |             unsafe { Transfer::new_write_raw(&mut self.dma, dma_request, src_ptr, dst_ptr, Default::default()) }; | ||||||
|  |         T::regs().cr().modify(|w| w.set_dmae(true)); | ||||||
|  | 
 | ||||||
|  |         // Wait for the transfer to complete.
 | ||||||
|  |         dma_transfer.await; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Save the peripheral state to a context.
 | ||||||
|  |     fn store_context(&mut self, ctx: &mut Context) { | ||||||
|  |         // Block waiting for data in ready.
 | ||||||
|  |         while !T::regs().sr().read().dinis() {} | ||||||
|  | 
 | ||||||
|  |         // Store peripheral context.
 | ||||||
|  |         ctx.imr = T::regs().imr().read().0; | ||||||
|  |         ctx.str = T::regs().str().read().0; | ||||||
|  |         ctx.cr = T::regs().cr().read().0; | ||||||
|  |         let mut i = 0; | ||||||
|  |         while i < NUM_CONTEXT_REGS { | ||||||
|  |             ctx.csr[i] = T::regs().csr(i).read(); | ||||||
|  |             i += 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Restore the peripheral state from a context.
 | ||||||
|  |     fn load_context(&mut self, ctx: &Context) { | ||||||
|  |         // Restore the peripheral state from the context.
 | ||||||
|  |         T::regs().imr().write_value(Imr { 0: ctx.imr }); | ||||||
|  |         T::regs().str().write_value(Str { 0: ctx.str }); | ||||||
|  |         T::regs().cr().write_value(Cr { 0: ctx.cr }); | ||||||
|  |         T::regs().cr().modify(|w| w.set_init(true)); | ||||||
|  |         let mut i = 0; | ||||||
|  |         while i < NUM_CONTEXT_REGS { | ||||||
|  |             T::regs().csr(i).write_value(ctx.csr[i]); | ||||||
|  |             i += 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) mod sealed { | ||||||
|  |     use super::*; | ||||||
|  | 
 | ||||||
|  |     pub trait Instance { | ||||||
|  |         fn regs() -> pac::hash::Hash; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// HASH instance trait.
 | ||||||
|  | pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { | ||||||
|  |     /// Interrupt for this HASH instance.
 | ||||||
|  |     type Interrupt: interrupt::typelevel::Interrupt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | foreach_interrupt!( | ||||||
|  |     ($inst:ident, hash, HASH, GLOBAL, $irq:ident) => { | ||||||
|  |         impl Instance for peripherals::$inst { | ||||||
|  |             type Interrupt = crate::interrupt::typelevel::$irq; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         impl sealed::Instance for peripherals::$inst { | ||||||
|  |             fn regs() -> crate::pac::hash::Hash { | ||||||
|  |                 crate::pac::$inst | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | dma_trait!(Dma, Instance); | ||||||
| @ -45,6 +45,8 @@ pub mod exti; | |||||||
| pub mod flash; | pub mod flash; | ||||||
| #[cfg(fmc)] | #[cfg(fmc)] | ||||||
| pub mod fmc; | pub mod fmc; | ||||||
|  | #[cfg(hash)] | ||||||
|  | pub mod hash; | ||||||
| #[cfg(hrtim)] | #[cfg(hrtim)] | ||||||
| pub mod hrtim; | pub mod hrtim; | ||||||
| #[cfg(i2c)] | #[cfg(i2c)] | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||||||
| # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` | # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` | ||||||
| runner = "probe-rs run --chip STM32F767ZITx" | runner = "probe-rs run --chip STM32F777ZITx" | ||||||
| 
 | 
 | ||||||
| [build] | [build] | ||||||
| target = "thumbv7em-none-eabihf" | target = "thumbv7em-none-eabihf" | ||||||
|  | |||||||
| @ -5,8 +5,8 @@ version = "0.1.0" | |||||||
| license = "MIT OR Apache-2.0" | license = "MIT OR Apache-2.0" | ||||||
| 
 | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
| # Change stm32f767zi to your chip name, if necessary. | # Change stm32f777zi to your chip name, if necessary. | ||||||
| embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"]  } | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"]  } | ||||||
| embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | ||||||
| embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | ||||||
| embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||||||
| @ -28,6 +28,7 @@ rand_core = "0.6.3" | |||||||
| critical-section = "1.1" | critical-section = "1.1" | ||||||
| embedded-storage = "0.3.1" | embedded-storage = "0.3.1" | ||||||
| static_cell = "2" | static_cell = "2" | ||||||
|  | sha2 = { version = "0.10.8", default-features = false } | ||||||
| 
 | 
 | ||||||
| [profile.release] | [profile.release] | ||||||
| debug = 2 | debug = 2 | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||||||
| 
 | 
 | ||||||
| bind_interrupts!(struct Irqs { | bind_interrupts!(struct Irqs { | ||||||
|     ETH => eth::InterruptHandler; |     ETH => eth::InterruptHandler; | ||||||
|     RNG => rng::InterruptHandler<peripherals::RNG>; |     HASH_RNG => rng::InterruptHandler<peripherals::RNG>; | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| type Device = Ethernet<'static, ETH, GenericSMI>; | type Device = Ethernet<'static, ETH, GenericSMI>; | ||||||
|  | |||||||
							
								
								
									
										56
									
								
								examples/stm32f7/src/bin/hash.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								examples/stm32f7/src/bin/hash.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::info; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::hash::*; | ||||||
|  | use embassy_stm32::{bind_interrupts, hash, peripherals, Config}; | ||||||
|  | use embassy_time::Instant; | ||||||
|  | use sha2::{Digest, Sha256}; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | bind_interrupts!(struct Irqs { | ||||||
|  |     HASH_RNG => hash::InterruptHandler<peripherals::HASH>; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) -> ! { | ||||||
|  |     let config = Config::default(); | ||||||
|  |     let p = embassy_stm32::init(config); | ||||||
|  | 
 | ||||||
|  |     let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; | ||||||
|  |     let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr"; | ||||||
|  | 
 | ||||||
|  |     let mut hw_hasher = Hash::new(p.HASH, p.DMA2_CH7, Irqs); | ||||||
|  | 
 | ||||||
|  |     let hw_start_time = Instant::now(); | ||||||
|  | 
 | ||||||
|  |     // Compute a digest in hardware.
 | ||||||
|  |     let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); | ||||||
|  |     hw_hasher.update(&mut context, test_1).await; | ||||||
|  |     hw_hasher.update(&mut context, test_2).await; | ||||||
|  |     let mut hw_digest: [u8; 32] = [0; 32]; | ||||||
|  |     hw_hasher.finish(context, &mut hw_digest).await; | ||||||
|  | 
 | ||||||
|  |     let hw_end_time = Instant::now(); | ||||||
|  |     let hw_execution_time = hw_end_time - hw_start_time; | ||||||
|  | 
 | ||||||
|  |     let sw_start_time = Instant::now(); | ||||||
|  | 
 | ||||||
|  |     // Compute a digest in software.
 | ||||||
|  |     let mut sw_hasher = Sha256::new(); | ||||||
|  |     sw_hasher.update(test_1); | ||||||
|  |     sw_hasher.update(test_2); | ||||||
|  |     let sw_digest = sw_hasher.finalize(); | ||||||
|  | 
 | ||||||
|  |     let sw_end_time = Instant::now(); | ||||||
|  |     let sw_execution_time = sw_end_time - sw_start_time; | ||||||
|  | 
 | ||||||
|  |     info!("Hardware Digest: {:?}", hw_digest); | ||||||
|  |     info!("Software Digest: {:?}", sw_digest[..]); | ||||||
|  |     info!("Hardware Execution Time: {:?}", hw_execution_time); | ||||||
|  |     info!("Software Execution Time: {:?}", sw_execution_time); | ||||||
|  |     assert_eq!(hw_digest, sw_digest[..]); | ||||||
|  | 
 | ||||||
|  |     loop {} | ||||||
|  | } | ||||||
| @ -15,22 +15,23 @@ stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma" | |||||||
| stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] | ||||||
| stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] | ||||||
| stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] | ||||||
| stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] | ||||||
| stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan"] | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash"] | ||||||
| stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan"] | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash"] | ||||||
| stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] | ||||||
| stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] | stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] | ||||||
| stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] | stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] | ||||||
| stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] | stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] | ||||||
| stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng"] | stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] | ||||||
| stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] | stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] | ||||||
| stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng"] | stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] | ||||||
| stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng"] | stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"] | ||||||
| stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] | stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] | ||||||
| stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] | ||||||
| stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng"] | stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] | ||||||
| stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] | stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] | ||||||
| 
 | 
 | ||||||
|  | hash = [] | ||||||
| eth = ["embassy-executor/task-arena-size-16384"] | eth = ["embassy-executor/task-arena-size-16384"] | ||||||
| rng = [] | rng = [] | ||||||
| sdmmc = [] | sdmmc = [] | ||||||
| @ -74,6 +75,7 @@ static_cell = "2" | |||||||
| portable-atomic = { version = "1.5", features = [] } | portable-atomic = { version = "1.5", features = [] } | ||||||
| 
 | 
 | ||||||
| chrono = { version = "^0.4", default-features = false, optional = true} | chrono = { version = "^0.4", default-features = false, optional = true} | ||||||
|  | sha2 = { version = "0.10.8", default-features = false } | ||||||
| 
 | 
 | ||||||
| # BEGIN TESTS | # BEGIN TESTS | ||||||
| # Generated by gen_test.py. DO NOT EDIT. | # Generated by gen_test.py. DO NOT EDIT. | ||||||
| @ -107,6 +109,11 @@ name = "gpio" | |||||||
| path = "src/bin/gpio.rs" | path = "src/bin/gpio.rs" | ||||||
| required-features = [] | required-features = [] | ||||||
| 
 | 
 | ||||||
|  | [[bin]] | ||||||
|  | name = "hash" | ||||||
|  | path = "src/bin/hash.rs" | ||||||
|  | required-features = [ "hash",] | ||||||
|  | 
 | ||||||
| [[bin]] | [[bin]] | ||||||
| name = "rng" | name = "rng" | ||||||
| path = "src/bin/rng.rs" | path = "src/bin/rng.rs" | ||||||
|  | |||||||
							
								
								
									
										78
									
								
								tests/stm32/src/bin/hash.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								tests/stm32/src/bin/hash.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | |||||||
|  | // required-features: hash
 | ||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | #[path = "../common.rs"] | ||||||
|  | mod common; | ||||||
|  | use common::*; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::hash::*; | ||||||
|  | use embassy_stm32::{bind_interrupts, hash, peripherals}; | ||||||
|  | use sha2::{Digest, Sha224, Sha256}; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[cfg(any(feature = "stm32l4a6zg", feature = "stm32h755zi", feature = "stm32h753zi"))] | ||||||
|  | bind_interrupts!(struct Irqs { | ||||||
|  |    HASH_RNG => hash::InterruptHandler<peripherals::HASH>; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | #[cfg(any(
 | ||||||
|  |     feature = "stm32wba52cg", | ||||||
|  |     feature = "stm32l552ze", | ||||||
|  |     feature = "stm32h563zi", | ||||||
|  |     feature = "stm32u5a5zj", | ||||||
|  |     feature = "stm32u585ai" | ||||||
|  | ))] | ||||||
|  | bind_interrupts!(struct Irqs { | ||||||
|  |     HASH => hash::InterruptHandler<peripherals::HASH>; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); | ||||||
|  |     let mut hw_hasher = Hash::new(p.HASH, NoDma, Irqs); | ||||||
|  | 
 | ||||||
|  |     let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; | ||||||
|  |     let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr"; | ||||||
|  |     let test_3: &[u8] = b"a.ewtkluGWEBR.KAJRBTA,RMNRBG,FDMGB.kger.tkasjrbt.akrjtba.krjtba.ktmyna,nmbvtyliasd;gdrtba,sfvs.kgjzshd.gkbsr.tksejb.SDkfBSE.gkfgb>ESkfbSE>gkJSBESE>kbSE>fk"; | ||||||
|  | 
 | ||||||
|  |     // Start an SHA-256 digest.
 | ||||||
|  |     let mut sha256context = hw_hasher.start(Algorithm::SHA256, DataType::Width8); | ||||||
|  |     hw_hasher.update_blocking(&mut sha256context, test_1); | ||||||
|  | 
 | ||||||
|  |     // Interrupt the SHA-256 digest to compute an SHA-224 digest.
 | ||||||
|  |     let mut sha224context = hw_hasher.start(Algorithm::SHA224, DataType::Width8); | ||||||
|  |     hw_hasher.update_blocking(&mut sha224context, test_3); | ||||||
|  |     let mut sha224_digest_buffer: [u8; 28] = [0; 28]; | ||||||
|  |     let _ = hw_hasher.finish_blocking(sha224context, &mut sha224_digest_buffer); | ||||||
|  | 
 | ||||||
|  |     // Finish the SHA-256 digest.
 | ||||||
|  |     hw_hasher.update_blocking(&mut sha256context, test_2); | ||||||
|  |     let mut sha256_digest_buffer: [u8; 32] = [0; 32]; | ||||||
|  |     let _ = hw_hasher.finish_blocking(sha256context, &mut sha256_digest_buffer); | ||||||
|  | 
 | ||||||
|  |     // Compute the SHA-256 digest in software.
 | ||||||
|  |     let mut sw_sha256_hasher = Sha256::new(); | ||||||
|  |     sw_sha256_hasher.update(test_1); | ||||||
|  |     sw_sha256_hasher.update(test_2); | ||||||
|  |     let sw_sha256_digest = sw_sha256_hasher.finalize(); | ||||||
|  | 
 | ||||||
|  |     //Compute the SHA-224 digest in software.
 | ||||||
|  |     let mut sw_sha224_hasher = Sha224::new(); | ||||||
|  |     sw_sha224_hasher.update(test_3); | ||||||
|  |     let sw_sha224_digest = sw_sha224_hasher.finalize(); | ||||||
|  | 
 | ||||||
|  |     // Compare the SHA-256 digests.
 | ||||||
|  |     info!("Hardware SHA-256 Digest: {:?}", sha256_digest_buffer); | ||||||
|  |     info!("Software SHA-256 Digest: {:?}", sw_sha256_digest[..]); | ||||||
|  |     defmt::assert!(sha256_digest_buffer == sw_sha256_digest[..]); | ||||||
|  | 
 | ||||||
|  |     // Compare the SHA-224 digests.
 | ||||||
|  |     info!("Hardware SHA-256 Digest: {:?}", sha224_digest_buffer); | ||||||
|  |     info!("Software SHA-256 Digest: {:?}", sw_sha224_digest[..]); | ||||||
|  |     defmt::assert!(sha224_digest_buffer == sw_sha224_digest[..]); | ||||||
|  | 
 | ||||||
|  |     info!("Test OK"); | ||||||
|  |     cortex_m::asm::bkpt(); | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user