Security

Post-Quantum Cryptography

Quantum-resistant cryptography implementation with Dilithium, Kyber, and Ringtail for LX

Post-Quantum Cryptography

LX implements NIST-approved post-quantum cryptographic algorithms to protect against future quantum computer attacks. Our hybrid approach provides security against both classical and quantum adversaries.

Quantum Threat Model

Timeline Assessment

Threat LevelTimelineCapabilityMitigation
CurrentNowNo cryptographic quantum computersClassical crypto sufficient
Near-term5-10 yearsEarly fault-tolerant QCHybrid signatures
Mid-term10-20 yearsCryptographically relevant QCFull PQ migration
Long-term20+ yearsLarge-scale quantum computersPQ-only systems

Vulnerable Algorithms

AlgorithmQuantum AttackStatus
RSA-2048/4096Shor's algorithmBroken with CRQC
ECDSA (secp256k1)Shor's algorithmBroken with CRQC
Ed25519Shor's algorithmBroken with CRQC
AES-256Grover's algorithmReduced to 128-bit
SHA-256Grover's algorithmReduced to 128-bit

CRQC: Cryptographically Relevant Quantum Computer

NIST Post-Quantum Standards

Selected Algorithms

┌─────────────────────────────────────────────────────────────────┐
│                 NIST PQ CRYPTOGRAPHY STANDARDS                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Digital Signatures (FIPS 204)                                  │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  ML-DSA (Dilithium)          Primary standard           │   │
│  │  SLH-DSA (SPHINCS+)          Hash-based backup          │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  Key Encapsulation (FIPS 203)                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  ML-KEM (Kyber)              Primary standard           │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  LX Extensions                                              │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  Ringtail                    Threshold lattice sigs     │   │
│  │  Hybrid BLS+RT               Warp message signing       │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

ML-DSA (Dilithium) Implementation

Security Levels

Parameter SetNIST LevelSignature SizePublic KeyUse Case
ML-DSA-44Level 22,420 bytes1,312 bytesGeneral use
ML-DSA-65Level 33,309 bytes1,952 bytesLX default
ML-DSA-87Level 54,627 bytes2,592 bytesHigh security

Implementation

package dilithium

import (
    "crypto/rand"
    "github.com/cloudflare/circl/sign/dilithium/mode3"
)

// DilithiumSigner provides ML-DSA-65 (Level 3) signatures
type DilithiumSigner struct {
    publicKey  mode3.PublicKey
    privateKey mode3.PrivateKey
}

// GenerateKeyPair creates new Dilithium key pair
func GenerateKeyPair() (*DilithiumSigner, error) {
    pub, priv, err := mode3.GenerateKey(rand.Reader)
    if err != nil {
        return nil, err
    }

    return &DilithiumSigner{
        publicKey:  *pub,
        privateKey: *priv,
    }, nil
}

// Sign creates Dilithium signature
func (s *DilithiumSigner) Sign(message []byte) []byte {
    return mode3.Sign(&s.privateKey, message)
}

// Verify checks Dilithium signature
func (s *DilithiumSigner) Verify(message, signature []byte) bool {
    return mode3.Verify(&s.publicKey, message, signature)
}

// PublicKeyBytes returns serialized public key
func (s *DilithiumSigner) PublicKeyBytes() []byte {
    var buf [mode3.PublicKeySize]byte
    s.publicKey.Pack(&buf)
    return buf[:]
}

// Constants
const (
    PublicKeySize  = mode3.PublicKeySize  // 1,952 bytes
    PrivateKeySize = mode3.PrivateKeySize // 4,032 bytes
    SignatureSize  = mode3.SignatureSize  // 3,309 bytes
)

Order Signing with Dilithium

package trading

import (
    "encoding/json"
    "time"
)

// DilithiumSignedOrder contains order with PQ signature
type DilithiumSignedOrder struct {
    Order           *Order `json:"order"`
    PublicKey       []byte `json:"public_key"`
    Signature       []byte `json:"signature"`
    SignatureScheme string `json:"scheme"` // "ml-dsa-65"
}

