CRC:将前一个余数放在哪里

CRC: where to put previous remainder

现在我正在编写带有多项式除法且没有位移的 CRC16 实现(出于教育目的)。

我的问题是:当我有前一个字节的 CRC 并读取新字节时,我需要放置前一个余数以计算新的 CRC? (在新字节之前、新字节之后或与新字节异或等...)

我的代码适用于文本文件中的一个符号,但它不适用于多个符号。在我看来,我把第一个余数放错了地方:)

完整代码将放在下面。

#include <stdio.h>
#include <stdint.h>

void printBits(uint32_t inbyte, int width) 
{
    char modres = inbyte % 2;
    inbyte = inbyte >> 1;
    if (width > 0) {
        printBits(inbyte, --width);
    }

    printf("%d", modres);
}

struct polynom 
{
    uint8_t x16;uint8_t x15;uint8_t x14;uint8_t x13;uint8_t x12;
    uint8_t x11;uint8_t x10;uint8_t x9;uint8_t x8;uint8_t x7;
    uint8_t x6;uint8_t x5;uint8_t x4;uint8_t x3;uint8_t x2;
    uint8_t x1;uint8_t x0;
};

struct polycrc 
{
    uint8_t x15; uint8_t x14; uint8_t x13; uint8_t x12;
    uint8_t x11; uint8_t x10; uint8_t x9; uint8_t x8; uint8_t x7;
    uint8_t x6; uint8_t x5; uint8_t x4; uint8_t x3; uint8_t x2;
    uint8_t x1; uint8_t x0;
};

struct byte 
{
    uint8_t x7; uint8_t x6; uint8_t x5; uint8_t x4;
    uint8_t x3; uint8_t x2; uint8_t x1; uint8_t x0;
};

void printPolynom(struct polynom inp) 
{
    printf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
        inp.x16, inp.x15, inp.x14, inp.x13, inp.x12, inp.x11, inp.x10,
        inp.x9, inp.x8, inp.x7, inp.x6, inp.x5, inp.x4, inp.x3, inp.x2,
        inp.x1, inp.x0);
}

void printCRC(struct polycrc inp)
{
    printf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
        inp.x15, inp.x14, inp.x13, inp.x12, inp.x11, inp.x10,
        inp.x9, inp.x8, inp.x7, inp.x6, inp.x5, inp.x4, inp.x3, inp.x2,
        inp.x1, inp.x0);
}

struct polycrc getCRC(uint8_t inByte, struct polycrc inCRC, 
                    struct polynom inp) 
{
    struct delim
    {
        uint8_t xb7, xb6, xb5, xb4, xb3, xb2, xb1, xb0,
            xa15, xa14, xa13, xa12, xa11, xa10, xa9, xa8, xa7,
            xa6, xa5, xa4, xa3, xa2, xa1, xa0;
    };

    struct Bytes
    {
        uint8_t b7; uint8_t b6; uint8_t b5; 
        uint8_t b4; uint8_t b3; uint8_t b2;
        uint8_t b1; uint8_t b0;
    };

    printBits(inByte, 7);
    printf("|");
    printCRC(inCRC);
    printf("\n");

    struct Bytes oneByte;
    oneByte.b0 = inByte % 2; inByte = inByte / 2;
    oneByte.b1 = inByte % 2; inByte = inByte / 2;
    oneByte.b2 = inByte % 2; inByte = inByte / 2;
    oneByte.b3 = inByte % 2; inByte = inByte / 2;
    oneByte.b4 = inByte % 2; inByte = inByte / 2;
    oneByte.b5 = inByte % 2; inByte = inByte / 2;
    oneByte.b6 = inByte % 2; inByte = inByte / 2;
    oneByte.b7 = inByte % 2; inByte = inByte / 2;

