Skip to main content

digest/
block_api.rs

1//! Low-level traits operating on blocks and wrappers around them.
2//!
3//! Usage of traits in this module in user code is discouraged. Instead use
4//! core algorithm wrapped by the wrapper types, which implement the
5//! higher-level traits.
6use crate::{Digest, HashMarker, InvalidOutputSize};
7
8pub use block_buffer::{Eager, Lazy};
9pub use common::{AlgorithmName, Block, BlockSizeUser, OutputSizeUser, Reset};
10
11use block_buffer::{BlockBuffer, BlockSizes, BufferKind};
12use common::Output;
13
14mod ct_variable;
15pub use ct_variable::CtOutWrapper;
16
17/// Buffer type used by type which implements [`BufferKindUser`].
18pub type Buffer<S> =
19    BlockBuffer<<S as BlockSizeUser>::BlockSize, <S as BufferKindUser>::BufferKind>;
20
21/// Types which consume data in blocks.
22pub trait UpdateCore: BlockSizeUser {
23    /// Update state using the provided data blocks.
24    fn update_blocks(&mut self, blocks: &[Block<Self>]);
25}
26
27/// Sub-trait of [`BlockSizeUser`] implemented if `BlockSize` is
28/// bigger than `U0` and smaller than `U256`.
29///
30/// This trait relies on the hack suggested [here][0] to work around
31/// the long standing Rust issue regarding non-propagation of `where` bounds.
32///
33/// [0]: https://github.com/rust-lang/rust/issues/20671#issuecomment-1905186183
34pub trait SmallBlockSizeUser:
35    BlockSizeUser<BlockSize = <Self as SmallBlockSizeUser>::_BlockSize>
36{
37    /// Helper associated type equal to `<Self as BlockSizeUser>::BlockSize`.
38    type _BlockSize: BlockSizes;
39}
40
41impl<T: BlockSizeUser> SmallBlockSizeUser for T
42where
43    T::BlockSize: BlockSizes,
44{
45    type _BlockSize = T::BlockSize;
46}
47
48/// Types which use [`BlockBuffer`] functionality.
49pub trait BufferKindUser: SmallBlockSizeUser {
50    /// Block buffer kind over which type operates.
51    type BufferKind: BufferKind;
52}
53
54/// Trait implemented by eager hashes which expose their block-level core.
55pub trait EagerHash: SmallBlockSizeUser + Digest + Clone {
56    /// Block-level core type of the hash.
57    type Core: HashMarker
58        + UpdateCore
59        + FixedOutputCore
60        + SmallBlockSizeUser<_BlockSize = <Self as SmallBlockSizeUser>::_BlockSize>
61        + BufferKindUser<BufferKind = Eager>
62        + Default
63        + Clone;
64}
65
66impl<T> EagerHash for T
67where
68    T: CoreProxy + SmallBlockSizeUser + Digest + Clone,
69    <T as CoreProxy>::Core: HashMarker
70        + UpdateCore
71        + FixedOutputCore
72        + SmallBlockSizeUser<_BlockSize = <T as SmallBlockSizeUser>::_BlockSize>
73        + BufferKindUser<BufferKind = Eager>
74        + Default
75        + Clone,
76{
77    type Core = T::Core;
78}
79
80/// Core trait for hash functions with fixed output size.
81pub trait FixedOutputCore: UpdateCore + BufferKindUser + OutputSizeUser {
82    /// Finalize state using remaining data stored in the provided block buffer,
83    /// write result into provided array and leave `self` in a dirty state.
84    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>);
85}
86
87/// Core trait for hash functions with extendable (XOF) output size.
88pub trait ExtendableOutputCore: UpdateCore + BufferKindUser {
89    /// XOF reader core state.
90    type ReaderCore: XofReaderCore;
91
92    /// Retrieve XOF reader using remaining data stored in the block buffer
93    /// and leave hasher in a dirty state.
94    fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore;
95}
96
97/// Core reader trait for extendable-output function (XOF) result.
98pub trait XofReaderCore: BlockSizeUser {
99    /// Read next XOF block.
100    fn read_block(&mut self) -> Block<Self>;
101}
102
103/// Core trait for hash functions with variable output size.
104///
105/// Maximum output size is equal to [`OutputSizeUser::OutputSize`].
106/// Users are expected to truncate result returned by the
107/// [`finalize_variable_core`] to `output_size` passed to the [`new`] method
108/// during construction. Truncation side is defined by the [`TRUNC_SIDE`]
109/// associated constant.
110///
111/// [`finalize_variable_core`]: VariableOutputCore::finalize_variable_core
112/// [`new`]: VariableOutputCore::new
113/// [`TRUNC_SIDE`]: VariableOutputCore::TRUNC_SIDE
114pub trait VariableOutputCore: UpdateCore + OutputSizeUser + BufferKindUser + Sized {
115    /// Side which should be used in a truncated result.
116    const TRUNC_SIDE: TruncSide;
117
118    /// Initialize hasher state for given output size.
119    ///
120    /// # Errors
121    /// Returns [`InvalidOutputSize`] if `output_size` is not valid for
122    /// the algorithm, e.g. if it's bigger than the [`OutputSize`]
123    /// associated type.
124    ///
125    /// [`OutputSize`]: OutputSizeUser::OutputSize
126    fn new(output_size: usize) -> Result<Self, InvalidOutputSize>;
127
128    /// Finalize hasher and write full hashing result into the `out` buffer.
129    ///
130    /// The result must be truncated to `output_size` used during hasher
131    /// construction. Truncation side is defined by the [`TRUNC_SIDE`]
132    /// associated constant.
133    ///
134    /// [`TRUNC_SIDE`]: VariableOutputCore::TRUNC_SIDE
135    fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>);
136}
137
138/// Trait adding customization string to hash functions with variable output.
139pub trait VariableOutputCoreCustomized: VariableOutputCore {
140    /// Create new hasher instance with the given customization string and output size.
141    fn new_customized(customization: &[u8], output_size: usize) -> Self;
142}
143
144/// Type which used for defining truncation side in the [`VariableOutputCore`]
145/// trait.
146#[derive(Copy, Clone, Debug)]
147pub enum TruncSide {
148    /// Truncate left side, i.e. `&out[..n]`.
149    Left,
150    /// Truncate right side, i.e. `&out[m..]`.
151    Right,
152}
153
154/// A proxy trait to the core block-level type.
155pub trait CoreProxy {
156    /// Core block-level type.
157    type Core: BufferKindUser;
158
159    /// Create `Self` from core and buffer.
160    fn compose(core: Self::Core, buffer: Buffer<Self::Core>) -> Self;
161    /// Decompose `self` into core and buffer.
162    fn decompose(self) -> (Self::Core, Buffer<Self::Core>);
163}