Generátor náhodných čísel založený na instrukcích RDSEED a RDRAND

14. 8. 2025
Doba čtení: 28 minut

Sdílet

Autor: Depositphotos
V informatice existuje několik oblastí, ve kterých je nutné používat generátory náhodných nebo alespoň pseudonáhodných hodnot. Moderní procesory s architekturou x86–64 pro tento účel nabízí instrukce RDRAND a RDSEED.

Obsah

1. Generátor náhodných čísel založený na instrukcích RDSEED a RDRAND

2. Detekce podpory instrukce RDRAND mikroprocesorem

3. První demonstrační příklad: zjištění, zda mikroprocesor podporuje instrukci RDRAND

4. Výsledky získané pro čip Intel Core i7–1270P

5. Přečtení náhodné hodnoty instrukcí RDRAND

6. Druhý demonstrační příklad – realizace volání instrukce RDRAND v assembleru

7. Otestování, že instrukce RDRAND pokaždé vrátí odlišnou hodnotu

8. Instrukce RDRAND ve vyšších programovacích jazycích

9. Vestavěné funkce v GCC umožňující volání instrukce RDRAND

10. Demonstrační příklad – přečtení a výpis sekvence deseti náhodných 32bitových hodnot

11. Způsob překladu demonstračního příkladu do assembleru

12. Jak kvalitní je sekvence náhodných čísel získaná opakovaným voláním RDRAND?

13. Program pro vygenerování binárního souboru s (pseudo)náhodným obsahem

14. Vygenerování binárního souboru s jedním milionem 32bitových pseudonáhodných hodnot

15. Projekt s implementací metrik pro otestování (pseudo)náhodných hodnot

16. Otestování hodnot vygenerovaných instrukcí RDRAND

17. Porovnání výsledků s výsledky deterministického generátoru pseudonáhodných hodnot

18. Příloha: pomocné soubory s makry a subrutinami použitými v příkladech napsaných v assembleru

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Generátor náhodných čísel založený na instrukcích RDSEEDRDRAND

V informatice existuje hned několik oblastí, ve kterých je nutné používat generátory náhodných nebo alespoň pseudonáhodných hodnot. Jedná se například o kryptografii (šifrování, generování klíčů atd.), ale taktéž o online kasina (nebo podobné hry pro velké množství hráčů založené na náhodě – zde kvalitní generátor náhodných čísel pomáhá kasinu, ne hráčům). A právě zda narážíme na poněkud kuriózní situaci: i když se to nemusí při každodenní práci s počítači zdát, tato zařízení jsou deterministická a je tedy relativně složité vypočítat (resp. získat) skutečně náhodné hodnoty. Proto se velmi často používají deterministické generátory pseudonáhodných hodnot, což však nemusí být dostatečně silné řešení.

Samozřejmě je možné i v běžném počítači například přečíst šum z mikrofonního vstupu (apod.), ovšem není úplně snadné dokázat, že výsledkem budou náhodné hodnoty a ne například výsledek deterministické činnosti A/D převodníku (existuje hned několik možností zkreslení). Navíc se jedná o dosti pomalé operace. I z těchto důvodů se do moderních PC přidávají obvody určené pro získání skutečně náhodných hodnot. Buď se jedná o různé přídavné karty (s příslušnými ovladači), nebo je možné využít nové instrukce nazvané RDSEED a RDRAND, kde prefix RD značí „read“.

Instrukce RDSEED slouží k přečtení skutečně náhodné sekvence bitů z nějakého vhodného zdroje náhodnosti, který může být umístěn přímo v mikroprocesoru nebo v čipové sadě. Kvůli přímému čtení ze zdroje náhodnosti (typicky se využívá senzor tepelného šumu) může být tato instrukce relativně pomalá; na druhou stranu se však jedná o skutečně náhodné hodnoty. Vzhledem k tomu, že může být k dispozici pouze jediný senzor tepelného šumu, bude se sdílet mezi všemi jádry mikroprocesoru. To ještě více přispívá k tomu, že je tato instrukce relativně pomalá.

Druhá instrukce se jmenuje RDRAND. Ta přečte – a to obecně velmi rychle – hodnotu vrácenou generátorem pseudonáhodných hodnot. To se může zdát jako cesta zpět k deterministickým algoritmům, ale tento generátor je vždy po maximálně 511 čteních restartován, přičemž je do něj předáno nové semínko (seed) získané podobně jako u instrukce RDSEED ze specializovaného obvodu. Interně použitý generátor pseudonáhodných hodnot je poměrně sofistikovaný, takže (společně s tím, že je periodicky nastavován) splňuje například NIST SP 800–90A.

Dnes se zaměříme na instrukci RDRAND, kterou lze zavolat jak přímo z assembleru, tak i z vyšších programovacích jazyků.

2. Detekce podpory instrukce RDRAND mikroprocesorem

Společně s přidáváním dalších rozšiřujících instrukčních sad pro platformu 80×86 se objevila nutnost zjištění, zda daný mikroprocesor nějakou rozšiřující instrukční sadu podporuje či nikoli. Pro tento účel se používá instrukce CPUID, s níž jsme se již v tomto seriálu několikrát setkali. Tuto instrukci použijeme pro získání informací kategorie číslo 0 a 1. O kterou kategorii se má jednat zadáme v registru EAX před zavoláním CPUID:

        mov eax, kategorie
        cpuid                        ; naplneni EDX, ECX a EBX

Pro kategorii 0 se ve trojici registrů EBX, EDX a ECX (v tomto pořadí) vrátí dvanáctiznakový řetězec s identifikací mikroprocesoru. Současně se v registru EAX vrátí číslo nejvyšší dostupné kategorie.

Z pohledu podpory či nepodpory instrukce RDRAND je důležitá první kategorie. V registru ECX se vrátí bitová pole, z nichž je možné vyčíst, která instrukční sada je podporována a která naopak nikoli. Konkrétně podpora instrukce RDRAND je uložena v bitu číslo 30. Následuje příklad použití CPUID pro rozeskok na základě (ne)podpory instrukce RDRAND:

        mov eax, 1                   ; prvni kategorie
        cpuid                        ; naplneni EDX a ECX
        bt ecx, 30                   ; test bitu cislo 30: podpora RDRAND
        jnc rdrand_not_supported
        print_string  rdrand_supported, rdrand_supported_length
rdrand_not_supported:
        ...
        ...
        ...

3. První demonstrační příklad: zjištění, zda mikroprocesor podporuje instrukci RDRAND

