Support verifiyng C CRC8 implementation - c

have made some test on a crc calculator I have written based on dallas crc8 applied in 1-Wire, it uses 0x8c poly. I am testing it adding 1, 2 and 3 bit errors on a 15 bytes string (adding bit errors also to the crc itself). The pasted implementation is unable to identify 2, 2bit errors and 9, 3 bit errors...
static inline uint8_t roll(char input_byte, uint8_t crc) {
for(uint8_t i = 8; i; i--, input_byte >>= 1) {
uint8_t result = (crc ^ input_byte) & 0x01;
crc >>= 1;
if(result) crc ^= 0x8C;
}
return crc;
};
static inline uint8_t compute(const uint8_t *input_byte, uint16_t length) {
uint8_t crc = 0;
for(uint16_t b = 0; b < length; b++)
crc = roll(input_byte[b], crc);
return crc;
};
Fiddling with the code I have noticed that removing & 0x01 cause a huge gain in accuracy whatever value data has (trying with different types of string):
static inline uint8_t roll(char input_byte, uint8_t crc) {
for(uint8_t i = 8; i; i--, input_byte >>= 1) {
uint8_t result = crc ^ input_byte;
crc >>= 1;
if(result) crc ^= 0x8C;
}
return crc;
};
static inline uint8_t compute(const uint8_t *input_byte, uint16_t length) {
uint8_t crc = 0;
for(uint16_t b = 0; b < length; b++)
crc = roll(input_byte[b], crc);
return crc;
};
With the posted modification I get no 1, 2 or 3 bit errors with always 100% accuracy for the range I need that is 0-15 characters or 0-120bits
Is there someone could help me understanding what is happening here?

I believe there's a flaw in your test methodology. According to my testing, the original implementation detects all 1, 2, and 3 bit errors, and 99.2% of 4 bit errors. Your proposed alternative almost always generates the exact same result (0xf7). This is to be expected since crc ^ input_byte will almost always be non-zero.
Hence, your implementation is equivalent (most of the time) to:
static inline uint8_t compute(const uint8_t *input_byte, uint16_t length) {
uint8_t crc = 0;
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 8; j++) {
crc >>= 1;
crc ^= 0x8C;
}
}
return crc;
}
which indeed generates the value 0xf7.
I believe the flaw in your test is that it assumes that a crc match is a good thing. On the contrary, if the crc on the original string is the same as the crc after injecting bit errors, that's bad (the crc generator did not detect the error).

Related

C Zephyr SDK CRC16 Implementation

I was looking around in the zephyr implementations and found this method for computing a crc16 checksum:
u16_t crc16(const u8_t *src, size_t len, u16_t polynomial,
u16_t initial_value, bool pad)
{
u16_t crc = initial_value;
size_t padding = pad ? sizeof(crc) : 0;
size_t i, b;
/* src length + padding (if required) */
for (i = 0; i < len + padding; i++) {
for (b = 0; b < 8; b++) {
u16_t divide = crc & 0x8000UL;
crc = (crc << 1U);
/* choose input bytes or implicit trailing zeros */
if (i < len) {
crc |= !!(src[i] & (0x80U >> b));
}
if (divide != 0U) {
crc = crc ^ polynomial;
}
}
}
return crc;
}
And I tripped over this line here:
crc |= !!(src[i] & (0x80U >> b));
I do not understand why they are using a boolean operator (!!) in this line. From my understanding this is what it does:
It basically does an implicit "casting" where it considers its operand on the right to be a boolean and negates it twice, which does not do anything besides making the output a 0 or a 1 depending on if the expression (src[i] & (0x80U >> b)) was bigger then 0 to start with.
Is this correct? Why are they using the operator in this way?
It is inserting bit 7-b from src[i] into the low bit of crc. If that bit is a 1, which will be somewhere in the result of the &, the !! turns it into a 1 in the low bit, which is then or'ed into crc.
This is truly painful to look at. A better and cleaner way to do it is crc |= (src[i] >> b) & 1;, where b counts down instead of up. E.g. int b = 8; do { b--; ... } while (b);. Better still would be to just exclusive-or the byte after the loop, which does the same thing:
/* src length + padding (if required) */
for (i = 0; i < len + padding; i++) {
for (b = 0; b < 8; b++)
crc = crc & 0x8000 ? (crc << 1) ^ polynomial : crc << 1;
if (i < len)
crc ^= src[i];
}
An optimizing compiler will unroll the b loop.

CRC implementing a specific polynomial. How does the polynomial relate to the polynomial used in code?

