Skip to content

Instantly share code, notes, and snippets.

@MCJack123
Last active November 27, 2022 07:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MCJack123/32c56917dc61da336ec0e8ca6aae39f8 to your computer and use it in GitHub Desktop.
Save MCJack123/32c56917dc61da336ec0e8ca6aae39f8 to your computer and use it in GitHub Desktop.
Filesystem encryption program for ComputerCraft
if fs.isUnlocked then
local args = {...}
if args[1] == "lock" or (args[1] == nil and fs.isUnlocked()) then
fs.lock()
print("The filesystem is now locked.")
elseif args[1] == "unlock" or args[1] == nil then
fs.unlock()
print("The filesystem is now unlocked.")
elseif args[1] == "encrypt" then
if args[3] == nil then error("Usage: fsencrypt encrypt <infile> <outfile>") end
fs.encrypt(args[2], args[3])
print(args[2] .. " has been encrypted as " .. args[3] .. ".")
elseif args[1] == "decrypt" then
if args[3] == nil then error("Usage: fsencrypt decrypt <infile> <outfile>") end
fs.decrypt(args[2], args[3])
print(args[2] .. " has been decrypted as " .. args[3] .. ".")
elseif args[1] == "help" then
print([[
Usage:
fsencrypt
Toggles lock status.
fsencrypt lock
Locks access to encrypted files.
fsencrypt unlock
Unlocks access to encrypted files.
fsencrypt encrypt <infile> <outfile>
Encrypts a file.
fsencrypt decrypt <infile> <outfile>
Decrypts a file.
fsencrypt help
Displays this help.]])
end
return
end
local aeslua = require "aeslua"
local sha2 = require "sha2"
local expect = require("cc.expect").expect
local sha256 = sha2.sha256
local function sxor(s1, s2)
local b1 = {}
local b2 = {}
local b3 = {}
for i=1,#s1 do
b1[#b1+1] = string.byte(s1, i)
end
for i=1,#s2 do
b2[#b2+1] = string.byte(s2, i)
end
for i=1,#b1 do
b3[#b3+1] = string.char(bit32.bxor(b1[i], b2[i]))
end
return table.concat(b3)
end
local function hex2bin(str) return str:gsub("%x%x", function(s) return string.char(tonumber(s, 16)) end) end
local function pbkdf2(hm, pass, salt, it)
local u
local t
u = hex2bin(sha2.hmac(hm, pass, salt.."\1"))
t = u
for i=2,it do
u = hex2bin(sha2.hmac(hm, pass, u))
t = sxor(t, u)
end
return t
end
local function iv2bin(iv)
local retval = ""
for _,v in ipairs(iv) do retval = retval .. string.char(v) end
return retval
end
local key, salt, filetree
local orig_fs = fs
_G.fs = {getName = orig_fs.getName, getDrive = orig_fs.getDrive, getFreeSpace = orig_fs.getFreeSpace, combine = orig_fs.combine, getDir = orig_fs.getDir, isDriveRoot = orig_fs.isDriveRoot, getCapacity = orig_fs.getCapacity}
function fs.unlock(password)
math.randomseed(os.epoch("utc"))
if not password then
write("Please enter the password: ")
password = read("\7")
end
local iv
salt = ""
if orig_fs.exists("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f") then
local file = orig_fs.open("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f", "rb")
local t = file.readAll()
file.close()
salt, iv = t:sub(1, 16), {t:sub(17):byte(1, 16)}
else
for _ = 1, 16 do salt = salt .. string.char(math.random(0, 255)) end
end
key = pbkdf2(sha256, password, salt, 2500)
password = nil
filetree = {}
if orig_fs.exists("9f721fc36d10270affc7dbba9594e7665f95e0ad6d1729f5d9c0e6cc18235cf3") then
local file = orig_fs.open("9f721fc36d10270affc7dbba9594e7665f95e0ad6d1729f5d9c0e6cc18235cf3", "rb")
local str = aeslua.decrypt(key, file.readAll(), 32, aeslua.CBCMODE, iv, true)
file.close()
if str == nil then
key, salt, filetree = nil
error("Incorrect password.", 2)
end
filetree = textutils.unserialize(str)
end
end
local function saveFileTree()
if key == nil or filetree == nil then return end
local iv = {}
if orig_fs.exists("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f") then
local file = orig_fs.open("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f", "rb")
local t = file.readAll()
file.close()
iv = {t:sub(17):byte(1, 16)}
else
for i = 1, 16 do iv[i] = math.random(0, 255) end
local file = orig_fs.open("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f", "wb")
file.write(salt .. iv2bin(iv))
file.close()
end
local file = orig_fs.open("9f721fc36d10270affc7dbba9594e7665f95e0ad6d1729f5d9c0e6cc18235cf3", "wb")
file.write(aeslua.encrypt(key, textutils.serialize(filetree), 32, aeslua.CBCMODE, iv, true))
file.close()
end
function fs.isUnlocked()
return key ~= nil and salt ~= nil and filetree ~= nil
end
function fs.lock()
saveFileTree()
key, salt, filetree = nil
end
local function splitPath(p)
local retval = {}
for m in p:gmatch("[^/]+") do table.insert(retval, m) end
return retval
end
local function getFileTree(list, t)
if #list == 0 then return t
elseif type(t) ~= "table" then return nil
else
local i = table.remove(list, 1)
return getFileTree(list, t[i])
end
end
local function getFilePath(path) return getFileTree(splitPath(path), filetree) end
local function setFileTree(list, v, t)
if #list > 1 and t[list[1]] == nil then t[list[1]] = {} end
if #list == 0 then error("Critical error while writing encrypted data")
elseif #list == 1 then t[list[1]] = v
else return setFileTree(list, v, t[table.remove(list, 1)]) end
end
local function setFilePath(path, v) return setFileTree(splitPath(path), v, filetree) end
local shamatch = "^%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x$"
local function isSHA(path) return fs.combine(path, ""):match(shamatch) ~= nil or fs.combine(path, "") == ".salt" or fs.combine(path, "") == ".filetree" end
function fs.list(dir)
expect(1, dir, "string")
local ok, retval = pcall(orig_fs.list, dir)
local tree = getFilePath(dir)
if not ok and type(tree) ~= "table" then error(retval:gsub("^.-:%d: ", ""), 2) end
retval = ok and retval or {}
if type(tree) == "table" then for k in pairs(tree) do table.insert(retval, k) end end
if fs.combine(dir, "") == "" then
local keep = {}
for _,v in ipairs(retval) do if not isSHA(v) then table.insert(keep, v) end end
retval = keep
end
table.sort(retval)
return retval
end
function fs.exists(path)
expect(1, path, "string")
if isSHA(path) then return false else return orig_fs.exists(path) or getFilePath(path) ~= nil end
end
function fs.isDir(path)
expect(1, path, "string")
if isSHA(path) then return false else return orig_fs.isDir(path) or type(getFilePath(path)) == "table" end
end
function fs.isReadOnly(path)
expect(1, path, "string")
return orig_fs.isReadOnly(path) -- more necessary?
end
function fs.getSize(path)
expect(1, path, "string")
if isSHA(path) then error("/" .. fs.combine(path, "") .. ": No such file", 2) end
local ok, retval = pcall(orig_fs.getSize, path)
local tree = getFilePath(path)
if not ok and tree == nil then error(retval:gsub("^.-:%d: ", ""), 2)
elseif type(tree) == "table" then return 0
elseif ok then return retval end
local file = fs.open(path, "rb")
retval = #file.readAll()
file.close()
return retval
end
function fs.makeDir(path)
expect(1, path, "string")
if isSHA(path) then error("/" .. fs.combine(path, "") .. ": File exists", 2)
elseif filetree == nil then return orig_fs.makeDir(path)
elseif type(getFilePath(path)) == "string" then error("/" .. fs.combine(path, "") .. ": File exists", 2) end
setFilePath(path, getFilePath(path) or {})
saveFileTree()
end
function fs.move(from, to)
expect(1, from, "string")
expect(2, to, "string")
if isSHA(from) then error("/" .. fs.combine(from, "") .. ": No such file or directory", 2)
elseif isSHA(to) then error("/" .. fs.combine(to, "") .. ": Permission denied", 2)
elseif orig_fs.exists(from) or filetree == nil then return orig_fs.move(from, to)
elseif getFilePath(from) == nil then error("/" .. fs.combine(from, "") .. ": No such file or directory", 2)
elseif getFilePath(to) ~= nil then error("/" .. fs.combine(to, "") .. ": File exists", 2) end
setFilePath(to, getFilePath(from))
setFilePath(from, nil)
saveFileTree()
end
function fs.copy(from, to)
expect(1, from, "string")
expect(2, to, "string")
if isSHA(from) then error("/" .. fs.combine(from, "") .. ": No such file or directory", 2)
elseif isSHA(to) then error("/" .. fs.combine(to, "") .. ": Permission denied", 2)
elseif orig_fs.exists(from) or filetree == nil then return orig_fs.copy(from, to)
elseif getFilePath(from) == nil then error("/" .. fs.combine(from, "") .. ": No such file or directory", 2)
elseif getFilePath(to) ~= nil then error("/" .. fs.combine(to, "") .. ": File exists", 2) end
setFilePath(to, getFilePath(from))
saveFileTree()
end
function fs.delete(path)
expect(1, path, "string")
if isSHA(path) then error("/" .. fs.combine(path, "") .. ": Permission denied", 2)
elseif orig_fs.exists(path) or filetree == nil then return orig_fs.delete(path) end
setFilePath(path, nil)
saveFileTree()
end
function fs.open(path, mode)
expect(1, path, "string")
expect(2, mode, "string")
if isSHA(path) then return nil, ("/" .. fs.combine(path, "") .. (mode:sub(1, 1) ~= "w" and ": No such file" or ": Permission denied"))
elseif orig_fs.exists(path) or filetree == nil then return orig_fs.open(path, mode)
elseif ({r=1, w=1, a=1, rb=1, wb=1, ab=1})[mode] == nil then return nil, ("/" .. fs.combine(path, "") .. ": Unknown mode") end
local contents, pos = "", 1
local isBinary = mode:sub(2, 2) == "b"
local closed = false
if mode:sub(1, 1) ~= "w" then
local iv = getFilePath(path)
if type(iv) ~= "string" then return nil, ("/" .. fs.combine(path, "") .. (iv == nil and ": No such file" or ": Is a directory")) end
local file, err = orig_fs.open(sha256(fs.combine(path, "") .. iv), "rb")
if not file then return file, err end
contents = aeslua.decrypt(key, file.readAll(), 32, aeslua.CBCMODE, {iv:byte(1, 16)}, true)
file.close()
if contents == nil then return nil, "Failed to decrypt file" end
if not isBinary then
local str = ""
for _,v in utf8.codes(contents) do if v < 256 then str = str .. string.char(v) else str = str .. "?" end end
contents = str
end
end
if mode:sub(1, 1) == "a" then pos = #contents + 1 end
if mode:sub(1, 1) == "r" then return {
read = function(n)
expect(1, n, "number", "nil")
if pos > #contents then return nil
elseif closed then error("attempt to use a closed file", 2)
elseif n == nil then
pos = pos + 1
if isBinary then return contents:byte(pos-1)
else return contents:sub(pos-1, pos-1) end
else
pos = pos + n
return contents:sub(pos - n, pos - 1)
end
end,
readLine = function()
if pos > #contents then return nil elseif closed then error("attempt to use a closed file", 2) end
local retval = ""
for c in contents:sub(pos):gmatch(".") do
pos = pos + 1
if c == '\n' then break end
retval = retval .. c
end
return retval
end,
readAll = function()
if pos > #contents then return nil elseif closed then error("attempt to use a closed file", 2) end
local retval = contents:sub(pos)
pos = #contents + 1
return retval
end,
seek = isBinary and function(whence, offset)
expect(1, whence, "string", "nil")
expect(2, offset, "number", "nil")
if closed then error("attempt to use a closed file", 2) end
whence = whence or "cur"
offset = offset or 0
if whence == "set" then pos = offset + 1
elseif whence == "cur" then pos = pos + offset
elseif whence == "end" then pos = #contents - offset + 1
else error("bad argument #1 to 'seek' (invalid option '" .. whence .. "')") end
return pos - 1
end or nil,
close = function()
if closed then error("attempt to use a closed file", 2) end
closed = true
pos = #contents + 1
end
} else return {
write = function(data)
expect(1, data, "string", "number")
if closed then error("attempt to use a closed file", 2) end
if type(data) == "number" then
if isBinary then data = string.char(data) or '?'
else data = tostring(data) end
end
contents = contents:sub(1, pos-1) .. data .. contents:sub(pos + #data)
end,
writeLine = function(data)
expect(1, data, "string", "number")
if closed then error("attempt to use a closed file", 2) end
if type(data) == "number" then
if isBinary then data = string.char(data) or '?'
else data = tostring(data) end
end
data = data .. "\n"
contents = contents:sub(1, pos-1) .. data .. contents:sub(pos + #data)
end,
flush = function()
if closed then error("attempt to use a closed file", 2) end
local data = ""
if not isBinary then for c in contents:gmatch(".") do data = data .. utf8.char(c:byte()) end
else data = contents end
local iv = getFilePath(path)
if iv then iv = {iv:byte(1, 16)} else
iv = {}
for i = 1, 16 do iv[i] = math.random(0, 255) end
end
local file = orig_fs.open(sha256(fs.combine(path, "") .. iv2bin(iv)), "wb")
file.write(aeslua.encrypt(key, data, 32, aeslua.CBCMODE, iv, true))
file.close()
setFilePath(path, iv2bin(iv))
saveFileTree()
end,
seek = isBinary and function(whence, offset)
if closed then error("attempt to use a closed file", 2) end
whence = whence or "cur"
offset = offset or 0
if whence == "set" then pos = offset + 1
elseif whence == "cur" then pos = pos + offset
elseif whence == "end" then pos = #contents - offset + 1
else error("bad argument #1 to 'seek' (invalid option '" .. whence .. "')") end
return pos - 1
end or nil,
close = function()
if closed then error("attempt to use a closed file", 2) end
local data = ""
if not isBinary then for c in contents:gmatch(".") do data = data .. utf8.char(c:byte()) end
else data = contents end
local iv = getFilePath(path)
if iv then iv = {iv:byte(1, 16)} else
iv = {}
for i = 1, 16 do iv[i] = math.random(0, 255) end
end
local file = orig_fs.open(sha256(fs.combine(path, "") .. iv2bin(iv)), "wb")
file.write(aeslua.encrypt(key, data, 32, aeslua.CBCMODE, iv, true))
file.close()
setFilePath(path, iv2bin(iv))
saveFileTree()
closed = true
pos = #contents + 1
end
} end
end
local function aux_find(parts, t)
t = t or filetree
if #parts == 0 then return t elseif type(t) ~= "table" then return nil end
local parts2 = {}
for i,v in ipairs(parts) do parts2[i] = v end
local name = table.remove(parts2, 1)
local retval = {}
for k, v in pairs(t) do if k:match("^" .. name:gsub("([%%%.])", "%%%1"):gsub("%*", "%.%*") .. "$") then retval[k] = aux_find(parts2, v) end end
return retval
end
local function combineKeys(t, prefix)
prefix = prefix or ""
if t == nil then return {} end
local retval = {}
for k,v in pairs(t) do
if type(v) == "string" then table.insert(retval, prefix .. k)
else for _,w in ipairs(combineKeys(v, prefix .. k .. "/")) do table.insert(retval, w) end end
end
return retval
end
function fs.find(wildcard)
expect(1, wildcard, "string")
local retval = orig_fs.find(wildcard)
for _,v in ipairs(combineKeys(aux_find(splitPath(wildcard)))) do table.insert(retval, v) end
local keep = {}
for _,v in ipairs(retval) do if not isSHA(fs.getName(v)) then table.insert(keep, v) end end
retval = keep
table.sort(retval)
return retval
end
function fs.attributes(path)
expect(1, path, "string")
if orig_fs.exists(path) or filetree == nil then return orig_fs.attributes(path) end
local data = getFilePath(path)
local attr
if data == nil then error("/" .. fs.combine(path, "") .. ": No such file", 2)
elseif type(data) == "table" then
attr = orig_fs.attributes("9f721fc36d10270affc7dbba9594e7665f95e0ad6d1729f5d9c0e6cc18235cf3")
attr.isDir = true
attr.size = 0
else
attr = orig_fs.attributes(sha256(fs.combine(path, "") .. data))
attr.isDir = false
attr.size = fs.getSize(path)
end
return attr
end
local tEmpty = {}
function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs )
if type( sPath ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 )
end
if type( sLocation ) ~= "string" then
error( "bad argument #2 (expected string, got " .. type( sLocation ) .. ")", 2 )
end
if bIncludeFiles ~= nil and type( bIncludeFiles ) ~= "boolean" then
error( "bad argument #3 (expected boolean, got " .. type( bIncludeFiles ) .. ")", 2 )
end
if bIncludeDirs ~= nil and type( bIncludeDirs ) ~= "boolean" then
error( "bad argument #4 (expected boolean, got " .. type( bIncludeDirs ) .. ")", 2 )
end
bIncludeFiles = (bIncludeFiles ~= false)
bIncludeDirs = (bIncludeDirs ~= false)
local sDir = sLocation
local nStart = 1
local nSlash = string.find( sPath, "[/\\]", nStart )
if nSlash == 1 then
sDir = ""
nStart = 2
end
local sName
while not sName do
local nSlash = string.find( sPath, "[/\\]", nStart )
if nSlash then
local sPart = string.sub( sPath, nStart, nSlash - 1 )
sDir = fs.combine( sDir, sPart )
nStart = nSlash + 1
else
sName = string.sub( sPath, nStart )
end
end
if fs.isDir( sDir ) then
local tResults = {}
if bIncludeDirs and sPath == "" then
table.insert( tResults, "." )
end
if sDir ~= "" then
if sPath == "" then
table.insert( tResults, (bIncludeDirs and "..") or "../" )
elseif sPath == "." then
table.insert( tResults, (bIncludeDirs and ".") or "./" )
end
end
local tFiles = fs.list( sDir )
for n=1,#tFiles do
local sFile = tFiles[n]
if #sFile >= #sName and string.sub( sFile, 1, #sName ) == sName then
local bIsDir = fs.isDir( fs.combine( sDir, sFile ) )
local sResult = string.sub( sFile, #sName + 1 )
if bIsDir then
table.insert( tResults, sResult .. "/" )
if bIncludeDirs and #sResult > 0 then
table.insert( tResults, sResult )
end
else
if bIncludeFiles and #sResult > 0 then
table.insert( tResults, sResult )
end
end
end
end
return tResults
end
return tEmpty
end
function fs.encrypt(from, to)
expect(1, from, "string")
expect(2, to, "string")
if filetree == nil then error("Cannot encrypt files while locked", 2)
elseif not orig_fs.exists(from) then error("/" .. fs.combine(from, "") .. ": No such file", 2)
elseif orig_fs.isDir(from) then error("/" .. fs.combine(from, "") .. ": Is a directory", 2)
elseif getFilePath(to) ~= nil then error("/" .. fs.combine(to, "") .. ": File exists", 2) end
local iv = {}
for i = 1, 16 do iv[i] = math.random(0, 255) end
local fromfile = orig_fs.open(from, "rb")
local tofile = orig_fs.open(sha256(fs.combine(to, "") .. iv2bin(iv)), "wb")
tofile.write(aeslua.encrypt(key, fromfile.readAll(), 32, aeslua.CBCMODE, iv, true))
fromfile.close()
tofile.close()
setFilePath(to, iv2bin(iv))
saveFileTree()
end
function fs.decrypt(from, to)
expect(1, from, "string")
expect(2, to, "string")
local iv = getFilePath(from)
if filetree == nil then error("Cannot decrypt files while locked", 2)
elseif iv == nil then error("/" .. fs.combine(from, "") .. ": No such file", 2)
elseif type(iv) == "table" then error("/" .. fs.combine(from, "") .. ": Is a directory", 2)
elseif orig_fs.exists(to) then error("/" .. fs.combine(to, "") .. ": File exists", 2) end
local fromfile = orig_fs.open(sha256(fs.combine(from, "") .. iv), "rb")
local tofile = orig_fs.open(to, "wb")
tofile.write(aeslua.decrypt(key, fromfile.readAll(), 32, aeslua.CBCMODE, {iv:byte(1, 16)}, true))
fromfile.close()
tofile.close()
end
_G.io = {}
do
--- Emulates Lua's standard [io library][io].
--
-- [io]: https://www.lua.org/manual/5.1/manual.html#5.7
--
-- @module io
local type_of = _G.type
--- If we return nil then close the file, as we've reached the end.
-- We use this weird wrapper function as we wish to preserve the varargs
local function checkResult(handle, ...)
if ... == nil and handle._autoclose and not handle._closed then handle:close() end
return ...
end
--- A file handle which can be read or written to.
--
-- @type Handle
local handleMetatable
handleMetatable = {
__name = "FILE*",
__tostring = function(self)
if self._closed then
return "file (closed)"
else
local hash = tostring(self._handle):match("table: (%x+)")
return "file (" .. hash .. ")"
end
end,
__index = {
--- Close this file handle, freeing any resources it uses.
--
-- @treturn[1] true If this handle was successfully closed.
-- @treturn[2] nil If this file handle could not be closed.
-- @treturn[2] string The reason it could not be closed.
-- @throws If this handle was already closed.
close = function(self)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if handle.close then
self._closed = true
handle.close()
return true
else
return nil, "attempt to close standard stream"
end
end,
--- Flush any buffered output, forcing it to be written to the file
--
-- @throws If the handle has been closed
flush = function(self)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if handle.flush then handle.flush() end
return true
end,
lines = function(self, ...)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if not handle.read then return nil, "file is not readable" end
local args = table.pack(...)
return function()
if self._closed then error("file is already closed", 2) end
return checkResult(self, self:read(table.unpack(args, 1, args.n)))
end
end,
read = function(self, ...)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if not handle.read and not handle.readLine then return nil, "Not opened for reading" end
local n = select("#", ...)
local output = {}
for i = 1, n do
local arg = select(i, ...)
local res
if type_of(arg) == "number" then
if handle.read then res = handle.read(arg) end
elseif type_of(arg) == "string" then
local format = arg:gsub("^%*", ""):sub(1, 1)
if format == "l" then
if handle.readLine then res = handle.readLine() end
elseif format == "L" and handle.readLine then
if handle.readLine then res = handle.readLine(true) end
elseif format == "a" then
if handle.readAll then res = handle.readAll() or "" end
elseif format == "n" then
res = nil -- Skip this format as we can't really handle it
else
error("bad argument #" .. i .. " (invalid format)", 2)
end
else
error("bad argument #" .. i .. " (expected string, got " .. type_of(arg) .. ")", 2)
end
output[i] = res
if not res then break end
end
-- Default to "l" if possible
if n == 0 and handle.readLine then return handle.readLine() end
return table.unpack(output, 1, n)
end,
seek = function(self, whence, offset)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if not handle.seek then return nil, "file is not seekable" end
-- It's a tail call, so error positions are preserved
return handle.seek(whence, offset)
end,
setvbuf = function(self, mode, size) end,
--- Write one or more values to the file
--
-- @tparam string|number ... The values to write.
-- @treturn[1] Handle The current file, allowing chained calls.
-- @treturn[2] nil If the file could not be written to.
-- @treturn[2] string The error message which occurred while writing.
write = function(self, ...)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if not handle.write then return nil, "file is not writable" end
for i = 1, select("#", ...) do
local arg = select(i, ...)
expect(i, arg, "string", "number")
handle.write(arg)
end
return self
end,
},
}
local defaultInput = setmetatable({
_handle = { readLine = _G.read },
}, handleMetatable)
local defaultOutput = setmetatable({
_handle = { write = _G.write },
}, handleMetatable)
local defaultError = setmetatable({
_handle = {
write = function(...)
local oldColour
if term.isColour() then
oldColour = term.getTextColour()
term.setTextColour(colors.red)
end
_G.write(...)
if term.isColour() then term.setTextColour(oldColour) end
end,
},
}, handleMetatable)
local currentInput = defaultInput
local currentOutput = defaultOutput
--- A file handle representing the "standard input". Reading from this
-- file will prompt the user for input.
io.stdin = defaultInput
--- A file handle representing the "standard output". Writing to this
-- file will display the written text to the screen.
io.stdout = defaultOutput
--- A file handle representing the "standard error" stream.
--
-- One may use this to display error messages, writing to it will display
-- them on the terminal.
io.stderr = defaultError
--- Closes the provided file handle.
--
-- @tparam[opt] Handle file The file handle to close, defaults to the
-- current output file.
--
-- @see Handle:close
-- @see io.output
function io.close(file)
if file == nil then return currentOutput:close() end
if type_of(file) ~= "table" or getmetatable(file) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(file) .. ")", 2)
end
return file:close()
end
--- Flushes the current output file.
--
-- @see Handle:flush
-- @see io.output
function io.flush()
return currentOutput:flush()
end
--- Get or set the current input file.
--
-- @tparam[opt] Handle|string file The new input file, either as a file path or pre-existing handle.
-- @treturn Handle The current input file.
-- @throws If the provided filename cannot be opened for reading.
function io.input(file)
if type_of(file) == "string" then
local res, err = open(file, "rb")
if not res then error(err, 2) end
currentInput = res
elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then
currentInput = file
elseif file ~= nil then
error("bad fileument #1 (FILE expected, got " .. type_of(file) .. ")", 2)
end
return currentInput
end
--- Opens the given file name in read mode and returns an iterator that,
-- each time it is called, returns a new line from the file.
--
-- This can be used in a for loop to iterate over all lines of a file:
--
-- ```lua
-- for line in io.lines(filename) do print(line) end
-- ```
--
-- Once the end of the file has been reached, @{nil} will be
-- returned. The file is automatically closed.
--
-- If no file name is given, the @{io.input|current input} will be used
-- instead. In this case, the handle is not used.
--
-- @tparam[opt] string filename The name of the file to extract lines from
-- @param ... The argument to pass to @{Handle:read} for each line.
-- @treturn function():string|nil The line iterator.
-- @throws If the file cannot be opened for reading
--
-- @see Handle:lines
-- @see io.input
function io.lines(filename, ...)
expect(1, filename, "string", "nil")
if filename then
local ok, err = open(filename, "rb")
if not ok then error(err, 2) end
-- We set this magic flag to mark this file as being opened by io.lines and so should be
-- closed automatically
ok._autoclose = true
return ok:lines(...)
else
return currentInput:lines(...)
end
end
--- Open a file with the given mode, either returning a new file handle
-- or @{nil}, plus an error message.
--
-- The `mode` string can be any of the following:
-- - **"r"**: Read mode
-- - **"w"**: Write mode
-- - **"w"**: Append mode
--
-- The mode may also have a `b` at the end, which opens the file in "binary
-- mode". This allows you to read binary files, as well as seek within a file.
--
-- @tparam string filename The name of the file to open.
-- @tparam[opt] string mode The mode to open the file with. This defaults to `rb`.
-- @treturn[1] Handle The opened file.
-- @treturn[2] nil In case of an error.
-- @treturn[2] string The reason the file could not be opened.
function io.open(filename, mode)
expect(1, filename, "string")
expect(2, mode, "string", "nil")
local sMode = mode and mode:gsub("%+", "") or "rb"
local file, err = fs.open(filename, sMode)
if not file then return nil, err end
return setmetatable({ _handle = file }, handleMetatable)
end
--- Get or set the current output file.
--
-- @tparam[opt] Handle|string file The new output file, either as a file path or pre-existing handle.
-- @treturn Handle The current output file.
-- @throws If the provided filename cannot be opened for writing.
function io.output(file)
if type_of(file) == "string" then
local res, err = open(file, "wb")
if not res then error(err, 2) end
currentOutput = res
elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then
currentOutput = file
elseif file ~= nil then
error("bad argument #1 (FILE expected, got " .. type_of(file) .. ")", 2)
end
return currentOutput
end
--- Read from the currently opened input file.
--
-- This is equivalent to `io.input():read(...)`. See @{Handle:read|the
-- documentation} there for full details.
--
-- @tparam string ... The formats to read, defaulting to a whole line.
-- @treturn (string|nil)... The data read, or @{nil} if nothing can be read.
function io.read(...)
return currentInput:read(...)
end
--- Checks whether `handle` is a given file handle, and determine if it is open
-- or not.
--
-- @param obj The value to check
-- @treturn string|nil `"file"` if this is an open file, `"closed file"` if it
-- is a closed file handle, or `nil` if not a file handle.
function io.type(obj)
if type_of(obj) == "table" and getmetatable(obj) == handleMetatable then
if obj._closed then
return "closed file"
else
return "file"
end
end
return nil
end
--- Write to the currently opened output file.
--
-- This is equivalent to `io.output():write(...)`. See @{Handle:write|the
-- documentation} there for full details.
--
-- @tparam string ... The strings to write
function io.write(...)
return currentOutput:write(...)
end
end
-- Hide the upvalues of the FS library since they could cause data leakage
-- This is the most advanced hiding we're doing; more protection can be offered by other tools
if debug then
local native_getupvalue, native_setupvalue = debug.getupvalue, debug.setupvalue
local getupvalue, setupvalue
function getupvalue(func, up)
if func == getupvalue then return nil end
for _,v in pairs(fs) do if func == v then return nil end end
return native_getupvalue(func, up)
end
function setupvalue(func, up, val)
if func == setupvalue then return nil end
for _,v in pairs(fs) do if func == v then return nil end end
return native_setupvalue(func, up, val)
end
debug.getupvalue = getupvalue
debug.setupvalue = setupvalue
end
fs.unlock()
print("FSEncrypt is now loaded.\nThe filesystem is now unlocked.")
if fs.isUnlocked then local a={...}if a[1]=="lock"or a[1]==nil and fs.isUnlocked()then fs.lock()print("The filesystem is now locked.")elseif a[1]=="unlock"or a[1]==nil then fs.unlock()print("The filesystem is now unlocked.")elseif a[1]=="encrypt"then if a[3]==nil then error("Usage: fsencrypt encrypt <infile> <outfile>")end;fs.encrypt(a[2],a[3])print(a[2].." has been encrypted as "..a[3]..".")elseif a[1]=="decrypt"then if a[3]==nil then error("Usage: fsencrypt decrypt <infile> <outfile>")end;fs.decrypt(a[2],a[3])print(a[2].." has been decrypted as "..a[3]..".")elseif a[1]=="help"then print([[
Usage:
fsencrypt
Toggles lock status.
fsencrypt lock
Locks access to encrypted files.
fsencrypt unlock
Unlocks access to encrypted files.
fsencrypt encrypt <infile> <outfile>
Encrypts a file.
fsencrypt decrypt <infile> <outfile>
Decrypts a file.
fsencrypt help
Displays this help.]])end;return end;local b=(function()local function c(d)local e=setmetatable({},{__index=_ENV or getfenv()})if setfenv then setfenv(d,e)end;return d(e)or e end;local bit=c(function(_ENV,...)local f=math.floor;local g,h;h=function(i,j)return f(i%4294967296/2^j)end;g=function(i,j)return i*2^j%4294967296 end;return{bnot=bit.bnot,band=bit.band,bor=bit.bor,bxor=bit.bxor,rshift=h,lshift=g}end)local k=c(function(_ENV,...)local l=bit.bxor;local g=bit.lshift;local m=0x100;local n=0xff;local o=0x11b;local p={}local q={}local function r(s,t)return l(s,t)end;local function u(s,t)return l(s,t)end;local function v(w)if w==1 then return 1 end;local x=n-q[w]return p[x]end;local function y(s,t)if s==0 or t==0 then return 0 end;local x=q[s]+q[t]if x>=n then x=x-n end;return p[x]end;local function z(s,t)if s==0 then return 0 end;local x=q[s]-q[t]if x<0 then x=x+n end;return p[x]end;local function A()for B=1,m do print("log(",B-1,")=",q[B-1])end end;local function C()for B=1,m do print("exp(",B-1,")=",p[B-1])end end;local function D()local i=1;for B=0,n-1 do p[B]=i;q[i]=B;i=l(g(i,1),i)if i>n then i=u(i,o)end end end;D()return{add=r,sub=u,invert=v,mul=y,div=z,printLog=A,printExp=C}end)local E=c(function(_ENV,...)local l=bit.bxor;local h=bit.rshift;local F=bit.band;local g=bit.lshift;local G;local function H(I)I=l(I,h(I,4))I=l(I,h(I,2))I=l(I,h(I,1))return F(I,1)end;local function J(K,L)if L==0 then return F(K,0xff)else return F(h(K,L*8),0xff)end end;local function M(K,L)if L==0 then return F(K,0xff)else return g(F(K,0xff),L*8)end end;local function N(O,P,m)local Q={}for B=0,m-1 do Q[B+1]=M(O[P+B*4],3)+M(O[P+B*4+1],2)+M(O[P+B*4+2],1)+M(O[P+B*4+3],0)if m%10000==0 then G()end end;return Q end;local function R(Q,S,T,m)m=m or#Q;for B=0,m-1 do for U=0,3 do S[T+B*4+3-U]=J(Q[B+1],U)end;if m%10000==0 then G()end end;return S end;local function V(O)local W=""for B,I in ipairs(O)do W=W..string.format("%02x ",I)end;return W end;local function X(O)local Y={}for B=1,#O,2 do Y[#Y+1]=tonumber(O:sub(B,B+1),16)end;return Y end;local function Z(_)local type=type(_)if type=="number"then return string.format("%08x",_)elseif type=="table"then return V(_)elseif type=="string"then local O={string.byte(_,1,#_)}return V(O)else return _ end end;local function a0(_)local a1=#_;local a2=math.random(0,255)local a3=math.random(0,255)local a4=string.char(a2,a3,a2,a3,J(a1,3),J(a1,2),J(a1,1),J(a1,0))_=a4 .._;local a5=math.ceil(#_/16)*16-#_;local a6=""for B=1,a5 do a6=a6 ..string.char(math.random(0,255))end;return _..a6 end;local function a7(_)local a8={string.byte(_,1,4)}if a8[1]==a8[3]and a8[2]==a8[4]then return true end;return false end;local function a9(_)if not a7(_)then return nil end;local a1=M(string.byte(_,5),3)+M(string.byte(_,6),2)+M(string.byte(_,7),1)+M(string.byte(_,8),0)return string.sub(_,9,8+a1)end;local function aa(_,ab)for B=1,16 do _[B]=l(_[B],ab[B])end end;local function ac(_)local B=16;while true do local ad=_[B]+1;if ad>=256 then _[B]=ad-256;B=(B-2)%16+1 else _[B]=ad;break end end end;local ae,af,ag=os.queueEvent,coroutine.yield,os.time;local ah=ag()function G()local ai=ag()if ai-ah>=0.03 then ah=ai;ae("sleep")af("sleep")end end;local function aj(O)local ak,a8,al,am=string.char,math.random,G,table.insert;local an={}for B=1,O do am(an,a8(0,255))if B%10240==0 then al()end end;return an end;local function ao(O)local ak,a8,al,am=string.char,math.random,G,table.insert;local an={}for B=1,O do am(an,ak(a8(0,255)))if B%10240==0 then al()end end;return table.concat(an)end;return{byteParity=H,getByte=J,putByte=M,bytesToInts=N,intsToBytes=R,bytesToHex=V,hexToBytes=X,toHexString=Z,padByteString=a0,properlyDecrypted=a7,unpadByteString=a9,xorIV=aa,increment=ac,sleepCheckIn=G,getRandomData=aj,getRandomString=ao}end)local ap=c(function(_ENV,...)local M=E.putByte;local J=E.getByte;local aq='rounds'local ar="type"local as=1;local at=2;local au={}local av={}local aw={}local ax={}local ay={}local az={}local aA={}local aB={}local aC={}local aD={}local aE={0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000,0x40000000,0x80000000,0x1b000000,0x36000000,0x6c000000,0xd8000000,0xab000000,0x4d000000,0x9a000000,0x2f000000}local function aF(I)local aG=0xf8;local an=0;for B=1,8 do an=bit.lshift(an,1)local aH=E.byteParity(bit.band(I,aG))an=an+aH;local aI=bit.band(aG,1)aG=bit.band(bit.rshift(aG,1),0xff)if aI~=0 then aG=bit.bor(aG,0x80)else aG=bit.band(aG,0x7f)end end;return bit.bxor(an,0x63)end;local function aJ()for B=0,255 do local aK;if B~=0 then aK=k.invert(B)else aK=B end;local aL=aF(aK)au[B]=aL;av[aL]=B end end;local function aM()for aN=0,255 do local I=au[aN]aw[aN]=M(k.mul(0x03,I),0)+M(I,1)+M(I,2)+M(k.mul(0x02,I),3)ax[aN]=M(I,0)+M(I,1)+M(k.mul(0x02,I),2)+M(k.mul(0x03,I),3)ay[aN]=M(I,0)+M(k.mul(0x02,I),1)+M(k.mul(0x03,I),2)+M(I,3)az[aN]=M(k.mul(0x02,I),0)+M(k.mul(0x03,I),1)+M(I,2)+M(I,3)end end;local function aO()for aN=0,255 do local I=av[aN]aA[aN]=M(k.mul(0x0b,I),0)+M(k.mul(0x0d,I),1)+M(k.mul(0x09,I),2)+M(k.mul(0x0e,I),3)aB[aN]=M(k.mul(0x0d,I),0)+M(k.mul(0x09,I),1)+M(k.mul(0x0e,I),2)+M(k.mul(0x0b,I),3)aC[aN]=M(k.mul(0x09,I),0)+M(k.mul(0x0e,I),1)+M(k.mul(0x0b,I),2)+M(k.mul(0x0d,I),3)aD[aN]=M(k.mul(0x0e,I),0)+M(k.mul(0x0b,I),1)+M(k.mul(0x0d,I),2)+M(k.mul(0x09,I),3)end end;local function aP(aQ)local aR=bit.band(aQ,0xff000000)return bit.lshift(aQ,8)+bit.rshift(aR,24)end;local function aS(aQ)return M(au[J(aQ,0)],0)+M(au[J(aQ,1)],1)+M(au[J(aQ,2)],2)+M(au[J(aQ,3)],3)end;local function aT(aU)local aV={}local aW=math.floor(#aU/4)if aW~=4 and aW~=6 and aW~=8 or aW*4~=#aU then error("Invalid key size: "..tostring(aW))return nil end;aV[aq]=aW+6;aV[ar]=as;for B=0,aW-1 do aV[B]=M(aU[B*4+1],3)+M(aU[B*4+2],2)+M(aU[B*4+3],1)+M(aU[B*4+4],0)end;for B=aW,(aV[aq]+1)*4-1 do local aR=aV[B-1]if B%aW==0 then aR=aP(aR)aR=aS(aR)local L=math.floor(B/aW)aR=bit.bxor(aR,aE[L])elseif aW>6 and B%aW==4 then aR=aS(aR)end;aV[B]=bit.bxor(aV[B-aW],aR)end;return aV end;local function aX(aQ)local aY=J(aQ,3)local aZ=J(aQ,2)local a_=J(aQ,1)local b0=J(aQ,0)return M(k.add(k.add(k.add(k.mul(0x0b,aZ),k.mul(0x0d,a_)),k.mul(0x09,b0)),k.mul(0x0e,aY)),3)+M(k.add(k.add(k.add(k.mul(0x0b,a_),k.mul(0x0d,b0)),k.mul(0x09,aY)),k.mul(0x0e,aZ)),2)+M(k.add(k.add(k.add(k.mul(0x0b,b0),k.mul(0x0d,aY)),k.mul(0x09,aZ)),k.mul(0x0e,a_)),1)+M(k.add(k.add(k.add(k.mul(0x0b,aY),k.mul(0x0d,aZ)),k.mul(0x09,a_)),k.mul(0x0e,b0)),0)end;local function b1(aQ)local aY=J(aQ,3)local aZ=J(aQ,2)local a_=J(aQ,1)local b0=J(aQ,0)local b2=bit.bxor(b0,a_)local b3=bit.bxor(aZ,aY)local b4=bit.bxor(b2,b3)b4=bit.bxor(b4,k.mul(0x08,b4))local b5=bit.bxor(b4,k.mul(0x04,bit.bxor(a_,aY)))b4=bit.bxor(b4,k.mul(0x04,bit.bxor(b0,aZ)))return M(bit.bxor(bit.bxor(b0,b4),k.mul(0x02,bit.bxor(aY,b0))),0)+M(bit.bxor(bit.bxor(a_,b5),k.mul(0x02,b2)),1)+M(bit.bxor(bit.bxor(aZ,b4),k.mul(0x02,bit.bxor(aY,b0))),2)+M(bit.bxor(bit.bxor(aY,b5),k.mul(0x02,b3)),3)end;local function b6(aU)local aV=aT(aU)if aV==nil then return nil end;aV[ar]=at;for B=4,(aV[aq]+1)*4-5 do aV[B]=aX(aV[B])end;return aV end;local function b7(b8,aU,b9)for B=0,3 do b8[B+1]=bit.bxor(b8[B+1],aU[b9*4+B])end end;local function ba(bb,bc)bc[1]=bit.bxor(bit.bxor(bit.bxor(aw[J(bb[1],3)],ax[J(bb[2],2)]),ay[J(bb[3],1)]),az[J(bb[4],0)])bc[2]=bit.bxor(bit.bxor(bit.bxor(aw[J(bb[2],3)],ax[J(bb[3],2)]),ay[J(bb[4],1)]),az[J(bb[1],0)])bc[3]=bit.bxor(bit.bxor(bit.bxor(aw[J(bb[3],3)],ax[J(bb[4],2)]),ay[J(bb[1],1)]),az[J(bb[2],0)])bc[4]=bit.bxor(bit.bxor(bit.bxor(aw[J(bb[4],3)],ax[J(bb[1],2)]),ay[J(bb[2],1)]),az[J(bb[3],0)])end;local function bd(bb,bc)bc[1]=M(au[J(bb[1],3)],3)+M(au[J(bb[2],2)],2)+M(au[J(bb[3],1)],1)+M(au[J(bb[4],0)],0)bc[2]=M(au[J(bb[2],3)],3)+M(au[J(bb[3],2)],2)+M(au[J(bb[4],1)],1)+M(au[J(bb[1],0)],0)bc[3]=M(au[J(bb[3],3)],3)+M(au[J(bb[4],2)],2)+M(au[J(bb[1],1)],1)+M(au[J(bb[2],0)],0)bc[4]=M(au[J(bb[4],3)],3)+M(au[J(bb[1],2)],2)+M(au[J(bb[2],1)],1)+M(au[J(bb[3],0)],0)end;local function be(bb,bc)bc[1]=bit.bxor(bit.bxor(bit.bxor(aA[J(bb[1],3)],aB[J(bb[4],2)]),aC[J(bb[3],1)]),aD[J(bb[2],0)])bc[2]=bit.bxor(bit.bxor(bit.bxor(aA[J(bb[2],3)],aB[J(bb[1],2)]),aC[J(bb[4],1)]),aD[J(bb[3],0)])bc[3]=bit.bxor(bit.bxor(bit.bxor(aA[J(bb[3],3)],aB[J(bb[2],2)]),aC[J(bb[1],1)]),aD[J(bb[4],0)])bc[4]=bit.bxor(bit.bxor(bit.bxor(aA[J(bb[4],3)],aB[J(bb[3],2)]),aC[J(bb[2],1)]),aD[J(bb[1],0)])end;local function bf(bb,bc)bc[1]=M(av[J(bb[1],3)],3)+M(av[J(bb[4],2)],2)+M(av[J(bb[3],1)],1)+M(av[J(bb[2],0)],0)bc[2]=M(av[J(bb[2],3)],3)+M(av[J(bb[1],2)],2)+M(av[J(bb[4],1)],1)+M(av[J(bb[3],0)],0)bc[3]=M(av[J(bb[3],3)],3)+M(av[J(bb[2],2)],2)+M(av[J(bb[1],1)],1)+M(av[J(bb[4],0)],0)bc[4]=M(av[J(bb[4],3)],3)+M(av[J(bb[3],2)],2)+M(av[J(bb[2],1)],1)+M(av[J(bb[1],0)],0)end;local function bg(aU,bh,bi,S,T)bi=bi or 1;S=S or{}T=T or 1;local b8={}local bj={}if aU[ar]~=as then error("No encryption key: "..tostring(aU[ar])..", expected "..as)return end;b8=E.bytesToInts(bh,bi,4)b7(b8,aU,0)local b9=1;while b9<aU[aq]-1 do ba(b8,bj)b7(bj,aU,b9)b9=b9+1;ba(bj,b8)b7(b8,aU,b9)b9=b9+1 end;ba(b8,bj)b7(bj,aU,b9)b9=b9+1;bd(bj,b8)b7(b8,aU,b9)E.sleepCheckIn()return E.intsToBytes(b8,S,T)end;local function bk(aU,bh,bi,S,T)bi=bi or 1;S=S or{}T=T or 1;local b8={}local bj={}if aU[ar]~=at then error("No decryption key: "..tostring(aU[ar]))return end;b8=E.bytesToInts(bh,bi,4)b7(b8,aU,aU[aq])local b9=aU[aq]-1;while b9>2 do be(b8,bj)b7(bj,aU,b9)b9=b9-1;be(bj,b8)b7(b8,aU,b9)b9=b9-1 end;be(b8,bj)b7(bj,aU,b9)b9=b9-1;bf(bj,b8)b7(b8,aU,b9)E.sleepCheckIn()return E.intsToBytes(b8,S,T)end;aJ()aM()aO()return{ROUNDS=aq,KEY_TYPE=ar,ENCRYPTION_KEY=as,DECRYPTION_KEY=at,expandEncryptionKey=aT,expandDecryptionKey=b6,encrypt=bg,decrypt=bk}end)local bl=c(function(_ENV,...)local function bm()return{}end;local function bn(bo,bp)table.insert(bo,bp)end;local function bq(bo)return table.concat(bo)end;return{new=bm,addString=bn,toString=bq}end)local br=c(function(_ENV,...)local bs={}local a8=math.random;function bs.encryptString(aU,_,bt,ab)if ab then local bu={}for B=1,16 do bu[B]=ab[B]end;ab=bu else ab={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}end;local bv=ap.expandEncryptionKey(aU)local bw=bl.new()for B=1,#_/16 do local bx=(B-1)*16+1;local by={string.byte(_,bx,bx+15)}ab=bt(bv,by,ab)bl.addString(bw,string.char(unpack(by)))end;return bl.toString(bw)end;function bs.encryptECB(bv,by,ab)ap.encrypt(bv,by,1,by,1)end;function bs.encryptCBC(bv,by,ab)E.xorIV(by,ab)ap.encrypt(bv,by,1,by,1)return by end;function bs.encryptOFB(bv,by,ab)ap.encrypt(bv,ab,1,ab,1)E.xorIV(by,ab)return ab end;function bs.encryptCFB(bv,by,ab)ap.encrypt(bv,ab,1,ab,1)E.xorIV(by,ab)return by end;function bs.encryptCTR(bv,by,ab)local bz={}for U=1,16 do bz[U]=ab[U]end;ap.encrypt(bv,ab,1,ab,1)E.xorIV(by,ab)E.increment(bz)return bz end;function bs.decryptString(aU,_,bt,ab)if ab then local bu={}for B=1,16 do bu[B]=ab[B]end;ab=bu else ab={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}end;local bv;if bt==bs.decryptOFB or bt==bs.decryptCFB or bt==bs.decryptCTR then bv=ap.expandEncryptionKey(aU)else bv=ap.expandDecryptionKey(aU)end;local bA=bl.new()for B=1,#_/16 do local bx=(B-1)*16+1;local by={string.byte(_,bx,bx+15)}ab=bt(bv,by,ab)bl.addString(bA,string.char(unpack(by)))end;return bl.toString(bA)end;function bs.decryptECB(bv,by,ab)ap.decrypt(bv,by,1,by,1)return ab end;function bs.decryptCBC(bv,by,ab)local bz={}for U=1,16 do bz[U]=by[U]end;ap.decrypt(bv,by,1,by,1)E.xorIV(by,ab)return bz end;function bs.decryptOFB(bv,by,ab)ap.encrypt(bv,ab,1,ab,1)E.xorIV(by,ab)return ab end;function bs.decryptCFB(bv,by,ab)local bz={}for U=1,16 do bz[U]=by[U]end;ap.encrypt(bv,ab,1,ab,1)E.xorIV(by,ab)return bz end;bs.decryptCTR=bs.encryptCTR;return bs end)local bB={AES128=16,AES192=24,AES256=32,ECBMODE=1,CBCMODE=2,OFBMODE=3,CFBMODE=4,CTRMODE=4}local function bC(bD,bE,ab)local bF=bE;if bE==bB.AES192 then bF=32 end;if bF>#bD then local bG=""for B=1,bF-#bD do bG=bG..string.char(0)end;bD=bD..bG else bD=string.sub(bD,1,bF)end;local bH={string.byte(bD,1,#bD)}bD=br.encryptString(bH,bD,br.encryptCBC,ab)bD=string.sub(bD,1,bE)return{string.byte(bD,1,#bD)}end;function bB.encrypt(bD,_,bE,bI,ab,bJ)assert(bD~=nil,"Empty password.")assert(bD~=nil,"Empty data.")local bI=bI or bB.CBCMODE;local bE=bE or bB.AES128;local aU=bJ and{bD:byte(1,bE)}or bC(bD,bE,ab)local bK=E.padByteString(_)if bI==bB.ECBMODE then return br.encryptString(aU,bK,br.encryptECB,ab)elseif bI==bB.CBCMODE then return br.encryptString(aU,bK,br.encryptCBC,ab)elseif bI==bB.OFBMODE then return br.encryptString(aU,bK,br.encryptOFB,ab)elseif bI==bB.CFBMODE then return br.encryptString(aU,bK,br.encryptCFB,ab)elseif bI==bB.CTRMODE then return br.encryptString(aU,bK,br.encryptCTR,ab)else error("Unknown mode",2)end end;function bB.decrypt(bD,_,bE,bI,ab,bJ)local bI=bI or bB.CBCMODE;local bE=bE or bB.AES128;local aU=bJ and{bD:byte(1,bE)}or bC(bD,bE,ab)local bL;if bI==bB.ECBMODE then bL=br.decryptString(aU,_,br.decryptECB,ab)elseif bI==bB.CBCMODE then bL=br.decryptString(aU,_,br.decryptCBC,ab)elseif bI==bB.OFBMODE then bL=br.decryptString(aU,_,br.decryptOFB,ab)elseif bI==bB.CFBMODE then bL=br.decryptString(aU,_,br.decryptCFB,ab)elseif bI==bB.CTRMODE then bL=br.decryptString(aU,_,br.decryptCTR,ab)else error("Unknown mode",2)end;return E.unpadByteString(bL)end;return bB end)()local bM=(function()local bN=false;local unpack,bO,I,ak,bP,u,bQ,bR,bS,f,bT,bU,bV,tonumber,type=table.unpack or unpack,table.concat,string.byte,string.char,string.rep,string.sub,string.gsub,string.gmatch,string.format,math.floor,math.ceil,math.min,math.max,tonumber,type;local function bW(bX)local bY,m,bZ,b_=0,bX,bX;while true do bY,b_,m,bZ=bY+1,m,m+m+1,bZ+bZ+bY%2;if bY>256 or m-(m-1)~=1 or bZ-(bZ-1)~=1 or m==bZ then return bY,false elseif m==b_ then return bY,true end end end;local aN=2/3;local c0=aN*5>3 and aN*4<3 and bW(1.0)>=53;assert(c0,"at least 53-bit floating point numbers are required")local c1,c2=bW(1)local c3=c2 and c1==64;local c4=c2 and c1==32;assert(c3 or c4 or not c2,"Lua integers must be either 32-bit or 64-bit")local c5=({false,[1]=true})[1]and(type(jit)~="table"or jit.version_num>=20000)local c6;local c7;local c8;local c9;local ca;if c5 then c9=require"bit"ca="bit"local cb,an=pcall(require,"ffi")if cb then c8=an end;c6=not not loadstring"b=0b0"c7=type(jit)=="table"and jit.arch or c8 and c8.arch or nil else for cc,cd in ipairs((_VERSION=="Lua 5.2"or type(_HOST)=="string")and{"bit32","bit"}or{"bit","bit32"})do if type(_G[cd])=="table"and _G[cd].bxor then c9=_G[cd]ca=cd;break end end end;if bN then print("Abilities:")print(" Lua version: "..(c5 and"LuaJIT "..(c6 and"2.1 "or"2.0 ")..(c7 or"")..(c8 and" with FFI"or" without FFI")or _VERSION))print(" Integer bitwise operators: "..(c3 and"int64"or c4 and"int32"or"no"))print(" 32-bit bitwise library: "..(ca or"not found"))end;local ce,cf;if c5 and c8 then ce="Using 'ffi' library of LuaJIT"cf="FFI"elseif c5 then ce="Using special code for FFI-less LuaJIT"cf="LJ"elseif c3 then ce="Using native int64 bitwise operators"cf="INT64"elseif c4 then ce="Using native int32 bitwise operators"cf="INT32"elseif ca then ce="Using '"..ca.."' library"cf="LIB32"else ce="Emulating bitwise operators using look-up table"cf="EMUL"end;if bN then print("Implementation selected:")print(" "..ce)end;local cg,ch,ci,cj,ck,cl,cm,cn,co,cp,cq;if cf=="FFI"or cf=="LJ"or cf=="LIB32"then cg=c9.band;ch=c9.bor;ci=c9.bxor;cj=c9.lshift;ck=c9.rshift;cl=c9.rol or c9.lrotate;cm=c9.ror or c9.rrotate;cn=c9.bnot;co=c9.tobit;cp=c9.tohex;assert(cg and ch and ci and cj and ck and cl and cm and cn,"Library '"..ca.."' is incomplete")cq=ci elseif cf=="EMUL"then function cj(aN,m)return aN*2^m%2^32 end;function ck(aN,m)aN=aN%2^32/2^m;return aN-aN%1 end;function cl(aN,m)aN=aN%2^32*2^m;local cr=aN%2^32;return cr+(aN-cr)/2^32 end;function cm(aN,m)aN=aN%2^32/2^m;local cr=aN%1;return cr*2^32+aN-cr end;local cs={[0]=0}local ct=0;for cu=0,127*256,256 do for aN=cu,cu+127 do aN=cs[aN]*2;cs[ct]=aN;cs[ct+1]=aN;cs[ct+256]=aN;cs[ct+257]=aN+1;ct=ct+2 end;ct=ct+256 end;local function cv(aN,cu,cw)local cx=aN%2^32;local cy=cu%2^32;local cz=cx%256;local cA=cy%256;local cB=cs[cz+cA*256]aN=cx-cz;cu=(cy-cA)/256;cz=aN%65536;cA=cu%256;cB=cB+cs[cz+cA]*256;aN=(aN-cz)/256;cu=(cu-cA)/256;cz=aN%65536+cu%256;cB=cB+cs[cz]*65536;cB=cB+cs[(aN+cu-cz)/256]*16777216;if cw then cB=cx+cy-cw*cB end;return cB end;function cg(aN,cu)return cv(aN,cu)end;function ch(aN,cu)return cv(aN,cu,1)end;function ci(aN,cu,cC,b2,b3)if cC then if b2 then if b3 then b2=cv(b2,b3,2)end;cC=cv(cC,b2,2)end;cu=cv(cu,cC,2)end;return cv(aN,cu,2)end;function cq(aN,cu)return aN+cu-2*cs[aN+cu*256]end end;cp=cp or pcall(bS,"%x",2^31)and function(aN)return bS("%08x",aN%4294967296)end or function(aN)return bS("%08x",(aN+2^31)%2^32-2^31)end;local function cD(aN)return ci(aN,0xA5A5A5A5)%4294967296 end;local function cE()return{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}end;local cF,cG,cH,cI,cJ;local cK,cL,cM,cN,cO,cP={},{},{},{},{},{}local cQ={[224]={},[256]=cN}local cR,cS={[384]={},[512]=cM},{[384]={},[512]=cN}local cT,cU={},{0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0}local cV={0,0,0,0,0,0,0,0,28,25,26,27,0,0,10,9,11,12,0,15,16,17,18,0,20,22,23,21}local cW,cX,cY;local cZ={}local c_,d0,d1=4294967296,0,0;local function d2(d3)local d4={}for cc,d5 in ipairs{1,9,13,17,18,21}do d4[d5]="<"..bP(d3,d5)end;return d4 end;if cf=="FFI"then local d6=c8.new"int32_t[80]"function cF(d7,d8,d9,d5)local da,db=d6,cL;for dc=d9,d9+d5-1,64 do for U=0,15 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=ch(cj(i,24),cj(c9,16),cj(dd,8),de)end;for U=16,63 do local i,c9=da[U-15],da[U-2]da[U]=co(ci(cm(i,7),cl(i,14),ck(i,3))+ci(cl(c9,15),cl(c9,13),ck(c9,10))+da[U-7]+da[U-16])end;local i,c9,dd,de,e,d,df,dg=d7[1],d7[2],d7[3],d7[4],d7[5],d7[6],d7[7],d7[8]for U=0,63,8 do local cC=co(ci(df,cg(e,ci(d,df)))+ci(cm(e,6),cm(e,11),cl(e,7))+da[U]+db[U+1]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(df,cg(e,ci(d,df)))+ci(cm(e,6),cm(e,11),cl(e,7))+da[U+1]+db[U+2]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(df,cg(e,ci(d,df)))+ci(cm(e,6),cm(e,11),cl(e,7))+da[U+2]+db[U+3]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(df,cg(e,ci(d,df)))+ci(cm(e,6),cm(e,11),cl(e,7))+da[U+3]+db[U+4]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(df,cg(e,ci(d,df)))+ci(cm(e,6),cm(e,11),cl(e,7))+da[U+4]+db[U+5]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(df,cg(e,ci(d,df)))+ci(cm(e,6),cm(e,11),cl(e,7))+da[U+5]+db[U+6]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(df,cg(e,ci(d,df)))+ci(cm(e,6),cm(e,11),cl(e,7))+da[U+6]+db[U+7]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(df,cg(e,ci(d,df)))+ci(cm(e,6),cm(e,11),cl(e,7))+da[U+7]+db[U+8]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)end;d7[1],d7[2],d7[3],d7[4]=co(i+d7[1]),co(c9+d7[2]),co(dd+d7[3]),co(de+d7[4])d7[5],d7[6],d7[7],d7[8]=co(e+d7[5]),co(d+d7[6]),co(df+d7[7]),co(dg+d7[8])end end;local dh=c8.new"int64_t[80]"local di=c8.typeof"int64_t"local dj=c8.typeof"int32_t"local dk=c8.typeof"uint32_t"d0=di(2^32)if c6 then local dl,dm,dn,dp,dq,dr,ds,dt=cg,ch,ci,cn,cj,ck,cl,cm;cW=cp;local du=c8.typeof"int64_t[30]"cY=0;d1=di(2^32)function cE()return du()end;function cJ(dv,cc,d8,d9,d5,dw)local dx=cO;local dy=ck(dw,3)for dc=d9,d9+d5-1,dw do for U=0,dy-1 do dc=dc+8;local dg,df,d,e,de,dd,c9,i=I(d8,dc-7,dc)dv[U]=dn(dv[U],dm(ch(cj(i,24),cj(c9,16),cj(dd,8),de)*di(2^32),dk(dj(ch(cj(e,24),cj(d,16),cj(df,8),dg)))))end;for dz=1,24 do for U=0,4 do dv[25+U]=dn(dv[U],dv[U+5],dv[U+10],dv[U+15],dv[U+20])end;local dA=dn(dv[25],ds(dv[27],1))dv[1],dv[6],dv[11],dv[16]=ds(dn(dA,dv[6]),44),ds(dn(dA,dv[16]),45),ds(dn(dA,dv[1]),1),ds(dn(dA,dv[11]),10)dv[21]=ds(dn(dA,dv[21]),2)dA=dn(dv[26],ds(dv[28],1))dv[2],dv[7],dv[12],dv[22]=ds(dn(dA,dv[12]),43),ds(dn(dA,dv[22]),61),ds(dn(dA,dv[7]),6),ds(dn(dA,dv[2]),62)dv[17]=ds(dn(dA,dv[17]),15)dA=dn(dv[27],ds(dv[29],1))dv[3],dv[8],dv[18],dv[23]=ds(dn(dA,dv[18]),21),ds(dn(dA,dv[3]),28),ds(dn(dA,dv[23]),56),ds(dn(dA,dv[8]),55)dv[13]=ds(dn(dA,dv[13]),25)dA=dn(dv[28],ds(dv[25],1))dv[4],dv[14],dv[19],dv[24]=ds(dn(dA,dv[24]),14),ds(dn(dA,dv[19]),8),ds(dn(dA,dv[4]),27),ds(dn(dA,dv[14]),39)dv[9]=ds(dn(dA,dv[9]),20)dA=dn(dv[29],ds(dv[26],1))dv[5],dv[10],dv[15],dv[20]=ds(dn(dA,dv[10]),3),ds(dn(dA,dv[20]),18),ds(dn(dA,dv[5]),36),ds(dn(dA,dv[15]),41)dv[0]=dn(dA,dv[0])dv[0],dv[1],dv[2],dv[3],dv[4]=dn(dv[0],dl(dp(dv[1]),dv[2]),dx[dz]),dn(dv[1],dl(dp(dv[2]),dv[3])),dn(dv[2],dl(dp(dv[3]),dv[4])),dn(dv[3],dl(dp(dv[4]),dv[0])),dn(dv[4],dl(dp(dv[0]),dv[1]))dv[5],dv[6],dv[7],dv[8],dv[9]=dn(dv[8],dl(dp(dv[9]),dv[5])),dn(dv[9],dl(dp(dv[5]),dv[6])),dn(dv[5],dl(dp(dv[6]),dv[7])),dn(dv[6],dl(dp(dv[7]),dv[8])),dn(dv[7],dl(dp(dv[8]),dv[9]))dv[10],dv[11],dv[12],dv[13],dv[14]=dn(dv[11],dl(dp(dv[12]),dv[13])),dn(dv[12],dl(dp(dv[13]),dv[14])),dn(dv[13],dl(dp(dv[14]),dv[10])),dn(dv[14],dl(dp(dv[10]),dv[11])),dn(dv[10],dl(dp(dv[11]),dv[12]))dv[15],dv[16],dv[17],dv[18],dv[19]=dn(dv[19],dl(dp(dv[15]),dv[16])),dn(dv[15],dl(dp(dv[16]),dv[17])),dn(dv[16],dl(dp(dv[17]),dv[18])),dn(dv[17],dl(dp(dv[18]),dv[19])),dn(dv[18],dl(dp(dv[19]),dv[15]))dv[20],dv[21],dv[22],dv[23],dv[24]=dn(dv[22],dl(dp(dv[23]),dv[24])),dn(dv[23],dl(dp(dv[24]),dv[20])),dn(dv[24],dl(dp(dv[20]),dv[21])),dn(dv[20],dl(dp(dv[21]),dv[22])),dn(dv[21],dl(dp(dv[22]),dv[23]))end end end;local dB=0xA5A5A5A5*di(2^32+1)function cX(dC)return dn(dC,dB)end;function cG(d7,cc,d8,d9,d5)local da,db=dh,cK;for dc=d9,d9+d5-1,128 do for U=0,15 do dc=dc+8;local i,c9,dd,de,e,d,df,dg=I(d8,dc-7,dc)da[U]=dm(ch(cj(i,24),cj(c9,16),cj(dd,8),de)*di(2^32),dk(dj(ch(cj(e,24),cj(d,16),cj(df,8),dg))))end;for U=16,79 do local i,c9=da[U-15],da[U-2]da[U]=dn(dt(i,1),dt(i,8),dr(i,7))+dn(dt(c9,19),ds(c9,3),dr(c9,6))+da[U-7]+da[U-16]end;local i,c9,dd,de,e,d,df,dg=d7[1],d7[2],d7[3],d7[4],d7[5],d7[6],d7[7],d7[8]for U=0,79,8 do local cC=dn(dt(e,14),dt(e,18),ds(e,23))+dn(df,dl(e,dn(d,df)))+dg+db[U+1]+da[U]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,dn(dl(dn(i,c9),dd),dl(i,c9))+dn(dt(i,28),ds(i,25),ds(i,30))+cC;cC=dn(dt(e,14),dt(e,18),ds(e,23))+dn(df,dl(e,dn(d,df)))+dg+db[U+2]+da[U+1]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,dn(dl(dn(i,c9),dd),dl(i,c9))+dn(dt(i,28),ds(i,25),ds(i,30))+cC;cC=dn(dt(e,14),dt(e,18),ds(e,23))+dn(df,dl(e,dn(d,df)))+dg+db[U+3]+da[U+2]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,dn(dl(dn(i,c9),dd),dl(i,c9))+dn(dt(i,28),ds(i,25),ds(i,30))+cC;cC=dn(dt(e,14),dt(e,18),ds(e,23))+dn(df,dl(e,dn(d,df)))+dg+db[U+4]+da[U+3]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,dn(dl(dn(i,c9),dd),dl(i,c9))+dn(dt(i,28),ds(i,25),ds(i,30))+cC;cC=dn(dt(e,14),dt(e,18),ds(e,23))+dn(df,dl(e,dn(d,df)))+dg+db[U+5]+da[U+4]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,dn(dl(dn(i,c9),dd),dl(i,c9))+dn(dt(i,28),ds(i,25),ds(i,30))+cC;cC=dn(dt(e,14),dt(e,18),ds(e,23))+dn(df,dl(e,dn(d,df)))+dg+db[U+6]+da[U+5]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,dn(dl(dn(i,c9),dd),dl(i,c9))+dn(dt(i,28),ds(i,25),ds(i,30))+cC;cC=dn(dt(e,14),dt(e,18),ds(e,23))+dn(df,dl(e,dn(d,df)))+dg+db[U+7]+da[U+6]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,dn(dl(dn(i,c9),dd),dl(i,c9))+dn(dt(i,28),ds(i,25),ds(i,30))+cC;cC=dn(dt(e,14),dt(e,18),ds(e,23))+dn(df,dl(e,dn(d,df)))+dg+db[U+8]+da[U+7]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,dn(dl(dn(i,c9),dd),dl(i,c9))+dn(dt(i,28),ds(i,25),ds(i,30))+cC end;d7[1]=i+d7[1]d7[2]=c9+d7[2]d7[3]=dd+d7[3]d7[4]=de+d7[4]d7[5]=e+d7[5]d7[6]=d+d7[6]d7[7]=df+d7[7]d7[8]=dg+d7[8]end end else local dD=c8.typeof"union{int64_t i64; struct{int32_t lo, hi;} i32;}"do local b3=dD(1)if b3.i32.lo<b3.i32.hi then dD=c8.typeof"union{int64_t i64; struct{int32_t hi, lo;} i32;}"end end;local dE=c8.typeof("$[?]",dD)local dF=dE(3)local function dG(i)dF[0].i64=i;local dH,dI=dF[0].i32.lo,dF[0].i32.hi;local dJ=ci(ch(ck(dH,1),cj(dI,31)),ch(ck(dH,8),cj(dI,24)),ch(ck(dH,7),cj(dI,25)))local dK=ci(ch(ck(dI,1),cj(dH,31)),ch(ck(dI,8),cj(dH,24)),ck(dI,7))return dK*di(2^32)+dk(dj(dJ))end;local function dL(c9)dF[0].i64=c9;local dM,dN=dF[0].i32.lo,dF[0].i32.hi;local dO=ci(ch(ck(dM,19),cj(dN,13)),ch(cj(dM,3),ck(dN,29)),ch(ck(dM,6),cj(dN,26)))local dP=ci(ch(ck(dN,19),cj(dM,13)),ch(cj(dN,3),ck(dM,29)),ck(dN,6))return dP*di(2^32)+dk(dj(dO))end;local function dQ(e)dF[0].i64=e;local dR,dS=dF[0].i32.lo,dF[0].i32.hi;local dO=ci(ch(ck(dR,14),cj(dS,18)),ch(ck(dR,18),cj(dS,14)),ch(cj(dR,23),ck(dS,9)))local dP=ci(ch(ck(dS,14),cj(dR,18)),ch(ck(dS,18),cj(dR,14)),ch(cj(dS,23),ck(dR,9)))return dP*di(2^32)+dk(dj(dO))end;local function dT(i)dF[0].i64=i;local dM,dN=dF[0].i32.lo,dF[0].i32.hi;local dO=ci(ch(ck(dM,28),cj(dN,4)),ch(cj(dM,30),ck(dN,2)),ch(cj(dM,25),ck(dN,7)))local dP=ci(ch(ck(dN,28),cj(dM,4)),ch(cj(dN,30),ck(dM,2)),ch(cj(dN,25),ck(dM,7)))return dP*di(2^32)+dk(dj(dO))end;local function dU(e,d,df)dF[0].i64=d;dF[1].i64=df;dF[2].i64=e;local dV,dW=dF[0].i32.lo,dF[0].i32.hi;local dX,dY=dF[1].i32.lo,dF[1].i32.hi;local dR,dS=dF[2].i32.lo,dF[2].i32.hi;local dZ=ci(dX,cg(dR,ci(dV,dX)))local d_=ci(dY,cg(dS,ci(dW,dY)))return d_*di(2^32)+dk(dj(dZ))end;local function e0(i,c9,dd)dF[0].i64=i;dF[1].i64=c9;dF[2].i64=dd;local dH,dI=dF[0].i32.lo,dF[0].i32.hi;local dM,dN=dF[1].i32.lo,dF[1].i32.hi;local e1,e2=dF[2].i32.lo,dF[2].i32.hi;local dZ=ci(cg(ci(dH,dM),e1),cg(dH,dM))local d_=ci(cg(ci(dI,dN),e2),cg(dI,dN))return d_*di(2^32)+dk(dj(dZ))end;function cX(dC)dF[0].i64=dC;local e3,e4=dF[0].i32.lo,dF[0].i32.hi;e3=ci(e3,0xA5A5A5A5)e4=ci(e4,0xA5A5A5A5)return e4*di(2^32)+dk(dj(e3))end;function cW(dC)dF[0].i64=dC;return cp(dF[0].i32.hi)..cp(dF[0].i32.lo)end;function cG(d7,cc,d8,d9,d5)local da,db=dh,cK;for dc=d9,d9+d5-1,128 do for U=0,15 do dc=dc+8;local i,c9,dd,de,e,d,df,dg=I(d8,dc-7,dc)da[U]=ch(cj(i,24),cj(c9,16),cj(dd,8),de)*di(2^32)+dk(dj(ch(cj(e,24),cj(d,16),cj(df,8),dg)))end;for U=16,79 do da[U]=dG(da[U-15])+dL(da[U-2])+da[U-7]+da[U-16]end;local i,c9,dd,de,e,d,df,dg=d7[1],d7[2],d7[3],d7[4],d7[5],d7[6],d7[7],d7[8]for U=0,79,8 do local cC=dQ(e)+dU(e,d,df)+dg+db[U+1]+da[U]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,e0(i,c9,dd)+dT(i)+cC;cC=dQ(e)+dU(e,d,df)+dg+db[U+2]+da[U+1]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,e0(i,c9,dd)+dT(i)+cC;cC=dQ(e)+dU(e,d,df)+dg+db[U+3]+da[U+2]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,e0(i,c9,dd)+dT(i)+cC;cC=dQ(e)+dU(e,d,df)+dg+db[U+4]+da[U+3]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,e0(i,c9,dd)+dT(i)+cC;cC=dQ(e)+dU(e,d,df)+dg+db[U+5]+da[U+4]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,e0(i,c9,dd)+dT(i)+cC;cC=dQ(e)+dU(e,d,df)+dg+db[U+6]+da[U+5]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,e0(i,c9,dd)+dT(i)+cC;cC=dQ(e)+dU(e,d,df)+dg+db[U+7]+da[U+6]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,e0(i,c9,dd)+dT(i)+cC;cC=dQ(e)+dU(e,d,df)+dg+db[U+8]+da[U+7]dg,df,d,e=df,d,e,cC+de;de,dd,c9,i=dd,c9,i,e0(i,c9,dd)+dT(i)+cC end;d7[1]=i+d7[1]d7[2]=c9+d7[2]d7[3]=dd+d7[3]d7[4]=de+d7[4]d7[5]=e+d7[5]d7[6]=d+d7[6]d7[7]=df+d7[7]d7[8]=dg+d7[8]end end end;function cH(d7,d8,d9,d5)local da,db=d6,cT;for dc=d9,d9+d5-1,64 do for U=0,15 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=ch(cj(de,24),cj(dd,16),cj(c9,8),i)end;local i,c9,dd,de=d7[1],d7[2],d7[3],d7[4]for U=0,15,4 do i,de,dd,c9=de,dd,c9,co(cl(ci(de,cg(c9,ci(dd,de)))+db[U+1]+da[U]+i,7)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(de,cg(c9,ci(dd,de)))+db[U+2]+da[U+1]+i,12)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(de,cg(c9,ci(dd,de)))+db[U+3]+da[U+2]+i,17)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(de,cg(c9,ci(dd,de)))+db[U+4]+da[U+3]+i,22)+c9)end;for U=16,31,4 do local df=5*U;i,de,dd,c9=de,dd,c9,co(cl(ci(dd,cg(de,ci(c9,dd)))+db[U+1]+da[cg(df+1,15)]+i,5)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,cg(de,ci(c9,dd)))+db[U+2]+da[cg(df+6,15)]+i,9)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,cg(de,ci(c9,dd)))+db[U+3]+da[cg(df-5,15)]+i,14)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,cg(de,ci(c9,dd)))+db[U+4]+da[cg(df,15)]+i,20)+c9)end;for U=32,47,4 do local df=3*U;i,de,dd,c9=de,dd,c9,co(cl(ci(c9,dd,de)+db[U+1]+da[cg(df+5,15)]+i,4)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(c9,dd,de)+db[U+2]+da[cg(df+8,15)]+i,11)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(c9,dd,de)+db[U+3]+da[cg(df-5,15)]+i,16)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(c9,dd,de)+db[U+4]+da[cg(df-2,15)]+i,23)+c9)end;for U=48,63,4 do local df=7*U;i,de,dd,c9=de,dd,c9,co(cl(ci(dd,ch(c9,cn(de)))+db[U+1]+da[cg(df,15)]+i,6)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,ch(c9,cn(de)))+db[U+2]+da[cg(df+7,15)]+i,10)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,ch(c9,cn(de)))+db[U+3]+da[cg(df-2,15)]+i,15)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,ch(c9,cn(de)))+db[U+4]+da[cg(df+5,15)]+i,21)+c9)end;d7[1],d7[2],d7[3],d7[4]=co(i+d7[1]),co(c9+d7[2]),co(dd+d7[3]),co(de+d7[4])end end;function cI(d7,d8,d9,d5)local da=d6;for dc=d9,d9+d5-1,64 do for U=0,15 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=ch(cj(i,24),cj(c9,16),cj(dd,8),de)end;for U=16,79 do da[U]=cl(ci(da[U-3],da[U-8],da[U-14],da[U-16]),1)end;local i,c9,dd,de,e=d7[1],d7[2],d7[3],d7[4],d7[5]for U=0,19,5 do e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U]+0x5A827999+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U+1]+0x5A827999+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U+2]+0x5A827999+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U+3]+0x5A827999+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U+4]+0x5A827999+e)end;for U=20,39,5 do e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U]+0x6ED9EBA1+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+1]+0x6ED9EBA1+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+2]+0x6ED9EBA1+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+3]+0x6ED9EBA1+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+4]+0x6ED9EBA1+e)end;for U=40,59,5 do e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U]+0x8F1BBCDC+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U+1]+0x8F1BBCDC+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U+2]+0x8F1BBCDC+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U+3]+0x8F1BBCDC+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U+4]+0x8F1BBCDC+e)end;for U=60,79,5 do e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U]+0xCA62C1D6+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+1]+0xCA62C1D6+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+2]+0xCA62C1D6+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+3]+0xCA62C1D6+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+4]+0xCA62C1D6+e)end;d7[1],d7[2],d7[3],d7[4],d7[5]=co(i+d7[1]),co(c9+d7[2]),co(dd+d7[3]),co(de+d7[4]),co(e+d7[5])end end end;if cf=="FFI"and not c6 or cf=="LJ"then if cf=="FFI"then local e5=c8.typeof"int32_t[31]"function cE()return e5()end end;function cJ(e6,e7,d8,d9,d5,dw)local e8,e9=cO,cP;local dy=ck(dw,3)for dc=d9,d9+d5-1,dw do for U=1,dy do local i,c9,dd,de=I(d8,dc+1,dc+4)e6[U]=ci(e6[U],ch(cj(de,24),cj(dd,16),cj(c9,8),i))dc=dc+8;i,c9,dd,de=I(d8,dc-3,dc)e7[U]=ci(e7[U],ch(cj(de,24),cj(dd,16),cj(c9,8),i))end;for dz=1,24 do for U=1,5 do e6[25+U]=ci(e6[U],e6[U+5],e6[U+10],e6[U+15],e6[U+20])end;for U=1,5 do e7[25+U]=ci(e7[U],e7[U+5],e7[U+10],e7[U+15],e7[U+20])end;local ea=ci(e6[26],cj(e6[28],1),ck(e7[28],31))local eb=ci(e7[26],cj(e7[28],1),ck(e6[28],31))e6[2],e7[2],e6[7],e7[7],e6[12],e7[12],e6[17],e7[17]=ci(ck(ci(ea,e6[7]),20),cj(ci(eb,e7[7]),12)),ci(ck(ci(eb,e7[7]),20),cj(ci(ea,e6[7]),12)),ci(ck(ci(ea,e6[17]),19),cj(ci(eb,e7[17]),13)),ci(ck(ci(eb,e7[17]),19),cj(ci(ea,e6[17]),13)),ci(cj(ci(ea,e6[2]),1),ck(ci(eb,e7[2]),31)),ci(cj(ci(eb,e7[2]),1),ck(ci(ea,e6[2]),31)),ci(cj(ci(ea,e6[12]),10),ck(ci(eb,e7[12]),22)),ci(cj(ci(eb,e7[12]),10),ck(ci(ea,e6[12]),22))local ec,d7=ci(ea,e6[22]),ci(eb,e7[22])e6[22],e7[22]=ci(cj(ec,2),ck(d7,30)),ci(cj(d7,2),ck(ec,30))ea=ci(e6[27],cj(e6[29],1),ck(e7[29],31))eb=ci(e7[27],cj(e7[29],1),ck(e6[29],31))e6[3],e7[3],e6[8],e7[8],e6[13],e7[13],e6[23],e7[23]=ci(ck(ci(ea,e6[13]),21),cj(ci(eb,e7[13]),11)),ci(ck(ci(eb,e7[13]),21),cj(ci(ea,e6[13]),11)),ci(ck(ci(ea,e6[23]),3),cj(ci(eb,e7[23]),29)),ci(ck(ci(eb,e7[23]),3),cj(ci(ea,e6[23]),29)),ci(cj(ci(ea,e6[8]),6),ck(ci(eb,e7[8]),26)),ci(cj(ci(eb,e7[8]),6),ck(ci(ea,e6[8]),26)),ci(ck(ci(ea,e6[3]),2),cj(ci(eb,e7[3]),30)),ci(ck(ci(eb,e7[3]),2),cj(ci(ea,e6[3]),30))ec,d7=ci(ea,e6[18]),ci(eb,e7[18])e6[18],e7[18]=ci(cj(ec,15),ck(d7,17)),ci(cj(d7,15),ck(ec,17))ea=ci(e6[28],cj(e6[30],1),ck(e7[30],31))eb=ci(e7[28],cj(e7[30],1),ck(e6[30],31))e6[4],e7[4],e6[9],e7[9],e6[19],e7[19],e6[24],e7[24]=ci(cj(ci(ea,e6[19]),21),ck(ci(eb,e7[19]),11)),ci(cj(ci(eb,e7[19]),21),ck(ci(ea,e6[19]),11)),ci(cj(ci(ea,e6[4]),28),ck(ci(eb,e7[4]),4)),ci(cj(ci(eb,e7[4]),28),ck(ci(ea,e6[4]),4)),ci(ck(ci(ea,e6[24]),8),cj(ci(eb,e7[24]),24)),ci(ck(ci(eb,e7[24]),8),cj(ci(ea,e6[24]),24)),ci(ck(ci(ea,e6[9]),9),cj(ci(eb,e7[9]),23)),ci(ck(ci(eb,e7[9]),9),cj(ci(ea,e6[9]),23))ec,d7=ci(ea,e6[14]),ci(eb,e7[14])e6[14],e7[14]=ci(cj(ec,25),ck(d7,7)),ci(cj(d7,25),ck(ec,7))ea=ci(e6[29],cj(e6[26],1),ck(e7[26],31))eb=ci(e7[29],cj(e7[26],1),ck(e6[26],31))e6[5],e7[5],e6[15],e7[15],e6[20],e7[20],e6[25],e7[25]=ci(cj(ci(ea,e6[25]),14),ck(ci(eb,e7[25]),18)),ci(cj(ci(eb,e7[25]),14),ck(ci(ea,e6[25]),18)),ci(cj(ci(ea,e6[20]),8),ck(ci(eb,e7[20]),24)),ci(cj(ci(eb,e7[20]),8),ck(ci(ea,e6[20]),24)),ci(cj(ci(ea,e6[5]),27),ck(ci(eb,e7[5]),5)),ci(cj(ci(eb,e7[5]),27),ck(ci(ea,e6[5]),5)),ci(ck(ci(ea,e6[15]),25),cj(ci(eb,e7[15]),7)),ci(ck(ci(eb,e7[15]),25),cj(ci(ea,e6[15]),7))ec,d7=ci(ea,e6[10]),ci(eb,e7[10])e6[10],e7[10]=ci(cj(ec,20),ck(d7,12)),ci(cj(d7,20),ck(ec,12))ea=ci(e6[30],cj(e6[27],1),ck(e7[27],31))eb=ci(e7[30],cj(e7[27],1),ck(e6[27],31))e6[6],e7[6],e6[11],e7[11],e6[16],e7[16],e6[21],e7[21]=ci(cj(ci(ea,e6[11]),3),ck(ci(eb,e7[11]),29)),ci(cj(ci(eb,e7[11]),3),ck(ci(ea,e6[11]),29)),ci(cj(ci(ea,e6[21]),18),ck(ci(eb,e7[21]),14)),ci(cj(ci(eb,e7[21]),18),ck(ci(ea,e6[21]),14)),ci(ck(ci(ea,e6[6]),28),cj(ci(eb,e7[6]),4)),ci(ck(ci(eb,e7[6]),28),cj(ci(ea,e6[6]),4)),ci(ck(ci(ea,e6[16]),23),cj(ci(eb,e7[16]),9)),ci(ck(ci(eb,e7[16]),23),cj(ci(ea,e6[16]),9))e6[1],e7[1]=ci(ea,e6[1]),ci(eb,e7[1])e6[1],e6[2],e6[3],e6[4],e6[5]=ci(e6[1],cg(cn(e6[2]),e6[3]),e8[dz]),ci(e6[2],cg(cn(e6[3]),e6[4])),ci(e6[3],cg(cn(e6[4]),e6[5])),ci(e6[4],cg(cn(e6[5]),e6[1])),ci(e6[5],cg(cn(e6[1]),e6[2]))e6[6],e6[7],e6[8],e6[9],e6[10]=ci(e6[9],cg(cn(e6[10]),e6[6])),ci(e6[10],cg(cn(e6[6]),e6[7])),ci(e6[6],cg(cn(e6[7]),e6[8])),ci(e6[7],cg(cn(e6[8]),e6[9])),ci(e6[8],cg(cn(e6[9]),e6[10]))e6[11],e6[12],e6[13],e6[14],e6[15]=ci(e6[12],cg(cn(e6[13]),e6[14])),ci(e6[13],cg(cn(e6[14]),e6[15])),ci(e6[14],cg(cn(e6[15]),e6[11])),ci(e6[15],cg(cn(e6[11]),e6[12])),ci(e6[11],cg(cn(e6[12]),e6[13]))e6[16],e6[17],e6[18],e6[19],e6[20]=ci(e6[20],cg(cn(e6[16]),e6[17])),ci(e6[16],cg(cn(e6[17]),e6[18])),ci(e6[17],cg(cn(e6[18]),e6[19])),ci(e6[18],cg(cn(e6[19]),e6[20])),ci(e6[19],cg(cn(e6[20]),e6[16]))e6[21],e6[22],e6[23],e6[24],e6[25]=ci(e6[23],cg(cn(e6[24]),e6[25])),ci(e6[24],cg(cn(e6[25]),e6[21])),ci(e6[25],cg(cn(e6[21]),e6[22])),ci(e6[21],cg(cn(e6[22]),e6[23])),ci(e6[22],cg(cn(e6[23]),e6[24]))e7[1],e7[2],e7[3],e7[4],e7[5]=ci(e7[1],cg(cn(e7[2]),e7[3]),e9[dz]),ci(e7[2],cg(cn(e7[3]),e7[4])),ci(e7[3],cg(cn(e7[4]),e7[5])),ci(e7[4],cg(cn(e7[5]),e7[1])),ci(e7[5],cg(cn(e7[1]),e7[2]))e7[6],e7[7],e7[8],e7[9],e7[10]=ci(e7[9],cg(cn(e7[10]),e7[6])),ci(e7[10],cg(cn(e7[6]),e7[7])),ci(e7[6],cg(cn(e7[7]),e7[8])),ci(e7[7],cg(cn(e7[8]),e7[9])),ci(e7[8],cg(cn(e7[9]),e7[10]))e7[11],e7[12],e7[13],e7[14],e7[15]=ci(e7[12],cg(cn(e7[13]),e7[14])),ci(e7[13],cg(cn(e7[14]),e7[15])),ci(e7[14],cg(cn(e7[15]),e7[11])),ci(e7[15],cg(cn(e7[11]),e7[12])),ci(e7[11],cg(cn(e7[12]),e7[13]))e7[16],e7[17],e7[18],e7[19],e7[20]=ci(e7[20],cg(cn(e7[16]),e7[17])),ci(e7[16],cg(cn(e7[17]),e7[18])),ci(e7[17],cg(cn(e7[18]),e7[19])),ci(e7[18],cg(cn(e7[19]),e7[20])),ci(e7[19],cg(cn(e7[20]),e7[16]))e7[21],e7[22],e7[23],e7[24],e7[25]=ci(e7[23],cg(cn(e7[24]),e7[25])),ci(e7[24],cg(cn(e7[25]),e7[21])),ci(e7[25],cg(cn(e7[21]),e7[22])),ci(e7[21],cg(cn(e7[22]),e7[23])),ci(e7[22],cg(cn(e7[23]),e7[24]))end end end end;if cf=="LJ"then function cF(d7,d8,d9,d5)local da,db=cZ,cL;for dc=d9,d9+d5-1,64 do for U=1,16 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=ch(cj(i,24),cj(c9,16),cj(dd,8),de)end;for U=17,64 do local i,c9=da[U-15],da[U-2]da[U]=co(co(ci(cm(i,7),cl(i,14),ck(i,3))+ci(cl(c9,15),cl(c9,13),ck(c9,10)))+co(da[U-7]+da[U-16]))end;local i,c9,dd,de,e,d,df,dg=d7[1],d7[2],d7[3],d7[4],d7[5],d7[6],d7[7],d7[8]for U=1,64,8 do local cC=co(ci(cm(e,6),cm(e,11),cl(e,7))+ci(df,cg(e,ci(d,df)))+db[U]+da[U]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(cm(e,6),cm(e,11),cl(e,7))+ci(df,cg(e,ci(d,df)))+db[U+1]+da[U+1]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(cm(e,6),cm(e,11),cl(e,7))+ci(df,cg(e,ci(d,df)))+db[U+2]+da[U+2]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(cm(e,6),cm(e,11),cl(e,7))+ci(df,cg(e,ci(d,df)))+db[U+3]+da[U+3]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(cm(e,6),cm(e,11),cl(e,7))+ci(df,cg(e,ci(d,df)))+db[U+4]+da[U+4]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(cm(e,6),cm(e,11),cl(e,7))+ci(df,cg(e,ci(d,df)))+db[U+5]+da[U+5]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(cm(e,6),cm(e,11),cl(e,7))+ci(df,cg(e,ci(d,df)))+db[U+6]+da[U+6]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)cC=co(ci(cm(e,6),cm(e,11),cl(e,7))+ci(df,cg(e,ci(d,df)))+db[U+7]+da[U+7]+dg)dg,df,d,e=df,d,e,co(de+cC)de,dd,c9,i=dd,c9,i,co(ci(cg(i,ci(c9,dd)),cg(c9,dd))+ci(cm(i,2),cm(i,13),cl(i,10))+cC)end;d7[1],d7[2],d7[3],d7[4]=co(i+d7[1]),co(c9+d7[2]),co(dd+d7[3]),co(de+d7[4])d7[5],d7[6],d7[7],d7[8]=co(e+d7[5]),co(d+d7[6]),co(df+d7[7]),co(dg+d7[8])end end;local function ed(dH,dI,dM,dN,e1,e2,ee,ef)local eg=dH%2^32+dM%2^32+e1%2^32+ee%2^32;local eh=dI+dN+e2+ef;local dZ=co(eg)local d_=co(eh+f(eg/2^32))return dZ,d_ end;if c7=="x86"then function cG(ei,ej,d8,d9,d5)local da,ek,el=cZ,cK,cL;for dc=d9,d9+d5-1,128 do for U=1,16*2 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=ch(cj(i,24),cj(c9,16),cj(dd,8),de)end;for em=17*2,80*2,2 do local dH,dI=da[em-30],da[em-31]local dJ=ci(ch(ck(dH,1),cj(dI,31)),ch(ck(dH,8),cj(dI,24)),ch(ck(dH,7),cj(dI,25)))local dK=ci(ch(ck(dI,1),cj(dH,31)),ch(ck(dI,8),cj(dH,24)),ck(dI,7))local dM,dN=da[em-4],da[em-5]local dO=ci(ch(ck(dM,19),cj(dN,13)),ch(cj(dM,3),ck(dN,29)),ch(ck(dM,6),cj(dN,26)))local dP=ci(ch(ck(dN,19),cj(dM,13)),ch(cj(dN,3),ck(dM,29)),ck(dN,6))da[em],da[em-1]=ed(dJ,dK,dO,dP,da[em-14],da[em-15],da[em-32],da[em-33])end;local dH,dM,e1,ee,dR,dV,dX,en=ei[1],ei[2],ei[3],ei[4],ei[5],ei[6],ei[7],ei[8]local dI,dN,e2,ef,dS,dW,dY,eo=ej[1],ej[2],ej[3],ej[4],ej[5],ej[6],ej[7],ej[8]local ep=0;for U=1,80 do local dJ=ci(dX,cg(dR,ci(dV,dX)))local dK=ci(dY,cg(dS,ci(dW,dY)))local dO=ci(ch(ck(dR,14),cj(dS,18)),ch(ck(dR,18),cj(dS,14)),ch(cj(dR,23),ck(dS,9)))local dP=ci(ch(ck(dS,14),cj(dR,18)),ch(ck(dS,18),cj(dR,14)),ch(cj(dS,23),ck(dR,9)))local eg=dO%2^32+dJ%2^32+en%2^32+ek[U]+da[2*U]%2^32;local eq,er=co(eg),co(dP+dK+eo+el[U]+da[2*U-1]+f(eg/2^32))ep=ep+ep;en,eo,dX,dY,dV,dW=ch(ep,dX),ch(ep,dY),ch(ep,dV),ch(ep,dW),ch(ep,dR),ch(ep,dS)local eg=eq%2^32+ee%2^32;dR,dS=co(eg),co(er+ef+f(eg/2^32))ee,ef,e1,e2,dM,dN=ch(ep,e1),ch(ep,e2),ch(ep,dM),ch(ep,dN),ch(ep,dH),ch(ep,dI)dO=ci(ch(ck(dM,28),cj(dN,4)),ch(cj(dM,30),ck(dN,2)),ch(cj(dM,25),ck(dN,7)))dP=ci(ch(ck(dN,28),cj(dM,4)),ch(cj(dN,30),ck(dM,2)),ch(cj(dN,25),ck(dM,7)))dJ=ch(cg(ee,e1),cg(dM,ci(ee,e1)))dK=ch(cg(ef,e2),cg(dN,ci(ef,e2)))local eg=eq%2^32+dJ%2^32+dO%2^32;dH,dI=co(eg),co(er+dK+dP+f(eg/2^32))end;ei[1],ej[1]=ed(ei[1],ej[1],dH,dI,0,0,0,0)ei[2],ej[2]=ed(ei[2],ej[2],dM,dN,0,0,0,0)ei[3],ej[3]=ed(ei[3],ej[3],e1,e2,0,0,0,0)ei[4],ej[4]=ed(ei[4],ej[4],ee,ef,0,0,0,0)ei[5],ej[5]=ed(ei[5],ej[5],dR,dS,0,0,0,0)ei[6],ej[6]=ed(ei[6],ej[6],dV,dW,0,0,0,0)ei[7],ej[7]=ed(ei[7],ej[7],dX,dY,0,0,0,0)ei[8],ej[8]=ed(ei[8],ej[8],en,eo,0,0,0,0)end end else function cG(ei,ej,d8,d9,d5)local da,ek,el=cZ,cK,cL;for dc=d9,d9+d5-1,128 do for U=1,16*2 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=ch(cj(i,24),cj(c9,16),cj(dd,8),de)end;for em=17*2,80*2,2 do local dH,dI=da[em-30],da[em-31]local dJ=ci(ch(ck(dH,1),cj(dI,31)),ch(ck(dH,8),cj(dI,24)),ch(ck(dH,7),cj(dI,25)))local dK=ci(ch(ck(dI,1),cj(dH,31)),ch(ck(dI,8),cj(dH,24)),ck(dI,7))local dM,dN=da[em-4],da[em-5]local dO=ci(ch(ck(dM,19),cj(dN,13)),ch(cj(dM,3),ck(dN,29)),ch(ck(dM,6),cj(dN,26)))local dP=ci(ch(ck(dN,19),cj(dM,13)),ch(cj(dN,3),ck(dM,29)),ck(dN,6))da[em],da[em-1]=ed(dJ,dK,dO,dP,da[em-14],da[em-15],da[em-32],da[em-33])end;local dH,dM,e1,ee,dR,dV,dX,en=ei[1],ei[2],ei[3],ei[4],ei[5],ei[6],ei[7],ei[8]local dI,dN,e2,ef,dS,dW,dY,eo=ej[1],ej[2],ej[3],ej[4],ej[5],ej[6],ej[7],ej[8]for U=1,80 do local dJ=ci(dX,cg(dR,ci(dV,dX)))local dK=ci(dY,cg(dS,ci(dW,dY)))local dO=ci(ch(ck(dR,14),cj(dS,18)),ch(ck(dR,18),cj(dS,14)),ch(cj(dR,23),ck(dS,9)))local dP=ci(ch(ck(dS,14),cj(dR,18)),ch(ck(dS,18),cj(dR,14)),ch(cj(dS,23),ck(dR,9)))local eg=dO%2^32+dJ%2^32+en%2^32+ek[U]+da[2*U]%2^32;local eq,er=co(eg),co(dP+dK+eo+el[U]+da[2*U-1]+f(eg/2^32))en,eo,dX,dY,dV,dW=dX,dY,dV,dW,dR,dS;local eg=eq%2^32+ee%2^32;dR,dS=co(eg),co(er+ef+f(eg/2^32))ee,ef,e1,e2,dM,dN=e1,e2,dM,dN,dH,dI;dO=ci(ch(ck(dM,28),cj(dN,4)),ch(cj(dM,30),ck(dN,2)),ch(cj(dM,25),ck(dN,7)))dP=ci(ch(ck(dN,28),cj(dM,4)),ch(cj(dN,30),ck(dM,2)),ch(cj(dN,25),ck(dM,7)))dJ=ch(cg(ee,e1),cg(dM,ci(ee,e1)))dK=ch(cg(ef,e2),cg(dN,ci(ef,e2)))local eg=eq%2^32+dO%2^32+dJ%2^32;dH,dI=co(eg),co(er+dP+dK+f(eg/2^32))end;ei[1],ej[1]=ed(ei[1],ej[1],dH,dI,0,0,0,0)ei[2],ej[2]=ed(ei[2],ej[2],dM,dN,0,0,0,0)ei[3],ej[3]=ed(ei[3],ej[3],e1,e2,0,0,0,0)ei[4],ej[4]=ed(ei[4],ej[4],ee,ef,0,0,0,0)ei[5],ej[5]=ed(ei[5],ej[5],dR,dS,0,0,0,0)ei[6],ej[6]=ed(ei[6],ej[6],dV,dW,0,0,0,0)ei[7],ej[7]=ed(ei[7],ej[7],dX,dY,0,0,0,0)ei[8],ej[8]=ed(ei[8],ej[8],en,eo,0,0,0,0)end end end;function cH(d7,d8,d9,d5)local da,db=cZ,cT;for dc=d9,d9+d5-1,64 do for U=1,16 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=ch(cj(de,24),cj(dd,16),cj(c9,8),i)end;local i,c9,dd,de=d7[1],d7[2],d7[3],d7[4]for U=1,16,4 do i,de,dd,c9=de,dd,c9,co(cl(ci(de,cg(c9,ci(dd,de)))+db[U]+da[U]+i,7)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(de,cg(c9,ci(dd,de)))+db[U+1]+da[U+1]+i,12)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(de,cg(c9,ci(dd,de)))+db[U+2]+da[U+2]+i,17)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(de,cg(c9,ci(dd,de)))+db[U+3]+da[U+3]+i,22)+c9)end;for U=17,32,4 do local df=5*U-4;i,de,dd,c9=de,dd,c9,co(cl(ci(dd,cg(de,ci(c9,dd)))+db[U]+da[cg(df,15)+1]+i,5)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,cg(de,ci(c9,dd)))+db[U+1]+da[cg(df+5,15)+1]+i,9)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,cg(de,ci(c9,dd)))+db[U+2]+da[cg(df+10,15)+1]+i,14)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,cg(de,ci(c9,dd)))+db[U+3]+da[cg(df-1,15)+1]+i,20)+c9)end;for U=33,48,4 do local df=3*U+2;i,de,dd,c9=de,dd,c9,co(cl(ci(c9,dd,de)+db[U]+da[cg(df,15)+1]+i,4)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(c9,dd,de)+db[U+1]+da[cg(df+3,15)+1]+i,11)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(c9,dd,de)+db[U+2]+da[cg(df+6,15)+1]+i,16)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(c9,dd,de)+db[U+3]+da[cg(df-7,15)+1]+i,23)+c9)end;for U=49,64,4 do local df=U*7;i,de,dd,c9=de,dd,c9,co(cl(ci(dd,ch(c9,cn(de)))+db[U]+da[cg(df-7,15)+1]+i,6)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,ch(c9,cn(de)))+db[U+1]+da[cg(df,15)+1]+i,10)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,ch(c9,cn(de)))+db[U+2]+da[cg(df+7,15)+1]+i,15)+c9)i,de,dd,c9=de,dd,c9,co(cl(ci(dd,ch(c9,cn(de)))+db[U+3]+da[cg(df-2,15)+1]+i,21)+c9)end;d7[1],d7[2],d7[3],d7[4]=co(i+d7[1]),co(c9+d7[2]),co(dd+d7[3]),co(de+d7[4])end end;function cI(d7,d8,d9,d5)local da=cZ;for dc=d9,d9+d5-1,64 do for U=1,16 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=ch(cj(i,24),cj(c9,16),cj(dd,8),de)end;for U=17,80 do da[U]=cl(ci(da[U-3],da[U-8],da[U-14],da[U-16]),1)end;local i,c9,dd,de,e=d7[1],d7[2],d7[3],d7[4],d7[5]for U=1,20,5 do e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U]+0x5A827999+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U+1]+0x5A827999+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U+2]+0x5A827999+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U+3]+0x5A827999+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(de,cg(c9,ci(de,dd)))+da[U+4]+0x5A827999+e)end;for U=21,40,5 do e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U]+0x6ED9EBA1+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+1]+0x6ED9EBA1+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+2]+0x6ED9EBA1+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+3]+0x6ED9EBA1+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+4]+0x6ED9EBA1+e)end;for U=41,60,5 do e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U]+0x8F1BBCDC+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U+1]+0x8F1BBCDC+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U+2]+0x8F1BBCDC+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U+3]+0x8F1BBCDC+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(cg(de,ci(c9,dd)),cg(c9,dd))+da[U+4]+0x8F1BBCDC+e)end;for U=61,80,5 do e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U]+0xCA62C1D6+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+1]+0xCA62C1D6+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+2]+0xCA62C1D6+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+3]+0xCA62C1D6+e)e,de,dd,c9,i=de,dd,cm(c9,2),i,co(cl(i,5)+ci(c9,dd,de)+da[U+4]+0xCA62C1D6+e)end;d7[1],d7[2],d7[3],d7[4],d7[5]=co(i+d7[1]),co(c9+d7[2]),co(dd+d7[3]),co(de+d7[4]),co(e+d7[5])end end end;if cf=="INT64"then d0=4294967296;d1=4294967296;cY=1;cW,cX,cq,cF,cG,cH,cI,cJ=load[[local a,b,c,d,e,f=...local g,h=string.format,string.unpack;local function i(j)return g("%016x",j)end;local function k(j)return j~0xa5a5a5a5a5a5a5a5 end;local function l(j,m)return j~m end;local n={}local function o(p,q,r,s)local t,u=n,d;local v,w,x,y,z,A,B,C=p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4",q,D)for E=17,64 do local F=t[E-15]F=F<<32|F;local G=t[E-2]G=G<<32|G;t[E]=F>>7~(F>>18)~(F>>35)+G>>17~(G>>19)~(G>>42)+t[E-7]+t[E-16]&1<<32-1 end;local F,G,H,I,J,K,L,M=v,w,x,y,z,A,B,C;for E=1,64 do J=J<<32|(J&1<<32-1)local N=J>>6~(J>>11)~(J>>25)+L~(J&(K~L))+M+u[E]+t[E]M=L;L=K;K=J;J=N+I;I=H;H=G;G=F;F=F<<32|(F&1<<32-1)F=N+F~H&I~(F&H)+F>>2~(F>>13)~(F>>22)end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z;A=K+A;B=L+B;C=M+C end;p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]=v,w,x,y,z,A,B,C end;local function O(p,P,q,r,s)local t,u=n,c;local v,w,x,y,z,A,B,C=p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]for D=r+1,r+s,128 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">i8i8i8i8i8i8i8i8i8i8i8i8i8i8i8i8",q,D)for E=17,80 do local F=t[E-15]local G=t[E-2]t[E]=F>>1~(F>>7)~(F>>8)~(F<<56)~(F<<63)+G>>6~(G>>19)~(G>>61)~(G<<3)~(G<<45)+t[E-7]+t[E-16]end;local F,G,H,I,J,K,L,M=v,w,x,y,z,A,B,C;for E=1,80 do local N=J>>14~(J>>18)~(J>>41)~(J<<23)~(J<<46)~(J<<50)+L~(J&(K~L))+M+u[E]+t[E]M=L;L=K;K=J;J=N+I;I=H;H=G;G=F;F=N+F~H&I~(F&H)+F>>28~(F>>34)~(F>>39)~(F<<25)~(F<<30)~(F<<36)end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z;A=K+A;B=L+B;C=M+C end;p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]=v,w,x,y,z,A,B,C end;local function Q(p,q,r,s)local t,u,a=n,b,a;local v,w,x,y=p[1],p[2],p[3],p[4]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h("<I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4",q,D)local F,G,H,I=v,w,x,y;local R=32-7;for E=1,16 do local S=I~(G&(H~I))+F+u[E]+t[E]F=I;I=H;H=G;G=S<<32|(S&1<<32-1)>>R+G;R=a[R]end;R=32-5;for E=17,32 do local S=H~(I&(G~H))+F+u[E]+t[5*E-4&15+1]F=I;I=H;H=G;G=S<<32|(S&1<<32-1)>>R+G;R=a[R]end;R=32-4;for E=33,48 do local S=G~H~I+F+u[E]+t[3*E+2&15+1]F=I;I=H;H=G;G=S<<32|(S&1<<32-1)>>R+G;R=a[R]end;R=32-6;for E=49,64 do local S=H~(G|~I)+F+u[E]+t[E*7-7&15+1]F=I;I=H;H=G;G=S<<32|(S&1<<32-1)>>R+G;R=a[R]end;v=F+v;w=G+w;x=H+x;y=I+y end;p[1],p[2],p[3],p[4]=v,w,x,y end;local function T(p,q,r,s)local t=n;local v,w,x,y,z=p[1],p[2],p[3],p[4],p[5]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4",q,D)for E=17,80 do local F=t[E-3]~t[E-8]~t[E-14]~t[E-16]t[E]=F<<32|F<<1>>32 end;local F,G,H,I,J=v,w,x,y,z;for E=1,20 do local N=F<<32|(F&1<<32-1)>>27+I~(G&(H~I))+0x5A827999+t[E]+J;J=I;I=H;H=G<<32|(G&1<<32-1)>>2;G=F;F=N end;for E=21,40 do local N=F<<32|(F&1<<32-1)>>27+G~H~I+0x6ED9EBA1+t[E]+J;J=I;I=H;H=G<<32|(G&1<<32-1)>>2;G=F;F=N end;for E=41,60 do local N=F<<32|(F&1<<32-1)>>27+G~H&I~(G&H)+0x8F1BBCDC+t[E]+J;J=I;I=H;H=G<<32|(G&1<<32-1)>>2;G=F;F=N end;for E=61,80 do local N=F<<32|(F&1<<32-1)>>27+G~H~I+0xCA62C1D6+t[E]+J;J=I;I=H;H=G<<32|(G&1<<32-1)>>2;G=F;F=N end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z end;p[1],p[2],p[3],p[4],p[5]=v,w,x,y,z end;local U=e("i8")local function V(W,P,q,r,s,X)local Y=f;local Z=X/8;local _=U[Z]for D=r+1,r+s,X do local a0={h(_,q,D)}for E=1,Z do W[E]=W[E]~a0[E]end;local a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an,ao,ap=W[1],W[2],W[3],W[4],W[5],W[6],W[7],W[8],W[9],W[10],W[11],W[12],W[13],W[14],W[15],W[16],W[17],W[18],W[19],W[20],W[21],W[22],W[23],W[24],W[25]for aq=1,24 do local ar=a1~a6~ab~ag~al;local as=a2~a7~ac~ah~am;local at=a3~a8~ad~ai~an;local au=a4~a9~ae~aj~ao;local av=a5~aa~af~ak~ap;local aw=ar~(at<<1)~(at>>63)local ax=aw~a2;local ay=aw~a7;local az=aw~ac;local aA=aw~ah;local aB=aw~am;a2=ay<<44~(ay>>20)a7=aA<<45~(aA>>19)ac=ax<<1~(ax>>63)ah=az<<10~(az>>54)am=aB<<2~(aB>>62)aw=as~(au<<1)~(au>>63)ax=aw~a3;ay=aw~a8;az=aw~ad;aA=aw~ai;aB=aw~an;a3=az<<43~(az>>21)a8=aB<<61~(aB>>3)ad=ay<<6~(ay>>58)ai=aA<<15~(aA>>49)an=ax<<62~(ax>>2)aw=at~(av<<1)~(av>>63)ax=aw~a4;ay=aw~a9;az=aw~ae;aA=aw~aj;aB=aw~ao;a4=aA<<21~(aA>>43)a9=ax<<28~(ax>>36)ae=az<<25~(az>>39)aj=aB<<56~(aB>>8)ao=ay<<55~(ay>>9)aw=au~(ar<<1)~(ar>>63)ax=aw~a5;ay=aw~aa;az=aw~af;aA=aw~ak;aB=aw~ap;a5=aB<<14~(aB>>50)aa=ay<<20~(ay>>44)af=aA<<8~(aA>>56)ak=ax<<27~(ax>>37)ap=az<<39~(az>>25)aw=av~(as<<1)~(as>>63)ay=aw~a6;az=aw~ab;aA=aw~ag;aB=aw~al;a6=az<<3~(az>>61)ab=aB<<18~(aB>>46)ag=ay<<36~(ay>>28)al=aA<<41~(aA>>23)a1=aw~a1;a1,a2,a3,a4,a5=a1~(~a2&a3),a2~(~a3&a4),a3~(~a4&a5),a4~(~a5&a1),a5~(~a1&a2)a6,a7,a8,a9,aa=a9~(~aa&a6),aa~(~a6&a7),a6~(~a7&a8),a7~(~a8&a9),a8~(~a9&aa)ab,ac,ad,ae,af=ac~(~ad&ae),ad~(~ae&af),ae~(~af&ab),af~(~ab&ac),ab~(~ac&ad)ag,ah,ai,aj,ak=ak~(~ag&ah),ag~(~ah&ai),ah~(~ai&aj),ai~(~aj&ak),aj~(~ak&ag)al,am,an,ao,ap=an~(~ao&ap),ao~(~ap&al),ap~(~al&am),al~(~am&an),am~(~an&ao)a1=a1~Y[aq]end;W[1]=a1;W[2]=a2;W[3]=a3;W[4]=a4;W[5]=a5;W[6]=a6;W[7]=a7;W[8]=a8;W[9]=a9;W[10]=aa;W[11]=ab;W[12]=ac;W[13]=ad;W[14]=ae;W[15]=af;W[16]=ag;W[17]=ah;W[18]=ai;W[19]=aj;W[20]=ak;W[21]=al;W[22]=am;W[23]=an;W[24]=ao;W[25]=ap end end;return i,k,l,o,O,Q,T,V]](cV,cT,cK,cL,d2,cO)end;if cf=="INT32"then c_=2^32;function cp(aN)return bS("%08x",aN)end;cD,cq,cF,cG,cH,cI,cJ=load[[local a,b,c,d,e,f,g=...local h,i=string.unpack,math.floor;local function j(k)return k~0xA5A5A5A5 end;local function l(k,m)return k~m end;local n={}local function o(p,q,r,s)local t,u=n,d;local v,w,x,y,z,A,B,C=p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4",q,D)for E=17,64 do local F,G=t[E-15],t[E-2]t[E]=F>>7~(F<<25)~(F<<14)~(F>>18)~(F>>3)+G<<15~(G>>17)~(G<<13)~(G>>19)~(G>>10)+t[E-7]+t[E-16]end;local F,G,H,I,J,K,L,M=v,w,x,y,z,A,B,C;for E=1,64 do local N=J>>6~(J<<26)~(J>>11)~(J<<21)~(J>>25)~(J<<7)+L~(J&(K~L))+M+u[E]+t[E]M=L;L=K;K=J;J=N+I;I=H;H=G;G=F;F=N+F~H&I~(F&H)+F>>2~(F<<30)~(F>>13)~(F<<19)~(F<<10)~(F>>22)end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z;A=K+A;B=L+B;C=M+C end;p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]=v,w,x,y,z,A,B,C end;local function O(P,Q,q,r,s)local i,t,R,S=i,n,c,d;local T,U,V,W,X,Y,Z,_=P[1],P[2],P[3],P[4],P[5],P[6],P[7],P[8]local a0,a1,a2,a3,a4,a5,a6,a7=Q[1],Q[2],Q[3],Q[4],Q[5],Q[6],Q[7],Q[8]for D=r+1,r+s,128 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16],t[17],t[18],t[19],t[20],t[21],t[22],t[23],t[24],t[25],t[26],t[27],t[28],t[29],t[30],t[31],t[32]=h(">i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4",q,D)for a8=17*2,80*2,2 do local a9,aa,ab,ac=t[a8-30],t[a8-31],t[a8-4],t[a8-5]local ad=a9>>1~(aa<<31)~(a9>>8)~(aa<<24)~(a9>>7)~(aa<<25)%2^32+ab>>19~(ac<<13)~(ab<<3)~(ac>>29)~(ab>>6)~(ac<<26)%2^32+t[a8-14]%2^32+t[a8-32]%2^32;t[a8-1]=aa>>1~(a9<<31)~(aa>>8)~(a9<<24)~(aa>>7)+ac>>19~(ab<<13)~(ac<<3)~(ab>>29)~(ac>>6)+t[a8-15]+t[a8-33]+i(ad/2^32)t[a8]=0|(ad+2^31)%2^32-2^31 end;local a9,ab,ae,af,ag,ah,ai,aj=T,U,V,W,X,Y,Z,_;local aa,ac,ak,al,am,an,ao,ap=a0,a1,a2,a3,a4,a5,a6,a7;for E=1,80 do local a8=2*E;local aq=ag>>14~(am<<18)~(ag>>18)~(am<<14)~(ag<<23)~(am>>9)%2^32+ai~(ag&(ah~ai))%2^32+aj%2^32+R[E]+t[a8]%2^32;local ar=am>>14~(ag<<18)~(am>>18)~(ag<<14)~(am<<23)~(ag>>9)+ao~(am&(an~ao))+ap+S[E]+t[a8-1]+i(aq/2^32)aq=aq%2^32;aj=ai;ap=ao;ai=ah;ao=an;ah=ag;an=am;ag=aq+af%2^32;am=ar+al+i(ag/2^32)ag=0|(ag+2^31)%2^32-2^31;af=ae;al=ak;ae=ab;ak=ac;ab=a9;ac=aa;aq=aq+af&ae~(ab&(af~ae))%2^32+ab>>28~(ac<<4)~(ab<<30)~(ac>>2)~(ab<<25)~(ac>>7)%2^32;aa=ar+al&ak~(ac&(al~ak))+ac>>28~(ab<<4)~(ac<<30)~(ab>>2)~(ac<<25)~(ab>>7)+i(aq/2^32)a9=0|(aq+2^31)%2^32-2^31 end;a9=T%2^32+a9%2^32;a0=a0+aa+i(a9/2^32)T=0|(a9+2^31)%2^32-2^31;a9=U%2^32+ab%2^32;a1=a1+ac+i(a9/2^32)U=0|(a9+2^31)%2^32-2^31;a9=V%2^32+ae%2^32;a2=a2+ak+i(a9/2^32)V=0|(a9+2^31)%2^32-2^31;a9=W%2^32+af%2^32;a3=a3+al+i(a9/2^32)W=0|(a9+2^31)%2^32-2^31;a9=X%2^32+ag%2^32;a4=a4+am+i(a9/2^32)X=0|(a9+2^31)%2^32-2^31;a9=Y%2^32+ah%2^32;a5=a5+an+i(a9/2^32)Y=0|(a9+2^31)%2^32-2^31;a9=Z%2^32+ai%2^32;a6=a6+ao+i(a9/2^32)Z=0|(a9+2^31)%2^32-2^31;a9=_%2^32+aj%2^32;a7=a7+ap+i(a9/2^32)_=0|(a9+2^31)%2^32-2^31 end;P[1],P[2],P[3],P[4],P[5],P[6],P[7],P[8]=T,U,V,W,X,Y,Z,_;Q[1],Q[2],Q[3],Q[4],Q[5],Q[6],Q[7],Q[8]=a0,a1,a2,a3,a4,a5,a6,a7 end;local function as(p,q,r,s)local t,u,a=n,b,a;local v,w,x,y=p[1],p[2],p[3],p[4]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h("<i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4",q,D)local F,G,H,I=v,w,x,y;local at=32-7;for E=1,16 do local au=I~(G&(H~I))+F+u[E]+t[E]F=I;I=H;H=G;G=au<<32-at|(au>>at)+G;at=a[at]end;at=32-5;for E=17,32 do local au=H~(I&(G~H))+F+u[E]+t[5*E-4&15+1]F=I;I=H;H=G;G=au<<32-at|(au>>at)+G;at=a[at]end;at=32-4;for E=33,48 do local au=G~H~I+F+u[E]+t[3*E+2&15+1]F=I;I=H;H=G;G=au<<32-at|(au>>at)+G;at=a[at]end;at=32-6;for E=49,64 do local au=H~(G|~I)+F+u[E]+t[E*7-7&15+1]F=I;I=H;H=G;G=au<<32-at|(au>>at)+G;at=a[at]end;v=F+v;w=G+w;x=H+x;y=I+y end;p[1],p[2],p[3],p[4]=v,w,x,y end;local function av(p,q,r,s)local t=n;local v,w,x,y,z=p[1],p[2],p[3],p[4],p[5]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4",q,D)for E=17,80 do local F=t[E-3]~t[E-8]~t[E-14]~t[E-16]t[E]=F<<1~(F>>31)end;local F,G,H,I,J=v,w,x,y,z;for E=1,20 do local N=F<<5~(F>>27)+I~(G&(H~I))+0x5A827999+t[E]+J;J=I;I=H;H=G<<30~(G>>2)G=F;F=N end;for E=21,40 do local N=F<<5~(F>>27)+G~H~I+0x6ED9EBA1+t[E]+J;J=I;I=H;H=G<<30~(G>>2)G=F;F=N end;for E=41,60 do local N=F<<5~(F>>27)+G~H&I~(G&H)+0x8F1BBCDC+t[E]+J;J=I;I=H;H=G<<30~(G>>2)G=F;F=N end;for E=61,80 do local N=F<<5~(F>>27)+G~H~I+0xCA62C1D6+t[E]+J;J=I;I=H;H=G<<30~(G>>2)G=F;F=N end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z end;p[1],p[2],p[3],p[4],p[5]=v,w,x,y,z end;local aw=e("i4i4")local function ax(ay,az,q,r,s,aA)local aB,aC=f,g;local aD=aA/8;local aE=aw[aD]for D=r+1,r+s,aA do local aF={h(aE,q,D)}for E=1,aD do ay[E]=ay[E]~aF[2*E-1]az[E]=az[E]~aF[2*E]end;local aG,aH,aI,aJ,aK,aL,aM,aN,aO,aP,aQ,aR,aS,aT,aU,aV,aW,aX,aY,aZ,a_,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf,bg,bh,bi,bj,bk,bl,bm,bn,bo,bp,bq,br,bs=ay[1],az[1],ay[2],az[2],ay[3],az[3],ay[4],az[4],ay[5],az[5],ay[6],az[6],ay[7],az[7],ay[8],az[8],ay[9],az[9],ay[10],az[10],ay[11],az[11],ay[12],az[12],ay[13],az[13],ay[14],az[14],ay[15],az[15],ay[16],az[16],ay[17],az[17],ay[18],az[18],ay[19],az[19],ay[20],az[20],ay[21],az[21],ay[22],az[22],ay[23],az[23],ay[24],az[24],ay[25],az[25]for bt=1,24 do local bu=aG~aQ~a_~b9~bj;local bv=aH~aR~b0~ba~bk;local bw=aI~aS~b1~bb~bl;local bx=aJ~aT~b2~bc~bm;local by=aK~aU~b3~bd~bn;local bz=aL~aV~b4~be~bo;local bA=aM~aW~b5~bf~bp;local bB=aN~aX~b6~bg~bq;local bC=aO~aY~b7~bh~br;local bD=aP~aZ~b8~bi~bs;local bE=bu~(by<<1)~(bz>>31)local bF=bv~(bz<<1)~(by>>31)local bG=bE~aI;local bH=bF~aJ;local bI=bE~aS;local bJ=bF~aT;local bK=bE~b1;local bL=bF~b2;local bM=bE~bb;local bN=bF~bc;local bO=bE~bl;local bP=bF~bm;aI=bI>>20~(bJ<<12)aJ=bJ>>20~(bI<<12)aS=bM>>19~(bN<<13)aT=bN>>19~(bM<<13)b1=bG<<1~(bH>>31)b2=bH<<1~(bG>>31)bb=bK<<10~(bL>>22)bc=bL<<10~(bK>>22)bl=bO<<2~(bP>>30)bm=bP<<2~(bO>>30)bE=bw~(bA<<1)~(bB>>31)bF=bx~(bB<<1)~(bA>>31)bG=bE~aK;bH=bF~aL;bI=bE~aU;bJ=bF~aV;bK=bE~b3;bL=bF~b4;bM=bE~bd;bN=bF~be;bO=bE~bn;bP=bF~bo;aK=bK>>21~(bL<<11)aL=bL>>21~(bK<<11)aU=bO>>3~(bP<<29)aV=bP>>3~(bO<<29)b3=bI<<6~(bJ>>26)b4=bJ<<6~(bI>>26)bd=bM<<15~(bN>>17)be=bN<<15~(bM>>17)bn=bG>>2~(bH<<30)bo=bH>>2~(bG<<30)bE=by~(bC<<1)~(bD>>31)bF=bz~(bD<<1)~(bC>>31)bG=bE~aM;bH=bF~aN;bI=bE~aW;bJ=bF~aX;bK=bE~b5;bL=bF~b6;bM=bE~bf;bN=bF~bg;bO=bE~bp;bP=bF~bq;aM=bM<<21~(bN>>11)aN=bN<<21~(bM>>11)aW=bG<<28~(bH>>4)aX=bH<<28~(bG>>4)b5=bK<<25~(bL>>7)b6=bL<<25~(bK>>7)bf=bO>>8~(bP<<24)bg=bP>>8~(bO<<24)bp=bI>>9~(bJ<<23)bq=bJ>>9~(bI<<23)bE=bA~(bu<<1)~(bv>>31)bF=bB~(bv<<1)~(bu>>31)bG=bE~aO;bH=bF~aP;bI=bE~aY;bJ=bF~aZ;bK=bE~b7;bL=bF~b8;bM=bE~bh;bN=bF~bi;bO=bE~br;bP=bF~bs;aO=bO<<14~(bP>>18)aP=bP<<14~(bO>>18)aY=bI<<20~(bJ>>12)aZ=bJ<<20~(bI>>12)b7=bM<<8~(bN>>24)b8=bN<<8~(bM>>24)bh=bG<<27~(bH>>5)bi=bH<<27~(bG>>5)br=bK>>25~(bL<<7)bs=bL>>25~(bK<<7)bE=bC~(bw<<1)~(bx>>31)bF=bD~(bx<<1)~(bw>>31)bI=bE~aQ;bJ=bF~aR;bK=bE~a_;bL=bF~b0;bM=bE~b9;bN=bF~ba;bO=bE~bj;bP=bF~bk;aQ=bK<<3~(bL>>29)aR=bL<<3~(bK>>29)a_=bO<<18~(bP>>14)b0=bP<<18~(bO>>14)b9=bI>>28~(bJ<<4)ba=bJ>>28~(bI<<4)bj=bM>>23~(bN<<9)bk=bN>>23~(bM<<9)aG=bE~aG;aH=bF~aH;aG,aI,aK,aM,aO=aG~(~aI&aK),aI~(~aK&aM),aK~(~aM&aO),aM~(~aO&aG),aO~(~aG&aI)aH,aJ,aL,aN,aP=aH~(~aJ&aL),aJ~(~aL&aN),aL~(~aN&aP),aN~(~aP&aH),aP~(~aH&aJ)aQ,aS,aU,aW,aY=aW~(~aY&aQ),aY~(~aQ&aS),aQ~(~aS&aU),aS~(~aU&aW),aU~(~aW&aY)aR,aT,aV,aX,aZ=aX~(~aZ&aR),aZ~(~aR&aT),aR~(~aT&aV),aT~(~aV&aX),aV~(~aX&aZ)a_,b1,b3,b5,b7=b1~(~b3&b5),b3~(~b5&b7),b5~(~b7&a_),b7~(~a_&b1),a_~(~b1&b3)b0,b2,b4,b6,b8=b2~(~b4&b6),b4~(~b6&b8),b6~(~b8&b0),b8~(~b0&b2),b0~(~b2&b4)b9,bb,bd,bf,bh=bh~(~b9&bb),b9~(~bb&bd),bb~(~bd&bf),bd~(~bf&bh),bf~(~bh&b9)ba,bc,be,bg,bi=bi~(~ba&bc),ba~(~bc&be),bc~(~be&bg),be~(~bg&bi),bg~(~bi&ba)bj,bl,bn,bp,br=bn~(~bp&br),bp~(~br&bj),br~(~bj&bl),bj~(~bl&bn),bl~(~bn&bp)bk,bm,bo,bq,bs=bo~(~bq&bs),bq~(~bs&bk),bs~(~bk&bm),bk~(~bm&bo),bm~(~bo&bq)aG=aG~aB[bt]aH=aH~aC[bt]end;ay[1]=aG;az[1]=aH;ay[2]=aI;az[2]=aJ;ay[3]=aK;az[3]=aL;ay[4]=aM;az[4]=aN;ay[5]=aO;az[5]=aP;ay[6]=aQ;az[6]=aR;ay[7]=aS;az[7]=aT;ay[8]=aU;az[8]=aV;ay[9]=aW;az[9]=aX;ay[10]=aY;az[10]=aZ;ay[11]=a_;az[11]=b0;ay[12]=b1;az[12]=b2;ay[13]=b3;az[13]=b4;ay[14]=b5;az[14]=b6;ay[15]=b7;az[15]=b8;ay[16]=b9;az[16]=ba;ay[17]=bb;az[17]=bc;ay[18]=bd;az[18]=be;ay[19]=bf;az[19]=bg;ay[20]=bh;az[20]=bi;ay[21]=bj;az[21]=bk;ay[22]=bl;az[22]=bm;ay[23]=bn;az[23]=bo;ay[24]=bp;az[24]=bq;ay[25]=br;az[25]=bs end end;return j,l,o,O,as,av,ax]](cV,cT,cK,cL,d2,cO,cP)end;if cf=="LIB32"or cf=="EMUL"then function cF(d7,d8,d9,d5)local da,db=cZ,cL;local es,et,eu,ev,ew,ex,ey,ez=d7[1],d7[2],d7[3],d7[4],d7[5],d7[6],d7[7],d7[8]for dc=d9,d9+d5-1,64 do for U=1,16 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=((i*256+c9)*256+dd)*256+de end;for U=17,64 do local i,c9=da[U-15],da[U-2]da[U]=ci(cm(i,7),cl(i,14),ck(i,3))+ci(cl(c9,15),cl(c9,13),ck(c9,10))+da[U-7]+da[U-16]end;local i,c9,dd,de,e,d,df,dg=es,et,eu,ev,ew,ex,ey,ez;for U=1,64 do local cC=ci(cm(e,6),cm(e,11),cl(e,7))+cg(e,d)+cg(-1-e,df)+dg+db[U]+da[U]dg=df;df=d;d=e;e=cC+de;de=dd;dd=c9;c9=i;i=cC+cg(de,dd)+cg(i,ci(de,dd))+ci(cm(i,2),cm(i,13),cl(i,10))end;es,et,eu,ev=(i+es)%4294967296,(c9+et)%4294967296,(dd+eu)%4294967296,(de+ev)%4294967296;ew,ex,ey,ez=(e+ew)%4294967296,(d+ex)%4294967296,(df+ey)%4294967296,(dg+ez)%4294967296 end;d7[1],d7[2],d7[3],d7[4],d7[5],d7[6],d7[7],d7[8]=es,et,eu,ev,ew,ex,ey,ez end;function cG(ei,ej,d8,d9,d5)local da,ek,el=cZ,cK,cL;local eA,eB,eC,eD,eE,eF,eG,eH=ei[1],ei[2],ei[3],ei[4],ei[5],ei[6],ei[7],ei[8]local eI,eJ,eK,eL,eM,eN,eO,eP=ej[1],ej[2],ej[3],ej[4],ej[5],ej[6],ej[7],ej[8]for dc=d9,d9+d5-1,128 do for U=1,16*2 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=((i*256+c9)*256+dd)*256+de end;for em=17*2,80*2,2 do local dH,dI,dM,dN=da[em-30],da[em-31],da[em-4],da[em-5]local eQ=ci(ck(dH,1)+cj(dI,31),ck(dH,8)+cj(dI,24),ck(dH,7)+cj(dI,25))%4294967296+ci(ck(dM,19)+cj(dN,13),cj(dM,3)+ck(dN,29),ck(dM,6)+cj(dN,26))%4294967296+da[em-14]+da[em-32]local eR=eQ%4294967296;da[em-1]=ci(ck(dI,1)+cj(dH,31),ck(dI,8)+cj(dH,24),ck(dI,7))+ci(ck(dN,19)+cj(dM,13),cj(dN,3)+ck(dM,29),ck(dN,6))+da[em-15]+da[em-33]+(eQ-eR)/4294967296;da[em]=eR end;local dH,dM,e1,ee,dR,dV,dX,en=eA,eB,eC,eD,eE,eF,eG,eH;local dI,dN,e2,ef,dS,dW,dY,eo=eI,eJ,eK,eL,eM,eN,eO,eP;for U=1,80 do local em=2*U;local eQ=ci(ck(dR,14)+cj(dS,18),ck(dR,18)+cj(dS,14),cj(dR,23)+ck(dS,9))%4294967296+(cg(dR,dV)+cg(-1-dR,dX))%4294967296+en+ek[U]+da[em]local eq=eQ%4294967296;local er=ci(ck(dS,14)+cj(dR,18),ck(dS,18)+cj(dR,14),cj(dS,23)+ck(dR,9))+cg(dS,dW)+cg(-1-dS,dY)+eo+el[U]+da[em-1]+(eQ-eq)/4294967296;en=dX;eo=dY;dX=dV;dY=dW;dV=dR;dW=dS;eQ=eq+ee;dR=eQ%4294967296;dS=er+ef+(eQ-dR)/4294967296;ee=e1;ef=e2;e1=dM;e2=dN;dM=dH;dN=dI;eQ=eq+(cg(ee,e1)+cg(dM,ci(ee,e1)))%4294967296+ci(ck(dM,28)+cj(dN,4),cj(dM,30)+ck(dN,2),cj(dM,25)+ck(dN,7))%4294967296;dH=eQ%4294967296;dI=er+cg(ef,e2)+cg(dN,ci(ef,e2))+ci(ck(dN,28)+cj(dM,4),cj(dN,30)+ck(dM,2),cj(dN,25)+ck(dM,7))+(eQ-dH)/4294967296 end;dH=eA+dH;eA=dH%4294967296;eI=(eI+dI+(dH-eA)/4294967296)%4294967296;dH=eB+dM;eB=dH%4294967296;eJ=(eJ+dN+(dH-eB)/4294967296)%4294967296;dH=eC+e1;eC=dH%4294967296;eK=(eK+e2+(dH-eC)/4294967296)%4294967296;dH=eD+ee;eD=dH%4294967296;eL=(eL+ef+(dH-eD)/4294967296)%4294967296;dH=eE+dR;eE=dH%4294967296;eM=(eM+dS+(dH-eE)/4294967296)%4294967296;dH=eF+dV;eF=dH%4294967296;eN=(eN+dW+(dH-eF)/4294967296)%4294967296;dH=eG+dX;eG=dH%4294967296;eO=(eO+dY+(dH-eG)/4294967296)%4294967296;dH=eH+en;eH=dH%4294967296;eP=(eP+eo+(dH-eH)/4294967296)%4294967296 end;ei[1],ei[2],ei[3],ei[4],ei[5],ei[6],ei[7],ei[8]=eA,eB,eC,eD,eE,eF,eG,eH;ej[1],ej[2],ej[3],ej[4],ej[5],ej[6],ej[7],ej[8]=eI,eJ,eK,eL,eM,eN,eO,eP end;function cH(d7,d8,d9,d5)local da,db,cV=cZ,cT,cV;local es,et,eu,ev=d7[1],d7[2],d7[3],d7[4]for dc=d9,d9+d5-1,64 do for U=1,16 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=((de*256+dd)*256+c9)*256+i end;local i,c9,dd,de=es,et,eu,ev;local bp=32-7;for U=1,16 do local eS=cm(cg(c9,dd)+cg(-1-c9,de)+i+db[U]+da[U],bp)+c9;bp=cV[bp]i=de;de=dd;dd=c9;c9=eS end;bp=32-5;for U=17,32 do local eS=cm(cg(de,c9)+cg(-1-de,dd)+i+db[U]+da[(5*U-4)%16+1],bp)+c9;bp=cV[bp]i=de;de=dd;dd=c9;c9=eS end;bp=32-4;for U=33,48 do local eS=cm(ci(ci(c9,dd),de)+i+db[U]+da[(3*U+2)%16+1],bp)+c9;bp=cV[bp]i=de;de=dd;dd=c9;c9=eS end;bp=32-6;for U=49,64 do local eS=cm(ci(dd,ch(c9,-1-de))+i+db[U]+da[(U*7-7)%16+1],bp)+c9;bp=cV[bp]i=de;de=dd;dd=c9;c9=eS end;es=(i+es)%4294967296;et=(c9+et)%4294967296;eu=(dd+eu)%4294967296;ev=(de+ev)%4294967296 end;d7[1],d7[2],d7[3],d7[4]=es,et,eu,ev end;function cI(d7,d8,d9,d5)local da=cZ;local es,et,eu,ev,ew=d7[1],d7[2],d7[3],d7[4],d7[5]for dc=d9,d9+d5-1,64 do for U=1,16 do dc=dc+4;local i,c9,dd,de=I(d8,dc-3,dc)da[U]=((i*256+c9)*256+dd)*256+de end;for U=17,80 do da[U]=cl(ci(da[U-3],da[U-8],da[U-14],da[U-16]),1)end;local i,c9,dd,de,e=es,et,eu,ev,ew;for U=1,20 do local cC=cl(i,5)+cg(c9,dd)+cg(-1-c9,de)+0x5A827999+da[U]+e;e=de;de=dd;dd=cm(c9,2)c9=i;i=cC end;for U=21,40 do local cC=cl(i,5)+ci(c9,dd,de)+0x6ED9EBA1+da[U]+e;e=de;de=dd;dd=cm(c9,2)c9=i;i=cC end;for U=41,60 do local cC=cl(i,5)+cg(de,dd)+cg(c9,ci(de,dd))+0x8F1BBCDC+da[U]+e;e=de;de=dd;dd=cm(c9,2)c9=i;i=cC end;for U=61,80 do local cC=cl(i,5)+ci(c9,dd,de)+0xCA62C1D6+da[U]+e;e=de;de=dd;dd=cm(c9,2)c9=i;i=cC end;es=(i+es)%4294967296;et=(c9+et)%4294967296;eu=(dd+eu)%4294967296;ev=(de+ev)%4294967296;ew=(e+ew)%4294967296 end;d7[1],d7[2],d7[3],d7[4],d7[5]=es,et,eu,ev,ew end;function cJ(e6,e7,d8,d9,d5,dw)local e8,e9=cO,cP;local dy=dw/8;for dc=d9,d9+d5-1,dw do for U=1,dy do local i,c9,dd,de=I(d8,dc+1,dc+4)e6[U]=ci(e6[U],((de*256+dd)*256+c9)*256+i)dc=dc+8;i,c9,dd,de=I(d8,dc-3,dc)e7[U]=ci(e7[U],((de*256+dd)*256+c9)*256+i)end;local eT,eU,eV,eW,eX,eY,eZ,e_,f0,f1,f2,f3,f4,f5,f6,f7,f8,f9,fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn,fo,fp,fq,fr,ft,fu,fv,fw,fx,fy,fz,fA,fB,fC,fD,fE,fF,fG=e6[1],e7[1],e6[2],e7[2],e6[3],e7[3],e6[4],e7[4],e6[5],e7[5],e6[6],e7[6],e6[7],e7[7],e6[8],e7[8],e6[9],e7[9],e6[10],e7[10],e6[11],e7[11],e6[12],e7[12],e6[13],e7[13],e6[14],e7[14],e6[15],e7[15],e6[16],e7[16],e6[17],e7[17],e6[18],e7[18],e6[19],e7[19],e6[20],e7[20],e6[21],e7[21],e6[22],e7[22],e6[23],e7[23],e6[24],e7[24],e6[25],e7[25]for dz=1,24 do local fH=ci(eT,f2,fc,fm,fx)local fI=ci(eU,f3,fd,fn,fy)local fJ=ci(eV,f4,fe,fo,fz)local fK=ci(eW,f5,ff,fp,fA)local fL=ci(eX,f6,fg,fq,fB)local fM=ci(eY,f7,fh,fr,fC)local fN=ci(eZ,f8,fi,ft,fD)local fO=ci(e_,f9,fj,fu,fE)local fP=ci(f0,fa,fk,fv,fF)local fQ=ci(f1,fb,fl,fw,fG)local ea=ci(fH,fL*2+(fM%2^32-fM%2^31)/2^31)local eb=ci(fI,fM*2+(fL%2^32-fL%2^31)/2^31)local fR=ci(ea,eV)local fS=ci(eb,eW)local fT=ci(ea,f4)local fU=ci(eb,f5)local fV=ci(ea,fe)local fW=ci(eb,ff)local fX=ci(ea,fo)local fY=ci(eb,fp)local fZ=ci(ea,fz)local f_=ci(eb,fA)eV=(fT%2^32-fT%2^20)/2^20+fU*2^12;eW=(fU%2^32-fU%2^20)/2^20+fT*2^12;f4=(fX%2^32-fX%2^19)/2^19+fY*2^13;f5=(fY%2^32-fY%2^19)/2^19+fX*2^13;fe=fR*2+(fS%2^32-fS%2^31)/2^31;ff=fS*2+(fR%2^32-fR%2^31)/2^31;fo=fV*2^10+(fW%2^32-fW%2^22)/2^22;fp=fW*2^10+(fV%2^32-fV%2^22)/2^22;fz=fZ*2^2+(f_%2^32-f_%2^30)/2^30;fA=f_*2^2+(fZ%2^32-fZ%2^30)/2^30;ea=ci(fJ,fN*2+(fO%2^32-fO%2^31)/2^31)eb=ci(fK,fO*2+(fN%2^32-fN%2^31)/2^31)fR=ci(ea,eX)fS=ci(eb,eY)fT=ci(ea,f6)fU=ci(eb,f7)fV=ci(ea,fg)fW=ci(eb,fh)fX=ci(ea,fq)fY=ci(eb,fr)fZ=ci(ea,fB)f_=ci(eb,fC)eX=(fV%2^32-fV%2^21)/2^21+fW*2^11;eY=(fW%2^32-fW%2^21)/2^21+fV*2^11;f6=(fZ%2^32-fZ%2^3)/2^3+f_*2^29%2^32;f7=(f_%2^32-f_%2^3)/2^3+fZ*2^29%2^32;fg=fT*2^6+(fU%2^32-fU%2^26)/2^26;fh=fU*2^6+(fT%2^32-fT%2^26)/2^26;fq=fX*2^15+(fY%2^32-fY%2^17)/2^17;fr=fY*2^15+(fX%2^32-fX%2^17)/2^17;fB=(fR%2^32-fR%2^2)/2^2+fS*2^30%2^32;fC=(fS%2^32-fS%2^2)/2^2+fR*2^30%2^32;ea=ci(fL,fP*2+(fQ%2^32-fQ%2^31)/2^31)eb=ci(fM,fQ*2+(fP%2^32-fP%2^31)/2^31)fR=ci(ea,eZ)fS=ci(eb,e_)fT=ci(ea,f8)fU=ci(eb,f9)fV=ci(ea,fi)fW=ci(eb,fj)fX=ci(ea,ft)fY=ci(eb,fu)fZ=ci(ea,fD)f_=ci(eb,fE)eZ=fX*2^21%2^32+(fY%2^32-fY%2^11)/2^11;e_=fY*2^21%2^32+(fX%2^32-fX%2^11)/2^11;f8=fR*2^28%2^32+(fS%2^32-fS%2^4)/2^4;f9=fS*2^28%2^32+(fR%2^32-fR%2^4)/2^4;fi=fV*2^25%2^32+(fW%2^32-fW%2^7)/2^7;fj=fW*2^25%2^32+(fV%2^32-fV%2^7)/2^7;ft=(fZ%2^32-fZ%2^8)/2^8+f_*2^24%2^32;fu=(f_%2^32-f_%2^8)/2^8+fZ*2^24%2^32;fD=(fT%2^32-fT%2^9)/2^9+fU*2^23%2^32;fE=(fU%2^32-fU%2^9)/2^9+fT*2^23%2^32;ea=ci(fN,fH*2+(fI%2^32-fI%2^31)/2^31)eb=ci(fO,fI*2+(fH%2^32-fH%2^31)/2^31)fR=ci(ea,f0)fS=ci(eb,f1)fT=ci(ea,fa)fU=ci(eb,fb)fV=ci(ea,fk)fW=ci(eb,fl)fX=ci(ea,fv)fY=ci(eb,fw)fZ=ci(ea,fF)f_=ci(eb,fG)f0=fZ*2^14+(f_%2^32-f_%2^18)/2^18;f1=f_*2^14+(fZ%2^32-fZ%2^18)/2^18;fa=fT*2^20%2^32+(fU%2^32-fU%2^12)/2^12;fb=fU*2^20%2^32+(fT%2^32-fT%2^12)/2^12;fk=fX*2^8+(fY%2^32-fY%2^24)/2^24;fl=fY*2^8+(fX%2^32-fX%2^24)/2^24;fv=fR*2^27%2^32+(fS%2^32-fS%2^5)/2^5;fw=fS*2^27%2^32+(fR%2^32-fR%2^5)/2^5;fF=(fV%2^32-fV%2^25)/2^25+fW*2^7;fG=(fW%2^32-fW%2^25)/2^25+fV*2^7;ea=ci(fP,fJ*2+(fK%2^32-fK%2^31)/2^31)eb=ci(fQ,fK*2+(fJ%2^32-fJ%2^31)/2^31)fT=ci(ea,f2)fU=ci(eb,f3)fV=ci(ea,fc)fW=ci(eb,fd)fX=ci(ea,fm)fY=ci(eb,fn)fZ=ci(ea,fx)f_=ci(eb,fy)f2=fV*2^3+(fW%2^32-fW%2^29)/2^29;f3=fW*2^3+(fV%2^32-fV%2^29)/2^29;fc=fZ*2^18+(f_%2^32-f_%2^14)/2^14;fd=f_*2^18+(fZ%2^32-fZ%2^14)/2^14;fm=(fT%2^32-fT%2^28)/2^28+fU*2^4;fn=(fU%2^32-fU%2^28)/2^28+fT*2^4;fx=(fX%2^32-fX%2^23)/2^23+fY*2^9;fy=(fY%2^32-fY%2^23)/2^23+fX*2^9;eT=ci(ea,eT)eU=ci(eb,eU)eT,eV,eX,eZ,f0=ci(eT,cg(-1-eV,eX)),ci(eV,cg(-1-eX,eZ)),ci(eX,cg(-1-eZ,f0)),ci(eZ,cg(-1-f0,eT)),ci(f0,cg(-1-eT,eV))eU,eW,eY,e_,f1=ci(eU,cg(-1-eW,eY)),ci(eW,cg(-1-eY,e_)),ci(eY,cg(-1-e_,f1)),ci(e_,cg(-1-f1,eU)),ci(f1,cg(-1-eU,eW))f2,f4,f6,f8,fa=ci(f8,cg(-1-fa,f2)),ci(fa,cg(-1-f2,f4)),ci(f2,cg(-1-f4,f6)),ci(f4,cg(-1-f6,f8)),ci(f6,cg(-1-f8,fa))f3,f5,f7,f9,fb=ci(f9,cg(-1-fb,f3)),ci(fb,cg(-1-f3,f5)),ci(f3,cg(-1-f5,f7)),ci(f5,cg(-1-f7,f9)),ci(f7,cg(-1-f9,fb))fc,fe,fg,fi,fk=ci(fe,cg(-1-fg,fi)),ci(fg,cg(-1-fi,fk)),ci(fi,cg(-1-fk,fc)),ci(fk,cg(-1-fc,fe)),ci(fc,cg(-1-fe,fg))fd,ff,fh,fj,fl=ci(ff,cg(-1-fh,fj)),ci(fh,cg(-1-fj,fl)),ci(fj,cg(-1-fl,fd)),ci(fl,cg(-1-fd,ff)),ci(fd,cg(-1-ff,fh))fm,fo,fq,ft,fv=ci(fv,cg(-1-fm,fo)),ci(fm,cg(-1-fo,fq)),ci(fo,cg(-1-fq,ft)),ci(fq,cg(-1-ft,fv)),ci(ft,cg(-1-fv,fm))fn,fp,fr,fu,fw=ci(fw,cg(-1-fn,fp)),ci(fn,cg(-1-fp,fr)),ci(fp,cg(-1-fr,fu)),ci(fr,cg(-1-fu,fw)),ci(fu,cg(-1-fw,fn))fx,fz,fB,fD,fF=ci(fB,cg(-1-fD,fF)),ci(fD,cg(-1-fF,fx)),ci(fF,cg(-1-fx,fz)),ci(fx,cg(-1-fz,fB)),ci(fz,cg(-1-fB,fD))fy,fA,fC,fE,fG=ci(fC,cg(-1-fE,fG)),ci(fE,cg(-1-fG,fy)),ci(fG,cg(-1-fy,fA)),ci(fy,cg(-1-fA,fC)),ci(fA,cg(-1-fC,fE))eT=ci(eT,e8[dz])eU=eU+e9[dz]end;e6[1]=eT;e7[1]=eU;e6[2]=eV;e7[2]=eW;e6[3]=eX;e7[3]=eY;e6[4]=eZ;e7[4]=e_;e6[5]=f0;e7[5]=f1;e6[6]=f2;e7[6]=f3;e6[7]=f4;e7[7]=f5;e6[8]=f6;e7[8]=f7;e6[9]=f8;e7[9]=f9;e6[10]=fa;e7[10]=fb;e6[11]=fc;e7[11]=fd;e6[12]=fe;e7[12]=ff;e6[13]=fg;e7[13]=fh;e6[14]=fi;e7[14]=fj;e6[15]=fk;e7[15]=fl;e6[16]=fm;e7[16]=fn;e6[17]=fo;e7[17]=fp;e6[18]=fq;e7[18]=fr;e6[19]=ft;e7[19]=fu;e6[20]=fv;e7[20]=fw;e6[21]=fx;e7[21]=fy;e6[22]=fz;e7[22]=fA;e6[23]=fB;e7[23]=fC;e6[24]=fD;e7[24]=fE;e6[25]=fF;e7[25]=fG end end end;do local function y(g0,g1,g2,g3)local an,g4,ad,g5={},0.0,0.0,1.0;for U=1,g3 do for bY=bV(1,U+1-#g1),bU(U,#g0)do g4=g4+g2*g0[bY]*g1[U+1-bY]end;local g6=g4%2^24;an[U]=f(g6)g4=(g4-g6)/2^24;ad=ad+g6*g5;g5=g5*2^24 end;return an,ad end;local ct,g7,g8,bX,g9,ga=0,{4,1,2,-2,2},4,{1},cN,cM;repeat g8=g8+g7[g8%6]local de=1;repeat de=de+g7[de%6]if de*de>g8 then local gb=g8^(1/3)local gc=gb*2^40;gc=y({gc-gc%1},bX,1.0,2)local cc,gd=y(gc,y(gc,gc,1.0,4),-1.0,4)local ge=gc[2]%65536*65536+f(gc[1]/256)local gf=gc[1]%256*16777216+f(gd*2^-56/3*gb/g8)if ct<16 then gb=g8^(1/2)gc=gb*2^40;gc=y({gc-gc%1},bX,1.0,2)cc,gd=y(gc,gc,-1.0,2)local ge=gc[2]%65536*65536+f(gc[1]/256)local gf=gc[1]%256*16777216+f(gd*2^-17/gb)local ct=ct%8+1;cQ[224][ct]=gf;g9[ct],ga[ct]=ge,gf+ge*d0;if ct>7 then g9,ga=cS[384],cR[384]end end;ct=ct+1;cL[ct],cK[ct]=ge,gf%c_+ge*d0;break end until g8%de==0 until ct>79 end;for gg=224,256,32 do local ei,ej={}if cX then for U=1,8 do ei[U]=cX(cM[U])end else ej={}for U=1,8 do ei[U]=cD(cM[U])ej[U]=cD(cN[U])end end;cG(ei,ej,"SHA-512/"..tostring(gg).."\128"..bP("\0",115).."\88",0,128)cR[gg]=ei;cS[gg]=ej end;do local gh,gi,gj=math.sin,math.abs,math.modf;for ct=1,64 do local ge,gf=gj(gi(gh(ct))*2^16)cT[ct]=ge*65536+f(gf*2^16)end end;do local gk=29;local function gl()local cr=gk%2;gk=cq((gk-cr)/2,142*cr)return cr end;for ct=1,24 do local gf,bZ=0;for cc=1,6 do bZ=bZ and bZ*bZ*2 or 1;gf=gf+gl()*bZ end;local ge=gl()*bZ;cP[ct],cO[ct]=ge,gf+ge*d1 end end;local function gm(gg,gn)local d7,go,gp={unpack(cQ[gg])},0.0,""local function gq(gr)if gr then if gp then go=go+#gr;local d9=0;if gp~=""and#gp+#gr>=64 then d9=64-#gp;cF(d7,gp..u(gr,1,d9),0,64)gp=""end;local d5=#gr-d9;local gs=d5%64;cF(d7,gr,d9,d5-gs)gp=gp..u(gr,#gr+1-gs)return gq else error("Adding more chunks is not allowed after receiving the result",2)end else if gp then local gt={gp,"\128",bP("\0",(-9-go)%64+1)}gp=nil;go=go*8/256^7;for U=4,10 do go=go%1*256;gt[U]=ak(f(go))end;gt=bO(gt)cF(d7,gt,0,#gt)local gu=gg/32;for U=1,gu do d7[U]=cp(d7[U])end;d7=bO(d7,"",1,gu)end;return d7 end end;if gn then return gq(gn)()else return gq end end;local function gv(gg,gn)local go,gp,ei,ej=0.0,"",{unpack(cR[gg])},not cW and{unpack(cS[gg])}local function gq(gr)if gr then if gp then go=go+#gr;local d9=0;if gp~=""and#gp+#gr>=128 then d9=128-#gp;cG(ei,ej,gp..u(gr,1,d9),0,128)gp=""end;local d5=#gr-d9;local gs=d5%128;cG(ei,ej,gr,d9,d5-gs)gp=gp..u(gr,#gr+1-gs)return gq else error("Adding more chunks is not allowed after receiving the result",2)end else if gp then local gt={gp,"\128",bP("\0",(-17-go)%128+9)}gp=nil;go=go*8/256^7;for U=4,10 do go=go%1*256;gt[U]=ak(f(go))end;gt=bO(gt)cG(ei,ej,gt,0,#gt)local gu=bT(gg/64)if cW then for U=1,gu do ei[U]=cW(ei[U])end else for U=1,gu do ei[U]=cp(ej[U])..cp(ei[U])end;ej=nil end;ei=u(bO(ei,"",1,gu),1,gg/4)end;return ei end end;if gn then return gq(gn)()else return gq end end;local function gw(gn)local d7,go,gp={unpack(cU,1,4)},0.0,""local function gq(gr)if gr then if gp then go=go+#gr;local d9=0;if gp~=""and#gp+#gr>=64 then d9=64-#gp;cH(d7,gp..u(gr,1,d9),0,64)gp=""end;local d5=#gr-d9;local gs=d5%64;cH(d7,gr,d9,d5-gs)gp=gp..u(gr,#gr+1-gs)return gq else error("Adding more chunks is not allowed after receiving the result",2)end else if gp then local gt={gp,"\128",bP("\0",(-9-go)%64)}gp=nil;go=go*8;for U=4,11 do local gx=go%256;gt[U]=ak(gx)go=(go-gx)/256 end;gt=bO(gt)cH(d7,gt,0,#gt)for U=1,4 do d7[U]=cp(d7[U])end;d7=bQ(bO(d7),"(..)(..)(..)(..)","%4%3%2%1")end;return d7 end end;if gn then return gq(gn)()else return gq end end;local function gy(gn)local d7,go,gp={unpack(cU)},0.0,""local function gq(gr)if gr then if gp then go=go+#gr;local d9=0;if gp~=""and#gp+#gr>=64 then d9=64-#gp;cI(d7,gp..u(gr,1,d9),0,64)gp=""end;local d5=#gr-d9;local gs=d5%64;cI(d7,gr,d9,d5-gs)gp=gp..u(gr,#gr+1-gs)return gq else error("Adding more chunks is not allowed after receiving the result",2)end else if gp then local gt={gp,"\128",bP("\0",(-9-go)%64+1)}gp=nil;go=go*8/256^7;for U=4,10 do go=go%1*256;gt[U]=ak(f(go))end;gt=bO(gt)cI(d7,gt,0,#gt)for U=1,5 do d7[U]=cp(d7[U])end;d7=bO(d7)end;return d7 end end;if gn then return gq(gn)()else return gq end end;local function gz(dw,gA,gB,gn)if type(gA)~="number"then error("Argument 'digest_size_in_bytes' must be a number",2)end;local gp,e6,e7="",cE(),d1==0 and cE()local an;local function gq(gr)if gr then if gp then local d9=0;if gp~=""and#gp+#gr>=dw then d9=dw-#gp;cJ(e6,e7,gp..u(gr,1,d9),0,dw,dw)gp=""end;local d5=#gr-d9;local gs=d5%dw;cJ(e6,e7,gr,d9,d5-gs,dw)gp=gp..u(gr,#gr+1-gs)return gq else error("Adding more chunks is not allowed after receiving the result",2)end else if gp then local gC=gB and 31 or 6;gp=gp..(#gp+1==dw and ak(gC+128)or ak(gC)..bP("\0",(-2-#gp)%dw).."\128")cJ(e6,e7,gp,0,#gp,dw)gp=nil;local gD=0;local gE=f(dw/8)local gF={}local function gG(dy)if gD>=gE then cJ(e6,e7,"\0\0\0\0\0\0\0\0",0,8,8)gD=0 end;dy=f(bU(dy,gE-gD))if d1~=0 then for U=1,dy do gF[U]=cW(e6[gD+U-1+cY])end else for U=1,dy do gF[U]=cp(e7[gD+U])..cp(e6[gD+U])end end;gD=gD+dy;return bQ(bO(gF,"",1,dy),"(..)(..)(..)(..)(..)(..)(..)(..)","%8%7%6%5%4%3%2%1"),dy*8 end;local gH={}local gI,gJ="",0;local function gK(gL)gL=gL or 1;if gL<=gJ then gJ=gJ-gL;local gM=gL*2;local an=u(gI,1,gM)gI=u(gI,gM+1)return an end;local gN=0;if gJ>0 then gN=1;gH[gN]=gI;gL=gL-gJ end;while gL>=8 do local gO,gP=gG(gL/8)gN=gN+1;gH[gN]=gO;gL=gL-gP end;if gL>0 then gI,gJ=gG(1)gN=gN+1;gH[gN]=gK(gL)else gI,gJ="",0 end;return bO(gH,"",1,gN)end;if gA<0 then an=gK else an=gK(gA)end end;return an end end;if gn then return gq(gn)()else return gq end end;local gQ,gR,gS;do function gQ(gT)return bQ(gT,"%x%x",function(gU)return ak(tonumber(gU,16))end)end;local gV={['+']=62,['-']=62,[62]='+',['/']=63,['_']=63,[63]='/',['=']=-1,['.']=-1,[-1]='='}local gW=0;for U,gX in ipairs{'AZ','az','09'}do for gY=I(gX),I(gX,2)do local gZ=ak(gY)gV[gZ]=gW;gV[gW]=gZ;gW=gW+1 end end;function gR(g_)local an={}for dc=1,#g_,3 do local h0,h1,h2,h3=I(u(g_,dc,dc+2)..'\0',1,-1)an[#an+1]=gV[f(h0/4)]..gV[h0%4*16+f(h1/16)]..gV[h2 and h1%16*4+f(h2/64)or-1]..gV[h3 and h2%64 or-1]end;return bO(an)end;function gS(h4)local an,h5={},3;for dc,gZ in bR(bQ(h4,'%s+',''),'()(.)')do local h6=gV[gZ]if h6<0 then h5=h5-1;h6=0 end;local ct=dc%4;if ct>0 then an[-ct]=h6 else local h0=an[-1]*4+f(an[-2]/16)local h1=an[-2]%16*16+f(an[-3]/4)local h2=an[-3]%4*64+h6;an[#an+1]=u(ak(h0,h1,h2),1,h5)end end;return bO(an)end end;local h7;local function h8(d8,g3,h9)return bQ(d8,".",function(dd)return ak(cq(I(dd),h9))end)..bP(ak(h9),g3-#d8)end;local function ha(hb,aU,gn)local hc=h7[hb]if not hc then error("Unknown hash function",2)end;if#aU>hc then aU=gQ(hb(aU))end;local hd=hb()(h8(aU,hc,0x36))local an;local function gq(gr)if not gr then an=an or hb(h8(aU,hc,0x5C)..gQ(hd()))return an elseif an then error("Adding more chunks is not allowed after receiving the result",2)else hd(gr)return gq end end;if gn then return gq(gn)()else return gq end end;local he={md5=gw,sha1=gy,sha224=function(gn)return gm(224,gn)end,sha256=function(gn)return gm(256,gn)end,sha512_224=function(gn)return gv(224,gn)end,sha512_256=function(gn)return gv(256,gn)end,sha384=function(gn)return gv(384,gn)end,sha512=function(gn)return gv(512,gn)end,sha3_224=function(gn)return gz((1600-2*224)/8,224/8,false,gn)end,sha3_256=function(gn)return gz((1600-2*256)/8,256/8,false,gn)end,sha3_384=function(gn)return gz((1600-2*384)/8,384/8,false,gn)end,sha3_512=function(gn)return gz((1600-2*512)/8,512/8,false,gn)end,shake128=function(gA,gn)return gz((1600-2*128)/8,gA,true,gn)end,shake256=function(gA,gn)return gz((1600-2*256)/8,gA,true,gn)end,hmac=ha,hex2bin=gQ,base642bin=gS,bin2base64=gR}h7={[he.md5]=64,[he.sha1]=64,[he.sha224]=64,[he.sha256]=64,[he.sha512_224]=128,[he.sha512_256]=128,[he.sha384]=128,[he.sha512]=128,[he.sha3_224]=(1600-2*224)/8,[he.sha3_256]=(1600-2*256)/8,[he.sha3_384]=(1600-2*384)/8,[he.sha3_512]=(1600-2*512)/8}return he end)()local hf=require("cc.expect").expect;local hg=bM.sha256;local function hh(hi,hj)local aZ={}local a_={}local b0={}for B=1,#hi do aZ[#aZ+1]=string.byte(hi,B)end;for B=1,#hj do a_[#a_+1]=string.byte(hj,B)end;for B=1,#aZ do b0[#b0+1]=string.char(bit32.bxor(aZ[B],a_[B]))end;return table.concat(b0)end;local function gQ(d8)return d8:gsub("%x%x",function(bp)return string.char(tonumber(bp,16))end)end;local function hk(hl,hm,hn,ho)local b3;local b2;b3=gQ(bM.hmac(hl,hm,hn.."\1"))b2=b3;for B=2,ho do b3=gQ(bM.hmac(hl,hm,b3))b2=hh(b2,b3)end;return b2 end;local function hp(ab)local hq=""for cc,b4 in ipairs(ab)do hq=hq..string.char(b4)end;return hq end;local aU,hn,hr;local hs=fs;_G.fs={getName=hs.getName,getDrive=hs.getDrive,getFreeSpace=hs.getFreeSpace,combine=hs.combine,getDir=hs.getDir,isDriveRoot=hs.isDriveRoot,getCapacity=hs.getCapacity}function fs.unlock(bD)math.randomseed(os.epoch("utc"))if not bD then write("Please enter the password: ")bD=read("\7")end;local ab;hn=""if hs.exists("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f")then local ht=hs.open("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f","rb")local b2=ht.readAll()ht.close()hn,ab=b2:sub(1,16),{b2:sub(17):byte(1,16)}else for cc=1,16 do hn=hn..string.char(math.random(0,255))end end;aU=hk(hg,bD,hn,2500)bD=nil;hr={}if hs.exists("9f721fc36d10270affc7dbba9594e7665f95e0ad6d1729f5d9c0e6cc18235cf3")then local ht=hs.open("9f721fc36d10270affc7dbba9594e7665f95e0ad6d1729f5d9c0e6cc18235cf3","rb")local d8=b.decrypt(aU,ht.readAll(),32,b.CBCMODE,ab,true)ht.close()if d8==nil then aU,hn,hr=nil;error("Incorrect password.",2)end;hr=textutils.unserialize(d8)end end;local function hu()if aU==nil or hr==nil then return end;local ab={}if hs.exists("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f")then local ht=hs.open("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f","rb")local b2=ht.readAll()ht.close()ab={b2:sub(17):byte(1,16)}else for B=1,16 do ab[B]=math.random(0,255)end;local ht=hs.open("f1a36aae5f891a6c695d12621d1e0ecc4cee1a5e951784d874b8e6ad94de223f","wb")ht.write(hn..hp(ab))ht.close()end;local ht=hs.open("9f721fc36d10270affc7dbba9594e7665f95e0ad6d1729f5d9c0e6cc18235cf3","wb")ht.write(b.encrypt(aU,textutils.serialize(hr),32,b.CBCMODE,ab,true))ht.close()end;function fs.isUnlocked()return aU~=nil and hn~=nil and hr~=nil end;function fs.lock()hu()aU,hn,hr=nil end;local function hv(g8)local hq={}for bZ in g8:gmatch("[^/]+")do table.insert(hq,bZ)end;return hq end;local function hw(hx,b2)if#hx==0 then return b2 elseif type(b2)~="table"then return nil else local B=table.remove(hx,1)return hw(hx,b2[B])end end;local function hy(hz)return hw(hv(hz),hr)end;local function hA(hx,b4,b2)if#hx>1 and b2[hx[1]]==nil then b2[hx[1]]={}end;if#hx==0 then error("Critical error while writing encrypted data")elseif#hx==1 then b2[hx[1]]=b4 else return hA(hx,b4,b2[table.remove(hx,1)])end end;local function hB(hz,b4)return hA(hv(hz),b4,hr)end;local hC="^%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x$"local function hD(hz)return fs.combine(hz,""):match(hC)~=nil or fs.combine(hz,"")==".salt"or fs.combine(hz,"")==".filetree"end;function fs.list(hE)hf(1,hE,"string")local hF,hq=pcall(hs.list,hE)local hG=hy(hE)if not hF and type(hG)~="table"then error(hq:gsub("^.-:%d: ",""),2)end;hq=hF and hq or{}if type(hG)=="table"then for bY in pairs(hG)do table.insert(hq,bY)end end;if fs.combine(hE,"")==""then local hH={}for cc,b4 in ipairs(hq)do if not hD(b4)then table.insert(hH,b4)end end;hq=hH end;table.sort(hq)return hq end;function fs.exists(hz)hf(1,hz,"string")if hD(hz)then return false else return hs.exists(hz)or hy(hz)~=nil end end;function fs.isDir(hz)hf(1,hz,"string")if hD(hz)then return false else return hs.isDir(hz)or type(hy(hz))=="table"end end;function fs.isReadOnly(hz)hf(1,hz,"string")return hs.isReadOnly(hz)end;function fs.getSize(hz)hf(1,hz,"string")if hD(hz)then error("/"..fs.combine(hz,"")..": No such file",2)end;local hF,hq=pcall(hs.getSize,hz)local hG=hy(hz)if not hF and hG==nil then error(hq:gsub("^.-:%d: ",""),2)elseif type(hG)=="table"then return 0 elseif hF then return hq end;local ht=fs.open(hz,"rb")hq=#ht.readAll()ht.close()return hq end;function fs.makeDir(hz)hf(1,hz,"string")if hD(hz)then error("/"..fs.combine(hz,"")..": File exists",2)elseif hr==nil then return hs.makeDir(hz)elseif type(hy(hz))=="string"then error("/"..fs.combine(hz,"")..": File exists",2)end;hB(hz,hy(hz)or{})hu()end;function fs.move(hI,hJ)hf(1,hI,"string")hf(2,hJ,"string")if hD(hI)then error("/"..fs.combine(hI,"")..": No such file or directory",2)elseif hD(hJ)then error("/"..fs.combine(hJ,"")..": Permission denied",2)elseif hs.exists(hI)or hr==nil then return hs.move(hI,hJ)elseif hy(hI)==nil then error("/"..fs.combine(hI,"")..": No such file or directory",2)elseif hy(hJ)~=nil then error("/"..fs.combine(hJ,"")..": File exists",2)end;hB(hJ,hy(hI))hB(hI,nil)hu()end;function fs.copy(hI,hJ)hf(1,hI,"string")hf(2,hJ,"string")if hD(hI)then error("/"..fs.combine(hI,"")..": No such file or directory",2)elseif hD(hJ)then error("/"..fs.combine(hJ,"")..": Permission denied",2)elseif hs.exists(hI)or hr==nil then return hs.copy(hI,hJ)elseif hy(hI)==nil then error("/"..fs.combine(hI,"")..": No such file or directory",2)elseif hy(hJ)~=nil then error("/"..fs.combine(hJ,"")..": File exists",2)end;hB(hJ,hy(hI))hu()end;function fs.delete(hz)hf(1,hz,"string")if hD(hz)then error("/"..fs.combine(hz,"")..": Permission denied",2)elseif hs.exists(hz)or hr==nil then return hs.delete(hz)end;hB(hz,nil)hu()end;function fs.open(hz,bI)hf(1,hz,"string")hf(2,bI,"string")if hD(hz)then return nil,"/"..fs.combine(hz,"")..(bI:sub(1,1)~="w"and": No such file"or": Permission denied")elseif hs.exists(hz)or hr==nil then return hs.open(hz,bI)elseif({r=1,w=1,a=1,rb=1,wb=1,ab=1})[bI]==nil then return nil,"/"..fs.combine(hz,"")..": Unknown mode"end;local hK,dc="",1;local hL=bI:sub(2,2)=="b"local hM=false;if bI:sub(1,1)~="w"then local ab=hy(hz)if type(ab)~="string"then return nil,"/"..fs.combine(hz,"")..(ab==nil and": No such file"or": Is a directory")end;local ht,hN=hs.open(hg(fs.combine(hz,"")..ab),"rb")if not ht then return ht,hN end;hK=b.decrypt(aU,ht.readAll(),32,b.CBCMODE,{ab:byte(1,16)},true)ht.close()if hK==nil then return nil,"Failed to decrypt file"end;if not hL then local d8=""for cc,b4 in utf8.codes(hK)do if b4<256 then d8=d8 ..string.char(b4)else d8=d8 .."?"end end;hK=d8 end end;if bI:sub(1,1)=="a"then dc=#hK+1 end;if bI:sub(1,1)=="r"then return{read=function(m)hf(1,m,"number","nil")if dc>#hK then return nil elseif hM then error("attempt to use a closed file",2)elseif m==nil then dc=dc+1;if hL then return hK:byte(dc-1)else return hK:sub(dc-1,dc-1)end else dc=dc+m;return hK:sub(dc-m,dc-1)end end,readLine=function()if dc>#hK then return nil elseif hM then error("attempt to use a closed file",2)end;local hq=""for dd in hK:sub(dc):gmatch(".")do dc=dc+1;if dd=='\n'then break end;hq=hq..dd end;return hq end,readAll=function()if dc>#hK then return nil elseif hM then error("attempt to use a closed file",2)end;local hq=hK:sub(dc)dc=#hK+1;return hq end,seek=hL and function(hO,bx)hf(1,hO,"string","nil")hf(2,bx,"number","nil")if hM then error("attempt to use a closed file",2)end;hO=hO or"cur"bx=bx or 0;if hO=="set"then dc=bx+1 elseif hO=="cur"then dc=dc+bx elseif hO=="end"then dc=#hK-bx+1 else error("bad argument #1 to 'seek' (invalid option '"..hO.."')")end;return dc-1 end or nil,close=function()if hM then error("attempt to use a closed file",2)end;hM=true;dc=#hK+1 end}else return{write=function(_)hf(1,_,"string","number")if hM then error("attempt to use a closed file",2)end;if type(_)=="number"then if hL then _=string.char(_)or'?'else _=tostring(_)end end;hK=hK:sub(1,dc-1).._..hK:sub(dc+#_)end,writeLine=function(_)hf(1,_,"string","number")if hM then error("attempt to use a closed file",2)end;if type(_)=="number"then if hL then _=string.char(_)or'?'else _=tostring(_)end end;_=_.."\n"hK=hK:sub(1,dc-1).._..hK:sub(dc+#_)end,flush=function()if hM then error("attempt to use a closed file",2)end;local _=""if not hL then for dd in hK:gmatch(".")do _=_..utf8.char(dd:byte())end else _=hK end;local ab=hy(hz)if ab then ab={ab:byte(1,16)}else ab={}for B=1,16 do ab[B]=math.random(0,255)end end;local ht=hs.open(hg(fs.combine(hz,"")..hp(ab)),"wb")ht.write(b.encrypt(aU,_,32,b.CBCMODE,ab,true))ht.close()hB(hz,hp(ab))hu()end,seek=hL and function(hO,bx)if hM then error("attempt to use a closed file",2)end;hO=hO or"cur"bx=bx or 0;if hO=="set"then dc=bx+1 elseif hO=="cur"then dc=dc+bx elseif hO=="end"then dc=#hK-bx+1 else error("bad argument #1 to 'seek' (invalid option '"..hO.."')")end;return dc-1 end or nil,close=function()if hM then error("attempt to use a closed file",2)end;local _=""if not hL then for dd in hK:gmatch(".")do _=_..utf8.char(dd:byte())end else _=hK end;local ab=hy(hz)if ab then ab={ab:byte(1,16)}else ab={}for B=1,16 do ab[B]=math.random(0,255)end end;local ht=hs.open(hg(fs.combine(hz,"")..hp(ab)),"wb")ht.write(b.encrypt(aU,_,32,b.CBCMODE,ab,true))ht.close()hB(hz,hp(ab))hu()hM=true;dc=#hK+1 end}end end;local function hP(gH,b2)b2=b2 or hr;if#gH==0 then return b2 elseif type(b2)~="table"then return nil end;local hQ={}for B,b4 in ipairs(gH)do hQ[B]=b4 end;local hR=table.remove(hQ,1)local hq={}for bY,b4 in pairs(b2)do if bY:match("^"..hR:gsub("([%%%.])","%%%1"):gsub("%*","%.%*").."$")then hq[bY]=hP(hQ,b4)end end;return hq end;local function hS(b2,a4)a4=a4 or""if b2==nil then return{}end;local hq={}for bY,b4 in pairs(b2)do if type(b4)=="string"then table.insert(hq,a4 ..bY)else for cc,b5 in ipairs(hS(b4,a4 ..bY.."/"))do table.insert(hq,b5)end end end;return hq end;function fs.find(hT)hf(1,hT,"string")local hq=hs.find(hT)for cc,b4 in ipairs(hS(hP(hv(hT))))do table.insert(hq,b4)end;local hH={}for cc,b4 in ipairs(hq)do if not hD(fs.getName(b4))then table.insert(hH,b4)end end;hq=hH;table.sort(hq)return hq end;function fs.attributes(hz)hf(1,hz,"string")if hs.exists(hz)or hr==nil then return hs.attributes(hz)end;local _=hy(hz)local hU;if _==nil then error("/"..fs.combine(hz,"")..": No such file",2)elseif type(_)=="table"then hU=hs.attributes("9f721fc36d10270affc7dbba9594e7665f95e0ad6d1729f5d9c0e6cc18235cf3")hU.isDir=true;hU.size=0 else hU=hs.attributes(hg(fs.combine(hz,"").._))hU.isDir=false;hU.size=fs.getSize(hz)end;return hU end;local hV={}function fs.complete(hW,hX,hY,hZ)if type(hW)~="string"then error("bad argument #1 (expected string, got "..type(hW)..")",2)end;if type(hX)~="string"then error("bad argument #2 (expected string, got "..type(hX)..")",2)end;if hY~=nil and type(hY)~="boolean"then error("bad argument #3 (expected boolean, got "..type(hY)..")",2)end;if hZ~=nil and type(hZ)~="boolean"then error("bad argument #4 (expected boolean, got "..type(hZ)..")",2)end;hY=hY~=false;hZ=hZ~=false;local h_=hX;local i0=1;local i1=string.find(hW,"[/\\]",i0)if i1==1 then h_=""i0=2 end;local i2;while not i2 do local i1=string.find(hW,"[/\\]",i0)if i1 then local i3=string.sub(hW,i0,i1-1)h_=fs.combine(h_,i3)i0=i1+1 else i2=string.sub(hW,i0)end end;if fs.isDir(h_)then local i4={}if hZ and hW==""then table.insert(i4,".")end;if h_~=""then if hW==""then table.insert(i4,hZ and".."or"../")elseif hW=="."then table.insert(i4,hZ and"."or"./")end end;local i5=fs.list(h_)for m=1,#i5 do local i6=i5[m]if#i6>=#i2 and string.sub(i6,1,#i2)==i2 then local i7=fs.isDir(fs.combine(h_,i6))local i8=string.sub(i6,#i2+1)if i7 then table.insert(i4,i8 .."/")if hZ and#i8>0 then table.insert(i4,i8)end else if hY and#i8>0 then table.insert(i4,i8)end end end end;return i4 end;return hV end;function fs.encrypt(hI,hJ)hf(1,hI,"string")hf(2,hJ,"string")if hr==nil then error("Cannot encrypt files while locked",2)elseif not hs.exists(hI)then error("/"..fs.combine(hI,"")..": No such file",2)elseif hs.isDir(hI)then error("/"..fs.combine(hI,"")..": Is a directory",2)elseif hy(hJ)~=nil then error("/"..fs.combine(hJ,"")..": File exists",2)end;local ab={}for B=1,16 do ab[B]=math.random(0,255)end;local i9=hs.open(hI,"rb")local ia=hs.open(hg(fs.combine(hJ,"")..hp(ab)),"wb")ia.write(b.encrypt(aU,i9.readAll(),32,b.CBCMODE,ab,true))i9.close()ia.close()hB(hJ,hp(ab))hu()end;function fs.decrypt(hI,hJ)hf(1,hI,"string")hf(2,hJ,"string")local ab=hy(hI)if hr==nil then error("Cannot decrypt files while locked",2)elseif ab==nil then error("/"..fs.combine(hI,"")..": No such file",2)elseif type(ab)=="table"then error("/"..fs.combine(hI,"")..": Is a directory",2)elseif hs.exists(hJ)then error("/"..fs.combine(hJ,"")..": File exists",2)end;local i9=hs.open(hg(fs.combine(hI,"")..ab),"rb")local ia=hs.open(hJ,"wb")ia.write(b.decrypt(aU,i9.readAll(),32,b.CBCMODE,{ab:byte(1,16)},true))i9.close()ia.close()end;_G.io={}do local ib=_G.type;local function ic(id,...)if...==nil and id._autoclose and not id._closed then id:close()end;return...end;local ie;ie={__name="FILE*",__tostring=function(self)if self._closed then return"file (closed)"else local ig=tostring(self._handle):match("table: (%x+)")return"file ("..ig..")"end end,__index={close=function(self)if ib(self)~="table"or getmetatable(self)~=ie then error("bad argument #1 (FILE expected, got "..ib(self)..")",2)end;if self._closed then error("attempt to use a closed file",2)end;local id=self._handle;if id.close then self._closed=true;id.close()return true else return nil,"attempt to close standard stream"end end,flush=function(self)if ib(self)~="table"or getmetatable(self)~=ie then error("bad argument #1 (FILE expected, got "..ib(self)..")",2)end;if self._closed then error("attempt to use a closed file",2)end;local id=self._handle;if id.flush then id.flush()end;return true end,lines=function(self,...)if ib(self)~="table"or getmetatable(self)~=ie then error("bad argument #1 (FILE expected, got "..ib(self)..")",2)end;if self._closed then error("attempt to use a closed file",2)end;local id=self._handle;if not id.read then return nil,"file is not readable"end;local a=table.pack(...)return function()if self._closed then error("file is already closed",2)end;return ic(self,self:read(table.unpack(a,1,a.n)))end end,read=function(self,...)if ib(self)~="table"or getmetatable(self)~=ie then error("bad argument #1 (FILE expected, got "..ib(self)..")",2)end;if self._closed then error("attempt to use a closed file",2)end;local id=self._handle;if not id.read and not id.readLine then return nil,"Not opened for reading"end;local m=select("#",...)local S={}for B=1,m do local ih=select(B,...)local cB;if ib(ih)=="number"then if id.read then cB=id.read(ih)end elseif ib(ih)=="string"then local ii=ih:gsub("^%*",""):sub(1,1)if ii=="l"then if id.readLine then cB=id.readLine()end elseif ii=="L"and id.readLine then if id.readLine then cB=id.readLine(true)end elseif ii=="a"then if id.readAll then cB=id.readAll()or""end elseif ii=="n"then cB=nil else error("bad argument #"..B.." (invalid format)",2)end else error("bad argument #"..B.." (expected string, got "..ib(ih)..")",2)end;S[B]=cB;if not cB then break end end;if m==0 and id.readLine then return id.readLine()end;return table.unpack(S,1,m)end,seek=function(self,hO,bx)if ib(self)~="table"or getmetatable(self)~=ie then error("bad argument #1 (FILE expected, got "..ib(self)..")",2)end;if self._closed then error("attempt to use a closed file",2)end;local id=self._handle;if not id.seek then return nil,"file is not seekable"end;return id.seek(hO,bx)end,setvbuf=function(self,bI,d5)end,write=function(self,...)if ib(self)~="table"or getmetatable(self)~=ie then error("bad argument #1 (FILE expected, got "..ib(self)..")",2)end;if self._closed then error("attempt to use a closed file",2)end;local id=self._handle;if not id.write then return nil,"file is not writable"end;for B=1,select("#",...)do local ih=select(B,...)hf(B,ih,"string","number")id.write(ih)end;return self end}}local ij=setmetatable({_handle={readLine=_G.read}},ie)local ik=setmetatable({_handle={write=_G.write}},ie)local il=setmetatable({_handle={write=function(...)local im;if term.isColour()then im=term.getTextColour()term.setTextColour(colors.red)end;_G.write(...)if term.isColour()then term.setTextColour(im)end end}},ie)local ip=ij;local iq=ik;io.stdin=ij;io.stdout=ik;io.stderr=il;function io.close(ht)if ht==nil then return iq:close()end;if ib(ht)~="table"or getmetatable(ht)~=ie then error("bad argument #1 (FILE expected, got "..ib(ht)..")",2)end;return ht:close()end;function io.flush()return iq:flush()end;function io.input(ht)if ib(ht)=="string"then local cB,hN=open(ht,"rb")if not cB then error(hN,2)end;ip=cB elseif ib(ht)=="table"and getmetatable(ht)==ie then ip=ht elseif ht~=nil then error("bad fileument #1 (FILE expected, got "..ib(ht)..")",2)end;return ip end;function io.lines(ir,...)hf(1,ir,"string","nil")if ir then local hF,hN=open(ir,"rb")if not hF then error(hN,2)end;hF._autoclose=true;return hF:lines(...)else return ip:lines(...)end end;function io.open(ir,bI)hf(1,ir,"string")hf(2,bI,"string","nil")local is=bI and bI:gsub("%+","")or"rb"local ht,hN=fs.open(ir,is)if not ht then return nil,hN end;return setmetatable({_handle=ht},ie)end;function io.output(ht)if ib(ht)=="string"then local cB,hN=open(ht,"wb")if not cB then error(hN,2)end;iq=cB elseif ib(ht)=="table"and getmetatable(ht)==ie then iq=ht elseif ht~=nil then error("bad argument #1 (FILE expected, got "..ib(ht)..")",2)end;return iq end;function io.read(...)return ip:read(...)end;function io.type(it)if ib(it)=="table"and getmetatable(it)==ie then if it._closed then return"closed file"else return"file"end end;return nil end;function io.write(...)return iq:write(...)end end;if debug then local iu,iv=debug.getupvalue,debug.setupvalue;local iw,ix;function iw(iy,iz)if iy==iw then return nil end;for cc,b4 in pairs(fs)do if iy==b4 then return nil end end;return iu(iy,iz)end;function ix(iy,iz,iA)if iy==ix then return nil end;for cc,b4 in pairs(fs)do if iy==b4 then return nil end end;return iv(iy,iz,iA)end;debug.getupvalue=iw;debug.setupvalue=ix end;fs.unlock()print("FSEncrypt is now loaded.\nThe filesystem is now unlocked.")
--------------------------------------------------------------------------------------------------------------------------
-- sha2.lua
--------------------------------------------------------------------------------------------------------------------------
-- VERSION: 9 (2020-05-10)
-- AUTHOR: Egor Skriptunoff
-- LICENSE: MIT (the same license as Lua itself)
--
--
-- DESCRIPTION:
-- This module contains functions to calculate SHA digest:
-- MD5, SHA-1,
-- SHA-224, SHA-256, SHA-512/224, SHA-512/256, SHA-384, SHA-512,
-- SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256,
-- HMAC
-- Written in pure Lua.
-- Compatible with:
-- Lua 5.1, Lua 5.2, Lua 5.3, Lua 5.4, Fengari, LuaJIT 2.0/2.1 (any CPU endianness).
-- Main feature of this module: it was heavily optimized for speed.
-- For every Lua version the module contains particular implementation branch to get benefits from version-specific features.
-- - branch for Lua 5.1 (emulating bitwise operators using look-up table)
-- - branch for Lua 5.2 (using bit32/bit library), suitable for both Lua 5.2 with native "bit32" and Lua 5.1 with external library "bit"
-- - branch for Lua 5.3/5.4 (using native 64-bit bitwise operators)
-- - branch for Lua 5.3/5.4 (using native 32-bit bitwise operators) for Lua built with LUA_INT_TYPE=LUA_INT_INT
-- - branch for LuaJIT without FFI library (useful in a sandboxed environment)
-- - branch for LuaJIT x86 without FFI library (LuaJIT x86 has oddity because of lack of CPU registers)
-- - branch for LuaJIT 2.0 with FFI library (bit.* functions work only with Lua numbers)
-- - branch for LuaJIT 2.1 with FFI library (bit.* functions can work with "int64_t" arguments)
--
--
-- USAGE:
-- Input data should be provided as a binary string: either as a whole string or as a sequence of substrings (chunk-by-chunk loading, total length < 9*10^15 bytes).
-- Result (SHA digest) is returned in hexadecimal representation as a string of lowercase hex digits.
-- Simplest usage example:
-- local sha = require("sha2")
-- local your_hash = sha.sha256("your string")
-- See file "sha2_test.lua" for more examples.
--
--
-- CHANGELOG:
-- version date description
-- ------- ---------- -----------
-- 9 2020-05-10 Now works in OpenWrt's Lua (dialect of Lua 5.1 with "double" + "invisible int32")
-- 8 2019-09-03 SHA3 functions added
-- 7 2019-03-17 Added functions to convert to/from base64
-- 6 2018-11-12 HMAC added
-- 5 2018-11-10 SHA-1 added
-- 4 2018-11-03 MD5 added
-- 3 2018-11-02 Bug fixed: incorrect hashing of long (2 GByte) data streams on Lua 5.3/5.4 built with "int32" integers
-- 2 2018-10-07 Decreased module loading time in Lua 5.1 implementation branch (thanks to Peter Melnichenko for giving a hint)
-- 1 2018-10-06 First release (only SHA-2 functions)
-----------------------------------------------------------------------------
local print_debug_messages = false -- set to true to view some messages about your system's abilities and implementation branch chosen for your system
local unpack, table_concat, byte, char, string_rep, sub, gsub, gmatch, string_format, floor, ceil, math_min, math_max, tonumber, type =
table.unpack or unpack, table.concat, string.byte, string.char, string.rep, string.sub, string.gsub, string.gmatch, string.format, math.floor, math.ceil, math.min, math.max, tonumber, type
--------------------------------------------------------------------------------
-- EXAMINING YOUR SYSTEM
--------------------------------------------------------------------------------
local function get_precision(one)
-- "one" must be either float 1.0 or integer 1
-- returns bits_precision, is_integer
-- This function works correctly with all floating point datatypes (including non-IEEE-754)
local k, n, m, prev_n = 0, one, one
while true do
k, prev_n, n, m = k + 1, n, n + n + 1, m + m + k % 2
if k > 256 or n - (n - 1) ~= 1 or m - (m - 1) ~= 1 or n == m then
return k, false -- floating point datatype
elseif n == prev_n then
return k, true -- integer datatype
end
end
end
-- Make sure Lua has "double" numbers
local x = 2/3
local Lua_has_double = x * 5 > 3 and x * 4 < 3 and get_precision(1.0) >= 53
assert(Lua_has_double, "at least 53-bit floating point numbers are required")
-- Q:
-- SHA2 was designed for FPU-less machines.
-- So, why floating point numbers are needed for this module?
-- A:
-- 53-bit "double" numbers are useful to calculate "magic numbers" used in SHA.
-- I prefer to write 50 LOC "magic numbers calculator" instead of storing more than 200 constants explicitly in this source file.
local int_prec, Lua_has_integers = get_precision(1)
local Lua_has_int64 = Lua_has_integers and int_prec == 64
local Lua_has_int32 = Lua_has_integers and int_prec == 32
assert(Lua_has_int64 or Lua_has_int32 or not Lua_has_integers, "Lua integers must be either 32-bit or 64-bit")
-- Q:
-- Does it mean that almost all non-standard configurations are not supported?
-- A:
-- Yes. Sorry, too many problems to support all possible Lua numbers configurations.
-- Lua 5.1/5.2 with "int32" will not work.
-- Lua 5.1/5.2 with "int64" will not work.
-- Lua 5.1/5.2 with "int128" will not work.
-- Lua 5.1/5.2 with "float" will not work.
-- Lua 5.1/5.2 with "double" is OK. (default config for Lua 5.1, Lua 5.2, LuaJIT)
-- Lua 5.3/5.4 with "int32" + "float" will not work.
-- Lua 5.3/5.4 with "int64" + "float" will not work.
-- Lua 5.3/5.4 with "int128" + "float" will not work.
-- Lua 5.3/5.4 with "int32" + "double" is OK. (config used by Fengari)
-- Lua 5.3/5.4 with "int64" + "double" is OK. (default config for Lua 5.3, Lua 5.4)
-- Lua 5.3/5.4 with "int128" + "double" will not work.
-- Using floating point numbers better than "double" instead of "double" is OK (non-IEEE-754 floating point implementation are allowed).
-- Using "int128" instead of "int64" is not OK: "int128" would require different branch of implementation for optimized SHA512.
-- Check for LuaJIT and 32-bit bitwise libraries
local is_LuaJIT = ({false, [1] = true})[1] and (type(jit) ~= "table" or jit.version_num >= 20000) -- LuaJIT 1.x.x is treated as vanilla Lua 5.1
local is_LuaJIT_21 -- LuaJIT 2.1+
local LuaJIT_arch
local ffi -- LuaJIT FFI library (as a table)
local b -- 32-bit bitwise library (as a table)
local library_name
if is_LuaJIT then
-- Assuming "bit" library is always available on LuaJIT
b = require"bit"
library_name = "bit"
-- "ffi" is intentionally disabled on some systems for safety reason
local LuaJIT_has_FFI, result = pcall(require, "ffi")
if LuaJIT_has_FFI then
ffi = result
end
is_LuaJIT_21 = not not loadstring"b=0b0"
LuaJIT_arch = type(jit) == "table" and jit.arch or ffi and ffi.arch or nil
else
-- For vanilla Lua, "bit"/"bit32" libraries are searched in global namespace only. No attempt is made to load a library if it's not loaded yet.
for _, libname in ipairs((_VERSION == "Lua 5.2" or type(_HOST) == "string") and {"bit32", "bit"} or {"bit", "bit32"}) do
if type(_G[libname]) == "table" and _G[libname].bxor then
b = _G[libname]
library_name = libname
break
end
end
end
--------------------------------------------------------------------------------
-- You can disable here some of your system's abilities (for testing purposes)
--------------------------------------------------------------------------------
-- is_LuaJIT = nil
-- is_LuaJIT_21 = nil
-- ffi = nil
-- Lua_has_int32 = nil
-- Lua_has_int64 = nil
-- b, library_name = nil
--------------------------------------------------------------------------------
if print_debug_messages then
-- Printing list of abilities of your system
print("Abilities:")
print(" Lua version: "..(is_LuaJIT and "LuaJIT "..(is_LuaJIT_21 and "2.1 " or "2.0 ")..(LuaJIT_arch or "")..(ffi and " with FFI" or " without FFI") or _VERSION))
print(" Integer bitwise operators: "..(Lua_has_int64 and "int64" or Lua_has_int32 and "int32" or "no"))
print(" 32-bit bitwise library: "..(library_name or "not found"))
end
-- Selecting the most suitable implementation for given set of abilities
local method, branch
if is_LuaJIT and ffi then
method = "Using 'ffi' library of LuaJIT"
branch = "FFI"
elseif is_LuaJIT then
method = "Using special code for FFI-less LuaJIT"
branch = "LJ"
elseif Lua_has_int64 then
method = "Using native int64 bitwise operators"
branch = "INT64"
elseif Lua_has_int32 then
method = "Using native int32 bitwise operators"
branch = "INT32"
elseif library_name then -- when bitwise library is available (Lua 5.2 with native library "bit32" or Lua 5.1 with external library "bit")
method = "Using '"..library_name.."' library"
branch = "LIB32"
else
method = "Emulating bitwise operators using look-up table"
branch = "EMUL"
end
if print_debug_messages then
-- Printing the implementation selected to be used on your system
print("Implementation selected:")
print(" "..method)
end
--------------------------------------------------------------------------------
-- BASIC 32-BIT BITWISE FUNCTIONS
--------------------------------------------------------------------------------
local AND, OR, XOR, SHL, SHR, ROL, ROR, NOT, NORM, HEX, XOR_BYTE
-- Only low 32 bits of function arguments matter, high bits are ignored
-- The result of all functions (except HEX) is an integer inside "correct range":
-- for "bit" library: (-2^31)..(2^31-1)
-- for "bit32" library: 0..(2^32-1)
if branch == "FFI" or branch == "LJ" or branch == "LIB32" then
-- Your system has 32-bit bitwise library (either "bit" or "bit32")
AND = b.band -- 2 arguments
OR = b.bor -- 2 arguments
XOR = b.bxor -- 2..5 arguments
SHL = b.lshift -- second argument is integer 0..31
SHR = b.rshift -- second argument is integer 0..31
ROL = b.rol or b.lrotate -- second argument is integer 0..31
ROR = b.ror or b.rrotate -- second argument is integer 0..31
NOT = b.bnot -- only for LuaJIT
NORM = b.tobit -- only for LuaJIT
HEX = b.tohex -- returns string of 8 lowercase hexadecimal digits
assert(AND and OR and XOR and SHL and SHR and ROL and ROR and NOT, "Library '"..library_name.."' is incomplete")
XOR_BYTE = XOR -- XOR of two bytes (0..255)
elseif branch == "EMUL" then
-- Emulating 32-bit bitwise operations using 53-bit floating point arithmetic
function SHL(x, n)
return (x * 2^n) % 2^32
end
function SHR(x, n)
-- return (x % 2^32 - x % 2^n) / 2^n
x = x % 2^32 / 2^n
return x - x % 1
end
function ROL(x, n)
x = x % 2^32 * 2^n
local r = x % 2^32
return r + (x - r) / 2^32
end
function ROR(x, n)
x = x % 2^32 / 2^n
local r = x % 1
return r * 2^32 + (x - r)
end
local AND_of_two_bytes = {[0] = 0} -- look-up table (256*256 entries)
local idx = 0
for y = 0, 127 * 256, 256 do
for x = y, y + 127 do
x = AND_of_two_bytes[x] * 2
AND_of_two_bytes[idx] = x
AND_of_two_bytes[idx + 1] = x
AND_of_two_bytes[idx + 256] = x
AND_of_two_bytes[idx + 257] = x + 1
idx = idx + 2
end
idx = idx + 256
end
local function and_or_xor(x, y, operation)
-- operation: nil = AND, 1 = OR, 2 = XOR
local x0 = x % 2^32
local y0 = y % 2^32
local rx = x0 % 256
local ry = y0 % 256
local res = AND_of_two_bytes[rx + ry * 256]
x = x0 - rx
y = (y0 - ry) / 256
rx = x % 65536
ry = y % 256
res = res + AND_of_two_bytes[rx + ry] * 256
x = (x - rx) / 256
y = (y - ry) / 256
rx = x % 65536 + y % 256
res = res + AND_of_two_bytes[rx] * 65536
res = res + AND_of_two_bytes[(x + y - rx) / 256] * 16777216
if operation then
res = x0 + y0 - operation * res
end
return res
end
function AND(x, y)
return and_or_xor(x, y)
end
function OR(x, y)
return and_or_xor(x, y, 1)
end
function XOR(x, y, z, t, u) -- 2..5 arguments
if z then
if t then
if u then
t = and_or_xor(t, u, 2)
end
z = and_or_xor(z, t, 2)
end
y = and_or_xor(y, z, 2)
end
return and_or_xor(x, y, 2)
end
function XOR_BYTE(x, y)
return x + y - 2 * AND_of_two_bytes[x + y * 256]
end
end
HEX = HEX
or
pcall(string_format, "%x", 2^31) and
function (x) -- returns string of 8 lowercase hexadecimal digits
return string_format("%08x", x % 4294967296)
end
or
function (x) -- for OpenWrt's dialect of Lua
return string_format("%08x", (x + 2^31) % 2^32 - 2^31)
end
local function XOR32A5(x)
return XOR(x, 0xA5A5A5A5) % 4294967296
end
local function create_array_of_lanes()
return {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
end
--------------------------------------------------------------------------------
-- CREATING OPTIMIZED INNER LOOP
--------------------------------------------------------------------------------
-- Inner loop functions
local sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed
-- Arrays of SHA2 "magic numbers" (in "INT64" and "FFI" branches "*_lo" arrays contain 64-bit values)
local sha2_K_lo, sha2_K_hi, sha2_H_lo, sha2_H_hi, sha3_RC_lo, sha3_RC_hi = {}, {}, {}, {}, {}, {}
local sha2_H_ext256 = {[224] = {}, [256] = sha2_H_hi}
local sha2_H_ext512_lo, sha2_H_ext512_hi = {[384] = {}, [512] = sha2_H_lo}, {[384] = {}, [512] = sha2_H_hi}
local md5_K, md5_sha1_H = {}, {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0}
local md5_next_shift = {0, 0, 0, 0, 0, 0, 0, 0, 28, 25, 26, 27, 0, 0, 10, 9, 11, 12, 0, 15, 16, 17, 18, 0, 20, 22, 23, 21}
local HEX64, XOR64A5, lanes_index_base -- defined only for branches that internally use 64-bit integers: "INT64" and "FFI"
local common_W = {} -- temporary table shared between all calculations (to avoid creating new temporary table every time)
local K_lo_modulo, hi_factor, hi_factor_keccak = 4294967296, 0, 0
local function build_keccak_format(elem)
local keccak_format = {}
for _, size in ipairs{1, 9, 13, 17, 18, 21} do
keccak_format[size] = "<"..string_rep(elem, size)
end
return keccak_format
end
if branch == "FFI" then
-- SHA256 implementation for "LuaJIT with FFI" branch
local common_W_FFI_int32 = ffi.new"int32_t[80]" -- 64 is enough for SHA256, but 80 is needed for SHA-1
function sha256_feed_64(H, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 64
local W, K = common_W_FFI_int32, sha2_K_hi
for pos = offs, offs + size - 1, 64 do
for j = 0, 15 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos) -- slow, but doesn't depend on endianness
W[j] = OR(SHL(a, 24), SHL(b, 16), SHL(c, 8), d)
end
for j = 16, 63 do
local a, b = W[j-15], W[j-2]
W[j] = NORM( XOR(ROR(a, 7), ROL(a, 14), SHR(a, 3)) + XOR(ROL(b, 15), ROL(b, 13), SHR(b, 10)) + W[j-7] + W[j-16] )
end
local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
for j = 0, 63, 8 do -- Thanks to Peter Cawley for this workaround (unroll the loop to avoid "PHI shuffling too complex" due to PHIs overlap)
local z = NORM( XOR(g, AND(e, XOR(f, g))) + XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + (W[j] + K[j+1] + h) )
h, g, f, e = g, f, e, NORM( d + z )
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(g, AND(e, XOR(f, g))) + XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + (W[j+1] + K[j+2] + h) )
h, g, f, e = g, f, e, NORM( d + z )
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(g, AND(e, XOR(f, g))) + XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + (W[j+2] + K[j+3] + h) )
h, g, f, e = g, f, e, NORM( d + z )
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(g, AND(e, XOR(f, g))) + XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + (W[j+3] + K[j+4] + h) )
h, g, f, e = g, f, e, NORM( d + z )
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(g, AND(e, XOR(f, g))) + XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + (W[j+4] + K[j+5] + h) )
h, g, f, e = g, f, e, NORM( d + z )
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(g, AND(e, XOR(f, g))) + XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + (W[j+5] + K[j+6] + h) )
h, g, f, e = g, f, e, NORM( d + z )
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(g, AND(e, XOR(f, g))) + XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + (W[j+6] + K[j+7] + h) )
h, g, f, e = g, f, e, NORM( d + z )
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(g, AND(e, XOR(f, g))) + XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + (W[j+7] + K[j+8] + h) )
h, g, f, e = g, f, e, NORM( d + z )
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
end
H[1], H[2], H[3], H[4] = NORM(a + H[1]), NORM(b + H[2]), NORM(c + H[3]), NORM(d + H[4])
H[5], H[6], H[7], H[8] = NORM(e + H[5]), NORM(f + H[6]), NORM(g + H[7]), NORM(h + H[8])
end
end
local common_W_FFI_int64 = ffi.new"int64_t[80]"
local int64 = ffi.typeof"int64_t"
local int32 = ffi.typeof"int32_t"
local uint32 = ffi.typeof"uint32_t"
hi_factor = int64(2^32)
if is_LuaJIT_21 then -- LuaJIT 2.1 supports bitwise 64-bit operations
local AND64, OR64, XOR64, NOT64, SHL64, SHR64, ROL64, ROR64 -- introducing synonyms for better code readability
= AND, OR, XOR, NOT, SHL, SHR, ROL, ROR
HEX64 = HEX
-- SHA3 implementation for "LuaJIT 2.1 + FFI" branch
local lanes_arr64 = ffi.typeof"int64_t[30]" -- 25 + 5 for temporary usage
-- lanes array is indexed from 0
lanes_index_base = 0
hi_factor_keccak = int64(2^32)
function create_array_of_lanes()
return lanes_arr64()
end
function keccak_feed(lanes, _, str, offs, size, block_size_in_bytes)
-- offs >= 0, size >= 0, size is multiple of block_size_in_bytes, block_size_in_bytes is positive multiple of 8
local RC = sha3_RC_lo
local qwords_qty = SHR(block_size_in_bytes, 3)
for pos = offs, offs + size - 1, block_size_in_bytes do
for j = 0, qwords_qty - 1 do
pos = pos + 8
local h, g, f, e, d, c, b, a = byte(str, pos - 7, pos) -- slow, but doesn't depend on endianness
lanes[j] = XOR64(lanes[j], OR64(OR(SHL(a, 24), SHL(b, 16), SHL(c, 8), d) * int64(2^32), uint32(int32(OR(SHL(e, 24), SHL(f, 16), SHL(g, 8), h)))))
end
for round_idx = 1, 24 do
for j = 0, 4 do
lanes[25 + j] = XOR64(lanes[j], lanes[j+5], lanes[j+10], lanes[j+15], lanes[j+20])
end
local D = XOR64(lanes[25], ROL64(lanes[27], 1))
lanes[1], lanes[6], lanes[11], lanes[16] = ROL64(XOR64(D, lanes[6]), 44), ROL64(XOR64(D, lanes[16]), 45), ROL64(XOR64(D, lanes[1]), 1), ROL64(XOR64(D, lanes[11]), 10)
lanes[21] = ROL64(XOR64(D, lanes[21]), 2)
D = XOR64(lanes[26], ROL64(lanes[28], 1))
lanes[2], lanes[7], lanes[12], lanes[22] = ROL64(XOR64(D, lanes[12]), 43), ROL64(XOR64(D, lanes[22]), 61), ROL64(XOR64(D, lanes[7]), 6), ROL64(XOR64(D, lanes[2]), 62)
lanes[17] = ROL64(XOR64(D, lanes[17]), 15)
D = XOR64(lanes[27], ROL64(lanes[29], 1))
lanes[3], lanes[8], lanes[18], lanes[23] = ROL64(XOR64(D, lanes[18]), 21), ROL64(XOR64(D, lanes[3]), 28), ROL64(XOR64(D, lanes[23]), 56), ROL64(XOR64(D, lanes[8]), 55)
lanes[13] = ROL64(XOR64(D, lanes[13]), 25)
D = XOR64(lanes[28], ROL64(lanes[25], 1))
lanes[4], lanes[14], lanes[19], lanes[24] = ROL64(XOR64(D, lanes[24]), 14), ROL64(XOR64(D, lanes[19]), 8), ROL64(XOR64(D, lanes[4]), 27), ROL64(XOR64(D, lanes[14]), 39)
lanes[9] = ROL64(XOR64(D, lanes[9]), 20)
D = XOR64(lanes[29], ROL64(lanes[26], 1))
lanes[5], lanes[10], lanes[15], lanes[20] = ROL64(XOR64(D, lanes[10]), 3), ROL64(XOR64(D, lanes[20]), 18), ROL64(XOR64(D, lanes[5]), 36), ROL64(XOR64(D, lanes[15]), 41)
lanes[0] = XOR64(D, lanes[0])
lanes[0], lanes[1], lanes[2], lanes[3], lanes[4] = XOR64(lanes[0], AND64(NOT64(lanes[1]), lanes[2]), RC[round_idx]), XOR64(lanes[1], AND64(NOT64(lanes[2]), lanes[3])), XOR64(lanes[2], AND64(NOT64(lanes[3]), lanes[4])), XOR64(lanes[3], AND64(NOT64(lanes[4]), lanes[0])), XOR64(lanes[4], AND64(NOT64(lanes[0]), lanes[1]))
lanes[5], lanes[6], lanes[7], lanes[8], lanes[9] = XOR64(lanes[8], AND64(NOT64(lanes[9]), lanes[5])), XOR64(lanes[9], AND64(NOT64(lanes[5]), lanes[6])), XOR64(lanes[5], AND64(NOT64(lanes[6]), lanes[7])), XOR64(lanes[6], AND64(NOT64(lanes[7]), lanes[8])), XOR64(lanes[7], AND64(NOT64(lanes[8]), lanes[9]))
lanes[10], lanes[11], lanes[12], lanes[13], lanes[14] = XOR64(lanes[11], AND64(NOT64(lanes[12]), lanes[13])), XOR64(lanes[12], AND64(NOT64(lanes[13]), lanes[14])), XOR64(lanes[13], AND64(NOT64(lanes[14]), lanes[10])), XOR64(lanes[14], AND64(NOT64(lanes[10]), lanes[11])), XOR64(lanes[10], AND64(NOT64(lanes[11]), lanes[12]))
lanes[15], lanes[16], lanes[17], lanes[18], lanes[19] = XOR64(lanes[19], AND64(NOT64(lanes[15]), lanes[16])), XOR64(lanes[15], AND64(NOT64(lanes[16]), lanes[17])), XOR64(lanes[16], AND64(NOT64(lanes[17]), lanes[18])), XOR64(lanes[17], AND64(NOT64(lanes[18]), lanes[19])), XOR64(lanes[18], AND64(NOT64(lanes[19]), lanes[15]))
lanes[20], lanes[21], lanes[22], lanes[23], lanes[24] = XOR64(lanes[22], AND64(NOT64(lanes[23]), lanes[24])), XOR64(lanes[23], AND64(NOT64(lanes[24]), lanes[20])), XOR64(lanes[24], AND64(NOT64(lanes[20]), lanes[21])), XOR64(lanes[20], AND64(NOT64(lanes[21]), lanes[22])), XOR64(lanes[21], AND64(NOT64(lanes[22]), lanes[23]))
end
end
end
-- SHA512 implementation for "LuaJIT 2.1 + FFI" branch
local A5_long = 0xA5A5A5A5 * int64(2^32 + 1) -- It's impossible to use constant 0xA5A5A5A5A5A5A5A5LL because it will raise syntax error on other Lua versions
function XOR64A5(long)
return XOR64(long, A5_long)
end
function sha512_feed_128(H, _, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 128
local W, K = common_W_FFI_int64, sha2_K_lo
for pos = offs, offs + size - 1, 128 do
for j = 0, 15 do
pos = pos + 8
local a, b, c, d, e, f, g, h = byte(str, pos - 7, pos) -- slow, but doesn't depend on endianness
W[j] = OR64(OR(SHL(a, 24), SHL(b, 16), SHL(c, 8), d) * int64(2^32), uint32(int32(OR(SHL(e, 24), SHL(f, 16), SHL(g, 8), h))))
end
for j = 16, 79 do
local a, b = W[j-15], W[j-2]
W[j] = XOR64(ROR64(a, 1), ROR64(a, 8), SHR64(a, 7)) + XOR64(ROR64(b, 19), ROL64(b, 3), SHR64(b, 6)) + W[j-7] + W[j-16]
end
local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
for j = 0, 79, 8 do
local z = XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23)) + XOR64(g, AND64(e, XOR64(f, g))) + h + K[j+1] + W[j]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XOR64(AND64(XOR64(a, b), c), AND64(a, b)) + XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30)) + z
z = XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23)) + XOR64(g, AND64(e, XOR64(f, g))) + h + K[j+2] + W[j+1]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XOR64(AND64(XOR64(a, b), c), AND64(a, b)) + XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30)) + z
z = XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23)) + XOR64(g, AND64(e, XOR64(f, g))) + h + K[j+3] + W[j+2]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XOR64(AND64(XOR64(a, b), c), AND64(a, b)) + XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30)) + z
z = XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23)) + XOR64(g, AND64(e, XOR64(f, g))) + h + K[j+4] + W[j+3]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XOR64(AND64(XOR64(a, b), c), AND64(a, b)) + XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30)) + z
z = XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23)) + XOR64(g, AND64(e, XOR64(f, g))) + h + K[j+5] + W[j+4]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XOR64(AND64(XOR64(a, b), c), AND64(a, b)) + XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30)) + z
z = XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23)) + XOR64(g, AND64(e, XOR64(f, g))) + h + K[j+6] + W[j+5]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XOR64(AND64(XOR64(a, b), c), AND64(a, b)) + XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30)) + z
z = XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23)) + XOR64(g, AND64(e, XOR64(f, g))) + h + K[j+7] + W[j+6]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XOR64(AND64(XOR64(a, b), c), AND64(a, b)) + XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30)) + z
z = XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23)) + XOR64(g, AND64(e, XOR64(f, g))) + h + K[j+8] + W[j+7]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XOR64(AND64(XOR64(a, b), c), AND64(a, b)) + XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30)) + z
end
H[1] = a + H[1]
H[2] = b + H[2]
H[3] = c + H[3]
H[4] = d + H[4]
H[5] = e + H[5]
H[6] = f + H[6]
H[7] = g + H[7]
H[8] = h + H[8]
end
end
else -- LuaJIT 2.0 doesn't support 64-bit bitwise operations
-- SHA512 implementation for "LuaJIT 2.0 + FFI" branch
local union64 = ffi.typeof"union{int64_t i64; struct{int32_t lo, hi;} i32;}"
do -- make sure the struct is endianness-compatible
local u = union64(1)
if u.i32.lo < u.i32.hi then
union64 = ffi.typeof"union{int64_t i64; struct{int32_t hi, lo;} i32;}"
end
end
local unions64 = ffi.typeof("$[?]", union64)
local U = unions64(3) -- this array of unions is used for fast splitting int64 into int32_high and int32_low
-- "xorrific" 64-bit functions :-)
-- int64 input is splitted into two int32 parts, some bitwise 32-bit operations are performed, finally the result is converted to int64
-- these functions are needed because bit.* functions in LuaJIT 2.0 don't work with int64_t
local function XORROR64_1(a)
-- return XOR64(ROR64(a, 1), ROR64(a, 8), SHR64(a, 7))
U[0].i64 = a
local a_lo, a_hi = U[0].i32.lo, U[0].i32.hi
local t_lo = XOR(OR(SHR(a_lo, 1), SHL(a_hi, 31)), OR(SHR(a_lo, 8), SHL(a_hi, 24)), OR(SHR(a_lo, 7), SHL(a_hi, 25)))
local t_hi = XOR(OR(SHR(a_hi, 1), SHL(a_lo, 31)), OR(SHR(a_hi, 8), SHL(a_lo, 24)), SHR(a_hi, 7))
return t_hi * int64(2^32) + uint32(int32(t_lo))
end
local function XORROR64_2(b)
-- return XOR64(ROR64(b, 19), ROL64(b, 3), SHR64(b, 6))
U[0].i64 = b
local b_lo, b_hi = U[0].i32.lo, U[0].i32.hi
local u_lo = XOR(OR(SHR(b_lo, 19), SHL(b_hi, 13)), OR(SHL(b_lo, 3), SHR(b_hi, 29)), OR(SHR(b_lo, 6), SHL(b_hi, 26)))
local u_hi = XOR(OR(SHR(b_hi, 19), SHL(b_lo, 13)), OR(SHL(b_hi, 3), SHR(b_lo, 29)), SHR(b_hi, 6))
return u_hi * int64(2^32) + uint32(int32(u_lo))
end
local function XORROR64_3(e)
-- return XOR64(ROR64(e, 14), ROR64(e, 18), ROL64(e, 23))
U[0].i64 = e
local e_lo, e_hi = U[0].i32.lo, U[0].i32.hi
local u_lo = XOR(OR(SHR(e_lo, 14), SHL(e_hi, 18)), OR(SHR(e_lo, 18), SHL(e_hi, 14)), OR(SHL(e_lo, 23), SHR(e_hi, 9)))
local u_hi = XOR(OR(SHR(e_hi, 14), SHL(e_lo, 18)), OR(SHR(e_hi, 18), SHL(e_lo, 14)), OR(SHL(e_hi, 23), SHR(e_lo, 9)))
return u_hi * int64(2^32) + uint32(int32(u_lo))
end
local function XORROR64_6(a)
-- return XOR64(ROR64(a, 28), ROL64(a, 25), ROL64(a, 30))
U[0].i64 = a
local b_lo, b_hi = U[0].i32.lo, U[0].i32.hi
local u_lo = XOR(OR(SHR(b_lo, 28), SHL(b_hi, 4)), OR(SHL(b_lo, 30), SHR(b_hi, 2)), OR(SHL(b_lo, 25), SHR(b_hi, 7)))
local u_hi = XOR(OR(SHR(b_hi, 28), SHL(b_lo, 4)), OR(SHL(b_hi, 30), SHR(b_lo, 2)), OR(SHL(b_hi, 25), SHR(b_lo, 7)))
return u_hi * int64(2^32) + uint32(int32(u_lo))
end
local function XORROR64_4(e, f, g)
-- return XOR64(g, AND64(e, XOR64(f, g)))
U[0].i64 = f
U[1].i64 = g
U[2].i64 = e
local f_lo, f_hi = U[0].i32.lo, U[0].i32.hi
local g_lo, g_hi = U[1].i32.lo, U[1].i32.hi
local e_lo, e_hi = U[2].i32.lo, U[2].i32.hi
local result_lo = XOR(g_lo, AND(e_lo, XOR(f_lo, g_lo)))
local result_hi = XOR(g_hi, AND(e_hi, XOR(f_hi, g_hi)))
return result_hi * int64(2^32) + uint32(int32(result_lo))
end
local function XORROR64_5(a, b, c)
-- return XOR64(AND64(XOR64(a, b), c), AND64(a, b))
U[0].i64 = a
U[1].i64 = b
U[2].i64 = c
local a_lo, a_hi = U[0].i32.lo, U[0].i32.hi
local b_lo, b_hi = U[1].i32.lo, U[1].i32.hi
local c_lo, c_hi = U[2].i32.lo, U[2].i32.hi
local result_lo = XOR(AND(XOR(a_lo, b_lo), c_lo), AND(a_lo, b_lo))
local result_hi = XOR(AND(XOR(a_hi, b_hi), c_hi), AND(a_hi, b_hi))
return result_hi * int64(2^32) + uint32(int32(result_lo))
end
function XOR64A5(long)
-- return XOR64(long, 0xA5A5A5A5A5A5A5A5)
U[0].i64 = long
local lo32, hi32 = U[0].i32.lo, U[0].i32.hi
lo32 = XOR(lo32, 0xA5A5A5A5)
hi32 = XOR(hi32, 0xA5A5A5A5)
return hi32 * int64(2^32) + uint32(int32(lo32))
end
function HEX64(long)
U[0].i64 = long
return HEX(U[0].i32.hi)..HEX(U[0].i32.lo)
end
function sha512_feed_128(H, _, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 128
local W, K = common_W_FFI_int64, sha2_K_lo
for pos = offs, offs + size - 1, 128 do
for j = 0, 15 do
pos = pos + 8
local a, b, c, d, e, f, g, h = byte(str, pos - 7, pos) -- slow, but doesn't depend on endianness
W[j] = OR(SHL(a, 24), SHL(b, 16), SHL(c, 8), d) * int64(2^32) + uint32(int32(OR(SHL(e, 24), SHL(f, 16), SHL(g, 8), h)))
end
for j = 16, 79 do
W[j] = XORROR64_1(W[j-15]) + XORROR64_2(W[j-2]) + W[j-7] + W[j-16]
end
local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
for j = 0, 79, 8 do
local z = XORROR64_3(e) + XORROR64_4(e, f, g) + h + K[j+1] + W[j]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XORROR64_5(a, b, c) + XORROR64_6(a) + z
z = XORROR64_3(e) + XORROR64_4(e, f, g) + h + K[j+2] + W[j+1]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XORROR64_5(a, b, c) + XORROR64_6(a) + z
z = XORROR64_3(e) + XORROR64_4(e, f, g) + h + K[j+3] + W[j+2]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XORROR64_5(a, b, c) + XORROR64_6(a) + z
z = XORROR64_3(e) + XORROR64_4(e, f, g) + h + K[j+4] + W[j+3]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XORROR64_5(a, b, c) + XORROR64_6(a) + z
z = XORROR64_3(e) + XORROR64_4(e, f, g) + h + K[j+5] + W[j+4]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XORROR64_5(a, b, c) + XORROR64_6(a) + z
z = XORROR64_3(e) + XORROR64_4(e, f, g) + h + K[j+6] + W[j+5]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XORROR64_5(a, b, c) + XORROR64_6(a) + z
z = XORROR64_3(e) + XORROR64_4(e, f, g) + h + K[j+7] + W[j+6]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XORROR64_5(a, b, c) + XORROR64_6(a) + z
z = XORROR64_3(e) + XORROR64_4(e, f, g) + h + K[j+8] + W[j+7]
h, g, f, e = g, f, e, z + d
d, c, b, a = c, b, a, XORROR64_5(a, b, c) + XORROR64_6(a) + z
end
H[1] = a + H[1]
H[2] = b + H[2]
H[3] = c + H[3]
H[4] = d + H[4]
H[5] = e + H[5]
H[6] = f + H[6]
H[7] = g + H[7]
H[8] = h + H[8]
end
end
end
-- MD5 implementation for "LuaJIT with FFI" branch
function md5_feed_64(H, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 64
local W, K = common_W_FFI_int32, md5_K
for pos = offs, offs + size - 1, 64 do
for j = 0, 15 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos) -- slow, but doesn't depend on endianness
W[j] = OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a)
end
local a, b, c, d = H[1], H[2], H[3], H[4]
for j = 0, 15, 4 do
a, d, c, b = d, c, b, NORM(ROL(XOR(d, AND(b, XOR(c, d))) + (K[j+1] + W[j ] + a), 7) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(d, AND(b, XOR(c, d))) + (K[j+2] + W[j+1] + a), 12) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(d, AND(b, XOR(c, d))) + (K[j+3] + W[j+2] + a), 17) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(d, AND(b, XOR(c, d))) + (K[j+4] + W[j+3] + a), 22) + b)
end
for j = 16, 31, 4 do
local g = 5*j
a, d, c, b = d, c, b, NORM(ROL(XOR(c, AND(d, XOR(b, c))) + (K[j+1] + W[AND(g + 1, 15)] + a), 5) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, AND(d, XOR(b, c))) + (K[j+2] + W[AND(g + 6, 15)] + a), 9) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, AND(d, XOR(b, c))) + (K[j+3] + W[AND(g - 5, 15)] + a), 14) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, AND(d, XOR(b, c))) + (K[j+4] + W[AND(g , 15)] + a), 20) + b)
end
for j = 32, 47, 4 do
local g = 3*j
a, d, c, b = d, c, b, NORM(ROL(XOR(b, c, d) + (K[j+1] + W[AND(g + 5, 15)] + a), 4) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(b, c, d) + (K[j+2] + W[AND(g + 8, 15)] + a), 11) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(b, c, d) + (K[j+3] + W[AND(g - 5, 15)] + a), 16) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(b, c, d) + (K[j+4] + W[AND(g - 2, 15)] + a), 23) + b)
end
for j = 48, 63, 4 do
local g = 7*j
a, d, c, b = d, c, b, NORM(ROL(XOR(c, OR(b, NOT(d))) + (K[j+1] + W[AND(g , 15)] + a), 6) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, OR(b, NOT(d))) + (K[j+2] + W[AND(g + 7, 15)] + a), 10) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, OR(b, NOT(d))) + (K[j+3] + W[AND(g - 2, 15)] + a), 15) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, OR(b, NOT(d))) + (K[j+4] + W[AND(g + 5, 15)] + a), 21) + b)
end
H[1], H[2], H[3], H[4] = NORM(a + H[1]), NORM(b + H[2]), NORM(c + H[3]), NORM(d + H[4])
end
end
-- SHA-1 implementation for "LuaJIT with FFI" branch
function sha1_feed_64(H, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 64
local W = common_W_FFI_int32
for pos = offs, offs + size - 1, 64 do
for j = 0, 15 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos) -- slow, but doesn't depend on endianness
W[j] = OR(SHL(a, 24), SHL(b, 16), SHL(c, 8), d)
end
for j = 16, 79 do
W[j] = ROL(XOR(W[j-3], W[j-8], W[j-14], W[j-16]), 1)
end
local a, b, c, d, e = H[1], H[2], H[3], H[4], H[5]
for j = 0, 19, 5 do
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j] + 0x5A827999 + e)) -- constant = floor(2^30 * sqrt(2))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j+1] + 0x5A827999 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j+2] + 0x5A827999 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j+3] + 0x5A827999 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j+4] + 0x5A827999 + e))
end
for j = 20, 39, 5 do
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j] + 0x6ED9EBA1 + e)) -- 2^30 * sqrt(3)
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+1] + 0x6ED9EBA1 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+2] + 0x6ED9EBA1 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+3] + 0x6ED9EBA1 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+4] + 0x6ED9EBA1 + e))
end
for j = 40, 59, 5 do
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j] + 0x8F1BBCDC + e)) -- 2^30 * sqrt(5)
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j+1] + 0x8F1BBCDC + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j+2] + 0x8F1BBCDC + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j+3] + 0x8F1BBCDC + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j+4] + 0x8F1BBCDC + e))
end
for j = 60, 79, 5 do
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j] + 0xCA62C1D6 + e)) -- 2^30 * sqrt(10)
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+1] + 0xCA62C1D6 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+2] + 0xCA62C1D6 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+3] + 0xCA62C1D6 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+4] + 0xCA62C1D6 + e))
end
H[1], H[2], H[3], H[4], H[5] = NORM(a + H[1]), NORM(b + H[2]), NORM(c + H[3]), NORM(d + H[4]), NORM(e + H[5])
end
end
end
-- SHA3 implementation for "LuaJIT 2.0 + FFI" and "LuaJIT without FFI" branches
if branch == "FFI" and not is_LuaJIT_21 or branch == "LJ" then
if branch == "FFI" then
local lanes_arr32 = ffi.typeof"int32_t[31]" -- 25 + 5 + 1 (due to 1-based indexing)
function create_array_of_lanes()
return lanes_arr32()
end
end
function keccak_feed(lanes_lo, lanes_hi, str, offs, size, block_size_in_bytes)
-- offs >= 0, size >= 0, size is multiple of block_size_in_bytes, block_size_in_bytes is positive multiple of 8
local RC_lo, RC_hi = sha3_RC_lo, sha3_RC_hi
local qwords_qty = SHR(block_size_in_bytes, 3)
for pos = offs, offs + size - 1, block_size_in_bytes do
for j = 1, qwords_qty do
local a, b, c, d = byte(str, pos + 1, pos + 4)
lanes_lo[j] = XOR(lanes_lo[j], OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a))
pos = pos + 8
a, b, c, d = byte(str, pos - 3, pos)
lanes_hi[j] = XOR(lanes_hi[j], OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a))
end
for round_idx = 1, 24 do
for j = 1, 5 do
lanes_lo[25 + j] = XOR(lanes_lo[j], lanes_lo[j + 5], lanes_lo[j + 10], lanes_lo[j + 15], lanes_lo[j + 20])
end
for j = 1, 5 do
lanes_hi[25 + j] = XOR(lanes_hi[j], lanes_hi[j + 5], lanes_hi[j + 10], lanes_hi[j + 15], lanes_hi[j + 20])
end
local D_lo = XOR(lanes_lo[26], SHL(lanes_lo[28], 1), SHR(lanes_hi[28], 31))
local D_hi = XOR(lanes_hi[26], SHL(lanes_hi[28], 1), SHR(lanes_lo[28], 31))
lanes_lo[2], lanes_hi[2], lanes_lo[7], lanes_hi[7], lanes_lo[12], lanes_hi[12], lanes_lo[17], lanes_hi[17] = XOR(SHR(XOR(D_lo, lanes_lo[7]), 20), SHL(XOR(D_hi, lanes_hi[7]), 12)), XOR(SHR(XOR(D_hi, lanes_hi[7]), 20), SHL(XOR(D_lo, lanes_lo[7]), 12)), XOR(SHR(XOR(D_lo, lanes_lo[17]), 19), SHL(XOR(D_hi, lanes_hi[17]), 13)), XOR(SHR(XOR(D_hi, lanes_hi[17]), 19), SHL(XOR(D_lo, lanes_lo[17]), 13)), XOR(SHL(XOR(D_lo, lanes_lo[2]), 1), SHR(XOR(D_hi, lanes_hi[2]), 31)), XOR(SHL(XOR(D_hi, lanes_hi[2]), 1), SHR(XOR(D_lo, lanes_lo[2]), 31)), XOR(SHL(XOR(D_lo, lanes_lo[12]), 10), SHR(XOR(D_hi, lanes_hi[12]), 22)), XOR(SHL(XOR(D_hi, lanes_hi[12]), 10), SHR(XOR(D_lo, lanes_lo[12]), 22))
local L, H = XOR(D_lo, lanes_lo[22]), XOR(D_hi, lanes_hi[22])
lanes_lo[22], lanes_hi[22] = XOR(SHL(L, 2), SHR(H, 30)), XOR(SHL(H, 2), SHR(L, 30))
D_lo = XOR(lanes_lo[27], SHL(lanes_lo[29], 1), SHR(lanes_hi[29], 31))
D_hi = XOR(lanes_hi[27], SHL(lanes_hi[29], 1), SHR(lanes_lo[29], 31))
lanes_lo[3], lanes_hi[3], lanes_lo[8], lanes_hi[8], lanes_lo[13], lanes_hi[13], lanes_lo[23], lanes_hi[23] = XOR(SHR(XOR(D_lo, lanes_lo[13]), 21), SHL(XOR(D_hi, lanes_hi[13]), 11)), XOR(SHR(XOR(D_hi, lanes_hi[13]), 21), SHL(XOR(D_lo, lanes_lo[13]), 11)), XOR(SHR(XOR(D_lo, lanes_lo[23]), 3), SHL(XOR(D_hi, lanes_hi[23]), 29)), XOR(SHR(XOR(D_hi, lanes_hi[23]), 3), SHL(XOR(D_lo, lanes_lo[23]), 29)), XOR(SHL(XOR(D_lo, lanes_lo[8]), 6), SHR(XOR(D_hi, lanes_hi[8]), 26)), XOR(SHL(XOR(D_hi, lanes_hi[8]), 6), SHR(XOR(D_lo, lanes_lo[8]), 26)), XOR(SHR(XOR(D_lo, lanes_lo[3]), 2), SHL(XOR(D_hi, lanes_hi[3]), 30)), XOR(SHR(XOR(D_hi, lanes_hi[3]), 2), SHL(XOR(D_lo, lanes_lo[3]), 30))
L, H = XOR(D_lo, lanes_lo[18]), XOR(D_hi, lanes_hi[18])
lanes_lo[18], lanes_hi[18] = XOR(SHL(L, 15), SHR(H, 17)), XOR(SHL(H, 15), SHR(L, 17))
D_lo = XOR(lanes_lo[28], SHL(lanes_lo[30], 1), SHR(lanes_hi[30], 31))
D_hi = XOR(lanes_hi[28], SHL(lanes_hi[30], 1), SHR(lanes_lo[30], 31))
lanes_lo[4], lanes_hi[4], lanes_lo[9], lanes_hi[9], lanes_lo[19], lanes_hi[19], lanes_lo[24], lanes_hi[24] = XOR(SHL(XOR(D_lo, lanes_lo[19]), 21), SHR(XOR(D_hi, lanes_hi[19]), 11)), XOR(SHL(XOR(D_hi, lanes_hi[19]), 21), SHR(XOR(D_lo, lanes_lo[19]), 11)), XOR(SHL(XOR(D_lo, lanes_lo[4]), 28), SHR(XOR(D_hi, lanes_hi[4]), 4)), XOR(SHL(XOR(D_hi, lanes_hi[4]), 28), SHR(XOR(D_lo, lanes_lo[4]), 4)), XOR(SHR(XOR(D_lo, lanes_lo[24]), 8), SHL(XOR(D_hi, lanes_hi[24]), 24)), XOR(SHR(XOR(D_hi, lanes_hi[24]), 8), SHL(XOR(D_lo, lanes_lo[24]), 24)), XOR(SHR(XOR(D_lo, lanes_lo[9]), 9), SHL(XOR(D_hi, lanes_hi[9]), 23)), XOR(SHR(XOR(D_hi, lanes_hi[9]), 9), SHL(XOR(D_lo, lanes_lo[9]), 23))
L, H = XOR(D_lo, lanes_lo[14]), XOR(D_hi, lanes_hi[14])
lanes_lo[14], lanes_hi[14] = XOR(SHL(L, 25), SHR(H, 7)), XOR(SHL(H, 25), SHR(L, 7))
D_lo = XOR(lanes_lo[29], SHL(lanes_lo[26], 1), SHR(lanes_hi[26], 31))
D_hi = XOR(lanes_hi[29], SHL(lanes_hi[26], 1), SHR(lanes_lo[26], 31))
lanes_lo[5], lanes_hi[5], lanes_lo[15], lanes_hi[15], lanes_lo[20], lanes_hi[20], lanes_lo[25], lanes_hi[25] = XOR(SHL(XOR(D_lo, lanes_lo[25]), 14), SHR(XOR(D_hi, lanes_hi[25]), 18)), XOR(SHL(XOR(D_hi, lanes_hi[25]), 14), SHR(XOR(D_lo, lanes_lo[25]), 18)), XOR(SHL(XOR(D_lo, lanes_lo[20]), 8), SHR(XOR(D_hi, lanes_hi[20]), 24)), XOR(SHL(XOR(D_hi, lanes_hi[20]), 8), SHR(XOR(D_lo, lanes_lo[20]), 24)), XOR(SHL(XOR(D_lo, lanes_lo[5]), 27), SHR(XOR(D_hi, lanes_hi[5]), 5)), XOR(SHL(XOR(D_hi, lanes_hi[5]), 27), SHR(XOR(D_lo, lanes_lo[5]), 5)), XOR(SHR(XOR(D_lo, lanes_lo[15]), 25), SHL(XOR(D_hi, lanes_hi[15]), 7)), XOR(SHR(XOR(D_hi, lanes_hi[15]), 25), SHL(XOR(D_lo, lanes_lo[15]), 7))
L, H = XOR(D_lo, lanes_lo[10]), XOR(D_hi, lanes_hi[10])
lanes_lo[10], lanes_hi[10] = XOR(SHL(L, 20), SHR(H, 12)), XOR(SHL(H, 20), SHR(L, 12))
D_lo = XOR(lanes_lo[30], SHL(lanes_lo[27], 1), SHR(lanes_hi[27], 31))
D_hi = XOR(lanes_hi[30], SHL(lanes_hi[27], 1), SHR(lanes_lo[27], 31))
lanes_lo[6], lanes_hi[6], lanes_lo[11], lanes_hi[11], lanes_lo[16], lanes_hi[16], lanes_lo[21], lanes_hi[21] = XOR(SHL(XOR(D_lo, lanes_lo[11]), 3), SHR(XOR(D_hi, lanes_hi[11]), 29)), XOR(SHL(XOR(D_hi, lanes_hi[11]), 3), SHR(XOR(D_lo, lanes_lo[11]), 29)), XOR(SHL(XOR(D_lo, lanes_lo[21]), 18), SHR(XOR(D_hi, lanes_hi[21]), 14)), XOR(SHL(XOR(D_hi, lanes_hi[21]), 18), SHR(XOR(D_lo, lanes_lo[21]), 14)), XOR(SHR(XOR(D_lo, lanes_lo[6]), 28), SHL(XOR(D_hi, lanes_hi[6]), 4)), XOR(SHR(XOR(D_hi, lanes_hi[6]), 28), SHL(XOR(D_lo, lanes_lo[6]), 4)), XOR(SHR(XOR(D_lo, lanes_lo[16]), 23), SHL(XOR(D_hi, lanes_hi[16]), 9)), XOR(SHR(XOR(D_hi, lanes_hi[16]), 23), SHL(XOR(D_lo, lanes_lo[16]), 9))
lanes_lo[1], lanes_hi[1] = XOR(D_lo, lanes_lo[1]), XOR(D_hi, lanes_hi[1])
lanes_lo[1], lanes_lo[2], lanes_lo[3], lanes_lo[4], lanes_lo[5] = XOR(lanes_lo[1], AND(NOT(lanes_lo[2]), lanes_lo[3]), RC_lo[round_idx]), XOR(lanes_lo[2], AND(NOT(lanes_lo[3]), lanes_lo[4])), XOR(lanes_lo[3], AND(NOT(lanes_lo[4]), lanes_lo[5])), XOR(lanes_lo[4], AND(NOT(lanes_lo[5]), lanes_lo[1])), XOR(lanes_lo[5], AND(NOT(lanes_lo[1]), lanes_lo[2]))
lanes_lo[6], lanes_lo[7], lanes_lo[8], lanes_lo[9], lanes_lo[10] = XOR(lanes_lo[9], AND(NOT(lanes_lo[10]), lanes_lo[6])), XOR(lanes_lo[10], AND(NOT(lanes_lo[6]), lanes_lo[7])), XOR(lanes_lo[6], AND(NOT(lanes_lo[7]), lanes_lo[8])), XOR(lanes_lo[7], AND(NOT(lanes_lo[8]), lanes_lo[9])), XOR(lanes_lo[8], AND(NOT(lanes_lo[9]), lanes_lo[10]))
lanes_lo[11], lanes_lo[12], lanes_lo[13], lanes_lo[14], lanes_lo[15] = XOR(lanes_lo[12], AND(NOT(lanes_lo[13]), lanes_lo[14])), XOR(lanes_lo[13], AND(NOT(lanes_lo[14]), lanes_lo[15])), XOR(lanes_lo[14], AND(NOT(lanes_lo[15]), lanes_lo[11])), XOR(lanes_lo[15], AND(NOT(lanes_lo[11]), lanes_lo[12])), XOR(lanes_lo[11], AND(NOT(lanes_lo[12]), lanes_lo[13]))
lanes_lo[16], lanes_lo[17], lanes_lo[18], lanes_lo[19], lanes_lo[20] = XOR(lanes_lo[20], AND(NOT(lanes_lo[16]), lanes_lo[17])), XOR(lanes_lo[16], AND(NOT(lanes_lo[17]), lanes_lo[18])), XOR(lanes_lo[17], AND(NOT(lanes_lo[18]), lanes_lo[19])), XOR(lanes_lo[18], AND(NOT(lanes_lo[19]), lanes_lo[20])), XOR(lanes_lo[19], AND(NOT(lanes_lo[20]), lanes_lo[16]))
lanes_lo[21], lanes_lo[22], lanes_lo[23], lanes_lo[24], lanes_lo[25] = XOR(lanes_lo[23], AND(NOT(lanes_lo[24]), lanes_lo[25])), XOR(lanes_lo[24], AND(NOT(lanes_lo[25]), lanes_lo[21])), XOR(lanes_lo[25], AND(NOT(lanes_lo[21]), lanes_lo[22])), XOR(lanes_lo[21], AND(NOT(lanes_lo[22]), lanes_lo[23])), XOR(lanes_lo[22], AND(NOT(lanes_lo[23]), lanes_lo[24]))
lanes_hi[1], lanes_hi[2], lanes_hi[3], lanes_hi[4], lanes_hi[5] = XOR(lanes_hi[1], AND(NOT(lanes_hi[2]), lanes_hi[3]), RC_hi[round_idx]), XOR(lanes_hi[2], AND(NOT(lanes_hi[3]), lanes_hi[4])), XOR(lanes_hi[3], AND(NOT(lanes_hi[4]), lanes_hi[5])), XOR(lanes_hi[4], AND(NOT(lanes_hi[5]), lanes_hi[1])), XOR(lanes_hi[5], AND(NOT(lanes_hi[1]), lanes_hi[2]))
lanes_hi[6], lanes_hi[7], lanes_hi[8], lanes_hi[9], lanes_hi[10] = XOR(lanes_hi[9], AND(NOT(lanes_hi[10]), lanes_hi[6])), XOR(lanes_hi[10], AND(NOT(lanes_hi[6]), lanes_hi[7])), XOR(lanes_hi[6], AND(NOT(lanes_hi[7]), lanes_hi[8])), XOR(lanes_hi[7], AND(NOT(lanes_hi[8]), lanes_hi[9])), XOR(lanes_hi[8], AND(NOT(lanes_hi[9]), lanes_hi[10]))
lanes_hi[11], lanes_hi[12], lanes_hi[13], lanes_hi[14], lanes_hi[15] = XOR(lanes_hi[12], AND(NOT(lanes_hi[13]), lanes_hi[14])), XOR(lanes_hi[13], AND(NOT(lanes_hi[14]), lanes_hi[15])), XOR(lanes_hi[14], AND(NOT(lanes_hi[15]), lanes_hi[11])), XOR(lanes_hi[15], AND(NOT(lanes_hi[11]), lanes_hi[12])), XOR(lanes_hi[11], AND(NOT(lanes_hi[12]), lanes_hi[13]))
lanes_hi[16], lanes_hi[17], lanes_hi[18], lanes_hi[19], lanes_hi[20] = XOR(lanes_hi[20], AND(NOT(lanes_hi[16]), lanes_hi[17])), XOR(lanes_hi[16], AND(NOT(lanes_hi[17]), lanes_hi[18])), XOR(lanes_hi[17], AND(NOT(lanes_hi[18]), lanes_hi[19])), XOR(lanes_hi[18], AND(NOT(lanes_hi[19]), lanes_hi[20])), XOR(lanes_hi[19], AND(NOT(lanes_hi[20]), lanes_hi[16]))
lanes_hi[21], lanes_hi[22], lanes_hi[23], lanes_hi[24], lanes_hi[25] = XOR(lanes_hi[23], AND(NOT(lanes_hi[24]), lanes_hi[25])), XOR(lanes_hi[24], AND(NOT(lanes_hi[25]), lanes_hi[21])), XOR(lanes_hi[25], AND(NOT(lanes_hi[21]), lanes_hi[22])), XOR(lanes_hi[21], AND(NOT(lanes_hi[22]), lanes_hi[23])), XOR(lanes_hi[22], AND(NOT(lanes_hi[23]), lanes_hi[24]))
end
end
end
end
if branch == "LJ" then
-- SHA256 implementation for "LuaJIT without FFI" branch
function sha256_feed_64(H, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 64
local W, K = common_W, sha2_K_hi
for pos = offs, offs + size - 1, 64 do
for j = 1, 16 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos)
W[j] = OR(SHL(a, 24), SHL(b, 16), SHL(c, 8), d)
end
for j = 17, 64 do
local a, b = W[j-15], W[j-2]
W[j] = NORM( NORM( XOR(ROR(a, 7), ROL(a, 14), SHR(a, 3)) + XOR(ROL(b, 15), ROL(b, 13), SHR(b, 10)) ) + NORM( W[j-7] + W[j-16] ) )
end
local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
for j = 1, 64, 8 do -- Thanks to Peter Cawley for this workaround (unroll the loop to avoid "PHI shuffling too complex" due to PHIs overlap)
local z = NORM( XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + XOR(g, AND(e, XOR(f, g))) + (K[j] + W[j] + h) )
h, g, f, e = g, f, e, NORM(d + z)
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + XOR(g, AND(e, XOR(f, g))) + (K[j+1] + W[j+1] + h) )
h, g, f, e = g, f, e, NORM(d + z)
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + XOR(g, AND(e, XOR(f, g))) + (K[j+2] + W[j+2] + h) )
h, g, f, e = g, f, e, NORM(d + z)
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + XOR(g, AND(e, XOR(f, g))) + (K[j+3] + W[j+3] + h) )
h, g, f, e = g, f, e, NORM(d + z)
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + XOR(g, AND(e, XOR(f, g))) + (K[j+4] + W[j+4] + h) )
h, g, f, e = g, f, e, NORM(d + z)
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + XOR(g, AND(e, XOR(f, g))) + (K[j+5] + W[j+5] + h) )
h, g, f, e = g, f, e, NORM(d + z)
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + XOR(g, AND(e, XOR(f, g))) + (K[j+6] + W[j+6] + h) )
h, g, f, e = g, f, e, NORM(d + z)
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
z = NORM( XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + XOR(g, AND(e, XOR(f, g))) + (K[j+7] + W[j+7] + h) )
h, g, f, e = g, f, e, NORM(d + z)
d, c, b, a = c, b, a, NORM( XOR(AND(a, XOR(b, c)), AND(b, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10)) + z )
end
H[1], H[2], H[3], H[4] = NORM(a + H[1]), NORM(b + H[2]), NORM(c + H[3]), NORM(d + H[4])
H[5], H[6], H[7], H[8] = NORM(e + H[5]), NORM(f + H[6]), NORM(g + H[7]), NORM(h + H[8])
end
end
local function ADD64_4(a_lo, a_hi, b_lo, b_hi, c_lo, c_hi, d_lo, d_hi)
local sum_lo = a_lo % 2^32 + b_lo % 2^32 + c_lo % 2^32 + d_lo % 2^32
local sum_hi = a_hi + b_hi + c_hi + d_hi
local result_lo = NORM( sum_lo )
local result_hi = NORM( sum_hi + floor(sum_lo / 2^32) )
return result_lo, result_hi
end
if LuaJIT_arch == "x86" then -- Special trick is required to avoid "PHI shuffling too complex" on x86 platform
-- SHA512 implementation for "LuaJIT x86 without FFI" branch
function sha512_feed_128(H_lo, H_hi, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 128
-- W1_hi, W1_lo, W2_hi, W2_lo, ... Wk_hi = W[2*k-1], Wk_lo = W[2*k]
local W, K_lo, K_hi = common_W, sha2_K_lo, sha2_K_hi
for pos = offs, offs + size - 1, 128 do
for j = 1, 16*2 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos)
W[j] = OR(SHL(a, 24), SHL(b, 16), SHL(c, 8), d)
end
for jj = 17*2, 80*2, 2 do
local a_lo, a_hi = W[jj-30], W[jj-31]
local t_lo = XOR(OR(SHR(a_lo, 1), SHL(a_hi, 31)), OR(SHR(a_lo, 8), SHL(a_hi, 24)), OR(SHR(a_lo, 7), SHL(a_hi, 25)))
local t_hi = XOR(OR(SHR(a_hi, 1), SHL(a_lo, 31)), OR(SHR(a_hi, 8), SHL(a_lo, 24)), SHR(a_hi, 7))
local b_lo, b_hi = W[jj-4], W[jj-5]
local u_lo = XOR(OR(SHR(b_lo, 19), SHL(b_hi, 13)), OR(SHL(b_lo, 3), SHR(b_hi, 29)), OR(SHR(b_lo, 6), SHL(b_hi, 26)))
local u_hi = XOR(OR(SHR(b_hi, 19), SHL(b_lo, 13)), OR(SHL(b_hi, 3), SHR(b_lo, 29)), SHR(b_hi, 6))
W[jj], W[jj-1] = ADD64_4(t_lo, t_hi, u_lo, u_hi, W[jj-14], W[jj-15], W[jj-32], W[jj-33])
end
local a_lo, b_lo, c_lo, d_lo, e_lo, f_lo, g_lo, h_lo = H_lo[1], H_lo[2], H_lo[3], H_lo[4], H_lo[5], H_lo[6], H_lo[7], H_lo[8]
local a_hi, b_hi, c_hi, d_hi, e_hi, f_hi, g_hi, h_hi = H_hi[1], H_hi[2], H_hi[3], H_hi[4], H_hi[5], H_hi[6], H_hi[7], H_hi[8]
local zero = 0
for j = 1, 80 do
local t_lo = XOR(g_lo, AND(e_lo, XOR(f_lo, g_lo)))
local t_hi = XOR(g_hi, AND(e_hi, XOR(f_hi, g_hi)))
local u_lo = XOR(OR(SHR(e_lo, 14), SHL(e_hi, 18)), OR(SHR(e_lo, 18), SHL(e_hi, 14)), OR(SHL(e_lo, 23), SHR(e_hi, 9)))
local u_hi = XOR(OR(SHR(e_hi, 14), SHL(e_lo, 18)), OR(SHR(e_hi, 18), SHL(e_lo, 14)), OR(SHL(e_hi, 23), SHR(e_lo, 9)))
local sum_lo = u_lo % 2^32 + t_lo % 2^32 + h_lo % 2^32 + K_lo[j] + W[2*j] % 2^32
local z_lo, z_hi = NORM( sum_lo ), NORM( u_hi + t_hi + h_hi + K_hi[j] + W[2*j-1] + floor(sum_lo / 2^32) )
zero = zero + zero -- this thick is needed to avoid "PHI shuffling too complex" due to PHIs overlap
h_lo, h_hi, g_lo, g_hi, f_lo, f_hi = OR(zero, g_lo), OR(zero, g_hi), OR(zero, f_lo), OR(zero, f_hi), OR(zero, e_lo), OR(zero, e_hi)
local sum_lo = z_lo % 2^32 + d_lo % 2^32
e_lo, e_hi = NORM( sum_lo ), NORM( z_hi + d_hi + floor(sum_lo / 2^32) )
d_lo, d_hi, c_lo, c_hi, b_lo, b_hi = OR(zero, c_lo), OR(zero, c_hi), OR(zero, b_lo), OR(zero, b_hi), OR(zero, a_lo), OR(zero, a_hi)
u_lo = XOR(OR(SHR(b_lo, 28), SHL(b_hi, 4)), OR(SHL(b_lo, 30), SHR(b_hi, 2)), OR(SHL(b_lo, 25), SHR(b_hi, 7)))
u_hi = XOR(OR(SHR(b_hi, 28), SHL(b_lo, 4)), OR(SHL(b_hi, 30), SHR(b_lo, 2)), OR(SHL(b_hi, 25), SHR(b_lo, 7)))
t_lo = OR(AND(d_lo, c_lo), AND(b_lo, XOR(d_lo, c_lo)))
t_hi = OR(AND(d_hi, c_hi), AND(b_hi, XOR(d_hi, c_hi)))
local sum_lo = z_lo % 2^32 + t_lo % 2^32 + u_lo % 2^32
a_lo, a_hi = NORM( sum_lo ), NORM( z_hi + t_hi + u_hi + floor(sum_lo / 2^32) )
end
H_lo[1], H_hi[1] = ADD64_4(H_lo[1], H_hi[1], a_lo, a_hi, 0, 0, 0, 0)
H_lo[2], H_hi[2] = ADD64_4(H_lo[2], H_hi[2], b_lo, b_hi, 0, 0, 0, 0)
H_lo[3], H_hi[3] = ADD64_4(H_lo[3], H_hi[3], c_lo, c_hi, 0, 0, 0, 0)
H_lo[4], H_hi[4] = ADD64_4(H_lo[4], H_hi[4], d_lo, d_hi, 0, 0, 0, 0)
H_lo[5], H_hi[5] = ADD64_4(H_lo[5], H_hi[5], e_lo, e_hi, 0, 0, 0, 0)
H_lo[6], H_hi[6] = ADD64_4(H_lo[6], H_hi[6], f_lo, f_hi, 0, 0, 0, 0)
H_lo[7], H_hi[7] = ADD64_4(H_lo[7], H_hi[7], g_lo, g_hi, 0, 0, 0, 0)
H_lo[8], H_hi[8] = ADD64_4(H_lo[8], H_hi[8], h_lo, h_hi, 0, 0, 0, 0)
end
end
else -- all platforms except x86
-- SHA512 implementation for "LuaJIT non-x86 without FFI" branch
function sha512_feed_128(H_lo, H_hi, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 128
-- W1_hi, W1_lo, W2_hi, W2_lo, ... Wk_hi = W[2*k-1], Wk_lo = W[2*k]
local W, K_lo, K_hi = common_W, sha2_K_lo, sha2_K_hi
for pos = offs, offs + size - 1, 128 do
for j = 1, 16*2 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos)
W[j] = OR(SHL(a, 24), SHL(b, 16), SHL(c, 8), d)
end
for jj = 17*2, 80*2, 2 do
local a_lo, a_hi = W[jj-30], W[jj-31]
local t_lo = XOR(OR(SHR(a_lo, 1), SHL(a_hi, 31)), OR(SHR(a_lo, 8), SHL(a_hi, 24)), OR(SHR(a_lo, 7), SHL(a_hi, 25)))
local t_hi = XOR(OR(SHR(a_hi, 1), SHL(a_lo, 31)), OR(SHR(a_hi, 8), SHL(a_lo, 24)), SHR(a_hi, 7))
local b_lo, b_hi = W[jj-4], W[jj-5]
local u_lo = XOR(OR(SHR(b_lo, 19), SHL(b_hi, 13)), OR(SHL(b_lo, 3), SHR(b_hi, 29)), OR(SHR(b_lo, 6), SHL(b_hi, 26)))
local u_hi = XOR(OR(SHR(b_hi, 19), SHL(b_lo, 13)), OR(SHL(b_hi, 3), SHR(b_lo, 29)), SHR(b_hi, 6))
W[jj], W[jj-1] = ADD64_4(t_lo, t_hi, u_lo, u_hi, W[jj-14], W[jj-15], W[jj-32], W[jj-33])
end
local a_lo, b_lo, c_lo, d_lo, e_lo, f_lo, g_lo, h_lo = H_lo[1], H_lo[2], H_lo[3], H_lo[4], H_lo[5], H_lo[6], H_lo[7], H_lo[8]
local a_hi, b_hi, c_hi, d_hi, e_hi, f_hi, g_hi, h_hi = H_hi[1], H_hi[2], H_hi[3], H_hi[4], H_hi[5], H_hi[6], H_hi[7], H_hi[8]
for j = 1, 80 do
local t_lo = XOR(g_lo, AND(e_lo, XOR(f_lo, g_lo)))
local t_hi = XOR(g_hi, AND(e_hi, XOR(f_hi, g_hi)))
local u_lo = XOR(OR(SHR(e_lo, 14), SHL(e_hi, 18)), OR(SHR(e_lo, 18), SHL(e_hi, 14)), OR(SHL(e_lo, 23), SHR(e_hi, 9)))
local u_hi = XOR(OR(SHR(e_hi, 14), SHL(e_lo, 18)), OR(SHR(e_hi, 18), SHL(e_lo, 14)), OR(SHL(e_hi, 23), SHR(e_lo, 9)))
local sum_lo = u_lo % 2^32 + t_lo % 2^32 + h_lo % 2^32 + K_lo[j] + W[2*j] % 2^32
local z_lo, z_hi = NORM( sum_lo ), NORM( u_hi + t_hi + h_hi + K_hi[j] + W[2*j-1] + floor(sum_lo / 2^32) )
h_lo, h_hi, g_lo, g_hi, f_lo, f_hi = g_lo, g_hi, f_lo, f_hi, e_lo, e_hi
local sum_lo = z_lo % 2^32 + d_lo % 2^32
e_lo, e_hi = NORM( sum_lo ), NORM( z_hi + d_hi + floor(sum_lo / 2^32) )
d_lo, d_hi, c_lo, c_hi, b_lo, b_hi = c_lo, c_hi, b_lo, b_hi, a_lo, a_hi
u_lo = XOR(OR(SHR(b_lo, 28), SHL(b_hi, 4)), OR(SHL(b_lo, 30), SHR(b_hi, 2)), OR(SHL(b_lo, 25), SHR(b_hi, 7)))
u_hi = XOR(OR(SHR(b_hi, 28), SHL(b_lo, 4)), OR(SHL(b_hi, 30), SHR(b_lo, 2)), OR(SHL(b_hi, 25), SHR(b_lo, 7)))
t_lo = OR(AND(d_lo, c_lo), AND(b_lo, XOR(d_lo, c_lo)))
t_hi = OR(AND(d_hi, c_hi), AND(b_hi, XOR(d_hi, c_hi)))
local sum_lo = z_lo % 2^32 + u_lo % 2^32 + t_lo % 2^32
a_lo, a_hi = NORM( sum_lo ), NORM( z_hi + u_hi + t_hi + floor(sum_lo / 2^32) )
end
H_lo[1], H_hi[1] = ADD64_4(H_lo[1], H_hi[1], a_lo, a_hi, 0, 0, 0, 0)
H_lo[2], H_hi[2] = ADD64_4(H_lo[2], H_hi[2], b_lo, b_hi, 0, 0, 0, 0)
H_lo[3], H_hi[3] = ADD64_4(H_lo[3], H_hi[3], c_lo, c_hi, 0, 0, 0, 0)
H_lo[4], H_hi[4] = ADD64_4(H_lo[4], H_hi[4], d_lo, d_hi, 0, 0, 0, 0)
H_lo[5], H_hi[5] = ADD64_4(H_lo[5], H_hi[5], e_lo, e_hi, 0, 0, 0, 0)
H_lo[6], H_hi[6] = ADD64_4(H_lo[6], H_hi[6], f_lo, f_hi, 0, 0, 0, 0)
H_lo[7], H_hi[7] = ADD64_4(H_lo[7], H_hi[7], g_lo, g_hi, 0, 0, 0, 0)
H_lo[8], H_hi[8] = ADD64_4(H_lo[8], H_hi[8], h_lo, h_hi, 0, 0, 0, 0)
end
end
end
-- MD5 implementation for "LuaJIT without FFI" branch
function md5_feed_64(H, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 64
local W, K = common_W, md5_K
for pos = offs, offs + size - 1, 64 do
for j = 1, 16 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos)
W[j] = OR(SHL(d, 24), SHL(c, 16), SHL(b, 8), a)
end
local a, b, c, d = H[1], H[2], H[3], H[4]
for j = 1, 16, 4 do
a, d, c, b = d, c, b, NORM(ROL(XOR(d, AND(b, XOR(c, d))) + (K[j ] + W[j ] + a), 7) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(d, AND(b, XOR(c, d))) + (K[j+1] + W[j+1] + a), 12) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(d, AND(b, XOR(c, d))) + (K[j+2] + W[j+2] + a), 17) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(d, AND(b, XOR(c, d))) + (K[j+3] + W[j+3] + a), 22) + b)
end
for j = 17, 32, 4 do
local g = 5*j-4
a, d, c, b = d, c, b, NORM(ROL(XOR(c, AND(d, XOR(b, c))) + (K[j ] + W[AND(g , 15) + 1] + a), 5) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, AND(d, XOR(b, c))) + (K[j+1] + W[AND(g + 5, 15) + 1] + a), 9) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, AND(d, XOR(b, c))) + (K[j+2] + W[AND(g + 10, 15) + 1] + a), 14) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, AND(d, XOR(b, c))) + (K[j+3] + W[AND(g - 1, 15) + 1] + a), 20) + b)
end
for j = 33, 48, 4 do
local g = 3*j+2
a, d, c, b = d, c, b, NORM(ROL(XOR(b, c, d) + (K[j ] + W[AND(g , 15) + 1] + a), 4) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(b, c, d) + (K[j+1] + W[AND(g + 3, 15) + 1] + a), 11) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(b, c, d) + (K[j+2] + W[AND(g + 6, 15) + 1] + a), 16) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(b, c, d) + (K[j+3] + W[AND(g - 7, 15) + 1] + a), 23) + b)
end
for j = 49, 64, 4 do
local g = j*7
a, d, c, b = d, c, b, NORM(ROL(XOR(c, OR(b, NOT(d))) + (K[j ] + W[AND(g - 7, 15) + 1] + a), 6) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, OR(b, NOT(d))) + (K[j+1] + W[AND(g , 15) + 1] + a), 10) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, OR(b, NOT(d))) + (K[j+2] + W[AND(g + 7, 15) + 1] + a), 15) + b)
a, d, c, b = d, c, b, NORM(ROL(XOR(c, OR(b, NOT(d))) + (K[j+3] + W[AND(g - 2, 15) + 1] + a), 21) + b)
end
H[1], H[2], H[3], H[4] = NORM(a + H[1]), NORM(b + H[2]), NORM(c + H[3]), NORM(d + H[4])
end
end
-- SHA-1 implementation for "LuaJIT without FFI" branch
function sha1_feed_64(H, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 64
local W = common_W
for pos = offs, offs + size - 1, 64 do
for j = 1, 16 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos)
W[j] = OR(SHL(a, 24), SHL(b, 16), SHL(c, 8), d)
end
for j = 17, 80 do
W[j] = ROL(XOR(W[j-3], W[j-8], W[j-14], W[j-16]), 1)
end
local a, b, c, d, e = H[1], H[2], H[3], H[4], H[5]
for j = 1, 20, 5 do
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j] + 0x5A827999 + e)) -- constant = floor(2^30 * sqrt(2))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j+1] + 0x5A827999 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j+2] + 0x5A827999 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j+3] + 0x5A827999 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(d, AND(b, XOR(d, c))) + (W[j+4] + 0x5A827999 + e))
end
for j = 21, 40, 5 do
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j] + 0x6ED9EBA1 + e)) -- 2^30 * sqrt(3)
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+1] + 0x6ED9EBA1 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+2] + 0x6ED9EBA1 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+3] + 0x6ED9EBA1 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+4] + 0x6ED9EBA1 + e))
end
for j = 41, 60, 5 do
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j] + 0x8F1BBCDC + e)) -- 2^30 * sqrt(5)
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j+1] + 0x8F1BBCDC + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j+2] + 0x8F1BBCDC + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j+3] + 0x8F1BBCDC + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(AND(d, XOR(b, c)), AND(b, c)) + (W[j+4] + 0x8F1BBCDC + e))
end
for j = 61, 80, 5 do
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j] + 0xCA62C1D6 + e)) -- 2^30 * sqrt(10)
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+1] + 0xCA62C1D6 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+2] + 0xCA62C1D6 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+3] + 0xCA62C1D6 + e))
e, d, c, b, a = d, c, ROR(b, 2), a, NORM(ROL(a, 5) + XOR(b, c, d) + (W[j+4] + 0xCA62C1D6 + e))
end
H[1], H[2], H[3], H[4], H[5] = NORM(a + H[1]), NORM(b + H[2]), NORM(c + H[3]), NORM(d + H[4]), NORM(e + H[5])
end
end
end
if branch == "INT64" then
-- implementation for Lua 5.3/5.4
hi_factor = 4294967296
hi_factor_keccak = 4294967296
lanes_index_base = 1
HEX64, XOR64A5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed = load[[local a,b,c,d,e,f=...local g,h=string.format,string.unpack;local function i(j)return g("%016x",j)end;local function k(j)return j~0xa5a5a5a5a5a5a5a5 end;local function l(j,m)return j~m end;local n={}local function o(p,q,r,s)local t,u=n,d;local v,w,x,y,z,A,B,C=p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4",q,D)for E=17,64 do local F=t[E-15]F=F<<32|F;local G=t[E-2]G=G<<32|G;t[E]=F>>7~(F>>18)~(F>>35)+G>>17~(G>>19)~(G>>42)+t[E-7]+t[E-16]&1<<32-1 end;local F,G,H,I,J,K,L,M=v,w,x,y,z,A,B,C;for E=1,64 do J=J<<32|(J&1<<32-1)local N=J>>6~(J>>11)~(J>>25)+L~(J&(K~L))+M+u[E]+t[E]M=L;L=K;K=J;J=N+I;I=H;H=G;G=F;F=F<<32|(F&1<<32-1)F=N+F~H&I~(F&H)+F>>2~(F>>13)~(F>>22)end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z;A=K+A;B=L+B;C=M+C end;p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]=v,w,x,y,z,A,B,C end;local function O(p,P,q,r,s)local t,u=n,c;local v,w,x,y,z,A,B,C=p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]for D=r+1,r+s,128 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">i8i8i8i8i8i8i8i8i8i8i8i8i8i8i8i8",q,D)for E=17,80 do local F=t[E-15]local G=t[E-2]t[E]=F>>1~(F>>7)~(F>>8)~(F<<56)~(F<<63)+G>>6~(G>>19)~(G>>61)~(G<<3)~(G<<45)+t[E-7]+t[E-16]end;local F,G,H,I,J,K,L,M=v,w,x,y,z,A,B,C;for E=1,80 do local N=J>>14~(J>>18)~(J>>41)~(J<<23)~(J<<46)~(J<<50)+L~(J&(K~L))+M+u[E]+t[E]M=L;L=K;K=J;J=N+I;I=H;H=G;G=F;F=N+F~H&I~(F&H)+F>>28~(F>>34)~(F>>39)~(F<<25)~(F<<30)~(F<<36)end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z;A=K+A;B=L+B;C=M+C end;p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]=v,w,x,y,z,A,B,C end;local function Q(p,q,r,s)local t,u,a=n,b,a;local v,w,x,y=p[1],p[2],p[3],p[4]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h("<I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4",q,D)local F,G,H,I=v,w,x,y;local R=32-7;for E=1,16 do local S=I~(G&(H~I))+F+u[E]+t[E]F=I;I=H;H=G;G=S<<32|(S&1<<32-1)>>R+G;R=a[R]end;R=32-5;for E=17,32 do local S=H~(I&(G~H))+F+u[E]+t[5*E-4&15+1]F=I;I=H;H=G;G=S<<32|(S&1<<32-1)>>R+G;R=a[R]end;R=32-4;for E=33,48 do local S=G~H~I+F+u[E]+t[3*E+2&15+1]F=I;I=H;H=G;G=S<<32|(S&1<<32-1)>>R+G;R=a[R]end;R=32-6;for E=49,64 do local S=H~(G|~I)+F+u[E]+t[E*7-7&15+1]F=I;I=H;H=G;G=S<<32|(S&1<<32-1)>>R+G;R=a[R]end;v=F+v;w=G+w;x=H+x;y=I+y end;p[1],p[2],p[3],p[4]=v,w,x,y end;local function T(p,q,r,s)local t=n;local v,w,x,y,z=p[1],p[2],p[3],p[4],p[5]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4I4",q,D)for E=17,80 do local F=t[E-3]~t[E-8]~t[E-14]~t[E-16]t[E]=F<<32|F<<1>>32 end;local F,G,H,I,J=v,w,x,y,z;for E=1,20 do local N=F<<32|(F&1<<32-1)>>27+I~(G&(H~I))+0x5A827999+t[E]+J;J=I;I=H;H=G<<32|(G&1<<32-1)>>2;G=F;F=N end;for E=21,40 do local N=F<<32|(F&1<<32-1)>>27+G~H~I+0x6ED9EBA1+t[E]+J;J=I;I=H;H=G<<32|(G&1<<32-1)>>2;G=F;F=N end;for E=41,60 do local N=F<<32|(F&1<<32-1)>>27+G~H&I~(G&H)+0x8F1BBCDC+t[E]+J;J=I;I=H;H=G<<32|(G&1<<32-1)>>2;G=F;F=N end;for E=61,80 do local N=F<<32|(F&1<<32-1)>>27+G~H~I+0xCA62C1D6+t[E]+J;J=I;I=H;H=G<<32|(G&1<<32-1)>>2;G=F;F=N end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z end;p[1],p[2],p[3],p[4],p[5]=v,w,x,y,z end;local U=e("i8")local function V(W,P,q,r,s,X)local Y=f;local Z=X/8;local _=U[Z]for D=r+1,r+s,X do local a0={h(_,q,D)}for E=1,Z do W[E]=W[E]~a0[E]end;local a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an,ao,ap=W[1],W[2],W[3],W[4],W[5],W[6],W[7],W[8],W[9],W[10],W[11],W[12],W[13],W[14],W[15],W[16],W[17],W[18],W[19],W[20],W[21],W[22],W[23],W[24],W[25]for aq=1,24 do local ar=a1~a6~ab~ag~al;local as=a2~a7~ac~ah~am;local at=a3~a8~ad~ai~an;local au=a4~a9~ae~aj~ao;local av=a5~aa~af~ak~ap;local aw=ar~(at<<1)~(at>>63)local ax=aw~a2;local ay=aw~a7;local az=aw~ac;local aA=aw~ah;local aB=aw~am;a2=ay<<44~(ay>>20)a7=aA<<45~(aA>>19)ac=ax<<1~(ax>>63)ah=az<<10~(az>>54)am=aB<<2~(aB>>62)aw=as~(au<<1)~(au>>63)ax=aw~a3;ay=aw~a8;az=aw~ad;aA=aw~ai;aB=aw~an;a3=az<<43~(az>>21)a8=aB<<61~(aB>>3)ad=ay<<6~(ay>>58)ai=aA<<15~(aA>>49)an=ax<<62~(ax>>2)aw=at~(av<<1)~(av>>63)ax=aw~a4;ay=aw~a9;az=aw~ae;aA=aw~aj;aB=aw~ao;a4=aA<<21~(aA>>43)a9=ax<<28~(ax>>36)ae=az<<25~(az>>39)aj=aB<<56~(aB>>8)ao=ay<<55~(ay>>9)aw=au~(ar<<1)~(ar>>63)ax=aw~a5;ay=aw~aa;az=aw~af;aA=aw~ak;aB=aw~ap;a5=aB<<14~(aB>>50)aa=ay<<20~(ay>>44)af=aA<<8~(aA>>56)ak=ax<<27~(ax>>37)ap=az<<39~(az>>25)aw=av~(as<<1)~(as>>63)ay=aw~a6;az=aw~ab;aA=aw~ag;aB=aw~al;a6=az<<3~(az>>61)ab=aB<<18~(aB>>46)ag=ay<<36~(ay>>28)al=aA<<41~(aA>>23)a1=aw~a1;a1,a2,a3,a4,a5=a1~(~a2&a3),a2~(~a3&a4),a3~(~a4&a5),a4~(~a5&a1),a5~(~a1&a2)a6,a7,a8,a9,aa=a9~(~aa&a6),aa~(~a6&a7),a6~(~a7&a8),a7~(~a8&a9),a8~(~a9&aa)ab,ac,ad,ae,af=ac~(~ad&ae),ad~(~ae&af),ae~(~af&ab),af~(~ab&ac),ab~(~ac&ad)ag,ah,ai,aj,ak=ak~(~ag&ah),ag~(~ah&ai),ah~(~ai&aj),ai~(~aj&ak),aj~(~ak&ag)al,am,an,ao,ap=an~(~ao&ap),ao~(~ap&al),ap~(~al&am),al~(~am&an),am~(~an&ao)a1=a1~Y[aq]end;W[1]=a1;W[2]=a2;W[3]=a3;W[4]=a4;W[5]=a5;W[6]=a6;W[7]=a7;W[8]=a8;W[9]=a9;W[10]=aa;W[11]=ab;W[12]=ac;W[13]=ad;W[14]=ae;W[15]=af;W[16]=ag;W[17]=ah;W[18]=ai;W[19]=aj;W[20]=ak;W[21]=al;W[22]=am;W[23]=an;W[24]=ao;W[25]=ap end end;return i,k,l,o,O,Q,T,V]](md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo)
end
if branch == "INT32" then
-- implementation for Lua 5.3/5.4 having non-standard numbers config "int32"+"double" (built with LUA_INT_TYPE=LUA_INT_INT)
K_lo_modulo = 2^32
function HEX(x) -- returns string of 8 lowercase hexadecimal digits
return string_format("%08x", x)
end
XOR32A5, XOR_BYTE, sha256_feed_64, sha512_feed_128, md5_feed_64, sha1_feed_64, keccak_feed = load[[local a,b,c,d,e,f,g=...local h,i=string.unpack,math.floor;local function j(k)return k~0xA5A5A5A5 end;local function l(k,m)return k~m end;local n={}local function o(p,q,r,s)local t,u=n,d;local v,w,x,y,z,A,B,C=p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4",q,D)for E=17,64 do local F,G=t[E-15],t[E-2]t[E]=F>>7~(F<<25)~(F<<14)~(F>>18)~(F>>3)+G<<15~(G>>17)~(G<<13)~(G>>19)~(G>>10)+t[E-7]+t[E-16]end;local F,G,H,I,J,K,L,M=v,w,x,y,z,A,B,C;for E=1,64 do local N=J>>6~(J<<26)~(J>>11)~(J<<21)~(J>>25)~(J<<7)+L~(J&(K~L))+M+u[E]+t[E]M=L;L=K;K=J;J=N+I;I=H;H=G;G=F;F=N+F~H&I~(F&H)+F>>2~(F<<30)~(F>>13)~(F<<19)~(F<<10)~(F>>22)end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z;A=K+A;B=L+B;C=M+C end;p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8]=v,w,x,y,z,A,B,C end;local function O(P,Q,q,r,s)local i,t,R,S=i,n,c,d;local T,U,V,W,X,Y,Z,_=P[1],P[2],P[3],P[4],P[5],P[6],P[7],P[8]local a0,a1,a2,a3,a4,a5,a6,a7=Q[1],Q[2],Q[3],Q[4],Q[5],Q[6],Q[7],Q[8]for D=r+1,r+s,128 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16],t[17],t[18],t[19],t[20],t[21],t[22],t[23],t[24],t[25],t[26],t[27],t[28],t[29],t[30],t[31],t[32]=h(">i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4",q,D)for a8=17*2,80*2,2 do local a9,aa,ab,ac=t[a8-30],t[a8-31],t[a8-4],t[a8-5]local ad=a9>>1~(aa<<31)~(a9>>8)~(aa<<24)~(a9>>7)~(aa<<25)%2^32+ab>>19~(ac<<13)~(ab<<3)~(ac>>29)~(ab>>6)~(ac<<26)%2^32+t[a8-14]%2^32+t[a8-32]%2^32;t[a8-1]=aa>>1~(a9<<31)~(aa>>8)~(a9<<24)~(aa>>7)+ac>>19~(ab<<13)~(ac<<3)~(ab>>29)~(ac>>6)+t[a8-15]+t[a8-33]+i(ad/2^32)t[a8]=0|(ad+2^31)%2^32-2^31 end;local a9,ab,ae,af,ag,ah,ai,aj=T,U,V,W,X,Y,Z,_;local aa,ac,ak,al,am,an,ao,ap=a0,a1,a2,a3,a4,a5,a6,a7;for E=1,80 do local a8=2*E;local aq=ag>>14~(am<<18)~(ag>>18)~(am<<14)~(ag<<23)~(am>>9)%2^32+ai~(ag&(ah~ai))%2^32+aj%2^32+R[E]+t[a8]%2^32;local ar=am>>14~(ag<<18)~(am>>18)~(ag<<14)~(am<<23)~(ag>>9)+ao~(am&(an~ao))+ap+S[E]+t[a8-1]+i(aq/2^32)aq=aq%2^32;aj=ai;ap=ao;ai=ah;ao=an;ah=ag;an=am;ag=aq+af%2^32;am=ar+al+i(ag/2^32)ag=0|(ag+2^31)%2^32-2^31;af=ae;al=ak;ae=ab;ak=ac;ab=a9;ac=aa;aq=aq+af&ae~(ab&(af~ae))%2^32+ab>>28~(ac<<4)~(ab<<30)~(ac>>2)~(ab<<25)~(ac>>7)%2^32;aa=ar+al&ak~(ac&(al~ak))+ac>>28~(ab<<4)~(ac<<30)~(ab>>2)~(ac<<25)~(ab>>7)+i(aq/2^32)a9=0|(aq+2^31)%2^32-2^31 end;a9=T%2^32+a9%2^32;a0=a0+aa+i(a9/2^32)T=0|(a9+2^31)%2^32-2^31;a9=U%2^32+ab%2^32;a1=a1+ac+i(a9/2^32)U=0|(a9+2^31)%2^32-2^31;a9=V%2^32+ae%2^32;a2=a2+ak+i(a9/2^32)V=0|(a9+2^31)%2^32-2^31;a9=W%2^32+af%2^32;a3=a3+al+i(a9/2^32)W=0|(a9+2^31)%2^32-2^31;a9=X%2^32+ag%2^32;a4=a4+am+i(a9/2^32)X=0|(a9+2^31)%2^32-2^31;a9=Y%2^32+ah%2^32;a5=a5+an+i(a9/2^32)Y=0|(a9+2^31)%2^32-2^31;a9=Z%2^32+ai%2^32;a6=a6+ao+i(a9/2^32)Z=0|(a9+2^31)%2^32-2^31;a9=_%2^32+aj%2^32;a7=a7+ap+i(a9/2^32)_=0|(a9+2^31)%2^32-2^31 end;P[1],P[2],P[3],P[4],P[5],P[6],P[7],P[8]=T,U,V,W,X,Y,Z,_;Q[1],Q[2],Q[3],Q[4],Q[5],Q[6],Q[7],Q[8]=a0,a1,a2,a3,a4,a5,a6,a7 end;local function as(p,q,r,s)local t,u,a=n,b,a;local v,w,x,y=p[1],p[2],p[3],p[4]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h("<i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4",q,D)local F,G,H,I=v,w,x,y;local at=32-7;for E=1,16 do local au=I~(G&(H~I))+F+u[E]+t[E]F=I;I=H;H=G;G=au<<32-at|(au>>at)+G;at=a[at]end;at=32-5;for E=17,32 do local au=H~(I&(G~H))+F+u[E]+t[5*E-4&15+1]F=I;I=H;H=G;G=au<<32-at|(au>>at)+G;at=a[at]end;at=32-4;for E=33,48 do local au=G~H~I+F+u[E]+t[3*E+2&15+1]F=I;I=H;H=G;G=au<<32-at|(au>>at)+G;at=a[at]end;at=32-6;for E=49,64 do local au=H~(G|~I)+F+u[E]+t[E*7-7&15+1]F=I;I=H;H=G;G=au<<32-at|(au>>at)+G;at=a[at]end;v=F+v;w=G+w;x=H+x;y=I+y end;p[1],p[2],p[3],p[4]=v,w,x,y end;local function av(p,q,r,s)local t=n;local v,w,x,y,z=p[1],p[2],p[3],p[4],p[5]for D=r+1,r+s,64 do t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16]=h(">i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4",q,D)for E=17,80 do local F=t[E-3]~t[E-8]~t[E-14]~t[E-16]t[E]=F<<1~(F>>31)end;local F,G,H,I,J=v,w,x,y,z;for E=1,20 do local N=F<<5~(F>>27)+I~(G&(H~I))+0x5A827999+t[E]+J;J=I;I=H;H=G<<30~(G>>2)G=F;F=N end;for E=21,40 do local N=F<<5~(F>>27)+G~H~I+0x6ED9EBA1+t[E]+J;J=I;I=H;H=G<<30~(G>>2)G=F;F=N end;for E=41,60 do local N=F<<5~(F>>27)+G~H&I~(G&H)+0x8F1BBCDC+t[E]+J;J=I;I=H;H=G<<30~(G>>2)G=F;F=N end;for E=61,80 do local N=F<<5~(F>>27)+G~H~I+0xCA62C1D6+t[E]+J;J=I;I=H;H=G<<30~(G>>2)G=F;F=N end;v=F+v;w=G+w;x=H+x;y=I+y;z=J+z end;p[1],p[2],p[3],p[4],p[5]=v,w,x,y,z end;local aw=e("i4i4")local function ax(ay,az,q,r,s,aA)local aB,aC=f,g;local aD=aA/8;local aE=aw[aD]for D=r+1,r+s,aA do local aF={h(aE,q,D)}for E=1,aD do ay[E]=ay[E]~aF[2*E-1]az[E]=az[E]~aF[2*E]end;local aG,aH,aI,aJ,aK,aL,aM,aN,aO,aP,aQ,aR,aS,aT,aU,aV,aW,aX,aY,aZ,a_,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf,bg,bh,bi,bj,bk,bl,bm,bn,bo,bp,bq,br,bs=ay[1],az[1],ay[2],az[2],ay[3],az[3],ay[4],az[4],ay[5],az[5],ay[6],az[6],ay[7],az[7],ay[8],az[8],ay[9],az[9],ay[10],az[10],ay[11],az[11],ay[12],az[12],ay[13],az[13],ay[14],az[14],ay[15],az[15],ay[16],az[16],ay[17],az[17],ay[18],az[18],ay[19],az[19],ay[20],az[20],ay[21],az[21],ay[22],az[22],ay[23],az[23],ay[24],az[24],ay[25],az[25]for bt=1,24 do local bu=aG~aQ~a_~b9~bj;local bv=aH~aR~b0~ba~bk;local bw=aI~aS~b1~bb~bl;local bx=aJ~aT~b2~bc~bm;local by=aK~aU~b3~bd~bn;local bz=aL~aV~b4~be~bo;local bA=aM~aW~b5~bf~bp;local bB=aN~aX~b6~bg~bq;local bC=aO~aY~b7~bh~br;local bD=aP~aZ~b8~bi~bs;local bE=bu~(by<<1)~(bz>>31)local bF=bv~(bz<<1)~(by>>31)local bG=bE~aI;local bH=bF~aJ;local bI=bE~aS;local bJ=bF~aT;local bK=bE~b1;local bL=bF~b2;local bM=bE~bb;local bN=bF~bc;local bO=bE~bl;local bP=bF~bm;aI=bI>>20~(bJ<<12)aJ=bJ>>20~(bI<<12)aS=bM>>19~(bN<<13)aT=bN>>19~(bM<<13)b1=bG<<1~(bH>>31)b2=bH<<1~(bG>>31)bb=bK<<10~(bL>>22)bc=bL<<10~(bK>>22)bl=bO<<2~(bP>>30)bm=bP<<2~(bO>>30)bE=bw~(bA<<1)~(bB>>31)bF=bx~(bB<<1)~(bA>>31)bG=bE~aK;bH=bF~aL;bI=bE~aU;bJ=bF~aV;bK=bE~b3;bL=bF~b4;bM=bE~bd;bN=bF~be;bO=bE~bn;bP=bF~bo;aK=bK>>21~(bL<<11)aL=bL>>21~(bK<<11)aU=bO>>3~(bP<<29)aV=bP>>3~(bO<<29)b3=bI<<6~(bJ>>26)b4=bJ<<6~(bI>>26)bd=bM<<15~(bN>>17)be=bN<<15~(bM>>17)bn=bG>>2~(bH<<30)bo=bH>>2~(bG<<30)bE=by~(bC<<1)~(bD>>31)bF=bz~(bD<<1)~(bC>>31)bG=bE~aM;bH=bF~aN;bI=bE~aW;bJ=bF~aX;bK=bE~b5;bL=bF~b6;bM=bE~bf;bN=bF~bg;bO=bE~bp;bP=bF~bq;aM=bM<<21~(bN>>11)aN=bN<<21~(bM>>11)aW=bG<<28~(bH>>4)aX=bH<<28~(bG>>4)b5=bK<<25~(bL>>7)b6=bL<<25~(bK>>7)bf=bO>>8~(bP<<24)bg=bP>>8~(bO<<24)bp=bI>>9~(bJ<<23)bq=bJ>>9~(bI<<23)bE=bA~(bu<<1)~(bv>>31)bF=bB~(bv<<1)~(bu>>31)bG=bE~aO;bH=bF~aP;bI=bE~aY;bJ=bF~aZ;bK=bE~b7;bL=bF~b8;bM=bE~bh;bN=bF~bi;bO=bE~br;bP=bF~bs;aO=bO<<14~(bP>>18)aP=bP<<14~(bO>>18)aY=bI<<20~(bJ>>12)aZ=bJ<<20~(bI>>12)b7=bM<<8~(bN>>24)b8=bN<<8~(bM>>24)bh=bG<<27~(bH>>5)bi=bH<<27~(bG>>5)br=bK>>25~(bL<<7)bs=bL>>25~(bK<<7)bE=bC~(bw<<1)~(bx>>31)bF=bD~(bx<<1)~(bw>>31)bI=bE~aQ;bJ=bF~aR;bK=bE~a_;bL=bF~b0;bM=bE~b9;bN=bF~ba;bO=bE~bj;bP=bF~bk;aQ=bK<<3~(bL>>29)aR=bL<<3~(bK>>29)a_=bO<<18~(bP>>14)b0=bP<<18~(bO>>14)b9=bI>>28~(bJ<<4)ba=bJ>>28~(bI<<4)bj=bM>>23~(bN<<9)bk=bN>>23~(bM<<9)aG=bE~aG;aH=bF~aH;aG,aI,aK,aM,aO=aG~(~aI&aK),aI~(~aK&aM),aK~(~aM&aO),aM~(~aO&aG),aO~(~aG&aI)aH,aJ,aL,aN,aP=aH~(~aJ&aL),aJ~(~aL&aN),aL~(~aN&aP),aN~(~aP&aH),aP~(~aH&aJ)aQ,aS,aU,aW,aY=aW~(~aY&aQ),aY~(~aQ&aS),aQ~(~aS&aU),aS~(~aU&aW),aU~(~aW&aY)aR,aT,aV,aX,aZ=aX~(~aZ&aR),aZ~(~aR&aT),aR~(~aT&aV),aT~(~aV&aX),aV~(~aX&aZ)a_,b1,b3,b5,b7=b1~(~b3&b5),b3~(~b5&b7),b5~(~b7&a_),b7~(~a_&b1),a_~(~b1&b3)b0,b2,b4,b6,b8=b2~(~b4&b6),b4~(~b6&b8),b6~(~b8&b0),b8~(~b0&b2),b0~(~b2&b4)b9,bb,bd,bf,bh=bh~(~b9&bb),b9~(~bb&bd),bb~(~bd&bf),bd~(~bf&bh),bf~(~bh&b9)ba,bc,be,bg,bi=bi~(~ba&bc),ba~(~bc&be),bc~(~be&bg),be~(~bg&bi),bg~(~bi&ba)bj,bl,bn,bp,br=bn~(~bp&br),bp~(~br&bj),br~(~bj&bl),bj~(~bl&bn),bl~(~bn&bp)bk,bm,bo,bq,bs=bo~(~bq&bs),bq~(~bs&bk),bs~(~bk&bm),bk~(~bm&bo),bm~(~bo&bq)aG=aG~aB[bt]aH=aH~aC[bt]end;ay[1]=aG;az[1]=aH;ay[2]=aI;az[2]=aJ;ay[3]=aK;az[3]=aL;ay[4]=aM;az[4]=aN;ay[5]=aO;az[5]=aP;ay[6]=aQ;az[6]=aR;ay[7]=aS;az[7]=aT;ay[8]=aU;az[8]=aV;ay[9]=aW;az[9]=aX;ay[10]=aY;az[10]=aZ;ay[11]=a_;az[11]=b0;ay[12]=b1;az[12]=b2;ay[13]=b3;az[13]=b4;ay[14]=b5;az[14]=b6;ay[15]=b7;az[15]=b8;ay[16]=b9;az[16]=ba;ay[17]=bb;az[17]=bc;ay[18]=bd;az[18]=be;ay[19]=bf;az[19]=bg;ay[20]=bh;az[20]=bi;ay[21]=bj;az[21]=bk;ay[22]=bl;az[22]=bm;ay[23]=bn;az[23]=bo;ay[24]=bp;az[24]=bq;ay[25]=br;az[25]=bs end end;return j,l,o,O,as,av,ax]](md5_next_shift, md5_K, sha2_K_lo, sha2_K_hi, build_keccak_format, sha3_RC_lo, sha3_RC_hi)
end
if branch == "LIB32" or branch == "EMUL" then
-- implementation for Lua 5.1/5.2 (with or without bitwise library available)
function sha256_feed_64(H, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 64
local W, K = common_W, sha2_K_hi
local h1, h2, h3, h4, h5, h6, h7, h8 = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
for pos = offs, offs + size - 1, 64 do
for j = 1, 16 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos)
W[j] = ((a * 256 + b) * 256 + c) * 256 + d
end
for j = 17, 64 do
local a, b = W[j-15], W[j-2]
W[j] = XOR(ROR(a, 7), ROL(a, 14), SHR(a, 3)) + XOR(ROL(b, 15), ROL(b, 13), SHR(b, 10)) + W[j-7] + W[j-16]
end
local a, b, c, d, e, f, g, h = h1, h2, h3, h4, h5, h6, h7, h8
for j = 1, 64 do
local z = XOR(ROR(e, 6), ROR(e, 11), ROL(e, 7)) + AND(e, f) + AND(-1-e, g) + h + K[j] + W[j]
h = g
g = f
f = e
e = z + d
d = c
c = b
b = a
a = z + AND(d, c) + AND(a, XOR(d, c)) + XOR(ROR(a, 2), ROR(a, 13), ROL(a, 10))
end
h1, h2, h3, h4 = (a + h1) % 4294967296, (b + h2) % 4294967296, (c + h3) % 4294967296, (d + h4) % 4294967296
h5, h6, h7, h8 = (e + h5) % 4294967296, (f + h6) % 4294967296, (g + h7) % 4294967296, (h + h8) % 4294967296
end
H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = h1, h2, h3, h4, h5, h6, h7, h8
end
function sha512_feed_128(H_lo, H_hi, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 128
-- W1_hi, W1_lo, W2_hi, W2_lo, ... Wk_hi = W[2*k-1], Wk_lo = W[2*k]
local W, K_lo, K_hi = common_W, sha2_K_lo, sha2_K_hi
local h1_lo, h2_lo, h3_lo, h4_lo, h5_lo, h6_lo, h7_lo, h8_lo = H_lo[1], H_lo[2], H_lo[3], H_lo[4], H_lo[5], H_lo[6], H_lo[7], H_lo[8]
local h1_hi, h2_hi, h3_hi, h4_hi, h5_hi, h6_hi, h7_hi, h8_hi = H_hi[1], H_hi[2], H_hi[3], H_hi[4], H_hi[5], H_hi[6], H_hi[7], H_hi[8]
for pos = offs, offs + size - 1, 128 do
for j = 1, 16*2 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos)
W[j] = ((a * 256 + b) * 256 + c) * 256 + d
end
for jj = 17*2, 80*2, 2 do
local a_lo, a_hi, b_lo, b_hi = W[jj-30], W[jj-31], W[jj-4], W[jj-5]
local tmp1 = XOR(SHR(a_lo, 1) + SHL(a_hi, 31), SHR(a_lo, 8) + SHL(a_hi, 24), SHR(a_lo, 7) + SHL(a_hi, 25)) % 4294967296 + XOR(SHR(b_lo, 19) + SHL(b_hi, 13), SHL(b_lo, 3) + SHR(b_hi, 29), SHR(b_lo, 6) + SHL(b_hi, 26)) % 4294967296 + W[jj-14] + W[jj-32]
local tmp2 = tmp1 % 4294967296
W[jj-1] = XOR(SHR(a_hi, 1) + SHL(a_lo, 31), SHR(a_hi, 8) + SHL(a_lo, 24), SHR(a_hi, 7)) + XOR(SHR(b_hi, 19) + SHL(b_lo, 13), SHL(b_hi, 3) + SHR(b_lo, 29), SHR(b_hi, 6)) + W[jj-15] + W[jj-33] + (tmp1 - tmp2) / 4294967296
W[jj] = tmp2
end
local a_lo, b_lo, c_lo, d_lo, e_lo, f_lo, g_lo, h_lo = h1_lo, h2_lo, h3_lo, h4_lo, h5_lo, h6_lo, h7_lo, h8_lo
local a_hi, b_hi, c_hi, d_hi, e_hi, f_hi, g_hi, h_hi = h1_hi, h2_hi, h3_hi, h4_hi, h5_hi, h6_hi, h7_hi, h8_hi
for j = 1, 80 do
local jj = 2*j
local tmp1 = XOR(SHR(e_lo, 14) + SHL(e_hi, 18), SHR(e_lo, 18) + SHL(e_hi, 14), SHL(e_lo, 23) + SHR(e_hi, 9)) % 4294967296 + (AND(e_lo, f_lo) + AND(-1-e_lo, g_lo)) % 4294967296 + h_lo + K_lo[j] + W[jj]
local z_lo = tmp1 % 4294967296
local z_hi = XOR(SHR(e_hi, 14) + SHL(e_lo, 18), SHR(e_hi, 18) + SHL(e_lo, 14), SHL(e_hi, 23) + SHR(e_lo, 9)) + AND(e_hi, f_hi) + AND(-1-e_hi, g_hi) + h_hi + K_hi[j] + W[jj-1] + (tmp1 - z_lo) / 4294967296
h_lo = g_lo
h_hi = g_hi
g_lo = f_lo
g_hi = f_hi
f_lo = e_lo
f_hi = e_hi
tmp1 = z_lo + d_lo
e_lo = tmp1 % 4294967296
e_hi = z_hi + d_hi + (tmp1 - e_lo) / 4294967296
d_lo = c_lo
d_hi = c_hi
c_lo = b_lo
c_hi = b_hi
b_lo = a_lo
b_hi = a_hi
tmp1 = z_lo + (AND(d_lo, c_lo) + AND(b_lo, XOR(d_lo, c_lo))) % 4294967296 + XOR(SHR(b_lo, 28) + SHL(b_hi, 4), SHL(b_lo, 30) + SHR(b_hi, 2), SHL(b_lo, 25) + SHR(b_hi, 7)) % 4294967296
a_lo = tmp1 % 4294967296
a_hi = z_hi + (AND(d_hi, c_hi) + AND(b_hi, XOR(d_hi, c_hi))) + XOR(SHR(b_hi, 28) + SHL(b_lo, 4), SHL(b_hi, 30) + SHR(b_lo, 2), SHL(b_hi, 25) + SHR(b_lo, 7)) + (tmp1 - a_lo) / 4294967296
end
a_lo = h1_lo + a_lo
h1_lo = a_lo % 4294967296
h1_hi = (h1_hi + a_hi + (a_lo - h1_lo) / 4294967296) % 4294967296
a_lo = h2_lo + b_lo
h2_lo = a_lo % 4294967296
h2_hi = (h2_hi + b_hi + (a_lo - h2_lo) / 4294967296) % 4294967296
a_lo = h3_lo + c_lo
h3_lo = a_lo % 4294967296
h3_hi = (h3_hi + c_hi + (a_lo - h3_lo) / 4294967296) % 4294967296
a_lo = h4_lo + d_lo
h4_lo = a_lo % 4294967296
h4_hi = (h4_hi + d_hi + (a_lo - h4_lo) / 4294967296) % 4294967296
a_lo = h5_lo + e_lo
h5_lo = a_lo % 4294967296
h5_hi = (h5_hi + e_hi + (a_lo - h5_lo) / 4294967296) % 4294967296
a_lo = h6_lo + f_lo
h6_lo = a_lo % 4294967296
h6_hi = (h6_hi + f_hi + (a_lo - h6_lo) / 4294967296) % 4294967296
a_lo = h7_lo + g_lo
h7_lo = a_lo % 4294967296
h7_hi = (h7_hi + g_hi + (a_lo - h7_lo) / 4294967296) % 4294967296
a_lo = h8_lo + h_lo
h8_lo = a_lo % 4294967296
h8_hi = (h8_hi + h_hi + (a_lo - h8_lo) / 4294967296) % 4294967296
end
H_lo[1], H_lo[2], H_lo[3], H_lo[4], H_lo[5], H_lo[6], H_lo[7], H_lo[8] = h1_lo, h2_lo, h3_lo, h4_lo, h5_lo, h6_lo, h7_lo, h8_lo
H_hi[1], H_hi[2], H_hi[3], H_hi[4], H_hi[5], H_hi[6], H_hi[7], H_hi[8] = h1_hi, h2_hi, h3_hi, h4_hi, h5_hi, h6_hi, h7_hi, h8_hi
end
function md5_feed_64(H, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 64
local W, K, md5_next_shift = common_W, md5_K, md5_next_shift
local h1, h2, h3, h4 = H[1], H[2], H[3], H[4]
for pos = offs, offs + size - 1, 64 do
for j = 1, 16 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos)
W[j] = ((d * 256 + c) * 256 + b) * 256 + a
end
local a, b, c, d = h1, h2, h3, h4
local s = 32-7
for j = 1, 16 do
local F = ROR(AND(b, c) + AND(-1-b, d) + a + K[j] + W[j], s) + b
s = md5_next_shift[s]
a = d
d = c
c = b
b = F
end
s = 32-5
for j = 17, 32 do
local F = ROR(AND(d, b) + AND(-1-d, c) + a + K[j] + W[(5*j-4) % 16 + 1], s) + b
s = md5_next_shift[s]
a = d
d = c
c = b
b = F
end
s = 32-4
for j = 33, 48 do
local F = ROR(XOR(XOR(b, c), d) + a + K[j] + W[(3*j+2) % 16 + 1], s) + b
s = md5_next_shift[s]
a = d
d = c
c = b
b = F
end
s = 32-6
for j = 49, 64 do
local F = ROR(XOR(c, OR(b, -1-d)) + a + K[j] + W[(j*7-7) % 16 + 1], s) + b
s = md5_next_shift[s]
a = d
d = c
c = b
b = F
end
h1 = (a + h1) % 4294967296
h2 = (b + h2) % 4294967296
h3 = (c + h3) % 4294967296
h4 = (d + h4) % 4294967296
end
H[1], H[2], H[3], H[4] = h1, h2, h3, h4
end
function sha1_feed_64(H, str, offs, size)
-- offs >= 0, size >= 0, size is multiple of 64
local W = common_W
local h1, h2, h3, h4, h5 = H[1], H[2], H[3], H[4], H[5]
for pos = offs, offs + size - 1, 64 do
for j = 1, 16 do
pos = pos + 4
local a, b, c, d = byte(str, pos - 3, pos)
W[j] = ((a * 256 + b) * 256 + c) * 256 + d
end
for j = 17, 80 do
W[j] = ROL(XOR(W[j-3], W[j-8], W[j-14], W[j-16]), 1)
end
local a, b, c, d, e = h1, h2, h3, h4, h5
for j = 1, 20 do
local z = ROL(a, 5) + AND(b, c) + AND(-1-b, d) + 0x5A827999 + W[j] + e -- constant = floor(2^30 * sqrt(2))
e = d
d = c
c = ROR(b, 2)
b = a
a = z
end
for j = 21, 40 do
local z = ROL(a, 5) + XOR(b, c, d) + 0x6ED9EBA1 + W[j] + e -- 2^30 * sqrt(3)
e = d
d = c
c = ROR(b, 2)
b = a
a = z
end
for j = 41, 60 do
local z = ROL(a, 5) + AND(d, c) + AND(b, XOR(d, c)) + 0x8F1BBCDC + W[j] + e -- 2^30 * sqrt(5)
e = d
d = c
c = ROR(b, 2)
b = a
a = z
end
for j = 61, 80 do
local z = ROL(a, 5) + XOR(b, c, d) + 0xCA62C1D6 + W[j] + e -- 2^30 * sqrt(10)
e = d
d = c
c = ROR(b, 2)
b = a
a = z
end
h1 = (a + h1) % 4294967296
h2 = (b + h2) % 4294967296
h3 = (c + h3) % 4294967296
h4 = (d + h4) % 4294967296
h5 = (e + h5) % 4294967296
end
H[1], H[2], H[3], H[4], H[5] = h1, h2, h3, h4, h5
end
function keccak_feed(lanes_lo, lanes_hi, str, offs, size, block_size_in_bytes)
-- This is an example of a Lua function having 79 local variables :-)
-- offs >= 0, size >= 0, size is multiple of block_size_in_bytes, block_size_in_bytes is positive multiple of 8
local RC_lo, RC_hi = sha3_RC_lo, sha3_RC_hi
local qwords_qty = block_size_in_bytes / 8
for pos = offs, offs + size - 1, block_size_in_bytes do
for j = 1, qwords_qty do
local a, b, c, d = byte(str, pos + 1, pos + 4)
lanes_lo[j] = XOR(lanes_lo[j], ((d * 256 + c) * 256 + b) * 256 + a)
pos = pos + 8
a, b, c, d = byte(str, pos - 3, pos)
lanes_hi[j] = XOR(lanes_hi[j], ((d * 256 + c) * 256 + b) * 256 + a)
end
local L01_lo, L01_hi, L02_lo, L02_hi, L03_lo, L03_hi, L04_lo, L04_hi, L05_lo, L05_hi, L06_lo, L06_hi, L07_lo, L07_hi, L08_lo, L08_hi,
L09_lo, L09_hi, L10_lo, L10_hi, L11_lo, L11_hi, L12_lo, L12_hi, L13_lo, L13_hi, L14_lo, L14_hi, L15_lo, L15_hi, L16_lo, L16_hi,
L17_lo, L17_hi, L18_lo, L18_hi, L19_lo, L19_hi, L20_lo, L20_hi, L21_lo, L21_hi, L22_lo, L22_hi, L23_lo, L23_hi, L24_lo, L24_hi, L25_lo, L25_hi =
lanes_lo[1], lanes_hi[1], lanes_lo[2], lanes_hi[2], lanes_lo[3], lanes_hi[3], lanes_lo[4], lanes_hi[4], lanes_lo[5], lanes_hi[5],
lanes_lo[6], lanes_hi[6], lanes_lo[7], lanes_hi[7], lanes_lo[8], lanes_hi[8], lanes_lo[9], lanes_hi[9], lanes_lo[10], lanes_hi[10],
lanes_lo[11], lanes_hi[11], lanes_lo[12], lanes_hi[12], lanes_lo[13], lanes_hi[13], lanes_lo[14], lanes_hi[14], lanes_lo[15], lanes_hi[15],
lanes_lo[16], lanes_hi[16], lanes_lo[17], lanes_hi[17], lanes_lo[18], lanes_hi[18], lanes_lo[19], lanes_hi[19], lanes_lo[20], lanes_hi[20],
lanes_lo[21], lanes_hi[21], lanes_lo[22], lanes_hi[22], lanes_lo[23], lanes_hi[23], lanes_lo[24], lanes_hi[24], lanes_lo[25], lanes_hi[25]
for round_idx = 1, 24 do
local C1_lo = XOR(L01_lo, L06_lo, L11_lo, L16_lo, L21_lo)
local C1_hi = XOR(L01_hi, L06_hi, L11_hi, L16_hi, L21_hi)
local C2_lo = XOR(L02_lo, L07_lo, L12_lo, L17_lo, L22_lo)
local C2_hi = XOR(L02_hi, L07_hi, L12_hi, L17_hi, L22_hi)
local C3_lo = XOR(L03_lo, L08_lo, L13_lo, L18_lo, L23_lo)
local C3_hi = XOR(L03_hi, L08_hi, L13_hi, L18_hi, L23_hi)
local C4_lo = XOR(L04_lo, L09_lo, L14_lo, L19_lo, L24_lo)
local C4_hi = XOR(L04_hi, L09_hi, L14_hi, L19_hi, L24_hi)
local C5_lo = XOR(L05_lo, L10_lo, L15_lo, L20_lo, L25_lo)
local C5_hi = XOR(L05_hi, L10_hi, L15_hi, L20_hi, L25_hi)
local D_lo = XOR(C1_lo, C3_lo * 2 + (C3_hi % 2^32 - C3_hi % 2^31) / 2^31)
local D_hi = XOR(C1_hi, C3_hi * 2 + (C3_lo % 2^32 - C3_lo % 2^31) / 2^31)
local T0_lo = XOR(D_lo, L02_lo)
local T0_hi = XOR(D_hi, L02_hi)
local T1_lo = XOR(D_lo, L07_lo)
local T1_hi = XOR(D_hi, L07_hi)
local T2_lo = XOR(D_lo, L12_lo)
local T2_hi = XOR(D_hi, L12_hi)
local T3_lo = XOR(D_lo, L17_lo)
local T3_hi = XOR(D_hi, L17_hi)
local T4_lo = XOR(D_lo, L22_lo)
local T4_hi = XOR(D_hi, L22_hi)
L02_lo = (T1_lo % 2^32 - T1_lo % 2^20) / 2^20 + T1_hi * 2^12
L02_hi = (T1_hi % 2^32 - T1_hi % 2^20) / 2^20 + T1_lo * 2^12
L07_lo = (T3_lo % 2^32 - T3_lo % 2^19) / 2^19 + T3_hi * 2^13
L07_hi = (T3_hi % 2^32 - T3_hi % 2^19) / 2^19 + T3_lo * 2^13
L12_lo = T0_lo * 2 + (T0_hi % 2^32 - T0_hi % 2^31) / 2^31
L12_hi = T0_hi * 2 + (T0_lo % 2^32 - T0_lo % 2^31) / 2^31
L17_lo = T2_lo * 2^10 + (T2_hi % 2^32 - T2_hi % 2^22) / 2^22
L17_hi = T2_hi * 2^10 + (T2_lo % 2^32 - T2_lo % 2^22) / 2^22
L22_lo = T4_lo * 2^2 + (T4_hi % 2^32 - T4_hi % 2^30) / 2^30
L22_hi = T4_hi * 2^2 + (T4_lo % 2^32 - T4_lo % 2^30) / 2^30
D_lo = XOR(C2_lo, C4_lo * 2 + (C4_hi % 2^32 - C4_hi % 2^31) / 2^31)
D_hi = XOR(C2_hi, C4_hi * 2 + (C4_lo % 2^32 - C4_lo % 2^31) / 2^31)
T0_lo = XOR(D_lo, L03_lo)
T0_hi = XOR(D_hi, L03_hi)
T1_lo = XOR(D_lo, L08_lo)
T1_hi = XOR(D_hi, L08_hi)
T2_lo = XOR(D_lo, L13_lo)
T2_hi = XOR(D_hi, L13_hi)
T3_lo = XOR(D_lo, L18_lo)
T3_hi = XOR(D_hi, L18_hi)
T4_lo = XOR(D_lo, L23_lo)
T4_hi = XOR(D_hi, L23_hi)
L03_lo = (T2_lo % 2^32 - T2_lo % 2^21) / 2^21 + T2_hi * 2^11
L03_hi = (T2_hi % 2^32 - T2_hi % 2^21) / 2^21 + T2_lo * 2^11
L08_lo = (T4_lo % 2^32 - T4_lo % 2^3) / 2^3 + T4_hi * 2^29 % 2^32
L08_hi = (T4_hi % 2^32 - T4_hi % 2^3) / 2^3 + T4_lo * 2^29 % 2^32
L13_lo = T1_lo * 2^6 + (T1_hi % 2^32 - T1_hi % 2^26) / 2^26
L13_hi = T1_hi * 2^6 + (T1_lo % 2^32 - T1_lo % 2^26) / 2^26
L18_lo = T3_lo * 2^15 + (T3_hi % 2^32 - T3_hi % 2^17) / 2^17
L18_hi = T3_hi * 2^15 + (T3_lo % 2^32 - T3_lo % 2^17) / 2^17
L23_lo = (T0_lo % 2^32 - T0_lo % 2^2) / 2^2 + T0_hi * 2^30 % 2^32
L23_hi = (T0_hi % 2^32 - T0_hi % 2^2) / 2^2 + T0_lo * 2^30 % 2^32
D_lo = XOR(C3_lo, C5_lo * 2 + (C5_hi % 2^32 - C5_hi % 2^31) / 2^31)
D_hi = XOR(C3_hi, C5_hi * 2 + (C5_lo % 2^32 - C5_lo % 2^31) / 2^31)
T0_lo = XOR(D_lo, L04_lo)
T0_hi = XOR(D_hi, L04_hi)
T1_lo = XOR(D_lo, L09_lo)
T1_hi = XOR(D_hi, L09_hi)
T2_lo = XOR(D_lo, L14_lo)
T2_hi = XOR(D_hi, L14_hi)
T3_lo = XOR(D_lo, L19_lo)
T3_hi = XOR(D_hi, L19_hi)
T4_lo = XOR(D_lo, L24_lo)
T4_hi = XOR(D_hi, L24_hi)
L04_lo = T3_lo * 2^21 % 2^32 + (T3_hi % 2^32 - T3_hi % 2^11) / 2^11
L04_hi = T3_hi * 2^21 % 2^32 + (T3_lo % 2^32 - T3_lo % 2^11) / 2^11
L09_lo = T0_lo * 2^28 % 2^32 + (T0_hi % 2^32 - T0_hi % 2^4) / 2^4
L09_hi = T0_hi * 2^28 % 2^32 + (T0_lo % 2^32 - T0_lo % 2^4) / 2^4
L14_lo = T2_lo * 2^25 % 2^32 + (T2_hi % 2^32 - T2_hi % 2^7) / 2^7
L14_hi = T2_hi * 2^25 % 2^32 + (T2_lo % 2^32 - T2_lo % 2^7) / 2^7
L19_lo = (T4_lo % 2^32 - T4_lo % 2^8) / 2^8 + T4_hi * 2^24 % 2^32
L19_hi = (T4_hi % 2^32 - T4_hi % 2^8) / 2^8 + T4_lo * 2^24 % 2^32
L24_lo = (T1_lo % 2^32 - T1_lo % 2^9) / 2^9 + T1_hi * 2^23 % 2^32
L24_hi = (T1_hi % 2^32 - T1_hi % 2^9) / 2^9 + T1_lo * 2^23 % 2^32
D_lo = XOR(C4_lo, C1_lo * 2 + (C1_hi % 2^32 - C1_hi % 2^31) / 2^31)
D_hi = XOR(C4_hi, C1_hi * 2 + (C1_lo % 2^32 - C1_lo % 2^31) / 2^31)
T0_lo = XOR(D_lo, L05_lo)
T0_hi = XOR(D_hi, L05_hi)
T1_lo = XOR(D_lo, L10_lo)
T1_hi = XOR(D_hi, L10_hi)
T2_lo = XOR(D_lo, L15_lo)
T2_hi = XOR(D_hi, L15_hi)
T3_lo = XOR(D_lo, L20_lo)
T3_hi = XOR(D_hi, L20_hi)
T4_lo = XOR(D_lo, L25_lo)
T4_hi = XOR(D_hi, L25_hi)
L05_lo = T4_lo * 2^14 + (T4_hi % 2^32 - T4_hi % 2^18) / 2^18
L05_hi = T4_hi * 2^14 + (T4_lo % 2^32 - T4_lo % 2^18) / 2^18
L10_lo = T1_lo * 2^20 % 2^32 + (T1_hi % 2^32 - T1_hi % 2^12) / 2^12
L10_hi = T1_hi * 2^20 % 2^32 + (T1_lo % 2^32 - T1_lo % 2^12) / 2^12
L15_lo = T3_lo * 2^8 + (T3_hi % 2^32 - T3_hi % 2^24) / 2^24
L15_hi = T3_hi * 2^8 + (T3_lo % 2^32 - T3_lo % 2^24) / 2^24
L20_lo = T0_lo * 2^27 % 2^32 + (T0_hi % 2^32 - T0_hi % 2^5) / 2^5
L20_hi = T0_hi * 2^27 % 2^32 + (T0_lo % 2^32 - T0_lo % 2^5) / 2^5
L25_lo = (T2_lo % 2^32 - T2_lo % 2^25) / 2^25 + T2_hi * 2^7
L25_hi = (T2_hi % 2^32 - T2_hi % 2^25) / 2^25 + T2_lo * 2^7
D_lo = XOR(C5_lo, C2_lo * 2 + (C2_hi % 2^32 - C2_hi % 2^31) / 2^31)
D_hi = XOR(C5_hi, C2_hi * 2 + (C2_lo % 2^32 - C2_lo % 2^31) / 2^31)
T1_lo = XOR(D_lo, L06_lo)
T1_hi = XOR(D_hi, L06_hi)
T2_lo = XOR(D_lo, L11_lo)
T2_hi = XOR(D_hi, L11_hi)
T3_lo = XOR(D_lo, L16_lo)
T3_hi = XOR(D_hi, L16_hi)
T4_lo = XOR(D_lo, L21_lo)
T4_hi = XOR(D_hi, L21_hi)
L06_lo = T2_lo * 2^3 + (T2_hi % 2^32 - T2_hi % 2^29) / 2^29
L06_hi = T2_hi * 2^3 + (T2_lo % 2^32 - T2_lo % 2^29) / 2^29
L11_lo = T4_lo * 2^18 + (T4_hi % 2^32 - T4_hi % 2^14) / 2^14
L11_hi = T4_hi * 2^18 + (T4_lo % 2^32 - T4_lo % 2^14) / 2^14
L16_lo = (T1_lo % 2^32 - T1_lo % 2^28) / 2^28 + T1_hi * 2^4
L16_hi = (T1_hi % 2^32 - T1_hi % 2^28) / 2^28 + T1_lo * 2^4
L21_lo = (T3_lo % 2^32 - T3_lo % 2^23) / 2^23 + T3_hi * 2^9
L21_hi = (T3_hi % 2^32 - T3_hi % 2^23) / 2^23 + T3_lo * 2^9
L01_lo = XOR(D_lo, L01_lo)
L01_hi = XOR(D_hi, L01_hi)
L01_lo, L02_lo, L03_lo, L04_lo, L05_lo = XOR(L01_lo, AND(-1-L02_lo, L03_lo)), XOR(L02_lo, AND(-1-L03_lo, L04_lo)), XOR(L03_lo, AND(-1-L04_lo, L05_lo)), XOR(L04_lo, AND(-1-L05_lo, L01_lo)), XOR(L05_lo, AND(-1-L01_lo, L02_lo))
L01_hi, L02_hi, L03_hi, L04_hi, L05_hi = XOR(L01_hi, AND(-1-L02_hi, L03_hi)), XOR(L02_hi, AND(-1-L03_hi, L04_hi)), XOR(L03_hi, AND(-1-L04_hi, L05_hi)), XOR(L04_hi, AND(-1-L05_hi, L01_hi)), XOR(L05_hi, AND(-1-L01_hi, L02_hi))
L06_lo, L07_lo, L08_lo, L09_lo, L10_lo = XOR(L09_lo, AND(-1-L10_lo, L06_lo)), XOR(L10_lo, AND(-1-L06_lo, L07_lo)), XOR(L06_lo, AND(-1-L07_lo, L08_lo)), XOR(L07_lo, AND(-1-L08_lo, L09_lo)), XOR(L08_lo, AND(-1-L09_lo, L10_lo))
L06_hi, L07_hi, L08_hi, L09_hi, L10_hi = XOR(L09_hi, AND(-1-L10_hi, L06_hi)), XOR(L10_hi, AND(-1-L06_hi, L07_hi)), XOR(L06_hi, AND(-1-L07_hi, L08_hi)), XOR(L07_hi, AND(-1-L08_hi, L09_hi)), XOR(L08_hi, AND(-1-L09_hi, L10_hi))
L11_lo, L12_lo, L13_lo, L14_lo, L15_lo = XOR(L12_lo, AND(-1-L13_lo, L14_lo)), XOR(L13_lo, AND(-1-L14_lo, L15_lo)), XOR(L14_lo, AND(-1-L15_lo, L11_lo)), XOR(L15_lo, AND(-1-L11_lo, L12_lo)), XOR(L11_lo, AND(-1-L12_lo, L13_lo))
L11_hi, L12_hi, L13_hi, L14_hi, L15_hi = XOR(L12_hi, AND(-1-L13_hi, L14_hi)), XOR(L13_hi, AND(-1-L14_hi, L15_hi)), XOR(L14_hi, AND(-1-L15_hi, L11_hi)), XOR(L15_hi, AND(-1-L11_hi, L12_hi)), XOR(L11_hi, AND(-1-L12_hi, L13_hi))
L16_lo, L17_lo, L18_lo, L19_lo, L20_lo = XOR(L20_lo, AND(-1-L16_lo, L17_lo)), XOR(L16_lo, AND(-1-L17_lo, L18_lo)), XOR(L17_lo, AND(-1-L18_lo, L19_lo)), XOR(L18_lo, AND(-1-L19_lo, L20_lo)), XOR(L19_lo, AND(-1-L20_lo, L16_lo))
L16_hi, L17_hi, L18_hi, L19_hi, L20_hi = XOR(L20_hi, AND(-1-L16_hi, L17_hi)), XOR(L16_hi, AND(-1-L17_hi, L18_hi)), XOR(L17_hi, AND(-1-L18_hi, L19_hi)), XOR(L18_hi, AND(-1-L19_hi, L20_hi)), XOR(L19_hi, AND(-1-L20_hi, L16_hi))
L21_lo, L22_lo, L23_lo, L24_lo, L25_lo = XOR(L23_lo, AND(-1-L24_lo, L25_lo)), XOR(L24_lo, AND(-1-L25_lo, L21_lo)), XOR(L25_lo, AND(-1-L21_lo, L22_lo)), XOR(L21_lo, AND(-1-L22_lo, L23_lo)), XOR(L22_lo, AND(-1-L23_lo, L24_lo))
L21_hi, L22_hi, L23_hi, L24_hi, L25_hi = XOR(L23_hi, AND(-1-L24_hi, L25_hi)), XOR(L24_hi, AND(-1-L25_hi, L21_hi)), XOR(L25_hi, AND(-1-L21_hi, L22_hi)), XOR(L21_hi, AND(-1-L22_hi, L23_hi)), XOR(L22_hi, AND(-1-L23_hi, L24_hi))
L01_lo = XOR(L01_lo, RC_lo[round_idx])
L01_hi = L01_hi + RC_hi[round_idx] -- RC_hi[] is either 0 or 0x80000000, so we could use fast addition instead of slow XOR
end
lanes_lo[1] = L01_lo
lanes_hi[1] = L01_hi
lanes_lo[2] = L02_lo
lanes_hi[2] = L02_hi
lanes_lo[3] = L03_lo
lanes_hi[3] = L03_hi
lanes_lo[4] = L04_lo
lanes_hi[4] = L04_hi
lanes_lo[5] = L05_lo
lanes_hi[5] = L05_hi
lanes_lo[6] = L06_lo
lanes_hi[6] = L06_hi
lanes_lo[7] = L07_lo
lanes_hi[7] = L07_hi
lanes_lo[8] = L08_lo
lanes_hi[8] = L08_hi
lanes_lo[9] = L09_lo
lanes_hi[9] = L09_hi
lanes_lo[10] = L10_lo
lanes_hi[10] = L10_hi
lanes_lo[11] = L11_lo
lanes_hi[11] = L11_hi
lanes_lo[12] = L12_lo
lanes_hi[12] = L12_hi
lanes_lo[13] = L13_lo
lanes_hi[13] = L13_hi
lanes_lo[14] = L14_lo
lanes_hi[14] = L14_hi
lanes_lo[15] = L15_lo
lanes_hi[15] = L15_hi
lanes_lo[16] = L16_lo
lanes_hi[16] = L16_hi
lanes_lo[17] = L17_lo
lanes_hi[17] = L17_hi
lanes_lo[18] = L18_lo
lanes_hi[18] = L18_hi
lanes_lo[19] = L19_lo
lanes_hi[19] = L19_hi
lanes_lo[20] = L20_lo
lanes_hi[20] = L20_hi
lanes_lo[21] = L21_lo
lanes_hi[21] = L21_hi
lanes_lo[22] = L22_lo
lanes_hi[22] = L22_hi
lanes_lo[23] = L23_lo
lanes_hi[23] = L23_hi
lanes_lo[24] = L24_lo
lanes_hi[24] = L24_hi
lanes_lo[25] = L25_lo
lanes_hi[25] = L25_hi
end
end
end
--------------------------------------------------------------------------------
-- MAGIC NUMBERS CALCULATOR
--------------------------------------------------------------------------------
-- Q:
-- Is 53-bit "double" math enough to calculate square roots and cube roots of primes with 64 correct bits after decimal point?
-- A:
-- Yes, 53-bit "double" arithmetic is enough.
-- We could obtain first 40 bits by direct calculation of p^(1/3) and next 40 bits by one step of Newton's method.
do
local function mul(src1, src2, factor, result_length)
-- src1, src2 - long integers (arrays of digits in base 2^24)
-- factor - small integer
-- returns long integer result (src1 * src2 * factor) and its floating point approximation
local result, carry, value, weight = {}, 0.0, 0.0, 1.0
for j = 1, result_length do
for k = math_max(1, j + 1 - #src2), math_min(j, #src1) do
carry = carry + factor * src1[k] * src2[j + 1 - k] -- "int32" is not enough for multiplication result, that's why "factor" must be of type "double"
end
local digit = carry % 2^24
result[j] = floor(digit)
carry = (carry - digit) / 2^24
value = value + digit * weight
weight = weight * 2^24
end
return result, value
end
local idx, step, p, one, sqrt_hi, sqrt_lo = 0, {4, 1, 2, -2, 2}, 4, {1}, sha2_H_hi, sha2_H_lo
repeat
p = p + step[p % 6]
local d = 1
repeat
d = d + step[d % 6]
if d*d > p then -- next prime number is found
local root = p^(1/3)
local R = root * 2^40
R = mul({R - R % 1}, one, 1.0, 2)
local _, delta = mul(R, mul(R, R, 1.0, 4), -1.0, 4)
local hi = R[2] % 65536 * 65536 + floor(R[1] / 256)
local lo = R[1] % 256 * 16777216 + floor(delta * (2^-56 / 3) * root / p)
if idx < 16 then
root = p^(1/2)
R = root * 2^40
R = mul({R - R % 1}, one, 1.0, 2)
_, delta = mul(R, R, -1.0, 2)
local hi = R[2] % 65536 * 65536 + floor(R[1] / 256)
local lo = R[1] % 256 * 16777216 + floor(delta * 2^-17 / root)
local idx = idx % 8 + 1
sha2_H_ext256[224][idx] = lo
sqrt_hi[idx], sqrt_lo[idx] = hi, lo + hi * hi_factor
if idx > 7 then
sqrt_hi, sqrt_lo = sha2_H_ext512_hi[384], sha2_H_ext512_lo[384]
end
end
idx = idx + 1
sha2_K_hi[idx], sha2_K_lo[idx] = hi, lo % K_lo_modulo + hi * hi_factor
break
end
until p % d == 0
until idx > 79
end
-- Calculating IVs for SHA512/224 and SHA512/256
for width = 224, 256, 32 do
local H_lo, H_hi = {}
if XOR64A5 then
for j = 1, 8 do
H_lo[j] = XOR64A5(sha2_H_lo[j])
end
else
H_hi = {}
for j = 1, 8 do
H_lo[j] = XOR32A5(sha2_H_lo[j])
H_hi[j] = XOR32A5(sha2_H_hi[j])
end
end
sha512_feed_128(H_lo, H_hi, "SHA-512/"..tostring(width).."\128"..string_rep("\0", 115).."\88", 0, 128)
sha2_H_ext512_lo[width] = H_lo
sha2_H_ext512_hi[width] = H_hi
end
-- Constants for MD5
do
local sin, abs, modf = math.sin, math.abs, math.modf
for idx = 1, 64 do
-- we can't use formula floor(abs(sin(idx))*2^32) because its result may be beyond integer range on Lua built with 32-bit integers
local hi, lo = modf(abs(sin(idx)) * 2^16)
md5_K[idx] = hi * 65536 + floor(lo * 2^16)
end
end
-- Constants for SHA3
do
local sh_reg = 29
local function next_bit()
local r = sh_reg % 2
sh_reg = XOR_BYTE((sh_reg - r) / 2, 142 * r)
return r
end
for idx = 1, 24 do
local lo, m = 0
for _ = 1, 6 do
m = m and m * m * 2 or 1
lo = lo + next_bit() * m
end
local hi = next_bit() * m
sha3_RC_hi[idx], sha3_RC_lo[idx] = hi, lo + hi * hi_factor_keccak
end
end
--------------------------------------------------------------------------------
-- MAIN FUNCTIONS
--------------------------------------------------------------------------------
local function sha256ext(width, message)
-- Create an instance (private objects for current calculation)
local H, length, tail = {unpack(sha2_H_ext256[width])}, 0.0, ""
local function partial(message_part)
if message_part then
if tail then
length = length + #message_part
local offs = 0
if tail ~= "" and #tail + #message_part >= 64 then
offs = 64 - #tail
sha256_feed_64(H, tail..sub(message_part, 1, offs), 0, 64)
tail = ""
end
local size = #message_part - offs
local size_tail = size % 64
sha256_feed_64(H, message_part, offs, size - size_tail)
tail = tail..sub(message_part, #message_part + 1 - size_tail)
return partial
else
error("Adding more chunks is not allowed after receiving the result", 2)
end
else
if tail then
local final_blocks = {tail, "\128", string_rep("\0", (-9 - length) % 64 + 1)}
tail = nil
-- Assuming user data length is shorter than (2^53)-9 bytes
-- Anyway, it looks very unrealistic that someone would spend more than a year of calculations to process 2^53 bytes of data by using this Lua script :-)
-- 2^53 bytes = 2^56 bits, so "bit-counter" fits in 7 bytes
length = length * (8 / 256^7) -- convert "byte-counter" to "bit-counter" and move decimal point to the left
for j = 4, 10 do
length = length % 1 * 256
final_blocks[j] = char(floor(length))
end
final_blocks = table_concat(final_blocks)
sha256_feed_64(H, final_blocks, 0, #final_blocks)
local max_reg = width / 32
for j = 1, max_reg do
H[j] = HEX(H[j])
end
H = table_concat(H, "", 1, max_reg)
end
return H
end
end
if message then
-- Actually perform calculations and return the SHA256 digest of a message
return partial(message)()
else
-- Return function for chunk-by-chunk loading
-- User should feed every chunk of input data as single argument to this function and finally get SHA256 digest by invoking this function without an argument
return partial
end
end
local function sha512ext(width, message)
-- Create an instance (private objects for current calculation)
local length, tail, H_lo, H_hi = 0.0, "", {unpack(sha2_H_ext512_lo[width])}, not HEX64 and {unpack(sha2_H_ext512_hi[width])}
local function partial(message_part)
if message_part then
if tail then
length = length + #message_part
local offs = 0
if tail ~= "" and #tail + #message_part >= 128 then
offs = 128 - #tail
sha512_feed_128(H_lo, H_hi, tail..sub(message_part, 1, offs), 0, 128)
tail = ""
end
local size = #message_part - offs
local size_tail = size % 128
sha512_feed_128(H_lo, H_hi, message_part, offs, size - size_tail)
tail = tail..sub(message_part, #message_part + 1 - size_tail)
return partial
else
error("Adding more chunks is not allowed after receiving the result", 2)
end
else
if tail then
local final_blocks = {tail, "\128", string_rep("\0", (-17-length) % 128 + 9)}
tail = nil
-- Assuming user data length is shorter than (2^53)-17 bytes
-- 2^53 bytes = 2^56 bits, so "bit-counter" fits in 7 bytes
length = length * (8 / 256^7) -- convert "byte-counter" to "bit-counter" and move floating point to the left
for j = 4, 10 do
length = length % 1 * 256
final_blocks[j] = char(floor(length))
end
final_blocks = table_concat(final_blocks)
sha512_feed_128(H_lo, H_hi, final_blocks, 0, #final_blocks)
local max_reg = ceil(width / 64)
if HEX64 then
for j = 1, max_reg do
H_lo[j] = HEX64(H_lo[j])
end
else
for j = 1, max_reg do
H_lo[j] = HEX(H_hi[j])..HEX(H_lo[j])
end
H_hi = nil
end
H_lo = sub(table_concat(H_lo, "", 1, max_reg), 1, width / 4)
end
return H_lo
end
end
if message then
-- Actually perform calculations and return the SHA512 digest of a message
return partial(message)()
else
-- Return function for chunk-by-chunk loading
-- User should feed every chunk of input data as single argument to this function and finally get SHA512 digest by invoking this function without an argument
return partial
end
end
local function md5(message)
-- Create an instance (private objects for current calculation)
local H, length, tail = {unpack(md5_sha1_H, 1, 4)}, 0.0, ""
local function partial(message_part)
if message_part then
if tail then
length = length + #message_part
local offs = 0
if tail ~= "" and #tail + #message_part >= 64 then
offs = 64 - #tail
md5_feed_64(H, tail..sub(message_part, 1, offs), 0, 64)
tail = ""
end
local size = #message_part - offs
local size_tail = size % 64
md5_feed_64(H, message_part, offs, size - size_tail)
tail = tail..sub(message_part, #message_part + 1 - size_tail)
return partial
else
error("Adding more chunks is not allowed after receiving the result", 2)
end
else
if tail then
local final_blocks = {tail, "\128", string_rep("\0", (-9 - length) % 64)}
tail = nil
length = length * 8 -- convert "byte-counter" to "bit-counter"
for j = 4, 11 do
local low_byte = length % 256
final_blocks[j] = char(low_byte)
length = (length - low_byte) / 256
end
final_blocks = table_concat(final_blocks)
md5_feed_64(H, final_blocks, 0, #final_blocks)
for j = 1, 4 do
H[j] = HEX(H[j])
end
H = gsub(table_concat(H), "(..)(..)(..)(..)", "%4%3%2%1")
end
return H
end
end
if message then
-- Actually perform calculations and return the MD5 digest of a message
return partial(message)()
else
-- Return function for chunk-by-chunk loading
-- User should feed every chunk of input data as single argument to this function and finally get MD5 digest by invoking this function without an argument
return partial
end
end
local function sha1(message)
-- Create an instance (private objects for current calculation)
local H, length, tail = {unpack(md5_sha1_H)}, 0.0, ""
local function partial(message_part)
if message_part then
if tail then
length = length + #message_part
local offs = 0
if tail ~= "" and #tail + #message_part >= 64 then
offs = 64 - #tail
sha1_feed_64(H, tail..sub(message_part, 1, offs), 0, 64)
tail = ""
end
local size = #message_part - offs
local size_tail = size % 64
sha1_feed_64(H, message_part, offs, size - size_tail)
tail = tail..sub(message_part, #message_part + 1 - size_tail)
return partial
else
error("Adding more chunks is not allowed after receiving the result", 2)
end
else
if tail then
local final_blocks = {tail, "\128", string_rep("\0", (-9 - length) % 64 + 1)}
tail = nil
-- Assuming user data length is shorter than (2^53)-9 bytes
-- 2^53 bytes = 2^56 bits, so "bit-counter" fits in 7 bytes
length = length * (8 / 256^7) -- convert "byte-counter" to "bit-counter" and move decimal point to the left
for j = 4, 10 do
length = length % 1 * 256
final_blocks[j] = char(floor(length))
end
final_blocks = table_concat(final_blocks)
sha1_feed_64(H, final_blocks, 0, #final_blocks)
for j = 1, 5 do
H[j] = HEX(H[j])
end
H = table_concat(H)
end
return H
end
end
if message then
-- Actually perform calculations and return the SHA-1 digest of a message
return partial(message)()
else
-- Return function for chunk-by-chunk loading
-- User should feed every chunk of input data as single argument to this function and finally get SHA-1 digest by invoking this function without an argument
return partial
end
end
local function keccak(block_size_in_bytes, digest_size_in_bytes, is_SHAKE, message)
-- "block_size_in_bytes" is multiple of 8
if type(digest_size_in_bytes) ~= "number" then
-- arguments in SHAKE are swapped:
-- NIST FIPS 202 defines SHAKE(message,num_bits)
-- this module defines SHAKE(num_bytes,message)
-- it's easy to forget about this swap, hence the check
error("Argument 'digest_size_in_bytes' must be a number", 2)
end
-- Create an instance (private objects for current calculation)
local tail, lanes_lo, lanes_hi = "", create_array_of_lanes(), hi_factor_keccak == 0 and create_array_of_lanes()
local result
--~ pad the input N using the pad function, yielding a padded bit string P with a length divisible by r (such that n = len(P)/r is integer),
--~ break P into n consecutive r-bit pieces P0, ..., Pn-1 (last is zero-padded)
--~ initialize the state S to a string of b 0 bits.
--~ absorb the input into the state: For each block Pi,
--~ extend Pi at the end by a string of c 0 bits, yielding one of length b,
--~ XOR that with S and
--~ apply the block permutation f to the result, yielding a new state S
--~ initialize Z to be the empty string
--~ while the length of Z is less than d:
--~ append the first r bits of S to Z
--~ if Z is still less than d bits long, apply f to S, yielding a new state S.
--~ truncate Z to d bits
local function partial(message_part)
if message_part then
if tail then
local offs = 0
if tail ~= "" and #tail + #message_part >= block_size_in_bytes then
offs = block_size_in_bytes - #tail
keccak_feed(lanes_lo, lanes_hi, tail..sub(message_part, 1, offs), 0, block_size_in_bytes, block_size_in_bytes)
tail = ""
end
local size = #message_part - offs
local size_tail = size % block_size_in_bytes
keccak_feed(lanes_lo, lanes_hi, message_part, offs, size - size_tail, block_size_in_bytes)
tail = tail..sub(message_part, #message_part + 1 - size_tail)
return partial
else
error("Adding more chunks is not allowed after receiving the result", 2)
end
else
if tail then
-- append the following bits to the message: for usual SHA3: 011(0*)1, for SHAKE: 11111(0*)1
local gap_start = is_SHAKE and 31 or 6
tail = tail..(#tail + 1 == block_size_in_bytes and char(gap_start + 128) or char(gap_start)..string_rep("\0", (-2 - #tail) % block_size_in_bytes).."\128")
keccak_feed(lanes_lo, lanes_hi, tail, 0, #tail, block_size_in_bytes)
tail = nil
local lanes_used = 0
local total_lanes = floor(block_size_in_bytes / 8)
local qwords = {}
local function get_next_qwords_of_digest(qwords_qty)
-- returns not more than 'qwords_qty' qwords ('qwords_qty' might be non-integer)
-- doesn't go across keccak-buffer boundary
-- block_size_in_bytes is a multiple of 8, so, keccak-buffer contains integer number of qwords
if lanes_used >= total_lanes then
keccak_feed(lanes_lo, lanes_hi, "\0\0\0\0\0\0\0\0", 0, 8, 8)
lanes_used = 0
end
qwords_qty = floor(math_min(qwords_qty, total_lanes - lanes_used))
if hi_factor_keccak ~= 0 then
for j = 1, qwords_qty do
qwords[j] = HEX64(lanes_lo[lanes_used + j - 1 + lanes_index_base])
end
else
for j = 1, qwords_qty do
qwords[j] = HEX(lanes_hi[lanes_used + j])..HEX(lanes_lo[lanes_used + j])
end
end
lanes_used = lanes_used + qwords_qty
return
gsub(table_concat(qwords, "", 1, qwords_qty), "(..)(..)(..)(..)(..)(..)(..)(..)", "%8%7%6%5%4%3%2%1"),
qwords_qty * 8
end
local parts = {} -- digest parts
local last_part, last_part_size = "", 0
local function get_next_part_of_digest(bytes_needed)
-- returns 'bytes_needed' bytes, for arbitrary integer 'bytes_needed'
bytes_needed = bytes_needed or 1
if bytes_needed <= last_part_size then
last_part_size = last_part_size - bytes_needed
local part_size_in_nibbles = bytes_needed * 2
local result = sub(last_part, 1, part_size_in_nibbles)
last_part = sub(last_part, part_size_in_nibbles + 1)
return result
end
local parts_qty = 0
if last_part_size > 0 then
parts_qty = 1
parts[parts_qty] = last_part
bytes_needed = bytes_needed - last_part_size
end
-- repeats until the length is enough
while bytes_needed >= 8 do
local next_part, next_part_size = get_next_qwords_of_digest(bytes_needed / 8)
parts_qty = parts_qty + 1
parts[parts_qty] = next_part
bytes_needed = bytes_needed - next_part_size
end
if bytes_needed > 0 then
last_part, last_part_size = get_next_qwords_of_digest(1)
parts_qty = parts_qty + 1
parts[parts_qty] = get_next_part_of_digest(bytes_needed)
else
last_part, last_part_size = "", 0
end
return table_concat(parts, "", 1, parts_qty)
end
if digest_size_in_bytes < 0 then
result = get_next_part_of_digest
else
result = get_next_part_of_digest(digest_size_in_bytes)
end
end
return result
end
end
if message then
-- Actually perform calculations and return the SHA3 digest of a message
return partial(message)()
else
-- Return function for chunk-by-chunk loading
-- User should feed every chunk of input data as single argument to this function and finally get SHA3 digest by invoking this function without an argument
return partial
end
end
local hex2bin, bin2base64, base642bin
do
function hex2bin(hex_string)
return (gsub(hex_string, "%x%x",
function (hh)
return char(tonumber(hh, 16))
end
))
end
local base64_symbols = {
['+'] = 62, ['-'] = 62, [62] = '+',
['/'] = 63, ['_'] = 63, [63] = '/',
['='] = -1, ['.'] = -1, [-1] = '='
}
local symbol_index = 0
for j, pair in ipairs{'AZ', 'az', '09'} do
for ascii = byte(pair), byte(pair, 2) do
local ch = char(ascii)
base64_symbols[ch] = symbol_index
base64_symbols[symbol_index] = ch
symbol_index = symbol_index + 1
end
end
function bin2base64(binary_string)
local result = {}
for pos = 1, #binary_string, 3 do
local c1, c2, c3, c4 = byte(sub(binary_string, pos, pos + 2)..'\0', 1, -1)
result[#result + 1] =
base64_symbols[floor(c1 / 4)]
..base64_symbols[c1 % 4 * 16 + floor(c2 / 16)]
..base64_symbols[c3 and c2 % 16 * 4 + floor(c3 / 64) or -1]
..base64_symbols[c4 and c3 % 64 or -1]
end
return table_concat(result)
end
function base642bin(base64_string)
local result, chars_qty = {}, 3
for pos, ch in gmatch(gsub(base64_string, '%s+', ''), '()(.)') do
local code = base64_symbols[ch]
if code < 0 then
chars_qty = chars_qty - 1
code = 0
end
local idx = pos % 4
if idx > 0 then
result[-idx] = code
else
local c1 = result[-1] * 4 + floor(result[-2] / 16)
local c2 = (result[-2] % 16) * 16 + floor(result[-3] / 4)
local c3 = (result[-3] % 4) * 64 + code
result[#result + 1] = sub(char(c1, c2, c3), 1, chars_qty)
end
end
return table_concat(result)
end
end
local block_size_for_HMAC -- this table will be initialized at the end of the module
local function pad_and_xor(str, result_length, byte_for_xor)
return gsub(str, ".",
function(c)
return char(XOR_BYTE(byte(c), byte_for_xor))
end
)..string_rep(char(byte_for_xor), result_length - #str)
end
local function hmac(hash_func, key, message)
-- Create an instance (private objects for current calculation)
local block_size = block_size_for_HMAC[hash_func]
if not block_size then
error("Unknown hash function", 2)
end
if #key > block_size then
key = hex2bin(hash_func(key))
end
local append = hash_func()(pad_and_xor(key, block_size, 0x36))
local result
local function partial(message_part)
if not message_part then
result = result or hash_func(pad_and_xor(key, block_size, 0x5C)..hex2bin(append()))
return result
elseif result then
error("Adding more chunks is not allowed after receiving the result", 2)
else
append(message_part)
return partial
end
end
if message then
-- Actually perform calculations and return the HMAC of a message
return partial(message)()
else
-- Return function for chunk-by-chunk loading of a message
-- User should feed every chunk of the message as single argument to this function and finally get HMAC by invoking this function without an argument
return partial
end
end
local sha = {
md5 = md5, -- MD5
sha1 = sha1, -- SHA-1
-- SHA2 hash functions:
sha224 = function (message) return sha256ext(224, message) end, -- SHA-224
sha256 = function (message) return sha256ext(256, message) end, -- SHA-256
sha512_224 = function (message) return sha512ext(224, message) end, -- SHA-512/224
sha512_256 = function (message) return sha512ext(256, message) end, -- SHA-512/256
sha384 = function (message) return sha512ext(384, message) end, -- SHA-384
sha512 = function (message) return sha512ext(512, message) end, -- SHA-512
-- SHA3 hash functions:
sha3_224 = function (message) return keccak((1600 - 2 * 224) / 8, 224 / 8, false, message) end, -- SHA3-224
sha3_256 = function (message) return keccak((1600 - 2 * 256) / 8, 256 / 8, false, message) end, -- SHA3-256
sha3_384 = function (message) return keccak((1600 - 2 * 384) / 8, 384 / 8, false, message) end, -- SHA3-384
sha3_512 = function (message) return keccak((1600 - 2 * 512) / 8, 512 / 8, false, message) end, -- SHA3-512
shake128 = function (digest_size_in_bytes, message) return keccak((1600 - 2 * 128) / 8, digest_size_in_bytes, true, message) end, -- SHAKE128
shake256 = function (digest_size_in_bytes, message) return keccak((1600 - 2 * 256) / 8, digest_size_in_bytes, true, message) end, -- SHAKE256
-- misc utilities:
hmac = hmac, -- HMAC(hash_func, key, message) is applicable to any hash function from this module except SHAKE*
hex2bin = hex2bin, -- converts hexadecimal representation to binary string
base642bin = base642bin, -- converts base64 representation to binary string
bin2base64 = bin2base64, -- converts binary string to base64 representation
}
block_size_for_HMAC = {
[sha.md5] = 64,
[sha.sha1] = 64,
[sha.sha224] = 64,
[sha.sha256] = 64,
[sha.sha512_224] = 128,
[sha.sha512_256] = 128,
[sha.sha384] = 128,
[sha.sha512] = 128,
[sha.sha3_224] = (1600 - 2 * 224) / 8,
[sha.sha3_256] = (1600 - 2 * 256) / 8,
[sha.sha3_384] = (1600 - 2 * 384) / 8,
[sha.sha3_512] = (1600 - 2 * 512) / 8,
}
return sha
local function _W(f) local e=setmetatable({}, {__index = _ENV or getfenv()}) if setfenv then setfenv(f, e) end return f(e) or e end
local bit=_W(function(_ENV, ...)
--[[
This bit API is designed to cope with unsigned integers instead of normal integers
To do this we add checks for overflows: (x > 2^31 ? x - 2 ^ 32 : x)
These are written in long form because no constant folding.
]]
local floor = math.floor
local lshift, rshift
rshift = function(a,disp)
return floor(a % 4294967296 / 2^disp)
end
lshift = function(a,disp)
return (a * 2^disp) % 4294967296
end
return {
-- bit operations
bnot = bit.bnot,
band = bit.band,
bor = bit.bor,
bxor = bit.bxor,
rshift = rshift,
lshift = lshift,
}
end)
local gf=_W(function(_ENV, ...)
-- finite field with base 2 and modulo irreducible polynom x^8+x^4+x^3+x+1 = 0x11d
local bxor = bit.bxor
local lshift = bit.lshift
-- private data of gf
local n = 0x100
local ord = 0xff
local irrPolynom = 0x11b
local exp = {}
local log = {}
--
-- add two polynoms (its simply xor)
--
local function add(operand1, operand2)
return bxor(operand1,operand2)
end
--
-- subtract two polynoms (same as addition)
--
local function sub(operand1, operand2)
return bxor(operand1,operand2)
end
--
-- inverts element
-- a^(-1) = g^(order - log(a))
--
local function invert(operand)
-- special case for 1
if (operand == 1) then
return 1
end
-- normal invert
local exponent = ord - log[operand]
return exp[exponent]
end
--
-- multiply two elements using a logarithm table
-- a*b = g^(log(a)+log(b))
--
local function mul(operand1, operand2)
if (operand1 == 0 or operand2 == 0) then
return 0
end
local exponent = log[operand1] + log[operand2]
if (exponent >= ord) then
exponent = exponent - ord
end
return exp[exponent]
end
--
-- divide two elements
-- a/b = g^(log(a)-log(b))
--
local function div(operand1, operand2)
if (operand1 == 0) then
return 0
end
-- TODO: exception if operand2 == 0
local exponent = log[operand1] - log[operand2]
if (exponent < 0) then
exponent = exponent + ord
end
return exp[exponent]
end
--
-- print logarithmic table
--
local function printLog()
for i = 1, n do
print("log(", i-1, ")=", log[i-1])
end
end
--
-- print exponentiation table
--
local function printExp()
for i = 1, n do
print("exp(", i-1, ")=", exp[i-1])
end
end
--
-- calculate logarithmic and exponentiation table
--
local function initMulTable()
local a = 1
for i = 0,ord-1 do
exp[i] = a
log[a] = i
-- multiply with generator x+1 -> left shift + 1
a = bxor(lshift(a, 1), a)
-- if a gets larger than order, reduce modulo irreducible polynom
if a > ord then
a = sub(a, irrPolynom)
end
end
end
initMulTable()
return {
add = add,
sub = sub,
invert = invert,
mul = mul,
div = div,
printLog = printLog,
printExp = printExp,
}
end)
local util=_W(function(_ENV, ...)
-- Cache some bit operators
local bxor = bit.bxor
local rshift = bit.rshift
local band = bit.band
local lshift = bit.lshift
local sleepCheckIn
--
-- calculate the parity of one byte
--
local function byteParity(byte)
byte = bxor(byte, rshift(byte, 4))
byte = bxor(byte, rshift(byte, 2))
byte = bxor(byte, rshift(byte, 1))
return band(byte, 1)
end
--
-- get byte at position index
--
local function getByte(number, index)
if (index == 0) then
return band(number,0xff)
else
return band(rshift(number, index*8),0xff)
end
end
--
-- put number into int at position index
--
local function putByte(number, index)
if (index == 0) then
return band(number,0xff)
else
return lshift(band(number,0xff),index*8)
end
end
--
-- convert byte array to int array
--
local function bytesToInts(bytes, start, n)
local ints = {}
for i = 0, n - 1 do
ints[i + 1] =
putByte(bytes[start + (i*4)], 3) +
putByte(bytes[start + (i*4) + 1], 2) +
putByte(bytes[start + (i*4) + 2], 1) +
putByte(bytes[start + (i*4) + 3], 0)
if n % 10000 == 0 then sleepCheckIn() end
end
return ints
end
--
-- convert int array to byte array
--
local function intsToBytes(ints, output, outputOffset, n)
n = n or #ints
for i = 0, n - 1 do
for j = 0,3 do
output[outputOffset + i*4 + (3 - j)] = getByte(ints[i + 1], j)
end
if n % 10000 == 0 then sleepCheckIn() end
end
return output
end
--
-- convert bytes to hexString
--
local function bytesToHex(bytes)
local hexBytes = ""
for i,byte in ipairs(bytes) do
hexBytes = hexBytes .. string.format("%02x ", byte)
end
return hexBytes
end
local function hexToBytes(bytes)
local out = {}
for i = 1, #bytes, 2 do
out[#out + 1] = tonumber(bytes:sub(i, i + 1), 16)
end
return out
end
--
-- convert data to hex string
--
local function toHexString(data)
local type = type(data)
if (type == "number") then
return string.format("%08x",data)
elseif (type == "table") then
return bytesToHex(data)
elseif (type == "string") then
local bytes = {string.byte(data, 1, #data)}
return bytesToHex(bytes)
else
return data
end
end
local function padByteString(data)
local dataLength = #data
local random1 = math.random(0,255)
local random2 = math.random(0,255)
local prefix = string.char(random1,
random2,
random1,
random2,
getByte(dataLength, 3),
getByte(dataLength, 2),
getByte(dataLength, 1),
getByte(dataLength, 0)
)
data = prefix .. data
local paddingLength = math.ceil(#data/16)*16 - #data
local padding = ""
for i=1,paddingLength do
padding = padding .. string.char(math.random(0,255))
end
return data .. padding
end
local function properlyDecrypted(data)
local random = {string.byte(data,1,4)}
if (random[1] == random[3] and random[2] == random[4]) then
return true
end
return false
end
local function unpadByteString(data)
if (not properlyDecrypted(data)) then
return nil
end
local dataLength = putByte(string.byte(data,5), 3)
+ putByte(string.byte(data,6), 2)
+ putByte(string.byte(data,7), 1)
+ putByte(string.byte(data,8), 0)
return string.sub(data,9,8+dataLength)
end
local function xorIV(data, iv)
for i = 1,16 do
data[i] = bxor(data[i], iv[i])
end
end
local function increment(data)
local i = 16
while true do
local value = data[i] + 1
if value >= 256 then
data[i] = value - 256
i = (i - 2) % 16 + 1
else
data[i] = value
break
end
end
end
-- Called every encryption cycle
local push, pull, time = os.queueEvent, coroutine.yield, os.time
local oldTime = time()
function sleepCheckIn()
local newTime = time()
if newTime - oldTime >= 0.03 then -- (0.020 * 1.5)
oldTime = newTime
push("sleep")
pull("sleep")
end
end
local function getRandomData(bytes)
local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
local result = {}
for i=1,bytes do
insert(result, random(0,255))
if i % 10240 == 0 then sleep() end
end
return result
end
local function getRandomString(bytes)
local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
local result = {}
for i=1,bytes do
insert(result, char(random(0,255)))
if i % 10240 == 0 then sleep() end
end
return table.concat(result)
end
return {
byteParity = byteParity,
getByte = getByte,
putByte = putByte,
bytesToInts = bytesToInts,
intsToBytes = intsToBytes,
bytesToHex = bytesToHex,
hexToBytes = hexToBytes,
toHexString = toHexString,
padByteString = padByteString,
properlyDecrypted = properlyDecrypted,
unpadByteString = unpadByteString,
xorIV = xorIV,
increment = increment,
sleepCheckIn = sleepCheckIn,
getRandomData = getRandomData,
getRandomString = getRandomString,
}
end)
local aes=_W(function(_ENV, ...)
-- Implementation of AES with nearly pure lua
-- AES with lua is slow, really slow :-)
local putByte = util.putByte
local getByte = util.getByte
-- some constants
local ROUNDS = 'rounds'
local KEY_TYPE = "type"
local ENCRYPTION_KEY=1
local DECRYPTION_KEY=2
-- aes SBOX
local SBox = {}
local iSBox = {}
-- aes tables
local table0 = {}
local table1 = {}
local table2 = {}
local table3 = {}
local tableInv0 = {}
local tableInv1 = {}
local tableInv2 = {}
local tableInv3 = {}
-- round constants
local rCon = {
0x01000000,
0x02000000,
0x04000000,
0x08000000,
0x10000000,
0x20000000,
0x40000000,
0x80000000,
0x1b000000,
0x36000000,
0x6c000000,
0xd8000000,
0xab000000,
0x4d000000,
0x9a000000,
0x2f000000,
}
--
-- affine transformation for calculating the S-Box of AES
--
local function affinMap(byte)
local mask = 0xf8
local result = 0
for i = 1,8 do
result = bit.lshift(result,1)
local parity = util.byteParity(bit.band(byte,mask))
result = result + parity
-- simulate roll
local lastbit = bit.band(mask, 1)
mask = bit.band(bit.rshift(mask, 1),0xff)
if (lastbit ~= 0) then
mask = bit.bor(mask, 0x80)
else
mask = bit.band(mask, 0x7f)
end
end
return bit.bxor(result, 0x63)
end
--
-- calculate S-Box and inverse S-Box of AES
-- apply affine transformation to inverse in finite field 2^8
--
local function calcSBox()
for i = 0, 255 do
local inverse
if (i ~= 0) then
inverse = gf.invert(i)
else
inverse = i
end
local mapped = affinMap(inverse)
SBox[i] = mapped
iSBox[mapped] = i
end
end
--
-- Calculate round tables
-- round tables are used to calculate shiftRow, MixColumn and SubBytes
-- with 4 table lookups and 4 xor operations.
--
local function calcRoundTables()
for x = 0,255 do
local byte = SBox[x]
table0[x] = putByte(gf.mul(0x03, byte), 0)
+ putByte( byte , 1)
+ putByte( byte , 2)
+ putByte(gf.mul(0x02, byte), 3)
table1[x] = putByte( byte , 0)
+ putByte( byte , 1)
+ putByte(gf.mul(0x02, byte), 2)
+ putByte(gf.mul(0x03, byte), 3)
table2[x] = putByte( byte , 0)
+ putByte(gf.mul(0x02, byte), 1)
+ putByte(gf.mul(0x03, byte), 2)
+ putByte( byte , 3)
table3[x] = putByte(gf.mul(0x02, byte), 0)
+ putByte(gf.mul(0x03, byte), 1)
+ putByte( byte , 2)
+ putByte( byte , 3)
end
end
--
-- Calculate inverse round tables
-- does the inverse of the normal roundtables for the equivalent
-- decryption algorithm.
--
local function calcInvRoundTables()
for x = 0,255 do
local byte = iSBox[x]
tableInv0[x] = putByte(gf.mul(0x0b, byte), 0)
+ putByte(gf.mul(0x0d, byte), 1)
+ putByte(gf.mul(0x09, byte), 2)
+ putByte(gf.mul(0x0e, byte), 3)
tableInv1[x] = putByte(gf.mul(0x0d, byte), 0)
+ putByte(gf.mul(0x09, byte), 1)
+ putByte(gf.mul(0x0e, byte), 2)
+ putByte(gf.mul(0x0b, byte), 3)
tableInv2[x] = putByte(gf.mul(0x09, byte), 0)
+ putByte(gf.mul(0x0e, byte), 1)
+ putByte(gf.mul(0x0b, byte), 2)
+ putByte(gf.mul(0x0d, byte), 3)
tableInv3[x] = putByte(gf.mul(0x0e, byte), 0)
+ putByte(gf.mul(0x0b, byte), 1)
+ putByte(gf.mul(0x0d, byte), 2)
+ putByte(gf.mul(0x09, byte), 3)
end
end
--
-- rotate word: 0xaabbccdd gets 0xbbccddaa
-- used for key schedule
--
local function rotWord(word)
local tmp = bit.band(word,0xff000000)
return (bit.lshift(word,8) + bit.rshift(tmp,24))
end
--
-- replace all bytes in a word with the SBox.
-- used for key schedule
--
local function subWord(word)
return putByte(SBox[getByte(word,0)],0)
+ putByte(SBox[getByte(word,1)],1)
+ putByte(SBox[getByte(word,2)],2)
+ putByte(SBox[getByte(word,3)],3)
end
--
-- generate key schedule for aes encryption
--
-- returns table with all round keys and
-- the necessary number of rounds saved in [ROUNDS]
--
local function expandEncryptionKey(key)
local keySchedule = {}
local keyWords = math.floor(#key / 4)
if ((keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8) or (keyWords * 4 ~= #key)) then
error("Invalid key size: " .. tostring(keyWords))
return nil
end
keySchedule[ROUNDS] = keyWords + 6
keySchedule[KEY_TYPE] = ENCRYPTION_KEY
for i = 0,keyWords - 1 do
keySchedule[i] = putByte(key[i*4+1], 3)
+ putByte(key[i*4+2], 2)
+ putByte(key[i*4+3], 1)
+ putByte(key[i*4+4], 0)
end
for i = keyWords, (keySchedule[ROUNDS] + 1)*4 - 1 do
local tmp = keySchedule[i-1]
if ( i % keyWords == 0) then
tmp = rotWord(tmp)
tmp = subWord(tmp)
local index = math.floor(i/keyWords)
tmp = bit.bxor(tmp,rCon[index])
elseif (keyWords > 6 and i % keyWords == 4) then
tmp = subWord(tmp)
end
keySchedule[i] = bit.bxor(keySchedule[(i-keyWords)],tmp)
end
return keySchedule
end
--
-- Inverse mix column
-- used for key schedule of decryption key
--
local function invMixColumnOld(word)
local b0 = getByte(word,3)
local b1 = getByte(word,2)
local b2 = getByte(word,1)
local b3 = getByte(word,0)
return putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b1),
gf.mul(0x0d, b2)),
gf.mul(0x09, b3)),
gf.mul(0x0e, b0)),3)
+ putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b2),
gf.mul(0x0d, b3)),
gf.mul(0x09, b0)),
gf.mul(0x0e, b1)),2)
+ putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b3),
gf.mul(0x0d, b0)),
gf.mul(0x09, b1)),
gf.mul(0x0e, b2)),1)
+ putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b0),
gf.mul(0x0d, b1)),
gf.mul(0x09, b2)),
gf.mul(0x0e, b3)),0)
end
--
-- Optimized inverse mix column
-- look at http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
-- TODO: make it work
--
local function invMixColumn(word)
local b0 = getByte(word,3)
local b1 = getByte(word,2)
local b2 = getByte(word,1)
local b3 = getByte(word,0)
local t = bit.bxor(b3,b2)
local u = bit.bxor(b1,b0)
local v = bit.bxor(t,u)
v = bit.bxor(v,gf.mul(0x08,v))
local w = bit.bxor(v,gf.mul(0x04, bit.bxor(b2,b0)))
v = bit.bxor(v,gf.mul(0x04, bit.bxor(b3,b1)))
return putByte( bit.bxor(bit.bxor(b3,v), gf.mul(0x02, bit.bxor(b0,b3))), 0)
+ putByte( bit.bxor(bit.bxor(b2,w), gf.mul(0x02, t )), 1)
+ putByte( bit.bxor(bit.bxor(b1,v), gf.mul(0x02, bit.bxor(b0,b3))), 2)
+ putByte( bit.bxor(bit.bxor(b0,w), gf.mul(0x02, u )), 3)
end
--
-- generate key schedule for aes decryption
--
-- uses key schedule for aes encryption and transforms each
-- key by inverse mix column.
--
local function expandDecryptionKey(key)
local keySchedule = expandEncryptionKey(key)
if (keySchedule == nil) then
return nil
end
keySchedule[KEY_TYPE] = DECRYPTION_KEY
for i = 4, (keySchedule[ROUNDS] + 1)*4 - 5 do
keySchedule[i] = invMixColumnOld(keySchedule[i])
end
return keySchedule
end
--
-- xor round key to state
--
local function addRoundKey(state, key, round)
for i = 0, 3 do
state[i + 1] = bit.bxor(state[i + 1], key[round*4+i])
end
end
--
-- do encryption round (ShiftRow, SubBytes, MixColumn together)
--
local function doRound(origState, dstState)
dstState[1] = bit.bxor(bit.bxor(bit.bxor(
table0[getByte(origState[1],3)],
table1[getByte(origState[2],2)]),
table2[getByte(origState[3],1)]),
table3[getByte(origState[4],0)])
dstState[2] = bit.bxor(bit.bxor(bit.bxor(
table0[getByte(origState[2],3)],
table1[getByte(origState[3],2)]),
table2[getByte(origState[4],1)]),
table3[getByte(origState[1],0)])
dstState[3] = bit.bxor(bit.bxor(bit.bxor(
table0[getByte(origState[3],3)],
table1[getByte(origState[4],2)]),
table2[getByte(origState[1],1)]),
table3[getByte(origState[2],0)])
dstState[4] = bit.bxor(bit.bxor(bit.bxor(
table0[getByte(origState[4],3)],
table1[getByte(origState[1],2)]),
table2[getByte(origState[2],1)]),
table3[getByte(origState[3],0)])
end
--
-- do last encryption round (ShiftRow and SubBytes)
--
local function doLastRound(origState, dstState)
dstState[1] = putByte(SBox[getByte(origState[1],3)], 3)
+ putByte(SBox[getByte(origState[2],2)], 2)
+ putByte(SBox[getByte(origState[3],1)], 1)
+ putByte(SBox[getByte(origState[4],0)], 0)
dstState[2] = putByte(SBox[getByte(origState[2],3)], 3)
+ putByte(SBox[getByte(origState[3],2)], 2)
+ putByte(SBox[getByte(origState[4],1)], 1)
+ putByte(SBox[getByte(origState[1],0)], 0)
dstState[3] = putByte(SBox[getByte(origState[3],3)], 3)
+ putByte(SBox[getByte(origState[4],2)], 2)
+ putByte(SBox[getByte(origState[1],1)], 1)
+ putByte(SBox[getByte(origState[2],0)], 0)
dstState[4] = putByte(SBox[getByte(origState[4],3)], 3)
+ putByte(SBox[getByte(origState[1],2)], 2)
+ putByte(SBox[getByte(origState[2],1)], 1)
+ putByte(SBox[getByte(origState[3],0)], 0)
end
--
-- do decryption round
--
local function doInvRound(origState, dstState)
dstState[1] = bit.bxor(bit.bxor(bit.bxor(
tableInv0[getByte(origState[1],3)],
tableInv1[getByte(origState[4],2)]),
tableInv2[getByte(origState[3],1)]),
tableInv3[getByte(origState[2],0)])
dstState[2] = bit.bxor(bit.bxor(bit.bxor(
tableInv0[getByte(origState[2],3)],
tableInv1[getByte(origState[1],2)]),
tableInv2[getByte(origState[4],1)]),
tableInv3[getByte(origState[3],0)])
dstState[3] = bit.bxor(bit.bxor(bit.bxor(
tableInv0[getByte(origState[3],3)],
tableInv1[getByte(origState[2],2)]),
tableInv2[getByte(origState[1],1)]),
tableInv3[getByte(origState[4],0)])
dstState[4] = bit.bxor(bit.bxor(bit.bxor(
tableInv0[getByte(origState[4],3)],
tableInv1[getByte(origState[3],2)]),
tableInv2[getByte(origState[2],1)]),
tableInv3[getByte(origState[1],0)])
end
--
-- do last decryption round
--
local function doInvLastRound(origState, dstState)
dstState[1] = putByte(iSBox[getByte(origState[1],3)], 3)
+ putByte(iSBox[getByte(origState[4],2)], 2)
+ putByte(iSBox[getByte(origState[3],1)], 1)
+ putByte(iSBox[getByte(origState[2],0)], 0)
dstState[2] = putByte(iSBox[getByte(origState[2],3)], 3)
+ putByte(iSBox[getByte(origState[1],2)], 2)
+ putByte(iSBox[getByte(origState[4],1)], 1)
+ putByte(iSBox[getByte(origState[3],0)], 0)
dstState[3] = putByte(iSBox[getByte(origState[3],3)], 3)
+ putByte(iSBox[getByte(origState[2],2)], 2)
+ putByte(iSBox[getByte(origState[1],1)], 1)
+ putByte(iSBox[getByte(origState[4],0)], 0)
dstState[4] = putByte(iSBox[getByte(origState[4],3)], 3)
+ putByte(iSBox[getByte(origState[3],2)], 2)
+ putByte(iSBox[getByte(origState[2],1)], 1)
+ putByte(iSBox[getByte(origState[1],0)], 0)
end
--
-- encrypts 16 Bytes
-- key encryption key schedule
-- input array with input data
-- inputOffset start index for input
-- output array for encrypted data
-- outputOffset start index for output
--
local function encrypt(key, input, inputOffset, output, outputOffset)
--default parameters
inputOffset = inputOffset or 1
output = output or {}
outputOffset = outputOffset or 1
local state = {}
local tmpState = {}
if (key[KEY_TYPE] ~= ENCRYPTION_KEY) then
error("No encryption key: " .. tostring(key[KEY_TYPE]) .. ", expected " .. ENCRYPTION_KEY)
return
end
state = util.bytesToInts(input, inputOffset, 4)
addRoundKey(state, key, 0)
local round = 1
while (round < key[ROUNDS] - 1) do
-- do a double round to save temporary assignments
doRound(state, tmpState)
addRoundKey(tmpState, key, round)
round = round + 1
doRound(tmpState, state)
addRoundKey(state, key, round)
round = round + 1
end
doRound(state, tmpState)
addRoundKey(tmpState, key, round)
round = round +1
doLastRound(tmpState, state)
addRoundKey(state, key, round)
util.sleepCheckIn()
return util.intsToBytes(state, output, outputOffset)
end
--
-- decrypt 16 bytes
-- key decryption key schedule
-- input array with input data
-- inputOffset start index for input
-- output array for decrypted data
-- outputOffset start index for output
---
local function decrypt(key, input, inputOffset, output, outputOffset)
-- default arguments
inputOffset = inputOffset or 1
output = output or {}
outputOffset = outputOffset or 1
local state = {}
local tmpState = {}
if (key[KEY_TYPE] ~= DECRYPTION_KEY) then
error("No decryption key: " .. tostring(key[KEY_TYPE]))
return
end
state = util.bytesToInts(input, inputOffset, 4)
addRoundKey(state, key, key[ROUNDS])
local round = key[ROUNDS] - 1
while (round > 2) do
-- do a double round to save temporary assignments
doInvRound(state, tmpState)
addRoundKey(tmpState, key, round)
round = round - 1
doInvRound(tmpState, state)
addRoundKey(state, key, round)
round = round - 1
end
doInvRound(state, tmpState)
addRoundKey(tmpState, key, round)
round = round - 1
doInvLastRound(tmpState, state)
addRoundKey(state, key, round)
util.sleepCheckIn()
return util.intsToBytes(state, output, outputOffset)
end
-- calculate all tables when loading this file
calcSBox()
calcRoundTables()
calcInvRoundTables()
return {
ROUNDS = ROUNDS,
KEY_TYPE = KEY_TYPE,
ENCRYPTION_KEY = ENCRYPTION_KEY,
DECRYPTION_KEY = DECRYPTION_KEY,
expandEncryptionKey = expandEncryptionKey,
expandDecryptionKey = expandDecryptionKey,
encrypt = encrypt,
decrypt = decrypt,
}
end)
local buffer=_W(function(_ENV, ...)
local function new ()
return {}
end
local function addString (stack, s)
table.insert(stack, s)
end
local function toString (stack)
return table.concat(stack)
end
return {
new = new,
addString = addString,
toString = toString,
}
end)
local ciphermode=_W(function(_ENV, ...)
local public = {}
--
-- Encrypt strings
-- key - byte array with key
-- string - string to encrypt
-- modefunction - function for cipher mode to use
--
local random = math.random
function public.encryptString(key, data, modeFunction, iv)
if iv then
local ivCopy = {}
for i = 1, 16 do ivCopy[i] = iv[i] end
iv = ivCopy
else
iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
end
local keySched = aes.expandEncryptionKey(key)
local encryptedData = buffer.new()
for i = 1, #data/16 do
local offset = (i-1)*16 + 1
local byteData = {string.byte(data,offset,offset +15)}
iv = modeFunction(keySched, byteData, iv)
buffer.addString(encryptedData, string.char(unpack(byteData)))
end
return buffer.toString(encryptedData)
end
--
-- the following 4 functions can be used as
-- modefunction for encryptString
--
-- Electronic code book mode encrypt function
function public.encryptECB(keySched, byteData, iv)
aes.encrypt(keySched, byteData, 1, byteData, 1)
end
-- Cipher block chaining mode encrypt function
function public.encryptCBC(keySched, byteData, iv)
util.xorIV(byteData, iv)
aes.encrypt(keySched, byteData, 1, byteData, 1)
return byteData
end
-- Output feedback mode encrypt function
function public.encryptOFB(keySched, byteData, iv)
aes.encrypt(keySched, iv, 1, iv, 1)
util.xorIV(byteData, iv)
return iv
end
-- Cipher feedback mode encrypt function
function public.encryptCFB(keySched, byteData, iv)
aes.encrypt(keySched, iv, 1, iv, 1)
util.xorIV(byteData, iv)
return byteData
end
function public.encryptCTR(keySched, byteData, iv)
local nextIV = {}
for j = 1, 16 do nextIV[j] = iv[j] end
aes.encrypt(keySched, iv, 1, iv, 1)
util.xorIV(byteData, iv)
util.increment(nextIV)
return nextIV
end
--
-- Decrypt strings
-- key - byte array with key
-- string - string to decrypt
-- modefunction - function for cipher mode to use
--
function public.decryptString(key, data, modeFunction, iv)
if iv then
local ivCopy = {}
for i = 1, 16 do ivCopy[i] = iv[i] end
iv = ivCopy
else
iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
end
local keySched
if modeFunction == public.decryptOFB or modeFunction == public.decryptCFB or modeFunction == public.decryptCTR then
keySched = aes.expandEncryptionKey(key)
else
keySched = aes.expandDecryptionKey(key)
end
local decryptedData = buffer.new()
for i = 1, #data/16 do
local offset = (i-1)*16 + 1
local byteData = {string.byte(data,offset,offset +15)}
iv = modeFunction(keySched, byteData, iv)
buffer.addString(decryptedData, string.char(unpack(byteData)))
end
return buffer.toString(decryptedData)
end
--
-- the following 4 functions can be used as
-- modefunction for decryptString
--
-- Electronic code book mode decrypt function
function public.decryptECB(keySched, byteData, iv)
aes.decrypt(keySched, byteData, 1, byteData, 1)
return iv
end
-- Cipher block chaining mode decrypt function
function public.decryptCBC(keySched, byteData, iv)
local nextIV = {}
for j = 1, 16 do nextIV[j] = byteData[j] end
aes.decrypt(keySched, byteData, 1, byteData, 1)
util.xorIV(byteData, iv)
return nextIV
end
-- Output feedback mode decrypt function
function public.decryptOFB(keySched, byteData, iv)
aes.encrypt(keySched, iv, 1, iv, 1)
util.xorIV(byteData, iv)
return iv
end
-- Cipher feedback mode decrypt function
function public.decryptCFB(keySched, byteData, iv)
local nextIV = {}
for j = 1, 16 do nextIV[j] = byteData[j] end
aes.encrypt(keySched, iv, 1, iv, 1)
util.xorIV(byteData, iv)
return nextIV
end
public.decryptCTR = public.encryptCTR
return public
end)
-- Simple API for encrypting strings.
--
local M = {
AES128 = 16,
AES192 = 24,
AES256 = 32,
ECBMODE = 1,
CBCMODE = 2,
OFBMODE = 3,
CFBMODE = 4,
CTRMODE = 4,
}
local function pwToKey(password, keyLength, iv)
local padLength = keyLength
if (keyLength == M.AES192) then
padLength = 32
end
if (padLength > #password) then
local postfix = ""
for i = 1,padLength - #password do
postfix = postfix .. string.char(0)
end
password = password .. postfix
else
password = string.sub(password, 1, padLength)
end
local pwBytes = {string.byte(password,1,#password)}
password = ciphermode.encryptString(pwBytes, password, ciphermode.encryptCBC, iv)
password = string.sub(password, 1, keyLength)
return {string.byte(password,1,#password)}
end
--
-- Encrypts string data with password password.
-- password - the encryption key is generated from this string
-- data - string to encrypt (must not be too large)
-- keyLength - length of aes key: 128(default), 192 or 256 Bit
-- mode - mode of encryption: ecb, cbc(default), ofb, cfb
--
-- mode and keyLength must be the same for encryption and decryption.
--
function M.encrypt(password, data, keyLength, mode, iv, isKey)
assert(password ~= nil, "Empty password.")
assert(password ~= nil, "Empty data.")
local mode = mode or M.CBCMODE
local keyLength = keyLength or M.AES128
local key = isKey and {password:byte(1, keyLength)} or pwToKey(password, keyLength, iv)
local paddedData = util.padByteString(data)
if mode == M.ECBMODE then
return ciphermode.encryptString(key, paddedData, ciphermode.encryptECB, iv)
elseif mode == M.CBCMODE then
return ciphermode.encryptString(key, paddedData, ciphermode.encryptCBC, iv)
elseif mode == M.OFBMODE then
return ciphermode.encryptString(key, paddedData, ciphermode.encryptOFB, iv)
elseif mode == M.CFBMODE then
return ciphermode.encryptString(key, paddedData, ciphermode.encryptCFB, iv)
elseif mode == M.CTRMODE then
return ciphermode.encryptString(key, paddedData, ciphermode.encryptCTR, iv)
else
error("Unknown mode", 2)
end
end
--
-- Decrypts string data with password password.
-- password - the decryption key is generated from this string
-- data - string to encrypt
-- keyLength - length of aes key: 128(default), 192 or 256 Bit
-- mode - mode of decryption: ecb, cbc(default), ofb, cfb
--
-- mode and keyLength must be the same for encryption and decryption.
--
function M.decrypt(password, data, keyLength, mode, iv, isKey)
local mode = mode or M.CBCMODE
local keyLength = keyLength or M.AES128
local key = isKey and {password:byte(1, keyLength)} or pwToKey(password, keyLength, iv)
local plain
if mode == M.ECBMODE then
plain = ciphermode.decryptString(key, data, ciphermode.decryptECB, iv)
elseif mode == M.CBCMODE then
plain = ciphermode.decryptString(key, data, ciphermode.decryptCBC, iv)
elseif mode == M.OFBMODE then
plain = ciphermode.decryptString(key, data, ciphermode.decryptOFB, iv)
elseif mode == M.CFBMODE then
plain = ciphermode.decryptString(key, data, ciphermode.decryptCFB, iv)
elseif mode == M.CTRMODE then
plain = ciphermode.decryptString(key, data, ciphermode.decryptCTR, iv)
else
error("Unknown mode", 2)
end
return util.unpadByteString(plain)
end
return M
@omnituensaeternum
Copy link

Broken does not work on CC restitched

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment