Powrót do strony głównej

PRNG na 12 timerach PHP: entropia 7.1 bita

Klasa ChaosRNG realizuje PRNG na 12 timerach do generowania bajtów z entropią 7.1+ bitów. Timery wprowadzają nieliniowość poprzez pauzy, pominięcia i modulację. Nadaje się do eksperymentów z tokenami.

PHP PRNG: 12 timerów dla 7+ bitów entropii
Advertisement 728x90

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:

Google AdInline article slot
  • 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.

Google AdInline article slot

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

Advertisement 728x90

Czytaj dalej