I have the following CRC function:
#define CRC8INIT 0x00
#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0
// ----------------------------------------------------------------------------
uint8_t crc8 (uint8_t *data, uint16_t number_of_bytes_in_data)
{
uint8_t crc;
uint16_t loop_count;
uint8_t bit_counter;
uint8_t b;
uint8_t feedback_bit;
crc = CRC8INIT;
for (loop_count = 0; loop_count != number_of_bytes_in_data; loop_count++) {
b = data[loop_count];
bit_counter = 8;
do {
feedback_bit = (crc ^ b) & 0x01;
if (feedback_bit == 0x01) {
crc = crc ^ CRC8POLY;
}
crc = (crc >> 1) & 0x7F;
if (feedback_bit == 0x01) {
crc = crc | 0x80;
}
b = b >> 1;
bit_counter--;
} while (bit_counter > 0);
}
return crc;
}
How does 0x18 relate to the polynomial X^8+X^5+X^4+X^0?
X^8+X^5+X^4+X^0 = 100110001
0x18 = 00011000
What if I define CRC8POLY as 0xEA instead (I have seen this), what polynomial would that represent?
How does 0x18 relate to the polynomial X^8+X^5+X^4+X^0?
Since the code is a right shifting CRC, the "most significant bit" of each byte is bit 0 instead of bit 7. The poly needs to be reversed from 100110001 to 100011001, which is 0x119, after the right shift, bit 0 of 0x119 is shifted off, so 0x118 can be used instead. The code uses a second if statement to or in (0x100) >> 1 == 0x80 if the feedback bit is 1. As an alternative, since feedback_bit is 0 or 1, then (0-feeback_bit) can be used as a mask (assuming two's complement math) for the poly instead of using an if statement.
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
#define CRC8INIT 0x00
#define CRC8POLY 0x8c // 0x119 >> 1
uint8_t crc8 (uint8_t *data, uint16_t number_of_bytes_in_data)
{
uint8_t crc;
uint16_t loop_count;
uint8_t bit_counter;
uint8_t b;
uint8_t feedback_bit;
crc = CRC8INIT;
for (loop_count = 0; loop_count != number_of_bytes_in_data; loop_count++) {
b = data[loop_count];
bit_counter = 8;
do {
feedback_bit = (crc ^ b) & 0x01;
crc = (crc >> 1) ^ ((0-feedback_bit) & CRC8POLY);
b = b >> 1;
bit_counter--;
} while (bit_counter > 0);
}
return crc;
}
That CRC code is written rather oddly, where the polynomial is applied in two different places, breaking up the bits. That is, at crc = crc ^ CRCPOLY and conditionally crc = crc | 0x80. It would normally be written more like this:
unsigned crc8(unsigned char const *dat, size_t len) {
unsigned crc = 0;
for (size_t i = 0; i < len; i++) {
crc ^= dat[i];
for (int k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ 0x8c : crc >> 1;
}
return crc;
}
where 0x8c is that polynomial reversed, without the x8 term.
Referring to Wiki article on CRC , it's crc8 realization as used in Dallas 1-wire chips. Note, that polinomial can be represented in Normal, Reversed, Reciprocal and Reversed reciprocal representations (see also Polynomial representations). Seems, that it is Reversed reciprocal representation with highest bit omitted.

Software logic for calculating crc in a bootloader application

I found a file to check crc of an incoming application via some interface and the program is as follows:
#define CRC16POLY 0x1021
#define PKTLEN_128 128
typedef struct Crc16Data {
uint16_t currentCrc; //!< Current CRC value.
} crc16_data_t;
void crc16_init(crc16_data_t * crc16Config)
{
// initialize running crc and byte count
crc16Config->currentCrc = 0;
}
void crc16_update(crc16_data_t * crc16Config, const uint8_t * src, uint32_t lengthInBytes)
{
uint32_t crc = crc16Config->currentCrc;
uint32_t j;
for (j=0; j < lengthInBytes; ++j)
{
uint32_t i;
uint32_t byte = src[j];
crc ^= byte << 8;
for (i = 0; i < 8; ++i)
{
uint32_t temp = crc << 1;
if (crc & 0x8000)
{
temp ^= 0x1021;
}
crc = temp;
}
}
crc16Config->currentCrc = crc;
}
void crc16_finalize(crc16_data_t * crc16Config, uint16_t * hash)
{
*hash = crc16Config->currentCrc;
}
I understood that it is simple crc software logic that doesnot involve any hardware generated crc mechanism to calculate crc of an incoming application and it is just counting the bytes of the application and adding them and placing them right? Can anyone explain what is happening inside void crc16_update(crc16_data_t * crc16Config, const uint8_t * src, uint32_t lengthInBytes) function?
And in one of the files crc16update(....) function is called as follows:
crc16_update(&crcInfo,buffer,PKTLEN_128);
where in another functions crcInfo,buffer information is found from
static void read_bytes(uint8_t * buffer, uint32_t byteCount)
{
uint32_t currentBytesRead = 0;
while(currentBytesRead != byteCount)
{
if (readOffset != writeOffset)
{
buffer[currentBytesRead++] = callback_buffer[readOffset++];
readOffset &= XMODEM_BUFLEN - 1;
}
}
}
static int read_packet(uint8_t *buffer, uint8_t idx)
{
uint8_t seq[2],crc1,crc2;
uint16_t crc16, verify16;
crc16_data_t crcInfo;
read_bytes(seq,2);
read_bytes(buffer,PKTLEN_128);
crc16_init(&crcInfo);
crc16_update(&crcInfo,buffer,PKTLEN_128);
crc16_finalize(&crcInfo,&verify16);
read_bytes(&crc1,1);
read_bytes(&crc2,1);
crc16 = ((uint16_t)crc1 << 8)|crc2;
if ((crc16 != verify16) || (seq[0] != idx) || (seq[1] != (uint8_t) ((~(uint32_t)idx)&0xff)))
return(-1);
return(0);
}
What is happening inside the function void crc16_update(crc16_data_t * crc16Config, const uint8_t * src, uint32_t lengthInBytes) ? Thanks in advance.
This code:
crc ^= byte << 8;
for (i = 0; i < 8; ++i)
{
uint32_t temp = crc << 1;
if (crc & 0x8000)
{
temp ^= 0x1021;
}
crc = temp;
}
updates the CRC with the byte. It simulates running a linear feedback shift register, whose state is the value of crc. That could can be written more compactly possibly making it easier to see what's going on:
crc ^= byte << 8;
for (int i = 0; i < 8; i++)
crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
The high bit of crc determines whether or not to exclusive-or the polynomial 0x1021 with the register, after the register is shifted up one bit, with that high bit dropping off the end.
To learn more about how this implementation is arrived at, you should read Ross William's CRC tutorial.

CRC32C - appending 0s/CRC to message

I am trying to get a better understanding of CRC, however I am stuck a bit.
There are few sample vectors here 1 which I can calculate correctly, however I am stuck with verifying that the calculated CRC is correct.
For example, given a message of 32 bytes:
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
my understanding is that you first append 32 bits of 0's to get a payload:
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f00000000
and calculate CRC on that message to obtain 0x73c2a486
To verify that CRC is correct you should then append CRC value to the original value, in this case:
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f73c2a486
And this should return 0, however I don't get that.
Would greatly appreciate if anyone could point out where I am going wrong.
Edit:
Sample code that I am using:
static uint32_t crc32c_table_small[256] =
{
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
};
static inline uint32_t crc32c_software_simple(uint32_t crc, const uint8_t * data, size_t num_bytes)
{
while (num_bytes--)
{
crc = (crc >> 8) ^ crc32c_table_small[(crc & 0xFF) ^ *data++];
}
return crc;
}
uint32_t num_bytes = 32;
uint32_t num_bytes_padded = num_bytes + sizeof(uint32_t);
uint8_t * test_data = (uint8_t*) malloc(num_bytes_padded);
for(uint32_t i = num_bytes; i < num_bytes_padded; i++) test_data[i] = 0;
for(uint32_t i = 0; i < num_bytes; i++)
{
test_data[i] = i;
}
binary(num_bytes_padded, test_data);
hex(num_bytes_padded, test_data);
uint32_t crc = 0xFFFFFFFF;
crc = ~crc32c_software_simple(crc, test_data, num_bytes_padded);
for(uint32_t i = 0; i < sizeof(uint32_t); i++) test_data[num_bytes + i] = ((uint8_t*)&crc)[i];
crc = 0xFFFFFFFF;
crc = ~crc32c_software_simple(crc, test_data, num_bytes_padded);
What you have there is a complete calculation of a CRC that does not require appending zeros to the end. The way it is used is to simply compute the CRC on the message (with nothing appended), and then append the computed CRC. On the other end, compute the CRC on the just the message (not including the CRC) and compare the computed CRC with the one that followed the message in the transmission. As opposed to looking for a zero. Super simple, and the way you would do it for any hash value.
It is true however that if you compute the CRC on the message and the appended CRC, assuming that the CRC is encoded in the proper bit and byte order, then the mathematics assures that the result will be the same constant, the "residual" for that CRC, for all correct message/CRC combinations. The residual in this case is not all zeros, because the CRC is exclusive-ored with a non-zero constant. You could do it by checking for the residual if you like, but it seems like a waste of time to compute the CRC on four more bytes, as well as adding some obscurity to the code, when you could just compare.
The example code does a post complement of the CRC. This will cause the verify CRC to be a constant non-zero value, in this case verify CRC == 0x48674bc7 if there are no errors (regardless of message size). The calling code needed a fix on the first call to crc32c_software_simple, to use num_bytes instead of num_bytes_padded, as noted in the comment below.
If there was no post complement of the CRC, then the verify would produce a zero CRC.
The code also does a pre-complement of the CRC, but this will not affect the verify.
int main()
{
uint32_t num_bytes = 32;
uint32_t num_bytes_padded = num_bytes + sizeof(uint32_t);
uint8_t * test_data = (uint8_t*) malloc(num_bytes_padded);
for(uint32_t i = num_bytes; i < num_bytes_padded; i++) test_data[i] = 0;
for(uint32_t i = 0; i < num_bytes; i++)
{
test_data[i] = i;
}
uint32_t crc = 0xFFFFFFFF;
crc = ~crc32c_software_simple(crc, test_data, num_bytes); // num_bytes fix
for(uint32_t i = 0; i < sizeof(uint32_t); i++) test_data[num_bytes + i] = ((uint8_t*)&crc)[i];
crc = 0xFFFFFFFF;
crc = ~crc32c_software_simple(crc, test_data, num_bytes_padded);
// if no errors, crc == 0x48674bc7
return 0;
}

CRC-32 with LFSR Byte by Byte in C

I implemented a CRC32 algorithm in C but after hours of looking around and trying to fix it, it still doesn't work. It compiles but the checksum is not the same as in several online CRC calculators. I suspect the error to be in the line "if (0 != (character & j))" but don't understand it, since it is even mainly the same as the code on wikipedia.
wikipedia
int CRC32_C(char *message){
int length, i, j;
unsigned long p,g;
char character;
p = 0x00000000;
g = 0x04C11DB7;
length = strlen(message);
for (i = 0; i < length; i++){
character=*message;
//iterieren durch die bits jedes zeichens
for (j= 0x80; j != 0; j >>= 1){
//(p & 0x80000000)? 1 : 0)
if (0 != (character & j))
p = (p << 1) ^ g;
else
p <<=1;
}
message++;
}
return p;
}
//sample main
int main(char ** argv, int argc){
char *msg;
int p;
msg = "HALLO";
p = CRC32_C(msg);
printf("p ist 0x%x \n", p);
return 0;
}
Sample input: "HALLO"
Expected result: 0x4E26F361 (according to this page, which uses the same generator polynomial, as seen at the bottom of the page)
Actual result: 0xc25a747d
#chux: I tried removing the "0 !=" in the if clause, but it didn't change the result.
CRC32_C simply stands for "Implemented in C". As the Generator polynomial suggests, it is standard Ethernet.
Thanks for your help
The CRC may be msb to lsb or lsb to msb, and the generator polynomial may be different in the online examples. CRC32_F is msb to lsb, CRC32_R is lsb to msb (with the polynomial reversed). If you can find an online CRC calculator that takes hex, try using hex 01 to test for msb to lsb, or hex 80 to test for lsb to msb. Other variations initialize the crc to 0xffffffff and/or invert (not) the crc after calculating the crc. Looking at a description of ethernet crc, try using CRC32_R, but change the initialization of crc to crc = 0xfffffffful; .
unsigned long CRC32_F(unsigned char *message, size_t length){
size_t i, j;
unsigned long crc,gnp;
crc = 0x00000000ul;
gnp = 0x04C11DB7ul;
for (i = 0; i < length; i++){
crc ^= ((unsigned long)*message)<<24;
for (j = 0; j < 8; j++){
if (crc & 0x80000000ul)
crc = (crc << 1) ^ gnp;
else
crc = (crc << 1);
}
message++;
}
return crc;
}
unsigned long CRC32_R(unsigned char *message, size_t length){
size_t i, j;
unsigned long crc,gnp;
crc = 0x00000000ul;
gnp = 0xEDB88320ul;
for (i = 0; i < length; i++){
crc ^= ((unsigned long)*message)<<0;
for (j = 0; j < 8; j++){
if (crc & 0x00000001ul)
crc = (crc >> 1) ^ gnp;
else
crc = (crc >> 1);
}
message++;
}
return crc;
}
This will generate the CRC 0x4E26F361 from HALLO:
#include <stddef.h>
#include <stdint.h>
/* CRC-32 (Ethernet, ZIP, etc.) polynomial in reversed bit order. */
#define POLY 0xedb88320
/* Compute CRC of buf[0..len-1] with initial CRC of crc. Start
with crc == 0. */
uint32_t crc32c(uint32_t crc, const unsigned char *buf, size_t len)
{
int k;
crc = ~crc;
while (len--) {
crc ^= *buf++;
for (k = 0; k < 8; k++)
crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
}
return ~crc;
}
The above computes the CRC bit-by-bit, where there are faster approaches. That happens to be CRC in common use, so you can find a fast implementation in zlib, called crc32(), which is already available as an installed library in most systems.

Resources