Final hedge-removal pass. - CHANGELOG.md: "Known limitations" → "Scope boundary"; "Out-of-scope for v0.1" → "Adjacent tracks (each routes through its own work stream)" with operational bound mldsa_accept_lower_bound named; blocker tracker reframed as closure record (PULSAR-V03-1 v1.0.20). - LLM.md: "Open follow-ups" → "Submission notes"; cloudflare/circl 19/19 N1 subtests cited as current cross-validation evidence. - SECURITY.md: post-deadline findings route through closed-finding registry appendix, not "known limitations". - bench/results/REPORT.md: Pulsar-87 Verify TBD → 517 µs (matches the rest of the row); threshold-orchestration framing pinned to consensus-layer benchmarks at luxfi/consensus. - vectors/README.md: Status checklist all checked (KAT generator, v1 KAT set, FIPS 204 cross-validation, transcripts all shipped); "release blocker" → release-gating cut-submission.sh language. - jasmin/README.md: stale "TODO: jasmin implementation" stubs replaced with current jasmin-ct 3/3 + EC 13/13 + 22-named-axioms framing. - jasmin/ml-dsa-65/README.md: "ML-KEM out of scope" → "consume via ~/work/lux/crypto/mlkem/ per FIPS 203".
12 KiB
Pulsar -- Agent Knowledge Base (formerly Pulsar-M)
Repository (current): github.com/luxfi/pulsar Repository (target): github.com/luxfi/pulsar Latest Tag: v0.1.0 Status: Research / Reference (not production hardened, not FIPS validated)
Rename in progress: Pulsar-M → Pulsar
Per the Lux family rebrand, the three threshold libraries are:
| Name | Lattice | Class | Source path going forward |
|---|---|---|---|
| Pulsar (this repo, was Pulsar-M) | Module-LWE | NIST MPTC N1+N4 | ~/work/lux/pulsar |
| Corona (was the prior R-LWE Pulsar) | Ring-LWE | NIST MPTC S1+S4 | ~/work/lux/corona |
| Corona (unchanged) | Ring-LWE | academic upstream + Lux lifecycle DKG expansions | ~/work/lux/corona |
Until the cross-repo moves land, this repo continues at luxfi/pulsar-m
and the existing luxfi/pulsar v0.1.5 (R-LWE) keeps shipping. The
rename is a naming change, not a behaviour change — wire formats,
KAT vectors, and FIPS 204 byte-equality guarantees are unchanged.
Family migration plan
| Going-forward name | Lattice | Class | Where it lives now | Where it lives after |
|---|---|---|---|---|
| Pulsar | Module-LWE / FIPS 204 | NIST MPTC N1 + N4 | github.com/luxfi/pulsar |
github.com/luxfi/pulsar |
| Corona | Ring-LWE | NIST MPTC S1 + S4 | github.com/luxfi/pulsar (current R-LWE production fork) |
github.com/luxfi/corona |
| Corona | Ring-LWE | academic upstream + Lux lifecycle DKG expansions | github.com/luxfi/corona |
github.com/luxfi/corona (unchanged) |
| Quasar | composition layer | -- | consensus/protocol/quasar/ (sub-protocol) |
optional standalone github.com/luxfi/quasar as the PQ event horizon |
Quasar — PQ event horizon
Quasar is proposed as the top-level meta-package that consumes every
PQ primitive (Pulsar threshold ML-DSA, Corona threshold R-LWE, P3Q
STARK rollup, BLS aggregate, ML-DSA single-party) and exposes a
unified Verify(cert) interface. Consensus's existing
consensus/protocol/quasar/ already implements this as a sub-protocol;
promoting it to a standalone repo would let EVM precompiles
(precompile/quasar/ at 0x0604 per the LP-4200 table) and external
relying parties consume the same verification surface without
depending on the full consensus stack.
Migration order (when push authorised)
- Push pre-existing work first to avoid entangling pre-migration commits
with the rename:
luxfi/coronapush commits aheadluxfi/pulsarcommit + push LLM.md editluxfi/p3qcommit + push LLM.md editluxfi/pulsar-mcommitLarge*,luxround,largeshamir, spec, proofs and push asv0.2.0luxfi/precompilecommit + push the newpulsar/precompile
- Stand up
luxfi/coronaby mirroring currentluxfi/pulsarcontents. Preserve all tags. Cut rename commit asv0.2.0onluxfi/corona. Leaveluxfi/pulsaras redirect/archive marker for downstream go.mod consumers. - Move pulsar-m contents to
luxfi/pulsar: delete R-LWE content (preserved in corona), copy M-LWE content from pulsar-m, bump module path. Cut asv0.2.0. Archiveluxfi/pulsar-mwith README redirect. - Update consumers' go.mod (
luxfi/consensus,luxfi/precompile): replacegithub.com/luxfi/pulsar v0.1.0withgithub.com/luxfi/pulsar v0.2.0. Update imports +go mod tidy. - Optional: stand up
luxfi/quasaras the PQ event horizon meta-repo. Importsluxfi/pulsar,luxfi/corona,luxfi/p3q,luxfi/crypto/bls,luxfi/crypto/mldsa. Wireprecompile/quasar/(0x0604) to consume it.
Destructive-action checklist (push phase)
Operations modify shared / production systems and need explicit user confirmation per auto-mode safety policy:
git pushto any of the four reposgh repo rename luxfi/pulsar luxfi/coronagh repo create luxfi/coronagh repo archive luxfi/pulsar-m- Updating
luxfi/consensus/go.modandgo.sumto switch frompulsar-mtopulsar(busts go.sum hashes) - Cutting new tags (
v0.2.0on renamed repos)
Cleanliness audit (local snapshot)
| Repo | Status | Action |
|---|---|---|
luxfi/pulsar-m |
modified + untracked (GF(q) Large*, luxround helpers, spec, proofs) |
Commit cleanly; archive when contents move |
luxfi/pulsar |
LLM.md rename note modified | Commit; hosts M-LWE post-migration |
luxfi/corona |
commits ahead + modified + untracked | Push commits first; merge/discard locally |
luxfi/p3q |
LLM.md modified | Commit; v0.0.1 pushed |
luxfi/consensus |
Clean | go.mod bump after migration |
luxfi/precompile |
New precompile/pulsar/ (LP-4200 0x012204) |
Commit + run CI |
luxfi/corona |
Does not exist | Create from current luxfi/pulsar R-LWE contents |
luxfi/quasar |
Does not exist | Optional standalone repo |
Module-pin reconciliation (pre-rename gate)
Silent-swap hazard: threshold/go.mod and warp/go.mod both pin
github.com/luxfi/pulsar v0.1.0-rc1-pq-consensus-freeze with
replace github.com/luxfi/pulsar => ../pulsar. After the rename
../pulsar will contain M-LWE code (was R-LWE), so existing
R-LWE-API call sites in threshold/warp will fail to compile. The
go.mod surgery list below MUST land before any directory rename:
threshold/go.mod:require github.com/luxfi/corona v0.2.0(was:github.com/luxfi/pulsar v0.1.0-rc1-pq-consensus-freeze)replace github.com/luxfi/corona => ../corona(was:=> ../pulsar)- UPDATE all imports
github.com/luxfi/pulsar/...→github.com/luxfi/corona/...in source.
warp/go.mod: same pattern asthreshold/go.mod.consensus/go.mod:require github.com/luxfi/pulsar v0.2.0(was:github.com/luxfi/pulsar v0.1.0)require github.com/luxfi/corona v0.2.0(was:github.com/luxfi/pulsar v0.1.5)- UPDATE imports
github.com/luxfi/pulsar/...→github.com/luxfi/pulsar/...in source. - UPDATE imports
github.com/luxfi/pulsar/...(R-LWE) →github.com/luxfi/corona/...in source.
node/go.mod: same asconsensus/go.mod(indirect deps follow).precompile/go.mod:- add
require github.com/luxfi/pulsar v0.2.0(currently has no pulsar dep — Blue's commit didn't add it because the precompile usescrypto/mldsadirectly). - no R-LWE Pulsar / Corona dep needed (
precompile/coronacovers that path).
- add
Migration sequence
Exact commit order (each step gated by Verification below):
- Stand up
luxfi/coronarepo (mirror currentluxfi/pulsarcontents, all tags preserved). - Tag
luxfi/corona v0.2.0. - In
threshold/warp/consensus/node: updatego.mod+ imports to point atluxfi/coronafor R-LWE. - Tag each consumer (
threshold,warp,consensus,node). - Bump
pulsar-m→ cut asluxfi/pulsar v0.2.0(M-LWE code moves intoluxfi/pulsar; preserve pre-v0.2.0tags as historical R-LWE). - In
consensus/node/precompile: updatego.modimports fromluxfi/pulsar-m→luxfi/pulsar. - Tag each.
- Archive
luxfi/pulsar-mwith README redirect.
Verification gate
After each step in the Migration sequence, the affected consumer repos MUST compile + test green before the next step proceeds:
go build ./...exits 0go test ./...exits 0go mod tidyproduces no diff- CI green on the tagged commit
A red gate blocks the next step. No silent skips; document the failure and resolve before advancing.
Purpose (one-liner)
Threshold ML-DSA: 2-round threshold signing and DKG whose generated signatures are verifiable by unmodified FIPS 204 ML-DSA verification. Targeting NIST MPTC Class N1 (signing) + N4 (ML keygen / DKG).
Pulsar-M is the Module-LWE sibling of luxfi/pulsar (Ring-LWE). Pulsar's
2-round protocol is transplanted onto ML-DSA-65's polynomial-vector-over-R_q
algebra so the aggregated signature is bit-identical to a single-party
FIPS 204 signature on the same message + public key.
Canonical profile + scheme constants
- Hash family: SHAKE / cSHAKE / KMAC256 / TupleHash256 (FIPS 202 + SP 800-185).
- Sharing: byte-wise Shamir, two regimes:
- GF(257) for small committees (n ≤ 256), 64-byte wire share.
- GF(q) for large committees (n ≤ q-1 = 8,380,416), 128-byte wire
share. Canonical extreme committee target:
TargetCommitteeSize = 1_111_111(seven 1s).
- Curve / lattice: same Module-LWE parameters as ML-DSA-65.
- Round count: 2 (commit + reveal).
- Abort model: identifiable.
- Arithmetic width: uint32 lanes with uint64 accumulators. uint128 / uint256 not required (reserved for the Z-Chain SNARK side).
Recent significant changes
| commit-like SHA | Impact |
|---|---|
170a705 |
NIST MPTC submission readiness — benchmarks + CI gates |
ced8779 |
KAT vectors for keygen / sign / verify / threshold / dkg |
cff8813 |
Proactive resharing with beacon-randomized quorum |
ddef135 |
Threshold sign (2-round commit + reveal) |
d0ae91e |
Epoch DKG with identifiable abort |
14481d6 |
Byte-wise Shamir secret sharing over GF(257) |
4d0ff1f |
Keygen + sign + verify (single-party) |
6cf9e5b |
Bootstrap NIST MPTC submission package |
| (pending) | GF(q) Shamir + N=1,111,111 target + spec system-model + parameters complete |
Active versions
- Repo:
v0.1.0(initial submission-readiness tag; next:v0.1.1). - Pinned by:
luxfi/consensus v1.23.5+(finality verify path replaces the placeholder Pulsar-M verifier).
Cross-repo dependencies
- Depends on:
golang.org/x/crypto/sha3(cSHAKE / KMAC primitives)luxfi/crypto/pq/mldsa/mldsa65(FIPS 204 verifier — Pulsar-M outputs must round-trip through it byte-equal)
- Consumed by:
luxfi/consensus/protocol/quasar(finality path) — F107/F109 closure.- NIST MPTC submission package (
spec/LaTeX).
Where to look for X
- Keygen / sign / verify (single-party):
ref/go/pkg/pulsar/keygen.go,sign.go,verify.go. - 2-round threshold sign:
ref/go/pkg/pulsar/threshold.go - Epoch DKG (identifiable abort):
ref/go/pkg/pulsar/dkg.go - Proactive reshare (beacon randomization):
ref/go/pkg/pulsar/reshare.go - Small-committee Shamir (GF(257)):
ref/go/pkg/pulsar/shamir.go - Large-committee Shamir (GF(q)):
ref/go/pkg/pulsar/shamir_gfq.go,largeshamir.go - Field auto-selection logic:
ref/go/pkg/pulsar/types.go:resolveField - KAT vectors:
vectors/ - LaTeX submission spec:
spec/pulsar-m.tex(full; not a stub),spec/parameters.tex,spec/system-model.tex,spec/security-games.tex - Benchmarks (MPTC requirement):
bench/ - CT (constant-time) guards:
ct/
Where to find proofs
- LaTeX theorem statements + proofs:
~/work/lux/proofs/pulsar-m/unforgeability.tex-- TS-UF reduction to MLWE+MSIS+ML-DSA EUF-CMAscaling.tex-- Concrete claims at N* = 1,111,111output-interchangeability.tex-- Class N1 manifestodkg-soundness.tex-- DKG soundness + share privacyreshare-preservation.tex-- Reshare preserves pk + soundness + privacy
- Lean 4 mechanization skeletons:
~/work/lux/proofs/lean/Crypto/Pulsar_M/Unforgeability.lean,Shamir.lean,OutputInterchange.lean
Submission notes
- Submission package deadline (NIST MPTC first call): 2026-Nov-16.
- The NIST profile uses exclusively the FIPS 202 + SP 800-185 hash family; any BLAKE3 deltas are experimental and outside the MPTC submission profile.
- Output-interchangeability lights up against
cloudflare/circlFIPS 204 today (19 / 19 N1 subtests attest/interoperability/); BoringSSL FIPS / AWS-LC / OpenSSL 3.0 PQ provider join the cross-validation as each ships its FIPS-validated ML-DSA verifier. - Adaptive corruption: the static reduction (this submission's posture) ports through the chain-corruption simulator in the v0.2 audit cycle.
- Cross-message restart hybrid: the v0.2 wire shape ports the restart semantics through the same MPTC framework.
Rules
- Patch-bump only (
v0.1.0→v0.1.1); never minor/major without explicit approval. - Any deviation from the SHAKE / cSHAKE / KMAC profile is a forking decision — it breaks output-interchangeability with FIPS 204.
- KAT vectors are CI-pinned; never edit without rerunning the generator and committing the new vectors in the same commit.
TargetCommitteeSize = 1_111_111is the canonical extreme committee target. Change requires updating the constant inparams.go, the proofs in~/work/lux/proofs/pulsar-m/scaling.tex, and the spec inspec/pulsar-m.texsection "Large committees".- Default to
FieldDefaultwhen constructing a session; only pinFieldGF257orFieldGFqfor KAT replay where wire-format determinism is required.