Files
threshold/protocols/pulsar/pulsar.go
zeekay 8d5b2309db protocols/{corona,pulsar}: extend alias surface for consensus consumers
Adds the re-exports luxfi/consensus needs through the canonical
threshold/protocols alias surface so the consensus engine no longer
imports luxfi/corona/* or luxfi/pulsar/ref/go directly.

Protocols/corona top-level gains Params, NewParams, GenerateKeys,
VerifyBatch, VerifyBatchAll forwards on top of the existing
Signer/KeyShare/GroupKey/Round1Data/Round2Data/Signature/Verify/
NewSigner type aliases.

New subpackages mirror the luxfi/corona namespace:

  protocols/corona/keyera     -> luxfi/corona/keyera
  protocols/corona/primitives -> luxfi/corona/primitives
  protocols/corona/reshare    -> luxfi/corona/reshare
  protocols/corona/sign       -> luxfi/corona/sign
  protocols/corona/gpu        -> luxfi/corona/gpu

A new protocols/pulsar subpackage mirrors luxfi/pulsar/ref/go/pkg/pulsar
covering Mode constants, Params/ParamsP{44,65,87}/ParamsFor, the
key/share/signature types, identity layer (IdentityKey,
IdentityDirectory, SymmetricSession, GenerateIdentity), two-round
threshold signing (ThresholdSigner, NewThresholdSigner, Combine),
DKG (DKGSession, NewDKGSession, DKGOutput, DKGRound1Msg, DKGRound2Msg),
and the single-party FIPS 204 baseline (GenerateKey, Sign, VerifyCtx).

The re-exports are type aliases and thin function forwards; no
behaviour change. The underlying corona kernel and pulsar reference
implementation are unchanged.

go.mod bumps luxfi/corona v0.4.1 -> v0.7.5 (needed for the gpu
subpackage, which appeared at v0.7.2) and adds luxfi/pulsar v1.0.12
matching the consensus consumer. Pre-existing prometheus-stack indirect
deps stripped by go mod tidy because the metric sweep already removed
the direct consumer.

Closes the 22-file layering violation flagged by the 2026-05-31
integration audit. The consensus consumer that target these new
alias paths lands in a companion commit on luxfi/consensus.

Layering shape after:

  consensus -> threshold/protocols/{corona,pulsar}  (stable alias)
                 |
                 v
              luxfi/corona, luxfi/pulsar  (primitive implementations)
2026-05-31 12:37:54 -07:00

243 lines
8.6 KiB
Go

// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package pulsar re-exports github.com/luxfi/pulsar/ref/go/pkg/pulsar
// through the threshold/protocols alias surface. Downstream consumers
// (luxfi/consensus) target this import path so the consensus engine
// does not depend directly on the pulsar reference-implementation
// module.
//
// The Pulsar headline claim: a signature produced by an n-of-t
// threshold ceremony verifies under unmodified FIPS 204 ML-DSA.Verify
// (NIST MPTC Category N1). See the upstream package's spec for the
// formal claim and the byte-equality reductions.
//
// Layering shape:
//
// consensus → threshold/protocols/pulsar ← stable alias surface
// ↓
// luxfi/pulsar/ref/go/pkg/pulsar ← reference math kernel
//
// The re-exports here are type aliases and thin function forwards; no
// behaviour change. The set of re-exports covers the surface that
// consensus's quasar / witness / wave-signer / pq-engine code paths
// consume. Adding symbols is allowed when a new consumer needs them;
// removing or renaming is a breaking change to the alias contract.
package pulsar
import (
"io"
"github.com/luxfi/pulsar/ref/go/pkg/pulsar"
)
// ---------------------------------------------------------------------
// Parameter set: NIST FIPS 204 ML-DSA modes.
// ---------------------------------------------------------------------
// Mode is the ML-DSA parameter set identifier (FIPS 204 §4 Table 1).
// Aliased to the kernel type so constants below retain their typed
// identity across the alias boundary.
type Mode = pulsar.Mode
const (
// ModeUnspecified rejects every operation; included so the zero
// value of Mode does not silently map to a real parameter set.
ModeUnspecified = pulsar.ModeUnspecified
// ModeP44 targets FIPS 204 ML-DSA-44 (NIST PQ Category 2).
ModeP44 = pulsar.ModeP44
// ModeP65 targets FIPS 204 ML-DSA-65 (NIST PQ Category 3).
// This is the Lux-default identity / threshold mode.
ModeP65 = pulsar.ModeP65
// ModeP87 targets FIPS 204 ML-DSA-87 (NIST PQ Category 5).
ModeP87 = pulsar.ModeP87
)
// Params bundles the lattice / sampler / wire parameters for one
// FIPS 204 mode. Aliased to the kernel type.
type Params = pulsar.Params
// ParamsP44 / P65 / P87 are the pre-built parameter blocks. Aliased
// to the kernel singletons so they retain pointer identity across the
// alias boundary (downstream callers that compare *Params by pointer
// for cache-keying see the same pointer either way).
var (
ParamsP44 = pulsar.ParamsP44
ParamsP65 = pulsar.ParamsP65
ParamsP87 = pulsar.ParamsP87
)
// ParamsFor returns the parameter block for a Mode. Returns an error
// for ModeUnspecified or an unrecognised mode.
func ParamsFor(mode Mode) (*Params, error) {
return pulsar.ParamsFor(mode)
}
// MustParamsFor panics on an unrecognised mode; for test code only.
func MustParamsFor(mode Mode) *Params {
return pulsar.MustParamsFor(mode)
}
// ---------------------------------------------------------------------
// Keys, shares, signatures, transcript types.
// ---------------------------------------------------------------------
// NodeID is the 32-byte party identifier the kernel uses across
// identity / DKG / signing protocols.
type NodeID = pulsar.NodeID
// PublicKey, PrivateKey, KeyShare, Signature are the wire types
// for FIPS-204-byte-equal signing under a Pulsar group key.
type (
PublicKey = pulsar.PublicKey
PrivateKey = pulsar.PrivateKey
KeyShare = pulsar.KeyShare
Signature = pulsar.Signature
)
// Round1Message and Round2Message are the wire types for the two-round
// threshold signing protocol.
type (
Round1Message = pulsar.Round1Message
Round2Message = pulsar.Round2Message
)
// ---------------------------------------------------------------------
// Identity layer: long-term keys, directory, session derivation.
// ---------------------------------------------------------------------
// IdentityKey and IdentityPublicKey are the long-term keypair types
// each party holds across DKG / signing sessions.
type (
IdentityKey = pulsar.IdentityKey
IdentityPublicKey = pulsar.IdentityPublicKey
)
// IdentityDirectory maps NodeID to the long-term public identity key
// of that party. Returned by NewIdentityDirectory.
type IdentityDirectory = pulsar.IdentityDirectory
// GenerateIdentity samples a fresh long-term identity keypair.
func GenerateIdentity(rng io.Reader) (*IdentityKey, error) {
return pulsar.GenerateIdentity(rng)
}
// NewIdentityDirectory wraps a NodeID → IdentityPublicKey map in the
// kernel's IdentityDirectory type (with the canonical ordering
// invariants the kernel relies on).
func NewIdentityDirectory(entries map[NodeID]*IdentityPublicKey) (IdentityDirectory, error) {
return pulsar.NewIdentityDirectory(entries)
}
// SymmetricSession derives the pairwise 32-byte symmetric session key
// that the two-round threshold protocol uses for envelope MACing.
func SymmetricSession(
a NodeID, ikA *IdentityKey,
b NodeID, ikB *IdentityKey,
sessionID [16]byte, transcript []byte,
) ([32]byte, error) {
return pulsar.SymmetricSession(a, ikA, b, ikB, sessionID, transcript)
}
// ---------------------------------------------------------------------
// Threshold signing: two-round protocol + final combine.
// ---------------------------------------------------------------------
// ThresholdSigner drives one party's role in the two-round threshold
// signing protocol.
type ThresholdSigner = pulsar.ThresholdSigner
// NewThresholdSigner constructs a ThresholdSigner pinned to a
// (sessionID, attempt, quorum) tuple. Each ThresholdSigner instance
// is single-use per attempt; rerun NewThresholdSigner to retry.
func NewThresholdSigner(
params *Params,
sessionID [16]byte,
attempt uint32,
quorum []NodeID,
share *KeyShare,
sessionKeys map[NodeID][32]byte,
message []byte,
rng io.Reader,
) (*ThresholdSigner, error) {
return pulsar.NewThresholdSigner(params, sessionID, attempt, quorum, share, sessionKeys, message, rng)
}
// Combine aggregates the Round1 / Round2 messages from a threshold
// quorum into a single FIPS 204 ML-DSA signature that verifies under
// the group's PublicKey via VerifyCtx.
func Combine(
params *Params,
groupPubkey *PublicKey,
message []byte,
ctx []byte,
randomized bool,
sessionID [16]byte,
attempt uint32,
quorum []NodeID,
threshold int,
round1 []*Round1Message,
round2 []*Round2Message,
allShares []*KeyShare,
) (*Signature, error) {
return pulsar.Combine(params, groupPubkey, message, ctx, randomized, sessionID, attempt, quorum, threshold, round1, round2, allShares)
}
// ---------------------------------------------------------------------
// DKG: Pedersen DKG over R_q^k, three-round protocol.
// ---------------------------------------------------------------------
// DKGSession drives one party's role in the three-round DKG protocol.
type DKGSession = pulsar.DKGSession
// DKGRound1Msg / DKGRound2Msg / DKGOutput are the wire and result
// types of the DKG protocol.
type (
DKGRound1Msg = pulsar.DKGRound1Msg
DKGRound2Msg = pulsar.DKGRound2Msg
DKGOutput = pulsar.DKGOutput
)
// NewDKGSession constructs a DKGSession pinned to a committee and
// threshold, with the calling party's NodeID and long-term identity
// key. The IdentityDirectory must contain a public key for every
// member of the committee.
func NewDKGSession(
params *Params,
committee []NodeID,
threshold int,
self NodeID,
identity *IdentityKey,
directory IdentityDirectory,
rng io.Reader,
) (*DKGSession, error) {
return pulsar.NewDKGSession(params, committee, threshold, self, identity, directory, rng)
}
// ---------------------------------------------------------------------
// Single-party signing and verification (FIPS 204 baseline path).
// ---------------------------------------------------------------------
// GenerateKey samples a single-party FIPS 204 keypair for the given
// parameter block.
func GenerateKey(params *Params, rng io.Reader) (*PrivateKey, error) {
return pulsar.GenerateKey(params, rng)
}
// Sign produces a single-party FIPS 204 signature under sk over
// message with optional context ctx.
func Sign(params *Params, sk *PrivateKey, message, ctx []byte, randomized bool, rng io.Reader) (*Signature, error) {
return pulsar.Sign(params, sk, message, ctx, randomized, rng)
}
// VerifyCtx verifies a signature under groupPubkey over message with
// context ctx. The Pulsar Class N1 claim: output is byte-equal to a
// single-party FIPS 204 signature, so this verifier is the canonical
// FIPS 204 ML-DSA.Verify.
func VerifyCtx(params *Params, groupPubkey *PublicKey, message, ctx []byte, sig *Signature) error {
return pulsar.VerifyCtx(params, groupPubkey, message, ctx, sig)
}