Skip to main content

ps_ecc/reed_solomon/methods/
compute_syndromes.rs

1use crate::finite_field::ANTILOG_TABLE;
2use crate::{Polynomial, ReedSolomon};
3
4impl ReedSolomon {
5    /// Computes the syndromes of a given codeword.
6    #[must_use]
7    pub fn compute_syndromes(num_parity_bytes: u8, received: &[u8]) -> Polynomial {
8        let num_parity_bytes = num_parity_bytes.into();
9
10        (0..num_parity_bytes)
11            .map(|i| Polynomial::eval_coefficients_at(received, ANTILOG_TABLE[i + 1].get()))
12            .collect()
13    }
14}
15
16#[cfg(test)]
17mod tests {
18    use ps_buffer::ToBuffer;
19
20    use crate::ReedSolomon;
21
22    type TestError = Box<dyn std::error::Error>;
23
24    #[test]
25    fn test_compute_syndromes_no_errors() -> Result<(), TestError> {
26        let rs = ReedSolomon::new(2)?;
27        let message = b"Syndrome".to_buffer()?;
28        let encoded = rs.encode(&message)?;
29
30        let syndromes = ReedSolomon::compute_syndromes(rs.parity_bytes(), &encoded);
31
32        assert!(syndromes.is_zero());
33
34        Ok(())
35    }
36
37    #[test]
38    fn test_compute_syndromes_with_errors() -> Result<(), TestError> {
39        let rs = ReedSolomon::new(2)?;
40        let message = b"Syndrome".to_buffer()?;
41        let encoded = rs.encode(&message)?;
42
43        let mut corrupted = encoded.clone()?;
44
45        corrupted[0] ^= 1;
46
47        let syndromes = ReedSolomon::compute_syndromes(rs.parity_bytes(), &corrupted);
48
49        assert!(syndromes.iter().any(|&s| s != 0));
50
51        Ok(())
52    }
53
54    #[test]
55    fn test_compute_syndromes_empty_codeword() {
56        let syndromes = ReedSolomon::compute_syndromes(4u8, &[]);
57
58        assert_eq!(syndromes.degree(), 0);
59        assert!(syndromes.is_zero());
60    }
61
62    /// Tests that single-error syndromes have no trailing zeros.
63    ///
64    /// A single error at position j produces syndrome `S_i` = e * α^(i*j), which is
65    /// non-zero for all i when e ≠ 0. Thus `coefficients()` equals `first_n_coefficients()`.
66    #[test]
67    fn test_single_error_syndrome_length() -> Result<(), TestError> {
68        let rs = ReedSolomon::new(3)?;
69        let message = b"Hello".to_buffer()?;
70        let encoded = rs.encode(&message)?;
71        let parity_bytes: usize = rs.parity_bytes().into();
72
73        // Single error - should always be correctable with t=3
74        let mut corrupted = encoded.clone()?;
75
76        corrupted[0] ^= 1;
77
78        let syndromes = ReedSolomon::compute_syndromes(rs.parity_bytes(), &corrupted);
79
80        // The full syndrome vector should have exactly parity_bytes elements
81        let full = syndromes.first_n_coefficients(parity_bytes);
82
83        assert_eq!(full.len(), parity_bytes);
84
85        // For a single error, coefficients() has no trailing zeros to trim,
86        // so it equals first_n_coefficients() in length.
87        let trimmed = syndromes.coefficients();
88
89        assert_eq!(
90            trimmed.len(),
91            parity_bytes,
92            "coefficients() returned {} elements, expected {}",
93            trimmed.len(),
94            parity_bytes
95        );
96
97        Ok(())
98    }
99}