SHISHUA: generator nomor acak semu tercepat di dunia


Enam bulan lalu, saya ingin membuat generator nomor pseudorandom terbaik (PRNG) dengan arsitektur yang tidak biasa. Saya pikir awalnya akan mudah, dan saat Anda bekerja, tugasnya perlahan akan menjadi lebih kompleks. Dan saya pikir jika saya bisa mempelajari semuanya dengan cukup cepat untuk mengatasi yang paling sulit.

Yang mengejutkan saya, kompleksitas tidak meningkat secara linear. Pengujian byte-kuadrat terbukti sangat sulit! Kemudian sama sulitnya untuk lulus tes diehard. Saya menerbitkan hasil saat ini untuk memahami kesulitan apa yang menunggu saya. Namun , tes PractRand gagal pada saat itu .

Maka sangat sulit untuk lulus ujian BigCrush .

Maka sangat sulit untuk mentransfer data 32 terabyte ketika melewati PractRand. Kecepatan telah menjadi masalah. Itu tidak cukup untuk membuat desain yang menghasilkan sepuluh megabyte per detik, karena melewati PractRand akan memakan waktu satu bulan. Tetapi saya harus mengakui bahwa sangat sulit untuk lulus tes ini dengan kecepatan gigabytes per detik .

Ketika Anda naik ke ketinggian seperti itu ... Anda ingin tahu apakah Anda bisa sampai ke perbatasan Pareto. Anda ingin membuat PRNG tercepat di dunia, yang akan lulus tes statistik paling kompleks.

Saya telah berhasil

Dalam artikel sebelumnya, saya berbicara tentang apa yang saya pelajari untuk mencapai tujuan saya. Dan di sini saya akan memberi tahu Anda bagaimana arsitektur final bekerja.

tujuan


Mari kita mulai dengan yang jelas: kecepatan tergantung pada platform . Saya fokus pada pengoptimalan untuk arsitektur x86-64 modern (prosesor Intel dan AMD).

Untuk membandingkan kinerja, metrik cpb klasik digunakan : ini adalah jumlah siklus prosesor yang dihabiskan untuk menghasilkan satu byte. Metrik ini dihitung dan dibandingkan di semua karya kriptografi. Cpb yang sedikit lebih rendah di dunia perangkat lunak atau perangkat keras dapat memastikan kemenangan dalam persaingan atau digunakan di situs web di seluruh dunia.

Untuk meningkatkan cpb, Anda dapat:

  1. Hasilkan lebih banyak byte dengan jumlah pekerjaan yang sama,
  2. Atau bekerja lebih sedikit untuk menghasilkan jumlah byte yang sama,
  3. Atau memparalelkan pekerjaan.

Kami akan melakukan semua hal di atas.

Menurut poin pertama, kita perlu menghasilkan lebih banyak bit pada setiap iterasi.

Saya takut mereka akan memberi tahu saya: "Jika tidak memberikan angka 32-bit, maka ini bukan PRSP", atau hal yang sama dengan angka 64-bit. Atau: "PRNG seharusnya hanya untuk arsitektur x86-64," seolah-olah instruksi seperti POPCNT atau register seperti% xmm7 dilarang.

Namun, PRNG adalah rekayasa: generator telah berusaha selama beberapa dekade untuk memeras segala kemungkinan dari prosesor! Ketika ROL muncul, mereka mulai mengandalkannya. Dengan munculnya prosesor 64-bit, mereka mulai mengandalkan% rax. Tentu saja, pada ARM, algoritma tersebut dapat bekerja lebih lambat (meskipun ini masih harus dilihat), namun, PRN 64-bit aktif digunakan bahkan sebelum Android mulai membutuhkan dukungan untuk 64-bit pada 2019!

Artinya, area ini berkembang seiring dengan perangkat kerasnya. Dan hari ini, prosesor Intel dan AMD karena AVX2 sudah mendukung operasi 256-bit. RC4 menghasilkan 1 byte, drand48 dapat menghasilkan 4 byte pada satu waktu, pcg64 - 8 byte, dan sekarang kita dapat langsung menghasilkan 32 byte.

