zeekay 82bd565201 mpc: deployment-mode flag + audit dispatcher for fund-private clusters
Adds the topology contract that lets a fund run mpcd as its own private
cluster — no Lux primary network registration, no shared M-Chain audit
ledger — using the same code path and the same operator surface.

Mode flag at cmd/mpcd/main.go:
  --network=primary|private              # registration target
  --audit-store=mchain|local-worm|...    # audit log destination
  --registrar-url, --registrar-auth      # primary-mode announcement
  --audit-worm-path, --audit-mchain-url  # backend selectors

pkg/audit:
  - Append-only Merkle hash chain. Tampering with any historical event
    invalidates every subsequent hash. Canonical bytes use fixed-order
    concatenation (json.Marshal map ordering is non-deterministic).
  - WORMDispatcher: NDJSON append, replay-on-start, fsync per Append.
  - MChainDispatcher: batched POST of (batchHash, fromSeq, toSeq) to a
    configurable anchor RPC.
  - compositeDispatcher: fan-out to multiple legs with per-leg sealing.
  - S3 Glacier Vault / Azure Immutable / GCS Object Lock dispatchers
    fail closed — wired into the flag surface but gated behind the
    cloud-audit build tag, no silent fallback.

pkg/identity/bootstrap.go: identity creation + (primary-mode only)
registrar announcement. Same on-disk format as the previous
loadOrGenerateIdentity (which is now removed); private mode is silent.

deployments/k8s-private: fund-only Kustomize overlay. Standalone
namespace, NetworkPolicy that blocks egress to anything outside the
fund's VPC, hardware-WORM PVC for the audit log, KMS-driven secret
template.

deployments/k8s-primary: env-var patch overlay on the existing lux-mpc
base. composite(local-worm,mchain) by default.

deployments/terraform/{aws,gcp,azure}: VPC + audit storage modules.
terraform validate passes; EKS/GKE/AKS + HSM modules are stubbed and
not yet plan-tested.

deployments/onprem/README.md: WORM storage + PKCS#11 HSM checklist.

Tests (14 total, all passing):
  pkg/audit:           6/6  (chain, WORM replay, MChain batching, composite,
                             cloud stubs fail loud, double-seal rejected)
  pkg/identity:        4/4  (private no-call, primary call, primary empty
                             URL no-op, primary registrar 503 surfaces)
  internal/privatemode: 4/4 (no registrar traffic, restart, tamper-detect,
                             cloud stubs fail loud)

Companion runbook in lux/papers/lux-private-mpc-deployment/
(LaTeX, 5 pages, tectonic-clean).
2025-12-28 16:20:40 -08:00
2025-05-02 20:37:09 +07:00
2025-12-28 13:48:21 -08:00
2025-12-31 22:21:37 -08:00

MPC

Threshold signing engine -- CGGMP21 (ECDSA), FROST (EdDSA), BLS, and SR25519. No full private key reconstruction, ever.

go get github.com/luxfi/mpc

Architecture

luxfi/mpc is a production MPC node (mpcd) that performs distributed key generation and threshold signing across a cluster. Each node holds a key share; t of n nodes must cooperate to produce a signature. The full private key never exists on any single machine, in memory or on disk.

Protocols

Protocol Curve Key Type Use
CGGMP21 secp256k1 secp256k1 Bitcoin, Ethereum, Lux C-Chain, all EVM L2s, XRPL
FROST Ed25519 ed25519 Solana, TON, Polkadot, Cardano, Substrate chains
BLS BLS12-381 bls Lux consensus, beacon chain, aggregated signatures
SR25519 Ristretto255 sr25519 Substrate/Polkadot native

Threshold Model

t >= floor(n/2) + 1

A 2-of-3 cluster tolerates 1 compromised or offline node. A 3-of-5 cluster tolerates 2. The threshold is configurable at key generation time.

Transport Modes

Consensus (default): Peer-to-peer ZAP protocol with built-in PoA consensus. No external dependencies. Nodes discover each other via --peer flags. This is the production path.

Legacy: NATS pub/sub + Consul service discovery. Deprecated but still supported via --mode=legacy.

Packages

