1use super::{
2 AlgorithmName, Buffer, BufferKindUser, FixedOutputCore, Reset, TruncSide, UpdateCore,
3 VariableOutputCore,
4};
5use crate::HashMarker;
6#[cfg(feature = "mac")]
7use crate::MacMarker;
8#[cfg(feature = "oid")]
9use const_oid::{AssociatedOid, ObjectIdentifier};
10use core::{fmt, marker::PhantomData};
11use crypto_common::{
12 generic_array::{ArrayLength, GenericArray},
13 typenum::{IsLess, IsLessOrEqual, Le, LeEq, NonZero, U256},
14 Block, BlockSizeUser, OutputSizeUser,
15};
16
17/// Dummy type used with [`CtVariableCoreWrapper`] in cases when
18/// resulting hash does not have a known OID.
19#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
20pub struct NoOid;
21
22/// Wrapper around [`VariableOutputCore`] which selects output size
23/// at compile time.
24#[derive(Clone)]
25pub struct CtVariableCoreWrapper<T, OutSize, O = NoOid>
26where
27 T: VariableOutputCore,
28 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
29 LeEq<OutSize, T::OutputSize>: NonZero,
30 T::BlockSize: IsLess<U256>,
31 Le<T::BlockSize, U256>: NonZero,
32{
33 inner: T,
34 _out: PhantomData<(OutSize, O)>,
35}
36
37impl<T, OutSize, O> HashMarker for CtVariableCoreWrapper<T, OutSize, O>
38where
39 T: VariableOutputCore + HashMarker,
40 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
41 LeEq<OutSize, T::OutputSize>: NonZero,
42 T::BlockSize: IsLess<U256>,
43 Le<T::BlockSize, U256>: NonZero,
44{
45}
46
47#[cfg(feature = "mac")]
48impl<T, OutSize, O> MacMarker for CtVariableCoreWrapper<T, OutSize, O>
49where
50 T: VariableOutputCore + MacMarker,
51 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
52 LeEq<OutSize, T::OutputSize>: NonZero,
53 T::BlockSize: IsLess<U256>,
54 Le<T::BlockSize, U256>: NonZero,
55{
56}
57
58impl<T, OutSize, O> BlockSizeUser for CtVariableCoreWrapper<T, OutSize, O>
59where
60 T: VariableOutputCore,
61 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
62 LeEq<OutSize, T::OutputSize>: NonZero,
63 T::BlockSize: IsLess<U256>,
64 Le<T::BlockSize, U256>: NonZero,
65{
66 type BlockSize = T::BlockSize;
67}
68
69impl<T, OutSize, O> UpdateCore for CtVariableCoreWrapper<T, OutSize, O>
70where
71 T: VariableOutputCore,
72 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
73 LeEq<OutSize, T::OutputSize>: NonZero,
74 T::BlockSize: IsLess<U256>,
75 Le<T::BlockSize, U256>: NonZero,
76{
77 #[inline]
78 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
79 self.inner.update_blocks(blocks);
80 }
81}
82
83impl<T, OutSize, O> OutputSizeUser for CtVariableCoreWrapper<T, OutSize, O>
84where
85 T: VariableOutputCore,
86 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize> + 'static,
87 LeEq<OutSize, T::OutputSize>: NonZero,
88 T::BlockSize: IsLess<U256>,
89 Le<T::BlockSize, U256>: NonZero,
90{
91 type OutputSize = OutSize;
92}
93
94impl<T, OutSize, O> BufferKindUser for CtVariableCoreWrapper<T, OutSize, O>
95where
96 T: VariableOutputCore,
97 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
98 LeEq<OutSize, T::OutputSize>: NonZero,
99 T::BlockSize: IsLess<U256>,
100 Le<T::BlockSize, U256>: NonZero,
101{
102 type BufferKind = T::BufferKind;
103}
104
105impl<T, OutSize, O> FixedOutputCore for CtVariableCoreWrapper<T, OutSize, O>
106where
107 T: VariableOutputCore,
108 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize> + 'static,
109 LeEq<OutSize, T::OutputSize>: NonZero,
110 T::BlockSize: IsLess<U256>,
111 Le<T::BlockSize, U256>: NonZero,
112{
113 #[inline]
114 fn finalize_fixed_core(
115 &mut self,
116 buffer: &mut Buffer<Self>,
117 out: &mut GenericArray<u8, Self::OutputSize>,
118 ) {
119 let mut full_res: GenericArray::OutputSize> = Default::default();
120 self.inner.finalize_variable_core(buffer, &mut full_res);
121 let n: usize = out.len();
122 let m: usize = full_res.len() - n;
123 match T::TRUNC_SIDE {
124 TruncSide::Left => out.copy_from_slice(&full_res[..n]),
125 TruncSide::Right => out.copy_from_slice(&full_res[m..]),
126 }
127 }
128}
129
130impl<T, OutSize, O> Default for CtVariableCoreWrapper<T, OutSize, O>
131where
132 T: VariableOutputCore,
133 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
134 LeEq<OutSize, T::OutputSize>: NonZero,
135 T::BlockSize: IsLess<U256>,
136 Le<T::BlockSize, U256>: NonZero,
137{
138 #[inline]
139 fn default() -> Self {
140 Self {
141 inner: T::new(OutSize::USIZE).unwrap(),
142 _out: PhantomData,
143 }
144 }
145}
146
147impl<T, OutSize, O> Reset for CtVariableCoreWrapper<T, OutSize, O>
148where
149 T: VariableOutputCore,
150 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
151 LeEq<OutSize, T::OutputSize>: NonZero,
152 T::BlockSize: IsLess<U256>,
153 Le<T::BlockSize, U256>: NonZero,
154{
155 #[inline]
156 fn reset(&mut self) {
157 *self = Default::default();
158 }
159}
160
161impl<T, OutSize, O> AlgorithmName for CtVariableCoreWrapper<T, OutSize, O>
162where
163 T: VariableOutputCore + AlgorithmName,
164 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
165 LeEq<OutSize, T::OutputSize>: NonZero,
166 T::BlockSize: IsLess<U256>,
167 Le<T::BlockSize, U256>: NonZero,
168{
169 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 T::write_alg_name(f)?;
171 f.write_str(data:"_")?;
172 write!(f, "{}", OutSize::USIZE)
173 }
174}
175
176#[cfg(feature = "oid")]
177#[cfg_attr(docsrs, doc(cfg(feature = "oid")))]
178impl<T, OutSize, O> AssociatedOid for CtVariableCoreWrapper<T, OutSize, O>
179where
180 T: VariableOutputCore,
181 O: AssociatedOid,
182 OutSize: ArrayLength<u8> + IsLessOrEqual<T::OutputSize>,
183 LeEq<OutSize, T::OutputSize>: NonZero,
184 T::BlockSize: IsLess<U256>,
185 Le<T::BlockSize, U256>: NonZero,
186{
187 const OID: ObjectIdentifier = O::OID;
188}
189
190/// Implement dummy type with hidden docs which is used to "carry" hasher
191/// OID for [`CtVariableCoreWrapper`].
192#[macro_export]
193macro_rules! impl_oid_carrier {
194 ($name:ident, $oid:literal) => {
195 #[doc(hidden)]
196 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
197 pub struct $name;
198
199 #[cfg(feature = "oid")]
200 impl AssociatedOid for $name {
201 const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap($oid);
202 }
203 };
204}
205