use super::Shake;
use crate::errors::UnknownCryptoError;
#[cfg(feature = "safe_api")]
use std::io;
pub const SHAKE_256_RATE: usize = 136;
#[derive(Clone, Debug)]
pub struct Shake256 {
pub(crate) _state: Shake<SHAKE_256_RATE>,
}
impl Default for Shake256 {
fn default() -> Self {
Self::new()
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
#[cfg(feature = "safe_api")]
impl io::Write for Shake256 {
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
self.absorb(bytes).map_err(io::Error::other)?;
Ok(bytes.len())
}
fn flush(&mut self) -> Result<(), io::Error> {
Ok(())
}
}
impl Shake256 {
pub fn new() -> Self {
Self {
_state: Shake::<SHAKE_256_RATE>::_new(64),
}
}
pub fn reset(&mut self) {
self._state._reset();
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn absorb(&mut self, data: &[u8]) -> Result<(), UnknownCryptoError> {
self._state._absorb(data)
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn squeeze(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
self._state._squeeze(dest)
}
}
#[cfg(test)]
mod public {
use super::*;
#[test]
fn test_default_equals_new() {
let new = Shake256::new();
let default = Shake256::default();
new._state.compare_state_to_other(&default._state);
}
#[test]
#[cfg(feature = "safe_api")]
fn test_debug_impl() {
let initial_state = Shake256::new();
let debug = format!("{initial_state:?}");
let expected = "Shake256 { _state: State { state: [***OMITTED***], buffer: [***OMITTED***], capacity: 64, until_absorb: 0, to_squeeze: 0, is_finalized: false } }";
assert_eq!(debug, expected);
}
mod test_streaming_interface {
use super::*;
use crate::test_framework::xof_interface::*;
impl TestableXofContext for Shake256 {
fn reset(&mut self) -> Result<(), UnknownCryptoError> {
self.reset();
Ok(())
}
fn absorb(&mut self, input: &[u8]) -> Result<(), UnknownCryptoError> {
self.absorb(input)
}
fn squeeze(&mut self, dest: &mut [u8]) -> Result<(), UnknownCryptoError> {
self.squeeze(dest)
}
fn compare_states(state_1: &Shake256, state_2: &Shake256) {
state_1._state.compare_state_to_other(&state_2._state);
}
}
#[test]
fn default_consistency_tests() {
let initial_state: Shake256 = Shake256::new();
let test_runner =
XofContextConsistencyTester::<Shake256>::new(initial_state, SHAKE_256_RATE);
test_runner.run_all_tests();
}
#[quickcheck]
#[cfg(feature = "safe_api")]
fn prop_input_to_consistency(data: Vec<u8>) -> bool {
let initial_state: Shake256 = Shake256::new();
let test_runner =
XofContextConsistencyTester::<Shake256>::new(initial_state, SHAKE_256_RATE);
test_runner.run_all_tests_property(&data);
true
}
}
#[cfg(feature = "safe_api")]
mod test_io_impls {
use crate::hazardous::hash::sha3::shake256::Shake256;
use std::io::Write;
#[quickcheck]
fn prop_hasher_write_same_as_update(data: Vec<u8>, outlen: u16) -> bool {
let mut hasher_a = Shake256::new();
let mut hasher_b = hasher_a.clone();
hasher_a.absorb(&data).unwrap();
hasher_b.write_all(&data).unwrap();
hasher_b.flush().unwrap();
hasher_a._state.compare_state_to_other(&hasher_b._state);
let mut hash_a = vec![0u8; outlen as usize];
let mut hash_b = vec![0u8; outlen as usize];
hasher_a.squeeze(&mut hash_a).unwrap();
hasher_b.squeeze(&mut hash_b).unwrap();
hasher_b.flush().unwrap();
hasher_a._state.compare_state_to_other(&hasher_b._state);
hash_a == hash_b
}
}
}