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 let mask: [u64; 2] = self.st[0..2].try_into().unwrap();
70 self.st[4] ^= block_offset;
71 self.permute();
72 out[..8].copy_from_slice(&(self.st[3] ^ mask[0]).to_le_bytes());
73 out[8..].copy_from_slice(&(self.st[4] ^ mask[1]).to_le_bytes());
74 }
75
76 #[inline(always)]
78 fn apply_rate(mut self, out: &mut [u8], block_offset: u64) {
79 let mask: [u64; 2] = self.st[0..2].try_into().unwrap();
80 self.st[4] ^= block_offset;
81 self.permute();
82 let out0 = u64::from_le_bytes(out[..8].try_into().unwrap());
83 let out1 = u64::from_le_bytes(out[8..][..8].try_into().unwrap());
84 out[..8].copy_from_slice(&(self.st[3] ^ out0 ^ mask[0]).to_le_bytes());
85 out[8..].copy_from_slice(&(self.st[4] ^ out1 ^ mask[1]).to_le_bytes());
86 }
87
88 #[inline(always)]
90 fn squeeze_rate(self, block_offset: u64) -> [u8; 16] {
91 let mut out = [0u8; 16];
92 self.store_rate(&mut out, block_offset);
93 out
94 }
95
96 pub fn fill(&self, mut out: &mut [u8], start_offset: u64) -> Result<(), &'static str> {
102 if start_offset.checked_add(out.len() as u64).is_none() {
103 return Err("offset would overflow");
104 }
105 let mut block_offset = start_offset / 16;
106 let offset_in_first_block = (start_offset % 16) as usize;
107 let bytes_to_copy = cmp::min(16 - offset_in_first_block, out.len());
108 if bytes_to_copy > 0 {
109 let rate = self.squeeze_rate(block_offset);
110 out[..bytes_to_copy].copy_from_slice(&rate[offset_in_first_block..][..bytes_to_copy]);
111 out = &mut out[bytes_to_copy..];
112 }
113 while out.len() >= 16 {
114 block_offset += 1;
115 self.store_rate(&mut out[..16], block_offset);
116 out = &mut out[16..];
117 }
118 if !out.is_empty() {
119 block_offset += 1;
120 let rate = self.squeeze_rate(block_offset);
121 out.copy_from_slice(&rate[..out.len()]);
122 }
123 Ok(())
124 }
125
126 pub fn apply_keystream(
139 &self,
140 mut out: &mut [u8],
141 start_offset: u64,
142 ) -> Result<(), &'static str> {
143 if start_offset.checked_add(out.len() as u64).is_none() {
144 return Err("offset would overflow");
145 }
146 let mut block_offset = start_offset / 16;
147 let offset_in_first_block = (start_offset % 16) as usize;
148 let bytes_to_copy = cmp::min(16 - offset_in_first_block, out.len());
149 if bytes_to_copy > 0 {
150 let rate = self.squeeze_rate(block_offset);
151 for i in 0..bytes_to_copy {
152 out[i] ^= rate[offset_in_first_block + i];
153 }
154 out = &mut out[bytes_to_copy..];
155 }
156 while out.len() >= 16 {
157 block_offset += 1;
158 self.apply_rate(&mut out[..16], block_offset);
159 out = &mut out[16..];
160 }
161 if !out.is_empty() {
162 block_offset += 1;
163 let rate = self.squeeze_rate(block_offset);
164 for i in 0..out.len() {
165 out[i] ^= rate[i];
166 }
167 }
168 Ok(())
169 }
170
171 #[inline(always)]
172 fn round(&mut self, rk: u64) {
173 let x = &mut self.st;
174 x[2] ^= rk;
175
176 x[0] ^= x[4];
177 x[4] ^= x[3];
178 x[2] ^= x[1];
179 let mut t = [
180 x[0] ^ (!x[1] & x[2]),
181 x[1] ^ (!x[2] & x[3]),
182 x[2] ^ (!x[3] & x[4]),
183 x[3] ^ (!x[4] & x[0]),
184 x[4] ^ (!x[0] & x[1]),
185 ];
186 t[1] ^= t[0];
187 t[3] ^= t[2];
188 t[0] ^= t[4];
189
190 x[2] = t[2] ^ t[2].rotate_right(6 - 1);
191 x[3] = t[3] ^ t[3].rotate_right(17 - 10);
192 x[4] = t[4] ^ t[4].rotate_right(41 - 7);
193 x[0] = t[0] ^ t[0].rotate_right(28 - 19);
194 x[1] = t[1] ^ t[1].rotate_right(61 - 39);
195 x[2] = t[2] ^ x[2].rotate_right(1);
196 x[3] = t[3] ^ x[3].rotate_right(10);
197 x[4] = t[4] ^ x[4].rotate_right(7);
198 x[0] = t[0] ^ x[0].rotate_right(19);
199 x[1] = t[1] ^ x[1].rotate_right(39);
200 x[2] = !x[2];
201 }
202
203 fn permute(&mut self) {
204 for &rk in &Self::RKS {
205 self.round(rk);
206 }
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213
214 #[test]
215 fn test_ascon() {
216 let mut key = [0u8; StreamCipher::KEY_LENGTH];
217 getrandom::getrandom(&mut key).unwrap();
218
219 let st = StreamCipher::new(&key, b"test");
220
221 let mut out = [0u8; 10000];
222 st.apply_keystream(&mut out, 10).unwrap();
223
224 let mut out2 = [0u8; 10000];
225 st.fill(&mut out2, 10).unwrap();
226
227 assert_eq!(out, out2);
228
229 st.fill(&mut out2, 11).unwrap();
230 assert_eq!(out[1..], out2[0..out2.len() - 1]);
231 }
232
233 #[test]
234 fn test_large_context() {
235 let mut key = [0u8; StreamCipher::KEY_LENGTH];
236 getrandom::getrandom(&mut key).unwrap();
237 let context = [0u8; 10000];
238 let _ = StreamCipher::new(&key, context);
239 }
240}