V dnešním prvním demonstračním příkladu si ověříme, jestli mikroprocesor skutečně podporuje instrukci RDRAND. Použijeme k tomu postup popsaný v předchozí kapitole, tj. analýzu bitových polí vracených instrukcí CPUID. Nejdříve se podívejme na zdrojový kód příkladu a posléze si ukážeme výsledky pro konkrétní mikroprocesor:

[bits 32]
 
%include "linux_macros.asm"
 
;-----------------------------------------------------------------------------
section .data
 
hex_message:
         times 8 db '?'
         db ' '
         hex_message_length equ $ - hex_message
 
rdrand_supported:
         db 10, "RDRAND supported"
         rdrand_supported_length equ $ - rdrand_supported
 
;-----------------------------------------------------------------------------
section .bss
 
id_string: resb 12
 
 
;-----------------------------------------------------------------------------
section .text
        global _start                ; tento symbol ma byt dostupny i linkeru
 
_start:
        ; ziskani indexu nejvyssi volatelne funkce CPUID
        xor eax, eax                 ; nulta kategorie
        cpuid
        mov     edx, eax             ; hodnota, ktera se ma vytisknout
        mov     ebx, hex_message     ; buffer, ktery se zaplni hexa cislicemi
        call    hex2string           ; zavolani prislusne subrutiny
        print_string   hex_message, hex_message_length    ; tisk hexadecimalni hodnoty
 
        ; test podpory RDRAND
        mov eax, 1                   ; prvni kategorie
        cpuid
        mov     ebx, hex_message     ; buffer, ktery se zaplni hexa cislicemi
        call    hex2string           ; zavolani prislusne subrutiny
        print_string   hex_message, hex_message_length    ; tisk hexadecimalni hodnoty
 
        ; vypis CPU ID
        xor eax, eax                 ; nulta kategorie
        cpuid
        mov [id_string], ebx         ; prvni ctyri znaky ID
        mov [id_string+4], edx       ; dalsi ctyri znaky ID
        mov [id_string+8], ecx       ; posledni ctyri znaky ID
        print_string id_string, 12   ; tisk 12 znaku CPU ID
 
        mov eax, 1                   ; prvni kategorie
        cpuid                        ; naplneni EDX a ECX
        bt ecx, 30                   ; test bitu cislo 30: podpora RDRAND
        jnc rdrand_not_supported
        print_string  rdrand_supported, rdrand_supported_length
rdrand_not_supported:
 
        exit                         ; ukonceni procesu
 
 
%include "hex2string.asm"
Poznámka: pro překlad a slinkování se použijí příkazy:
$ nasm -felf rdrand_support.asm -o rdrand_support.o
 
$ ld -melf_i386 rdrand_support.o -o rdrand_support

4. Výsledky získané pro čip Intel Core i7–1270P

V mém konkrétním případě (Intel Core i7–1270P) se po překladu a spuštění tohoto demonstračního příkladu vypíšou následující dva řádky:

00000020 BFEBFBFF GenuineIntel
RDRAND supported

Na prvním řádku je hexadecimálně zobrazen nejvyšší index volatelné funkce CPU ID (0×20), dále bitové pole s první kategorií podporovaných vlastností a poté již obsah registrů EBX, EDX a ECX s dvanáctiznakovou identifikací výrobce a (zhruba) modelu. Na druhém řádku se zobrazí informace o tom, že instrukce RDRAND je skutečně podporována.

5. Přečtení náhodné hodnoty instrukcí RDRAND

Samotná instrukce RDRAND – pochopitelně pokud je podporována – má tři různé operační kódy, které se odlišují podle toho, jestli se má vracet šestnáctibitová, 32bitová či dokonce 64bitová hodnota do zvoleného pracovního registru r16, r32 nebo r64:

Operační kód 64bit režim 32bit režim Stručný popis
NFx 0F C7 /6 RDRAND r16 ano ano vrací se šestnáctibitová náhodná hodnota
NFx 0F C7 /6 RDRAND r32 ano ano vrací se 32bitová náhodná hodnota
NFx REX.W + 0F C7 /6 RDRAND r64 ano ne vrací se 64bitová náhodná hodnota
Poznámka: pokud instrukce proběhne v pořádku (tedy v případě, že je podporována), nastaví se příznak přenosu CF na jedničku. V opačném případě je registr vynulován a příznak přenosu se nastaví na nulu. Ostatní příznakové bity OF, SF, ZF, AF a PF jsou vynulovány.

6. Druhý demonstrační příklad – realizace volání instrukce RDRAND v assembleru

Základní způsob použití instrukce RDRAND je ukázán v dnešním druhém demonstračním příkladu. Po jeho překladu a spuštění se instrukcí RDRAND vygeneruje 32bitová náhodná hodnota, která se zapíše do pracovního registru EDX. Následně je obsah tohoto registru vypsán v hexadecimální podobě (maximálně se bude jednat o osm hexadecimálních cifer) na standardní výstup. Realizace pro operační systém Linux může vypadat následovně:

[bits 32]
 
%include "linux_macros.asm"
 
;-----------------------------------------------------------------------------
section .data
 
hex_message:
         times 8 db '?'
         db 0x0a
         hex_message_length equ $ - hex_message
 
;-----------------------------------------------------------------------------
section .bss
 
 
;-----------------------------------------------------------------------------
section .text
        global _start                ; tento symbol ma byt dostupny i linkeru
 
_start:
        rdrand  edx                  ; ziskat pseudonahodnou hodnotu
        mov     ebx, hex_message     ; buffer, ktery se zaplni hexa cislicemi
        call    hex2string           ; zavolani prislusne subrutiny
        print_string   hex_message, hex_message_length    ; tisk hexadecimalni hodnoty
 
        exit                         ; ukonceni procesu
 
 
%include "hex2string.asm"

Příklad výstupu:

E570968D
Poznámka: pro překlad a slinkování se použijí příkazy:
$ nasm -felf rdrand_read.asm -o rdrand_read.o
 
$ ld -melf_i386 rdrand_read.o -o rdrand_read

7. Otestování, že instrukce RDRAND pokaždé vrátí odlišnou hodnotu

V úvodní kapitole jsme si řekli, že instrukce RDRAND při každém zavolání vrátí nějakou pseudonáhodnou hodnotu. Ověřme si tedy, že skutečně nedostáváme konstantní hodnoty. Pro tento účel zavoláme RDRAND v počítané programové smyčce, kterou založíme na čítači uloženém v registru ECX a instrukci LOOP, která sníží hodnotu v čítači a dokud se nedosáhne nuly, provede se další iterace:

        mov     ecx, 10              ; pocitadlo smycky
rand:
        ... volání RDRAND ...
        ... výpis hexadecimální hodnoty ...
        loop    rand                 ; opakovat smycku

