509 lines
24 KiB
C
509 lines
24 KiB
C
#include "correct/reed-solomon/encode.h"
|
|
|
|
// calculate all syndromes of the received polynomial at the roots of the generator
|
|
// because we're evaluating at the roots of the generator, and because the transmitted
|
|
// polynomial was made to be a product of the generator, we know that the transmitted
|
|
// polynomial is 0 at these roots
|
|
// any nonzero syndromes we find here are the values of the error polynomial evaluated
|
|
// at these roots, so these values give us a window into the error polynomial. if
|
|
// these syndromes are all zero, then we can conclude the error polynomial is also
|
|
// zero. if they're nonzero, then we know our message received an error in transit.
|
|
// returns true if syndromes are all zero
|
|
static bool reed_solomon_find_syndromes(field_t field, polynomial_t msgpoly, field_logarithm_t **generator_root_exp,
|
|
field_element_t *syndromes, size_t min_distance) {
|
|
bool all_zero = true;
|
|
memset(syndromes, 0, min_distance * sizeof(field_element_t));
|
|
for (unsigned int i = 0; i < min_distance; i++) {
|
|
// profiling reveals that this function takes about 50% of the cpu time of
|
|
// decoding. so, in order to speed it up a little, we precompute and save
|
|
// the successive powers of the roots of the generator, which are
|
|
// located in generator_root_exp
|
|
field_element_t eval = polynomial_eval_lut(field, msgpoly, generator_root_exp[i]);
|
|
if (eval) {
|
|
all_zero = false;
|
|
}
|
|
syndromes[i] = eval;
|
|
}
|
|
return all_zero;
|
|
}
|
|
|
|
// Berlekamp-Massey algorithm to find LFSR that describes syndromes
|
|
// returns number of errors and writes the error locator polynomial to rs->error_locator
|
|
static unsigned int reed_solomon_find_error_locator(correct_reed_solomon *rs, size_t num_erasures) {
|
|
unsigned int numerrors = 0;
|
|
|
|
memset(rs->error_locator.coeff, 0, (rs->min_distance + 1) * sizeof(field_element_t));
|
|
|
|
// initialize to f(x) = 1
|
|
rs->error_locator.coeff[0] = 1;
|
|
rs->error_locator.order = 0;
|
|
|
|
memcpy(rs->last_error_locator.coeff, rs->error_locator.coeff, (rs->min_distance + 1) * sizeof(field_element_t));
|
|
rs->last_error_locator.order = rs->error_locator.order;
|
|
|
|
field_element_t discrepancy;
|
|
field_element_t last_discrepancy = 1;
|
|
unsigned int delay_length = 1;
|
|
|
|
for (unsigned int i = rs->error_locator.order; i < rs->min_distance - num_erasures; i++) {
|
|
discrepancy = rs->syndromes[i];
|
|
for (unsigned int j = 1; j <= numerrors; j++) {
|
|
discrepancy = field_add(rs->field, discrepancy,
|
|
field_mul(rs->field, rs->error_locator.coeff[j], rs->syndromes[i - j]));
|
|
}
|
|
|
|
if (!discrepancy) {
|
|
// our existing LFSR describes the new syndrome as well
|
|
// leave it as-is but update the number of delay elements
|
|
// so that if a discrepancy occurs later we can eliminate it
|
|
delay_length++;
|
|
continue;
|
|
}
|
|
|
|
if (2 * numerrors <= i) {
|
|
// there's a discrepancy, but we still have room for more taps
|
|
// lengthen LFSR by one tap and set weight to eliminate discrepancy
|
|
|
|
// shift the last locator by the delay length, multiply by discrepancy,
|
|
// and divide by the last discrepancy
|
|
// we move down because we're shifting up, and this prevents overwriting
|
|
for (int j = rs->last_error_locator.order; j >= 0; j--) {
|
|
// the bounds here will be ok since we have a headroom of numerrors
|
|
rs->last_error_locator.coeff[j + delay_length] = field_div(
|
|
rs->field, field_mul(rs->field, rs->last_error_locator.coeff[j], discrepancy), last_discrepancy);
|
|
}
|
|
for (int j = delay_length - 1; j >= 0; j--) {
|
|
rs->last_error_locator.coeff[j] = 0;
|
|
}
|
|
|
|
// locator = locator - last_locator
|
|
// we will also update last_locator to be locator before this loop takes place
|
|
field_element_t temp;
|
|
for (int j = 0; j <= (rs->last_error_locator.order + delay_length); j++) {
|
|
temp = rs->error_locator.coeff[j];
|
|
rs->error_locator.coeff[j] =
|
|
field_add(rs->field, rs->error_locator.coeff[j], rs->last_error_locator.coeff[j]);
|
|
rs->last_error_locator.coeff[j] = temp;
|
|
}
|
|
unsigned int temp_order = rs->error_locator.order;
|
|
rs->error_locator.order = rs->last_error_locator.order + delay_length;
|
|
rs->last_error_locator.order = temp_order;
|
|
|
|
// now last_locator is locator before we started,
|
|
// and locator is (locator - (discrepancy/last_discrepancy) * x^(delay_length) * last_locator)
|
|
|
|
numerrors = i + 1 - numerrors;
|
|
last_discrepancy = discrepancy;
|
|
delay_length = 1;
|
|
continue;
|
|
}
|
|
|
|
// no more taps
|
|
// unlike the previous case, we are preserving last locator,
|
|
// but we'll update locator as before
|
|
// we're basically flattening the two loops from the previous case because
|
|
// we no longer need to update last_locator
|
|
for (int j = rs->last_error_locator.order; j >= 0; j--) {
|
|
rs->error_locator.coeff[j + delay_length] =
|
|
field_add(rs->field, rs->error_locator.coeff[j + delay_length],
|
|
field_div(rs->field, field_mul(rs->field, rs->last_error_locator.coeff[j], discrepancy),
|
|
last_discrepancy));
|
|
}
|
|
rs->error_locator.order = (rs->last_error_locator.order + delay_length > rs->error_locator.order)
|
|
? rs->last_error_locator.order + delay_length
|
|
: rs->error_locator.order;
|
|
delay_length++;
|
|
}
|
|
return rs->error_locator.order;
|
|
}
|
|
|
|
// find the roots of the error locator polynomial
|
|
// Chien search
|
|
bool reed_solomon_factorize_error_locator(field_t field, unsigned int num_skip, polynomial_t locator_log, field_element_t *roots,
|
|
field_logarithm_t **element_exp) {
|
|
// normally it'd be tricky to find all the roots
|
|
// but, the finite field is awfully finite...
|
|
// just brute force search across every field element
|
|
unsigned int root = num_skip;
|
|
memset(roots + num_skip, 0, (locator_log.order) * sizeof(field_element_t));
|
|
for (field_operation_t i = 0; i < 256; i++) {
|
|
// we make two optimizations here to help this search go faster
|
|
// a) we have precomputed the first successive powers of every single element
|
|
// in the field. we need at most n powers, where n is the largest possible
|
|
// degree of the error locator
|
|
// b) we have precomputed the error locator polynomial in log form, which
|
|
// helps reduce some lookups that would be done here
|
|
if (!polynomial_eval_log_lut(field, locator_log, element_exp[i])) {
|
|
roots[root] = (field_element_t)i;
|
|
root++;
|
|
}
|
|
}
|
|
// this is where we find out if we are have too many errors to recover from
|
|
// berlekamp-massey may have built an error locator that has 0 discrepancy
|
|
// on the syndromes but doesn't have enough roots
|
|
return root == locator_log.order + num_skip;
|
|
}
|
|
|
|
// use error locator and syndromes to find the error evaluator polynomial
|
|
void reed_solomon_find_error_evaluator(field_t field, polynomial_t locator, polynomial_t syndromes,
|
|
polynomial_t error_evaluator) {
|
|
// the error evaluator, omega(x), is S(x)*Lamba(x) mod x^(2t)
|
|
// where S(x) is a polynomial constructed from the syndromes
|
|
// S(1) + S(2)*x + ... + S(2t)*x(2t - 1)
|
|
// and Lambda(x) is the error locator
|
|
// the modulo is implicit here -- we have limited the max length of error_evaluator,
|
|
// which polynomial_mul will interpret to mean that it should not compute
|
|
// powers larger than that, which is the same as performing mod x^(2t)
|
|
polynomial_mul(field, locator, syndromes, error_evaluator);
|
|
}
|
|
|
|
// use error locator, error roots and syndromes to find the error values
|
|
// that is, the elements in the finite field which can be added to the received
|
|
// polynomial at the locations of the error roots in order to produce the
|
|
// transmitted polynomial
|
|
// forney algorithm
|
|
void reed_solomon_find_error_values(correct_reed_solomon *rs) {
|
|
// error value e(j) = -(X(j)^(1-c) * omega(X(j)^-1))/(lambda'(X(j)^-1))
|
|
// where X(j)^-1 is a root of the error locator, omega(X) is the error evaluator,
|
|
// lambda'(X) is the first formal derivative of the error locator,
|
|
// and c is the first consecutive root of the generator used in encoding
|
|
|
|
// first find omega(X), the error evaluator
|
|
// we generate S(x), the polynomial constructed from the roots of the syndromes
|
|
// this is *not* the polynomial constructed by expanding the products of roots
|
|
// S(x) = S(1) + S(2)*x + ... + S(2t)*x(2t - 1)
|
|
polynomial_t syndrome_poly;
|
|
syndrome_poly.order = rs->min_distance - 1;
|
|
syndrome_poly.coeff = rs->syndromes;
|
|
memset(rs->error_evaluator.coeff, 0, (rs->error_evaluator.order + 1) * sizeof(field_element_t));
|
|
reed_solomon_find_error_evaluator(rs->field, rs->error_locator, syndrome_poly, rs->error_evaluator);
|
|
|
|
// now find lambda'(X)
|
|
rs->error_locator_derivative.order = rs->error_locator.order - 1;
|
|
polynomial_formal_derivative(rs->field, rs->error_locator, rs->error_locator_derivative);
|
|
|
|
// calculate each e(j)
|
|
for (unsigned int i = 0; i < rs->error_locator.order; i++) {
|
|
if (rs->error_roots[i] == 0) {
|
|
continue;
|
|
}
|
|
rs->error_vals[i] = field_mul(
|
|
rs->field, field_pow(rs->field, rs->error_roots[i], rs->first_consecutive_root - 1),
|
|
field_div(
|
|
rs->field, polynomial_eval_lut(rs->field, rs->error_evaluator, rs->element_exp[rs->error_roots[i]]),
|
|
polynomial_eval_lut(rs->field, rs->error_locator_derivative, rs->element_exp[rs->error_roots[i]])));
|
|
}
|
|
}
|
|
|
|
void reed_solomon_find_error_locations(field_t field, field_logarithm_t generator_root_gap,
|
|
field_element_t *error_roots, field_logarithm_t *error_locations,
|
|
unsigned int num_errors, unsigned int num_skip) {
|
|
for (unsigned int i = 0; i < num_errors; i++) {
|
|
// the error roots are the reciprocals of the error locations, so div 1 by them
|
|
|
|
// we do mod 255 here because the log table aliases at index 1
|
|
// the log of 1 is both 0 and 255 (alpha^255 = alpha^0 = 1)
|
|
// for most uses it makes sense to have log(1) = 255, but in this case
|
|
// we're interested in a byte index, and the 255th index is not even valid
|
|
// just wrap it back to 0
|
|
|
|
if (error_roots[i] == 0) {
|
|
continue;
|
|
}
|
|
|
|
field_operation_t loc = field_div(field, 1, error_roots[i]);
|
|
for (field_operation_t j = 0; j < 256; j++) {
|
|
if (field_pow(field, j, generator_root_gap) == loc) {
|
|
error_locations[i] = field.log[j];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// erasure method -- take given locations and convert to roots
|
|
// this is the inverse of reed_solomon_find_error_locations
|
|
static void reed_solomon_find_error_roots_from_locations(field_t field, field_logarithm_t generator_root_gap,
|
|
const field_logarithm_t *error_locations,
|
|
field_element_t *error_roots, unsigned int num_errors) {
|
|
for (unsigned int i = 0; i < num_errors; i++) {
|
|
field_element_t loc = field_pow(field, field.exp[error_locations[i]], generator_root_gap);
|
|
// field_element_t loc = field.exp[error_locations[i]];
|
|
error_roots[i] = field_div(field, 1, loc);
|
|
// error_roots[i] = loc;
|
|
}
|
|
}
|
|
|
|
// erasure method -- given the roots of the error locator, create the polynomial
|
|
static polynomial_t reed_solomon_find_error_locator_from_roots(field_t field, unsigned int num_errors,
|
|
field_element_t *error_roots,
|
|
polynomial_t error_locator,
|
|
polynomial_t *scratch) {
|
|
// multiply out roots to build the error locator polynomial
|
|
return polynomial_init_from_roots(field, num_errors, error_roots, error_locator, scratch);
|
|
}
|
|
|
|
// erasure method
|
|
static void reed_solomon_find_modified_syndromes(correct_reed_solomon *rs, field_element_t *syndromes, polynomial_t error_locator, field_element_t *modified_syndromes) {
|
|
polynomial_t syndrome_poly;
|
|
syndrome_poly.order = rs->min_distance - 1;
|
|
syndrome_poly.coeff = syndromes;
|
|
|
|
polynomial_t modified_syndrome_poly;
|
|
modified_syndrome_poly.order = rs->min_distance - 1;
|
|
modified_syndrome_poly.coeff = modified_syndromes;
|
|
|
|
polynomial_mul(rs->field, error_locator, syndrome_poly, modified_syndrome_poly);
|
|
}
|
|
|
|
void correct_reed_solomon_decoder_create(correct_reed_solomon *rs) {
|
|
rs->has_init_decode = true;
|
|
rs->syndromes = calloc(rs->min_distance, sizeof(field_element_t));
|
|
rs->modified_syndromes = calloc(2 * rs->min_distance, sizeof(field_element_t));
|
|
rs->received_polynomial = polynomial_create(rs->block_length - 1);
|
|
rs->error_locator = polynomial_create(rs->min_distance);
|
|
rs->error_locator_log = polynomial_create(rs->min_distance);
|
|
rs->erasure_locator = polynomial_create(rs->min_distance);
|
|
rs->error_roots = calloc(2 * rs->min_distance, sizeof(field_element_t));
|
|
rs->error_vals = malloc(rs->min_distance * sizeof(field_element_t));
|
|
rs->error_locations = malloc(rs->min_distance * sizeof(field_logarithm_t));
|
|
|
|
rs->last_error_locator = polynomial_create(rs->min_distance);
|
|
rs->error_evaluator = polynomial_create(rs->min_distance - 1);
|
|
rs->error_locator_derivative = polynomial_create(rs->min_distance - 1);
|
|
|
|
// calculate and store the first block_length powers of every generator root
|
|
// we would have to do this work in order to calculate the syndromes
|
|
// if we save it, we can prevent the need to recalculate it on subsequent calls
|
|
// total memory usage is min_distance * block_length bytes e.g. 32 * 255 ~= 8k
|
|
rs->generator_root_exp = malloc(rs->min_distance * sizeof(field_logarithm_t *));
|
|
for (unsigned int i = 0; i < rs->min_distance; i++) {
|
|
rs->generator_root_exp[i] = malloc(rs->block_length * sizeof(field_logarithm_t));
|
|
polynomial_build_exp_lut(rs->field, rs->generator_roots[i], rs->block_length - 1, rs->generator_root_exp[i]);
|
|
}
|
|
|
|
// calculate and store the first min_distance powers of every element in the field
|
|
// we would have to do this for chien search anyway, and its size is only 256 * min_distance bytes
|
|
// for min_distance = 32 this is 8k of memory, a pittance for the speedup we receive in exchange
|
|
// we also get to reuse this work during error value calculation
|
|
rs->element_exp = malloc(256 * sizeof(field_logarithm_t *));
|
|
for (field_operation_t i = 0; i < 256; i++) {
|
|
rs->element_exp[i] = malloc(rs->min_distance * sizeof(field_logarithm_t));
|
|
polynomial_build_exp_lut(rs->field, i, rs->min_distance - 1, rs->element_exp[i]);
|
|
}
|
|
|
|
rs->init_from_roots_scratch[0] = polynomial_create(rs->min_distance);
|
|
rs->init_from_roots_scratch[1] = polynomial_create(rs->min_distance);
|
|
}
|
|
|
|
ssize_t correct_reed_solomon_decode(correct_reed_solomon *rs, const uint8_t *encoded, size_t encoded_length,
|
|
uint8_t *msg) {
|
|
if (encoded_length > rs->block_length) {
|
|
return -1;
|
|
}
|
|
|
|
// the message is the non-remainder part
|
|
size_t msg_length = encoded_length - rs->min_distance;
|
|
// if they handed us a nonfull block, we'll write in 0s
|
|
size_t pad_length = rs->block_length - encoded_length;
|
|
|
|
if (!rs->has_init_decode) {
|
|
// initialize rs for decoding
|
|
correct_reed_solomon_decoder_create(rs);
|
|
}
|
|
|
|
// we need to copy to our local buffer
|
|
// the buffer we're given has the coordinates in the wrong direction
|
|
// e.g. byte 0 corresponds to the 254th order coefficient
|
|
// so we're going to flip and then write padding
|
|
// the final copied buffer will look like
|
|
// | rem (rs->min_distance) | msg (msg_length) | pad (pad_length) |
|
|
|
|
for (unsigned int i = 0; i < encoded_length; i++) {
|
|
rs->received_polynomial.coeff[i] = encoded[encoded_length - (i + 1)];
|
|
}
|
|
|
|
// fill the pad_length with 0s
|
|
for (unsigned int i = 0; i < pad_length; i++) {
|
|
rs->received_polynomial.coeff[i + encoded_length] = 0;
|
|
}
|
|
|
|
|
|
bool all_zero = reed_solomon_find_syndromes(rs->field, rs->received_polynomial, rs->generator_root_exp,
|
|
rs->syndromes, rs->min_distance);
|
|
|
|
if (all_zero) {
|
|
// syndromes were all zero, so there was no error in the message
|
|
// copy to msg and we are done
|
|
for (unsigned int i = 0; i < msg_length; i++) {
|
|
msg[i] = rs->received_polynomial.coeff[encoded_length - (i + 1)];
|
|
}
|
|
return msg_length;
|
|
}
|
|
|
|
unsigned int order = reed_solomon_find_error_locator(rs, 0);
|
|
// XXX fix this vvvv
|
|
rs->error_locator.order = order;
|
|
|
|
for (unsigned int i = 0; i <= rs->error_locator.order; i++) {
|
|
// this is a little strange since the coeffs are logs, not elements
|
|
// also, we'll be storing log(0) = 0 for any 0 coeffs in the error locator
|
|
// that would seem bad but we'll just be using this in chien search, and we'll skip all 0 coeffs
|
|
// (you might point out that log(1) also = 0, which would seem to alias. however, that's ok,
|
|
// because log(1) = 255 as well, and in fact that's how it's represented in our log table)
|
|
rs->error_locator_log.coeff[i] = rs->field.log[rs->error_locator.coeff[i]];
|
|
}
|
|
rs->error_locator_log.order = rs->error_locator.order;
|
|
|
|
if (!reed_solomon_factorize_error_locator(rs->field, 0, rs->error_locator_log, rs->error_roots, rs->element_exp)) {
|
|
// roots couldn't be found, so there were too many errors to deal with
|
|
// RS has failed for this message
|
|
return -1;
|
|
}
|
|
|
|
reed_solomon_find_error_locations(rs->field, rs->generator_root_gap, rs->error_roots, rs->error_locations,
|
|
rs->error_locator.order, 0);
|
|
|
|
reed_solomon_find_error_values(rs);
|
|
|
|
for (unsigned int i = 0; i < rs->error_locator.order; i++) {
|
|
rs->received_polynomial.coeff[rs->error_locations[i]] =
|
|
field_sub(rs->field, rs->received_polynomial.coeff[rs->error_locations[i]], rs->error_vals[i]);
|
|
}
|
|
|
|
for (unsigned int i = 0; i < msg_length; i++) {
|
|
msg[i] = rs->received_polynomial.coeff[encoded_length - (i + 1)];
|
|
}
|
|
|
|
return msg_length;
|
|
}
|
|
|
|
ssize_t correct_reed_solomon_decode_with_erasures(correct_reed_solomon *rs, const uint8_t *encoded,
|
|
size_t encoded_length, const uint8_t *erasure_locations,
|
|
size_t erasure_length, uint8_t *msg) {
|
|
if (!erasure_length) {
|
|
return correct_reed_solomon_decode(rs, encoded, encoded_length, msg);
|
|
}
|
|
|
|
if (encoded_length > rs->block_length) {
|
|
return -1;
|
|
}
|
|
|
|
if (erasure_length > rs->min_distance) {
|
|
return -1;
|
|
}
|
|
|
|
// the message is the non-remainder part
|
|
size_t msg_length = encoded_length - rs->min_distance;
|
|
// if they handed us a nonfull block, we'll write in 0s
|
|
size_t pad_length = rs->block_length - encoded_length;
|
|
|
|
if (!rs->has_init_decode) {
|
|
// initialize rs for decoding
|
|
correct_reed_solomon_decoder_create(rs);
|
|
}
|
|
|
|
// we need to copy to our local buffer
|
|
// the buffer we're given has the coordinates in the wrong direction
|
|
// e.g. byte 0 corresponds to the 254th order coefficient
|
|
// so we're going to flip and then write padding
|
|
// the final copied buffer will look like
|
|
// | rem (rs->min_distance) | msg (msg_length) | pad (pad_length) |
|
|
|
|
for (unsigned int i = 0; i < encoded_length; i++) {
|
|
rs->received_polynomial.coeff[i] = encoded[encoded_length - (i + 1)];
|
|
}
|
|
|
|
// fill the pad_length with 0s
|
|
for (unsigned int i = 0; i < pad_length; i++) {
|
|
rs->received_polynomial.coeff[i + encoded_length] = 0;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < erasure_length; i++) {
|
|
// remap the coordinates of the erasures
|
|
rs->error_locations[i] = rs->block_length - (erasure_locations[i] + pad_length + 1);
|
|
}
|
|
|
|
reed_solomon_find_error_roots_from_locations(rs->field, rs->generator_root_gap, rs->error_locations,
|
|
rs->error_roots, erasure_length);
|
|
|
|
rs->erasure_locator =
|
|
reed_solomon_find_error_locator_from_roots(rs->field, erasure_length, rs->error_roots, rs->erasure_locator, rs->init_from_roots_scratch);
|
|
|
|
bool all_zero = reed_solomon_find_syndromes(rs->field, rs->received_polynomial, rs->generator_root_exp,
|
|
rs->syndromes, rs->min_distance);
|
|
|
|
if (all_zero) {
|
|
// syndromes were all zero, so there was no error in the message
|
|
// copy to msg and we are done
|
|
for (unsigned int i = 0; i < msg_length; i++) {
|
|
msg[i] = rs->received_polynomial.coeff[encoded_length - (i + 1)];
|
|
}
|
|
return msg_length;
|
|
}
|
|
|
|
reed_solomon_find_modified_syndromes(rs, rs->syndromes, rs->erasure_locator, rs->modified_syndromes);
|
|
|
|
field_element_t *syndrome_copy = malloc(rs->min_distance * sizeof(field_element_t));
|
|
memcpy(syndrome_copy, rs->syndromes, rs->min_distance * sizeof(field_element_t));
|
|
|
|
for (unsigned int i = erasure_length; i < rs->min_distance; i++) {
|
|
rs->syndromes[i - erasure_length] = rs->modified_syndromes[i];
|
|
}
|
|
|
|
unsigned int order = reed_solomon_find_error_locator(rs, erasure_length);
|
|
// XXX fix this vvvv
|
|
rs->error_locator.order = order;
|
|
|
|
for (unsigned int i = 0; i <= rs->error_locator.order; i++) {
|
|
// this is a little strange since the coeffs are logs, not elements
|
|
// also, we'll be storing log(0) = 0 for any 0 coeffs in the error locator
|
|
// that would seem bad but we'll just be using this in chien search, and we'll skip all 0 coeffs
|
|
// (you might point out that log(1) also = 0, which would seem to alias. however, that's ok,
|
|
// because log(1) = 255 as well, and in fact that's how it's represented in our log table)
|
|
rs->error_locator_log.coeff[i] = rs->field.log[rs->error_locator.coeff[i]];
|
|
}
|
|
rs->error_locator_log.order = rs->error_locator.order;
|
|
|
|
/*
|
|
for (unsigned int i = 0; i < erasure_length; i++) {
|
|
rs->error_roots[i] = field_div(rs->field, 1, rs->error_roots[i]);
|
|
}
|
|
*/
|
|
|
|
if (!reed_solomon_factorize_error_locator(rs->field, erasure_length, rs->error_locator_log, rs->error_roots, rs->element_exp)) {
|
|
// roots couldn't be found, so there were too many errors to deal with
|
|
// RS has failed for this message
|
|
free(syndrome_copy);
|
|
return -1;
|
|
}
|
|
|
|
polynomial_t temp_poly = polynomial_create(rs->error_locator.order + erasure_length);
|
|
polynomial_mul(rs->field, rs->erasure_locator, rs->error_locator, temp_poly);
|
|
polynomial_t placeholder_poly = rs->error_locator;
|
|
rs->error_locator = temp_poly;
|
|
|
|
reed_solomon_find_error_locations(rs->field, rs->generator_root_gap, rs->error_roots, rs->error_locations,
|
|
rs->error_locator.order, erasure_length);
|
|
|
|
memcpy(rs->syndromes, syndrome_copy, rs->min_distance * sizeof(field_element_t));
|
|
|
|
reed_solomon_find_error_values(rs);
|
|
|
|
for (unsigned int i = 0; i < rs->error_locator.order; i++) {
|
|
rs->received_polynomial.coeff[rs->error_locations[i]] =
|
|
field_sub(rs->field, rs->received_polynomial.coeff[rs->error_locations[i]], rs->error_vals[i]);
|
|
}
|
|
|
|
rs->error_locator = placeholder_poly;
|
|
|
|
for (unsigned int i = 0; i < msg_length; i++) {
|
|
msg[i] = rs->received_polynomial.coeff[encoded_length - (i + 1)];
|
|
}
|
|
|
|
polynomial_destroy(temp_poly);
|
|
free(syndrome_copy);
|
|
|
|
return msg_length;
|
|
}
|