reed_solomon_32/
decoder_impl.rs

1use crate::gf::poly_math::*;
2use crate::gf::poly::Polynom;
3use crate::buffer::Buffer;
4use crate::err::{CorrectionError, invalid_data_len, invalid_data_len_for_ecc, invalid_ecc, invalid_erase_pos, invalid_symbol, UsageError};
5use crate::gf;
6
7/// [`Decoder`] for messages with 0 ECC symbols
8pub const DECODER_0: Decoder = Decoder::new(0);
9
10/// [`Decoder`] for messages with 1 ECC symbol
11pub const DECODER_1: Decoder = Decoder::new(1);
12
13/// [`Decoder`] for messages with 2 ECC symbols
14pub const DECODER_2: Decoder = Decoder::new(2);
15
16/// [`Decoder`] for messages with 3 ECC symbols
17pub const DECODER_3: Decoder = Decoder::new(3);
18
19/// [`Decoder`] for messages with 4 ECC symbols
20pub const DECODER_4: Decoder = Decoder::new(4);
21
22/// [`Decoder`] for messages with 5 ECC symbols
23pub const DECODER_5: Decoder = Decoder::new(5);
24
25/// [`Decoder`] for messages with 6 ECC symbols
26pub const DECODER_6: Decoder = Decoder::new(6);
27
28/// [`Decoder`] for messages with 7 ECC symbols
29pub const DECODER_7: Decoder = Decoder::new(7);
30
31/// [`Decoder`] for messages with 8 ECC symbols
32pub const DECODER_8: Decoder = Decoder::new(8);
33
34/// [`Decoder`] for messages with 9 ECC symbols
35pub const DECODER_9: Decoder = Decoder::new(9);
36
37/// [`Decoder`] for messages with 10 ECC symbols
38pub const DECODER_10: Decoder = Decoder::new(10);
39
40/// [`Decoder`] for messages with 11 ECC symbol
41pub const DECODER_11: Decoder = Decoder::new(11);
42
43/// [`Decoder`] for messages with 12 ECC symbols
44pub const DECODER_12: Decoder = Decoder::new(12);
45
46/// [`Decoder`] for messages with 13 ECC symbols
47pub const DECODER_13: Decoder = Decoder::new(13);
48
49/// [`Decoder`] for messages with 14 ECC symbols
50pub const DECODER_14: Decoder = Decoder::new(14);
51
52/// [`Decoder`] for messages with 15 ECC symbols
53pub const DECODER_15: Decoder = Decoder::new(15);
54
55/// [`Decoder`] for messages with 16 ECC symbols
56pub const DECODER_16: Decoder = Decoder::new(16);
57
58/// [`Decoder`] for messages with 17 ECC symbols
59pub const DECODER_17: Decoder = Decoder::new(17);
60
61/// [`Decoder`] for messages with 18 ECC symbols
62pub const DECODER_18: Decoder = Decoder::new(18);
63
64/// [`Decoder`] for messages with 19 ECC symbols
65pub const DECODER_19: Decoder = Decoder::new(19);
66
67/// [`Decoder`] for messages with 20 ECC symbols
68pub const DECODER_20: Decoder = Decoder::new(20);
69
70/// [`Decoder`] for messages with 21 ECC symbol
71pub const DECODER_21: Decoder = Decoder::new(21);
72
73/// [`Decoder`] for messages with 22 ECC symbols
74pub const DECODER_22: Decoder = Decoder::new(22);
75
76/// [`Decoder`] for messages with 23 ECC symbols
77pub const DECODER_23: Decoder = Decoder::new(23);
78
79/// [`Decoder`] for messages with 24 ECC symbols
80pub const DECODER_24: Decoder = Decoder::new(24);
81
82/// [`Decoder`] for messages with 25 ECC symbols
83pub const DECODER_25: Decoder = Decoder::new(25);
84
85/// [`Decoder`] for messages with 26 ECC symbols
86pub const DECODER_26: Decoder = Decoder::new(26);
87
88/// [`Decoder`] for messages with 27 ECC symbols
89pub const DECODER_27: Decoder = Decoder::new(27);
90
91/// [`Decoder`] for messages with 28 ECC symbols
92pub const DECODER_28: Decoder = Decoder::new(28);
93
94/// [`Decoder`] for messages with 29 ECC symbols
95pub const DECODER_29: Decoder = Decoder::new(29);
96
97/// [`Decoder`] for messages with 30 ECC symbols
98pub const DECODER_30: Decoder = Decoder::new(30);
99
100/// Reed-Solomon BCH decoder
101#[derive(Debug, Copy, Clone)]
102pub struct Decoder {
103    ecc_len: u8,
104}
105
106fn check_message(msg: &[u8], ecc_len: u8) -> Result<(), UsageError> {
107    // NOTE: ecc_len is checked elsewhere - its not possible to create a Decoder
108    // with an invalid ecc_len.
109    if msg.len() > 31 {
110        return Err(invalid_data_len());
111    }
112    if msg.len() < ecc_len as usize {
113        return Err(invalid_data_len_for_ecc());
114    }
115    if msg.iter().any(|&x| x > 31) {
116        return Err(invalid_symbol());
117    }
118    Ok(())
119}
120
121impl Decoder {
122    const fn new(ecc_len: u8) -> Self {
123        if ecc_len >= 31 {
124            // TODO: Make this a regular assert!() or return a Result once panics in const
125            //       functions are allowed: https://rust-lang.github.io/rfcs/2345-const-panic.html
126            #[allow(unconditional_panic)]
127            ["Invalid ECC Value"][1000];
128        }
129        Decoder { ecc_len }
130    }
131
132    /// Decodes block-encoded message and returns `Buffer` with corrected message and ecc offset.
133    /// Also includes the number of errors corrected.
134    ///
135    /// # Example
136    /// ```rust
137    /// use reed_solomon_32::encode;
138    /// use reed_solomon_32::decoder::DECODER_4;
139    ///
140    /// // Encode message
141    /// let mut encoded = encode(&[1, 2, 3, 4], 4).unwrap();
142    ///
143    /// // Corrupt message
144    /// encoded[2] = 1;
145    /// encoded[3] = 2;
146    ///
147    /// // Let's assume it's known that `encoded[3]` is an error
148    /// let known_erasures = [3];
149    ///
150    /// // Decode and correct message,
151    /// let corrected = DECODER_4.correct_err_count(&mut encoded, Some(&known_erasures)).unwrap();
152    ///
153    /// // Check results
154    /// assert_eq!(&[1, 2, 3, 4], corrected.0.data());
155    /// assert_eq!(2, corrected.1);
156    /// ```
157    pub fn correct_err_count(&self,
158                             msg: &[u8],
159                             erase_pos: Option<&[u8]>)
160                             -> Result<(Buffer, usize), CorrectionError> {
161        check_message(msg, self.ecc_len)?;
162
163        if let Some(x) = erase_pos {
164            if x.len() > self.ecc_len as usize {
165                return Err(CorrectionError::TooManyErrors);
166            }
167            if x.iter().any(|&err_pos| err_pos as usize > msg.len()) {
168                return Err(invalid_erase_pos().into());
169            }
170        }
171
172       let mut msg = Buffer::from_slice(msg, msg.len() - self.ecc_len as usize);
173
174        let erase_pos = if let Some(erase_pos) = erase_pos {
175            for e_pos in erase_pos {
176                msg[*e_pos as usize] = 0;
177            }
178            erase_pos
179        } else {
180            &[]
181        };
182
183        let synd = self.calc_syndromes(&msg);
184
185        // No errors
186        if synd.iter().all(|x| *x == 0) {
187            return Ok((msg,0));
188        }
189
190        let fsynd = self.forney_syndromes(&synd, erase_pos, msg.len());
191        let err_loc = self.find_error_locator(&fsynd, None, erase_pos.len())?;
192        let mut err_pos = self.find_errors(&err_loc.reverse(), msg.len())?;
193
194        // Append erase_pos to err_pos
195        for x in erase_pos.iter() {
196            err_pos.push(*x);
197        }
198
199        let (msg_out, fixed) = self.correct_errata(&msg, &synd, &err_pos);
200
201        // Check output message correctness
202        if self.is_corrupted(&msg_out)? {
203            Err(CorrectionError::TooManyErrors)
204        } else {
205            Ok((Buffer::from_polynom(msg_out, msg.len() - self.ecc_len as usize), fixed))
206        }
207    }
208
209    /// Decodes block-encoded message and returns `Buffer` with corrected message and ecc offset.
210    ///
211    /// # Example
212    /// ```rust
213    /// use reed_solomon_32::encode;
214    /// use reed_solomon_32::decoder::DECODER_4;
215    ///
216    /// // Encode message
217    /// let mut encoded = encode(&[1, 2, 3, 4], 4).unwrap();
218    ///
219    /// // Corrupt message
220    /// encoded[2] = 1;
221    /// encoded[3] = 2;
222    ///
223    /// // Let's assume it's known that `encoded[3]` is an error
224    /// let known_erasures = [3];
225    ///
226    /// // Decode and correct message,
227    /// let corrected = DECODER_4.correct(&mut encoded, Some(&known_erasures)).unwrap();
228    ///
229    /// // Check results
230    /// assert_eq!(&[1, 2, 3, 4], corrected.data())
231    /// ```
232    pub fn correct(&self,
233                   msg: &[u8],
234                   erase_pos: Option<&[u8]>)
235                   -> Result<Buffer, CorrectionError> {
236        self.correct_err_count(msg, erase_pos).map(|(r,_)| r)
237     }
238
239    /// Performs fast corruption check.
240    ///
241    /// # Example
242    /// ```rust
243    /// use reed_solomon_32::encode;
244    /// use reed_solomon_32::decoder::DECODER_4;
245    ///
246    /// // Encode message
247    /// let mut encoded = encode(&[1, 2, 3, 4], 4).unwrap();
248    ///
249    /// assert_eq!(DECODER_4.is_corrupted(&encoded).unwrap(), false);
250    ///
251    /// // Corrupt message
252    /// encoded[2] = 1;
253    /// encoded[3] = 2;
254    ///
255    /// assert_eq!(DECODER_4.is_corrupted(&encoded).unwrap(), true);
256    /// ```
257    pub fn is_corrupted(&self, msg: &[u8]) -> Result<bool, UsageError> {
258        check_message(msg, self.ecc_len)?;
259        Ok((0..self.ecc_len).any(|x| msg.eval(gf::pow(2, x as i32)) != 0))
260    }
261
262    fn calc_syndromes(&self, msg: &[u8]) -> Polynom {
263        // index 0 is a pad for mathematical precision
264        let mut synd = Polynom::with_length(self.ecc_len as usize + 1);
265        for i in 0..self.ecc_len as usize {
266            synd[i + 1] = msg.eval(gf::pow(2, i as i32))
267        }
268
269        synd
270    }
271
272    fn find_errata_locator(&self, e_pos: &[u8]) -> Polynom {
273        let mut e_loc = polynom![1];
274
275        let add_lhs = [1];
276        let mut add_rhs = [0, 0];
277        for i in e_pos.iter() {
278            add_rhs[0] = gf::pow(2, *i as i32);
279            e_loc = e_loc.mul(&add_lhs.add(&add_rhs));
280        }
281
282        e_loc
283    }
284
285    fn find_error_evaluator(&self, synd: &[u8], err_loc: &[u8], syms: usize) -> Polynom {
286        let mut divisor = Polynom::with_length(syms + 2);
287        divisor[0] = 1;
288
289        let (_, remainder) = (synd.mul(err_loc)).div(&divisor);
290        remainder
291    }
292
293    /// Forney algorithm, computes the values (error magnitude) to correct the input message.
294    #[allow(non_snake_case)]
295    fn correct_errata(&self, msg: &[u8], synd: &[u8], err_pos: &[u8]) -> (Polynom, usize) {
296        // convert the positions to coefficients degrees
297        let mut coef_pos = Polynom::with_length(err_pos.len());
298        for (i, x) in err_pos.iter().enumerate() {
299            coef_pos[i] = msg.len() as u8 - 1 - x;
300        }
301
302        let err_loc = self.find_errata_locator(&coef_pos);
303        let synd = Polynom::from(synd);
304        let err_eval = self.find_error_evaluator(&synd.reverse(), &err_loc, err_loc.len() - 1)
305            .reverse();
306
307        let mut X = Polynom::new();
308
309        for px in coef_pos.iter() {
310            let l = (31 - px) as i32;
311            X.push(gf::pow(2, -l))
312        }
313
314        let mut E = Polynom::with_length(msg.len());
315        let mut fixed = 0;
316
317        let err_eval_rev = err_eval.reverse();
318        for (i, Xi) in X.iter().enumerate() {
319            let Xi_inv = gf::inverse(*Xi);
320
321            let mut err_loc_prime_tmp = Polynom::new();
322            for (j, Xj) in X.iter().enumerate() {
323                if j != i {
324                    err_loc_prime_tmp.push(gf::sub(1, gf::mul(Xi_inv, *Xj)));
325                }
326            }
327
328            let mut err_loc_prime = 1;
329            for coef in err_loc_prime_tmp.iter() {
330                err_loc_prime = gf::mul(err_loc_prime, *coef);
331            }
332
333            let y = err_eval_rev.eval(Xi_inv);
334            let y = gf::mul(gf::pow(*Xi, 1), y);
335
336            let magnitude = gf::div(y, err_loc_prime);
337
338            let E_index = err_pos[i] as usize;
339            E[E_index] = magnitude;
340            fixed += 1;
341        }
342
343        (msg.add(&E), fixed)
344    }
345
346    #[allow(non_snake_case)]
347    fn find_error_locator(&self,
348                          synd: &[u8],
349                          erase_loc: Option<&[u8]>,
350                          erase_count: usize)
351                          -> Result<Polynom, CorrectionError> {
352        let (mut err_loc, mut old_loc) = if let Some(erase_loc) = erase_loc {
353            (Polynom::from(erase_loc), Polynom::from(erase_loc))
354        } else {
355            (polynom![1], polynom![1])
356        };
357
358        let synd_shift = if synd.len() > self.ecc_len as usize {
359            synd.len() - self.ecc_len as usize
360        } else {
361            0
362        };
363
364        for i in 0..(self.ecc_len as usize - erase_count) {
365            let K = if erase_loc.is_some() {
366                erase_count + i + synd_shift
367            } else {
368                i + synd_shift
369            };
370
371            let mut delta = synd[K];
372            for j in 1..err_loc.len() {
373                let d_index = err_loc.len() - j - 1;
374                delta ^= gf::mul(err_loc[d_index], synd[K - j]);
375            }
376
377            old_loc.push(0);
378
379            if delta != 0 {
380                if old_loc.len() > err_loc.len() {
381                    let new_loc = old_loc.scale(delta);
382                    old_loc = err_loc.scale(gf::inverse(delta));
383                    err_loc = new_loc;
384                }
385
386                err_loc = err_loc.add(&old_loc.scale(delta));
387            }
388        }
389
390        let shift = err_loc.iter().take_while(|&&v| v == 0).count();
391        let err_loc = Polynom::from(&err_loc[shift..]);
392
393        let errs = err_loc.len() - 1;
394        let errs = if erase_count > errs {
395            erase_count
396        } else {
397            (errs - erase_count) * 2 + erase_count
398        };
399
400        if errs > self.ecc_len as usize {
401            Err(CorrectionError::TooManyErrors)
402        } else {
403            Ok(err_loc)
404        }
405    }
406
407    fn find_errors(&self, err_loc: &[u8], msg_len: usize) -> Result<Polynom, CorrectionError> {
408        let errs = err_loc.len() - 1;
409        let mut err_pos = polynom![];
410
411        for i in 0..msg_len {
412            if err_loc.eval(gf::pow(2, i as i32)) == 0 {
413                let x = msg_len as u8 - 1 - i as u8;
414                err_pos.push(x);
415            }
416        }
417
418        if err_pos.len() != errs {
419            Err(CorrectionError::TooManyErrors)
420        } else {
421            Ok(err_pos)
422        }
423    }
424
425    fn forney_syndromes(&self, synd: &[u8], pos: &[u8], msg_len: usize) -> Polynom {
426        let mut erase_pos_rev = Polynom::with_length(pos.len());
427        for (i, x) in pos.iter().enumerate() {
428            erase_pos_rev[i] = msg_len as u8 - 1 - x;
429        }
430
431        let mut fsynd = Polynom::from(&synd[1..]);
432
433        for pos in erase_pos_rev.iter() {
434            let x = gf::pow(2, *pos as i32);
435            for j in 0..(fsynd.len() - 1) {
436                fsynd[j] = gf::mul(fsynd[j], x) ^ fsynd[j + 1];
437            }
438        }
439
440        fsynd
441    }
442}
443
444/// Decodes block-encoded message and returns `Buffer` with corrected message and ecc offset.
445/// Also includes the number of errors corrected.
446///
447/// # Example
448/// ```rust
449/// use reed_solomon_32::encode;
450/// use reed_solomon_32::correct_err_count;
451///
452/// // Encode message
453/// let mut encoded = encode(&[1, 2, 3, 4], 4).unwrap();
454///
455/// // Corrupt message
456/// encoded[2] = 1;
457/// encoded[3] = 2;
458///
459/// // Let's assume it's known that `encoded[3]` is an error
460/// let known_erasures = [3];
461///
462/// // Decode and correct message,
463/// let corrected = correct_err_count(&mut encoded, 4, Some(&known_erasures)).unwrap();
464///
465/// // Check results
466/// assert_eq!(&[1, 2, 3, 4], corrected.0.data());
467/// assert_eq!(2, corrected.1);
468/// ```
469pub fn correct_err_count(
470    msg: &[u8],
471    ecc: u8,
472    erase_pos: Option<&[u8]>,
473) -> Result<(Buffer, usize), CorrectionError> {
474    if ecc >= 31 {
475        return Err(invalid_ecc().into());
476    }
477    Decoder::new(ecc).correct_err_count(msg, erase_pos)
478}
479
480/// Decodes block-encoded message and returns `Buffer` with corrected message and ecc offset.
481///
482/// # Example
483/// ```rust
484/// use reed_solomon_32::encode;
485/// use reed_solomon_32::correct;
486///
487/// // Encode message
488/// let mut encoded = encode(&[1, 2, 3, 4], 4).unwrap();
489///
490/// // Corrupt message
491/// encoded[2] = 1;
492/// encoded[3] = 2;
493///
494/// // Let's assume it's known that `encoded[3]` is an error
495/// let known_erasures = [3];
496///
497/// // Decode and correct message,
498/// let corrected = correct(&mut encoded, 4, Some(&known_erasures)).unwrap();
499///
500/// // Check results
501/// assert_eq!(&[1, 2, 3, 4], corrected.data())
502/// ```
503pub fn correct(
504    msg: &[u8],
505    ecc: u8,
506    erase_pos: Option<&[u8]>,
507) -> Result<Buffer, CorrectionError> {
508    if ecc >= 31 {
509        return Err(invalid_ecc().into());
510    }
511    Decoder::new(ecc).correct(msg, erase_pos)
512}
513
514/// Performs fast corruption check.
515///
516/// # Example
517/// ```rust
518/// use reed_solomon_32::encode;
519/// use reed_solomon_32::is_corrupted;
520///
521/// // Encode message
522/// let mut encoded = encode(&[1, 2, 3, 4], 4).unwrap();
523///
524/// assert_eq!(is_corrupted(&encoded, 4).unwrap(), false);
525///
526/// // Corrupt message
527/// encoded[2] = 1;
528/// encoded[3] = 2;
529///
530/// assert_eq!(is_corrupted(&encoded, 4).unwrap(), true);
531/// ```
532pub fn is_corrupted(msg: &[u8], ecc: u8) -> Result<bool, UsageError> {
533    if ecc >= 31 {
534        return Err(invalid_ecc().into());
535    }
536    Decoder::new(ecc).is_corrupted(msg)
537}
538
539#[cfg(test)]
540mod tests {
541    use super::*;
542    use crate::encode;
543
544    #[test]
545    fn calc_syndromes() {
546        let px = [1, 2, 3, 4, 5, 6, 7, 8, 9];
547        let mut encoded = encode(&px[..], 8).unwrap();
548
549        assert_eq!([0; 9], *Decoder::new(8).calc_syndromes(&encoded));
550
551        encoded[5] = 1;
552
553        assert_eq!([0, 7, 21, 4, 28, 30, 16, 31, 23],
554                   *Decoder::new(8).calc_syndromes(&encoded));
555    }
556
557    #[test]
558    fn is_corrupted() {
559        let px = [1, 2, 3, 4, 5, 6, 7, 8, 9];
560        let mut encoded = encode(&px[..], 8).unwrap();
561
562        assert_eq!(false, Decoder::new(8).is_corrupted(&encoded).unwrap());
563
564        encoded[5] = 1;
565
566        assert_eq!(true, Decoder::new(8).is_corrupted(&encoded).unwrap());
567    }
568
569    #[test]
570    fn find_errata_locator() {
571        let e_pos = [19, 18, 17, 14, 15, 16];
572        assert_eq!([10, 11, 10, 2, 16, 15, 1],
573                   *Decoder::new(6).find_errata_locator(&e_pos[..]));
574    }
575
576    #[test]
577    fn find_error_evaluator() {
578        let synd = [0, 7, 25, 13, 21, 5, 6];
579        let err_loc = [10, 11, 10, 2, 16, 15, 1];
580
581        assert_eq!([22, 13, 28, 6, 12, 2, 6],
582                   *Decoder::new(6).find_error_evaluator(&synd, &err_loc, 6));
583    }
584
585    #[test]
586    fn correct_errata() {
587        let msg = [0, 0, 0, 2, 2, 2, 19, 11, 14, 18, 1, 19, 16, 3, 28, 4, 20, 12, 12];
588        let synd = [0, 11, 9, 28, 29, 14, 12, 12, 1, 10];
589        let err_pos = [0, 1, 2, 5, 4, 3];
590        let result = [10, 11, 18, 18, 11, 3, 19, 11, 14, 18, 1, 19, 16, 3, 28, 4, 20, 12, 12];
591
592        assert_eq!(result,
593                   *Decoder::new(err_pos.len() as u8).correct_errata(&msg, &synd, &err_pos).0);
594    }
595
596    #[test]
597    fn error_count() {
598        let msg = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
599
600        let encoded = encode(&msg[..], 10).unwrap();
601        let mut errd = *encoded;
602
603        errd[0] = 31;
604        errd[3] = 31;
605
606        let (_correct,err) = Decoder::new(10).correct_err_count(&errd, None).unwrap();
607
608        assert_eq!(err, 2);
609    }
610
611    #[test]
612    fn find_error_locator() {
613        let synd = [29, 17, 2, 19, 4, 7, 28, 21, 6];
614        let nsym = 9;
615        let erase_loc = None;
616        let erase_count = 3;
617
618        let result = [7, 20, 30, 1];
619
620        let error_loc = Decoder::new(nsym).find_error_locator(&synd, erase_loc, erase_count);
621
622        assert!(error_loc.is_ok());
623        assert_eq!(result, *error_loc.unwrap());
624    }
625
626    #[test]
627    fn find_errors() {
628        let err_loc = [1, 24, 2, 4];
629        let msg_len = 16;
630        let result = [5, 4, 3];
631
632        let err_pos = Decoder::new(6).find_errors(&err_loc, msg_len);
633
634        assert!(err_pos.is_ok());
635        assert_eq!(result, *err_pos.unwrap());
636
637        let err_loc = [1, 2, 27, 25];
638        let msg_len = 16;
639
640        let err_pos = Decoder::new(6).find_errors(&err_loc, msg_len);
641
642        assert!(err_pos.is_err());
643    }
644
645    #[test]
646    fn forney_syndromes() {
647        let synd = [0, 29, 20, 23, 13, 24, 11];
648        let pos = [3, 4, 5];
649        let nmess = 16;
650
651        let result = [0, 0, 0, 17, 29, 11];
652        assert_eq!(result,
653                   *Decoder::new(6).forney_syndromes(&synd, &pos, nmess));
654    }
655
656    #[test]
657    fn decode() {
658        let mut msg = [0, 1, 2, 31, 31, 31, 31, 31, 31, 9, 4, 1, 17, 17, 3, 9, 19, 24, 5];
659        let ecc = 9;
660        let erase_pos = [3, 4, 5];
661
662        let result = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 1, 17, 17, 3, 9, 19, 24, 5];
663
664        let decoder = Decoder::new(ecc);
665        let decoded = decoder.correct(&mut msg[..], Some(&erase_pos)).unwrap();
666
667        assert_eq!(result, **decoded);
668    }
669
670    #[test]
671    fn decode_lots_of_errors() {
672        // fifteen 0s followed by fifteen 15s - with 30 error correcting
673        // symbols, this is the biggest error we can still correct.
674        let data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15];
675        let buffer = correct(&data, 30, None).unwrap();
676        assert_eq!(&[0u8][..], buffer.data());
677    }
678}