V praxi bude nutné hodnotu čítače uložit před výpisem hexadecimální hodnoty, protože tento kód modifikuje obsah registru ECX. Samozřejmě můžeme ECX uložit na zásobník a poté ho obnovit:

        mov     ecx, 10              ; pocitadlo smycky
rand:
        push    ecx                  ; uchovat hodnotu pocitadla
        ... volání RDRAND ...
        ... výpis hexadecimální hodnoty ...
        pop     ecx                  ; obnovit hodnotu pocitadla
        loop    rand                 ; opakovat smycku

Úplný zdrojový kód takto upraveného demonstračního příkladu vypadá následovně:

[bits 32]
 
%include "linux_macros.asm"
 
;-----------------------------------------------------------------------------
section .data
 
hex_message:
         times 8 db '?'
         db 0x0a
         hex_message_length equ $ - hex_message
 
;-----------------------------------------------------------------------------
section .bss
 
 
;-----------------------------------------------------------------------------
section .text
        global _start                ; tento symbol ma byt dostupny i linkeru
 
_start:
        mov     ecx, 10              ; pocitadlo smycky
rand:
        push    ecx                  ; uchovat hodnotu pocitadla
 
        rdrand  edx                  ; ziskat pseudonahodnou hodnotu
        mov     ebx, hex_message     ; buffer, ktery se zaplni hexa cislicemi
        call    hex2string           ; zavolani prislusne subrutiny
        print_string   hex_message, hex_message_length    ; tisk hexadecimalni hodnoty
 
        pop     ecx                  ; obnovit hodnotu pocitadla
        loop    rand                 ; opakovat smycku
 
        exit                         ; ukonceni procesu
 
 
%include "hex2string.asm"

Příklad výstupu:

B2FF885E
C07C2AA4
61B3E170
FA24F24B
57B51A51
9640F86D
180239A6
9B045C83
E039159D
E01952DD
Poznámka: při každém spuštění pochopitelně dostaneme zcela odlišnou sekvenci.

8. Instrukce RDRAND ve vyšších programovacích jazycích

Prozatím jsme si ukázali, jakým způsobem je možné instrukci RDRAND volat z programů psaných v assembleru. Jedná se o neprivilegovanou instrukci, takže její volání je vlastně velmi jednoduché. Ovšem v assembleru se v současnosti píše jen relativně malé množství kódu, takže bude zajímavé zjistit, zda a jak lze RDRAND zavolat z vyšších programovacích jazyků, zejména z céčka. Pokud totiž bude volání z jazyka C podporováno, je tím prakticky zajištěna i podpora v dalších vyšších programovacích jazycích, které většinou dokážou s jazykem C poměrně dobře kooperovat (Rust, Python, Go, do jisté míry i Java atd.). Dále uvedené ukázky jsou odladěny pro GNU C Compiler, ovšem zcela stejný postup lze aplikovat i v dalších překladačích, zejména v Clangu.

9. Vestavěné funkce v GCC umožňující volání instrukce RDRAND

Překladač GCC (a ovšem i některé další překladače céčka) podporují zápis programů, které interně volají instrukci RDRAND, a to bez toho, aby bylo nutné používat assembler. Konkrétně v GCC je dostupná trojice vestavěných funkcí, které po svém zavolání naplní obsah paměťového místa, jehož adresa je uvedena v jediné parametru funkci. „Pravou“ návratovou hodnotou je informace o tom, zda se volání podařilo či nikoli:

# Typ návratové hodnoty Jméno vestavěné funkce Parametr
1 unsigned int __builtin_ia32_rdrand16_step unsigned short *
2 unsigned int __builtin_ia32_rdrand32_step unsigned int *
3 unsigned int __builtin_ia32_rdrand64_step unsigned long long *

Pozor si ovšem musíme dát na to, že výše uvedenou trojici funkcí je možné volat pouze v případě, že při překladu (nikoli až při linkinku) použijeme přepínač -mrdrnd nebo specifikujeme takovou architekturu cílového CPU, která tuto instrukci podporuje. V případě, že bude jeden z těchto přepínačů použit, povede volání libovolné z těchto funkcí k vygenerování strojového kódu s instrukcí RDRAND:

$ gcc --target-help |grep mrdrnd
 
-mrdrnd                     Support RDRND built-in functions and code generation.

10. Demonstrační příklad – přečtení a výpis sekvence deseti náhodných 32bitových hodnot

Zatímco demonstrační příklady z první poloviny článku byly psané v assembleru mikroprocesorů s architekturou x86–64, budou další příklad psány v céčku (konkrétně v ANSI C, ale to je již detail). Následující příklad se po svém překladu a spuštění pokusí přečíst deset náhodných 32bitových hodnot a ty následně vypíše na terminál. Současně vypíše i příznak úspěšnosti či naopak neúspěšnosti přečtení těchto hodnot. Pokud je instrukce RDRAND podporována, mělo by být její volání úspěšné (nevyžaduje žádná privilegia):

#include <stdio.h>
#include <stdint.h>
 
int main(void) {
    int success;
    uint32_t int random_value;
    int i;
 
    for (i=0; i<10; i++) {
        success = __builtin_ia32_rdrand32_step(&random_value);
        printf("%d %x\n", success, random_value);
    }
    return 0;
}

V případě, že při překladu neuvedeme přepínač -mrdrnd, vypíše překladač chybu, protože nebude vestavěnou funkci __builtin_ia32_rdrand32_step podporovat (viz předchozí kapitolu). Toto chování si můžeme velmi snadno ověřit:

$ gcc rnrand_read.c

Výsledek pokusu o překlad našeho demonstračního příkladu dopadne neslavně:

rnrand_read.c: In function ‘main’:
rnrand_read.c:9:19: error: implicit declaration of function ‘__builtin_ia32_rdrand32_step’; did you mean ‘__builtin_ia32_rdtscp’? [-Wimplicit-function-declaration]
    9 |         success = __builtin_ia32_rdrand32_step(&random_value);
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                   __builtin_ia32_rdtscp

Korektní překlad bude realizován pouze po použití přepínače -mrdrnd. Vestavěné funkce budou dostupné v libovolné verze jazyka C, a to včetně ANSI C/C89:

$ gcc -mrdrnd -ansi -Wall -Werror rnrand_read.c

Výsledek by mohl vypadat následovně:

1 d49a35f7
1 563c3fd0
1 9c3fe577
1 34ee6930
1 68c498ee
1 1d38cc2f
1 244349d6
1 50f16a09
1 1324b913
1 af34d82c
Poznámka: díky tomu, že je generátor náhodných čísel vždy znovu inicializován, je prakticky jisté, že nikdy nezískáte výše uvedenou sekvenci hodnot.