    if (oneByte.b7 == 1){
        inCRC.x7 ^= inp.x0; inCRC.x8 ^= inp.x1; inCRC.x9 ^= inp.x2;
        inCRC.x10 ^= inp.x3; inCRC.x11 ^= inp.x4; inCRC.x12 ^= inp.x5;
        inCRC.x13 ^= inp.x6; inCRC.x14 ^= inp.x7; inCRC.x15 ^= inp.x8;
        oneByte.b0 ^= inp.x9; oneByte.b1 ^= inp.x10; oneByte.b2 ^= inp.x11;
        oneByte.b3 ^= inp.x12; oneByte.b4 ^= inp.x13; oneByte.b5 ^= inp.x14;
        oneByte.b6 ^= inp.x15; oneByte.b7 ^= inp.x16;
        inByte = oneByte.b6 * 2 * 2 * 2 * 2 * 2 * 2;
        inByte += oneByte.b5 * 2 * 2 * 2 * 2 * 2;
        inByte += oneByte.b4 * 2 * 2 * 2 * 2;
        inByte += oneByte.b3 * 2 * 2 * 2;
        inByte += oneByte.b2 * 2 * 2;
        inByte += oneByte.b1 * 2;
        inByte += oneByte.b0;

        return getCRC(inByte, inCRC, inp);
    }
    else if (oneByte.b6 == 1){
        inCRC.x6 ^= inp.x0; inCRC.x7 ^= inp.x1; inCRC.x8 ^= inp.x2;
        inCRC.x9 ^= inp.x3; inCRC.x10 ^= inp.x4; inCRC.x11 ^= inp.x5;
        inCRC.x12 ^= inp.x6; inCRC.x13 ^= inp.x7; inCRC.x14 ^= inp.x8;
        inCRC.x15 ^= inp.x9; oneByte.b0 ^= inp.x10; oneByte.b1 ^= inp.x11;
        oneByte.b2 ^= inp.x12; oneByte.b3 ^= inp.x13; oneByte.b4 ^= inp.x14;
        oneByte.b5 ^= inp.x15; oneByte.b6 ^= inp.x16;
        inByte = oneByte.b5 * 2 * 2 * 2 * 2 * 2;
        inByte += oneByte.b4 * 2 * 2 * 2 * 2;
        inByte += oneByte.b3 * 2 * 2 * 2;
        inByte += oneByte.b2 * 2 * 2;
        inByte += oneByte.b1 * 2;
        inByte += oneByte.b0;

        return getCRC(inByte, inCRC, inp);
    }
    else if (oneByte.b5 == 1){
        inCRC.x5 ^= inp.x0; inCRC.x6 ^= inp.x1; inCRC.x7 ^= inp.x2;
        inCRC.x8 ^= inp.x3; inCRC.x9 ^= inp.x4; inCRC.x10 ^= inp.x5;
        inCRC.x11 ^= inp.x6; inCRC.x12 ^= inp.x7; inCRC.x13 ^= inp.x8;
        inCRC.x14 ^= inp.x9; inCRC.x15 ^= inp.x10; oneByte.b0 ^= inp.x11;
        oneByte.b1 ^= inp.x12; oneByte.b2 ^= inp.x13; oneByte.b3 ^= inp.x14;
        oneByte.b4 ^= inp.x15; oneByte.b5 ^= inp.x16;
        inByte = oneByte.b4 * 2 * 2 * 2 * 2;
        inByte += oneByte.b3 * 2 * 2 * 2;
        inByte += oneByte.b2 * 2 * 2;
        inByte += oneByte.b1 * 2;
        inByte += oneByte.b0;

        return getCRC(inByte, inCRC, inp);
    }
    else if (oneByte.b4 == 1){
        inCRC.x4 ^= inp.x0; inCRC.x5 ^= inp.x1; inCRC.x6 ^= inp.x2;
        inCRC.x7 ^= inp.x3; inCRC.x8 ^= inp.x4; inCRC.x9 ^= inp.x5;
        inCRC.x10 ^= inp.x6; inCRC.x11 ^= inp.x7; inCRC.x12 ^= inp.x8;
        inCRC.x13 ^= inp.x9; inCRC.x14 ^= inp.x10; inCRC.x15 ^= inp.x11;
        oneByte.b0 ^= inp.x12; oneByte.b1 ^= inp.x13; oneByte.b2 ^= inp.x14;
        oneByte.b3 ^= inp.x15; oneByte.b4 ^= inp.x16;
        inByte = oneByte.b3 * 2 * 2 * 2;
        inByte += oneByte.b2 * 2 * 2;
        inByte += oneByte.b1 * 2;
        inByte += oneByte.b0;

        return getCRC(inByte, inCRC, inp);
    }
    else if (oneByte.b3 == 1){
        inCRC.x3 ^= inp.x0; inCRC.x4 ^= inp.x1; inCRC.x5 ^= inp.x2;
        inCRC.x6 ^= inp.x3; inCRC.x7 ^= inp.x4; inCRC.x8 ^= inp.x5;
        inCRC.x9 ^= inp.x6; inCRC.x10 ^= inp.x7; inCRC.x11 ^= inp.x8;
        inCRC.x12 ^= inp.x9; inCRC.x13 ^= inp.x10; inCRC.x14 ^= inp.x11;
        inCRC.x15 ^= inp.x12; oneByte.b0 ^= inp.x13; oneByte.b1 ^= inp.x14;
        oneByte.b2 ^= inp.x15; oneByte.b3 ^= inp.x16;
        inByte = oneByte.b2 * 2 * 2;
        inByte += oneByte.b1 * 2;
        inByte += oneByte.b0;

        return getCRC(inByte, inCRC, inp);
    }
    else if (oneByte.b2 == 1){
        inCRC.x2 ^= inp.x0; inCRC.x3 ^= inp.x1; inCRC.x4 ^= inp.x2;
        inCRC.x5 ^= inp.x3; inCRC.x6 ^= inp.x4; inCRC.x7 ^= inp.x5;
        inCRC.x8 ^= inp.x6; inCRC.x9 ^= inp.x7; inCRC.x10 ^= inp.x8;
        inCRC.x11 ^= inp.x9; inCRC.x12 ^= inp.x10; inCRC.x13 ^= inp.x11;
        inCRC.x14 ^= inp.x12; inCRC.x15 ^= inp.x13; oneByte.b0 ^= inp.x14;
        oneByte.b1 ^= inp.x15; oneByte.b2 ^= inp.x16;
        inByte = oneByte.b1 * 2;
        inByte += oneByte.b0;

        return getCRC(inByte, inCRC, inp);
    }
    else if (oneByte.b1 == 1){
        inCRC.x1 ^= inp.x0; inCRC.x2 ^= inp.x1; inCRC.x3 ^= inp.x2;
        inCRC.x4 ^= inp.x3; inCRC.x5 ^= inp.x4; inCRC.x6 ^= inp.x5;
        inCRC.x7 ^= inp.x6; inCRC.x8 ^= inp.x7; inCRC.x9 ^= inp.x8;
        inCRC.x10 ^= inp.x9; inCRC.x11 ^= inp.x10; inCRC.x12 ^= inp.x11;
        inCRC.x13 ^= inp.x12; inCRC.x14 ^= inp.x13; inCRC.x15 ^= inp.x14;
        oneByte.b0 ^= inp.x15; oneByte.b1 ^= inp.x16;
        inByte = oneByte.b0;

        return getCRC(inByte, inCRC, inp);
    }
    else if (oneByte.b0 == 1){
        inCRC.x0 ^= inp.x0; inCRC.x1 ^= inp.x1; inCRC.x2 ^= inp.x2;
        inCRC.x3 ^= inp.x3; inCRC.x4 ^= inp.x4; inCRC.x5 ^= inp.x5;
        inCRC.x6 ^= inp.x6; inCRC.x7 ^= inp.x7; inCRC.x8 ^= inp.x8;
        inCRC.x9 ^= inp.x9; inCRC.x10 ^= inp.x10; inCRC.x11 ^= inp.x11;
        inCRC.x12 ^= inp.x12; inCRC.x13 ^= inp.x13; inCRC.x14 ^= inp.x14;
        inCRC.x15 ^= inp.x15; oneByte.b0 ^= inp.x16;

        inByte = 0;

        return getCRC(inByte, inCRC, inp);
    }
    else {
        return inCRC;
    }
}

