Skip to main content

lib_q_aead/
rocca_s.rs

1//! Rocca-S AEAD Implementation
2//!
3//! This module provides the Rocca-S AEAD implementation using the lib-q-rocca-s crate.
4
5#[cfg(feature = "alloc")]
6use alloc::boxed::Box;
7use alloc::vec::Vec;
8
9use lib_q_core::{
10    Aead,
11    AeadDecryptSemantic,
12    AeadKey,
13    Algorithm,
14    DecryptSemanticOutcome,
15    Nonce,
16    Result,
17};
18
19// Plugin trait implementation
20use crate::metadata::{
21    AeadMetadata,
22    AeadWithMetadata,
23};
24
25/// Rocca-S AEAD implementation wrapper
26pub struct RoccaSAead {
27    metadata: &'static AeadMetadata,
28    inner: lib_q_rocca_s::RoccaSAead,
29}
30
31impl RoccaSAead {
32    /// Create a new Rocca-S AEAD instance
33    pub fn new() -> Self {
34        Self {
35            metadata: crate::metadata::get_metadata(Algorithm::RoccaS)
36                .expect("Rocca-S metadata not found"),
37            inner: lib_q_rocca_s::RoccaSAead::new(),
38        }
39    }
40}
41
42impl Aead for RoccaSAead {
43    fn encrypt(
44        &self,
45        key: &AeadKey,
46        nonce: &Nonce,
47        plaintext: &[u8],
48        associated_data: Option<&[u8]>,
49    ) -> Result<Vec<u8>> {
50        self.validate_key(key)?;
51        self.validate_nonce(nonce)?;
52        crate::security::validation::validate_plaintext(plaintext)?;
53
54        let associated_data = associated_data.unwrap_or(&[]);
55        crate::security::validation::validate_associated_data(associated_data)?;
56
57        #[cfg(feature = "rocca-s")]
58        {
59            self.inner
60                .encrypt(key, nonce, plaintext, Some(associated_data))
61        }
62
63        #[cfg(not(feature = "rocca-s"))]
64        {
65            Err(lib_q_core::Error::NotImplemented {
66                feature: "Rocca-S AEAD implementation requires 'rocca-s' feature",
67            })
68        }
69    }
70
71    fn decrypt(
72        &self,
73        key: &AeadKey,
74        nonce: &Nonce,
75        ciphertext: &[u8],
76        associated_data: Option<&[u8]>,
77    ) -> Result<Vec<u8>> {
78        self.validate_key(key)?;
79        self.validate_nonce(nonce)?;
80        self.validate_ciphertext_size(ciphertext.len())?;
81        crate::security::validation::validate_ciphertext(ciphertext)?;
82
83        let associated_data = associated_data.unwrap_or(&[]);
84        crate::security::validation::validate_associated_data(associated_data)?;
85
86        #[cfg(feature = "rocca-s")]
87        {
88            self.inner
89                .decrypt(key, nonce, ciphertext, Some(associated_data))
90        }
91
92        #[cfg(not(feature = "rocca-s"))]
93        {
94            Err(lib_q_core::Error::NotImplemented {
95                feature: "Rocca-S AEAD implementation requires 'rocca-s' feature",
96            })
97        }
98    }
99}
100
101impl AeadDecryptSemantic for RoccaSAead {
102    fn decrypt_semantic(
103        &self,
104        key: &AeadKey,
105        nonce: &Nonce,
106        ciphertext: &[u8],
107        associated_data: Option<&[u8]>,
108    ) -> Result<DecryptSemanticOutcome> {
109        self.validate_key(key)?;
110        self.validate_nonce(nonce)?;
111        self.validate_ciphertext_size(ciphertext.len())?;
112        crate::security::validation::validate_ciphertext(ciphertext)?;
113
114        let associated_data = associated_data.unwrap_or(&[]);
115        crate::security::validation::validate_associated_data(associated_data)?;
116
117        #[cfg(feature = "rocca-s")]
118        {
119            self.inner
120                .decrypt_semantic(key, nonce, ciphertext, Some(associated_data))
121        }
122
123        #[cfg(not(feature = "rocca-s"))]
124        {
125            Err(lib_q_core::Error::NotImplemented {
126                feature: "Rocca-S AEAD implementation requires 'rocca-s' feature",
127            })
128        }
129    }
130}
131
132impl AeadWithMetadata for RoccaSAead {
133    fn metadata(&self) -> &'static AeadMetadata {
134        self.metadata
135    }
136}
137
138impl Default for RoccaSAead {
139    fn default() -> Self {
140        Self::new()
141    }
142}
143
144// Implement the plugin trait.
145impl crate::plugin::AeadPlugin for RoccaSAead {
146    fn algorithm(&self) -> Algorithm {
147        Algorithm::RoccaS
148    }
149
150    fn create(&self) -> Result<Box<dyn AeadWithMetadata>> {
151        Ok(Box::new(Self::new()))
152    }
153
154    fn metadata(&self) -> &'static AeadMetadata {
155        crate::metadata::get_metadata(Algorithm::RoccaS).expect("Metadata not found for algorithm")
156    }
157
158    fn name(&self) -> &'static str {
159        "Rocca-S AEAD"
160    }
161
162    fn version(&self) -> &'static str {
163        "1.0.0"
164    }
165
166    fn description(&self) -> &'static str {
167        "High-throughput AES-round AEAD (IETF draft-nakano-rocca-s)"
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[test]
176    fn test_rocca_s_creation() {
177        let aead = RoccaSAead::new();
178        assert_eq!(aead.algorithm(), Algorithm::RoccaS);
179        assert_eq!(aead.key_size(), 32);
180        assert_eq!(aead.nonce_size(), 16);
181        assert_eq!(aead.tag_size(), 32);
182        assert_eq!(aead.security_level(), 1);
183    }
184
185    #[test]
186    fn test_rocca_s_metadata() {
187        let aead = RoccaSAead::new();
188        let metadata = aead.metadata();
189        assert_eq!(metadata.algorithm, Algorithm::RoccaS);
190        assert_eq!(metadata.name, "Rocca-S");
191        assert_eq!(metadata.key_size, 32);
192        assert_eq!(metadata.nonce_size, 16);
193        assert_eq!(metadata.tag_size, 32);
194        assert_eq!(metadata.security_level, 1);
195    }
196
197    #[test]
198    fn test_rocca_s_validation() {
199        let aead = RoccaSAead::new();
200        let key = AeadKey::new(vec![0u8; 32]);
201        assert!(aead.validate_key(&key).is_ok());
202        let invalid_key = AeadKey::new(vec![0u8; 16]);
203        assert!(aead.validate_key(&invalid_key).is_err());
204        let nonce = Nonce::new(vec![0u8; 16]);
205        assert!(aead.validate_nonce(&nonce).is_ok());
206        let invalid_nonce = Nonce::new(vec![0u8; 12]);
207        assert!(aead.validate_nonce(&invalid_nonce).is_err());
208    }
209
210    #[cfg(feature = "rocca-s")]
211    #[test]
212    fn test_rocca_s_encrypt_decrypt() {
213        let aead = RoccaSAead::new();
214        let key = AeadKey::new(vec![0u8; 32]);
215        let nonce = Nonce::new(vec![0u8; 16]);
216        let plaintext = b"Hello, World!";
217        let ad = b"metadata";
218
219        let ciphertext = aead
220            .encrypt(&key, &nonce, plaintext, Some(ad.as_slice()))
221            .unwrap();
222        assert_eq!(ciphertext.len(), plaintext.len() + aead.tag_size());
223
224        let decrypted = aead
225            .decrypt(&key, &nonce, &ciphertext, Some(ad.as_slice()))
226            .unwrap();
227        assert_eq!(decrypted, plaintext);
228    }
229
230    #[cfg(feature = "rocca-s")]
231    #[test]
232    fn test_rocca_s_authentication_failure() {
233        let aead = RoccaSAead::new();
234        let key = AeadKey::new(vec![0u8; 32]);
235        let nonce = Nonce::new(vec![0u8; 16]);
236        let ciphertext = aead.encrypt(&key, &nonce, b"Hello, World!", None).unwrap();
237        let mut tampered = ciphertext.clone();
238        tampered[0] ^= 0xFF;
239        let result = aead.decrypt(&key, &nonce, &tampered, None);
240        assert!(matches!(
241            result,
242            Err(lib_q_core::Error::VerificationFailed { .. })
243        ));
244    }
245
246    #[cfg(feature = "rocca-s")]
247    #[test]
248    fn test_rocca_s_official_kat() {
249        // IETF draft-nakano-rocca-s all-zero vector via the umbrella wrapper.
250        let aead = RoccaSAead::new();
251        let key = AeadKey::new(vec![0u8; 32]);
252        let nonce = Nonce::new(vec![0u8; 16]);
253        let ad = vec![0u8; 32];
254        let pt = vec![0u8; 64];
255        let ct = aead.encrypt(&key, &nonce, &pt, Some(&ad)).unwrap();
256        let tag = &ct[64..];
257        let expected_tag = [
258            0x8D, 0xF9, 0x34, 0xD1, 0x48, 0x37, 0x10, 0xC9, 0x41, 0x0F, 0x6A, 0x08, 0x9C, 0x4C,
259            0xED, 0x97, 0x91, 0x90, 0x1B, 0x7E, 0x2E, 0x66, 0x12, 0x06, 0x20, 0x2D, 0xB2, 0xCC,
260            0x7A, 0x24, 0xA3, 0x86,
261        ];
262        assert_eq!(tag, expected_tag);
263    }
264}