Difference in Boost CRC and linux/lib/crc-ccitt.c

2019-07-16 01:35发布

I have two sources to calculate the seemingly same crc value. I can not figure out why the 'boost/crc.hpp' implementation differs from the 'linux/lib/crc-ccitt.c' implementation.

crc-ccitt.c boost

Here is an example that illustrates the Problem. It is sligthly longer since i do not have the Linux kernel source on my Computer. It compiles if you link boost to it.

The Problem is that Linux and boost do not agree on the crc value. The Linux source states that:

  • The polynomial ... 0x8408.
  • Add the implicit x^16, and you have the standard CRC-CCITT.

I do not know how to apply x^16 but i die edit this question to reflect the deviating polynomial.

#include <stdio.h>
#include <boost\crc.hpp>

typedef unsigned short u16;
typedef unsigned char u8;

/*
*   linux/lib/crc-ccitt.c
*
*   This source code is licensed under the GNU General Public License,
*   Version 2. See the file COPYING for more details.
*/

/*modified for minimal example on stackoverflow*/
/*original source from http://mirrors.neusoft.edu.cn/rpi-kernel/lib/crc-ccitt.c */

u16 const crc_ccitt_table[256] = {
    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
    0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
    0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
    0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
    0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
    0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
    0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
    0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
    0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
    0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
    0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
    0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
    0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
    0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
    0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
    0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
    0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
    0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
    0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
    0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
    0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
    0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
    0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
    0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
    0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
    0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
    0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
    0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
    0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
    0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
    0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
    0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};

//from crc-ccitt.h
static inline u16 crc_ccitt_byte(u16 crc, const u8 c)
{
    return (crc >> 8) ^ crc_ccitt_table[(crc ^ c) & 0xff];
}

u16 crc_ccitt(u16 crc, u8 const *buffer, size_t len)
{
    while (len--)
        crc = crc_ccitt_byte(crc, *buffer++);
    return crc;
}

