0

I am using the boost crc library to calculate a 32-bit crc of an 112-bit (80-bit data + 32-bit crc) bitset. For testing, I reset all 80 data bits to 0. The calculation of the crc seems to work fine, but when I append the calculated crc to the data and calculate the crc again, I get a value > 0. But I expected a crc value of exactly 0. Here is the code:

    // creating 112-bit bitset and reset all values to 0
    bitset<112> b_data;
    b_data.reset();

    // create string containing data and blank crc
    string crc_string = b_data.to_string<char,string::traits_type,string::allocator_type>();

    // calculating crc using boost library
    boost::crc_32_type crc32;
    crc32 = for_each(crc_string.begin(), crc_string.end(), crc32);
    bitset<32> b_crc(crc32());

    // writing calculated crc to the last 32-bit of the 112-bit bitset.
    for(int i = 0; i!= b_crc.size(); i++){
        b_data[i+80] = b_crc[i];
    }

    // create string containing data and calculated crc
    string crc_string_check = b_data.to_string<char,string::traits_type,string::allocator_type>();

    // calculate crc again to check if the data is correct
    boost::crc_32_type crc32_check;
    crc32_check = std::for_each(crc_string_check.begin(), crc_string_check.end(), crc32_check);

    // output the result
    cout << crc32() << endl;
    cout << crc32_check() << endl;

The output is:

    1326744236
    559431208

The output I have expected is:

    1326744236
    0

So something goes wrong, but what? Any ideas ?

Thanks in advance.

user3853511
  • 43
  • 1
  • 6
  • 1
    Don't include the CRC as part of the data you use to calculate the CRC... think of it as two fields: 80-bits of data and 32-bits of CRC... the CRC only applies to the data – Buddy Jul 15 '15 at 17:41

3 Answers3

1

Your expectation of what is "satisfactory" is not correct. A CRC has the property you expect only if it has a zero initialization and no exclusive-or of the result. However the standard CRC-32 that you requested, crc_32_type initializes the CRC register with 0xffffffff, and exclusive-ors the result with 0xffffffff.

However you will always get the same constant when you take the CRC of the message concatenated with the message's CRC (assuming that you order the bytes of the CRC correctly). That constant is 0x2144df1c for this particular CRC, and is the CRC of four zero bytes.

It is common for CRC's to be defined in this way, so that the CRC of a string of zeros is not zero. Since the initialization and exclusive-or are the same, the CRC of the empty set is conveniently zero.

What you should be doing is simply computing the CRC on the message without the CRC, and compare that to the transmitted CRC. That is what is normally done, and applies to all message hashes in general.

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • Ok, that means boost does the crc calculation in a different way than I expected. But how can I check if the transmitted data is correct ? Just calculate the data´s crc again and compare it with the received crc? – user3853511 Jul 16 '15 at 10:09
0

First, like the commenter said, donot include the CRC bits once you check the sum. I suggest making a helper function to check n bits (80, in this case).

Secondly, consider refactoring the code to be readable and expressive of the intent:

Live On Coliru

#include <iostream>
#include <string>
#include <bitset>
#include <algorithm>
#include <boost/crc.hpp>
#include <cassert>

template <size_t N>
uint32_t crc32_n(std::bitset<N> const& bs, size_t n) {
    assert(n <= N);

    std::string const s = bs.template to_string<char>();
    auto f = s.begin();

    return std::for_each(f, f+n, boost::crc_32_type{})();
}

int main() {
    std::bitset<112> b_data;

    // set some random data (above the first 32 bits that are for CRC)
    srand(time(0));
    b_data.set(rand()%80 + 32);

    auto const crc = crc32_n(b_data, 80);

    std::cout << crc                 << ":\t" << b_data << "\n";
    b_data |= crc;
    std::cout << crc32_n(b_data, 80) << ":\t" << b_data << "\n";
}

Prints e.g.

1770803766: 0000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000
1770803766: 0000000000000000000000000000000000000000000000000000000000000000000000010000000001101001100011000101001000110110

or (on another run)

2436181323: 0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000
2436181323: 0000000000000000000000000000000000000000000000000000000000000000000000100000000010010001001101010010110101001011

I would love to go on and remove the horrific to_string call but see How do I convert bitset to array of bytes/uint8?

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
0

If you're going to include the CRC in the CRC check, which in my view is the correct technique, the expected result is always zero. Not the CRC that was transmitted.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • That's a sweet point (I hadn't realized it; showing that I don't use CRCs). It would be interesting to show a working example of this. My guess is that is precisely the OP's situation. – sehe Jul 16 '15 at 00:45
  • Yes, thats what I meant. My transmitted CRC is 1326744236 and when I calculate the CRC of the data and the transmitted crc appended, I would expect 0 as the result. But the result is 559431208. – user3853511 Jul 16 '15 at 09:55
  • I found the how-to on https://en.wikipedia.org/wiki/Cyclic_redundancy_check in the computation section. – user3853511 Jul 16 '15 at 10:06
  • No, it's not always zero. See my answer. – Mark Adler Jul 16 '15 at 16:42