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
14static 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
25static 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
35enum {
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 */
51static 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
64static 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
73void crc32_init(uint32_t *ctx) { *ctx = UINT32_MAX; }
74
75void crc32_add8(uint32_t *ctx, uint8_t byte) {
76 *ctx = crc32_internal_add8(*ctx, byte);
77}
78
79void crc32_add32(uint32_t *ctx, uint32_t word) {
80 *ctx = crc32_internal_add32(*ctx, word);
81}
82
83void 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
102uint32_t crc32_finish(const uint32_t *ctx) { return *ctx ^ UINT32_MAX; }
103
104uint32_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}