diff --git a/api/util/crc64.hpp b/api/util/crc64.hpp new file mode 100644 index 0000000000..6802baa037 --- /dev/null +++ b/api/util/crc64.hpp @@ -0,0 +1,131 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2017 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 the "License"; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#ifndef UTIL_CRC64_HPP +#define UTIL_CRC64_HPP + +#include +#include +#include +#include + +namespace util { + +template +struct crc64 { + explicit crc64(const std::string& data) noexcept + : crc64(data.data(), data.size()) + {} + + explicit crc64(const std::vector& data) noexcept + : crc64(data.data(), data.size()) + {} + + template + explicit crc64(const std::array& data) noexcept + : crc64(data.data(), data.size()) + {} + + constexpr explicit crc64(const char* data, size_t data_len) noexcept { + crc_register_ = checksum(0, data, data_len); + } + + + static constexpr inline uint64_t checksum(uint64_t crc_accumulator, const char* data, size_t data_len) noexcept { + auto crc64_table = get_table(); + + crc_accumulator = ~crc_accumulator; + + while (data_len > 8) { + crc_accumulator ^= static_cast(data[0]) | static_cast(data[1]) << 8 | + static_cast(data[2]) << 16 | static_cast(data[3]) << 24 | + static_cast(data[4]) << 32 | static_cast(data[5]) << 40 | + static_cast(data[6]) << 48 | static_cast(data[7]) << 56; + + crc_accumulator = crc64_table[7][crc_accumulator & 0xff] ^ + crc64_table[6][(crc_accumulator >> 8) & 0xff] ^ + crc64_table[5][(crc_accumulator >> 16) & 0xff] ^ + crc64_table[4][(crc_accumulator >> 24) & 0xff] ^ + crc64_table[3][(crc_accumulator >> 32) & 0xff] ^ + crc64_table[2][(crc_accumulator >> 40) & 0xff] ^ + crc64_table[1][(crc_accumulator >> 48) & 0xff] ^ + crc64_table[0][crc_accumulator >> 56]; + + data_len -= 8; + } + + for (size_t i = 0; i < data_len; ++i) { + crc_accumulator = crc64_table[0][static_cast(crc_accumulator) ^ data[i]] ^ (crc_accumulator >> 8); + } + + return ~crc_accumulator; + } + + constexpr operator uint64_t() const noexcept + { return crc_register_; } + +private: + uint64_t crc_register_ {0}; + + using CRC64_table_t = std::array, 8>; + + static constexpr inline const CRC64_table_t get_table() noexcept { + auto crc64_itable = get_init_table(); + + CRC64_table_t crc64_table; + crc64_table[0] = crc64_itable; + + for (uint64_t i = 0; i < 256; ++i) { + auto crc_accumulator = crc64_itable[i]; + + for (uint64_t j = 1; j < 8; ++j) { + crc_accumulator = crc64_itable[crc_accumulator & 0xff] ^ (crc_accumulator >> 8); + crc64_table[j][i] = crc_accumulator; + } + } + + return crc64_table; + } + + static constexpr inline const std::array get_init_table() noexcept { + std::array data; + + for (uint64_t i {0}; i < 256; ++i) { + uint64_t crc {i}; + + for (uint64_t j {0}; j < 8; ++j) { + if (crc & 1) { + crc = (crc >> 1) ^ POLY; + } else { + crc >>= 1; + } + } + + data[i] = crc; + } + + return data; + } +}; //< struct crc64 + +using crc64_iso_checksum = crc64<0xD800000000000000>; //< Specified in ISO 3309 +using crc64_ecma_checksum = crc64<0xC96C5795D7870F42>; //< Specified in ECMA 182 + +} //< namespace util + +#endif //< UTIL_CRC64_HPP