-
Notifications
You must be signed in to change notification settings - Fork 0
/
xxh64.lua
183 lines (162 loc) · 3.78 KB
/
xxh64.lua
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
local prime1, prime2, prime3, prime4, prime5 = 0x9E3779B185EBCA87, 0xC2B2AE3D27D4EB4F, 0x165667B19E3779F9, 0x85EBCA77C2B2AE63, 0x27D4EB2F165667C5
local function rotl64(x, r)
return (((x) << (r)) | ((x) >> (64 - (r))))
end
local function round(acc, input)
acc = acc + (input * prime2)
acc = rotl64(acc, 31)
acc = acc * prime1
return acc
end
local function merge_round(acc, val)
val = round(0, val)
acc = acc ~ val
acc = acc * prime1 + prime4
return acc
end
local function avalanche(h64)
h64 = h64 ~ (h64 >> 33)
h64 = h64 * prime2
h64 = h64 ~ (h64 >> 29)
h64 = h64 * prime3
h64 = h64 ~ (h64 >> 32)
return h64
end
local function finalize(h64, input)
local off = 0
while (#input-off) & 31 > 0 do
if ((#input-off) < 8) then
if ((#input-off) < 4) then
for i=1, (#input-off) do
h64 = h64 ~ (input:byte(off+1) * prime5)
off = off + 1
h64 = rotl64(h64, 11) * prime1
end
else
h64 = h64 ~ (string.unpack("<I4", input, off+1) * prime1)
off = off + 4
h64 = rotl64(h64, 23) * prime2 + prime3
end
else
local k1 = round(0, string.unpack("<l", input, off+1))
off = off + 8
h64 = h64 ~ k1
h64 = rotl64(h64, 27) * prime1 + prime4
end
end
return avalanche(h64)
end
local function endian_align(input, seed)
local l = #input
local h64 = 0
if (#input >= 32) then
local v1 = seed + prime1 + prime2
local v2 = seed + prime2
local v3 = seed
local v4 = seed - prime1
local off = 1
repeat
v1 = round(v1, string.unpack("<l", input, off))
off = off + 8
v2 = round(v2, string.unpack("<l", input, off))
off = off + 8
v3 = round(v3, string.unpack("<l", input, off))
off = off + 8
v4 = round(v4, string.unpack("<l", input, off))
off = off + 8
until #input - off + 1 < 32
input = input:sub(off)
h64 = rotl64(v1, 1) + rotl64(v2, 7) + rotl64(v3, 12) + rotl64(v4, 18)
h64 = merge_round(h64, v1)
h64 = merge_round(h64, v2)
h64 = merge_round(h64, v3)
h64 = merge_round(h64, v4)
else
h64 = seed + prime5
end
h64 = h64 + l
return finalize(h64, input)
end
local function xxh64(input, seed)
return endian_align(input, seed or 0)
end
local state = {}
local function create_state(seed)
local s = {
v1 = 0,
v2 = 0,
v3 = 0,
v4 = 0,
buffer = "",
size = 0
}
setmetatable(s, {__index=state})
s:reset(seed)
return s
end
function state:reset(seed)
seed = seed or 0
self.v1 = seed + prime1 + prime2
self.v2 = seed + prime2
self.v3 = seed
self.v4 = seed - prime1
self.buffer = ""
self.size = 0
end
function state:update(input)
if #input == 0 then return end
if #input + #self.buffer < 32 then
self.size = self.size + #input
self.buffer = self.buffer .. input
return
end
self.size = self.size + #input
input = self.buffer .. input
local data_len = #input - (#input & 31)
self.buffer = input:sub(data_len+1)
local data = input:sub(1, data_len)
local v1 = self.v1
local v2 = self.v2
local v3 = self.v3
local v4 = self.v4
local off = 1
repeat
v1 = round(v1, string.unpack("<l", data, off))
off = off + 8
v2 = round(v2, string.unpack("<l", data, off))
off = off + 8
v3 = round(v3, string.unpack("<l", data, off))
off = off + 8
v4 = round(v4, string.unpack("<l", data, off))
off = off + 8
until #data - off + 1 < 32
self.v1 = v1
self.v2 = v2
self.v3 = v3
self.v4 = v4
end
function state:digest(input)
if input then
self:update(input)
end
local h64 = 0
if (self.size >= 32) then
local v1 = self.v1
local v2 = self.v2
local v3 = self.v3
local v4 = self.v4
h64 = rotl64(v1, 1) + rotl64(v2, 7) + rotl64(v3, 12) + rotl64(v4, 18)
h64 = merge_round(h64, v1)
h64 = merge_round(h64, v2)
h64 = merge_round(h64, v3)
h64 = merge_round(h64, v4)
else
h64 = self.v3 + prime5
end
h64 = h64 + self.size
return finalize(h64, self.buffer)
end
return {
sum = xxh64,
state = create_state
}