1use alloc::vec::Vec;
6
7use core::ptr::NonNull;
8
9#[cfg(not(feature = "std"))]
10use cstr_core::CStr;
11#[cfg(feature = "std")]
12use std::ffi::CStr;
13
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Serialize};
16
17use crate::ffi::kem as ffi;
18use crate::newtype_buffer;
19use crate::*;
20
21newtype_buffer!(PublicKey, PublicKeyRef);
22newtype_buffer!(SecretKey, SecretKeyRef);
23newtype_buffer!(Ciphertext, CiphertextRef);
24newtype_buffer!(SharedSecret, SharedSecretRef);
25
26macro_rules! implement_kems {
27 { $(($feat: literal) $kem: ident: $oqs_id: ident),* $(,)? } => (
28
29 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
35 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36 #[allow(missing_docs)]
37 pub enum Algorithm {
38 $(
39 $kem,
40 )*
41 }
42
43 fn algorithm_to_id(algorithm: Algorithm) -> *const libc::c_char {
44 let id: &[u8] = match algorithm {
45 $(
46 Algorithm::$kem => &ffi::$oqs_id[..],
47 )*
48 };
49 id as *const _ as *const libc::c_char
50 }
51
52 $(
53 #[cfg(test)]
54 #[allow(non_snake_case)]
55 mod $kem {
56 use super::*;
57
58 #[test]
59 #[cfg(feature = $feat)]
60 fn test_encaps_decaps() -> Result<()> {
61 crate::init();
62
63 let alg = Algorithm::$kem;
64 let kem = Kem::new(alg)?;
65 let (pk, sk) = kem.keypair()?;
66 let (ct, ss1) = kem.encapsulate(&pk)?;
67 let ss2 = kem.decapsulate(&sk, &ct)?;
68 assert_eq!(ss1, ss2, "shared secret not equal!");
69 Ok(())
70 }
71
72 #[test]
73 fn test_enabled() {
74 crate::init();
75 if cfg!(feature = $feat) {
76 assert!(Algorithm::$kem.is_enabled());
77 } else {
78 assert!(!Algorithm::$kem.is_enabled())
79 }
80 }
81
82 #[test]
83 fn test_name() {
84 let algo = Algorithm::$kem;
85 let name = algo.name();
87 #[cfg(feature = "std")]
88 assert_eq!(name, algo.to_string());
89 assert!(!name.is_empty());
91 }
92
93 #[test]
94 fn test_get_algorithm_back() {
95 let algorithm = Algorithm::$kem;
96 if algorithm.is_enabled() {
97 let kem = Kem::new(algorithm).unwrap();
98 assert_eq!(algorithm, kem.algorithm());
99 }
100 }
101
102 #[test]
103 fn test_version() {
104 if let Ok(kem) = Kem::new(Algorithm::$kem) {
105 let version = kem.version();
107 assert!(!version.is_empty());
109 }
110 }
111 }
112 )*
113 )
114}
115
116implement_kems! {
117 ("bike") BikeL1: OQS_KEM_alg_bike_l1,
118 ("bike") BikeL3: OQS_KEM_alg_bike_l3,
119 ("bike") BikeL5: OQS_KEM_alg_bike_l5,
120 ("classic_mceliece") ClassicMcEliece348864: OQS_KEM_alg_classic_mceliece_348864,
121 ("classic_mceliece") ClassicMcEliece348864f: OQS_KEM_alg_classic_mceliece_348864f,
122 ("classic_mceliece") ClassicMcEliece460896: OQS_KEM_alg_classic_mceliece_460896,
123 ("classic_mceliece") ClassicMcEliece460896f: OQS_KEM_alg_classic_mceliece_460896f,
124 ("classic_mceliece") ClassicMcEliece6688128: OQS_KEM_alg_classic_mceliece_6688128,
125 ("classic_mceliece") ClassicMcEliece6688128f: OQS_KEM_alg_classic_mceliece_6688128f,
126 ("classic_mceliece") ClassicMcEliece6960119: OQS_KEM_alg_classic_mceliece_6960119,
127 ("classic_mceliece") ClassicMcEliece6960119f: OQS_KEM_alg_classic_mceliece_6960119f,
128 ("classic_mceliece") ClassicMcEliece8192128: OQS_KEM_alg_classic_mceliece_8192128,
129 ("classic_mceliece") ClassicMcEliece8192128f: OQS_KEM_alg_classic_mceliece_8192128f,
130 ("hqc") Hqc128: OQS_KEM_alg_hqc_128,
131 ("hqc") Hqc192: OQS_KEM_alg_hqc_192,
132 ("hqc") Hqc256: OQS_KEM_alg_hqc_256,
133 ("kyber") Kyber512: OQS_KEM_alg_kyber_512,
134 ("kyber") Kyber768: OQS_KEM_alg_kyber_768,
135 ("kyber") Kyber1024: OQS_KEM_alg_kyber_1024,
136 ("ntruprime") NtruPrimeSntrup761: OQS_KEM_alg_ntruprime_sntrup761,
137 ("frodokem") FrodoKem640Aes: OQS_KEM_alg_frodokem_640_aes,
138 ("frodokem") FrodoKem640Shake: OQS_KEM_alg_frodokem_640_shake,
139 ("frodokem") FrodoKem976Aes: OQS_KEM_alg_frodokem_976_aes,
140 ("frodokem") FrodoKem976Shake: OQS_KEM_alg_frodokem_976_shake,
141 ("frodokem") FrodoKem1344Aes: OQS_KEM_alg_frodokem_1344_aes,
142 ("frodokem") FrodoKem1344Shake: OQS_KEM_alg_frodokem_1344_shake,
143 ("ml_kem") MlKem512Ipd: OQS_KEM_alg_ml_kem_512_ipd,
144 ("ml_kem") MlKem768Ipd: OQS_KEM_alg_ml_kem_768_ipd,
145 ("ml_kem") MlKem1024Ipd: OQS_KEM_alg_ml_kem_1024_ipd,
146 ("ml_kem") MlKem512: OQS_KEM_alg_ml_kem_512,
147 ("ml_kem") MlKem768: OQS_KEM_alg_ml_kem_768,
148 ("ml_kem") MlKem1024: OQS_KEM_alg_ml_kem_1024,
149}
150
151impl Algorithm {
152 pub fn is_enabled(self) -> bool {
155 unsafe { ffi::OQS_KEM_alg_is_enabled(algorithm_to_id(self)) == 1 }
156 }
157
158 pub fn to_id(self) -> *const libc::c_char {
162 algorithm_to_id(self)
163 }
164
165 pub fn name(&self) -> &'static str {
169 let id = unsafe { CStr::from_ptr(self.to_id()) };
171 id.to_str().expect("OQS algorithm names must be UTF-8")
172 }
173}
174
175#[cfg(feature = "std")]
176impl std::fmt::Display for Algorithm {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 self.name().fmt(f)
179 }
180}
181
182pub struct Kem {
196 algorithm: Algorithm,
197 kem: NonNull<ffi::OQS_KEM>,
198}
199
200unsafe impl Sync for Kem {}
201unsafe impl Send for Kem {}
202
203impl Drop for Kem {
204 fn drop(&mut self) {
205 unsafe { ffi::OQS_KEM_free(self.kem.as_ptr()) };
206 }
207}
208
209impl core::convert::TryFrom<Algorithm> for Kem {
210 type Error = crate::Error;
211 fn try_from(alg: Algorithm) -> Result<Kem> {
212 Kem::new(alg)
213 }
214}
215
216impl Kem {
217 pub fn new(algorithm: Algorithm) -> Result<Self> {
219 let kem = unsafe { ffi::OQS_KEM_new(algorithm_to_id(algorithm)) };
220 NonNull::new(kem).map_or_else(
221 || Err(Error::AlgorithmDisabled),
222 |kem| Ok(Self { algorithm, kem }),
223 )
224 }
225
226 pub fn algorithm(&self) -> Algorithm {
228 self.algorithm
229 }
230
231 pub fn version(&self) -> &'static str {
233 let kem = unsafe { self.kem.as_ref() };
234 let cstr = unsafe { CStr::from_ptr(kem.alg_version) };
236 cstr.to_str()
237 .expect("Algorithm version strings must be UTF-8")
238 }
239
240 pub fn claimed_nist_level(&self) -> u8 {
242 let kem = unsafe { self.kem.as_ref() };
243 kem.claimed_nist_level
244 }
245
246 pub fn is_ind_cca(&self) -> bool {
248 let kem = unsafe { self.kem.as_ref() };
249 kem.ind_cca
250 }
251
252 pub fn length_public_key(&self) -> usize {
254 let kem = unsafe { self.kem.as_ref() };
255 kem.length_public_key
256 }
257
258 pub fn length_secret_key(&self) -> usize {
260 let kem = unsafe { self.kem.as_ref() };
261 kem.length_secret_key
262 }
263
264 pub fn length_ciphertext(&self) -> usize {
266 let kem = unsafe { self.kem.as_ref() };
267 kem.length_ciphertext
268 }
269
270 pub fn length_shared_secret(&self) -> usize {
272 let kem = unsafe { self.kem.as_ref() };
273 kem.length_shared_secret
274 }
275
276 pub fn secret_key_from_bytes<'a>(&self, buf: &'a [u8]) -> Option<SecretKeyRef<'a>> {
280 if self.length_secret_key() != buf.len() {
281 None
282 } else {
283 Some(SecretKeyRef::new(buf))
284 }
285 }
286
287 pub fn public_key_from_bytes<'a>(&self, buf: &'a [u8]) -> Option<PublicKeyRef<'a>> {
291 if self.length_public_key() != buf.len() {
292 None
293 } else {
294 Some(PublicKeyRef::new(buf))
295 }
296 }
297
298 pub fn ciphertext_from_bytes<'a>(&self, buf: &'a [u8]) -> Option<CiphertextRef<'a>> {
302 if self.length_ciphertext() != buf.len() {
303 None
304 } else {
305 Some(CiphertextRef::new(buf))
306 }
307 }
308
309 pub fn shared_secret_from_bytes<'a>(&self, buf: &'a [u8]) -> Option<SharedSecretRef<'a>> {
313 if self.length_shared_secret() != buf.len() {
314 None
315 } else {
316 Some(SharedSecretRef::new(buf))
317 }
318 }
319
320 pub fn keypair(&self) -> Result<(PublicKey, SecretKey)> {
322 let kem = unsafe { self.kem.as_ref() };
323 let func = kem.keypair.unwrap();
324 let mut pk = PublicKey {
325 bytes: Vec::with_capacity(kem.length_public_key),
326 };
327 let mut sk = SecretKey {
328 bytes: Vec::with_capacity(kem.length_secret_key),
329 };
330 let status = unsafe { func(pk.bytes.as_mut_ptr(), sk.bytes.as_mut_ptr()) };
331 status_to_result(status)?;
332 unsafe {
335 pk.bytes.set_len(kem.length_public_key);
336 sk.bytes.set_len(kem.length_secret_key);
337 }
338 Ok((pk, sk))
339 }
340
341 pub fn encapsulate<'a, P: Into<PublicKeyRef<'a>>>(
343 &self,
344 pk: P,
345 ) -> Result<(Ciphertext, SharedSecret)> {
346 let pk = pk.into();
347 if pk.bytes.len() != self.length_public_key() {
348 return Err(Error::InvalidLength);
349 }
350 let kem = unsafe { self.kem.as_ref() };
351 let func = kem.encaps.unwrap();
352 let mut ct = Ciphertext {
353 bytes: Vec::with_capacity(kem.length_ciphertext),
354 };
355 let mut ss = SharedSecret {
356 bytes: Vec::with_capacity(kem.length_shared_secret),
357 };
358 let status = unsafe {
360 func(
361 ct.bytes.as_mut_ptr(),
362 ss.bytes.as_mut_ptr(),
363 pk.bytes.as_ptr(),
364 )
365 };
366 status_to_result(status)?;
367 unsafe {
370 ct.bytes.set_len(kem.length_ciphertext);
371 ss.bytes.set_len(kem.length_shared_secret);
372 }
373 Ok((ct, ss))
374 }
375
376 pub fn decapsulate<'a, 'b, S: Into<SecretKeyRef<'a>>, C: Into<CiphertextRef<'b>>>(
378 &self,
379 sk: S,
380 ct: C,
381 ) -> Result<SharedSecret> {
382 let kem = unsafe { self.kem.as_ref() };
383 let sk = sk.into();
384 let ct = ct.into();
385 if sk.bytes.len() != self.length_secret_key() || ct.bytes.len() != self.length_ciphertext()
386 {
387 return Err(Error::InvalidLength);
388 }
389 let mut ss = SharedSecret {
390 bytes: Vec::with_capacity(kem.length_shared_secret),
391 };
392 let func = kem.decaps.unwrap();
393 let status = unsafe { func(ss.bytes.as_mut_ptr(), ct.bytes.as_ptr(), sk.bytes.as_ptr()) };
395 status_to_result(status)?;
396 unsafe { ss.bytes.set_len(kem.length_shared_secret) };
399 Ok(ss)
400 }
401}