11. Způsob překladu demonstračního příkladu do assembleru

Ověřme si ještě, zda překladač GCC skutečně převedl volání vestavěných funkcí __builtin_ia32_rdrandXX_step na instrukci RDRAND. Toto ověření je vhodné provést v případě, že se náhodné hodnoty budou využívat v kryptografických algoritmech, v online hrách (kasinech) atd. Provedeme překlad do assembleru a pro větší čitelnost si vynutíme vygenerování assemblerovského zdrojového kódu založeného na syntaxi používané firmou Intel:

$ gcc -mrdrnd -S -masm=intel -Og rdrand_read.c

Ve výsledném kódu je volání instrukce RDRAND podtrženo:

        .file   "rdrand_read.c"
        .intel_syntax noprefix
        .text
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "%d %x\n"
        .text
        .globl  main
        .type   main, @function
main:
.LFB11:
        .cfi_startproc
        push    rbx
        .cfi_def_cfa_offset 16
        .cfi_offset 3, -16
        sub     rsp, 16
        .cfi_def_cfa_offset 32
        mov     ebx, 0
        jmp     .L2
.L3:
        rdrand  esi
        mov     DWORD PTR [rsp+12], esi
        mov     eax, 1
        cmovc   esi, eax
        mov     edx, DWORD PTR [rsp+12]
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        add     ebx, 1
.L2:
        cmp     ebx, 9
        jle     .L3
        mov     eax, 0
        add     rsp, 16
        .cfi_def_cfa_offset 16
        pop     rbx
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
.LFE11:
        .size   main, .-main
        .ident  "GCC: (GNU) 14.2.1 20240912 (Red Hat 14.2.1-3)"
        .section        .note.GNU-stack,"",@progbits

12. Jak kvalitní je sekvence náhodných čísel získaná opakovaným voláním RDRAND?

Jak jsme si již naznačili v úvodní kapitole, negeneruje instrukce RDRAND skutečné náhodné hodnoty, ale „jen“ hodnoty pseudonáhodné, i když samotné semínko je přečteno z generátoru skutečně náhodných čísel (tato situace ovšem nastane až po vrácení 511 hodnot). Musíme si tedy ověřit, jak náhodná je ve skutečnosti sekvence čísel, která je opakovaným voláním instrukce RDRAND získána. Pro tento účel existuje poměrně velké množství metrik, jejichž podrobný popis přesahuje rámec dnešního článku (ovšem jedná se o velmi zajímavou problematiku). Proto využijeme existující nástroj, který přečte obsah binárního souboru s (pseudo)náhodnými daty a s využitím většího množství metrik ověří, do jaké míry jsou tato data náhodná. Pro zajímavost porovnáme hodnoty vytvářené instrukcí RDRAND s hodnotami získanými klasickým deterministickým generátorem pseudonáhodných hodnot (ovšem nevyužijeme funkci rand ze základní knihovny).

13. Program pro vygenerování binárního souboru s (pseudo)náhodným obsahem

Abychom si ověřili, do jaké míry jsou hodnoty vrácené instrukcí RDRAND náhodné, necháme si vygenerovat binární soubor s (pseudo)náhodným obsahem, který budeme posléze analyzovat. Pro jednoduchost při implementaci zůstaneme u jazyka C, i když naprosto stejný program je pochopitelně možné vytvořit i v assmebleru (i když nebude přenositelný):

#include <stdio.h>
#include <stdint.h>
 
int main(void) {
    FILE *fout;
 
    int success;
    uint32_t random_value;
    int i;
 
    fout = fopen("random.bin", "wb");
    if (fout == NULL) {
        perror("fopen");
        return 1;
    }
 
    for (i=0; i<10; i++) {
        success = __builtin_ia32_rdrand32_step(&random_value);
        if (success != 1) {
            perror("rdrand32");
            return 2;
        }
        fwrite(&random_value, sizeof(uint32_t), 1, fout);
        if (ferror(fout)) {
            perror("fwrite");
            return 1;
        }
    }
 
    fclose(fout);
 
    return 0;
}

14. Vygenerování binárního souboru s jedním milionem 32bitových pseudonáhodných hodnot

Předchozí příklad vygeneroval pouze 40 náhodných bajtů. Upravme si ho proto do podoby, kdy se vygeneruje 1000000 třiceti dvoubitových hodnot:

    ...
    ...
    ...
    for (i=0; i<1000000; i++) {
        ...
        ...
        ...
    }
    ...
    ...
    ...

Po překladu a spuštění bychom měli získat soubor random.bin s délkou přesně 4000000 bajtů:

$ ls -l random.bin
 
-rw-r--r--. 1 ptisnovs ptisnovs 4000000 Aug  8 18:47 random.bin

15. Projekt s implementací metrik pro otestování (pseudo)náhodných hodnot

Pro otestování, jak kvalitní jsou hodnoty získané instrukcí RDRAND, použijeme projekt s implementací testovací sady SP800–22 Rev 1a PRNG. Tento projekt je naprogramován v Pythonu, takže testy budou poměrně zdlouhavé.

Projekt s testy naklonujeme do nového adresáře:

$ git clone git@github.com:dj-on-github/sp800_22_tests.git

Zjistíme, zda je testovací sada spustitelná:

$ ./sp800_22_tests.py --help

Výsledek by měl vypadat následovně:

usage: sp800_22_tests.py [-h] [--be] [-t TESTNAME] [--list_tests] [filename]
 
Test data for distinguishability form random, using NIST SP800-22Rev1a algorithms.
 
positional arguments:
  filename              Filename of binary file to test
 
options:
  -h, --help            show this help message and exit
  --be                  Treat data as big endian bits within bytes. Defaults to little endian
  -t TESTNAME, --testname TESTNAME
                        Select the test to run. Defaults to running all tests. Use --list_tests to see the list
  --list_tests          Display the list of tests

Můžeme si vypsat i testy, které jsou implementovány:

$ ./sp800_22_tests.py --list_tests
Tests of Distinguishability from Random
1   : monobit_test
2   : frequency_within_block_test
3   : runs_test
4   : longest_run_ones_in_a_block_test
5   : binary_matrix_rank_test
6   : dft_test
7   : non_overlapping_template_matching_test
8   : overlapping_template_matching_test
9   : maurers_universal_test
10  : linear_complexity_test
11  : serial_test
12  : approximate_entropy_test
13  : cumulative_sums_test
14  : random_excursion_test
15  : random_excursion_variant_test

16. Otestování hodnot vygenerovaných instrukcí RDRAND

Nyní testy spustíme oproti souboru random.bin, který byl vytvořen v rámci čtrnácté kapitoly. Výsledné metriky se pochopitelně mohou nepatrně odlišovat, nicméně celkové výsledky by se měnit neměly:

