Message
Message
native
--!optimize 2
task.spawn(function(...)
repeat wait() until game:IsLoaded()
local proxiedServices = {
LinkingService = {{
"OpenUrl"
}, game:GetService("LinkingService")},
ScriptContext = {{
"SaveScriptProfilingData",
"AddCoreScriptLocal",
"ScriptProfilerService"
}, game:GetService("ScriptContext")},
--[[
MessageBusService = {{
"Call",
"GetLast",
"GetMessageId",
"GetProtocolMethodRequestMessageId",
"GetProtocolMethodResponseMessageId",
"MakeRequest",
"Publish",
"PublishProtocolMethodRequest",
"PublishProtocolMethodResponse",
"Subscribe",
"SubscribeToProtocolMethodRequest",
"SubscribeToProtocolMethodResponse"
}, game:GetService("MessageBusService")},
GuiService = {{
"OpenBrowserWindow",
"OpenNativeOverlay"
}, game:GetService("GuiService")},
MarketplaceService = {{
"GetRobuxBalance",
"PerformPurchase",
"PerformPurchaseV2",
}, game:GetService("MarketplaceService")},
HttpRbxApiService = {{
"GetAsyncFullUrl",
"PostAsyncFullUrl",
"GetAsync",
"PostAsync",
"RequestAsync"
}, game:GetService("HttpRbxApiService")},
CoreGui = {{
"TakeScreenshot",
"ToggleRecording"
}, game:GetService("CoreGui")},
Players = {{
"ReportAbuse",
"ReportAbuseV3"
}, game:GetService("Players")},
HttpService = {{
"RequestInternal"
}, game:GetService("HttpService")},
BrowserService = {{
"ExecuteJavaScript",
"OpenBrowserWindow",
"ReturnToJavaScript",
"OpenUrl",
"SendCommand",
"OpenNativeOverlay"
}, game:GetService("BrowserService")},
CaptureService = {{
"DeleteCapture"
}, game:GetService("CaptureService")},
OmniRecommendationsService = {{
"MakeRequest"
}, game:GetService("OmniRecommendationsService")},
OpenCloudService = {{
"HttpRequestAsync"
}, game:GetService("OpenCloudService")}
]]
}
local ENV = {}
local rs = game:GetService("RunService")
local players = game:GetService("Players")
local _fetch_stubmodule do
local current_module = 1
local modules_list = {}
local in_use_modules = {}
for _, obj in
game:FindService("CoreGui").RobloxGui.Modules:GetDescendants() do
if not obj:IsA("ModuleScript") then
if obj.Name:match("AvatarExperience")
then
for _, o in obj:GetDescendants() do
if o.Name == "Flags" or o.Name == "Test" then
for _, oa in o:GetDescendants() do
if not oa:IsA("ModuleScript") then
continue end
table.insert(modules_list,
oa:Clone())
end
end
end
else
if
obj.Name:match("ReportAnything")
or obj.Name:match("TestHelpers")
then
for _, o in obj:GetDescendants() do
if not o:IsA("ModuleScript") then
continue end
table.insert(modules_list, o:Clone())
end
end
end
continue
end
end
function _fetch_stubmodule()
local idx = find_new_module()
in_use_modules[current_module] = nil
current_module = idx
in_use_modules[current_module] = true
return modules_list[idx]
end
function Length(Table)
local counter = 0
for _, v in pairs(Table) do
counter =counter + 1
end
return counter
end
end
setaddressholder.Name = "setaddressholder"
setaddressholder.Parent = game.CoreGui
setaddressholder_bool.Name = "setaddressholder_bool"
setaddressholder_bool.Parent = game.CoreGui
local mt = {
__newindex = function(t, key, value)
rawset(t, key, value)
_G[key] = value
rawset(getfenv(), key, value)
end,
__index = function(t, key)
local resp = rawget(_G, key)
if resp == nil then
return false
end
return resp
end
}
setmetatable(ENV, mt)
function getgenv()
return ENV
end
getgenv().getrenv = function()
return renv
end
-- objects
local hidden_ui_container = Instance.new("Folder")
hidden_ui_container.Name = "\0nx-hui"
hidden_ui_container.RobloxLocked = true
hidden_ui_container.Parent =
game:FindService("CoreGui"):FindFirstChild("RobloxGui")
-- variables
instances_reg = setmetatable({ [game] = true }, { __mode = "ks" })
touchers_reg = setmetatable({}, { __mode = "ks" })
-- functions
local _loaded_saveinstance
-- init
game.DescendantAdded:Connect(addToInstancesReg)
game.DescendantRemoving:Connect(addToInstancesReg)
-- main
function getinstances()
return filterAllInstances(function()
return true
end)
end
function getnilinstances()
return filterAllInstances(function(instance)
return instance.Parent == nil
end)
end
function getscripts()
return filterAllInstances(function(instance)
return instance:IsA("LocalScript") or
instance:IsA("ModuleScript")
end)
end
function getsenv(src)
if scr == nil then return getfenv() end
return filterAllInstances(function(instance)
if type(instance) == "function" and getfenv(instance).script ==
scr then
return getfenv(instance)
end
end)
end
getrunningscripts = getscripts
function getmodules()
return filterAllInstances(function(instance)
return instance:IsA("ModuleScript")
end)
end
getloadedmodules = getmodules
getrunningmodules = getmodules
function gethui()
return hidden_ui_container
end
local hb
hb = game:GetService("RunService").Heartbeat:Connect(function()
tmpPart.CFrame = workspace.Camera.CFrame
* CFrame.new(0, 0, -20)
* CFrame.new(
workspace.Camera.CFrame.LookVector.X,
workspace.Camera.CFrame.LookVector.Y,
workspace.Camera.CFrame.LookVector.Z
)
game:GetService("VirtualUser")
:ClickButton1(Vector2.new(20, 20),
workspace:FindFirstChildOfClass("Camera").CFrame)
end)
clickdetector.MouseClick:Once(function()
hb:Disconnect()
clickdetector.MaxActivationDistance = oldCDMaxActivationDistance
clickdetector.Parent = oldCDParent
tmpPart:Destroy()
end)
end
proximityprompt.MaxActivationDistance = 9e9
proximityprompt:InputHoldBegin()
for i = 1, amount or 1 do
if skip then
proximityprompt.HoldDuration = 0
else
task.wait(proximityprompt.HoldDuration + 0.01)
end
end
proximityprompt:InputHoldEnd()
proximityprompt.MaxActivationDistance = oldMaxDistance
proximityprompt.HoldDuration = oldHoldDuration
end
local Bridge = {
main_container = Instance.new("Folder"),
module_holder = Instance.new("ObjectValue"),
executing_script = nil,
channels_container = Instance.new("Folder"),
sessions = {},
queued_datas = {},
recieved_actions_list = {},
action_callbacks = {},
}
Bridge.module_holder.Name = "ModuleHolder"
Bridge.module_holder.Parent = Bridge.main_container
Bridge.channels_container.Name = "Channels"
Bridge.channels_container.Parent = Bridge.main_container
Bridge.main_container.Name = "Bridge"
Bridge.main_container.Parent = bridge_parent
bridge.main_container = Instance.new("Folder")
bridge.module_holder = Instance.new("ObjectValue")
bridge.loadstring_holder = Instance.new("ObjectValue")
bridge.execution = Instance.new("BoolValue")
bridge.players = Instance.new("StringValue")
bridge.executing_script = nil
bridge.loadstring_script = nil
bridge.main_container.Name = "Bridge"
bridge.main_container.Parent = game:FindService("CoreGui")
--[[
if script.Name == "LuaSocialLibrariesDeps" or script.Name ==
"PolicyService" then
bridge.main_container.Parent =
game:FindService("CoreGui").RobloxGui.Modules.CoreUtility
else
bridge.main_container.Parent = game:FindService("CoreGui")
end
]]
bridge.execution.Name = "Execution"
bridge.execution.Parent = bridge.main_container
bridge.players.Name = "LunaPlayers"
bridge.players.Parent = bridge.main_container
bridge.players.Value = players.LocalPlayer.Name
bridge.module_holder.Name = "ModuleHolder"
bridge.module_holder.Parent = bridge.main_container
bridge.loadstring_holder.Name = "LoadstringHolder"
bridge.loadstring_holder.Parent = bridge.main_container
bridge.executing_script = fetch_stubmodule():Clone()
bridge.module_holder.Value = bridge.executing_script
bridge.loadstring_script = fetch_stubmodule():Clone()
bridge.loadstring_holder.Value = bridge.loadstring_script
request:Start(function(success, result)
if success then
response = result
else
response = {}
end
end)
end)
if not success then
return "ERROR: " .. tostring(res)
else
return res
end
end
data.Headers = heads
data.Headers["Roblox-Place-Id"] = tostring(game.PlaceId)
data.Headers["Roblox-Game-Id"] = tostring(game.JobId)
data.Headers["Roblox-Session-Id"] = HttpService:JSONEncode({
["GameId"] = tostring(game.JobId),
["PlaceId"] = tostring(game.PlaceId)
})
if from then
data.Headers["User-Agent"] = "Roblox/WinInet"
end
request:Start(function(success, result)
--print(success, result)
if success then
response = result
else
response = {}
end
end)
return HttpService:JSONDecode(response.Body)
end)
if not success then
return "ERROR: " .. tostring(res)
else
return res
end
end
function bridge:json(response)
local success, res = pcall(function()
return HttpService:JSONDecode(response.Body)
end)
return res
end
local params = {
Url = url,
Method = "GET",
Headers = {
["Content-Type"] = "application/json",
}
}
request:Start(function(success, result)
if success then
response = result
else
response = {}
end
end)
return HttpService:JSONDecode(tostring(response.Body))
end)
if not success then
return "ERROR: " .. tostring(res)
else
return res
end
end
function getobjects(assetid)
if type(assetid) == "number" then
assetid = "rbxassetid://" .. assetid
end
return { game:GetService("InsertService"):LoadLocalAsset(assetid) }
end
local httpContentTypeToHeader
do
-- * Keep this updated https://github.com/MaximumADHD/Roblox-Client-
Tracker/blob/roblox/LuaPackages/Packages/_Index/HttpServiceMock/HttpServiceMock/
httpContentTypeToHeader.lua
-- *
https://create.roblox.com/docs/reference/engine/enums/HttpContentType
local httpContentTypeToHeaderLookup = {
[Enum.HttpContentType.ApplicationJson] = "application/json",
[Enum.HttpContentType.ApplicationUrlEncoded] = "application/x-
www-form-urlencoded",
[Enum.HttpContentType.ApplicationXml] = "application/xml",
[Enum.HttpContentType.TextPlain] = "text/plain",
[Enum.HttpContentType.TextXml] = "text/xml",
}
httpContentTypeToHeader = function(httpContentType:
Enum.HttpContentType): string
local value = httpContentTypeToHeaderLookup[httpContentType]
assert(value, "Unable to map Enum.HttpContentType to Content-
Type. Use a Content-Type string instead")
return value
end
end
proxyMt.__tostring = function(self)
return serviceTable[2].Name
end
proxyMt.__metatable = getmetatable(serviceTable[2])
end
local real = {}
--[[
local WRAPPED = setmetatable({}, { __mode = "k" })
local REAL_OBJECT = setmetatable({}, { __mode = "k" })
local oldInstanceNew = Instance.new
local TS = game:GetService("TweenService")
local oldCreate = TS.Create
local SpecialHooks = {
HttpGet = function(url, arg2, arg3)
assert(type(url) == "string", "arg #1 must be type string")
assert(url ~= "", "arg #1 cannot be empty")
local args = {
Method = "GET",
Url = url,
}
local args = {
Method = "POST",
Url = url,
Body = data,
}
if type(arg3) == "boolean" then
arg3, arg4, arg5 = arg4, arg5, nil
end
if arg5 then
args.Headers = arg3
end
if arg3 then
args.Headers = args.Headers or {}
args.Headers["Content-Type"] =
(type(arg3) == "string")
and arg3
or httpContentTypeToHeader(arg3)
end
if typeof(arg4) == "boolean" and arg4 then
args.Headers = args.Headers or {}
args.Headers["Content-Encoding"] = "gzip"
end
GetObjects = function(assetid)
return getobjects(assetid)
end,
SpecialHooks.HttpGetAsync = SpecialHooks.HttpGet
SpecialHooks.HttpPostAsync = SpecialHooks.HttpPost
WRAPPED[obj] = proxy
REAL_OBJECT[proxy] = obj
if find({
"Load",
"OpenScreenshotsFolder",
"OpenVideosFolder"
}, index) then
error("Attempt to call a blocked function: " ..
tostring(index), 2)
end
for i = 1, #results do
results[i] = unwrapIfProxy(results[i])
end
return table.unpack(results)
return rawValue
end
meta.__tostring = function()
return tostring(REAL_OBJECT[proxy])
end
meta.__metatable = getmetatable(REAL_OBJECT[proxy])
return proxy
end
local SpecialHooks = {
HttpGet = function(url, arg2, arg3)
assert(type(url) == "string", "arg #1 must be type string")
assert(url ~= "", "arg #1 cannot be empty")
local args = {
Method = "GET",
Url = url,
}
local args = {
Method = "POST",
Url = url,
Body = data,
}
if type(arg3) == "boolean" then
arg3, arg4, arg5 = arg4, arg5, nil
end
if arg5 then
args.Headers = arg3
end
if arg3 then
args.Headers = args.Headers or {}
args.Headers["Content-Type"] =
(type(arg3) == "string")
and arg3
or httpContentTypeToHeader(arg3)
end
if typeof(arg4) == "boolean" and arg4 then
args.Headers = args.Headers or {}
args.Headers["Content-Encoding"] = "gzip"
end
GetObjects = function(assetid)
return getobjects(assetid)
end,
}
SpecialHooks.HttpGetAsync = SpecialHooks.HttpGet
SpecialHooks.HttpPostAsync = SpecialHooks.HttpPost
getgenv().game = wrapInstance(game)
getgenv().Game = wrapInstance(Game)
function getproperties(instance)
assert(typeof(instance) == "Instance", `arg #1 must be type Instance`)
setaddressholder.Value = instance
return container
end
function gethiddenproperties(instance)
assert(typeof(instance) == "Instance", `arg #1 must be type Instance`)
local hidden_properties = {}
return hidden_properties
end
return gethiddenproperties(instance)[property_name]
end
function iscclosure(func)
assert(type(func) == "function", `arg #1 must be type function`)
return debug.info(func, "s") == "[C]"
end
function islclosure(func)
assert(type(func) == "function", `arg #1 must be type function`)
return debug.info(func, "s") ~= "[C]"
end
function getscripthash(src)
return src:GetHash()
end
return coroutine.wrap(function(...)
local args = { ... }
while true do
args = { coroutine.yield(func(unpack(args))) }
end
end)
end
function newcclosure(func)
assert(type(func) == "function", `arg #1 must be type function`)
return newWrappedCClosure(func)
end
function newlclosure(func)
return function(...)
return func(...)
end
end
function isexecutorclosure(func)
if iscclosure(func) then
return debug.info(func, "n") == "" -- * Hopefully there aren't
any false positives
end
local f_env = getfenv(func)
return f_env.script.Parent == nil or f_env == getfenv(0) -- TODO The
second part can be fooled if isexecutorclosure(HijackedModule.Function)
end
function clonefunction(func)
return if iscclosure(func) then newcclosure(func) else
newlclosure(func)
end
return coroutine.wrap(function(...)
setfenv(0, virtual_env)
setfenv(1, virtual_env)
return func(...)
end)(...)
end
getthread = coroutine.running
checkclosure = isexecutorclosure
isourclosure = isexecutorclosure
coroutine.wrap(function()
while true do
if bridge.execution.Value == true then
while calledexec do
task.wait()
end
script_load.Name = "NX"
script_load.Name = original
bridge.execution.Value = false
calledexec = false
while justcalledlocal do
task.wait()
end
justcalledlocal = true
bridge:post("loadstring", {source=source,type="loadstring"})
justcalledlocal = false
return func
end
end)
function require(moduleScript)
assert(typeof(moduleScript) == "Instance", "Attempted to call require
with invalid argument(s). ", 2)
assert(moduleScript.ClassName == "ModuleScript", "Attempted to call
require with invalid argument(s). ", 2)
objectValue:Destroy()
return _require(moduleScript)
end
identifyexecutor = function()
return "NX", "1.0"
end
getexecutorname = identifyexecutor
http = {}
request = (function(data)
return bridge:request(data)
end)
setclipboard = function(text)
bridge:send("setclipboard", {arg="value",value=text})
end
toclipboard = setclipboard
isreadonly = table.isfrozen
--[[
ADVANCED ENCRYPTION STANDARD (AES)
-- SUBSTITUTION BOXES
local s_box = { 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103,
43, 254, 215, 171, 118, 202,
130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114,
192, 183, 253, 147, 38, 54,
63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35,
195, 24, 150, 5, 154, 7,
18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90,
160, 82, 59, 214, 179, 41,
227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190,
57, 74, 76, 88, 207, 208,
239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159,
168, 81, 163, 64, 143, 146,
157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19,
236, 95, 151, 68, 23, 196,
167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144,
136, 70, 238, 184, 20, 222,
94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172,
98, 145, 149, 228, 121, 231,
200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174,
8, 186, 120, 37, 46, 28,
166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181,
102, 72, 3, 246, 14, 97,
53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142,
148, 155, 30, 135, 233, 206,
85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45,
15, 176, 84, 187, 22}
local inv_s_box = { 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163,
158, 129, 243, 215, 251, 124,
227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233,
203, 84, 123, 148, 50, 166,
194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161,
102, 40, 217, 36, 178, 118,
91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152,
22, 212, 164, 92, 204, 93,
101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70,
87, 167, 141, 157, 132, 144,
216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69,
6, 208, 44, 30, 143, 202,
63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17,
65, 79, 103, 220, 234, 151,
242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53,
133, 226, 249, 55, 232, 28,
117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98,
14, 170, 24, 190, 27, 252,
86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90,
244, 31, 221, 168, 51, 136,
7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127,
169, 25, 181, 74, 13, 45,
229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245,
176, 200, 235, 187, 60, 131,
83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20,
99, 85, 33, 12, 125}
-- TRANSFORMATION FUNCTIONS
local function subBytes (s, inv) -- Processes State using the
S-box
inv = if inv then inv_s_box else s_box
for i = 1, 4 do
for j = 1, 4 do
s[i][j] = inv[s[i][j] + 1]
end
end
end
local function shiftRows (s, inv) -- Processes State by
circularly shifting rows
s[1][3], s[2][3], s[3][3], s[4][3] = s[3][3], s[4][3], s[1][3], s[2][3]
if inv then
s[1][2], s[2][2], s[3][2], s[4][2] = s[4][2], s[1][2], s[2][2],
s[3][2]
s[1][4], s[2][4], s[3][4], s[4][4] = s[2][4], s[3][4], s[4][4],
s[1][4]
else
s[1][2], s[2][2], s[3][2], s[4][2] = s[2][2], s[3][2], s[4][2],
s[1][2]
s[1][4], s[2][4], s[3][4], s[4][4] = s[4][4], s[1][4], s[2][4],
s[3][4]
end
end
local function addRoundKey (s, k) -- Processes Cipher by
adding a round key to the State
for i = 1, 4 do
for j = 1, 4 do
s[i][j] = bit32.bxor(s[i][j], k[i][j])
end
end
end
local function mixColumns (s, inv) -- Processes Cipher by taking
and mixing State columns
local t, u
if inv then
for i = 1, 4 do
t = xtime(xtime(bit32.bxor(s[i][1], s[i][3])))
u = xtime(xtime(bit32.bxor(s[i][2], s[i][4])))
s[i][1], s[i][2] = bit32.bxor(s[i][1], t), bit32.bxor(s[i]
[2], u)
s[i][3], s[i][4] = bit32.bxor(s[i][3], t), bit32.bxor(s[i]
[4], u)
end
end
local i
for j = 1, 4 do
i = s[j]
t, u = bit32.bxor (i[1], i[2], i[3], i[4]), i[1]
for k = 1, 4 do
i[k] = bit32.bxor (i[k], t, xtime(bit32.bxor(i[k], i[k + 1]
or u)))
end
end
end
return t
end
local function xorBytes (t, a, b) -- Returns bitwise XOR of all
their bytes
table.clear (t)
return o, a
end
-- MAIN ALGORITHM
local function expandKey (key) -- Key expansion
local kc = bytesToMatrix(if #key == 16 then {{}, {}, {}, {}} elseif
#key == 24 then {{}, {}, {}, {}
, {}, {}} else {{}, {}, {}, {}, {}, {}, {}, {}}, key)
local is = #key / 4
local i, t, w = 2, {}, nil
table.clear (t)
xorBytes (w, table.move(w, 1, 4, 1, t), kc[#kc - is + 1])
table.insert(kc, w)
end
table.clear (t)
for i = 1, #kc / 4 do
table.insert(t, {})
table.move (kc, i * 4 - 3, i * 4, 1, t[#t])
end
return t
end
local function encrypt (key, km, pt, ps, r) -- Block cipher encryption
bytesToMatrix (ps, pt)
addRoundKey (ps, km[1])
for i = 2, #key / 4 + 6 do
subBytes (ps)
shiftRows (ps)
mixColumns (ps)
addRoundKey (ps, km[i])
end
subBytes (ps)
shiftRows (ps)
addRoundKey (ps, km[#km])
-- INITIALIZATION FUNCTIONS
local function convertType (a) -- Converts data
to bytes if possible
if type(a) == "string" then
local r = {}
local iv = deepCopy(initVector)
local b, k, s, t = {}, {}, {{}, {}, {}, {}}, {}
for i = 1, #plainText, 16 do
table.move(plainText, i, i + 15, 1, k)
table.move(encrypt(key, km, k, s, t), 1, 16, i, b)
end
return b, iv
end,
decrypt_ECB = function(key : bytes, cipherText : bytes, initVector :
bytes?) : bytes
local km
key, cipherText, km = init(key, cipherText, false, initVector)
return b
end,
-- Cipher block chaining (CBC)
encrypt_CBC = function(key : bytes, plainText : bytes, initVector :
bytes?) : bytes
local km
key, plainText, km, initVector = init(key, plainText, false,
initVector)
local iv = deepCopy(initVector)
local b, k, p, s, t = {}, {}, initVector, {{}, {}, {}, {}}, {}
for i = 1, #plainText, 16 do
table.move(plainText, i, i + 15, 1, k)
table.move(encrypt(key, km, xorBytes(t, k, p), s, p), 1,
16, i, b)
end
return b, iv
end,
decrypt_CBC = function(key : bytes, cipherText : bytes, initVector :
bytes?) : bytes
local km
key, cipherText, km, initVector = init(key, cipherText, false,
initVector)
return b
end,
-- Propagating cipher block chaining (PCBC)
encrypt_PCBC = function(key : bytes, plainText : bytes, initVector :
bytes?) : bytes
local km
key, plainText, km, initVector = init(key, plainText, false,
initVector)
local iv = deepCopy(initVector)
local b, k, c, p, s, t = {}, {}, initVector, table.create(16, 0),
{{}, {}, {}, {}}, {}
for i = 1, #plainText, 16 do
table.move(plainText, i, i + 15, 1, k)
table.move(encrypt(key, km, xorBytes(k, xorBytes(t, c, k),
p), s, c), 1, 16, i, b)
table.move(plainText, i, i + 15, 1, p)
end
return b, iv
end,
decrypt_PCBC = function(key : bytes, cipherText : bytes, initVector :
bytes?) : bytes
local km
key, cipherText, km, initVector = init(key, cipherText, false,
initVector)
return b
end,
-- Cipher feedback (CFB)
encrypt_CFB = function(key : bytes, plainText : bytes, initVector :
bytes?, segmentSize : number?)
: bytes
local km
key, plainText, km, initVector, segmentSize = init(key,
plainText, false, initVector,
if segmentSize == nil then 1 else segmentSize)
local iv = deepCopy(initVector)
local b, k, p, q, s, t = {}, {}, initVector, {}, {{}, {}, {},
{}}, {}
for i = 1, #plainText, segmentSize do
table.move(plainText, i, i + segmentSize - 1, 1, k)
table.move(xorBytes(q, encrypt(key, km, p, s, t), k), 1,
segmentSize, i, b)
for j = 16, segmentSize + 1, - 1 do
table.insert(q, 1, p[j])
end
table.move(q, 1, 16, 1, p)
end
return b, iv
end,
decrypt_CFB = function(key : bytes, cipherText : bytes, initVector :
bytes, segmentSize : number?)
: bytes
local km
key, cipherText, km, initVector, segmentSize = init(key,
cipherText, false, initVector,
if segmentSize == nil then 1 else segmentSize)
return b
end,
-- Output feedback (OFB)
encrypt_OFB = function(key : bytes, plainText : bytes, initVector :
bytes?) : bytes
local km
key, plainText, km, initVector = init(key, plainText, false,
initVector)
local iv = deepCopy(initVector)
local b, k, p, s, t = {}, {}, initVector, {{}, {}, {}, {}}, {}
for i = 1, #plainText, 16 do
table.move(plainText, i, i + 15, 1, k)
table.move(encrypt(key, km, p, s, t), 1, 16, 1, p)
table.move(xorBytes(t, k, p), 1, 16, i, b)
end
return b, iv
end,
-- Counter (CTR)
encrypt_CTR = function(key : bytes, plainText : bytes, counter :
((bytes) -> bytes) | bytes | { [
string]: any }?) : bytes
local km
key, plainText, km, counter = init(key, plainText, true, counter)
local iv = deepCopy(counter)
local b, k, c, s, t, r, n = {}, {}, {}, {{}, {}, {}, {}}, {},
type(counter) == "table", nil
for i = 1, #plainText, 16 do
if r then
if i > 1 and incBytes(counter.InitValue,
counter.LittleEndian) then
table.move(counter.InitOverflow, 1, 16, 1,
counter.InitValue)
end
table.clear (c)
table.move (counter.Prefix, 1, #counter.Prefix, 1,
c)
table.move (counter.InitValue, 1, counter.Length, #c
+ 1, c)
table.move (counter.Suffix, 1, #counter.Suffix, #c +
1, c)
else
n = convertType(counter(c, (i + 15) / 16))
assert (#n == 16, "Counter must be 16
bytes long")
table.move (n, 1, 16, 1, c)
end
table.move(plainText, i, i + 15, 1, k)
table.move(xorBytes(c, encrypt(key, km, c, s, t), k), 1,
16, i, b)
end
return b, iv
end
} -- Returns the library
--!native
--!optimize 2
-- Credits @Reselim
local alphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
local padding = string.byte("=")
for index = 1, 64 do
local value = index - 1
local character = string.byte(alphabet, index)
-- Since we use readu32 and chunks are 3 bytes large, we can't read the
last chunk here
for chunkIndex = 1, inputChunks - 1 do
local inputIndex = (chunkIndex - 1) * 3
local outputIndex = (chunkIndex - 1) * 4
-- 8 + 24 - (6 * index)
local value1 = bit32.rshift(chunk, 26)
local value2 = bit32.band(bit32.rshift(chunk, 20), 0b111111)
local value3 = bit32.band(bit32.rshift(chunk, 14), 0b111111)
local value4 = bit32.band(bit32.rshift(chunk, 8), 0b111111)
buffer.writeu8(output, outputIndex,
buffer.readu8(lookupValueToCharacter, value1))
buffer.writeu8(output, outputIndex + 1,
buffer.readu8(lookupValueToCharacter, value2))
buffer.writeu8(output, outputIndex + 2,
buffer.readu8(lookupValueToCharacter, value3))
buffer.writeu8(output, outputIndex + 3,
buffer.readu8(lookupValueToCharacter, value4))
end
if inputRemainder == 1 then
local chunk = buffer.readu8(input, inputLength - 1)
buffer.writeu8(output, outputLength - 4,
buffer.readu8(lookupValueToCharacter, value1))
buffer.writeu8(output, outputLength - 3,
buffer.readu8(lookupValueToCharacter, value2))
buffer.writeu8(output, outputLength - 2, padding)
buffer.writeu8(output, outputLength - 1, padding)
elseif inputRemainder == 2 then
local chunk = bit32.bor(
bit32.lshift(buffer.readu8(input, inputLength - 2), 8),
buffer.readu8(input, inputLength - 1)
)
buffer.writeu8(output, outputLength - 4,
buffer.readu8(lookupValueToCharacter, value1))
buffer.writeu8(output, outputLength - 3,
buffer.readu8(lookupValueToCharacter, value2))
buffer.writeu8(output, outputLength - 2,
buffer.readu8(lookupValueToCharacter, value3))
buffer.writeu8(output, outputLength - 1, padding)
elseif inputRemainder == 0 and inputLength ~= 0 then
local chunk = bit32.bor(
bit32.lshift(buffer.readu8(input, inputLength - 3), 16),
bit32.lshift(buffer.readu8(input, inputLength - 2), 8),
buffer.readu8(input, inputLength - 1)
)
buffer.writeu8(output, outputLength - 4,
buffer.readu8(lookupValueToCharacter, value1))
buffer.writeu8(output, outputLength - 3,
buffer.readu8(lookupValueToCharacter, value2))
buffer.writeu8(output, outputLength - 2,
buffer.readu8(lookupValueToCharacter, value3))
buffer.writeu8(output, outputLength - 1,
buffer.readu8(lookupValueToCharacter, value4))
end
return output
end
if inputLength ~= 0 then
local lastInputIndex = (inputChunks - 1) * 4
local lastOutputIndex = (inputChunks - 1) * 3
if inputPadding == 0 then
local lastCharacter3 = bit32.band(lastChunk,
0b11111111)
buffer.writeu8(output, lastOutputIndex + 2,
lastCharacter3)
end
end
end
end
return output
end
base64 = {
encode = encode,
decode = decode,
}
-----------------------------------------------------------------------------
---
-- CREATING OPTIMIZED INNER LOOP
-----------------------------------------------------------------------------
---
-- 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 TWO_POW_2 = 2 ^ 2
local TWO_POW_3 = 2 ^ 3
local TWO_POW_4 = 2 ^ 4
local TWO_POW_5 = 2 ^ 5
local TWO_POW_6 = 2 ^ 6
local TWO_POW_7 = 2 ^ 7
local TWO_POW_8 = 2 ^ 8
local TWO_POW_9 = 2 ^ 9
local TWO_POW_10 = 2 ^ 10
local TWO_POW_11 = 2 ^ 11
local TWO_POW_12 = 2 ^ 12
local TWO_POW_13 = 2 ^ 13
local TWO_POW_14 = 2 ^ 14
local TWO_POW_15 = 2 ^ 15
local TWO_POW_16 = 2 ^ 16
local TWO_POW_17 = 2 ^ 17
local TWO_POW_18 = 2 ^ 18
local TWO_POW_19 = 2 ^ 19
local TWO_POW_20 = 2 ^ 20
local TWO_POW_21 = 2 ^ 21
local TWO_POW_22 = 2 ^ 22
local TWO_POW_23 = 2 ^ 23
local TWO_POW_24 = 2 ^ 24
local TWO_POW_25 = 2 ^ 25
local TWO_POW_26 = 2 ^ 26
local TWO_POW_27 = 2 ^ 27
local TWO_POW_28 = 2 ^ 28
local TWO_POW_29 = 2 ^ 29
local TWO_POW_30 = 2 ^ 30
local TWO_POW_31 = 2 ^ 31
local TWO_POW_32 = 2 ^ 32
local TWO_POW_40 = 2 ^ 40
for j = 17, 64 do
local a, b = W[j - 15], W[j - 2]
W[j] = bit32_bxor(bit32_rrotate(a, 7), bit32_lrotate(a,
14), bit32_rshift(a, 3)) + bit32_bxor(bit32_lrotate(b, 15), bit32_lrotate(b, 13),
bit32_rshift(b, 10)) + W[j - 7] + W[j - 16]
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
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 = bit32_bxor(bit32_rshift(e_lo, 14) +
bit32_lshift(e_hi, 18), bit32_rshift(e_lo, 18) + bit32_lshift(e_hi, 14),
bit32_lshift(e_lo, 23) + bit32_rshift(e_hi, 9)) % 4294967296 +
(bit32_band(e_lo, f_lo) + bit32_band(-1 - e_lo,
g_lo)) % 4294967296 +
h_lo + K_lo[j] + W[jj]
local z_lo = tmp1 % 4294967296
local z_hi = bit32_bxor(bit32_rshift(e_hi, 14) +
bit32_lshift(e_lo, 18), bit32_rshift(e_hi, 18) + bit32_lshift(e_lo, 14),
bit32_lshift(e_hi, 23) + bit32_rshift(e_lo, 9)) +
bit32_band(e_hi, f_hi) + bit32_band(-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 + (bit32_band(d_lo, c_lo) + bit32_band(b_lo,
bit32_bxor(d_lo, c_lo))) % 4294967296 + bit32_bxor(bit32_rshift(b_lo, 28) +
bit32_lshift(b_hi, 4), bit32_lshift(b_lo, 30) + bit32_rshift(b_hi, 2),
bit32_lshift(b_lo, 25) + bit32_rshift(b_hi, 7)) % 4294967296
a_lo = tmp1 % 4294967296
a_hi = z_hi + (bit32_band(d_hi, c_hi) + bit32_band(b_hi,
bit32_bxor(d_hi, c_hi))) + bit32_bxor(bit32_rshift(b_hi, 28) + bit32_lshift(b_lo,
4), bit32_lshift(b_hi, 30) + bit32_rshift(b_lo, 2), bit32_lshift(b_hi, 25) +
bit32_rshift(b_lo, 7)) + (tmp1 - a_lo) / 4294967296
end
s = 27
for j = 17, 32 do
local F = bit32_rrotate(bit32_band(d, b) + bit32_band(-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 = 28
for j = 33, 48 do
local F = bit32_rrotate(bit32_bxor(bit32_bxor(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 = 26
for j = 49, 64 do
local F = bit32_rrotate(bit32_bxor(c, bit32_bor(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
for j = 17, 80 do
W[j] = bit32_lrotate(bit32_bxor(W[j - 3], W[j - 8], W[j -
14], W[j - 16]), 1)
end
for j = 21, 40 do
local z = bit32_lrotate(a, 5) + bit32_bxor(b, c, d) +
0x6ED9EBA1 + W[j] + e -- TWO_POW_30 * sqrt(3)
e = d
d = c
c = bit32_rrotate(b, 2)
b = a
a = z
end
for j = 41, 60 do
local z = bit32_lrotate(a, 5) + bit32_band(d, c) +
bit32_band(b, bit32_bxor(d, c)) + 0x8F1BBCDC + W[j] + e -- TWO_POW_30 * sqrt(5)
e = d
d = c
c = bit32_rrotate(b, 2)
b = a
a = z
end
for j = 61, 80 do
local z = bit32_lrotate(a, 5) + bit32_bxor(b, c, d) +
0xCA62C1D6 + W[j] + e -- TWO_POW_30 * sqrt(10)
e = d
d = c
c = bit32_rrotate(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
for round_idx = 1, 24 do
local C1_lo = bit32_bxor(L01_lo, L06_lo, L11_lo, L16_lo,
L21_lo)
local C1_hi = bit32_bxor(L01_hi, L06_hi, L11_hi, L16_hi,
L21_hi)
local C2_lo = bit32_bxor(L02_lo, L07_lo, L12_lo, L17_lo,
L22_lo)
local C2_hi = bit32_bxor(L02_hi, L07_hi, L12_hi, L17_hi,
L22_hi)
local C3_lo = bit32_bxor(L03_lo, L08_lo, L13_lo, L18_lo,
L23_lo)
local C3_hi = bit32_bxor(L03_hi, L08_hi, L13_hi, L18_hi,
L23_hi)
local C4_lo = bit32_bxor(L04_lo, L09_lo, L14_lo, L19_lo,
L24_lo)
local C4_hi = bit32_bxor(L04_hi, L09_hi, L14_hi, L19_hi,
L24_hi)
local C5_lo = bit32_bxor(L05_lo, L10_lo, L15_lo, L20_lo,
L25_lo)
local C5_hi = bit32_bxor(L05_hi, L10_hi, L15_hi, L20_hi,
L25_hi)
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
do
local function mul(src1, src2, factor, result_length)
local result, carry, value, weight = table.create(result_length),
0, 0, 1
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
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
for idx = 1, 24 do
local lo, m = 0, nil
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 Array256 = sha2_H_ext256[width] -- # == 8
local length, tail = 0, ""
local H = table.create(8)
H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8] = Array256[1],
Array256[2], Array256[3], Array256[4], Array256[5], Array256[6], Array256[7],
Array256[8]
tail = nil
-- Assuming user data length is shorter than
(TWO_POW_53)-9 bytes
-- Anyway, it looks very unrealistic that someone
would spend more than a year of calculations to process TWO_POW_53 bytes of data by
using this Lua script :-)
-- TWO_POW_53 bytes = TWO_POW_56 bits, so "bit-
counter" fits in 7 bytes
length = length * (8 / TWO56_POW_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] =
string.char(math.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] = string.format("%08x", H[j] % 4294967296)
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
tail = nil
-- Assuming user data length is shorter than
(TWO_POW_53)-17 bytes
-- TWO_POW_53 bytes = TWO_POW_56 bits, so "bit-
counter" fits in 7 bytes
length = length * (8 / TWO56_POW_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] =
string.char(math.floor(length))
end
final_blocks = table.concat(final_blocks)
sha512_feed_128(H_lo, H_hi, final_blocks, 0,
#final_blocks)
local max_reg = math.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] = string.format("%08x", H_hi[j] %
4294967296) .. string.format("%08x", H_lo[j] % 4294967296)
end
H_hi = nil
end
H_lo = string.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
final_blocks = table.concat(final_blocks)
md5_feed_64(H, final_blocks, 0, #final_blocks)
for j = 1, 4 do
H[j] = string.format("%08x", H[j] % 4294967296)
end
H = string.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
final_blocks = table.concat(final_blocks)
sha1_feed_64(H, final_blocks, 0, #final_blocks)
for j = 1, 5 do
H[j] = string.format("%08x", H[j] % 4294967296)
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
--~ 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
local partLength = #message_part
if tail then
local offs = 0
if tail ~= "" and #tail + partLength >=
block_size_in_bytes then
offs = block_size_in_bytes - #tail
keccak_feed(lanes_lo, lanes_hi, tail ..
string.sub(message_part, 1, offs), 0, block_size_in_bytes, block_size_in_bytes)
tail = ""
end
local lanes_used = 0
local total_lanes = math.floor(block_size_in_bytes /
8)
local qwords = {}
qwords_qty = math.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] = string.format("%08x",
lanes_hi[lanes_used + j] % 4294967296) .. string.format("%08x", lanes_lo[lanes_used
+ j] % 4294967296)
end
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 base64_symbols = {
["+"] = 62, ["-"] = 62, [62] = "+";
["/"] = 63, ["_"] = 63, [63] = "/";
["="] = -1, ["."] = -1, [-1] = "=";
}
local symbol_index = 0
for j, pair in {"AZ", "az", "09"} do
for ascii = string.byte(pair), string.byte(pair, 2) do
local ch = string.char(ascii)
base64_symbols[ch] = symbol_index
base64_symbols[symbol_index] = ch
symbol_index = symbol_index + 1
end
end
return table.concat(result)
end
return table.concat(result)
end
-- For the sake of speed of converting hexes to strings, there's a map of the
conversions here
local BinaryStringMap = {}
for Index = 0, 255 do
BinaryStringMap[string.format("%02x", Index)] = string.char(Index)
end
local result
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
local FinalMessage = partial(message)()
return AsBinary and (string.gsub(FinalMessage, "%x%x",
BinaryStringMap)) or FinalMessage
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
sha = {
md5 = md5,
sha1 = sha1,
-- SHA2 hash functions:
sha224 = function(message)
return sha256ext(224, message)
end;
sha256 = function(message)
return sha256ext(256, message)
end;
sha512_224 = function(message)
return sha512ext(224, message)
end;
sha512_256 = function(message)
return sha512ext(256, message)
end;
sha384 = function(message)
return sha512ext(384, message)
end;
sha512 = function(message)
return sha512ext(512, message)
end;
sha3_256 = function(message)
return keccak((1600 - 2 * 256) / 8, 256 / 8, false, message)
end;
sha3_384 = function(message)
return keccak((1600 - 2 * 384) / 8, 384 / 8, false, message)
end;
sha3_512 = function(message)
return keccak((1600 - 2 * 512) / 8, 512 / 8, false, message)
end;
-- misc utilities:
hmac = hmac; -- HMAC(hash_func, key, message) is applicable to any hash
function from this module except SHAKE*
hex_to_bin = hex2bin; -- converts hexadecimal representation to binary
string
base64_to_bin = base642bin; -- converts base64 representation to binary
string
bin_to_base64 = bin2base64; -- converts binary string to base64
representation
--base64_encode = Base64.Encode;
--base64_decode = Base64.Decode;
}
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;
}
--!strict
-- metatablecat 2022
lz4 = {}
type Streamer = {
Offset: number,
Source: string,
Length: number,
IsFinished: boolean,
LastUnreadBytes: number,
read: (Streamer, len: number?, shiftOffset: boolean?) -> string,
seek: (Streamer, len: number) -> (),
append: (Streamer, newData: string) -> (),
toEnd: (Streamer) -> ()
}
type BlockData = {
[number]: {
Literal: string,
LiteralLength: number,
MatchOffset: number?,
MatchLength: number?
}
}
if shift then
self:seek(len)
end
self.LastUnreadBytes = unreadBytes
return dat
end
return Stream
end
repeat
pushToLiteral = true
local nextByte = iostream:read()
if pushMatch then
pushToLiteral = false
table.insert(blocks, {
Literal = lit,
LiteralLength =
string.len(lit),
MatchOffset = realPosition +
1,
MatchLength = matchLen,
})
lit = ""
end
else
LiteralPushValue = nextByte
end
end
else
LiteralPushValue = nextByte
end
if pushToLiteral then
lit = lit .. LiteralPushValue
processed = processed .. nextByte
end
until iostream.IsFinished
table.insert(blocks, {
Literal = lit,
LiteralLength = string.len(lit)
})
else
local str = iostream.Source
blocks[1] = {
Literal = str,
LiteralLength = string.len(str)
}
end
-- create token
local tokenLit = math.clamp(litLen, 0, 15)
local tokenMat = math.clamp(matLen, 0, 15)
repeat
local nextToken = math.clamp(matLen, 0, 0xFF)
write(string.pack("<I1", nextToken))
if nextToken == 0xFF then
matLen = matLen - 255
end
until nextToken < 0xFF
end
end
end
--append chunks
local compLen = string.len(output) - 4
local decompLen = iostream.Length
if compressedLen == 0 then
return inputStream:read(decompressedLen)
end
repeat
local token = string.byte(inputStream:read())
local litLen = bit32.rshift(token, 4)
local matLen = bit32.band(token, 15) + 4
outputStream:seek(-offset)
local pos = outputStream.Offset
local match = outputStream:read(matLen)
local unreadBytes = outputStream.LastUnreadBytes
local extra
if unreadBytes then
repeat
outputStream.Offset = pos
extra = outputStream:read(unreadBytes)
unreadBytes = outputStream.LastUnreadBytes
match ..= extra
until unreadBytes <= 0
end
outputStream:append(match)
outputStream:toEnd()
end
return outputStream.Source
end
crypt = {}
do
local b64 = {
encode = function(input)
local Type = type(input)
if Type ~= "string" and Type ~= "number" then
return error("arg #1 must be type string or number",
2)
end
crypt.base64encode = b64.encode
crypt.base64_encode = b64.encode
crypt.base64decode = b64.decode
crypt.base64_decode = b64.decode
end
do
local modes = {}
if iv then
iv = crypt.base64decode(iv)
pcall(function()
iv =
game:GetService("HttpService"):JSONDecode(iv)
end)
if 16 < #iv then
iv = string.sub(iv, 1, 16)
elseif #iv < 16 then
iv = PKCS7_unpad(iv)
end
end
pcall(function()
key = crypt.base64decode(key)
end)
data = bytes_to_char(data)
if action == "decrypt" then
data = PKCS7_pad(data)
else
if table_type(iv) == "array" then
iv = bytes_to_char(iv)
else
iv =
game:GetService("HttpService"):JSONEncode(iv)
end
iv = crypt.base64encode(iv)
data = crypt.base64encode(data)
end
return data, iv
end
end
crypt.encrypt = crypt_generalized("encrypt")
crypt.decrypt = crypt_generalized("decrypt")
-- * Tests
-- for mode in { "ECB", "CBC", "PCBC", "CFB", "OFB", "CTR" } do
-- local key = "10syfhOVeMW[F#Ojbqjv[)R7,Ad=diNB"
-- local data = "test lorem ips\1" -- "xtest lorem ips\1" breaks
our padding algorithm sadly lol
-- local encrypted, iv = crypt.encrypt(data, key, nil, mode)
return crypt.base64encode(table.concat(randomBytes))
end
function crypt.generatekey()
return crypt.generatebytes(32)
end
crypt.lz4 = lz4
crypt.lz4compress = lz4.compress
crypt.lz4decompress = lz4.decompress
lz4compress = lz4.compress
lz4decompress = lz4.decompress
base64_encode = base64.encode
base64_decode = base64.decode
local RunService = game:GetService("RunService")
local Capped, FractionOfASecond
local Heartbeat = RunService.Heartbeat
function setfpscap(fps_cap)
if fps_cap == 0 or fps_cap == nil or 1e4 <= fps_cap then -- ~7k fps is
the highest people have gotten; --?maybe compare to getfpsmax instead? (but we have
to ensure getfpsmax is accurate first)
if Capped then
task.cancel(Capped)
Capped = nil
FractionOfASecond = nil
end
return
end
FractionOfASecond = 1 / fps_cap
if Capped then
return
end
local function Capper()
-- * Modified version of https://github.com/MaximumADHD/Super-
Nostalgia-Zone/blob/540221bc945a8fc3a45baf51b40e02272a21329d/Client/
FpsCap.client.lua#
local t0 = os.clock()
Heartbeat:Wait()
-- repeat until t0 + t1 < tick()
-- local count = 0
while os.clock() <= t0 + FractionOfASecond do -- * not using
repeat to avoid unreasonable extra iterations
-- count+=1
end
-- task.spawn(print,count)
end
Capper() -- Yield until it kicks in basically
Capped = task.spawn(function()
-- capping = true -- * this works too
while true do
Capper()
end
end)
end
local result = {}
result.short_src = short_src
result.source = "@" .. short_src
result.what = if short_src == "[C]" then "C" else "Lua"
elseif "f" == option then
result.func = debug.info(f, "f")
elseif "l" == option then
result.currentline = debug.info(f, "l")
elseif "n" == option then
result.name = debug.info(f, "n")
elseif "u" == option or option == "a" then
local numparams, is_vararg = debug.info(f, "a")
result.numparams = numparams
result.is_vararg = if is_vararg then 1 else 0
return result
end
debug_lib.getmetatable = function(table_or_userdata)
local result = getmetatable(table_or_userdata)
if result == nil then -- No meta
return
end
if type(result) == "table" and pcall(setmetatable, table_or_userdata,
result) then
return result
end
local real_metamethods = {}
xpcall(function()
return table_or_userdata._
end, function()
real_metamethods.__index = debug.info(2, "f")
end)
xpcall(function()
table_or_userdata._ = table_or_userdata
end, function()
real_metamethods.__newindex = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata:___()
end, function()
real_metamethods.__namecall = debug.info(2, "f")
end)
xpcall(function()
table_or_userdata()
end, function()
real_metamethods.__call = debug.info(2, "f")
end)
xpcall(function() -- * LUAU
for _ in table_or_userdata do
end
end, function()
real_metamethods.__iter = debug.info(2, "f")
end)
xpcall(function()
return #table_or_userdata
end, function()
real_metamethods.__len = debug.info(2, "f")
end)
local type_check_semibypass = {}
xpcall(function()
return table_or_userdata == table_or_userdata
end, function()
real_metamethods.__eq = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata + type_check_semibypass
end, function()
real_metamethods.__add = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata - type_check_semibypass
end, function()
real_metamethods.__sub = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata * type_check_semibypass
end, function()
real_metamethods.__mul = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata / type_check_semibypass
end, function()
real_metamethods.__div = debug.info(2, "f")
end)
xpcall(function() -- * LUAU
return table_or_userdata // type_check_semibypass
end, function()
real_metamethods.__idiv = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata % type_check_semibypass
end, function()
real_metamethods.__mod = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata ^ type_check_semibypass
end, function()
real_metamethods.__pow = debug.info(2, "f")
end)
xpcall(function()
return -table_or_userdata
end, function()
real_metamethods.__unm = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata < type_check_semibypass
end, function()
real_metamethods.__lt = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata <= type_check_semibypass
end, function()
real_metamethods.__le = debug.info(2, "f")
end)
xpcall(function()
return table_or_userdata .. type_check_semibypass
end, function()
real_metamethods.__concat = debug.info(2, "f")
end)
real_metamethods.__type = typeof(table_or_userdata)
real_metamethods.__metatable = getmetatable(game)
real_metamethods.__tostring = function()
return tostring(table_or_userdata)
end
return real_metamethods
end
debug_lib.setmetatable = setmetatable
debug = debug_lib
function getrawmetatable(object)
assert(type(object) == "table" or type(object) == "userdata", "invalid
argument #1 to 'getrawmetatable' (table or userdata expected, got " .. type(object)
.. ")", 2)
local raw_mt = debug.getmetatable(object)
if raw_mt and raw_mt.__metatable then
raw_mt.__metatable = nil
local result_mt = debug.getmetatable(object)
raw_mt.__metatable = "Locked!"
return result_mt
end
return raw_mt
end
cache = {}
do
local function ReturnOriginal(instance) --! This function might be
needed to call in other functions (testing required)
local CloneInfo = CloneRefs.Clones[instance] -- *Checks if its a
clone and not a real instance
if CloneInfo then
return CloneInfo.Original -- *Grabs the original instance
then
end
end
function cache.cloneref(instance)
local Original = ReturnOriginal(instance)
if Original then
instance = Original
end
return Clone --, if Mt_Clone then Mt_Clone else nil -- Make sure
this only works inside init script
end
function cache.compareinstances(instance, instance2)
-- assert(typeof(instance) == "Instance", `arg #1 must be type
Instance`) -- Uncomment when we start hooking typeof
-- assert(typeof(instance2) == "Instance", `arg #2 must be type
Instance`) -- Uncomment when we start hooking typeof
cache.iscached = function(thing)
if cache[thing] == 'REMOVE' then return false end
return typeof(thing) == "Instance"
end
cache.invalidate = function(thing)
cache[thing] = 'REMOVE'
thing.Parent = nil
end
cache.replace = function(a, b)
if cache[a] then
cache[a] = b
end
local n, p = a.Name, a.Parent -- name, parent
b.Parent = p
b.Name = n
a.Parent = nil
end
iscached = cache.iscached
cloneref = cache.cloneref
invalidate = cache.invalidate
replace = cache.replace
compareinstances = cache.compareinstances
end
-- objects
local camera = workspace.CurrentCamera
drawing_container = Instance.new("ScreenGui")
drawing_container.Name = "Drawing"
drawing_container.IgnoreGuiInset = true
drawing_container.DisplayOrder = 0x7fffffff
local wedge_template = Instance.new("ImageLabel")
wedge_template.BackgroundTransparency = 1
wedge_template.AnchorPoint = Vector2.one / 2
wedge_template.BorderSizePixel = 0
wedge_template.Image = "rbxassetid://0"
wedge_template.ImageColor3 = Color3.new()
wedge_template.ZIndex = 0
-- variables
local vect2_half = Vector2.one / 2
local drawing_idx = 0
drawing_obj_reg = {}
local drawing_fonts_list = {
[0] = Font.fromEnum(Enum.Font.BuilderSans),
Font.fromEnum(Enum.Font.Arial),
Font.fromEnum(Enum.Font.Nunito),
Font.fromEnum(Enum.Font.RobotoMono),
}
local triangle_assets = {
left = "rbxassetid://319692171",
right = "rbxassetid://319692151",
}
-- function
local function get_font_from_idx(font_idx: number): Font
return drawing_fonts_list[font_idx]
end
wedges.w1.Parent = parent
wedges.w2.Parent = parent
if is_destroyed then
return
end
lineFrame.BackgroundColor3 = drawing_info.Color
lineFrame.Visible = drawing_info.Visible
lineFrame.ZIndex = drawing_info.ZIndex
lineFrame.BackgroundTransparency =
convert_dtransparency(drawing_info.Transparency)
lineFrame.Size = UDim2.new()
lineFrame.Parent = drawing_container
return setmetatable(drawing_obj, {
__newindex = function(_, index, value)
if type(drawing_info[index]) == "nil" then
return
end
lineFrame.Position =
UDim2.fromOffset(center.X, center.Y)
lineFrame.Rotation = theta
lineFrame.Size =
UDim2.fromOffset(distance, drawing_info.Thickness)
elseif index == "To" then
local direction = (value -
drawing_info.From)
local center = (value +
drawing_info.From) / 2
local distance = direction.Magnitude
local theta =
math.deg(math.atan2(direction.Y, direction.X))
lineFrame.Position =
UDim2.fromOffset(center.X, center.Y)
lineFrame.Rotation = theta
lineFrame.Size =
UDim2.fromOffset(distance, drawing_info.Thickness)
elseif index == "Thickness" then
local distance = (drawing_info.To -
drawing_info.From).Magnitude
lineFrame.Size =
UDim2.fromOffset(distance, value)
elseif index == "Visible" then
lineFrame.Visible = value
elseif index == "ZIndex" then
lineFrame.ZIndex = value
elseif index == "Transparency" then
lineFrame.BackgroundTransparency =
convert_dtransparency(value)
elseif index == "Color" then
lineFrame.BackgroundColor3 = value
end
drawing_info[index] = value
end,
__index = function(self, index)
if index == "Remove" or index == "Destroy" then
return function()
lineFrame:Destroy()
drawing_info.Remove(self)
return drawing_info:Remove()
end
end
return drawing_info[index]
end,
})
elseif drawing_type == "Text" then
local drawing_info = (
{
Text = "",
Font = drawing_lib.Fonts.UI,
Size = 0,
Position = Vector2.zero,
Center = false,
Outline = false,
OutlineColor = Color3.new(),
} + base_drawing_obj
)
textLabel.Visible = drawing_info.Visible
textLabel.TextColor3 = drawing_info.Color
textLabel.TextTransparency =
convert_dtransparency(drawing_info.Transparency)
textLabel.ZIndex = drawing_info.ZIndex
textLabel.FontFace = get_font_from_idx(drawing_info.Font)
textLabel.TextSize = drawing_info.Size
textLabel:GetPropertyChangedSignal("TextBounds"):Connect(function()
local textBounds = textLabel.TextBounds
local offset = textBounds / 2
textLabel.Size = UDim2.fromOffset(textBounds.X,
textBounds.Y)
textLabel.Position = UDim2.fromOffset(
drawing_info.Position.X + (if not
drawing_info.Center then offset.X else 0),
drawing_info.Position.Y + offset.Y
)
end)
uiStroke.Thickness = 1
uiStroke.Enabled = drawing_info.Outline
uiStroke.Color = drawing_info.Color
textLabel.Position = UDim2.fromOffset(
value.X + (if not
drawing_info.Center then offset.X else 0),
value.Y + offset.Y
)
elseif index == "Center" then
local position = (if value then
camera.ViewportSize / 2 else drawing_info.Position)
textLabel.Position =
UDim2.fromOffset(position.X, position.Y)
elseif index == "Outline" then
uiStroke.Enabled = value
elseif index == "OutlineColor" then
uiStroke.Color = value
elseif index == "Visible" then
textLabel.Visible = value
elseif index == "ZIndex" then
textLabel.ZIndex = value
elseif index == "Transparency" then
local transparency =
convert_dtransparency(value)
textLabel.TextTransparency = transparency
uiStroke.Transparency = transparency
elseif index == "Color" then
textLabel.TextColor3 = value
end
drawing_info[index] = value
end,
__index = function(self, index)
if index == "Remove" or index == "Destroy" then
return function()
textLabel:Destroy()
drawing_info.Remove(self)
return drawing_info:Remove()
end
elseif index == "TextBounds" then
return textLabel.TextBounds
end
return drawing_info[index]
end,
})
elseif drawing_type == "Circle" then
local drawing_info = (
{
Radius = 150,
Position = Vector2.zero,
Thickness = 0.7,
Filled = false,
} + base_drawing_obj
)
uiCorner.CornerRadius = UDim.new(1, 0)
circleFrame.Size = UDim2.fromOffset(drawing_info.Radius,
drawing_info.Radius)
uiStroke.Thickness = drawing_info.Thickness
uiStroke.Enabled = not drawing_info.Filled
uiStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
circleFrame.BackgroundTransparency = (if
drawing_info.Filled then transparency else 1)
uiStroke.Transparency = transparency
elseif index == "Color" then
circleFrame.BackgroundColor3 = value
uiStroke.Color = value
end
drawing_info[index] = value
end,
__index = function(self, index)
if index == "Remove" or index == "Destroy" then
return function()
circleFrame:Destroy()
drawing_info.Remove(self)
return drawing_info:Remove()
end
end
return drawing_info[index]
end,
})
elseif drawing_type == "Square" then
local drawing_info = (
{
Size = Vector2.zero,
Position = Vector2.zero,
Thickness = 0.7,
Filled = false,
} + base_drawing_obj
)
squareFrame.BackgroundTransparency = (
if drawing_info.Filled then
convert_dtransparency(drawing_info.Transparency) else 1
)
squareFrame.ZIndex = drawing_info.ZIndex
squareFrame.BackgroundColor3 = drawing_info.Color
squareFrame.Visible = drawing_info.Visible
uiStroke.Thickness = drawing_info.Thickness
uiStroke.Enabled = not drawing_info.Filled
uiStroke.LineJoinMode = Enum.LineJoinMode.Miter
squareFrame.BackgroundTransparency = (if
drawing_info.Filled then transparency else 1)
uiStroke.Transparency = transparency
elseif index == "Color" then
uiStroke.Color = value
squareFrame.BackgroundColor3 = value
end
drawing_info[index] = value
end,
__index = function(self, index)
if index == "Remove" or index == "Destroy" then
return function()
squareFrame:Destroy()
drawing_info.Remove(self)
return drawing_info:Remove()
end
end
return drawing_info[index]
end,
})
elseif drawing_type == "Image" then
local drawing_info = (
{
Data = "",
DataURL = "rbxassetid://0",
Size = Vector2.zero,
Position = Vector2.zero,
} + base_drawing_obj
)
imageFrame.Visible = drawing_info.Visible
imageFrame.ZIndex = drawing_info.ZIndex
imageFrame.ImageTransparency =
convert_dtransparency(drawing_info.Transparency)
imageFrame.ImageColor3 = drawing_info.Color
imageFrame.Parent = drawing_container
return setmetatable(drawing_obj, {
__newindex = function(_, index, value)
if type(drawing_info[index]) == "nil" then
return
end
if index == "DataURL" then -- temporary
property
imageFrame.Image = value
elseif index == "Size" then
imageFrame.Size =
UDim2.fromOffset(value.X, value.Y)
elseif index == "Position" then
imageFrame.Position =
UDim2.fromOffset(value.X, value.Y)
elseif index == "Visible" then
imageFrame.Visible = value
elseif index == "ZIndex" then
imageFrame.ZIndex = value
elseif index == "Transparency" then
imageFrame.ImageTransparency =
convert_dtransparency(value)
elseif index == "Color" then
imageFrame.ImageColor3 = value
end
drawing_info[index] = value
end,
__index = function(self, index)
if index == "Remove" or index == "Destroy" then
return function()
imageFrame:Destroy()
drawing_info.Remove(self)
return drawing_info:Remove()
end
end
return drawing_info[index]
end,
})
elseif drawing_type == "Quad" then
local drawing_info = (
{
PointA = Vector2.zero,
PointB = Vector2.zero,
PointC = Vector2.zero,
PointD = Vector2.zero,
Thickness = 1,
Filled = false,
} + base_drawing_obj
)
local line_points = {}
line_points.A = drawing_lib.new("Line")
line_points.B = drawing_lib.new("Line")
line_points.C = drawing_lib.new("Line")
line_points.D = drawing_lib.new("Line")
construct_tri1(drawing_info.PointA, drawing_info.PointB,
drawing_info.PointC)
construct_tri2(drawing_info.PointA, drawing_info.PointC,
drawing_info.PointD)
wedges1.w1.Visible = drawing_info.Filled
wedges1.w2.Visible = drawing_info.Filled
wedges2.w1.Visible = drawing_info.Filled
wedges2.w2.Visible = drawing_info.Filled
return setmetatable(drawing_obj, {
__newindex = function(_, index, value)
if type(drawing_info[index]) == "nil" then
return
end
remove_tri1()
remove_tri2()
drawing_info.Remove(self)
return drawing_info:Remove()
end
end
return drawing_info[index]
end,
})
elseif drawing_type == "Triangle" then
local drawing_info = (
{
PointA = Vector2.zero,
PointB = Vector2.zero,
PointC = Vector2.zero,
Thickness = 1,
Filled = false,
} + base_drawing_obj
)
local line_points = {}
line_points.A = drawing_lib.new("Line")
line_points.B = drawing_lib.new("Line")
line_points.C = drawing_lib.new("Line")
local construct_tri1, remove_tri1, wedges1 =
new_2d_triangle(drawing_container)
construct_tri1(drawing_info.PointA, drawing_info.PointB,
drawing_info.PointC)
wedges1.w1.Visible = drawing_info.Filled
wedges1.w2.Visible = drawing_info.Filled
return setmetatable(drawing_obj, {
__newindex = function(_, index, value)
if type(drawing_info[index]) == "nil" then
return
end
remove_tri1()
drawing_info.Remove(self)
return drawing_info:Remove()
end
end
return drawing_info[index]
end,
})
end
return error(`Drawing object "{drawing_type}" doesn't exist`, 2)
end
function drawing_lib.new(...)
local drawing_obj = new(...)
table.insert(drawing_obj_reg, drawing_obj)
return drawing_obj
end
end
-- * misc drawing funcs
return object[property]
end
object[property] = value
end
drawing_container.Parent = gethui()
Drawing = drawing_lib
Drawing.clear = clearDrawCache
cleardrawcache = clearDrawCache
isrenderobj = isRenderObject
getrenderproperty = getRenderProperty
setrenderproperty = setRenderProperty
input, alias =
{}, {
["isrbxactive"] = { "isgameactive", "iswindowactive" },
["keyclick"] = { "hitkey" },
}
do -- IsFocused
local window_focused = true -- TODO Find a better way instead of
Assuming (Maybe we could force focus)
UserInputService.WindowFocusReleased:Connect(function()
window_focused = false
end)
UserInputService.WindowFocused:Connect(function()
window_focused = true
end)
function isrbxactive()
return window_focused
end
end
isgameactive = isrbxactive
iswindowactive = isrbxactive
-- basic virtual key code -> roblox KeyCode map (for backwards compatibility)
-- https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-
codes
-- https://developer.roblox.com/api-reference/enum/KeyCode
--[[ --TODO Map these to mouse functions?
]]
local map = {
-- [0x03] = Enum.KeyCode.LeftControl + Enum.KeyCode.Break
-- TODO These need to only appear once (it will be a problem if we move
some keycode from beginning to end, currently we only need to do the opposite
luckily)
[0x14] = Enum.KeyCode.CapsLock,
[0x1F] = Enum.KeyCode.Mode,
[0x21] = Enum.KeyCode.PageUp,
[0x22] = Enum.KeyCode.PageDown,
[0x23] = Enum.KeyCode.End,
[0x24] = Enum.KeyCode.Home,
[0x25] = Enum.KeyCode.Left,
[0x26] = Enum.KeyCode.Up,
[0x27] = Enum.KeyCode.Right,
[0x28] = Enum.KeyCode.Down,
[0x29] = false,
[0x2A] = Enum.KeyCode.Print, -- Not sure
[0x2B] = false,
[0x2C] = Enum.KeyCode.Print,
[0x2D] = Enum.KeyCode.Insert,
[0x2E] = Enum.KeyCode.Delete,
[0x2F] = Enum.KeyCode.Help,
[0x5B] = Enum.KeyCode.LeftSuper,
[0x5C] = Enum.KeyCode.RightSuper,
[0x5D] = Enum.KeyCode.Menu, -- Not sure
[0x5E] = false,
[0x5F] = false,
[0x6A] = Enum.KeyCode.KeypadMultiply,
[0x6B] = Enum.KeyCode.KeypadPlus,
[0x6C] = false,
[0x6D] = Enum.KeyCode.KeypadMinus,
[0x6E] = Enum.KeyCode.KeypadPeriod,
[0x6F] = Enum.KeyCode.KeypadDivide,
[0x7F] = false,
[0x90] = Enum.KeyCode.NumLock,
[0x91] = Enum.KeyCode.ScrollLock,
[0xA0] = Enum.KeyCode.LeftShift,
[0xA1] = Enum.KeyCode.RightShift,
[0xA2] = Enum.KeyCode.LeftControl,
[0xA3] = Enum.KeyCode.RightControl,
[0xA4] = Enum.KeyCode.LeftAlt,
[0xA5] = Enum.KeyCode.RightAlt,
[0xBA] = Enum.KeyCode.Semicolon,
[0xBB] = Enum.KeyCode.Plus,
[0xBC] = Enum.KeyCode.Comma,
[0xBD] = Enum.KeyCode.Minus,
[0xBE] = Enum.KeyCode.Period,
[0xBF] = Enum.KeyCode.Slash,
[0xC0] = Enum.KeyCode.Backquote,
[0xDB] = Enum.KeyCode.LeftBracket,
[0xDC] = Enum.KeyCode.BackSlash,
[0xDD] = Enum.KeyCode.RightBracket,
[0xDE] = Enum.KeyCode.Quote,
[0xE2] = Enum.KeyCode.LessThan,
function keyclick(...)
input.keypress(...)
input.keyrelease(...)
end
end
local Input = {
KeyPress = keyclick,
KeyDown = keypress,
KeyUp = keyrelease,
}
hitkey = keyclick
do -- Mouse
-- VirtualInputManager is typed to disallow a nil window, but it does
not
-- throw errors and tests rely on it `nil` being allowed
local function mouse_generalized(mouseButton, isDown)
return function(x, y, repeatCount)
VirtualInputManager:SendMouseButtonEvent(
x or UserInputService:GetMouseLocation().X,
y or UserInputService:GetMouseLocation().Y,
mouseButton,
isDown,
nil,
repeatCount or 0
)
end
end
Input[mouse_map[lua_index]] = function(action)
if 1 == action then
press()
elseif 2 == action then
release()
else
click()
end
end
function mousemoveabs(x, y)
VirtualInputManager:SendMouseMoveEvent(
x or UserInputService:GetMouseLocation().X,
y or UserInputService:GetMouseLocation().Y,
nil
)
end
function mousemoverel(x, y)
-- x,y need to be specified here or we need a fallback (0)
mousemoveabs(
x and UserInputService:GetMouseLocation().X + x,
y and UserInputService:GetMouseLocation().Y + y
)
end
function mousescroll(pixels, x, y)
if type(pixels) == "boolean" then
pixels = pixels and 120 or -120
end
--
function readfile(file)
data = bridge:send("readfile", {arg="file", value=file})
if data == nil then
return ""
end
if not data.status then
error(data.content)
end
return data.content
end
function listfiles(file)
data = bridge:send("listfiles", {arg="file", value=file})
if data == nil then
return {}
end
if typeof(data.content) == "table" then
return data.content
else
return {}
end
end
function isfile(path)
data = bridge:post("isfile", {type="isfile",filename=path})
if data == nil then
return false
end
return data.status
end
function getcustomasset(assetName)
data = bridge:post("getcustomasset",
{type="getcustomasset",filename=assetName})
if data == nil then
return false
end
return data.content
end
delfolder = function(path)
data = bridge:post("delfolder", {type="delfolder",filename=path})
end
function delfile(path)
data = bridge:post("delfile", {type="delfile",filename=path})
if data == nil then
return false
end
return data.status
end
function gethwid()
data = bridge:send("gethwid", {arg="gethwid", value="1"})
if data == nil then
return ""
end
return data.content
end
--
function lrm_load_script(script_id)
local code = [[
ce_like_loadstring_fn = loadstring;
loadstring = nil;
]] .. game:HttpGet("https://api.luarmor.net/files/v3/l/" .. script_id ..
".lua")
return loadstring(code)({ Origin = "NX" })
end
function makefolder(file)
data = bridge:send("makefolder", {arg="file", value=file})
if data == nil then
return false
end
return data.status
end
function isfolder(path)
data = bridge:send("isfolder", {arg="file", value=path})
if data == nil then
return false
end
return data.status
end
function getexecutioncontext()
local RunService = game:GetService("RunService")
return if RunService:IsClient()
then "Client"
elseif RunService:IsServer() then "Server"
else if RunService:IsStudio() then "Studio" else "Unknown"
end
getscript.Name = "getbytecodeobject"
getscript.Parent = game.CoreGui
function getscriptbytecode(instance)
assert(typeof(instance) == "Instance" and
instance:IsA("LuaSourceContainer"), `arg #1 must be LuaSourceContainer`)
getscript.Value = instance
dumpstring = getscriptbytecode
function getscripthash(instance)
assert(typeof(instance) == "Instance" and
instance:IsA("LuaSourceContainer"), `arg #1 must be LuaSourceContainer`)
-- main
if game.Players.LocalPlayer then
bridge:send("gameentered", {arg="name",
value=game.Players.LocalPlayer.Name})
end
-----------------------------------------------------------------------------
---
-- Batched Yield-Safe Signal Implementation
--
-- This is a Signal class which has effectively identical behavior to a
--
-- normal RBXScriptSignal, with the only difference being a couple extra
--
-- stack frames at the bottom of the stack trace when an error is thrown.
--
-- This implementation caches runner coroutines, so the ability to yield in
--
-- the signal handlers comes at minimal extra cost over a naive signal
--
-- implementation that either always or never spawns a thread.
--
--
--
-- API:
--
-- local Signal = require(THIS MODULE)
--
-- local sig = Signal.new()
--
-- local connection = sig:Connect(function(arg1, arg2, ...) ... end)
--
-- sig:Fire(arg1, arg2, ...)
--
-- connection:Disconnect()
--
-- sig:DisconnectAll()
--
-- local arg1, arg2, ... = sig:Wait()
--
--
--
-- Licence:
--
-- Licenced under the MIT licence.
--
--
--
-- Authors:
--
-- stravant - July 31st, 2021 - Created the file.
--
-----------------------------------------------------------------------------
---
-- Function which acquires the currently idle handler runner thread, runs the
-- function fn on it, and then releases the thread, returning it to being the
-- currently idle one.
-- If there was a currently idle runner thread already, that's okay, that old
-- one will just get thrown and eventually GCed.
local function acquireRunnerThreadAndCallEventHandler(fn, ...)
local acquiredRunnerThread = freeRunnerThread
freeRunnerThread = nil
fn(...)
-- The handler finished running, this runner thread is free again.
freeRunnerThread = acquiredRunnerThread
end
-- Connection class
local Connection = {}
Connection.__index = Connection
function Connection:Disconnect()
self._connected = false
-- Unhook the node, but DON'T clear it. That way any fire calls that
are
-- currently sitting on this node will be able to iterate forwards off
of
-- it, but any subsequent fire calls will not hit it, and it will be
GCed
-- when no more fire calls are sitting on it.
if self._signal._handlerListHead == self then
self._signal._handlerListHead = self._next
else
local prev = self._signal._handlerListHead
while prev and prev._next ~= self do
prev = prev._next
end
if prev then
prev._next = self._next
end
end
end
-- Signal class
local Signal = {}
Signal.__index = Signal
function Signal.new()
return setmetatable({
_handlerListHead = false,
}, Signal)
end
function Signal:Connect(fn)
local connection = Connection.new(self, fn)
if self._handlerListHead then
connection._next = self._handlerListHead
self._handlerListHead = connection
else
self._handlerListHead = connection
end
return connection
end
goodsignal = Signal
do -- Websockets
WebSocket = { connect = nil }
local websocket_mt = {
__index = function(self, index)
if not rawget(self, "__OBJECT_ACTIVE") then
error("WebSocket is closed.")
end
websocket_connection.__OBJECT_CLOSE:Connect(function()
websocket_connection.__OBJECT_ACTIVE = false
end)
game:GetService("Players").LocalPlayer.OnTeleport:Connect(function(teleportState)
if teleportState == Enum.TeleportState.Started and
websocket_connection.__OBJECT_ACTIVE then
websocket_connection:Close()
end
end)
coroutine.wrap(function()
while true do
task.wait(0.100)
if websocket_connection.__OBJECT_ACTIVE == false then
break
end
local resp =
game:HttpGet("http://localhost:3000/bridge?action=".. url .. "_message")
if resp then
local data = HttpService:JSONDecode(resp)
if data.status == true then
for _, value in data.content do
websocket_connection.__OBJECT_MESSAGE:Fire(value)
end
end
else
break
end
end
end)()
coroutine.wrap(function()
while true do
task.wait(0.100)
if websocket_connection.__OBJECT_ACTIVE == false then
break
end
local resp =
game:HttpGet("http://localhost:3000/bridge?action=".. url .. "_close")
if resp then
local data = HttpService:JSONDecode(resp)
if data.status == true then
websocket_connection.__OBJECT_CLOSE:Fire("")
break
end
else
websocket_connection.__OBJECT_CLOSE:Fire("")
break
end
end
end)()
return websocket_connection
end
end
http.request = request
http_request = request
--[[
sha384 = sha.sha384
base64encode = crypt.base64encode
local disassemble =
loadstring(game:HttpGet("https://raw.githubusercontent.com/suffz/luna/refs/heads/
main/decompile.luau"))()
decompile = function(a1)
return disassemble(a1)
end
local Params = {
RepoURL =
"https://raw.githubusercontent.com/luau/UniversalSynSaveInstance/main/",
SSI = "saveinstance",
}
local synsaveinstance = loadstring(game:HttpGet(Params.RepoURL ..
Params.SSI .. ".luau", true), Params.SSI)()
saveinstance = function(Options)
return synsaveinstance(Options)
end
savegame = function()
return synsaveinstance(game)
end
]]
loadfile = (function(filename)
return loadstring(readfile(filename))
end)
function getthreadidentity()
data = bridge:send("getthreadidentity", {arg="identity", value="1"})
if data == nil then
return false
end
return data.content
end
getidentity = getthreadidentity
getthreadcontext = getthreadidentity
function checkcaller()
return 3 <= getthreadidentity()
end
function setthreadidentity(identity)
data = bridge:send("setthreadidentity", {arg="identity",
value=identity})
if data == nil then
return false
end
return data.status
end
setidentity = setthreadidentity
local last_call = 0
local function konst_call(konstantType: string, scriptPath: Script |
ModuleScript | LocalScript): string
local success: boolean, bytecode: string = pcall(getscriptbytecode,
scriptPath)
function Decompile(script_instance)
if typeof(script_instance) ~= "Instance" then
return "-- invalid argument #1 to 'Decompile' (Instance expected,
got " .. typeof(script_instance) .. ")"
end
if script_instance.ClassName ~= "LocalScript" and
script_instance.ClassName ~= "ModuleScript" then
return "-- Only LocalScript and ModuleScript is supported but got
\"" .. script_instance.ClassName .. "\""
end
return tostring(konst_call("/konstant/decompile",
script_instance)):gsub("\t", " ")
end
decompile = decompile
function __Disassemble(script_instance)
if typeof(script_instance) ~= "Instance" then
return "-- invalid argument #1 to 'disassemble' (Instance
expected, got " .. typeof(script_instance) .. ")"
end
if script_instance.ClassName ~= "LocalScript" and
script_instance.ClassName ~= "ModuleScript" then
return "-- Only LocalScript and ModuleScript is supported but got
\"" .. script_instance.ClassName .. "\""
end
return tostring(konst_call("/konstant/disassemble",
script_instance)):gsub("\t", " ")
end
__disassemble = __Disassemble
bridge:post("joinedgame", {source=game.PlaceId,type="joinedgame"})
end)
wait()
while wait(9e9) do
wait(9e9)
end