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