1pub mod dual_basis;
10pub mod gf;
11
12pub const N: u8 = 255;
14#[allow(unused)]
16pub const J: u8 = 8;
17#[allow(unused)]
19pub const PRIM: i32 = 391;
20pub const GEN: u8 = 173;
22pub const FCR: i32 = 112;
24pub const PARITY_LEN: usize = 32;
26
27#[derive(Debug, PartialEq, Clone)]
29pub enum RSState {
30 Ok,
32 Corrected(i32),
34 Uncorrectable(String),
37 NotPerformed,
38}
39
40fn correct_errata(input: &[u8], synd: &[u8], errpos: &[i32]) -> Result<Vec<u8>, &'static str> {
41 let mut coef_pos = vec![0i32; errpos.len()];
42 for (i, p) in errpos.iter().enumerate() {
43 coef_pos[i] = input.len() as i32 - 1 - p;
44 }
45
46 let errloc = find_errata_locator(&coef_pos[..]);
47 let mut rev_synd = synd.to_owned();
48 rev_synd.reverse();
49 let mut erreval = find_error_evaluator(&rev_synd, &errloc, errloc.len() as i32 - 1);
50 erreval.reverse();
51
52 let mut x = vec![0u8; coef_pos.len()];
53 for (i, p) in coef_pos.iter().enumerate() {
54 x[i] = gf::pow(GEN as u8, -(N as i32 - p));
55 }
56
57 let mut e = vec![0u8; input.len()];
58 for (i, xi) in x.iter().enumerate() {
59 let xi_inv = gf::inv(*xi);
60 let mut errloc_prime_tmp: Vec<u8> = Vec::new();
61 for j in 0..x.len() {
62 if j != i {
63 errloc_prime_tmp.push(1 ^ gf::mult(xi_inv, x[j]));
64 }
65 }
66 let mut errloc_prime = 1u8;
67 for c in errloc_prime_tmp.iter() {
68 errloc_prime = gf::mult(errloc_prime, *c);
69 }
70
71 let mut erreval_rev = erreval.to_owned();
72 erreval_rev.reverse();
73 let mut y = gf::poly_eval(&erreval_rev, xi_inv);
74 y = gf::mult(gf::pow(*xi, 1 - FCR), y);
75
76 if errloc_prime == 0 {
77 return Err("failed to find error magnitude");
78 }
79
80 e[errpos[i] as usize] = gf::div(y, errloc_prime);
81 }
82
83 let zult = &gf::poly_add(&input, &e);
84 Ok(zult.to_vec())
85}
86
87fn find_errata_locator(errpos: &[i32]) -> Vec<u8> {
88 let mut errloc = vec![1u8];
89 for p in errpos.iter() {
90 let x = &[gf::pow(GEN as u8, *p), 0];
91 let y = gf::poly_add(&[1u8], x);
92 errloc = gf::poly_mult(&errloc, &y);
93 }
94 errloc
95}
96
97fn find_error_evaluator(synd: &[u8], errloc: &[u8], n: i32) -> Vec<u8> {
98 let mut divisor: Vec<u8> = vec![0u8; n as usize + 2];
99 divisor[0] = 1;
100 let (_, rem) = gf::poly_div(&gf::poly_mult(&synd, &errloc), &divisor);
101 rem
102}
103
104fn find_errors(errloc: &[u8]) -> Vec<i32> {
105 let num_errs = errloc.len() - 1;
106 let mut errpos: Vec<i32> = Vec::with_capacity(num_errs);
107 let n = N as i32;
108 for i in 0..n {
109 if gf::poly_eval(errloc, gf::pow(GEN, i as i32)) == 0 {
110 errpos.push(N as i32 - 1 - i);
111 }
112 }
113 errpos
114}
115
116fn find_error_locator(synd: &[u8], parity_len: usize) -> Vec<u8> {
117 let mut errloc = vec![1u8];
118 let mut oldloc = vec![1u8];
119 let mut synd_shift = 0;
120 if synd.len() > parity_len {
121 synd_shift = synd.len() - parity_len;
122 }
123 for i in 0..parity_len {
124 let k = i as usize + synd_shift;
125 let mut delta = synd[k];
126 for j in 1..errloc.len() {
127 delta ^= gf::mult(errloc[errloc.len() - j - 1], synd[k - j]);
128 }
129 oldloc.push(0);
130 if delta != 0 {
131 if oldloc.len() > errloc.len() {
132 let newloc = gf::poly_scale(&oldloc, delta);
133 oldloc = gf::poly_scale(&errloc, gf::inv(delta));
134 errloc = newloc;
135 }
136 errloc = gf::poly_add(&errloc, &gf::poly_scale(&oldloc, delta));
137 }
138 }
139
140 while errloc.len() > 0 && errloc[0] == 0 {
141 errloc = errloc[1..].to_vec();
142 }
143
144 errloc
145}
146
147fn forney_syndromes(synd: &[u8], pos: &[i32], nmess: i32) -> Vec<u8> {
148 let mut erase_pos_rev = vec![0i32; pos.len()];
149 for (i, p) in pos.iter().enumerate() {
150 erase_pos_rev[i] = nmess - 1 - p;
151 }
152 let mut fsynd: Vec<u8> = Vec::with_capacity(synd.len() - 1);
153 fsynd.extend_from_slice(&synd[1..]);
154 for i in 0..pos.len() {
155 let x = gf::pow(GEN as u8, erase_pos_rev[i]);
156 for j in 0..fsynd.len() - 1 {
157 fsynd[j] = gf::mult(fsynd[j], x) ^ fsynd[j + 1];
158 }
159 }
160 fsynd
161}
162
163fn calc_syndromes(input: &[u8], parity_len: usize) -> Vec<u8> {
164 let mut synd: Vec<u8> = vec![0u8; parity_len + 1];
165 for i in 0..parity_len {
166 let p = gf::pow(GEN, i as i32 + FCR);
167 synd[i + 1] = gf::poly_eval(&input, p);
168 }
169 synd
170}
171
172pub struct Block {
173 pub state: RSState,
175 pub message: Option<Vec<u8>>,
177}
178
179pub fn correct_message(input: &[u8]) -> Block {
189 let input = input.to_vec();
190 if input.len() != N as usize {
191 return Block {
192 state: RSState::Uncorrectable("invalid input".to_owned()),
193 message: None,
194 };
195 }
196 let out = dual_basis::to_conv(&input).clone();
197
198 let synd = calc_syndromes(&out, PARITY_LEN);
199 let max = synd.iter().max().unwrap();
200 if *max == 0 {
202 return Block {
203 state: RSState::Ok,
204 message: Some(input),
205 };
206 }
207
208 let fsynd = forney_syndromes(&synd, &[], out.len() as i32);
209 let errloc = find_error_locator(&fsynd[..], PARITY_LEN);
210
211 let num_errs = errloc.len() - 1;
212 if num_errs * 2 > PARITY_LEN {
213 return Block {
214 state: RSState::Uncorrectable(format!(
215 "too many errors to correct; expected no more than {:?}, found {:?}",
216 PARITY_LEN / 2,
217 num_errs
218 ))
219 .to_owned(),
220 message: None,
221 };
222 }
223
224 let mut errloc_rev = errloc.clone();
225 errloc_rev.reverse();
226 let errpos = find_errors(&errloc_rev[..]);
227 if errpos.len() != num_errs {
228 return Block {
229 state: RSState::Uncorrectable(
230 format!(
231 "failed to generate error positions; expected {} postions, got {}",
232 num_errs,
233 errpos.len()
234 )
235 .to_owned(),
236 ),
237 message: None,
238 };
239 }
240
241 let out = match correct_errata(&out, &synd, &errpos) {
242 Err(err) => {
243 return Block {
244 state: RSState::Uncorrectable(err.to_owned()),
245 message: None,
246 }
247 }
248 Ok(block) => block,
249 };
250
251 let synd = calc_syndromes(&out, PARITY_LEN);
252 if *synd.iter().max().unwrap() > 0 {
253 return Block {
254 state: RSState::Uncorrectable("failed to correct all errors".to_owned()),
255 message: None,
256 };
257 }
258
259 Block {
260 state: RSState::Corrected(errloc.len() as i32 - 1),
261 message: Some(dual_basis::to_dual(&out)),
262 }
263}
264
265pub fn has_errors(msg: &[u8]) -> bool {
267 let msg = dual_basis::to_conv(msg);
268 let mut x = 0;
269 for i in calc_syndromes(&msg[..], PARITY_LEN) {
270 if i > x {
271 x = i;
272 }
273 }
274 x != 0
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 const FIXTURE_MSG: &[u8; 255] = &[
283 0x67, 0xc4, 0x6b, 0xa7, 0x3e, 0xbe, 0x4c, 0x33, 0x6c, 0xb2, 0x23, 0x3a, 0x74, 0x06, 0x2b,
284 0x18, 0xab, 0xb8, 0x09, 0xe6, 0x7d, 0xaf, 0x5d, 0xe5, 0xdf, 0x76, 0x25, 0x3f, 0xb9, 0x14,
285 0xee, 0xec, 0xd1, 0xa3, 0x39, 0x5f, 0x38, 0x68, 0xf0, 0x26, 0xa6, 0x8a, 0xcb, 0x09, 0xaf,
286 0x4e, 0xf8, 0x93, 0xf7, 0x45, 0x4b, 0x0d, 0xa9, 0xb8, 0x74, 0x0e, 0xf3, 0xc7, 0xed, 0x6e,
287 0xa3, 0x0f, 0xf6, 0x79, 0x94, 0x16, 0xe2, 0x7f, 0xad, 0x91, 0x91, 0x04, 0xac, 0xa4, 0xae,
288 0xb4, 0x51, 0x76, 0x2f, 0x62, 0x03, 0x5e, 0xa1, 0xe5, 0x5c, 0x45, 0xf8, 0x1f, 0x7a, 0x7b,
289 0xe8, 0x35, 0xd8, 0xcc, 0x51, 0x0e, 0xae, 0x3a, 0x2a, 0x64, 0x1d, 0x03, 0x10, 0xcd, 0x18,
290 0xe6, 0x7f, 0xef, 0xba, 0xd9, 0xe8, 0x98, 0x47, 0x82, 0x9c, 0xa1, 0x58, 0x47, 0x25, 0xdf,
291 0x41, 0xd2, 0x01, 0x62, 0x3c, 0x24, 0x88, 0x90, 0xe9, 0xd7, 0x38, 0x1b, 0xa0, 0xa2, 0xb4,
292 0x23, 0xea, 0x7e, 0x58, 0x0d, 0xf4, 0x61, 0x24, 0x14, 0xb0, 0x41, 0x90, 0x0c, 0xb7, 0xbb,
293 0x5c, 0x59, 0x1b, 0xc6, 0x69, 0x24, 0x0f, 0xb6, 0x0e, 0x14, 0xa1, 0xb1, 0x8e, 0x48, 0x0f,
294 0x17, 0x1d, 0xfb, 0x0f, 0x38, 0x42, 0xe3, 0x24, 0x58, 0xab, 0x82, 0xa8, 0xfd, 0xdf, 0xac,
295 0x68, 0x93, 0x3d, 0x0d, 0x8f, 0x50, 0x52, 0x44, 0x6c, 0xba, 0xd3, 0x51, 0x99, 0x9c, 0x3e,
296 0xad, 0xd5, 0xa8, 0xd7, 0x9d, 0xc7, 0x7f, 0x9f, 0xc9, 0x2a, 0xac, 0xe5, 0xc2, 0xcd, 0x9a,
297 0x9b, 0xfa, 0x2d, 0x72, 0xab, 0x6b, 0xa4, 0x6b, 0x8b, 0x7d, 0xfa, 0x6c, 0x83, 0x63, 0x77,
298 0x9f, 0x4e, 0x9a, 0x20, 0x35, 0xd2, 0x91, 0xce, 0xf4, 0x21, 0x1a, 0x97, 0x3c, 0x1a, 0x15,
299 0x9d, 0xfc, 0x98, 0xba, 0x72, 0x1b, 0x9a, 0xa2, 0xe9, 0xc9, 0x46, 0x68, 0xce, 0xad, 0x27,
300 ];
301
302 #[test]
303 fn test_calc_syndromes() {
304 const EXPECTED: &[u8] = &[
305 0x00, 0xb7, 0xd5, 0x62, 0x7b, 0xf5, 0xa0, 0x52, 0x91, 0xc1, 0xd2, 0x97, 0xd0, 0x40,
306 0x68, 0x59, 0x0d, 0xcb, 0xc0, 0x84, 0x84, 0x68, 0xa6, 0xd9, 0x79, 0xf9, 0xad, 0x4c,
307 0x81, 0x9f, 0x14, 0x2f, 0x78,
308 ];
309
310 let zult = calc_syndromes(FIXTURE_MSG, PARITY_LEN);
311
312 for ((i, z), e) in zult.iter().enumerate().zip(EXPECTED.iter()) {
313 assert_eq!(
314 z, e,
315 "not all elements equal: expected {}, got {} at index {}\n{:?}",
316 e, z, i, zult
317 );
318 }
319 }
320
321 #[test]
322 fn test_correct_message_noerrors() {
323 let msg = FIXTURE_MSG.clone();
324
325 assert!(!has_errors(&msg), "expected message not to have errors");
326
327 let block = correct_message(&msg);
328
329 assert_eq!(block.message.unwrap().len(), 255);
330 assert_eq!(
331 block.state,
332 RSState::Ok,
333 "correcting a message with no errors should be Ok"
334 );
335 }
336
337 #[test]
338 fn test_correct_message_introduced_errors() {
339 let mut msg = FIXTURE_MSG.clone();
340
341 msg[0] = 0;
343 msg[2] = 2;
344 msg[4] = 2;
345 msg[6] = 2;
346
347 assert!(has_errors(&msg), "expected message to have errors");
348
349 let block = correct_message(&msg);
350 assert_eq!(block.message.unwrap().len(), 255);
351 assert_eq!(block.state, RSState::Corrected(4));
352 }
353
354 #[test]
355 fn test_correct_message2() {
356 let msg = vec![
359 0x67, 0x4c, 0x00, 0xff, 0xff, 0x80, 0x02, 0xf8, 0x7f, 0x01, 0xf7, 0x4f, 0xb5, 0x65,
360 0x14, 0x29, 0xfd, 0x68, 0x38, 0x9e, 0x6a, 0xca, 0x28, 0x53, 0xfa, 0xd0, 0x71, 0x3d,
361 0xd4, 0x95, 0x50, 0xa6, 0xf4, 0xa0, 0xe2, 0x7b, 0xa9, 0x2a, 0xa1, 0x4c, 0xe9, 0x41,
362 0xc5, 0xf6, 0x52, 0x54, 0x42, 0x99, 0xd2, 0x83, 0x8b, 0xed, 0xa5, 0xa8, 0x84, 0x33,
363 0xa4, 0x06, 0x16, 0xdb, 0x4b, 0x51, 0x08, 0x66, 0x48, 0x0d, 0x2c, 0xb7, 0x97, 0xa2,
364 0x10, 0xcd, 0x90, 0x1a, 0x59, 0x6e, 0x2e, 0x45, 0x21, 0x9b, 0x20, 0x35, 0xb2, 0xdd,
365 0x5d, 0x8a, 0x43, 0x37, 0x40, 0x6b, 0x64, 0xba, 0xbb, 0x15, 0x87, 0x6f, 0x80, 0xd7,
366 0xc9, 0x74, 0x77, 0x2b, 0x0f, 0xde, 0x01, 0xae, 0x92, 0xe8, 0xef, 0x57, 0x1e, 0xbd,
367 0x03, 0x5c, 0x24, 0xd1, 0xdf, 0xaf, 0x3c, 0x7a, 0x07, 0xb8, 0x49, 0xa3, 0xbe, 0x5f,
368 0x78, 0xf5, 0x0e, 0x70, 0x93, 0x46, 0x7d, 0xbf, 0xf1, 0xea, 0x1d, 0xe1, 0x27, 0x8d,
369 0xfb, 0x7e, 0xe3, 0xd5, 0x3b, 0xc2, 0x4e, 0x1b, 0xf7, 0xfc, 0xc6, 0xaa, 0x76, 0x85,
370 0x9d, 0x36, 0xee, 0xf9, 0x8c, 0x55, 0xec, 0x0b, 0x3a, 0x6c, 0xdc, 0xf3, 0x18, 0xab,
371 0xd8, 0x17, 0x75, 0xd9, 0xb9, 0xe7, 0x31, 0x56, 0xb0, 0x2f, 0xeb, 0xb3, 0x73, 0xcf,
372 0x62, 0xac, 0x60, 0x5e, 0xd6, 0x67, 0xe6, 0x9f, 0xc4, 0x58, 0xc0, 0xbc, 0xad, 0xce,
373 0xcc, 0x3e, 0x88, 0xb1, 0x81, 0x79, 0x5b, 0x9c, 0x98, 0x7c, 0x11, 0x63, 0x02, 0xf2,
374 0xb6, 0x39, 0x30, 0xf8, 0x22, 0xc7, 0x04, 0xe4, 0x6d, 0x72, 0x61, 0xf0, 0x44, 0x8f,
375 0x09, 0xc8, 0xda, 0xe5, 0xc3, 0xe0, 0x89, 0x1f, 0x13, 0x91, 0xb4, 0xcb, 0x86, 0xc1,
376 0x12, 0x3f, 0x26, 0x23, 0x69, 0x96, 0x0c, 0x82, 0x25, 0x7f, 0x4d, 0x47, 0xd3, 0x2d,
377 0x19, 0x05, 0x4a,
378 ];
379
380 assert!(has_errors(&msg), "expected message to have errors");
381
382 let block = correct_message(&msg);
383 assert_eq!(block.message.unwrap().len(), 255);
384 assert_eq!(block.state, RSState::Corrected(11));
385 }
386}