: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
return (string) sodium_unpad($padded, $blockSize);
throw new SodiumException('block size cannot be less than 1');
$padded_len = ParagonIE_Sodium_Core_Util::strlen($padded);
if ($padded_len < $blockSize) {
throw new SodiumException('invalid padding');
# tail = &padded[padded_len - 1U];
for ($i = 0; $i < $blockSize; ++$i) {
$c = ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]);
# (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
($acc - 1) & ($pad_len - 1) & (($c ^ 80) - 1)
# pad_len |= i & (1U + ~is_barrier);
$pad_len |= $i & (1 + ~$is_barrier);
# valid |= (unsigned char) is_barrier;
$valid |= ($is_barrier & 0xff);
# unpadded_len = padded_len - 1U - pad_len;
$unpadded_len = $padded_len - 1 - $pad_len;
throw new SodiumException('invalid padding');
return ParagonIE_Sodium_Core_Util::substr($padded, 0, $unpadded_len);
* Will sodium_compat run fast on the current hardware and PHP configuration?
public static function polyfill_is_fast()
if (extension_loaded('sodium')) {
if (extension_loaded('libsodium')) {
return PHP_INT_SIZE === 8;
* Generate a string of bytes from the kernel's CSPRNG.
* Proudly uses /dev/urandom (if getrandom(2) is not available).
public static function randombytes_buf($numBytes)
if (!is_int($numBytes)) {
if (is_numeric($numBytes)) {
$numBytes = (int) $numBytes;
'Argument 1 must be an integer, ' . gettype($numBytes) . ' given.'
/** @var positive-int $numBytes */
if (self::use_fallback('randombytes_buf')) {
return (string) call_user_func('\\Sodium\\randombytes_buf', $numBytes);
throw new SodiumException("Number of bytes must be a positive integer");
return random_bytes($numBytes);
* Generate an integer between 0 and $range (non-inclusive).
public static function randombytes_uniform($range)
if (is_numeric($range)) {
'Argument 1 must be an integer, ' . gettype($range) . ' given.'
if (self::use_fallback('randombytes_uniform')) {
return (int) call_user_func('\\Sodium\\randombytes_uniform', $range);
return random_int(0, $range - 1);
* Generate a random 16-bit integer.
public static function randombytes_random16()
if (self::use_fallback('randombytes_random16')) {
return (int) call_user_func('\\Sodium\\randombytes_random16');
return random_int(0, 65535);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_is_valid_point($p, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_is_valid_point($p);
$r = ParagonIE_Sodium_Core_Ristretto255::ristretto255_frombytes($p);
return $r['res'] === 0 &&
ParagonIE_Sodium_Core_Ristretto255::ristretto255_point_is_canonical($p) === 1;
} catch (SodiumException $ex) {
if ($ex->getMessage() === 'S is not canonical') {
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_add($p, $q, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_add($p, $q);
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_add($p, $q);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_sub($p, $q, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_sub($p, $q);
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_sub($p, $q);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_from_hash($r, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_from_hash($r);
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_from_hash($r);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_random($dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_random();
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_random();
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_scalar_random($dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_random();
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_random();
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_scalar_invert($s, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_invert($s);
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_invert($s);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_scalar_negate($s, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_negate($s);
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_negate($s);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_scalar_complement($s, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_complement($s);
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_complement($s);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_scalar_add($x, $y, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_add($x, $y);
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_add($x, $y);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_scalar_sub($x, $y, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_sub($x, $y);
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_sub($x, $y);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_scalar_mul($x, $y, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_mul($x, $y);
return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_mul($x, $y);
* @param bool $dontFallback
* @throws SodiumException
public static function scalarmult_ristretto255($n, $p, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_scalarmult_ristretto255($n, $p);
return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255($n, $p);
* @param bool $dontFallback
* @throws SodiumException
public static function scalarmult_ristretto255_base($n, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_scalarmult_ristretto255_base($n);
return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255_base($n);
* @param bool $dontFallback
* @throws SodiumException
public static function ristretto255_scalar_reduce($s, $dontFallback = false)
if (self::useNewSodiumAPI() && !$dontFallback) {
return sodium_crypto_core_ristretto255_scalar_reduce($s);
return ParagonIE_Sodium_Core_Ristretto255::sc_reduce($s);
* Runtime testing method for 32-bit platforms.
* Usage: If runtime_speed_test() returns FALSE, then our 32-bit
* implementation is to slow to use safely without risking timeouts.
* If this happens, install sodium from PECL to get acceptable
* @param int $iterations Number of multiplications to attempt
* @param int $maxTimeout Milliseconds
* @return bool TRUE if we're fast enough, FALSE is not
* @throws SodiumException
public static function runtime_speed_test($iterations, $maxTimeout)
if (self::polyfill_is_fast()) {
$start = microtime(true);
/** @var ParagonIE_Sodium_Core32_Int64 $a */
$a = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16));
for ($i = 0; $i < $iterations; ++$i) {
/** @var ParagonIE_Sodium_Core32_Int64 $b */
$b = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16));
$diff = (int) ceil(($end - $start) * 1000);
return $diff < $maxTimeout;
* Add two numbers (little-endian unsigned), storing the value in the first
* @throws SodiumException
public static function sub(&$val, $addv)
$val_len = ParagonIE_Sodium_Core_Util::strlen($val);
$addv_len = ParagonIE_Sodium_Core_Util::strlen($addv);
if ($val_len !== $addv_len) {
throw new SodiumException('values must have the same length');
$A = ParagonIE_Sodium_Core_Util::stringToIntArray($val);
$B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv);
for ($i = 0; $i < $val_len; $i++) {
$c = ($A[$i] - $B[$i] - $c);
$val = ParagonIE_Sodium_Core_Util::intArrayToString($A);
* This emulates libsodium's version_string() function, except ours is
* prefixed with 'polyfill-'.
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress UndefinedFunction
public static function version_string()
if (self::useNewSodiumAPI()) {
return (string) sodium_version_string();
if (self::use_fallback('version_string')) {
return (string) call_user_func('\\Sodium\\version_string');
return (string) self::VERSION_STRING;
* Should we use the libsodium core function instead?
* This is always a good idea, if it's available. (Unless we're in the
* middle of running our unit test suite.)
* If ext/libsodium is available, use it. Return TRUE.
* Otherwise, we have to use the code provided herein. Return FALSE.
* @param string $sodium_func_name
protected static function use_fallback($sodium_func_name = '')
$res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300;
// No libsodium installed
if (self::$disableFallbackForUnitTests) {
// Don't fallback. Use the PHP implementation.
if (!empty($sodium_func_name)) {
return is_callable('\\Sodium\\' . $sodium_func_name);
* Libsodium as implemented in PHP 7.2
* and/or ext/sodium (via PECL)
* @ref https://wiki.php.net/rfc/libsodium
protected static function useNewSodiumAPI()
$res = PHP_VERSION_ID >= 70000 && extension_loaded('sodium');
if (self::$disableFallbackForUnitTests) {
// Don't fallback. Use the PHP implementation.