-
Notifications
You must be signed in to change notification settings - Fork 330
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Since openssl does not support crc as a digest algorithm I extended our support through a new self implemented class and took the initial implementation out to it's own class. crc32 support is implemented using zlib's implementation. crc32c and crc64nvme are supported using our own implementation to generate the crc table at compiletime.
- Loading branch information
Showing
5 changed files
with
262 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Copyright (c) 2017-2025 Cloudflare, Inc. | ||
// Licensed under the Apache 2.0 license found in the LICENSE file or at: | ||
// https://opensource.org/licenses/Apache-2.0 | ||
|
||
#include "crc-impl.h" | ||
|
||
#include <array> | ||
#include <type_traits> | ||
|
||
namespace { | ||
constexpr auto crcTableSize = 256; | ||
template <typename T> | ||
constexpr T reverse(T value) { | ||
static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, uint64_t>::value, | ||
"value must be uint32_t or uint64_t"); | ||
if constexpr (std::is_same<T, uint32_t>::value) { | ||
value = ((value & 0xaaaaaaaa) >> 1) | ((value & 0x55555555) << 1); | ||
value = ((value & 0xcccccccc) >> 2) | ((value & 0x33333333) << 2); | ||
value = ((value & 0xf0f0f0f0) >> 4) | ((value & 0x0f0f0f0f) << 4); | ||
value = ((value & 0xff00ff00) >> 8) | ((value & 0x00ff00ff) << 8); | ||
value = (value >> 16) | (value << 16); | ||
return value; | ||
} else { | ||
value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1) | ((value & 0x5555555555555555) << 1); | ||
value = ((value & 0xcccccccccccccccc) >> 2) | ((value & 0x3333333333333333) << 2); | ||
value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4) | ((value & 0x0f0f0f0f0f0f0f0f) << 4); | ||
value = ((value & 0xff00ff00ff00ff00) >> 8) | ((value & 0x00ff00ff00ff00ff) << 8); | ||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16); | ||
value = (value >> 32) | (value << 32); | ||
return value; | ||
} | ||
} | ||
|
||
template <typename T> | ||
constexpr std::array<T, crcTableSize> gen_crc_table(T polynomial, bool reflectIn, bool reflectOut) { | ||
static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, uint64_t>::value, | ||
"polynomial must be uint32_t or uint64_t"); | ||
constexpr auto numIterations = sizeof(polynomial) * 8; // number of bits in polynomial | ||
auto crcTable = std::array<T, crcTableSize>{}; | ||
|
||
for (T byte = 0u; byte < crcTableSize; ++byte) { | ||
T crc = (reflectIn ? (reverse(T(byte)) >> (numIterations - 8)) : byte); | ||
|
||
for (int i = 0; i < numIterations; ++i) { | ||
if (crc & (static_cast<T>(1) << (numIterations - 1))) { | ||
crc = (crc << 1) ^ polynomial; | ||
} else { | ||
crc <<= 1; | ||
} | ||
} | ||
|
||
crcTable[byte] = (reflectOut ? reverse(crc) : crc); | ||
} | ||
|
||
return crcTable; | ||
} | ||
|
||
// https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.cat.crc-32-iscsi | ||
constexpr auto crc32c_table = gen_crc_table(static_cast<uint32_t>(0x1edc6f41), true, true); | ||
// https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.cat.crc-64-nvme | ||
constexpr auto crc64nvme_table = | ||
gen_crc_table(static_cast<uint64_t>(0xad93d23594c93659), true, true); | ||
} // namespace | ||
|
||
uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length) { | ||
if (data == nullptr) { | ||
return 0; | ||
} | ||
crc ^= 0xffffffff; | ||
while (length--) { | ||
crc = crc32c_table[(crc ^ *data++) & 0xffL] ^ (crc >> 8); | ||
} | ||
return crc ^ 0xffffffff; | ||
} | ||
|
||
uint64_t crc64nvme(uint64_t crc, const uint8_t *data, unsigned int length) { | ||
if (data == nullptr) { | ||
return 0; | ||
} | ||
crc ^= 0xffffffffffffffff; | ||
while (length--) { | ||
crc = crc64nvme_table[(crc ^ *data++) & 0xffL] ^ (crc >> 8); | ||
} | ||
return crc ^ 0xffffffffffffffff; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// Copyright (c) 2017-2025 Cloudflare, Inc. | ||
// Licensed under the Apache 2.0 license found in the LICENSE file or at: | ||
// https://opensource.org/licenses/Apache-2.0 | ||
|
||
#pragma once | ||
#include <stdint.h> | ||
|
||
uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length); | ||
uint64_t crc64nvme(uint64_t crc, const uint8_t *data, unsigned int length); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters