1 | use super::{AlgorithmName, TruncSide, UpdateCore, VariableOutputCore}; |
2 | #[cfg (feature = "mac" )] |
3 | use crate::MacMarker; |
4 | use crate::{HashMarker, InvalidBufferSize}; |
5 | use crate::{InvalidOutputSize, Reset, Update, VariableOutput, VariableOutputReset}; |
6 | use block_buffer::BlockBuffer; |
7 | use core::fmt; |
8 | use crypto_common::typenum::{IsLess, Le, NonZero, Unsigned, U256}; |
9 | |
10 | /// Wrapper around [`VariableOutputCore`] which selects output size |
11 | /// at run time. |
12 | #[derive (Clone)] |
13 | pub struct RtVariableCoreWrapper<T> |
14 | where |
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 | |
24 | impl<T> RtVariableCoreWrapper<T> |
25 | where |
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 | |
52 | impl<T> HashMarker for RtVariableCoreWrapper<T> |
53 | where |
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" )))] |
62 | impl<T> MacMarker for RtVariableCoreWrapper<T> |
63 | where |
64 | T: VariableOutputCore + MacMarker, |
65 | T::BlockSize: IsLess<U256>, |
66 | Le<T::BlockSize, U256>: NonZero, |
67 | { |
68 | } |
69 | |
70 | impl<T> Reset for RtVariableCoreWrapper<T> |
71 | where |
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 | |
83 | impl<T> Update for RtVariableCoreWrapper<T> |
84 | where |
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 | |
96 | impl<T> VariableOutput for RtVariableCoreWrapper<T> |
97 | where |
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 | |
122 | impl<T> VariableOutputReset for RtVariableCoreWrapper<T> |
123 | where |
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 | |
136 | impl<T> fmt::Debug for RtVariableCoreWrapper<T> |
137 | where |
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" )))] |
150 | impl<T> std::io::Write for RtVariableCoreWrapper<T> |
151 | where |
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 | |