#![cfg(mlkem)]
use crate::sys;
#[cfg(random)]
use crate::random::RNG;
pub struct MlKem {
ws_key: *mut sys::MlKemKey,
}
impl MlKem {
pub const TYPE_512: i32 = sys::WC_ML_KEM_512 as i32;
pub const TYPE_768: i32 = sys::WC_ML_KEM_768 as i32;
pub const TYPE_1024: i32 = sys::WC_ML_KEM_1024 as i32;
pub const SYM_SIZE: usize = sys::WC_ML_KEM_SYM_SZ as usize;
pub const SHARED_SECRET_SIZE: usize = sys::WC_ML_KEM_SS_SZ as usize;
pub const MAKEKEY_RAND_SIZE: usize = sys::WC_ML_KEM_MAKEKEY_RAND_SZ as usize;
pub const ENC_RAND_SIZE: usize = sys::WC_ML_KEM_ENC_RAND_SZ as usize;
#[cfg(random)]
pub fn generate(key_type: i32, rng: &RNG) -> Result<Self, i32> {
Self::generate_ex(key_type, rng, None, None)
}
#[cfg(random)]
pub fn generate_ex(
key_type: i32,
rng: &RNG,
heap: Option<*mut core::ffi::c_void>,
dev_id: Option<i32>,
) -> Result<Self, i32> {
let key = Self::new_ex(key_type, heap, dev_id)?;
let rc = unsafe { sys::wc_MlKemKey_MakeKey(key.ws_key, rng.wc_rng) };
if rc != 0 {
return Err(rc);
}
Ok(key)
}
pub fn generate_with_random(key_type: i32, rand: &[u8]) -> Result<Self, i32> {
Self::generate_with_random_ex(key_type, rand, None, None)
}
pub fn generate_with_random_ex(
key_type: i32,
rand: &[u8],
heap: Option<*mut core::ffi::c_void>,
dev_id: Option<i32>,
) -> Result<Self, i32> {
if rand.len() != Self::MAKEKEY_RAND_SIZE {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let key = Self::new_ex(key_type, heap, dev_id)?;
let rc = unsafe {
sys::wc_MlKemKey_MakeKeyWithRandom(
key.ws_key,
rand.as_ptr(),
rand.len() as core::ffi::c_int,
)
};
if rc != 0 {
return Err(rc);
}
Ok(key)
}
pub fn new(key_type: i32) -> Result<Self, i32> {
Self::new_ex(key_type, None, None)
}
pub fn new_ex(
key_type: i32,
heap: Option<*mut core::ffi::c_void>,
dev_id: Option<i32>,
) -> Result<Self, i32> {
let heap = match heap {
Some(h) => h,
None => core::ptr::null_mut(),
};
let dev_id = match dev_id {
Some(id) => id,
None => sys::INVALID_DEVID,
};
let ws_key = unsafe { sys::wc_MlKemKey_New(key_type, heap, dev_id) };
if ws_key.is_null() {
return Err(sys::wolfCrypt_ErrorCodes_MEMORY_E);
}
Ok(MlKem { ws_key })
}
pub fn cipher_text_size(&self) -> Result<usize, i32> {
let mut len = 0u32;
let rc = unsafe { sys::wc_MlKemKey_CipherTextSize(self.ws_key, &mut len) };
if rc != 0 {
return Err(rc);
}
Ok(len as usize)
}
pub fn shared_secret_size(&self) -> Result<usize, i32> {
let mut len = 0u32;
let rc = unsafe { sys::wc_MlKemKey_SharedSecretSize(self.ws_key, &mut len) };
if rc != 0 {
return Err(rc);
}
Ok(len as usize)
}
pub fn private_key_size(&self) -> Result<usize, i32> {
let mut len = 0u32;
let rc = unsafe { sys::wc_MlKemKey_PrivateKeySize(self.ws_key, &mut len) };
if rc != 0 {
return Err(rc);
}
Ok(len as usize)
}
pub fn public_key_size(&self) -> Result<usize, i32> {
let mut len = 0u32;
let rc = unsafe { sys::wc_MlKemKey_PublicKeySize(self.ws_key, &mut len) };
if rc != 0 {
return Err(rc);
}
Ok(len as usize)
}
#[cfg(random)]
pub fn encapsulate(
&mut self,
ct: &mut [u8],
ss: &mut [u8],
rng: &RNG,
) -> Result<(), i32> {
let expected_ct_size = self.cipher_text_size()?;
if ct.len() != expected_ct_size {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
if ss.len() != Self::SHARED_SECRET_SIZE {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let rc = unsafe {
sys::wc_MlKemKey_Encapsulate(
self.ws_key,
ct.as_mut_ptr(),
ss.as_mut_ptr(),
rng.wc_rng,
)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
pub fn encapsulate_with_random(
&mut self,
ct: &mut [u8],
ss: &mut [u8],
rand: &[u8],
) -> Result<(), i32> {
if rand.len() != Self::ENC_RAND_SIZE {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let expected_ct_size = self.cipher_text_size()?;
if ct.len() != expected_ct_size {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
if ss.len() != Self::SHARED_SECRET_SIZE {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let rc = unsafe {
sys::wc_MlKemKey_EncapsulateWithRandom(
self.ws_key,
ct.as_mut_ptr(),
ss.as_mut_ptr(),
rand.as_ptr(),
rand.len() as core::ffi::c_int,
)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
pub fn decapsulate(&mut self, ss: &mut [u8], ct: &[u8]) -> Result<(), i32> {
if ss.len() != Self::SHARED_SECRET_SIZE {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let ct_size = crate::buffer_len_to_u32(ct.len())?;
let rc = unsafe {
sys::wc_MlKemKey_Decapsulate(
self.ws_key,
ss.as_mut_ptr(),
ct.as_ptr(),
ct_size,
)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
pub fn encode_public_key(&self, out: &mut [u8]) -> Result<(), i32> {
let out_size = crate::buffer_len_to_u32(out.len())?;
let rc = unsafe {
sys::wc_MlKemKey_EncodePublicKey(self.ws_key, out.as_mut_ptr(), out_size)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
pub fn encode_private_key(&self, out: &mut [u8]) -> Result<(), i32> {
let out_size = crate::buffer_len_to_u32(out.len())?;
let rc = unsafe {
sys::wc_MlKemKey_EncodePrivateKey(self.ws_key, out.as_mut_ptr(), out_size)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
pub fn decode_public_key(&mut self, data: &[u8]) -> Result<(), i32> {
let data_size = crate::buffer_len_to_u32(data.len())?;
let rc = unsafe {
sys::wc_MlKemKey_DecodePublicKey(self.ws_key, data.as_ptr(), data_size)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
pub fn decode_private_key(&mut self, data: &[u8]) -> Result<(), i32> {
let data_size = crate::buffer_len_to_u32(data.len())?;
let rc = unsafe {
sys::wc_MlKemKey_DecodePrivateKey(self.ws_key, data.as_ptr(), data_size)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
}
impl MlKem {
fn zeroize(&mut self) {
self.ws_key = core::ptr::null_mut();
}
}
impl Drop for MlKem {
fn drop(&mut self) {
unsafe {
sys::wc_MlKemKey_Delete(self.ws_key, core::ptr::null_mut());
}
self.zeroize();
}
}