use super::{AlgorithmName, TruncSide, UpdateCore, VariableOutputCore};
#[cfg(feature = "mac")]
use crate::MacMarker;
use crate::{HashMarker, InvalidBufferSize};
use crate::{InvalidOutputSize, Reset, Update, VariableOutput, VariableOutputReset};
use block_buffer::BlockBuffer;
use core::fmt;
use crypto_common::typenum::{IsLess, Le, NonZero, Unsigned, U256};
#[derive(Clone)]
pub struct RtVariableCoreWrapper<T>
where
T: VariableOutputCore + UpdateCore,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
core: T,
buffer: BlockBuffer<T::BlockSize, T::BufferKind>,
output_size: usize,
}
impl<T> RtVariableCoreWrapper<T>
where
T: VariableOutputCore,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
#[inline]
fn finalize_dirty(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> {
let Self {
core,
buffer,
output_size,
} = self;
if out.len() != *output_size || out.len() > Self::MAX_OUTPUT_SIZE {
return Err(InvalidBufferSize);
}
let mut full_res = Default::default();
core.finalize_variable_core(buffer, &mut full_res);
let n = out.len();
let m = full_res.len() - n;
match T::TRUNC_SIDE {
TruncSide::Left => out.copy_from_slice(&full_res[..n]),
TruncSide::Right => out.copy_from_slice(&full_res[m..]),
}
Ok(())
}
}
impl<T> HashMarker for RtVariableCoreWrapper<T>
where
T: VariableOutputCore + HashMarker,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
}
#[cfg(feature = "mac")]
#[cfg_attr(docsrs, doc(cfg(feature = "mac")))]
impl<T> MacMarker for RtVariableCoreWrapper<T>
where
T: VariableOutputCore + MacMarker,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
}
impl<T> Reset for RtVariableCoreWrapper<T>
where
T: VariableOutputCore + UpdateCore + Reset,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
#[inline]
fn reset(&mut self) {
self.buffer.reset();
self.core.reset();
}
}
impl<T> Update for RtVariableCoreWrapper<T>
where
T: VariableOutputCore + UpdateCore,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
#[inline]
fn update(&mut self, input: &[u8]) {
let Self { core, buffer, .. } = self;
buffer.digest_blocks(input, |blocks| core.update_blocks(blocks));
}
}
impl<T> VariableOutput for RtVariableCoreWrapper<T>
where
T: VariableOutputCore + UpdateCore,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
const MAX_OUTPUT_SIZE: usize = T::OutputSize::USIZE;
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
let buffer = Default::default();
T::new(output_size).map(|core| Self {
core,
buffer,
output_size,
})
}
fn output_size(&self) -> usize {
self.output_size
}
fn finalize_variable(mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> {
self.finalize_dirty(out)
}
}
impl<T> VariableOutputReset for RtVariableCoreWrapper<T>
where
T: VariableOutputCore + UpdateCore + Reset,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
fn finalize_variable_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> {
self.finalize_dirty(out)?;
self.core.reset();
self.buffer.reset();
Ok(())
}
}
impl<T> fmt::Debug for RtVariableCoreWrapper<T>
where
T: VariableOutputCore + UpdateCore + AlgorithmName,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
T::write_alg_name(f)?;
f.write_str(" { .. }")
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl<T> std::io::Write for RtVariableCoreWrapper<T>
where
T: VariableOutputCore + UpdateCore,
T::BlockSize: IsLess<U256>,
Le<T::BlockSize, U256>: NonZero,
{
#[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
Update::update(self, buf);
Ok(buf.len())
}
#[inline]
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}