use core::ffi::c_void;
use crate::error::{check, WolfCryptError, len_as_u32};
macro_rules! impl_shake {
(
$name:ident,
$block_size:expr,
$init_fn:path,
$update_fn:path,
$final_fn:path,
$absorb_fn:path,
$squeeze_fn:path,
$free_fn:path,
$cfg_gate:meta
) => {
#[$cfg_gate]
pub struct $name {
inner: wolfcrypt_rs::WcShake,
}
#[$cfg_gate]
unsafe impl Send for $name {}
#[$cfg_gate]
impl $name {
pub const BLOCK_SIZE: usize = $block_size;
pub fn new() -> Result<Self, WolfCryptError> {
let mut inner = wolfcrypt_rs::WcShake::zeroed();
let rc = unsafe {
$init_fn(
&mut inner as *mut wolfcrypt_rs::WcShake,
core::ptr::null_mut::<c_void>(),
-2, )
};
check(rc, stringify!($init_fn))?;
Ok(Self { inner })
}
pub fn update(&mut self, data: &[u8]) -> Result<(), WolfCryptError> {
let rc = unsafe {
$update_fn(
&mut self.inner as *mut wolfcrypt_rs::WcShake,
data.as_ptr(),
len_as_u32(data.len()),
)
};
check(rc, stringify!($update_fn))
}
pub fn finalize(&mut self, out: &mut [u8]) -> Result<(), WolfCryptError> {
let rc = unsafe {
$final_fn(
&mut self.inner as *mut wolfcrypt_rs::WcShake,
out.as_mut_ptr(),
len_as_u32(out.len()),
)
};
check(rc, stringify!($final_fn))
}
pub fn absorb(&mut self, data: &[u8]) -> Result<(), WolfCryptError> {
let rc = unsafe {
$absorb_fn(
&mut self.inner as *mut wolfcrypt_rs::WcShake,
data.as_ptr(),
len_as_u32(data.len()),
)
};
check(rc, stringify!($absorb_fn))
}
pub fn squeeze_blocks(&mut self, out: &mut [u8]) -> Result<(), WolfCryptError> {
if out.len() % Self::BLOCK_SIZE != 0 {
return Err(WolfCryptError::InvalidInput);
}
let block_cnt = (out.len() / Self::BLOCK_SIZE) as u32;
let rc = unsafe {
$squeeze_fn(
&mut self.inner as *mut wolfcrypt_rs::WcShake,
out.as_mut_ptr(),
block_cnt,
)
};
check(rc, stringify!($squeeze_fn))
}
}
#[$cfg_gate]
impl Drop for $name {
fn drop(&mut self) {
unsafe {
$free_fn(&mut self.inner as *mut wolfcrypt_rs::WcShake);
}
}
}
};
}
impl_shake!(
Shake128,
168,
wolfcrypt_rs::wc_InitShake128,
wolfcrypt_rs::wc_Shake128_Update,
wolfcrypt_rs::wc_Shake128_Final,
wolfcrypt_rs::wc_Shake128_Absorb,
wolfcrypt_rs::wc_Shake128_SqueezeBlocks,
wolfcrypt_rs::wc_Shake128_Free,
cfg(wolfssl_shake128)
);
impl_shake!(
Shake256,
136,
wolfcrypt_rs::wc_InitShake256,
wolfcrypt_rs::wc_Shake256_Update,
wolfcrypt_rs::wc_Shake256_Final,
wolfcrypt_rs::wc_Shake256_Absorb,
wolfcrypt_rs::wc_Shake256_SqueezeBlocks,
wolfcrypt_rs::wc_Shake256_Free,
cfg(wolfssl_shake256)
);