Corona is a Module-LWE threshold signature (Ringtail/Raccoon line,
ePrint 2024/1113; module dims M=8, N=7 over Z_q[X]/(X^256+1), rank>1).
Pulsar is Module-LWE (FIPS-204 ML-DSA). Neither is Ring-LWE; the "M"
in ML-KEM/ML-DSA is Module.
Fixes the 0x012206 slot-map comments (p3q, magnetar, starkfri,
modules/registerer), the Corona precompile doc comments, the registry
CORONA description string, and the README/LLM/corona-README docs.
Comments, strings, and docs only — no identifier, precompile address,
selector, gas value, or on-chain digest changed.
P3Q (0x012205) is the rollup-commit PQ verifier (kind-byte dispatch to
Pulsar/Corona/Magnetar), NOT a STARK — STARK-FRI is at 0x012220. Correct
three stale comments (magnetar, modules/registerer, fhe/dos_audit) that
labeled 0x012205 a STARK. Align the registry.go C-nibble doc-comment to
the authoritative node/genesis/builder/registry.go: remove phantom
M-Chain, add D-Chain at C=3, mark Zoo/Hanzo/SPC as sovereign-L1 EVM.
Comments only; no constant or VM logic changed. Builds clean.
0x9999 — the native C<->D atomic DEX settlement money path — is now ALWAYS-ON:
present + active on every chain that loads the EVM plugin, from genesis, with NO
dexSettleConfig genesis/upgrade entry. This is the production-launch design; the
per-net config-gate is killed. Forward-perfect, one activation way.
Activation: modules.Module gains an AlwaysOn flag (+ modules.AlwaysOnModules()).
SettleModule sets AlwaysOn=true. The Configurator is retained only to satisfy the
interface; for an always-on module the host never invokes Configure (no activating
config). SettleConfig collapses to a parameter-free {Upgrade} marker that always
Verifies — 0x9999 takes no per-net parameters.
Params resolved at RUNTIME, not config (Configure has no consensus context, so it
cannot resolve them):
- protocolFeeController: built-in DefaultDAOTreasury (set in init). One canonical
DAO governance authority across every network; not a compromised dev key.
- networkID / cChainID: already sourced at runtime via contract.AtomicState.
- dChainID (THE crux): contract.AtomicState gains DChainID(). The 4 native-client
sites that read loadDChainTarget(stateDB) now read atomicState.DChainID(), which
the host resolves from the chain topology (consensus-context "D"/dexvm alias).
ids.Empty (no dexvm on this network) closes the seam — fail-secure, no mint.
Money-path logic is byte-for-byte unchanged: DeriveIntentID/DerivePositionCommitID,
lock/stage/credit, conservation, exactly-once, rail discriminator, FIX-2 one-batch
flush, nonReentrant/custody guards all untouched. The ONLY change is HOW the
precompile activates and obtains its params (runtime, not config). The Empty-dChain
revert is preserved (strengthened: SubmitSwapIntent/SubmitPositionCommit now revert
on Empty instead of falling back to the C-Chain's own id).
Dead config machinery removed (one way, no dead code): SetSettle{ChainIdentity,
DChainTarget}, loadDChainTarget, loadSettleChainIdentity, cfg{Net,CChain,DChain}IDKey
slots, the STM read-set entries for them, and the now-unused kvAdapter Configure bridge.
Tests: full dex suite 335/335 PASS, 0 fail, 0 skip (CGO_ENABLED=0; the test binary's
only CGO dep is luxfi/accel, unrelated to the pure-Go money path). Harness feeds the
D peer via the runtime AtomicState capability, mirroring production exactly — proof
that the money path is intact with zero config.
go.sum: reconcile e2e threshold v1.9.4 to the origin-canonical hash (upstream re-tag).
DEX module previously defaulted ProtocolFeeController to Anvil/Foundry
account #0 (0xf39Fd6...92266) whose private key
(0xac0974...80) is in every Foundry user's ~/.foundry. At Quasar Edition
activation, any random caller could have invoked PauseDEX, ResumeDEX,
or the irreversible FreezePool on the chain-wide AMM precompile — a
chain-wide compromise the cryptographer review caught.
Fix is a fail-closed activation gate:
- dex/module.go::Configure() returns ErrDEXNoProtocolFeeController when
upgrade.json dexConfig omits protocolFeeController (zero address).
luxd will refuse to advance past the activation block until the
operator populates the field with a real KMS-controlled multisig.
- compromisedDevControllers map blocks all ten Anvil deterministic
accounts; any explicit attempt to install a public dev key fails with
ErrDEXCompromisedController (the address is included in the error).
- dex/dex_test.go covers: zero-address rejection, all 10 anvil
addresses rejected, a real address activates cleanly, random callers
cannot invoke admin functions even with a real controller, and the
Configure interface still returns *Config.
Same audit pass also wires three previously-stub-only precompiles into
the modules.RegisterModule registry so upgrade.json can gate them:
- kzg4844 (LP-3665 KZG point-evaluation extensions, ConfigKey=kzg4844Config)
- ed25519 (LP-3211, ConfigKey=ed25519Config) — Solana/TON/XRP signature
verify lands as a first-class registered precompile alongside the
legacy NewModule() metadata wrapper.
- secp256r1 (EIP-7212 P256-verify, ConfigKey=secp256r1Config) — stateful
adapter wraps the existing Contract.Run(input) into a contract
StatefulPrecompiledContract that does gas deduction and strict-PQ
refusal uniformly.
- modules/registerer.go extends reservedRanges with 0x100-0x1FF
(post-EVM-standard EIP band, for P256) and 0x32000...0000 to
0x32FF000...0000 (high-byte LP-3xxx classical-signature page, for
ed25519). Both ranges are narrow enough that no other precompile
family overlaps.
router precompile audit: no Anvil default existed there (RouterConfig
already used zero-as-skip semantics rather than zero-as-default).
Tests:
go test -count=1 -race -timeout 120s ./dex/... ./kzg4844/... \\
./ed25519/... ./secp256r1/... ./modules/...
All pass; full ./... suite (49 packages) green.
Magnetar is the threshold sibling of SLH-DSA in the LP-4200 unified PQCrypto
block. The construction (Pedersen-VSS DKG + MPC evaluation over the WOTS+/
FORS/Merkle signing tree of FIPS 205) produces a signature byte-equal to a
single-party FIPS 205 signature on the same message and group public key.
The precompile dispatches to luxfi/crypto/slhdsa.VerifySignatureCtx under
the hood — the verifier is interchangeable with single-party SLH-DSA. The
dedicated slot 0x012207 binds the verification to "this signature came
from a threshold ceremony" for on-chain code that cares about the binding,
provides gas-tier separation, and reserves the slot for future non-FIPS-
205 verification paths (identifiable-abort hint, aggregated-cert envelope).
Mirrors the pulsar precompile shape (threshold ML-DSA at 0x012204) and the
slhdsa precompile shape (single-party SLH-DSA at 0x012203). All 12 FIPS 205
parameter sets (SHA2/SHAKE × 128/192/256 × s/f) are accepted with the same
per-mode gas schedule as slhdsa.
Tests pin the canonical address, exercise the per-mode gas table, reject
short / unsupported-mode inputs, round-trip a valid FIPS 205 signature
through the precompile, and confirm a flipped signature byte yields the
0x00 result word.
The pre-LP-4200 quasar package was a tangle:
- verklePrecompile shipped a forgeable oracle (rip-shipped in commit b0803ae)
- blsPrecompile + blsAggregatePrecompile + coronaPrecompile + hybridPrecompile + compressedPrecompile were classical-crypto contracts living in the 0x0300..0020-25 slots — overlapping the 0x0300-0x03FF range that AI Mining officially owns
- quasar/module.go only registered the (forgeable) verkle slot; the other 5 were declared but unwired
All 6 precompiles now refuse-and-deprecated; the LP-4200 0x012200 block (ML-KEM, ML-DSA, SLH-DSA, Pulsar, P3Q, Corona) is the canonical PQ home.
Rip:
- precompile/quasar/ deleted (IQuasar.sol, contract.go, contract_test.go, module.go)
- blank-import dropped from lux/chains/evm/main.go + liquidity/evm/main.go
- modules/registerer.go: AI Mining is now sole owner of 0x0300-0x03FF; comment updated to record the quasar retirement so future readers know not to re-claim the range.
Neither pulsar/ nor p3q/ had a module.go. ML-DSA / ML-KEM / SLH-DSA /
Corona each had an init() that calls modules.RegisterModule(...) at
import time — that's how the registry binds the precompile's
Configurator + Contract to its Address. Without a module.go for
pulsar + p3q, neither was reachable from chain transactions; calling
the address fell through to 'no code' (silently returned empty,
caller saw 'verification = 0').
The Pulsar slot is the canonical Module-LWE threshold signature
verifier in the LP-4200 block — the StrictPQ profile's primary
threshold-signing path. P3Q is the strict-PQ STARK proof verifier
for the family canonical Plonky3-fork backend.
Add module.go for both, mirroring the mldsa/corona pattern:
configurator + Config + init() registering against the canonical
address. Tests pass for both packages.
Also update modules/registerer.go to document the full 0x012200
block (was only listing through Corona-Threshold=0x12204; now
explicit through 0x12206 Corona).
Per LP-4200 unified PQCrypto block:
- ML-KEM 0x012201 (was 0x0200...0007)
- ML-DSA 0x012202 (was 0x0200...0006)
- SLH-DSA 0x012203 (was 0x0600...0001)
- Corona 0x012204 (was 0x0200...000B)
Adds LP-12xxx range (0x012000-0x012FFF) to modules/registerer
whitelist so the new block validates as in-range.
LLM.md updated to mark legacy 0x0600 / 0x0800 ranges as superseded
by the unified block.
Solidity callers updated in luxfi/standard (#59).
Spec docs reconciled in lp-3500/lp-3520 (#61).