SLH-DSA (SPHINCS+, NIST FIPS 205) ist ein hash-basiertes Post-Quantum-Signaturverfahren. Die Sicherheit beruht ausschließlich auf der Kollisionsresistenz von SHA-256 — keine gittertheoretischen Annahmen wie bei ML-DSA.
Rechenzeit einplanen.SLHDSAKeyGenmitSLHParams128sbraucht rund 8 Sekunden, das vollständige Beispiel unten (KeyGen, Sign, Verify) rund 75 Sekunden. Einzelheiten und der Vergleich mitSLHParamsMinistehen unter Laufzeiten.
Für Versuche und Tests eignet sichSLHParamsMini. Dieser Parametersatz ist allerdings nicht FIPS-konform und gehört nicht in Produktivcode.
===== Laufzeiten =====
Gemessen mit lyxc 1.0.21A auf einem Arbeitsplatzrechner (ThinkPad T480, Linux 6.8). Die absoluten Werte hängen an der Maschine — das Verhältnis der Parametersätze zueinander nicht.
| Parametersatz | KeyGen | KeyGen + Sign + Verify | Signaturlänge |
|---|---|---|---|
SLHParams128s | 8,3 s | 75,0 s | 7856 Byte |
SLHParamsMini | < 0,1 s | 0,21 s | 1392 Byte |
Der Löwenanteil geht ins Signieren, nicht in die Schlüsselerzeugung: bei SLHParams128s entfallen rund 8 Sekunden auf KeyGen und rund 67 Sekunden auf Sign und Verify zusammen. Wer nur den Ablauf ausprobieren will, nimmt SLHParamsMini — derselbe Code, derselbe Ausgang, in einer Fünftelsekunde statt in gut einer Minute.
Es hängt nicht, es rechnet. Die Zeit geht in die Hash-Bäume; die Speicheranforderung ist seit dem Kleinspeicher-Pool in alloc nicht mehr der Engpass (#1258, #1319).
| Fassung | KeyGen SLHParams128s |
|---|---|
| 1.0.15G | 21 s |
| 1.0.16F | 11 s |
| vor dem Pool-Fix | 86 s |
| 1.0.17K bis 1.0.20A | 8,3–8,7 s |
Klassifikation: Asymmetrisches, hash-basiertes Signaturverfahren. Zustandslos (stateless) — keine Signaturzähler nötig wie bei XMSS/LMS.
import std.crypto.pqc.slhdsa;
→ std.crypto.pqc · std.crypto.pqc.pqc (High-Level API) · std.crypto
| Parametersatz | n | h | Quantensicherheit | SK | PK | Signatur | Empfehlung |
|---|---|---|---|---|---|---|---|
| SLH-DSA-SHA2-128s | 16 | 63 | ~128-Bit | 64 B | 32 B | 7856 B | Standardwahl |
| SLH-DSA-SHA2-256s | 32 | 64 | ~256-Bit | 128 B | 64 B | 29792 B | Höchste Sicherheit |
| Mini (nicht FIPS) | 16 | 4 | — | 64 B | 32 B | 1392 B | Nur für Tests |
Vergleich mit ML-DSA: SLH-DSA erzeugt größere Signaturen (7856 B vs. 3293 B für ~128-Bit), hat aber kleinere Schlüssel (PK nur 32 B). Vorteil: rein hash-basierte Sicherheitsannahmen, breit konservativ.
| Konstante | Wert | Bedeutung |
|---|---|---|
SLH_128S_SK | 64 | SK-Größe SLH-DSA-128s in Bytes |
SLH_128S_PK | 32 | PK-Größe SLH-DSA-128s in Bytes |
SLH_128S_SIG | 7856 | Signaturlänge SLH-DSA-128s in Bytes |
SLH_256S_SK | 128 | SK-Größe SLH-DSA-256s in Bytes |
SLH_256S_PK | 64 | PK-Größe SLH-DSA-256s in Bytes |
SLH_256S_SIG | 29792 | Signaturlänge SLH-DSA-256s in Bytes |
SLH_MINI_SIG | 1392 | Signaturlänge Mini-Params (nicht FIPS) |
SLH_PS | 96 | Größe des Parameter-Blocks in Bytes |
ADRS-Typ-Codes (intern, für eigene ADRS-Konstruktionen):
SLH_WOTS=0, SLH_WOTS_PK=1, SLH_TREE=2, SLH_FORS_TREE=3, SLH_FORS_ROOTS=4, SLH_WOTS_PRF=5, SLH_FORS_PRF=6
Parameter-Initialisierung (muss vor KeyGen/Sign/Verify aufgerufen werden):
| Funktion | Beschreibung |
|---|---|
SLHParams128s(ps) | Füllt 96-Byte-Parameterblock ps für SLH-DSA-SHA2-128s |
SLHParams256s(ps) | Füllt 96-Byte-Parameterblock ps für SLH-DSA-SHA2-256s |
SLHParamsMini(ps) | Füllt Parameterblock für Mini-Satz (n=16, h=4 — nur Tests, nicht FIPS-konform) |
Schlüssel und Signatur:
| Funktion | Beschreibung |
|---|---|
SLHDSAKeyGen(ps, skseed, skprf, pkseed, sk, pk) | Erzeugt Schlüsselpaar aus drei Seeds (je n Bytes). sk: SLH_xxx_SK Bytes; pk: SLH_xxx_PK Bytes. |
SLHDSASign(ps, sk, msg, mlen, optrand, sig): int64 | Signiert msg (mlen Bytes). optrand: 0 für deterministische Signatur (empfohlen). sig: caller-alloziert mit SLH_xxx_SIG Bytes. Gibt tatsächliche Signaturlänge zurück. |
SLHDSAVerify(ps, pk, msg, mlen, sig): int64 | Verifiziert Signatur. Gibt 1 bei gültig, 0 bei ungültig. |
import std.crypto.pqc.slhdsa;
import std.crypto.rand;
import std.alloc;
fn main(): int64 {
// Parameter-Block initialisieren (SLH-DSA-128s)
var ps: int64 := alloc(SLH_PS);
SLHParams128s(ps);
// Seeds: skseed[16], skprf[16], pkseed[16] (n=16 für 128s)
var seeds: int64 := alloc(48);
RandBytesExact(seeds, 48);
// Schlüsselpaar erzeugen
var sk: int64 := alloc(SLH_128S_SK);
var pk: int64 := alloc(SLH_128S_PK);
SLHDSAKeyGen(ps, seeds, seeds + 16, seeds + 32, sk, pk);
// Signieren
var msg: pchar := "Hello, SLH-DSA!"c;
var m_len: int64 := 15;
var sig: int64 := alloc(SLH_128S_SIG);
var sig_len: int64 := SLHDSASign(ps, sk, msg as int64, m_len, 0, sig);
// Verifizieren
var ok: int64 := SLHDSAVerify(ps, pk, msg as int64, m_len, sig);
// ok == 1 wenn gültig
free(ps, SLH_PS); free(seeds, 48);
free(sk, SLH_128S_SK); free(pk, SLH_128S_PK);
free(sig, SLH_128S_SIG);
return 0;
}
Hinweis: Für den einfachsten Einstieg → std.crypto.pqc.pqc verwenden (kein manuelles Parameter-Block-Management).
| Eigenschaft | Ergebnis |
|---|---|
| NIST-Standard | FIPS 205 (2024) — offiziell standardisiert |
| Sicherheitsannahme | Nur SHA-256-Kollisionsresistenz (konservativste aller PQC-Optionen) |
| Quantensicherheit | ~128-Bit (128s) / ~256-Bit (256s) |
| Signatur-Overhead | 7856 B (128s) — größer als ML-DSA, aber kleinster Public Key (32 B) |
| Zustandslos | Ja — keine Signaturzähler nötig (anders als XMSS/LMS) |
Letzte Aktualisierung: 2026-08-15 — Laufzeiten mit lyxc 1.0.20A neu gemessen, je Parametersatz getrennt nach KeyGen und Gesamtlauf (#1319)
Codebeispiele geprüft: gegen lyxc 1.2.5C übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen).