Commit Graph
391 Commits
Author SHA1 Message Date
zeekay 21da3d64e0 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.
2026-04-07 14:00:47 -07:00
zeekay 7678f7311c fix: remove local replace directive for hanzoai/base
Bump hanzoai/base from v0.28.0 (broken module path) to v0.39.1
(correct module path). Removes the local development replace
directive so the module resolves from the Go module proxy.
2026-04-07 13:29:46 -07:00
zeekay 36179858a8 docs: README — architecture, primitives, usage 2026-04-07 09:42:50 -07:00
zeekay 4decb5c091 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
2026-04-07 01:18:53 -07:00
zeekay 0f6f05e9d2 feat: SQLite default — zero external deps to start
db.New() auto-detects backend from DSN:
- "" or "sqlite://path" or "file.db" → SQLite (default)
- "postgres://..." → PostgreSQL (production upgrade)

KV (Valkey/Redis) is optional — pass "" to skip.
No postgres, no redis required to run mpcd out of the box.
Removed pgxpool direct dependency from db package.
2026-04-07 01:05:03 -07:00
zeekay a44255bf9f fix: remove all tenant-specific data from MPC infrastructure
MPC is generic infrastructure — no hardcoded tenant URLs.
- Remove pars.network, zoo.network from OIDC issuers, ingress, TLS
- Remove satschel.com, liquidity.io from CORS, WebAuthn, tests
- CORS/WebAuthn origins now env-driven: MPC_CORS_ORIGINS, MPC_WEBAUTHN_ORIGINS
- Ingress: mpc.lux.network only — tenants route through their own ingress
- Tests updated to match infrastructure-only origin lists
2026-04-07 00:42:17 -07:00
zeekay 60fc83b28d 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.
2026-04-07 00:01:47 -07:00
zeekay c410a11693 fix: use badger API directly in e2e test instead of kvstore.Store
CheckKeyInAllNodes was assigning *badger.DB to kvstore.Store.DB which
requires database.Database — badger.DB is missing the Compact method.
The test only needs Get and Close, so use badger.View/txn.Get directly.
2026-04-06 23:53:14 -07:00
zeekay ae30fd3e50 fix: deduplicate KMS JSON helpers, use shared writeJSON/writeError
Remove duplicate writeKMSJSON/writeKMSError from handlers_kms.go.
Reuse writeJSON/writeError from middleware.go — one way to do things.
2026-04-06 23:44:21 -07:00
zeekay e41c634bc3 test: 33 regression tests for all security fixes
- handlers_kms_test.go: input validation, orgID from context not header
- auth_test.go: JWT iss/aud enforcement, refresh/access token separation
- ratelimit_test.go: clientIP uses RemoteAddr, ignores XFF
- server_test.go: maxBodySize middleware enforcement
2026-04-06 23:35:05 -07:00
zeekay bb92392e50 security: fix remaining Red team findings (LOW + MEDIUM)
MEDIUM: Bridge wallet org isolation — added orgID filter to wallet query
  in handleBridgeSign, prevents cross-tenant signing.
LOW-1: JWT iss/aud claims — tokens now carry issuer "mpc.lux.network"
  and distinct audiences ("mpc-api" vs "mpc-refresh"). Refresh tokens
  can no longer be used as access tokens.
LOW-2: Rate limiter XFF bypass — clientIP uses r.RemoteAddr (set by
  RealIP middleware) instead of parsing X-Forwarded-For directly.
LOW-3: Request body size limit — 1MB maxBodySize middleware prevents OOM
  from oversized payloads.
2026-04-06 23:28:34 -07:00
zeekay e635b1e186 security: fix 3 critical findings from Red team review
CRITICAL-1: KMS routes registered outside auth middleware — moved inside
  authenticated route group with requireRole("owner", "admin")
CRITICAL-2: X-Org-ID header trusted without validation — replaced with
  getOrgID(r.Context()) from JWT claims
