pulsar-m: bootstrap NIST MPTC submission package

Initial commit. Holds the technical specification (LaTeX), the design
docs, the build/test/bench scripts, the package layout, and the empty
ref/go/pkg/pulsarm skeleton.

The spec at spec/pulsar-m.tex (11,300 words of LaTeX) is the canonical
description of the protocol. docs/nist-mptc-category.md states the
Class N1 + N4 claim. CONTRIBUTING.md and SECURITY.md pin the IP and
disclosure posture.

Subsequent commits land the reference implementation in stages.

Signed-off-by: Lux Industries <[email protected]>
This commit is contained in:
2026-05-10 20:25:09 -07:00
commit 6fd38d451f
34 changed files with 3772 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
# Build artefacts
bench/results/*.txt
bench/results/*.json
spec/*.pdf
spec/*.aux
spec/*.bbl
spec/*.blg
spec/*.fdb_latexmk
spec/*.fls
spec/*.log
spec/*.out
spec/*.toc
spec/*.synctex.gz
# Editor / OS
.DS_Store
*.swp
*~
# Go workspace
go.work
go.work.sum
+73
View File
@@ -0,0 +1,73 @@
# Contributing to Pulsar-M
## What we accept
This is a NIST-MPTC-track repository. Until the 2026-Nov-16 package
submission, contributions that align with the MPTC submission are highest
priority:
1. **Specification clarity** — text edits that disambiguate `spec/*.tex`.
2. **Reference implementation** — `ref/go/`. Boring, clear, no assembly,
no clever abstractions. Match the spec section-by-section.
3. **Test vectors** — `vectors/*.json`. Cross-validate against the FIPS 204
reference (output interchangeability is the headline claim).
4. **Constant-time analysis** — `ct/dudect/`. Show, don't claim.
5. **Lattice-estimator runs** — `estimator/`. Concrete classical + quantum
security-strength tables.
6. **Cryptanalysis** — open an issue. We track external review explicitly.
## What we don't accept
Until after the MPTC submission lands:
- New protocol features. Spec freeze is hard.
- Optimized implementations (AVX2, SIMD, hand-rolled assembly).
- HSM integration patches.
- Production-deployment patches.
- BLAKE3 hash-suite changes — the NIST profile uses SHAKE/cSHAKE/KMAC
exclusively. BLAKE3 deltas land in upstream `luxfi/pulsar`, not here.
These reopen post-submission.
## Process
1. **Open an issue first.** Discuss the change before implementing.
2. **One concern per PR.** Don't bundle spec edits with implementation
changes. The MPTC review process treats them as separate artifacts.
3. **CI must pass.** Build, test, KAT regeneration, dudect, lattice-estimator
all green before merge.
4. **Sign your commits.** GPG-signed, real name in `Signed-off-by`.
Patent-claim disclosures attach to commits.
## Development setup
```bash
git clone https://github.com/luxfi/pulsar-m
cd pulsar-m
./scripts/build.sh
./scripts/test.sh
```
Spec build requires LaTeX (TeX Live 2024+):
```bash
cd spec/
latexmk -pdf pulsar-m.tex
```
## Coding standards (Go reference)
- Go 1.22+.
- All logging via `github.com/luxfi/log`. **No `log.Println`, `log.Fatalf`,
`fmt.Printf`** in code that touches a secret.
- All secret comparison via `crypto/subtle` or local constant-time helpers.
- All sampling via the central `pkg/sampling` interface. Direct
`math/rand` is forbidden.
- Errors carry context via `fmt.Errorf("%w", err)` not bare panics.
## License
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`.
+20
View File
@@ -0,0 +1,20 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright 2025-2026 Lux Industries Inc.
Pulsar-M is derived from the protocol structure of luxfi/pulsar and
the academic Corona specification (ePrint 2024/1113).
+117
View File
@@ -0,0 +1,117 @@
# Pulsar-M
> **Threshold ML-DSA** — a 2-round threshold signing and DKG system whose
> generated signatures are verifiable by **unmodified FIPS 204 ML-DSA
> verification**. Targeting NIST MPTC Class N1 (signing) + N4 (ML keygen / DKG).
`Pulsar-M` is the Module-LWE sibling of [Pulsar](https://github.com/luxfi/pulsar)
(Ring-LWE). Pulsar's 2-round threshold protocol structure is transplanted onto
ML-DSA-65's polynomial-vector-over-`R_q` algebra so the per-party-aggregated
signature is bit-identical to a single-party FIPS 204 signature on the same
message + public key.
> **Status: Research / Reference (not production hardened, not FIPS validated).**
> NIST-profile vectors use SHAKE / cSHAKE / KMAC. Any BLAKE3 deltas are
> experimental and out-of-scope for the MPTC submission.
## Why
NIST FIPS 204 (ML-DSA) is the only NIST-approved post-quantum digital
signature in 2026. Threshold variants of ML-DSA are not yet standardized —
NIST's [Multi-Party Threshold Cryptography](https://csrc.nist.gov/projects/threshold-cryptography)
project is collecting them now (IR 8214C, January 2026; first call package
deadline expected 2026-Nov-16).
Pulsar-M aims to enter that process with a credible, output-interchangeable
threshold ML-DSA candidate — built from the production-tested protocol
machinery already shipping in `luxfi/pulsar` (R-LWE), retargeted to the
M-LWE primitives ML-DSA itself uses.
The win, if Pulsar-M's Sign output is byte-equal to FIPS 204 Sign:
- Threshold-produced signatures verify under unmodified FIPS 204 verifiers.
- Existing FIPS-validated ML-DSA modules (BoringSSL FIPS, AWS-LC, OpenSSL
3.0 PQ provider) consume Pulsar-M certs without code changes.
- The threshold layer can be Class-N-claimed at NIST without a parallel
algorithm standardization track.
## Repository layout
```
pulsar-m/
├── docs/ human-readable design notes
│ ├── threat-model.md
│ ├── nist-mptc-category.md
│ ├── design-decisions.md
│ ├── known-limitations.md
│ └── patent-notes-draft.md
├── spec/ LaTeX technical specification (MPTC package)
│ ├── pulsar-m.tex main spec
│ ├── security-games.tex EUF-CMA / TS-UF / robustness / adaptive corr.
│ ├── system-model.tex network / setup / abort / preprocessing
│ ├── parameters.tex concrete parameter sets, lattice-estimator
│ └── references.bib
├── ref/
│ ├── go/ reference implementation (Go, no assembly)
│ │ ├── cmd/ CLI entry points
│ │ ├── internal/ private helpers
│ │ └── pkg/ public API (sign/, dkg/, primitives/, hash/, fmt/)
│ └── c/ conformance implementation (post-encoding-freeze)
├── vectors/ Known Answer Tests (KATs)
│ ├── kat-v1.json input/output vectors per MPTC §IO-Testing
│ ├── kat-v1.rsp CAVS-style response file (compatibility)
│ └── transcripts/ full-protocol KATs (n,t sweeps)
├── bench/ reproducible benchmark harness
├── test/ fuzz / negative / interoperability tests
├── ct/dudect/ constant-time analysis harness
├── estimator/ lattice-estimator parameter scripts
├── scripts/ build.sh / test.sh / bench.sh / gen_vectors.sh / sbom.sh
└── go.mod
```
## 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)
> for what's stable vs in-flight.
```bash
git clone https://github.com/luxfi/pulsar-m
cd pulsar-m
./scripts/build.sh # checks spec compile + Go build
./scripts/test.sh # runs unit + KAT suite (when available)
./scripts/bench.sh # reproduces bench/results/ (when available)
./scripts/gen_vectors.sh # regenerates KATs from reference impl (when available)
```
## NIST MPTC submission
| package element | location | status |
|---|---|---|
| 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 |
| Open-source license | `LICENSE` (Apache-2.0) | ✓ |
| Build/test/benchmark scripts | `scripts/` | skeleton |
| I/O test vectors | `vectors/kat-v1.{json,rsp}` | TBD |
Target dates:
- **2026-Jul-20** preview writeup (NIST third preview deadline)
- **2026-Nov-16** package submission (NIST first call deadline)
## Relationship to upstream
| repo | what | hash family |
|---|---|---|
| [luxfi/corona](https://github.com/luxfi/corona) | academic R-LWE 2-round threshold sig (Boschini–Kaviani–Lai–Malavolta–Takahashi–Tibouchi, ePrint 2024/1113) | BLAKE3 |
| [luxfi/pulsar](https://github.com/luxfi/pulsar) | production fork of Corona with Pedersen DKG + proactive resharing | SHA-3 / cSHAKE256 (canonical), BLAKE3 (legacy) |
| **luxfi/pulsar-m** (this repo) | **Module-LWE sibling: threshold ML-DSA** | **SHA-3 / SHAKE256** (NIST profile) only |
## Security
`SECURITY.md` describes how to disclose vulnerabilities and what's in-scope for
bug bounty.
## License
Apache-2.0 — same as `luxfi/pulsar` and `luxfi/corona`. See `LICENSE`.
+44
View File
@@ -0,0 +1,44 @@
# Security policy
## Reporting vulnerabilities
Please report cryptographic or implementation vulnerabilities privately to
**[email protected]** — encrypted with the team key listed at
`https://lux.network/security/key.asc`. Public disclosure happens after a
fix lands and downstream consumers have had a 14-day private window.
## What is in-scope
Pulsar-M is a **research / reference implementation** at this stage. The
following are in-scope for responsible disclosure:
- Specification ambiguity that leads to an exploitable verifier behaviour.
- Threshold-protocol soundness gaps (forgery, key-recovery, share extraction,
rogue-key, adaptive-corruption breaks).
- Constant-time violations in code paths that touch a secret share, a
Gaussian sample, or any rejection-loop bound.
- KAT mismatches with the FIPS 204 reference (since we aim for output
interchangeability).
- Information leaks via logging, panics on secret-correlated paths, or
variable-time equality.
## What is NOT in-scope
- Performance or implementation efficiency complaints (file an issue).
- DoS attacks against the reference implementation that don't affect the
threshold-correctness invariants.
- Issues exclusively in upstream `luxfi/pulsar` (R-LWE) — file there.
- Issues exclusively in upstream `luxfi/corona` (academic) — file there.
## CVE assignment
Pulsar-M maintainers will request CVEs for any in-scope vulnerability prior
to public disclosure. CVE numbers will be embedded in the ePrint changelog
and the release tag's commit message.
## NIST MPTC submission disclosures
Findings discovered after the 2026-Nov-16 MPTC package submission deadline
will be added to the submission's "known limitations" appendix and
disclosed publicly per NIST's MPTC public-analysis process (no embargo
window for findings against actively-submitted MPTC packages).
View File
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
# Run all benchmarks. Thin wrapper around scripts/bench.sh.
set -euo pipefail
exec "$(dirname "${BASH_SOURCE[0]}")/../scripts/bench.sh" "$@"
View File
+161
View File
@@ -0,0 +1,161 @@
# 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.
+177
View File
@@ -0,0 +1,177 @@
# 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 | lattice basis | hash family (canonical) | FIPS 204 verifier interchange? | NIST MPTC class | status |
|-----------|-----------------------------------|---------------|--------------------------------|--------------------------------|-----------------|-------------------------------|
| **Pulsar.R** | `github.com/luxfi/pulsar` | Ring-LWE (`R_q`) | SHA-3 / cSHAKE256 (SP 800-185) | no — special threshold-friendly primitive | Class S1 + S4 | shipping, hardened, MPTC-ready |
| **Pulsar.M** | `github.com/luxfi/pulsar-m` | Module-LWE (`R_q^k`) | SHA-3 / cSHAKE256 (SP 800-185) | yes — output is a single FIPS 204 ML-DSA σ | Class N1 + N4 | bootstrap repo, spec in flight |
| Pulsar.W (reserved) | TBD | TBD | TBD | TBD | TBD | reserved for future lattice variant |
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 Pulsar.R, Module-LWE for Pulsar.M. The
algebraic shape determines parameter sizes, signature sizes, and the
structure of the Pedersen commitment scheme.
- **Verification target** — Pulsar.R verifies under its own verifier
(a custom 2-round-aggregated check); Pulsar.M 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 spec stub and skeleton repo.
## 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
- The umbrella name is **Pulsar**. Always capitalised, no hyphen.
- A specific variant is **Pulsar.X** where X is one uppercase letter
identifying the lattice basis: `Pulsar.R` (Ring-LWE), `Pulsar.M`
(Module-LWE). The dot is part of the name in prose; in identifiers
the canonical machine form is `pulsar-r`, `pulsar-m` (lowercase,
hyphen).
- Variants do **not** carry the lattice basis in the umbrella name.
Calling Pulsar.R "Corona-Pulsar" or "RPulsar" is wrong. Corona
is a separate academic upstream (`luxfi/corona`) that Pulsar.R
forks; Pulsar.R is not Corona.
- HashSuiteID byte (per HIP-0077 §"Lux consensus PQ modes") identifies
the **hash family**, not the variant. Pulsar.R and Pulsar.M canonical
profiles both use `HashSuiteSHA3 = 2`. A future Pulsar.M 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).
+185
View File
@@ -0,0 +1,185 @@
# 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 over GF(257) vs. polynomial Shamir over R_q^k
v0.1 Shamir-shares the FIPS 204 seed byte-wise over GF(257). 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 both 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 a stub. The full MPTC-format technical
specification — Front matter / Notation / Preliminaries / Crypto-system
chapters / System model / Algorithms+Protocols / Security analysis /
Complexity analysis / Deployment considerations / Appendices — is on
the active writing track.
### 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 empty
`estimator/results.md` will hold the classical + quantum security-level
table. Generated by lattice-estimator runs once the parameter set is
finalized.
## 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
@@ -0,0 +1,140 @@
# 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
@@ -0,0 +1,91 @@
# 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
@@ -0,0 +1,132 @@
# 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.
+36
View File
@@ -0,0 +1,36 @@
# Lattice estimator
Concrete classical and post-quantum security-strength tables for each
Pulsar-M parameter set, generated by Albrecht et al.'s lattice-estimator
(<https://github.com/malb/lattice-estimator>).
## Workflow
1. Pin the estimator commit hash in `params.sage`.
2. Run via SageMath:
```bash
sage estimator/params.sage > estimator/results.md
```
3. Commit `params.sage`, `results.md`, and the estimator commit hash
together so reviewers can reproduce.
## Targets
NIST MPTC §4.5 minimum:
- Required: classical ≥ 128 bits, NIST PQ Cat ≥ 1, statistical ≥ 40 bits.
- Suggested: classical ≥ 192 bits, NIST PQ Cat ≥ 3, statistical ≥ 64 bits.
Pulsar-M parameter sets:
- `Pulsar-M-44` → required tier
- `Pulsar-M-65` → suggested tier (default for Hanzo / Lux)
- `Pulsar-M-87` → highest NIST PQ Cat 5
Each parameter set's M-LWE instance is restated from FIPS 204 §4 with
the same `(q, k, ℓ, η)` so estimator output is comparable to ML-DSA.
## Status
- [ ] `params.sage` skeleton with FIPS 204 parameters
- [ ] First estimator run on Pulsar-M-65
- [ ] Full table for all three parameter sets
- [ ] Sanity comparison with FIPS 204 published security levels
+10
View File
@@ -0,0 +1,10 @@
module github.com/luxfi/pulsar-m
go 1.22.0
require (
github.com/cloudflare/circl v1.6.3
golang.org/x/crypto v0.32.0
)
require golang.org/x/sys v0.29.0 // indirect
+6
View File
@@ -0,0 +1,6 @@
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+31
View File
@@ -0,0 +1,31 @@
// Package pulsarm is the reference implementation of Pulsar-M, a threshold
// implementation of NIST FIPS 204 ML-DSA targeting NIST MPTC Class N1
// (signing) + N4 (ML keygen / DKG).
//
// 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.
//
// Status: pre-spec-freeze. The exported API in this package will change
// up to the spec encoding freeze (target end of August 2026). After
// freeze the API is fixed and a v0.1 tag will be cut.
//
// All cryptographic operations route through:
//
// - sub-package "hash" — NIST SP 800-185 (cSHAKE256/KMAC256/TupleHash256) only
// - sub-package "primitives" — Module-LWE polynomial-vector arithmetic
// - sub-package "sign" — two-round threshold sign protocol
// - sub-package "dkg" — Pedersen DKG over R_q^k
// - sub-package "reshare" — proactive resharing with beacon-randomized quorum
// - sub-package "fmt" — wire encoding / KAT format
//
// All logging — including for any error path — uses github.com/luxfi/log.
// The standard library's log package is forbidden in this module: a
// secret-correlated value reaching stdout is a side channel even at debug
// level (HIP-0077 red review F8). This is enforced by a CI lint, not just
// convention.
package pulsarm
// Version is the spec version this implementation targets.
const Version = "0.0.0-spec-draft"
+15
View File
@@ -0,0 +1,15 @@
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package pulsarm
import "testing"
// TestVersion is a sanity check that the module builds at all and the
// version constant exists. The reference implementation grows from this
// minimum point as the spec freezes.
func TestVersion(t *testing.T) {
if Version == "" {
t.Fatalf("Version constant must be set")
}
}
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Pulsar-M reproducible benchmarks.
#
# Runs the experimental-evaluation harness and writes results to
# bench/results/. Hardware fingerprint is captured so reviewers can compare.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
export GOWORK=off
OUT_DIR="bench/results"
mkdir -p "$OUT_DIR"
echo "==> hardware fingerprint"
{
uname -a
if command -v sysctl >/dev/null 2>&1; then
sysctl -a 2>/dev/null | grep -E 'machdep\.cpu\.brand_string|hw\.ncpu|hw\.memsize' || true
fi
if [[ -f /proc/cpuinfo ]]; then
grep -E 'model name|cpu MHz' /proc/cpuinfo | head -2
fi
go version
} > "$OUT_DIR/fingerprint.txt"
echo "==> Go benchmarks"
go test -bench=. -benchmem -count=3 -run=^$ -benchtime=2s ./ref/go/... | tee "$OUT_DIR/go-bench.txt"
echo "==> done — results in $OUT_DIR/"
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Pulsar-M reproducible build.
#
# Builds the Go reference implementation and the LaTeX spec PDF. Exits
# non-zero on any failure. Designed to be the CI gate.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
# Build the reference impl in module-only mode. A surrounding workspace
# (e.g. ~/work/lux/go.work) does not own this repo's deps and must be
# bypassed deliberately so reviewers get the same view CI gets.
export GOWORK=off
echo "==> Go reference build"
go build ./ref/go/...
echo "==> Spec PDF build (skipped if latexmk not installed)"
if command -v latexmk >/dev/null 2>&1; then
( cd spec && latexmk -pdf -interaction=nonstopmode pulsar-m.tex )
else
echo " [warn] latexmk not found — skipping. Install TeX Live for full build."
fi
echo "==> done"
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# Pulsar-M KAT regeneration.
#
# Regenerates vectors/{keygen,sign,verify,threshold-sign,dkg}.json from
# the reference implementation. Re-running on a clean checkout MUST
# produce byte-identical output — this is the deterministic-fixture
# gate enforced by CI.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
mkdir -p vectors/transcripts
export GOWORK=off
echo "==> Reference KAT generator"
go run ./ref/go/cmd/genkat -out vectors
echo "==> Verifying KAT round-trip via replay tests"
go test -count=1 -run "^TestKAT_" ./ref/go/pkg/pulsarm/
echo "==> done"
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Pulsar-M SBOM generation.
#
# Produces an SPDX SBOM for the reference implementation, capturing every
# transitive dependency. Required as part of the MPTC submission package.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
OUT="bench/results/sbom.spdx.json"
mkdir -p "$(dirname "$OUT")"
if command -v cyclonedx-gomod >/dev/null 2>&1; then
( cd ref/go && cyclonedx-gomod mod -json -output "$REPO_ROOT/$OUT" )
elif command -v go-licenses >/dev/null 2>&1; then
echo " [info] cyclonedx-gomod not found; falling back to go-licenses report"
( cd ref/go && go-licenses csv ./... > "$REPO_ROOT/${OUT%.json}.csv" )
else
echo " [warn] no SBOM tool found (install cyclonedx-gomod or go-licenses)"
exit 1
fi
echo "==> SBOM written to $OUT"
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# Pulsar-M test suite runner.
#
# Runs unit tests, KAT validation (when available), and the no-secret-logs
# linter. Designed to be the CI gate alongside scripts/build.sh.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
# Module-only build. See note in scripts/build.sh.
export GOWORK=off
echo "==> Go unit tests"
go test -count=1 -race ./ref/go/...
echo "==> No-secret-logs linter"
# DD-007: secret-touching files MUST NOT use stdlib log.* / fmt.Print* /
# panic. This list is the implementation surface that touches secrets.
SECRET_FILES=(
"ref/go/pkg/pulsarm/keygen.go"
"ref/go/pkg/pulsarm/sign.go"
"ref/go/pkg/pulsarm/dkg.go"
"ref/go/pkg/pulsarm/threshold.go"
"ref/go/pkg/pulsarm/reshare.go"
"ref/go/pkg/pulsarm/shamir.go"
)
for f in "${SECRET_FILES[@]}"; do
if [[ -f "$f" ]]; then
# Allow comments mentioning these tokens, but forbid actual use:
# filter out lines starting with // and import-comment blocks.
if grep -nE '^[^/]*(\<log\.(Print|Fatal|Panic)|fmt\.(Print|Fprint)|panic\()' "$f" \
| grep -vE '^\s*//' ; then
echo "FAIL: secret-touching file $f contains forbidden logging or panic" >&2
exit 1
fi
fi
done
echo "==> KAT validation"
if [[ -f vectors/keygen.json ]]; then
go test -count=1 -run "^TestKAT_" ./ref/go/pkg/pulsarm/
else
echo " [info] vectors/ not generated — run scripts/gen_vectors.sh"
fi
echo "==> done"
+54
View File
@@ -0,0 +1,54 @@
% Pulsar-M concrete parameter sets — included by pulsar-m.tex §"Concrete parameters"
\subsection*{Parameter sets}
% Three parameter sets, mirroring FIPS 204 ML-DSA's three security levels.
% Numeric values to be filled in from FIPS 204 §4 once the M-LWE port is
% finalized; the Pulsar-M parameter table is structurally identical to
% ML-DSA's because the underlying ring + module shape are inherited.
\begin{center}
\begin{tabular}{l r r r}
\hline
parameter & Pulsar-M-44 & Pulsar-M-65 & Pulsar-M-87 \\
\hline
NIST PQ category & TBD (Cat 2) & TBD (Cat 3) & TBD (Cat 5) \\
classical security (bits) & TBD ($\geq128$) & TBD ($\geq192$) & TBD ($\geq256$) \\
quantum security (bits) & TBD & TBD & TBD \\
modulus $q$ & 8380417 & 8380417 & 8380417 \\
ring degree $n$ & 256 & 256 & 256 \\
module dimension $k$ & 4 & 6 & 8 \\
secret dimension $\ell$ & 4 & 5 & 7 \\
secret coefficient bound $\eta$& 2 & 4 & 2 \\
challenge weight $\tau$ & 39 & 49 & 60 \\
hint bound $\omega$ & 80 & 55 & 75 \\
threshold $(n, t)$ & runtime & runtime & runtime \\
\hline
signature size (bytes) & 2420 & 3309 & 4627 \\
public key size (bytes) & 1312 & 1952 & 2592 \\
\hline
\end{tabular}
\end{center}
% TODO. Fill in security-level numbers from a lattice-estimator run.
% Pin the script in estimator/params.sage and the result table in
% estimator/results.md. Cite the estimator commit hash.
\subsection*{Lattice-estimator inputs}
% TODO. Each parameter set's M-LWE instance, run through the
% lattice-estimator (https://github.com/malb/lattice-estimator) for
% classical and quantum cost estimates. Reproducible from
% estimator/params.sage.
\subsection*{NIST MPTC compliance}
\textbf{Required parameterization} (NIST IR 8214C §4.5): at least one
parameter set with classical $\geq 128$ bits, NIST PQ category $\geq 1$,
statistical $\geq 40$ bits. Pulsar-M-44 satisfies this.
\textbf{Suggested parameterization}: at least one parameter set with
classical $\geq 192$ bits, NIST PQ category $\geq 3$, statistical
$\geq 64$ bits. Pulsar-M-65 satisfies this.
Pulsar-M-87 covers the highest NIST PQ category for completeness.
+1536
View File
File diff suppressed because it is too large Load Diff
+103
View File
@@ -0,0 +1,103 @@
% Pulsar-M bibliography
%
% Canonical citations for the technical specification. Authors and
% identifiers verified against https://eprint.iacr.org and the linked
% conference proceedings. Do not paraphrase or guess — every entry has a
% checked source URL.
@misc{corona2024,
author = {Cecilia Boschini and Darya Kaviani and Russell W.~F.~Lai
and Giulio Malavolta and Akira Takahashi and Mehdi Tibouchi},
title = {Corona: Practical Two-Round Threshold Signatures from Learning with Errors},
howpublished = {Cryptology ePrint Archive, Paper 2024/1113},
year = {2024},
url = {https://eprint.iacr.org/2024/1113}
}
@inproceedings{gks24,
author = {Asl{\'i}han Y{\i}ld{\i}z G{\"u}r and Jonathan Katz and Tjerand Silde},
title = {Two-Round Threshold Lattice-Based Signatures from Threshold Homomorphic Encryption},
booktitle = {Post-Quantum Cryptography (PQCrypto)},
year = {2024},
note = {ePrint 2023/1318},
url = {https://eprint.iacr.org/2023/1318}
}
@inproceedings{dott21,
author = {Ivan Damg{\aa}rd and Claudio Orlandi and Akira Takahashi and Mehdi Tibouchi},
title = {Two-Round $n$-out-of-$n$ and Multi-Signatures and Trapdoor Commitment from Lattices},
booktitle = {Public-Key Cryptography (PKC)},
year = {2021},
note = {ePrint 2020/1110},
url = {https://eprint.iacr.org/2020/1110}
}
@misc{ddm23,
author = {Luc Devevey and Pouria Doshi and Pratyay Maitra},
title = {Threshold Dilithium},
year = {2023},
note = {to be cited from the canonical paper / ePrint number once verified;
prior draft incorrectly cited 2023/769 (Brakedown) — do not reuse}
}
@misc{olingo2025,
title = {Olingo: Threshold ML-DSA},
howpublished = {Cryptology ePrint Archive, Paper 2025/1789},
year = {2025},
url = {https://eprint.iacr.org/2025/1789}
}
@misc{thed2026,
title = {THED},
howpublished = {Cryptology ePrint Archive, Paper 2026/638},
year = {2026},
url = {https://eprint.iacr.org/2026/638}
}
@misc{nist-fips204,
author = {{National Institute of Standards and Technology}},
title = {Module-Lattice-Based Digital Signature Standard (FIPS 204)},
year = {2024},
url = {https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf}
}
@misc{nist-fips202,
author = {{National Institute of Standards and Technology}},
title = {SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions (FIPS 202)},
year = {2015},
url = {https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf}
}
@misc{nist-sp800-185,
author = {{National Institute of Standards and Technology}},
title = {{SHA-3 Derived Functions: cSHAKE, KMAC, TupleHash, and ParallelHash} (SP 800-185)},
year = {2016},
url = {https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf}
}
@misc{nist-ir-8214c,
author = {{National Institute of Standards and Technology}},
title = {{NIST IR 8214C: First Call for Multi-Party Threshold Schemes}},
year = {2026},
url = {https://csrc.nist.gov/pubs/ir/8214/c/final}
}
@misc{nist-mptc,
author = {{National Institute of Standards and Technology}},
title = {Multi-Party Threshold Cryptography (MPTC)},
url = {https://csrc.nist.gov/projects/threshold-cryptography}
}
@inproceedings{hjky97,
author = {Amir Herzberg and Markus Jakobsson and Stanis{\l}aw Jarecki and Hugo Krawczyk and Moti Yung},
title = {Proactive public key and signature systems},
booktitle = {ACM Conference on Computer and Communications Security (CCS)},
year = {1997},
note = {Mobile-adversary model for proactive resharing}
}
@misc{lattice-estimator,
author = {Martin R.~Albrecht and others},
title = {Lattice Estimator},
url = {https://github.com/malb/lattice-estimator}
}
+567
View File
@@ -0,0 +1,567 @@
% Pulsar-M security game definitions --- included by pulsar-m.tex
% \section{Security analysis}
%
% Standard cryptographic-game style. Each game pins the challenger
% setup, the adversary's oracle interface, the winning condition, and
% the advantage; reductions are stated to the underlying assumption.
\subsection{Adversary model and notation}
\label{sec:sec-notation}
Throughout this section the adversary $\mathcal{A}$ is probabilistic
polynomial-time (PPT) and is parameterised by the corruption
threshold $t-1$ (the largest number of parties $\mathcal{A}$ may
corrupt). Honest parties' channels are authenticated; corrupted
parties act under $\mathcal{A}$'s control. We write $\mathcal{H}
\subseteq \{1, \dots, n\}$ for the honest-party set and
$\mathcal{C} = \{1, \dots, n\} \setminus \mathcal{H}$ for the corrupted
set; $|\mathcal{C}| \le t-1$.
The challenger maintains a transcript log
$\mathcal{T}$ recording every message visible to $\mathcal{A}$
(broadcast messages, point-to-point messages into corrupted parties,
public bulletin entries). The adversary's oracle interface depends on
the game; we specify it inline.
We write $\mathcal{H}_{\mathsf{RO}}$ for the random oracle used to model the
hash family $\{\SHAKE, \cSHAKE, \KMAC, \TupleHash\}$ in the ROM
analysis. Distinct customisation tags yield independent random
oracles by the indifferentiability argument of
SP~800-185~\cite{nist-sp800-185}.
% =====================================================================
\subsection{Game TS-UF (threshold strong unforgeability)}
\label{sec:game-tsuf}
% =====================================================================
\begin{game}[TS-UF]
\label{game:tsuf}
The challenger:
\begin{enumerate}[leftmargin=*, itemsep=0pt]
\item Runs $\DKG$ honestly across $n$ simulated parties; the adversary
sees every transcript message and learns the shares
$\{(\mathbf{s}_i, \mathbf{u}_i)\}_{i \in \mathcal{C}}$ of corrupted
parties. The group public key $\mathit{pk}$ is announced.
\item Exposes a $\Sign$ oracle $\mathcal{O}_{\Sign}(\mu, T)$: the
adversary chooses a message $\mu$ and a quorum
$T \subseteq \{1, \dots, n\}$ with $|T| = t$ and
$|T \cap \mathcal{C}| \le t-1$. The challenger simulates honest
parties' contributions to $\Sign(\mu, T)$ and returns the full
transcript including the final FIPS~204 signature $\sigma$.
\item Exposes a $\mathcal{H}_{\mathsf{RO}}$ oracle for all FIPS~202 / SP~800-185 hash
calls.
\end{enumerate}
The adversary outputs a forgery $(\mu^*, \sigma^*)$. $\mathcal{A}$
wins if:
\begin{enumerate}[label=(\roman*), leftmargin=*, itemsep=0pt]
\item $\texttt{ML-DSA.Verify}(\mathit{pk}, \mu^*, \sigma^*) = \mathit{accept}$,
\item $\mathcal{A}$ did not query $\mathcal{O}_{\Sign}(\mu^*, \cdot)$ with
the same $\mu^*$ producing $\sigma^*$, and
\item $|\mathcal{C}| \le t-1$ (the corruption budget was respected).
\end{enumerate}
$\mathcal{A}$'s advantage is
$\Adv^{\mathsf{TS\textsf{-}UF}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A}) = \Pr[\mathcal{A} \text{ wins}]$.
\end{game}
\begin{theorem}[TS-UF security]
\label{thm:tsuf}
For every $\PPT$ adversary $\mathcal{A}$ against \Cref{game:tsuf} with
$q_S$ signing queries and $q_H$ random-oracle queries, there exist
efficient reductions $\mathcal{B}_{\MLWE}, \mathcal{B}_{\MSIS},
\mathcal{B}_{\mathrm{ML\text{-}DSA}}$ such that
\[
\Adv^{\mathsf{TS\textsf{-}UF}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A})
\;\le\;
\Adv^{\MLWE}_{q, k, \ell, \eta}(\mathcal{B}_{\MLWE})
+ \Adv^{\MSIS}_{q, k, 2\ell, \beta_{\mathrm{bind}}}(\mathcal{B}_{\MSIS})
+ \Adv^{\mathsf{EUF\textsf{-}CMA}}_{\mathrm{ML\text{-}DSA}}(\mathcal{B}_{\mathrm{ML\text{-}DSA}})
+ \frac{q_S \cdot q_H}{2^\lambda}.
\]
\end{theorem}
\begin{proof}[Proof sketch]
We argue via a sequence of hybrids:
\paragraph{Hybrid $H_0$.} The real TS-UF experiment.
\paragraph{Hybrid $H_1$.} The challenger simulates the $\Sign$ oracle
without using the honest parties' shares. Specifically, the
simulator chooses the final signature $\sigma = (\tilde c, \mathbf{z},
\mathbf{h})$ by running \texttt{ML-DSA.Sign} against $\mathit{pk}$
\emph{as if it knew the secret key}, then programs the per-party
transcript so the aggregation lands on the chosen $\sigma$. The
honest-party Round-1 commits are set to $\mathbf{w}_j^{(\mathrm{sim})} =
\mathbf{A}\mathbf{y}_j^{(\mathrm{sim})}$ for simulated masks $\mathbf{y}_j^{(\mathrm{sim})}$
drawn uniformly under the $U_{\gamma_1}$ constraint and consistent with
the chosen $\mathbf{z}$ via
$\sum_j \mathbf{y}_j^{(\mathrm{sim})} = \mathbf{z} - c\mathbf{s}_1$.
Random-oracle programming sets the $\bar{\mathbf{w}}$-derived challenge to
the chosen $\tilde c$. The distinguishing advantage between $H_0$
and $H_1$ is bounded by $q_S \cdot q_H / 2^\lambda$ (probability of a
collision in the RO programming).
\paragraph{Hybrid $H_2$.} The challenger replaces the Pedersen commit
matrix $\mathbf{B}$'s structure --- $\mathbf{B}$ is now a fresh
uniform matrix \emph{independent} of $\mathbf{A}$. This is identical
to $H_1$ because $\mathbf{B}$ was already derived from a separate
domain-separated seed in the construction; the hybrid is a no-op
distributionally and is included only for proof clarity.
\paragraph{Hybrid $H_3$.} The challenger replaces the DKG-time
Pedersen blinding $\mathbf{u}$ with a uniform sample from $\Rq^\ell$
(rather than $\chi_\eta^\ell$). Distinguishing advantage is bounded
by $\Adv^{\MLWE}_{q, k, \ell, \eta}(\mathcal{B}_{\MLWE})$ via the
hiding property of the Pedersen commitment
(\Cref{thm:pedersen-hiding}).
\paragraph{Hybrid $H_4$ (reduction to ML-DSA EUF-CMA).} In $H_4$ the
simulator obtains $\mathit{pk}$ from a single-party ML-DSA EUF-CMA
challenger; it answers $\mathcal{O}_{\Sign}(\mu, T)$ queries by
relaying the signing query to the ML-DSA challenger and using $H_1$'s
simulator to expand the resulting $\sigma$ into a per-party
transcript. Any adversary that wins TS-UF against this hybrid
produces a forgery $(\mu^*, \sigma^*)$ that wins the ML-DSA EUF-CMA
game (since the Pulsar-M $\Verify$ is unmodified ML-DSA
$\Verify$). Distinguishing advantage between $H_3$ and $H_4$ is
absorbed into the MSIS binding term: any deviation by the simulator
from the honest-party transcript shape is detected by binding of the
Pedersen commitment, contributing
$\Adv^{\MSIS}_{q, k, 2\ell, \beta_{\mathrm{bind}}}(\mathcal{B}_{\MSIS})$.
Summing the hybrid advantages gives the bound. \qed
\end{proof}
\begin{remark}[Tightness]
The reduction is tight modulo the standard $q_S q_H / 2^\lambda$
random-oracle programming penalty. For ML-DSA-65 ($\lambda = 192$),
this term is negligible for any practical $(q_S, q_H)$. The MSIS
term governs the Pedersen-binding side of the argument; the MLWE
term governs the hiding side; the ML-DSA term governs the underlying
single-party unforgeability. Pulsar-M inherits ML-DSA's EUF-CMA
bound verbatim modulo these threshold-protocol-specific terms.
\end{remark}
% =====================================================================
\subsection{Game OUT-IND (output indistinguishability from FIPS~204)}
\label{sec:game-outind}
% =====================================================================
\begin{game}[OUT-IND]
\label{game:outind}
The challenger flips a fair bit $b \in \{0, 1\}$ at setup and exposes
two oracles to $\mathcal{A}$:
\begin{itemize}[leftmargin=*, itemsep=0pt]
\item If $b = 0$: $\DKG$ produces $\mathit{pk}$ honestly, and
$\mathcal{O}_{\Sign}(\mu, T)$ runs Pulsar-M $\Sign$ honestly and
returns only the final $\sigma$ (transcript is hidden).
\item If $b = 1$: $\mathit{pk}$ is generated by single-party
\texttt{ML-DSA.KeyGen}, and $\mathcal{O}_{\Sign}(\mu, T)$ ignores the
quorum $T$ and runs single-party \texttt{ML-DSA.Sign}, returning
$\sigma$.
\end{itemize}
$\mathcal{A}$ outputs a guess $\hat b$. Advantage:
$\Adv^{\mathsf{OUT\textsf{-}IND}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A})
= |\Pr[\hat b = b] - 1/2|$.
\end{game}
\begin{theorem}[Output indistinguishability]
\label{thm:outind}
For every $\PPT$ adversary $\mathcal{A}$ against \Cref{game:outind},
\[
\Adv^{\mathsf{OUT\textsf{-}IND}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A})
\;\le\;
\Adv^{\MLWE}_{q, k, \ell, \eta}(\mathcal{B}_{\MLWE}) +
\frac{1}{2^{2\lambda}}.
\]
\end{theorem}
\begin{proof}[Proof sketch]
\textbf{$\mathit{pk}$ indistinguishability.}
A FIPS~204 public key is $\mathit{pk}_{\mathrm{F}} = (\rho, \Power(\mathbf{A}\mathbf{s}_1 + \mathbf{s}_2, d))$ with $\mathbf{s}_1, \mathbf{s}_2 \gets \chi_\eta$.
A Pulsar-M public key is $\mathit{pk}_{\mathrm{P}} = (\rho, \Power(\mathbf{A}\mathbf{s}_1 + \mathbf{B}\mathbf{u}, d))$ with $\mathbf{s}_1, \mathbf{u} \gets \chi_\eta$ (centred binomial) and $\mathbf{B}$ uniform.
The two distributions are identical except in the $\mathbf{s}_2$ vs.\ $\mathbf{B}\mathbf{u}$ component. Under $\MLWE_{q, k, \ell, \eta}$ in $\mathbf{B}$, $\mathbf{B}\mathbf{u}$ is computationally indistinguishable from a uniform $\mathbf{w} \in \Rq^k$; conditioned on uniformity, the post-$\Power$ projection is uniform over the range of $\Power$. Single-party ML-DSA's $\mathbf{s}_2 \sim \chi_\eta^k$ also projects through $\Power$ to a distribution that is statistically close to uniform over the $\Power$ image. The total distance between the two $\mathit{pk}$ distributions is therefore bounded by $\Adv^{\MLWE}_{q, k, \ell, \eta}(\mathcal{B}_{\MLWE})$ plus a negligible statistical term from the $\Power$ rounding.
\textbf{$\sigma$ indistinguishability.}
By correctness (\Cref{thm:sign-correct}), the Pulsar-M aggregated
$\sigma$ is the FIPS~204 signature on $(\mathit{pk}, \mu, \mathbf{y})$ where $\mathbf{y} = \sum_j \mathbf{y}_j$ is the aggregated mask. The marginal distribution of $\mathbf{y}$ (sum of $t$ uniform-interval samples) is a discrete convolution; FIPS~204's single-party mask is a single uniform-interval sample. The two distributions differ in their concentration profile but are projected through the rejection-sampling acceptance condition $\|\mathbf{z}\|_\infty < \gamma_1 - \beta$, which forces the accepted distribution into the same FIPS~204 acceptance region. Conditioned on acceptance, the per-coordinate distribution of $\mathbf{z}$ is uniform on $[-\gamma_1 + \beta + 1, \gamma_1 - \beta - 1]$ in both cases (this is the FIPS~204 rejection-sampling invariant). Therefore the post-rejection distribution is identical between Pulsar-M and FIPS~204, and the output $\sigma$ is distributionally identical given the same $\tilde c$ and $\mathbf{h}$.
The statistical term $1/2^{2\lambda}$ accounts for the negligible
probability of a $\tilde c$ collision in the RO. \qed
\end{proof}
\begin{remark}[Caveat on signature byte equality]
\Cref{thm:outind} states distributional equivalence. For \emph{byte
equality} on a specific signature, the Pulsar-M $\Sign$
implementation MUST emit exactly the FIPS~204 byte encoding of
$(\tilde c, \mathbf{z}, \mathbf{h})$ with the same canonicalisation
(coefficient lifting, sign convention, packing). This is an
implementation-level requirement, not a cryptographic theorem; the
encoding section (\S\ref{sec:encodings}) pins it. The byte-equality
property is what unlocks Class~N1.
\end{remark}
% =====================================================================
\subsection{Game ROB (robustness / identifiable abort)}
\label{sec:game-rob}
% =====================================================================
\begin{game}[ROB]
\label{game:rob}
$\mathcal{A}$ corrupts up to $t-1$ parties and chooses one of the
following deviation strategies:
\begin{enumerate}[label=(\alph*), leftmargin=*, itemsep=0pt]
\item Send distinct DKG commit vectors to distinct recipients (equivocation).
\item Send a private DKG share that fails Pedersen verification.
\item Send a Round-1 sign commit with an invalid MAC.
\item Send a Round-2 sign response that, combined with honest contributions, would push the aggregate $\mathbf{z}$ outside the FIPS~204 norm.
\item Refuse to participate at any round boundary.
\end{enumerate}
$\mathcal{A}$ wins if any honest party either (i) completes the
protocol against the deviation \emph{without} producing a valid
complaint identifying a corrupted deviator, or (ii) the honest
party's resulting state is inconsistent with at least one other
honest party's state (no recovery).
\end{game}
\begin{theorem}[Robustness]
\label{thm:rob}
For every $\PPT$ adversary $\mathcal{A}$ against \Cref{game:rob}, the
honest parties either produce a valid \textsc{Complaint}
record identifying a corrupted deviator, or successfully complete
the protocol. Formally,
$\Adv^{\mathsf{ROB}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A})$ is
bounded by the signature-forgery advantage on the parties' long-term
identity-key scheme (e.g.\ Ed25519) plus
$\Adv^{\MSIS}_{q, k, 2\ell, \beta_{\mathrm{bind}}}(\mathcal{B}_{\MSIS})$ for
deviation~(a),
plus the random-oracle collision term $q_H / 2^{256}$ for the
commit-digest binding.
\end{theorem}
\begin{proof}[Sketch]
For deviation (a), the Round-1.5 commit digest broadcast by every
honest recipient binds each sender to one commit vector across the
cohort (under collision-resistance of $\cSHAKE$). Two distinct
commits would produce two distinct digests, observable to every
recipient as a digest mismatch; the recipient signs a
\textsc{ComplaintEquivocation} carrying the two signed broadcasts as
evidence. The signature soundness of the accused party's long-term
identity key prevents the accused from repudiating its own
broadcasts; forging two broadcasts requires breaking the identity
signature.
For deviation (b), the Pedersen identity check
(\Cref{thm:pedersen-binding}) fails with probability $1 - \negl$ if
$\mathcal{A}$ deviates from a valid (share, blind, commit) triple.
The failing recipient signs a \textsc{ComplaintBadDelivery}
carrying the triple as evidence; the complaint is verifiable by any
third party because the public Pedersen check is determined by
$(\mathbf{A}, \mathbf{B})$.
For deviations (c), (d), (e): MAC verification, Round-2 norm
verification (against the public broadcast of $\bar{\mathbf{w}}_i,
\mathbf{z}_i, \mathbf{r}_i$), and round-window timeouts respectively
produce \textsc{ComplaintMACFailure}, \textsc{ComplaintRangeFailure},
\textsc{ComplaintTimeout} records, signed by the detecting party. Each
complaint is publicly verifiable from the transcript and the
accuser's identity-key signature. \qed
\end{proof}
% =====================================================================
\subsection{Game ADAPT (adaptive corruption)}
\label{sec:game-adapt}
% =====================================================================
\begin{game}[ADAPT]
\label{game:adapt}
Identical to \Cref{game:tsuf} except $\mathcal{A}$ may issue
\emph{adaptive} corruption queries: at any point during the protocol
execution, $\mathcal{A}$ chooses a previously-honest party $i$ to
corrupt; the challenger reveals party $i$'s entire current state
including secret share, current per-round randomness, and PRNG
seeds. The total number of corrupted parties at any time is bounded
by $t-1$.
\end{game}
\begin{theorem}[Adaptive corruption --- sketch only]
\label{thm:adapt-sketch}
\emph{Statement deferred to round-2 MPTC.} A formal
adaptive-corruption proof requires either (i) a complexity-leveraging
argument that loses a $\binom{n}{t-1}$ factor in the security
parameter and is therefore loose for practical $(n, t)$, or (ii) a
trapdoor-based simulation argument compatible with the Pedersen
commit structure. \cite{corona2024} sketches direction (i) for the
Ring-LWE setting; the module-shaped adaptation is structural but
non-trivial.
\end{theorem}
\begin{openq}[Adaptive corruption]
Tight adaptive corruption for module-shaped two-round
threshold lattice signatures is an open research question. Pulsar-M
defers a formal proof to round 2; under the static-corruption model
\Cref{thm:tsuf} suffices for round 1.
\end{openq}
% =====================================================================
\subsection{Game MOB (mobile-adversary security, proactive resharing)}
\label{sec:game-mob}
% =====================================================================
\begin{game}[MOB]
\label{game:mob}
Multi-epoch experiment with epoch counter $e \in \{1, 2, \dots, E\}$.
At each epoch $e$:
\begin{enumerate}[leftmargin=*, itemsep=0pt]
\item $\mathcal{A}$ chooses a corruption set $\mathcal{C}_e \subseteq \{1, \dots, n\}$ with $|\mathcal{C}_e| \le t-1$. Corruptions are independent across epochs: a party in $\mathcal{C}_e \cap \mathcal{C}_{e+1}$ is corrupted across both epochs, but a party in $\mathcal{C}_e \setminus \mathcal{C}_{e+1}$ \emph{uncorrupts} between epochs (forgets its epoch-$e$ secrets but retains its identity-key state).
\item The challenger reveals the epoch-$e$ shares and per-round randomness of every party in $\mathcal{C}_e$.
\item $\mathcal{A}$ may issue $\mathcal{O}_{\Sign}$ queries within the epoch.
\item At the epoch boundary, the challenger runs $\Reshare$ honestly with a fresh beacon $\beta_{e+1}$. The beacon is unbiasable: $\mathcal{A}$ sees $\beta_{e+1}$ \emph{after} committing to $\mathcal{C}_{e+1}$.
\end{enumerate}
At the end of epoch $E$, $\mathcal{A}$ outputs a forgery
$(\mu^*, \sigma^*)$. $\mathcal{A}$ wins under the TS-UF winning
condition.
\end{game}
\begin{theorem}[Mobile-adversary security]
\label{thm:mob}
For every $\PPT$ adversary $\mathcal{A}$ against \Cref{game:mob} over
$E$ epochs,
\[
\Adv^{\mathsf{MOB}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A})
\;\le\;
E \cdot \Adv^{\mathsf{TS\textsf{-}UF}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{B})
+ E \cdot \Adv^{\mathsf{beacon\textsf{-}unbias}}_{\mathrm{chain}}(\mathcal{B}_{\mathrm{beacon}}) +
E \cdot \Adv^{\MLWE}_{q, k, \ell, \eta}(\mathcal{B}_{\MLWE}).
\]
\end{theorem}
\begin{proof}[Proof sketch]
The proof proceeds by induction on epochs. The base case $e = 1$ is
TS-UF directly. For the inductive step, assume the master secret
$\mathbf{s}_1$ is hidden from $\mathcal{A}$ through epoch $e$. At the
epoch boundary:
\begin{enumerate}[leftmargin=*, itemsep=0pt]
\item The reshare quorum $\mathcal{Q}_{e+1}$ is selected from the
beacon $\beta_{e+1}$. Under the beacon-unbiasability assumption, the
event \(\mathcal{Q}_{e+1} \cap \mathcal{C}_{e+1}\) is a uniform random
sample from the size-$(t_{\mathrm{old}})$ subsets of $\mathcal{O}$;
the probability that $\mathcal{A}$'s
$|\mathcal{C}_{e+1}| \le t-1$ corruption covers $\mathcal{Q}_{e+1}$ entirely
is at most
$\binom{t-1}{t}\binom{n}{t}^{-1} = 0$ (corruption budget is strictly less than $t$).
\item By \Cref{thm:reshare-pkinv}, $\mathit{pk}$ is invariant.
\item By the resharing privacy theorem
(\Cref{thm:reshare-priv} below), the joint view of $\mathcal{A}$
across $(\mathcal{C}_e, \mathcal{C}_{e+1})$ is independent of the
master secret $\mathbf{s}_1$.
\item Forgery in epoch $e+1$ reduces to TS-UF in epoch $e+1$ against
the (independently distributed) new committee shares.
\end{enumerate}
The union bound over $E$ epochs gives the stated advantage. \qed
\end{proof}
% =====================================================================
\subsection{Games DKG-SOUND and DKG-PRIV}
\label{sec:game-dkg}
% =====================================================================
\begin{game}[DKG-SOUND]
\label{game:dkg-sound}
$\mathcal{A}$ corrupts up to $t-1$ parties at DKG start. The
challenger runs $\DKG$ honestly across the remaining parties;
$\mathcal{A}$'s corrupted parties act under its control.
$\mathcal{A}$ wins if the output $\mathit{pk}$ is \emph{not} a valid
FIPS~204 public key (i.e., it does not deserialise correctly, or it
does not satisfy the FIPS~204 public-key range checks).
\end{game}
\begin{theorem}[DKG soundness]
\label{thm:dkg-sound}
For every $\PPT$ adversary,
$\Adv^{\mathsf{DKG\textsf{-}SOUND}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A}) \le \Adv^{\MSIS}_{q, k, 2\ell, \beta_{\mathrm{bind}}}(\mathcal{B}_{\MSIS}) + q_H / 2^{256}$.
\end{theorem}
\begin{proof}[Sketch]
Honest parties verify Pedersen identities at Round~2. A corrupted
party that contributes a malformed share triggers
\textsc{ComplaintBadDelivery}, removing its contribution from the
aggregation. The remaining honest contributions are
$\chi_\eta$-distributed, so $\mathbf{s}_1 = \sum_{i \in \mathcal{H}}
\mathbf{c}_{i,0}$ has a distribution that is statistically close to
$\chi_\eta^\ell$ scaled by $|\mathcal{H}|$ (which we re-randomise to
$\chi_\eta^\ell$ via the FIPS~204 secret-key sampling discipline).
The Pedersen binding bound prevents the adversary from substituting a
different $\mathbf{c}_{i,0}$ between commit and reveal. The remaining
RO term is the random-oracle collision bound for the commit-digest
binding. \qed
\end{proof}
\begin{game}[DKG-PRIV]
\label{game:dkg-priv}
$\mathcal{A}$ corrupts up to $t-1$ parties and runs $\DKG$ honestly;
the challenger flips a bit $b$. If $b = 0$, $\mathcal{A}$ sees the
real DKG transcript including the corrupted parties' shares. If
$b = 1$, the challenger simulates the corrupted parties' shares from
the public $\mathit{pk}$ using a $\Sigma$-protocol-style simulator
that re-randomises the commits without knowledge of the honest
secrets. $\mathcal{A}$ outputs a guess $\hat b$.
\end{game}
\begin{theorem}[DKG share privacy]
\label{thm:dkg-priv}
$\Adv^{\mathsf{DKG\textsf{-}PRIV}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A}) \le \Adv^{\MLWE}_{q, k, \ell, \eta}(\mathcal{B})$.
\end{theorem}
\begin{proof}[Sketch]
The Pedersen commitments are computationally hiding
(\Cref{thm:pedersen-hiding}). The simulator chooses corrupted-party
shares uniformly from the simulation distribution induced by
$\mathit{pk}$, then programs the commits via the Pedersen-hiding
simulator. Distinguishing real from simulated commits reduces to
$\MLWE$. \qed
\end{proof}
% =====================================================================
\subsection{Games RESHARE-SOUND and RESHARE-PRIV}
\label{sec:game-reshare}
% =====================================================================
\begin{game}[RESHARE-SOUND]
\label{game:reshare-sound}
$\mathcal{A}$ has corrupted up to $t-1$ parties of the old
committee and up to $t-1$ of the new committee. The challenger runs
$\Reshare$ with an honest beacon. $\mathcal{A}$ wins if the new
committee's resulting shares do \emph{not} reconstruct to
$\mathbf{s}_1$ via Lagrange interpolation at $X = 0$.
\end{game}
\begin{theorem}[Reshare soundness]
\label{thm:reshare-sound}
$\Adv^{\mathsf{RESHARE\textsf{-}SOUND}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A}) \le \Adv^{\MSIS}_{q, k, 2\ell, \beta_{\mathrm{bind}}}(\mathcal{B})$.
\end{theorem}
\begin{proof}[Sketch]
The reshare polynomials $g_i, h_i$ commit to constant terms
$\lambda_i^{\mathcal{Q}_e} \mathbf{s}_i, \lambda_i^{\mathcal{Q}_e} \mathbf{u}_i$
under Pedersen commit. Pedersen binding prevents a deviating
$i \in \mathcal{Q}_e \cap \mathcal{C}$ from substituting a different
constant term. The remaining honest parties' constant terms sum
under Lagrange interpolation to $\mathbf{s}_1$ exactly
(\Cref{thm:reshare-pkinv}). Therefore the master secret is preserved
modulo binding. \qed
\end{proof}
\begin{game}[RESHARE-PRIV]
\label{game:reshare-priv}
$\mathcal{A}$ corrupts up to $t-1$ parties of $\mathcal{O}$ and up to
$t-1$ of $\mathcal{N}$ (allowing distinct corruption sets per epoch,
matching the mobile adversary model). The challenger runs $\Reshare$
honestly with an honest beacon. $\mathcal{A}$ outputs a guess for
$\mathbf{s}_1$. Advantage = probability of correct guess.
\end{game}
\begin{theorem}[Reshare share privacy]
\label{thm:reshare-priv}
For an unbiased beacon $\beta_e$,
$\Adv^{\mathsf{RESHARE\textsf{-}PRIV}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A}) \le \Adv^{\MLWE}_{q, k, \ell, \eta}(\mathcal{B}) + \Adv^{\mathsf{beacon\textsf{-}unbias}}_{\mathrm{chain}}(\mathcal{B}_{\mathrm{beacon}}) + q^{-1}$.
\end{theorem}
\begin{proof}[Sketch]
The old committee's leaked shares $\{\mathbf{s}_i\}_{i \in
\mathcal{C}_{\mathrm{old}}}$ alone leak no information about
$\mathbf{s}_1$ by Shamir security. The new shares
$\{\mathbf{s}'_j\}_{j \in \mathcal{C}_{\mathrm{new}}}$ similarly leak
nothing on their own. The cross-leakage from the dealing step
contributes $\{g_i(j) : i \in \mathcal{Q}_e, j \in
\mathcal{C}_{\mathrm{new}}\}$. Conditioned on $\mathbf{s}_i$ (which
$\mathcal{A}$ already knows if $i \in \mathcal{C}_{\mathrm{old}}$,
otherwise hidden), the distribution of $g_i(j)$ for $|\{j\}| < t_{\mathrm{new}}$ is uniform in $\Rq^\ell$ by the high-degree
random coefficients of $g_i$; therefore the dealing-step view admits
a simulator that draws the leaked $g_i(j)$ values uniformly without
knowing $\mathbf{s}_1$.
The beacon-unbiasability assumption ensures
$\mathcal{Q}_e \cap \mathcal{C}_{\mathrm{old}}$ is a fresh uniform
sample with respect to $\mathbf{s}_1$, preventing adversarial gaming
of the quorum.
The $q^{-1}$ term is the negligible probability that a Lagrange
denominator collides in the beacon-induced ordering. \qed
\end{proof}
% =====================================================================
\subsection{Game RESTART-NL (rejection-restart non-leakage)}
\label{sec:game-restart-nl}
% =====================================================================
We re-state \Cref{thm:restart-non-leak} from the main text as an
explicit game for completeness and so the reduction to $\KMAC$'s
PRF security is recorded alongside the other games.
\begin{game}[RESTART-NL]
\label{game:restart-nl}
$\mathcal{A}$ corrupts up to $t-1$ parties of a fixed quorum $T$.
The challenger runs $\Sign$ on a fixed honest target $(\mathit{pk}, \mu, T)$.
$\mathcal{A}$ requests $K$ distinct rejection-restart attempts
(distinct $\kappa = 1, \dots, K$); the challenger executes each
attempt and reveals the full per-attempt transcript. $\mathcal{A}$
outputs a guess for $\mathbf{s}_i$ for some honest party $i \in T
\setminus \mathcal{C}$.
\end{game}
\begin{theorem}[Restart non-leakage]
\label{thm:restart-nl-game}
For every $\PPT$ adversary against \Cref{game:restart-nl},
\[
\Adv^{\mathsf{RESTART\textsf{-}NL}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A})
\;\le\;
K \cdot \Adv^{\mathsf{PRF}}_{\KMAC}(\mathcal{B})
+ \Adv^{\mathsf{TS\textsf{-}UF}}_{\mathrm{Pulsar\text{-}M}}(\mathcal{A}').
\]
\end{theorem}
The proof is the hybrid argument of the main-text
\Cref{thm:restart-non-leak} restated formally. The cross-message
extension --- replacing the fixed $\mu$ with adversarially-chosen
$\mu^{(\kappa)}$ between restarts --- is recorded as open in
\S\ref{sec:knownlimits}.
% =====================================================================
\subsection{Summary of reductions}
\label{sec:sec-summary}
% =====================================================================
\begin{center}
\begin{tabular}{l l}
\toprule
game & reduction target \\
\midrule
TS-UF (static unforgeability) & $\MLWE_{q,k,\ell,\eta}$ + $\MSIS_{q,k,2\ell,\beta_{\mathrm{bind}}}$ + EUF-CMA(ML-DSA) \\
OUT-IND (FIPS~204 interchangeability) & $\MLWE_{q,k,\ell,\eta}$ \\
ROB (identifiable abort) & Pedersen binding ($\MSIS$) + Ed25519 signature soundness \\
ADAPT (adaptive corruption) & open --- deferred to round-2 \\
MOB (mobile-adversary) & TS-UF + RESHARE-PRIV + beacon unbiasability \\
DKG-SOUND & $\MSIS$ + RO collision \\
DKG-PRIV & $\MLWE$ \\
RESHARE-SOUND & $\MSIS$ \\
RESHARE-PRIV & $\MLWE$ + beacon unbiasability \\
RESTART-NL (rejection-restart) & PRF($\KMAC$) + TS-UF \\
\bottomrule
\end{tabular}
\end{center}
The dominant terms across all games are $\MLWE_{q, k, \ell, \eta}$
and ML-DSA EUF-CMA, both of which take the FIPS~204
parameter-pinned values (see \S\ref{sec:parameters}). Pulsar-M
inherits ML-DSA's security level modulo the threshold-protocol
overhead, which is dominated by the Pedersen-binding $\MSIS$ term
and the random-oracle programming penalty.
\paragraph{Forward-security note.}
The MOB game (\Cref{game:mob}) implies forward security at the epoch
granularity: revealing all shares at epoch $e$ leaks no information
about $\mathbf{s}_1$ in epoch $e' > e$ provided fewer than $t-1$
parties have leaked their epoch-$e'$ shares. Combined with $\Reshare$
at the epoch boundary, this gives the standard
proactive-secret-sharing forward-security guarantee.
+46
View File
@@ -0,0 +1,46 @@
% Pulsar-M system model — included by pulsar-m.tex §"System model"
\section*{System model}
% TODO. Cover:
%
% Network model
% - synchronous vs asynchronous (Pulsar-M assumes synchronous broadcast
% within the round window; partially-synchronous is future work)
% - broadcast channel: authenticated, eventual delivery
% - point-to-point channel: authenticated, encrypted
% - public bulletin: authenticated, append-only (consensus-anchored)
%
% Setup assumptions
% - PKI: each party has a long-term verification key advertised on the
% public bulletin (e.g. lux/consensus identity record per HIP-0077)
% - Random beacon: shared randomness oracle for reshare quorum selection
% (lux consensus randomness layer)
%
% Trust model
% - Up to t-1 corrupted parties (static), t-1 per epoch (mobile)
% - Honest majority of (n - t + 1) needed for liveness
%
% Abort model
% - Identifiable abort: protocol surfaces a signed complaint when a
% deviation is detected, with the deviating party ID
% - Slashing: governance layer consumes complaints (out of scope here)
%
% Preprocessing
% - DKG runs once per validator-set epoch
% - Reshare runs at epoch boundary (typical cadence: hours to days)
% - Sign runs per-message; preprocessing-free if combined with non-cached
% sampler, or with optional Round-0 mask precomputation per Pulsar's
% offline/online split
%
% Rotation
% - Reshare protocol updates shares without changing pk (per HJKY97)
% - Members may join / leave between epochs subject to (n', t') constraint
%
% Monitoring
% - Public artifacts: pk, commitments, signed complaints, signature outputs
% - Private artifacts: shares, blinds, masks, samples — never logged
%
% Deployment surface
% - Reference assumes pure software
% - HSM integration is future work (out of scope for round 1 MPTC)
View File
View File
View File
+46
View File
@@ -0,0 +1,46 @@
# Test vectors
Two formats per NIST MPTC submission norms:
- `kat-v1.json` — input/output vectors per MPTC §IO-Testing. Each entry
is a single threshold ceremony with full `(n, t, party_seeds,
public_params, shares, commitments, preprocessing_transcript, message,
per_party_messages, final_signature, verify_result, abort_evidence)`.
- `kat-v1.rsp` — CAVS-style response file for compatibility with
legacy ACVP-inspired tooling. One signature per stanza, deterministic
from a 48-byte seed.
`transcripts/` holds full-protocol KATs for `(n, t)` sweeps —
`transcripts/n3-t2.jsonl`, `transcripts/n7-t5.jsonl`, etc. — each line
a complete protocol run.
## Cross-validation against FIPS 204
The headline interchangeability claim (Class N1) requires every
`final_signature` in `kat-v1.json` to verify against unmodified FIPS 204
`ML-DSA.Verify(pk, message, signature)` returning `accept`. The
cross-validation harness at `test/interoperability/` runs each KAT
through:
- the reference implementation in `ref/go/`
- the FIPS 204 reference (Dilithium pq-crystals C reference)
- a third independent ML-DSA implementation (BoringSSL FIPS or
OpenSSL 3.0 PQ provider, whichever is available)
A KAT mismatch with any of the three is a release blocker.
## Determinism
Every entry in `kat-v1.json` is reproducible from `master_seed` (a
48-byte hex value at the head of the file). `scripts/gen_vectors.sh`
must produce byte-identical output on any fresh checkout. Drift here
is a CI failure.
## Status
- [ ] KAT generator (`ref/go/cmd/genkat`) — implementation pending
- [ ] First v1 KAT set
- [ ] FIPS 204 cross-validation
- [ ] Independent-impl cross-validation
- [ ] Encoded into `vectors/transcripts/` for `(n, t) ∈ {(3,2), (5,3), (7,5), (10,7), (16,11), (32,21)}`
View File