1#![cfg_attr(not(feature = "std"), no_std)]
5
6#[cfg(feature = "alloc")]
7extern crate alloc;
8#[cfg(feature = "alloc")]
9use alloc::vec::Vec;
10
11use crate::error::Error as KemError; use core::marker::PhantomData;
13use dcrypt_algorithms::error::Error as AlgoError;
14use dcrypt_api::{
15 error::Error as ApiError,
16 traits::serialize::{Serialize, SerializeSecret},
17 Kem as KemTrait, Key as ApiKey, Result as ApiResult,
18};
19use rand::{CryptoRng, RngCore};
20use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
21
22use super::ind_cca::{kem_decaps, kem_encaps, kem_keygen};
23use super::params::KyberParams; #[derive(Clone, Debug, Zeroize)]
30pub struct KyberPublicKey(Vec<u8>);
31
32impl KyberPublicKey {
33 pub fn new(data: Vec<u8>) -> Self {
34 Self(data)
35 }
36 pub fn into_vec(self) -> Vec<u8> {
37 self.0
38 }
39 pub fn as_bytes(&self) -> &[u8] {
40 &self.0
41 }
42 pub fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
43 Ok(Self(bytes.to_vec()))
44 }
45 pub fn to_bytes(&self) -> Vec<u8> {
46 self.0.clone()
47 }
48}
49
50impl Serialize for KyberPublicKey {
51 fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
52 Self::from_bytes(bytes)
53 }
54 fn to_bytes(&self) -> Vec<u8> {
55 self.to_bytes()
56 }
57}
58
59#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
66pub struct KyberSecretKey(Vec<u8>);
67
68impl KyberSecretKey {
69 pub fn new(data: Vec<u8>) -> Self {
70 Self(data)
71 }
72 pub fn to_vec(&self) -> Vec<u8> {
73 self.0.clone()
74 }
75 pub fn len(&self) -> usize {
76 self.0.len()
77 }
78 pub fn is_empty(&self) -> bool {
79 self.0.is_empty()
80 }
81 pub(crate) fn as_bytes(&self) -> &[u8] {
82 &self.0
83 }
84 pub fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
85 Ok(Self(bytes.to_vec()))
86 }
87 pub fn to_bytes_zeroizing(&self) -> Zeroizing<Vec<u8>> {
88 Zeroizing::new(self.0.clone())
89 }
90}
91
92impl SerializeSecret for KyberSecretKey {
93 fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
94 Self::from_bytes(bytes)
95 }
96 fn to_bytes_zeroizing(&self) -> Zeroizing<Vec<u8>> {
97 self.to_bytes_zeroizing()
98 }
99}
100
101#[derive(Clone, Debug)]
106pub struct KyberCiphertext(Vec<u8>);
107
108impl KyberCiphertext {
109 pub fn new(data: Vec<u8>) -> Self {
110 Self(data)
111 }
112 pub fn into_vec(self) -> Vec<u8> {
113 self.0
114 }
115 pub fn as_bytes(&self) -> &[u8] {
116 &self.0
117 }
118 pub fn len(&self) -> usize {
119 self.0.len()
120 }
121 pub fn is_empty(&self) -> bool {
122 self.0.is_empty()
123 }
124 pub fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
125 Ok(Self(bytes.to_vec()))
126 }
127 pub fn to_bytes(&self) -> Vec<u8> {
128 self.0.clone()
129 }
130}
131
132impl Serialize for KyberCiphertext {
133 fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
134 Self::from_bytes(bytes)
135 }
136 fn to_bytes(&self) -> Vec<u8> {
137 self.to_bytes()
138 }
139}
140
141#[derive(Clone, Zeroize, ZeroizeOnDrop)]
148pub struct KyberSharedSecret(ApiKey);
149
150impl KyberSharedSecret {
151 pub fn new(key: ApiKey) -> Self {
152 Self(key)
153 }
154 pub fn to_key(&self) -> ApiKey {
155 self.0.clone()
156 }
157 pub fn len(&self) -> usize {
158 self.0.as_ref().len()
159 }
160 pub fn is_empty(&self) -> bool {
161 self.0.as_ref().is_empty()
162 }
163 pub(crate) fn as_bytes(&self) -> &[u8] {
164 self.0.as_ref()
165 }
166 pub fn to_bytes_zeroizing(&self) -> Zeroizing<Vec<u8>> {
167 Zeroizing::new(self.0.as_ref().to_vec())
168 }
169}
170
171impl SerializeSecret for KyberSharedSecret {
172 fn from_bytes(bytes: &[u8]) -> ApiResult<Self> {
173 Ok(Self(ApiKey::new(bytes)))
174 }
175 fn to_bytes_zeroizing(&self) -> Zeroizing<Vec<u8>> {
176 self.to_bytes_zeroizing()
177 }
178}
179
180impl core::fmt::Debug for KyberSharedSecret {
181 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
182 f.debug_struct("KyberSharedSecret")
183 .field("length", &self.len())
184 .finish()
185 }
186}
187
188pub struct KyberKem<P: KyberParams> {
190 _params: PhantomData<P>,
191}
192
193impl<P: KyberParams> KemTrait for KyberKem<P> {
194 type PublicKey = KyberPublicKey;
195 type SecretKey = KyberSecretKey;
196 type SharedSecret = KyberSharedSecret;
197 type Ciphertext = KyberCiphertext;
198 type KeyPair = (Self::PublicKey, Self::SecretKey);
199
200 fn name() -> &'static str {
201 P::NAME
202 }
203
204 fn keypair<R: RngCore + CryptoRng>(rng: &mut R) -> ApiResult<Self::KeyPair> {
205 let (pk_bytes, sk_bytes) =
206 kem_keygen::<P, R>(rng).map_err(|algo_err| ApiError::from(KemError::from(algo_err)))?;
207 Ok((KyberPublicKey::new(pk_bytes), KyberSecretKey::new(sk_bytes)))
208 }
209
210 fn public_key(keypair: &Self::KeyPair) -> Self::PublicKey {
211 keypair.0.clone()
212 }
213
214 fn secret_key(keypair: &Self::KeyPair) -> Self::SecretKey {
215 keypair.1.clone()
216 }
217
218 fn encapsulate<R: RngCore + CryptoRng>(
219 rng: &mut R,
220 public_key: &Self::PublicKey,
221 ) -> ApiResult<(Self::Ciphertext, Self::SharedSecret)> {
222 if public_key.as_bytes().len() != P::PUBLIC_KEY_BYTES {
223 return Err(ApiError::InvalidKey {
224 context: "Kyber public key",
225 #[cfg(feature = "std")]
226 message: format!(
227 "Incorrect length: expected {}, got {}",
228 P::PUBLIC_KEY_BYTES,
229 public_key.as_bytes().len()
230 ),
231 });
232 }
233
234 let (ct_bytes, ss_bytes_fixed) = kem_encaps::<P, R>(&public_key.0, rng)
235 .map_err(|algo_err| ApiError::from(KemError::from(algo_err)))?;
236
237 Ok((
238 KyberCiphertext::new(ct_bytes),
239 KyberSharedSecret::new(ApiKey::new(ss_bytes_fixed.as_ref())),
240 ))
241 }
242
243 fn decapsulate(
244 secret_key: &Self::SecretKey,
245 ciphertext: &Self::Ciphertext,
246 ) -> ApiResult<Self::SharedSecret> {
247 if secret_key.as_bytes().len() != P::SECRET_KEY_BYTES {
248 return Err(ApiError::InvalidKey {
249 context: "Kyber secret key",
250 #[cfg(feature = "std")]
251 message: format!(
252 "Incorrect length: expected {}, got {}",
253 P::SECRET_KEY_BYTES,
254 secret_key.as_bytes().len()
255 ),
256 });
257 }
258 if ciphertext.as_bytes().len() != P::CIPHERTEXT_BYTES {
259 return Err(ApiError::InvalidCiphertext {
260 context: "Kyber ciphertext",
261 #[cfg(feature = "std")]
262 message: format!(
263 "Incorrect length: expected {}, got {}",
264 P::CIPHERTEXT_BYTES,
265 ciphertext.as_bytes().len()
266 ),
267 });
268 }
269
270 let ss_bytes_fixed =
271 kem_decaps::<P>(&secret_key.0, &ciphertext.0).map_err(|algo_err| match algo_err {
272 AlgoError::Processing { .. } => ApiError::DecryptionFailed {
273 context: P::NAME,
274 #[cfg(feature = "std")]
275 message: "Decapsulation failed".into(),
276 },
277 _ => ApiError::from(KemError::from(algo_err)),
278 })?;
279
280 Ok(KyberSharedSecret::new(ApiKey::new(ss_bytes_fixed.as_ref())))
281 }
282}