Commit Graph
39 Commits
Author SHA1 Message Date
zeekay 1dc9a9e6f2 feat(zap): adopt canonical port 9999 across MPC + transport
ZAP is the binary protocol — like HTTP=80 and HTTPS=443, ZAP=9999
across the Lux ecosystem. The DNS name (e.g. zap.kms.svc, zap.mpc.svc,
mpc-node-headless.lux-mpc.svc) disambiguates the service; the port is
always the same.

Changes:
- mpcd --listen default :9651 → :9999
- pkg/transport/{transport,factory}.go: comments and examples
- k8s/mpc-statefulset.yaml: ports + peer template
- k8s/network-policy.yaml: ingress/egress allow rules
- cloudbuild.yaml: EXPOSE
- deployments/customer-3of5/{compose.yml,k8s/*,topology.yaml}: full
  template sweep — every peer hostname is distinct, port is uniform 9999
- README.md / LLM.md: example commands

luxd validator P2P (9631 mainnet, 9641 testnet, 9651 devnet) is a
DIFFERENT protocol on a DIFFERENT pod and is unchanged.
2025-12-28 15:07:49 -08:00
zeekay 0d917ec271 fix(mpc): HasSigningQuorum uses operator-facing threshold semantics
Follow-up to 5215d42. The CLI/CRD `--threshold` flag surfaces the
OPERATOR-facing "minimum signers required" count (e.g. threshold=2 for
a 2-of-3 ensemble, threshold=3 for 3-of-5). The CGGMP21 signing API
internally stores the polynomial degree (one below signers-required)
in keyInfo.Threshold — so the sign code continues to compare
`len(signerPeerIDs) >= keyInfo.Threshold + 1`. Those two surfaces are
off-by-one by protocol library convention.

HasSigningQuorum is operator-facing (used by /healthz) so it uses the
CRD/CLI semantics directly: quorum holds when `readyCount >= threshold`.

Scientist's repro: 3-node 2-of-3 ensemble (CRD threshold=2) with one
peer down — readyCount=2, threshold=2 → quorum holds, /healthz returns
200. With the previous commit the arithmetic was readyCount>=threshold+1
which would have required all 3 nodes up.

Tests updated accordingly (Test_HasSigningQuorum_3Node_2of3 now uses
threshold=2 matching the deployed CRD, Test_HasSigningQuorum_5Node_3of5
uses threshold=3, boundary test covers the new arithmetic).
2025-12-28 13:02:00 -08:00
zeekay 5215d4275d fix(mpc): /healthz reports quorum — not all-peers-ready (P0-1)
Survivor nodes in a t-of-n ensemble now report healthy so long as they
still have enough ready peers (including self) to form a signing quorum
for their configured threshold. Previously, ArePeersReady() was the gate
and any single peer loss collapsed availability on the remaining nodes.

Repro (Scientist, 2026-04-20): scale liquid-mpc-mpc-node StatefulSet
from 3 → 2 replicas in the liquidity devnet; surviving pods returned HTTP
503 with log "Peers not ready expected=3 ready=2" even though 2 nodes
are sufficient for the 2-of-3 (threshold=1) signing quorum.

Fix:

- pkg/transport/registry.go: add HasSigningQuorum(threshold) which returns
  true when readyCount >= threshold+1 (the CGGMP21/FROST signers-required
  count used everywhere in pkg/mpc/node.go).
- pkg/mpc/registry.go: matching method on the legacy Consul-backed
  registry plus interface addition to PeerRegistry.
- cmd/mpcd/main.go: /healthz handler switched to HasSigningQuorum(threshold)
  for the 200/503 gate. ArePeersReady() is still reported in the JSON
  body (as `ready`) for observability. `status` becomes
  "healthy" / "healthy-reduced" / "degraded" so operators can see the
  in-between state.
- cmd/mpcd/main.go: ConsensusPeerRegistry wrapper delegates the new
  method to the underlying transport registry.

Keygen sessions deliberately continue to require ArePeersReady() — a
fresh wallet still needs every participant present. Only the /healthz
gate is relaxed, which matches the availability story for signing.

Tests: pkg/transport/registry_test.go covers
- Test_HasSigningQuorum_3Node_2of3 (the Scientist repro — survivors
  still quorum-ok after one peer loss)
- Test_HasSigningQuorum_5Node_3of5 (larger ensemble, f=2 tolerance)
- Test_HasSigningQuorum_ArePeersReady_Decoupled (the two APIs do not
  gate each other)
- Test_HasSigningQuorum_BoundaryCheck (pins arithmetic: required =
  threshold+1, not threshold)

All 11 test cases pass; transport + mpc package suites clean.
2025-12-28 12:55:23 -08:00
zeekay a420490996 feat(ui): embedded MPC admin dashboard — @hanzo/gui + go:embed
Vite + React SPA with 9 pages (Dashboard, Wallets, Vaults, Policies,
Settlements, Bridge, Payments, Audit, Settings) served at /_/mpc/ via
go:embed. Replaces the separate Next.js dashboard pod — the UI now ships
inside the mpcd binary. Uses @tanstack/react-query, wouter hash router,
dark theme, inline styles. Build output: 272KB.
2025-12-27 21:28:17 -08:00
zeekay 847ddebc2e fix: remove postgres/valkey/legacy mode — consensus+ZapDB only
- Removed --mode, --api-db, --api-kv, --db flags
- Removed legacy NATS/Consul transport (runNode, ~200 lines)
- Removed standalone API server (runAPIOnly, ~200 lines)
- Removed Consul helpers, NATS connection, interactive prompts
- Dashboard now uses ZapDB (SQLite) instead of postgres
- pkg/db: removed postgres backend, removed valkey client
- Consensus mode is the only mode. Zero external deps.
2025-12-28 06:18:03 -08:00
zeekay d947c601ab fix: /healthz only — removed legacy health endpoints 2025-12-28 04:05:37 -08:00
zeekay 4fbf8da718 feat: add /healthz endpoint (platform health check standard)
Add /healthz alias on the internal MPC API (port 9800) alongside
the existing /health endpoint. Both return the same response.
2025-12-28 03:58:59 -08:00
zeekay 10dcad018e fix: address red team findings — auth, TLS, KMS fallback, AAD
M-1:  compose.yml commented section now enforces JWT_SECRET required syntax
M-3:  TLS client config uses TOFU certificate pinning instead of blind
      InsecureSkipVerify — SHA-256 fingerprint pinned on first connect,
      mismatches rejected on subsequent connections
M-4:  TLSOnlyListener plaintext escape hatch gated behind both
      ALLOW_PLAINTEXT=true AND ENVIRONMENT=development
M-5:  KMS fallback to unencrypted storage is now log.Fatal in production
      (ENVIRONMENT != "development"), including Put-time failures
M-6:  isKeyShare() now checks org: prefix, key-type prefixes (frost:,
      bls:, sr25519:, tfhe:), and hex wallet IDs instead of returning true
M-9:  AES-GCM Encrypt/Decrypt accept optional AAD variadic parameter
      for context-binding; existing callers remain backward compatible
M-12: Internal /keygen endpoint requires org_id in request body (400 if
      missing); orgID propagated to GenerateKeyMessage and audit log
2025-12-28 02:59:23 -08:00
zeekay 68959865c1 security: harden internal MPC API, enforce TLS-only transport, restrict egress
- Add bearer token auth to internal MPC API (port 9800): /keygen, /keys,
  /backup now require Authorization header. Token from MPC_INTERNAL_API_KEY
  env (KMS-synced) or derived from Ed25519 node identity.
- Replace DualModeListener with TLSOnlyListener: plaintext peer connections
  are rejected. TLS 1.3 with PQ key exchange is mandatory.
- Add dedicated 20 RPM rate limiter on bridge signing and intent signing
  endpoints (separate from global 100 RPM).
- Add body size limit (1MB), read/write timeouts, and 10 RPM rate limiter
  to internal MPC API server.
- Restrict K8s NetworkPolicy egress for MPC nodes to peers, postgres,
  valkey, DNS, and HTTPS only (was unrestricted).
- Wire cluster-api-key in api-deployment for authenticated proxy to
  internal MPC API. Forward as Authorization: Bearer header.
- Remove hardcoded dev JWT_SECRET default from compose.yml (now required).
- Add internal-api-key to KMSSecret CRD and StatefulSet env.
2025-12-28 02:52:46 -08:00
zeekay 6857bdfbda feat: Base framework + consensus default + minimal ops
- Mount chi handlers on Hanzo Base (lifecycle, health, auth framework)
- Default mode: consensus (ZAP p2p) — NATS/Consul deprecated
- compose.yml: 2 services (api + dashboard), SQLite, no external DB
- config.yaml: consensus mode, SQLite-first
- Makefile: simplified build targets, docker compose format
- K8s: kustomization.yaml for idempotent deploys
- Removed listenAddr from NewServer (Base handles listening)
- Legacy NATS/Consul preserved but not default
2025-12-28 02:32:54 -08:00
zeekay 522b59b1a8 fix: remove /api/ prefix from all routes — use /v1/ only
Subdomain routing (mpc.lux.network/v1/) not path prefix (/api/v1/).
Updated: server routes, KMS routes, main.go forwarding, compose,
K8s dashboard config, ingressroute, landing page HTML.
2025-12-28 02:13:02 -08:00
zeekay 4e915d77c3 security: fix 15 custody audit findings, add regression + fuzz tests
Fixes all findings from the Blue Team defensive security review of the
redacted → redacted custody architecture transition.

HIGH:
- S-1: Implement P-256 ECDH + AES-256-GCM encryption of passkey backup shards
- W-2: Reject unparseable WebAuthn public keys (was silently skipping verification)
- O-1: Add Ed25519 binary signature verification package (pkg/integrity)

MEDIUM:
- W-1: Validate attestation is a real P-256 curve point, not raw attestation object
- W-3: Add origin validation to all WebAuthn flows (register, verify, trade approve)
- N-2: Remove plaintext TCP fallback from MPC node transport (TLS mandatory)
- K-1: Fail-closed on empty/whitespace orgID (prevents cross-tenant key leakage)
- A-1: Make AuditEntry immutable (Update/Delete return error)
- A-2: Add MPC-level signing audit log (wallet, message hash, intent, trigger)
- O-3: Invalidate backup shards after key reshare (stale shares are useless)
- O-2: Reject env/file password providers in production (require cloud HSM)

LOW:
- T-1: Add error handling + MarkSignFailed to signing goroutine
- T-2: Verify caller authorization in handleTradeSubmit
- K-2: Secret erasure stub now calls runtime.GC() instead of no-op
- N-1: Add VerifyConnection callback to reject peers without TLS certs

Tests: 69 unit + 7 fuzz targets, ~900K fuzz executions, 19/19 packages green.
Makefile: add -tags json1 for SQLite JSON function support in ORM tests.
2025-12-28 01:00:12 -08:00
zeekay ad4f429f1e fix: per-org MPC isolation — orgID end-to-end threading + security hardening
- M-1 CRITICAL: Remove legacy key share fallback (cross-tenant leak)
- M-2 HIGH: orgID now required string on all Node methods (not variadic)
- M-3 HIGH: Key material zeroing after signing sessions
- Thread orgID through MPCBackend interface, all API handlers
- Reshare + TFHE sessions use OrgScopedKey for reads/writes
- Remove hardcoded JWT default (fail-hard if not set)
- Add warning log for empty orgID legacy path
- Regression tests: TestGetKeyShareWithFallback_M1_CrossTenantLeak
2025-12-28 00:20:28 -08:00
zeekay e40f0b6dff fix: goimports formatting with local-prefixes (matches golangci-lint) 2025-12-27 23:14:14 -08:00
zeekay 0d7a523c3e security: add orgID multi-tenancy isolation, rename badger to zapdb
Multi-tenancy isolation (addresses Dragonfire review MPC audit):
- Add OrgID field to all event messages (keygen, sign, reshare)
- Scope session dedup keys as orgID-walletID-txID
- Namespace KVStore keys with org prefix (org:<orgID>:<key>)
- Backward-compatible fallback to legacy unscoped keys
- New org_kvstore.go with OrgScopedKey/GetKeyShareWithFallback

Naming cleanup:
- Rename all badger references to zapdb in code, config, tests
- config.yaml: badger_password → zapdb_password
- AppConfig: BadgerPassword → ZapDBPassword
- Fix MPCiumVersion typo → MPCVersion
2025-12-27 22:41:08 -08:00
zeekay 4641ad7c09 feat: BLS threshold + security hardening + ZapDB KMS-backing
Security (from red team review):
- Replay protection: request_id + timestamp freshness on sign API
- Ed25519 message auth re-enabled on all protocol messages
- DKG timeout (5min) + signing timeout (30s) with watchdog
- Dedup map TTL cleanup (10min expiry, 2min sweep)

BLS threshold signing:
- KeyTypeBLS + keygen/signing sessions
- TrustedDealer pattern for BLS DKG
- CBOR serialization for BLS config
- 8 tests

ZapDB KMS-backing:
- HSM PasswordProvider wired to ZapDB init
- Supports: AWS KMS, GCP KMS, Azure KV, env, file
- Default env for backward compat
- 19 tests

Also: sr25519 sessions, fixed SignWireMessage build break
2025-12-27 21:54:46 -08:00
zeekay d302b84776 Wire HSM threshold attestation into MPC daemon
- Add --hsm-attest / MPC_HSM_ATTEST flag for share attestation
- Add --hsm-signer / --hsm-signer-key-id flags for co-signing
- KeyShareVault initialized when attestation enabled
- Bump github.com/luxfi/hsm v1.0.0 → v1.1.0
2025-12-27 18:36:07 -08:00
zeekay 439300efdd feat: multi-chain address derivation (BTC, SOL), fix policy engine
- Derive Bitcoin P2PKH address from secp256k1 ECDSA pubkey
- Derive Solana address from Ed25519 pubkey (base58)
- Fix loadPolicies: gracefully return empty list instead of error
  when no policies exist (was causing "failed to load policies" error)
- Filter enabled policies in-memory (JSONB boolean filter unreliable)
- Add BTC/SOL address fields to KeygenResult and wallet creation
- Update /info endpoint with full chain support matrix
- Map EVM-compatible chains (Lux, XRP) and Ed25519 chains (TON)
2025-12-27 11:45:33 -08:00
zeekay 2ba9ca4c93 fix: derive eth_address from 32-byte ECDSA keys, return int for connected_peers
- /health returns connected_peers as int (count) not string array
- /keygen derives eth_address from 32-byte keys (was >= 33, now >= 32)
- Skip initiator verification when no explicit key configured (consensus mode)
2025-12-27 11:38:55 -08:00
zeekay 57c0e70099 fix: sign keygen/sign messages in consensus mode, fix API proxy paths
- ConsensusIdentityStore now uses node's own key as initiator key when
  no explicit event_initiator_pubkey is configured (consensus mode)
- /keygen HTTP endpoint signs GenerateKeyMessage with node's Ed25519 key
- ConsensusMPCBackend.TriggerKeygen/TriggerSign sign messages before publish
- apiOnlyMPCBackend forwards to /keygen and /health (internal API paths)
  instead of /api/v1/keygen and /api/v1/status (dashboard API paths)
- mpc-api deployment points to port 9800 (internal API, no auth required)
  instead of port 8081 (dashboard API, auth required)
- /health response uses snake_case keys matching ClusterStatus JSON tags
2025-12-27 11:32:18 -08:00
zeekay ced778a524 fix(ci): goimports formatting, no-panic logger test, remove unconvert
- goimports -w on all pkg/api, pkg/db, cmd/mpcd files
- TestError_PanicsOnOddKeyValues → TestError_OddKeyValuesLogsWarning
  (logger was intentionally changed to warn+sentinel instead of panic)
- int(threshold) → threshold (threshold is already int from c.Int())
2025-12-27 16:36:55 -08:00
zeekay d73d4876e1 refactor(kvstore): rename Badger→ZapDB types, clean up package API
- git mv badger.go→zapdb.go, badger_backup.go→zap_backup.go
- BadgerKVStore→Store, BadgerConfig→Config, NewBadgerKVStore→New
- BadgerBackupExecutor→Backup, NewBadgerBackupExecutor→NewBackup
- BadgerBackupMeta→BackupMeta, BadgerBackupVersionInfo→BackupVersion
- Config fields: DBPath→Path, EncryptionKey→Key, BackupEncryptionKey→BackupKey, BackupDir→Dir
- Backup fields: BackupEncryptionKey→Key, BackupDir→Dir
- Store fields: BackupExecutor→Exec, db→DB (exported, fixes e2e compile)
- Updated all callers: transport/factory, transport/state, backup/s3,
  cmd/mpcd/main, cmd/lux-mpc-cli/recovery, scripts/migration/add-key-type,
  e2e/base_test, pkg/kvstore/backup_test
2025-12-27 16:23:40 -08:00
zeekay 3fceb5dce6 feat(mpc): key listing, KMS backup/restore, API-only backend, CGGMP21 config serialization 2025-12-27 16:03:48 -08:00
zeekay a4d822eb28 fix(security): Ed25519 initiator verification, proper share verification, no panics
- ConsensusIdentityStore.VerifyInitiatorMessage: implement real Ed25519
  signature verification using the configured event_initiator_pubkey
  instead of blindly accepting all messages
- cggmp21Aggregator.VerifyShare: implement ECDSA partial signature
  verification using secp256k1 curve arithmetic (R' = u1*G + u2*Y_i,
  check R'.x == r mod n) against the party's public key share
- frostAggregator.VerifyShare: implement Schnorr/BIP-340 partial
  signature verification (compute R_i = s_i*G - c*Y_i, verify on curve)
- logger.Error: replace panic on odd keyValues with warning log and
  sentinel value to avoid crashing production
- session.ProcessInboundMessage/ProcessOutboundMessage: replace panics
  with error log and graceful no-op for unoverridden base methods
- eddsaReshareSession: implement ProcessInboundMessage (unmarshal wire
  format, dedup, route to FROST party) and ProcessOutboundMessage (read
  from party Messages channel, wrap in wire format, send)
- cggmp21ReshareSession: implement matching message handlers
- eddsaReshareSession.Reshare: extract actual Ed25519 public key from
  FROST result via GetPublicKeyBytes() instead of empty placeholder
2025-12-27 15:57:11 -08:00
zeekay e6e3d55e22 feat(hsm): AWS/GCP/Azure KMS password providers, CREATE2 address prediction
- Implement CREATE2 address prediction in PredictAccountAddress() using
  keccak256(0xff ++ factory ++ salt ++ keccak256(initCode))[12:] formula.
  Also add general-purpose PredictCreate2Address() with raw [20]byte params.

- Create pkg/hsm package with PasswordProvider interface and 5 implementations:
  - AWSKMSProvider: decrypts ZAPDB_ENCRYPTED_PASSWORD via AWS KMS Decrypt API
    with full SigV4 signing and EC2 instance metadata credential fallback
  - GCPKMSProvider: decrypts via GCP Cloud KMS REST API with GCE metadata OAuth2
  - AzureKVProvider: unwraps via Azure Key Vault REST API with MSI token auth
  - EnvProvider: reads from LUX_MPC_PASSWORD/ZAPDB_PASSWORD env vars (default)
  - FileProvider: reads from file (K8s mounted secrets)

- Add NewPasswordProvider factory (pkg/hsm/factory.go) driven by MPC_HSM_PROVIDER
  env var (values: aws, gcp, azure, env, file)

- Wire HSM provider into mpcd consensus startup, replacing direct env var read
  with graceful fallback chain: HSM provider -> viper config -> dev default

- Add --hsm-provider and --hsm-key-id CLI flags with MPC_HSM_PROVIDER/MPC_HSM_KEY_ID
  env var sources

- 25 tests passing (9 smart + 16 HSM)
2025-12-27 15:50:34 -08:00
zeekay 906f8bdf1a refactor: use luxfi/database abstraction for KV storage, rename BadgerDB→ZapDB
- Replace direct github.com/luxfi/zapdb/v4 imports with github.com/luxfi/database
  abstraction in pkg/kvstore/ (zapdb.New + encdb.New for encryption)
- BadgerKVStore now uses database.Database interface internally — backend is
  pluggable (zapdb/leveldb/memdb) without changing MPC code
- Remove custom badger_logger.go (database module handles its own logging)
- Update BadgerBackupExecutor to use database.Database instead of *badger.DB;
  RestoreAllBackupsEncrypted loads into raw zapdb (values are already
  individually encrypted by encdb)
- Rewrite backup_test.go to use KVStore interface instead of raw badger API
- Update migration script to use KVStore Put/Get/Delete/Keys instead of txn API
- Rename all user-visible "BadgerDB"/"Badger" strings to "ZapDB" in logs,
  prompts, and comments across cmd/mpcd/main.go, pkg/kvstore/, pkg/transport/
- Fix backup_test.go type reference: badgerBackupExecutor→BadgerBackupExecutor
  (resolves CI test and lint failures)
2025-12-27 15:37:19 -08:00
zeekay 7fd512051e feat: replace BadgerDB with ZapDB, remove local replace directives, vendor mode CI/CD
- Replace github.com/dgraph-io/badger/v4 with github.com/luxfi/zapdb/v4 v4.9.2
  throughout pkg/kvstore/, pkg/transport/, cmd/mpcd/, e2e/, scripts/
- Rename BadgerPath/BadgerPassword → ZapDBPath/ZapDBPassword in FactoryConfig
- Remove local replace directives from go.mod:
  - hanzoai/orm: now uses published v0.3.2 (tagged on GitHub)
  - hanzoai/kv-go/v9: now uses published v9.17.2-hanzo.1
  - Only remaining replace: agl/ed25519 → luxfi/edwards25519
- Add vendor/ directory (GOWORK=off go mod vendor) for reproducible builds
- Update Dockerfile to golang:1.26-alpine + -mod=vendor build flag
- Update CI/CD to use self-hosted linux/amd64 runners (no cross-compilation)
- Add k8s/valkey.yaml for session KV store
- Update k8s manifests: api-kv support, ZapDB password env, fresh secrets
- Dashboard API and MPC nodes all tested running on cluster (3/3 nodes healthy)
2025-12-27 15:30:42 -08:00
zeekay ac49dfeae9 fix: subscribe to correct signing result topic and parse byte fields
TriggerSign was subscribing to mpc_signing_result.{txID} but the
signing session publishes to mpc_signing_result.{walletID}. Also
fixed result parsing: R/S are []byte (base64 in JSON), not hex strings.
2025-12-27 15:17:27 -08:00
zeekay 4b2dc29e5c fix: populate ParticipantPeerIDs in ConsensusKeyInfoStore for signing
ConsensusKeyInfoStore.Get() was returning empty ParticipantPeerIDs,
causing "Not enough participants to sign" errors. Now populates from
peer registry's ready peers list.
2025-12-27 15:04:12 -08:00
zeekay 21fb080177 fix: normalize ecdsa->secp256k1 key type in signing requests 2025-12-27 14:57:35 -08:00
zeekay 717298214b fix: register key type as secp256k1 (not ecdsa) for CGGMP21 signing 2025-12-27 14:50:58 -08:00
zeekay 8bd63168a2 fix: pass key type in signing requests, increase API timeout to 120s
- TriggerSign now looks up key type from keyInfoStore (was empty, causing
  "CGGMP21 only supports Secp256k1" errors)
- Wire keyInfoStore into ConsensusMPCBackend
- Increase HTTP middleware timeout from 30s to 120s for MPC signing
2025-12-27 14:44:20 -08:00
zeekay c98d565859 fix: derive ETH addresses from 32-byte ECDSA x-coordinates
CGGMP21 keygen returns 32-byte x-coordinate, not 33-byte compressed key.
Added secp256k1 point decompression (y² = x³ + 7 mod p) to recover the
full uncompressed public key for keccak256 address derivation.
2025-12-27 14:11:14 -08:00
zeekay 392469a838 feat: add standalone api subcommand for dashboard-only deployment
mpcd api --db $DATABASE_URL --jwt-secret $JWT_SECRET --listen :8081

Runs the Dashboard API server without MPC transport, suitable for
cloud dashboard deployments where MPC operations are handled by
separate MPC nodes.
2025-12-27 13:38:07 -08:00
zeekay 6b38df60a4 feat: MPC wallet dashboard - full-stack implementation
Complete MPC wallet management platform rivaling Fireblocks/Utila/Fordefi:

Backend (Go):
- REST API with 60+ endpoints on chi router (pkg/api/)
- PostgreSQL schema with 13 tables (pkg/db/)
- JWT + MFA auth, bcrypt passwords, API key management
- Policy engine (deny/approve/require_approval)
- Transaction signing flow with approval workflow
- Subscription scheduler for recurring payments
- Payment requests with public pay pages
- Safe + ERC-4337 smart wallet integration (pkg/smart/)
- Rate limiting, webhook delivery (HMAC-SHA256), audit logging
- 27 passing tests (auth, policy engine, middleware)

Frontend (Next.js 14):
- 27 routes with monochrome dark theme (Tailwind + Geist fonts)
- Full API client with JWT auto-refresh
- React Query hooks for all resources
- Pages: dashboard, vaults, wallets, transactions, policies,
  whitelist, team, settings, API keys, webhooks, audit,
  subscriptions, payments, smart wallets

Infrastructure:
- Dockerfiles for API (Go) and dashboard (Next.js standalone)
- compose.yml for local development (PostgreSQL + API + dashboard)
- K8s manifests for mpc.lux.network + cloud.lux.network
- GitHub Actions deploy workflow (build → push GHCR → kubectl apply)
- TLS via cert-manager, Traefik IngressRoute for both domains
2025-12-27 13:11:38 -08:00
zeekay 369c76432b feat: add /keygen HTTP endpoint, PubSub self-delivery, increase keygen timeout
- Add POST /keygen endpoint for triggering MPC keygen via HTTP API
- Fix PubSub self-delivery: Publish now delivers to local subscribers
  before broadcasting to peers (required for consensus mode keygen)
- Increase KeyGenTimeOut from 30s to 120s (Paillier prime generation
  takes 6-15s per node, multi-round protocol needs more time)
- Add pubKeyToEthAddress helper for deriving ETH addresses from ECDSA keys
- Bump version to 0.3.3
2025-12-27 12:51:46 -08:00
zeekay 97516cdc18 feat: add S3 backup integration, keepalive pings, and connection stability
- Add S3 backup manager (pkg/backup/s3.go) for periodic encrypted BadgerDB
  backups with upload to S3-compatible storage (MinIO)
- Add 30s keepalive pings in transport layer to prevent idle read timeouts
- Increase read timeout from 30s to 5 minutes
- Add connection tie-breaking for simultaneous peer connections (lower node
  ID keeps outbound) to prevent connection storms
- Add pointer-specific peer removal (removePeerConn) to prevent orphaned
  goroutines from removing replacement connections
- Export BadgerBackupExecutor type for use by backup package
- Add /backup HTTP endpoint for on-demand backup triggers
- Bump version to 0.3.2
2025-12-27 12:45:09 -08:00
zeekay 84848df05d fix: lint issues - goimports formatting and unnecessary conversion
- Update .golangci.yml to v2 format with formatters section
- Fix goimports for local package grouping (tfhe_session.go, crypto_adapter.go, manager_test.go)
- Remove unnecessary int() conversion in mpcd main.go
2025-12-27 09:46:21 -08:00
zeekay 33c08f435d chore: sync dependencies and format code 2025-12-27 09:26:29 -08:00