Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
lua_path="$script_dir/?.lua;$script_dir/?/init.lua;$script_dir/src/?.lua;$script_dir/src/?/init.lua;$script_dir/vendor/?.lua;$LUA_PATH"

# Parse command line arguments to determine which modules to run
all_modules=("sha256" "sha512" "blake2" "chacha20" "chacha20_poly1305" "poly1305" "aes_gcm" "hkdf" "random" "bignum" "srp" "x25519" "x448" "ed25519" "openssl_wrapper")
all_modules=("sha256" "sha512" "blake2" "chacha20" "chacha20_poly1305" "poly1305" "aes_gcm" "hkdf" "random" "bignum" "srp" "x25519" "x448" "ed25519" "openssl_wrapper" "lpack")
default_modules=("${all_modules[@]}")
modules_to_run=("$@")

Expand Down Expand Up @@ -147,6 +147,15 @@ run_selftest "X448" "x448" "crypto.x448"
run_selftest "Ed25519" "ed25519" "crypto.ed25519"
run_selftest "OpenSSL gating" "openssl_wrapper" "crypto.openssl_wrapper"

# Control4's LuaJIT has string.pack/unpack as lpack, a different dialect: every
# selftest again with that shape installed before bitn loads.
run_test "All selftests with lpack-shaped string.pack" "lpack" "
dofile('$script_dir/test/lpack_stub.lua')
if not require('crypto').selftest() then
os.exit(1)
end
"

passed_count=${#passed_modules[@]}
failed_count=${#failed_modules[@]}
total_count=$((passed_count + failed_count))
Expand Down
83 changes: 83 additions & 0 deletions test/lpack_stub.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
--- @diagnostic disable: duplicate-set-field
-- Installs string.pack/string.unpack in the shape Control4's LuaJIT ships (lpack),
-- as measured on a controller: single-letter codes with no size suffix, '<' and
-- '=' little-endian, '>' big-endian, a NUL ends the format, a digit or unknown
-- code raises, and unpack(data, fmt, pos) returns the next position before the
-- values, with nil for a value the data cannot supply. Loaded ahead of bitn so a
-- byte helper that assumes the 5.3 dialect fails here rather than on a controller.
local SIZE = { b = 1, B = 1, c = 1, h = 2, H = 2, i = 4, I = 4, l = 4, L = 4 }

local function pack_int(value, size, big_endian)
value = value % 2 ^ (8 * size)
local out = {}
for _ = 1, size do
out[#out + 1] = string.char(value % 256)
value = math.floor(value / 256)
end
if big_endian then
local reversed = {}
for i = size, 1, -1 do
reversed[#reversed + 1] = out[i]
end
out = reversed
end
return table.concat(out)
end

local function unpack_int(data, pos, size, big_endian)
if #data < pos + size - 1 then
return pos, nil
end
local value = 0
for i = 0, size - 1 do
local weight = big_endian and (size - 1 - i) or i
value = value + string.byte(data, pos + i) * 2 ^ (8 * weight)
end
return pos + size, value
end

local function codes(fmt)
local out = {}
for c in fmt:gmatch(".") do
if c == "\0" then
break
end
out[#out + 1] = c
end
return out
end

function string.pack(fmt, ...)
local args, i, out, big_endian = { ... }, 0, {}, false
for _, c in ipairs(codes(fmt)) do
if c == "<" or c == "=" then
big_endian = false
elseif c == ">" then
big_endian = true
elseif SIZE[c] then
i = i + 1
out[#out + 1] = pack_int(args[i], SIZE[c], big_endian)
else
error("lpack stub: unsupported code '" .. c .. "'")
end
end
return table.concat(out)
end

function string.unpack(data, fmt, pos)
pos = pos or 1
local out, n, big_endian = {}, 0, false
for _, c in ipairs(codes(fmt)) do
if c == "<" or c == "=" then
big_endian = false
elseif c == ">" then
big_endian = true
elseif SIZE[c] then
n = n + 1
pos, out[n] = unpack_int(data, pos, SIZE[c], big_endian)
else
error("lpack stub: unsupported code '" .. c .. "'")
end
end
return pos, (table.unpack or unpack)(out, 1, n)
end
35 changes: 30 additions & 5 deletions vendor/bitn.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,31 @@ _compat.to_unsigned = to_unsigned
-- Constants
local MASK32 = 0xFFFFFFFF

-- string.pack/unpack are bound only if they answer in the 5.3 dialect. Control4's
-- LuaJIT ships lpack under the same names: no size suffixes, and unpack takes
-- (data, fmt, pos) and returns the position first, so existence proves nothing.
local function probe_string_pack()
local pack, unpack = rawget(string, "pack"), rawget(string, "unpack")
if not (pack and unpack) then
return nil, nil
end
local packed_ok, packed = pcall(pack, "<I4", 0x04030201)
if not packed_ok or packed ~= "\1\2\3\4" then
return nil, nil
end
packed_ok, packed = pcall(pack, ">I4", 0x04030201)
if not packed_ok or packed ~= "\4\3\2\1" then
return nil, nil
end
local unpacked_ok, value, next_pos = pcall(unpack, "<I4", "\0\1\2\3\4", 2)
if not unpacked_ok or value ~= 0x04030201 or next_pos ~= 6 then
return nil, nil
end
return pack, unpack
end

_compat.string_pack, _compat.string_unpack = probe_string_pack()

--------------------------------------------------------------------------------
-- Implementation 1: Native operators (Lua 5.3+)
--------------------------------------------------------------------------------
Expand Down Expand Up @@ -1178,8 +1203,8 @@ end

local string_char = string.char
local string_byte = string.byte
local string_pack = rawget(string, "pack")
local string_unpack = rawget(string, "unpack")
local string_pack = _compat.string_pack
local string_unpack = _compat.string_unpack
-- % is the whole operation on the pure Lua backend; skip the call.
local fast_band = _compat.has_native_ops or _compat.has_bit_lib

Expand Down Expand Up @@ -1887,8 +1912,8 @@ local bit32_rshift = bit32.rshift
local impl_name = _compat.impl_name
local math_floor = math.floor
local string_char = string.char
local string_pack = rawget(string, "pack")
local string_unpack = rawget(string, "unpack")
local string_pack = _compat.string_pack
local string_unpack = _compat.string_unpack

-- Private metatable for Int64 type identification
local Int64Meta = { __name = "Int64" }
Expand Down Expand Up @@ -3543,7 +3568,7 @@ local bitn = {
}

--- Library version (injected at build time for releases).
local VERSION = "v0.6.3"
local VERSION = "v0.6.4"

--- Get the library version string.
--- @return string version Version string (e.g., "v1.0.0" or "dev")
Expand Down
Loading