use super::rows::{matrix_rows1, matrix_rows2, matrix_rows4};
use super::{Affine8D, Blocked, Gfni};
use super::{Affine8DPrepared, PreparedMatrix};
use crate::field::gf8b::Elem;
use crate::field::gf8d;
use crate::kernel::Matrix;
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_gfni(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &[(&[Elem], &[u8])],
) {
for (t, (coeffs, _)) in terms.iter().enumerate() {
assert_eq!(
coeffs.len(),
nrows,
"mul_add_matrix_gfni: term {t} needs {nrows} coefficients"
);
}
mul_add_matrix_gfni_with(_token, rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_gfni_with<M: Matrix<Elem> + ?Sized>(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
assert!(
nrows
.checked_mul(row_len)
.is_some_and(|needed| needed <= rows.len()),
"mul_add_matrix_gfni: rows buffer does not hold {nrows} rows of {row_len} bytes"
);
for term in 0..terms.len() {
assert_eq!(terms.source(term).len(), row_len);
}
if terms.len() == 0 {
return;
}
mul_add_matrix_impl::<Gfni, M, false>(rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_affine(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &[(&[gf8d::Elem], &[u8])],
) {
for (t, (coeffs, _)) in terms.iter().enumerate() {
assert_eq!(
coeffs.len(),
nrows,
"mul_add_matrix_affine: term {t} needs {nrows} coefficients"
);
}
mul_add_matrix_affine_with(_token, rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_affine_with<M: Matrix<gf8d::Elem> + ?Sized>(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
assert!(
nrows
.checked_mul(row_len)
.is_some_and(|needed| needed <= rows.len()),
"mul_add_matrix_affine: rows buffer does not hold {nrows} rows of {row_len} bytes"
);
for term in 0..terms.len() {
assert_eq!(terms.source(term).len(), row_len);
}
if terms.len() == 0 {
return;
}
mul_add_matrix_impl::<Affine8D, M, false>(rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix_gfni(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &[(&[Elem], &[u8])],
) {
for (t, (coeffs, _)) in terms.iter().enumerate() {
assert_eq!(
coeffs.len(),
nrows,
"mul_into_matrix_gfni: term {t} needs {nrows} coefficients"
);
}
mul_into_matrix_gfni_with(_token, rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix_gfni_with<M: Matrix<Elem> + ?Sized>(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
assert!(
nrows
.checked_mul(row_len)
.is_some_and(|needed| needed <= rows.len()),
"mul_into_matrix_gfni: rows buffer does not hold {nrows} rows of {row_len} bytes"
);
for term in 0..terms.len() {
assert_eq!(terms.source(term).len(), row_len);
}
mul_add_matrix_impl::<Gfni, M, true>(rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix_affine(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &[(&[gf8d::Elem], &[u8])],
) {
for (t, (coeffs, _)) in terms.iter().enumerate() {
assert_eq!(
coeffs.len(),
nrows,
"mul_into_matrix_affine: term {t} needs {nrows} coefficients"
);
}
mul_into_matrix_affine_with(_token, rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix_affine_with<M: Matrix<gf8d::Elem> + ?Sized>(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
assert!(
nrows
.checked_mul(row_len)
.is_some_and(|needed| needed <= rows.len()),
"mul_into_matrix_affine: rows buffer does not hold {nrows} rows of {row_len} bytes"
);
for term in 0..terms.len() {
assert_eq!(terms.source(term).len(), row_len);
}
mul_add_matrix_impl::<Affine8D, M, true>(rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_affine_prepared_with(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
prepared: &[crate::kernel::gf8::Prepared8D],
srcs: &[&[u8]],
) {
assert!(
nrows
.checked_mul(row_len)
.is_some_and(|needed| needed <= rows.len()),
"matrix_affine_prepared: rows buffer does not hold {nrows} rows of {row_len} bytes"
);
assert_eq!(
prepared.len(),
nrows * srcs.len(),
"matrix_affine_prepared: one prepared coefficient per (term, row)"
);
for src in srcs {
assert_eq!(src.len(), row_len);
}
if srcs.is_empty() {
return;
}
let terms = PreparedMatrix {
prepared,
nrows,
sources: srcs,
};
mul_add_matrix_impl::<Affine8DPrepared, PreparedMatrix, false>(rows, row_len, nrows, &terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix_affine_prepared_with(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
prepared: &[crate::kernel::gf8::Prepared8D],
srcs: &[&[u8]],
) {
assert!(
nrows
.checked_mul(row_len)
.is_some_and(|needed| needed <= rows.len()),
"matrix_overwrite_affine_prepared: rows buffer does not hold {nrows} rows of {row_len} bytes"
);
assert_eq!(
prepared.len(),
nrows * srcs.len(),
"matrix_overwrite_affine_prepared: one prepared coefficient per (term, row)"
);
for src in srcs {
assert_eq!(src.len(), row_len);
}
if srcs.is_empty() {
rows[..nrows * row_len].fill(0);
return;
}
let terms = PreparedMatrix {
prepared,
nrows,
sources: srcs,
};
mul_add_matrix_impl::<Affine8DPrepared, PreparedMatrix, true>(rows, row_len, nrows, &terms);
}
#[allow(unsafe_code)]
#[archmage::rite(v3_gfni_crypto)]
fn mul_add_matrix_impl<S: Blocked, M: Matrix<S::Coeff> + ?Sized, const OVERWRITE: bool>(
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
let base = rows.as_mut_ptr();
let mut g = 0;
while g + 4 <= nrows {
let ptrs = unsafe {
[
base.add(g * row_len),
base.add((g + 1) * row_len),
base.add((g + 2) * row_len),
base.add((g + 3) * row_len),
]
};
matrix_rows4::<S, M, OVERWRITE>(ptrs, row_len, g, terms);
g += 4;
}
if g + 2 <= nrows {
let ptrs = unsafe { [base.add(g * row_len), base.add((g + 1) * row_len)] };
matrix_rows2::<S, M, OVERWRITE>(ptrs, row_len, g, terms);
g += 2;
}
if g < nrows {
let ptr = unsafe { base.add(g * row_len) };
matrix_rows1::<S, M, OVERWRITE>(ptr, row_len, g, terms);
}
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_at_gfni(
_token: archmage::X64V3GfniCryptoToken,
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &[(&[Elem], &[u8])],
) {
for (t, (coeffs, _)) in terms.iter().enumerate() {
assert_eq!(
coeffs.len(),
row_starts.len(),
"mul_add_matrix_at_gfni: term {t} needs {} coefficients",
row_starts.len()
);
}
mul_add_matrix_at_gfni_with(_token, dst, row_len, row_starts, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_at_gfni_with<M: Matrix<Elem> + ?Sized>(
_token: archmage::X64V3GfniCryptoToken,
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &M,
) {
check_scattered("mul_add_matrix_at_gfni", dst.len(), row_len, row_starts);
for term in 0..terms.len() {
assert_eq!(terms.source(term).len(), row_len);
}
if terms.len() == 0 || row_starts.is_empty() {
return;
}
mul_add_matrix_at_impl::<Gfni, M>(dst, row_len, row_starts, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_at_affine(
_token: archmage::X64V3GfniCryptoToken,
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &[(&[gf8d::Elem], &[u8])],
) {
for (t, (coeffs, _)) in terms.iter().enumerate() {
assert_eq!(
coeffs.len(),
row_starts.len(),
"mul_add_matrix_at_affine: term {t} needs {} coefficients",
row_starts.len()
);
}
mul_add_matrix_at_affine_with(_token, dst, row_len, row_starts, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_at_affine_with<M: Matrix<gf8d::Elem> + ?Sized>(
_token: archmage::X64V3GfniCryptoToken,
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &M,
) {
check_scattered("mul_add_matrix_at_affine", dst.len(), row_len, row_starts);
for term in 0..terms.len() {
assert_eq!(terms.source(term).len(), row_len);
}
if terms.len() == 0 || row_starts.is_empty() {
return;
}
mul_add_matrix_at_impl::<Affine8D, M>(dst, row_len, row_starts, terms);
}
fn check_scattered(name: &str, dst_len: usize, row_len: usize, row_starts: &[usize]) {
for (j, &start) in row_starts.iter().enumerate() {
let end = start
.checked_add(row_len)
.unwrap_or_else(|| panic!("{name}: row offset plus length overflows"));
assert!(
end <= dst_len,
"{name}: row {j} spans {start}..{end} but dst is {dst_len} bytes"
);
}
for (a, &sa) in row_starts.iter().enumerate() {
for &sb in &row_starts[a + 1..] {
let (lo, hi) = if sa <= sb { (sa, sb) } else { (sb, sa) };
assert!(
hi - lo >= row_len,
"{name}: rows at {sa} and {sb} overlap for {row_len}-byte rows"
);
}
}
}
#[allow(unsafe_code)]
#[archmage::rite(v3_gfni_crypto)]
fn mul_add_matrix_at_impl<S: Blocked, M: Matrix<S::Coeff> + ?Sized>(
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &M,
) {
let base = dst.as_mut_ptr();
let nrows = row_starts.len();
let mut g = 0;
while g + 4 <= nrows {
let ptrs = unsafe {
[
base.add(row_starts[g]),
base.add(row_starts[g + 1]),
base.add(row_starts[g + 2]),
base.add(row_starts[g + 3]),
]
};
matrix_rows4::<S, M, false>(ptrs, row_len, g, terms);
g += 4;
}
if g + 2 <= nrows {
let ptrs = unsafe { [base.add(row_starts[g]), base.add(row_starts[g + 1])] };
matrix_rows2::<S, M, false>(ptrs, row_len, g, terms);
g += 2;
}
if g < nrows {
let ptr = unsafe { base.add(row_starts[g]) };
matrix_rows1::<S, M, false>(ptr, row_len, g, terms);
}
}