digest/core_api/
rt_variable.rs

1use super::{AlgorithmName, TruncSide, UpdateCore, VariableOutputCore};
2#[cfg(feature = "mac")]
3use crate::MacMarker;
4use crate::{HashMarker, InvalidBufferSize};
5use crate::{InvalidOutputSize, Reset, Update, VariableOutput, VariableOutputReset};
6use block_buffer::BlockBuffer;
7use core::fmt;
8use crypto_common::typenum::{IsLess, Le, NonZero, Unsigned, U256};
9
10/// Wrapper around [`VariableOutputCore`] which selects output size
11/// at run time.
12#[derive(Clone)]
13pub struct RtVariableCoreWrapper<T>
14where
15    T: VariableOutputCore + UpdateCore,
16    T::BlockSize: IsLess<U256>,
17    Le<T::BlockSize, U256>: NonZero,
18{
19    core: T,
20    buffer: BlockBuffer<T::BlockSize, T::BufferKind>,
21    output_size: usize,
22}
23
24impl<T> RtVariableCoreWrapper<T>
25where
26    T: VariableOutputCore,
27    T::BlockSize: IsLess<U256>,
28    Le<T::BlockSize, U256>: NonZero,
29{
30    #[inline]
31    fn finalize_dirty(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> {
32        let Self {
33            core,
34            buffer,
35            output_size,
36        } = self;
37        if out.len() != *output_size || out.len() > Self::MAX_OUTPUT_SIZE {
38            return Err(InvalidBufferSize);
39        }
40        let mut full_res = Default::default();
41        core.finalize_variable_core(buffer, &mut full_res);
42        let n = out.len();
43        let m = full_res.len() - n;
44        match T::TRUNC_SIDE {
45            TruncSide::Left => out.copy_from_slice(&full_res[..n]),
46            TruncSide::Right => out.copy_from_slice(&full_res[m..]),
47        }
48        Ok(())
49    }
50}
51
52impl<T> HashMarker for RtVariableCoreWrapper<T>
53where
54    T: VariableOutputCore + HashMarker,
55    T::BlockSize: IsLess<U256>,
56    Le<T::BlockSize, U256>: NonZero,
57{
58}
59
60#[cfg(feature = "mac")]
61#[cfg_attr(docsrs, doc(cfg(feature = "mac")))]
62impl<T> MacMarker for RtVariableCoreWrapper<T>
63where
64    T: VariableOutputCore + MacMarker,
65    T::BlockSize: IsLess<U256>,
66    Le<T::BlockSize, U256>: NonZero,
67{
68}
69
70impl<T> Reset for RtVariableCoreWrapper<T>
71where
72    T: VariableOutputCore + UpdateCore + Reset,
73    T::BlockSize: IsLess<U256>,
74    Le<T::BlockSize, U256>: NonZero,
75{
76    #[inline]
77    fn reset(&mut self) {
78        self.buffer.reset();
79        self.core.reset();
80    }
81}
82
83impl<T> Update for RtVariableCoreWrapper<T>
84where
85    T: VariableOutputCore + UpdateCore,
86    T::BlockSize: IsLess<U256>,
87    Le<T::BlockSize, U256>: NonZero,
88{
89    #[inline]
90    fn update(&mut self, input: &[u8]) {
91        let Self { core, buffer, .. } = self;
92        buffer.digest_blocks(input, |blocks| core.update_blocks(blocks));
93    }
94}
95
96impl<T> VariableOutput for RtVariableCoreWrapper<T>
97where
98    T: VariableOutputCore + UpdateCore,
99    T::BlockSize: IsLess<U256>,
100    Le<T::BlockSize, U256>: NonZero,
101{
102    const MAX_OUTPUT_SIZE: usize = T::OutputSize::USIZE;
103
104    fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
105        let buffer = Default::default();
106        T::new(output_size).map(|core| Self {
107            core,
108            buffer,
109            output_size,
110        })
111    }
112
113    fn output_size(&self) -> usize {
114        self.output_size
115    }
116
117    fn finalize_variable(mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> {
118        self.finalize_dirty(out)
119    }
120}
121
122impl<T> VariableOutputReset for RtVariableCoreWrapper<T>
123where
124    T: VariableOutputCore + UpdateCore + Reset,
125    T::BlockSize: IsLess<U256>,
126    Le<T::BlockSize, U256>: NonZero,
127{
128    fn finalize_variable_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferSize> {
129        self.finalize_dirty(out)?;
130        self.core.reset();
131        self.buffer.reset();
132        Ok(())
133    }
134}
135
136impl<T> fmt::Debug for RtVariableCoreWrapper<T>
137where
138    T: VariableOutputCore + UpdateCore + AlgorithmName,
139    T::BlockSize: IsLess<U256>,
140    Le<T::BlockSize, U256>: NonZero,
141{
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
143        T::write_alg_name(f)?;
144        f.write_str(" { .. }")
145    }
146}
147
148#[cfg(feature = "std")]
149#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
150impl<T> std::io::Write for RtVariableCoreWrapper<T>
151where
152    T: VariableOutputCore + UpdateCore,
153    T::BlockSize: IsLess<U256>,
154    Le<T::BlockSize, U256>: NonZero,
155{
156    #[inline]
157    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
158        Update::update(self, buf);
159        Ok(buf.len())
160    }
161
162    #[inline]
163    fn flush(&mut self) -> std::io::Result<()> {
164        Ok(())
165    }
166}