#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
)]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms, missing_debug_implementations)]
pub use common::{
self, Block, Key, KeyInit, ParBlocks, Reset, array,
typenum::{self, consts},
};
use common::{
BlockSizeUser, ParBlocksSizeUser,
array::{Array, ArraySize},
};
use core::slice;
use ctutils::CtEq;
use typenum::Unsigned;
pub trait UhfBackend: ParBlocksSizeUser {
fn proc_block(&mut self, block: &Block<Self>);
#[inline(always)]
fn proc_par_blocks(&mut self, blocks: &ParBlocks<Self>) {
for block in blocks {
self.proc_block(block);
}
}
fn blocks_needed_to_align(&self) -> usize {
0
}
}
pub trait UhfClosure: BlockSizeUser {
fn call<B: UhfBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B);
}
pub trait UniversalHash: BlockSizeUser + Sized {
fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>);
#[inline]
fn update(&mut self, blocks: &[Block<Self>]) {
struct Ctx<'a, BS: ArraySize> {
blocks: &'a [Block<Self>],
}
impl<BS: ArraySize> BlockSizeUser for Ctx<'_, BS> {
type BlockSize = BS;
}
impl<BS: ArraySize> UhfClosure for Ctx<'_, BS> {
#[inline(always)]
fn call<B: UhfBackend<BlockSize = BS>>(self, backend: &mut B) {
let pb = B::ParBlocksSize::USIZE;
if pb > 1 {
let (par_blocks, tail) = Array::slice_as_chunks(self.blocks);
for par_block in par_blocks {
backend.proc_par_blocks(par_block);
}
for block in tail {
backend.proc_block(block);
}
} else {
for block in self.blocks {
backend.proc_block(block);
}
}
}
}
self.update_with_backend(Ctx { blocks });
}
#[inline]
fn update_padded(&mut self, data: &[u8]) {
let (blocks, tail) = Array::slice_as_chunks(data);
self.update(blocks);
if !tail.is_empty() {
let mut padded_block = Array::default();
padded_block[..tail.len()].copy_from_slice(tail);
self.update(slice::from_ref(&padded_block));
}
}
fn finalize(self) -> Block<Self>;
#[inline]
fn finalize_reset(&mut self) -> Block<Self>
where
Self: Clone + Reset,
{
let ret = self.clone().finalize();
self.reset();
ret
}
#[inline]
fn verify(self, expected: &Block<Self>) -> Result<(), Error> {
if self.finalize().ct_eq(expected).into() {
Ok(())
} else {
Err(Error)
}
}
}
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub struct Error;
impl core::fmt::Display for Error {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("UHF output mismatch")
}
}
impl core::error::Error for Error {}