/*********************************************************************** * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 * * This software library is licensed under terms of the GNU GENERAL * PUBLIC LICENSE * * * RSCODE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RSCODE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Rscode. If not, see . * * Commercial licensing is available under a separate license, please * contact author for details. * * Source code is available at http://rscode.sourceforge.net * Berlekamp-Peterson and Berlekamp-Massey Algorithms for error-location * * From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 205. * * This finds the coefficients of the error locator polynomial. * * The roots are then found by looking for the values of a^n * where evaluating the polynomial yields zero. * * Error correction is done using the error-evaluator equation on pp 207. * */ #include #include "ecc.h" /* The Error Locator Polynomial, also known as Lambda or Sigma. Lambda[0] == 1 */ static int Lambda[MAXDEG]; /* The Error Evaluator Polynomial */ static int Omega[MAXDEG]; /* local ANSI declarations */ static int compute_discrepancy(int lambda[], int S[], int L, int n); static void init_gamma(int gamma[]); static void compute_modified_omega (void); static void mul_z_poly (int src[]); /* error locations found using Chien's search*/ static int ErrorLocs[256]; int NErrors; extern int xMaxErrors; /* erasure flags */ static int ErasureLocs[256]; static int NErasures; /* From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 216. */ void Modified_Berlekamp_Massey (void) { int n, L, L2, k, d, i; int psi[MAXDEG], psi2[MAXDEG], D[MAXDEG]; int gamma[MAXDEG]; /* initialize Gamma, the erasure locator polynomial */ init_gamma(gamma); /* initialize to z */ copy_poly(D, gamma); mul_z_poly(D); copy_poly(psi, gamma); k = -1; L = NErasures; for (n = NErasures; n < NPAR; n++) { d = compute_discrepancy(psi, synBytes, L, n); if (d != 0) { /* psi2 = psi - d*D */ for (i = 0; i < NPAR*2; i++) psi2[i] = psi[i] ^ gmult(d, D[i]); if (L < (n-k)) { L2 = n-k; k = n-L; /* D = scale_poly(ginv(d), psi); */ for (i = 0; i < NPAR*2; i++) D[i] = gmult(psi[i], ginv(d)); L = L2; } /* psi = psi2 */ for (i = 0; i < NPAR*2; i++) psi[i] = psi2[i]; } mul_z_poly(D); } for(i = 0; i < NPAR*2; i++) Lambda[i] = psi[i]; compute_modified_omega(); } /* given Psi (called Lambda in Modified_Berlekamp_Massey) and synBytes, compute the combined erasure/error evaluator polynomial as Psi*S mod z^4 */ void compute_modified_omega () { int i; int product[MAXDEG*2]; mult_polys(product, Lambda, synBytes); zero_poly(Omega); for(i = 0; i < NPAR; i++) Omega[i] = product[i]; } /* polynomial multiplication */ void mult_polys (int dst[], int p1[], int p2[]) { int i, j; int tmp1[MAXDEG*2]; for (i=0; i < (NPAR*2*2); i++) dst[i] = 0; for (i = 0; i < NPAR*2; i++) { for(j=NPAR*2; j<(NPAR*2*2); j++) tmp1[j]=0; /* scale tmp1 by p1[i] */ for(j=0; j= i; j--) tmp1[j] = tmp1[j-i]; for (j = 0; j < i; j++) tmp1[j] = 0; /* add into partial product */ for(j=0; j < (NPAR*2*2); j++) dst[j] ^= tmp1[j]; } } /* gamma = product (1-z*a^Ij) for erasure locs Ij */ void init_gamma (int gamma[]) { int e, tmp[MAXDEG]; zero_poly(gamma); zero_poly(tmp); gamma[0] = 1; for (e = 0; e < NErasures; e++) { copy_poly(tmp, gamma); scale_poly(gexp[ErasureLocs[e]], tmp); mul_z_poly(tmp); add_polys(gamma, tmp); } } void compute_next_omega (int d, int A[], int dst[], int src[]) { int i; for ( i = 0; i < NPAR*2; i++) { dst[i] = src[i] ^ gmult(d, A[i]); } } int compute_discrepancy (int lambda[], int S[], int L, int n) { int i, sum=0; for (i = 0; i <= L; i++) sum ^= gmult(lambda[i], S[n-i]); return (sum); } /********** polynomial arithmetic *******************/ void add_polys (int dst[], int src[]) { int i; for (i = 0; i < NPAR*2; i++) dst[i] ^= src[i]; } void copy_poly (int dst[], int src[]) { int i; for (i = 0; i < NPAR*2; i++) dst[i] = src[i]; } void scale_poly (int k, int poly[]) { int i; for (i = 0; i < NPAR*2; i++) poly[i] = gmult(k, poly[i]); } void zero_poly (int poly[]) { int i; for (i = 0; i < NPAR*2; i++) poly[i] = 0; } /* multiply by z, i.e., shift right by 1 */ static void mul_z_poly (int src[]) { int i; for (i = NPAR*2-1; i > 0; i--) src[i] = src[i-1]; src[0] = 0; } /* Finds all the roots of an error-locator polynomial with coefficients * Lambda[j] by evaluating Lambda at successive values of alpha. * * This can be tested with the decoder's equations case. */ void Find_Roots (void) { int sum, r, k; NErrors = 0; for (r = 1; r < 256; r++) { sum = 0; /* evaluate lambda at r */ for (k = 0; k < NPAR+1; k++) { sum ^= gmult(gexp[(k*r)%255], Lambda[k]); } if (sum == 0) { ErrorLocs[NErrors] = (255-r); NErrors++; if (DEBUG) fprintf(stderr, "Root found at r = %d, (255-r) = %d\n", r, (255-r)); } } } /* Combined Erasure And Error Magnitude Computation * * Pass in the codeword, its size in bytes, as well as * an array of any known erasure locations, along the number * of these erasures. * * Evaluate Omega(actually Psi)/Lambda' at the roots * alpha^(-i) for error locs i. * * returns 1 if everything ok, or 0 if an out-of-bounds error is found * */ int correct_errors_erasures (unsigned char codeword[], int csize, int nerasures, int erasures[]) { int r, i, j, err; /* If you want to take advantage of erasure correction, be sure to set NErasures and ErasureLocs[] with the locations of erasures. */ NErasures = nerasures; for (i = 0; i < NErasures; i++) ErasureLocs[i] = erasures[i]; Modified_Berlekamp_Massey(); Find_Roots(); if (DEBUG) fprintf(stderr, "RS found %d errors\n", NErrors); if ((NErrors <= xMaxErrors) && NErrors > 0) { /* first check for illegal error locs */ for (r = 0; r < NErrors; r++) { if (ErrorLocs[r] >= csize) { if (DEBUG) fprintf(stderr, "Error loc i=%d outside of codeword length %d\n", i, csize); return(0); } } for (r = 0; r < NErrors; r++) { int num, denom; i = ErrorLocs[r]; /* evaluate Omega at alpha^(-i) */ num = 0; for (j = 0; j < NPAR*2; j++) num ^= gmult(Omega[j], gexp[((255-i)*j)%255]); /* evaluate Lambda' (derivative) at alpha^(-i) ; all odd powers disappear */ denom = 0; for (j = 1; j < NPAR*2; j += 2) { denom ^= gmult(Lambda[j], gexp[((255-i)*(j-1)) % 255]); } err = gmult(num, ginv(denom)); if (DEBUG) fprintf(stderr, "Error magnitude %#x at loc %d\n", err, csize-i); codeword[csize-i-1] ^= err; } return(1); } else { if (DEBUG && NErrors) fprintf(stderr, "Uncorrectable codeword\n"); return(0); } }