ssv-dkg
π« This tool was not audited.
When using distributed key generation you understand all the risks involved with experimental cryptography.
Distributed Key Generation is a cryptographic process that aims to solve the problem of coordinating N parties to cryptographically sign and verify signatures without relying on Trusted Third Parties. The process is demonstrated to be successful in computing a key pair in the presence of a number T attackers in a decentralized network. To do so, this algorithm generates a public key, and a secret key of which no single party knows, but has some share of. The involvement of many parties requires Distributed key generation to ensure secrecy in the presence of malicious contributions to the key calculation. For more information about DKG in general, please visit this page.
The SSV team built this tool leveraging drand's DKG protocol implementation (please visit their documentation for more details on it). This implementation operates under the assumption of a p2p network, allowing operators to communicate.
The ssv-dkg
was built to lift this assumption and provide a communication layer that centered on an Initiator figure, to facilitate communication between operators. The introduced potential risk for centralization and bad actors is handled with signatures and signature verifications, as explained in the Security notes section.
Finally, the outcome of the DKG ceremony is a BLS key pair to be used for validator duties by operators on the ssv.network. As such, the tool ends the process by creating a deposit file to activate the newly created validator key pair, and proceeds to generating the payload for the transaction.
In order for the DKG protocol to execute successfully:
- all the chosen Operators must be running the
ssv-dkg
tool as Operators - separately, an Initiator (one of the Operators, or a separate entity), starts the DKG ceremony by running the ssv-dkg tool with the init parameter
- the tool automatically exchange data between the interested parties, as outlined in the Flow Description section, until the key shares are created
For details on how to run the tool as an Operator, please head over to this section containing the related instructions. Similarly, head over to this other section for instructions on how to launch the tool as the Initiator of the DKG ceremony.
The ssv-dkg
tool does not provide Operators data for the operations described above (ID, endpoint, public key).
Teams integrating with SSV are responsible for sourcing it however they see fit. This information can be collected in various ways, such as the official SSV API. Other suggested options are, for example, building an ad-hoc Operator data service, or a preset file where all Operators data is stored.
Information about Operators must be collected in a JSON file and supplied to Initiator to be used use for the key generation ceremony, as shown above.
Operators info file example:
[
{
"id": 143,
"public_key": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBM2VyQk9IUTVJYkJmL3lxak1UMmYKNElQYWJBMkY4YmwzQWlJVStRQlBUd2s2UFRRZS9EZVZMVkx6cm5wWFdZemNTRUZVSnZZeU5WM3ZhYkxGN2VDZwpxNlptRUJhSHN5S2NYS0g5N0JCb21VaDF4TGl5OFRGTkk0VGdjL0JwSU51dEdrRGkrVUhCT0tBcHE0TUVaSXlsCnJpTHlaeDFNZnJ6QTF0ZUNRaVJ3T2tzN0wrT1IraElNOEwvNFRtTUd4RDFhS2tXOHhpUzlKL256YXB5YkxsczMKR3cwWER0Q25XLzREWFVLSm1wLzFrMHlNeHZjT1phUjJWSjB0aUFVMjBKNDcrcUtndi9kZHI1YjNjQ2F5NDhpVQptcks2MkNEaHdyNVpqaU1WSHg2R1NJK0kvZmhMckI2Z2dSdTBYVVVFYTljNzVvR3k1SHVKSFA5dTJIQ0dZSXI5CjBRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K",
"ip": "http://141.94.143.182:3030"
},
{
"id": 219,
"public_key": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBcjNlTjVhR205NTN5U0VrcHBDZnAKZmp2bFpMaG51Y0c2ajI2emxHYjNobHcvVXE5aG9tSmhzOVUzTHFuYzU4dk5RR2pENzhCTUZOMy8xUStXanZRSgpuQVJJVVdJTnJONWNoMFBTMXBqb21CVlB0Nkg0RE5ha1lSamxCM0V0QmZGaGFOcDdlQzd4dGFMbzc3Qk5velMxCjBBOFpSRC9IaGg3T3lkNWttUWVnV1pIOGlGRCszcHZnV1ZMUWFibkZuK00xWW9LYUhDNkRHSzdnSzdEYTRlMGcKUTF4MFRhSmRZMUUvcStUQ01oUGhwcmtoVlFlNFBLU0NKOWJHSnRDblBpRUFqa2VWa09RZlA0Z095b0VjaW5jMQpTR2pveVo1dVZPU1hEZGYzVzdYUE9pZEpFU1VoY1hqS05DMC9IN09ZM2pqdTZyUU9NZmFqSERhb3VSWEJGaHZDCnp3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K",
"ip": "http://209.35.77.243:12015"
},
{
"id": 33,
"public_key": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdmo5UmpQTFk5YXd1WVc3NVRVcVoKVWozRWRMN2NkdDFnUjlydHowQU02TENNbTdCNG5DcW1RYjRCeFBsUktVeVl1ZnNEbXIzeTVqUmdVbHBHR0ZRawpOWmU0VGRZQkxPNnRUZ1NyMXphMUlGR0R2dzdJUUJZSHoramFEYVN6Zk9vYnNiUldiMDVaZFdGc01keGlEam5vCnR2NHZ4eGpCOWlXa2xmaytUNXB4K3ZwTWZnd1M2Ui9EOU84Y0dZdTg1b0RpQXgzQ0tPampuY3BPV0pndHhxZUMKbENDbldxSS9PeTFSa1FVcFNYL1hsRHozSHhCN0NlY0IzeUUwNnNTbXd1WTZHdk9tMUEvMmdNVUprbDFTUmFjbgpDeFhYK1hVWWFEemZGdXBBeWxPVnIxMEFnUkpTcVd2SkoxcnJCZkFwSzBMNzFMQzFzVzRyWjloMGFIN2pweW1aCjF3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K",
"ip": "http://51.81.109.67:3030"
},
{
"id": 190,
"public_key": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBeEowZDYxN09BSHpxOUQzTUt2WFoKTEJRR2VzVU4xZGFXOC9MNEt4UWJFVlN6Y2JzTlY1Q1RqNm5OWGtnOW1LQzIyWWRRazRZcGpNbk9reENrMXNXRApvUXI4bG4zZTJxbU9zeHJuOGFxZEJhVGZmaFZ4WDJrTU9BZUZCcEJPN0lrTXBOUTFwMzdDMzh0Rmx0eFpxSEt3CkFJVXg5UjVGWWhOZXhrOEUrQlpMYzJFSzl4bjZIMTFUY21hN2NVZW03VUpDeUR3VFlLVC9JN21ZTXV3UGFpTTAKTm1Ta0JoeFYrdkd3bmJqWWhCaEZQTi9MMTJRWi9YZUVJcHFzcGRKTFpkUmhRd2VlZG1MdTNLcXdFdnhhNEJZVQpWcTlkeG9qd1JDdU9TL2tvM1pTQ3hubWpJaHlGQUJXYW5WU2x5TW5xdGFaZTFkdm1STG12RTFpL3RjN251MnRnCi93SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K",
"ip": "http://80.181.85.114:3030"
},
{
"id": 34,
"public_key": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBNHZMUm93Ry9HeVFYdnFaS092MzEKYlNkRVFId3FoTmR2d2JCckdyYlQ0dmVWVHNPbDNPRVF6K3dWMjBVaXJjeHBVVVRKc081K0wrTzlnR0xNMWdTRgpFMVJRU01zMXEzSkZtNlY0VXFQU3pMK09DcDlMS3ZIRnJKMmU4VGwyZ25UU0tPNzFncGtUdFRrb2ZlLzlJRjFOCmNZMDlJbkQwTWNtZzk1Qm14alBuREV3VE1uVzBQU3JVTnJQYVNlMTJTVHJ0Q2JCTUJFUFR5RnI5elovRWFESFIKSHFaZjlkeE9VMjBiQnNSUVlSMnhCZFBtWHFKaFZZMTQrOExmaWpLRmhMcDNmZ25IL0xtK0NjTE5FOFQ3ZjhTTApoZUhLcnMrcUV4VERTcDR4MWhLMzk4dnpWTElOL0h6T20yeXV3Z3cxeG9zdThTOFlVUzNCeTFGZ3g2RExZc3RyCmxRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K",
"ip": "http://148.113.20.206:3030"
}
]
There are a couple of options to launch the DKG tool:
It is advised launching the tool as a Docker image as it is the most convenient way and only requires to have Docker installed. The team builds a Docker image with every release of the tool.
All of the necessary configuration information can be provided in a YAML file (referenced as initiator.yaml
from now on).
A good way to manage all the necessary files (operators_info.json
, encrypted_private_key.json
, password
) is to store them in a single folder (in this case initiator-config
) together with the initiator.yaml
configuration file, like so:
ssv@localhost:~/ssv-dkg# tree initiator-config
initiator-config
βββ encrypted_private_key.json
βββ initiator.yaml
βββ operators_info.json
βββ password
1 directory, 4 files
With this configuration, a typical configuration file would look like this:
operatorIDs: [143, 219, 33, 34] # array of Operator IDs which will be used for a DKG ceremony
withdrawAddress: "0xa1a66cc5d309f19fb2fda2b7601b223053d0f7f4" # Address where reward payments for the validator are sent
owner: "0xb64923DA2c1A9907AdC63617d882D824033a091c" # Address of owner of the Cluster that will manage the validator on ssv.network
nonce: 0 # Owner nonce for the SSV contract
network: "prater" # Network name (default: mainnet)
operatorsInfoPath: /data/operators_info.json # Path to the file containing operators information
# Alternatively:
# operatorsInfo: '[{"id": 1,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"}, {"id": 2,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"},...]' # Raw content of the JSON file with operators information
outputPath: /data/output # Path to store the resulting staking deposit and ssv contract payload files
initiatorPrivKey: /data/encrypted_private_key.json # Path to private key of ssv initiator
initiatorPrivKeyPassword: /data/password # Path to password file to decrypt the key
# Alternatively:
# generateInitiatorKey: false # If set true - generates a new RSA key pair + random secure password. The result is stored at `outputPath`
logLevel: info # Logger's log level (default: debug)
logFormat: json # Logger's encoding (default: json)
logLevelFormat: capitalColor # Logger's level format (default: capitalColor)
logFilePath: /data/debug.log # Path to file where logs should be written (default: ./data/debug.log)
βΉοΈ In the config file above,
/data/
represents the container's shared volume created by the docker command itself with the-v
option.
A special note goes to the nonce
field, which represents how many validators the address identified in the owner parameter has already registered to the ssv.network.
You can keep track of this counter yourself, or you can use the ssv-scanner
tool made available by the SSV team to source it. For more information, please refer to the related user guide or to its SDK documentation page.
βΉοΈ Note: For more details on
operatorsInfoPath
parameter, head over to the Operators data section above
Under the assumption that all the necessary files (operators_info.json
, encrypted_private_key.json
, password
) are under the same folder (represented below with <PATH_TO_FOLDER_WITH_CONFIG_FILES>
) you can run the tool using the command below:
docker run --name ssv_dkg_initiator \
-v "<PATH_TO_FOLDER_WITH_CONFIG_FILES>":/data -it \
"bloxstaking/ssv-dkg:latest" /app init --generateInitiatorKey \
--configPath /data/initiator.yaml && \
docker rm ssv_dkg_initiator
Just make sure to substitute <PATH_TO_FOLDER_WITH_CONFIG_FILES>
with the actual folder containing all the files.
You can, of course, change the configuration above to one that suits you better, just be mindful about changing the path references in the docker command and in the operator.yaml
file as well.
βΉοΈ Note: The Initiator needs to sign all messages exchanged with DKG participants with an RSA key. The
--generateInitiatorKey
option will automatically create it, and encrypt it with a random password. Both the key and the password will be returned as output.If you already have a password-encrypted RSA key, make sure to omit this option.
Click here if you want to generate an RSA with a password of your choosing
First of all, write down your chosen password in a text file, for example password
, replacing <PASSWORD>
with a password of your choosing:
echo "<PASSWORD>" >> password
To generate Initiator RSA keys, make sure to update `initiator.yaml`:
# initiatorPrivKey: /data/encrypted_private_key.json
initiatorPrivKeyPassword: /data/password # Path to password file
generateInitiatorKey: true
Run:
docker run --name ssv_dkg_initiator \
-v "<PATH_TO_FOLDER_WITH_CONFIG_FILES>":/data -it \
"bloxstaking/ssv-dkg:latest" /app init --configPath /data/initiator.yaml && \
docker rm ssv_dkg_initiator
This will create encrypted_private_key-<VALIDATOR_PUBKEY>.json
with encrypted by password RSA key pair.
To build from source you'll need to have Go version 1.20 installed on your system
A prerequisite for this is to have go
version 1.20 installed on the system, and an optional requirement is to have the make
tool installed as well (alternatively you could run the corresponding command defined in the Makefile
).
make install
It is advised to store all the necessary files (operators_info.json
, encrypted_private_key.json
, password
) in a single folder (in this case initiator-config
), as shown below:
ssv@localhost:~/ssv-dkg# tree initiator-config
initiator-config
βββ encrypted_private_key.json
βββ operators_info.json
βββ password
1 directory, 3 files
The Initiator provides the initial details needed to run DKG between all operators via the init
command. You can launch the following command with the appropriate values to each parameter:
ssv-dkg init \
--operatorIDs 1,2,3,4 \
--operatorsInfoPath ./examples/operators_integration.json \
# Alternatively:
# --operatorsInfo: '[{"id": 1,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"}, {"id": 2,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"},...]'
--owner 0x81592c3de184a3e2c0dcb5a261bc107bfa91f494 \
--nonce 4 \
--withdrawAddress 0xa1a66cc5d309f19fb2fda2b7601b223053d0f7f4 \
--network "mainnet" \
--outputPath /output \
--initiatorPrivKey ./encrypted_private_key.json \
--initiatorPrivKeyPassword ./password \
# Alternatively:
# --generateInitiatorKey: false # If set true - generates a new RSA key pair + random secure password. The result is stored at `outputPath`
--logLevel info \
--logFormat json \
--logLevelFormat capitalColor \
--logFilePath ./initiator_logs/debug.log
Here's an explanation of each parameter:
Argument | type | description |
---|---|---|
--operatorIDs |
int[] | Operator IDs which will be used for a DKG ceremony |
--operatorsInfoPath |
string | Path to operators info: ID, base64(RSA pub key), endpoint |
--operatorsInfo |
string | Raw content of the JSON file with operators information |
--owner |
address | Owner address for the SSV contract |
--nonce |
int | Owner nonce for the SSV contract |
--withdrawAddress |
address | Address where reward payments for the validator are sent |
--network |
mainnet / prater / holesky | Network name (default: mainnet ) |
--outputPath |
string | Path to store the output files |
--initiatorPrivKey |
string | Private key of ssv initiator (path, or plain text, if not encrypted) |
--initiatorPrivKeyPassword |
string | Path to password file to decrypt the key (if absent, provide plain text private key) |
--generateInitiatorKey |
boolean | Generates a new RSA key pair + random secure password. Result stored at outputPath (default: false ) |
--logLevel |
debug / info / warning / error / critical | Logger's log level (default: debug ) |
--logFormat |
json / console | Logger's encoding (default: json ) |
--logLevelFormat |
capitalColor / capital / lowercase | Logger's level format (default: capitalColor ) |
--logFilePath |
string | Path to file where logs should be written (default: ./data/debug.log ) |
A special note goes to the nonce
field, which represents how many validators the address identified in the owner parameter has already registered to the ssv.network.
You can keep track of this counter yourself, or you can use the ssv-scanner
tool made available by the SSV team to source it. For more information, please refer to the related user guide or to its SDK documentation page.
βΉοΈ Note: For more details on
operatorsInfoPath
parameter, head over to the Operators data section.
It is also possible to use YAML configuration file. Just pay attention to the path of the necessary files, which needs to be changed to reflect the local configuration.
If the initiator.yaml
file is created in the same folder as the other files, and the folder structure looks like this:
ssv@localhost:~/ssv-dkg# tree initiator-config
initiator-config
βββ encrypted_private_key.json
βββ initiator.yaml
βββ operators_info.json
βββ password
1 directory, 4 files
Then the content of the YAML file should be changed to this:
operatorIDs: [143, 219, 33, 34] # array of Operator IDs which will be used for a DKG ceremony
withdrawAddress: "0xa1a66cc5d309f19fb2fda2b7601b223053d0f7f4" # Address where reward payments for the validator are sent
owner: "0xb64923DA2c1A9907AdC63617d882D824033a091c" # Address of owner of the Cluster that will manage the validator on ssv.network
nonce: 0 # Owner nonce for the SSV contract
network: "prater" # Network name (default: mainnet)
operatorsInfoPath: ./initiator-config/operators_info.json # Path to the file containing operators information
# Alternatively:
# operatorsInfo: '[{"id": 1,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"}, {"id": 2,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"},...]' # Raw content of the JSON file with operators information
outputPath: ./output # Path to store the resulting staking deposit and ssv contract payload files
initiatorPrivKey: ./initiator-config/encrypted_private_key.json # Path to private key of ssv initiator
initiatorPrivKeyPassword: ./initiator-config/password # Path to password file to decrypt the key
# Alternatively:
# generateInitiatorKey: true # If set true - generates a new RSA key pair + random secure password. The result is stored at `outputPath`
logLevel: info # Logger's log level (default: debug)
logFormat: json # Logger's encoding (default: json)
logLevelFormat: capitalColor # Logger's level format (default: capitalColor)
logFilePath: ./initiator-config/debug.log # Path to file where logs should be written (default: ./data/debug.log)
A special note goes to the nonce
field, which represents how many validators the address identified in the owner parameter has already registered to the ssv.network.
You can keep track of this counter yourself, or you can use the ssv-scanner
tool made available by the SSV team to source it. For more information, please refer to the related user guide or to its SDK documentation page.
βΉοΈ Note: For more details on
operatorsInfoPath
parameter, head over to the Operators data section.
Then the tool can be launched from the root folder, by running this command:
ssv-dkg init --configPath ./initiator-config/initiator.yaml
If the --configPath
parameter is not provided, ssv-dkg
will be looking for a file named config.yaml
in ./config/
folder at the same root as the binary (i.e. ./config/config.yaml
)
After launching the ssv-dkg
tool as shown above, it will commence a DKG ceremony with the selected operators.
Following the successful completion of the DKG ceremony, several files have been generated and placed in the directory where the command was launched from:
deposit-[validator_pubkey].json
- this file contains the deposit data necessary to perform the transaction on the Deposit contract and activate the validator on the Beacon layerkeyshares-[validator_pubkey].json
- this file contains the keyshares necessary to register the validator on the ssv.networkencrypted_private_key-[validator_pubkey].json
andpassword-[validator_pubkey]
(not present if thegenerateInitiatorKey
option is not used) - these files contain the keys used to sign messages during the ceremony (sometimes called ceremony identifiers), which are crucial for resharing your validator to a different set of operators in the future.
Using ssv-dkg
tool, it is also possible to change the operators managing a validator generated through a DKG ceremony.
For example, if an initial DKG ceremony created a cluster composed of operator with IDs [1,2,3,4], the resharing ceremony can create a new cluster, with a completely different set of operators (e.g. with IDs [5,6,7,8]) or a set with partial overlap (e.g. with IDs [1,2,5,6]). The new threshold will be computed based on a new set of operators, using 3f+1 tolerance.
β οΈ All operators (old set and new set) must be online to complete the resharing ceremony.
Similarly to the initiation of a new DKG ceremony, key resharing can be accomplished by launching a Docker command, or building from source and running the resulting executable.
All of the necessary configuration information can be provided in a YAML file (referenced as reshare.yaml
in this section).
A good way to manage all the necessary files (operators_info.json
, encrypted_private_key.json
, password
) is to store them in a single folder (in this case initiator-config
) together with the reshare.yaml
configuration file, like so:
ssv@localhost:~/ssv-dkg# tree initiator-config
initiator-config
βββ encrypted_private_key.json
βββ reshare.yaml
βββ operators_info.json
βββ password
1 directory, 4 files
With this configuration, a typical configuration file would look like this:
operatorIDs: [1,2,3,4] # array of Operator IDs that participated in the initial or a previous resharing DKG ceremony
newOperatorIDs: [5, 6, 7, 8] # array of Operator IDs for which the new KeyShares of the existing validator will be generated
oldID: "dbd12b3155454666a6710a2262695bb82cda41948d612d98" # HEX of previous DKG ceremony ID. Can be found in the `keyshares-[validator-pub_key]-[ID].json`
withdrawAddress: "0xa1a66cc5d309f19fb2fda2b7601b223053d0f7f4" # Address where reward payments for the validator are sent
owner: "0xb64923DA2c1A9907AdC63617d882D824033a091c" # Address of owner of the Cluster that will manage the validator on ssv.network
nonce: 0 # Owner nonce for the SSV contract
network: "prater" # Network name (default: mainnet)
operatorsInfoPath: /data/operators_info.json # Path to the file containing operators information
# Alternatively:
# operatorsInfo: '[{"id": 1,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"}, {"id": 2,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"},...]' # Raw content of the JSON file with operators information
outputPath: /data/output # Path to store the resulting staking deposit and ssv contract payload files
initiatorPrivKey: /data/encrypted_private_key.json # Path to private key of ssv initiator
initiatorPrivKeyPassword: /data/password # Path to password file to decrypt the key
# Alternatively:
# generateInitiatorKey: false # If set true - generates a new RSA key pair + random secure password. The result is stored at `outputPath`
logLevel: info # Logger's log level (default: debug)
logFormat: json # Logger's encoding (default: json)
logLevelFormat: capitalColor # Logger's level format (default: capitalColor)
logFilePath: /data/debug.log # Path to file where logs should be written (default: ./data/debug.log)
βΉοΈ In the config file above,
/data/
represents the container's shared volume created by the docker command itself with the-v
option.
A special note goes to the nonce
field, which represents how many validators the address identified in the owner parameter has already registered to the ssv.network.
You can keep track of this counter yourself, or you can use the ssv-scanner
tool made available by the SSV team to source it. For more information, please refer to the related user guide or to its SDK documentation page.
βΉοΈ Note: For more details on
operatorsInfoPath
parameter, head over to the Operators data section above
docker run --name ssv_dkg_reshare \
-v "<PATH_TO_FOLDER_WITH_CONFIG_FILES>":/data -it \
"bloxstaking/ssv-dkg:latest" /app reshare --configPath /data/reshare.yaml && \
docker rm ssv_dkg_initiator
Just make sure to substitute <PATH_TO_FOLDER_WITH_CONFIG_FILES>
with the actual folder containing all the files.
You can, of course, change the configuration above to one that suits you better, just be mindful about changing the path references in the docker command and in the operator.yaml
file as well.
β οΈ Note: It is not possible to create a new key pair during resharing. The same key used duringinit
ceremony must be used.
To build from source you'll need to have Go version 1.20 installed on your system
A prerequisite for this is to have go
version 1.20 installed on the system, and an optional requirement is to have the make
tool installed as well (alternatively you could run the corresponding command defined in the Makefile
).
make install
It is advised to store all the necessary files (operators_info.json
, encrypted_private_key.json
, password
) in a single folder (in this case initiator-config
), as shown below:
ssv@localhost:~/ssv-dkg# tree initiator-config
initiator-config
βββ encrypted_private_key.json
βββ operators_info.json
βββ password
1 directory, 3 files
The Initiator provides the necessary details to run DKG ceremony between all operators via the reshare
command. You can launch the following command with the appropriate values to each parameter:
ssv-dkg reshare \
--operatorIDs 1,2,3,4 \
--newOperatorIDs 5, 6, 7, 8 \
--oldID "dbd12b3155454666a6710a2262695bb82cda41948d612d98" \
--operatorsInfoPath ./examples/operators_integration.json \
# Alternatively:
# --operatorsInfo: '[{"id": 1,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"}, {"id": 2,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"},...]'
--owner 0x81592c3de184a3e2c0dcb5a261bc107bfa91f494 \
--nonce 4 \
--outputPath /output \
--initiatorPrivKey ./encrypted_private_key.json \
--initiatorPrivKeyPassword ./password \
--logLevel info \
--logFormat json \
--logLevelFormat capitalColor \
--logFilePath ./initiator_logs/debug.log
Here's an explanation of each parameter:
Argument | type | description |
---|---|---|
--operatorIDs |
int[] | array of Operator IDs that participated in the initial or a previous resharing DKG ceremony |
--newOperatorIDs |
int[] | array of Operator IDs for which the new KeyShares of the existing validator will be generated |
--oldID |
string | HEX of previous DKG ceremony ID. Can be found in the keyshares-[validator-pub_key]-[ID].json |
β οΈ Note: It is not possible to create a new key pair during resharing. The same key used duringinit
ceremony must be used.
A special note goes to the nonce
field, which represents how many validators the address identified in the owner parameter has already registered to the ssv.network.
You can keep track of this counter yourself, or you can use the ssv-scanner
tool made available by the SSV team to source it. For more information, please refer to the related user guide or to its SDK documentation page.
βΉοΈ Note: For more details on
operatorsInfoPath
parameter, head over to the Operators data section.
It is also possible to use YAML configuration file. Just pay attention to the path of the necessary files, which needs to be changed to reflect the local configuration.
If the reshare.yaml
file is created in the same folder as the other files, and the folder structure looks like this:
ssv@localhost:~/ssv-dkg# tree initiator-config
initiator-config
βββ encrypted_private_key.json
βββ reshare.yaml
βββ operators_info.json
βββ password
1 directory, 4 files
Then the content of the YAML file should be changed to this:
operatorIDs: [1,2,3,4] # array of Operator IDs that participated in the initial or a previous resharing DKG ceremony
newOperatorIDs: [5, 6, 7, 8] # array of Operator IDs for which the new KeyShares of the existing validator will be generated
oldID: "dbd12b3155454666a6710a2262695bb82cda41948d612d98" # HEX of previous DKG ceremony ID. Can be found in the `keyshares-[validator-pub_key]-[ID].json`
withdrawAddress: "0xa1a66cc5d309f19fb2fda2b7601b223053d0f7f4" # Address where reward payments for the validator are sent
owner: "0xb64923DA2c1A9907AdC63617d882D824033a091c" # Address of owner of the Cluster that will manage the validator on ssv.network
nonce: 0 # Owner nonce for the SSV contract
network: "prater" # Network name (default: mainnet)
operatorsInfoPath: /data/operators_info.json # Path to the file containing operators information
# Alternatively:
# operatorsInfo: '[{"id": 1,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"}, {"id": 2,"public_key": "LS0tLS1CRUdJTiBSU0....","ip": "http://localhost:3030"},...]' # Raw content of the JSON file with operators information
outputPath: /data/output # Path to store the resulting staking deposit and ssv contract payload files
initiatorPrivKey: /data/encrypted_private_key.json # Path to private key of ssv initiator
initiatorPrivKeyPassword: /data/password # Path to password file to decrypt the key
# Alternatively:
# generateInitiatorKey: false # If set true - generates a new RSA key pair + random secure password. The result is stored at `outputPath`
logLevel: info # Logger's log level (default: debug)
logFormat: json # Logger's encoding (default: json)
logLevelFormat: capitalColor # Logger's level format (default: capitalColor)
logFilePath: /data/debug.log # Path to file where logs should be written (default: ./data/debug.log)
A special note goes to the nonce
field, which represents how many validators the address identified in the owner parameter has already registered to the ssv.network.
You can keep track of this counter yourself, or you can use the ssv-scanner
tool made available by the SSV team to source it. For more information, please refer to the related user guide or to its SDK documentation page.
βΉοΈ Note: For more details on
operatorsInfoPath
parameter, head over to the Operators data section.
Then the tool can be launched from the root folder, by running this command:
ssv-dkg init --configPath ./initiator-config/reshare.yaml
If the --configPath
parameter is not provided, ssv-dkg
will be looking for a file named config.yaml
in ./config/
folder at the same root as the binary (i.e. ./config/config.yaml
)
2023-10-11T16:36:26.745937Z FATAL dkg-initiator π₯ Failed to initiate DKG ceremony: {"error": "Post \"http://79.44.117.213:3030/init\": dial tcp 79.44.117.213:3030: i/o timeout"}
When this error appears, it means that the ssv-dkg
tool cannot connect to one of the selected operators.
This could be temporary, but if it persists, we recommend changing one of the operators.
2023-10-11T16:29:47.226138Z FATAL dkg-initiator π₯ Failed to load operators: {"error": "invalid operator URL parse \"80.181.85.114:3030\": invalid URI for request"}
When this error appears, it means that the endpoint information for one of the operators is incorrect.
You could manually verify the operators_info.json
or the initiator command-generated by the webapp, or simply change one of the operators.
2023-10-13T15:21:54.597429Z FATAL dkg-initiator π₯ Failed to initiate DKG ceremony: {"error": "Post \"http://80.181.85.114:3030/init\": dial tcp 80.181.85.114:3030: connect: connection refused"}
When this error appears, it means that the ssv-dkg
tool cannot connect to one of the selected operators, and the reason could be because their ssv-dkg
operator node has shut down.
This could be temporary, as they will likely start the node again, but if it persists, we recommend changing one of the operators.
2023-10-18T12:06:01.946194Z FATAL dkg-initiator π₯ Please provide either private key path or generate command, not both
This error appears when the generateInitiatorKey
argument has been used in conjunction with the initiatorPrivKey
and the initiatorPrivKeyPassword
. These options are mutually exclusive, so please remove one or the other from your YAML config file, or from the command used to launch the initiator.
2023-10-18T12:14:52.667985Z FATAL dkg-initiator π₯ Please provide either operator info string or path, not both
This error appears when the operatorsInfo
argument has been used in conjunction with the operatorsInfoPath
. These options are mutually exclusive, so please remove one or the other from your YAML config file, or from the command used to launch the initiator.
A DKG-Operator is able to participate in multiple DKG ceremonies in parallel thanks to the ssv-dkg
tool.
The ssv-dkg
tool is separate from the ssv-node
, and could be running on a different machine, but the two are heavily correlated, as the keyshare generated by the ssv-dkg
tool, will ultimately be used by the Node itself to manage the related validator.
β οΈ Thessv-dkg
client should be kept online at all times. This is paramount if you want to participate in DKG ceremonies initiated by stakers, thus having the chance to operate their validators. Please select the machine where you want to launch it in accordance to this principle.
In order to successfully participate in DKG ceremonies initiated by stakers, you will need to possess and/or provide this information:
- operator ID - the ID of the operator you want to receive keyshares created with DKG
- machine endpoint - the endpoint (protocol:ip:port) of the machine where you intend to execute the
ssv-dkg
tool (if you have a domain name, instead of anip
that works as well) - encrypted operator RSA private key - this is a password-encrypted file, containing the operator's private key (follow this guide to generate an encrypted private key file or this migration guide to encrypt existing keys)
So make sure to have them available before proceeding.
β οΈ The RSA key pair is needed to sign all of the messages exchanged between ceremony participants, but the public key linked to it will also be used to encrypt the generated keyshares. Thus, SSV Node Operators must use the private key already in their possession when running the DKG tool, otherwise they won't be able to decrypt the keyshare and perform validator duties.
There are a couple of options to launch the DKG tool:
It is advised launching the tool as a Docker image as it is the most convenient way and only requires to have Docker installed. The team builds a Docker image with every release of the tool.
All of the necessary configuration information can be provided in a YAML file (referenced as operator.yaml
from now on).
A good way to manage all the necessary files (encrypted_private_key.json
, password
) is to store them in a single folder (in this case operator-config
), together with the operator.yaml
configuration file, like so:
ssv@localhost:~/ssv-dkg# tree operator-config
operator-config
βββ encrypted_private_key.json
βββ operator.yaml
βββ password
1 directory, 3 files
With this configuration, a typical configuration file would look like this:
operatorPrivKey: /data/encrypted_private_key.json
operatorPrivKeyPassword: /data/password
port: 3030
storeShare: true
logLevel: info
logFormat: json
logLevelFormat: capitalColor
logFilePath: /data/debug.log
outputPath: ./output
βΉοΈ In the config file above,
/data/
represents the container's shared volume created by the docker command itself with the-v
option.
Under the assumption that all the necessary files (encrypted_private_key.json
, operator.yaml
, password
) are under the same folder (represented below with <PATH_TO_FOLDER_WITH_CONFIG_FILES>
) you can run the tool using the command below:
docker run --restart unless-stopped --name ssv_dkg -p 3030:3030 \
-v "<PATH_TO_FOLDER_WITH_CONFIG_FILES>":/data -it \
"bloxstaking/ssv-dkg:latest" /app start-operator --configPath /data/operator.yaml
Just make sure to substitute <PATH_TO_FOLDER_WITH_CONFIG_FILES>
with the actual folder containing all the files.
You can, of course, change the configuration above to one that suits you better, just be mindful about changing the path references in the docker command and in the `operator.yaml`` file as well.
To build from source you'll need to have Go version 1.20 installed on your system
A prerequisite for this is to have go
version 1.20 installed on the system, and an optional requirement is to have the make
tool installed as well (alternatively you could run the corresponding command defined in the Makefile
).
make install
It is advised to store all the necessary files (encrypted_private_key.json
, password
) in a single folder (in this case operator-config
), as shown below:
ssv@localhost:~/ssv-dkg# tree operator-config
operator-config
βββ encrypted_private_key.json
βββ password
1 directory, 2 files
To run the DKG tool as an operator, you can launch the following command with the appropriate values to each parameter:
ssv-dkg start-operator \
--operatorPrivKey ./operator-config/encrypted_private_key.json \
--operatorPrivKeyPassword ./operator-config/password \
--port 3030 \
--storeShare true \
--logLevel info \
--logFormat json \
--logLevelFormat capitalColor \
--logFilePath ./operator-config/debug.log
--DBPath ./output/operator1_db/
--outputPath /output
Here's an explanation of each parameter:
Argument | type | description |
---|---|---|
--privKey | string | Private key of ssv operator (path, or plain text, if not encrypted) |
--port | int | Port for listening messages (default: 3030 ) |
--password | string | Path to password file to decrypt the key (if absent, provide plain text private key) |
--storeShare | boolean | Whether to store the created bls key share to a file for later reuse if needed (default: false ) |
--outputPath | string | Path to store the output files (ecrypted share) |
--logLevel | debug / info / warning / error / critical | Logger's log level (default: debug ) |
--logFormat | json / console | Logger's encoding (default: json ) |
--logLevelFormat | capitalColor / capital / lowercase | Logger's level format (default: capitalColor ) |
--logFilePath | string | Path to file where logs should be written (default: ./data/debug.log ) |
--DBPath | string | Path to folder where Badger DB should be written (default: ./data/db.log ) |
It is also possible to use YAML configuration file, just as it was shown in the Docker section above. Just pay attention to the path of the necessary files, which needs to be changed to reflect the local configuration. If the operator.yaml file is created in the same folder as the other files, and the folder structure looks like this:
ssv@localhost:~/ssv-dkg# tree operator-config
operator-config
βββ encrypted_private_key.json
βββ operator.yaml
βββ password
1 directory, 3 files
Then the content of the YAML file should be changed to this:
privKey: ./operator-config/encrypted_private_key.json
password: ./operator-config/password
port: 3030
storeShare: true
logLevel: info
logFormat: json
logLevelFormat: capitalColor
logFilePath: ./operator-config/debug.log
outputPath: ./output
Then the tool can be launched from the root folder, by running this command:
ssv-dkg start-operator --configPath "./operator-config/operator.yaml"
If the --configPath
parameter is not provided, ssv-dkg
will be looking for a file named operator.yaml
in ./config/
folder at the same root as the binary (i.e. ./config/operator.yaml
)
β οΈ If you want to make sure to participate in DKG ceremonies initiated by stakers, and have the chance to operate their validators, it is absolutely necessary to the update operator with the proper information, and verify their correctness.
Once the DKG tool is up and running, please make sure to update your operator metadata, and provide your DKG Operator endpoint, in the form of protocol:ip:port
(if you have a domain name, instead of an ip
that works as well).
Please head over to the Operator User guide on how to update metadata and follow the instructions
To run localy an example with 4 operators. Configuration files: examples/config
- Build the image
make docker-build-image # build the Docker image
- Run 4 operators locally
make docker-demo-operators # run 4 local operators
- In a separate terminal window, run inititator
make docker-demo-initiator # run 1 local initiator
Results will be placed to examples/output
- The Initiator creates an initiation (
init
) message, signs it and sends it to all Operators - Upon receiving initiation message, the Operators check Initiator message signature and create their own DKG identity:
- new DKG secrets created
- if a new
init
message with ID [24]byte is received and at least 5 minutes have passed from the last init message with the same ID, the DKG instance is recreated - Exchange signed message containing the DKG identity is created
- Operator replies to init message with the created Exchange message
- The Initiator collects all responses into one combined message and verifies signatures
- The Initiator sends back the combined message to all Operators
- Each Operator receives combined exchange message and starts the DKG process, responding back to Initiator with a signed dkg deal bundle
- The Initiator packs the deal bundles together and sends them back to all Operators
- Operators process dkg bundles and finish the DKG protocol of creating a shared key. After DKG process is finished each Operator has a share of the shared key which can be used for signing
- Each Operator signs a deposit root, using its share of the shared key, then encrypts the share with the initial RSA key and sends it to the Initiator
- Initiator receives all messages from Operators with signatures/encrypted shares and prepares the deposit data with a signature and save it as JSON file
- Initiator prepares a payload for SSV contract
- After the deposit is successful and SSV contract transaction is accepted, Operators can continue with their duties using their share of the distributes key
βΉοΈ NOTE: Threshold is computed automatically using 3f+1 tolerance.
A DKG-operator can handle multiple DKG instances, it saves up to MaxInstances
(1024) up to MaxInstanceTime
(5 minutes). If a new init
arrives the DKG-operator tries to clean instances older than MaxInstanceTime
from the list. If any of them are found, they are removed and the incoming is added, otherwise it responds with an error, saying that the maximum number of instances is already running.
It is important to briefly explain how the communication between DKG ceremony Initiator and Operators is secured:
- Initiator is using RSA key (2048 bits) to sign init message sent to Operators. Upon receiving the signature, Operators verify it using public key included in the init message. If the signature is valid, Operators store this pub key for further verification of messages coming from the Initiator(s).
- Operators are using RSA key (ssv Operator key - 2048 bits) to sign every message sent back to Initiator.
- Initiator verifies every incoming message from any Operator using ID and Public Key provided by Operators' info file, then Initiator creates a combined message and signs it.
- Operators verify each of the messages from other Operators participating in the ceremony and verifies Initiator's signature of the combined message.
- During the DKG protocol execution, the BLS auth scheme is used - G2 for its signature space and G1 for its public keys
More info about how things are designed/work under the hood can be found here