int main()
{
    //  Initializing polynomial
    struct polynom p;
    p.x16 = 1; p.x15 = 1; p.x2 = 1; p.x0 = 1;
    p.x14 = 0; p.x13 = 0; p.x12 = 0; p.x11 = 0; p.x10 = 0; p.x9 = 0;
    p.x8 = 0; p.x7 = 0; p.x6 = 0; p.x5 = 0; p.x4 = 0;
    p.x3 = 0; p.x1 = 0;

    // Initializing CRC
    struct polycrc crc;
    crc.x15 = 0; crc.x14 = 0; crc.x13 = 0; crc.x12 = 0; crc.x11 = 0;
    crc.x10 = 0; crc.x9 = 0; crc.x8 = 0; crc.x7 = 0; crc.x6 = 0;
    crc.x5 = 0; crc.x4 = 0; crc.x3 = 0; crc.x2 = 0; crc.x1 = 0;
    crc.x0 = 0;

    //  Print p and crc to check
    printPolynom(p);
    printf("\n");
    printCRC(crc);
    printf("\n");

    char* inFileName = "input1.txt";
    FILE* inputFile;
    uint8_t c = 0;

    fopen_s(&inputFile, inFileName, "r");

    if (inputFile == NULL) {
        printf("Error opening file %s", inFileName);
        return 1;
    }

    //  Read file and count CRC
    c = fgetc(inputFile);
    while (!feof(inputFile)) {
        crc = getCRC(c, crc, p);
        printf("Byte %0x CRC: ", c);
        printCRC(crc);
        printf("\n");
        c = fgetc(inputFile);
    }
    fclose(inputFile);

    return 0;
}

