feat: Reed-Solomon 纠错编码 + 数据交错

This commit is contained in:
2026-06-16 23:40:52 +08:00
parent fb091bfb87
commit c6c80c906c
+144 -1
View File
@@ -1 +1,144 @@
// FIXME: Reed-Solomon 编码器 — Task 4
use crate::ecc::galois;
/// 计算多项式相乘: a(x) * b(x) in GF(2⁸)
fn poly_mul(a: &[u8], b: &[u8]) -> Vec<u8> {
let mut result = vec![0u8; a.len() + b.len() - 1];
for (i, &ai) in a.iter().enumerate() {
for (j, &bj) in b.iter().enumerate() {
result[i + j] = galois::add(result[i + j], galois::mul(ai, bj));
}
}
result
}
/// 构造 RS 生成多项式: ∏ᵢ₌₀ⁿ⁻¹ (x - αⁱ)
/// 参数 n: 纠错码字数
fn generator_polynomial(n: u8) -> Vec<u8> {
let mut g = vec![1u8]; // 从 g(x) = 1 开始
for i in 0..n {
// g(x) *= (x + αⁱ) in GF(2⁸) — 注意加法和减法相同
let factor = vec![1u8, galois::pow(2, i as usize)];
g = poly_mul(&g, &factor);
}
g
}
/// 多项式长除法: message(x) * xⁿ ÷ generator(x),返回余数(即纠错码字)
/// data: 数据码字
/// ec_count: 纠错码字数量
pub fn compute_ec(data: &[u8], ec_count: u8) -> Vec<u8> {
let gen = generator_polynomial(ec_count);
// 构造被除数: data 后接 ec_count 个零
let mut dividend = vec![0u8; data.len() + ec_count as usize];
dividend[..data.len()].copy_from_slice(data);
// 多项式长除法
for i in 0..data.len() {
let coef = dividend[i];
if coef != 0 {
for (j, &g) in gen.iter().enumerate() {
dividend[i + j] = galois::add(dividend[i + j], galois::mul(coef, g));
}
}
}
// 余数 = 最后 ec_count 个系数
dividend[data.len()..].to_vec()
}
/// 对一组数据块生成纠错码字并交错排列
/// blocks: 每个数据块的内容
/// ec_count: 每块纠错码字数
/// 返回: 数据码字交错 + 纠错码字交错
pub fn interleave(blocks: &[Vec<u8>], ec_count: u8) -> Vec<u8> {
// 数据码字交错:取每块第1个,再取每块第2个...
let max_data = blocks.iter().map(|b| b.len()).max().unwrap_or(0);
let mut result = Vec::new();
for i in 0..max_data {
for block in blocks.iter() {
if i < block.len() {
result.push(block[i]);
}
}
}
// 对每个块计算 EC
let ec_blocks: Vec<Vec<u8>> = blocks
.iter()
.map(|b| compute_ec(b, ec_count))
.collect();
// EC 码字交错
for i in 0..ec_count as usize {
for ec in ec_blocks.iter() {
result.push(ec[i]);
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generator_polynomial_degree() {
let g = generator_polynomial(7);
// 7 个纠错码字 → 生成多项式应为 7 次,共 8 个系数
assert_eq!(g.len(), 8);
// 首项系数应为 1 (x⁷ 的系数)
assert_eq!(g[0], 1);
}
#[test]
fn test_compute_ec_zero_data() {
// 全零数据 + EC → EC 应全零
let ec = compute_ec(&vec![0u8; 19], 7);
assert_eq!(ec, vec![0u8; 7]);
}
#[test]
fn test_compute_ec_length() {
let data = vec![
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
];
let ec = compute_ec(&data, 10);
// EC 码字数量应等于 ec_count
assert_eq!(ec.len(), 10);
}
#[test]
fn test_compute_ec_nonzero() {
// 非零数据应产生非零 EC
let data = vec![
0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11,
0xEC, 0x11, 0xA3, 0x12, 0xD3,
];
let ec = compute_ec(&data, 7);
assert_eq!(ec.len(), 7);
// 非零数据 + 非零多项式 → EC 不应全零
assert!(ec.iter().any(|&x| x != 0));
}
#[test]
fn test_interleave_basic() {
let b1 = vec![1, 2, 3];
let b2 = vec![4, 5];
// 数据交错: 1, 4, 2, 5, 3
// EC 交错: b1_ec[0], b2_ec[0], b1_ec[1], b2_ec[1], ...
let result = interleave(&[b1, b2], 2);
// 前 5 个是数据交错
assert_eq!(&result[..5], &[1, 4, 2, 5, 3]);
}
#[test]
fn test_interleave_single_block() {
let b1 = vec![10, 20, 30];
let result = interleave(&[b1.clone()], 3);
// 单个块: 数据直接输出 + 3 个 EC
assert_eq!(&result[..3], &[10, 20, 30]);
assert_eq!(result.len(), 6); // 3 data + 3 ec
}
}