#![no_std]
#![forbid(unsafe_code)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![allow(clippy::collapsible_if)]
#![allow(clippy::identity_op)]
#![allow(clippy::manual_div_ceil)]
#![allow(clippy::manual_memcpy)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::unnecessary_map_or)]
#![allow(clippy::unnecessary_mut_passed)]
mod api;
mod benes;
mod bm;
mod controlbits;
mod crypto_hash;
mod decrypt;
mod encrypt;
mod gf;
mod int32_sort;
mod libq_provider;
mod operations;
mod params;
mod pk_gen;
mod root;
mod sk_gen;
mod synd;
mod test_utils;
mod transpose;
mod uint64_sort;
mod util;
#[cfg(feature = "nist-aes-rng")]
#[cfg_attr(docsrs, doc(cfg(feature = "nist-aes-rng")))]
mod nist_aes_rng;
use core::fmt::Debug;
use rand_core::{
CryptoRng,
Rng,
};
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
pub use api::{
CRYPTO_BYTES,
CRYPTO_CIPHERTEXTBYTES,
CRYPTO_PRIMITIVE,
CRYPTO_PUBLICKEYBYTES,
CRYPTO_SECRETKEYBYTES,
};
pub use lib_q_random::ClassicalMcElieceRng as LibQRng;
#[cfg(feature = "alloc")]
pub use libq_provider::LibQCbKemProvider;
#[cfg(feature = "nist-aes-rng")]
#[cfg_attr(docsrs, doc(cfg(feature = "nist-aes-rng")))]
pub use nist_aes_rng::{
AesState,
MAX_BYTES_PER_REQUEST,
NistDrbgError,
RESEED_INTERVAL,
SEEDLEN,
};
mod macros {
macro_rules! sub {
($var:expr, $offset:expr, $len:expr) => {{
<&[u8; $len]>::try_from(&$var[$offset..($offset + $len)])
.expect("slice has the correct length")
}};
(mut $var:expr, $offset:expr, $len:expr) => {{
<&mut [u8; $len]>::try_from(&mut $var[$offset..($offset + $len)])
.expect("slice has the correct length")
}};
($var:expr, $offset:expr, $len:expr, $t:ty) => {{
<&[$t; $len]>::try_from(&$var[$offset..($offset + $len)])
.expect("slice has the correct length")
}};
(mut $var:expr, $offset:expr, $len:expr, $t:ty) => {{
<&mut [$t; $len]>::try_from(&mut $var[$offset..($offset + $len)])
.expect("slice has the correct length")
}};
}
pub(crate) use sub;
}
#[derive(Debug)]
enum KeyBufferMut<'a, const SIZE: usize> {
Borrowed(&'a mut [u8; SIZE]),
#[cfg(feature = "alloc")]
Owned(Box<[u8; SIZE]>),
}
impl<const SIZE: usize> KeyBufferMut<'_, SIZE> {
#[cfg(feature = "alloc")]
fn to_owned(&self) -> KeyBufferMut<'static, SIZE> {
let mut new_buffer = util::alloc_boxed_array::<SIZE>();
new_buffer.copy_from_slice(self.as_ref());
KeyBufferMut::Owned(new_buffer)
}
}
impl<const SIZE: usize> AsRef<[u8; SIZE]> for KeyBufferMut<'_, SIZE> {
fn as_ref(&self) -> &[u8; SIZE] {
match &self {
KeyBufferMut::Borrowed(buf) => buf,
#[cfg(feature = "alloc")]
KeyBufferMut::Owned(buf) => buf.as_ref(),
}
}
}
impl<const SIZE: usize> AsMut<[u8; SIZE]> for KeyBufferMut<'_, SIZE> {
fn as_mut(&mut self) -> &mut [u8; SIZE] {
match self {
KeyBufferMut::Borrowed(buf) => buf,
#[cfg(feature = "alloc")]
KeyBufferMut::Owned(buf) => buf.as_mut(),
}
}
}
#[cfg(feature = "zeroize")]
impl<const SIZE: usize> zeroize::Zeroize for KeyBufferMut<'_, SIZE> {
fn zeroize(&mut self) {
match self {
KeyBufferMut::Borrowed(buf) => buf.zeroize(),
#[cfg(feature = "alloc")]
KeyBufferMut::Owned(buf) => buf.zeroize(),
}
}
}
#[derive(Debug)]
#[must_use]
pub struct PublicKey<'a>(KeyBufferMut<'a, CRYPTO_PUBLICKEYBYTES>);
impl PublicKey<'_> {
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
pub fn to_owned(&self) -> PublicKey<'static> {
PublicKey(self.0.to_owned())
}
pub fn as_array(&self) -> &[u8; CRYPTO_PUBLICKEYBYTES] {
self.0.as_ref()
}
}
impl AsRef<[u8]> for PublicKey<'_> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl<'a> From<&'a mut [u8; CRYPTO_PUBLICKEYBYTES]> for PublicKey<'a> {
fn from(data: &'a mut [u8; CRYPTO_PUBLICKEYBYTES]) -> Self {
Self(KeyBufferMut::Borrowed(data))
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
impl From<Box<[u8; CRYPTO_PUBLICKEYBYTES]>> for PublicKey<'static> {
fn from(data: Box<[u8; CRYPTO_PUBLICKEYBYTES]>) -> Self {
Self(KeyBufferMut::Owned(data))
}
}
#[cfg(feature = "zeroize")]
impl zeroize::Zeroize for PublicKey<'_> {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
#[cfg(feature = "zeroize")]
impl zeroize::ZeroizeOnDrop for PublicKey<'_> {}
impl Drop for PublicKey<'_> {
fn drop(&mut self) {
#[cfg(feature = "zeroize")]
{
use zeroize::Zeroize;
self.zeroize();
}
}
}
#[must_use]
pub struct SecretKey<'a>(KeyBufferMut<'a, CRYPTO_SECRETKEYBYTES>);
impl SecretKey<'_> {
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
pub fn to_owned(&self) -> SecretKey<'static> {
SecretKey(self.0.to_owned())
}
pub fn as_array(&self) -> &[u8; CRYPTO_SECRETKEYBYTES] {
self.0.as_ref()
}
}
impl Debug for SecretKey<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("SecretKey").field(&"-- redacted --").finish()
}
}
impl AsRef<[u8]> for SecretKey<'_> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl<'a> From<&'a mut [u8; CRYPTO_SECRETKEYBYTES]> for SecretKey<'a> {
fn from(data: &'a mut [u8; CRYPTO_SECRETKEYBYTES]) -> Self {
Self(KeyBufferMut::Borrowed(data))
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
impl From<Box<[u8; CRYPTO_SECRETKEYBYTES]>> for SecretKey<'static> {
fn from(data: Box<[u8; CRYPTO_SECRETKEYBYTES]>) -> Self {
Self(KeyBufferMut::Owned(data))
}
}
#[cfg(feature = "zeroize")]
impl zeroize::Zeroize for SecretKey<'_> {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
#[cfg(feature = "zeroize")]
impl zeroize::ZeroizeOnDrop for SecretKey<'_> {}
impl Drop for SecretKey<'_> {
fn drop(&mut self) {
#[cfg(feature = "zeroize")]
{
use zeroize::Zeroize;
self.zeroize();
}
}
}
#[derive(Debug)]
#[must_use]
pub struct Ciphertext([u8; CRYPTO_CIPHERTEXTBYTES]);
impl Ciphertext {
pub fn as_array(&self) -> &[u8; CRYPTO_CIPHERTEXTBYTES] {
&self.0
}
}
impl AsRef<[u8]> for Ciphertext {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl From<[u8; CRYPTO_CIPHERTEXTBYTES]> for Ciphertext {
fn from(data: [u8; CRYPTO_CIPHERTEXTBYTES]) -> Self {
Self(data)
}
}
#[cfg(feature = "zeroize")]
impl zeroize::Zeroize for Ciphertext {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
#[cfg(feature = "zeroize")]
impl zeroize::ZeroizeOnDrop for Ciphertext {}
impl Drop for Ciphertext {
fn drop(&mut self) {
#[cfg(feature = "zeroize")]
{
use zeroize::Zeroize;
self.zeroize();
}
}
}
#[must_use]
pub struct SharedSecret<'a>(KeyBufferMut<'a, CRYPTO_BYTES>);
impl SharedSecret<'_> {
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
pub fn to_owned(&self) -> SharedSecret<'static> {
SharedSecret(self.0.to_owned())
}
pub fn as_array(&self) -> &[u8; CRYPTO_BYTES] {
self.0.as_ref()
}
}
impl Debug for SharedSecret<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("SharedSecret")
.field(&"-- redacted --")
.finish()
}
}
impl AsRef<[u8]> for SharedSecret<'_> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
#[cfg(feature = "zeroize")]
impl zeroize::Zeroize for SharedSecret<'_> {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
#[cfg(feature = "zeroize")]
impl zeroize::ZeroizeOnDrop for SharedSecret<'_> {}
impl Drop for SharedSecret<'_> {
fn drop(&mut self) {
#[cfg(feature = "zeroize")]
{
use zeroize::Zeroize;
self.zeroize();
}
}
}
pub fn keypair<'public, 'secret, R: CryptoRng + Rng>(
public_key_buf: &'public mut [u8; CRYPTO_PUBLICKEYBYTES],
secret_key_buf: &'secret mut [u8; CRYPTO_SECRETKEYBYTES],
rng: &mut R,
) -> (PublicKey<'public>, SecretKey<'secret>) {
operations::crypto_kem_keypair(public_key_buf, secret_key_buf, rng);
(
PublicKey(KeyBufferMut::Borrowed(public_key_buf)),
SecretKey(KeyBufferMut::Borrowed(secret_key_buf)),
)
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn keypair_boxed<R: CryptoRng + Rng>(rng: &mut R) -> (PublicKey<'static>, SecretKey<'static>) {
let mut public_key_buf = util::alloc_boxed_array::<CRYPTO_PUBLICKEYBYTES>();
let mut secret_key_buf = util::alloc_boxed_array::<CRYPTO_SECRETKEYBYTES>();
operations::crypto_kem_keypair(&mut public_key_buf, &mut secret_key_buf, rng);
(
PublicKey(KeyBufferMut::Owned(public_key_buf)),
SecretKey(KeyBufferMut::Owned(secret_key_buf)),
)
}
pub fn encapsulate<'shared_secret, R: CryptoRng + Rng>(
public_key: &PublicKey<'_>,
shared_secret_buf: &'shared_secret mut [u8; CRYPTO_BYTES],
rng: &mut R,
) -> (Ciphertext, SharedSecret<'shared_secret>) {
let mut shared_secret_buf = KeyBufferMut::Borrowed(shared_secret_buf);
let mut ciphertext_buf = [0u8; CRYPTO_CIPHERTEXTBYTES];
operations::crypto_kem_enc(
&mut ciphertext_buf,
shared_secret_buf.as_mut(),
public_key.0.as_ref(),
rng,
);
(Ciphertext(ciphertext_buf), SharedSecret(shared_secret_buf))
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn encapsulate_boxed<R: CryptoRng + Rng>(
public_key: &PublicKey<'_>,
rng: &mut R,
) -> (Ciphertext, SharedSecret<'static>) {
let mut shared_secret_buf = KeyBufferMut::Owned(Box::new([0u8; CRYPTO_BYTES]));
let mut ciphertext_buf = [0u8; CRYPTO_CIPHERTEXTBYTES];
operations::crypto_kem_enc(
&mut ciphertext_buf,
shared_secret_buf.as_mut(),
public_key.0.as_ref(),
rng,
);
(Ciphertext(ciphertext_buf), SharedSecret(shared_secret_buf))
}
pub fn decapsulate<'shared_secret>(
ciphertext: &Ciphertext,
secret_key: &SecretKey,
shared_secret_buf: &'shared_secret mut [u8; CRYPTO_BYTES],
) -> SharedSecret<'shared_secret> {
let mut shared_secret_buf = KeyBufferMut::Borrowed(shared_secret_buf);
operations::crypto_kem_dec(
shared_secret_buf.as_mut(),
ciphertext.as_array(),
secret_key.as_array(),
);
SharedSecret(shared_secret_buf)
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn decapsulate_boxed(ciphertext: &Ciphertext, secret_key: &SecretKey) -> SharedSecret<'static> {
let mut shared_secret_buf = KeyBufferMut::Owned(Box::new([0u8; CRYPTO_BYTES]));
operations::crypto_kem_dec(
shared_secret_buf.as_mut(),
ciphertext.as_array(),
secret_key.as_array(),
);
SharedSecret(shared_secret_buf)
}
#[cfg(feature = "wasm")]
mod wasm;