mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
gofmt: cleanup after Corona purge identifier renames
This commit is contained in:
@@ -30,9 +30,9 @@ import (
|
||||
|
||||
"github.com/luxfi/consensus/config"
|
||||
"github.com/luxfi/consensus/protocol/quasar"
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/crypto/mldsa"
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
@@ -61,10 +61,10 @@ const coronaMaxRetries = 4
|
||||
type modeMetrics struct {
|
||||
mode config.PQMode
|
||||
n int
|
||||
signNs int64 // ns per validator-sign call (real measurement)
|
||||
aggNs int64 // ns to aggregate N shares
|
||||
verifyNs int64 // ns per cert verify
|
||||
certBytes int // serialized cert size
|
||||
signNs int64 // ns per validator-sign call (real measurement)
|
||||
aggNs int64 // ns to aggregate N shares
|
||||
verifyNs int64 // ns per cert verify
|
||||
certBytes int // serialized cert size
|
||||
pending string // non-empty -> mode is not yet implemented
|
||||
}
|
||||
|
||||
@@ -275,11 +275,11 @@ func BenchmarkPQModes_BLSPlusMLDSA(b *testing.B) {
|
||||
})
|
||||
|
||||
cert := &quasar.QuasarCert{
|
||||
BLS: blsAgg,
|
||||
BLS: blsAgg,
|
||||
MLDSARollup: mldsaPayload,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
}
|
||||
certBytes, err := cert.MarshalBinary()
|
||||
if err != nil {
|
||||
@@ -472,7 +472,7 @@ func BenchmarkPQModes_BLSPlusCorona(b *testing.B) {
|
||||
|
||||
cert := &quasar.QuasarCert{
|
||||
BLS: res.blsAgg,
|
||||
Corona: res.rtBytes,
|
||||
Corona: res.rtBytes,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
@@ -513,11 +513,11 @@ func BenchmarkPQModes_BLSPlusGroth16(b *testing.B) {
|
||||
// Cert wire size: BLS aggregate (48 B) + 192 B Groth16 placeholder.
|
||||
groth16Placeholder := make([]byte, 192)
|
||||
cert := &quasar.QuasarCert{
|
||||
BLS: blsAgg,
|
||||
BLS: blsAgg,
|
||||
MLDSARollup: groth16Placeholder,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
}
|
||||
certBytes, err := cert.MarshalBinary()
|
||||
if err != nil {
|
||||
@@ -618,12 +618,12 @@ func BenchmarkPQModes_TripleQuantum(b *testing.B) {
|
||||
})
|
||||
|
||||
cert := &quasar.QuasarCert{
|
||||
BLS: res.blsAgg,
|
||||
BLS: res.blsAgg,
|
||||
Corona: res.rtBytes,
|
||||
MLDSARollup: mldsaPayload,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: n,
|
||||
}
|
||||
certBytes, err := cert.MarshalBinary()
|
||||
if err != nil {
|
||||
|
||||
+4
-4
@@ -294,10 +294,10 @@ func (m PQMode) HashProfile() string {
|
||||
type SigSchemeID uint8
|
||||
|
||||
const (
|
||||
SigSchemeNone SigSchemeID = 0x00
|
||||
SigSchemeBLS12381 SigSchemeID = 0x10
|
||||
SigSchemeNasua SigSchemeID = 0x20
|
||||
SigSchemePulsarR SigSchemeID = 0x30
|
||||
SigSchemeNone SigSchemeID = 0x00
|
||||
SigSchemeBLS12381 SigSchemeID = 0x10
|
||||
SigSchemeNasua SigSchemeID = 0x20
|
||||
SigSchemePulsarR SigSchemeID = 0x30
|
||||
|
||||
// Raw single-party ML-DSA (FIPS 204).
|
||||
SigSchemeMLDSA44 SigSchemeID = 0x41
|
||||
|
||||
+10
-10
@@ -119,11 +119,11 @@ func TestPQMode_PolicyID(t *testing.T) {
|
||||
mode PQMode
|
||||
want uint16
|
||||
}{
|
||||
{PQModeBLS, 1}, // PolicyQuorum
|
||||
{PQModeNasua, 5}, // PolicyPQ
|
||||
{PQModePulsar, 5}, // PolicyPQ (same wire shape, SHA-3 negotiated out-of-band)
|
||||
{PQModeQuasar, 4}, // PolicyQuantum
|
||||
{PQModeMLDSA, 6}, // PolicyPZ
|
||||
{PQModeBLS, 1}, // PolicyQuorum
|
||||
{PQModeNasua, 5}, // PolicyPQ
|
||||
{PQModePulsar, 5}, // PolicyPQ (same wire shape, SHA-3 negotiated out-of-band)
|
||||
{PQModeQuasar, 4}, // PolicyQuantum
|
||||
{PQModeMLDSA, 6}, // PolicyPZ
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := c.mode.PolicyID(); got != c.want {
|
||||
@@ -178,11 +178,11 @@ func TestPQMode_HashSuiteID(t *testing.T) {
|
||||
mode PQMode
|
||||
want HashSuiteID
|
||||
}{
|
||||
{PQModeBLS, HashSuiteNone}, // 0x00
|
||||
{PQModeNasua, HashSuiteBLAKE3Legacy}, // 0x02
|
||||
{PQModePulsar, HashSuiteSHA3NIST}, // 0x01
|
||||
{PQModeQuasar, HashSuiteSHA3NIST}, // 0x01
|
||||
{PQModeMLDSA, HashSuiteSHA3NIST}, // 0x01 (SHAKE256 ∈ FIPS 202)
|
||||
{PQModeBLS, HashSuiteNone}, // 0x00
|
||||
{PQModeNasua, HashSuiteBLAKE3Legacy}, // 0x02
|
||||
{PQModePulsar, HashSuiteSHA3NIST}, // 0x01
|
||||
{PQModeQuasar, HashSuiteSHA3NIST}, // 0x01
|
||||
{PQModeMLDSA, HashSuiteSHA3NIST}, // 0x01 (SHAKE256 ∈ FIPS 202)
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := c.mode.HashSuiteID(); got != c.want {
|
||||
|
||||
@@ -27,24 +27,24 @@ import (
|
||||
// SEVERITY: critical (blocker)
|
||||
//
|
||||
// The Blue agent producing security_profile.go used schema A:
|
||||
// * Field names: AllowedProofBackends / AllowedProofFormats
|
||||
// * Forbid flag: ForbidClassicalSNARKs (plural s)
|
||||
// * Profile constants live in profiles.go (not yet written): the
|
||||
// - Field names: AllowedProofBackends / AllowedProofFormats
|
||||
// - Forbid flag: ForbidClassicalSNARKs (plural s)
|
||||
// - Profile constants live in profiles.go (not yet written): the
|
||||
// functions StrictPQ() / Permissive() / FIPS() each
|
||||
// `return &StrictPQProfile` / `&PermissiveProfile` / etc.
|
||||
// * ProfileID is a uint32 field in ChainSecurityProfile (line 254);
|
||||
// - ProfileID is a uint32 field in ChainSecurityProfile (line 254);
|
||||
// the constants ProfileStrictPQ (line 60) are typed ProfileID
|
||||
// (uint8). The constants are not assignable to the field.
|
||||
// * ComputeHash returns ([48]byte, error)
|
||||
// - ComputeHash returns ([48]byte, error)
|
||||
//
|
||||
// The Blue agent producing security_profile_test.go used schema B:
|
||||
// * Field names: AllowedBackends / AllowedFormats
|
||||
// * Forbid flag: ForbidClassicalSNARK (no s)
|
||||
// * Tests `if p.ProfileID != ProfileStrictPQ` directly (compile
|
||||
// - Field names: AllowedBackends / AllowedFormats
|
||||
// - Forbid flag: ForbidClassicalSNARK (no s)
|
||||
// - Tests `if p.ProfileID != ProfileStrictPQ` directly (compile
|
||||
// error: uint32 vs ProfileID)
|
||||
// * Calls `ErrProfileForbiddenPolicy` (not defined; only
|
||||
// - Calls `ErrProfileForbiddenPolicy` (not defined; only
|
||||
// ErrProfileFieldInvalid is exported)
|
||||
// * Calls `a.ComputeHash() != b.ComputeHash()` as a value comparison
|
||||
// - Calls `a.ComputeHash() != b.ComputeHash()` as a value comparison
|
||||
// (the new signature returns (val, err); compile error)
|
||||
//
|
||||
// Result: the package will not vet, will not build, will not test.
|
||||
@@ -58,20 +58,20 @@ import (
|
||||
//
|
||||
// FIX: pick ONE schema and apply consistently. Production-grade
|
||||
// choice:
|
||||
// * Plural collection names: AllowedProofBackends / AllowedProofFormats
|
||||
// * Plural forbid name: ForbidClassicalSNARKs (matches every other
|
||||
// - Plural collection names: AllowedProofBackends / AllowedProofFormats
|
||||
// - Plural forbid name: ForbidClassicalSNARKs (matches every other
|
||||
// plural collection)
|
||||
// * Profile constants typed ProfileID (uint8); the struct field is
|
||||
// - Profile constants typed ProfileID (uint8); the struct field is
|
||||
// also ProfileID (the type). Do NOT make the struct field uint32 —
|
||||
// that is a category error.
|
||||
// * Add profiles.go with the canonical StrictPQProfile /
|
||||
// - Add profiles.go with the canonical StrictPQProfile /
|
||||
// PermissiveProfile / FIPSProfile constants, computed once
|
||||
// via MustComputeHash at package init.
|
||||
// * Add error variables ErrProfileForbiddenPolicy /
|
||||
// - Add error variables ErrProfileForbiddenPolicy /
|
||||
// ErrProfileForbiddenBackend / ErrProfileForbiddenFormat /
|
||||
// ErrProfileStrictRequiresTransparent so callers can errors.Is
|
||||
// against the specific failure.
|
||||
// * ComputeHash returns ([48]byte, error); existing callers that
|
||||
// - ComputeHash returns ([48]byte, error); existing callers that
|
||||
// used the no-error variant get a compile-time fix-prompt.
|
||||
//
|
||||
// This file's tests assume the post-fix schema A names. Once the build
|
||||
@@ -101,9 +101,11 @@ func TestF51_PackageBuilds(t *testing.T) {
|
||||
// holding a nil-dereference panic waiting to happen.
|
||||
//
|
||||
// FIX: write profiles.go that defines:
|
||||
// var StrictPQProfile = ChainSecurityProfile{ /* all fields */ }
|
||||
// var PermissiveProfile = ChainSecurityProfile{ /* all fields */ }
|
||||
// var FIPSProfile = ChainSecurityProfile{ /* all fields */ }
|
||||
//
|
||||
// var StrictPQProfile = ChainSecurityProfile{ /* all fields */ }
|
||||
// var PermissiveProfile = ChainSecurityProfile{ /* all fields */ }
|
||||
// var FIPSProfile = ChainSecurityProfile{ /* all fields */ }
|
||||
//
|
||||
// Then call MustComputeHash on each at init time and write the
|
||||
// returned hash back into ProfileHash so the constant carries its
|
||||
// own pinned hash for genesis comparison.
|
||||
@@ -141,15 +143,16 @@ func TestF52_CanonicalProfilesExist(t *testing.T) {
|
||||
// the canonical strict-PQ profile to fail Validate at runtime.
|
||||
//
|
||||
// FIX: bulk-rename in security_profile_test.go (sed -i, not by hand):
|
||||
// AllowedBackends → AllowedProofBackends
|
||||
// AllowedFormats → AllowedProofFormats
|
||||
// ForbidClassicalSNARK → ForbidClassicalSNARKs
|
||||
// ErrProfileForbiddenPolicy → (define this var per F51 fix)
|
||||
// ErrProfileForbiddenBackend → (define this var)
|
||||
// ErrProfileForbiddenFormat → (define this var)
|
||||
// ErrProfileStrictRequiresTransparent → (define this var)
|
||||
// a.ComputeHash() != b.ComputeHash() → call .ComputeHash() with
|
||||
// error handling, then compare hashes
|
||||
//
|
||||
// AllowedBackends → AllowedProofBackends
|
||||
// AllowedFormats → AllowedProofFormats
|
||||
// ForbidClassicalSNARK → ForbidClassicalSNARKs
|
||||
// ErrProfileForbiddenPolicy → (define this var per F51 fix)
|
||||
// ErrProfileForbiddenBackend → (define this var)
|
||||
// ErrProfileForbiddenFormat → (define this var)
|
||||
// ErrProfileStrictRequiresTransparent → (define this var)
|
||||
// a.ComputeHash() != b.ComputeHash() → call .ComputeHash() with
|
||||
// error handling, then compare hashes
|
||||
func TestF53_ValidateRejectsZeroProfile(t *testing.T) {
|
||||
// A zero-init ChainSecurityProfile MUST fail Validate. The
|
||||
// architecture says "Zero value = INVALID (never default-secure)."
|
||||
|
||||
@@ -1107,4 +1107,3 @@ func FIPS() *ChainSecurityProfile {
|
||||
p := FIPSProfile
|
||||
return &p
|
||||
}
|
||||
|
||||
|
||||
@@ -714,4 +714,3 @@ func TestStrictPQProfile_ProfileHashIsStable(t *testing.T) {
|
||||
t.Fatalf("ComputeHash drift: got %x, want pinned %x", computed[:], strict.ProfileHash[:])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -374,8 +374,8 @@ func TestPopcount(t *testing.T) {
|
||||
{0b1010, 4, 2},
|
||||
{0b0000, 4, 0},
|
||||
{0b11111111, 8, 8},
|
||||
{0xFF, 4, 4}, // only lower 4 bits: 0b1111
|
||||
{0xFFFF, 10, 10}, // lower 10 bits all set
|
||||
{0xFF, 4, 4}, // only lower 4 bits: 0b1111
|
||||
{0xFFFF, 10, 10}, // lower 10 bits all set
|
||||
{0b1010101010, 10, 5},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -162,10 +162,10 @@ func TestChainConsensusProcessVoteNilConsensus(t *testing.T) {
|
||||
// Manually add block without initializing driver
|
||||
blockID := ids.GenerateTestID()
|
||||
block := &Block{
|
||||
id: blockID,
|
||||
parentID: ids.Empty,
|
||||
height: 0,
|
||||
driver: nil, // intentionally nil
|
||||
id: blockID,
|
||||
parentID: ids.Empty,
|
||||
height: 0,
|
||||
driver: nil, // intentionally nil
|
||||
}
|
||||
consensus.blocks[blockID] = block
|
||||
|
||||
@@ -913,7 +913,7 @@ func TestChainConsensusPollNilConsensus(t *testing.T) {
|
||||
// Add block without consensus
|
||||
blockID := ids.GenerateTestID()
|
||||
block := &Block{
|
||||
id: blockID,
|
||||
id: blockID,
|
||||
driver: nil,
|
||||
}
|
||||
consensus.blocks[blockID] = block
|
||||
|
||||
@@ -21,9 +21,9 @@ type Block struct {
|
||||
data []byte
|
||||
|
||||
// Consensus state - Photon -> Wave -> Focus finality
|
||||
driver *engine.Driver
|
||||
accepted bool
|
||||
rejected bool
|
||||
driver *engine.Driver
|
||||
accepted bool
|
||||
rejected bool
|
||||
|
||||
// Vote tracking for rejection support
|
||||
acceptVotes int
|
||||
|
||||
@@ -1401,10 +1401,10 @@ func TestSlashing_SlashingDBAccessor(t *testing.T) {
|
||||
|
||||
// failingBuildVM fails BuildBlock N times then succeeds.
|
||||
type failingBuildVM struct {
|
||||
failCount int
|
||||
callCount int
|
||||
blocks []*mockBlock
|
||||
preferenceID ids.ID
|
||||
failCount int
|
||||
callCount int
|
||||
blocks []*mockBlock
|
||||
preferenceID ids.ID
|
||||
setPreferenceErr error
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,11 @@ type testGossiper struct {
|
||||
pushQueries int
|
||||
}
|
||||
|
||||
func (g *testGossiper) GossipPut(_ ids.ID, _ ids.ID, _ []byte) int { return 0 }
|
||||
func (g *testGossiper) SendPushQuery(_ ids.ID, _ ids.ID, _ []byte, _ []ids.NodeID) int { g.pushQueries++; return 0 }
|
||||
func (g *testGossiper) GossipPut(_ ids.ID, _ ids.ID, _ []byte) int { return 0 }
|
||||
func (g *testGossiper) SendPushQuery(_ ids.ID, _ ids.ID, _ []byte, _ []ids.NodeID) int {
|
||||
g.pushQueries++
|
||||
return 0
|
||||
}
|
||||
func (g *testGossiper) SendPullQuery(_ ids.ID, _ ids.ID, _ ids.ID, _ []ids.NodeID) int { return 0 }
|
||||
func (g *testGossiper) SendVote(_ ids.ID, _ ids.NodeID, _ ids.ID) error { return nil }
|
||||
|
||||
|
||||
@@ -36,11 +36,11 @@ type Vertex struct {
|
||||
outputs []UTXO // UTXOs created by this vertex's transactions
|
||||
|
||||
// Consensus state - using Lux consensus with Prism DAG protocol
|
||||
mu sync.RWMutex
|
||||
driver *engine.Driver
|
||||
accepted bool
|
||||
rejected bool
|
||||
processing bool
|
||||
mu sync.RWMutex
|
||||
driver *engine.Driver
|
||||
accepted bool
|
||||
rejected bool
|
||||
processing bool
|
||||
|
||||
// Dependencies tracking
|
||||
parents []*Vertex
|
||||
|
||||
@@ -282,11 +282,11 @@ func TestProcessBlockEmptyCertificates(t *testing.T) {
|
||||
|
||||
func TestFinalityEventFields(t *testing.T) {
|
||||
event := FinalityEvent{
|
||||
Height: 100,
|
||||
BlockID: ids.GenerateTestID(),
|
||||
Timestamp: time.Now(),
|
||||
MLDSARollup: []byte("pq-proof"),
|
||||
BLSProof: []byte("bls-proof"),
|
||||
Height: 100,
|
||||
BlockID: ids.GenerateTestID(),
|
||||
Timestamp: time.Now(),
|
||||
MLDSARollup: []byte("pq-proof"),
|
||||
BLSProof: []byte("bls-proof"),
|
||||
}
|
||||
|
||||
require.Equal(t, uint64(100), event.Height)
|
||||
@@ -471,7 +471,7 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
Height: 100,
|
||||
Timestamp: testTime,
|
||||
Cert: &quasar.QuasarCert{
|
||||
BLS: []byte("bls-proof-data"),
|
||||
BLS: []byte("bls-proof-data"),
|
||||
MLDSARollup: []byte("pq-proof-data"),
|
||||
},
|
||||
},
|
||||
@@ -496,7 +496,7 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
Height: 75,
|
||||
Timestamp: testTime,
|
||||
Cert: &quasar.QuasarCert{
|
||||
BLS: []byte{},
|
||||
BLS: []byte{},
|
||||
MLDSARollup: []byte{},
|
||||
},
|
||||
},
|
||||
@@ -612,7 +612,7 @@ func TestSetFinalizedCallbackInvocation(t *testing.T) {
|
||||
Height: 42,
|
||||
Timestamp: time.Now(),
|
||||
Cert: &quasar.QuasarCert{
|
||||
BLS: []byte("test-bls"),
|
||||
BLS: []byte("test-bls"),
|
||||
MLDSARollup: []byte("test-pq"),
|
||||
},
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,10 +8,10 @@ import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/luxfi/corona/threshold"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/crypto/mldsa"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/corona/threshold"
|
||||
)
|
||||
|
||||
// CertificateGenerator generates real BLS and Corona threshold signatures.
|
||||
|
||||
+1
-1
@@ -8,10 +8,10 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/luxfi/consensus/protocol/quasar"
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/crypto/mldsa"
|
||||
"github.com/luxfi/ids"
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
)
|
||||
|
||||
// Engine defines the post-quantum consensus engine
|
||||
|
||||
@@ -70,8 +70,8 @@ func setupAssets(bridge *lx.CrossChainBridge) error {
|
||||
WrappedContract: map[string]string{
|
||||
"lux": "0x...lux",
|
||||
},
|
||||
MinTransfer: new(big.Int).SetUint64(10000000000000000), // 0.01 ETH
|
||||
MaxTransfer: new(big.Int).SetUint64(1000000000000000000), // 1 ETH
|
||||
MinTransfer: new(big.Int).SetUint64(10000000000000000), // 0.01 ETH
|
||||
MaxTransfer: new(big.Int).SetUint64(1000000000000000000), // 1 ETH
|
||||
DailyLimit: new(big.Int).Mul(big.NewInt(10), new(big.Int).SetUint64(1000000000000000000)), // 10 ETH
|
||||
DailyVolume: big.NewInt(0),
|
||||
LastReset: time.Now(),
|
||||
@@ -89,9 +89,9 @@ func setupAssets(bridge *lx.CrossChainBridge) error {
|
||||
WrappedContract: map[string]string{
|
||||
"ethereum": "0x...eth",
|
||||
},
|
||||
MinTransfer: new(big.Int).SetUint64(1000000000000000000), // 1 LUX
|
||||
MaxTransfer: new(big.Int).Mul(big.NewInt(1000), new(big.Int).SetUint64(1000000000000000000)), // 1000 LUX
|
||||
DailyLimit: new(big.Int).Mul(big.NewInt(100000), new(big.Int).SetUint64(1000000000000000000)), // 100k LUX
|
||||
MinTransfer: new(big.Int).SetUint64(1000000000000000000), // 1 LUX
|
||||
MaxTransfer: new(big.Int).Mul(big.NewInt(1000), new(big.Int).SetUint64(1000000000000000000)), // 1000 LUX
|
||||
DailyLimit: new(big.Int).Mul(big.NewInt(100000), new(big.Int).SetUint64(1000000000000000000)), // 100k LUX
|
||||
DailyVolume: big.NewInt(0),
|
||||
LastReset: time.Now(),
|
||||
Paused: false,
|
||||
|
||||
+12
-12
@@ -125,11 +125,11 @@ type Vote struct {
|
||||
|
||||
// Signature scheme tags
|
||||
const (
|
||||
SigNone byte = 0x00
|
||||
SigEd25519 byte = 0x01
|
||||
SigBLS byte = 0x02
|
||||
SigCorona byte = 0x03
|
||||
SigQuasar byte = 0x04 // BLS + Corona (Quasar protocol)
|
||||
SigNone byte = 0x00
|
||||
SigEd25519 byte = 0x01
|
||||
SigBLS byte = 0x02
|
||||
SigCorona byte = 0x03
|
||||
SigQuasar byte = 0x04 // BLS + Corona (Quasar protocol)
|
||||
)
|
||||
|
||||
// NewVote creates a vote with current timestamp
|
||||
@@ -343,13 +343,13 @@ func (h HashSuiteID) String() string {
|
||||
type SigSchemeID uint8
|
||||
|
||||
const (
|
||||
SigSchemeNone SigSchemeID = 0x00
|
||||
SigSchemeBLS12381 SigSchemeID = 0x10
|
||||
SigSchemeNasua SigSchemeID = 0x20
|
||||
SigSchemePulsarR SigSchemeID = 0x30
|
||||
SigSchemePulsarM44 SigSchemeID = 0x41
|
||||
SigSchemePulsarM65 SigSchemeID = 0x42 // production default
|
||||
SigSchemePulsarM87 SigSchemeID = 0x43
|
||||
SigSchemeNone SigSchemeID = 0x00
|
||||
SigSchemeBLS12381 SigSchemeID = 0x10
|
||||
SigSchemeNasua SigSchemeID = 0x20
|
||||
SigSchemePulsarR SigSchemeID = 0x30
|
||||
SigSchemePulsarM44 SigSchemeID = 0x41
|
||||
SigSchemePulsarM65 SigSchemeID = 0x42 // production default
|
||||
SigSchemePulsarM87 SigSchemeID = 0x43
|
||||
)
|
||||
|
||||
// String returns the canonical wire name of the signature scheme.
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/consensus/protocol/quasar"
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/crypto/mldsa"
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
)
|
||||
|
||||
// maxCandidates is the upper bound on tracked candidates per policy instance.
|
||||
@@ -621,12 +621,12 @@ func (p *QuantumPolicy) MaybeFinalize(ctx context.Context, candidateID Candidate
|
||||
// per-validator share bytes so the wire layer is self-contained, and
|
||||
// embed individual ML-DSA-65 signatures in MLDSAProof.
|
||||
qc := &quasar.QuasarCert{
|
||||
BLS: concatSignatures(p.blsVotes[candidateID]),
|
||||
BLS: concatSignatures(p.blsVotes[candidateID]),
|
||||
Corona: concatSignatures(p.pqVotes[candidateID]),
|
||||
MLDSARollup: nil,
|
||||
Epoch: candidate.Height,
|
||||
Finality: time.Now(),
|
||||
Validators: blsCount,
|
||||
Epoch: candidate.Height,
|
||||
Finality: time.Now(),
|
||||
Validators: blsCount,
|
||||
}
|
||||
|
||||
proofBytes, err := qc.MarshalBinary()
|
||||
|
||||
@@ -118,9 +118,9 @@ func TestRealThresholdSig_Accepted(t *testing.T) {
|
||||
// garbage BLS and PQ bytes is rejected by VerifyWithKeys.
|
||||
func TestQuasarCert_GarbageBytes_Rejected(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte{0x01},
|
||||
MLDSARollup: []byte{0x01},
|
||||
Validators: 1,
|
||||
BLS: []byte{0x01},
|
||||
MLDSARollup: []byte{0x01},
|
||||
Validators: 1,
|
||||
}
|
||||
|
||||
// Verify with any key must return false -- bytes don't match any valid sig
|
||||
@@ -144,8 +144,8 @@ func TestQuasarCert_NilCert_Rejected(t *testing.T) {
|
||||
// TestQuasarCert_EmptyBLS_Rejected proves empty BLS field is rejected.
|
||||
func TestQuasarCert_EmptyBLS_Rejected(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte{},
|
||||
MLDSARollup: []byte{0x01, 0x02},
|
||||
BLS: []byte{},
|
||||
MLDSARollup: []byte{0x01, 0x02},
|
||||
}
|
||||
require.False(t, cert.VerifyWithKeys([]byte("key"), []byte("key")),
|
||||
"QuasarCert with empty BLS must return false")
|
||||
@@ -154,8 +154,8 @@ func TestQuasarCert_EmptyBLS_Rejected(t *testing.T) {
|
||||
// TestQuasarCert_EmptyPQ_Rejected proves empty PQ field is rejected.
|
||||
func TestQuasarCert_EmptyPQ_Rejected(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte{0x01, 0x02},
|
||||
MLDSARollup: []byte{},
|
||||
BLS: []byte{0x01, 0x02},
|
||||
MLDSARollup: []byte{},
|
||||
}
|
||||
require.False(t, cert.VerifyWithKeys([]byte("key"), []byte("key")),
|
||||
"QuasarCert with empty PQ must return false")
|
||||
|
||||
@@ -53,12 +53,12 @@ func TestQuasarCert_RoundTrip_E2E(t *testing.T) {
|
||||
// 2. Build QuasarCert. We embed the BLS share as the BLS field for
|
||||
// end-to-end byte exercise; full aggregation is a higher-layer concern.
|
||||
cert := &QuasarCert{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: []byte{0x01}, // structural-only; cryptographic Corona is via coronaGobEncode of a real Signature
|
||||
MLDSARollup: EncodeMLDSASigs([][]byte{sig.MLDSA}),
|
||||
Epoch: 1,
|
||||
Finality: time.Unix(1700000000, 0),
|
||||
Validators: 3,
|
||||
Epoch: 1,
|
||||
Finality: time.Unix(1700000000, 0),
|
||||
Validators: 3,
|
||||
}
|
||||
|
||||
// 3. Marshal / unmarshal round-trip.
|
||||
@@ -121,9 +121,9 @@ func TestQuasarCert_UnmarshalCorrupt(t *testing.T) {
|
||||
cases := [][]byte{
|
||||
nil,
|
||||
{},
|
||||
{0x00}, // wrong scheme
|
||||
{CertSchemeQuasar}, // truncated header
|
||||
{CertSchemeQuasar, 0x00, 0xFF}, // BLS length exceeds buffer
|
||||
{0x00}, // wrong scheme
|
||||
{CertSchemeQuasar}, // truncated header
|
||||
{CertSchemeQuasar, 0x00, 0xFF}, // BLS length exceeds buffer
|
||||
append([]byte{CertSchemeQuasar}, make([]byte, 4)...), // still truncated
|
||||
}
|
||||
for i, c := range cases {
|
||||
|
||||
@@ -690,7 +690,7 @@ func TestSigner_VerifyQuasarSig_ValidatorNotFound(t *testing.T) {
|
||||
sig := &QuasarSig{
|
||||
ValidatorID: "nonexistent",
|
||||
BLS: []byte{1, 2, 3},
|
||||
Corona: []byte{4, 5, 6},
|
||||
Corona: []byte{4, 5, 6},
|
||||
}
|
||||
|
||||
result := h.VerifyQuasarSig([]byte("test"), sig)
|
||||
@@ -706,7 +706,7 @@ func TestSigner_VerifyQuasarSig_InvalidBLS(t *testing.T) {
|
||||
sig := &QuasarSig{
|
||||
ValidatorID: "v1",
|
||||
BLS: []byte{1, 2, 3}, // Invalid BLS bytes
|
||||
Corona: []byte{4, 5, 6},
|
||||
Corona: []byte{4, 5, 6},
|
||||
}
|
||||
|
||||
result := h.VerifyQuasarSig([]byte("test"), sig)
|
||||
@@ -885,7 +885,7 @@ func TestQuasarCert_Verify(t *testing.T) {
|
||||
{
|
||||
name: "empty BLS",
|
||||
cert: &QuasarCert{
|
||||
BLS: nil,
|
||||
BLS: nil,
|
||||
MLDSARollup: []byte{1, 2, 3},
|
||||
},
|
||||
validators: []string{"v1"},
|
||||
@@ -894,7 +894,7 @@ func TestQuasarCert_Verify(t *testing.T) {
|
||||
{
|
||||
name: "empty PQ",
|
||||
cert: &QuasarCert{
|
||||
BLS: []byte{1, 2, 3},
|
||||
BLS: []byte{1, 2, 3},
|
||||
MLDSARollup: nil,
|
||||
},
|
||||
validators: []string{"v1"},
|
||||
@@ -903,9 +903,9 @@ func TestQuasarCert_Verify(t *testing.T) {
|
||||
{
|
||||
name: "non-empty cert without crypto verification returns false",
|
||||
cert: &QuasarCert{
|
||||
BLS: []byte{1, 2, 3},
|
||||
BLS: []byte{1, 2, 3},
|
||||
MLDSARollup: []byte{4, 5, 6},
|
||||
Validators: 0,
|
||||
Validators: 0,
|
||||
},
|
||||
validators: []string{"v1", "v2"},
|
||||
want: false, // Verify() always returns false; use VerifyWithKeys
|
||||
@@ -933,11 +933,11 @@ func TestBlock_Fields(t *testing.T) {
|
||||
Timestamp: now,
|
||||
Data: []byte("test data"),
|
||||
Cert: &QuasarCert{
|
||||
BLS: []byte{7, 8, 9},
|
||||
BLS: []byte{7, 8, 9},
|
||||
MLDSARollup: []byte{10, 11, 12},
|
||||
Validators: 1,
|
||||
Epoch: 100,
|
||||
Finality: now,
|
||||
Validators: 1,
|
||||
Epoch: 100,
|
||||
Finality: now,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1052,7 +1052,7 @@ func TestWitnessProof_Size(t *testing.T) {
|
||||
Path: make([]byte, 16),
|
||||
OpeningProof: make([]byte, 32),
|
||||
BLSAggregate: make([]byte, 96),
|
||||
CoronaBits: make([]byte, 4),
|
||||
CoronaBits: make([]byte, 4),
|
||||
ValidatorSet: make([]byte, 32),
|
||||
BlockHeight: 100,
|
||||
StateRoot: make([]byte, 32),
|
||||
@@ -1093,7 +1093,7 @@ func TestWitnessProof_Compress(t *testing.T) {
|
||||
w := &WitnessProof{
|
||||
Commitment: make([]byte, 32),
|
||||
OpeningProof: make([]byte, 32),
|
||||
CoronaBits: []byte{0xFF, 0x0F, 0x00, 0x01},
|
||||
CoronaBits: []byte{0xFF, 0x0F, 0x00, 0x01},
|
||||
BlockHeight: 0x12345678,
|
||||
Timestamp: 0xFEDCBA98,
|
||||
}
|
||||
@@ -1346,7 +1346,7 @@ func TestVerkleWitness_VerifyStateTransition(t *testing.T) {
|
||||
Commitment: commitmentBytes[:],
|
||||
Path: path,
|
||||
OpeningProof: openingProof,
|
||||
CoronaBits: []byte{0x01}, // 1 signer meets threshold of 1
|
||||
CoronaBits: []byte{0x01}, // 1 signer meets threshold of 1
|
||||
BlockHeight: 100,
|
||||
StateRoot: stateRoot,
|
||||
}
|
||||
@@ -1364,7 +1364,7 @@ func TestVerkleWitness_VerifyStateTransition_InvalidCommitment(t *testing.T) {
|
||||
Commitment: []byte{1, 2, 3}, // Invalid commitment bytes
|
||||
Path: []byte{4, 5, 6},
|
||||
OpeningProof: []byte{7, 8, 9},
|
||||
CoronaBits: []byte{0x01},
|
||||
CoronaBits: []byte{0x01},
|
||||
}
|
||||
|
||||
err := w.VerifyStateTransition(witness)
|
||||
@@ -1393,7 +1393,7 @@ func TestVerkleWitness_BatchVerify(t *testing.T) {
|
||||
Commitment: commitmentBytes[:],
|
||||
Path: path,
|
||||
OpeningProof: openingProof,
|
||||
CoronaBits: []byte{0x01},
|
||||
CoronaBits: []byte{0x01},
|
||||
StateRoot: stateRoot,
|
||||
}
|
||||
}
|
||||
@@ -1421,7 +1421,7 @@ func TestVerkleWitness_BatchVerify_WithInvalid(t *testing.T) {
|
||||
Commitment: commitmentBytes[:],
|
||||
Path: path,
|
||||
OpeningProof: openingProof,
|
||||
CoronaBits: []byte{0x01},
|
||||
CoronaBits: []byte{0x01},
|
||||
StateRoot: stateRoot,
|
||||
}
|
||||
|
||||
@@ -1430,7 +1430,7 @@ func TestVerkleWitness_BatchVerify_WithInvalid(t *testing.T) {
|
||||
Commitment: []byte{1, 2, 3}, // Invalid
|
||||
Path: []byte{4, 5, 6},
|
||||
OpeningProof: []byte{7, 8, 9},
|
||||
CoronaBits: []byte{0x01},
|
||||
CoronaBits: []byte{0x01},
|
||||
}
|
||||
|
||||
witnesses := []*WitnessProof{validWitness, invalidWitness}
|
||||
@@ -1471,7 +1471,7 @@ func TestVerkleWitness_FullVerification(t *testing.T) {
|
||||
Path: path,
|
||||
OpeningProof: openingProof,
|
||||
BLSAggregate: blsSigBytes,
|
||||
CoronaBits: []byte{0x01},
|
||||
CoronaBits: []byte{0x01},
|
||||
ValidatorSet: []byte{5, 6, 7, 8},
|
||||
BlockHeight: 100,
|
||||
StateRoot: stateRoot,
|
||||
@@ -1507,7 +1507,7 @@ func TestVerkleWitness_FullVerification_InsufficientThreshold(t *testing.T) {
|
||||
Path: path,
|
||||
OpeningProof: openingProof,
|
||||
BLSAggregate: blsSig, // Valid-length signature
|
||||
CoronaBits: []byte{0x01}, // Only 1 signer, need 5
|
||||
CoronaBits: []byte{0x01}, // Only 1 signer, need 5
|
||||
ValidatorSet: []byte{5, 6, 7, 8},
|
||||
StateRoot: stateRoot,
|
||||
}
|
||||
@@ -1867,7 +1867,7 @@ func TestSigner_AggregateSignatures_InvalidBLS(t *testing.T) {
|
||||
sig := &QuasarSig{
|
||||
ValidatorID: "v1",
|
||||
BLS: []byte{1, 2, 3}, // Invalid BLS bytes
|
||||
Corona: []byte{4, 5, 6},
|
||||
Corona: []byte{4, 5, 6},
|
||||
}
|
||||
|
||||
_, err := h.AggregateSignatures([]byte("test"), []*QuasarSig{sig})
|
||||
@@ -2355,7 +2355,7 @@ func TestVerkleWitness_VerifyVerkleCommitment_InvalidOpeningProof(t *testing.T)
|
||||
Commitment: commitmentBytes[:],
|
||||
Path: path,
|
||||
OpeningProof: []byte{1, 2, 3, 4, 5}, // Wrong proof
|
||||
CoronaBits: []byte{0x01},
|
||||
CoronaBits: []byte{0x01},
|
||||
StateRoot: stateRoot,
|
||||
}
|
||||
|
||||
@@ -2684,7 +2684,7 @@ func TestVerkleWitness_FullVerification_CoronaThresholdNotMet(t *testing.T) {
|
||||
Path: path,
|
||||
OpeningProof: openingProof,
|
||||
BLSAggregate: blsSig, // Valid-length signature
|
||||
CoronaBits: []byte{0x01}, // Only 1 signer, need 10
|
||||
CoronaBits: []byte{0x01}, // Only 1 signer, need 10
|
||||
ValidatorSet: []byte{5, 6, 7, 8},
|
||||
StateRoot: stateRoot,
|
||||
}
|
||||
@@ -2866,7 +2866,7 @@ func TestVerkleWitness_VerifyStateTransition_FastPath(t *testing.T) {
|
||||
Commitment: commitmentBytes[:],
|
||||
Path: path,
|
||||
OpeningProof: openingProof,
|
||||
CoronaBits: []byte{0x01}, // 1 signer meets threshold
|
||||
CoronaBits: []byte{0x01}, // 1 signer meets threshold
|
||||
StateRoot: stateRoot,
|
||||
}
|
||||
|
||||
@@ -2898,7 +2898,7 @@ func TestVerkleWitness_VerifyStateTransition_SlowPath(t *testing.T) {
|
||||
Path: path,
|
||||
OpeningProof: openingProof,
|
||||
BLSAggregate: blsSigBytes,
|
||||
CoronaBits: []byte{0x01}, // 1 signer meets threshold
|
||||
CoronaBits: []byte{0x01}, // 1 signer meets threshold
|
||||
ValidatorSet: []byte{5, 6, 7, 8},
|
||||
StateRoot: stateRoot,
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ type QuantumBlock struct {
|
||||
SourceBlocks []*Block
|
||||
QuantumHash string
|
||||
BLSSignature []byte
|
||||
CoronaProof []byte // ML-DSA signature
|
||||
CoronaProof []byte // ML-DSA signature
|
||||
Timestamp time.Time
|
||||
CreatedAt time.Time // When this block entered the pending set
|
||||
ValidatorSigs map[string]*QuasarSig
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
"github.com/luxfi/lattice/v7/ring"
|
||||
"github.com/luxfi/lattice/v7/utils/structs"
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
)
|
||||
|
||||
// coronaGobEncode serializes a Pulsar threshold signature using the
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/luxfi/crypto/threshold"
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
"github.com/luxfi/crypto/threshold"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ func TestBlock(t *testing.T) {
|
||||
Hash: "0xabc123",
|
||||
Timestamp: time.Now(),
|
||||
Cert: &QuasarCert{
|
||||
BLS: []byte("bls"),
|
||||
BLS: []byte("bls"),
|
||||
MLDSARollup: []byte("pq"),
|
||||
},
|
||||
}
|
||||
@@ -327,7 +327,7 @@ func TestQuantumFinality_Integration(t *testing.T) {
|
||||
Hash: proposal,
|
||||
Timestamp: time.Now(),
|
||||
Cert: &QuasarCert{
|
||||
BLS: cert.BLSAgg,
|
||||
BLS: cert.BLSAgg,
|
||||
MLDSARollup: cert.PQCert,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func BenchmarkAggregateSignatures(b *testing.B) {
|
||||
// Copy to avoid pool reuse during benchmark
|
||||
sigs[i] = &QuasarSig{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
}
|
||||
ReleaseQuasarSig(sig)
|
||||
@@ -126,7 +126,7 @@ func BenchmarkVerifyAggregatedSignature(b *testing.B) {
|
||||
}
|
||||
sigs[i] = &QuasarSig{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
}
|
||||
ReleaseQuasarSig(sig)
|
||||
@@ -173,7 +173,7 @@ func BenchmarkVerifyAggregatedSignatureParallel(b *testing.B) {
|
||||
}
|
||||
sigs[i] = &QuasarSig{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
}
|
||||
ReleaseQuasarSig(sig)
|
||||
|
||||
@@ -55,7 +55,7 @@ type QBlock struct {
|
||||
// root is 48 bytes (BLS12-381 G1 / KZG commitment width) so the same
|
||||
// field can carry either a hash digest or a commitment without an
|
||||
// envelope-format split.
|
||||
StateRoot [48]byte
|
||||
StateRoot [48]byte
|
||||
ZChainStateRoot [48]byte
|
||||
ValidatorSetRoot [48]byte
|
||||
CommitteeRoot [48]byte
|
||||
|
||||
@@ -77,7 +77,7 @@ func validBlock() *QBlock {
|
||||
Height: 100,
|
||||
RoundOrView: 7,
|
||||
ParentQBlockHash: b32(0x01),
|
||||
StateRoot: b48(0x02),
|
||||
StateRoot: b48(0x02),
|
||||
ZChainStateRoot: b48(0x03),
|
||||
ValidatorSetRoot: b48(0x04),
|
||||
CommitteeRoot: b48(0x05),
|
||||
|
||||
+35
-35
@@ -29,9 +29,9 @@ var (
|
||||
sigPool = sync.Pool{
|
||||
New: func() any {
|
||||
return &QuasarSig{
|
||||
BLS: make([]byte, 0, 96),
|
||||
Corona: make([]byte, 0, 4096),
|
||||
MLDSA: make([]byte, 0, 3309), // ML-DSA-65 sig size
|
||||
BLS: make([]byte, 0, 96),
|
||||
Corona: make([]byte, 0, 4096),
|
||||
MLDSA: make([]byte, 0, 3309), // ML-DSA-65 sig size
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -91,7 +91,7 @@ type signer struct {
|
||||
type Validator struct {
|
||||
ID string
|
||||
BLSPubKey *bls.PublicKey
|
||||
CoronaPub []byte // Corona group public key contribution
|
||||
CoronaPub []byte // Corona group public key contribution
|
||||
MLDSAPubKey *mldsa.PublicKey // ML-DSA-65 identity key (nil if not configured)
|
||||
Weight uint64
|
||||
Active bool
|
||||
@@ -126,15 +126,15 @@ func newSigner(thresholdVal int) (*signer, error) {
|
||||
}
|
||||
|
||||
return &signer{
|
||||
blsKeys: make(map[string]*bls.SecretKey),
|
||||
blsPubKeys: make(map[string]*bls.PublicKey),
|
||||
blsSigners: make(map[string]threshold.Signer),
|
||||
blsKeys: make(map[string]*bls.SecretKey),
|
||||
blsPubKeys: make(map[string]*bls.PublicKey),
|
||||
blsSigners: make(map[string]threshold.Signer),
|
||||
coronaSigners: make(map[string]*coronaThreshold.Signer),
|
||||
coronaShares: make(map[string]*coronaThreshold.KeyShare),
|
||||
mldsaKeys: make(map[string]*mldsa.PrivateKey),
|
||||
mldsaPubKeys: make(map[string]*mldsa.PublicKey),
|
||||
validators: make(map[string]*Validator),
|
||||
threshold: thresholdVal,
|
||||
mldsaKeys: make(map[string]*mldsa.PrivateKey),
|
||||
mldsaPubKeys: make(map[string]*mldsa.PublicKey),
|
||||
validators: make(map[string]*Validator),
|
||||
threshold: thresholdVal,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -145,15 +145,15 @@ func newSignerWithDualThreshold(config SignerConfig) (*signer, error) {
|
||||
}
|
||||
|
||||
h := &signer{
|
||||
blsKeys: make(map[string]*bls.SecretKey),
|
||||
blsPubKeys: make(map[string]*bls.PublicKey),
|
||||
blsSigners: make(map[string]threshold.Signer),
|
||||
blsKeys: make(map[string]*bls.SecretKey),
|
||||
blsPubKeys: make(map[string]*bls.PublicKey),
|
||||
blsSigners: make(map[string]threshold.Signer),
|
||||
coronaSigners: make(map[string]*coronaThreshold.Signer),
|
||||
coronaShares: make(map[string]*coronaThreshold.KeyShare),
|
||||
mldsaKeys: make(map[string]*mldsa.PrivateKey),
|
||||
mldsaPubKeys: make(map[string]*mldsa.PublicKey),
|
||||
validators: make(map[string]*Validator),
|
||||
threshold: config.Threshold,
|
||||
mldsaKeys: make(map[string]*mldsa.PrivateKey),
|
||||
mldsaPubKeys: make(map[string]*mldsa.PublicKey),
|
||||
validators: make(map[string]*Validator),
|
||||
threshold: config.Threshold,
|
||||
}
|
||||
|
||||
// Initialize BLS threshold scheme
|
||||
@@ -234,10 +234,10 @@ func GenerateDualKeys(t, n int) (*SignerConfig, error) {
|
||||
}
|
||||
|
||||
return &SignerConfig{
|
||||
Threshold: t,
|
||||
TotalParties: n,
|
||||
BLSKeyShares: blsShareMap,
|
||||
BLSGroupKey: blsGroupKey,
|
||||
Threshold: t,
|
||||
TotalParties: n,
|
||||
BLSKeyShares: blsShareMap,
|
||||
BLSGroupKey: blsGroupKey,
|
||||
CoronaShares: coronaShareMap,
|
||||
CoronaGroupKey: coronaGroupKey,
|
||||
}, nil
|
||||
@@ -786,11 +786,11 @@ type QuasarSig struct {
|
||||
|
||||
// AggregatedSignature contains aggregated signatures.
|
||||
type AggregatedSignature struct {
|
||||
BLSAggregated []byte
|
||||
BLSAggregated []byte
|
||||
CoronaAggregated []byte
|
||||
ValidatorIDs []string
|
||||
SignerCount int
|
||||
IsThreshold bool
|
||||
ValidatorIDs []string
|
||||
SignerCount int
|
||||
IsThreshold bool
|
||||
}
|
||||
|
||||
// AnyValidatorID returns any configured validator ID, or "" if none.
|
||||
@@ -858,17 +858,17 @@ func newSignerWithThresholdConfig(config ThresholdConfig) (*signer, error) {
|
||||
}
|
||||
|
||||
h := &signer{
|
||||
blsKeys: make(map[string]*bls.SecretKey),
|
||||
blsPubKeys: make(map[string]*bls.PublicKey),
|
||||
blsSigners: make(map[string]threshold.Signer),
|
||||
blsKeys: make(map[string]*bls.SecretKey),
|
||||
blsPubKeys: make(map[string]*bls.PublicKey),
|
||||
blsSigners: make(map[string]threshold.Signer),
|
||||
coronaSigners: make(map[string]*coronaThreshold.Signer),
|
||||
coronaShares: make(map[string]*coronaThreshold.KeyShare),
|
||||
mldsaKeys: make(map[string]*mldsa.PrivateKey),
|
||||
mldsaPubKeys: make(map[string]*mldsa.PublicKey),
|
||||
validators: make(map[string]*Validator),
|
||||
threshold: config.Threshold,
|
||||
blsScheme: scheme,
|
||||
blsGroupKey: config.GroupKey,
|
||||
mldsaKeys: make(map[string]*mldsa.PrivateKey),
|
||||
mldsaPubKeys: make(map[string]*mldsa.PublicKey),
|
||||
validators: make(map[string]*Validator),
|
||||
threshold: config.Threshold,
|
||||
blsScheme: scheme,
|
||||
blsGroupKey: config.GroupKey,
|
||||
}
|
||||
|
||||
if config.GroupKey != nil {
|
||||
|
||||
@@ -39,7 +39,7 @@ type roundDigestInputs struct {
|
||||
parentQBlockHash [32]byte
|
||||
payloadRoot [48]byte
|
||||
daRoot [48]byte
|
||||
sourceStateRoot [48]byte
|
||||
sourceStateRoot [48]byte
|
||||
zchainStateRoot [48]byte
|
||||
validatorRoot [48]byte
|
||||
committeeRoot [48]byte
|
||||
@@ -67,7 +67,7 @@ func canonicalRoundDigest() roundDigestInputs {
|
||||
parentQBlockHash: fillN32(0x01),
|
||||
payloadRoot: fillN48(0x02),
|
||||
daRoot: fillN48(0x03),
|
||||
sourceStateRoot: fillN48(0x04),
|
||||
sourceStateRoot: fillN48(0x04),
|
||||
zchainStateRoot: fillN48(0x05),
|
||||
validatorRoot: fillN48(0x06),
|
||||
committeeRoot: fillN48(0x07),
|
||||
|
||||
@@ -33,7 +33,7 @@ type canonicalRoundDigestInputs struct {
|
||||
parentQBlockHash [32]byte
|
||||
payloadRoot [48]byte
|
||||
daRoot [48]byte
|
||||
sourceStateRoot [48]byte
|
||||
sourceStateRoot [48]byte
|
||||
zchainStateRoot [48]byte
|
||||
validatorSetRoot [48]byte
|
||||
committeeRoot [48]byte
|
||||
@@ -72,7 +72,7 @@ func canonical() canonicalRoundDigestInputs {
|
||||
parentQBlockHash: ps,
|
||||
payloadRoot: mk48(0x10),
|
||||
daRoot: mk48(0x18),
|
||||
sourceStateRoot: mk48(0x20),
|
||||
sourceStateRoot: mk48(0x20),
|
||||
zchainStateRoot: mk48(0x30),
|
||||
validatorSetRoot: mk48(0x40),
|
||||
committeeRoot: mk48(0x50),
|
||||
@@ -136,32 +136,32 @@ func TestComputeRoundDigest_BindsEveryField(t *testing.T) {
|
||||
|
||||
mutations := map[string]func(*canonicalRoundDigestInputs){
|
||||
"profileID": func(x *canonicalRoundDigestInputs) { x.profileID ^= 1 },
|
||||
"hashSuite": func(x *canonicalRoundDigestInputs) { x.hashSuite = config.HashSuiteBLAKE3Legacy },
|
||||
"hashSuite": func(x *canonicalRoundDigestInputs) { x.hashSuite = config.HashSuiteBLAKE3Legacy },
|
||||
"identityScheme": func(x *canonicalRoundDigestInputs) { x.identityScheme = config.IdentitySchemeMLDSA87 },
|
||||
"finalityScheme": func(x *canonicalRoundDigestInputs) { x.finalityScheme = config.SigSchemePulsarM87 },
|
||||
"proofPolicy": func(x *canonicalRoundDigestInputs) { x.proofPolicy = config.ProofPolicySTARKFRIKeccak },
|
||||
"proofBackend": func(x *canonicalRoundDigestInputs) { x.proofBackend = config.ProofBackendSP1CompressedSTARK },
|
||||
"proofFormat": func(x *canonicalRoundDigestInputs) { x.proofFormat = config.ProofFormatSP1BinaryV1 },
|
||||
"verifierID": func(x *canonicalRoundDigestInputs) { x.verifierID = config.VerifierSP1CompressedSTARKPQ },
|
||||
"networkID": func(x *canonicalRoundDigestInputs) { x.networkID ^= 1 },
|
||||
"chainID": func(x *canonicalRoundDigestInputs) { x.chainID ^= 1 },
|
||||
"epoch": func(x *canonicalRoundDigestInputs) { x.epoch ^= 1 },
|
||||
"height": func(x *canonicalRoundDigestInputs) { x.height ^= 1 },
|
||||
"roundOrView": func(x *canonicalRoundDigestInputs) { x.roundOrView ^= 1 },
|
||||
"parentQBlockHash[0]": func(x *canonicalRoundDigestInputs) { x.parentQBlockHash[0] ^= 1 },
|
||||
"parentQBlockHash[31]": func(x *canonicalRoundDigestInputs) { x.parentQBlockHash[31] ^= 1 },
|
||||
"payloadRoot[0]": func(x *canonicalRoundDigestInputs) { x.payloadRoot[0] ^= 1 },
|
||||
"payloadRoot[47]": func(x *canonicalRoundDigestInputs) { x.payloadRoot[47] ^= 1 },
|
||||
"daRoot[0]": func(x *canonicalRoundDigestInputs) { x.daRoot[0] ^= 1 },
|
||||
"daRoot[47]": func(x *canonicalRoundDigestInputs) { x.daRoot[47] ^= 1 },
|
||||
"sourceStateRoot[0]": func(x *canonicalRoundDigestInputs) { x.sourceStateRoot[0] ^= 1 },
|
||||
"zchainStateRoot[0]": func(x *canonicalRoundDigestInputs) { x.zchainStateRoot[0] ^= 1 },
|
||||
"validatorSetRoot[0]": func(x *canonicalRoundDigestInputs) { x.validatorSetRoot[0] ^= 1 },
|
||||
"committeeRoot[0]": func(x *canonicalRoundDigestInputs) { x.committeeRoot[0] ^= 1 },
|
||||
"dkgTranscriptRoot[0]": func(x *canonicalRoundDigestInputs) { x.dkgTranscriptRoot[0] ^= 1 },
|
||||
"groupPubKeyHash[0]": func(x *canonicalRoundDigestInputs) { x.groupPubKeyHash[0] ^= 1 },
|
||||
"signerSetCommit[0]": func(x *canonicalRoundDigestInputs) { x.signerSetCommit[0] ^= 1 },
|
||||
"signerSetCommit[47]": func(x *canonicalRoundDigestInputs) { x.signerSetCommit[47] ^= 1 },
|
||||
"finalityScheme": func(x *canonicalRoundDigestInputs) { x.finalityScheme = config.SigSchemePulsarM87 },
|
||||
"proofPolicy": func(x *canonicalRoundDigestInputs) { x.proofPolicy = config.ProofPolicySTARKFRIKeccak },
|
||||
"proofBackend": func(x *canonicalRoundDigestInputs) { x.proofBackend = config.ProofBackendSP1CompressedSTARK },
|
||||
"proofFormat": func(x *canonicalRoundDigestInputs) { x.proofFormat = config.ProofFormatSP1BinaryV1 },
|
||||
"verifierID": func(x *canonicalRoundDigestInputs) { x.verifierID = config.VerifierSP1CompressedSTARKPQ },
|
||||
"networkID": func(x *canonicalRoundDigestInputs) { x.networkID ^= 1 },
|
||||
"chainID": func(x *canonicalRoundDigestInputs) { x.chainID ^= 1 },
|
||||
"epoch": func(x *canonicalRoundDigestInputs) { x.epoch ^= 1 },
|
||||
"height": func(x *canonicalRoundDigestInputs) { x.height ^= 1 },
|
||||
"roundOrView": func(x *canonicalRoundDigestInputs) { x.roundOrView ^= 1 },
|
||||
"parentQBlockHash[0]": func(x *canonicalRoundDigestInputs) { x.parentQBlockHash[0] ^= 1 },
|
||||
"parentQBlockHash[31]": func(x *canonicalRoundDigestInputs) { x.parentQBlockHash[31] ^= 1 },
|
||||
"payloadRoot[0]": func(x *canonicalRoundDigestInputs) { x.payloadRoot[0] ^= 1 },
|
||||
"payloadRoot[47]": func(x *canonicalRoundDigestInputs) { x.payloadRoot[47] ^= 1 },
|
||||
"daRoot[0]": func(x *canonicalRoundDigestInputs) { x.daRoot[0] ^= 1 },
|
||||
"daRoot[47]": func(x *canonicalRoundDigestInputs) { x.daRoot[47] ^= 1 },
|
||||
"sourceStateRoot[0]": func(x *canonicalRoundDigestInputs) { x.sourceStateRoot[0] ^= 1 },
|
||||
"zchainStateRoot[0]": func(x *canonicalRoundDigestInputs) { x.zchainStateRoot[0] ^= 1 },
|
||||
"validatorSetRoot[0]": func(x *canonicalRoundDigestInputs) { x.validatorSetRoot[0] ^= 1 },
|
||||
"committeeRoot[0]": func(x *canonicalRoundDigestInputs) { x.committeeRoot[0] ^= 1 },
|
||||
"dkgTranscriptRoot[0]": func(x *canonicalRoundDigestInputs) { x.dkgTranscriptRoot[0] ^= 1 },
|
||||
"groupPubKeyHash[0]": func(x *canonicalRoundDigestInputs) { x.groupPubKeyHash[0] ^= 1 },
|
||||
"signerSetCommit[0]": func(x *canonicalRoundDigestInputs) { x.signerSetCommit[0] ^= 1 },
|
||||
"signerSetCommit[47]": func(x *canonicalRoundDigestInputs) { x.signerSetCommit[47] ^= 1 },
|
||||
}
|
||||
|
||||
for name, mut := range mutations {
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestCRITICAL1_ForgedThresholdSigRejected(t *testing.T) {
|
||||
BLS: []byte("this-is-not-a-valid-bls-signature-at-all"),
|
||||
ValidatorID: "v1",
|
||||
IsThreshold: true,
|
||||
SignerIndex: 0,
|
||||
SignerIndex: 0,
|
||||
}
|
||||
|
||||
require.False(t, s.VerifyQuasarSig(message, forgedSig),
|
||||
@@ -79,9 +79,9 @@ func TestCRITICAL1_ThresholdSigWithoutVerifier(t *testing.T) {
|
||||
// any non-empty bytes passed verification. No cryptographic check.
|
||||
func TestCRITICAL2_QuasarCertVerifyRejectGarbage(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte("garbage-bls-not-a-real-signature"),
|
||||
MLDSARollup: []byte("garbage-pq-not-a-real-certificate"),
|
||||
Validators: 0,
|
||||
BLS: []byte("garbage-bls-not-a-real-signature"),
|
||||
MLDSARollup: []byte("garbage-pq-not-a-real-certificate"),
|
||||
Validators: 0,
|
||||
}
|
||||
|
||||
require.False(t, cert.Verify([]string{"v1", "v2", "v3"}),
|
||||
@@ -99,15 +99,15 @@ func TestCRITICAL2_QuasarCertVerifyWithKeysNilCert(t *testing.T) {
|
||||
// BLS or PQ fields are rejected.
|
||||
func TestCRITICAL2_QuasarCertVerifyWithKeysEmptyFields(t *testing.T) {
|
||||
// Empty BLS
|
||||
cert := &QuasarCert{BLS: nil, MLDSARollup: []byte("pq")}
|
||||
cert := &QuasarCert{BLS: nil, MLDSARollup: []byte("pq")}
|
||||
require.False(t, cert.VerifyWithKeys([]byte("key"), []byte("pq")))
|
||||
|
||||
// Empty PQ
|
||||
cert = &QuasarCert{BLS: []byte("bls"), MLDSARollup: nil}
|
||||
cert = &QuasarCert{BLS: []byte("bls"), MLDSARollup: nil}
|
||||
require.False(t, cert.VerifyWithKeys([]byte("key"), []byte("pq")))
|
||||
|
||||
// Empty group key
|
||||
cert = &QuasarCert{BLS: []byte("bls"), MLDSARollup: []byte("pq")}
|
||||
cert = &QuasarCert{BLS: []byte("bls"), MLDSARollup: []byte("pq")}
|
||||
require.False(t, cert.VerifyWithKeys(nil, []byte("pq")))
|
||||
}
|
||||
|
||||
|
||||
@@ -133,12 +133,12 @@ func TestGenerateCert_NilProfile_AcceptsPlaceholder(t *testing.T) {
|
||||
// if generateCert somehow emits it.
|
||||
func TestQuasarCert_Verify_RejectsMissingCorona(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte("bls"),
|
||||
BLS: []byte("bls"),
|
||||
Corona: nil, // missing
|
||||
MLDSARollup: []byte("mldsa"),
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: 1,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: 1,
|
||||
}
|
||||
if cert.Verify(nil) {
|
||||
t.Fatal("QuasarCert.Verify accepted cert with nil Corona")
|
||||
@@ -149,12 +149,12 @@ func TestQuasarCert_Verify_RejectsMissingCorona(t *testing.T) {
|
||||
// layer. Tests for symmetry with the Corona case.
|
||||
func TestQuasarCert_Verify_RejectsMissingMLDSA(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: []byte("bls"),
|
||||
BLS: []byte("bls"),
|
||||
Corona: []byte("rt"),
|
||||
MLDSARollup: nil, // missing
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: 1,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: 1,
|
||||
}
|
||||
if cert.Verify(nil) {
|
||||
t.Fatal("QuasarCert.Verify accepted cert with nil MLDSAProof")
|
||||
@@ -164,12 +164,12 @@ func TestQuasarCert_Verify_RejectsMissingMLDSA(t *testing.T) {
|
||||
// TestQuasarCert_Verify_RejectsMissingBLS — same shape for BLS.
|
||||
func TestQuasarCert_Verify_RejectsMissingBLS(t *testing.T) {
|
||||
cert := &QuasarCert{
|
||||
BLS: nil, // missing
|
||||
BLS: nil, // missing
|
||||
Corona: []byte("rt"),
|
||||
MLDSARollup: []byte("mldsa"),
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: 1,
|
||||
Epoch: 1,
|
||||
Finality: time.Now(),
|
||||
Validators: 1,
|
||||
}
|
||||
if cert.Verify(nil) {
|
||||
t.Fatal("QuasarCert.Verify accepted cert with nil BLS")
|
||||
|
||||
@@ -73,7 +73,7 @@ func TestTripleSignVerify(t *testing.T) {
|
||||
BLS: sig.BLS,
|
||||
ValidatorID: sig.ValidatorID,
|
||||
IsThreshold: sig.IsThreshold,
|
||||
SignerIndex: sig.SignerIndex,
|
||||
SignerIndex: sig.SignerIndex,
|
||||
}
|
||||
if !s.VerifyQuasarSig(msg, blsOnly) {
|
||||
t.Fatal("BLS-only verification failed")
|
||||
@@ -85,7 +85,7 @@ func TestTripleSignVerify(t *testing.T) {
|
||||
MLDSA: []byte("not-a-valid-mldsa-sig"),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
IsThreshold: sig.IsThreshold,
|
||||
SignerIndex: sig.SignerIndex,
|
||||
SignerIndex: sig.SignerIndex,
|
||||
}
|
||||
if s.VerifyQuasarSig(msg, corruptMLDSA) {
|
||||
t.Fatal("verification should fail with corrupted MLDSA")
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/crypto/mldsa"
|
||||
coronaThreshold "github.com/luxfi/corona/threshold"
|
||||
)
|
||||
|
||||
// Block represents a finalized block in the Quasar consensus.
|
||||
@@ -446,9 +446,9 @@ type CoronaSignature struct {
|
||||
// BLS aggregate: 48 bytes
|
||||
// PQ proof: variable (aggregated Corona + ML-DSA, or future SNARK)
|
||||
type QuasarSignature struct {
|
||||
BLS *BLSSignature // Classical fast path (aggregatable)
|
||||
BLS *BLSSignature // Classical fast path (aggregatable)
|
||||
Corona *CoronaSignature // PQ anonymous path (ring-LWE threshold)
|
||||
MLDSA []byte // PQ identity proof (ML-DSA-65, FIPS 204)
|
||||
MLDSA []byte // PQ identity proof (ML-DSA-65, FIPS 204)
|
||||
}
|
||||
|
||||
// CoronaRound1Data contains the output of Corona Round 1.
|
||||
|
||||
@@ -102,7 +102,7 @@ type WitnessProof struct {
|
||||
// Legacy fields (classical-compat deployments). Strict-PQ
|
||||
// verifiers refuse to consult CoronaBits / BLSAggregate.
|
||||
BLSAggregate []byte // Aggregated BLS signature
|
||||
CoronaBits []byte // Bitfield of Corona signers
|
||||
CoronaBits []byte // Bitfield of Corona signers
|
||||
ValidatorSet []byte // Compressed validator set hash
|
||||
|
||||
// Block metadata
|
||||
@@ -415,7 +415,7 @@ func (v *VerkleWitness) CreateWitness(
|
||||
Path: compressPath(stateRoot),
|
||||
OpeningProof: openingProof,
|
||||
BLSAggregate: bls.SignatureToBytes(blsAgg),
|
||||
CoronaBits: coronaBits,
|
||||
CoronaBits: coronaBits,
|
||||
ValidatorSet: hashValidatorSet(),
|
||||
BlockHeight: height,
|
||||
StateRoot: stateRoot,
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestVerifyPQFinality_PulsarM_RealVerifyAccepts(t *testing.T) {
|
||||
Commitment: make([]byte, 32),
|
||||
Path: make([]byte, 16),
|
||||
OpeningProof: make([]byte, 48),
|
||||
CoronaBits: []byte{0x01},
|
||||
CoronaBits: []byte{0x01},
|
||||
BlockHeight: 100,
|
||||
StateRoot: make([]byte, 32),
|
||||
Timestamp: 1700000000,
|
||||
@@ -73,7 +73,7 @@ func TestVerifyPQFinality_PulsarM_TamperedSignatureRejected(t *testing.T) {
|
||||
Commitment: make([]byte, 32),
|
||||
Path: make([]byte, 16),
|
||||
OpeningProof: make([]byte, 48),
|
||||
CoronaBits: []byte{0x01},
|
||||
CoronaBits: []byte{0x01},
|
||||
BlockHeight: 100,
|
||||
StateRoot: make([]byte, 32),
|
||||
Timestamp: 1700000000,
|
||||
@@ -123,7 +123,7 @@ func TestVerifyPQFinality_PulsarM_BitCountAlone_DoesNotPass(t *testing.T) {
|
||||
Commitment: make([]byte, 32),
|
||||
Path: make([]byte, 16),
|
||||
OpeningProof: make([]byte, 48),
|
||||
CoronaBits: []byte{0xFF}, // 8 bits set — bit-count would pass at any threshold ≤ 8
|
||||
CoronaBits: []byte{0xFF}, // 8 bits set — bit-count would pass at any threshold ≤ 8
|
||||
BlockHeight: 100,
|
||||
StateRoot: make([]byte, 32),
|
||||
Timestamp: 1700000000,
|
||||
|
||||
@@ -301,8 +301,8 @@ func TestThresholdAlwaysInRange(t *testing.T) {
|
||||
|
||||
kValues := []int{1, 2, 3, 10, 50, 100, 1000, 10000}
|
||||
for _, k := range kValues {
|
||||
lo := int(thetaMin * float64(k)) // floor
|
||||
hi := int(thetaMax*float64(k)) + 1 // ceiling with margin
|
||||
lo := int(thetaMin * float64(k)) // floor
|
||||
hi := int(thetaMax*float64(k)) + 1 // ceiling with margin
|
||||
|
||||
for phase := uint64(0); phase < 200; phase++ {
|
||||
threshold := s.SelectThreshold(phase, k)
|
||||
|
||||
Reference in New Issue
Block a user