1 /*
2 * Copyright (c) 2018 Workaround GmbH.
3 * Copyright (c) 2017 Intel Corporation.
4 * Copyright (c) 2017 Nordic Semiconductor ASA
5 * Copyright (c) 2015 Runtime Inc
6 * Copyright (c) 2018 Google LLC.
7 * Copyright (c) 2022 Meta
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11 /** @file
12 * @brief CRC computation function
13 */
14
15 #ifndef ZEPHYR_INCLUDE_SYS_CRC_H_
16 #define ZEPHYR_INCLUDE_SYS_CRC_H_
17
18 #include <zephyr/types.h>
19 #include <stdbool.h>
20 #include <stddef.h>
21
22 #include <zephyr/sys/__assert.h>
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 /* Initial value expected to be used at the beginning of the crc8_ccitt
29 * computation.
30 */
31 #define CRC8_CCITT_INITIAL_VALUE 0xFF
32 #define CRC8_ROHC_INITIAL_VALUE 0xFF
33
34 /* Initial value expected to be used at the beginning of the OpenPGP CRC-24 computation. */
35 #define CRC24_PGP_INITIAL_VALUE 0x00B704CEU
36 /*
37 * The CRC-24 value is stored on a 32-bit value, only the 3 least significant bytes
38 * are meaningful. Use the following mask to only keep the CRC-24 value.
39 */
40 #define CRC24_FINAL_VALUE_MASK 0x00FFFFFFU
41
42 /**
43 * @defgroup checksum Checksum
44 * @ingroup os_services
45 */
46
47 /**
48 * @defgroup crc CRC
49 * @ingroup checksum
50 * @{
51 */
52
53 /**
54 * @brief CRC algorithm enumeration
55 *
56 * These values should be used with the @ref crc dispatch function.
57 */
58 enum crc_type {
59 CRC4, /**< Use @ref crc4 */
60 CRC4_TI, /**< Use @ref crc4_ti */
61 CRC7_BE, /**< Use @ref crc7_be */
62 CRC8, /**< Use @ref crc8 */
63 CRC8_CCITT, /**< Use @ref crc8_ccitt */
64 CRC8_ROHC, /**< Use @ref crc8_rohc */
65 CRC16, /**< Use @ref crc16 */
66 CRC16_ANSI, /**< Use @ref crc16_ansi */
67 CRC16_CCITT, /**< Use @ref crc16_ccitt */
68 CRC16_ITU_T, /**< Use @ref crc16_itu_t */
69 CRC24_PGP, /**< Use @ref crc24_pgp */
70 CRC32_C, /**< Use @ref crc32_c */
71 CRC32_IEEE, /**< Use @ref crc32_ieee */
72 };
73
74 /**
75 * @brief Generic function for computing a CRC-16 without input or output
76 * reflection.
77 *
78 * Compute CRC-16 by passing in the address of the input, the input length
79 * and polynomial used in addition to the initial value. This is O(n*8) where n
80 * is the length of the buffer provided. No reflection is performed.
81 *
82 * @note If you are planning to use a CRC based on poly 0x1012 the functions
83 * crc16_itu_t() is faster and thus recommended over this one.
84 *
85 * @param poly The polynomial to use omitting the leading x^16
86 * coefficient
87 * @param seed Initial value for the CRC computation
88 * @param src Input bytes for the computation
89 * @param len Length of the input in bytes
90 *
91 * @return The computed CRC16 value (without any XOR applied to it)
92 */
93 uint16_t crc16(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
94
95 /**
96 * @brief Generic function for computing a CRC-16 with input and output
97 * reflection.
98 *
99 * Compute CRC-16 by passing in the address of the input, the input length
100 * and polynomial used in addition to the initial value. This is O(n*8) where n
101 * is the length of the buffer provided. Both input and output are reflected.
102 *
103 * @note If you are planning to use a CRC based on poly 0x1012 the function
104 * crc16_ccitt() is faster and thus recommended over this one.
105 *
106 * The following checksums can, among others, be calculated by this function,
107 * depending on the value provided for the initial seed and the value the final
108 * calculated CRC is XORed with:
109 *
110 * - CRC-16/ANSI, CRC-16/MODBUS, CRC-16/USB, CRC-16/IBM
111 * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-modbus
112 * poly: 0x8005 (0xA001) initial seed: 0xffff, xor output: 0x0000
113 *
114 * @param poly The polynomial to use omitting the leading x^16
115 * coefficient. Important: please reflect the poly. For example,
116 * use 0xA001 instead of 0x8005 for CRC-16-MODBUS.
117 * @param seed Initial value for the CRC computation
118 * @param src Input bytes for the computation
119 * @param len Length of the input in bytes
120 *
121 * @return The computed CRC16 value (without any XOR applied to it)
122 */
123 uint16_t crc16_reflect(uint16_t poly, uint16_t seed, const uint8_t *src, size_t len);
124 /**
125 * @brief Generic function for computing CRC 8
126 *
127 * Compute CRC 8 by passing in the address of the input, the input length
128 * and polynomial used in addition to the initial value.
129 *
130 * @param src Input bytes for the computation
131 * @param len Length of the input in bytes
132 * @param polynomial The polynomial to use omitting the leading x^8
133 * coefficient
134 * @param initial_value Initial value for the CRC computation
135 * @param reversed Should we use reflected/reversed values or not
136 *
137 * @return The computed CRC8 value
138 */
139 uint8_t crc8(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
140 bool reversed);
141
142 /**
143 * @brief Compute the checksum of a buffer with polynomial 0x1021, reflecting
144 * input and output.
145 *
146 * This function is able to calculate any CRC that uses 0x1021 as it polynomial
147 * and requires reflecting both the input and the output. It is a fast variant
148 * that runs in O(n) time, where n is the length of the input buffer.
149 *
150 * The following checksums can, among others, be calculated by this function,
151 * depending on the value provided for the initial seed and the value the final
152 * calculated CRC is XORed with:
153 *
154 * - CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/KERMIT
155 * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-kermit
156 * initial seed: 0x0000, xor output: 0x0000
157 *
158 * - CRC-16/X-25, CRC-16/IBM-SDLC, CRC-16/ISO-HDLC
159 * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-sdlc
160 * initial seed: 0xffff, xor output: 0xffff
161 *
162 * @note To calculate the CRC across non-contiguous blocks use the return
163 * value from block N-1 as the seed for block N.
164 *
165 * See ITU-T Recommendation V.41 (November 1988).
166 *
167 * @param seed Value to seed the CRC with
168 * @param src Input bytes for the computation
169 * @param len Length of the input in bytes
170 *
171 * @return The computed CRC16 value (without any XOR applied to it)
172 */
173 uint16_t crc16_ccitt(uint16_t seed, const uint8_t *src, size_t len);
174
175 /**
176 * @brief Compute the checksum of a buffer with polynomial 0x1021, no
177 * reflection of input or output.
178 *
179 * This function is able to calculate any CRC that uses 0x1021 as it polynomial
180 * and requires no reflection on both the input and the output. It is a fast
181 * variant that runs in O(n) time, where n is the length of the input buffer.
182 *
183 * The following checksums can, among others, be calculated by this function,
184 * depending on the value provided for the initial seed and the value the final
185 * calculated CRC is XORed with:
186 *
187 * - CRC-16/XMODEM, CRC-16/ACORN, CRC-16/LTE
188 * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-xmodem
189 * initial seed: 0x0000, xor output: 0x0000
190 *
191 * - CRC16/CCITT-FALSE, CRC-16/IBM-3740, CRC-16/AUTOSAR
192 * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-ibm-3740
193 * initial seed: 0xffff, xor output: 0x0000
194 *
195 * - CRC-16/GSM
196 * https://reveng.sourceforge.io/crc-catalogue/16.htm#crc.cat.crc-16-gsm
197 * initial seed: 0x0000, xor output: 0xffff
198 *
199 * @note To calculate the CRC across non-contiguous blocks use the return
200 * value from block N-1 as the seed for block N.
201 *
202 * See ITU-T Recommendation V.41 (November 1988) (MSB first).
203 *
204 * @param seed Value to seed the CRC with
205 * @param src Input bytes for the computation
206 * @param len Length of the input in bytes
207 *
208 * @return The computed CRC16 value (without any XOR applied to it)
209 */
210 uint16_t crc16_itu_t(uint16_t seed, const uint8_t *src, size_t len);
211
212 /**
213 * @brief Compute the ANSI (or Modbus) variant of CRC-16
214 *
215 * The ANSI variant of CRC-16 uses 0x8005 (0xA001 reflected) as its polynomial
216 * with the initial * value set to 0xffff.
217 *
218 * @param src Input bytes for the computation
219 * @param len Length of the input in bytes
220 *
221 * @return The computed CRC16 value
222 */
crc16_ansi(const uint8_t * src,size_t len)223 static inline uint16_t crc16_ansi(const uint8_t *src, size_t len)
224 {
225 return crc16_reflect(0xA001, 0xffff, src, len);
226 }
227
228 /**
229 * @brief Generate IEEE conform CRC32 checksum.
230 *
231 * @param data Pointer to data on which the CRC should be calculated.
232 * @param len Data length.
233 *
234 * @return CRC32 value.
235 *
236 */
237 uint32_t crc32_ieee(const uint8_t *data, size_t len);
238
239 /**
240 * @brief Update an IEEE conforming CRC32 checksum.
241 *
242 * @param crc CRC32 checksum that needs to be updated.
243 * @param data Pointer to data on which the CRC should be calculated.
244 * @param len Data length.
245 *
246 * @return CRC32 value.
247 *
248 */
249 uint32_t crc32_ieee_update(uint32_t crc, const uint8_t *data, size_t len);
250
251 /**
252 * @brief Calculate CRC32C (Castagnoli) checksum.
253 *
254 * @param crc CRC32C checksum that needs to be updated.
255 * @param data Pointer to data on which the CRC should be calculated.
256 * @param len Data length.
257 * @param first_pkt Whether this is the first packet in the stream.
258 * @param last_pkt Whether this is the last packet in the stream.
259 *
260 * @return CRC32 value.
261 *
262 */
263 uint32_t crc32_c(uint32_t crc, const uint8_t *data,
264 size_t len, bool first_pkt, bool last_pkt);
265
266 /**
267 * @brief Compute CCITT variant of CRC 8
268 *
269 * Normal CCITT variant of CRC 8 is using 0x07.
270 *
271 * @param initial_value Initial value for the CRC computation
272 * @param buf Input bytes for the computation
273 * @param len Length of the input in bytes
274 *
275 * @return The computed CRC8 value
276 */
277 uint8_t crc8_ccitt(uint8_t initial_value, const void *buf, size_t len);
278
279 /**
280 * @brief Compute ROHC variant of CRC 8
281 *
282 * ROHC (Robust Header Compression) variant of CRC 8.
283 * Uses 0x07 as the polynomial with reflection.
284 *
285 * @param initial_value Initial value for the CRC computation
286 * @param buf Input bytes for the computation
287 * @param len Length of the input in bytes
288 *
289 * @return The computed CRC8 value
290 */
291 uint8_t crc8_rohc(uint8_t initial_value, const void *buf, size_t len);
292
293 /**
294 * @brief Compute the CRC-7 checksum of a buffer.
295 *
296 * See JESD84-A441. Used by the MMC protocol. Uses 0x09 as the
297 * polynomial with no reflection. The CRC is left
298 * justified, so bit 7 of the result is bit 6 of the CRC.
299 *
300 * @param seed Value to seed the CRC with
301 * @param src Input bytes for the computation
302 * @param len Length of the input in bytes
303 *
304 * @return The computed CRC7 value
305 */
306 uint8_t crc7_be(uint8_t seed, const uint8_t *src, size_t len);
307
308 /**
309 * @brief Compute the CRC-4 checksum of a buffer.
310 *
311 * Used by the TMAG5170 sensor. Uses 0x03 as the
312 * polynomial with no reflection. 4 most significant
313 * bits of the CRC result will be set to zero.
314 *
315 * @param seed Value to seed the CRC with
316 * @param src Input bytes for the computation
317 * @param len Length of the input in bytes
318 *
319 * @return The computed CRC4 value
320 */
321 uint8_t crc4_ti(uint8_t seed, const uint8_t *src, size_t len);
322
323 /**
324 * @brief Generic function for computing CRC 4
325 *
326 * Compute CRC 4 by passing in the address of the input, the input length
327 * and polynomial used in addition to the initial value. The input buffer
328 * must be aligned to a whole byte. It is guaranteed that 4 most significant
329 * bits of the result will be set to zero.
330 *
331 * @param src Input bytes for the computation
332 * @param len Length of the input in bytes
333 * @param polynomial The polynomial to use omitting the leading x^4
334 * coefficient
335 * @param initial_value Initial value for the CRC computation
336 * @param reversed Should we use reflected/reversed values or not
337 *
338 * @return The computed CRC4 value
339 */
340 uint8_t crc4(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value,
341 bool reversed);
342
343 /**
344 * @brief Generate an OpenPGP CRC-24 checksum as defined in RFC 4880 section 6.1.
345 *
346 * @param data A pointer to the data on which the CRC will be calculated.
347 * @param len Data length in bytes.
348 *
349 * @return The CRC-24 value.
350 */
351 uint32_t crc24_pgp(const uint8_t *data, size_t len);
352
353 /**
354 * @brief Update an OpenPGP CRC-24 checksum.
355 *
356 * @param crc The CRC-24 checksum that needs to be updated. The full 32-bit value of the CRC needs
357 * to be used between calls, do not mask the value to keep only the last 24 bits.
358 * @param data A pointer to the data on which the CRC will be calculated.
359 * @param len Data length in bytes.
360 *
361 * @return The CRC-24 value. When the last buffer of data has been processed, mask the value
362 * with CRC24_FINAL_VALUE_MASK to keep only the meaningful 24 bits of the CRC result.
363 */
364 uint32_t crc24_pgp_update(uint32_t crc, const uint8_t *data, size_t len);
365
366 /**
367 * @brief Compute a CRC checksum, in a generic way.
368 *
369 * This is a dispatch function that calls the individual CRC routine
370 * determined by @p type.
371 *
372 * For 7, 8, 16 and 24-bit CRCs, the relevant @p seed and @p poly values should
373 * be passed in via the least-significant byte(s).
374 *
375 * Similarly, for 7, 8, 16 and 24-bit CRCs, the relevant result is stored in the
376 * least-significant byte(s) of the returned value.
377 *
378 * @param type CRC algorithm to use.
379 * @param src Input bytes for the computation
380 * @param len Length of the input in bytes
381 * @param seed Value to seed the CRC with
382 * @param poly The polynomial to use omitting the leading coefficient
383 * @param reflect Should we use reflected/reversed values or not
384 * @param first Whether this is the first packet in the stream.
385 * @param last Whether this is the last packet in the stream.
386 * @return uint32_t the computed CRC value
387 */
crc_by_type(enum crc_type type,const uint8_t * src,size_t len,uint32_t seed,uint32_t poly,bool reflect,bool first,bool last)388 static inline uint32_t crc_by_type(enum crc_type type, const uint8_t *src, size_t len,
389 uint32_t seed, uint32_t poly, bool reflect, bool first,
390 bool last)
391 {
392 switch (type) {
393 case CRC4:
394 return crc4(src, len, poly, seed, reflect);
395 case CRC4_TI:
396 return crc4_ti(seed, src, len);
397 case CRC7_BE:
398 return crc7_be(seed, src, len);
399 case CRC8:
400 return crc8(src, len, poly, seed, reflect);
401 case CRC8_CCITT:
402 return crc8_ccitt(seed, src, len);
403 case CRC8_ROHC:
404 return crc8_rohc(seed, src, len);
405 case CRC16:
406 if (reflect) {
407 return crc16_reflect(poly, seed, src, len);
408 } else {
409 return crc16(poly, seed, src, len);
410 }
411 case CRC16_ANSI:
412 return crc16_ansi(src, len);
413 case CRC16_CCITT:
414 return crc16_ccitt(seed, src, len);
415 case CRC16_ITU_T:
416 return crc16_itu_t(seed, src, len);
417 case CRC24_PGP: {
418 uint32_t crc = crc24_pgp_update(seed, src, len);
419
420 if (last)
421 crc &= CRC24_FINAL_VALUE_MASK;
422 return crc;
423 }
424 case CRC32_C:
425 return crc32_c(seed, src, len, first, last);
426 case CRC32_IEEE:
427 return crc32_ieee_update(seed, src, len);
428 default:
429 break;
430 }
431
432 __ASSERT_NO_MSG(false);
433 return -1;
434 }
435
436 /**
437 * @}
438 */
439
440 #ifdef __cplusplus
441 }
442 #endif
443
444 #endif
445