Tests of Distinguishability from Random
TEST: monobit_test
  Ones count   = 16002474
  Zeroes count = 15997526
  PASS
  P=0.381742010349456
TEST: frequency_within_block_test
  n = 32000000
  N = 99
  M = 323232
  PASS
  P=0.016363453060209376
TEST: runs_test
  prop  0.5000773125
  tau  0.00035355339059327376
  vobs  15997442.0
  PASS
  P=0.36586054912558746
TEST: longest_run_ones_in_a_block_test
  n = 32000000
  K = 6
  M = 10000
  N = 75
  chi_sq = 7.062112789716308
  PASS
  P=0.3151412465525687
TEST: binary_matrix_rank_test
  Number of blocks 31250
  Data bits used: 32000000
  Data bits discarded: 0
  Full Rank Count  =  9002
  Full Rank -1 Count =  18103
  Remainder Count =  4145
  Chi-Square =  0.4486112659932162
  PASS
  P=0.7990708746184348
TEST: dft_test
  N0 = 15200000.000000
  N1 = 15200124.000000
  PASS
  P=0.8405777193396355
TEST: non_overlapping_template_matching_test
  PASS
  P=0.9099065451579921
TEST: overlapping_template_matching_test
  B =  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  m =  10
  M =  1062
  N =  968
  K =  5
  model =  [352, 179, 134, 97, 68, 135]
  v[j] =   [580, 141, 101, 56, 47, 43]
  chisq =  6.780899397146134
  PASS
  P=0.23745168802495786
TEST: maurers_universal_test
  sum = 29375620.88424485
  fn = 10.16946589683095
  PASS
  P=0.41030644109319797
TEST: linear_complexity_test
  M =  512
  N =  62500
  K =  6
  chisq =  2.2519091978212007
  P =  0.8951344431090033
  PASS
  P=0.8951344431090033
TEST: serial_test
  psi_sq_m   =  17.469030998647213
  psi_sq_mm1 =  7.197106998413801
  psi_sq_mm2 =  2.348089501261711
  delta1     =  10.271924000233412
  delta2     =  5.422906503081322
  P1         =  0.24645678090722536
  P2         =  0.24658963035192114
  PASS
P=0.24645678090722536
P=0.24658963035192114
TEST: approximate_entropy_test
  n         =  32000000
  m         =  3
  Pattern 1 of 8, count = 3998217
  Pattern 2 of 8, count = 4000588
  Pattern 3 of 8, count = 3999448
  Pattern 4 of 8, count = 3999273
  Pattern 5 of 8, count = 4000588
  Pattern 6 of 8, count = 3998133
  Pattern 7 of 8, count = 3999273
  Pattern 8 of 8, count = 4004480
  phi(3)    = -4.382027
  Pattern 1 of 16, count = 2000148
  Pattern 2 of 16, count = 1998069
  Pattern 3 of 16, count = 2000528
  Pattern 4 of 16, count = 2000060
  Pattern 5 of 16, count = 2000285
  Pattern 6 of 16, count = 1999163
  Pattern 7 of 16, count = 1998244
  Pattern 8 of 16, count = 2001029
  Pattern 9 of 16, count = 1998069
  Pattern 10 of 16, count = 2002519
  Pattern 11 of 16, count = 1998920
  Pattern 12 of 16, count = 1999213
  Pattern 13 of 16, count = 2000303
  Pattern 14 of 16, count = 1998970
  Pattern 15 of 16, count = 2001029
  Pattern 16 of 16, count = 2003451
  phi(3)    = -5.075174
  AppEn(3)  = 0.693147
  ChiSquare =  10.270517456945072
  PASS
  P=0.24655018820637375
TEST: cumulative_sums_test
PASS
  PASS
P=0.30009060907640817
P=0.3654675300008945
TEST: random_excursion_test
J=3795
x = -4  chisq = 2.277509        p = 0.809564
x = -3  chisq = 21.315877       p = 0.000706  Not Random
x = -2  chisq = 8.381990        p = 0.136402
x = -1  chisq = 9.269424        p = 0.098788
x = 1   chisq = 7.581427        p = 0.180863
x = 2   chisq = 17.648646       p = 0.003421  Not Random
x = 3   chisq = 3.632979        p = 0.603369
x = 4   chisq = 2.222378        p = 0.817597
FAIL: Data not random
  FAIL
P=0.8095643977803422
P=0.0007059586033140604
P=0.13640211952704734
P=0.0987883878164268
P=0.18086283358054378
P=0.0034205664260353688
P=0.603368571138448
P=0.8175970567482853
TEST: random_excursion_variant_test
J= 3795
x = -9   count=4344     p = 0.126422
x = -8   count=4095     p = 0.373945
x = -7   count=3898     p = 0.742985
x = -6   count=3822     p = 0.925552
x = -5   count=3733     p = 0.812487
x = -4   count=3750     p = 0.845214
x = -3   count=3918     p = 0.527784
x = -2   count=4057     p = 0.082514
x = -1   count=4002     p = 0.017501
x = 1    count=3696     p = 0.255808
x = 2    count=3836     p = 0.785847
x = 3    count=3893     p = 0.614922
x = 4    count=3778     p = 0.941207
x = 5    count=3683     p = 0.668269
x = 6    count=3563     p = 0.422023
x = 7    count=3464     p = 0.292000
x = 8    count=3503     p = 0.386820
x = 9    count=3547     p = 0.489937
PASS
  PASS
P=0.12642201640045245
P=0.3739447986092539
P=0.7429854218086411
P=0.925551671800892
P=0.812486864855873
P=0.8452142837803289
P=0.5277841063848452
P=0.08251432838963278
P=0.017500678846047855
P=0.25580771506589667
P=0.7858465900792965
P=0.6149217634548362
P=0.9412070171775442
P=0.6682691399315276
P=0.42202260140624953
P=0.2919997884594155
P=0.38681988986649096
P=0.4899371303964931

Nejdůležitější je závěrečná tabulka:

SUMMARY
-------
monobit_test                             0.381742010349456  PASS
frequency_within_block_test              0.016363453060209376 PASS
runs_test                                0.36586054912558746 PASS
longest_run_ones_in_a_block_test         0.3151412465525687 PASS
binary_matrix_rank_test                  0.7990708746184348 PASS
dft_test                                 0.8405777193396355 PASS
non_overlapping_template_matching_test   0.9099065451579921 PASS
overlapping_template_matching_test       0.23745168802495786 PASS
maurers_universal_test                   0.41030644109319797 PASS
linear_complexity_test                   0.8951344431090033 PASS
serial_test                              0.24645678090722536 PASS
approximate_entropy_test                 0.24655018820637375 PASS
cumulative_sums_test                     0.30009060907640817 PASS
random_excursion_test                    0.0007059586033140604 FAIL
random_excursion_variant_test            0.017500678846047855 PASS

