1use crate::algebraic::{berlekamp_massey, chien_search};
47use crate::block::{BlockCode, container_traits, expect_len};
48use comnum_core::signal::hard_decisions;
49use comnum_core::{Result, ensure};
50use comnum_math::gf2::{poly_mul, poly_rem};
51use comnum_math::gf2m::Field;
52
53#[derive(Clone, Debug, PartialEq, Eq)]
55pub struct Bch {
56 field: Field,
57 t: usize,
58 n: usize,
59 generator: Vec<u8>,
61}
62
63impl Bch {
64 pub fn new(m: u32, poly: u32, t: usize, n: usize) -> Result<Bch> {
71 let field = Field::new(m, poly)?;
72 ensure(t >= 1, || "BCH: t must be at least 1".into())?;
73 let mut generator = vec![1u8];
74 let mut used: Vec<Vec<u8>> = Vec::new();
75 for i in (1..2 * t).step_by(2) {
76 let mi = field.minimal_polynomial(i);
77 if !used.contains(&mi) {
78 generator = poly_mul(&generator, &mi);
79 used.push(mi);
80 }
81 }
82 let r = generator.len() - 1;
83 ensure(n <= field.order() && n > r, || {
84 format!("BCH: the length {n} must exceed the {r} parity bits and not exceed {}", field.order())
85 })?;
86 Ok(Bch { field, t, n, generator })
87 }
88
89 pub fn n(&self) -> usize {
91 self.n
92 }
93
94 pub fn k(&self) -> usize {
96 self.n + 1 - self.generator.len()
97 }
98
99 pub fn t(&self) -> usize {
101 self.t
102 }
103
104 pub fn generator(&self) -> &[u8] {
106 &self.generator
107 }
108
109 pub fn encode(&self, msg: &[u8]) -> Result<Vec<u8>> {
115 expect_len(msg.len(), self.k(), "bits")?;
116 let mut c: Vec<u8> = msg.iter().map(|b| b & 1).collect();
118 c.extend(poly_rem(msg, &self.generator));
119 Ok(c)
120 }
121
122 pub fn decode(&self, r: &[u8]) -> Result<(Vec<u8>, Option<usize>)> {
129 expect_len(r.len(), self.n, "bits")?;
130 let f = &self.field;
131 let n = self.n;
132 let two_t = 2 * self.t;
133 let mut s = vec![0u32; two_t + 1];
135 for (i, &b) in r.iter().enumerate() {
136 if b & 1 == 1 {
137 let e = n - 1 - i;
138 for (j, sj) in s.iter_mut().enumerate().skip(1) {
139 *sj ^= f.pow(j * e);
140 }
141 }
142 }
143 let k = self.k();
144 let msg = r[..k].iter().map(|b| b & 1).collect::<Vec<u8>>();
145 if s.iter().all(|&v| v == 0) {
146 return Ok((msg, Some(0)));
147 }
148 let (lambda, _) = berlekamp_massey(f, &s[1..]);
150 let degree = lambda.len() - 1;
151 if degree > self.t {
152 return Ok((msg, None));
153 }
154 let order = f.order();
157 let roots = chien_search(f, &lambda, n, |i| (n - 1 - i) % order);
158 if roots.len() != degree {
159 return Ok((msg, None));
160 }
161 let mut out: Vec<u8> = r.iter().map(|b| b & 1).collect();
162 for &i in &roots {
163 out[i] ^= 1;
164 }
165 let found = roots.len();
166 out.truncate(k);
167 Ok((out, Some(found)))
168 }
169}
170
171impl BlockCode for Bch {
172 fn k(&self) -> usize {
173 Bch::k(self)
174 }
175
176 fn n(&self) -> usize {
177 Bch::n(self)
178 }
179
180 fn encode_block(&self, info: &[u8]) -> Result<Vec<u8>> {
181 self.encode(info)
182 }
183
184 fn decode_block(&self, llr: &[f64]) -> Result<Vec<u8>> {
187 expect_len(llr.len(), Bch::n(self), "LLRs")?;
188 Ok(self.decode(&hard_decisions(llr))?.0)
189 }
190}
191
192container_traits!(Bch);
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197 use comnum_core::rng::Rng;
198
199 fn former_encode(code: &Bch, msg: &[u8]) -> Vec<u8> {
201 let r = code.generator.len() - 1;
202 let words = r.div_ceil(64);
203 let mut g = vec![0u64; words];
204 for (d, &b) in code.generator[..r].iter().enumerate() {
205 if b == 1 {
206 g[d / 64] |= 1 << (d % 64);
207 }
208 }
209 let mut reg = vec![0u64; words];
210 let top = r - 1;
211 for &b in msg {
212 let fb = ((reg[top / 64] >> (top % 64)) & 1) as u8 ^ (b & 1);
213 for w in (0..words).rev() {
214 let carry = if w > 0 { reg[w - 1] >> 63 } else { 0 };
215 reg[w] = (reg[w] << 1) | carry;
216 }
217 if r % 64 != 0 {
218 reg[words - 1] &= (1u64 << (r % 64)) - 1;
219 }
220 if fb == 1 {
221 for (x, y) in reg.iter_mut().zip(&g) {
222 *x ^= y;
223 }
224 }
225 }
226 let mut c: Vec<u8> = msg.iter().map(|b| b & 1).collect();
227 c.extend((0..r).rev().map(|d| ((reg[d / 64] >> (d % 64)) & 1) as u8));
228 c
229 }
230
231 #[test]
232 fn the_codewords_are_those_of_the_former_encoder() {
233 let mut rng = Rng::new(17);
234 for (m, poly, t, n) in
236 [(5, 0b10_0101, 2, 31), (16, 0x1_002D, 12, 16_200), (16, 0x1_002D, 4, 1000), (8, 0x11D, 8, 255)]
237 {
238 let code = Bch::new(m, poly, t, n).unwrap();
239 for _ in 0..3 {
240 let msg: Vec<u8> = (0..code.k()).map(|_| rng.bit()).collect();
241 assert_eq!(code.encode(&msg).unwrap(), former_encode(&code, &msg), "m {m}, t {t}, n {n}");
242 }
243 }
244 }
245
246 #[test]
247 fn the_generators_of_dvb_s2_are_the_products_of_the_published_polynomials() {
248 let table6a: [&[usize]; 12] = [
250 &[0, 2, 3, 5, 16],
251 &[0, 1, 4, 5, 6, 8, 16],
252 &[0, 2, 3, 4, 5, 7, 8, 9, 10, 11, 16],
253 &[0, 2, 4, 6, 9, 11, 12, 14, 16],
254 &[0, 1, 2, 3, 5, 8, 9, 10, 11, 12, 16],
255 &[0, 2, 4, 5, 7, 8, 9, 10, 12, 13, 14, 15, 16],
256 &[0, 2, 5, 6, 8, 9, 10, 11, 13, 15, 16],
257 &[0, 1, 2, 5, 6, 8, 9, 12, 13, 14, 16],
258 &[0, 5, 7, 9, 10, 11, 16],
259 &[0, 1, 2, 5, 7, 8, 10, 12, 13, 14, 16],
260 &[0, 2, 3, 5, 9, 11, 12, 13, 16],
261 &[0, 1, 5, 6, 7, 9, 11, 12, 16],
262 ];
263 let f = Field::new(16, 0b1_0000_0000_0010_1101).unwrap();
264 for (i, g) in table6a.iter().enumerate() {
265 let mut p = vec![0u8; 17];
266 for &d in *g {
267 p[d] = 1;
268 }
269 assert_eq!(f.minimal_polynomial(2 * i + 1), p, "g{}", i + 1);
270 }
271 }
272
273 #[test]
274 fn up_to_t_errors_are_corrected_and_more_are_mostly_detected() {
275 let code = Bch::new(14, 0b100_0000_0010_1011, 12, 7200).unwrap();
277 assert_eq!(code.k(), 7032);
278 let mut rng = Rng::new(4);
279 let mut positions: Vec<usize> = (0..code.n()).collect();
281 let (mut detected, mut wrong) = (0, 0);
282 for errors in (0..=12).chain((13..=24).flat_map(|e| [e; 4])) {
283 let msg: Vec<u8> = (0..code.k()).map(|_| rng.bit()).collect();
284 let mut c = code.encode(&msg).unwrap();
285 rng.shuffle(&mut positions);
286 for &p in &positions[..errors] {
287 c[p] ^= 1;
288 }
289 let (m, n) = code.decode(&c).unwrap();
290 if errors <= 12 {
291 assert_eq!((&m, n), (&msg, Some(errors)), "{errors} errors");
293 } else if n.is_none() {
294 assert_eq!(m, c[..code.k()], "{errors} errors");
296 detected += 1;
297 } else {
298 assert_ne!(m, msg, "{errors} errors");
300 wrong += 1;
301 }
302 }
303 assert_eq!((detected, wrong), (48, 0), "{detected} detected, {wrong} miscorrected");
306 let msg: Vec<u8> = (0..code.k()).map(|_| rng.bit()).collect();
308 let mut c = code.encode(&msg).unwrap();
309 for p in [3, 100, 2000, 5000, 7031, 7032, 7100, 7199, 1, 2, 4000, 6000] {
310 c[p] ^= 1;
311 }
312 assert_eq!(code.decode(&c).unwrap(), (msg, Some(12)));
313 }
314}