Faster SHA (#2112)

Co-authored-by: Dominic Fischer <git@dominicfischer.me>
This commit is contained in:
Dominic Fischer 2024-09-09 11:18:38 +01:00 committed by GitHub
parent 6295c5f9da
commit 3ea95bd0d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 11 deletions

View File

@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Input`, `Output`, `OutputOpenDrain` and `Flex` are now type-erased by default. Use the new `new_typed` constructor to keep using the ZST pin types. (#2075) - `Input`, `Output`, `OutputOpenDrain` and `Flex` are now type-erased by default. Use the new `new_typed` constructor to keep using the ZST pin types. (#2075)
- To avoid confusion with the `Rtc::current_time` wall clock time APIs, we've renamed `esp_hal::time::current_time` to `esp_hal::time::now`. (#2091) - To avoid confusion with the `Rtc::current_time` wall clock time APIs, we've renamed `esp_hal::time::current_time` to `esp_hal::time::now`. (#2091)
- Renamed `touch::Continous` to `touch::Continuous`. (#2094) - Renamed `touch::Continous` to `touch::Continuous`. (#2094)
- Faster SHA (#2112)
- The (previously undocumented) `ErasedPin` enum has been replaced with the `ErasedPin` struct. (#2094) - The (previously undocumented) `ErasedPin` enum has been replaced with the `ErasedPin` struct. (#2094)
- Renamed and merged `Rtc::get_time_us` and `Rtc::get_time_ms` into `Rtc::time_since_boot` (#1883) - Renamed and merged `Rtc::get_time_us` and `Rtc::get_time_ms` into `Rtc::time_since_boot` (#1883)
- ESP32: Added support for touch sensing on GPIO32 and 33 (#2109) - ESP32: Added support for touch sensing on GPIO32 and 33 (#2109)

View File

@ -135,6 +135,7 @@ pub struct ShaDigest<'d, A, S: BorrowMut<Sha<'d>>> {
cursor: usize, cursor: usize,
first_run: bool, first_run: bool,
finished: bool, finished: bool,
message_buffer_is_full: bool,
phantom: PhantomData<(&'d (), A)>, phantom: PhantomData<(&'d (), A)>,
} }
@ -155,6 +156,7 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut<Sha<'d>>> ShaDigest<'d, A, S> {
cursor: 0, cursor: 0,
first_run: true, first_run: true,
finished: false, finished: false,
message_buffer_is_full: false,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -188,6 +190,7 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut<Sha<'d>>> ShaDigest<'d, A, S> {
cursor: ctx.cursor, cursor: ctx.cursor,
first_run: ctx.first_run, first_run: ctx.first_run,
finished: ctx.finished, finished: ctx.finished,
message_buffer_is_full: ctx.message_buffer_is_full,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -205,9 +208,6 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut<Sha<'d>>> ShaDigest<'d, A, S> {
/// Updates the SHA digest with the provided data buffer. /// Updates the SHA digest with the provided data buffer.
pub fn update<'a>(&mut self, incoming: &'a [u8]) -> nb::Result<&'a [u8], Infallible> { pub fn update<'a>(&mut self, incoming: &'a [u8]) -> nb::Result<&'a [u8], Infallible> {
if self.is_busy() {
return Err(nb::Error::WouldBlock);
}
self.finished = false; self.finished = false;
self.write_data(incoming) self.write_data(incoming)
@ -221,10 +221,6 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut<Sha<'d>>> ShaDigest<'d, A, S> {
/// [ShaAlgorithm::DIGEST_LENGTH], but smaller inputs can be given to /// [ShaAlgorithm::DIGEST_LENGTH], but smaller inputs can be given to
/// get a "short hash" /// get a "short hash"
pub fn finish(&mut self, output: &mut [u8]) -> nb::Result<(), Infallible> { pub fn finish(&mut self, output: &mut [u8]) -> nb::Result<(), Infallible> {
if self.is_busy() {
return Err(nb::Error::WouldBlock);
}
// Store message length for padding // Store message length for padding
let length = (self.cursor as u64 * 8).to_be_bytes(); let length = (self.cursor as u64 * 8).to_be_bytes();
nb::block!(self.update(&[0x80]))?; // Append "1" bit nb::block!(self.update(&[0x80]))?; // Append "1" bit
@ -232,6 +228,11 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut<Sha<'d>>> ShaDigest<'d, A, S> {
// Flush partial data, ensures aligned cursor // Flush partial data, ensures aligned cursor
{ {
while self.is_busy() {} while self.is_busy() {}
if self.message_buffer_is_full {
self.process_buffer();
self.message_buffer_is_full = false;
while self.is_busy() {}
}
let flushed = self.alignment_helper.flush_to( let flushed = self.alignment_helper.flush_to(
m_mem(&self.sha.borrow_mut().sha, 0), m_mem(&self.sha.borrow_mut().sha, 0),
@ -320,6 +321,7 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut<Sha<'d>>> ShaDigest<'d, A, S> {
context.cursor = self.cursor; context.cursor = self.cursor;
context.first_run = self.first_run; context.first_run = self.first_run;
context.finished = self.finished; context.finished = self.finished;
context.message_buffer_is_full = self.message_buffer_is_full;
// Save the content of the current hash. // Save the content of the current hash.
self.alignment_helper.volatile_read_regset( self.alignment_helper.volatile_read_regset(
@ -378,10 +380,18 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut<Sha<'d>>> ShaDigest<'d, A, S> {
} }
fn write_data<'a>(&mut self, incoming: &'a [u8]) -> nb::Result<&'a [u8], Infallible> { fn write_data<'a>(&mut self, incoming: &'a [u8]) -> nb::Result<&'a [u8], Infallible> {
if self.message_buffer_is_full {
if self.is_busy() { if self.is_busy() {
// The message buffer is full and the hardware is still processing the previous
// message. There's nothing to be done besides wait for the hardware.
return Err(nb::Error::WouldBlock); return Err(nb::Error::WouldBlock);
} else {
// Submit the full buffer.
self.process_buffer();
// The buffer is now free for filling.
self.message_buffer_is_full = false;
}
} }
self.finished = false;
let mod_cursor = self.cursor % A::CHUNK_LENGTH; let mod_cursor = self.cursor % A::CHUNK_LENGTH;
let chunk_len = A::CHUNK_LENGTH; let chunk_len = A::CHUNK_LENGTH;
@ -396,8 +406,17 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut<Sha<'d>>> ShaDigest<'d, A, S> {
self.cursor = self.cursor.wrapping_add(incoming.len() - remaining.len()); self.cursor = self.cursor.wrapping_add(incoming.len() - remaining.len());
if bound_reached { if bound_reached {
// Message is full now.
if self.is_busy() {
// The message buffer is full and the hardware is still processing the previous
// message. There's nothing to be done besides wait for the hardware.
self.message_buffer_is_full = true;
} else {
// Send the full buffer.
self.process_buffer(); self.process_buffer();
} }
}
Ok(remaining) Ok(remaining)
} }
@ -411,6 +430,7 @@ pub struct Context<A: ShaAlgorithm> {
cursor: usize, cursor: usize,
first_run: bool, first_run: bool,
finished: bool, finished: bool,
message_buffer_is_full: bool,
/// Buffered bytes (SHA_M_n_REG) to be processed. /// Buffered bytes (SHA_M_n_REG) to be processed.
buffer: [u32; 32], buffer: [u32; 32],
/// Saved digest (SHA_H_n_REG) for interleaving operation /// Saved digest (SHA_H_n_REG) for interleaving operation
@ -426,6 +446,7 @@ impl<A: ShaAlgorithm> Context<A> {
cursor: 0, cursor: 0,
first_run: true, first_run: true,
finished: false, finished: false,
message_buffer_is_full: false,
alignment_helper: AlignmentHelper::default(), alignment_helper: AlignmentHelper::default(),
buffer: [0; 32], buffer: [0; 32],
saved_digest: [0; 64], saved_digest: [0; 64],