Commit Graph
352 Commits
Author SHA1 Message Date
zeekay dc6eb7ebab ci: use ubuntu-latest runner (self-hosted runner offline) 2025-12-27 22:34:30 -08:00
zeekay 9ef0c7881f fix: exclude go.work from Docker build context 2025-12-27 22:27:53 -08:00
zeekay 3beb7589b4 fix: CI uses Dockerfile directly, pass GITHUB_TOKEN build-arg 2025-12-27 22:21:16 -08:00
zeekay e48beaefa6 fix: add Dockerfile.prebuilt for CI multi-arch build 2025-12-27 22:14:38 -08:00
zeekay 683a15771a fix: bump luxfi/fhe v1.7.6 → v1.7.7 (checksum mismatch) 2025-12-27 22:08:01 -08:00
zeekay 55b49bb9da 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.
2025-12-27 22:01:24 -08:00
zeekay 5106e6b61a 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 2362c6606c deps: update golang.org/x/crypto, x/net, x/sys to latest 2025-12-27 21:48:09 -08:00
zeekay 7620698a36 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.
2025-12-27 21:41:32 -08:00
zeekay d12d984eaf fix: multi-stage Dockerfile, remove prebuilt — Go 1.26, alpine 3.21, GOPRIVATE for private deps 2025-12-27 21:34:54 -08:00
zeekay cf954b7d36 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 3c4a089670 feat: dashboard pages + security hardening for intents, settlements, tx lifecycle
Backend:
- Reorg detection in tx tracker (re-verify block hash, detect receipt disappearance)
- Post-finalization safety margin (6 extra blocks before stopping tracking)
- Server-side HSM co-signing (HSMProvider interface, server calls HSM directly)
- Background intent expiry reaper (5-min sweep for stuck intents)
- Domain-separated intent hashing (lux-mpc-intent:v1 prefix)
- Backup rate limiting (max 3 active per wallet)
- Default backup changed to 2-of-3 (iCloud + HSM + offline) for fault tolerance
- All status transitions now use RecordTransition with proper actors

Frontend:
- Intents list page with status filter
- Intent detail page with lifecycle progress bar, sign/co-sign actions
- Settlements list page with status filter
- Settlement detail page with lifecycle, HSM signatures, transfer agency
- Enhanced transaction detail with on-chain confirmation, revert reason, status history
- Wallet backup UI with Shamir shard visualization
- Updated StatusBadge with all new status colors
- Nav updated with Intents + Settlements links
- Co-sign UI updated for server-side HSM flow (key_id only, no client signature)
2025-12-27 18:16:15 -08:00
zeekay 6f83e39ab0 feat: tx lifecycle tracking, Shamir backup sharding, settlement engine
Transaction Lifecycle ("did the tx land?"):
- TxTracker polls eth_getTransactionReceipt for block inclusion
- Receipt fields: blockNumber, blockHash, receiptStatus, gasUsed, revertReason
- Confirmation counter with configurable target (default 12)
- StatusHistory records every state transition with timestamp and actor
- Stuck/dropped tx detection with webhook alerts

Backup Key Sharding (Secure Recovery Flow):
- GF(2^8) Shamir Secret Sharing (ShamirSplit/ShamirCombine)
- WalletBackup: AES-256-GCM encrypt key share, Shamir-split the key
- Labeled shard destinations: icloud, hsm, offline, custody, device
- Default 2-of-2 (iCloud + Platform HSM), institutional 3-of-5

Settlement & Intent Engine:
- Intent lifecycle: pending_sign → signed → co_signed → recorded → matched
- HSM co-signing as second signer in multisig flow
- Settlement with HSM multisig attestation collection
- TransferAgency hash registration and verification
- WalletBackup, Intent, Settlement DB models

API Routes:
- POST/GET /intents, /intents/:id/sign, /intents/:id/co-sign
- GET /settlements, /settlements/:id
- POST/GET /wallets/:id/backup
- New webhooks: tx.included, tx.finalized, tx.reverted, intent.*

