mirror of
https://github.com/luxfi/crypto.git
synced 2026-07-27 01:54:50 +00:00
security(crypto): remove fail-open aggregated verifier
crypto/aggregated ThresholdSignature.Verify ignored its message argument and returned true for any non-empty []byte — a method named Verify that verifies nothing. Zero importers workspace-wide, so it was never reachable; removing it before it ever could be. Real threshold verification lives in luxfi/threshold. Verified: CGO_ENABLED=0 go build ./... clean, no remaining references.
This commit is contained in:
@@ -33,3 +33,4 @@ target/
|
|||||||
test-results/
|
test-results/
|
||||||
tmp/
|
tmp/
|
||||||
*.eco
|
*.eco
|
||||||
|
*.test
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
||||||
// See the file LICENSE for licensing terms.
|
|
||||||
|
|
||||||
package aggregated
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/luxfi/crypto/bls"
|
|
||||||
"github.com/luxfi/crypto/cggmp21"
|
|
||||||
"github.com/luxfi/ids"
|
|
||||||
log "github.com/luxfi/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BLSManager manages BLS signature operations
|
|
||||||
type BLSManager struct {
|
|
||||||
log log.Logger
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBLSManager creates a new BLS manager
|
|
||||||
func NewBLSManager(log log.Logger) *BLSManager {
|
|
||||||
return &BLSManager{
|
|
||||||
log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateKeyPair generates a new BLS key pair
|
|
||||||
func (m *BLSManager) CreateKeyPair() (*bls.SecretKey, *bls.PublicKey, error) {
|
|
||||||
sk, err := bls.NewSecretKey()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pk := sk.PublicKey()
|
|
||||||
return sk, pk, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign creates a BLS signature
|
|
||||||
func (m *BLSManager) Sign(sk *bls.SecretKey, message []byte) (*bls.Signature, error) {
|
|
||||||
sig, err := sk.Sign(message)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return sig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ThresholdManager manages threshold signature operations
|
|
||||||
// Actual threshold operations use github.com/luxfi/threshold
|
|
||||||
type ThresholdManager struct {
|
|
||||||
log log.Logger
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewThresholdManager creates a new threshold manager
|
|
||||||
func NewThresholdManager(log log.Logger) *ThresholdManager {
|
|
||||||
return &ThresholdManager{
|
|
||||||
log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CGGMP21Manager manages CGGMP21 threshold signature operations
|
|
||||||
type CGGMP21Manager struct {
|
|
||||||
log log.Logger
|
|
||||||
parties map[int]*cggmp21.Party
|
|
||||||
config *cggmp21.Config
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCGGMP21Manager creates a new CGGMP21 manager
|
|
||||||
func NewCGGMP21Manager(log log.Logger) *CGGMP21Manager {
|
|
||||||
return &CGGMP21Manager{
|
|
||||||
log: log,
|
|
||||||
parties: make(map[int]*cggmp21.Party),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitializeParty creates a new CGGMP21 party
|
|
||||||
func (m *CGGMP21Manager) InitializeParty(
|
|
||||||
partyID ids.NodeID,
|
|
||||||
index int,
|
|
||||||
config *cggmp21.Config,
|
|
||||||
) error {
|
|
||||||
m.mu.Lock()
|
|
||||||
defer m.mu.Unlock()
|
|
||||||
|
|
||||||
party, err := cggmp21.NewParty(partyID, index, config, m.log)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.parties[index] = party
|
|
||||||
m.config = config
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetParty retrieves a CGGMP21 party by index
|
|
||||||
func (m *CGGMP21Manager) GetParty(index int) (*cggmp21.Party, error) {
|
|
||||||
m.mu.RLock()
|
|
||||||
defer m.mu.RUnlock()
|
|
||||||
|
|
||||||
party, exists := m.parties[index]
|
|
||||||
if !exists {
|
|
||||||
return nil, errors.New("party not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return party, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FeeCollector manages fee collection for signature operations
|
|
||||||
type FeeCollector struct {
|
|
||||||
collectedFees map[SignatureType]uint64
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFeeCollector creates a new fee collector
|
|
||||||
func NewFeeCollector() FeeCollector {
|
|
||||||
return FeeCollector{
|
|
||||||
collectedFees: make(map[SignatureType]uint64),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CollectFee records a fee collection
|
|
||||||
func (fc *FeeCollector) CollectFee(sigType SignatureType, amount uint64) {
|
|
||||||
fc.mu.Lock()
|
|
||||||
defer fc.mu.Unlock()
|
|
||||||
|
|
||||||
fc.collectedFees[sigType] += amount
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectedFees returns total collected fees by type
|
|
||||||
func (fc *FeeCollector) GetCollectedFees() map[SignatureType]uint64 {
|
|
||||||
fc.mu.RLock()
|
|
||||||
defer fc.mu.RUnlock()
|
|
||||||
|
|
||||||
fees := make(map[SignatureType]uint64)
|
|
||||||
for k, v := range fc.collectedFees {
|
|
||||||
fees[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
return fees
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTotalFees returns the total of all collected fees
|
|
||||||
func (fc *FeeCollector) GetTotalFees() uint64 {
|
|
||||||
fc.mu.RLock()
|
|
||||||
defer fc.mu.RUnlock()
|
|
||||||
|
|
||||||
var total uint64
|
|
||||||
for _, amount := range fc.collectedFees {
|
|
||||||
total += amount
|
|
||||||
}
|
|
||||||
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetFees resets the fee collection
|
|
||||||
func (fc *FeeCollector) ResetFees() map[SignatureType]uint64 {
|
|
||||||
fc.mu.Lock()
|
|
||||||
defer fc.mu.Unlock()
|
|
||||||
|
|
||||||
oldFees := fc.collectedFees
|
|
||||||
fc.collectedFees = make(map[SignatureType]uint64)
|
|
||||||
|
|
||||||
return oldFees
|
|
||||||
}
|
|
||||||
@@ -1,582 +0,0 @@
|
|||||||
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
||||||
// See the file LICENSE for licensing terms.
|
|
||||||
|
|
||||||
package aggregated
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/luxfi/crypto/bls"
|
|
||||||
"github.com/luxfi/ids"
|
|
||||||
log "github.com/luxfi/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ThresholdPublicKey wraps raw bytes for threshold public keys.
|
|
||||||
// Threshold key generation and signing are handled by github.com/luxfi/threshold.
|
|
||||||
type ThresholdPublicKey struct {
|
|
||||||
Bytes []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal checks if two threshold public keys are equal
|
|
||||||
func (pk *ThresholdPublicKey) Equal(other *ThresholdPublicKey) bool {
|
|
||||||
if pk == nil || other == nil {
|
|
||||||
return pk == other
|
|
||||||
}
|
|
||||||
if len(pk.Bytes) != len(other.Bytes) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i := range pk.Bytes {
|
|
||||||
if pk.Bytes[i] != other.Bytes[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ThresholdSignature wraps raw bytes for threshold signatures.
|
|
||||||
// Threshold signing and combination are handled by github.com/luxfi/threshold.
|
|
||||||
type ThresholdSignature struct {
|
|
||||||
Bytes []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify performs a basic non-empty check. Full cryptographic verification
|
|
||||||
// requires the threshold public key and is done via github.com/luxfi/threshold.
|
|
||||||
func (ts *ThresholdSignature) Verify(message []byte) bool {
|
|
||||||
return len(ts.Bytes) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import log field helpers
|
|
||||||
var (
|
|
||||||
logUint8 = log.Uint8
|
|
||||||
logUint64 = log.Uint64
|
|
||||||
logBool = log.Bool
|
|
||||||
logString = log.String
|
|
||||||
)
|
|
||||||
|
|
||||||
// SignatureType represents the type of aggregated signature
|
|
||||||
type SignatureType uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
SignatureTypeBLS SignatureType = iota
|
|
||||||
SignatureTypeCorona
|
|
||||||
SignatureTypeCGGMP21
|
|
||||||
)
|
|
||||||
|
|
||||||
// SignatureConfig contains configuration for signature aggregation
|
|
||||||
type SignatureConfig struct {
|
|
||||||
// Network-wide signature type preference
|
|
||||||
PreferredType SignatureType `json:"preferredType"`
|
|
||||||
|
|
||||||
// Enable specific signature types
|
|
||||||
EnableBLS bool `json:"enableBLS"`
|
|
||||||
EnableCorona bool `json:"enableCorona"`
|
|
||||||
EnableCGGMP21 bool `json:"enableCGGMP21"`
|
|
||||||
|
|
||||||
// Fee configuration (in nLUX - nano LUX)
|
|
||||||
BLSFee uint64 `json:"blsFee"` // 0 = free
|
|
||||||
CoronaFee uint64 `json:"coronaFee"` // Premium for enhanced privacy
|
|
||||||
CGGMP21Fee uint64 `json:"cggmp21Fee"` // Premium for threshold signatures
|
|
||||||
|
|
||||||
// Performance settings
|
|
||||||
ParallelAggregation bool `json:"parallelAggregation"`
|
|
||||||
MaxSignersPerRound int `json:"maxSignersPerRound"`
|
|
||||||
|
|
||||||
// Security settings
|
|
||||||
MinSigners int `json:"minSigners"`
|
|
||||||
ThresholdRatio float64 `json:"thresholdRatio"` // e.g., 0.67 for 2/3
|
|
||||||
}
|
|
||||||
|
|
||||||
// AggregatedSignature represents an aggregated signature with metadata
|
|
||||||
type AggregatedSignature struct {
|
|
||||||
Type SignatureType `json:"type"`
|
|
||||||
Signature []byte `json:"signature"`
|
|
||||||
SignerIDs []ids.NodeID `json:"signerIds,omitempty"`
|
|
||||||
SignerCount int `json:"signerCount"`
|
|
||||||
ThresholdPubKeys []*ThresholdPublicKey `json:"thresholdPubKeys,omitempty"` // For Corona threshold
|
|
||||||
AggregateKey []byte `json:"aggregateKey,omitempty"` // For BLS
|
|
||||||
ThresholdRequired int `json:"threshold,omitempty"` // For threshold schemes
|
|
||||||
TotalFee uint64 `json:"totalFee"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignatureAggregator manages network-wide signature aggregation
|
|
||||||
type SignatureAggregator struct {
|
|
||||||
config SignatureConfig
|
|
||||||
log log.Logger
|
|
||||||
|
|
||||||
// Signature managers
|
|
||||||
blsManager *BLSManager
|
|
||||||
thresholdManager *ThresholdManager
|
|
||||||
cggmpManager *CGGMP21Manager
|
|
||||||
|
|
||||||
// Active aggregation sessions
|
|
||||||
sessions map[string]*AggregationSession
|
|
||||||
|
|
||||||
// Fee collector
|
|
||||||
feeCollector FeeCollector
|
|
||||||
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// AggregationSession represents an active signature aggregation
|
|
||||||
type AggregationSession struct {
|
|
||||||
SessionID string
|
|
||||||
Message []byte
|
|
||||||
SignatureType SignatureType
|
|
||||||
|
|
||||||
// Collected signatures
|
|
||||||
BLSSignatures []*bls.Signature
|
|
||||||
BLSPublicKeys []*bls.PublicKey
|
|
||||||
ThresholdSignatures []*ThresholdSignature
|
|
||||||
ThresholdPubKeys []*ThresholdPublicKey
|
|
||||||
|
|
||||||
// Signers
|
|
||||||
Signers map[ids.NodeID]bool
|
|
||||||
SignerCount int
|
|
||||||
|
|
||||||
// Status
|
|
||||||
StartTime int64
|
|
||||||
Completed bool
|
|
||||||
Result *AggregatedSignature
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSignatureAggregator creates a new signature aggregator
|
|
||||||
func NewSignatureAggregator(config SignatureConfig, log log.Logger) (*SignatureAggregator, error) {
|
|
||||||
sa := &SignatureAggregator{
|
|
||||||
config: config,
|
|
||||||
log: log,
|
|
||||||
sessions: make(map[string]*AggregationSession),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize signature managers based on config
|
|
||||||
if config.EnableBLS {
|
|
||||||
sa.blsManager = NewBLSManager(log)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.EnableCorona {
|
|
||||||
sa.thresholdManager = NewThresholdManager(log)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.EnableCGGMP21 {
|
|
||||||
sa.cggmpManager = NewCGGMP21Manager(log)
|
|
||||||
}
|
|
||||||
|
|
||||||
sa.feeCollector = NewFeeCollector()
|
|
||||||
|
|
||||||
log.Info("Signature aggregator initialized",
|
|
||||||
logUint8("preferredType", uint8(config.PreferredType)),
|
|
||||||
logBool("blsEnabled", config.EnableBLS),
|
|
||||||
logBool("coronaEnabled", config.EnableCorona),
|
|
||||||
logBool("cggmp21Enabled", config.EnableCGGMP21),
|
|
||||||
logUint64("blsFee", config.BLSFee),
|
|
||||||
logUint64("coronaFee", config.CoronaFee),
|
|
||||||
)
|
|
||||||
|
|
||||||
return sa, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartAggregation starts a new signature aggregation session
|
|
||||||
func (sa *SignatureAggregator) StartAggregation(
|
|
||||||
sessionID string,
|
|
||||||
message []byte,
|
|
||||||
sigType SignatureType,
|
|
||||||
expectedSigners int,
|
|
||||||
) error {
|
|
||||||
sa.mu.Lock()
|
|
||||||
defer sa.mu.Unlock()
|
|
||||||
|
|
||||||
if _, exists := sa.sessions[sessionID]; exists {
|
|
||||||
return errors.New("session already exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate signature type is enabled
|
|
||||||
switch sigType {
|
|
||||||
case SignatureTypeBLS:
|
|
||||||
if !sa.config.EnableBLS {
|
|
||||||
return errors.New("BLS signatures not enabled")
|
|
||||||
}
|
|
||||||
case SignatureTypeCorona:
|
|
||||||
if !sa.config.EnableCorona {
|
|
||||||
return errors.New("Corona signatures not enabled")
|
|
||||||
}
|
|
||||||
case SignatureTypeCGGMP21:
|
|
||||||
if !sa.config.EnableCGGMP21 {
|
|
||||||
return errors.New("CGGMP21 signatures not enabled")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("unknown signature type")
|
|
||||||
}
|
|
||||||
|
|
||||||
session := &AggregationSession{
|
|
||||||
SessionID: sessionID,
|
|
||||||
Message: message,
|
|
||||||
SignatureType: sigType,
|
|
||||||
Signers: make(map[ids.NodeID]bool),
|
|
||||||
StartTime: getCurrentTime(),
|
|
||||||
}
|
|
||||||
|
|
||||||
sa.sessions[sessionID] = session
|
|
||||||
|
|
||||||
sa.log.Debug("Started aggregation session",
|
|
||||||
log.String("sessionID", sessionID),
|
|
||||||
log.Uint8("type", uint8(sigType)),
|
|
||||||
log.Int("expectedSigners", expectedSigners),
|
|
||||||
)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSignature adds a signature to an aggregation session
|
|
||||||
func (sa *SignatureAggregator) AddSignature(
|
|
||||||
sessionID string,
|
|
||||||
signerID ids.NodeID,
|
|
||||||
signature []byte,
|
|
||||||
publicKey []byte,
|
|
||||||
) error {
|
|
||||||
sa.mu.Lock()
|
|
||||||
defer sa.mu.Unlock()
|
|
||||||
|
|
||||||
session, exists := sa.sessions[sessionID]
|
|
||||||
if !exists {
|
|
||||||
return errors.New("session not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if session.Completed {
|
|
||||||
return errors.New("session already completed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if signer already contributed
|
|
||||||
if session.Signers[signerID] {
|
|
||||||
return errors.New("signer already contributed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add signature based on type
|
|
||||||
switch session.SignatureType {
|
|
||||||
case SignatureTypeBLS:
|
|
||||||
return sa.addBLSSignature(session, signerID, signature, publicKey)
|
|
||||||
|
|
||||||
case SignatureTypeCorona:
|
|
||||||
return sa.addCoronaSignature(session, signerID, signature, publicKey)
|
|
||||||
|
|
||||||
case SignatureTypeCGGMP21:
|
|
||||||
return errors.New("CGGMP21 uses different protocol flow")
|
|
||||||
|
|
||||||
default:
|
|
||||||
return errors.New("unknown signature type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// addBLSSignature adds a BLS signature to the session
|
|
||||||
func (sa *SignatureAggregator) addBLSSignature(
|
|
||||||
session *AggregationSession,
|
|
||||||
signerID ids.NodeID,
|
|
||||||
signature []byte,
|
|
||||||
publicKey []byte,
|
|
||||||
) error {
|
|
||||||
// Parse BLS signature and public key
|
|
||||||
sig, err := bls.SignatureFromBytes(signature)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid BLS signature: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pk, err := bls.PublicKeyFromCompressedBytes(publicKey)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid BLS public key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify individual signature
|
|
||||||
valid := bls.Verify(pk, sig, session.Message)
|
|
||||||
if !valid {
|
|
||||||
return fmt.Errorf("BLS signature verification failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add to session
|
|
||||||
session.BLSSignatures = append(session.BLSSignatures, sig)
|
|
||||||
session.BLSPublicKeys = append(session.BLSPublicKeys, pk)
|
|
||||||
session.Signers[signerID] = true
|
|
||||||
session.SignerCount++
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// addCoronaSignature adds a Corona threshold signature share to the session
|
|
||||||
// Actual threshold operations are coordinated through github.com/luxfi/threshold
|
|
||||||
func (sa *SignatureAggregator) addCoronaSignature(
|
|
||||||
session *AggregationSession,
|
|
||||||
signerID ids.NodeID,
|
|
||||||
signature []byte,
|
|
||||||
publicKey []byte,
|
|
||||||
) error {
|
|
||||||
// Create threshold signature placeholder
|
|
||||||
// Actual deserialization would use github.com/luxfi/threshold
|
|
||||||
thresholdSig := &ThresholdSignature{
|
|
||||||
Bytes: signature,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create threshold public key placeholder
|
|
||||||
pk := &ThresholdPublicKey{
|
|
||||||
Bytes: publicKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add to participant list if not already present
|
|
||||||
inList := false
|
|
||||||
for _, existingPK := range session.ThresholdPubKeys {
|
|
||||||
if existingPK.Equal(pk) {
|
|
||||||
inList = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !inList {
|
|
||||||
session.ThresholdPubKeys = append(session.ThresholdPubKeys, pk)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store signature share
|
|
||||||
session.ThresholdSignatures = append(session.ThresholdSignatures, thresholdSig)
|
|
||||||
session.Signers[signerID] = true
|
|
||||||
session.SignerCount++
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FinalizeAggregation completes the aggregation and returns the result
|
|
||||||
func (sa *SignatureAggregator) FinalizeAggregation(
|
|
||||||
sessionID string,
|
|
||||||
requiredSigners int,
|
|
||||||
) (*AggregatedSignature, error) {
|
|
||||||
sa.mu.Lock()
|
|
||||||
defer sa.mu.Unlock()
|
|
||||||
|
|
||||||
session, exists := sa.sessions[sessionID]
|
|
||||||
if !exists {
|
|
||||||
return nil, errors.New("session not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if session.Completed {
|
|
||||||
return session.Result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check minimum signers
|
|
||||||
if session.SignerCount < requiredSigners {
|
|
||||||
return nil, fmt.Errorf("insufficient signers: %d < %d", session.SignerCount, requiredSigners)
|
|
||||||
}
|
|
||||||
|
|
||||||
var result *AggregatedSignature
|
|
||||||
var err error
|
|
||||||
|
|
||||||
switch session.SignatureType {
|
|
||||||
case SignatureTypeBLS:
|
|
||||||
result, err = sa.finalizeBLS(session)
|
|
||||||
|
|
||||||
case SignatureTypeCorona:
|
|
||||||
result, err = sa.finalizeCorona(session)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, errors.New("unknown signature type")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate total fee
|
|
||||||
result.TotalFee = sa.calculateFee(session.SignatureType, session.SignerCount)
|
|
||||||
|
|
||||||
// Mark session as completed
|
|
||||||
session.Completed = true
|
|
||||||
session.Result = result
|
|
||||||
|
|
||||||
sa.log.Info("Finalized aggregation",
|
|
||||||
log.String("sessionID", sessionID),
|
|
||||||
log.Uint8("type", uint8(session.SignatureType)),
|
|
||||||
log.Int("signers", session.SignerCount),
|
|
||||||
log.Uint64("totalFee", result.TotalFee),
|
|
||||||
)
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// finalizeBLS aggregates BLS signatures
|
|
||||||
func (sa *SignatureAggregator) finalizeBLS(session *AggregationSession) (*AggregatedSignature, error) {
|
|
||||||
if len(session.BLSSignatures) == 0 {
|
|
||||||
return nil, errors.New("no BLS signatures to aggregate")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aggregate signatures
|
|
||||||
aggSig, err := bls.AggregateSignatures(session.BLSSignatures)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("BLS aggregation failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aggregate public keys
|
|
||||||
aggPK, err := bls.AggregatePublicKeys(session.BLSPublicKeys)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("BLS public key aggregation failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify aggregate signature
|
|
||||||
valid := bls.Verify(aggPK, aggSig, session.Message)
|
|
||||||
if !valid {
|
|
||||||
return nil, fmt.Errorf("aggregate signature verification failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
sigBytes := bls.SignatureToBytes(aggSig)
|
|
||||||
pkBytes := bls.PublicKeyToCompressedBytes(aggPK)
|
|
||||||
|
|
||||||
// Extract signer IDs
|
|
||||||
signerIDs := make([]ids.NodeID, 0, len(session.Signers))
|
|
||||||
for id := range session.Signers {
|
|
||||||
signerIDs = append(signerIDs, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &AggregatedSignature{
|
|
||||||
Type: SignatureTypeBLS,
|
|
||||||
Signature: sigBytes,
|
|
||||||
SignerIDs: signerIDs,
|
|
||||||
SignerCount: session.SignerCount,
|
|
||||||
AggregateKey: pkBytes,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// finalizeCorona aggregates threshold signature shares
|
|
||||||
// Actual threshold aggregation uses github.com/luxfi/threshold protocols
|
|
||||||
func (sa *SignatureAggregator) finalizeCorona(session *AggregationSession) (*AggregatedSignature, error) {
|
|
||||||
if len(session.ThresholdSignatures) == 0 {
|
|
||||||
return nil, errors.New("no threshold signatures collected")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aggregate threshold signature shares
|
|
||||||
// In production, this would use github.com/luxfi/threshold to combine shares
|
|
||||||
// For now, concatenate the signature bytes as a placeholder
|
|
||||||
var sigBytes []byte
|
|
||||||
for _, sig := range session.ThresholdSignatures {
|
|
||||||
sigBytes = append(sigBytes, sig.Bytes...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify threshold signature
|
|
||||||
// Actual verification would use the threshold package
|
|
||||||
if len(sigBytes) == 0 {
|
|
||||||
return nil, fmt.Errorf("threshold signature aggregation failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &AggregatedSignature{
|
|
||||||
Type: SignatureTypeCorona,
|
|
||||||
Signature: sigBytes,
|
|
||||||
SignerCount: session.SignerCount,
|
|
||||||
ThresholdPubKeys: session.ThresholdPubKeys,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculateFee calculates the total fee for signature aggregation
|
|
||||||
func (sa *SignatureAggregator) calculateFee(sigType SignatureType, signerCount int) uint64 {
|
|
||||||
var feePerSigner uint64
|
|
||||||
|
|
||||||
switch sigType {
|
|
||||||
case SignatureTypeBLS:
|
|
||||||
feePerSigner = sa.config.BLSFee // 0 for free
|
|
||||||
case SignatureTypeCorona:
|
|
||||||
feePerSigner = sa.config.CoronaFee // Premium fee
|
|
||||||
case SignatureTypeCGGMP21:
|
|
||||||
feePerSigner = sa.config.CGGMP21Fee // Premium fee
|
|
||||||
default:
|
|
||||||
feePerSigner = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return feePerSigner * uint64(signerCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyAggregatedSignature verifies an aggregated signature
|
|
||||||
func (sa *SignatureAggregator) VerifyAggregatedSignature(
|
|
||||||
message []byte,
|
|
||||||
aggSig *AggregatedSignature,
|
|
||||||
) error {
|
|
||||||
switch aggSig.Type {
|
|
||||||
case SignatureTypeBLS:
|
|
||||||
return sa.verifyBLSAggregate(message, aggSig)
|
|
||||||
|
|
||||||
case SignatureTypeCorona:
|
|
||||||
return sa.verifyCoronaAggregate(message, aggSig)
|
|
||||||
|
|
||||||
case SignatureTypeCGGMP21:
|
|
||||||
return errors.New("CGGMP21 verification not implemented")
|
|
||||||
|
|
||||||
default:
|
|
||||||
return errors.New("unknown signature type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// verifyBLSAggregate verifies a BLS aggregate signature
|
|
||||||
func (sa *SignatureAggregator) verifyBLSAggregate(message []byte, aggSig *AggregatedSignature) error {
|
|
||||||
sig, err := bls.SignatureFromBytes(aggSig.Signature)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
pk, err := bls.PublicKeyFromCompressedBytes(aggSig.AggregateKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
valid := bls.Verify(pk, sig, message)
|
|
||||||
if !valid {
|
|
||||||
return errors.New("BLS signature verification failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// verifyCoronaAggregate verifies a Corona ring signature
|
|
||||||
func (sa *SignatureAggregator) verifyCoronaAggregate(message []byte, aggSig *AggregatedSignature) error {
|
|
||||||
// For now, simplified verification
|
|
||||||
// In production, deserialize and verify properly
|
|
||||||
if len(aggSig.Signature) < 256 {
|
|
||||||
return errors.New("invalid ring signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSessionStatus returns the status of an aggregation session
|
|
||||||
func (sa *SignatureAggregator) GetSessionStatus(sessionID string) (map[string]interface{}, error) {
|
|
||||||
sa.mu.RLock()
|
|
||||||
defer sa.mu.RUnlock()
|
|
||||||
|
|
||||||
session, exists := sa.sessions[sessionID]
|
|
||||||
if !exists {
|
|
||||||
return nil, errors.New("session not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
status := map[string]interface{}{
|
|
||||||
"sessionID": session.SessionID,
|
|
||||||
"signatureType": session.SignatureType,
|
|
||||||
"signerCount": session.SignerCount,
|
|
||||||
"completed": session.Completed,
|
|
||||||
"startTime": session.StartTime,
|
|
||||||
}
|
|
||||||
|
|
||||||
if session.Completed && session.Result != nil {
|
|
||||||
status["totalFee"] = session.Result.TotalFee
|
|
||||||
}
|
|
||||||
|
|
||||||
return status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup removes old sessions
|
|
||||||
func (sa *SignatureAggregator) Cleanup(maxAge int64) {
|
|
||||||
sa.mu.Lock()
|
|
||||||
defer sa.mu.Unlock()
|
|
||||||
|
|
||||||
currentTime := getCurrentTime()
|
|
||||||
|
|
||||||
for sessionID, session := range sa.sessions {
|
|
||||||
if currentTime-session.StartTime > maxAge {
|
|
||||||
delete(sa.sessions, sessionID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function
|
|
||||||
func getCurrentTime() int64 {
|
|
||||||
return time.Now().Unix()
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user