// SignOrder creates Dilithium-signed order
func SignOrder(signer *DilithiumSigner, order *Order) (*DilithiumSignedOrder, error) {
    // Canonical serialization
    orderBytes, err := canonicalMarshal(order)
    if err != nil {
        return nil, err
    }

    return &DilithiumSignedOrder{
        Order:           order,
        PublicKey:       signer.PublicKeyBytes(),
        Signature:       signer.Sign(orderBytes),
        SignatureScheme: "ml-dsa-65",
    }, nil
}

// VerifyOrder checks Dilithium signature on order
func VerifyOrder(signed *DilithiumSignedOrder) (bool, error) {
    if signed.SignatureScheme != "ml-dsa-65" {
        return false, ErrUnsupportedScheme
    }

    var pubKey mode3.PublicKey
    if err := pubKey.Unpack((*[mode3.PublicKeySize]byte)(signed.PublicKey)); err != nil {
        return false, err
    }

    orderBytes, err := canonicalMarshal(signed.Order)
    if err != nil {
        return false, err
    }

    return mode3.Verify(&pubKey, orderBytes, signed.Signature), nil
}

ML-KEM (Kyber) Implementation

Security Levels

Parameter SetNIST LevelCiphertext SizePublic KeyShared Secret
ML-KEM-512Level 1768 bytes800 bytes32 bytes
ML-KEM-768Level 31,088 bytes1,184 bytes32 bytes
ML-KEM-1024Level 51,568 bytes1,568 bytes32 bytes

Implementation

package kyber

import (
    "crypto/rand"
    "github.com/cloudflare/circl/kem/kyber/kyber768"
)

// KyberKEM provides ML-KEM-768 key encapsulation
type KyberKEM struct {
    publicKey  kyber768.PublicKey
    privateKey kyber768.PrivateKey
}

// GenerateKeyPair creates new Kyber key pair
func GenerateKeyPair() (*KyberKEM, error) {
    pub, priv, err := kyber768.GenerateKeyPair(rand.Reader)
    if err != nil {
        return nil, err
    }

    return &KyberKEM{
        publicKey:  *pub,
        privateKey: *priv,
    }, nil
}

// Encapsulate creates ciphertext and shared secret
func (k *KyberKEM) Encapsulate() (ciphertext, sharedSecret []byte, err error) {
    ct, ss, err := kyber768.Encapsulate(&k.publicKey)
    if err != nil {
        return nil, nil, err
    }
    return ct, ss, nil
}

// Decapsulate recovers shared secret from ciphertext
func (k *KyberKEM) Decapsulate(ciphertext []byte) ([]byte, error) {
    return kyber768.Decapsulate(&k.privateKey, ciphertext)
}

// PublicKeyBytes returns serialized public key
func (k *KyberKEM) PublicKeyBytes() []byte {
    var buf [kyber768.PublicKeySize]byte
    k.publicKey.Pack(&buf)
    return buf[:]
}

// Constants
const (
    PublicKeySize  = kyber768.PublicKeySize  // 1,184 bytes
    PrivateKeySize = kyber768.PrivateKeySize // 2,400 bytes
    CiphertextSize = kyber768.CiphertextSize // 1,088 bytes
    SharedKeySize  = kyber768.SharedKeySize  // 32 bytes
)

Hybrid Key Exchange (X25519 + Kyber)

package hybrid

import (
    "crypto/sha3"
    "golang.org/x/crypto/chacha20poly1305"
    "golang.org/x/crypto/curve25519"
)

// HybridKeyExchange combines X25519 and Kyber
type HybridKeyExchange struct {
    x25519Private [32]byte
    x25519Public  [32]byte
    kyber         *KyberKEM
}

// NewHybridKeyExchange generates hybrid key pair
func NewHybridKeyExchange() (*HybridKeyExchange, error) {
    h := &HybridKeyExchange{}

    // X25519 key generation
    if _, err := rand.Read(h.x25519Private[:]); err != nil {
        return nil, err
    }
    curve25519.ScalarBaseMult(&h.x25519Public, &h.x25519Private)

    // Kyber key generation
    var err error
    h.kyber, err = GenerateKeyPair()
    if err != nil {
        return nil, err
    }

    return h, nil
}

