LPsLux Proposals
Precompiles
LP-4440

Corona — Module-LWE Threshold Signatures (Ringtail-Derived)

Final

Lux's foundational post-quantum threshold-signature scheme and its native verifier precompile — a two-round Module-LWE construction derived from Ringtail (ePrint 2024/1113). The first of the Lux lattice threshold family by development age. Corona and Pulsar (LP-4450) are both Module-LWE; they differ by base signature (Raccoon vs ML-DSA), parameter regime, and codebase — the permissionless lifecycle is shared across all Lux legs, not a distinguisher. Raw precompile 0x012206 per LP-0120.

Category
Core
Created
2025-11-13

Implementation status (code-audited 2026-07-03): SHIPPED corona repo: Module-LWE two-round threshold (Ringtail/Raccoon line), slot 0x012206.

Abstract

Corona is Lux's two-round Module-LWE threshold signature scheme — the foundational member of the Lux lattice threshold-signature family by development age — together with its native EVM verifier precompile. Corona is Lux's first-party fork of Ringtail (IACR ePrint 2024/1113), parameterised over a module of dimension M = 8 × N' = 7 (a public matrix A ∈ R_q^{8×7} over the ring R_q = Z_q[X]/(X^256 + 1), modulus q = 0x1000000004A01). Corona was the first Lux PQ threshold construction implemented; Pulsar (LP-4450) followed, and Magnetar (LP-4540) added a hash-based cross-family leg.

