ps_ecc/reed_solomon/methods/
validate.rs1use crate::{Polynomial, ReedSolomon};
2
3impl ReedSolomon {
4 #[must_use]
15 pub fn validate(&self, received: &[u8]) -> Option<Polynomial> {
16 let parity_bytes = self.parity_bytes();
17 let syndromes = Self::compute_syndromes(parity_bytes, received);
18
19 let length_is_valid = received.len() >= usize::from(parity_bytes)
20 && received.len() <= usize::from(Polynomial::MAX_COEFFICIENTS);
21
22 if length_is_valid && syndromes.is_zero() {
23 None
24 } else {
25 Some(syndromes)
26 }
27 }
28}
29
30#[cfg(test)]
31mod tests {
32 use ps_buffer::{Buffer, ToBuffer};
33
34 use crate::ReedSolomon;
35
36 type TestError = Box<dyn std::error::Error>;
37
38 #[test]
39 fn test_validate() -> Result<(), TestError> {
40 let rs = ReedSolomon::new(4)?;
41 let message = b"Hello, World!".to_buffer()?;
42 let encoded = rs.encode(&message)?;
43
44 assert!(rs.validate(&encoded).is_none());
45
46 let mut corrupted = Buffer::with_capacity(encoded.len())?;
47
48 corrupted.extend_from_slice(&encoded)?;
49 corrupted[2] ^= 1;
50
51 assert!(rs.validate(&corrupted).is_some());
52
53 Ok(())
54 }
55
56 #[test]
57 fn test_validate_no_errors() -> Result<(), TestError> {
58 let rs = ReedSolomon::new(1)?;
59 let message = b"Valid".to_buffer()?;
60 let encoded = rs.encode(&message)?;
61
62 assert!(rs.validate(&encoded).is_none());
63
64 Ok(())
65 }
66
67 #[test]
68 fn test_validate_with_errors() -> Result<(), TestError> {
69 let rs = ReedSolomon::new(1)?;
70 let message = b"Valid".to_buffer()?;
71 let encoded = rs.encode(&message)?;
72
73 let mut corrupted = encoded.clone()?;
74
75 corrupted[0] ^= 4;
76
77 assert!(rs.validate(&corrupted).is_some());
78
79 Ok(())
80 }
81
82 #[test]
83 fn test_validate_rejects_input_shorter_than_parity() -> Result<(), TestError> {
84 let rs = ReedSolomon::new(4)?;
88
89 assert!(rs.validate(&[]).is_some());
90 assert!(rs.validate(&[0u8; 7]).is_some());
91
92 Ok(())
93 }
94
95 #[test]
96 fn test_validate_rejects_input_longer_than_max_codeword() -> Result<(), TestError> {
97 let rs = ReedSolomon::new(4)?;
101
102 assert!(rs.validate(&[0u8; 256]).is_some());
103 assert!(rs.validate(&[0u8; 300]).is_some());
104
105 Ok(())
106 }
107
108 #[test]
109 fn test_validate_accepts_maximum_length_codeword() -> Result<(), TestError> {
110 let rs = ReedSolomon::new(4)?;
112
113 assert!(rs.validate(&[0u8; 255]).is_none());
114
115 Ok(())
116 }
117
118 #[test]
119 fn test_validate_accepts_parity_only_codeword() -> Result<(), TestError> {
120 let rs = ReedSolomon::new(4)?;
123
124 assert!(rs.validate(&[0u8; 8]).is_none());
125
126 Ok(())
127 }
128
129 #[test]
130 fn test_validate_zero_parity_empty_input() -> Result<(), TestError> {
131 let rs = ReedSolomon::new(0)?;
132
133 assert!(rs.validate(&[]).is_none());
134
135 Ok(())
136 }
137
138 #[test]
139 fn test_validate_large_parity() -> Result<(), TestError> {
140 let rs = ReedSolomon::new(16)?;
141 let message = b"LargeParity".to_buffer()?;
142 let encoded = rs.encode(&message)?;
143
144 assert!(rs.validate(&encoded).is_none());
145
146 let mut corrupted = encoded.clone()?;
147
148 corrupted[10] ^= 1;
149
150 assert!(rs.validate(&corrupted).is_some());
151
152 Ok(())
153 }
154}