Files
zeekayandHanzo Dev 22731aba99 spec: cite Ringtail by its title, and state Corona's licence
references.bib gave ePrint 2024/1113 the title "Corona: Practical Two-Round
Threshold Signatures from Learning with Errors". The paper is "Ringtail:
Practical Two-Round Threshold Signatures from Learning with Errors", by the
six authors the entry already named correctly. A title is the authors' words.
The file's own header asks for exactly this — "verified against
https://eprint.iacr.org... Do not paraphrase or guess".

Ringtail is their scheme. Corona is Lux's implementation over Ring-LWE;
Pulsar retargets the same two-round structure to Module-LWE for FIPS 204.
The prose and the citation key now say so, and this spec is the NIST MPTC
submission, so it is the last place to get it wrong.

patent-notes.tex stated "Corona's open-source repo is Apache-2.0 with no
asserted patent claims". Corona is under the Lux Ecosystem License v1.2,
which reserves commercial use — no Apache grant and no Apache §3 patent
grant. The surrounding paragraph had been flattened by a rename into
"Pulsar ... is derivative of Pulsar" and "Pulsar (and therefore Pulsar) is a
fork"; it now names Corona and Ringtail where each is meant.

Dropped the residual Pulsar-M spelling, including the naming rule that
forbade writing "Pulsar" and required writing "Pulsar".

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-29 11:12:14 -07:00

16 KiB
Raw Permalink Blame History

Pulsar -- Agent Knowledge Base (formerly Pulsar)

Repository (current): github.com/luxfi/pulsar Repository (target): github.com/luxfi/pulsar Latest Tag: v1.2.0 Status: TALUS threshold ML-DSA BUILT; PULSAR-V13-W-LEAK CLOSED (semi-honest, simulation-proven). Not yet FIPS-validated; open residuals = the malicious-secure CSCP layer + a networked MPC deployment (Residual A) and dealerless-key impossibility ⇒ trusted-dealer keygen + Corona-carries-permissionless (Residual B). EasyCrypt + Lean machine-check on host (gate ec-machine-check.sh, 14/14); TALUS / no-leak BCC threshold path interop-verified byte-equal under CIRCL + pq-crystals.

Rename in progress: Pulsar → Pulsar

Per the Lux family rebrand, the three threshold libraries are:

Name Lattice Class Source path going forward
Pulsar (this repo, was Pulsar) Module-LWE NIST MPTC N1+N4 ~/work/lux/pulsar
Corona (was the prior R-LWE Pulsar) Ring-LWE NIST MPTC S1+S4 ~/work/lux/corona
Corona (unchanged) Ring-LWE academic upstream + Lux lifecycle DKG expansions ~/work/lux/corona

Until the cross-repo moves land, this repo continues at luxfi/pulsar-m and the existing luxfi/pulsar v0.1.5 (R-LWE) keeps shipping. The rename is a naming change, not a behaviour change — wire formats, KAT vectors, and FIPS 204 byte-equality guarantees are unchanged.

Family migration plan

Going-forward name Lattice Class Where it lives now Where it lives after
Pulsar Module-LWE / FIPS 204 NIST MPTC N1 + N4 github.com/luxfi/pulsar github.com/luxfi/pulsar
Corona Ring-LWE NIST MPTC S1 + S4 github.com/luxfi/pulsar (current R-LWE production fork) github.com/luxfi/corona
Corona Ring-LWE academic upstream + Lux lifecycle DKG expansions github.com/luxfi/corona github.com/luxfi/corona (unchanged)
Quasar composition layer -- consensus/protocol/quasar/ (sub-protocol) optional standalone github.com/luxfi/quasar as the PQ event horizon

Quasar — PQ event horizon

Quasar is proposed as the top-level meta-package that consumes every PQ primitive (Pulsar threshold ML-DSA, Corona threshold R-LWE, P3Q STARK rollup, BLS aggregate, ML-DSA single-party) and exposes a unified Verify(cert) interface. Consensus's existing consensus/protocol/quasar/ already implements this as a sub-protocol; promoting it to a standalone repo would let EVM precompiles (precompile/quasar/ at 0x0604 per the LP-4200 table) and external relying parties consume the same verification surface without depending on the full consensus stack.

