Botan 3.13.0
Crypto and TLS for C&
crc24.cpp
Go to the documentation of this file.
1/*
2* CRC24
3* (C) 1999-2007 Jack Lloyd
4* (C) 2017 [Ribose Inc](https://www.ribose.com). Performed by Krzysztof Kwiatkowski.
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/crc24.h>
10
11#include <botan/internal/loadstor.h>
12#include <array>
13
14namespace Botan {
15
16namespace {
17
18/*
19* The tables are computed same way as in a method proposed
20* by D. Sarwate (1988), for the OpenPGP CRC24 polynomial 0x864CFB.
21*
22* Each entry is stored with its bytes reversed, since the CRC state is
23* kept byte-reversed (see the initial value 0xCE04B7), allowing the
24* update loop to use little-endian loads and right shifts.
25*/
26consteval std::array<uint32_t, 256> crc24_sarwate_table() noexcept {
27 std::array<uint32_t, 256> table = {};
28 for(size_t i = 0; i != 256; ++i) {
29 uint32_t crc = static_cast<uint32_t>(i) << 16;
30 for(size_t j = 0; j != 8; ++j) {
31 crc = ((crc << 1) & 0xFFFFFF) ^ ((crc & 0x800000) != 0 ? 0x864CFB : 0);
32 }
33 table[i] = ((crc & 0xFF) << 16) | (crc & 0xFF00) | (crc >> 16);
34 }
35 return table;
36}
37
38/*
39* Derives the T1, T2 and T3 tables used by the Slicing-by-N algorithm:
40*
41* T1[j] = (T0[j] >> 8) ^ T0[ T0[j] & 0xFF ]
42* T2[j] = (T1[j] >> 8) ^ T0[ T1[j] & 0xFF ]
43* T3[j] = (T2[j] >> 8) ^ T0[ T2[j] & 0xFF ]
44*/
45consteval std::array<uint32_t, 256> crc24_slicing_table(const std::array<uint32_t, 256>& prev,
46 const std::array<uint32_t, 256>& t0) noexcept {
47 std::array<uint32_t, 256> table = {};
48 for(size_t i = 0; i != 256; ++i) {
49 table[i] = (prev[i] >> 8) ^ t0[prev[i] & 0xFF];
50 }
51 return table;
52}
53
54alignas(256) constexpr auto CRC24_T0 = crc24_sarwate_table();
55alignas(256) constexpr auto CRC24_T1 = crc24_slicing_table(CRC24_T0, CRC24_T0);
56alignas(256) constexpr auto CRC24_T2 = crc24_slicing_table(CRC24_T1, CRC24_T0);
57alignas(256) constexpr auto CRC24_T3 = crc24_slicing_table(CRC24_T2, CRC24_T0);
58
59inline uint32_t process8(uint32_t crc, uint8_t data) {
60 return (crc >> 8) ^ CRC24_T0[get_byte<3>(crc) ^ data];
61}
62
63inline uint32_t process32(uint32_t crc, uint32_t word) {
64 const uint32_t sum = crc ^ word;
65
66 return CRC24_T3[get_byte<3>(sum)] ^ CRC24_T2[get_byte<2>(sum)] ^ CRC24_T1[get_byte<1>(sum)] ^
67 CRC24_T0[get_byte<0>(sum)];
68}
69} // namespace
70
71std::unique_ptr<HashFunction> CRC24::copy_state() const {
72 return std::make_unique<CRC24>(*this);
73}
74
75/*
76* Update a CRC24 Checksum
77*
78* Implementation uses Slicing-by-N algorithm described in
79* "Novel Table Lookup-Based Algorithms for High-Performance
80* CRC Generation", by M.Kounavis.
81*
82* This algorithm uses the 4 look-up tables T0, T1, T2 and T3
83* computed above.
84*/
85void CRC24::add_data(std::span<const uint8_t> input) {
86 uint32_t tmp = m_crc;
87
88 // Input is word aligned if WA & input == 0
89 static const uint8_t WA = sizeof(size_t) - 1;
90
91 // Ensure input is word aligned before processing in parallel
92 for(; !input.empty() && (reinterpret_cast<uintptr_t>(input.data()) & WA) > 0; input = input.last(input.size() - 1)) {
93 tmp = process8(tmp, input.front());
94 }
95
96 while(input.size() >= 16) {
97 uint32_t d[4];
98 load_le(d, input.data(), 4);
99 tmp = process32(tmp, d[0]);
100 tmp = process32(tmp, d[1]);
101 tmp = process32(tmp, d[2]);
102 tmp = process32(tmp, d[3]);
103
104 input = input.last(input.size() - 16);
105 }
106
107 for(; !input.empty(); input = input.last(input.size() - 1)) {
108 tmp = process8(tmp, input.front());
109 }
110
111 m_crc = tmp;
112}
113
114/*
115* Finalize a CRC24 Checksum
116*/
117void CRC24::final_result(std::span<uint8_t> output) {
118 output[0] = get_byte<3>(m_crc);
119 output[1] = get_byte<2>(m_crc);
120 output[2] = get_byte<1>(m_crc);
121 clear();
122}
123
124} // namespace Botan
void clear() override
Definition crc24.h:33
std::unique_ptr< HashFunction > copy_state() const override
Definition crc24.cpp:71
constexpr uint8_t get_byte(T input)
Definition loadstor.h:79
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
The native machine word, used as the limb type for multiprecision integers.
Definition types.h:131