Quasar mainnet defaults, strict-PQ profile, and L1 onboarding
Concrete defaults for Quasar consensus on Lux primary network; the strict-PQ profile chain configuration; the L1 onboarding path for chains that want end-to-end post-quantum security with bidirectional warp messaging.
Implementation status (code-audited 2026-07-03): PARTIAL SigSchemeID 0x52 Pulsar-M-65 (consensus/config/pq_mode.go:288), BLS+Pulsar finality (config/profiles.go), PQ mode + scheme-pin confirmed; RefuseUnderStrictPQ lives at precompile-dex/contract/strict_pq.go.
Abstract
Defines the canonical Quasar mainnet defaults for the Lux primary network and the strict-PQ profile that L1s opt into when they want every cryptographic primitive on the chain (consensus, signatures, bridge) to be post-quantum. Specifies the precompile registry, the wire format, the light-client storage model, and the bidirectional warp messaging contract that lets a strict-PQ L1 launch on Lux, evolve to full-PQ-native, and continue to exchange warp messages with the primary network without dropping to a classical primitive at any point on the wire.
Motivation
Three operational questions need a single canonical answer:
- What does the Lux mainnet ship as the default consensus configuration?
- How does a chain launching on Lux declare itself strict-PQ — and what does that constrain?
- Can a strict-PQ L1 warp-message the primary network without breaking its own PQ guarantee?
This LP collapses those three questions into one configuration matrix.
Specification
Cryptographic primitives in scope
| Family | Scheme | Precompile | Hardness | Sig size | Verify |
|---|---|---|---|---|---|
| Classical fast lane | BLS12-381 aggregate | standard precompiles | co-CDH | 48 B | 714 µs |
| Module-LWE threshold | Pulsar (FIPS 204 byte-equal ML-DSA-65) | 0x012204 | MLWE + MSIS | 3,309 B | 181 µs (3 µs cached) |
| Module-LWE threshold | Corona | 0x012206 | MLWE | 33,052 B | 1.6 ms |
| Hash-based threshold (proposed) | Magnetar (public-DKG MPC threshold SLH-DSA) | 0x012207 | hash collision resistance | ~35,664 B | ~1.92 ms |
| Code-based KEM (family-disjoint) | HQC (NIST PQC4 backup KEM) | 0x012208 | Syndrome Decoding | CT 4,481 B (HQC-128) | ~150 µs (backend-bound) |
| Hash-based signature | SLH-DSA-192f (FIPS 205) | 0x012203 | hash collision resistance | 35,664 B | 1.92 ms (131 µs cached) |
| Module-LWE KEM | ML-KEM-768 (FIPS 203) | 0x012201 | MLWE | — | 25 µs |
| Strict-PQ STARK | STARK-FRI verifier (placeholder, pending dedicated LP) | 0x012220 | hash (cSHAKE256 / Goldilocks) | ~30 KB | ~5-10 ms |
| PQ unified verifier family | P3Q (kind-byte dispatch — see LP-218 / LP-220) | 0x012205 | hash + lattice (per-kind) | varies | varies |
| Classical SNARK | Groth16 | 0x0901 | KZG / pairings | 192 B | ~1-3 ms |
Pulsar is the canonical PQ floor on the signature side. ML-KEM-768 is the canonical PQ floor on the KEM side. The other PQ schemes are profile-selectable add-ons. HQC closes the family-disjoint gap on the KEM side — its hardness rests on Syndrome Decoding rather than Module-LWE, so a structural break against MLWE does not compromise HQC and vice-versa. Magnetar is the analogue closer on the signature side (public-DKG MPC threshold SLH-DSA at 0x012207 with Pedersen-style VSS for auditable distributed key generation).
Slot history — 0x012205 reassignment
0x012205 was previously allocated for Strict-PQ STARK (Plonky3 fork) in this LP. Per LP-218 §"Slot history: STARK-FRI rename" (2026-06-03), the STARK-FRI verifier moved to placeholder slot 0x012220 pending its own dedicated LP. Slot 0x012205 is now owned by LP-218 / LP-220 for the P3Q unified verifier family (kind-byte dispatch). LP-0120 retains ownership of raw-primitive verifier slots 0x012206 (Corona) and 0x012207 (Magnetar); LP-220 wraps these under the unified verifier family but does not displace the raw slots. LP-300 records this reassignment in §"Existing conflicts resolved".
Mainnet defaults (Lux primary network)
FinalitySchemeID: BLSPlusPulsar (the production default)
FastLane: BLS12-381 aggregate (48 B + bitmap, 714 µs verify)
Used for speculative block building + 2-block tail
confirmation. Anchored at Pulsar — speculative
BLS confirms can be revoked by Pulsar rejection.
Finality: Pulsar threshold (Module-LWE, FIPS 204 byte-equal)
3,309 B per cert at P65, 3 µs cached verify.
Threshold (t, k) sampled per Lux round via VRF
sortition from the validator registry.
Rollup: Optional. Off by default. Enable per L1 if
per-validator identity sigs need to be compressed
onto chain — pick Groth16 (192 B, classical) or
STARK-FRI (~30 KB, strict-PQ, placeholder slot
`0x012220` pending a dedicated LP).
Light-client surface: Z-Chain rollup proofs only. ~30 KB per epoch.
PQ profile gate: contract.RefuseUnderStrictPQ (single chokepoint
at every classical precompile's Run()).
Signature-scheme registry and the scheme-agnostic certificate (Normative)
Quasar is scheme-agnostic: the consensus engine defines only the quorum
rule (a stake-weighted strict-⅔ predicate — LP-0110 §3), and the node injects
the per-signer signature scheme as a one-byte wire tag SigSchemeID. This is why
the classical→PQ migration is a profile flip, not a protocol change; it is
proved invariant under the scheme substitution in
proofs/pq-finality-no-bls.tex §"Scheme-agnostic certificate and the signature
registry" (Proposition PQ migration is a profile flip).
SigSchemeID (config/pq_mode.go) is block-structured and open-ended. New
entries claim the next free integer in their block, are pinned in
pq_mode_test.go before any code references them, and a retired id is never
reused:
| Wire byte | Scheme | Family / hardness | Notes |
|---|---|---|---|
0x00 | none | — | BLS-only certs commit to no scheme |
0x10 | BLS12-381 aggregate | co-CDH (classical) | day-1 cert, live |
0x20 | Nasua (academic R-LWE) | R-LWE, BLAKE3 profile | trusted-dealer; federation/bridge only; not an open-chain stance |
0x30 | Pulsar.R | R-LWE threshold (SHA-3 profile) | production R-LWE |
0x41 / 0x42 / 0x43 | ML-DSA-44 / -65 / -87 | M-LWE (FIPS 204, single-party) | raw per-validator sig |
0x51 / 0x52 / 0x53 | Pulsar-M-44 / -65 / -87 | M-LWE threshold (FIPS 204-compatible) | 0x52 = production PQ default |
The 0x40 (raw single-party) and 0x50 (Pulsar-M threshold) blocks are kept
distinct on purpose: both verify under the unmodified FIPS 204
ML-DSA.Verify relation, but the producing protocol differs (single-party vs.
threshold), and the receiver needs to know which kernel emitted the bytes.
Naming note (wire byte is canonical). In config/pq_mode.go the 0x20
constant is SigSchemeNasua (String() → "nasua"); the block comment and some
external references still call this academic R-LWE finality scheme
"Corona-academic". That is distinct from the Corona Module-LWE threshold
precompile at 0x012206 (LP-4440). The human name is being reconciled toward
Nasua; the wire byte 0x20 is stable regardless and MUST NOT be renumbered.
Transcript binding (cross-suite confusion resistance). SigSchemeID and
HashSuiteID are covered inputs to the signed cert transcript
("LUX/chain/vote/v2" ‖ chainID ‖ height ‖ round ‖ canonicalID ‖ parentCanonical ‖ setRoot ‖ SigSchemeID ‖ HashSuiteID, hashed with SHAKE256). Flipping the
scheme byte post-signing changes the digest the signatures cover, so a
cross-suite confusion attack fails on signature verification, not on a
byte-equality check (proof: pq-finality-no-bls.tex Lemma Cross-suite confusion
resistance).
Orthogonal axes. SigSchemeID is one of six independent wire axes, each with
its own numbering and its own 0x90+ forbidden-marker block so audit tooling can
name a classical leakage explicitly: PolicyID (witness-set shape),
HashSuiteID (0x01 SHA3-NIST normative / 0x02 BLAKE3-legacy),
SigSchemeID (this table), ProofPolicyID (proof security class — STARK/FRI PQ
vs. classical-forbidden), ProofBackendID (0x30 direct weighted-quorum full-
node verify, 0x22 P3Q, …), and IdentitySchemeID (validator identity, FIPS 204
ML-DSA). The end-to-end axes (WalletSchemeID, TxSchemeID, ContractAuthID,
KeyExchangeID, RecoverySchemeID) pin the wallet/tx/contract/KEM/recovery
layers respectively.
Profile-flip activation. PQ finality is enabled by pinning the validator finality/identity scheme, not by swapping the engine:
- Default mainnet:
SigSchemeID = 0x52(Pulsar-M-65) as the finality default;0x10BLS runs the speculative fast lane. - Strict-PQ: pin
ValidatorSchemeID/finality to ML-DSA-65 (0x42) or -87 (0x43), or Pulsar-M-65/-87 (0x52/0x53); classical schemes are refused.PQSigner/PQVerifierenforce the pin and reject a mismatch withErrPQSchemeMismatch. The quorum rule and the no-double-finalization argument are unchanged across the flip; only the per-signer forgery bound improves from the Shor-breakable BLS bound to the lattice MLWE/MSIS bound.
Worked example (BLS → Pulsar-M-65). A chain running the classical default
finalizes with SigSchemeID = 0x10: each cert carries a 48-byte BLS aggregate,
and the safety proof (LP-0110 §2.7; quasar-cert-soundness.tex) rests on the
co-CDH forgery bound. To go post-quantum, the operator flips the finality scheme
to 0x52 (Pulsar-M-65). Nothing in the rule changes: the same committee is
sampled, the same strict-⅔ stake threshold is required, the same set-root is
cross-checked, and the same decided-height sign gate applies — so the
No double-finalization theorem holds verbatim with Verify_{0x10} replaced by
Verify_{0x52}. The only differences are the cert bytes (a ~3.3 KB M-LWE
threshold signature instead of 48 B) and the forgery bound (MLWE/MSIS instead of
co-CDH), which is precisely why an adversary with a quantum computer gains
nothing. Because 0x52 is a value the assembler reads — not a code path — the
migration ships as a config/profile change, gated by contract.RefuseUnderStrictPQ
so classical precompiles refuse to execute once the flip is live.
Assumption diversity (honest). Pulsar (R-/M-LWE) and ML-DSA (M-LWE) both rest
on lattice hardness — two lattice legs buy defense-in-depth against
implementation faults, not independent hardness. The genuine cross-family
diversifier is the hash-based SLH-DSA (FIPS 205) reserved for recovery and
high-value roots (RecoverySchemeID 0x05–0x07), which survives a total break of
lattice assumptions.
Q-Chain. The PQ proof root and omni-chain consensus coordinator is the Q-Chain (QuantumVM under Quasar) — the chain that anchors validator PQ identity, carries the strict-PQ finality certificates, and coordinates cross-chain ordering. Q-Chain finality blocks are specified in LP-170; the quantum-secure consensus family is LP-4099 (superseded into LP-0110 + this LP).
Strict-PQ profile
A chain declares itself strict-PQ at genesis by setting:
{
"chainConfig": {
"networkUpgradeOverrides": {
"strictPQTimestamp": 0 // active from genesis
},
"isStrictPQ": true,
"finalitySchemeID": "Pulsar" // OR "Aurora" OR "Magnetar"
}
}
When IsStrictPQ(time) == true, every classical-primitive precompile refuses to execute. The single chokepoint is precompile/contract/strict_pq.go#RefuseUnderStrictPQ — called from the top of Run() in each classical module (BLS12-381, BN254, KZG, secp256k1, secp256r1, Ed25519, Ristretto, Pedersen, Baby Jubjub, Pasta, Pulsar's own Groth16 wrap, etc.).
What's forbidden under strict-PQ
| Forbidden | Why |
|---|---|
| BLS12-381 G1/G2/Pairing | Discrete log under Shor's |
| BN254 (Add, ScalarMul, Pairing) | Same |
KZG (0x0900) | Uses BN254 pairings |
| Groth16 / PLONK / fflonk / Halo2 | Curve-based SNARKs |
| secp256k1 / ECDSA | Discrete log |
| secp256r1 / P-256 | Same |
| Ed25519, sr25519, Ristretto | Discrete log on Edwards |
| Pedersen over BN254 | Curve-based |
| Baby Jubjub, Pasta (Pallas/Vesta) | Curve-based |
| RIPEMD160, Blake2F | Pre-PQ hash families with caveats |
| C-Chain / EVM with classical-only precompiles | Use a Lux EVM with PQ-precompile registry instead |
What's allowed under strict-PQ
| Allowed | Notes |
|---|---|
Pulsar (0x012204) | Module-LWE FIPS 204 threshold |
Corona (0x012206) | Module-LWE threshold |
Magnetar (0x012207, proposed) | Public-DKG MPC threshold SLH-DSA (FIPS 205 byte-equal) |
ML-DSA single-party (0x012202) | FIPS 204 |
SLH-DSA (0x012203) | FIPS 205 hash-based |
ML-KEM (0x012201) | FIPS 203 KEM (Module-LWE) |
HQC (0x012208) | NIST PQC4 KEM (code-based, family-disjoint from ML-KEM) |
STARK-FRI (0x012220, placeholder) | Strict-PQ rollup (pending dedicated LP — see LP-218 §"Slot history: STARK-FRI rename") |
P3Q unified verifier (0x012205) | Unified verifier family with kind-byte dispatch (LP-218 / LP-220) |
| cSHAKE256, BLAKE3, SHA-3 | Hash primitives |
| Pulsar bridge messages | E2E PQ warp |
X-Wing+ (0x2222, proposed) | X25519 ∥ ML-KEM-768 ∥ HQC hybrid envelope (extends X-Wing with code-family KEM) |
Wire format minimums
Per-block on-the-wire (1.1M-signer registry, k=128 sampled committee):
Z-Chain header
parent_hash 32 B
state_root 32 B
validators_root 32 B (Merkle root of the 1.1M-validator registry)
rollup_proof_root 32 B
epoch + slot 8 B
─────
136 B header
Pulsar threshold sig over header
3,309 B
Sortition proof (k=128 from N=1.1M, Merkle path)
~3.8 KB (128 × 30 B path + payload)
────────────────────────────
Total per Z-Chain block ~7.3 KB
STARK-FRI proof transmitted once per epoch (~30 KB), not per block. For 1 ms block time, batch into 1-second super-rollups so light clients verify ~30 KB per second of chain progress instead of per millisecond. (STARK-FRI verifier currently parked at placeholder slot 0x012220 per LP-218 §"Slot history: STARK-FRI rename"; awaits a dedicated LP.)
Light-client storage budget
Persistent state (constant in time):
Pulsar group public key 1,952 B
Validator-set Merkle root 32 B (refreshed per epoch from P-Chain)
Z-Chain head pointer 32 B
Latest STARK-FRI checkpoint ~30 KB (verifier at placeholder 0x012220)
─────────
~32 KB persistent
Per-tx-of-interest (ephemeral):
Tx Merkle inclusion proof ~1 KB
(STARK-FRI header amortised across the epoch)
A subscribed-to-100-addresses light client: ~32 KB + ~100 KB = ~132 KB total state. Drops proofs once rolled into the next STARK-FRI checkpoint.
Pruned full node ("forget mode")
Keep forever:
Z-Chain proof chain (STARK-FRI per epoch) ~30 KB × 52K/yr ≈ 1.5 GB/yr
Validator-set history Merkle ~10 MB/yr
P-Chain state diffs ~100 MB/yr
Drop after rollup:
Full block bodies / tx data older than 2 epochs
Pruned-node total disk: ~1.6 GB/year vs archival ~10 TB/year for full chain history at 1 ms block time. ~6,000× compression.
L1 onboarding — strict-PQ launch checklist
1. Genesis config:
strictPQTimestamp = 0
finalitySchemeID = "Pulsar" (or "Aurora" / "Magnetar")
classicalCompatUnsafe = false
2. Validator key material:
pubkey scheme = ML-DSA-65 (Pulsar pk)
NodeIDScheme byte = 0x42 (SigSchemeMLDSA65)
3. Precompile registry (in evm/main.go blank-imports):
_ "github.com/luxfi/precompile/mlkem" // 0x012201
_ "github.com/luxfi/precompile/mldsa" // 0x012202
_ "github.com/luxfi/precompile/slhdsa" // 0x012203
_ "github.com/luxfi/precompile/pulsar" // 0x012204
_ "github.com/luxfi/precompile/p3q" // 0x012205 (unified verifier family — LP-218 / LP-220)
_ "github.com/luxfi/precompile/corona" // 0x012206
_ "github.com/luxfi/precompile/magnetar" // 0x012207 (proposed)
_ "github.com/luxfi/precompile/hqc" // 0x012208 (family-disjoint KEM)
// _ "github.com/luxfi/precompile/starkfri" // 0x012220 (placeholder, pending dedicated LP — see LP-218 §"Slot history: STARK-FRI rename")
_ "github.com/luxfi/precompile/xwing" // 0x2221 (X25519 ∥ ML-KEM-768)
// _ "github.com/luxfi/precompile/xwingplus" // 0x2222 (proposed: X-Wing+, X25519 ∥ ML-KEM ∥ HQC)
// ABSENT under strict-PQ:
// _ "github.com/luxfi/precompile/kzg4844"
// _ "github.com/luxfi/precompile/bls12381"
// (any other classical-curve module)
4. Warp:
SchemeCorona Scheme = "corona" (warp/crypto/signature/interface.go)
OR
Pulsar threshold over warp messages (default)
Classical SchemeBLS still available but profile-gated.
5. Bridge (B-Chain) custody:
MPC key scheme = Pulsar (or Corona)
Cross-chain messages signed by source-chain Pulsar threshold
Re-signed by B-Chain Pulsar MPC for destination
6. Light-client RPC endpoints:
GET /v1/zchain/head
GET /v1/zchain/proof/{epoch}
GET /v1/zchain/inclusion/{tx_hash}
(returns: STARK-FRI proof over a Pulsar-finalised batch + Merkle path)
Warp messaging — strict-PQ L1 ↔ Lux primary network
Bidirectional, end-to-end PQ:
STRICT-PQ L1 LUX PRIMARY NETWORK
──────────── ───────────────────
Outbound from L1:
L1 produces tx → Pulsar finality on L1 block ← (one Pulsar sig per block)
Bridge module on L1 → wraps message + L1 Pulsar proof + Z-Chain rollup ref
→ emits warp event
Validator gossip → carries the wrapped message
Lux primary B-Chain → ingests, verifies L1's Pulsar proof
via precompile 0x012204 — strict-PQ verify
→ re-signs for destination chain via B-Chain MPC
→ emits warp event on Lux primary
Destination Lux chain ← verifies B-Chain re-signature (Pulsar)
← message executes
Inbound to L1:
Same path, mirrored. Lux-primary-Pulsar proof → L1 B-Chain → L1 destination
Every signature on every leg is one of: Pulsar (M-LWE) or Corona (M-LWE) or SLH-DSA (hash) or STARK-FRI. No BLS, no ECDSA, no KZG, no Groth16 anywhere on the warp wire when both ends are strict-PQ.
If one end is strict-PQ and the other is mixed (e.g., Lux mainnet C-Chain running BLS-fast-lane + Pulsar-finality), the strict-PQ end MUST verify only the Pulsar portion of the proof; the BLS aggregate is dropped at the strict-PQ boundary. This is enforced by the precompile-level RefuseUnderStrictPQ gate on the strict-PQ side and by Pulsar's own self-sufficient finality on both sides.
Can an L1 run only EVM (no other VMs)?
Yes. An L1 launched on Lux can ship with the EVM as its sole VM. Strict-PQ does not require running M-Chain (MPC), F-Chain (FHE), or any other Lux-primary chain locally — those are services exposed by the Lux primary network that the L1 can opt into via warp messaging. Strict-PQ requirements on a single-EVM L1:
Required: Optional:
EVM + PQ precompile registry M-Chain MPC custody (use Lux primary's)
P-Chain validator follower F-Chain FHE compute (use Lux primary's)
Z-Chain follower B-Chain teleport ingress
Pulsar threshold ceremony Per-validator identity sig rollup
Strict-PQ chain config
At a minimum: one EVM + Pulsar threshold + Z-Chain follower. ~32 KB persistent state for light clients, ~1.6 GB/yr for pruned nodes, ~10 TB/yr for archival.
Rationale
Why Pulsar as the PQ floor (not Aurora or Magnetar)
Pulsar is byte-equal to FIPS 204 ML-DSA-65 — the only NIST-validated PQ signature standard. Module-LWE and Module-SIS are stress-tested through the NIST PQC competition. There's no operational benefit to stacking more PQ schemes by default. Defense-in-depth additions (Corona for intra-lattice diversity in the Aurora profile, plus Magnetar for cross-family hash diversity in the Polaris profile) are profile-selectable, not the floor.
Certificate profile naming
Strict-PQ chains pick one finality scheme. Names are astronomical so they stay distinct from the Wing-prefixed transport/KEM hybrids (X-Wing, Z-Wing) and the Z-Chain rollup surface:
finalitySchemeID | Construction | Story |
|---|---|---|
Pulsar | threshold ML-DSA (FIPS 204) | the PQ floor — fast, regular pulse |
Aurora | Pulsar ∥ Corona | combined glow from intra-lattice diversity |
Polaris | Pulsar ∥ Corona ∥ Magnetar | maximum-assurance, adds the hash-only tail |
Pulsar / Corona / Magnetar are the primitive names; Aurora / Polaris are the certificate profile names that bundle them. The Wing prefix is reserved for hybrid constructions on the transport lane (Z-Wing channel, LP-9702 — legacy, do not overload) and the KEM lane (X-Wing, IETF; X-Wing+, the code-family extension at 0x2222). No Wing names on the cert lane, no new Wing letters introduced — X-Wing+ is a notation extension of the IETF name, not a new Lux Wing brand.
Why MLWE ⊃ RLWE rules out "2× lattice safety"
Module-LWE with module rank k=1 is Ring-LWE. Polynomial-time reductions between them exist (with parameter shifts in modulus and error width). Stacking Pulsar and Corona (both Module-LWE, different parameter sets and codebases) gives implementation-level defense-in-depth but not family-disjoint hardness. For true family-disjoint PQ defense, cross to hash (SLH-DSA / Magnetar on signatures) or codes (HQC on KEM). HQC at 0x012208 and Magnetar at 0x012207 close those two gaps: a structural break in lattice cryptography would not compromise HQC (its hardness is Syndrome Decoding on random quasi-cyclic codes) or Magnetar (its hardness is collision/preimage resistance of the underlying hash family).
Why HQC on the KEM side and Magnetar on the signature side
The Lux PQCrypto block aims for two-axis coverage: by-default lattice (Pulsar + ML-KEM) for speed, profile-selectable code (HQC) and hash (Magnetar, SLH-DSA) for cross-family hedge. A chain that wants belt-and-suspenders KEM can chain X25519 ∥ ML-KEM-768 ∥ HQC at 0x2222 — X-Wing+, the code-family extension of the IETF X-Wing KEM combiner. Breaking the X-Wing+ shared secret requires solving ECDLP, MLWE, AND Syndrome Decoding simultaneously. The cost is one additional KEM operation (~150 µs for HQC-128 encapsulate) and ~4.5 KB of ciphertext per envelope on top of the X-Wing baseline.
Why Z-Chain is the light-client surface
Following the Z-Chain rollup gives a light client "this state was finalized by these validators" for any other chain in the topology, with a constant-size proof per epoch. Pulsar's threshold output is constant in n (the registry size), so the Z-Chain proof chain is constant-rate even as the validator set grows to 1.1M signers.
Why strict-PQ is profile-gated, not chain-default
The Lux primary network ships BLS as a fast lane because the bandwidth and verify cost are negligible (48 B, 714 µs) compared to Pulsar (3.3 KB, 181 µs single / 3 µs cached). Speculative 2-block confirmation under BLS, with canonical finality at Pulsar, gives the operational profile most chains want. Strict-PQ chains pay the cost of dropping BLS in exchange for a wire that no quantum adversary can attack at any point.
Backwards compatibility
This LP changes no existing wire format. Strict-PQ is an opt-in chain configuration. Existing chains continue under their current profile until they reconfigure at a genesis upgrade.
Security considerations
- Post-quantum everywhere is one gate, not per-precompile policy. The chain-wide posture is a single value —
Mode(pq/mode.go:47):classicalignores PQ material,hybridvalidates it when present,strict-pqrefuses every classical authentication root. At the EVM-precompile layer,ModeStrictPQinstalls the one enforcement function:RefuseUnderStrictPQ(precompile/contract/strict_pq.go:33), called at the top ofRun()by every classical precompile before it does any work — across 18 modules (BLS12-381, BN254/KZG, secp256r1, Ed25519/sr25519, Curve25519/X25519, Pedersen, BabyJubjub, Pasta, Poseidon, BLAKE3, FROST, CGGMP21, Ring, VRF, HPKE, the ZK SNARK verifiers; the BLS12-381 module alone guards 7 operations). Decomplecting the gate from each precompile's verification logic is the whole design: profile enforcement lives in one function, primitive math stays in its own lane. Bypassing the gate means modifying that one function — a chain compiled with the strict-PQ profile cannot route around it, because there is no second place the policy is expressed. - Cross-profile warp messaging (strict-PQ end ↔ mixed end) requires the strict-PQ end to verify only the Pulsar portion of the proof. The BLS portion is opaque to it; the security boundary is Pulsar.
- Sortition VRF for the per-cert k-of-N committee uses a PQ-safe VRF (cSHAKE256-based). No discrete-log VRF in the sortition path.
- B-Chain bridge custody key shares are Pulsar MPC by default in strict-PQ mode; Corona MPC available as a profile-selectable alternative.
Test cases
TestStrictPQ_ClassicalRefused — every classical precompile returns
ErrClassicalForbiddenInPQ when the
chain reports strict-PQ
TestStrictPQ_PulsarAccepted — Pulsar verify succeeds under strict-PQ
TestZChain_LightClientFollowsOnly — light client constructs state from
Z-Chain proofs alone (no full blocks)
TestWarp_E2E_PQ_Roundtrip — strict-PQ L1 ↔ Lux primary warp
message verifies on both ends with
only PQ primitives on the wire
References
- LP-110: Quasar Consensus
- LP-118: Warp Signature Aggregation Protocol
- FIPS 204: Module-Lattice-Based Digital Signature Standard (ML-DSA)
- FIPS 205: Stateless Hash-Based Digital Signature Standard (SLH-DSA)
- FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism (ML-KEM)
- Boschini-Kaviani-Lai-Malavolta-Takahashi-Tibouchi, IACR ePrint 2024/1113 (Ringtail — the academic two-round lattice threshold; Lux's Corona is the production Module-LWE scheme that follows this construction. Distinct artifacts — do not relabel the paper as "Corona".)
- NIST IR 8528: Status Report on the Fourth Round of the NIST Post-Quantum Cryptography Standardization Process (HQC + Falcon backups)
- proofs/lean/Crypto/Pulsar/ (machine-checked threshold correctness)
- proofs/lean/Crypto/Threshold_Lagrange.lean (shared algebraic core)
- proofs/lean/Crypto/Corona.lean (Module-LWE threshold)
- proofs/lean/Crypto/MLKEM.lean (Module-LWE KEM)
- proofs/lean/Crypto/HQC.lean (code-based KEM, family-disjoint from MLKEM)