1#![no_std]
21#![doc(
22 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
23 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
24)]
25#![cfg_attr(docsrs, feature(doc_cfg))]
26#![deny(unsafe_code)]
27#![warn(missing_docs, rust_2018_idioms)]
28
29#[cfg(feature = "std")]
30extern crate std;
31
32pub use crypto_common::{
33 self, generic_array,
34 typenum::{self, consts},
35 Block, Key, KeyInit, ParBlocks, Reset,
36};
37
38use core::slice;
39use crypto_common::{BlockSizeUser, ParBlocksSizeUser};
40use generic_array::{ArrayLength, GenericArray};
41use subtle::ConstantTimeEq;
42use typenum::Unsigned;
43
44pub trait UhfBackend: ParBlocksSizeUser {
46 fn proc_block(&mut self, block: &Block<Self>);
48
49 #[inline(always)]
51 fn proc_par_blocks(&mut self, blocks: &ParBlocks<Self>) {
52 for block in blocks {
53 self.proc_block(block);
54 }
55 }
56
57 fn blocks_needed_to_align(&self) -> usize {
61 0
62 }
63}
64
65pub trait UhfClosure: BlockSizeUser {
69 fn call<B: UhfBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B);
71}
72
73pub trait UniversalHash: BlockSizeUser + Sized {
76 fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>);
78
79 #[inline]
81 fn update(&mut self, blocks: &[Block<Self>]) {
82 struct Ctx<'a, BS: ArrayLength<u8>> {
83 blocks: &'a [Block<Self>],
84 }
85
86 impl<'a, BS: ArrayLength<u8>> BlockSizeUser for Ctx<'a, BS> {
87 type BlockSize = BS;
88 }
89
90 impl<'a, BS: ArrayLength<u8>> UhfClosure for Ctx<'a, BS> {
91 #[inline(always)]
92 fn call<B: UhfBackend<BlockSize = BS>>(self, backend: &mut B) {
93 let pb = B::ParBlocksSize::USIZE;
94 if pb > 1 {
95 let (par_blocks, tail) = to_blocks(self.blocks);
96 for par_block in par_blocks {
97 backend.proc_par_blocks(par_block);
98 }
99 for block in tail {
100 backend.proc_block(block);
101 }
102 } else {
103 for block in self.blocks {
104 backend.proc_block(block);
105 }
106 }
107 }
108 }
109
110 self.update_with_backend(Ctx { blocks });
111 }
112
113 #[inline]
120 fn update_padded(&mut self, data: &[u8]) {
121 let (blocks, tail) = to_blocks(data);
122
123 self.update(blocks);
124
125 if !tail.is_empty() {
126 let mut padded_block = GenericArray::default();
127 padded_block[..tail.len()].copy_from_slice(tail);
128 self.update(slice::from_ref(&padded_block));
129 }
130 }
131
132 fn finalize(self) -> Block<Self>;
134
135 #[inline]
138 fn finalize_reset(&mut self) -> Block<Self>
139 where
140 Self: Clone + Reset,
141 {
142 let ret = self.clone().finalize();
143 self.reset();
144 ret
145 }
146
147 #[inline]
153 fn verify(self, expected: &Block<Self>) -> Result<(), Error> {
154 if self.finalize().ct_eq(expected).into() {
155 Ok(())
156 } else {
157 Err(Error)
158 }
159 }
160}
161
162#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
165pub struct Error;
166
167impl core::fmt::Display for Error {
168 #[inline]
169 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
170 f.write_str("UHF output mismatch")
171 }
172}
173
174#[cfg(feature = "std")]
175#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
176impl std::error::Error for Error {}
177
178#[inline(always)]
181fn to_blocks<T, N: ArrayLength<T>>(data: &[T]) -> (&[GenericArray<T, N>], &[T]) {
182 let nb = data.len() / N::USIZE;
183 let (left, right) = data.split_at(nb * N::USIZE);
184 let p = left.as_ptr() as *const GenericArray<T, N>;
185 #[allow(unsafe_code)]
188 let blocks = unsafe { slice::from_raw_parts(p, nb) };
189 (blocks, right)
190}