3 * Reed-Solomon encoding and decoding,
4 * by Phil Karn (karn@ka9q.ampr.org) September 1996
5 * Copyright 1999 Phil Karn, KA9Q
6 * Separate CCSDS version create Dec 1998, merged into this version May 1999
8 * This file is derived from my generic RS encoder/decoder, which is
9 * in turn based on the program "new_rs_erasures.c" by Robert
10 * Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy
11 * (harit@spectra.eng.hawaii.edu), Aug 1995
13 * Wireshark - Network traffic analyzer
14 * By Gerald Combs <gerald@wireshark.org>
15 * Copyright 1998 Gerald Combs
17 * SPDX-License-Identifier: GPL-2.0-or-later
22 #define WS_LOG_DOMAIN LOG_DOMAIN_EPAN
25 #include "reedsolomon.h"
26 #include <wsutil/wslog.h>
29 /* CCSDS field generator polynomial: 1+x+x^2+x^7+x^8 */
30 int Pp
[MM
+1] = { 1, 1, 1, 0, 0, 0, 0, 1, 1 };
33 /* MM, KK, B0, PRIM are user-defined in rs.h */
35 /* Primitive polynomials - see Lin & Costello, Appendix A,
36 * and Lee & Messerschmitt, p. 453.
38 #if(MM == 2)/* Admittedly silly */
39 int Pp
[MM
+1] = { 1, 1, 1 };
43 int Pp
[MM
+1] = { 1, 1, 0, 1 };
47 int Pp
[MM
+1] = { 1, 1, 0, 0, 1 };
51 int Pp
[MM
+1] = { 1, 0, 1, 0, 0, 1 };
55 int Pp
[MM
+1] = { 1, 1, 0, 0, 0, 0, 1 };
59 int Pp
[MM
+1] = { 1, 0, 0, 1, 0, 0, 0, 1 };
62 /* 1+x^2+x^3+x^4+x^8 */
63 int Pp
[MM
+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1 };
67 int Pp
[MM
+1] = { 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
71 int Pp
[MM
+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
75 int Pp
[MM
+1] = { 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
78 /* 1+x+x^4+x^6+x^12 */
79 int Pp
[MM
+1] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1 };
82 /* 1+x+x^3+x^4+x^13 */
83 int Pp
[MM
+1] = { 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
86 /* 1+x+x^6+x^10+x^14 */
87 int Pp
[MM
+1] = { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 };
91 int Pp
[MM
+1] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
94 /* 1+x+x^3+x^12+x^16 */
95 int Pp
[MM
+1] = { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 };
98 #error "Either CCSDS must be defined, or MM must be set in range 2-16"
103 #ifdef STANDARD_ORDER /* first byte transmitted is index of x**(KK-1) in message poly*/
104 /* definitions used in the encode routine*/
105 #define MESSAGE(i) data[KK-(i)-1]
106 #define REMAINDER(i) bb[NN-KK-(i)-1]
107 /* definitions used in the decode routine*/
108 #define RECEIVED(i) data[NN-1-(i)]
109 #define ERAS_INDEX(i) (NN-1-eras_pos[i])
110 #define INDEX_TO_POS(i) (NN-1-(i))
111 #else /* first byte transmitted is index of x**0 in message polynomial*/
112 /* definitions used in the encode routine*/
113 #define MESSAGE(i) data[i]
114 #define REMAINDER(i) bb[i]
115 /* definitions used in the decode routine*/
116 #define RECEIVED(i) data[i]
117 #define ERAS_INDEX(i) eras_pos[i]
118 #define INDEX_TO_POS(i) i
122 /* This defines the type used to store an element of the Galois Field
123 * used by the code. Make sure this is something larger than a char if
124 * if anything larger than GF(256) is used.
126 * Note: unsigned char will work up to GF(256) but int seems to run
127 * faster on the Pentium.
131 /* index->polynomial form conversion table */
132 static gf Alpha_to
[NN
+ 1];
134 /* Polynomial->index form conversion table */
135 static gf Index_of
[NN
+ 1];
137 /* No legal value in index form represents zero, so
138 * we need a special value for this purpose
142 /* Generator polynomial g(x) in index form */
143 static gf Gg
[NN
- KK
+ 1];
145 static int RS_init
; /* Initialization flag */
147 /* Compute x % NN, where NN is 2**MM - 1,
148 * without a slow divide
150 /* static inline gf*/
156 x
= (x
>> MM
) + (x
& NN
);
161 #define min_(a,b) ((a) < (b) ? (a) : (b))
163 #define CLEAR(a,n) {\
165 for(ci=(n)-1;ci >=0;ci--)\
169 #define COPY(a,b,n) {\
171 for(ci=(n)-1;ci >=0;ci--)\
175 #define COPYDOWN(a,b,n) {\
177 for(ci=(n)-1;ci >=0;ci--)\
181 static void init_rs(void);
184 /* Conversion lookup tables from conventional alpha to Berlekamp's
185 * dual-basis representation. Used in the CCSDS version only.
186 * taltab[] -- convert conventional to dual basis
187 * tal1tab[] -- convert dual basis to conventional
189 * Note: the actual RS encoder/decoder works with the conventional basis.
190 * So data is converted from dual to conventional basis before either
191 * encoding or decoding and then converted back.
193 static unsigned char taltab
[NN
+1],tal1tab
[NN
+1];
195 static unsigned char tal
[] = { 0x8d, 0xef, 0xec, 0x86, 0xfa, 0x99, 0xaf, 0x7b };
197 /* Generate conversion lookup tables between conventional alpha representation
198 * (@**7, @**6, ...@**0)
199 * and Berlekamp's dual basis representation
207 for(i
=0;i
<256;i
++){/* For each value of input */
209 for(j
=0;j
<8;j
++) /* for each column of matrix */
210 for(k
=0;k
<8;k
++){ /* for each row of matrix */
212 taltab
[i
] ^= tal
[7-k
] & (1<<j
);
214 tal1tab
[taltab
[i
]] = i
;
220 static int Ldec
;/* Decrement for aux location variable in Chien search */
225 for(Ldec
=1;(Ldec
% PRIM
) != 0;Ldec
+= NN
)
233 /* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
234 lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
235 polynomial form -> index form index_of[j=alpha**i] = i
236 alpha=2 is the primitive element of GF(2**m)
237 HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
238 Let @ represent the primitive element commonly called "alpha" that
239 is the root of the primitive polynomial p(x). Then in GF(2^m), for any
241 @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
242 where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
243 of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
244 example the polynomial representation of @^5 would be given by the binary
245 representation of the integer "alpha_to[5]".
246 Similarly, index_of[] can be used as follows:
247 As above, let @ represent the primitive element of GF(2^m) that is
248 the root of the primitive polynomial p(x). In order to find the power
249 of @ (alpha) that has the polynomial representation
250 a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
251 we consider the integer "i" whose binary representation with a(0) being LSB
252 and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
253 "index_of[i]". Now, @^index_of[i] is that element whose polynomial
254 representation is (a(0),a(1),a(2),...,a(m-1)).
256 The element alpha_to[2^m-1] = 0 always signifying that the
257 representation of "@^infinity" = 0 is (0,0,0,...,0).
258 Similarly, the element index_of[0] = A0 always signifying
259 that the power of alpha which has the polynomial representation
260 (0,0,...,0) is "infinity".
267 register int i
, mask
;
271 for (i
= 0; i
< MM
; i
++) {
273 Index_of
[Alpha_to
[i
]] = i
;
274 /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
276 Alpha_to
[MM
] ^= mask
; /* Bit-wise EXOR operation */
277 mask
<<= 1; /* single left-shift */
279 Index_of
[Alpha_to
[MM
]] = MM
;
281 * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
282 * poly-repr of @^i shifted left one-bit and accounting for any @^MM
283 * term that may occur when poly-repr of @^i is shifted.
286 for (i
= MM
+ 1; i
< NN
; i
++) {
287 if (Alpha_to
[i
- 1] >= mask
)
288 Alpha_to
[i
] = Alpha_to
[MM
] ^ ((Alpha_to
[i
- 1] ^ mask
) << 1);
290 Alpha_to
[i
] = Alpha_to
[i
- 1] << 1;
291 Index_of
[Alpha_to
[i
]] = i
;
298 * Obtain the generator polynomial of the TT-error correcting, length
299 * NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0,
304 * If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2.
305 * g(x) = (x+@) (x+@**2)
307 * If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4.
308 * g(x) = (x+1) (x+@) (x+@**2) (x+@**3)
316 for (i
= 0; i
< NN
- KK
; i
++) {
319 * Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by
320 * (@**(B0+i)*PRIM + x)
322 for (j
= i
; j
> 0; j
--)
324 Gg
[j
] = Gg
[j
- 1] ^ Alpha_to
[modnn((Index_of
[Gg
[j
]]) + (B0
+ i
) *PRIM
)];
327 /* Gg[0] can never be zero */
328 Gg
[0] = Alpha_to
[modnn(Index_of
[Gg
[0]] + (B0
+ i
) * PRIM
)];
330 /* convert Gg[] to index form for quicker encoding */
331 for (i
= 0; i
<= NN
- KK
; i
++)
332 Gg
[i
] = Index_of
[Gg
[i
]];
337 * take the string of symbols in data[i], i=0..(k-1) and encode
338 * systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[]
339 * is input and bb[] is output in polynomial form. Encoding is done by using
340 * a feedback shift register with appropriate connections specified by the
341 * elements of Gg[], which was generated above. Codeword is c(X) =
342 * data(X)*X**(NN-KK)+ b(X)
346 encode_rs(dtype data
[], dtype bb
[])
351 #if DEBUG >= 1 && MM != 8
352 /* Check for illegal input values */
364 /* Convert to conventional basis */
366 MESSAGE(i
) = tal1tab
[MESSAGE(i
)];
369 for(i
= KK
- 1; i
>= 0; i
--) {
370 feedback
= Index_of
[MESSAGE(i
) ^ REMAINDER(NN
- KK
- 1)];
371 if (feedback
!= A0
) { /* feedback term is non-zero */
372 for (j
= NN
- KK
- 1; j
> 0; j
--)
374 REMAINDER(j
) = REMAINDER(j
- 1) ^ Alpha_to
[modnn(Gg
[j
] + feedback
)];
376 REMAINDER(j
) = REMAINDER(j
- 1);
377 REMAINDER(0) = Alpha_to
[modnn(Gg
[0] + feedback
)];
378 } else { /* feedback term is zero. encoder becomes a
379 * single-byte shifter */
380 for (j
= NN
- KK
- 1; j
> 0; j
--)
381 REMAINDER(j
) = REMAINDER(j
- 1);
386 /* Convert to l-basis */
388 MESSAGE(i
) = taltab
[MESSAGE(i
)];
395 * Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful,
396 * writes the codeword into data[] itself. Otherwise data[] is unaltered.
398 * Return number of symbols corrected, or -1 if codeword is illegal
399 * or uncorrectable. If eras_pos is non-null, the detected error locations
400 * are written back. NOTE! This array must be at least NN-KK elements long.
402 * First "no_eras" erasures are declared by the calling program. Then, the
403 * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
404 * If the number of channel errors is not greater than "t_after_eras" the
405 * transmitted codeword will be recovered. Details of algorithm can be found
406 * in R. Blahut's "Theory ... of Error-Correcting Codes".
408 * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
409 * will result. The decoder *could* check for this condition, but it would involve
410 * extra time on every decoding operation.
414 eras_dec_rs(dtype data
[], int eras_pos
[], int no_eras
)
416 int deg_lambda
, el
, deg_omega
;
418 gf u
,q
,tmp
,num1
,num2
,den
,discr_r
;
419 gf lambda
[NN
-KK
+ 1], s
[NN
-KK
+ 1]; /* Err+Eras Locator poly
420 * and syndrome poly */
421 gf b
[NN
-KK
+ 1], t
[NN
-KK
+ 1], omega
[NN
-KK
+ 1];
422 gf root
[NN
-KK
], reg
[NN
-KK
+ 1], loc
[NN
-KK
];
423 int syn_error
, count
;
429 /* Convert to conventional basis */
431 RECEIVED(i
) = tal1tab
[RECEIVED(i
)];
434 #if DEBUG >= 1 && MM != 8
435 /* Check for illegal input values */
440 /* form the syndromes; i.e., evaluate data(x) at roots of g(x)
441 * namely @**(B0+i)*PRIM, i = 0, ... ,(NN-KK-1)
443 for(i
=1;i
<=NN
-KK
;i
++){
449 tmp
= Index_of
[RECEIVED(j
)];
451 /* s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*j)]; */
452 for(i
=1;i
<=NN
-KK
;i
++)
453 s
[i
] ^= Alpha_to
[modnn(tmp
+ (B0
+i
-1)*PRIM
*j
)];
455 /* Convert syndromes to index form, checking for nonzero condition */
457 for(i
=1;i
<=NN
-KK
;i
++){
459 /*ws_debug("syndrome %d = %x\n",i,s[i]);*/
460 s
[i
] = Index_of
[s
[i
]];
464 /* if syndrome is zero, data[] is a codeword and there are no
465 * errors to correct. So return data[] unmodified
470 CLEAR(&lambda
[1],NN
-KK
);
474 /* Init lambda to be the erasure locator polynomial */
475 lambda
[1] = Alpha_to
[modnn(PRIM
* ERAS_INDEX(0))];
476 for (i
= 1; i
< no_eras
; i
++) {
477 u
= modnn(PRIM
*ERAS_INDEX(i
));
478 for (j
= i
+1; j
> 0; j
--) {
479 tmp
= Index_of
[lambda
[j
- 1]];
481 lambda
[j
] ^= Alpha_to
[modnn(u
+ tmp
)];
485 /* Test code that verifies the erasure locator polynomial just constructed
486 Needed only for decoder debugging. */
488 /* find roots of the erasure location polynomial */
489 for(i
=1;i
<=no_eras
;i
++)
490 reg
[i
] = Index_of
[lambda
[i
]];
492 for (i
= 1,k
=NN
-Ldec
; i
<= NN
; i
++,k
= modnn(NN
+k
-Ldec
)) {
494 for (j
= 1; j
<= no_eras
; j
++)
496 reg
[j
] = modnn(reg
[j
] + j
);
497 q
^= Alpha_to
[reg
[j
]];
501 /* store root and error location number indices */
506 if (count
!= no_eras
) {
507 ws_debug("\n lambda(x) is WRONG\n");
512 printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
513 for (i
= 0; i
< count
; i
++)
514 printf("%d ", loc
[i
]);
519 for(i
=0;i
<NN
-KK
+1;i
++)
520 b
[i
] = Index_of
[lambda
[i
]];
523 * Begin Berlekamp-Massey algorithm to determine error+erasure
528 while (++r
<= NN
-KK
) { /* r is the step number */
529 /* Compute discrepancy at the r-th step in poly-form */
531 for (i
= 0; i
< r
; i
++){
532 if ((lambda
[i
] != 0) && (s
[r
- i
] != A0
)) {
533 discr_r
^= Alpha_to
[modnn(Index_of
[lambda
[i
]] + s
[r
- i
])];
536 discr_r
= Index_of
[discr_r
]; /* Index form */
538 /* 2 lines below: B(x) <-- x*B(x) */
539 COPYDOWN(&b
[1],b
,NN
-KK
);
542 /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
544 for (i
= 0 ; i
< NN
-KK
; i
++) {
546 t
[i
+1] = lambda
[i
+1] ^ Alpha_to
[modnn(discr_r
+ b
[i
])];
548 t
[i
+1] = lambda
[i
+1];
550 if (2 * el
<= r
+ no_eras
- 1) {
551 el
= r
+ no_eras
- el
;
553 * 2 lines below: B(x) <-- inv(discr_r) *
556 for (i
= 0; i
<= NN
-KK
; i
++)
557 b
[i
] = (lambda
[i
] == 0) ? A0
: modnn(Index_of
[lambda
[i
]] - discr_r
+ NN
);
559 /* 2 lines below: B(x) <-- x*B(x) */
560 COPYDOWN(&b
[1],b
,NN
-KK
);
563 COPY(lambda
,t
,NN
-KK
+1);
567 /* Convert lambda to index form and compute deg(lambda(x)) */
569 for(i
=0;i
<NN
-KK
+1;i
++){
570 lambda
[i
] = Index_of
[lambda
[i
]];
575 * Find roots of the error+erasure locator polynomial by Chien
578 COPY(®
[1],&lambda
[1],NN
-KK
);
579 count
= 0; /* Number of roots of lambda(x) */
580 for (i
= 1,k
=NN
-Ldec
; i
<= NN
; i
++,k
= modnn(NN
+k
-Ldec
)) {
582 for (j
= deg_lambda
; j
> 0; j
--){
584 reg
[j
] = modnn(reg
[j
] + j
);
585 q
^= Alpha_to
[reg
[j
]];
590 /* store root (index-form) and error location number */
593 /* If we've already found max possible roots,
594 * abort the search to save time
596 if(++count
== deg_lambda
)
599 if (deg_lambda
!= count
) {
601 * deg(lambda) unequal to number of roots => uncorrectable
608 * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
609 * x**(NN-KK)). in index form. Also find deg(omega).
612 for (i
= 0; i
< NN
-KK
;i
++){
614 j
= (deg_lambda
< i
) ? deg_lambda
: i
;
616 if ((s
[i
+ 1 - j
] != A0
) && (lambda
[j
] != A0
))
617 tmp
^= Alpha_to
[modnn(s
[i
+ 1 - j
] + lambda
[j
])];
621 omega
[i
] = Index_of
[tmp
];
626 * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
627 * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
629 for (j
= count
-1; j
>=0; j
--) {
631 for (i
= deg_omega
; i
>= 0; i
--) {
633 num1
^= Alpha_to
[modnn(omega
[i
] + i
* root
[j
])];
635 num2
= Alpha_to
[modnn(root
[j
] * (B0
- 1) + NN
)];
638 /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
639 for (i
= min_(deg_lambda
,NN
-KK
-1) & ~1; i
>= 0; i
-=2) {
640 if(lambda
[i
+1] != A0
)
641 den
^= Alpha_to
[modnn(lambda
[i
+1] + i
* root
[j
])];
645 ws_debug("\n ERROR: denominator = 0\n");
647 /* Convert to dual- basis */
651 /* Apply error to data */
653 RECEIVED(loc
[j
]) ^= Alpha_to
[modnn(Index_of
[num1
] + Index_of
[num2
] + NN
- Index_of
[den
])];
658 /* Convert to dual- basis */
660 RECEIVED(i
) = taltab
[RECEIVED(i
)];
662 if(eras_pos
!= NULL
){
663 for(i
=0;i
<count
;i
++){
665 eras_pos
[i
] = INDEX_TO_POS(loc
[i
]);
670 /* Encoder/decoder initialization - call this first! */
686 * Editor modelines - https://www.wireshark.org/tools/modelines.html
691 * indent-tabs-mode: nil
694 * ex: set shiftwidth=2 tabstop=8 expandtab:
695 * :indentSize=2:tabSize=8:noTabs=true: