#![cfg(dilithium)]
#[cfg(all(random, any(dilithium_make_key, dilithium_sign)))]
use crate::random::RNG;
use crate::sys;
use core::mem::MaybeUninit;
pub struct Dilithium {
ws_key: sys::dilithium_key,
}
impl Dilithium {
pub const LEVEL_44: u8 = sys::WC_ML_DSA_44 as u8;
pub const LEVEL_65: u8 = sys::WC_ML_DSA_65 as u8;
pub const LEVEL_87: u8 = sys::WC_ML_DSA_87 as u8;
#[cfg(dilithium_make_key_seed_sz)]
pub const DILITHIUM_SEED_SZ: usize = sys::DILITHIUM_SEED_SZ as usize;
#[cfg(dilithium_rnd_sz)]
pub const SIGN_SEED_SIZE: usize = sys::DILITHIUM_RND_SZ as usize;
#[cfg(dilithium_level2)]
pub const LEVEL2_KEY_SIZE: usize = sys::DILITHIUM_LEVEL2_KEY_SIZE as usize;
#[cfg(dilithium_level2)]
pub const LEVEL2_SIG_SIZE: usize = sys::DILITHIUM_LEVEL2_SIG_SIZE as usize;
#[cfg(dilithium_level2)]
pub const LEVEL2_PUB_KEY_SIZE: usize = sys::DILITHIUM_LEVEL2_PUB_KEY_SIZE as usize;
#[cfg(dilithium_level2)]
pub const LEVEL2_PRV_KEY_SIZE: usize =
sys::DILITHIUM_LEVEL2_PUB_KEY_SIZE as usize + sys::DILITHIUM_LEVEL2_KEY_SIZE as usize;
#[cfg(dilithium_level3)]
pub const LEVEL3_KEY_SIZE: usize = sys::DILITHIUM_LEVEL3_KEY_SIZE as usize;
#[cfg(dilithium_level3)]
pub const LEVEL3_SIG_SIZE: usize = sys::DILITHIUM_LEVEL3_SIG_SIZE as usize;
#[cfg(dilithium_level3)]
pub const LEVEL3_PUB_KEY_SIZE: usize = sys::DILITHIUM_LEVEL3_PUB_KEY_SIZE as usize;
#[cfg(dilithium_level3)]
pub const LEVEL3_PRV_KEY_SIZE: usize =
sys::DILITHIUM_LEVEL3_PUB_KEY_SIZE as usize + sys::DILITHIUM_LEVEL3_KEY_SIZE as usize;
#[cfg(dilithium_level5)]
pub const LEVEL5_KEY_SIZE: usize = sys::DILITHIUM_LEVEL5_KEY_SIZE as usize;
#[cfg(dilithium_level5)]
pub const LEVEL5_SIG_SIZE: usize = sys::DILITHIUM_LEVEL5_SIG_SIZE as usize;
#[cfg(dilithium_level5)]
pub const LEVEL5_PUB_KEY_SIZE: usize = sys::DILITHIUM_LEVEL5_PUB_KEY_SIZE as usize;
#[cfg(dilithium_level5)]
pub const LEVEL5_PRV_KEY_SIZE: usize =
sys::DILITHIUM_LEVEL5_PUB_KEY_SIZE as usize + sys::DILITHIUM_LEVEL5_KEY_SIZE as usize;
#[cfg(all(dilithium_make_key, random))]
pub fn generate(level: u8, rng: &mut RNG) -> Result<Self, i32> {
Self::generate_ex(level, rng, None, None)
}
#[cfg(all(dilithium_make_key, random))]
pub fn generate_ex(
level: u8,
rng: &mut RNG,
heap: Option<*mut core::ffi::c_void>,
dev_id: Option<i32>,
) -> Result<Self, i32> {
let mut key = Self::new_ex(heap, dev_id)?;
let rc = unsafe { sys::wc_dilithium_set_level(&mut key.ws_key, level) };
if rc != 0 {
return Err(rc);
}
let rc = unsafe { sys::wc_dilithium_make_key(&mut key.ws_key, &mut rng.wc_rng) };
if rc != 0 {
return Err(rc);
}
Ok(key)
}
#[cfg(dilithium_make_key_from_seed)]
pub fn generate_from_seed(level: u8, seed: &[u8]) -> Result<Self, i32> {
Self::generate_from_seed_ex(level, seed, None, None)
}
#[cfg(dilithium_make_key_from_seed)]
pub fn generate_from_seed_ex(
level: u8,
seed: &[u8],
heap: Option<*mut core::ffi::c_void>,
dev_id: Option<i32>,
) -> Result<Self, i32> {
#[cfg(dilithium_make_key_seed_sz)]
if seed.len() != Self::DILITHIUM_SEED_SZ {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let mut key = Self::new_ex(heap, dev_id)?;
let rc = unsafe { sys::wc_dilithium_set_level(&mut key.ws_key, level) };
if rc != 0 {
return Err(rc);
}
let rc = unsafe { sys::wc_dilithium_make_key_from_seed(&mut key.ws_key, seed.as_ptr()) };
if rc != 0 {
return Err(rc);
}
Ok(key)
}
pub fn new() -> Result<Self, i32> {
Self::new_ex(None, None)
}
pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option<i32>) -> Result<Self, i32> {
let mut ws_key: MaybeUninit<sys::dilithium_key> = MaybeUninit::uninit();
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 rc = unsafe { sys::wc_dilithium_init_ex(ws_key.as_mut_ptr(), heap, dev_id) };
if rc != 0 {
return Err(rc);
}
let ws_key = unsafe { ws_key.assume_init() };
Ok(Dilithium { ws_key })
}
pub fn set_level(&mut self, level: u8) -> Result<(), i32> {
let rc = unsafe { sys::wc_dilithium_set_level(&mut self.ws_key, level) };
if rc != 0 {
return Err(rc);
}
Ok(())
}
pub fn get_level(&mut self) -> Result<u8, i32> {
let mut level = 0u8;
let rc = unsafe { sys::wc_dilithium_get_level(&mut self.ws_key, &mut level) };
if rc != 0 {
return Err(rc);
}
Ok(level)
}
pub fn size(&mut self) -> Result<usize, i32> {
let rc = unsafe { sys::wc_dilithium_size(&mut self.ws_key) };
if rc < 0 {
return Err(rc);
}
Ok(rc as usize)
}
pub fn priv_size(&mut self) -> Result<usize, i32> {
let rc = unsafe { sys::wc_dilithium_priv_size(&mut self.ws_key) };
if rc < 0 {
return Err(rc);
}
Ok(rc as usize)
}
pub fn pub_size(&mut self) -> Result<usize, i32> {
let rc = unsafe { sys::wc_dilithium_pub_size(&mut self.ws_key) };
if rc < 0 {
return Err(rc);
}
Ok(rc as usize)
}
pub fn sig_size(&mut self) -> Result<usize, i32> {
let rc = unsafe { sys::wc_dilithium_sig_size(&mut self.ws_key) };
if rc < 0 {
return Err(rc);
}
Ok(rc as usize)
}
#[cfg(dilithium_check_key)]
pub fn check_key(&mut self) -> Result<(), i32> {
let rc = unsafe { sys::wc_dilithium_check_key(&mut self.ws_key) };
if rc != 0 {
return Err(rc);
}
Ok(())
}
#[cfg(dilithium_import)]
pub fn import_public(&mut self, public: &[u8]) -> Result<(), i32> {
let public_size = public.len() as u32;
let rc = unsafe {
sys::wc_dilithium_import_public(public.as_ptr(), public_size, &mut self.ws_key)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
#[cfg(dilithium_import)]
pub fn import_private(&mut self, private: &[u8]) -> Result<(), i32> {
let private_size = private.len() as u32;
let rc = unsafe {
sys::wc_dilithium_import_private(private.as_ptr(), private_size, &mut self.ws_key)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
#[cfg(dilithium_import)]
pub fn import_key(&mut self, private: &[u8], public: &[u8]) -> Result<(), i32> {
let private_size = private.len() as u32;
let public_size = public.len() as u32;
let rc = unsafe {
sys::wc_dilithium_import_key(
private.as_ptr(),
private_size,
public.as_ptr(),
public_size,
&mut self.ws_key,
)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
#[cfg(dilithium_export)]
pub fn export_public(&mut self, public: &mut [u8]) -> Result<usize, i32> {
let mut public_size = public.len() as u32;
let rc = unsafe {
sys::wc_dilithium_export_public(&mut self.ws_key, public.as_mut_ptr(), &mut public_size)
};
if rc != 0 {
return Err(rc);
}
Ok(public_size as usize)
}
#[cfg(dilithium_export)]
pub fn export_private(&mut self, private: &mut [u8]) -> Result<usize, i32> {
let mut private_size = private.len() as u32;
let rc = unsafe {
sys::wc_dilithium_export_private(
&mut self.ws_key,
private.as_mut_ptr(),
&mut private_size,
)
};
if rc != 0 {
return Err(rc);
}
Ok(private_size as usize)
}
#[cfg(dilithium_export)]
pub fn export_key(&mut self, private: &mut [u8], public: &mut [u8]) -> Result<(), i32> {
let mut private_size = private.len() as u32;
let mut public_size = public.len() as u32;
let rc = unsafe {
sys::wc_dilithium_export_key(
&mut self.ws_key,
private.as_mut_ptr(),
&mut private_size,
public.as_mut_ptr(),
&mut public_size,
)
};
if rc != 0 {
return Err(rc);
}
Ok(())
}
#[cfg(all(dilithium_sign, random))]
pub fn sign_msg(&mut self, msg: &[u8], sig: &mut [u8], rng: &mut RNG) -> Result<usize, i32> {
let msg_len = msg.len() as u32;
let mut sig_len = sig.len() as u32;
let rc = unsafe {
sys::wc_dilithium_sign_ctx_msg(
core::ptr::null(),
0,
msg.as_ptr(),
msg_len,
sig.as_mut_ptr(),
&mut sig_len,
&mut self.ws_key,
&mut rng.wc_rng,
)
};
if rc != 0 {
return Err(rc);
}
Ok(sig_len as usize)
}
#[cfg(all(dilithium_sign, random))]
pub fn sign_ctx_msg(
&mut self,
ctx: &[u8],
msg: &[u8],
sig: &mut [u8],
rng: &mut RNG,
) -> Result<usize, i32> {
if ctx.len() > 255 {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let ctx_len = ctx.len() as u8;
let msg_len = msg.len() as u32;
let mut sig_len = sig.len() as u32;
let rc = unsafe {
sys::wc_dilithium_sign_ctx_msg(
ctx.as_ptr(),
ctx_len,
msg.as_ptr(),
msg_len,
sig.as_mut_ptr(),
&mut sig_len,
&mut self.ws_key,
&mut rng.wc_rng,
)
};
if rc != 0 {
return Err(rc);
}
Ok(sig_len as usize)
}
#[cfg(all(dilithium_sign, random))]
pub fn sign_ctx_hash(
&mut self,
ctx: &[u8],
hash_alg: i32,
hash: &[u8],
sig: &mut [u8],
rng: &mut RNG,
) -> Result<usize, i32> {
if ctx.len() > 255 {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let ctx_len = ctx.len() as u8;
let hash_len = hash.len() as u32;
let mut sig_len = sig.len() as u32;
let rc = unsafe {
sys::wc_dilithium_sign_ctx_hash(
ctx.as_ptr(),
ctx_len,
hash_alg,
hash.as_ptr(),
hash_len,
sig.as_mut_ptr(),
&mut sig_len,
&mut self.ws_key,
&mut rng.wc_rng,
)
};
if rc != 0 {
return Err(rc);
}
Ok(sig_len as usize)
}
#[cfg(dilithium_sign_with_seed)]
pub fn sign_msg_with_seed(
&mut self,
msg: &[u8],
sig: &mut [u8],
seed: &[u8],
) -> Result<usize, i32> {
#[cfg(dilithium_rnd_sz)]
if seed.len() != sys::DILITHIUM_RND_SZ as usize {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let msg_len = msg.len() as u32;
let mut sig_len = sig.len() as u32;
let rc = unsafe {
sys::wc_dilithium_sign_ctx_msg_with_seed(
core::ptr::null(),
0,
msg.as_ptr(),
msg_len,
sig.as_mut_ptr(),
&mut sig_len,
&mut self.ws_key,
seed.as_ptr(),
)
};
if rc != 0 {
return Err(rc);
}
Ok(sig_len as usize)
}
#[cfg(dilithium_sign_with_seed)]
pub fn sign_ctx_msg_with_seed(
&mut self,
ctx: &[u8],
msg: &[u8],
sig: &mut [u8],
seed: &[u8],
) -> Result<usize, i32> {
if ctx.len() > 255 {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
#[cfg(dilithium_rnd_sz)]
if seed.len() != sys::DILITHIUM_RND_SZ as usize {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let ctx_len = ctx.len() as u8;
let msg_len = msg.len() as u32;
let mut sig_len = sig.len() as u32;
let rc = unsafe {
sys::wc_dilithium_sign_ctx_msg_with_seed(
ctx.as_ptr(),
ctx_len,
msg.as_ptr(),
msg_len,
sig.as_mut_ptr(),
&mut sig_len,
&mut self.ws_key,
seed.as_ptr(),
)
};
if rc != 0 {
return Err(rc);
}
Ok(sig_len as usize)
}
#[cfg(dilithium_sign_with_seed)]
pub fn sign_ctx_hash_with_seed(
&mut self,
ctx: &[u8],
hash_alg: i32,
hash: &[u8],
sig: &mut [u8],
seed: &[u8],
) -> Result<usize, i32> {
if ctx.len() > 255 {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
#[cfg(dilithium_rnd_sz)]
if seed.len() != sys::DILITHIUM_RND_SZ as usize {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let ctx_len = ctx.len() as u8;
let hash_len = hash.len() as u32;
let mut sig_len = sig.len() as u32;
let rc = unsafe {
sys::wc_dilithium_sign_ctx_hash_with_seed(
ctx.as_ptr(),
ctx_len,
hash_alg,
hash.as_ptr(),
hash_len,
sig.as_mut_ptr(),
&mut sig_len,
&mut self.ws_key,
seed.as_ptr(),
)
};
if rc != 0 {
return Err(rc);
}
Ok(sig_len as usize)
}
#[cfg(dilithium_verify)]
pub fn verify_msg(&mut self, sig: &[u8], msg: &[u8]) -> Result<bool, i32> {
let sig_len = sig.len() as u32;
let msg_len = msg.len() as u32;
let mut res = 0i32;
let rc = unsafe {
sys::wc_dilithium_verify_ctx_msg(
sig.as_ptr(),
sig_len,
core::ptr::null(),
0,
msg.as_ptr(),
msg_len,
&mut res,
&mut self.ws_key,
)
};
if rc != 0 {
return Err(rc);
}
Ok(res == 1)
}
#[cfg(dilithium_verify)]
pub fn verify_ctx_msg(&mut self, sig: &[u8], ctx: &[u8], msg: &[u8]) -> Result<bool, i32> {
if ctx.len() > 255 {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let sig_len = sig.len() as u32;
let ctx_len = ctx.len() as u8;
let msg_len = msg.len() as u32;
let mut res = 0i32;
let rc = unsafe {
sys::wc_dilithium_verify_ctx_msg(
sig.as_ptr(),
sig_len,
ctx.as_ptr(),
ctx_len,
msg.as_ptr(),
msg_len,
&mut res,
&mut self.ws_key,
)
};
if rc != 0 {
return Err(rc);
}
Ok(res == 1)
}
#[cfg(dilithium_verify)]
pub fn verify_ctx_hash(
&mut self,
sig: &[u8],
ctx: &[u8],
hash_alg: i32,
hash: &[u8],
) -> Result<bool, i32> {
if ctx.len() > 255 {
return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E);
}
let sig_len = sig.len() as u32;
let ctx_len = ctx.len() as u8;
let hash_len = hash.len() as u32;
let mut res = 0i32;
let rc = unsafe {
sys::wc_dilithium_verify_ctx_hash(
sig.as_ptr(),
sig_len,
ctx.as_ptr(),
ctx_len,
hash_alg,
hash.as_ptr(),
hash_len,
&mut res,
&mut self.ws_key,
)
};
if rc != 0 {
return Err(rc);
}
Ok(res == 1)
}
}
impl Drop for Dilithium {
fn drop(&mut self) {
unsafe {
sys::wc_dilithium_free(&mut self.ws_key);
}
}
}