Files
consensus/protocol/quasar/wave_signer_test.go
zeekay 24b7cd2154 consensus: route corona + pulsar through threshold/protocols alias
Replaces every direct import of luxfi/corona/* and luxfi/pulsar/ref/go
in consensus with the canonical luxfi/threshold/protocols/{corona,pulsar}
alias surface. Pure import swap + go.mod bump; no behaviour change.

Files touched (16):

  bench/pq_modes_bench_test.go
  engine/pq/crypto.go
  engine/pq/engine.go
  pkg/wire/policies.go
  protocol/quasar/cert_size_compare_test.go
  protocol/quasar/corona_gob.go
  protocol/quasar/dual_threshold_test.go
  protocol/quasar/epoch.go
  protocol/quasar/epoch_test.go
  protocol/quasar/gpu_accel.go
  protocol/quasar/grouped_threshold.go
  protocol/quasar/quasar.go
  protocol/quasar/types.go
  protocol/quasar/wave_signer.go
  protocol/quasar/wave_signer_test.go
  protocol/quasar/witness.go
  protocol/quasar/witness_pulsar_test.go

Import path swaps:

  luxfi/corona/threshold        -> luxfi/threshold/protocols/corona
  luxfi/corona/keyera           -> luxfi/threshold/protocols/corona/keyera
  luxfi/corona/primitives       -> luxfi/threshold/protocols/corona/primitives
  luxfi/corona/reshare          -> luxfi/threshold/protocols/corona/reshare
  luxfi/corona/sign             -> luxfi/threshold/protocols/corona/sign
  luxfi/corona/gpu              -> luxfi/threshold/protocols/corona/gpu
  luxfi/pulsar/ref/go/pkg/pulsar -> luxfi/threshold/protocols/pulsar

The aliased package name "coronaThreshold" used by quasar / engine/pq /
pkg/wire identifiers is preserved at the call sites (it now refers to
the threshold/protocols/corona alias package). engine/pq/crypto.go is
the only file where the package was bare-imported as `threshold`; that
identifier was renamed to `corona` to match the new alias path.

go.mod:

  - luxfi/threshold bumped to a branch pseudo-version that carries the
    new alias subpackages; will pin to a stable tag once threshold's
    companion commit lands and a release is cut.
  - luxfi/corona and luxfi/pulsar drop to indirect (consensus now
    reaches them only via threshold/protocols).
  - luxfi/math v1.4.0 -> v1.4.1 and luxfi/metric v1.5.0 -> v1.5.7 are
    transitive minimum-version bumps pulled by the new threshold
    requirement; they are no-op for consensus call sites.

Comment-only references to "github.com/luxfi/corona/..." in bls.go,
round_digest.go, reshare_epoch.go, comprehensive_test.go,
engine_test.go, quasar_bench_test.go and config/pq_mode.go are
documentation pointers to where the underlying implementation lives;
they are accurate either way and are left unchanged (out of refactor
scope).

Layering shape after:

  consensus -> threshold/protocols/{corona,pulsar}  (stable alias)
                 |
                 v
              luxfi/corona, luxfi/pulsar  (primitive implementations)

Closes the 22-file layering violation flagged by the 2026-05-31
integration audit. Tests pass: ./engine/pq/..., ./pkg/wire/...,
./protocol/quasar/... (all key cases — TestEpochManager*,
TestRoundSigner*, TestVerifyPQFinality*, TestBLSThreshold*,
TestDualSigningFlow, TestCoronaCertSize* — green; the pre-existing
TestGroupedEpochManager_ParallelKeygen perf-bound flake on slow
machines was reproduced on unmodified main, so it is not a
regression).
2026-05-31 12:39:47 -07:00

128 lines
3.6 KiB
Go

// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package quasar
import (
"bytes"
"context"
"crypto/rand"
"testing"
"github.com/luxfi/consensus/protocol/prism"
"github.com/luxfi/ids"
"github.com/luxfi/threshold/protocols/pulsar"
)
// TestRoundSigner_RunRound_ProducesFIPS204Verifiable runs a
// minimal Lux round at (K, T) = (3, 2): three sampled validators
// produce one FIPS 204 ML-DSA signature on a round item, which
// verifies under unmodified pulsar.VerifyCtx (i.e. FIPS 204
// ML-DSA.Verify with the precompile ctx).
func TestRoundSigner_RunRound_ProducesFIPS204Verifiable(t *testing.T) {
params := pulsar.MustParamsFor(pulsar.ModeP65)
// Build a (3, 2) DKG using pulsar directly to set up the
// per-validator KeyShares. This mirrors what a real Lux
// validator-set DKG ceremony would produce at the start of an
// epoch.
committee := []pulsar.NodeID{
{0x01, 0x00, 'V'}, {0x02, 0x00, 'V'}, {0x03, 0x00, 'V'},
}
const n, threshold = 3, 2
// Per-party long-term identity keys (v1.0.7 mandatory CR-6/8 closure).
identities := make(map[pulsar.NodeID]*pulsar.IdentityKey, n)
dirEntries := make(map[pulsar.NodeID]*pulsar.IdentityPublicKey, n)
for i := 0; i < n; i++ {
ik, err := pulsar.GenerateIdentity(rand.Reader)
if err != nil {
t.Fatal(err)
}
identities[committee[i]] = ik
dirEntries[committee[i]] = ik.PublicKey()
}
directory, err := pulsar.NewIdentityDirectory(dirEntries)
if err != nil {
t.Fatal(err)
}
dkg := make([]*pulsar.DKGSession, n)
for i := 0; i < n; i++ {
rng := bytes.NewReader(append([]byte{byte(i)}, bytes.Repeat([]byte{0xDE, 0xAD}, 32)...))
s, err := pulsar.NewDKGSession(params, committee, threshold, committee[i], identities[committee[i]], directory, rng)
if err != nil {
t.Fatal(err)
}
dkg[i] = s
}
r1 := make([]*pulsar.DKGRound1Msg, n)
for i, s := range dkg {
m, err := s.Round1()
if err != nil {
t.Fatal(err)
}
r1[i] = m
}
r2 := make([]*pulsar.DKGRound2Msg, n)
for i, s := range dkg {
m, err := s.Round2(r1)
if err != nil {
t.Fatal(err)
}
r2[i] = m
}
outs := make([]*pulsar.DKGOutput, n)
for i, s := range dkg {
out, err := s.Round3(r1, r2)
if err != nil {
t.Fatal(err)
}
outs[i] = out
}
groupPK := outs[0].GroupPubkey
// Build the RoundSigner's share map keyed by ids.NodeID.
shares := make(map[ids.NodeID]*pulsar.KeyShare, n)
pool := make([]ids.NodeID, n)
for i := 0; i < n; i++ {
var id ids.NodeID
copy(id[:], committee[i][:])
pool[i] = id
shares[id] = outs[i].SecretShare
}
ctxBytes := []byte("lux-evm-precompile-pulsar-v1")
signer := &RoundSigner{
Params: params,
Cut: prism.NewUniformCut(pool),
K: 3,
Threshold: 2,
Shares: shares,
PrecompileCtx: ctxBytes,
}
// Drive one Lux round.
item := []byte("lux-round smoke test item")
res, err := signer.RunRound(context.Background(), item)
if err != nil {
t.Fatalf("RunRound: %v", err)
}
// The result must verify under unmodified FIPS 204 ML-DSA.Verify
// with the precompile ctx -- this is the Class N1 manifesto in
// effect end-to-end through the Wave-driver adapter.
if err := pulsar.VerifyCtx(params, groupPK, item, ctxBytes, res.Signature); err != nil {
t.Fatalf("FIPS 204 verify (with precompile ctx) on RoundSigner output: %v", err)
}
// Signature must NOT verify under a different ctx -- proves ctx
// is load-bearing end-to-end.
if err := pulsar.VerifyCtx(params, groupPK, item, nil, res.Signature); err == nil {
t.Fatalf("expected verify failure under ctx=nil; got nil error")
}
// Suppress the unused rand import in case the test ever reverts.
_ = rand.Reader
}