1#![deny(unsafe_code)]
4
5extern crate alloc;
6
7use alloc::string::ToString;
8use alloc::vec::Vec;
9
10use aead::generic_array::GenericArray;
11use aead::{
12 AeadInPlace,
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_ref = GenericArray::from_slice(nonce_z.as_slice());
87 let cipher = {
88 let kz = stack_secret::zeroizing_copy_16(kb);
89 RomulusN::new(GenericArray::from_slice(kz.as_slice()))
90 };
91 let mut buf = plaintext.to_vec();
92 let tag = cipher
93 .encrypt_in_place_detached(nonce_ref, ad, &mut buf)
94 .map_err(|_| Error::EncryptionFailed {
95 operation: "Romulus-N encrypt".to_string(),
96 })?;
97 buf.extend_from_slice(tag.as_slice());
98 Ok(buf)
99 }
100
101 fn decrypt(
102 &self,
103 key: &AeadKey,
104 nonce: &Nonce,
105 ciphertext: &[u8],
106 associated_data: Option<&[u8]>,
107 ) -> Result<Vec<u8>> {
108 let kb = key.as_bytes();
109 if kb.len() != Self::key_size() {
110 return Err(Error::InvalidKeySize {
111 expected: Self::key_size(),
112 actual: kb.len(),
113 });
114 }
115 let nb = nonce.as_bytes();
116 if nb.len() != Self::nonce_size() {
117 return Err(Error::InvalidNonceSize {
118 expected: Self::nonce_size(),
119 actual: nb.len(),
120 });
121 }
122 if ciphertext.len() < Self::tag_size() {
123 return Err(Error::aead_ciphertext_shorter_than_tag(
124 Self::tag_size(),
125 ciphertext.len(),
126 ));
127 }
128 let ad = associated_data.unwrap_or(&[]);
129 let body_len = ciphertext.len() - Self::tag_size();
130 let key_z = stack_secret::zeroizing_copy_16(kb);
131 let nonce_z = stack_secret::zeroizing_copy_16(nb);
132 let tag_arr =
133 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
134 Error::VerificationFailed {
135 operation: "AEAD tag verification".to_string(),
136 }
137 })?;
138 let mut buf = ciphertext[..body_len].to_vec();
139 crate::romulus_n::romulus_n_decrypt(&key_z, &nonce_z, ad, &mut buf, &tag_arr).map_err(
140 |_| Error::VerificationFailed {
141 operation: "AEAD tag verification".to_string(),
142 },
143 )?;
144 Ok(buf)
145 }
146}
147
148impl AeadDecryptSemantic for RomulusNAead {
149 fn decrypt_semantic(
150 &self,
151 key: &AeadKey,
152 nonce: &Nonce,
153 ciphertext: &[u8],
154 associated_data: Option<&[u8]>,
155 ) -> Result<DecryptSemanticOutcome> {
156 let kb = key.as_bytes();
157 if kb.len() != Self::key_size() {
158 return Err(Error::InvalidKeySize {
159 expected: Self::key_size(),
160 actual: kb.len(),
161 });
162 }
163 let nb = nonce.as_bytes();
164 if nb.len() != Self::nonce_size() {
165 return Err(Error::InvalidNonceSize {
166 expected: Self::nonce_size(),
167 actual: nb.len(),
168 });
169 }
170 if ciphertext.len() < Self::tag_size() {
171 return Err(Error::aead_ciphertext_shorter_than_tag(
172 Self::tag_size(),
173 ciphertext.len(),
174 ));
175 }
176 let ad = associated_data.unwrap_or(&[]);
177 let body_len = ciphertext.len() - Self::tag_size();
178 let key_z = stack_secret::zeroizing_copy_16(kb);
179 let nonce_z = stack_secret::zeroizing_copy_16(nb);
180 let tag_arr =
181 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
182 Error::VerificationFailed {
183 operation: "AEAD tag verification".to_string(),
184 }
185 })?;
186 let mut buf = ciphertext[..body_len].to_vec();
187 if crate::romulus_n::romulus_n_decrypt_core(&key_z, &nonce_z, ad, &mut buf, &tag_arr) {
188 Ok(DecryptSemanticOutcome::Success(Zeroizing::new(buf)))
189 } else {
190 buf.zeroize();
191 Ok(DecryptSemanticOutcome::AuthenticationFailed)
192 }
193 }
194}
195
196pub struct RomulusMAead;
198
199impl RomulusMAead {
200 pub const fn new() -> Self {
201 Self
202 }
203
204 pub const fn key_size() -> usize {
205 16
206 }
207
208 pub const fn nonce_size() -> usize {
209 16
210 }
211
212 pub const fn tag_size() -> usize {
213 16
214 }
215}
216
217impl Default for RomulusMAead {
218 fn default() -> Self {
219 Self::new()
220 }
221}
222
223impl Aead for RomulusMAead {
224 fn encrypt(
225 &self,
226 key: &AeadKey,
227 nonce: &Nonce,
228 plaintext: &[u8],
229 associated_data: Option<&[u8]>,
230 ) -> Result<Vec<u8>> {
231 let kb = key.as_bytes();
232 if kb.len() != Self::key_size() {
233 return Err(Error::InvalidKeySize {
234 expected: Self::key_size(),
235 actual: kb.len(),
236 });
237 }
238 let nb = nonce.as_bytes();
239 if nb.len() != Self::nonce_size() {
240 return Err(Error::InvalidNonceSize {
241 expected: Self::nonce_size(),
242 actual: nb.len(),
243 });
244 }
245 let ad = associated_data.unwrap_or(&[]);
246 let nonce_z = stack_secret::zeroizing_copy_16(nb);
247 let nonce_ref = GenericArray::from_slice(nonce_z.as_slice());
248 let cipher = {
249 let kz = stack_secret::zeroizing_copy_16(kb);
250 RomulusM::new(GenericArray::from_slice(kz.as_slice()))
251 };
252 let mut buf = plaintext.to_vec();
253 let tag = cipher
254 .encrypt_in_place_detached(nonce_ref, ad, &mut buf)
255 .map_err(|_| Error::EncryptionFailed {
256 operation: "Romulus-M encrypt".to_string(),
257 })?;
258 buf.extend_from_slice(tag.as_slice());
259 Ok(buf)
260 }
261
262 fn decrypt(
263 &self,
264 key: &AeadKey,
265 nonce: &Nonce,
266 ciphertext: &[u8],
267 associated_data: Option<&[u8]>,
268 ) -> Result<Vec<u8>> {
269 let kb = key.as_bytes();
270 if kb.len() != Self::key_size() {
271 return Err(Error::InvalidKeySize {
272 expected: Self::key_size(),
273 actual: kb.len(),
274 });
275 }
276 let nb = nonce.as_bytes();
277 if nb.len() != Self::nonce_size() {
278 return Err(Error::InvalidNonceSize {
279 expected: Self::nonce_size(),
280 actual: nb.len(),
281 });
282 }
283 if ciphertext.len() < Self::tag_size() {
284 return Err(Error::aead_ciphertext_shorter_than_tag(
285 Self::tag_size(),
286 ciphertext.len(),
287 ));
288 }
289 let ad = associated_data.unwrap_or(&[]);
290 let body_len = ciphertext.len() - Self::tag_size();
291 let key_z = stack_secret::zeroizing_copy_16(kb);
292 let nonce_z = stack_secret::zeroizing_copy_16(nb);
293 let tag_arr =
294 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
295 Error::VerificationFailed {
296 operation: "AEAD tag verification".to_string(),
297 }
298 })?;
299 let mut buf = ciphertext[..body_len].to_vec();
300 crate::romulus_m::romulus_m_decrypt(&key_z, &nonce_z, ad, &mut buf, &tag_arr).map_err(
301 |_| Error::VerificationFailed {
302 operation: "AEAD tag verification".to_string(),
303 },
304 )?;
305 Ok(buf)
306 }
307}
308
309impl AeadDecryptSemantic for RomulusMAead {
310 fn decrypt_semantic(
311 &self,
312 key: &AeadKey,
313 nonce: &Nonce,
314 ciphertext: &[u8],
315 associated_data: Option<&[u8]>,
316 ) -> Result<DecryptSemanticOutcome> {
317 let kb = key.as_bytes();
318 if kb.len() != Self::key_size() {
319 return Err(Error::InvalidKeySize {
320 expected: Self::key_size(),
321 actual: kb.len(),
322 });
323 }
324 let nb = nonce.as_bytes();
325 if nb.len() != Self::nonce_size() {
326 return Err(Error::InvalidNonceSize {
327 expected: Self::nonce_size(),
328 actual: nb.len(),
329 });
330 }
331 if ciphertext.len() < Self::tag_size() {
332 return Err(Error::aead_ciphertext_shorter_than_tag(
333 Self::tag_size(),
334 ciphertext.len(),
335 ));
336 }
337 let ad = associated_data.unwrap_or(&[]);
338 let body_len = ciphertext.len() - Self::tag_size();
339 let key_z = stack_secret::zeroizing_copy_16(kb);
340 let nonce_z = stack_secret::zeroizing_copy_16(nb);
341 let tag_arr =
342 <[u8; stack_secret::LEN]>::try_from(&ciphertext[body_len..]).map_err(|_| {
343 Error::VerificationFailed {
344 operation: "AEAD tag verification".to_string(),
345 }
346 })?;
347 let mut buf = ciphertext[..body_len].to_vec();
348 if crate::romulus_m::romulus_m_decrypt_core(&key_z, &nonce_z, ad, &mut buf, &tag_arr) {
349 Ok(DecryptSemanticOutcome::Success(Zeroizing::new(buf)))
350 } else {
351 buf.zeroize();
352 Ok(DecryptSemanticOutcome::AuthenticationFailed)
353 }
354 }
355}