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