Single repo, one canonical impl + spec + proofs + KAT + cut tool.
Per "ONE and ONLY ONE way to do things" the prior dual-repo split
(luxfi/pulsar = production library, luxfi/pulsar-mptc = NIST MPTC
submission framework) is collapsed into a single canonical home at
github.com/luxfi/pulsar. SINGLE-IMPL-PLAN.md (now marked COMPLETED)
describes the steps; this commit lands the final step.
Files moved (89 new):
16 submission docs (SUBMISSION, NIST-SUBMISSION, SPEC, SUITE,
PATENTS, AXIOM-INVENTORY, PROOF-CLAIMS, FIPS-TRACEABILITY,
TRUSTED-COMPUTING-BASE, HANZO-CRYPTO-SUITE, INFORMATION-
ARCHITECTURE, ROADMAP, CHANGELOG, SYNC-STATUS, STATUS-
SUBMISSION-READINESS, SINGLE-IMPL-PLAN)
10 docs/ supplements (ietf-draft-skeleton, magnetar, evaluation,
patent-claims, x-wing-sig, design-decisions, family-architecture,
threat-model, nist-mptc-category, patent-notes-draft)
19 proofs/ (13 EC theories + 2 EC lemmas + 4 metadata/READMEs +
lean-easycrypt-bridge.md)
14 jasmin/ (lib/* + ml-dsa-65 fetch + threshold/{combine,round1,
round2}.jazz + READMEs)
10 ct/dudect/ (Makefile, combine_ct.go, dudect_combine.c,
dudect_compat.h, dudect_verify.c, fetch.sh, README, run-
submission.sh, verify_ct.go) + ct/jasmin-ct-libjade.md
1 .github/workflows/ci.yml
1 test/interoperability/n1_class_test.go (19/19 N1 subtests)
1 bench/results/REPORT.md
11 scripts/ (cut-submission, check-high-assurance, check-lean-
bridge, nightly, extract-jasmin-ec, checks/{ec-admits, ec-
compile, ec-refinement-scaffold, ec-regressions, extraction,
jasmin}, checks/test/{go-unit, interop, kat, no-secret-logs})
Files merged (16 overlapping, mptc-canonical chosen because newer +
post-rewire-correct; pulsar versions still bore stale "Pulsar-M" /
"pulsarm" branding):
README.md, BLOCKERS.md, CONTRIBUTING.md, LICENSE, LICENSING.md,
SECURITY.md, .gitignore, bench/run_all.sh, vectors/dkg.json (v1.0.7
regen), scripts/{bench,build,gen_vectors,sbom,test}.sh,
spec/{pulsar,parameters,system-model}.tex,
CRYPTOGRAPHER-SIGN-OFF.md (path refs).
Pulsar-only spec supplements preserved:
spec/{blockers,design-decisions,family-architecture,nist-mptc-
category,patent-notes,threat-model}.tex.
Path rewrites applied: 158 occurrences across 26 files
github.com/luxfi/pulsar-mptc -> github.com/luxfi/pulsar
~/work/lux/pulsar-mptc/ -> ~/work/lux/pulsar/
luxfi/pulsar-mptc -> luxfi/pulsar
pulsar-mptc/ -> ./
Narrative collapses (no more two-repo framing):
SUBMISSION.md "At a glance" — single Repository row
SYNC-STATUS.md — rewritten to single-repo state
SINGLE-IMPL-PLAN.md — marked COMPLETED 2026-05-18
HANZO-CRYPTO-SUITE.md — tier 1 row = single canonical home
scripts/cut-submission.sh — replace/vendor dance removed; cuts
directly from in-tree canonical sources
go.mod: dropped mptc's replace directive (no longer needed since this
IS the canonical pulsar repo). Module path is github.com/luxfi/pulsar.
Deps: cloudflare/circl v1.6.3, golang.org/x/crypto v0.32.0.
Verification:
GOWORK=off go build ./... PASS
GOWORK=off go test -count=1 ./... PASS (1.4s)
GOWORK=off go test -race ./ref/... PASS (14.7s)
go test ./test/interoperability/ PASS (19/19 N1 subtests)
scripts/check-high-assurance.sh PASS
scripts/check-lean-bridge.sh PASS (5/5 bridges)
scripts/gen_vectors.sh byte-identical replay
scripts/cut-submission.sh --help PASS
12 KiB
Experimental evaluation — Pulsar v0.1
NIST MPTC Report on Experimental Evaluation (per NIST IR 8214C §6). This document synthesises performance, correctness, side-channel, and security-parameter evidence into a single reviewer-facing report.
Raw benchmark output:
bench/results/REPORT.md+bench/results/go-bench.txt. Constant-time analysis:ct/dudect/README.md. Test-vector cross-validation:vectors/README.md+test/interoperability/. Security parameter estimator:estimator/README.md.
§1 Methodology
§1.1 Performance benchmarks
- Platform: Apple M1 Max, 10 cores, 64 GiB RAM, Darwin 25.4.0
- Toolchain: Go 1.26.2 darwin/arm64, default
go buildflags - Methodology: median of three runs,
go test -bench=. -benchmem - Reproduce:
scripts/bench.shfrom a fresh clone - Raw data:
bench/results/go-bench.txt
§1.2 Correctness (KAT cross-validation)
- Reference implementation:
ref/go/pkg/pulsar/(Apache-2.0) - Cross-validation peers (3 independent ML-DSA-65 implementations):
- pq-crystals Dilithium-3 C reference (NIST PQC round-3 reference)
cloudflare/circlML-DSA-65 (single-party, FIPS 204-conformant)- BoringSSL FIPS / OpenSSL 3.0 PQ provider (when available at test time)
- Test vectors:
vectors/(5 JSON sets covering DKG, keygen, sign, threshold-sign, verify) + per-(n,t) transcripts invectors/transcripts/ - Harness:
test/interoperability/n1_class_test.go
§1.3 Constant-time analysis
- Static analyzer:
jasmin-cton the Jasmin threshold layer (jasmin/threshold/{round1,round2,combine}.jazz) - Dynamic analyzer:
dudectat 10⁹ samples per target (nightly gate viascripts/nightly.sh) - Allowed-failure: libjade ML-DSA-65 sign (jasmin-ct issue #2,
documented in
ct/jasmin-ct-libjade.md)
§1.4 Security parameter estimation
- Tool:
estimator/— Lux internal Module-LWE / Module-SIS hardness estimator - Reference: matches FIPS 204 §4 Table 1 parameter analysis
- Categories: ML-DSA-44 (Cat 2), ML-DSA-65 (Cat 3), ML-DSA-87 (Cat 5)
§2 Performance results (single-party path)
Excerpted from bench/results/REPORT.md. Median of three runs.
| Parameter set | KeyGen | Sign | Verify |
|---|---|---|---|
| ML-DSA-44 (Cat 2) | 175 µs | 1.36 ms | 245 µs |
| ML-DSA-65 (Cat 3) | 343 µs | 2.63 ms | 398 µs |
| ML-DSA-87 (Cat 5) | 461 µs | 3.29 ms | 517 µs |
Memory: constant-allocation per operation (5–7 allocs/op regardless of input). KeyGen dominates allocation cost (∼60–125 KB per call); Sign and Verify are sub-10 KB.
Comparison context: cloudflare/circl's single-party ML-DSA-65 ran
at ~340 µs KeyGen / ~2.6 ms Sign / ~390 µs Verify on the same hardware
— Pulsar's single-party path is within single-digit-percent (within
measurement noise) of the optimized baseline, as expected since both
exercise the same FIPS 204 primitive.
Variance: a single ML-DSA-65 Sign sample at 5.27 ms vs the 2.6 ms
median is the visible rejection-sampling tail of FIPS 204 §6.2. This
is standard ML-DSA behaviour, not a Pulsar artifact. Production
deployments amortise it with preprocessing (see spec/pulsar.tex
§4.4).
§3 Performance results (threshold path)
| Configuration | Latency (median) | Notes |
|---|---|---|
| DKG 5-of-3 (P65) | ~2.6 ms wall-clock + N×network RTT | Lux mainnet committee setup; T=3, N=5 |
| DKG 7-of-4 (P65) | ~4.4 ms | |
| DKG 10-of-7 (P65) | ~7.8 ms | |
| Combine at t = 21 | ~300 µs CPU overhead vs single-party Sign | Lagrange-coefficient products over R_q |
Per-party Round-1 + Round-2 costs are dominated by the underlying
ML-DSA-65 sign-share work, which lands within 10% of single-party
Sign. Combine is O(t) Lagrange-coefficient products in R_q.
Threshold orchestration latency (network RTTs, abort-detection,
membership) is out of scope for this report; see the Lux Quasar
consensus layer (luxfi/consensus).
§4 Correctness — KAT cross-validation
| Test category | Status | Vector file |
|---|---|---|
| Single-party Sign vectors (Pulsar ↔ pq-crystals) | ✅ 100% bit-equal | vectors/sign.json |
| Single-party Verify (Pulsar ↔ circl ↔ BoringSSL) | ✅ Cross-accept on all | vectors/verify.json |
| DKG transcripts (n=3..21, t=2..14) | ✅ All reproduce deterministically | vectors/dkg.json + transcripts |
| Threshold Sign output ↔ single-party Sign on reconstructed sk | ✅ Bit-equal under honest quorum | vectors/threshold-sign.json |
| Malformed signature rejection | ✅ All malformed inputs rejected by all 3 verifiers | test/negative/ |
| Reshare pk-preservation | ✅ pk identical across rotation | vectors/transcripts/n*-t*-reshare.jsonl |
Cross-validation is automated in scripts/test.sh and runs on every
CI push. A single mismatch fails the gate.
§5 Constant-time analysis
| Layer | Status | Tool | Evidence |
|---|---|---|---|
| Threshold Round-1 | ✅ CT-clean | jasmin-ct (static) | scripts/checks/jasmin.sh 3/3 |
| Threshold Round-2 | ✅ CT-clean | jasmin-ct | same |
| Threshold Combine | ✅ CT-clean | jasmin-ct | same |
| libjade ML-DSA-65 Sign | ⚠ Advisory | jasmin-ct | issue #2 — keygen_end.jinc:125 random_zeta_p type-check; documented at ct/jasmin-ct-libjade.md |
| Pulsar.Sign (Go reference) | Intentionally NOT CT | dudect | per FIPS 204 §3.3 — Sign is not required to be CT |
| Pulsar.Verify (Go reference) | ✅ CT (intent) | dudect at 10⁹ samples (nightly) | ct/dudect/verify_ct.go |
Sensitive-region map (per FIPS 204): ExpandMask, y sampling, A·y, HighBits/LowBits, rejection-condition evaluation, hint generation, sk unpacking. All threshold-layer touches of these regions are within the Jasmin code that jasmin-ct certifies; the Go reference is for correctness/audit, not production CT.
For production deployment: a separate constant-time review of the production binary (Rust crate, C library, or WASM) is required. The reference implementation's CT properties do NOT automatically transfer.
§6 Side-channel notes
Beyond constant-time, the following side-channels need separate audits:
| Risk | Status |
|---|---|
| Power / EM | Not addressed in v0.1 — depends on deployment |
| Cache timing | Subsumed by jasmin-ct (no secret-dependent memory access) on threshold layer |
| Fault injection | Not addressed in v0.1 — application-level concern |
| Branch prediction | Subsumed by jasmin-ct |
| Speculation | Not directly analyzed; Jasmin's emitted assembly has documented speculation behaviour on x86_64 |
| Rejection-sampling timing | FIPS 204 §3.3 explicitly allows variable-time Sign; the rejection sample count is NOT secret-dependent on s_1/s_2 (it's secret-dependent on y and rho_rnd, which are session-ephemeral) |
§7 Security parameter analysis
Pulsar parameter sets match FIPS 204 §4 Table 1 exactly:
| Set | NIST Category | Pub key (bytes) | Sec key (bytes) | Sig (bytes) | M-LWE secret bound | M-SIS forgery bound |
|---|---|---|---|---|---|---|
| ML-DSA-44 | Cat 2 | 1312 | 2560 | 2420 | 2^123 classical / 2^111 quantum | 2^123 / 2^111 |
| ML-DSA-65 | Cat 3 | 1952 | 4032 | 3309 | 2^182 / 2^165 | 2^182 / 2^165 |
| ML-DSA-87 | Cat 5 | 2592 | 4896 | 4627 | 2^252 / 2^229 | 2^252 / 2^229 |
These bounds come from FIPS 204's analysis (NIST FIPS 204 Appendix B);
this submission ADOPTS them and does not independently re-derive
lattice hardness. The estimator/ directory restates the M-LWE
instance for each parameter set so an auditor can plug it into
public estimators (e.g., the leaky-LWE-estimator) and reproduce
NIST's analysis.
Threshold-specific security impact:
- The Pulsar construction does NOT degrade FIPS 204's hardness (the reconstructed secret IS the FIPS 204 secret).
- The DKG soundness reduction is to standard threshold-cryptography
assumptions (Pedersen-VSS soundness); see
pulsar-m/dkg-soundness.texand the Lean reduction. - Identifiable abort under synchronous network is preserved by the
v8 third-party-verifiable evidence protocol (commit
effc648, spec §5.3).
§8 Comparison to alternative threshold schemes
| Scheme | Round count | Signature output | Underlying lattice |
|---|---|---|---|
| Pulsar (this) | 2 | Byte-equal to FIPS 204 ML-DSA | Module-LWE |
| Lux Corona (R-LWE sibling) | 2 | Byte-equal to FIPS 204 ML-DSA | Ring-LWE |
| Raccoon | 3 | Compatible verification | Module-LWE |
| Corona (upstream academic) | 2 | Not interchange-tested at submission | R-LWE |
| LWE-based threshold-Dilithium variants | 3+ | Variable | Module-LWE |
Pulsar's distinguishing properties:
- 2 rounds (not 3+).
- Byte-identical output to single-party FIPS 204 — no verifier modification needed.
- N4 reshare with public-key preservation.
- Machine-checked refinement proof (EasyCrypt + Lean + Jasmin).
- Identifiable abort with third-party verifiable evidence.
§9 Reproducibility
| Artifact | How to reproduce |
|---|---|
| Performance benchmarks | scripts/bench.sh from a fresh clone |
| KAT vectors | scripts/gen_vectors.sh (deterministic from 48-byte seed) |
| Constant-time analysis | scripts/check-high-assurance.sh (jasmin-ct) + scripts/nightly.sh (dudect) |
| EC proof gate | scripts/check-high-assurance.sh (13/13 EC compile + 0/0 admits + 5/5 Lean bridges) |
| Build artifact reproducibility | scripts/build.sh should produce byte-identical output across reruns |
A reviewer's reproduction loop:
git clone --branch submission-2026-11-16 https://github.com/luxfi/pulsar
cd pulsar
opam switch jasmin && opam install . --deps-only
scripts/build.sh # build everything deterministically
scripts/check-high-assurance.sh # proof + CT gate (should be green)
scripts/test.sh # KAT cross-validation
scripts/bench.sh # performance benchmarks
diff bench/results/REPORT.md # should reproduce within timing noise
Drift = bug; please report at https://github.com/luxfi/pulsar/issues.
§10 Limitations and open work
| Limitation | Tracking |
|---|---|
| Threshold orchestration latency benchmarks (network RTTs, abort handling) | Out of scope — see Lux Quasar consensus benchmarks |
| GPU/accelerated implementation | luxfi/accel — separate repo |
| FIPS 140-3 module validation | Downstream — lab-run validation post-submission |
| ACVP/CAVP algorithm validation | Downstream — lab-run validation |
| Threshold SLH-DSA variant | Tier 3 (experimental research profile) — not in v0.1 |
| Continuous fuzzing infrastructure | test/fuzz/ exists; coverage expansion ongoing |
| External cryptographic audit | Scoping; engagement timing TBD |
§11 Summary
| Dimension | Result |
|---|---|
| Performance (single-party) | Within 5% of optimized FIPS 204 reference |
| Performance (threshold) | DKG sub-millisecond per party at typical n,t |
| Correctness (KAT) | 100% cross-validate against 3 independent ML-DSA implementations |
| Constant-time | Threshold layer green (jasmin-ct 3/3 blocking); libjade sign advisory under #2 |
| Proof | 13/13 EC compile, 0/0 admits, 5/5 Lean bridges |
| Security parameters | Match FIPS 204 Table 1 exactly |
| Threshold-specific security | DKG + sign + reshare reductions stated; mechanization in flight |
Pulsar v0.1 delivers reference-grade implementation correctness for FIPS 204 ML-DSA-65 threshold signing with machine-checked refinement proofs. Production deployment requires separate lab-grade ACVP/CAVP validation + side-channel review on the deployed binary.
Document metadata
- Name:
docs/evaluation.md - Version: v1.0 (post v10)
- Date: 2026-05-18
- Companion:
bench/results/REPORT.md(raw bench numbers),ct/dudect/README.md(CT analysis methodology)