Skip to content

Keys and committee

A Frost validator holds several keys with different jobs and different lifetimes. This page covers generating them and assembling the committee.

frost-node keygen --out-dir keys/ generates the full set:

Key Scheme Role
protocol ML-DSA-65 The genesis block key — signs consensus blocks. Rotating, expiring.
network-pq ML-DSA-65 Post-quantum transport identity (RFC 7250 raw public key).
network Ed25519 Legacy transport identity.
checkpoint ML-DSA-65 Checkpoint root, lattice leg.
checkpoint-slh SLH-DSA-SHA2-192s Checkpoint root, hash-based leg.

The two checkpoint keys are a matched pair, not alternatives: every checkpoint is signed with both, and both must verify. A break in the lattice family does not break the checkpoint chain. See Two-tier consensus keys.

Committee assembly is a multi-party ceremony. Each operator generates keys locally and contributes public halves; the coordinator assembles the manifest.

Terminal window
# 1. Each operator generates their keys.
frost-node keygen --out-dir keys/
# 2. Public keys go into the shared committee spec.
# 3. Each operator certifies their PQ network key against the committee
# digest — the binding that ties transport identity to committee identity.
frost-node bind --spec committee-spec.yaml --keys keys/
# 4. Each operator signs their genesis block-key delegation: the checkpoint
# root's chain-scoped certification of the block key for the genesis
# validity window.
frost-node delegate --spec committee-spec.yaml --keys keys/
# 5. The coordinator assembles the manifest from the public halves.
# This verifies every binding, all-or-none.
frost-node committee --spec committee-spec.yaml --out manifest.yaml

Steps 3 and 4 must both complete before step 5. Assembly verifies them and refuses a partial set.

The manifest records the committee digest, and the genesis block’s extraData must carry that digest. frost-node run cross-checks the execution layer’s genesis against the committee at startup and refuses to run on a mismatch.

This is what anchors trust for every node that ever joins: a new node verifies the checkpoint chain against the committee digest in genesis, so it is trusting the chain definition rather than whoever served it data.

The manifest is chain-defining and identical on every node: the serialised committee, the epoch start timestamp, the pinned protocol config, the fee recipients, and the observer endpoints followers dial.

Fee recipients live here rather than in local config for a specific reason: every node pays the committed leader’s recipient, so the choice must be deterministic. A node-local fee recipient would fork the chain.

The node config is local only: key paths, the consensus database path, a bind-address override, the Engine API URL and JWT, and the ingress and metrics listen addresses.

If you are ever unsure which file something belongs in, ask whether two nodes disagreeing about it would produce different blocks. If yes, it goes in the manifest.

Role is determined by key presence, not a flag:

  • protocol_key set → validator, participating in consensus.
  • protocol_key absent → follower, on the observer path.

A follower still needs a network identity to dial the observer endpoint, but holds no consensus keys.

The network-pq key path in the node config selects the fully post-quantum transport, which is the deployment default. All nodes on a network must agree. Flipping transport mode is a coordinated full-network restart, not a rolling one.

The post-quantum transport uses X25519MLKEM768 as the only offered key exchange group — no classical fallback to negotiate down to — with ML-DSA-65 raw public keys as identities.

Block keys rotate as a routine per-validator operation, with a defined lifecycle in the checkpoint chain and expiring validity windows. Rotate well before a window expires; a node whose block key has expired cannot propose.

Rotation is deliberately ordinary rather than exceptional. A rotation path only used in emergencies is a rotation path nobody knows works.