-
Notifications
You must be signed in to change notification settings - Fork 2
updated SSV DKG ceremony #122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
e66aea5
74f1763
62ce1d1
d4dd3f8
11bdfca
16b1f1b
734aab6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,216 @@ | ||
| --- | ||
| title: DKG Ceremony | ||
| description: Create distributed validators on SSV Network through a DKG ceremony — the full key is never assembled — and register them in your StakeWise Vault through the DVT Relayer. | ||
| --- | ||
|
|
||
| # DKG Ceremony | ||
|
|
||
| In the DKG ceremony the SSV operators generate the validator key shares together. The full private key is never constructed on any machine. The ceremony is run with [`ssv-dkg` ↗](https://github.com/ssvlabs/ssv-dkg) and involves two roles: **operators**, who each run a long-lived `ssv-dkg` service, and an **Initiator**, who triggers the ceremony and collects its outputs (the Initiator does not need to be an operator, though in a self-run cluster it usually is). The full [ceremony flow ↗](https://docs.ssv.network/stakers/tools/ssv-dkg-client/#flow-description) is abstracted away by the [SSV webapp ↗](https://app.ssv.network), which generates the command and the resulting files for you. | ||
|
|
||
| ## How Vaults Use the DKG Ceremony | ||
|
|
||
| Running your Vault's validators across a cluster of SSV operators goes through several stages: | ||
|
|
||
| 1. **Key shares generation.** The operators run a DKG ceremony that outputs the key shares `keyshares.json`. | ||
| 2. **Validator registration on SSV.** The validator is registered on the SSV network with `keyshares.json`, publishing each operator's encrypted share on-chain, where their node — and the DVT Sidecar — can read it. | ||
| 3. **Validator registration on the Beacon Chain.** Each Sidecar reads its share and sends its deposit and exit signature shares to the Relayer, which combines them into the full deposit signature (and re-encrypts the exit signature for the oracles). The Operator Service then sends the registration request to the Vault contract. | ||
|
|
||
| ## Step 1: Operators Run the DKG Service | ||
|
|
||
| Each operator runs a long-lived `ssv-dkg` service so it can take part in ceremonies. This is separate from the SSV node and reuses the operator's existing key. | ||
|
|
||
| 1. Create an `operator.config.yaml` next to your `encrypted_private_key.json` and `password` files: | ||
|
|
||
| ```yaml | ||
| privKey: /data/encrypted_private_key.json | ||
| privKeyPassword: /data/password | ||
| operatorID: 1 # your SSV operator ID | ||
| port: 3030 | ||
| logLevel: info | ||
| logFilePath: /data/debug.log | ||
| outputPath: /data/output | ||
| ``` | ||
|
|
||
| 2. Start the service: | ||
|
|
||
| ```bash | ||
| docker run --restart unless-stopped --name ssv_dkg -p 3030:3030 \ | ||
| -v "$(pwd)":/data -u `id -u $USER` -it \ | ||
| "ssvlabs/ssv-dkg:v3.0.3" start-operator --configPath /data/operator.config.yaml | ||
| ``` | ||
|
|
||
| :::custom-warning[Expose the DKG Port and Stay Online] | ||
| The service must be reachable by the Initiator during a ceremony. Open the DKG port on your firewall and make the endpoint available over HTTPS. Keep the service online — if it is unreachable, the ceremony cannot reach its threshold. | ||
| ::: | ||
|
|
||
| These details — operator ID, RSA public key, and endpoint — are published in the SSV registry, so the webapp can include them automatically when you select your operators for the ceremony. | ||
|
|
||
| ## Step 2: Run the DKG Ceremony | ||
|
|
||
| Run the ceremony from the SSV webapp — it generates the `ssv-dkg` command for you, with the operators and addresses already filled in. | ||
|
|
||
| 1. In the webapp, open **Operators → Validator Clusters → Create a cluster** and select your cluster's operators (search by **ID** or name; minimum 4). They must be **DKG-enabled** — running `ssv-dkg start-operator` (Step 1) with a reachable endpoint. | ||
| 2. Choose **Generate new key shares → Offline → DKG**. | ||
| 3. Set the number of validators and the **Withdrawal Address** to your **Vault contract address**, then confirm. | ||
| 4. Copy the generated command and run it on a machine with Docker. The webapp pre-fills `--operatorIDs`, `--operatorsInfo` (each operator's RSA key + endpoint), `--owner`, `--nonce`, and `--withdrawAddress`: | ||
|
|
||
| ```bash | ||
| docker pull ssvlabs/ssv-dkg:v3.0.3 && docker run --rm -v "$(pwd)":/ssv-dkg/data -it \ | ||
| "ssvlabs/ssv-dkg:v3.0.3" init \ | ||
| --owner <YOUR_SSV_WALLET> --nonce <NONCE> \ | ||
| --withdrawAddress <YOUR_VAULT_ADDRESS> \ | ||
| --operatorIDs 1,2,3,4 \ | ||
| --operatorsInfo '[{"id":1,"public_key":"LS0t...","ip":"https://5.4.3.2:3030"}, ...]' \ | ||
| --network hoodi --validators 1 --outputPath ./data --tlsInsecure | ||
| ``` | ||
|
|
||
| :::custom-info[Key flags (filled in by the webapp)] | ||
| | Flag | What it is | | ||
| |------|-----------| | ||
| | <nobr>`--withdrawAddress`</nobr> | Your **Vault contract address** (from the Withdrawal Address you set) | | ||
| | <nobr>`--owner`</nobr> | Your SSV cluster owner wallet — pays SSV fees and manages the cluster, not the Vault's Validators Manager | | ||
| | <nobr>`--nonce`</nobr> | The owner wallet's current SSV validator-registration count | | ||
| | <nobr>`--operatorIDs` / `--operatorsInfo`</nobr> | The operators you selected, with their RSA public keys and endpoints | | ||
| ::: | ||
|
|
||
| :::custom-tips[Advanced: run it standalone] | ||
| You can also run `ssv-dkg init` outside the webapp by building your own `operators_info.json` (each operator's `id`, base64 RSA `public_key`, and `ip`). The webapp path just assembles this for you. For the step-by-step, see SSV's [ssv-dkg client guide ↗](https://docs.ssv.network/stakers/tools/ssv-dkg-client/). | ||
| ::: | ||
|
|
||
| The ceremony writes a `ceremony-<timestamp>/` directory with `keyshares.json`, `deposit_data.json`, and `proofs.json`: | ||
|
|
||
| <details className="custom-details"> | ||
| <summary>Ceremony output</summary> | ||
|
|
||
| ``` | ||
| ceremony-<timestamp>/ | ||
| ├─ <nonce>-0x<validator public key>/ | ||
| │ ├─ deposit_data.json # Deposit data to activate the validator — not used by StakeWise (the Vault deposits) | ||
| │ ├─ keyshares.json # Encrypted shares, to register on SSV | ||
| │ └─ proof.json # Proof used to reshare to new operators later | ||
| ├─ deposit_data.json # Aggregated across all validators | ||
| ├─ keyshares.json # Aggregated across all validators | ||
| └─ proofs.json # Aggregated across all validators | ||
| ``` | ||
|
|
||
| The `keyshares.json` holds each operator's share encrypted to its RSA key — see the [KeyShares file structure ↗](https://docs.ssv.network/developers/security/keyshares-structure). | ||
|
|
||
| </details> | ||
|
|
||
| :::custom-tips[Keep the Proofs] | ||
| Back up `proofs.json`. It lets you reshare the cluster to a different set of operators later without running a new ceremony. | ||
| ::: | ||
|
|
||
| ## Step 3: Register the Keyshares on SSV | ||
|
|
||
| Register the keyshares on SSV so the encrypted shares are published on-chain — the Sidecars read each operator's share from there. **You do not deposit here:** in the StakeWise flow the **Vault** deposits later, through the Relayer (Step 6), not via the SSV Launchpad. | ||
|
|
||
| After the ceremony, the webapp shows a **Deposit Validator** step and a **Register Validator** step: | ||
|
|
||
| 1. **Skip the Launchpad deposit.** Click **"My validator has been activated"** to unlock registration — you are *not* depositing 32 ETH yourself; the Vault does that later. | ||
| 2. Click **Register Validator**, upload the ceremony's **`keyshares.json`**, and complete registration (fund the cluster → Approve SSV → Register Validator) — the same [registration steps](/operator/alternative-key-management/dvt/ssv-split-keys#register-the-validator) as Split Keys. | ||
|
|
||
| ## Step 4: Run the DVT Sidecar | ||
|
|
||
| Each operator runs one [DVT Sidecar ↗](https://github.com/stakewise/dvt-operator-sidecar) on the machine running their node. SSV records the operators, their fees, and the encrypted key shares in its on-chain registry. In SSV mode the Sidecar does **not** read the share from a local file — it reads the operator's encrypted share from that on-chain registry and decrypts it with the operator's RSA key, then signs the deposit and exit messages and submits the signature shares to the Relayer. | ||
|
|
||
| 1. Create the `.env` file from the repository's template: | ||
|
|
||
| ```bash | ||
| cp .env.example .env | ||
| ``` | ||
|
|
||
| 2. Set the values for your SSV operator: | ||
|
|
||
| ```ini | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Syntax highlight is missing on rendered preview https://docs-367dqii75-stakewise.vercel.app/operator/alternative-key-management/dvt/ssv-dkg. How to fix: add ini support rohit-gohri/redocusaurus#68 |
||
| # Network: mainnet or hoodi | ||
| NETWORK=mainnet | ||
|
|
||
| # DVT cluster type | ||
| CLUSTER_TYPE=SSV | ||
|
|
||
| # URL of your DVT Relayer | ||
| RELAYER_ENDPOINT=http://relayer | ||
|
|
||
| # This operator's SSV key (same files used to run the node and the DKG service). | ||
| # This is the RSA operator key used to DECRYPT the on-chain share — not a validator key share. | ||
| SSV_OPERATOR_KEY_FILE=encrypted_private_key.json | ||
| SSV_OPERATOR_PASSWORD_FILE=password | ||
| # This operator's SSV operator ID | ||
| SSV_OPERATOR_ID=1 | ||
|
|
||
| # Execution and consensus client endpoints (the execution endpoint is used to read the on-chain shares) | ||
| EXECUTION_ENDPOINT=http://execution:8545 | ||
| CONSENSUS_ENDPOINT=http://consensus:5052 | ||
| ``` | ||
|
|
||
| 3. Run the container: | ||
|
|
||
| ```bash | ||
| docker run \ | ||
| -u $(id -u):$(id -g) \ | ||
| --env-file .env \ | ||
| -v $(pwd)/data:/data \ | ||
| europe-west4-docker.pkg.dev/stakewiselabs/public/dvt-operator-sidecar:v2.0.0 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Latest version is v2.1.0, released today |
||
| ``` | ||
|
|
||
| ## Step 5: Run the DVT Relayer | ||
|
|
||
| One [DVT Relayer ↗](https://github.com/stakewise/dvt-relayer) serves the whole cluster. It collects the Sidecars' signature shares, reconstructs the full signatures, and serves the registration data to the Operator Service. It holds the Vault's Validators Manager wallet to sign registrations, but never has access to the validator key shares. | ||
|
|
||
| 1. Create the `.env` from the repository's template: | ||
|
|
||
| ```bash | ||
| cp .env.example .env | ||
| ``` | ||
|
|
||
| 2. In a `data/` directory, place the files the Relayer reads: | ||
|
|
||
| - `validators-manager-key.json` and `validators-manager-password.txt` — the keystore and password for the Ethereum wallet set as your Vault's [Validators Manager](/operator/validators-manager). This is an EOA that signs registration transactions, not a validator signing key. | ||
| - `public_keys.txt` — the distributed validator **public** keys, one per line. Take the `pubkey` of each validator from the ceremony's `deposit_data.json`. | ||
|
|
||
| 3. Set the values (file paths point inside the mounted `/data`): | ||
|
|
||
| ```ini | ||
| # API server | ||
| RELAYER_HOST=0.0.0.0 | ||
| RELAYER_PORT=8000 | ||
|
|
||
| # BLS signature threshold — must match your cluster's threshold | ||
| SIGNATURE_THRESHOLD=3 | ||
|
|
||
| # Network: mainnet or hoodi | ||
| NETWORK=mainnet | ||
|
|
||
| # Execution and consensus client endpoints | ||
| EXECUTION_ENDPOINT=https://execution | ||
| CONSENSUS_ENDPOINT=https://consensus | ||
|
|
||
| # Validator public keys to register, one per line | ||
| PUBLIC_KEYS_FILE=/data/public_keys.txt | ||
|
|
||
| # The Validators Manager wallet that signs registrations | ||
| VALIDATORS_MANAGER_KEY_FILE=/data/validators-manager-key.json | ||
| VALIDATORS_MANAGER_PASSWORD_FILE=/data/validators-manager-password.txt | ||
| ``` | ||
|
|
||
| 4. Pull and run the Relayer: | ||
|
|
||
| ```bash | ||
| export DVT_RELAYER_VERSION=v1.0.0 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Latest version is v1.1.0 , released today |
||
| docker run --rm -ti \ | ||
| --env-file .env \ | ||
| -v $(pwd)/data:/data \ | ||
| -p 8000:8000 \ | ||
| europe-west4-docker.pkg.dev/stakewiselabs/public/dvt-relayer:$DVT_RELAYER_VERSION | ||
| ``` | ||
|
|
||
| ## Step 6: Start the Operator Service in Relayer Mode | ||
|
|
||
| Because the Operator Service has no keystores, start it in Relayer mode pointing at your DVT Relayer: | ||
|
|
||
| ```bash | ||
| ./operator start-relayer | ||
| ``` | ||
|
|
||
| The Operator Service polls the Relayer for validators that have all required signatures and registers them in the Vault contract. At that moment the **Vault deposits its pooled ETH**, and the validator is created on the beacon chain. Once it activates, the SSV operators perform its duties using their shares. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Long sentences are a bit of a slog here. Mind turning this into a bulleted list?