1
2
3
4
5
6
7
8
9
10
11
12
13 package crc32
14
15 import (
16 "errors"
17 "hash"
18 "sync"
19 "sync/atomic"
20 )
21
22
23 const Size = 4
24
25
26 const (
27
28
29 IEEE = 0xedb88320
30
31
32
33
34 Castagnoli = 0x82f63b78
35
36
37
38
39 Koopman = 0xeb31d82e
40 )
41
42
43 type Table [256]uint32
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 var castagnoliTable *Table
78 var castagnoliTable8 *slicing8Table
79 var updateCastagnoli func(crc uint32, p []byte) uint32
80 var castagnoliOnce sync.Once
81 var haveCastagnoli atomic.Bool
82
83 func castagnoliInit() {
84 castagnoliTable = simpleMakeTable(Castagnoli)
85
86 if archAvailableCastagnoli() {
87 archInitCastagnoli()
88 updateCastagnoli = archUpdateCastagnoli
89 } else {
90
91 castagnoliTable8 = slicingMakeTable(Castagnoli)
92 updateCastagnoli = func(crc uint32, p []byte) uint32 {
93 return slicingUpdate(crc, castagnoliTable8, p)
94 }
95 }
96
97 haveCastagnoli.Store(true)
98 }
99
100
101 var IEEETable = simpleMakeTable(IEEE)
102
103
104 var ieeeTable8 *slicing8Table
105 var updateIEEE func(crc uint32, p []byte) uint32
106 var ieeeOnce sync.Once
107
108 func ieeeInit() {
109 if archAvailableIEEE() {
110 archInitIEEE()
111 updateIEEE = archUpdateIEEE
112 } else {
113
114 ieeeTable8 = slicingMakeTable(IEEE)
115 updateIEEE = func(crc uint32, p []byte) uint32 {
116 return slicingUpdate(crc, ieeeTable8, p)
117 }
118 }
119 }
120
121
122
123 func MakeTable(poly uint32) *Table {
124 switch poly {
125 case IEEE:
126 ieeeOnce.Do(ieeeInit)
127 return IEEETable
128 case Castagnoli:
129 castagnoliOnce.Do(castagnoliInit)
130 return castagnoliTable
131 default:
132 return simpleMakeTable(poly)
133 }
134 }
135
136
137 type digest struct {
138 crc uint32
139 tab *Table
140 }
141
142
143
144
145
146
147 func New(tab *Table) hash.Hash32 {
148 if tab == IEEETable {
149 ieeeOnce.Do(ieeeInit)
150 }
151 return &digest{0, tab}
152 }
153
154
155
156
157
158
159 func NewIEEE() hash.Hash32 { return New(IEEETable) }
160
161 func (d *digest) Size() int { return Size }
162
163 func (d *digest) BlockSize() int { return 1 }
164
165 func (d *digest) Reset() { d.crc = 0 }
166
167 const (
168 magic = "crc\x01"
169 marshaledSize = len(magic) + 4 + 4
170 )
171
172 func (d *digest) MarshalBinary() ([]byte, error) {
173 b := make([]byte, 0, marshaledSize)
174 b = append(b, magic...)
175 b = appendUint32(b, tableSum(d.tab))
176 b = appendUint32(b, d.crc)
177 return b, nil
178 }
179
180 func (d *digest) UnmarshalBinary(b []byte) error {
181 if len(b) < len(magic) || string(b[:len(magic)]) != magic {
182 return errors.New("hash/crc32: invalid hash state identifier")
183 }
184 if len(b) != marshaledSize {
185 return errors.New("hash/crc32: invalid hash state size")
186 }
187 if tableSum(d.tab) != readUint32(b[4:]) {
188 return errors.New("hash/crc32: tables do not match")
189 }
190 d.crc = readUint32(b[8:])
191 return nil
192 }
193
194
195
196 func appendUint32(b []byte, x uint32) []byte {
197 return append(b,
198 byte(x>>24),
199 byte(x>>16),
200 byte(x>>8),
201 byte(x),
202 )
203 }
204
205
206
207 func readUint32(b []byte) uint32 {
208 _ = b[3]
209 return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
210 }
211
212 func update(crc uint32, tab *Table, p []byte, checkInitIEEE bool) uint32 {
213 switch {
214 case haveCastagnoli.Load() && tab == castagnoliTable:
215 return updateCastagnoli(crc, p)
216 case tab == IEEETable:
217 if checkInitIEEE {
218 ieeeOnce.Do(ieeeInit)
219 }
220 return updateIEEE(crc, p)
221 default:
222 return simpleUpdate(crc, tab, p)
223 }
224 }
225
226
227 func Update(crc uint32, tab *Table, p []byte) uint32 {
228
229
230 return update(crc, tab, p, true)
231 }
232
233 func (d *digest) Write(p []byte) (n int, err error) {
234
235
236 d.crc = update(d.crc, d.tab, p, false)
237 return len(p), nil
238 }
239
240 func (d *digest) Sum32() uint32 { return d.crc }
241
242 func (d *digest) Sum(in []byte) []byte {
243 s := d.Sum32()
244 return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
245 }
246
247
248
249 func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
250
251
252
253 func ChecksumIEEE(data []byte) uint32 {
254 ieeeOnce.Do(ieeeInit)
255 return updateIEEE(0, data)
256 }
257
258
259 func tableSum(t *Table) uint32 {
260 var a [1024]byte
261 b := a[:0]
262 if t != nil {
263 for _, x := range t {
264 b = appendUint32(b, x)
265 }
266 }
267 return ChecksumIEEE(b)
268 }
269
View as plain text