universal_hash/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
6    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
7)]
8#![forbid(unsafe_code)]
9#![warn(missing_docs, rust_2018_idioms, missing_debug_implementations)]
10
11pub use crypto_common::{
12    self, Block, Key, KeyInit, ParBlocks, Reset, array,
13    typenum::{self, consts},
14};
15
16use core::slice;
17use crypto_common::{BlockSizeUser, BlockSizes, ParBlocksSizeUser, array::Array};
18use subtle::ConstantTimeEq;
19use typenum::Unsigned;
20
21/// Trait implemented by UHF backends.
22pub trait UhfBackend: ParBlocksSizeUser {
23    /// Process single block.
24    fn proc_block(&mut self, block: &Block<Self>);
25
26    /// Process several blocks in parallel.
27    #[inline(always)]
28    fn proc_par_blocks(&mut self, blocks: &ParBlocks<Self>) {
29        for block in blocks {
30            self.proc_block(block);
31        }
32    }
33
34    /// Returns the number of blocks that should be passed to `Self::proc_block` before
35    /// `Self::proc_par_blocks` can be used efficiently. This is always less than
36    /// `Self::ParBlocksSize`.
37    fn blocks_needed_to_align(&self) -> usize {
38        0
39    }
40}
41
42/// Trait for [`UhfBackend`] users.
43///
44/// This trait is used to define rank-2 closures.
45pub trait UhfClosure: BlockSizeUser {
46    /// Execute closure with the provided UHF backend.
47    fn call<B: UhfBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B);
48}
49
50/// The [`UniversalHash`] trait defines a generic interface for universal hash
51/// functions.
52pub trait UniversalHash: BlockSizeUser + Sized {
53    /// Update hash function state using the provided rank-2 closure.
54    fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>);
55
56    /// Update hash function state with the provided block.
57    #[inline]
58    fn update(&mut self, blocks: &[Block<Self>]) {
59        struct Ctx<'a, BS: BlockSizes> {
60            blocks: &'a [Block<Self>],
61        }
62
63        impl<BS: BlockSizes> BlockSizeUser for Ctx<'_, BS> {
64            type BlockSize = BS;
65        }
66
67        impl<BS: BlockSizes> UhfClosure for Ctx<'_, BS> {
68            #[inline(always)]
69            fn call<B: UhfBackend<BlockSize = BS>>(self, backend: &mut B) {
70                let pb = B::ParBlocksSize::USIZE;
71                if pb > 1 {
72                    let (par_blocks, tail) = Array::slice_as_chunks(self.blocks);
73                    for par_block in par_blocks {
74                        backend.proc_par_blocks(par_block);
75                    }
76                    for block in tail {
77                        backend.proc_block(block);
78                    }
79                } else {
80                    for block in self.blocks {
81                        backend.proc_block(block);
82                    }
83                }
84            }
85        }
86
87        self.update_with_backend(Ctx { blocks });
88    }
89
90    /// Input data into the universal hash function. If the length of the
91    /// data is not a multiple of the block size, the remaining data is
92    /// padded with zeroes up to the `BlockSize`.
93    ///
94    /// This approach is frequently used by AEAD modes which use
95    /// Message Authentication Codes (MACs) based on universal hashing.
96    #[inline]
97    fn update_padded(&mut self, data: &[u8]) {
98        let (blocks, tail) = Array::slice_as_chunks(data);
99
100        self.update(blocks);
101
102        if !tail.is_empty() {
103            let mut padded_block = Array::default();
104            padded_block[..tail.len()].copy_from_slice(tail);
105            self.update(slice::from_ref(&padded_block));
106        }
107    }
108
109    /// Retrieve result and consume hasher instance.
110    fn finalize(self) -> Block<Self>;
111
112    /// Obtain the output of a [`UniversalHash`] computation and reset it back
113    /// to its initial state.
114    #[inline]
115    fn finalize_reset(&mut self) -> Block<Self>
116    where
117        Self: Clone + Reset,
118    {
119        let ret = self.clone().finalize();
120        self.reset();
121        ret
122    }
123
124    /// Verify the [`UniversalHash`] of the processed input matches
125    /// a given `expected` value.
126    ///
127    /// This is useful when constructing Message Authentication Codes (MACs)
128    /// from universal hash functions.
129    #[inline]
130    fn verify(self, expected: &Block<Self>) -> Result<(), Error> {
131        if self.finalize().ct_eq(expected).into() {
132            Ok(())
133        } else {
134            Err(Error)
135        }
136    }
137}
138
139/// Error type used by the [`UniversalHash::verify`] method
140/// to indicate that UHF output is not equal the expected value.
141#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
142pub struct Error;
143
144impl core::fmt::Display for Error {
145    #[inline]
146    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
147        f.write_str("UHF output mismatch")
148    }
149}
150
151impl core::error::Error for Error {}