Z této tabulky je patrné, že „neprošel“ pouze jediný test random_excursion_test. Podrobnosti si řekneme příště.

17. Porovnání výsledků s výsledky deterministického generátoru pseudonáhodných hodnot

Bude zajímavé si porovnat výsledky otestování pseudonáhodných hodnot vygenerovaných instrukcí RDRAND se softwarově implementovaným generátorem pseudonáhodných hodnot (PRNG). Klasickou funkci rand (viz https://github.com/lattera/glib­c/blob/master/stdlib/random_r­.c#L341) použít přímo nelze, protože ořezává nejvyšší bit. Pokusme se tedy inspirovat některými existujícími PRNG: buď na posuvném registru se zpětnovazebními smyčkami (LFSR) nebo založeným na známém algoritmu XorShift (což je jedna z možných implementací LFSR, která je velmi rychlá a lze ji snadno implementovat i na osmibitových CPU). Konkrétní implementace byla inspirována tímto kódem:

#include <stdio.h>
#include <stdint.h>
 
 
uint32_t xorshift32(void) {
    const uint32_t start_state = 0xACE1u;
    static uint32_t state = start_state;
 
    uint32_t x = state;
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x <<  5;
    return state = x;
}
 
int main(void) {
    FILE *fout;
 
    uint32_t random_value;
    int i;
 
    fout = fopen("random.bin", "wb");
    if (fout == NULL) {
        perror("fopen");
        return 1;
    }
 
    for (i=0; i<1000000; i++) {
        random_value = xorshift32();
        fwrite(&random_value, sizeof(uint32_t), 1, fout);
        if (ferror(fout)) {
            perror("fwrite");
            return 1;
        }
    }
 
    fclose(fout);
 
    return 0;
}

Výsledky testu pseudonáhodných hodnot nyní budou vypadat následovně:

Tests of Distinguishability from Random
TEST: monobit_test
  Ones count   = 16003561
  Zeroes count = 15996439
  PASS
  P=0.2080290229323611
TEST: frequency_within_block_test
  n = 32000000
  N = 99
  M = 323232
  PASS
  P=0.8614428497587631
TEST: runs_test
  prop  0.50011128125
  tau  0.00035355339059327376
  vobs  16002865.0
  PASS
  P=0.3109595205564162
TEST: longest_run_ones_in_a_block_test
  n = 32000000
  K = 6
  M = 10000
  N = 75
  chi_sq = 22.941016541697515
  FAIL
  P=0.0008164762821414863
TEST: binary_matrix_rank_test
  Number of blocks 31250
  Data bits used: 32000000
  Data bits discarded: 0
  Full Rank Count  =  31250
  Full Rank -1 Count =  0
  Remainder Count =  0
  Chi-Square =  76960.83183277596
  FAIL
  P=0.0
TEST: dft_test
  N0 = 15200000.000000
  N1 = 15201888.000000
  FAIL
  P=0.002193202101438405
TEST: non_overlapping_template_matching_test
  PASS
  P=0.9993894628376528
TEST: overlapping_template_matching_test
  B =  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  m =  10
  M =  1062
  N =  968
  K =  5
  model =  [352, 179, 134, 97, 68, 135]
  v[j] =   [595, 150, 99, 48, 32, 44]
  chisq =  4.462951491364795
  PASS
  P=0.48485565251215446
TEST: maurers_universal_test
  sum = 29377040.220677454
  fn = 10.169957253030853
  PASS
  P=0.9134294606289255
TEST: linear_complexity_test
  M =  512
  N =  62500
  K =  6
  chisq =  8.824348198476159
  P =  0.18370025599170844
  PASS
  P=0.18370025599170844
TEST: serial_test
  psi_sq_m   =  15.084697999060154
  psi_sq_mm1 =  7.5235175006091595
  psi_sq_mm2 =  4.195492248982191
  delta1     =  7.5611804984509945
  delta2     =  4.233155246824026
  P1         =  0.47746392082023353
  P2         =  0.3753703504323772
  PASS
P=0.47746392082023353
P=0.3753703504323772
TEST: approximate_entropy_test
  n         =  32000000
  m         =  3
  Pattern 1 of 8, count = 3996493
  Pattern 2 of 8, count = 3998514
  Pattern 3 of 8, count = 4001144
  Pattern 4 of 8, count = 4000288
  Pattern 5 of 8, count = 3998514
  Pattern 6 of 8, count = 4002918
  Pattern 7 of 8, count = 4000288
  Pattern 8 of 8, count = 4001841
  phi(3)    = -4.382027
  Pattern 1 of 16, count = 1997631
  Pattern 2 of 16, count = 1998862
  Pattern 3 of 16, count = 2000811
  Pattern 4 of 16, count = 1997703
  Pattern 5 of 16, count = 1999985
  Pattern 6 of 16, count = 2001159
  Pattern 7 of 16, count = 1999967
  Pattern 8 of 16, count = 2000321
  Pattern 9 of 16, count = 1998862
  Pattern 10 of 16, count = 1999652
  Pattern 11 of 16, count = 2000333
  Pattern 12 of 16, count = 2002585
  Pattern 13 of 16, count = 1998529
  Pattern 14 of 16, count = 2001759
  Pattern 15 of 16, count = 2000321
  Pattern 16 of 16, count = 2001520
  phi(3)    = -5.075174
  AppEn(3)  = 0.693147
  ChiSquare =  7.561090846763818
  PASS
  P=0.4774731288894847
TEST: cumulative_sums_test
PASS
  PASS
P=0.33602422186921377
P=0.24415913425280134
TEST: random_excursion_test
J=7693
x = -4  chisq = 8.002090        p = 0.156121
x = -3  chisq = 1.777649        p = 0.878976
x = -2  chisq = 1.259272        p = 0.939066
x = -1  chisq = 8.128416        p = 0.149299
x = 1   chisq = 4.735801        p = 0.448966
x = 2   chisq = 1.803213        p = 0.875649
x = 3   chisq = 2.294887        p = 0.807018
x = 4   chisq = 2.816422        p = 0.728263
PASS
  PASS
P=0.15612050457353127
P=0.8789756760269307
P=0.9390662428576048
P=0.14929894014192574
P=0.44896643380466994
P=0.8756486991836885
P=0.8070175988774235
P=0.7282626872703772
TEST: random_excursion_variant_test
J= 7693
x = -9   count=8004     p = 0.543123
x = -8   count=7917     p = 0.641021
x = -7   count=7920     p = 0.611759
x = -6   count=7834     p = 0.731797
x = -5   count=7753     p = 0.871906
x = -4   count=7851     p = 0.630201
x = -3   count=7931     p = 0.390847
x = -2   count=7910     p = 0.312479
x = -1   count=7839     p = 0.239181
x = 1    count=7527     p = 0.180807
x = 2    count=7491     p = 0.347107
x = 3    count=7433     p = 0.348552
x = 4    count=7135     p = 0.089077
x = 5    count=6962     p = 0.049482
x = 6    count=6988     p = 0.086587
x = 7    count=7161     p = 0.234229
x = 8    count=7269     p = 0.377460
x = 9    count=7229     p = 0.364271
PASS
  PASS
P=0.5431229529294412
P=0.6410206735453066
P=0.6117587281384658
P=0.7317969690295173
P=0.8719060321940433
P=0.6302014247555671
P=0.39084685974524846
P=0.3124787233136639
P=0.23918087197125792
P=0.18080694993165813
P=0.34710650922851455
P=0.34855224987536226
P=0.08907689521634357
P=0.04948197607007566
P=0.0865873799112578
P=0.23422934975621235
P=0.3774596342564739
P=0.36427054513505974

Hodnoty jsou nepatrně horší (podle očekávání):

SUMMARY
-------
monobit_test                             0.2080290229323611 PASS
frequency_within_block_test              0.8614428497587631 PASS
runs_test                                0.3109595205564162 PASS
longest_run_ones_in_a_block_test         0.0008164762821414863 FAIL
binary_matrix_rank_test                  0.0                FAIL
dft_test                                 0.002193202101438405 FAIL
non_overlapping_template_matching_test   0.9993894628376528 PASS
overlapping_template_matching_test       0.48485565251215446 PASS
maurers_universal_test                   0.9134294606289255 PASS
linear_complexity_test                   0.18370025599170844 PASS
serial_test                              0.3753703504323772 PASS
approximate_entropy_test                 0.4774731288894847 PASS
cumulative_sums_test                     0.24415913425280134 PASS
random_excursion_test                    0.14929894014192574 PASS
random_excursion_variant_test            0.04948197607007566 PASS

18. Příloha: pomocné soubory s makry a subrutinami použitými v příkladech napsaných v assembleru

Soubor linux_macros.asm obsahuje základní makra používaná v programech, které mají být spouštěny v Linuxu, tj. které mají volat funkce jádra (kernelu):

%ifndef LINUX_MACROS_LIB
%define LINUX_MACROS_LIB
 
; Linux kernel system call table
sys_exit  equ 1
sys_write equ 4
 
 
; makro pro tisk retezce na obrazovku
%macro print_string 2
        mov   eax, sys_write      ; cislo syscallu pro funkci "write"
        mov   ebx, 1              ; standardni vystup
        mov   ecx, %1             ; adresa retezce, ktery se ma vytisknout
        mov   edx, %2             ; delka retezce
        int   80h                 ; volani Linuxoveho kernelu
%endmacro
 
 
; makro pro tisk 32bitove hexadecimalni hodnoty
; na standardni vystup
%macro print_hex 2
        push ebx                  ; uschovat EBX pro dalsi pouziti
        mov     edx, %1           ; zapamatovat si hodnotu pro tisk
        mov     ebx, hex_message  ; buffer, ktery se zaplni hexa cislicemi
        mov     byte [ebx+8], %2  ; oddelovac, konec radku, atd.
        call    hex2string        ; zavolani prislusne subrutiny
        print_string   hex_message, hex_message_length  ; tisk hexadecimalni hodnoty
        pop ebx                   ; obnovit EBX
%endmacro
 
 
; makro pro vypis obsahu MMX vektoru
%macro print_mmx_reg_as_hex 1
        mov  ebx, mmx_tmp         ; adresa bufferu
        movq [ebx], %1            ; ulozeni do pameti (8 bajtu)
        mov  eax, [ebx+4]         ; nacteni casti MMX vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx]           ; nacteni casti MMX vektoru do celociselneho registru
        print_hex eax, 0x0a       ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
