Commit Graph
777 Commits
Author SHA1 Message Date
zooqueenandHanzo Dev 8f64a40e8d ci: target native arcd runners (evo/spark)
Replace retired self-hosted labels with native host arcd daemons:
evo (linux/amd64), spark (linux/arm64).

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-07 15:59:02 -07:00
zeekay bd60eca43c go: 1.26.3 → 1.26.4 (security: crypto/x509, mime, net/textproto) 2026-06-06 22:11:17 -07:00
Abhishek KrishnaandGitHub 7d0a8ef44f docs: lead INSTALLATION with consensus-mode + add operator runbook outline (#15) 2026-06-06 21:57:01 -07:00
zeekay 359b885498 mpc: rip zapauth bearer-token gate (decomplect)
Trust at the network boundary (NetworkPolicy + ZAP wire), not in the
application envelope. Companion to luxfi/keys v1.2.0 (LoadMnemonic
identity-free) and luxfi/kms v1.12.0 (iamclient gone).

Killed:
  - pkg/zapauth/     (JWKS verifier + AuthHelloFrame parser)
  - pkg/api/zap_kms_server.go: KMSZapConfig, auth+authRequired fields,
    handleAuthHello, respondAuthHello, checkAuth, StartKMSZAPWith
  - cmd/mpcd: ZAP_JWKS_URL, ZAP_EXPECTED_ISS, ZAP_EXPECTED_AUDIENCES,
    ZAP_AUTH_REQUIRED — all gone.

Note: mpc still has a pre-existing build block from upstream luxfi/geth
v1.16.79 → precompile pseudo-version (unrelated to this change).
2026-06-06 21:06:17 -07:00
zeekay eec833b39b ringtail → corona total rename — no alias, no wire compat
Per CTO directive: kill any alias, any shim. R-LWE threshold sig is
named Corona across all live code. Forward-only.

Sweep covers Go + TS + Sol + k8s YAML + JSON + LP markdown + skills
+ docs. Skipped: papers/audits/legal/licenses/blog/HISTORY (immutable
historical record).
2026-06-06 13:56:42 -07:00
zeekay 65c540f183 WIP: session checkpoint 2026-06-05 (codec rip in flight) 2026-06-05 15:33:58 -07:00
zeekay 6dd329ff3e mpc: swap minio-go/v7 → hanzos3/go-sdk v1.0.2
Canonical S3 SDK across the stack is the Hanzo S3 fork at
github.com/hanzos3/go-sdk (package `s3`). Imports use an explicit
`s3 "github.com/hanzos3/go-sdk"` alias to avoid the `go-sdk` last-path-
segment mismatch with `package s3`.

`pkg/backup/s3.go` swept: `minio.Client` → `s3.Client`, `minio.New` →
`s3.New`, `minio.Options` → `s3.Options`, `minio.MakeBucketOptions` →
`s3.MakeBucketOptions`, `minio.PutObjectOptions` → `s3.PutObjectOptions`.

Field name `s3Client *s3.Client` is fine (no shadow with the package
qualifier).

Dropped stale `luxfi/zapdb v1.0.0` entries in go.work.sum that were
blocking go mod tidy (their hashes no longer match the proxy after
zapdb's own sweep).

No behavioral changes.
2026-06-03 11:07:39 -07:00
zeekay 8181aa4e34 fix: gofmt -s across repo (CI format check) 2026-06-02 11:39:20 -07:00
zeekay cb61a4533f chore(deps): go get -u ./...
Updated dependencies to latest minor versions via go get -u + go mod tidy.
2026-06-02 11:16:12 -07:00
zeekay 44315d335f merge: feat/scale-standard 2026-06-01 16:35:38 -07:00
zeekay 4528ee4530 merge: env/drop-lux-prefix 2026-06-01 16:35:36 -07:00
zeekay 2ce4bb9918 merge: daemon-standalone-consensus-2026-04-28 2026-06-01 16:35:36 -07:00
zeekayandGitHub a23b56a1d2 build(mpc): GOEXPERIMENT=jsonv2 alongside runtimesecret per SCALE_STANDARD (#13)
* build(mpc): GOEXPERIMENT=jsonv2 alongside runtimesecret per SCALE_STANDARD

Per SCALE_STANDARD.md §2 (~/work/hanzo/hips/docs/SCALE_STANDARD.md) —
every Go production Dockerfile that emits JSON to a client builds with
GOEXPERIMENT=jsonv2. Verified on hanzoai/zip's json_bench_test.go:
- Edge POST roundtrip: -12% time, -23% allocs
- Marshal-only: -22% time
- Unmarshal-only: -19% time, -25% allocs

GOEXPERIMENT is comma-separated, so jsonv2 composes cleanly with the
pre-existing runtimesecret experiment used by the MPC data plane.

* ci: switch workflows to lux-build (luxfi-scoped ARC pool)

Cross-org runs-on dispatch failure: hanzo-build-linux-amd64 scale set is
registered to github.com/hanzoai and silently rejects luxfi/* jobs.
Switch to lux-build (githubConfigUrl=github.com/luxfi, max 20).

* test/zapauth: deterministic invalid-signature test (was flaky)

TestZapAuthInvalidSignature flipped one base64 char of the signature
segment. ECDSA accepts a wrong sig with probability ≈ 1/2^6 per
single-char flip (alphabet is 64), making the test ~1.5% flake rate
in CI.

Fix: replace the entire signature segment with all-A's. Still
decodable as base64url but cryptographically guaranteed-invalid
bytes — Verify rejection is now deterministic.

Verified: ran -count=10 ./pkg/zapauth/ — all pass.

* deps: bump accel/crypto/corona/threshold/fhe/lens/math to current tags

* api/db: decomplect — KeccakAddress on Wallet / TreasuryWallet / KeygenResult

Wave 5 of the workspace-wide eth* naming purge.

pkg/db/models.go — Wallet + TreasuryWallet:
- New canonical KeccakAddress *string field with json `keccakAddress`
- EthAddress kept with json `ethAddress` as `// Deprecated:` alias
- NormalizeAddresses() method on both structs mirrors the two fields
  via the package-private mirrorAddrPtrPair helper

pkg/api/server.go — KeygenResult (backend response):
- New canonical KeccakAddress string field with json `keccak_address`
- EthAddress kept with json `eth_address` as `// Deprecated:` alias
- NormalizeAddresses() method mirrors both fields

pkg/api/handlers_wallets.go, handlers_treasury.go, handlers_bridge.go,
handlers_mpc.go — all sites that constructed wallet rows from MPC
backend results now:
  1. Call result.NormalizeAddresses() on the backend response so both
     KeccakAddress / EthAddress carry the same value before copy
  2. Copy both fields onto the persisted Wallet / TreasuryWallet row
  3. Call wal.NormalizeAddresses() to ensure DB row has both
  4. Read from the canonical KeccakAddress at response-construction
     sites (toWalletResponse, treasury response, bridge response)

The "ethereum"/"lux"/"xrp" labels in addresses map (handleGetWalletAddresses)
are per-chain DISPLAY labels keyed by chain name a client knows;
the values are the Keccak-derived 20-byte address. Map keys NOT
decomplected here — they're per-chain UI labels, not internal naming.

Effect on the wire:
- API consumers reading wallet.ethAddress see the same value as
  wallet.keccakAddress
- New consumers can switch to keccakAddress today
- ORM persistence stores both fields (eventually consistent via
  NormalizeAddresses calls at handler boundaries)

Tests: pkg/api unit tests pass (1.8s); pkg/db has no test files.
Deprecation alias retention means downstream KMS / dashboards
keep working at every step of the migration.

Per CLAUDE.md x.x.x+1.

* strip KeccakAddress + EthAddress dual-field bridge (no aliases)

Forward-only completion of the workspace strip-aliases cascade. The
canonical JSON field is evmAddress, the Go field is EVMAddress. No
NormalizeAddresses helpers, no mirrorAddrPtrPair, no deprecated
KeccakAddress, no deprecated EthAddress.

Touched:
  pkg/api/server.go            KeygenResult drops KeccakAddress +
                               EthAddress + NormalizeAddresses
  pkg/db/models.go             Wallet drops KeccakAddress + EthAddress
                               TreasuryWallet drops KeccakAddress +
                               EthAddress
                               Drops NormalizeAddresses + mirrorAddrPtrPair
  pkg/api/handlers_wallets.go  rip mirror calls; only EVMAddress
                               populated on Wallet rows
  pkg/api/handlers_treasury.go rip mirror calls on TreasuryWallet
  pkg/api/handlers_mpc.go      rip NormalizeAddresses calls; rename
                               filter("ethAddress=") → ("evmAddress=")
  pkg/api/handlers_bridge.go   local var keccakAddress → evmAddr
  pkg/api/handlers_smart_wallets.go wallet.EthAddress → wallet.EVMAddress
  pkg/api/treasury_test.go     mock KeygenResult EthAddress → EVMAddress
  pkg/api/zap_kms_server_test.go same
  cmd/mpcd/main.go             pubKeyToEthAddress → pubKeyToEVMAddress,
                               \"eth_address\" → \"evm_address\",
                               local var ethAddr → evmAddr, KeygenResult
                               EthAddress → EVMAddress field

Deps: bump luxfi/metric v1.5.1 → v1.5.7 to pick up ExponentialBuckets
(via transitive luxfi/threshold dep).

The value IS \"EVM-runtime account address\" — that's the data model.
The Keccak256(secp256k1 pubkey) derivation is HOW.
2026-05-29 21:05:40 -07:00
zeekay dcdeb407ac strip KeccakAddress + EthAddress dual-field bridge (no aliases)
Forward-only completion of the workspace strip-aliases cascade. The
canonical JSON field is evmAddress, the Go field is EVMAddress. No
NormalizeAddresses helpers, no mirrorAddrPtrPair, no deprecated
KeccakAddress, no deprecated EthAddress.

Touched:
  pkg/api/server.go            KeygenResult drops KeccakAddress +
                               EthAddress + NormalizeAddresses
  pkg/db/models.go             Wallet drops KeccakAddress + EthAddress
                               TreasuryWallet drops KeccakAddress +
                               EthAddress
                               Drops NormalizeAddresses + mirrorAddrPtrPair
  pkg/api/handlers_wallets.go  rip mirror calls; only EVMAddress
                               populated on Wallet rows
  pkg/api/handlers_treasury.go rip mirror calls on TreasuryWallet
  pkg/api/handlers_mpc.go      rip NormalizeAddresses calls; rename
                               filter("ethAddress=") → ("evmAddress=")
  pkg/api/handlers_bridge.go   local var keccakAddress → evmAddr
  pkg/api/handlers_smart_wallets.go wallet.EthAddress → wallet.EVMAddress
  pkg/api/treasury_test.go     mock KeygenResult EthAddress → EVMAddress
  pkg/api/zap_kms_server_test.go same
  cmd/mpcd/main.go             pubKeyToEthAddress → pubKeyToEVMAddress,
                               \"eth_address\" → \"evm_address\",
                               local var ethAddr → evmAddr, KeygenResult
                               EthAddress → EVMAddress field

Deps: bump luxfi/metric v1.5.1 → v1.5.7 to pick up ExponentialBuckets
(via transitive luxfi/threshold dep).

The value IS \"EVM-runtime account address\" — that's the data model.
The Keccak256(secp256k1 pubkey) derivation is HOW.
2026-05-24 08:13:04 -07:00
zeekay 93980759db api/db: decomplect — KeccakAddress on Wallet / TreasuryWallet / KeygenResult
Wave 5 of the workspace-wide eth* naming purge.

pkg/db/models.go — Wallet + TreasuryWallet:
- New canonical KeccakAddress *string field with json `keccakAddress`
- EthAddress kept with json `ethAddress` as `// Deprecated:` alias
- NormalizeAddresses() method on both structs mirrors the two fields
  via the package-private mirrorAddrPtrPair helper

pkg/api/server.go — KeygenResult (backend response):
- New canonical KeccakAddress string field with json `keccak_address`
- EthAddress kept with json `eth_address` as `// Deprecated:` alias
- NormalizeAddresses() method mirrors both fields

pkg/api/handlers_wallets.go, handlers_treasury.go, handlers_bridge.go,
handlers_mpc.go — all sites that constructed wallet rows from MPC
backend results now:
  1. Call result.NormalizeAddresses() on the backend response so both
     KeccakAddress / EthAddress carry the same value before copy
  2. Copy both fields onto the persisted Wallet / TreasuryWallet row
  3. Call wal.NormalizeAddresses() to ensure DB row has both
  4. Read from the canonical KeccakAddress at response-construction
     sites (toWalletResponse, treasury response, bridge response)

The "ethereum"/"lux"/"xrp" labels in addresses map (handleGetWalletAddresses)
are per-chain DISPLAY labels keyed by chain name a client knows;
the values are the Keccak-derived 20-byte address. Map keys NOT
decomplected here — they're per-chain UI labels, not internal naming.

Effect on the wire:
- API consumers reading wallet.ethAddress see the same value as
  wallet.keccakAddress
- New consumers can switch to keccakAddress today
- ORM persistence stores both fields (eventually consistent via
  NormalizeAddresses calls at handler boundaries)

Tests: pkg/api unit tests pass (1.8s); pkg/db has no test files.
Deprecation alias retention means downstream KMS / dashboards
keep working at every step of the migration.

Per CLAUDE.md x.x.x+1.
2026-05-23 21:06:23 -07:00
zeekay f93a5c3d8a deps: bump accel/crypto/corona/threshold/fhe/lens/math to current tags 2026-05-21 15:00:31 -07:00
zeekay 619ea01b99 test/zapauth: deterministic invalid-signature test (was flaky)
TestZapAuthInvalidSignature flipped one base64 char of the signature
segment. ECDSA accepts a wrong sig with probability ≈ 1/2^6 per
single-char flip (alphabet is 64), making the test ~1.5% flake rate
in CI.

Fix: replace the entire signature segment with all-A's. Still
decodable as base64url but cryptographically guaranteed-invalid
bytes — Verify rejection is now deterministic.

Verified: ran -count=10 ./pkg/zapauth/ — all pass.
2026-05-21 12:22:22 -07:00
zeekay d3a3a34947 ci: switch workflows to lux-build (luxfi-scoped ARC pool)
Cross-org runs-on dispatch failure: hanzo-build-linux-amd64 scale set is
registered to github.com/hanzoai and silently rejects luxfi/* jobs.
Switch to lux-build (githubConfigUrl=github.com/luxfi, max 20).
2026-05-19 13:21:15 -07:00
zeekay d41adb9ef6 build(mpc): GOEXPERIMENT=jsonv2 alongside runtimesecret per SCALE_STANDARD
Per SCALE_STANDARD.md §2 (~/work/hanzo/hips/docs/SCALE_STANDARD.md) —
every Go production Dockerfile that emits JSON to a client builds with
GOEXPERIMENT=jsonv2. Verified on hanzoai/zip's json_bench_test.go:
- Edge POST roundtrip: -12% time, -23% allocs
- Marshal-only: -22% time
- Unmarshal-only: -19% time, -25% allocs

GOEXPERIMENT is comma-separated, so jsonv2 composes cleanly with the
pre-existing runtimesecret experiment used by the MPC data plane.
2026-05-19 12:35:01 -07:00
zeekay dbc7917431 fix: edwards25519 go.sum hash refresh (h1 + /go.mod both) 2026-05-19 09:57:04 -07:00
zeekay c9f2f30e9b merge: fix/edwards25519-gosum-hash — CI cross-compile arm64 from hanzo-build-linux-amd64 + gosum hash fix 2026-05-19 09:54:45 -07:00
zeekay a009254c51 ci: cross-compile arm64 from amd64 (no GH-hosted arm runners)
- docker.yml: drop ubuntu-24.04-arm. Both arches now build on
  hanzo-build-linux-amd64 via docker buildx + QEMU for the arm64 leg
  (QEMU is acceptable for Docker builds per policy).
- release.yml: drop the imaginary hanzo-build-linux-arm64 runner. Both
  arches cross-compile on hanzo-build-linux-amd64 with GOOS=linux
  GOARCH=<arch> (CGO_ENABLED=0).
2026-05-19 09:11:26 -07:00
zeekayandGitHub 76fc5b2b66 Merge pull request #12 from luxfi/fix/edwards25519-gosum-hash
fix: pin luxfi/edwards25519 v0.1.0 go.sum to proxy hash
2026-05-16 18:27:43 -07:00
zeekay 72e0a7b96c go.sum: pin luxfi/edwards25519 v0.1.0 to proxy hash
Same pattern as the threshold fhe + protocol zapdb fixes. Local-direct
hash differs from proxy.golang.org hash; CI uses proxy + sum.golang.org
and was failing on `GOWORK=off go mod download` with checksum mismatch.

Pin canonical proxy hash (h1:zuSrBtg... / h1:tFuuyXvI...).
2026-05-16 18:27:34 -07:00
zeekayandGitHub 290d5c391d Merge pull request #11 from luxfi/fix/pnpm-docker-build
fix(ui): pin pnpm 10.16.1 + onlyBuiltDependencies allowlist
2026-05-16 18:17:48 -07:00
zeekay 16fec218d6 fix(ui): pin pnpm 10.16.1 + onlyBuiltDependencies allowlist
Docker build was failing on `pnpm install` because corepack pulled the
latest pnpm (v11.x) which exits non-zero when build scripts (esbuild)
are present without explicit approval. Pin to v10.16.1 (stable, ships
the same `onlyBuiltDependencies` shape) and declare the esbuild build
script in package.json so future v11+ upgrades stay non-interactive.

Also swap `2>/dev/null || pnpm install` for `|| pnpm install --no-frozen-lockfile`
so we don't swallow real diagnostics — fall back to a controlled lockfile
update only when --frozen-lockfile fails.
2026-05-16 18:17:31 -07:00
zeekay 24fa827c89 deps: bump hanzoai/orm v0.4.0 → v0.5.2 (pure-Go SQLite, CGO_ENABLED=0) 2026-05-16 17:20:20 -07:00
zeekayandGitHub 281172ea48 chore: bump Go toolchain to 1.26.3 (#10)
Pin Go version to 1.26.3 across go.mod, CI workflows, and Dockerfiles
for canonical alignment with the rest of the luxfi/* stack.
2026-05-16 16:44:26 -07:00
zeekayandGitHub 064583dd82 Merge pull request #9 from luxfi/licensing/canonical-pointer
docs: add LICENSING.md pointer to canonical Lux IP strategy
2026-05-15 16:38:34 -07:00
zeekay babf013dbb docs: add LICENSING.md pointing at canonical Lux IP strategy
Single LICENSING.md file referencing the canonical three-tier IP and
licensing strategy at github.com/luxfi/.github/blob/main/profile/README.md.

LICENSE file is unchanged; this only adds a navigational pointer.
2026-05-15 16:38:27 -07:00
zeekayandGitHub f3bccb10e9 env: drop LUX_ prefix from env vars (noise) (#8)
Renames:
- LUX_ALLOW_FAKE_TFHE_FOR_TESTING_ONLY -> ALLOW_FAKE_TFHE_FOR_TESTING_ONLY
  (test opt-in for the placeholder UNSAFE TFHE primitive)
- LUX_MPC_CONFIG -> MPC_CONFIG (docs/compose env)
- LUX_MPC_MODE   -> MODE        (Viper config key 'mode' override)

The brand prefix was noise; the env var names speak for themselves.
README/LLM/config docs updated to reflect that Viper has no env prefix
configured (AutomaticEnv reads uppercased config keys directly), so the
prior 'LUX_MPC_*' documentation was inaccurate.

Note: file format magic in pkg/kvstore/zap_backup.go remains
"LUX_MPC_BACKUP" — that's an on-disk format identifier, not an env var.
Renaming it would invalidate every existing backup file.

BREAKING: external callers/operators must update their environment
variable names. Per CLAUDE.md no-backwards-compatibility rule, the old
forms are removed.
2026-05-15 16:01:13 -07:00
zeekay 95adb59fc7 env: drop LUX_ prefix from env vars (noise)
Renames:
- LUX_ALLOW_FAKE_TFHE_FOR_TESTING_ONLY -> ALLOW_FAKE_TFHE_FOR_TESTING_ONLY
  (test opt-in for the placeholder UNSAFE TFHE primitive)
- LUX_MPC_CONFIG -> MPC_CONFIG (docs/compose env)
- LUX_MPC_MODE   -> MODE        (Viper config key 'mode' override)

The brand prefix was noise; the env var names speak for themselves.
README/LLM/config docs updated to reflect that Viper has no env prefix
configured (AutomaticEnv reads uppercased config keys directly), so the
prior 'LUX_MPC_*' documentation was inaccurate.

Note: file format magic in pkg/kvstore/zap_backup.go remains
"LUX_MPC_BACKUP" — that's an on-disk format identifier, not an env var.
Renaming it would invalidate every existing backup file.

BREAKING: external callers/operators must update their environment
variable names. Per CLAUDE.md no-backwards-compatibility rule, the old
forms are removed.
2026-05-15 16:00:50 -07:00
zeekayandGitHub 5ffece2ede Merge pull request #7 from luxfi/chore/bump-threshold-1.6.12
chore: bump threshold v1.6.10 → v1.6.12 + corona v0.4.0
2026-05-15 15:50:32 -07:00
zeekay 3f077ed949 chore: bump threshold v1.6.10 → v1.6.12 + corona v0.4.0
Cascading from luxfi/threshold v1.6.12 (Ringtail → Corona rename, also
pulls corona v0.4.0). Unblocks mpc build against latest pins.
2026-05-15 15:50:12 -07:00
zeekayandGitHub c2ef7641fa Merge pull request #6 from luxfi/fix/gosum-edwards25519
go.sum: refresh filippo.io/edwards25519 checksum
2026-05-15 15:14:24 -07:00
zeekay 6c3a992835 go.sum: refresh filippo.io/edwards25519 checksum 2026-05-15 15:13:53 -07:00
zeekay b5e4df1e7e go.sum: fix luxfi/[email protected] hashes (match sum.golang.org) 2026-05-15 14:59:36 -07:00
zeekay 5d9ae0169e mpc: drop Ringtail identifiers — wire API renamed to Corona
The two MPC files that still carried Ringtail names:
  cmd/mpcd/main.go        — comment ref to luxfi/ringtail
  pkg/api/handlers_kms.go — ValidatorKeySet wire schema

handlers_kms.go renames:
  ValidatorKeySet.RingtailWalletID   → CoronaWalletID
  ValidatorKeySet.RingtailPublicKey  → CoronaPublicKey
  JSON tags ringtailWalletId/PubKey  → coronaWalletId/PubKey
  local `ringtailWalletID` and the per-validator suffix
  "validator-<id>-ringtail"          → "validator-<id>-corona"
  router switch `case "ringtail":`   → `case "corona":`

cmd/mpcd/main.go: comment "luxfi/corona and luxfi/ringtail" was
collapsed to just "luxfi/corona" — the dispatcher's not-yet-impl
stub now references only the live R-LWE library.

Wire break, no compat layer (forwards-perfection policy):
KMS callers must re-issue requests with the new field names.

Build: go build ./... PASS.
Tests: pkg/api PASS 1.374s.
2026-05-14 09:34:28 -07:00
zeekay b3b083c6d5 mpcd: gate embedded threshold dispatcher with bearer-token + loopback bind
Red round 5 finding B1. The embedded dispatcher on --threshold-listen
was an anonymous local signing oracle:

  1. Any process on the host could POST `{"method":"frost.sign",...}`
     and obtain signatures with no auth gate (only the API on :9800
     enforced MPC_INTERNAL_API_KEY).
  2. An operator typo `MPC_THRESHOLD_LISTEN=0.0.0.0:7300` exposed it
     cluster-wide.
  3. Any SSRF inside mpcd pivoted into the dispatcher.

Fix mirrors the existing internal-API auth pattern (cmd/mpcd/main.go
line ~456):

  - Auth token: read MPC_THRESHOLD_AUTH_TOKEN; if unset, derive a
    deterministic per-cluster token from the node Ed25519 seed
    (SHA-256(seed || "mpc-threshold-rpc") hex). All nodes share the
    same key without extra config; log warns when derivation is used.
    Server.SetAuthToken installs the gate.
  - Loopback bind: refuse non-loopback addr unless
    MPC_THRESHOLD_ALLOW_REMOTE=1 — operators must explicitly
    acknowledge the exposure. Bare `:port` (= 0.0.0.0) is NOT loopback.

Also picks up luxfi/threshold v1.6.10 which removes the pulsar/corona
in-memory-token surface (Red HIGH B2) — pulsar.*/corona.* now return a
typed "not yet implemented" error.

Tests:
  - TestIsThresholdLoopback locks the loopback predicate (8 cases:
    127.0.0.1, [::1], localhost OK; 0.0.0.0, :port, RFC1918 refused).
  - TestEmbeddedDispatcher_AuthGate proves 401 on missing/wrong token,
    200 on valid token through the dispatcher mpcd installs.

4 tests pass in cmd/mpcd (was 2, +2).
2026-05-13 16:46:22 -07:00
zeekay 0ea64a63e7 mpcd: embed luxfi/threshold/pkg/thresholdd dispatcher (six schemes)
mpcd is the production threshold daemon. With this commit it embeds
the JSON-RPC dispatcher from luxfi/threshold/pkg/thresholdd on a new
--threshold-listen flag (default 127.0.0.1:7300, MPC_THRESHOLD_LISTEN
env var). The dispatcher exposes every supported scheme:

  cggmp21 (secp256k1 ECDSA, CGGMP21 fork)
  frost   (secp256k1 Schnorr, RFC 9591)
  bls     (BLS12-381 Shamir/Lagrange)
  sr25519 (Ristretto255, via mpc node's own session — separate path)
  pulsar  (M-LWE / FIPS 204 ML-DSA-65 threshold, via luxfi/corona/threshold)
  corona  (R-LWE / Ringtail, via luxfi/ringtail/threshold)
  doerner (reserved; upstream protocol non-functional, returns explicit error)

Wire format matches teleport/mpc/src/signers/rpc.ts byte-for-byte:

  POST /  {"jsonrpc":"2.0","id":N,"method":"<scheme>.<op>","params":{...}}

Methods per scheme: keygen / sign / verify. Public-key handles are
returned by keygen and bound on sign/verify.

Decomplecting note: the dispatcher carries zero policy. Profile
gating, auth, audit, and rate-limiting live on mpcd's existing API
surface (and on the cluster ingress in front of it). The threshold
listener is loopback by default; production exposure happens via the
KMS-facing ZAP server or the gateway.

There is no separate thresholdd daemon to deploy. The luxfi/threshold
repo's cmd/thresholdd remains as a developer / CI binary that imports
the same package — one wire, one implementation, two startup paths.

Tests: TestEmbeddedDispatcher_BLSRoundTrip (full keygen → sign →
verify → forgery rejection) and TestEmbeddedDispatcher_UnknownScheme
(-32601 method-not-found contract) both pass. README updated with the
new protocol table; full surface documented in
luxfi/threshold/LLM.md "thresholdd — unified JSON-RPC dispatcher".
2026-05-13 15:56:56 -07:00
zeekay c6a0e2d1a6 deps: bump luxfi/crypto v1.19.0 — canonical luxfi/crypto/ipa 2026-05-13 11:55:40 -07:00
zeekay 4bf07ef07f client: spell out org-scoping requirements for Threshold.Cancel
Cancel was documented as "cancels a pending session belonging to the
caller's org" but the contract did not name HOW the implementation
enforces that. A loose implementation could:

  - read session, transition state, then check org_id (TOCTOU window)
  - distinguish "not yours" from "not found" in the error message
    (enumeration oracle leaks the existence of cross-org sessions)
  - skip the org predicate when a concurrent legitimate caller also
    has the row open (race condition lets the wrong-org call win)

Tightened doc names the three required behaviors:
  - orgID derived from ctx Claims, not caller-supplied
  - SELECT-FOR-UPDATE + WHERE org_id = ctx.OrgID; mismatch returns
    ErrSessionNotFound (same opaque response as unknown id)
  - row-level CAS with the org predicate in WHERE, so two callers
    cannot race the state transition
  - idempotency on already-cancelled scoped to the SAME org

go.work bumped to 1.26.3 to satisfy the per-module go directive.
2026-05-13 02:47:05 -07:00
zeekay 5e92895cb6 client: harden Threshold — payload-hash binding, idempotency-key conflict, typed errors, ctx-derived identity 2026-05-13 02:18:05 -07:00
zeekay 472c6e2669 client: declare canonical Threshold interface 2026-05-13 01:15:54 -07:00
zeekay 0db2f9b2e5 rename: drop upstream-brand mention in OAuth callback comment 2026-05-13 00:48:41 -07:00
zeekay 81a77675fb go.mod: bump go directive to 1.26.3 (security advisory) 2026-05-12 20:55:00 -07:00
zeekay e1895dc2d8 deps: database v1.18.3 (drops zapdb/v4 transitive) 2026-05-05 17:28:30 -07:00
zeekayandGitHub 00390645b9 fix(build): CGO_ENABLED=1 for go-sqlite3 (unblocks /v1/mpc/wallets) (#4)
* ringtail: fix lux/mpc go.sum corruption (luxfi/edwards25519)

The recorded go.sum hash for github.com/luxfi/[email protected] was
stale — the proxy now serves go.mod content (`module github.com/luxfi/
edwards25519\n\ngo 1.21\n`) that hashes to MBoV+bPE..., while go.sum had
the older tFuuyXvI... value (matching whatever go.mod content was first
published, evidently `module github.com/agl/ed25519`). Result: every Go
build in the workspace, including ringtail's dkg tests, errored with a
checksum mismatch SECURITY ERROR.

Fix: remove the two stale edwards25519 lines and re-run go mod tidy so
the current proxy content is re-pinned. New hashes:

  h1:YPoT831TZMslvNyy/KuTtpHi4BGZWgpwak06RCaYLzo=        (zip)
  h1:MBoV+bPEz1tSMADPMSUaYdZ+agY3syG8B6z7RmJBH0A=        (mod)

Verified: `cd ~/work/lux/ringtail && go test ./dkg/...` passes
TestDKG_2of3, TestDKG_3of5, TestDKG_InvalidParams, TestDKG_MissingData
(env override GOENV=/dev/null + GOPROXY=https://proxy.golang.org,direct
to bypass the unrelated GONOPROXY=hanzoai/* setting in the user's global
go env that prevents the proxy from serving the cached but git-deleted
hanzoai/[email protected] — that's a separate workspace-config issue,
not a go.sum corruption).

* fix(build): enable CGO so go-sqlite3 driver registers

The /v1/mpc/wallets HTTP API was 503'ing because CGO_ENABLED=0
left mattn/go-sqlite3 unregistered, so the wallet tables couldn't
open. Workaround was seeding wallets into TA's user_wallets table.

Switch to CGO=1 with statically-linked external linker so the binary
still runs in a scratch/alpine runtime without sqlite-libs at runtime.
2026-05-05 03:01:20 -07:00
zeekay 08c09c0349 feat(zapauth): JWKS-bearer gate on KMS-facing ZAP server (LP-103)
New pkg/zapauth verifies a JWT presented in OpAuthHello (0x00EF)
BEFORE the X25519+ML-KEM-768 hybrid handshake. Per-peer claims are
attached by ZAP peer ID and consulted on every opcode dispatch.

Backwards compatible: defaults to auth=off so v1.13.x clients keep
working. ZAP_AUTH_REQUIRED=true rejects unauthenticated peers; the
flip happens after every KMS deploys with bearer minting (luxfi/kms
v1.9.0 pkg/iamclient).

- pkg/zapauth/{verifier,verifier_test}.go — Verifier, JWKS cache,
  AuthHello frame, stdlib-only signature verification (RS/ES/EdDSA).
- pkg/api/zap_kms_server.go — KMSZapConfig, StartKMSZAPWith, per-op
  checkAuth gate, OpAuthHello handler.
- pkg/api/zap_kms_server_auth_test.go — required+advisory+missing+bad
  token + nil-verifier integration tests against a self-contained
  ES256 JWKS endpoint.
- cmd/mpcd/main.go — wires ZAP_JWKS_URL / ZAP_EXPECTED_ISS /
  ZAP_EXPECTED_AUDIENCES / ZAP_AUTH_REQUIRED env vars.
- docs/zap-auth.md, LLM.md — protocol reference + LLM map entry.

Tests: pkg/zapauth (13/13), pkg/api KMSZAP (10/10 — 5 original +
5 new auth integration), pkg/zap (existing untouched).
2026-05-02 09:30:48 -07:00
zeekay f9ae303ec9 fix(ui): remove orphan pages blocking docker build
Users/Webhooks/Whitelist/APIKeys/Devices/Login/Operations and the
webauthn.ts shim referenced API methods, hooks, and types that were
never implemented in lib/api.ts or hooks/use-mpc.ts. None are routed
in App.tsx — pure dead code that broke `pnpm build` (and therefore
the Docker UI stage).

Routed pages remain: Dashboard, Wallets, Vaults, Policies,
Settlements, Bridge, Payments, Audit, Settings.

Unblocks ghcr.io/luxfi/mpc:v1.13.2 publish for #70 ZAP rollout.
2026-05-01 01:55:28 -07:00