Skip to content

Conversation

@FZambia
Copy link
Contributor

@FZambia FZambia commented Nov 1, 2025

This PR introduces a new WithLoadSha1() option for NewLuaScript and NewLuaScriptReadOnly constructors,
enabling SHA-1 hash loading from Redis instead of client-side calculation. This provides FIPS compliance
while maintaining EVALSHA performance benefits.

Problem:

  • Client-side SHA-1 calculation causes panics in FIPS mode (fips140=only)
  • Current workaround: NewLuaScriptNoSha() always uses EVAL, sending full script every time. It comes with performance cost: slower than EVALSHA - ~36% slower in benchmarks here, +47.84% reported in Support Lua scripts without SHA-1 usage for FIPS compliancy #836.

Proposed solution:

Allow SHA-1 to be obtained from Redis via SCRIPT LOAD response which returns calculated hash. This maintains EVALSHA performance without client-side usage of sha1 package. Delegates compliance problems to Redis server only (most likely approved already).

Benchmark run over local Redis 7.4.0 which show that WithLoadSha1() performs on par with default NewLuaScript() while NewLuaScriptNoSha() is significantly slower:

name                            time/op
LuaScript_Exec/Default-8        5.59µs ± 1%
LuaScript_Exec/LoadSha1-8       5.60µs ± 1%    (Same as Default, FIPS-compliant)
LuaScript_Exec/NoSha-8          7.61µs ± 1%    (36% slower than LoadSha1)

LuaScript_ExecMulti/Default-8    163µs ± 1%
LuaScript_ExecMulti/LoadSha1-8   163µs ± 2%    (Same as Default, FIPS-compliant)
LuaScript_ExecMulti/NoSha-8      101µs ± 5%

name                            alloc/op
LuaScript_Exec/Default-8          264B ± 0%
LuaScript_Exec/LoadSha1-8         264B ± 0%
LuaScript_Exec/NoSha-8            265B ± 0%

LuaScript_ExecMulti/Default-8   1.91kB ± 0%
LuaScript_ExecMulti/LoadSha1-8  1.92kB ± 0%
LuaScript_ExecMulti/NoSha-8     1.30kB ± 0%

name                            allocs/op
LuaScript_Exec/Default-8          7.00 ± 0%
LuaScript_Exec/LoadSha1-8         7.00 ± 0%
LuaScript_Exec/NoSha-8            7.00 ± 0%

LuaScript_ExecMulti/Default-8     38.0 ± 0%
LuaScript_ExecMulti/LoadSha1-8    39.0 ± 0%
LuaScript_ExecMulti/NoSha-8       29.0 ± 0%

Implementation notes

I initially added LuaOption to NewLuaScriptNoSha, but after thinking more about it, it made more sense to add to the
main NewLuaScript constructor instead. NoSha constructors are left special for backwards compatibility, and they anyway
solve a different use case (always EVAL, avoid collisions concern, so may still make sense for some users I believe).
Adding LuaOption to NewLuaScriptNoSha is also looks a bit ugly because it's not a main use case for Lua scripts.

ExecMulti

TBH I do not quite understand why ExecMulti loads scripts every time to all nodes, most like there is a valid reason - very curious to understand. So changed it a bit blindly - but seems to be working.

@jit-ci
Copy link

jit-ci bot commented Nov 1, 2025

Hi, I’m Jit, a friendly security platform designed to help developers build secure applications from day zero with an MVS (Minimal viable security) mindset.

In case there are security findings, they will be communicated to you as a comment inside the PR.

Hope you’ll enjoy using Jit.

Questions? Comments? Want to learn more? Get in touch with us.

@rueian
Copy link
Collaborator

rueian commented Nov 1, 2025

Thanks @FZambia,

TBH I do not quite understand why ExecMulti loads scripts every time to all nodes, most like there is a valid reason - very curious to understand. So changed it a bit blindly - but seems to be working.

Actually, it is simply because handling NOSCRIPT error is a bit complex and hard to code in context of ExecMulti, but yeah, we can try not to load scripts every time to all nodes.

@rueian rueian merged commit 1433ef7 into redis:main Nov 1, 2025
37 checks passed
rueian pushed a commit that referenced this pull request Nov 3, 2025
A minor follow-up for #914

* Use `WithLoadSHA1` instead of `WithLoadSha1` to be more idiomatic for
Go
* Have `WithLoadSHA1(enabled bool)` instead of just `WithLoadSHA1()`.
This allows making Lua script in one line `rueidis.NewLuaScript(script,
rueidis.WithLoadSHA1(config.LoadSHA1))` instead of dealing with
`[]LuaOption` slice and filling it conditionally based on application's
`config.LoadSHA1`.
rueian pushed a commit to valkey-io/valkey-go that referenced this pull request Nov 10, 2025
A minor follow-up for redis/rueidis#914

* Use `WithLoadSHA1` instead of `WithLoadSha1` to be more idiomatic for
Go
* Have `WithLoadSHA1(enabled bool)` instead of just `WithLoadSHA1()`.
This allows making Lua script in one line `rueidis.NewLuaScript(script,
rueidis.WithLoadSHA1(config.LoadSHA1))` instead of dealing with
`[]LuaOption` slice and filling it conditionally based on application's
`config.LoadSHA1`.

Signed-off-by: Rueian <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants