Signer

Hybrid BLS and Pulsar signing for Lux consensus

Signer

Hybrid signing combining BLS with Pulsar (lattice-based threshold signatures) for Lux consensus.

Overview

  • Hybrid Signatures: BLS + Pulsar threshold signing
  • Classical Security: BLS provides efficient, aggregatable signatures
  • Post-Quantum Ready: Pulsar lattice-based threshold scheme
  • Consensus Optimized: Designed for Lux's Quasar consensus

Architecture

Lux consensus uses two cryptographic layers:

LayerAlgorithmPurpose
ClassicalBLS12-381Efficient aggregatable signatures
ThresholdPulsarLattice-based threshold signatures

Implementation

Creating a Signer

package main

import (
    "fmt"
    "github.com/luxfi/crypto/signer"
)

func main() {
    s, err := signer.NewSigner()
    if err != nil {
        panic(err)
    }

    fmt.Printf("BLS Public Key: %x\n", s.GetBLSPublicKey())
    fmt.Printf("Pulsar Public Key: %x\n", s.GetRingtailPublicKey().Bytes())
}

BLS Signing

BLS signatures are used for classical operations and can be aggregated:

func sign(s *signer.Signer, msg []byte) ([]byte, error) {
    return s.SignBLS(msg)
}

func verify(s *signer.Signer, msg, sig []byte) bool {
    return s.VerifyBLS(msg, sig)
}

Pulsar Threshold Signing

Pulsar is a lattice-based threshold signature scheme used for post-quantum security in consensus:

// Pulsar threshold signing requires coordination through consensus
// The signer package provides key management
pk := s.GetRingtailPublicKey()

// Threshold operations are coordinated by the consensus layer
// See github.com/luxfi/consensus for full implementation

Consensus Integration

Quasar Consensus

The Lux Quasar consensus uses both BLS and Pulsar:

type ConsensusMessage struct {
    Height       uint64
    Round        int
    BlockHash    []byte
    BLSSignature []byte      // Aggregatable
    RingtailSig  []byte      // Threshold contribution
}

// BLS signatures are aggregated across validators
func aggregateBLS(sigs [][]byte) ([]byte, error) {
    return bls.AggregateSignatures(sigs)
}

// Pulsar uses threshold aggregation
// Requires t-of-n validators to create final signature

Block Finalization

type FinalizedBlock struct {
    Height        uint64
    Hash          []byte
    BLSAggregate  []byte  // Aggregated BLS from validators
    RingtailCert  []byte  // Threshold certificate
    ValidatorSet  []byte  // Participating validators
}

Performance Comparison

OperationBLSNotes
Sign1.2 msSingle validator
Verify2.5 msSingle signature
Aggregate0.1 msPer signature
Batch Verify3.0 ms100 signatures
Signature Size96 BConstant
Public Key Size48 BCompressed

Pulsar threshold operations depend on the consensus layer.

Key Management

Export Public Keys

func exportPublicKeys(s *signer.Signer) map[string][]byte {
    return map[string][]byte{
        "bls":      s.GetBLSPublicKey(),
        "ringtail": s.GetRingtailPublicKey().Bytes(),
    }
}

Access Raw Keys

// For advanced operations
blsKey := s.BLSSecretKey()
ringtailKey := s.RingtailPrivateKey()

Security Considerations

Dual-Layer Security

The hybrid approach provides security even if one algorithm is compromised:

  • BLS only broken: Pulsar threshold maintains security
  • Pulsar only broken: BLS maintains classical security
  • Both secure: Defense in depth

Key Generation

func secureKeyGeneration() (*signer.Signer, error) {
    // Signer uses crypto/rand internally
    s, err := signer.NewSigner()
    if err != nil {
        return nil, err
    }

    // Verify key generation
    if len(s.GetBLSPublicKey()) == 0 {
        return nil, errors.New("BLS key generation failed")
    }
    if s.GetRingtailPublicKey() == nil {
        return nil, errors.New("Pulsar key generation failed")
    }

    return s, nil
}

Testing

func TestSigner(t *testing.T) {
    s, err := signer.NewSigner()
    require.NoError(t, err)

    message := []byte("test message")

    // Test BLS
    blsSig, err := s.SignBLS(message)
    require.NoError(t, err)
    require.True(t, s.VerifyBLS(message, blsSig))

    // Wrong message should fail
    require.False(t, s.VerifyBLS([]byte("wrong"), blsSig))

    // Pulsar key should exist
    require.NotNil(t, s.GetRingtailPublicKey())
}

References