-
Notifications
You must be signed in to change notification settings - Fork 0
/
digest.go
144 lines (111 loc) · 2.9 KB
/
digest.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
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
package xxhash64
// The size of a XXHash64 hash value in bytes
const Size = 8
// The blocksize of XXHash64 hash function in bytes
const BlockSize = 32
type digest struct {
s [4]uint64
x [BlockSize]byte
nx int
len uint64
seed uint64
}
// newDigest returns a new digest instance.
func newDigest(seed uint64) *digest {
d := new(digest)
d.seed = seed
d.Reset()
return d
}
// Reset resets the Hash to its initial state.
func (d *digest) Reset() {
d.s[0] = d.seed + prime[0] + prime[1]
d.s[1] = d.seed + prime[1]
d.s[2] = d.seed
d.s[3] = d.seed - prime[0]
d.len = 0
d.nx = 0
}
// Size returns the number of bytes returned by Sum().
func (d *digest) Size() int {
return Size
}
// BlockSize gives the minimum number of bytes accepted by Write().
func (d *digest) BlockSize() int {
return BlockSize
}
// Write adds p bytes to the Hash.
func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
var xx int
plen := len(p)
for d.nx + plen >= BlockSize {
copy(d.x[d.nx:], p)
d.compress(d.x[:])
xx = BlockSize - d.nx
plen -= xx
p = p[xx:]
d.nx = 0
}
copy(d.x[d.nx:], p)
d.nx += plen
return
}
// Sum appends the current hash to b and returns the resulting slice.
func (d *digest) Sum(in []byte) []byte {
// Make a copy of d so that caller can keep writing and summing.
d0 := *d
sum := d0.checkSum()
return append(in, sum[:]...)
}
func (d *digest) checkSum() (out [Size]byte) {
sum := d.Sum64()
putu64be(out[:], sum)
return
}
// Sum64 returns the 64bits Hash value.
func (d *digest) Sum64() uint64 {
var tmp uint64
if d.len >= 32 {
tmp = rotl(d.s[0], 1) + rotl(d.s[1], 7) + rotl(d.s[2], 12) + rotl(d.s[3], 18)
tmp = mergeRound(tmp, d.s[0])
tmp = mergeRound(tmp, d.s[1])
tmp = mergeRound(tmp, d.s[2])
tmp = mergeRound(tmp, d.s[3])
tmp += d.len
} else {
tmp = d.seed + prime[4] + d.len
}
p := 0
n := d.nx
for n := n - 8; p <= n; p += 8 {
tmp ^= rotl(getu64(d.x[p:]) * prime[1], 31) * prime[0]
tmp = rotl(tmp, 27) * prime[0] + prime[3]
}
if p + 4 <= n {
sub := d.x[p : p+4]
tmp ^= uint64(getu32(sub)) * prime[0]
tmp = rotl(tmp, 23) * prime[1] + prime[2]
p += 4
}
for ; p < n; p++ {
tmp ^= uint64(d.x[p]) * prime[4]
tmp = rotl(tmp, 11) * prime[0]
}
tmp = avalanche(tmp)
return tmp
}
func (d *digest) compress(data []byte) {
datas := bytesToUint64s(data)
d.s[0] = round(d.s[0], datas[0])
d.s[1] = round(d.s[1], datas[1])
d.s[2] = round(d.s[2], datas[2])
d.s[3] = round(d.s[3], datas[3])
}
// checksum returns the 64bits Hash value.
func checksum(data []byte, seed uint64) uint64 {
h := newDigest(seed)
h.Write(data)
return h.Sum64()
}