40 tests passing across backup, settlement, txtracker, api packages.
2025-12-27 18:09:37 -08:00
zeekay 03376ea07e fix(ci): add Dockerfile.prebuilt for multi-arch API builds
Was gitignored, causing CI to fail with "no such file" error.
Uses TARGETARCH to select the correct cross-compiled binary.
2025-12-27 16:43:32 -08:00
zeekay 94863f3b09 ci: rename runners to {org}-{role}-{os}-{arch} convention
Unified ARC runner naming across all orgs:
- lux-build → lux-build-linux-amd64
- hanzo-build → hanzo-build-linux-amd64
- hanzo-k8s → hanzo-deploy-linux-amd64
- liquidity-build → liquidity-build-linux-amd64
2025-12-27 16:17:03 -08:00
zeekay bb7d188529 feat(dashboard): landing page with login + docs hub
- Replace redirect-to-dashboard with proper landing page showing
  branding, feature cards, chain chips, and sign-in button
- Add /docs hub page with section cards, API reference, and examples
- Update middleware to allow / and /docs as public paths
2025-12-27 14:31:06 -08:00
zeekay ec054bc4d8 feat(api): add landing page to dashboard API
Add HTML landing page at / route for mpc.lux.network showing:
- CGGMP21 and FROST protocol info
- Supported chains (BTC, ETH, LUX, SOL, XRPL, TON, etc.)
- Links to health, bridge dashboard, and API docs

Also update go.work to Go 1.26.1.
2025-12-27 14:24:28 -08:00
zeekay d2a7c0f0d0 chore: bump Go 1.26.0 → 1.26.1
Fixes 5 stdlib CVEs (html/template, os, net/url, crypto/x509 x2).
2025-12-27 13:05:01 -08:00
zeekay 8ca5058cc4 chore: upgrade zapdb v4.9.2 → v4.9.3
Picks up upstream badger merge, Go 1.26 vet fixes, and grpc build
tag for protobuf.
2025-12-27 12:58:23 -08:00
zeekay a36b2775a3 fix(ci): use v3 KMS API with workspaceId and Universal Auth
- environment=production → environment=prod (matches KMS config)
- v1/secrets/raw → v3/secrets/raw with workspaceId
- Added KMS_CLIENT_ID/SECRET Universal Auth with HANZO_API_KEY fallback
2025-12-27 12:31:54 -08:00
zeekay a5cd9efa5d ci: migrate deploy to HANZO_API_KEY + KMS
Replace pre-configured doctl auth with KMS credential fetch using
HANZO_API_KEY for MPC services deployment to lux-k8s.
2025-12-27 12:25:17 -08:00
zeekay 361d3b58be chore: gitignore test artifacts, add go.work.sum 2025-12-27 10:45:57 -08:00
zeekay 8560d6dd16 fix: use /oauth/authorize for MPC login, rename app in IAM DB
- Changed login redirect from /login to /oauth/authorize (standard OAuth2
  authorization endpoint)
- IAM app renamed from app-lux-mpc to lux-mpc so implicit flow resolves
  correctly (Casdoor uses client_id as app name lookup)
- Updated E2E tests to match new OAuth flow
2025-12-27 12:18:39 -08:00
zeekay 0e3349fdc4 feat: bridge admin dashboard, WebAuthn device management, LSS protocol selection
- Bridge admin pages: /bridge (overview), /bridge/wallets (signing wallet
  selector), /bridge/fees (fee config), /bridge/contracts (BRIDGE_ROLE mgmt)
- Bridge config API: GET/PATCH /api/v1/bridge/config, GET /bridge/networks
- BridgeConfig model in DB (org-scoped, stores wallet ID, fees, toggles)
- WebAuthn device management: /settings/devices (register/delete devices)
- Biometric approve button on transaction detail page using WebAuthn API
- Dashboard lib/webauthn.ts with startRegistration, startAuthentication
- Protocol selection in wallet creation wizard (CGGMP21, LSS, FROST)
- Protocol field on Wallet model, validation in create handler
- Wallet detail page shows protocol type
- Bridge nav link in sidebar
2025-12-27 12:12:02 -08:00
zeekay d377958319 fix: dual-mode TLS listener for zero-downtime PQ TLS rolling upgrades
- DualModeListener sniffs first byte: 0x16 → TLS, else plaintext
- Client falls back to plaintext TCP if TLS dial fails
- Enables rolling upgrades without breaking peer connectivity
- All nodes now running PQ TLS 1.3 (X25519MLKEM768) in production
2025-12-27 12:05:25 -08:00
zeekay 540d35f03b feat: post-quantum TLS 1.3 for MPC node-to-node transport
- Add PQ TLS using Go 1.26 built-in X25519MLKEM768 hybrid key exchange
- Self-signed certs from Ed25519 identity keys (no separate PKI needed)
- Server: ListenTLS with ML-KEM-768 preferred curve
- Client: DialTLS with InsecureSkipVerify (auth via ZAP identity)
- Fallback to plaintext TCP when identity keys not configured
- Test confirms X25519MLKEM768 negotiation on every handshake
- Also supports SecP256r1MLKEM768 and SecP384r1MLKEM1024 fallbacks
2025-12-27 11:58:47 -08:00
zeekay be54888298 feat: WebAuthn biometric signing, enforce approver roles in policies
- Add WebAuthn/FIDO2 registration and verification endpoints
  POST /webauthn/register/begin, /register/complete, /verify
