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
24pub trait UhfBackend: ParBlocksSizeUser {
26 fn proc_block(&mut self, block: &Block<Self>);
28
29 #[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 fn blocks_needed_to_align(&self) -> usize {
41 0
42 }
43}
44
45pub trait UhfClosure: BlockSizeUser {
49 fn call<B: UhfBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B);
51}
52
53pub trait UniversalHash: BlockSizeUser + Sized {
56 fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>);
58
59 #[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 #[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 fn finalize(self) -> Block<Self>;
114
115 #[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 #[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#[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 {}