pub(crate) mod tower;
#[allow(unused_imports)]
pub(crate) use tower::gf16;
pub(crate) mod gf1;
pub(crate) mod gf8;
pub(crate) mod goldilocks;
pub(crate) mod mersenne31;
pub(crate) mod prime;
pub(crate) mod quad_mersenne31;
pub(crate) mod scalar;
pub(crate) mod tables;
#[cfg(all(feature = "simd", target_arch = "aarch64"))]
pub(crate) mod aarch64;
#[cfg(all(feature = "simd", target_arch = "wasm32"))]
pub(crate) mod wasm32;
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
pub(crate) mod x86;
#[cfg(all(
feature = "simd",
any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "wasm32"
)
))]
pub(crate) mod matrix_provider;
pub(crate) use byte_ops::xor;
#[allow(unused_imports)]
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
pub(crate) use matrix_provider::FlatMatrix;
#[cfg(all(
feature = "simd",
any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "wasm32"
)
))]
pub(crate) use matrix_provider::Matrix;
#[cfg(test)]
mod tests;
use crate::field::{FieldBuffer, PrimeIdentity};
#[cfg(all(
feature = "simd",
any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "wasm32"
)
))]
use archmage::SimdToken;
#[cfg(feature = "simd")]
use simdispatch::Selection;
mod private {
pub trait Sealed {}
}
impl<R: crate::kernel::tables::Gf8Data> private::Sealed for crate::field::Binary<8, R> {}
impl<S: crate::field::binary::tower::TowerSpec> private::Sealed
for crate::field::Binary<16, crate::field::binary::tower::Tower<S>>
where
S::Base: crate::field::binary::BinaryDegree<8>,
{
}
impl<S: crate::field::binary::tower::TowerSpec> private::Sealed
for crate::field::Binary<32, crate::field::binary::tower::Tower<S>>
where
S::Base: crate::field::binary::BinaryDegree<16>,
{
}
impl<S: crate::field::binary::tower::TowerSpec> private::Sealed
for crate::field::Binary<64, crate::field::binary::tower::Tower<S>>
where
S::Base: crate::field::binary::BinaryDegree<32>,
{
}
impl private::Sealed for crate::field::mersenne31::Mersenne31 {}
impl private::Sealed for crate::field::goldilocks::Goldilocks {}
impl private::Sealed for crate::field::quad_mersenne31::QuadMersenne31 {}
pub use simdispatch::{Backend, ParseBackendError};
#[cfg(not(feature = "simd512"))]
pub const FGF_TIERS: &[Backend] = &[
Backend::V3GfniCrypto,
Backend::V3,
Backend::V2,
Backend::NeonAes,
Backend::Neon,
Backend::Wasm128,
Backend::Scalar,
];
#[cfg(feature = "simd512")]
pub const FGF_TIERS: &[Backend] = &[
Backend::V4x,
Backend::V3GfniCrypto,
Backend::V3,
Backend::V2,
Backend::NeonAes,
Backend::Neon,
Backend::Wasm128,
Backend::Scalar,
];
pub trait KernelBackend {
fn has_native_mul(self) -> bool;
fn has_blocked_rows(self) -> bool;
}
impl KernelBackend for Backend {
#[inline]
fn has_native_mul(self) -> bool {
matches!(self, Backend::V4x | Backend::V3GfniCrypto)
}
#[inline]
fn has_blocked_rows(self) -> bool {
matches!(
self,
Backend::V4x | Backend::V3GfniCrypto | Backend::Neon | Backend::NeonAes
)
}
}
#[inline]
#[must_use]
pub fn backend() -> Backend {
#[cfg(feature = "simd")]
{
BACKEND.backend
}
#[cfg(not(feature = "simd"))]
{
Backend::Scalar
}
}
#[cfg(feature = "simd")]
static BACKEND: std::sync::LazyLock<ResolvedBackend> =
std::sync::LazyLock::new(ResolvedBackend::new);
#[cfg(feature = "simd")]
struct ResolvedBackend {
backend: Backend,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
x86: X86Proof,
#[cfg(target_arch = "aarch64")]
neon: NeonProof,
#[cfg(target_arch = "wasm32")]
wasm128: Option<archmage::Wasm128Token>,
}
#[cfg(feature = "simd")]
impl ResolvedBackend {
fn new() -> Self {
let backend = Selection::new("SIMD_BACKEND").supports(FGF_TIERS).resolve();
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
let x86 = match backend {
#[cfg(feature = "simd512")]
Backend::V4x => X86Proof::V4x(
archmage::X64V4xToken::summon()
.expect("selected x86 V4x backend must have its capability token"),
),
Backend::V3GfniCrypto => X86Proof::V3GfniCrypto(
archmage::X64V3GfniCryptoToken::summon()
.expect("selected x86 GFNI backend must have its capability token"),
),
Backend::V3 => X86Proof::V3(
archmage::X64V3Token::summon()
.expect("selected x86 V3 backend must have its capability token"),
),
Backend::V2 => X86Proof::V2(
archmage::X64V2Token::summon()
.expect("selected x86 V2 backend must have its capability token"),
),
_ => X86Proof::Scalar,
};
#[cfg(target_arch = "aarch64")]
let neon = match backend {
Backend::NeonAes => NeonProof::NeonAes(
archmage::NeonAesToken::summon()
.expect("selected NEON-AES backend must have its capability token"),
),
Backend::Neon => NeonProof::Neon(
archmage::NeonToken::summon()
.expect("selected NEON backend must have its capability token"),
),
_ => NeonProof::Scalar,
};
#[cfg(target_arch = "wasm32")]
let wasm128 = match backend {
Backend::Wasm128 => Some(
archmage::Wasm128Token::summon()
.expect("selected wasm128 backend must have its capability token"),
),
_ => None,
};
Self {
backend,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
x86,
#[cfg(target_arch = "aarch64")]
neon,
#[cfg(target_arch = "wasm32")]
wasm128,
}
}
}
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
#[derive(Clone, Copy)]
pub(crate) enum X86Proof {
#[cfg(feature = "simd512")]
V4x(archmage::X64V4xToken),
V3GfniCrypto(archmage::X64V3GfniCryptoToken),
V3(archmage::X64V3Token),
V2(archmage::X64V2Token),
Scalar,
}
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
#[inline]
pub(crate) fn x86_proof() -> X86Proof {
BACKEND.x86
}
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
#[inline]
pub(crate) fn x86_v3_gfni_token() -> archmage::X64V3GfniCryptoToken {
match x86_proof() {
#[cfg(feature = "simd512")]
X86Proof::V4x(token) => token.v3_gfni_crypto(),
X86Proof::V3GfniCrypto(token) => token,
_ => unreachable!("GFNI kernel reached without the selected GFNI proof"),
}
}
#[cfg(all(feature = "simd512", any(target_arch = "x86", target_arch = "x86_64")))]
#[inline]
pub(crate) fn x86_v4x_token() -> archmage::X64V4xToken {
match x86_proof() {
X86Proof::V4x(token) => token,
_ => unreachable!("AVX-512 kernel reached without the selected V4x proof"),
}
}
#[cfg(all(feature = "simd512", any(target_arch = "x86", target_arch = "x86_64")))]
#[inline]
pub(crate) fn x86_v4_token() -> archmage::X64V4Token {
x86_v4x_token().v4()
}
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
#[inline]
pub(crate) fn x86_v3_token() -> archmage::X64V3Token {
match x86_proof() {
#[cfg(feature = "simd512")]
X86Proof::V4x(token) => token.v3(),
X86Proof::V3GfniCrypto(token) => token.v3(),
X86Proof::V3(token) => token,
_ => unreachable!("V3 kernel reached without a selected V3 proof"),
}
}
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
#[inline]
pub(crate) fn x86_v2_token() -> archmage::X64V2Token {
match x86_proof() {
#[cfg(feature = "simd512")]
X86Proof::V4x(token) => token.v3().v2(),
X86Proof::V3GfniCrypto(token) => token.v3().v2(),
X86Proof::V3(token) => token.v2(),
X86Proof::V2(token) => token,
X86Proof::Scalar => unreachable!("V2 kernel reached without a selected V2 proof"),
}
}
#[cfg(all(feature = "simd", target_arch = "aarch64"))]
#[derive(Clone, Copy)]
pub(crate) enum NeonProof {
Neon(archmage::NeonToken),
NeonAes(archmage::NeonAesToken),
Scalar,
}
#[cfg(all(feature = "simd", target_arch = "aarch64"))]
#[inline]
pub(crate) fn neon_proof() -> NeonProof {
BACKEND.neon
}
#[cfg(all(feature = "simd", target_arch = "aarch64"))]
#[inline]
pub(crate) fn neon_token() -> archmage::NeonToken {
match neon_proof() {
NeonProof::NeonAes(token) => token.neon(),
NeonProof::Neon(token) => token,
NeonProof::Scalar => unreachable!("NEON kernel reached without a selected NEON proof"),
}
}
#[cfg(all(feature = "simd", target_arch = "aarch64"))]
#[inline]
pub(crate) fn neon_aes_token() -> archmage::NeonAesToken {
match neon_proof() {
NeonProof::NeonAes(token) => token,
_ => unreachable!("PMULL kernel reached without a selected NEON-AES proof"),
}
}
#[cfg(all(feature = "simd", target_arch = "wasm32"))]
#[inline]
pub(crate) fn wasm128_token() -> archmage::Wasm128Token {
BACKEND
.wasm128
.expect("Wasm kernel reached without a selected simd128 proof")
}
#[inline]
#[must_use]
pub fn backend_for<F: FieldKernels>() -> Backend {
F::backend()
}
#[inline]
#[must_use]
pub fn has_vector_elementwise<F: FieldKernels>() -> bool {
F::has_vector_elementwise()
}
#[inline]
#[must_use]
pub fn vector_elementwise_min_bytes<F: FieldKernels>() -> usize {
F::vector_elementwise_min_bytes()
}
#[allow(private_bounds)]
pub trait FieldKernels: FieldBuffer + private::Sealed + KernelDispatch {
#[inline]
#[must_use]
fn backend() -> Backend {
Backend::Scalar
}
#[inline]
#[must_use]
fn has_vector_elementwise() -> bool {
false
}
#[inline]
#[must_use]
fn vector_elementwise_min_bytes() -> usize {
0
}
}
pub(crate) trait KernelDispatch: FieldBuffer {
type Prepared: Clone + Send + Sync + core::fmt::Debug;
fn prepare(_proof: RawDispatch, coeff: crate::field::Elem<Self>) -> Self::Prepared;
fn prepared_coeff(_proof: RawDispatch, prepared: &Self::Prepared) -> crate::field::Elem<Self>;
fn add_assign(_proof: RawDispatch, dst: &mut [u8], src: &[u8]);
fn add_gather_offsets(_proof: RawDispatch, region: &[u8], dst: &mut [u8], offsets: &[u32]) {
let live = dst.len();
for &start in offsets {
Self::add_assign(
RawDispatch,
dst,
®ion[start as usize..start as usize + live],
);
}
}
fn sub_assign(_proof: RawDispatch, dst: &mut [u8], src: &[u8]);
fn add_assign_rows(_proof: RawDispatch, dst: &mut [u8], src: &[u8], _row_len: usize) {
Self::add_assign(RawDispatch, dst, src);
}
fn mul_add(_proof: RawDispatch, dst: &mut [u8], coeff: &Self::Prepared, src: &[u8]);
fn mul_into(_proof: RawDispatch, dst: &mut [u8], coeff: &Self::Prepared, src: &[u8]) {
dst.copy_from_slice(src);
Self::mul_assign(RawDispatch, dst, coeff);
}
fn mul_assign(_proof: RawDispatch, dst: &mut [u8], coeff: &Self::Prepared);
fn mul_add_scatter(
_proof: RawDispatch,
rows: &mut [u8],
row_len: usize,
coeffs: &[crate::field::Elem<Self>],
src: &[u8],
);
fn mul_add_gather(
_proof: RawDispatch,
dst: &mut [u8],
coeffs: &[crate::field::Elem<Self>],
srcs: &[&[u8]],
);
fn mul_into_gather(
_proof: RawDispatch,
dst: &mut [u8],
coeffs: &[crate::field::Elem<Self>],
srcs: &[&[u8]],
) {
let mut pairs = coeffs.iter().copied().zip(srcs.iter().copied());
let Some((first, src)) = pairs.next() else {
dst.fill(0);
return;
};
Self::mul_into(RawDispatch, dst, &Self::prepare(RawDispatch, first), src);
for (coeff, src) in pairs {
Self::mul_add(RawDispatch, dst, &Self::prepare(RawDispatch, coeff), src);
}
}
fn mul_add_matrix(
_proof: RawDispatch,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &[(&[crate::field::Elem<Self>], &[u8])],
);
#[cfg(feature = "alloc")]
fn mul_add_scatter_with(
_proof: RawDispatch,
rows: &mut [u8],
row_len: usize,
coeffs: &[Self::Prepared],
src: &[u8],
) {
for (row, coeff) in rows.chunks_exact_mut(row_len).zip(coeffs) {
Self::mul_add(RawDispatch, row, coeff, src);
}
}
#[cfg(feature = "alloc")]
fn mul_add_scatter_plan(
_proof: RawDispatch,
rows: &mut [u8],
row_len: usize,
_values: &[crate::field::Elem<Self>],
coeffs: &[Self::Prepared],
src: &[u8],
) {
Self::mul_add_scatter_with(RawDispatch, rows, row_len, coeffs, src);
}
#[cfg(feature = "alloc")]
fn mul_add_gather_with(
_proof: RawDispatch,
dst: &mut [u8],
coeffs: &[Self::Prepared],
srcs: &[&[u8]],
) {
for (coeff, &src) in coeffs.iter().zip(srcs) {
Self::mul_add(RawDispatch, dst, coeff, src);
}
}
#[cfg(feature = "alloc")]
fn mul_add_gather_plan(
_proof: RawDispatch,
dst: &mut [u8],
_values: &[crate::field::Elem<Self>],
coeffs: &[Self::Prepared],
srcs: &[&[u8]],
) {
Self::mul_add_gather_with(RawDispatch, dst, coeffs, srcs);
}
#[cfg(any(feature = "alloc", test))]
fn mul_into_gather_with(
_proof: RawDispatch,
dst: &mut [u8],
coeffs: &[Self::Prepared],
srcs: &[&[u8]],
) {
let mut pairs = coeffs.iter().zip(srcs.iter().copied());
let Some((first, src)) = pairs.next() else {
dst.fill(0);
return;
};
Self::mul_into(RawDispatch, dst, first, src);
for (coeff, src) in pairs {
Self::mul_add(RawDispatch, dst, coeff, src);
}
}
#[cfg(feature = "alloc")]
fn mul_into_gather_plan(
_proof: RawDispatch,
dst: &mut [u8],
_values: &[crate::field::Elem<Self>],
coeffs: &[Self::Prepared],
srcs: &[&[u8]],
) {
Self::mul_into_gather_with(RawDispatch, dst, coeffs, srcs);
}
#[cfg(test)]
fn mul_add_matrix_with(
_proof: RawDispatch,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &[(&[Self::Prepared], &[u8])],
) {
for &(coeffs, src) in terms {
for (row, coeff) in rows.chunks_exact_mut(row_len).take(nrows).zip(coeffs) {
Self::mul_add(RawDispatch, row, coeff, src);
}
}
}
#[cfg(feature = "alloc")]
fn mul_add_matrix_plan(
_proof: RawDispatch,
rows: &mut [u8],
row_len: usize,
nrows: usize,
_values: &[crate::field::Elem<Self>],
coeffs: &[Self::Prepared],
srcs: &[&[u8]],
) {
for (term, &src) in srcs.iter().enumerate() {
let start = term * nrows;
for (row, coeff) in rows
.chunks_exact_mut(row_len)
.take(nrows)
.zip(&coeffs[start..start + nrows])
{
Self::mul_add(RawDispatch, row, coeff, src);
}
}
}
fn mul_into_matrix(
_proof: RawDispatch,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &[(&[crate::field::Elem<Self>], &[u8])],
) {
for row in rows.chunks_exact_mut(row_len).take(nrows) {
row.fill(0);
}
Self::mul_add_matrix(RawDispatch, rows, row_len, nrows, terms);
}
#[cfg(feature = "alloc")]
fn mul_into_matrix_plan(
_proof: RawDispatch,
rows: &mut [u8],
row_len: usize,
nrows: usize,
values: &[crate::field::Elem<Self>],
coeffs: &[Self::Prepared],
srcs: &[&[u8]],
) {
for row in rows.chunks_exact_mut(row_len).take(nrows) {
row.fill(0);
}
Self::mul_add_matrix_plan(RawDispatch, rows, row_len, nrows, values, coeffs, srcs);
}
fn mul_add_matrix_at(
_proof: RawDispatch,
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &[(&[crate::field::Elem<Self>], &[u8])],
) {
Self::mul_add_matrix_at_rows(RawDispatch, dst, row_len, row_starts, terms);
}
fn mul_add_matrix_at_rows(
_proof: RawDispatch,
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &[(&[crate::field::Elem<Self>], &[u8])],
) {
for &(coeffs, src) in terms {
for (&start, &coeff) in row_starts.iter().zip(coeffs) {
Self::mul_add(
RawDispatch,
&mut dst[start..start + row_len],
&Self::prepare(RawDispatch, coeff),
src,
);
}
}
}
fn mul_elementwise(_proof: RawDispatch, dst: &mut [u8], a: &[u8], b: &[u8]);
fn mul_elementwise_assign(_proof: RawDispatch, dst: &mut [u8], src: &[u8]) {
scalar::mul_elementwise_assign::<Self>(dst, src);
}
fn add_assign_scalar(_proof: RawDispatch, dst: &mut [u8], value: &Self::Prepared) {
let elem = Self::prepared_coeff(RawDispatch, value);
if <Self::Characteristic as PrimeIdentity>::CHARACTERISTIC == 2 {
let mut encoded = [0u8; 8];
Self::encode(&mut encoded[..Self::BYTES], elem);
byte_ops::xor_broadcast(dst, &encoded[..Self::BYTES]);
} else {
prime::add_assign_scalar::<Self>(dst, elem);
}
}
fn sub_assign_scalar(_proof: RawDispatch, dst: &mut [u8], value: &Self::Prepared) {
let elem = Self::prepared_coeff(RawDispatch, value);
if <Self::Characteristic as PrimeIdentity>::CHARACTERISTIC == 2 {
let mut encoded = [0u8; 8];
Self::encode(&mut encoded[..Self::BYTES], elem);
byte_ops::xor_broadcast(dst, &encoded[..Self::BYTES]);
} else {
prime::sub_assign_scalar::<Self>(dst, elem);
}
}
}
pub(crate) struct RawDispatch;
#[cfg(all(
feature = "simd",
any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "wasm32"
)
))]
pub(crate) mod proven_checks {
#[inline]
pub(crate) fn check_equal(
name: &str,
left_name: impl core::fmt::Display,
left: usize,
right_name: impl core::fmt::Display,
right: usize,
) {
assert_eq!(
left, right,
"{name}: {left_name} is {left} bytes but {right_name} is {right} bytes"
);
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline]
pub(crate) fn check_elem_multiple(name: &str, len: usize, elem_bytes: usize) {
assert!(
len.is_multiple_of(elem_bytes),
"{name}: buffer of {len} bytes is not a whole number of {elem_bytes}-byte elements"
);
}
#[cfg(any(target_arch = "aarch64", target_arch = "wasm32"))]
#[inline]
pub(crate) fn check_row_span(name: &str, buffer_len: usize, row_len: usize, count: usize) {
let used = count
.checked_mul(row_len)
.unwrap_or_else(|| panic!("{name}: row geometry overflows"));
assert!(
buffer_len >= used,
"{name}: rows is {buffer_len} bytes but {count} rows of {row_len} bytes need {used}"
);
}
#[cfg(all(
feature = "simd",
any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "wasm32"
)
))]
#[inline]
pub(crate) fn check_terms<E>(
name: &str,
row_len: usize,
nrows: usize,
terms: &[(&[E], &[u8])],
) {
for (t, &(coeffs, src)) in terms.iter().enumerate() {
check_equal(
name,
format_args!("term {t} coefficients"),
coeffs.len(),
"rows",
nrows,
);
check_equal(
name,
format_args!("term {t} source"),
src.len(),
"row_len",
row_len,
);
}
}
}
pub(crate) fn xor_gather(region: &[u8], dst: &mut [u8], offsets: &[u32]) {
let live = dst.len();
for (index, &start) in offsets.iter().enumerate() {
let start = start as usize;
assert!(
start + live <= region.len(),
"xor_gather: offset {index} ({start}) + {live} exceeds region of {} bytes",
region.len(),
);
}
if offsets.is_empty() {
return;
}
if live <= XOR_INLINE_MAX {
for &start in offsets {
scalar::xor(dst, ®ion[start as usize..start as usize + live]);
}
return;
}
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
match x86_proof() {
#[cfg(feature = "simd512")]
X86Proof::V4x(token) => {
x86::xor_gather_avx2(token.v3(), region, dst, offsets);
}
X86Proof::V3GfniCrypto(token) => {
x86::xor_gather_avx2(token.v3(), region, dst, offsets);
}
X86Proof::V3(token) => x86::xor_gather_avx2(token, region, dst, offsets),
X86Proof::V2(token) => {
for &start in offsets {
x86::xor_sse2(
token.v1(),
dst,
®ion[start as usize..start as usize + live],
);
}
}
X86Proof::Scalar => {
for &start in offsets {
scalar::xor(dst, ®ion[start as usize..start as usize + live]);
}
}
}
#[cfg(not(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64"))))]
match backend() {
#[cfg(all(feature = "simd", target_arch = "aarch64"))]
Backend::Neon | Backend::NeonAes => {
for &start in offsets {
aarch64::xor_neon(
neon_token(),
dst,
®ion[start as usize..start as usize + live],
);
}
}
#[cfg(all(feature = "simd", target_arch = "wasm32"))]
Backend::Wasm128 => {
for &start in offsets {
wasm32::xor_simd128(
wasm128_token(),
dst,
®ion[start as usize..start as usize + live],
);
}
}
_ => {
for &start in offsets {
scalar::xor(dst, ®ion[start as usize..start as usize + live]);
}
}
}
}
const XOR_INLINE_MAX: usize = 31;
pub(crate) mod byte_ops {
use super::*;
pub fn xor(dst: &mut [u8], src: &[u8]) {
assert_eq!(dst.len(), src.len(), "fgf::xor: length mismatch");
if dst.len() <= XOR_INLINE_MAX {
scalar::xor(dst, src);
return;
}
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
match x86_proof() {
#[cfg(feature = "simd512")]
X86Proof::V4x(token) if dst.len() >= x86::bytes::XOR_AVX512_MIN => {
x86::bytes::xor_avx512(token.v4(), dst, src);
}
#[cfg(feature = "simd512")]
X86Proof::V4x(token) => x86::xor_avx2(token.v3(), dst, src),
X86Proof::V3GfniCrypto(token) => x86::xor_avx2(token.v3(), dst, src),
X86Proof::V3(token) => x86::xor_avx2(token, dst, src),
X86Proof::V2(token) => x86::xor_sse2(token.v1(), dst, src),
X86Proof::Scalar => scalar::xor(dst, src),
}
#[cfg(not(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64"))))]
match backend() {
#[cfg(all(feature = "simd", target_arch = "aarch64"))]
Backend::Neon | Backend::NeonAes => aarch64::xor_neon(neon_token(), dst, src),
#[cfg(all(feature = "simd", target_arch = "wasm32"))]
Backend::Wasm128 => wasm32::xor_simd128(wasm128_token(), dst, src),
_ => scalar::xor(dst, src),
}
}
pub fn xor_broadcast(dst: &mut [u8], value_bytes: &[u8]) {
#[cfg(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64")))]
match x86_proof() {
#[cfg(feature = "simd512")]
X86Proof::V4x(token) => {
x86::bytes::xor_broadcast_avx2(token.v3(), dst, value_bytes);
}
X86Proof::V3GfniCrypto(token) => {
x86::bytes::xor_broadcast_avx2(token.v3(), dst, value_bytes);
}
X86Proof::V3(token) => x86::bytes::xor_broadcast_avx2(token, dst, value_bytes),
X86Proof::V2(token) => x86::bytes::xor_broadcast_sse2(token.v1(), dst, value_bytes),
X86Proof::Scalar => scalar::xor_broadcast_bytes(dst, value_bytes),
}
#[cfg(not(all(feature = "simd", any(target_arch = "x86", target_arch = "x86_64"))))]
match backend() {
#[cfg(all(feature = "simd", target_arch = "aarch64"))]
Backend::Neon | Backend::NeonAes => {
aarch64::bytes::xor_broadcast_neon(neon_token(), dst, value_bytes);
}
#[cfg(all(feature = "simd", target_arch = "wasm32"))]
Backend::Wasm128 => {
wasm32::bytes::xor_broadcast_simd128(wasm128_token(), dst, value_bytes);
}
_ => scalar::xor_broadcast_bytes(dst, value_bytes),
}
}
}