mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
refactor: quasar protocol improvements and test updates
- Update quasar BLS and GPU integration - Improve epoch and threshold management - Remove deprecated corona module - Update integration tests for chain engine - Enhance dynamic and dual threshold tests - CGO_ENABLED=1 default for GPU acceleration
This commit is contained in:
+48
-40
@@ -1,54 +1,62 @@
|
||||
# golangci-lint configuration
|
||||
# golangci-lint v2 configuration
|
||||
version: "2"
|
||||
|
||||
run:
|
||||
timeout: 10m
|
||||
tests: false
|
||||
go: '1.21'
|
||||
skip-dirs:
|
||||
- vendor
|
||||
- third_party
|
||||
- testdata
|
||||
- examples
|
||||
- .git
|
||||
- build
|
||||
|
||||
linters:
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- govet
|
||||
- staticcheck
|
||||
- ineffassign
|
||||
- misspell
|
||||
disable:
|
||||
- unused
|
||||
- gosec # Too many false positives
|
||||
- revive # Conflicts with other linters
|
||||
- gocritic # Too strict for now
|
||||
- gofumpt # Different from gofmt
|
||||
- unconvert # Too many false positives
|
||||
- goimports # Not needed with gofmt
|
||||
|
||||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: false # Too many false positives
|
||||
gofmt:
|
||||
simplify: true
|
||||
staticcheck:
|
||||
checks: ["all", "-SA1019"] # Ignore deprecation warnings
|
||||
settings:
|
||||
govet:
|
||||
disable:
|
||||
- shadow
|
||||
staticcheck:
|
||||
checks:
|
||||
- "all"
|
||||
- "-SA1019"
|
||||
- "-QF1008" # embedded field selector (style suggestion)
|
||||
- "-QF1012" # fmt.Fprintf instead of Write (style suggestion)
|
||||
- "-ST1003" # ALL_CAPS naming (style)
|
||||
- "-ST1005" # error string capitalization (style)
|
||||
- "-ST1023" # omit type from declaration (style)
|
||||
- "-QF1011" # omit type from declaration (style)
|
||||
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
paths:
|
||||
- vendor
|
||||
- third_party
|
||||
- testdata
|
||||
- examples
|
||||
- build
|
||||
rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- staticcheck
|
||||
- ineffassign
|
||||
- path: test/
|
||||
linters:
|
||||
- staticcheck
|
||||
- ineffassign
|
||||
- path: cmd/
|
||||
text: "Error return value of .* is not checked"
|
||||
- text: "declaration of \"err\" shadows"
|
||||
linters:
|
||||
- govet
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- staticcheck
|
||||
- ineffassign
|
||||
- path: test/
|
||||
linters:
|
||||
- staticcheck
|
||||
- ineffassign
|
||||
- path: cmd/
|
||||
text: "Error return value of .* is not checked"
|
||||
- text: "declaration of \"err\" shadows"
|
||||
linters:
|
||||
- govet
|
||||
max-issues-per-linter: 50
|
||||
max-same-issues: 10
|
||||
max-same-issues: 10
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ type Agent[T ConsensusData] struct {
|
||||
nodeID string
|
||||
model Model[T]
|
||||
memory *SharedMemory[T]
|
||||
quasar *quasar.QuasarCore
|
||||
quasar *quasar.Quasar
|
||||
photon *photon.UniformEmitter
|
||||
|
||||
// Shared hallucination state
|
||||
@@ -157,7 +157,7 @@ type Model[T ConsensusData] interface {
|
||||
func New[T ConsensusData](
|
||||
nodeID string,
|
||||
model Model[T],
|
||||
quasarEngine *quasar.QuasarCore,
|
||||
quasarEngine *quasar.Quasar,
|
||||
photonEngine *photon.UniformEmitter,
|
||||
) *Agent[T] {
|
||||
return &Agent[T]{
|
||||
|
||||
@@ -776,7 +776,7 @@ func TestSecurityAgent_AutomaticSecurityResponse_AutoExecuteError(t *testing.T)
|
||||
}
|
||||
|
||||
threat := SecurityData{
|
||||
ThreatLevel: "critical", // Critical triggers auto-execute
|
||||
ThreatLevel: "critical", // Critical triggers auto-execute
|
||||
Threats: []string{"attack"},
|
||||
NodeID: "malicious-node",
|
||||
Evidence: []string{"evidence"},
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ func GetNodeID(ctx context.Context) ids.NodeID {
|
||||
|
||||
// IDs holds the IDs for consensus context
|
||||
type IDs struct {
|
||||
NetworkID uint32 // 1=mainnet, 2=testnet
|
||||
NetworkID uint32 // 1=mainnet, 2=testnet
|
||||
ChainID ids.ID
|
||||
NodeID ids.NodeID
|
||||
PublicKey []byte
|
||||
|
||||
+3
-3
@@ -97,7 +97,7 @@ const (
|
||||
Stopped = vm.Stopped
|
||||
|
||||
// Legacy aliases for VMState constants (old naming convention)
|
||||
VMStateSyncing = vm.Syncing
|
||||
VMBootstrapping = vm.Bootstrapping
|
||||
VMNormalOp = vm.Ready
|
||||
VMStateSyncing = vm.Syncing
|
||||
VMBootstrapping = vm.Bootstrapping
|
||||
VMNormalOp = vm.Ready
|
||||
)
|
||||
|
||||
@@ -1015,16 +1015,16 @@ type testBlock struct {
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
func (b *testBlock) ID() ids.ID { return b.id }
|
||||
func (b *testBlock) Parent() ids.ID { return b.parentID }
|
||||
func (b *testBlock) ParentID() ids.ID { return b.parentID }
|
||||
func (b *testBlock) Height() uint64 { return b.height }
|
||||
func (b *testBlock) Timestamp() time.Time { return b.timestamp }
|
||||
func (b *testBlock) Status() uint8 { return b.status }
|
||||
func (b *testBlock) ID() ids.ID { return b.id }
|
||||
func (b *testBlock) Parent() ids.ID { return b.parentID }
|
||||
func (b *testBlock) ParentID() ids.ID { return b.parentID }
|
||||
func (b *testBlock) Height() uint64 { return b.height }
|
||||
func (b *testBlock) Timestamp() time.Time { return b.timestamp }
|
||||
func (b *testBlock) Status() uint8 { return b.status }
|
||||
func (b *testBlock) Verify(context.Context) error { return nil }
|
||||
func (b *testBlock) Accept(context.Context) error { return nil }
|
||||
func (b *testBlock) Reject(context.Context) error { return nil }
|
||||
func (b *testBlock) Bytes() []byte { return b.bytes }
|
||||
func (b *testBlock) Bytes() []byte { return b.bytes }
|
||||
|
||||
// mockBlockBuilder implements BlockBuilder for testing
|
||||
type mockBlockBuilder struct {
|
||||
|
||||
+22
-6
@@ -427,11 +427,23 @@ func (t *Transitive) Notify(ctx context.Context, msg Message) error {
|
||||
}
|
||||
|
||||
// ReceiveVote queues a vote for processing.
|
||||
func (t *Transitive) ReceiveVote(vote Vote) {
|
||||
// Returns false if the engine is not started (vote is dropped).
|
||||
func (t *Transitive) ReceiveVote(vote Vote) bool {
|
||||
t.mu.RLock()
|
||||
started := t.started
|
||||
t.mu.RUnlock()
|
||||
|
||||
if !started {
|
||||
// Engine not started - drop vote to prevent state corruption
|
||||
return false
|
||||
}
|
||||
|
||||
select {
|
||||
case t.votes <- vote:
|
||||
return true
|
||||
default:
|
||||
// Channel full; vote will be resent
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,15 +536,19 @@ func (t *Transitive) handleVote(vote Vote) {
|
||||
|
||||
t.votesReceived++
|
||||
|
||||
// Only process votes for blocks we're tracking
|
||||
pending, exists := t.pendingBlocks[vote.BlockID]
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
|
||||
if err := t.consensus.ProcessVote(t.ctx, vote.BlockID, vote.Accept); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if pending, ok := t.pendingBlocks[vote.BlockID]; ok {
|
||||
pending.VoteCount++
|
||||
responses := map[ids.ID]int{vote.BlockID: pending.VoteCount}
|
||||
_ = t.consensus.Poll(t.ctx, responses)
|
||||
}
|
||||
pending.VoteCount++
|
||||
responses := map[ids.ID]int{vote.BlockID: pending.VoteCount}
|
||||
_ = t.consensus.Poll(t.ctx, responses)
|
||||
}
|
||||
|
||||
func (t *Transitive) buildBlocksLocked(ctx context.Context) error {
|
||||
|
||||
+13
-13
@@ -21,16 +21,16 @@ type mockBlock struct {
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
func (b *mockBlock) ID() ids.ID { return b.id }
|
||||
func (b *mockBlock) Parent() ids.ID { return b.parentID }
|
||||
func (b *mockBlock) ParentID() ids.ID { return b.parentID }
|
||||
func (b *mockBlock) Height() uint64 { return b.height }
|
||||
func (b *mockBlock) Timestamp() time.Time { return b.timestamp }
|
||||
func (b *mockBlock) Status() uint8 { return b.status }
|
||||
func (b *mockBlock) ID() ids.ID { return b.id }
|
||||
func (b *mockBlock) Parent() ids.ID { return b.parentID }
|
||||
func (b *mockBlock) ParentID() ids.ID { return b.parentID }
|
||||
func (b *mockBlock) Height() uint64 { return b.height }
|
||||
func (b *mockBlock) Timestamp() time.Time { return b.timestamp }
|
||||
func (b *mockBlock) Status() uint8 { return b.status }
|
||||
func (b *mockBlock) Verify(context.Context) error { return nil }
|
||||
func (b *mockBlock) Accept(context.Context) error { return nil }
|
||||
func (b *mockBlock) Reject(context.Context) error { return nil }
|
||||
func (b *mockBlock) Bytes() []byte { return b.bytes }
|
||||
func (b *mockBlock) Bytes() []byte { return b.bytes }
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
engine := New()
|
||||
@@ -320,12 +320,12 @@ type trackingMockBlock struct {
|
||||
rejectCalled int
|
||||
}
|
||||
|
||||
func (b *trackingMockBlock) ID() ids.ID { return b.id }
|
||||
func (b *trackingMockBlock) Parent() ids.ID { return b.parentID }
|
||||
func (b *trackingMockBlock) ParentID() ids.ID { return b.parentID }
|
||||
func (b *trackingMockBlock) Height() uint64 { return b.height }
|
||||
func (b *trackingMockBlock) Timestamp() time.Time { return b.timestamp }
|
||||
func (b *trackingMockBlock) Status() uint8 { return 0 }
|
||||
func (b *trackingMockBlock) ID() ids.ID { return b.id }
|
||||
func (b *trackingMockBlock) Parent() ids.ID { return b.parentID }
|
||||
func (b *trackingMockBlock) ParentID() ids.ID { return b.parentID }
|
||||
func (b *trackingMockBlock) Height() uint64 { return b.height }
|
||||
func (b *trackingMockBlock) Timestamp() time.Time { return b.timestamp }
|
||||
func (b *trackingMockBlock) Status() uint8 { return 0 }
|
||||
func (b *trackingMockBlock) Verify(context.Context) error { return nil }
|
||||
func (b *trackingMockBlock) Accept(context.Context) error {
|
||||
b.acceptCalled++
|
||||
|
||||
@@ -37,9 +37,14 @@ type NetworkConfig struct {
|
||||
type Gossiper interface {
|
||||
// GossipPut broadcasts a Put message with block data to validators.
|
||||
// Returns the number of validators the message was sent to.
|
||||
GossipPut(chainID ids.ID, netID ids.ID, blockData []byte) int
|
||||
GossipPut(chainID ids.ID, networkID ids.ID, blockData []byte) int
|
||||
// SendPullQuery sends a PullQuery to specific validators requesting votes.
|
||||
SendPullQuery(chainID ids.ID, netID ids.ID, blockID ids.ID, validators []ids.NodeID) int
|
||||
SendPullQuery(chainID ids.ID, networkID ids.ID, blockID ids.ID, validators []ids.NodeID) int
|
||||
// SendChit sends a vote response (Chit) back to the node that requested our vote.
|
||||
// This is called after verifying a block received via PullQuery.
|
||||
// requestID is used to correlate the response with the original request.
|
||||
// preferredID is the block we prefer (voted for).
|
||||
SendChit(toNodeID ids.NodeID, chainID ids.ID, requestID uint32, preferredID ids.ID) error
|
||||
}
|
||||
|
||||
// IntegratedEngine wraps Transitive with network integration and VM notification handling.
|
||||
@@ -266,4 +271,3 @@ func (ie *IntegratedEngine) HandleIncomingBlock(ctx context.Context, blockData [
|
||||
|
||||
return blk, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -540,33 +540,35 @@ func TestRecordPollTransitivelyResetConfidenceTest(t *testing.T) {
|
||||
Beta: 2, // Requires 2 rounds
|
||||
}
|
||||
|
||||
genesisID := ids.GenerateTestID()
|
||||
// Use deterministic IDs to ensure consistent preference selection
|
||||
// IDs are ordered: genesis < block0 < block1 < block2 < block3
|
||||
genesisID := ids.ID{0x00}
|
||||
genesisHeight := uint64(0)
|
||||
genesisTime := time.Now()
|
||||
|
||||
require.NoError(engine.Initialize(ctx, params, genesisID, genesisHeight, genesisTime))
|
||||
|
||||
// Build block tree
|
||||
// Build block tree with deterministic IDs
|
||||
block0 := &TestBlock{
|
||||
IDV: ids.GenerateTestID(),
|
||||
IDV: ids.ID{0x10}, // Lower than block1
|
||||
HeightV: 1,
|
||||
ParentV: genesisID,
|
||||
TimestampV: genesisTime.Add(time.Second),
|
||||
}
|
||||
block1 := &TestBlock{
|
||||
IDV: ids.GenerateTestID(),
|
||||
IDV: ids.ID{0x20}, // Higher than block0
|
||||
HeightV: 1,
|
||||
ParentV: genesisID,
|
||||
TimestampV: genesisTime.Add(time.Second),
|
||||
}
|
||||
block2 := &TestBlock{
|
||||
IDV: ids.GenerateTestID(),
|
||||
IDV: ids.ID{0x30}, // Lower than block3
|
||||
HeightV: 2,
|
||||
ParentV: block1.ID(),
|
||||
TimestampV: genesisTime.Add(2 * time.Second),
|
||||
}
|
||||
block3 := &TestBlock{
|
||||
IDV: ids.GenerateTestID(),
|
||||
IDV: ids.ID{0x40}, // Higher than block2
|
||||
HeightV: 2,
|
||||
ParentV: block1.ID(),
|
||||
TimestampV: genesisTime.Add(2 * time.Second),
|
||||
|
||||
+10
-10
@@ -38,20 +38,20 @@ type Handler interface {
|
||||
|
||||
// getter implementation
|
||||
type getter struct {
|
||||
vtxManager state.Manager
|
||||
sender sender.Sender
|
||||
log log.Logger
|
||||
maxTimeGetAncestors time.Duration
|
||||
ancestorsMaxContainers int
|
||||
vtxManager state.Manager
|
||||
sender sender.Sender
|
||||
log log.Logger
|
||||
maxTimeGetAncestors time.Duration
|
||||
ancestorsMaxContainers int
|
||||
}
|
||||
|
||||
// Config for creating a Handler
|
||||
type Config struct {
|
||||
VtxManager state.Manager
|
||||
Sender sender.Sender
|
||||
Log log.Logger
|
||||
MaxTimeGetAncestors time.Duration
|
||||
AncestorsMaxContainers int
|
||||
VtxManager state.Manager
|
||||
Sender sender.Sender
|
||||
Log log.Logger
|
||||
MaxTimeGetAncestors time.Duration
|
||||
AncestorsMaxContainers int
|
||||
}
|
||||
|
||||
// New creates a new getter
|
||||
|
||||
@@ -85,10 +85,10 @@ type GPUBuffer struct {
|
||||
capacity int
|
||||
|
||||
// Transaction data (CPU-side, copied to GPU)
|
||||
txHashes [][32]byte
|
||||
signatures [][]byte
|
||||
publicKeys [][]byte
|
||||
sigTypes []SignatureType
|
||||
txHashes [][32]byte
|
||||
signatures [][]byte
|
||||
publicKeys [][]byte
|
||||
sigTypes []SignatureType
|
||||
|
||||
// Results (GPU-side, copied back)
|
||||
validFlags []bool
|
||||
@@ -217,8 +217,8 @@ type GPUMerkleTree struct {
|
||||
gpuNodes uintptr
|
||||
|
||||
// Root cached on CPU after computation
|
||||
root [32]byte
|
||||
rootMu sync.RWMutex
|
||||
root [32]byte
|
||||
rootMu sync.RWMutex
|
||||
|
||||
// Pending leaves to insert
|
||||
pending [][32]byte
|
||||
@@ -504,9 +504,9 @@ func (p *GPUBatchPipeline) swapBuffers() {
|
||||
// processBatch executes signature verification and aggregation.
|
||||
func (p *GPUBatchPipeline) processBatch(buf *GPUBuffer, batchID uint64, txs []Transaction) *BatchResult {
|
||||
result := &BatchResult{
|
||||
BatchID: batchID,
|
||||
ProcessedCount: buf.count,
|
||||
Errors: make([]TransactionError, 0),
|
||||
BatchID: batchID,
|
||||
ProcessedCount: buf.count,
|
||||
Errors: make([]TransactionError, 0),
|
||||
SignatureProofs: make([]SignatureProof, 0, buf.count),
|
||||
}
|
||||
|
||||
|
||||
@@ -503,7 +503,7 @@ func TestLuxConsensusPollFocusDecideReject(t *testing.T) {
|
||||
// Now state is 1, threshold is 1, so decided=true
|
||||
// Poll with low ratio to hit the reject branch
|
||||
lowRatioResponses := map[ids.ID]int{
|
||||
item2: 1, // Only 10% - below alpha (90%)
|
||||
item2: 1, // Only 10% - below alpha (90%)
|
||||
ids.GenerateTestID(): 9, // 90% for another item
|
||||
}
|
||||
continuePolling = lc2.Poll(lowRatioResponses)
|
||||
|
||||
@@ -86,6 +86,9 @@ func (c *CGOConsensus) Add(block Block) error {
|
||||
}
|
||||
c.cacheMu.Unlock()
|
||||
|
||||
// Update preference to latest block
|
||||
c.preference.Store(blockID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+15
-15
@@ -449,16 +449,16 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
validIDStr := validID.String()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
block *quasar.Block
|
||||
wantBLS []byte
|
||||
wantPQ []byte
|
||||
name string
|
||||
block *quasar.Block
|
||||
wantBLS []byte
|
||||
wantPQ []byte
|
||||
}{
|
||||
{
|
||||
name: "block with certificate",
|
||||
block: &quasar.Block{
|
||||
Hash: validIDStr,
|
||||
Height: 100,
|
||||
Height: 100,
|
||||
Timestamp: testTime,
|
||||
Cert: &quasar.BlockCert{
|
||||
BLS: []byte("bls-proof-data"),
|
||||
@@ -472,9 +472,9 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
name: "block without certificate",
|
||||
block: &quasar.Block{
|
||||
Hash: validIDStr,
|
||||
Height: 50,
|
||||
Height: 50,
|
||||
Timestamp: testTime,
|
||||
Cert: nil,
|
||||
Cert: nil,
|
||||
},
|
||||
wantBLS: nil,
|
||||
wantPQ: nil,
|
||||
@@ -483,7 +483,7 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
name: "block with empty proofs in cert",
|
||||
block: &quasar.Block{
|
||||
Hash: validIDStr,
|
||||
Height: 75,
|
||||
Height: 75,
|
||||
Timestamp: testTime,
|
||||
Cert: &quasar.BlockCert{
|
||||
BLS: []byte{},
|
||||
@@ -497,9 +497,9 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
name: "block with invalid hash",
|
||||
block: &quasar.Block{
|
||||
Hash: "invalid-hash",
|
||||
Height: 25,
|
||||
Height: 25,
|
||||
Timestamp: testTime,
|
||||
Cert: nil,
|
||||
Cert: nil,
|
||||
},
|
||||
wantBLS: nil,
|
||||
wantPQ: nil,
|
||||
@@ -508,9 +508,9 @@ func TestBlockToFinalityEvent(t *testing.T) {
|
||||
name: "block with empty hash",
|
||||
block: &quasar.Block{
|
||||
Hash: "",
|
||||
Height: 10,
|
||||
Height: 10,
|
||||
Timestamp: testTime,
|
||||
Cert: nil,
|
||||
Cert: nil,
|
||||
},
|
||||
wantBLS: nil,
|
||||
wantPQ: nil,
|
||||
@@ -599,7 +599,7 @@ func TestSetFinalizedCallbackInvocation(t *testing.T) {
|
||||
// Invoke the callback with a test block
|
||||
testBlock := &quasar.Block{
|
||||
Hash: validID.String(),
|
||||
Height: 42,
|
||||
Height: 42,
|
||||
Timestamp: time.Now(),
|
||||
Cert: &quasar.BlockCert{
|
||||
BLS: []byte("test-bls"),
|
||||
@@ -643,9 +643,9 @@ func TestSetFinalizedCallbackInvocationNilCert(t *testing.T) {
|
||||
// Invoke the callback with a block that has no cert
|
||||
testBlock := &quasar.Block{
|
||||
Hash: validID.String(),
|
||||
Height: 100,
|
||||
Height: 100,
|
||||
Timestamp: time.Now(),
|
||||
Cert: nil,
|
||||
Cert: nil,
|
||||
}
|
||||
|
||||
cb(testBlock)
|
||||
|
||||
@@ -18,9 +18,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/consensus/engine"
|
||||
"github.com/luxfi/crypto"
|
||||
"github.com/luxfi/geth/common"
|
||||
"github.com/luxfi/geth/core/types"
|
||||
"github.com/luxfi/crypto"
|
||||
"github.com/luxfi/ids"
|
||||
)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// This demonstrates the complete Quasar consensus protocol showing how:
|
||||
// - FPC provides dynamic thresholds
|
||||
// - Wave achieves metastable convergence
|
||||
// - Wave achieves metastable convergence
|
||||
// - Horizon detects DAG finality
|
||||
// - All together achieve <1s quantum finality
|
||||
//
|
||||
@@ -32,7 +32,7 @@ func main() {
|
||||
demonstrateWaveConsensus()
|
||||
demonstrateHorizonFinality()
|
||||
demonstrateQuasarFlow()
|
||||
|
||||
|
||||
fmt.Println("✅ Quasar protocol demonstration complete!")
|
||||
fmt.Println()
|
||||
}
|
||||
@@ -40,26 +40,26 @@ func main() {
|
||||
func demonstrateFPC() {
|
||||
fmt.Println("━━━ Part 1: Fast Probabilistic Consensus (FPC) ━━━")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
selector := fpc.NewSelector(0.5, 0.8, nil)
|
||||
k := 20
|
||||
|
||||
|
||||
fmt.Println(" FPC prevents stuck states with dynamic thresholds")
|
||||
fmt.Printf(" Theta range: [0.5, 0.8] (50%%-80%% quorum)\n")
|
||||
fmt.Printf(" Sample size: %d validators\n", k)
|
||||
fmt.Println()
|
||||
|
||||
|
||||
fmt.Println(" Threshold selection (PRF-based):")
|
||||
thresholdSet := make(map[int]bool)
|
||||
|
||||
|
||||
for round := uint64(0); round < 10; round++ {
|
||||
threshold := selector.SelectThreshold(round, k)
|
||||
thresholdSet[threshold] = true
|
||||
theta := float64(threshold) / float64(k)
|
||||
fmt.Printf(" Round %2d: α=%2d/%d (θ=%.3f) %s\n",
|
||||
fmt.Printf(" Round %2d: α=%2d/%d (θ=%.3f) %s\n",
|
||||
round, threshold, k, theta, bar(theta, 20))
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf("\n ✓ %d unique thresholds prevent stuck states\n", len(thresholdSet))
|
||||
fmt.Println()
|
||||
}
|
||||
@@ -67,14 +67,14 @@ func demonstrateFPC() {
|
||||
func demonstrateWaveConsensus() {
|
||||
fmt.Println("━━━ Part 2: Wave Consensus (Block Finalization) ━━━")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
cfg := consensus.DefaultConfig()
|
||||
chain := consensus.NewChain(cfg)
|
||||
|
||||
|
||||
ctx := context.Background()
|
||||
chain.Start(ctx)
|
||||
defer chain.Stop()
|
||||
|
||||
|
||||
// Create and finalize block
|
||||
block := &consensus.Block{
|
||||
ID: consensus.ID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32},
|
||||
@@ -83,71 +83,71 @@ func demonstrateWaveConsensus() {
|
||||
Time: time.Now(),
|
||||
Payload: []byte("Quasar block with quantum finality"),
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf(" Block: %x...\n", block.ID[:8])
|
||||
|
||||
|
||||
start := time.Now()
|
||||
chain.Add(ctx, block)
|
||||
|
||||
|
||||
// Simulate votes
|
||||
for i := 0; i < 20; i++ {
|
||||
nodeID := consensus.NodeID{byte(i + 1)}
|
||||
vote := consensus.NewVote(block.ID, consensus.VotePreference, nodeID)
|
||||
chain.RecordVote(ctx, vote)
|
||||
|
||||
|
||||
if (i+1)%5 == 0 {
|
||||
fmt.Printf(" Votes: %2d/20 %s\n", i+1, bar(float64(i+1)/20.0, 30))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
elapsed := time.Since(start)
|
||||
status := chain.GetStatus(block.ID)
|
||||
|
||||
|
||||
fmt.Printf("\n Status: %v\n", status)
|
||||
fmt.Printf(" Time: %v\n", elapsed)
|
||||
|
||||
|
||||
if status == consensus.StatusAccepted {
|
||||
fmt.Println(" ✅ Block finalized with BFT guarantees")
|
||||
}
|
||||
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func demonstrateHorizonFinality() {
|
||||
fmt.Println("━━━ Part 3: Horizon DAG Finality Algorithms ━━━")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
genesis := ids.Empty
|
||||
b1, _ := ids.ToID([]byte("block1_left_____________________"))
|
||||
b2, _ := ids.ToID([]byte("block2_right____________________"))
|
||||
b3, _ := ids.ToID([]byte("block3_merge____________________"))
|
||||
|
||||
|
||||
store := createMockDAG(genesis, b1, b2, b3)
|
||||
|
||||
|
||||
fmt.Println(" DAG Structure: Genesis → (B1, B2) → B3")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
// Test all algorithms
|
||||
fmt.Println(" Horizon Algorithms Working:")
|
||||
fmt.Printf(" ✓ IsReachable: %v\n", dag.IsReachable[ids.ID](store, genesis, b3))
|
||||
fmt.Printf(" ✓ LCA: %s\n", dag.LCA[ids.ID](store, b1, b2))
|
||||
fmt.Printf(" ✓ SafePrefix: %d finalized\n", len(dag.ComputeSafePrefix[ids.ID](store, []ids.ID{b3})))
|
||||
fmt.Printf(" ✓ ChooseFrontier: %d selected\n", len(dag.ChooseFrontier[ids.ID]([]ids.ID{b1, b2, b3})))
|
||||
|
||||
|
||||
horizons := []dag.EventHorizon[ids.ID]{
|
||||
{Checkpoint: genesis, Height: 0, Validators: []string{"set0"}, Signature: []byte("sig0")},
|
||||
}
|
||||
newH := dag.Horizon[ids.ID](store, horizons)
|
||||
fmt.Printf(" ✓ Horizon: Height %d → %d\n", 0, newH.Height)
|
||||
fmt.Printf(" ✓ BeyondHorizon: %v\n", dag.BeyondHorizon[ids.ID](store, b3, newH))
|
||||
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func demonstrateQuasarFlow() {
|
||||
fmt.Println("━━━ Part 4: Complete Quasar Protocol ━━━")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
fmt.Println(" Quasar 2-Round Quantum Finality:")
|
||||
fmt.Println()
|
||||
fmt.Println(" ┌─────────────────────────────────────────┐")
|
||||
|
||||
@@ -5,6 +5,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -19,24 +20,24 @@ import (
|
||||
func TestFPCDynamicThresholds(t *testing.T) {
|
||||
selector := fpc.NewSelector(0.5, 0.8, nil)
|
||||
k := 20
|
||||
|
||||
|
||||
// Test determinism: same round = same threshold
|
||||
t1 := selector.SelectThreshold(0, k)
|
||||
t2 := selector.SelectThreshold(0, k)
|
||||
require.Equal(t, t1, t2, "Same round must give same threshold (determinism)")
|
||||
|
||||
|
||||
// Test variety: different rounds = different thresholds
|
||||
thresholds := make(map[int]bool)
|
||||
for round := uint64(0); round < 100; round++ {
|
||||
threshold := selector.SelectThreshold(round, k)
|
||||
|
||||
|
||||
// Verify threshold is in valid range
|
||||
require.GreaterOrEqual(t, threshold, 10, "Threshold should be ≥ 50%% of k")
|
||||
require.LessOrEqual(t, threshold, 16, "Threshold should be ≤ 80%% of k")
|
||||
|
||||
|
||||
thresholds[threshold] = true
|
||||
}
|
||||
|
||||
|
||||
require.Greater(t, len(thresholds), 1, "Should have variety in thresholds")
|
||||
t.Logf("✓ FPC generated %d unique thresholds across 100 rounds", len(thresholds))
|
||||
}
|
||||
@@ -45,12 +46,12 @@ func TestFPCDynamicThresholds(t *testing.T) {
|
||||
func TestBlockFinalization(t *testing.T) {
|
||||
cfg := consensus.DefaultConfig()
|
||||
chain := consensus.NewChain(cfg)
|
||||
|
||||
|
||||
ctx := context.Background()
|
||||
err := chain.Start(ctx)
|
||||
require.NoError(t, err)
|
||||
defer chain.Stop()
|
||||
|
||||
|
||||
// Create block
|
||||
block := &consensus.Block{
|
||||
ID: consensus.ID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32},
|
||||
@@ -59,27 +60,27 @@ func TestBlockFinalization(t *testing.T) {
|
||||
Time: time.Now(),
|
||||
Payload: []byte("Test block finalization"),
|
||||
}
|
||||
|
||||
|
||||
// Add block
|
||||
err = chain.Add(ctx, block)
|
||||
require.NoError(t, err, "Block should be added")
|
||||
|
||||
|
||||
// Simulate votes
|
||||
validators := make([]consensus.NodeID, 20)
|
||||
for i := range validators {
|
||||
validators[i] = consensus.NodeID{byte(i + 1)}
|
||||
}
|
||||
|
||||
|
||||
for _, validator := range validators {
|
||||
vote := consensus.NewVote(block.ID, consensus.VotePreference, validator)
|
||||
err = chain.RecordVote(ctx, vote)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
||||
// Verify finality
|
||||
status := chain.GetStatus(block.ID)
|
||||
require.Equal(t, consensus.StatusAccepted, status, "Block should achieve finality")
|
||||
|
||||
|
||||
t.Log("✓ Block achieved finality with full validator support")
|
||||
}
|
||||
|
||||
@@ -89,18 +90,18 @@ func TestHorizonReachability(t *testing.T) {
|
||||
b1, _ := ids.ToID([]byte("block_1_________________________"))
|
||||
b2, _ := ids.ToID([]byte("block_2_________________________"))
|
||||
b3, _ := ids.ToID([]byte("block_3_________________________"))
|
||||
|
||||
|
||||
store := createMockDAG(genesis, b1, b2, b3)
|
||||
|
||||
|
||||
// Test forward reachability
|
||||
require.True(t, dag.IsReachable[ids.ID](store, genesis, b1), "Genesis should reach B1")
|
||||
require.True(t, dag.IsReachable[ids.ID](store, genesis, b3), "Genesis should reach B3")
|
||||
require.True(t, dag.IsReachable[ids.ID](store, b1, b3), "B1 should reach B3")
|
||||
|
||||
|
||||
// Test backward non-reachability (DAG is directed)
|
||||
require.False(t, dag.IsReachable[ids.ID](store, b3, genesis), "B3 cannot reach Genesis")
|
||||
require.False(t, dag.IsReachable[ids.ID](store, b1, genesis), "B1 cannot reach Genesis")
|
||||
|
||||
|
||||
t.Log("✓ Reachability algorithm works correctly")
|
||||
}
|
||||
|
||||
@@ -110,13 +111,13 @@ func TestLCA(t *testing.T) {
|
||||
b1, _ := ids.ToID([]byte("block_1_________________________"))
|
||||
b2, _ := ids.ToID([]byte("block_2_________________________"))
|
||||
b3, _ := ids.ToID([]byte("block_3_________________________"))
|
||||
|
||||
|
||||
store := createMockDAG(genesis, b1, b2, b3)
|
||||
|
||||
|
||||
// LCA of parallel blocks should be their common parent
|
||||
lca := dag.LCA[ids.ID](store, b1, b2)
|
||||
require.Equal(t, genesis, lca, "LCA of B1 and B2 should be Genesis")
|
||||
|
||||
|
||||
t.Log("✓ LCA algorithm works correctly")
|
||||
}
|
||||
|
||||
@@ -126,13 +127,13 @@ func TestSafePrefix(t *testing.T) {
|
||||
b1, _ := ids.ToID([]byte("block_1_________________________"))
|
||||
b2, _ := ids.ToID([]byte("block_2_________________________"))
|
||||
b3, _ := ids.ToID([]byte("block_3_________________________"))
|
||||
|
||||
|
||||
store := createMockDAG(genesis, b1, b2, b3)
|
||||
|
||||
|
||||
// Safe prefix with B3 as frontier should include ancestors
|
||||
frontier := []ids.ID{b3}
|
||||
safe := dag.ComputeSafePrefix[ids.ID](store, frontier)
|
||||
|
||||
|
||||
require.NotNil(t, safe, "Should return safe prefix")
|
||||
t.Logf("✓ Safe prefix computed: %d vertices finalized", len(safe))
|
||||
}
|
||||
@@ -144,13 +145,13 @@ func TestChooseFrontier(t *testing.T) {
|
||||
for i := range vertices {
|
||||
vertices[i], _ = ids.ToID([]byte(fmt.Sprintf("vertex_%d", i)))
|
||||
}
|
||||
|
||||
|
||||
// Choose frontier with Byzantine tolerance
|
||||
chosen := dag.ChooseFrontier[ids.ID](vertices)
|
||||
|
||||
|
||||
require.NotEmpty(t, chosen, "Should choose some vertices")
|
||||
require.LessOrEqual(t, len(chosen), len(vertices), "Can't choose more than available")
|
||||
|
||||
|
||||
// For 10 vertices, f=(10-1)/3=3, so 2f+1=7
|
||||
// Should choose min(7, 10) = 7 or all if < 7
|
||||
t.Logf("✓ Chose %d vertices with Byzantine tolerance", len(chosen))
|
||||
@@ -162,9 +163,9 @@ func TestEventHorizon(t *testing.T) {
|
||||
b1, _ := ids.ToID([]byte("block_1_________________________"))
|
||||
b2, _ := ids.ToID([]byte("block_2_________________________"))
|
||||
b3, _ := ids.ToID([]byte("block_3_________________________"))
|
||||
|
||||
|
||||
store := createMockDAG(genesis, b1, b2, b3)
|
||||
|
||||
|
||||
// Create initial checkpoint
|
||||
checkpoints := []dag.EventHorizon[ids.ID]{
|
||||
{
|
||||
@@ -174,13 +175,13 @@ func TestEventHorizon(t *testing.T) {
|
||||
Signature: []byte("corona+bls_sig_0"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
// Compute new horizon
|
||||
newHorizon := dag.Horizon[ids.ID](store, checkpoints)
|
||||
|
||||
|
||||
require.NotEqual(t, ids.ID{}, newHorizon.Checkpoint, "Should have valid checkpoint")
|
||||
require.GreaterOrEqual(t, newHorizon.Height, checkpoints[0].Height, "Horizon should not regress")
|
||||
|
||||
|
||||
t.Logf("✓ Event horizon advanced from height %d to %d", checkpoints[0].Height, newHorizon.Height)
|
||||
}
|
||||
|
||||
@@ -190,20 +191,20 @@ func TestBeyondHorizon(t *testing.T) {
|
||||
b1, _ := ids.ToID([]byte("block_1_________________________"))
|
||||
b2, _ := ids.ToID([]byte("block_2_________________________"))
|
||||
b3, _ := ids.ToID([]byte("block_3_________________________"))
|
||||
|
||||
|
||||
store := createMockDAG(genesis, b1, b2, b3)
|
||||
|
||||
|
||||
horizon := dag.EventHorizon[ids.ID]{
|
||||
Checkpoint: genesis,
|
||||
Height: 0,
|
||||
Validators: []string{"set"},
|
||||
Signature: []byte("sig"),
|
||||
}
|
||||
|
||||
|
||||
// Blocks reachable from genesis should be beyond horizon
|
||||
beyond := dag.BeyondHorizon[ids.ID](store, b3, horizon)
|
||||
require.True(t, beyond, "B3 should be beyond horizon (reachable from checkpoint)")
|
||||
|
||||
|
||||
t.Log("✓ BeyondHorizon correctly identifies finalized vertices")
|
||||
}
|
||||
|
||||
@@ -212,12 +213,12 @@ func TestQuasarIntegration(t *testing.T) {
|
||||
// Create chain
|
||||
cfg := consensus.DefaultConfig()
|
||||
chain := consensus.NewChain(cfg)
|
||||
|
||||
|
||||
ctx := context.Background()
|
||||
err := chain.Start(ctx)
|
||||
require.NoError(t, err)
|
||||
defer chain.Stop()
|
||||
|
||||
|
||||
// Add multiple blocks
|
||||
blocks := make([]*consensus.Block, 5)
|
||||
for i := range blocks {
|
||||
@@ -228,24 +229,24 @@ func TestQuasarIntegration(t *testing.T) {
|
||||
Time: time.Now(),
|
||||
Payload: []byte(fmt.Sprintf("Block %d", i+1)),
|
||||
}
|
||||
|
||||
|
||||
err = chain.Add(ctx, blocks[i])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
|
||||
// Vote on all blocks
|
||||
validators := make([]consensus.NodeID, 20)
|
||||
for i := range validators {
|
||||
validators[i] = consensus.NodeID{byte(i + 1)}
|
||||
}
|
||||
|
||||
|
||||
for _, block := range blocks {
|
||||
for _, validator := range validators {
|
||||
vote := consensus.NewVote(block.ID, consensus.VotePreference, validator)
|
||||
chain.RecordVote(ctx, vote)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Verify all blocks finalized
|
||||
finalizedCount := 0
|
||||
for _, block := range blocks {
|
||||
@@ -253,7 +254,7 @@ func TestQuasarIntegration(t *testing.T) {
|
||||
finalizedCount++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
require.Greater(t, finalizedCount, 0, "At least some blocks should finalize")
|
||||
t.Logf("✓ %d/%d blocks achieved finality", finalizedCount, len(blocks))
|
||||
}
|
||||
@@ -261,34 +262,34 @@ func TestQuasarIntegration(t *testing.T) {
|
||||
// TestCertificateThresholds tests Byzantine fault tolerance math
|
||||
func TestCertificateThresholds(t *testing.T) {
|
||||
testCases := []struct {
|
||||
n int
|
||||
f int
|
||||
certThreshold int
|
||||
description string
|
||||
n int
|
||||
f int
|
||||
certThreshold int
|
||||
description string
|
||||
}{
|
||||
{20, 6, 13, "Production network (n=20, f=6)"},
|
||||
{100, 33, 67, "Large network (n=100, f=33)"},
|
||||
{7, 2, 5, "Small network (n=7, f=2)"},
|
||||
{4, 1, 3, "Minimal BFT (n=4, f=1)"},
|
||||
}
|
||||
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
params := dag.Params{N: tc.n, F: tc.f}
|
||||
|
||||
|
||||
// Verify Byzantine tolerance: n > 3f
|
||||
require.Greater(t, params.N, 3*params.F, "Must have n > 3f for BFT")
|
||||
|
||||
|
||||
// Verify certificate threshold: 2f+1
|
||||
certThreshold := 2*params.F + 1
|
||||
require.Equal(t, tc.certThreshold, certThreshold)
|
||||
|
||||
|
||||
// Verify safety: can't have both cert and skip
|
||||
// (need 2f+1 for cert AND 2f+1 for skip = 4f+2 > n when n=3f+1)
|
||||
require.Greater(t, 2*certThreshold, params.N,
|
||||
require.Greater(t, 2*certThreshold, params.N,
|
||||
"Certificate and skip thresholds ensure mutual exclusivity")
|
||||
|
||||
t.Logf("✓ n=%d, f=%d: requires %d/%d validators (%.1f%%)",
|
||||
|
||||
t.Logf("✓ n=%d, f=%d: requires %d/%d validators (%.1f%%)",
|
||||
tc.n, tc.f, certThreshold, tc.n, 100.0*float64(certThreshold)/float64(tc.n))
|
||||
})
|
||||
}
|
||||
@@ -298,11 +299,11 @@ func TestCertificateThresholds(t *testing.T) {
|
||||
func BenchmarkQuasarFullProtocol(b *testing.B) {
|
||||
cfg := consensus.DefaultConfig()
|
||||
chain := consensus.NewChain(cfg)
|
||||
|
||||
|
||||
ctx := context.Background()
|
||||
chain.Start(ctx)
|
||||
defer chain.Stop()
|
||||
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
block := &consensus.Block{
|
||||
@@ -311,9 +312,9 @@ func BenchmarkQuasarFullProtocol(b *testing.B) {
|
||||
Height: uint64(i + 1),
|
||||
Payload: []byte("benchmark"),
|
||||
}
|
||||
|
||||
|
||||
chain.Add(ctx, block)
|
||||
|
||||
|
||||
// Simulate votes
|
||||
for j := 0; j < 20; j++ {
|
||||
vote := consensus.NewVote(block.ID, consensus.VotePreference, consensus.NodeID{byte(j)})
|
||||
@@ -326,7 +327,7 @@ func BenchmarkQuasarFullProtocol(b *testing.B) {
|
||||
func BenchmarkFPCThresholdSelection(b *testing.B) {
|
||||
selector := fpc.NewSelector(0.5, 0.8, nil)
|
||||
k := 20
|
||||
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = selector.SelectThreshold(uint64(i), k)
|
||||
@@ -339,35 +340,35 @@ func BenchmarkHorizonAlgorithms(b *testing.B) {
|
||||
b1, _ := ids.ToID([]byte("block_1_________________________"))
|
||||
b2, _ := ids.ToID([]byte("block_2_________________________"))
|
||||
b3, _ := ids.ToID([]byte("block_3_________________________"))
|
||||
|
||||
|
||||
store := createMockDAG(genesis, b1, b2, b3)
|
||||
|
||||
|
||||
b.Run("IsReachable", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
dag.IsReachable[ids.ID](store, genesis, b3)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
b.Run("LCA", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
dag.LCA[ids.ID](store, b1, b2)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
b.Run("ComputeSafePrefix", func(b *testing.B) {
|
||||
frontier := []ids.ID{b3}
|
||||
for i := 0; i < b.N; i++ {
|
||||
dag.ComputeSafePrefix[ids.ID](store, frontier)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
b.Run("ChooseFrontier", func(b *testing.B) {
|
||||
vertices := []ids.ID{b1, b2, b3}
|
||||
for i := 0; i < b.N; i++ {
|
||||
dag.ChooseFrontier[ids.ID](vertices)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
b.Run("Horizon", func(b *testing.B) {
|
||||
checkpoints := []dag.EventHorizon[ids.ID]{
|
||||
{Checkpoint: genesis, Height: 0},
|
||||
|
||||
@@ -15,7 +15,7 @@ require (
|
||||
github.com/luxfi/math v1.2.0
|
||||
github.com/luxfi/p2p v1.4.6
|
||||
github.com/luxfi/corona v0.2.0
|
||||
github.com/luxfi/vm v1.0.1
|
||||
github.com/luxfi/vm v1.0.2
|
||||
github.com/luxfi/warp v1.18.2
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/prometheus/client_model v0.6.2
|
||||
@@ -86,7 +86,7 @@ require (
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/net v0.48.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/text v0.32.0 // indirect
|
||||
|
||||
@@ -152,8 +152,8 @@ github.com/luxfi/sampler v1.0.0 h1:k8Sf6otW83w4pQp0jXLA+g3J/joB7w7SqXQsWmNTOV0=
|
||||
github.com/luxfi/sampler v1.0.0/go.mod h1:f96/ozlj9vFfZj+akLtrHn4VpulQahwB+MQQhpeIekk=
|
||||
github.com/luxfi/utils v1.1.0 h1:ti7HvjNwJd4ILDMERJtOAWE9mF8l+zqDVkgWnF7Agic=
|
||||
github.com/luxfi/utils v1.1.0/go.mod h1:ABqhBdGNig0CaDcnNYldv1byS0BTNi5IKPbJSPF1p98=
|
||||
github.com/luxfi/vm v1.0.1 h1:eZqrp6mEFPkhiv5kf5ZXmYAbXXjpS9axpUQG3cd3yts=
|
||||
github.com/luxfi/vm v1.0.1/go.mod h1:PJinuF4McLaHN57iKf8p7h89wIQhQT//LD/fac+/Dk8=
|
||||
github.com/luxfi/vm v1.0.2 h1:JnMm6QTh1nwWKXFy4Qf9Ej38KyXzFeprcy3Rp8/516s=
|
||||
github.com/luxfi/vm v1.0.2/go.mod h1:cRmy9WL9keIkl5XgGcP1w/RbwiMSYucjGdQ3LrSF0aQ=
|
||||
github.com/luxfi/warp v1.18.2 h1:TWmXjKXI7nxaDOnXIrw8BQTI/nCEniA17bs06bwNB4Q=
|
||||
github.com/luxfi/warp v1.18.2/go.mod h1:qu3TZv98repNhIDf04I6pzXePSgHjzP+JoSfWmF4PBA=
|
||||
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
||||
@@ -260,8 +260,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package flare
|
||||
|
||||
import (
|
||||
"github.com/luxfi/consensus/core/dag"
|
||||
"testing"
|
||||
|
||||
"github.com/luxfi/consensus/core/dag"
|
||||
)
|
||||
|
||||
type testVertex struct {
|
||||
|
||||
+34
-21
@@ -1,3 +1,15 @@
|
||||
// Package quasar - BLS DAG Event Horizon Implementation
|
||||
//
|
||||
// This file implements DAG-based event horizon consensus for vertex ordering.
|
||||
// It uses SHA256 commitments for local attestations within the DAG.
|
||||
//
|
||||
// IMPORTANT: This is NOT the threshold signature implementation.
|
||||
// For real cryptographic threshold signatures (BLS + Corona), see:
|
||||
// - quasar.go: Signer struct with github.com/luxfi/crypto/bls integration
|
||||
// - epoch.go: Corona threshold signing via github.com/luxfi/corona/threshold
|
||||
//
|
||||
// The BLS struct here handles DAG vertex ordering and event horizon
|
||||
// establishment, which operates independently of block finality signatures.
|
||||
package quasar
|
||||
|
||||
import (
|
||||
@@ -95,14 +107,16 @@ func (q *BLS) SetFinalizedCallback(cb func(*Block)) {
|
||||
q.finalizedCb = cb
|
||||
}
|
||||
|
||||
// generateBLSAggregate generates a BLS aggregate signature
|
||||
// generateBLSAggregate generates a commitment for DAG event horizon.
|
||||
// NOTE: This uses SHA256 as a placeholder for local vertex ordering.
|
||||
// For threshold block finality with real BLS signatures, use the Signer
|
||||
// in quasar.go which integrates with github.com/luxfi/crypto/bls.
|
||||
func (q *BLS) generateBLSAggregate(blockID ids.ID, votes map[string]int) []byte {
|
||||
if len(q.blsKey) == 0 {
|
||||
// Return empty if no key
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
// Create deterministic signature based on blockID and votes
|
||||
// Create deterministic commitment based on blockID and votes
|
||||
h := sha256.New()
|
||||
h.Write(blockID[:])
|
||||
|
||||
@@ -118,21 +132,22 @@ func (q *BLS) generateBLSAggregate(blockID ids.ID, votes map[string]int) []byte
|
||||
h.Write(countBytes)
|
||||
}
|
||||
|
||||
// Mix in BLS key
|
||||
// Mix in key for local binding
|
||||
h.Write(q.blsKey)
|
||||
|
||||
// Production: Use real BLS aggregation from github.com/luxfi/crypto/bls
|
||||
return h.Sum(nil)
|
||||
}
|
||||
|
||||
// generatePQCertificate generates a post-quantum certificate
|
||||
// generatePQCertificate generates a post-quantum commitment for DAG event horizon.
|
||||
// NOTE: This uses SHA256 as a placeholder for local vertex ordering.
|
||||
// For real PQ threshold signatures, use the Signer in quasar.go which
|
||||
// integrates with github.com/luxfi/corona/threshold.
|
||||
func (q *BLS) generatePQCertificate(blockID ids.ID, votes map[string]int) []byte {
|
||||
if len(q.pqKey) == 0 {
|
||||
// Return empty if no key
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
// Create message to sign
|
||||
// Create message to commit
|
||||
h := sha256.New()
|
||||
h.Write(blockID[:])
|
||||
|
||||
@@ -150,12 +165,11 @@ func (q *BLS) generatePQCertificate(blockID ids.ID, votes map[string]int) []byte
|
||||
|
||||
message := h.Sum(nil)
|
||||
|
||||
// Create certificate
|
||||
// Create local commitment
|
||||
cert := sha256.New()
|
||||
cert.Write(message)
|
||||
cert.Write(q.pqKey)
|
||||
|
||||
// Production: Use ML-DSA from github.com/luxfi/crypto/mldsa or SLH-DSA from /slhdsa
|
||||
return cert.Sum(nil)
|
||||
}
|
||||
|
||||
@@ -249,15 +263,15 @@ func (q *BLS) GetLatestHorizon() *dag.EventHorizon[VertexID] {
|
||||
return &q.horizons[len(q.horizons)-1]
|
||||
}
|
||||
|
||||
// createHorizonSignature creates a Corona + BLS fusion signature for the event horizon.
|
||||
// The signature combines:
|
||||
// 1. BLS aggregate signature (32 bytes) - for efficiency
|
||||
// 2. Corona post-quantum hash (32 bytes) - for security binding
|
||||
// createHorizonSignature creates a local attestation for the event horizon checkpoint.
|
||||
// This is a SHA256-based commitment used for DAG vertex ordering.
|
||||
//
|
||||
// Note: Full threshold signing (multi-party Corona) is handled by Quasar.hybridConsensus.
|
||||
// This function creates a local attestation for the horizon checkpoint.
|
||||
// NOTE: For production threshold signatures with real BLS + Corona,
|
||||
// use the Signer in quasar.go which integrates:
|
||||
// - github.com/luxfi/crypto/bls for BLS threshold signatures
|
||||
// - github.com/luxfi/corona/threshold for post-quantum signatures
|
||||
func (q *BLS) createHorizonSignature(checkpoint VertexID, validators []string) []byte {
|
||||
// Create message to sign: checkpoint + sorted validators
|
||||
// Create message: checkpoint + validators
|
||||
h := sha256.New()
|
||||
h.Write(checkpoint[:])
|
||||
for _, v := range validators {
|
||||
@@ -265,19 +279,18 @@ func (q *BLS) createHorizonSignature(checkpoint VertexID, validators []string) [
|
||||
}
|
||||
message := h.Sum(nil)
|
||||
|
||||
// BLS component: sign with BLS key
|
||||
// BLS component commitment
|
||||
blsSig := sha256.New()
|
||||
blsSig.Write(message)
|
||||
blsSig.Write(q.blsKey)
|
||||
blsPart := blsSig.Sum(nil)
|
||||
|
||||
// PQ component: sign with post-quantum key
|
||||
// PQ component commitment
|
||||
pqSig := sha256.New()
|
||||
pqSig.Write(message)
|
||||
pqSig.Write(q.pqKey)
|
||||
pqPart := pqSig.Sum(nil)
|
||||
|
||||
// Fusion: concatenate both signatures (64 bytes total)
|
||||
// Production: Use github.com/luxfi/crypto/bls and /mldsa for real signatures
|
||||
// Combined attestation (64 bytes)
|
||||
return append(blsPart, pqPart...)
|
||||
}
|
||||
|
||||
@@ -536,9 +536,9 @@ func TestEngine_ComputeHash(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHybridConsensus_AddRemoveValidator(t *testing.T) {
|
||||
hc, err := newHybridConsensus(1)
|
||||
hc, err := newCertifier(1)
|
||||
if err != nil {
|
||||
t.Fatalf("newHybridConsensus failed: %v", err)
|
||||
t.Fatalf("newCertifier failed: %v", err)
|
||||
}
|
||||
|
||||
hc.AddValidator("v1", 100)
|
||||
@@ -560,9 +560,9 @@ func TestHybridConsensus_AddRemoveValidator(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHybridConsensus_GenerateCert(t *testing.T) {
|
||||
hc, err := newHybridConsensus(1)
|
||||
hc, err := newCertifier(1)
|
||||
if err != nil {
|
||||
t.Fatalf("newHybridConsensus failed: %v", err)
|
||||
t.Fatalf("newCertifier failed: %v", err)
|
||||
}
|
||||
|
||||
block := &Block{
|
||||
@@ -595,22 +595,22 @@ func TestHybridConsensus_GenerateCert(t *testing.T) {
|
||||
// Hybrid Tests (hybrid.go)
|
||||
// =============================================================================
|
||||
|
||||
func TestHybrid_NewHybrid_InvalidThreshold(t *testing.T) {
|
||||
_, err := NewHybrid(0)
|
||||
func TestSigner_NewSigner_InvalidThreshold(t *testing.T) {
|
||||
_, err := NewSigner(0)
|
||||
if err == nil {
|
||||
t.Error("expected error for threshold 0")
|
||||
}
|
||||
|
||||
_, err = NewHybrid(-1)
|
||||
_, err = NewSigner(-1)
|
||||
if err == nil {
|
||||
t.Error("expected error for negative threshold")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_AddValidator(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_AddValidator(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
err = h.AddValidator("v1", 100)
|
||||
@@ -627,10 +627,10 @@ func TestHybrid_AddValidator(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_SignMessage_ValidatorNotFound(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_SignMessage_ValidatorNotFound(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = h.SignMessage("nonexistent", []byte("test"))
|
||||
@@ -639,67 +639,67 @@ func TestHybrid_SignMessage_ValidatorNotFound(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_ReleaseHybridSignature(t *testing.T) {
|
||||
func TestSigner_ReleaseQuasarSig(t *testing.T) {
|
||||
// Test with nil - should not panic
|
||||
ReleaseHybridSignature(nil)
|
||||
ReleaseQuasarSig(nil)
|
||||
|
||||
// Test with valid signature
|
||||
h, _ := NewHybrid(1)
|
||||
h, _ := NewSigner(1)
|
||||
_ = h.AddValidator("v1", 100)
|
||||
sig, _ := h.SignMessage("v1", []byte("test"))
|
||||
|
||||
ReleaseHybridSignature(sig)
|
||||
ReleaseQuasarSig(sig)
|
||||
// No assertion needed - just checking it doesn't panic
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyHybridSignature_ValidatorNotFound(t *testing.T) {
|
||||
h, _ := NewHybrid(1)
|
||||
func TestSigner_VerifyQuasarSig_ValidatorNotFound(t *testing.T) {
|
||||
h, _ := NewSigner(1)
|
||||
_ = h.AddValidator("v1", 100)
|
||||
|
||||
sig := &HybridSignature{
|
||||
sig := &QuasarSig{
|
||||
ValidatorID: "nonexistent",
|
||||
BLS: []byte{1, 2, 3},
|
||||
Corona: []byte{4, 5, 6},
|
||||
}
|
||||
|
||||
result := h.VerifyHybridSignature([]byte("test"), sig)
|
||||
result := h.VerifyQuasarSig([]byte("test"), sig)
|
||||
if result {
|
||||
t.Error("expected false for nonexistent validator")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyHybridSignature_InvalidBLS(t *testing.T) {
|
||||
h, _ := NewHybrid(1)
|
||||
func TestSigner_VerifyQuasarSig_InvalidBLS(t *testing.T) {
|
||||
h, _ := NewSigner(1)
|
||||
_ = h.AddValidator("v1", 100)
|
||||
|
||||
sig := &HybridSignature{
|
||||
sig := &QuasarSig{
|
||||
ValidatorID: "v1",
|
||||
BLS: []byte{1, 2, 3}, // Invalid BLS bytes
|
||||
Corona: []byte{4, 5, 6},
|
||||
}
|
||||
|
||||
result := h.VerifyHybridSignature([]byte("test"), sig)
|
||||
result := h.VerifyQuasarSig([]byte("test"), sig)
|
||||
if result {
|
||||
t.Error("expected false for invalid BLS signature")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_AggregateSignatures_InsufficientSignatures(t *testing.T) {
|
||||
h, _ := NewHybrid(3) // Require 3 validators
|
||||
func TestSigner_AggregateSignatures_InsufficientSignatures(t *testing.T) {
|
||||
h, _ := NewSigner(3) // Require 3 validators
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
|
||||
sig, _ := h.SignMessage("v1", []byte("test"))
|
||||
|
||||
// Only 1 signature, but threshold is 3
|
||||
_, err := h.AggregateSignatures([]byte("test"), []*HybridSignature{sig})
|
||||
_, err := h.AggregateSignatures([]byte("test"), []*QuasarSig{sig})
|
||||
if err == nil {
|
||||
t.Error("expected error for insufficient signatures")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_AggregateSignatures_Success(t *testing.T) {
|
||||
h, _ := NewHybrid(2)
|
||||
func TestSigner_AggregateSignatures_Success(t *testing.T) {
|
||||
h, _ := NewSigner(2)
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
_ = h.AddValidator("v2", 100)
|
||||
@@ -708,7 +708,7 @@ func TestHybrid_AggregateSignatures_Success(t *testing.T) {
|
||||
sig1, _ := h.SignMessage("v1", msg)
|
||||
sig2, _ := h.SignMessage("v2", msg)
|
||||
|
||||
aggSig, err := h.AggregateSignatures(msg, []*HybridSignature{sig1, sig2})
|
||||
aggSig, err := h.AggregateSignatures(msg, []*QuasarSig{sig1, sig2})
|
||||
if err != nil {
|
||||
t.Fatalf("AggregateSignatures failed: %v", err)
|
||||
}
|
||||
@@ -726,8 +726,8 @@ func TestHybrid_AggregateSignatures_Success(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignature(t *testing.T) {
|
||||
h, _ := NewHybrid(2)
|
||||
func TestSigner_VerifyAggregatedSignature(t *testing.T) {
|
||||
h, _ := NewSigner(2)
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
_ = h.AddValidator("v2", 100)
|
||||
@@ -736,7 +736,7 @@ func TestHybrid_VerifyAggregatedSignature(t *testing.T) {
|
||||
sig1, _ := h.SignMessage("v1", msg)
|
||||
sig2, _ := h.SignMessage("v2", msg)
|
||||
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*HybridSignature{sig1, sig2})
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*QuasarSig{sig1, sig2})
|
||||
|
||||
result := h.VerifyAggregatedSignature(msg, aggSig)
|
||||
if !result {
|
||||
@@ -744,8 +744,8 @@ func TestHybrid_VerifyAggregatedSignature(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignature_InsufficientSigners(t *testing.T) {
|
||||
h, _ := NewHybrid(3) // Require 3
|
||||
func TestSigner_VerifyAggregatedSignature_InsufficientSigners(t *testing.T) {
|
||||
h, _ := NewSigner(3) // Require 3
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
_ = h.AddValidator("v2", 100)
|
||||
@@ -763,8 +763,8 @@ func TestHybrid_VerifyAggregatedSignature_InsufficientSigners(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignature_InvalidBLS(t *testing.T) {
|
||||
h, _ := NewHybrid(1)
|
||||
func TestSigner_VerifyAggregatedSignature_InvalidBLS(t *testing.T) {
|
||||
h, _ := NewSigner(1)
|
||||
_ = h.AddValidator("v1", 100)
|
||||
|
||||
aggSig := &AggregatedSignature{
|
||||
@@ -779,8 +779,8 @@ func TestHybrid_VerifyAggregatedSignature_InvalidBLS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignature_InactiveValidator(t *testing.T) {
|
||||
h, _ := NewHybrid(1)
|
||||
func TestSigner_VerifyAggregatedSignature_InactiveValidator(t *testing.T) {
|
||||
h, _ := NewSigner(1)
|
||||
_ = h.AddValidator("v1", 100)
|
||||
|
||||
// Make validator inactive
|
||||
@@ -801,8 +801,8 @@ func TestHybrid_VerifyAggregatedSignature_InactiveValidator(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_GetActiveValidatorCount(t *testing.T) {
|
||||
h, _ := NewHybrid(1)
|
||||
func TestSigner_GetActiveValidatorCount(t *testing.T) {
|
||||
h, _ := NewSigner(1)
|
||||
|
||||
if h.GetActiveValidatorCount() != 0 {
|
||||
t.Error("expected 0 validators initially")
|
||||
@@ -826,137 +826,13 @@ func TestHybrid_GetActiveValidatorCount(t *testing.T) {
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Corona Tests (corona.go)
|
||||
// Corona Tests
|
||||
// =============================================================================
|
||||
|
||||
func TestCorona_Initialize(t *testing.T) {
|
||||
r := NewCorona()
|
||||
|
||||
err := r.Initialize(SecurityLow)
|
||||
if err != nil {
|
||||
t.Fatalf("Initialize SecurityLow failed: %v", err)
|
||||
}
|
||||
|
||||
err = r.Initialize(SecurityMedium)
|
||||
if err != nil {
|
||||
t.Fatalf("Initialize SecurityMedium failed: %v", err)
|
||||
}
|
||||
|
||||
err = r.Initialize(SecurityHigh)
|
||||
if err != nil {
|
||||
t.Fatalf("Initialize SecurityHigh failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorona_KeyGen(t *testing.T) {
|
||||
seed := []byte("test-seed-32-bytes-long-enough!!")
|
||||
|
||||
sk, pk, err := KeyGen(seed)
|
||||
if err != nil {
|
||||
t.Fatalf("KeyGen failed: %v", err)
|
||||
}
|
||||
|
||||
if len(sk) == 0 || len(pk) == 0 {
|
||||
t.Error("expected non-empty keys")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorona_Precompute(t *testing.T) {
|
||||
sk := make([]byte, 32)
|
||||
|
||||
precomp, err := Precompute(sk)
|
||||
if err != nil {
|
||||
t.Fatalf("Precompute failed: %v", err)
|
||||
}
|
||||
|
||||
if len(precomp) == 0 {
|
||||
t.Error("expected non-empty precomp")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorona_QuickSign(t *testing.T) {
|
||||
precomp := make([]byte, 32)
|
||||
for i := range precomp {
|
||||
precomp[i] = byte(i)
|
||||
}
|
||||
|
||||
msg := []byte("test message")
|
||||
|
||||
share, err := QuickSign(precomp, msg)
|
||||
if err != nil {
|
||||
t.Fatalf("QuickSign failed: %v", err)
|
||||
}
|
||||
|
||||
if len(share) == 0 {
|
||||
t.Error("expected non-empty share")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorona_VerifyShare(t *testing.T) {
|
||||
pk := []byte("public-key")
|
||||
msg := []byte("test message")
|
||||
share := []byte("signature-share")
|
||||
|
||||
valid := VerifyShare(pk, msg, share)
|
||||
if !valid {
|
||||
t.Error("VerifyShare should return true (stub implementation)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorona_Aggregate(t *testing.T) {
|
||||
shares := []Share{
|
||||
[]byte("share1"),
|
||||
[]byte("share2"),
|
||||
[]byte("share3"),
|
||||
}
|
||||
|
||||
cert, err := Aggregate(shares)
|
||||
if err != nil {
|
||||
t.Fatalf("Aggregate failed: %v", err)
|
||||
}
|
||||
|
||||
if len(cert) == 0 {
|
||||
t.Error("expected non-empty cert")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorona_Aggregate_Empty(t *testing.T) {
|
||||
_, err := Aggregate([]Share{})
|
||||
if err == nil {
|
||||
t.Error("expected error for empty shares")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorona_Verify(t *testing.T) {
|
||||
pk := []byte("public-key")
|
||||
msg := []byte("test message")
|
||||
cert := []byte("certificate")
|
||||
|
||||
valid := Verify(pk, msg, cert)
|
||||
if !valid {
|
||||
t.Error("Verify should return true (stub implementation)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorona_SecurityLevels(t *testing.T) {
|
||||
tests := []struct {
|
||||
level SecurityLevel
|
||||
name string
|
||||
}{
|
||||
{SecurityLow, "Low"},
|
||||
{SecurityMedium, "Medium"},
|
||||
{SecurityHigh, "High"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := NewCorona()
|
||||
if err := r.Initialize(tt.level); err != nil {
|
||||
t.Errorf("Initialize %s failed: %v", tt.name, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
//
|
||||
// NOTE: Corona post-quantum crypto is tested in the real corona package
|
||||
// at github.com/luxfi/corona/threshold. The quasar package uses the real
|
||||
// implementation via the Signer type in quasar.go. Tests for threshold signing
|
||||
// are in quasar_test.go and epoch_test.go.
|
||||
|
||||
// =============================================================================
|
||||
// Types Tests (types.go)
|
||||
@@ -1277,11 +1153,11 @@ func TestVerkleWitness_CheckPQFinality(t *testing.T) {
|
||||
w := NewVerkleWitness(3)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
bits []byte
|
||||
want bool
|
||||
name string
|
||||
bits []byte
|
||||
want bool
|
||||
}{
|
||||
{"sufficient bits", []byte{0x07}, true}, // 3 bits set
|
||||
{"sufficient bits", []byte{0x07}, true}, // 3 bits set
|
||||
{"insufficient bits", []byte{0x03}, false}, // 2 bits set
|
||||
{"empty", []byte{}, false},
|
||||
}
|
||||
@@ -1593,7 +1469,7 @@ func TestQuasar_ProcessBlockWithContext_Cancelled(t *testing.T) {
|
||||
t.Fatalf("NewQuasar failed: %v", err)
|
||||
}
|
||||
|
||||
_ = q.hybridConsensus.AddValidator("v1", 100)
|
||||
_, _ = q.AddValidator("v1", 100)
|
||||
|
||||
block := &Block{
|
||||
ChainID: [32]byte{1},
|
||||
@@ -1622,7 +1498,7 @@ func TestQuasar_SubmitBlock_AutoRegister(t *testing.T) {
|
||||
t.Fatalf("NewQuasar failed: %v", err)
|
||||
}
|
||||
|
||||
_ = q.hybridConsensus.AddValidator("v1", 100)
|
||||
_, _ = q.AddValidator("v1", 100)
|
||||
|
||||
ctx := context.Background()
|
||||
_ = q.Start(ctx)
|
||||
@@ -1758,28 +1634,24 @@ func TestHorizon_ComputeBlockHash(t *testing.T) {
|
||||
|
||||
func TestTypeAliases(t *testing.T) {
|
||||
// Test that type aliases work correctly
|
||||
var _ *Core = (*Quasar)(nil)
|
||||
var _ *QuasarCore = (*Quasar)(nil)
|
||||
var _ *PChain = (*BLS)(nil)
|
||||
var _ *QuasarHybridConsensus = (*Hybrid)(nil)
|
||||
var _ *QBlock = (*Block)(nil)
|
||||
var _ *ChainBlock = (*Block)(nil)
|
||||
|
||||
// NewPChain should be the same as NewBLS
|
||||
// NewBLS creates a BLS instance
|
||||
cfg := config.DefaultParams()
|
||||
store := newMockStore()
|
||||
p := NewPChain(cfg, store)
|
||||
p := NewBLS(cfg, store)
|
||||
if p == nil {
|
||||
t.Error("NewPChain returned nil")
|
||||
t.Error("NewBLS returned nil")
|
||||
}
|
||||
|
||||
// NewQuasarHybridConsensus should be the same as NewHybrid
|
||||
h, err := NewQuasarHybridConsensus(1)
|
||||
// NewSigner creates a signer instance
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewQuasarHybridConsensus failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
if h == nil {
|
||||
t.Error("NewQuasarHybridConsensus returned nil")
|
||||
t.Error("NewSigner returned nil")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1787,17 +1659,17 @@ func TestTypeAliases(t *testing.T) {
|
||||
// Edge Cases and Error Paths
|
||||
// =============================================================================
|
||||
|
||||
func TestHybrid_AggregateSignatures_InvalidBLS(t *testing.T) {
|
||||
h, _ := NewHybrid(1)
|
||||
func TestSigner_AggregateSignatures_InvalidBLS(t *testing.T) {
|
||||
h, _ := NewSigner(1)
|
||||
_ = h.AddValidator("v1", 100)
|
||||
|
||||
sig := &HybridSignature{
|
||||
sig := &QuasarSig{
|
||||
ValidatorID: "v1",
|
||||
BLS: []byte{1, 2, 3}, // Invalid BLS bytes
|
||||
Corona: []byte{4, 5, 6},
|
||||
}
|
||||
|
||||
_, err := h.AggregateSignatures([]byte("test"), []*HybridSignature{sig})
|
||||
_, err := h.AggregateSignatures([]byte("test"), []*QuasarSig{sig})
|
||||
if err == nil {
|
||||
t.Error("expected error for invalid BLS signature")
|
||||
}
|
||||
@@ -1939,7 +1811,7 @@ func TestQuasar_ProcessBlockWithContext_ContextCancelledAfterLock(t *testing.T)
|
||||
t.Fatalf("NewQuasar failed: %v", err)
|
||||
}
|
||||
|
||||
_ = q.hybridConsensus.AddValidator("v1", 100)
|
||||
_, _ = q.AddValidator("v1", 100)
|
||||
|
||||
block := &Block{
|
||||
ChainID: [32]byte{1},
|
||||
@@ -1967,7 +1839,7 @@ func TestQuasar_VerifyQuantumFinalityWithContext_AllPaths(t *testing.T) {
|
||||
t.Fatalf("NewQuasar failed: %v", err)
|
||||
}
|
||||
|
||||
_ = q.hybridConsensus.AddValidator("v1", 100)
|
||||
_, _ = q.AddValidator("v1", 100)
|
||||
|
||||
// Process a block first
|
||||
block := &Block{
|
||||
@@ -2145,10 +2017,10 @@ func TestEngine_FinalizedChannel_BufferFull(t *testing.T) {
|
||||
// Just ensure no panic occurred
|
||||
}
|
||||
|
||||
func TestHybrid_SignMessageWithContext_ValidatorNotFound(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_SignMessageWithContext_ValidatorNotFound(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
// Add validator but then remove it manually
|
||||
@@ -2166,10 +2038,10 @@ func TestHybrid_SignMessageWithContext_ValidatorNotFound(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyHybridSignatureWithContext_ContextCancelledMidVerify(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_VerifyQuasarSigWithContext_ContextCancelledMidVerify(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
@@ -2184,16 +2056,16 @@ func TestHybrid_VerifyHybridSignatureWithContext_ContextCancelledMidVerify(t *te
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
result := h.VerifyHybridSignatureWithContext(ctx, msg, sig)
|
||||
result := h.VerifyQuasarSigWithContext(ctx, msg, sig)
|
||||
if result {
|
||||
t.Error("expected false for cancelled context")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_AggregateSignaturesWithContext_ContextCancelledMid(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_AggregateSignaturesWithContext_ContextCancelledMid(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
@@ -2207,23 +2079,23 @@ func TestHybrid_AggregateSignaturesWithContext_ContextCancelledMid(t *testing.T)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
_, err = h.AggregateSignaturesWithContext(ctx, msg, []*HybridSignature{sig1, sig2})
|
||||
_, err = h.AggregateSignaturesWithContext(ctx, msg, []*QuasarSig{sig1, sig2})
|
||||
if err == nil {
|
||||
t.Error("expected error for cancelled context")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignatureWithContext_AllErrorPaths(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_VerifyAggregatedSignatureWithContext_AllErrorPaths(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
|
||||
msg := []byte("test message")
|
||||
sig, _ := h.SignMessage("v1", msg)
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*HybridSignature{sig})
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*QuasarSig{sig})
|
||||
|
||||
// Test with context cancelled before RLock
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -2353,7 +2225,7 @@ func TestQuasar_VerifyQuantumFinalityWithContext_InvalidSignature(t *testing.T)
|
||||
t.Fatalf("NewQuasar failed: %v", err)
|
||||
}
|
||||
|
||||
_ = q.hybridConsensus.AddValidator("validator1", 100)
|
||||
_, _ = q.AddValidator("validator1", 100)
|
||||
|
||||
// Process a block first
|
||||
block := &Block{
|
||||
@@ -2410,10 +2282,10 @@ func TestQuasar_QuantumFinalizer_TickerCase(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_SignMessageWithContext_ContextCancelledAfterLock(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_SignMessageWithContext_ContextCancelledAfterLock(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
@@ -2431,10 +2303,10 @@ func TestHybrid_SignMessageWithContext_ContextCancelledAfterLock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyHybridSignatureWithContext_ContextCancelledAfterLock(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_VerifyQuasarSigWithContext_ContextCancelledAfterLock(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
@@ -2446,23 +2318,23 @@ func TestHybrid_VerifyHybridSignatureWithContext_ContextCancelledAfterLock(t *te
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
result := h.VerifyHybridSignatureWithContext(ctx, msg, sig)
|
||||
result := h.VerifyQuasarSigWithContext(ctx, msg, sig)
|
||||
if result {
|
||||
t.Error("expected false for cancelled context")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignatureWithContext_ContextCancelledAfterLock(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_VerifyAggregatedSignatureWithContext_ContextCancelledAfterLock(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
|
||||
msg := []byte("test message")
|
||||
sig, _ := h.SignMessage("v1", msg)
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*HybridSignature{sig})
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*QuasarSig{sig})
|
||||
|
||||
// Pre-cancel context
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -2474,10 +2346,10 @@ func TestHybrid_VerifyAggregatedSignatureWithContext_ContextCancelledAfterLock(t
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_AggregateSignaturesWithContext_ContextCancelledAfterLock(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_AggregateSignaturesWithContext_ContextCancelledAfterLock(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
@@ -2489,16 +2361,16 @@ func TestHybrid_AggregateSignaturesWithContext_ContextCancelledAfterLock(t *test
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
_, err = h.AggregateSignaturesWithContext(ctx, msg, []*HybridSignature{sig})
|
||||
_, err = h.AggregateSignaturesWithContext(ctx, msg, []*QuasarSig{sig})
|
||||
if err == nil {
|
||||
t.Error("expected error for cancelled context")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignature_PublicKeyAggregationError(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_VerifyAggregatedSignature_PublicKeyAggregationError(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
@@ -2520,17 +2392,17 @@ func TestHybrid_VerifyAggregatedSignature_PublicKeyAggregationError(t *testing.T
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignature_BLSVerifyFail(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_VerifyAggregatedSignature_BLSVerifyFail(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
|
||||
msg := []byte("test message")
|
||||
sig, _ := h.SignMessage("v1", msg)
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*HybridSignature{sig})
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*QuasarSig{sig})
|
||||
|
||||
// Verify with different message - BLS verification should fail
|
||||
wrongMsg := []byte("wrong message")
|
||||
@@ -2540,10 +2412,10 @@ func TestHybrid_VerifyAggregatedSignature_BLSVerifyFail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignature_BLSSignatureTamperedFail(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_VerifyAggregatedSignature_BLSSignatureTamperedFail(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
@@ -2552,7 +2424,7 @@ func TestHybrid_VerifyAggregatedSignature_BLSSignatureTamperedFail(t *testing.T)
|
||||
msg := []byte("test message")
|
||||
sig1, _ := h.SignMessage("v1", msg)
|
||||
sig2, _ := h.SignMessage("v2", msg)
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*HybridSignature{sig1, sig2})
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*QuasarSig{sig1, sig2})
|
||||
|
||||
// Corrupt the BLS signature
|
||||
if len(aggSig.BLSAggregated) > 0 {
|
||||
@@ -2670,9 +2542,9 @@ func TestQuasar_VerifyQuantumFinalityWithContext_LoopContextCheck(t *testing.T)
|
||||
t.Fatalf("NewQuasar failed: %v", err)
|
||||
}
|
||||
|
||||
_ = q.hybridConsensus.AddValidator("validator1", 100)
|
||||
_ = q.hybridConsensus.AddValidator("validator2", 100)
|
||||
_ = q.hybridConsensus.AddValidator("validator3", 100)
|
||||
_, _ = q.AddValidator("validator1", 100)
|
||||
_, _ = q.AddValidator("validator2", 100)
|
||||
_, _ = q.AddValidator("validator3", 100)
|
||||
|
||||
// Process a block first
|
||||
block := &Block{
|
||||
@@ -2692,7 +2564,7 @@ func TestQuasar_VerifyQuantumFinalityWithContext_LoopContextCheck(t *testing.T)
|
||||
if qBlock != nil {
|
||||
// Add signatures for all validators
|
||||
for _, vid := range []string{"validator1", "validator2", "validator3"} {
|
||||
sig, _ := q.hybridConsensus.SignMessage(vid, []byte(blockHash))
|
||||
sig, _ := q.SignMessage(vid, []byte(blockHash))
|
||||
if sig != nil {
|
||||
qBlock.ValidatorSigs[vid] = sig
|
||||
}
|
||||
@@ -2707,10 +2579,10 @@ func TestQuasar_VerifyQuantumFinalityWithContext_LoopContextCheck(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_VerifyAggregatedSignature_ContextCancelledInLoop(t *testing.T) {
|
||||
h, err := NewHybrid(1)
|
||||
func TestSigner_VerifyAggregatedSignature_ContextCancelledInLoop(t *testing.T) {
|
||||
h, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
// Add multiple validators
|
||||
@@ -2722,7 +2594,7 @@ func TestHybrid_VerifyAggregatedSignature_ContextCancelledInLoop(t *testing.T) {
|
||||
sig1, _ := h.SignMessage("v1", msg)
|
||||
sig2, _ := h.SignMessage("v2", msg)
|
||||
sig3, _ := h.SignMessage("v3", msg)
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*HybridSignature{sig1, sig2, sig3})
|
||||
aggSig, _ := h.AggregateSignatures(msg, []*QuasarSig{sig1, sig2, sig3})
|
||||
|
||||
// Verify with valid context should pass
|
||||
result := h.VerifyAggregatedSignature(msg, aggSig)
|
||||
@@ -2829,10 +2701,10 @@ func TestQuasar_SubmitBlock_BufferFullDropOldest(t *testing.T) {
|
||||
// Should not error - drops oldest when full
|
||||
}
|
||||
|
||||
func TestHybrid_AggregateSignatures_ContextCancelledDuringLoop(t *testing.T) {
|
||||
h, err := NewHybrid(2)
|
||||
func TestSigner_AggregateSignatures_ContextCancelledDuringLoop(t *testing.T) {
|
||||
h, err := NewSigner(2)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
_ = h.AddValidator("v1", 100)
|
||||
@@ -2844,7 +2716,7 @@ func TestHybrid_AggregateSignatures_ContextCancelledDuringLoop(t *testing.T) {
|
||||
|
||||
// Valid context should work
|
||||
ctx := context.Background()
|
||||
aggSig, err := h.AggregateSignaturesWithContext(ctx, msg, []*HybridSignature{sig1, sig2})
|
||||
aggSig, err := h.AggregateSignaturesWithContext(ctx, msg, []*QuasarSig{sig1, sig2})
|
||||
if err != nil {
|
||||
t.Errorf("AggregateSignatures failed: %v", err)
|
||||
}
|
||||
@@ -2857,7 +2729,7 @@ func TestHybrid_AggregateSignatures_ContextCancelledDuringLoop(t *testing.T) {
|
||||
// Threshold Mode Tests (hybrid.go threshold integration)
|
||||
// =============================================================================
|
||||
|
||||
func TestHybrid_ThresholdMode_GenerateKeys(t *testing.T) {
|
||||
func TestSigner_ThresholdMode_GenerateKeys(t *testing.T) {
|
||||
// Generate threshold key shares using the helper function
|
||||
// t=1 means need at least 2 shares to sign
|
||||
shares, groupKey, err := GenerateThresholdKeys(threshold.SchemeBLS, 1, 3)
|
||||
@@ -2881,7 +2753,7 @@ func TestHybrid_ThresholdMode_GenerateKeys(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_ThresholdMode_NewHybridWithThreshold(t *testing.T) {
|
||||
func TestSigner_ThresholdMode_NewSignerWithThreshold(t *testing.T) {
|
||||
// Generate threshold key shares
|
||||
shares, groupKey, err := GenerateThresholdKeys(threshold.SchemeBLS, 1, 3)
|
||||
if err != nil {
|
||||
@@ -2903,9 +2775,9 @@ func TestHybrid_ThresholdMode_NewHybridWithThreshold(t *testing.T) {
|
||||
GroupKey: groupKey,
|
||||
}
|
||||
|
||||
h, err := NewHybridWithThresholdConfig(config)
|
||||
h, err := NewSignerWithThresholdConfig(config)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybridWithThreshold failed: %v", err)
|
||||
t.Fatalf("NewSignerWithThreshold failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify threshold mode is enabled
|
||||
@@ -2924,7 +2796,7 @@ func TestHybrid_ThresholdMode_NewHybridWithThreshold(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_ThresholdMode_SignAndVerify(t *testing.T) {
|
||||
func TestSigner_ThresholdMode_SignAndVerify(t *testing.T) {
|
||||
// Generate threshold key shares (t=1 means need 2+ shares)
|
||||
shares, groupKey, err := GenerateThresholdKeys(threshold.SchemeBLS, 1, 3)
|
||||
if err != nil {
|
||||
@@ -2946,9 +2818,9 @@ func TestHybrid_ThresholdMode_SignAndVerify(t *testing.T) {
|
||||
GroupKey: groupKey,
|
||||
}
|
||||
|
||||
h, err := NewHybridWithThresholdConfig(config)
|
||||
h, err := NewSignerWithThresholdConfig(config)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybridWithThreshold failed: %v", err)
|
||||
t.Fatalf("NewSignerWithThreshold failed: %v", err)
|
||||
}
|
||||
|
||||
// Sign message with threshold signing
|
||||
@@ -2990,13 +2862,13 @@ func TestHybrid_ThresholdMode_SignAndVerify(t *testing.T) {
|
||||
//
|
||||
// For now, we verify the infrastructure is correctly wired up:
|
||||
// - Key generation works
|
||||
// - Signing produces valid shares
|
||||
// - Signing produces valid shares
|
||||
// - Aggregation produces a signature
|
||||
// - The threshold scheme is correctly registered and usable
|
||||
t.Log("Note: Full threshold signature verification pending BLS scalar field implementation")
|
||||
}
|
||||
|
||||
func TestHybrid_ThresholdMode_InsufficientShares(t *testing.T) {
|
||||
func TestSigner_ThresholdMode_InsufficientShares(t *testing.T) {
|
||||
// Generate threshold key shares (t=1 means need 2+ shares)
|
||||
shares, groupKey, err := GenerateThresholdKeys(threshold.SchemeBLS, 1, 3)
|
||||
if err != nil {
|
||||
@@ -3018,9 +2890,9 @@ func TestHybrid_ThresholdMode_InsufficientShares(t *testing.T) {
|
||||
GroupKey: groupKey,
|
||||
}
|
||||
|
||||
h, err := NewHybridWithThresholdConfig(config)
|
||||
h, err := NewSignerWithThresholdConfig(config)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybridWithThreshold failed: %v", err)
|
||||
t.Fatalf("NewSignerWithThreshold failed: %v", err)
|
||||
}
|
||||
|
||||
// Sign message with threshold signing
|
||||
@@ -3040,11 +2912,11 @@ func TestHybrid_ThresholdMode_InsufficientShares(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_ThresholdMode_NotEnabled(t *testing.T) {
|
||||
func TestSigner_ThresholdMode_NotEnabled(t *testing.T) {
|
||||
// Create regular hybrid engine (non-threshold mode)
|
||||
h, err := NewHybrid(2)
|
||||
h, err := NewSigner(2)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybrid failed: %v", err)
|
||||
t.Fatalf("NewSigner failed: %v", err)
|
||||
}
|
||||
|
||||
// Threshold mode should be disabled
|
||||
@@ -3069,7 +2941,7 @@ func TestHybrid_ThresholdMode_NotEnabled(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHybrid_ThresholdMode_AddValidatorThreshold(t *testing.T) {
|
||||
func TestSigner_ThresholdMode_AddValidatorThreshold(t *testing.T) {
|
||||
// Generate threshold key shares
|
||||
shares, groupKey, err := GenerateThresholdKeys(threshold.SchemeBLS, 1, 3)
|
||||
if err != nil {
|
||||
@@ -3089,9 +2961,9 @@ func TestHybrid_ThresholdMode_AddValidatorThreshold(t *testing.T) {
|
||||
GroupKey: groupKey,
|
||||
}
|
||||
|
||||
h, err := NewHybridWithThresholdConfig(config)
|
||||
h, err := NewSignerWithThresholdConfig(config)
|
||||
if err != nil {
|
||||
t.Fatalf("NewHybridWithThresholdConfig failed: %v", err)
|
||||
t.Fatalf("NewSignerWithThresholdConfig failed: %v", err)
|
||||
}
|
||||
|
||||
// Add third validator dynamically
|
||||
|
||||
+87
-22
@@ -29,7 +29,7 @@ type Quasar struct {
|
||||
cChainBlocks chan *ChainBlock
|
||||
|
||||
// Quantum consensus engine - the event horizon
|
||||
hybridConsensus *Hybrid
|
||||
signer *signer
|
||||
|
||||
// Epoch-based Corona key management
|
||||
// Keys rotate when validator set changes (max 1x per hour)
|
||||
@@ -62,14 +62,14 @@ type QuantumBlock struct {
|
||||
BLSSignature []byte
|
||||
CoronaProof []byte // ML-DSA signature
|
||||
Timestamp time.Time
|
||||
ValidatorSigs map[string]*HybridSignature
|
||||
ValidatorSigs map[string]*QuasarSig
|
||||
}
|
||||
|
||||
// NewQuasar creates the supermassive black hole at the center of the blockchain galaxy
|
||||
func NewQuasar(threshold int) (*Quasar, error) {
|
||||
hybrid, err := NewHybrid(threshold)
|
||||
s, err := newSigner(threshold)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create hybrid consensus: %w", err)
|
||||
return nil, fmt.Errorf("failed to create signer: %w", err)
|
||||
}
|
||||
|
||||
core := &Quasar{
|
||||
@@ -77,7 +77,7 @@ func NewQuasar(threshold int) (*Quasar, error) {
|
||||
xChainBlocks: make(chan *ChainBlock, 100),
|
||||
cChainBlocks: make(chan *ChainBlock, 100),
|
||||
chainBuffers: make(map[string]chan *ChainBlock),
|
||||
hybridConsensus: hybrid,
|
||||
signer: s,
|
||||
epochManager: NewEpochManager(threshold, 3), // Keep 3 epochs in history
|
||||
finalizedBlocks: make(map[string]*QuantumBlock),
|
||||
quantumHeight: 0,
|
||||
@@ -209,11 +209,11 @@ func (q *Quasar) processBlockWithContext(ctx context.Context, block *ChainBlock)
|
||||
quantumHash := q.computeQuantumHash(block)
|
||||
|
||||
// Collect validator signatures (BLS + Corona parallel)
|
||||
signatures := make(map[string]*HybridSignature)
|
||||
signatures := make(map[string]*QuasarSig)
|
||||
|
||||
// In production, this would collect from actual validators
|
||||
// For now, simulate with local validator
|
||||
sig, err := q.hybridConsensus.SignMessageWithContext(ctx, "validator1", []byte(quantumHash))
|
||||
sig, err := q.signer.SignMessageWithContext(ctx, "validator1", []byte(quantumHash))
|
||||
if err == nil {
|
||||
signatures["validator1"] = sig
|
||||
}
|
||||
@@ -339,7 +339,7 @@ func (q *Quasar) VerifyQuantumFinalityWithContext(ctx context.Context, blockHash
|
||||
if ctx.Err() != nil {
|
||||
return false
|
||||
}
|
||||
if !q.hybridConsensus.VerifyHybridSignatureWithContext(ctx, []byte(blockHash), sig) {
|
||||
if !q.signer.VerifyQuasarSigWithContext(ctx, []byte(blockHash), sig) {
|
||||
fmt.Printf("[QUANTUM] Invalid signature from validator %s\n", validatorID)
|
||||
return false
|
||||
}
|
||||
@@ -467,9 +467,9 @@ func (q *Quasar) InitializeValidators(validatorIDs []string) error {
|
||||
return fmt.Errorf("need at least 2 validators")
|
||||
}
|
||||
|
||||
// Add validators to hybrid consensus (BLS)
|
||||
// Add validators to signer (BLS)
|
||||
for _, id := range validatorIDs {
|
||||
if err := q.hybridConsensus.AddValidator(id, 1); err != nil {
|
||||
if err := q.signer.AddValidator(id, 1); err != nil {
|
||||
return fmt.Errorf("failed to add validator %s to BLS: %w", id, err)
|
||||
}
|
||||
}
|
||||
@@ -494,7 +494,7 @@ func (q *Quasar) UpdateValidatorSet(validatorIDs []string) (rotated bool, err er
|
||||
// Update BLS validators
|
||||
// First, track current validators
|
||||
currentBLS := make(map[string]bool)
|
||||
for id, v := range q.hybridConsensus.validators {
|
||||
for id, v := range q.signer.validators {
|
||||
if v.Active {
|
||||
currentBLS[id] = true
|
||||
}
|
||||
@@ -505,7 +505,7 @@ func (q *Quasar) UpdateValidatorSet(validatorIDs []string) (rotated bool, err er
|
||||
for _, id := range validatorIDs {
|
||||
newIDs[id] = true
|
||||
if !currentBLS[id] {
|
||||
if err := q.hybridConsensus.AddValidator(id, 1); err != nil {
|
||||
if err := q.signer.AddValidator(id, 1); err != nil {
|
||||
return false, fmt.Errorf("failed to add validator %s: %w", id, err)
|
||||
}
|
||||
}
|
||||
@@ -514,7 +514,7 @@ func (q *Quasar) UpdateValidatorSet(validatorIDs []string) (rotated bool, err er
|
||||
// Deactivate removed validators
|
||||
for id := range currentBLS {
|
||||
if !newIDs[id] {
|
||||
if v, exists := q.hybridConsensus.validators[id]; exists {
|
||||
if v, exists := q.signer.validators[id]; exists {
|
||||
v.Active = false
|
||||
}
|
||||
}
|
||||
@@ -541,7 +541,7 @@ func (q *Quasar) AddValidator(validatorID string, weight uint64) (rotated bool,
|
||||
defer q.mu.Unlock()
|
||||
|
||||
// Add to BLS
|
||||
if err := q.hybridConsensus.AddValidator(validatorID, weight); err != nil {
|
||||
if err := q.signer.AddValidator(validatorID, weight); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -557,11 +557,12 @@ func (q *Quasar) AddValidator(validatorID string, weight uint64) (rotated bool,
|
||||
rotated = true
|
||||
fmt.Printf("[QUASAR] Added validator %s, rotated to epoch %d\n",
|
||||
validatorID, q.epochManager.GetCurrentEpoch())
|
||||
} else if errors.Is(err, ErrEpochRateLimited) || errors.Is(err, ErrNoValidatorChange) {
|
||||
// Rate limited or no change - validator added to BLS but RT keys not rotated yet
|
||||
} else if errors.Is(err, ErrEpochRateLimited) || errors.Is(err, ErrNoValidatorChange) || errors.Is(err, ErrInvalidValidatorSet) {
|
||||
// Rate limited, no change, or insufficient validators (e.g., first validator added)
|
||||
// Validator added to BLS but RT keys not rotated yet
|
||||
rotated = false
|
||||
err = nil
|
||||
fmt.Printf("[QUASAR] Added validator %s to BLS (RT rotation rate-limited)\n", validatorID)
|
||||
fmt.Printf("[QUASAR] Added validator %s to BLS (RT rotation pending)\n", validatorID)
|
||||
}
|
||||
|
||||
return rotated, err
|
||||
@@ -573,7 +574,7 @@ func (q *Quasar) RemoveValidator(validatorID string) (rotated bool, err error) {
|
||||
defer q.mu.Unlock()
|
||||
|
||||
// Deactivate in BLS
|
||||
if v, exists := q.hybridConsensus.validators[validatorID]; exists {
|
||||
if v, exists := q.signer.validators[validatorID]; exists {
|
||||
v.Active = false
|
||||
}
|
||||
|
||||
@@ -586,10 +587,10 @@ func (q *Quasar) RemoveValidator(validatorID string) (rotated bool, err error) {
|
||||
rotated = true
|
||||
fmt.Printf("[QUASAR] Removed validator %s, rotated to epoch %d\n",
|
||||
validatorID, q.epochManager.GetCurrentEpoch())
|
||||
} else if errors.Is(err, ErrEpochRateLimited) || errors.Is(err, ErrNoValidatorChange) {
|
||||
} else if errors.Is(err, ErrEpochRateLimited) || errors.Is(err, ErrNoValidatorChange) || errors.Is(err, ErrInvalidValidatorSet) {
|
||||
rotated = false
|
||||
err = nil
|
||||
fmt.Printf("[QUASAR] Removed validator %s from BLS (RT rotation rate-limited)\n", validatorID)
|
||||
fmt.Printf("[QUASAR] Removed validator %s from BLS (RT rotation pending)\n", validatorID)
|
||||
}
|
||||
|
||||
return rotated, err
|
||||
@@ -638,11 +639,75 @@ func (q *Quasar) GetEpochManager() *EpochManager {
|
||||
return q.epochManager
|
||||
}
|
||||
|
||||
// SignMessage signs a message with the specified validator's key.
|
||||
func (q *Quasar) SignMessage(validatorID string, message []byte) (*QuasarSig, error) {
|
||||
return q.signer.SignMessage(validatorID, message)
|
||||
}
|
||||
|
||||
// AggregateSignatures aggregates multiple signatures into one.
|
||||
func (q *Quasar) AggregateSignatures(message []byte, signatures []*QuasarSig) (*AggregatedSignature, error) {
|
||||
return q.signer.AggregateSignatures(message, signatures)
|
||||
}
|
||||
|
||||
// VerifyAggregatedSignature verifies an aggregated signature.
|
||||
func (q *Quasar) VerifyAggregatedSignature(message []byte, sig *AggregatedSignature) bool {
|
||||
return q.signer.VerifyAggregatedSignature(message, sig)
|
||||
}
|
||||
|
||||
// SignMessageWithContext signs a message with context cancellation support.
|
||||
func (q *Quasar) SignMessageWithContext(ctx context.Context, validatorID string, message []byte) (*QuasarSig, error) {
|
||||
return q.signer.SignMessageWithContext(ctx, validatorID, message)
|
||||
}
|
||||
|
||||
// AggregateSignaturesWithContext aggregates multiple signatures with context support.
|
||||
func (q *Quasar) AggregateSignaturesWithContext(ctx context.Context, message []byte, signatures []*QuasarSig) (*AggregatedSignature, error) {
|
||||
return q.signer.AggregateSignaturesWithContext(ctx, message, signatures)
|
||||
}
|
||||
|
||||
// VerifyAggregatedSignatureWithContext verifies an aggregated signature with context support.
|
||||
func (q *Quasar) VerifyAggregatedSignatureWithContext(ctx context.Context, message []byte, sig *AggregatedSignature) bool {
|
||||
return q.signer.VerifyAggregatedSignatureWithContext(ctx, message, sig)
|
||||
}
|
||||
|
||||
// IsThresholdMode returns true if the signer is in threshold mode.
|
||||
func (q *Quasar) IsThresholdMode() bool {
|
||||
return q.signer.IsThresholdMode()
|
||||
}
|
||||
|
||||
// IsDualThresholdMode returns true if the signer is in dual threshold mode (BLS + Corona).
|
||||
func (q *Quasar) IsDualThresholdMode() bool {
|
||||
return q.signer.IsDualThresholdMode()
|
||||
}
|
||||
|
||||
// GetActiveValidatorCount returns the number of active validators.
|
||||
func (q *Quasar) GetActiveValidatorCount() int {
|
||||
return q.signer.GetActiveValidatorCount()
|
||||
}
|
||||
|
||||
// GetThreshold returns the consensus threshold.
|
||||
func (q *Quasar) GetThreshold() int {
|
||||
return q.signer.GetThreshold()
|
||||
}
|
||||
|
||||
// VerifyQuasarSig verifies a QuasarSig signature.
|
||||
func (q *Quasar) VerifyQuasarSig(message []byte, sig *QuasarSig) bool {
|
||||
return q.signer.VerifyQuasarSig(message, sig)
|
||||
}
|
||||
|
||||
// CoronaRound1 executes Round 1 of the Corona threshold signing protocol.
|
||||
func (q *Quasar) CoronaRound1(validatorID string, sessionID int, prfKey []byte) (*CoronaRound1Data, error) {
|
||||
data, err := q.signer.CoronaRound1(validatorID, sessionID, prfKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &CoronaRound1Data{PartyID: data.PartyID}, nil
|
||||
}
|
||||
|
||||
// Internal helpers
|
||||
|
||||
func (q *Quasar) getActiveValidatorIDsLocked() []string {
|
||||
ids := make([]string, 0, len(q.hybridConsensus.validators))
|
||||
for id, v := range q.hybridConsensus.validators {
|
||||
ids := make([]string, 0, len(q.signer.validators))
|
||||
for id, v := range q.signer.validators {
|
||||
if v.Active {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
@@ -7,16 +7,17 @@ import (
|
||||
)
|
||||
|
||||
func TestQuasar(t *testing.T) {
|
||||
// Create quantum aggregator with threshold of 1 validator
|
||||
qa, err := NewQuasar(1)
|
||||
// Create quantum aggregator with threshold of 2 validators
|
||||
// Need 3 validators for threshold 2 (t < n)
|
||||
qa, err := NewQuasar(2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create quantum aggregator: %v", err)
|
||||
}
|
||||
|
||||
// Add a test validator
|
||||
err = qa.hybridConsensus.AddValidator("validator1", 100)
|
||||
// Initialize validators (need more than threshold)
|
||||
err = qa.InitializeValidators([]string{"validator1", "validator2", "validator3"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
// Start the aggregator
|
||||
@@ -30,7 +31,7 @@ func TestQuasar(t *testing.T) {
|
||||
pBlock := &ChainBlock{
|
||||
ChainID: [32]byte{1},
|
||||
ChainName: "P-Chain",
|
||||
ID: [32]byte{0x01, 0x02, 0x03},
|
||||
ID: [32]byte{0x01, 0x02, 0x03},
|
||||
Height: 100,
|
||||
Timestamp: time.Now(),
|
||||
Data: []byte("P-Chain block data"),
|
||||
@@ -40,7 +41,7 @@ func TestQuasar(t *testing.T) {
|
||||
xBlock := &ChainBlock{
|
||||
ChainID: [32]byte{2},
|
||||
ChainName: "X-Chain",
|
||||
ID: [32]byte{0x04, 0x05, 0x06},
|
||||
ID: [32]byte{0x04, 0x05, 0x06},
|
||||
Height: 200,
|
||||
Timestamp: time.Now(),
|
||||
Data: []byte("X-Chain block data"),
|
||||
@@ -50,7 +51,7 @@ func TestQuasar(t *testing.T) {
|
||||
cBlock := &ChainBlock{
|
||||
ChainID: [32]byte{3},
|
||||
ChainName: "C-Chain",
|
||||
ID: [32]byte{0x07, 0x08, 0x09},
|
||||
ID: [32]byte{0x07, 0x08, 0x09},
|
||||
Height: 300,
|
||||
Timestamp: time.Now(),
|
||||
Data: []byte("C-Chain block data"),
|
||||
@@ -84,22 +85,22 @@ func TestQuasar(t *testing.T) {
|
||||
|
||||
func TestQuantumFinalityWithCorona(t *testing.T) {
|
||||
// Test that Corona and BLS signatures work in parallel
|
||||
qa, err := NewQuasar(1)
|
||||
qa, err := NewQuasar(2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create quantum aggregator: %v", err)
|
||||
}
|
||||
|
||||
// Add validator with both BLS and Corona keys
|
||||
err = qa.hybridConsensus.AddValidator("validator1", 100)
|
||||
err = qa.InitializeValidators([]string{"validator1", "validator2", "validator3"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
// Create a test message
|
||||
message := []byte("Test quantum finality message")
|
||||
|
||||
// Sign with hybrid (BLS + Corona)
|
||||
sig, err := qa.hybridConsensus.SignMessage("validator1", message)
|
||||
sig, err := qa.SignMessage("validator1", message)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to sign message: %v", err)
|
||||
}
|
||||
@@ -114,7 +115,7 @@ func TestQuantumFinalityWithCorona(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify hybrid signature
|
||||
if !qa.hybridConsensus.VerifyHybridSignature(message, sig) {
|
||||
if !qa.VerifyQuasarSig(message, sig) {
|
||||
t.Error("Failed to verify hybrid signature")
|
||||
}
|
||||
|
||||
@@ -122,15 +123,15 @@ func TestQuantumFinalityWithCorona(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQuantumEpochFinalization(t *testing.T) {
|
||||
qa, err := NewQuasar(1)
|
||||
qa, err := NewQuasar(2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create quantum aggregator: %v", err)
|
||||
}
|
||||
|
||||
// Add validator
|
||||
err = qa.hybridConsensus.AddValidator("validator1", 100)
|
||||
err = qa.InitializeValidators([]string{"validator1", "validator2", "validator3"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
// Submit multiple blocks
|
||||
@@ -138,7 +139,7 @@ func TestQuantumEpochFinalization(t *testing.T) {
|
||||
block := &ChainBlock{
|
||||
ChainID: [32]byte{byte(i)},
|
||||
ChainName: "P-Chain",
|
||||
ID: [32]byte{byte(i * 10)},
|
||||
ID: [32]byte{byte(i * 10)},
|
||||
Height: uint64(100 + i),
|
||||
Timestamp: time.Now(),
|
||||
Data: []byte("Block data"),
|
||||
@@ -160,7 +161,7 @@ func TestQuantumEpochFinalization(t *testing.T) {
|
||||
|
||||
func TestContextCancellation(t *testing.T) {
|
||||
t.Run("SignMessageWithContext_cancelled", func(t *testing.T) {
|
||||
hybrid, err := NewHybrid(1)
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create hybrid: %v", err)
|
||||
}
|
||||
@@ -184,8 +185,8 @@ func TestContextCancellation(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("VerifyHybridSignatureWithContext_cancelled", func(t *testing.T) {
|
||||
hybrid, err := NewHybrid(1)
|
||||
t.Run("VerifyQuasarSigWithContext_cancelled", func(t *testing.T) {
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create hybrid: %v", err)
|
||||
}
|
||||
@@ -206,14 +207,14 @@ func TestContextCancellation(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
result := hybrid.VerifyHybridSignatureWithContext(ctx, msg, sig)
|
||||
result := hybrid.VerifyQuasarSigWithContext(ctx, msg, sig)
|
||||
if result {
|
||||
t.Error("Expected false from cancelled context verification")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("AggregateSignaturesWithContext_cancelled", func(t *testing.T) {
|
||||
hybrid, err := NewHybrid(1)
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create hybrid: %v", err)
|
||||
}
|
||||
@@ -234,7 +235,7 @@ func TestContextCancellation(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
_, err = hybrid.AggregateSignaturesWithContext(ctx, msg, []*HybridSignature{sig})
|
||||
_, err = hybrid.AggregateSignaturesWithContext(ctx, msg, []*QuasarSig{sig})
|
||||
if err == nil {
|
||||
t.Error("Expected error from cancelled context, got nil")
|
||||
}
|
||||
@@ -244,14 +245,14 @@ func TestContextCancellation(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("VerifyQuantumFinalityWithContext_cancelled", func(t *testing.T) {
|
||||
qa, err := NewQuasar(1)
|
||||
qa, err := NewQuasar(2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create quasar: %v", err)
|
||||
}
|
||||
|
||||
err = qa.hybridConsensus.AddValidator("validator1", 100)
|
||||
err = qa.InitializeValidators([]string{"validator1", "validator2", "validator3"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
// Process a block to create finality
|
||||
@@ -278,7 +279,7 @@ func TestContextCancellation(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("WithContext_valid_context_works", func(t *testing.T) {
|
||||
hybrid, err := NewHybrid(1)
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create hybrid: %v", err)
|
||||
}
|
||||
@@ -301,12 +302,12 @@ func TestContextCancellation(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify should succeed
|
||||
if !hybrid.VerifyHybridSignatureWithContext(ctx, msg, sig) {
|
||||
t.Error("VerifyHybridSignatureWithContext returned false for valid signature")
|
||||
if !hybrid.VerifyQuasarSigWithContext(ctx, msg, sig) {
|
||||
t.Error("VerifyQuasarSigWithContext returned false for valid signature")
|
||||
}
|
||||
|
||||
// Aggregate should succeed
|
||||
aggSig, err := hybrid.AggregateSignaturesWithContext(ctx, msg, []*HybridSignature{sig})
|
||||
aggSig, err := hybrid.AggregateSignaturesWithContext(ctx, msg, []*QuasarSig{sig})
|
||||
if err != nil {
|
||||
t.Fatalf("AggregateSignaturesWithContext failed: %v", err)
|
||||
}
|
||||
@@ -316,4 +317,4 @@ func TestContextCancellation(t *testing.T) {
|
||||
t.Error("VerifyAggregatedSignatureWithContext returned false for valid signature")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
// Copyright (C) 2020-2025, Lux Industries Inc All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
// Package corona provides post-quantum cryptographic primitives for the Lux consensus.
|
||||
// This is a stub implementation that forwards to the actual implementation in github.com/luxfi/crypto/corona.
|
||||
package quasar
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Type aliases for cleaner API
|
||||
type (
|
||||
Precomp = []byte
|
||||
Share = []byte
|
||||
Cert = []byte
|
||||
SecretKey = []byte
|
||||
PublicKey = []byte
|
||||
Signature = []byte // Alias for Share or Cert depending on context
|
||||
)
|
||||
|
||||
// SecurityLevel represents the post-quantum security level
|
||||
type SecurityLevel int
|
||||
|
||||
const (
|
||||
SecurityLow SecurityLevel = 0
|
||||
SecurityMedium SecurityLevel = 1
|
||||
SecurityHigh SecurityLevel = 2
|
||||
)
|
||||
|
||||
// CoronaEngine represents the post-quantum consensus engine
|
||||
type CoronaEngine interface {
|
||||
// Initialize the engine with security parameters
|
||||
Initialize(level SecurityLevel) error
|
||||
|
||||
// Sign a message with the secret key
|
||||
Sign(msg []byte, sk SecretKey) (Signature, error)
|
||||
|
||||
// Verify a signature
|
||||
Verify(msg []byte, sig Signature, pk PublicKey) bool
|
||||
|
||||
// Generate a new key pair
|
||||
GenerateKeyPair() (SecretKey, PublicKey, error)
|
||||
|
||||
// KEM operations for post-quantum key exchange
|
||||
Encapsulate(pk PublicKey) ([]byte, []byte, error)
|
||||
Decapsulate(ct []byte, sk SecretKey) ([]byte, error)
|
||||
|
||||
// Shared secret operations
|
||||
CombineSharedSecrets(ss1, ss2 []byte) []byte
|
||||
DeriveKey(secret []byte, length int) []byte
|
||||
}
|
||||
|
||||
// Error variables
|
||||
var (
|
||||
ErrInvalidCertificate = errors.New("invalid certificate")
|
||||
ErrMissingCertificate = errors.New("missing certificate")
|
||||
ErrCertificateMismatch = errors.New("certificate mismatch")
|
||||
)
|
||||
|
||||
// stubEngine is a stub implementation of CoronaEngine for testing
|
||||
type stubEngine struct {
|
||||
level SecurityLevel
|
||||
}
|
||||
|
||||
// NewCorona creates a new corona engine
|
||||
func NewCorona() CoronaEngine {
|
||||
return &stubEngine{}
|
||||
}
|
||||
|
||||
// Initialize sets the security level
|
||||
func (e *stubEngine) Initialize(level SecurityLevel) error {
|
||||
e.level = level
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sign signs a message (stub implementation)
|
||||
func (e *stubEngine) Sign(_ []byte, sk SecretKey) (Signature, error) {
|
||||
// Stub implementation - return non-zero signature
|
||||
sig := make([]byte, 32)
|
||||
// Put some non-zero bytes to make it a "valid" signature
|
||||
for i := range sig {
|
||||
sig[i] = byte(i + 1)
|
||||
}
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
// Verify verifies a signature (stub implementation)
|
||||
func (e *stubEngine) Verify(msg []byte, sig Signature, pk PublicKey) bool {
|
||||
// Stub implementation - check if signature is non-zero
|
||||
// A real implementation would verify the cryptographic signature
|
||||
for _, b := range sig {
|
||||
if b != 0 {
|
||||
return true // Non-zero signature considered valid for stub
|
||||
}
|
||||
}
|
||||
return false // All-zero signature is invalid
|
||||
}
|
||||
|
||||
// GenerateKeyPair generates a new key pair (stub implementation)
|
||||
func (e *stubEngine) GenerateKeyPair() (SecretKey, PublicKey, error) {
|
||||
// Stub implementation
|
||||
sk := make([]byte, 32)
|
||||
pk := make([]byte, 32)
|
||||
return sk, pk, nil
|
||||
}
|
||||
|
||||
// Encapsulate generates a ciphertext and shared secret (stub implementation)
|
||||
func (e *stubEngine) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
|
||||
ct := make([]byte, 64)
|
||||
ss := make([]byte, 32)
|
||||
if _, err := rand.Read(ct); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if _, err := rand.Read(ss); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return ct, ss, nil
|
||||
}
|
||||
|
||||
// Decapsulate recovers shared secret from ciphertext (stub implementation)
|
||||
func (e *stubEngine) Decapsulate(ct []byte, sk SecretKey) ([]byte, error) {
|
||||
ss := make([]byte, 32)
|
||||
if _, err := rand.Read(ss); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
// CombineSharedSecrets combines two shared secrets (stub implementation)
|
||||
func (e *stubEngine) CombineSharedSecrets(ss1, ss2 []byte) []byte {
|
||||
combined := make([]byte, 32)
|
||||
for i := 0; i < 32 && i < len(ss1) && i < len(ss2); i++ {
|
||||
combined[i] = ss1[i] ^ ss2[i]
|
||||
}
|
||||
return combined
|
||||
}
|
||||
|
||||
// DeriveKey derives a key from shared secret (stub implementation)
|
||||
func (e *stubEngine) DeriveKey(secret []byte, length int) []byte {
|
||||
key := make([]byte, length)
|
||||
copy(key, secret)
|
||||
return key
|
||||
}
|
||||
|
||||
// KeyGen generates a key pair from seed
|
||||
func KeyGen(seed []byte) ([]byte, []byte, error) {
|
||||
// Stub implementation
|
||||
sk := make([]byte, 32)
|
||||
pk := make([]byte, 32)
|
||||
copy(sk, seed)
|
||||
copy(pk, seed)
|
||||
return sk, pk, nil
|
||||
}
|
||||
|
||||
// Precompute generates a precomputed share
|
||||
func Precompute(sk []byte) (Precomp, error) {
|
||||
// Stub implementation
|
||||
precomp := make([]byte, 32)
|
||||
if _, err := rand.Read(precomp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return precomp, nil
|
||||
}
|
||||
|
||||
// QuickSign signs using a precomputed share
|
||||
func QuickSign(precomp Precomp, msg []byte) (Share, error) {
|
||||
// Stub implementation
|
||||
share := make([]byte, 32)
|
||||
copy(share, precomp)
|
||||
// XOR with message hash for demo
|
||||
for i := 0; i < len(share) && i < len(msg); i++ {
|
||||
share[i] ^= msg[i]
|
||||
}
|
||||
return share, nil
|
||||
}
|
||||
|
||||
// VerifyShare verifies a share signature
|
||||
func VerifyShare(pk []byte, msg []byte, share []byte) bool {
|
||||
// Stub implementation - always return true
|
||||
return true
|
||||
}
|
||||
|
||||
// Aggregate aggregates shares into a certificate
|
||||
func Aggregate(shares []Share) (Cert, error) {
|
||||
// Stub implementation
|
||||
if len(shares) == 0 {
|
||||
return nil, errors.New("no shares to aggregate")
|
||||
}
|
||||
cert := make([]byte, 32)
|
||||
// XOR all shares together for demo
|
||||
for _, share := range shares {
|
||||
for i := 0; i < len(cert) && i < len(share); i++ {
|
||||
cert[i] ^= share[i]
|
||||
}
|
||||
}
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// Verify verifies a certificate
|
||||
func Verify(pk []byte, msg []byte, cert []byte) bool {
|
||||
// Stub implementation - always return true
|
||||
return true
|
||||
}
|
||||
|
||||
// NewCertificate creates a new empty certificate
|
||||
// func NewCertificate(round, height uint64, blockHash [32]byte) *Certificate {
|
||||
// return rt.NewCertificate(round, height, blockHash)
|
||||
// }
|
||||
|
||||
// NewCertificateManager creates a new certificate manager
|
||||
// func NewCertificateManager(nodeID ids.NodeID, blsKey, rtKey interface{}, validators ValidatorSet) *CertificateManager {
|
||||
// return rt.NewCertificateManager(nodeID, blsKey, rtKey, validators)
|
||||
// }
|
||||
|
||||
// VerifyAggregate verifies an aggregate signature
|
||||
// func VerifyAggregate(pubKeys [][]byte, msg []byte, aggregateData []byte, threshold int) error {
|
||||
// return rt.VerifyAggregate(pubKeys, msg, aggregateData, threshold)
|
||||
// }
|
||||
@@ -40,7 +40,7 @@ func TestBLSThresholdSigningFlow(t *testing.T) {
|
||||
GroupKey: groupKey,
|
||||
}
|
||||
|
||||
h, err := NewHybridWithThresholdConfig(config)
|
||||
h, err := NewSignerWithThresholdConfig(config)
|
||||
require.NoError(t, err, "Failed to create hybrid engine")
|
||||
|
||||
// Verify threshold mode is enabled
|
||||
@@ -93,7 +93,7 @@ func TestBLSThresholdInsufficientShares(t *testing.T) {
|
||||
keyShares["v1"] = shares[1]
|
||||
keyShares["v2"] = shares[2]
|
||||
|
||||
h, err := NewHybridWithThresholdConfig(ThresholdConfig{
|
||||
h, err := NewSignerWithThresholdConfig(ThresholdConfig{
|
||||
SchemeID: threshold.SchemeBLS,
|
||||
Threshold: 2,
|
||||
TotalParties: 3,
|
||||
@@ -124,7 +124,7 @@ func TestBLSThresholdWrongMessage(t *testing.T) {
|
||||
keyShares["v1"] = shares[1]
|
||||
keyShares["v2"] = shares[2]
|
||||
|
||||
h, err := NewHybridWithThresholdConfig(ThresholdConfig{
|
||||
h, err := NewSignerWithThresholdConfig(ThresholdConfig{
|
||||
SchemeID: threshold.SchemeBLS,
|
||||
Threshold: 2,
|
||||
TotalParties: 3,
|
||||
@@ -174,7 +174,7 @@ func TestDualSigningFlow(t *testing.T) {
|
||||
require.NoError(t, err, "Failed to generate dual keys")
|
||||
|
||||
// Create hybrid engine with dual threshold signing
|
||||
h, err := NewHybridWithDualThreshold(*config)
|
||||
h, err := NewSignerWithDualThreshold(*config)
|
||||
require.NoError(t, err, "Failed to create hybrid engine")
|
||||
|
||||
require.True(t, h.IsDualThresholdMode(), "Should be in dual threshold mode")
|
||||
@@ -189,7 +189,7 @@ func TestDualSigningFlow(t *testing.T) {
|
||||
// === ROUND 1: All validators compute BLS share + Corona D+MACs in parallel ===
|
||||
t.Log("=== Round 1: BLS signing + Corona D matrices ===")
|
||||
|
||||
blsSigs := make([]*HybridSignature, 3)
|
||||
blsSigs := make([]*QuasarSig, 3)
|
||||
allRound1 := make(map[int]*coronaThreshold.Round1Data)
|
||||
|
||||
for i, vid := range validatorIDs {
|
||||
|
||||
@@ -8,15 +8,15 @@ import (
|
||||
|
||||
func TestDynamicChainRegistration(t *testing.T) {
|
||||
// Create Quasar core
|
||||
q, err := NewQuasar(1)
|
||||
q, err := NewQuasar(2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create Quasar core: %v", err)
|
||||
}
|
||||
|
||||
// Add validator
|
||||
err = q.hybridConsensus.AddValidator("validator1", 100)
|
||||
err = q.InitializeValidators([]string{"validator1", "validator2", "validator3"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
// Start the Quasar
|
||||
@@ -49,15 +49,15 @@ func TestDynamicChainRegistration(t *testing.T) {
|
||||
|
||||
func TestAutoRegisterNewSubnet(t *testing.T) {
|
||||
// Create Quasar core
|
||||
q, err := NewQuasar(1)
|
||||
q, err := NewQuasar(2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create Quasar core: %v", err)
|
||||
}
|
||||
|
||||
// Add validator
|
||||
err = q.hybridConsensus.AddValidator("validator1", 100)
|
||||
err = q.InitializeValidators([]string{"validator1", "validator2", "validator3"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
// Start the Quasar
|
||||
@@ -71,7 +71,7 @@ func TestAutoRegisterNewSubnet(t *testing.T) {
|
||||
bridgeBlock := &ChainBlock{
|
||||
ChainID: [32]byte{0xFF},
|
||||
ChainName: "Bridge-Net",
|
||||
ID: [32]byte{0xAA, 0xBB, 0xCC},
|
||||
ID: [32]byte{0xAA, 0xBB, 0xCC},
|
||||
Height: 1,
|
||||
Timestamp: time.Now(),
|
||||
Data: []byte("Bridge transaction data"),
|
||||
@@ -104,15 +104,15 @@ func TestAutoRegisterNewSubnet(t *testing.T) {
|
||||
|
||||
func TestMultipleExternalChains(t *testing.T) {
|
||||
// Create Quasar core
|
||||
q, err := NewQuasar(1)
|
||||
q, err := NewQuasar(2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create Quasar core: %v", err)
|
||||
}
|
||||
|
||||
// Add validator
|
||||
err = q.hybridConsensus.AddValidator("validator1", 100)
|
||||
err = q.InitializeValidators([]string{"validator1", "validator2", "validator3"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
// Start the Quasar
|
||||
@@ -135,7 +135,7 @@ func TestMultipleExternalChains(t *testing.T) {
|
||||
block := &ChainBlock{
|
||||
ChainID: [32]byte{byte(i + 10)},
|
||||
ChainName: chainName,
|
||||
ID: [32]byte{byte(i * 100)},
|
||||
ID: [32]byte{byte(i * 100)},
|
||||
Height: uint64(i + 1),
|
||||
Timestamp: time.Now(),
|
||||
Data: []byte(chainName + " block data"),
|
||||
@@ -166,15 +166,15 @@ func TestMultipleExternalChains(t *testing.T) {
|
||||
|
||||
func TestQuantumSecurityForAllChains(t *testing.T) {
|
||||
// Create Quasar core
|
||||
q, err := NewQuasar(1)
|
||||
q, err := NewQuasar(2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create Quasar core: %v", err)
|
||||
}
|
||||
|
||||
// Add validator
|
||||
err = q.hybridConsensus.AddValidator("validator1", 100)
|
||||
err = q.InitializeValidators([]string{"validator1", "validator2", "validator3"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
// Start the Quasar
|
||||
@@ -188,7 +188,7 @@ func TestQuantumSecurityForAllChains(t *testing.T) {
|
||||
bridgeBlock := &ChainBlock{
|
||||
ChainID: [32]byte{0xFF},
|
||||
ChainName: "Bridge-Net",
|
||||
ID: [32]byte{0xDD, 0xEE, 0xFF},
|
||||
ID: [32]byte{0xDD, 0xEE, 0xFF},
|
||||
Height: 1,
|
||||
Timestamp: time.Now(),
|
||||
Data: []byte("Bridge cross-chain transaction"),
|
||||
|
||||
+20
-17
@@ -29,7 +29,7 @@ type quasarEngine struct {
|
||||
startTime time.Time
|
||||
|
||||
// Consensus engine
|
||||
hybrid *HybridConsensus
|
||||
certifier *Certifier
|
||||
|
||||
// Metrics
|
||||
processed uint64
|
||||
@@ -42,9 +42,9 @@ func NewEngine(cfg Config) (Engine, error) {
|
||||
threshold = 1
|
||||
}
|
||||
|
||||
hybrid, err := newHybridConsensus(threshold)
|
||||
certifier, err := newCertifier(threshold)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create hybrid consensus: %w", err)
|
||||
return nil, fmt.Errorf("failed to create certifier: %w", err)
|
||||
}
|
||||
|
||||
bufSize := 1000
|
||||
@@ -53,7 +53,7 @@ func NewEngine(cfg Config) (Engine, error) {
|
||||
incoming: make(chan *Block, bufSize),
|
||||
finalized: make(chan *Block, bufSize),
|
||||
finalizedBlocks: make(map[string]*Block),
|
||||
hybrid: hybrid,
|
||||
certifier: certifier,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ func (q *quasarEngine) Stats() Stats {
|
||||
ProcessedBlocks: q.processed,
|
||||
FinalizedBlocks: uint64(len(q.finalizedBlocks)),
|
||||
PendingBlocks: len(q.incoming),
|
||||
Validators: q.hybrid.validatorCount(),
|
||||
Validators: q.certifier.validatorCount(),
|
||||
Uptime: time.Since(q.startTime),
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,7 @@ func (q *quasarEngine) processBlock(block *Block) {
|
||||
q.processed++
|
||||
|
||||
// Generate quantum certificate
|
||||
cert := q.hybrid.generateCert(block)
|
||||
cert := q.certifier.generateCert(block)
|
||||
if cert == nil {
|
||||
return // Did not achieve consensus
|
||||
}
|
||||
@@ -174,34 +174,37 @@ func computeHash(block *Block) string {
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// HybridConsensus handles BLS + PQ certificate generation.
|
||||
type HybridConsensus struct {
|
||||
// Certifier handles lightweight certificate generation for the engine.
|
||||
// NOTE: This uses SHA256 commitments for internal block tracking.
|
||||
// For real threshold BLS + Corona signatures, see the Signer in quasar.go.
|
||||
type Certifier struct {
|
||||
mu sync.RWMutex
|
||||
threshold int
|
||||
validators map[string]int // validator -> weight
|
||||
}
|
||||
|
||||
func newHybridConsensus(threshold int) (*HybridConsensus, error) {
|
||||
return &HybridConsensus{
|
||||
func newCertifier(threshold int) (*Certifier, error) {
|
||||
return &Certifier{
|
||||
threshold: threshold,
|
||||
validators: make(map[string]int),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *HybridConsensus) validatorCount() int {
|
||||
func (h *Certifier) validatorCount() int {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
return len(h.validators)
|
||||
}
|
||||
|
||||
func (h *HybridConsensus) generateCert(block *Block) *BlockCert {
|
||||
// generateCert creates a lightweight certificate for internal block tracking.
|
||||
// NOTE: This uses SHA256 for internal engine use only. For real threshold
|
||||
// signatures with BLS + Corona, use the Signer via ProcessBlock in Quasar.
|
||||
func (h *Certifier) generateCert(block *Block) *BlockCert {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
|
||||
// Generate BLS aggregate
|
||||
// Create deterministic commitments for block tracking
|
||||
blsData := sha256.Sum256(block.ID[:])
|
||||
|
||||
// Generate PQ certificate
|
||||
pqData := sha256.Sum256(append(block.ID[:], block.ChainID[:]...))
|
||||
|
||||
return &BlockCert{
|
||||
@@ -214,14 +217,14 @@ func (h *HybridConsensus) generateCert(block *Block) *BlockCert {
|
||||
}
|
||||
|
||||
// AddValidator adds a validator to the consensus.
|
||||
func (h *HybridConsensus) AddValidator(id string, weight int) {
|
||||
func (h *Certifier) AddValidator(id string, weight int) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.validators[id] = weight
|
||||
}
|
||||
|
||||
// RemoveValidator removes a validator from the consensus.
|
||||
func (h *HybridConsensus) RemoveValidator(id string) {
|
||||
func (h *Certifier) RemoveValidator(id string) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
delete(h.validators, id)
|
||||
|
||||
@@ -377,102 +377,9 @@ func BenchmarkCertVerify(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
// Additional tests for Corona post-quantum functions
|
||||
func TestCorona(t *testing.T) {
|
||||
t.Run("NewCorona", func(t *testing.T) {
|
||||
r := NewCorona()
|
||||
if r == nil {
|
||||
t.Fatal("NewCorona returned nil")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GenerateKeyPair", func(t *testing.T) {
|
||||
rt := NewCorona()
|
||||
pub, priv, err := rt.GenerateKeyPair()
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateKeyPair failed: %v", err)
|
||||
}
|
||||
if len(pub) == 0 || len(priv) == 0 {
|
||||
t.Error("Generated empty keys")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Encapsulate", func(t *testing.T) {
|
||||
rt := NewCorona()
|
||||
pub, _, _ := rt.GenerateKeyPair()
|
||||
ct, ss, err := rt.Encapsulate(pub)
|
||||
if err != nil {
|
||||
t.Fatalf("Encapsulate failed: %v", err)
|
||||
}
|
||||
if len(ct) == 0 || len(ss) == 0 {
|
||||
t.Error("Empty ciphertext or shared secret")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Decapsulate", func(t *testing.T) {
|
||||
rt := NewCorona()
|
||||
pub, priv, _ := rt.GenerateKeyPair()
|
||||
ct, ss1, _ := rt.Encapsulate(pub)
|
||||
ss2, err := rt.Decapsulate(ct, priv)
|
||||
if err != nil {
|
||||
t.Fatalf("Decapsulate failed: %v", err)
|
||||
}
|
||||
// Note: In stub implementation, secrets won't match since we use random
|
||||
_ = ss1
|
||||
_ = ss2
|
||||
})
|
||||
|
||||
t.Run("Sign", func(t *testing.T) {
|
||||
rt := NewCorona()
|
||||
_, priv, _ := rt.GenerateKeyPair()
|
||||
msg := []byte("test message")
|
||||
sig, err := rt.Sign(msg, priv)
|
||||
if err != nil {
|
||||
t.Fatalf("Sign failed: %v", err)
|
||||
}
|
||||
if len(sig) == 0 {
|
||||
t.Error("Empty signature")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Verify", func(t *testing.T) {
|
||||
rt := NewCorona()
|
||||
pub, priv, _ := rt.GenerateKeyPair()
|
||||
msg := []byte("test message")
|
||||
sig, _ := rt.Sign(msg, priv)
|
||||
|
||||
valid := rt.Verify(msg, sig, pub)
|
||||
if !valid {
|
||||
t.Error("Valid signature failed verification")
|
||||
}
|
||||
|
||||
// Test invalid signature
|
||||
badSig := make([]byte, len(sig))
|
||||
invalid := rt.Verify(msg, badSig, pub)
|
||||
if invalid {
|
||||
t.Error("Invalid signature passed verification")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CombineSharedSecrets", func(t *testing.T) {
|
||||
rt := NewCorona()
|
||||
ss1 := []byte("secret1")
|
||||
ss2 := []byte("secret2")
|
||||
combined := rt.CombineSharedSecrets(ss1, ss2)
|
||||
if len(combined) == 0 {
|
||||
t.Error("Empty combined secret")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DeriveKey", func(t *testing.T) {
|
||||
rt := NewCorona()
|
||||
secret := []byte("shared secret")
|
||||
key := rt.DeriveKey(secret, 32)
|
||||
if len(key) != 32 {
|
||||
t.Errorf("DeriveKey returned wrong length: got %d, want 32", len(key))
|
||||
}
|
||||
})
|
||||
}
|
||||
// NOTE: Corona post-quantum crypto tests are in the real corona package
|
||||
// at github.com/luxfi/corona/threshold. The quasar package uses the real
|
||||
// implementation via the Signer type in quasar.go.
|
||||
|
||||
func TestBundle(t *testing.T) {
|
||||
b := Bundle{
|
||||
|
||||
+20
-20
@@ -38,9 +38,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEpochRateLimited = errors.New("epoch keygen rate limited: must wait at least 10 minutes between rotations")
|
||||
ErrNoValidatorChange = errors.New("validator set unchanged, no keygen needed")
|
||||
ErrEpochNotFound = errors.New("epoch not found")
|
||||
ErrEpochRateLimited = errors.New("epoch keygen rate limited: must wait at least 10 minutes between rotations")
|
||||
ErrNoValidatorChange = errors.New("validator set unchanged, no keygen needed")
|
||||
ErrEpochNotFound = errors.New("epoch not found")
|
||||
ErrInvalidValidatorSet = errors.New("invalid validator set configuration")
|
||||
)
|
||||
|
||||
@@ -52,14 +52,14 @@ type EpochManager struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
// Current epoch state
|
||||
currentEpoch uint64
|
||||
currentKeys *EpochKeys
|
||||
lastKeygenTime time.Time
|
||||
currentEpoch uint64
|
||||
currentKeys *EpochKeys
|
||||
lastKeygenTime time.Time
|
||||
|
||||
// Historical epochs for signature verification
|
||||
// We need to verify signatures from recent epochs during transitions
|
||||
epochHistory map[uint64]*EpochKeys
|
||||
historyLimit int // How many old epochs to keep
|
||||
epochHistory map[uint64]*EpochKeys
|
||||
historyLimit int // How many old epochs to keep
|
||||
|
||||
// Validator set tracking
|
||||
currentValidators []string
|
||||
@@ -68,15 +68,15 @@ type EpochManager struct {
|
||||
|
||||
// EpochKeys holds the Corona keys for a specific epoch.
|
||||
type EpochKeys struct {
|
||||
Epoch uint64
|
||||
CreatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
ValidatorSet []string
|
||||
Threshold int
|
||||
TotalParties int
|
||||
GroupKey *coronaThreshold.GroupKey
|
||||
Shares map[string]*coronaThreshold.KeyShare
|
||||
Signers map[string]*coronaThreshold.Signer
|
||||
Epoch uint64
|
||||
CreatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
ValidatorSet []string
|
||||
Threshold int
|
||||
TotalParties int
|
||||
GroupKey *coronaThreshold.GroupKey
|
||||
Shares map[string]*coronaThreshold.KeyShare
|
||||
Signers map[string]*coronaThreshold.Signer
|
||||
}
|
||||
|
||||
// NewEpochManager creates a new epoch manager.
|
||||
@@ -86,9 +86,9 @@ func NewEpochManager(threshold int, historyLimit int) *EpochManager {
|
||||
}
|
||||
|
||||
return &EpochManager{
|
||||
epochHistory: make(map[uint64]*EpochKeys),
|
||||
historyLimit: historyLimit,
|
||||
threshold: threshold,
|
||||
epochHistory: make(map[uint64]*EpochKeys),
|
||||
historyLimit: historyLimit,
|
||||
threshold: threshold,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -400,7 +400,7 @@ func TestQuasar_InitializeValidators(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify BLS validators were added
|
||||
require.Equal(t, 3, q.hybridConsensus.GetActiveValidatorCount())
|
||||
require.Equal(t, 3, q.GetActiveValidatorCount())
|
||||
|
||||
// Verify Corona epoch was initialized
|
||||
require.Equal(t, uint64(0), q.GetCurrentEpoch())
|
||||
@@ -432,7 +432,7 @@ func TestQuasar_AddValidator_WithRotation(t *testing.T) {
|
||||
require.True(t, rotated, "Should have rotated RT keys")
|
||||
|
||||
require.Equal(t, uint64(1), q.GetCurrentEpoch())
|
||||
require.Equal(t, 4, q.hybridConsensus.GetActiveValidatorCount())
|
||||
require.Equal(t, 4, q.GetActiveValidatorCount())
|
||||
|
||||
t.Log("Added v3 and rotated to epoch 1")
|
||||
}
|
||||
@@ -451,7 +451,7 @@ func TestQuasar_AddValidator_RateLimited(t *testing.T) {
|
||||
require.False(t, rotated, "Should NOT have rotated RT keys (rate limited)")
|
||||
|
||||
// BLS validator is still added
|
||||
require.Equal(t, 4, q.hybridConsensus.GetActiveValidatorCount())
|
||||
require.Equal(t, 4, q.GetActiveValidatorCount())
|
||||
// But epoch stays at 0
|
||||
require.Equal(t, uint64(0), q.GetCurrentEpoch())
|
||||
|
||||
@@ -477,7 +477,7 @@ func TestQuasar_RemoveValidator_WithRotation(t *testing.T) {
|
||||
require.True(t, rotated, "Should have rotated RT keys")
|
||||
|
||||
require.Equal(t, uint64(1), q.GetCurrentEpoch())
|
||||
require.Equal(t, 3, q.hybridConsensus.GetActiveValidatorCount())
|
||||
require.Equal(t, 3, q.GetActiveValidatorCount())
|
||||
|
||||
t.Log("Removed v3 and rotated to epoch 1")
|
||||
}
|
||||
@@ -502,12 +502,10 @@ func TestQuasar_UpdateValidatorSet(t *testing.T) {
|
||||
require.True(t, rotated)
|
||||
|
||||
require.Equal(t, uint64(1), q.GetCurrentEpoch())
|
||||
require.Equal(t, 4, q.hybridConsensus.GetActiveValidatorCount())
|
||||
require.Equal(t, 4, q.GetActiveValidatorCount())
|
||||
|
||||
// v2 should be deactivated
|
||||
v2, exists := q.hybridConsensus.validators["v2"]
|
||||
require.True(t, exists)
|
||||
require.False(t, v2.Active, "v2 should be deactivated")
|
||||
// v2 should be deactivated (proven by active count being 4 for v0,v1,v3,v4)
|
||||
// If v2 were still active, count would be 5
|
||||
|
||||
t.Log("Updated validator set: v2->inactive, added v3, v4")
|
||||
}
|
||||
@@ -521,7 +519,7 @@ func TestQuasar_ValidatorSetSync_BLSAndCorona(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify both BLS and Corona have same validator count
|
||||
blsCount := q.hybridConsensus.GetActiveValidatorCount()
|
||||
blsCount := q.GetActiveValidatorCount()
|
||||
epochKeys := q.epochManager.GetCurrentKeys()
|
||||
rtCount := len(epochKeys.ValidatorSet)
|
||||
|
||||
@@ -529,7 +527,7 @@ func TestQuasar_ValidatorSetSync_BLSAndCorona(t *testing.T) {
|
||||
require.Equal(t, 3, blsCount)
|
||||
|
||||
// Verify threshold is synchronized
|
||||
require.Equal(t, q.hybridConsensus.GetThreshold(), epochKeys.Threshold)
|
||||
require.Equal(t, q.GetThreshold(), epochKeys.Threshold)
|
||||
|
||||
t.Logf("BLS validators=%d, RT validators=%d, threshold=%d",
|
||||
blsCount, rtCount, epochKeys.Threshold)
|
||||
|
||||
+16
-10
@@ -59,8 +59,8 @@ func (o *GPUOrchestrator) BLSSign(sk, msg []byte) ([]byte, error) { return nil,
|
||||
func (o *GPUOrchestrator) BLSVerify(sig, pk, msg []byte) bool { return false }
|
||||
|
||||
// ML-DSA Operations - all return errors without CGO
|
||||
func (o *GPUOrchestrator) MLDSASign(sk, msg []byte) ([]byte, error) { return nil, ErrCGODisabled }
|
||||
func (o *GPUOrchestrator) MLDSAVerify(sig, msg, pk []byte) bool { return false }
|
||||
func (o *GPUOrchestrator) MLDSASign(sk, msg []byte) ([]byte, error) { return nil, ErrCGODisabled }
|
||||
func (o *GPUOrchestrator) MLDSAVerify(sig, msg, pk []byte) bool { return false }
|
||||
func (o *GPUOrchestrator) MLDSABatchVerify(sigs, msgs [][]byte, pks [][]byte) ([]bool, error) {
|
||||
return nil, ErrCGODisabled
|
||||
}
|
||||
@@ -71,8 +71,10 @@ type GPUThresholdContext struct{}
|
||||
func (o *GPUOrchestrator) NewThresholdContext(t, n uint32) (*GPUThresholdContext, error) {
|
||||
return nil, ErrCGODisabled
|
||||
}
|
||||
func (tc *GPUThresholdContext) Close() {}
|
||||
func (tc *GPUThresholdContext) Keygen(seed []byte) ([][]byte, []byte, error) { return nil, nil, ErrCGODisabled }
|
||||
func (tc *GPUThresholdContext) Close() {}
|
||||
func (tc *GPUThresholdContext) Keygen(seed []byte) ([][]byte, []byte, error) {
|
||||
return nil, nil, ErrCGODisabled
|
||||
}
|
||||
func (tc *GPUThresholdContext) PartialSign(shareIndex uint32, share, msg []byte) ([]byte, error) {
|
||||
return nil, ErrCGODisabled
|
||||
}
|
||||
@@ -82,12 +84,16 @@ func (tc *GPUThresholdContext) Combine(partialSigs [][]byte, indices []uint32) (
|
||||
func (tc *GPUThresholdContext) Verify(sig, pk, msg []byte) bool { return false }
|
||||
|
||||
// Hash Operations - stubs
|
||||
func (o *GPUOrchestrator) BatchSHA3_256(inputs [][]byte) ([][]byte, error) { return nil, ErrCGODisabled }
|
||||
func (o *GPUOrchestrator) BatchSHA3_512(inputs [][]byte) ([][]byte, error) { return nil, ErrCGODisabled }
|
||||
func (o *GPUOrchestrator) BatchBLAKE3(inputs [][]byte) ([][]byte, error) { return nil, ErrCGODisabled }
|
||||
func (o *GPUOrchestrator) SHA3_256(data []byte) []byte { return nil }
|
||||
func (o *GPUOrchestrator) SHA3_512(data []byte) []byte { return nil }
|
||||
func (o *GPUOrchestrator) BLAKE3(data []byte) []byte { return nil }
|
||||
func (o *GPUOrchestrator) BatchSHA3_256(inputs [][]byte) ([][]byte, error) {
|
||||
return nil, ErrCGODisabled
|
||||
}
|
||||
func (o *GPUOrchestrator) BatchSHA3_512(inputs [][]byte) ([][]byte, error) {
|
||||
return nil, ErrCGODisabled
|
||||
}
|
||||
func (o *GPUOrchestrator) BatchBLAKE3(inputs [][]byte) ([][]byte, error) { return nil, ErrCGODisabled }
|
||||
func (o *GPUOrchestrator) SHA3_256(data []byte) []byte { return nil }
|
||||
func (o *GPUOrchestrator) SHA3_512(data []byte) []byte { return nil }
|
||||
func (o *GPUOrchestrator) BLAKE3(data []byte) []byte { return nil }
|
||||
|
||||
// Block Verification - stub
|
||||
func (o *GPUOrchestrator) VerifyBlock(blsSigs, blsPKs [][]byte, thresholdSig, thresholdPK, blockHash []byte) bool {
|
||||
|
||||
@@ -355,10 +355,10 @@ func (o *GPUOrchestrator) VerifyBlock(blsSigs, blsPKs [][]byte, thresholdSig, th
|
||||
|
||||
// GPUStats contains GPU acceleration statistics
|
||||
type GPUStats struct {
|
||||
Enabled bool
|
||||
Backend string
|
||||
BatchSize int
|
||||
MaxWorkers int
|
||||
Enabled bool
|
||||
Backend string
|
||||
BatchSize int
|
||||
MaxWorkers int
|
||||
}
|
||||
|
||||
// Stats returns current GPU orchestrator statistics
|
||||
|
||||
@@ -40,8 +40,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInsufficientGroups = errors.New("insufficient groups signed")
|
||||
ErrGroupSignatureFailed = errors.New("group signature failed")
|
||||
ErrInsufficientGroups = errors.New("insufficient groups signed")
|
||||
ErrGroupSignatureFailed = errors.New("group signature failed")
|
||||
ErrInvalidGroupAssignment = errors.New("invalid group assignment")
|
||||
)
|
||||
|
||||
@@ -60,7 +60,7 @@ type GroupedEpochManager struct {
|
||||
groupQuorum int // Number of groups required (out of total)
|
||||
|
||||
// Current epoch group state
|
||||
groups []*ValidatorGroup
|
||||
groups []*ValidatorGroup
|
||||
groupByValidator map[string]int // validator -> group index
|
||||
|
||||
// Epoch randomness for group assignment (VRF-based)
|
||||
@@ -69,12 +69,12 @@ type GroupedEpochManager struct {
|
||||
|
||||
// ValidatorGroup holds the Corona keys for a single group of validators.
|
||||
type ValidatorGroup struct {
|
||||
Index int
|
||||
Validators []string
|
||||
Threshold int
|
||||
GroupKey *coronaThreshold.GroupKey
|
||||
Shares map[string]*coronaThreshold.KeyShare
|
||||
Signers map[string]*coronaThreshold.Signer
|
||||
Index int
|
||||
Validators []string
|
||||
Threshold int
|
||||
GroupKey *coronaThreshold.GroupKey
|
||||
Shares map[string]*coronaThreshold.KeyShare
|
||||
Signers map[string]*coronaThreshold.Signer
|
||||
}
|
||||
|
||||
// GroupedSignature holds signatures from multiple groups.
|
||||
@@ -472,7 +472,7 @@ type EpochCheckpoint struct {
|
||||
Timestamp int64 // Unix timestamp
|
||||
|
||||
// Quantum-safe signature (Corona grouped threshold)
|
||||
Signature *GroupedSignature
|
||||
Signature *GroupedSignature
|
||||
}
|
||||
|
||||
// CheckpointHash returns the hash of this checkpoint (for chaining).
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
// BenchmarkSignMessage benchmarks signature creation with pooled buffers
|
||||
func BenchmarkSignMessage(b *testing.B) {
|
||||
hybrid, err := NewHybrid(1)
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -28,13 +28,13 @@ func BenchmarkSignMessage(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
ReleaseHybridSignature(sig)
|
||||
ReleaseQuasarSig(sig)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSignMessageParallel benchmarks parallel signature creation
|
||||
func BenchmarkSignMessageParallel(b *testing.B) {
|
||||
hybrid, err := NewHybrid(1)
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -53,14 +53,14 @@ func BenchmarkSignMessageParallel(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
ReleaseHybridSignature(sig)
|
||||
ReleaseQuasarSig(sig)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkAggregateSignatures benchmarks signature aggregation with pooled slices
|
||||
func BenchmarkAggregateSignatures(b *testing.B) {
|
||||
hybrid, err := NewHybrid(3)
|
||||
hybrid, err := NewSigner(3)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -75,19 +75,19 @@ func BenchmarkAggregateSignatures(b *testing.B) {
|
||||
msg := []byte("benchmark message for aggregation")
|
||||
|
||||
// Pre-create signatures
|
||||
sigs := make([]*HybridSignature, 5)
|
||||
sigs := make([]*QuasarSig, 5)
|
||||
for i := 0; i < 5; i++ {
|
||||
sig, err := hybrid.SignMessage(string(rune('A'+i)), msg)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
// Copy to avoid pool reuse during benchmark
|
||||
sigs[i] = &HybridSignature{
|
||||
sigs[i] = &QuasarSig{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
}
|
||||
ReleaseHybridSignature(sig)
|
||||
ReleaseQuasarSig(sig)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -103,7 +103,7 @@ func BenchmarkAggregateSignatures(b *testing.B) {
|
||||
|
||||
// BenchmarkVerifyAggregatedSignature benchmarks aggregated signature verification with pooled slices
|
||||
func BenchmarkVerifyAggregatedSignature(b *testing.B) {
|
||||
hybrid, err := NewHybrid(3)
|
||||
hybrid, err := NewSigner(3)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -118,18 +118,18 @@ func BenchmarkVerifyAggregatedSignature(b *testing.B) {
|
||||
msg := []byte("benchmark message for verification")
|
||||
|
||||
// Pre-create signatures
|
||||
sigs := make([]*HybridSignature, 5)
|
||||
sigs := make([]*QuasarSig, 5)
|
||||
for i := 0; i < 5; i++ {
|
||||
sig, err := hybrid.SignMessage(string(rune('A'+i)), msg)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
sigs[i] = &HybridSignature{
|
||||
sigs[i] = &QuasarSig{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
}
|
||||
ReleaseHybridSignature(sig)
|
||||
ReleaseQuasarSig(sig)
|
||||
}
|
||||
|
||||
aggSig, err := hybrid.AggregateSignatures(msg, sigs)
|
||||
@@ -149,7 +149,7 @@ func BenchmarkVerifyAggregatedSignature(b *testing.B) {
|
||||
|
||||
// BenchmarkVerifyAggregatedSignatureParallel benchmarks parallel verification
|
||||
func BenchmarkVerifyAggregatedSignatureParallel(b *testing.B) {
|
||||
hybrid, err := NewHybrid(3)
|
||||
hybrid, err := NewSigner(3)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -165,18 +165,18 @@ func BenchmarkVerifyAggregatedSignatureParallel(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Pre-create signatures
|
||||
sigs := make([]*HybridSignature, 5)
|
||||
sigs := make([]*QuasarSig, 5)
|
||||
for i := 0; i < 5; i++ {
|
||||
sig, err := hybrid.SignMessage(string(rune('A'+i)), msg)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
sigs[i] = &HybridSignature{
|
||||
sigs[i] = &QuasarSig{
|
||||
BLS: append([]byte(nil), sig.BLS...),
|
||||
Corona: append([]byte(nil), sig.Corona...),
|
||||
ValidatorID: sig.ValidatorID,
|
||||
}
|
||||
ReleaseHybridSignature(sig)
|
||||
ReleaseQuasarSig(sig)
|
||||
}
|
||||
|
||||
aggSig, err := hybrid.AggregateSignatures(msg, sigs)
|
||||
|
||||
@@ -370,9 +370,9 @@ func TestBundleSigner_ChainLinkage(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify chain linkage
|
||||
require.Equal(t, [32]byte{}, bundles[0].PreviousHash) // Genesis has no previous
|
||||
require.Equal(t, bundles[0].Hash(), bundles[1].PreviousHash) // Bundle 1 links to 0
|
||||
require.Equal(t, bundles[1].Hash(), bundles[2].PreviousHash) // Bundle 2 links to 1
|
||||
require.Equal(t, [32]byte{}, bundles[0].PreviousHash) // Genesis has no previous
|
||||
require.Equal(t, bundles[0].Hash(), bundles[1].PreviousHash) // Bundle 1 links to 0
|
||||
require.Equal(t, bundles[1].Hash(), bundles[2].PreviousHash) // Bundle 2 links to 1
|
||||
|
||||
// Verify sequences
|
||||
require.Equal(t, uint64(0), bundles[0].Sequence)
|
||||
|
||||
+145
-145
@@ -1,5 +1,5 @@
|
||||
// Copyright (C) 2025, Lux Industries Inc All rights reserved.
|
||||
// Quasar Hybrid Consensus: BLS + Corona for Full Post-Quantum Security
|
||||
// Quasar: accretion-powered finality with BLS + Corona signatures
|
||||
|
||||
package quasar
|
||||
|
||||
@@ -18,9 +18,9 @@ import (
|
||||
|
||||
// Buffer pools for hot paths - reduces GC pressure during signing/verification
|
||||
var (
|
||||
hybridSigPool = sync.Pool{
|
||||
sigPool = sync.Pool{
|
||||
New: func() any {
|
||||
return &HybridSignature{
|
||||
return &QuasarSig{
|
||||
BLS: make([]byte, 0, 96),
|
||||
Corona: make([]byte, 0, 4096),
|
||||
}
|
||||
@@ -42,11 +42,11 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Hybrid implements parallel BLS+Corona threshold signing for PQ-safe consensus.
|
||||
// Signer implements parallel BLS+Corona threshold signing for PQ-safe consensus.
|
||||
// BLS provides fast classical threshold signatures.
|
||||
// Corona provides post-quantum threshold signatures based on Ring-LWE.
|
||||
// Both run in parallel to provide quantum-safe finality.
|
||||
type Hybrid struct {
|
||||
type signer struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
// Classical BLS threshold signing (via crypto/threshold)
|
||||
@@ -79,8 +79,8 @@ type Validator struct {
|
||||
Active bool
|
||||
}
|
||||
|
||||
// HybridConfig configures the dual threshold signing system.
|
||||
type HybridConfig struct {
|
||||
// SignerConfig configures the dual threshold signing system.
|
||||
type SignerConfig struct {
|
||||
Threshold int
|
||||
TotalParties int
|
||||
|
||||
@@ -101,13 +101,13 @@ type CoronaRound1State struct {
|
||||
Round1Data map[int]*coronaThreshold.Round1Data
|
||||
}
|
||||
|
||||
// NewHybrid creates a new hybrid consensus engine with basic BLS support.
|
||||
func NewHybrid(thresholdVal int) (*Hybrid, error) {
|
||||
// NewSigner creates a new signer engine with basic BLS support.
|
||||
func newSigner(thresholdVal int) (*signer, error) {
|
||||
if thresholdVal < 1 {
|
||||
return nil, errors.New("threshold must be at least 1")
|
||||
}
|
||||
|
||||
return &Hybrid{
|
||||
return &signer{
|
||||
blsKeys: make(map[string]*bls.SecretKey),
|
||||
blsPubKeys: make(map[string]*bls.PublicKey),
|
||||
blsSigners: make(map[string]threshold.Signer),
|
||||
@@ -118,13 +118,13 @@ func NewHybrid(thresholdVal int) (*Hybrid, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewHybridWithDualThreshold creates a hybrid engine with full dual threshold signing.
|
||||
func NewHybridWithDualThreshold(config HybridConfig) (*Hybrid, error) {
|
||||
// NewSignerWithDualThreshold creates a signer with full dual threshold signing.
|
||||
func newSignerWithDualThreshold(config SignerConfig) (*signer, error) {
|
||||
if config.Threshold < 1 {
|
||||
return nil, errors.New("threshold must be at least 1")
|
||||
}
|
||||
|
||||
h := &Hybrid{
|
||||
h := &signer{
|
||||
blsKeys: make(map[string]*bls.SecretKey),
|
||||
blsPubKeys: make(map[string]*bls.PublicKey),
|
||||
blsSigners: make(map[string]threshold.Signer),
|
||||
@@ -173,7 +173,7 @@ func NewHybridWithDualThreshold(config HybridConfig) (*Hybrid, error) {
|
||||
|
||||
// GenerateDualKeys generates both BLS and Corona threshold keys for an epoch.
|
||||
// Call this when the validator set changes.
|
||||
func GenerateDualKeys(t, n int) (*HybridConfig, error) {
|
||||
func GenerateDualKeys(t, n int) (*SignerConfig, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Generate BLS threshold keys
|
||||
@@ -211,7 +211,7 @@ func GenerateDualKeys(t, n int) (*HybridConfig, error) {
|
||||
coronaShareMap[id] = coronaShares[i]
|
||||
}
|
||||
|
||||
return &HybridConfig{
|
||||
return &SignerConfig{
|
||||
Threshold: t,
|
||||
TotalParties: n,
|
||||
BLSKeyShares: blsShareMap,
|
||||
@@ -227,18 +227,18 @@ func GenerateDualKeys(t, n int) (*HybridConfig, error) {
|
||||
|
||||
// CoronaRound1 performs Round 1 of Corona signing for a validator.
|
||||
// Returns Round1Data to broadcast to other validators.
|
||||
func (h *Hybrid) CoronaRound1(validatorID string, sessionID int, prfKey []byte) (*coronaThreshold.Round1Data, error) {
|
||||
h.mu.RLock()
|
||||
signer, exists := h.coronaSigners[validatorID]
|
||||
h.mu.RUnlock()
|
||||
func (s *signer) CoronaRound1(validatorID string, sessionID int, prfKey []byte) (*coronaThreshold.Round1Data, error) {
|
||||
s.mu.RLock()
|
||||
signer, exists := s.coronaSigners[validatorID]
|
||||
s.mu.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("validator %s not found in Corona signers", validatorID)
|
||||
}
|
||||
|
||||
// Get all signer indices
|
||||
signerIDs := make([]int, 0, len(h.coronaSigners))
|
||||
for _, s := range h.coronaShares {
|
||||
signerIDs := make([]int, 0, len(s.coronaSigners))
|
||||
for _, s := range s.coronaShares {
|
||||
signerIDs = append(signerIDs, s.Index)
|
||||
}
|
||||
|
||||
@@ -248,17 +248,17 @@ func (h *Hybrid) CoronaRound1(validatorID string, sessionID int, prfKey []byte)
|
||||
// CoronaRound2 performs Round 2 of Corona signing for a validator.
|
||||
// Requires collected Round 1 data from all signers.
|
||||
// Returns Round2Data to broadcast.
|
||||
func (h *Hybrid) CoronaRound2(validatorID string, sessionID int, message string, prfKey []byte, round1Data map[int]*coronaThreshold.Round1Data) (*coronaThreshold.Round2Data, error) {
|
||||
h.mu.RLock()
|
||||
signer, exists := h.coronaSigners[validatorID]
|
||||
h.mu.RUnlock()
|
||||
func (s *signer) CoronaRound2(validatorID string, sessionID int, message string, prfKey []byte, round1Data map[int]*coronaThreshold.Round1Data) (*coronaThreshold.Round2Data, error) {
|
||||
s.mu.RLock()
|
||||
signer, exists := s.coronaSigners[validatorID]
|
||||
s.mu.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("validator %s not found in Corona signers", validatorID)
|
||||
}
|
||||
|
||||
signerIDs := make([]int, 0, len(h.coronaSigners))
|
||||
for _, s := range h.coronaShares {
|
||||
signerIDs := make([]int, 0, len(s.coronaSigners))
|
||||
for _, s := range s.coronaShares {
|
||||
signerIDs = append(signerIDs, s.Index)
|
||||
}
|
||||
|
||||
@@ -267,10 +267,10 @@ func (h *Hybrid) CoronaRound2(validatorID string, sessionID int, message string,
|
||||
|
||||
// CoronaFinalize aggregates Round 2 data into the final signature.
|
||||
// Any validator can call this.
|
||||
func (h *Hybrid) CoronaFinalize(validatorID string, round2Data map[int]*coronaThreshold.Round2Data) (*coronaThreshold.Signature, error) {
|
||||
h.mu.RLock()
|
||||
signer, exists := h.coronaSigners[validatorID]
|
||||
h.mu.RUnlock()
|
||||
func (s *signer) CoronaFinalize(validatorID string, round2Data map[int]*coronaThreshold.Round2Data) (*coronaThreshold.Signature, error) {
|
||||
s.mu.RLock()
|
||||
signer, exists := s.coronaSigners[validatorID]
|
||||
s.mu.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("validator %s not found in Corona signers", validatorID)
|
||||
@@ -280,11 +280,11 @@ func (h *Hybrid) CoronaFinalize(validatorID string, round2Data map[int]*coronaTh
|
||||
}
|
||||
|
||||
// VerifyCoronaSignature verifies a Corona threshold signature.
|
||||
func (h *Hybrid) VerifyCoronaSignature(message string, sig *coronaThreshold.Signature) bool {
|
||||
if h.coronaGroupKey == nil || sig == nil {
|
||||
func (s *signer) VerifyCoronaSignature(message string, sig *coronaThreshold.Signature) bool {
|
||||
if s.coronaGroupKey == nil || sig == nil {
|
||||
return false
|
||||
}
|
||||
return coronaThreshold.Verify(h.coronaGroupKey, message, sig)
|
||||
return coronaThreshold.Verify(s.coronaGroupKey, message, sig)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -294,11 +294,11 @@ func (h *Hybrid) VerifyCoronaSignature(message string, sig *coronaThreshold.Sign
|
||||
// DualSignRound1 performs Round 1 of both BLS and Corona in parallel.
|
||||
// BLS: Computes signature share (single round)
|
||||
// Corona: Computes D matrix + MACs (Round 1 of 2)
|
||||
func (h *Hybrid) DualSignRound1(ctx context.Context, validatorID string, message []byte, sessionID int, prfKey []byte) (*HybridSignature, *coronaThreshold.Round1Data, error) {
|
||||
h.mu.RLock()
|
||||
blsSigner, hasBLS := h.blsSigners[validatorID]
|
||||
_, hasCorona := h.coronaSigners[validatorID]
|
||||
h.mu.RUnlock()
|
||||
func (s *signer) DualSignRound1(ctx context.Context, validatorID string, message []byte, sessionID int, prfKey []byte) (*QuasarSig, *coronaThreshold.Round1Data, error) {
|
||||
s.mu.RLock()
|
||||
blsSigner, hasBLS := s.blsSigners[validatorID]
|
||||
_, hasCorona := s.coronaSigners[validatorID]
|
||||
s.mu.RUnlock()
|
||||
|
||||
if !hasBLS || !hasCorona {
|
||||
return nil, nil, errors.New("validator not configured for dual signing")
|
||||
@@ -310,8 +310,8 @@ func (h *Hybrid) DualSignRound1(ctx context.Context, validatorID string, message
|
||||
var round1Data *coronaThreshold.Round1Data
|
||||
|
||||
// Get BLS signer indices
|
||||
blsIndices := make([]int, 0, len(h.blsSigners))
|
||||
for _, s := range h.blsSigners {
|
||||
blsIndices := make([]int, 0, len(s.blsSigners))
|
||||
for _, s := range s.blsSigners {
|
||||
blsIndices = append(blsIndices, s.Index())
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ func (h *Hybrid) DualSignRound1(ctx context.Context, validatorID string, message
|
||||
// Corona Round 1
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
round1Data, _ = h.CoronaRound1(validatorID, sessionID, prfKey)
|
||||
round1Data, _ = s.CoronaRound1(validatorID, sessionID, prfKey)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
@@ -335,7 +335,7 @@ func (h *Hybrid) DualSignRound1(ctx context.Context, validatorID string, message
|
||||
return nil, nil, fmt.Errorf("BLS signing failed: %w", blsErr)
|
||||
}
|
||||
|
||||
sig := &HybridSignature{
|
||||
sig := &QuasarSig{
|
||||
BLS: blsShare.Bytes(),
|
||||
ValidatorID: validatorID,
|
||||
IsThreshold: true,
|
||||
@@ -346,8 +346,8 @@ func (h *Hybrid) DualSignRound1(ctx context.Context, validatorID string, message
|
||||
}
|
||||
|
||||
// DualSignRound2 performs Round 2 of Corona (BLS is already done in Round1).
|
||||
func (h *Hybrid) DualSignRound2(validatorID string, sessionID int, message string, prfKey []byte, round1Data map[int]*coronaThreshold.Round1Data) (*coronaThreshold.Round2Data, error) {
|
||||
return h.CoronaRound2(validatorID, sessionID, message, prfKey, round1Data)
|
||||
func (s *signer) DualSignRound2(validatorID string, sessionID int, message string, prfKey []byte, round1Data map[int]*coronaThreshold.Round1Data) (*coronaThreshold.Round2Data, error) {
|
||||
return s.CoronaRound2(validatorID, sessionID, message, prfKey, round1Data)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -355,9 +355,9 @@ func (h *Hybrid) DualSignRound2(validatorID string, sessionID int, message strin
|
||||
// ============================================================================
|
||||
|
||||
// AddValidator adds a validator with legacy BLS key generation.
|
||||
func (h *Hybrid) AddValidator(id string, weight uint64) error {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
func (s *signer) AddValidator(id string, weight uint64) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
blsSK, err := bls.NewSecretKey()
|
||||
if err != nil {
|
||||
@@ -365,10 +365,10 @@ func (h *Hybrid) AddValidator(id string, weight uint64) error {
|
||||
}
|
||||
blsPK := blsSK.PublicKey()
|
||||
|
||||
h.blsKeys[id] = blsSK
|
||||
h.blsPubKeys[id] = blsPK
|
||||
s.blsKeys[id] = blsSK
|
||||
s.blsPubKeys[id] = blsPK
|
||||
|
||||
h.validators[id] = &Validator{
|
||||
s.validators[id] = &Validator{
|
||||
ID: id,
|
||||
BLSPubKey: blsPK,
|
||||
Weight: weight,
|
||||
@@ -379,29 +379,29 @@ func (h *Hybrid) AddValidator(id string, weight uint64) error {
|
||||
}
|
||||
|
||||
// SignMessage signs a message with BLS (legacy mode or threshold).
|
||||
func (h *Hybrid) SignMessage(validatorID string, message []byte) (*HybridSignature, error) {
|
||||
return h.SignMessageWithContext(context.Background(), validatorID, message)
|
||||
func (s *signer) SignMessage(validatorID string, message []byte) (*QuasarSig, error) {
|
||||
return s.SignMessageWithContext(context.Background(), validatorID, message)
|
||||
}
|
||||
|
||||
// SignMessageWithContext signs a message.
|
||||
func (h *Hybrid) SignMessageWithContext(ctx context.Context, validatorID string, message []byte) (*HybridSignature, error) {
|
||||
func (s *signer) SignMessageWithContext(ctx context.Context, validatorID string, message []byte) (*QuasarSig, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
sig := hybridSigPool.Get().(*HybridSignature)
|
||||
sig := sigPool.Get().(*QuasarSig)
|
||||
sig.BLS = sig.BLS[:0]
|
||||
sig.Corona = sig.Corona[:0]
|
||||
sig.ValidatorID = validatorID
|
||||
|
||||
// Check for threshold signer
|
||||
blsSigner, hasBLSSigner := h.blsSigners[validatorID]
|
||||
blsSigner, hasBLSSigner := s.blsSigners[validatorID]
|
||||
if hasBLSSigner {
|
||||
blsIndices := make([]int, 0, len(h.blsSigners))
|
||||
for _, s := range h.blsSigners {
|
||||
blsIndices := make([]int, 0, len(s.blsSigners))
|
||||
for _, s := range s.blsSigners {
|
||||
blsIndices = append(blsIndices, s.Index())
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@ func (h *Hybrid) SignMessageWithContext(ctx context.Context, validatorID string,
|
||||
}
|
||||
|
||||
// Fall back to legacy BLS
|
||||
blsSK, exists := h.blsKeys[validatorID]
|
||||
blsSK, exists := s.blsKeys[validatorID]
|
||||
if !exists {
|
||||
return nil, errors.New("validator not found")
|
||||
}
|
||||
@@ -433,36 +433,36 @@ func (h *Hybrid) SignMessageWithContext(ctx context.Context, validatorID string,
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
// ReleaseHybridSignature returns a HybridSignature to the pool.
|
||||
func ReleaseHybridSignature(sig *HybridSignature) {
|
||||
// ReleaseQuasarSig returns a QuasarSig to the pool.
|
||||
func ReleaseQuasarSig(sig *QuasarSig) {
|
||||
if sig == nil {
|
||||
return
|
||||
}
|
||||
sig.ValidatorID = ""
|
||||
sig.IsThreshold = false
|
||||
sig.SignerIndex = 0
|
||||
hybridSigPool.Put(sig)
|
||||
sigPool.Put(sig)
|
||||
}
|
||||
|
||||
// VerifyHybridSignature verifies a signature.
|
||||
func (h *Hybrid) VerifyHybridSignature(message []byte, sig *HybridSignature) bool {
|
||||
return h.VerifyHybridSignatureWithContext(context.Background(), message, sig)
|
||||
// VerifyQuasarSig verifies a signature.
|
||||
func (s *signer) VerifyQuasarSig(message []byte, sig *QuasarSig) bool {
|
||||
return s.VerifyQuasarSigWithContext(context.Background(), message, sig)
|
||||
}
|
||||
|
||||
// VerifyHybridSignatureWithContext verifies a signature.
|
||||
func (h *Hybrid) VerifyHybridSignatureWithContext(ctx context.Context, message []byte, sig *HybridSignature) bool {
|
||||
// VerifyQuasarSigWithContext verifies a signature.
|
||||
func (s *signer) VerifyQuasarSigWithContext(ctx context.Context, message []byte, sig *QuasarSig) bool {
|
||||
if ctx.Err() != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if sig.IsThreshold {
|
||||
return true // Shares verified during aggregation
|
||||
}
|
||||
|
||||
validator, exists := h.validators[sig.ValidatorID]
|
||||
validator, exists := s.validators[sig.ValidatorID]
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
@@ -476,38 +476,38 @@ func (h *Hybrid) VerifyHybridSignatureWithContext(ctx context.Context, message [
|
||||
}
|
||||
|
||||
// AggregateSignatures aggregates BLS threshold signature shares.
|
||||
func (h *Hybrid) AggregateSignatures(message []byte, signatures []*HybridSignature) (*AggregatedSignature, error) {
|
||||
return h.AggregateSignaturesWithContext(context.Background(), message, signatures)
|
||||
func (s *signer) AggregateSignatures(message []byte, signatures []*QuasarSig) (*AggregatedSignature, error) {
|
||||
return s.AggregateSignaturesWithContext(context.Background(), message, signatures)
|
||||
}
|
||||
|
||||
// AggregateSignaturesWithContext aggregates signatures.
|
||||
func (h *Hybrid) AggregateSignaturesWithContext(ctx context.Context, message []byte, signatures []*HybridSignature) (*AggregatedSignature, error) {
|
||||
func (s *signer) AggregateSignaturesWithContext(ctx context.Context, message []byte, signatures []*QuasarSig) (*AggregatedSignature, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if len(signatures) < h.threshold {
|
||||
return nil, fmt.Errorf("insufficient signatures: %d < %d", len(signatures), h.threshold)
|
||||
if len(signatures) < s.threshold {
|
||||
return nil, fmt.Errorf("insufficient signatures: %d < %d", len(signatures), s.threshold)
|
||||
}
|
||||
|
||||
// Check for threshold mode
|
||||
if len(signatures) > 0 && signatures[0].IsThreshold && h.blsAggregator != nil {
|
||||
if len(signatures) > 0 && signatures[0].IsThreshold && s.blsAggregator != nil {
|
||||
blsShares := make([]threshold.SignatureShare, 0, len(signatures))
|
||||
|
||||
for _, sig := range signatures {
|
||||
if len(sig.BLS) > 0 {
|
||||
share, err := h.blsScheme.ParseSignatureShare(sig.BLS)
|
||||
share, err := s.blsScheme.ParseSignatureShare(sig.BLS)
|
||||
if err == nil {
|
||||
blsShares = append(blsShares, share)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(blsShares) >= h.threshold {
|
||||
blsAggSig, err := h.blsAggregator.Aggregate(ctx, message, blsShares, nil)
|
||||
if len(blsShares) >= s.threshold {
|
||||
blsAggSig, err := s.blsAggregator.Aggregate(ctx, message, blsShares, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("BLS aggregation failed: %w", err)
|
||||
}
|
||||
@@ -552,26 +552,26 @@ func (h *Hybrid) AggregateSignaturesWithContext(ctx context.Context, message []b
|
||||
}
|
||||
|
||||
// VerifyAggregatedSignature verifies an aggregated signature.
|
||||
func (h *Hybrid) VerifyAggregatedSignature(message []byte, aggSig *AggregatedSignature) bool {
|
||||
return h.VerifyAggregatedSignatureWithContext(context.Background(), message, aggSig)
|
||||
func (s *signer) VerifyAggregatedSignature(message []byte, aggSig *AggregatedSignature) bool {
|
||||
return s.VerifyAggregatedSignatureWithContext(context.Background(), message, aggSig)
|
||||
}
|
||||
|
||||
// VerifyAggregatedSignatureWithContext verifies an aggregated signature.
|
||||
func (h *Hybrid) VerifyAggregatedSignatureWithContext(ctx context.Context, message []byte, aggSig *AggregatedSignature) bool {
|
||||
func (s *signer) VerifyAggregatedSignatureWithContext(ctx context.Context, message []byte, aggSig *AggregatedSignature) bool {
|
||||
if ctx.Err() != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if aggSig.SignerCount < h.threshold {
|
||||
if aggSig.SignerCount < s.threshold {
|
||||
return false
|
||||
}
|
||||
|
||||
if aggSig.IsThreshold {
|
||||
if h.blsVerifier != nil && len(aggSig.BLSAggregated) > 0 {
|
||||
return h.blsVerifier.VerifyBytes(message, aggSig.BLSAggregated)
|
||||
if s.blsVerifier != nil && len(aggSig.BLSAggregated) > 0 {
|
||||
return s.blsVerifier.VerifyBytes(message, aggSig.BLSAggregated)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -590,7 +590,7 @@ func (h *Hybrid) VerifyAggregatedSignatureWithContext(ctx context.Context, messa
|
||||
}()
|
||||
|
||||
for _, validatorID := range aggSig.ValidatorIDs {
|
||||
validator, exists := h.validators[validatorID]
|
||||
validator, exists := s.validators[validatorID]
|
||||
if !exists || !validator.Active {
|
||||
return false
|
||||
}
|
||||
@@ -605,8 +605,8 @@ func (h *Hybrid) VerifyAggregatedSignatureWithContext(ctx context.Context, messa
|
||||
return bls.Verify(aggPubKey, blsSig, message)
|
||||
}
|
||||
|
||||
// HybridSignature contains BLS and optionally Corona signature data.
|
||||
type HybridSignature struct {
|
||||
// QuasarSig contains BLS and optionally Corona signature data.
|
||||
type QuasarSig struct {
|
||||
BLS []byte
|
||||
Corona []byte
|
||||
ValidatorID string
|
||||
@@ -624,12 +624,12 @@ type AggregatedSignature struct {
|
||||
}
|
||||
|
||||
// GetActiveValidatorCount returns the number of active validators.
|
||||
func (h *Hybrid) GetActiveValidatorCount() int {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
func (s *signer) GetActiveValidatorCount() int {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
count := 0
|
||||
for _, v := range h.validators {
|
||||
for _, v := range s.validators {
|
||||
if v.Active {
|
||||
count++
|
||||
}
|
||||
@@ -638,18 +638,18 @@ func (h *Hybrid) GetActiveValidatorCount() int {
|
||||
}
|
||||
|
||||
// GetThreshold returns the consensus threshold.
|
||||
func (h *Hybrid) GetThreshold() int {
|
||||
return h.threshold
|
||||
func (s *signer) GetThreshold() int {
|
||||
return s.threshold
|
||||
}
|
||||
|
||||
// IsThresholdMode returns true if BLS threshold signing is enabled.
|
||||
func (h *Hybrid) IsThresholdMode() bool {
|
||||
return h.blsScheme != nil
|
||||
func (s *signer) IsThresholdMode() bool {
|
||||
return s.blsScheme != nil
|
||||
}
|
||||
|
||||
// IsDualThresholdMode returns true if both BLS and Corona are enabled.
|
||||
func (h *Hybrid) IsDualThresholdMode() bool {
|
||||
return h.blsScheme != nil && h.coronaGroupKey != nil
|
||||
func (s *signer) IsDualThresholdMode() bool {
|
||||
return s.blsScheme != nil && s.coronaGroupKey != nil
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -665,8 +665,8 @@ type ThresholdConfig struct {
|
||||
GroupKey threshold.PublicKey
|
||||
}
|
||||
|
||||
// NewHybridWithThresholdConfig creates a hybrid engine from ThresholdConfig.
|
||||
func NewHybridWithThresholdConfig(config ThresholdConfig) (*Hybrid, error) {
|
||||
// newSignerWithThresholdConfig creates a signer from ThresholdConfig.
|
||||
func newSignerWithThresholdConfig(config ThresholdConfig) (*signer, error) {
|
||||
if config.Threshold < 1 {
|
||||
return nil, errors.New("threshold must be at least 1")
|
||||
}
|
||||
@@ -676,7 +676,7 @@ func NewHybridWithThresholdConfig(config ThresholdConfig) (*Hybrid, error) {
|
||||
return nil, fmt.Errorf("failed to get threshold scheme: %w", err)
|
||||
}
|
||||
|
||||
h := &Hybrid{
|
||||
h := &signer{
|
||||
blsKeys: make(map[string]*bls.SecretKey),
|
||||
blsPubKeys: make(map[string]*bls.PublicKey),
|
||||
blsSigners: make(map[string]threshold.Signer),
|
||||
@@ -710,9 +710,9 @@ func NewHybridWithThresholdConfig(config ThresholdConfig) (*Hybrid, error) {
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// NewHybridWithThreshold is an alias for NewHybridWithDualThreshold.
|
||||
func NewHybridWithThreshold(config HybridConfig) (*Hybrid, error) {
|
||||
return NewHybridWithDualThreshold(config)
|
||||
// newSignerWithThreshold is an alias for newSignerWithDualThreshold.
|
||||
func newSignerWithThreshold(config SignerConfig) (*signer, error) {
|
||||
return newSignerWithDualThreshold(config)
|
||||
}
|
||||
|
||||
// GenerateThresholdKeys generates threshold keys for a single scheme.
|
||||
@@ -734,32 +734,32 @@ func GenerateThresholdKeys(schemeID threshold.SchemeID, t, n int) ([]threshold.K
|
||||
}
|
||||
|
||||
// GenerateDualThresholdKeys generates both BLS and Corona keys (backward compat).
|
||||
func GenerateDualThresholdKeys(t, n int) (*HybridConfig, error) {
|
||||
func GenerateDualThresholdKeys(t, n int) (*SignerConfig, error) {
|
||||
return GenerateDualKeys(t, n)
|
||||
}
|
||||
|
||||
// ThresholdScheme returns the BLS threshold scheme.
|
||||
func (h *Hybrid) ThresholdScheme() threshold.Scheme {
|
||||
return h.blsScheme
|
||||
func (s *signer) ThresholdScheme() threshold.Scheme {
|
||||
return s.blsScheme
|
||||
}
|
||||
|
||||
// ThresholdGroupKey returns the BLS group public key.
|
||||
func (h *Hybrid) ThresholdGroupKey() threshold.PublicKey {
|
||||
return h.blsGroupKey
|
||||
func (s *signer) ThresholdGroupKey() threshold.PublicKey {
|
||||
return s.blsGroupKey
|
||||
}
|
||||
|
||||
// SignMessageThreshold signs using BLS threshold.
|
||||
func (h *Hybrid) SignMessageThreshold(ctx context.Context, validatorID string, message []byte) (threshold.SignatureShare, error) {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
func (s *signer) SignMessageThreshold(ctx context.Context, validatorID string, message []byte) (threshold.SignatureShare, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
signer, exists := h.blsSigners[validatorID]
|
||||
signer, exists := s.blsSigners[validatorID]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("validator %s not found in BLS signers", validatorID)
|
||||
}
|
||||
|
||||
signerIndices := make([]int, 0, len(h.blsSigners))
|
||||
for _, s := range h.blsSigners {
|
||||
signerIndices := make([]int, 0, len(s.blsSigners))
|
||||
for _, s := range s.blsSigners {
|
||||
signerIndices = append(signerIndices, s.Index())
|
||||
}
|
||||
|
||||
@@ -767,62 +767,62 @@ func (h *Hybrid) SignMessageThreshold(ctx context.Context, validatorID string, m
|
||||
}
|
||||
|
||||
// AggregateThresholdSignatures aggregates BLS threshold shares.
|
||||
func (h *Hybrid) AggregateThresholdSignatures(ctx context.Context, message []byte, shares []threshold.SignatureShare) (threshold.Signature, error) {
|
||||
if h.blsAggregator == nil {
|
||||
func (s *signer) AggregateThresholdSignatures(ctx context.Context, message []byte, shares []threshold.SignatureShare) (threshold.Signature, error) {
|
||||
if s.blsAggregator == nil {
|
||||
return nil, errors.New("BLS aggregator not initialized")
|
||||
}
|
||||
|
||||
if len(shares) <= h.threshold {
|
||||
return nil, fmt.Errorf("insufficient shares: need at least %d, got %d", h.threshold+1, len(shares))
|
||||
if len(shares) <= s.threshold {
|
||||
return nil, fmt.Errorf("insufficient shares: need at least %d, got %d", s.threshold+1, len(shares))
|
||||
}
|
||||
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return h.blsAggregator.Aggregate(ctx, message, shares, nil)
|
||||
return s.blsAggregator.Aggregate(ctx, message, shares, nil)
|
||||
}
|
||||
|
||||
// VerifyThresholdSignature verifies a BLS threshold signature.
|
||||
func (h *Hybrid) VerifyThresholdSignature(message []byte, sig threshold.Signature) bool {
|
||||
if h.blsVerifier == nil {
|
||||
func (s *signer) VerifyThresholdSignature(message []byte, sig threshold.Signature) bool {
|
||||
if s.blsVerifier == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
return h.blsVerifier.Verify(message, sig)
|
||||
return s.blsVerifier.Verify(message, sig)
|
||||
}
|
||||
|
||||
// VerifyThresholdSignatureBytes verifies serialized BLS threshold signature.
|
||||
func (h *Hybrid) VerifyThresholdSignatureBytes(message, sig []byte) bool {
|
||||
if h.blsVerifier == nil {
|
||||
func (s *signer) VerifyThresholdSignatureBytes(message, sig []byte) bool {
|
||||
if s.blsVerifier == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
return h.blsVerifier.VerifyBytes(message, sig)
|
||||
return s.blsVerifier.VerifyBytes(message, sig)
|
||||
}
|
||||
|
||||
// AddValidatorThreshold adds a validator with BLS threshold key share.
|
||||
func (h *Hybrid) AddValidatorThreshold(id string, keyShare threshold.KeyShare, weight uint64) error {
|
||||
if h.blsScheme == nil {
|
||||
func (s *signer) AddValidatorThreshold(id string, keyShare threshold.KeyShare, weight uint64) error {
|
||||
if s.blsScheme == nil {
|
||||
return errors.New("BLS threshold scheme not initialized")
|
||||
}
|
||||
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
signer, err := h.blsScheme.NewSigner(keyShare)
|
||||
signer, err := s.blsScheme.NewSigner(keyShare)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create signer: %w", err)
|
||||
}
|
||||
|
||||
h.blsSigners[id] = signer
|
||||
s.blsSigners[id] = signer
|
||||
|
||||
h.validators[id] = &Validator{
|
||||
s.validators[id] = &Validator{
|
||||
ID: id,
|
||||
Weight: weight,
|
||||
Active: true,
|
||||
|
||||
@@ -96,8 +96,8 @@ func BenchmarkBLSSigningVariableMessageSize(b *testing.B) {
|
||||
// Hybrid Signature Benchmarks (BLS + ML-DSA/Corona)
|
||||
// =============================================================================
|
||||
|
||||
func BenchmarkHybridSignatureCreation(b *testing.B) {
|
||||
hybrid, err := NewHybrid(1)
|
||||
func BenchmarkQuasarSigCreation(b *testing.B) {
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -118,8 +118,8 @@ func BenchmarkHybridSignatureCreation(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHybridSignatureVerification(b *testing.B) {
|
||||
hybrid, err := NewHybrid(1)
|
||||
func BenchmarkQuasarSigVerification(b *testing.B) {
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -137,15 +137,15 @@ func BenchmarkHybridSignatureVerification(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if !hybrid.VerifyHybridSignature(message, sig) {
|
||||
if !hybrid.VerifyQuasarSig(message, sig) {
|
||||
b.Fatal("verification failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHybridSignatureVariableMessageSize(b *testing.B) {
|
||||
func BenchmarkQuasarSigVariableMessageSize(b *testing.B) {
|
||||
sizes := []int{32, 64, 128, 256, 512, 1024}
|
||||
hybrid, err := NewHybrid(1)
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -179,7 +179,7 @@ func BenchmarkHybridSignatureVariableMessageSize(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if !hybrid.VerifyHybridSignature(message, sig) {
|
||||
if !hybrid.VerifyQuasarSig(message, sig) {
|
||||
b.Fatal("verification failed")
|
||||
}
|
||||
}
|
||||
@@ -268,12 +268,12 @@ func BenchmarkBLSAggregatedVerification(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHybridAggregation(b *testing.B) {
|
||||
func BenchmarkSignerAggregation(b *testing.B) {
|
||||
counts := []int{4, 8, 16, 32}
|
||||
|
||||
for _, count := range counts {
|
||||
b.Run(fmt.Sprintf("%d_validators", count), func(b *testing.B) {
|
||||
hybrid, err := NewHybrid(count)
|
||||
hybrid, err := NewSigner(count)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -282,7 +282,7 @@ func BenchmarkHybridAggregation(b *testing.B) {
|
||||
rand.Read(message)
|
||||
|
||||
// Add validators and collect signatures
|
||||
sigs := make([]*HybridSignature, count)
|
||||
sigs := make([]*QuasarSig, count)
|
||||
for i := 0; i < count; i++ {
|
||||
id := fmt.Sprintf("validator-%d", i)
|
||||
if err := hybrid.AddValidator(id, 100); err != nil {
|
||||
@@ -307,12 +307,12 @@ func BenchmarkHybridAggregation(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHybridAggregatedVerification(b *testing.B) {
|
||||
func BenchmarkSignerAggregatedVerification(b *testing.B) {
|
||||
counts := []int{4, 8, 16, 32}
|
||||
|
||||
for _, count := range counts {
|
||||
b.Run(fmt.Sprintf("%d_validators", count), func(b *testing.B) {
|
||||
hybrid, err := NewHybrid(count)
|
||||
hybrid, err := NewSigner(count)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -321,7 +321,7 @@ func BenchmarkHybridAggregatedVerification(b *testing.B) {
|
||||
rand.Read(message)
|
||||
|
||||
// Add validators and collect signatures
|
||||
sigs := make([]*HybridSignature, count)
|
||||
sigs := make([]*QuasarSig, count)
|
||||
for i := 0; i < count; i++ {
|
||||
id := fmt.Sprintf("validator-%d", i)
|
||||
if err := hybrid.AddValidator(id, 100); err != nil {
|
||||
@@ -369,7 +369,7 @@ func BenchmarkThresholdRound(b *testing.B) {
|
||||
|
||||
for _, tc := range thresholds {
|
||||
b.Run(fmt.Sprintf("n%d_t%d", tc.n, tc.t), func(b *testing.B) {
|
||||
hybrid, err := NewHybrid(tc.t)
|
||||
hybrid, err := NewSigner(tc.t)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -391,7 +391,7 @@ func BenchmarkThresholdRound(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Collect threshold signatures (simulate a round)
|
||||
sigs := make([]*HybridSignature, tc.t)
|
||||
sigs := make([]*QuasarSig, tc.t)
|
||||
for j := 0; j < tc.t; j++ {
|
||||
sig, err := hybrid.SignMessage(ids[j], message)
|
||||
if err != nil {
|
||||
@@ -421,7 +421,7 @@ func BenchmarkThresholdSigningOnly(b *testing.B) {
|
||||
|
||||
for _, t := range thresholds {
|
||||
b.Run(fmt.Sprintf("%d_signers", t), func(b *testing.B) {
|
||||
hybrid, err := NewHybrid(t)
|
||||
hybrid, err := NewSigner(t)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -533,93 +533,9 @@ func BenchmarkMLDSAVerification(b *testing.B) {
|
||||
// Corona (Stub) Benchmarks
|
||||
// =============================================================================
|
||||
|
||||
func BenchmarkCoronaKeyGen(b *testing.B) {
|
||||
seed := make([]byte, 32)
|
||||
rand.Read(seed)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, err := KeyGen(seed)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCoronaPrecompute(b *testing.B) {
|
||||
sk := make([]byte, 32)
|
||||
rand.Read(sk)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := Precompute(sk)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCoronaQuickSign(b *testing.B) {
|
||||
sk := make([]byte, 32)
|
||||
rand.Read(sk)
|
||||
precomp, err := Precompute(sk)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
message := make([]byte, 32)
|
||||
rand.Read(message)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := QuickSign(precomp, message)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCoronaAggregate(b *testing.B) {
|
||||
counts := []int{4, 8, 16, 32, 64}
|
||||
|
||||
for _, count := range counts {
|
||||
b.Run(fmt.Sprintf("%d_shares", count), func(b *testing.B) {
|
||||
shares := make([]Share, count)
|
||||
for i := 0; i < count; i++ {
|
||||
shares[i] = make([]byte, 32)
|
||||
rand.Read(shares[i])
|
||||
}
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := Aggregate(shares)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCoronaVerify(b *testing.B) {
|
||||
pk := make([]byte, 32)
|
||||
rand.Read(pk)
|
||||
message := make([]byte, 32)
|
||||
rand.Read(message)
|
||||
cert := make([]byte, 32)
|
||||
rand.Read(cert)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if !Verify(pk, message, cert) {
|
||||
b.Fatal("verification failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE: Corona benchmarks are in the real corona package at
|
||||
// github.com/luxfi/corona/threshold. The quasar package uses the real
|
||||
// implementation via the Signer type in quasar.go.
|
||||
|
||||
// =============================================================================
|
||||
// End-to-End Quasar Benchmarks
|
||||
@@ -630,7 +546,11 @@ func BenchmarkQuasarBlockProcessing(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if err := qa.hybridConsensus.AddValidator("validator1", 100); err != nil {
|
||||
// Need at least 2 validators for epoch manager
|
||||
if _, err := qa.AddValidator("validator1", 100); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if _, err := qa.AddValidator("validator2", 100); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -680,7 +600,7 @@ func BenchmarkQuasarValidatorAddition(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
hybrid, err := NewHybrid(1)
|
||||
hybrid, err := NewSigner(1)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -57,13 +57,13 @@ func (u *unarySnowball) RecordPoll(voteCount, threshold int) bool {
|
||||
|
||||
// binaryTreeSnowball tracks binary choice at tree branch point
|
||||
type binaryTreeSnowball struct {
|
||||
preference int
|
||||
prefStrength [2]int
|
||||
confidence int
|
||||
finalized bool
|
||||
alphaPreference int
|
||||
alphaConfidence int
|
||||
beta int
|
||||
preference int
|
||||
prefStrength [2]int
|
||||
confidence int
|
||||
finalized bool
|
||||
alphaPreference int
|
||||
alphaConfidence int
|
||||
beta int
|
||||
}
|
||||
|
||||
func newBinaryTreeSnowball(alphaPreference, alphaConfidence, beta int) *binaryTreeSnowball {
|
||||
@@ -114,7 +114,7 @@ type consensusTree struct {
|
||||
preference [32]byte
|
||||
finalized bool
|
||||
// Track choice to branch mapping for binary snowball
|
||||
choices [2][32]byte // choices[0] = first choice, choices[1] = second choice
|
||||
choices [2][32]byte // choices[0] = first choice, choices[1] = second choice
|
||||
numChoices int
|
||||
}
|
||||
|
||||
@@ -643,7 +643,7 @@ func TestQuasarThroughput(t *testing.T) {
|
||||
func TestHybridConsensusBasic(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
hybrid, err := newHybridConsensus(2)
|
||||
hybrid, err := newCertifier(2)
|
||||
require.NoError(err)
|
||||
|
||||
// Add validators
|
||||
@@ -676,7 +676,7 @@ func TestHybridConsensusBasic(t *testing.T) {
|
||||
func TestHybridConsensusValidatorChurn(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
hybrid, err := newHybridConsensus(2)
|
||||
hybrid, err := newCertifier(2)
|
||||
require.NoError(err)
|
||||
|
||||
hybrid.AddValidator("v1", 100)
|
||||
|
||||
+50
-18
@@ -69,26 +69,58 @@ type Stats struct {
|
||||
Uptime time.Duration // Time since start
|
||||
}
|
||||
|
||||
// Core is an alias for the aggregator implementation.
|
||||
// Use NewCore() to create a new instance.
|
||||
type Core = Quasar
|
||||
// BLSSignature contains a classical BLS threshold signature.
|
||||
// Fast path for consensus - used in parallel with CoronaSignature.
|
||||
type BLSSignature struct {
|
||||
Signature []byte // BLS signature bytes
|
||||
ValidatorID string // Signing validator
|
||||
IsThreshold bool // True if threshold signature
|
||||
SignerIndex int // Signer index in committee
|
||||
}
|
||||
|
||||
// QuasarCore is a deprecated alias for backward compatibility.
|
||||
// Deprecated: Use Quasar or Core instead.
|
||||
type QuasarCore = Quasar
|
||||
// CoronaSignature contains a post-quantum Corona threshold signature.
|
||||
// Quantum-safe path - used in parallel with BLSSignature.
|
||||
type CoronaSignature struct {
|
||||
Signature []byte // Corona (Ring-LWE) signature bytes
|
||||
ValidatorID string // Signing validator
|
||||
IsThreshold bool // True if threshold signature
|
||||
SignerIndex int // Signer index in committee
|
||||
Round int // Corona protocol round (1 or 2)
|
||||
}
|
||||
|
||||
// PChain is a deprecated alias for backward compatibility.
|
||||
// Deprecated: Use BLS instead.
|
||||
type PChain = BLS
|
||||
// QuasarSignature bundles BLS + Corona for complete quantum finality.
|
||||
// Both signatures are collected in parallel.
|
||||
type QuasarSignature struct {
|
||||
BLS *BLSSignature // Classical fast path
|
||||
Corona *CoronaSignature // Quantum-safe path
|
||||
}
|
||||
|
||||
// NewPChain is a deprecated alias for backward compatibility.
|
||||
// Deprecated: Use NewBLS instead.
|
||||
var NewPChain = NewBLS
|
||||
// CoronaRound1Data contains the output of Corona Round 1.
|
||||
type CoronaRound1Data struct {
|
||||
PartyID int
|
||||
}
|
||||
|
||||
// QuasarHybridConsensus is a deprecated alias for backward compatibility.
|
||||
// Deprecated: Use Hybrid instead.
|
||||
type QuasarHybridConsensus = Hybrid
|
||||
// Signer is the exported interface for the quantum signing engine.
|
||||
// It provides parallel BLS+Corona threshold signing for PQ-safe consensus.
|
||||
type Signer = signer
|
||||
|
||||
// NewQuasarHybridConsensus is a deprecated alias for backward compatibility.
|
||||
// Deprecated: Use NewHybrid instead.
|
||||
var NewQuasarHybridConsensus = NewHybrid
|
||||
// NewSigner creates a new quantum signer with the given threshold.
|
||||
func NewSigner(threshold int) (*Signer, error) {
|
||||
return newSigner(threshold)
|
||||
}
|
||||
|
||||
// NewSignerWithConfig creates a new quantum signer with full configuration.
|
||||
func NewSignerWithConfig(config SignerConfig) (*Signer, error) {
|
||||
return newSignerWithDualThreshold(config)
|
||||
}
|
||||
|
||||
// NewSignerWithDualThreshold creates a new quantum signer with dual threshold configuration.
|
||||
// This is an alias for NewSignerWithConfig for backward compatibility.
|
||||
func NewSignerWithDualThreshold(config SignerConfig) (*Signer, error) {
|
||||
return NewSignerWithConfig(config)
|
||||
}
|
||||
|
||||
// NewSignerWithThresholdConfig creates a signer from ThresholdConfig.
|
||||
func NewSignerWithThresholdConfig(config ThresholdConfig) (*Signer, error) {
|
||||
return newSignerWithThresholdConfig(config)
|
||||
}
|
||||
|
||||
@@ -267,9 +267,17 @@ func (v *VerkleWitness) cacheWitness(witness *WitnessProof) {
|
||||
}
|
||||
}
|
||||
|
||||
// verifyBLSAggregate verifies BLS aggregate signature for fallback verification.
|
||||
// NOTE: This is a placeholder for the VerkleWitness slow path. Since the witness
|
||||
// assumes PQ finality (via checkPQFinality), this path is rarely exercised.
|
||||
// For real BLS verification, see the Signer.VerifyQuasarSig in quasar.go which
|
||||
// uses github.com/luxfi/crypto/bls for actual signature verification.
|
||||
func (v *VerkleWitness) verifyBLSAggregate(aggSig []byte, validatorSet []byte) error {
|
||||
// Placeholder for BLS aggregate verification
|
||||
// In production, this would verify against the validator set
|
||||
// With PQ finality assumption, this path is rarely used.
|
||||
// Real verification happens in Signer.VerifyQuasarSig.
|
||||
if len(aggSig) == 0 {
|
||||
return errors.New("empty aggregate signature")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,12 @@ const (
|
||||
// - confidence -> consecutive rounds at threshold
|
||||
// - finalized -> decided
|
||||
type binarySnowball struct {
|
||||
alphaPreference int // minimum votes to update preference
|
||||
alphaConfidence int // minimum votes to increment confidence
|
||||
beta int // consecutive rounds needed for finalization
|
||||
preference int // current preference (0 or 1)
|
||||
alphaPreference int // minimum votes to update preference
|
||||
alphaConfidence int // minimum votes to increment confidence
|
||||
beta int // consecutive rounds needed for finalization
|
||||
preference int // current preference (0 or 1)
|
||||
prefStrength [2]int // accumulated votes per choice
|
||||
confidence int // consecutive successful polls
|
||||
confidence int // consecutive successful polls
|
||||
finalized bool
|
||||
}
|
||||
|
||||
@@ -429,9 +429,9 @@ func TestWaveSnowballDecisionPersistence(t *testing.T) {
|
||||
// TestWaveParameterValidation tests configuration constraints
|
||||
func TestWaveParameterValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg Config
|
||||
valid bool
|
||||
name string
|
||||
cfg Config
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
name: "valid minimal",
|
||||
|
||||
@@ -62,7 +62,7 @@ const (
|
||||
type HonestNode struct {
|
||||
id string
|
||||
agent *ai.Agent[ai.BlockData]
|
||||
quasar *quasar.QuasarCore
|
||||
quasar *quasar.Quasar
|
||||
photon *photon.UniformEmitter
|
||||
votes map[ids.ID]float64
|
||||
preference ids.ID
|
||||
|
||||
@@ -11,20 +11,15 @@ import (
|
||||
func TestAIConsensusIntegration(t *testing.T) {
|
||||
t.Run("AI Agent with Quasar Consensus", func(t *testing.T) {
|
||||
// Create Quasar hybrid consensus
|
||||
consensus, err := quasar.NewQuasarHybridConsensus(2)
|
||||
consensus, err := quasar.NewQuasar(2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create consensus: %v", err)
|
||||
}
|
||||
|
||||
// Add validators
|
||||
err = consensus.AddValidator("validator1", 100)
|
||||
// Initialize validators (requires threshold < validator count)
|
||||
err = consensus.InitializeValidators([]string{"validator1", "validator2", "validator3"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
}
|
||||
|
||||
err = consensus.AddValidator("validator2", 100)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add validator: %v", err)
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
// Create a simple model that implements BasicModel
|
||||
@@ -96,7 +91,7 @@ func TestAIConsensusIntegration(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify signature
|
||||
if !consensus.VerifyHybridSignature(message, sig) {
|
||||
if !consensus.VerifyQuasarSig(message, sig) {
|
||||
t.Fatal("Signature verification failed")
|
||||
}
|
||||
|
||||
@@ -106,7 +101,7 @@ func TestAIConsensusIntegration(t *testing.T) {
|
||||
t.Fatalf("Failed to sign with validator2: %v", err)
|
||||
}
|
||||
|
||||
sigs := []*quasar.HybridSignature{sig, sig2}
|
||||
sigs := []*quasar.QuasarSig{sig, sig2}
|
||||
aggSig, err := consensus.AggregateSignatures(message, sigs)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to aggregate signatures: %v", err)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/luxfi/consensus/core/choices"
|
||||
"github.com/luxfi/consensus/test/helpers"
|
||||
consensustest "github.com/luxfi/consensus/test/helpers"
|
||||
"github.com/luxfi/consensus/types/bag"
|
||||
"github.com/luxfi/consensus/utils/set"
|
||||
"github.com/luxfi/ids"
|
||||
|
||||
@@ -706,16 +706,14 @@ func TestAIConsensusRandomized(t *testing.T) {
|
||||
// ==================== Hybrid Consensus Tests ====================
|
||||
|
||||
func TestHybridConsensusRandomized(t *testing.T) {
|
||||
quasarConsensus, err := quasar.NewQuasarHybridConsensus(3)
|
||||
quasarConsensus, err := quasar.NewQuasar(3)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create Quasar consensus: %v", err)
|
||||
}
|
||||
|
||||
validators := []string{"val1", "val2", "val3"}
|
||||
for _, v := range validators {
|
||||
if err := quasarConsensus.AddValidator(v, 100); err != nil {
|
||||
t.Fatalf("Failed to add validator %s: %v", v, err)
|
||||
}
|
||||
validators := []string{"val1", "val2", "val3", "val4"}
|
||||
if err := quasarConsensus.InitializeValidators(validators); err != nil {
|
||||
t.Fatalf("Failed to initialize validators: %v", err)
|
||||
}
|
||||
|
||||
rng := NewMersenneTwister(123)
|
||||
@@ -733,7 +731,7 @@ func TestHybridConsensusRandomized(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
if quasarConsensus.VerifyHybridSignature(message, sig) {
|
||||
if quasarConsensus.VerifyQuasarSig(message, sig) {
|
||||
successfulSigs++
|
||||
} else {
|
||||
t.Errorf("Signature verification failed for message %d", i)
|
||||
|
||||
@@ -734,6 +734,6 @@ func (l *testListener) OnValidatorLightChanged(netID ids.ID, nodeID ids.NodeID,
|
||||
|
||||
type testSetListener struct{}
|
||||
|
||||
func (l *testSetListener) OnValidatorAdded(nodeID ids.NodeID, light uint64) {}
|
||||
func (l *testSetListener) OnValidatorRemoved(nodeID ids.NodeID, light uint64) {}
|
||||
func (l *testSetListener) OnValidatorAdded(nodeID ids.NodeID, light uint64) {}
|
||||
func (l *testSetListener) OnValidatorRemoved(nodeID ids.NodeID, light uint64) {}
|
||||
func (l *testSetListener) OnValidatorLightChanged(nodeID ids.NodeID, oldLight, newLight uint64) {}
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/ids"
|
||||
mathset "github.com/luxfi/math/set"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -72,7 +72,7 @@ func TestFlattenValidatorSetNoPubKey(t *testing.T) {
|
||||
|
||||
result, err := FlattenValidatorSet(vdrSet)
|
||||
require.NoError(err)
|
||||
require.Empty(result.Validators) // No validators with public keys
|
||||
require.Empty(result.Validators) // No validators with public keys
|
||||
require.Equal(uint64(100), result.TotalWeight) // But weight still counted
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user