Files
threshold/pkg/thresholdd/doc.go
T
zeekay d92cad5638 security(thresholdd): remove trusted-dealer BLS scheme — H-2
The thresholdd daemon registered a "bls" scheme whose keygen ran a
TrustedDealer in-process (one node mints the whole group secret key) —
the same single-point-of-compromise trusted-dealer BLS custody removed
from mpc. BLS is consensus-only (native per-validator keys), never a
custodied threshold key. Remove the daemon's bls scheme so the dispatcher
can no longer mint a trusted-dealer BLS key.

- Delete pkg/thresholdd/bls.go (blsScheme / TrustedDealer keygen).
- server.go: drop s.schemes["bls"] + the bls keygen/sign/verify procs.
- zap_schema.go: drop ProcBLS{Keygen,Sign,Verify} opcodes.
- Tests: delete the bls-specific round-trip + benchmarks; rewire the
  auth-gate tests (which used bls only as a fast keygen driver) to frost;
  drop bls from the sign_ctx unsupported-scheme loop.
- Scrub stale bls mentions from doc comments.

NOT touched: protocols/bls (the library primitive) stays — luxfi/chains
(a non-owned repo) consumes bls.TrustedDealer/AggregateSignatures
directly. Deleting protocols/bls must be a coordinated change with the
chains owner; flagged, not forced here.

Verified: GOWORK=off go build ./... green; affected thresholdd tests
(auth-gate, ProcOpcode, ZapShares, FrostRoundTrip, sign_ctx unsupported)
pass without -short. Zero bls refs remain in thresholdd.
2026-06-26 18:46:02 -07:00

91 lines
4.0 KiB
Go

// Package thresholdd is the ZAP-native dispatcher that exposes every
// luxfi/threshold protocol (cggmp21, frost, pulsar, corona, magnetar,
// doerner) on a single byte-passthrough transport.
//
// One wire, one transport: the historical HTTP+JSON+hex path was
// removed in favour of ZAP byte-passthrough. There is no JSON-RPC
// fallback, no `--http` flag, no deprecation shim. Pre-cutover
// JSON-RPC clients fail to connect — that is the documented behaviour.
//
// The same dispatcher is started by both:
//
// - The standalone thresholdd binary (cmd/thresholdd/main.go) used
// for development and CI; and
// - luxfi/mpc's production daemon mpcd, which embeds the dispatcher
// as a sub-listener so a single MPC process owns every threshold
// scheme it speaks.
//
// Wire shape (see zap_schema.go for the field offsets):
//
// ZAP message with procedure opcode in msg.Flags upper byte;
// message kind (request/response/error) in the lower byte.
//
// Procedures (per scheme):
//
// <scheme>.keygen { Threshold, Participants }
// -> { PublicKey, Shares } (all bytes)
// <scheme>.sign { Message, PubKey }
// -> { Signature }
// <scheme>.verify { Message, Signature, PubKey }
// -> { OK }
//
// Pulsar and magnetar additionally expose:
//
// <scheme>.sign_ctx { Message, PubKey, Ctx, ChainID }
// -> { Signature }
//
// where Ctx is the FIPS-204 §5.2 / FIPS-205 §10.2 context octet
// string (raw bytes; empty binds the empty ctx). Signatures emitted
// via sign_ctx satisfy the on-chain EVM precompile's domain-
// separation contract (`lux-evm-precompile-mldsa-v1` /
// `lux-evm-precompile-slhdsa-v1`) — verifiable by passing the same
// ctx to luxfi/precompile/{mldsa,slhdsa}.VerifySignatureCtx, or by
// any FIPS-204/205 verifier with ctx-binding support.
//
// Decomplecting note: this package contains zero ROUTING policy.
// Per-method admission, auth, audit, and rate limiting belong on
// the caller side (mpcd's API surface, or the teleport bus).
//
// Strict-PQ profile gate (profile.go):
//
// The dispatcher DOES carry one narrow piece of policy: the
// strict-PQ refusal gate on Sign_Ctx. This is NOT routing —
// it is a primitive-soundness guard tightly coupled to the
// pulsar v0.3 dealer shortcut (and the magnetar single-
// validator shortcut) that the dispatcher's Sign_Ctx path
// uses today. Refusing those under strict-PQ has to happen at
// the call site that produces the signature, not at an outer
// routing layer that does not know which signing path the
// dispatcher chose. The gate is ONE function in ONE place:
// profile.go::RefuseUnderStrictPQ.
//
// Strict-PQ profile semantics:
//
// - Strict-PQ profile (ProfileID 0x01 or 0x03 in
// luxfi/consensus/config terms): NO single-party dealer
// shortcuts ANYWHERE on the dispatcher. Sign_Ctx refuses
// with a ZAP ErrorResponse carrying strictPQ=true (callers
// branch via errors.Is(ErrRefusedUnderStrictPQ)) until the
// underlying primitive is swapped to a proper threshold
// ctx-bound path (pulsar v0.4 OrchestrateV03SignCtx;
// magnetar aggregate cert with ctx).
// - Legacy-compat profile (everything else): dealer shortcuts
// are acceptable as documented dev-tooling. Operators are
// responsible for not building production on top of
// permissive profiles.
//
// Chain-profile lookup is supplied by the embedder via the
// ChainProfileResolver interface (no upward dep on
// luxfi/consensus/config). The standalone thresholdd CLI
// leaves the resolver unwired (gate fails open — dev tooling);
// luxfi/mpc / luxfi/node wire an adapter that calls
// config.ProfileByID under the hood.
//
// When sister-agent's pulsar v0.4 / magnetar aggregate-cert
// ctx-bound paths land, the dispatcher's Sign_Ctx swaps to
// those — the gate then becomes dead code on those call sites
// and the chain-ID-based refusal vanishes. profile.go and
// the gate function stay as the documented audit hook for any
// future primitive-soundness gate on strict-PQ chains.
package thresholdd