use super::Zuc128Keystream;
use crate::internal::mac::{MacCore, MacKeyPair, MacWord};
use numeric_cast::TruncatingCast;
use stdx::default::default;
pub struct Zuc128Mac(MacCore<Zuc128Keystream, u32>);
impl Zuc128Mac {
#[must_use]
pub fn compute(ik: &[u8; 16], iv: &[u8; 16], msg: &[u8], bitlen: usize) -> u32 {
Self::new(ik, iv).finish(msg, bitlen)
}
#[must_use]
pub fn new(ik: &[u8; 16], iv: &[u8; 16]) -> Self {
let mut zuc = Zuc128Keystream::new(ik, iv);
let key = u64::gen_key_pair(&mut zuc);
Self(MacCore {
zuc,
key,
tag: 0,
rem: default(),
cnt: 0,
})
}
pub fn update(&mut self, msg: &[u8]) {
self.0.update(msg);
}
#[must_use]
pub fn finish(mut self, tail: &[u8], bitlen: usize) -> u32 {
let final_bitlen = self.0.finish(tail, bitlen);
let mut tag = self.0.tag;
let key = self.0.key;
tag ^= key.high();
if final_bitlen == 0 {
tag ^= key.truncating_cast::<u32>();
} else {
tag ^= self.0.zuc.generate();
}
tag
}
}
impl digest::Update for Zuc128Mac {
fn update(&mut self, data: &[u8]) {
Zuc128Mac::update(self, data);
}
}
impl digest::OutputSizeUser for Zuc128Mac {
type OutputSize = digest::typenum::U4;
}
impl digest::FixedOutput for Zuc128Mac {
fn finalize_into(self, out: &mut digest::Output<Self>) {
let tag = self.finish(&[], 0);
*out = tag.to_be_array();
}
}
impl digest::MacMarker for Zuc128Mac {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_digest() {
fn require_digest_mac<T: digest::Mac>() {}
require_digest_mac::<Zuc128Mac>();
}
}