opam install jasmin pulls apron → mlgmpidl which needs libmpfr-dev and
libppl-dev system packages. opam refuses to apt-install interactively
in CI (responds 'n' to the depext prompt), so preinstall in apt step.
Closes PULSAR-V04-CTX. The previous v0.3 OrchestrateV03Sign hardcoded
the FIPS 204 §5.4 step-2 ctx prefix to empty (0x00 0x00); ctx-bound
permissionless threshold sign was therefore impossible and operators
that needed FIPS 204 §5.2 domain separation (e.g. the
lux-evm-precompile-mldsa-v1 EVM precompile) had to route through the
threshold dispatcher's dealerKey single-party shortcut, which
materialised the master sk in the dispatcher process — breaking the
v0.3 public-BFT-safety contract for any session that used the
ctx-bound path.
API additions (ref/go/pkg/pulsar):
- NewAlgebraicThresholdSignerCtx(..., ctx, ...) — per-party state
machine bound to FIPS 204 §5.4 ctx.
- AlgebraicAggregateCtx(..., ctx, ...) — public-BFT-safe aggregator
that threads ctx into the μ prehash.
- OrchestrateV03SignCtx(..., ctx, ...) — one-shot ctx-bound driver,
sibling of OrchestrateV03Sign.
- ErrCtxTooLarge — alias of ErrCtxTooLong returned at ALL three
boundaries (constructor, aggregator, orchestrator) on ctx > 255.
Backwards compatibility:
- OrchestrateV03Sign(msg) == OrchestrateV03SignCtx(nil, msg)
byte-for-byte under identical deterministic RNG seeds.
- AlgebraicAggregate is now a thin wrapper calling
AlgebraicAggregateCtx with nil ctx.
- NewAlgebraicThresholdSigner is now a thin wrapper calling
NewAlgebraicThresholdSignerCtx with nil ctx.
The μ derivation is decomplected into ONE helper deriveMuCtx — the
single source of truth for FIPS 204 §5.4 step 2. Both per-party
Round-2 and the aggregator call it; signer/aggregator parity is
structural.
v0.2 (TransitionalAggregate) deleted from pulsar core: it materialised
the master sk at sign time. Operator-controlled MPC custody that
requires master-sk reconstruction lives at
luxfi/threshold/protocols/mldsa-tee/ behind an explicit TEE attestation
gate. v0.3/v0.4 algebraic-aggregate is the SOLE permissionless
production path. mldsa_wire.go now hosts the version-agnostic FIPS 204
ring primitives previously co-located with v0.2.
Tests added (threshold_v03_ctx_test.go):
- TestOrchestrateV03SignCtx_Mu_Includes_Ctx — μ depends on ctx.
- TestOrchestrateV03SignCtx_EmptyCtx_MatchesV03Sign — backwards-compat
byte-equality under identical seeds.
- TestOrchestrateV03SignCtx_CtxTooLarge_Rejected — 256-byte ctx
refused at constructor + aggregator + orchestrator.
- TestOrchestrateV03SignCtx_VerifyMatchesFIPS204 — output verifies
under cloudflare/circl mldsa65.Verify with same ctx, rejected with
different ctx.
TestAlgebraic_NoSkAccess now covers BOTH AlgebraicAggregate (the
wrapper) AND AlgebraicAggregateCtx (the load-bearing entry point) via
runAlgebraicAggregateASTChecks.
EasyCrypt proof: proofs/easycrypt/V04_Sign_Ctx.ec — discharges
threshold_sign_ctx_equiv_fips204_sign_with_ctx (AlgebraicAggregateCtx
output ≡ FIPS 204 §5.4 SignCtx(sk_master, ctx, M)) under the same
abstract reductions Pulsar_N1.ec uses for empty ctx, plus the
empty-ctx specialisation corollary.
CI: opam install alt-ergo (Ubuntu 24.04 noble dropped the apt package).
Graduation gates: full pkg/pulsar suite green under -count=1 -short
and -race (M2 Pro release: 8.3s plain / 136.4s race).
cd ref/go && GOWORK=off go test -count=1 -short -timeout 600s ./...
cd ref/go && GOWORK=off go test -race -count=1 -short -timeout 900s ./pkg/pulsar/