use classic_mceliece_rust::{
decapsulate_boxed, encapsulate_boxed, keypair_boxed, Ciphertext as Ct, PublicKey as Pk,
SecretKey as Sk, SharedSecret as Ss, CRYPTO_PUBLICKEYBYTES as MCELIECE_PUBLIC_KEY_LEN,
CRYPTO_SECRETKEYBYTES as MCELIECE_SECRET_KEY_LEN,
};
use libcrux_traits::kem::{KEMError, KeyPair as KEMKeyPair, KEM};
use tls_codec::{Deserialize, Serialize, SerializeBytes, Size, VLByteSlice, VLBytes};
const MCELIECE460896F_CIPHERTEXT_LEN: usize = 156;
pub struct Ciphertext(pub(crate) Ct);
impl Serialize for Ciphertext {
fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
VLByteSlice(self.0.as_ref()).tls_serialize(writer)
}
}
impl Deserialize for Ciphertext {
fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<Self, tls_codec::Error>
where
Self: Sized,
{
let bytes_deserialized = VLBytes::tls_deserialize(bytes)?;
Ok(Ciphertext(Ct::from(
<[u8; MCELIECE460896F_CIPHERTEXT_LEN]>::try_from(bytes_deserialized.as_slice())?,
)))
}
}
impl Size for Ciphertext {
fn tls_serialized_len(&self) -> usize {
VLByteSlice(self.0.as_ref()).tls_serialized_len()
}
}
pub struct PublicKey(pub(crate) Pk<'static>);
impl From<Box<[u8; MCELIECE_PUBLIC_KEY_LEN]>> for PublicKey {
fn from(value: Box<[u8; MCELIECE_PUBLIC_KEY_LEN]>) -> Self {
Self(Pk::from(value))
}
}
impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
pub struct SecretKey(pub(crate) Sk<'static>);
impl AsRef<[u8]> for SecretKey {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl From<Box<[u8; MCELIECE_SECRET_KEY_LEN]>> for SecretKey {
fn from(value: Box<[u8; MCELIECE_SECRET_KEY_LEN]>) -> Self {
Self(Sk::from(value))
}
}
pub struct KeyPair {
pub pk: PublicKey,
pub sk: SecretKey,
}
impl KeyPair {
pub fn generate_key_pair(rng: &mut impl rand::CryptoRng) -> Self {
let mut rng = McElieceRng::new(rng);
let (pk, sk) = keypair_boxed(&mut rng);
Self {
pk: PublicKey(pk),
sk: SecretKey(sk),
}
}
}
impl Size for PublicKey {
fn tls_serialized_len(&self) -> usize {
VLByteSlice(self.0.as_ref()).tls_serialized_len()
}
}
impl Serialize for PublicKey {
fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
VLByteSlice(self.0.as_ref()).tls_serialize(writer)
}
}
impl Serialize for &PublicKey {
fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
VLByteSlice(self.0.as_ref()).tls_serialize(writer)
}
}
impl Size for &PublicKey {
fn tls_serialized_len(&self) -> usize {
VLByteSlice(self.0.as_ref()).tls_serialized_len()
}
}
impl<'a> Size for SharedSecret<'a> {
fn tls_serialized_len(&self) -> usize {
VLByteSlice(self.0.as_ref()).tls_serialized_len()
}
}
impl<'a> SerializeBytes for SharedSecret<'a> {
fn tls_serialize(&self) -> Result<Vec<u8>, tls_codec::Error> {
SerializeBytes::tls_serialize(&self.0.as_ref())
}
}
pub struct SharedSecret<'a>(pub(crate) Ss<'a>);
impl<'a> Serialize for SharedSecret<'a> {
fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
VLByteSlice(self.0.as_ref()).tls_serialize(writer)
}
}
pub struct ClassicMcEliece;
#[cfg(feature = "v1")]
impl crate::v1::traits::private::Seal for ClassicMcEliece {}
pub(crate) struct McElieceRng<'a, T: rand::CryptoRng> {
inner_rng: &'a mut T,
}
impl<'a, T: rand::CryptoRng> McElieceRng<'a, T> {
pub(crate) fn new(inner_rng: &'a mut T) -> Self {
Self { inner_rng }
}
}
impl<T: rand::CryptoRng> rand_old::RngCore for McElieceRng<'_, T> {
fn next_u32(&mut self) -> u32 {
self.inner_rng.next_u32()
}
fn next_u64(&mut self) -> u64 {
self.inner_rng.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.inner_rng.fill_bytes(dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_old::Error> {
self.inner_rng.fill_bytes(dest);
Ok(())
}
}
impl<T: rand::CryptoRng> rand_old::CryptoRng for McElieceRng<'_, T> {}
impl KEM for ClassicMcEliece {
type Ciphertext = Ciphertext;
type SharedSecret = SharedSecret<'static>;
type EncapsulationKey = PublicKey;
type DecapsulationKey = Sk<'static>;
fn generate_key_pair(
rng: &mut impl rand::CryptoRng,
) -> Result<KEMKeyPair<Sk<'static>, PublicKey>, KEMError> {
let mut rng = McElieceRng::new(rng);
let (pk, sk) = keypair_boxed(&mut rng);
Ok((sk, PublicKey(pk)))
}
fn encapsulate(
ek: &Self::EncapsulationKey,
rng: &mut impl rand::CryptoRng,
) -> Result<(Self::SharedSecret, Self::Ciphertext), KEMError> {
let mut rng = McElieceRng::new(rng);
let (enc, ss) = encapsulate_boxed(&ek.0, &mut rng);
Ok((SharedSecret(ss), Ciphertext(enc)))
}
fn decapsulate(
dk: &Self::DecapsulationKey,
ctxt: &Self::Ciphertext,
) -> Result<Self::SharedSecret, KEMError> {
let ss = decapsulate_boxed(&ctxt.0, dk);
Ok(SharedSecret(ss))
}
}
#[cfg(feature = "v1")]
impl crate::v1::traits::PSQ for ClassicMcEliece {
type InnerKEM = Self;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::v1::traits::PSQ;
#[test]
#[cfg(feature = "v1")]
fn simple_classic_mceliece() {
let mut rng = rand::rng();
let (sk, pk) = ClassicMcEliece::generate_key_pair(&mut rng).unwrap();
let sctx = b"test context";
let (psk_initiator, message) =
ClassicMcEliece::encapsulate_psq(&pk, sctx, &mut rng).unwrap();
let psk_responder = ClassicMcEliece::decapsulate_psq(&sk, &pk, &message, sctx).unwrap();
assert_eq!(psk_initiator, psk_responder);
}
}