libclod
C library for interacting with NBTs, region files, LOD data and other things.
Loading...
Searching...
No Matches
crc.c
1#include "config.h"
2#include <clod/hash.h>
3#include <stddef.h>
4#include <stdint.h>
5
6#include "crc_tables.h"
7
8#if CLOD_HAVE_X86_64
9#include <immintrin.h>
10#endif
11
12#ifdef __GNUC__
13#define HAVE_CRC32_INTRINSIC __builtin_cpu_supports("sse4.2")
14#else
15#define HAVE_CRC32_INTRINSIC 0
16#endif
17
18CLOD_CONST
19static uint64_t gf2_mul_mod(uint64_t a, const uint64_t b, const uint64_t polynomial, const uint8_t bits) {
20 uint64_t res = 0;
21 for (uint8_t i = 0; i < bits; i++) {
22 if (b & UINT64_C(1) << i)
23 res ^= a;
24 if (a & UINT64_C(1) << (bits - 1))
25 a = a << 1 ^ polynomial;
26 else
27 a = a << 1;
28 }
29 return res & (bits == 64 ? UINT64_C(-1) : (UINT64_C(1) << bits) - 1);
30}
31
32CLOD_CONST
33static uint64_t gf2_mul_mod_reflected(uint64_t a, const uint64_t b, const uint64_t polynomial, const uint8_t bits) {
34 uint64_t res = 0;
35 for (uint8_t i = 0; i < bits; i++) {
36 if (b & UINT64_C(1) << i)
37 res ^= a;
38 if (a & 1)
39 a = a >> 1 ^ polynomial;
40 else
41 a >>= 1;
42 }
43 return res;
44}
45
46uint64_t clod_crc64_add(uint64_t crc, const void *restrict data, size_t data_len) {
47 const uint8_t *restrict bytes = data;
48 if (bytes)
49 for (size_t i = 0; i < data_len; i++)
50 crc = crc64_table[(crc >> 56) ^ bytes[i]] ^ crc << 8;
51 else
52 for (uint8_t b = 0; data_len > 0; b++, data_len >>= 1)
53 if (data_len & 1)
54 crc = gf2_mul_mod(crc, crc64_power_table[b], CRC64_NORMALISED_POLYNOMIAL, 64);
55 return crc;
56}
57
58uint32_t clod_crc32_add(uint32_t crc, const void *restrict data, size_t data_len) {
59 const uint8_t *restrict bytes = data;
60 if (bytes) {
61 #if CLOD_HAVE_X86_64
62 if (HAVE_CRC32_INTRINSIC) {
63 size_t i = 0;
64 while (((uintptr_t)data + i ) % 8 != 0 && i < data_len)
65 crc = _mm_crc32_u8(crc, bytes[i++]);
66
67 uint64_t crc64 = crc;
68 for (; i + 8 <= data_len; i += 8)
69 crc64 = _mm_crc32_u64(crc64, *(uint64_t*)((char*)data + i));
70
71 crc = (uint32_t)crc64;
72 while (i < data_len)
73 crc = _mm_crc32_u8(crc, bytes[i++]);
74
75 return crc;
76 }
77 #endif
78 for (size_t i = 0; i < data_len; i++)
79 crc = crc32_table[(crc & 0xff) ^ bytes[i]] ^ crc >> 8;
80 } else
81 for (uint8_t b = 0; data_len > 0; b++, data_len >>= 1)
82 if (data_len & 1)
83 crc = (uint32_t)gf2_mul_mod_reflected(crc, crc32_power_table[b], CRC32_NORMALISED_POLYNOMIAL, 32);
84 return crc;
85}
86
87uint32_t clod_crc24_add(uint32_t crc, const void *restrict data, size_t data_len) {
88 const uint8_t *restrict bytes = data;
89 crc = crc & 0x00FFFFFF;
90 if (bytes)
91 for (size_t i = 0; i < data_len; i++)
92 crc = (crc24_table[(crc >> 16) ^ bytes[i]] ^ crc << 8) & 0x00FFFFFF;
93 else
94 for (uint8_t b = 0; data_len > 0; b++, data_len >>= 1)
95 if (data_len & 1)
96 crc = (uint32_t)gf2_mul_mod(crc, crc24_power_table[b], CRC24_NORMALISED_POLYNOMIAL, 24);
97 return crc;
98}
99
100uint16_t clod_crc16_add(uint16_t crc, const void *restrict data, size_t data_len) {
101 const uint8_t *restrict bytes = data;
102 if (bytes)
103 for (size_t i = 0; i < data_len; i++)
104 crc = crc16_table[(crc & 0xff) ^ bytes[i]] ^ (uint16_t)(crc >> 8);
105 else
106 for (uint8_t b = 0; data_len > 0; b++, data_len >>= 1)
107 if (data_len & 1)
108 crc = (uint16_t)gf2_mul_mod_reflected(crc, crc16_power_table[b], CRC16_NORMALISED_POLYNOMIAL, 16);
109 return crc;
110}
111
112uint8_t clod_crc8_add(uint8_t crc, const void *restrict data, size_t data_len) {
113 const uint8_t *restrict bytes = data;
114 if (bytes)
115 for (size_t i = 0; i < data_len; i++)
116 crc = crc8_table[(crc & 0xff) ^ bytes[i]] ^ (uint8_t)(crc >> 8);
117 else
118 for (uint8_t b = 0; data_len > 0; b++, data_len >>= 1)
119 if (data_len & 1)
120 crc = (uint8_t)gf2_mul_mod(crc, crc8_power_table[b], CRC8_NORMALISED_POLYNOMIAL, 8);
121 return crc;
122}
uint64_t clod_crc64_add(uint64_t crc, const void *data, size_t data_len)
uint8_t clod_crc8_add(uint8_t crc, const void *data, size_t data_len)
uint32_t clod_crc24_add(uint32_t crc, const void *data, size_t data_len)
uint32_t clod_crc32_add(uint32_t crc, const void *data, size_t data_len)
uint16_t clod_crc16_add(uint16_t crc, const void *data, size_t data_len)