use super::super::rows::{RESOLVE_CHUNK, rows_body, rows_resolved_chunked};
use super::super::{Affine8D, factor_word};
use super::rows_external_chunked;
use crate::field::gf8d;
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix1_external_8d(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
maps: &[u64],
srcs: &[&[u8]],
lanes: usize,
) {
assert_eq!(
row_len % 32,
0,
"matrix_overwrite1_external: needs a 32-byte-multiple row"
);
assert!(
row_len <= rows.len(),
"matrix_overwrite1_external: rows buffer does not hold one row of {row_len} bytes"
);
assert_eq!(
maps.len(),
srcs.len(),
"matrix_overwrite1_external: one resolved map per source"
);
for src in srcs {
assert_eq!(src.len(), row_len);
}
let (chunks, rest) = maps.as_chunks::<1>();
debug_assert!(rest.is_empty());
let ptr = rows.as_mut_ptr();
match lanes {
3 => rows_body::<Affine8D, 1, 3, true>([ptr], row_len, chunks, srcs),
4 => rows_body::<Affine8D, 1, 4, true>([ptr], row_len, chunks, srcs),
_ => panic!("matrix_overwrite1_external: lanes must be 3 or 4"),
}
}
#[must_use]
#[allow(unsafe_code)]
pub fn resolve_probe_8d(terms: &[(&[gf8d::Elem], &[u8])]) -> u64 {
for (coeffs, _) in terms {
assert!(
!coeffs.is_empty(),
"resolve_probe: term needs one coefficient"
);
}
let count = terms.len();
let mut sink = 0u64;
let mut start = 0;
loop {
let taken = (count - start).min(RESOLVE_CHUNK);
let mut maps: [core::mem::MaybeUninit<[u64; 1]>; RESOLVE_CHUNK] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
let mut srcs: [core::mem::MaybeUninit<&[u8]>; RESOLVE_CHUNK] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
for offset in 0..taken {
let (coeffs, source) = terms[start + offset];
maps[offset].write([factor_word::<Affine8D>(coeffs[0])]);
srcs[offset].write(source);
}
let (maps, srcs): (&[[u64; 1]], &[&[u8]]) = unsafe {
(
core::slice::from_raw_parts(maps.as_ptr().cast::<[u64; 1]>(), taken),
core::slice::from_raw_parts(srcs.as_ptr().cast::<&[u8]>(), taken),
)
};
for (words, src) in maps.iter().zip(srcs) {
sink ^= words[0] ^ src.as_ptr() as u64;
}
start += taken;
if start >= count {
return sink;
}
}
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix1_fullinit_8d(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
terms: &[(&[gf8d::Elem], &[u8])],
lanes: usize,
) {
assert!(
row_len <= rows.len(),
"matrix_overwrite1_fullinit: rows buffer does not hold one row of {row_len} bytes"
);
for (coeffs, src) in terms {
assert_eq!(src.len(), row_len);
assert!(
!coeffs.is_empty(),
"matrix_overwrite1_fullinit: term needs one coefficient"
);
}
let ptr = rows.as_mut_ptr();
match lanes {
3 => rows_resolved_chunked::<
Affine8D,
[(&[gf8d::Elem], &[u8])],
1,
3,
true,
RESOLVE_CHUNK,
true,
>([ptr], row_len, 0, terms),
4 => rows_resolved_chunked::<
Affine8D,
[(&[gf8d::Elem], &[u8])],
1,
4,
true,
RESOLVE_CHUNK,
true,
>([ptr], row_len, 0, terms),
_ => panic!("matrix_overwrite1_fullinit: lanes must be 3 or 4"),
}
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix1_chunk_8d(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
terms: &[(&[gf8d::Elem], &[u8])],
lanes: usize,
chunk: usize,
) {
assert!(
row_len <= rows.len(),
"matrix_overwrite1_chunk: rows buffer does not hold one row of {row_len} bytes"
);
for (coeffs, src) in terms {
assert_eq!(src.len(), row_len);
assert!(
!coeffs.is_empty(),
"matrix_overwrite1_chunk: term needs one coefficient"
);
}
let ptr = rows.as_mut_ptr();
match (lanes, chunk) {
(3, 32) => {
rows_resolved_chunked::<Affine8D, [(&[gf8d::Elem], &[u8])], 1, 3, true, 32, false>(
[ptr],
row_len,
0,
terms,
);
}
(4, 32) => {
rows_resolved_chunked::<Affine8D, [(&[gf8d::Elem], &[u8])], 1, 4, true, 32, false>(
[ptr],
row_len,
0,
terms,
);
}
(3, 64) => {
rows_resolved_chunked::<Affine8D, [(&[gf8d::Elem], &[u8])], 1, 3, true, 64, false>(
[ptr],
row_len,
0,
terms,
);
}
(4, 64) => {
rows_resolved_chunked::<Affine8D, [(&[gf8d::Elem], &[u8])], 1, 4, true, 64, false>(
[ptr],
row_len,
0,
terms,
);
}
(3, 96) => {
rows_resolved_chunked::<Affine8D, [(&[gf8d::Elem], &[u8])], 1, 3, true, 96, false>(
[ptr],
row_len,
0,
terms,
);
}
(4, 96) => {
rows_resolved_chunked::<Affine8D, [(&[gf8d::Elem], &[u8])], 1, 4, true, 96, false>(
[ptr],
row_len,
0,
terms,
);
}
_ => panic!("matrix_overwrite1_chunk: lanes must be 3 or 4, chunk 32/64/96"),
}
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix1_external_chunk_8d(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
maps: &[u64],
srcs: &[&[u8]],
lanes: usize,
chunk: usize,
) {
assert_eq!(
row_len % 32,
0,
"matrix_overwrite1_external_chunk: needs a 32-byte-multiple row"
);
assert!(
row_len <= rows.len(),
"matrix_overwrite1_external_chunk: rows buffer does not hold one row of {row_len} bytes"
);
assert_eq!(
maps.len(),
srcs.len(),
"matrix_overwrite1_external_chunk: one resolved map per source"
);
for src in srcs {
assert_eq!(src.len(), row_len);
}
assert!(
matches!(chunk, 0 | 32 | 64 | 96),
"matrix_overwrite1_external_chunk: chunk must be 0, 32, 64 or 96"
);
assert!(
matches!(lanes, 3 | 4),
"matrix_overwrite1_external_chunk: lanes must be 3 or 4"
);
if maps.is_empty() {
rows[..row_len].fill(0);
return;
}
let (words, rest) = maps.as_chunks::<1>();
debug_assert!(rest.is_empty());
let ptr = rows.as_mut_ptr();
match lanes {
3 => rows_external_chunked::<1, 3>([ptr], row_len, words, srcs, chunk),
4 => rows_external_chunked::<1, 4>([ptr], row_len, words, srcs, chunk),
_ => panic!("matrix_overwrite1_external_chunk: lanes must be 3 or 4"),
}
}