bc_components/mlkem/
mlkem_level.rs

1use anyhow::{ bail, Error, Result };
2use pqcrypto_mlkem::*;
3use dcbor::prelude::*;
4
5use super::{ MLKEMPrivateKey, MLKEMPublicKey };
6
7/// Security levels for the ML-KEM post-quantum key encapsulation mechanism.
8///
9/// ML-KEM (Module Lattice-based Key Encapsulation Mechanism) is a post-quantum
10/// key encapsulation mechanism standardized by NIST. It provides resistance
11/// against attacks from both classical and quantum computers.
12///
13/// Each security level offers different trade-offs between security, performance,
14/// and key/ciphertext sizes:
15///
16/// - `MLKEM512`: NIST security level 1 (roughly equivalent to AES-128)
17/// - `MLKEM768`: NIST security level 3 (roughly equivalent to AES-192)
18/// - `MLKEM1024`: NIST security level 5 (roughly equivalent to AES-256)
19///
20/// The numeric values (512, 768, 1024) correspond to the parameter sets and are used
21/// in CBOR serialization.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23#[repr(u32)]
24pub enum MLKEM {
25    /// ML-KEM-512 (NIST security level 1, roughly equivalent to AES-128)
26    MLKEM512 = 512,
27    /// ML-KEM-768 (NIST security level 3, roughly equivalent to AES-192)
28    MLKEM768 = 768,
29    /// ML-KEM-1024 (NIST security level 5, roughly equivalent to AES-256)
30    MLKEM1024 = 1024,
31}
32
33impl MLKEM {
34    /// The size of a shared secret in bytes (32 bytes for all security levels).
35    pub const SHARED_SECRET_SIZE: usize = mlkem512::shared_secret_bytes();
36
37    /// Generates a new ML-KEM keypair with the specified security level.
38    ///
39    /// # Returns
40    /// A tuple containing the private key and public key.
41    ///
42    /// # Examples
43    ///
44    /// ```
45    /// use bc_components::MLKEM;
46    ///
47    /// let (private_key, public_key) = MLKEM::MLKEM512.keypair();
48    /// ```
49    pub fn keypair(self) -> (MLKEMPrivateKey, MLKEMPublicKey) {
50        match self {
51            MLKEM::MLKEM512 => {
52                let (pk, sk) = mlkem512::keypair();
53                (MLKEMPrivateKey::MLKEM512(sk.into()), MLKEMPublicKey::MLKEM512(pk.into()))
54            }
55            MLKEM::MLKEM768 => {
56                let (pk, sk) = mlkem768::keypair();
57                (MLKEMPrivateKey::MLKEM768(sk.into()), MLKEMPublicKey::MLKEM768(pk.into()))
58            }
59            MLKEM::MLKEM1024 => {
60                let (pk, sk) = mlkem1024::keypair();
61                (MLKEMPrivateKey::MLKEM1024(sk.into()), MLKEMPublicKey::MLKEM1024(pk.into()))
62            }
63        }
64    }
65
66    /// Returns the size of a private key in bytes for this security level.
67    ///
68    /// # Returns
69    /// - `MLKEM512`: 1632 bytes
70    /// - `MLKEM768`: 2400 bytes
71    /// - `MLKEM1024`: 3168 bytes
72    pub fn private_key_size(&self) -> usize {
73        match self {
74            MLKEM::MLKEM512 => mlkem512::secret_key_bytes(),
75            MLKEM::MLKEM768 => mlkem768::secret_key_bytes(),
76            MLKEM::MLKEM1024 => mlkem1024::secret_key_bytes(),
77        }
78    }
79
80    /// Returns the size of a public key in bytes for this security level.
81    ///
82    /// # Returns
83    /// - `MLKEM512`: 800 bytes
84    /// - `MLKEM768`: 1184 bytes
85    /// - `MLKEM1024`: 1568 bytes
86    pub fn public_key_size(&self) -> usize {
87        match self {
88            MLKEM::MLKEM512 => mlkem512::public_key_bytes(),
89            MLKEM::MLKEM768 => mlkem768::public_key_bytes(),
90            MLKEM::MLKEM1024 => mlkem1024::public_key_bytes(),
91        }
92    }
93
94    /// Returns the size of a shared secret in bytes for this security level.
95    ///
96    /// This is 32 bytes for all security levels.
97    pub fn shared_secret_size(&self) -> usize {
98        match self {
99            MLKEM::MLKEM512 => mlkem512::shared_secret_bytes(),
100            MLKEM::MLKEM768 => mlkem768::shared_secret_bytes(),
101            MLKEM::MLKEM1024 => mlkem1024::shared_secret_bytes(),
102        }
103    }
104
105    /// Returns the size of a ciphertext in bytes for this security level.
106    ///
107    /// # Returns
108    /// - `MLKEM512`: 768 bytes
109    /// - `MLKEM768`: 1088 bytes
110    /// - `MLKEM1024`: 1568 bytes
111    pub fn ciphertext_size(&self) -> usize {
112        match self {
113            MLKEM::MLKEM512 => mlkem512::ciphertext_bytes(),
114            MLKEM::MLKEM768 => mlkem768::ciphertext_bytes(),
115            MLKEM::MLKEM1024 => mlkem1024::ciphertext_bytes(),
116        }
117    }
118}
119
120/// Converts an `MLKEM` value to CBOR.
121impl From<MLKEM> for CBOR {
122    /// Converts to the numeric security level value (512, 768, or 1024).
123    fn from(mlkem: MLKEM) -> Self {
124        (mlkem as u32).into()
125    }
126}
127
128/// Attempts to convert CBOR to an `MLKEM` value.
129impl TryFrom<CBOR> for MLKEM {
130    type Error = Error;
131
132    /// Converts from a CBOR-encoded security level (512, 768, or 1024).
133    ///
134    /// # Errors
135    /// Returns an error if the CBOR value doesn't represent a valid ML-KEM level.
136    fn try_from(cbor: CBOR) -> Result<Self> {
137        let level = u32::try_from(cbor)?;
138        match level {
139            512 => Ok(MLKEM::MLKEM512),
140            768 => Ok(MLKEM::MLKEM768),
141            1024 => Ok(MLKEM::MLKEM1024),
142            _ => bail!("Invalid MLKEM level: {}", level),
143        }
144    }
145}