This is the production/manual operator procedure. For the test-only tiny ceremony, use the scripted three-machine rehearsal and its machine-specific
.envfiles.
This runbook is for participants, public witnesses, mirror operators, auditors, release upload stations, and production-decision signers. The coordinator uses COORDINATOR_RUNBOOK.md.
The proof-tool repository remains the
authority for ceremony validity. Relay transports bytes and reports public
position; the trusted mpc-ceremony binary authenticates definitions, chains,
identities, and evidence.
Follow the role-machine path in docs/INSTALL.md. It contains
the official AWS CLI v2 installation procedure and exact steps for verifying
and installing published relay and mpc-ceremony binaries. Release
maintainers and independent build auditors use
docs/RELEASE.md; ceremony roles do not need Go.
Do not continue until these commands resolve to the reviewed paths and versions:
relay --help
mpc-ceremony help
aws --version
command -v relay mpc-ceremony aws
Record the outputs in your local operator log.
Obtain these trust inputs independently of ceremony storage:
- the coordinator public key;
- the approved ceremony-kit tag and archive hash.
Verify the kit before installation. Its authenticated release.json pins the
Relay and proof-tool repositories, tags, and binary hashes. Do not accept these
trust inputs merely because they appeared in the same bucket as the artifacts
they are meant to check.
The coordinator also provides relay-storage.json, the public ceremony
material, and each non-participant role's signed enrollment record. Stage them
under one absolute ceremony home:
CEREMONY_HOME=/var/lib/mpc-ceremonies/CEREMONY_ID
install -d -m 0700 "$CEREMONY_HOME/public" "$CEREMONY_HOME/config" "$CEREMONY_HOME/run"
install -m 0600 relay-storage.json "$CEREMONY_HOME/config/relay-storage.json"
# Place ceremony.json and ceremony.sig under "$CEREMONY_HOME/public".
Keep the independently obtained coordinator public key and private signing keys at their separately approved absolute paths. A deterministic local path does not authenticate a trust anchor.
If your role uploads anything, the coordinator later supplies a secret
temporary grant. A grant is a bearer credential limited to your identity's
inbox prefix. Store it with mode 0600, never paste it into chat or logs, and
request a replacement immediately if it leaks. Grants and cloud secrets never
belong in the persistent role config.
Create a validated production profile with your local signing key before any temporary upload credential is issued:
relay ceremony init-config \
--home "$CEREMONY_HOME" \
--role participant \
--phase phase1 \
--coordinator-key /trusted/coordinator-public-key.hex \
--signing-key /secure/participant-03.ed25519.private.hex \
--environment /secure/participant-03.environment.json
ROLE_CONFIG="$CEREMONY_HOME/config/participant-phase1.json"
Enrollment asks proof-tool to match your key to the authenticated participant roster. It does not trust the key's filename or the coordinator's assertion about your identity.
Check the signed public position without an upload credential:
relay participant status --config "$ROLE_CONFIG"
After confirming it is the participant's turn, the coordinator supplies a short-lived scoped grant. Run:
relay participant run --config "$ROLE_CONFIG" \
--grant participant-03.grant.json
This is the only command required for the turn. Relay first checks the grant lifetime and public head. If it is not your turn, it exits before expensive work. Otherwise it:
- downloads and verifies the accepted transcript;
- invokes the proof-tool contribution;
- asks you to destroy the contribution environment;
- requires you to type
DESTROYEDbefore creating the signed erasure record; - confirms that the public head has not changed; and
- uploads the candidate manifest last for coordinator review.
Long operations print UTC start, completion, and failure times, plus a one-minute elapsed-time heartbeat while otherwise silent. Proof-tool replay counts and Relay transfer progress remain visible. A heartbeat is not a percentage or ETA.
Running status first is optional: participant run independently repeats the
same out-of-turn check before expensive work.
Initialize the profile using the signed public-witness enrollment:
relay ceremony init-config \
--home "$CEREMONY_HOME" --role witness --phase phase1 \
--coordinator-key /trusted/coordinator-public-key.hex \
--enrollment /trusted/witness-01.json \
--enrollment-signature /trusted/witness-01.sig
ROLE_CONFIG="$CEREMONY_HOME/config/witness-phase1.json"
Wait for a published closure:
relay witness run --config "$ROLE_CONFIG" --interval 60s
Use --once to poll once and exit; it exits non-zero when no closure has
been published yet, so a single check that observed nothing is never mistaken
for an observation. After observing closure, independently
confirm that its beacon round has not occurred and is at least the definition's
witness lead away. Relay cannot make that real-world timing claim for you.
Prepare the authenticated receipt with proof-tool, review and sign its canonical bytes, then upload the signed output using “Submit evidence” below. Your grant must name your signed public-witness enrollment.
Initialize mirror-phase1.json as above with --role mirror and the signed
mirror enrollment, then set ROLE_CONFIG to that path.
Synchronize the current authenticated chain prefix into an independently operated storage location:
relay mirror run --config "$ROLE_CONFIG"
Draft a receipt for the exact retained head:
relay mirror receipt \
--config "$ROLE_CONFIG" \
--chain <chain> \
--chain-signature <chain-signature> \
--index 3 \
--location s3://mirror/... \
--stored-at 2026-09-01T12:00:00Z \
--out receipt-0003.json
Authenticate and canonicalize the draft:
mpc-ceremony ops prepare-mirror-receipt \
--draft receipt-0003.json \
--ceremony ceremony.json \
--ceremony-signature ceremony.sig \
--coordinator-public-key-file coordinator.pub \
--transcript-root . \
--chain phase1/chain-0003.json \
--chain-signature phase1/chain-0003.sig \
--mirror-enrollment operations/enrollments/mirror-01.json \
--mirror-enrollment-signature operations/enrollments/mirror-01.sig \
--out-dir receipt-0003-signing
Review and sign the exported canonical bytes offline, then submit the signed output. Only the location's SHA-256 enters the receipt; the location itself is not published or fetched.
Initialize one authenticated auditor profile per phase using --role auditor
and the signed auditor enrollment.
Synchronize both phases from independently checked mirrors, not the coordinator's local copy:
relay auditor run --config "$CEREMONY_HOME/config/auditor-phase1.json"
relay auditor run --config "$CEREMONY_HOME/config/auditor-phase2.json"
Replay the ceremony with mpc-ceremony audit. Upload the resulting signed
audit record using your auditor grant.
The signing machine should remain offline and receive no storage credential. Review and sign the proof-tool output there, then move only the signed output to a separate online upload station. Give the scoped release or decision grant to that station and submit the evidence from it.
On the release upload station, initialize a release-phase1.json profile with
--role release and the authenticated release-signer enrollment. It contains
no release signing key. Submit with:
relay release run \
--config "$CEREMONY_HOME/config/release-phase1.json" \
--grant release-signer.grant.json \
--dir ./signed-release-output
A storage upload proves only possession of the scoped grant. The release bundle or production decision is authoritative only after proof-tool verifies its record and ceremony signatures.
Witnesses, mirrors, auditors, release upload stations, and decision signers all use the same transport command after producing signed proof-tool output:
relay witness submit \
--config "$ROLE_CONFIG" \
--grant witness-01.grant.json \
--dir ./signed-witness-output
or:
relay auditor submit \
--config "$ROLE_CONFIG" \
--grant auditor-01.grant.json \
--file audit.json \
--file audit.sig
Production-decision evidence retains the generic compatibility command because one decision grant may be authorized by a coordinator, auditor, or release signer enrollment rather than one fixed Relay role profile:
relay submit-evidence \
--grant decision-signer.grant.json \
--dir ./signed-decision-output
Relay rejects symlinks, non-regular files, duplicate names, and filenames that
look like private keys, credentials, or grants. It uploads manifest.json
last, so an interrupted upload never appears complete.
Send the printed manifest key to the coordinator through the agreed channel. The coordinator will discover it independently and run the relevant proof-tool verification before using the evidence.
- If a grant is expired or below its minimum remaining window, stop and request a replacement before beginning expensive work.
- If Relay says it is not your turn, do not retry the contribution manually. Wait for the coordinator and a new public head.
- If the public head changes during a contribution, Relay keeps the candidate local and refuses to upload it. Ask the coordinator how to proceed.
- Relay records the highest public index seen under
~/.relayand rejects a pointer that moves backward. Do not delete this state to silence a warning; contact the coordinator. - Relay refuses to overwrite a local file whose bytes differ from the authenticated digest.
- Keep private signing keys, contribution environments, grants, and provider credentials out of published and evidence directories.