Skip to main content

Overview

The generate-operator-keys command generates cryptographic keys for your SSV operator. These keys are used to decrypt validator share data from SSV contract events. The command supports three modes:
  1. Raw key generation (default, not recommended for production)
  2. Encrypted keystore generation (recommended for production)
  3. Convert existing raw key to encrypted keystore
Raw format is NOT recommended for production use as it can expose sensitive data. Always use encrypted keystore format for production deployments.

Usage

ssvnode generate-operator-keys [flags]

Flags

--password-file
string
default:""
Path to file containing the password used to encrypt the private key.When provided, the command generates an encrypted keystore JSON file instead of raw keys.Alias: -p
ssvnode generate-operator-keys --password-file=password.txt
--operator-key-file
string
default:""
Path to an existing operator private key file to convert to encrypted format.Use with --password-file to encrypt an existing raw key.Alias: -o
ssvnode generate-operator-keys --operator-key-file=raw_key.txt --password-file=password.txt
--legacy-pubkey
boolean
default:"false"
Store public key in keystore using legacy format ("pubKey" instead of "pubkey").Only use if you need compatibility with older SSV versions.Alias: -l
ssvnode generate-operator-keys --password-file=password.txt --legacy-pubkey
This mode generates unencrypted keys. Do not use in production!
Generate a new operator key pair in raw (base64-encoded) format:
./bin/ssvnode generate-operator-keys

Output

generated public key (base64)  pk=LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdr...
generated private key (base64) sk=LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0N...
The output shows:
  • pk - Public key (base64-encoded)
  • sk - Private key (base64-encoded)
The private key can be used directly in config.yaml under OperatorPrivateKey, but this is not secure for production.
Generate a new operator key encrypted with a password:

Step 1: Create Password File

echo "YourSecurePassword123!" > password.txt
chmod 600 password.txt

Step 2: Generate Encrypted Keystore

./bin/ssvnode generate-operator-keys --password-file=password.txt

Output

private key encrypted and stored in encrypted_private_key.json
The command creates encrypted_private_key.json containing your encrypted operator key:
encrypted_private_key.json
{
  "version": 4,
  "pubkey": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0t...",
  "crypto": {
    "cipher": "aes-128-ctr",
    "cipherparams": {
      "iv": "264daa3f303d7259501c93d997d84fe6"
    },
    "ciphertext": "8c9b4c...",
    "kdf": "scrypt",
    "kdfparams": {
      "dklen": 32,
      "n": 262144,
      "p": 1,
      "r": 8,
      "salt": "d4e56740f876aef8..."
    },
    "mac": "2103ac29920d71da29f15d..."
  }
}

Step 3: Configure Your Node

Reference the encrypted keystore in your config.yaml:
config.yaml
KeyStore:
  PrivateKeyFile: ./encrypted_private_key.json
  PasswordFile: ./password.txt

ssv:
  Network: mainnet

eth2:
  BeaconNodeAddr: http://localhost:5052

eth1:
  ETH1Addr: ws://localhost:8546/ws

Mode 3: Convert Existing Key to Encrypted Format

If you already have a raw operator key, convert it to encrypted format:

Step 1: Save Your Raw Key

echo "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ..." > raw_operator_key.txt

Step 2: Create Password File

echo "YourSecurePassword123!" > password.txt
chmod 600 password.txt

Step 3: Convert to Encrypted Keystore

./bin/ssvnode generate-operator-keys \
  --operator-key-file=raw_operator_key.txt \
  --password-file=password.txt

Output

private key encrypted and stored in encrypted_private_key.json
The encrypted keystore is created with the same keys as your raw key, now securely encrypted.

Security Best Practices

  • Use strong, unique passwords (minimum 12 characters)
  • Never reuse passwords across operators
  • Store password files separately from keystore files
  • Use password managers for production environments
  • Set restrictive permissions: chmod 600 password.txt
# Set restrictive permissions on keystore
chmod 600 encrypted_private_key.json

# Verify permissions
ls -la encrypted_private_key.json
# Should show: -rw------- (only owner can read/write)
What to backup:
  • encrypted_private_key.json (encrypted keystore)
  • password.txt (password file)
  • Public key (from initial generation or from keystore)
