bc_components/mlkem/
mlkem_level.rs

1use dcbor::prelude::*;
2use pqcrypto_mlkem::*;
3
4use super::{MLKEMPrivateKey, MLKEMPublicKey};
5use crate::{Error, Result};
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,
14/// performance, 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
21/// used 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                (
54                    MLKEMPrivateKey::MLKEM512(sk.into()),
55                    MLKEMPublicKey::MLKEM512(pk.into()),
56                )
57            }
58            MLKEM::MLKEM768 => {
59                let (pk, sk) = mlkem768::keypair();
60                (
61                    MLKEMPrivateKey::MLKEM768(sk.into()),
62                    MLKEMPublicKey::MLKEM768(pk.into()),
63                )
64            }
65            MLKEM::MLKEM1024 => {
66                let (pk, sk) = mlkem1024::keypair();
67                (
68                    MLKEMPrivateKey::MLKEM1024(sk.into()),
69                    MLKEMPublicKey::MLKEM1024(pk.into()),
70                )
71            }
72        }
73    }
74
75    /// Returns the size of a private key in bytes for this security level.
76    ///
77    /// # Returns
78    /// - `MLKEM512`: 1632 bytes
79    /// - `MLKEM768`: 2400 bytes
80    /// - `MLKEM1024`: 3168 bytes
81    pub fn private_key_size(&self) -> usize {
82        match self {
83            MLKEM::MLKEM512 => mlkem512::secret_key_bytes(),
84            MLKEM::MLKEM768 => mlkem768::secret_key_bytes(),
85            MLKEM::MLKEM1024 => mlkem1024::secret_key_bytes(),
86        }
87    }
88
89    /// Returns the size of a public key in bytes for this security level.
90    ///
91    /// # Returns
92    /// - `MLKEM512`: 800 bytes
93    /// - `MLKEM768`: 1184 bytes
94    /// - `MLKEM1024`: 1568 bytes
95    pub fn public_key_size(&self) -> usize {
96        match self {
97            MLKEM::MLKEM512 => mlkem512::public_key_bytes(),
98            MLKEM::MLKEM768 => mlkem768::public_key_bytes(),
99            MLKEM::MLKEM1024 => mlkem1024::public_key_bytes(),
100        }
101    }
102
103    /// Returns the size of a shared secret in bytes for this security level.
104    ///
105    /// This is 32 bytes for all security levels.
106    pub fn shared_secret_size(&self) -> usize {
107        match self {
108            MLKEM::MLKEM512 => mlkem512::shared_secret_bytes(),
109            MLKEM::MLKEM768 => mlkem768::shared_secret_bytes(),
110            MLKEM::MLKEM1024 => mlkem1024::shared_secret_bytes(),
111        }
112    }
113
114    /// Returns the size of a ciphertext in bytes for this security level.
115    ///
116    /// # Returns
117    /// - `MLKEM512`: 768 bytes
118    /// - `MLKEM768`: 1088 bytes
119    /// - `MLKEM1024`: 1568 bytes
120    pub fn ciphertext_size(&self) -> usize {
121        match self {
122            MLKEM::MLKEM512 => mlkem512::ciphertext_bytes(),
123            MLKEM::MLKEM768 => mlkem768::ciphertext_bytes(),
124            MLKEM::MLKEM1024 => mlkem1024::ciphertext_bytes(),
125        }
126    }
127}
128
129/// Converts an `MLKEM` value to CBOR.
130impl From<MLKEM> for CBOR {
131    /// Converts to the numeric security level value (512, 768, or 1024).
132    fn from(mlkem: MLKEM) -> Self { (mlkem as u32).into() }
133}
134
135/// Attempts to convert CBOR to an `MLKEM` value.
136impl TryFrom<CBOR> for MLKEM {
137    type Error = Error;
138
139    /// Converts from a CBOR-encoded security level (512, 768, or 1024).
140    ///
141    /// # Errors
142    /// Returns an error if the CBOR value doesn't represent a valid ML-KEM
143    /// level.
144    fn try_from(cbor: CBOR) -> Result<Self> {
145        let level = u32::try_from(cbor)?;
146        match level {
147            512 => Ok(MLKEM::MLKEM512),
148            768 => Ok(MLKEM::MLKEM768),
149            1024 => Ok(MLKEM::MLKEM1024),
150            _ => Err(Error::post_quantum(format!(
151                "Invalid MLKEM level: {}",
152                level
153            ))),
154        }
155    }
156}