CRITICAL-3: (KMS standalone addressed in lux/kms repo)
2026-04-06 23:23:05 -07:00
zeekay 529e246117 feat: merge KMS validator key management into MPC binary
KMS routes now live inside MPC API server — one binary for both:
- POST /api/v1/keys/generate — create validator BLS + Ringtail keys
- GET /api/v1/keys — list all validator key sets
- GET /api/v1/keys/{id} — get validator key set
- POST /api/v1/keys/{id}/sign — sign with validator key
- POST /api/v1/keys/{id}/rotate — reshare validator keys

Storage: ORM (same postgres/ZapDB as MPC wallets).
No separate KMS binary needed — mpcd serves both.
2026-04-06 23:12:19 -07:00
zeekay 425668bd2b fix: remove duplicate bridge watchers, expose Handler for Base mount
- Remove pkg/bridge/ (btc_watcher + orchestrator) — bridge/opnet-watcher
  is the single source of truth for chain watching per CTO directive
- Add Handler() to API server for mounting on Hanzo Base
- MPC is signing-only; bridge is the control plane
2026-04-06 23:07:25 -07:00
zeekay f322744693 ci: multi-arch Docker (amd64+arm64)
Add QEMU setup step before Buildx in both build-api and
build-dashboard jobs. Without QEMU, buildx cannot emulate
arm64 on amd64 runners, causing multi-platform builds to fail.
release.yml already had QEMU — this aligns deploy.yml.
2026-04-05 14:58:46 -07:00
zeekay 9edc0cedb3 feat: configurable WebAuthn RP ID and origins for Liquidity exchange
Add MPC_WEBAUTHN_RP_ID and MPC_WEBAUTHN_ORIGINS env vars to make
WebAuthn relying party and origin allowlist configurable. Adds
Liquidity exchange origins (exchange.{dev,test,main}.satschel.com,
liquidity.io) to WebAuthn origin checks, CORS, and security tests.
2026-04-02 19:09:00 -07:00
zeekay ea72f22dc7 chore: update all dependencies
Go: 98 deps updated including crypto v1.17.45, threshold v1.6.0,
otel v1.42.0, cbor v2.9.1, samber/lo v1.53.0, urfave/cli v3.8.0.
Excluded luxfi/log v1.3.0 (broken module path declaration).
Makefile: add -tags json1 + CGO_ENABLED=1 for SQLite JSON support.

Dashboard: next 15.3.3, react 19.2.4, zustand 5.0.12,
tanstack/react-query 5.96.1, typescript 6.0.2, playwright 1.59.0.
Pinned eslint to v9 (v10 has peer dep conflicts with next eslint plugins).
Pinned tailwindcss to v3 (v4 requires postcss migration).

19/19 packages pass, dashboard builds clean.
2026-04-01 09:11:20 -07:00
zeekay 04f303dcb2 security: fix 15 custody audit findings, add regression + fuzz tests
Fixes all findings from the Blue Team defensive security review of the
Satschel → Liquidity.io 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.
2026-04-01 09:00:06 -07:00
zeekay 78caaacd0c feat: passkey-encrypted backup shard — company CANNOT decrypt
Backup shard (shard 3) is encrypted with user's WebAuthn passkey
public key (P-256 ECDH). HSM stores the ciphertext but cannot
decrypt — only user's biometric (via Secure Enclave private key) can.

ATS shard (2) + encrypted_backup (3) = company CANNOT sign.
User shard (1) + passkey_decrypt(3) = user CAN exit independently.