8 byte bisa berupa angka 64-bit, dan sebagian besar bahasa pemrograman memiliki tipe bawaan untuk ini. Tetapi beberapa bahasa menyediakan tipe untuk 16 byte (pengecualian penting adalah __uint128_t dalam C). Bahkan lebih sedikit bahasa yang mengetikkan 32 byte (kecuali internal).

Jadi kita bisa mengucapkan selamat tinggal pada prototipe fungsi PRNG yang biasa (contoh dari benchmark HWD Vigny ):

static uint64_t next(void);

Sebagai gantinya, Anda dapat membuat generator yang mengisi buffer (contoh dari tolok ukur saya ):

void prng_gen(prng_state *s, __uint64_t buf[], __uint64_t size);

Apa kerugian dari solusi ini?

Jika generator Anda menghasilkan 32 byte pada suatu waktu, maka Anda perlu konsumen untuk menyediakan array yang merupakan kelipatan 32 (idealnya selaras dengan 32 byte). Meskipun Anda dapat melakukannya tanpa itu, kami hanya akan mengisi buffer. Kami akan menghapus data yang tidak terpakai darinya dan mengisinya lagi seperlunya. Penundaan menjadi tidak dapat diprediksi: beberapa panggilan hanya akan membaca buffer. Tapi rata-rata semuanya akan sama.

Sekarang kita menghasilkan lebih banyak byte, melakukan jumlah pekerjaan yang sama. Bagaimana kita memparalelkannya?

Paralelisme


Prosesor menawarkan seperangkat alat paralelisasi yang luar biasa di semua tingkatan.

Pertama, ini adalah instruksi SIMD (Instruksi Tunggal, Banyak Data). Misalnya, AVX2 secara bersamaan melakukan empat penambahan 64-bit, atau delapan tambahan 32-bit, dll.

Ini telah digunakan dalam kriptografi selama sekitar lima belas tahun. Concurrency menyediakan kinerja luar biasa dari ChaCha20 . Ini digunakan oleh kebanyakan primitif penting yang tidak menggunakan AESNI. Sebagai contoh, NORX dan Gimli dirancang dengan mempertimbangkan paralelisme.

Baru-baru ini, minat terhadap topik ini juga meningkat dalam komunitas PRNG non-kriptografi. Secara khusus, primitif yang ada yang tidak dirancang untuk SIMD dapat menjadi dasar untuk menciptakan PRN yang sangat cepat.

Ketika Sebastiano Vigna mempromosikan arsitektur xoshiro256 ++-nya di perpustakaan standar Julia, ia menemukan bahwa hasil dari delapan instance PRNG yang kompetitif dan diinisialisasi berbeda dapat digabungkan dengan sangat cepat jika setiap operasi dilakukan secara bersamaan di semua PRNR.

SIMD hanyalah salah satu level paralelisasi dalam prosesor. Saya sarankan membaca artikel sebelumnya tentang topik ini untuk memiliki ide yang lebih baik, tetapi saya akan memberikan beberapa penjelasan.

Jalur pipa prosesor memungkinkan beberapa instruksi untuk diproses pada tahapan yang berbeda. Jika Anda mengatur urutan pelaksanaannya dengan baik untuk mengurangi ketergantungan antar tahap, Anda dapat mempercepat pemrosesan instruksi.

Eksekusi Superscalar memungkinkan Anda untuk secara bersamaan memproses bagian-bagian komputasi dari instruksi. Tetapi untuk ini mereka seharusnya tidak memiliki ketergantungan baca-tulis. Anda dapat mengadaptasi arsitektur untuk mengurangi risiko downtime dengan merekam jauh sebelum membaca.

Eksekusi luar biasa memungkinkan prosesor untuk menjalankan instruksi tidak dalam urutan, tetapi karena mereka siap, bahkan jika instruksi sebelumnya belum siap. Tetapi untuk ini seharusnya tidak ada ketergantungan baca-tulis.

Dan sekarang kita lolos implementasi!

Arsitektur


