...
1
2
3
4
5
6
7
8 package crc64
9
10 import (
11 "errors"
12 "hash"
13 "sync"
14 )
15
16
17 const Size = 8
18
19
20 const (
21
22 ISO = 0xD800000000000000
23
24
25 ECMA = 0xC96C5795D7870F42
26 )
27
28
29 type Table [256]uint64
30
31 var (
32 slicing8TablesBuildOnce sync.Once
33 slicing8TableISO *[8]Table
34 slicing8TableECMA *[8]Table
35 )
36
37 func buildSlicing8TablesOnce() {
38 slicing8TablesBuildOnce.Do(buildSlicing8Tables)
39 }
40
41 func buildSlicing8Tables() {
42 slicing8TableISO = makeSlicingBy8Table(makeTable(ISO))
43 slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA))
44 }
45
46
47
48 func MakeTable(poly uint64) *Table {
49 buildSlicing8TablesOnce()
50 switch poly {
51 case ISO:
52 return &slicing8TableISO[0]
53 case ECMA:
54 return &slicing8TableECMA[0]
55 default:
56 return makeTable(poly)
57 }
58 }
59
60 func makeTable(poly uint64) *Table {
61 t := new(Table)
62 for i := 0; i < 256; i++ {
63 crc := uint64(i)
64 for j := 0; j < 8; j++ {
65 if crc&1 == 1 {
66 crc = (crc >> 1) ^ poly
67 } else {
68 crc >>= 1
69 }
70 }
71 t[i] = crc
72 }
73 return t
74 }
75
76 func makeSlicingBy8Table(t *Table) *[8]Table {
77 var helperTable [8]Table
78 helperTable[0] = *t
79 for i := 0; i < 256; i++ {
80 crc := t[i]
81 for j := 1; j < 8; j++ {
82 crc = t[crc&0xff] ^ (crc >> 8)
83 helperTable[j][i] = crc
84 }
85 }
86 return &helperTable
87 }
88
89
90 type digest struct {
91 crc uint64
92 tab *Table
93 }
94
95
96
97
98
99
100 func New(tab *Table) hash.Hash64 { return &digest{0, tab} }
101
102 func (d *digest) Size() int { return Size }
103
104 func (d *digest) BlockSize() int { return 1 }
105
106 func (d *digest) Reset() { d.crc = 0 }
107
108 const (
109 magic = "crc\x02"
110 marshaledSize = len(magic) + 8 + 8
111 )
112
113 func (d *digest) MarshalBinary() ([]byte, error) {
114 b := make([]byte, 0, marshaledSize)
115 b = append(b, magic...)
116 b = appendUint64(b, tableSum(d.tab))
117 b = appendUint64(b, d.crc)
118 return b, nil
119 }
120
121 func (d *digest) UnmarshalBinary(b []byte) error {
122 if len(b) < len(magic) || string(b[:len(magic)]) != magic {
123 return errors.New("hash/crc64: invalid hash state identifier")
124 }
125 if len(b) != marshaledSize {
126 return errors.New("hash/crc64: invalid hash state size")
127 }
128 if tableSum(d.tab) != readUint64(b[4:]) {
129 return errors.New("hash/crc64: tables do not match")
130 }
131 d.crc = readUint64(b[12:])
132 return nil
133 }
134
135
136
137 func appendUint64(b []byte, x uint64) []byte {
138 return append(b,
139 byte(x>>56),
140 byte(x>>48),
141 byte(x>>40),
142 byte(x>>32),
143 byte(x>>24),
144 byte(x>>16),
145 byte(x>>8),
146 byte(x),
147 )
148 }
149
150
151
152 func readUint64(b []byte) uint64 {
153 _ = b[7]
154 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
155 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
156 }
157
158 func update(crc uint64, tab *Table, p []byte) uint64 {
159 buildSlicing8TablesOnce()
160 crc = ^crc
161
162 for len(p) >= 64 {
163 var helperTable *[8]Table
164 if *tab == slicing8TableECMA[0] {
165 helperTable = slicing8TableECMA
166 } else if *tab == slicing8TableISO[0] {
167 helperTable = slicing8TableISO
168
169 } else if len(p) >= 2048 {
170
171
172 helperTable = makeSlicingBy8Table(tab)
173 } else {
174 break
175 }
176
177 for len(p) > 8 {
178 crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 |
179 uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
180 crc = helperTable[7][crc&0xff] ^
181 helperTable[6][(crc>>8)&0xff] ^
182 helperTable[5][(crc>>16)&0xff] ^
183 helperTable[4][(crc>>24)&0xff] ^
184 helperTable[3][(crc>>32)&0xff] ^
185 helperTable[2][(crc>>40)&0xff] ^
186 helperTable[1][(crc>>48)&0xff] ^
187 helperTable[0][crc>>56]
188 p = p[8:]
189 }
190 }
191
192 for _, v := range p {
193 crc = tab[byte(crc)^v] ^ (crc >> 8)
194 }
195 return ^crc
196 }
197
198
199 func Update(crc uint64, tab *Table, p []byte) uint64 {
200 return update(crc, tab, p)
201 }
202
203 func (d *digest) Write(p []byte) (n int, err error) {
204 d.crc = update(d.crc, d.tab, p)
205 return len(p), nil
206 }
207
208 func (d *digest) Sum64() uint64 { return d.crc }
209
210 func (d *digest) Sum(in []byte) []byte {
211 s := d.Sum64()
212 return append(in, byte(s>>56), byte(s>>48), byte(s>>40), byte(s>>32), byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
213 }
214
215
216
217 func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) }
218
219
220 func tableSum(t *Table) uint64 {
221 var a [2048]byte
222 b := a[:0]
223 if t != nil {
224 for _, x := range t {
225 b = appendUint64(b, x)
226 }
227 }
228 return Checksum(b, MakeTable(ISO))
229 }
230
View as plain text