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 func appendUint32(b []byte, x uint32) []byte {
195 a := [4]byte{
196 byte(x >> 24),
197 byte(x >> 16),
198 byte(x >> 8),
199 byte(x),
200 }
201 return append(b, a[:]...)
202 }
203
204 func readUint32(b []byte) uint32 {
205 _ = b[3]
206 return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
207 }
208
209 func update(crc uint32, tab *Table, p []byte, checkInitIEEE bool) uint32 {
210 switch {
211 case haveCastagnoli.Load() && tab == castagnoliTable:
212 return updateCastagnoli(crc, p)
213 case tab == IEEETable:
214 if checkInitIEEE {
215 ieeeOnce.Do(ieeeInit)
216 }
217 return updateIEEE(crc, p)
218 default:
219 return simpleUpdate(crc, tab, p)
220 }
221 }
222
223
224 func Update(crc uint32, tab *Table, p []byte) uint32 {
225
226
227 return update(crc, tab, p, true)
228 }
229
230 func (d *digest) Write(p []byte) (n int, err error) {
231
232
233 d.crc = update(d.crc, d.tab, p, false)
234 return len(p), nil
235 }
236
237 func (d *digest) Sum32() uint32 { return d.crc }
238
239 func (d *digest) Sum(in []byte) []byte {
240 s := d.Sum32()
241 return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
242 }
243
244
245
246 func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
247
248
249
250 func ChecksumIEEE(data []byte) uint32 {
251 ieeeOnce.Do(ieeeInit)
252 return updateIEEE(0, data)
253 }
254
255
256 func tableSum(t *Table) uint32 {
257 var a [1024]byte
258 b := a[:0]
259 if t != nil {
260 for _, x := range t {
261 b = appendUint32(b, x)
262 }
263 }
264 return ChecksumIEEE(b)
265 }
266
View as plain text