clatter 2.2.0

no_std compatible implementation of Noise protocol framework with Post-Quantum extensions
Documentation
//! ML-KEM implementation by PQClean: https://github.com/pqclean/pqclean/,
//! bindings generated by https://github.com/rustpq/pqcrypto.

use pqcrypto_mlkem::{mlkem1024, mlkem512, mlkem768};
use pqcrypto_traits::kem::{Ciphertext, PublicKey, SecretKey, SharedSecret};

use crate::bytearray::{ByteArray, SensitiveByteArray};
use crate::error::KemError;
use crate::traits::{CryptoComponent, Kem, Rng};
use crate::KeyPair;

/// ML-KEM-512 KEM implementation
#[derive(Clone)]
pub struct MlKem512;
/// ML-KEM-768 KEM implementation
#[derive(Clone)]
pub struct MlKem768;
/// ML-KEM-1024 KEM implementation
#[derive(Clone)]
pub struct MlKem1024;

impl CryptoComponent for MlKem512 {
    fn name() -> &'static str {
        "MLKEM512"
    }
}

impl CryptoComponent for MlKem768 {
    fn name() -> &'static str {
        "MLKEM768"
    }
}

impl CryptoComponent for MlKem1024 {
    fn name() -> &'static str {
        "MLKEM1024"
    }
}

macro_rules! impl_ml_kem {
    ($kyber:ty, $module:ident) => {
        impl Kem for $kyber {
            #[cfg(feature = "alloc")]
            type SecretKey =
                SensitiveByteArray<crate::bytearray::HeapArray<{ $module::secret_key_bytes() }>>;
            #[cfg(not(feature = "alloc"))]
            type SecretKey = SensitiveByteArray<[u8; $module::secret_key_bytes()]>;

            #[cfg(feature = "alloc")]
            type PubKey = crate::bytearray::HeapArray<{ $module::public_key_bytes() }>;
            #[cfg(not(feature = "alloc"))]
            type PubKey = [u8; $module::public_key_bytes()];

            #[cfg(feature = "alloc")]
            type Ct = crate::bytearray::HeapArray<{ $module::ciphertext_bytes() }>;
            #[cfg(not(feature = "alloc"))]
            type Ct = [u8; $module::ciphertext_bytes()];

            type Ss = SensitiveByteArray<[u8; $module::shared_secret_bytes()]>;

            fn genkey_rng<R: Rng>(
                _rng: &mut R,
            ) -> crate::error::KemResult<crate::KeyPair<Self::PubKey, Self::SecretKey>> {
                // PQClean uses their own RNG
                let (pk, sk) = $module::keypair();
                Ok(KeyPair {
                    public: ByteArray::from_slice(pk.as_bytes()),
                    secret: SensitiveByteArray::from_slice(sk.as_bytes()),
                })
            }

            fn encapsulate<R: Rng>(
                pk: &[u8],
                _rng: &mut R,
            ) -> crate::error::KemResult<(Self::Ct, Self::Ss)> {
                let pk = $module::PublicKey::from_bytes(pk).map_err(|_| KemError::Input)?;
                // PQClean uses their own RNG
                let (ss, ct) = $module::encapsulate(&pk);
                Ok((
                    Self::Ct::from_slice(ct.as_bytes()),
                    Self::Ss::from_slice(ss.as_bytes()),
                ))
            }

            fn decapsulate(ct: &[u8], sk: &[u8]) -> crate::error::KemResult<Self::Ss> {
                let sk = $module::SecretKey::from_bytes(sk).map_err(|_| KemError::Input)?;
                let ct = $module::Ciphertext::from_bytes(ct).map_err(|_| KemError::Input)?;
                let ss = $module::decapsulate(&ct, &sk);
                Ok(Self::Ss::from_slice(&ss.as_bytes()))
            }
        }
    };
}

impl_ml_kem!(MlKem512, mlkem512);
impl_ml_kem!(MlKem768, mlkem768);
impl_ml_kem!(MlKem1024, mlkem1024);