- Biometric approval: Face ID/Touch ID/YubiKey approve transactions
- Challenge bound to transaction ID (SHA256) preventing replay
- Enforce ApproverRoles from policy engine during transaction approval
- Add WebAuthnCredential DB model (pending_registration, active, revoked)
- Policy decisions now carry ApproverRoles for role-gated approvals
2025-12-27 11:52:10 -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 1eae86833c fix: OAuth login URL uses /login endpoint, update E2E selectors to match Lux ID form
- Login redirect uses /login instead of /oauth/authorize (matches actual
  Casdoor login page URL that renders the form)
- E2E tests updated to use correct field placeholders (Email, Password)
  and button text (Sign In) matching the Lux ID login component
- Exempt /healthz from rate limiting to prevent K8s probe failures
2025-12-27 11:25:41 -08:00
zeekay 52d8d964d6 fix: OAuth callback handles query string tokens, correct authorize endpoint
- Callback page now checks both hash fragment and query string for
  access_token (Casdoor returns it in query string, not hash)
- Login redirect uses /oauth/authorize instead of /login/oauth/authorize
- Add hanzo.id to default OIDC issuers in MPC API
- Update E2E tests to match corrected authorize URL
2025-12-27 11:19:03 -08:00
zeekay 62b1591a23 security: add NetworkPolicies, pod hardening (non-root, read-only rootfs)
- Add NetworkPolicies for lux-mpc namespace (mpc-node, mpc-api, dashboard)
- Add securityContext: runAsNonRoot(uid=1000), readOnlyRootFilesystem,
  drop ALL capabilities, seccomp RuntimeDefault
- Add /tmp emptyDir for read-only rootfs compatibility
2025-12-27 11:05:49 -08:00
zeekay 0232b7df72 feat: standalone mpc-api deployment, implicit OAuth flow, E2E tests
- Separate mpc-api into its own Deployment with --cluster-url proxy to mpc-node-0
- Switch OAuth from authorization code flow to implicit flow (response_type=token)
- Add Playwright E2E tests for Lux ID login flow and OIDC discovery
- Update CI to apply api-deployment.yaml and wait for mpc-api rollout
2025-12-27 10:59:11 -08:00
zeekay a11334d45a feat: OIDC login via Lux ID, fix ingress routing, deploy to lux-k8s
- Add OIDC token exchange endpoint (POST /api/v1/auth/oidc) that
  validates Lux ID access tokens and issues local MPC API JWTs
- Update dashboard auth callback to do 2-step exchange: get Lux ID
  token, then exchange for MPC API JWT via OIDC endpoint
- Fix IngressRoute to use path-based routing (/api/v1 → API, / → dashboard)
- Fix deploy.yml to target lux-k8s cluster (not hanzo-k8s)
- Fix wallet creation page to use api client instead of raw fetch
- Add /api and /healthz to dashboard middleware public paths
2025-12-27 10:52:34 -08:00
zeekay d902266df9 fix: remove standalone mpc-api deploy, add imagePullPolicy Always
The API runs on node-0 of the MPC StatefulSet (--api-db, --api-listen flags).
The standalone mpc-api deployment was broken (missing --node-id in consensus
mode) and unnecessary. Removed from deploy workflow.