Added UserPasskeyFingerprint to WalletBackup model.
Backup handler looks up user's WebAuthn credential for encryption.
2026-03-31 17:51:52 -07:00
zeekay 095ccdd16f feat: add biometric trade approval flow with push notifications
- Trade approval service: submit, approve (WebAuthn), reject, pending
- Push notifier: APNS (iOS) + FCM (Android) for trade approval requests
- Biometric verification: Face ID/Touch ID with 30s freshness, nonce replay guard
- Custody policy engine: KYC/AML/sanctions/limits checks before co-signing
- Device store: register/revoke mobile devices with Secure Enclave keys
- API routes: POST /api/v1/trade/{submit,approve,reject}, GET pending
- Trade expiry reaper: cleanup expired approvals (>5 min)
- 17 custody tests + 33 API tests passing
2026-03-30 15:25:53 -07:00
zeekay 1cf2bd619c fix: rename env vars to MPC_PASSWORD, remove LUX_ prefix
- Default env var: MPC_PASSWORD (was LUX_MPC_PASSWORD)
- No fallback to ZAPDB_PASSWORD — single source
- Factory env_var config reads from config map only (not env)
- Cloud HSM providers unchanged (ZAPDB_ENCRYPTED_PASSWORD)
- All tests pass
2026-03-30 09:21:51 -07:00
zeekay 22436897a1 chore: sync local changes 2026-03-26 22:47:15 -07:00
zeekay e84b2d2f25 security: convert secrets.yaml to KMSSecret CRD, remove hardcoded ZapDB password 2026-03-24 18:21:04 -07:00
zeekay 0e90ba3d15 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
2026-03-24 16:55:54 -07:00
zeekay e3936dc59c feat: per-user shard encryption + wallet isolation
EncryptedKVStore: AES-256-GCM wrapper over ZapDB for per-user shard encryption.
Each user's key shards encrypted with a unique DEK:

  user DEK = HMAC-SHA256(masterKey, "mpc:shard:" + orgID + ":" + userID)
  org DEK  = HMAC-SHA256(masterKey, "mpc:org:" + orgID)

Three layers of MPC data protection:
  1. ZapDB ChaCha20-Poly1305 (node-level, existing)
  2. EncryptedKVStore AES-256-GCM (per-user, NEW)
  3. API filter on createdBy (access control, NEW)

Even if ZapDB is fully dumped, individual users' shards are
independently encrypted. Wrong user key → decryption fails.

5 new tests: roundtrip, key uniqueness, wrong-key rejection,
empty values, org vs user key separation.
2026-03-24 14:58:54 -07:00
zeekay 9c9730d4ec feat: per-user wallet isolation — non-admin users only see their own wallets 2026-03-24 12:58:36 -07:00
zeekay 9b69cdf4a2 docs: complete multi-chain protocol mapping (BTC, ETH, SOL, TON, XRP, DOT, KSM) 2026-03-23 18:32:30 -07:00
zeekay aaf1d8bf1f feat: 3-of-5 customer+Lux MPC reference deployment with Safe multisig integration 2026-03-23 18:26:05 -07:00
zeekay fe9baa2ab7 security: fix keygen org-scoping + orgID injection prevention
Three fixes:

1. OrgScopedKey sanitizes colons in orgID to prevent key injection
   via the ":" separator (e.g. orgID "evil:org:fake" would create
   ambiguous key paths).

2. All 5 keygen sessions (CGGMP21, FROST, BLS, SR25519, LSS) now
   write key shares with OrgScopedKey(orgID, key) instead of bare
   keys. Previously keygen wrote unscoped but signing read scoped,
   causing key-not-found errors in multi-tenant deployments.

3. Added orgID field to session struct and threaded it through all
   keygen constructors and Node.Create*KeyGenSession methods using
   variadic orgID ...string for backward compatibility.
v1.1.1
2026-03-22 20:38:12 -07:00
Darkhorse7starsandHanzo Dev 4cdf09e3dc Fix StatefulSet update: use server-side apply with force-conflicts
StatefulSets don't allow updating immutable spec fields with regular
kubectl apply. Use --server-side --force-conflicts to handle this,
falling back to --force if server-side apply isn't available.

Co-authored-by: Hanzo Dev <[email protected]>
2026-03-22 21:09:15 -05:00
Darkhorse7starsandHanzo Dev 99740f03e7 Fix deploy: install doctl via official action
The deploy step was failing with 'doctl: command not found' because
doctl isn't pre-installed on ubuntu-latest runners. Use the official
digitalocean/action-doctl@v2 action to install and authenticate.

Co-authored-by: Hanzo Dev <[email protected]>
2026-03-22 21:01:19 -05:00
Darkhorse7starsandHanzo Dev 78523d4b9e Add debug logging to KMS deploy credentials step
Show HTTP status codes and error messages to diagnose
why the Universal Auth login or secrets fetch is failing.

