Cara membangkitkan bilangan acak yang besarC

Saya mencari cara untuk menghasilkan angka acak besar di urutan 2^64 di C... (100000000 - 999999999), untuk digunakan dalam algoritma enkripsi kunci publik (seperti p dan q).

Saya tidak ingin menghasilkan angka yang lebih kecil dari 2^64 (yaitu lebih kecil dari 10.0000000).

Adakah yang bisa membantu saya melakukan ini?


person gfppaste    schedule 27.10.2011    source sumber
comment
2^64 jauh lebih besar dari 999999999.   -  person undur_gongor    schedule 28.10.2011
comment
[100000000 - 999999999] adalah 900.000.000 nilai yang berbeda. Ini adalah angka dengan urutan 30 bit, bukan 64.   -  person chux - Reinstate Monica    schedule 16.08.2018


Jawaban (6)


random() mengembalikan panjang yang pada sistem 64bit harus 64 bit. Jika Anda menggunakan sistem 32bit, Anda dapat melakukan hal berikut:

#include <inttypes.h>

uint64_t num;

/* add code to seed random number generator */

num = rand();
num = (num << 32) | rand();

// enforce limits of value between 100000000 and 999999999
num = (num % (999999999 - 100000000)) + 100000000;

Alternatifnya pada sistem NIX Anda dapat membaca /dev/random ke dalam buffer Anda:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>   

int fd;
uint64_t num; 
if ((fd = open("/dev/random", O_RDONLY) == -1)
{
    /* handle error */
};
read(fd, &num, 8);
close(fd);

// enforce limits of value between 100000000 and 999999999
num = (num % (999999999 - 100000000)) + 100000000;

A

person David M. Syzdek    schedule 27.10.2011
comment
rand() dibatasi oleh RAND_MAX yang tidak diperlukan 2^32. Dan, Anda masih memerlukan sesuatu untuk diteruskan ke srand(). Fungsionalitas /dev/random juga tersedia di platform lain. - person Piotr Praszmo; 27.10.2011
comment
Ini tidak menjamin persyaratan saya tidak ingin menghasilkan angka yang lebih kecil dari ... 100000000 terpenuhi. - person undur_gongor; 28.10.2011
comment
Tambahkan baris num = (num % (999999999 - 100000000)) + 100000000; untuk menghasilkan bilangan acak batas bawah 100000000 dan batas atas 999999999. - person David M. Syzdek; 28.10.2011
comment
Lebih baik, tapi sekarang angka di atas 805933941 (2^64 -1 mod 899999999) kemungkinannya sedikit lebih kecil dibandingkan angka di bawah ;-) - person undur_gongor; 28.10.2011
comment
Di komputer saya RAND_MAX adalah 2^31, bukan 2^32. - person Chiel ten Brinke; 26.12.2014
comment
Dengan asumsi bilangan yang lebih kecil u32 terdistribusi secara merata, apakah bilangan gabungan tersebut u64 = (u32 << 32) | u32 juga? - person this; 02.07.2015
comment
num = (num << 32) | rand(); kemungkinan lemah mengingat Jika Anda menggunakan 32bit, maka RAND_MAX kemungkinan 2^31-1 atau kurang. Maka num = (num << 32) | rand(); akan selalu menghasilkan num mentah dengan beberapa bit dibersihkan pada posisi yang sama. num % (999999999 - 100000000) memang membantu mendistribusikan masalah tersebut namun mengakibatkan kurangnya distribusi yang seragam. - person chux - Reinstate Monica; 16.08.2018

Anda dapat menggabungkan dua bilangan bulat acak berukuran 4 byte untuk menghasilkan bilangan bulat berukuran 8 byte:

#include <stdint.h>
...
uint64_t random = 
  (((uint64_t) rand() <<  0) & 0x00000000FFFFFFFFull) | 
  (((uint64_t) rand() << 32) & 0xFFFFFFFF00000000ull);

Karena rand mengembalikan int, dan sizeof(int) >= 4 di hampir semua platform modern, kode ini seharusnya berfungsi. Saya telah menambahkan << 0 untuk membuat maksudnya lebih eksplisit.

Masking dengan 0x00000000FFFFFFFF dan 0xFFFFFFFF00000000 adalah untuk mencegah tumpang tindih bit dalam dua angka dalam kasus sizeof(int) > 4.

EDIT

