Skip to main content

lib_q_aead/
romulus_m.rs

1//! Romulus-M AEAD — registry-facing type.
2
3use alloc::boxed::Box;
4use alloc::vec::Vec;
5
6use lib_q_core::{
7    Aead,
8    AeadDecryptSemantic,
9    AeadKey,
10    Algorithm,
11    DecryptSemanticOutcome,
12    Nonce,
13    Result,
14};
15
16use crate::metadata::{
17    AeadMetadata,
18    AeadWithMetadata,
19};
20
21/// Romulus-M (nonce-misuse-resistant AEAD) for the lib-Q AEAD registry.
22pub struct RomulusMAead {
23    metadata: &'static AeadMetadata,
24    inner: lib_q_romulus::RomulusMAead,
25}
26
27impl RomulusMAead {
28    pub fn new() -> Self {
29        Self {
30            metadata: crate::metadata::get_metadata(Algorithm::RomulusM)
31                .expect("Romulus-M metadata"),
32            inner: lib_q_romulus::RomulusMAead::new(),
33        }
34    }
35}
36
37impl Aead for RomulusMAead {
38    fn encrypt(
39        &self,
40        key: &AeadKey,
41        nonce: &Nonce,
42        plaintext: &[u8],
43        associated_data: Option<&[u8]>,
44    ) -> Result<Vec<u8>> {
45        self.validate_key(key)?;
46        self.validate_nonce(nonce)?;
47        crate::security::validation::validate_plaintext(plaintext)?;
48        let ad = associated_data.unwrap_or(&[]);
49        crate::security::validation::validate_associated_data(ad)?;
50        self.inner.encrypt(key, nonce, plaintext, Some(ad))
51    }
52
53    fn decrypt(
54        &self,
55        key: &AeadKey,
56        nonce: &Nonce,
57        ciphertext: &[u8],
58        associated_data: Option<&[u8]>,
59    ) -> Result<Vec<u8>> {
60        self.validate_key(key)?;
61        self.validate_nonce(nonce)?;
62        self.validate_ciphertext_size(ciphertext.len())?;
63        crate::security::validation::validate_ciphertext(ciphertext)?;
64        let ad = associated_data.unwrap_or(&[]);
65        crate::security::validation::validate_associated_data(ad)?;
66        self.inner.decrypt(key, nonce, ciphertext, Some(ad))
67    }
68}
69
70impl AeadDecryptSemantic for RomulusMAead {
71    fn decrypt_semantic(
72        &self,
73        key: &AeadKey,
74        nonce: &Nonce,
75        ciphertext: &[u8],
76        associated_data: Option<&[u8]>,
77    ) -> Result<DecryptSemanticOutcome> {
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        let ad = associated_data.unwrap_or(&[]);
83        crate::security::validation::validate_associated_data(ad)?;
84        self.inner
85            .decrypt_semantic(key, nonce, ciphertext, Some(ad))
86    }
87}
88
89impl AeadWithMetadata for RomulusMAead {
90    fn metadata(&self) -> &'static AeadMetadata {
91        self.metadata
92    }
93}
94
95impl Default for RomulusMAead {
96    fn default() -> Self {
97        Self::new()
98    }
99}
100
101impl crate::plugin::AeadPlugin for RomulusMAead {
102    fn algorithm(&self) -> Algorithm {
103        Algorithm::RomulusM
104    }
105
106    fn create(&self) -> Result<Box<dyn AeadWithMetadata>> {
107        Ok(Box::new(Self::new()))
108    }
109
110    fn metadata(&self) -> &'static AeadMetadata {
111        crate::metadata::get_metadata(Algorithm::RomulusM).expect("Romulus-M metadata")
112    }
113
114    fn name(&self) -> &'static str {
115        "Romulus-M"
116    }
117
118    fn version(&self) -> &'static str {
119        "1.3.0"
120    }
121
122    fn description(&self) -> &'static str {
123        "Romulus-M misuse-resistant AEAD (SKINNY-128-384+), 128-bit key/nonce/tag"
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    #[test]
132    fn romulus_m_metadata_matches() {
133        let a = RomulusMAead::new();
134        assert_eq!(a.algorithm(), Algorithm::RomulusM);
135        assert_eq!(a.key_size(), 16);
136        assert_eq!(a.nonce_size(), 16);
137        assert_eq!(a.tag_size(), 16);
138    }
139
140    #[test]
141    fn romulus_m_roundtrip_registry() {
142        let a = RomulusMAead::new();
143        let key = AeadKey::new([7u8; 16].to_vec());
144        let nonce = Nonce::new([8u8; 16].to_vec());
145        let pt = b"hello-romulus-m";
146        let ad = b"ad-bytes";
147        let ct = a
148            .encrypt(&key, &nonce, pt.as_slice(), Some(ad.as_slice()))
149            .expect("encrypt");
150        let out = a
151            .decrypt(&key, &nonce, ct.as_slice(), Some(ad.as_slice()))
152            .expect("decrypt");
153        assert_eq!(out.as_slice(), pt.as_slice());
154    }
155}