// HybridPublicKey contains both public keys
type HybridPublicKey struct {
    X25519 [32]byte
    Kyber  []byte
}

// PublicKey returns the hybrid public key
func (h *HybridKeyExchange) PublicKey() *HybridPublicKey {
    return &HybridPublicKey{
        X25519: h.x25519Public,
        Kyber:  h.kyber.PublicKeyBytes(),
    }
}

// HybridEncapsulation contains both encapsulations
type HybridEncapsulation struct {
    X25519Ephemeral [32]byte
    KyberCiphertext []byte
}

// EncapsulateTo creates hybrid shared secret with recipient
func EncapsulateTo(recipientPubKey *HybridPublicKey) (*HybridEncapsulation, []byte, error) {
    // X25519 ephemeral key exchange
    var x25519Ephemeral, x25519Private [32]byte
    if _, err := rand.Read(x25519Private[:]); err != nil {
        return nil, nil, err
    }
    curve25519.ScalarBaseMult(&x25519Ephemeral, &x25519Private)

    var x25519Shared [32]byte
    curve25519.ScalarMult(&x25519Shared, &x25519Private, &recipientPubKey.X25519)

    // Kyber encapsulation
    var kyberPubKey kyber768.PublicKey
    if err := kyberPubKey.Unpack((*[kyber768.PublicKeySize]byte)(recipientPubKey.Kyber)); err != nil {
        return nil, nil, err
    }

    kyberCt, kyberShared, err := kyber768.Encapsulate(&kyberPubKey)
    if err != nil {
        return nil, nil, err
    }

    // Combine: SHAKE256(x25519_shared || kyber_shared || "LX-DEX-HYBRID-v1")
    hasher := sha3.NewShake256()
    hasher.Write(x25519Shared[:])
    hasher.Write(kyberShared)
    hasher.Write([]byte("LX-DEX-HYBRID-v1"))

    combinedSecret := make([]byte, 32)
    hasher.Read(combinedSecret)

    return &HybridEncapsulation{
        X25519Ephemeral: x25519Ephemeral,
        KyberCiphertext: kyberCt,
    }, combinedSecret, nil
}

// Decapsulate recovers hybrid shared secret
func (h *HybridKeyExchange) Decapsulate(enc *HybridEncapsulation) ([]byte, error) {
    // X25519 decapsulation
    var x25519Shared [32]byte
    curve25519.ScalarMult(&x25519Shared, &h.x25519Private, &enc.X25519Ephemeral)

    // Kyber decapsulation
    kyberShared, err := h.kyber.Decapsulate(enc.KyberCiphertext)
    if err != nil {
        return nil, err
    }

    // Combine
    hasher := sha3.NewShake256()
    hasher.Write(x25519Shared[:])
    hasher.Write(kyberShared)
    hasher.Write([]byte("LX-DEX-HYBRID-v1"))

    combinedSecret := make([]byte, 32)
    hasher.Read(combinedSecret)

    return combinedSecret, nil
}

Ringtail Threshold Signatures

Ringtail is LX's custom lattice-based threshold signature scheme, enabling MPC signing with quantum resistance.

Security Parameters

Security LevelNQThreshold Support
128-bit51212,289t-of-n
192-bit76832,749t-of-n
256-bit1,02465,521t-of-n

Architecture

┌─────────────────────────────────────────────────────────────────┐
│               RINGTAIL THRESHOLD SIGNING                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Key Generation (DKG)                                           │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  Party 1 ──┐                                            │   │
│  │  Party 2 ──┼── Shamir Secret Sharing ── Combined PK     │   │
│  │  Party n ──┘   (t-of-n threshold)                       │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
│  Signing Protocol                                               │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  1. Message broadcast to all parties                     │   │
│  │  2. Each party creates partial signature                 │   │
│  │  3. Collect t partial signatures                         │   │
│  │  4. Combine into full Ringtail signature                │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Implementation

