LPsLux Proposals
Post-Quantum Cryptography
LP-4500

SLH-DSA Stateless Hash-Based Digital Signatures (Family Root)

Final

NIST FIPS 205 SLH-DSA stateless hash-based post-quantum digital signature implementation. Family root for parameter tiers LP-4510 (SLH-DSA-128), LP-4520 (SLH-DSA-192, default), LP-4530 (SLH-DSA-256).

Category
Core
Created
2025-11-22

Implementation status (code-audited 2026-07-03): SHIPPED Wraps circl/sign/slhdsa (crypto/slhdsa/slhdsa.go), 12 parameter sets, KAT tests present (kat_test.go, kat_vectors_test.go).

Provenance

Originally LP-4317; renumbered for the unified-4xxx consolidation (PQ hash sigs 4500-4599; family-root). Tiers: LP-4510 (SLH-DSA-128), LP-4520 (SLH-DSA-192, network default), LP-4530 (SLH-DSA-256). Threshold variant (Magnetar): LP-4540. The 4317 slot is a permanent pointer to this LP.

Abstract

SLH-DSA (Stateless Hash-based Digital Signature Algorithm, NIST FIPS 205) integration for Lux Network. Most conservative PQ signature scheme — security relies only on hash collision resistance, not on lattice assumptions.

Use cases

Long-lived validator keys (multi-year commitments), root CAs, genesis block signatures, governance proposal signing. Diversified quantum security alongside ML-DSA (defense in depth: hash-based vs lattice-based).

Specification

Algorithm

SLH-DSA construction:

  • FORS: Forest of Random Subsets (few-time signature)
  • WOTS+: Winternitz One-Time Signature
  • Hash trees: Merkle tree key aggregation
  • Hypertree: multi-layer tree construction

Parameter Sets

Twelve sets (SHA2 + SHAKE variants, 128/192/256-bit, small/fast):

SHA2

ModeSecurityPKSKSigSignVerify
SHA2-128s128-bit (NIST-1)32 B64 B7,856 B~309 ms~286 μs
SHA2-128f128-bit (NIST-1)32 B64 B17,088 B~10 ms~286 μs
SHA2-192s192-bit (NIST-3)48 B96 B16,224 B~418 ms~397 μs
SHA2-192f192-bit (NIST-3)48 B96 B35,664 B~15 ms~397 μs
SHA2-256s256-bit (NIST-5)64 B128 B29,792 B~603 ms~593 μs
SHA2-256f256-bit (NIST-5)64 B128 B49,856 B~23 ms~593 μs

SHAKE

ModeSecurityPKSKSigSignVerify
SHAKE-128s128-bit (NIST-1)32 B64 B7,856 B~1.0 s~286 μs
SHAKE-128f128-bit (NIST-1)32 B64 B17,088 B~38 ms~286 μs
SHAKE-192s192-bit (NIST-3)48 B96 B16,224 B~1.4 s~397 μs
SHAKE-192f192-bit (NIST-3)48 B96 B35,664 B~54 ms~397 μs
SHAKE-256s256-bit (NIST-5)64 B128 B29,792 B~2.0 s~593 μs
SHAKE-256f256-bit (NIST-5)64 B128 B49,856 B~80 ms~593 μs

s = small signature / slow signing. f = fast signing / large sig. Lux default: SHA2-128f.

Key Generation

import "github.com/luxfi/crypto/slhdsa"

sk, err := slhdsa.GenerateKey(rand.Reader, slhdsa.SHA2_128f)
pk := sk.PublicKey
privBytes := sk.Bytes()  // 64 B
pubBytes  := pk.Bytes()  // 32 B

Signing (deterministic; stateless)

signature, err := sk.Sign(rand.Reader, message, nil)
// 17,088 B for SHA2-128f

Verification

valid := pk.Verify(message, signature, nil)

Checks: signature size matches mode, hash-tree path, FORS sig, WOTS+ chain.

Integration

Critical Infrastructure Signing

type CriticalValidatorRegistration struct {
    ValidatorID   ids.ID
    StakeDuration time.Duration  // multi-year
    BLS           []byte         // 96 B  - fast consensus
    SLHDSA        []byte         // 17,088 B - long-term security
    Mode          uint8
}

Governance Proposals

type GovernanceProposal struct {
    ProposalID  ids.ID
    Title       string
    Description string
    Actions     []Action
    Signature   []byte  // 17,088 B (SHA2-128f)
    PublicKey   []byte  // 32 B
    Mode        uint8   // SHA2_128f
}

Root Certificate Authority

