Skip to content
nklave GitHub

Architecture

Enforce first. Sign second. Log everything.

nklave is a trust boundary between an untrusted validator client and your signing keys. Every request runs the same four-step lifecycle before a key is ever consulted — and every decision is sealed into a verifiable checkpoint chain.

  UNTRUSTED                TRUST BOUNDARY (nklave)              CUSTODY
  ┌──────────────┐         ┌───────────────────────────┐      ┌────────────┐
  │  Validator   │  sign   │  1. policy.evaluate(ctx)   │      │  Signing   │
  │  client      │ ──────▶ │     fork-allowlist         │      │  keys      │
  │  (Lighthouse │  req    │     rate-limit             │      │  keystore  │
  │   Teku Prysm │         │     custom policies        │ sig  │  YubiHSM   │
  │   Lodestar)  │         │  2. slashing-protection DB │ ───▶ │  CloudHSM  │
  │              │ ◀────── │  3. append to audit log    │ only │  GCP KMS   │
  └──────────────┘  Allow  │  4. request signature ─────┼──if──┘            │
                    Refuse  │                            │ allowed
                            └───────────────────────────┘   Refused reqs
                                        │                    never reach
                                        ▼                    the keys.
                            ┌───────────────────────────┐
                            │  Merkle-root checkpoint    │
                            │  every 60s, operator-signed│
                            └───────────────────────────┘

The request lifecycle

1

Policy layer evaluates

The policy layer runs first — fork-allowlist, rate-limit, and slashing rules — resolving the request to an explicit Allow or Refuse(code). A refusal stops here; the key is never reached. This is the extension point that carries new guardrails as restaking adds signing constraints.

2

Slashing-protection DB is consulted

Double-vote / surround-vote for attestations, double-proposal for blocks (and (height, round) for CometBFT). Safety state is monotonic and cannot be rolled back by host tampering.

3

Decision is logged

The allow or refuse decision, with a deterministic reason code, is committed to the append-only log atomically with the slashing-protection DB update.

4

Key is requested — only if allowed

Only an allowed request reaches the custody backend. A refused request never touches the keystore or HSM, so enforcement holds even on a compromised host.

Why the log is trustworthy

Decisions are appended to a newline-delimited JSON log and sealed into Merkle-root checkpoints every 60 seconds, each signed by a separate operator key kept apart from any validator key. Running nklave log verify --from 0 --to latest re-walks every checkpoint, recomputes each Merkle root, and confirms the operator-key signatures. A non-zero exit means the log was edited — tampering is detectable, not just discouraged.

Five minutes from zero to signing through nklave.

Run the container, import your slashing history, and switch your signer URL.