package ringtail

import (
    "github.com/luxfi/threshold/protocols/ringtail"
)

// RingtailConfig defines security parameters
type RingtailConfig struct {
    N         int // Ring dimension
    Q         int // Modulus
    Threshold int // t in t-of-n
    Parties   int // n total parties
}

// DefaultConfig returns 192-bit security config
func DefaultConfig() *RingtailConfig {
    return &RingtailConfig{
        N:         768,
        Q:         32749,
        Threshold: 67, // 2/3 of 100
        Parties:   100,
    }
}

// RingtailParty represents one MPC participant
type RingtailParty struct {
    config     *RingtailConfig
    privateKey *ringtail.PrivateKeyShare
    publicKey  []byte // Combined public key
    partyID    int
}

// NewParty creates new Ringtail party
func NewParty(config *RingtailConfig, partyID int) *RingtailParty {
    return &RingtailParty{
        config:  config,
        partyID: partyID,
    }
}

// GenerateKeyShare participates in DKG
func (p *RingtailParty) GenerateKeyShare(dkg *ringtail.DKG) error {
    share, combinedPK, err := dkg.GenerateShare(p.partyID)
    if err != nil {
        return err
    }

    p.privateKey = share
    p.publicKey = combinedPK
    return nil
}

// CreatePartialSignature creates party's signature share
func (p *RingtailParty) CreatePartialSignature(message []byte) (*ringtail.PartialSignature, error) {
    return ringtail.PartialSign(p.privateKey, message)
}

// CombineSignatures combines t partial signatures
func CombineSignatures(
    config *RingtailConfig,
    partialSigs []*ringtail.PartialSignature,
) ([]byte, error) {
    if len(partialSigs) < config.Threshold {
        return nil, ErrInsufficientSignatures
    }

    return ringtail.Combine(partialSigs)
}

// Verify checks Ringtail signature
func Verify(publicKey, message, signature []byte) bool {
    return ringtail.Verify(publicKey, message, signature)
}

Hybrid BLS+Ringtail Warp Signatures

For Warp cross-chain messaging, LX uses hybrid BLS+Ringtail signatures:

package warp

// HybridBLSRTSignature combines classical and PQ signatures
type HybridBLSRTSignature struct {
    Signers            []byte   `json:"signers"`    // Bit vector
    BLSSignature       [96]byte `json:"bls_sig"`    // BLS aggregate
    RingtailSignature  []byte   `json:"rt_sig"`     // Ringtail signature
    RingtailPublicKeys [][]byte `json:"rt_pubkeys"` // Per-signer RT keys
}

// Verify checks both BLS and Ringtail signatures
func (s *HybridBLSRTSignature) Verify(
    msg *UnsignedMessage,
    networkID uint32,
    validators []*Validator,
    quorumNum, quorumDen uint64,
) error {
    // 1. Verify network ID
    if msg.NetworkID != networkID {
        return ErrNetworkIDMismatch
    }

    // 2. Parse signers bitset
    signerIndices := parseSignerBitset(s.Signers)

    // 3. Check quorum weight
    var totalWeight, signerWeight uint64
    var signerValidators []*Validator
    for i, v := range validators {
        totalWeight += v.Weight
        if contains(signerIndices, i) {
            signerWeight += v.Weight
            signerValidators = append(signerValidators, v)
        }
    }

    if signerWeight*quorumDen < totalWeight*quorumNum {
        return ErrInsufficientQuorum
    }

    // 4. Verify BLS aggregate signature
    msgHash := sha256.Sum256(msg.Bytes())
    if !verifyBLSAggregate(signerValidators, msgHash[:], s.BLSSignature[:]) {
        return ErrInvalidBLSSignature
    }

    // 5. Verify Ringtail signature
    if !verifyRingtailMulti(s.RingtailPublicKeys, msgHash[:], s.RingtailSignature) {
        return ErrInvalidRingtailSignature
    }

    return nil
}

Migration Strategy

Phase 1: Hybrid (Current)