Subject: Lux Network Root CA
Public Key Algorithm: SLH-DSA-SHA2-256s
Signature Algorithm: SLH-DSA-SHA2-256s
Validity: 10 years

EVM Precompile

Address: 0x0000000000000000000000000000000000012203

interface ISLHDSA {
    function verify(
        bytes calldata publicKey,
        bytes calldata message,
        bytes calldata signature,
        uint8 mode
    ) external view returns (bool valid);
}

Gas: 500,000 base + 50/byte of message.

contract GovernanceVault {
    address constant SLHDSA = 0x0000000000000000000000000000000000012203;
    uint8 constant REQUIRED_MODE = 4; // SHA2-256s

    function submitProposal(
        bytes calldata pubKey,
        bytes calldata proposal,
        bytes calldata signature
    ) external {
        (bool success, bytes memory result) = SLHDSA.staticcall(
            abi.encode(pubKey, proposal, signature, REQUIRED_MODE)
        );
        require(success && abi.decode(result, (bool)), "Invalid SLH-DSA signature");
    }
}

Implementation

Core Library

crypto/slhdsa/. Dep: github.com/cloudflare/circl v1.6.1 (FIPS 205). Files: slhdsa.go (5,123 B), slhdsa_test.go (8,445 B).

package slhdsa

type Mode int
const (
    SHA2_128s   Mode = iota
    SHA2_128f                // default
    SHA2_192s
    SHA2_192f
    SHA2_256s
    SHA2_256f
    SHAKE_128s
    SHAKE_128f
    SHAKE_192s
    SHAKE_192f
    SHAKE_256s
    SHAKE_256f
)

func GenerateKey(rand io.Reader, mode Mode) (*PrivateKey, error)
func (sk *PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) ([]byte, error)
func (pk *PublicKey)  Verify(message, signature []byte, opts crypto.SignerOpts) bool
func PrivateKeyFromBytes(mode Mode, data []byte) (*PrivateKey, error)
func PublicKeyFromBytes(data []byte, mode Mode) (*PublicKey, error)
func GetPublicKeySize(mode Mode)  int
func GetPrivateKeySize(mode Mode) int
func GetSignatureSize(mode Mode)  int

EVM Precompile

evm/precompile/contracts/slhdsa/: contract.go (5,280 B), contract_test.go (9,433 B), module.go (1,226 B), ISLHDSA.sol (8,067 B).

Test Results

15/15 passing: SignVerify_SHA2_128s, SignVerify_SHAKE_128s, SignVerify_SHA2_256s, InvalidSignature, WrongMessage, EmptyMessage, LargeMessage, PrivateKeyFromBytes, PublicKeyFromBytes, AllModes (12 parameter sets), InvalidMode, InvalidKeySize, GetPublicKeySize, GetSignatureSize, DeterministicSigning.

Benchmarks (Apple M1 Max):

BenchmarkSLHDSA_Sign_SHA2_128s      3 ops    309,000,000 ns/op (309 ms)
BenchmarkSLHDSA_Sign_SHA2_128f    100 ops     10,000,000 ns/op  (10 ms)
BenchmarkSLHDSA_Sign_SHA2_256s      2 ops    603,000,000 ns/op (603 ms)
BenchmarkSLHDSA_Verify_SHA2_128s  3,500 ops      286,000 ns/op (286 μs)
BenchmarkSLHDSA_Verify_SHA2_256s  1,686 ops      593,000 ns/op (593 μs)
BenchmarkSLHDSA_KeyGen_SHA2_128f    285 ops   35,000,000 ns/op  (35 ms)

BenchmarkSLHDSA_Sign_SHAKE_128s     1 op   1,020,000,000 ns/op (1.02 s)
BenchmarkSLHDSA_Sign_SHAKE_128f    26 ops     38,000,000 ns/op  (38 ms)

Migration

Phase 1 — critical infrastructure: SLH-DSA for long-lived validator keys; root CA certificates SHA2-256s; governance proposals support SLH-DSA. Phase 2 — EVM integration: deploy precompile on C-Chain; on-chain governance using SLH-DSA. Phase 3 — diversified security: validators choose ML-DSA (fast) or SLH-DSA (conservative); critical operations require SLH-DSA.

Security Considerations

Conservative foundation. Security relies only on hash collision resistance — no math hardness assumptions. Decades of analysis (Merkle 1979). Resistant to all quantum algorithms, including future ones. SHA-256 → 128-bit security; SHAKE256 → adjustable.