Co-authored-by: Hanzo Dev <[email protected]>
2026-03-22 20:53:51 -05:00
zeekay 4ed637df8c feat: enable Go 1.26 runtime/secret for forward secrecy of key shares
Add GOEXPERIMENT=runtimesecret to Makefile, CI, and Dockerfile builds.
Wrap key share loading in all 5 signing session types with
withSecretErasure() so stack/register state containing raw share bytes
is zeroed after parsing. Build-tagged stub ensures everything compiles
without the experiment flag.
2026-03-22 13:37:19 -07:00
zeekay 913dfd3778 fix: goimports formatting with local-prefixes (matches golangci-lint) 2026-03-22 13:17:50 -07:00
zeekay a339744021 fix: enable CGO for BLS tests (blst requires CGO_ENABLED=1) 2026-03-22 13:03:02 -07:00
zeekay cf0d6e2238 fix: goimports formatting + CGO_ENABLED=0 for CI tests
- Run goimports -w on all 17 Go files with formatting issues
- Set CGO_ENABLED=0 on all CI steps (test, lint, build, CodeQL, SBOM)
- Remove -race flag from tests (requires CGO which pulls in blst.h)
- All 17 test packages pass with CGO_ENABLED=0
2026-03-22 12:50:58 -07:00
zeekay 7059a6a5ce fix: CI uses go mod download instead of vendor (fixes blst CGO build)
Vendoring doesn't properly include C source files needed by
supranational/blst. Switch to module cache with CGO_ENABLED=1.
2026-03-22 12:49:52 -07:00
zeekay 87291931e7 fix: remove hsm from go.work (fixes CI, use 'go work use ../hsm' locally) 2026-03-22 12:41:38 -07:00
zeekay cb1bc5ecbc 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
2026-03-22 12:02:30 -07:00
zeekay 184b88d06b ci: use ubuntu-latest runner (self-hosted runner offline) 2026-03-20 11:31:28 -07:00
zeekay 518ccf6800 fix: exclude go.work from Docker build context 2026-03-20 11:24:40 -07:00
zeekay 66ec6649c1 fix: CI uses Dockerfile directly, pass GITHUB_TOKEN build-arg 2026-03-20 10:58:59 -07:00
zeekay f3a782941b fix: add Dockerfile.prebuilt for CI multi-arch build 2026-03-20 10:55:29 -07:00
zeekay 3b50768156 fix: bump luxfi/fhe v1.7.6 → v1.7.7 (checksum mismatch) 2026-03-20 10:50:10 -07:00
zeekay bb97518e2b fix: update go.sum for luxfi/fhe + blst, add .gcloudignore
Stale checksum for luxfi/[email protected] caused CI build failures.
Removed old entry, re-downloaded with correct hash.
Added .gcloudignore to exclude go.work, e2e/, and binaries from cloud builds.
2026-03-20 10:44:25 -07:00
zeekay c7f126adbf 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
v1.1.0
2026-03-19 01:15:33 -07:00
zeekay 3343f2b01d deps: update golang.org/x/crypto, x/net, x/sys to latest v1.0.12 2026-03-18 14:15:21 -07:00
zeekay 8b66b6ffd9 feat: sr25519 threshold signing for Polkadot/Substrate
MPC daemon now supports sr25519 (Schnorrkel) key generation and
threshold signing using FROST over the ristretto255 group.

New files:
- pkg/mpc/sr25519_keygen_session.go — threshold keygen
- pkg/mpc/sr25519_signing_session.go — threshold signing
- pkg/mpc/sr25519_config_marshal.go — CBOR serialization
- pkg/mpc/ristretto255.go — local curve implementation
- pkg/eventconsumer/signing_handler_sr25519.go — event routing

Wiring:
- KeyTypeSR25519 constant + session type
- Event consumer routes sr25519 keygen/signing events
- API accepts "sr25519" as valid protocol
- DOT/KSM network codes mapped to sr25519 key type
- Signing context configurable (default "substrate")

14 tests passing.
2026-03-18 14:09:08 -07:00
zeekay ff7ea60be8 fix: multi-stage Dockerfile, remove prebuilt — Go 1.26, alpine 3.21, GOPRIVATE for private deps 2026-03-16 21:48:31 -07:00
zeekay bdd4d05ab0 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
2026-03-02 23:52:08 -08:00