mirror of
https://github.com/luxfi/crypto.git
synced 2026-07-27 01:54:50 +00:00
255 lines
6.9 KiB
Go
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")
|
|
}
|
|
}
|
|
})
|
|
}
|