reed_solomon_32/
encoder_impl.rs

1use crate::gf::poly::Polynom;
2use crate::buffer::Buffer;
3use crate::err::{invalid_combined_len, invalid_data_len, invalid_ecc, invalid_symbol, UsageError};
4use crate::gf;
5
6/// [`Encoder`] for messages with 0 ECC symbols
7pub const ENCODER_0: Encoder = Encoder::new(polynom![1]);
8
9/// [`Encoder`] for messages with 1 ECC symbol
10pub const ENCODER_1: Encoder = Encoder::new(polynom![1, 1]);
11
12/// [`Encoder`] for messages with 2 ECC symbols
13pub const ENCODER_2: Encoder = Encoder::new(polynom![1, 3, 2]);
14
15/// [`Encoder`] for messages with 3 ECC symbols
16pub const ENCODER_3: Encoder = Encoder::new(polynom![1, 7, 14, 8]);
17
18/// [`Encoder`] for messages with 4 ECC symbols
19pub const ENCODER_4: Encoder = Encoder::new(polynom![1, 15, 19, 23, 10]);
20
21/// [`Encoder`] for messages with 5 ECC symbols
22pub const ENCODER_5: Encoder = Encoder::new(polynom![1, 31, 24, 15, 24, 17]);
23
24/// [`Encoder`] for messages with 6 ECC symbols
25pub const ENCODER_6: Encoder = Encoder::new(polynom![1, 26, 20, 24, 14, 6, 31]);
26
27/// [`Encoder`] for messages with 7 ECC symbols
28pub const ENCODER_7: Encoder = Encoder::new(polynom![1, 16, 11, 4, 5, 5, 6, 24]);
29
30/// [`Encoder`] for messages with 8 ECC symbols
31pub const ENCODER_8: Encoder = Encoder::new(polynom![1, 4, 12, 12, 31, 11, 8, 15, 22]);
32
33/// [`Encoder`] for messages with 9 ECC symbols
34pub const ENCODER_9: Encoder = Encoder::new(polynom![1, 9, 29, 26, 9, 4, 24, 8, 23, 5]);
35
36/// [`Encoder`] for messages with 10 ECC symbols
37pub const ENCODER_10: Encoder = Encoder::new(polynom![1, 19, 9, 21, 10, 16, 31, 26, 25, 21, 29]);
38
39/// [`Encoder`] for messages with 11 ECC symbols
40pub const ENCODER_11: Encoder = Encoder::new(polynom![1, 2, 2, 24, 8, 11, 2, 3, 31, 5, 31, 30]);
41
42/// [`Encoder`] for messages with 12 ECC symbols
43pub const ENCODER_12: Encoder = Encoder::new(polynom![1, 5, 12, 22, 10, 22, 22, 13, 22, 18, 4, 9, 16]);
44
45/// [`Encoder`] for messages with 13 ECC symbols
46pub const ENCODER_13: Encoder = Encoder::new(polynom![1, 11, 31, 20, 16, 21, 12, 23, 26, 8, 3, 20, 1, 27]);
47
48/// [`Encoder`] for messages with 14 ECC symbols
49pub const ENCODER_14: Encoder = Encoder::new(polynom![1, 23, 5, 2, 28, 6, 28, 19, 23, 29, 24, 21, 13, 7, 9]);
50
51/// [`Encoder`] for messages with 15 ECC symbols
52pub const ENCODER_15: Encoder = Encoder::new(polynom![1, 10, 31, 4, 3, 13, 24, 24, 22, 7, 14, 5, 8, 18, 16, 14]);
53
54/// [`Encoder`] for messages with 16 ECC symbols
55pub const ENCODER_16: Encoder = Encoder::new(polynom![1, 21, 7, 22, 16, 9, 23, 29, 19, 9, 25, 14, 4, 17, 13, 8, 11]);
56
57/// [`Encoder`] for messages with 17 ECC symbols
58pub const ENCODER_17: Encoder = Encoder::new(polynom![1, 14, 19, 29, 12, 5, 10, 26, 1, 13, 4, 31, 18, 18, 26, 22, 13, 14]);
59
60/// [`Encoder`] for messages with 18 ECC symbols
61pub const ENCODER_18: Encoder = Encoder::new(polynom![1, 29, 26, 21, 13, 15, 31, 21, 22, 30, 29, 25, 16, 9, 1, 1, 16, 23, 9]);
62
63/// [`Encoder`] for messages with 19 ECC symbols
64pub const ENCODER_19: Encoder = Encoder::new(polynom![1, 30, 24, 30, 23, 24, 14, 17, 12, 1, 26, 27, 30, 28, 26, 2, 19, 2, 21, 27]);
65
66/// [`Encoder`] for messages with 20 ECC symbols
67pub const ENCODER_20: Encoder = Encoder::new(polynom![1, 24, 22, 4, 25, 5, 20, 16, 5, 12, 28, 13, 14, 18, 24, 20, 31, 7, 25, 10, 16]);
68
69/// [`Encoder`] for messages with 21 ECC symbols
70pub const ENCODER_21: Encoder = Encoder::new(polynom![1, 20, 7, 23, 12, 24, 13, 27, 27, 21, 6, 9, 24, 16, 30, 5, 20, 23, 24, 23, 7, 30]);
71
72/// [`Encoder`] for messages with 22 ECC symbols
73pub const ENCODER_22: Encoder = Encoder::new(polynom![1, 12, 17, 21, 23, 9, 10, 18, 17, 31, 8, 19, 30, 23, 7, 24, 3, 1, 3, 16, 28, 28, 29]);
74
75/// [`Encoder`] for messages with 23 ECC symbols
76pub const ENCODER_23: Encoder = Encoder::new(polynom![1, 25, 22, 23, 11, 26, 6, 4, 9, 29, 2, 10, 19, 8, 20, 28, 13, 27, 22, 10, 11, 12, 13, 5]);
77
78/// [`Encoder`] for messages with 24 ECC symbols
79pub const ENCODER_24: Encoder = Encoder::new(polynom![1, 22, 5, 27, 8, 28, 4, 3, 16, 5, 8, 20, 26, 18, 3, 14, 8, 26, 27, 6, 2, 10, 3, 4, 22]);
80
81/// [`Encoder`] for messages with 25 ECC symbols
82pub const ENCODER_25: Encoder = Encoder::new(polynom![1, 8, 29, 18, 18, 23, 14, 20, 23, 19, 1, 31, 27, 22, 12, 9, 13, 17, 31, 28, 12, 19, 17, 3, 1, 24]);
83
84/// [`Encoder`] for messages with 26 ECC symbols
85pub const ENCODER_26: Encoder = Encoder::new(polynom![1, 17, 11, 31, 12, 9, 2, 30, 21, 31, 6, 6, 1, 7, 25, 20, 2, 21, 15, 6, 24, 14, 22, 19, 15, 1, 31]);
86
87/// [`Encoder`] for messages with 27 ECC symbols
88pub const ENCODER_27: Encoder = Encoder::new(polynom![1, 6, 14, 10, 29, 22, 28, 21, 19, 12, 23, 27, 28, 16, 19, 24, 6, 30, 28, 5, 5, 21, 2, 28, 1, 2, 8, 17]);
89
90/// [`Encoder`] for messages with 28 ECC symbols
91pub const ENCODER_28: Encoder = Encoder::new(polynom![1, 13, 17, 7, 25, 7, 2, 15, 16, 16, 12, 14, 18, 10, 18, 4, 21, 1, 16, 31, 7, 23, 1, 10, 27, 9, 30, 3, 10]);
92
93/// [`Encoder`] for messages with 29 ECC symbols
94pub const ENCODER_29: Encoder = Encoder::new(polynom![1, 27, 20, 19, 20, 18, 15, 6, 28, 18, 14, 29, 8, 1, 26, 15, 7, 7, 6, 29, 9, 26, 14, 28, 19, 21, 9, 27, 21, 8]);
95
96/// [`Encoder`] for messages with 30 ECC symbols
97pub const ENCODER_30: Encoder = Encoder::new(polynom![1, 18, 9, 22, 11, 23, 25, 30, 15, 21, 24, 12, 6, 3, 19, 27, 31, 29, 28, 14, 7, 17, 26, 13, 20, 10, 5, 16, 8, 4, 2]);
98
99/// Reed-Solomon BCH encoder
100#[derive(Debug, Copy, Clone)]
101pub struct Encoder {
102    generator: Polynom,
103}
104
105impl Encoder {
106    const fn new(generator: Polynom) -> Self {
107        Encoder { generator }
108    }
109
110    /// Encodes passed `&[u8]` slice and returns `Buffer` with result.
111    ///
112    /// The number of ecc symbols used will depend on `Encoder` constant
113    /// that was used.
114    ///
115    /// # Example
116    /// ```rust
117    /// use reed_solomon_32::encoder::ENCODER_8;
118    ///
119    /// let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
120    ///
121    /// let encoded = ENCODER_8.encode(&data).unwrap();
122    ///
123    /// println!("whole: {:?}", &encoded[..]);
124    /// println!("data:  {:?}", encoded.data());
125    /// println!("ecc:   {:?}", encoded.ecc());
126    /// ```
127    pub fn encode(&self, data: &[u8]) -> Result<Buffer, UsageError> {
128        if data.len() > 31 {
129            return Err(invalid_data_len());
130        }
131        if data.len() + self.generator.len() - 1 > 31 {
132            return Err(invalid_combined_len());
133        }
134        if data.iter().any(|&x| x > 31) {
135            return Err(invalid_symbol());
136        }
137
138        let mut data_out = Polynom::from(data);
139        let data_len = data.len();
140
141        data_out.set_length(data_len + self.generator.len() - 1);
142
143        let gen = self.generator;
144        let mut lgen = Polynom::with_length(self.generator.len());
145        for (i, gen_i) in gen.iter().enumerate() {
146            lgen[i] = gf::LOG[*gen_i as usize];
147        }
148
149        for i in 0..data_len {
150            let coef = data_out[i];
151            if coef != 0 {
152                let lcoef = gf::LOG[coef as usize] as usize;
153                for j in 1..gen.len() {
154                    data_out[i + j] ^= gf::EXP[(lcoef + lgen[j] as usize)];
155                }
156            }
157        }
158
159        data_out[..data_len].copy_from_slice(data);
160        Ok(Buffer::from_polynom(data_out, data_len))
161    }
162}
163
164/// Encodes passed `&[u8]` slice and returns `Buffer` with result using
165/// `ecc` error correcting symbols.
166///
167/// # Example
168/// ```rust
169/// use reed_solomon_32::encode;
170///
171/// let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
172///
173/// let encoded = encode(&data, 8).unwrap();
174///
175/// println!("whole: {:?}", &encoded[..]);
176/// println!("data:  {:?}", encoded.data());
177/// println!("ecc:   {:?}", encoded.ecc());
178/// ```
179pub fn encode(data: &[u8], ecc: u8) -> Result<Buffer, UsageError> {
180    match ecc {
181        0 => ENCODER_0.encode(data),
182        1 => ENCODER_1.encode(data),
183        2 => ENCODER_2.encode(data),
184        3 => ENCODER_3.encode(data),
185        4 => ENCODER_4.encode(data),
186        5 => ENCODER_5.encode(data),
187        6 => ENCODER_6.encode(data),
188        7 => ENCODER_7.encode(data),
189        8 => ENCODER_8.encode(data),
190        9 => ENCODER_9.encode(data),
191        10 => ENCODER_10.encode(data),
192        11 => ENCODER_11.encode(data),
193        12 => ENCODER_12.encode(data),
194        13 => ENCODER_13.encode(data),
195        14 => ENCODER_14.encode(data),
196        15 => ENCODER_15.encode(data),
197        16 => ENCODER_16.encode(data),
198        17 => ENCODER_17.encode(data),
199        18 => ENCODER_18.encode(data),
200        19 => ENCODER_19.encode(data),
201        20 => ENCODER_20.encode(data),
202        21 => ENCODER_21.encode(data),
203        22 => ENCODER_22.encode(data),
204        23 => ENCODER_23.encode(data),
205        24 => ENCODER_24.encode(data),
206        25 => ENCODER_25.encode(data),
207        26 => ENCODER_26.encode(data),
208        27 => ENCODER_27.encode(data),
209        28 => ENCODER_28.encode(data),
210        29 => ENCODER_29.encode(data),
211        30 => ENCODER_30.encode(data),
212        _ => Err(invalid_ecc()),
213    }
214}
215
216#[cfg(test)]
217mod tests {
218    use crate::gf::poly_math::Mul as _;
219    use crate::gf::poly::Polynom;
220    use crate::gf;
221
222    #[test]
223    fn generator_poly() {
224        fn generator_poly(ecclen: usize) -> Polynom {
225            let mut gen = polynom![1];
226            let mut mm = [1, 0];
227            for i in 0..ecclen {
228                mm[1] = gf::pow(2, i as i32);
229                gen = gen.mul(&mm);
230            }
231            gen
232        }
233
234        assert_eq!(&super::ENCODER_0.generator[..], &generator_poly(0)[..]);
235        assert_eq!(&super::ENCODER_1.generator[..], &generator_poly(1)[..]);
236        assert_eq!(&super::ENCODER_2.generator[..], &generator_poly(2)[..]);
237        assert_eq!(&super::ENCODER_3.generator[..], &generator_poly(3)[..]);
238        assert_eq!(&super::ENCODER_4.generator[..], &generator_poly(4)[..]);
239        assert_eq!(&super::ENCODER_5.generator[..], &generator_poly(5)[..]);
240        assert_eq!(&super::ENCODER_6.generator[..], &generator_poly(6)[..]);
241        assert_eq!(&super::ENCODER_7.generator[..], &generator_poly(7)[..]);
242        assert_eq!(&super::ENCODER_8.generator[..], &generator_poly(8)[..]);
243        assert_eq!(&super::ENCODER_9.generator[..], &generator_poly(9)[..]);
244        assert_eq!(&super::ENCODER_10.generator[..], &generator_poly(10)[..]);
245        assert_eq!(&super::ENCODER_11.generator[..], &generator_poly(11)[..]);
246        assert_eq!(&super::ENCODER_12.generator[..], &generator_poly(12)[..]);
247        assert_eq!(&super::ENCODER_13.generator[..], &generator_poly(13)[..]);
248        assert_eq!(&super::ENCODER_14.generator[..], &generator_poly(14)[..]);
249        assert_eq!(&super::ENCODER_15.generator[..], &generator_poly(15)[..]);
250        assert_eq!(&super::ENCODER_16.generator[..], &generator_poly(16)[..]);
251        assert_eq!(&super::ENCODER_17.generator[..], &generator_poly(17)[..]);
252        assert_eq!(&super::ENCODER_18.generator[..], &generator_poly(18)[..]);
253        assert_eq!(&super::ENCODER_19.generator[..], &generator_poly(19)[..]);
254        assert_eq!(&super::ENCODER_20.generator[..], &generator_poly(20)[..]);
255        assert_eq!(&super::ENCODER_21.generator[..], &generator_poly(21)[..]);
256        assert_eq!(&super::ENCODER_22.generator[..], &generator_poly(22)[..]);
257        assert_eq!(&super::ENCODER_23.generator[..], &generator_poly(23)[..]);
258        assert_eq!(&super::ENCODER_24.generator[..], &generator_poly(24)[..]);
259        assert_eq!(&super::ENCODER_25.generator[..], &generator_poly(25)[..]);
260        assert_eq!(&super::ENCODER_26.generator[..], &generator_poly(26)[..]);
261        assert_eq!(&super::ENCODER_27.generator[..], &generator_poly(27)[..]);
262        assert_eq!(&super::ENCODER_28.generator[..], &generator_poly(28)[..]);
263        assert_eq!(&super::ENCODER_29.generator[..], &generator_poly(29)[..]);
264        assert_eq!(&super::ENCODER_30.generator[..], &generator_poly(30)[..]);
265    }
266
267    #[test]
268    fn encode() {
269        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
270        let ecc = [5, 10, 26, 18, 9, 22, 13, 21];
271
272        let encoded = super::encode(&data[..], ecc.len() as u8).unwrap();
273
274        assert_eq!(data, encoded.data());
275        assert_eq!(ecc, encoded.ecc());
276    }
277}