#define check(X, Y) \
if (X != Y) { \
    printf("%s !=  %s\n", #X, #Y); \
} else { \
    printf("%s ==  %s   !!! celebrate\n", #X, #Y); \
} 

void runTestSet(unsigned char * data, unsigned size)
{
    u16 linux = crc_ccitt(0xFFFF, data, size);

    boost::crc_ccitt_type boost_crc_ccitt_type;
    boost::crc_16_type boost_crc_16_type;
    boost::crc_32_type boost_crc_32_type;
    boost::crc_xmodem_type boost_crc_xmodem_type;
    boost::crc_optimal<16, 0x8408, 0xFFFF, 0, false, false> boost_crc_optimal_16_8408_FFFF_0_0_0;
    boost::crc_optimal<16, 0x8408, 0xFFFF, 0, true, true> boost_crc_optimal_16_8408_FFFF_0_1_1;
    boost::crc_optimal<16, 0xA001, 0xFFFF, 0, true, true> boost_crc_optimal_16_A001_FFFF_0_1_1;
    boost::crc_optimal<16, 0x8408, 0xFFFF, 0, true, false> boost_crc_optimal_16_8408_FFFF_0_1_0;
    boost::crc_optimal<16, 0x856F, 0xFFFF, 0, true, true> boost_crc_optimal_16_856F_FFFF_0_1_1;
    boost::crc_optimal<16, 0x856F, 0xFFFF, 0, true, false> boost_crc_optimal_16_856F_FFFF_0_1_0;

    boost_crc_ccitt_type.process_bytes(data, size);
    boost_crc_16_type.process_bytes(data, size);
    boost_crc_32_type.process_bytes(data, size);
    boost_crc_xmodem_type.process_bytes(data, size);
    boost_crc_optimal_16_8408_FFFF_0_0_0.process_bytes(data, size);
    boost_crc_optimal_16_8408_FFFF_0_1_1.process_bytes(data, size);
    boost_crc_optimal_16_A001_FFFF_0_1_1.process_bytes(data, size);
    boost_crc_optimal_16_8408_FFFF_0_1_0.process_bytes(data, size);
    boost_crc_optimal_16_856F_FFFF_0_1_1.process_bytes(data, size);
    boost_crc_optimal_16_856F_FFFF_0_1_0.process_bytes(data, size);

    printf("Testing with sequence: '");
    for (unsigned n = 0; n < size; ++n)
    {
        if (n > 0) printf(" ");
        printf("0x%02X", data[n]);
    }
    printf("'\n");
    check(boost_crc_ccitt_type.checksum(), linux);
    check(boost_crc_16_type.checksum(), linux);
    check(boost_crc_32_type.checksum(), linux);
    check(boost_crc_xmodem_type.checksum(), linux);
    check(boost_crc_optimal_16_8408_FFFF_0_0_0.checksum(), linux);
    check(boost_crc_optimal_16_8408_FFFF_0_1_1.checksum(), linux);
    check(boost_crc_optimal_16_A001_FFFF_0_1_1.checksum(), linux);
    check(boost_crc_optimal_16_8408_FFFF_0_1_0.checksum(), linux);
    check(boost_crc_optimal_16_856F_FFFF_0_1_1.checksum(), linux);
    check(boost_crc_optimal_16_856F_FFFF_0_1_0.checksum(), linux);
    printf("End Of Testrun\n\n");
}


int main()
{
    unsigned char simple[] = {0x80};
    unsigned char sequence[] = "123456789";
    runTestSet(simple, sizeof(simple));
    runTestSet(sequence, sizeof(sequence));
    return 0;
}

I see that i did not state my usecase for this. I have a System dependency and need to use the incorrect(?) Linux crc. I want to trim the boost implementation in a way that allows me to do this using boost instead.

The output on my machine is:

enter image description here

4条回答
The star\"
2楼-- · 2019-07-16 01:36

Through Trial and error i found a solution that seems to produce the correct hits. Thanks everyone for the hints. This type boost::crc_optimal<16, 0x1021, 0xFFFF, 0, true, true> seems to be correct.

I do not know why and that worries me a bit.

#include <stdio.h>
#include <boost\crc.hpp>

typedef unsigned short u16;
typedef unsigned char u8;

/*
*   linux/lib/crc-ccitt.c
*
*   This source code is licensed under the GNU General Public License,
*   Version 2. See the file COPYING for more details.
*/

/*modified for minimal example on stackoverflow*/
/*original source from http://mirrors.neusoft.edu.cn/rpi-kernel/lib/crc-ccitt.c */

u16 const crc_ccitt_table[256] = {
    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
    0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
    0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
    0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
    0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
    0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
    0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
    0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
    0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
    0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
    0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
    0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
    0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
    0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
    0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
    0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
    0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
    0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
    0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
    0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
    0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
    0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
    0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
    0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
    0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
    0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
    0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
    0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
    0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
    0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
    0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
    0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};

//from crc-ccitt.h
static inline u16 crc_ccitt_byte(u16 crc, const u8 c)
{
    return (crc >> 8) ^ crc_ccitt_table[(crc ^ c) & 0xff];
}

u16 crc_ccitt(u16 crc, u8 const *buffer, size_t len)
{
    while (len--)
        crc = crc_ccitt_byte(crc, *buffer++);
    return crc;
}

#define check(X, Y) \
if (X != Y) { \
    printf("%s (0x%08X) !=  %s (0x%08X)\n", #X, X, #Y, Y); \
} else { \
    printf("%s (0x%08X) ==  %s (0x%08X)!!! celebrate\n", #X, X, #Y, Y); \
}

void runTestSet(unsigned char * data, unsigned size)
{
    u16 linux = crc_ccitt(0xFFFF, data, size);
    boost::crc_optimal<16, 0x1021, 0xFFFF, 0, true, true> boost_crc_optimal_16_1021_FFFF_0_1_1;
    boost_crc_optimal_16_1021_FFFF_0_1_1.process_bytes(data, size);

    printf("Testing with sequence: '");
    for (unsigned n = 0; n < size; ++n)
    {
        if (n > 0) printf(" ");
        printf("0x%02X", data[n]);
    }
    printf("'\n");
    check(boost_crc_optimal_16_1021_FFFF_0_1_1.checksum(), linux);
    printf("End Of Testrun\n\n");
}


int main()
{
    unsigned char zero_Length[] = {0x00};
    unsigned char simple[] = {0x80};
    unsigned char sequence[] = "123456789";
    unsigned char LotsOfAs[] = "AAAAAAAAAAAAAAAAAAAAAAAAA";
    runTestSet(zero_Length, 0);
    runTestSet(simple, sizeof(simple));
    runTestSet(sequence, sizeof(sequence)-1);
    runTestSet(LotsOfAs, sizeof(LotsOfAs)-1);
    return 0;
}
查看更多
姐就是有狂的资本
3楼-- · 2019-07-16 01:40

Given lib/crc-ccitt.c does not use the 0x1021 polynomial required for CRC-CCITT. So, i think boost version is correct since crc_ccitt_type is a typedef:

typedef crc_optimal<16, 0x1021, 0xFFFF, 0, false, false>  crc_ccitt_type;

P.S. Warning: your line size = sizeof(data) / sizeof(data[0]) is not correct, but it gives right number. This counts number of elements, not number of bytes (but since sizeof(char)==1 it caclulates right size).

查看更多
Root(大扎)
4楼-- · 2019-07-16 01:43

update - based on these web site crc calculators

(choose ccitt(0xffff)) http://www.lammertbies.nl/comm/info/crc-calculation.html

(choose crc ccitt) http://www.zorc.breitbandkatze.de/crc.html

A third site that calls this version crc-16-ccitt-false, and also lists the other variations also called ccitt.

http://reveng.sourceforge.net/crc-catalogue/16.htm#crc.cat.crc-16-ccitt-false

In this case the bits are not reversed. Also the 9 byte string "123456789" seems like a common test. However other web sites mention that some versions of ccitt do reverse the bits as done in the linux example. My guess is that which one to use will be protocol / device specific. At least now you have both the reversed (linux) and non-reversed (the code in this answer) if you need to switch.

Example code added:

A CRC is the remainder after doing a Galois type divide of a string of bits by a n bit polynomial, producing an n-1 bit remainder. In the case of a floppy disk, a 17 bit polynomial, 0x11021 is used to produce a 16 bit remainder. The logic for each bit goes something like this:

    crc << = 1;
    if(crc & 0x10000)crc ^= 0x11021;

This can be also implemented s:

    if(crc & 0x8000){crc = ((crc<<1) & 0xffff) & 0x1021;}
    else {crc = ((crc<<1) & 0xffff);}

Example code. This should match the boost code.

typedef unsigned short u16;
typedef unsigned char u8;

u16 crctbl[256] = {
    0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
    0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
    0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
    0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
    0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
    0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
    0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
    0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
    0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
    0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
    0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
    0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
    0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
    0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
    0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
    0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
    0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
    0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
    0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
    0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
    0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
    0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
    0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
    0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
    0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
    0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
    0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
    0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
    0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
    0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
    0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
    0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0};

u16 gencrc(u8 *bfr, size_t len)
{
u16 crc = 0xffff;
    while(len--)
        crc = (crc << 8) ^ crctbl[(crc >> 8)^*bfr++];
    return(crc);
}

int main()
{
u16 crc;
u8 a[4]  = {0x80, 0, 0, 0};
u8 b[10] = {"123456789"};
    crc = gencrc(a, 1);   // returns 0x7078
    crc = gencrc(b, 9);   // returns 0x29b1
    return(0);
}
查看更多
冷血范
5楼-- · 2019-07-16 02:00

The table from the question does indeed use the polynomial 0x1021. This can be checked by generating the table with this short program:

#include <iostream>

unsigned long SwapBits(unsigned long swap, int bits)
{
    unsigned long r = 0;
    for(int i = 0; i < bits; i++) {
        if(swap & 1) r |= 1 << (bits - i - 1);
        swap >>= 1;
    }
    return r;
}

int main()
{
    const unsigned short poly = 0x1021;
    unsigned short CRCTab[256];
    for(int i = 0; i < 256; i++) {
        CRCTab[i] = SwapBits(i, 8) << 8;
        for(int j = 0; j < 8; j++) CRCTab[i] = (CRCTab[i] << 1) ^ ((CRCTab[i] & 0x8000) ? poly : 0);
        CRCTab[i] = SwapBits(CRCTab[i], 16);
    }
    for(int i = 0; i < 256; ) {
        char str[10];
        for(int j = 0; j < 8; j++, i++) {
            sprintf(str, "0x%04x, ", CRCTab[i]);
            std::cout << str;
        }
        std::cout << "\n";
    }
    return 0;
}
查看更多
登录 后发表回答