#ifndef CRC_BITWISE_2019_01_11_H #define CRC_BITWISE_2019_01_11_H #include #include #include #if(__cplusplus >= 201703L) namespace al::crypto::stream::crc { #else namespace al { namespace crypto { namespace stream { namespace crc { #endif template::exact_unsigned_type Polynomial, const typename al::crypto::util::uint_type_helper::exact_unsigned_type InitValue, const typename al::crypto::util::uint_type_helper::exact_unsigned_type FinalXor = (std::numeric_limits::exact_unsigned_type>::max)(), const bool ReflectIn = false, const bool ReflectOut = false> class crc_bitwise : public al::crypto::stream::crc::crc_base::exact_unsigned_type> { private: using local_result_type = typename al::crypto::util::uint_type_helper::exact_unsigned_type; using base_class_type = al::crypto::stream::crc::crc_base; public: crc_bitwise() : my_crc(0U) { } crc_bitwise(const crc_bitwise&) = default; crc_bitwise(crc_bitwise&&) noexcept = default; ~crc_bitwise() override = default; auto operator=(const crc_bitwise&) -> crc_bitwise& = default; auto operator=(crc_bitwise&&) noexcept -> crc_bitwise& = default; auto initialize(const local_result_type custom_init) -> void { my_crc = local_result_type(custom_init << poly_shift_amount); } auto initialize() -> void override { my_crc = local_result_type(InitValue << poly_shift_amount); } auto process_data(const std::uint8_t* message, const std::size_t count) -> void override { for(std::size_t data_index = 0U; data_index < count; ++data_index) { // Obtain the next data element (and reflect it if necessary). const std::uint8_t next_data_element = detail::crc_helper<8U, reflect_in>::reflect(message[data_index]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) my_crc = local_result_type(my_crc ^ local_result_type(local_result_type(next_data_element) << data_shift_amount)); // Process the next data byte, one bit at a time. for(std::uint_fast8_t bit_index = 0U; bit_index < 8U; ++bit_index) { const bool high_bit_is_set = (local_result_type(my_crc & high_bit_value) != 0U); my_crc = local_result_type(my_crc << 1U); if(high_bit_is_set) { // Shift through the polynomial. Also left-justify the // polynomial within the width of result_type, if necessary. my_crc = local_result_type(my_crc ^ local_result_type(polynomial << poly_shift_amount)); } } } } auto finalize() -> void override { // Downshift the result to compensate for a potential // left-justification of the polynomial in the loop above. my_crc = local_result_type(my_crc >> poly_shift_amount); // Reflect the output result if necessary. my_crc = detail::crc_helper::reflect(my_crc); // Perform the final XOR on the result. my_crc = local_result_type(my_crc ^ final_xor); } AL_CRYPTO_NODISCARD auto get_result() const -> local_result_type override { return my_crc; } private: static const local_result_type polynomial = Polynomial; static const bool reflect_in = ReflectIn; static const bool reflect_out = ReflectOut; static const local_result_type final_xor = FinalXor; static const local_result_type high_bit_value = local_result_type(1ULL << (std::numeric_limits::digits - 1U)); static const std::size_t poly_shift_amount = static_cast(static_cast(std::numeric_limits::digits) - NumberOfBits); static const std::size_t data_shift_amount = static_cast(std::numeric_limits::digits - 8); local_result_type my_crc; }; #if(__cplusplus >= 201703L) } // namespace al::crypto::stream::crc #else } // namespace crc } // namespace stream } // namespace crypto } // namespace al #endif #endif // CRC_BITWISE_2019_01_11_H