#!/usr/bin/php 
<?php 
use ParagonIE\Argon2Refiner\ParameterRecommender; 
 
if (file_exists(dirname(__DIR__) . '/vendor/autoload.php')) { 
    // We're a standalone package 
    require_once dirname(__DIR__) . '/vendor/autoload.php'; 
} elseif (file_exists(dirname(__DIR__, 3) . '/autoload.php')) { 
    // We're installed as a library 
    require_once dirname(__DIR__, 3) . '/autoload.php'; 
} else { 
    // Trust the include path. 
    require_once 'vendor/autoload.php'; 
} 
 
$ms = $argc > 1 ? $argv[1] : 500; 
$recommender = (new ParameterRecommender($ms)); 
if ($argc > 2) { 
    $tolerance = (int) $argv[2]; 
    if ($tolerance > 0) { 
        $recommender->setTolerance($tolerance); 
    } 
} 
 
$results = $recommender->runBenchmarks(); 
if (empty($results)) { 
    echo 'No parameters meet your target time window.', PHP_EOL; 
    exit(255); 
} 
 
$min = [ 
    'diff' => PHP_INT_MAX, 
    'data' => [ 
        'time_cost' => null, 
        'mem_cost' => null, 
        'bench_time' => PHP_INT_MAX 
    ] 
]; 
 
foreach ($results as $i => $res) { 
    $weightedDiff = $res['bench_time'] - $ms; 
    if ($weightedDiff > 0) { 
        // Apply a penalty to overshots 
        $weightedDiff *= 2; 
    } else { 
        $weightedDiff *= -1; 
    } 
    if ($weightedDiff < $min['diff']) { 
        $min = [ 
            'diff' => $weightedDiff, 
            'data' => $res 
        ]; 
    } 
    $results[$i]['diff'] = $weightedDiff; 
} 
 
$reduced = $min['data']['mem_cost'] >> 10; 
echo 'Recommended Argon2id parameters:', PHP_EOL; 
echo "\t       Memory cost (sodium): {$min['data']['mem_cost']}\n"; 
echo "\tMemory cost (password_hash): {$reduced}\n"; 
echo "\t                  Time cost: {$min['data']['time_cost']}\n\n"; 
echo "Real time: {$min['data']['bench_time']}ms\n"; 
 
 |