mirror of
https://github.com/luxfi/pulsar.git
synced 2026-09-24 00:25:52 +00:00
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]>
297 lines
16 KiB
Markdown
297 lines
16 KiB
Markdown
# 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.
|