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 func appendUint64(b []byte, x uint64) []byte {
136 a := [8]byte{
137 byte(x >> 56),
138 byte(x >> 48),
139 byte(x >> 40),
140 byte(x >> 32),
141 byte(x >> 24),
142 byte(x >> 16),
143 byte(x >> 8),
144 byte(x),
145 }
146 return append(b, a[:]...)
147 }
148
149 func readUint64(b []byte) uint64 {
150 _ = b[7]
151 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
152 uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
153 }
154
155 func update(crc uint64, tab *Table, p []byte) uint64 {
156 buildSlicing8TablesOnce()
157 crc = ^crc
158
159 for len(p) >= 64 {
160 var helperTable *[8]Table
161 if *tab == slicing8TableECMA[0] {
162 helperTable = slicing8TableECMA
163 } else if *tab == slicing8TableISO[0] {
164 helperTable = slicing8TableISO
165
166 } else if len(p) > 16384 {
167 helperTable = makeSlicingBy8Table(tab)
168 } else {
169 break
170 }
171
172 for len(p) > 8 {
173 crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 |
174 uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
175 crc = helperTable[7][crc&0xff] ^
176 helperTable[6][(crc>>8)&0xff] ^
177 helperTable[5][(crc>>16)&0xff] ^
178 helperTable[4][(crc>>24)&0xff] ^
179 helperTable[3][(crc>>32)&0xff] ^
180 helperTable[2][(crc>>40)&0xff] ^
181 helperTable[1][(crc>>48)&0xff] ^
182 helperTable[0][crc>>56]
183 p = p[8:]
184 }
185 }
186
187 for _, v := range p {
188 crc = tab[byte(crc)^v] ^ (crc >> 8)
189 }
190 return ^crc
191 }
192
193
194 func Update(crc uint64, tab *Table, p []byte) uint64 {
195 return update(crc, tab, p)
196 }
197
198 func (d *digest) Write(p []byte) (n int, err error) {
199 d.crc = update(d.crc, d.tab, p)
200 return len(p), nil
201 }
202
203 func (d *digest) Sum64() uint64 { return d.crc }
204
205 func (d *digest) Sum(in []byte) []byte {
206 s := d.Sum64()
207 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))
208 }
209
210
211
212 func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) }
213
214
215 func tableSum(t *Table) uint64 {
216 var a [2048]byte
217 b := a[:0]
218 if t != nil {
219 for _, x := range t {
220 b = appendUint64(b, x)
221 }
222 }
223 return Checksum(b, MakeTable(ISO))
224 }
225
View as plain text