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 castagnoliArchImpl bool
80 var updateCastagnoli func(crc uint32, p []byte) uint32
81 var castagnoliOnce sync.Once
82 var haveCastagnoli uint32
83
84 func castagnoliInit() {
85 castagnoliTable = simpleMakeTable(Castagnoli)
86 castagnoliArchImpl = archAvailableCastagnoli()
87
88 if castagnoliArchImpl {
89 archInitCastagnoli()
90 updateCastagnoli = archUpdateCastagnoli
91 } else {
92
93 castagnoliTable8 = slicingMakeTable(Castagnoli)
94 updateCastagnoli = func(crc uint32, p []byte) uint32 {
95 return slicingUpdate(crc, castagnoliTable8, p)
96 }
97 }
98
99 atomic.StoreUint32(&haveCastagnoli, 1)
100 }
101
102
103 var IEEETable = simpleMakeTable(IEEE)
104
105
106 var ieeeTable8 *slicing8Table
107 var ieeeArchImpl bool
108 var updateIEEE func(crc uint32, p []byte) uint32
109 var ieeeOnce sync.Once
110
111 func ieeeInit() {
112 ieeeArchImpl = archAvailableIEEE()
113
114 if ieeeArchImpl {
115 archInitIEEE()
116 updateIEEE = archUpdateIEEE
117 } else {
118
119 ieeeTable8 = slicingMakeTable(IEEE)
120 updateIEEE = func(crc uint32, p []byte) uint32 {
121 return slicingUpdate(crc, ieeeTable8, p)
122 }
123 }
124 }
125
126
127
128 func MakeTable(poly uint32) *Table {
129 switch poly {
130 case IEEE:
131 ieeeOnce.Do(ieeeInit)
132 return IEEETable
133 case Castagnoli:
134 castagnoliOnce.Do(castagnoliInit)
135 return castagnoliTable
136 }
137 return simpleMakeTable(poly)
138 }
139
140
141 type digest struct {
142 crc uint32
143 tab *Table
144 }
145
146
147
148
149
150
151 func New(tab *Table) hash.Hash32 {
152 if tab == IEEETable {
153 ieeeOnce.Do(ieeeInit)
154 }
155 return &digest{0, tab}
156 }
157
158
159
160
161
162
163 func NewIEEE() hash.Hash32 { return New(IEEETable) }
164
165 func (d *digest) Size() int { return Size }
166
167 func (d *digest) BlockSize() int { return 1 }
168
169 func (d *digest) Reset() { d.crc = 0 }
170
171 const (
172 magic = "crc\x01"
173 marshaledSize = len(magic) + 4 + 4
174 )
175
176 func (d *digest) MarshalBinary() ([]byte, error) {
177 b := make([]byte, 0, marshaledSize)
178 b = append(b, magic...)
179 b = appendUint32(b, tableSum(d.tab))
180 b = appendUint32(b, d.crc)
181 return b, nil
182 }
183
184 func (d *digest) UnmarshalBinary(b []byte) error {
185 if len(b) < len(magic) || string(b[:len(magic)]) != magic {
186 return errors.New("hash/crc32: invalid hash state identifier")
187 }
188 if len(b) != marshaledSize {
189 return errors.New("hash/crc32: invalid hash state size")
190 }
191 if tableSum(d.tab) != readUint32(b[4:]) {
192 return errors.New("hash/crc32: tables do not match")
193 }
194 d.crc = readUint32(b[8:])
195 return nil
196 }
197
198 func appendUint32(b []byte, x uint32) []byte {
199 a := [4]byte{
200 byte(x >> 24),
201 byte(x >> 16),
202 byte(x >> 8),
203 byte(x),
204 }
205 return append(b, a[:]...)
206 }
207
208 func readUint32(b []byte) uint32 {
209 _ = b[3]
210 return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
211 }
212
213
214 func Update(crc uint32, tab *Table, p []byte) uint32 {
215 switch {
216 case atomic.LoadUint32(&haveCastagnoli) != 0 && tab == castagnoliTable:
217 return updateCastagnoli(crc, p)
218 case tab == IEEETable:
219
220
221 ieeeOnce.Do(ieeeInit)
222 return updateIEEE(crc, p)
223 default:
224 return simpleUpdate(crc, tab, p)
225 }
226 }
227
228 func (d *digest) Write(p []byte) (n int, err error) {
229 switch {
230 case atomic.LoadUint32(&haveCastagnoli) != 0 && d.tab == castagnoliTable:
231 d.crc = updateCastagnoli(d.crc, p)
232 case d.tab == IEEETable:
233
234
235 d.crc = updateIEEE(d.crc, p)
236 default:
237 d.crc = simpleUpdate(d.crc, d.tab, p)
238 }
239 return len(p), nil
240 }
241
242 func (d *digest) Sum32() uint32 { return d.crc }
243
244 func (d *digest) Sum(in []byte) []byte {
245 s := d.Sum32()
246 return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
247 }
248
249
250
251 func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
252
253
254
255 func ChecksumIEEE(data []byte) uint32 {
256 ieeeOnce.Do(ieeeInit)
257 return updateIEEE(0, data)
258 }
259
260
261 func tableSum(t *Table) uint32 {
262 var a [1024]byte
263 b := a[:0]
264 if t != nil {
265 for _, x := range t {
266 b = appendUint32(b, x)
267 }
268 }
269 return ChecksumIEEE(b)
270 }
271
View as plain text