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}