Skip to content

Instantly share code, notes, and snippets.

@sarciszewski
Last active February 16, 2016 22:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sarciszewski/f7bd4c0358a44321787b to your computer and use it in GitHub Desktop.
Save sarciszewski/f7bd4c0358a44321787b to your computer and use it in GitHub Desktop.
PRNG Benchmarks

In response to some people claiming that using a CSPRNG is "going way overboard" and/or is "overkill", I've written this test to verify the performance impact of using a CSPRNG versus their insecure mt_rand() based hacks.

I think the results are conclusive (at least on my device): A 50% speed increase. In addition to less-predictable randomness.

If anyone would like to suggest a benchmark script (or conditions that lead to different results with mine), let me know and I will link to them here.

<?php
function shitty_prng($bytes = 32)
{
$buf = '';
for ($i = 0; $i < $bytes; ++$i) {
$buf .= chr(mt_rand(0, 255));
}
}
function better_prng($bytes = 32)
{
if (function_exists('mcrypt_create_iv')) {
return mcrypt_create_iv(32, MCRYPT_DEV_URANDOM);
}
return openssl_random_pseudo_bytes(32);
}
function openssl_prng($bytes = 32)
{
return openssl_random_pseudo_bytes(32);
}
function mcrypt_prng($bytes = 32)
{
return mcrypt_create_iv(32, MCRYPT_DEV_URANDOM);
}
<?php
require "functions.php";
$buf = '';
$tests = [];
$start = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
$buf = shitty_prng();
}
$tests['mtrand'] = ( microtime(true) - $start );
$start = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
$buf = better_prng();
}
$tests['csprng'] = ( microtime(true) - $start );
$start = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
$buf = openssl_prng();
}
$tests['openssl'] = ( microtime(true) - $start );
$start = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
$buf = mcrypt_prng();
}
$tests['mcrypt'] = ( microtime(true) - $start );
var_dump($tests);
array(4) {
["mtrand"]=>
float(2.3792960643768)
["csprng"]=>
float(1.0584290027618)
["openssl"]=>
float(0.38547611236572)
["mcrypt"]=>
float(0.97102904319763)
}
array(4) {
["mtrand"]=>
float(2.4055750370026)
["csprng"]=>
float(1.0631558895111)
["openssl"]=>
float(0.30554485321045)
["mcrypt"]=>
float(1.106586933136)
}
array(4) {
["mtrand"]=>
float(2.3207230567932)
["csprng"]=>
float(1.0591180324554)
["openssl"]=>
float(0.29997992515564)
["mcrypt"]=>
float(1.0387818813324)
}
array(4) {
["mtrand"]=>
float(2.3104860782623)
["csprng"]=>
float(1.1197648048401)
["openssl"]=>
float(0.2982759475708)
["mcrypt"]=>
float(1.0270299911499)
}
@Lewiscowles1986
Copy link

Just tested on PHP7 minus mcrypt for reasons of it not being in my docker for PHP7 (I think it's deprecated)

array(3) {
    ["mtrand"]=> float(0.54768705368042) 
    ["csprng"]=> float(0.20757412910461) 
    ["openssl"]=> float(0.19972586631775) 
}

I ran multiple times, looks like the numbers are pretty solid, very little difference very old quad core inside docker environment

@paragonie-scott
Copy link

Try again with random_bytes() instead of mcrypt:

function shitty_prng($bytes = 32)
{
   $buf = '';
   for ($i = 0; $i < $bytes; ++$i) {
      $buf .= chr(mt_rand(0, 255));
   }
}
function better_prng($bytes = 32)
{
   if (function_exists('mcrypt_create_iv')) {
      return mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM);
   }
   return openssl_random_pseudo_bytes($bytes);
}
function openssl_prng($bytes = 32)
{
   return openssl_random_pseudo_bytes($bytes);
}
function best_prng($bytes = 32)
{
   return random_bytes($bytes);
}

$buf = '';
$tests = [];
$start = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
        $buf = shitty_prng();
}
$tests['mtrand'] = ( microtime(true) - $start ); 
$start = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
        $buf = better_prng();
}
$tests['csprng'] = ( microtime(true) - $start ); 
$start = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
        $buf = openssl_prng();
}
$tests['openssl'] = ( microtime(true) - $start ); 
$start = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
        $buf = best_prng();
}
$tests['best'] = ( microtime(true) - $start ); 
var_dump($tests);

Four runs:

root@debian:~# php bench.php 
array(4) {
  ["mtrand"]=>
  float(0.48157906532288)
  ["csprng"]=>
  float(0.30486798286438)
  ["openssl"]=>
  float(0.15188217163086)
  ["best"]=>
  float(0.28898501396179)
}
array(4) {
  ["mtrand"]=>
  float(0.4787449836731)
  ["csprng"]=>
  float(0.29729914665222)
  ["openssl"]=>
  float(0.13547110557556)
  ["best"]=>
  float(0.28169298171997)
}
array(4) {
  ["mtrand"]=>
  float(0.4635169506073)
  ["csprng"]=>
  float(0.3045289516449)
  ["openssl"]=>
  float(0.13414788246155)
  ["best"]=>
  float(0.28961706161499)
}
array(4) {
  ["mtrand"]=>
  float(0.45156908035278)
  ["csprng"]=>
  float(0.30080914497375)
  ["openssl"]=>
  float(0.13886404037476)
  ["best"]=>
  float(0.29005599021912)
}

@paragonie-scott
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment