blob: 27e34496f4d98a71427f362b8d00cd198d5cbf9f [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/silicon_creator/lib/crc32.h"
#include <stdbool.h>
#include "sw/device/lib/base/memory.h"
enum {
/**
* CRC32 polynomial.
*/
kCrc32Poly = 0xedb88320,
};
void crc32_init(uint32_t *ctx) { *ctx = UINT32_MAX; }
/**
* Computes the CRC32 of a buffer as expected by Python's `zlib.crc32()`. The
* implementation below is basically a simplified, i.e. byte-by-byte and without
* a lookup table, version of zlib's crc32, which also matches IEEE 802.3
* CRC-32. See
* https://github.com/madler/zlib/blob/2fa463bacfff79181df1a5270fb67cc679a53e71/crc32.c,
* lines 111-112 and 276-279.
*/
void crc32_add8(uint32_t *ctx, uint8_t byte) {
*ctx ^= byte;
for (size_t i = 0; i < 8; ++i) {
bool lsb = *ctx & 1;
*ctx >>= 1;
if (lsb) {
*ctx ^= kCrc32Poly;
}
}
}
void crc32_add32(uint32_t *ctx, uint32_t word) {
char *bytes = (char *)&word;
for (size_t i = 0; i < sizeof(uint32_t); ++i) {
crc32_add8(ctx, bytes[i]);
}
}
void crc32_add(uint32_t *ctx, const void *buf, size_t len) {
const char *data = buf;
// Unaligned head.
for (; len > 0 && (uintptr_t)data & 0x3; --len, ++data) {
crc32_add8(ctx, *data);
}
// Aligned body.
for (; len >= sizeof(uint32_t);
len -= sizeof(uint32_t), data += sizeof(uint32_t)) {
crc32_add32(ctx, read_32(data));
}
// Unaligned tail.
for (; len > 0; --len, ++data) {
crc32_add8(ctx, *data);
}
}
uint32_t crc32_finish(const uint32_t *ctx) { return *ctx ^ UINT32_MAX; }
uint32_t crc32(const void *buf, size_t len) {
uint32_t ctx;
crc32_init(&ctx);
crc32_add(&ctx, buf, len);
return crc32_finish(&ctx);
}