简体   繁体   中英

C ulong array operation CRC32

i'm really rusty when it comes with C and i need to understand code made by another developer, based around CRC32. I've got a ulong array

static const ulong crc32_table[256] =
{
      0x00000000ul, 0x04c11db7ul, 0x09823b6eul, 0x0d4326d9ul,
      0x130476dcul, 0x17c56b6bul, 0x1a864db2ul, 0x1e475005ul,
      0x2608edb8ul, 0x22c9f00ful, 0x2f8ad6d6ul, 0x2b4bcb61ul,
      0x350c9b64ul, 0x31cd86d3ul, 0x3c8ea00aul, 0x384fbdbdul,
      ...
};

This array is then used in ciphering data, this way:

void CRC32(const byte *buf, uint len, const byte init[4], byte crc[4]) {
    memcpy(crc, init, 4);
    while (len--) {
        const byte * tmp = (const byte *)(crc32_table + (crc[3] ^ *buf));
        crc[3] = crc[2] ^ tmp[3];
        crc[2] = crc[1] ^ tmp[2];
        crc[1] = crc[0] ^ tmp[1];
        crc[0] = tmp[0];
        ++buf;
    }
}

What i don't understand is the line:

const byte * tmp = (const byte *)(crc32_table + (crc[3] ^ *buf));

It seems the whole array is used in addition and casted to byte (uint in fact) but i'm not used to this kind of operation.

Can someone help me?

I need to write an equivalent to the CRC32 function but in C# Would this work:

            uint[] crc = sharedkey;
            uint[] buff = new uint[] { 0x4fu, 0xaeu, 0x07u, 0x0bu, 0x68u, 0x56u, 0x34u, 0x12u };

            for(int i=0; i < len; i++)
            {
                byte[] tmp = BitConverter.GetBytes(crc32_table[(int)(crc[3] ^ buff[i])]);            

                crc[3] = crc[2] ^ tmp[3];
                crc[2] = crc[1] ^ tmp[2];
                crc[1] = crc[0] ^ tmp[1];
                crc[0] = tmp[0];
            } 

  

Let's dissect the entire function. The function is declared as follows:

void CRC32(const byte *buf, uint len, const byte init[4], byte crc[4]) 

const byte *buf - The input buffer that the CRC is being calculated for

uint len - The length of the CRC to be calculated

const byte init[4] - The initialization vector of the CRC

byte crc[4] - The output / result of the CRC calculation

We first see that crc is initialized to the initialization vector in memcpy(crc, init, 4); Then we have a loop that iterates len times. At the end of this loop, the buf pointer is incremented with ++buf .

Now to the part you are having difficulty understanding.

Each byte of buf is XOR'd with crc[3] , the result of which is used as an offset into the crc32_table . The resulting value is stored in tmp which is then used to scramble the four bytes of crc . Key factors behind this working involve crc32_table having 256 entries, and there being 256 possible values of a byte (which is the result of the operation you are trying to understand). Thus the offset index is always valid.

The remaining operations are simply XORs that further scramble crc .

UPDATE

Although I've dissected the function, the primary confusion involves a concept known as pointer arithmetic. In C, the value of an unindexed array (such as crc32_table ) is a pointer to a memory location storing data of consecutive types, based on the array type and length. For example,

Let's say we have the following array ulong crc32_table[256] at memory location 0x400000 .

Then the value of crc32_table is 0x400000 .

Furthermore, &crc32_table[0] is also 0x400000 (this translates to the address of the first entry in the crc32_table array ).

However, &crc32_table[1] is 0x400008 (if sizeof(ulong) is 8 bytes on your system)

Here is the interesting part.

crc32_table + 1 is also 0x400008 , (the same as &crc32_table[1] ).

This is known as pointer arithmetic, and it is the same concept that is used in the CRC code you provided. That code is simply calculating an offset 0-255 into an array of size 256, so each possible offset is valid and translated into an appropriate array index.

Here,

const byte * tmp = (const byte *)(crc32_table + (crc[3] ^ *buf));

with buf pointing to the next byte of the input, this xors the next input byte with the high byte of the current CRC value, and looks that up in the table. Or rather, it looks up the address to that element in the table, and casts it to a const byte * , so that the bytes can be read later. ( crc32_table + (foo) is the same as &crc32_table[foo] .)

Then, this:

crc[3] = crc[2] ^ tmp[3];
crc[2] = crc[1] ^ tmp[2];
crc[1] = crc[0] ^ tmp[1];
crc[0] = tmp[0];

shifts the value of the CRC by 8 bits (note the indexes), and xors in the value picked from the table. Here, tmp is a pointer-to-byte (probably unsigned char * ), which then points to the first byte of one of the values in the table. The accesses through tmp[0] to tmp[3] then read that byte and the following bytes of the value, individually. If ulong is unsigned long , it's at least 32 bits, or four bytes, so the accesses don't go to the following value. The byte order needs to be known to be correct for that to work, though.

I would do that using uint32_t s, instead of char arrays, but whatever. Something like this, that is, though I didn't test, it's probably wrong:

uint32_t tmp, crc = init;
while (len--) { 
    tmp = crc32_table(((crc >> 24) & 0xff) ^ *buf++);
    crc = (crc << 8) ^ tmp; 
}

Using that precalculated table is an optimization for calculating CRCs. If you look at the definitions, you'll usually see them as circuits where a single bit is shifted out from one end of a register, used to possibly flip some of the bits in the register, and an input bit shifted in at the same time. The table lookup just deals with that 8 bits at a time; the values in the table are the net bits flipped in the register when those 8 bits get shifted out.

I mark this question as answered, as there are enough informations here to solve my problem

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM