seekable_stream_cipher/
ascon.rs1use core::cmp;
2
3#[derive(Clone, Copy)]
5pub struct StreamCipher {
6 st: [u64; 5],
8}
9
10impl StreamCipher {
11 pub const KEY_LENGTH: usize = 32;
13
14 const RKS: [u64; 12] = [
16 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b,
17 ];
18
19 pub fn new(key: &[u8; Self::KEY_LENGTH], context: impl AsRef<[u8]>) -> Self {
26 let context = context.as_ref();
27 let st = [0x010080cc00000000, 0, 0, 0, 0];
28
29 let mut state = StreamCipher { st };
30 state.st[1] ^= u64::from_le_bytes(key[0..8].try_into().unwrap());
31 state.st[2] ^= u64::from_le_bytes(key[8..16].try_into().unwrap());
32 state.st[3] ^= u64::from_le_bytes(key[16..24].try_into().unwrap());
33 state.st[4] ^= u64::from_le_bytes(key[24..32].try_into().unwrap());
34 state.permute();
35
36 let mut context = context;
37
38 while context.len() > 32 {
39 let context_part_len = 32;
40 state.st[0] ^= u64::from_le_bytes(context[0..8].try_into().unwrap());
41 state.st[1] ^= u64::from_le_bytes(context[8..16].try_into().unwrap());
42 state.st[2] ^= u64::from_le_bytes(context[16..24].try_into().unwrap());
43 state.st[3] ^= u64::from_le_bytes(context[24..32].try_into().unwrap());
44 context = &context[context_part_len..];
45 state.permute();
46 }
47
48 let context_len = context.len();
49 let mut buf = [0u8; 32];
50 buf[..context_len].copy_from_slice(context);
51 state.st[0] ^= u64::from_le_bytes(buf[0..8].try_into().unwrap());
52 state.st[1] ^= u64::from_le_bytes(buf[8..16].try_into().unwrap());
53 state.st[2] ^= u64::from_le_bytes(buf[16..24].try_into().unwrap());
54 state.st[3] ^= u64::from_le_bytes(buf[24..32].try_into().unwrap());
55 state.st[4] ^= 0x01;
56 state.permute();
57
58 state.st[0] ^= u64::from_le_bytes(key[0..8].try_into().unwrap());
59 state.st[1] ^= u64::from_le_bytes(key[8..16].try_into().unwrap());
60 state.st[2] ^= u64::from_le_bytes(key[16..24].try_into().unwrap());
61 state.st[3] ^= u64::from_le_bytes(key[24..32].try_into().unwrap());
62
63 state
64 }
65
66 #[inline(always)]
68 fn store_rate(mut self, out: &mut [u8], block_offset: u64) {
69 self.st[4] ^= block_offset;
70 let mask = self.st;
71 self.permute();
72 for (x, mask) in self.st.iter_mut().zip(mask) {
73 *x ^= mask;
74 }
75 for i in 0..5 {
76 out[i * 8..][..8].copy_from_slice(&self.st[i].to_le_bytes());
77 }
78 }
79
80 #[inline(always)]
82 fn apply_rate(mut self, out: &mut [u8], block_offset: u64) {
83 self.st[4] ^= block_offset;
84 let mask = self.st;
85 self.permute();
86 for (x, mask) in self.st.iter_mut().zip(mask) {
87 *x ^= mask;
88 }
89 for i in 0..5 {
90 let x = u64::from_le_bytes(out[i * 8..][..8].try_into().unwrap());
91 out[i * 8..][..8].copy_from_slice(&(self.st[i] ^ x).to_le_bytes());
92 }
93 }
94
95 #[inline(always)]
97 fn squeeze_rate(self, block_offset: u64) -> [u8; 40] {
98 let mut out = [0u8; 40];
99 self.store_rate(&mut out, block_offset);
100 out
101 }
102
103 pub fn fill(&self, mut out: &mut [u8], start_offset: u64) -> Result<(), &'static str> {
109 if start_offset.checked_add(out.len() as u64).is_none() {
110 return Err("offset would overflow");
111 }
112 let mut block_offset = start_offset / 40;
113 let offset_in_first_block = (start_offset % 40) as usize;
114 if offset_in_first_block != 0 {
115 let bytes_to_copy = cmp::min(40 - offset_in_first_block, out.len());
116 if bytes_to_copy > 0 {
117 let rate = self.squeeze_rate(block_offset);
118 out[..bytes_to_copy]
119 .copy_from_slice(&rate[offset_in_first_block..][..bytes_to_copy]);
120 out = &mut out[bytes_to_copy..];
121 }
122 block_offset += 1;
123 }
124 while out.len() >= 40 {
125 self.store_rate(&mut out[..40], block_offset);
126 block_offset += 1;
127 out = &mut out[40..];
128 }
129 if !out.is_empty() {
130 let rate = self.squeeze_rate(block_offset);
131 out.copy_from_slice(&rate[..out.len()]);
132 }
133 Ok(())
134 }
135
136 pub fn apply_keystream(
149 &self,
150 mut out: &mut [u8],
151 start_offset: u64,
152 ) -> Result<(), &'static str> {
153 if start_offset.checked_add(out.len() as u64).is_none() {
154 return Err("offset would overflow");
155 }
156 let mut block_offset = start_offset / 40;
157 let offset_in_first_block = (start_offset % 40) as usize;
158 if offset_in_first_block != 0 {
159 let bytes_to_copy = cmp::min(40 - offset_in_first_block, out.len());
160 if bytes_to_copy > 0 {
161 let rate = self.squeeze_rate(block_offset);
162 for i in 0..bytes_to_copy {
163 out[i] ^= rate[offset_in_first_block + i];
164 }
165 out = &mut out[bytes_to_copy..];
166 }
167 block_offset += 1;
168 }
169 while out.len() >= 40 {
170 self.apply_rate(&mut out[..40], block_offset);
171 block_offset += 1;
172 out = &mut out[40..];
173 }
174 if !out.is_empty() {
175 let rate = self.squeeze_rate(block_offset);
176 for i in 0..out.len() {
177 out[i] ^= rate[i];
178 }
179 }
180 Ok(())
181 }
182
183 #[inline(always)]
184 fn round(&mut self, rk: u64) {
185 let x = &mut self.st;
186 x[2] ^= rk;
187
188 x[0] ^= x[4];
189 x[4] ^= x[3];
190 x[2] ^= x[1];
191 let mut t = [
192 x[0] ^ (!x[1] & x[2]),
193 x[1] ^ (!x[2] & x[3]),
194 x[2] ^ (!x[3] & x[4]),
195 x[3] ^ (!x[4] & x[0]),
196 x[4] ^ (!x[0] & x[1]),
197 ];
198 t[1] ^= t[0];
199 t[3] ^= t[2];
200 t[0] ^= t[4];
201
202 x[2] = t[2] ^ t[2].rotate_right(6 - 1);
203 x[3] = t[3] ^ t[3].rotate_right(17 - 10);
204 x[4] = t[4] ^ t[4].rotate_right(41 - 7);
205 x[0] = t[0] ^ t[0].rotate_right(28 - 19);
206 x[1] = t[1] ^ t[1].rotate_right(61 - 39);
207 x[2] = t[2] ^ x[2].rotate_right(1);
208 x[3] = t[3] ^ x[3].rotate_right(10);
209 x[4] = t[4] ^ x[4].rotate_right(7);
210 x[0] = t[0] ^ x[0].rotate_right(19);
211 x[1] = t[1] ^ x[1].rotate_right(39);
212 x[2] = !x[2];
213 }
214
215 fn permute(&mut self) {
216 for &rk in &Self::RKS {
217 self.round(rk);
218 }
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225
226 #[test]
227 fn test_ascon() {
228 let mut key = [0u8; StreamCipher::KEY_LENGTH];
229 getrandom::fill(&mut key).unwrap();
230
231 let st = StreamCipher::new(&key, b"test");
232
233 let mut out = [0u8; 10000];
234 st.apply_keystream(&mut out, 10).unwrap();
235
236 let mut out2 = [0u8; 10000];
237 st.fill(&mut out2, 10).unwrap();
238
239 assert_eq!(out, out2);
240
241 st.fill(&mut out2, 11).unwrap();
242 assert_eq!(out[1..], out2[0..out2.len() - 1]);
243
244 out.fill(0);
245 st.apply_keystream(&mut out, 0).unwrap();
246 st.fill(&mut out2, 0).unwrap();
247 assert_eq!(out, out2);
248
249 st.fill(&mut out, 40).unwrap();
250 assert_eq!(out[..out2.len() - 40], out2[40..]);
251 }
252
253 #[test]
254 fn test_large_context() {
255 let mut key = [0u8; StreamCipher::KEY_LENGTH];
256 getrandom::fill(&mut key).unwrap();
257 let context = [0u8; 10000];
258 let _ = StreamCipher::new(&key, context);
259 }
260}