use crate::engine::{
tables::{self, Exp, Log, Skew},
utils, Engine, GfElement, ShardsRefMut, GF_MODULUS,
};
#[derive(Clone, Copy)]
pub struct Naive {
exp: &'static Exp,
log: &'static Log,
skew: &'static Skew,
}
impl Naive {
pub fn new() -> Self {
let exp_log = tables::get_exp_log();
let skew = tables::get_skew();
Self {
exp: &exp_log.exp,
log: &exp_log.log,
skew,
}
}
}
impl Engine for Naive {
fn fft(
&self,
data: &mut ShardsRefMut,
pos: usize,
size: usize,
truncated_size: usize,
skew_delta: usize,
) {
debug_assert!(size.is_power_of_two());
debug_assert!(truncated_size <= size);
let mut dist = size / 2;
while dist > 0 {
let mut r = 0;
while r < truncated_size {
let log_m = self.skew[r + dist + skew_delta - 1];
for i in r..r + dist {
let (a, b) = data.dist2_mut(pos + i, dist);
if log_m != GF_MODULUS {
self.mul_add(a, b, log_m);
}
utils::xor(b, a);
}
r += dist * 2;
}
dist /= 2;
}
}
fn ifft(
&self,
data: &mut ShardsRefMut,
pos: usize,
size: usize,
truncated_size: usize,
skew_delta: usize,
) {
debug_assert!(size.is_power_of_two());
debug_assert!(truncated_size <= size);
let mut dist = 1;
while dist < size {
let mut r = 0;
while r < truncated_size {
let log_m = self.skew[r + dist + skew_delta - 1];
for i in r..r + dist {
let (a, b) = data.dist2_mut(pos + i, dist);
utils::xor(b, a);
if log_m != GF_MODULUS {
self.mul_add(a, b, log_m);
}
}
r += dist * 2;
}
dist *= 2;
}
}
fn mul(&self, x: &mut [[u8; 64]], log_m: GfElement) {
for chunk in x.iter_mut() {
for i in 0..32 {
let lo = GfElement::from(chunk[i]);
let hi = GfElement::from(chunk[i + 32]);
let prod = tables::mul(lo | (hi << 8), log_m, self.exp, self.log);
chunk[i] = prod as u8;
chunk[i + 32] = (prod >> 8) as u8;
}
}
}
}
impl Default for Naive {
fn default() -> Self {
Self::new()
}
}
impl Naive {
fn mul_add(&self, x: &mut [[u8; 64]], y: &[[u8; 64]], log_m: GfElement) {
debug_assert_eq!(x.len(), y.len());
for (x_chunk, y_chunk) in core::iter::zip(x.iter_mut(), y.iter()) {
for i in 0..32 {
let lo = GfElement::from(y_chunk[i]);
let hi = GfElement::from(y_chunk[i + 32]);
let prod = tables::mul(lo | (hi << 8), log_m, self.exp, self.log);
x_chunk[i] ^= prod as u8;
x_chunk[i + 32] ^= (prod >> 8) as u8;
}
}
}
}