Karena @Banthar berkomentar bahwa RAND_MAX belum tentu 2 ^ 32, dan menurut saya setidaknya dijamin 2 ^ 16, Anda dapat menggabungkan empat angka 2-byte hanya untuk memastikan:

uint64_t random = 
  (((uint64_t) rand() <<  0) & 0x000000000000FFFFull) | 
  (((uint64_t) rand() << 16) & 0x00000000FFFF0000ull) | 
  (((uint64_t) rand() << 32) & 0x0000FFFF00000000ull) |
  (((uint64_t) rand() << 48) & 0xFFFF000000000000ull);
person Blagovest Buyukliev    schedule 27.10.2011
comment
Jika Anda menggunakan ^ untuk menggabungkan angka-angka dan bukan |, Anda tidak perlu khawatir tentang penyembunyiannya. - person caf; 28.10.2011
comment
Off-by-one: RAND_MAX sangat kecil kemungkinannya menjadi 2 ^ 32. Mungkin (2 ^ 32) - 1. Namun hal itu pun jarang terjadi. Kemungkinan besar sama dengan INT_MAX yang memiliki nilai umum (2 ^ 31) - 1 atau (2 ^ 15) - 1. C menetapkan RAND_MAX menjadi setidaknya (2^15) - 1, bukan 2 ^ 16. - person chux - Reinstate Monica; 16.08.2018

Anda sedang mencari PRNG dengan kekuatan kriptografi, seperti openssl/rand: http://www.openssl.org/docs/crypto/rand.html

person wkl    schedule 27.10.2011
comment
Atau BCryptGenRandom di Windows Vista dan lebih tinggi. - person Alexey Frunze; 28.10.2011
comment
+1: menggunakan rand() untuk ini adalah lubang keamanan (memprediksi keluaran rand() tidak terlalu menantang) - person Frank Farmer; 28.10.2011
comment
openssl.org/docs/crypto/rand.html tautan mati pada Agustus 2018 .Salah satu masalah dengan jawaban hanya tautan. - person chux - Reinstate Monica; 16.08.2018

Saya tahu saya mungkin akan ditampar oleh OliCharlesworth, tetapi gunakan rand() dengan skala dan offset. Ada di stdlib.h Untuk mencakup seluruh rentang, Anda harus menambahkannya ke rand() yang lebih kecil untuk mengisi kekosongan dalam pemetaan.

person MartyTPS    schedule 27.10.2011

Anda dapat membuat bilangan besar L dari bilangan yang lebih kecil (misalnya A & B). Misalnya, dengan sesuatu seperti L = (2^ n)*A + B di mana ^ menunjukkan eksponensial dan n adalah bilangan bulat konstan (misalnya 32). Kemudian Anda memberi kode 1<<n (pergeseran kiri bitwise) untuk operasi pangkat 2.

Jadi, Anda dapat membuat bilangan acak yang besar dari bilangan acak yang lebih kecil.

person Basile Starynkevitch    schedule 27.10.2011
comment
apa arti huruf L, n, A, and b? bisakah Anda menjelaskannya? - person Ameen; 06.12.2014
comment
Dengan asumsi bilangan yang lebih kecil u32 terdistribusi secara merata, apakah bilangan gabungan tersebut u64 = (u32 << 32) | u32 juga? - person this; 02.07.2015
comment
@ini. Saya kira ya, tetapi Anda harus bertanya pada ahli matematika. - person Basile Starynkevitch; 02.07.2015
comment
L = (2^ n)*A + B menjadi masalah jika rentang B bukan [0...(2^ n)-1]. Lebih baik menggunakan L = (2^ n)*A ^ B jika rentang B lebih lebar (dan masih pangkat 2). Yang terbaik adalah L = (max_possible_value_of_B + (type_of_L)1) *A + B - person chux - Reinstate Monica; 16.08.2018

Atau, Anda dapat menggunakan dua generator angka acak dengan benih INDEPENDEN dan menggabungkan angka keluarannya seperti yang disarankan. Itu tergantung apakah Anda menginginkan RNG nomor 64 bit dengan periode di kisaran 2^64. Hanya saja, jangan gunakan panggilan default yang bergantung pada waktu, karena Anda akan mendapatkan seed yang identik untuk setiap generator. Cara yang benar, saya tidak tahu ...

person jwoods486    schedule 10.08.2015