use crate::{Block, Key, Tag};
use core::{arch::aarch64::*, mem};
use universal_hash::{
consts::{U1, U16},
crypto_common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser},
KeyInit, Reset, UhfBackend,
};
#[derive(Clone)]
pub struct Polyval {
h: uint8x16_t,
y: uint8x16_t,
}
impl KeySizeUser for Polyval {
type KeySize = U16;
}
impl KeyInit for Polyval {
fn new(h: &Key) -> Self {
unsafe {
Self {
h: vld1q_u8(h.as_ptr()),
y: vdupq_n_u8(0), }
}
}
}
impl BlockSizeUser for Polyval {
type BlockSize = U16;
}
impl ParBlocksSizeUser for Polyval {
type ParBlocksSize = U1;
}
impl UhfBackend for Polyval {
fn proc_block(&mut self, x: &Block) {
unsafe {
self.mul(x);
}
}
}
impl Reset for Polyval {
fn reset(&mut self) {
unsafe {
self.y = vdupq_n_u8(0);
}
}
}
impl Polyval {
const MASK: u128 = 1 << 127 | 1 << 126 | 1 << 121 | 1;
pub(crate) fn finalize(self) -> Tag {
unsafe { mem::transmute(self.y) }
}
#[inline]
#[target_feature(enable = "neon")]
unsafe fn mul(&mut self, x: &Block) {
let h = self.h;
let y = veorq_u8(self.y, vld1q_u8(x.as_ptr()));
let z = vdupq_n_u8(0);
let r0 = pmull::<0, 0>(h, y);
let r1 = pmull::<1, 1>(h, y);
let t0 = pmull::<0, 1>(h, y);
let t1 = pmull::<1, 0>(h, y);
let t0 = veorq_u8(t0, t1);
let t1 = vextq_u8(z, t0, 8);
let r0 = veorq_u8(r0, t1);
let t1 = vextq_u8(t0, z, 8);
let r1 = veorq_u8(r1, t1);
let p = mem::transmute(Self::MASK);
let t0 = pmull::<0, 1>(r0, p);
let t1 = vextq_u8(t0, t0, 8);
let r0 = veorq_u8(r0, t1);
let t1 = pmull::<1, 1>(r0, p);
let r0 = veorq_u8(r0, t1);
self.y = veorq_u8(r0, r1);
}
}
#[inline(always)]
unsafe fn pmull<const A_LANE: i32, const B_LANE: i32>(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t {
mem::transmute(vmull_p64(
vgetq_lane_u64(vreinterpretq_u64_u8(a), A_LANE),
vgetq_lane_u64(vreinterpretq_u64_u8(b), B_LANE),
))
}