Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False Positives #28

Open
meerd opened this issue Feb 18, 2019 · 1 comment
Open

False Positives #28

meerd opened this issue Feb 18, 2019 · 1 comment

Comments

@meerd
Copy link

meerd commented Feb 18, 2019

Hello @brian-armstrong and others,

I am still evaluating libcorrect for one of my projects. In the application, an eight-byte payload exists, and it consists of 4 bytes data + 4 bytes RS error correction code. Please see my test code below. There are three functions:

1st - A basic encoding/decoding code that works as expected.
2nd - This function works on five different payloads. Some bits of the payloads corrupted, but all of them are expected to recover. The library successfully decodes these payloads as expected.
3rd - This function encodes five different data (all is 4 bytes long) and obtains payloads. (4 bytes + 4 bytes = 8 bytes) Then, in the code, I intentionally distort ECC part of the payload. The expected behavior would be seeing all with decoding errors, but interestingly the library successfully decodes 3 of 5 payloads.

Is it a bug? Or am I doing something wrong?

Looking forward to seeing your feedback.

Thanks in advance.
meerd


#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <correct.h>

/* ################################ ========================================= */

#define DATA_LENGTH     4
#define ECC_LENGTH      4
#define PAYLOAD_LENGTH  (DATA_LENGTH + ECC_LENGTH)

#define SAMPLE_COUNT   5

#define dump_bytes(msg, buf, size) \
    do { \
        unsigned int ctr_dump_bytes = 0; \
        printf("| %s | = ", msg); \
        for (; ctr_dump_bytes < (size); ++ctr_dump_bytes) \
            printf("0x%02x ", ((uint8_t *)(buf))[ctr_dump_bytes]); \
        printf("\n"); \
    } while (0)
 

/* ################################ ========================================= */
/* A simple encode & decode test. */
/* ################################ ========================================= */
void rs_test1(correct_reed_solomon *ctx)
{
    const uint8_t data[DATA_LENGTH]                 = { 0xde, 0xad, 0xbe, 0xef };
    const uint8_t expected_payload[PAYLOAD_LENGTH]  = { 0xde, 0xad, 0xbe, 0xef, 0x83, 0x86, 0xc9, 0xee }; 
    uint8_t encoded[PAYLOAD_LENGTH]                 = { 0x00 };
    uint8_t decoded[PAYLOAD_LENGTH]                 = { 0x00 };
    ssize_t result; 

    fprintf(stdout, "Running %s...\n", __FUNCTION__); 
    
    dump_bytes("Encoded bytes:", encoded, PAYLOAD_LENGTH);
    /* Compare */
    result = correct_reed_solomon_encode(ctx, data, DATA_LENGTH, encoded);
    /* 255 is returned by the library */
    assert(255 == result);
    
    /* Compare the expected output with encoded buffer.  */
    result = memcmp(expected_payload, encoded, PAYLOAD_LENGTH);
    dump_bytes("Encoded bytes:", encoded, PAYLOAD_LENGTH);
    assert(0 == result);

    /* Decode the encoded buffer. */
    result = correct_reed_solomon_decode(ctx, encoded, PAYLOAD_LENGTH, decoded);
    /* See if the remaining bytes are still zero. */
    dump_bytes("Decoded bytes:", decoded, PAYLOAD_LENGTH);
    assert(DATA_LENGTH == result);

    /* Compare the decoded buffer with the original data. */
    result = memcmp(data, decoded, DATA_LENGTH);
    assert(result == 0);

    fprintf(stdout, "###################################\n");
    fprintf(stdout, "%s passed!\n", __FUNCTION__); 
    fprintf(stdout, "###################################\n");
}

/* ################################ ========================================= */
/* Some of the payloads includes errors, but all should be able to be recovered. */
/* ################################ ========================================= */

void rs_test2(correct_reed_solomon *ctx)
{
    uint8_t recoverable_payload[SAMPLE_COUNT][PAYLOAD_LENGTH] = { 
                                                                   { 0x11, 0x11, 0x11, 0x11, 0x6a, 0xec, 0x1b, 0x9d },
                                                                   { 0x56, 0xd4, 0xaa, 0xe3, 0x19, 0x90, 0xac, 0xee },
                                                                   { 0xff, 0xff, 0xff, 0xff, 0x1c, 0x8d, 0x99, 0x60 },
                                                                   { 0xaa, 0x00, 0xaa, 0xaa, 0xa3, 0xf6, 0x00, 0xbb },
                                                                   { 0x24, 0x00, 0x38, 0x90, 0x8b, 0x71, 0xff, 0x76 }
                                                                };
    int failure = 0;
    int i;

    fprintf(stdout, "Running %s...\n", __FUNCTION__); 
    
    for (i = 0; i < SAMPLE_COUNT; ++i) {
        uint8_t buf[DATA_LENGTH] = { 0x00 };
        ssize_t result = correct_reed_solomon_decode(ctx, recoverable_payload[i], PAYLOAD_LENGTH, buf);

        failure += (DATA_LENGTH != result);
        fprintf(stdout, "Decoding result for distorted input (idx: %d): %s\n", i, ((DATA_LENGTH == result) ? "SUCCESS" : "FAILURE")) ;
    }    

    fprintf(stdout, "###################################\n");
    /* If no failures has been detected so far, then the test passed! */
    if (0 == failure)
        fprintf(stdout, "%s passed!\n", __FUNCTION__);
    else
        fprintf(stdout, "%s FAILED!\n", __FUNCTION__);
    fprintf(stdout, "###################################\n");
}