Stateless. Keys safely copyable/backed-up. No state sync. No catastrophic state-loss compromise (vs XMSS/LMS).

Trade-offs vs ML-DSA. SLH-DSA: more conservative; resistant to future lattice breaks. Cost: 2-60× slower signing (10 ms – 2 s vs 417 μs); 2-15× larger sigs (7-49 KB vs 3 KB).

Side-channel. Constant-time hash ops; no secret-dependent branches or memory access. CIRCL production-validated.

Key management. SLH-DSA private keys are 64-128 B (smaller than ML-DSA's 4 KB). BIP-39 seed derivation; encrypt backups with AES-256.

Backwards Compatibility

Hybrid period (2026-2027): validators support ML-DSA, SLH-DSA, or both. Governance proposals accept either. ECDSA addresses keep functioning.

Rationale

SLH-DSA vs XMSS/LMS: stateless (no catastrophic state-loss); simpler operations. SLH-DSA vs ML-DSA: hash-only hardness (more conservative); trade: much larger sigs, slower signing.

SHA2-128f as default: 128-bit matches current standards. 10 ms signing acceptable. 17 KB sigs acceptable. SHA-2 has better hardware support than SHAKE.

Variant selection:

  • SHA2-128f: standard transactions, regular validators.
  • SHA2-256s: root CAs, genesis, 10+ year security (accept 603 ms).
  • SHA2-192f: high-value transactions, important proposals.

Reference

package main

import (
    "crypto/rand"
    "fmt"

    "github.com/luxfi/crypto/slhdsa"
)

func main() {
    sk, _ := slhdsa.GenerateKey(rand.Reader, slhdsa.SHA2_128f)
    commitment := []byte("Validator commitment for 3 years")
    signature, _ := sk.Sign(rand.Reader, commitment, nil)
    fmt.Printf("Signature size: %d bytes\n", len(signature))  // 17088
    valid := sk.PublicKey.Verify(commitment, signature, nil)
    fmt.Printf("Signature valid: %v\n", valid)                // true

    // Deterministic
    signature2, _ := sk.Sign(rand.Reader, commitment, nil)
    fmt.Printf("Signatures match: %v\n", string(signature) == string(signature2)) // true
}
// Governance proposal — maximum security
func signGovernanceProposal(proposal []byte) ([]byte, error) {
    sk, err := slhdsa.GenerateKey(rand.Reader, slhdsa.SHA2_256s)
    if err != nil { return nil, err }
    signature, err := sk.Sign(rand.Reader, proposal, nil)
    if err != nil { return nil, err }
    return signature, nil  // 29,792 B
}

Copyright and related rights waived via CC0.

References

  • LP-4400 — ML-DSA (lattice alternative)
  • LP-4540 — Magnetar (threshold SLH-DSA)
  • LP-4600 — ML-KEM (complementary KEM)
  • LP-4940 — Hybrid envelope

Standards

Implementation

  • ~/work/lux/crypto/slhdsa/
  • ~/work/lux/evm/precompile/contracts/slhdsa/

Appendix A: Signature size comparison

SchemeSig SizeSign TimeHardness
ECDSA (secp256k1)65 B~88 μsEC discrete log (quantum-broken)
BLS12-38196 B~1,200 μsPairing (quantum-broken)
ML-DSA-653,293 B~417 μsModule-lattice (quantum-resistant)
SLH-DSA-SHA2-128s7,856 B~309 msHash (quantum-resistant)
SLH-DSA-SHA2-128f17,088 B~10 msHash (quantum-resistant)
SLH-DSA-SHA2-256s29,792 B~603 msHash (quantum-resistant)

SLH-DSA sigs are 120-450× ECDSA, but most conservative PQ security.

Appendix B: Selection matrix

ModeSecuritySignSig SizeBest For
SHA2-128f128-bit10 ms17 KBGeneral transactions, standard validators
SHA2-192f192-bit15 ms35 KBHigh-value transactions, important proposals
SHA2-256s256-bit603 ms29 KBRoot CAs, genesis, ultimate security
SHA2-256f256-bit23 ms49 KBMaximum security with faster signing
SHA2-128s128-bit309 ms7.8 KBBandwidth-constrained

Appendix C: History

  • 1979 — Merkle invents Merkle signatures (first hash-based)
  • 2001 — XMSS (stateful, limited)
  • 2013 — SPHINCS (first practical stateless hash-based)
  • 2015 — SPHINCS+ (better perf, smaller sigs)
  • 2024 — NIST standardizes as FIPS 205

40+ years of cryptanalysis; no known attacks on underlying construction.