1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
// Package crc64 implements the Avro CRC-64 checksum.
// See https://avro.apache.org/docs/current/spec.html#schema_fingerprints for information.
package crc64
import (
"hash"
)
func init() {
buildTable()
}
// Size is the of a CRC-64 checksum in bytes.
const Size = 8
// ByteOrder denotes how integers are encoded into bytes. The ByteOrder
// interface in encoding/binary cancels some optimizations, so use a more
// direct implementation.
type ByteOrder int
// ByteOrder constants.
const (
LittleEndian ByteOrder = iota
BigEndian
)
// Empty is the empty checksum.
const Empty = 0xc15d213aa4d7a795
// Table is a 256-word table representing the polynomial for efficient processing.
type Table [256]uint64
func makeTable() *Table {
t := new(Table)
for i := range 256 {
fp := uint64(i)
for range 8 {
fp = (fp >> 1) ^ (Empty & -(fp & 1))
}
t[i] = fp
}
return t
}
var crc64Table *Table
func buildTable() {
crc64Table = makeTable()
}
type digest struct {
crc uint64
tab *Table
byteOrder ByteOrder
}
// New creates a new hash.Hash64 computing the Avro CRC-64 checksum.
// Its Sum method will lay the value out in big-endian byte order.
func New() hash.Hash64 {
return newDigest(BigEndian)
}
// NewWithByteOrder creates a new hash.Hash64 computing the Avro CRC-64
// checksum. Its Sum method will lay the value out in specified byte order.
func NewWithByteOrder(byteOrder ByteOrder) hash.Hash64 {
return newDigest(byteOrder)
}
func newDigest(byteOrder ByteOrder) *digest {
return &digest{
crc: Empty,
tab: crc64Table,
byteOrder: byteOrder,
}
}
// Size returns the bytes size of the checksum.
func (d *digest) Size() int {
return Size
}
// BlockSize returns the block size of the checksum.
func (d *digest) BlockSize() int {
return 1
}
// Reset resets the hash instance.
func (d *digest) Reset() {
d.crc = Empty
}
// Write accumulatively adds the given data to the checksum.
func (d *digest) Write(p []byte) (n int, err error) {
for i := range p {
d.crc = (d.crc >> 8) ^ d.tab[(int)(byte(d.crc)^p[i])&0xff]
}
return len(p), nil
}
// Sum64 returns the checksum as a uint64.
func (d *digest) Sum64() uint64 {
return d.crc
}
// Sum returns the checksum as a byte slice, using the given byte slice.
func (d *digest) Sum(in []byte) []byte {
b := d.sumBytes()
return append(in, b[:]...)
}
// sumBytes returns the checksum as a byte array in digest byte order.
func (d *digest) sumBytes() [Size]byte {
s := d.Sum64()
switch d.byteOrder {
case LittleEndian:
return [Size]byte{
byte(s),
byte(s >> 8),
byte(s >> 16),
byte(s >> 24),
byte(s >> 32),
byte(s >> 40),
byte(s >> 48),
byte(s >> 56),
}
case BigEndian:
return [Size]byte{
byte(s >> 56),
byte(s >> 48),
byte(s >> 40),
byte(s >> 32),
byte(s >> 24),
byte(s >> 16),
byte(s >> 8),
byte(s),
}
}
panic("unknown byte order")
}
// Sum returns the CRC64 checksum of the data, in big-endian byte order.
func Sum(data []byte) [Size]byte {
return SumWithByteOrder(data, BigEndian)
}
// SumWithByteOrder returns the CRC64 checksum of the data, in specified byte
// order.
func SumWithByteOrder(data []byte, byteOrder ByteOrder) [Size]byte {
d := newDigest(byteOrder)
_, _ = d.Write(data)
return d.sumBytes()
}
|