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 pub fn encrypt_bytes(
227 &self,
228 key: &[u8],
229 nonce: &[u8],
230 plaintext: &[u8],
231 associated_data: Option<&[u8]>,
232 ) -> Result<Vec<u8>> {
233 let kb = key;
234 if kb.len() != Self::key_size() {
235 return Err(Error::InvalidKeySize {
236 expected: Self::key_size(),
237 actual: kb.len(),
238 });
239 }
240 let nb = nonce;
241 if nb.len() != Self::nonce_size() {
242 return Err(Error::InvalidNonceSize {
243 expected: Self::nonce_size(),
244 actual: nb.len(),
245 });
246 }
247 let ad = associated_data.unwrap_or(&[]);
248 let nonce_z = stack_secret::zeroizing_copy_16(nb);
249 let nonce_arr =
250 Array::try_from(nonce_z.as_slice()).map_err(|_| Error::InvalidNonceSize {
251 expected: Self::nonce_size(),
252 actual: nonce_z.len(),
253 })?;
254 let cipher = {
255 let kz = stack_secret::zeroizing_copy_16(kb);
256 let key_arr = Array::try_from(kz.as_slice()).map_err(|_| Error::InvalidKeySize {
257 expected: Self::key_size(),
258 actual: kz.len(),
259 })?;
260 RomulusM::new(&key_arr)
261 };
262 let mut buf = plaintext.to_vec();
263 let tag = cipher
264 .encrypt_inout_detached(&nonce_arr, ad, buf.as_mut_slice().into())
265 .map_err(|_| Error::EncryptionFailed {
266 operation: "Romulus-M encrypt".to_string(),
267 })?;
268 buf.extend_from_slice(tag.as_slice());
269 Ok(buf)
270 }
271
272 pub fn decrypt_bytes(
274 &self,
275 key: &[u8],
276 nonce: &[u8],
277 ciphertext: &[u8],
278 associated_data: Option<&[u8]>,
279 ) -> Result<Vec<u8>> {
280 let kb = key;
281 if kb.len() != Self::key_size() {
282 return Err(Error::InvalidKeySize {
283 expected: Self::key_size(),
284 actual: kb.len(),
285 });
286 }
287 let nb = nonce;
288 if nb.len() != Self::nonce_size() {
289 return Err(Error::InvalidNonceSize {
290 expected: Self::nonce_size(),
291 actual: nb.len(),
292 });
293 }
294 if ciphertext.len() < Self::tag_size() {
295 return Err(Error::aead_ciphertext_shorter_than_tag(
296 Self::tag_size(),
297 ciphertext.len(),
298 ));
299 }
300 let ad = associated_data.unwrap_or(&[]);
301 let body_len = ciphertext.len() - Self::tag_size();
302 let key_z = stack_secret::zeroizing_copy_16(kb);
303 let nonce_z = stack_secret::zeroizing_copy_16(nb);
304 let tag_arr =
305 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
306 Error::VerificationFailed {
307 operation: "AEAD tag verification".to_string(),
308 }
309 })?;
310 let mut buf = ciphertext[..body_len].to_vec();
311 crate::romulus_m::romulus_m_decrypt(&key_z, &nonce_z, ad, &mut buf, &tag_arr).map_err(
312 |_| Error::VerificationFailed {
313 operation: "AEAD tag verification".to_string(),
314 },
315 )?;
316 Ok(buf)
317 }
318}
319
320impl Default for RomulusMAead {
321 fn default() -> Self {
322 Self::new()
323 }
324}
325
326impl Aead for RomulusMAead {
327 fn encrypt(
328 &self,
329 key: &AeadKey,
330 nonce: &Nonce,
331 plaintext: &[u8],
332 associated_data: Option<&[u8]>,
333 ) -> Result<Vec<u8>> {
334 self.encrypt_bytes(key.as_bytes(), nonce.as_bytes(), plaintext, associated_data)
335 }
336
337 fn decrypt(
338 &self,
339 key: &AeadKey,
340 nonce: &Nonce,
341 ciphertext: &[u8],
342 associated_data: Option<&[u8]>,
343 ) -> Result<Vec<u8>> {
344 self.decrypt_bytes(
345 key.as_bytes(),
346 nonce.as_bytes(),
347 ciphertext,
348 associated_data,
349 )
350 }
351}
352
353impl AeadDecryptSemantic for RomulusMAead {
354 fn decrypt_semantic(
355 &self,
356 key: &AeadKey,
357 nonce: &Nonce,
358 ciphertext: &[u8],
359 associated_data: Option<&[u8]>,
360 ) -> Result<DecryptSemanticOutcome> {
361 let kb = key.as_bytes();
362 if kb.len() != Self::key_size() {
363 return Err(Error::InvalidKeySize {
364 expected: Self::key_size(),
365 actual: kb.len(),
366 });
367 }
368 let nb = nonce.as_bytes();
369 if nb.len() != Self::nonce_size() {
370 return Err(Error::InvalidNonceSize {
371 expected: Self::nonce_size(),
372 actual: nb.len(),
373 });
374 }
375 if ciphertext.len() < Self::tag_size() {
376 return Err(Error::aead_ciphertext_shorter_than_tag(
377 Self::tag_size(),
378 ciphertext.len(),
379 ));
380 }
381 let ad = associated_data.unwrap_or(&[]);
382 let body_len = ciphertext.len() - Self::tag_size();
383 let key_z = stack_secret::zeroizing_copy_16(kb);
384 let nonce_z = stack_secret::zeroizing_copy_16(nb);
385 let tag_arr =
386 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
387 Error::VerificationFailed {
388 operation: "AEAD tag verification".to_string(),
389 }
390 })?;
391 let mut buf = ciphertext[..body_len].to_vec();
392 if crate::romulus_m::romulus_m_decrypt_core(&key_z, &nonce_z, ad, &mut buf, &tag_arr) {
393 Ok(DecryptSemanticOutcome::Success(Zeroizing::new(buf)))
394 } else {
395 buf.zeroize();
396 Ok(DecryptSemanticOutcome::AuthenticationFailed)
397 }
398 }
399}