%endmacro
 
 
; makro pro vypis obsahu SSE vektoru
%macro print_sse_reg_as_hex 1
        mov  ebx, sse_tmp         ; adresa bufferu
        movups [ebx], %1          ; ulozeni do pameti (16 bajtu)
        mov  eax, [ebx+12]        ; nacteni casti SSE vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx+8]         ; nacteni casti SSE vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx+4]         ; nacteni casti SSE vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx]           ; nacteni casti SSE vektoru do celociselneho registru
        print_hex eax, 0x0a       ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
%endmacro
 
 
; makro pro vypis obsahu AVX vektoru
%macro print_avx_reg_as_hex 1
        mov  ebx, avx_tmp         ; adresa bufferu
        vmovdqu [ebx], %1         ; ulozeni do pameti (32 bajtu)
        mov  eax, [ebx+28]        ; nacteni casti AVX vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx+24]        ; nacteni casti AVX vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx+20]        ; nacteni casti AVX vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx+16]        ; nacteni casti AVX vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx+12]        ; nacteni casti AVX vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx+8]         ; nacteni casti AVX vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx+4]         ; nacteni casti AVX vektoru do celociselneho registru
        print_hex eax, ' '        ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
        mov  eax, [ebx]           ; nacteni casti AVX vektoru do celociselneho registru
        print_hex eax, 0x0a       ; zobrazeni obsahu tohoto registru v hexadecimalnim tvaru
%endmacro
 
 
; makro pro ukonceni procesu 
%macro exit 0
        mov   eax,sys_exit        ; cislo sycallu pro funkci "exit"
        mov   ebx,0               ; exit code = 0
        int   80h                 ; volani Linuxoveho kernelu
%endmacro
 
 
%endif

Soubor hex2string.asm obsahuje subrutinu nazvanou taktéž hex2string, která převede vstupní 32bitovou hodnotu uloženou v registru EDX do řetězce:

%ifndef HEX_2_STRING_LIB
%define HEX_2_STRING_LIB
 
; subrutina urcena pro prevod 32bitove hexadecimalni hodnoty na retezec
; Vstup: EDX - hodnota, ktera se ma prevest na retezec
;        EBX - adresa jiz drive alokovaneho retezce (resp. osmice bajtu)
hex2string:
                  mov ecx,  8             ; pocet opakovani smycky
 