Pertimbangkan skema yang disebut semi-SHISHUA. Dari mana nama seperti itu berasal akan menjadi semakin jelas saat Anda membaca.

Skemanya terlihat seperti ini:


Pertimbangkan baris demi baris.

typedef struct prng_state {
  __m256i state[2];
  __m256i output;
  __m256i counter;
} prng_state;

Negara dibagi menjadi dua bagian, yang ditempatkan di register AVX2 (256 bit). Untuk meningkatkan kecepatan, kami menjaga hasilnya dekat dengan negara itu sendiri, tetapi itu bukan bagian dari negara.

Kami juga memiliki penghitung 64-bit. Untuk menyederhanakan perhitungan, ini juga merupakan register AVX2. Faktanya adalah bahwa AVX2 memiliki fitur kecil: register biasa (% rax dan sejenisnya) tidak dapat ditransfer langsung ke SIMD melalui MOV, mereka harus melewati RAM (paling sering melalui tumpukan), yang meningkatkan penundaan dan biaya dua instruksi prosesor (MOV pada stack, VMOV dari stack).

Sekarang mari kita lihat generasi. Mari kita mulai dengan memuat, lalu pergi melalui buffer dan mengisinya dengan 32 byte di setiap iterasi.

inline void prng_gen(prng_state *s, __uint64_t buf[], __uint64_t size) {
  __m256i s0 = s->state[0], counter = s->counter,
          s1 = s->state[1],       o = s->output;
  for (__uint64_t i = 0; i < size; i += 4) {
    _mm256_storeu_si256((__m256i*)&buf[i], o);
    // …
  }
  s->state[0] = s0; s->counter = counter;
  s->state[1] = s1; s->output  = o;
}

Karena fungsinya inline, segera mengisi buffer saat startup memungkinkan prosesor untuk segera menjalankan instruksi tergantung pada ini melalui mekanisme eksekusi yang luar biasa.

Di dalam loop, kami dengan cepat melakukan tiga operasi negara:

  1. SHI ft
  2. SHU main-main
  3. A dd

Maka dari itu nama SHISHUA!

Giliran pertama


u0 = _mm256_srli_epi64(s0, 1);              u1 = _mm256_srli_epi64(s1, 3);

Sayangnya, AVX2 tidak mendukung revs. Tapi saya ingin mencampur bit dari satu posisi dalam angka 64-bit dengan bit dari posisi lain! Dan shift adalah cara terbaik untuk mewujudkan ini. Kami akan bergeser dengan angka ganjil, sehingga setiap bit akan mengunjungi semua posisi 64-bit, dan tidak setengah dari mereka.

Selama shift, bit hilang, yang mengarah pada penghapusan informasi dari negara kita. Ini buruk, Anda harus meminimalkan kerugian. Angka ganjil terkecil adalah 1 dan 3, kami akan menggunakan nilai shift yang berbeda untuk meningkatkan perbedaan antara dua bagian. Ini akan membantu mengurangi kesamaan korelasi-diri mereka.

Kami akan bergeser ke kanan, karena bit paling kanan memiliki difusi terendah selama penambahan: misalnya, bit paling tidak signifikan dalam A + B hanyalah XOR dari bit paling tidak signifikan A dan B.

Aduk


t0 = _mm256_permutevar8x32_epi32(s0, shu0); t1 = _mm256_permutevar8x32_epi32(s1, shu1);

Kami akan menggunakan pencampuran 32-bit, karena memberikan granularitas yang berbeda dibandingkan dengan operasi 64-bit yang kami gunakan di mana-mana (penyelarasan 64-bit dilanggar). Ini juga bisa menjadi operasi lintas-jalur: pengocokan lainnya dapat memindahkan bit dalam 128 bit kiri jika mereka mulai dari kiri, atau dalam 128 bit kanan jika mereka mulai dari kanan.

Pencampuran Konstanta:

__m256i shu0 = _mm256_set_epi32(4, 3, 2, 1, 0, 7, 6, 5),
        shu1 = _mm256_set_epi32(2, 1, 0, 7, 6, 5, 4, 3);

