pub fn finish(&mut self, output: &mut [u8]) -> nb::Result<(), Infallible> {
        // Store message length for padding
        let length = (self.cursor as u64 * 8).to_be_bytes();
        nb::block!(self.update(&[0x80]))?; // Append "1" bit

        // Flush partial data, ensures aligned cursor
        {
            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(
                m_mem(&self.sha.borrow().sha, 0),
                (self.cursor % A::CHUNK_LENGTH) / self.alignment_helper.align_size(),
            );
            self.cursor = self.cursor.wrapping_add(flushed);

            if flushed > 0 && self.cursor % A::CHUNK_LENGTH == 0 {
                self.process_buffer();
                while self.is_busy() {}
            }
        }
        debug_assert!(self.cursor % 4 == 0);

        let mod_cursor = self.cursor % A::CHUNK_LENGTH;
        if (A::CHUNK_LENGTH - mod_cursor) < A::CHUNK_LENGTH / 8 {
            // Zero out remaining data if buffer is almost full (>=448/896), and process
            // buffer
            let pad_len = A::CHUNK_LENGTH - mod_cursor;
            self.alignment_helper.volatile_write(
                m_mem(&self.sha.borrow().sha, 0),
                0_u8,
                pad_len / self.alignment_helper.align_size(),
                mod_cursor / self.alignment_helper.align_size(),
            );
            self.process_buffer();
            self.cursor = self.cursor.wrapping_add(pad_len);

            debug_assert_eq!(self.cursor % A::CHUNK_LENGTH, 0);

            // Spin-wait for finish
            while self.is_busy() {}
        }

        let mod_cursor = self.cursor % A::CHUNK_LENGTH; // Should be zero if branched above
        let pad_len = A::CHUNK_LENGTH - mod_cursor - size_of::<u64>();

        self.alignment_helper.volatile_write(
            m_mem(&self.sha.borrow().sha, 0),
            0,
            pad_len / self.alignment_helper.align_size(),
            mod_cursor / self.alignment_helper.align_size(),
        );

        self.alignment_helper.aligned_volatile_copy(
            m_mem(&self.sha.borrow().sha, 0),
            &length,
            A::CHUNK_LENGTH / self.alignment_helper.align_size(),
            (A::CHUNK_LENGTH - size_of::<u64>()) / self.alignment_helper.align_size(),
        );

        self.process_buffer();
        // Spin-wait for final buffer to be processed
        while self.is_busy() {}

        // ESP32 requires additional load to retrieve output
        #[cfg(esp32)]
        {
            A::load(&self.sha.borrow().sha);

            // Spin wait for result, 8-20 clock cycles according to manual
            while self.is_busy() {}
        }

        self.alignment_helper.volatile_read_regset(
            h_mem(&self.sha.borrow().sha, 0),
            output,
            core::cmp::min(output.len(), 32) / self.alignment_helper.align_size(),
        );

        self.first_run = true;
        self.cursor = 0;
        self.alignment_helper.reset();

        Ok(())
    }
Finish of the calculation (if not already) and copy result to output
After `finish()` is called `update()`s will contribute to a new hash
which can be calculated again with `finish()`.

Typically, output is expected to be the size of
[ShaAlgorithm::DIGEST_LENGTH], but smaller inputs can be given to
get a "short hash"
esp-hal/src/sha.rs