Migration order (when push authorised)

  1. Push pre-existing work first to avoid entangling pre-migration commits with the rename:
    • luxfi/corona push commits ahead
    • luxfi/pulsar commit + push LLM.md edit
    • luxfi/p3q commit + push LLM.md edit
    • luxfi/pulsar-m commit Large*, luxround, largeshamir, spec, proofs and push as v0.2.0
    • luxfi/precompile commit + push the new pulsar/ precompile
  2. Stand up luxfi/corona by mirroring current luxfi/pulsar contents. Preserve all tags. Cut rename commit as v0.2.0 on luxfi/corona. Leave luxfi/pulsar as redirect/archive marker for downstream go.mod consumers.
  3. Move pulsar-m contents to luxfi/pulsar: delete R-LWE content (preserved in corona), copy M-LWE content from pulsar-m, bump module path. Cut as v0.2.0. Archive luxfi/pulsar-m with README redirect.
  4. Update consumers' go.mod (luxfi/consensus, luxfi/precompile): replace github.com/luxfi/pulsar v0.1.0 with github.com/luxfi/pulsar v0.2.0. Update imports + go mod tidy.
  5. Optional: stand up luxfi/quasar as the PQ event horizon meta-repo. Imports luxfi/pulsar, luxfi/corona, luxfi/p3q, luxfi/crypto/bls, luxfi/crypto/mldsa. Wire precompile/quasar/ (0x0604) to consume it.

Destructive-action checklist (push phase)

Operations modify shared / production systems and need explicit user confirmation per auto-mode safety policy:

  • git push to any of the four repos
  • gh repo rename luxfi/pulsar luxfi/corona
  • gh repo create luxfi/corona
  • gh repo archive luxfi/pulsar-m
  • Updating luxfi/consensus/go.mod and go.sum to switch from pulsar-m to pulsar (busts go.sum hashes)
  • Cutting new tags (v0.2.0 on renamed repos)

Cleanliness audit (local snapshot)

Repo Status Action
luxfi/pulsar-m modified + untracked (GF(q) Large*, luxround helpers, spec, proofs) Commit cleanly; archive when contents move
luxfi/pulsar LLM.md rename note modified Commit; hosts M-LWE post-migration
luxfi/corona commits ahead + modified + untracked Push commits first; merge/discard locally
luxfi/p3q LLM.md modified Commit; v0.0.1 pushed
luxfi/consensus Clean go.mod bump after migration
luxfi/precompile New precompile/pulsar/ (LP-4200 0x012204) Commit + run CI
luxfi/corona Does not exist Create from current luxfi/pulsar R-LWE contents
luxfi/quasar Does not exist Optional standalone repo

Module-pin reconciliation (pre-rename gate)

Silent-swap hazard: threshold/go.mod and warp/go.mod both pin github.com/luxfi/pulsar v0.1.0-rc1-pq-consensus-freeze with replace github.com/luxfi/pulsar => ../pulsar. After the rename ../pulsar will contain M-LWE code (was R-LWE), so existing R-LWE-API call sites in threshold/warp will fail to compile. The go.mod surgery list below MUST land before any directory rename:

  • threshold/go.mod:
    • require github.com/luxfi/corona v0.2.0 (was: github.com/luxfi/pulsar v0.1.0-rc1-pq-consensus-freeze)
    • replace github.com/luxfi/corona => ../corona (was: => ../pulsar)
    • UPDATE all imports github.com/luxfi/pulsar/... → github.com/luxfi/corona/... in source.
  • warp/go.mod: same pattern as threshold/go.mod.
  • consensus/go.mod:
    • require github.com/luxfi/pulsar v0.2.0 (was: github.com/luxfi/pulsar v0.1.0)
    • require github.com/luxfi/corona v0.2.0 (was: github.com/luxfi/pulsar v0.1.5)
    • UPDATE imports github.com/luxfi/pulsar/... → github.com/luxfi/pulsar/... in source.
    • UPDATE imports github.com/luxfi/pulsar/... (R-LWE) → github.com/luxfi/corona/... in source.
  • node/go.mod: same as consensus/go.mod (indirect deps follow).
  • precompile/go.mod:
    • add require github.com/luxfi/pulsar v0.2.0 (currently has no pulsar dep — Blue's commit didn't add it because the precompile uses crypto/mldsa directly).
    • no R-LWE Pulsar / Corona dep needed (precompile/corona covers that path).

Migration sequence

Exact commit order (each step gated by Verification below):

  1. Stand up luxfi/corona repo (mirror current luxfi/pulsar contents, all tags preserved).
  2. Tag luxfi/corona v0.2.0.
  3. In threshold / warp / consensus / node: update go.mod + imports to point at luxfi/corona for R-LWE.
  4. Tag each consumer (threshold, warp, consensus, node).
  5. Bump pulsar-m → cut as luxfi/pulsar v0.2.0 (M-LWE code moves into luxfi/pulsar; preserve pre-v0.2.0 tags as historical R-LWE).
  6. In consensus / node / precompile: update go.mod imports from luxfi/pulsar-m → luxfi/pulsar.
  7. Tag each.
  8. Archive luxfi/pulsar-m with README redirect.

Verification gate