Agar pencampuran benar-benar meningkatkan hasilnya, kami akan memindahkan bagian 32-bit yang lemah (dispersi rendah) dari penambahan 64-bit ke posisi yang kuat, sehingga penambahan selanjutnya akan memperkaya mereka.

Bagian 32-bit low-end dari 64-bit chunk tidak pernah berpindah ke chunk 64-bit yang sama dengan bagian high-order. Dengan demikian, kedua bagian tidak tetap berada dalam potongan yang sama, yang meningkatkan pencampuran.

Pada akhirnya, setiap bagian 32-bit melewati semua posisi dalam lingkaran: dari A ke B, dari B ke C, ... dari H ke A.

Anda mungkin telah memperhatikan bahwa pencampuran paling sederhana yang memperhitungkan semua persyaratan ini adalah dua 256-bit turnover (putaran masing-masing 96 bit dan 160 bit ke kanan).

Tambahan


Mari kita tambahkan potongan 64-bit dari dua variabel sementara - shift dan mixing.

s0 = _mm256_add_epi64(t0, u0);              s1 = _mm256_add_epi64(t1, u1);

Penambahan adalah sumber utama dispersi: dalam operasi ini, bit digabungkan menjadi kombinasi tak tereduksi dari XOR dan ekspresi AND yang didistribusikan melalui posisi 64-bit.

Menyimpan hasil penambahan dalam keadaan secara permanen menjaga dispersi ini.

Fungsi output


Dari mana kita mendapatkan output?

Sederhana: struktur yang kami buat memungkinkan kami untuk menghasilkan dua bagian keadaan bebas s0 dan s1, yang tidak saling memengaruhi dengan cara apa pun. Terapkan XOR pada mereka dan dapatkan hasil yang sepenuhnya acak.

Untuk memperkuat independensi antara data yang kami terapkan XOR, kami mengambil hasil parsial: bagian bergeser dari satu negara dan bagian campuran dari yang lain.

o = _mm256_xor_si256(u0, t1);

Ini mirip dengan mengurangi ketergantungan baca-tulis antara instruksi dalam prosesor superscalar, seolah-olah u0 dan t1 siap untuk membaca ke s0 dan s1.

Sekarang diskusikan konternya. Kami memprosesnya di awal siklus. Pertama, ubah status, dan kemudian tambahkan nilai penghitung:

s1 = _mm256_add_epi64(s1, counter);
counter = _mm256_add_epi64(counter, increment);

Mengapa kita pertama-tama mengubah status, dan kemudian memperbarui penghitung? s1 menjadi tersedia lebih awal, ini mengurangi kemungkinan bahwa instruksi selanjutnya yang membacanya akan berhenti di pipa prosesor. Selain itu, urutan ini membantu menghindari ketergantungan langsung dari penghitung baca-tulis.

Kami menerapkan penghitung ke s1, dan bukan ke s0, karena mereka berdua mempengaruhi output, bagaimanapun, s1 kehilangan lebih banyak bit karena pergeseran, sehingga membantu untuk "bangkit" setelah pergeseran.

Penghitung mungkin tidak mencatat tes PractRand. Tujuan utamanya adalah untuk menetapkan batas bawah 2 69byte = 512 exbibytes untuk periode PRNG: kita mulai mengulangi siklus hanya setelah satu milenium bekerja dengan kecepatan 10 gibytes per detik. Tampaknya tidak mungkin terlalu lambat untuk penggunaan praktis pada abad-abad mendatang.

Kenaikan:

__m256i increment = _mm256_set_epi64x(1, 3, 5, 7);

Angka ganjil dipilih sebagai kenaikan, karena hanya angka coprime dasar yang mencakup seluruh siklus bidang hingga GF (2 64 ), dan semua angka ganjil adalah coprime untuk 2. Dengan kata lain, jika Anda menambah bilangan bulat genap dalam rentang dari 0 hingga 4, kembali ke 0 setelah 4, ternyata urutan 0-2-0-2- ..., yang tidak akan mengarah ke 1 atau 3. Dan kenaikan aneh melewati semua bilangan bulat.

