std.crypto.ct

Constant-Time Utilities — timing-seitenkanal-freie Basisfunktionen für kryptographischen Code. Alle Operationen laufen in streng konstanter Zeit: keine datenbabhängigen Branches, kein datenabhängiges Memory-Access-Pattern. Intern genutzt von ML-KEM, ML-DSA und DADQ.

import std.crypto.ct;

std.crypto · Standard Library


Funktionen

Auswahl und Vergleich:

Funktion Signatur Beschreibung
CTSelect (a, b, mask): int64 Gibt a zurück wenn mask = 0xFFFF…FF, sonst b. Kein Branch.
CTEqual (a, b): int64 Gibt 0xFFFF…FF zurück wenn a == b, sonst 0.
CTIsZero (x): int64 Gibt 0xFFFF…FF zurück wenn x == 0, sonst 0.
CTMemEqual (a, b, len): int64 Vergleicht len Bytes ohne Early-Exit. Gibt 1 zurück wenn gleich.

Speicher:

Funktion Signatur Beschreibung
SecureZero (ptr, len) Überschreibt len Bytes mit 0. Nicht vom Compiler wegoptimiert (Barrier).

Modulare Arithmetik:

Funktion Signatur Beschreibung
CTBarrettReduce (a, q): int64 Barrett-Reduktion: a mod q ohne Division in konstanter Zeit. Nutzt 2³²/q-Approximation.
CTMontgomeryReduce (a, q, qinv): int64 Montgomery-Reduktion: a × R⁻¹ mod q. Erfordert qinv = q⁻¹ mod 2³².

Verwendungsbeispiele

Constant-Time Vergleich (kein Early-Exit):

import std.crypto.ct;

// Sicher: MAC-Vergleich in konstanter Zeit (keine Timing-Leaks)
var mac1: int64 := alloc(32);
var mac2: int64 := alloc(32);
// ... beide MACs berechnen ...
var equal: int64 := CTMemEqual(mac1, mac2, 32);   // 1 = gleich, 0 = verschieden
free(mac1, 32); free(mac2, 32);

CTSelect für branchlose Auswahl:

import std.crypto.ct;

// Wähle a oder b ohne if-Branch (wichtig in krypto-kritischen Schleifen):
var mask: int64 := CTEqual(condition, 1);   // 0xFFFFFFFFFFFFFFFF wenn condition==1
var result: int64 := CTSelect(a, b, mask);  // a wenn mask gesetzt, sonst b

SecureZero nach Schlüsselverwendung:

import std.crypto.ct;
import std.alloc;

var sk: int64 := alloc(576);
// ... Schlüssel verwenden ...
SecureZero(sk, 576);   // Schlüsselmaterial sicher löschen (nicht wegoptimiert)
free(sk, 576);


Warum Constant-Time?

Normaler Code wie if a == b { … } läuft auf modernen CPUs unterschiedlich lang je nach Daten (Branch-Predictor, Cache). Ein Angreifer kann daraus Rückschlüsse auf geheime Daten ziehen (Timing-Angriff).

CTMemEqual verwendet XOR aller Bytes und gibt das Ergebnis erst am Ende zurück — kein Early-Exit, immer gleiche Laufzeit.

CTSelect nutzt bitweise Maskierung statt eines if-Branches:

CTSelect(a, b, mask) = (a & mask) | (b & ~mask)

Letzte Aktualisierung: 2026-06-08