CRC32C - appending 0s/CRC to message - c
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;
}
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.
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.
Support verifiyng C CRC8 implementation
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).
CRC32 calculation with CRC hash at the beginning of the message in C
I need to calculate CRC of the message and put it at the beginning of this message, so that the final CRC of the message with 'prepended' patch bytes equals 0. I was able to do this very easily with the help of few articles, but not for my specific parameters. The thing is that I have to use a given CRC32 algorithm which calculates the CRC of the memory block, but I don't have that 'reverse' algorithm that calculates those 4 patch bytes/'kind of CRC'. Parameters of the given CRC32 algorithm are: Polynomial: 0x04C11DB7 Endianess: big-endian Initial value: 0xFFFFFFFF Reflected: false XOR out with: 0L Test stream: 0x0123, 0x4567, 0x89AB, 0xCDEF results in CRC = 0x612793C3 The code to calculate the CRC (half-byte, table-driven, I hope data type definitions are self-explanatory): uint32 crc32tab(uint16* data, uint32 len, uint32 crc) { uint8 nibble; int i; while(len--) { for(i = 3; i >= 0; i--) { nibble = (*data >> i*4) & 0x0F; crc = ((crc << 4) | nibble) ^ tab[crc >> 28]; } data++; } return crc; } The table needed is (I thougth the short [16] table should contain every 16th element from the large [256] table, but this table contains actually first 16 elements, but that's how it was provided to me): static const uint32 tab[16]= { 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD }; I modified the code so it's not so long, but the functionality stays the same. The problem is that this forward CRC calculation looks more like backward/reverse CRC calc. I've spent almost a week trying to find out the correct polynomial/algorithm/table combination, but with no luck. If it helps, I came up with bit-wise algorithm that corresponds to table-driven code above, although that was not so hard after all: uint32 crc32(uint16* data, uint32 len, uint32 crc) { uint32 i; while(len--) { for(i = 0; i < 16; i++) { // #define POLY 0x04C11DB7 crc = (crc << 1) ^ (((crc ^ *data) & 0x80000000) ? POLY : 0); } crc ^= *data++; } return crc; } Here are expected results - first 2 16-bit words make the needed unknown CRC and the rest is the known data itself (by feeding these examples to provided algorithm, the result is 0). {0x3288, 0xD244, 0xCDEF, 0x89AB, 0x4567, 0x0123} {0xC704, 0xDD7B, 0x0000} - append as many zeros as you like, the result is the same {0xCEBD, 0x1ADD, 0xFFFF} {0x81AB, 0xB932, 0xFFFF, 0xFFFF} {0x0857, 0x0465, 0x0000, 0x0123} {0x1583, 0xD959, 0x0123} ^ ^ | | unknown bytes that I need to calculate I think testing this on 0xFFFF or 0x0000 words is convenient because the direction of calculation and endianess is not important (I hope :D). So be careful to use other test bytes, because the direction of calculation is quite devious :D. Also you can see that by feeding only zeros to the algorithm (both forward and backward), the result is so-called residue (0xC704DD7B), that may be helpful. So...I wrote at least 10 different functions (bite-wise, tables, combination of polynomials etc.) trying to solve this, but with no luck. I give you here the function in which I put my hopes into. It's 'reversed' algorithm of the table-driven one above, with different table of course. The problem is that the only correct CRC I get from that is with all 0s message and that's not so unexpected. Also I have written the reversed implementation of the bit-wise algorithm (reversed shifts, etc.), but that one returns only the first byte correctly. Here is the table-driven one, pointer to data should point to the last element of the message and crc input should be the requested crc (0s for the whole message or you can maybe take another approach - that the last 4 bytes of message are the CRC you are looking for: Calculating CRC initial value instead of appending the CRC to payload) : uint32 crc32tabrev(uint16* data, uint32 len, uint32 crc) { uint8 nibble; int i; while(len--) { for(i = 0; i < 4; i++) { nibble = (*data >> i*4) & 0x0F; crc = (crc >> 4) ^ revtab[((crc ^ nibble) & 0x0F)]; } data--; } return reverse(crc); //reverse() flips all bits around center (MSB <-> LSB ...) } The table, which I hope is 'the chosen one': static const uint32 revtab[16]= { 0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 0x6B6B51F4, 0x4DB26158, 0x5005713C, 0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C, 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C }; As you can see, this algorithm has some perks which make me run in circles and I think I'm maybe on the right track, but I'm missing something. I hope an extra pair of eyes will see what I can not. I'm sorry for the long post (no potato :D), but I think all of that explanation was neccessary. Thank you in advance for insight or advice.
I will answer for your CRC specification, that of a CRC-32/MPEG-2. I will have to ignore your attempts at calculating that CRC, since they are incorrect. Anyway, to answer your question, I happen to have written a program that solves this problem. It is called spoof.c. It very rapidly computes what bits to change in a message to get a desired CRC. It does this in order log(n) time, where n is the length of the message. Here is an example: Let's take the nine-byte message 123456789 (those digits represented in ASCII). We will prepend it with four zero bytes, which we will change to get the desired CRC at the end. The message in hex is then: 00 00 00 00 31 32 33 34 35 36 37 38 39. Now we compute the CRC-32/MPEG-2 for that message. We get 373c5870. Now we run spoof with this input, which is the CRC length in bits, the fact that it is not reflected, the polynomial, the CRC we just computed, the length of the message in bytes, and all 32 bit locations in the first four bytes (which is what we are allowing spoof to change): 32 0 04C11DB7 373c5870 13 0 0 1 2 3 4 5 6 7 1 0 1 2 3 4 5 6 7 2 0 1 2 3 4 5 6 7 3 0 1 2 3 4 5 6 7 It gives this output with what bits in those first four bytes to set: invert these bits in the sequence: offset bit 0 1 0 2 0 4 0 5 0 6 1 0 1 2 1 5 1 7 2 0 2 2 2 5 2 6 2 7 3 0 3 1 3 2 3 4 3 5 3 7 We then set the first four bytes to: 76 a5 e5 b7. We then test by computing the CRC-32/MPEG-2 of the message 76 a5 e5 b7 31 32 33 34 35 36 37 38 39 and we get 00000000, the desired result. You can adapt spoof.c to your application. Here is an example that correctly computes the CRC-32/MPEG-2 on a stream of bytes using a bit-wise algorithm: uint32_t crc32m(uint32_t crc, const unsigned char *buf, size_t len) { int k; while (len--) { crc ^= (uint32_t)(*buf++) << 24; for (k = 0; k < 8; k++) crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1; } return crc; } and with a nybble-wise algorithm using the table in the question (which is correct): uint32_t crc_table[] = { 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD }; uint32_t crc32m_nyb(uint32_t crc, const unsigned char *buf, size_t len) { while (len--) { crc ^= (uint32_t)(*buf++) << 24; crc = (crc << 4) ^ crc_table[crc >> 28]; crc = (crc << 4) ^ crc_table[crc >> 28]; } return crc; } In both cases, the initial CRC must be 0xffffffff.
Alternate approach. Assumes xorout = 0, if not, then after calculating the normal crc, then crc ^= xorout to remove it. The method here multiplies the normal crc by (1/2)%(crc polynomial) raised to (message size in bits) power % (crc polynomial) equivalent to cycling it backwards. If the message size is fixed, then the mapping is fixed and time complexity is O(1). Otherwise, it's O(log(n)). This example code uses Visual Studio and an intrinsic for carryless multiply (PCLMULQDQ), which uses XMM (128 bit) registers. Visual Studio uses __m128i type to represent integer XMM values. #include <stdio.h> #include <stdlib.h> #include <intrin.h> typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #define POLY (0x104c11db7ull) #define POLYM ( 0x04c11db7u) static uint32_t crctbl[256]; static __m128i poly; /* poly */ static __m128i invpoly; /* 2^64 / POLY */ void GenMPoly(void) /* generate __m128i poly info */ { uint64_t N = 0x100000000ull; uint64_t Q = 0; for(size_t i = 0; i < 33; i++){ Q <<= 1; if(N&0x100000000ull){ Q |= 1; N ^= POLY; } N <<= 1; } poly.m128i_u64[0] = POLY; invpoly.m128i_u64[0] = Q; } void GenTbl(void) /* generate crc table */ { uint32_t crc; uint32_t c; uint32_t i; for(c = 0; c < 0x100; c++){ crc = c<<24; for(i = 0; i < 8; i++) /* assumes twos complement */ crc = (crc<<1)^((0-(crc>>31))&POLYM); crctbl[c] = crc; } } uint32_t GenCrc(uint8_t * bfr, size_t size) /* generate crc */ { uint32_t crc = 0xffffffffu; while(size--) crc = (crc<<8)^crctbl[(crc>>24)^*bfr++]; return(crc); } /* carryless multiply modulo poly */ uint32_t MpyModPoly(uint32_t a, uint32_t b) /* (a*b)%poly */ { __m128i ma, mb, mp, mt; ma.m128i_u64[0] = a; mb.m128i_u64[0] = b; mp = _mm_clmulepi64_si128(ma, mb, 0x00); /* p[0] = a*b */ mt = _mm_clmulepi64_si128(mp, invpoly, 0x00); /* t[1] = (p[0]*((2^64)/POLY))>>64 */ mt = _mm_clmulepi64_si128(mt, poly, 0x01); /* t[0] = t[1]*POLY */ return mp.m128i_u32[0] ^ mt.m128i_u32[0]; /* ret = p[0] ^ t[0] */ } /* exponentiate by repeated squaring modulo poly */ uint32_t PowModPoly(uint32_t a, uint32_t b) /* pow(a,b)%poly */ { uint32_t prd = 0x1u; /* current product */ uint32_t sqr = a; /* current square */ while(b){ if(b&1) prd = MpyModPoly(prd, sqr); sqr = MpyModPoly(sqr, sqr); b >>= 1; } return prd; } int main() { uint32_t inv; /* 1/2 % poly, constant */ uint32_t fix; /* fix value, constant if msg size fixed */ uint32_t crc; /* crc at end of msg */ uint32_t pre; /* prefix for msg */ uint8_t msg[13] = {0x00,0x00,0x00,0x00,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39}; GenMPoly(); /* generate __m128i polys */ GenTbl(); /* generate crc table */ inv = PowModPoly(2, 0xfffffffeu); /* inv = 2^(2^32-2) % Poly = 1/2 % poly */ fix = PowModPoly(inv, 8*sizeof(msg)); /* fix value */ crc = GenCrc(msg, sizeof(msg)); /* calculate normal crc */ pre = MpyModPoly(fix, crc); /* convert to prefix */ printf("crc = %08x pre = %08x ", crc, pre); msg[0] = (uint8_t)(pre>>24); /* store prefix in msg */ msg[1] = (uint8_t)(pre>>16); msg[2] = (uint8_t)(pre>> 8); msg[3] = (uint8_t)(pre>> 0); crc = GenCrc(msg, sizeof(msg)); /* check result */ if(crc == 0) printf("passed\n"); else printf("failed\n"); return 0; }
Well, few hours after my question, someone whose name I don't remember posted an answer to my question which turned out to be correct. Somehow this answer got completely deleted, I don't know why or who did it, but I'd like to thank to this person and in the case you will see this, please post your answer again and I'll delete this one. But for other users, here's his answer that worked for me, thank you again, mysterious one (unfortunately, I can't replicate his notes and suggestions well enough, just the code itself): Edit: The original answer came from user samgak, so this stays here until he'll post his answer. The reverse CRC algorithm: uint32 revcrc32(uint16* data, uint32 len, uint32 crc) { uint32 i; data += len - 1; while(len--) { crc ^= *data--; for(i = 0; i < 16; i++) { uint32 crc1 = ((crc ^ POLY) >> 1) | 0x80000000; uint32 crc2 = crc >> 1; if(((crc1 << 1) ^ (((crc1 ^ *data) & 0x80000000) ? POLY : 0)) == crc) crc = crc1; else if(((crc2 << 1) ^ (((crc2 ^ *data) & 0x80000000) ? POLY : 0)) == crc) crc = crc2; } } return crc; } Find patch bytes: #define CRC_OF_ZERO 0xb7647d void bruteforcecrc32(uint32 targetcrc) { // compute prefixes: uint16 j; for(j = 0; j <= 0xffff; j++) { uint32 crc = revcrc32(&j, 1, targetcrc); if((crc >> 16) == (CRC_OF_ZERO >> 16)) { printf("prefixes: %04lX %04lX\n", (crc ^ CRC_OF_ZERO) & 0xffff, (uint32)j); return; } } } Usage: uint16 test[] = {0x0123, 0x4567, 0x89AB, 0xCDEF}; // prefix should be 0x0CD8236A bruteforcecrc32(revcrc32(test, 4, 0L));
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.