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}