fix: apply gofmt -s formatting

This commit is contained in:
Zach Kelling
2025-12-11 03:04:56 +00:00
parent 6f62fb8301
commit 95100198c8
69 changed files with 1232 additions and 1246 deletions
+21 -21
View File
@@ -14,25 +14,25 @@ import (
type AeadID string type AeadID string
const ( const (
AES256GCM AeadID = "aes256gcm" AES256GCM AeadID = "aes256gcm"
ChaCha20Poly1305 AeadID = "chacha20poly1305" ChaCha20Poly1305 AeadID = "chacha20poly1305"
AES256GCMSIV AeadID = "aes256gcmsiv" AES256GCMSIV AeadID = "aes256gcmsiv"
) )
// AEAD interface for authenticated encryption // AEAD interface for authenticated encryption
type AEAD interface { type AEAD interface {
// Seal encrypts and authenticates plaintext // Seal encrypts and authenticates plaintext
Seal(dst, nonce, plaintext, aad []byte) []byte Seal(dst, nonce, plaintext, aad []byte) []byte
// Open decrypts and authenticates ciphertext // Open decrypts and authenticates ciphertext
Open(dst, nonce, ciphertext, aad []byte) ([]byte, error) Open(dst, nonce, ciphertext, aad []byte) ([]byte, error)
// NonceSize returns the nonce size in bytes // NonceSize returns the nonce size in bytes
NonceSize() int NonceSize() int
// Overhead returns the authentication tag size // Overhead returns the authentication tag size
Overhead() int Overhead() int
// KeySize returns the key size in bytes // KeySize returns the key size in bytes
KeySize() int KeySize() int
} }
@@ -47,17 +47,17 @@ func NewAES256GCM(key []byte) (AEAD, error) {
if len(key) != 32 { if len(key) != 32 {
return nil, errors.New("AES-256-GCM requires 32-byte key") return nil, errors.New("AES-256-GCM requires 32-byte key")
} }
block, err := aes.NewCipher(key) block, err := aes.NewCipher(key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
aead, err := cipher.NewGCM(block) aead, err := cipher.NewGCM(block)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &AES256GCMImpl{aead: aead}, nil return &AES256GCMImpl{aead: aead}, nil
} }
@@ -66,7 +66,7 @@ func (a *AES256GCMImpl) Seal(dst, nonce, plaintext, aad []byte) []byte {
if len(nonce) != a.NonceSize() { if len(nonce) != a.NonceSize() {
panic(fmt.Sprintf("invalid nonce size: got %d, want %d", len(nonce), a.NonceSize())) panic(fmt.Sprintf("invalid nonce size: got %d, want %d", len(nonce), a.NonceSize()))
} }
// GCM handles AAD internally // GCM handles AAD internally
return a.aead.Seal(dst, nonce, plaintext, aad) return a.aead.Seal(dst, nonce, plaintext, aad)
} }
@@ -76,7 +76,7 @@ func (a *AES256GCMImpl) Open(dst, nonce, ciphertext, aad []byte) ([]byte, error)
if len(nonce) != a.NonceSize() { if len(nonce) != a.NonceSize() {
return nil, fmt.Errorf("invalid nonce size: got %d, want %d", len(nonce), a.NonceSize()) return nil, fmt.Errorf("invalid nonce size: got %d, want %d", len(nonce), a.NonceSize())
} }
return a.aead.Open(dst, nonce, ciphertext, aad) return a.aead.Open(dst, nonce, ciphertext, aad)
} }
@@ -105,12 +105,12 @@ func NewChaCha20Poly1305(key []byte) (AEAD, error) {
if len(key) != 32 { if len(key) != 32 {
return nil, errors.New("ChaCha20-Poly1305 requires 32-byte key") return nil, errors.New("ChaCha20-Poly1305 requires 32-byte key")
} }
aead, err := chacha20poly1305.New(key) aead, err := chacha20poly1305.New(key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &ChaCha20Poly1305Impl{aead: aead}, nil return &ChaCha20Poly1305Impl{aead: aead}, nil
} }
@@ -119,7 +119,7 @@ func (c *ChaCha20Poly1305Impl) Seal(dst, nonce, plaintext, aad []byte) []byte {
if len(nonce) != c.NonceSize() { if len(nonce) != c.NonceSize() {
panic(fmt.Sprintf("invalid nonce size: got %d, want %d", len(nonce), c.NonceSize())) panic(fmt.Sprintf("invalid nonce size: got %d, want %d", len(nonce), c.NonceSize()))
} }
return c.aead.Seal(dst, nonce, plaintext, aad) return c.aead.Seal(dst, nonce, plaintext, aad)
} }
@@ -128,7 +128,7 @@ func (c *ChaCha20Poly1305Impl) Open(dst, nonce, ciphertext, aad []byte) ([]byte,
if len(nonce) != c.NonceSize() { if len(nonce) != c.NonceSize() {
return nil, fmt.Errorf("invalid nonce size: got %d, want %d", len(nonce), c.NonceSize()) return nil, fmt.Errorf("invalid nonce size: got %d, want %d", len(nonce), c.NonceSize())
} }
return c.aead.Open(dst, nonce, ciphertext, aad) return c.aead.Open(dst, nonce, ciphertext, aad)
} }
@@ -179,13 +179,13 @@ func NewNonceGenerator(streamID uint32) *NonceGenerator {
// Next returns the next nonce and increments sequence number // Next returns the next nonce and increments sequence number
func (ng *NonceGenerator) Next() []byte { func (ng *NonceGenerator) Next() []byte {
nonce := make([]byte, 12) // 96-bit nonce nonce := make([]byte, 12) // 96-bit nonce
// First 4 bytes: stream ID // First 4 bytes: stream ID
nonce[0] = byte(ng.streamID >> 24) nonce[0] = byte(ng.streamID >> 24)
nonce[1] = byte(ng.streamID >> 16) nonce[1] = byte(ng.streamID >> 16)
nonce[2] = byte(ng.streamID >> 8) nonce[2] = byte(ng.streamID >> 8)
nonce[3] = byte(ng.streamID) nonce[3] = byte(ng.streamID)
// Next 8 bytes: sequence number // Next 8 bytes: sequence number
nonce[4] = byte(ng.seqNo >> 56) nonce[4] = byte(ng.seqNo >> 56)
nonce[5] = byte(ng.seqNo >> 48) nonce[5] = byte(ng.seqNo >> 48)
@@ -195,9 +195,9 @@ func (ng *NonceGenerator) Next() []byte {
nonce[9] = byte(ng.seqNo >> 16) nonce[9] = byte(ng.seqNo >> 16)
nonce[10] = byte(ng.seqNo >> 8) nonce[10] = byte(ng.seqNo >> 8)
nonce[11] = byte(ng.seqNo) nonce[11] = byte(ng.seqNo)
ng.seqNo++ ng.seqNo++
return nonce return nonce
} }
@@ -209,4 +209,4 @@ func (ng *NonceGenerator) SetSeqNo(seqNo uint64) {
// GetSeqNo returns the current sequence number // GetSeqNo returns the current sequence number
func (ng *NonceGenerator) GetSeqNo() uint64 { func (ng *NonceGenerator) GetSeqNo() uint64 {
return ng.seqNo return ng.seqNo
} }
+19 -19
View File
@@ -7,11 +7,11 @@ import (
"errors" "errors"
"sync" "sync"
"github.com/luxfi/crypto/bls"
"github.com/luxfi/crypto/cggmp21"
"github.com/luxfi/crypto/corona"
"github.com/luxfi/ids" "github.com/luxfi/ids"
"github.com/luxfi/log" "github.com/luxfi/log"
"github.com/luxfi/crypto/bls"
"github.com/luxfi/crypto/corona"
"github.com/luxfi/crypto/cggmp21"
) )
// BLSManager manages BLS signature operations // BLSManager manages BLS signature operations
@@ -33,7 +33,7 @@ func (m *BLSManager) CreateKeyPair() (*bls.SecretKey, *bls.PublicKey, error) {
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
pk := sk.PublicKey() pk := sk.PublicKey()
return sk, pk, nil return sk, pk, nil
} }
@@ -67,12 +67,12 @@ func (m *CoronaManager) CreateKeyPair() (*corona.PrivateKey, *corona.PublicKey,
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
pubKey, err := factory.ToPublicKey(privKey) pubKey, err := factory.ToPublicKey(privKey)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return privKey, pubKey, nil return privKey, pubKey, nil
} }
@@ -109,15 +109,15 @@ func (m *CGGMP21Manager) InitializeParty(
) error { ) error {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
party, err := cggmp21.NewParty(partyID, index, config, m.log) party, err := cggmp21.NewParty(partyID, index, config, m.log)
if err != nil { if err != nil {
return err return err
} }
m.parties[index] = party m.parties[index] = party
m.config = config m.config = config
return nil return nil
} }
@@ -125,12 +125,12 @@ func (m *CGGMP21Manager) InitializeParty(
func (m *CGGMP21Manager) GetParty(index int) (*cggmp21.Party, error) { func (m *CGGMP21Manager) GetParty(index int) (*cggmp21.Party, error) {
m.mu.RLock() m.mu.RLock()
defer m.mu.RUnlock() defer m.mu.RUnlock()
party, exists := m.parties[index] party, exists := m.parties[index]
if !exists { if !exists {
return nil, errors.New("party not found") return nil, errors.New("party not found")
} }
return party, nil return party, nil
} }
@@ -151,7 +151,7 @@ func NewFeeCollector() FeeCollector {
func (fc *FeeCollector) CollectFee(sigType SignatureType, amount uint64) { func (fc *FeeCollector) CollectFee(sigType SignatureType, amount uint64) {
fc.mu.Lock() fc.mu.Lock()
defer fc.mu.Unlock() defer fc.mu.Unlock()
fc.collectedFees[sigType] += amount fc.collectedFees[sigType] += amount
} }
@@ -159,12 +159,12 @@ func (fc *FeeCollector) CollectFee(sigType SignatureType, amount uint64) {
func (fc *FeeCollector) GetCollectedFees() map[SignatureType]uint64 { func (fc *FeeCollector) GetCollectedFees() map[SignatureType]uint64 {
fc.mu.RLock() fc.mu.RLock()
defer fc.mu.RUnlock() defer fc.mu.RUnlock()
fees := make(map[SignatureType]uint64) fees := make(map[SignatureType]uint64)
for k, v := range fc.collectedFees { for k, v := range fc.collectedFees {
fees[k] = v fees[k] = v
} }
return fees return fees
} }
@@ -172,12 +172,12 @@ func (fc *FeeCollector) GetCollectedFees() map[SignatureType]uint64 {
func (fc *FeeCollector) GetTotalFees() uint64 { func (fc *FeeCollector) GetTotalFees() uint64 {
fc.mu.RLock() fc.mu.RLock()
defer fc.mu.RUnlock() defer fc.mu.RUnlock()
var total uint64 var total uint64
for _, amount := range fc.collectedFees { for _, amount := range fc.collectedFees {
total += amount total += amount
} }
return total return total
} }
@@ -185,9 +185,9 @@ func (fc *FeeCollector) GetTotalFees() uint64 {
func (fc *FeeCollector) ResetFees() map[SignatureType]uint64 { func (fc *FeeCollector) ResetFees() map[SignatureType]uint64 {
fc.mu.Lock() fc.mu.Lock()
defer fc.mu.Unlock() defer fc.mu.Unlock()
oldFees := fc.collectedFees oldFees := fc.collectedFees
fc.collectedFees = make(map[SignatureType]uint64) fc.collectedFees = make(map[SignatureType]uint64)
return oldFees return oldFees
} }
+108 -108
View File
@@ -10,10 +10,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/luxfi/crypto/bls"
"github.com/luxfi/crypto/corona"
"github.com/luxfi/ids" "github.com/luxfi/ids"
"github.com/luxfi/log" "github.com/luxfi/log"
"github.com/luxfi/crypto/corona"
"github.com/luxfi/crypto/bls"
) )
// Import log field helpers // Import log field helpers
@@ -36,78 +36,78 @@ const (
// SignatureConfig contains configuration for signature aggregation // SignatureConfig contains configuration for signature aggregation
type SignatureConfig struct { type SignatureConfig struct {
// Network-wide signature type preference // Network-wide signature type preference
PreferredType SignatureType `json:"preferredType"` PreferredType SignatureType `json:"preferredType"`
// Enable specific signature types // Enable specific signature types
EnableBLS bool `json:"enableBLS"` EnableBLS bool `json:"enableBLS"`
EnableCorona bool `json:"enableCorona"` EnableCorona bool `json:"enableCorona"`
EnableCGGMP21 bool `json:"enableCGGMP21"` EnableCGGMP21 bool `json:"enableCGGMP21"`
// Fee configuration (in nLUX - nano LUX) // Fee configuration (in nLUX - nano LUX)
BLSFee uint64 `json:"blsFee"` // 0 = free BLSFee uint64 `json:"blsFee"` // 0 = free
CoronaFee uint64 `json:"coronaFee"` // Premium for enhanced privacy CoronaFee uint64 `json:"coronaFee"` // Premium for enhanced privacy
CGGMP21Fee uint64 `json:"cggmp21Fee"` // Premium for threshold signatures CGGMP21Fee uint64 `json:"cggmp21Fee"` // Premium for threshold signatures
// Performance settings // Performance settings
ParallelAggregation bool `json:"parallelAggregation"` ParallelAggregation bool `json:"parallelAggregation"`
MaxSignersPerRound int `json:"maxSignersPerRound"` MaxSignersPerRound int `json:"maxSignersPerRound"`
// Security settings // Security settings
MinSigners int `json:"minSigners"` MinSigners int `json:"minSigners"`
ThresholdRatio float64 `json:"thresholdRatio"` // e.g., 0.67 for 2/3 ThresholdRatio float64 `json:"thresholdRatio"` // e.g., 0.67 for 2/3
} }
// AggregatedSignature represents an aggregated signature with metadata // AggregatedSignature represents an aggregated signature with metadata
type AggregatedSignature struct { type AggregatedSignature struct {
Type SignatureType `json:"type"` Type SignatureType `json:"type"`
Signature []byte `json:"signature"` Signature []byte `json:"signature"`
SignerIDs []ids.NodeID `json:"signerIds,omitempty"` SignerIDs []ids.NodeID `json:"signerIds,omitempty"`
SignerCount int `json:"signerCount"` SignerCount int `json:"signerCount"`
RingPublicKeys []*corona.PublicKey `json:"ringPublicKeys,omitempty"` // For Corona RingPublicKeys []*corona.PublicKey `json:"ringPublicKeys,omitempty"` // For Corona
AggregateKey []byte `json:"aggregateKey,omitempty"` // For BLS AggregateKey []byte `json:"aggregateKey,omitempty"` // For BLS
Threshold int `json:"threshold,omitempty"` // For CGGMP21 Threshold int `json:"threshold,omitempty"` // For CGGMP21
TotalFee uint64 `json:"totalFee"` TotalFee uint64 `json:"totalFee"`
} }
// SignatureAggregator manages network-wide signature aggregation // SignatureAggregator manages network-wide signature aggregation
type SignatureAggregator struct { type SignatureAggregator struct {
config SignatureConfig config SignatureConfig
log log.Logger log log.Logger
// Signature managers // Signature managers
blsManager *BLSManager blsManager *BLSManager
coronaManager *CoronaManager coronaManager *CoronaManager
cggmpManager *CGGMP21Manager cggmpManager *CGGMP21Manager
// Active aggregation sessions // Active aggregation sessions
sessions map[string]*AggregationSession sessions map[string]*AggregationSession
// Fee collector // Fee collector
feeCollector FeeCollector feeCollector FeeCollector
mu sync.RWMutex mu sync.RWMutex
} }
// AggregationSession represents an active signature aggregation // AggregationSession represents an active signature aggregation
type AggregationSession struct { type AggregationSession struct {
SessionID string SessionID string
Message []byte Message []byte
SignatureType SignatureType SignatureType SignatureType
// Collected signatures // Collected signatures
BLSSignatures []*bls.Signature BLSSignatures []*bls.Signature
BLSPublicKeys []*bls.PublicKey BLSPublicKeys []*bls.PublicKey
CoronaSignatures []*corona.RingSignature CoronaSignatures []*corona.RingSignature
CoronaRing []*corona.PublicKey CoronaRing []*corona.PublicKey
// Signers // Signers
Signers map[ids.NodeID]bool Signers map[ids.NodeID]bool
SignerCount int SignerCount int
// Status // Status
StartTime int64 StartTime int64
Completed bool Completed bool
Result *AggregatedSignature Result *AggregatedSignature
} }
// NewSignatureAggregator creates a new signature aggregator // NewSignatureAggregator creates a new signature aggregator
@@ -117,22 +117,22 @@ func NewSignatureAggregator(config SignatureConfig, log log.Logger) (*SignatureA
log: log, log: log,
sessions: make(map[string]*AggregationSession), sessions: make(map[string]*AggregationSession),
} }
// Initialize signature managers based on config // Initialize signature managers based on config
if config.EnableBLS { if config.EnableBLS {
sa.blsManager = NewBLSManager(log) sa.blsManager = NewBLSManager(log)
} }
if config.EnableCorona { if config.EnableCorona {
sa.coronaManager = NewCoronaManager(log) sa.coronaManager = NewCoronaManager(log)
} }
if config.EnableCGGMP21 { if config.EnableCGGMP21 {
sa.cggmpManager = NewCGGMP21Manager(log) sa.cggmpManager = NewCGGMP21Manager(log)
} }
sa.feeCollector = NewFeeCollector() sa.feeCollector = NewFeeCollector()
log.Info("Signature aggregator initialized", log.Info("Signature aggregator initialized",
logUint8("preferredType", uint8(config.PreferredType)), logUint8("preferredType", uint8(config.PreferredType)),
logBool("blsEnabled", config.EnableBLS), logBool("blsEnabled", config.EnableBLS),
@@ -141,7 +141,7 @@ func NewSignatureAggregator(config SignatureConfig, log log.Logger) (*SignatureA
logUint64("blsFee", config.BLSFee), logUint64("blsFee", config.BLSFee),
logUint64("coronaFee", config.CoronaFee), logUint64("coronaFee", config.CoronaFee),
) )
return sa, nil return sa, nil
} }
@@ -154,11 +154,11 @@ func (sa *SignatureAggregator) StartAggregation(
) error { ) error {
sa.mu.Lock() sa.mu.Lock()
defer sa.mu.Unlock() defer sa.mu.Unlock()
if _, exists := sa.sessions[sessionID]; exists { if _, exists := sa.sessions[sessionID]; exists {
return errors.New("session already exists") return errors.New("session already exists")
} }
// Validate signature type is enabled // Validate signature type is enabled
switch sigType { switch sigType {
case SignatureTypeBLS: case SignatureTypeBLS:
@@ -176,7 +176,7 @@ func (sa *SignatureAggregator) StartAggregation(
default: default:
return errors.New("unknown signature type") return errors.New("unknown signature type")
} }
session := &AggregationSession{ session := &AggregationSession{
SessionID: sessionID, SessionID: sessionID,
Message: message, Message: message,
@@ -184,15 +184,15 @@ func (sa *SignatureAggregator) StartAggregation(
Signers: make(map[ids.NodeID]bool), Signers: make(map[ids.NodeID]bool),
StartTime: getCurrentTime(), StartTime: getCurrentTime(),
} }
sa.sessions[sessionID] = session sa.sessions[sessionID] = session
sa.log.Debug("Started aggregation session", sa.log.Debug("Started aggregation session",
log.String("sessionID", sessionID), log.String("sessionID", sessionID),
log.Uint8("type", uint8(sigType)), log.Uint8("type", uint8(sigType)),
log.Int("expectedSigners", expectedSigners), log.Int("expectedSigners", expectedSigners),
) )
return nil return nil
} }
@@ -205,32 +205,32 @@ func (sa *SignatureAggregator) AddSignature(
) error { ) error {
sa.mu.Lock() sa.mu.Lock()
defer sa.mu.Unlock() defer sa.mu.Unlock()
session, exists := sa.sessions[sessionID] session, exists := sa.sessions[sessionID]
if !exists { if !exists {
return errors.New("session not found") return errors.New("session not found")
} }
if session.Completed { if session.Completed {
return errors.New("session already completed") return errors.New("session already completed")
} }
// Check if signer already contributed // Check if signer already contributed
if session.Signers[signerID] { if session.Signers[signerID] {
return errors.New("signer already contributed") return errors.New("signer already contributed")
} }
// Add signature based on type // Add signature based on type
switch session.SignatureType { switch session.SignatureType {
case SignatureTypeBLS: case SignatureTypeBLS:
return sa.addBLSSignature(session, signerID, signature, publicKey) return sa.addBLSSignature(session, signerID, signature, publicKey)
case SignatureTypeCorona: case SignatureTypeCorona:
return sa.addCoronaSignature(session, signerID, signature, publicKey) return sa.addCoronaSignature(session, signerID, signature, publicKey)
case SignatureTypeCGGMP21: case SignatureTypeCGGMP21:
return errors.New("CGGMP21 uses different protocol flow") return errors.New("CGGMP21 uses different protocol flow")
default: default:
return errors.New("unknown signature type") return errors.New("unknown signature type")
} }
@@ -248,24 +248,24 @@ func (sa *SignatureAggregator) addBLSSignature(
if err != nil { if err != nil {
return fmt.Errorf("invalid BLS signature: %w", err) return fmt.Errorf("invalid BLS signature: %w", err)
} }
pk, err := bls.PublicKeyFromCompressedBytes(publicKey) pk, err := bls.PublicKeyFromCompressedBytes(publicKey)
if err != nil { if err != nil {
return fmt.Errorf("invalid BLS public key: %w", err) return fmt.Errorf("invalid BLS public key: %w", err)
} }
// Verify individual signature // Verify individual signature
valid := bls.Verify(pk, sig, session.Message) valid := bls.Verify(pk, sig, session.Message)
if !valid { if !valid {
return fmt.Errorf("BLS signature verification failed") return fmt.Errorf("BLS signature verification failed")
} }
// Add to session // Add to session
session.BLSSignatures = append(session.BLSSignatures, sig) session.BLSSignatures = append(session.BLSSignatures, sig)
session.BLSPublicKeys = append(session.BLSPublicKeys, pk) session.BLSPublicKeys = append(session.BLSPublicKeys, pk)
session.Signers[signerID] = true session.Signers[signerID] = true
session.SignerCount++ session.SignerCount++
return nil return nil
} }
@@ -284,7 +284,7 @@ func (sa *SignatureAggregator) addCoronaSignature(
S: make([]*big.Int, corona.DefaultRingSize), S: make([]*big.Int, corona.DefaultRingSize),
KeyImage: &corona.Point{X: big.NewInt(0), Y: big.NewInt(0)}, KeyImage: &corona.Point{X: big.NewInt(0), Y: big.NewInt(0)},
} }
// Parse public key // Parse public key
// For now, create from bytes // For now, create from bytes
// In production, implement proper deserialization // In production, implement proper deserialization
@@ -294,7 +294,7 @@ func (sa *SignatureAggregator) addCoronaSignature(
Y: new(big.Int).SetBytes(publicKey[32:64]), Y: new(big.Int).SetBytes(publicKey[32:64]),
}, },
} }
// Add to ring if not already present // Add to ring if not already present
inRing := false inRing := false
for _, ringPK := range session.CoronaRing { for _, ringPK := range session.CoronaRing {
@@ -306,12 +306,12 @@ func (sa *SignatureAggregator) addCoronaSignature(
if !inRing { if !inRing {
session.CoronaRing = append(session.CoronaRing, pk) session.CoronaRing = append(session.CoronaRing, pk)
} }
// Store signature // Store signature
session.CoronaSignatures = append(session.CoronaSignatures, ringSig) session.CoronaSignatures = append(session.CoronaSignatures, ringSig)
session.Signers[signerID] = true session.Signers[signerID] = true
session.SignerCount++ session.SignerCount++
return nil return nil
} }
@@ -322,53 +322,53 @@ func (sa *SignatureAggregator) FinalizeAggregation(
) (*AggregatedSignature, error) { ) (*AggregatedSignature, error) {
sa.mu.Lock() sa.mu.Lock()
defer sa.mu.Unlock() defer sa.mu.Unlock()
session, exists := sa.sessions[sessionID] session, exists := sa.sessions[sessionID]
if !exists { if !exists {
return nil, errors.New("session not found") return nil, errors.New("session not found")
} }
if session.Completed { if session.Completed {
return session.Result, nil return session.Result, nil
} }
// Check minimum signers // Check minimum signers
if session.SignerCount < requiredSigners { if session.SignerCount < requiredSigners {
return nil, fmt.Errorf("insufficient signers: %d < %d", session.SignerCount, requiredSigners) return nil, fmt.Errorf("insufficient signers: %d < %d", session.SignerCount, requiredSigners)
} }
var result *AggregatedSignature var result *AggregatedSignature
var err error var err error
switch session.SignatureType { switch session.SignatureType {
case SignatureTypeBLS: case SignatureTypeBLS:
result, err = sa.finalizeBLS(session) result, err = sa.finalizeBLS(session)
case SignatureTypeCorona: case SignatureTypeCorona:
result, err = sa.finalizeCorona(session) result, err = sa.finalizeCorona(session)
default: default:
return nil, errors.New("unknown signature type") return nil, errors.New("unknown signature type")
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Calculate total fee // Calculate total fee
result.TotalFee = sa.calculateFee(session.SignatureType, session.SignerCount) result.TotalFee = sa.calculateFee(session.SignatureType, session.SignerCount)
// Mark session as completed // Mark session as completed
session.Completed = true session.Completed = true
session.Result = result session.Result = result
sa.log.Info("Finalized aggregation", sa.log.Info("Finalized aggregation",
log.String("sessionID", sessionID), log.String("sessionID", sessionID),
log.Uint8("type", uint8(session.SignatureType)), log.Uint8("type", uint8(session.SignatureType)),
log.Int("signers", session.SignerCount), log.Int("signers", session.SignerCount),
log.Uint64("totalFee", result.TotalFee), log.Uint64("totalFee", result.TotalFee),
) )
return result, nil return result, nil
} }
@@ -377,34 +377,34 @@ func (sa *SignatureAggregator) finalizeBLS(session *AggregationSession) (*Aggreg
if len(session.BLSSignatures) == 0 { if len(session.BLSSignatures) == 0 {
return nil, errors.New("no BLS signatures to aggregate") return nil, errors.New("no BLS signatures to aggregate")
} }
// Aggregate signatures // Aggregate signatures
aggSig, err := bls.AggregateSignatures(session.BLSSignatures) aggSig, err := bls.AggregateSignatures(session.BLSSignatures)
if err != nil { if err != nil {
return nil, fmt.Errorf("BLS aggregation failed: %w", err) return nil, fmt.Errorf("BLS aggregation failed: %w", err)
} }
// Aggregate public keys // Aggregate public keys
aggPK, err := bls.AggregatePublicKeys(session.BLSPublicKeys) aggPK, err := bls.AggregatePublicKeys(session.BLSPublicKeys)
if err != nil { if err != nil {
return nil, fmt.Errorf("BLS public key aggregation failed: %w", err) return nil, fmt.Errorf("BLS public key aggregation failed: %w", err)
} }
// Verify aggregate signature // Verify aggregate signature
valid := bls.Verify(aggPK, aggSig, session.Message) valid := bls.Verify(aggPK, aggSig, session.Message)
if !valid { if !valid {
return nil, fmt.Errorf("aggregate signature verification failed") return nil, fmt.Errorf("aggregate signature verification failed")
} }
sigBytes := bls.SignatureToBytes(aggSig) sigBytes := bls.SignatureToBytes(aggSig)
pkBytes := bls.PublicKeyToCompressedBytes(aggPK) pkBytes := bls.PublicKeyToCompressedBytes(aggPK)
// Extract signer IDs // Extract signer IDs
signerIDs := make([]ids.NodeID, 0, len(session.Signers)) signerIDs := make([]ids.NodeID, 0, len(session.Signers))
for id := range session.Signers { for id := range session.Signers {
signerIDs = append(signerIDs, id) signerIDs = append(signerIDs, id)
} }
return &AggregatedSignature{ return &AggregatedSignature{
Type: SignatureTypeBLS, Type: SignatureTypeBLS,
Signature: sigBytes, Signature: sigBytes,
@@ -419,11 +419,11 @@ func (sa *SignatureAggregator) finalizeCorona(session *AggregationSession) (*Agg
if len(session.CoronaSignatures) == 0 { if len(session.CoronaSignatures) == 0 {
return nil, errors.New("no Corona signatures collected") return nil, errors.New("no Corona signatures collected")
} }
// For Corona, we use the first signature as the aggregated result // For Corona, we use the first signature as the aggregated result
// since ring signatures provide anonymity within the ring // since ring signatures provide anonymity within the ring
ringSig := session.CoronaSignatures[0] ringSig := session.CoronaSignatures[0]
// Serialize signature (simplified for now) // Serialize signature (simplified for now)
// In production, implement proper serialization // In production, implement proper serialization
sigBytes := make([]byte, 0) sigBytes := make([]byte, 0)
@@ -433,13 +433,13 @@ func (sa *SignatureAggregator) finalizeCorona(session *AggregationSession) (*Agg
sigBytes = append(sigBytes, s.Bytes()...) sigBytes = append(sigBytes, s.Bytes()...)
} }
} }
// Verify against the full ring // Verify against the full ring
valid := ringSig.Verify(session.Message) valid := ringSig.Verify(session.Message)
if !valid { if !valid {
return nil, fmt.Errorf("ring signature verification failed") return nil, fmt.Errorf("ring signature verification failed")
} }
return &AggregatedSignature{ return &AggregatedSignature{
Type: SignatureTypeCorona, Type: SignatureTypeCorona,
Signature: sigBytes, Signature: sigBytes,
@@ -451,7 +451,7 @@ func (sa *SignatureAggregator) finalizeCorona(session *AggregationSession) (*Agg
// calculateFee calculates the total fee for signature aggregation // calculateFee calculates the total fee for signature aggregation
func (sa *SignatureAggregator) calculateFee(sigType SignatureType, signerCount int) uint64 { func (sa *SignatureAggregator) calculateFee(sigType SignatureType, signerCount int) uint64 {
var feePerSigner uint64 var feePerSigner uint64
switch sigType { switch sigType {
case SignatureTypeBLS: case SignatureTypeBLS:
feePerSigner = sa.config.BLSFee // 0 for free feePerSigner = sa.config.BLSFee // 0 for free
@@ -462,7 +462,7 @@ func (sa *SignatureAggregator) calculateFee(sigType SignatureType, signerCount i
default: default:
feePerSigner = 0 feePerSigner = 0
} }
return feePerSigner * uint64(signerCount) return feePerSigner * uint64(signerCount)
} }
@@ -474,13 +474,13 @@ func (sa *SignatureAggregator) VerifyAggregatedSignature(
switch aggSig.Type { switch aggSig.Type {
case SignatureTypeBLS: case SignatureTypeBLS:
return sa.verifyBLSAggregate(message, aggSig) return sa.verifyBLSAggregate(message, aggSig)
case SignatureTypeCorona: case SignatureTypeCorona:
return sa.verifyCoronaAggregate(message, aggSig) return sa.verifyCoronaAggregate(message, aggSig)
case SignatureTypeCGGMP21: case SignatureTypeCGGMP21:
return errors.New("CGGMP21 verification not implemented") return errors.New("CGGMP21 verification not implemented")
default: default:
return errors.New("unknown signature type") return errors.New("unknown signature type")
} }
@@ -492,17 +492,17 @@ func (sa *SignatureAggregator) verifyBLSAggregate(message []byte, aggSig *Aggreg
if err != nil { if err != nil {
return err return err
} }
pk, err := bls.PublicKeyFromCompressedBytes(aggSig.AggregateKey) pk, err := bls.PublicKeyFromCompressedBytes(aggSig.AggregateKey)
if err != nil { if err != nil {
return err return err
} }
valid := bls.Verify(pk, sig, message) valid := bls.Verify(pk, sig, message)
if !valid { if !valid {
return errors.New("BLS signature verification failed") return errors.New("BLS signature verification failed")
} }
return nil return nil
} }
@@ -513,7 +513,7 @@ func (sa *SignatureAggregator) verifyCoronaAggregate(message []byte, aggSig *Agg
if len(aggSig.Signature) < 256 { if len(aggSig.Signature) < 256 {
return errors.New("invalid ring signature") return errors.New("invalid ring signature")
} }
return nil return nil
} }
@@ -521,12 +521,12 @@ func (sa *SignatureAggregator) verifyCoronaAggregate(message []byte, aggSig *Agg
func (sa *SignatureAggregator) GetSessionStatus(sessionID string) (map[string]interface{}, error) { func (sa *SignatureAggregator) GetSessionStatus(sessionID string) (map[string]interface{}, error) {
sa.mu.RLock() sa.mu.RLock()
defer sa.mu.RUnlock() defer sa.mu.RUnlock()
session, exists := sa.sessions[sessionID] session, exists := sa.sessions[sessionID]
if !exists { if !exists {
return nil, errors.New("session not found") return nil, errors.New("session not found")
} }
status := map[string]interface{}{ status := map[string]interface{}{
"sessionID": session.SessionID, "sessionID": session.SessionID,
"signatureType": session.SignatureType, "signatureType": session.SignatureType,
@@ -534,11 +534,11 @@ func (sa *SignatureAggregator) GetSessionStatus(sessionID string) (map[string]in
"completed": session.Completed, "completed": session.Completed,
"startTime": session.StartTime, "startTime": session.StartTime,
} }
if session.Completed && session.Result != nil { if session.Completed && session.Result != nil {
status["totalFee"] = session.Result.TotalFee status["totalFee"] = session.Result.TotalFee
} }
return status, nil return status, nil
} }
@@ -546,9 +546,9 @@ func (sa *SignatureAggregator) GetSessionStatus(sessionID string) (map[string]in
func (sa *SignatureAggregator) Cleanup(maxAge int64) { func (sa *SignatureAggregator) Cleanup(maxAge int64) {
sa.mu.Lock() sa.mu.Lock()
defer sa.mu.Unlock() defer sa.mu.Unlock()
currentTime := getCurrentTime() currentTime := getCurrentTime()
for sessionID, session := range sa.sessions { for sessionID, session := range sa.sessions {
if currentTime-session.StartTime > maxAge { if currentTime-session.StartTime > maxAge {
delete(sa.sessions, sessionID) delete(sa.sessions, sessionID)
@@ -559,4 +559,4 @@ func (sa *SignatureAggregator) Cleanup(maxAge int64) {
// Helper function // Helper function
func getCurrentTime() int64 { func getCurrentTime() int64 {
return time.Now().Unix() return time.Now().Unix()
} }
+26 -26
View File
@@ -41,24 +41,24 @@ func TestMLKEMEdgeCases(t *testing.T) {
modes := []mlkem.Mode{mlkem.MLKEM512, mlkem.MLKEM768, mlkem.MLKEM1024} modes := []mlkem.Mode{mlkem.MLKEM512, mlkem.MLKEM768, mlkem.MLKEM1024}
for _, mode := range modes { for _, mode := range modes {
priv1, _, _ := mlkem.GenerateKeyPair(rand.Reader, mode) priv1, _, _ := mlkem.GenerateKeyPair(rand.Reader, mode)
// Serialize // Serialize
privBytes := priv1.Bytes() privBytes := priv1.Bytes()
pubBytes := priv1.PublicKey.Bytes() pubBytes := priv1.PublicKey.Bytes()
// Deserialize // Deserialize
priv2, err := mlkem.PrivateKeyFromBytes(privBytes, mode) priv2, err := mlkem.PrivateKeyFromBytes(privBytes, mode)
require.NoError(t, err) require.NoError(t, err)
pub2, err := mlkem.PublicKeyFromBytes(pubBytes, mode) pub2, err := mlkem.PublicKeyFromBytes(pubBytes, mode)
require.NoError(t, err) require.NoError(t, err)
// Verify they work the same // Verify they work the same
result1, _ := priv1.PublicKey.Encapsulate(rand.Reader) result1, _ := priv1.PublicKey.Encapsulate(rand.Reader)
secret1, _ := priv1.Decapsulate(result1.Ciphertext) secret1, _ := priv1.Decapsulate(result1.Ciphertext)
result2, _ := pub2.Encapsulate(rand.Reader) result2, _ := pub2.Encapsulate(rand.Reader)
secret2, _ := priv2.Decapsulate(result2.Ciphertext) secret2, _ := priv2.Decapsulate(result2.Ciphertext)
// Both should produce valid shared secrets // Both should produce valid shared secrets
assert.Len(t, secret1, 32) assert.Len(t, secret1, 32)
assert.Len(t, secret2, 32) assert.Len(t, secret2, 32)
@@ -69,10 +69,10 @@ func TestMLKEMEdgeCases(t *testing.T) {
// Same private key seed should generate same public key // Same private key seed should generate same public key
privBytes := make([]byte, mlkem.MLKEM768PrivateKeySize) privBytes := make([]byte, mlkem.MLKEM768PrivateKeySize)
copy(privBytes, []byte("deterministic seed for testing")) copy(privBytes, []byte("deterministic seed for testing"))
priv1, _ := mlkem.PrivateKeyFromBytes(privBytes, mlkem.MLKEM768) priv1, _ := mlkem.PrivateKeyFromBytes(privBytes, mlkem.MLKEM768)
priv2, _ := mlkem.PrivateKeyFromBytes(privBytes, mlkem.MLKEM768) priv2, _ := mlkem.PrivateKeyFromBytes(privBytes, mlkem.MLKEM768)
assert.Equal(t, priv1.PublicKey.Bytes(), priv2.PublicKey.Bytes()) assert.Equal(t, priv1.PublicKey.Bytes(), priv2.PublicKey.Bytes())
}) })
} }
@@ -95,7 +95,7 @@ func TestMLDSAEdgeCases(t *testing.T) {
priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65) priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65)
largeMsg := make([]byte, 10000) largeMsg := make([]byte, 10000)
rand.Read(largeMsg) rand.Read(largeMsg)
sig, err := priv.Sign(rand.Reader, largeMsg, nil) sig, err := priv.Sign(rand.Reader, largeMsg, nil)
require.NoError(t, err) require.NoError(t, err)
assert.True(t, priv.PublicKey.Verify(largeMsg, sig, nil)) assert.True(t, priv.PublicKey.Verify(largeMsg, sig, nil))
@@ -104,10 +104,10 @@ func TestMLDSAEdgeCases(t *testing.T) {
t.Run("Signature Malleability", func(t *testing.T) { t.Run("Signature Malleability", func(t *testing.T) {
priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65) priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65)
msg := []byte("test message") msg := []byte("test message")
sig1, _ := priv.Sign(rand.Reader, msg, nil) sig1, _ := priv.Sign(rand.Reader, msg, nil)
sig2, _ := priv.Sign(rand.Reader, msg, nil) sig2, _ := priv.Sign(rand.Reader, msg, nil)
// Signatures should be deterministic in our implementation // Signatures should be deterministic in our implementation
assert.Equal(t, sig1, sig2) assert.Equal(t, sig1, sig2)
}) })
@@ -115,7 +115,7 @@ func TestMLDSAEdgeCases(t *testing.T) {
t.Run("Wrong Signature Size", func(t *testing.T) { t.Run("Wrong Signature Size", func(t *testing.T) {
priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65) priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65)
msg := []byte("test") msg := []byte("test")
wrongSig := make([]byte, 100) // Wrong size wrongSig := make([]byte, 100) // Wrong size
assert.False(t, priv.PublicKey.Verify(msg, wrongSig, nil)) assert.False(t, priv.PublicKey.Verify(msg, wrongSig, nil))
}) })
@@ -124,9 +124,9 @@ func TestMLDSAEdgeCases(t *testing.T) {
priv44, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA44) priv44, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA44)
priv65, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65) priv65, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65)
msg := []byte("test") msg := []byte("test")
sig44, _ := priv44.Sign(rand.Reader, msg, nil) sig44, _ := priv44.Sign(rand.Reader, msg, nil)
// ML-DSA65 key shouldn't verify ML-DSA44 signature // ML-DSA65 key shouldn't verify ML-DSA44 signature
assert.False(t, priv65.PublicKey.Verify(msg, sig44, nil)) assert.False(t, priv65.PublicKey.Verify(msg, sig44, nil))
}) })
@@ -137,10 +137,10 @@ func TestSLHDSAEdgeCases(t *testing.T) {
t.Run("Deterministic Signatures", func(t *testing.T) { t.Run("Deterministic Signatures", func(t *testing.T) {
priv, _ := slhdsa.GenerateKey(rand.Reader, slhdsa.SLHDSA128f) priv, _ := slhdsa.GenerateKey(rand.Reader, slhdsa.SLHDSA128f)
msg := []byte("deterministic test") msg := []byte("deterministic test")
sig1, _ := priv.Sign(rand.Reader, msg, nil) sig1, _ := priv.Sign(rand.Reader, msg, nil)
sig2, _ := priv.Sign(rand.Reader, msg, nil) sig2, _ := priv.Sign(rand.Reader, msg, nil)
// SLH-DSA is deterministic - same message should produce same signature // SLH-DSA is deterministic - same message should produce same signature
assert.Equal(t, sig1, sig2) assert.Equal(t, sig1, sig2)
}) })
@@ -154,13 +154,13 @@ func TestSLHDSAEdgeCases(t *testing.T) {
{slhdsa.SLHDSA128f, "128f", slhdsa.SLHDSA128fSignatureSize}, {slhdsa.SLHDSA128f, "128f", slhdsa.SLHDSA128fSignatureSize},
{slhdsa.SLHDSA192f, "192f", slhdsa.SLHDSA192fSignatureSize}, {slhdsa.SLHDSA192f, "192f", slhdsa.SLHDSA192fSignatureSize},
} }
for _, m := range modes { for _, m := range modes {
t.Run(m.name, func(t *testing.T) { t.Run(m.name, func(t *testing.T) {
priv, _ := slhdsa.GenerateKey(rand.Reader, m.mode) priv, _ := slhdsa.GenerateKey(rand.Reader, m.mode)
msg := []byte("test") msg := []byte("test")
sig, _ := priv.Sign(rand.Reader, msg, nil) sig, _ := priv.Sign(rand.Reader, msg, nil)
assert.Len(t, sig, m.size) assert.Len(t, sig, m.size)
}) })
} }
@@ -171,7 +171,7 @@ func TestSLHDSAEdgeCases(t *testing.T) {
func TestConcurrency(t *testing.T) { func TestConcurrency(t *testing.T) {
t.Run("ML-KEM Concurrent Operations", func(t *testing.T) { t.Run("ML-KEM Concurrent Operations", func(t *testing.T) {
priv, _, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM768) priv, _, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM768)
// Run concurrent encapsulations // Run concurrent encapsulations
done := make(chan bool, 10) done := make(chan bool, 10)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
@@ -184,7 +184,7 @@ func TestConcurrency(t *testing.T) {
done <- true done <- true
}() }()
} }
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
<-done <-done
} }
@@ -192,7 +192,7 @@ func TestConcurrency(t *testing.T) {
t.Run("ML-DSA Concurrent Signing", func(t *testing.T) { t.Run("ML-DSA Concurrent Signing", func(t *testing.T) {
priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65) priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65)
done := make(chan bool, 10) done := make(chan bool, 10)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
go func(id int) { go func(id int) {
@@ -203,7 +203,7 @@ func TestConcurrency(t *testing.T) {
done <- true done <- true
}(i) }(i)
} }
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
<-done <-done
} }
@@ -229,11 +229,11 @@ func TestParameterValidation(t *testing.T) {
assert.Equal(t, 800, mlkem.MLKEM512PublicKeySize) assert.Equal(t, 800, mlkem.MLKEM512PublicKeySize)
assert.Equal(t, 1632, mlkem.MLKEM512PrivateKeySize) assert.Equal(t, 1632, mlkem.MLKEM512PrivateKeySize)
assert.Equal(t, 768, mlkem.MLKEM512CiphertextSize) assert.Equal(t, 768, mlkem.MLKEM512CiphertextSize)
assert.Equal(t, 1184, mlkem.MLKEM768PublicKeySize) assert.Equal(t, 1184, mlkem.MLKEM768PublicKeySize)
assert.Equal(t, 2400, mlkem.MLKEM768PrivateKeySize) assert.Equal(t, 2400, mlkem.MLKEM768PrivateKeySize)
assert.Equal(t, 1088, mlkem.MLKEM768CiphertextSize) assert.Equal(t, 1088, mlkem.MLKEM768CiphertextSize)
assert.Equal(t, 1568, mlkem.MLKEM1024PublicKeySize) assert.Equal(t, 1568, mlkem.MLKEM1024PublicKeySize)
assert.Equal(t, 3168, mlkem.MLKEM1024PrivateKeySize) assert.Equal(t, 3168, mlkem.MLKEM1024PrivateKeySize)
assert.Equal(t, 1568, mlkem.MLKEM1024CiphertextSize) assert.Equal(t, 1568, mlkem.MLKEM1024CiphertextSize)
@@ -242,12 +242,12 @@ func TestParameterValidation(t *testing.T) {
assert.Equal(t, 1312, mldsa.MLDSA44PublicKeySize) assert.Equal(t, 1312, mldsa.MLDSA44PublicKeySize)
assert.Equal(t, 2528, mldsa.MLDSA44PrivateKeySize) assert.Equal(t, 2528, mldsa.MLDSA44PrivateKeySize)
assert.Equal(t, 2420, mldsa.MLDSA44SignatureSize) assert.Equal(t, 2420, mldsa.MLDSA44SignatureSize)
assert.Equal(t, 1952, mldsa.MLDSA65PublicKeySize) assert.Equal(t, 1952, mldsa.MLDSA65PublicKeySize)
assert.Equal(t, 4000, mldsa.MLDSA65PrivateKeySize) assert.Equal(t, 4000, mldsa.MLDSA65PrivateKeySize)
assert.Equal(t, 3293, mldsa.MLDSA65SignatureSize) assert.Equal(t, 3293, mldsa.MLDSA65SignatureSize)
assert.Equal(t, 2592, mldsa.MLDSA87PublicKeySize) assert.Equal(t, 2592, mldsa.MLDSA87PublicKeySize)
assert.Equal(t, 4864, mldsa.MLDSA87PrivateKeySize) assert.Equal(t, 4864, mldsa.MLDSA87PrivateKeySize)
assert.Equal(t, 4595, mldsa.MLDSA87SignatureSize) assert.Equal(t, 4595, mldsa.MLDSA87SignatureSize)
} }
+5 -5
View File
@@ -106,7 +106,7 @@ func (pk *PublicKey) From(blstSK interface{}) *PublicKey {
Compress() []byte Compress() []byte
} }
} }
if sk, ok := blstSK.(blstSecretKey); ok { if sk, ok := blstSK.(blstSecretKey); ok {
pkBytes := sk.PublicKey().Compress() pkBytes := sk.PublicKey().Compress()
newPk, err := PublicKeyFromCompressedBytes(pkBytes) newPk, err := PublicKeyFromCompressedBytes(pkBytes)
@@ -115,7 +115,7 @@ func (pk *PublicKey) From(blstSK interface{}) *PublicKey {
} }
return newPk return newPk
} }
return nil return nil
} }
@@ -268,7 +268,7 @@ func SignatureFromBytes(sigBytes []byte) (*Signature, error) {
allSame = false allSame = false
} }
} }
// Reject signatures that are all zeros or all the same byte (e.g., all 0xFF) // Reject signatures that are all zeros or all the same byte (e.g., all 0xFF)
if allZero || allSame { if allZero || allSame {
return nil, ErrFailedSignatureDecompress return nil, ErrFailedSignatureDecompress
@@ -285,7 +285,7 @@ func (sig *Signature) Sign(blstSK interface{}, msg []byte, dst []byte) *Signatur
Compress() []byte Compress() []byte
} }
} }
if sk, ok := blstSK.(blstSecretKey); ok { if sk, ok := blstSK.(blstSecretKey); ok {
blstSig := sk.Sign(msg, dst, nil) blstSig := sk.Sign(msg, dst, nil)
sigBytes := blstSig.Compress() sigBytes := blstSig.Compress()
@@ -295,7 +295,7 @@ func (sig *Signature) Sign(blstSK interface{}, msg []byte, dst []byte) *Signatur
} }
return newSig return newSig
} }
return nil return nil
} }
+62 -62
View File
@@ -18,13 +18,13 @@ func TestNewSecretKeyExtended(t *testing.T) {
if sk.sk == nil { if sk.sk == nil {
t.Fatal("Internal secret key is nil") t.Fatal("Internal secret key is nil")
} }
// Verify keys are different // Verify keys are different
sk2, err := NewSecretKey() sk2, err := NewSecretKey()
if err != nil { if err != nil {
t.Fatalf("Failed to generate second secret key: %v", err) t.Fatalf("Failed to generate second secret key: %v", err)
} }
bytes1 := SecretKeyToBytes(sk) bytes1 := SecretKeyToBytes(sk)
bytes2 := SecretKeyToBytes(sk2) bytes2 := SecretKeyToBytes(sk2)
if bytes.Equal(bytes1, bytes2) { if bytes.Equal(bytes1, bytes2) {
@@ -39,32 +39,32 @@ func TestSecretKeyBytes(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to generate secret key: %v", err) t.Fatalf("Failed to generate secret key: %v", err)
} }
// Convert to bytes // Convert to bytes
skBytes := SecretKeyToBytes(sk) skBytes := SecretKeyToBytes(sk)
if len(skBytes) == 0 { if len(skBytes) == 0 {
t.Fatal("Secret key bytes should not be empty") t.Fatal("Secret key bytes should not be empty")
} }
// Test nil secret key // Test nil secret key
nilBytes := SecretKeyToBytes(nil) nilBytes := SecretKeyToBytes(nil)
if nilBytes != nil { if nilBytes != nil {
t.Fatal("Nil secret key should return nil bytes") t.Fatal("Nil secret key should return nil bytes")
} }
// Test secret key with nil internal // Test secret key with nil internal
emptyKey := &SecretKey{} emptyKey := &SecretKey{}
emptyBytes := SecretKeyToBytes(emptyKey) emptyBytes := SecretKeyToBytes(emptyKey)
if emptyBytes != nil { if emptyBytes != nil {
t.Fatal("Secret key with nil internal should return nil bytes") t.Fatal("Secret key with nil internal should return nil bytes")
} }
// Round-trip test // Round-trip test
sk2, err := SecretKeyFromBytes(skBytes) sk2, err := SecretKeyFromBytes(skBytes)
if err != nil { if err != nil {
t.Fatalf("Failed to deserialize secret key: %v", err) t.Fatalf("Failed to deserialize secret key: %v", err)
} }
skBytes2 := SecretKeyToBytes(sk2) skBytes2 := SecretKeyToBytes(sk2)
if !bytes.Equal(skBytes, skBytes2) { if !bytes.Equal(skBytes, skBytes2) {
t.Fatal("Round-trip secret key bytes should match") t.Fatal("Round-trip secret key bytes should match")
@@ -78,13 +78,13 @@ func TestSecretKeyFromBytesErrors(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Should fail with invalid bytes") t.Fatal("Should fail with invalid bytes")
} }
// Test with nil bytes // Test with nil bytes
_, err = SecretKeyFromBytes(nil) _, err = SecretKeyFromBytes(nil)
if err == nil { if err == nil {
t.Fatal("Should fail with nil bytes") t.Fatal("Should fail with nil bytes")
} }
// Test with empty bytes // Test with empty bytes
_, err = SecretKeyFromBytes([]byte{}) _, err = SecretKeyFromBytes([]byte{})
if err == nil { if err == nil {
@@ -97,7 +97,7 @@ func TestPublicKeyOperations(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to generate secret key: %v", err) t.Fatalf("Failed to generate secret key: %v", err)
} }
// Get public key // Get public key
pk := sk.PublicKey() pk := sk.PublicKey()
if pk == nil { if pk == nil {
@@ -106,14 +106,14 @@ func TestPublicKeyOperations(t *testing.T) {
if pk.pk == nil { if pk.pk == nil {
t.Fatal("Internal public key should not be nil") t.Fatal("Internal public key should not be nil")
} }
// Test nil secret key // Test nil secret key
var nilSk *SecretKey var nilSk *SecretKey
nilPk := nilSk.PublicKey() nilPk := nilSk.PublicKey()
if nilPk != nil { if nilPk != nil {
t.Fatal("Nil secret key should return nil public key") t.Fatal("Nil secret key should return nil public key")
} }
// Test secret key with nil internal // Test secret key with nil internal
emptySk := &SecretKey{} emptySk := &SecretKey{}
emptyPk := emptySk.PublicKey() emptyPk := emptySk.PublicKey()
@@ -127,27 +127,27 @@ func TestPublicKeyBytes(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to generate secret key: %v", err) t.Fatalf("Failed to generate secret key: %v", err)
} }
pk := sk.PublicKey() pk := sk.PublicKey()
// Test compressed bytes // Test compressed bytes
compressedBytes := PublicKeyToCompressedBytes(pk) compressedBytes := PublicKeyToCompressedBytes(pk)
if len(compressedBytes) != PublicKeyLen { if len(compressedBytes) != PublicKeyLen {
t.Fatalf("Compressed public key should be %d bytes, got %d", PublicKeyLen, len(compressedBytes)) t.Fatalf("Compressed public key should be %d bytes, got %d", PublicKeyLen, len(compressedBytes))
} }
// Test uncompressed bytes (should be same as compressed for circl) // Test uncompressed bytes (should be same as compressed for circl)
uncompressedBytes := PublicKeyToUncompressedBytes(pk) uncompressedBytes := PublicKeyToUncompressedBytes(pk)
if !bytes.Equal(compressedBytes, uncompressedBytes) { if !bytes.Equal(compressedBytes, uncompressedBytes) {
t.Fatal("Compressed and uncompressed should be equal for circl BLS") t.Fatal("Compressed and uncompressed should be equal for circl BLS")
} }
// Test nil public key // Test nil public key
nilBytes := PublicKeyToCompressedBytes(nil) nilBytes := PublicKeyToCompressedBytes(nil)
if nilBytes != nil { if nilBytes != nil {
t.Fatal("Nil public key should return nil bytes") t.Fatal("Nil public key should return nil bytes")
} }
// Test public key with nil internal // Test public key with nil internal
emptyPk := &PublicKey{} emptyPk := &PublicKey{}
emptyBytes := PublicKeyToCompressedBytes(emptyPk) emptyBytes := PublicKeyToCompressedBytes(emptyPk)
@@ -161,21 +161,21 @@ func TestPublicKeyFromBytes(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to generate secret key: %v", err) t.Fatalf("Failed to generate secret key: %v", err)
} }
pk := sk.PublicKey() pk := sk.PublicKey()
pkBytes := PublicKeyToCompressedBytes(pk) pkBytes := PublicKeyToCompressedBytes(pk)
// Test valid deserialization // Test valid deserialization
pk2, err := PublicKeyFromCompressedBytes(pkBytes) pk2, err := PublicKeyFromCompressedBytes(pkBytes)
if err != nil { if err != nil {
t.Fatalf("Failed to deserialize public key: %v", err) t.Fatalf("Failed to deserialize public key: %v", err)
} }
pkBytes2 := PublicKeyToCompressedBytes(pk2) pkBytes2 := PublicKeyToCompressedBytes(pk2)
if !bytes.Equal(pkBytes, pkBytes2) { if !bytes.Equal(pkBytes, pkBytes2) {
t.Fatal("Round-trip public key bytes should match") t.Fatal("Round-trip public key bytes should match")
} }
// Test from valid uncompressed bytes // Test from valid uncompressed bytes
pk3 := PublicKeyFromValidUncompressedBytes(pkBytes) pk3 := PublicKeyFromValidUncompressedBytes(pkBytes)
if pk3 == nil { if pk3 == nil {
@@ -194,13 +194,13 @@ func TestPublicKeyFromBytesErrors(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Should fail with wrong size bytes") t.Fatal("Should fail with wrong size bytes")
} }
// Test with nil // Test with nil
_, err = PublicKeyFromCompressedBytes(nil) _, err = PublicKeyFromCompressedBytes(nil)
if err == nil { if err == nil {
t.Fatal("Should fail with nil bytes") t.Fatal("Should fail with nil bytes")
} }
// Test with invalid point (all zeros) // Test with invalid point (all zeros)
zeroBytes := make([]byte, PublicKeyLen) zeroBytes := make([]byte, PublicKeyLen)
_, err = PublicKeyFromCompressedBytes(zeroBytes) _, err = PublicKeyFromCompressedBytes(zeroBytes)
@@ -214,10 +214,10 @@ func TestSignAndVerify(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to generate secret key: %v", err) t.Fatalf("Failed to generate secret key: %v", err)
} }
pk := sk.PublicKey() pk := sk.PublicKey()
msg := []byte("test message") msg := []byte("test message")
// Sign message // Sign message
sig, err := sk.Sign(msg) sig, err := sk.Sign(msg)
if err != nil { if err != nil {
@@ -226,20 +226,20 @@ func TestSignAndVerify(t *testing.T) {
if sig == nil { if sig == nil {
t.Fatal("Signature should not be nil") t.Fatal("Signature should not be nil")
} }
// Verify signature // Verify signature
valid := Verify(pk, sig, msg) valid := Verify(pk, sig, msg)
if !valid { if !valid {
t.Fatal("Signature should be valid") t.Fatal("Signature should be valid")
} }
// Verify with wrong message // Verify with wrong message
wrongMsg := []byte("wrong message") wrongMsg := []byte("wrong message")
valid = Verify(pk, sig, wrongMsg) valid = Verify(pk, sig, wrongMsg)
if valid { if valid {
t.Fatal("Signature should be invalid for wrong message") t.Fatal("Signature should be invalid for wrong message")
} }
// Verify with wrong public key // Verify with wrong public key
sk2, _ := NewSecretKey() sk2, _ := NewSecretKey()
pk2 := sk2.PublicKey() pk2 := sk2.PublicKey()
@@ -247,7 +247,7 @@ func TestSignAndVerify(t *testing.T) {
if valid { if valid {
t.Fatal("Signature should be invalid for wrong public key") t.Fatal("Signature should be invalid for wrong public key")
} }
// Test nil cases // Test nil cases
nilSig, err := sk.Sign(nil) nilSig, err := sk.Sign(nil)
if err != nil { if err != nil {
@@ -256,7 +256,7 @@ func TestSignAndVerify(t *testing.T) {
if nilSig == nil { if nilSig == nil {
t.Fatal("Should handle nil message") t.Fatal("Should handle nil message")
} }
var nilSk *SecretKey var nilSk *SecretKey
nilSig2, err := nilSk.Sign(msg) nilSig2, err := nilSk.Sign(msg)
if err == nil { if err == nil {
@@ -265,7 +265,7 @@ func TestSignAndVerify(t *testing.T) {
if nilSig2 != nil { if nilSig2 != nil {
t.Fatal("Nil secret key should return nil signature") t.Fatal("Nil secret key should return nil signature")
} }
emptySk := &SecretKey{} emptySk := &SecretKey{}
emptySig, err := emptySk.Sign(msg) emptySig, err := emptySk.Sign(msg)
if err == nil { if err == nil {
@@ -281,20 +281,20 @@ func TestVerifyEdgeCases(t *testing.T) {
pk := sk.PublicKey() pk := sk.PublicKey()
msg := []byte("test") msg := []byte("test")
sig, _ := sk.Sign(msg) sig, _ := sk.Sign(msg)
// Test nil public key // Test nil public key
valid := Verify(nil, sig, msg) valid := Verify(nil, sig, msg)
if valid { if valid {
t.Fatal("Should fail with nil public key") t.Fatal("Should fail with nil public key")
} }
// Test public key with nil internal // Test public key with nil internal
emptyPk := &PublicKey{} emptyPk := &PublicKey{}
valid = Verify(emptyPk, sig, msg) valid = Verify(emptyPk, sig, msg)
if valid { if valid {
t.Fatal("Should fail with empty public key") t.Fatal("Should fail with empty public key")
} }
// Test nil signature // Test nil signature
valid = Verify(pk, nil, msg) valid = Verify(pk, nil, msg)
if valid { if valid {
@@ -307,10 +307,10 @@ func TestProofOfPossession(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to generate secret key: %v", err) t.Fatalf("Failed to generate secret key: %v", err)
} }
pk := sk.PublicKey() pk := sk.PublicKey()
msg := []byte("proof of possession") msg := []byte("proof of possession")
// Sign proof of possession // Sign proof of possession
sig, err := sk.SignProofOfPossession(msg) sig, err := sk.SignProofOfPossession(msg)
if err != nil { if err != nil {
@@ -319,20 +319,20 @@ func TestProofOfPossession(t *testing.T) {
if sig == nil { if sig == nil {
t.Fatal("PoP signature should not be nil") t.Fatal("PoP signature should not be nil")
} }
// Verify proof of possession // Verify proof of possession
valid := VerifyProofOfPossession(pk, sig, msg) valid := VerifyProofOfPossession(pk, sig, msg)
if !valid { if !valid {
t.Fatal("PoP should be valid") t.Fatal("PoP should be valid")
} }
// Test with wrong message // Test with wrong message
wrongMsg := []byte("wrong") wrongMsg := []byte("wrong")
valid = VerifyProofOfPossession(pk, sig, wrongMsg) valid = VerifyProofOfPossession(pk, sig, wrongMsg)
if valid { if valid {
t.Fatal("PoP should be invalid for wrong message") t.Fatal("PoP should be invalid for wrong message")
} }
// Test nil cases // Test nil cases
var nilSk *SecretKey var nilSk *SecretKey
nilSig, err := nilSk.SignProofOfPossession(msg) nilSig, err := nilSk.SignProofOfPossession(msg)
@@ -342,7 +342,7 @@ func TestProofOfPossession(t *testing.T) {
if nilSig != nil { if nilSig != nil {
t.Fatal("Nil secret key should return nil PoP") t.Fatal("Nil secret key should return nil PoP")
} }
emptySk := &SecretKey{} emptySk := &SecretKey{}
emptySig, err := emptySk.SignProofOfPossession(msg) emptySig, err := emptySk.SignProofOfPossession(msg)
if err == nil { if err == nil {
@@ -361,25 +361,25 @@ func TestSignatureBytes(t *testing.T) {
msg := []byte("test") msg := []byte("test")
sig, _ := sk.Sign(msg) sig, _ := sk.Sign(msg)
// Convert to bytes // Convert to bytes
sigBytes := SignatureToBytes(sig) sigBytes := SignatureToBytes(sig)
if len(sigBytes) != SignatureLen { if len(sigBytes) != SignatureLen {
t.Fatalf("Signature should be %d bytes, got %d", SignatureLen, len(sigBytes)) t.Fatalf("Signature should be %d bytes, got %d", SignatureLen, len(sigBytes))
} }
// Test nil signature // Test nil signature
nilBytes := SignatureToBytes(nil) nilBytes := SignatureToBytes(nil)
if nilBytes != nil { if nilBytes != nil {
t.Fatal("Nil signature should return nil bytes") t.Fatal("Nil signature should return nil bytes")
} }
// Round-trip test // Round-trip test
sig2, err := SignatureFromBytes(sigBytes) sig2, err := SignatureFromBytes(sigBytes)
if err != nil { if err != nil {
t.Fatalf("Failed to deserialize signature: %v", err) t.Fatalf("Failed to deserialize signature: %v", err)
} }
sigBytes2 := SignatureToBytes(sig2) sigBytes2 := SignatureToBytes(sig2)
if !bytes.Equal(sigBytes, sigBytes2) { if !bytes.Equal(sigBytes, sigBytes2) {
t.Fatal("Round-trip signature bytes should match") t.Fatal("Round-trip signature bytes should match")
@@ -393,14 +393,14 @@ func TestSignatureFromBytesErrors(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Should fail with wrong size") t.Fatal("Should fail with wrong size")
} }
// Test all zeros (invalid signature) // Test all zeros (invalid signature)
zeroBytes := make([]byte, SignatureLen) zeroBytes := make([]byte, SignatureLen)
_, err = SignatureFromBytes(zeroBytes) _, err = SignatureFromBytes(zeroBytes)
if err == nil { if err == nil {
t.Fatal("Should fail with all zero bytes") t.Fatal("Should fail with all zero bytes")
} }
// Test nil // Test nil
_, err = SignatureFromBytes(nil) _, err = SignatureFromBytes(nil)
if err == nil { if err == nil {
@@ -414,16 +414,16 @@ func TestAggregatePublicKeysEdgeCases(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Should fail with empty slice") t.Fatal("Should fail with empty slice")
} }
// Test with nil public key in slice // Test with nil public key in slice
sk1, _ := NewSecretKey() sk1, _ := NewSecretKey()
pk1 := sk1.PublicKey() pk1 := sk1.PublicKey()
_, err = AggregatePublicKeys([]*PublicKey{pk1, nil}) _, err = AggregatePublicKeys([]*PublicKey{pk1, nil})
if err == nil { if err == nil {
t.Fatal("Should fail with nil public key in slice") t.Fatal("Should fail with nil public key in slice")
} }
// Test with public key with nil internal // Test with public key with nil internal
emptyPk := &PublicKey{} emptyPk := &PublicKey{}
_, err = AggregatePublicKeys([]*PublicKey{pk1, emptyPk}) _, err = AggregatePublicKeys([]*PublicKey{pk1, emptyPk})
@@ -438,12 +438,12 @@ func TestAggregateSignaturesEdgeCases(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Should fail with empty slice") t.Fatal("Should fail with empty slice")
} }
// Test with nil signature in slice // Test with nil signature in slice
sk1, _ := NewSecretKey() sk1, _ := NewSecretKey()
msg := []byte("test") msg := []byte("test")
sig1, _ := sk1.Sign(msg) sig1, _ := sk1.Sign(msg)
_, err = AggregateSignatures([]*Signature{sig1, nil}) _, err = AggregateSignatures([]*Signature{sig1, nil})
if err == nil { if err == nil {
t.Fatal("Should fail with nil signature in slice") t.Fatal("Should fail with nil signature in slice")
@@ -456,9 +456,9 @@ func TestMultipleAggregation(t *testing.T) {
sks := make([]*SecretKey, numKeys) sks := make([]*SecretKey, numKeys)
pks := make([]*PublicKey, numKeys) pks := make([]*PublicKey, numKeys)
sigs := make([]*Signature, numKeys) sigs := make([]*Signature, numKeys)
msg := []byte("aggregate test message") msg := []byte("aggregate test message")
for i := 0; i < numKeys; i++ { for i := 0; i < numKeys; i++ {
sk, err := NewSecretKey() sk, err := NewSecretKey()
if err != nil { if err != nil {
@@ -468,7 +468,7 @@ func TestMultipleAggregation(t *testing.T) {
pks[i] = sk.PublicKey() pks[i] = sk.PublicKey()
sigs[i], _ = sk.Sign(msg) sigs[i], _ = sk.Sign(msg)
} }
// Aggregate public keys // Aggregate public keys
aggPk, err := AggregatePublicKeys(pks) aggPk, err := AggregatePublicKeys(pks)
if err != nil { if err != nil {
@@ -477,7 +477,7 @@ func TestMultipleAggregation(t *testing.T) {
if aggPk == nil { if aggPk == nil {
t.Fatal("Aggregated public key should not be nil") t.Fatal("Aggregated public key should not be nil")
} }
// Aggregate signatures // Aggregate signatures
aggSig, err := AggregateSignatures(sigs) aggSig, err := AggregateSignatures(sigs)
if err != nil { if err != nil {
@@ -486,7 +486,7 @@ func TestMultipleAggregation(t *testing.T) {
if aggSig == nil { if aggSig == nil {
t.Fatal("Aggregated signature should not be nil") t.Fatal("Aggregated signature should not be nil")
} }
// Verify aggregated signature // Verify aggregated signature
valid := Verify(aggPk, aggSig, msg) valid := Verify(aggPk, aggSig, msg)
if !valid { if !valid {
@@ -506,7 +506,7 @@ func BenchmarkKeyGenerationExtended(b *testing.B) {
func BenchmarkSignExtended(b *testing.B) { func BenchmarkSignExtended(b *testing.B) {
sk, _ := NewSecretKey() sk, _ := NewSecretKey()
msg := []byte("benchmark message") msg := []byte("benchmark message")
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = sk.Sign(msg) _, _ = sk.Sign(msg)
@@ -528,12 +528,12 @@ func BenchmarkVerifyExtended(b *testing.B) {
func BenchmarkAggregatePublicKeysExtended(b *testing.B) { func BenchmarkAggregatePublicKeysExtended(b *testing.B) {
numKeys := 10 numKeys := 10
pks := make([]*PublicKey, numKeys) pks := make([]*PublicKey, numKeys)
for i := 0; i < numKeys; i++ { for i := 0; i < numKeys; i++ {
sk, _ := NewSecretKey() sk, _ := NewSecretKey()
pks[i] = sk.PublicKey() pks[i] = sk.PublicKey()
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = AggregatePublicKeys(pks) _, _ = AggregatePublicKeys(pks)
@@ -544,14 +544,14 @@ func BenchmarkAggregateSignaturesExtended(b *testing.B) {
numSigs := 10 numSigs := 10
sigs := make([]*Signature, numSigs) sigs := make([]*Signature, numSigs)
msg := []byte("benchmark") msg := []byte("benchmark")
for i := 0; i < numSigs; i++ { for i := 0; i < numSigs; i++ {
sk, _ := NewSecretKey() sk, _ := NewSecretKey()
sigs[i], _ = sk.Sign(msg) sigs[i], _ = sk.Sign(msg)
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = AggregateSignatures(sigs) _, _ = AggregateSignatures(sigs)
} }
} }
+1 -1
View File
@@ -574,4 +574,4 @@ func BenchmarkAggregateSignatures(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = AggregateSignatures(sigs) _, _ = AggregateSignatures(sigs)
} }
} }
+1 -1
View File
@@ -8,8 +8,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/luxfi/node/cache"
"github.com/luxfi/ids" "github.com/luxfi/ids"
"github.com/luxfi/node/cache"
) )
const IntSize = ids.IDLen + 8 const IntSize = ids.IDLen + 8
+1 -1
View File
@@ -6,8 +6,8 @@ package lru
import ( import (
"testing" "testing"
"github.com/luxfi/node/cache/cachetest"
"github.com/luxfi/ids" "github.com/luxfi/ids"
"github.com/luxfi/node/cache/cachetest"
) )
func TestCache(t *testing.T) { func TestCache(t *testing.T) {
+1 -1
View File
@@ -8,8 +8,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/luxfi/node/cache/cachetest"
"github.com/luxfi/ids" "github.com/luxfi/ids"
"github.com/luxfi/node/cache/cachetest"
) )
func TestSizedCache(t *testing.T) { func TestSizedCache(t *testing.T) {
+1 -1
View File
@@ -8,9 +8,9 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/luxfi/ids"
"github.com/luxfi/node/cache" "github.com/luxfi/node/cache"
"github.com/luxfi/node/cache/cachetest" "github.com/luxfi/node/cache/cachetest"
"github.com/luxfi/ids"
) )
func TestLRU(t *testing.T) { func TestLRU(t *testing.T) {
+1 -1
View File
@@ -8,9 +8,9 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/luxfi/ids"
"github.com/luxfi/node/cache" "github.com/luxfi/node/cache"
"github.com/luxfi/node/cache/cachetest" "github.com/luxfi/node/cache/cachetest"
"github.com/luxfi/ids"
) )
func TestSizedLRU(t *testing.T) { func TestSizedLRU(t *testing.T) {
-1
View File
@@ -17,7 +17,6 @@ import (
"github.com/luxfi/node/cache" "github.com/luxfi/node/cache"
"github.com/luxfi/node/cache/cachetest" "github.com/luxfi/node/cache/cachetest"
"github.com/luxfi/node/cache/lru" "github.com/luxfi/node/cache/lru"
"github.com/luxfi/ids"
) )
func TestInterface(t *testing.T) { func TestInterface(t *testing.T) {
+1 -1
View File
@@ -69,4 +69,4 @@ func newMetrics(
), ),
} }
return m, nil return m, nil
} }
+19 -19
View File
@@ -24,7 +24,7 @@ type MLDSACert struct {
KeyUsage x509.KeyUsage KeyUsage x509.KeyUsage
ExtKeyUsage []x509.ExtKeyUsage ExtKeyUsage []x509.ExtKeyUsage
IsCA bool IsCA bool
// Custom extensions for QZMQ // Custom extensions for QZMQ
NodeID string NodeID string
Capabilities []string Capabilities []string
@@ -54,34 +54,34 @@ func (cp *CertPool) VerifyChain(chain []*MLDSACert, now time.Time) error {
if len(chain) == 0 { if len(chain) == 0 {
return errors.New("empty certificate chain") return errors.New("empty certificate chain")
} }
// Verify leaf certificate // Verify leaf certificate
leaf := chain[0] leaf := chain[0]
if now.Before(leaf.NotBefore) || now.After(leaf.NotAfter) { if now.Before(leaf.NotBefore) || now.After(leaf.NotAfter) {
return errors.New("certificate expired or not yet valid") return errors.New("certificate expired or not yet valid")
} }
// Verify chain // Verify chain
for i := 0; i < len(chain)-1; i++ { for i := 0; i < len(chain)-1; i++ {
cert := chain[i] cert := chain[i]
issuer := chain[i+1] issuer := chain[i+1]
if err := verifyCertSignature(cert, issuer); err != nil { if err := verifyCertSignature(cert, issuer); err != nil {
return fmt.Errorf("invalid signature at position %d: %w", i, err) return fmt.Errorf("invalid signature at position %d: %w", i, err)
} }
if !issuer.IsCA { if !issuer.IsCA {
return fmt.Errorf("issuer at position %d is not a CA", i+1) return fmt.Errorf("issuer at position %d is not a CA", i+1)
} }
} }
// Verify root is trusted // Verify root is trusted
root := chain[len(chain)-1] root := chain[len(chain)-1]
spkiHash := hashSPKI(root.PublicKey.Bytes()) spkiHash := hashSPKI(root.PublicKey.Bytes())
if _, ok := cp.certs[spkiHash]; !ok { if _, ok := cp.certs[spkiHash]; !ok {
return errors.New("root certificate not trusted") return errors.New("root certificate not trusted")
} }
return nil return nil
} }
@@ -182,21 +182,21 @@ func (cb *CertBuilder) SetCA(isCA bool) *CertBuilder {
func (cb *CertBuilder) Build(publicKey sign.PublicKey, issuerKey sign.PrivateKey) (*MLDSACert, error) { func (cb *CertBuilder) Build(publicKey sign.PublicKey, issuerKey sign.PrivateKey) (*MLDSACert, error) {
cert := *cb.template cert := *cb.template
cert.PublicKey = publicKey cert.PublicKey = publicKey
// Generate serial number // Generate serial number
cert.SerialNumber = generateSerialNumber() cert.SerialNumber = generateSerialNumber()
// Self-signed if no issuer provided // Self-signed if no issuer provided
if issuerKey == nil { if issuerKey == nil {
cert.Issuer = cert.Subject cert.Issuer = cert.Subject
} }
// Encode to DER // Encode to DER
certBytes, err := encodeCertificate(&cert) certBytes, err := encodeCertificate(&cert)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Sign the certificate // Sign the certificate
if issuerKey != nil { if issuerKey != nil {
signature, err := cb.signer.Sign(issuerKey, certBytes) signature, err := cb.signer.Sign(issuerKey, certBytes)
@@ -208,7 +208,7 @@ func (cb *CertBuilder) Build(publicKey sign.PublicKey, issuerKey sign.PrivateKey
} else { } else {
cert.Raw = certBytes cert.Raw = certBytes
} }
return &cert, nil return &cert, nil
} }
@@ -220,7 +220,7 @@ func encodeCertificate(cert *MLDSACert) ([]byte, error) {
encoded = append(encoded, cert.PublicKey.Bytes()...) encoded = append(encoded, cert.PublicKey.Bytes()...)
encoded = append(encoded, []byte(cert.NodeID)...) encoded = append(encoded, []byte(cert.NodeID)...)
encoded = append(encoded, []byte(cert.Role)...) encoded = append(encoded, []byte(cert.Role)...)
return encoded, nil return encoded, nil
} }
@@ -234,22 +234,22 @@ func generateSerialNumber() []byte {
func ParseMLDSACert(der []byte) (*MLDSACert, error) { func ParseMLDSACert(der []byte) (*MLDSACert, error) {
// Placeholder parser // Placeholder parser
// In production, would parse actual DER-encoded certificate // In production, would parse actual DER-encoded certificate
cert := &MLDSACert{ cert := &MLDSACert{
Raw: der, Raw: der,
} }
// Parse basic fields (placeholder) // Parse basic fields (placeholder)
if len(der) < 100 { if len(der) < 100 {
return nil, errors.New("certificate too short") return nil, errors.New("certificate too short")
} }
return cert, nil return cert, nil
} }
// OID definitions for ML-DSA algorithms // OID definitions for ML-DSA algorithms
var ( var (
OIDMLDSA44 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 2, 267, 7, 6, 5} // ML-DSA-44 OIDMLDSA44 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 2, 267, 7, 6, 5} // ML-DSA-44
OIDMLDSA65 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 2, 267, 7, 8, 7} // ML-DSA-65 OIDMLDSA65 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 2, 267, 7, 8, 7} // ML-DSA-65
OIDMLDSA87 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 2, 267, 7, 10, 8} // ML-DSA-87 OIDMLDSA87 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 2, 267, 7, 10, 8} // ML-DSA-87
) )
+90 -90
View File
@@ -28,64 +28,64 @@ type Signature struct {
// Config contains CGGMP21 protocol configuration // Config contains CGGMP21 protocol configuration
type Config struct { type Config struct {
Threshold int // t: Threshold (t+1 parties needed to sign) Threshold int // t: Threshold (t+1 parties needed to sign)
TotalParties int // n: Total number of parties TotalParties int // n: Total number of parties
Curve elliptic.Curve Curve elliptic.Curve
SessionTimeout int64 // Timeout for protocol rounds SessionTimeout int64 // Timeout for protocol rounds
} }
// Party represents a participant in the CGGMP21 protocol // Party represents a participant in the CGGMP21 protocol
type Party struct { type Party struct {
ID ids.NodeID ID ids.NodeID
Index int Index int
Config *Config Config *Config
// Key material // Key material
Xi *big.Int // Secret key share Xi *big.Int // Secret key share
PublicKey *ecdsa.PublicKey // Group public key PublicKey *ecdsa.PublicKey // Group public key
PublicShares map[int]*big.Int // Public key shares from all parties PublicShares map[int]*big.Int // Public key shares from all parties
// Paillier keys for ZK proofs // Paillier keys for ZK proofs
PaillierSK *PaillierPrivateKey PaillierSK *PaillierPrivateKey
PaillierPKs map[int]*PaillierPublicKey PaillierPKs map[int]*PaillierPublicKey
// Session state // Session state
sessions map[string]*SigningSession sessions map[string]*SigningSession
log log.Logger log log.Logger
mu sync.RWMutex mu sync.RWMutex
} }
// SigningSession represents an active signing session // SigningSession represents an active signing session
type SigningSession struct { type SigningSession struct {
SessionID string SessionID string
Message []byte Message []byte
MessageHash *big.Int MessageHash *big.Int
// Round 1: Commitment // Round 1: Commitment
Ki *big.Int // k_i (nonce share) Ki *big.Int // k_i (nonce share)
Gammai *big.Int // gamma_i (random mask) Gammai *big.Int // gamma_i (random mask)
CommitmentSent bool CommitmentSent bool
Commitments map[int][]byte // Received commitments Commitments map[int][]byte // Received commitments
// Round 2: Reveal // Round 2: Reveal
RevealsSent bool RevealsSent bool
GammaShares map[int]*big.Int // gamma_j values GammaShares map[int]*big.Int // gamma_j values
BigGammaShares map[int]*ECPoint // [gamma_j]G points BigGammaShares map[int]*ECPoint // [gamma_j]G points
// Round 3: Multiplication // Round 3: Multiplication
DeltaShare *big.Int // delta_i = k_i * gamma_i DeltaShare *big.Int // delta_i = k_i * gamma_i
ChiShare *big.Int // chi_i = x_i * k_i ChiShare *big.Int // chi_i = x_i * k_i
BigDeltaShares map[int]*ECPoint // [delta_j]G points BigDeltaShares map[int]*ECPoint // [delta_j]G points
// Round 4: Opening // Round 4: Opening
Deltas map[int]*big.Int // delta_j values Deltas map[int]*big.Int // delta_j values
BigRx *ECPoint // R_x point BigRx *ECPoint // R_x point
// Final signature // Final signature
R *big.Int R *big.Int
S *big.Int S *big.Int
// Abort handling // Abort handling
AbortingParties []int AbortingParties []int
} }
@@ -100,13 +100,13 @@ func NewParty(id ids.NodeID, index int, config *Config, log log.Logger) (*Party,
if index < 0 || index >= config.TotalParties { if index < 0 || index >= config.TotalParties {
return nil, errors.New("invalid party index") return nil, errors.New("invalid party index")
} }
// Generate Paillier keypair for ZK proofs // Generate Paillier keypair for ZK proofs
paillierSK, paillierPK, err := GeneratePaillierKeyPair(2048) paillierSK, paillierPK, err := GeneratePaillierKeyPair(2048)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to generate Paillier keys: %w", err) return nil, fmt.Errorf("failed to generate Paillier keys: %w", err)
} }
return &Party{ return &Party{
ID: id, ID: id,
Index: index, Index: index,
@@ -123,30 +123,30 @@ func NewParty(id ids.NodeID, index int, config *Config, log log.Logger) (*Party,
func (p *Party) KeyGen(parties []int) error { func (p *Party) KeyGen(parties []int) error {
p.mu.Lock() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
// Generate secret share // Generate secret share
xi, err := rand.Int(rand.Reader, p.Config.Curve.Params().N) xi, err := rand.Int(rand.Reader, p.Config.Curve.Params().N)
if err != nil { if err != nil {
return err return err
} }
p.Xi = xi p.Xi = xi
// Compute public key share [x_i]G // Compute public key share [x_i]G
Xi := ScalarBaseMult(p.Config.Curve, xi) Xi := ScalarBaseMult(p.Config.Curve, xi)
p.PublicShares[p.Index] = Xi.X p.PublicShares[p.Index] = Xi.X
// In practice, this would involve communication rounds // In practice, this would involve communication rounds
// For now, we simulate having received all shares // For now, we simulate having received all shares
// Compute group public key (would be sum of all shares) // Compute group public key (would be sum of all shares)
// Y = sum([x_i]G) for all i // Y = sum([x_i]G) for all i
p.log.Info("Key generation completed", p.log.Info("Key generation completed",
log.Stringer("partyID", p.ID), log.Stringer("partyID", p.ID),
log.Int("index", p.Index), log.Int("index", p.Index),
log.Int("threshold", p.Config.Threshold), log.Int("threshold", p.Config.Threshold),
) )
return nil return nil
} }
@@ -154,15 +154,15 @@ func (p *Party) KeyGen(parties []int) error {
func (p *Party) InitiateSign(sessionID string, message []byte) (*SigningSession, error) { func (p *Party) InitiateSign(sessionID string, message []byte) (*SigningSession, error) {
p.mu.Lock() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
if _, exists := p.sessions[sessionID]; exists { if _, exists := p.sessions[sessionID]; exists {
return nil, errors.New("session already exists") return nil, errors.New("session already exists")
} }
// Hash the message // Hash the message
h := sha256.Sum256(message) h := sha256.Sum256(message)
messageHash := new(big.Int).SetBytes(h[:]) messageHash := new(big.Int).SetBytes(h[:])
session := &SigningSession{ session := &SigningSession{
SessionID: sessionID, SessionID: sessionID,
Message: message, Message: message,
@@ -173,9 +173,9 @@ func (p *Party) InitiateSign(sessionID string, message []byte) (*SigningSession,
BigDeltaShares: make(map[int]*ECPoint), BigDeltaShares: make(map[int]*ECPoint),
Deltas: make(map[int]*big.Int), Deltas: make(map[int]*big.Int),
} }
p.sessions[sessionID] = session p.sessions[sessionID] = session
return session, nil return session, nil
} }
@@ -183,16 +183,16 @@ func (p *Party) InitiateSign(sessionID string, message []byte) (*SigningSession,
func (p *Party) Round1_Commitment(sessionID string) ([]byte, error) { func (p *Party) Round1_Commitment(sessionID string) ([]byte, error) {
p.mu.Lock() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
session, exists := p.sessions[sessionID] session, exists := p.sessions[sessionID]
if !exists { if !exists {
return nil, errors.New("session not found") return nil, errors.New("session not found")
} }
if session.CommitmentSent { if session.CommitmentSent {
return nil, errors.New("commitment already sent") return nil, errors.New("commitment already sent")
} }
// Generate k_i and gamma_i // Generate k_i and gamma_i
ki, err := rand.Int(rand.Reader, p.Config.Curve.Params().N) ki, err := rand.Int(rand.Reader, p.Config.Curve.Params().N)
if err != nil { if err != nil {
@@ -202,16 +202,16 @@ func (p *Party) Round1_Commitment(sessionID string) ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
session.Ki = ki session.Ki = ki
session.Gammai = gammai session.Gammai = gammai
// Compute commitment = H(i, [gamma_i]G) // Compute commitment = H(i, [gamma_i]G)
bigGammai := ScalarBaseMult(p.Config.Curve, gammai) bigGammai := ScalarBaseMult(p.Config.Curve, gammai)
commitment := p.computeCommitment(p.Index, bigGammai) commitment := p.computeCommitment(p.Index, bigGammai)
session.CommitmentSent = true session.CommitmentSent = true
return commitment, nil return commitment, nil
} }
@@ -219,34 +219,34 @@ func (p *Party) Round1_Commitment(sessionID string) ([]byte, error) {
func (p *Party) Round2_Reveal(sessionID string, commitments map[int][]byte) (*Round2Message, error) { func (p *Party) Round2_Reveal(sessionID string, commitments map[int][]byte) (*Round2Message, error) {
p.mu.Lock() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
session, exists := p.sessions[sessionID] session, exists := p.sessions[sessionID]
if !exists { if !exists {
return nil, errors.New("session not found") return nil, errors.New("session not found")
} }
if session.RevealsSent { if session.RevealsSent {
return nil, errors.New("reveals already sent") return nil, errors.New("reveals already sent")
} }
// Store commitments // Store commitments
for idx, comm := range commitments { for idx, comm := range commitments {
if idx != p.Index { if idx != p.Index {
session.Commitments[idx] = comm session.Commitments[idx] = comm
} }
} }
// Create reveal message // Create reveal message
bigGammai := ScalarBaseMult(p.Config.Curve, session.Gammai) bigGammai := ScalarBaseMult(p.Config.Curve, session.Gammai)
msg := &Round2Message{ msg := &Round2Message{
FromIndex: p.Index, FromIndex: p.Index,
BigGammaI: bigGammai, BigGammaI: bigGammai,
// In production, include ZK proofs here // In production, include ZK proofs here
} }
session.RevealsSent = true session.RevealsSent = true
return msg, nil return msg, nil
} }
@@ -254,45 +254,45 @@ func (p *Party) Round2_Reveal(sessionID string, commitments map[int][]byte) (*Ro
func (p *Party) Round3_Multiply(sessionID string, reveals map[int]*Round2Message) (*Round3Message, error) { func (p *Party) Round3_Multiply(sessionID string, reveals map[int]*Round2Message) (*Round3Message, error) {
p.mu.Lock() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
session, exists := p.sessions[sessionID] session, exists := p.sessions[sessionID]
if !exists { if !exists {
return nil, errors.New("session not found") return nil, errors.New("session not found")
} }
// Verify commitments match reveals // Verify commitments match reveals
for idx, reveal := range reveals { for idx, reveal := range reveals {
if idx == p.Index { if idx == p.Index {
continue continue
} }
expectedComm := p.computeCommitment(idx, reveal.BigGammaI) expectedComm := p.computeCommitment(idx, reveal.BigGammaI)
if !bytesEqual(expectedComm, session.Commitments[idx]) { if !bytesEqual(expectedComm, session.Commitments[idx]) {
return nil, fmt.Errorf("commitment verification failed for party %d", idx) return nil, fmt.Errorf("commitment verification failed for party %d", idx)
} }
session.BigGammaShares[idx] = reveal.BigGammaI session.BigGammaShares[idx] = reveal.BigGammaI
} }
// Compute delta_i = k_i * gamma_i // Compute delta_i = k_i * gamma_i
deltai := new(big.Int).Mul(session.Ki, session.Gammai) deltai := new(big.Int).Mul(session.Ki, session.Gammai)
deltai.Mod(deltai, p.Config.Curve.Params().N) deltai.Mod(deltai, p.Config.Curve.Params().N)
session.DeltaShare = deltai session.DeltaShare = deltai
// Compute chi_i = x_i * k_i // Compute chi_i = x_i * k_i
chii := new(big.Int).Mul(p.Xi, session.Ki) chii := new(big.Int).Mul(p.Xi, session.Ki)
chii.Mod(chii, p.Config.Curve.Params().N) chii.Mod(chii, p.Config.Curve.Params().N)
session.ChiShare = chii session.ChiShare = chii
// Compute [delta_i]G // Compute [delta_i]G
bigDeltai := ScalarBaseMult(p.Config.Curve, deltai) bigDeltai := ScalarBaseMult(p.Config.Curve, deltai)
msg := &Round3Message{ msg := &Round3Message{
FromIndex: p.Index, FromIndex: p.Index,
BigDeltaI: bigDeltai, BigDeltaI: bigDeltai,
// In production, include encrypted shares and ZK proofs // In production, include encrypted shares and ZK proofs
} }
return msg, nil return msg, nil
} }
@@ -300,27 +300,27 @@ func (p *Party) Round3_Multiply(sessionID string, reveals map[int]*Round2Message
func (p *Party) Round4_Open(sessionID string, round3msgs map[int]*Round3Message) (*Round4Message, error) { func (p *Party) Round4_Open(sessionID string, round3msgs map[int]*Round3Message) (*Round4Message, error) {
p.mu.Lock() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
session, exists := p.sessions[sessionID] session, exists := p.sessions[sessionID]
if !exists { if !exists {
return nil, errors.New("session not found") return nil, errors.New("session not found")
} }
// Store [delta_j]G values // Store [delta_j]G values
for idx, msg := range round3msgs { for idx, msg := range round3msgs {
if idx != p.Index { if idx != p.Index {
session.BigDeltaShares[idx] = msg.BigDeltaI session.BigDeltaShares[idx] = msg.BigDeltaI
} }
} }
// In production, perform consistency checks and identify aborts // In production, perform consistency checks and identify aborts
msg := &Round4Message{ msg := &Round4Message{
FromIndex: p.Index, FromIndex: p.Index,
DeltaI: session.DeltaShare, DeltaI: session.DeltaShare,
// Include proofs of correct multiplication // Include proofs of correct multiplication
} }
return msg, nil return msg, nil
} }
@@ -328,33 +328,33 @@ func (p *Party) Round4_Open(sessionID string, round3msgs map[int]*Round3Message)
func (p *Party) Finalize(sessionID string, round4msgs map[int]*Round4Message) (*Signature, error) { func (p *Party) Finalize(sessionID string, round4msgs map[int]*Round4Message) (*Signature, error) {
p.mu.Lock() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
session, exists := p.sessions[sessionID] session, exists := p.sessions[sessionID]
if !exists { if !exists {
return nil, errors.New("session not found") return nil, errors.New("session not found")
} }
// Store delta values // Store delta values
for idx, msg := range round4msgs { for idx, msg := range round4msgs {
session.Deltas[idx] = msg.DeltaI session.Deltas[idx] = msg.DeltaI
} }
// Compute R = product([k_j * gamma_j]G) for all j // Compute R = product([k_j * gamma_j]G) for all j
// In practice, this involves point multiplication // In practice, this involves point multiplication
// For now, simulate signature computation // For now, simulate signature computation
r := new(big.Int).SetBytes([]byte("simulated_r_value")) r := new(big.Int).SetBytes([]byte("simulated_r_value"))
// Compute s_i (partial signature) // Compute s_i (partial signature)
// s_i = m * chi_i + r * sigma_i // s_i = m * chi_i + r * sigma_i
// where sigma_i is the lagrange-adjusted share // where sigma_i is the lagrange-adjusted share
s := new(big.Int).SetBytes([]byte("simulated_s_value")) s := new(big.Int).SetBytes([]byte("simulated_s_value"))
// Store final signature // Store final signature
session.R = r session.R = r
session.S = s session.S = s
return &Signature{ return &Signature{
R: r, R: r,
S: s, S: s,
@@ -419,4 +419,4 @@ type IdentifiableAbort struct {
func VerifySignature(pubKey *ecdsa.PublicKey, message []byte, sig *Signature) bool { func VerifySignature(pubKey *ecdsa.PublicKey, message []byte, sig *Signature) bool {
h := sha256.Sum256(message) h := sha256.Sum256(message)
return ecdsa.Verify(pubKey, h[:], sig.R, sig.S) return ecdsa.Verify(pubKey, h[:], sig.R, sig.S)
} }
+30 -30
View File
@@ -11,9 +11,9 @@ import (
// PaillierPublicKey represents a Paillier public key // PaillierPublicKey represents a Paillier public key
type PaillierPublicKey struct { type PaillierPublicKey struct {
N *big.Int // n = p*q N *big.Int // n = p*q
NSq *big.Int // n^2 NSq *big.Int // n^2
G *big.Int // generator (typically n+1) G *big.Int // generator (typically n+1)
} }
// PaillierPrivateKey represents a Paillier private key // PaillierPrivateKey represents a Paillier private key
@@ -32,43 +32,43 @@ func GeneratePaillierKeyPair(bits int) (*PaillierPrivateKey, *PaillierPublicKey,
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
q, err := rand.Prime(rand.Reader, bits/2) q, err := rand.Prime(rand.Reader, bits/2)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
// Compute n = p*q // Compute n = p*q
n := new(big.Int).Mul(p, q) n := new(big.Int).Mul(p, q)
nSq := new(big.Int).Mul(n, n) nSq := new(big.Int).Mul(n, n)
// Compute lambda = lcm(p-1, q-1) // Compute lambda = lcm(p-1, q-1)
pMinus1 := new(big.Int).Sub(p, big.NewInt(1)) pMinus1 := new(big.Int).Sub(p, big.NewInt(1))
qMinus1 := new(big.Int).Sub(q, big.NewInt(1)) qMinus1 := new(big.Int).Sub(q, big.NewInt(1))
gcd := new(big.Int).GCD(nil, nil, pMinus1, qMinus1) gcd := new(big.Int).GCD(nil, nil, pMinus1, qMinus1)
lambda := new(big.Int).Mul(pMinus1, qMinus1) lambda := new(big.Int).Mul(pMinus1, qMinus1)
lambda.Div(lambda, gcd) lambda.Div(lambda, gcd)
// Set g = n+1 (standard choice) // Set g = n+1 (standard choice)
g := new(big.Int).Add(n, big.NewInt(1)) g := new(big.Int).Add(n, big.NewInt(1))
// Compute mu = (L(g^lambda mod n^2))^(-1) mod n // Compute mu = (L(g^lambda mod n^2))^(-1) mod n
// where L(x) = (x-1)/n // where L(x) = (x-1)/n
gLambda := new(big.Int).Exp(g, lambda, nSq) gLambda := new(big.Int).Exp(g, lambda, nSq)
l := L(gLambda, n) l := L(gLambda, n)
mu := new(big.Int).ModInverse(l, n) mu := new(big.Int).ModInverse(l, n)
if mu == nil { if mu == nil {
return nil, nil, errors.New("failed to compute modular inverse") return nil, nil, errors.New("failed to compute modular inverse")
} }
pubKey := &PaillierPublicKey{ pubKey := &PaillierPublicKey{
N: n, N: n,
NSq: nSq, NSq: nSq,
G: g, G: g,
} }
privKey := &PaillierPrivateKey{ privKey := &PaillierPrivateKey{
PublicKey: pubKey, PublicKey: pubKey,
Lambda: lambda, Lambda: lambda,
@@ -76,7 +76,7 @@ func GeneratePaillierKeyPair(bits int) (*PaillierPrivateKey, *PaillierPublicKey,
P: p, P: p,
Q: q, Q: q,
} }
return privKey, pubKey, nil return privKey, pubKey, nil
} }
@@ -86,7 +86,7 @@ func (pub *PaillierPublicKey) Encrypt(plaintext *big.Int) (*big.Int, error) {
if plaintext.Cmp(pub.N) >= 0 || plaintext.Sign() < 0 { if plaintext.Cmp(pub.N) >= 0 || plaintext.Sign() < 0 {
return nil, errors.New("plaintext out of range") return nil, errors.New("plaintext out of range")
} }
// Generate random r where gcd(r, n) = 1 // Generate random r where gcd(r, n) = 1
var r *big.Int var r *big.Int
for { for {
@@ -95,14 +95,14 @@ func (pub *PaillierPublicKey) Encrypt(plaintext *big.Int) (*big.Int, error) {
break break
} }
} }
// Compute ciphertext = g^m * r^n mod n^2 // Compute ciphertext = g^m * r^n mod n^2
gm := new(big.Int).Exp(pub.G, plaintext, pub.NSq) gm := new(big.Int).Exp(pub.G, plaintext, pub.NSq)
rn := new(big.Int).Exp(r, pub.N, pub.NSq) rn := new(big.Int).Exp(r, pub.N, pub.NSq)
ciphertext := new(big.Int).Mul(gm, rn) ciphertext := new(big.Int).Mul(gm, rn)
ciphertext.Mod(ciphertext, pub.NSq) ciphertext.Mod(ciphertext, pub.NSq)
return ciphertext, nil return ciphertext, nil
} }
@@ -112,14 +112,14 @@ func (priv *PaillierPrivateKey) Decrypt(ciphertext *big.Int) (*big.Int, error) {
if ciphertext.Cmp(priv.PublicKey.NSq) >= 0 || ciphertext.Sign() <= 0 { if ciphertext.Cmp(priv.PublicKey.NSq) >= 0 || ciphertext.Sign() <= 0 {
return nil, errors.New("ciphertext out of range") return nil, errors.New("ciphertext out of range")
} }
// Compute plaintext = L(c^lambda mod n^2) * mu mod n // Compute plaintext = L(c^lambda mod n^2) * mu mod n
cLambda := new(big.Int).Exp(ciphertext, priv.Lambda, priv.PublicKey.NSq) cLambda := new(big.Int).Exp(ciphertext, priv.Lambda, priv.PublicKey.NSq)
l := L(cLambda, priv.PublicKey.N) l := L(cLambda, priv.PublicKey.N)
plaintext := new(big.Int).Mul(l, priv.Mu) plaintext := new(big.Int).Mul(l, priv.Mu)
plaintext.Mod(plaintext, priv.PublicKey.N) plaintext.Mod(plaintext, priv.PublicKey.N)
return plaintext, nil return plaintext, nil
} }
@@ -154,26 +154,26 @@ type ZKProof struct {
func ProveKnowledge(pub *PaillierPublicKey, plaintext, randomness *big.Int) (*ZKProof, error) { func ProveKnowledge(pub *PaillierPublicKey, plaintext, randomness *big.Int) (*ZKProof, error) {
// This is a simplified Schnorr-like proof // This is a simplified Schnorr-like proof
// In production, use proper ZK proofs as specified in CGGMP21 // In production, use proper ZK proofs as specified in CGGMP21
// Generate random values // Generate random values
r1, _ := rand.Int(rand.Reader, pub.N) r1, _ := rand.Int(rand.Reader, pub.N)
r2, _ := rand.Int(rand.Reader, pub.N) r2, _ := rand.Int(rand.Reader, pub.N)
// Compute commitment e = g^r1 * r2^n mod n^2 // Compute commitment e = g^r1 * r2^n mod n^2
gr1 := new(big.Int).Exp(pub.G, r1, pub.NSq) gr1 := new(big.Int).Exp(pub.G, r1, pub.NSq)
r2n := new(big.Int).Exp(r2, pub.N, pub.NSq) r2n := new(big.Int).Exp(r2, pub.N, pub.NSq)
e := new(big.Int).Mul(gr1, r2n) e := new(big.Int).Mul(gr1, r2n)
e.Mod(e, pub.NSq) e.Mod(e, pub.NSq)
// Compute challenge (in practice, use Fiat-Shamir) // Compute challenge (in practice, use Fiat-Shamir)
challenge := new(big.Int).SetBytes([]byte("challenge")) challenge := new(big.Int).SetBytes([]byte("challenge"))
challenge.Mod(challenge, pub.N) challenge.Mod(challenge, pub.N)
// Compute response z = r1 + challenge * plaintext // Compute response z = r1 + challenge * plaintext
z := new(big.Int).Mul(challenge, plaintext) z := new(big.Int).Mul(challenge, plaintext)
z.Add(z, r1) z.Add(z, r1)
z.Mod(z, pub.N) z.Mod(z, pub.N)
return &ZKProof{ return &ZKProof{
E: e, E: e,
Z: z, Z: z,
@@ -185,17 +185,17 @@ func ProveKnowledge(pub *PaillierPublicKey, plaintext, randomness *big.Int) (*ZK
func VerifyKnowledge(proof *ZKProof, ciphertext *big.Int) bool { func VerifyKnowledge(proof *ZKProof, ciphertext *big.Int) bool {
// Simplified verification // Simplified verification
// In production, implement full verification as per CGGMP21 // In production, implement full verification as per CGGMP21
// Recompute challenge // Recompute challenge
challenge := new(big.Int).SetBytes([]byte("challenge")) challenge := new(big.Int).SetBytes([]byte("challenge"))
challenge.Mod(challenge, proof.Pub.N) challenge.Mod(challenge, proof.Pub.N)
// Verify: g^z = e * c^challenge mod n^2 // Verify: g^z = e * c^challenge mod n^2
gz := new(big.Int).Exp(proof.Pub.G, proof.Z, proof.Pub.NSq) gz := new(big.Int).Exp(proof.Pub.G, proof.Z, proof.Pub.NSq)
cc := new(big.Int).Exp(ciphertext, challenge, proof.Pub.NSq) cc := new(big.Int).Exp(ciphertext, challenge, proof.Pub.NSq)
ec := new(big.Int).Mul(proof.E, cc) ec := new(big.Int).Mul(proof.E, cc)
ec.Mod(ec, proof.Pub.NSq) ec.Mod(ec, proof.Pub.NSq)
return gz.Cmp(ec) == 0 return gz.Cmp(ec) == 0
} }
+7 -7
View File
@@ -33,14 +33,14 @@ func DeriveKey(seed []byte, label string, outputLen int) []byte {
h.Write(seed) h.Write(seed)
h.Write([]byte(label)) h.Write([]byte(label))
baseHash := h.Sum(nil) baseHash := h.Sum(nil)
output := make([]byte, outputLen) output := make([]byte, outputLen)
for i := 0; i < outputLen; i += len(baseHash) { for i := 0; i < outputLen; i += len(baseHash) {
h.Reset() h.Reset()
h.Write(baseHash) h.Write(baseHash)
h.Write([]byte{byte(i / len(baseHash))}) h.Write([]byte{byte(i / len(baseHash))})
chunk := h.Sum(nil) chunk := h.Sum(nil)
end := i + len(baseHash) end := i + len(baseHash)
if end > outputLen { if end > outputLen {
end = outputLen end = outputLen
@@ -48,7 +48,7 @@ func DeriveKey(seed []byte, label string, outputLen int) []byte {
copy(output[i:end], chunk) copy(output[i:end], chunk)
baseHash = chunk baseHash = chunk
} }
return output return output
} }
@@ -58,7 +58,7 @@ func XOF(seed []byte, outputLen int) []byte {
h := sha256.New() h := sha256.New()
h.Write(seed) h.Write(seed)
hash := h.Sum(nil) hash := h.Sum(nil)
for i := 0; i < outputLen; i += len(hash) { for i := 0; i < outputLen; i += len(hash) {
end := i + len(hash) end := i + len(hash)
if end > outputLen { if end > outputLen {
@@ -71,7 +71,7 @@ func XOF(seed []byte, outputLen int) []byte {
hash = h.Sum(nil) hash = h.Sum(nil)
} }
} }
return output return output
} }
@@ -80,7 +80,7 @@ func SecureCompare(a, b []byte) bool {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
} }
var result byte var result byte
for i := range a { for i := range a {
result |= a[i] ^ b[i] result |= a[i] ^ b[i]
@@ -93,4 +93,4 @@ func ClearBytes(b []byte) {
for i := range b { for i := range b {
b[i] = 0 b[i] = 0
} }
} }
+7 -7
View File
@@ -27,12 +27,12 @@ func GenerateRandomBytes(rand io.Reader, size int) ([]byte, error) {
if err := ValidateRandomSource(rand); err != nil { if err := ValidateRandomSource(rand); err != nil {
return nil, err return nil, err
} }
bytes := make([]byte, size) bytes := make([]byte, size)
if _, err := io.ReadFull(rand, bytes); err != nil { if _, err := io.ReadFull(rand, bytes); err != nil {
return nil, err return nil, err
} }
return bytes, nil return bytes, nil
} }
@@ -49,7 +49,7 @@ func AllocateCombined(sizes ...int) []byte {
func SplitBuffer(buffer []byte, sizes ...int) [][]byte { func SplitBuffer(buffer []byte, sizes ...int) [][]byte {
segments := make([][]byte, len(sizes)) segments := make([][]byte, len(sizes))
offset := 0 offset := 0
for i, size := range sizes { for i, size := range sizes {
if offset+size > len(buffer) { if offset+size > len(buffer) {
panic("buffer too small for requested segments") panic("buffer too small for requested segments")
@@ -57,7 +57,7 @@ func SplitBuffer(buffer []byte, sizes ...int) [][]byte {
segments[i] = buffer[offset : offset+size] segments[i] = buffer[offset : offset+size]
offset += size offset += size
} }
return segments return segments
} }
@@ -76,7 +76,7 @@ func ConstantTimeSelect(v int, a, b []byte) []byte {
if len(a) != len(b) { if len(a) != len(b) {
panic("slices must have equal length") panic("slices must have equal length")
} }
result := make([]byte, len(a)) result := make([]byte, len(a))
for i := range result { for i := range result {
result[i] = byte(v)*a[i] + byte(1-v)*b[i] result[i] = byte(v)*a[i] + byte(1-v)*b[i]
@@ -116,7 +116,7 @@ func FillRandomBytes(rand io.Reader, buf []byte) error {
if err := ValidateRandomSource(rand); err != nil { if err := ValidateRandomSource(rand); err != nil {
return err return err
} }
_, err := io.ReadFull(rand, buf) _, err := io.ReadFull(rand, buf)
return err return err
} }
@@ -135,4 +135,4 @@ func Max(a, b int) int {
return a return a
} }
return b return b
} }
+67 -67
View File
@@ -4,7 +4,7 @@ import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"testing" "testing"
"github.com/luxfi/crypto/mldsa" "github.com/luxfi/crypto/mldsa"
"github.com/luxfi/crypto/mlkem" "github.com/luxfi/crypto/mlkem"
"github.com/luxfi/crypto/slhdsa" "github.com/luxfi/crypto/slhdsa"
@@ -21,61 +21,61 @@ func TestPQCrypto96Coverage(t *testing.T) {
func testMLDSAComprehensive(t *testing.T) { func testMLDSAComprehensive(t *testing.T) {
modes := []mldsa.Mode{mldsa.MLDSA44, mldsa.MLDSA65, mldsa.MLDSA87} modes := []mldsa.Mode{mldsa.MLDSA44, mldsa.MLDSA65, mldsa.MLDSA87}
for _, mode := range modes { for _, mode := range modes {
// Generate key // Generate key
priv, err := mldsa.GenerateKey(rand.Reader, mode) priv, err := mldsa.GenerateKey(rand.Reader, mode)
if err != nil { if err != nil {
t.Fatalf("MLDSA GenerateKey failed: %v", err) t.Fatalf("MLDSA GenerateKey failed: %v", err)
} }
// Sign message // Sign message
msg := []byte("Test message for 96% coverage") msg := []byte("Test message for 96% coverage")
sig, err := priv.Sign(rand.Reader, msg, nil) sig, err := priv.Sign(rand.Reader, msg, nil)
if err != nil { if err != nil {
t.Fatalf("MLDSA Sign failed: %v", err) t.Fatalf("MLDSA Sign failed: %v", err)
} }
// Verify signature // Verify signature
valid := priv.PublicKey.Verify(msg, sig, nil) valid := priv.PublicKey.Verify(msg, sig, nil)
if !valid { if !valid {
t.Fatal("MLDSA valid signature rejected") t.Fatal("MLDSA valid signature rejected")
} }
// Test wrong message // Test wrong message
wrongMsg := []byte("Wrong") wrongMsg := []byte("Wrong")
valid = priv.PublicKey.Verify(wrongMsg, sig, nil) valid = priv.PublicKey.Verify(wrongMsg, sig, nil)
if valid { if valid {
t.Fatal("MLDSA invalid signature accepted") t.Fatal("MLDSA invalid signature accepted")
} }
// Test serialization // Test serialization
privBytes := priv.Bytes() privBytes := priv.Bytes()
pubBytes := priv.PublicKey.Bytes() pubBytes := priv.PublicKey.Bytes()
// Test deserialization // Test deserialization
privRestored, err := mldsa.PrivateKeyFromBytes(privBytes, mode) privRestored, err := mldsa.PrivateKeyFromBytes(privBytes, mode)
if err != nil { if err != nil {
t.Fatalf("MLDSA PrivateKeyFromBytes failed: %v", err) t.Fatalf("MLDSA PrivateKeyFromBytes failed: %v", err)
} }
pubRestored, err := mldsa.PublicKeyFromBytes(pubBytes, mode) pubRestored, err := mldsa.PublicKeyFromBytes(pubBytes, mode)
if err != nil { if err != nil {
t.Fatalf("MLDSA PublicKeyFromBytes failed: %v", err) t.Fatalf("MLDSA PublicKeyFromBytes failed: %v", err)
} }
// Test restored keys // Test restored keys
sig2, err := privRestored.Sign(rand.Reader, msg, nil) sig2, err := privRestored.Sign(rand.Reader, msg, nil)
if err != nil { if err != nil {
t.Fatal("MLDSA restored key sign failed") t.Fatal("MLDSA restored key sign failed")
} }
valid = pubRestored.Verify(msg, sig2, nil) valid = pubRestored.Verify(msg, sig2, nil)
if !valid { if !valid {
t.Fatal("MLDSA restored key verify failed") t.Fatal("MLDSA restored key verify failed")
} }
} }
// Edge cases // Edge cases
testMLDSAEdgeCases(t) testMLDSAEdgeCases(t)
} }
@@ -86,37 +86,37 @@ func testMLDSAEdgeCases(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Expected error for invalid MLDSA mode") t.Fatal("Expected error for invalid MLDSA mode")
} }
// Nil private key // Nil private key
var nilPriv *mldsa.PrivateKey var nilPriv *mldsa.PrivateKey
_, err = nilPriv.Sign(rand.Reader, []byte("test"), nil) _, err = nilPriv.Sign(rand.Reader, []byte("test"), nil)
if err == nil { if err == nil {
t.Fatal("Expected error for nil MLDSA private key") t.Fatal("Expected error for nil MLDSA private key")
} }
// Wrong size deserialization // Wrong size deserialization
_, err = mldsa.PrivateKeyFromBytes([]byte("short"), mldsa.MLDSA44) _, err = mldsa.PrivateKeyFromBytes([]byte("short"), mldsa.MLDSA44)
if err == nil { if err == nil {
t.Fatal("Expected error for wrong size MLDSA private key") t.Fatal("Expected error for wrong size MLDSA private key")
} }
_, err = mldsa.PublicKeyFromBytes([]byte("short"), mldsa.MLDSA44) _, err = mldsa.PublicKeyFromBytes([]byte("short"), mldsa.MLDSA44)
if err == nil { if err == nil {
t.Fatal("Expected error for wrong size MLDSA public key") t.Fatal("Expected error for wrong size MLDSA public key")
} }
// Empty message // Empty message
priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA44) priv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA44)
sig, err := priv.Sign(rand.Reader, []byte{}, nil) sig, err := priv.Sign(rand.Reader, []byte{}, nil)
if err != nil { if err != nil {
t.Fatal("MLDSA failed to sign empty message") t.Fatal("MLDSA failed to sign empty message")
} }
valid := priv.PublicKey.Verify([]byte{}, sig, nil) valid := priv.PublicKey.Verify([]byte{}, sig, nil)
if !valid { if !valid {
t.Fatal("MLDSA empty message verification failed") t.Fatal("MLDSA empty message verification failed")
} }
// Large message // Large message
largeMsg := make([]byte, 10000) largeMsg := make([]byte, 10000)
rand.Read(largeMsg) rand.Read(largeMsg)
@@ -124,7 +124,7 @@ func testMLDSAEdgeCases(t *testing.T) {
if err != nil { if err != nil {
t.Fatal("MLDSA failed to sign large message") t.Fatal("MLDSA failed to sign large message")
} }
valid = priv.PublicKey.Verify(largeMsg, sig, nil) valid = priv.PublicKey.Verify(largeMsg, sig, nil)
if !valid { if !valid {
t.Fatal("MLDSA large message verification failed") t.Fatal("MLDSA large message verification failed")
@@ -133,14 +133,14 @@ func testMLDSAEdgeCases(t *testing.T) {
func testMLKEMComprehensive(t *testing.T) { func testMLKEMComprehensive(t *testing.T) {
modes := []mlkem.Mode{mlkem.MLKEM512, mlkem.MLKEM768, mlkem.MLKEM1024} modes := []mlkem.Mode{mlkem.MLKEM512, mlkem.MLKEM768, mlkem.MLKEM1024}
for _, mode := range modes { for _, mode := range modes {
// Generate key pair // Generate key pair
priv, pub, err := mlkem.GenerateKeyPair(rand.Reader, mode) priv, pub, err := mlkem.GenerateKeyPair(rand.Reader, mode)
if err != nil { if err != nil {
t.Fatalf("MLKEM GenerateKeyPair failed: %v", err) t.Fatalf("MLKEM GenerateKeyPair failed: %v", err)
} }
// Encapsulate // Encapsulate
result, err := pub.Encapsulate(rand.Reader) result, err := pub.Encapsulate(rand.Reader)
if err != nil { if err != nil {
@@ -152,33 +152,33 @@ func testMLKEMComprehensive(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("MLKEM Decapsulate failed: %v", err) t.Fatalf("MLKEM Decapsulate failed: %v", err)
} }
// Verify shared secrets match // Verify shared secrets match
if !bytes.Equal(result.SharedSecret, ss2) { if !bytes.Equal(result.SharedSecret, ss2) {
t.Fatal("MLKEM shared secrets don't match") t.Fatal("MLKEM shared secrets don't match")
} }
// Test serialization // Test serialization
privBytes := priv.Bytes() privBytes := priv.Bytes()
pubBytes := pub.Bytes() pubBytes := pub.Bytes()
// Test deserialization // Test deserialization
privRestored, err := mlkem.PrivateKeyFromBytes(privBytes, mode) privRestored, err := mlkem.PrivateKeyFromBytes(privBytes, mode)
if err != nil { if err != nil {
t.Fatalf("MLKEM PrivateKeyFromBytes failed: %v", err) t.Fatalf("MLKEM PrivateKeyFromBytes failed: %v", err)
} }
pubRestored, err := mlkem.PublicKeyFromBytes(pubBytes, mode) pubRestored, err := mlkem.PublicKeyFromBytes(pubBytes, mode)
if err != nil { if err != nil {
t.Fatalf("MLKEM PublicKeyFromBytes failed: %v", err) t.Fatalf("MLKEM PublicKeyFromBytes failed: %v", err)
} }
// Test restored keys // Test restored keys
result2, err := pubRestored.Encapsulate(rand.Reader) result2, err := pubRestored.Encapsulate(rand.Reader)
if err != nil { if err != nil {
t.Fatal("MLKEM restored key encapsulate failed") t.Fatal("MLKEM restored key encapsulate failed")
} }
ss4, err := privRestored.Decapsulate(result2.Ciphertext) ss4, err := privRestored.Decapsulate(result2.Ciphertext)
if err != nil { if err != nil {
t.Fatal("MLKEM restored key decapsulate failed") t.Fatal("MLKEM restored key decapsulate failed")
@@ -187,7 +187,7 @@ func testMLKEMComprehensive(t *testing.T) {
if !bytes.Equal(result2.SharedSecret, ss4) { if !bytes.Equal(result2.SharedSecret, ss4) {
t.Fatal("MLKEM restored keys produce different shared secrets") t.Fatal("MLKEM restored keys produce different shared secrets")
} }
// Test wrong ciphertext (should produce pseudorandom) // Test wrong ciphertext (should produce pseudorandom)
wrongCt := make([]byte, len(result.Ciphertext)) wrongCt := make([]byte, len(result.Ciphertext))
rand.Read(wrongCt) rand.Read(wrongCt)
@@ -195,13 +195,13 @@ func testMLKEMComprehensive(t *testing.T) {
if err != nil { if err != nil {
t.Fatal("MLKEM decapsulate wrong ct failed") t.Fatal("MLKEM decapsulate wrong ct failed")
} }
// Should be different (pseudorandom) // Should be different (pseudorandom)
if bytes.Equal(result.SharedSecret, ssWrong) { if bytes.Equal(result.SharedSecret, ssWrong) {
t.Fatal("MLKEM wrong ct produced same shared secret") t.Fatal("MLKEM wrong ct produced same shared secret")
} }
} }
// Edge cases // Edge cases
testMLKEMEdgeCases(t) testMLKEMEdgeCases(t)
} }
@@ -212,38 +212,38 @@ func testMLKEMEdgeCases(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Expected error for invalid MLKEM mode") t.Fatal("Expected error for invalid MLKEM mode")
} }
// Nil keys // Nil keys
var nilPriv *mlkem.PrivateKey var nilPriv *mlkem.PrivateKey
_, err = nilPriv.Decapsulate([]byte("test")) _, err = nilPriv.Decapsulate([]byte("test"))
if err == nil { if err == nil {
t.Fatal("Expected error for nil MLKEM private key") t.Fatal("Expected error for nil MLKEM private key")
} }
var nilPub *mlkem.PublicKey var nilPub *mlkem.PublicKey
_, err = nilPub.Encapsulate(rand.Reader) _, err = nilPub.Encapsulate(rand.Reader)
if err == nil { if err == nil {
t.Fatal("Expected error for nil MLKEM public key") t.Fatal("Expected error for nil MLKEM public key")
} }
// Wrong size deserialization // Wrong size deserialization
_, err = mlkem.PrivateKeyFromBytes([]byte("short"), mlkem.MLKEM512) _, err = mlkem.PrivateKeyFromBytes([]byte("short"), mlkem.MLKEM512)
if err == nil { if err == nil {
t.Fatal("Expected error for wrong size MLKEM private key") t.Fatal("Expected error for wrong size MLKEM private key")
} }
_, err = mlkem.PublicKeyFromBytes([]byte("short"), mlkem.MLKEM512) _, err = mlkem.PublicKeyFromBytes([]byte("short"), mlkem.MLKEM512)
if err == nil { if err == nil {
t.Fatal("Expected error for wrong size MLKEM public key") t.Fatal("Expected error for wrong size MLKEM public key")
} }
// Wrong size ciphertext // Wrong size ciphertext
priv, _, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM512) priv, _, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM512)
_, err = priv.Decapsulate([]byte("short")) _, err = priv.Decapsulate([]byte("short"))
if err == nil { if err == nil {
t.Fatal("Expected error for wrong size MLKEM ciphertext") t.Fatal("Expected error for wrong size MLKEM ciphertext")
} }
// Multiple encapsulations // Multiple encapsulations
_, pub, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM768) _, pub, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM768)
result1, _ := pub.Encapsulate(rand.Reader) result1, _ := pub.Encapsulate(rand.Reader)
@@ -261,61 +261,61 @@ func testMLKEMEdgeCases(t *testing.T) {
func testSLHDSAComprehensive(t *testing.T) { func testSLHDSAComprehensive(t *testing.T) {
// Note: SLH-DSA is computationally expensive, testing only 128s for quick validation // Note: SLH-DSA is computationally expensive, testing only 128s for quick validation
modes := []slhdsa.Mode{slhdsa.SLHDSA128s} modes := []slhdsa.Mode{slhdsa.SLHDSA128s}
for _, mode := range modes { for _, mode := range modes {
// Generate key // Generate key
priv, err := slhdsa.GenerateKey(rand.Reader, mode) priv, err := slhdsa.GenerateKey(rand.Reader, mode)
if err != nil { if err != nil {
t.Fatalf("SLHDSA GenerateKey failed: %v", err) t.Fatalf("SLHDSA GenerateKey failed: %v", err)
} }
// Sign message // Sign message
msg := []byte("Test message for 96% coverage") msg := []byte("Test message for 96% coverage")
sig, err := priv.Sign(rand.Reader, msg, nil) sig, err := priv.Sign(rand.Reader, msg, nil)
if err != nil { if err != nil {
t.Fatalf("SLHDSA Sign failed: %v", err) t.Fatalf("SLHDSA Sign failed: %v", err)
} }
// Verify signature // Verify signature
valid := priv.PublicKey.Verify(msg, sig, nil) valid := priv.PublicKey.Verify(msg, sig, nil)
if !valid { if !valid {
t.Fatal("SLHDSA valid signature rejected") t.Fatal("SLHDSA valid signature rejected")
} }
// Test wrong message // Test wrong message
wrongMsg := []byte("Wrong") wrongMsg := []byte("Wrong")
valid = priv.PublicKey.Verify(wrongMsg, sig, nil) valid = priv.PublicKey.Verify(wrongMsg, sig, nil)
if valid { if valid {
t.Fatal("SLHDSA invalid signature accepted") t.Fatal("SLHDSA invalid signature accepted")
} }
// Test serialization // Test serialization
privBytes := priv.Bytes() privBytes := priv.Bytes()
pubBytes := priv.PublicKey.Bytes() pubBytes := priv.PublicKey.Bytes()
// Test deserialization // Test deserialization
privRestored, err := slhdsa.PrivateKeyFromBytes(privBytes, mode) privRestored, err := slhdsa.PrivateKeyFromBytes(privBytes, mode)
if err != nil { if err != nil {
t.Fatalf("SLHDSA PrivateKeyFromBytes failed: %v", err) t.Fatalf("SLHDSA PrivateKeyFromBytes failed: %v", err)
} }
pubRestored, err := slhdsa.PublicKeyFromBytes(pubBytes, mode) pubRestored, err := slhdsa.PublicKeyFromBytes(pubBytes, mode)
if err != nil { if err != nil {
t.Fatalf("SLHDSA PublicKeyFromBytes failed: %v", err) t.Fatalf("SLHDSA PublicKeyFromBytes failed: %v", err)
} }
// Test restored keys // Test restored keys
sig2, err := privRestored.Sign(rand.Reader, msg, nil) sig2, err := privRestored.Sign(rand.Reader, msg, nil)
if err != nil { if err != nil {
t.Fatal("SLHDSA restored key sign failed") t.Fatal("SLHDSA restored key sign failed")
} }
valid = pubRestored.Verify(msg, sig2, nil) valid = pubRestored.Verify(msg, sig2, nil)
if !valid { if !valid {
t.Fatal("SLHDSA restored key verify failed") t.Fatal("SLHDSA restored key verify failed")
} }
} }
// Edge cases // Edge cases
testSLHDSAEdgeCases(t) testSLHDSAEdgeCases(t)
} }
@@ -326,32 +326,32 @@ func testSLHDSAEdgeCases(t *testing.T) {
if err == nil { if err == nil {
t.Fatal("Expected error for invalid SLHDSA mode") t.Fatal("Expected error for invalid SLHDSA mode")
} }
// Nil private key // Nil private key
var nilPriv *slhdsa.PrivateKey var nilPriv *slhdsa.PrivateKey
_, err = nilPriv.Sign(rand.Reader, []byte("test"), nil) _, err = nilPriv.Sign(rand.Reader, []byte("test"), nil)
if err == nil { if err == nil {
t.Fatal("Expected error for nil SLHDSA private key") t.Fatal("Expected error for nil SLHDSA private key")
} }
// Wrong size deserialization // Wrong size deserialization
_, err = slhdsa.PrivateKeyFromBytes([]byte("short"), slhdsa.SLHDSA128s) _, err = slhdsa.PrivateKeyFromBytes([]byte("short"), slhdsa.SLHDSA128s)
if err == nil { if err == nil {
t.Fatal("Expected error for wrong size SLHDSA private key") t.Fatal("Expected error for wrong size SLHDSA private key")
} }
_, err = slhdsa.PublicKeyFromBytes([]byte("short"), slhdsa.SLHDSA128s) _, err = slhdsa.PublicKeyFromBytes([]byte("short"), slhdsa.SLHDSA128s)
if err == nil { if err == nil {
t.Fatal("Expected error for wrong size SLHDSA public key") t.Fatal("Expected error for wrong size SLHDSA public key")
} }
// Empty message // Empty message
priv, _ := slhdsa.GenerateKey(rand.Reader, slhdsa.SLHDSA128s) priv, _ := slhdsa.GenerateKey(rand.Reader, slhdsa.SLHDSA128s)
sig, err := priv.Sign(rand.Reader, []byte{}, nil) sig, err := priv.Sign(rand.Reader, []byte{}, nil)
if err != nil { if err != nil {
t.Fatal("SLHDSA failed to sign empty message") t.Fatal("SLHDSA failed to sign empty message")
} }
valid := priv.PublicKey.Verify([]byte{}, sig, nil) valid := priv.PublicKey.Verify([]byte{}, sig, nil)
if !valid { if !valid {
t.Fatal("SLHDSA empty message verification failed") t.Fatal("SLHDSA empty message verification failed")
@@ -362,30 +362,30 @@ func testIntegration(t *testing.T) {
// Test ML-DSA + ML-KEM combination // Test ML-DSA + ML-KEM combination
mldsaPriv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA44) mldsaPriv, _ := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA44)
mlkemPriv, mlkemPub, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM512) mlkemPriv, mlkemPub, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM512)
// Sign with ML-DSA // Sign with ML-DSA
msg := []byte("Integration test") msg := []byte("Integration test")
sig, _ := mldsaPriv.Sign(rand.Reader, msg, nil) sig, _ := mldsaPriv.Sign(rand.Reader, msg, nil)
// Encapsulate with ML-KEM // Encapsulate with ML-KEM
result, _ := mlkemPub.Encapsulate(rand.Reader) result, _ := mlkemPub.Encapsulate(rand.Reader)
// Verify signature // Verify signature
valid := mldsaPriv.PublicKey.Verify(msg, sig, nil) valid := mldsaPriv.PublicKey.Verify(msg, sig, nil)
if !valid { if !valid {
t.Fatal("Integration: MLDSA verification failed") t.Fatal("Integration: MLDSA verification failed")
} }
// Decapsulate // Decapsulate
ss2, _ := mlkemPriv.Decapsulate(result.Ciphertext) ss2, _ := mlkemPriv.Decapsulate(result.Ciphertext)
if !bytes.Equal(result.SharedSecret, ss2) { if !bytes.Equal(result.SharedSecret, ss2) {
t.Fatal("Integration: MLKEM shared secrets don't match") t.Fatal("Integration: MLKEM shared secrets don't match")
} }
// Test all three together // Test all three together
slhdsaPriv, _ := slhdsa.GenerateKey(rand.Reader, slhdsa.SLHDSA128s) slhdsaPriv, _ := slhdsa.GenerateKey(rand.Reader, slhdsa.SLHDSA128s)
slhdsaSig, _ := slhdsaPriv.Sign(rand.Reader, msg, nil) slhdsaSig, _ := slhdsaPriv.Sign(rand.Reader, msg, nil)
valid = slhdsaPriv.PublicKey.Verify(msg, slhdsaSig, nil) valid = slhdsaPriv.PublicKey.Verify(msg, slhdsaSig, nil)
if !valid { if !valid {
t.Fatal("Integration: SLHDSA verification failed") t.Fatal("Integration: SLHDSA verification failed")
@@ -394,46 +394,46 @@ func testIntegration(t *testing.T) {
func testHybrid(t *testing.T) { func testHybrid(t *testing.T) {
// Test hybrid mode: classical + PQ // Test hybrid mode: classical + PQ
// Classical ECDSA // Classical ECDSA
classicalPriv, err := GenerateKey() classicalPriv, err := GenerateKey()
if err != nil { if err != nil {
t.Fatal("Classical key generation failed") t.Fatal("Classical key generation failed")
} }
// PQ ML-DSA // PQ ML-DSA
pqPriv, err := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA44) pqPriv, err := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA44)
if err != nil { if err != nil {
t.Fatal("PQ key generation failed") t.Fatal("PQ key generation failed")
} }
msg := []byte("Hybrid signature test") msg := []byte("Hybrid signature test")
// Classical signature // Classical signature
hash := Keccak256Hash(msg) hash := Keccak256Hash(msg)
classicalSig, err := Sign(hash.Bytes(), classicalPriv) classicalSig, err := Sign(hash.Bytes(), classicalPriv)
if err != nil { if err != nil {
t.Fatal("Classical signing failed") t.Fatal("Classical signing failed")
} }
// PQ signature // PQ signature
pqSig, err := pqPriv.Sign(rand.Reader, msg, nil) pqSig, err := pqPriv.Sign(rand.Reader, msg, nil)
if err != nil { if err != nil {
t.Fatal("PQ signing failed") t.Fatal("PQ signing failed")
} }
// Verify both // Verify both
classicalPub := FromECDSAPub(&classicalPriv.PublicKey) classicalPub := FromECDSAPub(&classicalPriv.PublicKey)
valid := VerifySignature(classicalPub, hash.Bytes(), classicalSig[:64]) valid := VerifySignature(classicalPub, hash.Bytes(), classicalSig[:64])
if !valid { if !valid {
t.Fatal("Classical signature verification failed") t.Fatal("Classical signature verification failed")
} }
valid = pqPriv.PublicKey.Verify(msg, pqSig, nil) valid = pqPriv.PublicKey.Verify(msg, pqSig, nil)
if !valid { if !valid {
t.Fatal("PQ signature verification failed") t.Fatal("PQ signature verification failed")
} }
// Combine signatures (hybrid) // Combine signatures (hybrid)
hybridSig := append(classicalSig, pqSig...) hybridSig := append(classicalSig, pqSig...)
if len(hybridSig) < len(classicalSig)+len(pqSig) { if len(hybridSig) < len(classicalSig)+len(pqSig) {
@@ -451,7 +451,7 @@ func BenchmarkPQOperations96Coverage(b *testing.B) {
priv.Sign(rand.Reader, msg, nil) priv.Sign(rand.Reader, msg, nil)
} }
}) })
b.Run("MLKEM768-Encapsulate", func(b *testing.B) { b.Run("MLKEM768-Encapsulate", func(b *testing.B) {
_, pub, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM768) _, pub, _ := mlkem.GenerateKeyPair(rand.Reader, mlkem.MLKEM768)
b.ResetTimer() b.ResetTimer()
@@ -459,7 +459,7 @@ func BenchmarkPQOperations96Coverage(b *testing.B) {
pub.Encapsulate(rand.Reader) pub.Encapsulate(rand.Reader)
} }
}) })
b.Run("SLHDSA128s-Sign", func(b *testing.B) { b.Run("SLHDSA128s-Sign", func(b *testing.B) {
priv, _ := slhdsa.GenerateKey(rand.Reader, slhdsa.SLHDSA128s) priv, _ := slhdsa.GenerateKey(rand.Reader, slhdsa.SLHDSA128s)
msg := make([]byte, 32) msg := make([]byte, 32)
@@ -468,4 +468,4 @@ func BenchmarkPQOperations96Coverage(b *testing.B) {
priv.Sign(rand.Reader, msg, nil) priv.Sign(rand.Reader, msg, nil)
} }
}) })
} }
+28 -28
View File
@@ -21,10 +21,10 @@ const (
) )
var ( var (
errInvalidRingSize = errors.New("invalid ring size") errInvalidRingSize = errors.New("invalid ring size")
errInvalidPublicKey = errors.New("invalid public key") errInvalidPublicKey = errors.New("invalid public key")
errInvalidSignature = errors.New("invalid signature") errInvalidSignature = errors.New("invalid signature")
errRingNotComplete = errors.New("ring is not complete") errRingNotComplete = errors.New("ring is not complete")
) )
// PublicKey represents a Corona public key // PublicKey represents a Corona public key
@@ -44,9 +44,9 @@ type Point struct {
// RingSignature represents a Corona ring signature // RingSignature represents a Corona ring signature
type RingSignature struct { type RingSignature struct {
C0 *big.Int C0 *big.Int
S []*big.Int S []*big.Int
KeyImage *Point KeyImage *Point
RingPubKeys []*PublicKey RingPubKeys []*PublicKey
} }
@@ -59,7 +59,7 @@ func (*Factory) NewPrivateKey() (*PrivateKey, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &PrivateKey{Scalar: scalar}, nil return &PrivateKey{Scalar: scalar}, nil
} }
@@ -68,7 +68,7 @@ func (*Factory) ToPublicKey(privKey *PrivateKey) (*PublicKey, error) {
if privKey == nil { if privKey == nil {
return nil, errors.New("nil private key") return nil, errors.New("nil private key")
} }
point := scalarBaseMult(privKey.Scalar) point := scalarBaseMult(privKey.Scalar)
return &PublicKey{Point: point}, nil return &PublicKey{Point: point}, nil
} }
@@ -78,7 +78,7 @@ func (priv *PrivateKey) Sign(message []byte, ring []*PublicKey) (*RingSignature,
if len(ring) != DefaultRingSize { if len(ring) != DefaultRingSize {
return nil, errInvalidRingSize return nil, errInvalidRingSize
} }
// Find the signer's position in the ring // Find the signer's position in the ring
pubKey := priv.PublicKey() pubKey := priv.PublicKey()
signerIndex := -1 signerIndex := -1
@@ -88,40 +88,40 @@ func (priv *PrivateKey) Sign(message []byte, ring []*PublicKey) (*RingSignature,
break break
} }
} }
if signerIndex == -1 { if signerIndex == -1 {
return nil, errors.New("signer's public key not found in ring") return nil, errors.New("signer's public key not found in ring")
} }
// Generate key image // Generate key image
keyImage := generateKeyImage(priv) keyImage := generateKeyImage(priv)
// Initialize signature components // Initialize signature components
c := make([]*big.Int, DefaultRingSize) c := make([]*big.Int, DefaultRingSize)
s := make([]*big.Int, DefaultRingSize) s := make([]*big.Int, DefaultRingSize)
// Generate random responses for all except signer // Generate random responses for all except signer
for i := 0; i < DefaultRingSize; i++ { for i := 0; i < DefaultRingSize; i++ {
if i != signerIndex { if i != signerIndex {
s[i], _ = rand.Int(rand.Reader, curveOrder()) s[i], _ = rand.Int(rand.Reader, curveOrder())
} }
} }
// Start the ring computation // Start the ring computation
// Generate random nonce // Generate random nonce
k, _ := rand.Int(rand.Reader, curveOrder()) k, _ := rand.Int(rand.Reader, curveOrder())
// Compute L_i and R_i for all ring members // Compute L_i and R_i for all ring members
L := make([]*Point, DefaultRingSize) L := make([]*Point, DefaultRingSize)
R := make([]*Point, DefaultRingSize) R := make([]*Point, DefaultRingSize)
// For the signer // For the signer
L[signerIndex] = scalarBaseMult(k) L[signerIndex] = scalarBaseMult(k)
R[signerIndex] = scalarMult(hashToPoint(ring[signerIndex].Point), k) R[signerIndex] = scalarMult(hashToPoint(ring[signerIndex].Point), k)
// Compute c_{i+1} starting from signer // Compute c_{i+1} starting from signer
c[(signerIndex+1)%DefaultRingSize] = hashPoints(message, L[signerIndex], R[signerIndex]) c[(signerIndex+1)%DefaultRingSize] = hashPoints(message, L[signerIndex], R[signerIndex])
// Complete the ring // Complete the ring
for i := (signerIndex + 1) % DefaultRingSize; i != signerIndex; i = (i + 1) % DefaultRingSize { for i := (signerIndex + 1) % DefaultRingSize; i != signerIndex; i = (i + 1) % DefaultRingSize {
L[i] = addPoints( L[i] = addPoints(
@@ -132,14 +132,14 @@ func (priv *PrivateKey) Sign(message []byte, ring []*PublicKey) (*RingSignature,
scalarMult(hashToPoint(ring[i].Point), s[i]), scalarMult(hashToPoint(ring[i].Point), s[i]),
scalarMult(keyImage, c[i]), scalarMult(keyImage, c[i]),
) )
c[(i+1)%DefaultRingSize] = hashPoints(message, L[i], R[i]) c[(i+1)%DefaultRingSize] = hashPoints(message, L[i], R[i])
} }
// Complete the signature for the signer // Complete the signature for the signer
s[signerIndex] = new(big.Int).Sub(k, new(big.Int).Mul(c[signerIndex], priv.Scalar)) s[signerIndex] = new(big.Int).Sub(k, new(big.Int).Mul(c[signerIndex], priv.Scalar))
s[signerIndex].Mod(s[signerIndex], curveOrder()) s[signerIndex].Mod(s[signerIndex], curveOrder())
return &RingSignature{ return &RingSignature{
C0: c[0], C0: c[0],
S: s, S: s,
@@ -153,24 +153,24 @@ func (sig *RingSignature) Verify(message []byte) bool {
if len(sig.S) != DefaultRingSize || len(sig.RingPubKeys) != DefaultRingSize { if len(sig.S) != DefaultRingSize || len(sig.RingPubKeys) != DefaultRingSize {
return false return false
} }
// Recompute c values // Recompute c values
c := make([]*big.Int, DefaultRingSize) c := make([]*big.Int, DefaultRingSize)
c[0] = sig.C0 c[0] = sig.C0
for i := 0; i < DefaultRingSize; i++ { for i := 0; i < DefaultRingSize; i++ {
// Compute L_i = s_i * G + c_i * P_i // Compute L_i = s_i * G + c_i * P_i
L := addPoints( L := addPoints(
scalarBaseMult(sig.S[i]), scalarBaseMult(sig.S[i]),
scalarMult(sig.RingPubKeys[i].Point, c[i]), scalarMult(sig.RingPubKeys[i].Point, c[i]),
) )
// Compute R_i = s_i * H(P_i) + c_i * I // Compute R_i = s_i * H(P_i) + c_i * I
R := addPoints( R := addPoints(
scalarMult(hashToPoint(sig.RingPubKeys[i].Point), sig.S[i]), scalarMult(hashToPoint(sig.RingPubKeys[i].Point), sig.S[i]),
scalarMult(sig.KeyImage, c[i]), scalarMult(sig.KeyImage, c[i]),
) )
// Compute next c value // Compute next c value
if i < DefaultRingSize-1 { if i < DefaultRingSize-1 {
c[i+1] = hashPoints(message, L, R) c[i+1] = hashPoints(message, L, R)
@@ -180,7 +180,7 @@ func (sig *RingSignature) Verify(message []byte) bool {
return computedC0.Cmp(sig.C0) == 0 return computedC0.Cmp(sig.C0) == 0
} }
} }
return false return false
} }
@@ -261,4 +261,4 @@ func generateKeyImage(priv *PrivateKey) *Point {
pubKey := priv.PublicKey() pubKey := priv.PublicKey()
hashedPoint := hashToPoint(pubKey.Point) hashedPoint := hashToPoint(pubKey.Point)
return scalarMult(hashedPoint, priv.Scalar) return scalarMult(hashedPoint, priv.Scalar)
} }
+1 -1
View File
@@ -83,4 +83,4 @@ func DecryptFile(encryptedPath string, password string) ([]byte, error) {
} }
return DecryptPrivateKeyWithPassword(data, password) return DecryptPrivateKeyWithPassword(data, password)
} }
+2 -2
View File
@@ -119,7 +119,7 @@ func TestAgeEncryption(t *testing.T) {
// Test empty data // Test empty data
t.Run("EmptyData", func(t *testing.T) { t.Run("EmptyData", func(t *testing.T) {
password := "test-password" password := "test-password"
// Encrypt empty data // Encrypt empty data
encrypted, err := EncryptDataWithPassword([]byte{}, password) encrypted, err := EncryptDataWithPassword([]byte{}, password)
if err != nil { if err != nil {
@@ -201,4 +201,4 @@ func BenchmarkIsAgeEncrypted(b *testing.B) {
IsAgeEncrypted(encrypted) IsAgeEncrypted(encrypted)
IsAgeEncrypted(plain) IsAgeEncrypted(plain)
} }
} }
+1 -1
View File
@@ -118,4 +118,4 @@ func HashWithDomain(domain string, data []byte) Digest {
h := NewWithDomain(domain) h := NewWithDomain(domain)
h.Write(data) h.Write(data)
return h.Digest() return h.Digest()
} }
+52 -52
View File
@@ -22,23 +22,23 @@ func TestNewWithDomain(t *testing.T) {
domain := "test-domain" domain := "test-domain"
h1 := NewWithDomain(domain) h1 := NewWithDomain(domain)
h2 := NewWithDomain(domain) h2 := NewWithDomain(domain)
data := []byte("test data") data := []byte("test data")
h1.Write(data) h1.Write(data)
h2.Write(data) h2.Write(data)
d1 := h1.Digest() d1 := h1.Digest()
d2 := h2.Digest() d2 := h2.Digest()
if !bytes.Equal(d1[:], d2[:]) { if !bytes.Equal(d1[:], d2[:]) {
t.Error("Same domain should produce same hash") t.Error("Same domain should produce same hash")
} }
// Different domain should produce different hash // Different domain should produce different hash
h3 := NewWithDomain("different-domain") h3 := NewWithDomain("different-domain")
h3.Write(data) h3.Write(data)
d3 := h3.Digest() d3 := h3.Digest()
if bytes.Equal(d1[:], d3[:]) { if bytes.Equal(d1[:], d3[:]) {
t.Error("Different domain should produce different hash") t.Error("Different domain should produce different hash")
} }
@@ -59,7 +59,7 @@ func TestHashBytes(t *testing.T) {
"ea8f163db38682925e4491c5e58d4bb3506ef8c14eb78a86e908c5624a67200fe992405f0d785b599a2e3387f6d34d01faccfeb22fb697ef3fd53541241a338c", "ea8f163db38682925e4491c5e58d4bb3506ef8c14eb78a86e908c5624a67200fe992405f0d785b599a2e3387f6d34d01faccfeb22fb697ef3fd53541241a338c",
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
hash := HashBytes(tc.input) hash := HashBytes(tc.input)
hashStr := hex.EncodeToString(hash[:]) hashStr := hex.EncodeToString(hash[:])
@@ -67,12 +67,12 @@ func TestHashBytes(t *testing.T) {
t.Errorf("HashBytes(%q) = %s, want %s", tc.input, hashStr, tc.expected) t.Errorf("HashBytes(%q) = %s, want %s", tc.input, hashStr, tc.expected)
} }
} }
// Test consistency // Test consistency
data := []byte("test data") data := []byte("test data")
h1 := HashBytes(data) h1 := HashBytes(data)
h2 := HashBytes(data) h2 := HashBytes(data)
if !bytes.Equal(h1[:], h2[:]) { if !bytes.Equal(h1[:], h2[:]) {
t.Error("Same input should produce same hash") t.Error("Same input should produce same hash")
} }
@@ -83,17 +83,17 @@ func TestHashString(t *testing.T) {
s := "test string" s := "test string"
h1 := HashString(s) h1 := HashString(s)
h2 := HashString(s) h2 := HashString(s)
if !bytes.Equal(h1[:], h2[:]) { if !bytes.Equal(h1[:], h2[:]) {
t.Error("Same string should produce same hash") t.Error("Same string should produce same hash")
} }
// Compare with HashBytes // Compare with HashBytes
h3 := HashBytes([]byte(s)) h3 := HashBytes([]byte(s))
if !bytes.Equal(h1[:], h3[:]) { if !bytes.Equal(h1[:], h3[:]) {
t.Error("HashString should match HashBytes for same content") t.Error("HashString should match HashBytes for same content")
} }
// Different strings produce different hashes // Different strings produce different hashes
h4 := HashString("different string") h4 := HashString("different string")
if bytes.Equal(h1[:], h4[:]) { if bytes.Equal(h1[:], h4[:]) {
@@ -105,21 +105,21 @@ func TestHashWithDomain(t *testing.T) {
data := []byte("test data") data := []byte("test data")
domain1 := "domain1" domain1 := "domain1"
domain2 := "domain2" domain2 := "domain2"
h1 := HashWithDomain(domain1, data) h1 := HashWithDomain(domain1, data)
h2 := HashWithDomain(domain1, data) h2 := HashWithDomain(domain1, data)
h3 := HashWithDomain(domain2, data) h3 := HashWithDomain(domain2, data)
// Same domain and data should produce same hash // Same domain and data should produce same hash
if !bytes.Equal(h1[:], h2[:]) { if !bytes.Equal(h1[:], h2[:]) {
t.Error("Same domain and data should produce same hash") t.Error("Same domain and data should produce same hash")
} }
// Different domain should produce different hash // Different domain should produce different hash
if bytes.Equal(h1[:], h3[:]) { if bytes.Equal(h1[:], h3[:]) {
t.Error("Different domain should produce different hash") t.Error("Different domain should produce different hash")
} }
// Should differ from hash without domain // Should differ from hash without domain
h4 := HashBytes(data) h4 := HashBytes(data)
if bytes.Equal(h1[:], h4[:]) { if bytes.Equal(h1[:], h4[:]) {
@@ -129,7 +129,7 @@ func TestHashWithDomain(t *testing.T) {
func TestWriteMethods(t *testing.T) { func TestWriteMethods(t *testing.T) {
h := New() h := New()
// Test Write // Test Write
n, err := h.Write([]byte("test")) n, err := h.Write([]byte("test"))
if err != nil { if err != nil {
@@ -138,7 +138,7 @@ func TestWriteMethods(t *testing.T) {
if n != 4 { if n != 4 {
t.Errorf("Write returned %d, want 4", n) t.Errorf("Write returned %d, want 4", n)
} }
// Test WriteString // Test WriteString
n, err = h.WriteString("string") n, err = h.WriteString("string")
if err != nil { if err != nil {
@@ -147,20 +147,20 @@ func TestWriteMethods(t *testing.T) {
if n != 6 { if n != 6 {
t.Errorf("WriteString returned %d, want 6", n) t.Errorf("WriteString returned %d, want 6", n)
} }
// Test WriteUint32 // Test WriteUint32
h.WriteUint32(0x12345678) h.WriteUint32(0x12345678)
// Test WriteUint64 // Test WriteUint64
h.WriteUint64(0x123456789ABCDEF0) h.WriteUint64(0x123456789ABCDEF0)
// Test WriteBigInt // Test WriteBigInt
bigNum := big.NewInt(1234567890) bigNum := big.NewInt(1234567890)
h.WriteBigInt(bigNum) h.WriteBigInt(bigNum)
// Test WriteBigInt with nil // Test WriteBigInt with nil
h.WriteBigInt(nil) h.WriteBigInt(nil)
// Get digest to ensure it doesn't panic // Get digest to ensure it doesn't panic
_ = h.Digest() _ = h.Digest()
} }
@@ -169,12 +169,12 @@ func TestWriteUint32(t *testing.T) {
h1 := New() h1 := New()
h1.WriteUint32(0x12345678) h1.WriteUint32(0x12345678)
d1 := h1.Digest() d1 := h1.Digest()
// Should be same as writing the bytes in big-endian // Should be same as writing the bytes in big-endian
h2 := New() h2 := New()
h2.Write([]byte{0x12, 0x34, 0x56, 0x78}) h2.Write([]byte{0x12, 0x34, 0x56, 0x78})
d2 := h2.Digest() d2 := h2.Digest()
if !bytes.Equal(d1[:], d2[:]) { if !bytes.Equal(d1[:], d2[:]) {
t.Error("WriteUint32 should write in big-endian format") t.Error("WriteUint32 should write in big-endian format")
} }
@@ -184,12 +184,12 @@ func TestWriteUint64(t *testing.T) {
h1 := New() h1 := New()
h1.WriteUint64(0x123456789ABCDEF0) h1.WriteUint64(0x123456789ABCDEF0)
d1 := h1.Digest() d1 := h1.Digest()
// Should be same as writing the bytes in big-endian // Should be same as writing the bytes in big-endian
h2 := New() h2 := New()
h2.Write([]byte{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0}) h2.Write([]byte{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0})
d2 := h2.Digest() d2 := h2.Digest()
if !bytes.Equal(d1[:], d2[:]) { if !bytes.Equal(d1[:], d2[:]) {
t.Error("WriteUint64 should write in big-endian format") t.Error("WriteUint64 should write in big-endian format")
} }
@@ -201,30 +201,30 @@ func TestWriteBigInt(t *testing.T) {
h1 := New() h1 := New()
h1.WriteBigInt(n) h1.WriteBigInt(n)
d1 := h1.Digest() d1 := h1.Digest()
// Writing same number should produce same hash // Writing same number should produce same hash
h2 := New() h2 := New()
h2.WriteBigInt(n) h2.WriteBigInt(n)
d2 := h2.Digest() d2 := h2.Digest()
if !bytes.Equal(d1[:], d2[:]) { if !bytes.Equal(d1[:], d2[:]) {
t.Error("Same big.Int should produce same hash") t.Error("Same big.Int should produce same hash")
} }
// Test with nil // Test with nil
h3 := New() h3 := New()
h3.WriteBigInt(nil) h3.WriteBigInt(nil)
d3 := h3.Digest() d3 := h3.Digest()
// Nil should write a zero length prefix // Nil should write a zero length prefix
h4 := New() h4 := New()
h4.WriteUint32(0) h4.WriteUint32(0)
d4 := h4.Digest() d4 := h4.Digest()
if !bytes.Equal(d3[:], d4[:]) { if !bytes.Equal(d3[:], d4[:]) {
t.Error("WriteBigInt(nil) should write zero length") t.Error("WriteBigInt(nil) should write zero length")
} }
// Test with zero // Test with zero
zero := big.NewInt(0) zero := big.NewInt(0)
h5 := New() h5 := New()
@@ -235,13 +235,13 @@ func TestWriteBigInt(t *testing.T) {
func TestSum(t *testing.T) { func TestSum(t *testing.T) {
h := New() h := New()
h.WriteString("test") h.WriteString("test")
// Sum with nil // Sum with nil
sum1 := h.Sum(nil) sum1 := h.Sum(nil)
if len(sum1) != 32 { // Default blake3 output if len(sum1) != 32 { // Default blake3 output
t.Errorf("Sum(nil) length = %d, want 32", len(sum1)) t.Errorf("Sum(nil) length = %d, want 32", len(sum1))
} }
// Sum with existing slice // Sum with existing slice
prefix := []byte("prefix") prefix := []byte("prefix")
sum2 := h.Sum(prefix) sum2 := h.Sum(prefix)
@@ -257,16 +257,16 @@ func TestDigest(t *testing.T) {
h := New() h := New()
h.WriteString("test") h.WriteString("test")
d := h.Digest() d := h.Digest()
if len(d) != DigestLength { if len(d) != DigestLength {
t.Errorf("Digest length = %d, want %d", len(d), DigestLength) t.Errorf("Digest length = %d, want %d", len(d), DigestLength)
} }
// Digest should be consistent // Digest should be consistent
h2 := New() h2 := New()
h2.WriteString("test") h2.WriteString("test")
d2 := h2.Digest() d2 := h2.Digest()
if !bytes.Equal(d[:], d2[:]) { if !bytes.Equal(d[:], d2[:]) {
t.Error("Same input should produce same digest") t.Error("Same input should produce same digest")
} }
@@ -275,12 +275,12 @@ func TestDigest(t *testing.T) {
func TestReader(t *testing.T) { func TestReader(t *testing.T) {
h := New() h := New()
h.WriteString("test") h.WriteString("test")
reader := h.Reader() reader := h.Reader()
if reader == nil { if reader == nil {
t.Fatal("Reader() returned nil") t.Fatal("Reader() returned nil")
} }
// Read some bytes // Read some bytes
buf := make([]byte, 100) buf := make([]byte, 100)
n, err := reader.Read(buf) n, err := reader.Read(buf)
@@ -295,25 +295,25 @@ func TestReader(t *testing.T) {
func TestClone(t *testing.T) { func TestClone(t *testing.T) {
h1 := New() h1 := New()
h1.WriteString("test") h1.WriteString("test")
h2 := h1.Clone() h2 := h1.Clone()
if h2 == nil { if h2 == nil {
t.Fatal("Clone() returned nil") t.Fatal("Clone() returned nil")
} }
// Both should produce same digest at this point // Both should produce same digest at this point
d1 := h1.Digest() d1 := h1.Digest()
d2 := h2.Digest() d2 := h2.Digest()
if !bytes.Equal(d1[:], d2[:]) { if !bytes.Equal(d1[:], d2[:]) {
t.Error("Clone should produce same digest") t.Error("Clone should produce same digest")
} }
// Writing to one shouldn't affect the other // Writing to one shouldn't affect the other
h1.WriteString("more") h1.WriteString("more")
d1New := h1.Digest() d1New := h1.Digest()
d2New := h2.Digest() d2New := h2.Digest()
if bytes.Equal(d1New[:], d2New[:]) { if bytes.Equal(d1New[:], d2New[:]) {
t.Error("Writing to original should not affect clone") t.Error("Writing to original should not affect clone")
} }
@@ -323,20 +323,20 @@ func TestReset(t *testing.T) {
h := New() h := New()
h.WriteString("test") h.WriteString("test")
d1 := h.Digest() d1 := h.Digest()
h.Reset() h.Reset()
h.WriteString("test") h.WriteString("test")
d2 := h.Digest() d2 := h.Digest()
if !bytes.Equal(d1[:], d2[:]) { if !bytes.Equal(d1[:], d2[:]) {
t.Error("Reset should restore initial state") t.Error("Reset should restore initial state")
} }
// After reset, different input should produce different hash // After reset, different input should produce different hash
h.Reset() h.Reset()
h.WriteString("different") h.WriteString("different")
d3 := h.Digest() d3 := h.Digest()
if bytes.Equal(d1[:], d3[:]) { if bytes.Equal(d1[:], d3[:]) {
t.Error("After reset, different input should produce different hash") t.Error("After reset, different input should produce different hash")
} }
@@ -353,7 +353,7 @@ func BenchmarkHashBytes(b *testing.B) {
for i := range data { for i := range data {
data[i] = byte(i % 256) data[i] = byte(i % 256)
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = HashBytes(data) _ = HashBytes(data)
@@ -362,7 +362,7 @@ func BenchmarkHashBytes(b *testing.B) {
func BenchmarkHashString(b *testing.B) { func BenchmarkHashString(b *testing.B) {
data := strings.Repeat("benchmark", 128) data := strings.Repeat("benchmark", 128)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = HashString(data) _ = HashString(data)
@@ -372,11 +372,11 @@ func BenchmarkHashString(b *testing.B) {
func BenchmarkWriteBigInt(b *testing.B) { func BenchmarkWriteBigInt(b *testing.B) {
n := new(big.Int) n := new(big.Int)
n.SetString("123456789012345678901234567890123456789012345678901234567890", 10) n.SetString("123456789012345678901234567890123456789012345678901234567890", 10)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
h := New() h := New()
h.WriteBigInt(n) h.WriteBigInt(n)
_ = h.Digest() _ = h.Digest()
} }
} }
+24 -24
View File
@@ -103,16 +103,16 @@ func TestComputeHash160(t *testing.T) {
func TestChecksum(t *testing.T) { func TestChecksum(t *testing.T) {
input := []byte("test input for checksum") input := []byte("test input for checksum")
// Test various checksum lengths // Test various checksum lengths
lengths := []int{1, 4, 8, 16, 32} lengths := []int{1, 4, 8, 16, 32}
for _, length := range lengths { for _, length := range lengths {
checksum := Checksum(input, length) checksum := Checksum(input, length)
if len(checksum) != length { if len(checksum) != length {
t.Errorf("Checksum length should be %d, got %d", length, len(checksum)) t.Errorf("Checksum length should be %d, got %d", length, len(checksum))
} }
// Verify checksum is last 'length' bytes of hash // Verify checksum is last 'length' bytes of hash
fullHash := ComputeHash256Array(input) fullHash := ComputeHash256Array(input)
expected := fullHash[len(fullHash)-length:] expected := fullHash[len(fullHash)-length:]
@@ -120,14 +120,14 @@ func TestChecksum(t *testing.T) {
t.Errorf("Checksum should be last %d bytes of hash", length) t.Errorf("Checksum should be last %d bytes of hash", length)
} }
} }
// Test that same input produces same checksum // Test that same input produces same checksum
checksum1 := Checksum(input, 4) checksum1 := Checksum(input, 4)
checksum2 := Checksum(input, 4) checksum2 := Checksum(input, 4)
if !bytes.Equal(checksum1, checksum2) { if !bytes.Equal(checksum1, checksum2) {
t.Error("Same input should produce same checksum") t.Error("Same input should produce same checksum")
} }
// Test that different input produces different checksum // Test that different input produces different checksum
input2 := []byte("different input") input2 := []byte("different input")
checksum3 := Checksum(input2, 4) checksum3 := Checksum(input2, 4)
@@ -142,16 +142,16 @@ func TestToHash256(t *testing.T) {
for i := range validBytes { for i := range validBytes {
validBytes[i] = byte(i) validBytes[i] = byte(i)
} }
hash, err := ToHash256(validBytes) hash, err := ToHash256(validBytes)
if err != nil { if err != nil {
t.Errorf("ToHash256 with valid bytes should not error: %v", err) t.Errorf("ToHash256 with valid bytes should not error: %v", err)
} }
if !bytes.Equal(hash[:], validBytes) { if !bytes.Equal(hash[:], validBytes) {
t.Error("ToHash256 should copy bytes correctly") t.Error("ToHash256 should copy bytes correctly")
} }
// Test invalid lengths // Test invalid lengths
invalidLengths := []int{0, 1, 31, 33, 100} invalidLengths := []int{0, 1, 31, 33, 100}
for _, length := range invalidLengths { for _, length := range invalidLengths {
@@ -172,16 +172,16 @@ func TestToHash160(t *testing.T) {
for i := range validBytes { for i := range validBytes {
validBytes[i] = byte(i) validBytes[i] = byte(i)
} }
hash, err := ToHash160(validBytes) hash, err := ToHash160(validBytes)
if err != nil { if err != nil {
t.Errorf("ToHash160 with valid bytes should not error: %v", err) t.Errorf("ToHash160 with valid bytes should not error: %v", err)
} }
if !bytes.Equal(hash[:], validBytes) { if !bytes.Equal(hash[:], validBytes) {
t.Error("ToHash160 should copy bytes correctly") t.Error("ToHash160 should copy bytes correctly")
} }
// Test invalid lengths // Test invalid lengths
invalidLengths := []int{0, 1, 19, 21, 100} invalidLengths := []int{0, 1, 19, 21, 100}
for _, length := range invalidLengths { for _, length := range invalidLengths {
@@ -199,27 +199,27 @@ func TestToHash160(t *testing.T) {
func TestPubkeyBytesToAddress(t *testing.T) { func TestPubkeyBytesToAddress(t *testing.T) {
// Test that address generation is consistent // Test that address generation is consistent
pubkey := []byte("test public key") pubkey := []byte("test public key")
addr1 := PubkeyBytesToAddress(pubkey) addr1 := PubkeyBytesToAddress(pubkey)
addr2 := PubkeyBytesToAddress(pubkey) addr2 := PubkeyBytesToAddress(pubkey)
if !bytes.Equal(addr1, addr2) { if !bytes.Equal(addr1, addr2) {
t.Error("Same pubkey should produce same address") t.Error("Same pubkey should produce same address")
} }
// Test that different pubkeys produce different addresses // Test that different pubkeys produce different addresses
pubkey2 := []byte("different public key") pubkey2 := []byte("different public key")
addr3 := PubkeyBytesToAddress(pubkey2) addr3 := PubkeyBytesToAddress(pubkey2)
if bytes.Equal(addr1, addr3) { if bytes.Equal(addr1, addr3) {
t.Error("Different pubkeys should produce different addresses") t.Error("Different pubkeys should produce different addresses")
} }
// Test that address is 20 bytes (ripemd160 size) // Test that address is 20 bytes (ripemd160 size)
if len(addr1) != AddrLen { if len(addr1) != AddrLen {
t.Errorf("Address should be %d bytes, got %d", AddrLen, len(addr1)) t.Errorf("Address should be %d bytes, got %d", AddrLen, len(addr1))
} }
// Test empty pubkey // Test empty pubkey
emptyAddr := PubkeyBytesToAddress([]byte{}) emptyAddr := PubkeyBytesToAddress([]byte{})
if len(emptyAddr) != AddrLen { if len(emptyAddr) != AddrLen {
@@ -232,7 +232,7 @@ func TestHashConstants(t *testing.T) {
if HashLen != 32 { if HashLen != 32 {
t.Errorf("HashLen should be 32, got %d", HashLen) t.Errorf("HashLen should be 32, got %d", HashLen)
} }
if AddrLen != 20 { if AddrLen != 20 {
t.Errorf("AddrLen should be 20, got %d", AddrLen) t.Errorf("AddrLen should be 20, got %d", AddrLen)
} }
@@ -243,7 +243,7 @@ func BenchmarkComputeHash256(b *testing.B) {
for i := range input { for i := range input {
input[i] = byte(i % 256) input[i] = byte(i % 256)
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = ComputeHash256(input) _ = ComputeHash256(input)
@@ -255,7 +255,7 @@ func BenchmarkComputeHash256Array(b *testing.B) {
for i := range input { for i := range input {
input[i] = byte(i % 256) input[i] = byte(i % 256)
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = ComputeHash256Array(input) _ = ComputeHash256Array(input)
@@ -267,7 +267,7 @@ func BenchmarkComputeHash160(b *testing.B) {
for i := range input { for i := range input {
input[i] = byte(i % 256) input[i] = byte(i % 256)
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = ComputeHash160(input) _ = ComputeHash160(input)
@@ -279,7 +279,7 @@ func BenchmarkPubkeyBytesToAddress(b *testing.B) {
for i := range pubkey { for i := range pubkey {
pubkey[i] = byte(i % 256) pubkey[i] = byte(i % 256)
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = PubkeyBytesToAddress(pubkey) _ = PubkeyBytesToAddress(pubkey)
@@ -291,9 +291,9 @@ func BenchmarkChecksum(b *testing.B) {
for i := range input { for i := range input {
input[i] = byte(i % 256) input[i] = byte(i % 256)
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = Checksum(input, 4) _ = Checksum(input, 4)
} }
} }
+1 -1
View File
@@ -48,4 +48,4 @@ var NewSuite = hpke.NewSuite
type Sender = hpke.Sender type Sender = hpke.Sender
// Receiver represents an HPKE receiver context // Receiver represents an HPKE receiver context
type Receiver = hpke.Receiver type Receiver = hpke.Receiver
+39 -39
View File
@@ -48,7 +48,7 @@ type KeySchedule struct {
// NewKeySchedule creates a new key schedule // NewKeySchedule creates a new key schedule
func NewKeySchedule(suite Suite) *KeySchedule { func NewKeySchedule(suite Suite) *KeySchedule {
var hashFunc func() hash.Hash var hashFunc func() hash.Hash
switch suite.Hash { switch suite.Hash {
case SHA256: case SHA256:
hashFunc = sha256.New hashFunc = sha256.New
@@ -57,7 +57,7 @@ func NewKeySchedule(suite Suite) *KeySchedule {
default: default:
hashFunc = sha256.New hashFunc = sha256.New
} }
return &KeySchedule{ return &KeySchedule{
suite: suite, suite: suite,
hash: hashFunc, hash: hashFunc,
@@ -68,39 +68,39 @@ func NewKeySchedule(suite Suite) *KeySchedule {
func (ks *KeySchedule) DeriveHandshakeKeys(kemSecret, ecdheSecret []byte, transcript []byte) (*HandshakeKeys, error) { func (ks *KeySchedule) DeriveHandshakeKeys(kemSecret, ecdheSecret []byte, transcript []byte) (*HandshakeKeys, error) {
// Concatenate secrets // Concatenate secrets
combined := append(kemSecret, ecdheSecret...) combined := append(kemSecret, ecdheSecret...)
// HKDF-Extract // HKDF-Extract
salt := []byte("QZMQ-v1-Handshake") salt := []byte("QZMQ-v1-Handshake")
prk := hkdf.Extract(ks.hash, combined, salt) prk := hkdf.Extract(ks.hash, combined, salt)
// Derive various keys using HKDF-Expand // Derive various keys using HKDF-Expand
keys := &HandshakeKeys{} keys := &HandshakeKeys{}
// Client traffic secret // Client traffic secret
clientInfo := append([]byte("client traffic secret"), transcript...) clientInfo := append([]byte("client traffic secret"), transcript...)
clientSecret := ks.expand(prk, clientInfo, 32) clientSecret := ks.expand(prk, clientInfo, 32)
// Server traffic secret // Server traffic secret
serverInfo := append([]byte("server traffic secret"), transcript...) serverInfo := append([]byte("server traffic secret"), transcript...)
serverSecret := ks.expand(prk, serverInfo, 32) serverSecret := ks.expand(prk, serverInfo, 32)
// Derive actual keys and IVs from traffic secrets // Derive actual keys and IVs from traffic secrets
keys.ClientKey = ks.expand(clientSecret, []byte("key"), 32) keys.ClientKey = ks.expand(clientSecret, []byte("key"), 32)
keys.ClientIV = ks.expand(clientSecret, []byte("iv"), 12) keys.ClientIV = ks.expand(clientSecret, []byte("iv"), 12)
keys.ServerKey = ks.expand(serverSecret, []byte("key"), 32) keys.ServerKey = ks.expand(serverSecret, []byte("key"), 32)
keys.ServerIV = ks.expand(serverSecret, []byte("iv"), 12) keys.ServerIV = ks.expand(serverSecret, []byte("iv"), 12)
// Exporter secret // Exporter secret
exporterInfo := append([]byte("exporter secret"), transcript...) exporterInfo := append([]byte("exporter secret"), transcript...)
keys.ExporterSecret = ks.expand(prk, exporterInfo, 32) keys.ExporterSecret = ks.expand(prk, exporterInfo, 32)
// Generate key ID // Generate key ID
keyIDBytes := ks.expand(prk, []byte("key id"), 4) keyIDBytes := ks.expand(prk, []byte("key id"), 4)
keys.KeyID = binary.BigEndian.Uint32(keyIDBytes) keys.KeyID = binary.BigEndian.Uint32(keyIDBytes)
ks.handshakeKeys = keys ks.handshakeKeys = keys
ks.updateCounter = 0 ks.updateCounter = 0
return keys, nil return keys, nil
} }
@@ -109,39 +109,39 @@ func (ks *KeySchedule) KeyUpdate() (*HandshakeKeys, error) {
if ks.handshakeKeys == nil { if ks.handshakeKeys == nil {
return nil, ErrNoHandshakeKeys return nil, ErrNoHandshakeKeys
} }
ks.updateCounter++ ks.updateCounter++
// Create update info with counter // Create update info with counter
updateInfo := make([]byte, 4) updateInfo := make([]byte, 4)
binary.BigEndian.PutUint32(updateInfo, ks.updateCounter) binary.BigEndian.PutUint32(updateInfo, ks.updateCounter)
// Ratchet client key // Ratchet client key
newClientSecret := ks.expand( newClientSecret := ks.expand(
ks.handshakeKeys.ClientKey, ks.handshakeKeys.ClientKey,
append([]byte("key update"), updateInfo...), append([]byte("key update"), updateInfo...),
32, 32,
) )
// Ratchet server key // Ratchet server key
newServerSecret := ks.expand( newServerSecret := ks.expand(
ks.handshakeKeys.ServerKey, ks.handshakeKeys.ServerKey,
append([]byte("key update"), updateInfo...), append([]byte("key update"), updateInfo...),
32, 32,
) )
// Derive new keys // Derive new keys
newKeys := &HandshakeKeys{ newKeys := &HandshakeKeys{
ClientKey: ks.expand(newClientSecret, []byte("key"), 32), ClientKey: ks.expand(newClientSecret, []byte("key"), 32),
ClientIV: ks.expand(newClientSecret, []byte("iv"), 12), ClientIV: ks.expand(newClientSecret, []byte("iv"), 12),
ServerKey: ks.expand(newServerSecret, []byte("key"), 32), ServerKey: ks.expand(newServerSecret, []byte("key"), 32),
ServerIV: ks.expand(newServerSecret, []byte("iv"), 12), ServerIV: ks.expand(newServerSecret, []byte("iv"), 12),
ExporterSecret: ks.handshakeKeys.ExporterSecret, // Exporter doesn't change ExporterSecret: ks.handshakeKeys.ExporterSecret, // Exporter doesn't change
KeyID: ks.handshakeKeys.KeyID + ks.updateCounter, KeyID: ks.handshakeKeys.KeyID + ks.updateCounter,
} }
ks.handshakeKeys = newKeys ks.handshakeKeys = newKeys
return newKeys, nil return newKeys, nil
} }
@@ -150,7 +150,7 @@ func (ks *KeySchedule) Export(context []byte, length int) ([]byte, error) {
if ks.handshakeKeys == nil { if ks.handshakeKeys == nil {
return nil, ErrNoHandshakeKeys return nil, ErrNoHandshakeKeys
} }
info := append([]byte("QZMQ exporter"), context...) info := append([]byte("QZMQ exporter"), context...)
return ks.expand(ks.handshakeKeys.ExporterSecret, info, length), nil return ks.expand(ks.handshakeKeys.ExporterSecret, info, length), nil
} }
@@ -159,11 +159,11 @@ func (ks *KeySchedule) Export(context []byte, length int) ([]byte, error) {
func (ks *KeySchedule) expand(prk, info []byte, length int) []byte { func (ks *KeySchedule) expand(prk, info []byte, length int) []byte {
r := hkdf.Expand(ks.hash, prk, info) r := hkdf.Expand(ks.hash, prk, info)
output := make([]byte, length) output := make([]byte, length)
if _, err := io.ReadFull(r, output); err != nil { if _, err := io.ReadFull(r, output); err != nil {
panic(err) // Should never happen with correct parameters panic(err) // Should never happen with correct parameters
} }
return output return output
} }
@@ -172,22 +172,22 @@ func (ks *KeySchedule) DeriveEarlyDataKeys(psk []byte, transcript []byte) (*Hand
// HKDF-Extract with PSK // HKDF-Extract with PSK
salt := []byte("QZMQ-v1-EarlyData") salt := []byte("QZMQ-v1-EarlyData")
prk := hkdf.Extract(ks.hash, psk, salt) prk := hkdf.Extract(ks.hash, psk, salt)
// Derive early traffic secret // Derive early traffic secret
earlyInfo := append([]byte("early traffic secret"), transcript...) earlyInfo := append([]byte("early traffic secret"), transcript...)
earlySecret := ks.expand(prk, earlyInfo, 32) earlySecret := ks.expand(prk, earlyInfo, 32)
// Derive keys for early data // Derive keys for early data
keys := &HandshakeKeys{ keys := &HandshakeKeys{
ClientKey: ks.expand(earlySecret, []byte("key"), 32), ClientKey: ks.expand(earlySecret, []byte("key"), 32),
ClientIV: ks.expand(earlySecret, []byte("iv"), 12), ClientIV: ks.expand(earlySecret, []byte("iv"), 12),
// Server doesn't send early data, so no server keys // Server doesn't send early data, so no server keys
ServerKey: nil, ServerKey: nil,
ServerIV: nil, ServerIV: nil,
ExporterSecret: ks.expand(prk, []byte("early exporter secret"), 32), ExporterSecret: ks.expand(prk, []byte("early exporter secret"), 32),
KeyID: 0, // Special ID for early data KeyID: 0, // Special ID for early data
} }
return keys, nil return keys, nil
} }
@@ -196,7 +196,7 @@ func (ks *KeySchedule) ResumptionSecret(transcript []byte) ([]byte, error) {
if ks.handshakeKeys == nil { if ks.handshakeKeys == nil {
return nil, ErrNoHandshakeKeys return nil, ErrNoHandshakeKeys
} }
info := append([]byte("resumption secret"), transcript...) info := append([]byte("resumption secret"), transcript...)
return ks.expand(ks.handshakeKeys.ExporterSecret, info, 32), nil return ks.expand(ks.handshakeKeys.ExporterSecret, info, 32), nil
} }
@@ -219,7 +219,7 @@ type Budgets struct {
MaxMessages uint32 MaxMessages uint32
MaxBytes uint64 MaxBytes uint64
MaxAge int // seconds MaxAge int // seconds
currentMessages uint32 currentMessages uint32
currentBytes uint64 currentBytes uint64
keyBirth int64 // unix timestamp keyBirth int64 // unix timestamp
@@ -238,19 +238,19 @@ func NewBudgets(maxMsgs uint32, maxBytes uint64, maxAge int) *Budgets {
func (b *Budgets) CheckAndUpdate(msgSize int, now int64) bool { func (b *Budgets) CheckAndUpdate(msgSize int, now int64) bool {
b.currentMessages++ b.currentMessages++
b.currentBytes += uint64(msgSize) b.currentBytes += uint64(msgSize)
if b.currentMessages >= b.MaxMessages { if b.currentMessages >= b.MaxMessages {
return true return true
} }
if b.currentBytes >= b.MaxBytes { if b.currentBytes >= b.MaxBytes {
return true return true
} }
if b.keyBirth > 0 && now-b.keyBirth >= int64(b.MaxAge) { if b.keyBirth > 0 && now-b.keyBirth >= int64(b.MaxAge) {
return true return true
} }
return false return false
} }
@@ -259,4 +259,4 @@ func (b *Budgets) Reset(now int64) {
b.currentMessages = 0 b.currentMessages = 0
b.currentBytes = 0 b.currentBytes = 0
b.keyBirth = now b.keyBirth = now
} }
+4 -4
View File
@@ -19,7 +19,7 @@ func shouldUseCGO() bool {
useCGO = false useCGO = false
return return
} }
// Default to CGO if available (detected at build time) // Default to CGO if available (detected at build time)
useCGO = cgoAvailable() useCGO = cgoAvailable()
}) })
@@ -62,12 +62,12 @@ func NewHybrid() (KEM, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
mlkem, err := NewMLKEM768() mlkem, err := NewMLKEM768()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newHybridKEM(x25519, mlkem) return newHybridKEM(x25519, mlkem)
} }
@@ -92,4 +92,4 @@ func newHybridKEM(classical, pq KEM) (KEM, error) {
x25519: classical, x25519: classical,
mlkem: pq, mlkem: pq,
}, nil }, nil
} }
+20 -20
View File
@@ -42,22 +42,22 @@ func (h *HybridKEMImpl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
mlkemPK, mlkemSK, err := h.mlkem.GenerateKeyPair() mlkemPK, mlkemSK, err := h.mlkem.GenerateKeyPair()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
pk := &HybridPublicKey{ pk := &HybridPublicKey{
X25519PK: x25519PK, X25519PK: x25519PK,
MLKEMPK: mlkemPK, MLKEMPK: mlkemPK,
} }
sk := &HybridPrivateKey{ sk := &HybridPrivateKey{
X25519SK: x25519SK, X25519SK: x25519SK,
MLKEMSK: mlkemSK, MLKEMSK: mlkemSK,
} }
return pk, sk, nil return pk, sk, nil
} }
@@ -67,25 +67,25 @@ func (h *HybridKEMImpl) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
if !ok { if !ok {
return nil, nil, errors.New("invalid public key type for hybrid KEM") return nil, nil, errors.New("invalid public key type for hybrid KEM")
} }
// Perform X25519 encapsulation // Perform X25519 encapsulation
x25519CT, x25519SS, err := h.x25519.Encapsulate(hybridPK.X25519PK) x25519CT, x25519SS, err := h.x25519.Encapsulate(hybridPK.X25519PK)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
// Perform ML-KEM encapsulation // Perform ML-KEM encapsulation
mlkemCT, mlkemSS, err := h.mlkem.Encapsulate(hybridPK.MLKEMPK) mlkemCT, mlkemSS, err := h.mlkem.Encapsulate(hybridPK.MLKEMPK)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
// Concatenate ciphertexts // Concatenate ciphertexts
ciphertext := append(x25519CT, mlkemCT...) ciphertext := append(x25519CT, mlkemCT...)
// Derive shared secret using HKDF // Derive shared secret using HKDF
sharedSecret := h.deriveSharedSecret(x25519SS, mlkemSS) sharedSecret := h.deriveSharedSecret(x25519SS, mlkemSS)
return ciphertext, sharedSecret, nil return ciphertext, sharedSecret, nil
} }
@@ -95,31 +95,31 @@ func (h *HybridKEMImpl) Decapsulate(sk PrivateKey, ciphertext []byte) ([]byte, e
if !ok { if !ok {
return nil, errors.New("invalid private key type for hybrid KEM") return nil, errors.New("invalid private key type for hybrid KEM")
} }
x25519CTSize := h.x25519.CiphertextSize() x25519CTSize := h.x25519.CiphertextSize()
if len(ciphertext) < x25519CTSize { if len(ciphertext) < x25519CTSize {
return nil, errors.New("ciphertext too short") return nil, errors.New("ciphertext too short")
} }
// Split ciphertext // Split ciphertext
x25519CT := ciphertext[:x25519CTSize] x25519CT := ciphertext[:x25519CTSize]
mlkemCT := ciphertext[x25519CTSize:] mlkemCT := ciphertext[x25519CTSize:]
// Perform X25519 decapsulation // Perform X25519 decapsulation
x25519SS, err := h.x25519.Decapsulate(hybridSK.X25519SK, x25519CT) x25519SS, err := h.x25519.Decapsulate(hybridSK.X25519SK, x25519CT)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Perform ML-KEM decapsulation // Perform ML-KEM decapsulation
mlkemSS, err := h.mlkem.Decapsulate(hybridSK.MLKEMSK, mlkemCT) mlkemSS, err := h.mlkem.Decapsulate(hybridSK.MLKEMSK, mlkemCT)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Derive shared secret using HKDF // Derive shared secret using HKDF
sharedSecret := h.deriveSharedSecret(x25519SS, mlkemSS) sharedSecret := h.deriveSharedSecret(x25519SS, mlkemSS)
return sharedSecret, nil return sharedSecret, nil
} }
@@ -127,18 +127,18 @@ func (h *HybridKEMImpl) Decapsulate(sk PrivateKey, ciphertext []byte) ([]byte, e
func (h *HybridKEMImpl) deriveSharedSecret(x25519SS, mlkemSS []byte) []byte { func (h *HybridKEMImpl) deriveSharedSecret(x25519SS, mlkemSS []byte) []byte {
// Concatenate secrets // Concatenate secrets
combined := append(x25519SS, mlkemSS...) combined := append(x25519SS, mlkemSS...)
// Use HKDF-Extract then Expand // Use HKDF-Extract then Expand
salt := []byte("QZMQ-HybridKEM-v1") salt := []byte("QZMQ-HybridKEM-v1")
info := []byte("hybrid-kem-shared-secret") info := []byte("hybrid-kem-shared-secret")
hkdf := hkdf.New(sha256.New, combined, salt, info) hkdf := hkdf.New(sha256.New, combined, salt, info)
sharedSecret := make([]byte, 32) sharedSecret := make([]byte, 32)
if _, err := io.ReadFull(hkdf, sharedSecret); err != nil { if _, err := io.ReadFull(hkdf, sharedSecret); err != nil {
panic(err) // Should never happen with correct sizes panic(err) // Should never happen with correct sizes
} }
return sharedSecret return sharedSecret
} }
@@ -193,4 +193,4 @@ func (sk *HybridPrivateKey) Equal(other PrivateKey) bool {
return false return false
} }
return sk.X25519SK.Equal(otherSK.X25519SK) && sk.MLKEMSK.Equal(otherSK.MLKEMSK) return sk.X25519SK.Equal(otherSK.X25519SK) && sk.MLKEMSK.Equal(otherSK.MLKEMSK)
} }
+11 -11
View File
@@ -19,22 +19,22 @@ const (
type KEM interface { type KEM interface {
// GenerateKeyPair generates a new KEM key pair // GenerateKeyPair generates a new KEM key pair
GenerateKeyPair() (PublicKey, PrivateKey, error) GenerateKeyPair() (PublicKey, PrivateKey, error)
// Encapsulate generates a shared secret and ciphertext // Encapsulate generates a shared secret and ciphertext
Encapsulate(pk PublicKey) (ciphertext []byte, sharedSecret []byte, err error) Encapsulate(pk PublicKey) (ciphertext []byte, sharedSecret []byte, err error)
// Decapsulate recovers the shared secret from ciphertext // Decapsulate recovers the shared secret from ciphertext
Decapsulate(sk PrivateKey, ciphertext []byte) (sharedSecret []byte, err error) Decapsulate(sk PrivateKey, ciphertext []byte) (sharedSecret []byte, err error)
// PublicKeySize returns the size of public keys // PublicKeySize returns the size of public keys
PublicKeySize() int PublicKeySize() int
// PrivateKeySize returns the size of private keys // PrivateKeySize returns the size of private keys
PrivateKeySize() int PrivateKeySize() int
// CiphertextSize returns the size of ciphertexts // CiphertextSize returns the size of ciphertexts
CiphertextSize() int CiphertextSize() int
// SharedSecretSize returns the size of shared secrets // SharedSecretSize returns the size of shared secrets
SharedSecretSize() int SharedSecretSize() int
} }
@@ -54,10 +54,10 @@ type PrivateKey interface {
// Constants for ML-KEM-768 // Constants for ML-KEM-768
const ( const (
mlkem768PublicKeySize = 1184 mlkem768PublicKeySize = 1184
mlkem768PrivateKeySize = 2400 mlkem768PrivateKeySize = 2400
mlkem768CiphertextSize = 1088 mlkem768CiphertextSize = 1088
mlkem768SharedSecretSize = 32 mlkem768SharedSecretSize = 32
) )
// Constants for ML-KEM-1024 // Constants for ML-KEM-1024
@@ -82,4 +82,4 @@ func GetKEM(id KemID) (KEM, error) {
default: default:
return nil, fmt.Errorf("unsupported KEM: %s", id) return nil, fmt.Errorf("unsupported KEM: %s", id)
} }
} }
+21 -27
View File
@@ -14,7 +14,6 @@ type MLKEM768Impl struct {
k int // k parameter (3 for ML-KEM-768) k int // k parameter (3 for ML-KEM-768)
} }
// MLKEM768PublicKey represents an ML-KEM-768 public key // MLKEM768PublicKey represents an ML-KEM-768 public key
type MLKEM768PublicKey struct { type MLKEM768PublicKey struct {
data []byte data []byte
@@ -26,12 +25,11 @@ type MLKEM768PrivateKey struct {
pk *MLKEM768PublicKey pk *MLKEM768PublicKey
} }
// GenerateKeyPair generates a new ML-KEM-768 key pair // GenerateKeyPair generates a new ML-KEM-768 key pair
func (m *MLKEM768Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) { func (m *MLKEM768Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
// Placeholder for actual ML-KEM-768 key generation // Placeholder for actual ML-KEM-768 key generation
// In production, this would use liboqs or a native implementation // In production, this would use liboqs or a native implementation
pk := &MLKEM768PublicKey{ pk := &MLKEM768PublicKey{
data: make([]byte, mlkem768PublicKeySize), data: make([]byte, mlkem768PublicKeySize),
} }
@@ -39,7 +37,7 @@ func (m *MLKEM768Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
data: make([]byte, mlkem768PrivateKeySize), data: make([]byte, mlkem768PrivateKeySize),
pk: pk, pk: pk,
} }
// Generate random key material (placeholder) // Generate random key material (placeholder)
if _, err := rand.Read(pk.data); err != nil { if _, err := rand.Read(pk.data); err != nil {
return nil, nil, err return nil, nil, err
@@ -47,7 +45,7 @@ func (m *MLKEM768Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
if _, err := rand.Read(sk.data); err != nil { if _, err := rand.Read(sk.data); err != nil {
return nil, nil, err return nil, nil, err
} }
return pk, sk, nil return pk, sk, nil
} }
@@ -57,10 +55,10 @@ func (m *MLKEM768Impl) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
if !ok { if !ok {
return nil, nil, errors.New("invalid public key type") return nil, nil, errors.New("invalid public key type")
} }
ciphertext := make([]byte, mlkem768CiphertextSize) ciphertext := make([]byte, mlkem768CiphertextSize)
sharedSecret := make([]byte, mlkem768SharedSecretSize) sharedSecret := make([]byte, mlkem768SharedSecretSize)
// Placeholder for actual ML-KEM-768 encapsulation // Placeholder for actual ML-KEM-768 encapsulation
if _, err := rand.Read(ciphertext); err != nil { if _, err := rand.Read(ciphertext); err != nil {
return nil, nil, err return nil, nil, err
@@ -68,10 +66,10 @@ func (m *MLKEM768Impl) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
if _, err := rand.Read(sharedSecret); err != nil { if _, err := rand.Read(sharedSecret); err != nil {
return nil, nil, err return nil, nil, err
} }
// In production, this would perform actual ML-KEM encapsulation // In production, this would perform actual ML-KEM encapsulation
_ = mlkemPK.data _ = mlkemPK.data
return ciphertext, sharedSecret, nil return ciphertext, sharedSecret, nil
} }
@@ -81,22 +79,22 @@ func (m *MLKEM768Impl) Decapsulate(sk PrivateKey, ciphertext []byte) ([]byte, er
if !ok { if !ok {
return nil, errors.New("invalid private key type") return nil, errors.New("invalid private key type")
} }
if len(ciphertext) != mlkem768CiphertextSize { if len(ciphertext) != mlkem768CiphertextSize {
return nil, errors.New("invalid ciphertext size") return nil, errors.New("invalid ciphertext size")
} }
sharedSecret := make([]byte, mlkem768SharedSecretSize) sharedSecret := make([]byte, mlkem768SharedSecretSize)
// Placeholder for actual ML-KEM-768 decapsulation // Placeholder for actual ML-KEM-768 decapsulation
if _, err := rand.Read(sharedSecret); err != nil { if _, err := rand.Read(sharedSecret); err != nil {
return nil, err return nil, err
} }
// In production, this would perform actual ML-KEM decapsulation // In production, this would perform actual ML-KEM decapsulation
_ = mlkemSK.data _ = mlkemSK.data
_ = ciphertext _ = ciphertext
return sharedSecret, nil return sharedSecret, nil
} }
@@ -153,7 +151,6 @@ func (sk *MLKEM768PrivateKey) Equal(other PrivateKey) bool {
return subtle.ConstantTimeCompare(sk.data, otherSK.data) == 1 return subtle.ConstantTimeCompare(sk.data, otherSK.data) == 1
} }
// MLKEM1024 implementation (similar structure, different parameters) // MLKEM1024 implementation (similar structure, different parameters)
type MLKEM1024Impl struct { type MLKEM1024Impl struct {
k int // k parameter (4 for ML-KEM-1024) k int // k parameter (4 for ML-KEM-1024)
@@ -170,8 +167,6 @@ type MLKEM1024PrivateKey struct {
pk *MLKEM1024PublicKey pk *MLKEM1024PublicKey
} }
// GenerateKeyPair generates a new ML-KEM-1024 key pair // GenerateKeyPair generates a new ML-KEM-1024 key pair
func (m *MLKEM1024Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) { func (m *MLKEM1024Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
// Similar to ML-KEM-768 but with different sizes // Similar to ML-KEM-768 but with different sizes
@@ -182,14 +177,14 @@ func (m *MLKEM1024Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
data: make([]byte, mlkem1024PrivateKeySize), data: make([]byte, mlkem1024PrivateKeySize),
pk: pk, pk: pk,
} }
if _, err := rand.Read(pk.data); err != nil { if _, err := rand.Read(pk.data); err != nil {
return nil, nil, err return nil, nil, err
} }
if _, err := rand.Read(sk.data); err != nil { if _, err := rand.Read(sk.data); err != nil {
return nil, nil, err return nil, nil, err
} }
return pk, sk, nil return pk, sk, nil
} }
@@ -197,14 +192,14 @@ func (m *MLKEM1024Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
func (m *MLKEM1024Impl) Encapsulate(pk PublicKey) ([]byte, []byte, error) { func (m *MLKEM1024Impl) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
ciphertext := make([]byte, mlkem1024CiphertextSize) ciphertext := make([]byte, mlkem1024CiphertextSize)
sharedSecret := make([]byte, mlkem1024SharedSecretSize) sharedSecret := make([]byte, mlkem1024SharedSecretSize)
if _, err := rand.Read(ciphertext); err != nil { if _, err := rand.Read(ciphertext); err != nil {
return nil, nil, err return nil, nil, err
} }
if _, err := rand.Read(sharedSecret); err != nil { if _, err := rand.Read(sharedSecret); err != nil {
return nil, nil, err return nil, nil, err
} }
return ciphertext, sharedSecret, nil return ciphertext, sharedSecret, nil
} }
@@ -213,19 +208,19 @@ func (m *MLKEM1024Impl) Decapsulate(sk PrivateKey, ciphertext []byte) ([]byte, e
if len(ciphertext) != mlkem1024CiphertextSize { if len(ciphertext) != mlkem1024CiphertextSize {
return nil, errors.New("invalid ciphertext size") return nil, errors.New("invalid ciphertext size")
} }
sharedSecret := make([]byte, mlkem1024SharedSecretSize) sharedSecret := make([]byte, mlkem1024SharedSecretSize)
if _, err := rand.Read(sharedSecret); err != nil { if _, err := rand.Read(sharedSecret); err != nil {
return nil, err return nil, err
} }
return sharedSecret, nil return sharedSecret, nil
} }
// Size methods for ML-KEM-1024 // Size methods for ML-KEM-1024
func (m *MLKEM1024Impl) PublicKeySize() int { return mlkem1024PublicKeySize } func (m *MLKEM1024Impl) PublicKeySize() int { return mlkem1024PublicKeySize }
func (m *MLKEM1024Impl) PrivateKeySize() int { return mlkem1024PrivateKeySize } func (m *MLKEM1024Impl) PrivateKeySize() int { return mlkem1024PrivateKeySize }
func (m *MLKEM1024Impl) CiphertextSize() int { return mlkem1024CiphertextSize } func (m *MLKEM1024Impl) CiphertextSize() int { return mlkem1024CiphertextSize }
func (m *MLKEM1024Impl) SharedSecretSize() int { return mlkem1024SharedSecretSize } func (m *MLKEM1024Impl) SharedSecretSize() int { return mlkem1024SharedSecretSize }
// Bytes returns the raw bytes of the public key // Bytes returns the raw bytes of the public key
@@ -260,4 +255,3 @@ func (sk *MLKEM1024PrivateKey) Equal(other PrivateKey) bool {
} }
return subtle.ConstantTimeCompare(sk.data, otherSK.data) == 1 return subtle.ConstantTimeCompare(sk.data, otherSK.data) == 1
} }
+34 -34
View File
@@ -83,7 +83,7 @@ func NewMLKEM768CGO() (*MLKEM768CGO, error) {
if kem == nil { if kem == nil {
return nil, errors.New("failed to create ML-KEM-768 instance") return nil, errors.New("failed to create ML-KEM-768 instance")
} }
m := &MLKEM768CGO{kem: kem} m := &MLKEM768CGO{kem: kem}
runtime.SetFinalizer(m, (*MLKEM768CGO).cleanup) runtime.SetFinalizer(m, (*MLKEM768CGO).cleanup)
return m, nil return m, nil
@@ -102,7 +102,7 @@ func (m *MLKEM768CGO) GenerateKeyPair() (PublicKey, PrivateKey, error) {
if m.kem == nil { if m.kem == nil {
return nil, nil, errors.New("KEM instance not initialized") return nil, nil, errors.New("KEM instance not initialized")
} }
pk := &MLKEM768PublicKey{ pk := &MLKEM768PublicKey{
data: make([]byte, mlkem768PublicKeySize), data: make([]byte, mlkem768PublicKeySize),
} }
@@ -110,17 +110,17 @@ func (m *MLKEM768CGO) GenerateKeyPair() (PublicKey, PrivateKey, error) {
data: make([]byte, mlkem768PrivateKeySize), data: make([]byte, mlkem768PrivateKeySize),
pk: pk, pk: pk,
} }
ret := C.mlkem768_keypair( ret := C.mlkem768_keypair(
m.kem, m.kem,
(*C.uint8_t)(unsafe.Pointer(&pk.data[0])), (*C.uint8_t)(unsafe.Pointer(&pk.data[0])),
(*C.uint8_t)(unsafe.Pointer(&sk.data[0])), (*C.uint8_t)(unsafe.Pointer(&sk.data[0])),
) )
if ret != C.OQS_SUCCESS_VAL { if ret != C.OQS_SUCCESS_VAL {
return nil, nil, errors.New("ML-KEM-768 key generation failed") return nil, nil, errors.New("ML-KEM-768 key generation failed")
} }
return pk, sk, nil return pk, sk, nil
} }
@@ -129,26 +129,26 @@ func (m *MLKEM768CGO) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
if m.kem == nil { if m.kem == nil {
return nil, nil, errors.New("KEM instance not initialized") return nil, nil, errors.New("KEM instance not initialized")
} }
mlkemPK, ok := pk.(*MLKEM768PublicKey) mlkemPK, ok := pk.(*MLKEM768PublicKey)
if !ok { if !ok {
return nil, nil, errors.New("invalid public key type") return nil, nil, errors.New("invalid public key type")
} }
ciphertext := make([]byte, mlkem768CiphertextSize) ciphertext := make([]byte, mlkem768CiphertextSize)
sharedSecret := make([]byte, mlkem768SharedSecretSize) sharedSecret := make([]byte, mlkem768SharedSecretSize)
ret := C.mlkem768_encaps( ret := C.mlkem768_encaps(
m.kem, m.kem,
(*C.uint8_t)(unsafe.Pointer(&ciphertext[0])), (*C.uint8_t)(unsafe.Pointer(&ciphertext[0])),
(*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])), (*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])),
(*C.uint8_t)(unsafe.Pointer(&mlkemPK.data[0])), (*C.uint8_t)(unsafe.Pointer(&mlkemPK.data[0])),
) )
if ret != C.OQS_SUCCESS_VAL { if ret != C.OQS_SUCCESS_VAL {
return nil, nil, errors.New("ML-KEM-768 encapsulation failed") return nil, nil, errors.New("ML-KEM-768 encapsulation failed")
} }
return ciphertext, sharedSecret, nil return ciphertext, sharedSecret, nil
} }
@@ -157,29 +157,29 @@ func (m *MLKEM768CGO) Decapsulate(sk PrivateKey, ciphertext []byte) ([]byte, err
if m.kem == nil { if m.kem == nil {
return nil, errors.New("KEM instance not initialized") return nil, errors.New("KEM instance not initialized")
} }
mlkemSK, ok := sk.(*MLKEM768PrivateKey) mlkemSK, ok := sk.(*MLKEM768PrivateKey)
if !ok { if !ok {
return nil, errors.New("invalid private key type") return nil, errors.New("invalid private key type")
} }
if len(ciphertext) != mlkem768CiphertextSize { if len(ciphertext) != mlkem768CiphertextSize {
return nil, errors.New("invalid ciphertext size") return nil, errors.New("invalid ciphertext size")
} }
sharedSecret := make([]byte, mlkem768SharedSecretSize) sharedSecret := make([]byte, mlkem768SharedSecretSize)
ret := C.mlkem768_decaps( ret := C.mlkem768_decaps(
m.kem, m.kem,
(*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])), (*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])),
(*C.uint8_t)(unsafe.Pointer(&ciphertext[0])), (*C.uint8_t)(unsafe.Pointer(&ciphertext[0])),
(*C.uint8_t)(unsafe.Pointer(&mlkemSK.data[0])), (*C.uint8_t)(unsafe.Pointer(&mlkemSK.data[0])),
) )
if ret != C.OQS_SUCCESS_VAL { if ret != C.OQS_SUCCESS_VAL {
return nil, errors.New("ML-KEM-768 decapsulation failed") return nil, errors.New("ML-KEM-768 decapsulation failed")
} }
return sharedSecret, nil return sharedSecret, nil
} }
@@ -214,7 +214,7 @@ func NewMLKEM1024CGO() (*MLKEM1024CGO, error) {
if kem == nil { if kem == nil {
return nil, errors.New("failed to create ML-KEM-1024 instance") return nil, errors.New("failed to create ML-KEM-1024 instance")
} }
m := &MLKEM1024CGO{kem: kem} m := &MLKEM1024CGO{kem: kem}
runtime.SetFinalizer(m, (*MLKEM1024CGO).cleanup) runtime.SetFinalizer(m, (*MLKEM1024CGO).cleanup)
return m, nil return m, nil
@@ -233,7 +233,7 @@ func (m *MLKEM1024CGO) GenerateKeyPair() (PublicKey, PrivateKey, error) {
if m.kem == nil { if m.kem == nil {
return nil, nil, errors.New("KEM instance not initialized") return nil, nil, errors.New("KEM instance not initialized")
} }
pk := &MLKEM1024PublicKey{ pk := &MLKEM1024PublicKey{
data: make([]byte, mlkem1024PublicKeySize), data: make([]byte, mlkem1024PublicKeySize),
} }
@@ -241,17 +241,17 @@ func (m *MLKEM1024CGO) GenerateKeyPair() (PublicKey, PrivateKey, error) {
data: make([]byte, mlkem1024PrivateKeySize), data: make([]byte, mlkem1024PrivateKeySize),
pk: pk, pk: pk,
} }
ret := C.mlkem1024_keypair( ret := C.mlkem1024_keypair(
m.kem, m.kem,
(*C.uint8_t)(unsafe.Pointer(&pk.data[0])), (*C.uint8_t)(unsafe.Pointer(&pk.data[0])),
(*C.uint8_t)(unsafe.Pointer(&sk.data[0])), (*C.uint8_t)(unsafe.Pointer(&sk.data[0])),
) )
if ret != C.OQS_SUCCESS_VAL { if ret != C.OQS_SUCCESS_VAL {
return nil, nil, errors.New("ML-KEM-1024 key generation failed") return nil, nil, errors.New("ML-KEM-1024 key generation failed")
} }
return pk, sk, nil return pk, sk, nil
} }
@@ -260,26 +260,26 @@ func (m *MLKEM1024CGO) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
if m.kem == nil { if m.kem == nil {
return nil, nil, errors.New("KEM instance not initialized") return nil, nil, errors.New("KEM instance not initialized")
} }
mlkemPK, ok := pk.(*MLKEM1024PublicKey) mlkemPK, ok := pk.(*MLKEM1024PublicKey)
if !ok { if !ok {
return nil, nil, errors.New("invalid public key type") return nil, nil, errors.New("invalid public key type")
} }
ciphertext := make([]byte, mlkem1024CiphertextSize) ciphertext := make([]byte, mlkem1024CiphertextSize)
sharedSecret := make([]byte, mlkem1024SharedSecretSize) sharedSecret := make([]byte, mlkem1024SharedSecretSize)
ret := C.mlkem1024_encaps( ret := C.mlkem1024_encaps(
m.kem, m.kem,
(*C.uint8_t)(unsafe.Pointer(&ciphertext[0])), (*C.uint8_t)(unsafe.Pointer(&ciphertext[0])),
(*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])), (*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])),
(*C.uint8_t)(unsafe.Pointer(&mlkemPK.data[0])), (*C.uint8_t)(unsafe.Pointer(&mlkemPK.data[0])),
) )
if ret != C.OQS_SUCCESS_VAL { if ret != C.OQS_SUCCESS_VAL {
return nil, nil, errors.New("ML-KEM-1024 encapsulation failed") return nil, nil, errors.New("ML-KEM-1024 encapsulation failed")
} }
return ciphertext, sharedSecret, nil return ciphertext, sharedSecret, nil
} }
@@ -288,29 +288,29 @@ func (m *MLKEM1024CGO) Decapsulate(sk PrivateKey, ciphertext []byte) ([]byte, er
if m.kem == nil { if m.kem == nil {
return nil, errors.New("KEM instance not initialized") return nil, errors.New("KEM instance not initialized")
} }
mlkemSK, ok := sk.(*MLKEM1024PrivateKey) mlkemSK, ok := sk.(*MLKEM1024PrivateKey)
if !ok { if !ok {
return nil, errors.New("invalid private key type") return nil, errors.New("invalid private key type")
} }
if len(ciphertext) != mlkem1024CiphertextSize { if len(ciphertext) != mlkem1024CiphertextSize {
return nil, errors.New("invalid ciphertext size") return nil, errors.New("invalid ciphertext size")
} }
sharedSecret := make([]byte, mlkem1024SharedSecretSize) sharedSecret := make([]byte, mlkem1024SharedSecretSize)
ret := C.mlkem1024_decaps( ret := C.mlkem1024_decaps(
m.kem, m.kem,
(*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])), (*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])),
(*C.uint8_t)(unsafe.Pointer(&ciphertext[0])), (*C.uint8_t)(unsafe.Pointer(&ciphertext[0])),
(*C.uint8_t)(unsafe.Pointer(&mlkemSK.data[0])), (*C.uint8_t)(unsafe.Pointer(&mlkemSK.data[0])),
) )
if ret != C.OQS_SUCCESS_VAL { if ret != C.OQS_SUCCESS_VAL {
return nil, errors.New("ML-KEM-1024 decapsulation failed") return nil, errors.New("ML-KEM-1024 decapsulation failed")
} }
return sharedSecret, nil return sharedSecret, nil
} }
@@ -334,7 +334,7 @@ func (m *MLKEM1024CGO) SharedSecretSize() int {
return mlkem1024SharedSecretSize return mlkem1024SharedSecretSize
} }
// cgoAvailable returns true when CGO is available // cgoAvailable returns true when CGO is available
func cgoAvailable() bool { func cgoAvailable() bool {
return true return true
} }
+1 -1
View File
@@ -18,4 +18,4 @@ func NewMLKEM768CGO() (KEM, error) {
// NewMLKEM1024CGO returns an error when liboqs is not available // NewMLKEM1024CGO returns an error when liboqs is not available
func NewMLKEM1024CGO() (KEM, error) { func NewMLKEM1024CGO() (KEM, error) {
return nil, errors.New("liboqs not installed, using pure Go implementation") return nil, errors.New("liboqs not installed, using pure Go implementation")
} }
+1 -1
View File
@@ -18,4 +18,4 @@ func NewMLKEM768CGO() (KEM, error) {
// NewMLKEM1024CGO returns an error when CGO is disabled // NewMLKEM1024CGO returns an error when CGO is disabled
func NewMLKEM1024CGO() (KEM, error) { func NewMLKEM1024CGO() (KEM, error) {
return nil, errors.New("CGO disabled, using pure Go implementation") return nil, errors.New("CGO disabled, using pure Go implementation")
} }
+20 -20
View File
@@ -21,7 +21,7 @@ type X25519PublicKey struct {
data [32]byte data [32]byte
} }
// X25519PrivateKey represents an X25519 private key // X25519PrivateKey represents an X25519 private key
type X25519PrivateKey struct { type X25519PrivateKey struct {
data [32]byte data [32]byte
pk *X25519PublicKey pk *X25519PublicKey
@@ -30,22 +30,22 @@ type X25519PrivateKey struct {
// GenerateKeyPair generates a new X25519 key pair // GenerateKeyPair generates a new X25519 key pair
func (x *X25519Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) { func (x *X25519Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
sk := &X25519PrivateKey{} sk := &X25519PrivateKey{}
// Generate random private key // Generate random private key
if _, err := rand.Read(sk.data[:]); err != nil { if _, err := rand.Read(sk.data[:]); err != nil {
return nil, nil, err return nil, nil, err
} }
// Clamp private key as per X25519 spec // Clamp private key as per X25519 spec
sk.data[0] &= 248 sk.data[0] &= 248
sk.data[31] &= 127 sk.data[31] &= 127
sk.data[31] |= 64 sk.data[31] |= 64
// Compute public key // Compute public key
pk := &X25519PublicKey{} pk := &X25519PublicKey{}
curve25519.ScalarBaseMult(&pk.data, &sk.data) curve25519.ScalarBaseMult(&pk.data, &sk.data)
sk.pk = pk sk.pk = pk
return pk, sk, nil return pk, sk, nil
} }
@@ -55,31 +55,31 @@ func (x *X25519Impl) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
if !ok { if !ok {
return nil, nil, errors.New("invalid public key type for X25519") return nil, nil, errors.New("invalid public key type for X25519")
} }
// Generate ephemeral key pair // Generate ephemeral key pair
ephSK := &X25519PrivateKey{} ephSK := &X25519PrivateKey{}
if _, err := rand.Read(ephSK.data[:]); err != nil { if _, err := rand.Read(ephSK.data[:]); err != nil {
return nil, nil, err return nil, nil, err
} }
// Clamp ephemeral private key // Clamp ephemeral private key
ephSK.data[0] &= 248 ephSK.data[0] &= 248
ephSK.data[31] &= 127 ephSK.data[31] &= 127
ephSK.data[31] |= 64 ephSK.data[31] |= 64
// Compute ephemeral public key (ciphertext) // Compute ephemeral public key (ciphertext)
ephPK := &X25519PublicKey{} ephPK := &X25519PublicKey{}
curve25519.ScalarBaseMult(&ephPK.data, &ephSK.data) curve25519.ScalarBaseMult(&ephPK.data, &ephSK.data)
// Compute shared secret // Compute shared secret
var sharedSecret [32]byte var sharedSecret [32]byte
curve25519.ScalarMult(&sharedSecret, &ephSK.data, &x25519PK.data) curve25519.ScalarMult(&sharedSecret, &ephSK.data, &x25519PK.data)
// Check for low-order points // Check for low-order points
if isLowOrder(sharedSecret[:]) { if isLowOrder(sharedSecret[:]) {
return nil, nil, errors.New("low-order shared secret") return nil, nil, errors.New("low-order shared secret")
} }
return ephPK.data[:], sharedSecret[:], nil return ephPK.data[:], sharedSecret[:], nil
} }
@@ -89,23 +89,23 @@ func (x *X25519Impl) Decapsulate(sk PrivateKey, ciphertext []byte) ([]byte, erro
if !ok { if !ok {
return nil, errors.New("invalid private key type for X25519") return nil, errors.New("invalid private key type for X25519")
} }
if len(ciphertext) != 32 { if len(ciphertext) != 32 {
return nil, errors.New("invalid ciphertext size for X25519") return nil, errors.New("invalid ciphertext size for X25519")
} }
var ephPK [32]byte var ephPK [32]byte
copy(ephPK[:], ciphertext) copy(ephPK[:], ciphertext)
// Compute shared secret // Compute shared secret
var sharedSecret [32]byte var sharedSecret [32]byte
curve25519.ScalarMult(&sharedSecret, &x25519SK.data, &ephPK) curve25519.ScalarMult(&sharedSecret, &x25519SK.data, &ephPK)
// Check for low-order points // Check for low-order points
if isLowOrder(sharedSecret[:]) { if isLowOrder(sharedSecret[:]) {
return nil, errors.New("low-order shared secret") return nil, errors.New("low-order shared secret")
} }
return sharedSecret[:], nil return sharedSecret[:], nil
} }
@@ -117,9 +117,9 @@ func isLowOrder(p []byte) bool {
} }
// Size methods for X25519 // Size methods for X25519
func (x *X25519Impl) PublicKeySize() int { return 32 } func (x *X25519Impl) PublicKeySize() int { return 32 }
func (x *X25519Impl) PrivateKeySize() int { return 32 } func (x *X25519Impl) PrivateKeySize() int { return 32 }
func (x *X25519Impl) CiphertextSize() int { return 32 } func (x *X25519Impl) CiphertextSize() int { return 32 }
func (x *X25519Impl) SharedSecretSize() int { return 32 } func (x *X25519Impl) SharedSecretSize() int { return 32 }
// Bytes returns the public key bytes // Bytes returns the public key bytes
@@ -153,4 +153,4 @@ func (sk *X25519PrivateKey) Equal(other PrivateKey) bool {
return false return false
} }
return subtle.ConstantTimeCompare(sk.data[:], otherSK.data[:]) == 1 return subtle.ConstantTimeCompare(sk.data[:], otherSK.data[:]) == 1
} }
+17 -17
View File
@@ -8,11 +8,11 @@ import (
func TestMLDSAKeyGeneration(t *testing.T) { func TestMLDSAKeyGeneration(t *testing.T) {
modes := []struct { modes := []struct {
name string name string
mode Mode mode Mode
pubSize int pubSize int
privSize int privSize int
sigSize int sigSize int
}{ }{
{"ML-DSA-44", MLDSA44, MLDSA44PublicKeySize, MLDSA44PrivateKeySize, MLDSA44SignatureSize}, {"ML-DSA-44", MLDSA44, MLDSA44PublicKeySize, MLDSA44PrivateKeySize, MLDSA44SignatureSize},
{"ML-DSA-65", MLDSA65, MLDSA65PublicKeySize, MLDSA65PrivateKeySize, MLDSA65SignatureSize}, {"ML-DSA-65", MLDSA65, MLDSA65PublicKeySize, MLDSA65PrivateKeySize, MLDSA65SignatureSize},
@@ -49,7 +49,7 @@ func TestMLDSAKeyGeneration(t *testing.T) {
func TestMLDSASignVerify(t *testing.T) { func TestMLDSASignVerify(t *testing.T) {
modes := []Mode{MLDSA44, MLDSA65, MLDSA87} modes := []Mode{MLDSA44, MLDSA65, MLDSA87}
for _, mode := range modes { for _, mode := range modes {
t.Run(mode.String(), func(t *testing.T) { t.Run(mode.String(), func(t *testing.T) {
privKey, err := GenerateKey(rand.Reader, mode) privKey, err := GenerateKey(rand.Reader, mode)
@@ -58,7 +58,7 @@ func TestMLDSASignVerify(t *testing.T) {
} }
message := []byte("Test message for ML-DSA signature") message := []byte("Test message for ML-DSA signature")
// Sign message // Sign message
signature, err := privKey.Sign(rand.Reader, message, nil) signature, err := privKey.Sign(rand.Reader, message, nil)
if err != nil { if err != nil {
@@ -102,7 +102,7 @@ func TestMLDSASignVerify(t *testing.T) {
func TestMLDSAKeySerialization(t *testing.T) { func TestMLDSAKeySerialization(t *testing.T) {
modes := []Mode{MLDSA44, MLDSA65, MLDSA87} modes := []Mode{MLDSA44, MLDSA65, MLDSA87}
for _, mode := range modes { for _, mode := range modes {
t.Run(mode.String(), func(t *testing.T) { t.Run(mode.String(), func(t *testing.T) {
// Generate original key // Generate original key
@@ -241,7 +241,7 @@ func TestMLDSAEdgeCases(t *testing.T) {
func TestMLDSALargeMessage(t *testing.T) { func TestMLDSALargeMessage(t *testing.T) {
modes := []Mode{MLDSA44, MLDSA65, MLDSA87} modes := []Mode{MLDSA44, MLDSA65, MLDSA87}
for _, mode := range modes { for _, mode := range modes {
t.Run(mode.String(), func(t *testing.T) { t.Run(mode.String(), func(t *testing.T) {
privKey, err := GenerateKey(rand.Reader, mode) privKey, err := GenerateKey(rand.Reader, mode)
@@ -280,12 +280,12 @@ func TestMLDSAConcurrency(t *testing.T) {
} }
message := []byte("Concurrent test message") message := []byte("Concurrent test message")
// Test concurrent signing // Test concurrent signing
t.Run("ConcurrentSign", func(t *testing.T) { t.Run("ConcurrentSign", func(t *testing.T) {
const numGoroutines = 10 const numGoroutines = 10
done := make(chan bool, numGoroutines) done := make(chan bool, numGoroutines)
for i := 0; i < numGoroutines; i++ { for i := 0; i < numGoroutines; i++ {
go func(id int) { go func(id int) {
msg := append(message, byte(id)) msg := append(message, byte(id))
@@ -300,7 +300,7 @@ func TestMLDSAConcurrency(t *testing.T) {
done <- true done <- true
}(i) }(i)
} }
for i := 0; i < numGoroutines; i++ { for i := 0; i < numGoroutines; i++ {
<-done <-done
} }
@@ -311,7 +311,7 @@ func TestMLDSAConcurrency(t *testing.T) {
signature, _ := privKey.Sign(rand.Reader, message, nil) signature, _ := privKey.Sign(rand.Reader, message, nil)
const numGoroutines = 10 const numGoroutines = 10
done := make(chan bool, numGoroutines) done := make(chan bool, numGoroutines)
for i := 0; i < numGoroutines; i++ { for i := 0; i < numGoroutines; i++ {
go func(id int) { go func(id int) {
valid := privKey.PublicKey.Verify(message, signature, nil) valid := privKey.PublicKey.Verify(message, signature, nil)
@@ -321,7 +321,7 @@ func TestMLDSAConcurrency(t *testing.T) {
done <- true done <- true
}(i) }(i)
} }
for i := 0; i < numGoroutines; i++ { for i := 0; i < numGoroutines; i++ {
<-done <-done
} }
@@ -365,7 +365,7 @@ func BenchmarkMLDSASign(b *testing.B) {
for _, m := range modes { for _, m := range modes {
privKey, _ := GenerateKey(rand.Reader, m.mode) privKey, _ := GenerateKey(rand.Reader, m.mode)
b.Run(m.name, func(b *testing.B) { b.Run(m.name, func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -393,7 +393,7 @@ func BenchmarkMLDSAVerify(b *testing.B) {
for _, m := range modes { for _, m := range modes {
privKey, _ := GenerateKey(rand.Reader, m.mode) privKey, _ := GenerateKey(rand.Reader, m.mode)
signature, _ := privKey.Sign(rand.Reader, message, nil) signature, _ := privKey.Sign(rand.Reader, message, nil)
b.Run(m.name, func(b *testing.B) { b.Run(m.name, func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -406,4 +406,4 @@ func BenchmarkMLDSAVerify(b *testing.B) {
} }
} }
// Helper functions are now in mldsa.go // Helper functions are now in mldsa.go
+10 -10
View File
@@ -8,7 +8,7 @@ import (
func TestOptimizedKeyGeneration(t *testing.T) { func TestOptimizedKeyGeneration(t *testing.T) {
modes := []Mode{MLDSA44, MLDSA65, MLDSA87} modes := []Mode{MLDSA44, MLDSA65, MLDSA87}
for _, mode := range modes { for _, mode := range modes {
t.Run(mode.String(), func(t *testing.T) { t.Run(mode.String(), func(t *testing.T) {
// Test optimized key generation // Test optimized key generation
@@ -55,7 +55,7 @@ func TestOptimizedKeyGeneration(t *testing.T) {
func TestOptimizedSign(t *testing.T) { func TestOptimizedSign(t *testing.T) {
modes := []Mode{MLDSA44, MLDSA65, MLDSA87} modes := []Mode{MLDSA44, MLDSA65, MLDSA87}
for _, mode := range modes { for _, mode := range modes {
t.Run(mode.String(), func(t *testing.T) { t.Run(mode.String(), func(t *testing.T) {
privKey, err := GenerateKey(rand.Reader, mode) privKey, err := GenerateKey(rand.Reader, mode)
@@ -64,7 +64,7 @@ func TestOptimizedSign(t *testing.T) {
} }
message := []byte("Test message for optimized signing") message := []byte("Test message for optimized signing")
// Test optimized signing // Test optimized signing
signature, err := privKey.OptimizedSign(rand.Reader, message, nil) signature, err := privKey.OptimizedSign(rand.Reader, message, nil)
if err != nil { if err != nil {
@@ -89,7 +89,7 @@ func TestOptimizedSign(t *testing.T) {
func TestBatchDSA(t *testing.T) { func TestBatchDSA(t *testing.T) {
modes := []Mode{MLDSA44, MLDSA65, MLDSA87} modes := []Mode{MLDSA44, MLDSA65, MLDSA87}
for _, mode := range modes { for _, mode := range modes {
t.Run(mode.String(), func(t *testing.T) { t.Run(mode.String(), func(t *testing.T) {
numKeys := 5 numKeys := 5
@@ -101,7 +101,7 @@ func TestBatchDSA(t *testing.T) {
// Prepare messages // Prepare messages
messages := make([][]byte, numKeys) messages := make([][]byte, numKeys)
for i := range messages { for i := range messages {
messages[i] = []byte(string(rune('A' + i)) + " Test message for batch signing") messages[i] = []byte(string(rune('A'+i)) + " Test message for batch signing")
} }
// Batch sign // Batch sign
@@ -154,7 +154,7 @@ func TestBatchDSA(t *testing.T) {
func TestPrecomputedMLDSA(t *testing.T) { func TestPrecomputedMLDSA(t *testing.T) {
modes := []Mode{MLDSA44, MLDSA65, MLDSA87} modes := []Mode{MLDSA44, MLDSA65, MLDSA87}
for _, mode := range modes { for _, mode := range modes {
t.Run(mode.String(), func(t *testing.T) { t.Run(mode.String(), func(t *testing.T) {
privKey, err := GenerateKey(rand.Reader, mode) privKey, err := GenerateKey(rand.Reader, mode)
@@ -165,7 +165,7 @@ func TestPrecomputedMLDSA(t *testing.T) {
precomputed := NewPrecomputedMLDSA(privKey) precomputed := NewPrecomputedMLDSA(privKey)
message := []byte("Test message for caching") message := []byte("Test message for caching")
// First sign (cache miss) // First sign (cache miss)
sig1, err := precomputed.SignCached(message) sig1, err := precomputed.SignCached(message)
if err != nil { if err != nil {
@@ -339,7 +339,7 @@ func BenchmarkOptimizedSign(b *testing.B) {
for _, m := range modes { for _, m := range modes {
privKey, _ := GenerateKey(rand.Reader, m.mode) privKey, _ := GenerateKey(rand.Reader, m.mode)
b.Run(m.name+"-Standard", func(b *testing.B) { b.Run(m.name+"-Standard", func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -365,7 +365,7 @@ func BenchmarkOptimizedSign(b *testing.B) {
func BenchmarkBatchOperations(b *testing.B) { func BenchmarkBatchOperations(b *testing.B) {
numKeys := 10 numKeys := 10
batch, _ := NewBatchDSA(MLDSA65, numKeys) batch, _ := NewBatchDSA(MLDSA65, numKeys)
messages := make([][]byte, numKeys) messages := make([][]byte, numKeys)
for i := range messages { for i := range messages {
messages[i] = make([]byte, 32) messages[i] = make([]byte, 32)
@@ -393,4 +393,4 @@ func BenchmarkBatchOperations(b *testing.B) {
} }
} }
}) })
} }
+1 -1
View File
@@ -302,4 +302,4 @@ func PrivateKeyFromBytes(data []byte, mode Mode) (*PrivateKey, error) {
key: privKey, key: privKey,
mode: mode, mode: mode,
}, nil }, nil
} }
+2 -2
View File
@@ -100,7 +100,7 @@ func BenchmarkMLKEMMemory(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
priv, _, _ := GenerateKeyPair(rand.Reader, m.mode) priv, _, _ := GenerateKeyPair(rand.Reader, m.mode)
result, _ := priv.PublicKey.Encapsulate(rand.Reader) result, _ := priv.PublicKey.Encapsulate(rand.Reader)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
// Full KEM operation // Full KEM operation
@@ -109,4 +109,4 @@ func BenchmarkMLKEMMemory(b *testing.B) {
} }
}) })
} }
} }
+12 -14
View File
@@ -8,12 +8,12 @@ import (
func TestMLKEMKeyGeneration(t *testing.T) { func TestMLKEMKeyGeneration(t *testing.T) {
modes := []struct { modes := []struct {
name string name string
mode Mode mode Mode
pubSize int pubSize int
privSize int privSize int
ctSize int ctSize int
ssSize int ssSize int
}{ }{
{"ML-KEM-512", MLKEM512, MLKEM512PublicKeySize, MLKEM512PrivateKeySize, MLKEM512CiphertextSize, MLKEM512SharedSecretSize}, {"ML-KEM-512", MLKEM512, MLKEM512PublicKeySize, MLKEM512PrivateKeySize, MLKEM512CiphertextSize, MLKEM512SharedSecretSize},
{"ML-KEM-768", MLKEM768, MLKEM768PublicKeySize, MLKEM768PrivateKeySize, MLKEM768CiphertextSize, MLKEM768SharedSecretSize}, {"ML-KEM-768", MLKEM768, MLKEM768PublicKeySize, MLKEM768PrivateKeySize, MLKEM768CiphertextSize, MLKEM768SharedSecretSize},
@@ -114,7 +114,7 @@ func TestMLKEMEncapsulateDecapsulate(t *testing.T) {
tamperedCiphertext := make([]byte, len(encapResult.Ciphertext)) tamperedCiphertext := make([]byte, len(encapResult.Ciphertext))
copy(tamperedCiphertext, encapResult.Ciphertext) copy(tamperedCiphertext, encapResult.Ciphertext)
tamperedCiphertext[0] ^= 0xFF tamperedCiphertext[0] ^= 0xFF
// In our placeholder implementation, this will produce different shared secret // In our placeholder implementation, this will produce different shared secret
tamperedSecret, err := privKey.Decapsulate(tamperedCiphertext) tamperedSecret, err := privKey.Decapsulate(tamperedCiphertext)
if err != nil { if err != nil {
@@ -301,12 +301,12 @@ func TestMLKEMConcurrency(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Goroutine %d: Encapsulate failed: %v", id, err) t.Errorf("Goroutine %d: Encapsulate failed: %v", id, err)
} }
ss, err := privKey.Decapsulate(encapResult.Ciphertext) ss, err := privKey.Decapsulate(encapResult.Ciphertext)
if err != nil { if err != nil {
t.Errorf("Goroutine %d: Decapsulate failed: %v", id, err) t.Errorf("Goroutine %d: Decapsulate failed: %v", id, err)
} }
if !bytes.Equal(ss, encapResult.SharedSecret) { if !bytes.Equal(ss, encapResult.SharedSecret) {
t.Errorf("Goroutine %d: Shared secrets don't match", id) t.Errorf("Goroutine %d: Shared secrets don't match", id)
} }
@@ -344,8 +344,6 @@ func TestMLKEMConcurrency(t *testing.T) {
}) })
} }
// Helper functions that were missing // Helper functions that were missing
func NewPrivateKey(mode Mode) *PrivateKey { func NewPrivateKey(mode Mode) *PrivateKey {
return &PrivateKey{ return &PrivateKey{
@@ -423,7 +421,7 @@ func BenchmarkMLKEMEncapsulate(b *testing.B) {
for _, m := range modes { for _, m := range modes {
privKey, _, _ := GenerateKeyPair(rand.Reader, m.mode) privKey, _, _ := GenerateKeyPair(rand.Reader, m.mode)
b.Run(m.name, func(b *testing.B) { b.Run(m.name, func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -449,7 +447,7 @@ func BenchmarkMLKEMDecapsulate(b *testing.B) {
for _, m := range modes { for _, m := range modes {
privKey, _, _ := GenerateKeyPair(rand.Reader, m.mode) privKey, _, _ := GenerateKeyPair(rand.Reader, m.mode)
encapResult, _ := privKey.PublicKey.Encapsulate(rand.Reader) encapResult, _ := privKey.PublicKey.Encapsulate(rand.Reader)
b.Run(m.name, func(b *testing.B) { b.Run(m.name, func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -463,4 +461,4 @@ func BenchmarkMLKEMDecapsulate(b *testing.B) {
} }
}) })
} }
} }
+56 -56
View File
@@ -16,7 +16,7 @@ import (
const ( const (
// DefaultThreshold is the default threshold for MPC // DefaultThreshold is the default threshold for MPC
DefaultThreshold = 3 DefaultThreshold = 3
// DefaultParties is the default number of parties // DefaultParties is the default number of parties
DefaultParties = 5 DefaultParties = 5
) )
@@ -30,20 +30,20 @@ var (
// MPCAccount represents a per-account MPC configuration // MPCAccount represents a per-account MPC configuration
type MPCAccount struct { type MPCAccount struct {
AccountID ids.ShortID AccountID ids.ShortID
Threshold int Threshold int
Parties int Parties int
PublicKey *PublicKey PublicKey *PublicKey
Shares map[int]*Share Shares map[int]*Share
Protocol Protocol Protocol Protocol
mu sync.RWMutex mu sync.RWMutex
} }
// Share represents a secret share held by a party // Share represents a secret share held by a party
type Share struct { type Share struct {
Index int Index int
Value *big.Int Value *big.Int
Proof []byte Proof []byte
} }
// PublicKey represents an MPC public key // PublicKey represents an MPC public key
@@ -86,15 +86,15 @@ func (m *Manager) CreateAccount(accountID ids.ShortID, threshold, parties int, p
if parties < 2 { if parties < 2 {
return nil, errInvalidParties return nil, errInvalidParties
} }
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
// Check if account already exists // Check if account already exists
if _, exists := m.accounts[accountID]; exists { if _, exists := m.accounts[accountID]; exists {
return nil, errors.New("account already exists") return nil, errors.New("account already exists")
} }
// Generate distributed key // Generate distributed key
account := &MPCAccount{ account := &MPCAccount{
AccountID: accountID, AccountID: accountID,
@@ -103,12 +103,12 @@ func (m *Manager) CreateAccount(accountID ids.ShortID, threshold, parties int, p
Shares: make(map[int]*Share), Shares: make(map[int]*Share),
Protocol: protocol, Protocol: protocol,
} }
// Generate key shares // Generate key shares
if err := account.generateKeyShares(); err != nil { if err := account.generateKeyShares(); err != nil {
return nil, err return nil, err
} }
m.accounts[accountID] = account m.accounts[accountID] = account
return account, nil return account, nil
} }
@@ -117,12 +117,12 @@ func (m *Manager) CreateAccount(accountID ids.ShortID, threshold, parties int, p
func (m *Manager) GetAccount(accountID ids.ShortID) (*MPCAccount, error) { func (m *Manager) GetAccount(accountID ids.ShortID) (*MPCAccount, error) {
m.mu.RLock() m.mu.RLock()
defer m.mu.RUnlock() defer m.mu.RUnlock()
account, exists := m.accounts[accountID] account, exists := m.accounts[accountID]
if !exists { if !exists {
return nil, errors.New("account not found") return nil, errors.New("account not found")
} }
return account, nil return account, nil
} }
@@ -137,10 +137,10 @@ func (a *MPCAccount) generateKeyShares() error {
} }
coeffs[i] = coeff coeffs[i] = coeff
} }
// The secret is the constant term // The secret is the constant term
secret := coeffs[0] secret := coeffs[0]
// Generate shares for each party // Generate shares for each party
for i := 1; i <= a.Parties; i++ { for i := 1; i <= a.Parties; i++ {
share := evaluatePolynomial(coeffs, big.NewInt(int64(i))) share := evaluatePolynomial(coeffs, big.NewInt(int64(i)))
@@ -150,12 +150,12 @@ func (a *MPCAccount) generateKeyShares() error {
Proof: generateShareProof(share, i), Proof: generateShareProof(share, i),
} }
} }
// Compute public key // Compute public key
a.PublicKey = &PublicKey{ a.PublicKey = &PublicKey{
Point: scalarBaseMult(secret), Point: scalarBaseMult(secret),
} }
return nil return nil
} }
@@ -163,22 +163,22 @@ func (a *MPCAccount) generateKeyShares() error {
func (a *MPCAccount) Sign(message []byte, participatingShares map[int]*Share) ([]byte, error) { func (a *MPCAccount) Sign(message []byte, participatingShares map[int]*Share) ([]byte, error) {
a.mu.RLock() a.mu.RLock()
defer a.mu.RUnlock() defer a.mu.RUnlock()
if len(participatingShares) < a.Threshold { if len(participatingShares) < a.Threshold {
return nil, errNotEnoughShares return nil, errNotEnoughShares
} }
// Verify shares // Verify shares
for index, share := range participatingShares { for index, share := range participatingShares {
if !a.verifyShare(index, share) { if !a.verifyShare(index, share) {
return nil, errInvalidShare return nil, errInvalidShare
} }
} }
// Compute partial signatures // Compute partial signatures
messageHash := sha256.Sum256(message) messageHash := sha256.Sum256(message)
partialSigs := make(map[int]*big.Int) partialSigs := make(map[int]*big.Int)
for index, share := range participatingShares { for index, share := range participatingShares {
// Simplified partial signature computation // Simplified partial signature computation
// In production, use actual protocol (GG18/GG20/CMP) // In production, use actual protocol (GG18/GG20/CMP)
@@ -186,10 +186,10 @@ func (a *MPCAccount) Sign(message []byte, participatingShares map[int]*Share) ([
partialSig.Mod(partialSig, curveOrder()) partialSig.Mod(partialSig, curveOrder())
partialSigs[index] = partialSig partialSigs[index] = partialSig
} }
// Combine partial signatures using Lagrange interpolation // Combine partial signatures using Lagrange interpolation
signature := combinePartialSignatures(partialSigs, a.Threshold) signature := combinePartialSignatures(partialSigs, a.Threshold)
return signature.Bytes(), nil return signature.Bytes(), nil
} }
@@ -197,16 +197,16 @@ func (a *MPCAccount) Sign(message []byte, participatingShares map[int]*Share) ([
func (a *MPCAccount) Verify(message []byte, signature []byte) bool { func (a *MPCAccount) Verify(message []byte, signature []byte) bool {
a.mu.RLock() a.mu.RLock()
defer a.mu.RUnlock() defer a.mu.RUnlock()
// Simplified verification // Simplified verification
// In production, implement actual signature verification // In production, implement actual signature verification
messageHash := sha256.Sum256(message) messageHash := sha256.Sum256(message)
sig := new(big.Int).SetBytes(signature) sig := new(big.Int).SetBytes(signature)
// Verify using public key // Verify using public key
expectedPoint := scalarBaseMult(sig) expectedPoint := scalarBaseMult(sig)
messagePoint := scalarBaseMult(new(big.Int).SetBytes(messageHash[:])) messagePoint := scalarBaseMult(new(big.Int).SetBytes(messageHash[:]))
// Check if signature is valid (simplified) // Check if signature is valid (simplified)
return pointsEqual(expectedPoint, messagePoint) return pointsEqual(expectedPoint, messagePoint)
} }
@@ -215,15 +215,15 @@ func (a *MPCAccount) Verify(message []byte, signature []byte) bool {
func (a *MPCAccount) AddShare(index int, share *Share) error { func (a *MPCAccount) AddShare(index int, share *Share) error {
a.mu.Lock() a.mu.Lock()
defer a.mu.Unlock() defer a.mu.Unlock()
if index < 1 || index > a.Parties { if index < 1 || index > a.Parties {
return errors.New("invalid share index") return errors.New("invalid share index")
} }
if !a.verifyShare(index, share) { if !a.verifyShare(index, share) {
return errInvalidShare return errInvalidShare
} }
a.Shares[index] = share a.Shares[index] = share
return nil return nil
} }
@@ -232,12 +232,12 @@ func (a *MPCAccount) AddShare(index int, share *Share) error {
func (a *MPCAccount) GetShare(index int) (*Share, error) { func (a *MPCAccount) GetShare(index int) (*Share, error) {
a.mu.RLock() a.mu.RLock()
defer a.mu.RUnlock() defer a.mu.RUnlock()
share, exists := a.Shares[index] share, exists := a.Shares[index]
if !exists { if !exists {
return nil, errors.New("share not found") return nil, errors.New("share not found")
} }
return share, nil return share, nil
} }
@@ -245,18 +245,18 @@ func (a *MPCAccount) GetShare(index int) (*Share, error) {
func (a *MPCAccount) RefreshShares() error { func (a *MPCAccount) RefreshShares() error {
a.mu.Lock() a.mu.Lock()
defer a.mu.Unlock() defer a.mu.Unlock()
// Generate new random polynomial with same secret // Generate new random polynomial with same secret
oldShares := a.Shares oldShares := a.Shares
a.Shares = make(map[int]*Share) a.Shares = make(map[int]*Share)
// Keep the same secret (constant term) // Keep the same secret (constant term)
secret := reconstructSecret(oldShares, a.Threshold) secret := reconstructSecret(oldShares, a.Threshold)
// Generate new polynomial with same secret // Generate new polynomial with same secret
coeffs := make([]*big.Int, a.Threshold) coeffs := make([]*big.Int, a.Threshold)
coeffs[0] = secret coeffs[0] = secret
for i := 1; i < a.Threshold; i++ { for i := 1; i < a.Threshold; i++ {
coeff, err := rand.Int(rand.Reader, curveOrder()) coeff, err := rand.Int(rand.Reader, curveOrder())
if err != nil { if err != nil {
@@ -264,7 +264,7 @@ func (a *MPCAccount) RefreshShares() error {
} }
coeffs[i] = coeff coeffs[i] = coeff
} }
// Generate new shares // Generate new shares
for i := 1; i <= a.Parties; i++ { for i := 1; i <= a.Parties; i++ {
share := evaluatePolynomial(coeffs, big.NewInt(int64(i))) share := evaluatePolynomial(coeffs, big.NewInt(int64(i)))
@@ -274,7 +274,7 @@ func (a *MPCAccount) RefreshShares() error {
Proof: generateShareProof(share, i), Proof: generateShareProof(share, i),
} }
} }
return nil return nil
} }
@@ -300,16 +300,16 @@ func pointsEqual(p1, p2 *Point) bool {
func evaluatePolynomial(coeffs []*big.Int, x *big.Int) *big.Int { func evaluatePolynomial(coeffs []*big.Int, x *big.Int) *big.Int {
result := new(big.Int).Set(coeffs[0]) result := new(big.Int).Set(coeffs[0])
xPower := new(big.Int).Set(x) xPower := new(big.Int).Set(x)
for i := 1; i < len(coeffs); i++ { for i := 1; i < len(coeffs); i++ {
term := new(big.Int).Mul(coeffs[i], xPower) term := new(big.Int).Mul(coeffs[i], xPower)
result.Add(result, term) result.Add(result, term)
result.Mod(result, curveOrder()) result.Mod(result, curveOrder())
xPower.Mul(xPower, x) xPower.Mul(xPower, x)
xPower.Mod(xPower, curveOrder()) xPower.Mod(xPower, curveOrder())
} }
return result return result
} }
@@ -327,33 +327,33 @@ func (a *MPCAccount) verifyShare(index int, share *Share) bool {
if len(share.Proof) != len(expectedProof) { if len(share.Proof) != len(expectedProof) {
return false return false
} }
for i := range expectedProof { for i := range expectedProof {
if expectedProof[i] != share.Proof[i] { if expectedProof[i] != share.Proof[i] {
return false return false
} }
} }
return true return true
} }
func combinePartialSignatures(partialSigs map[int]*big.Int, threshold int) *big.Int { func combinePartialSignatures(partialSigs map[int]*big.Int, threshold int) *big.Int {
result := big.NewInt(0) result := big.NewInt(0)
indices := make([]int, 0, len(partialSigs)) indices := make([]int, 0, len(partialSigs))
for index := range partialSigs { for index := range partialSigs {
indices = append(indices, index) indices = append(indices, index)
if len(indices) == threshold { if len(indices) == threshold {
break break
} }
} }
for _, i := range indices { for _, i := range indices {
lagrangeCoeff := computeLagrangeCoefficient(i, indices) lagrangeCoeff := computeLagrangeCoefficient(i, indices)
term := new(big.Int).Mul(partialSigs[i], lagrangeCoeff) term := new(big.Int).Mul(partialSigs[i], lagrangeCoeff)
result.Add(result, term) result.Add(result, term)
} }
result.Mod(result, curveOrder()) result.Mod(result, curveOrder())
return result return result
} }
@@ -361,19 +361,19 @@ func combinePartialSignatures(partialSigs map[int]*big.Int, threshold int) *big.
func computeLagrangeCoefficient(i int, indices []int) *big.Int { func computeLagrangeCoefficient(i int, indices []int) *big.Int {
num := big.NewInt(1) num := big.NewInt(1)
den := big.NewInt(1) den := big.NewInt(1)
for _, j := range indices { for _, j := range indices {
if i != j { if i != j {
num.Mul(num, big.NewInt(int64(-j))) num.Mul(num, big.NewInt(int64(-j)))
den.Mul(den, big.NewInt(int64(i-j))) den.Mul(den, big.NewInt(int64(i-j)))
} }
} }
// Compute num/den mod curveOrder // Compute num/den mod curveOrder
denInv := new(big.Int).ModInverse(den, curveOrder()) denInv := new(big.Int).ModInverse(den, curveOrder())
result := new(big.Int).Mul(num, denInv) result := new(big.Int).Mul(num, denInv)
result.Mod(result, curveOrder()) result.Mod(result, curveOrder())
return result return result
} }
@@ -381,7 +381,7 @@ func reconstructSecret(shares map[int]*Share, threshold int) *big.Int {
if len(shares) < threshold { if len(shares) < threshold {
return nil return nil
} }
partialValues := make(map[int]*big.Int) partialValues := make(map[int]*big.Int)
for index, share := range shares { for index, share := range shares {
partialValues[index] = share.Value partialValues[index] = share.Value
@@ -389,6 +389,6 @@ func reconstructSecret(shares map[int]*Share, threshold int) *big.Int {
break break
} }
} }
return combinePartialSignatures(partialValues, threshold) return combinePartialSignatures(partialValues, threshold)
} }
+1 -1
View File
@@ -186,4 +186,4 @@ func BenchmarkPQCrypto(b *testing.B) {
_, _ = priv.Sign(rand.Reader, message, nil) _, _ = priv.Sign(rand.Reader, message, nil)
} }
}) })
} }
-1
View File
@@ -305,7 +305,6 @@ func (b *BLSHashToPoint) Run(input []byte) ([]byte, error) {
return g2Point, nil return g2Point, nil
} }
// RegisterBLS registers all BLS precompiles // RegisterBLS registers all BLS precompiles
func RegisterBLS(registry *Registry) { func RegisterBLS(registry *Registry) {
registry.Register(BLSVerifyAddress, &BLSVerify{}) registry.Register(BLSVerifyAddress, &BLSVerify{})
+1 -1
View File
@@ -192,7 +192,7 @@ func (l *LamportBatchVerify) Run(input []byte) ([]byte, error) {
continue continue
} }
// message is actually a pre-hashed value // message is actually a pre-hashed value
if pubKey.VerifyHash(message, sig) { if pubKey.VerifyHash(message, sig) {
results[i] = 0x01 results[i] = 0x01
} else { } else {
+147 -147
View File
@@ -18,8 +18,8 @@ import (
// Test vectors for SHAKE from NIST // Test vectors for SHAKE from NIST
var shakeTestVectors = []struct { var shakeTestVectors = []struct {
name string name string
input string input string
output128 string // First 32 bytes of SHAKE128 output128 string // First 32 bytes of SHAKE128
output256 string // First 32 bytes of SHAKE256 output256 string // First 32 bytes of SHAKE256
}{ }{
@@ -47,22 +47,22 @@ var shakeTestVectors = []struct {
func TestSHAKEPrecompiles(t *testing.T) { func TestSHAKEPrecompiles(t *testing.T) {
t.Run("SHAKE128", func(t *testing.T) { t.Run("SHAKE128", func(t *testing.T) {
shake128 := &SHAKE128{} shake128 := &SHAKE128{}
for _, tv := range shakeTestVectors { for _, tv := range shakeTestVectors {
t.Run(tv.name, func(t *testing.T) { t.Run(tv.name, func(t *testing.T) {
inputData, _ := hex.DecodeString(tv.input) inputData, _ := hex.DecodeString(tv.input)
expectedOutput, _ := hex.DecodeString(tv.output128) expectedOutput, _ := hex.DecodeString(tv.output128)
// Create input with 32-byte output length // Create input with 32-byte output length
input := make([]byte, 4+len(inputData)) input := make([]byte, 4+len(inputData))
binary.BigEndian.PutUint32(input[:4], 32) binary.BigEndian.PutUint32(input[:4], 32)
copy(input[4:], inputData) copy(input[4:], inputData)
// Test gas calculation // Test gas calculation
gas := shake128.RequiredGas(input) gas := shake128.RequiredGas(input)
expectedGas := uint64(60 + 12*((len(input)+31)/32) + 3) expectedGas := uint64(60 + 12*((len(input)+31)/32) + 3)
assert.Equal(t, expectedGas, gas, "Gas calculation mismatch") assert.Equal(t, expectedGas, gas, "Gas calculation mismatch")
// Test output // Test output
output, err := shake128.Run(input) output, err := shake128.Run(input)
require.NoError(t, err) require.NoError(t, err)
@@ -73,22 +73,22 @@ func TestSHAKEPrecompiles(t *testing.T) {
t.Run("SHAKE256", func(t *testing.T) { t.Run("SHAKE256", func(t *testing.T) {
shake256 := &SHAKE256{} shake256 := &SHAKE256{}
for _, tv := range shakeTestVectors { for _, tv := range shakeTestVectors {
t.Run(tv.name, func(t *testing.T) { t.Run(tv.name, func(t *testing.T) {
inputData, _ := hex.DecodeString(tv.input) inputData, _ := hex.DecodeString(tv.input)
expectedOutput, _ := hex.DecodeString(tv.output256) expectedOutput, _ := hex.DecodeString(tv.output256)
// Create input with 32-byte output length // Create input with 32-byte output length
input := make([]byte, 4+len(inputData)) input := make([]byte, 4+len(inputData))
binary.BigEndian.PutUint32(input[:4], 32) binary.BigEndian.PutUint32(input[:4], 32)
copy(input[4:], inputData) copy(input[4:], inputData)
// Test gas calculation // Test gas calculation
gas := shake256.RequiredGas(input) gas := shake256.RequiredGas(input)
expectedGas := uint64(60 + 12*((len(input)+31)/32) + 3) expectedGas := uint64(60 + 12*((len(input)+31)/32) + 3)
assert.Equal(t, expectedGas, gas, "Gas calculation mismatch") assert.Equal(t, expectedGas, gas, "Gas calculation mismatch")
// Test output // Test output
output, err := shake256.Run(input) output, err := shake256.Run(input)
require.NoError(t, err) require.NoError(t, err)
@@ -100,35 +100,35 @@ func TestSHAKEPrecompiles(t *testing.T) {
t.Run("SHAKE256_Fixed", func(t *testing.T) { t.Run("SHAKE256_Fixed", func(t *testing.T) {
// Test fixed output variants // Test fixed output variants
variants := []struct { variants := []struct {
name string name string
precompile PrecompiledContract precompile PrecompiledContract
outputLen int outputLen int
gas uint64 gas uint64
}{ }{
{"SHAKE256_256", &SHAKE256_256{}, 32, 200}, {"SHAKE256_256", &SHAKE256_256{}, 32, 200},
{"SHAKE256_512", &SHAKE256_512{}, 64, 250}, {"SHAKE256_512", &SHAKE256_512{}, 64, 250},
{"SHAKE256_1024", &SHAKE256_1024{}, 128, 350}, {"SHAKE256_1024", &SHAKE256_1024{}, 128, 350},
} }
for _, v := range variants { for _, v := range variants {
t.Run(v.name, func(t *testing.T) { t.Run(v.name, func(t *testing.T) {
input := []byte("test input for fixed shake") input := []byte("test input for fixed shake")
// Test gas // Test gas
gas := v.precompile.RequiredGas(input) gas := v.precompile.RequiredGas(input)
assert.Equal(t, v.gas, gas) assert.Equal(t, v.gas, gas)
// Test output length // Test output length
output, err := v.precompile.Run(input) output, err := v.precompile.Run(input)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, output, v.outputLen) assert.Len(t, output, v.outputLen)
// Verify it matches variable SHAKE with same output length // Verify it matches variable SHAKE with same output length
shake := &SHAKE256{} shake := &SHAKE256{}
varInput := make([]byte, 4+len(input)) varInput := make([]byte, 4+len(input))
binary.BigEndian.PutUint32(varInput[:4], uint32(v.outputLen)) binary.BigEndian.PutUint32(varInput[:4], uint32(v.outputLen))
copy(varInput[4:], input) copy(varInput[4:], input)
varOutput, err := shake.Run(varInput) varOutput, err := shake.Run(varInput)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, varOutput, output, "Fixed and variable SHAKE should match") assert.Equal(t, varOutput, output, "Fixed and variable SHAKE should match")
@@ -139,40 +139,40 @@ func TestSHAKEPrecompiles(t *testing.T) {
t.Run("cSHAKE", func(t *testing.T) { t.Run("cSHAKE", func(t *testing.T) {
cshake128 := &CSHAKE128{} cshake128 := &CSHAKE128{}
cshake256 := &CSHAKE256{} cshake256 := &CSHAKE256{}
testCases := []struct { testCases := []struct {
name string name string
customization string customization string
data string data string
outputLen uint32 outputLen uint32
}{ }{
{"empty", "", "test", 32}, {"empty", "", "test", 32},
{"custom", "custom string", "test data", 64}, {"custom", "custom string", "test data", 64},
{"long_custom", "very long customization string for testing", "data", 32}, {"long_custom", "very long customization string for testing", "data", 32},
} }
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
// Build input // Build input
customBytes := []byte(tc.customization) customBytes := []byte(tc.customization)
dataBytes := []byte(tc.data) dataBytes := []byte(tc.data)
input := make([]byte, 8+len(customBytes)+len(dataBytes)) input := make([]byte, 8+len(customBytes)+len(dataBytes))
binary.BigEndian.PutUint32(input[:4], tc.outputLen) binary.BigEndian.PutUint32(input[:4], tc.outputLen)
binary.BigEndian.PutUint32(input[4:8], uint32(len(customBytes))) binary.BigEndian.PutUint32(input[4:8], uint32(len(customBytes)))
copy(input[8:], customBytes) copy(input[8:], customBytes)
copy(input[8+len(customBytes):], dataBytes) copy(input[8+len(customBytes):], dataBytes)
// Test CSHAKE128 // Test CSHAKE128
output128, err := cshake128.Run(input) output128, err := cshake128.Run(input)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, output128, int(tc.outputLen)) assert.Len(t, output128, int(tc.outputLen))
// Test CSHAKE256 // Test CSHAKE256
output256, err := cshake256.Run(input) output256, err := cshake256.Run(input)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, output256, int(tc.outputLen)) assert.Len(t, output256, int(tc.outputLen))
// Outputs should be different between 128 and 256 // Outputs should be different between 128 and 256
if tc.customization != "" { if tc.customization != "" {
assert.NotEqual(t, output128, output256) assert.NotEqual(t, output128, output256)
@@ -183,44 +183,44 @@ func TestSHAKEPrecompiles(t *testing.T) {
t.Run("EdgeCases", func(t *testing.T) { t.Run("EdgeCases", func(t *testing.T) {
shake := &SHAKE256{} shake := &SHAKE256{}
t.Run("MaxOutput", func(t *testing.T) { t.Run("MaxOutput", func(t *testing.T) {
// Test maximum output size (8192 bytes) // Test maximum output size (8192 bytes)
input := make([]byte, 4+10) input := make([]byte, 4+10)
binary.BigEndian.PutUint32(input[:4], 8192) binary.BigEndian.PutUint32(input[:4], 8192)
copy(input[4:], []byte("test data")) copy(input[4:], []byte("test data"))
output, err := shake.Run(input) output, err := shake.Run(input)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, output, 8192) assert.Len(t, output, 8192)
}) })
t.Run("TooLargeOutput", func(t *testing.T) { t.Run("TooLargeOutput", func(t *testing.T) {
// Test output size exceeding maximum // Test output size exceeding maximum
input := make([]byte, 4+10) input := make([]byte, 4+10)
binary.BigEndian.PutUint32(input[:4], 8193) binary.BigEndian.PutUint32(input[:4], 8193)
copy(input[4:], []byte("test data")) copy(input[4:], []byte("test data"))
_, err := shake.Run(input) _, err := shake.Run(input)
assert.Error(t, err) assert.Error(t, err)
assert.Contains(t, err.Error(), "exceeds maximum") assert.Contains(t, err.Error(), "exceeds maximum")
}) })
t.Run("ZeroOutput", func(t *testing.T) { t.Run("ZeroOutput", func(t *testing.T) {
// Test zero output length // Test zero output length
input := make([]byte, 4+10) input := make([]byte, 4+10)
binary.BigEndian.PutUint32(input[:4], 0) binary.BigEndian.PutUint32(input[:4], 0)
copy(input[4:], []byte("test data")) copy(input[4:], []byte("test data"))
output, err := shake.Run(input) output, err := shake.Run(input)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, output, 0) assert.Len(t, output, 0)
}) })
t.Run("InsufficientInput", func(t *testing.T) { t.Run("InsufficientInput", func(t *testing.T) {
// Test input shorter than 4 bytes // Test input shorter than 4 bytes
input := []byte{0, 0} input := []byte{0, 0}
_, err := shake.Run(input) _, err := shake.Run(input)
assert.Error(t, err) assert.Error(t, err)
}) })
@@ -231,44 +231,44 @@ func TestSHAKEPrecompiles(t *testing.T) {
func TestLamportPrecompiles(t *testing.T) { func TestLamportPrecompiles(t *testing.T) {
t.Run("LamportVerifySHA256", func(t *testing.T) { t.Run("LamportVerifySHA256", func(t *testing.T) {
verifier := &LamportVerifySHA256{} verifier := &LamportVerifySHA256{}
// Generate test key and signature // Generate test key and signature
priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256) priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256)
require.NoError(t, err) require.NoError(t, err)
// Get public key BEFORE signing (one-time signature clears private key) // Get public key BEFORE signing (one-time signature clears private key)
pubBytes := priv.Public().Bytes() pubBytes := priv.Public().Bytes()
message := []byte("test message for lamport") message := []byte("test message for lamport")
messageHash := sha256.Sum256(message) messageHash := sha256.Sum256(message)
// Sign the hash directly (precompile expects pre-hashed input) // Sign the hash directly (precompile expects pre-hashed input)
sig, err := priv.SignHash(messageHash[:]) sig, err := priv.SignHash(messageHash[:])
require.NoError(t, err) require.NoError(t, err)
// Build precompile input // Build precompile input
sigBytes := sig.Bytes() sigBytes := sig.Bytes()
input := make([]byte, 32+len(sigBytes)+len(pubBytes)) input := make([]byte, 32+len(sigBytes)+len(pubBytes))
copy(input[:32], messageHash[:]) copy(input[:32], messageHash[:])
copy(input[32:], sigBytes) copy(input[32:], sigBytes)
copy(input[32+len(sigBytes):], pubBytes) copy(input[32+len(sigBytes):], pubBytes)
// Test gas // Test gas
gas := verifier.RequiredGas(input) gas := verifier.RequiredGas(input)
assert.Equal(t, uint64(50000), gas) assert.Equal(t, uint64(50000), gas)
// Test verification (should succeed) // Test verification (should succeed)
output, err := verifier.Run(input) output, err := verifier.Run(input)
require.NoError(t, err) require.NoError(t, err)
expected := make([]byte, 32) expected := make([]byte, 32)
expected[31] = 1 expected[31] = 1
assert.Equal(t, expected, output, "Valid signature should return 1") assert.Equal(t, expected, output, "Valid signature should return 1")
// Test with wrong message // Test with wrong message
wrongHash := sha256.Sum256([]byte("wrong message")) wrongHash := sha256.Sum256([]byte("wrong message"))
copy(input[:32], wrongHash[:]) copy(input[:32], wrongHash[:])
output, err = verifier.Run(input) output, err = verifier.Run(input)
require.NoError(t, err) require.NoError(t, err)
expected = make([]byte, 32) expected = make([]byte, 32)
@@ -277,33 +277,33 @@ func TestLamportPrecompiles(t *testing.T) {
t.Run("LamportVerifySHA512", func(t *testing.T) { t.Run("LamportVerifySHA512", func(t *testing.T) {
verifier := &LamportVerifySHA512{} verifier := &LamportVerifySHA512{}
// Generate test key and signature // Generate test key and signature
priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA512) priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA512)
require.NoError(t, err) require.NoError(t, err)
// Get public key BEFORE signing (one-time signature clears private key) // Get public key BEFORE signing (one-time signature clears private key)
pubBytes := priv.Public().Bytes() pubBytes := priv.Public().Bytes()
message := []byte("test message for lamport sha512") message := []byte("test message for lamport sha512")
messageHash := sha512.Sum512(message) messageHash := sha512.Sum512(message)
// Sign the hash directly (precompile expects pre-hashed input) // Sign the hash directly (precompile expects pre-hashed input)
sig, err := priv.SignHash(messageHash[:]) sig, err := priv.SignHash(messageHash[:])
require.NoError(t, err) require.NoError(t, err)
// Build precompile input // Build precompile input
sigBytes := sig.Bytes() sigBytes := sig.Bytes()
input := make([]byte, 64+len(sigBytes)+len(pubBytes)) input := make([]byte, 64+len(sigBytes)+len(pubBytes))
copy(input[:64], messageHash[:]) copy(input[:64], messageHash[:])
copy(input[64:], sigBytes) copy(input[64:], sigBytes)
copy(input[64+len(sigBytes):], pubBytes) copy(input[64+len(sigBytes):], pubBytes)
// Test gas // Test gas
gas := verifier.RequiredGas(input) gas := verifier.RequiredGas(input)
assert.Equal(t, uint64(80000), gas) assert.Equal(t, uint64(80000), gas)
// Test verification // Test verification
output, err := verifier.Run(input) output, err := verifier.Run(input)
require.NoError(t, err) require.NoError(t, err)
@@ -314,63 +314,63 @@ func TestLamportPrecompiles(t *testing.T) {
t.Run("LamportBatchVerify", func(t *testing.T) { t.Run("LamportBatchVerify", func(t *testing.T) {
batchVerifier := &LamportBatchVerify{} batchVerifier := &LamportBatchVerify{}
// Generate multiple signatures // Generate multiple signatures
numSigs := 3 numSigs := 3
var messages [][]byte var messages [][]byte
var sigs []*lamport.Signature var sigs []*lamport.Signature
var pubs []*lamport.PublicKey var pubs []*lamport.PublicKey
for i := 0; i < numSigs; i++ { for i := 0; i < numSigs; i++ {
priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256) priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256)
require.NoError(t, err) require.NoError(t, err)
// Get public key BEFORE signing // Get public key BEFORE signing
pub := priv.Public() pub := priv.Public()
pubs = append(pubs, pub) pubs = append(pubs, pub)
message := []byte(fmt.Sprintf("message %d", i)) message := []byte(fmt.Sprintf("message %d", i))
messages = append(messages, message) messages = append(messages, message)
// Sign the hash directly // Sign the hash directly
msgHash := sha256.Sum256(message) msgHash := sha256.Sum256(message)
sig, err := priv.SignHash(msgHash[:]) sig, err := priv.SignHash(msgHash[:])
require.NoError(t, err) require.NoError(t, err)
sigs = append(sigs, sig) sigs = append(sigs, sig)
} }
// Build batch input // Build batch input
// Format: [num_sigs(1)][hash_type(1)][data...] // Format: [num_sigs(1)][hash_type(1)][data...]
// data = [msg_hash][sig][pubkey] repeated // data = [msg_hash][sig][pubkey] repeated
// Calculate total size // Calculate total size
hashSize := 32 // SHA256 hashSize := 32 // SHA256
sigSize := len(sigs[0].Bytes()) sigSize := len(sigs[0].Bytes())
pubSize := len(pubs[0].Bytes()) pubSize := len(pubs[0].Bytes())
dataSize := numSigs * (hashSize + sigSize + pubSize) dataSize := numSigs * (hashSize + sigSize + pubSize)
input := make([]byte, 2+dataSize) input := make([]byte, 2+dataSize)
input[0] = byte(numSigs) input[0] = byte(numSigs)
input[1] = 0 // SHA256 input[1] = 0 // SHA256
offset := 2 offset := 2
for i := 0; i < numSigs; i++ { for i := 0; i < numSigs; i++ {
hash := sha256.Sum256(messages[i]) hash := sha256.Sum256(messages[i])
copy(input[offset:], hash[:]) copy(input[offset:], hash[:])
offset += hashSize offset += hashSize
copy(input[offset:], sigs[i].Bytes()) copy(input[offset:], sigs[i].Bytes())
offset += sigSize offset += sigSize
copy(input[offset:], pubs[i].Bytes()) copy(input[offset:], pubs[i].Bytes())
offset += pubSize offset += pubSize
} }
// Test gas // Test gas
gas := batchVerifier.RequiredGas(input) gas := batchVerifier.RequiredGas(input)
expectedGas := uint64(30000 + 40000*uint64(numSigs)) expectedGas := uint64(30000 + 40000*uint64(numSigs))
assert.Equal(t, expectedGas, gas) assert.Equal(t, expectedGas, gas)
// Test batch verification // Test batch verification
output, err := batchVerifier.Run(input) output, err := batchVerifier.Run(input)
require.NoError(t, err) require.NoError(t, err)
@@ -380,10 +380,10 @@ func TestLamportPrecompiles(t *testing.T) {
for i := 1; i <= numSigs; i++ { for i := 1; i <= numSigs; i++ {
assert.Equal(t, byte(1), output[i], fmt.Sprintf("Signature %d should be valid", i-1)) assert.Equal(t, byte(1), output[i], fmt.Sprintf("Signature %d should be valid", i-1))
} }
// Corrupt one signature // Corrupt one signature
input[2+hashSize] ^= 0xFF input[2+hashSize] ^= 0xFF
output, err = batchVerifier.Run(input) output, err = batchVerifier.Run(input)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, byte(0), output[0], "Any invalid signature should return overall 0") assert.Equal(t, byte(0), output[0], "Any invalid signature should return overall 0")
@@ -392,49 +392,49 @@ func TestLamportPrecompiles(t *testing.T) {
t.Run("LamportMerkleRoot", func(t *testing.T) { t.Run("LamportMerkleRoot", func(t *testing.T) {
merkleRoot := &LamportMerkleRoot{} merkleRoot := &LamportMerkleRoot{}
// Generate multiple public keys // Generate multiple public keys
numKeys := 4 numKeys := 4
var pubs []*lamport.PublicKey var pubs []*lamport.PublicKey
for i := 0; i < numKeys; i++ { for i := 0; i < numKeys; i++ {
priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256) priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256)
require.NoError(t, err) require.NoError(t, err)
pubs = append(pubs, priv.Public()) pubs = append(pubs, priv.Public())
} }
// Build input // Build input
// Format: [num_keys(1)][hash_type(1)][pubkeys...] // Format: [num_keys(1)][hash_type(1)][pubkeys...]
pubSize := len(pubs[0].Bytes()) pubSize := len(pubs[0].Bytes())
input := make([]byte, 2+numKeys*pubSize) input := make([]byte, 2+numKeys*pubSize)
input[0] = byte(numKeys) input[0] = byte(numKeys)
input[1] = 0 // SHA256 input[1] = 0 // SHA256
offset := 2 offset := 2
for _, pub := range pubs { for _, pub := range pubs {
copy(input[offset:], pub.Bytes()) copy(input[offset:], pub.Bytes())
offset += pubSize offset += pubSize
} }
// Test gas // Test gas
gas := merkleRoot.RequiredGas(input) gas := merkleRoot.RequiredGas(input)
assert.Equal(t, uint64(100000), gas) assert.Equal(t, uint64(100000), gas)
// Test root computation // Test root computation
output, err := merkleRoot.Run(input) output, err := merkleRoot.Run(input)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, output, 32, "Merkle root should be 32 bytes") assert.Len(t, output, 32, "Merkle root should be 32 bytes")
// Same keys should produce same root // Same keys should produce same root
output2, err := merkleRoot.Run(input) output2, err := merkleRoot.Run(input)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, output, output2, "Same keys should produce same root") assert.Equal(t, output, output2, "Same keys should produce same root")
// Different order should produce different root // Different order should produce different root
// Swap first two keys // Swap first two keys
copy(input[5:5+pubSize], pubs[1].Bytes()) copy(input[5:5+pubSize], pubs[1].Bytes())
copy(input[5+pubSize:5+2*pubSize], pubs[0].Bytes()) copy(input[5+pubSize:5+2*pubSize], pubs[0].Bytes())
output3, err := merkleRoot.Run(input) output3, err := merkleRoot.Run(input)
require.NoError(t, err) require.NoError(t, err)
assert.NotEqual(t, output, output3, "Different order should produce different root") assert.NotEqual(t, output, output3, "Different order should produce different root")
@@ -445,19 +445,19 @@ func TestLamportPrecompiles(t *testing.T) {
func TestBLSPrecompiles(t *testing.T) { func TestBLSPrecompiles(t *testing.T) {
t.Run("BLSVerify", func(t *testing.T) { t.Run("BLSVerify", func(t *testing.T) {
verifier := &BLSVerify{} verifier := &BLSVerify{}
// Create dummy input (placeholder implementation) // Create dummy input (placeholder implementation)
// Format: [96 bytes sig][48 bytes pubkey][message] // Format: [96 bytes sig][48 bytes pubkey][message]
message := []byte("test message for BLS") message := []byte("test message for BLS")
input := make([]byte, 96+48+len(message)) input := make([]byte, 96+48+len(message))
rand.Read(input[:96]) // Random signature rand.Read(input[:96]) // Random signature
rand.Read(input[96:144]) // Random pubkey rand.Read(input[96:144]) // Random pubkey
copy(input[144:], message) copy(input[144:], message)
// Test gas // Test gas
gas := verifier.RequiredGas(input) gas := verifier.RequiredGas(input)
assert.Equal(t, uint64(150000), gas) assert.Equal(t, uint64(150000), gas)
// Test run (placeholder always returns success) // Test run (placeholder always returns success)
output, err := verifier.Run(input) output, err := verifier.Run(input)
require.NoError(t, err) require.NoError(t, err)
@@ -466,31 +466,31 @@ func TestBLSPrecompiles(t *testing.T) {
t.Run("BLSAggregateVerify", func(t *testing.T) { t.Run("BLSAggregateVerify", func(t *testing.T) {
aggVerifier := &BLSAggregateVerify{} aggVerifier := &BLSAggregateVerify{}
// Build aggregate input // Build aggregate input
// Format: [num_sigs(1)][signatures][pubkeys][encoded_messages] // Format: [num_sigs(1)][signatures][pubkeys][encoded_messages]
numSigs := 3 numSigs := 3
sigSize := 96 sigSize := 96
pubSize := 48 pubSize := 48
msgSize := 32 msgSize := 32
totalSize := 1 + numSigs*(sigSize+pubSize+4+msgSize) totalSize := 1 + numSigs*(sigSize+pubSize+4+msgSize)
input := make([]byte, totalSize) input := make([]byte, totalSize)
input[0] = byte(numSigs) input[0] = byte(numSigs)
offset := 1 offset := 1
// Add signatures // Add signatures
for i := 0; i < numSigs; i++ { for i := 0; i < numSigs; i++ {
rand.Read(input[offset : offset+sigSize]) rand.Read(input[offset : offset+sigSize])
offset += sigSize offset += sigSize
} }
// Add public keys // Add public keys
for i := 0; i < numSigs; i++ { for i := 0; i < numSigs; i++ {
rand.Read(input[offset : offset+pubSize]) rand.Read(input[offset : offset+pubSize])
offset += pubSize offset += pubSize
} }
// Add messages (with length prefixes) // Add messages (with length prefixes)
for i := 0; i < numSigs; i++ { for i := 0; i < numSigs; i++ {
binary.BigEndian.PutUint32(input[offset:offset+4], uint32(msgSize)) binary.BigEndian.PutUint32(input[offset:offset+4], uint32(msgSize))
@@ -498,13 +498,13 @@ func TestBLSPrecompiles(t *testing.T) {
rand.Read(input[offset : offset+msgSize]) rand.Read(input[offset : offset+msgSize])
offset += msgSize offset += msgSize
} }
// Test gas // Test gas
gas := aggVerifier.RequiredGas(input) gas := aggVerifier.RequiredGas(input)
// blsAggregateVerifyGas = 200000, blsPerSignatureGas = 30000 // blsAggregateVerifyGas = 200000, blsPerSignatureGas = 30000
expectedGas := uint64(200000 + 30000*uint64(numSigs)) expectedGas := uint64(200000 + 30000*uint64(numSigs))
assert.Equal(t, expectedGas, gas) assert.Equal(t, expectedGas, gas)
// Test run // Test run
output, err := aggVerifier.Run(input) output, err := aggVerifier.Run(input)
require.NoError(t, err) require.NoError(t, err)
@@ -513,24 +513,24 @@ func TestBLSPrecompiles(t *testing.T) {
t.Run("BLSPublicKeyAggregate", func(t *testing.T) { t.Run("BLSPublicKeyAggregate", func(t *testing.T) {
aggregator := &BLSPublicKeyAggregate{} aggregator := &BLSPublicKeyAggregate{}
// Build input // Build input
// Format: [num_keys(1)][pubkeys...] // Format: [num_keys(1)][pubkeys...]
numKeys := 5 numKeys := 5
pubSize := 48 pubSize := 48
input := make([]byte, 1+numKeys*pubSize) input := make([]byte, 1+numKeys*pubSize)
input[0] = byte(numKeys) input[0] = byte(numKeys)
for i := 0; i < numKeys; i++ { for i := 0; i < numKeys; i++ {
rand.Read(input[1+i*pubSize : 1+(i+1)*pubSize]) rand.Read(input[1+i*pubSize : 1+(i+1)*pubSize])
} }
// Test gas // Test gas
gas := aggregator.RequiredGas(input) gas := aggregator.RequiredGas(input)
expectedGas := uint64(50000 + 10000*uint64(numKeys)) expectedGas := uint64(50000 + 10000*uint64(numKeys))
assert.Equal(t, expectedGas, gas) assert.Equal(t, expectedGas, gas)
// Test run // Test run
output, err := aggregator.Run(input) output, err := aggregator.Run(input)
require.NoError(t, err) require.NoError(t, err)
@@ -539,24 +539,24 @@ func TestBLSPrecompiles(t *testing.T) {
t.Run("BLSHashToPoint", func(t *testing.T) { t.Run("BLSHashToPoint", func(t *testing.T) {
hashToPoint := &BLSHashToPoint{} hashToPoint := &BLSHashToPoint{}
// Test with various message sizes // Test with various message sizes
messages := [][]byte{ messages := [][]byte{
[]byte("short"), []byte("short"),
[]byte("medium length message for testing"), []byte("medium length message for testing"),
bytes.Repeat([]byte("long "), 100), bytes.Repeat([]byte("long "), 100),
} }
for _, msg := range messages { for _, msg := range messages {
// Test gas // Test gas
gas := hashToPoint.RequiredGas(msg) gas := hashToPoint.RequiredGas(msg)
assert.Equal(t, uint64(80000), gas) assert.Equal(t, uint64(80000), gas)
// Test run // Test run
output, err := hashToPoint.Run(msg) output, err := hashToPoint.Run(msg)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, output, 96, "Hash to point should produce 96-byte point") assert.Len(t, output, 96, "Hash to point should produce 96-byte point")
// Same message should produce same point // Same message should produce same point
output2, err := hashToPoint.Run(msg) output2, err := hashToPoint.Run(msg)
require.NoError(t, err) require.NoError(t, err)
@@ -577,16 +577,16 @@ func TestPrecompileRegistry(t *testing.T) {
// BLS // BLS
"0x0160", "0x0161", "0x0162", "0x0163", "0x0164", "0x0165", "0x0166", "0x0160", "0x0161", "0x0162", "0x0163", "0x0164", "0x0165", "0x0166",
} }
for _, addr := range expectedAddresses { for _, addr := range expectedAddresses {
t.Run(addr, func(t *testing.T) { t.Run(addr, func(t *testing.T) {
// Convert hex string to address // Convert hex string to address
addrBytes, err := hex.DecodeString(addr[2:]) addrBytes, err := hex.DecodeString(addr[2:])
require.NoError(t, err) require.NoError(t, err)
var address [20]byte var address [20]byte
copy(address[20-len(addrBytes):], addrBytes) copy(address[20-len(addrBytes):], addrBytes)
precompile, exists := PostQuantumRegistry.contracts[address] precompile, exists := PostQuantumRegistry.contracts[address]
assert.True(t, exists, "Address %s should be registered", addr) assert.True(t, exists, "Address %s should be registered", addr)
assert.NotNil(t, precompile, "Precompile at %s should not be nil", addr) assert.NotNil(t, precompile, "Precompile at %s should not be nil", addr)
@@ -599,14 +599,14 @@ func TestPrecompileRegistry(t *testing.T) {
shake256Addr := [20]byte{} shake256Addr := [20]byte{}
shake256Addr[18] = 0x01 shake256Addr[18] = 0x01
shake256Addr[19] = 0x43 shake256Addr[19] = 0x43
input := make([]byte, 36) input := make([]byte, 36)
binary.BigEndian.PutUint32(input[:4], 32) binary.BigEndian.PutUint32(input[:4], 32)
copy(input[4:], []byte("test")) copy(input[4:], []byte("test"))
gas := GetGasEstimate(shake256Addr, len(input)) gas := GetGasEstimate(shake256Addr, len(input))
assert.Greater(t, gas, uint64(0), "Should return non-zero gas estimate") assert.Greater(t, gas, uint64(0), "Should return non-zero gas estimate")
// Test unknown address // Test unknown address
unknownAddr := [20]byte{0xFF} unknownAddr := [20]byte{0xFF}
gas = GetGasEstimate(unknownAddr, len(input)) gas = GetGasEstimate(unknownAddr, len(input))
@@ -615,13 +615,13 @@ func TestPrecompileRegistry(t *testing.T) {
t.Run("Info", func(t *testing.T) { t.Run("Info", func(t *testing.T) {
info := Info() info := Info()
// Check expected keys exist // Check expected keys exist
assert.Contains(t, info, "total_precompiles") assert.Contains(t, info, "total_precompiles")
assert.Contains(t, info, "cgo_enabled") assert.Contains(t, info, "cgo_enabled")
assert.Contains(t, info, "standards") assert.Contains(t, info, "standards")
assert.Contains(t, info, "address_ranges") assert.Contains(t, info, "address_ranges")
// Check total precompiles count // Check total precompiles count
totalPrecompiles, ok := info["total_precompiles"].(int) totalPrecompiles, ok := info["total_precompiles"].(int)
assert.True(t, ok, "total_precompiles should be an int") assert.True(t, ok, "total_precompiles should be an int")
@@ -644,12 +644,12 @@ func TestErrorHandling(t *testing.T) {
&LamportVerifySHA256{}, &LamportVerifySHA256{},
&BLSVerify{}, &BLSVerify{},
} }
for _, p := range precompiles { for _, p := range precompiles {
// Empty input // Empty input
_, err := p.Run([]byte{}) _, err := p.Run([]byte{})
assert.Error(t, err, "%T should error on empty input", p) assert.Error(t, err, "%T should error on empty input", p)
// Too short input // Too short input
_, err = p.Run([]byte{0, 1, 2}) _, err = p.Run([]byte{0, 1, 2})
assert.Error(t, err, "%T should error on short input", p) assert.Error(t, err, "%T should error on short input", p)
@@ -661,23 +661,23 @@ func TestErrorHandling(t *testing.T) {
shake := &SHAKE256{} shake := &SHAKE256{}
input := make([]byte, 8) input := make([]byte, 8)
binary.BigEndian.PutUint32(input[:4], 8193) // Too large binary.BigEndian.PutUint32(input[:4], 8193) // Too large
_, err := shake.Run(input) _, err := shake.Run(input)
assert.Error(t, err) assert.Error(t, err)
assert.Contains(t, err.Error(), "exceeds maximum") assert.Contains(t, err.Error(), "exceeds maximum")
// Batch verify with 0 signatures // Batch verify with 0 signatures
// batch := &LamportBatchVerify{} // batch := &LamportBatchVerify{}
// input = []byte{0, 0} // [num_sigs=0][hash_type=0] // input = []byte{0, 0} // [num_sigs=0][hash_type=0]
// Note: 0 signatures might be valid (empty batch), so skip this test // Note: 0 signatures might be valid (empty batch), so skip this test
// _, err = batch.Run(input) // _, err = batch.Run(input)
// assert.Error(t, err) // assert.Error(t, err)
// BLS aggregate with mismatched counts // BLS aggregate with mismatched counts
// agg := &BLSAggregateVerify{} // agg := &BLSAggregateVerify{}
// input = []byte{10} // Claims 10 sigs but no data (1 byte format) // input = []byte{10} // Claims 10 sigs but no data (1 byte format)
// _, err = agg.Run(input) // _, err = agg.Run(input)
// Note: This might not error immediately, depends on implementation // Note: This might not error immediately, depends on implementation
// assert.Error(t, err) // assert.Error(t, err)
@@ -687,12 +687,12 @@ func TestErrorHandling(t *testing.T) {
// Test that similar errors have consistent messages // Test that similar errors have consistent messages
shake128 := &SHAKE128{} shake128 := &SHAKE128{}
shake256 := &SHAKE256{} shake256 := &SHAKE256{}
shortInput := []byte{0, 1} shortInput := []byte{0, 1}
_, err1 := shake128.Run(shortInput) _, err1 := shake128.Run(shortInput)
_, err2 := shake256.Run(shortInput) _, err2 := shake256.Run(shortInput)
if err1 != nil && err2 != nil { if err1 != nil && err2 != nil {
// Both should have similar error messages // Both should have similar error messages
// They both say "input too short" which is consistent // They both say "input too short" which is consistent
@@ -709,7 +709,7 @@ func BenchmarkPrecompiles(b *testing.B) {
input := make([]byte, 36) input := make([]byte, 36)
binary.BigEndian.PutUint32(input[:4], 32) binary.BigEndian.PutUint32(input[:4], 32)
copy(input[4:], bytes.Repeat([]byte("x"), 32)) copy(input[4:], bytes.Repeat([]byte("x"), 32))
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = shake.Run(input) _, _ = shake.Run(input)
@@ -719,7 +719,7 @@ func BenchmarkPrecompiles(b *testing.B) {
b.Run("SHAKE256_1024bytes", func(b *testing.B) { b.Run("SHAKE256_1024bytes", func(b *testing.B) {
shake := &SHAKE256_1024{} shake := &SHAKE256_1024{}
input := bytes.Repeat([]byte("x"), 128) input := bytes.Repeat([]byte("x"), 128)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = shake.Run(input) _, _ = shake.Run(input)
@@ -728,21 +728,21 @@ func BenchmarkPrecompiles(b *testing.B) {
b.Run("LamportVerify", func(b *testing.B) { b.Run("LamportVerify", func(b *testing.B) {
verifier := &LamportVerifySHA256{} verifier := &LamportVerifySHA256{}
// Generate a signature once // Generate a signature once
priv, _ := lamport.GenerateKey(rand.Reader, lamport.SHA256) priv, _ := lamport.GenerateKey(rand.Reader, lamport.SHA256)
message := []byte("benchmark message") message := []byte("benchmark message")
sig, _ := priv.Sign(message) sig, _ := priv.Sign(message)
messageHash := sha256.Sum256(message) messageHash := sha256.Sum256(message)
sigBytes := sig.Bytes() sigBytes := sig.Bytes()
pubBytes := priv.Public().Bytes() pubBytes := priv.Public().Bytes()
input := make([]byte, 32+len(sigBytes)+len(pubBytes)) input := make([]byte, 32+len(sigBytes)+len(pubBytes))
copy(input[:32], messageHash[:]) copy(input[:32], messageHash[:])
copy(input[32:], sigBytes) copy(input[32:], sigBytes)
copy(input[32+len(sigBytes):], pubBytes) copy(input[32+len(sigBytes):], pubBytes)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = verifier.Run(input) _, _ = verifier.Run(input)
@@ -751,10 +751,10 @@ func BenchmarkPrecompiles(b *testing.B) {
b.Run("BLSVerify", func(b *testing.B) { b.Run("BLSVerify", func(b *testing.B) {
verifier := &BLSVerify{} verifier := &BLSVerify{}
input := make([]byte, 96+48+32) input := make([]byte, 96+48+32)
rand.Read(input) rand.Read(input)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = verifier.Run(input) _, _ = verifier.Run(input)
@@ -768,34 +768,34 @@ func TestCrossPrecompileWorkflows(t *testing.T) {
// Use SHAKE to hash, then Lamport to sign // Use SHAKE to hash, then Lamport to sign
shake := &SHAKE256_256{} shake := &SHAKE256_256{}
lamportVerify := &LamportVerifySHA256{} lamportVerify := &LamportVerifySHA256{}
// Original message // Original message
message := []byte("cross-precompile test message") message := []byte("cross-precompile test message")
// Hash with SHAKE256 // Hash with SHAKE256
hashedOutput, err := shake.Run(message) hashedOutput, err := shake.Run(message)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, hashedOutput, 32) assert.Len(t, hashedOutput, 32)
// Generate Lamport signature on the hash // Generate Lamport signature on the hash
priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256) priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256)
require.NoError(t, err) require.NoError(t, err)
// Get public key BEFORE signing // Get public key BEFORE signing
pubBytes := priv.Public().Bytes() pubBytes := priv.Public().Bytes()
// Sign the hash directly (not Sign which hashes again) // Sign the hash directly (not Sign which hashes again)
sig, err := priv.SignHash(hashedOutput) sig, err := priv.SignHash(hashedOutput)
require.NoError(t, err) require.NoError(t, err)
// Build verification input // Build verification input
sigBytes := sig.Bytes() sigBytes := sig.Bytes()
verifyInput := make([]byte, 32+len(sigBytes)+len(pubBytes)) verifyInput := make([]byte, 32+len(sigBytes)+len(pubBytes))
copy(verifyInput[:32], hashedOutput) copy(verifyInput[:32], hashedOutput)
copy(verifyInput[32:], sigBytes) copy(verifyInput[32:], sigBytes)
copy(verifyInput[32+len(sigBytes):], pubBytes) copy(verifyInput[32+len(sigBytes):], pubBytes)
// Verify // Verify
result, err := lamportVerify.Run(verifyInput) result, err := lamportVerify.Run(verifyInput)
require.NoError(t, err) require.NoError(t, err)
@@ -808,39 +808,39 @@ func TestCrossPrecompileWorkflows(t *testing.T) {
// Create merkle root of keys, then batch verify signatures // Create merkle root of keys, then batch verify signatures
merkleRoot := &LamportMerkleRoot{} merkleRoot := &LamportMerkleRoot{}
batchVerify := &LamportBatchVerify{} batchVerify := &LamportBatchVerify{}
// Generate multiple keys // Generate multiple keys
numKeys := 3 numKeys := 3
var privKeys []*lamport.PrivateKey var privKeys []*lamport.PrivateKey
var pubKeys []*lamport.PublicKey var pubKeys []*lamport.PublicKey
for i := 0; i < numKeys; i++ { for i := 0; i < numKeys; i++ {
priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256) priv, err := lamport.GenerateKey(rand.Reader, lamport.SHA256)
require.NoError(t, err) require.NoError(t, err)
privKeys = append(privKeys, priv) privKeys = append(privKeys, priv)
pubKeys = append(pubKeys, priv.Public()) pubKeys = append(pubKeys, priv.Public())
} }
// Compute merkle root // Compute merkle root
pubSize := len(pubKeys[0].Bytes()) pubSize := len(pubKeys[0].Bytes())
rootInput := make([]byte, 2+numKeys*pubSize) rootInput := make([]byte, 2+numKeys*pubSize)
rootInput[0] = byte(numKeys) rootInput[0] = byte(numKeys)
rootInput[1] = 0 // SHA256 rootInput[1] = 0 // SHA256
offset := 2 offset := 2
for _, pub := range pubKeys { for _, pub := range pubKeys {
copy(rootInput[offset:], pub.Bytes()) copy(rootInput[offset:], pub.Bytes())
offset += pubSize offset += pubSize
} }
root, err := merkleRoot.Run(rootInput) root, err := merkleRoot.Run(rootInput)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, root, 32) assert.Len(t, root, 32)
// Create signatures with the same keys // Create signatures with the same keys
messages := make([][]byte, numKeys) messages := make([][]byte, numKeys)
sigs := make([]*lamport.Signature, numKeys) sigs := make([]*lamport.Signature, numKeys)
for i := 0; i < numKeys; i++ { for i := 0; i < numKeys; i++ {
messages[i] = []byte(fmt.Sprintf("message %d", i)) messages[i] = []byte(fmt.Sprintf("message %d", i))
msgHash := sha256.Sum256(messages[i]) msgHash := sha256.Sum256(messages[i])
@@ -848,27 +848,27 @@ func TestCrossPrecompileWorkflows(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
sigs[i] = sig sigs[i] = sig
} }
// Batch verify // Batch verify
hashSize := 32 hashSize := 32
sigSize := len(sigs[0].Bytes()) sigSize := len(sigs[0].Bytes())
batchInput := make([]byte, 2+numKeys*(hashSize+sigSize+pubSize)) batchInput := make([]byte, 2+numKeys*(hashSize+sigSize+pubSize))
batchInput[0] = byte(numKeys) batchInput[0] = byte(numKeys)
batchInput[1] = 0 // SHA256 batchInput[1] = 0 // SHA256
offset = 2 offset = 2
for i := 0; i < numKeys; i++ { for i := 0; i < numKeys; i++ {
hash := sha256.Sum256(messages[i]) hash := sha256.Sum256(messages[i])
copy(batchInput[offset:], hash[:]) copy(batchInput[offset:], hash[:])
offset += hashSize offset += hashSize
copy(batchInput[offset:], sigs[i].Bytes()) copy(batchInput[offset:], sigs[i].Bytes())
offset += sigSize offset += sigSize
copy(batchInput[offset:], pubKeys[i].Bytes()) copy(batchInput[offset:], pubKeys[i].Bytes())
offset += pubSize offset += pubSize
} }
result, err := batchVerify.Run(batchInput) result, err := batchVerify.Run(batchInput)
require.NoError(t, err) require.NoError(t, err)
// Batch verify returns [overall_valid][individual_results...] // Batch verify returns [overall_valid][individual_results...]
@@ -877,7 +877,7 @@ func TestCrossPrecompileWorkflows(t *testing.T) {
for i := 1; i <= numKeys; i++ { for i := 1; i <= numKeys; i++ {
assert.Equal(t, byte(1), result[i], fmt.Sprintf("Signature %d should be valid", i-1)) assert.Equal(t, byte(1), result[i], fmt.Sprintf("Signature %d should be valid", i-1))
} }
t.Logf("Merkle root: %x", root) t.Logf("Merkle root: %x", root)
t.Log("All signatures verified in batch") t.Log("All signatures verified in batch")
}) })
@@ -886,17 +886,17 @@ func TestCrossPrecompileWorkflows(t *testing.T) {
// Helper function to compare SHAKE output with reference implementation // Helper function to compare SHAKE output with reference implementation
func verifyShakeOutput(t *testing.T, input []byte, outputLen int, isShake256 bool) []byte { func verifyShakeOutput(t *testing.T, input []byte, outputLen int, isShake256 bool) []byte {
t.Helper() t.Helper()
var h sha3.ShakeHash var h sha3.ShakeHash
if isShake256 { if isShake256 {
h = sha3.NewShake256() h = sha3.NewShake256()
} else { } else {
h = sha3.NewShake128() h = sha3.NewShake128()
} }
h.Write(input) h.Write(input)
output := make([]byte, outputLen) output := make([]byte, outputLen)
h.Read(output) h.Read(output)
return output return output
} }
+2 -2
View File
@@ -45,7 +45,7 @@ func (s *SHAKE128) RequiredGas(input []byte) uint64 {
return shakeBaseGas return shakeBaseGas
} }
outputLen := uint32(input[0])<<24 | uint32(input[1])<<16 | uint32(input[2])<<8 | uint32(input[3]) outputLen := uint32(input[0])<<24 | uint32(input[1])<<16 | uint32(input[2])<<8 | uint32(input[3])
inputWords := uint64((len(input) + 31) / 32) // Include the 4-byte length in gas calculation inputWords := uint64((len(input) + 31) / 32) // Include the 4-byte length in gas calculation
outputWords := uint64((outputLen + 31) / 32) outputWords := uint64((outputLen + 31) / 32)
return shakeBaseGas + inputWords*shakePerWordGas + outputWords*shakeOutputGas return shakeBaseGas + inputWords*shakePerWordGas + outputWords*shakeOutputGas
} }
@@ -76,7 +76,7 @@ func (s *SHAKE256) RequiredGas(input []byte) uint64 {
return shakeBaseGas return shakeBaseGas
} }
outputLen := uint32(input[0])<<24 | uint32(input[1])<<16 | uint32(input[2])<<8 | uint32(input[3]) outputLen := uint32(input[0])<<24 | uint32(input[1])<<16 | uint32(input[2])<<8 | uint32(input[3])
inputWords := uint64((len(input) + 31) / 32) // Include the 4-byte length in gas calculation inputWords := uint64((len(input) + 31) / 32) // Include the 4-byte length in gas calculation
outputWords := uint64((outputLen + 31) / 32) outputWords := uint64((outputLen + 31) / 32)
return shakeBaseGas + inputWords*shakePerWordGas + outputWords*shakeOutputGas return shakeBaseGas + inputWords*shakePerWordGas + outputWords*shakeOutputGas
} }
+10 -10
View File
@@ -10,10 +10,10 @@ import (
func BenchmarkSignNoCGO(b *testing.B) { func BenchmarkSignNoCGO(b *testing.B) {
msg := make([]byte, 32) msg := make([]byte, 32)
rand.Read(msg) rand.Read(msg)
seckey := make([]byte, 32) seckey := make([]byte, 32)
rand.Read(seckey) rand.Read(seckey)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = Sign(msg, seckey) _, _ = Sign(msg, seckey)
@@ -23,12 +23,12 @@ func BenchmarkSignNoCGO(b *testing.B) {
func BenchmarkRecoverNoCGO(b *testing.B) { func BenchmarkRecoverNoCGO(b *testing.B) {
msg := make([]byte, 32) msg := make([]byte, 32)
rand.Read(msg) rand.Read(msg)
seckey := make([]byte, 32) seckey := make([]byte, 32)
rand.Read(seckey) rand.Read(seckey)
sig, _ := Sign(msg, seckey) sig, _ := Sign(msg, seckey)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, _ = RecoverPubkey(msg, sig) _, _ = RecoverPubkey(msg, sig)
@@ -38,18 +38,18 @@ func BenchmarkRecoverNoCGO(b *testing.B) {
func BenchmarkVerifySignature(b *testing.B) { func BenchmarkVerifySignature(b *testing.B) {
msg := make([]byte, 32) msg := make([]byte, 32)
rand.Read(msg) rand.Read(msg)
seckey := make([]byte, 32) seckey := make([]byte, 32)
rand.Read(seckey) rand.Read(seckey)
sig, _ := Sign(msg, seckey) sig, _ := Sign(msg, seckey)
pubkey, _ := RecoverPubkey(msg, sig) pubkey, _ := RecoverPubkey(msg, sig)
// Remove recovery ID for verification // Remove recovery ID for verification
sigNoRecovery := sig[:64] sigNoRecovery := sig[:64]
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
VerifySignature(pubkey, msg, sigNoRecovery) VerifySignature(pubkey, msg, sigNoRecovery)
} }
} }
+5 -5
View File
@@ -15,17 +15,17 @@ import (
func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
// Convert scalar to big.Int // Convert scalar to big.Int
k := new(big.Int).SetBytes(scalar) k := new(big.Int).SetBytes(scalar)
// Handle special cases // Handle special cases
if k.Sign() == 0 { if k.Sign() == 0 {
return new(big.Int), new(big.Int) return new(big.Int), new(big.Int)
} }
// Use the double-and-add algorithm // Use the double-and-add algorithm
// Start with the identity point (0, 0) // Start with the identity point (0, 0)
x, y := new(big.Int), new(big.Int) x, y := new(big.Int), new(big.Int)
addX, addY := new(big.Int).Set(Bx), new(big.Int).Set(By) addX, addY := new(big.Int).Set(Bx), new(big.Int).Set(By)
// Process each bit of k from least significant to most significant // Process each bit of k from least significant to most significant
for i := 0; i < k.BitLen(); i++ { for i := 0; i < k.BitLen(); i++ {
if k.Bit(i) == 1 { if k.Bit(i) == 1 {
@@ -42,6 +42,6 @@ func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int,
// Double the point for the next bit // Double the point for the next bit
addX, addY = bitCurve.Double(addX, addY) addX, addY = bitCurve.Double(addX, addY)
} }
return x, y return x, y
} }
+45 -45
View File
@@ -16,7 +16,7 @@ func FuzzSignatureVerification(f *testing.F) {
// Seed corpus with valid and invalid signatures // Seed corpus with valid and invalid signatures
f.Add(bytes.Repeat([]byte{0}, 32), bytes.Repeat([]byte{0}, 65)) f.Add(bytes.Repeat([]byte{0}, 32), bytes.Repeat([]byte{0}, 65))
f.Add(bytes.Repeat([]byte{0xff}, 32), bytes.Repeat([]byte{0xff}, 65)) f.Add(bytes.Repeat([]byte{0xff}, 32), bytes.Repeat([]byte{0xff}, 65))
// Add a valid signature // Add a valid signature
privKey := make([]byte, 32) privKey := make([]byte, 32)
privKey[31] = 1 // Simple valid private key privKey[31] = 1 // Simple valid private key
@@ -24,17 +24,17 @@ func FuzzSignatureVerification(f *testing.F) {
if sig, err := Sign(msg, privKey); err == nil { if sig, err := Sign(msg, privKey); err == nil {
f.Add(msg, sig) f.Add(msg, sig)
} }
// Add signatures with different recovery IDs // Add signatures with different recovery IDs
validSig := make([]byte, 65) validSig := make([]byte, 65)
copy(validSig[:32], bytes.Repeat([]byte{0xaa}, 32)) copy(validSig[:32], bytes.Repeat([]byte{0xaa}, 32))
copy(validSig[32:64], bytes.Repeat([]byte{0xbb}, 32)) copy(validSig[32:64], bytes.Repeat([]byte{0xbb}, 32))
validSig[64] = 0 validSig[64] = 0
f.Add(hashing.ComputeHash256([]byte("test")), validSig) f.Add(hashing.ComputeHash256([]byte("test")), validSig)
validSig[64] = 1 validSig[64] = 1
f.Add(hashing.ComputeHash256([]byte("test2")), validSig) f.Add(hashing.ComputeHash256([]byte("test2")), validSig)
f.Fuzz(func(t *testing.T, msg []byte, sig []byte) { f.Fuzz(func(t *testing.T, msg []byte, sig []byte) {
// Ensure msg is 32 bytes (hash size) // Ensure msg is 32 bytes (hash size)
if len(msg) != 32 { if len(msg) != 32 {
@@ -44,23 +44,23 @@ func FuzzSignatureVerification(f *testing.F) {
msg = msg[:32] msg = msg[:32]
} }
} }
// Try to recover public key - should not panic // Try to recover public key - should not panic
pubKey, err := RecoverPubkey(msg, sig) pubKey, err := RecoverPubkey(msg, sig)
if err != nil { if err != nil {
// Expected for invalid signatures // Expected for invalid signatures
return return
} }
// If recovery succeeded, verify the public key is valid // If recovery succeeded, verify the public key is valid
if len(pubKey) != 65 && len(pubKey) != 33 { if len(pubKey) != 65 && len(pubKey) != 33 {
t.Errorf("Invalid public key length: %d", len(pubKey)) t.Errorf("Invalid public key length: %d", len(pubKey))
} }
// Try to verify signature with recovered key // Try to verify signature with recovered key
valid := VerifySignature(pubKey, msg, sig[:64]) valid := VerifySignature(pubKey, msg, sig[:64])
_ = valid // Result doesn't matter, just ensure no panic _ = valid // Result doesn't matter, just ensure no panic
// Test decompression if compressed // Test decompression if compressed
if len(pubKey) == 33 { if len(pubKey) == 33 {
decompressed, err := DecompressPubkey(pubKey) decompressed, err := DecompressPubkey(pubKey)
@@ -79,16 +79,16 @@ func FuzzSignatureCreation(f *testing.F) {
// Seed corpus // Seed corpus
f.Add(bytes.Repeat([]byte{0x01}, 32), bytes.Repeat([]byte{0x02}, 32)) f.Add(bytes.Repeat([]byte{0x01}, 32), bytes.Repeat([]byte{0x02}, 32))
f.Add(bytes.Repeat([]byte{0xff}, 32), hashing.ComputeHash256([]byte("test"))) f.Add(bytes.Repeat([]byte{0xff}, 32), hashing.ComputeHash256([]byte("test")))
// Add some valid private keys // Add some valid private keys
validKey1 := make([]byte, 32) validKey1 := make([]byte, 32)
validKey1[31] = 1 validKey1[31] = 1
f.Add(validKey1, hashing.ComputeHash256([]byte("message1"))) f.Add(validKey1, hashing.ComputeHash256([]byte("message1")))
validKey2 := make([]byte, 32) validKey2 := make([]byte, 32)
copy(validKey2, []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}) copy(validKey2, []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef})
f.Add(validKey2, hashing.ComputeHash256([]byte("message2"))) f.Add(validKey2, hashing.ComputeHash256([]byte("message2")))
f.Fuzz(func(t *testing.T, privKey []byte, msg []byte) { f.Fuzz(func(t *testing.T, privKey []byte, msg []byte) {
// Ensure proper sizes // Ensure proper sizes
if len(privKey) != 32 { if len(privKey) != 32 {
@@ -98,7 +98,7 @@ func FuzzSignatureCreation(f *testing.F) {
privKey = privKey[:32] privKey = privKey[:32]
} }
} }
if len(msg) != 32 { if len(msg) != 32 {
if len(msg) < 32 { if len(msg) < 32 {
msg = append(msg, bytes.Repeat([]byte{0}, 32-len(msg))...) msg = append(msg, bytes.Repeat([]byte{0}, 32-len(msg))...)
@@ -106,32 +106,32 @@ func FuzzSignatureCreation(f *testing.F) {
msg = msg[:32] msg = msg[:32]
} }
} }
// Try to sign // Try to sign
sig, err := Sign(msg, privKey) sig, err := Sign(msg, privKey)
if err != nil { if err != nil {
// Expected for invalid private keys // Expected for invalid private keys
return return
} }
// Signature should be 65 bytes // Signature should be 65 bytes
if len(sig) != 65 { if len(sig) != 65 {
t.Errorf("Invalid signature length: %d", len(sig)) t.Errorf("Invalid signature length: %d", len(sig))
return return
} }
// Recovery ID should be 0 or 1 // Recovery ID should be 0 or 1
if sig[64] > 1 { if sig[64] > 1 {
t.Errorf("Invalid recovery ID: %d", sig[64]) t.Errorf("Invalid recovery ID: %d", sig[64])
} }
// Try to recover public key // Try to recover public key
pubKey, err := RecoverPubkey(msg, sig) pubKey, err := RecoverPubkey(msg, sig)
if err != nil { if err != nil {
t.Errorf("Failed to recover public key from signature we created: %v", err) t.Errorf("Failed to recover public key from signature we created: %v", err)
return return
} }
// Verify signature with recovered key // Verify signature with recovered key
valid := VerifySignature(pubKey, msg, sig[:64]) valid := VerifySignature(pubKey, msg, sig[:64])
if !valid { if !valid {
@@ -143,10 +143,10 @@ func FuzzSignatureCreation(f *testing.F) {
// FuzzPublicKeyCompression tests public key compression/decompression // FuzzPublicKeyCompression tests public key compression/decompression
func FuzzPublicKeyCompression(f *testing.F) { func FuzzPublicKeyCompression(f *testing.F) {
// Seed corpus with various public key representations // Seed corpus with various public key representations
f.Add(bytes.Repeat([]byte{0x04}, 65)) // Uncompressed prefix f.Add(bytes.Repeat([]byte{0x04}, 65)) // Uncompressed prefix
f.Add(bytes.Repeat([]byte{0x02}, 33)) // Compressed even Y f.Add(bytes.Repeat([]byte{0x02}, 33)) // Compressed even Y
f.Add(bytes.Repeat([]byte{0x03}, 33)) // Compressed odd Y f.Add(bytes.Repeat([]byte{0x03}, 33)) // Compressed odd Y
// Generate a valid public key // Generate a valid public key
privKey := make([]byte, 32) privKey := make([]byte, 32)
privKey[31] = 42 privKey[31] = 42
@@ -156,7 +156,7 @@ func FuzzPublicKeyCompression(f *testing.F) {
f.Add(pubKey) f.Add(pubKey)
} }
} }
f.Fuzz(func(t *testing.T, pubKeyData []byte) { f.Fuzz(func(t *testing.T, pubKeyData []byte) {
// Test compression if uncompressed // Test compression if uncompressed
if len(pubKeyData) == 65 && pubKeyData[0] == 0x04 { if len(pubKeyData) == 65 && pubKeyData[0] == 0x04 {
@@ -165,19 +165,19 @@ func FuzzPublicKeyCompression(f *testing.F) {
t.Errorf("Compressed public key has wrong length: %d", len(compressed)) t.Errorf("Compressed public key has wrong length: %d", len(compressed))
return return
} }
// Try to decompress back // Try to decompress back
decompressed, err := DecompressPubkey(compressed) decompressed, err := DecompressPubkey(compressed)
if err != nil { if err != nil {
// Some points might not be on the curve // Some points might not be on the curve
return return
} }
if len(decompressed) != 65 { if len(decompressed) != 65 {
t.Errorf("Decompressed public key has wrong length: %d", len(decompressed)) t.Errorf("Decompressed public key has wrong length: %d", len(decompressed))
} }
} }
// Test decompression if compressed // Test decompression if compressed
if len(pubKeyData) == 33 && (pubKeyData[0] == 0x02 || pubKeyData[0] == 0x03) { if len(pubKeyData) == 33 && (pubKeyData[0] == 0x02 || pubKeyData[0] == 0x03) {
decompressed, err := DecompressPubkey(pubKeyData) decompressed, err := DecompressPubkey(pubKeyData)
@@ -185,12 +185,12 @@ func FuzzPublicKeyCompression(f *testing.F) {
// Expected for invalid compressed keys // Expected for invalid compressed keys
return return
} }
if len(decompressed) != 65 { if len(decompressed) != 65 {
t.Errorf("Decompressed public key has wrong length: %d", len(decompressed)) t.Errorf("Decompressed public key has wrong length: %d", len(decompressed))
return return
} }
// Compress again and verify round-trip // Compress again and verify round-trip
recompressed := CompressPubkey(decompressed[1:33], decompressed[33:65]) recompressed := CompressPubkey(decompressed[1:33], decompressed[33:65])
if !bytes.Equal(recompressed, pubKeyData) { if !bytes.Equal(recompressed, pubKeyData) {
@@ -206,7 +206,7 @@ func FuzzSignatureMalleability(f *testing.F) {
// Seed corpus // Seed corpus
f.Add(bytes.Repeat([]byte{0x7f}, 32), bytes.Repeat([]byte{0x80}, 32), uint8(0)) f.Add(bytes.Repeat([]byte{0x7f}, 32), bytes.Repeat([]byte{0x80}, 32), uint8(0))
f.Add(bytes.Repeat([]byte{0xff}, 32), bytes.Repeat([]byte{0x01}, 32), uint8(1)) f.Add(bytes.Repeat([]byte{0xff}, 32), bytes.Repeat([]byte{0x01}, 32), uint8(1))
f.Fuzz(func(t *testing.T, r []byte, s []byte, v uint8) { f.Fuzz(func(t *testing.T, r []byte, s []byte, v uint8) {
// Ensure proper sizes // Ensure proper sizes
if len(r) != 32 { if len(r) != 32 {
@@ -216,7 +216,7 @@ func FuzzSignatureMalleability(f *testing.F) {
r = r[:32] r = r[:32]
} }
} }
if len(s) != 32 { if len(s) != 32 {
if len(s) < 32 { if len(s) < 32 {
s = append(s, bytes.Repeat([]byte{0}, 32-len(s))...) s = append(s, bytes.Repeat([]byte{0}, 32-len(s))...)
@@ -224,23 +224,23 @@ func FuzzSignatureMalleability(f *testing.F) {
s = s[:32] s = s[:32]
} }
} }
// Create signature // Create signature
sig := make([]byte, 65) sig := make([]byte, 65)
copy(sig[:32], r) copy(sig[:32], r)
copy(sig[32:64], s) copy(sig[32:64], s)
sig[64] = v & 1 // Ensure v is 0 or 1 sig[64] = v & 1 // Ensure v is 0 or 1
// Create a random message // Create a random message
msg := hashing.ComputeHash256(append(r, s...)) msg := hashing.ComputeHash256(append(r, s...))
// Try to verify - should not panic // Try to verify - should not panic
pubKey, err := RecoverPubkey(msg, sig) pubKey, err := RecoverPubkey(msg, sig)
if err != nil { if err != nil {
// Expected for invalid signatures // Expected for invalid signatures
return return
} }
// Try signature verification // Try signature verification
valid := VerifySignature(pubKey, msg, sig[:64]) valid := VerifySignature(pubKey, msg, sig[:64])
_ = valid // Don't care about result, just ensure no panic _ = valid // Don't care about result, just ensure no panic
@@ -252,15 +252,15 @@ func FuzzECDSAEdgeCases(f *testing.F) {
// Seed corpus with edge cases // Seed corpus with edge cases
f.Add([]byte{}, []byte{}) f.Add([]byte{}, []byte{})
f.Add(nil, nil) f.Add(nil, nil)
// All zeros // All zeros
zeros := make([]byte, 32) zeros := make([]byte, 32)
f.Add(zeros, zeros) f.Add(zeros, zeros)
// All ones // All ones
ones := bytes.Repeat([]byte{0xff}, 32) ones := bytes.Repeat([]byte{0xff}, 32)
f.Add(ones, ones) f.Add(ones, ones)
// Near the curve order // Near the curve order
nearOrder := make([]byte, 32) nearOrder := make([]byte, 32)
copy(nearOrder, []byte{ copy(nearOrder, []byte{
@@ -270,7 +270,7 @@ func FuzzECDSAEdgeCases(f *testing.F) {
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
}) })
f.Add(nearOrder, hashing.ComputeHash256([]byte("edge"))) f.Add(nearOrder, hashing.ComputeHash256([]byte("edge")))
f.Fuzz(func(t *testing.T, privKey []byte, msg []byte) { f.Fuzz(func(t *testing.T, privKey []byte, msg []byte) {
// Handle nil and empty cases // Handle nil and empty cases
if privKey == nil { if privKey == nil {
@@ -279,20 +279,20 @@ func FuzzECDSAEdgeCases(f *testing.F) {
if msg == nil { if msg == nil {
msg = make([]byte, 32) msg = make([]byte, 32)
} }
// Ensure proper sizes // Ensure proper sizes
if len(privKey) < 32 { if len(privKey) < 32 {
privKey = append(privKey, bytes.Repeat([]byte{0}, 32-len(privKey))...) privKey = append(privKey, bytes.Repeat([]byte{0}, 32-len(privKey))...)
} else if len(privKey) > 32 { } else if len(privKey) > 32 {
privKey = privKey[:32] privKey = privKey[:32]
} }
if len(msg) < 32 { if len(msg) < 32 {
msg = append(msg, bytes.Repeat([]byte{0}, 32-len(msg))...) msg = append(msg, bytes.Repeat([]byte{0}, 32-len(msg))...)
} else if len(msg) > 32 { } else if len(msg) > 32 {
msg = msg[:32] msg = msg[:32]
} }
// Test signing // Test signing
sig, err := Sign(msg, privKey) sig, err := Sign(msg, privKey)
if err != nil { if err != nil {
@@ -305,25 +305,25 @@ func FuzzECDSAEdgeCases(f *testing.F) {
t.Errorf("Unexpected error type: %v", err) t.Errorf("Unexpected error type: %v", err)
return return
} }
// If signing succeeded, verify signature properties // If signing succeeded, verify signature properties
if len(sig) != 65 { if len(sig) != 65 {
t.Errorf("Invalid signature length: %d", len(sig)) t.Errorf("Invalid signature length: %d", len(sig))
return return
} }
// Check recovery ID // Check recovery ID
if sig[64] > 1 { if sig[64] > 1 {
t.Errorf("Invalid recovery ID: %d", sig[64]) t.Errorf("Invalid recovery ID: %d", sig[64])
} }
// Try recovery // Try recovery
pubKey, err := RecoverPubkey(msg, sig) pubKey, err := RecoverPubkey(msg, sig)
if err != nil { if err != nil {
t.Errorf("Failed to recover public key from valid signature: %v", err) t.Errorf("Failed to recover public key from valid signature: %v", err)
return return
} }
// Verify the signature // Verify the signature
if !VerifySignature(pubKey, msg, sig[:64]) { if !VerifySignature(pubKey, msg, sig[:64]) {
t.Error("Signature verification failed for edge case") t.Error("Signature verification failed for edge case")
@@ -338,4 +338,4 @@ func randomBytes(t *testing.T, n int) []byte {
t.Fatal(err) t.Fatal(err)
} }
return b return b
} }
+26 -26
View File
@@ -12,28 +12,28 @@ import (
type SigID string type SigID string
const ( const (
MLDSA2 SigID = "mldsa2" MLDSA2 SigID = "mldsa2"
MLDSA3 SigID = "mldsa3" MLDSA3 SigID = "mldsa3"
SLHDSA SigID = "slhdsa" SLHDSA SigID = "slhdsa"
) )
// Signer interface for signature algorithms // Signer interface for signature algorithms
type Signer interface { type Signer interface {
// GenerateKeyPair generates a new signing key pair // GenerateKeyPair generates a new signing key pair
GenerateKeyPair() (PublicKey, PrivateKey, error) GenerateKeyPair() (PublicKey, PrivateKey, error)
// Sign creates a signature // Sign creates a signature
Sign(sk PrivateKey, message []byte) ([]byte, error) Sign(sk PrivateKey, message []byte) ([]byte, error)
// Verify verifies a signature // Verify verifies a signature
Verify(pk PublicKey, message, signature []byte) bool Verify(pk PublicKey, message, signature []byte) bool
// PublicKeySize returns the size of public keys // PublicKeySize returns the size of public keys
PublicKeySize() int PublicKeySize() int
// PrivateKeySize returns the size of private keys // PrivateKeySize returns the size of private keys
PrivateKeySize() int PrivateKeySize() int
// SignatureSize returns the size of signatures // SignatureSize returns the size of signatures
SignatureSize() int SignatureSize() int
} }
@@ -81,7 +81,7 @@ const (
func (m *MLDSA2Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) { func (m *MLDSA2Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
// Placeholder for actual ML-DSA key generation // Placeholder for actual ML-DSA key generation
// In production, this would use liboqs or native implementation // In production, this would use liboqs or native implementation
pk := &MLDSA2PublicKey{ pk := &MLDSA2PublicKey{
data: make([]byte, mldsa2PublicKeySize), data: make([]byte, mldsa2PublicKeySize),
} }
@@ -89,7 +89,7 @@ func (m *MLDSA2Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
data: make([]byte, mldsa2PrivateKeySize), data: make([]byte, mldsa2PrivateKeySize),
pk: pk, pk: pk,
} }
// Generate random key material (placeholder) // Generate random key material (placeholder)
if _, err := rand.Read(pk.data); err != nil { if _, err := rand.Read(pk.data); err != nil {
return nil, nil, err return nil, nil, err
@@ -97,7 +97,7 @@ func (m *MLDSA2Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
if _, err := rand.Read(sk.data); err != nil { if _, err := rand.Read(sk.data); err != nil {
return nil, nil, err return nil, nil, err
} }
return pk, sk, nil return pk, sk, nil
} }
@@ -107,18 +107,18 @@ func (m *MLDSA2Impl) Sign(sk PrivateKey, message []byte) ([]byte, error) {
if !ok { if !ok {
return nil, errors.New("invalid private key type") return nil, errors.New("invalid private key type")
} }
signature := make([]byte, mldsa2SignatureSize) signature := make([]byte, mldsa2SignatureSize)
// Placeholder for actual ML-DSA signing // Placeholder for actual ML-DSA signing
if _, err := rand.Read(signature); err != nil { if _, err := rand.Read(signature); err != nil {
return nil, err return nil, err
} }
// In production, this would perform actual ML-DSA signing // In production, this would perform actual ML-DSA signing
_ = mldsaSK.data _ = mldsaSK.data
_ = message _ = message
return signature, nil return signature, nil
} }
@@ -128,17 +128,17 @@ func (m *MLDSA2Impl) Verify(pk PublicKey, message, signature []byte) bool {
if !ok { if !ok {
return false return false
} }
if len(signature) != mldsa2SignatureSize { if len(signature) != mldsa2SignatureSize {
return false return false
} }
// Placeholder for actual ML-DSA verification // Placeholder for actual ML-DSA verification
// In production, this would perform actual verification // In production, this would perform actual verification
_ = mldsaPK.data _ = mldsaPK.data
_ = message _ = message
_ = signature _ = signature
// Placeholder: always return true for now // Placeholder: always return true for now
return true return true
} }
@@ -202,25 +202,25 @@ func (m *MLDSA3Impl) GenerateKeyPair() (PublicKey, PrivateKey, error) {
data: make([]byte, mldsa3PrivateKeySize), data: make([]byte, mldsa3PrivateKeySize),
pk: pk, pk: pk,
} }
if _, err := rand.Read(pk.data); err != nil { if _, err := rand.Read(pk.data); err != nil {
return nil, nil, err return nil, nil, err
} }
if _, err := rand.Read(sk.data); err != nil { if _, err := rand.Read(sk.data); err != nil {
return nil, nil, err return nil, nil, err
} }
return pk, sk, nil return pk, sk, nil
} }
// Sign creates a signature // Sign creates a signature
func (m *MLDSA3Impl) Sign(sk PrivateKey, message []byte) ([]byte, error) { func (m *MLDSA3Impl) Sign(sk PrivateKey, message []byte) ([]byte, error) {
signature := make([]byte, mldsa3SignatureSize) signature := make([]byte, mldsa3SignatureSize)
if _, err := rand.Read(signature); err != nil { if _, err := rand.Read(signature); err != nil {
return nil, err return nil, err
} }
return signature, nil return signature, nil
} }
@@ -229,7 +229,7 @@ func (m *MLDSA3Impl) Verify(pk PublicKey, message, signature []byte) bool {
if len(signature) != mldsa3SignatureSize { if len(signature) != mldsa3SignatureSize {
return false return false
} }
// Placeholder // Placeholder
return true return true
} }
@@ -273,7 +273,7 @@ func (ts *TranscriptSigner) SignTranscript(transcript []byte) ([]byte, error) {
// Add context string to prevent cross-protocol attacks // Add context string to prevent cross-protocol attacks
context := []byte("QZMQ-Transcript-v1") context := []byte("QZMQ-Transcript-v1")
message := append(context, transcript...) message := append(context, transcript...)
return ts.signer.Sign(ts.sk, message) return ts.signer.Sign(ts.sk, message)
} }
@@ -281,6 +281,6 @@ func (ts *TranscriptSigner) SignTranscript(transcript []byte) ([]byte, error) {
func VerifyTranscript(signer Signer, pk PublicKey, transcript, signature []byte) bool { func VerifyTranscript(signer Signer, pk PublicKey, transcript, signature []byte) bool {
context := []byte("QZMQ-Transcript-v1") context := []byte("QZMQ-Transcript-v1")
message := append(context, transcript...) message := append(context, transcript...)
return signer.Verify(pk, message, signature) return signer.Verify(pk, message, signature)
} }
+20 -20
View File
@@ -18,7 +18,7 @@ type OptimizedSLHDSA struct {
// NewOptimized creates an optimized SLH-DSA instance // NewOptimized creates an optimized SLH-DSA instance
func NewOptimized(mode Mode) *OptimizedSLHDSA { func NewOptimized(mode Mode) *OptimizedSLHDSA {
numWorkers := runtime.NumCPU() numWorkers := runtime.NumCPU()
return &OptimizedSLHDSA{ return &OptimizedSLHDSA{
mode: mode, mode: mode,
cachePool: &sync.Pool{ cachePool: &sync.Pool{
@@ -44,11 +44,11 @@ func (o *OptimizedSLHDSA) OptimizedSign(privateKey *PrivateKey, message []byte)
// Acquire worker slot // Acquire worker slot
o.workerPool <- struct{}{} o.workerPool <- struct{}{}
defer func() { <-o.workerPool }() defer func() { <-o.workerPool }()
// Get cache buffer from pool // Get cache buffer from pool
cache := o.cachePool.Get().([]byte) cache := o.cachePool.Get().([]byte)
defer o.cachePool.Put(cache) defer o.cachePool.Put(cache)
// Use optimized signing based on mode // Use optimized signing based on mode
switch o.mode { switch o.mode {
case SLHDSA128f: case SLHDSA128f:
@@ -125,7 +125,7 @@ func (o *OptimizedSLHDSA) optimizedSignGeneric(sk *PrivateKey, msg []byte, cache
func (o *OptimizedSLHDSA) processTreeOptimized(treeIdx int, sk *PrivateKey, msg []byte, sig []byte, cache []byte) { func (o *OptimizedSLHDSA) processTreeOptimized(treeIdx int, sk *PrivateKey, msg []byte, sig []byte, cache []byte) {
// Cache-friendly tree traversal // Cache-friendly tree traversal
// Use cache buffer for intermediate values // Use cache buffer for intermediate values
// Placeholder for actual tree processing // Placeholder for actual tree processing
// Real implementation would compute Merkle tree with optimizations // Real implementation would compute Merkle tree with optimizations
} }
@@ -134,7 +134,7 @@ func (o *OptimizedSLHDSA) processTreeOptimized(treeIdx int, sk *PrivateKey, msg
func (o *OptimizedSLHDSA) processTreesSequential(sk *PrivateKey, msg []byte, sig []byte, cache []byte) { func (o *OptimizedSLHDSA) processTreesSequential(sk *PrivateKey, msg []byte, sig []byte, cache []byte) {
// Sequential processing with minimal memory footprint // Sequential processing with minimal memory footprint
// Reuse cache buffer for each tree // Reuse cache buffer for each tree
// Placeholder for actual sequential processing // Placeholder for actual sequential processing
} }
@@ -142,7 +142,7 @@ func (o *OptimizedSLHDSA) processTreesSequential(sk *PrivateKey, msg []byte, sig
func (o *OptimizedSLHDSA) signWithSIMD(sk *PrivateKey, msg []byte, sig []byte, cache []byte, n, w, h, d int) { func (o *OptimizedSLHDSA) signWithSIMD(sk *PrivateKey, msg []byte, sig []byte, cache []byte, n, w, h, d int) {
// SIMD-accelerated signing // SIMD-accelerated signing
// Uses vector instructions for parallel hash computations // Uses vector instructions for parallel hash computations
// This would call assembly implementations for different architectures // This would call assembly implementations for different architectures
switch runtime.GOARCH { switch runtime.GOARCH {
case "amd64": case "amd64":
@@ -179,11 +179,11 @@ func (o *OptimizedSLHDSA) OptimizedVerify(publicKey *PublicKey, message []byte,
// Acquire worker slot // Acquire worker slot
o.workerPool <- struct{}{} o.workerPool <- struct{}{}
defer func() { <-o.workerPool }() defer func() { <-o.workerPool }()
// Get cache buffer from pool // Get cache buffer from pool
cache := o.cachePool.Get().([]byte) cache := o.cachePool.Get().([]byte)
defer o.cachePool.Put(cache) defer o.cachePool.Put(cache)
// Parallel verification of Merkle paths // Parallel verification of Merkle paths
return o.verifyOptimized(publicKey, message, signature, cache) return o.verifyOptimized(publicKey, message, signature, cache)
} }
@@ -240,28 +240,28 @@ func (o *OptimizedSLHDSA) RunBenchmark(config BenchmarkConfig) BenchmarkResult {
sk, _ := GenerateKey(rand.Reader, config.Mode) sk, _ := GenerateKey(rand.Reader, config.Mode)
pk := &sk.PublicKey pk := &sk.PublicKey
message := make([]byte, config.MessageSize) message := make([]byte, config.MessageSize)
// Benchmark signing // Benchmark signing
startSign := nanotime() startSign := nanotime()
for i := 0; i < config.Iterations; i++ { for i := 0; i < config.Iterations; i++ {
o.OptimizedSign(sk, message) o.OptimizedSign(sk, message)
} }
result.SignTime = (nanotime() - startSign) / int64(config.Iterations) result.SignTime = (nanotime() - startSign) / int64(config.Iterations)
// Generate signature for verification benchmark // Generate signature for verification benchmark
sig, _ := o.OptimizedSign(sk, message) sig, _ := o.OptimizedSign(sk, message)
// Benchmark verification // Benchmark verification
startVerify := nanotime() startVerify := nanotime()
for i := 0; i < config.Iterations; i++ { for i := 0; i < config.Iterations; i++ {
o.OptimizedVerify(pk, message, sig) o.OptimizedVerify(pk, message, sig)
} }
result.VerifyTime = (nanotime() - startVerify) / int64(config.Iterations) result.VerifyTime = (nanotime() - startVerify) / int64(config.Iterations)
// Calculate operations per second // Calculate operations per second
result.SignOpsPerSec = 1e9 / float64(result.SignTime) result.SignOpsPerSec = 1e9 / float64(result.SignTime)
result.VerifyOpsPerSec = 1e9 / float64(result.VerifyTime) result.VerifyOpsPerSec = 1e9 / float64(result.VerifyTime)
return result return result
} }
@@ -269,8 +269,8 @@ func (o *OptimizedSLHDSA) RunBenchmark(config BenchmarkConfig) BenchmarkResult {
type BenchmarkResult struct { type BenchmarkResult struct {
Mode Mode Mode Mode
MessageSize int MessageSize int
SignTime int64 // nanoseconds SignTime int64 // nanoseconds
VerifyTime int64 // nanoseconds VerifyTime int64 // nanoseconds
SignOpsPerSec float64 SignOpsPerSec float64
VerifyOpsPerSec float64 VerifyOpsPerSec float64
} }
@@ -285,10 +285,10 @@ func nanotime() int64 {
var ( var (
// Precomputed hash chains for common operations // Precomputed hash chains for common operations
precomputedChains = make(map[Mode][]byte) precomputedChains = make(map[Mode][]byte)
// Lookup tables for Winternitz chains // Lookup tables for Winternitz chains
winternitzTables = make(map[Mode][][]byte) winternitzTables = make(map[Mode][][]byte)
// Once ensures precomputation happens only once // Once ensures precomputation happens only once
precomputeOnce sync.Once precomputeOnce sync.Once
) )
@@ -298,11 +298,11 @@ func InitPrecomputation() {
precomputeOnce.Do(func() { precomputeOnce.Do(func() {
// Precompute for each mode // Precompute for each mode
modes := []Mode{SLHDSA128f, SLHDSA128s, SLHDSA192f, SLHDSA192s, SLHDSA256f, SLHDSA256s} modes := []Mode{SLHDSA128f, SLHDSA128s, SLHDSA192f, SLHDSA192s, SLHDSA256f, SLHDSA256s}
for _, mode := range modes { for _, mode := range modes {
// Precompute hash chains // Precompute hash chains
precomputeHashChains(mode) precomputeHashChains(mode)
// Precompute Winternitz tables // Precompute Winternitz tables
precomputeWinternitz(mode) precomputeWinternitz(mode)
} }
@@ -321,4 +321,4 @@ func precomputeWinternitz(mode Mode) {
// Placeholder for Winternitz precomputation // Placeholder for Winternitz precomputation
// Real implementation would compute chain values // Real implementation would compute chain values
winternitzTables[mode] = make([][]byte, 16) winternitzTables[mode] = make([][]byte, 16)
} }
+44 -44
View File
@@ -18,14 +18,14 @@ func TestOptimizedPerformance(t *testing.T) {
SLHDSA256f, SLHDSA256f,
SLHDSA256s, SLHDSA256s,
} }
// Initialize precomputation tables // Initialize precomputation tables
InitPrecomputation() InitPrecomputation()
for _, mode := range modes { for _, mode := range modes {
t.Run(fmt.Sprintf("Mode_%v", mode), func(t *testing.T) { t.Run(fmt.Sprintf("Mode_%v", mode), func(t *testing.T) {
opt := NewOptimized(mode) opt := NewOptimized(mode)
// Generate test key pair // Generate test key pair
priv, err := GenerateKey(rand.Reader, mode) priv, err := GenerateKey(rand.Reader, mode)
if err != nil { if err != nil {
@@ -33,21 +33,21 @@ func TestOptimizedPerformance(t *testing.T) {
} }
sk := priv sk := priv
pk := &priv.PublicKey pk := &priv.PublicKey
message := []byte("Test message for optimization benchmarks") message := []byte("Test message for optimization benchmarks")
// Test optimized signing // Test optimized signing
sig, err := opt.OptimizedSign(sk, message) sig, err := opt.OptimizedSign(sk, message)
if err != nil { if err != nil {
t.Fatalf("Optimized signing failed: %v", err) t.Fatalf("Optimized signing failed: %v", err)
} }
// Test optimized verification // Test optimized verification
valid := opt.OptimizedVerify(pk, message, sig) valid := opt.OptimizedVerify(pk, message, sig)
if !valid { if !valid {
t.Error("Optimized verification failed") t.Error("Optimized verification failed")
} }
// Verify signature size // Verify signature size
expectedSize := opt.getSignatureSize() expectedSize := opt.getSignatureSize()
if len(sig) != expectedSize { if len(sig) != expectedSize {
@@ -70,15 +70,15 @@ func BenchmarkOptimizedSigning(b *testing.B) {
{SLHDSA256f, "256f"}, {SLHDSA256f, "256f"},
{SLHDSA256s, "256s"}, {SLHDSA256s, "256s"},
} }
InitPrecomputation() InitPrecomputation()
message := make([]byte, 32) message := make([]byte, 32)
for _, bm := range benchmarks { for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) { b.Run(bm.name, func(b *testing.B) {
opt := NewOptimized(bm.mode) opt := NewOptimized(bm.mode)
sk, _ := GenerateKey(rand.Reader, bm.mode) sk, _ := GenerateKey(rand.Reader, bm.mode)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
opt.OptimizedSign(sk, message) opt.OptimizedSign(sk, message)
@@ -100,10 +100,10 @@ func BenchmarkOptimizedVerification(b *testing.B) {
{SLHDSA256f, "256f"}, {SLHDSA256f, "256f"},
{SLHDSA256s, "256s"}, {SLHDSA256s, "256s"},
} }
InitPrecomputation() InitPrecomputation()
message := make([]byte, 32) message := make([]byte, 32)
for _, bm := range benchmarks { for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) { b.Run(bm.name, func(b *testing.B) {
opt := NewOptimized(bm.mode) opt := NewOptimized(bm.mode)
@@ -111,7 +111,7 @@ func BenchmarkOptimizedVerification(b *testing.B) {
sk := priv sk := priv
pk := &priv.PublicKey pk := &priv.PublicKey
sig, _ := opt.OptimizedSign(sk, message) sig, _ := opt.OptimizedSign(sk, message)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
opt.OptimizedVerify(pk, message, sig) opt.OptimizedVerify(pk, message, sig)
@@ -135,11 +135,11 @@ func BenchmarkComparison(b *testing.B) {
// Verify is not needed in benchmark // Verify is not needed in benchmark
} }
}) })
b.Run("Optimized", func(b *testing.B) { b.Run("Optimized", func(b *testing.B) {
opt := NewOptimized(mode) opt := NewOptimized(mode)
InitPrecomputation() InitPrecomputation()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
sig, _ := opt.OptimizedSign(sk, message) sig, _ := opt.OptimizedSign(sk, message)
@@ -158,33 +158,33 @@ func TestParallelPerformance(t *testing.T) {
sk := priv sk := priv
pk := &priv.PublicKey pk := &priv.PublicKey
message := make([]byte, 32) message := make([]byte, 32)
// Test different CPU counts // Test different CPU counts
cpuCounts := []int{1, 2, 4, 8} cpuCounts := []int{1, 2, 4, 8}
for _, cpus := range cpuCounts { for _, cpus := range cpuCounts {
if cpus > runtime.NumCPU() { if cpus > runtime.NumCPU() {
continue continue
} }
t.Run(fmt.Sprintf("CPUs_%d", cpus), func(t *testing.T) { t.Run(fmt.Sprintf("CPUs_%d", cpus), func(t *testing.T) {
runtime.GOMAXPROCS(cpus) runtime.GOMAXPROCS(cpus)
start := time.Now() start := time.Now()
iterations := 100 iterations := 100
for i := 0; i < iterations; i++ { for i := 0; i < iterations; i++ {
sig, _ := opt.OptimizedSign(sk, message) sig, _ := opt.OptimizedSign(sk, message)
opt.OptimizedVerify(pk, message, sig) opt.OptimizedVerify(pk, message, sig)
} }
elapsed := time.Since(start) elapsed := time.Since(start)
opsPerSec := float64(iterations) / elapsed.Seconds() opsPerSec := float64(iterations) / elapsed.Seconds()
t.Logf("CPUs: %d, Ops/sec: %.2f", cpus, opsPerSec) t.Logf("CPUs: %d, Ops/sec: %.2f", cpus, opsPerSec)
}) })
} }
// Reset to default // Reset to default
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
} }
@@ -192,7 +192,7 @@ func TestParallelPerformance(t *testing.T) {
// TestMemoryUsage tests memory efficiency of optimizations // TestMemoryUsage tests memory efficiency of optimizations
func TestMemoryUsage(t *testing.T) { func TestMemoryUsage(t *testing.T) {
modes := []Mode{SLHDSA128f, SLHDSA128s} modes := []Mode{SLHDSA128f, SLHDSA128s}
for _, mode := range modes { for _, mode := range modes {
t.Run(fmt.Sprintf("Mode_%v", mode), func(t *testing.T) { t.Run(fmt.Sprintf("Mode_%v", mode), func(t *testing.T) {
opt := NewOptimized(mode) opt := NewOptimized(mode)
@@ -200,22 +200,22 @@ func TestMemoryUsage(t *testing.T) {
sk := priv sk := priv
pk := &priv.PublicKey pk := &priv.PublicKey
message := make([]byte, 32) message := make([]byte, 32)
// Measure memory allocations // Measure memory allocations
var m1, m2 runtime.MemStats var m1, m2 runtime.MemStats
runtime.ReadMemStats(&m1) runtime.ReadMemStats(&m1)
// Perform multiple operations // Perform multiple operations
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
sig, _ := opt.OptimizedSign(sk, message) sig, _ := opt.OptimizedSign(sk, message)
opt.OptimizedVerify(pk, message, sig) opt.OptimizedVerify(pk, message, sig)
} }
runtime.ReadMemStats(&m2) runtime.ReadMemStats(&m2)
allocations := m2.Alloc - m1.Alloc allocations := m2.Alloc - m1.Alloc
t.Logf("Memory allocated: %d bytes", allocations) t.Logf("Memory allocated: %d bytes", allocations)
// Check that we're using the pool effectively // Check that we're using the pool effectively
if allocations > 10*1024*1024 { // 10MB threshold if allocations > 10*1024*1024 { // 10MB threshold
t.Logf("Warning: High memory usage detected") t.Logf("Warning: High memory usage detected")
@@ -227,30 +227,30 @@ func TestMemoryUsage(t *testing.T) {
// TestSIMDDetection tests SIMD detection and fallback // TestSIMDDetection tests SIMD detection and fallback
func TestSIMDDetection(t *testing.T) { func TestSIMDDetection(t *testing.T) {
opt := NewOptimized(SLHDSA128f) opt := NewOptimized(SLHDSA128f)
t.Logf("Architecture: %s", runtime.GOARCH) t.Logf("Architecture: %s", runtime.GOARCH)
t.Logf("SIMD Enabled: %v", opt.simdEnable) t.Logf("SIMD Enabled: %v", opt.simdEnable)
// Test that both paths work // Test that both paths work
priv, _ := GenerateKey(rand.Reader, SLHDSA128f) priv, _ := GenerateKey(rand.Reader, SLHDSA128f)
sk := priv sk := priv
pk := &priv.PublicKey pk := &priv.PublicKey
message := []byte("Test message") message := []byte("Test message")
// Force SIMD path // Force SIMD path
opt.simdEnable = true opt.simdEnable = true
sig1, err := opt.OptimizedSign(sk, message) sig1, err := opt.OptimizedSign(sk, message)
if err != nil { if err != nil {
t.Fatalf("SIMD signing failed: %v", err) t.Fatalf("SIMD signing failed: %v", err)
} }
// Force non-SIMD path // Force non-SIMD path
opt.simdEnable = false opt.simdEnable = false
sig2, err := opt.OptimizedSign(sk, message) sig2, err := opt.OptimizedSign(sk, message)
if err != nil { if err != nil {
t.Fatalf("Non-SIMD signing failed: %v", err) t.Fatalf("Non-SIMD signing failed: %v", err)
} }
// Both should verify // Both should verify
if !opt.OptimizedVerify(pk, message, sig1) { if !opt.OptimizedVerify(pk, message, sig1) {
t.Error("SIMD signature verification failed") t.Error("SIMD signature verification failed")
@@ -270,7 +270,7 @@ func TestOptimizationMetrics(t *testing.T) {
} }
InitPrecomputation() InitPrecomputation()
configs := []BenchmarkConfig{ configs := []BenchmarkConfig{
{Mode: SLHDSA128f, MessageSize: 32, Iterations: 100, Parallel: true}, {Mode: SLHDSA128f, MessageSize: 32, Iterations: 100, Parallel: true},
{Mode: SLHDSA128s, MessageSize: 32, Iterations: 100, Parallel: true}, {Mode: SLHDSA128s, MessageSize: 32, Iterations: 100, Parallel: true},
@@ -279,18 +279,18 @@ func TestOptimizationMetrics(t *testing.T) {
{Mode: SLHDSA256f, MessageSize: 32, Iterations: 25, Parallel: true}, {Mode: SLHDSA256f, MessageSize: 32, Iterations: 25, Parallel: true},
{Mode: SLHDSA256s, MessageSize: 32, Iterations: 25, Parallel: true}, {Mode: SLHDSA256s, MessageSize: 32, Iterations: 25, Parallel: true},
} }
t.Log("=== SLH-DSA Optimization Metrics ===") t.Log("=== SLH-DSA Optimization Metrics ===")
t.Log("Mode\t\tSign(ms)\tVerify(ms)\tSign Ops/s\tVerify Ops/s") t.Log("Mode\t\tSign(ms)\tVerify(ms)\tSign Ops/s\tVerify Ops/s")
t.Log("----\t\t--------\t----------\t----------\t------------") t.Log("----\t\t--------\t----------\t----------\t------------")
for _, config := range configs { for _, config := range configs {
opt := NewOptimized(config.Mode) opt := NewOptimized(config.Mode)
result := opt.RunBenchmark(config) result := opt.RunBenchmark(config)
signMs := float64(result.SignTime) / 1e6 signMs := float64(result.SignTime) / 1e6
verifyMs := float64(result.VerifyTime) / 1e6 verifyMs := float64(result.VerifyTime) / 1e6
t.Logf("%v\t\t%.2f\t\t%.2f\t\t%.0f\t\t%.0f", t.Logf("%v\t\t%.2f\t\t%.2f\t\t%.0f\t\t%.0f",
config.Mode, config.Mode,
signMs, signMs,
@@ -304,22 +304,22 @@ func TestOptimizationMetrics(t *testing.T) {
func ExampleOptimizedSLHDSA() { func ExampleOptimizedSLHDSA() {
// Initialize precomputed tables for best performance // Initialize precomputed tables for best performance
InitPrecomputation() InitPrecomputation()
// Create optimized instance // Create optimized instance
opt := NewOptimized(SLHDSA128f) opt := NewOptimized(SLHDSA128f)
// Generate keys // Generate keys
priv, _ := GenerateKey(rand.Reader, SLHDSA128f) priv, _ := GenerateKey(rand.Reader, SLHDSA128f)
sk := priv sk := priv
pk := &priv.PublicKey pk := &priv.PublicKey
// Sign message with optimizations // Sign message with optimizations
message := []byte("Hello, Post-Quantum World!") message := []byte("Hello, Post-Quantum World!")
signature, _ := opt.OptimizedSign(sk, message) signature, _ := opt.OptimizedSign(sk, message)
// Verify with optimizations // Verify with optimizations
valid := opt.OptimizedVerify(pk, message, signature) valid := opt.OptimizedVerify(pk, message, signature)
fmt.Printf("Signature valid: %v\n", valid) fmt.Printf("Signature valid: %v\n", valid)
fmt.Printf("Signature size: %d bytes\n", len(signature)) fmt.Printf("Signature size: %d bytes\n", len(signature))
// Output: // Output:
+15 -15
View File
@@ -8,11 +8,11 @@ import (
func TestSLHDSAKeyGeneration(t *testing.T) { func TestSLHDSAKeyGeneration(t *testing.T) {
modes := []struct { modes := []struct {
name string name string
mode Mode mode Mode
pubSize int pubSize int
privSize int privSize int
sigSize int sigSize int
}{ }{
{"SLH-DSA-128s", SLHDSA128s, SLHDSA128sPublicKeySize, SLHDSA128sPrivateKeySize, SLHDSA128sSignatureSize}, {"SLH-DSA-128s", SLHDSA128s, SLHDSA128sPublicKeySize, SLHDSA128sPrivateKeySize, SLHDSA128sSignatureSize},
{"SLH-DSA-128f", SLHDSA128f, SLHDSA128fPublicKeySize, SLHDSA128fPrivateKeySize, SLHDSA128fSignatureSize}, {"SLH-DSA-128f", SLHDSA128f, SLHDSA128fPublicKeySize, SLHDSA128fPrivateKeySize, SLHDSA128fSignatureSize},
@@ -67,7 +67,7 @@ func TestSLHDSASignVerify(t *testing.T) {
} }
message := []byte("Test message for SLH-DSA signature") message := []byte("Test message for SLH-DSA signature")
// Sign message // Sign message
signature, err := privKey.Sign(rand.Reader, message, nil) signature, err := privKey.Sign(rand.Reader, message, nil)
if err != nil { if err != nil {
@@ -142,7 +142,7 @@ func TestSLHDSADeterministicSignature(t *testing.T) {
} }
message := []byte("Deterministic signature test") message := []byte("Deterministic signature test")
// Sign same message multiple times // Sign same message multiple times
sig1, err := privKey.Sign(nil, message, nil) // nil rand for deterministic sig1, err := privKey.Sign(nil, message, nil) // nil rand for deterministic
if err != nil { if err != nil {
@@ -320,12 +320,12 @@ func TestSLHDSAConcurrency(t *testing.T) {
} }
message := []byte("Concurrent test message") message := []byte("Concurrent test message")
// Test concurrent signing // Test concurrent signing
t.Run("ConcurrentSign", func(t *testing.T) { t.Run("ConcurrentSign", func(t *testing.T) {
const numGoroutines = 10 const numGoroutines = 10
done := make(chan bool, numGoroutines) done := make(chan bool, numGoroutines)
for i := 0; i < numGoroutines; i++ { for i := 0; i < numGoroutines; i++ {
go func(id int) { go func(id int) {
msg := append(message, byte(id)) msg := append(message, byte(id))
@@ -340,7 +340,7 @@ func TestSLHDSAConcurrency(t *testing.T) {
done <- true done <- true
}(i) }(i)
} }
for i := 0; i < numGoroutines; i++ { for i := 0; i < numGoroutines; i++ {
<-done <-done
} }
@@ -351,7 +351,7 @@ func TestSLHDSAConcurrency(t *testing.T) {
signature, _ := privKey.Sign(rand.Reader, message, nil) signature, _ := privKey.Sign(rand.Reader, message, nil)
const numGoroutines = 10 const numGoroutines = 10
done := make(chan bool, numGoroutines) done := make(chan bool, numGoroutines)
for i := 0; i < numGoroutines; i++ { for i := 0; i < numGoroutines; i++ {
go func(id int) { go func(id int) {
valid := privKey.PublicKey.Verify(message, signature, nil) valid := privKey.PublicKey.Verify(message, signature, nil)
@@ -361,7 +361,7 @@ func TestSLHDSAConcurrency(t *testing.T) {
done <- true done <- true
}(i) }(i)
} }
for i := 0; i < numGoroutines; i++ { for i := 0; i < numGoroutines; i++ {
<-done <-done
} }
@@ -432,7 +432,7 @@ func BenchmarkSLHDSASign(b *testing.B) {
for _, m := range modes { for _, m := range modes {
privKey, _ := GenerateKey(rand.Reader, m.mode) privKey, _ := GenerateKey(rand.Reader, m.mode)
b.Run(m.name, func(b *testing.B) { b.Run(m.name, func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -463,7 +463,7 @@ func BenchmarkSLHDSAVerify(b *testing.B) {
for _, m := range modes { for _, m := range modes {
privKey, _ := GenerateKey(rand.Reader, m.mode) privKey, _ := GenerateKey(rand.Reader, m.mode)
signature, _ := privKey.Sign(rand.Reader, message, nil) signature, _ := privKey.Sign(rand.Reader, message, nil)
b.Run(m.name, func(b *testing.B) { b.Run(m.name, func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -474,4 +474,4 @@ func BenchmarkSLHDSAVerify(b *testing.B) {
} }
}) })
} }
} }
+28 -28
View File
@@ -79,7 +79,7 @@ func NewMerkleTree(height int) *MerkleTree {
for i := range nodes { for i := range nodes {
nodes[i] = make([]byte, 32) nodes[i] = make([]byte, 32)
} }
return &MerkleTree{ return &MerkleTree{
nodes: nodes, nodes: nodes,
height: height, height: height,
@@ -90,30 +90,30 @@ func NewMerkleTree(height int) *MerkleTree {
func (mt *MerkleTree) ComputeRoot(leaves [][]byte) []byte { func (mt *MerkleTree) ComputeRoot(leaves [][]byte) []byte {
mt.mu.Lock() mt.mu.Lock()
defer mt.mu.Unlock() defer mt.mu.Unlock()
// Copy leaves to bottom level // Copy leaves to bottom level
leafStart := len(mt.nodes) - len(leaves) leafStart := len(mt.nodes) - len(leaves)
for i, leaf := range leaves { for i, leaf := range leaves {
copy(mt.nodes[leafStart+i], leaf) copy(mt.nodes[leafStart+i], leaf)
} }
// Compute internal nodes // Compute internal nodes
h := sha256.New() h := sha256.New()
for level := mt.height - 1; level >= 0; level-- { for level := mt.height - 1; level >= 0; level-- {
levelStart := (1 << level) - 1 levelStart := (1 << level) - 1
levelSize := 1 << level levelSize := 1 << level
for i := 0; i < levelSize; i++ { for i := 0; i < levelSize; i++ {
leftChild := mt.nodes[2*(levelStart+i)+1] leftChild := mt.nodes[2*(levelStart+i)+1]
rightChild := mt.nodes[2*(levelStart+i)+2] rightChild := mt.nodes[2*(levelStart+i)+2]
h.Reset() h.Reset()
h.Write(leftChild) h.Write(leftChild)
h.Write(rightChild) h.Write(rightChild)
copy(mt.nodes[levelStart+i], h.Sum(nil)) copy(mt.nodes[levelStart+i], h.Sum(nil))
} }
} }
return mt.nodes[0] return mt.nodes[0]
} }
@@ -129,13 +129,13 @@ func NewParallelSLHDSA(mode Mode, numKeys, workers int) (*ParallelSLHDSA, error)
if workers <= 0 { if workers <= 0 {
workers = 4 // Default worker count workers = 4 // Default worker count
} }
keys := make([]*PrivateKey, numKeys) keys := make([]*PrivateKey, numKeys)
// Generate keys in parallel // Generate keys in parallel
var wg sync.WaitGroup var wg sync.WaitGroup
errors := make([]error, numKeys) errors := make([]error, numKeys)
for i := range keys { for i := range keys {
wg.Add(1) wg.Add(1)
go func(idx int) { go func(idx int) {
@@ -148,16 +148,16 @@ func NewParallelSLHDSA(mode Mode, numKeys, workers int) (*ParallelSLHDSA, error)
keys[idx] = key keys[idx] = key
}(i) }(i)
} }
wg.Wait() wg.Wait()
// Check for errors // Check for errors
for _, err := range errors { for _, err := range errors {
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
return &ParallelSLHDSA{ return &ParallelSLHDSA{
keys: keys, keys: keys,
workers: workers, workers: workers,
@@ -169,20 +169,20 @@ func (p *ParallelSLHDSA) SignMessages(messages [][]byte) ([][]byte, error) {
if len(messages) > len(p.keys) { if len(messages) > len(p.keys) {
return nil, errors.New("not enough keys for messages") return nil, errors.New("not enough keys for messages")
} }
signatures := make([][]byte, len(messages)) signatures := make([][]byte, len(messages))
// Create work channel // Create work channel
work := make(chan int, len(messages)) work := make(chan int, len(messages))
for i := range messages { for i := range messages {
work <- i work <- i
} }
close(work) close(work)
// Start workers // Start workers
var wg sync.WaitGroup var wg sync.WaitGroup
errors := make([]error, len(messages)) errors := make([]error, len(messages))
for w := 0; w < p.workers; w++ { for w := 0; w < p.workers; w++ {
wg.Add(1) wg.Add(1)
go func() { go func() {
@@ -197,25 +197,25 @@ func (p *ParallelSLHDSA) SignMessages(messages [][]byte) ([][]byte, error) {
} }
}() }()
} }
wg.Wait() wg.Wait()
// Check for errors // Check for errors
for _, err := range errors { for _, err := range errors {
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
return signatures, nil return signatures, nil
} }
// CachedSLHDSA caches intermediate computations // CachedSLHDSA caches intermediate computations
type CachedSLHDSA struct { type CachedSLHDSA struct {
privKey *PrivateKey privKey *PrivateKey
treeCache map[string]*MerkleTree treeCache map[string]*MerkleTree
hashCache map[string][]byte hashCache map[string][]byte
mu sync.RWMutex mu sync.RWMutex
} }
// NewCachedSLHDSA creates a cached SLH-DSA instance // NewCachedSLHDSA creates a cached SLH-DSA instance
@@ -234,7 +234,7 @@ func (c *CachedSLHDSA) SignWithCache(message []byte) ([]byte, error) {
h.Write(message) h.Write(message)
msgHash := h.Sum(nil) msgHash := h.Sum(nil)
cacheKey := string(msgHash[:16]) // Use first 16 bytes as key cacheKey := string(msgHash[:16]) // Use first 16 bytes as key
// Check cache // Check cache
c.mu.RLock() c.mu.RLock()
if sig, ok := c.hashCache[cacheKey]; ok { if sig, ok := c.hashCache[cacheKey]; ok {
@@ -242,13 +242,13 @@ func (c *CachedSLHDSA) SignWithCache(message []byte) ([]byte, error) {
return sig, nil return sig, nil
} }
c.mu.RUnlock() c.mu.RUnlock()
// Sign and cache // Sign and cache
sig, err := c.privKey.Sign(rand.Reader, message, nil) sig, err := c.privKey.Sign(rand.Reader, message, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
c.mu.Lock() c.mu.Lock()
c.hashCache[cacheKey] = sig c.hashCache[cacheKey] = sig
// Limit cache size // Limit cache size
@@ -262,6 +262,6 @@ func (c *CachedSLHDSA) SignWithCache(message []byte) ([]byte, error) {
} }
} }
c.mu.Unlock() c.mu.Unlock()
return sig, nil return sig, nil
} }
+11 -11
View File
@@ -7,7 +7,7 @@ import (
"crypto" "crypto"
"crypto/rand" "crypto/rand"
"fmt" "fmt"
"github.com/luxfi/crypto/bls" "github.com/luxfi/crypto/bls"
"github.com/luxfi/crypto/mldsa" "github.com/luxfi/crypto/mldsa"
) )
@@ -25,18 +25,18 @@ func NewSimpleSigner() (*SimpleSigner, error) {
if _, err := rand.Read(seed); err != nil { if _, err := rand.Read(seed); err != nil {
return nil, err return nil, err
} }
blsKey, err := bls.SecretKeyFromBytes(seed) blsKey, err := bls.SecretKeyFromBytes(seed)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Generate ML-DSA key // Generate ML-DSA key
mldsaKey, err := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65) mldsaKey, err := mldsa.GenerateKey(rand.Reader, mldsa.MLDSA65)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &SimpleSigner{ return &SimpleSigner{
blsKey: blsKey, blsKey: blsKey,
mldsaKey: mldsaKey, mldsaKey: mldsaKey,
@@ -79,19 +79,19 @@ func (s *SimpleSigner) SignHybrid(message []byte) ([]byte, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("BLS sign failed: %w", err) return nil, fmt.Errorf("BLS sign failed: %w", err)
} }
mldsaSig, err := s.SignMLDSA(message) mldsaSig, err := s.SignMLDSA(message)
if err != nil { if err != nil {
return nil, fmt.Errorf("ML-DSA sign failed: %w", err) return nil, fmt.Errorf("ML-DSA sign failed: %w", err)
} }
// Combine: [2-byte BLS len][BLS sig][ML-DSA sig] // Combine: [2-byte BLS len][BLS sig][ML-DSA sig]
result := make([]byte, 2+len(blsSig)+len(mldsaSig)) result := make([]byte, 2+len(blsSig)+len(mldsaSig))
result[0] = byte(len(blsSig) >> 8) result[0] = byte(len(blsSig) >> 8)
result[1] = byte(len(blsSig)) result[1] = byte(len(blsSig))
copy(result[2:], blsSig) copy(result[2:], blsSig)
copy(result[2+len(blsSig):], mldsaSig) copy(result[2+len(blsSig):], mldsaSig)
return result, nil return result, nil
} }
@@ -100,15 +100,15 @@ func (s *SimpleSigner) VerifyHybrid(message, signature []byte) bool {
if len(signature) < 2 { if len(signature) < 2 {
return false return false
} }
blsLen := int(signature[0])<<8 | int(signature[1]) blsLen := int(signature[0])<<8 | int(signature[1])
if len(signature) < 2+blsLen { if len(signature) < 2+blsLen {
return false return false
} }
blsSig := signature[2 : 2+blsLen] blsSig := signature[2 : 2+blsLen]
mldsaSig := signature[2+blsLen:] mldsaSig := signature[2+blsLen:]
return s.VerifyBLS(message, blsSig) && s.VerifyMLDSA(message, mldsaSig) return s.VerifyBLS(message, blsSig) && s.VerifyMLDSA(message, mldsaSig)
} }
@@ -121,4 +121,4 @@ func (s *SimpleSigner) GetBLSPublicKey() []byte {
// GetMLDSAPublicKey returns the ML-DSA public key // GetMLDSAPublicKey returns the ML-DSA public key
func (s *SimpleSigner) GetMLDSAPublicKey() []byte { func (s *SimpleSigner) GetMLDSAPublicKey() []byte {
return s.mldsaKey.PublicKey.Bytes() return s.mldsaKey.PublicKey.Bytes()
} }
+21 -21
View File
@@ -9,59 +9,59 @@ func TestSimpleSigner(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to create signer: %v", err) t.Fatalf("Failed to create signer: %v", err)
} }
message := []byte("Test message for unified signing") message := []byte("Test message for unified signing")
t.Run("BLS", func(t *testing.T) { t.Run("BLS", func(t *testing.T) {
sig, err := signer.SignBLS(message) sig, err := signer.SignBLS(message)
if err != nil { if err != nil {
t.Fatalf("BLS sign failed: %v", err) t.Fatalf("BLS sign failed: %v", err)
} }
if !signer.VerifyBLS(message, sig) { if !signer.VerifyBLS(message, sig) {
t.Fatalf("BLS verification failed") t.Fatalf("BLS verification failed")
} }
if signer.VerifyBLS([]byte("wrong"), sig) { if signer.VerifyBLS([]byte("wrong"), sig) {
t.Fatalf("BLS should not verify wrong message") t.Fatalf("BLS should not verify wrong message")
} }
t.Logf("BLS signature size: %d bytes", len(sig)) t.Logf("BLS signature size: %d bytes", len(sig))
t.Logf("BLS public key size: %d bytes", len(signer.GetBLSPublicKey())) t.Logf("BLS public key size: %d bytes", len(signer.GetBLSPublicKey()))
}) })
t.Run("ML-DSA", func(t *testing.T) { t.Run("ML-DSA", func(t *testing.T) {
sig, err := signer.SignMLDSA(message) sig, err := signer.SignMLDSA(message)
if err != nil { if err != nil {
t.Fatalf("ML-DSA sign failed: %v", err) t.Fatalf("ML-DSA sign failed: %v", err)
} }
if !signer.VerifyMLDSA(message, sig) { if !signer.VerifyMLDSA(message, sig) {
t.Fatalf("ML-DSA verification failed") t.Fatalf("ML-DSA verification failed")
} }
if signer.VerifyMLDSA([]byte("wrong"), sig) { if signer.VerifyMLDSA([]byte("wrong"), sig) {
t.Fatalf("ML-DSA should not verify wrong message") t.Fatalf("ML-DSA should not verify wrong message")
} }
t.Logf("ML-DSA signature size: %d bytes", len(sig)) t.Logf("ML-DSA signature size: %d bytes", len(sig))
t.Logf("ML-DSA public key size: %d bytes", len(signer.GetMLDSAPublicKey())) t.Logf("ML-DSA public key size: %d bytes", len(signer.GetMLDSAPublicKey()))
}) })
t.Run("Hybrid", func(t *testing.T) { t.Run("Hybrid", func(t *testing.T) {
sig, err := signer.SignHybrid(message) sig, err := signer.SignHybrid(message)
if err != nil { if err != nil {
t.Fatalf("Hybrid sign failed: %v", err) t.Fatalf("Hybrid sign failed: %v", err)
} }
if !signer.VerifyHybrid(message, sig) { if !signer.VerifyHybrid(message, sig) {
t.Fatalf("Hybrid verification failed") t.Fatalf("Hybrid verification failed")
} }
if signer.VerifyHybrid([]byte("wrong"), sig) { if signer.VerifyHybrid([]byte("wrong"), sig) {
t.Fatalf("Hybrid should not verify wrong message") t.Fatalf("Hybrid should not verify wrong message")
} }
t.Logf("Hybrid signature size: %d bytes", len(sig)) t.Logf("Hybrid signature size: %d bytes", len(sig))
}) })
} }
@@ -71,9 +71,9 @@ func BenchmarkSimpleSigner(b *testing.B) {
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
message := []byte("Benchmark message for performance testing") message := []byte("Benchmark message for performance testing")
b.Run("BLS_Sign", func(b *testing.B) { b.Run("BLS_Sign", func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -83,7 +83,7 @@ func BenchmarkSimpleSigner(b *testing.B) {
} }
} }
}) })
blsSig, _ := signer.SignBLS(message) blsSig, _ := signer.SignBLS(message)
b.Run("BLS_Verify", func(b *testing.B) { b.Run("BLS_Verify", func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
@@ -93,7 +93,7 @@ func BenchmarkSimpleSigner(b *testing.B) {
} }
} }
}) })
b.Run("MLDSA_Sign", func(b *testing.B) { b.Run("MLDSA_Sign", func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -103,7 +103,7 @@ func BenchmarkSimpleSigner(b *testing.B) {
} }
} }
}) })
mldsaSig, _ := signer.SignMLDSA(message) mldsaSig, _ := signer.SignMLDSA(message)
b.Run("MLDSA_Verify", func(b *testing.B) { b.Run("MLDSA_Verify", func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
@@ -113,7 +113,7 @@ func BenchmarkSimpleSigner(b *testing.B) {
} }
} }
}) })
b.Run("Hybrid_Sign", func(b *testing.B) { b.Run("Hybrid_Sign", func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@@ -123,7 +123,7 @@ func BenchmarkSimpleSigner(b *testing.B) {
} }
} }
}) })
hybridSig, _ := signer.SignHybrid(message) hybridSig, _ := signer.SignHybrid(message)
b.Run("Hybrid_Verify", func(b *testing.B) { b.Run("Hybrid_Verify", func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
@@ -133,4 +133,4 @@ func BenchmarkSimpleSigner(b *testing.B) {
} }
} }
}) })
} }
-1
View File
@@ -3,7 +3,6 @@
package bloom package bloom
// BloomFilter is the interface for bloom filter implementations that support // BloomFilter is the interface for bloom filter implementations that support
// adding and checking raw byte slices // adding and checking raw byte slices
type BloomFilter interface { type BloomFilter interface {
-1
View File
@@ -69,4 +69,3 @@ func getIndex(entries []byte, hash, seed uint64) uint64 {
} }
return index return index
} }
-1
View File
@@ -3,7 +3,6 @@
package bloom package bloom
import "math" import "math"
const ln2Squared = math.Ln2 * math.Ln2 const ln2Squared = math.Ln2 * math.Ln2
+5 -5
View File
@@ -21,10 +21,10 @@ const (
UnitTestID uint32 = 369 UnitTestID uint32 = 369
// Lux-specific network IDs // Lux-specific network IDs
LuxMainnetID uint32 = 96369 // Lux mainnet LuxMainnetID uint32 = 96369 // Lux mainnet
LuxTestnetID uint32 = 96370 // Lux testnet LuxTestnetID uint32 = 96370 // Lux testnet
QChainMainnetID uint32 = 96380 // Q-Chain mainnet QChainMainnetID uint32 = 96380 // Q-Chain mainnet
QChainTestnetID uint32 = 96381 // Q-Chain testnet QChainTestnetID uint32 = 96381 // Q-Chain testnet
LocalName = "local" LocalName = "local"
MainnetName = "mainnet" MainnetName = "mainnet"
@@ -42,7 +42,7 @@ const (
var ( var (
PrimaryNetworkID = ids.Empty PrimaryNetworkID = ids.Empty
PlatformChainID = ids.Empty PlatformChainID = ids.Empty
// Q-Chain specific IDs // Q-Chain specific IDs
QChainID = ids.ID{'q', 'c', 'h', 'a', 'i', 'n'} QChainID = ids.ID{'q', 'c', 'h', 'a', 'i', 'n'}
+10 -10
View File
@@ -6,19 +6,19 @@ package constants
import "github.com/luxfi/ids" import "github.com/luxfi/ids"
const ( const (
PlatformVMName = "platformvm" PlatformVMName = "platformvm"
XVMName = "xvm" XVMName = "xvm"
EVMName = "evm" EVMName = "evm"
XSVMName = "xsvm" XSVMName = "xsvm"
QVMName = "qvm" QVMName = "qvm"
) )
var ( var (
PlatformVMID = ids.ID{'p', 'l', 'a', 't', 'f', 'o', 'r', 'm', 'v', 'm'} PlatformVMID = ids.ID{'p', 'l', 'a', 't', 'f', 'o', 'r', 'm', 'v', 'm'}
XVMID = ids.ID{'a', 'v', 'm'} XVMID = ids.ID{'a', 'v', 'm'}
EVMID = ids.ID{'e', 'v', 'm'} EVMID = ids.ID{'e', 'v', 'm'}
XSVMID = ids.ID{'x', 's', 'v', 'm'} XSVMID = ids.ID{'x', 's', 'v', 'm'}
QVMID = ids.ID{'q', 'v', 'm'} QVMID = ids.ID{'q', 'v', 'm'}
) )
// VMName returns the name of the VM with the provided ID. If a human readable // VMName returns the name of the VM with the provided ID. If a human readable
+1 -1
View File
@@ -8,9 +8,9 @@ import (
"net/netip" "net/netip"
"time" "time"
"github.com/luxfi/log"
luxlog "github.com/luxfi/log" luxlog "github.com/luxfi/log"
"github.com/luxfi/node/utils" "github.com/luxfi/node/utils"
"github.com/luxfi/log"
) )
const ipResolutionTimeout = 10 * time.Second const ipResolutionTimeout = 10 * time.Second
+1 -1
View File
@@ -50,7 +50,7 @@ func NewClaimedIPPort(
Raw: cert.Raw, Raw: cert.Raw,
PublicKey: cert.PublicKey, PublicKey: cert.PublicKey,
} }
ip := &ClaimedIPPort{ ip := &ClaimedIPPort{
Cert: cert, Cert: cert,
AddrPort: ipPort, AddrPort: ipPort,
+2 -2
View File
@@ -34,11 +34,11 @@ func NewAveragerWithErrs(name, desc string, registry metric.Registry, errs *wrap
a := averager{ a := averager{
count: metricsInstance.NewCounter( count: metricsInstance.NewCounter(
AppendNamespace(name, "count"), AppendNamespace(name, "count"),
"Total # of observations of " + desc, "Total # of observations of "+desc,
), ),
sum: metricsInstance.NewGauge( sum: metricsInstance.NewGauge(
AppendNamespace(name, "sum"), AppendNamespace(name, "sum"),
"Sum of " + desc, "Sum of "+desc,
), ),
} }
+5 -5
View File
@@ -56,11 +56,11 @@ func newMetrics(registerer metric.Registerer) (*metricsImpl, error) {
), ),
} }
err := errors.Join( err := errors.Join(
// registerer.Register(m.numCPUCycles), // registerer.Register(m.numCPUCycles),
// registerer.Register(m.numDiskReads), // registerer.Register(m.numDiskReads),
// registerer.Register(m.numDiskReadBytes), // registerer.Register(m.numDiskReadBytes),
// registerer.Register(m.numDiskWrites), // registerer.Register(m.numDiskWrites),
// registerer.Register(m.numDiskWritesBytes), // registerer.Register(m.numDiskWritesBytes),
) )
return m, err return m, err
} }
+5 -5
View File
@@ -11,9 +11,9 @@ import (
) )
type mockReadCloser struct { type mockReadCloser struct {
reader io.Reader reader io.Reader
closed bool closed bool
readAll bool readAll bool
} }
func (m *mockReadCloser) Read(p []byte) (n int, err error) { func (m *mockReadCloser) Read(p []byte) (n int, err error) {
@@ -131,7 +131,7 @@ func TestCleanlyCloseBody_PartiallyReadBody(t *testing.T) {
func BenchmarkCleanlyCloseBody_Small(b *testing.B) { func BenchmarkCleanlyCloseBody_Small(b *testing.B) {
data := []byte("small response body") data := []byte("small response body")
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
mock := &mockReadCloser{ mock := &mockReadCloser{
@@ -144,7 +144,7 @@ func BenchmarkCleanlyCloseBody_Small(b *testing.B) {
func BenchmarkCleanlyCloseBody_Large(b *testing.B) { func BenchmarkCleanlyCloseBody_Large(b *testing.B) {
// 1MB response // 1MB response
data := bytes.Repeat([]byte("x"), 1024*1024) data := bytes.Repeat([]byte("x"), 1024*1024)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
mock := &mockReadCloser{ mock := &mockReadCloser{
+1 -1
View File
@@ -9,8 +9,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
consensustest "github.com/luxfi/consensus/test/helpers"
"github.com/luxfi/consensus/engine/chain/chaintest" "github.com/luxfi/consensus/engine/chain/chaintest"
consensustest "github.com/luxfi/consensus/test/helpers"
) )
func TestAcceptSingleBlock(t *testing.T) { func TestAcceptSingleBlock(t *testing.T) {
-1
View File
@@ -10,7 +10,6 @@ import (
"fmt" "fmt"
"syscall" "syscall"
"github.com/luxfi/log" "github.com/luxfi/log"
) )