SLH-DSA Stateless Hash-Based Digital Signatures (Family Root)
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).
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
| Mode | Security | PK | SK | Sig | Sign | Verify |
|---|---|---|---|---|---|---|
| SHA2-128s | 128-bit (NIST-1) | 32 B | 64 B | 7,856 B | ~309 ms | ~286 μs |
| SHA2-128f | 128-bit (NIST-1) | 32 B | 64 B | 17,088 B | ~10 ms | ~286 μs |
| SHA2-192s | 192-bit (NIST-3) | 48 B | 96 B | 16,224 B | ~418 ms | ~397 μs |
| SHA2-192f | 192-bit (NIST-3) | 48 B | 96 B | 35,664 B | ~15 ms | ~397 μs |
| SHA2-256s | 256-bit (NIST-5) | 64 B | 128 B | 29,792 B | ~603 ms | ~593 μs |
| SHA2-256f | 256-bit (NIST-5) | 64 B | 128 B | 49,856 B | ~23 ms | ~593 μs |
SHAKE
| Mode | Security | PK | SK | Sig | Sign | Verify |
|---|---|---|---|---|---|---|
| SHAKE-128s | 128-bit (NIST-1) | 32 B | 64 B | 7,856 B | ~1.0 s | ~286 μs |
| SHAKE-128f | 128-bit (NIST-1) | 32 B | 64 B | 17,088 B | ~38 ms | ~286 μs |
| SHAKE-192s | 192-bit (NIST-3) | 48 B | 96 B | 16,224 B | ~1.4 s | ~397 μs |
| SHAKE-192f | 192-bit (NIST-3) | 48 B | 96 B | 35,664 B | ~54 ms | ~397 μs |
| SHAKE-256s | 256-bit (NIST-5) | 64 B | 128 B | 29,792 B | ~2.0 s | ~593 μs |
| SHAKE-256f | 256-bit (NIST-5) | 64 B | 128 B | 49,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
Copyright and related rights waived via CC0.
References
Related LPs
- LP-4400 — ML-DSA (lattice alternative)
- LP-4540 — Magnetar (threshold SLH-DSA)
- LP-4600 — ML-KEM (complementary KEM)
- LP-4940 — Hybrid envelope
Standards
- FIPS 205: Stateless Hash-Based Digital Signature Standard
- SPHINCS+: Spec v3.1
- CIRCL: Cloudflare Cryptographic Library
- Merkle (1979): "Secrecy, Authentication, and Public Key Systems"
Implementation
~/work/lux/crypto/slhdsa/~/work/lux/evm/precompile/contracts/slhdsa/
Appendix A: Signature size comparison
| Scheme | Sig Size | Sign Time | Hardness |
|---|---|---|---|
| ECDSA (secp256k1) | 65 B | ~88 μs | EC discrete log (quantum-broken) |
| BLS12-381 | 96 B | ~1,200 μs | Pairing (quantum-broken) |
| ML-DSA-65 | 3,293 B | ~417 μs | Module-lattice (quantum-resistant) |
| SLH-DSA-SHA2-128s | 7,856 B | ~309 ms | Hash (quantum-resistant) |
| SLH-DSA-SHA2-128f | 17,088 B | ~10 ms | Hash (quantum-resistant) |
| SLH-DSA-SHA2-256s | 29,792 B | ~603 ms | Hash (quantum-resistant) |
SLH-DSA sigs are 120-450× ECDSA, but most conservative PQ security.
Appendix B: Selection matrix
| Mode | Security | Sign | Sig Size | Best For |
|---|---|---|---|---|
| SHA2-128f | 128-bit | 10 ms | 17 KB | General transactions, standard validators |
| SHA2-192f | 192-bit | 15 ms | 35 KB | High-value transactions, important proposals |
| SHA2-256s | 256-bit | 603 ms | 29 KB | Root CAs, genesis, ultimate security |
| SHA2-256f | 256-bit | 23 ms | 49 KB | Maximum security with faster signing |
| SHA2-128s | 128-bit | 309 ms | 7.8 KB | Bandwidth-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.