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
//! Implementations of correlation-robust hash functions (and their variants)
//! based on fixed-key AES.
use crate::{Aes128, Block, FIXED_KEY_AES128};
use vectoreyes::{
array_utils::{ArrayUnrolledExt, ArrayUnrolledOps, UnrollableArraySize},
SimdBase8, U8x16,
};
/// AES-based correlation-robust hash function.
///
/// This hash function supports the correlation-robust variants given in
/// <https://eprint.iacr.org/2019/074>.
pub struct AesHash {
aes: Aes128,
}
/// `AesHash` with a fixed key.
pub const AES_HASH: AesHash = AesHash {
aes: FIXED_KEY_AES128,
};
impl AesHash {
/// Initialize the hash function using `key`.
#[inline]
pub fn new(key: Block) -> Self {
let aes = Aes128::new(key);
AesHash { aes }
}
/// Correlation-robust hash function for 128-bit inputs (cf.
/// <https://eprint.iacr.org/2019/074>, §7.2).
///
/// The function computes `π(x) ⊕ x`.
#[inline]
pub fn cr_hash(&self, _i: Block, x: Block) -> Block {
self.aes.encrypt(x) ^ x
}
/// Circular correlation-robust hash function (cf.
/// <https://eprint.iacr.org/2019/074>, §7.3).
///
/// The function computes `H(σ(x))`, where `H` is a correlation-robust hash
/// function and `σ(x₀ || x₁) = (x₀ ⊕ x₁) || x₁`.
#[inline]
pub fn ccr_hash(&self, i: Block, x: Block) -> Block {
let x = U8x16::from(x.0);
self.cr_hash(i, Block::from(x.shift_bytes_right::<8>() ^ x))
}
/// Tweakable circular correlation robust hash function (cf.
/// <https://eprint.iacr.org/2019/074>, §7.4).
///
/// The function computes `π(π(x) ⊕ i) ⊕ π(x)`.
#[inline]
pub fn tccr_hash(&self, i: Block, x: Block) -> Block {
let y = self.aes.encrypt(x);
let t = y ^ i;
let z = self.aes.encrypt(t);
y ^ z
}
/// Batch tweakable circular correlation robust hash function
pub fn tccr_hash_many<const Q: usize>(&self, i: Block, xs: [Block; Q]) -> [Block; Q]
where
ArrayUnrolledOps: UnrollableArraySize<Q>,
{
let y = self.aes.encrypt_blocks(xs);
let t = y.array_map(
#[inline(always)]
|x| x ^ i,
);
let z = self.aes.encrypt_blocks(t);
y.array_zip(z).array_map(
#[inline(always)]
|(a, b)| a ^ b,
)
}
}