Corona and Pulsar are both Module-LWE threshold schemes. They are not "rank-1 vs rank-k": both operate over a module of rank greater than one. They differ instead by parameter regime, lifecycle, and codebase. Corona is the Ringtail-derived scheme: its own large parameter set, ~33–35 KB signatures, and a permissionless, leaderless distributed key generation built for validator sets that change over time. Pulsar is the production-tuned variant whose parameters make it byte-equal to FIPS 204 ML-DSA-65 (~3.3 KB signatures) for FIPS interoperability. (As a general lattice fact, Ring-LWE is Module-LWE at rank one — but that is not Corona's instantiation; Corona is a genuine module construction at rank ~7–8.)

Corona produces a compact two-round threshold signature (one message-independent precomputation round, one signing round, then a non-interactive combine) and is trustless at both ends: a genuinely dealerless Pedersen-VSS distributed key generation in which no party ever holds the master secret (keyera.BootstrapPedersen, built on the shared luxfi/dkg library), and no-reconstruct t-of-n signing in which the secret is never reassembled — not even transiently at a coordinator (audited and certified in Corona v0.10.0). Hardness is Module-LWE with Module-SIS commitments. It is verified by the raw precompile at 0x012206 (LP-0120): signature ~33–35 KB, verification ~1.6 ms; the combined output verifies under the stock Ringtail/Raccoon verifier (no bespoke threshold verifier). Corona is the natively dealerless intra-lattice diversity leg of the Aurora certificate profile (LP-4900) and the Polaris profile (LP-4910), composed alongside Pulsar under Quasar.

Corona extends the Ringtail two-round lattice threshold construction (IACR ePrint 2024/1113) to public, permissionless validator sets. The academic construction assumes a fixed, known set of parties; Corona's contribution is making it work when validators join and leave permissionlessly — leaderless distributed key generation with no trusted dealer, dynamic resharing across a changing validator set, and on-chain Q-Chain ceremony binding. That is the engineering a public chain needs and an academic threshold scheme does not provide.

Use cases: Quasar consensus validator threshold sigs; threshold wallets; DAO governance; cross-chain bridges; enterprise custody.

Motivation

The Lux PQ-finality stack needs more than one threshold signature primitive so that a structural advance against any single construction does not by itself forge a QuasarCert. Corona is the Ringtail-derived Module-LWE scheme: a well-studied lattice (the same cyclotomic-ring NTT structure as ML-KEM / ML-DSA) and the historical starting point for Lux threshold signing. It is profile-selectable, not the default floor — Pulsar (Module-LWE tuned to FIPS 204 byte-equality) is the strict-PQ floor; Corona adds intra-lattice diversity in Aurora, and Magnetar adds true cross-family (hash) diversity in Polaris. Because Corona and Pulsar are both Module-LWE, their composition in Aurora is implementation-level defence-in-depth (distinct parameters, codebases, samplers), not family-disjoint hardness — see the Rationale.

Specification

Scheme

  • Hardness. Module-LWE (with Module-SIS commitments) over the ring R_q = Z_q[X]/(X^256 + 1), with a module of dimension M = 8 × N' = 7 (public matrix A ∈ R_q^{8×7}; secret s ∈ R_q^{7}; error e ∈ R_q^{8}; b = A·s + e). NIST Category 1.
  • Rounds. Two-round signing: Round 1 (message-independent precomputation / commitment), Round 2 (signing share over the message), then a non-interactive Combine into a single aggregate. Two rounds is optimal — no dealer-free threshold scheme can do better.
  • DKG (genuinely dealerless). Permissionless, leaderless distributed key generation via Pedersen-VSS (keyera.BootstrapPedersen), built on the shared no-reconstruct DKG library luxfi/dkg (VSS share-dealing, equivocation gate, identifiable-abort blame) and anchored to the Q-Chain ceremony root, with a production lifecycle (generation, resharing, snapshots). No party ever holds the master secret s: each party aggregates only its own share, and the group key is finalised from the public aggregate b = A·s + e″ (Path-(a) noise flooding, domain tag CORONA-BOOTSTRAP-PEDERSEN-NOISEFLOOD-v1). Corona is the natively-dealerless leg of the stack.
  • No-reconstruct signing. The t-of-n signing path never forms the full secret s = Σ_j λ_j·s_j, not even transiently at the combiner: each signer emits only a masked partial, SignFinalize sums the masked partials (z_sum = Σ_j z_j), and s appears only as the coefficient of the public challenge c inside the aggregate. Certified in Corona v0.10.0 by structural (AST call-graph), behavioural (no secret-bearing wire field), and independent-verifier gates (threshold/no_reconstruct_sign_test.go). Dealerless keygen + no-reconstruct signing make Corona a strict trustless lane, eligible for the strict-PQ posture.
  • Verifier. Raw precompile 0x012206 (LP-0120). Under the P3Q unified rollup-batch verifier (LP-218 / LP-220) Corona is kind byte 0x02 at slot 0x012205; the raw 0x012206 path remains for non-rollup-batch use.
  • Sizes (LP-0120). Signature ~33–35 KB; verification ~1.6 ms. Corona is not byte-equal to any FIPS standard — that byte-equality is a property of Pulsar (LP-4450), not Corona.

The canonical parameter set is fixed by the reference implementation and its KAT vectors (luxfi/corona, a fork of luxfi/ringtail): ring R_q = Z_q[X]/(X^256 + 1) (degree 256), module dimensions M = 8, N' = 7, modulus q = 0x1000000004A01 (a 48-bit NTT-friendly prime), key-generation Gaussian width σ_E = 6.108, challenge ternary weight κ = 23, rejection bound B = 2^48.6. This LP fixes the role, slot, rounds, DKG model, family relationships, and the precompile ABI below; the sampler internals track the reference code.

Precompile address

0x012206

The raw verifier slot 0x012206 is owned by LP-0120. (Historical note: the original LP-7324 precompile shipped at the EVM-style string address 0x020000000000000000000000000000000000000B; the canonical raw-slot address is 0x012206. See Provenance.)

Input format (packed)

OffsetLengthFieldDescription
04thresholdRequired signers (big-endian uint32)
44totalPartiesTotal participants (big-endian uint32)
832messageHashHash of message
40varsignatureCorona threshold signature (~33 KB per LP-0120)

Minimum size: 40 B + signature.

Signature contents

Round 1 commitments (all signers) + Round 2 lattice-based shares + aggregated threshold signature + participant bitmap.

Output

32-byte word: 0x...0001 valid, 0x...0000 invalid.

Gas

gas = 150,000 + (totalParties × 10,000)

Examples: 3-of-5 → 200,000 gas; 10-of-15 → 300,000; 67-of-100 → 1,150,000.

150K base for Module-LWE verification + 10K per party (commitment verification, share validation, aggregation).

Solidity interface

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ICorona {
    function verifyThreshold(
        uint32 threshold,
        uint32 totalParties,
        bytes32 messageHash,
        bytes calldata signature
    ) external view returns (bool valid);
}

library CoronaLib {
    ICorona constant CORONA = ICorona(0x0000000000000000000000000000000000012206);

    function verifyOrRevert(
        uint32 threshold,
        uint32 totalParties,
        bytes32 messageHash,
        bytes calldata signature
    ) internal view {
        require(
            CORONA.verifyThreshold(threshold, totalParties, messageHash, signature),
            "Corona: invalid threshold signature"
        );
    }

    function estimateGas(uint32 totalParties) internal pure returns (uint256) {
        return 150_000 + (uint256(totalParties) * 10_000);
    }
}

abstract contract CoronaVerifier {
    ICorona internal constant corona = ICorona(0x0000000000000000000000000000000000012206);

    modifier validCoronaSignature(
        uint32 threshold,
        uint32 totalParties,
        bytes32 messageHash,
        bytes calldata signature
    ) {
        require(
            corona.verifyThreshold(threshold, totalParties, messageHash, signature),
            "Invalid Corona threshold signature"
        );
        _;
    }
}

Example

contract ThresholdWallet is CoronaVerifier {
    uint32 public threshold   = 2;
    uint32 public totalOwners = 3;

    function withdraw(
        address to,
        uint256 amount,
        uint256 nonce,
        bytes calldata thresholdSig
    ) external {
        bytes32 txHash = keccak256(abi.encode(to, amount, nonce));
        CoronaLib.verifyOrRevert(threshold, totalOwners, txHash, thresholdSig);
        payable(to).transfer(amount);
    }
}

Rationale

Corona vs other threshold schemes

SchemePost-QuantumRoundsTrusted DealerHardness
CoronaYes2NoModule-LWE (Ringtail-derived; M=8, N'=7)
Pulsar (LP-4450)Yes2NoModule-LWE (FIPS 204 byte-equal)
Magnetar (LP-4540)YesNoHash (SLH-DSA, FIPS 205)
FROSTNo2NoDiscrete Log
CGGMP21No5+NoDiscrete Log
BLSNo1YesPairing

Corona and Pulsar (LP-4450) are both Module-LWE constructions; they differ by base signature (Raccoon vs ML-DSA), parameter regime, and codebase — not by module rank, and not by lifecycle (the permissionless, leaderless, dynamically-resharable adaptation is shared across Corona, Pulsar, and Magnetar). Pulsar ‖ Corona is therefore implementation-level defence-in-depth (different code, different parameter sets, different rejection samplers), not family-disjoint hardness — a structural advance against the cyclotomic-ring module lattice problem could in principle touch both legs. Magnetar (hash) is the only true cross-family leg. Among classical comparators, FROST cost is ~50K + 5K per signer; Corona is the price of quantum resistance on the same dealer-free, two-round profile.

Provenance and lineage

Corona is Lux's first-party fork of Ringtail (IACR ePrint 2024/1113, IEEE S&P 2025), which thresholdizes the Raccoon signature family — a masking-friendly Fiat–Shamir-with-aborts Module-LWE scheme, distinct from Dilithium/ML-DSA, with a 48-bit modulus chosen for threshold-friendly rounding. Ringtail builds on Threshold Raccoon (EUROCRYPT 2024) and adapts the random-linear-combination and full-rank-commitment techniques of MuSig-L (CRYPTO 2022) and FROST; it is the standard-assumption counterpart of EKT (Espitau–Katsumata–Takemure, CRYPTO 2024), which relied on the non-standard algebraic one-more LWE assumption. Corona's parameters are bit-identical to Ringtail's 128-bit set (paper Table 2): ring degree N=256, q = 2^48 + 2^14 + 2^11 + 2^9 + 1 = 0x1000000004A01, (N', M, D̄) = (7, 8, 48), κ=23, σ=6.108. Its full proof reduces to self-target Module-SIS and Hint-Module-LWE, both reducing to standard Module-LWE / Module-SIS.

The name "Ringtail" is the raccoon-family mammal (the scheme thresholdizes Raccoon) — not a reference to Ring-LWE. Corona is Module-LWE at module rank 7 (a genuine matrix A ∈ R_q^{8×7}); it would coincide with Ring-LWE only in the degenerate rank-1 case, which it does not use.

A Corona signature is therefore a Raccoon signature and does not verify under FIPS 204. The Corona↔Pulsar split is at the base signature: Corona thresholdizes Raccoon (standard-assumption, practical, not FIPS-compatible), whereas Pulsar (LP-4450) thresholdizes ML-DSA/Dilithium to stay byte-equal to FIPS 204 — the harder, FIPS-compatible target, since ML-DSA's rejection sampling and hint bits do not split cleanly across parties.

Two rounds

Optimal — no threshold scheme can do better than 2 rounds without a trusted dealer.

Quasar integration

Corona provides the intra-lattice diversity leg of Quasar certificate profiles: Aurora (LP-4900) is Pulsar ‖ Corona, Polaris (LP-4910) is Pulsar ‖ Corona ‖ Magnetar. The Pulsar leg (LP-4450) is the PQ floor; Corona is composed alongside it by reference under Quasar (LP-0110), never redefined there.

Backwards Compatibility

New precompile; no compatibility issues. Migration from classical threshold (FROST/CGGMP21) — dual signatures during transition, then migrate keys to a PQ scheme (Corona or Pulsar), then deprecate the classical leg.

Test Cases

Test 1 — Valid 2-of-3. Input: threshold=2, totalParties=3, messageHash = keccak256("Test message for threshold signature"), valid signature from 2 of 3. Output: 0x...0001. Gas: 180,000.

Test 2 — Insufficient signers (1-of-3). Threshold=2 but signature from 1 party. Output: 0x...0000.

Test 3 — Invalid share. Threshold=2, totalParties=3, one corrupted share. Output: 0x...0000.

Test 4 — Large threshold (67-of-100). Output: 0x...0001. Gas: 1,150,000.

Reference Implementation

Stack:

Solidity Interface
  ICorona.sol → CoronaLib.sol → CoronaVerifier.sol
         │ staticcall
EVM Precompile (Go)
  precompile/corona/contract.goRun() → Verify()
         │ calls
Corona Protocol (Go)
  corona/ → 2-round threshold + DKG + Shamir over Module-LWE
         │ uses
Lattice Primitives
  lattice/ → Module-LWE, Module-SIS, NTT (matrix A ∈ R_q^{8×7})

EVM precompile — ~/work/lux/precompile/corona/

FileLinesPurpose
contract.go257Precompile at raw slot 0x012206
module.go50EVM registration
contract_test.go236Test suite
ICorona.sol288Solidity interface + library
README.md501Docs

Corona protocol — ~/work/lux/corona/

PathPurpose
keyera/bootstrap_pedersen.goDealerless Pedersen-VSS key-era bootstrap (BootstrapPedersen) — no party holds s; share-dealing + blame via luxfi/dkg
keyera/Key-era lifecycle (generation, resharing, snapshots; Path-(a) noise-flood finalize)
threshold/threshold.got-of-n threshold signer over Module-LWE (ring via lattice/v7)
threshold/no_reconstruct_sign_test.goNo-reconstruct certification (AST call-graph + behavioural + independent-verifier gates)
sign/sign.go2-round signing; SignFinalize sums masked partials (no secret s formed)
sign/verify.goNon-destructive stock verification
sign/aggregate.goThreshold aggregation
sign/types.goSignature + public key types
share/lagrange.goLagrange coefficients (λ_j) for masked-share aggregation
network/Party communication

Core functions:

// Dealerless key-era bootstrap (no trusted dealer; no party ever holds s):
func BootstrapPedersen(suite hash.HashSuite, t int, validators []string,
    groupID CoronaGroupID, eraID CoronaKeyEraID, entropy io.Reader,
) (*KeyEra, *BootstrapTranscript, error)

// No-reconstruct t-of-n signing (combiner sums masked z partials; s never formed):
func SignRound1(share *Share, message []byte) (*Round1Output, error)
func SignRound2(share *Share, round1Outputs []*Round1Output) (*SignatureShare, error)
func SignFinalize(z map[int]Vector, ...) (Signature) // z_sum = Σ_j z_j
func Verify(groupKey *GroupKey, message []byte, sig *Signature) bool

Lattice primitives — ~/work/lux/lattice/

PathPurpose
ring/ring.goCyclotomic ring R_q = Z_q[X]/(X^256 + 1)
ring/ntt.goForward NTT
ring/intt.goInverse NTT
mlwe/sample.goDiscrete Gaussian sampling
mlwe/keygen.goModule-LWE key generation (matrix A ∈ R_q^{8×7})
mlwe/commit.goModule-LWE commitment (b = A·s + e)
sis/hash.goModule-SIS commitment hash
params/Security parameters

Module-LWE parameters (NIST Category 1; the real symbol names from luxfi/corona sign/config.go):

const (
    M    = 8                  // Module rows  (public matrix A ∈ R_q^{M×N})
    N    = 7                  // Module cols  (secret s ∈ R_q^{N})
    LogN = 8                  // Ring degree 2^LogN = 256 → R_q = Z_q[X]/(X^256+1)
    Q    = 0x1000000004A01    // 48-bit NTT-friendly prime (q ≡ 1 mod 2·256)
)
// Gaussian width σ_E = 6.108, challenge ternary weight κ = 23,
// rejection bound B ≈ 2^48.6 (Ringtail 128-bit set, paper Table 2).
// LWE dimension d = M·256 = 2048; BKZ blocksize β ≈ 430.
// Classical ~2^142; quantum (Grover-enhanced sieving) ~2^130.

Note: in sign/config.go the symbol N = 7 is the module-column count (not the ring degree); the ring degree is 2^LogN = 256. Earlier drafts of this LP overloaded N for both — corrected here to the shipped names.

Quasar integration — ~/work/lux/consensus/protocol/quasar/

FilePurpose
epoch.goEpochManager (Corona key rotation)
corona.goThreshold Corona signing for finality certs
hybrid_consensus.goMulti-cert finality (BLS + lattice legs)
epoch_test.go8 epoch tests

EpochManager:

type EpochManager struct {
    currentEpoch      uint64
    currentKeys       *EpochKeys
    lastKeygenTime    time.Time
    epochHistory      map[uint64]*EpochKeys  // cross-epoch verify
    historyLimit      int                     // default 3
    currentValidators []string
    threshold         int
}

const (
    MinEpochDuration = 1  * time.Hour   // rate limit
    MaxEpochDuration = 24 * time.Hour   // forced rotation
    HistoryLimit     = 3                // epochs preserved
)

func (em *EpochManager) VerifySignatureForEpoch(message string, sig *Signature, epoch uint64) bool

Tests passing

  • Precompile: valid threshold sig, insufficient threshold rejection, invalid share detection, large threshold (10-of-15), gas verification, edge cases.
  • Protocol: 2-round correctness, t-of-n aggregation, non-malleability, cross-party verification.
  • Epoch: creation/rotation, cross-epoch verify, rate-limit enforcement, history pruning.

Machine-checked proofs

proofs/lean/Crypto/Corona.lean (Module-LWE threshold correctness) over proofs/lean/Crypto/Threshold_Lagrange.lean (shared algebraic core).

Repositories

ComponentRepository
Precompilegithub.com/luxfi/precompile/corona/ (raw slot 0x012206)
Corona librarygithub.com/luxfi/corona/ (v0.10.1)
Shared no-reconstruct DKGgithub.com/luxfi/dkg/ (v0.2.0 — Pedersen-VSS + blame)
Lattice primitivesgithub.com/luxfi/lattice/v7 (v7.1.0)
C/C++/GPU backendsluxcpp/crypto/corona/ (CUDA / Metal / WGSL)
Epoch / Quasar finalitygithub.com/luxfi/consensus/protocol/quasar/
Solidity interface~/work/lux/standard/contracts/precompiles/corona/

Security Considerations

Quantum

Module-LWE hardness — no efficient quantum algorithm. Module-SIS for commitments — also quantum-resistant. NIST Category 1 (~128-bit classical, ~130-bit quantum); worst-case lattice reduction over the module.

Threshold

Safety: adversary controlling < threshold parties learns NOTHING about the private key; corrupted shares don't help forge. Liveness: any threshold parties produce a signature; robust against n − threshold offline.

Distributed key generation (dealerless) and no-reconstruct signing

Keygen (keyera.BootstrapPedersen, over luxfi/dkg):
  1. Each party deals a Pedersen-VSS sharing of its own contribution.
  2. Equivocation gate + Pedersen verification; identifiable-abort blame.
  3. Each party aggregates ONLY its own share s_j of the master s.
  4. Group key from the public aggregate b = A·s + e″ (noise-flooded).
     → No party ever holds s (no-reconstruct keygen).

Signing (no-reconstruct):
  1. Each signer emits a masked partial z_j (its share + Lagrange coeff λ_j).
  2. SignFinalize sums masked partials: z_sum = Σ_j z_j.
  3. s = Σ_j λ_j·s_j appears ONLY as the coefficient of the public c.
     → No party/coordinator ever forms s, even transiently.

Neither keygen nor signing reconstructs the master secret. This is the strict trustless-lane property certified in Corona v0.10.0 (threshold/no_reconstruct_sign_test.go: AST call-graph + behavioural + independent-verifier gates, with negative controls).

Side-channel

Constant-time lattice ops; blinded share generation; secure memory clearing; no timing-dependent branches.

Quantum attack scenarios

AttackClassicalPost-Quantum
Break one shareSafe (DL)Safe (Module-LWE)
Break thresholdSafe (DL)Safe (Module-LWE)
Break commitmentSafe (hash)Safe (Module-SIS)
Forge signatureSafe (DL)Safe (Module-LWE)
Shor's algorithmBreaks DLModule-LWE unaffected

Key management

Shares stored encrypted at rest; never combined; rotated periodically (forward security); backed up redundantly (liveness); HSM/TEE when possible.

Epoch-based rotation

ConstantValuePurpose
MinEpochDuration1 hourRate limit
MaxEpochDuration24 hoursForced rotation
HistoryLimit3 epochsCross-epoch verify window

Triggers: validator-set change (rate-limited to 1/hour); forced expiration at 24 h; manual RotateEpoch(validators, force=true). Counter is uint64 → 2.1 trillion years at 1/hr.

func (em *EpochManager) RotateEpoch(validators []string, force bool) error {
    if !force && time.Since(em.lastKeygenTime) < MinEpochDuration {
        return ErrTooSoon
    }
    if time.Since(em.lastKeygenTime) > MaxEpochDuration {
        force = true
    }
    groupKey, shares := coronaDKG(validators, threshold)
    em.pruneHistory()
    return nil
}

Multi-leg certificate finality

Corona is one lattice leg of a Quasar certificate profile (BLS fast lane

  • Pulsar PQ floor + Corona intra-lattice diversity). Every configured leg must validate for finality:
func ValidateBlock(block *Block) bool {
    if !bls.Verify(block.BLSSignature)       { return false }
    if !corona.Verify(block.CoronaSignature) { return false }
    return true
}

Secure contract usage

// GOOD: verify before state changes
function withdraw(bytes calldata sig) external {
    require(corona.verify(sig), "Invalid sig");
    // safe state modification
}

// BAD: state change before verification (reentrancy)
function withdraw(bytes calldata sig) external {
    updateState();
    require(corona.verify(sig), "Invalid sig");
}

Replay-protected vault example:

contract QuantumSafeVault is CoronaVerifier {
    uint32 public threshold;
    uint32 public totalOwners;
    mapping(bytes32 => bool) public usedNonces;

    function withdraw(
        address to,
        uint256 amount,
        uint256 nonce,
        bytes calldata sig
    ) external nonReentrant {
        bytes32 messageHash = keccak256(abi.encode(
            "CoronaVault-v1",
            block.chainid,
            address(this),
            to, amount, nonce
        ));
        require(!usedNonces[messageHash], "Nonce already used");
        usedNonces[messageHash] = true;
        CoronaLib.verifyOrRevert(threshold, totalOwners, messageHash, sig);
        (bool success,) = to.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

Network usage map

ComponentLocationUsage
Precompileprecompile/corona/On-chain verification
Corona librarycorona/Threshold signing
Lattice primitiveslattice/Module-LWE, Module-SIS, NTT
Epoch managementconsensus/protocol/quasar/epoch.goValidator key rotation
Quasar finalityconsensus/protocol/quasar/hybrid_consensus.goMulti-cert finality
C-Chainnode/vms/coreth/Smart-contract verification
Bridge custodynode/bridges/PQ bridge security
Warp messagingnode/vms/platformvm/warp/Cross-chain (L1 / L2) PQ sigs

Economic Impact

Gas comparison:

Scheme3-of-510-of-15Security
Corona200,000300,000Post-quantum
FROST75,000125,000Classical
CGGMP21125,000225,000Classical

2-3× higher gas for quantum security. Worth it for high-value assets (> $1M), long-term storage (> 5y), critical infrastructure, regulated PQ. For Quasar validators using the Aurora/Polaris profiles: ~200K gas per Corona verification per block, $0.01-$0.10 cost.

Implementation Notes

import "github.com/luxfi/corona/sign"

func verifyCorona(threshold, totalParties uint32, msgHash []byte, sig []byte) bool {
    return sign.Verify(sig, msgHash, threshold, totalParties)
}

Corona package: 2-round signing, distributed keygen, Shamir, NTT-based polynomial ops, network stack.

Parameter validation: threshold > 0; threshold ≤ totalParties; totalParties ≥ 2; recommended threshold ≥ totalParties/2 + 1 (honest majority); maximum totalParties ≤ 1000 (practical). Byzantine threshold: threshold > totalParties × 2/3; liveness: totalParties − threshold < totalParties/3. Optimal: 67-of-100.

Provenance

Corona is the first Lux lattice threshold scheme by development age. This LP is the canonical, comprehensive Corona specification (scheme + precompile).

Renumbering history. The construction was first specified as LP-7324 ("Corona Threshold Signature Precompile") and shipped at the EVM-style string address 0x020000000000000000000000000000000000000B. During the unified-4xxx crypto consolidation it was briefly mis-titled "Pulsar" at LP-4440 (a labelling error: the body was always two-round / luxfi/corona / 0x012206 Corona content). LP-4440 is now corrected to its true identity — Corona — and the canonical raw verifier slot is 0x012206 (owned by LP-0120). A separate, clean Corona algorithm stub previously lived at LP-4470; LP-4440 is now the single canonical Corona LP. The LP-7324 slot remains a permanent pointer to LP-4440.

Family relationships. Corona and Pulsar (LP-4450) are both Module-LWE threshold signatures; they differ by parameter regime, lifecycle, and codebase, not by module rank. Corona is the Ringtail-derived scheme (large ~33–35 KB signatures, permissionless leaderless DKG); Pulsar is the production-tuned variant whose parameters make it byte-equal to FIPS 204 ML-DSA-65 (~3.3 KB) and is the strict-PQ floor. Corona and Magnetar (LP-4540, hash-based) are profile-selectable diversity legs. The three are composed by the Aurora (LP-4900, Pulsar ‖ Corona) and Polaris (LP-4910, Pulsar ‖ Corona ‖ Magnetar) certificate profiles under Quasar.

Academic origin. Corona is Lux's first-party fork of Ringtail (IACR ePrint 2024/1113), a practical two-round Module-LWE threshold signature. Corona is Lux's distinct production scheme: cite ePrint 2024/1113 for the construction and luxfi/corona for the scheme — they are separate artifacts. (Earlier drafts mislabelled the academic paper as "Corona" and mis-attributed it to Pulsar; corrected here — Corona is the Ringtail-derived fork.)

References

  • Boschini, Kaviani, Lai, Malavolta, Takahashi, Tibouchi, Ringtail: Practical Two-Round Threshold Signatures from LWE (IACR ePrint 2024/1113; IEEE S&P 2025). The two-round Module-LWE threshold construction Corona forks.
  • Module-LWE: Langlois, Stehlé, Worst-Case to Average-Case Reductions for Module Lattices (Designs, Codes and Cryptography 2015).
  • Implementation: github.com/luxfi/corona (v0.10.2, a fork of github.com/luxfi/ringtail), precompile/corona/.
  • Shared base: github.com/luxfi/dkg (the one no-reconstruct Pedersen-VSS DKG library) and github.com/luxfi/mlwe (v0.2.1) are both consumed by Corona and Pulsar (LP-4450) — the one-and-one-way DRY base. As of corona v0.10.2 Corona consumes mlwe/transcript (SP 800-185 cSHAKE/KMAC) and mlwe/share (Shamir Lagrange + prime field) — a byte-preserving de-dup (19/19 KAT oracles byte-identical). Corona's ring arithmetic stays github.com/luxfi/lattice/v7 (its 48-bit Ringtail ring); only mlwe's FIPS-204 23-bit ring (mlwe/ring/mldsa) is Pulsar-specific — wrong modulus for Corona's 48-bit ring, so Corona does not consume that one package.
  • LP-0120: Quasar mainnet defaults — owns raw slot 0x012206.
  • LP-4400: ML-DSA family root (non-threshold PQ sig).
  • LP-4450: Pulsar — Module-LWE threshold ML-DSA, FIPS 204 byte-equal (the production-tuned Module-LWE sibling of Corona).
  • LP-4540: Magnetar — hash-based threshold SLH-DSA (cross-family leg).
  • LP-4900 / LP-4910: Aurora / Polaris certificate profiles.
  • LP-4710: FROST (classical threshold for comparison).
  • LP-4720: CGGMP21 (classical ECDSA threshold).

Copyright and related rights waived via CC0.