use crate::tiny_keccak::{bits_to_rate, keccakf::KeccakF, left_encode, Hasher, KeccakState, Xof, EMPTY};
#[derive(Clone)]
pub struct CShake {
state: KeccakState<KeccakF>,
}
impl CShake {
const DELIM: u8 = 0x04;
pub fn v128(name: Option<&[u8]>, custom_string: Option<&[u8]>) -> CShake {
CShake::new(name, custom_string, 128)
}
pub fn v256(name: Option<&[u8]>, custom_string: Option<&[u8]>) -> CShake {
CShake::new(name, custom_string, 256)
}
pub(crate) fn new(name: Option<&[u8]>, custom_string: Option<&[u8]>, bits: usize) -> CShake {
let rate = bits_to_rate(bits);
if name.is_none() && custom_string.is_none() {
let state = KeccakState::new(rate, 0x1f);
return CShake { state };
}
let name = name.unwrap_or(&EMPTY);
let custom_string = custom_string.unwrap_or(&EMPTY);
let mut state = KeccakState::new(rate, Self::DELIM);
state.update(left_encode(rate).value());
state.update(left_encode(name.len() * 8).value());
state.update(name);
state.update(left_encode(custom_string.len() * 8).value());
state.update(custom_string);
state.fill_block();
CShake { state }
}
}
impl Hasher for CShake {
fn update(&mut self, input: &[u8]) {
self.state.update(input);
}
fn finalize(&mut self, output: &mut [u8]) {
self.state.finalize(output);
}
}
impl Xof for CShake {
fn squeeze(&mut self, output: &mut [u8]) {
self.state.squeeze(output);
}
}
pub fn cshake128(output: &mut [u8], input: &[u8], name: Option<&[u8]>, custom_string: Option<&[u8]>) {
cshake_xof(output, input, name, custom_string, 128);
}
pub fn cshake256(output: &mut [u8], input: &[u8], name: Option<&[u8]>, custom_string: Option<&[u8]>) {
cshake_xof(output, input, name, custom_string, 256);
}
fn cshake_xof(output: &mut [u8], input: &[u8], name: Option<&[u8]>, custom_string: Option<&[u8]>, bits: usize) {
let mut shaker = CShake::new(name, custom_string, bits);
shaker.update(input);
shaker.finalize(output);
}