Untuk semua angka 64-bit dalam keadaan, kami akan menggunakan angka ganjil yang berbeda, yang selanjutnya akan memisahkan mereka dan sedikit meningkatkan pencampuran. Saya memilih angka ganjil terkecil sehingga tidak terlihat ajaib.

Inilah cara transisi fungsi dan fungsi keluaran bekerja. Bagaimana cara menginisialisasi mereka?

Inisialisasi


Kami menginisialisasi keadaan menggunakan digit heksadesimal Φ, bilangan irasional yang paling tidak diperkirakan oleh fraksi.

static __uint64_t phi[8] = {
  0x9E3779B97F4A7C15, 0xF39CC0605CEDC834, 0x1082276BF3A27251, 0xF86C6A11D0C18E95,
  0x2767F0B153D27B7F, 0x0347045B5BF1827F, 0x01886F0928403002, 0xC1D64BA40F335E36,
};

Ambil biji 256-bit. Ini sering dilakukan dalam kriptografi dan tidak membahayakan pekerjaan PRNG non-kriptografi:

prng_state prng_init(SEEDTYPE seed[4]) {
  prng_state s;
  // …
  return s;
}

Kami tidak ingin mendefinisikan ulang seluruh bagian negara (s0 atau s1) dengan angka awal ini, kami hanya perlu mempengaruhi setengahnya. Dengan cara ini kita akan menghindari penggunaan pelemahan angka awal, yang secara tidak sengaja atau sengaja menimbulkan kondisi awal yang diketahui lemah.

Karena kami tidak mengubah setengah dari masing-masing negara, kami mempertahankan kontrol atas 128 bit status. Entropi semacam itu sudah cukup untuk memulai dan mempertahankan posisi yang kuat.

s.state[0] = _mm256_set_epi64x(phi[3], phi[2] ^ seed[1], phi[1], phi[0] ^ seed[0]);
s.state[1] = _mm256_set_epi64x(phi[7], phi[6] ^ seed[3], phi[5], phi[4] ^ seed[2]);

Kemudian kami ulangi ( ROUNDS) beberapa kali urutan berikut:

  1. Jalankan langkah-langkah ( STEPS) dari iterasi SHISHUA.
  2. Kami menetapkan satu bagian dari negara bagian ke negara bagian lain, dan bagian yang lain untuk output.

for (char i = 0; i < ROUNDS; i++) {
  prng_gen(&s, buf, 4 * STEPS);
  s.state[0] = s.state[1];
  s.state[1] = s.output;
}

Menetapkan hasil keluaran meningkatkan dispersi negara. Selama inisialisasi, kerja tambahan dan korelasi keadaan tidak menjadi masalah, karena rangkaian operasi ini dilakukan sekali. Kami hanya tertarik pada dispersi selama inisialisasi.

Setelah mengevaluasi efek pada korelasi nilai awal, saya memilih STEPS2 untuk nilai dan ROUNDS10 untuk 10. Saya menghitung korelasi dengan menghitung anomali "tidak biasa" dan "mencurigakan" yang timbul dari alat kontrol kualitas PRNG di PractRand.

Performa


Sulit untuk mengukur kecepatan karena beberapa alasan:

  • Pengukuran jam mungkin tidak cukup akurat.
  • , , - , -, .
  • , . .
  • : , .

Saya menggunakan instruksi prosesor RDTSC, yang menghitung jumlah siklus.

Agar siapa pun dapat mereproduksi hasil saya, saya menggunakan mesin virtual berbasis cloud. Ini tidak mengubah tingkat hasil benchmark dibandingkan dengan pengujian lokal. Selain itu, Anda tidak perlu membeli komputer yang sama seperti komputer saya. Akhirnya, ada banyak situasi di mana PRNG diluncurkan di awan.

Saya memilih Google Cloud Platform N2 (prosesor Intel) dan N2D (prosesor AMD). Keuntungan dari GCP adalah bahwa mereka menawarkan server dengan prosesor dari kedua produsen. Pada artikel ini, kami akan fokus pada Intel, tetapi untuk AMD hasilnya akan berada dalam urutan yang sama.

