Skip to main content

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