use super::ErrorDecodingError;
use crate::errorcode::GF;
use crate::SymbolSize;
use alloc::{vec, vec::Vec};
#[cfg(test)]
use pretty_assertions::assert_eq;
pub fn decode(codewords: &mut [u8], size: SymbolSize) -> Result<(), ErrorDecodingError> {
let setup = size.block_setup();
let err_len = setup.num_ecc_per_block;
let stride = setup.num_ecc_blocks;
let num_data = size.num_data_codewords();
let (data, error) = codewords.split_at_mut(num_data);
for block in 0..setup.num_ecc_blocks {
decode_gen(
&mut data[block..],
&mut error[block..],
stride,
err_len,
find_inv_error_locations_levinson_durbin,
find_error_values_bp,
)?;
}
Ok(())
}
fn decode_gen<F, G>(
data: &mut [u8],
error: &mut [u8],
stride: usize,
err_len: usize,
inv_error_locs: F,
find_err_vals: G,
) -> Result<(), ErrorDecodingError>
where
F: Fn(&[GF]) -> Result<Vec<GF>, ErrorDecodingError>,
G: Fn(&mut [GF], &[GF], &mut [GF]),
{
let n_data = (data.len() + stride - 1) / stride;
let n_error = (error.len() + stride - 1) / stride;
let n = n_data + n_error;
assert!(err_len >= 1, "degree of generator polynomial must be >= 1");
assert!(n > err_len, "data length shorter than error code suffix");
let mut syndromes = vec![GF(0); err_len];
let received = data
.iter()
.copied()
.step_by(stride)
.chain(error.iter().copied().step_by(stride));
let have_non_zero = super::primitive_element_evaluation(received, &mut syndromes);
if !have_non_zero {
return Ok(());
}
let lambda_coeff = inv_error_locs(&syndromes)?;
let mut inv_error_locations = super::chien_search(&lambda_coeff);
if inv_error_locations.len() != lambda_coeff.len() - 1 || inv_error_locations[0] == GF(0) {
return Err(ErrorDecodingError::Malfunction);
}
let t = err_len / 2;
let v = lambda_coeff.len() - 1;
for j in t..=2 * t - v - 1 {
debug_assert!(syndromes[j..].len() >= lambda_coeff.len());
let t_j: GF = syndromes[j..]
.iter()
.zip(lambda_coeff.iter())
.map(|(a, b)| *a * *b)
.sum();
if t_j != GF(0) {
return Err(ErrorDecodingError::Malfunction);
}
}
find_err_vals(&mut inv_error_locations, &lambda_coeff, &mut syndromes);
let error_locations = inv_error_locations;
for (loc, err) in error_locations.iter().zip(syndromes.iter()) {
let i = loc.log();
if i >= n {
return Err(ErrorDecodingError::ErrorsOutsideRange);
}
let mut idx = (n - i - 1) * stride;
if idx < data.len() {
data[idx] = (GF(data[idx]) - *err).into();
} else {
idx -= data.len();
error[idx] = (GF(error[idx]) - *err).into();
}
}
Ok(())
}
fn find_inv_error_locations_levinson_durbin(syn: &[GF]) -> Result<Vec<GF>, ErrorDecodingError> {
let t = syn.len() / 2;
let mut v = syn.iter().take_while(|s| **s == GF(0)).count() + 1;
let mut y = Vec::with_capacity(t);
y.push(GF(1) / syn[v - 1]);
y.extend(core::iter::repeat(GF(0)).take(v - 1));
let mut w = Vec::<GF>::with_capacity(t);
w.extend(syn[v..=2 * v - 1].iter().rev());
for i in 0..v {
for j in v - i..v {
let wj = w[j];
w[v - 1 - i] -= syn[i + j] * wj;
}
w[v - 1 - i] /= syn[v - 1];
}
fn dot(a: &[GF], b: &[GF]) -> GF {
debug_assert_eq!(a.len(), b.len());
a.iter().zip(b.iter()).map(|(p, q)| *p * *q).sum()
}
let mut tmp = Vec::with_capacity(t);
let mut sigma = Vec::with_capacity(t);
let mut gamma = Vec::with_capacity(t);
while v < t {
tmp.clear();
tmp.extend_from_slice(&w);
tmp.push(-GF(1));
let eps_v: GF = dot(&syn[v..=2 * v], &tmp);
if eps_v != GF(0) {
w.insert(0, GF(0));
for (wi, yi) in w[..v].iter_mut().zip(y.iter()) {
*wi -= eps_v * *yi;
}
let beta: GF = dot(&syn[v + 1..=2 * v + 1], &tmp) / eps_v;
let gamma: GF = dot(&syn[v..=2 * v - 1], &y);
for (wi, ti) in w.iter_mut().zip(tmp.iter()) {
*wi -= (beta - gamma) * *ti;
}
let eps_inv = GF(1) / eps_v;
for (yi, ti) in y.iter_mut().zip(tmp.iter()) {
*yi = *ti * eps_inv;
}
y.push(-eps_inv);
v += 1;
} else {
let m = (1..t - v).find_map(|i| {
let sigma_i = dot(&syn[v + i..=2 * v + i], &tmp);
if sigma_i == GF(0) {
None
} else {
Some((i, sigma_i))
}
});
let (m, sigma_m) = if let Some((m, sigma_m)) = m {
(m, sigma_m)
} else {
break;
};
let n = m + v;
sigma.clear();
sigma.push(sigma_m);
sigma.extend((m + 1..=2 * m).map(|k| dot(&syn[v + k..=2 * v + k], &tmp)));
debug_assert_eq!(sigma.len(), m + 1);
tmp.pop(); for k in 0..=m {
let rho = syn[2 * v + k] - dot(&syn[v..=2 * v - 1], &tmp);
let eta = tmp[v - 1];
tmp.pop();
tmp.insert(0, GF(0));
for (wki, (yi, wi)) in tmp.iter_mut().zip(y.iter().zip(w.iter())) {
*wki += rho * *yi + eta * *wi;
}
}
y.clear();
y.resize(n + 1, GF(0));
let sigma_m_inv = GF(1) / sigma_m;
for (yi, w) in y.iter_mut().zip(w.iter()) {
*yi = *w * sigma_m_inv;
}
y[w.len()] = -sigma_m_inv;
gamma.clear();
gamma.extend(
(0..=m).map(|i| syn[n + v + 1 + i] - dot(&syn[v + i..=2 * v - 1 + i], &tmp)),
);
for i in 0..=m {
for j in 0..i {
let gj = gamma[j];
gamma[i] -= sigma[i - j] * gj;
}
gamma[i] /= sigma[0];
}
if cfg!(debug_assertions) {
for i in 0..=m {
let mut row = GF(0);
for j in 0..=i {
row += sigma[i - j] * gamma[j];
}
let target = syn[n + v + 1 + i] - dot(&syn[v + i..=2 * v - 1 + i], &tmp);
debug_assert_eq!(row, target, "gamma, row {}", i);
}
}
tmp.resize(n + 1, GF(0)); for (i, gamma_i) in gamma.iter().enumerate() {
for (ti, wj) in tmp[m - i..].iter_mut().zip(w.iter()) {
*ti += *gamma_i * *wj;
}
tmp[m - i + v] -= *gamma_i;
}
core::mem::swap(&mut tmp, &mut w);
v = n + 1;
}
if cfg!(debug_assertions) {
debug_assert_eq!(w.len(), v);
debug_assert_eq!(y.len(), v);
for i in 0..v {
let mut row = GF(0);
for j in 0..v {
row += syn[i + j] * y[j];
}
let target = if i == v - 1 { GF(1) } else { GF(0) };
debug_assert_eq!(row, target, "y_{}, row {}", v, i);
}
for i in 0..v {
let mut row = GF(0);
for j in 0..v {
row += syn[i + j] * w[j];
}
debug_assert_eq!(row, syn[v + i], "w_{}, row {}", v, i);
}
}
}
w.push(GF(1));
Ok(w)
}
fn find_error_values_bp(x_loc: &mut [GF], _lambda: &[GF], syn: &mut [GF]) {
let e = x_loc.len();
for z in x_loc.iter_mut() {
*z = GF(1) / *z;
}
for (k, x_loc_k) in x_loc.iter().enumerate().take(e - 1) {
for j in (k + 1..e).rev() {
let tmp = syn[j - 1];
syn[j] -= *x_loc_k * tmp;
}
}
for k in (0..e - 1).rev() {
for j in k + 1..e {
syn[j] /= x_loc[j] - x_loc[j - k - 1];
}
for j in k..e - 1 {
let tmp = syn[j + 1];
syn[j] -= tmp;
}
}
for i in 0..e {
syn[i] /= x_loc[i];
}
}
#[allow(unused)]
fn find_inv_error_locations_bm(syn: &[GF]) -> Result<Vec<GF>, ErrorDecodingError> {
let mut len_lfsr = 0; let mut cur = vec![GF(1)]; let mut prev = vec![GF(1)]; let mut l = 1; let mut discrepancy_m = GF(1); for k in 0..syn.len() {
let discrepancy = syn[k]
+ cur[1..]
.iter()
.zip(syn[..k].iter().rev())
.map(|(a, b)| *a * *b)
.sum();
if discrepancy == GF(0) {
l += 1;
} else if 2 * len_lfsr > k {
let tmp = discrepancy / discrepancy_m;
for (ci, pj) in cur[l..].iter_mut().zip(prev.iter()) {
*ci -= tmp * *pj;
}
l += 1;
} else {
let cur_clone_before = cur.clone();
let tmp = discrepancy / discrepancy_m;
cur.resize(l + prev.len(), GF(0));
for (ci, pj) in cur[l..].iter_mut().zip(prev.iter()) {
*ci -= tmp * *pj;
}
len_lfsr = k + 1 - len_lfsr;
prev = cur_clone_before;
discrepancy_m = discrepancy;
l = 1;
}
}
if cur.len() - 1 > syn.len() / 2 {
Err(ErrorDecodingError::TooManyErrors)
} else {
cur.reverse();
Ok(cur)
}
}
#[allow(unused)]
fn find_inv_error_locations_lu(syndomes: &[GF]) -> Result<Vec<GF>, ErrorDecodingError> {
let v = syndomes.len() / 2;
let mut matrix = vec![GF(0); v * v]; for i in 0..v {
for j in 0..v {
matrix[i * v + j] = syndomes[i + j];
}
}
let mut coeff = vec![];
for vi in (1..=v).rev() {
let mut m = matrix.clone();
let mut b: Vec<GF> = syndomes[vi..2 * vi].into();
debug_assert_eq!(b.len(), vi);
if super::solve(&mut m, &mut b[..vi], v) {
b.truncate(vi);
coeff = b;
break;
}
}
if coeff.is_empty() {
return Err(ErrorDecodingError::TooManyErrors);
}
coeff.push(GF(1));
Ok(coeff)
}
#[allow(unused)]
fn find_error_values_forney(inv_x_locs: &mut [GF], lambda: &[GF], syn: &mut [GF]) {
let n = syn.len();
let mut omega = vec![GF(0); n];
for (i, si) in syn.iter().copied().enumerate() {
for (j, lj) in lambda.iter().rev().take(n - i).copied().enumerate() {
omega[n - 1 - (j + i)] += lj * si;
}
}
for (x_inv, out) in inv_x_locs.iter().copied().zip(syn.iter_mut()) {
let mut omega_x = GF(0);
for o in omega.iter().copied() {
omega_x = omega_x * x_inv + o;
}
let mut lambda_der_x = GF(0);
for (k, lk) in lambda[..lambda.len() - 1].iter().copied().enumerate() {
lambda_der_x = lambda_der_x * x_inv + lk * (lambda.len() - k - 1);
}
*out = -omega_x / lambda_der_x;
}
for z in inv_x_locs.iter_mut() {
*z = GF(1) / *z;
}
}
#[test]
fn solve_vandermonde_diag() {
let mut x = [GF(28), GF(181), GF(59), GF(129), GF(189)];
for tmp in x.iter_mut() {
*tmp = GF(1) / *tmp;
}
let mut rhs = [GF(66), GF(27), GF(189), GF(255), GF(206)];
let mut y1 = rhs;
find_error_values_bp(&mut x[..], &[], &mut y1[..]);
let mut mat = [
GF(28),
GF(181),
GF(59),
GF(129),
GF(189),
GF(125),
GF(250),
GF(220),
GF(115),
GF(186),
GF(85),
GF(18),
GF(99),
GF(40),
GF(254),
GF(66),
GF(37),
GF(133),
GF(22),
GF(175),
GF(251),
GF(255),
GF(1),
GF(36),
GF(15),
];
super::solve(&mut mat, &mut rhs, x.len());
assert_eq!(&rhs[..], &y1);
}
#[test]
fn test_recovery() {
let mut data = vec![1, 2, 3];
let ecc = crate::errorcode::encode_error(&data, SymbolSize::Square10);
data.extend_from_slice(&ecc);
assert_eq!(data.len(), 3 + 5);
let mut received = data.clone();
received[0] = 230;
received[3 + 5 - 1] = 32;
decode(&mut received, SymbolSize::Square10).unwrap();
assert_eq!(&data, &received);
}
#[test]
fn test_recovery1() {
let mut data = vec![
255, 255, 255, 72, 52, 38, 52, 52, 52, 52, 52, 52, 52, 52, 52, 72, 0, 0, 72, 0, 0, 10,
];
let ecc = crate::errorcode::encode_error(&data, SymbolSize::Square20);
data.extend_from_slice(&ecc);
let mut received = data.clone();
received[0] = 52;
received[8] = 144;
decode(&mut received, SymbolSize::Square20).unwrap();
assert_eq!(&data, &received);
}
#[test]
fn test_recovery2() {
let mut data = vec![
144, 144, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255,
];
let ecc = crate::errorcode::encode_error(&data, SymbolSize::Square20);
data.extend_from_slice(&ecc);
let mut received = data.clone();
received[1] = 32;
received[0] = 0;
received[12] = 0;
received[16] = 144;
decode(&mut received, SymbolSize::Square20).unwrap();
assert_eq!(&data, &received);
}
#[test]
fn test_recovery3() {
let mut data = vec![
255, 23, 189, 54, 189, 189, 189, 189, 255, 255, 255, 255, 255, 255, 255, 67, 4, 0, 255,
189, 48, 37,
];
let ecc = crate::errorcode::encode_error(&data, SymbolSize::Square20);
data.extend_from_slice(&ecc);
let mut received = data.clone();
received[0] = 247;
received[1] = 49;
received[5] = 255;
received[6] = 0;
received[8] = 49;
received[10] = 0;
received[12] = 65;
received[15] = 177;
received[16] = 32;
decode(&mut received, SymbolSize::Square20).unwrap();
assert_eq!(&data, &received);
}
#[test]
fn test_recovery4() {
let mut data = vec![
49, 95, 49, 44, 49, 49, 0, 0, 0, 32, 255, 247, 255, 254, 189, 189, 189, 189, 189, 189, 189,
189,
];
let ecc = crate::errorcode::encode_error(&data, SymbolSize::Square20);
data.extend_from_slice(&ecc);
let mut received = data.clone();
received[1] = 49;
received[0] = 44;
received[13] = 49;
received[10] = 0;
received[8] = 101;
received[15] = 54;
received[6] = 206;
received[21] = 191;
received[5] = 50;
decode(&mut received, SymbolSize::Square20).unwrap();
assert_eq!(&data, &received);
}