Untuk mempelajari lebih dalam topik ini, mari kita singkirkan generator kriptografi RC4 lama. Tidak dapat memparalelkan pekerjaan, saya mengerti7,5 cpb (siklus per byte yang dihasilkan).

Sekarang mari kita jalankan MCG yang sangat populer dan cepat: Lehmer128 PRNG yang paling sederhana , yang lulus tes BigCrush, menunjukkan 0,5 cpb . Wow LUAR BIASA!

Kemudian kita akan menjalankan pengembangan terbaru, yang digunakan untuk tabel hash cepat - wyrand . 0,41 cpb , sedikit lebih baik!

Beberapa PRSP tidak lulus tes PractRand 32-terabyte, tetapi mereka bekerja dengan sangat cepat. Xoshiro256 + hanya mencapai 512 mebibytes, tetapi menunjukkan kecepatan yang sangat tinggi: 0,34 cpb .

Perkembangan baru RomuTrio lainnya . Dia mengklaim sebagai PRNG tercepat di dunia - 0,31 cpb.

Oke, itu sudah cukup. Apa yang ditunjukkan semi-SHISHUA?

0,14 cpb . Dua kali lebih cepat dari RomuTrio.


Keren. Sekarang coba generator cryptographic ChaCha8. Dia mencapai ... 0,12 cpb .

Oh

SIMD adalah sihir nyata!

Untuk komunitas kriptografi, ini bukan kejutan khusus . ChaCha8 sangat mudah diparalelkan. Ini hanya counter hash dalam kondisi difus.

Dan ingat bagaimana tim bahasa Julia mencoba menggabungkan beberapa contoh arsitektur Vigny untuk membuat PRNG berbasis SIMD yang cepat? Mari kita lihat hasilnya menggunakan teknik ini ( 8 buah Xoshiro256 + ). 0,09 cpb !

Secara teknis, laptop saya bisa mempengaruhi hasilnya. Saya tidak yakin mengapa pengembangan tim Julia lebih cepat dari ChaCha8 di GCP, tetapi lebih lambat saat diuji secara lokal. Di mesin saya, semi-SHISHUA berjalan lebih cepat dari pengembangan tim Julia, tetapi lebih lambat dari ChaCha8.

Perlu untuk mengalahkan semua pesaing.

Anda mungkin sudah bertanya mengapa kami menyebut generator semi-SHISHUA versi sebelumnya? Karena ternyata mudah untuk menggandakan kecepatan jika Anda menjalankan dua salinan semi-SHISHUA.

Mirip dengan gagasan perintah Julia, kami secara terpisah menginisialisasi dua PRNG (empat blok negara 256-bit), secara bergantian memasok output dari pekerjaan mereka.

Tetapi jika kita membuat lebih banyak status, maka kita dapat menghasilkan lebih banyak data, menggabungkan empat status berpasangan:

o0 = _mm256_xor_si256(u0, t1);
o1 = _mm256_xor_si256(u2, t3);
o2 = _mm256_xor_si256(s0, s3);
o3 = _mm256_xor_si256(s2, s1);

Jadi kami mendapat SHISHUA, yang menunjukkan kecepatan 0,06 cpb .

Ini dua kali lebih cepat dari pesaing tercepat sebelumnya di dunia yang lulus tes PractRand 32-terabyte. Hasilnya ada di grafik.

Saya percaya bahwa perkembangannya ternyata kompetitif. Ini bekerja lebih cepat di laptop saya - 0,03 cpb, tapi saya akan mematuhi prinsip saya tentang tolok ukur.

Semoga untuk beberapa minggu lagi generator saya akan tetap di podium tercepat di dunia (silakan lakukan).

Kualitas


Generator dengan jujur ​​melewati tes BigCrush dan 32-terabyte PractRand. Dan semuanya berkat empat aliran keluaran.