.print_one_digit: rol edx, 4              ; rotace doleva znamena, ze se do spodnich 4 bitu nasune dalsi cifra
                  mov al, dl              ; nechceme porusit obsah vstupni hodnoty v EDX, proto pouzijeme AL
                  and al, 0x0f            ; maskovani, potrebujeme pracovat jen s jednou cifrou
                  cmp al, 10              ; je cifra vetsi nebo rovna 10?
                  jl  .store_digit        ; neni, pouze prevest 0..9 na ASCII hodnotu '0'..'9'
 
.alpha_digit:     add al, 'A'-10-'0'      ; prevod hodnoty 10..15 na znaky 'A'..'F'
 
.store_digit:     add al, '0'
                  mov [ebx], al           ; ulozeni cifry do retezce
                  inc ebx                 ; dalsi cifra
                  loop .print_one_digit   ; a opakovani smycky, dokud se nedosahlo nuly
 
                  ret                     ; navrat ze subrutiny
 
%endif

19. Repositář s demonstračními příklady

Demonstrační příklady napsané v jazyku C i v assembleru mikroprocesorů s architekturou x86–64, byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/8bit-fame. Jednotlivé demonstrační příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý (dnes již poměrně rozsáhlý) repositář:

# Příklad Stručný popis Adresa
1 rdrand_support.asm test, jestli je instrukce RDRAND mikroprocesorem podporována https://github.com/tisnik/8bit-fame/blob/master/pc-linux/rdrand_support.asm
2 rdrand_read.asm přečtení jedné 32bitové hodnoty instrukcí RDRAND https://github.com/tisnik/8bit-fame/blob/master/pc-linux/rdrand_read.asm
3 rdrand_read_loop.asm přečtení sekvence 32bitových hodnot instrukcí RDRAND https://github.com/tisnik/8bit-fame/blob/master/pc-linux/rdrand_read_loop.asm
       
4 rdrand_read.c přečtení náhodné 32bitové hodnoty, realizace s využitím vestavěné funkce GCC https://github.com/tisnik/8bit-fame/blob/master/gcc-builtins/rdrand_read.c
5 rdrand_read.asm výsledek překladu předchozího zdrojového kódu do assembleru https://github.com/tisnik/8bit-fame/blob/master/gcc-builtins/rdrand_read.asm
       
6 rand_gen.c vygenerování binárního souboru s pseudonáhodnými 32bitovými hodnotami https://github.com/tisnik/8bit-fame/blob/master/gcc-builtins/rand_gen.c
7 rdrand_gen.c vygenerování binárního souboru s hodnotami vrácenými instrukcí RDRAND https://github.com/tisnik/8bit-fame/blob/master/gcc-builtins/rdrand_gen.c

20. Odkazy na Internetu

  1. RDRAND (Wikipedia)
    https://en.wikipedia.org/wiki/RDRAND
  2. RDRAND instruction
    https://www.felixcloutier­.com/x86/rdrand
  3. Random Number Generator
    https://wiki.osdev.org/Ran­dom_Number_Generator
  4. GCC documentation: Extensions to the C Language Family
    https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions
  5. GCC documentation: Using Vector Instructions through Built-in Functions
    https://gcc.gnu.org/online­docs/gcc/Vector-Extensions.html
  6. SSE (Streaming SIMD Extentions)
    http://www.songho.ca/misc/sse/sse­.html
  7. Timothy A. Chagnon: SSE and SSE2
    http://www.cs.drexel.edu/~tc365/mpi-wht/sse.pdf
  8. CPU design (Wikipedia)
    http://en.wikipedia.org/wi­ki/CPU_design
  9. GCC Compiler Intrinsics
    https://iq.opengenus.org/gcc-compiler-intrinsics/
  10. Other Built-in Functions Provided by GCC
    https://gcc.gnu.org/online­docs/gcc/Other-Builtins.html
  11. GCC: 6.60 Built-in Functions Specific to Particular Target Machines
    https://gcc.gnu.org/online­docs/gcc/Target-Builtins.html#Target-Builtins
  12. Stránka projektu Compiler Explorer
    https://godbolt.org/
  13. The LLVM Compiler Infrastructure
    https://llvm.org/
  14. GCC, the GNU Compiler Collection
    https://gcc.gnu.org/
  15. Clang
    https://clang.llvm.org/
  16. Clang: Assembling a Complete Toolchain
    https://clang.llvm.org/doc­s/Toolchain.html
  17. Integer overflow
    https://en.wikipedia.org/wi­ki/Integer_overflow
  18. SETcc — Set Byte on Condition
    https://www.felixcloutier­.com/x86/setcc
  19. The ARMv8 instruction sets
    http://infocenter.arm.com/hel­p/index.jsp?topic=/com.ar­m.doc.den0024a/ch05s01.html
  20. A64 Instruction Set
    https://developer.arm.com/pro­ducts/architecture/instruc­tion-sets/a64-instruction-set
  21. Switching between the instruction sets
    http://infocenter.arm.com/hel­p/index.jsp?topic=/com.ar­m.doc.den0024a/ch05s01.html
  22. The A64 instruction set
    http://infocenter.arm.com/hel­p/index.jsp?topic=/com.ar­m.doc.den0024a/ch05s01.html
  23. Introduction to ARMv8 64-bit Architecture
    https://quequero.org/2014/04/in­troduction-to-arm-architecture/
  24. Undefined behavior (Wikipedia)
    https://en.wikipedia.org/wi­ki/Undefined_behavior
  25. Is signed integer overflow still undefined behavior in C++?
    https://stackoverflow.com/qu­estions/16188263/is-signed-integer-overflow-still-undefined-behavior-in-c
  26. Allowing signed integer overflows in C/C++
    https://stackoverflow.com/qu­estions/4240748/allowing-signed-integer-overflows-in-c-c
  27. SXTB, SXTH, SXTW
    https://www.scs.stanford.e­du/~zyedidia/arm64/sxtb_z_p_z­.html
  28. Is there any legitimate use for Intel's RDRAND?
    https://stackoverflow.com/qu­estions/26771329/is-there-any-legitimate-use-for-intels-rdrand
  29. Intel® Digital Random Number Generator (DRNG) Software Implementation Guide
    https://www.intel.com/con­tent/www/us/en/developer/ar­ticles/guide/intel-digital-random-number-generator-drng-software-implementation-guide.html
  30. Hardware random number generator
    https://en.wikipedia.org/wi­ki/Hardware_random_number_ge­nerator
  31. Random number generator attack
    https://en.wikipedia.org/wi­ki/Random_number_generator_at­tack
  32. random_r.c (Glibc)
    https://github.com/lattera/glib­c/blob/master/stdlib/random_r­.c#L341
  33. Xorshift
    https://en.wikipedia.org/wi­ki/Xorshift
Neutrální ikona do widgetu na odběr článků ze seriálů

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.


Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.