feat: Reed-Solomon 纠错编码 + 数据交错
This commit is contained in:
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user