#![forbid(unsafe_code)]
use fgf::{Elem, backend_for, ops};
type Gf16 = fgf::FiniteField<2, 16, fgf::Extension<fgf::Rijndael16, 2>>;
const SYMBOLS: usize = 8;
const ROW_LEN: usize = SYMBOLS * 2;
fn main() {
let first = std::array::from_fn::<_, SYMBOLS, _>(|i| Elem::<Gf16>::from_raw(0x1200 + i as u16));
let second =
std::array::from_fn::<_, SYMBOLS, _>(|i| Elem::<Gf16>::from_raw(0x3400 + i as u16));
let third = std::array::from_fn::<_, SYMBOLS, _>(|i| Elem::<Gf16>::from_raw(0x5600 + i as u16));
let mut payloads = [[0u8; ROW_LEN]; 3];
for (dst, elements) in payloads.iter_mut().zip([first, second, third]) {
ops::pack::<Gf16>(dst, &elements);
}
let coefficients = [
Elem::<Gf16>::ONE,
Elem::<Gf16>::from_raw(0x0108),
Elem::<Gf16>::ONE,
Elem::<Gf16>::from_raw(0x0203),
Elem::<Gf16>::ONE,
Elem::<Gf16>::from_raw(0x0405),
];
let matrix = ops::CoeffMatrix::<Gf16>::from_source_major(3, 2, &coefficients);
let mut parity = [0u8; 2 * ROW_LEN];
for (source, payload) in payloads.iter().enumerate() {
ops::mul_add_scatter_with(
&mut parity,
ROW_LEN,
matrix.source(source).unwrap(),
payload,
);
}
let mut replacement = second;
replacement[3] += Elem::<Gf16>::from_raw(0xabcd);
let mut replacement_bytes = [0u8; ROW_LEN];
ops::pack::<Gf16>(&mut replacement_bytes, &replacement);
let mut delta = replacement_bytes;
ops::sub_assign::<Gf16>(&mut delta, &payloads[1]);
ops::mul_add_scatter_with(&mut parity, ROW_LEN, matrix.source(1).unwrap(), &delta);
payloads[1] = replacement_bytes;
let sources: [&[u8]; 3] = payloads.each_ref().map(|row| row.as_slice());
let mut batch = [0xa5; 2 * ROW_LEN];
ops::mul_into_matrix_with(&mut batch, ROW_LEN, &matrix, &sources);
assert_eq!(parity, batch);
const HEADER: usize = 4;
let offsets = [HEADER, HEADER + 2 * ROW_LEN];
let mut frame = [0x5a; HEADER + 3 * ROW_LEN];
for start in offsets {
frame[start..start + ROW_LEN].fill(0);
}
ops::mul_add_matrix_at_with(&mut frame, ROW_LEN, &offsets, &matrix, &sources);
assert_eq!(&frame[..HEADER], &[0x5a; HEADER]);
assert_eq!(
&frame[HEADER + ROW_LEN..HEADER + 2 * ROW_LEN],
&[0x5a; ROW_LEN]
);
for (output, start) in offsets.into_iter().enumerate() {
assert_eq!(
&frame[start..start + ROW_LEN],
&parity[output * ROW_LEN..(output + 1) * ROW_LEN]
);
}
let mut direct = [0x5a; HEADER + 3 * ROW_LEN];
ops::mul_into_matrix_at_with(&mut direct, ROW_LEN, &offsets, &matrix, &sources);
assert_eq!(direct, frame);
let mut elements = [Elem::ZERO; SYMBOLS];
ops::unpack::<Gf16>(&mut elements, &parity[ROW_LEN..]);
println!("Gf16 backend: {:?}", backend_for::<Gf16>());
println!("Updated weighted parity: {elements:?}");
println!("Streaming, batch, and offset-addressed outputs agree; frame metadata is intact.");
}