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