Software APIs
crc32.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/lib/base/crc32.h"
6 
7 #include <stdbool.h>
8 
11 
12 #ifdef OT_PLATFORM_RV32
14 static uint32_t crc32_internal_add8(uint32_t ctx, uint8_t byte) {
15  ctx ^= byte;
16  asm(".option push;"
17  ".option arch, +zbr0p93;"
18  "crc32.b %0, %1;"
19  ".option pop;"
20  : "+r"(ctx));
21  return ctx;
22 }
23 
25 static uint32_t crc32_internal_add32(uint32_t ctx, uint32_t word) {
26  ctx ^= word;
27  asm(".option push;"
28  ".option arch, +zbr0p93;"
29  "crc32.w %0, %1;"
30  ".option pop;"
31  : "+r"(ctx));
32  return ctx;
33 }
34 #else
35 enum {
36  /**
37  * CRC32 polynomial.
38  */
39  kCrc32Poly = 0xedb88320,
40 };
41 
42 /**
43  * Computes the CRC32 of a buffer as expected by Python's `zlib.crc32()`. The
44  * implementation below is basically a simplified, i.e. byte-by-byte and without
45  * a lookup table, version of zlib's crc32, which also matches IEEE 802.3
46  * CRC-32. See
47  * https://github.com/madler/zlib/blob/2fa463bacfff79181df1a5270fb67cc679a53e71/crc32.c,
48  * lines 111-112 and 276-279.
49  */
51 static uint32_t crc32_internal_add8(uint32_t ctx, uint8_t byte) {
52  ctx ^= byte;
53  for (size_t i = 0; i < 8; ++i) {
54  bool lsb = ctx & 1;
55  ctx >>= 1;
56  if (lsb) {
57  ctx ^= kCrc32Poly;
58  }
59  }
60  return ctx;
61 }
62 
64 static uint32_t crc32_internal_add32(uint32_t ctx, uint32_t word) {
65  char *bytes = (char *)&word;
66  for (size_t i = 0; i < sizeof(uint32_t); ++i) {
67  ctx = crc32_internal_add8(ctx, bytes[i]);
68  }
69  return ctx;
70 }
71 #endif
72 
73 void crc32_init(uint32_t *ctx) { *ctx = UINT32_MAX; }
74 
75 void crc32_add8(uint32_t *ctx, uint8_t byte) {
76  *ctx = crc32_internal_add8(*ctx, byte);
77 }
78 
79 void crc32_add32(uint32_t *ctx, uint32_t word) {
80  *ctx = crc32_internal_add32(*ctx, word);
81 }
82 
83 void crc32_add(uint32_t *ctx, const void *buf, size_t len) {
84  const char *data = buf;
85  uint32_t state = *ctx;
86  // Unaligned head.
87  for (; len > 0 && (uintptr_t)data & 0x3; --len, ++data) {
88  state = crc32_internal_add8(state, *data);
89  }
90  // Aligned body.
91  for (; len >= sizeof(uint32_t);
92  len -= sizeof(uint32_t), data += sizeof(uint32_t)) {
93  state = crc32_internal_add32(state, read_32(data));
94  }
95  // Unaligned tail.
96  for (; len > 0; --len, ++data) {
97  state = crc32_internal_add8(state, *data);
98  }
99  *ctx = state;
100 }
101 
102 uint32_t crc32_finish(const uint32_t *ctx) { return *ctx ^ UINT32_MAX; }
103 
104 uint32_t crc32(const void *buf, size_t len) {
105  uint32_t ctx;
106  crc32_init(&ctx);
107  crc32_add(&ctx, buf, len);
108  return crc32_finish(&ctx);
109 }