cmd/mpcd/            Daemon binary (CLI, API server, node lifecycle)
pkg/mpc/             Core MPC node -- session management, key generation, signing
  keygen_session.go    CGGMP21 distributed key generation
  signing_session.go   CGGMP21 threshold signing (secp256k1)
  signing_session_frost.go  FROST threshold signing (Ed25519)
  bls_keygen_session.go     BLS key generation
  bls_signing_session.go    BLS threshold signing
  sr25519_keygen_session.go SR25519 key generation
  sr25519_signing_session.go SR25519 threshold signing
  reshare_session.go   Key resharing (rotate shares without changing public key)
  recovery.go          Key share recovery
  tfhe_session.go      FHE threshold decryption sessions
pkg/api/             HTTP API (key generation, signing, key info, health)
pkg/transport/       P2P transport (consensus mode ZAP, legacy NATS)
pkg/messaging/       PubSub abstraction over transport layer
pkg/db/              Key share storage (SQLite default, PostgreSQL optional)
pkg/kvstore/         Encrypted key-value store (AES-256, age encryption)
pkg/keyinfo/         Key metadata management
pkg/identity/        Node identity (Ed25519 keypair, mutual authentication)
pkg/backup/          Encrypted periodic backups
pkg/encryption/      AES-256-GCM encryption for key material at rest
pkg/kms/             KMS integration for secret management
pkg/hsm/             HSM provider abstraction (env, AWS, GCP)
pkg/client/          Go client library for MPC API
pkg/event/           Event types (keygen, sign, reshare)
pkg/eventconsumer/   Event processing pipeline
pkg/protocol/        Wire protocol messages
pkg/settlement/      Trade settlement signing
pkg/smart/           Smart contract transaction construction
pkg/custody/         Custody policy engine
pkg/integrity/       Key share integrity verification
pkg/txtracker/       Transaction lifecycle tracking

Security Properties

  • Key shares encrypted at rest with AES-256-GCM (key from HSM/KMS)
  • Inter-node messages authenticated with Ed25519 signatures
  • No key share leaves the node unencrypted
  • Resharing rotates shares without changing the public key or requiring all nodes
  • Backup files encrypted with age (modern, audited encryption)
  • Secret key bytes zeroed from memory after use (pkg/mpc/secret.go)

Quick Start

# Node 0
mpcd start --node-id node0 --listen :9999 --api :9800 \
  --threshold 2 --peer node1:9999 --peer node2:9999

# Node 1
mpcd start --node-id node1 --listen :9999 --api :9801 \
  --threshold 2 --peer node0:9999 --peer node2:9999

# Node 2
mpcd start --node-id node2 --listen :9999 --api :9802 \
  --threshold 2 --peer node0:9999 --peer node1:9999

Generate a Wallet

curl -X POST http://localhost:9800/v1/keygen \
  -H "Content-Type: application/json" \
  -d '{"wallet_id": "w-001", "key_type": "secp256k1"}'

Sign a Transaction

curl -X POST http://localhost:9800/v1/sign \
  -H "Content-Type: application/json" \
  -d '{"wallet_id": "w-001", "message": "0xdeadbeef...", "key_type": "secp256k1"}'

Go Client

import "github.com/luxfi/mpc/pkg/client"

c := client.New("http://localhost:9800")
result, err := c.CreateWallet("w-001", "secp256k1")
sig, err := c.Sign("w-001", txHash, "secp256k1")

Configuration

config.yaml or environment variables (LUX_MPC_*):

mode: consensus
environment: local          # mainnet | testnet | local
mpc_threshold: 2
max_concurrent_keygen: 2
db_path: "."                # SQLite (default), or postgres:// URL
backup_enabled: true
backup_period_seconds: 300
backup_dir: backups

All secrets are sourced from KMS via --hsm-provider=env|aws|gcp. No plaintext secrets in config.

Deployment

Docker Compose

docker compose up

Kubernetes

cd k8s && kubectl kustomize . | kubectl apply -f -

K8s manifests are in k8s/ with Kustomize overlays. Production deployment uses cloudbuild.yaml for CI/CD to GHCR.

Testing

go test ./...       # 331 test functions

# End-to-end (3-node cluster)
cd e2e && make test

Papers

Dependencies

License

Lux Ecosystem License v1.2. See LICENSE.

S
Description
▼ LUX multi-party compute nodes / wallet service using CGGMP21, FROST protocol
Readme
47 MiB
Languages
Go 83.8%
TypeScript 14%
Shell 0.9%
Solidity 0.7%
HCL 0.2%
Other 0.2%