use std::ops::Deref;
use crate::{Error, gf};
pub struct GaloisFiledTable(Vec<u8>);
impl GaloisFiledTable {
pub fn try_from_matrix(matrix: &[u8], rows: usize, cols: usize) -> Result<Self, Error> {
if matrix.len() != rows * cols {
return Err(Error::invalid_arguments(format!(
"Invalid matrix size: length {}, expected {} x {} = {}",
matrix.len(),
rows,
cols,
rows * cols
)));
}
let mut gf_table = vec![0_u8; cols * rows * 32];
crate::ec::init_tables(
cols.try_into().unwrap(),
rows.try_into().unwrap(),
matrix,
&mut gf_table[..],
);
Ok(Self(gf_table))
}
pub fn as_slice(&self) -> &[u8] {
&self.0
}
}
impl From<Vec<u8>> for GaloisFiledTable {
fn from(value: Vec<u8>) -> Self {
Self(value)
}
}
impl Deref for GaloisFiledTable {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl AsRef<[u8]> for GaloisFiledTable {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
pub fn dot_prod<T>(
table: &GaloisFiledTable,
source: impl AsRef<[T]>,
dest: &mut [u8],
) -> Result<(), Error>
where
T: AsRef<[u8]>,
{
let len = dest.len();
if len < 32 {
return Err(Error::invalid_arguments(format!(
"Destination buffer too small: length {}, expected at least 32",
len
)));
}
let source = source.as_ref();
if source.iter().any(|s| s.as_ref().len() != len) {
return Err(Error::invalid_arguments(
"Source slices must be equal in length to destination buffer",
));
}
if table.len() != 32 * source.len() {
return Err(Error::invalid_arguments(format!(
"Table length mismatch: expected 32 * source number {}, got {}",
32 * source.len(),
table.len()
)));
}
let src_ptrs = source
.iter()
.map(|s| s.as_ref().as_ptr())
.collect::<Vec<_>>();
gf::vect_dot_prod(
len.try_into().unwrap(),
source.len().try_into().unwrap(),
table,
&src_ptrs,
dest,
);
Ok(())
}
pub fn mul_add(
table: &GaloisFiledTable,
source_num: usize,
index: usize,
source_i: &[u8],
dest: &mut [u8],
) -> Result<(), Error> {
let len = dest.len();
if len < 64 {
return Err(Error::invalid_arguments(format!(
"Destination buffer too small: length {}, expected at least 64",
len
)));
}
if source_i.len() != len {
return Err(Error::invalid_arguments(format!(
"Source slice length mismatch: source {}, dest {}",
source_i.len(),
len,
)));
}
if table.len() != 32 * source_num {
return Err(Error::invalid_arguments(format!(
"Table length mismatch: expected 32 * source number {}, got {}",
32 * source_num,
table.len()
)));
}
if index >= source_num {
return Err(Error::invalid_arguments(format!(
"Index out of bounds: index {}, source number {}",
index, source_num
)));
}
crate::gf::vect_mad(
len.try_into().unwrap(),
source_num.try_into().unwrap(),
index.try_into().unwrap(),
table,
source_i,
dest,
);
Ok(())
}