Skip to content
BitExactdocs
Documentation
On this page

Key management and rotation#

Three key roles exist. Each is hybrid: an ed25519 key and its post-quantum (ML-DSA) half, which signs everything the ed25519 key signs (see the bundle spec's Post-quantum signatures). The export key and the vendor key are raw key files generated with bitexact keygen (<name>.key and <name>.pq.key, file mode 0600, keep offline where the role allows); the two halves rotate together, as one key. The recorder key may instead live in a PKCS#11 token or as a KMS envelope, in which case there is no key file at all - see Recorder-key custody, and read the rotation note below before planning one. Every signature carries a key_id (BLAKE2b-64 of the public key) so relying parties can identify the signer without parsing keys.

RoleHeld byOnline?
Export signing keyThe operator exporting evidenceOnly during export
Recorder checkpoint key (BITEXACT_SIGNING_KEY)The recording hostYes — accept this or disable checkpoints
Vendor license keyBitExactNever leaves the vendor

Rotating an export or recorder key#

  1. Recorder key only: get the license first. A license names the recorder keys it authorizes (recorder_keys), and the deployment records only under one of them. Send the new key's public half and ask for a license naming both keys, then install it before switching. Switch first and every call from then on passes through unrecorded, with a declared gap, until the new license arrives. Once the old key is retired, a license naming only the new one can replace it at the next renewal.

  2. Generate the new key: bitexact keygen -o new.key.

  3. Add the new public key to relying parties' trust files alongside the old one — trust files accept multiple keys precisely so rotation has an overlap window. A trust file is JSON with bundle_keys and recorder_keys arrays, each entry {"key_id": ..., "public_key": ..., "pq_public_key": ...} - keygen prints the entry; the verifier reads it with --trust-file. bitexact recorder-key (and --pq for its post-quantum half) prints the public half of whichever backend holds the current one. A run cannot change post-quantum key part-way under the same ed25519 key, so switch both halves at once.

  4. Switch signing to the new key: replace the file behind BITEXACT_SIGNING_KEY, or use --key new.key for exports.

    If the recorder key lives in an HSM or a KMS envelope there is no file to replace. Generate the new key in the token (or encrypt a new one under KMS), point BITEXACT_HSM_KEY_LABEL or BITEXACT_SIGNING_KMS_CIPHERTEXT at it, and restart the recorder. The old key stays in the token for as long as you need to verify what it signed; nothing in the bundle format changes.

  5. After the overlap window, remove the old public key from trust files. Bundles signed under the old key remain verifiable by anyone who keeps its public half; re-export and re-sign if a relying party must standardize on current keys.

Checkpoint records embed their signing key_id, so a rotation mid-retention is visible and auditable in the checkpoint chain itself.

Compromise response#

Remove the compromised public key from every trust file immediately — verification against those trust files then fails for anything it signed. Re-export affected runs signed with a new key; the manifests themselves are unaffected (chain hashes carry no key material).