mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
203 lines
6.5 KiB
Bash
Executable File
203 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Initialize a 3-of-5 MPC cluster for Customer + Lux topology.
|
|
#
|
|
# This script:
|
|
# 1. Generates Ed25519 identity keypairs for all 5 nodes
|
|
# 2. Creates key directories for compose.yml volume mounts
|
|
# 3. Generates a peer configuration file
|
|
# 4. Prints instructions for DKG and KMS registration
|
|
#
|
|
# Prerequisites:
|
|
# - Go toolchain (for keygen via mpcd)
|
|
# - openssl (for Ed25519 key generation)
|
|
#
|
|
# Usage:
|
|
# ./init.sh # Interactive: generates all keys locally
|
|
# ./init.sh --lux-only # Generate only Lux node keys (customer generates theirs)
|
|
# ./init.sh --customer-only # Generate only customer node keys
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
KEYS_DIR="${SCRIPT_DIR}/keys"
|
|
|
|
NODES_LUX=(lux-0 lux-1 lux-2)
|
|
NODES_CUSTOMER=(cust-0 cust-1)
|
|
THRESHOLD=3
|
|
TOTAL=5
|
|
|
|
MODE="${1:-all}"
|
|
|
|
log() { echo "[init] $*"; }
|
|
err() { echo "[init] ERROR: $*" >&2; exit 1; }
|
|
|
|
# Generate an Ed25519 keypair and write to directory.
|
|
# Args: $1 = node ID, $2 = output directory
|
|
generate_identity() {
|
|
local node_id="$1"
|
|
local key_dir="$2"
|
|
|
|
mkdir -p "${key_dir}"
|
|
|
|
# Generate Ed25519 private key (64 bytes: seed + public)
|
|
openssl genpkey -algorithm Ed25519 -out "${key_dir}/identity.pem" 2>/dev/null
|
|
|
|
# Extract raw private key (32-byte seed)
|
|
openssl pkey -in "${key_dir}/identity.pem" -outform DER 2>/dev/null | \
|
|
tail -c 32 | xxd -p -c 64 > "${key_dir}/identity.key"
|
|
|
|
# Extract public key (32 bytes)
|
|
openssl pkey -in "${key_dir}/identity.pem" -pubout -outform DER 2>/dev/null | \
|
|
tail -c 32 | xxd -p -c 64 > "${key_dir}/identity.pub"
|
|
|
|
# Write node ID
|
|
echo "${node_id}" > "${key_dir}/node-id"
|
|
|
|
local pubkey
|
|
pubkey=$(cat "${key_dir}/identity.pub")
|
|
log " ${node_id}: pubkey=${pubkey}"
|
|
}
|
|
|
|
# Generate ZapDB password (32 bytes, hex-encoded for AES-256)
|
|
generate_zapdb_password() {
|
|
local node_id="$1"
|
|
local key_dir="$2"
|
|
openssl rand -hex 32 > "${key_dir}/zapdb-password"
|
|
log " ${node_id}: zapdb password generated"
|
|
}
|
|
|
|
# Write .env file for compose.yml
|
|
write_env_file() {
|
|
local env_file="${SCRIPT_DIR}/.env"
|
|
log "Writing ${env_file}"
|
|
|
|
{
|
|
echo "# Generated by init.sh -- DO NOT COMMIT"
|
|
echo "# Store these values in KMS for production."
|
|
for node in "${NODES_LUX[@]}" "${NODES_CUSTOMER[@]}"; do
|
|
local var_name
|
|
var_name="ZAPDB_PASSWORD_$(echo "${node}" | tr '[:lower:]-' '[:upper:]_')"
|
|
echo "${var_name}=$(cat "${KEYS_DIR}/${node}/zapdb-password")"
|
|
done
|
|
echo ""
|
|
echo "# Set these manually:"
|
|
echo "MPC_API_TOKEN="
|
|
echo "MPC_VAULT_ID="
|
|
} > "${env_file}"
|
|
|
|
chmod 600 "${env_file}"
|
|
}
|
|
|
|
# Write peer registry JSON (consumed by mpcd for initial peer discovery)
|
|
write_peer_config() {
|
|
local config_file="${SCRIPT_DIR}/peers.json"
|
|
log "Writing ${config_file}"
|
|
|
|
echo "{" > "${config_file}"
|
|
echo ' "threshold": '"${THRESHOLD}"',' >> "${config_file}"
|
|
echo ' "peers": {' >> "${config_file}"
|
|
|
|
local all_nodes=("${NODES_LUX[@]}" "${NODES_CUSTOMER[@]}")
|
|
local count=${#all_nodes[@]}
|
|
for i in "${!all_nodes[@]}"; do
|
|
local node="${all_nodes[$i]}"
|
|
local pubkey
|
|
pubkey=$(cat "${KEYS_DIR}/${node}/identity.pub")
|
|
local comma=","
|
|
if [ "$((i + 1))" -eq "${count}" ]; then
|
|
comma=""
|
|
fi
|
|
echo " \"${node}\": {\"pubkey\": \"${pubkey}\"}${comma}" >> "${config_file}"
|
|
done
|
|
|
|
echo ' }' >> "${config_file}"
|
|
echo '}' >> "${config_file}"
|
|
}
|
|
|
|
# Main
|
|
log "Initializing 3-of-5 MPC cluster (threshold=${THRESHOLD}, total=${TOTAL})"
|
|
log "Mode: ${MODE}"
|
|
log "Keys directory: ${KEYS_DIR}"
|
|
echo ""
|
|
|
|
case "${MODE}" in
|
|
all|--all)
|
|
log "Generating Lux node identities..."
|
|
for node in "${NODES_LUX[@]}"; do
|
|
generate_identity "${node}" "${KEYS_DIR}/${node}"
|
|
generate_zapdb_password "${node}" "${KEYS_DIR}/${node}"
|
|
done
|
|
|
|
echo ""
|
|
log "Generating customer node identities..."
|
|
for node in "${NODES_CUSTOMER[@]}"; do
|
|
generate_identity "${node}" "${KEYS_DIR}/${node}"
|
|
generate_zapdb_password "${node}" "${KEYS_DIR}/${node}"
|
|
done
|
|
;;
|
|
|
|
--lux-only)
|
|
log "Generating Lux node identities only..."
|
|
for node in "${NODES_LUX[@]}"; do
|
|
generate_identity "${node}" "${KEYS_DIR}/${node}"
|
|
generate_zapdb_password "${node}" "${KEYS_DIR}/${node}"
|
|
done
|
|
;;
|
|
|
|
--customer-only)
|
|
log "Generating customer node identities only..."
|
|
for node in "${NODES_CUSTOMER[@]}"; do
|
|
generate_identity "${node}" "${KEYS_DIR}/${node}"
|
|
generate_zapdb_password "${node}" "${KEYS_DIR}/${node}"
|
|
done
|
|
;;
|
|
|
|
*)
|
|
err "Unknown mode: ${MODE}. Use: all, --lux-only, --customer-only"
|
|
;;
|
|
esac
|
|
|
|
echo ""
|
|
|
|
# Write configs if all keys exist
|
|
if [ -d "${KEYS_DIR}/lux-0" ] && [ -d "${KEYS_DIR}/cust-0" ]; then
|
|
write_peer_config
|
|
write_env_file
|
|
fi
|
|
|
|
echo ""
|
|
log "========================================="
|
|
log "Initialization complete."
|
|
log ""
|
|
log "Next steps:"
|
|
log ""
|
|
log " 1. Start the cluster:"
|
|
log " docker compose up -d"
|
|
log ""
|
|
log " 2. Verify all nodes are healthy:"
|
|
log " for port in 9800 9801 9802 9810 9811; do"
|
|
log " echo \"Port \${port}: \$(curl -s http://localhost:\${port}/health)\""
|
|
log " done"
|
|
log ""
|
|
log " 3. Run DKG (distributed key generation):"
|
|
log " curl -X POST http://localhost:9800/keygen \\"
|
|
log " -H 'Content-Type: application/json' \\"
|
|
log " -d '{\"keyId\":\"main\",\"threshold\":3,\"parties\":5,\"curve\":\"secp256k1\"}'"
|
|
log ""
|
|
log " 4. Register the generated key in KMS:"
|
|
log " curl -X POST http://localhost:8080/keys \\"
|
|
log " -H 'Content-Type: application/json' \\"
|
|
log " -d '{\"name\":\"customer-main\",\"type\":\"mpc\",\"keyId\":\"main\"}'"
|
|
log ""
|
|
log " 5. For Safe integration, generate 3 FROST keys:"
|
|
log " for key in safe-owner-ops safe-owner-dao safe-owner-recovery; do"
|
|
log " curl -X POST http://localhost:9800/keygen \\"
|
|
log " -H 'Content-Type: application/json' \\"
|
|
log " -d \"{\\\"keyId\\\":\\\"\${key}\\\",\\\"threshold\\\":3,\\\"parties\\\":5,\\\"curve\\\":\\\"secp256k1\\\",\\\"protocol\\\":\\\"frost\\\"}\""
|
|
log " done"
|
|
log ""
|
|
log " IMPORTANT: Store ZapDB passwords and identity keys in KMS."
|
|
log " The .env file and keys/ directory contain secrets."
|
|
log " DO NOT commit them to git."
|
|
log "========================================="
|