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(seed0x04))
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(mr_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(mr_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