#![no_std]
#![forbid(unsafe_code)]
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
#![warn(missing_docs, rust_2018_idioms)]
#[cfg(feature = "std")]
extern crate std;
pub use generic_array::{self, typenum::consts};
use generic_array::typenum::Unsigned;
use generic_array::{ArrayLength, GenericArray};
use subtle::{Choice, ConstantTimeEq};
pub type Key<U> = GenericArray<u8, <U as NewUniversalHash>::KeySize>;
pub type Block<U> = GenericArray<u8, <U as UniversalHash>::BlockSize>;
pub trait NewUniversalHash: Sized {
type KeySize: ArrayLength<u8>;
fn new(key: &Key<Self>) -> Self;
}
pub trait UniversalHash: Clone {
type BlockSize: ArrayLength<u8>;
fn update(&mut self, block: &Block<Self>);
fn update_padded(&mut self, data: &[u8]) {
let mut chunks = data.chunks_exact(Self::BlockSize::to_usize());
for chunk in &mut chunks {
self.update(GenericArray::from_slice(chunk));
}
let rem = chunks.remainder();
if !rem.is_empty() {
let mut padded_block = GenericArray::default();
padded_block[..rem.len()].copy_from_slice(rem);
self.update(&padded_block);
}
}
fn reset(&mut self);
fn finalize(self) -> Output<Self>;
fn finalize_reset(&mut self) -> Output<Self> {
let res = self.clone().finalize();
self.reset();
res
}
fn verify(self, other: &Block<Self>) -> Result<(), Error> {
if self.finalize() == other.into() {
Ok(())
} else {
Err(Error)
}
}
}
#[derive(Clone)]
pub struct Output<U: UniversalHash> {
bytes: GenericArray<u8, U::BlockSize>,
}
impl<U> Output<U>
where
U: UniversalHash,
{
pub fn new(bytes: Block<U>) -> Output<U> {
Output { bytes }
}
pub fn into_bytes(self) -> Block<U> {
self.bytes
}
}
impl<U> From<Block<U>> for Output<U>
where
U: UniversalHash,
{
fn from(bytes: Block<U>) -> Self {
Output { bytes }
}
}
impl<'a, U> From<&'a Block<U>> for Output<U>
where
U: UniversalHash,
{
fn from(bytes: &'a Block<U>) -> Self {
bytes.clone().into()
}
}
impl<U> ConstantTimeEq for Output<U>
where
U: UniversalHash,
{
fn ct_eq(&self, other: &Self) -> Choice {
self.bytes.ct_eq(&other.bytes)
}
}
impl<U> PartialEq for Output<U>
where
U: UniversalHash,
{
fn eq(&self, x: &Output<U>) -> bool {
self.ct_eq(x).unwrap_u8() == 1
}
}
impl<U: UniversalHash> Eq for Output<U> {}
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub struct Error;
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("UHF output mismatch")
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}