bc_components/encapsulation/
encapsulation_private_key.rs

1use bc_ur::prelude::*;
2
3use crate::{
4    Decrypter, EncapsulationCiphertext, EncapsulationScheme, Error,
5    MLKEMPrivateKey, Result, SymmetricKey, X25519PrivateKey, tags,
6};
7
8/// A private key used for key encapsulation mechanisms (KEM).
9///
10/// `EncapsulationPrivateKey` is an enum representing different types of private
11/// keys that can be used for key encapsulation, including:
12///
13/// - X25519: Curve25519-based key exchange
14/// - ML-KEM: Module Lattice-based Key Encapsulation Mechanism at various
15///   security levels
16///
17/// These private keys are used to decrypt (decapsulate) shared secrets that
18/// have been encapsulated with the corresponding public keys.
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub enum EncapsulationPrivateKey {
21    /// An X25519 private key
22    X25519(X25519PrivateKey),
23    /// An ML-KEM private key (post-quantum)
24    MLKEM(MLKEMPrivateKey),
25}
26
27impl EncapsulationPrivateKey {
28    /// Returns the encapsulation scheme associated with this private key.
29    ///
30    /// # Returns
31    ///
32    /// The encapsulation scheme (X25519, MLKEM512, MLKEM768, or MLKEM1024)
33    /// that corresponds to this private key.
34    ///
35    /// # Example
36    ///
37    /// ```
38    /// use bc_components::{
39    ///     EncapsulationPrivateKey, EncapsulationScheme, X25519PrivateKey,
40    /// };
41    ///
42    /// let x25519_private_key = X25519PrivateKey::new();
43    /// let encapsulation_private_key =
44    ///     EncapsulationPrivateKey::X25519(x25519_private_key);
45    /// assert_eq!(
46    ///     encapsulation_private_key.encapsulation_scheme(),
47    ///     EncapsulationScheme::X25519
48    /// );
49    /// ```
50    pub fn encapsulation_scheme(&self) -> EncapsulationScheme {
51        match self {
52            Self::X25519(_) => EncapsulationScheme::X25519,
53            Self::MLKEM(pk) => match pk.level() {
54                crate::MLKEM::MLKEM512 => EncapsulationScheme::MLKEM512,
55                crate::MLKEM::MLKEM768 => EncapsulationScheme::MLKEM768,
56                crate::MLKEM::MLKEM1024 => EncapsulationScheme::MLKEM1024,
57            },
58        }
59    }
60
61    /// Decapsulates a shared secret from a ciphertext using this private key.
62    ///
63    /// This method performs the decapsulation operation for key exchange. It
64    /// takes an `EncapsulationCiphertext` and extracts the shared secret
65    /// that was encapsulated using the corresponding public key.
66    ///
67    /// # Parameters
68    ///
69    /// * `ciphertext` - The encapsulation ciphertext containing the
70    ///   encapsulated shared secret
71    ///
72    /// # Returns
73    ///
74    /// A `Result` containing the decapsulated `SymmetricKey` if successful,
75    /// or an error if the decapsulation fails or if the ciphertext type doesn't
76    /// match the private key type.
77    ///
78    /// # Errors
79    ///
80    /// Returns an error if:
81    /// - The ciphertext type doesn't match the private key type
82    /// - The decapsulation operation fails
83    ///
84    /// # Example
85    ///
86    /// ```
87    /// use bc_components::EncapsulationScheme;
88    ///
89    /// // Generate a key pair
90    /// let (private_key, public_key) = EncapsulationScheme::default().keypair();
91    ///
92    /// // Encapsulate a new shared secret using the public key
93    /// let (secret1, ciphertext) = public_key.encapsulate_new_shared_secret();
94    ///
95    /// // Decapsulate the shared secret using the private key
96    /// let secret2 = private_key.decapsulate_shared_secret(&ciphertext).unwrap();
97    ///
98    /// // The original and decapsulated secrets should match
99    /// assert_eq!(secret1, secret2);
100    /// ```
101    pub fn decapsulate_shared_secret(
102        &self,
103        ciphertext: &EncapsulationCiphertext,
104    ) -> Result<SymmetricKey> {
105        match (self, ciphertext) {
106            (
107                EncapsulationPrivateKey::X25519(private_key),
108                EncapsulationCiphertext::X25519(public_key),
109            ) => Ok(private_key.shared_key_with(public_key)),
110            (
111                EncapsulationPrivateKey::MLKEM(private_key),
112                EncapsulationCiphertext::MLKEM(ciphertext),
113            ) => private_key.decapsulate_shared_secret(ciphertext),
114            _ => Err(Error::crypto(format!(
115                "Mismatched key encapsulation types. private key: {:?}, ciphertext: {:?}",
116                self.encapsulation_scheme(),
117                ciphertext.encapsulation_scheme()
118            ))),
119        }
120    }
121}
122
123/// Implementation of the `Decrypter` trait for `EncapsulationPrivateKey`.
124///
125/// This allows `EncapsulationPrivateKey` to be used with the generic decryption
126/// interface defined by the `Decrypter` trait.
127impl Decrypter for EncapsulationPrivateKey {
128    fn encapsulation_private_key(&self) -> EncapsulationPrivateKey {
129        self.clone()
130    }
131
132    fn decapsulate_shared_secret(
133        &self,
134        ciphertext: &EncapsulationCiphertext,
135    ) -> Result<SymmetricKey> {
136        self.decapsulate_shared_secret(ciphertext)
137    }
138}
139
140/// Conversion from `EncapsulationPrivateKey` to CBOR for serialization.
141impl From<EncapsulationPrivateKey> for CBOR {
142    fn from(private_key: EncapsulationPrivateKey) -> Self {
143        match private_key {
144            EncapsulationPrivateKey::X25519(private_key) => private_key.into(),
145            EncapsulationPrivateKey::MLKEM(private_key) => private_key.into(),
146        }
147    }
148}
149
150/// Conversion from CBOR to `EncapsulationPrivateKey` for deserialization.
151impl TryFrom<CBOR> for EncapsulationPrivateKey {
152    type Error = dcbor::Error;
153
154    fn try_from(cbor: CBOR) -> std::result::Result<Self, dcbor::Error> {
155        match cbor.as_case() {
156            CBORCase::Tagged(tag, _) => match tag.value() {
157                tags::TAG_X25519_PRIVATE_KEY => {
158                    Ok(EncapsulationPrivateKey::X25519(
159                        X25519PrivateKey::try_from(cbor)?,
160                    ))
161                }
162                tags::TAG_MLKEM_PRIVATE_KEY => {
163                    Ok(EncapsulationPrivateKey::MLKEM(
164                        MLKEMPrivateKey::try_from(cbor)?,
165                    ))
166                }
167                _ => {
168                    Err(dcbor::Error::msg("Invalid encapsulation private key"))
169                }
170            },
171            _ => Err(dcbor::Error::msg("Invalid encapsulation private key")),
172        }
173    }
174}