extern crate alloc;
use alloc::vec::Vec;
use crate::Field;
use crate::errors::Error;
use crate::matrix::Matrix;
use super::CodecFamily;
pub(crate) trait AsLeopardU8: Sized {
fn slice_to_u8(slice: &[Self]) -> &[u8];
fn slice_to_u8_mut(slice: &mut [Self]) -> &mut [u8];
}
impl AsLeopardU8 for u8 {
#[inline]
fn slice_to_u8(slice: &[u8]) -> &[u8] {
slice
}
#[inline]
fn slice_to_u8_mut(slice: &mut [u8]) -> &mut [u8] {
slice
}
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum FamilyState<F: Field> {
Classic,
LeopardGF8(LeopardGF8Codec<F>),
LeopardGF16,
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct LeopardGF8Codec<F: Field> {
data_shards: usize,
parity_shards: usize,
total_shards: usize,
setup_rows: usize,
setup_cols: usize,
parity_rows: Vec<Vec<F::Elem>>,
_marker: core::marker::PhantomData<F>,
}
impl<F: Field> LeopardGF8Codec<F> {
pub(crate) fn new(
data_shards: usize,
parity_shards: usize,
setup_matrix: Matrix<F>,
) -> Result<Self, Error> {
validate_leopard_gf8::<F>(data_shards, parity_shards)?;
Ok(Self {
data_shards,
parity_shards,
total_shards: data_shards.saturating_add(parity_shards),
setup_rows: setup_matrix.row_count(),
setup_cols: setup_matrix.col_count(),
parity_rows: (data_shards..(data_shards + parity_shards))
.map(|row| setup_matrix.get_row(row).to_vec())
.collect(),
_marker: core::marker::PhantomData,
})
}
pub(crate) fn data_shards(&self) -> usize {
self.data_shards
}
pub(crate) fn parity_shards(&self) -> usize {
self.parity_shards
}
pub(crate) fn total_shards(&self) -> usize {
self.total_shards
}
pub(crate) fn setup_matrix(&self) -> &Matrix<F> {
unreachable!(
"LeopardGF8 prototype only keeps setup metadata, not an executable matrix handle"
)
}
pub(crate) fn setup_shape(&self) -> (usize, usize) {
(self.setup_rows, self.setup_cols)
}
pub(crate) fn parity_rows(&self) -> Vec<&[F::Elem]> {
self.parity_rows.iter().map(|row| row.as_slice()).collect()
}
}
pub(crate) fn leopard_gf8_state<F: Field>(
family_state: &FamilyState<F>,
) -> Result<&LeopardGF8Codec<F>, Error> {
match family_state {
FamilyState::LeopardGF8(codec) => Ok(codec),
FamilyState::Classic => Err(Error::UnsupportedCodecFamily),
FamilyState::LeopardGF16 => Err(Error::UnsupportedLeopardPrototype),
}
}
pub(crate) fn validate_leopard_shard_len(shard_len: usize) -> Result<(), Error> {
if shard_len == 0 || !shard_len.is_multiple_of(64) {
return Err(Error::IncorrectShardSize);
}
Ok(())
}
pub(crate) fn build_family_state<F: Field>(
codec_family: CodecFamily,
data_shards: usize,
parity_shards: usize,
setup_matrix: &Matrix<F>,
) -> Result<FamilyState<F>, Error> {
match codec_family {
CodecFamily::Classic => Ok(FamilyState::Classic),
CodecFamily::LeopardGF8 => Ok(FamilyState::LeopardGF8(LeopardGF8Codec::new(
data_shards,
parity_shards,
{
let mut matrix = Matrix::new(setup_matrix.row_count(), setup_matrix.col_count());
for row in 0..setup_matrix.row_count() {
for col in 0..setup_matrix.col_count() {
matrix.set(row, col, setup_matrix.get(row, col));
}
}
matrix
},
)?)),
CodecFamily::LeopardGF16 => Ok(FamilyState::LeopardGF16),
}
}
pub(crate) fn validate_leopard_family<F: Field>(
codec_family: CodecFamily,
data_shards: usize,
parity_shards: usize,
) -> Result<(), Error> {
match codec_family {
CodecFamily::Classic => Ok(()),
CodecFamily::LeopardGF8 => validate_leopard_gf8::<F>(data_shards, parity_shards),
CodecFamily::LeopardGF16 => validate_leopard_gf16::<F>(data_shards, parity_shards),
}
}
fn validate_leopard_gf8<F: Field>(data_shards: usize, parity_shards: usize) -> Result<(), Error> {
let total_shards = data_shards.saturating_add(parity_shards);
if F::ORDER != 256 {
return Err(Error::UnsupportedCodecFamily);
}
if total_shards == 0 || total_shards > 256 {
return Err(Error::UnsupportedCodecFamily);
}
Ok(())
}
fn validate_leopard_gf16<F: Field>(data_shards: usize, parity_shards: usize) -> Result<(), Error> {
let total_shards = data_shards.saturating_add(parity_shards);
if F::ORDER != 256 {
return Err(Error::UnsupportedCodecFamily);
}
if total_shards == 0 || total_shards > 65536 {
return Err(Error::UnsupportedCodecFamily);
}
Ok(())
}
pub(crate) fn leopard_gf8_encode(
data_shards: usize,
parity_shards: usize,
data: &[&[u8]],
parity: &mut [&mut [u8]],
) -> Result<(), Error> {
super::leopard_gf8::encode_with_tables(data_shards, parity_shards, data, parity)?;
Ok(())
}
pub(crate) fn leopard_gf16_encode(
data_shards: usize,
parity_shards: usize,
data: &[&[u8]],
parity: &mut [&mut [u8]],
) -> Result<(), Error> {
super::leopard_gf16::encode::encode_with_tables16(data_shards, parity_shards, data, parity)?;
Ok(())
}
pub(crate) fn leopard_gf16_reconstruct(
present: &[bool],
outputs: &mut [&mut [u8]],
input_data: &[Option<&[u8]>],
data_shards: usize,
parity_shards: usize,
) -> Result<(), Error> {
let tables = super::leopard_gf16::init_leopard_gf16_tables();
super::leopard_gf16::decode::reconstruct_with_tables16(
present,
outputs,
input_data,
data_shards,
parity_shards,
tables,
)
}