Skip to content

server: let the caller say where the CertificateVerify signature runs - #62

Open
nevindra wants to merge 1 commit into
ianic:mainfrom
nevindra:offload-main
Open

nevindra wants to merge 1 commit into
ianic:mainfrom
nevindra:offload-main

Conversation

@nevindra

@nevindra nevindra commented Oct 8, 2026 •

Copy link
Copy Markdown

The CertificateVerify signature is the one step of a server handshake measured in milliseconds: 2.6 ms for an RSA-2048 key even through its CRT form (#59, and its port to main in a sibling PR). On an event loop that serves many connections per thread, every other connection on that thread waits behind it, so a burst of new connections stalls the requests of the ones already open.

This adds Options.offload on the server:

pub const Offload = struct {
    context: ?*anyopaque = null,
    run: *const fn (context: ?*anyopaque, job: *const fn (arg: *anyopaque) void, arg: *anyopaque) void,
};

run executes the job (on a thread pool, say) and returns once it has finished; the handshake computes the signature through it. null, the default, keeps the signature on the calling thread, so nothing changes for a caller who does not set it.

The RSA-PSS salt is drawn from rng before the hop, and the job signs with a CSPRNG seeded from it, since rng may be bound to the caller's thread or event loop.

It is independent of the CRT change and applies to main on its own. nilo (an HTTP server on zio) has pinned it on zig-0.16.x since it was written, and uses it to sign on its blocking pool.

Tests

zig build test on Zig 0.17.0: 89 passed, 1 skipped. Two tests are new: makeCertificateVerify with offload null, and with an offload that signs RSA on another thread.

The signature is the one step of a server handshake measured in
milliseconds: 2.6 ms for an RSA-2048 key even through its CRT form. On an
event loop that serves many connections per thread, every other connection
on that thread waits behind it, so a burst of new connections stalls the
requests of the ones already open.

`Options.offload` is a function that runs a job and returns once it has
finished; the handshake computes the signature through it. Null keeps the
signature on the calling thread, as before. The RSA-PSS salt is drawn from
`rng` before the hop and the job signs with a CSPRNG seeded from it, since
`rng` may be bound to the caller's thread or event loop.
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.

1 participant