1#![deny(unsafe_code)]
4
5extern crate alloc;
6
7use alloc::string::ToString;
8use alloc::vec::Vec;
9
10use aead::array::Array;
11use aead::{
12 AeadInOut,
13 KeyInit,
14};
15use lib_q_core::{
16 Aead,
17 AeadDecryptSemantic,
18 AeadKey,
19 DecryptSemanticOutcome,
20 Error,
21 Nonce,
22 Result,
23};
24use zeroize::{
25 Zeroize,
26 Zeroizing,
27};
28
29use crate::{
30 RomulusM,
31 RomulusN,
32 stack_secret,
33};
34
35pub struct RomulusNAead;
37
38impl RomulusNAead {
39 pub const fn new() -> Self {
40 Self
41 }
42
43 pub const fn key_size() -> usize {
44 16
45 }
46
47 pub const fn nonce_size() -> usize {
48 16
49 }
50
51 pub const fn tag_size() -> usize {
52 16
53 }
54}
55
56impl Default for RomulusNAead {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl Aead for RomulusNAead {
63 fn encrypt(
64 &self,
65 key: &AeadKey,
66 nonce: &Nonce,
67 plaintext: &[u8],
68 associated_data: Option<&[u8]>,
69 ) -> Result<Vec<u8>> {
70 let kb = key.as_bytes();
71 if kb.len() != Self::key_size() {
72 return Err(Error::InvalidKeySize {
73 expected: Self::key_size(),
74 actual: kb.len(),
75 });
76 }
77 let nb = nonce.as_bytes();
78 if nb.len() != Self::nonce_size() {
79 return Err(Error::InvalidNonceSize {
80 expected: Self::nonce_size(),
81 actual: nb.len(),
82 });
83 }
84 let ad = associated_data.unwrap_or(&[]);
85 let nonce_z = stack_secret::zeroizing_copy_16(nb);
86 let nonce_arr =
87 Array::try_from(nonce_z.as_slice()).map_err(|_| Error::InvalidNonceSize {
88 expected: Self::nonce_size(),
89 actual: nonce_z.len(),
90 })?;
91 let cipher = {
92 let kz = stack_secret::zeroizing_copy_16(kb);
93 let key_arr = Array::try_from(kz.as_slice()).map_err(|_| Error::InvalidKeySize {
94 expected: Self::key_size(),
95 actual: kz.len(),
96 })?;
97 RomulusN::new(&key_arr)
98 };
99 let mut buf = plaintext.to_vec();
100 let tag = cipher
101 .encrypt_inout_detached(&nonce_arr, ad, buf.as_mut_slice().into())
102 .map_err(|_| Error::EncryptionFailed {
103 operation: "Romulus-N encrypt".to_string(),
104 })?;
105 buf.extend_from_slice(tag.as_slice());
106 Ok(buf)
107 }
108
109 fn decrypt(
110 &self,
111 key: &AeadKey,
112 nonce: &Nonce,
113 ciphertext: &[u8],
114 associated_data: Option<&[u8]>,
115 ) -> Result<Vec<u8>> {
116 let kb = key.as_bytes();
117 if kb.len() != Self::key_size() {
118 return Err(Error::InvalidKeySize {
119 expected: Self::key_size(),
120 actual: kb.len(),
121 });
122 }
123 let nb = nonce.as_bytes();
124 if nb.len() != Self::nonce_size() {
125 return Err(Error::InvalidNonceSize {
126 expected: Self::nonce_size(),
127 actual: nb.len(),
128 });
129 }
130 if ciphertext.len() < Self::tag_size() {
131 return Err(Error::aead_ciphertext_shorter_than_tag(
132 Self::tag_size(),
133 ciphertext.len(),
134 ));
135 }
136 let ad = associated_data.unwrap_or(&[]);
137 let body_len = ciphertext.len() - Self::tag_size();
138 let key_z = stack_secret::zeroizing_copy_16(kb);
139 let nonce_z = stack_secret::zeroizing_copy_16(nb);
140 let tag_arr =
141 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
142 Error::VerificationFailed {
143 operation: "AEAD tag verification".to_string(),
144 }
145 })?;
146 let mut buf = ciphertext[..body_len].to_vec();
147 crate::romulus_n::romulus_n_decrypt(&key_z, &nonce_z, ad, &mut buf, &tag_arr).map_err(
148 |_| Error::VerificationFailed {
149 operation: "AEAD tag verification".to_string(),
150 },
151 )?;
152 Ok(buf)
153 }
154}
155
156impl AeadDecryptSemantic for RomulusNAead {
157 fn decrypt_semantic(
158 &self,
159 key: &AeadKey,
160 nonce: &Nonce,
161 ciphertext: &[u8],
162 associated_data: Option<&[u8]>,
163 ) -> Result<DecryptSemanticOutcome> {
164 let kb = key.as_bytes();
165 if kb.len() != Self::key_size() {
166 return Err(Error::InvalidKeySize {
167 expected: Self::key_size(),
168 actual: kb.len(),
169 });
170 }
171 let nb = nonce.as_bytes();
172 if nb.len() != Self::nonce_size() {
173 return Err(Error::InvalidNonceSize {
174 expected: Self::nonce_size(),
175 actual: nb.len(),
176 });
177 }
178 if ciphertext.len() < Self::tag_size() {
179 return Err(Error::aead_ciphertext_shorter_than_tag(
180 Self::tag_size(),
181 ciphertext.len(),
182 ));
183 }
184 let ad = associated_data.unwrap_or(&[]);
185 let body_len = ciphertext.len() - Self::tag_size();
186 let key_z = stack_secret::zeroizing_copy_16(kb);
187 let nonce_z = stack_secret::zeroizing_copy_16(nb);
188 let tag_arr =
189 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
190 Error::VerificationFailed {
191 operation: "AEAD tag verification".to_string(),
192 }
193 })?;
194 let mut buf = ciphertext[..body_len].to_vec();
195 if crate::romulus_n::romulus_n_decrypt_core(&key_z, &nonce_z, ad, &mut buf, &tag_arr) {
196 Ok(DecryptSemanticOutcome::Success(Zeroizing::new(buf)))
197 } else {
198 buf.zeroize();
199 Ok(DecryptSemanticOutcome::AuthenticationFailed)
200 }
201 }
202}
203
204pub struct RomulusMAead;
206
207impl RomulusMAead {
208 pub const fn new() -> Self {
209 Self
210 }
211
212 pub const fn key_size() -> usize {
213 16
214 }
215
216 pub const fn nonce_size() -> usize {
217 16
218 }
219
220 pub const fn tag_size() -> usize {
221 16
222 }
223}
224
225impl Default for RomulusMAead {
226 fn default() -> Self {
227 Self::new()
228 }
229}
230
231impl Aead for RomulusMAead {
232 fn encrypt(
233 &self,
234 key: &AeadKey,
235 nonce: &Nonce,
236 plaintext: &[u8],
237 associated_data: Option<&[u8]>,
238 ) -> Result<Vec<u8>> {
239 let kb = key.as_bytes();
240 if kb.len() != Self::key_size() {
241 return Err(Error::InvalidKeySize {
242 expected: Self::key_size(),
243 actual: kb.len(),
244 });
245 }
246 let nb = nonce.as_bytes();
247 if nb.len() != Self::nonce_size() {
248 return Err(Error::InvalidNonceSize {
249 expected: Self::nonce_size(),
250 actual: nb.len(),
251 });
252 }
253 let ad = associated_data.unwrap_or(&[]);
254 let nonce_z = stack_secret::zeroizing_copy_16(nb);
255 let nonce_arr =
256 Array::try_from(nonce_z.as_slice()).map_err(|_| Error::InvalidNonceSize {
257 expected: Self::nonce_size(),
258 actual: nonce_z.len(),
259 })?;
260 let cipher = {
261 let kz = stack_secret::zeroizing_copy_16(kb);
262 let key_arr = Array::try_from(kz.as_slice()).map_err(|_| Error::InvalidKeySize {
263 expected: Self::key_size(),
264 actual: kz.len(),
265 })?;
266 RomulusM::new(&key_arr)
267 };
268 let mut buf = plaintext.to_vec();
269 let tag = cipher
270 .encrypt_inout_detached(&nonce_arr, ad, buf.as_mut_slice().into())
271 .map_err(|_| Error::EncryptionFailed {
272 operation: "Romulus-M encrypt".to_string(),
273 })?;
274 buf.extend_from_slice(tag.as_slice());
275 Ok(buf)
276 }
277
278 fn decrypt(
279 &self,
280 key: &AeadKey,
281 nonce: &Nonce,
282 ciphertext: &[u8],
283 associated_data: Option<&[u8]>,
284 ) -> Result<Vec<u8>> {
285 let kb = key.as_bytes();
286 if kb.len() != Self::key_size() {
287 return Err(Error::InvalidKeySize {
288 expected: Self::key_size(),
289 actual: kb.len(),
290 });
291 }
292 let nb = nonce.as_bytes();
293 if nb.len() != Self::nonce_size() {
294 return Err(Error::InvalidNonceSize {
295 expected: Self::nonce_size(),
296 actual: nb.len(),
297 });
298 }
299 if ciphertext.len() < Self::tag_size() {
300 return Err(Error::aead_ciphertext_shorter_than_tag(
301 Self::tag_size(),
302 ciphertext.len(),
303 ));
304 }
305 let ad = associated_data.unwrap_or(&[]);
306 let body_len = ciphertext.len() - Self::tag_size();
307 let key_z = stack_secret::zeroizing_copy_16(kb);
308 let nonce_z = stack_secret::zeroizing_copy_16(nb);
309 let tag_arr =
310 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
311 Error::VerificationFailed {
312 operation: "AEAD tag verification".to_string(),
313 }
314 })?;
315 let mut buf = ciphertext[..body_len].to_vec();
316 crate::romulus_m::romulus_m_decrypt(&key_z, &nonce_z, ad, &mut buf, &tag_arr).map_err(
317 |_| Error::VerificationFailed {
318 operation: "AEAD tag verification".to_string(),
319 },
320 )?;
321 Ok(buf)
322 }
323}
324
325impl AeadDecryptSemantic for RomulusMAead {
326 fn decrypt_semantic(
327 &self,
328 key: &AeadKey,
329 nonce: &Nonce,
330 ciphertext: &[u8],
331 associated_data: Option<&[u8]>,
332 ) -> Result<DecryptSemanticOutcome> {
333 let kb = key.as_bytes();
334 if kb.len() != Self::key_size() {
335 return Err(Error::InvalidKeySize {
336 expected: Self::key_size(),
337 actual: kb.len(),
338 });
339 }
340 let nb = nonce.as_bytes();
341 if nb.len() != Self::nonce_size() {
342 return Err(Error::InvalidNonceSize {
343 expected: Self::nonce_size(),
344 actual: nb.len(),
345 });
346 }
347 if ciphertext.len() < Self::tag_size() {
348 return Err(Error::aead_ciphertext_shorter_than_tag(
349 Self::tag_size(),
350 ciphertext.len(),
351 ));
352 }
353 let ad = associated_data.unwrap_or(&[]);
354 let body_len = ciphertext.len() - Self::tag_size();
355 let key_z = stack_secret::zeroizing_copy_16(kb);
356 let nonce_z = stack_secret::zeroizing_copy_16(nb);
357 let tag_arr =
358 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
359 Error::VerificationFailed {
360 operation: "AEAD tag verification".to_string(),
361 }
362 })?;
363 let mut buf = ciphertext[..body_len].to_vec();
364 if crate::romulus_m::romulus_m_decrypt_core(&key_z, &nonce_z, ad, &mut buf, &tag_arr) {
365 Ok(DecryptSemanticOutcome::Success(Zeroizing::new(buf)))
366 } else {
367 buf.zeroize();
368 Ok(DecryptSemanticOutcome::AuthenticationFailed)
369 }
370 }
371}