Files
crypto/signer/signer_test.go
T

255 lines
6.9 KiB
Go

package signer
import (
"context"
"testing"
"github.com/luxfi/crypto/threshold"
_ "github.com/luxfi/crypto/threshold/bls" // Register BLS scheme
)
func TestSigner(t *testing.T) {
signer, err := NewSigner()
if err != nil {
t.Fatalf("Failed to create signer: %v", err)
}
message := []byte("Test message for Lux consensus signing")
t.Run("BLS", func(t *testing.T) {
sig, err := signer.SignBLS(message)
if err != nil {
t.Fatalf("BLS sign failed: %v", err)
}
if !signer.VerifyBLS(message, sig) {
t.Fatalf("BLS verification failed")
}
if signer.VerifyBLS([]byte("wrong"), sig) {
t.Fatalf("BLS should not verify wrong message")
}
t.Logf("BLS signature size: %d bytes", len(sig))
t.Logf("BLS public key size: %d bytes", len(signer.GetBLSPublicKey()))
})
t.Run("ThresholdSeed", func(t *testing.T) {
seed := signer.ThresholdSeed()
if len(seed) != 32 {
t.Fatalf("Threshold seed should be 32 bytes, got %d", len(seed))
}
t.Logf("Threshold seed: %x...", seed[:8])
})
t.Run("ThresholdNotInitialized", func(t *testing.T) {
if signer.HasThresholdKey() {
t.Fatal("Signer should not have threshold key initially")
}
if signer.ThresholdSchemeID() != threshold.SchemeUnknown {
t.Fatalf("Expected SchemeUnknown, got %v", signer.ThresholdSchemeID())
}
if signer.ThresholdIndex() != -1 {
t.Fatalf("Expected index -1, got %d", signer.ThresholdIndex())
}
if signer.ThresholdPublicShare() != nil {
t.Fatal("Expected nil public share")
}
if signer.ThresholdGroupKey() != nil {
t.Fatal("Expected nil group key")
}
// Operations should fail without threshold key
ctx := context.Background()
_, err := signer.SignThresholdShare(ctx, message, []int{0})
if err != threshold.ErrNotInitialized {
t.Fatalf("Expected ErrNotInitialized, got %v", err)
}
_, err = signer.AggregateThresholdShares(ctx, message, nil)
if err != threshold.ErrNotInitialized {
t.Fatalf("Expected ErrNotInitialized, got %v", err)
}
err = signer.VerifyThresholdShare(message, nil, nil)
if err != threshold.ErrNotInitialized {
t.Fatalf("Expected ErrNotInitialized, got %v", err)
}
if signer.VerifyThreshold(message, nil) {
t.Fatal("Expected false without threshold key")
}
if signer.VerifyThresholdBytes(message, nil) {
t.Fatal("Expected false without threshold key")
}
})
}
func TestSignerWithThreshold(t *testing.T) {
// Get BLS scheme
scheme, err := threshold.GetScheme(threshold.SchemeBLS)
if err != nil {
t.Fatalf("Failed to get BLS scheme: %v", err)
}
// Create key shares using trusted dealer
config := threshold.DealerConfig{
Threshold: 1, // 2-of-3
TotalParties: 3,
}
dealer, err := scheme.NewTrustedDealer(config)
if err != nil {
t.Fatalf("Failed to create dealer: %v", err)
}
ctx := context.Background()
shares, groupKey, err := dealer.GenerateShares(ctx)
if err != nil {
t.Fatalf("Failed to generate shares: %v", err)
}
// Create signers with threshold key shares
signers := make([]*Signer, len(shares))
for i, share := range shares {
signer, err := NewSignerWithThreshold(share)
if err != nil {
t.Fatalf("Failed to create signer %d: %v", i, err)
}
signers[i] = signer
}
t.Run("ThresholdKeyInfo", func(t *testing.T) {
for i, signer := range signers {
if !signer.HasThresholdKey() {
t.Fatalf("Signer %d should have threshold key", i)
}
if signer.ThresholdSchemeID() != threshold.SchemeBLS {
t.Fatalf("Signer %d: expected BLS, got %v", i, signer.ThresholdSchemeID())
}
if signer.ThresholdIndex() != i {
t.Fatalf("Signer %d: expected index %d, got %d", i, i, signer.ThresholdIndex())
}
if len(signer.ThresholdPublicShare()) == 0 {
t.Fatalf("Signer %d: empty public share", i)
}
if !signer.ThresholdGroupKey().Equal(groupKey) {
t.Fatalf("Signer %d: group key mismatch", i)
}
}
})
t.Run("ThresholdSigning", func(t *testing.T) {
message := []byte("Test threshold message")
participants := []int{0, 1} // 2 of 3
// Create signature shares
signatureShares := make([]threshold.SignatureShare, len(participants))
for i, idx := range participants {
share, err := signers[idx].SignThresholdShare(ctx, message, participants)
if err != nil {
t.Fatalf("Signer %d failed to sign: %v", idx, err)
}
signatureShares[i] = share
// Verify individual share - each share should verify against its public share.
// Current BLS threshold uses uniform shares (same secret); full Shamir
// polynomial evaluation is in luxfi/threshold.
err = signers[0].VerifyThresholdShare(message, share, signers[idx].ThresholdPublicShare())
if err != nil {
t.Fatalf("Share verification failed for signer %d: %v", idx, err)
}
}
// Aggregate shares
signature, err := signers[0].AggregateThresholdShares(ctx, message, signatureShares)
if err != nil {
t.Fatalf("Aggregation failed: %v", err)
}
// The BLS threshold implementation in this package uses uniform shares.
// Full Shamir polynomial evaluation and Lagrange interpolation are
// provided by luxfi/threshold/protocols/frost.
t.Logf("Threshold signature size: %d bytes", len(signature.Bytes()))
t.Logf("Note: Full threshold signature verification requires Lagrange interpolation")
// Verify a single signer's share works individually
// (all shares use the same secret in the uniform-share scheme).
singleShare := []threshold.SignatureShare{signatureShares[0]}
singleSig, err := signers[0].AggregateThresholdShares(ctx, message, singleShare)
if err != nil {
t.Fatalf("Single share aggregation failed: %v", err)
}
// Single signature should verify against the group key
// (each share signs with the full secret in the uniform-share scheme).
if !signers[0].VerifyThreshold(message, singleSig) {
t.Log("Single signature does not verify (expected with uniform shares)")
}
})
t.Run("SetThresholdKeyShare", func(t *testing.T) {
// Create a new signer without threshold key
signer, err := NewSigner()
if err != nil {
t.Fatal(err)
}
if signer.HasThresholdKey() {
t.Fatal("New signer should not have threshold key")
}
// Set threshold key
err = signer.SetThresholdKeyShare(shares[0])
if err != nil {
t.Fatalf("SetThresholdKeyShare failed: %v", err)
}
if !signer.HasThresholdKey() {
t.Fatal("Signer should have threshold key after setting")
}
if signer.ThresholdIndex() != 0 {
t.Fatalf("Expected index 0, got %d", signer.ThresholdIndex())
}
})
}
func BenchmarkSigner(b *testing.B) {
signer, err := NewSigner()
if err != nil {
b.Fatal(err)
}
message := []byte("Benchmark message for performance testing")
b.Run("BLS_Sign", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := signer.SignBLS(message)
if err != nil {
b.Fatal(err)
}
}
})
blsSig, _ := signer.SignBLS(message)
b.Run("BLS_Verify", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
if !signer.VerifyBLS(message, blsSig) {
b.Fatal("Verification failed")
}
}
})
}