After each step in the Migration sequence, the affected consumer repos MUST compile + test green before the next step proceeds:

  • go build ./... exits 0
  • go test ./... exits 0
  • go mod tidy produces no diff
  • CI green on the tagged commit

A red gate blocks the next step. No silent skips; document the failure and resolve before advancing.

Purpose (one-liner)

Threshold ML-DSA: a two-round lattice kernel + one-round online signing (TALUS) and DKG whose generated signatures are verifiable by unmodified FIPS 204 ML-DSA verification. Targeting NIST MPTC Class N1 (signing) + N4 (ML keygen / DKG).

Pulsar is the Module-LWE sibling of luxfi/pulsar (Ring-LWE). Pulsar's two-round kernel is transplanted onto ML-DSA-65's polynomial-vector-over-R_q algebra so the aggregated signature is bit-identical to a single-party FIPS 204 signature on the same message + public key; TALUS (v1.2.0) adds one-round online signing on top.

TALUS — threshold ML-DSA (v1.2.0)

TALUS is the threshold ML-DSA scheme on Pulsar's two-round lattice kernel, adding one-round online signing. Source: ref/go/pkg/pulsar/talus*.go.

  • Three pillars. Dealerless Shamir nonce DKG (talus_nonce_dkg.go), CEF = Carry Elimination Framework / distributed w1 (talus_cef.go), CSCP = the CarryCompare secure-comparison protocol (talus_cscp.go). BCC = Boundary Clearance Condition. These route around the impossibility of FROST-style additive-nonce threshold ML-DSA (HighBits/r0/carry is non-linear).
  • W-LEAK closed (semi-honest, simulation-proven). Commit 530c24e: the REAL CSCP secure-comparison circuit (bit-decompose + carry-save bitAdd + prefix bitLT over BGW multiplication, coefficient-exact vs FIPS Decompose) drives CEFComputeW1 → cscpSecureHighBitsVec, so NO node forms w0 or the full commitment w even transiently (only masked openings {valid, maskC, w1}). Proven leak-free by TestCSCP_MultiNode_LeakFree / TestCSCP_LeakFree_Structural / TestCSCP_MaskOpen_HidesW — but in an in-process N-party SIMULATION (NOT a networked/deployed MPC, NOT malicious-secure). Always describe as semi-honest, simulation-proven.
  • Two profiles. Pulsar-TEE (TEE-backed w1) and PulsarPC (honest-majority N ≥ 2T−1, enforced by TalusMinPartiesMPC / newCSCPCtx / cscpSecureHighBitsVec / bgwMulShares). Signature byte-identical across both.
  • Stock FIPS-204. A TALUS signature verifies byte-equal under UNMODIFIED cloudflare/circl mldsa65.Verify / mldsa87.Verify (TestTalus_MPC_EndToEnd_StockVerify, TestTalus_MPC_Mode87).
  • Malicious deviation = liveness-only. FindHint (recovers the FIPS hint from public w' = A·z − c·t1·2^d) + TalusReleaseGate (mandatory stock FIPS-204 verify, never releases a failed sig) bound any malicious CSCP deviation to abort/retry — never forge or leak (TestCSCP_WrongW1_CaughtByFindHint). This is Residual A (the malicious-secure CSCP layer + a networked MPC deployment, un-built).
  • KEYGEN is trusted-dealer (Residual B). Dealerless byte-FIPS-204 KEY DKG is proven unreachable: FIPS-204 KeyGen samples s1,s2 from S_η = {‖p‖∞ ≤ η}; a dealerless sum of N ≥ 2 contributions has ℓ∞-support up to N·η > η, breaking BCC byte-validity (‖c·s2‖∞ ≤ N·β > β) and the FIPS-204 security-equivalence (distributed_bcc_dkg.go → ErrDealerlessByteFIPSUnreachable). KEYGEN stays trusted-dealer; the permissionless guarantee is carried by Corona (corona v0.8.0, natively dealerless via Pedersen DKG over R_q) in the Quasar AND-mode cert.

Canonical profile + scheme constants

  • Hash family: SHAKE / cSHAKE / KMAC256 / TupleHash256 (FIPS 202 + SP 800-185).
  • Sharing: byte-wise Shamir, two regimes:
    • GF(257) for small committees (n ≤ 256), 64-byte wire share.
    • GF(q) for large committees (n ≤ q-1 = 8,380,416), 128-byte wire share. Canonical extreme committee target: TargetCommitteeSize = 1_111_111 (seven 1s).
  • Curve / lattice: same Module-LWE parameters as ML-DSA-65.
  • Round count: two-round kernel (commit + reveal); TALUS adds one-round online signing.
  • Abort model: identifiable.
  • Arithmetic width: uint32 lanes with uint64 accumulators. uint128 / uint256 not required (reserved for the Z-Chain SNARK side).

Recent significant changes

commit-like SHA Impact
170a705 NIST MPTC submission readiness — benchmarks + CI gates
ced8779 KAT vectors for keygen / sign / verify / threshold / dkg
cff8813 Proactive resharing with beacon-randomized quorum
ddef135 Threshold sign (2-round commit + reveal)
d0ae91e Epoch DKG with identifiable abort
14481d6 Byte-wise Shamir secret sharing over GF(257)
4d0ff1f Keygen + sign + verify (single-party)
6cf9e5b Bootstrap NIST MPTC submission package
(pending) GF(q) Shamir + N=1,111,111 target + spec system-model + parameters complete

Active versions

  • Repo: v1.2.0 (current; TALUS threshold ML-DSA + PULSAR-V13-W-LEAK closed semi-honest).
  • Pinned by: luxfi/consensus v1.23.5+ (finality verify path replaces the placeholder Pulsar verifier).

Cross-repo dependencies

  • Depends on:
    • golang.org/x/crypto/sha3 (cSHAKE / KMAC primitives)
    • luxfi/crypto/pq/mldsa/mldsa65 (FIPS 204 verifier — Pulsar outputs must round-trip through it byte-equal)
  • Consumed by:
    • luxfi/consensus/protocol/quasar (finality path) — F107/F109 closure.
    • NIST MPTC submission package (spec/ LaTeX).

Where to look for X

  • Keygen / sign / verify (single-party): ref/go/pkg/pulsar/keygen.go, sign.go, verify.go.
  • 2-round threshold sign: ref/go/pkg/pulsar/threshold.go
  • Epoch DKG (identifiable abort): ref/go/pkg/pulsar/dkg.go
  • Proactive reshare (beacon randomization): ref/go/pkg/pulsar/reshare.go
  • Small-committee Shamir (GF(257)): ref/go/pkg/pulsar/shamir.go
  • Large-committee Shamir (GF(q)): ref/go/pkg/pulsar/shamir_gfq.go, largeshamir.go
  • Field auto-selection logic: ref/go/pkg/pulsar/types.go:resolveField
  • KAT vectors: vectors/
  • LaTeX submission spec: spec/pulsar-m.tex (full; not a stub), spec/parameters.tex, spec/system-model.tex, spec/security-games.tex
  • Benchmarks (MPTC requirement): bench/
  • CT (constant-time) guards: ct/

Where to find proofs

  • LaTeX theorem statements + proofs: ~/work/lux/proofs/pulsar-m/
    • unforgeability.tex -- TS-UF reduction to MLWE+MSIS+ML-DSA EUF-CMA
    • scaling.tex -- Concrete claims at N* = 1,111,111
    • output-interchangeability.tex -- Class N1 manifesto
    • dkg-soundness.tex -- DKG soundness + share privacy
    • reshare-preservation.tex -- Reshare preserves pk + soundness + privacy
  • Lean 4 mechanization skeletons: ~/work/lux/proofs/lean/Crypto/Pulsar_M/
    • Unforgeability.lean, Shamir.lean, OutputInterchange.lean

Submission notes

  • Submission package deadline (NIST MPTC first call): 2026-Nov-16.
  • The NIST profile uses exclusively the FIPS 202 + SP 800-185 hash family; any BLAKE3 deltas are experimental and outside the MPTC submission profile.
  • Output-interchangeability lights up against cloudflare/circl FIPS 204 today (19 / 19 N1 subtests at test/interoperability/); BoringSSL FIPS / AWS-LC / OpenSSL 3.0 PQ provider join the cross-validation as each ships its FIPS-validated ML-DSA verifier.
  • Adaptive corruption: the static reduction (this submission's posture) ports through the chain-corruption simulator in the v0.2 audit cycle.
  • Cross-message restart hybrid: the v0.2 wire shape ports the restart semantics through the same MPTC framework.

Rules

  1. Patch-bump only (v0.1.0 → v0.1.1); never minor/major without explicit approval.
  2. Any deviation from the SHAKE / cSHAKE / KMAC profile is a forking decision — it breaks output-interchangeability with FIPS 204.
  3. KAT vectors are CI-pinned; never edit without rerunning the generator and committing the new vectors in the same commit.
  4. TargetCommitteeSize = 1_111_111 is the canonical extreme committee target. Change requires updating the constant in params.go, the proofs in ~/work/lux/proofs/pulsar-m/scaling.tex, and the spec in spec/pulsar-m.tex section "Large committees".
  5. Default to FieldDefault when constructing a session; only pin FieldGF257 or FieldGFq for KAT replay where wire-format determinism is required.