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}