I need many cryptographically secure numbers, so I was thinking about extracting randomness from /dev/urandom
and then "converting" it into (say) unsigned long long int
. I guess it should be very efficient and it seems it is cryptographically secure, but I will investigate this aspect more in the future.
Now the question is: how can I do so?
I found this code:
char * block;
short size = 1;
ifstream urandom("/dev/urandom", ios::in|ios::binary);
urandom.read(block,size);
urandom.close();
Does it make sense? And how do I convert what I get to the type I desire?
EDIT - Using random
interface of C++11
Following a suggestion from the comments, I tried using a uniform distribution over the integers and a random_device
initialized as /dev/urandom
. Here is the code:
std::uniform_int_distribution<unsigned int> dist(0, modulus-1);
std::random_device urandom("/dev/urandom");
for(unsigned int i = start ; i < end ; ++i)
{
vector[i] = dist(urandom);
}
The problem is that this code is approximately 1000 times slower than before (I was using a xorshift128+ generator): 5 milliseconds vs. almost 5 seconds. Is this normal? Honestly, I thought that streaming bytes in from /dev/urandom
and converting them to unsigned int
would have been way faster... Am I missing something?
So first of your example is incorrect and would cause undefined behaviour.
The char*
block isn't pointing to any allocated data, so the ifstream::read
would actually write into unallocated memory.
Apart from this the type of size
is signed short
while it should be size_t
.
In order to read a unsigned long long int
you could use `ifstream' like this:
#include <iostream>
#include <fstream>
int main()
{
using namespace std;
unsigned long long int random_value = 0; //Declare value to store data into
size_t size = sizeof(random_value); //Declare size of data
ifstream urandom("/dev/urandom", ios::in|ios::binary); //Open stream
if(urandom) //Check if stream is open
{
urandom.read(reinterpret_cast<char*>(&random_value), size); //Read from urandom
if(urandom) //Check if stream is ok, read succeeded
{
std::cout << "Read random value: " << random_value << std::endl;
}
else //Read failed
{
std::cerr << "Failed to read from /dev/urandom" << std::endl;
}
urandom.close(); //close stream
}
else //Open failed
{
std::cerr << "Failed to open /dev/urandom" << std::endl;
}
return 0;
}
The interesting part would be where this actually reads with urandom.read(reinterpret_cast<char*>(&random_value), size);
The size
should be clear. By using sizeof
we get the actual size in bytes of the data we want to store the random value into. This is useful as this value might be different on different architectures (e.g. 32-bit and 64-bit).
Be careful if the data type you pass here is a pointer. sizeof
will only return the size of the pointer and not the size of the data it is pointing to.
random_value
is of type unsigned long long int
. So &random_value
is the type of the appropriate pointer unsigned long long int*
.
But we want to read bytes (char
) and therefore need to change/cast the value from unsigned long long int*
to char*
(reinterpret_cast<char*>(&random_value)
).