#[derive(Clone)]
pub struct GHash {
hh: [u64; Self::BLOCK_LEN],
hl: [u64; Self::BLOCK_LEN],
buf: [u8; Self::BLOCK_LEN],
}
impl GHash {
pub const KEY_LEN: usize = 16;
pub const BLOCK_LEN: usize = 16;
pub const TAG_LEN: usize = 16;
pub fn new(h: &[u8; Self::BLOCK_LEN]) -> Self {
let mut vh = u64::from_be_bytes([
h[0], h[1], h[2], h[3],
h[4], h[5], h[6], h[7],
]);
let mut vl = u64::from_be_bytes([
h[ 8], h[ 9], h[10], h[11],
h[12], h[13], h[14], h[15],
]);
let mut hl = [0u64; Self::BLOCK_LEN];
let mut hh = [0u64; Self::BLOCK_LEN];
hl[8] = vl;
hh[8] = vh;
let mut i = 4usize;
while i > 0 {
let t = ( vl & 1 ) * 0xe1000000;
vl = ( vh << 63 ) | ( vl >> 1 );
vh = ( vh >> 1 ) ^ (t << 32);
hl[i] = vl;
hh[i] = vh;
i >>= 1;
}
i = 2usize;
while i <= 8 {
vh = hh[i];
vl = hl[i];
for j in 1usize..i {
hh[i + j] = vh ^ hh[j];
hl[i + j] = vl ^ hl[j];
}
i *= 2;
}
let buf = [0u8; 16];
Self { hh, hl, buf }
}
#[inline]
fn gf_mul(&mut self, x: &[u8]) {
const LAST4: [u64; 16] = [
0x0000, 0x1c20, 0x3840, 0x2460,
0x7080, 0x6ca0, 0x48c0, 0x54e0,
0xe100, 0xfd20, 0xd940, 0xc560,
0x9180, 0x8da0, 0xa9c0, 0xb5e0,
];
let hh = &self.hh;
let hl = &self.hl;
for i in 0..16 {
self.buf[i] ^= x[i];
}
let x = &mut self.buf;
let mut lo: u8 = x[15] & 0xf;
let mut hi: u8 = 0;
let mut zh: u64 = hh[lo as usize];
let mut zl: u64 = hl[lo as usize];
let mut rem: u8 = 0;
for i in 0..16 {
lo = x[16 - 1 - i] & 0xf;
hi = (x[16 - 1 - i] >> 4) & 0xf;
if i != 0 {
rem = (zl & 0xf) as u8;
zl = ( zh << 60 ) | ( zl >> 4 );
zh = zh >> 4;
zh ^= LAST4[rem as usize] << 48;
zh ^= hh[lo as usize];
zl ^= hl[lo as usize];
}
rem = (zl & 0xf) as u8;
zl = ( zh << 60 ) | ( zl >> 4 );
zh = zh >> 4;
zh ^= LAST4[rem as usize] << 48;
zh ^= hh[hi as usize];
zl ^= hl[hi as usize];
}
let a = zh.to_be_bytes();
let b = zl.to_be_bytes();
x[0.. 8].copy_from_slice(&a);
x[8..16].copy_from_slice(&b);
}
pub fn update(&mut self, m: &[u8]) {
let mlen = m.len();
if mlen == 0 {
return ();
}
let n = mlen / Self::BLOCK_LEN;
for i in 0..n {
let chunk = &m[i * Self::BLOCK_LEN..i * Self::BLOCK_LEN + Self::BLOCK_LEN];
self.gf_mul(chunk);
}
if mlen % Self::BLOCK_LEN != 0 {
let rem = &m[n * Self::BLOCK_LEN..];
let rlen = rem.len();
let mut last_block = [0u8; Self::BLOCK_LEN];
last_block[..rlen].copy_from_slice(rem);
self.gf_mul(&last_block);
}
}
pub fn finalize(self) -> [u8; Self::TAG_LEN] {
self.buf
}
}