1#![doc = include_str!("../README.md")]
2#![no_std]
3#![forbid(unsafe_code)]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6mod api;
7mod benes;
8mod bm;
9mod controlbits;
10mod crypto_hash;
11mod decrypt;
12mod encrypt;
13mod gf;
14mod int32_sort;
15mod nist_aes_rng;
16mod operations;
17mod params;
18mod pk_gen;
19mod root;
20mod sk_gen;
21mod synd;
22mod test_katkem;
23mod test_kem;
24mod test_utils;
25mod transpose;
26mod uint64_sort;
27mod util;
28
29use core::fmt::Debug;
30use rand::{CryptoRng, RngCore};
31
32#[cfg(feature = "alloc")]
33extern crate alloc;
34#[cfg(feature = "alloc")]
35use alloc::boxed::Box;
36
37#[cfg(feature = "kem")]
38pub use kem_api::ClassicMcEliece;
39
40pub use api::{
41 CRYPTO_BYTES, CRYPTO_CIPHERTEXTBYTES, CRYPTO_PRIMITIVE, CRYPTO_PUBLICKEYBYTES,
42 CRYPTO_SECRETKEYBYTES,
43};
44
45mod macros {
46 macro_rules! sub {
49 ($var:expr, $offset:expr, $len:expr) => {{
50 <&[u8; $len]>::try_from(&$var[$offset..($offset + $len)])
51 .expect("slice has the correct length")
52 }};
53 (mut $var:expr, $offset:expr, $len:expr) => {{
54 <&mut [u8; $len]>::try_from(&mut $var[$offset..($offset + $len)])
55 .expect("slice has the correct length")
56 }};
57 ($var:expr, $offset:expr, $len:expr, $t:ty) => {{
58 <&[$t; $len]>::try_from(&$var[$offset..($offset + $len)])
59 .expect("slice has the correct length")
60 }};
61 (mut $var:expr, $offset:expr, $len:expr, $t:ty) => {{
62 <&mut [$t; $len]>::try_from(&mut $var[$offset..($offset + $len)])
63 .expect("slice has the correct length")
64 }};
65 }
66
67 pub(crate) use sub;
68}
69
70#[derive(Debug)]
71enum KeyBufferMut<'a, const SIZE: usize> {
72 Borrowed(&'a mut [u8; SIZE]),
73 #[cfg(feature = "alloc")]
74 Owned(Box<[u8; SIZE]>),
75}
76
77impl<const SIZE: usize> KeyBufferMut<'_, SIZE> {
78 #[cfg(feature = "alloc")]
79 fn to_owned(&self) -> KeyBufferMut<'static, SIZE> {
80 let mut new_buffer = util::alloc_boxed_array::<SIZE>();
81 new_buffer.copy_from_slice(self.as_ref());
82 KeyBufferMut::Owned(new_buffer)
83 }
84}
85
86impl<const SIZE: usize> AsRef<[u8; SIZE]> for KeyBufferMut<'_, SIZE> {
87 fn as_ref(&self) -> &[u8; SIZE] {
88 match &self {
89 KeyBufferMut::Borrowed(buf) => buf,
90 #[cfg(feature = "alloc")]
91 KeyBufferMut::Owned(buf) => buf.as_ref(),
92 }
93 }
94}
95
96impl<const SIZE: usize> AsMut<[u8; SIZE]> for KeyBufferMut<'_, SIZE> {
97 fn as_mut(&mut self) -> &mut [u8; SIZE] {
98 match self {
99 KeyBufferMut::Borrowed(buf) => buf,
100 #[cfg(feature = "alloc")]
101 KeyBufferMut::Owned(buf) => buf.as_mut(),
102 }
103 }
104}
105
106#[cfg(feature = "zeroize")]
107impl<const SIZE: usize> zeroize::Zeroize for KeyBufferMut<'_, SIZE> {
108 fn zeroize(&mut self) {
109 match self {
110 KeyBufferMut::Borrowed(buf) => buf.zeroize(),
111 #[cfg(feature = "alloc")]
112 KeyBufferMut::Owned(buf) => buf.zeroize(),
113 }
114 }
115}
116
117#[derive(Debug)]
120#[must_use]
121pub struct PublicKey<'a>(KeyBufferMut<'a, CRYPTO_PUBLICKEYBYTES>);
122
123impl PublicKey<'_> {
124 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
126 #[cfg(feature = "alloc")]
127 pub fn to_owned(&self) -> PublicKey<'static> {
128 PublicKey(self.0.to_owned())
129 }
130
131 pub fn as_array(&self) -> &[u8; CRYPTO_PUBLICKEYBYTES] {
132 self.0.as_ref()
133 }
134}
135
136impl AsRef<[u8]> for PublicKey<'_> {
137 fn as_ref(&self) -> &[u8] {
138 self.0.as_ref()
139 }
140}
141
142impl<'a> From<&'a mut [u8; CRYPTO_PUBLICKEYBYTES]> for PublicKey<'a> {
143 fn from(data: &'a mut [u8; CRYPTO_PUBLICKEYBYTES]) -> Self {
144 Self(KeyBufferMut::Borrowed(data))
145 }
146}
147
148#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
149#[cfg(feature = "alloc")]
150impl From<Box<[u8; CRYPTO_PUBLICKEYBYTES]>> for PublicKey<'static> {
151 fn from(data: Box<[u8; CRYPTO_PUBLICKEYBYTES]>) -> Self {
152 Self(KeyBufferMut::Owned(data))
153 }
154}
155
156#[cfg(feature = "zeroize")]
157impl zeroize::Zeroize for PublicKey<'_> {
158 fn zeroize(&mut self) {
159 self.0.zeroize();
160 }
161}
162
163#[cfg(feature = "zeroize")]
164impl zeroize::ZeroizeOnDrop for PublicKey<'_> {}
165
166impl Drop for PublicKey<'_> {
167 fn drop(&mut self) {
168 #[cfg(feature = "zeroize")]
169 {
170 use zeroize::Zeroize;
171 self.zeroize();
172 }
173 }
174}
175
176#[must_use]
181pub struct SecretKey<'a>(KeyBufferMut<'a, CRYPTO_SECRETKEYBYTES>);
182
183impl SecretKey<'_> {
184 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
186 #[cfg(feature = "alloc")]
187 pub fn to_owned(&self) -> SecretKey<'static> {
188 SecretKey(self.0.to_owned())
189 }
190
191 pub fn as_array(&self) -> &[u8; CRYPTO_SECRETKEYBYTES] {
198 self.0.as_ref()
199 }
200}
201
202impl Debug for SecretKey<'_> {
203 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
204 f.debug_tuple("SecretKey").field(&"-- redacted --").finish()
205 }
206}
207
208impl AsRef<[u8]> for SecretKey<'_> {
209 fn as_ref(&self) -> &[u8] {
210 self.0.as_ref()
211 }
212}
213
214impl<'a> From<&'a mut [u8; CRYPTO_SECRETKEYBYTES]> for SecretKey<'a> {
215 fn from(data: &'a mut [u8; CRYPTO_SECRETKEYBYTES]) -> Self {
218 Self(KeyBufferMut::Borrowed(data))
219 }
220}
221
222#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
223#[cfg(feature = "alloc")]
224impl From<Box<[u8; CRYPTO_SECRETKEYBYTES]>> for SecretKey<'static> {
225 fn from(data: Box<[u8; CRYPTO_SECRETKEYBYTES]>) -> Self {
226 Self(KeyBufferMut::Owned(data))
227 }
228}
229
230#[cfg(feature = "zeroize")]
231impl zeroize::Zeroize for SecretKey<'_> {
232 fn zeroize(&mut self) {
233 self.0.zeroize();
234 }
235}
236
237#[cfg(feature = "zeroize")]
238impl zeroize::ZeroizeOnDrop for SecretKey<'_> {}
239
240impl Drop for SecretKey<'_> {
241 fn drop(&mut self) {
242 #[cfg(feature = "zeroize")]
243 {
244 use zeroize::Zeroize;
245 self.zeroize();
246 }
247 }
248}
249
250#[derive(Debug)]
252#[must_use]
253pub struct Ciphertext([u8; CRYPTO_CIPHERTEXTBYTES]);
254
255impl Ciphertext {
256 pub fn as_array(&self) -> &[u8; CRYPTO_CIPHERTEXTBYTES] {
257 &self.0
258 }
259}
260
261impl AsRef<[u8]> for Ciphertext {
262 fn as_ref(&self) -> &[u8] {
263 self.0.as_ref()
264 }
265}
266
267impl From<[u8; CRYPTO_CIPHERTEXTBYTES]> for Ciphertext {
268 fn from(data: [u8; CRYPTO_CIPHERTEXTBYTES]) -> Self {
269 Self(data)
270 }
271}
272
273#[must_use]
276pub struct SharedSecret<'a>(KeyBufferMut<'a, CRYPTO_BYTES>);
277
278impl SharedSecret<'_> {
279 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
281 #[cfg(feature = "alloc")]
282 pub fn to_owned(&self) -> SharedSecret<'static> {
283 SharedSecret(self.0.to_owned())
284 }
285
286 pub fn as_array(&self) -> &[u8; CRYPTO_BYTES] {
287 self.0.as_ref()
288 }
289}
290
291impl Debug for SharedSecret<'_> {
292 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
293 f.debug_tuple("SharedSecret")
294 .field(&"-- redacted --")
295 .finish()
296 }
297}
298
299impl AsRef<[u8]> for SharedSecret<'_> {
300 fn as_ref(&self) -> &[u8] {
301 self.0.as_ref()
302 }
303}
304
305#[cfg(feature = "zeroize")]
306impl zeroize::Zeroize for SharedSecret<'_> {
307 fn zeroize(&mut self) {
308 self.0.zeroize();
309 }
310}
311
312#[cfg(feature = "zeroize")]
313impl zeroize::ZeroizeOnDrop for SharedSecret<'_> {}
314
315impl Drop for SharedSecret<'_> {
316 fn drop(&mut self) {
317 #[cfg(feature = "zeroize")]
318 {
319 use zeroize::Zeroize;
320 self.zeroize();
321 }
322 }
323}
324
325pub fn keypair<'public, 'secret, R: CryptoRng + RngCore>(
331 public_key_buf: &'public mut [u8; CRYPTO_PUBLICKEYBYTES],
332 secret_key_buf: &'secret mut [u8; CRYPTO_SECRETKEYBYTES],
333 rng: &mut R,
334) -> (PublicKey<'public>, SecretKey<'secret>) {
335 operations::crypto_kem_keypair(public_key_buf, secret_key_buf, rng);
336
337 (
338 PublicKey(KeyBufferMut::Borrowed(public_key_buf)),
339 SecretKey(KeyBufferMut::Borrowed(secret_key_buf)),
340 )
341}
342
343#[cfg(feature = "alloc")]
346#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
347pub fn keypair_boxed<R: CryptoRng + RngCore>(
348 rng: &mut R,
349) -> (PublicKey<'static>, SecretKey<'static>) {
350 let mut public_key_buf = util::alloc_boxed_array::<CRYPTO_PUBLICKEYBYTES>();
351 let mut secret_key_buf = util::alloc_boxed_array::<CRYPTO_SECRETKEYBYTES>();
352
353 operations::crypto_kem_keypair(&mut public_key_buf, &mut secret_key_buf, rng);
354
355 (
356 PublicKey(KeyBufferMut::Owned(public_key_buf)),
357 SecretKey(KeyBufferMut::Owned(secret_key_buf)),
358 )
359}
360
361pub fn encapsulate<'shared_secret, R: CryptoRng + RngCore>(
368 public_key: &PublicKey<'_>,
369 shared_secret_buf: &'shared_secret mut [u8; CRYPTO_BYTES],
370 rng: &mut R,
371) -> (Ciphertext, SharedSecret<'shared_secret>) {
372 let mut shared_secret_buf = KeyBufferMut::Borrowed(shared_secret_buf);
373 let mut ciphertext_buf = [0u8; CRYPTO_CIPHERTEXTBYTES];
374
375 operations::crypto_kem_enc(
376 &mut ciphertext_buf,
377 shared_secret_buf.as_mut(),
378 public_key.0.as_ref(),
379 rng,
380 );
381
382 (Ciphertext(ciphertext_buf), SharedSecret(shared_secret_buf))
383}
384
385#[cfg(feature = "alloc")]
388#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
389pub fn encapsulate_boxed<R: CryptoRng + RngCore>(
390 public_key: &PublicKey<'_>,
391 rng: &mut R,
392) -> (Ciphertext, SharedSecret<'static>) {
393 let mut shared_secret_buf = KeyBufferMut::Owned(Box::new([0u8; CRYPTO_BYTES]));
394 let mut ciphertext_buf = [0u8; CRYPTO_CIPHERTEXTBYTES];
395
396 operations::crypto_kem_enc(
397 &mut ciphertext_buf,
398 shared_secret_buf.as_mut(),
399 public_key.0.as_ref(),
400 rng,
401 );
402
403 (Ciphertext(ciphertext_buf), SharedSecret(shared_secret_buf))
404}
405
406pub fn decapsulate<'shared_secret>(
411 ciphertext: &Ciphertext,
412 secret_key: &SecretKey,
413 shared_secret_buf: &'shared_secret mut [u8; CRYPTO_BYTES],
414) -> SharedSecret<'shared_secret> {
415 let mut shared_secret_buf = KeyBufferMut::Borrowed(shared_secret_buf);
416
417 operations::crypto_kem_dec(
418 shared_secret_buf.as_mut(),
419 ciphertext.as_array(),
420 secret_key.as_array(),
421 );
422
423 SharedSecret(shared_secret_buf)
424}
425
426#[cfg(feature = "alloc")]
429#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
430pub fn decapsulate_boxed(ciphertext: &Ciphertext, secret_key: &SecretKey) -> SharedSecret<'static> {
431 let mut shared_secret_buf = KeyBufferMut::Owned(Box::new([0u8; CRYPTO_BYTES]));
432
433 operations::crypto_kem_dec(
434 shared_secret_buf.as_mut(),
435 ciphertext.as_array(),
436 secret_key.as_array(),
437 );
438
439 SharedSecret(shared_secret_buf)
440}
441
442#[cfg(feature = "kem")]
443mod kem_api {
444 use kem::generic_array::{typenum, GenericArray};
445 use kem::{Decapsulator, EncappedKey, Encapsulator, SharedSecret};
446 use rand::{CryptoRng, RngCore};
447
448 use crate::{Ciphertext, PublicKey, SecretKey};
449 use crate::{CRYPTO_BYTES, CRYPTO_CIPHERTEXTBYTES};
450
451 #[derive(Debug)]
453 #[cfg_attr(docsrs, doc(cfg(feature = "kem")))]
454 pub struct ClassicMcEliece;
455
456 impl Encapsulator<Ciphertext> for ClassicMcEliece {
457 fn try_encap<R: CryptoRng + RngCore>(
458 &self,
459 csprng: &mut R,
460 recip_pubkey: &<Ciphertext as EncappedKey>::RecipientPublicKey,
461 ) -> Result<(Ciphertext, SharedSecret<Ciphertext>), kem::Error> {
462 let mut ciphertext_buf = [0u8; CRYPTO_CIPHERTEXTBYTES];
463 let mut shared_secret = GenericArray::<_, _>::default();
464
465 let shared_secret_buf: &mut [u8; CRYPTO_BYTES] = shared_secret
466 .as_mut_slice()
467 .try_into()
468 .expect("GenericArray should be CRYPTO_BYTES long");
469
470 crate::operations::crypto_kem_enc(
471 &mut ciphertext_buf,
472 shared_secret_buf,
473 recip_pubkey.0.as_ref(),
474 csprng,
475 );
476 Ok((
477 Ciphertext(ciphertext_buf),
478 SharedSecret::<Ciphertext>::new(shared_secret),
479 ))
480 }
481 }
482
483 #[cfg_attr(docsrs, doc(cfg(feature = "kem")))]
484 impl EncappedKey for Ciphertext {
485 type EncappedKeySize = crate::api::CryptoCiphertextBytesTypenum;
486
487 type SharedSecretSize = typenum::U32;
488
489 type SenderPublicKey = ();
490
491 type RecipientPublicKey = PublicKey<'static>;
492
493 fn from_bytes(bytes: &GenericArray<u8, Self::EncappedKeySize>) -> Result<Self, kem::Error> {
494 let mut data = [0u8; CRYPTO_CIPHERTEXTBYTES];
495 data.copy_from_slice(bytes.as_slice());
496 Ok(Ciphertext(data))
497 }
498 }
499
500 #[cfg_attr(docsrs, doc(cfg(feature = "kem")))]
501 impl<'sk> Decapsulator<Ciphertext> for SecretKey<'sk> {
502 fn try_decap(
503 &self,
504 ciphertext: &Ciphertext,
505 ) -> Result<SharedSecret<Ciphertext>, kem::Error> {
506 let mut shared_secret = GenericArray::<_, _>::default();
507
508 let shared_secret_buf: &mut [u8; CRYPTO_BYTES] = shared_secret
509 .as_mut_slice()
510 .try_into()
511 .expect("GenericArray should be CRYPTO_BYTES long");
512
513 crate::operations::crypto_kem_dec(
514 shared_secret_buf,
515 ciphertext.as_array(),
516 self.as_array(),
517 );
518 Ok(SharedSecret::<Ciphertext>::new(shared_secret))
519 }
520 }
521}
522
523#[cfg(test)]
525#[macro_use]
526extern crate std;