1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! Traits for [Universal Hash Functions].
//!
//! # About universal hashes
//!
//! Universal hash functions provide a "universal family" of possible
//! hash functions where a given member of a family is selected by a key.
//!
//! They are well suited to the purpose of "one time authenticators" for a
//! sequence of bytestring inputs, as their construction has a number of
//! desirable properties such as pairwise independence as well as amenability
//! to efficient implementations, particularly when implemented using SIMD
//! instructions.
//!
//! When combined with a cipher, such as in Galois/Counter Mode (GCM) or the
//! Salsa20 family AEAD constructions, they can provide the core functionality
//! for a Message Authentication Code (MAC).
//!
//! [Universal Hash Functions]: https://en.wikipedia.org/wiki/Universal_hashing

#![no_std]
#![forbid(unsafe_code)]
#![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",
    html_root_url = "https://docs.rs/universal-hash/0.4.1"
)]
#![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};

/// Keys to a [`UniversalHash`].
pub type Key<U> = GenericArray<u8, <U as NewUniversalHash>::KeySize>;

/// Blocks are inputs to a [`UniversalHash`].
pub type Block<U> = GenericArray<u8, <U as UniversalHash>::BlockSize>;

/// Instantiate a [`UniversalHash`] algorithm.
pub trait NewUniversalHash: Sized {
    /// Size of the key for the universal hash function.
    type KeySize: ArrayLength<u8>;

    /// Instantiate a universal hash function with the given key.
    fn new(key: &Key<Self>) -> Self;
}

/// The [`UniversalHash`] trait defines a generic interface for universal hash
/// functions.
pub trait UniversalHash: Clone {
    /// Size of the inputs to and outputs from the universal hash function
    type BlockSize: ArrayLength<u8>;

    /// Input a block into the universal hash function
    fn update(&mut self, block: &Block<Self>);

    /// Input data into the universal hash function. If the length of the
    /// data is not a multiple of the block size, the remaining data is
    /// padded with zeroes up to the `BlockSize`.
    ///
    /// This approach is frequently used by AEAD modes which use
    /// Message Authentication Codes (MACs) based on universal hashing.
    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);
        }
    }

    /// Reset [`UniversalHash`] instance.
    fn reset(&mut self);

    /// Obtain the [`Output`] of a [`UniversalHash`] function and consume it.
    fn finalize(self) -> Output<Self>;

    /// Obtain the [`Output`] of a [`UniversalHash`] computation and reset it back
    /// to its initial state.
    fn finalize_reset(&mut self) -> Output<Self> {
        let res = self.clone().finalize();
        self.reset();
        res
    }

    /// Verify the [`UniversalHash`] of the processed input matches a given [`Output`].
    /// This is useful when constructing Message Authentication Codes (MACs)
    /// from universal hash functions.
    fn verify(self, other: &Block<Self>) -> Result<(), Error> {
        if self.finalize() == other.into() {
            Ok(())
        } else {
            Err(Error)
        }
    }
}

/// Outputs of universal hash functions which are a thin wrapper around a
/// byte array. Provides a safe [`Eq`] implementation that runs in constant time,
/// which is useful for implementing Message Authentication Codes (MACs) based
/// on universal hashing.
#[derive(Clone)]
pub struct Output<U: UniversalHash> {
    bytes: GenericArray<u8, U::BlockSize>,
}

impl<U> Output<U>
where
    U: UniversalHash,
{
    /// Create a new [`Output`] block.
    pub fn new(bytes: Block<U>) -> Output<U> {
        Output { bytes }
    }

    /// Get the inner [`GenericArray`] this type wraps
    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> {}

/// Error type for when the [`Output`] of a [`UniversalHash`]
/// is not equal to the expected value.
#[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 {}