┌─────────────────────────────────────────────────────────────────┐
│              PHASE 1: HYBRID MODE (2024-2027)                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Signatures: Ed25519 + Dilithium (both required)                │
│  Key Exchange: X25519 + Kyber (combined secret)                 │
│  Warp: BLS + Ringtail (dual verification)                       │
│                                                                  │
│  Security: Protected against classical AND quantum attacks      │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Phase 2: PQ-Primary (2027-2030)

┌─────────────────────────────────────────────────────────────────┐
│              PHASE 2: PQ-PRIMARY (2027-2030)                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Signatures: Dilithium primary, Ed25519 optional                │
│  Key Exchange: Kyber primary, X25519 fallback                   │
│  Warp: Ringtail primary, BLS for legacy                         │
│                                                                  │
│  Classical components for backward compatibility only           │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Phase 3: PQ-Only (2030+)

┌─────────────────────────────────────────────────────────────────┐
│              PHASE 3: PQ-ONLY (2030+)                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Signatures: Dilithium only                                     │
│  Key Exchange: Kyber only                                       │
│  Warp: Ringtail only                                            │
│                                                                  │
│  Full quantum resistance, classical algorithms deprecated       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Performance Comparison

Signature Performance

AlgorithmSign (ops/sec)Verify (ops/sec)Size
Ed2551950,00015,00064 bytes
Dilithium-38,00012,0003,309 bytes
Hybrid6,50010,0003,373 bytes

Key Exchange Performance

AlgorithmEncaps (ops/sec)Decaps (ops/sec)Ciphertext
X2551925,00025,00032 bytes
Kyber-76815,00018,0001,088 bytes
Hybrid12,00014,0001,120 bytes

Bandwidth Impact

┌─────────────────────────────────────────────────────────────────┐
│               BANDWIDTH IMPACT ANALYSIS                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Order Signature Overhead:                                      │
│  ├── Classical only: 64 bytes (Ed25519)                         │
│  ├── PQ only: 3,309 bytes (Dilithium)                          │
│  └── Hybrid: 3,373 bytes (52x increase)                        │
│                                                                  │
│  Warp Message Overhead (100 validators):                        │
│  ├── BLS only: ~100 bytes                                      │
│  ├── Ringtail only: ~5,000 bytes                               │
│  └── Hybrid: ~5,100 bytes (51x increase)                       │
│                                                                  │
│  Mitigation: Signature aggregation, compression                 │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

SDK Integration

TypeScript

import { DilithiumSigner, KyberKEM, HybridEncrypt } from '@luxfi/pq-crypto'

// Generate Dilithium key pair
const signer = await DilithiumSigner.generate()

// Sign order
const signedOrder = await signer.signOrder({
  symbol: 'BTC-USD',
  side: 'buy',
  price: '50000',
  quantity: '1.0'
})

// Hybrid encryption
const hybrid = new HybridEncrypt()
const { publicKey } = await hybrid.generateKeys()

// Encrypt sensitive data
const encrypted = await hybrid.encrypt(publicKey, sensitiveData)

Python

from lx_dex.crypto import DilithiumSigner, KyberKEM, HybridEncrypt

# Generate Dilithium key pair
signer = DilithiumSigner.generate()

# Sign order
signed_order = signer.sign_order({
    'symbol': 'BTC-USD',
    'side': 'buy',
    'price': '50000',
    'quantity': '1.0'
})

# Verify signature
is_valid = DilithiumSigner.verify(signed_order)

Best Practices

Key Management

  • Store PQ keys in HSM with PQ-capable firmware
  • Implement key rotation with 90-day maximum lifetime
  • Use hybrid keys during transition period
  • Backup keys with quantum-safe encryption

Implementation

  • Use NIST-approved implementations (CIRCL, liboqs)
  • Validate all cryptographic parameters
  • Implement constant-time operations
  • Test with known test vectors

Deployment

  • Enable hybrid mode by default
  • Monitor PQ algorithm performance
  • Plan migration timeline based on NIST guidance
  • Maintain backward compatibility during transition

References