ps_ecc/reed_solomon/methods/
validate_detached.rs1use crate::{Polynomial, RSConstructorError, ReedSolomon};
2
3impl ReedSolomon {
4 pub fn validate_detached(
21 parity: &[u8],
22 data: &[u8],
23 ) -> Result<Option<Polynomial>, RSConstructorError> {
24 let syndromes = Self::compute_syndromes_detached(parity, data)?;
25
26 let length_is_valid =
27 parity.len() + data.len() <= usize::from(Polynomial::MAX_COEFFICIENTS);
28
29 if length_is_valid && syndromes.is_zero() {
30 Ok(None)
31 } else {
32 Ok(Some(syndromes))
33 }
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use ps_buffer::{Buffer, ToBuffer};
40
41 use crate::{RSConstructorError, ReedSolomon};
42
43 type TestError = Box<dyn std::error::Error>;
44
45 #[test]
46 fn test_validate_detached() -> Result<(), TestError> {
47 let rs = ReedSolomon::new(4)?;
48 let message = b"Hello, World!".to_buffer()?;
49 let parity = rs.generate_parity(&message)?;
50
51 assert!(ReedSolomon::validate_detached(&parity, &message)?.is_none());
52
53 let mut corrupted = Buffer::with_capacity(message.len())?;
54
55 corrupted.extend_from_slice(&message)?;
56 corrupted[2] ^= 1;
57
58 assert!(ReedSolomon::validate_detached(&parity, &corrupted)?.is_some());
59
60 Ok(())
61 }
62
63 #[test]
64 fn test_validate_detached_no_errors_case_2() -> Result<(), TestError> {
65 let rs = ReedSolomon::new(2)?;
66 let message = b"Detached2".to_buffer()?;
67 let parity = rs.generate_parity(&message)?;
68
69 assert!(ReedSolomon::validate_detached(&parity, &message)?.is_none());
70
71 Ok(())
72 }
73
74 #[test]
75 fn test_validate_detached_with_errors_case_2() -> Result<(), TestError> {
76 let rs = ReedSolomon::new(2)?;
77 let message = b"Detached2".to_buffer()?;
78 let parity = rs.generate_parity(&message)?;
79
80 let mut corrupted = message.clone()?;
81
82 corrupted[1] ^= 8;
83
84 assert!(ReedSolomon::validate_detached(&parity, &corrupted)?.is_some());
85
86 Ok(())
87 }
88
89 #[test]
90 fn test_validate_detached_rejects_odd_parity_length() {
91 let parity = [0u8; 3];
92
93 assert_eq!(
94 ReedSolomon::validate_detached(&parity, &[]),
95 Err(RSConstructorError::OddParityLength(3))
96 );
97 }
98
99 #[test]
100 fn test_validate_detached_empty_parity_is_trivially_valid() -> Result<(), TestError> {
101 assert!(ReedSolomon::validate_detached(&[], b"anything")?.is_none());
102
103 Ok(())
104 }
105
106 #[test]
107 fn test_validate_detached_rejects_oversized_combined_length() -> Result<(), TestError> {
108 assert!(ReedSolomon::validate_detached(&[0u8; 4], &[0u8; 252])?.is_some());
112
113 Ok(())
114 }
115
116 #[test]
117 fn test_validate_detached_accepts_maximum_combined_length() -> Result<(), TestError> {
118 assert!(ReedSolomon::validate_detached(&[0u8; 4], &[0u8; 251])?.is_none());
120
121 Ok(())
122 }
123
124 #[test]
125 fn test_validate_detached_rejects_oversized_parity() {
126 for parity_len in [127usize, 256, 300] {
129 let parity = vec![0u8; parity_len];
130
131 assert_eq!(
132 ReedSolomon::validate_detached(&parity, &[]),
133 Err(RSConstructorError::ParityTooHigh)
134 );
135 }
136 }
137}