Skip to content

Commit 35d7459

Browse files
authored
digest: add ExtendableOutputDirty and VariableOutputDirty traits (#183)
Adds traits which provide an implementation-focused low-level API similar to the `FixedOutputDirty` trait introduced in #180, but for the `ExtendableOutput` and `VariableOutput` traits. Like `FixedOutputDirty`, these traits have blanket impls when the same type also impls the `Reset` trait. Also adds corresponding `*_reset` methods to the respective `finalize*` methods of these traits.
1 parent b1d81ba commit 35d7459

File tree

1 file changed

+122
-4
lines changed

1 file changed

+122
-4
lines changed

digest/src/lib.rs

+122-4
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl<D: FixedOutputDirty + Reset> FixedOutput for D {
140140
}
141141

142142
/// Trait for returning digest result with the variable size
143-
pub trait VariableOutput: core::marker::Sized {
143+
pub trait VariableOutput: Sized {
144144
/// Create new hasher instance with the given output size.
145145
///
146146
/// It will return `Err(InvalidOutputSize)` in case if hasher can not return
@@ -155,7 +155,13 @@ pub trait VariableOutput: core::marker::Sized {
155155
///
156156
/// Closure is guaranteed to be called, length of the buffer passed to it
157157
/// will be equal to `output_size`.
158-
fn finalize_variable<F: FnOnce(&[u8])>(self, f: F);
158+
fn finalize_variable(self, f: impl FnOnce(&[u8]));
159+
160+
/// Retrieve result via closure and reset the hasher state.
161+
///
162+
/// Closure is guaranteed to be called, length of the buffer passed to it
163+
/// will be equal to `output_size`.
164+
fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8]));
159165

160166
/// Retrieve result into a boxed slice and consume hasher.
161167
///
@@ -169,6 +175,66 @@ pub trait VariableOutput: core::marker::Sized {
169175
self.finalize_variable(|res| buf.copy_from_slice(res));
170176
buf
171177
}
178+
179+
/// Retrieve result into a boxed slice and reset hasher state.
180+
///
181+
/// `Box<[u8]>` is used instead of `Vec<u8>` to save stack space, since
182+
/// they have size of 2 and 3 words respectively.
183+
#[cfg(feature = "alloc")]
184+
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
185+
fn finalize_boxed_reset(&mut self) -> Box<[u8]> {
186+
let n = self.output_size();
187+
let mut buf = vec![0u8; n].into_boxed_slice();
188+
self.finalize_variable_reset(|res| buf.copy_from_slice(res));
189+
buf
190+
}
191+
}
192+
193+
/// Trait for variable-sized output digest implementations to use to retrieve
194+
/// the hash output.
195+
///
196+
/// Usage of this trait in user code is discouraged. Instead use the
197+
/// [`VariableOutput::finalize_variable`] or
198+
/// [`VariableOutput::finalize_variable_reset`] methods.
199+
///
200+
/// Types which impl this trait along with [`Reset`] will receive a blanket
201+
/// impl of [`VariableOutput`].
202+
pub trait VariableOutputDirty: Sized {
203+
/// Create new hasher instance with the given output size.
204+
///
205+
/// It will return `Err(InvalidOutputSize)` in case if hasher can not return
206+
/// specified output size. It will always return an error if output size
207+
/// equals to zero.
208+
fn new(output_size: usize) -> Result<Self, InvalidOutputSize>;
209+
210+
/// Get output size of the hasher instance provided to the `new` method
211+
fn output_size(&self) -> usize;
212+
213+
/// Retrieve result into provided buffer and leave hasher in a dirty state.
214+
///
215+
/// Implementations should panic if this is called twice without resetting.
216+
fn finalize_variable_dirty(&mut self, f: impl FnOnce(&[u8]));
217+
}
218+
219+
impl<D: VariableOutputDirty + Reset> VariableOutput for D {
220+
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
221+
<Self as VariableOutputDirty>::new(output_size)
222+
}
223+
224+
fn output_size(&self) -> usize {
225+
<Self as VariableOutputDirty>::output_size(self)
226+
}
227+
228+
#[inline]
229+
fn finalize_variable(mut self, f: impl FnOnce(&[u8])) {
230+
self.finalize_variable_dirty(f);
231+
}
232+
233+
#[inline]
234+
fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8])) {
235+
self.finalize_variable_dirty(f);
236+
self.reset();
237+
}
172238
}
173239

174240
/// Trait for describing readers which are used to extract extendable output
@@ -193,14 +259,18 @@ pub trait XofReader {
193259
}
194260

195261
/// Trait which describes extendable-output functions (XOF).
196-
pub trait ExtendableOutput: core::marker::Sized {
262+
pub trait ExtendableOutput: Sized {
197263
/// Reader
198264
type Reader: XofReader;
199265

200266
/// Retrieve XOF reader and consume hasher instance.
201267
fn finalize_xof(self) -> Self::Reader;
202268

203-
/// Retrieve result into a boxed slice of the specified size.
269+
/// Retrieve XOF reader and reset hasher instance state.
270+
fn finalize_xof_reset(&mut self) -> Self::Reader;
271+
272+
/// Retrieve result into a boxed slice of the specified size and consume
273+
/// the hasher.
204274
///
205275
/// `Box<[u8]>` is used instead of `Vec<u8>` to save stack space, since
206276
/// they have size of 2 and 3 words respectively.
@@ -211,6 +281,54 @@ pub trait ExtendableOutput: core::marker::Sized {
211281
self.finalize_xof().read(&mut buf);
212282
buf
213283
}
284+
285+
/// Retrieve result into a boxed slice of the specified size and reset
286+
/// the hasher's state.
287+
///
288+
/// `Box<[u8]>` is used instead of `Vec<u8>` to save stack space, since
289+
/// they have size of 2 and 3 words respectively.
290+
#[cfg(feature = "alloc")]
291+
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
292+
fn finalize_boxed_reset(&mut self, n: usize) -> Box<[u8]> {
293+
let mut buf = vec![0u8; n].into_boxed_slice();
294+
self.finalize_xof_reset().read(&mut buf);
295+
buf
296+
}
297+
}
298+
299+
/// Trait for extendable-output function (XOF) implementations to use to
300+
/// retrieve the hash output.
301+
///
302+
/// Usage of this trait in user code is discouraged. Instead use the
303+
/// [`VariableOutput::finalize_variable`] or
304+
/// [`VariableOutput::finalize_variable_reset`] methods.
305+
///
306+
/// Types which impl this trait along with [`Reset`] will receive a blanket
307+
/// impl of [`VariableOutput`].
308+
pub trait ExtendableOutputDirty: Sized {
309+
/// Reader
310+
type Reader: XofReader;
311+
312+
/// Retrieve XOF reader and consume hasher instance.
313+
///
314+
/// Implementations should panic if this is called twice without resetting.
315+
fn finalize_xof_dirty(&mut self) -> Self::Reader;
316+
}
317+
318+
impl<X: ExtendableOutputDirty + Reset> ExtendableOutput for X {
319+
type Reader = X::Reader;
320+
321+
#[inline]
322+
fn finalize_xof(mut self) -> Self::Reader {
323+
self.finalize_xof_dirty()
324+
}
325+
326+
#[inline]
327+
fn finalize_xof_reset(&mut self) -> Self::Reader {
328+
let reader = self.finalize_xof_dirty();
329+
self.reset();
330+
reader
331+
}
214332
}
215333

216334
/// Trait for resetting hash instances

0 commit comments

Comments
 (0)