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 haveCastagnoli atomic.Bool
82
83 var castagnoliInitOnce = sync.OnceFunc(func() {
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
107 var ieeeInitOnce = sync.OnceFunc(func() {
108 if archAvailableIEEE() {
109 archInitIEEE()
110 updateIEEE = archUpdateIEEE
111 } else {
112
113 ieeeTable8 = slicingMakeTable(IEEE)
114 updateIEEE = func(crc uint32, p []byte) uint32 {
115 return slicingUpdate(crc, ieeeTable8, p)
116 }
117 }
118 })
119
120
121
122 func MakeTable(poly uint32) *Table {
123 switch poly {
124 case IEEE:
125 ieeeInitOnce()
126 return IEEETable
127 case Castagnoli:
128 castagnoliInitOnce()
129 return castagnoliTable
130 default:
131 return simpleMakeTable(poly)
132 }
133 }
134
135
136 type digest struct {
137 crc uint32
138 tab *Table
139 }
140
141
142
143
144
145
146 func New(tab *Table) hash.Hash32 {
147 if tab == IEEETable {
148 ieeeInitOnce()
149 }
150 return &digest{0, tab}
151 }
152
153
154
155
156
157
158 func NewIEEE() hash.Hash32 { return New(IEEETable) }
159
160 func (d *digest) Size() int { return Size }
161
162 func (d *digest) BlockSize() int { return 1 }
163
164 func (d *digest) Reset() { d.crc = 0 }
165
166 const (
167 magic = "crc\x01"
168 marshaledSize = len(magic) + 4 + 4
169 )
170
171 func (d *digest) AppendBinary(b []byte) ([]byte, error) {
172 b = append(b, magic...)
173 b = byteorder.BeAppendUint32(b, tableSum(d.tab))
174 b = byteorder.BeAppendUint32(b, d.crc)
175 return b, nil
176 }
177
178 func (d *digest) MarshalBinary() ([]byte, error) {
179 return d.AppendBinary(make([]byte, 0, marshaledSize))
180
181 }
182
183 func (d *digest) UnmarshalBinary(b []byte) error {
184 if len(b) < len(magic) || string(b[:len(magic)]) != magic {
185 return errors.New("hash/crc32: invalid hash state identifier")
186 }
187 if len(b) != marshaledSize {
188 return errors.New("hash/crc32: invalid hash state size")
189 }
190 if tableSum(d.tab) != byteorder.BeUint32(b[4:]) {
191 return errors.New("hash/crc32: tables do not match")
192 }
193 d.crc = byteorder.BeUint32(b[8:])
194 return nil
195 }
196
197 func update(crc uint32, tab *Table, p []byte, checkInitIEEE bool) uint32 {
198 switch {
199 case haveCastagnoli.Load() && tab == castagnoliTable:
200 return updateCastagnoli(crc, p)
201 case tab == IEEETable:
202 if checkInitIEEE {
203 ieeeInitOnce()
204 }
205 return updateIEEE(crc, p)
206 default:
207 return simpleUpdate(crc, tab, p)
208 }
209 }
210
211
212 func Update(crc uint32, tab *Table, p []byte) uint32 {
213
214
215 return update(crc, tab, p, true)
216 }
217
218 func (d *digest) Write(p []byte) (n int, err error) {
219
220
221 d.crc = update(d.crc, d.tab, p, false)
222 return len(p), nil
223 }
224
225 func (d *digest) Sum32() uint32 { return d.crc }
226
227 func (d *digest) Sum(in []byte) []byte {
228 s := d.Sum32()
229 return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
230 }
231
232
233
234 func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
235
236
237
238 func ChecksumIEEE(data []byte) uint32 {
239 ieeeInitOnce()
240 return updateIEEE(0, data)
241 }
242
243
244 func tableSum(t *Table) uint32 {
245 var a [1024]byte
246 b := a[:0]
247 if t != nil {
248 for _, x := range t {
249 b = byteorder.BeAppendUint32(b, x)
250 }
251 }
252 return ChecksumIEEE(b)
253 }
254
View as plain text