How-To use CRC32 checksums

You want to detect whether data has been corrupted? Good old CRC32 to the rescue!

Basics

CRC32 calculates a 32 bit checksum over data; if a bit gets flipped in the data, you get a different checksum. Of course, this is not cryptographically secure, and collisions do occur – but it’s rare enough that as a checksum, CRC32 remains useful.

We define two types:

  1. liberate::checksum::crc32_checksum is platform dependent in size, but at least 32 bits long. It’s an alias for std::uint_fast_32t and should be used for calculating sums.

  2. liberate::checksum::crc32_serialize on the other hand is a 32-bit type that you can assign your calculated value to, and serialize it as only four bytes.

CRC32 basics
1#include <liberate/liberate/checksum.h>
2
3using namespace liberate::checksum;
4
5char buf1[] = { /* something */ };
6std::vector<char> buf2; // Initialize with something
7
8auto sum1 = crc32(buf1, buf1 + sizeof(buf1));
9auto sum2 = crc32(buf2.begin(), buf2.end());

You just apply the liberate::checksum::crc32() function to some range, and it calculates the sum. The only constraint is that the range’s value type is some 8 bit integer type.

Note

As an implementation detail, the entire CRC32 lookup table is calculated at compile time as a constexpr value, meaning calculation of CRC32 checksums should yield about as compact code as you can get without dipping into assembly.

No, there are no benchmarks. But if you run tests, let us know!

Polynomials

So now you have a CRC32 checksum. Ahh, but which CRC32?

Well, you can choose. CRC32 describes both an algorithm, and a polynomial to use in the algorithm, but people have used different polynomials for different purposes.

This library defaults to the “normal” polynomial, as defined by ISO3309 and the IEEE 802.3 standards, and POSIX, etc. But there are a few more as you can see in liberate::checksum::crc32_polynomials. You just add the enum value as a third parameter:

CRC32 polynomial selection
1auto sum1 = crc32(buf1, buf1 + sizeof(buf1));
2auto sum2 = crc32(buf2.begin(), buf2.end(), CRC32_CASTAGNOLI);
3assert(sum1 != sum2);

Serialization

Serialize CRC32 in 32 bits:

CRC32 serialization
1crc32_serialize tmp = sum1;
2auto used = liberate::serialization::serialize_int(out, sizeof(out), tmp);