| 24 | |
| 25 | #[inline(always)] |
| 26 | pub(crate) fn absorb_partial<const N: usize, const RATE: usize>( |
| 27 | state: &mut [u64; N], |
| 28 | offset: usize, |
| 29 | data: &[u8], |
| 30 | ) { |
| 31 | const { |
| 32 | assert!(size_of::<[u8; RATE]>() <= size_of::<[u64; N]>()); |
| 33 | assert!(RATE % size_of::<u64>() == 0); |
| 34 | }; |
| 35 | |
| 36 | if cfg!(target_endian = "little") { |
| 37 | // SAFETY: casting of `&mut [u64; N]` into `&mut [u8; M]` is safe if |
| 38 | // `size_of::<[u8; M]>() <= size_of::<[u64; N]>())` |
| 39 | let sub_state: &mut [u8; RATE] = unsafe { &mut *(state.as_mut_ptr().cast()) }; |
| 40 | |
| 41 | let dst = &mut sub_state[offset..][..data.len()]; |
| 42 | |
| 43 | for i in 0..dst.len() { |
| 44 | dst[i] ^= data[i]; |
| 45 | } |
| 46 | } else { |
| 47 | let mut buf = [0u8; RATE]; |
| 48 | buf[offset..][..data.len()].copy_from_slice(data); |
| 49 | |
| 50 | let chunks = buf.chunks_exact(size_of::<u64>()); |
| 51 | assert!(chunks.remainder().is_empty()); |
| 52 | |
| 53 | for (dst, chunk) in state.iter_mut().zip(chunks) { |
| 54 | let chunk = chunk.try_into().expect("chunk has correct length"); |
| 55 | *dst ^= u64::from_le_bytes(chunk); |
| 56 | } |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | #[inline(always)] |
| 61 | pub(crate) fn squeeze_read_full<const N: usize, const RATE: usize>( |