pub(super) struct Gf {
size: usize,
pub fcr: usize,
exp: Vec<usize>,
log: Vec<usize>,
}
impl Gf {
pub fn new(primitive: usize, size: usize, fcr: usize) -> Gf {
let mut exp = vec![0usize; size * 2];
let mut log = vec![0usize; size];
let mut x = 1usize;
for (i, e) in exp.iter_mut().enumerate().take(size) {
*e = x;
log[x] = i;
x <<= 1;
if x >= size {
x ^= primitive;
x &= size - 1;
}
}
for i in size..size * 2 {
exp[i] = exp[i - size + 1];
}
Gf {
size,
fcr,
exp,
log,
}
}
pub fn f16() -> Gf {
Gf::new(0x13, 16, 0)
}
pub fn f256() -> Gf {
Gf::new(0x11D, 256, 1)
}
#[inline]
pub fn exp(&self, a: usize) -> usize {
self.exp[a]
}
#[inline]
pub fn mul(&self, a: usize, b: usize) -> usize {
if a == 0 || b == 0 {
return 0;
}
self.exp[self.log[a] + self.log[b]]
}
#[inline]
pub fn inv(&self, a: usize) -> usize {
self.exp[self.size - 1 - self.log[a]]
}
pub fn pow(&self, exponent: isize) -> usize {
let order = (self.size - 1) as isize;
let mut e = exponent % order;
if e < 0 {
e += order;
}
self.exp[e as usize]
}
}
pub(super) fn rs_encode(gf: &Gf, data: &[usize], num_parity: usize) -> Vec<usize> {
let mut genpoly = vec![1usize];
for i in 0..num_parity {
let root = gf.exp(gf.fcr + i);
let mut next = vec![0usize; genpoly.len() + 1];
next[..genpoly.len()].copy_from_slice(&genpoly);
for (j, &g) in genpoly.iter().enumerate() {
next[j + 1] ^= gf.mul(g, root);
}
genpoly = next;
}
let mut out = vec![0usize; data.len() + num_parity];
out[..data.len()].copy_from_slice(data);
for i in 0..data.len() {
let coef = out[i];
if coef != 0 {
for j in 1..=num_parity {
out[i + j] ^= gf.mul(genpoly[j], coef);
}
}
}
out[..data.len()].copy_from_slice(data);
out
}
pub(super) fn rs_decode(gf: &Gf, codeword: &[usize], num_parity: usize) -> Option<Vec<usize>> {
if num_parity == 0 {
return Some(codeword.to_vec());
}
let syn = syndromes(gf, codeword, num_parity);
if syn.iter().all(|&s| s == 0) {
return Some(codeword.to_vec());
}
if let Some(fixed) = correct_single(gf, codeword, &syn) {
return Some(fixed);
}
if num_parity >= 4
&& let Some(fixed) = correct_double(gf, codeword, &syn)
{
return Some(fixed);
}
None
}
fn syndromes(gf: &Gf, codeword: &[usize], num_parity: usize) -> Vec<usize> {
(0..num_parity)
.map(|si| {
let root = gf.pow((gf.fcr + si) as isize);
codeword
.iter()
.fold(0usize, |acc, &sym| gf.mul(acc, root) ^ sym)
})
.collect()
}
fn error_term(gf: &Gf, n: usize, pos: usize, si: usize) -> usize {
gf.pow(((gf.fcr + si) * (n - 1 - pos)) as isize)
}
fn correct_single(gf: &Gf, codeword: &[usize], syn: &[usize]) -> Option<Vec<usize>> {
let n = codeword.len();
for pos in 0..n {
let a0 = error_term(gf, n, pos, 0);
if a0 == 0 {
continue;
}
let mag = gf.mul(syn[0], gf.inv(a0));
if mag == 0 {
continue;
}
if syn
.iter()
.enumerate()
.all(|(si, &s)| gf.mul(mag, error_term(gf, n, pos, si)) == s)
{
let mut out = codeword.to_vec();
out[pos] ^= mag;
if syndromes(gf, &out, syn.len()).iter().all(|&s| s == 0) {
return Some(out);
}
}
}
None
}
fn correct_double(gf: &Gf, codeword: &[usize], syn: &[usize]) -> Option<Vec<usize>> {
let n = codeword.len();
if syn.len() < 2 {
return None;
}
for p in 0..n {
for q in p + 1..n {
let (a0, b0) = (error_term(gf, n, p, 0), error_term(gf, n, q, 0));
let (a1, b1) = (error_term(gf, n, p, 1), error_term(gf, n, q, 1));
let det = gf.mul(a0, b1) ^ gf.mul(a1, b0);
if det == 0 {
continue;
}
let inv = gf.inv(det);
let ep = gf.mul(gf.mul(syn[0], b1) ^ gf.mul(syn[1], b0), inv);
let eq = gf.mul(gf.mul(a0, syn[1]) ^ gf.mul(a1, syn[0]), inv);
if ep == 0 || eq == 0 {
continue;
}
let ok = syn.iter().enumerate().all(|(si, &s)| {
gf.mul(ep, error_term(gf, n, p, si)) ^ gf.mul(eq, error_term(gf, n, q, si)) == s
});
if !ok {
continue;
}
let mut out = codeword.to_vec();
out[p] ^= ep;
out[q] ^= eq;
if syndromes(gf, &out, syn.len()).iter().all(|&s| s == 0) {
return Some(out);
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn field_basics() {
let gf = Gf::f256();
assert_eq!(gf.exp(0), 1);
assert_eq!(gf.exp(1), 2);
assert_eq!(gf.exp(255), gf.exp(0));
assert_eq!(gf.mul(0, 5), 0);
assert_eq!(gf.mul(1, 5), 5);
}
#[test]
fn rs_roundtrip_with_errors() {
let gf = Gf::f256();
let data = [12usize, 34, 56, 78, 90, 11, 22, 33, 44];
let mut cw = rs_encode(&gf, &data, 4);
assert_eq!(rs_decode(&gf, &cw, 4).unwrap()[..9], data);
cw[3] ^= 0x5a; assert_eq!(rs_decode(&gf, &cw, 4).unwrap()[..9], data);
cw[10] ^= 0x11; assert_eq!(rs_decode(&gf, &cw, 4).unwrap()[..9], data);
}
#[test]
fn zero_data_zero_parity() {
let gf = Gf::f256();
let cw = rs_encode(&gf, &[0, 0, 0, 0, 0], 2);
assert_eq!(cw, vec![0; 7]);
}
}