Skip to content

Commit

Permalink
perf(cipher) improve performance on cipher
Browse files Browse the repository at this point in the history
For example, cipher:encrypt() is 35% faster on 4096 bytes of input
  • Loading branch information
fffonion committed Dec 21, 2023
1 parent e87e93f commit ba5de3e
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 30 deletions.
7 changes: 7 additions & 0 deletions examples/perf/framework.lua
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ end

local no_count_iter = false

local run_only = os.getenv("RUN_ONLY")

local function test(desc, r, iter, expected)
if run_only and not string.match(desc, run_only) then
print("SKIP " .. desc)
return
end

print("RUNNING " .. ITER .. " ITERATIONS FOR " .. desc)
local sum, avg, max
local ok, err
Expand Down
6 changes: 4 additions & 2 deletions examples/perf/test_other_libs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ do
end
end

local v = require "jit.dump"
v.on(nil, "/tmp/a.out")

------------- bn

set_iteration(1000000)
Expand Down Expand Up @@ -74,12 +77,11 @@ if lua_openssl then
end

if lua_pack then
test("lua_pack unpack 6 int", function()
test("lua_pack bn unpack 6 int", function()
return lua_pack.unpack(binary_input, ">6I")
end)
end


------------- cipher
write_seperator()

Expand Down
62 changes: 34 additions & 28 deletions lib/resty/openssl/cipher.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ local OPENSSL_3X = require("resty.openssl.version").OPENSSL_3X
local uchar_array = ctypes.uchar_array
local void_ptr = ctypes.void_ptr
local ptr_of_int = ctypes.ptr_of_int
local uchar_ptr = ctypes.uchar_ptr

local _M = {}
local mt = {__index = _M}
Expand All @@ -23,7 +22,8 @@ local cipher_ctx_ptr_ct = ffi.typeof('EVP_CIPHER_CTX*')

local out_length = ptr_of_int()
-- EVP_MAX_BLOCK_LENGTH is 32, we give it a 64 to be future proof
local out_buffer = ctypes.uchar_array(1024 + 64)
local out_buffer_size = 1024
local out_buffer = ctypes.uchar_array(out_buffer_size + 64)

function _M.new(typ, properties)
if not typ then
Expand Down Expand Up @@ -195,49 +195,55 @@ function _M:set_aead_tag(tag)
return true
end

local update_buffer = {}
function _M:update(...)
if not self.initialized then
return nil, "cipher:update: cipher not initalized, call cipher:init first"
end

local ret = {}
table.clear(update_buffer)
local _out_buffer = out_buffer
for i, s in ipairs({...}) do
local inl = #s
if inl > 1024 then
s = ffi_cast(uchar_ptr, s)
for i=0, inl-1, 1024 do
local chunk_size = 1024
if inl - i < 1024 then
chunk_size = inl - i
end
if C.EVP_CipherUpdate(self.ctx, out_buffer, out_length, s+i, chunk_size) ~= 1 then
return nil, format_error("cipher:update")
end
table.insert(ret, ffi_str(out_buffer, out_length[0]))
end
else
if C.EVP_CipherUpdate(self.ctx, out_buffer, out_length, s, inl) ~= 1 then
return nil, format_error("cipher:update")
end
table.insert(ret, ffi_str(out_buffer, out_length[0]))
if inl > out_buffer_size and _out_buffer == out_buffer then
-- create a larger buffer than the default one
_out_buffer = ctypes.uchar_array(inl + 64)
end
if C.EVP_CipherUpdate(self.ctx, _out_buffer, out_length, s, inl) ~= 1 then
return nil, format_error("cipher:update")
end
table.insert(update_buffer, ffi_str(_out_buffer, out_length[0]))
end
return table.concat(ret, "")
return table.concat(update_buffer, "")
end

function _M:final(s)
local ret, err
if not self.initialized then
return nil, "cipher:update: cipher not initalized, call cipher:init first"
end

out_length[0] = 0
local offset = 0 -- advance the offset if we have update buffer
local _out_buffer = out_buffer
if s then
ret, err = self:update(s)
if err then
return nil, err
local inl = #s
if inl > out_buffer_size then
-- create a larger buffer than the default one
_out_buffer = ctypes.uchar_array(inl + 64)
end

if C.EVP_CipherUpdate(self.ctx, _out_buffer, out_length, s, inl) ~= 1 then
return nil, format_error("cipher:final")
end
offset = out_length[0]
end
if C.EVP_CipherFinal_ex(self.ctx, out_buffer, out_length) ~= 1 then

if C.EVP_CipherFinal_ex(self.ctx, _out_buffer + offset, out_length) ~= 1 then
return nil, format_error("cipher:final: EVP_CipherFinal_ex")
end
local final_ret = ffi_str(out_buffer, out_length[0])
return ret and (ret .. final_ret) or final_ret


return ffi_str(_out_buffer, out_length[0] + offset)
end


Expand Down

0 comments on commit ba5de3e

Please sign in to comment.