Added imagePullPolicy: Always to ensure :latest tag pulls fresh images.
2025-12-27 10:39:19 -08:00
zeekay 2febb591a4 fix: dashboard deploy, 5-of-3 MPC cluster, pnpm migration
- Dockerfile: use pnpm exclusively (was falling back to npm)
- StatefulSet: 5 replicas with threshold 3 (was 3 replicas, threshold 2)
- deploy.yml: fix namespace typo (lux-bridge -> lux-mpc), add mpc-api restart
- Migrate dashboard from npm to pnpm (pnpm-lock.yaml replaces package-lock.json)

Deploying latest code fixes auth (middleware.ts enforces lux_mpc_session),
dynamic data fetching (dashboard/page.tsx calls API), and Geist font loading
(font files are included in the Next.js build output).
2025-12-27 10:32:42 -08:00
zeekay dee0f7a593 fix: Geist fonts in docs, round buttons across dashboard
- Replace Inter with Geist Sans/Mono in docs site
- Add geist package to docs dependencies
- Round all buttons to rounded-lg in dashboard and login pages
2025-12-27 10:26:05 -08:00
zeekay a8ab0814bc unify all sql images to :latest (PG18)
Single version policy: ghcr.io/hanzoai/sql:latest everywhere.
No version pinning, no backwards compat, always latest stable.
2025-12-27 17:56:23 -08:00
zeekay c5ce6124d9 unify on hanzoai/sql:17-alpine, IngressClass ingress
Standardize all postgres images to ghcr.io/hanzoai/sql:17-alpine
and IngressClass to 'ingress' for white-label portability.
2025-12-27 17:49:45 -08:00
zeekay 9ff655c588 build: use pre-built binary in Dockerfile
GoReleaser copies the compiled binary into the Docker context.
Dockerfile should COPY the binary, not rebuild from source.
2025-12-27 17:43:08 -08:00
zeekay ecc04f187c ci: fix multi-platform Docker builds in goreleaser
Split into per-arch image templates (amd64/arm64) with docker_manifests
to combine them — this is the correct goreleaser v2 pattern.
Single --platform=linux/amd64,linux/arm64 fails with docker exporter
not supporting manifest lists in buildx docker driver.
2025-12-27 17:36:31 -08:00
zeekay 5916fe46f9 ci: fix release workflow for multi-platform Docker builds
- Add QEMU + Docker Buildx setup before GoReleaser (required for linux/amd64+arm64)
- Remove redundant publish-docker job (GoReleaser handles multi-platform builds)
- Update GO_VERSION to 1.26.0
- Fix go install path: cmd/lux-mpc -> cmd/mpcd
2025-12-27 17:29:53 -08:00
zeekay 7d984692b8 fix(release): drop Windows builds (term.ReadPassword/syscall.Stdin incompatible cross-compile)
mpcd and lux-mpc-cli use terminal password prompts via golang.org/x/term which requires
syscall.Stdin as int — incompatible with Windows syscall.Handle (uintptr). Both are
server/ops tools targeting Linux/macOS; Windows support is out of scope.
2025-12-27 17:23:16 -08:00
zeekay 6ced3efbaf fix(release): drop Windows from lux-mpc-cli (syscall.Stdin type mismatch on Windows) 2025-12-27 17:16:39 -08:00
zeekay 36866b1c83 fix(release): update goreleaser — cmd/lux-mpc→cmd/mpcd, remove missing systemd/configs paths 2025-12-27 17:10:02 -08:00
zeekay 7cfc8e9874 chore(e2e): use real semver tag v1.0.5, remove local path replace
e2e now references github.com/luxfi/mpc v1.0.5 (semantic tag).
Local resolution handled by go.work workspace, not replace directive.
Only remaining replace is agl/ed25519 → luxfi/edwards25519 (broken upstream).
2025-12-27 17:03:24 -08:00
zeekay ccb91d25e0 chore: go 1.26, add go.work, tidy modules
- Bump e2e module to go 1.26.0
- Add go.work workspace file (replaces need for local replaces)
- Remove dgraph-io/badger from e2e direct deps (unused directly)
- Tidy both modules
- Document agl/ed25519 redirect requirement (broken upstream)
2025-12-27 16:56:47 -08:00
zeekay 586448689d fix(ci): goimports with local-prefixes=github.com/luxfi/mpc 2025-12-27 16:50:10 -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