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