Skip to content

Run a witness

witness-node is the signing service for one witness. It holds one Ed25519 private key or BLS12-381 secret key and answers gateway signing requests. It is pre-1.0 and unaudited; run it only on a host and network path you control.

Build and generate a key

Build the binary from the workspace root:

cargo build --release -p witness-node

Generate an Ed25519 keypair with the repository's key generator:

target/release/witness-node --generate-key

For a BLS keypair:

target/release/witness-node --generate-key --bls

Keep the private key secret. Give the public key and witness ID to the network coordinator; do not give the private key to the gateway or publish the witness.json file.

Configuration

The default configuration path is witness.json. The node configuration has these operational fields:

{
  "id": "witness-1",
  "signature_scheme": "ed25519",
  "private_key": "<32-byte-hex-private-key>",
  "host": "127.0.0.1",
  "port": 3000,
  "network_id": "my-network",
  "signing_auth_token": "<high-entropy-secret>",
  "max_clock_skew": 300
}

private_key is a 32-byte Ed25519 seed or BLS secret key, according to the declared scheme. signing_auth_token is required and must be non-empty. max_clock_skew defaults to 300 seconds. A previous_signing_auth_token may be present during the implementation's token-rotation transition; this is credential overlap, not a general revoke mechanism.

The node validates the key and token at startup. Keep the configuration file access-controlled: the private key and bearer tokens are operational secrets, even though the process zeroizes those string fields when its configuration is dropped.

Start and bind

Start with the config defaults:

target/release/witness-node --config /etc/witness/witness.json

Override the bind host or port only when the network design requires it:

target/release/witness-node \
  --config /etc/witness/witness.json \
  --host 127.0.0.1 \
  --port 3000

The node speaks plain HTTP and defaults to loopback. Do not expose /v1/sign to the public internet. Put the node on a trusted/private path accessible to the configured gateway, or apply an equivalent network boundary. The gateway must send the matching bearer token.

Endpoints and checks

  • GET /health is a liveness probe.
  • GET /v1/info reports the node ID, public key, and network ID.
  • POST /v1/sign requires Authorization: Bearer <signing_auth_token>.

Authentication is checked before the node's defense-in-depth limit of 60 sign requests per IP per minute. A signing request is rejected when its timestamp exceeds max_clock_skew or its attestation network ID differs from the node's configured network_id.

Keep clocks synchronized across gateways and witnesses. A valid response from /health proves liveness only; it does not prove that a witness is honest or that a threshold can be met.