-
Notifications
You must be signed in to change notification settings - Fork 0
/
digest.go
129 lines (99 loc) · 2.49 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
package xxhash32
// The size of a XXHash32 hash value in bytes
const Size = 4
// The blocksize of XXHash32 hash function in bytes
const BlockSize = 16
type digest struct {
s [4]uint32
x [BlockSize]byte
nx int
len uint64
seed uint32
}
func newDigest(seed uint32) *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 in 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.Sum32()
putu32be(out[:], sum)
return
}
// Sum32 returns the 32 bits Hash value.
func (d *digest) Sum32() uint32 {
tmp := uint32(d.len)
if d.len >= 16 {
tmp += rotl(d.s[0], 1) + rotl(d.s[1], 7) + rotl(d.s[2], 12) + rotl(d.s[3], 18)
} else {
tmp += d.seed + prime[4]
}
p := 0
n := d.nx
for n := n - 4; p <= n; p += 4 {
tmp += getu32(d.x[p:]) * prime[2]
tmp = rotl(tmp, 17) * prime[3]
}
for ; p < n; p++ {
tmp += uint32(d.x[p]) * prime[4]
tmp = rotl(tmp, 11) * prime[0]
}
tmp = avalanche(tmp)
return tmp
}
func (d *digest) compress(data []byte) {
datas := bytesToUint32s(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 32bits Hash value.
func checksum(data []byte, seed uint32) uint32 {
h := newDigest(seed)
h.Write(data)
return h.Sum32()
}