为了一次处理一个字节的CRC序列,该序列是一个输入字节与高位(如果左移)或低位(如果右移)CRC的xor,然后循环16位CRC就像线性反馈移位寄存器一样,使用 CRC 多项式进行反馈 8 次。这可以使用 256 个条目查找来加速 table。问题是寻求一种类似硬件的解决方案,使用位域结构将未循环的 16 位输入 CRC 映射到 8 循环的 16 位输出 CRC。

映射是二进制线性映射(如二进制(与、异或)矩阵乘以 16 x 16 位矩阵),顺序无关紧要。可以使用一组 16 个方程式,每个方程式将未循环 CRC 位的一个子集异或为循环 CRC 位。对于一组 16 个输入 CRC 值,每个设置 1 位:{0x0001、0x0002、0x0004、...、0x2000、0x4000、0x8000} 和注意哪些输入位对每个输出位有贡献。

对于每个输入字节,多项式 0x11021 的左移 CRC 示例:

    /* xor the input byte to the upper 8 bits of the CRC */
    crcin.b8 ^= dat.b0;
    crcin.b9 ^= dat.b1;
    crcin.ba ^= dat.b2;
    crcin.bb ^= dat.b3;
    crcin.bc ^= dat.b4;
    crcin.bd ^= dat.b5;
    crcin.be ^= dat.b6;
    crcin.bf ^= dat.b7;
    /* cycle the 16 bit CRC 8 times via mapping */
    crcot.b0 = crcin.b8 ^ crcin.bc;
    crcot.b1 = crcin.b9 ^ crcin.bd;
    crcot.b2 = crcin.ba ^ crcin.be;
    crcot.b3 = crcin.bb ^ crcin.bf;
    crcot.b4 = crcin.bc;
    crcot.b5 = crcin.b8 ^ crcin.bc ^ crcin.bd;
    crcot.b6 = crcin.b9 ^ crcin.bd ^ crcin.be;
    crcot.b7 = crcin.ba ^ crcin.be ^ crcin.bf;
    crcot.b8 = crcin.b0 ^ crcin.bb ^ crcin.bf;
    crcot.b9 = crcin.b1 ^ crcin.bc;
    crcot.ba = crcin.b2 ^ crcin.bd;
    crcot.bb = crcin.b3 ^ crcin.be;
    crcot.bc = crcin.b4 ^ crcin.b8 ^ crcin.bc ^ crcin.bf;
    crcot.bd = crcin.b5 ^ crcin.b9 ^ crcin.bd;
    crcot.be = crcin.b6 ^ crcin.ba ^ crcin.be;
    crcot.bf = crcin.b7 ^ crcin.bb ^ crcin.bf;
    crcin = crcot;