Skip to main content

sponge_cursor/
u64_le_utils.rs

1//! Utility functions.
2//!
3//! Note that support of big-endian targets is somewhat sub-optimal since we prioritized
4//! simplicity of the implementation.
5
6#[inline(always)]
7pub(crate) fn absorb_full<const N: usize, const RATE: usize>(
8    state: &mut [u64; N],
9    block: &[u8; RATE],
10) {
11    const {
12        assert!(size_of::<[u8; RATE]>() <= size_of::<[u64; N]>());
13        assert!(RATE % size_of::<u64>() == 0);
14    };
15
16    let chunks = block.chunks_exact(size_of::<u64>());
17    assert!(chunks.remainder().is_empty());
18
19    for (dst, chunk) in state.iter_mut().zip(chunks) {
20        let chunk = chunk.try_into().expect("chunk has correct length");
21        *dst ^= u64::from_le_bytes(chunk);
22    }
23}
24
25#[inline(always)]
26pub(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)]
61pub(crate) fn squeeze_read_full<const N: usize, const RATE: usize>(
62    state: &[u64; N],
63    dst: &mut [u8; RATE],
64) {
65    const {
66        assert!(size_of::<[u8; RATE]>() <= size_of::<[u64; N]>());
67        assert!(RATE % size_of::<u64>() == 0);
68    };
69
70    let mut dst_chunks = dst.chunks_exact_mut(size_of::<u64>());
71    for (src, dst_chunk) in state.iter().zip(&mut dst_chunks) {
72        dst_chunk.copy_from_slice(&src.to_le_bytes());
73    }
74    assert!(dst_chunks.into_remainder().is_empty());
75}
76
77#[inline(always)]
78pub(crate) fn squeeze_read_partial<const N: usize, const RATE: usize>(
79    state: &[u64; N],
80    offset: usize,
81    dst: &mut [u8],
82) {
83    const {
84        assert!(size_of::<[u8; RATE]>() <= size_of::<[u64; N]>());
85        assert!(RATE % size_of::<u64>() == 0);
86    };
87
88    let mut buf = [0u8; RATE];
89
90    let sub_state: &[u8; RATE] = if cfg!(target_endian = "little") {
91        // SAFETY: casting of `&[u64; N]` into `&[u8; M]` is safe if
92        // `size_of::<[u8; M]>() <= size_of::<[u64; N]>())`
93        unsafe { &*(state.as_ptr().cast::<[u8; RATE]>()) }
94    } else {
95        let mut chunks = buf.chunks_exact_mut(size_of::<u64>());
96        for (src, dst) in state.iter().zip(&mut chunks) {
97            dst.copy_from_slice(&src.to_le_bytes());
98        }
99        assert!(chunks.into_remainder().is_empty());
100        &buf
101    };
102
103    let src = &sub_state[offset..][..dst.len()];
104    dst.copy_from_slice(src);
105}
106
107#[inline(always)]
108pub(crate) fn squeeze_xor_full<const N: usize, const RATE: usize>(
109    state: &[u64; N],
110    dst: &mut [u8; RATE],
111) {
112    const {
113        assert!(size_of::<[u8; RATE]>() <= size_of::<[u64; N]>());
114        assert!(RATE % size_of::<u64>() == 0);
115    };
116
117    let mut dst_chunks = dst.chunks_exact_mut(size_of::<u64>());
118    for (src, dst_chunk) in state.iter().zip(&mut dst_chunks) {
119        let dst_chunk: &mut [u8; 8] = dst_chunk.try_into().expect("chunk has correct size");
120        let chunk_val = u64::from_le_bytes(*dst_chunk);
121        *dst_chunk = (chunk_val ^ src).to_le_bytes();
122    }
123    assert!(dst_chunks.into_remainder().is_empty());
124}
125
126#[inline(always)]
127pub(crate) fn squeeze_xor_partial<const N: usize, const RATE: usize>(
128    state: &[u64; N],
129    offset: usize,
130    dst: &mut [u8],
131) {
132    const {
133        assert!(size_of::<[u8; RATE]>() <= size_of::<[u64; N]>());
134        assert!(RATE % size_of::<u64>() == 0);
135    };
136
137    let mut buf = [0u8; RATE];
138
139    let sub_state: &[u8; RATE] = if cfg!(target_endian = "little") {
140        // SAFETY: casting of `&[u64; N]` into `&[u8; M]` is safe if
141        // `size_of::<[u8; M]>() <= size_of::<[u64; N]>())`
142        unsafe { &*(state.as_ptr().cast::<[u8; RATE]>()) }
143    } else {
144        let mut chunks = buf.chunks_exact_mut(size_of::<u64>());
145        for (src, dst) in state.iter().zip(&mut chunks) {
146            dst.copy_from_slice(&src.to_le_bytes());
147        }
148        assert!(chunks.into_remainder().is_empty());
149        &buf
150    };
151
152    let src = &sub_state[offset..][..dst.len()];
153    for i in 0..dst.len() {
154        dst[i] ^= src[i];
155    }
156}