1#![no_std]
76#![forbid(unsafe_code)]
77#![cfg_attr(docsrs, feature(doc_cfg))]
78#![allow(clippy::collapsible_if)]
80#![allow(clippy::identity_op)]
81#![allow(clippy::manual_div_ceil)]
82#![allow(clippy::manual_memcpy)]
83#![allow(clippy::needless_range_loop)]
84#![allow(clippy::unnecessary_map_or)]
85#![allow(clippy::unnecessary_mut_passed)]
86
87mod api;
88mod benes;
89mod bm;
90mod controlbits;
91mod crypto_hash;
92mod decrypt;
93mod encrypt;
94mod gf;
95mod int32_sort;
96mod libq_provider;
97mod operations;
98mod params;
99mod pk_gen;
100mod root;
101mod sk_gen;
102mod synd;
103mod test_utils;
104mod transpose;
105mod uint64_sort;
106mod util;
107
108#[cfg(feature = "nist-aes-rng")]
109#[cfg_attr(docsrs, doc(cfg(feature = "nist-aes-rng")))]
110mod nist_aes_rng;
111
112use core::fmt::Debug;
113
114use rand_core::{
115 CryptoRng,
116 Rng,
117};
118
119#[cfg(feature = "alloc")]
120extern crate alloc;
121#[cfg(feature = "alloc")]
122use alloc::boxed::Box;
123
124pub use api::{
125 CRYPTO_BYTES,
126 CRYPTO_CIPHERTEXTBYTES,
127 CRYPTO_PRIMITIVE,
128 CRYPTO_PUBLICKEYBYTES,
129 CRYPTO_SECRETKEYBYTES,
130};
131pub use lib_q_random::ClassicalMcElieceRng as LibQRng;
133#[cfg(feature = "alloc")]
135pub use libq_provider::LibQCbKemProvider;
136#[cfg(feature = "nist-aes-rng")]
137#[cfg_attr(docsrs, doc(cfg(feature = "nist-aes-rng")))]
138pub use nist_aes_rng::{
139 AesState,
140 MAX_BYTES_PER_REQUEST,
141 NistDrbgError,
142 RESEED_INTERVAL,
143 SEEDLEN,
144};
145
146mod macros {
147 macro_rules! sub {
150 ($var:expr, $offset:expr, $len:expr) => {{
151 <&[u8; $len]>::try_from(&$var[$offset..($offset + $len)])
152 .expect("slice has the correct length")
153 }};
154 (mut $var:expr, $offset:expr, $len:expr) => {{
155 <&mut [u8; $len]>::try_from(&mut $var[$offset..($offset + $len)])
156 .expect("slice has the correct length")
157 }};
158 ($var:expr, $offset:expr, $len:expr, $t:ty) => {{
159 <&[$t; $len]>::try_from(&$var[$offset..($offset + $len)])
160 .expect("slice has the correct length")
161 }};
162 (mut $var:expr, $offset:expr, $len:expr, $t:ty) => {{
163 <&mut [$t; $len]>::try_from(&mut $var[$offset..($offset + $len)])
164 .expect("slice has the correct length")
165 }};
166 }
167
168 pub(crate) use sub;
169}
170
171#[derive(Debug)]
172enum KeyBufferMut<'a, const SIZE: usize> {
173 Borrowed(&'a mut [u8; SIZE]),
174 #[cfg(feature = "alloc")]
175 Owned(Box<[u8; SIZE]>),
176}
177
178impl<const SIZE: usize> KeyBufferMut<'_, SIZE> {
179 #[cfg(feature = "alloc")]
180 fn to_owned(&self) -> KeyBufferMut<'static, SIZE> {
181 let mut new_buffer = util::alloc_boxed_array::<SIZE>();
182 new_buffer.copy_from_slice(self.as_ref());
183 KeyBufferMut::Owned(new_buffer)
184 }
185}
186
187impl<const SIZE: usize> AsRef<[u8; SIZE]> for KeyBufferMut<'_, SIZE> {
188 fn as_ref(&self) -> &[u8; SIZE] {
189 match &self {
190 KeyBufferMut::Borrowed(buf) => buf,
191 #[cfg(feature = "alloc")]
192 KeyBufferMut::Owned(buf) => buf.as_ref(),
193 }
194 }
195}
196
197impl<const SIZE: usize> AsMut<[u8; SIZE]> for KeyBufferMut<'_, SIZE> {
198 fn as_mut(&mut self) -> &mut [u8; SIZE] {
199 match self {
200 KeyBufferMut::Borrowed(buf) => buf,
201 #[cfg(feature = "alloc")]
202 KeyBufferMut::Owned(buf) => buf.as_mut(),
203 }
204 }
205}
206
207#[cfg(feature = "zeroize")]
208impl<const SIZE: usize> zeroize::Zeroize for KeyBufferMut<'_, SIZE> {
209 fn zeroize(&mut self) {
210 match self {
211 KeyBufferMut::Borrowed(buf) => buf.zeroize(),
212 #[cfg(feature = "alloc")]
213 KeyBufferMut::Owned(buf) => buf.zeroize(),
214 }
215 }
216}
217
218#[derive(Debug)]
221#[must_use]
222pub struct PublicKey<'a>(KeyBufferMut<'a, CRYPTO_PUBLICKEYBYTES>);
223
224impl PublicKey<'_> {
225 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
227 #[cfg(feature = "alloc")]
228 pub fn to_owned(&self) -> PublicKey<'static> {
229 PublicKey(self.0.to_owned())
230 }
231
232 pub fn as_array(&self) -> &[u8; CRYPTO_PUBLICKEYBYTES] {
233 self.0.as_ref()
234 }
235}
236
237impl AsRef<[u8]> for PublicKey<'_> {
238 fn as_ref(&self) -> &[u8] {
239 self.0.as_ref()
240 }
241}
242
243impl<'a> From<&'a mut [u8; CRYPTO_PUBLICKEYBYTES]> for PublicKey<'a> {
244 fn from(data: &'a mut [u8; CRYPTO_PUBLICKEYBYTES]) -> Self {
245 Self(KeyBufferMut::Borrowed(data))
246 }
247}
248
249#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
250#[cfg(feature = "alloc")]
251impl From<Box<[u8; CRYPTO_PUBLICKEYBYTES]>> for PublicKey<'static> {
252 fn from(data: Box<[u8; CRYPTO_PUBLICKEYBYTES]>) -> Self {
253 Self(KeyBufferMut::Owned(data))
254 }
255}
256
257#[cfg(feature = "zeroize")]
258impl zeroize::Zeroize for PublicKey<'_> {
259 fn zeroize(&mut self) {
260 self.0.zeroize();
261 }
262}
263
264#[cfg(feature = "zeroize")]
265impl zeroize::ZeroizeOnDrop for PublicKey<'_> {}
266
267impl Drop for PublicKey<'_> {
268 fn drop(&mut self) {
269 #[cfg(feature = "zeroize")]
270 {
271 use zeroize::Zeroize;
272 self.zeroize();
273 }
274 }
275}
276
277#[must_use]
282pub struct SecretKey<'a>(KeyBufferMut<'a, CRYPTO_SECRETKEYBYTES>);
283
284impl SecretKey<'_> {
285 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
287 #[cfg(feature = "alloc")]
288 pub fn to_owned(&self) -> SecretKey<'static> {
289 SecretKey(self.0.to_owned())
290 }
291
292 pub fn as_array(&self) -> &[u8; CRYPTO_SECRETKEYBYTES] {
299 self.0.as_ref()
300 }
301}
302
303impl Debug for SecretKey<'_> {
304 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
305 f.debug_tuple("SecretKey").field(&"-- redacted --").finish()
306 }
307}
308
309impl AsRef<[u8]> for SecretKey<'_> {
310 fn as_ref(&self) -> &[u8] {
311 self.0.as_ref()
312 }
313}
314
315impl<'a> From<&'a mut [u8; CRYPTO_SECRETKEYBYTES]> for SecretKey<'a> {
316 fn from(data: &'a mut [u8; CRYPTO_SECRETKEYBYTES]) -> Self {
319 Self(KeyBufferMut::Borrowed(data))
320 }
321}
322
323#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
324#[cfg(feature = "alloc")]
325impl From<Box<[u8; CRYPTO_SECRETKEYBYTES]>> for SecretKey<'static> {
326 fn from(data: Box<[u8; CRYPTO_SECRETKEYBYTES]>) -> Self {
327 Self(KeyBufferMut::Owned(data))
328 }
329}
330
331#[cfg(feature = "zeroize")]
332impl zeroize::Zeroize for SecretKey<'_> {
333 fn zeroize(&mut self) {
334 self.0.zeroize();
335 }
336}
337
338#[cfg(feature = "zeroize")]
339impl zeroize::ZeroizeOnDrop for SecretKey<'_> {}
340
341impl Drop for SecretKey<'_> {
342 fn drop(&mut self) {
343 #[cfg(feature = "zeroize")]
344 {
345 use zeroize::Zeroize;
346 self.zeroize();
347 }
348 }
349}
350
351#[derive(Debug)]
353#[must_use]
354pub struct Ciphertext([u8; CRYPTO_CIPHERTEXTBYTES]);
355
356impl Ciphertext {
357 pub fn as_array(&self) -> &[u8; CRYPTO_CIPHERTEXTBYTES] {
358 &self.0
359 }
360}
361
362impl AsRef<[u8]> for Ciphertext {
363 fn as_ref(&self) -> &[u8] {
364 self.0.as_ref()
365 }
366}
367
368impl From<[u8; CRYPTO_CIPHERTEXTBYTES]> for Ciphertext {
369 fn from(data: [u8; CRYPTO_CIPHERTEXTBYTES]) -> Self {
370 Self(data)
371 }
372}
373
374#[cfg(feature = "zeroize")]
375impl zeroize::Zeroize for Ciphertext {
376 fn zeroize(&mut self) {
377 self.0.zeroize();
378 }
379}
380
381#[cfg(feature = "zeroize")]
382impl zeroize::ZeroizeOnDrop for Ciphertext {}
383
384impl Drop for Ciphertext {
385 fn drop(&mut self) {
386 #[cfg(feature = "zeroize")]
387 {
388 use zeroize::Zeroize;
389 self.zeroize();
390 }
391 }
392}
393
394#[must_use]
397pub struct SharedSecret<'a>(KeyBufferMut<'a, CRYPTO_BYTES>);
398
399impl SharedSecret<'_> {
400 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
402 #[cfg(feature = "alloc")]
403 pub fn to_owned(&self) -> SharedSecret<'static> {
404 SharedSecret(self.0.to_owned())
405 }
406
407 pub fn as_array(&self) -> &[u8; CRYPTO_BYTES] {
408 self.0.as_ref()
409 }
410}
411
412impl Debug for SharedSecret<'_> {
413 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
414 f.debug_tuple("SharedSecret")
415 .field(&"-- redacted --")
416 .finish()
417 }
418}
419
420impl AsRef<[u8]> for SharedSecret<'_> {
421 fn as_ref(&self) -> &[u8] {
422 self.0.as_ref()
423 }
424}
425
426#[cfg(feature = "zeroize")]
427impl zeroize::Zeroize for SharedSecret<'_> {
428 fn zeroize(&mut self) {
429 self.0.zeroize();
430 }
431}
432
433#[cfg(feature = "zeroize")]
434impl zeroize::ZeroizeOnDrop for SharedSecret<'_> {}
435
436impl Drop for SharedSecret<'_> {
437 fn drop(&mut self) {
438 #[cfg(feature = "zeroize")]
439 {
440 use zeroize::Zeroize;
441 self.zeroize();
442 }
443 }
444}
445
446pub fn keypair<'public, 'secret, R: CryptoRng + Rng>(
452 public_key_buf: &'public mut [u8; CRYPTO_PUBLICKEYBYTES],
453 secret_key_buf: &'secret mut [u8; CRYPTO_SECRETKEYBYTES],
454 rng: &mut R,
455) -> (PublicKey<'public>, SecretKey<'secret>) {
456 operations::crypto_kem_keypair(public_key_buf, secret_key_buf, rng);
457
458 (
459 PublicKey(KeyBufferMut::Borrowed(public_key_buf)),
460 SecretKey(KeyBufferMut::Borrowed(secret_key_buf)),
461 )
462}
463
464#[cfg(feature = "alloc")]
467#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
468pub fn keypair_boxed<R: CryptoRng + Rng>(rng: &mut R) -> (PublicKey<'static>, SecretKey<'static>) {
469 let mut public_key_buf = util::alloc_boxed_array::<CRYPTO_PUBLICKEYBYTES>();
470 let mut secret_key_buf = util::alloc_boxed_array::<CRYPTO_SECRETKEYBYTES>();
471
472 operations::crypto_kem_keypair(&mut public_key_buf, &mut secret_key_buf, rng);
473
474 (
475 PublicKey(KeyBufferMut::Owned(public_key_buf)),
476 SecretKey(KeyBufferMut::Owned(secret_key_buf)),
477 )
478}
479
480pub fn encapsulate<'shared_secret, R: CryptoRng + Rng>(
487 public_key: &PublicKey<'_>,
488 shared_secret_buf: &'shared_secret mut [u8; CRYPTO_BYTES],
489 rng: &mut R,
490) -> (Ciphertext, SharedSecret<'shared_secret>) {
491 let mut shared_secret_buf = KeyBufferMut::Borrowed(shared_secret_buf);
492 let mut ciphertext_buf = [0u8; CRYPTO_CIPHERTEXTBYTES];
493
494 operations::crypto_kem_enc(
495 &mut ciphertext_buf,
496 shared_secret_buf.as_mut(),
497 public_key.0.as_ref(),
498 rng,
499 );
500
501 (Ciphertext(ciphertext_buf), SharedSecret(shared_secret_buf))
502}
503
504#[cfg(feature = "alloc")]
507#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
508pub fn encapsulate_boxed<R: CryptoRng + Rng>(
509 public_key: &PublicKey<'_>,
510 rng: &mut R,
511) -> (Ciphertext, SharedSecret<'static>) {
512 let mut shared_secret_buf = KeyBufferMut::Owned(Box::new([0u8; CRYPTO_BYTES]));
513 let mut ciphertext_buf = [0u8; CRYPTO_CIPHERTEXTBYTES];
514
515 operations::crypto_kem_enc(
516 &mut ciphertext_buf,
517 shared_secret_buf.as_mut(),
518 public_key.0.as_ref(),
519 rng,
520 );
521
522 (Ciphertext(ciphertext_buf), SharedSecret(shared_secret_buf))
523}
524
525pub fn decapsulate<'shared_secret>(
530 ciphertext: &Ciphertext,
531 secret_key: &SecretKey,
532 shared_secret_buf: &'shared_secret mut [u8; CRYPTO_BYTES],
533) -> SharedSecret<'shared_secret> {
534 let mut shared_secret_buf = KeyBufferMut::Borrowed(shared_secret_buf);
535
536 operations::crypto_kem_dec(
537 shared_secret_buf.as_mut(),
538 ciphertext.as_array(),
539 secret_key.as_array(),
540 );
541
542 SharedSecret(shared_secret_buf)
543}
544
545#[cfg(feature = "alloc")]
548#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
549pub fn decapsulate_boxed(ciphertext: &Ciphertext, secret_key: &SecretKey) -> SharedSecret<'static> {
550 let mut shared_secret_buf = KeyBufferMut::Owned(Box::new([0u8; CRYPTO_BYTES]));
551
552 operations::crypto_kem_dec(
553 shared_secret_buf.as_mut(),
554 ciphertext.as_array(),
555 secret_key.as_array(),
556 );
557
558 SharedSecret(shared_secret_buf)
559}
560
561#[cfg(feature = "wasm")]
562mod wasm;
563
564