use core::arch::asm;
use core::arch::x86_64::*;
use crate::aes::x86::Keys;
use crate::clmul::{product, reduce};
use ic_core::Zeroize;
const BLOCK: usize = 16;
const NARROW: usize = BLOCK * 8;
const WIDE: usize = BLOCK * 16;
const WIDE32: usize = BLOCK * 32;
const NPOW: usize = 32;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Kernel {
Clmul8,
Vaes256,
Vaes512,
}
macro_rules! cached_detect {
($($f:tt),+) => {{
use core::sync::atomic::{AtomicU8, Ordering};
static CACHED: AtomicU8 = AtomicU8::new(0);
match CACHED.load(Ordering::Relaxed) {
1 => true,
2 => false,
_ => {
let have = true $(&& std::arch::is_x86_feature_detected!($f))+;
CACHED.store(u8::from(!have) + 1, Ordering::Relaxed);
have
}
}
}};
}
#[derive(Clone, Copy, Debug)]
pub struct Wide(());
impl Wide {
pub fn detect() -> Option<Wide> {
cached_detect!("avx2", "vaes", "vpclmulqdq", "aes", "pclmulqdq", "ssse3")
.then_some(Wide(()))
}
}
#[derive(Clone, Copy, Debug)]
pub struct Wide512(());
impl Wide512 {
pub fn detect() -> Option<Wide512> {
let have = Wide::detect().is_some() && cached_detect!("avx512f", "avx512bw");
have.then_some(Wide512(()))
}
}
pub fn best_kernel() -> Kernel {
if Wide512::detect().is_some() {
Kernel::Vaes512
} else if Wide::detect().is_some() {
Kernel::Vaes256
} else {
Kernel::Clmul8
}
}
#[derive(Clone, Copy, Debug)]
enum Path {
Narrow,
Wide(Wide),
Wide512(Wide512),
}
pub(crate) struct HashKey {
powers: [[u8; BLOCK]; NPOW],
h: [u8; BLOCK],
kara: [[u8; BLOCK]; NPOW],
path: Path,
}
impl HashKey {
pub(crate) unsafe fn new(keys: &Keys, kernel: Kernel) -> HashKey {
let w512 = match kernel {
Kernel::Vaes512 => Wide512::detect(),
_ => None,
};
let w256 = match kernel {
Kernel::Vaes512 | Kernel::Vaes256 => Wide::detect(),
Kernel::Clmul8 => None,
};
let path = match (w512, w256) {
(Some(t), _) => Path::Wide512(t),
(None, Some(t)) => Path::Wide(t),
(None, None) => Path::Narrow,
};
let mut hk = HashKey {
powers: [[0u8; BLOCK]; NPOW],
h: [0u8; BLOCK],
kara: [[0u8; BLOCK]; NPOW],
path,
};
unsafe { compute_powers(keys, &mut hk) };
hk
}
#[cfg(test)]
pub(crate) fn kernel(&self) -> Kernel {
match self.path {
Path::Narrow => Kernel::Clmul8,
Path::Wide(_) => Kernel::Vaes256,
Path::Wide512(_) => Kernel::Vaes512,
}
}
pub(crate) fn h(&self) -> &[u8; BLOCK] {
&self.h
}
#[inline]
#[target_feature(enable = "sse2")]
fn power(&self, i: usize) -> __m128i {
unsafe { _mm_loadu_si128(self.powers[i].as_ptr() as *const __m128i) }
}
#[inline]
#[target_feature(enable = "avx2")]
fn power_pair(&self, i: usize) -> __m256i {
let pair = &self.powers[i..i + 2];
unsafe { _mm256_loadu_si256(pair.as_ptr() as *const __m256i) }
}
}
impl Drop for HashKey {
fn drop(&mut self) {
for p in self.powers.iter_mut().chain(self.kara.iter_mut()) {
p.zeroize();
}
self.h.zeroize();
}
}
#[target_feature(enable = "aes,pclmulqdq,ssse3")]
fn compute_powers(keys: &Keys, hk: &mut HashKey) {
let (rk, rounds) = keys.enc_round_keys();
let h = aes1(rk, rounds, _mm_setzero_si128());
unsafe { _mm_storeu_si128(hk.h.as_mut_ptr() as *mut __m128i, h) };
let hs = _mm_shuffle_epi8(h, bswap());
let mut p = hs;
for i in (0..NPOW).rev() {
if i < NPOW - 1 {
let (lo, mid, hi) = product(p, hs);
p = reduce(lo, mid, hi);
}
let k = _mm_xor_si128(p, _mm_shuffle_epi32::<0x4e>(p));
unsafe {
_mm_storeu_si128(hk.powers[i].as_mut_ptr() as *mut __m128i, p);
_mm_storeu_si128(hk.kara[i].as_mut_ptr() as *mut __m128i, k);
}
}
}
pub(crate) unsafe fn seal_or_open(
keys: &Keys,
hk: &HashKey,
j0: &[u8; BLOCK],
aad: &[u8],
data: &mut [u8],
encrypting: bool,
) -> [u8; BLOCK] {
match hk.path {
Path::Wide512(w) => unsafe { run_wide(Bulk::Zmm(w), keys, hk, j0, aad, data, encrypting) },
Path::Wide(w) => unsafe { run_wide(Bulk::Ymm(w), keys, hk, j0, aad, data, encrypting) },
Path::Narrow => unsafe { run_narrow(keys, hk, j0, aad, data, encrypting) },
}
}
#[inline]
#[target_feature(enable = "sse2")]
fn bswap() -> __m128i {
_mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
}
#[inline]
#[target_feature(enable = "sse2")]
fn ctr_swap() -> __m128i {
_mm_set_epi8(12, 13, 14, 15, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
}
struct Counter(__m128i);
impl Counter {
#[inline]
#[target_feature(enable = "ssse3")]
fn after(j0: __m128i) -> Counter {
Counter(_mm_add_epi32(
_mm_shuffle_epi8(j0, ctr_swap()),
_mm_set_epi32(1, 0, 0, 0),
))
}
#[inline]
#[target_feature(enable = "ssse3")]
fn next(&mut self) -> __m128i {
let out = _mm_shuffle_epi8(self.0, ctr_swap());
self.0 = _mm_add_epi32(self.0, _mm_set_epi32(1, 0, 0, 0));
out
}
}
#[inline]
#[target_feature(enable = "aes")]
fn aes1(rk: &[__m128i; 15], rounds: usize, block: __m128i) -> __m128i {
let mut b = _mm_xor_si128(block, rk[0]);
for k in &rk[1..rounds] {
b = _mm_aesenc_si128(b, *k);
}
_mm_aesenclast_si128(b, rk[rounds])
}
struct Pending {
y: __m128i,
buf: [__m128i; 8],
n: usize,
}
impl Pending {
#[inline]
#[target_feature(enable = "sse2")]
fn new() -> Pending {
Pending {
y: _mm_setzero_si128(),
buf: [_mm_setzero_si128(); 8],
n: 0,
}
}
#[inline]
#[target_feature(enable = "pclmulqdq,ssse3")]
fn push(&mut self, hk: &HashKey, x: __m128i) {
self.buf[self.n] = x;
self.n += 1;
if self.n == self.buf.len() {
self.flush(hk);
}
}
#[inline]
#[target_feature(enable = "pclmulqdq,ssse3")]
fn push_padded(&mut self, hk: &HashKey, bytes: &[u8]) {
let mask = bswap();
let mut whole = bytes.chunks_exact(BLOCK);
for b in &mut whole {
let x = unsafe { _mm_loadu_si128(b.as_ptr() as *const __m128i) };
self.push(hk, _mm_shuffle_epi8(x, mask));
}
let rest = whole.remainder();
if !rest.is_empty() {
let mut last = [0u8; BLOCK];
last[..rest.len()].copy_from_slice(rest);
let x = unsafe { _mm_loadu_si128(last.as_ptr() as *const __m128i) };
self.push(hk, _mm_shuffle_epi8(x, mask));
}
}
#[inline]
#[target_feature(enable = "pclmulqdq,ssse3")]
fn flush(&mut self, hk: &HashKey) {
let n = self.n;
if n == 0 {
return;
}
let (mut lo, mut mid, mut hi) = (
_mm_setzero_si128(),
_mm_setzero_si128(),
_mm_setzero_si128(),
);
for j in 0..n {
let mut x = self.buf[j];
if j == 0 {
x = _mm_xor_si128(x, self.y);
}
let (l, m, u) = product(x, hk.power(NPOW - n + j));
lo = _mm_xor_si128(lo, l);
mid = _mm_xor_si128(mid, m);
hi = _mm_xor_si128(hi, u);
}
self.y = reduce(lo, mid, hi);
self.n = 0;
}
}
impl Drop for Pending {
fn drop(&mut self) {
wipe(core::slice::from_mut(&mut self.y));
wipe(&mut self.buf);
}
}
#[inline]
fn wipe(regs: &mut [__m128i]) {
for r in regs.iter_mut() {
unsafe { core::ptr::write_volatile(r, core::mem::zeroed()) };
}
}
#[inline]
#[target_feature(enable = "aes,pclmulqdq,ssse3")]
#[allow(clippy::too_many_arguments)]
fn finish(
keys: &Keys,
hk: &HashKey,
g: &mut Pending,
ctr: &mut Counter,
j0: __m128i,
tail: &mut [u8],
aad_len: usize,
data_len: usize,
encrypting: bool,
) -> [u8; BLOCK] {
debug_assert!(tail.len() < NARROW);
let (rk, rounds) = keys.enc_round_keys();
let mask = bswap();
let blocks = tail.len().div_ceil(BLOCK);
let mut s = [_mm_setzero_si128(); 9];
s[0] = j0;
for slot in s[1..=blocks].iter_mut() {
*slot = ctr.next();
}
let live = &mut s[..=blocks];
for b in live.iter_mut() {
*b = _mm_xor_si128(*b, rk[0]);
}
for k in &rk[1..rounds] {
for b in live.iter_mut() {
*b = _mm_aesenc_si128(*b, *k);
}
}
for b in live.iter_mut() {
*b = _mm_aesenclast_si128(*b, rk[rounds]);
}
let mut whole = tail.chunks_exact_mut(BLOCK);
let mut i = 1;
for b in &mut whole {
let p = b.as_mut_ptr();
let input = unsafe { _mm_loadu_si128(p as *const __m128i) };
let output = _mm_xor_si128(input, s[i]);
unsafe { _mm_storeu_si128(p as *mut __m128i, output) };
let ct = if encrypting { output } else { input };
g.push(hk, _mm_shuffle_epi8(ct, mask));
i += 1;
}
let rest = whole.into_remainder();
if !rest.is_empty() {
let mut buf = [0u8; BLOCK];
buf[..rest.len()].copy_from_slice(rest);
let input = unsafe { _mm_loadu_si128(buf.as_ptr() as *const __m128i) };
let output = _mm_xor_si128(input, s[i]);
unsafe { _mm_storeu_si128(buf.as_mut_ptr() as *mut __m128i, output) };
rest.copy_from_slice(&buf[..rest.len()]);
let ct = if encrypting {
buf[rest.len()..].fill(0);
unsafe { _mm_loadu_si128(buf.as_ptr() as *const __m128i) }
} else {
input
};
g.push(hk, _mm_shuffle_epi8(ct, mask));
buf.zeroize();
}
let len_block = _mm_set_epi64x(
(aad_len as u64).wrapping_mul(8) as i64,
(data_len as u64).wrapping_mul(8) as i64,
);
g.push(hk, len_block);
g.flush(hk);
let tag = _mm_xor_si128(_mm_shuffle_epi8(g.y, mask), s[0]);
wipe(&mut s);
let mut out = [0u8; BLOCK];
unsafe { _mm_storeu_si128(out.as_mut_ptr() as *mut __m128i, tag) };
out
}
#[inline]
#[target_feature(enable = "aes,pclmulqdq,ssse3")]
unsafe fn aes8_ghash8<const G: bool>(
rk: &[__m128i; 15],
rounds: usize,
ctr: &mut Counter,
gsrc: *const u8,
y: &mut __m128i,
h: &[__m128i; 8],
) -> [__m128i; 8] {
let mask = bswap();
let mut s = [_mm_setzero_si128(); 8];
for b in s.iter_mut() {
*b = _mm_xor_si128(ctr.next(), rk[0]);
}
let (mut lo, mut mid, mut hi) = (
_mm_setzero_si128(),
_mm_setzero_si128(),
_mm_setzero_si128(),
);
for j in 0..8 {
let k = rk[1 + j];
for b in s.iter_mut() {
*b = _mm_aesenc_si128(*b, k);
}
if G {
let raw = unsafe { _mm_loadu_si128(gsrc.add(j * BLOCK) as *const __m128i) };
let mut x = _mm_shuffle_epi8(raw, mask);
if j == 0 {
x = _mm_xor_si128(x, *y);
}
let (l, m, u) = product(x, h[j]);
lo = _mm_xor_si128(lo, l);
mid = _mm_xor_si128(mid, m);
hi = _mm_xor_si128(hi, u);
}
}
if G {
*y = reduce(lo, mid, hi);
}
for k in &rk[9..rounds] {
for b in s.iter_mut() {
*b = _mm_aesenc_si128(*b, *k);
}
}
for b in s.iter_mut() {
*b = _mm_aesenclast_si128(*b, rk[rounds]);
}
s
}
#[inline]
#[target_feature(enable = "pclmulqdq,ssse3")]
unsafe fn ghash8(src: *const u8, y: __m128i, h: &[__m128i; 8]) -> __m128i {
let mask = bswap();
let (mut lo, mut mid, mut hi) = (
_mm_setzero_si128(),
_mm_setzero_si128(),
_mm_setzero_si128(),
);
for (j, hj) in h.iter().enumerate() {
let raw = unsafe { _mm_loadu_si128(src.add(j * BLOCK) as *const __m128i) };
let mut x = _mm_shuffle_epi8(raw, mask);
if j == 0 {
x = _mm_xor_si128(x, y);
}
let (l, m, u) = product(x, *hj);
lo = _mm_xor_si128(lo, l);
mid = _mm_xor_si128(mid, m);
hi = _mm_xor_si128(hi, u);
}
reduce(lo, mid, hi)
}
#[inline]
#[target_feature(enable = "sse2")]
unsafe fn xor8(p: *mut u8, ks: &[__m128i; 8]) {
for (j, k) in ks.iter().enumerate() {
unsafe {
let q = p.add(j * BLOCK) as *mut __m128i;
_mm_storeu_si128(q, _mm_xor_si128(_mm_loadu_si128(q), *k));
}
}
}
#[target_feature(enable = "aes,pclmulqdq,ssse3")]
fn bulk_narrow(
keys: &Keys,
hk: &HashKey,
ctr: &mut Counter,
data: &mut [u8],
mut y: __m128i,
encrypting: bool,
) -> __m128i {
debug_assert_eq!(data.len() % NARROW, 0);
let (rk, rounds) = keys.enc_round_keys();
let mut h = [_mm_setzero_si128(); 8];
for (j, slot) in h.iter_mut().enumerate() {
*slot = hk.power(NPOW - 8 + j);
}
let groups = data.len() / NARROW;
let base = data.as_mut_ptr();
for i in 0..groups {
unsafe {
let p = base.add(i * NARROW);
let ks = if !encrypting {
aes8_ghash8::<true>(rk, rounds, ctr, p, &mut y, &h)
} else if i > 0 {
aes8_ghash8::<true>(rk, rounds, ctr, p.sub(NARROW), &mut y, &h)
} else {
aes8_ghash8::<false>(rk, rounds, ctr, p, &mut y, &h)
};
xor8(p, &ks);
}
}
if encrypting && groups > 0 {
y = unsafe { ghash8(base.add((groups - 1) * NARROW), y, &h) };
}
y
}
#[target_feature(enable = "aes,pclmulqdq,ssse3")]
fn run_narrow(
keys: &Keys,
hk: &HashKey,
j0: &[u8; BLOCK],
aad: &[u8],
data: &mut [u8],
encrypting: bool,
) -> [u8; BLOCK] {
let j0 = unsafe { _mm_loadu_si128(j0.as_ptr() as *const __m128i) };
let mut g = Pending::new();
g.push_padded(hk, aad);
let mut ctr = Counter::after(j0);
let data_len = data.len();
let whole = data_len - data_len % NARROW;
let (body, tail) = data.split_at_mut(whole);
if !body.is_empty() {
g.flush(hk);
g.y = bulk_narrow(keys, hk, &mut ctr, body, g.y, encrypting);
}
finish(
keys,
hk,
&mut g,
&mut ctr,
j0,
tail,
aad.len(),
data_len,
encrypting,
)
}
macro_rules! wide_op {
($(#[$doc:meta])* $name:ident, $tmpl:literal) => {
$(#[$doc])*
#[inline]
#[target_feature(enable = "avx2")]
fn $name(_: Wide, a: __m256i, b: __m256i) -> __m256i {
let r: __m256i;
unsafe {
asm!(
$tmpl,
r = lateout(ymm_reg) r,
a = in(ymm_reg) a,
b = in(ymm_reg) b,
options(pure, nomem, nostack, preserves_flags),
);
}
r
}
};
}
wide_op!(
aesenc2,
"vaesenc {r}, {a}, {b}"
);
wide_op!(
aesenclast2,
"vaesenclast {r}, {a}, {b}"
);
wide_op!(
clmul2_00,
"vpclmulqdq {r}, {a}, {b}, 0x00"
);
wide_op!(
clmul2_01,
"vpclmulqdq {r}, {a}, {b}, 0x01"
);
wide_op!(
clmul2_10,
"vpclmulqdq {r}, {a}, {b}, 0x10"
);
wide_op!(
clmul2_11,
"vpclmulqdq {r}, {a}, {b}, 0x11"
);
#[inline]
#[target_feature(enable = "avx2")]
fn bswap2() -> __m256i {
_mm256_set_m128i(bswap(), bswap())
}
#[inline]
#[target_feature(enable = "avx2")]
fn product2(w: Wide, a: __m256i, b: __m256i) -> (__m256i, __m256i, __m256i) {
(
clmul2_00(w, a, b),
_mm256_xor_si256(clmul2_10(w, a, b), clmul2_01(w, a, b)),
clmul2_11(w, a, b),
)
}
#[inline]
#[target_feature(enable = "avx2,pclmulqdq,ssse3")]
fn reduce2(lo: __m256i, mid: __m256i, hi: __m256i) -> __m128i {
reduce(fold2(lo), fold2(mid), fold2(hi))
}
#[inline]
#[target_feature(enable = "avx2")]
fn fold2(v: __m256i) -> __m128i {
_mm_xor_si128(_mm256_castsi256_si128(v), _mm256_extracti128_si256::<1>(v))
}
#[inline]
#[target_feature(enable = "avx2,aes,pclmulqdq,ssse3")]
#[allow(clippy::too_many_arguments)]
unsafe fn aes16_ghash16<const G: bool>(
w: Wide,
rk: &[__m256i; 15],
rounds: usize,
ctr: &mut Counter,
gsrc: *const u8,
y: &mut __m128i,
hk: &HashKey,
) -> [__m256i; 8] {
let swap = _mm256_set_m128i(ctr_swap(), ctr_swap());
let base = _mm256_add_epi32(
_mm256_set_m128i(ctr.0, ctr.0),
_mm256_set_epi32(1, 0, 0, 0, 0, 0, 0, 0),
);
let mut s = [_mm256_setzero_si256(); 8];
for (k, b) in s.iter_mut().enumerate() {
let step = (2 * k) as i32;
let c = _mm256_add_epi32(base, _mm256_set_epi32(step, 0, 0, 0, step, 0, 0, 0));
*b = _mm256_xor_si256(_mm256_shuffle_epi8(c, swap), rk[0]);
}
ctr.0 = _mm_add_epi32(ctr.0, _mm_set_epi32(16, 0, 0, 0));
let mask = bswap2();
let (mut lo, mut mid, mut hi) = (
_mm256_setzero_si256(),
_mm256_setzero_si256(),
_mm256_setzero_si256(),
);
for j in 0..8 {
let k = rk[1 + j];
for b in s.iter_mut() {
*b = aesenc2(w, *b, k);
}
if G {
let raw = unsafe { _mm256_loadu_si256(gsrc.add(j * 2 * BLOCK) as *const __m256i) };
let mut x = _mm256_shuffle_epi8(raw, mask);
if j == 0 {
x = _mm256_xor_si256(x, _mm256_set_m128i(_mm_setzero_si128(), *y));
}
let (l, m, u) = product2(w, x, hk.power_pair(NPOW - 16 + 2 * j));
lo = _mm256_xor_si256(lo, l);
mid = _mm256_xor_si256(mid, m);
hi = _mm256_xor_si256(hi, u);
}
}
if G {
*y = reduce2(lo, mid, hi);
}
for k in &rk[9..rounds] {
for b in s.iter_mut() {
*b = aesenc2(w, *b, *k);
}
}
for b in s.iter_mut() {
*b = aesenclast2(w, *b, rk[rounds]);
}
s
}
#[inline]
#[target_feature(enable = "avx2,pclmulqdq,ssse3")]
unsafe fn ghash16(w: Wide, src: *const u8, y: __m128i, hk: &HashKey) -> __m128i {
let mask = bswap2();
let (mut lo, mut mid, mut hi) = (
_mm256_setzero_si256(),
_mm256_setzero_si256(),
_mm256_setzero_si256(),
);
for j in 0..8 {
let raw = unsafe { _mm256_loadu_si256(src.add(j * 2 * BLOCK) as *const __m256i) };
let mut x = _mm256_shuffle_epi8(raw, mask);
if j == 0 {
x = _mm256_xor_si256(x, _mm256_set_m128i(_mm_setzero_si128(), y));
}
let (l, m, u) = product2(w, x, hk.power_pair(NPOW - 16 + 2 * j));
lo = _mm256_xor_si256(lo, l);
mid = _mm256_xor_si256(mid, m);
hi = _mm256_xor_si256(hi, u);
}
reduce2(lo, mid, hi)
}
#[inline]
#[target_feature(enable = "avx2")]
unsafe fn xor16(p: *mut u8, ks: &[__m256i; 8]) {
for (j, k) in ks.iter().enumerate() {
unsafe {
let q = p.add(j * 2 * BLOCK) as *mut __m256i;
_mm256_storeu_si256(q, _mm256_xor_si256(_mm256_loadu_si256(q), *k));
}
}
}
#[target_feature(enable = "avx2,aes,pclmulqdq,ssse3")]
fn bulk_wide(
w: Wide,
keys: &Keys,
hk: &HashKey,
ctr: &mut Counter,
data: &mut [u8],
mut y: __m128i,
encrypting: bool,
) -> __m128i {
debug_assert_eq!(data.len() % WIDE, 0);
let (rk1, rounds) = keys.enc_round_keys();
let mut rk = [_mm256_setzero_si256(); 15];
for (wide, narrow) in rk.iter_mut().zip(rk1.iter()).take(rounds + 1) {
*wide = _mm256_broadcastsi128_si256(*narrow);
}
let groups = data.len() / WIDE;
let base = data.as_mut_ptr();
for i in 0..groups {
unsafe {
let p = base.add(i * WIDE);
let ks = if !encrypting {
aes16_ghash16::<true>(w, &rk, rounds, ctr, p, &mut y, hk)
} else if i > 0 {
aes16_ghash16::<true>(w, &rk, rounds, ctr, p.sub(WIDE), &mut y, hk)
} else {
aes16_ghash16::<false>(w, &rk, rounds, ctr, p, &mut y, hk)
};
xor16(p, &ks);
}
}
if encrypting && groups > 0 {
y = unsafe { ghash16(w, base.add((groups - 1) * WIDE), y, hk) };
}
y
}
#[derive(Clone, Copy)]
enum Bulk {
Ymm(Wide),
Zmm(Wide512),
}
#[target_feature(enable = "avx2,aes,pclmulqdq,ssse3")]
fn run_wide(
bulk: Bulk,
keys: &Keys,
hk: &HashKey,
j0: &[u8; BLOCK],
aad: &[u8],
data: &mut [u8],
encrypting: bool,
) -> [u8; BLOCK] {
let j0 = unsafe { _mm_loadu_si128(j0.as_ptr() as *const __m128i) };
let mut g = Pending::new();
g.push_padded(hk, aad);
let mut ctr = Counter::after(j0);
let data_len = data.len();
let wide = data_len - data_len % WIDE;
let (body, rest) = data.split_at_mut(wide);
let narrow = rest.len() - rest.len() % NARROW;
let (mid, tail) = rest.split_at_mut(narrow);
if !body.is_empty() || !mid.is_empty() {
g.flush(hk);
}
if !body.is_empty() {
g.y = match bulk {
Bulk::Ymm(w) => bulk_wide(w, keys, hk, &mut ctr, body, g.y, encrypting),
Bulk::Zmm(w) => bulk_zmm(w, keys, hk, &mut ctr, body, g.y, encrypting),
};
}
if !mid.is_empty() {
g.y = bulk_narrow(keys, hk, &mut ctr, mid, g.y, encrypting);
}
finish(
keys,
hk,
&mut g,
&mut ctr,
j0,
tail,
aad.len(),
data_len,
encrypting,
)
}
#[repr(C, align(64))]
struct ZmmConsts([u8; 256]);
static ZMM_CONSTS: ZmmConsts = ZmmConsts({
let mut c = [0u8; 256];
let mut lane = 0;
while lane < 4 {
let mut i = 0;
while i < 16 {
c[lane * 16 + i] = (15 - i) as u8;
c[64 + lane * 16 + i] = if i < 12 { i as u8 } else { (27 - i) as u8 };
i += 1;
}
c[128 + lane * 16 + 12] = 4;
c[192 + lane * 16 + 12] = lane as u8;
lane += 1;
}
c
});
macro_rules! zmm_round {
($insn:literal, $addr:literal) => {
concat!(
"vbroadcasti32x4 zmm4, xmmword ptr [",
$addr,
"]\n",
$insn,
" zmm0, zmm0, zmm4\n",
$insn,
" zmm1, zmm1, zmm4\n",
$insn,
" zmm2, zmm2, zmm4\n",
$insn,
" zmm3, zmm3, zmm4\n",
)
};
}
macro_rules! zmm_aes {
() => {
concat!(
"vpshufb zmm0, zmm10, zmm12\n",
"vpaddd zmm10, zmm10, zmm11\n",
"vpshufb zmm1, zmm10, zmm12\n",
"vpaddd zmm10, zmm10, zmm11\n",
"vpshufb zmm2, zmm10, zmm12\n",
"vpaddd zmm10, zmm10, zmm11\n",
"vpshufb zmm3, zmm10, zmm12\n",
"vpaddd zmm10, zmm10, zmm11\n",
"vbroadcasti32x4 zmm4, xmmword ptr [{rk}]\n",
"vpxorq zmm0, zmm0, zmm4\n",
"vpxorq zmm1, zmm1, zmm4\n",
"vpxorq zmm2, zmm2, zmm4\n",
"vpxorq zmm3, zmm3, zmm4\n",
zmm_round!("vaesenc", "{rk} + 16"),
zmm_round!("vaesenc", "{rk} + 32"),
zmm_round!("vaesenc", "{rk} + 48"),
zmm_round!("vaesenc", "{rk} + 64"),
zmm_round!("vaesenc", "{rk} + 80"),
zmm_round!("vaesenc", "{rk} + 96"),
zmm_round!("vaesenc", "{rk} + 112"),
zmm_round!("vaesenc", "{rk} + 128"),
zmm_round!("vaesenc", "{rk} + 144"),
"cmp {rounds}, 10\n",
"je 3f\n",
zmm_round!("vaesenc", "{rk} + 160"),
zmm_round!("vaesenc", "{rk} + 176"),
"cmp {rounds}, 12\n",
"je 3f\n",
zmm_round!("vaesenc", "{rk} + 192"),
zmm_round!("vaesenc", "{rk} + 208"),
"3:\n",
zmm_round!("vaesenclast", "{rkl}"),
)
};
}
macro_rules! zmm_xor_store {
() => {
concat!(
"vpxorq zmm0, zmm0, zmmword ptr [{p}]\n",
"vpxorq zmm1, zmm1, zmmword ptr [{p} + 64]\n",
"vpxorq zmm2, zmm2, zmmword ptr [{p} + 128]\n",
"vpxorq zmm3, zmm3, zmmword ptr [{p} + 192]\n",
"vmovdqu64 zmmword ptr [{p}], zmm0\n",
"vmovdqu64 zmmword ptr [{p} + 64], zmm1\n",
"vmovdqu64 zmmword ptr [{p} + 128], zmm2\n",
"vmovdqu64 zmmword ptr [{p} + 192], zmm3\n",
)
};
}
macro_rules! zmm_load {
(reg $src:literal) => {
concat!("vpshufb zmm5, ", $src, ", zmm13\n")
};
(mem $off:literal) => {
concat!(
"vmovdqu64 zmm5, zmmword ptr [{p} + ",
$off,
"]\n",
"vpshufb zmm5, zmm5, zmm13\n",
)
};
}
macro_rules! zmm_ghash {
($l0:expr, $l1:expr, $l2:expr, $l3:expr) => {
concat!(
$l0,
"vpshufd zmm4, zmm5, 0x4e\n",
"vpxorq zmm4, zmm4, zmm5\n",
"vpclmulqdq zmm6, zmm5, zmmword ptr [{pw}], 0x00\n",
"vpclmulqdq zmm8, zmm5, zmmword ptr [{pw}], 0x11\n",
"vpclmulqdq zmm7, zmm4, zmmword ptr [{pk}], 0x00\n",
$l1,
zmm_mul_acc!("64"),
$l2,
zmm_mul_acc!("128"),
$l3,
zmm_mul_acc!("192"),
"vextracti64x4 ymm14, zmm6, 1\n",
"vpxor ymm6, ymm6, ymm14\n",
"vextracti128 xmm14, ymm6, 1\n",
"vpxor xmm6, xmm6, xmm14\n",
"vextracti64x4 ymm14, zmm7, 1\n",
"vpxor ymm7, ymm7, ymm14\n",
"vextracti128 xmm14, ymm7, 1\n",
"vpxor xmm7, xmm7, xmm14\n",
"vextracti64x4 ymm14, zmm8, 1\n",
"vpxor ymm8, ymm8, ymm14\n",
"vextracti128 xmm14, ymm8, 1\n",
"vpxor xmm8, xmm8, xmm14\n",
"vpshufd xmm4, xmm9, 0x4e\n",
"vpxor xmm4, xmm4, xmm9\n",
"vpclmulqdq xmm14, xmm9, xmmword ptr [{pw}], 0x00\n",
"vpclmulqdq xmm15, xmm9, xmmword ptr [{pw}], 0x11\n",
"vpclmulqdq xmm4, xmm4, xmmword ptr [{pk}], 0x00\n",
"vpxor xmm6, xmm6, xmm14\n",
"vpxor xmm8, xmm8, xmm15\n",
"vpxor xmm7, xmm7, xmm4\n",
"vpxor xmm7, xmm7, xmm6\n",
"vpxor xmm7, xmm7, xmm8\n",
"vpslldq xmm14, xmm7, 8\n",
"vpxor xmm6, xmm6, xmm14\n",
"vpsrldq xmm14, xmm7, 8\n",
"vpxor xmm8, xmm8, xmm14\n",
"vpsrld xmm14, xmm6, 31\n",
"vpsrld xmm15, xmm8, 31\n",
"vpslld xmm6, xmm6, 1\n",
"vpslld xmm8, xmm8, 1\n",
"vpslldq xmm7, xmm14, 4\n",
"vpor xmm6, xmm6, xmm7\n",
"vpslldq xmm7, xmm15, 4\n",
"vpor xmm8, xmm8, xmm7\n",
"vpsrldq xmm14, xmm14, 12\n",
"vpor xmm8, xmm8, xmm14\n",
"vpslld xmm14, xmm6, 31\n",
"vpslld xmm15, xmm6, 30\n",
"vpxor xmm14, xmm14, xmm15\n",
"vpslld xmm15, xmm6, 25\n",
"vpxor xmm14, xmm14, xmm15\n",
"vpsrldq xmm15, xmm14, 4\n",
"vpslldq xmm14, xmm14, 12\n",
"vpxor xmm6, xmm6, xmm14\n",
"vpsrld xmm14, xmm6, 1\n",
"vpxor xmm15, xmm15, xmm14\n",
"vpsrld xmm14, xmm6, 2\n",
"vpxor xmm15, xmm15, xmm14\n",
"vpsrld xmm14, xmm6, 7\n",
"vpxor xmm15, xmm15, xmm14\n",
"vpxor xmm6, xmm6, xmm15\n",
"vpxor xmm9, xmm8, xmm6\n",
)
};
}
macro_rules! zmm_mul_acc {
($off:literal) => {
concat!(
"vpshufd zmm4, zmm5, 0x4e\n",
"vpxorq zmm4, zmm4, zmm5\n",
"vpclmulqdq zmm14, zmm5, zmmword ptr [{pw} + ",
$off,
"], 0x00\n",
"vpclmulqdq zmm15, zmm5, zmmword ptr [{pw} + ",
$off,
"], 0x11\n",
"vpclmulqdq zmm4, zmm4, zmmword ptr [{pk} + ",
$off,
"], 0x00\n",
"vpxorq zmm6, zmm6, zmm14\n",
"vpxorq zmm8, zmm8, zmm15\n",
"vpxorq zmm7, zmm7, zmm4\n",
)
};
}
#[inline(never)]
#[allow(clippy::too_many_arguments)]
unsafe fn zmm_groups<const ENC: bool>(
p: *mut u8,
groups: usize,
rk: *const u8,
rk_last: *const u8,
rounds: usize,
pw: *const u8,
pk: *const u8,
state: *mut u8,
) {
debug_assert!(groups > 0);
unsafe {
if ENC {
asm!(
"vmovdqu64 zmm13, zmmword ptr [{c}]",
"vmovdqu64 zmm12, zmmword ptr [{c} + 64]",
"vmovdqu64 zmm11, zmmword ptr [{c} + 128]",
"vbroadcasti32x4 zmm10, xmmword ptr [{st} + 16]",
"vpaddd zmm10, zmm10, zmmword ptr [{c} + 192]",
"vmovdqu xmm9, xmmword ptr [{st}]",
"2:",
zmm_aes!(),
zmm_xor_store!(),
zmm_ghash!(
zmm_load!(reg "zmm0"),
zmm_load!(reg "zmm1"),
zmm_load!(reg "zmm2"),
zmm_load!(reg "zmm3")
),
"add {p}, 256",
"dec {n}",
"jnz 2b",
"vmovdqu xmmword ptr [{st}], xmm9",
"vmovdqu xmmword ptr [{st} + 16], xmm10",
"vzeroupper",
p = inout(reg) p => _,
n = inout(reg) groups => _,
rk = in(reg) rk,
rkl = in(reg) rk_last,
rounds = in(reg) rounds,
pw = in(reg) pw,
pk = in(reg) pk,
st = in(reg) state,
c = in(reg) ZMM_CONSTS.0.as_ptr(),
out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
options(nostack),
);
} else {
asm!(
"vmovdqu64 zmm13, zmmword ptr [{c}]",
"vmovdqu64 zmm12, zmmword ptr [{c} + 64]",
"vmovdqu64 zmm11, zmmword ptr [{c} + 128]",
"vbroadcasti32x4 zmm10, xmmword ptr [{st} + 16]",
"vpaddd zmm10, zmm10, zmmword ptr [{c} + 192]",
"vmovdqu xmm9, xmmword ptr [{st}]",
"2:",
zmm_ghash!(
zmm_load!(mem "0"),
zmm_load!(mem "64"),
zmm_load!(mem "128"),
zmm_load!(mem "192")
),
zmm_aes!(),
zmm_xor_store!(),
"add {p}, 256",
"dec {n}",
"jnz 2b",
"vmovdqu xmmword ptr [{st}], xmm9",
"vmovdqu xmmword ptr [{st} + 16], xmm10",
"vzeroupper",
p = inout(reg) p => _,
n = inout(reg) groups => _,
rk = in(reg) rk,
rkl = in(reg) rk_last,
rounds = in(reg) rounds,
pw = in(reg) pw,
pk = in(reg) pk,
st = in(reg) state,
c = in(reg) ZMM_CONSTS.0.as_ptr(),
out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
options(nostack),
);
}
}
}
macro_rules! z32_ctr {
() => {
concat!(
"vbroadcasti32x4 zmm8, xmmword ptr [{st} + 16]\n",
"vpaddd zmm8, zmm8, zmmword ptr [{c} + 192]\n",
"vpshufb zmm0, zmm8, zmmword ptr [{c} + 64]\n",
"vpaddd zmm8, zmm8, zmmword ptr [{c} + 128]\n",
"vpshufb zmm1, zmm8, zmmword ptr [{c} + 64]\n",
"vpaddd zmm8, zmm8, zmmword ptr [{c} + 128]\n",
"vpshufb zmm2, zmm8, zmmword ptr [{c} + 64]\n",
"vpaddd zmm8, zmm8, zmmword ptr [{c} + 128]\n",
"vpshufb zmm3, zmm8, zmmword ptr [{c} + 64]\n",
"vpaddd zmm8, zmm8, zmmword ptr [{c} + 128]\n",
"vpshufb zmm4, zmm8, zmmword ptr [{c} + 64]\n",
"vpaddd zmm8, zmm8, zmmword ptr [{c} + 128]\n",
"vpshufb zmm5, zmm8, zmmword ptr [{c} + 64]\n",
"vpaddd zmm8, zmm8, zmmword ptr [{c} + 128]\n",
"vpshufb zmm6, zmm8, zmmword ptr [{c} + 64]\n",
"vpaddd zmm8, zmm8, zmmword ptr [{c} + 128]\n",
"vpshufb zmm7, zmm8, zmmword ptr [{c} + 64]\n",
"vpaddd zmm8, zmm8, zmmword ptr [{c} + 128]\n",
"vmovdqu xmmword ptr [{st} + 16], xmm8\n",
"vbroadcasti32x4 zmm8, xmmword ptr [{rk}]\n",
"vpxorq zmm0, zmm0, zmm8\n",
"vpxorq zmm1, zmm1, zmm8\n",
"vpxorq zmm2, zmm2, zmm8\n",
"vpxorq zmm3, zmm3, zmm8\n",
"vpxorq zmm4, zmm4, zmm8\n",
"vpxorq zmm5, zmm5, zmm8\n",
"vpxorq zmm6, zmm6, zmm8\n",
"vpxorq zmm7, zmm7, zmm8\n",
)
};
}
macro_rules! z32_round {
($insn:literal, $addr:literal) => {
concat!(
"vbroadcasti32x4 zmm8, xmmword ptr [",
$addr,
"]\n",
$insn,
" zmm0, zmm0, zmm8\n",
$insn,
" zmm1, zmm1, zmm8\n",
$insn,
" zmm2, zmm2, zmm8\n",
$insn,
" zmm3, zmm3, zmm8\n",
$insn,
" zmm4, zmm4, zmm8\n",
$insn,
" zmm5, zmm5, zmm8\n",
$insn,
" zmm6, zmm6, zmm8\n",
$insn,
" zmm7, zmm7, zmm8\n",
)
};
}
macro_rules! z32_last_rounds {
() => {
concat!(
"cmp {rounds}, 10\n",
"je 3f\n",
z32_round!("vaesenc", "{rk} + 160"),
z32_round!("vaesenc", "{rk} + 176"),
"cmp {rounds}, 12\n",
"je 3f\n",
z32_round!("vaesenc", "{rk} + 192"),
z32_round!("vaesenc", "{rk} + 208"),
"3:\n",
z32_round!("vaesenclast", "{rkl}"),
)
};
}
macro_rules! z32_xor_store {
() => {
concat!(
"vpxorq zmm0, zmm0, zmmword ptr [{p}]\n",
"vpxorq zmm1, zmm1, zmmword ptr [{p} + 64]\n",
"vpxorq zmm2, zmm2, zmmword ptr [{p} + 128]\n",
"vpxorq zmm3, zmm3, zmmword ptr [{p} + 192]\n",
"vpxorq zmm4, zmm4, zmmword ptr [{p} + 256]\n",
"vpxorq zmm5, zmm5, zmmword ptr [{p} + 320]\n",
"vpxorq zmm6, zmm6, zmmword ptr [{p} + 384]\n",
"vpxorq zmm7, zmm7, zmmword ptr [{p} + 448]\n",
"vmovdqu64 zmmword ptr [{p}], zmm0\n",
"vmovdqu64 zmmword ptr [{p} + 64], zmm1\n",
"vmovdqu64 zmmword ptr [{p} + 128], zmm2\n",
"vmovdqu64 zmmword ptr [{p} + 192], zmm3\n",
"vmovdqu64 zmmword ptr [{p} + 256], zmm4\n",
"vmovdqu64 zmmword ptr [{p} + 320], zmm5\n",
"vmovdqu64 zmmword ptr [{p} + 384], zmm6\n",
"vmovdqu64 zmmword ptr [{p} + 448], zmm7\n",
)
};
}
macro_rules! z32_gstep {
(first, $src:literal) => {
concat!(
"vmovdqu64 zmm13, zmmword ptr [",
$src,
"]\n",
"vpshufb zmm13, zmm13, zmmword ptr [{c}]\n",
"vpshufd zmm14, zmm13, 0x4e\n",
"vpxorq zmm14, zmm14, zmm13\n",
"vpclmulqdq zmm10, zmm13, zmmword ptr [{pw}], 0x00\n",
"vpclmulqdq zmm12, zmm13, zmmword ptr [{pw}], 0x11\n",
"vpclmulqdq zmm11, zmm14, zmmword ptr [{pk}], 0x00\n",
)
};
($src:literal, $off:literal) => {
concat!(
"vmovdqu64 zmm13, zmmword ptr [",
$src,
" + ",
$off,
"]\n",
"vpshufb zmm13, zmm13, zmmword ptr [{c}]\n",
"vpshufd zmm14, zmm13, 0x4e\n",
"vpxorq zmm14, zmm14, zmm13\n",
"vpclmulqdq zmm15, zmm13, zmmword ptr [{pw} + ",
$off,
"], 0x00\n",
"vpxorq zmm10, zmm10, zmm15\n",
"vpclmulqdq zmm15, zmm13, zmmword ptr [{pw} + ",
$off,
"], 0x11\n",
"vpxorq zmm12, zmm12, zmm15\n",
"vpclmulqdq zmm15, zmm14, zmmword ptr [{pk} + ",
$off,
"], 0x00\n",
"vpxorq zmm11, zmm11, zmm15\n",
)
};
}
macro_rules! z32_reduce {
() => {
concat!(
"vextracti64x4 ymm13, zmm10, 1\n",
"vpxor ymm10, ymm10, ymm13\n",
"vextracti128 xmm13, ymm10, 1\n",
"vpxor xmm10, xmm10, xmm13\n",
"vextracti64x4 ymm13, zmm11, 1\n",
"vpxor ymm11, ymm11, ymm13\n",
"vextracti128 xmm13, ymm11, 1\n",
"vpxor xmm11, xmm11, xmm13\n",
"vextracti64x4 ymm13, zmm12, 1\n",
"vpxor ymm12, ymm12, ymm13\n",
"vextracti128 xmm13, ymm12, 1\n",
"vpxor xmm12, xmm12, xmm13\n",
"vpshufd xmm13, xmm9, 0x4e\n",
"vpxor xmm13, xmm13, xmm9\n",
"vpclmulqdq xmm14, xmm9, xmmword ptr [{pw}], 0x00\n",
"vpclmulqdq xmm15, xmm9, xmmword ptr [{pw}], 0x11\n",
"vpclmulqdq xmm13, xmm13, xmmword ptr [{pk}], 0x00\n",
"vpxor xmm10, xmm10, xmm14\n",
"vpxor xmm12, xmm12, xmm15\n",
"vpxor xmm11, xmm11, xmm13\n",
"vpxor xmm11, xmm11, xmm10\n",
"vpxor xmm11, xmm11, xmm12\n",
"vpslldq xmm14, xmm11, 8\n",
"vpxor xmm10, xmm10, xmm14\n",
"vpsrldq xmm14, xmm11, 8\n",
"vpxor xmm12, xmm12, xmm14\n",
"vpsrld xmm14, xmm10, 31\n",
"vpsrld xmm15, xmm12, 31\n",
"vpslld xmm10, xmm10, 1\n",
"vpslld xmm12, xmm12, 1\n",
"vpslldq xmm11, xmm14, 4\n",
"vpor xmm10, xmm10, xmm11\n",
"vpslldq xmm11, xmm15, 4\n",
"vpor xmm12, xmm12, xmm11\n",
"vpsrldq xmm14, xmm14, 12\n",
"vpor xmm12, xmm12, xmm14\n",
"vpslld xmm14, xmm10, 31\n",
"vpslld xmm15, xmm10, 30\n",
"vpxor xmm14, xmm14, xmm15\n",
"vpslld xmm15, xmm10, 25\n",
"vpxor xmm14, xmm14, xmm15\n",
"vpsrldq xmm15, xmm14, 4\n",
"vpslldq xmm14, xmm14, 12\n",
"vpxor xmm10, xmm10, xmm14\n",
"vpsrld xmm14, xmm10, 1\n",
"vpxor xmm15, xmm15, xmm14\n",
"vpsrld xmm14, xmm10, 2\n",
"vpxor xmm15, xmm15, xmm14\n",
"vpsrld xmm14, xmm10, 7\n",
"vpxor xmm15, xmm15, xmm14\n",
"vpxor xmm10, xmm10, xmm15\n",
"vpxor xmm9, xmm12, xmm10\n",
)
};
}
macro_rules! z32_stitched {
($src:literal) => {
concat!(
z32_ctr!(),
z32_round!("vaesenc", "{rk} + 16"),
z32_gstep!(first, $src),
z32_round!("vaesenc", "{rk} + 32"),
z32_gstep!($src, "64"),
z32_round!("vaesenc", "{rk} + 48"),
z32_gstep!($src, "128"),
z32_round!("vaesenc", "{rk} + 64"),
z32_gstep!($src, "192"),
z32_round!("vaesenc", "{rk} + 80"),
z32_gstep!($src, "256"),
z32_round!("vaesenc", "{rk} + 96"),
z32_gstep!($src, "320"),
z32_round!("vaesenc", "{rk} + 112"),
z32_gstep!($src, "384"),
z32_round!("vaesenc", "{rk} + 128"),
z32_gstep!($src, "448"),
z32_round!("vaesenc", "{rk} + 144"),
z32_reduce!(),
z32_last_rounds!(),
z32_xor_store!(),
)
};
}
macro_rules! z32_aes_only {
() => {
concat!(
z32_ctr!(),
z32_round!("vaesenc", "{rk} + 16"),
z32_round!("vaesenc", "{rk} + 32"),
z32_round!("vaesenc", "{rk} + 48"),
z32_round!("vaesenc", "{rk} + 64"),
z32_round!("vaesenc", "{rk} + 80"),
z32_round!("vaesenc", "{rk} + 96"),
z32_round!("vaesenc", "{rk} + 112"),
z32_round!("vaesenc", "{rk} + 128"),
z32_round!("vaesenc", "{rk} + 144"),
z32_last_rounds!(),
z32_xor_store!(),
)
};
}
macro_rules! z32_ghash_only {
($src:literal) => {
concat!(
z32_gstep!(first, $src),
z32_gstep!($src, "64"),
z32_gstep!($src, "128"),
z32_gstep!($src, "192"),
z32_gstep!($src, "256"),
z32_gstep!($src, "320"),
z32_gstep!($src, "384"),
z32_gstep!($src, "448"),
z32_reduce!(),
)
};
}
#[inline(never)]
#[allow(clippy::too_many_arguments)]
unsafe fn zmm32_groups<const ENC: bool>(
p: *mut u8,
groups: usize,
rk: *const u8,
rk_last: *const u8,
rounds: usize,
pw: *const u8,
pk: *const u8,
state: *mut u8,
) {
debug_assert!(groups > 0);
unsafe {
if ENC {
asm!(
"vmovdqu xmm9, xmmword ptr [{st}]",
z32_aes_only!(),
"add {p}, 512",
"dec {n}",
"jz 4f",
"2:",
z32_stitched!("{p} - 512"),
"add {p}, 512",
"dec {n}",
"jnz 2b",
"4:",
z32_ghash_only!("{p} - 512"),
"vmovdqu xmmword ptr [{st}], xmm9",
"vzeroupper",
p = inout(reg) p => _,
n = inout(reg) groups => _,
rk = in(reg) rk,
rkl = in(reg) rk_last,
rounds = in(reg) rounds,
pw = in(reg) pw,
pk = in(reg) pk,
st = in(reg) state,
c = in(reg) ZMM_CONSTS.0.as_ptr(),
out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
options(nostack),
);
} else {
asm!(
"vmovdqu xmm9, xmmword ptr [{st}]",
"2:",
z32_stitched!("{p}"),
"add {p}, 512",
"dec {n}",
"jnz 2b",
"vmovdqu xmmword ptr [{st}], xmm9",
"vzeroupper",
p = inout(reg) p => _,
n = inout(reg) groups => _,
rk = in(reg) rk,
rkl = in(reg) rk_last,
rounds = in(reg) rounds,
pw = in(reg) pw,
pk = in(reg) pk,
st = in(reg) state,
c = in(reg) ZMM_CONSTS.0.as_ptr(),
out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
options(nostack),
);
}
}
}
#[target_feature(enable = "sse2")]
fn bulk_zmm(
_w: Wide512,
keys: &Keys,
hk: &HashKey,
ctr: &mut Counter,
data: &mut [u8],
y: __m128i,
encrypting: bool,
) -> __m128i {
debug_assert_eq!(data.len() % WIDE, 0);
if data.is_empty() {
return y;
}
let (rk, rounds) = keys.enc_round_keys();
let mut state = [0u8; 32];
unsafe {
_mm_storeu_si128(state.as_mut_ptr() as *mut __m128i, y);
_mm_storeu_si128(state.as_mut_ptr().add(BLOCK) as *mut __m128i, ctr.0);
}
let rk_ptr = rk.as_ptr() as *const u8;
let rk_last = rk[rounds..].as_ptr() as *const u8;
let st = state.as_mut_ptr();
let big = data.len() / WIDE32;
let (head, rest) = data.split_at_mut(big * WIDE32);
if big > 0 {
let pw = hk.powers.as_ptr() as *const u8;
let pk = hk.kara.as_ptr() as *const u8;
unsafe {
if encrypting {
zmm32_groups::<true>(head.as_mut_ptr(), big, rk_ptr, rk_last, rounds, pw, pk, st);
} else {
zmm32_groups::<false>(head.as_mut_ptr(), big, rk_ptr, rk_last, rounds, pw, pk, st);
}
}
}
let small = rest.len() / WIDE;
if small > 0 {
let pw = hk.powers[NPOW - 16..].as_ptr() as *const u8;
let pk = hk.kara[NPOW - 16..].as_ptr() as *const u8;
unsafe {
if encrypting {
zmm_groups::<true>(
rest.as_mut_ptr(),
small,
rk_ptr,
rk_last,
rounds,
pw,
pk,
st,
);
} else {
zmm_groups::<false>(
rest.as_mut_ptr(),
small,
rk_ptr,
rk_last,
rounds,
pw,
pk,
st,
);
}
}
}
let (y, c) = unsafe {
(
_mm_loadu_si128(state.as_ptr() as *const __m128i),
_mm_loadu_si128(state.as_ptr().add(BLOCK) as *const __m128i),
)
};
state.zeroize();
ctr.0 = c;
y
}