Skip to content

Instantly share code, notes, and snippets.

@D4ryl00
Created May 7, 2026 02:53
Show Gist options
  • Select an option

  • Save D4ryl00/f5a1200d325717cae4fde6a387db28f6 to your computer and use it in GitHub Desktop.

Select an option

Save D4ryl00/f5a1200d325717cae4fde6a387db28f6 to your computer and use it in GitHub Desktop.
Hardware signing latency for gnoland validators

Hardware signing latency for gnoland validators

Validator signing is not only a key-management problem. It is also a latency problem.

During one consensus round, a validator may sign up to three message types:

  • proposal, only if it is the proposer
  • prevote
  • precommit

If consensus moves to another round for the same height, this repeats. If the signer backend is slow, the validator can miss votes even when the node itself is healthy.

For gnoland validators using gnokms, the important question is simple: how long does one Ed25519 signature take?

Test setup

A branch, chore/ledger-benchmarks from d4ryl00/gno, adds Ledger support and more detailed logging inside gnokms and gnoland to measure where time is spent.

Benchmarks were run with val-scenarios, branch chore/benchmark-scenario-tests, using binaries built from chore/ledger-benchmarks.

The setup compares local signing, gnokms+gnokey, and gnokms+ledger, with one or multiple validators signing consensus messages of different sizes.

Baseline: local Ed25519 signing

Local signing is effectively free compared to consensus timings.

backend proposal avg prevote avg precommit avg
local ~0.03 ms ~0.026-0.027 ms ~0.026-0.027 ms

This is the baseline: pure software Ed25519 is not the bottleneck.

gnokms overhead

gnokms itself is not the bottleneck.

Measured from gnoland and gnokms logs:

gnoland: signature received from gnokms 587.104456ms
gnokms:  signature received from ledger 586.959406ms
delta:   ~145 us

Same with gnokey:

gnoland: 248.163 ms
gnokms:  248.070 ms
delta:   ~93 us

So the remote signer framing, socket path, and gnokms wrapping are sub-millisecond. Backend choice dominates signing latency.

gnokey backend

gnokms+gnokey measured around:

phase average
proposal ~197 ms
prevote ~193-196 ms
precommit ~173-186 ms

Most of this is not Ed25519. It comes from decrypting the local encrypted key file.

bcryptSecurityParameter = 12 is hard-coded in tm2/pkg/crypto/keys/armor/armor.go, and a local benchmark measured bcrypt at roughly:

BenchmarkBcryptGenerateFromPassword param-12: ~174 ms/op

So gnokey is simple and keeps the key encrypted at rest, but every signature pays a large key-decryption cost and the key is still used on the host.

Ledger backend

Tested device:

One important implementation detail: Ledger signing latency improved after increasing the APDU chunk size during communication. Before that change, signing was around ~730 ms per operation. After increasing the chunk size, the steady-state delay dropped to about ~550 ms per operation.

After increasing the APDU chunk size, measured gnokms+ledger latency was:

phase average
proposal ~565 ms
prevote ~584 ms
precommit ~527 ms

USB capture with Wireshark showed that the wire is not the issue:

operation wire host stall on-device total
getVersion ~3 ms ~51 ms ~0 ms ~54 ms
sign ~104 B payload ~3 ms ~51 ms ~525 ms ~580 ms

Main finding: the Ledger signing cost is mostly on-device. gnokms overhead is negligible, and USB wire time is negligible.

This makes Ledger a questionable choice for hot-path validator consensus on chains with sub-second timing requirements. It remains useful for cold-path operations and key management.

YubiHSM 2

YubiHSM 2 is a better fit than a YubiKey for continuous validator signing because it is designed as a server-side HSM.

It supports daemonized signing, object capabilities, PKCS#11/native APIs, and published signing-performance numbers.

Official YubiHSM 2 EdDSA-25519 signing table:

algorithm / payload average duration
EdDSA-25519, 32 B ~105 ms
EdDSA-25519, 64 B ~121 ms
EdDSA-25519, 128 B ~137 ms
EdDSA-25519, 256 B ~168 ms
EdDSA-25519, 512 B ~229 ms
EdDSA-25519, 1024 B ~353 ms

Source: YubiHSM 2 performance table.

I only found official Ed25519 performance documentation for YubiHSM 2. I did not find equivalent official performance tables for YubiKey 5, Ledger devices, or other hardware models. Those backends need to be measured directly in the validator-signing path before drawing production conclusions.

These published numbers are much closer to gnokey than to Ledger, while keeping the private key inside dedicated hardware. The remaining work is to measure YubiHSM 2 through the actual gnokms validator-signing path.

YubiKey 5

YubiKey 5 is different from YubiHSM 2.

A YubiKey is primarily an authenticator and smart-card device. It is built for FIDO2, PIV, OpenPGP, SSH login, and user-held credentials.

It can support Ed25519 in newer firmware and applets, but that does not automatically make it a good validator signer. Unlike YubiHSM 2, I could not find an official Ed25519 signing-performance table for YubiKey 5.

A YubiKey may be useful for experiments or low-frequency signing, but it should not be treated as equivalent to a YubiHSM 2 for validator infrastructure.

Practical comparison

backend measured / published latency notes
local Ed25519 ~0.03 ms baseline
gnokms overhead <1 ms not the bottleneck
gnokms+gnokey ~170-200 ms mostly bcrypt key decryption
YubiHSM 2 Ed25519 ~105-137 ms for 32-128 B official HSM performance table
gnokms+ledger Nano S Plus ~526-602 ms mostly on-device
YubiKey 5 unknown must be benchmarked

Conclusion

For gnoland validators, signing backend latency matters.

gnokms itself is fast enough. The real choice is the backend:

  • local signing is fastest but exposes key material to the host
  • gnokey is simple but pays a bcrypt cost on every signature
  • Ledger gives hardware isolation but is slow for consensus-path signing
  • YubiHSM 2 is the most promising hardware candidate for continuous validator signing, based on its server-HSM design and published Ed25519 performance
  • YubiKey 5 needs dedicated benchmarking before being considered for production use
@moul

moul commented May 7, 2026

Copy link
Copy Markdown

"gnokms+gnokey: mostly bcrypt key decryption"

This makes me think that we could eventually have a "gnokey daemon" that performs the key decryption once.

@moul

moul commented May 7, 2026

Copy link
Copy Markdown

YubiHSM 2 Ed25519 | ~105-137 ms for 32-128 B | official HSM performance table

This does not consider all the USB communication and the potential warm-up time, which could actually be slower.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment