What's the disadvantage of mt_rand?
mt_rand
uses the Mersenne Twister algorithm, which is far better than the LCG typically used by rand
. For example, the period of an LCG is a measly 232, whereas the period of mt_rand is 219937 − 1. Also, all the values generated by an LCG will lie on lines or planes when plotted into a multidimensional space. Also, it is not only practically feasible, but relatively easy to determine the parameters of an LCG. The only advantage LCGs have is being potentially slightly faster, but on a scale that is completely irrelevant when coding in php.
However, mt_rand
is not suitable for cryptographic purposes (generation of tokens, passwords or cryptographic keys) either.
If you need cryptographic randomness, use random_int
in php 7. On older php versions, read from /dev/urandom
or /dev/random
on a POSIX-conforming operating system.
is mt_rand() more secure than rand()
Directly from the docs:
This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. If you need a cryptographically secure value, consider using openssl_random_pseudo_bytes() instead.
mt_rand
generates better random numbers than rand
, and much faster. But that doesn't make it "secure" in the sense that it should be used for cryptography. Whether it's secure enough for your application is pretty subjective.
Difference between mt_rand() and rand()
Update
Since PHP 7.1 mt_rand
has superseded rand
completely, and rand
was made an alias for mt_rand
. The answer below focuses on the differences between the two functions for older versions, and the reasons for introducing mt_rand
.
Speed was not why mt_rand
was introduced!
The rand
function existed way before mt_rand
, but it was deeply flawed. A PRNG must get some entropy, a number from which it generates a sequence of random numbers. If you print out a list of ten numbers that were generated by rand()
like so:
for ($i=0;$i<10;++$i)
echo rand(), PHP_EOL;
The output can be used to work out what the rand
seed was, and with it, you can predict the next random numbers. There are tools out there that do this, so google a bit and test it.
There's also an issue with rand
relativily quickly showing patterns in its random numbers as demonstrated here. A problem mt_rand
seems to solve a lot better, too.
mt_rand
uses a better randomization algorithm (Mersenne Twist), which requires more random numbers to be known before the seed can be determined and is faster. This does not mean that mt_rand
is, by definition, faster than rand
is, this only means that the way the numbers are generated is faster, and appears to have no real impact on the function's performance, as other answers here have demonstrated.
Either way, have a look at the mt_srand
and the srand
docs. I'm sure they'll contain some more info
If mt_rand
's algorithm translates in an increase in performance, then that's great for you, but it's a happy coincidence. TL;TR:
mt_rand
was introduced to fix the problems that exist in rand
!
How is PHP's mt_rand seeded?
In PHP 5.4, if mt_rand
is automatically seeded the first time it's used (PHP source). The seed value is a function of the current timestamp, the PHP process PID and a value produced by PHP's internal LCG. I didn't check the source for previous versions of PHP, but the documentation implies that this seeding algorithm has been in use starting from PHP 5.2.1.
The RNG algorithm behind mt_rand
is the Mersenne Twister. It doesn't really make sense to talk about "how bad" it is, because it's clearly documented (not on the PHP docs page, unfortunately) that it is entirely unsuitable for cryptographic applications. If you want crypto-strength randomness, use a documented crypto-strength generator.
Update: You might also want to look at this question from crypto.SE.
PHP generating random numbers
Are you using rand()
? Consider "generating a better random value".
Addendum; it's always good to see two sides of a coin.
PHP equivalent of javascript Math.random()
You could use a function that returns the value:
PHP
function random() {
return (float)rand()/(float)getrandmax();
}
// Generates
// 0.85552537614063
// 0.23554185613575
// 0.025269325846126
// 0.016418958098086
JavaScript
var random = function () {
return Math.random();
};
// Generates
// 0.6855146484449506
// 0.910828611580655
// 0.46277225855737925
// 0.6367355801630765
@elclanrs solution is easier and doesn't need the cast in return.
Update
There's a good question about the difference between PHP mt_rand()
and rand()
here:
What's the disadvantage of mt_rand?
If PHP's mt_rand() uses a faster algorithm than rand(), why not just change rand() to use the newer implementation?
Mainly because that's the PHP way. Just like they added mysql_real_escape_string
instead of replacing mysql_escape_string
with it.
However, it might also be related to the disadvantages the mersenne-twister algorithm has (I have no clue if they are also present in the rand()
algorithm though):
The algorithm in its native form is not suitable for cryptography (unlike Blum Blum Shub). Observing a sufficient number of iterates (624 in the case of MT19937, since this figure is the size of the state vector from which future iterates are produced) allows one to predict all future iterates. A pair of cryptographic stream ciphers based on output from Mersenne twister has been proposed by Makoto Matsumoto et al. The authors claim speeds 1.5 to 2 times faster than Advanced Encryption Standard in counter mode. wikipedia
Another issue is that it can take a long time to turn a non-random initial state (notably the presence of many zeros) into output that passes randomness tests. A small lagged Fibonacci generator or linear congruential generator gets started much more quickly and usually is used to seed the Mersenne Twister with random initial values. wikipedia
using rand() for CSRF, can it be safe(r)?
It'll probably be good enough, as long as the generated tokens are user-specific and/or are expired relatively soon. However, if you're going to change it at all, you should change it to use a decent PRNG, which is available on most systems in the form of /dev/random
and can be accessed using a number of ways:
mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM)
openssl_random_pseudo_bytes($raw_salt_len)
fopen('/dev/urandom', 'r') // then fread enough bytes from it
Simply bin2hex
or base64_encode
the return values of the above. Your rand
(or better mt_rand
) solution should only be a fallback in case none of the above are available.
Related Topics
PHP Objects VS Arrays -- Performance Comparison While Iterating
PHP Technique to Query the Apns Feedback Server
PHP Recursion to Get All Possibilities of Strings
How to Add a Delete Button to a PHP Form That Will Delete a Row from a MySQL Table
PHP Add Elements to Multidimensional Array with Array_Push
How to Add New Column to MySQL Table
Php-Fpm Doesn't Write to Error Log
Access Denied for User 'Homestead'@'Localhost' (Using Password: Yes)
Custom User Authentication Base on the Response of an API Call
What's the Best Way to Pass a PHP Variable to JavaScript
Will Copy-On-Write Prevent Data Duplication on Arrays
Getting a Modified Preorder Tree Traversal Model (Nested Set) into a <Ul>
What Does "Mass Assignment" Mean in Laravel
Ssl Operation Failed with Code 1: Dh Key Too Small