Lux Docs
Lux Skills Reference

Lux Ringtail - Post-Quantum Threshold Signatures

Ringtail is the post-quantum signature primitive for Lux consensus. It enables t-of-n threshold signing without relying on classical assumptions R...

Overview

Ringtail is a pure Go implementation of the Ringtail post-quantum threshold signature scheme from eprint.iacr.org/2024/1113. It provides practical two-round lattice-based threshold signatures from standard LWE (Learning With Errors) assumptions, built on the github.com/luxfi/lattice/v7 ring polynomial library.

Ringtail is the post-quantum signature primitive for Lux consensus. It enables t-of-n threshold signing without relying on classical assumptions (RSA, ECDSA) that are vulnerable to quantum computers.

When to use

  • Implementing or modifying post-quantum threshold signatures in the Lux stack
  • Integrating PQ-safe consensus finality (Quasar certificates)
  • Working with lattice-based cryptographic protocols
  • Benchmarking or testing Ring-LWE signing performance
  • Extending the threshold package for new signing protocols

Hard requirements

  1. ALWAYS use github.com/luxfi/* packages -- NEVER go-ethereum or luxfi
  2. NEVER use EWOQ keys
  3. Requires github.com/luxfi/lattice/v7 for all ring polynomial operations
  4. Go packages stay at v1.x.x (the module itself has no version suffix)

Quick reference

ItemValue
Repogithub.com/luxfi/ringtail
Modulegithub.com/luxfi/ringtail
Go version1.26.1
Binarybin/ringtail
Papereprint.iacr.org/2024/1113
LicenseApache 2.0
Key depgithub.com/luxfi/lattice/v7 v7.0.0

Core Concepts

Directory structure

luxfi/ringtail/
  main.go                  -- Entry point: local sim or P2P party mode
  sign/
    config.go              -- Scheme parameters (Q, N, M, bounds, ring dims)
    sign.go                -- Core: Party, Gen, SignRound1/2, Finalize, Verify
    local.go               -- Local single-machine simulation with stats
  primitives/
    hash.go                -- Hash, MAC, PRF, GaussianHash, LowNormHash
    shamir.go              -- Shamir secret sharing over ring vectors
  networking/
    networking.go          -- TCP P2P comm between signers (send/recv)
  threshold/
    threshold.go           -- High-level API: GenerateKeys, Signer, Verify
    threshold_test.go      -- Full signing flow tests (key gen, sign, verify)
  utils/
    utils.go               -- NTT/Montgomery, matrix/vector ops, rounding
    utils-naive.go          -- Naive ring multiplication (test-only)
  test_helpers.go          -- Shared test utilities

Scheme parameters (sign/config.go)

ParameterValueDescription
LogN8Ring dimension N = 256
Q0x1000000004A0148-bit NTT-friendly prime
M8Public key matrix rows
N7Secret key dimension
Dbar48Commitment column count
Kappa23Security parameter
KeySize32256-bit keys
SigmaE6.108Error distribution width
SigmaStar~2^37.3Masking distribution width

Protocol flow

  1. Gen (Trusted Dealer): Generate LWE public key (A, b), Shamir-split secret key into shares, distribute seeds and MAC keys to all parties.
  2. Sign Round 1 (Each party): Sample masking vectors, compute commitment matrix D_i and MAC tags, broadcast to all parties.
  3. Sign Round 2 (Each party): Verify MACs, check D-sum full rank, compute partial signature z_i using Lagrange coefficients, send to combiner.
  4. Finalize (Combiner): Aggregate z shares into final signature (c, z, Delta).
  5. Verify (Anyone): Recompute hash, check L2 norm bound.

Two API levels

Low-level (sign package): Direct Party struct with explicit ring operations. Used by main.go for P2P networking mode.

High-level (threshold package): Clean GenerateKeys/Signer/Verify API with proper error handling. Preferred for integration.


// Generate 2-of-3 threshold keys
shares, groupKey, err := threshold.GenerateKeys(2, 3, nil)

// Create signers
signers := make([]*threshold.Signer, 3)
for i, share := range shares {
    signers[i] = threshold.NewSigner(share)
}

// Round 1
round1Data := make(map[int]*threshold.Round1Data)
for _, s := range signers {
    round1Data[s.Round1(sessionID, prfKey, signerIDs).PartyID] = ...
}

// Round 2
round2Data := make(map[int]*threshold.Round2Data)
for _, s := range signers {
    data, err := s.Round2(sessionID, message, prfKey, signerIDs, round1Data)
    round2Data[data.PartyID] = data
}

// Finalize + Verify
sig, err := signers[0].Finalize(round2Data)
valid := threshold.Verify(groupKey, message, sig)

Build and test

make build          # bin/ringtail
make test           # go test -v -timeout 30s ./...
make test-race      # Tests with race detector
make bench          # Benchmarks with -benchmem
make coverage       # HTML coverage report
make ci             # fmt, vet, lint, test-race, coverage, build

Running

# Local simulation (no networking)
./bin/ringtail l 1 3      # l=local, 1=iterations, 3=parties

# Distributed P2P (one terminal per party)
./bin/ringtail 0 1 3      # Party 0 = trusted dealer
./bin/ringtail 1 1 3      # Party 1 = combiner
./bin/ringtail 2 1 3      # Party 2 = signer

Troubleshooting

IssueCauseSolution
MAC verification failedCorrupted network data or wrong MAC keysCheck TCP connectivity; ensure all parties use same dealer key
NTT panicRing dimension mismatchEnsure LogN matches across all parties
Full rank check failedDegenerate commitment matrixRetry with fresh randomness (rare)
Connection refused in P2P modeParty not started in timeStart all parties before TCP timeout
Slow benchmarksLarge party countStart with 3 parties; computation scales with K
  • lux/lux-lattice.md -- Ring polynomial library (RLWE, NTT, sampling)
  • lux/lux-crypto.md -- Classical crypto primitives (BLS, secp256k1)
  • lux/lux-consensus.md -- Quasar consensus (consumes Ringtail for PQ certificates)
  • lux/lux-threshold.md -- Threshold cryptography abstractions
  • lux/lux-fhe.md -- Homomorphic encryption (shares lattice foundations)

Last Updated: 2026-03-13

On this page