pub(crate) use details::Backend;
mod details;
mod scalar;
pub(crate) fn scalar() -> Backend {
Backend::new(scalar::fill_buf)
}
macro_rules! arch_backends {
($(#[cfg($cond:meta)] mod $name:ident;)+) => {
$(
#[cfg($cond)]
pub(crate) mod $name;
#[cfg(not($cond))]
pub(crate) mod $name {
pub(crate) fn detect() -> Option<crate::Backend> {
None
}
}
)+
};
}
arch_backends! {
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
mod avx2;
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
mod sse2;
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
mod neon;
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
mod simd128;
}
pub(crate) fn detect_best() -> Backend {
avx2::detect()
.or_else(sse2::detect)
.or_else(neon::detect)
.or_else(simd128::detect)
.unwrap_or_else(scalar)
}
fn init_state<T: Copy>(ctr: T, key: &[u32; 8], splat: impl Fn(u32) -> T) -> [T; 16] {
const C0: u32 = u32::from_le_bytes(*b"expa");
const C1: u32 = u32::from_le_bytes(*b"nd 3");
const C2: u32 = u32::from_le_bytes(*b"2-by");
const C3: u32 = u32::from_le_bytes(*b"te k");
let [k0, k1, k2, k3, k4, k5, k6, k7] = *key;
#[rustfmt::skip]
let x = [
splat(C0), splat(C1), splat(C2), splat(C3),
splat(k0), splat(k1), splat(k2), splat(k3),
splat(k4), splat(k5), splat(k6), splat(k7),
ctr, splat(0), splat(0), splat(0),
];
x
}
#[inline]
fn eight_rounds<T: Copy>(x: &mut [T; 16], qr: impl Fn([T; 4]) -> [T; 4]) {
const ROUNDS: u32 = 8;
for _ in (0..ROUNDS).step_by(2) {
[x[0], x[4], x[8], x[12]] = qr([x[0], x[4], x[8], x[12]]);
[x[1], x[5], x[9], x[13]] = qr([x[1], x[5], x[9], x[13]]);
[x[2], x[6], x[10], x[14]] = qr([x[2], x[6], x[10], x[14]]);
[x[3], x[7], x[11], x[15]] = qr([x[3], x[7], x[11], x[15]]);
[x[0], x[5], x[10], x[15]] = qr([x[0], x[5], x[10], x[15]]);
[x[1], x[6], x[11], x[12]] = qr([x[1], x[6], x[11], x[12]]);
[x[2], x[7], x[8], x[13]] = qr([x[2], x[7], x[8], x[13]]);
[x[3], x[4], x[9], x[14]] = qr([x[3], x[4], x[9], x[14]]);
}
}