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: &mut T,
34 buffer: &mut BlockBuffer<::BlockSize, …>,
35 output_size: &mut usize,
36 } = self;
37 if out.len() != *output_size || out.len() > Self::MAX_OUTPUT_SIZE {
38 return Err(InvalidBufferSize);
39 }
40 let mut full_res: GenericArray::OutputSize> = Default::default();
41 core.finalize_variable_core(buffer, &mut full_res);
42 let n: usize = out.len();
43 let m: usize = 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: &mut T, buffer: &mut BlockBuffer<::BlockSize, …>, .. } = self;
92 buffer.digest_blocks(input, |blocks: &[GenericArray::BlockSize>]| 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: BlockBuffer<::BlockSize, …> = Default::default();
106 T::new(output_size).map(|core: T| 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(data:" { .. }")
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, data:buf);
159 Ok(buf.len())
160 }
161
162 #[inline]
163 fn flush(&mut self) -> std::io::Result<()> {
164 Ok(())
165 }
166}
167