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
9 changes: 9 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ jobs:
ok = false
end
end
-- bignum.selftest passes on a binding it declines, so only this loop
-- catches a real build failing a per-operation known-answer check.
for _, op in ipairs({ "mul", "divmod", "mod", "mod_mul", "mod_exp" }) do
local accelerated, reason = crypto.bignum.is_accelerated(op)
print(string.format(" bignum.%-7s accelerated=%s %s", op, tostring(accelerated), reason or ""))
if not accelerated then
ok = false
end
end
if not ok then
error("feature gate did not resolve as measured for this binding")
end
Expand Down
15 changes: 12 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ lua-crypto/
│ ├── ed25519.lua # Ed25519 signatures, RFC 8032 (always pure Lua)
│ ├── hkdf.lua # HKDF-Extract/Expand, RFC 5869 (SHA-256/512)
│ ├── random.lua # CSPRNG bytes; raises rather than returning weak ones
│ ├── bignum.lua # Arbitrary-precision integers; OpenSSL-preferred modexp
│ ├── bignum.lua # Arbitrary-precision integers; OpenSSL-preferred modexp, mul, divmod
│ ├── srp.lua # SRP-6a client, RFC 5054 group 15 + SHA-512 (HAP)
│ ├── openssl_wrapper.lua # Optional lua-openssl acceleration + graceful fallback
│ ├── annotations.lua # Shared LuaCATS aliases (workspace-wide; not require'd)
Expand Down Expand Up @@ -164,6 +164,13 @@ Routing is deliberate and hardwired, not runtime-probed:
`hmac_sha512`, which already prefer OpenSSL, so it inherits acceleration
transitively. `Feature.KDF` is declared but unused; see the rationale comment
in `hkdf.lua`.
- **bignum** → per operation, behind `Feature.BN` and that operation's own
multi-limb known-answer check; `bignum.is_accelerated(op)` reports each.
`mod_exp` routes at every size; `mul`, `divmod`, `mod` and `mod_mul` once
estimated pure-Lua work reaches `ROUTE_MIN_RATIO` limb products per limb
converted, so linear-cost calls stay pure Lua. The measurements and the one
known loss (narrow `mul` under LuaJIT's JIT) are in `bignum.lua`'s OpenSSL
section; measure whether Control4's LuaJIT runs its JIT before changing it.

### Feature gating

Expand All @@ -183,7 +190,7 @@ verdict for a version string rather than the binding's behaviour:
| Feature | Supported | Note |
|---|---|---|
| `AAD` | no | 0.8.5 < 0.9.2 floor. On 0.8.5 `cipher:update(aad, true)` ignores the flag and encrypts the AAD as plaintext, so ChaCha20-Poly1305 correctly stays pure Lua there. |
| `BN` | yes | Modular exponentiation is spelled `powmod` on this build. The wrapper accepts either spelling (`bn.powmod` or `bn.mod_exp`) and both are pinned. |
| `BN` | yes | Modular exponentiation is spelled `powmod` on this build. The wrapper accepts either spelling (`bn.powmod` or `bn.mod_exp`) and both are pinned. `mul`, `divmod`, `mod` and `mulmod` are present too. A zero divisor or modulus answers 0 rather than raising, and `tohex` signs negatives; `bignum` guards both (0.8.5, 0.9.2 and 0.11.1 rocks, 2026-10-17). |
| `KDF` | yes | `kdf.derive` present, currently unused. |
| `OKP` | no | `pkey.new("ed25519")` fails. |
| `RANDOM` | yes | `random` and `rand_status` both present, `rand_status()` true, `random(n, true)` returns n distinct bytes (measured 2026-08-08). `random(0)` and negative lengths raise. |
Expand Down Expand Up @@ -360,7 +367,9 @@ injected from git tags during release.
and `0.11.1-1` and runs the suite against each with acceleration both on and
off. This is the only place the DriverWorks feature table above is checked
against a real binding rather than a stand-in, so a change to
`openssl_wrapper` that passes `check` and `test` can still fail here.
`openssl_wrapper` that passes `check` and `test` can still fail here. It also
asserts `bignum.is_accelerated(op)` for every routed bignum operation, since
bignum's own selftest accepts a binding it declines.
- `build` — single-file distributions.
- **release.yml**: on version tags (`v*`) — publishes **both** `build/crypto.lua`
and `build/crypto-portable.lua`. (build.yml's artifact upload keeps only
Expand Down
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ portable enough to run inside sandboxed Lua hosts such as Control4 DriverWorks.
- **Zero Dependencies**: Pure Lua implementation, no C extensions required
- **Portable**: Runs on any Lua interpreter (5.1+) and LuaJIT
- **Optional OpenSSL acceleration**: Transparently prefers the host `lua-openssl`
binding for hashing and AEAD when available, and falls back to pure Lua
automatically
binding for hashing, AEAD and big-number arithmetic when available, and falls
back to pure Lua automatically
- **Well-tested**: Every module ships known-answer self-tests (RFC vectors)

## Supported Algorithms
Expand All @@ -32,7 +32,7 @@ portable enough to run inside sandboxed Lua hosts such as Control4 DriverWorks.
| Signature | Ed25519 (RFC 8032) | `crypto.ed25519` |
| Key derivation | HKDF over SHA-256/SHA-512 (RFC 5869) | `crypto.hkdf` |
| PAKE | SRP-6a client, RFC 5054 group 15 + SHA-512 | `crypto.srp` |
| Big integers | Arbitrary precision, OpenSSL-preferred modexp | `crypto.bignum` |
| Big integers | Arbitrary precision, OpenSSL-preferred modexp, mul and divmod | `crypto.bignum` |
| Randomness | CSPRNG bytes, or a hard failure | `crypto.random` |

## Randomness
Expand Down Expand Up @@ -69,7 +69,7 @@ Callers that already have entropy can keep bypassing generation entirely:
The pure-Lua implementations are the baseline and always work. When the host
provides the [`lua-openssl`](https://github.com/zhaozg/lua-openssl) binding —
for example, Control4 DriverWorks exposes it beginning with OS 3.4.1 — you can
opt in to hardware-accelerated hashing and AEAD:
opt in to hardware-accelerated hashing, AEAD and big-number arithmetic:

```lua
local crypto = require("crypto")
Expand Down Expand Up @@ -119,6 +119,12 @@ since entropy is a capability rather than an optimisation.
Note that `bn`'s modular exponentiation is named `powmod`, not `mod_exp`, on
every build tested.

With `BN` available, `crypto.bignum` routes `mod_exp` through `bn` at any size,
and `mul`, `divmod`, `mod` and `mod_mul` once the work outweighs converting the
operands (5-30x faster at 3072 bits); cheaper calls stay in pure Lua. Each
operation must first reproduce a known answer, results are identical either
way, and `crypto.bignum.is_accelerated(op)` reports per operation.

## Installation

### Option 1: Single-file Distribution (Recommended)
Expand Down
Loading
Loading