v / vlib / hash / crc32 / crc32.v
145 lines · 127 sloc · 3.77 KB · ef11575ce2f92fe4353ad9fce591499ad0889859
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4
5// This is a fairly basic crc32 implementation, with 4 variants of the crc32 algorithm, and a way
6// to create custom crc32 tables from user-provided polynomials.
7module crc32
8
9// polynomials
10pub const ieee = u32(0xedb88320)
11pub const castagnoli = u32(0x82f63b78)
12pub const koopman = u32(0xeb31d82e)
13// q is the standard CRC-32Q polynomial (MSB-first).
14pub const q = u32(0x814141ab)
15// q_reflected is the reflected (LSB-first) form of CRC-32Q polynomial.
16pub const q_reflected = u32(0xd5828281)
17
18// Named aliases for common CRC-32 variants.
19pub const crc32c = castagnoli
20pub const crc32k = koopman
21pub const crc32q = q
22pub const crc32q_reflected = q_reflected
23
24struct Crc32 {
25mut:
26 table []u32
27}
28
29// generate_table populates a 256-word table from the specified polynomial `poly`
30// to represent the polynomial for efficient processing.
31@[direct_array_access]
32fn (mut c Crc32) generate_table(poly u32) {
33 c.table = []u32{len: 256}
34 for i in 0 .. 256 {
35 mut crc := u32(i)
36 for _ in 0 .. 8 {
37 if crc & u32(1) == u32(1) {
38 crc = (crc >> 1) ^ poly
39 } else {
40 crc >>= u32(1)
41 }
42 }
43 c.table[i] = crc
44 }
45}
46
47@[direct_array_access]
48fn (c &Crc32) update32(crc u32, b []u8) u32 {
49 mut next := crc
50 for i in 0 .. b.len {
51 next = c.table[u8(next) ^ b[i]] ^ (next >> 8)
52 }
53 return next
54}
55
56// update_state updates an internal CRC state with the bytes in `b`.
57// Start from `~u32(0)` and finalize with `~state`.
58pub fn (c &Crc32) update_state(state u32, b []u8) u32 {
59 return c.update32(state, b)
60}
61
62// checksum returns the CRC-32 checksum of data `b` by using the polynomial represented by `c`'s table.
63pub fn (c &Crc32) checksum(b []u8) u32 {
64 return ~c.update_state(~u32(0), b)
65}
66
67// update returns the updated CRC-32 checksum for `b`, starting from `crc`.
68// Use `crc = 0` for a fresh checksum, or pass a previous result to continue streaming.
69pub fn (c &Crc32) update(crc u32, b []u8) u32 {
70 state := c.update_state(~crc, b)
71 return ~state
72}
73
74// new creates a `Crc32` polynomial.
75pub fn new(poly u32) &Crc32 {
76 mut c := &Crc32{}
77 c.generate_table(poly)
78 return c
79}
80
81// sum_with_poly calculates the CRC-32 checksum of `b` for the provided polynomial.
82// Built-in constants use their canonical parameter sets.
83pub fn sum_with_poly(poly u32, b []u8) u32 {
84 return match poly {
85 ieee { ieee_poly.checksum(b) }
86 crc32c { crc32c_poly.checksum(b) }
87 crc32k { crc32k_poly.checksum(b) }
88 crc32q { crc32q_sum_internal(b) }
89 crc32q_reflected { crc32q_reflected_poly.checksum(b) }
90 else { new(poly).checksum(b) }
91 }
92}
93
94const ieee_poly = new(ieee)
95const crc32c_poly = new(crc32c)
96const crc32k_poly = new(crc32k)
97const crc32q_reflected_poly = new(crc32q_reflected)
98const crc32q_table = crc32q_generate_table(q)
99
100@[direct_array_access]
101fn crc32q_generate_table(poly u32) []u32 {
102 mut table := []u32{len: 256}
103 for i in 0 .. 256 {
104 mut crc := u32(i) << 24
105 for _ in 0 .. 8 {
106 if crc & u32(0x80000000) != 0 {
107 crc = (crc << 1) ^ poly
108 } else {
109 crc <<= 1
110 }
111 }
112 table[i] = crc
113 }
114 return table
115}
116
117@[direct_array_access]
118fn crc32q_sum_internal(b []u8) u32 {
119 mut crc := u32(0)
120 for byte in b {
121 idx := u8((crc >> 24) ^ byte)
122 crc = crc32q_table[idx] ^ (crc << 8)
123 }
124 return crc
125}
126
127// sum calculates the CRC-32 checksum of `b` by using the IEEE polynomial.
128pub fn sum(b []u8) u32 {
129 return ieee_poly.checksum(b)
130}
131
132// sum_crc32c calculates the CRC-32C checksum of `b`.
133pub fn sum_crc32c(b []u8) u32 {
134 return crc32c_poly.checksum(b)
135}
136
137// sum_crc32k calculates the CRC-32K checksum of `b`.
138pub fn sum_crc32k(b []u8) u32 {
139 return crc32k_poly.checksum(b)
140}
141
142// sum_crc32q calculates the CRC-32Q checksum of `b`.
143pub fn sum_crc32q(b []u8) u32 {
144 return crc32q_sum_internal(b)
145}
146