std.crypto.pqc.dadq
DADQ (Dynamically Dimensioned Alternating Quasigroup Cryptosystem) ist ein symmetrisches Authenticated Cipher basierend auf algebraischen Quasigruppen (Latin Squares über Z₂₅₆). Es ist vollständig in Lyx implementiert ohne externe Bibliotheken.
Klassifikation: DADQ-SYM — symmetrische authentifizierte Verschlüsselung. Kein Public-Key-Schema (siehe AP-3.1 — Unmöglichkeitssatz). Für hybride PKE → DADQ-SYM + ML-KEM.
import std.crypto.pqc.dadq;
→ std.crypto · Standard Library
Hinweis: DADQ ist nicht von NIST evaluiert oder standardisiert. Für zertifizierte Post-Quantum-Kryptografie nach FIPS 203/204/205 → ML-KEM, ML-DSA, SLH-DSA.
Mathematischer Hintergrund
Die algebraische Grundstruktur ist ein Quasigruppen-System Q = (Z₂₅₆, ·) definiert durch eine 256×256 Latin-Square-Tabelle T:
T[a][b] := π[(a + b) mod 256]
wobei π eine geheime Permutation aus dem Seed ist. Latin-Square-Eigenschaft: jede Zeile und Spalte enthält jedes Element genau einmal — jede Operation ist bijektiv.
Verschlüsselung (DADQ-SYM, Phase-2-Schema):
r_seed <- CSPRNG(32 Bytes)
r[i] = DRBG(r_seed, i) (SHA256-basiert, auf m_len Bytes expandiert)
m_enc[i] = T_pub[m[i]][r[i]] (T_pub = sigma ∘ T_priv ∘ sigma_inv)
commit = r_seed XOR SHA256(m_enc)
hash_mr = SHA256(m || r_seed)
c = m_enc || commit || hash_mr
Entschlüsselung:
r_seed = SHA256(m_enc) XOR commit
r[i] = DRBG(r_seed, i)
sr = sigma_inv[r[i]]; sc = sigma_inv[m_enc[i]]
m[i] = sigma[T_priv_col_inv[sr][sc]]
verify: SHA256(m_dec || r_seed) == hash_mr
Ciphertext-Overhead: 64 Bytes (commit[32] + hash_mr[32]).
Der symmetrische Schlüssel ist master_seed (32 Bytes). dadqKeyGen leitet daraus sigma, sigma_inv, seed_T_priv und key_mac ab. T_pub wird on-demand aus diesen Feldern rekonstruiert.
Formale Sicherheitsanalyse
AP-3.1 — Härteannahmen und Klassifikation
Unmöglichkeitssatz (Latin-Square PKE):
Kein Latin-Square-basiertes PKE-Schema mit vollständig öffentlicher Tabelle T_pub ist OW-CPA-sicher. Begründung: col_inv(T_pub) ist stets in O(n²) berechenbar — bei n = 256 sind das 65.536 Operationen. Damit ist die Einweg-Eigenschaft einer öffentlichen Latin-Square-Tabelle nicht erfüllbar.
Konsequenz: DADQ wird als symmetrisches Authenticated Cipher (DADQ-SYM) formalisiert. T wird aus einem geheimen Seed on-demand erzeugt und ist niemals öffentlich.
Reduktion DADQ-SYM-OW ≤ₚ SHA256-Preimage (ROM-Modell):
Im Random-Oracle-Modell gilt: Jeder Algorithmus A, der DADQ-SYM mit Vorteil ε bricht (One-Way-Angriff auf den Klartext), kann als Subroutine genutzt werden, um SHA256 mit Vorteil ε zu invertieren. Das Commitment r XOR SHA256(m_enc) bindet r an m_enc; ohne SHA256-Preimage ist r nicht rekonstruierbar, und ohne r ist T_col_inv nicht anwendbar.
Für PKE: Hybridkonstruktion DADQ-SYM + ML-KEM empfohlen: ML-KEM kapselt den symmetrischen DADQ-Schlüssel (32-Byte master_seed); DADQ-SYM übernimmt die eigentliche Datenverschlüsselung.
AP-3.2 — Grover-Resistenz (Quantensicherheit)
Der Schlüsselraum von DADQ-SYM ist |K| = 2²⁵⁶ (master_seed = 32 Bytes aus CSPRNG).
Grovers Algorithmus halbiert den Suchexponenten:
Grover-Bound: √(2²⁵⁶) = 2¹²⁸ Quantenoperationen
Ergebnis: 128-Bit Quantensicherheit (äquivalent zu AES-256 gegen Grover).
Empirische Bestätigung: In 100 zufälligen Schlüsselpaaren wurden keine Kollisionen beobachtet (jeder master_seed erzeugt eine eindeutige Permutation π via Fisher-Yates/DRBG).
AP-3.3 — Dimensionsvarianz (seed_D)
Das Feld seed_D (sk[512..543]) dient als Dimensionsparameter. Seine statistische Qualität wurde mit dem NIST SP 800-22-Subset getestet:
0 / 50 Fehlschläge in Frequenz-Test und Block-Frequenz-Test
Formales Ergebnis: seed_D ist sicherheitsneutral — der Vorteil eines Angreifers mit Kenntnis von D ist nicht größer als ohne:
Adv(A mit D) ≤ Adv(A ohne D) + negl(λ)
Die ursprüngliche „Moving-Target-Defense“-Metapher (dynamisch wechselnde Dimension als Sicherheitsmerkmal) wird durch dieses Ergebnis ersetzt: seed_D erweitert den Schlüsselraum additiv, bietet aber keine eigenständige Sicherheitsgarantie jenseits der Latin-Square-Konstruktion.
Konstanten
| Konstante | Wert | Bedeutung |
|---|---|---|
DADQ_SEED_LEN | 32 | Master-Seed-Länge in Bytes (symmetrischer Schlüssel) |
DADQ_PK_LEN | 65536 | T_pub-Tabelle: 256×256 Bytes (volle Latin-Square, kein komprimierter Key) |
DADQ_SK_LEN | 544 | sigma(256) + sigma_inv(256) + seed_T_priv(32) — ohne key_mac |
DADQ_SK_LEN_FULL | 576 | Vollständiger SK inkl. key_mac[32] (sk[544..575]) |
DADQ_OVERHEAD | 64 | Ciphertext-Overhead: commit(32) + hash_mr(32) |
DADQ_TABLE_SZ | 65536 | Größe der 256×256-Byte Latin-Square-Tabelle |
DADQ_BLOCK_SZ | 16 | Interner Blockparameter |
DADQ_FO_SK_LEN | 608 | FO-SK: DADQ_SK_LEN_FULL(576) + key_fo(32) |
Funktionen
Schlüsselableitung:
| Funktion | Beschreibung |
|---|---|
dadqKeyGen(master_seed, pk, sk) | Leitet sk (576B) und T_pub (→ pk, 65536B) aus master_seed ab |
dadqKeyGenFull(master_seed, pk, sk) | Identisch mit dadqKeyGen — nur für API-Kompatibilität erhalten |
Puffer-Anforderungen:
- pk: mindestens DADQ_PK_LEN (65536) Bytes
- sk: mindestens DADQ_SK_LEN_FULL (576) Bytes (beide Funktionen)
SK-Layout: sk[0..255] = sigma · sk[256..511] = sigma_inv · sk[512..543] = seed_T_priv · sk[544..575] = key_mac
Verschlüsselung:
| Funktion | Beschreibung |
|---|---|
dadqEnc(pk, m, m_len, c) | Verschlüsselt m (m_len Bytes) → c (m_len + 32 Bytes) |
dadqEncAlloc(pk, m, m_len) | Wie dadqEnc, allokiert c-Puffer selbst, Rückgabe: Zeiger |
Entschlüsselung:
| Funktion | Beschreibung |
|---|---|
dadqDec(sk, c, c_len, m) | Entschlüsselt c → m. Rückgabe: 0=OK, -1=Authentifizierung fehlgeschlagen |
dadqDecAlloc(sk, c, c_len) | Wie dadqDec, allokiert m-Puffer selbst, Rückgabe: Zeiger oder 0 bei Fehler |
Symmetrischer Modus (DADQ-SYM, Phase 3):
T_pub bleibt intern — kein col_inv-Angriff möglich, da T_pub dem Angreifer unbekannt.
| Funktion | Beschreibung |
|---|---|
dadqSymKeyGen(seed, sk) | Leitet sk (576B) ab; T_pub wird intern erzeugt und nicht zurückgegeben |
dadqSymEnc(sk, m, m_len, c) | Verschlüsselt mit sk; T_pub wird intern abgeleitet |
dadqSymDec(sk, c, c_len, m): int64 | Entschlüsselt; identisch mit dadqDec |
Fujisaki-Okamoto Transform (DADQ-FO, Phase 4 — IND-CCA2):
r_seed ist deterministisch: r_seed = HMAC-SHA256(key_fo, m). Ermöglicht Wiederverschlüsselung → CCA2-Sicherheit im ROM (FO-Theorem).
| Funktion | Beschreibung | ||
|---|---|---|---|
dadqFOKeyGen(master_seed, sk_fo) | Leitet sk_fo (608B) ab: sk(576B) + key_fo(32B, SHA256(seed | 0x04)) | |
dadqFOKeyGenRand(sk_fo) | Wie dadqFOKeyGen mit internem CSPRNG-Seed; Seed wird nach Ableitung gelöscht | ||
dadqFOEnc(sk_fo, m, m_len, c) | Verschlüsselt deterministisch (r_seed via HMAC) | ||
dadqFODec(sk_fo, c, c_len, m): int64 | Entschlüsselt; prüft HMAC(key_fo, m_dec) == r_seed und SHA256(m | r_seed) == hash_mr (CT) | |
Implementierungshärtung (Phase 6):
| Funktion | Beschreibung |
|---|---|
dadqZeroize(buf, n) | Überschreibt n Bytes mit 0 (sichere Speicherlöschung, AP-6.3) |
dadqValidateSeed(seed): int64 | Prüft 32-Byte-Seed auf schwache Werte (all-zero, alle Bytes identisch); 0=OK, -1=schwach (AP-6.2) |
Hilfsfunktionen:
| Funktion | Beschreibung |
|---|---|
dadqFreeCtx(p, sz) | Gibt allokierten Puffer frei (null-safe) |
Verwendungsbeispiele
Basis-API (dadqKeyGen + dadqEnc/Dec):
import std.crypto.pqc.dadq;
import std.crypto.rand;
import std.alloc;
fn main(): int64 {
// Symmetrischer Schlüssel: 32 Bytes CSPRNG-Zufall
var master_seed: int64 := alloc(DADQ_SEED_LEN);
RandBytesExact(master_seed, DADQ_SEED_LEN);
// Schlüssel ableiten — pk = T_pub (65536 Bytes!), sk = 576 Bytes
var pk: int64 := alloc(DADQ_PK_LEN); // 65536 Bytes
var sk: int64 := alloc(DADQ_SK_LEN_FULL); // 576 Bytes
dadqKeyGen(master_seed, pk, sk);
// Verschlüsseln (Overhead = 64 Bytes: commit + hash_mr)
var msg: pchar := "Hello, DADQ!"c;
var m_len: int64 := 12;
var c: int64 := dadqEncAlloc(pk, msg as int64, m_len);
var c_len: int64 := m_len + DADQ_OVERHEAD; // + 64
// Entschlüsseln — gibt 0 zurück wenn Authentifizierung OK
var m_out: int64 := dadqDecAlloc(sk, c, c_len);
dadqFreeCtx(m_out, m_len);
dadqFreeCtx(c, c_len);
free(sk, DADQ_SK_LEN_FULL);
free(pk, DADQ_PK_LEN);
free(master_seed, DADQ_SEED_LEN);
return 0;
}
FO-Modus (IND-CCA2, empfohlen für neue Anwendungen):
import std.crypto.pqc.dadq;
import std.alloc;
fn main(): int64 {
// sk_fo intern mit CSPRNG-Seed ableiten (sicherste Variante)
var sk_fo: int64 := alloc(DADQ_FO_SK_LEN); // 608 Bytes
dadqFOKeyGenRand(sk_fo);
var msg: pchar := "Hello, FO!"c;
var m_len: int64 := 10;
var c_len: int64 := m_len + DADQ_OVERHEAD;
var c: int64 := alloc(c_len);
dadqFOEnc(sk_fo, msg as int64, m_len, c);
var m_out: int64 := alloc(m_len);
var rc: int64 := dadqFODec(sk_fo, c, c_len, m_out);
dadqZeroize(sk_fo, DADQ_FO_SK_LEN);
free(m_out, m_len);
free(c, c_len);
free(sk_fo, DADQ_FO_SK_LEN);
return rc;
}
Sicherheitseigenschaften im Überblick
| Eigenschaft | Ergebnis | ||
|---|---|---|---|
| Klassifikation | Symmetrisches Authenticated Cipher (DADQ-SYM) | ||
| OW-CPA Latin-Square PKE | Unmöglich — col_inv(T_pub) in O(n²) | ||
| OW-Reduktion | DADQ-SYM-OW ≤ₚ SHA256-Preimage (ROM) | ||
| Klassische Sicherheit | 256-Bit (Schlüsselraum 2²⁵⁶) | ||
| Quantensicherheit (Grover) | 128-Bit (Grover-Bound: 2¹²⁸ QOps) | ||
| seed_D (Dimensionsvarianz) | Sicherheitsneutral; NIST SP 800-22: 0/50 Fehlschläge | ||
| Authentifizierung | SHA256(m | r_seed) == hash_mr + HMAC-Check (FO); constant-time; -1 bei Manipulation | |
| Gröbner-Basis über GF(2⁸) | Polynomgrad von T ≈ 255 — praktisch unpraktikabel | ||
| IND-CCA2 | dadqFODec via FO-Transform (Phase 4); deterministisches r_seed via HMAC | ||
| PKE-Einsatz | Hybrid: DADQ-SYM + ML-KEM (ML-KEM kapselt master_seed) | ||
| NIST-Standardisierung | Keine — experimentell | ||
Letzte Aktualisierung: 2026-06-08
