pulsar-m: convert NIST MPTC deliverables docs/*.md → spec/*.tex (CLAUDE.md LaTeX-only rule)

Per ~/.claude/CLAUDE.md ("papers/proofs/audits stay in LaTeX, never .md"
+ "NEVER write random summary files"), the six NIST MPTC submission
deliverables move from docs/ Markdown into spec/ LaTeX as
\input{...} chapters of pulsar-m.tex:

  docs/nist-mptc-category.md   -> spec/nist-mptc-category.tex
  docs/patent-notes-draft.md   -> spec/patent-notes.tex
  docs/threat-model.md         -> spec/threat-model.tex
  docs/known-limitations.md    -> spec/known-limitations.tex
  docs/family-architecture.md  -> spec/family-architecture.tex
  docs/design-decisions.md     -> spec/design-decisions.tex

Content preserved verbatim; only LaTeX-syntax stylistic edits.
pulsar-m.tex now \inputs each as its own section / appendix.
Go-source comments that referenced docs/* updated to spec/*.tex.
README + CONTRIBUTING refreshed.

GOWORK=off go test -count=1 ./... clean.
This commit is contained in:
2026-05-11 12:31:43 -07:00
parent 38319c9fc8
commit 52eea92a11
21 changed files with 1187 additions and 936 deletions
+1 -1
View File
@@ -70,4 +70,4 @@ By contributing, you agree your contribution is licensed under Apache-2.0
and grant the patent license described in the Apache 2.0 §3.
For NIST MPTC submission: contributions are subject to the patent-claim
disclosures collected in `docs/patent-notes-draft.md`.
disclosures collected in `spec/patent-notes.tex`.
+2 -2
View File
@@ -71,7 +71,7 @@ pulsar-m/
## Quickstart
> **Pulsar-M is in pre-spec stage.** Reference impl, vectors, and bench harness
> ship after the spec freezes. Track [docs/known-limitations.md](docs/known-limitations.md)
> ship after the spec freezes. Track [spec/known-limitations.tex](spec/known-limitations.tex)
> for what's stable vs in-flight.
```bash
@@ -90,7 +90,7 @@ cd pulsar-m
| Technical Specification | `spec/pulsar-m.pdf` (built from `spec/pulsar-m.tex`) | draft |
| Reference Implementation | `ref/go/` | skeleton |
| Report on Experimental Evaluation | `bench/results/REPORT.md` | TBD |
| Notes on Patent Claims | `docs/patent-notes-draft.md` | TBD |
| Notes on Patent Claims | `spec/patent-notes.tex` | TBD |
| Open-source license | `LICENSE` (Apache-2.0) | ✓ |
| Build/test/benchmark scripts | `scripts/` | skeleton |
| I/O test vectors | `vectors/kat-v1.{json,rsp}` | TBD |
-161
View File
@@ -1,161 +0,0 @@
# Design decisions log
Each entry: decision, rationale, alternatives, status, date.
## DD-001 Target FIPS 204 output interchangeability (Class N)
**Decision.** Pulsar-M aims for Class N1 + N4 (NIST MPTC IR 8214C):
threshold-produced signatures verify under unmodified FIPS 204
ML-DSA.Verify.
**Rationale.** Output interchangeability gives the strongest NIST
positioning. FIPS-validated ML-DSA modules in 2026 (BoringSSL FIPS,
AWS-LC, OpenSSL 3.0) consume Pulsar-M certs without code changes. This
is the headline pitch for MPTC.
**Alternative.** Class S (special threshold-friendly primitive). Easier
spec, but does not give the FIPS-module-compatibility win. Pulsar
(R-LWE) takes this path.
**Status.** Targeted. Final class decision deferred until reference impl
demonstrates byte-equal output on at least one parameter set.
## DD-002 Hash family: SHA-3 (cSHAKE256 / KMAC256 / TupleHash256) only
**Decision.** Pulsar-M's NIST profile uses exclusively the FIPS 202 + SP
800-185 hash family. No BLAKE3.
**Rationale.** NIST MPTC §4.6 lists allowed symmetric primitives for
Class N: AES, Ascon, SHA-2, SHA-3, SHAKE/cSHAKE, HMAC/KMAC/CMAC/GMAC.
BLAKE3 is not on the list. Including BLAKE3 in the NIST submission
profile is a strategic liability.
The same SHAKE-256 sponge is used internally by ML-DSA-65 (FIPS 204
§5.1). Sharing the hash family with the underlying primitive removes a
whole class of cryptanalytic concern (cross-domain collisions, mixed
hash-family soundness arguments).
**Alternative considered.** Dual-suite with BLAKE3 as the production
profile and SHA-3 as the NIST profile, like Pulsar's current dual-suite.
Rejected because Pulsar-M is NIST-track and shouldn't ship a non-NIST
default.
**Status.** Final.
## DD-003 Lattice: Module-LWE per FIPS 204, not Ring-LWE
**Decision.** Pulsar-M operates over `R_q^k` (module of polynomials)
with the same `(q, k, ℓ, η, β, ω, ...)` parameter set as ML-DSA-65.
Not `R_q` (single polynomial) as Pulsar / Corona use.
**Rationale.** This is the whole point of the project. Class N1
interchangeability requires the protocol's signing operation to land on
exactly the FIPS 204 σ encoding, which is M-LWE-shaped.
**Alternative.** Stay R-LWE. Easier (we already have Pulsar). But then
we lose the Class N positioning and become Class S like Pulsar.
**Status.** Final.
## DD-004 Reference implementation language: Go
**Decision.** Reference implementation is Go (`ref/go/`). C
implementation comes after spec encodings freeze (`ref/c/`).
**Rationale.** Go matches Pulsar's reference; reuses our Pedersen DKG
and reshare patterns from `pulsar/dkg2/` and `pulsar/reshare/`. Clear,
boring, no assembly. NIST MPTC §4.3 doesn't mandate language.
**Alternative.** C reference first. Standard NIST PQC submission style.
Rejected for round 1 because we need to ship by 2026-Nov-16; Go is
faster to write and review. C reference becomes a follow-on artifact
for round 2 review.
**Status.** Final for MPTC round 1.
## DD-005 DKG: Pedersen-style over `R_q^k`
**Decision.** Distributed keygen uses Pedersen DKG over the M-LWE module
ring, with Feldman-style verifiable secret sharing replaced by the
module-shaped Pedersen commitment scheme.
**Rationale.** Pulsar's `dkg2/` package already does this for `R_q`
(R-LWE). The M-LWE port preserves the soundness argument with constant
overhead per coefficient slot.
**Alternative.** Trusted-dealer DKG (academic Corona). Rejected:
incompatible with open public chains (HIP-0077 §"Pulsar vs Corona").
**Status.** Final.
## DD-006 Proactive resharing: HJKY97-style with beacon-randomized quorum
**Decision.** Long-lived deployments use proactive secret resharing with
a beacon-derived per-reshare quorum selection (not deterministic
smallest-ID).
**Rationale.** Deterministic quorum selection (Pulsar's current
`reshare.go:206-209`) lets a mobile adversary game the corrupt-set
positioning. HIP-0077 red review F10 flagged this. Pulsar-M's reshare
selects via the chain's randomness beacon at the reshare epoch boundary.
**Alternative.** Deterministic quorum, accept the leakage as a documented
limitation. Rejected for MPTC submission.
**Status.** Final.
## DD-007 No application-level logging in secret-touching code paths
**Decision.** Secret-touching functions (Sign, Verify-of-shares, DKG
verification, reshare verification) emit zero log lines. Constant-time
analysis treats any log call as a failed gate.
**Rationale.** Pulsar's pre-fix `log.Println(Bsquare, sumSquares)` in
`sign.go` (HIP-0077 red F8) is exactly the failure mode this rule
prevents. A logged value derived from secret state is a side channel
even at debug level.
**Alternative.** Allow debug logging gated by build tag. Rejected:
build tags get accidentally enabled in production; the rule is
absolute.
**Status.** Final. CI gate: `go vet -vettool=...` plus a custom linter
that rejects `log.*`, `fmt.Print*`, `panic` in `pkg/sign/`, `pkg/dkg/`,
`pkg/reshare/`.
## DD-008 Encoding freeze before C reference
**Decision.** Reference Go locks every byte of the wire encoding before
the C reference begins. Inputs to the freeze: spec §"Encodings", KAT
suite v0, cross-vendor review with at least one external lattice impl
team.
**Rationale.** Two implementations diverging on encoding is a recurring
source of NIST PQC submission rejections. Freeze first, port second.
**Status.** Targeted for end of August 2026.
## DD-009 Patent claims: prepared in advance
**Decision.** Patent-claim disclosures collected in
`docs/patent-notes-draft.md` from day 1 of the repo. Every contribution
adds the contributor's patent-claim notice (or explicit "no claims").
**Rationale.** NIST MPTC §6 requires Notes on Patent Claims as a package
deliverable. Late collection blows up the submission timeline.
**Status.** In progress.
## DD-010 Two-track NIST plan: MPTC now, CMVP later
**Decision.** Track A targets MPTC submission 2026-Nov-16. Track B
prepares for eventual NIST PQC standardization + CMVP module
validation, which is a multi-year process not scheduled.
**Rationale.** MPTC is the active NIST process for threshold schemes
right now. CMVP requires an approved standard, which threshold schemes
don't yet have. We can prepare a clean module boundary for future CMVP
work without waiting for the standard.
**Status.** Track A active. Track B is a parallel readiness exercise,
not a near-term gate.
-190
View File
@@ -1,190 +0,0 @@
# The Pulsar threshold-signature family
> **Pulsar** is one name for a family of lattice-based threshold signature
> schemes. Variants share the same protocol skeleton (2-round threshold
> sign, Pedersen DKG with proper hiding, proactive resharing,
> identifiable abort) but differ in the underlying lattice problem and
> NIST-compatibility target.
This document is the canonical statement of the family architecture.
Every Pulsar variant references it. Every NIST submission cites it.
Every consumer that wires "the Pulsar family" into a downstream system
points here for the variant table.
## Variants
| variant | repo (target) | lattice basis | hash family (canonical) | FIPS 204 verifier interchange? | NIST MPTC class | status |
|-----------|-----------------------------------|---------------|--------------------------------|--------------------------------|-----------------|-------------------------------|
| **Pulsar** (was Pulsar.M / pulsar-m) | `github.com/luxfi/pulsar` | Module-LWE (`R_q^k`) | SHA-3 / cSHAKE256 (SP 800-185) | yes — output is a single FIPS 204 ML-DSA σ | Class N1 + N4 | this repo; reference complete, KAT-pinned |
| **Corona** (was Pulsar.R / luxfi/pulsar) | `github.com/luxfi/corona` | Ring-LWE (`R_q`) | SHA-3 / cSHAKE256 (SP 800-185) | no — special threshold-friendly primitive | Class S1 + S4 | production R-LWE fork, lifecycle DKG complete |
| **Corona** (academic upstream + Lux expansions) | `github.com/luxfi/corona` | Ring-LWE (`R_q`) | BLAKE3 (academic) / SHA-3 (Lux expansions) | no | academic | upstream + lifecycle DKG expansions in flight |
All variants share:
- **Protocol skeleton** — 2-round threshold sign, Pedersen DKG, proactive
resharing with beacon-randomized quorum, identifiable abort with signed
complaints.
- **Hash suite** — NIST SP 800-185 (cSHAKE256, KMAC256, TupleHash256) is
canonical for every NIST-track variant. BLAKE3 deltas appear only in
legacy / academic profiles (`Pulsar.R-BLAKE3`, upstream Corona) and
are explicitly out-of-scope for any MPTC submission.
- **Constant-time discipline** — every secret-touching path constant-time
via `crypto/subtle` or local equivalents. No stdlib `log` in any
primitive package; all logging goes through `github.com/luxfi/log` at
fields the threat model has explicitly classified as public.
- **Implementation language** — Go reference; C / Rust conformance after
encoding-freeze gate per variant.
What differs between variants:
- **Algebra** — Ring-LWE for Corona, Module-LWE for Pulsar. The
algebraic shape determines parameter sizes, signature sizes, and the
structure of the Pedersen commitment scheme.
- **Verification target** — Corona verifies under its own verifier
(a custom 2-round-aggregated check); Pulsar verifies under
unmodified FIPS 204 ML-DSA.Verify. The latter is the single highest-
value property of the family.
- **NIST submission posture** — see Class column above.
- **Production maturity** — Pulsar.R has a hardened reshare path,
KAT suite, deployed code. Pulsar.M has a complete spec
(`spec/pulsar-m.tex` plus `parameters.tex`, `system-model.tex`,
`security-games.tex`), a working Go reference (single-party and
threshold paths, both GF(257) and GF(q) Shamir layers), and a
KAT suite. The scaling target N* = 1,111,111 is empirically
validated. Production hardening (HSM integration, formal CT
guarantees, cross-implementation conformance vs. BoringSSL FIPS /
AWS-LC / OpenSSL 3) is round-2 work.
## Why one family
NIST MPTC IR 8214C accepts each variant as a separate submission package
in either Class N or Class S. Submitting two as a coordinated **family**:
1. **Reuses infrastructure once.** The DKG harness, KAT cross-validation,
transcript binding, constant-time analysis, lattice-estimator runs,
patent disclosure, and IP review build to a shared `pulsar-test/` and
`pulsar-spec-common/` set of artifacts both submissions reference.
2. **Cross-validates the protocol skeleton.** A reviewer attacking the
Pedersen DKG soundness in Pulsar.R is also attacking it in Pulsar.M.
Soundness arguments compose; reviewers don't have to redo work.
3. **Demonstrates orthogonality.** Both submissions running on the same
2-round structure with different lattice bases is itself a security
argument: the family's robustness comes from a small, audited
protocol skeleton with parameterized algebra, not from a one-off
primitive.
4. **Forwards-only.** Adding `Pulsar.W` (or whichever future variant)
becomes a parameter-set + algebra change against the same skeleton,
not a new project. The naming reservation is pre-paid.
## What goes where
| artifact | shared | Pulsar.R | Pulsar.M |
|-----------------------------------|--------------|-----------------------------------|-------------------------------------|
| 2-round protocol description | shared spec | parameterised for `R_q` | parameterised for `R_q^k` |
| Pedersen DKG (proper hiding) | shared spec | params for `R_q` | params for `R_q^k` |
| Proactive resharing (beacon-rand) | shared spec | params for `R_q` | params for `R_q^k` |
| Reference Go impl | shared testkit | full primitive in `pulsar/` | full primitive in `pulsar-m/` |
| KATs | shared format | `vectors/` per repo | `vectors/` per repo |
| Lattice estimator | shared script | parameter file per variant | parameter file per variant |
| Patent claims | shared review | repo-local `patent-notes.md` | repo-local `patent-notes.md` |
| MPTC technical specification PDF | NO | `pulsar/spec/pulsar-r.pdf` | `pulsar-m/spec/pulsar-m.pdf` |
| MPTC submission package | NO — separate Class S vs Class N | one per variant | one per variant |
Two separate MPTC packages, one shared technical foundation. The shared
material is brought in by reference from each submission's spec PDF,
matching how PQ-CRYSTALS submitted Dilithium and Kyber as related
algorithms in Round 3.
## Naming discipline
Three sibling threshold-signature libraries; each is its own NIST
MPTC submission package (no umbrella package).
- **Pulsar** — the FIPS 204-compatible Module-LWE threshold. Always
capitalised, no hyphen, no suffix. Identifier form: `pulsar`.
- **Corona** — the Ring-LWE production threshold (Lux's hardened fork
of Corona). Always capitalised. Identifier form: `corona`.
- **Corona** — the academic Ring-LWE upstream plus Lux's lifecycle
DKG expansions. Always capitalised. Identifier form: `corona`.
Naming rules:
- Do not write "Pulsar.M" or "Pulsar-M" in new prose; both are the
pre-rebrand legacy names of the M-LWE threshold (now just "Pulsar").
- Do not write "Pulsar.R" or "Pulsar-R"; the R-LWE threshold is now
"Corona" -- distinct name, distinct repo.
- HashSuiteID byte (per HIP-0077 §"Lux consensus PQ modes") identifies
the **hash family**, not the variant. Pulsar and Corona canonical
profiles both use `HashSuiteSHA3 = 2`. A future Pulsar with a
different hash family (e.g. SHAKE256 only) would claim a new
HashSuiteID without renaming the variant.
## Repo organisation
```
~/work/lux/
├── pulsar/ ← Pulsar.R (R-LWE, production fork of Corona)
│ ├── sign/
│ ├── primitives/
│ ├── dkg2/ ← Pedersen DKG over R_q
│ ├── reshare/ ← proactive resharing
│ ├── hash/ ← Pulsar-SHA3 + Pulsar-BLAKE3 (legacy)
│ └── ...
├── pulsar-m/ ← Pulsar.M (M-LWE, FIPS 204-compatible)
│ ├── ref/go/
│ ├── spec/ ← own MPTC technical spec PDF
│ ├── docs/ ← family-architecture.md = THIS file
│ └── ...
├── corona/ ← academic upstream (NOT Pulsar; cited as the
│ R-LWE 2-round skeleton's origin)
└── consensus/
└── protocol/quasar/ ← witness orchestrator that consumes Pulsar
variants via WitnessProducer interface
```
The `consensus/protocol/quasar/` orchestrator binds to Pulsar variants
through `QWitnessProducer` (interface in
`consensus/protocol/quasar/witness_producer.go`). Quasar doesn't know
which variant produces the witness — it gets a `[]byte` and a
HashSuiteID. Variants are interchangeable at the orchestration layer,
which is exactly the orthogonality the family architecture claims.
## NIST submission strategy
Per CTO Decision 4 (recorded in this branch's HIP-0077 process notes):
> Submit BOTH. Pulsar.M leads (Class N1+N4, FIPS 204 verifier-interchangeable,
> highest strategic value). Pulsar.R parallel (Class S1+S4, established
> production code, demonstrates the family's R-LWE branch). Withdrawing
> either wastes existing work; submitting both forces the team to factor
> shared infrastructure into reusable modules — the orthogonality
> requirement.
Single Git tag, simultaneous cut: `mptc-preview-2026` on `pulsar` and
`pulsar-m` at the same SHA discipline. Both submissions reference frozen
artifacts. Drift between the two repos after the tag is only allowed
via amendments NIST permits in the public-analysis window.
## Status
- [x] Pulsar.R production code (shipping in Lux primary network)
- [x] Pulsar.R hardening: F8 (no log of secret state), F9 (constant-time reshare), F12 (LIGHT_MNEMONIC guard)
- [ ] Pulsar.R MPTC spec doc finalised (`pulsar/spec/pulsar-r.pdf` to be added)
- [ ] Pulsar.R `mptc-preview-2026` tag
- [x] Pulsar.M repo bootstrap (`pulsar-m/`)
- [ ] Pulsar.M Module-LWE algorithm body in spec (in flight via scientist agent)
- [ ] Pulsar.M reference implementation
- [ ] Pulsar.M FIPS 204 cross-validation (output interchangeability proof)
- [ ] Pulsar.M `mptc-preview-2026` tag
- [ ] Family architecture cross-reference baked into HIP-0077
## See also
- HIP-0077 (`hanzo/hips/HIPs/hip-0077-mesh-identity-gossip-and-payments.md`)
— defines the PQMode enum that selects which Pulsar variant the
consensus layer asks for.
- HIP-0078 (in flight) — Q-Chain PQ-rollup. Replaces Z-Chain Groth16/BN254
with a PQ-secure SNARK. Pulsar.M's per-validator ML-DSA-65 sigs are the
rollup target.
- NIST IR 8214C — *First Call for Multi-Party Threshold Schemes* (January
2026, package deadline 2026-Nov-16).
-206
View File
@@ -1,206 +0,0 @@
# Known limitations
Maintained as a living document. Better that reviewers see the gaps before
they find them.
## Spec / protocol
### Output interchangeability with FIPS 204 — DEMONSTRATED IN v0.1
The headline claim — "Pulsar-M signatures verify under unmodified
FIPS 204 ML-DSA.Verify" — holds for the v0.1 reference. The
`pulsarm.Verify` entry point dispatches to
`cloudflare/circl/sign/mldsa{44,65,87}.Verify` verbatim; the
threshold-sign output is the same byte-for-byte signature an
unmodified FIPS 204 signer would have produced on the
reconstructed seed. KAT cross-validation lives at
`ref/go/pkg/pulsarm/kat_test.go: TestKAT_ThresholdSign_Replay`,
which verifies every committed threshold signature under
`pulsarm.Verify` and therefore under the underlying FIPS 204
verifier.
### v0.1 uses reconstruction-aggregator; v0.2 will use Lagrange-linearity
v0.1 instantiates the threshold protocol via a
**reconstruction-aggregator** model: a threshold quorum delivers
byte-wise Shamir shares of the FIPS 204 seed to an aggregator
(any honest quorum member), which Lagrange-reconstructs the
master byte-sum in GF(257), runs the deterministic cSHAKE256 mix
that DKG committed to, and calls FIPS 204 Sign once. The master
seed lives in the aggregator's memory for the duration of one
Sign call.
The pulsar-m.tex §4.2 **Lagrange-linearity sign** path — each
party computes `z_i = y_i + c · λ_i · s_i` locally and the
aggregator sums them, with the master secret never reconstructed
— is the v0.2 target. It is mathematically equivalent at the
output level (the produced signature is byte-equal) but
information-theoretically stronger because no party ever holds
the master secret.
The v0.1 model is acceptable for the round-1 MPTC submission
when paired with the reshare cadence specified in
`spec/system-model.tex` (no aggregator holds a secret across more
than one signature). v0.2 ships the stronger soundness property
that adaptive-corruption analysis requires.
### Pedersen commitments: RO model in v0.1, M-LWE in v0.2
v0.1 uses cSHAKE256 RO-binding commitments
`C_i = cSHAKE256(c_i || blind_i)`. v0.2 replaces them with the
R_q^k Pedersen commitment of `spec/pulsar-m.tex` §3.2:
`C_{i,k} = A · c_{i,k} + B · r_{i,k}`. Both bindings are sound;
the v0.2 M-LWE binding is the post-quantum-safe variant required
for the formal proof to reduce to an M-LWE / MSIS hardness
assumption (the v0.1 RO-binding reduces to cSHAKE256 collision
resistance, which itself reduces to SHA-3 security).
### Per-byte Shamir: dual-field design
v0.1 Shamir-shares the FIPS 204 seed byte-wise. The reference
implementation supports two fields:
- **GF(257)** for committees with n ≤ 256 (default for small
validator sets, 64-byte wire share).
- **GF(q) = GF(8 380 417)** for committees with 256 < n ≤ q-1
(mandatory for any large committee, 128-byte wire share).
Auto-selection logic in `ref/go/pkg/pulsarm/types.go::resolveField`
picks the narrowest field that fits. The canonical extreme committee
target is `TargetCommitteeSize = 1_111_111` (seven 1s); see
`spec/pulsar-m.tex` §"Large committees" for the formal scaling
theorem.
v0.2 will reshape this to polynomial Shamir over `R_q^k` matching
`spec/pulsar-m.tex` §3.3. The output is the same FIPS 204 signature
in all cases; the v0.2 reshape is required to make the
Lagrange-linearity sign path work without round-tripping through the
byte-sum representation.
### Adaptive corruption proof not yet written
Static-corruption security is the baseline target. Adaptive-corruption
security is a stretch goal for the round-1 submission and a hard
requirement for round 2.
### Mobile-adversary (proactive resharing) proof inherits Pulsar's gaps
Pulsar's `reshare/` package has documented soundness against mobile
adversaries with deterministic quorum selection (the F10 weakness in
HIP-0077). Pulsar-M's `reshare/` ports this with beacon-randomized
quorum selection, which strictly improves on Pulsar — but the formal
proof of the strengthened protocol is still in draft.
## Implementation
### Reference implementation is Go-only for round 1
The C reference comes after spec encoding freeze. Round-1 reviewers
have only the Go reference. NIST MPTC permits any language; a C
companion is strongly recommended for round 2.
### No optimized implementation
`ref/go/` is the boring, clear, slow reference. AVX-512 / NEON / SHA-3-NI
optimization is post-submission work. Performance numbers in the
experimental-evaluation report reflect the reference, not optimized
implementations.
### No first-order masking
Power analysis resistance via masking is post-submission hardening.
The reference is constant-time at the algorithmic level (no
secret-dependent branches, no secret-dependent memory access patterns
in inner loops) but has no power-side-channel countermeasures.
### No HSM integration
Production-deployment patches (HSM integration, FIPS 140-3 module
shim) are post-submission. The reference is software-only.
### Constant-time analysis is dudect-level
Go's compiler is not guaranteed constant-time at the IR level. We use
dudect (`ct/dudect/`) to check the leading-edge timing distribution for
secret-correlated values. This catches the obvious leaks but does not
provide the formal guarantee of e.g. Jasmin-verified C kernels. Formal
verification (Jasmin/Formosa/EasyCrypt) is post-submission.
## NIST process
### No prior NIST MPTC preview submission
We're starting from cold. The third-preview window deadline (2026-Jul-20)
is roughly two months out. Achieving a credible preview writeup in that
window is the immediate gate. If we miss the third preview, we lose the
ability to submit the round-1 package without a preview, which is a hard
requirement per IR 8214C §5.1.
### Patent claims not yet inventoried
Pulsar inherits Corona's IP posture. Pulsar-M needs a fresh
patent-claim review for the M-LWE adaptation. `docs/patent-notes-draft.md`
collects claims as they're discovered; final notice for the package is
on the critical path for 2026-Nov-16.
### External cryptanalysis engagement not yet contracted
NIST MPTC submissions are strengthened by independent academic
cryptanalysis. We have not yet engaged a third party. A 6-month
engagement starting July 2026 is the target — this aligns with the
post-package public-analysis window rather than blocking the package
itself.
## Repo / build
### Go module initialised
`go.mod` brings in `cloudflare/[email protected]` (FIPS 204 backbone)
and `golang.org/x/crypto/sha3` (FIPS 202 / SP 800-185 transcripts).
Cleanly builds with `GOWORK=off`.
### Spec PDF not yet built
`spec/pulsar-m.tex` is **complete** as LaTeX source (1500+ lines
covering Front matter / Notation / Preliminaries / Algorithms /
Verification / Reshare / Identifiable abort / Security analysis /
Concrete parameters / Large committees / Encodings / System model /
Implementation considerations / Performance / Test vectors /
Complexity analysis / Deployment / Comparison / Patent claims /
Known limitations / Open questions). The companion files
`security-games.tex`, `system-model.tex`, and `parameters.tex` are
also complete. Building the PDF via `latexmk -pdf spec/pulsar-m.tex`
is on the active writing track once the bib resolution lands.
### KAT suite generated
`vectors/{keygen,sign,verify,threshold-sign,dkg}.json` are committed.
`scripts/gen_vectors.sh` re-runs the generator and verifies that
re-running produces byte-identical output (the deterministic-fixture
gate). The CAVS-style `kat-v1.rsp` ACVP companion is on the v0.2
path; ACVP support requires the post-encoding-freeze byte layout.
### Lattice-estimator parameter table
`spec/parameters.tex` now includes the classical + quantum
security-level table (numbers inherited verbatim from FIPS 204 §8
because Pulsar-M does not alter the underlying M-LWE parameters).
The Albrecht et al. lattice-estimator script
`estimator/params.sage` reproduces the table; the estimator commit
hash is pinned at submission in `estimator/README.md`.
## Compared to Pulsar (R-LWE)
| dimension | Pulsar | Pulsar-M |
|---|---|---|
| Algebraic basis | Ring-LWE | Module-LWE |
| Hash | SHA-3 cSHAKE / BLAKE3 legacy | SHA-3 cSHAKE only |
| FIPS 204 output interchange | no (R-LWE) | yes (target) |
| MPTC class | S1/S4 | N1/N4 |
| Parameter sets | Pulsar-internal | ML-DSA-44/65/87 |
| DKG | Pedersen over `R_q` | Pedersen over `R_q^k` |
| Reshare | deterministic quorum | beacon-randomized quorum |
Where Pulsar provides feature X and Pulsar-M doesn't yet, Pulsar-M's
goal is to inherit X verbatim from Pulsar's `dkg2/` and `reshare/`
packages with the M-LWE shape change.
-140
View File
@@ -1,140 +0,0 @@
# NIST MPTC category targeting
> Reference: NIST IR 8214C, *First Call for Multi-Party Threshold Schemes*
> (January 2026). Package deadline expected 2026-Nov-16. Preview deadline
> 2026-Jul-20.
## Pulsar-M target: **Class N1 + N4**
NIST MPTC subdivides threshold schemes into:
- **Class S** (Special) — threshold-friendly primitives that *are not*
output-interchangeable with a NIST-specified primitive. Submission
evaluated for "novel threshold-friendly design."
- **Class N** (Normal-mode) — threshold implementations *of* a NIST-specified
primitive whose outputs are interchangeable with the corresponding
non-threshold primitive's outputs.
- **N1**: signing
- **N2**: encryption / decryption
- **N3**: KEM
- **N4**: ML keygen / DKG (Module-Lattice key generation, distributed)
Pulsar-M aims for **N1 (threshold ML-DSA signing) + N4 (distributed ML-DSA
keygen)**. The headline interchangeability claim:
> A signature `σ` produced by a Pulsar-M threshold ceremony on message `μ`
> against group public key `pk` verifies under unmodified
> [FIPS 204 ML-DSA.Verify(pk, μ, σ)] returning `accept`.
If we can prove and demonstrate this, Pulsar-M is a Class N candidate. If
the output is not bit-for-bit FIPS 204 (e.g. encoding differs in any
field), Pulsar-M falls back to Class S — still valid, but a weaker NIST
positioning.
## Output interchangeability — what has to hold
ML-DSA-65 signatures (FIPS 204 §5.4, Algorithm 26 `sigEncode`) are
encoded as a fixed-length 3309-byte string σ = (c̃, z, h) whose three
components decompose exactly as:
```
σ = (c̃ ‖ z ‖ h) 3309 bytes
c̃ ∈ {0,1}^{2λ} 48 bytes
// FIPS 204 commitment-hash length; 2λ bits with λ=192 = 384 bits.
// (2λ here is the FIPS 204 commitment-hash parameter, not the
// security level — the two happen to numerically agree for
// ML-DSA-65 because the standard ties one to the other at this
// parameter set.)
z ∈ R^ℓ_q 3200 bytes
// ℓ = 5 polynomials, each 256 coefficients, packed at
// log2(2γ_1) = 20 bits per coefficient.
// 5 · 256 · 20 / 8 = 3200 bytes.
h ∈ {0,1}^{ω + k} 61 bytes
// ω = 55 (hint bound), k = 6 (commitment-vector dimension).
// FIPS 204 Algorithm 22 `hintBitPack` + Algorithm 28
// `sigEncode` pack ω + k = 61 bits as 61 bytes (one byte per
// bit position, terminator-first encoding per the standard).
total: 48 + 3200 + 61 = 3309 bytes ✓ FIPS 204 Table 2
```
For Pulsar-M to claim Class N1, the threshold-aggregated signature MUST
deserialize as exactly this triple, with the same byte layout, the same
canonicalization rules, and the same rejection criteria. The threshold
protocol is allowed to perform multiple rounds internally, but its emitted
artifact MUST be a single FIPS 204 σ.
This is non-trivial: ML-DSA's rejection sampling means a single-shot
threshold output can fail rejection and require restart. Pulsar's
2-round structure handles this for R-LWE; Pulsar-M needs to reproduce
the rejection-restart logic for M-LWE without leaking secret information
across the restart.
## Required package deliverables
Per NIST IR 8214C §5:
| element | format | location |
|---|---|---|
| Technical Specification | PDF (LaTeX) | `spec/pulsar-m.pdf` |
| Reference Implementation | open-source code | `ref/go/` |
| Report on Experimental Evaluation | PDF + reproducible scripts | `bench/results/REPORT.md` + `bench/run_all.sh` |
| Notes on Patent Claims | PDF | `docs/patent-notes-draft.md` → finalized |
| Concrete parameter set | section in spec | `spec/parameters.tex` |
| Security analysis (proofs) | section in spec | `spec/security-games.tex` |
| Public repository | GitHub or equiv | `https://github.com/luxfi/pulsar-m` |
| Build/test/benchmark scripts | shell | `scripts/*.sh` |
| Open-source license | text | `LICENSE` (Apache-2.0) |
| I/O test vectors | JSON / RSP | `vectors/kat-v1.{json,rsp}` |
Optional but strongly recommended:
- Executive summary (1-2 pages) at front of spec.
- Threat-model document (`docs/threat-model.md`).
- System-model document (`docs/system-model.md` → `spec/system-model.tex`).
- Known-limitations appendix (so reviewers see the gaps before they find them).
## Required security strengths
NIST MPTC §4.5 gives the required and suggested security-strength targets:
| target | classical | post-quantum (NIST PQ category) | statistical |
|---|---|---|---|
| **required** (≥1 parameterization) | ≥ 128 bits | ≥ Category 1 | ≥ 40 bits |
| **suggested** (additional, optional) | ≥ 192 bits | ≥ Category 3 | ≥ 64 bits |
Pulsar-M will ship parameter sets matching ML-DSA-65 (Category 3) for the
suggested target, and potentially ML-DSA-44 (Category 2) and ML-DSA-87
(Category 5) for full coverage.
## Class N vs Class S decision
Pulsar-M is N if and only if:
1. A working reference implementation produces signatures byte-equal to
FIPS 204 ML-DSA on the same `(pk, μ)` for some valid threshold ceremony.
2. The threshold key generation produces a `pk` that's a valid FIPS 204
ML-DSA public key (no extra public material distinguishable from a
single-party `pk`).
3. The verification relation in the spec is the FIPS 204 verifier
verbatim, with no Pulsar-specific changes.
If any of (1)-(3) fails, we ship as Class S with a clear "future work:
output interchangeability" note. The class decision is finalized at the
point we freeze the spec encoding.
## Pulsar (R-LWE) for comparison
Pulsar (R-LWE) targets **Class S1 + S4**: special threshold-friendly
two-round signature, not output-interchangeable with any NIST-approved
primitive. The S1/S4 framing is the right framing for Corona-derivatives
unless and until NIST blesses Corona-shaped outputs as a primitive.
## Status
- [ ] Class declared (N vs S, awaiting spec freeze)
- [ ] Preview writeup drafted
- [ ] Preview submitted (target 2026-Jul-20)
- [ ] Spec freeze
- [ ] Reference impl complete
- [ ] KATs cross-validated against FIPS 204 reference
- [ ] Experimental-evaluation report
- [ ] Patent-claims notes finalized
- [ ] Package submitted (target 2026-Nov-16)
-91
View File
@@ -1,91 +0,0 @@
# Notes on patent claims (draft)
> Required by NIST MPTC IR 8214C §5 as a package deliverable. This document
> is collected over the development period and finalized for the
> submission.
## Status
**Draft.** No patent claims have been formally identified. This page
tracks claims as contributors disclose them.
## Inherited from upstream
### Pulsar (`luxfi/pulsar`)
Pulsar-M reuses Pulsar's protocol structure. Pulsar's IP posture per
its README:
- Apache-2.0 licensed.
- Patent grant per Apache 2.0 §3 from each contributor.
- No known active patent claims as of repository creation.
This applies to Pulsar-M to the extent that Pulsar-M code or protocol
elements are derivative of Pulsar.
### Corona (`luxfi/corona`)
Pulsar (and therefore Pulsar-M) is a fork of academic Corona.
Corona (ePrint 2024/1113) authors: Cecilia Boschini, Darya Kaviani,
Russell W. F. Lai, Giulio Malavolta, Akira Takahashi, Mehdi Tibouchi.
Corona's open-source repo is Apache-2.0 with no asserted patent
claims as of mid-2026. Pulsar-M's M-LWE adaptation does not import
Corona code directly but inherits the protocol structure.
### ML-DSA / FIPS 204
ML-DSA is a NIST-standardized algorithm. The Dilithium team's IP
disclosures during NIST PQC standardization are public on the NIST
PQC website. Pulsar-M targets output interchangeability with FIPS 204
but does not assert any rights over FIPS 204 itself.
## Contributor disclosures
Per CONTRIBUTING.md, every commit's `Signed-off-by` line is taken as
either:
1. An explicit assertion that the contributor has no relevant patent
claims, OR
2. A reference to a disclosed claim listed below.
| date | contributor | type | disclosure |
|---|---|---|---|
| 2026-05-10 | Lux Industries Inc | initial repo | no claims asserted |
(Updated as contributions land.)
## Third-party patents we may need to navigate
Live concerns to investigate before submission:
- Lattice-estimator usage (we use the open-source estimator; license
pass-through to MIT).
- Gaussian sampler implementation (FIPS 204 references CDT; alternate
rejection samplers may have IP).
- Polynomial multiplication via NTT (standard, no known IP).
- Pedersen commitments (1991 paper, expired patents).
The submission's Notes on Patent Claims will explicitly call out each
of these.
## NIST MPTC submission requirements
NIST IR 8214C §5 (Notes on Patent Claims) requires:
> Submitter(s) shall include a statement of any patent claims known to
> them that may be relevant to the submitted package, regardless of who
> owns the claim. Statements of "no known claims" are acceptable.
Our final statement, once the spec freezes:
> *To be drafted at spec freeze. Will incorporate every disclosure in
> the contributor table above, every inherited claim from Pulsar /
> Corona / ML-DSA, and the third-party investigation outcome.*
## Process
1. Every PR review checks for new IP-relevant code.
2. Significant cryptographic additions (new sampling routine, new
commitment shape, new aggregation step) trigger an explicit IP
review with one of the sponsor's IP counsel.
3. Final statement assembled at freeze, included in
`spec/pulsar-m.pdf` Appendix A.
-132
View File
@@ -1,132 +0,0 @@
# Pulsar-M threat model
## Adversary classes
We give an adversary the union of the following capabilities, parameterized
by `t` (the corruption threshold) and the corruption model:
### Static corruption (default)
- Adversary `A` selects up to `t-1` parties to corrupt **before** protocol
start. From start to end of the protocol, those `t-1` parties are
controlled; the remaining honest parties run the protocol faithfully.
- `A` sees all messages on the broadcast channel + all messages on the
authenticated point-to-point channels into corrupted parties.
- `A` learns each corrupted party's full state (secret share, randomness,
per-round values) including session-state values.
- `A` can selectively delay messages within the round window but cannot
forge messages from honest parties on authenticated channels.
### Adaptive corruption (stronger model)
- Adversary `A` can corrupt up to `t-1` parties at any time during the
protocol, including mid-round, conditioned on the transcript so far.
- Once corrupted, a party remains corrupted for the rest of the protocol.
- All other capabilities as in static.
The Pulsar-M security analysis (`spec/security-games.tex`) provides the
precise game definitions. Static security is the baseline; adaptive
security is a stretch goal for the first MPTC submission and a hard
requirement for the second-round response.
### Mobile corruption (proactive resharing)
For long-lived deployments where the validator set rotates between epochs
(Pulsar's `reshare/` direction), the relevant model is HJKY97 mobile
adversary: `A` can corrupt up to `t-1` parties **per epoch**, with the
corruption set varying across epochs. The adversary may *uncorrupt* a
party (forget what it learned) at epoch boundaries.
Pulsar-M proactive resharing inherits the soundness argument from Pulsar's
`reshare/` (with the constant-time fix from F9 of the Hanzo HIP-0077
red review). The MPTC submission documents the mobile-adversary game
explicitly.
## Out-of-scope adversary capabilities
- Compromise of the cryptographic hash function (SHAKE-256 / cSHAKE-256 /
KMAC-256). NIST FIPS 202 + SP 800-185 are taken as building blocks.
- Side-channel attacks on the *physical* hardware running a party
(power analysis, EM, fault injection). Mitigation discussed in
`docs/known-limitations.md` as future work.
- Compromise of the BIP-32/BIP-39 mnemonic from which device-specific
keys are derived. The HD-derivation security argument lives in
HIP-0077 §"Identity"; the Pulsar-M layer assumes parties' input keys
are uniformly distributed.
## In-scope security goals
### Threshold unforgeability (TS-UF)
For any PPT adversary `A` controlling up to `t-1` parties, `A` cannot
produce a valid Pulsar-M signature `σ*` on any message `μ*` that an
honest signing ceremony has not produced.
### Robustness / identifiable abort
If a corrupted party deviates from the protocol, the honest parties:
1. Detect the deviation.
2. Identify the deviating party.
3. Produce signed evidence of the deviation suitable for slashing /
reputation reduction.
### Output indistinguishability from FIPS 204
A Pulsar-M signature `σ` on message `μ` against group public key `pk`
is computationally indistinguishable from a FIPS 204 ML-DSA signature on
the same `(pk, μ)`. Specifically: an adversary that can distinguish the
two with non-negligible advantage breaks the underlying M-LWE assumption.
### Bias resistance
The randomness used in each party's contribution (Gaussian samples,
challenge polynomials) is statistically indistinguishable from uniform
even given the adversary's view of corrupted parties' randomness.
### DKG soundness
Pedersen DKG over `R_q^k` produces a public key `pk` distributed
uniformly over the valid M-LWE public-key space, with no party holding
more than `1/n` partial information about the corresponding secret key.
## Assumed channels
| channel | property | purpose |
|---|---|---|
| Broadcast | authenticated, eventual-delivery | round transcripts, public coins |
| Point-to-point | authenticated, encrypted | private share / blind delivery |
| Public bulletin | authenticated, append-only | DKG commitments, reshare records |
The reference implementation provides these channels via TCP + TLS.
Production deployments (e.g. Lux consensus + Quasar) bind these to
their existing P2P transport.
## Trusted parameters
- The cyclotomic ring `R_q = Z_q[X] / (X^256 + 1)` and parameters
`(q, k, ℓ, η, β, ω, …)` exactly as in FIPS 204 ML-DSA-65.
- The hash family: SHAKE-256 (FIPS 202), cSHAKE-256 / KMAC-256 /
TupleHash-256 (NIST SP 800-185). Customization tags are pinned in
`spec/pulsar-m.tex`.
- The Gaussian sampler parameters from FIPS 204 §3.3 / §4.2.
No trusted setup beyond NIST primitives.
## Failure modes addressed
The MPTC submission documents how Pulsar-M handles each failure mode that
broke earlier threshold-lattice schemes:
- **Rejection-sampling restart leaking secret information across rounds**:
Pulsar's PRNG-key per-round domain separation (CRIT-1 fix from
upstream's 2026-05-03 amendment) ports forward.
- **Constant-time share comparison**: `dkg2.constTimePolyEqual` pattern
ported from upstream Pulsar (`reshare/commit.go` F9 fix).
- **Information leaks via logging**: zero stdlib `log` use in any
secret-touching path; all logging via `luxfi/log` at fields that are
explicitly public.
- **Deterministic quorum selection in resharing leaking adversary
positioning**: Pulsar-M uses a beacon-derived per-reshare quorum
selection (HIP-0077 §"reshare quorum" F10 fix).
- **Cross-mode hash-suite confusion**: NIST profile is exclusively
SHA-3 family; no BLAKE3 in Pulsar-M ever.
+1 -1
View File
@@ -27,7 +27,7 @@ package pulsarm
// guarantees under M-LWE hardness (a stronger PQ-safe binding
// argument). Both targets are Class N4-eligible.
//
// See docs/known-limitations.md for the v0.1 → v0.2 path.
// See spec/known-limitations.tex for the v0.1 → v0.2 path.
import (
"crypto/rand"
+1 -1
View File
@@ -5,7 +5,7 @@
// The headline claim of Pulsar-M is output interchangeability with FIPS 204:
// a signature produced by an n-of-t threshold ceremony verifies under
// unmodified FIPS 204 ML-DSA.Verify(pk, message, signature). See
// docs/nist-mptc-category.md for the formal claim and its scope.
// spec/nist-mptc-category.tex for the formal claim and its scope.
//
// Status: pre-spec-freeze. The exported API in this package will change
// up to the spec encoding freeze (target end of August 2026). After
+2 -2
View File
@@ -179,7 +179,7 @@ func TestLarge_DKG_AboveCap(t *testing.T) {
// small-committee (GF(257)) path. Cross-committee reshare changes
// the committee root and therefore the cSHAKE256-mixed master seed
// in the v0.1 reconstruction-aggregator instantiation; see
// docs/known-limitations.md.
// spec/known-limitations.tex.
func TestLarge_Reshare_SameCommittee_PubInvariant(t *testing.T) {
params := MustParamsFor(ModeP65)
committee := makeLargeCommittee(5)
@@ -301,7 +301,7 @@ func TestLarge_Reshare_SameCommittee_PubInvariant(t *testing.T) {
// is bound to the committee root. This test asserts that the reshare
// ceremony succeeds (new shares are produced) but not that pk is
// preserved across the committee change. The pk-preserving cross-
// committee reshare is on the v0.2 path; see docs/known-limitations.md.
// committee reshare is on the v0.2 path; see spec/known-limitations.tex.
func TestLarge_Reshare_E2E(t *testing.T) {
params := MustParamsFor(ModeP65)
+1 -1
View File
@@ -28,7 +28,7 @@ package pulsarm
// pulsar-m.tex §4.2 form. The reconstruction-aggregator path collapses
// the Lagrange-linearity-of-z computation of §4.2 into a single FIPS
// 204 Sign call after share Lagrange reconstruction. This trade is
// documented in docs/known-limitations.md; the v0.2 path implements
// documented in spec/known-limitations.tex; the v0.2 path implements
// the pure Lagrange-linearity sign where the secret is never
// reconstructed in any party's memory.
+1 -1
View File
@@ -170,7 +170,7 @@ type Round2Message struct {
// PartialSig is this party's contribution toward the FIPS 204
// signature. In the v0.1 reconstruction-aggregator instantiation
// (see docs/known-limitations.md), this is the Shamir share of
// (see spec/known-limitations.tex), this is the Shamir share of
// the seed encrypted under the round transcript hash; the
// aggregator collects t shares, reconstructs the seed, and emits
// a single FIPS 204 signature. The Lagrange-linearity path of
+1 -1
View File
@@ -12,7 +12,7 @@ package pulsarm
// signature produced by ThresholdSign (threshold.go) flows through
// the SAME Verify code path as a single-party Sign output.
//
// Per pulsar-m.tex §4.3 and docs/nist-mptc-category.md, this is the
// Per pulsar-m.tex §4.3 and spec/nist-mptc-category.tex, this is the
// load-bearing property of the entire Pulsar-M family: anything that
// changes Verify breaks Class N1 output interchangeability.
+204
View File
@@ -0,0 +1,204 @@
% Pulsar-M design decisions log -- included by pulsar-m.tex.
% Mirrors docs/design-decisions.md (now deleted; this file is the
% canonical LaTeX form). Each entry: decision, rationale,
% alternatives, status, date.
\subsection{DD-001 Target FIPS 204 output interchangeability (Class
N)}
\paragraph{Decision.}
Pulsar-M aims for Class N1 + N4 (NIST MPTC IR 8214C):
threshold-produced signatures verify under unmodified FIPS~204
ML-DSA.Verify.
\paragraph{Rationale.}
Output interchangeability gives the strongest NIST positioning.
FIPS-validated ML-DSA modules in 2026 (BoringSSL FIPS, AWS-LC,
OpenSSL 3.0) consume Pulsar-M certs without code changes. This is
the headline pitch for MPTC.
\paragraph{Alternative.}
Class S (special threshold-friendly primitive). Easier spec, but
does not give the FIPS-module-compatibility win. Pulsar (R-LWE)
takes this path.
\paragraph{Status.}
Targeted. Final class decision deferred until reference impl
demonstrates byte-equal output on at least one parameter set.
\subsection{DD-002 Hash family: SHA-3 (cSHAKE256 / KMAC256 /
TupleHash256) only}
\paragraph{Decision.}
Pulsar-M's NIST profile uses exclusively the FIPS~202 + SP 800-185
hash family. No BLAKE3.
\paragraph{Rationale.}
NIST MPTC \S4.6 lists allowed symmetric primitives for Class N: AES,
Ascon, SHA-2, SHA-3, SHAKE/cSHAKE, HMAC/KMAC/CMAC/GMAC. BLAKE3 is
not on the list. Including BLAKE3 in the NIST submission profile is
a strategic liability.
The same SHAKE-256 sponge is used internally by ML-DSA-65 (FIPS~204
\S5.1). Sharing the hash family with the underlying primitive
removes a whole class of cryptanalytic concern (cross-domain
collisions, mixed hash-family soundness arguments).
\paragraph{Alternative considered.}
Dual-suite with BLAKE3 as the production profile and SHA-3 as the
NIST profile, like Pulsar's current dual-suite. Rejected because
Pulsar-M is NIST-track and shouldn't ship a non-NIST default.
\paragraph{Status.}
Final.
\subsection{DD-003 Lattice: Module-LWE per FIPS 204, not Ring-LWE}
\paragraph{Decision.}
Pulsar-M operates over $\Rq^k$ (module of polynomials) with the same
$(q, k, \ell, \eta, \beta, \omega, \ldots)$ parameter set as
ML-DSA-65. Not $\Rq$ (single polynomial) as Pulsar / Corona use.
\paragraph{Rationale.}
This is the whole point of the project. Class N1 interchangeability
requires the protocol's signing operation to land on exactly the
FIPS~204 $\sigma$ encoding, which is M-LWE-shaped.
\paragraph{Alternative.}
Stay R-LWE. Easier (we already have Pulsar). But then we lose the
Class N positioning and become Class S like Pulsar.
\paragraph{Status.}
Final.
\subsection{DD-004 Reference implementation language: Go}
\paragraph{Decision.}
Reference implementation is Go (\texttt{ref/go/}). C implementation
comes after spec encodings freeze (\texttt{ref/c/}).
\paragraph{Rationale.}
Go matches Pulsar's reference; reuses our Pedersen DKG and reshare
patterns from \texttt{pulsar/dkg2/} and \texttt{pulsar/reshare/}.
Clear, boring, no assembly. NIST MPTC \S4.3 doesn't mandate
language.
\paragraph{Alternative.}
C reference first. Standard NIST PQC submission style. Rejected for
round 1 because we need to ship by 2026-Nov-16; Go is faster to
write and review. C reference becomes a follow-on artifact for round
2 review.
\paragraph{Status.}
Final for MPTC round 1.
\subsection{DD-005 DKG: Pedersen-style over $\Rq^k$}
\paragraph{Decision.}
Distributed keygen uses Pedersen DKG over the M-LWE module ring,
with Feldman-style verifiable secret sharing replaced by the
module-shaped Pedersen commitment scheme.
\paragraph{Rationale.}
Pulsar's \texttt{dkg2/} package already does this for $\Rq$ (R-LWE).
The M-LWE port preserves the soundness argument with constant
overhead per coefficient slot.
\paragraph{Alternative.}
Trusted-dealer DKG (academic Corona). Rejected: incompatible with
open public chains (HIP-0077 \S``Pulsar vs Corona'').
\paragraph{Status.}
Final.
\subsection{DD-006 Proactive resharing: HJKY97-style with
beacon-randomized quorum}
\paragraph{Decision.}
Long-lived deployments use proactive secret resharing with a
beacon-derived per-reshare quorum selection (not deterministic
smallest-ID).
\paragraph{Rationale.}
Deterministic quorum selection (Pulsar's current
\texttt{reshare.go:206-209}) lets a mobile adversary game the
corrupt-set positioning. HIP-0077 red review F10 flagged this.
Pulsar-M's reshare selects via the chain's randomness beacon at the
reshare epoch boundary.
\paragraph{Alternative.}
Deterministic quorum, accept the leakage as a documented limitation.
Rejected for MPTC submission.
\paragraph{Status.}
Final.
\subsection{DD-007 No application-level logging in secret-touching
code paths}
\paragraph{Decision.}
Secret-touching functions (Sign, Verify-of-shares, DKG verification,
reshare verification) emit zero log lines. Constant-time analysis
treats any log call as a failed gate.
\paragraph{Rationale.}
Pulsar's pre-fix \texttt{log.Println(Bsquare, sumSquares)} in
\texttt{sign.go} (HIP-0077 red F8) is exactly the failure mode this
rule prevents. A logged value derived from secret state is a side
channel even at debug level.
\paragraph{Alternative.}
Allow debug logging gated by build tag. Rejected: build tags get
accidentally enabled in production; the rule is absolute.
\paragraph{Status.}
Final. CI gate: \texttt{go vet -vettool=...} plus a custom linter
that rejects \texttt{log.*}, \texttt{fmt.Print*}, \texttt{panic} in
\texttt{pkg/sign/}, \texttt{pkg/dkg/}, \texttt{pkg/reshare/}.
\subsection{DD-008 Encoding freeze before C reference}
\paragraph{Decision.}
Reference Go locks every byte of the wire encoding before the C
reference begins. Inputs to the freeze: spec \S``Encodings'', KAT
suite v0, cross-vendor review with at least one external lattice
impl team.
\paragraph{Rationale.}
Two implementations diverging on encoding is a recurring source of
NIST PQC submission rejections. Freeze first, port second.
\paragraph{Status.}
Targeted for end of August 2026.
\subsection{DD-009 Patent claims: prepared in advance}
\paragraph{Decision.}
Patent-claim disclosures collected in
\texttt{spec/patent-notes.tex} from day 1 of the repo. Every
contribution adds the contributor's patent-claim notice (or explicit
``no claims'').
\paragraph{Rationale.}
NIST MPTC \S6 requires Notes on Patent Claims as a package
deliverable. Late collection blows up the submission timeline.
\paragraph{Status.}
In progress.
\subsection{DD-010 Two-track NIST plan: MPTC now, CMVP later}
\paragraph{Decision.}
Track A targets MPTC submission 2026-Nov-16. Track B prepares for
eventual NIST PQC standardization + CMVP module validation, which is
a multi-year process not scheduled.
\paragraph{Rationale.}
MPTC is the active NIST process for threshold schemes right now.
CMVP requires an approved standard, which threshold schemes don't
yet have. We can prepare a clean module boundary for future CMVP
work without waiting for the standard.
\paragraph{Status.}
Track A active. Track B is a parallel readiness exercise, not a
near-term gate.
+278
View File
@@ -0,0 +1,278 @@
% Pulsar threshold-signature family architecture -- included by
% pulsar-m.tex. Mirrors docs/family-architecture.md (now deleted;
% this file is the canonical LaTeX form).
\begin{quote}
\textbf{Pulsar} is one name for a family of lattice-based threshold
signature schemes. Variants share the same protocol skeleton
(2-round threshold sign, Pedersen DKG with proper hiding, proactive
resharing, identifiable abort) but differ in the underlying lattice
problem and NIST-compatibility target.
\end{quote}
This document is the canonical statement of the family architecture.
Every Pulsar variant references it. Every NIST submission cites it.
Every consumer that wires ``the Pulsar family'' into a downstream
system points here for the variant table.
\subsection{Variants}
\begin{center}
\small
\begin{tabular}{p{2.3cm}p{3.0cm}p{1.8cm}p{2.6cm}p{2.2cm}p{1.6cm}p{2.4cm}}
\toprule
variant & repo (target) & lattice basis & hash family (canonical) &
FIPS 204 verifier interchange? & NIST MPTC class & status \\
\midrule
\textbf{Pulsar} (was Pulsar.M / pulsar-m) &
\texttt{github.com/luxfi/pulsar} &
Module-LWE ($\Rq^k$) &
SHA-3 / cSHAKE256 (SP 800-185) &
yes --- output is a single FIPS~204 ML-DSA $\sigma$ &
Class N1 + N4 &
this repo; reference complete, KAT-pinned \\
\textbf{Corona} (was Pulsar.R / luxfi/pulsar) &
\texttt{github.com/luxfi/corona} &
Ring-LWE ($\Rq$) &
SHA-3 / cSHAKE256 (SP 800-185) &
no --- special threshold-friendly primitive &
Class S1 + S4 &
production R-LWE fork, lifecycle DKG complete \\
\textbf{Corona} (academic upstream + Lux expansions) &
\texttt{github.com/luxfi/corona} &
Ring-LWE ($\Rq$) &
BLAKE3 (academic) / SHA-3 (Lux expansions) &
no &
academic &
upstream + lifecycle DKG expansions in flight \\
\bottomrule
\end{tabular}
\end{center}
All variants share:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item \textbf{Protocol skeleton} --- 2-round threshold sign, Pedersen
DKG, proactive resharing with beacon-randomized quorum, identifiable
abort with signed complaints.
\item \textbf{Hash suite} --- NIST SP 800-185 (cSHAKE256, KMAC256,
TupleHash256) is canonical for every NIST-track variant. BLAKE3
deltas appear only in legacy / academic profiles
(\texttt{Pulsar.R-BLAKE3}, upstream Corona) and are explicitly
out-of-scope for any MPTC submission.
\item \textbf{Constant-time discipline} --- every secret-touching
path constant-time via \texttt{crypto/subtle} or local equivalents.
No stdlib \texttt{log} in any primitive package; all logging goes
through \texttt{github.com/luxfi/log} at fields the threat model has
explicitly classified as public.
\item \textbf{Implementation language} --- Go reference; C / Rust
conformance after encoding-freeze gate per variant.
\end{itemize}
What differs between variants:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item \textbf{Algebra} --- Ring-LWE for Corona, Module-LWE for
Pulsar. The algebraic shape determines parameter sizes, signature
sizes, and the structure of the Pedersen commitment scheme.
\item \textbf{Verification target} --- Corona verifies under its own
verifier (a custom 2-round-aggregated check); Pulsar verifies under
unmodified FIPS~204 ML-DSA.Verify. The latter is the single
highest-value property of the family.
\item \textbf{NIST submission posture} --- see Class column above.
\item \textbf{Production maturity} --- Pulsar.R has a hardened
reshare path, KAT suite, deployed code. Pulsar.M has a complete spec
(\texttt{spec/pulsar-m.tex} plus \texttt{parameters.tex},
\texttt{system-model.tex}, \texttt{security-games.tex}), a working
Go reference (single-party and threshold paths, both
$\mathrm{GF}(257)$ and $\mathrm{GF}(q)$ Shamir layers), and a KAT
suite. The scaling target $N^* = 1{,}111{,}111$ is empirically
validated. Production hardening (HSM integration, formal CT
guarantees, cross-implementation conformance vs.\ BoringSSL FIPS /
AWS-LC / OpenSSL 3) is round-2 work.
\end{itemize}
\subsection{Why one family}
NIST MPTC IR 8214C accepts each variant as a separate submission
package in either Class N or Class S. Submitting two as a
coordinated \textbf{family}:
\begin{enumerate}[leftmargin=*, itemsep=0pt]
\item \textbf{Reuses infrastructure once.} The DKG harness, KAT
cross-validation, transcript binding, constant-time analysis,
lattice-estimator runs, patent disclosure, and IP review build to a
shared \texttt{pulsar-test/} and \texttt{pulsar-spec-common/} set of
artifacts both submissions reference.
\item \textbf{Cross-validates the protocol skeleton.} A reviewer
attacking the Pedersen DKG soundness in Pulsar.R is also attacking
it in Pulsar.M. Soundness arguments compose; reviewers don't have to
redo work.
\item \textbf{Demonstrates orthogonality.} Both submissions running
on the same 2-round structure with different lattice bases is itself
a security argument: the family's robustness comes from a small,
audited protocol skeleton with parameterized algebra, not from a
one-off primitive.
\item \textbf{Forwards-only.} Adding \texttt{Pulsar.W} (or whichever
future variant) becomes a parameter-set + algebra change against the
same skeleton, not a new project. The naming reservation is
pre-paid.
\end{enumerate}
\subsection{What goes where}
\begin{center}
\small
\begin{tabular}{p{4.0cm}p{2.5cm}p{3.5cm}p{3.5cm}}
\toprule
artifact & shared & Pulsar.R & Pulsar.M \\
\midrule
2-round protocol description & shared spec &
parameterised for $\Rq$ & parameterised for $\Rq^k$ \\
Pedersen DKG (proper hiding) & shared spec &
params for $\Rq$ & params for $\Rq^k$ \\
Proactive resharing (beacon-rand) & shared spec &
params for $\Rq$ & params for $\Rq^k$ \\
Reference Go impl & shared testkit &
full primitive in \texttt{pulsar/} &
full primitive in \texttt{pulsar-m/} \\
KATs & shared format &
\texttt{vectors/} per repo &
\texttt{vectors/} per repo \\
Lattice estimator & shared script &
parameter file per variant &
parameter file per variant \\
Patent claims & shared review &
repo-local \texttt{patent-notes.tex} &
repo-local \texttt{patent-notes.tex} \\
MPTC technical specification PDF & NO &
\texttt{pulsar/spec/pulsar-r.pdf} &
\texttt{pulsar-m/spec/pulsar-m.pdf} \\
MPTC submission package & NO --- separate Class S vs Class N &
one per variant & one per variant \\
\bottomrule
\end{tabular}
\end{center}
Two separate MPTC packages, one shared technical foundation. The
shared material is brought in by reference from each submission's
spec PDF, matching how PQ-CRYSTALS submitted Dilithium and Kyber as
related algorithms in Round 3.
\subsection{Naming discipline}
Three sibling threshold-signature libraries; each is its own NIST
MPTC submission package (no umbrella package).
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item \textbf{Pulsar} --- the FIPS 204-compatible Module-LWE
threshold. Always capitalised, no hyphen, no suffix. Identifier
form: \texttt{pulsar}.
\item \textbf{Corona} --- the Ring-LWE production threshold (Lux's
hardened fork of Corona). Always capitalised. Identifier form:
\texttt{corona}.
\item \textbf{Corona} --- the academic Ring-LWE upstream plus Lux's
lifecycle DKG expansions. Always capitalised. Identifier form:
\texttt{corona}.
\end{itemize}
Naming rules:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item Do not write ``Pulsar.M'' or ``Pulsar-M'' in new prose; both
are the pre-rebrand legacy names of the M-LWE threshold (now just
``Pulsar'').
\item Do not write ``Pulsar.R'' or ``Pulsar-R''; the R-LWE threshold
is now ``Corona'' --- distinct name, distinct repo.
\item HashSuiteID byte (per HIP-0077 \S``Lux consensus PQ modes'')
identifies the \textbf{hash family}, not the variant. Pulsar and
Corona canonical profiles both use \texttt{HashSuiteSHA3 = 2}. A
future Pulsar with a different hash family (e.g.\ SHAKE256 only)
would claim a new HashSuiteID without renaming the variant.
\end{itemize}
\subsection{Repo organisation}
\begin{verbatim}
~/work/lux/
|-- pulsar/ <- Pulsar.R (R-LWE, production fork of Corona)
| |-- sign/
| |-- primitives/
| |-- dkg2/ <- Pedersen DKG over R_q
| |-- reshare/ <- proactive resharing
| |-- hash/ <- Pulsar-SHA3 + Pulsar-BLAKE3 (legacy)
| `-- ...
|-- pulsar-m/ <- Pulsar.M (M-LWE, FIPS 204-compatible)
| |-- ref/go/
| |-- spec/ <- own MPTC technical spec PDF
| |-- docs/ <- family-architecture moved to spec/
| `-- ...
|-- corona/ <- academic upstream (NOT Pulsar; cited as the
| R-LWE 2-round skeleton's origin)
`-- consensus/
`-- protocol/quasar/ <- witness orchestrator that consumes Pulsar
variants via WitnessProducer interface
\end{verbatim}
The \texttt{consensus/protocol/quasar/} orchestrator binds to Pulsar
variants through \texttt{QWitnessProducer} (interface in
\texttt{consensus/protocol/quasar/witness\_producer.go}). Quasar
doesn't know which variant produces the witness --- it gets a
\texttt{[]byte} and a HashSuiteID. Variants are interchangeable at
the orchestration layer, which is exactly the orthogonality the
family architecture claims.
\subsection{NIST submission strategy}
Per CTO Decision 4 (recorded in this branch's HIP-0077 process
notes):
\begin{quote}
Submit BOTH. Pulsar.M leads (Class N1+N4, FIPS~204
verifier-interchangeable, highest strategic value). Pulsar.R parallel
(Class S1+S4, established production code, demonstrates the family's
R-LWE branch). Withdrawing either wastes existing work; submitting
both forces the team to factor shared infrastructure into reusable
modules --- the orthogonality requirement.
\end{quote}
Single Git tag, simultaneous cut: \texttt{mptc-preview-2026} on
\texttt{pulsar} and \texttt{pulsar-m} at the same SHA discipline.
Both submissions reference frozen artifacts. Drift between the two
repos after the tag is only allowed via amendments NIST permits in
the public-analysis window.
\subsection{Status}
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item[$\boxtimes$] Pulsar.R production code (shipping in Lux primary
network)
\item[$\boxtimes$] Pulsar.R hardening: F8 (no log of secret state),
F9 (constant-time reshare), F12 (LIGHT\_MNEMONIC guard)
\item[$\square$] Pulsar.R MPTC spec doc finalised
(\texttt{pulsar/spec/pulsar-r.pdf} to be added)
\item[$\square$] Pulsar.R \texttt{mptc-preview-2026} tag
\item[$\boxtimes$] Pulsar.M repo bootstrap (\texttt{pulsar-m/})
\item[$\square$] Pulsar.M Module-LWE algorithm body in spec (in
flight via scientist agent)
\item[$\square$] Pulsar.M reference implementation
\item[$\square$] Pulsar.M FIPS~204 cross-validation (output
interchangeability proof)
\item[$\square$] Pulsar.M \texttt{mptc-preview-2026} tag
\item[$\square$] Family architecture cross-reference baked into
HIP-0077
\end{itemize}
\subsection{See also}
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item HIP-0077
(\texttt{hanzo/hips/HIPs/hip-0077-mesh-identity-gossip-and-payments.md})
--- defines the PQMode enum that selects which Pulsar variant the
consensus layer asks for.
\item HIP-0078 (in flight) --- Q-Chain PQ-rollup. Replaces Z-Chain
Groth16/BN254 with a PQ-secure SNARK. Pulsar.M's per-validator
ML-DSA-65 sigs are the rollup target.
\item NIST IR 8214C --- \emph{First Call for Multi-Party Threshold
Schemes} (January 2026, package deadline 2026-Nov-16).
\end{itemize}
+211
View File
@@ -0,0 +1,211 @@
% Pulsar-M known limitations -- included by pulsar-m.tex.
% Mirrors docs/known-limitations.md (now deleted; this file is the
% canonical LaTeX form, maintained as a living document).
Maintained as a living document. Better that reviewers see the gaps
before they find them.
\subsection{Spec / protocol}
\paragraph{Output interchangeability with FIPS 204 --- DEMONSTRATED
IN v0.1.}
The headline claim --- ``Pulsar-M signatures verify under unmodified
FIPS~204 ML-DSA.Verify'' --- holds for the v0.1 reference. The
\texttt{pulsarm.Verify} entry point dispatches to
\texttt{cloudflare/circl/sign/mldsa\{44,65,87\}.Verify} verbatim; the
threshold-sign output is the same byte-for-byte signature an
unmodified FIPS~204 signer would have produced on the reconstructed
seed. KAT cross-validation lives at
\texttt{ref/go/pkg/pulsarm/kat\_test.go:
TestKAT\_ThresholdSign\_Replay}, which verifies every committed
threshold signature under \texttt{pulsarm.Verify} and therefore
under the underlying FIPS~204 verifier.
\paragraph{v0.1 uses reconstruction-aggregator; v0.2 will use
Lagrange-linearity.}
v0.1 instantiates the threshold protocol via a
\textbf{reconstruction-aggregator} model: a threshold quorum
delivers byte-wise Shamir shares of the FIPS~204 seed to an
aggregator (any honest quorum member), which Lagrange-reconstructs
the master byte-sum in $\mathrm{GF}(257)$, runs the deterministic
cSHAKE256 mix that DKG committed to, and calls FIPS~204 Sign once.
The master seed lives in the aggregator's memory for the duration of
one Sign call.
The \texttt{pulsar-m.tex} \S4.2 \textbf{Lagrange-linearity sign}
path --- each party computes $\mathbf{z}_i = \mathbf{y}_i + c \cdot
\lambda_i \cdot \mathbf{s}_i$ locally and the aggregator sums them,
with the master secret never reconstructed --- is the v0.2 target.
It is mathematically equivalent at the output level (the produced
signature is byte-equal) but information-theoretically stronger
because no party ever holds the master secret.
The v0.1 model is acceptable for the round-1 MPTC submission when
paired with the reshare cadence specified in
\texttt{spec/system-model.tex} (no aggregator holds a secret across
more than one signature). v0.2 ships the stronger soundness property
that adaptive-corruption analysis requires.
\paragraph{Pedersen commitments: RO model in v0.1, M-LWE in v0.2.}
v0.1 uses cSHAKE256 RO-binding commitments
$C_i = \cSHAKE256(c_i \,\Vert\, \mathit{blind}_i)$. v0.2 replaces
them with the $\Rq^k$ Pedersen commitment of
\texttt{spec/pulsar-m.tex} \S3.2:
$C_{i,k} = \mathbf{A} \cdot c_{i,k} + \mathbf{B} \cdot r_{i,k}$. Both
bindings are sound; the v0.2 M-LWE binding is the post-quantum-safe
variant required for the formal proof to reduce to an M-LWE / MSIS
hardness assumption (the v0.1 RO-binding reduces to cSHAKE256
collision resistance, which itself reduces to SHA-3 security).
\paragraph{Per-byte Shamir: dual-field design.}
v0.1 Shamir-shares the FIPS~204 seed byte-wise. The reference
implementation supports two fields:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item $\mathrm{GF}(257)$ for committees with $n \le 256$ (default
for small validator sets, 64-byte wire share).
\item $\mathrm{GF}(q) = \mathrm{GF}(8\,380\,417)$ for committees with
$256 < n \le q - 1$ (mandatory for any large committee, 128-byte
wire share).
\end{itemize}
Auto-selection logic in
\texttt{ref/go/pkg/pulsarm/types.go::resolveField} picks the
narrowest field that fits. The canonical extreme committee target is
\texttt{TargetCommitteeSize = 1\_111\_111} (seven 1s); see
\texttt{spec/pulsar-m.tex} \S``Large committees'' for the formal
scaling theorem.
v0.2 will reshape this to polynomial Shamir over $\Rq^k$ matching
\texttt{spec/pulsar-m.tex} \S3.3. The output is the same FIPS~204
signature in all cases; the v0.2 reshape is required to make the
Lagrange-linearity sign path work without round-tripping through the
byte-sum representation.
\paragraph{Adaptive corruption proof not yet written.}
Static-corruption security is the baseline target.
Adaptive-corruption security is a stretch goal for the round-1
submission and a hard requirement for round 2.
\paragraph{Mobile-adversary (proactive resharing) proof inherits
Pulsar's gaps.}
Pulsar's \texttt{reshare/} package has documented soundness against
mobile adversaries with deterministic quorum selection (the F10
weakness in HIP-0077). Pulsar-M's \texttt{reshare/} ports this with
beacon-randomized quorum selection, which strictly improves on
Pulsar --- but the formal proof of the strengthened protocol is
still in draft.
\subsection{Implementation}
\paragraph{Reference implementation is Go-only for round 1.}
The C reference comes after spec encoding freeze. Round-1 reviewers
have only the Go reference. NIST MPTC permits any language; a C
companion is strongly recommended for round 2.
\paragraph{No optimized implementation.}
\texttt{ref/go/} is the boring, clear, slow reference. AVX-512 /
NEON / SHA-3-NI optimization is post-submission work. Performance
numbers in the experimental-evaluation report reflect the reference,
not optimized implementations.
\paragraph{No first-order masking.}
Power analysis resistance via masking is post-submission hardening.
The reference is constant-time at the algorithmic level (no
secret-dependent branches, no secret-dependent memory access
patterns in inner loops) but has no power-side-channel
countermeasures.
\paragraph{No HSM integration.}
Production-deployment patches (HSM integration, FIPS 140-3 module
shim) are post-submission. The reference is software-only.
\paragraph{Constant-time analysis is dudect-level.}
Go's compiler is not guaranteed constant-time at the IR level. We
use dudect (\texttt{ct/dudect/}) to check the leading-edge timing
distribution for secret-correlated values. This catches the obvious
leaks but does not provide the formal guarantee of e.g.\
Jasmin-verified C kernels. Formal verification
(Jasmin/Formosa/EasyCrypt) is post-submission.
\subsection{NIST process}
\paragraph{No prior NIST MPTC preview submission.}
We're starting from cold. The third-preview window deadline
(2026-Jul-20) is roughly two months out. Achieving a credible
preview writeup in that window is the immediate gate. If we miss the
third preview, we lose the ability to submit the round-1 package
without a preview, which is a hard requirement per IR 8214C \S5.1.
\paragraph{Patent claims not yet inventoried.}
Pulsar inherits Corona's IP posture. Pulsar-M needs a fresh
patent-claim review for the M-LWE adaptation.
\texttt{spec/patent-notes.tex} collects claims as they're discovered;
final notice for the package is on the critical path for
2026-Nov-16.
\paragraph{External cryptanalysis engagement not yet contracted.}
NIST MPTC submissions are strengthened by independent academic
cryptanalysis. We have not yet engaged a third party. A 6-month
engagement starting July 2026 is the target --- this aligns with the
post-package public-analysis window rather than blocking the package
itself.
\subsection{Repo / build}
\paragraph{Go module initialised.}
\texttt{go.mod} brings in \texttt{cloudflare/[email protected]} (FIPS~204
backbone) and \texttt{golang.org/x/crypto/sha3} (FIPS~202 / SP
800-185 transcripts). Cleanly builds with \texttt{GOWORK=off}.
\paragraph{Spec PDF not yet built.}
\texttt{spec/pulsar-m.tex} is \textbf{complete} as LaTeX source
(1500+ lines covering Front matter / Notation / Preliminaries /
Algorithms / Verification / Reshare / Identifiable abort / Security
analysis / Concrete parameters / Large committees / Encodings /
System model / Implementation considerations / Performance / Test
vectors / Complexity analysis / Deployment / Comparison / Patent
claims / Known limitations / Open questions). The companion files
\texttt{security-games.tex}, \texttt{system-model.tex}, and
\texttt{parameters.tex} are also complete. Building the PDF via
\texttt{latexmk -pdf spec/pulsar-m.tex} is on the active writing
track once the bib resolution lands.
\paragraph{KAT suite generated.}
\texttt{vectors/\{keygen,sign,verify,threshold-sign,dkg\}.json} are
committed. \texttt{scripts/gen\_vectors.sh} re-runs the generator
and verifies that re-running produces byte-identical output (the
deterministic-fixture gate). The CAVS-style \texttt{kat-v1.rsp} ACVP
companion is on the v0.2 path; ACVP support requires the
post-encoding-freeze byte layout.
\paragraph{Lattice-estimator parameter table.}
\texttt{spec/parameters.tex} now includes the classical + quantum
security-level table (numbers inherited verbatim from FIPS~204 \S8
because Pulsar-M does not alter the underlying M-LWE parameters).
The Albrecht et al.\ lattice-estimator script
\texttt{estimator/params.sage} reproduces the table; the estimator
commit hash is pinned at submission in
\texttt{estimator/README.md}.
\subsection{Compared to Pulsar (R-LWE)}
\begin{center}
\begin{tabular}{lll}
\toprule
dimension & Pulsar & Pulsar-M \\
\midrule
Algebraic basis & Ring-LWE & Module-LWE \\
Hash & SHA-3 cSHAKE / BLAKE3 legacy & SHA-3 cSHAKE only \\
FIPS~204 output interchange & no (R-LWE) & yes (target) \\
MPTC class & S1/S4 & N1/N4 \\
Parameter sets & Pulsar-internal & ML-DSA-44/65/87 \\
DKG & Pedersen over $\Rq$ & Pedersen over $\Rq^k$ \\
Reshare & deterministic quorum & beacon-randomized quorum \\
\bottomrule
\end{tabular}
\end{center}
Where Pulsar provides feature X and Pulsar-M doesn't yet, Pulsar-M's
goal is to inherit X verbatim from Pulsar's \texttt{dkg2/} and
\texttt{reshare/} packages with the M-LWE shape change.
+183
View File
@@ -0,0 +1,183 @@
% Pulsar-M NIST MPTC category targeting -- included by pulsar-m.tex.
% Mirrors docs/nist-mptc-category.md (now deleted; this file is the
% canonical LaTeX form).
\paragraph{Reference.}
NIST IR 8214C, \emph{First Call for Multi-Party Threshold Schemes}
(January 2026). Package deadline expected 2026-Nov-16. Preview
deadline 2026-Jul-20.
\subsection{Pulsar-M target: Class N1 + N4}
NIST MPTC subdivides threshold schemes into:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item \textbf{Class S} (Special) --- threshold-friendly primitives
that \emph{are not} output-interchangeable with a NIST-specified
primitive. Submission evaluated for ``novel threshold-friendly
design.''
\item \textbf{Class N} (Normal-mode) --- threshold implementations
\emph{of} a NIST-specified primitive whose outputs are
interchangeable with the corresponding non-threshold primitive's
outputs.
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item \textbf{N1}: signing
\item \textbf{N2}: encryption / decryption
\item \textbf{N3}: KEM
\item \textbf{N4}: ML keygen / DKG (Module-Lattice key generation,
distributed)
\end{itemize}
\end{itemize}
Pulsar-M aims for \textbf{N1 (threshold ML-DSA signing) + N4
(distributed ML-DSA keygen)}. The headline interchangeability claim:
\begin{quote}
A signature $\sigma$ produced by a Pulsar-M threshold ceremony on
message $\mu$ against group public key $\mathit{pk}$ verifies under
unmodified FIPS~204 \texttt{ML-DSA.Verify}$(\mathit{pk}, \mu,
\sigma)$ returning \texttt{accept}.
\end{quote}
If we can prove and demonstrate this, Pulsar-M is a Class N
candidate. If the output is not bit-for-bit FIPS~204 (e.g.\ encoding
differs in any field), Pulsar-M falls back to Class S --- still
valid, but a weaker NIST positioning.
\subsection{Output interchangeability --- what has to hold}
ML-DSA-65 signatures (FIPS~204 \S5.4, Algorithm~26 \texttt{sigEncode})
are encoded as a fixed-length 3309-byte string $\sigma = (\tilde c,
\mathbf{z}, \mathbf{h})$ whose three components decompose exactly as:
\begin{verbatim}
sigma = (c_tilde || z || h) 3309 bytes
c_tilde in {0,1}^{2 lambda} 48 bytes
// FIPS 204 commitment-hash length; 2 lambda bits with
// lambda=192 = 384 bits.
// (2 lambda here is the FIPS 204 commitment-hash parameter,
// not the security level -- the two happen to numerically
// agree for ML-DSA-65 because the standard ties one to the
// other at this parameter set.)
z in R^ell_q 3200 bytes
// ell = 5 polynomials, each 256 coefficients, packed at
// log2(2 gamma_1) = 20 bits per coefficient.
// 5 * 256 * 20 / 8 = 3200 bytes.
h in {0,1}^{omega + k} 61 bytes
// omega = 55 (hint bound), k = 6 (commitment-vector
// dimension). FIPS 204 Algorithm 22 hintBitPack + Algorithm
// 28 sigEncode pack omega + k = 61 bits as 61 bytes (one
// byte per bit position, terminator-first encoding per the
// standard).
total: 48 + 3200 + 61 = 3309 bytes (FIPS 204 Table 2)
\end{verbatim}
For Pulsar-M to claim Class N1, the threshold-aggregated signature
MUST deserialize as exactly this triple, with the same byte layout,
the same canonicalization rules, and the same rejection criteria.
The threshold protocol is allowed to perform multiple rounds
internally, but its emitted artifact MUST be a single FIPS~204
$\sigma$.
This is non-trivial: ML-DSA's rejection sampling means a single-shot
threshold output can fail rejection and require restart. Pulsar's
2-round structure handles this for R-LWE; Pulsar-M needs to
reproduce the rejection-restart logic for M-LWE without leaking
secret information across the restart.
\subsection{Required package deliverables}
Per NIST IR 8214C \S5:
\begin{center}
\begin{tabular}{lll}
\toprule
element & format & location \\
\midrule
Technical Specification & PDF (LaTeX) & \texttt{spec/pulsar-m.pdf} \\
Reference Implementation & open-source code & \texttt{ref/go/} \\
Report on Experimental Evaluation & PDF + reproducible scripts &
\texttt{bench/results/REPORT.md} + \texttt{bench/run\_all.sh} \\
Notes on Patent Claims & PDF & \texttt{spec/patent-notes.tex} \\
Concrete parameter set & section in spec & \texttt{spec/parameters.tex} \\
Security analysis (proofs) & section in spec & \texttt{spec/security-games.tex} \\
Public repository & GitHub or equiv & \url{https://github.com/luxfi/pulsar-m} \\
Build/test/benchmark scripts & shell & \texttt{scripts/*.sh} \\
Open-source license & text & \texttt{LICENSE} (Apache-2.0) \\
I/O test vectors & JSON / RSP & \texttt{vectors/kat-v1.\{json,rsp\}} \\
\bottomrule
\end{tabular}
\end{center}
Optional but strongly recommended:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item Executive summary (1-2 pages) at front of spec.
\item Threat-model document (\texttt{spec/threat-model.tex}).
\item System-model document (\texttt{spec/system-model.tex}).
\item Known-limitations appendix (so reviewers see the gaps before
they find them).
\end{itemize}
\subsection{Required security strengths}
NIST MPTC \S4.5 gives the required and suggested security-strength
targets:
\begin{center}
\begin{tabular}{llll}
\toprule
target & classical & post-quantum (NIST PQ category) & statistical \\
\midrule
\textbf{required} ($\ge 1$ parameterization) & $\ge 128$ bits &
$\ge$ Category 1 & $\ge 40$ bits \\
\textbf{suggested} (additional, optional) & $\ge 192$ bits &
$\ge$ Category 3 & $\ge 64$ bits \\
\bottomrule
\end{tabular}
\end{center}
Pulsar-M will ship parameter sets matching ML-DSA-65 (Category 3)
for the suggested target, and potentially ML-DSA-44 (Category 2) and
ML-DSA-87 (Category 5) for full coverage.
\subsection{Class N vs Class S decision}
Pulsar-M is N if and only if:
\begin{enumerate}[leftmargin=*, itemsep=0pt]
\item A working reference implementation produces signatures
byte-equal to FIPS~204 ML-DSA on the same $(\mathit{pk}, \mu)$ for
some valid threshold ceremony.
\item The threshold key generation produces a $\mathit{pk}$ that's a
valid FIPS~204 ML-DSA public key (no extra public material
distinguishable from a single-party $\mathit{pk}$).
\item The verification relation in the spec is the FIPS~204 verifier
verbatim, with no Pulsar-specific changes.
\end{enumerate}
If any of (1)-(3) fails, we ship as Class S with a clear ``future
work: output interchangeability'' note. The class decision is
finalized at the point we freeze the spec encoding.
\subsection{Pulsar (R-LWE) for comparison}
Pulsar (R-LWE) targets \textbf{Class S1 + S4}: special
threshold-friendly two-round signature, not output-interchangeable
with any NIST-approved primitive. The S1/S4 framing is the right
framing for Corona-derivatives unless and until NIST blesses
Corona-shaped outputs as a primitive.
\subsection{Status}
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item[$\square$] Class declared (N vs S, awaiting spec freeze)
\item[$\square$] Preview writeup drafted
\item[$\square$] Preview submitted (target 2026-Jul-20)
\item[$\square$] Spec freeze
\item[$\square$] Reference impl complete
\item[$\square$] KATs cross-validated against FIPS~204 reference
\item[$\square$] Experimental-evaluation report
\item[$\square$] Patent-claims notes finalized
\item[$\square$] Package submitted (target 2026-Nov-16)
\end{itemize}
+111
View File
@@ -0,0 +1,111 @@
% Pulsar-M Notes on Patent Claims -- included by pulsar-m.tex.
% Mirrors docs/patent-notes-draft.md (now deleted; this file is the
% submission-package patent-claims appendix).
\paragraph{Required by NIST MPTC IR 8214C \S5} as a package
deliverable. This document is collected over the development period
and finalized for the submission.
\subsection{Status}
\textbf{Draft.} No patent claims have been formally identified. This
appendix tracks claims as contributors disclose them.
\subsection{Inherited from upstream}
\paragraph{Pulsar (\texttt{luxfi/pulsar}).}
Pulsar-M reuses Pulsar's protocol structure. Pulsar's IP posture per
its README:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item Apache-2.0 licensed.
\item Patent grant per Apache 2.0 \S3 from each contributor.
\item No known active patent claims as of repository creation.
\end{itemize}
This applies to Pulsar-M to the extent that Pulsar-M code or
protocol elements are derivative of Pulsar.
\paragraph{Corona (\texttt{luxfi/corona}).}
Pulsar (and therefore Pulsar-M) is a fork of academic Corona.
Corona (ePrint 2024/1113) authors: Cecilia Boschini, Darya
Kaviani, Russell W. F. Lai, Giulio Malavolta, Akira Takahashi, Mehdi
Tibouchi. Corona's open-source repo is Apache-2.0 with no asserted
patent claims as of mid-2026. Pulsar-M's M-LWE adaptation does not
import Corona code directly but inherits the protocol structure.
\paragraph{ML-DSA / FIPS 204.}
ML-DSA is a NIST-standardized algorithm. The Dilithium team's IP
disclosures during NIST PQC standardization are public on the NIST
PQC website. Pulsar-M targets output interchangeability with
FIPS~204 but does not assert any rights over FIPS~204 itself.
\subsection{Contributor disclosures}
Per \texttt{CONTRIBUTING.md}, every commit's \texttt{Signed-off-by}
line is taken as either:
\begin{enumerate}[leftmargin=*, itemsep=0pt]
\item An explicit assertion that the contributor has no relevant
patent claims, OR
\item A reference to a disclosed claim listed below.
\end{enumerate}
\begin{center}
\begin{tabular}{llll}
\toprule
date & contributor & type & disclosure \\
\midrule
2026-05-10 & Lux Industries Inc & initial repo & no claims asserted \\
\bottomrule
\end{tabular}
\end{center}
(Updated as contributions land.)
\subsection{Third-party patents we may need to navigate}
Live concerns to investigate before submission:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item Lattice-estimator usage (we use the open-source estimator;
license pass-through to MIT).
\item Gaussian sampler implementation (FIPS~204 references CDT;
alternate rejection samplers may have IP).
\item Polynomial multiplication via NTT (standard, no known IP).
\item Pedersen commitments (1991 paper, expired patents).
\end{itemize}
The submission's Notes on Patent Claims will explicitly call out
each of these.
\subsection{NIST MPTC submission requirements}
NIST IR 8214C \S5 (Notes on Patent Claims) requires:
\begin{quote}
Submitter(s) shall include a statement of any patent claims known
to them that may be relevant to the submitted package, regardless
of who owns the claim. Statements of ``no known claims'' are
acceptable.
\end{quote}
Our final statement, once the spec freezes:
\begin{quote}
\emph{To be drafted at spec freeze. Will incorporate every
disclosure in the contributor table above, every inherited claim
from Pulsar / Corona / ML-DSA, and the third-party investigation
outcome.}
\end{quote}
\subsection{Process}
\begin{enumerate}[leftmargin=*, itemsep=0pt]
\item Every PR review checks for new IP-relevant code.
\item Significant cryptographic additions (new sampling routine, new
commitment shape, new aggregation step) trigger an explicit IP
review with one of the sponsor's IP counsel.
\item Final statement assembled at freeze, included in
\texttt{spec/pulsar-m.pdf} Appendix~A.
\end{enumerate}
+26 -6
View File
@@ -1417,8 +1417,8 @@ The reference implementation targets constant-time semantics as
specified in \S\ref{sec:impl-ct}. Physical side-channel resistance
(power analysis, EM, fault injection, cache timing) is out of scope
for the round-1 MPTC submission; see
\texttt{docs/known-limitations.md} for the deferred mitigations and
\S\ref{sec:knownlimits} for the round-2 roadmap.
\S\ref{sec:knownlimits} for the deferred mitigations and round-2
roadmap.
% =====================================================================
\section{Test vectors}
@@ -1594,20 +1594,40 @@ $\beta_e$ & chain randomness beacon at epoch $e$ \\
\end{tabular}
\end{center}
\section{NIST MPTC category targeting}
\label{sec:nist-mptc-category}
\input{nist-mptc-category}
\section{Threat model}
\label{sec:threat-model}
\input{threat-model}
\section{Design decisions}
\label{sec:design-decisions}
\input{design-decisions}
\section{Pulsar family architecture}
\label{sec:family-architecture}
\input{family-architecture}
\section{Patent claims}
\label{sec:patent}
Final patent disclosure assembled from
\texttt{docs/patent-notes-draft.md} at the submission freeze. Lux
Final patent disclosure assembled at the submission freeze. Lux
Industries Inc.\ asserts no patent claims on the cryptographic body
of Pulsar-M; the threshold protocol is a port of the publicly-known
Corona~\cite{corona2024} construction with the beacon-quorum
strengthening of DD-006, both of which are explicitly placed into
the public domain by this submission.
\input{patent-notes}
\section{Known limitations}
\label{sec:knownlimits}
Mirror of \texttt{docs/known-limitations.md}, frozen at submission.
Round-1 MPTC limitations and round-2 roadmap items:
Frozen at submission. Round-1 MPTC limitations and round-2 roadmap
items:
\input{known-limitations}
\subsection{Round-1 / round-2 roadmap (inline)}
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item \textbf{Adaptive corruption proof.} Round-1 proves
+164
View File
@@ -0,0 +1,164 @@
% Pulsar-M threat model -- included by pulsar-m.tex.
% Mirrors docs/threat-model.md (now deleted; this file is the
% canonical LaTeX form).
\subsection{Adversary classes}
We give an adversary the union of the following capabilities,
parameterized by $t$ (the corruption threshold) and the corruption
model:
\paragraph{Static corruption (default).}
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item Adversary $\mathcal{A}$ selects up to $t-1$ parties to corrupt
\textbf{before} protocol start. From start to end of the protocol,
those $t-1$ parties are controlled; the remaining honest parties run
the protocol faithfully.
\item $\mathcal{A}$ sees all messages on the broadcast channel + all
messages on the authenticated point-to-point channels into corrupted
parties.
\item $\mathcal{A}$ learns each corrupted party's full state (secret
share, randomness, per-round values) including session-state values.
\item $\mathcal{A}$ can selectively delay messages within the round
window but cannot forge messages from honest parties on
authenticated channels.
\end{itemize}
\paragraph{Adaptive corruption (stronger model).}
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item Adversary $\mathcal{A}$ can corrupt up to $t-1$ parties at any
time during the protocol, including mid-round, conditioned on the
transcript so far.
\item Once corrupted, a party remains corrupted for the rest of the
protocol.
\item All other capabilities as in static.
\end{itemize}
The Pulsar-M security analysis (\texttt{spec/security-games.tex})
provides the precise game definitions. Static security is the
baseline; adaptive security is a stretch goal for the first MPTC
submission and a hard requirement for the second-round response.
\paragraph{Mobile corruption (proactive resharing).}
For long-lived deployments where the validator set rotates between
epochs (Pulsar's \texttt{reshare/} direction), the relevant model is
HJKY97 mobile adversary: $\mathcal{A}$ can corrupt up to $t-1$
parties \textbf{per epoch}, with the corruption set varying across
epochs. The adversary may \emph{uncorrupt} a party (forget what it
learned) at epoch boundaries.
Pulsar-M proactive resharing inherits the soundness argument from
Pulsar's \texttt{reshare/} (with the constant-time fix from F9 of
the Hanzo HIP-0077 red review). The MPTC submission documents the
mobile-adversary game explicitly.
\subsection{Out-of-scope adversary capabilities}
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item Compromise of the cryptographic hash function (SHAKE-256 /
cSHAKE-256 / KMAC-256). NIST FIPS 202 + SP 800-185 are taken as
building blocks.
\item Side-channel attacks on the \emph{physical} hardware running a
party (power analysis, EM, fault injection). Mitigation discussed in
\S\ref{sec:knownlimits} as future work.
\item Compromise of the BIP-32/BIP-39 mnemonic from which
device-specific keys are derived. The HD-derivation security
argument lives in HIP-0077 \S``Identity''; the Pulsar-M layer
assumes parties' input keys are uniformly distributed.
\end{itemize}
\subsection{In-scope security goals}
\paragraph{Threshold unforgeability (TS-UF).}
For any PPT adversary $\mathcal{A}$ controlling up to $t-1$ parties,
$\mathcal{A}$ cannot produce a valid Pulsar-M signature $\sigma^*$
on any message $\mu^*$ that an honest signing ceremony has not
produced.
\paragraph{Robustness / identifiable abort.}
If a corrupted party deviates from the protocol, the honest parties:
\begin{enumerate}[leftmargin=*, itemsep=0pt]
\item Detect the deviation.
\item Identify the deviating party.
\item Produce signed evidence of the deviation suitable for slashing
/ reputation reduction.
\end{enumerate}
\paragraph{Output indistinguishability from FIPS 204.}
A Pulsar-M signature $\sigma$ on message $\mu$ against group public
key $\mathit{pk}$ is computationally indistinguishable from a
FIPS~204 ML-DSA signature on the same $(\mathit{pk}, \mu)$.
Specifically: an adversary that can distinguish the two with
non-negligible advantage breaks the underlying M-LWE assumption.
\paragraph{Bias resistance.}
The randomness used in each party's contribution (Gaussian samples,
challenge polynomials) is statistically indistinguishable from
uniform even given the adversary's view of corrupted parties'
randomness.
\paragraph{DKG soundness.}
Pedersen DKG over $\Rq^k$ produces a public key $\mathit{pk}$
distributed uniformly over the valid M-LWE public-key space, with no
party holding more than $1/n$ partial information about the
corresponding secret key.
\subsection{Assumed channels}
\begin{center}
\begin{tabular}{lll}
\toprule
channel & property & purpose \\
\midrule
Broadcast & authenticated, eventual-delivery & round transcripts,
public coins \\
Point-to-point & authenticated, encrypted & private share / blind
delivery \\
Public bulletin & authenticated, append-only & DKG commitments,
reshare records \\
\bottomrule
\end{tabular}
\end{center}
The reference implementation provides these channels via TCP + TLS.
Production deployments (e.g.\ Lux consensus + Quasar) bind these to
their existing P2P transport.
\subsection{Trusted parameters}
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item The cyclotomic ring $\Rq = \Zq[X] / (X^{256} + 1)$ and
parameters $(q, k, \ell, \eta, \beta, \omega, \ldots)$ exactly as in
FIPS~204 ML-DSA-65.
\item The hash family: SHAKE-256 (FIPS 202), cSHAKE-256 / KMAC-256 /
TupleHash-256 (NIST SP 800-185). Customization tags are pinned in
\texttt{spec/pulsar-m.tex}.
\item The Gaussian sampler parameters from FIPS~204 \S3.3 / \S4.2.
\end{itemize}
No trusted setup beyond NIST primitives.
\subsection{Failure modes addressed}
The MPTC submission documents how Pulsar-M handles each failure
mode that broke earlier threshold-lattice schemes:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item \textbf{Rejection-sampling restart leaking secret information
across rounds}: Pulsar's PRNG-key per-round domain separation
(CRIT-1 fix from upstream's 2026-05-03 amendment) ports forward.
\item \textbf{Constant-time share comparison}:
\texttt{dkg2.constTimePolyEqual} pattern ported from upstream
Pulsar (\texttt{reshare/commit.go} F9 fix).
\item \textbf{Information leaks via logging}: zero stdlib
\texttt{log} use in any secret-touching path; all logging via
\texttt{luxfi/log} at fields that are explicitly public.
\item \textbf{Deterministic quorum selection in resharing leaking
adversary positioning}: Pulsar-M uses a beacon-derived per-reshare
quorum selection (HIP-0077 \S``reshare quorum'' F10 fix).
\item \textbf{Cross-mode hash-suite confusion}: NIST profile is
exclusively SHA-3 family; no BLAKE3 in Pulsar-M ever.
\end{itemize}