Kerugian dari arsitektur termasuk irreversibilitasnya . Ini dapat dilihat dengan mengurangi ke kondisi 4-bit dengan s0 = [a, b]dan s1 = [c, d]. Dengan bergeser, kita mendapatkan [0, a]dan [0, d], dan dengan mengaduk, [b, c]dan [d, a]. Baru s0sama dengan [b, c] + [0, a] = [b⊕(a∧c), a⊕c], tapi s1sama [d, a] + [0, c] = [d⊕(a∧c), a⊕c]. Jika a = ¬c, lalu, a⊕c = 1dan a∧c = 0karena itu, s0 = [b, 1]dan s1 = [d, 1]. Yaitu, kita mendapatkan dua kombinasi adan c, yang memberi kita keadaan akhir yang sama.

Dalam kasus kami, ini bukan masalah, karena penghitung 64-bit juga merupakan bagian dari keadaan. Ternyata siklus minimum 2 71byte (128 byte per transisi negara), yang pada kecepatan 10 gibytes / detik. akan bertahan tujuh ribu tahun. Ini menyeimbangkan keadaan yang hilang.

Selain itu, meskipun tidak dapat dibalikkan, periode transisi rata-rata antar negara adalah 2 ^ ((256 + 1) ÷ 2). Ini memberikan siklus rata-rata 2.135 byte (pada kecepatan 10 gibytes / detik. Ini akan bertahan lebih dari satu triliun kali lebih lama daripada alam semesta ada). Meskipun saya percaya bahwa siklus menengah terlalu tinggi, karena mereka tidak memberi tahu kami apa-apa tentang kualitas generator.

Berikut adalah hasil benchmark:

GeneratorPerformaKualitasKorelasi benih
SHISHUA0,06> 32 TiB> 256 GiB
xoshiro256 + x80,091 KiB0 KiB
ChaCha80,12> 32 TiB?> 32 TiB?
RomuTrio0,31> 32 TiB1 KiB
xoshiro256 +0,34512 MiB1 KiB
Wyrand0,41> 32 TiB8 KiB
Lehmer1280,44> 32 TiB1 KiB
RC47.481 TiB1 KiB

  1. Kinerja : Jumlah siklus prosesor yang dihabiskan untuk satu byte yang dihasilkan. Diterima di mesin cloud N2 GCP dan N2D (AMD), urutannya sama.
  2. Kualitas : Level di mana generator gagal lulus tes PractRand. Jika tidak gagal, ada tanda>. Jika hasilnya tidak terbukti, ada tanda tanya.
  3. Korelasi nomor benih : PractRand traversal dengan byte bergantian dari delapan aliran dengan nomor benih 0, 1, 2, 4, 8, 16, 32, 64. Kami menggunakan PractRand dengan konvolusi ganda dan pengujian lanjutan.



Lebih lanjut


Meskipun dalam kasus kami tidak ada masalah dengan irreversibilitas, kami masih bisa meningkatkan SHISHUA.

Menurut pendapat saya, PRNG yang ideal memiliki sifat-sifat berikut:

  1. , 21024. 10 /. 10282 , . «» ( ). , . , 128- NEON ARM? , , .
  2. . , SHISHUA XOR . , .
  3. , 2128 ( ). SHISHUA, , . , ( ) (, , . 2).
  4. Inisialisasi negara memiliki dispersi sempurna : semua bit dari angka awal mempengaruhi semua bit negara dengan probabilitas yang sama. Saya ingin mencari tahu sehubungan dengan SHISHUA.

Salah satu masalah yang menghambat pengembangan PRNG dan kriptografi secara keseluruhan adalah kurangnya alat tujuan umum yang lebih baik. Saya membutuhkan alat yang dapat segera memberi saya hasil pengukuran yang tepat sehingga saya dapat membandingkan berbagai arsitektur dengan cepat.

Namun, PractRand sangat bagus dibandingkan dengan yang sebelumnya:

  • Itu tidak memungkinkan mengevaluasi generator berkualitas tinggi, sehingga tidak mungkin untuk membandingkan mereka satu sama lain. Kita harus mengatakan: "baiklah, setelah 32 terabyte mereka tidak memiliki anomali ..."
  • Butuh berminggu-minggu untuk menjalankannya ...

Saya harap situasinya akan segera membaik.

All Articles