Zorya-NEO/src/zy-neo/builtins/util_xxh64.lua

178 lines
3.9 KiB
Lua

-- i can't see "v2" without thinking of ace combat zero
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)
while #input & 31 > 0 do
if (#input < 8) then
if (#input < 4) then
for i=1, #input do
h64 = h64 ~ (input:byte() * prime5)
input = input:sub(2)
h64 = rotl64(h64, 11) * prime1
end
else
h64 = h64 ~ (string.unpack("<I4", input) * prime1)
input = input:sub(5)
h64 = rotl64(h64, 23) * prime2 + prime3
end
else
local k1 = round(0, string.unpack("<l", input))
input = input:sub(9)
h64 = h64 ~ k1
h64 = rotl64(h64, 27) * prime1 + prime4
end
end
return avalanche(h64)
end
local function endian_align(input, seed)
local l = #input
if (#input >= 32) then
local v1 = seed + prime1 + prime2
local v2 = seed + prime2 -- << It's time. >>
local v3 = seed
local v4 = seed - prime1
repeat
v1 = round(v1, string.unpack("<l", input))
input = input:sub(9)
v2 = round(v2, string.unpack("<l", input))
input = input:sub(9)
v3 = round(v3, string.unpack("<l", input))
input = input:sub(9)
v4 = round(v4, string.unpack("<l", input))
input = input:sub(9)
until #input < 32
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, -- << Too bad buddy, this twisted game needs to be reset. We'll start over from 'Zero' with this V2 and entrust the future to the next generation. >>
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 -- << What have borders ever given us? >>
self.v3 = seed
self.v4 = seed - prime1
self.buffer = ""
self.size = 0
end
function state:update(input)
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 -- << Can you see any borders from up here? >>
local v3 = self.v3
local v4 = self.v4
repeat
v1 = round(v1, string.unpack("<l", data))
data = data:sub(9)
v2 = round(v2, string.unpack("<l", data))
data = data:sub(9)
v3 = round(v3, string.unpack("<l", data))
data = data:sub(9)
v4 = round(v4, string.unpack("<l", data))
data = data:sub(9)
until #data < 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) -- << That's what V2 is for. >>
end
return {
sum = xxh64,
state = create_state
}