Crypt-PQClean-Sign
view release on metacpan or search on metacpan
pqclean/crypto_kem/hqc-192/clean/reed_solomon.c view on Meta::CPAN
tmp2 = 1;
inverse = PQCLEAN_HQC192_CLEAN_gf_inverse(beta_j[i]);
inverse_power_j = 1;
for (size_t j = 1; j <= PARAM_DELTA; ++j) {
inverse_power_j = PQCLEAN_HQC192_CLEAN_gf_mul(inverse_power_j, inverse);
tmp1 ^= PQCLEAN_HQC192_CLEAN_gf_mul(inverse_power_j, z[j]);
}
for (size_t k = 1; k < PARAM_DELTA; ++k) {
tmp2 = PQCLEAN_HQC192_CLEAN_gf_mul(tmp2, (1 ^ PQCLEAN_HQC192_CLEAN_gf_mul(inverse, beta_j[(i + k) % PARAM_DELTA])));
}
mask1 = (uint16_t) (((int16_t) i - delta_real_value) >> 15); // i < delta_real_value
e_j[i] = mask1 & PQCLEAN_HQC192_CLEAN_gf_mul(tmp1, PQCLEAN_HQC192_CLEAN_gf_inverse(tmp2));
}
// Place the delta e_{j_i} values at the right coordinates of the output vector
delta_counter = 0;
for (size_t i = 0; i < PARAM_N1; ++i) {
found = 0;
mask1 = (uint16_t) (-((int32_t)error[i]) >> 31); // error[i] != 0
for (size_t j = 0; j < PARAM_DELTA; j++) {
mask2 = ~((uint16_t) (-((int32_t) j ^ delta_counter) >> 31)); // j == delta_counter
error_values[i] += mask1 & mask2 & e_j[j];
found += mask1 & mask2 & 1;
}
delta_counter += found;
}
}
/**
* @brief Correct the errors
*
* @param[out] cdw Array of PARAM_N1 elements receiving the corrected vector
* @param[in] error Array of the error vector
* @param[in] error_values Array of PARAM_DELTA elements storing the error values
*/
static void correct_errors(uint8_t *cdw, const uint16_t *error_values) {
for (size_t i = 0; i < PARAM_N1; ++i) {
cdw[i] ^= error_values[i];
}
}
/**
* @brief Decodes the received word
*
* This function relies on six steps:
* <ol>
* <li> The first step, is the computation of the 2*PARAM_DELTA syndromes.
* <li> The second step is the computation of the error-locator polynomial sigma.
* <li> The third step, done by additive FFT, is finding the error-locator numbers by calculating the roots of the polynomial sigma and takings their inverses.
* <li> The fourth step, is the polynomial z(x).
* <li> The fifth step, is the computation of the error values.
* <li> The sixth step is the correction of the errors in the received polynomial.
* </ol>
* For a more complete picture on Reed-Solomon decoding, see Shu. Lin and Daniel J. Costello in Error Control Coding: Fundamentals and Applications @cite lin1983error
*
* @param[out] msg Array of size VEC_K_SIZE_64 receiving the decoded message
* @param[in] cdw Array of size VEC_N1_SIZE_64 storing the received word
*/
void PQCLEAN_HQC192_CLEAN_reed_solomon_decode(uint8_t *msg, uint8_t *cdw) {
uint16_t syndromes[2 * PARAM_DELTA] = {0};
uint16_t sigma[1 << PARAM_FFT] = {0};
uint8_t error[1 << PARAM_M] = {0};
uint16_t z[PARAM_N1] = {0};
uint16_t error_values[PARAM_N1] = {0};
uint16_t deg;
// Calculate the 2*PARAM_DELTA syndromes
compute_syndromes(syndromes, cdw);
// Compute the error locator polynomial sigma
// Sigma's degree is at most PARAM_DELTA but the FFT requires the extra room
deg = compute_elp(sigma, syndromes);
// Compute the error polynomial error
compute_roots(error, sigma);
// Compute the polynomial z(x)
compute_z_poly(z, sigma, deg, syndromes);
// Compute the error values
compute_error_values(error_values, z, error);
// Correct the errors
correct_errors(cdw, error_values);
// Retrieve the message from the decoded codeword
memcpy(msg, cdw + (PARAM_G - 1), PARAM_K);
}
( run in 3.460 seconds using v1.01-cache-2.11-cpan-bbb979687b5 )