/
crc64.go
93 lines (75 loc) · 1.87 KB
/
crc64.go
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
// 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"
"sync"
)
// Size is the of a CRC-64 checksum in bytes.
const Size = 8
// 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 := 0; i < 256; i++ {
fp := uint64(i)
for j := 0; j < 8; j++ {
fp = (fp >> 1) ^ (Empty & -(fp & 1))
}
t[i] = fp
}
return t
}
var (
tableBuildOnce sync.Once
crc64Table *Table
)
func buildTableOnce() {
tableBuildOnce.Do(buildTable)
}
func buildTable() {
crc64Table = makeTable()
}
type digest struct {
crc uint64
tab *Table
}
// 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 {
buildTableOnce()
return &digest{
crc: Empty,
tab: crc64Table,
}
}
// 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 := 0; i < len(p); i++ {
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 {
s := d.Sum64()
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))
}