Backup storage:
  • Store backups in separate, secure locations
  • Use encrypted backup solutions
  • Never commit to version control systems
  • Consider hardware security modules (HSM) for production
Bad - Raw key in config:
OperatorPrivateKey: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ...
Good - Encrypted keystore:
KeyStore:
  PrivateKeyFile: ./encrypted_private_key.json
  PasswordFile: ./password.txt

Examples

Generate New Encrypted Operator Key

# Create password file
echo "MySecurePassword123!" > password.txt

# Generate encrypted keystore
./bin/ssvnode generate-operator-keys --password-file=password.txt

# Verify keystore was created
ls -la encrypted_private_key.json

# Extract public key from keystore for registration
jq -r '.pubkey' encrypted_private_key.json

Convert Raw Key to Encrypted

# You have a raw key from earlier generation
cat raw_key.txt
# LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ...

# Create password file
echo "MySecurePassword123!" > password.txt

# Convert to encrypted keystore
./bin/ssvnode generate-operator-keys \
  --operator-key-file=raw_key.txt \
  --password-file=password.txt

# Remove raw key file (no longer needed)
shred -u raw_key.txt

Generate with Legacy Public Key Format

# For compatibility with older SSV versions
./bin/ssvnode generate-operator-keys \
  --password-file=password.txt \
  --legacy-pubkey

# Keystore will use "pubKey" instead of "pubkey"
jq '.pubKey' encrypted_private_key.json

Using Environment Variables

# Create password file from environment
echo "$OPERATOR_PASSWORD" > /tmp/password.txt

# Generate keystore
./bin/ssvnode generate-operator-keys --password-file=/tmp/password.txt

# Move to secure location
mv encrypted_private_key.json /secure/path/
mv /tmp/password.txt /secure/path/password.txt

# Set permissions
chmod 600 /secure/path/encrypted_private_key.json
chmod 600 /secure/path/password.txt

Output Files

Encrypted Keystore JSON

When using --password-file, the command creates encrypted_private_key.json:
FieldDescription
versionKeystore version (4 = EIP-2335 compatible)
pubkeyBase64-encoded public key
crypto.cipherEncryption algorithm (aes-128-ctr)
crypto.ciphertextEncrypted private key data
crypto.kdfKey derivation function (scrypt)
crypto.kdfparamsKDF parameters (n, r, p, salt)
crypto.macMessage authentication code for verification

Console Output

Without --password-file, keys are printed to console:
generated public key (base64)  pk=LS0tLS1CRUdJTi...
generated private key (base64) sk=LS0tLS1CRUdJTi...
Console output may be logged by your terminal. Use encrypted keystores to avoid exposing keys.

Troubleshooting

Failed to read password file: no such file or directory
Solution: Ensure the password file exists and path is correct:
ls -la password.txt
./bin/ssvnode generate-operator-keys --password-file=./password.txt
Failed to parse private key
Solution: Ensure your operator key file contains valid base64-encoded RSA key:
# Check file contents
cat raw_key.txt
# Should start with: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ==
Failed to save private key: permission denied
Solution: Check write permissions in current directory:
# Check permissions
ls -ld .

# Or specify writable directory
cd /path/to/writable/directory
./bin/ssvnode generate-operator-keys --password-file=password.txt
If your password file is empty, the encryption will still work but with an empty password:
# Verify password file has content
cat password.txt
# Should output your password

# Check file size
wc -c password.txt
# Should be > 0 bytes

Using Generated Keys

In Configuration File

config.yaml
# Recommended: Use encrypted keystore
KeyStore:
  PrivateKeyFile: ./encrypted_private_key.json
  PasswordFile: ./password.txt

# OR (not recommended for production)
OperatorPrivateKey: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ...

Extract Public Key

Your public key is needed for operator registration:
# From encrypted keystore
jq -r '.pubkey' encrypted_private_key.json

# From raw generation (saved during initial output)
echo "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0t..."

See Also

Build docs developers (and LLMs) love