Generator pseudolosowych bajtów oparty na 12 czasomierzach w PHP
Klasa ChaosRNG wykorzystuje 12 wzajemnie powiązanych czasomierzy do generowania bajtów z entropią do 7.1–8 bitów na symbol. Każdy czasomierz wprowadza nieliniowość: od podstawowego czasu i nanosekund do pauz i wstawiania zerowych bajtów. To eksperymentalne podejście dla zadań, które nie wymagają certyfikowanych prymitywów kryptograficznych.
Konstruktor inicjalizuje stan przez XOR mikrosekund (T1), nanosekund (T2), PID i pamięci (T7). Współczynnik zakrzywienia zaczyna się od 1.001, wyłącznik jest włączony domyślnie.
Logika czasomierzy
Czasomierze formują potok przetwarzania:
- T1: mikrosekundy od 1970 roku.
- T2: nanosekundy od uruchomienia systemu.
- T3: aktualizacja 64-bitowego stanu — dodanie lub odjęcie młodszego bajtu sumy.
- T4: modulacja czasu przez mnożenie/dzielenie przez współczynnik k, aktualizowany każdy takt.
- T5: określa segmenty (1000–10000).
- T6: wybiera segment do ważenia czasu.
- T7: dżitter cache i przerwań przez PID i pamięć.
- T8: wyłącznik — pomijanie rzeczywistych bajtów w wyłączonym stanie.
- T9: zarządza T8 na podstawie ostatniego bajta (<5 — włącz, >5 — wyłącz).
- T10: ukryty punkt startu w konstruktorze.
- T11: wstawienie 0x00 przy ($state & 10) === 0.
- T12: pauzy 1–100 taktów z aktualizacją stanu podczas oczekiwania.
/**
* ChaosRNG - generator losowych bajtów z 12 czasomierzami
*
* 12 czasomierzy:
* T1 – zwykłe zegary (microtime)
* T2 – dokładne zegary (hrtime)
* T3 – pamięć (stan $state)
* T4 – zakrzywiacz (mnoży/dzieli czas)
* T5 – segmentator (liczba segmentów 1000-10000)
* T6 – wybieracz (wybór segmentu)
* T7 – ukryty szum (dżitter, przerwania)
* T8 – wyłącznik (wł/wył wydania)
* T9 – obserwator (zarządza wyłącznikiem)
* T10 – punkt startowy (moment inicjalizacji)
* T11 – punkt (wstawienie zerowego bajta)
* T12 – milczek (pauzy 1-100 taktów)
*/
class ChaosRNG {
// Właściwości klasy
private $state; // T3: 64-bitowy stan
private $k; // T4: współczynnik zakrzywienia
private $enabled; // T8: wyłącznik (wł/wył)
private $lastByte; // T9: ostatni wydany bajt
private $dot; // T11: flaga punktu
private $pauseLen; // T12: długość pauzy
private $pauseRem; // T12: reszta pauzy
/**
* Konstruktor — T10 (punkt startowy)
* Mieszamy wszystko, czego nie można powtórzyć
*/
public function __construct() {
// XOR wszystkich źródeł → unikalny stan początkowy
$this->state = (int)(microtime(true) * 1000000) // T1: mikrosekundy
^ hrtime(true) // T2: nanosekundy
^ getmypid() // T7: PID procesu
^ memory_get_usage(); // T7: użyta pamięć
$this->k = 1.001; // T4: początkowy współczynnik
$this->enabled = true; // T8: wyłącznik włączony
$this->lastByte = 0; // T9: ostatniego bajtu nie ma
$this->dot = false; // T11: punkt nie wstawiony
$this->pauseLen = 0; // T12: brak pauzy
$this->pauseRem = 0; // T12: reszta pauzy = 0
}
/**
* T1: zwykłe zegary
* Zwraca mikrosekundy od 1970 roku
*/
private function t1() {
return (int)(microtime(true) * 1000000);
}
/**
* T2: dokładne zegary
* Zwraca nanosekundy od uruchomienia systemu
*/
private function t2() {
return hrtime(true);
}
/**
* Wewnętrzny generator bajtu (T3-T7)
* Zmienia stan i zwraca jeden bajt
*/
private function nextByteInternal() {
// T5: liczba segmentów od 1000 do 10000
$K = 1000 + ($this->state % 9001);
// T6: wybór konkretnego segmentu
$slot = (($this->state >> 8) % $K);
// T1 i T2: pobieramy aktualny czas
$t1 = $this->t1();
$t2 = $this->t2();
// T4: zakrzywiacz (rozciągamy lub ściskamy czas)
if ($this->state & 1) {
$t1 = $t1 * $this->k; // rozciągamy T1
} else {
$t2 = $t2 / $this->k; // ściskamy T2
}
// Sumujemy z uwzględnieniem wybranego segmentu
$total = (int)($t1 * ($slot + 1) / $K)
+ (int)($t2 * ($slot + 1) / $K);
// T3: aktualizujemy stan (dodajemy lub odejmujemy)
if ($total & 1) {
$this->state += ($total & 0xFF);
} else {
$this->state -= ($total & 0xFF);
}
// Aktualizujemy współczynnik zakrzywienia
$this->k = 1.0 + (($this->state & 0xFF) / 10000.0);
// Zwracamy młodszy bajt stanu
return $this->state & 0xFF;
}
/**
* Publiczna metoda: pobierz N losowych bajtów
* Uwzględnia wszystkie 12 czasomierzy
*/
public function getBytes($n) {
$out = [];
for ($i = 0; $i < $n; $i++) {
// T12: pauza (milczek)
while ($this->pauseRem > 0) {
$this->pauseRem--;
$this->nextByteInternal(); // stan się zmienia
}
// Jeśli pauza zakończona — generujemy nową
if ($this->pauseRem === 0 && $this->pauseLen === 0) {
$this->pauseLen = 1 + ($this->state % 100); // 1-100 taktów
$this->pauseRem = $this->pauseLen;
}
// T11: punkt (wstawienie zerowego bajta)
if (($this->state & 10) === 0 && !$this->dot) {
$this->dot = true;
$this->nextByteInternal();
$out[] = 0x00; // punkt = zerowy bajt
continue;
}
$this->dot = false;
// T9: obserwator za wyłącznikiem
if ($this->lastByte < 5) {
$this->enabled = true; // włączamy
} elseif ($this->lastByte > 5) {
$this->enabled = false; // wyłączamy
}
// jeśli równy 5 — nic nie zmieniamy
// Generujemy bajt
$byte = $this->nextByteInternal();
// T8: wyłącznik
if (!$this->enabled) {
// Jeśli wyłączony — wydajemy fikcyjny bajt
$out[] = $this->nextByteInternal() & 0xFF;
continue;
}
// Zapisujemy ostatni wydany bajt
$this->lastByte = $byte;
// Resetujemy pauzę po wydaniu rzeczywistego bajtu
if ($this->pauseLen > 0) {
$this->pauseLen = 0;
$this->pauseRem = 0;
}
$out[] = $byte;
}
return $out;
}
}
Obliczanie entropii Shannona
Metoda statyczna entropy() oblicza entropię za pomocą wzoru -Σ p * log2(p) dla częstotliwości bajtów. Test na 64 KB danych pokazuje średnio 7.12 bitu.
public static function entropy($bytes) {
// Liczymy częstotliwość każdego bajtu
$freq = array_fill(0, 256, 0);
foreach ($bytes as $b) {
$freq[$b]++;
}
// Wzór Shannona: -Σ p * log2(p)
$e = 0;
$total = count($bytes);
foreach ($freq as $c) {
if ($c > 0) {
$p = $c / $total;
$e -= $p * log($p, 2);
}
}
return $e;
}
// Test
$rng = new ChaosRNG();
$data = $rng->getBytes(65536);
$entropy = ChaosRNG::entropy($data);
echo "Entropia: " . round($entropy, 4) . " / 8 bitów\n";
Nieliniowość i odporność
Odzyskanie stanu wymaga wiedzy o k, liczbie segmentów, pauzach, pozycji wyłącznika. Stan w 64 bitach komplikuje ataki bez dostępu do serwera. Entropia >6.5 bitów nawet na wirtualnych maszynach sprawia, że sekwencja jest statystycznie bliska losowej.
Zastosowanie: generowanie tokenów, haseł (16 znaków ~113 bitów entropii). Nie dla kryptografii — tylko eksperymenty.
Co jest ważne
- 12 czasomierzy tworzy nieliniowy potok z pauzami i pominięciami dla skomplikowania analizy.
- Entropia Shannona 7.1+ bitów na bajt, test na 64 KB.
- T12 (pauzy) i T11 (zera) łamią czasową i sekwencyjną przewidywalność.
- Stan 64 bity — kompromis między odpornością a szybkością.
- Nie używać w produkcji krypto: eksperymentalny PRNG.
— Editorial Team
Brak komentarzy.