01 · Problem
Wofür braucht man das?
Simulationen und Tests benötigen reproduzierbare Folgen statt des globalen und nicht seedbaren Math.random.
02 · Denkmodell
Das mentale Modell
Ein Seed initialisiert einen endlichen Zustand. Jede Transition produziert einen Integer und den nächsten Zustand; Float- und Bereichsfunktionen sind sichere Abbildungen darauf.
LCG, Lagged Fibonacci, MT, Wichmann-Hill und XORShift sind angelegt. Die Basisklasse ignoriert ihren Seed, Seed-Hexkonvertierung verliert Daten und die Fortuna-Ausgabe bleibt Math.random statt kryptografisch.
03 · Kontrollfluss
Was passiert in welcher Reihenfolge?
- Seed auf eine feste, gültige Zustandsbreite normalisieren.
- Pro Abruf exakt eine deterministische State-Transition ausführen.
- Unsigned Integer in [0, 1) oder ohne Modulo-Bias in einen Integerbereich abbilden.
- Gewichtete Auswahl über positive Rohgewichte und kumulative Intervalle ausführen.
04 · Bauteile
Die entscheidenden Verträge
Seed
Bufferbasierter Seedcontainer mit fehleranfälliger Hexkonvertierung.
PseudoRandomNumberGenerator
Basisklasse für nextFloat und nextInt, nutzt aktuell Math.random.
MersenneTwister / XORShift / weitere Strategien
Konkrete Zustandsalgorithmen.
PseudoRandomItemSelector
Wählt Items anhand als Prozent interpretierten Gewichten.
05 · Build it yourself
Selbst implementieren
Ein Xorshift32 genügt als kleiner reproduzierbarer Generator; Sicherheit ist ausdrücklich nicht sein Ziel.
- Seed als von null verschiedenen uint32 normalisieren.
- State ausschließlich über die definierte Bittransition verändern.
- Durch 2^32 teilen, damit nextFloat niemals 1 ergibt.
class XorShift32 {
private state: number;
constructor(seed: number) { this.state = seed >>> 0 || 0x9e3779b9; }
nextUint32() {
let value = this.state;
value ^= value << 13;
value ^= value >>> 17;
value ^= value << 5;
return (this.state = value >>> 0);
}
nextFloat() { return this.nextUint32() / 0x1_0000_0000; }
}06 · Verifizieren
Was du testen solltest
- Gleiche Seeds liefern über viele Schritte exakt gleiche Folgen.
- Jeder Float liegt in [0, 1) und jede Integerabbildung im verlangten Bereich.
- Gewichtete Auswahl lehnt leere, negative, NaN- und vollständig nullgewichtete Listen ab.
07 · Grenzen
Kompromisse und Stolperfallen
- Kleine PRNGs sind schnell und statistisch begrenzt.
- Große Zustände verbessern Perioden, machen Snapshot und Restore teurer.
- Keiner dieser Algorithmen darf für Schlüssel, Tokens oder andere Sicherheitswerte verwendet werden.
Für Kryptografie ausschließlich crypto.getRandomValues oder node:crypto verwenden. Der Name Fortuna im Repository verspricht aktuell eine Sicherheit, die die Implementierung nicht liefert.
08 · Weiterdenken