LCOV - code coverage report
Current view: top level - src - decode.c (source / functions) Coverage Total Hit
Test: poporon Coverage Report Lines: 92.2 % 179 165
Test Date: 2025-04-08 01:35:23 Functions: 100.0 % 6 6
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * libpoporon - decode.c
       3              :  * 
       4              :  * Copyright (c) 2025 Go Kudo
       5              :  *
       6              :  * This library is licensed under the BSD 3-Clause License.
       7              :  * For license details, please refer to the LICENSE file.
       8              :  *
       9              :  * SPDX-FileCopyrightText: Go Kudo <zeriyoshi@gmail.com>
      10              :  * SPDX-License-Identifier: BSD-3-Clause
      11              :  */
      12              : 
      13              : #include "poporon_internal.h"
      14              : 
      15           20 : static inline bool error_correction_u8(
      16              :     poporon_t *pprn, uint8_t *data, size_t size, uint8_t *parity, uint16_t *syndrome_ptr,
      17              :     uint32_t erasure_count, uint32_t *erasure_positions, uint16_t *corrections,
      18              :     int16_t padding_length,
      19              :     size_t *errors_corrected
      20              : ) {
      21              :     uint32_t iteration_count, polynomial_degree;
      22              :     uint16_t error_locator_degree, error_evaluator_degree, polynomial_evaluation;
      23              :     uint16_t temp_value, numerator_value, second_numerator, denominator_value, discrepancy;
      24              :     uint16_t error_count;
      25              :     int16_t i, j, k;
      26              :     uint8_t poly_term;
      27              :     bool success;
      28              :     
      29           20 :     success = true;
      30              : 
      31           20 :     pmemset(&pprn->buffer->error_locator[1], 0, pprn->rs->num_roots * sizeof(pprn->buffer->error_locator[0]));
      32           20 :     pprn->buffer->error_locator[0] = 1;
      33              : 
      34           20 :     if (erasure_count > 0) {
      35            1 :         pprn->buffer->error_locator[1] = pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, pprn->rs->primitive_element * (pprn->rs->gf->field_size - 1 - (erasure_positions[0] + padding_length)))];
      36           16 :         for (i = 1; i < erasure_count; i++) {
      37           15 :             poly_term = gf_mod(pprn->rs->gf, pprn->rs->primitive_element * (pprn->rs->gf->field_size - 1 - (erasure_positions[i] + padding_length)));
      38          150 :             for (j = i + 1; j > 0; j--) {
      39          135 :                 temp_value = pprn->rs->gf->exp2log[pprn->buffer->error_locator[j - 1]];
      40          135 :                 if (temp_value != pprn->rs->gf->field_size) {
      41          135 :                     pprn->buffer->error_locator[j] ^= pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, poly_term + temp_value)];
      42              :                 }
      43              :             }
      44              :         }
      45              :     }
      46              : 
      47          680 :     for (i = 0; i < pprn->rs->num_roots + 1; i++) {
      48          660 :         pprn->buffer->coefficients[i] = pprn->rs->gf->exp2log[pprn->buffer->error_locator[i]];
      49              :     }
      50              : 
      51              :     /* Berlekamp-Massey */
      52           20 :     iteration_count = erasure_count;
      53           20 :     polynomial_degree = erasure_count;
      54          644 :     while (++iteration_count <= pprn->rs->num_roots) {
      55          624 :         discrepancy = 0;
      56        11048 :         for (i = 0; i < iteration_count; i++) {
      57        10424 :             if ((pprn->buffer->error_locator[i] != 0) && (syndrome_ptr[iteration_count - i - 1] != pprn->rs->gf->field_size)) {
      58         4031 :                 discrepancy ^= pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, pprn->rs->gf->exp2log[pprn->buffer->error_locator[i]] + syndrome_ptr[iteration_count - i - 1])];
      59              :             }
      60              :         }
      61          624 :         discrepancy = pprn->rs->gf->exp2log[discrepancy];
      62              :         
      63          624 :         if (discrepancy == pprn->rs->gf->field_size) {
      64          451 :             pmemmove(&pprn->buffer->coefficients[1], pprn->buffer->coefficients, pprn->rs->num_roots * sizeof(pprn->buffer->coefficients[0]));
      65          451 :             pprn->buffer->coefficients[0] = pprn->rs->gf->field_size;
      66              :         } else {
      67          173 :             pprn->buffer->polynomial[0] = pprn->buffer->error_locator[0];
      68              : 
      69         5709 :             for (i = 0; i < pprn->rs->num_roots; i++) {
      70         5536 :                 if (pprn->buffer->coefficients[i] != pprn->rs->gf->field_size) {
      71         1672 :                     pprn->buffer->polynomial[i + 1] = pprn->buffer->error_locator[i + 1] ^ 
      72          836 :                         pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, discrepancy + pprn->buffer->coefficients[i])];
      73              :                 } else {
      74         4700 :                     pprn->buffer->polynomial[i + 1] = pprn->buffer->error_locator[i + 1];
      75              :                 }
      76              :             }
      77              : 
      78          173 :             if (2 * polynomial_degree <= iteration_count + erasure_count - 1) {
      79          154 :                 polynomial_degree = iteration_count + erasure_count - polynomial_degree;
      80         5236 :                 for (i = 0; i <= pprn->rs->num_roots; i++) {
      81        10164 :                     pprn->buffer->coefficients[i] = (pprn->buffer->error_locator[i] == 0) ? 
      82         4131 :                         pprn->rs->gf->field_size : 
      83          951 :                         gf_mod(pprn->rs->gf, pprn->rs->gf->exp2log[pprn->buffer->error_locator[i]] - discrepancy + pprn->rs->gf->field_size);
      84              :                 }
      85              :             } else {
      86           19 :                 pmemmove(&pprn->buffer->coefficients[1], pprn->buffer->coefficients, pprn->rs->num_roots * sizeof(pprn->buffer->coefficients[0]));
      87           19 :                 pprn->buffer->coefficients[0] = pprn->rs->gf->field_size;
      88              :             }
      89              : 
      90          173 :             pmemcpy(pprn->buffer->error_locator, pprn->buffer->polynomial, (pprn->rs->num_roots + 1) * sizeof(pprn->buffer->polynomial[0]));
      91              :         }
      92              :     }
      93              : 
      94           20 :     error_locator_degree = 0;
      95          680 :     for (i = 0; i < pprn->rs->num_roots + 1; i++) {
      96          660 :         pprn->buffer->error_locator[i] = pprn->rs->gf->exp2log[pprn->buffer->error_locator[i]];
      97              : 
      98          660 :         if (pprn->buffer->error_locator[i] != pprn->rs->gf->field_size) {
      99          189 :             error_locator_degree = i;
     100              :         }
     101              :     }
     102              : 
     103           20 :     if (error_locator_degree == 0) {
     104            0 :         return false;
     105              :     }
     106              : 
     107              :     /* Chien search */
     108           20 :     pmemcpy(&pprn->buffer->register_coefficients[1], &pprn->buffer->error_locator[1], pprn->rs->num_roots * sizeof(pprn->buffer->register_coefficients[0]));
     109           20 :     error_count = 0;
     110         4045 :     for (i = 1, k = pprn->buffer->primitive_inverse - 1; i <= pprn->rs->gf->field_size; i++, k = gf_mod(pprn->rs->gf, k + pprn->buffer->primitive_inverse)) {
     111         4045 :         polynomial_evaluation = 1;
     112              : 
     113        38471 :         for (j = error_locator_degree; j > 0; j--) {
     114        34426 :             if (pprn->buffer->register_coefficients[j] != pprn->rs->gf->field_size) {
     115        34364 :                 pprn->buffer->register_coefficients[j] = gf_mod(pprn->rs->gf, pprn->buffer->register_coefficients[j] + j);
     116        34364 :                 polynomial_evaluation ^= pprn->rs->gf->log2exp[pprn->buffer->register_coefficients[j]];
     117              :             }
     118              :         }
     119              : 
     120         4045 :         if (polynomial_evaluation != 0)
     121         3890 :             continue;
     122              : 
     123          155 :         if (k < padding_length) {
     124            1 :             return false;
     125              :         }
     126              : 
     127          154 :         pprn->buffer->error_roots[error_count] = i;
     128          154 :         pprn->buffer->error_locations[error_count] = k;
     129          154 :         if (++error_count == error_locator_degree) {
     130           19 :             break;
     131              :         }
     132              :     }
     133              :     
     134           19 :     if (error_locator_degree != error_count) {
     135            0 :         return false;
     136              :     }
     137              :     
     138              :     /* Forney */
     139           19 :     error_evaluator_degree = error_locator_degree - 1;
     140          173 :     for (i = 0; i <= error_evaluator_degree; i++) {
     141          154 :         temp_value = 0;
     142              : 
     143         1108 :         for (j = i; j >= 0; j--) {
     144          954 :             if ((syndrome_ptr[i - j] != pprn->rs->gf->field_size) && (pprn->buffer->error_locator[j] != pprn->rs->gf->field_size)) {
     145          954 :                 temp_value ^= pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, syndrome_ptr[i - j] + pprn->buffer->error_locator[j])];
     146              :             }
     147              :         }
     148              : 
     149          154 :         pprn->buffer->error_evaluator[i] = pprn->rs->gf->exp2log[temp_value];
     150              :     }
     151           19 :     *errors_corrected = 0;
     152          173 :     for (j = error_count - 1; j >= 0; j--) {
     153          154 :         numerator_value = 0;
     154              : 
     155         1908 :         for (i = error_evaluator_degree; i >= 0; i--) {
     156         1754 :             if (pprn->buffer->error_evaluator[i] != pprn->rs->gf->field_size) {
     157          910 :                 numerator_value ^= pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, pprn->buffer->error_evaluator[i] + i * pprn->buffer->error_roots[j])];
     158              :             }
     159              :         }
     160              : 
     161          154 :         if (numerator_value == 0) {
     162            0 :             pprn->buffer->coefficients[j] = 0;
     163            0 :             continue;
     164              :         }
     165              : 
     166          154 :         second_numerator = pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, pprn->buffer->error_roots[j] * (pprn->rs->first_consective_root - 1) + pprn->rs->gf->field_size)];
     167          154 :         denominator_value = 0;
     168              : 
     169         1152 :         for (i = (error_locator_degree < (pprn->rs->num_roots - 1) ? error_locator_degree : (pprn->rs->num_roots - 1)) & ~1; i >= 0; i -= 2) {
     170          998 :             if (pprn->buffer->error_locator[i + 1] != pprn->rs->gf->field_size) {
     171          910 :                 denominator_value ^= pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, pprn->buffer->error_locator[i + 1] + i * pprn->buffer->error_roots[j])];
     172              :             }
     173              :         }
     174              : 
     175          154 :         pprn->buffer->coefficients[j] = pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, pprn->rs->gf->exp2log[numerator_value] + pprn->rs->gf->exp2log[second_numerator] + pprn->rs->gf->field_size - pprn->rs->gf->exp2log[denominator_value])];
     176          154 :         (*errors_corrected)++;
     177              :     }
     178              : 
     179              :     /* Validate */
     180          627 :     for (i = 0; i < pprn->rs->num_roots; i++) {
     181          608 :         temp_value = 0;
     182              : 
     183         5536 :         for (j = 0; j < error_count; j++) {
     184         4928 :             if (pprn->buffer->coefficients[j] == 0) {
     185            0 :                 continue;
     186              :             }
     187              : 
     188         4928 :             k = (pprn->rs->first_consective_root + i) * pprn->rs->primitive_element * (pprn->rs->gf->field_size - pprn->buffer->error_locations[j] - 1);
     189         4928 :             temp_value ^= pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, pprn->rs->gf->exp2log[pprn->buffer->coefficients[j]] + k)];
     190              :         }
     191              : 
     192          608 :         if (temp_value != pprn->rs->gf->log2exp[syndrome_ptr[i]]) {
     193            0 :             return false;
     194              :         }
     195              :     }
     196              : 
     197              :     /* Correction */
     198           19 :     if (corrections && erasure_positions) {
     199           17 :         for (i = 0; i < error_count; i++) {
     200           16 :             data[erasure_positions[i]] ^= pprn->buffer->coefficients[i];
     201              :         }
     202           18 :     } else if (data && parity) {
     203          156 :         for (i = 0; i < error_count; i++) {
     204          138 :             if (pprn->buffer->error_locations[i] < (pprn->rs->gf->field_size - pprn->rs->num_roots)) {
     205          138 :                 data[pprn->buffer->error_locations[i] - padding_length] ^= pprn->buffer->coefficients[i];
     206              :             }
     207              :             else {
     208            0 :                 parity[pprn->buffer->error_locations[i] - padding_length - size] ^= pprn->buffer->coefficients[i];
     209              :             }
     210              :         }
     211              :     }
     212              : 
     213           19 :     return true;
     214              : }
     215              : 
     216           21 : static inline bool calculate_syndrome_u8(poporon_t *pprn, uint8_t *data, size_t size, uint8_t *parity, uint16_t *syndrome)
     217              : {
     218              :     int16_t i, j;
     219              :     uint16_t syndrome_error_flag;
     220              :     
     221           21 :     syndrome_error_flag = 0;
     222              : 
     223              :     /* Calculate syndrome from data */
     224          693 :     for (i = 0; i < pprn->rs->num_roots; i++) {
     225          672 :         syndrome[i] = data[0] & ((uint16_t)pprn->rs->gf->field_size);
     226              :     }
     227              : 
     228         1344 :     for (j = 1; j < size; j++) {
     229        43659 :         for (i = 0; i < pprn->rs->num_roots; i++) {
     230        42336 :             if (syndrome[i] == 0) {
     231          159 :                 syndrome[i] = data[j] & ((uint16_t)pprn->rs->gf->field_size);
     232              :             } else {
     233        84354 :                 syndrome[i] = (data[j] & ((uint16_t)pprn->rs->gf->field_size)) ^
     234        42177 :                     pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, pprn->rs->gf->exp2log[syndrome[i]] + (pprn->rs->first_consective_root + i) * pprn->rs->primitive_element)];
     235              :             }
     236              :         }
     237              :     }
     238              : 
     239              :     /* Calculate syndrome from parity */
     240          693 :     for (j = 0; j < pprn->rs->num_roots; j++) {
     241        22176 :         for (i = 0; i < pprn->rs->num_roots; i++) {
     242        21504 :             if (syndrome[i] == 0) {
     243           90 :                 syndrome[i] = parity[j] & ((uint16_t)pprn->rs->gf->field_size);
     244              :             } else {
     245        42828 :                 syndrome[i] = (parity[j] & ((uint16_t)pprn->rs->gf->field_size)) ^
     246        21414 :                     pprn->rs->gf->log2exp[gf_mod(pprn->rs->gf, pprn->rs->gf->exp2log[syndrome[i]] + (pprn->rs->first_consective_root + i) * pprn->rs->primitive_element)];
     247              :             }
     248              :         }
     249              :     }
     250              :     
     251          693 :     for (i = 0; i < pprn->rs->num_roots; i++) {
     252          672 :         syndrome_error_flag |= syndrome[i];
     253          672 :         syndrome[i] = pprn->rs->gf->exp2log[syndrome[i]];
     254              :     }
     255              : 
     256           21 :     return syndrome_error_flag != 0;
     257              : }
     258              : 
     259           22 : static inline int16_t calculate_padding_length(poporon_t *pprn, size_t size)
     260              : {
     261              :     int16_t padding_length;
     262              :     
     263           22 :     padding_length = pprn->rs->gf->field_size - pprn->rs->num_roots - size;
     264              :     
     265           22 :     if (padding_length < 0 || padding_length >= pprn->rs->gf->field_size - pprn->rs->num_roots) {
     266            0 :         return -1;
     267              :     }
     268              :     
     269           22 :     return padding_length;
     270              : }
     271              : 
     272            6 : extern bool poporon_decode_u8_with_syndrome(poporon_t *pprn, uint8_t *data, uint8_t *parity, size_t size, uint16_t *syndrome, size_t *corrected_num)
     273              : {
     274              :     size_t errors_corrected;
     275              :     int16_t padding_length;
     276              :     uint16_t i;
     277              :     bool success, has_errors;
     278              : 
     279            6 :     errors_corrected = 0;
     280            6 :     success = false;
     281            6 :     has_errors = false;
     282              : 
     283            6 :     if (!pprn || !data || !parity || !size || !syndrome) {
     284            5 :         goto finish;
     285              :     }
     286              : 
     287            1 :     padding_length = calculate_padding_length(pprn, size);
     288            1 :     if (padding_length < 0) {
     289            0 :         goto finish;
     290              :     }
     291              : 
     292           33 :     for (i = 0; i < pprn->rs->num_roots; i++) {
     293           32 :         if (syndrome[i] != pprn->rs->gf->field_size) {
     294            0 :             has_errors = true;
     295            0 :             break;
     296              :         }
     297              :     }
     298              : 
     299            1 :     if (has_errors && !error_correction_u8(pprn, data, size, parity, syndrome, 0, NULL, NULL, padding_length, &errors_corrected)) {
     300            0 :         goto finish;
     301              :     }
     302              : 
     303            1 :     success = true;
     304              : 
     305            6 : finish:
     306            6 :     if (corrected_num) {
     307            6 :         *corrected_num = errors_corrected;
     308              :     }
     309              : 
     310            6 :     return success;
     311              : }
     312              : 
     313            6 : extern bool poporon_decode_u8_with_erasure(poporon_t *pprn, uint8_t *data, size_t size, uint8_t *parity, poporon_erasure_t *eras, size_t *corrected_num)
     314              : {
     315              :     size_t errors_corrected;
     316              :     int16_t padding_length;
     317              :     bool success;
     318              : 
     319            6 :     errors_corrected = 0;
     320            6 :     success = false;
     321              : 
     322            6 :     if (!pprn || !data || !parity || !eras || !size) {
     323            5 :         goto finish;
     324              :     }
     325              : 
     326            1 :     padding_length = calculate_padding_length(pprn, size);
     327            1 :     if (padding_length < 0) {
     328            0 :         goto finish;
     329              :     }
     330              : 
     331            2 :     success = !calculate_syndrome_u8(pprn, data, size, parity, pprn->buffer->syndrome) 
     332            1 :             || error_correction_u8(pprn, data, size, parity, pprn->buffer->syndrome, eras->erasure_count, eras->erasure_positions, eras->corrections, padding_length, &errors_corrected);
     333              : 
     334            6 : finish:
     335            6 :     if (corrected_num) {
     336            6 :         *corrected_num = errors_corrected;
     337              :     }
     338              : 
     339            6 :     return success;
     340              : }
     341              : 
     342           24 : extern bool poporon_decode_u8(poporon_t *pprn, uint8_t *data, size_t size, uint8_t *parity, size_t *corrected_num)
     343              : {
     344              :     size_t errors_corrected;
     345              :     int16_t padding_length;
     346              :     bool success;
     347              :     
     348           24 :     errors_corrected = 0;
     349           24 :     success = false;
     350              : 
     351           24 :     if (!pprn || !data || !parity || !size) {
     352            4 :         goto finish;
     353              :     }
     354              : 
     355           20 :     padding_length = calculate_padding_length(pprn, size);
     356           20 :     if (padding_length < 0) {
     357            0 :         goto finish;
     358              :     }
     359              : 
     360           40 :     success = !calculate_syndrome_u8(pprn, data, size, parity, pprn->buffer->syndrome)
     361           20 :              || error_correction_u8(pprn, data, size, parity, pprn->buffer->syndrome, 0, NULL, NULL, padding_length, &errors_corrected);
     362              : 
     363           24 : finish:
     364           24 :     if (corrected_num) {
     365           23 :         *corrected_num = errors_corrected;
     366              :     }
     367              : 
     368           24 :     return success;
     369              : }
        

Generated by: LCOV version 2.0-1