Skip to content

Instantly share code, notes, and snippets.

@metatablecat
Last active November 22, 2025 14:27
Show Gist options
  • Select an option

  • Save metatablecat/1f6cd6f4495f95700eb1a686de4ebe5e to your computer and use it in GitHub Desktop.

Select an option

Save metatablecat/1f6cd6f4495f95700eb1a686de4ebe5e to your computer and use it in GitHub Desktop.
A Lua Base64 Impl based around strings.
local SEQ = {
[0] = "A", "B", "C", "D", "E", "F", "G", "H",
"I", "J", "K", "L", "M", "N", "O", "P",
"Q", "R", "S", "T", "U", "V", "W", "X",
"Y", "Z", "a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v",
"w", "x", "y", "z", "0", "1", "2", "3",
"4", "5", "6", "7", "8", "9", "+", "/",
}
local STRING_FAST = {}
local INDEX = {[61] = 0, [65] = 0}
for key, val in ipairs(SEQ) do
-- memoization
INDEX[string.byte(val)] = key
end
-- string.char has a MASSIVE overhead, its faster to precompute
-- the values for performance
for i = 0, 255 do
local c = string.char(i)
STRING_FAST[i] = c
end
local b64 = {}
function b64.encode(str)
local len = string.len(str)
local output = table.create(math.ceil(len/4)*4)
local index = 1
for i = 1, len, 3 do
local b0, b1, b2 = string.byte(str, i, i + 2)
local b = bit32.lshift(b0, 16) + bit32.lshift(b1 or 0, 8) + (b2 or 0)
output[index] = SEQ[bit32.extract(b, 18, 6)]
output[index + 1] = SEQ[bit32.extract(b, 12, 6)]
output[index + 2] = b1 and SEQ[bit32.extract(b, 6, 6)] or "="
output[index + 3] = b2 and SEQ[bit32.band(b, 63)] or "="
index += 4
end
return table.concat(output)
end
function b64.decode(hash)
-- given a 24 bit word (4 6-bit letters), decode 3 bytes from it
local len = string.len(hash)
local output = table.create(len * 0.75)
local index = 1
for i = 1, len, 4 do
local c0, c1, c2, c3 = string.byte(hash, i, i + 3)
local b =
bit32.lshift(INDEX[c0], 18)
+ bit32.lshift(INDEX[c1], 12)
+ bit32.lshift(INDEX[c2], 6)
+ (INDEX[c3])
output[index] = STRING_FAST[bit32.extract(b, 16, 8)]
output[index + 1] = c2 ~= "=" and STRING_FAST[bit32.extract(b, 8, 8)] or "="
output[index + 2] = c3 ~= "=" and STRING_FAST[bit32.band(b, 0xFF)] or "="
index += 3
end
return table.concat(output)
end
return b64

NOTE: This would probably be a lot faster if it relied on buffer, rather than strings.q

The following benchmark was compared against the Base64 library available here using Boatbomber's plugin

Data was tested with 100,000 char strings

decode encode AGF decode AGF encode
10th % 2.751ms 4.755ms 5.185ms 7.554ms
50th % 2.997ms 5.123ms 7.474ms 9.015ms
90th % 3.482ms 5.864ms 8.847ms 10.030ms
Avg 8.934ms 11.329ms 27.008ms 20.659ms
Min 2.519ms 4.468ms 4.417ms 6.623ms
Max 15.348ms 18.191ms 49.599ms 34.694ms
Average bytes per second 111,931,945.377 88,269,044.046 37,026,066.350 48,405,053.487
@phoriah
Copy link

phoriah commented Nov 22, 2025

I only meant base64-wise, but yes I get what you mean.
Would be cool to see if it's possible to beat it with a luau implementation.

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