/* ################################ ========================================= */
/* The last four bytes of all payloads distorted intentionally. All of the 
 * decoding attempts are expected to fail. */
/* ################################ ========================================= */
void rs_test3(correct_reed_solomon *ctx)
{

    uint8_t sample_data[SAMPLE_COUNT][DATA_LENGTH] = { 
                                                        { 0xaa, 0xaa, 0xaa, 0xaa }, 
                                                        { 0xff, 0xff, 0xff, 0xff },
                                                        { 0x4f, 0xf3, 0x89, 0x18 },
                                                        { 0x12, 0x34, 0x56, 0x78 },
                                                        { 0x24, 0xff, 0x38, 0x90 }
                                                     };

    uint8_t expected_payload[SAMPLE_COUNT][PAYLOAD_LENGTH] = {
                                                                { 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0xf6, 0xee, 0xbb },
                                                                { 0xff, 0xff, 0xff, 0xff, 0x7c, 0x8d, 0x99, 0x68 },
                                                                { 0x4f, 0xf3, 0x89, 0x18, 0x31, 0x23, 0x07, 0x38 },
                                                                { 0x12, 0x34, 0x56, 0x78, 0x54, 0x56, 0x20, 0x2a },
                                                                { 0x24, 0xff, 0x38, 0x90, 0x8b, 0x71, 0xff, 0x76 }
                                                            };
 

    uint8_t distorted_ecc[SAMPLE_COUNT][ECC_LENGTH] = {
                                                        { 0x00, 0x00, 0x00, 0x00 },
                                                        { 0xff, 0xff, 0xff, 0xff },
                                                        { 0xb7, 0x1f, 0xff, 0x75 },
                                                        { 0xff, 0xff, 0xff, 0xff },
                                                        { 0x8b, 0x71, 0xff, 0x76 }
                                                     };

    int failure = 0;

    uint8_t buf[PAYLOAD_LENGTH];
    int i;


    fprintf(stdout, "Running %s...\n", __FUNCTION__); 
    
    for (i = 0; i < SAMPLE_COUNT; ++i) {
        /* Clean the contents */
        memset(buf, 0x00, sizeof(buf));
        /* Encode sample_data[i] */

        ssize_t result = correct_reed_solomon_encode(ctx, sample_data[i], DATA_LENGTH, buf);
    
        assert(255 == result);

        fprintf(stdout, "Checking encoded data integrity (%d)...\n", i);
        dump_bytes("Encoded value:", buf, PAYLOAD_LENGTH);
        
        if (memcmp(expected_payload[i], buf, PAYLOAD_LENGTH)) {
            dump_bytes("Expected payload:", expected_payload[i], PAYLOAD_LENGTH);
            fprintf(stdout, "\n Encoding failed!\n");
            abort();
        } else {
            fprintf(stdout, " OK!\n");
        }
    }

    for (i = 0; i < SAMPLE_COUNT; ++i) {
       uint8_t output[PAYLOAD_LENGTH] = { 0x00 };
       ssize_t result = 0;

       /* Copy data */
       memcpy(buf, sample_data[i], DATA_LENGTH);
       /* Intentionally distort ecc values completely */
       memcpy(buf + DATA_LENGTH, distorted_ecc[i], ECC_LENGTH);
       /* Print modified payload */ 
       dump_bytes("Data with distorted ECC:", buf, PAYLOAD_LENGTH);
       /* Decode modified payload. The function is EXPECTED to fail! */
       result = correct_reed_solomon_decode(ctx, buf, PAYLOAD_LENGTH, output);

       fprintf(stdout, "Decoding result for distorted input (idx: %d): %s\n", i, ((DATA_LENGTH == result) ? "DECODING SUCCESS (False Positive!)" : "DECODING FAILURE")) ;
       failure += (DATA_LENGTH == result);
    }

    fprintf(stdout, "###################################\n");
    /* If no failures has been detected so far, then the test passed! */
    if (0 == failure)
        fprintf(stdout, "%s passed!\n", __FUNCTION__); 
    else
        fprintf(stdout, "%s FAILED!\n", __FUNCTION__); 
    fprintf(stdout, "###################################\n");
}

/* ################################ ========================================= */

int main(void)
{
    const uint16_t primitive_polynomial   = correct_rs_primitive_polynomial_8_4_3_2_0;
    const uint8_t  first_consecutive_root = 0;
    const uint8_t  generator_root_gap     = 1;
    const uint8_t  num_roots              = 4;

    /* Create reed solomon codec instance */
    correct_reed_solomon *ctx = correct_reed_solomon_create(primitive_polynomial,
                                                            first_consecutive_root,
                                                            generator_root_gap,
                                                            num_roots);
    assert(0 != ctx);

    rs_test1(ctx);
    rs_test2(ctx);
    rs_test3(ctx);

    /* Destroy rs codec instance. */
    correct_reed_solomon_destroy(ctx);
    
    fprintf(stdout, "All tests completed successfully!\n");

    return 0;
}
@brian-armstrong
Copy link
Member

Hi @meerd

In general, Reed-Solomon doesn't make any guarantees about what happens once you exceed the error-correction capabilities. There simply isn't enough information present to know whether this has happened. If you want to check the integrity of your data, add a checksum/CRC. You can verify your checksum after error correction, so that the checksum will only fail when the error rate exceeds the correction capacity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants