use super::galois::{self, EXP};
pub fn generator_poly(k: usize) -> Vec<u8> {
let mut g = vec![1u8];
for i in 0..k {
let alpha_i = EXP[i];
let mut new_g = vec![0u8; g.len() + 1];
for (j, &gj) in g.iter().enumerate() {
new_g[j] ^= gj; new_g[j + 1] ^= galois::mul(gj, alpha_i); }
g = new_g;
}
g
}
pub fn encode(data: &[u8], k: usize) -> Vec<u8> {
let g = generator_poly(k);
let mut buf = vec![0u8; data.len() + k];
buf[..data.len()].copy_from_slice(data);
for i in 0..data.len() {
let coef = buf[i];
if coef != 0 {
for j in 0..=k {
buf[i + j] ^= galois::mul(g[j], coef);
}
}
}
buf[data.len()..].to_vec()
}
fn poly_add(a: &[u8], b: &[u8]) -> Vec<u8> {
let n = a.len().max(b.len());
let mut r = vec![0u8; n];
for (i, &v) in a.iter().enumerate() {
r[i + n - a.len()] ^= v;
}
for (i, &v) in b.iter().enumerate() {
r[i + n - b.len()] ^= v;
}
r
}
fn poly_mul(a: &[u8], b: &[u8]) -> Vec<u8> {
let mut r = vec![0u8; a.len() + b.len() - 1];
for (i, &av) in a.iter().enumerate() {
if av == 0 {
continue;
}
for (j, &bv) in b.iter().enumerate() {
r[i + j] ^= galois::mul(av, bv);
}
}
r
}
fn poly_eval(p: &[u8], x: u8) -> u8 {
let mut y = 0u8;
for &c in p {
y = galois::mul(y, x) ^ c;
}
y
}
fn poly_scale(p: &[u8], s: u8) -> Vec<u8> {
p.iter().map(|&c| galois::mul(c, s)).collect()
}
fn syndromes(received: &[u8], k: usize) -> Vec<u8> {
(0..k).map(|i| poly_eval(received, EXP[i])).collect()
}
fn berlekamp_massey(syndromes: &[u8]) -> Vec<u8> {
let mut c: Vec<u8> = vec![1];
let mut b: Vec<u8> = vec![1];
let mut l: usize = 0; let mut m: usize = 1; let mut bb: u8 = 1;
for n in 0..syndromes.len() {
let mut d = syndromes[n];
for i in 1..=l {
let ci = c[c.len() - 1 - i];
d ^= galois::mul(ci, syndromes[n - i]);
}
if d == 0 {
m += 1;
} else if 2 * l <= n {
let t = c.clone();
let scale = galois::div(d, bb);
let shifted = {
let mut tmp = b.clone();
tmp.extend(std::iter::repeat(0u8).take(m));
tmp
};
let term = poly_scale(&shifted, scale);
c = poly_add(&c, &term);
l = n + 1 - l;
b = t;
bb = d;
m = 1;
} else {
let scale = galois::div(d, bb);
let shifted = {
let mut tmp = b.clone();
tmp.extend(std::iter::repeat(0u8).take(m));
tmp
};
let term = poly_scale(&shifted, scale);
c = poly_add(&c, &term);
m += 1;
}
}
while c.len() > 1 && c[0] == 0 {
c.remove(0);
}
c
}
fn chien_search(lambda: &[u8], n: usize) -> Vec<usize> {
let mut positions = Vec::new();
for p in 0..n {
let x = EXP[(255 - p as i32).rem_euclid(255) as usize];
if poly_eval(lambda, x) == 0 {
positions.push(p);
}
}
positions
}
fn forney(syndromes: &[u8], lambda: &[u8], positions: &[usize], n: usize) -> Vec<u8> {
let k = syndromes.len();
let s_high_first: Vec<u8> = syndromes.iter().rev().copied().collect();
let prod = poly_mul(&s_high_first, lambda);
let omega_start = prod.len().saturating_sub(k);
let omega: Vec<u8> = prod[omega_start..].to_vec();
let mut lambda_prime = vec![0u8; lambda.len() - 1];
let deg = lambda.len() - 1;
for i in 1..=deg {
if i % 2 == 1 {
lambda_prime[(lambda.len() - 1) - i] = lambda[deg - i];
}
}
let mut magnitudes = Vec::with_capacity(positions.len());
for &p in positions {
let xi = EXP[(255 - p as i32).rem_euclid(255) as usize];
let num = poly_eval(&omega, xi);
let den = poly_eval(&lambda_prime, xi);
debug_assert!(den != 0, "Λ' 在错位处不应为零");
let x_p = EXP[p % 255];
let mag = galois::mul(x_p, galois::div(num, den));
magnitudes.push(mag);
let _ = n;
}
magnitudes
}
pub fn decode(received: &[u8], k: usize) -> Result<Vec<u8>, &'static str> {
let n = received.len();
if n <= k {
return Err("received too short");
}
let s = syndromes(received, k);
if s.iter().all(|&x| x == 0) {
return Ok(received[..n - k].to_vec());
}
let lambda = berlekamp_massey(&s);
let positions = chien_search(&lambda, n);
let expected_errors = lambda.len() - 1; if positions.len() != expected_errors {
return Err("decoder failed: could not locate all errors");
}
let mags = forney(&s, &lambda, &positions, n);
let mut corrected = received.to_vec();
for (&p, &m) in positions.iter().zip(mags.iter()) {
corrected[n - 1 - p] ^= m;
}
let s2 = syndromes(&corrected, k);
if !s2.iter().all(|&x| x == 0) {
return Err("decoder failed: residual syndrome");
}
Ok(corrected[..n - k].to_vec())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encode_qr_v1m_reference_vector() {
let data = [
0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11,
0xEC, 0x11,
];
let expected_ec = [0xA5, 0x24, 0xD4, 0xC1, 0xED, 0x36, 0xC7, 0x87, 0x2C, 0x55];
let ec = encode(&data, 10);
assert_eq!(ec, expected_ec);
}
#[test]
fn generator_poly_small() {
assert_eq!(generator_poly(0), vec![1]);
assert_eq!(generator_poly(1), vec![1, 1]); assert_eq!(generator_poly(2), vec![1, 3, 2]);
}
#[test]
fn encode_then_decode_no_error() {
let data: Vec<u8> = (0..20).map(|i| (i * 7 + 13) as u8).collect();
let k = 8;
let ec = encode(&data, k);
let mut received = data.clone();
received.extend(&ec);
let recovered = decode(&received, k).unwrap();
assert_eq!(recovered, data);
}
#[test]
fn decode_corrects_single_error() {
let data: Vec<u8> = (0..16).map(|i| (i * 11 + 3) as u8).collect();
let k = 8; let ec = encode(&data, k);
let mut received = data.clone();
received.extend(&ec);
received[5] ^= 0xAB; let recovered = decode(&received, k).unwrap();
assert_eq!(recovered, data);
}
#[test]
fn decode_corrects_multiple_errors() {
let data: Vec<u8> = (0..16).map(|i| (i * 11 + 3) as u8).collect();
let k = 10; let ec = encode(&data, k);
let mut received = data.clone();
received.extend(&ec);
received[0] ^= 0x01;
received[3] ^= 0xFF;
received[10] ^= 0x80;
received[20] ^= 0x55; let recovered = decode(&received, k).unwrap();
assert_eq!(recovered, data);
}
#[test]
fn decode_fails_on_too_many_errors() {
let data: Vec<u8> = (0..16).map(|i| (i * 11 + 3) as u8).collect();
let k = 4; let ec = encode(&data, k);
let mut received = data.clone();
received.extend(&ec);
received[0] ^= 0x01;
received[1] ^= 0x02;
received[2] ^= 0x04;
let result = decode(&received, k);
if let Ok(r) = result {
assert_ne!(r, data);
}
}
}