1#![cfg_attr(not(feature = "std"), no_std)]
42#![warn(missing_docs)]
43#![warn(clippy::all)]
44
45#[cfg(not(feature = "std"))]
46extern crate alloc;
47
48pub mod dsa;
49pub mod error;
50pub mod kem;
51pub mod keys;
52pub mod symmetric;
53pub mod utils;
54
55pub use error::{Error, Result};
56
57use serde::{Deserialize, Serialize};
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
61pub enum SecurityLevel {
62 Level3,
64 #[default]
66 Level5,
67}
68
69impl SecurityLevel {
70 pub fn algorithm_names(&self) -> AlgorithmNames {
72 match self {
73 SecurityLevel::Level3 => AlgorithmNames {
74 kem: "ML-KEM-768",
75 dsa: "ML-DSA-65",
76 },
77 SecurityLevel::Level5 => AlgorithmNames {
78 kem: "ML-KEM-1024",
79 dsa: "ML-DSA-87",
80 },
81 }
82 }
83
84 pub fn as_u8(&self) -> u8 {
86 match self {
87 SecurityLevel::Level3 => 3,
88 SecurityLevel::Level5 => 5,
89 }
90 }
91}
92
93impl std::fmt::Display for SecurityLevel {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 match self {
96 SecurityLevel::Level3 => write!(f, "Level 3 (ML-KEM-768 + ML-DSA-65)"),
97 SecurityLevel::Level5 => write!(f, "Level 5 (ML-KEM-1024 + ML-DSA-87)"),
98 }
99 }
100}
101
102#[derive(Debug, Clone, Copy)]
104pub struct AlgorithmNames {
105 pub kem: &'static str,
107 pub dsa: &'static str,
109}
110
111#[derive(Clone, Serialize, Deserialize)]
113pub struct KeySet {
114 pub kem: kem::KemKeyPair,
116 pub dsa: dsa::DsaKeyPair,
118 pub security_level: SecurityLevel,
120 pub generated_at: i64,
122}
123
124impl KeySet {
125 pub fn generate(security_level: SecurityLevel) -> Result<Self> {
127 let kem_keys = kem::generate_keypair(security_level)?;
128 let dsa_keys = dsa::generate_keypair(security_level)?;
129
130 Ok(Self {
131 kem: kem_keys,
132 dsa: dsa_keys,
133 security_level,
134 generated_at: chrono::Utc::now().timestamp(),
135 })
136 }
137
138 pub fn public_keys(&self) -> PublicKeySet {
140 PublicKeySet {
141 kem_public_key: self.kem.public_key.clone(),
142 dsa_public_key: self.dsa.public_key.clone(),
143 security_level: self.security_level,
144 }
145 }
146}
147
148#[derive(Clone, Serialize, Deserialize)]
150pub struct PublicKeySet {
151 pub kem_public_key: Vec<u8>,
153 pub dsa_public_key: Vec<u8>,
155 pub security_level: SecurityLevel,
157}
158
159pub fn encrypt_and_sign(
163 data: &[u8],
164 recipient_kem_public_key: &[u8],
165 sender_dsa_secret_key: &[u8],
166 security_level: SecurityLevel,
167) -> Result<EncryptedSignedPayload> {
168 let (kem_ciphertext, shared_secret) =
170 kem::encapsulate_with_level(recipient_kem_public_key, security_level)?;
171
172 let encrypted = symmetric::encrypt_with_secret(data, &shared_secret)?;
174
175 let mut sign_data = Vec::new();
177 sign_data.extend_from_slice(&encrypted.ciphertext);
178 sign_data.extend_from_slice(&encrypted.nonce);
179 sign_data.extend_from_slice(&kem_ciphertext);
180
181 let signature = dsa::sign_with_level(&sign_data, sender_dsa_secret_key, security_level)?;
183
184 Ok(EncryptedSignedPayload {
185 kem_ciphertext,
186 ciphertext: encrypted.ciphertext,
187 nonce: encrypted.nonce,
188 signature,
189 security_level,
190 })
191}
192
193pub fn verify_and_decrypt(
195 payload: &EncryptedSignedPayload,
196 sender_dsa_public_key: &[u8],
197 recipient_kem_secret_key: &[u8],
198) -> Result<Vec<u8>> {
199 let mut sign_data = Vec::new();
201 sign_data.extend_from_slice(&payload.ciphertext);
202 sign_data.extend_from_slice(&payload.nonce);
203 sign_data.extend_from_slice(&payload.kem_ciphertext);
204
205 let valid = dsa::verify_with_level(
207 &sign_data,
208 &payload.signature,
209 sender_dsa_public_key,
210 payload.security_level,
211 )?;
212
213 if !valid {
214 return Err(Error::SignatureVerificationFailed);
215 }
216
217 let shared_secret = kem::decapsulate_with_level(
219 &payload.kem_ciphertext,
220 recipient_kem_secret_key,
221 payload.security_level,
222 )?;
223
224 let encrypted = symmetric::EncryptedData {
226 ciphertext: payload.ciphertext.clone(),
227 nonce: payload.nonce.clone(),
228 };
229
230 symmetric::decrypt_with_secret(&encrypted, &shared_secret)
231}
232
233#[derive(Clone, Serialize, Deserialize)]
235pub struct EncryptedSignedPayload {
236 pub kem_ciphertext: Vec<u8>,
238 pub ciphertext: Vec<u8>,
240 pub nonce: Vec<u8>,
242 pub signature: Vec<u8>,
244 pub security_level: SecurityLevel,
246}
247
248pub fn version() -> &'static str {
250 env!("CARGO_PKG_VERSION")
251}
252
253pub fn algorithm_info(level: SecurityLevel) -> AlgorithmInfo {
255 let names = level.algorithm_names();
256 AlgorithmInfo {
257 kem: names.kem.to_string(),
258 dsa: names.dsa.to_string(),
259 symmetric: "AES-256-GCM".to_string(),
260 hash: "SHA3-256/512".to_string(),
261 security_level: level,
262 nist_fips: vec![
263 "FIPS 203 (ML-KEM)".to_string(),
264 "FIPS 204 (ML-DSA)".to_string(),
265 ],
266 }
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct AlgorithmInfo {
272 pub kem: String,
274 pub dsa: String,
276 pub symmetric: String,
278 pub hash: String,
280 pub security_level: SecurityLevel,
282 pub nist_fips: Vec<String>,
284}
285
286#[cfg(test)]
287mod tests {
288 use super::*;
289
290 #[test]
291 fn test_security_level_display() {
292 assert!(SecurityLevel::Level5.to_string().contains("Level 5"));
293 assert!(SecurityLevel::Level3.to_string().contains("Level 3"));
294 }
295
296 #[test]
297 fn test_key_set_generation() {
298 let keys = KeySet::generate(SecurityLevel::Level5).unwrap();
299 assert!(!keys.kem.public_key.is_empty());
300 assert!(!keys.dsa.public_key.is_empty());
301 assert_eq!(keys.security_level, SecurityLevel::Level5);
302 }
303
304 #[test]
305 fn test_encrypt_and_sign_verify_and_decrypt() {
306 let alice = KeySet::generate(SecurityLevel::Level5).unwrap();
307 let bob = KeySet::generate(SecurityLevel::Level5).unwrap();
308
309 let message = b"Hello, quantum-safe world!";
310
311 let payload = encrypt_and_sign(
313 message,
314 &bob.kem.public_key,
315 &alice.dsa.secret_key,
316 SecurityLevel::Level5,
317 )
318 .unwrap();
319
320 let decrypted =
322 verify_and_decrypt(&payload, &alice.dsa.public_key, &bob.kem.secret_key).unwrap();
323
324 assert_eq!(message.as_slice(), decrypted.as_slice());
325 }
326
327 #[test]
328 fn test_algorithm_info() {
329 let info = algorithm_info(SecurityLevel::Level5);
330 assert_eq!(info.kem, "ML-KEM-1024");
331 assert_eq!(info.dsa, "ML-DSA-87");
332 }
333}