Spade
Mini Shell
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit75254bdcf8dcdff9c640de25cd452ac4::getLoader();
#!/usr/bin/env bash
basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) )
php -dphar.readonly=0 "$basedir/other/build_phar.php" $*{
"name": "paragonie/random_compat",
"description": "PHP 5.x polyfill for random_bytes() and
random_int() from PHP 7",
"keywords": [
"csprng",
"random",
"polyfill",
"pseudorandom"
],
"license": "MIT",
"type": "library",
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"support": {
"issues":
"https://github.com/paragonie/random_compat/issues",
"email": "info@paragonie.com",
"source":
"https://github.com/paragonie/random_compat"
},
"require": {
"php": ">= 7"
},
"require-dev": {
"vimeo/psalm": "^1",
"phpunit/phpunit": "4.*|5.*"
},
"suggest": {
"ext-libsodium": "Provides a modern crypto API that can
be used to generate random bytes."
}
}
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm
pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p
+h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc
-----END PUBLIC KEY-----
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (MingW32)
iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip
QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg
1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW
NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA
NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV
JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74=
=B6+8
-----END PGP SIGNATURE-----
<?php
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* @version 2.99.99
* @released 2018-06-06
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE
* SOFTWARE.
*/
// NOP
The MIT License (MIT)
Copyright (c) 2015 Paragon Initiative Enterprises
Permission is hereby granted, free of charge, to any person obtaining a
copy
of this software and associated documentation files (the
"Software"), to deal
in the Software without restriction, including without limitation the
rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE
SOFTWARE.
<?php
$dist = dirname(__DIR__).'/dist';
if (!is_dir($dist)) {
mkdir($dist, 0755);
}
if (file_exists($dist.'/random_compat.phar')) {
unlink($dist.'/random_compat.phar');
}
$phar = new Phar(
$dist.'/random_compat.phar',
FilesystemIterator::CURRENT_AS_FILEINFO |
\FilesystemIterator::KEY_AS_FILENAME,
'random_compat.phar'
);
rename(
dirname(__DIR__).'/lib/random.php',
dirname(__DIR__).'/lib/index.php'
);
$phar->buildFromDirectory(dirname(__DIR__).'/lib');
rename(
dirname(__DIR__).'/lib/index.php',
dirname(__DIR__).'/lib/random.php'
);
/**
* If we pass an (optional) path to a private key as a second argument, we
will
* sign the Phar with OpenSSL.
*
* If you leave this out, it will produce an unsigned .phar!
*/
if ($argc > 1) {
if (!@is_readable($argv[1])) {
echo 'Could not read the private key file:', $argv[1],
"\n";
exit(255);
}
$pkeyFile = file_get_contents($argv[1]);
$private = openssl_get_privatekey($pkeyFile);
if ($private !== false) {
$pkey = '';
openssl_pkey_export($private, $pkey);
$phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey);
/**
* Save the corresponding public key to the file
*/
if (!@is_readable($dist.'/random_compat.phar.pubkey')) {
$details = openssl_pkey_get_details($private);
file_put_contents(
$dist.'/random_compat.phar.pubkey',
$details['key']
);
}
} else {
echo 'An error occurred reading the private key from
OpenSSL.', "\n";
exit(255);
}
}
<?php
require_once 'lib/byte_safe_strings.php';
require_once 'lib/cast_to_int.php';
require_once 'lib/error_polyfill.php';
require_once 'other/ide_stubs/libsodium.php';
require_once 'lib/random.php';
$int = random_int(0, 65536);
<?xml version="1.0"?>
<psalm
autoloader="psalm-autoload.php"
stopOnFirstError="false"
useDocblockTypes="true"
>
<projectFiles>
<directory name="lib" />
</projectFiles>
<issueHandlers>
<RedundantConditionGivenDocblockType errorLevel="info"
/>
<UnresolvableInclude errorLevel="info" />
<DuplicateClass errorLevel="info" />
<InvalidOperand errorLevel="info" />
<UndefinedConstant errorLevel="info" />
<MissingReturnType errorLevel="info" />
<InvalidReturnType errorLevel="info" />
</issueHandlers>
</psalm>
/.idea/
/.php_cs.cache
/.phpunit.result.cache
/box/
/dist/sodium-compat.phar
/dist/sodium-compat.phar.sig
/composer.lock
/vendor/
/psalm.xml
build: false
shallow_clone: false
platform:
- x86
- x64
clone_folder: C:\projects\sodium_compat
image: Visual Studio 2017
install:
- cinst -y OpenSSL.Light
- SET PATH=C:\Program Files\OpenSSL;%PATH%
- sc config wuauserv start= auto
- net start wuauserv
- cinst -y php --version 5.6.30
- cd c:\tools\php56
- copy php.ini-production php.ini
- echo date.timezone="UTC" >> php.ini
- echo extension_dir=ext >> php.ini
- echo extension=php_openssl.dll >> php.ini
- cd C:\projects\sodium_compat
- SET PATH=C:\tools\php56;%PATH%
- php.exe -r
"readfile('http://getcomposer.org/installer');" |
php.exe
- php.exe composer.phar install --prefer-source --no-interaction
test_script:
- cd C:\projects\sodium_compat
- vendor\bin\phpunit.bat tests/Windows32Test.php
<?php
require_once 'autoload.php';
ParagonIE_Sodium_Compat::$fastMult = true;
<?php
require_once 'autoload.php';
define('DO_PEDANTIC_TEST', true);
ParagonIE_Sodium_Compat::$fastMult = true;
<?php
/*
This file should only ever be loaded on PHP 7+
*/
if (PHP_VERSION_ID < 70000) {
return;
}
spl_autoload_register(function ($class) {
$namespace = 'ParagonIE_Sodium_';
// Does the class use the namespace prefix?
$len = strlen($namespace);
if (strncmp($namespace, $class, $len) !== 0) {
// no, move to the next registered autoloader
return false;
}
// Get the relative class name
$relative_class = substr($class, $len);
// Replace the namespace prefix with the base directory, replace
namespace
// separators with directory separators in the relative class name,
append
// with .php
$file = dirname(__FILE__) . '/src/' .
str_replace('_', '/', $relative_class) .
'.php';
// if the file exists, require it
if (file_exists($file)) {
require_once $file;
return true;
}
return false;
});
<?php
require_once (dirname(__FILE__) . '/vendor/autoload.php');
if (PHP_VERSION_ID >= 50300) {
require_once (dirname(__FILE__) . '/tests/phpunit-shim.php');
}
<?php
if (PHP_VERSION_ID < 70000) {
if (!is_callable('sodiumCompatAutoloader')) {
/**
* Sodium_Compat autoloader.
*
* @param string $class Class name to be autoloaded.
*
* @return bool Stop autoloading?
*/
function sodiumCompatAutoloader($class)
{
$namespace = 'ParagonIE_Sodium_';
// Does the class use the namespace prefix?
$len = strlen($namespace);
if (strncmp($namespace, $class, $len) !== 0) {
// no, move to the next registered autoloader
return false;
}
// Get the relative class name
$relative_class = substr($class, $len);
// Replace the namespace prefix with the base directory,
replace namespace
// separators with directory separators in the relative class
name, append
// with .php
$file = dirname(__FILE__) . '/src/' .
str_replace('_', '/', $relative_class) .
'.php';
// if the file exists, require it
if (file_exists($file)) {
require_once $file;
return true;
}
return false;
}
// Now that we have an autoloader, let's register it!
spl_autoload_register('sodiumCompatAutoloader');
}
} else {
require_once dirname(__FILE__) . '/autoload-php7.php';
}
if (!class_exists('SodiumException', false)) {
require_once dirname(__FILE__) . '/src/SodiumException.php';
}
if (PHP_VERSION_ID >= 50300) {
// Namespaces didn't exist before 5.3.0, so don't even try to
use this
// unless PHP >= 5.3.0
require_once dirname(__FILE__) . '/lib/namespaced.php';
require_once dirname(__FILE__) . '/lib/sodium_compat.php';
} else {
require_once dirname(__FILE__) .
'/src/PHP52/SplFixedArray.php';
}
if (PHP_VERSION_ID < 70200 || !extension_loaded('sodium')) {
if (PHP_VERSION_ID >= 50300 &&
!defined('SODIUM_CRYPTO_SCALARMULT_BYTES')) {
require_once dirname(__FILE__) .
'/lib/php72compat_const.php';
}
if (PHP_VERSION_ID >= 70000) {
assert(class_exists('ParagonIE_Sodium_Compat'),
'Possible filesystem/autoloader bug?');
} else {
assert(class_exists('ParagonIE_Sodium_Compat'));
}
require_once (dirname(__FILE__) . '/lib/php72compat.php');
}
#!/usr/bin/env bash
curl -LSs https://box-project.github.io/box2/installer.php | php
mkdir ~/box
mv box.phar ~/box/box
PATH=$PATH:~/box/ make -C dist/ build-phar
# PATH=$PATH:~/box/ make -C dist/ sign-phar
{
"name": "paragonie/sodium_compat",
"description": "Pure PHP implementation of libsodium; uses
the PHP extension if it exists",
"keywords": [
"PHP",
"cryptography",
"elliptic curve",
"elliptic curve cryptography",
"Pure-PHP cryptography",
"side-channel resistant",
"Curve25519",
"X25519",
"ECDH",
"Elliptic Curve Diffie-Hellman",
"Ed25519",
"RFC 7748",
"RFC 8032",
"EdDSA",
"Edwards-curve Digital Signature Algorithm",
"ChaCha20",
"Salsa20",
"Xchacha20",
"Xsalsa20",
"Poly1305",
"BLAKE2b",
"public-key cryptography",
"secret-key cryptography",
"AEAD",
"Chapoly",
"Salpoly",
"ChaCha20-Poly1305",
"XSalsa20-Poly1305",
"XChaCha20-Poly1305",
"encryption",
"authentication",
"libsodium"
],
"license": "ISC",
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com"
},
{
"name": "Frank Denis",
"email": "jedisct1@pureftpd.org"
}
],
"autoload": {
"files": ["autoload.php"]
},
"repositories": [
{
"type": "git",
"url": "https://github.com/garex/phpunit"
},
{
"type": "git",
"url":
"https://github.com/garex/phpunit-mock-objects"
}
],
"require": {
"php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7|^8",
"xrstf/composer-php52": "1.*",
"paragonie/random_compat": ">=1"
},
"minimum-stability": "dev",
"require-dev": {
"phpunit/phpunit-php52": "dev-3.6.12-php52",
"phpunit/phpunit-mock-objects-php52":
"dev-1.1.0-php52"
},
"scripts": {
"post-install-cmd": [
"xrstf\\Composer52\\Generator::onPostInstallCmd"
],
"post-update-cmd": [
"xrstf\\Composer52\\Generator::onPostInstallCmd"
],
"post-autoload-dump": [
"xrstf\\Composer52\\Generator::onPostInstallCmd"
]
},
"suggest": {
"ext-libsodium": "PHP < 7.0: Better performance,
password hashing (Argon2i), secure memory management (memzero), and better
security.",
"ext-sodium": "PHP >= 7.0: Better performance,
password hashing (Argon2i), secure memory management (memzero), and better
security."
}
}
{
"name": "paragonie/sodium_compat",
"description": "Pure PHP implementation of libsodium; uses
the PHP extension if it exists",
"keywords": [
"PHP",
"cryptography",
"elliptic curve",
"elliptic curve cryptography",
"Pure-PHP cryptography",
"side-channel resistant",
"Curve25519",
"X25519",
"ECDH",
"Elliptic Curve Diffie-Hellman",
"Ed25519",
"RFC 7748",
"RFC 8032",
"EdDSA",
"Edwards-curve Digital Signature Algorithm",
"ChaCha20",
"Salsa20",
"Xchacha20",
"Xsalsa20",
"Poly1305",
"BLAKE2b",
"public-key cryptography",
"secret-key cryptography",
"AEAD",
"Chapoly",
"Salpoly",
"ChaCha20-Poly1305",
"XSalsa20-Poly1305",
"XChaCha20-Poly1305",
"encryption",
"authentication",
"libsodium"
],
"license": "ISC",
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com"
},
{
"name": "Frank Denis",
"email": "jedisct1@pureftpd.org"
}
],
"autoload": {
"files": ["autoload.php"]
},
"require": {
"php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7|^8",
"paragonie/random_compat": ">=1"
},
"require-dev": {
"phpunit/phpunit": "^3|^4|^5|^6|^7|^8|^9"
},
"suggest": {
"ext-libsodium": "PHP < 7.0: Better performance,
password hashing (Argon2i), secure memory management (memzero), and better
security.",
"ext-sodium": "PHP >= 7.0: Better performance,
password hashing (Argon2i), secure memory management (memzero), and better
security."
}
}
{
"chmod": "0755",
"finder": [
{
"in": "",
"name": "autoload.php"
},
{
"in": "src",
"name": "*.php"
},
{
"in": "lib",
"name": "*.php"
},
{
"in": "vendor/composer",
"name": "*.php"
},
{
"in": "vendor/paragonie",
"name": "*.php"
}
],
"compactors": [
"Herrera\\Box\\Compactor\\Php"
],
"main": "vendor/autoload.php",
"output": "sodium-compat.phar",
"shebang": false,
"stub": true
}
# This builds sodium-compat.phar. To run this Makefile, `box` and
`composer`
# must be installed and in your $PATH. Run it from inside the dist/
directory.
box := $(shell which box)
composer := "composer"
gitcommit := $(shell git rev-parse HEAD)
.PHONY: all
all: build-phar
.PHONY: sign-phar
sign-phar:
gpg -u 7F52D5C61D1255C731362E826B97A1C2826404DA --armor --output
sodium-compat.phar.sig --detach-sig sodium-compat.phar
# ensure we run in clean tree. export git tree and run there.
.PHONY: build-phar
build-phar:
@echo "Creating .phar from revision $(shell git rev-parse
HEAD)."
rm -rf worktree
install -d worktree
(cd $(CURDIR)/..; git archive HEAD) | tar -x -C worktree
$(MAKE) -f $(CURDIR)/Makefile -C worktree sodium-compat.phar
mv worktree/*.phar .
rm -rf worktree
.PHONY: clean
clean:
rm -vf sodium-compat.phar sodium-compat.phar.sig
# Inside workdir/:
sodium-compat.phar: dist/box.json composer.lock
cp dist/box.json .
php -d phar.readonly=0 $(box) build -c box.json -v
composer.lock:
$(composer) config autoloader-suffix $(gitcommit)
$(composer) install --no-dev
<?php
namespace Sodium;
require_once dirname(dirname(__FILE__)) . '/autoload.php';
use ParagonIE_Sodium_Compat;
const CRYPTO_AEAD_AES256GCM_KEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_AES256GCM_KEYBYTES;
const CRYPTO_AEAD_AES256GCM_NSECBYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_AES256GCM_NSECBYTES;
const CRYPTO_AEAD_AES256GCM_NPUBBYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_AES256GCM_NPUBBYTES;
const CRYPTO_AEAD_AES256GCM_ABYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_AES256GCM_ABYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_ABYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES =
ParagonIE_Sodium_Compat::CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES;
const CRYPTO_AUTH_BYTES = ParagonIE_Sodium_Compat::CRYPTO_AUTH_BYTES;
const CRYPTO_AUTH_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_AUTH_KEYBYTES;
const CRYPTO_BOX_SEALBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_SEALBYTES;
const CRYPTO_BOX_SECRETKEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES;
const CRYPTO_BOX_PUBLICKEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES;
const CRYPTO_BOX_KEYPAIRBYTES =
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES;
const CRYPTO_BOX_MACBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_MACBYTES;
const CRYPTO_BOX_NONCEBYTES =
ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES;
const CRYPTO_BOX_SEEDBYTES = ParagonIE_Sodium_Compat::CRYPTO_BOX_SEEDBYTES;
const CRYPTO_KX_BYTES = ParagonIE_Sodium_Compat::CRYPTO_KX_BYTES;
const CRYPTO_KX_SEEDBYTES = ParagonIE_Sodium_Compat::CRYPTO_KX_SEEDBYTES;
const CRYPTO_KX_PUBLICKEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_KX_PUBLICKEYBYTES;
const CRYPTO_KX_SECRETKEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_KX_SECRETKEYBYTES;
const CRYPTO_GENERICHASH_BYTES =
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES;
const CRYPTO_GENERICHASH_BYTES_MIN =
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MIN;
const CRYPTO_GENERICHASH_BYTES_MAX =
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MAX;
const CRYPTO_GENERICHASH_KEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES;
const CRYPTO_GENERICHASH_KEYBYTES_MIN =
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MIN;
const CRYPTO_GENERICHASH_KEYBYTES_MAX =
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MAX;
const CRYPTO_SCALARMULT_BYTES =
ParagonIE_Sodium_Compat::CRYPTO_SCALARMULT_BYTES;
const CRYPTO_SCALARMULT_SCALARBYTES =
ParagonIE_Sodium_Compat::CRYPTO_SCALARMULT_SCALARBYTES;
const CRYPTO_SHORTHASH_BYTES =
ParagonIE_Sodium_Compat::CRYPTO_SHORTHASH_BYTES;
const CRYPTO_SHORTHASH_KEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_SHORTHASH_KEYBYTES;
const CRYPTO_SECRETBOX_KEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES;
const CRYPTO_SECRETBOX_MACBYTES =
ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES;
const CRYPTO_SECRETBOX_NONCEBYTES =
ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES;
const CRYPTO_SIGN_BYTES = ParagonIE_Sodium_Compat::CRYPTO_SIGN_BYTES;
const CRYPTO_SIGN_SEEDBYTES =
ParagonIE_Sodium_Compat::CRYPTO_SIGN_SEEDBYTES;
const CRYPTO_SIGN_PUBLICKEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_SIGN_PUBLICKEYBYTES;
const CRYPTO_SIGN_SECRETKEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_SIGN_SECRETKEYBYTES;
const CRYPTO_SIGN_KEYPAIRBYTES =
ParagonIE_Sodium_Compat::CRYPTO_SIGN_KEYPAIRBYTES;
const CRYPTO_STREAM_KEYBYTES =
ParagonIE_Sodium_Compat::CRYPTO_STREAM_KEYBYTES;
const CRYPTO_STREAM_NONCEBYTES =
ParagonIE_Sodium_Compat::CRYPTO_STREAM_NONCEBYTES;
<?php
require_once dirname(dirname(__FILE__)) . '/autoload.php';
if (PHP_VERSION_ID < 50300) {
return;
}
/*
* This file is just for convenience, to allow developers to reduce
verbosity when
* they add this project to their libraries.
*
* Replace this:
*
* $x =
ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_encrypt(...$args);
*
* with this:
*
* use ParagonIE\Sodium\Compat;
*
* $x = Compat::crypto_aead_xchacha20poly1305_encrypt(...$args);
*/
spl_autoload_register(function ($class) {
if ($class[0] === '\\') {
$class = substr($class, 1);
}
$namespace = 'ParagonIE\\Sodium';
// Does the class use the namespace prefix?
$len = strlen($namespace);
if (strncmp($namespace, $class, $len) !== 0) {
// no, move to the next registered autoloader
return false;
}
// Get the relative class name
$relative_class = substr($class, $len);
// Replace the namespace prefix with the base directory, replace
namespace
// separators with directory separators in the relative class name,
append
// with .php
$file = dirname(dirname(__FILE__)) . '/namespaced/' .
str_replace('\\', '/', $relative_class) .
'.php';
// if the file exists, require it
if (file_exists($file)) {
require_once $file;
return true;
}
return false;
});
<?php
require_once dirname(dirname(__FILE__)) . '/autoload.php';
/**
* This file will monkey patch the pure-PHP implementation in place of the
* PECL functions and constants, but only if they do not already exist.
*
* Thus, the functions or constants just proxy to the appropriate
* ParagonIE_Sodium_Compat method or class constant, respectively.
*/
foreach (array(
'BASE64_VARIANT_ORIGINAL',
'BASE64_VARIANT_ORIGINAL_NO_PADDING',
'BASE64_VARIANT_URLSAFE',
'BASE64_VARIANT_URLSAFE_NO_PADDING',
'CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_ABYTES',
'CRYPTO_AEAD_AES256GCM_KEYBYTES',
'CRYPTO_AEAD_AES256GCM_NSECBYTES',
'CRYPTO_AEAD_AES256GCM_NPUBBYTES',
'CRYPTO_AEAD_AES256GCM_ABYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES',
'CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES',
'CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES',
'CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES',
'CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES',
'CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES',
'CRYPTO_AUTH_BYTES',
'CRYPTO_AUTH_KEYBYTES',
'CRYPTO_BOX_SEALBYTES',
'CRYPTO_BOX_SECRETKEYBYTES',
'CRYPTO_BOX_PUBLICKEYBYTES',
'CRYPTO_BOX_KEYPAIRBYTES',
'CRYPTO_BOX_MACBYTES',
'CRYPTO_BOX_NONCEBYTES',
'CRYPTO_BOX_SEEDBYTES',
'CRYPTO_KDF_BYTES_MIN',
'CRYPTO_KDF_BYTES_MAX',
'CRYPTO_KDF_CONTEXTBYTES',
'CRYPTO_KDF_KEYBYTES',
'CRYPTO_KX_BYTES',
'CRYPTO_KX_KEYPAIRBYTES',
'CRYPTO_KX_PRIMITIVE',
'CRYPTO_KX_SEEDBYTES',
'CRYPTO_KX_PUBLICKEYBYTES',
'CRYPTO_KX_SECRETKEYBYTES',
'CRYPTO_KX_SESSIONKEYBYTES',
'CRYPTO_GENERICHASH_BYTES',
'CRYPTO_GENERICHASH_BYTES_MIN',
'CRYPTO_GENERICHASH_BYTES_MAX',
'CRYPTO_GENERICHASH_KEYBYTES',
'CRYPTO_GENERICHASH_KEYBYTES_MIN',
'CRYPTO_GENERICHASH_KEYBYTES_MAX',
'CRYPTO_PWHASH_SALTBYTES',
'CRYPTO_PWHASH_STRPREFIX',
'CRYPTO_PWHASH_ALG_ARGON2I13',
'CRYPTO_PWHASH_ALG_ARGON2ID13',
'CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE',
'CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE',
'CRYPTO_PWHASH_MEMLIMIT_MODERATE',
'CRYPTO_PWHASH_OPSLIMIT_MODERATE',
'CRYPTO_PWHASH_MEMLIMIT_SENSITIVE',
'CRYPTO_PWHASH_OPSLIMIT_SENSITIVE',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE',
'CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE',
'CRYPTO_SCALARMULT_BYTES',
'CRYPTO_SCALARMULT_SCALARBYTES',
'CRYPTO_SHORTHASH_BYTES',
'CRYPTO_SHORTHASH_KEYBYTES',
'CRYPTO_SECRETBOX_KEYBYTES',
'CRYPTO_SECRETBOX_MACBYTES',
'CRYPTO_SECRETBOX_NONCEBYTES',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL',
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX',
'CRYPTO_SIGN_BYTES',
'CRYPTO_SIGN_SEEDBYTES',
'CRYPTO_SIGN_PUBLICKEYBYTES',
'CRYPTO_SIGN_SECRETKEYBYTES',
'CRYPTO_SIGN_KEYPAIRBYTES',
'CRYPTO_STREAM_KEYBYTES',
'CRYPTO_STREAM_NONCEBYTES',
'LIBRARY_MAJOR_VERSION',
'LIBRARY_MINOR_VERSION',
'LIBRARY_VERSION_MAJOR',
'LIBRARY_VERSION_MINOR',
'VERSION_STRING'
) as $constant
) {
if (!defined("SODIUM_$constant") &&
defined("ParagonIE_Sodium_Compat::$constant")) {
define("SODIUM_$constant",
constant("ParagonIE_Sodium_Compat::$constant"));
}
}
if (!is_callable('sodium_add')) {
/**
* @see ParagonIE_Sodium_Compat::add()
* @param string $val
* @param string $addv
* @return void
* @throws SodiumException
*/
function sodium_add(&$val, $addv)
{
ParagonIE_Sodium_Compat::add($val, $addv);
}
}
if (!is_callable('sodium_base642bin')) {
/**
* @see ParagonIE_Sodium_Compat::bin2base64()
* @param string $string
* @param int $variant
* @param string $ignore
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_base642bin($string, $variant, $ignore ='')
{
return ParagonIE_Sodium_Compat::base642bin($string, $variant,
$ignore);
}
}
if (!is_callable('sodium_bin2base64')) {
/**
* @see ParagonIE_Sodium_Compat::bin2base64()
* @param string $string
* @param int $variant
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_bin2base64($string, $variant)
{
return ParagonIE_Sodium_Compat::bin2base64($string, $variant);
}
}
if (!is_callable('sodium_bin2hex')) {
/**
* @see ParagonIE_Sodium_Compat::hex2bin()
* @param string $string
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_bin2hex($string)
{
return ParagonIE_Sodium_Compat::bin2hex($string);
}
}
if (!is_callable('sodium_compare')) {
/**
* @see ParagonIE_Sodium_Compat::compare()
* @param string $a
* @param string $b
* @return int
* @throws SodiumException
* @throws TypeError
*/
function sodium_compare($a, $b)
{
return ParagonIE_Sodium_Compat::compare($a, $b);
}
}
if (!is_callable('sodium_crypto_aead_aes256gcm_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_aead_aes256gcm_decrypt($message, $assocData,
$nonce, $key)
{
try {
return
ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt($message,
$assocData, $nonce, $key);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_aead_aes256gcm_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_aes256gcm_encrypt($message, $assocData,
$nonce, $key)
{
return
ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_encrypt($message,
$assocData, $nonce, $key);
}
}
if (!is_callable('sodium_crypto_aead_aes256gcm_is_available')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_is_available()
* @return bool
*/
function sodium_crypto_aead_aes256gcm_is_available()
{
return
ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_is_available();
}
}
if (!is_callable('sodium_crypto_aead_chacha20poly1305_decrypt'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_aead_chacha20poly1305_decrypt($message,
$assocData, $nonce, $key)
{
try {
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_decrypt($message,
$assocData, $nonce, $key);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_aead_chacha20poly1305_encrypt'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_chacha20poly1305_encrypt($message,
$assocData, $nonce, $key)
{
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_encrypt($message,
$assocData, $nonce, $key);
}
}
if (!is_callable('sodium_crypto_aead_chacha20poly1305_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_aead_chacha20poly1305_keygen()
{
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_keygen();
}
}
if
(!is_callable('sodium_crypto_aead_chacha20poly1305_ietf_decrypt'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_aead_chacha20poly1305_ietf_decrypt($message,
$assocData, $nonce, $key)
{
try {
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_decrypt($message,
$assocData, $nonce, $key);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if
(!is_callable('sodium_crypto_aead_chacha20poly1305_ietf_encrypt'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_chacha20poly1305_ietf_encrypt($message,
$assocData, $nonce, $key)
{
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt($message,
$assocData, $nonce, $key);
}
}
if
(!is_callable('sodium_crypto_aead_chacha20poly1305_ietf_keygen'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_aead_chacha20poly1305_ietf_keygen()
{
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_keygen();
}
}
if
(!is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_aead_xchacha20poly1305_ietf_decrypt($message,
$assocData, $nonce, $key)
{
try {
return
ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_decrypt($message,
$assocData, $nonce, $key, true);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if
(!is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_xchacha20poly1305_ietf_encrypt($message,
$assocData, $nonce, $key)
{
return
ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_encrypt($message,
$assocData, $nonce, $key, true);
}
}
if
(!is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_keygen'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_aead_xchacha20poly1305_ietf_keygen()
{
return
ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_keygen();
}
}
if (!is_callable('sodium_crypto_auth')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth()
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_auth($message, $key)
{
return ParagonIE_Sodium_Compat::crypto_auth($message, $key);
}
}
if (!is_callable('sodium_crypto_auth_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_auth_keygen()
{
return ParagonIE_Sodium_Compat::crypto_auth_keygen();
}
}
if (!is_callable('sodium_crypto_auth_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth_verify()
* @param string $mac
* @param string $message
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_auth_verify($mac, $message, $key)
{
return ParagonIE_Sodium_Compat::crypto_auth_verify($mac, $message,
$key);
}
}
if (!is_callable('sodium_crypto_box')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box()
* @param string $message
* @param string $nonce
* @param string $kp
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box($message, $nonce, $kp)
{
return ParagonIE_Sodium_Compat::crypto_box($message, $nonce, $kp);
}
}
if (!is_callable('sodium_crypto_box_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_keypair()
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_keypair()
{
return ParagonIE_Sodium_Compat::crypto_box_keypair();
}
}
if
(!is_callable('sodium_crypto_box_keypair_from_secretkey_and_publickey'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey()
* @param string $sk
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_keypair_from_secretkey_and_publickey($sk,
$pk)
{
return
ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey($sk,
$pk);
}
}
if (!is_callable('sodium_crypto_box_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_open()
* @param string $message
* @param string $nonce
* @param string $kp
* @return string|bool
*/
function sodium_crypto_box_open($message, $nonce, $kp)
{
try {
return ParagonIE_Sodium_Compat::crypto_box_open($message,
$nonce, $kp);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_box_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_publickey()
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_publickey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_box_publickey($keypair);
}
}
if (!is_callable('sodium_crypto_box_publickey_from_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_publickey_from_secretkey()
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_publickey_from_secretkey($sk)
{
return
ParagonIE_Sodium_Compat::crypto_box_publickey_from_secretkey($sk);
}
}
if (!is_callable('sodium_crypto_box_seal')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seal()
* @param string $message
* @param string $publicKey
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_seal($message, $publicKey)
{
return ParagonIE_Sodium_Compat::crypto_box_seal($message,
$publicKey);
}
}
if (!is_callable('sodium_crypto_box_seal_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seal_open()
* @param string $message
* @param string $kp
* @return string|bool
* @throws SodiumException
*/
function sodium_crypto_box_seal_open($message, $kp)
{
try {
return ParagonIE_Sodium_Compat::crypto_box_seal_open($message,
$kp);
} catch (SodiumException $ex) {
if ($ex->getMessage() === 'Argument 2 must be
CRYPTO_BOX_KEYPAIRBYTES long.') {
throw $ex;
}
return false;
}
}
}
if (!is_callable('sodium_crypto_box_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_secretkey()
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_secretkey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_box_secretkey($keypair);
}
}
if (!is_callable('sodium_crypto_box_seed_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seed_keypair()
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_box_seed_keypair($seed)
{
return ParagonIE_Sodium_Compat::crypto_box_seed_keypair($seed);
}
}
if (!is_callable('sodium_crypto_generichash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash()
* @param string $message
* @param string|null $key
* @param int $outLen
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_generichash($message, $key = null, $outLen = 32)
{
return ParagonIE_Sodium_Compat::crypto_generichash($message, $key,
$outLen);
}
}
if (!is_callable('sodium_crypto_generichash_final')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_final()
* @param string|null $ctx
* @param int $outputLength
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_generichash_final(&$ctx, $outputLength = 32)
{
return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx,
$outputLength);
}
}
if (!is_callable('sodium_crypto_generichash_init')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_init()
* @param string|null $key
* @param int $outLen
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_generichash_init($key = null, $outLen = 32)
{
return ParagonIE_Sodium_Compat::crypto_generichash_init($key,
$outLen);
}
}
if (!is_callable('sodium_crypto_generichash_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_generichash_keygen()
{
return ParagonIE_Sodium_Compat::crypto_generichash_keygen();
}
}
if (!is_callable('sodium_crypto_generichash_update')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_update()
* @param string|null $ctx
* @param string $message
* @return void
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_generichash_update(&$ctx, $message =
'')
{
ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, $message);
}
}
if (!is_callable('sodium_crypto_kdf_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_kdf_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_kdf_keygen()
{
return ParagonIE_Sodium_Compat::crypto_kdf_keygen();
}
}
if (!is_callable('sodium_crypto_kdf_derive_from_key')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_kdf_derive_from_key()
* @param int $subkey_len
* @param int $subkey_id
* @param string $context
* @param string $key
* @return string
* @throws Exception
*/
function sodium_crypto_kdf_derive_from_key($subkey_len, $subkey_id,
$context, $key)
{
return ParagonIE_Sodium_Compat::crypto_kdf_derive_from_key(
$subkey_len,
$subkey_id,
$context,
$key
);
}
}
if (!is_callable('sodium_crypto_kx')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_kx()
* @param string $my_secret
* @param string $their_public
* @param string $client_public
* @param string $server_public
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_kx($my_secret, $their_public, $client_public,
$server_public)
{
return ParagonIE_Sodium_Compat::crypto_kx(
$my_secret,
$their_public,
$client_public,
$server_public
);
}
}
if (!is_callable('sodium_crypto_kx_seed_keypair')) {
/**
* @param string $seed
* @return string
* @throws Exception
*/
function sodium_crypto_kx_seed_keypair($seed)
{
return ParagonIE_Sodium_Compat::crypto_kx_seed_keypair($seed);
}
}
if (!is_callable('sodium_crypto_kx_keypair')) {
/**
* @return string
* @throws Exception
*/
function sodium_crypto_kx_keypair()
{
return ParagonIE_Sodium_Compat::crypto_kx_keypair();
}
}
if (!is_callable('sodium_crypto_kx_client_session_keys')) {
/**
* @param string $keypair
* @param string $serverPublicKey
* @return array{0: string, 1: string}
* @throws SodiumException
*/
function sodium_crypto_kx_client_session_keys($keypair,
$serverPublicKey)
{
return
ParagonIE_Sodium_Compat::crypto_kx_client_session_keys($keypair,
$serverPublicKey);
}
}
if (!is_callable('sodium_crypto_kx_server_session_keys')) {
/**
* @param string $keypair
* @param string $clientPublicKey
* @return array{0: string, 1: string}
* @throws SodiumException
*/
function sodium_crypto_kx_server_session_keys($keypair,
$clientPublicKey)
{
return
ParagonIE_Sodium_Compat::crypto_kx_server_session_keys($keypair,
$clientPublicKey);
}
}
if (!is_callable('sodium_crypto_kx_secretkey')) {
/**
* @param string $keypair
* @return string
* @throws Exception
*/
function sodium_crypto_kx_secretkey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_kx_secretkey($keypair);
}
}
if (!is_callable('sodium_crypto_kx_publickey')) {
/**
* @param string $keypair
* @return string
* @throws Exception
*/
function sodium_crypto_kx_publickey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_kx_publickey($keypair);
}
}
if (!is_callable('sodium_crypto_pwhash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash()
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @param int|null $algo
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit,
$memlimit, $algo = null)
{
return ParagonIE_Sodium_Compat::crypto_pwhash($outlen, $passwd,
$salt, $opslimit, $memlimit, $algo);
}
}
if (!is_callable('sodium_crypto_pwhash_str')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str()
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_str($passwd, $opslimit, $memlimit)
{
return ParagonIE_Sodium_Compat::crypto_pwhash_str($passwd,
$opslimit, $memlimit);
}
}
if (!is_callable('sodium_crypto_pwhash_str_needs_rehash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str_needs_rehash()
* @param string $hash
* @param int $opslimit
* @param int $memlimit
* @return bool
*
* @throws SodiumException
*/
function sodium_crypto_pwhash_str_needs_rehash($hash, $opslimit,
$memlimit)
{
return
ParagonIE_Sodium_Compat::crypto_pwhash_str_needs_rehash($hash, $opslimit,
$memlimit);
}
}
if (!is_callable('sodium_crypto_pwhash_str_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str_verify()
* @param string $passwd
* @param string $hash
* @return bool
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_str_verify($passwd, $hash)
{
return ParagonIE_Sodium_Compat::crypto_pwhash_str_verify($passwd,
$hash);
}
}
if (!is_callable('sodium_crypto_pwhash_scryptsalsa208sha256')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256()
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_scryptsalsa208sha256($outlen, $passwd,
$salt, $opslimit, $memlimit)
{
return
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256($outlen,
$passwd, $salt, $opslimit, $memlimit);
}
}
if
(!is_callable('sodium_crypto_pwhash_scryptsalsa208sha256_str')) {
/**
* @see
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str()
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_scryptsalsa208sha256_str($passwd,
$opslimit, $memlimit)
{
return
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str($passwd,
$opslimit, $memlimit);
}
}
if
(!is_callable('sodium_crypto_pwhash_scryptsalsa208sha256_str_verify'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str_verify()
* @param string $passwd
* @param string $hash
* @return bool
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_pwhash_scryptsalsa208sha256_str_verify($passwd,
$hash)
{
return
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str_verify($passwd,
$hash);
}
}
if (!is_callable('sodium_crypto_scalarmult')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult()
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_scalarmult($n, $p)
{
return ParagonIE_Sodium_Compat::crypto_scalarmult($n, $p);
}
}
if (!is_callable('sodium_crypto_scalarmult_base')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult_base()
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_scalarmult_base($n)
{
return ParagonIE_Sodium_Compat::crypto_scalarmult_base($n);
}
}
if (!is_callable('sodium_crypto_secretbox')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_secretbox($message, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_secretbox($message, $nonce,
$key);
}
}
if (!is_callable('sodium_crypto_secretbox_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_secretbox_keygen()
{
return ParagonIE_Sodium_Compat::crypto_secretbox_keygen();
}
}
if (!is_callable('sodium_crypto_secretbox_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox_open()
* @param string $message
* @param string $nonce
* @param string $key
* @return string|bool
*/
function sodium_crypto_secretbox_open($message, $nonce, $key)
{
try {
return ParagonIE_Sodium_Compat::crypto_secretbox_open($message,
$nonce, $key);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if
(!is_callable('sodium_crypto_secretstream_xchacha20poly1305_init_push'))
{
/**
* @param string $key
* @return array<int, string>
* @throws SodiumException
*/
function sodium_crypto_secretstream_xchacha20poly1305_init_push($key)
{
return
ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_push($key);
}
}
if
(!is_callable('sodium_crypto_secretstream_xchacha20poly1305_push'))
{
/**
* @param string $state
* @param string $msg
* @param string $aad
* @param int $tag
* @return string
* @throws SodiumException
*/
function sodium_crypto_secretstream_xchacha20poly1305_push(&$state,
$msg, $aad = '', $tag = 0)
{
return
ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_push($state,
$msg, $aad, $tag);
}
}
if
(!is_callable('sodium_crypto_secretstream_xchacha20poly1305_init_pull'))
{
/**
* @param string $header
* @param string $key
* @return string
* @throws Exception
*/
function
sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $key)
{
return
ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_pull($header,
$key);
}
}
if
(!is_callable('sodium_crypto_secretstream_xchacha20poly1305_pull'))
{
/**
* @param string $state
* @param string $cipher
* @param string $aad
* @return bool|array{0: string, 1: int}
* @throws SodiumException
*/
function sodium_crypto_secretstream_xchacha20poly1305_pull(&$state,
$cipher, $aad = '')
{
return
ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_pull($state,
$cipher, $aad);
}
}
if
(!is_callable('sodium_crypto_secretstream_xchacha20poly1305_rekey'))
{
/**
* @param string $state
* @return void
* @throws SodiumException
*/
function
sodium_crypto_secretstream_xchacha20poly1305_rekey(&$state)
{
ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_rekey($state);
}
}
if
(!is_callable('sodium_crypto_secretstream_xchacha20poly1305_keygen'))
{
/**
* @return string
* @throws Exception
*/
function sodium_crypto_secretstream_xchacha20poly1305_keygen()
{
return
ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_keygen();
}
}
if (!is_callable('sodium_crypto_shorthash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_shorthash()
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_shorthash($message, $key = '')
{
return ParagonIE_Sodium_Compat::crypto_shorthash($message, $key);
}
}
if (!is_callable('sodium_crypto_shorthash_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_shorthash_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_shorthash_keygen()
{
return ParagonIE_Sodium_Compat::crypto_shorthash_keygen();
}
}
if (!is_callable('sodium_crypto_sign')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign()
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign($message, $sk)
{
return ParagonIE_Sodium_Compat::crypto_sign($message, $sk);
}
}
if (!is_callable('sodium_crypto_sign_detached')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_detached()
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_detached($message, $sk)
{
return ParagonIE_Sodium_Compat::crypto_sign_detached($message,
$sk);
}
}
if
(!is_callable('sodium_crypto_sign_keypair_from_secretkey_and_publickey'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey()
* @param string $sk
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk,
$pk)
{
return
ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey($sk,
$pk);
}
}
if (!is_callable('sodium_crypto_sign_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_keypair()
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_keypair()
{
return ParagonIE_Sodium_Compat::crypto_sign_keypair();
}
}
if (!is_callable('sodium_crypto_sign_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_open()
* @param string $signedMessage
* @param string $pk
* @return string|bool
*/
function sodium_crypto_sign_open($signedMessage, $pk)
{
try {
return
ParagonIE_Sodium_Compat::crypto_sign_open($signedMessage, $pk);
} catch (Error $ex) {
return false;
} catch (Exception $ex) {
return false;
}
}
}
if (!is_callable('sodium_crypto_sign_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_publickey()
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_publickey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_sign_publickey($keypair);
}
}
if (!is_callable('sodium_crypto_sign_publickey_from_secretkey'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey()
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_publickey_from_secretkey($sk)
{
return
ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey($sk);
}
}
if (!is_callable('sodium_crypto_sign_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_secretkey()
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_secretkey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_sign_secretkey($keypair);
}
}
if (!is_callable('sodium_crypto_sign_seed_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_seed_keypair()
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_seed_keypair($seed)
{
return ParagonIE_Sodium_Compat::crypto_sign_seed_keypair($seed);
}
}
if (!is_callable('sodium_crypto_sign_verify_detached')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_verify_detached()
* @param string $signature
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_verify_detached($signature, $message, $pk)
{
return
ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $message,
$pk);
}
}
if (!is_callable('sodium_crypto_sign_ed25519_pk_to_curve25519'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519()
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_ed25519_pk_to_curve25519($pk)
{
return
ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519($pk);
}
}
if (!is_callable('sodium_crypto_sign_ed25519_sk_to_curve25519'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519()
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_sign_ed25519_sk_to_curve25519($sk)
{
return
ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519($sk);
}
}
if (!is_callable('sodium_crypto_stream')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream()
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream($len, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_stream($len, $nonce, $key);
}
}
if (!is_callable('sodium_crypto_stream_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_stream_keygen()
{
return ParagonIE_Sodium_Compat::crypto_stream_keygen();
}
}
if (!is_callable('sodium_crypto_stream_xor')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xor()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream_xor($message, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_stream_xor($message, $nonce,
$key);
}
}
if (!is_callable('sodium_hex2bin')) {
/**
* @see ParagonIE_Sodium_Compat::hex2bin()
* @param string $string
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_hex2bin($string)
{
return ParagonIE_Sodium_Compat::hex2bin($string);
}
}
if (!is_callable('sodium_increment')) {
/**
* @see ParagonIE_Sodium_Compat::increment()
* @param string $string
* @return void
* @throws SodiumException
* @throws TypeError
*/
function sodium_increment(&$string)
{
ParagonIE_Sodium_Compat::increment($string);
}
}
if (!is_callable('sodium_library_version_major')) {
/**
* @see ParagonIE_Sodium_Compat::library_version_major()
* @return int
*/
function sodium_library_version_major()
{
return ParagonIE_Sodium_Compat::library_version_major();
}
}
if (!is_callable('sodium_library_version_minor')) {
/**
* @see ParagonIE_Sodium_Compat::library_version_minor()
* @return int
*/
function sodium_library_version_minor()
{
return ParagonIE_Sodium_Compat::library_version_minor();
}
}
if (!is_callable('sodium_version_string')) {
/**
* @see ParagonIE_Sodium_Compat::version_string()
* @return string
*/
function sodium_version_string()
{
return ParagonIE_Sodium_Compat::version_string();
}
}
if (!is_callable('sodium_memcmp')) {
/**
* @see ParagonIE_Sodium_Compat::memcmp()
* @param string $a
* @param string $b
* @return int
* @throws SodiumException
* @throws TypeError
*/
function sodium_memcmp($a, $b)
{
return ParagonIE_Sodium_Compat::memcmp($a, $b);
}
}
if (!is_callable('sodium_memzero')) {
/**
* @see ParagonIE_Sodium_Compat::memzero()
* @param string $str
* @return void
* @throws SodiumException
* @throws TypeError
*/
function sodium_memzero(&$str)
{
ParagonIE_Sodium_Compat::memzero($str);
}
}
if (!is_callable('sodium_pad')) {
/**
* @see ParagonIE_Sodium_Compat::pad()
* @param string $unpadded
* @param int $blockSize
* @return int
* @throws SodiumException
* @throws TypeError
*/
function sodium_pad($unpadded, $blockSize)
{
return ParagonIE_Sodium_Compat::pad($unpadded, $blockSize, true);
}
}
if (!is_callable('sodium_unpad')) {
/**
* @see ParagonIE_Sodium_Compat::pad()
* @param string $padded
* @param int $blockSize
* @return int
* @throws SodiumException
* @throws TypeError
*/
function sodium_unpad($padded, $blockSize)
{
return ParagonIE_Sodium_Compat::unpad($padded, $blockSize, true);
}
}
if (!is_callable('sodium_randombytes_buf')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_buf()
* @param int $amount
* @return string
* @throws Exception
*/
function sodium_randombytes_buf($amount)
{
return ParagonIE_Sodium_Compat::randombytes_buf($amount);
}
}
if (!is_callable('sodium_randombytes_uniform')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_uniform()
* @param int $upperLimit
* @return int
* @throws Exception
*/
function sodium_randombytes_uniform($upperLimit)
{
return ParagonIE_Sodium_Compat::randombytes_uniform($upperLimit);
}
}
if (!is_callable('sodium_randombytes_random16')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_random16()
* @return int
* @throws Exception
*/
function sodium_randombytes_random16()
{
return ParagonIE_Sodium_Compat::randombytes_random16();
}
}
<?php
const SODIUM_LIBRARY_MAJOR_VERSION = 9;
const SODIUM_LIBRARY_MINOR_VERSION = 1;
const SODIUM_LIBRARY_VERSION = '1.0.8';
const SODIUM_BASE64_VARIANT_ORIGINAL = 1;
const SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
const SODIUM_BASE64_VARIANT_URLSAFE = 5;
const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
const SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12;
const SODIUM_CRYPTO_AEAD_AES256GCM_ABYTES = 16;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12;
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16;
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24;
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16;
const SODIUM_CRYPTO_AUTH_BYTES = 32;
const SODIUM_CRYPTO_AUTH_KEYBYTES = 32;
const SODIUM_CRYPTO_BOX_SEALBYTES = 16;
const SODIUM_CRYPTO_BOX_SECRETKEYBYTES = 32;
const SODIUM_CRYPTO_BOX_PUBLICKEYBYTES = 32;
const SODIUM_CRYPTO_BOX_KEYPAIRBYTES = 64;
const SODIUM_CRYPTO_BOX_MACBYTES = 16;
const SODIUM_CRYPTO_BOX_NONCEBYTES = 24;
const SODIUM_CRYPTO_BOX_SEEDBYTES = 32;
const SODIUM_CRYPTO_KDF_BYTES_MIN = 16;
const SODIUM_CRYPTO_KDF_BYTES_MAX = 64;
const SODIUM_CRYPTO_KDF_CONTEXTBYTES = 8;
const SODIUM_CRYPTO_KDF_KEYBYTES = 32;
const SODIUM_CRYPTO_KX_BYTES = 32;
const SODIUM_CRYPTO_KX_PRIMITIVE = 'x25519blake2b';
const SODIUM_CRYPTO_KX_SEEDBYTES = 32;
const SODIUM_CRYPTO_KX_KEYPAIRBYTES = 64;
const SODIUM_CRYPTO_KX_PUBLICKEYBYTES = 32;
const SODIUM_CRYPTO_KX_SECRETKEYBYTES = 32;
const SODIUM_CRYPTO_KX_SESSIONKEYBYTES = 32;
const SODIUM_CRYPTO_GENERICHASH_BYTES = 32;
const SODIUM_CRYPTO_GENERICHASH_BYTES_MIN = 16;
const SODIUM_CRYPTO_GENERICHASH_BYTES_MAX = 64;
const SODIUM_CRYPTO_GENERICHASH_KEYBYTES = 32;
const SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MIN = 16;
const SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
const SODIUM_CRYPTO_PWHASH_SALTBYTES = 16;
const SODIUM_CRYPTO_PWHASH_STRPREFIX = '$argon2id$';
const SODIUM_CRYPTO_PWHASH_ALG_ARGON2I13 = 1;
const SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13 = 2;
const SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432;
const SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4;
const SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728;
const SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6;
const SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912;
const SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX =
'$7$';
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE =
534288;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE =
16777216;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE =
33554432;
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE =
1073741824;
const SODIUM_CRYPTO_SCALARMULT_BYTES = 32;
const SODIUM_CRYPTO_SCALARMULT_SCALARBYTES = 32;
const SODIUM_CRYPTO_SHORTHASH_BYTES = 8;
const SODIUM_CRYPTO_SHORTHASH_KEYBYTES = 16;
const SODIUM_CRYPTO_SECRETBOX_KEYBYTES = 32;
const SODIUM_CRYPTO_SECRETBOX_MACBYTES = 16;
const SODIUM_CRYPTO_SECRETBOX_NONCEBYTES = 24;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3;
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX =
0x3fffffff80;
const SODIUM_CRYPTO_SIGN_BYTES = 64;
const SODIUM_CRYPTO_SIGN_SEEDBYTES = 32;
const SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES = 32;
const SODIUM_CRYPTO_SIGN_SECRETKEYBYTES = 64;
const SODIUM_CRYPTO_SIGN_KEYPAIRBYTES = 96;
const SODIUM_CRYPTO_STREAM_KEYBYTES = 32;
const SODIUM_CRYPTO_STREAM_NONCEBYTES = 24;
<?php
namespace Sodium;
require_once dirname(dirname(__FILE__)) . '/autoload.php';
use ParagonIE_Sodium_Compat;
/**
* This file will monkey patch the pure-PHP implementation in place of the
* PECL functions, but only if they do not already exist.
*
* Thus, the functions just proxy to the appropriate
ParagonIE_Sodium_Compat
* method.
*/
if (!is_callable('\\Sodium\\bin2hex')) {
/**
* @see ParagonIE_Sodium_Compat::bin2hex()
* @param string $string
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function bin2hex($string)
{
return ParagonIE_Sodium_Compat::bin2hex($string);
}
}
if (!is_callable('\\Sodium\\compare')) {
/**
* @see ParagonIE_Sodium_Compat::compare()
* @param string $a
* @param string $b
* @return int
* @throws \SodiumException
* @throws \TypeError
*/
function compare($a, $b)
{
return ParagonIE_Sodium_Compat::compare($a, $b);
}
}
if (!is_callable('\\Sodium\\crypto_aead_aes256gcm_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function crypto_aead_aes256gcm_decrypt($message, $assocData, $nonce,
$key)
{
try {
return
ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_decrypt($message,
$assocData, $nonce, $key);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_aead_aes256gcm_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_aead_aes256gcm_encrypt($message, $assocData, $nonce,
$key)
{
return
ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_encrypt($message,
$assocData, $nonce, $key);
}
}
if (!is_callable('\\Sodium\\crypto_aead_aes256gcm_is_available'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_is_available()
* @return bool
*/
function crypto_aead_aes256gcm_is_available()
{
return
ParagonIE_Sodium_Compat::crypto_aead_aes256gcm_is_available();
}
}
if
(!is_callable('\\Sodium\\crypto_aead_chacha20poly1305_decrypt'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function crypto_aead_chacha20poly1305_decrypt($message, $assocData,
$nonce, $key)
{
try {
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_decrypt($message,
$assocData, $nonce, $key);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if
(!is_callable('\\Sodium\\crypto_aead_chacha20poly1305_encrypt'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_aead_chacha20poly1305_encrypt($message, $assocData,
$nonce, $key)
{
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_encrypt($message,
$assocData, $nonce, $key);
}
}
if
(!is_callable('\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_decrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string|bool
*/
function crypto_aead_chacha20poly1305_ietf_decrypt($message,
$assocData, $nonce, $key)
{
try {
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_decrypt($message,
$assocData, $nonce, $key);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if
(!is_callable('\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt()
* @param string $message
* @param string $assocData
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_aead_chacha20poly1305_ietf_encrypt($message,
$assocData, $nonce, $key)
{
return
ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_encrypt($message,
$assocData, $nonce, $key);
}
}
if (!is_callable('\\Sodium\\crypto_auth')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth()
* @param string $message
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_auth($message, $key)
{
return ParagonIE_Sodium_Compat::crypto_auth($message, $key);
}
}
if (!is_callable('\\Sodium\\crypto_auth_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_auth_verify()
* @param string $mac
* @param string $message
* @param string $key
* @return bool
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_auth_verify($mac, $message, $key)
{
return ParagonIE_Sodium_Compat::crypto_auth_verify($mac, $message,
$key);
}
}
if (!is_callable('\\Sodium\\crypto_box')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box()
* @param string $message
* @param string $nonce
* @param string $kp
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box($message, $nonce, $kp)
{
return ParagonIE_Sodium_Compat::crypto_box($message, $nonce, $kp);
}
}
if (!is_callable('\\Sodium\\crypto_box_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_keypair()
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_keypair()
{
return ParagonIE_Sodium_Compat::crypto_box_keypair();
}
}
if
(!is_callable('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey()
* @param string $sk
* @param string $pk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_keypair_from_secretkey_and_publickey($sk, $pk)
{
return
ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey($sk,
$pk);
}
}
if (!is_callable('\\Sodium\\crypto_box_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_open()
* @param string $message
* @param string $nonce
* @param string $kp
* @return string|bool
*/
function crypto_box_open($message, $nonce, $kp)
{
try {
return ParagonIE_Sodium_Compat::crypto_box_open($message,
$nonce, $kp);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_box_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_publickey()
* @param string $keypair
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_publickey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_box_publickey($keypair);
}
}
if
(!is_callable('\\Sodium\\crypto_box_publickey_from_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_publickey_from_secretkey()
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_publickey_from_secretkey($sk)
{
return
ParagonIE_Sodium_Compat::crypto_box_publickey_from_secretkey($sk);
}
}
if (!is_callable('\\Sodium\\crypto_box_seal')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seal_open()
* @param string $message
* @param string $publicKey
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_seal($message, $publicKey)
{
return ParagonIE_Sodium_Compat::crypto_box_seal($message,
$publicKey);
}
}
if (!is_callable('\\Sodium\\crypto_box_seal_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_seal_open()
* @param string $message
* @param string $kp
* @return string|bool
*/
function crypto_box_seal_open($message, $kp)
{
try {
return ParagonIE_Sodium_Compat::crypto_box_seal_open($message,
$kp);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_box_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_box_secretkey()
* @param string $keypair
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_box_secretkey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_box_secretkey($keypair);
}
}
if (!is_callable('\\Sodium\\crypto_generichash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash()
* @param string $message
* @param string|null $key
* @param int $outLen
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_generichash($message, $key = null, $outLen = 32)
{
return ParagonIE_Sodium_Compat::crypto_generichash($message, $key,
$outLen);
}
}
if (!is_callable('\\Sodium\\crypto_generichash_final')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_final()
* @param string|null $ctx
* @param int $outputLength
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_generichash_final(&$ctx, $outputLength = 32)
{
return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx,
$outputLength);
}
}
if (!is_callable('\\Sodium\\crypto_generichash_init')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_init()
* @param string|null $key
* @param int $outLen
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_generichash_init($key = null, $outLen = 32)
{
return ParagonIE_Sodium_Compat::crypto_generichash_init($key,
$outLen);
}
}
if (!is_callable('\\Sodium\\crypto_generichash_update')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_generichash_update()
* @param string|null $ctx
* @param string $message
* @return void
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_generichash_update(&$ctx, $message = '')
{
ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, $message);
}
}
if (!is_callable('\\Sodium\\crypto_kx')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_kx()
* @param string $my_secret
* @param string $their_public
* @param string $client_public
* @param string $server_public
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_kx($my_secret, $their_public, $client_public,
$server_public)
{
return ParagonIE_Sodium_Compat::crypto_kx(
$my_secret,
$their_public,
$client_public,
$server_public
);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash()
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit)
{
return ParagonIE_Sodium_Compat::crypto_pwhash($outlen, $passwd,
$salt, $opslimit, $memlimit);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash_str')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str()
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_str($passwd, $opslimit, $memlimit)
{
return ParagonIE_Sodium_Compat::crypto_pwhash_str($passwd,
$opslimit, $memlimit);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash_str_verify')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str_verify()
* @param string $passwd
* @param string $hash
* @return bool
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_str_verify($passwd, $hash)
{
return ParagonIE_Sodium_Compat::crypto_pwhash_str_verify($passwd,
$hash);
}
}
if (!is_callable('\\Sodium\\crypto_pwhash_scryptsalsa208sha256'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256()
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt,
$opslimit, $memlimit)
{
return
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256($outlen,
$passwd, $salt, $opslimit, $memlimit);
}
}
if
(!is_callable('\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str()
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit,
$memlimit)
{
return
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str($passwd,
$opslimit, $memlimit);
}
}
if
(!is_callable('\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify'))
{
/**
* @see
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str_verify()
* @param string $passwd
* @param string $hash
* @return bool
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash)
{
return
ParagonIE_Sodium_Compat::crypto_pwhash_scryptsalsa208sha256_str_verify($passwd,
$hash);
}
}
if (!is_callable('\\Sodium\\crypto_scalarmult')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult()
* @param string $n
* @param string $p
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_scalarmult($n, $p)
{
return ParagonIE_Sodium_Compat::crypto_scalarmult($n, $p);
}
}
if (!is_callable('\\Sodium\\crypto_scalarmult_base')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult_base()
* @param string $n
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_scalarmult_base($n)
{
return ParagonIE_Sodium_Compat::crypto_scalarmult_base($n);
}
}
if (!is_callable('\\Sodium\\crypto_secretbox')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_secretbox($message, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_secretbox($message, $nonce,
$key);
}
}
if (!is_callable('\\Sodium\\crypto_secretbox_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_secretbox_open()
* @param string $message
* @param string $nonce
* @param string $key
* @return string|bool
*/
function crypto_secretbox_open($message, $nonce, $key)
{
try {
return ParagonIE_Sodium_Compat::crypto_secretbox_open($message,
$nonce, $key);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_shorthash')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_shorthash()
* @param string $message
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_shorthash($message, $key = '')
{
return ParagonIE_Sodium_Compat::crypto_shorthash($message, $key);
}
}
if (!is_callable('\\Sodium\\crypto_sign')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign()
* @param string $message
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign($message, $sk)
{
return ParagonIE_Sodium_Compat::crypto_sign($message, $sk);
}
}
if (!is_callable('\\Sodium\\crypto_sign_detached')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_detached()
* @param string $message
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_detached($message, $sk)
{
return ParagonIE_Sodium_Compat::crypto_sign_detached($message,
$sk);
}
}
if (!is_callable('\\Sodium\\crypto_sign_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_keypair()
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_keypair()
{
return ParagonIE_Sodium_Compat::crypto_sign_keypair();
}
}
if (!is_callable('\\Sodium\\crypto_sign_open')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_open()
* @param string $signedMessage
* @param string $pk
* @return string|bool
*/
function crypto_sign_open($signedMessage, $pk)
{
try {
return
ParagonIE_Sodium_Compat::crypto_sign_open($signedMessage, $pk);
} catch (\TypeError $ex) {
return false;
} catch (\SodiumException $ex) {
return false;
}
}
}
if (!is_callable('\\Sodium\\crypto_sign_publickey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_publickey()
* @param string $keypair
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_publickey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_sign_publickey($keypair);
}
}
if
(!is_callable('\\Sodium\\crypto_sign_publickey_from_secretkey'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey()
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_publickey_from_secretkey($sk)
{
return
ParagonIE_Sodium_Compat::crypto_sign_publickey_from_secretkey($sk);
}
}
if (!is_callable('\\Sodium\\crypto_sign_secretkey')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_secretkey()
* @param string $keypair
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_secretkey($keypair)
{
return ParagonIE_Sodium_Compat::crypto_sign_secretkey($keypair);
}
}
if (!is_callable('\\Sodium\\crypto_sign_seed_keypair')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_seed_keypair()
* @param string $seed
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_seed_keypair($seed)
{
return ParagonIE_Sodium_Compat::crypto_sign_seed_keypair($seed);
}
}
if (!is_callable('\\Sodium\\crypto_sign_verify_detached')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_verify_detached()
* @param string $signature
* @param string $message
* @param string $pk
* @return bool
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_verify_detached($signature, $message, $pk)
{
return
ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $message,
$pk);
}
}
if
(!is_callable('\\Sodium\\crypto_sign_ed25519_pk_to_curve25519'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519()
* @param string $pk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_ed25519_pk_to_curve25519($pk)
{
return
ParagonIE_Sodium_Compat::crypto_sign_ed25519_pk_to_curve25519($pk);
}
}
if
(!is_callable('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519'))
{
/**
* @see ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519()
* @param string $sk
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_sign_ed25519_sk_to_curve25519($sk)
{
return
ParagonIE_Sodium_Compat::crypto_sign_ed25519_sk_to_curve25519($sk);
}
}
if (!is_callable('\\Sodium\\crypto_stream')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream()
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_stream($len, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_stream($len, $nonce, $key);
}
}
if (!is_callable('\\Sodium\\crypto_stream_xor')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xor()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function crypto_stream_xor($message, $nonce, $key)
{
return ParagonIE_Sodium_Compat::crypto_stream_xor($message, $nonce,
$key);
}
}
if (!is_callable('\\Sodium\\hex2bin')) {
/**
* @see ParagonIE_Sodium_Compat::hex2bin()
* @param string $string
* @return string
* @throws \SodiumException
* @throws \TypeError
*/
function hex2bin($string)
{
return ParagonIE_Sodium_Compat::hex2bin($string);
}
}
if (!is_callable('\\Sodium\\memcmp')) {
/**
* @see ParagonIE_Sodium_Compat::memcmp()
* @param string $a
* @param string $b
* @return int
* @throws \SodiumException
* @throws \TypeError
*/
function memcmp($a, $b)
{
return ParagonIE_Sodium_Compat::memcmp($a, $b);
}
}
if (!is_callable('\\Sodium\\memzero')) {
/**
* @see ParagonIE_Sodium_Compat::memzero()
* @param string $str
* @return void
* @throws \SodiumException
* @throws \TypeError
*/
function memzero(&$str)
{
ParagonIE_Sodium_Compat::memzero($str);
}
}
if (!is_callable('\\Sodium\\randombytes_buf')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_buf()
* @param int $amount
* @return string
* @throws \TypeError
*/
function randombytes_buf($amount)
{
return ParagonIE_Sodium_Compat::randombytes_buf($amount);
}
}
if (!is_callable('\\Sodium\\randombytes_uniform')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_uniform()
* @param int $upperLimit
* @return int
* @throws \SodiumException
* @throws \Error
*/
function randombytes_uniform($upperLimit)
{
return ParagonIE_Sodium_Compat::randombytes_uniform($upperLimit);
}
}
if (!is_callable('\\Sodium\\randombytes_random16')) {
/**
* @see ParagonIE_Sodium_Compat::randombytes_random16()
* @return int
*/
function randombytes_random16()
{
return ParagonIE_Sodium_Compat::randombytes_random16();
}
}
if (!defined('\\Sodium\\CRYPTO_AUTH_BYTES')) {
require_once dirname(__FILE__) . '/constants.php';
}
/*
* ISC License
*
* Copyright (c) 2016-2019
* Paragon Initiative Enterprises <security at paragonie dot com>
*
* Copyright (c) 2013-2019
* Frank Denis <j at pureftpd dot org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/<?php
namespace ParagonIE\Sodium;
class Compat extends \ParagonIE_Sodium_Compat
{
}
<?php
namespace ParagonIE\Sodium\Core;
class BLAKE2b extends \ParagonIE_Sodium_Core_BLAKE2b
{
}
<?php
namespace ParagonIE\Sodium\Core\ChaCha20;
class Ctx extends \ParagonIE_Sodium_Core_ChaCha20_Ctx
{
}
<?php
namespace ParagonIE\Sodium\Core\ChaCha20;
class IetfCtx extends \ParagonIE_Sodium_Core_ChaCha20_IetfCtx
{
}
<?php
namespace ParagonIE\Sodium\Core;
class ChaCha20 extends \ParagonIE_Sodium_Core_ChaCha20
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519;
class Fe extends \ParagonIE_Sodium_Core_Curve25519_Fe
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class Cached extends \ParagonIE_Sodium_Core_Curve25519_Ge_Cached
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class P1p1 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class P2 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P2
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class P3 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P3
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class Precomp extends \ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
{
}
<?php
namespace ParagonIE\Sodium\Core\Curve25519;
class H extends \ParagonIE_Sodium_Core_Curve25519_H
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Curve25519 extends \ParagonIE_Sodium_Core_Curve25519
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Ed25519 extends \ParagonIE_Sodium_Core_Ed25519
{
}
<?php
namespace ParagonIE\Sodium\Core;
class HChaCha20 extends \ParagonIE_Sodium_Core_HChaCha20
{
}
<?php
namespace ParagonIE\Sodium\Core;
class HSalsa20 extends \ParagonIE_Sodium_Core_HSalsa20
{
}
<?php
namespace ParagonIE\Sodium\Core\Poly1305;
class State extends \ParagonIE_Sodium_Core_Poly1305_State
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Poly1305 extends \ParagonIE_Sodium_Core_Poly1305
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Salsa20 extends \ParagonIE_Sodium_Core_Salsa20
{
}
<?php
namespace ParagonIE\Sodium\Core;
class SipHash extends \ParagonIE_Sodium_Core_SipHash
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Util extends \ParagonIE_Sodium_Core_Util
{
}
<?php
namespace ParagonIE\Sodium\Core;
class X25519 extends \ParagonIE_Sodium_Core_X25519
{
}
<?php
namespace ParagonIE\Sodium\Core;
class XChaCha20 extends \ParagonIE_Sodium_Core_XChaCha20
{
}
<?php
namespace ParagonIE\Sodium\Core;
class Xsalsa20 extends \ParagonIE_Sodium_Core_XSalsa20
{
}
<?php
namespace ParagonIE\Sodium;
class Crypto extends \ParagonIE_Sodium_Crypto
{
}
<?php
namespace ParagonIE\Sodium;
class File extends \ParagonIE_Sodium_File
{
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
backupGlobals="true"
backupStaticAttributes="false"
bootstrap="autoload-phpunit.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
>
<testsuites>
<testsuite name="Unit Tests">
<directory
suffix="Test.php">./tests/unit</directory>
</testsuite>
<testsuite name="Libsodium Compatibility Tests">
<directory
suffix="Test.php">./tests/compat</directory>
</testsuite>
</testsuites>
<filter>
<whitelist
processUncoveredFilesFromWhitelist="true">
<directory
suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit><?xml version="1.0"?>
<psalm
useDocblockTypes="true"
totallyTyped="true"
>
<projectFiles>
<directory name="src" />
</projectFiles>
<issueHandlers>
<InvalidFunctionCall errorLevel="suppress" />
<!--
Previous issue type is suppressed because we have to use a
string
as a function name for PHP 5.2 compatibility. When testing, be
sure
to change this to "info".
-->
<UndefinedFunction errorLevel="info" />
<!--
Inconsistently erroneous.
-->
<DuplicateClass errorLevel="info" />
<!--
Psalm isn't correctly identifying the guard conditions
that return
early if a class already exists.
-->
<RedundantConditionGivenDocblockType
errorLevel="suppress" />
<TooFewArguments errorLevel="info" />
<DocblockTypeContradiction errorLevel="suppress" />
<RedundantCondition errorLevel="info" />
<!--
Redundancy is good for PHP <7
-->
<TypeDoesNotContainType errorLevel="info" />
<!--
This mostly fails on `PHP_INT_SIZE === 4`
-->
<InternalMethod errorLevel="suppress" />
<!--
We mark methods as internal.
-->
<PossiblyNullArgument errorLevel="suppress" />
<!--
Not interesting
-->
<RedundantCast errorLevel="info" />
</issueHandlers>
</psalm>
<?xml version="1.0"?>
<psalm
useDocblockTypes="true"
totallyTyped="true"
>
<projectFiles>
<directory name="src" />
</projectFiles>
<issueHandlers>
<InvalidFunctionCall errorLevel="suppress" />
<!--
Previous issue type is suppressed because we have to use a
string
as a function name for PHP 5.2 compatibility. When testing, be
sure
to change this to "info".
-->
<UndefinedFunction errorLevel="info" />
<!--
Inconsistently erroneous.
-->
<DuplicateClass errorLevel="info" />
<!--
Psalm isn't correctly identifying the guard conditions
that return
early if a class already exists.
-->
<RedundantConditionGivenDocblockType
errorLevel="suppress" />
<TooFewArguments errorLevel="info" />
<DocblockTypeContradiction errorLevel="info" />
<RedundantCondition errorLevel="info" />
<!--
Redundancy is good for PHP <7
-->
<TypeDoesNotContainType errorLevel="info" />
<!--
This mostly fails on `PHP_INT_SIZE === 4`
-->
</issueHandlers>
</psalm>
# Sodium Compat
[](https://travis-ci.org/paragonie/sodium_compat)
[](https://ci.appveyor.com/project/paragonie-scott/sodium-compat)
[](https://packagist.org/packages/paragonie/sodium_compat)
[](https://packagist.org/packages/paragonie/sodium_compat)
[](https://packagist.org/packages/paragonie/sodium_compat)
[](https://packagist.org/packages/paragonie/sodium_compat)
Sodium Compat is a pure PHP polyfill for the Sodium cryptography library
(libsodium), a core extension in PHP 7.2.0+ and otherwise [available in
PECL](https://pecl.php.net/package/libsodium).
This library tentativeley supports PHP 5.2.4 - 8.x (latest), but officially
only supports [non-EOL'd versions of
PHP](https://secure.php.net/supported-versions.php).
If you have the PHP extension installed, Sodium Compat will
opportunistically
and transparently use the PHP extension instead of our implementation.
## IMPORTANT!
This cryptography library has not been formally audited by an independent
third
party that specializes in cryptography or cryptanalysis.
If you require such an audit before you can use sodium_compat in your
projects
and have the funds for such an audit, please open an issue or contact
`security at paragonie dot com` so we can help get the ball rolling.
However, sodium_compat has been adopted by high profile open source
projects,
such as
[Joomla!](https://github.com/joomla/joomla-cms/blob/459d74686d2a638ec51149d7c44ddab8075852be/composer.json#L40)
and
[Magento](https://github.com/magento/magento2/blob/8fd89cfdf52c561ac0ca7bc20fd38ef688e201b0/composer.json#L44).
Furthermore, sodium_compat was developed by Paragon Initiative Enterprises,
a
company that *specializes* in secure PHP development and PHP cryptography,
and
has been informally reviewed by many other security experts who also
specialize
in PHP.
If you'd like to learn more about the defensive security measures
we've taken
to prevent sodium_compat from being a source of vulnerability in your
systems,
please read [*Cryptographically Secure PHP
Development*](https://paragonie.com/blog/2017/02/cryptographically-secure-php-development).
# Installing Sodium Compat
If you're using Composer:
```bash
composer require paragonie/sodium_compat
```
### Install From Source
If you're not using Composer, download a [release
tarball](https://github.com/paragonie/sodium_compat/releases)
(which should be signed with [our GnuPG public
key](https://paragonie.com/static/gpg-public-key.txt)), extract
its contents, then include our `autoload.php` script in your project.
```php
<?php
require_once "/path/to/sodium_compat/autoload.php";
```
### PHP Archives (Phar) Releases
Since version 1.3.0, [sodium_compat
releases](https://github.com/paragonie/sodium_compat/releases) include a
PHP Archive (.phar file) and associated GPG signature. First, download both
files and verify them with our
GPG public key, like so:
```bash
# Getting our public key from the keyserver:
gpg --fingerprint 7F52D5C61D1255C731362E826B97A1C2826404DA
if [ $? -ne 0 ]; then
echo -e "\033[33mDownloading PGP Public Key...\033[0m"
gpg --keyserver pgp.mit.edu --recv-keys
7F52D5C61D1255C731362E826B97A1C2826404DA
# Security <security@paragonie.com>
gpg --fingerprint 7F52D5C61D1255C731362E826B97A1C2826404DA
if [ $? -ne 0 ]; then
echo -e "\033[31mCould not download PGP public key for
verification\033[0m"
exit 1
fi
fi
# Verifying the PHP Archive
gpg --verify sodium-compat.phar.sig sodium-compat.phar
```
Now, simply include this .phar file in your application.
```php
<?php
require_once "/path/to/sodium-compat.phar";
```
# Support
[Commercial support for
libsodium](https://download.libsodium.org/doc/commercial_support/) is
available
from multiple vendors. If you need help using sodium_compat in one of your
projects, [contact Paragon Initiative
Enterprises](https://paragonie.com/contact).
Non-commercial report will be facilitated through [Github
issues](https://github.com/paragonie/sodium_compat/issues).
We offer no guarantees of our availability to resolve questions about
integrating sodium_compat into third-party
software for free, but will strive to fix any bugs (security-related or
otherwise) in our library.
## Support Contracts
If your company uses this library in their products or services, you may be
interested in [purchasing a support contract from Paragon Initiative
Enterprises](https://paragonie.com/enterprise).
# Using Sodium Compat
## True Polyfill
If you're using PHP 5.3.0 or newer and do not have the PECL extension
installed,
you can just use the [standard ext/sodium API features
as-is](https://paragonie.com/book/pecl-libsodium)
and the polyfill will work its magic.
```php
<?php
require_once "/path/to/sodium_compat/autoload.php";
$alice_kp = \Sodium\crypto_sign_keypair();
$alice_sk = \Sodium\crypto_sign_secretkey($alice_kp);
$alice_pk = \Sodium\crypto_sign_publickey($alice_kp);
$message = 'This is a test message.';
$signature = \Sodium\crypto_sign_detached($message, $alice_sk);
if (\Sodium\crypto_sign_verify_detached($signature, $message, $alice_pk)) {
echo 'OK', PHP_EOL;
} else {
throw new Exception('Invalid signature');
}
```
The polyfill does not expose this API on PHP < 5.3, or if you have the
PHP
extension installed already.
## General-Use Polyfill
If your users are on PHP < 5.3, or you want to write code that will work
whether or not the PECL extension is available, you'll want to use the
**`ParagonIE_Sodium_Compat`** class for most of your libsodium needs.
The above example, written for general use:
```php
<?php
require_once "/path/to/sodium_compat/autoload.php";
$alice_kp = ParagonIE_Sodium_Compat::crypto_sign_keypair();
$alice_sk = ParagonIE_Sodium_Compat::crypto_sign_secretkey($alice_kp);
$alice_pk = ParagonIE_Sodium_Compat::crypto_sign_publickey($alice_kp);
$message = 'This is a test message.';
$signature = ParagonIE_Sodium_Compat::crypto_sign_detached($message,
$alice_sk);
if (ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature,
$message, $alice_pk)) {
echo 'OK', PHP_EOL;
} else {
throw new Exception('Invalid signature');
}
```
Generally: If you replace `\Sodium\ ` with `ParagonIE_Sodium_Compat::`, any
code already written for the libsodium PHP extension should work with our
polyfill without additional code changes.
Since this doesn't require a namespace, this API *is* exposed on PHP
5.2.
Since version 0.7.0, we have our own namespaced API (`ParagonIE\Sodium\*`)
to allow brevity
in software that uses PHP 5.3+. This is useful if you want to use our file
cryptography
features without writing `ParagonIE_Sodium_File` every time. This is not
exposed on PHP < 5.3,
so if your project supports PHP < 5.3, use the underscore method
instead.
To learn how to use Libsodium, read [*Using Libsodium in PHP
Projects*](https://paragonie.com/book/pecl-libsodium).
## PHP 7.2 Polyfill
As per the [second vote on the libsodium
RFC](https://wiki.php.net/rfc/libsodium#proposed_voting_choices),
PHP 7.2 uses `sodium_*` instead of `\Sodium\*`.
```php
<?php
require_once "/path/to/sodium_compat/autoload.php";
$alice_kp = sodium_crypto_sign_keypair();
$alice_sk = sodium_crypto_sign_secretkey($alice_kp);
$alice_pk = sodium_crypto_sign_publickey($alice_kp);
$message = 'This is a test message.';
$signature = sodium_crypto_sign_detached($message, $alice_sk);
if (sodium_crypto_sign_verify_detached($signature, $message, $alice_pk)) {
echo 'OK', PHP_EOL;
} else {
throw new Exception('Invalid signature');
}
```
## Help, Sodium_Compat is Slow! How can I make it fast?
There are three ways to make it fast:
1. Use PHP 7.2.
2. [Install the libsodium PHP extension from
PECL](https://paragonie.com/book/pecl-libsodium/read/00-intro.md#installing-libsodium).
3. Only if the previous two options are not available for you:
1. Verify that [the processor you're using actually implements
constant-time multiplication](https://bearssl.org/ctmul.html).
Sodium_compat does, but it must trade some speed in order to attain
cross-platform security.
2. Only if you are 100% certain that your processor is safe, you can set
`ParagonIE_Sodium_Compat::$fastMult = true;`
without harming the security of your cryptography keys. If your
processor *isn't* safe, then decide whether you
want speed or security because you can't have both.
### How can I tell if sodium_compat will be slow, at runtime?
Since version 1.8, you can use the `polyfill_is_fast()` static method to
determine if sodium_compat will be slow at runtime.
```php
<?php
if (ParagonIE_Sodium_Compat::polyfill_is_fast()) {
// Use libsodium now
$process->execute();
} else {
// Defer to a cron job or other sort of asynchronous process
$process->enqueue();
}
```
### Help, my PHP only has 32-Bit Integers! It's super slow!
Some features of sodium_compat are ***incredibly slow* with PHP 5 on
Windows**
(in particular: public-key cryptography (encryption and signatures) is
affected), and there is nothing we can do about that, due to platform
restrictions on integers.
For acceptable performance, we highly recommend Windows users to version
1.0.6
of the libsodium extension from PECL or, alternatively, simply upgrade to
PHP 7
and the slowdown will be greatly reduced.
This is also true of non-Windows 32-bit operating systems, or if somehow
PHP
was compiled where `PHP_INT_SIZE` equals `4` instead of `8` (i.e. Linux on
i386).
## Documentation
First, you'll want to read the [Libsodium Quick
Reference](https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use).
It aims to answer, "Which function should I use for [common
problem]?".
If you don't find the answers in the Quick Reference page, check out
[*Using Libsodium in PHP
Projects*](https://paragonie.com/book/pecl-libsodium).
Finally, the [official libsodium
documentation](https://download.libsodium.org/doc/)
(which was written for the C library, not the PHP library) also contains a
lot of
insightful technical information you may find helpful.
## API Coverage
**Recommended reading:** [Libsodium Quick
Reference](https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use)
* Mainline NaCl Features
* `crypto_auth()`
* `crypto_auth_verify()`
* `crypto_box()`
* `crypto_box_open()`
* `crypto_scalarmult()`
* `crypto_secretbox()`
* `crypto_secretbox_open()`
* `crypto_sign()`
* `crypto_sign_open()`
* PECL Libsodium Features
* `crypto_aead_aes256gcm_encrypt()`
* `crypto_aead_aes256gcm_decrypt()`
* `crypto_aead_chacha20poly1305_encrypt()`
* `crypto_aead_chacha20poly1305_decrypt()`
* `crypto_aead_chacha20poly1305_ietf_encrypt()`
* `crypto_aead_chacha20poly1305_ietf_decrypt()`
* `crypto_aead_xchacha20poly1305_ietf_encrypt()`
* `crypto_aead_xchacha20poly1305_ietf_decrypt()`
* `crypto_box_xchacha20poly1305()`
* `crypto_box_xchacha20poly1305_open()`
* `crypto_box_seal()`
* `crypto_box_seal_open()`
* `crypto_generichash()`
* `crypto_generichash_init()`
* `crypto_generichash_update()`
* `crypto_generichash_final()`
* `crypto_kx()`
* `crypto_secretbox_xchacha20poly1305()`
* `crypto_secretbox_xchacha20poly1305_open()`
* `crypto_shorthash()`
* `crypto_sign_detached()`
* `crypto_sign_ed25519_pk_to_curve25519()`
* `crypto_sign_ed25519_sk_to_curve25519()`
* `crypto_sign_verify_detached()`
* For advanced users only:
* `crypto_stream()`
* `crypto_stream_xor()`
* Other utilities (e.g. `crypto_*_keypair()`)
* `add()`
* `base642bin()`
* `bin2base64()`
* `bin2hex()`
* `hex2bin()`
* `crypto_kdf_derive_from_key()`
* `crypto_kx_client_session_keys()`
* `crypto_kx_server_session_keys()`
* `crypto_secretstream_xchacha20poly1305_init_push()`
* `crypto_secretstream_xchacha20poly1305_push()`
* `crypto_secretstream_xchacha20poly1305_init_pull()`
* `crypto_secretstream_xchacha20poly1305_pull()`
* `crypto_secretstream_xchacha20poly1305_rekey()`
* `pad()`
* `unpad()`
### Cryptography Primitives Provided
* **X25519** - Elliptic Curve Diffie Hellman over Curve25519
* **Ed25519** - Edwards curve Digital Signature Algorithm over Curve25519
* **Xsalsa20** - Extended-nonce Salsa20 stream cipher
* **ChaCha20** - Stream cipher
* **Xchacha20** - Extended-nonce ChaCha20 stream cipher
* **Poly1305** - Polynomial Evaluation Message Authentication Code modulo
2^130 - 5
* **BLAKE2b** - Cryptographic Hash Function
* **SipHash-2-4** - Fast hash, but not collision-resistant; ideal for hash
tables.
### Features Excluded from this Polyfill
* `\Sodium\memzero()` - Although we expose this API endpoint, we can't
reliably
zero buffers from PHP.
If you have the PHP extension installed, sodium_compat
will use the native implementation to zero out the string provided.
Otherwise
it will throw a `SodiumException`.
* `\Sodium\crypto_pwhash()` - It's not feasible to polyfill scrypt or
Argon2
into PHP and get reasonable performance. Users would feel motivated to
select
parameters that downgrade security to avoid denial of service (DoS)
attacks.
The only winning move is not to play.
If ext/sodium or ext/libsodium is installed, these API methods will
fallthrough
to the extension. Otherwise, our polyfill library will throw a
`SodiumException`.
To detect support for Argon2i at runtime, use
`ParagonIE_Sodium_Compat::crypto_pwhash_is_available()`, which returns a
boolean value (`TRUE` or `FALSE`).
### PHPCompatibility Ruleset
For sodium_compat users and that utilize
[`PHPCompatibility`](https://github.com/PHPCompatibility/PHPCompatibility)
in their CI process, there is now a custom ruleset available which can be
used
to prevent false positives being thrown by `PHPCompatibility` for the
native
PHP functionality being polyfilled by this repo.
You can find the repo for the `PHPCompatibilityParagonieSodiumCompat`
ruleset
here [on
Github](https://github.com/PHPCompatibility/PHPCompatibilityParagonie)
and [on
Packagist](https://packagist.org/packages/phpcompatibility/phpcompatibility-paragonie).
<?php
/**
* Libsodium compatibility layer
*
* This is the only class you should be interfacing with, as a user of
* sodium_compat.
*
* If the PHP extension for libsodium is installed, it will always use that
* instead of our implementations. You get better performance and stronger
* guarantees against side-channels that way.
*
* However, if your users don't have the PHP extension installed, we
offer a
* compatible interface here. It will give you the correct results as if
the
* PHP extension was installed. It won't be as fast, of course.
*
* CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION *
CAUTION *
*
*
* Until audited, this is probably not safe to use! DANGER WILL
ROBINSON *
*
*
* CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION *
CAUTION *
*/
if (class_exists('ParagonIE_Sodium_Compat', false)) {
return;
}
class ParagonIE_Sodium_Compat
{
/**
* This parameter prevents the use of the PECL extension.
* It should only be used for unit testing.
*
* @var bool
*/
public static $disableFallbackForUnitTests = false;
/**
* Use fast multiplication rather than our constant-time multiplication
* implementation. Can be enabled at runtime. Only enable this if you
* are absolutely certain that there is no timing leak on your
platform.
*
* @var bool
*/
public static $fastMult = false;
const LIBRARY_MAJOR_VERSION = 9;
const LIBRARY_MINOR_VERSION = 1;
const LIBRARY_VERSION_MAJOR = 9;
const LIBRARY_VERSION_MINOR = 1;
const VERSION_STRING = 'polyfill-1.0.8';
// From libsodium
const BASE64_VARIANT_ORIGINAL = 1;
const BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
const BASE64_VARIANT_URLSAFE = 5;
const BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
const CRYPTO_AEAD_AES256GCM_KEYBYTES = 32;
const CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
const CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12;
const CRYPTO_AEAD_AES256GCM_ABYTES = 16;
const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32;
const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0;
const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8;
const CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12;
const CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16;
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32;
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0;
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24;
const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16;
const CRYPTO_AUTH_BYTES = 32;
const CRYPTO_AUTH_KEYBYTES = 32;
const CRYPTO_BOX_SEALBYTES = 16;
const CRYPTO_BOX_SECRETKEYBYTES = 32;
const CRYPTO_BOX_PUBLICKEYBYTES = 32;
const CRYPTO_BOX_KEYPAIRBYTES = 64;
const CRYPTO_BOX_MACBYTES = 16;
const CRYPTO_BOX_NONCEBYTES = 24;
const CRYPTO_BOX_SEEDBYTES = 32;
const CRYPTO_KDF_BYTES_MIN = 16;
const CRYPTO_KDF_BYTES_MAX = 64;
const CRYPTO_KDF_CONTEXTBYTES = 8;
const CRYPTO_KDF_KEYBYTES = 32;
const CRYPTO_KX_BYTES = 32;
const CRYPTO_KX_PRIMITIVE = 'x25519blake2b';
const CRYPTO_KX_SEEDBYTES = 32;
const CRYPTO_KX_KEYPAIRBYTES = 64;
const CRYPTO_KX_PUBLICKEYBYTES = 32;
const CRYPTO_KX_SECRETKEYBYTES = 32;
const CRYPTO_KX_SESSIONKEYBYTES = 32;
const CRYPTO_GENERICHASH_BYTES = 32;
const CRYPTO_GENERICHASH_BYTES_MIN = 16;
const CRYPTO_GENERICHASH_BYTES_MAX = 64;
const CRYPTO_GENERICHASH_KEYBYTES = 32;
const CRYPTO_GENERICHASH_KEYBYTES_MIN = 16;
const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
const CRYPTO_PWHASH_SALTBYTES = 16;
const CRYPTO_PWHASH_STRPREFIX = '$argon2id$';
const CRYPTO_PWHASH_ALG_ARGON2I13 = 1;
const CRYPTO_PWHASH_ALG_ARGON2ID13 = 2;
const CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432;
const CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4;
const CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728;
const CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6;
const CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912;
const CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX = '$7$';
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE = 534288;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE =
16777216;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE = 33554432;
const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE =
1073741824;
const CRYPTO_SCALARMULT_BYTES = 32;
const CRYPTO_SCALARMULT_SCALARBYTES = 32;
const CRYPTO_SHORTHASH_BYTES = 8;
const CRYPTO_SHORTHASH_KEYBYTES = 16;
const CRYPTO_SECRETBOX_KEYBYTES = 32;
const CRYPTO_SECRETBOX_MACBYTES = 16;
const CRYPTO_SECRETBOX_NONCEBYTES = 24;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3;
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX =
0x3fffffff80;
const CRYPTO_SIGN_BYTES = 64;
const CRYPTO_SIGN_SEEDBYTES = 32;
const CRYPTO_SIGN_PUBLICKEYBYTES = 32;
const CRYPTO_SIGN_SECRETKEYBYTES = 64;
const CRYPTO_SIGN_KEYPAIRBYTES = 96;
const CRYPTO_STREAM_KEYBYTES = 32;
const CRYPTO_STREAM_NONCEBYTES = 24;
/**
* Add two numbers (little-endian unsigned), storing the value in the
first
* parameter.
*
* This mutates $val.
*
* @param string $val
* @param string $addv
* @return void
* @throws SodiumException
*/
public static function add(&$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);
$c = 0;
for ($i = 0; $i < $val_len; $i++) {
$c += ($A[$i] + $B[$i]);
$A[$i] = ($c & 0xff);
$c >>= 8;
}
$val = ParagonIE_Sodium_Core_Util::intArrayToString($A);
}
/**
* @param string $encoded
* @param int $variant
* @param string $ignore
* @return string
* @throws SodiumException
*/
public static function base642bin($encoded, $variant, $ignore =
'')
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($encoded,
'string', 1);
/** @var string $encoded */
$encoded = (string) $encoded;
if (ParagonIE_Sodium_Core_Util::strlen($encoded) === 0) {
return '';
}
// Just strip before decoding
if (!empty($ignore)) {
$encoded = str_replace($ignore, '', $encoded);
}
try {
switch ($variant) {
case self::BASE64_VARIANT_ORIGINAL:
return
ParagonIE_Sodium_Core_Base64_Original::decode($encoded, true);
case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
return
ParagonIE_Sodium_Core_Base64_Original::decode($encoded, false);
case self::BASE64_VARIANT_URLSAFE:
return
ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, true);
case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
return
ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, false);
default:
throw new SodiumException('invalid base64 variant
identifier');
}
} catch (Exception $ex) {
if ($ex instanceof SodiumException) {
throw $ex;
}
throw new SodiumException('invalid base64 string');
}
}
/**
* @param string $decoded
* @param int $variant
* @return string
* @throws SodiumException
*/
public static function bin2base64($decoded, $variant)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($decoded,
'string', 1);
/** @var string $decoded */
$decoded = (string) $decoded;
if (ParagonIE_Sodium_Core_Util::strlen($decoded) === 0) {
return '';
}
switch ($variant) {
case self::BASE64_VARIANT_ORIGINAL:
return
ParagonIE_Sodium_Core_Base64_Original::encode($decoded);
case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
return
ParagonIE_Sodium_Core_Base64_Original::encodeUnpadded($decoded);
case self::BASE64_VARIANT_URLSAFE:
return
ParagonIE_Sodium_Core_Base64_UrlSafe::encode($decoded);
case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
return
ParagonIE_Sodium_Core_Base64_UrlSafe::encodeUnpadded($decoded);
default:
throw new SodiumException('invalid base64 variant
identifier');
}
}
/**
* Cache-timing-safe implementation of bin2hex().
*
* @param string $string A string (probably raw binary)
* @return string A hexadecimal-encoded string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function bin2hex($string)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($string,
'string', 1);
if (self::useNewSodiumAPI()) {
return (string) sodium_bin2hex($string);
}
if (self::use_fallback('bin2hex')) {
return (string) call_user_func('\\Sodium\\bin2hex',
$string);
}
return ParagonIE_Sodium_Core_Util::bin2hex($string);
}
/**
* Compare two strings, in constant-time.
* Compared to memcmp(), compare() is more useful for sorting.
*
* @param string $left The left operand; must be a string
* @param string $right The right operand; must be a string
* @return int If < 0 if the left operand is less than the
right
* If = 0 if both strings are equal
* If > 0 if the right operand is less than the
left
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function compare($left, $right)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($left,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($right,
'string', 2);
if (self::useNewSodiumAPI()) {
return (int) sodium_compare($left, $right);
}
if (self::use_fallback('compare')) {
return (int) call_user_func('\\Sodium\\compare',
$left, $right);
}
return ParagonIE_Sodium_Core_Util::compare($left, $right);
}
/**
* Is AES-256-GCM even available to use?
*
* @return bool
* @psalm-suppress UndefinedFunction
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_aes256gcm_is_available()
{
if (self::useNewSodiumAPI()) {
return sodium_crypto_aead_aes256gcm_is_available();
}
if
(self::use_fallback('crypto_aead_aes256gcm_is_available')) {
return
call_user_func('\\Sodium\\crypto_aead_aes256gcm_is_available');
}
if (PHP_VERSION_ID < 70100) {
// OpenSSL doesn't support AEAD before 7.1.0
return false;
}
if (!is_callable('openssl_encrypt') ||
!is_callable('openssl_decrypt')) {
// OpenSSL isn't installed
return false;
}
return (bool) in_array('aes-256-gcm',
openssl_get_cipher_methods());
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* AES-256-GCM
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $ciphertext Encrypted message (with Poly1305 MAC
appended)
* @param string $assocData Authenticated Associated Data
(unencrypted)
* @param string $nonce Number to be used only Once; must be 8
bytes
* @param string $key Encryption key
*
* @return string|bool The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_aes256gcm_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
if (!self::crypto_aead_aes256gcm_is_available()) {
throw new SodiumException('AES-256-GCM is not
available');
}
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) {
throw new SodiumException('Nonce must be
CRYPTO_AEAD_AES256GCM_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AEAD_AES256GCM_KEYBYTES) {
throw new SodiumException('Key must be
CRYPTO_AEAD_AES256GCM_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) <
self::CRYPTO_AEAD_AES256GCM_ABYTES) {
throw new SodiumException('Message must be at least
CRYPTO_AEAD_AES256GCM_ABYTES long');
}
if (!is_callable('openssl_decrypt')) {
throw new SodiumException('The OpenSSL extension is not
installed, or openssl_decrypt() is not available');
}
/** @var string $ctext */
$ctext = ParagonIE_Sodium_Core_Util::substr($ciphertext, 0,
-self::CRYPTO_AEAD_AES256GCM_ABYTES);
/** @var string $authTag */
$authTag = ParagonIE_Sodium_Core_Util::substr($ciphertext,
-self::CRYPTO_AEAD_AES256GCM_ABYTES, 16);
return openssl_decrypt(
$ctext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$nonce,
$authTag,
$assocData
);
}
/**
* Authenticated Encryption with Associated Data: Encryption
*
* Algorithm:
* AES-256-GCM
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8
bytes
* @param string $key Encryption key
*
* @return string Ciphertext with a 16-byte GCM message
* authentication code appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_aes256gcm_encrypt(
$plaintext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
if (!self::crypto_aead_aes256gcm_is_available()) {
throw new SodiumException('AES-256-GCM is not
available');
}
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) {
throw new SodiumException('Nonce must be
CRYPTO_AEAD_AES256GCM_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AEAD_AES256GCM_KEYBYTES) {
throw new SodiumException('Key must be
CRYPTO_AEAD_AES256GCM_KEYBYTES long');
}
if (!is_callable('openssl_encrypt')) {
throw new SodiumException('The OpenSSL extension is not
installed, or openssl_encrypt() is not available');
}
$authTag = '';
$ciphertext = openssl_encrypt(
$plaintext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$nonce,
$authTag,
$assocData
);
return $ciphertext . $authTag;
}
/**
* Return a secure random key for use with the AES-256-GCM
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_aes256gcm_keygen()
{
return random_bytes(self::CRYPTO_AEAD_AES256GCM_KEYBYTES);
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* ChaCha20-Poly1305
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $ciphertext Encrypted message (with Poly1305 MAC
appended)
* @param string $assocData Authenticated Associated Data
(unencrypted)
* @param string $nonce Number to be used only Once; must be 8
bytes
* @param string $key Encryption key
*
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_chacha20poly1305_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) {
throw new SodiumException('Nonce must be
CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
throw new SodiumException('Key must be
CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) <
self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) {
throw new SodiumException('Message must be at least
CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_aead_chacha20poly1305_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
if
(self::use_fallback('crypto_aead_chacha20poly1305_decrypt')) {
return call_user_func(
'\\Sodium\\crypto_aead_chacha20poly1305_decrypt',
$ciphertext,
$assocData,
$nonce,
$key
);
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
/**
* Authenticated Encryption with Associated Data
*
* Algorithm:
* ChaCha20-Poly1305
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8
bytes
* @param string $key Encryption key
*
* @return string Ciphertext with a 16-byte Poly1305 message
* authentication code appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_chacha20poly1305_encrypt(
$plaintext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) {
throw new SodiumException('Nonce must be
CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
throw new SodiumException('Key must be
CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_aead_chacha20poly1305_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
if
(self::use_fallback('crypto_aead_chacha20poly1305_encrypt')) {
return (string) call_user_func(
'\\Sodium\\crypto_aead_chacha20poly1305_encrypt',
$plaintext,
$assocData,
$nonce,
$key
);
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* ChaCha20-Poly1305
*
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
* Regular mode uses a 64-bit random nonce with a 64-bit counter.
*
* @param string $ciphertext Encrypted message (with Poly1305 MAC
appended)
* @param string $assocData Authenticated Associated Data
(unencrypted)
* @param string $nonce Number to be used only Once; must be 12
bytes
* @param string $key Encryption key
*
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_aead_chacha20poly1305_ietf_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) {
throw new SodiumException('Nonce must be
CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
throw new SodiumException('Key must be
CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) <
self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) {
throw new SodiumException('Message must be at least
CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_aead_chacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
if
(self::use_fallback('crypto_aead_chacha20poly1305_ietf_decrypt'))
{
return call_user_func(
'\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt',
$ciphertext,
$assocData,
$nonce,
$key
);
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
/**
* Return a secure random key for use with the ChaCha20-Poly1305
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_chacha20poly1305_keygen()
{
return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES);
}
/**
* Authenticated Encryption with Associated Data
*
* Algorithm:
* ChaCha20-Poly1305
*
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
* Regular mode uses a 64-bit random nonce with a 64-bit counter.
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once; must be 8 bytes
* @param string $key Encryption key
*
* @return string Ciphertext with a 16-byte Poly1305 message
* authentication code appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_chacha20poly1305_ietf_encrypt(
$plaintext = '',
$assocData = '',
$nonce = '',
$key = ''
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) {
throw new SodiumException('Nonce must be
CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
throw new SodiumException('Key must be
CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
}
if (self::useNewSodiumAPI()) {
return (string)
sodium_crypto_aead_chacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
if
(self::use_fallback('crypto_aead_chacha20poly1305_ietf_encrypt'))
{
return (string) call_user_func(
'\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt',
$plaintext,
$assocData,
$nonce,
$key
);
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
/**
* Return a secure random key for use with the ChaCha20-Poly1305
* symmetric AEAD interface. (IETF version)
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_chacha20poly1305_ietf_keygen()
{
return
random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES);
}
/**
* Authenticated Encryption with Associated Data: Decryption
*
* Algorithm:
* XChaCha20-Poly1305
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $ciphertext Encrypted message (with Poly1305 MAC
appended)
* @param string $assocData Authenticated Associated Data
(unencrypted)
* @param string $nonce Number to be used only Once; must be 8
bytes
* @param string $key Encryption key
* @param bool $dontFallback Don't fallback to ext/sodium
*
* @return string|bool The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_xchacha20poly1305_ietf_decrypt(
$ciphertext = '',
$assocData = '',
$nonce = '',
$key = '',
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) {
throw new SodiumException('Nonce must be
CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) {
throw new SodiumException('Key must be
CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) <
self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES) {
throw new SodiumException('Message must be at least
CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES long');
}
if (self::useNewSodiumAPI() && !$dontFallback) {
if
(is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt'))
{
return sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
return
ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_decrypt(
$ciphertext,
$assocData,
$nonce,
$key
);
}
/**
* Authenticated Encryption with Associated Data
*
* Algorithm:
* XChaCha20-Poly1305
*
* This mode uses a 64-bit random nonce with a 64-bit counter.
* IETF mode uses a 96-bit random nonce with a 32-bit counter.
*
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data
(unencrypted)
* @param string $nonce Number to be used only Once; must be 8
bytes
* @param string $key Encryption key
* @param bool $dontFallback Don't fallback to ext/sodium
*
* @return string Ciphertext with a 16-byte Poly1305 message
* authentication code appended
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_aead_xchacha20poly1305_ietf_encrypt(
$plaintext = '',
$assocData = '',
$nonce = '',
$key = '',
$dontFallback = false
) {
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($assocData,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) {
throw new SodiumException('Nonce must be
CRYPTO_AEAD_XCHACHA20POLY1305_NPUBBYTES long');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) {
throw new SodiumException('Key must be
CRYPTO_AEAD_XCHACHA20POLY1305_KEYBYTES long');
}
if (self::useNewSodiumAPI() && !$dontFallback) {
if
(is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt'))
{
return sodium_crypto_aead_xchacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
return
ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_encrypt(
$plaintext,
$assocData,
$nonce,
$key
);
}
/**
* Return a secure random key for use with the XChaCha20-Poly1305
* symmetric AEAD interface.
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_aead_xchacha20poly1305_ietf_keygen()
{
return
random_bytes(self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES);
}
/**
* Authenticate a message. Uses symmetric-key cryptography.
*
* Algorithm:
* HMAC-SHA512-256. Which is HMAC-SHA-512 truncated to 256 bits.
* Not to be confused with HMAC-SHA-512/256 which would use the
* SHA-512/256 hash function (uses different initial parameters
* but still truncates to 256 bits to sidestep length-extension
* attacks).
*
* @param string $message Message to be authenticated
* @param string $key Symmetric authentication key
* @return string Message authentication code
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_auth($message, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AUTH_KEYBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_AUTH_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_auth($message, $key);
}
if (self::use_fallback('crypto_auth')) {
return (string)
call_user_func('\\Sodium\\crypto_auth', $message, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::auth($message, $key);
}
return ParagonIE_Sodium_Crypto::auth($message, $key);
}
/**
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_auth_keygen()
{
return random_bytes(self::CRYPTO_AUTH_KEYBYTES);
}
/**
* Verify the MAC of a message previously authenticated with
crypto_auth.
*
* @param string $mac Message authentication code
* @param string $message Message whose authenticity you are attempting
to
* verify (with a given MAC and key)
* @param string $key Symmetric authentication key
* @return bool TRUE if authenticated, FALSE otherwise
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_auth_verify($mac, $message, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($mac,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($message,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($mac) !==
self::CRYPTO_AUTH_BYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_AUTH_BYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_AUTH_KEYBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_AUTH_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (bool) sodium_crypto_auth_verify($mac, $message, $key);
}
if (self::use_fallback('crypto_auth_verify')) {
return (bool)
call_user_func('\\Sodium\\crypto_auth_verify', $mac, $message,
$key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::auth_verify($mac, $message,
$key);
}
return ParagonIE_Sodium_Crypto::auth_verify($mac, $message, $key);
}
/**
* Authenticated asymmetric-key encryption. Both the sender and
recipient
* may decrypt messages.
*
* Algorithm: X25519-XSalsa20-Poly1305.
* X25519: Elliptic-Curve Diffie Hellman over Curve25519.
* XSalsa20: Extended-nonce variant of salsa20.
* Poyl1305: Polynomial MAC for one-time message authentication.
*
* @param string $plaintext The message to be encrypted
* @param string $nonce A Number to only be used Once; must be 24 bytes
* @param string $keypair Your secret key and your recipient's
public key
* @return string Ciphertext with 16-byte Poly1305 MAC
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box($plaintext, $nonce, $keypair)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($keypair,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_BOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_BOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box($plaintext, $nonce,
$keypair);
}
if (self::use_fallback('crypto_box')) {
return (string)
call_user_func('\\Sodium\\crypto_box', $plaintext, $nonce,
$keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box($plaintext, $nonce,
$keypair);
}
return ParagonIE_Sodium_Crypto::box($plaintext, $nonce, $keypair);
}
/**
* Anonymous public-key encryption. Only the recipient may decrypt
messages.
*
* Algorithm: X25519-XSalsa20-Poly1305, as with crypto_box.
* The sender's X25519 keypair is ephemeral.
* Nonce is generated from the BLAKE2b hash of both public keys.
*
* This provides ciphertext integrity.
*
* @param string $plaintext Message to be sealed
* @param string $publicKey Your recipient's public key
* @return string Sealed message that only your recipient can
* decrypt
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_seal($plaintext, $publicKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey,
'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !==
self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_seal($plaintext, $publicKey);
}
if (self::use_fallback('crypto_box_seal')) {
return (string)
call_user_func('\\Sodium\\crypto_box_seal', $plaintext,
$publicKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_seal($plaintext,
$publicKey);
}
return ParagonIE_Sodium_Crypto::box_seal($plaintext, $publicKey);
}
/**
* Opens a message encrypted with crypto_box_seal(). Requires
* the recipient's keypair (sk || pk) to decrypt successfully.
*
* This validates ciphertext integrity.
*
* @param string $ciphertext Sealed message to be opened
* @param string $keypair Your crypto_box keypair
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_box_seal_open($ciphertext, $keypair)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($keypair,
'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_box_seal_open($ciphertext, $keypair);
}
if (self::use_fallback('crypto_box_seal_open')) {
return
call_user_func('\\Sodium\\crypto_box_seal_open', $ciphertext,
$keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_seal_open($ciphertext,
$keypair);
}
return ParagonIE_Sodium_Crypto::box_seal_open($ciphertext,
$keypair);
}
/**
* Generate a new random X25519 keypair.
*
* @return string A 64-byte string; the first 32 are your secret key,
while
* the last 32 are your public key.
crypto_box_secretkey()
* and crypto_box_publickey() exist to separate them so
you
* don't accidentally get them mixed up!
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_keypair()
{
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_keypair();
}
if (self::use_fallback('crypto_box_keypair')) {
return (string)
call_user_func('\\Sodium\\crypto_box_keypair');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_keypair();
}
return ParagonIE_Sodium_Crypto::box_keypair();
}
/**
* Combine two keys into a keypair for use in library methods that
expect
* a keypair. This doesn't necessarily have to be the same
person's keys.
*
* @param string $secretKey Secret key
* @param string $publicKey Public key
* @return string Keypair
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function
crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey,
'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !==
self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !==
self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string)
sodium_crypto_box_keypair_from_secretkey_and_publickey($secretKey,
$publicKey);
}
if
(self::use_fallback('crypto_box_keypair_from_secretkey_and_publickey'))
{
return (string)
call_user_func('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey',
$secretKey, $publicKey);
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::box_keypair_from_secretkey_and_publickey($secretKey,
$publicKey);
}
return
ParagonIE_Sodium_Crypto::box_keypair_from_secretkey_and_publickey($secretKey,
$publicKey);
}
/**
* Decrypt a message previously encrypted with crypto_box().
*
* @param string $ciphertext Encrypted message
* @param string $nonce Number to only be used Once; must be 24
bytes
* @param string $keypair Your secret key and the sender's
public key
* @return string The original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_box_open($ciphertext, $nonce, $keypair)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($keypair,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) <
self::CRYPTO_BOX_MACBYTES) {
throw new SodiumException('Argument 1 must be at least
CRYPTO_BOX_MACBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_BOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_BOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_box_open($ciphertext, $nonce, $keypair);
}
if (self::use_fallback('crypto_box_open')) {
return call_user_func('\\Sodium\\crypto_box_open',
$ciphertext, $nonce, $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_open($ciphertext, $nonce,
$keypair);
}
return ParagonIE_Sodium_Crypto::box_open($ciphertext, $nonce,
$keypair);
}
/**
* Extract the public key from a crypto_box keypair.
*
* @param string $keypair Keypair containing secret and public key
* @return string Your crypto_box public key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_publickey($keypair)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($keypair,
'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_publickey($keypair);
}
if (self::use_fallback('crypto_box_publickey')) {
return (string)
call_user_func('\\Sodium\\crypto_box_publickey', $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_publickey($keypair);
}
return ParagonIE_Sodium_Crypto::box_publickey($keypair);
}
/**
* Calculate the X25519 public key from a given X25519 secret key.
*
* @param string $secretKey Any X25519 secret key
* @return string The corresponding X25519 public key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_publickey_from_secretkey($secretKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey,
'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !==
self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string)
sodium_crypto_box_publickey_from_secretkey($secretKey);
}
if
(self::use_fallback('crypto_box_publickey_from_secretkey')) {
return (string)
call_user_func('\\Sodium\\crypto_box_publickey_from_secretkey',
$secretKey);
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::box_publickey_from_secretkey($secretKey);
}
return
ParagonIE_Sodium_Crypto::box_publickey_from_secretkey($secretKey);
}
/**
* Extract the secret key from a crypto_box keypair.
*
* @param string $keypair
* @return string Your crypto_box secret key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_box_secretkey($keypair)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($keypair,
'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
self::CRYPTO_BOX_KEYPAIRBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_BOX_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_secretkey($keypair);
}
if (self::use_fallback('crypto_box_secretkey')) {
return (string)
call_user_func('\\Sodium\\crypto_box_secretkey', $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_secretkey($keypair);
}
return ParagonIE_Sodium_Crypto::box_secretkey($keypair);
}
/**
* Generate an X25519 keypair from a seed.
*
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress UndefinedFunction
*/
public static function crypto_box_seed_keypair($seed)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($seed,
'string', 1);
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_box_seed_keypair($seed);
}
if (self::use_fallback('crypto_box_seed_keypair')) {
return (string)
call_user_func('\\Sodium\\crypto_box_seed_keypair', $seed);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::box_seed_keypair($seed);
}
return ParagonIE_Sodium_Crypto::box_seed_keypair($seed);
}
/**
* Calculates a BLAKE2b hash, with an optional key.
*
* @param string $message The message to be hashed
* @param string|null $key If specified, must be a string between
16
* and 64 bytes long
* @param int $length Output length in bytes; must be between
16
* and 64 (default = 32)
* @return string Raw binary
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_generichash($message, $key =
'', $length = self::CRYPTO_GENERICHASH_BYTES)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message,
'string', 1);
if (is_null($key)) {
$key = '';
}
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($length,
'int', 3);
/* Input validation: */
if (!empty($key)) {
if (ParagonIE_Sodium_Core_Util::strlen($key) <
self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
throw new SodiumException('Unsupported key size. Must
be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) >
self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
throw new SodiumException('Unsupported key size. Must
be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
}
}
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_generichash($message, $key,
$length);
}
if (self::use_fallback('crypto_generichash')) {
return (string)
call_user_func('\\Sodium\\crypto_generichash', $message, $key,
$length);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::generichash($message, $key,
$length);
}
return ParagonIE_Sodium_Crypto::generichash($message, $key,
$length);
}
/**
* Get the final BLAKE2b hash output for a given context.
*
* @param string $ctx BLAKE2 hashing context. Generated by
crypto_generichash_init().
* @param int $length Hash output size.
* @return string Final BLAKE2b hash.
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress ReferenceConstraintViolation
* @psalm-suppress ConflictingReferenceConstraint
*/
public static function crypto_generichash_final(&$ctx, $length =
self::CRYPTO_GENERICHASH_BYTES)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ctx,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($length,
'int', 2);
if (self::useNewSodiumAPI()) {
return sodium_crypto_generichash_final($ctx, $length);
}
if (self::use_fallback('crypto_generichash_final')) {
$func = '\\Sodium\\crypto_generichash_final';
return (string) $func($ctx, $length);
}
if ($length < 1) {
try {
self::memzero($ctx);
} catch (SodiumException $ex) {
unset($ctx);
}
return '';
}
if (PHP_INT_SIZE === 4) {
$result = ParagonIE_Sodium_Crypto32::generichash_final($ctx,
$length);
} else {
$result = ParagonIE_Sodium_Crypto::generichash_final($ctx,
$length);
}
try {
self::memzero($ctx);
} catch (SodiumException $ex) {
unset($ctx);
}
return $result;
}
/**
* Initialize a BLAKE2b hashing context, for use in a streaming
interface.
*
* @param string|null $key If specified must be a string between 16 and
64 bytes
* @param int $length The size of the desired hash output
* @return string A BLAKE2 hashing context, encoded as a
string
* (To be 100% compatible with ext/libsodium)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_generichash_init($key = '',
$length = self::CRYPTO_GENERICHASH_BYTES)
{
/* Type checks: */
if (is_null($key)) {
$key = '';
}
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($length,
'int', 2);
/* Input validation: */
if (!empty($key)) {
if (ParagonIE_Sodium_Core_Util::strlen($key) <
self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
throw new SodiumException('Unsupported key size. Must
be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) >
self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
throw new SodiumException('Unsupported key size. Must
be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
}
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_generichash_init($key, $length);
}
if (self::use_fallback('crypto_generichash_init')) {
return (string)
call_user_func('\\Sodium\\crypto_generichash_init', $key,
$length);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::generichash_init($key,
$length);
}
return ParagonIE_Sodium_Crypto::generichash_init($key, $length);
}
/**
* Initialize a BLAKE2b hashing context, for use in a streaming
interface.
*
* @param string|null $key If specified must be a string between 16 and
64 bytes
* @param int $length The size of the desired hash output
* @param string $salt Salt (up to 16 bytes)
* @param string $personal Personalization string (up to 16 bytes)
* @return string A BLAKE2 hashing context, encoded as a
string
* (To be 100% compatible with ext/libsodium)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_generichash_init_salt_personal(
$key = '',
$length = self::CRYPTO_GENERICHASH_BYTES,
$salt = '',
$personal = ''
) {
/* Type checks: */
if (is_null($key)) {
$key = '';
}
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($length,
'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($salt,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($personal,
'string', 4);
$salt = str_pad($salt, 16, "\0", STR_PAD_RIGHT);
$personal = str_pad($personal, 16, "\0", STR_PAD_RIGHT);
/* Input validation: */
if (!empty($key)) {
/*
if (ParagonIE_Sodium_Core_Util::strlen($key) <
self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
throw new SodiumException('Unsupported key size. Must
be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
}
*/
if (ParagonIE_Sodium_Core_Util::strlen($key) >
self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
throw new SodiumException('Unsupported key size. Must
be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
}
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::generichash_init_salt_personal($key, $length,
$salt, $personal);
}
return
ParagonIE_Sodium_Crypto::generichash_init_salt_personal($key, $length,
$salt, $personal);
}
/**
* Update a BLAKE2b hashing context with additional data.
*
* @param string $ctx BLAKE2 hashing context. Generated by
crypto_generichash_init().
* $ctx is passed by reference and gets updated
in-place.
* @param-out string $ctx
* @param string $message The message to append to the existing hash
state.
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress ReferenceConstraintViolation
*/
public static function crypto_generichash_update(&$ctx, $message)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ctx,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($message,
'string', 2);
if (self::useNewSodiumAPI()) {
sodium_crypto_generichash_update($ctx, $message);
return;
}
if (self::use_fallback('crypto_generichash_update')) {
$func = '\\Sodium\\crypto_generichash_update';
$func($ctx, $message);
return;
}
if (PHP_INT_SIZE === 4) {
$ctx = ParagonIE_Sodium_Crypto32::generichash_update($ctx,
$message);
} else {
$ctx = ParagonIE_Sodium_Crypto::generichash_update($ctx,
$message);
}
}
/**
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_generichash_keygen()
{
return random_bytes(self::CRYPTO_GENERICHASH_KEYBYTES);
}
/**
* @param int $subkey_len
* @param int $subkey_id
* @param string $context
* @param string $key
* @return string
* @throws SodiumException
*/
public static function crypto_kdf_derive_from_key(
$subkey_len,
$subkey_id,
$context,
$key
) {
ParagonIE_Sodium_Core_Util::declareScalarType($subkey_len,
'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($subkey_id,
'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($context,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 4);
$subkey_id = (int) $subkey_id;
$subkey_len = (int) $subkey_len;
$context = (string) $context;
$key = (string) $key;
if ($subkey_len < self::CRYPTO_KDF_BYTES_MIN) {
throw new SodiumException('subkey cannot be smaller than
SODIUM_CRYPTO_KDF_BYTES_MIN');
}
if ($subkey_len > self::CRYPTO_KDF_BYTES_MAX) {
throw new SodiumException('subkey cannot be larger than
SODIUM_CRYPTO_KDF_BYTES_MAX');
}
if ($subkey_id < 0) {
throw new SodiumException('subkey_id cannot be
negative');
}
if (ParagonIE_Sodium_Core_Util::strlen($context) !==
self::CRYPTO_KDF_CONTEXTBYTES) {
throw new SodiumException('context should be
SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_KDF_KEYBYTES) {
throw new SodiumException('key should be
SODIUM_CRYPTO_KDF_KEYBYTES bytes');
}
$salt = ParagonIE_Sodium_Core_Util::store64_le($subkey_id);
$state = self::crypto_generichash_init_salt_personal(
$key,
$subkey_len,
$salt,
$context
);
return self::crypto_generichash_final($state, $subkey_len);
}
/**
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_kdf_keygen()
{
return random_bytes(self::CRYPTO_KDF_KEYBYTES);
}
/**
* Perform a key exchange, between a designated client and a server.
*
* Typically, you would designate one machine to be the client and the
* other to be the server. The first two keys are what you'd
expect for
* scalarmult() below, but the latter two public keys don't swap
places.
*
* | ALICE | BOB
|
* | Client | Server
|
*
|--------------------------------|-------------------------------------|
* | shared = crypto_kx( | shared = crypto_kx(
|
* | alice_sk, | bob_sk,
| <- contextual
* | bob_pk, | alice_pk,
| <- contextual
* | alice_pk, | alice_pk,
| <----- static
* | bob_pk | bob_pk
| <----- static
* | ) | )
|
*
* They are used along with the scalarmult product to generate a
256-bit
* BLAKE2b hash unique to the client and server keys.
*
* @param string $my_secret
* @param string $their_public
* @param string $client_public
* @param string $server_public
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_kx($my_secret, $their_public,
$client_public, $server_public)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($my_secret,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($their_public,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($client_public,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($server_public,
'string', 4);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($my_secret) !==
self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($their_public) !==
self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($client_public) !==
self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($server_public) !==
self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 4 must be
CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
if (is_callable('sodium_crypto_kx')) {
return (string) sodium_crypto_kx(
$my_secret,
$their_public,
$client_public,
$server_public
);
}
}
if (self::use_fallback('crypto_kx')) {
return (string) call_user_func(
'\\Sodium\\crypto_kx',
$my_secret,
$their_public,
$client_public,
$server_public
);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::keyExchange(
$my_secret,
$their_public,
$client_public,
$server_public
);
}
return ParagonIE_Sodium_Crypto::keyExchange(
$my_secret,
$their_public,
$client_public,
$server_public
);
}
/**
* @param string $seed
* @return string
* @throws SodiumException
*/
public static function crypto_kx_seed_keypair($seed)
{
ParagonIE_Sodium_Core_Util::declareScalarType($seed,
'string', 1);
$seed = (string) $seed;
if (ParagonIE_Sodium_Core_Util::strlen($seed) !==
self::CRYPTO_KX_SEEDBYTES) {
throw new SodiumException('seed must be
SODIUM_CRYPTO_KX_SEEDBYTES bytes');
}
$sk = self::crypto_generichash($seed, '',
self::CRYPTO_KX_SECRETKEYBYTES);
$pk = self::crypto_scalarmult_base($sk);
return $sk . $pk;
}
/**
* @return string
* @throws Exception
*/
public static function crypto_kx_keypair()
{
$sk = self::randombytes_buf(self::CRYPTO_KX_SECRETKEYBYTES);
$pk = self::crypto_scalarmult_base($sk);
return $sk . $pk;
}
/**
* @param string $keypair
* @param string $serverPublicKey
* @return array{0: string, 1: string}
* @throws SodiumException
*/
public static function crypto_kx_client_session_keys($keypair,
$serverPublicKey)
{
ParagonIE_Sodium_Core_Util::declareScalarType($keypair,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($serverPublicKey,
'string', 2);
$keypair = (string) $keypair;
$serverPublicKey = (string) $serverPublicKey;
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
self::CRYPTO_KX_KEYPAIRBYTES) {
throw new SodiumException('keypair should be
SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
}
if (ParagonIE_Sodium_Core_Util::strlen($serverPublicKey) !==
self::CRYPTO_KX_PUBLICKEYBYTES) {
throw new SodiumException('public keys must be
SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
}
$sk = self::crypto_kx_secretkey($keypair);
$pk = self::crypto_kx_publickey($keypair);
$h = self::crypto_generichash_init(null,
self::CRYPTO_KX_SESSIONKEYBYTES * 2);
self::crypto_generichash_update($h, self::crypto_scalarmult($sk,
$serverPublicKey));
self::crypto_generichash_update($h, $pk);
self::crypto_generichash_update($h, $serverPublicKey);
$sessionKeys = self::crypto_generichash_final($h,
self::CRYPTO_KX_SESSIONKEYBYTES * 2);
return array(
ParagonIE_Sodium_Core_Util::substr(
$sessionKeys,
0,
self::CRYPTO_KX_SESSIONKEYBYTES
),
ParagonIE_Sodium_Core_Util::substr(
$sessionKeys,
self::CRYPTO_KX_SESSIONKEYBYTES,
self::CRYPTO_KX_SESSIONKEYBYTES
)
);
}
/**
* @param string $keypair
* @param string $clientPublicKey
* @return array{0: string, 1: string}
* @throws SodiumException
*/
public static function crypto_kx_server_session_keys($keypair,
$clientPublicKey)
{
ParagonIE_Sodium_Core_Util::declareScalarType($keypair,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($clientPublicKey,
'string', 2);
$keypair = (string) $keypair;
$clientPublicKey = (string) $clientPublicKey;
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
self::CRYPTO_KX_KEYPAIRBYTES) {
throw new SodiumException('keypair should be
SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
}
if (ParagonIE_Sodium_Core_Util::strlen($clientPublicKey) !==
self::CRYPTO_KX_PUBLICKEYBYTES) {
throw new SodiumException('public keys must be
SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
}
$sk = self::crypto_kx_secretkey($keypair);
$pk = self::crypto_kx_publickey($keypair);
$h = self::crypto_generichash_init(null,
self::CRYPTO_KX_SESSIONKEYBYTES * 2);
self::crypto_generichash_update($h, self::crypto_scalarmult($sk,
$clientPublicKey));
self::crypto_generichash_update($h, $clientPublicKey);
self::crypto_generichash_update($h, $pk);
$sessionKeys = self::crypto_generichash_final($h,
self::CRYPTO_KX_SESSIONKEYBYTES * 2);
return array(
ParagonIE_Sodium_Core_Util::substr(
$sessionKeys,
self::CRYPTO_KX_SESSIONKEYBYTES,
self::CRYPTO_KX_SESSIONKEYBYTES
),
ParagonIE_Sodium_Core_Util::substr(
$sessionKeys,
0,
self::CRYPTO_KX_SESSIONKEYBYTES
)
);
}
/**
* @param string $kp
* @return string
* @throws SodiumException
*/
public static function crypto_kx_secretkey($kp)
{
return ParagonIE_Sodium_Core_Util::substr(
$kp,
0,
self::CRYPTO_KX_SECRETKEYBYTES
);
}
/**
* @param string $kp
* @return string
* @throws SodiumException
*/
public static function crypto_kx_publickey($kp)
{
return ParagonIE_Sodium_Core_Util::substr(
$kp,
self::CRYPTO_KX_SECRETKEYBYTES,
self::CRYPTO_KX_PUBLICKEYBYTES
);
}
/**
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @param int|null $alg
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_pwhash($outlen, $passwd, $salt,
$opslimit, $memlimit, $alg = null)
{
ParagonIE_Sodium_Core_Util::declareScalarType($outlen,
'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($passwd,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($salt,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit,
'int', 4);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit,
'int', 5);
if (self::useNewSodiumAPI()) {
if (!is_null($alg)) {
ParagonIE_Sodium_Core_Util::declareScalarType($alg,
'int', 6);
return sodium_crypto_pwhash($outlen, $passwd, $salt,
$opslimit, $memlimit, $alg);
}
return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit,
$memlimit);
}
if (self::use_fallback('crypto_pwhash')) {
return (string)
call_user_func('\\Sodium\\crypto_pwhash', $outlen, $passwd,
$salt, $opslimit, $memlimit);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to
implement Argon2i with acceptable performance in pure-PHP'
);
}
/**
* !Exclusive to sodium_compat!
*
* This returns TRUE if the native crypto_pwhash API is available by
libsodium.
* This returns FALSE if only sodium_compat is available.
*
* @return bool
*/
public static function crypto_pwhash_is_available()
{
if (self::useNewSodiumAPI()) {
return true;
}
if (self::use_fallback('crypto_pwhash')) {
return true;
}
return false;
}
/**
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_pwhash_str($passwd, $opslimit, $memlimit)
{
ParagonIE_Sodium_Core_Util::declareScalarType($passwd,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit,
'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit,
'int', 3);
if (self::useNewSodiumAPI()) {
return sodium_crypto_pwhash_str($passwd, $opslimit, $memlimit);
}
if (self::use_fallback('crypto_pwhash_str')) {
return (string)
call_user_func('\\Sodium\\crypto_pwhash_str', $passwd, $opslimit,
$memlimit);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to
implement Argon2i with acceptable performance in pure-PHP'
);
}
/**
* Do we need to rehash this password?
*
* @param string $hash
* @param int $opslimit
* @param int $memlimit
* @return bool
* @throws SodiumException
*/
public static function crypto_pwhash_str_needs_rehash($hash, $opslimit,
$memlimit)
{
ParagonIE_Sodium_Core_Util::declareScalarType($hash,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit,
'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit,
'int', 3);
// Just grab the first 4 pieces.
$pieces = explode('$', (string) $hash);
$prefix = implode('$', array_slice($pieces, 0, 4));
// Rebuild the expected header.
/** @var int $ops */
$ops = (int) $opslimit;
/** @var int $mem */
$mem = (int) $memlimit >> 10;
$encoded = self::CRYPTO_PWHASH_STRPREFIX . 'v=19$m=' .
$mem . ',t=' . $ops . ',p=1';
// Do they match? If so, we don't need to rehash, so return
false.
return !ParagonIE_Sodium_Core_Util::hashEquals($encoded, $prefix);
}
/**
* @param string $passwd
* @param string $hash
* @return bool
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_pwhash_str_verify($passwd, $hash)
{
ParagonIE_Sodium_Core_Util::declareScalarType($passwd,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($hash,
'string', 2);
if (self::useNewSodiumAPI()) {
return (bool) sodium_crypto_pwhash_str_verify($passwd, $hash);
}
if (self::use_fallback('crypto_pwhash_str_verify')) {
return (bool)
call_user_func('\\Sodium\\crypto_pwhash_str_verify', $passwd,
$hash);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to
implement Argon2i with acceptable performance in pure-PHP'
);
}
/**
* @param int $outlen
* @param string $passwd
* @param string $salt
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_pwhash_scryptsalsa208sha256($outlen,
$passwd, $salt, $opslimit, $memlimit)
{
ParagonIE_Sodium_Core_Util::declareScalarType($outlen,
'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($passwd,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($salt,
'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit,
'int', 4);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit,
'int', 5);
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_pwhash_scryptsalsa208sha256(
(int) $outlen,
(string) $passwd,
(string) $salt,
(int) $opslimit,
(int) $memlimit
);
}
if
(self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) {
return (string) call_user_func(
'\\Sodium\\crypto_pwhash_scryptsalsa208sha256',
(int) $outlen,
(string) $passwd,
(string) $salt,
(int) $opslimit,
(int) $memlimit
);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to
implement Scrypt with acceptable performance in pure-PHP'
);
}
/**
* !Exclusive to sodium_compat!
*
* This returns TRUE if the native crypto_pwhash API is available by
libsodium.
* This returns FALSE if only sodium_compat is available.
*
* @return bool
*/
public static function
crypto_pwhash_scryptsalsa208sha256_is_available()
{
if (self::useNewSodiumAPI()) {
return true;
}
if
(self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) {
return true;
}
return false;
}
/**
* @param string $passwd
* @param int $opslimit
* @param int $memlimit
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_pwhash_scryptsalsa208sha256_str($passwd,
$opslimit, $memlimit)
{
ParagonIE_Sodium_Core_Util::declareScalarType($passwd,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit,
'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit,
'int', 3);
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_pwhash_scryptsalsa208sha256_str(
(string) $passwd,
(int) $opslimit,
(int) $memlimit
);
}
if
(self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str')) {
return (string) call_user_func(
'\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str',
(string) $passwd,
(int) $opslimit,
(int) $memlimit
);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to
implement Scrypt with acceptable performance in pure-PHP'
);
}
/**
* @param string $passwd
* @param string $hash
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function
crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash)
{
ParagonIE_Sodium_Core_Util::declareScalarType($passwd,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($hash,
'string', 2);
if (self::useNewSodiumAPI()) {
return (bool)
sodium_crypto_pwhash_scryptsalsa208sha256_str_verify(
(string) $passwd,
(string) $hash
);
}
if
(self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str_verify'))
{
return (bool) call_user_func(
'\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify',
(string) $passwd,
(string) $hash
);
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to
implement Scrypt with acceptable performance in pure-PHP'
);
}
/**
* Calculate the shared secret between your secret key and your
* recipient's public key.
*
* Algorithm: X25519 (ECDH over Curve25519)
*
* @param string $secretKey
* @param string $publicKey
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_scalarmult($secretKey, $publicKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey,
'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !==
self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !==
self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_BOX_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_scalarmult($secretKey, $publicKey);
}
if (self::use_fallback('crypto_scalarmult')) {
return (string)
call_user_func('\\Sodium\\crypto_scalarmult', $secretKey,
$publicKey);
}
/* Output validation: Forbid all-zero keys */
if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey,
str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
throw new SodiumException('Zero secret key is not
allowed');
}
if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey,
str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) {
throw new SodiumException('Zero public key is not
allowed');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::scalarmult($secretKey,
$publicKey);
}
return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey);
}
/**
* Calculate an X25519 public key from an X25519 secret key.
*
* @param string $secretKey
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress TooFewArguments
* @psalm-suppress MixedArgument
*/
public static function crypto_scalarmult_base($secretKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey,
'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !==
self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_BOX_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_scalarmult_base($secretKey);
}
if (self::use_fallback('crypto_scalarmult_base')) {
return (string)
call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey);
}
if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey,
str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
throw new SodiumException('Zero secret key is not
allowed');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::scalarmult_base($secretKey);
}
return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey);
}
/**
* Authenticated symmetric-key encryption.
*
* Algorithm: XSalsa20-Poly1305
*
* @param string $plaintext The message you're encrypting
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Ciphertext with Poly1305 MAC
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_secretbox($plaintext, $nonce, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_secretbox($plaintext, $nonce, $key);
}
if (self::use_fallback('crypto_secretbox')) {
return (string)
call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce,
$key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox($plaintext, $nonce,
$key);
}
return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce,
$key);
}
/**
* Decrypts a message previously encrypted with crypto_secretbox().
*
* @param string $ciphertext Ciphertext with Poly1305 MAC
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_secretbox_open($ciphertext, $nonce, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
}
if (self::use_fallback('crypto_secretbox_open')) {
return
call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext,
$nonce, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox_open($ciphertext,
$nonce, $key);
}
return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce,
$key);
}
/**
* Return a secure random key for use with crypto_secretbox
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_secretbox_keygen()
{
return random_bytes(self::CRYPTO_SECRETBOX_KEYBYTES);
}
/**
* Authenticated symmetric-key encryption.
*
* Algorithm: XChaCha20-Poly1305
*
* @param string $plaintext The message you're encrypting
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Ciphertext with Poly1305 MAC
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_secretbox_xchacha20poly1305($plaintext,
$nonce, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305($plaintext, $nonce,
$key);
}
return
ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce,
$key);
}
/**
* Decrypts a message previously encrypted with
crypto_secretbox_xchacha20poly1305().
*
* @param string $ciphertext Ciphertext with Poly1305 MAC
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Original plaintext message
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function
crypto_secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305_open($ciphertext,
$nonce, $key);
}
return
ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext,
$nonce, $key);
}
/**
* @param string $key
* @return array<int, string> Returns a state and a header.
* @throws Exception
* @throws SodiumException
*/
public static function
crypto_secretstream_xchacha20poly1305_init_push($key)
{
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_push($key);
}
return
ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_push($key);
}
/**
* @param string $header
* @param string $key
* @return string Returns a state.
* @throws Exception
*/
public static function
crypto_secretstream_xchacha20poly1305_init_pull($header, $key)
{
if (ParagonIE_Sodium_Core_Util::strlen($header) <
self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) {
throw new SodiumException(
'header size should be
SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes'
);
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_pull($key,
$header);
}
return
ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_pull($key,
$header);
}
/**
* @param string $state
* @param string $msg
* @param string $aad
* @param int $tag
* @return string
* @throws SodiumException
*/
public static function
crypto_secretstream_xchacha20poly1305_push(&$state, $msg, $aad =
'', $tag = 0)
{
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_push(
$state,
$msg,
$aad,
$tag
);
}
return
ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_push(
$state,
$msg,
$aad,
$tag
);
}
/**
* @param string $state
* @param string $msg
* @param string $aad
* @return bool|array{0: string, 1: int}
* @throws SodiumException
*/
public static function
crypto_secretstream_xchacha20poly1305_pull(&$state, $msg, $aad =
'')
{
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_pull(
$state,
$msg,
$aad
);
}
return
ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_pull(
$state,
$msg,
$aad
);
}
/**
* @return string
* @throws Exception
*/
public static function crypto_secretstream_xchacha20poly1305_keygen()
{
return
random_bytes(self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES);
}
/**
* @param string $state
* @return void
* @throws SodiumException
*/
public static function
crypto_secretstream_xchacha20poly1305_rekey(&$state)
{
if (PHP_INT_SIZE === 4) {
ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_rekey($state);
} else {
ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_rekey($state);
}
}
/**
* Calculates a SipHash-2-4 hash of a message for a given key.
*
* @param string $message Input message
* @param string $key SipHash-2-4 key
* @return string Hash
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_shorthash($message, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_SHORTHASH_KEYBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SHORTHASH_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_shorthash($message, $key);
}
if (self::use_fallback('crypto_shorthash')) {
return (string)
call_user_func('\\Sodium\\crypto_shorthash', $message, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_SipHash::sipHash24($message,
$key);
}
return ParagonIE_Sodium_Core_SipHash::sipHash24($message, $key);
}
/**
* Return a secure random key for use with crypto_shorthash
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_shorthash_keygen()
{
return random_bytes(self::CRYPTO_SHORTHASH_KEYBYTES);
}
/**
* Returns a signed message. You probably want crypto_sign_detached()
* instead, which only returns the signature.
*
* Algorithm: Ed25519 (EdDSA over Curve25519)
*
* @param string $message Message to be signed.
* @param string $secretKey Secret signing key.
* @return string Signed message (signature is prefixed).
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_sign($message, $secretKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey,
'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !==
self::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SIGN_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign($message, $secretKey);
}
if (self::use_fallback('crypto_sign')) {
return (string)
call_user_func('\\Sodium\\crypto_sign', $message, $secretKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::sign($message, $secretKey);
}
return ParagonIE_Sodium_Crypto::sign($message, $secretKey);
}
/**
* Validates a signed message then returns the message.
*
* @param string $signedMessage A signed message
* @param string $publicKey A public key
* @return string The original message (if the signature
is
* valid for this public key)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
*/
public static function crypto_sign_open($signedMessage, $publicKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($signedMessage,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey,
'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($signedMessage) <
self::CRYPTO_SIGN_BYTES) {
throw new SodiumException('Argument 1 must be at least
CRYPTO_SIGN_BYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !==
self::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SIGN_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
/**
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
*/
return sodium_crypto_sign_open($signedMessage, $publicKey);
}
if (self::use_fallback('crypto_sign_open')) {
return call_user_func('\\Sodium\\crypto_sign_open',
$signedMessage, $publicKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::sign_open($signedMessage,
$publicKey);
}
return ParagonIE_Sodium_Crypto::sign_open($signedMessage,
$publicKey);
}
/**
* Generate a new random Ed25519 keypair.
*
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_sign_keypair()
{
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_keypair();
}
if (self::use_fallback('crypto_sign_keypair')) {
return (string)
call_user_func('\\Sodium\\crypto_sign_keypair');
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_Ed25519::keypair();
}
return ParagonIE_Sodium_Core_Ed25519::keypair();
}
/**
* @param string $sk
* @param string $pk
* @return string
* @throws SodiumException
*/
public static function
crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk)
{
ParagonIE_Sodium_Core_Util::declareScalarType($sk,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($pk,
'string', 1);
$sk = (string) $sk;
$pk = (string) $pk;
if (ParagonIE_Sodium_Core_Util::strlen($sk) !==
self::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new SodiumException('secretkey should be
SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes');
}
if (ParagonIE_Sodium_Core_Util::strlen($pk) !==
self::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new SodiumException('publickey should be
SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes');
}
if (self::useNewSodiumAPI()) {
return
sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk);
}
return $sk . $pk;
}
/**
* Generate an Ed25519 keypair from a seed.
*
* @param string $seed Input seed
* @return string Keypair
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_seed_keypair($seed)
{
ParagonIE_Sodium_Core_Util::declareScalarType($seed,
'string', 1);
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_seed_keypair($seed);
}
if (self::use_fallback('crypto_sign_keypair')) {
return (string)
call_user_func('\\Sodium\\crypto_sign_seed_keypair', $seed);
}
$publicKey = '';
$secretKey = '';
if (PHP_INT_SIZE === 4) {
ParagonIE_Sodium_Core32_Ed25519::seed_keypair($publicKey,
$secretKey, $seed);
} else {
ParagonIE_Sodium_Core_Ed25519::seed_keypair($publicKey,
$secretKey, $seed);
}
return $secretKey . $publicKey;
}
/**
* Extract an Ed25519 public key from an Ed25519 keypair.
*
* @param string $keypair Keypair
* @return string Public key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_publickey($keypair)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($keypair,
'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
self::CRYPTO_SIGN_KEYPAIRBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_SIGN_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_publickey($keypair);
}
if (self::use_fallback('crypto_sign_publickey')) {
return (string)
call_user_func('\\Sodium\\crypto_sign_publickey', $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_Ed25519::publickey($keypair);
}
return ParagonIE_Sodium_Core_Ed25519::publickey($keypair);
}
/**
* Calculate an Ed25519 public key from an Ed25519 secret key.
*
* @param string $secretKey Your Ed25519 secret key
* @return string The corresponding Ed25519 public key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_publickey_from_secretkey($secretKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey,
'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !==
self::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_SIGN_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_publickey_from_secretkey($secretKey);
}
if
(self::use_fallback('crypto_sign_publickey_from_secretkey')) {
return (string)
call_user_func('\\Sodium\\crypto_sign_publickey_from_secretkey',
$secretKey);
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Core32_Ed25519::publickey_from_secretkey($secretKey);
}
return
ParagonIE_Sodium_Core_Ed25519::publickey_from_secretkey($secretKey);
}
/**
* Extract an Ed25519 secret key from an Ed25519 keypair.
*
* @param string $keypair Keypair
* @return string Secret key
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_secretkey($keypair)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($keypair,
'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
self::CRYPTO_SIGN_KEYPAIRBYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_SIGN_KEYPAIRBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_secretkey($keypair);
}
if (self::use_fallback('crypto_sign_secretkey')) {
return (string)
call_user_func('\\Sodium\\crypto_sign_secretkey', $keypair);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_Ed25519::secretkey($keypair);
}
return ParagonIE_Sodium_Core_Ed25519::secretkey($keypair);
}
/**
* Calculate the Ed25519 signature of a message and return ONLY the
signature.
*
* Algorithm: Ed25519 (EdDSA over Curve25519)
*
* @param string $message Message to be signed
* @param string $secretKey Secret signing key
* @return string Digital signature
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_detached($message, $secretKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey,
'string', 2);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !==
self::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SIGN_SECRETKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_detached($message, $secretKey);
}
if (self::use_fallback('crypto_sign_detached')) {
return (string)
call_user_func('\\Sodium\\crypto_sign_detached', $message,
$secretKey);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::sign_detached($message,
$secretKey);
}
return ParagonIE_Sodium_Crypto::sign_detached($message,
$secretKey);
}
/**
* Verify the Ed25519 signature of a message.
*
* @param string $signature Digital sginature
* @param string $message Message to be verified
* @param string $publicKey Public key
* @return bool TRUE if this signature is good for this
public key;
* FALSE otherwise
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_verify_detached($signature,
$message, $publicKey)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($signature,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($message,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($signature) !==
self::CRYPTO_SIGN_BYTES) {
throw new SodiumException('Argument 1 must be
CRYPTO_SIGN_BYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !==
self::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_SIGN_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_sign_verify_detached($signature, $message,
$publicKey);
}
if (self::use_fallback('crypto_sign_verify_detached')) {
return (bool) call_user_func(
'\\Sodium\\crypto_sign_verify_detached',
$signature,
$message,
$publicKey
);
}
if (PHP_INT_SIZE === 4) {
return
ParagonIE_Sodium_Crypto32::sign_verify_detached($signature, $message,
$publicKey);
}
return ParagonIE_Sodium_Crypto::sign_verify_detached($signature,
$message, $publicKey);
}
/**
* Convert an Ed25519 public key to a Curve25519 public key
*
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_ed25519_pk_to_curve25519($pk)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($pk,
'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($pk) <
self::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new SodiumException('Argument 1 must be at least
CRYPTO_SIGN_PUBLICKEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
if
(is_callable('crypto_sign_ed25519_pk_to_curve25519')) {
return (string)
sodium_crypto_sign_ed25519_pk_to_curve25519($pk);
}
}
if
(self::use_fallback('crypto_sign_ed25519_pk_to_curve25519')) {
return (string)
call_user_func('\\Sodium\\crypto_sign_ed25519_pk_to_curve25519',
$pk);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_Ed25519::pk_to_curve25519($pk);
}
return ParagonIE_Sodium_Core_Ed25519::pk_to_curve25519($pk);
}
/**
* Convert an Ed25519 secret key to a Curve25519 secret key
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_sign_ed25519_sk_to_curve25519($sk)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($sk,
'string', 1);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($sk) <
self::CRYPTO_SIGN_SEEDBYTES) {
throw new SodiumException('Argument 1 must be at least
CRYPTO_SIGN_SEEDBYTES long.');
}
if (self::useNewSodiumAPI()) {
if
(is_callable('crypto_sign_ed25519_sk_to_curve25519')) {
return sodium_crypto_sign_ed25519_sk_to_curve25519($sk);
}
}
if
(self::use_fallback('crypto_sign_ed25519_sk_to_curve25519')) {
return (string)
call_user_func('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519',
$sk);
}
$h = hash('sha512',
ParagonIE_Sodium_Core_Util::substr($sk, 0, 32), true);
$h[0] = ParagonIE_Sodium_Core_Util::intToChr(
ParagonIE_Sodium_Core_Util::chrToInt($h[0]) & 248
);
$h[31] = ParagonIE_Sodium_Core_Util::intToChr(
(ParagonIE_Sodium_Core_Util::chrToInt($h[31]) & 127) | 64
);
return ParagonIE_Sodium_Core_Util::substr($h, 0, 32);
}
/**
* Expand a key and nonce into a keystream of pseudorandom bytes.
*
* @param int $len Number of bytes desired
* @param string $nonce Number to be used Once; must be 24 bytes
* @param string $key XSalsa20 key
* @return string Pseudorandom stream that can be XORed with
messages
* to provide encryption (but not authentication;
see
* Poly1305 or crypto_auth() for that, which is
not
* optional for security)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_stream($len, $nonce, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($len,
'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_STREAM_NONCEBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_STREAM_KEYBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_STREAM_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_stream($len, $nonce, $key);
}
if (self::use_fallback('crypto_stream')) {
return (string)
call_user_func('\\Sodium\\crypto_stream', $len, $nonce, $key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20($len, $nonce,
$key);
}
return ParagonIE_Sodium_Core_XSalsa20::xsalsa20($len, $nonce,
$key);
}
/**
* DANGER! UNAUTHENTICATED ENCRYPTION!
*
* Unless you are following expert advice, do not used this feature.
*
* Algorithm: XSalsa20
*
* This DOES NOT provide ciphertext integrity.
*
* @param string $message Plaintext message
* @param string $nonce Number to be used Once; must be 24 bytes
* @param string $key Encryption key
* @return string Encrypted text which is vulnerable to chosen-
* ciphertext attacks unless you implement some
* other mitigation to the ciphertext (i.e.
* Encrypt then MAC)
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function crypto_stream_xor($message, $nonce, $key)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($message,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce,
'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key,
'string', 3);
/* Input validation: */
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !==
self::CRYPTO_STREAM_NONCEBYTES) {
throw new SodiumException('Argument 2 must be
CRYPTO_SECRETBOX_NONCEBYTES long.');
}
if (ParagonIE_Sodium_Core_Util::strlen($key) !==
self::CRYPTO_STREAM_KEYBYTES) {
throw new SodiumException('Argument 3 must be
CRYPTO_SECRETBOX_KEYBYTES long.');
}
if (self::useNewSodiumAPI()) {
return sodium_crypto_stream_xor($message, $nonce, $key);
}
if (self::use_fallback('crypto_stream_xor')) {
return (string)
call_user_func('\\Sodium\\crypto_stream_xor', $message, $nonce,
$key);
}
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20_xor($message,
$nonce, $key);
}
return ParagonIE_Sodium_Core_XSalsa20::xsalsa20_xor($message,
$nonce, $key);
}
/**
* Return a secure random key for use with crypto_stream
*
* @return string
* @throws Exception
* @throws Error
*/
public static function crypto_stream_keygen()
{
return random_bytes(self::CRYPTO_STREAM_KEYBYTES);
}
/**
* Cache-timing-safe implementation of hex2bin().
*
* @param string $string Hexadecimal string
* @return string Raw binary string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress TooFewArguments
* @psalm-suppress MixedArgument
*/
public static function hex2bin($string)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($string,
'string', 1);
if (self::useNewSodiumAPI()) {
if (is_callable('sodium_hex2bin')) {
return (string) sodium_hex2bin($string);
}
}
if (self::use_fallback('hex2bin')) {
return (string) call_user_func('\\Sodium\\hex2bin',
$string);
}
return ParagonIE_Sodium_Core_Util::hex2bin($string);
}
/**
* Increase a string (little endian)
*
* @param string $var
*
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function increment(&$var)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($var,
'string', 1);
if (self::useNewSodiumAPI()) {
sodium_increment($var);
return;
}
if (self::use_fallback('increment')) {
$func = '\\Sodium\\increment';
$func($var);
return;
}
$len = ParagonIE_Sodium_Core_Util::strlen($var);
$c = 1;
$copy = '';
for ($i = 0; $i < $len; ++$i) {
$c += ParagonIE_Sodium_Core_Util::chrToInt(
ParagonIE_Sodium_Core_Util::substr($var, $i, 1)
);
$copy .= ParagonIE_Sodium_Core_Util::intToChr($c);
$c >>= 8;
}
$var = $copy;
}
/**
* The equivalent to the libsodium minor version we aim to be
compatible
* with (sans pwhash and memzero).
*
* @return int
*/
public static function library_version_major()
{
if (self::useNewSodiumAPI() &&
defined('SODIUM_LIBRARY_MAJOR_VERSION')) {
return SODIUM_LIBRARY_MAJOR_VERSION;
}
if (self::use_fallback('library_version_major')) {
/** @psalm-suppress UndefinedFunction */
return (int)
call_user_func('\\Sodium\\library_version_major');
}
return self::LIBRARY_VERSION_MAJOR;
}
/**
* The equivalent to the libsodium minor version we aim to be
compatible
* with (sans pwhash and memzero).
*
* @return int
*/
public static function library_version_minor()
{
if (self::useNewSodiumAPI() &&
defined('SODIUM_LIBRARY_MINOR_VERSION')) {
return SODIUM_LIBRARY_MINOR_VERSION;
}
if (self::use_fallback('library_version_minor')) {
/** @psalm-suppress UndefinedFunction */
return (int)
call_user_func('\\Sodium\\library_version_minor');
}
return self::LIBRARY_VERSION_MINOR;
}
/**
* Compare two strings.
*
* @param string $left
* @param string $right
* @return int
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
*/
public static function memcmp($left, $right)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($left,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($right,
'string', 2);
if (self::useNewSodiumAPI()) {
return sodium_memcmp($left, $right);
}
if (self::use_fallback('memcmp')) {
return (int) call_user_func('\\Sodium\\memcmp',
$left, $right);
}
/** @var string $left */
/** @var string $right */
return ParagonIE_Sodium_Core_Util::memcmp($left, $right);
}
/**
* It's actually not possible to zero memory buffers in PHP. You
need the
* native library for that.
*
* @param string|null $var
* @param-out string|null $var
*
* @return void
* @throws SodiumException (Unless libsodium is installed)
* @throws TypeError
* @psalm-suppress TooFewArguments
*/
public static function memzero(&$var)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($var,
'string', 1);
if (self::useNewSodiumAPI()) {
/** @psalm-suppress MixedArgument */
sodium_memzero($var);
return;
}
if (self::use_fallback('memzero')) {
$func = '\\Sodium\\memzero';
$func($var);
if ($var === null) {
return;
}
}
// This is the best we can do.
throw new SodiumException(
'This is not implemented in sodium_compat, as it is not
possible to securely wipe memory from PHP. ' .
'To fix this error, make sure libsodium is installed and
the PHP extension is enabled.'
);
}
/**
* @param string $unpadded
* @param int $blockSize
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function pad($unpadded, $blockSize, $dontFallback =
false)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($unpadded,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($blockSize,
'int', 2);
$unpadded = (string) $unpadded;
$blockSize = (int) $blockSize;
if (self::useNewSodiumAPI() && !$dontFallback) {
return (string) sodium_pad($unpadded, $blockSize);
}
if ($blockSize <= 0) {
throw new SodiumException(
'block size cannot be less than 1'
);
}
$unpadded_len = ParagonIE_Sodium_Core_Util::strlen($unpadded);
$xpadlen = ($blockSize - 1);
if (($blockSize & ($blockSize - 1)) === 0) {
$xpadlen -= $unpadded_len & ($blockSize - 1);
} else {
$xpadlen -= $unpadded_len % $blockSize;
}
$xpadded_len = $unpadded_len + $xpadlen;
$padded = str_repeat("\0", $xpadded_len - 1);
if ($unpadded_len > 0) {
$st = 1;
$i = 0;
$k = $unpadded_len;
for ($j = 0; $j <= $xpadded_len; ++$j) {
$i = (int) $i;
$k = (int) $k;
$st = (int) $st;
if ($j >= $unpadded_len) {
$padded[$j] = "\0";
} else {
$padded[$j] = $unpadded[$j];
}
/** @var int $k */
$k -= $st;
$st = (int) (~(
(
(
($k >> 48)
|
($k >> 32)
|
($k >> 16)
|
$k
) - 1
) >> 16
)
) & 1;
$i += $st;
}
}
$mask = 0;
$tail = $xpadded_len;
for ($i = 0; $i < $blockSize; ++$i) {
# barrier_mask = (unsigned char)
# (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) *
CHAR_BIT));
$barrier_mask = (($i ^ $xpadlen) -1) >> ((PHP_INT_SIZE
<< 3) - 1);
# tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
$padded[$tail - $i] = ParagonIE_Sodium_Core_Util::intToChr(
(ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i])
& $mask)
|
(0x80 & $barrier_mask)
);
# mask |= barrier_mask;
$mask |= $barrier_mask;
}
return $padded;
}
/**
* @param string $padded
* @param int $blockSize
* @param bool $dontFallback
* @return string
* @throws SodiumException
*/
public static function unpad($padded, $blockSize, $dontFallback =
false)
{
/* Type checks: */
ParagonIE_Sodium_Core_Util::declareScalarType($padded,
'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($blockSize,
'int', 2);
$padded = (string) $padded;
$blockSize = (int) $blockSize;
if (self::useNewSodiumAPI() && !$dontFallback) {
return (string) sodium_unpad($padded, $blockSize);
}
if ($blockSize <= 0) {
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];
$tail = $padded_len - 1;
$acc = 0;
$valid = 0;
$pad_len = 0;
$found = 0;
for ($i = 0; $i < $blockSize; ++$i) {
# c = tail[-i];
$c = ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]);
# is_barrier =
# (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) -
1U) ) >> 8) & 1U;
$is_barrier = (
(
($acc - 1) & ($pad_len - 1) & (($c ^ 80) - 1)
) >> 7
) & 1;
$is_barrier &= ~$found;
$found |= $is_barrier;
# acc |= c;
$acc |= $c;
# 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;
if ($valid !== 1) {
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?
*
* @return bool
*/
public static function polyfill_is_fast()
{
if (extension_loaded('sodium')) {
return true;
}
if (extension_loaded('libsodium')) {
return true;
}
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).
*
* @param int $numBytes
* @return string
* @throws Exception
* @throws TypeError
*/
public static function randombytes_buf($numBytes)
{
/* Type checks: */
if (!is_int($numBytes)) {
if (is_numeric($numBytes)) {
$numBytes = (int) $numBytes;
} else {
throw new TypeError(
'Argument 1 must be an integer, ' .
gettype($numBytes) . ' given.'
);
}
}
if (self::use_fallback('randombytes_buf')) {
return (string)
call_user_func('\\Sodium\\randombytes_buf', $numBytes);
}
return random_bytes($numBytes);
}
/**
* Generate an integer between 0 and $range (non-inclusive).
*
* @param int $range
* @return int
* @throws Exception
* @throws Error
* @throws TypeError
*/
public static function randombytes_uniform($range)
{
/* Type checks: */
if (!is_int($range)) {
if (is_numeric($range)) {
$range = (int) $range;
} else {
throw new TypeError(
'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.
*
* @return int
* @throws Exception
* @throws Error
* @throws TypeError
*/
public static function randombytes_random16()
{
if (self::use_fallback('randombytes_random16')) {
return (int)
call_user_func('\\Sodium\\randombytes_random16');
}
return random_int(0, 65535);
}
/**
* 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
* performance.
*
* @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()) {
return true;
}
/** @var float $end */
$end = 0.0;
/** @var float $start */
$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));
$a->mulInt64($b);
}
/** @var float $end */
$end = microtime(true);
/** @var int $diff */
$diff = (int) ceil(($end - $start) * 1000);
return $diff < $maxTimeout;
}
/**
* This emulates libsodium's version_string() function, except
ours is
* prefixed with 'polyfill-'.
*
* @return string
* @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
*
* @return bool
*/
protected static function use_fallback($sodium_func_name =
'')
{
static $res = null;
if ($res === null) {
$res = extension_loaded('libsodium') &&
PHP_VERSION_ID >= 50300;
}
if ($res === false) {
// No libsodium installed
return false;
}
if (self::$disableFallbackForUnitTests) {
// Don't fallback. Use the PHP implementation.
return false;
}
if (!empty($sodium_func_name)) {
return is_callable('\\Sodium\\' . $sodium_func_name);
}
return true;
}
/**
* Libsodium as implemented in PHP 7.2
* and/or ext/sodium (via PECL)
*
* @ref https://wiki.php.net/rfc/libsodium
* @return bool
*/
protected static function useNewSodiumAPI()
{
static $res = null;
if ($res === null) {
$res = PHP_VERSION_ID >= 70000 &&
extension_loaded('sodium');
}
if (self::$disableFallbackForUnitTests) {
// Don't fallback. Use the PHP implementation.
return false;
}
return (bool) $res;
}
}
<?php
/**
* Class ParagonIE_Sodium_Core_Base64
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot
com)
*
* We have to copy/paste the contents into the variant files because PHP
5.2
* doesn't support late static binding, and we have no better
workaround
* available that won't break PHP 7+. Therefore, we're forced to
duplicate code.
*/
abstract class ParagonIE_Sodium_Core_Base64_Common
{
/**
* Encode into Base64
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encode($src)
{
return self::doEncode($src, true);
}
/**
* Encode into Base64, no = padding
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encodeUnpadded($src)
{
return self::doEncode($src, false);
}
/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
* @throws TypeError
*/
protected static function doEncode($src, $pad = true)
{
$dest = '';
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
// Main loop (no padding):
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .=
self::encode6Bits( $b0 >> 2 ) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4))
& 63) .
self::encode6Bits((($b1 << 2) | ($b2 >> 6))
& 63) .
self::encode6Bits( $b2 & 63);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .=
self::encode6Bits($b0 >> 2) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4))
& 63) .
self::encode6Bits(($b1 << 2) & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .=
self::encode6Bits( $b0 >> 2) .
self::encode6Bits(($b0 << 4) & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}
/**
* decode from base64 into binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $src
* @param bool $strictPadding
* @return string
* @throws RangeException
* @throws TypeError
* @psalm-suppress RedundantCondition
*/
public static function decode($src, $strictPadding = false)
{
// Remove padding
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
if ($srcLen === 0) {
return '';
}
if ($strictPadding) {
if (($srcLen & 3) === 0) {
if ($src[$srcLen - 1] === '=') {
$srcLen--;
if ($src[$srcLen - 1] === '=') {
$srcLen--;
}
}
}
if (($srcLen & 3) === 1) {
throw new RangeException(
'Incorrect padding'
);
}
if ($src[$srcLen - 1] === '=') {
throw new RangeException(
'Incorrect padding'
);
}
} else {
$src = rtrim($src, '=');
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
}
$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
$c0 = self::decode6Bits($chunk[1]);
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$c3 = self::decode6Bits($chunk[4]);
$dest .= pack(
'CCC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff),
((($c2 << 6) | $c3 ) & 0xff)
);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$c0 = self::decode6Bits($chunk[1]);
if ($i + 2 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$dest .= pack(
'CC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff)
);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$dest .= pack(
'C',
((($c0 << 2) | ($c1 >> 4)) & 0xff)
);
$err |= ($c0 | $c1) >> 8;
} elseif ($i < $srcLen && $strictPadding) {
$err |= 1;
}
}
/** @var bool $check */
$check = ($err === 0);
if (!$check) {
throw new RangeException(
'Base64::decode() only expects characters in the
correct base64 alphabet'
);
}
return $dest;
}
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit
integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
* @param int $src
* @return int
*/
abstract protected static function decode6Bits($src);
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit
integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
abstract protected static function encode6Bits($src);
}
<?php
/**
* Class ParagonIE_Sodium_Core_Base64
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot
com)
*/
class ParagonIE_Sodium_Core_Base64_Original
{
// COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
/**
* Encode into Base64
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encode($src)
{
return self::doEncode($src, true);
}
/**
* Encode into Base64, no = padding
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encodeUnpadded($src)
{
return self::doEncode($src, false);
}
/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
* @throws TypeError
*/
protected static function doEncode($src, $pad = true)
{
$dest = '';
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
// Main loop (no padding):
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .=
self::encode6Bits( $b0 >> 2 ) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4))
& 63) .
self::encode6Bits((($b1 << 2) | ($b2 >> 6))
& 63) .
self::encode6Bits( $b2 & 63);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .=
self::encode6Bits($b0 >> 2) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4))
& 63) .
self::encode6Bits(($b1 << 2) & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .=
self::encode6Bits( $b0 >> 2) .
self::encode6Bits(($b0 << 4) & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}
/**
* decode from base64 into binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $src
* @param bool $strictPadding
* @return string
* @throws RangeException
* @throws TypeError
* @psalm-suppress RedundantCondition
*/
public static function decode($src, $strictPadding = false)
{
// Remove padding
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
if ($srcLen === 0) {
return '';
}
if ($strictPadding) {
if (($srcLen & 3) === 0) {
if ($src[$srcLen - 1] === '=') {
$srcLen--;
if ($src[$srcLen - 1] === '=') {
$srcLen--;
}
}
}
if (($srcLen & 3) === 1) {
throw new RangeException(
'Incorrect padding'
);
}
if ($src[$srcLen - 1] === '=') {
throw new RangeException(
'Incorrect padding'
);
}
} else {
$src = rtrim($src, '=');
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
}
$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
$c0 = self::decode6Bits($chunk[1]);
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$c3 = self::decode6Bits($chunk[4]);
$dest .= pack(
'CCC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff),
((($c2 << 6) | $c3) & 0xff)
);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$c0 = self::decode6Bits($chunk[1]);
if ($i + 2 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$dest .= pack(
'CC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff)
);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$dest .= pack(
'C',
((($c0 << 2) | ($c1 >> 4)) & 0xff)
);
$err |= ($c0 | $c1) >> 8;
} elseif ($i < $srcLen && $strictPadding) {
$err |= 1;
}
}
/** @var bool $check */
$check = ($err === 0);
if (!$check) {
throw new RangeException(
'Base64::decode() only expects characters in the
correct base64 alphabet'
);
}
return $dest;
}
// COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit
integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x40 && $src < 0x5b) $ret += $src -
0x41 + 1; // -64
$ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) &
($src - 64);
// if ($src > 0x60 && $src < 0x7b) $ret += $src -
0x61 + 26 + 1; // -70
$ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) &
($src - 70);
// if ($src > 0x2f && $src < 0x3a) $ret += $src -
0x30 + 52 + 1; // 5
$ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) &
($src + 5);
// if ($src == 0x2b) $ret += 62 + 1;
$ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63;
// if ($src == 0x2f) ret += 63 + 1;
$ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit
integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$diff = 0x41;
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
$diff += ((25 - $src) >> 8) & 6;
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
$diff -= ((51 - $src) >> 8) & 75;
// if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15
$diff -= ((61 - $src) >> 8) & 15;
// if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3
$diff += ((62 - $src) >> 8) & 3;
return pack('C', $src + $diff);
}
}
<?php
/**
* Class ParagonIE_Sodium_Core_Base64UrlSafe
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot
com)
*/
class ParagonIE_Sodium_Core_Base64_UrlSafe
{
// COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
/**
* Encode into Base64
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encode($src)
{
return self::doEncode($src, true);
}
/**
* Encode into Base64, no = padding
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encodeUnpadded($src)
{
return self::doEncode($src, false);
}
/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
* @throws TypeError
*/
protected static function doEncode($src, $pad = true)
{
$dest = '';
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
// Main loop (no padding):
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .=
self::encode6Bits( $b0 >> 2 ) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4))
& 63) .
self::encode6Bits((($b1 << 2) | ($b2 >> 6))
& 63) .
self::encode6Bits( $b2 & 63);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .=
self::encode6Bits($b0 >> 2) .
self::encode6Bits((($b0 << 4) | ($b1 >> 4))
& 63) .
self::encode6Bits(($b1 << 2) & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .=
self::encode6Bits( $b0 >> 2) .
self::encode6Bits(($b0 << 4) & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}
/**
* decode from base64 into binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $src
* @param bool $strictPadding
* @return string
* @throws RangeException
* @throws TypeError
* @psalm-suppress RedundantCondition
*/
public static function decode($src, $strictPadding = false)
{
// Remove padding
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
if ($srcLen === 0) {
return '';
}
if ($strictPadding) {
if (($srcLen & 3) === 0) {
if ($src[$srcLen - 1] === '=') {
$srcLen--;
if ($src[$srcLen - 1] === '=') {
$srcLen--;
}
}
}
if (($srcLen & 3) === 1) {
throw new RangeException(
'Incorrect padding'
);
}
if ($src[$srcLen - 1] === '=') {
throw new RangeException(
'Incorrect padding'
);
}
} else {
$src = rtrim($src, '=');
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
}
$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
$c0 = self::decode6Bits($chunk[1]);
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$c3 = self::decode6Bits($chunk[4]);
$dest .= pack(
'CCC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff),
((($c2 << 6) | $c3) & 0xff)
);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = unpack('C*',
ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$c0 = self::decode6Bits($chunk[1]);
if ($i + 2 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$dest .= pack(
'CC',
((($c0 << 2) | ($c1 >> 4)) & 0xff),
((($c1 << 4) | ($c2 >> 2)) & 0xff)
);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$dest .= pack(
'C',
((($c0 << 2) | ($c1 >> 4)) & 0xff)
);
$err |= ($c0 | $c1) >> 8;
} elseif ($i < $srcLen && $strictPadding) {
$err |= 1;
}
}
/** @var bool $check */
$check = ($err === 0);
if (!$check) {
throw new RangeException(
'Base64::decode() only expects characters in the
correct base64 alphabet'
);
}
return $dest;
}
// COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit
integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x40 && $src < 0x5b) $ret += $src -
0x41 + 1; // -64
$ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) &
($src - 64);
// if ($src > 0x60 && $src < 0x7b) $ret += $src -
0x61 + 26 + 1; // -70
$ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) &
($src - 70);
// if ($src > 0x2f && $src < 0x3a) $ret += $src -
0x30 + 52 + 1; // 5
$ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) &
($src + 5);
// if ($src == 0x2c) $ret += 62 + 1;
$ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63;
// if ($src == 0x5f) ret += 63 + 1;
$ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit
integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$diff = 0x41;
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
$diff += ((25 - $src) >> 8) & 6;
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
$diff -= ((51 - $src) >> 8) & 75;
// if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
$diff -= ((61 - $src) >> 8) & 13;
// if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
$diff += ((62 - $src) >> 8) & 49;
return pack('C', $src + $diff);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_BLAKE2b', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_BLAKE2b
*
* Based on the work of Devi Mandiri in devi/salt.
*/
abstract class ParagonIE_Sodium_Core_BLAKE2b extends
ParagonIE_Sodium_Core_Util
{
/**
* @var SplFixedArray
*/
protected static $iv;
/**
* @var array<int, array<int, int>>
*/
protected static $sigma = array(
array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15),
array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5,
3),
array( 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9,
4),
array( 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15,
8),
array( 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3,
13),
array( 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1,
9),
array( 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8,
11),
array( 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2,
10),
array( 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10,
5),
array( 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 ,
0),
array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15),
array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5,
3)
);
const BLOCKBYTES = 128;
const OUTBYTES = 64;
const KEYBYTES = 64;
/**
* Turn two 32-bit integers into a fixed array representing a 64-bit
integer.
*
* @internal You should not use this directly from another application
*
* @param int $high
* @param int $low
* @return SplFixedArray
* @psalm-suppress MixedAssignment
*/
public static function new64($high, $low)
{
$i64 = new SplFixedArray(2);
$i64[0] = $high & 0xffffffff;
$i64[1] = $low & 0xffffffff;
return $i64;
}
/**
* Convert an arbitrary number into an SplFixedArray of two 32-bit
integers
* that represents a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $num
* @return SplFixedArray
*/
protected static function to64($num)
{
list($hi, $lo) = self::numericTo64BitInteger($num);
return self::new64($hi, $lo);
}
/**
* Adds two 64-bit integers together, returning their sum as a
SplFixedArray
* containing two 32-bit integers (representing a 64-bit integer).
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @return SplFixedArray
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
protected static function add64($x, $y)
{
$l = ($x[1] + $y[1]) & 0xffffffff;
return self::new64(
(int) ($x[0] + $y[0] + (
($l < $x[1]) ? 1 : 0
)),
(int) $l
);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @param SplFixedArray $z
* @return SplFixedArray
*/
protected static function add364($x, $y, $z)
{
return self::add64($x, self::add64($y, $z));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
*/
protected static function xor64(SplFixedArray $x, SplFixedArray $y)
{
if (!is_numeric($x[0])) {
throw new SodiumException('x[0] is not an integer');
}
if (!is_numeric($x[1])) {
throw new SodiumException('x[1] is not an integer');
}
if (!is_numeric($y[0])) {
throw new SodiumException('y[0] is not an integer');
}
if (!is_numeric($y[1])) {
throw new SodiumException('y[1] is not an integer');
}
return self::new64(
(int) (($x[0] ^ $y[0]) & 0xffffffff),
(int) (($x[1] ^ $y[1]) & 0xffffffff)
);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $c
* @return SplFixedArray
* @psalm-suppress MixedAssignment
*/
public static function rotr64($x, $c)
{
if ($c >= 64) {
$c %= 64;
}
if ($c >= 32) {
/** @var int $tmp */
$tmp = $x[0];
$x[0] = $x[1];
$x[1] = $tmp;
$c -= 32;
}
if ($c === 0) {
return $x;
}
$l0 = 0;
$c = 64 - $c;
if ($c < 32) {
/** @var int $h0 */
$h0 = ((int) ($x[0]) << $c) | (
(
(int) ($x[1]) & ((1 << $c) - 1)
<<
(32 - $c)
) >> (32 - $c)
);
/** @var int $l0 */
$l0 = (int) ($x[1]) << $c;
} else {
/** @var int $h0 */
$h0 = (int) ($x[1]) << ($c - 32);
}
$h1 = 0;
$c1 = 64 - $c;
if ($c1 < 32) {
/** @var int $h1 */
$h1 = (int) ($x[0]) >> $c1;
/** @var int $l1 */
$l1 = ((int) ($x[1]) >> $c1) | ((int) ($x[0]) & ((1
<< $c1) - 1)) << (32 - $c1);
} else {
/** @var int $l1 */
$l1 = (int) ($x[0]) >> ($c1 - 32);
}
return self::new64($h0 | $h1, $l0 | $l1);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @return int
* @psalm-suppress MixedOperand
*/
protected static function flatten64($x)
{
return (int) ($x[0] * 4294967296 + $x[1]);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @return SplFixedArray
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayOffset
*/
protected static function load64(SplFixedArray $x, $i)
{
/** @var int $l */
$l = (int) ($x[$i])
| ((int) ($x[$i+1]) << 8)
| ((int) ($x[$i+2]) << 16)
| ((int) ($x[$i+3]) << 24);
/** @var int $h */
$h = (int) ($x[$i+4])
| ((int) ($x[$i+5]) << 8)
| ((int) ($x[$i+6]) << 16)
| ((int) ($x[$i+7]) << 24);
return self::new64($h, $l);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @param SplFixedArray $u
* @return void
* @psalm-suppress MixedAssignment
*/
protected static function store64(SplFixedArray $x, $i, SplFixedArray
$u)
{
$maxLength = $x->getSize() - 1;
for ($j = 0; $j < 8; ++$j) {
/*
[0, 1, 2, 3, 4, 5, 6, 7]
... becomes ...
[0, 0, 0, 0, 1, 1, 1, 1]
*/
/** @var int $uIdx */
$uIdx = ((7 - $j) & 4) >> 2;
$x[$i] = ((int) ($u[$uIdx]) & 0xff);
if (++$i > $maxLength) {
return;
}
/** @psalm-suppress MixedOperand */
$u[$uIdx] >>= 8;
}
}
/**
* This just sets the $iv static variable.
*
* @internal You should not use this directly from another application
*
* @return void
*/
public static function pseudoConstructor()
{
static $called = false;
if ($called) {
return;
}
self::$iv = new SplFixedArray(8);
self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908);
self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b);
self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b);
self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1);
self::$iv[4] = self::new64(0x510e527f, 0xade682d1);
self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f);
self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b);
self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179);
$called = true;
}
/**
* Returns a fresh BLAKE2 context.
*
* @internal You should not use this directly from another application
*
* @return SplFixedArray
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
protected static function context()
{
$ctx = new SplFixedArray(6);
$ctx[0] = new SplFixedArray(8); // h
$ctx[1] = new SplFixedArray(2); // t
$ctx[2] = new SplFixedArray(2); // f
$ctx[3] = new SplFixedArray(256); // buf
$ctx[4] = 0; // buflen
$ctx[5] = 0; // last_node (uint8_t)
for ($i = 8; $i--;) {
$ctx[0][$i] = self::$iv[$i];
}
for ($i = 256; $i--;) {
$ctx[3][$i] = 0;
}
$zero = self::new64(0, 0);
$ctx[1][0] = $zero;
$ctx[1][1] = $zero;
$ctx[2][0] = $zero;
$ctx[2][1] = $zero;
return $ctx;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $buf
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
protected static function compress(SplFixedArray $ctx, SplFixedArray
$buf)
{
$m = new SplFixedArray(16);
$v = new SplFixedArray(16);
for ($i = 16; $i--;) {
$m[$i] = self::load64($buf, $i << 3);
}
for ($i = 8; $i--;) {
$v[$i] = $ctx[0][$i];
}
$v[ 8] = self::$iv[0];
$v[ 9] = self::$iv[1];
$v[10] = self::$iv[2];
$v[11] = self::$iv[3];
$v[12] = self::xor64($ctx[1][0], self::$iv[4]);
$v[13] = self::xor64($ctx[1][1], self::$iv[5]);
$v[14] = self::xor64($ctx[2][0], self::$iv[6]);
$v[15] = self::xor64($ctx[2][1], self::$iv[7]);
for ($r = 0; $r < 12; ++$r) {
$v = self::G($r, 0, 0, 4, 8, 12, $v, $m);
$v = self::G($r, 1, 1, 5, 9, 13, $v, $m);
$v = self::G($r, 2, 2, 6, 10, 14, $v, $m);
$v = self::G($r, 3, 3, 7, 11, 15, $v, $m);
$v = self::G($r, 4, 0, 5, 10, 15, $v, $m);
$v = self::G($r, 5, 1, 6, 11, 12, $v, $m);
$v = self::G($r, 6, 2, 7, 8, 13, $v, $m);
$v = self::G($r, 7, 3, 4, 9, 14, $v, $m);
}
for ($i = 8; $i--;) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i], self::xor64($v[$i], $v[$i+8])
);
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $r
* @param int $i
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @param SplFixedArray $v
* @param SplFixedArray $m
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayOffset
*/
public static function G($r, $i, $a, $b, $c, $d, SplFixedArray $v,
SplFixedArray $m)
{
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i
<< 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24);
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i
<< 1) + 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param int $inc
* @return void
* @throws SodiumException
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
public static function increment_counter($ctx, $inc)
{
if ($inc < 0) {
throw new SodiumException('Increasing by a negative number
makes no sense.');
}
$t = self::to64($inc);
# S->t is $ctx[1] in our implementation
# S->t[0] = ( uint64_t )( t >> 0 );
$ctx[1][0] = self::add64($ctx[1][0], $t);
# S->t[1] += ( S->t[0] < inc );
if (self::flatten64($ctx[1][0]) < $inc) {
$ctx[1][1] = self::add64($ctx[1][1], self::to64(1));
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $p
* @param int $plen
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedOperand
*/
public static function update(SplFixedArray $ctx, SplFixedArray $p,
$plen)
{
self::pseudoConstructor();
$offset = 0;
while ($plen > 0) {
$left = $ctx[4];
$fill = 256 - $left;
if ($plen > $fill) {
# memcpy( S->buf + left, in, fill ); /* Fill buffer */
for ($i = $fill; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
# S->buflen += fill;
$ctx[4] += $fill;
# blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
self::increment_counter($ctx, 128);
# blake2b_compress( S, S->buf ); /* Compress */
self::compress($ctx, $ctx[3]);
# memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES,
BLAKE2B_BLOCKBYTES ); /* Shift buffer left */
for ($i = 128; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
# S->buflen -= BLAKE2B_BLOCKBYTES;
$ctx[4] -= 128;
# in += fill;
$offset += $fill;
# inlen -= fill;
$plen -= $fill;
} else {
for ($i = $plen; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
$ctx[4] += $plen;
$offset += $plen;
$plen -= $plen;
}
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $out
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedOperand
*/
public static function finish(SplFixedArray $ctx, SplFixedArray $out)
{
self::pseudoConstructor();
if ($ctx[4] > 128) {
self::increment_counter($ctx, 128);
self::compress($ctx, $ctx[3]);
$ctx[4] -= 128;
if ($ctx[4] > 128) {
throw new SodiumException('Failed to assert that
buflen <= 128 bytes');
}
for ($i = $ctx[4]; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
}
self::increment_counter($ctx, $ctx[4]);
$ctx[2][0] = self::new64(0xffffffff, 0xffffffff);
for ($i = 256 - $ctx[4]; $i--;) {
$ctx[3][$i+$ctx[4]] = 0;
}
self::compress($ctx, $ctx[3]);
$i = (int) (($out->getSize() - 1) / 8);
for (; $i >= 0; --$i) {
self::store64($out, $i << 3, $ctx[0][$i]);
}
return $out;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray|null $key
* @param int $outlen
* @param SplFixedArray|null $salt
* @param SplFixedArray|null $personal
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
public static function init(
$key = null,
$outlen = 64,
$salt = null,
$personal = null
) {
self::pseudoConstructor();
$klen = 0;
if ($key !== null) {
if (count($key) > 64) {
throw new SodiumException('Invalid key size');
}
$klen = count($key);
}
if ($outlen > 64) {
throw new SodiumException('Invalid output size');
}
$ctx = self::context();
$p = new SplFixedArray(64);
// Zero our param buffer...
for ($i = 64; --$i;) {
$p[$i] = 0;
}
$p[0] = $outlen; // digest_length
$p[1] = $klen; // key_length
$p[2] = 1; // fanout
$p[3] = 1; // depth
if ($salt instanceof SplFixedArray) {
// salt: [32] through [47]
for ($i = 0; $i < 16; ++$i) {
$p[32 + $i] = (int) $salt[$i];
}
}
if ($personal instanceof SplFixedArray) {
// personal: [48] through [63]
for ($i = 0; $i < 16; ++$i) {
$p[48 + $i] = (int) $personal[$i];
}
}
$ctx[0][0] = self::xor64(
$ctx[0][0],
self::load64($p, 0)
);
if ($salt instanceof SplFixedArray || $personal instanceof
SplFixedArray) {
// We need to do what blake2b_init_param() does:
for ($i = 1; $i < 8; ++$i) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i],
self::load64($p, $i << 3)
);
}
}
if ($klen > 0 && $key instanceof SplFixedArray) {
$block = new SplFixedArray(128);
for ($i = 128; $i--;) {
$block[$i] = 0;
}
for ($i = $klen; $i--;) {
$block[$i] = $key[$i];
}
self::update($ctx, $block, 128);
$ctx[4] = 128;
}
return $ctx;
}
/**
* Convert a string into an SplFixedArray of integers
*
* @internal You should not use this directly from another application
*
* @param string $str
* @return SplFixedArray
*/
public static function stringToSplFixedArray($str = '')
{
$values = unpack('C*', $str);
return SplFixedArray::fromArray(array_values($values));
}
/**
* Convert an SplFixedArray of integers into a string
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $a
* @return string
* @throws TypeError
*/
public static function SplFixedArrayToString(SplFixedArray $a)
{
/**
* @var array<int, int|string> $arr
*/
$arr = $a->toArray();
$c = $a->count();
array_unshift($arr, str_repeat('C', $c));
return (string) (call_user_func_array('pack', $arr));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @return string
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedMethodCall
*/
public static function contextToString(SplFixedArray $ctx)
{
$str = '';
/** @var array<int, array<int, int>> $ctxA */
$ctxA = $ctx[0]->toArray();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$str .= self::store32_le($ctxA[$i][1]);
$str .= self::store32_le($ctxA[$i][0]);
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctxA = $ctx[$i]->toArray();
$str .= self::store32_le($ctxA[0][1]);
$str .= self::store32_le($ctxA[0][0]);
$str .= self::store32_le($ctxA[1][1]);
$str .= self::store32_le($ctxA[1][0]);
}
# uint8_t buf[2 * 128];
$str .= self::SplFixedArrayToString($ctx[3]);
/** @var int $ctx4 */
$ctx4 = (int) $ctx[4];
# size_t buflen;
$str .= implode('', array(
self::intToChr($ctx4 & 0xff),
self::intToChr(($ctx4 >> 8) & 0xff),
self::intToChr(($ctx4 >> 16) & 0xff),
self::intToChr(($ctx4 >> 24) & 0xff),
self::intToChr(($ctx4 >> 32) & 0xff),
self::intToChr(($ctx4 >> 40) & 0xff),
self::intToChr(($ctx4 >> 48) & 0xff),
self::intToChr(($ctx4 >> 56) & 0xff)
));
# uint8_t last_node;
return $str . self::intToChr($ctx[5]) .
str_repeat("\x00", 23);
}
/**
* Creates an SplFixedArray containing other SplFixedArray elements,
from
* a string (compatible with \Sodium\crypto_generichash_{init, update,
final})
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAssignment
*/
public static function stringToContext($string)
{
$ctx = self::context();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$ctx[0][$i] = SplFixedArray::fromArray(
array(
self::load_4(
self::substr($string, (($i << 3) + 4), 4)
),
self::load_4(
self::substr($string, (($i << 3) + 0), 4)
)
)
);
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctx[$i][1] = SplFixedArray::fromArray(
array(
self::load_4(self::substr($string, 76 + (($i - 1)
<< 4), 4)),
self::load_4(self::substr($string, 72 + (($i - 1)
<< 4), 4))
)
);
$ctx[$i][0] = SplFixedArray::fromArray(
array(
self::load_4(self::substr($string, 68 + (($i - 1)
<< 4), 4)),
self::load_4(self::substr($string, 64 + (($i - 1)
<< 4), 4))
)
);
}
# uint8_t buf[2 * 128];
$ctx[3] = self::stringToSplFixedArray(self::substr($string, 96,
256));
# uint8_t buf[2 * 128];
$int = 0;
for ($i = 0; $i < 8; ++$i) {
$int |= self::chrToInt($string[352 + $i]) << ($i <<
3);
}
$ctx[4] = $int;
return $ctx;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_Ctx
*/
class ParagonIE_Sodium_Core_ChaCha20_Ctx extends ParagonIE_Sodium_Core_Util
implements ArrayAccess
{
/**
* @var SplFixedArray internally, <int, int>
*/
protected $container;
/**
* ParagonIE_Sodium_Core_ChaCha20_Ctx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 8 0x00 bytes.
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '', $iv = '',
$counter = '')
{
if (self::strlen($key) !== 32) {
throw new InvalidArgumentException('ChaCha20 expects a
256-bit key.');
}
if (self::strlen($iv) !== 8) {
throw new InvalidArgumentException('ChaCha20 expects a
64-bit nonce.');
}
$this->container = new SplFixedArray(16);
/* "expand 32-byte k" as per ChaCha20 spec */
$this->container[0] = 0x61707865;
$this->container[1] = 0x3320646e;
$this->container[2] = 0x79622d32;
$this->container[3] = 0x6b206574;
$this->container[4] = self::load_4(self::substr($key, 0, 4));
$this->container[5] = self::load_4(self::substr($key, 4, 4));
$this->container[6] = self::load_4(self::substr($key, 8, 4));
$this->container[7] = self::load_4(self::substr($key, 12, 4));
$this->container[8] = self::load_4(self::substr($key, 16, 4));
$this->container[9] = self::load_4(self::substr($key, 20, 4));
$this->container[10] = self::load_4(self::substr($key, 24, 4));
$this->container[11] = self::load_4(self::substr($key, 28, 4));
if (empty($counter)) {
$this->container[12] = 0;
$this->container[13] = 0;
} else {
$this->container[12] = self::load_4(self::substr($counter,
0, 4));
$this->container[13] = self::load_4(self::substr($counter,
4, 4));
}
$this->container[14] = self::load_4(self::substr($iv, 0, 4));
$this->container[15] = self::load_4(self::substr($iv, 4, 4));
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @param int $value
* @return void
* @psalm-suppress MixedArrayOffset
*/
public function offsetSet($offset, $value)
{
if (!is_int($offset)) {
throw new InvalidArgumentException('Expected an
integer');
}
if (!is_int($value)) {
throw new InvalidArgumentException('Expected an
integer');
}
$this->container[$offset] = $value;
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return mixed|null
* @psalm-suppress MixedArrayOffset
*/
public function offsetGet($offset)
{
return isset($this->container[$offset])
? $this->container[$offset]
: null;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_IetfCtx
*/
class ParagonIE_Sodium_Core_ChaCha20_IetfCtx extends
ParagonIE_Sodium_Core_ChaCha20_Ctx
{
/**
* ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 4 0x00 bytes.
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '', $iv = '',
$counter = '')
{
if (self::strlen($iv) !== 12) {
throw new InvalidArgumentException('ChaCha20 expects a
96-bit nonce in IETF mode.');
}
parent::__construct($key, self::substr($iv, 0, 8), $counter);
if (!empty($counter)) {
$this->container[12] = self::load_4(self::substr($counter,
0, 4));
}
$this->container[13] = self::load_4(self::substr($iv, 0, 4));
$this->container[14] = self::load_4(self::substr($iv, 4, 4));
$this->container[15] = self::load_4(self::substr($iv, 8, 4));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20
*/
class ParagonIE_Sodium_Core_ChaCha20 extends ParagonIE_Sodium_Core_Util
{
/**
* Bitwise left rotation
*
* @internal You should not use this directly from another application
*
* @param int $v
* @param int $n
* @return int
*/
public static function rotate($v, $n)
{
$v &= 0xffffffff;
$n &= 31;
return (int) (
0xffffffff & (
($v << $n)
|
($v >> (32 - $n))
)
);
}
/**
* The ChaCha20 quarter round function. Works on four 32-bit integers.
*
* @internal You should not use this directly from another application
*
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @return array<int, int>
*/
protected static function quarterRound($a, $b, $c, $d)
{
# a = PLUS(a,b); d = ROTATE(XOR(d,a),16);
/** @var int $a */
$a = ($a + $b) & 0xffffffff;
$d = self::rotate($d ^ $a, 16);
# c = PLUS(c,d); b = ROTATE(XOR(b,c),12);
/** @var int $c */
$c = ($c + $d) & 0xffffffff;
$b = self::rotate($b ^ $c, 12);
# a = PLUS(a,b); d = ROTATE(XOR(d,a), 8);
/** @var int $a */
$a = ($a + $b) & 0xffffffff;
$d = self::rotate($d ^ $a, 8);
# c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
/** @var int $c */
$c = ($c + $d) & 0xffffffff;
$b = self::rotate($b ^ $c, 7);
return array((int) $a, (int) $b, (int) $c, (int) $d);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx
* @param string $message
*
* @return string
* @throws TypeError
* @throws SodiumException
*/
public static function encryptBytes(
ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx,
$message = ''
) {
$bytes = self::strlen($message);
/*
j0 = ctx->input[0];
j1 = ctx->input[1];
j2 = ctx->input[2];
j3 = ctx->input[3];
j4 = ctx->input[4];
j5 = ctx->input[5];
j6 = ctx->input[6];
j7 = ctx->input[7];
j8 = ctx->input[8];
j9 = ctx->input[9];
j10 = ctx->input[10];
j11 = ctx->input[11];
j12 = ctx->input[12];
j13 = ctx->input[13];
j14 = ctx->input[14];
j15 = ctx->input[15];
*/
$j0 = (int) $ctx[0];
$j1 = (int) $ctx[1];
$j2 = (int) $ctx[2];
$j3 = (int) $ctx[3];
$j4 = (int) $ctx[4];
$j5 = (int) $ctx[5];
$j6 = (int) $ctx[6];
$j7 = (int) $ctx[7];
$j8 = (int) $ctx[8];
$j9 = (int) $ctx[9];
$j10 = (int) $ctx[10];
$j11 = (int) $ctx[11];
$j12 = (int) $ctx[12];
$j13 = (int) $ctx[13];
$j14 = (int) $ctx[14];
$j15 = (int) $ctx[15];
$c = '';
for (;;) {
if ($bytes < 64) {
$message .= str_repeat("\x00", 64 - $bytes);
}
$x0 = (int) $j0;
$x1 = (int) $j1;
$x2 = (int) $j2;
$x3 = (int) $j3;
$x4 = (int) $j4;
$x5 = (int) $j5;
$x6 = (int) $j6;
$x7 = (int) $j7;
$x8 = (int) $j8;
$x9 = (int) $j9;
$x10 = (int) $j10;
$x11 = (int) $j11;
$x12 = (int) $j12;
$x13 = (int) $j13;
$x14 = (int) $j14;
$x15 = (int) $j15;
# for (i = 20; i > 0; i -= 2) {
for ($i = 20; $i > 0; $i -= 2) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4,
$x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5,
$x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6,
$x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7,
$x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5,
$x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6,
$x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7,
$x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4,
$x9, $x14);
}
/*
x0 = PLUS(x0, j0);
x1 = PLUS(x1, j1);
x2 = PLUS(x2, j2);
x3 = PLUS(x3, j3);
x4 = PLUS(x4, j4);
x5 = PLUS(x5, j5);
x6 = PLUS(x6, j6);
x7 = PLUS(x7, j7);
x8 = PLUS(x8, j8);
x9 = PLUS(x9, j9);
x10 = PLUS(x10, j10);
x11 = PLUS(x11, j11);
x12 = PLUS(x12, j12);
x13 = PLUS(x13, j13);
x14 = PLUS(x14, j14);
x15 = PLUS(x15, j15);
*/
/** @var int $x0 */
$x0 = ($x0 & 0xffffffff) + $j0;
/** @var int $x1 */
$x1 = ($x1 & 0xffffffff) + $j1;
/** @var int $x2 */
$x2 = ($x2 & 0xffffffff) + $j2;
/** @var int $x3 */
$x3 = ($x3 & 0xffffffff) + $j3;
/** @var int $x4 */
$x4 = ($x4 & 0xffffffff) + $j4;
/** @var int $x5 */
$x5 = ($x5 & 0xffffffff) + $j5;
/** @var int $x6 */
$x6 = ($x6 & 0xffffffff) + $j6;
/** @var int $x7 */
$x7 = ($x7 & 0xffffffff) + $j7;
/** @var int $x8 */
$x8 = ($x8 & 0xffffffff) + $j8;
/** @var int $x9 */
$x9 = ($x9 & 0xffffffff) + $j9;
/** @var int $x10 */
$x10 = ($x10 & 0xffffffff) + $j10;
/** @var int $x11 */
$x11 = ($x11 & 0xffffffff) + $j11;
/** @var int $x12 */
$x12 = ($x12 & 0xffffffff) + $j12;
/** @var int $x13 */
$x13 = ($x13 & 0xffffffff) + $j13;
/** @var int $x14 */
$x14 = ($x14 & 0xffffffff) + $j14;
/** @var int $x15 */
$x15 = ($x15 & 0xffffffff) + $j15;
/*
x0 = XOR(x0, LOAD32_LE(m + 0));
x1 = XOR(x1, LOAD32_LE(m + 4));
x2 = XOR(x2, LOAD32_LE(m + 8));
x3 = XOR(x3, LOAD32_LE(m + 12));
x4 = XOR(x4, LOAD32_LE(m + 16));
x5 = XOR(x5, LOAD32_LE(m + 20));
x6 = XOR(x6, LOAD32_LE(m + 24));
x7 = XOR(x7, LOAD32_LE(m + 28));
x8 = XOR(x8, LOAD32_LE(m + 32));
x9 = XOR(x9, LOAD32_LE(m + 36));
x10 = XOR(x10, LOAD32_LE(m + 40));
x11 = XOR(x11, LOAD32_LE(m + 44));
x12 = XOR(x12, LOAD32_LE(m + 48));
x13 = XOR(x13, LOAD32_LE(m + 52));
x14 = XOR(x14, LOAD32_LE(m + 56));
x15 = XOR(x15, LOAD32_LE(m + 60));
*/
$x0 ^= self::load_4(self::substr($message, 0, 4));
$x1 ^= self::load_4(self::substr($message, 4, 4));
$x2 ^= self::load_4(self::substr($message, 8, 4));
$x3 ^= self::load_4(self::substr($message, 12, 4));
$x4 ^= self::load_4(self::substr($message, 16, 4));
$x5 ^= self::load_4(self::substr($message, 20, 4));
$x6 ^= self::load_4(self::substr($message, 24, 4));
$x7 ^= self::load_4(self::substr($message, 28, 4));
$x8 ^= self::load_4(self::substr($message, 32, 4));
$x9 ^= self::load_4(self::substr($message, 36, 4));
$x10 ^= self::load_4(self::substr($message, 40, 4));
$x11 ^= self::load_4(self::substr($message, 44, 4));
$x12 ^= self::load_4(self::substr($message, 48, 4));
$x13 ^= self::load_4(self::substr($message, 52, 4));
$x14 ^= self::load_4(self::substr($message, 56, 4));
$x15 ^= self::load_4(self::substr($message, 60, 4));
/*
j12 = PLUSONE(j12);
if (!j12) {
j13 = PLUSONE(j13);
}
*/
++$j12;
if ($j12 & 0xf0000000) {
throw new SodiumException('Overflow');
}
/*
STORE32_LE(c + 0, x0);
STORE32_LE(c + 4, x1);
STORE32_LE(c + 8, x2);
STORE32_LE(c + 12, x3);
STORE32_LE(c + 16, x4);
STORE32_LE(c + 20, x5);
STORE32_LE(c + 24, x6);
STORE32_LE(c + 28, x7);
STORE32_LE(c + 32, x8);
STORE32_LE(c + 36, x9);
STORE32_LE(c + 40, x10);
STORE32_LE(c + 44, x11);
STORE32_LE(c + 48, x12);
STORE32_LE(c + 52, x13);
STORE32_LE(c + 56, x14);
STORE32_LE(c + 60, x15);
*/
$block = self::store32_le((int) ($x0 & 0xffffffff)) .
self::store32_le((int) ($x1 & 0xffffffff)) .
self::store32_le((int) ($x2 & 0xffffffff)) .
self::store32_le((int) ($x3 & 0xffffffff)) .
self::store32_le((int) ($x4 & 0xffffffff)) .
self::store32_le((int) ($x5 & 0xffffffff)) .
self::store32_le((int) ($x6 & 0xffffffff)) .
self::store32_le((int) ($x7 & 0xffffffff)) .
self::store32_le((int) ($x8 & 0xffffffff)) .
self::store32_le((int) ($x9 & 0xffffffff)) .
self::store32_le((int) ($x10 & 0xffffffff)) .
self::store32_le((int) ($x11 & 0xffffffff)) .
self::store32_le((int) ($x12 & 0xffffffff)) .
self::store32_le((int) ($x13 & 0xffffffff)) .
self::store32_le((int) ($x14 & 0xffffffff)) .
self::store32_le((int) ($x15 & 0xffffffff));
/* Partial block */
if ($bytes < 64) {
$c .= self::substr($block, 0, $bytes);
break;
}
/* Full block */
$c .= $block;
$bytes -= 64;
if ($bytes <= 0) {
break;
}
$message = self::substr($message, 64);
}
/* end for(;;) loop */
$ctx[12] = $j12;
$ctx[13] = $j13;
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key =
'')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStream($len, $nonce = '', $key =
'')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '',
$key = '', $ic = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce, $ic),
$message
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '',
$key = '', $ic = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce, $ic),
$message
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Fe', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Fe
*
* This represents a Field Element
*/
class ParagonIE_Sodium_Core_Curve25519_Fe implements ArrayAccess
{
/**
* @var array<int, int>
*/
protected $container = array();
/**
* @var int
*/
protected $size = 10;
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @param bool $save_indexes
* @return self
*/
public static function fromArray($array, $save_indexes = null)
{
$count = count($array);
if ($save_indexes) {
$keys = array_keys($array);
} else {
$keys = range(0, $count - 1);
}
$array = array_values($array);
/** @var array<int, int> $keys */
$obj = new ParagonIE_Sodium_Core_Curve25519_Fe();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($keys[$i], $array[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($i, $array[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param int|null $offset
* @param int $value
* @return void
* @psalm-suppress MixedArrayOffset
*/
public function offsetSet($offset, $value)
{
if (!is_int($value)) {
throw new InvalidArgumentException('Expected an
integer');
}
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
* @psalm-suppress MixedArrayOffset
*/
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return int
* @psalm-suppress MixedArrayOffset
*/
public function offsetGet($offset)
{
if (!isset($this->container[$offset])) {
$this->container[$offset] = 0;
}
return (int) ($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
return array(implode(', ', $this->container));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Cached',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Cached
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_Cached
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $YplusX;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $YminusX;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $T2d;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_Cached constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YplusX
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YminusX
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $Z
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $T2d
*/
public function __construct(
ParagonIE_Sodium_Core_Curve25519_Fe $YplusX = null,
ParagonIE_Sodium_Core_Curve25519_Fe $YminusX = null,
ParagonIE_Sodium_Core_Curve25519_Fe $Z = null,
ParagonIE_Sodium_Core_Curve25519_Fe $T2d = null
) {
if ($YplusX === null) {
$YplusX = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->YplusX = $YplusX;
if ($YminusX === null) {
$YminusX = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->YminusX = $YminusX;
if ($Z === null) {
$Z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Z = $Z;
if ($T2d === null) {
$T2d = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->T2d = $T2d;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P1p1',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t
*/
public function __construct(
ParagonIE_Sodium_Core_Curve25519_Fe $x = null,
ParagonIE_Sodium_Core_Curve25519_Fe $y = null,
ParagonIE_Sodium_Core_Curve25519_Fe $z = null,
ParagonIE_Sodium_Core_Curve25519_Fe $t = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Z = $z;
if ($t === null) {
$t = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->T = $t;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P2',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P2
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P2 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z
*/
public function __construct(
ParagonIE_Sodium_Core_Curve25519_Fe $x = null,
ParagonIE_Sodium_Core_Curve25519_Fe $y = null,
ParagonIE_Sodium_Core_Curve25519_Fe $z = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Z = $z;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P3',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P3
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P3 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t
*/
public function __construct(
ParagonIE_Sodium_Core_Curve25519_Fe $x = null,
ParagonIE_Sodium_Core_Curve25519_Fe $y = null,
ParagonIE_Sodium_Core_Curve25519_Fe $z = null,
ParagonIE_Sodium_Core_Curve25519_Fe $t = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Z = $z;
if ($t === null) {
$t = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->T = $t;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Precomp',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $yplusx;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $yminusx;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $xy2d;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_Precomp constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $yplusx
* @param ParagonIE_Sodium_Core_Curve25519_Fe $yminusx
* @param ParagonIE_Sodium_Core_Curve25519_Fe $xy2d
*/
public function __construct(
ParagonIE_Sodium_Core_Curve25519_Fe $yplusx = null,
ParagonIE_Sodium_Core_Curve25519_Fe $yminusx = null,
ParagonIE_Sodium_Core_Curve25519_Fe $xy2d = null
) {
if ($yplusx === null) {
$yplusx = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->yplusx = $yplusx;
if ($yminusx === null) {
$yminusx = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->yminusx = $yminusx;
if ($xy2d === null) {
$xy2d = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->xy2d = $xy2d;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519_H', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_H
*
* This just contains the constants in the ref10/base.h file
*/
class ParagonIE_Sodium_Core_Curve25519_H extends ParagonIE_Sodium_Core_Util
{
/**
* See: libsodium's crypto_core/curve25519/ref10/base.h
*
* @var array<int, array<int, array<int, array<int,
int>>>> Basically, int[32][8][3][10]
*/
protected static $base = array(
array(
array(
array(25967493, -14356035, 29566456, 3660896, -12694345,
4014787, 27544626, -11754271, -6079156, 2047605),
array(-12545711, 934262, -2722910, 3049990, -727428,
9406986, 12720692, 5043384, 19500929, -15469378),
array(-8738181, 4489570, 9688441, -14785194, 10184609,
-12363380, 29287919, 11864899, -24514362, -4438546),
),
array(
array(-12815894, -12976347, -21581243, 11784320, -25355658,
-2750717, -11717903, -3814571, -358445, -10211303),
array(-21703237, 6903825, 27185491, 6451973, -29577724,
-9554005, -15616551, 11189268, -26829678, -5319081),
array(26966642, 11152617, 32442495, 15396054, 14353839,
-12752335, -3128826, -9541118, -15472047, -4166697),
),
array(
array(15636291, -9688557, 24204773, -7912398, 616977,
-16685262, 27787600, -14772189, 28944400, -1550024),
array(16568933, 4717097, -11556148, -1102322, 15682896,
-11807043, 16354577, -11775962, 7689662, 11199574),
array(30464156, -5976125, -11779434, -15670865, 23220365,
15915852, 7512774, 10017326, -17749093, -9920357),
),
array(
array(-17036878, 13921892, 10945806, -6033431, 27105052,
-16084379, -28926210, 15006023, 3284568, -6276540),
array(23599295, -8306047, -11193664, -7687416, 13236774,
10506355, 7464579, 9656445, 13059162, 10374397),
array(7798556, 16710257, 3033922, 2874086, 28997861,
2835604, 32406664, -3839045, -641708, -101325),
),
array(
array(10861363, 11473154, 27284546, 1981175, -30064349,
12577861, 32867885, 14515107, -15438304, 10819380),
array(4708026, 6336745, 20377586, 9066809, -11272109,
6594696, -25653668, 12483688, -12668491, 5581306),
array(19563160, 16186464, -29386857, 4097519, 10237984,
-4348115, 28542350, 13850243, -23678021, -15815942),
),
array(
array(-15371964, -12862754, 32573250, 4720197, -26436522,
5875511, -19188627, -15224819, -9818940, -12085777),
array(-8549212, 109983, 15149363, 2178705, 22900618,
4543417, 3044240, -15689887, 1762328, 14866737),
array(-18199695, -15951423, -10473290, 1707278, -17185920,
3916101, -28236412, 3959421, 27914454, 4383652),
),
array(
array(5153746, 9909285, 1723747, -2777874, 30523605,
5516873, 19480852, 5230134, -23952439, -15175766),
array(-30269007, -3463509, 7665486, 10083793, 28475525,
1649722, 20654025, 16520125, 30598449, 7715701),
array(28881845, 14381568, 9657904, 3680757, -20181635,
7843316, -31400660, 1370708, 29794553, -1409300),
),
array(
array(14499471, -2729599, -33191113, -4254652, 28494862,
14271267, 30290735, 10876454, -33154098, 2381726),
array(-7195431, -2655363, -14730155, 462251, -27724326,
3941372, -6236617, 3696005, -32300832, 15351955),
array(27431194, 8222322, 16448760, -3907995, -18707002,
11938355, -32961401, -2970515, 29551813, 10109425),
),
),
array(
array(
array(-13657040, -13155431, -31283750, 11777098, 21447386,
6519384, -2378284, -1627556, 10092783, -4764171),
array(27939166, 14210322, 4677035, 16277044, -22964462,
-12398139, -32508754, 12005538, -17810127, 12803510),
array(17228999, -15661624, -1233527, 300140, -1224870,
-11714777, 30364213, -9038194, 18016357, 4397660),
),
array(
array(-10958843, -7690207, 4776341, -14954238, 27850028,
-15602212, -26619106, 14544525, -17477504, 982639),
array(29253598, 15796703, -2863982, -9908884, 10057023,
3163536, 7332899, -4120128, -21047696, 9934963),
array(5793303, 16271923, -24131614, -10116404, 29188560,
1206517, -14747930, 4559895, -30123922, -10897950),
),
array(
array(-27643952, -11493006, 16282657, -11036493, 28414021,
-15012264, 24191034, 4541697, -13338309, 5500568),
array(12650548, -1497113, 9052871, 11355358, -17680037,
-8400164, -17430592, 12264343, 10874051, 13524335),
array(25556948, -3045990, 714651, 2510400, 23394682,
-10415330, 33119038, 5080568, -22528059, 5376628),
),
array(
array(-26088264, -4011052, -17013699, -3537628, -6726793,
1920897, -22321305, -9447443, 4535768, 1569007),
array(-2255422, 14606630, -21692440, -8039818, 28430649,
8775819, -30494562, 3044290, 31848280, 12543772),
array(-22028579, 2943893, -31857513, 6777306, 13784462,
-4292203, -27377195, -2062731, 7718482, 14474653),
),
array(
array(2385315, 2454213, -22631320, 46603, -4437935,
-15680415, 656965, -7236665, 24316168, -5253567),
array(13741529, 10911568, -33233417, -8603737, -20177830,
-1033297, 33040651, -13424532, -20729456, 8321686),
array(21060490, -2212744, 15712757, -4336099, 1639040,
10656336, 23845965, -11874838, -9984458, 608372),
),
array(
array(-13672732, -15087586, -10889693, -7557059, -6036909,
11305547, 1123968, -6780577, 27229399, 23887),
array(-23244140, -294205, -11744728, 14712571, -29465699,
-2029617, 12797024, -6440308, -1633405, 16678954),
array(-29500620, 4770662, -16054387, 14001338, 7830047,
9564805, -1508144, -4795045, -17169265, 4904953),
),
array(
array(24059557, 14617003, 19037157, -15039908, 19766093,
-14906429, 5169211, 16191880, 2128236, -4326833),
array(-16981152, 4124966, -8540610, -10653797, 30336522,
-14105247, -29806336, 916033, -6882542, -2986532),
array(-22630907, 12419372, -7134229, -7473371, -16478904,
16739175, 285431, 2763829, 15736322, 4143876),
),
array(
array(2379352, 11839345, -4110402, -5988665, 11274298,
794957, 212801, -14594663, 23527084, -16458268),
array(33431127, -11130478, -17838966, -15626900, 8909499,
8376530, -32625340, 4087881, -15188911, -14416214),
array(1767683, 7197987, -13205226, -2022635, -13091350,
448826, 5799055, 4357868, -4774191, -16323038),
),
),
array(
array(
array(6721966, 13833823, -23523388, -1551314, 26354293,
-11863321, 23365147, -3949732, 7390890, 2759800),
array(4409041, 2052381, 23373853, 10530217, 7676779,
-12885954, 21302353, -4264057, 1244380, -12919645),
array(-4421239, 7169619, 4982368, -2957590, 30256825,
-2777540, 14086413, 9208236, 15886429, 16489664),
),
array(
array(1996075, 10375649, 14346367, 13311202, -6874135,
-16438411, -13693198, 398369, -30606455, -712933),
array(-25307465, 9795880, -2777414, 14878809, -33531835,
14780363, 13348553, 12076947, -30836462, 5113182),
array(-17770784, 11797796, 31950843, 13929123, -25888302,
12288344, -30341101, -7336386, 13847711, 5387222),
),
array(
array(-18582163, -3416217, 17824843, -2340966, 22744343,
-10442611, 8763061, 3617786, -19600662, 10370991),
array(20246567, -14369378, 22358229, -543712, 18507283,
-10413996, 14554437, -8746092, 32232924, 16763880),
array(9648505, 10094563, 26416693, 14745928, -30374318,
-6472621, 11094161, 15689506, 3140038, -16510092),
),
array(
array(-16160072, 5472695, 31895588, 4744994, 8823515,
10365685, -27224800, 9448613, -28774454, 366295),
array(19153450, 11523972, -11096490, -6503142, -24647631,
5420647, 28344573, 8041113, 719605, 11671788),
array(8678025, 2694440, -6808014, 2517372, 4964326,
11152271, -15432916, -15266516, 27000813, -10195553),
),
array(
array(-15157904, 7134312, 8639287, -2814877, -7235688,
10421742, 564065, 5336097, 6750977, -14521026),
array(11836410, -3979488, 26297894, 16080799, 23455045,
15735944, 1695823, -8819122, 8169720, 16220347),
array(-18115838, 8653647, 17578566, -6092619, -8025777,
-16012763, -11144307, -2627664, -5990708, -14166033),
),
array(
array(-23308498, -10968312, 15213228, -10081214, -30853605,
-11050004, 27884329, 2847284, 2655861, 1738395),
array(-27537433, -14253021, -25336301, -8002780, -9370762,
8129821, 21651608, -3239336, -19087449, -11005278),
array(1533110, 3437855, 23735889, 459276, 29970501,
11335377, 26030092, 5821408, 10478196, 8544890),
),
array(
array(32173121, -16129311, 24896207, 3921497, 22579056,
-3410854, 19270449, 12217473, 17789017, -3395995),
array(-30552961, -2228401, -15578829, -10147201, 13243889,
517024, 15479401, -3853233, 30460520, 1052596),
array(-11614875, 13323618, 32618793, 8175907, -15230173,
12596687, 27491595, -4612359, 3179268, -9478891),
),
array(
array(31947069, -14366651, -4640583, -15339921, -15125977,
-6039709, -14756777, -16411740, 19072640, -9511060),
array(11685058, 11822410, 3158003, -13952594, 33402194,
-4165066, 5977896, -5215017, 473099, 5040608),
array(-20290863, 8198642, -27410132, 11602123, 1290375,
-2799760, 28326862, 1721092, -19558642, -3131606),
),
),
array(
array(
array(7881532, 10687937, 7578723, 7738378, -18951012,
-2553952, 21820786, 8076149, -27868496, 11538389),
array(-19935666, 3899861, 18283497, -6801568, -15728660,
-11249211, 8754525, 7446702, -5676054, 5797016),
array(-11295600, -3793569, -15782110, -7964573, 12708869,
-8456199, 2014099, -9050574, -2369172, -5877341),
),
array(
array(-22472376, -11568741, -27682020, 1146375, 18956691,
16640559, 1192730, -3714199, 15123619, 10811505),
array(14352098, -3419715, -18942044, 10822655, 32750596,
4699007, -70363, 15776356, -28886779, -11974553),
array(-28241164, -8072475, -4978962, -5315317, 29416931,
1847569, -20654173, -16484855, 4714547, -9600655),
),
array(
array(15200332, 8368572, 19679101, 15970074, -31872674,
1959451, 24611599, -4543832, -11745876, 12340220),
array(12876937, -10480056, 33134381, 6590940, -6307776,
14872440, 9613953, 8241152, 15370987, 9608631),
array(-4143277, -12014408, 8446281, -391603, 4407738,
13629032, -7724868, 15866074, -28210621, -8814099),
),
array(
array(26660628, -15677655, 8393734, 358047, -7401291,
992988, -23904233, 858697, 20571223, 8420556),
array(14620715, 13067227, -15447274, 8264467, 14106269,
15080814, 33531827, 12516406, -21574435, -12476749),
array(236881, 10476226, 57258, -14677024, 6472998, 2466984,
17258519, 7256740, 8791136, 15069930),
),
array(
array(1276410, -9371918, 22949635, -16322807, -23493039,
-5702186, 14711875, 4874229, -30663140, -2331391),
array(5855666, 4990204, -13711848, 7294284, -7804282,
1924647, -1423175, -7912378, -33069337, 9234253),
array(20590503, -9018988, 31529744, -7352666, -2706834,
10650548, 31559055, -11609587, 18979186, 13396066),
),
array(
array(24474287, 4968103, 22267082, 4407354, 24063882,
-8325180, -18816887, 13594782, 33514650, 7021958),
array(-11566906, -6565505, -21365085, 15928892, -26158305,
4315421, -25948728, -3916677, -21480480, 12868082),
array(-28635013, 13504661, 19988037, -2132761, 21078225,
6443208, -21446107, 2244500, -12455797, -8089383),
),
array(
array(-30595528, 13793479, -5852820, 319136, -25723172,
-6263899, 33086546, 8957937, -15233648, 5540521),
array(-11630176, -11503902, -8119500, -7643073, 2620056,
1022908, -23710744, -1568984, -16128528, -14962807),
array(23152971, 775386, 27395463, 14006635, -9701118,
4649512, 1689819, 892185, -11513277, -15205948),
),
array(
array(9770129, 9586738, 26496094, 4324120, 1556511,
-3550024, 27453819, 4763127, -19179614, 5867134),
array(-32765025, 1927590, 31726409, -4753295, 23962434,
-16019500, 27846559, 5931263, -29749703, -16108455),
array(27461885, -2977536, 22380810, 1815854, -23033753,
-3031938, 7283490, -15148073, -19526700, 7734629),
),
),
array(
array(
array(-8010264, -9590817, -11120403, 6196038, 29344158,
-13430885, 7585295, -3176626, 18549497, 15302069),
array(-32658337, -6171222, -7672793, -11051681, 6258878,
13504381, 10458790, -6418461, -8872242, 8424746),
array(24687205, 8613276, -30667046, -3233545, 1863892,
-1830544, 19206234, 7134917, -11284482, -828919),
),
array(
array(11334899, -9218022, 8025293, 12707519, 17523892,
-10476071, 10243738, -14685461, -5066034, 16498837),
array(8911542, 6887158, -9584260, -6958590, 11145641,
-9543680, 17303925, -14124238, 6536641, 10543906),
array(-28946384, 15479763, -17466835, 568876, -1497683,
11223454, -2669190, -16625574, -27235709, 8876771),
),
array(
array(-25742899, -12566864, -15649966, -846607, -33026686,
-796288, -33481822, 15824474, -604426, -9039817),
array(10330056, 70051, 7957388, -9002667, 9764902,
15609756, 27698697, -4890037, 1657394, 3084098),
array(10477963, -7470260, 12119566, -13250805, 29016247,
-5365589, 31280319, 14396151, -30233575, 15272409),
),
array(
array(-12288309, 3169463, 28813183, 16658753, 25116432,
-5630466, -25173957, -12636138, -25014757, 1950504),
array(-26180358, 9489187, 11053416, -14746161, -31053720,
5825630, -8384306, -8767532, 15341279, 8373727),
array(28685821, 7759505, -14378516, -12002860, -31971820,
4079242, 298136, -10232602, -2878207, 15190420),
),
array(
array(-32932876, 13806336, -14337485, -15794431, -24004620,
10940928, 8669718, 2742393, -26033313, -6875003),
array(-1580388, -11729417, -25979658, -11445023, -17411874,
-10912854, 9291594, -16247779, -12154742, 6048605),
array(-30305315, 14843444, 1539301, 11864366, 20201677,
1900163, 13934231, 5128323, 11213262, 9168384),
),
array(
array(-26280513, 11007847, 19408960, -940758, -18592965,
-4328580, -5088060, -11105150, 20470157, -16398701),
array(-23136053, 9282192, 14855179, -15390078, -7362815,
-14408560, -22783952, 14461608, 14042978, 5230683),
array(29969567, -2741594, -16711867, -8552442, 9175486,
-2468974, 21556951, 3506042, -5933891, -12449708),
),
array(
array(-3144746, 8744661, 19704003, 4581278, -20430686,
6830683, -21284170, 8971513, -28539189, 15326563),
array(-19464629, 10110288, -17262528, -3503892, -23500387,
1355669, -15523050, 15300988, -20514118, 9168260),
array(-5353335, 4488613, -23803248, 16314347, 7780487,
-15638939, -28948358, 9601605, 33087103, -9011387),
),
array(
array(-19443170, -15512900, -20797467, -12445323,
-29824447, 10229461, -27444329, -15000531, -5996870, 15664672),
array(23294591, -16632613, -22650781, -8470978, 27844204,
11461195, 13099750, -2460356, 18151676, 13417686),
array(-24722913, -4176517, -31150679, 5988919, -26858785,
6685065, 1661597, -12551441, 15271676, -15452665),
),
),
array(
array(
array(11433042, -13228665, 8239631, -5279517, -1985436,
-725718, -18698764, 2167544, -6921301, -13440182),
array(-31436171, 15575146, 30436815, 12192228, -22463353,
9395379, -9917708, -8638997, 12215110, 12028277),
array(14098400, 6555944, 23007258, 5757252, -15427832,
-12950502, 30123440, 4617780, -16900089, -655628),
),
array(
array(-4026201, -15240835, 11893168, 13718664, -14809462,
1847385, -15819999, 10154009, 23973261, -12684474),
array(-26531820, -3695990, -1908898, 2534301, -31870557,
-16550355, 18341390, -11419951, 32013174, -10103539),
array(-25479301, 10876443, -11771086, -14625140, -12369567,
1838104, 21911214, 6354752, 4425632, -837822),
),
array(
array(-10433389, -14612966, 22229858, -3091047, -13191166,
776729, -17415375, -12020462, 4725005, 14044970),
array(19268650, -7304421, 1555349, 8692754, -21474059,
-9910664, 6347390, -1411784, -19522291, -16109756),
array(-24864089, 12986008, -10898878, -5558584, -11312371,
-148526, 19541418, 8180106, 9282262, 10282508),
),
array(
array(-26205082, 4428547, -8661196, -13194263, 4098402,
-14165257, 15522535, 8372215, 5542595, -10702683),
array(-10562541, 14895633, 26814552, -16673850, -17480754,
-2489360, -2781891, 6993761, -18093885, 10114655),
array(-20107055, -929418, 31422704, 10427861, -7110749,
6150669, -29091755, -11529146, 25953725, -106158),
),
array(
array(-4234397, -8039292, -9119125, 3046000, 2101609,
-12607294, 19390020, 6094296, -3315279, 12831125),
array(-15998678, 7578152, 5310217, 14408357, -33548620,
-224739, 31575954, 6326196, 7381791, -2421839),
array(-20902779, 3296811, 24736065, -16328389, 18374254,
7318640, 6295303, 8082724, -15362489, 12339664),
),
array(
array(27724736, 2291157, 6088201, -14184798, 1792727,
5857634, 13848414, 15768922, 25091167, 14856294),
array(-18866652, 8331043, 24373479, 8541013, -701998,
-9269457, 12927300, -12695493, -22182473, -9012899),
array(-11423429, -5421590, 11632845, 3405020, 30536730,
-11674039, -27260765, 13866390, 30146206, 9142070),
),
array(
array(3924129, -15307516, -13817122, -10054960, 12291820,
-668366, -27702774, 9326384, -8237858, 4171294),
array(-15921940, 16037937, 6713787, 16606682, -21612135,
2790944, 26396185, 3731949, 345228, -5462949),
array(-21327538, 13448259, 25284571, 1143661, 20614966,
-8849387, 2031539, -12391231, -16253183, -13582083),
),
array(
array(31016211, -16722429, 26371392, -14451233, -5027349,
14854137, 17477601, 3842657, 28012650, -16405420),
array(-5075835, 9368966, -8562079, -4600902, -15249953,
6970560, -9189873, 16292057, -8867157, 3507940),
array(29439664, 3537914, 23333589, 6997794, -17555561,
-11018068, -15209202, -15051267, -9164929, 6580396),
),
),
array(
array(
array(-12185861, -7679788, 16438269, 10826160, -8696817,
-6235611, 17860444, -9273846, -2095802, 9304567),
array(20714564, -4336911, 29088195, 7406487, 11426967,
-5095705, 14792667, -14608617, 5289421, -477127),
array(-16665533, -10650790, -6160345, -13305760, 9192020,
-1802462, 17271490, 12349094, 26939669, -3752294),
),
array(
array(-12889898, 9373458, 31595848, 16374215, 21471720,
13221525, -27283495, -12348559, -3698806, 117887),
array(22263325, -6560050, 3984570, -11174646, -15114008,
-566785, 28311253, 5358056, -23319780, 541964),
array(16259219, 3261970, 2309254, -15534474, -16885711,
-4581916, 24134070, -16705829, -13337066, -13552195),
),
array(
array(9378160, -13140186, -22845982, -12745264, 28198281,
-7244098, -2399684, -717351, 690426, 14876244),
array(24977353, -314384, -8223969, -13465086, 28432343,
-1176353, -13068804, -12297348, -22380984, 6618999),
array(-1538174, 11685646, 12944378, 13682314, -24389511,
-14413193, 8044829, -13817328, 32239829, -5652762),
),
array(
array(-18603066, 4762990, -926250, 8885304, -28412480,
-3187315, 9781647, -10350059, 32779359, 5095274),
array(-33008130, -5214506, -32264887, -3685216, 9460461,
-9327423, -24601656, 14506724, 21639561, -2630236),
array(-16400943, -13112215, 25239338, 15531969, 3987758,
-4499318, -1289502, -6863535, 17874574, 558605),
),
array(
array(-13600129, 10240081, 9171883, 16131053, -20869254,
9599700, 33499487, 5080151, 2085892, 5119761),
array(-22205145, -2519528, -16381601, 414691, -25019550,
2170430, 30634760, -8363614, -31999993, -5759884),
array(-6845704, 15791202, 8550074, -1312654, 29928809,
-12092256, 27534430, -7192145, -22351378, 12961482),
),
array(
array(-24492060, -9570771, 10368194, 11582341, -23397293,
-2245287, 16533930, 8206996, -30194652, -5159638),
array(-11121496, -3382234, 2307366, 6362031, -135455,
8868177, -16835630, 7031275, 7589640, 8945490),
array(-32152748, 8917967, 6661220, -11677616, -1192060,
-15793393, 7251489, -11182180, 24099109, -14456170),
),
array(
array(5019558, -7907470, 4244127, -14714356, -26933272,
6453165, -19118182, -13289025, -6231896, -10280736),
array(10853594, 10721687, 26480089, 5861829, -22995819,
1972175, -1866647, -10557898, -3363451, -6441124),
array(-17002408, 5906790, 221599, -6563147, 7828208,
-13248918, 24362661, -2008168, -13866408, 7421392),
),
array(
array(8139927, -6546497, 32257646, -5890546, 30375719,
1886181, -21175108, 15441252, 28826358, -4123029),
array(6267086, 9695052, 7709135, -16603597, -32869068,
-1886135, 14795160, -7840124, 13746021, -1742048),
array(28584902, 7787108, -6732942, -15050729, 22846041,
-7571236, -3181936, -363524, 4771362, -8419958),
),
),
array(
array(
array(24949256, 6376279, -27466481, -8174608, -18646154,
-9930606, 33543569, -12141695, 3569627, 11342593),
array(26514989, 4740088, 27912651, 3697550, 19331575,
-11472339, 6809886, 4608608, 7325975, -14801071),
array(-11618399, -14554430, -24321212, 7655128, -1369274,
5214312, -27400540, 10258390, -17646694, -8186692),
),
array(
array(11431204, 15823007, 26570245, 14329124, 18029990,
4796082, -31446179, 15580664, 9280358, -3973687),
array(-160783, -10326257, -22855316, -4304997, -20861367,
-13621002, -32810901, -11181622, -15545091, 4387441),
array(-20799378, 12194512, 3937617, -5805892, -27154820,
9340370, -24513992, 8548137, 20617071, -7482001),
),
array(
array(-938825, -3930586, -8714311, 16124718, 24603125,
-6225393, -13775352, -11875822, 24345683, 10325460),
array(-19855277, -1568885, -22202708, 8714034, 14007766,
6928528, 16318175, -1010689, 4766743, 3552007),
array(-21751364, -16730916, 1351763, -803421, -4009670,
3950935, 3217514, 14481909, 10988822, -3994762),
),
array(
array(15564307, -14311570, 3101243, 5684148, 30446780,
-8051356, 12677127, -6505343, -8295852, 13296005),
array(-9442290, 6624296, -30298964, -11913677, -4670981,
-2057379, 31521204, 9614054, -30000824, 12074674),
array(4771191, -135239, 14290749, -13089852, 27992298,
14998318, -1413936, -1556716, 29832613, -16391035),
),
array(
array(7064884, -7541174, -19161962, -5067537, -18891269,
-2912736, 25825242, 5293297, -27122660, 13101590),
array(-2298563, 2439670, -7466610, 1719965, -27267541,
-16328445, 32512469, -5317593, -30356070, -4190957),
array(-30006540, 10162316, -33180176, 3981723, -16482138,
-13070044, 14413974, 9515896, 19568978, 9628812),
),
array(
array(33053803, 199357, 15894591, 1583059, 27380243,
-4580435, -17838894, -6106839, -6291786, 3437740),
array(-18978877, 3884493, 19469877, 12726490, 15913552,
13614290, -22961733, 70104, 7463304, 4176122),
array(-27124001, 10659917, 11482427, -16070381, 12771467,
-6635117, -32719404, -5322751, 24216882, 5944158),
),
array(
array(8894125, 7450974, -2664149, -9765752, -28080517,
-12389115, 19345746, 14680796, 11632993, 5847885),
array(26942781, -2315317, 9129564, -4906607, 26024105,
11769399, -11518837, 6367194, -9727230, 4782140),
array(19916461, -4828410, -22910704, -11414391, 25606324,
-5972441, 33253853, 8220911, 6358847, -1873857),
),
array(
array(801428, -2081702, 16569428, 11065167, 29875704,
96627, 7908388, -4480480, -13538503, 1387155),
array(19646058, 5720633, -11416706, 12814209, 11607948,
12749789, 14147075, 15156355, -21866831, 11835260),
array(19299512, 1155910, 28703737, 14890794, 2925026,
7269399, 26121523, 15467869, -26560550, 5052483),
),
),
array(
array(
array(-3017432, 10058206, 1980837, 3964243, 22160966,
12322533, -6431123, -12618185, 12228557, -7003677),
array(32944382, 14922211, -22844894, 5188528, 21913450,
-8719943, 4001465, 13238564, -6114803, 8653815),
array(22865569, -4652735, 27603668, -12545395, 14348958,
8234005, 24808405, 5719875, 28483275, 2841751),
),
array(
array(-16420968, -1113305, -327719, -12107856, 21886282,
-15552774, -1887966, -315658, 19932058, -12739203),
array(-11656086, 10087521, -8864888, -5536143, -19278573,
-3055912, 3999228, 13239134, -4777469, -13910208),
array(1382174, -11694719, 17266790, 9194690, -13324356,
9720081, 20403944, 11284705, -14013818, 3093230),
),
array(
array(16650921, -11037932, -1064178, 1570629, -8329746,
7352753, -302424, 16271225, -24049421, -6691850),
array(-21911077, -5927941, -4611316, -5560156, -31744103,
-10785293, 24123614, 15193618, -21652117, -16739389),
array(-9935934, -4289447, -25279823, 4372842, 2087473,
10399484, 31870908, 14690798, 17361620, 11864968),
),
array(
array(-11307610, 6210372, 13206574, 5806320, -29017692,
-13967200, -12331205, -7486601, -25578460, -16240689),
array(14668462, -12270235, 26039039, 15305210, 25515617,
4542480, 10453892, 6577524, 9145645, -6443880),
array(5974874, 3053895, -9433049, -10385191, -31865124,
3225009, -7972642, 3936128, -5652273, -3050304),
),
array(
array(30625386, -4729400, -25555961, -12792866, -20484575,
7695099, 17097188, -16303496, -27999779, 1803632),
array(-3553091, 9865099, -5228566, 4272701, -5673832,
-16689700, 14911344, 12196514, -21405489, 7047412),
array(20093277, 9920966, -11138194, -5343857, 13161587,
12044805, -32856851, 4124601, -32343828, -10257566),
),
array(
array(-20788824, 14084654, -13531713, 7842147, 19119038,
-13822605, 4752377, -8714640, -21679658, 2288038),
array(-26819236, -3283715, 29965059, 3039786, -14473765,
2540457, 29457502, 14625692, -24819617, 12570232),
array(-1063558, -11551823, 16920318, 12494842, 1278292,
-5869109, -21159943, -3498680, -11974704, 4724943),
),
array(
array(17960970, -11775534, -4140968, -9702530, -8876562,
-1410617, -12907383, -8659932, -29576300, 1903856),
array(23134274, -14279132, -10681997, -1611936, 20684485,
15770816, -12989750, 3190296, 26955097, 14109738),
array(15308788, 5320727, -30113809, -14318877, 22902008,
7767164, 29425325, -11277562, 31960942, 11934971),
),
array(
array(-27395711, 8435796, 4109644, 12222639, -24627868,
14818669, 20638173, 4875028, 10491392, 1379718),
array(-13159415, 9197841, 3875503, -8936108, -1383712,
-5879801, 33518459, 16176658, 21432314, 12180697),
array(-11787308, 11500838, 13787581, -13832590, -22430679,
10140205, 1465425, 12689540, -10301319, -13872883),
),
),
array(
array(
array(5414091, -15386041, -21007664, 9643570, 12834970,
1186149, -2622916, -1342231, 26128231, 6032912),
array(-26337395, -13766162, 32496025, -13653919, 17847801,
-12669156, 3604025, 8316894, -25875034, -10437358),
array(3296484, 6223048, 24680646, -12246460, -23052020,
5903205, -8862297, -4639164, 12376617, 3188849),
),
array(
array(29190488, -14659046, 27549113, -1183516, 3520066,
-10697301, 32049515, -7309113, -16109234, -9852307),
array(-14744486, -9309156, 735818, -598978, -20407687,
-5057904, 25246078, -15795669, 18640741, -960977),
array(-6928835, -16430795, 10361374, 5642961, 4910474,
12345252, -31638386, -494430, 10530747, 1053335),
),
array(
array(-29265967, -14186805, -13538216, -12117373,
-19457059, -10655384, -31462369, -2948985, 24018831, 15026644),
array(-22592535, -3145277, -2289276, 5953843, -13440189,
9425631, 25310643, 13003497, -2314791, -15145616),
array(-27419985, -603321, -8043984, -1669117, -26092265,
13987819, -27297622, 187899, -23166419, -2531735),
),
array(
array(-21744398, -13810475, 1844840, 5021428, -10434399,
-15911473, 9716667, 16266922, -5070217, 726099),
array(29370922, -6053998, 7334071, -15342259, 9385287,
2247707, -13661962, -4839461, 30007388, -15823341),
array(-936379, 16086691, 23751945, -543318, -1167538,
-5189036, 9137109, 730663, 9835848, 4555336),
),
array(
array(-23376435, 1410446, -22253753, -12899614, 30867635,
15826977, 17693930, 544696, -11985298, 12422646),
array(31117226, -12215734, -13502838, 6561947, -9876867,
-12757670, -5118685, -4096706, 29120153, 13924425),
array(-17400879, -14233209, 19675799, -2734756, -11006962,
-5858820, -9383939, -11317700, 7240931, -237388),
),
array(
array(-31361739, -11346780, -15007447, -5856218, -22453340,
-12152771, 1222336, 4389483, 3293637, -15551743),
array(-16684801, -14444245, 11038544, 11054958, -13801175,
-3338533, -24319580, 7733547, 12796905, -6335822),
array(-8759414, -10817836, -25418864, 10783769, -30615557,
-9746811, -28253339, 3647836, 3222231, -11160462),
),
array(
array(18606113, 1693100, -25448386, -15170272, 4112353,
10045021, 23603893, -2048234, -7550776, 2484985),
array(9255317, -3131197, -12156162, -1004256, 13098013,
-9214866, 16377220, -2102812, -19802075, -3034702),
array(-22729289, 7496160, -5742199, 11329249, 19991973,
-3347502, -31718148, 9936966, -30097688, -10618797),
),
array(
array(21878590, -5001297, 4338336, 13643897, -3036865,
13160960, 19708896, 5415497, -7360503, -4109293),
array(27736861, 10103576, 12500508, 8502413, -3413016,
-9633558, 10436918, -1550276, -23659143, -8132100),
array(19492550, -12104365, -29681976, -852630, -3208171,
12403437, 30066266, 8367329, 13243957, 8709688),
),
),
array(
array(
array(12015105, 2801261, 28198131, 10151021, 24818120,
-4743133, -11194191, -5645734, 5150968, 7274186),
array(2831366, -12492146, 1478975, 6122054, 23825128,
-12733586, 31097299, 6083058, 31021603, -9793610),
array(-2529932, -2229646, 445613, 10720828, -13849527,
-11505937, -23507731, 16354465, 15067285, -14147707),
),
array(
array(7840942, 14037873, -33364863, 15934016, -728213,
-3642706, 21403988, 1057586, -19379462, -12403220),
array(915865, -16469274, 15608285, -8789130, -24357026,
6060030, -17371319, 8410997, -7220461, 16527025),
array(32922597, -556987, 20336074, -16184568, 10903705,
-5384487, 16957574, 52992, 23834301, 6588044),
),
array(
array(32752030, 11232950, 3381995, -8714866, 22652988,
-10744103, 17159699, 16689107, -20314580, -1305992),
array(-4689649, 9166776, -25710296, -10847306, 11576752,
12733943, 7924251, -2752281, 1976123, -7249027),
array(21251222, 16309901, -2983015, -6783122, 30810597,
12967303, 156041, -3371252, 12331345, -8237197),
),
array(
array(8651614, -4477032, -16085636, -4996994, 13002507,
2950805, 29054427, -5106970, 10008136, -4667901),
array(31486080, 15114593, -14261250, 12951354, 14369431,
-7387845, 16347321, -13662089, 8684155, -10532952),
array(19443825, 11385320, 24468943, -9659068, -23919258,
2187569, -26263207, -6086921, 31316348, 14219878),
),
array(
array(-28594490, 1193785, 32245219, 11392485, 31092169,
15722801, 27146014, 6992409, 29126555, 9207390),
array(32382935, 1110093, 18477781, 11028262, -27411763,
-7548111, -4980517, 10843782, -7957600, -14435730),
array(2814918, 7836403, 27519878, -7868156, -20894015,
-11553689, -21494559, 8550130, 28346258, 1994730),
),
array(
array(-19578299, 8085545, -14000519, -3948622, 2785838,
-16231307, -19516951, 7174894, 22628102, 8115180),
array(-30405132, 955511, -11133838, -15078069, -32447087,
-13278079, -25651578, 3317160, -9943017, 930272),
array(-15303681, -6833769, 28856490, 1357446, 23421993,
1057177, 24091212, -1388970, -22765376, -10650715),
),
array(
array(-22751231, -5303997, -12907607, -12768866, -15811511,
-7797053, -14839018, -16554220, -1867018, 8398970),
array(-31969310, 2106403, -4736360, 1362501, 12813763,
16200670, 22981545, -6291273, 18009408, -15772772),
array(-17220923, -9545221, -27784654, 14166835, 29815394,
7444469, 29551787, -3727419, 19288549, 1325865),
),
array(
array(15100157, -15835752, -23923978, -1005098, -26450192,
15509408, 12376730, -3479146, 33166107, -8042750),
array(20909231, 13023121, -9209752, 16251778, -5778415,
-8094914, 12412151, 10018715, 2213263, -13878373),
array(32529814, -11074689, 30361439, -16689753, -9135940,
1513226, 22922121, 6382134, -5766928, 8371348),
),
),
array(
array(
array(9923462, 11271500, 12616794, 3544722, -29998368,
-1721626, 12891687, -8193132, -26442943, 10486144),
array(-22597207, -7012665, 8587003, -8257861, 4084309,
-12970062, 361726, 2610596, -23921530, -11455195),
array(5408411, -1136691, -4969122, 10561668, 24145918,
14240566, 31319731, -4235541, 19985175, -3436086),
),
array(
array(-13994457, 16616821, 14549246, 3341099, 32155958,
13648976, -17577068, 8849297, 65030, 8370684),
array(-8320926, -12049626, 31204563, 5839400, -20627288,
-1057277, -19442942, 6922164, 12743482, -9800518),
array(-2361371, 12678785, 28815050, 4759974, -23893047,
4884717, 23783145, 11038569, 18800704, 255233),
),
array(
array(-5269658, -1773886, 13957886, 7990715, 23132995,
728773, 13393847, 9066957, 19258688, -14753793),
array(-2936654, -10827535, -10432089, 14516793, -3640786,
4372541, -31934921, 2209390, -1524053, 2055794),
array(580882, 16705327, 5468415, -2683018, -30926419,
-14696000, -7203346, -8994389, -30021019, 7394435),
),
array(
array(23838809, 1822728, -15738443, 15242727, 8318092,
-3733104, -21672180, -3492205, -4821741, 14799921),
array(13345610, 9759151, 3371034, -16137791, 16353039,
8577942, 31129804, 13496856, -9056018, 7402518),
array(2286874, -4435931, -20042458, -2008336, -13696227,
5038122, 11006906, -15760352, 8205061, 1607563),
),
array(
array(14414086, -8002132, 3331830, -3208217, 22249151,
-5594188, 18364661, -2906958, 30019587, -9029278),
array(-27688051, 1585953, -10775053, 931069, -29120221,
-11002319, -14410829, 12029093, 9944378, 8024),
array(4368715, -3709630, 29874200, -15022983, -20230386,
-11410704, -16114594, -999085, -8142388, 5640030),
),
array(
array(10299610, 13746483, 11661824, 16234854, 7630238,
5998374, 9809887, -16694564, 15219798, -14327783),
array(27425505, -5719081, 3055006, 10660664, 23458024,
595578, -15398605, -1173195, -18342183, 9742717),
array(6744077, 2427284, 26042789, 2720740, -847906,
1118974, 32324614, 7406442, 12420155, 1994844),
),
array(
array(14012521, -5024720, -18384453, -9578469, -26485342,
-3936439, -13033478, -10909803, 24319929, -6446333),
array(16412690, -4507367, 10772641, 15929391, -17068788,
-4658621, 10555945, -10484049, -30102368, -4739048),
array(22397382, -7767684, -9293161, -12792868, 17166287,
-9755136, -27333065, 6199366, 21880021, -12250760),
),
array(
array(-4283307, 5368523, -31117018, 8163389, -30323063,
3209128, 16557151, 8890729, 8840445, 4957760),
array(-15447727, 709327, -6919446, -10870178, -29777922,
6522332, -21720181, 12130072, -14796503, 5005757),
array(-2114751, -14308128, 23019042, 15765735, -25269683,
6002752, 10183197, -13239326, -16395286, -2176112),
),
),
array(
array(
array(-19025756, 1632005, 13466291, -7995100, -23640451,
16573537, -32013908, -3057104, 22208662, 2000468),
array(3065073, -1412761, -25598674, -361432, -17683065,
-5703415, -8164212, 11248527, -3691214, -7414184),
array(10379208, -6045554, 8877319, 1473647, -29291284,
-12507580, 16690915, 2553332, -3132688, 16400289),
),
array(
array(15716668, 1254266, -18472690, 7446274, -8448918,
6344164, -22097271, -7285580, 26894937, 9132066),
array(24158887, 12938817, 11085297, -8177598, -28063478,
-4457083, -30576463, 64452, -6817084, -2692882),
array(13488534, 7794716, 22236231, 5989356, 25426474,
-12578208, 2350710, -3418511, -4688006, 2364226),
),
array(
array(16335052, 9132434, 25640582, 6678888, 1725628,
8517937, -11807024, -11697457, 15445875, -7798101),
array(29004207, -7867081, 28661402, -640412, -12794003,
-7943086, 31863255, -4135540, -278050, -15759279),
array(-6122061, -14866665, -28614905, 14569919, -10857999,
-3591829, 10343412, -6976290, -29828287, -10815811),
),
array(
array(27081650, 3463984, 14099042, -4517604, 1616303,
-6205604, 29542636, 15372179, 17293797, 960709),
array(20263915, 11434237, -5765435, 11236810, 13505955,
-10857102, -16111345, 6493122, -19384511, 7639714),
array(-2830798, -14839232, 25403038, -8215196, -8317012,
-16173699, 18006287, -16043750, 29994677, -15808121),
),
array(
array(9769828, 5202651, -24157398, -13631392, -28051003,
-11561624, -24613141, -13860782, -31184575, 709464),
array(12286395, 13076066, -21775189, -1176622, -25003198,
4057652, -32018128, -8890874, 16102007, 13205847),
array(13733362, 5599946, 10557076, 3195751, -5557991,
8536970, -25540170, 8525972, 10151379, 10394400),
),
array(
array(4024660, -16137551, 22436262, 12276534, -9099015,
-2686099, 19698229, 11743039, -33302334, 8934414),
array(-15879800, -4525240, -8580747, -2934061, 14634845,
-698278, -9449077, 3137094, -11536886, 11721158),
array(17555939, -5013938, 8268606, 2331751, -22738815,
9761013, 9319229, 8835153, -9205489, -1280045),
),
array(
array(-461409, -7830014, 20614118, 16688288, -7514766,
-4807119, 22300304, 505429, 6108462, -6183415),
array(-5070281, 12367917, -30663534, 3234473, 32617080,
-8422642, 29880583, -13483331, -26898490, -7867459),
array(-31975283, 5726539, 26934134, 10237677, -3173717,
-605053, 24199304, 3795095, 7592688, -14992079),
),
array(
array(21594432, -14964228, 17466408, -4077222, 32537084,
2739898, 6407723, 12018833, -28256052, 4298412),
array(-20650503, -11961496, -27236275, 570498, 3767144,
-1717540, 13891942, -1569194, 13717174, 10805743),
array(-14676630, -15644296, 15287174, 11927123, 24177847,
-8175568, -796431, 14860609, -26938930, -5863836),
),
),
array(
array(
array(12962541, 5311799, -10060768, 11658280, 18855286,
-7954201, 13286263, -12808704, -4381056, 9882022),
array(18512079, 11319350, -20123124, 15090309, 18818594,
5271736, -22727904, 3666879, -23967430, -3299429),
array(-6789020, -3146043, 16192429, 13241070, 15898607,
-14206114, -10084880, -6661110, -2403099, 5276065),
),
array(
array(30169808, -5317648, 26306206, -11750859, 27814964,
7069267, 7152851, 3684982, 1449224, 13082861),
array(10342826, 3098505, 2119311, 193222, 25702612,
12233820, 23697382, 15056736, -21016438, -8202000),
array(-33150110, 3261608, 22745853, 7948688, 19370557,
-15177665, -26171976, 6482814, -10300080, -11060101),
),
array(
array(32869458, -5408545, 25609743, 15678670, -10687769,
-15471071, 26112421, 2521008, -22664288, 6904815),
array(29506923, 4457497, 3377935, -9796444, -30510046,
12935080, 1561737, 3841096, -29003639, -6657642),
array(10340844, -6630377, -18656632, -2278430, 12621151,
-13339055, 30878497, -11824370, -25584551, 5181966),
),
array(
array(25940115, -12658025, 17324188, -10307374, -8671468,
15029094, 24396252, -16450922, -2322852, -12388574),
array(-21765684, 9916823, -1300409, 4079498, -1028346,
11909559, 1782390, 12641087, 20603771, -6561742),
array(-18882287, -11673380, 24849422, 11501709, 13161720,
-4768874, 1925523, 11914390, 4662781, 7820689),
),
array(
array(12241050, -425982, 8132691, 9393934, 32846760,
-1599620, 29749456, 12172924, 16136752, 15264020),
array(-10349955, -14680563, -8211979, 2330220, -17662549,
-14545780, 10658213, 6671822, 19012087, 3772772),
array(3753511, -3421066, 10617074, 2028709, 14841030,
-6721664, 28718732, -15762884, 20527771, 12988982),
),
array(
array(-14822485, -5797269, -3707987, 12689773, -898983,
-10914866, -24183046, -10564943, 3299665, -12424953),
array(-16777703, -15253301, -9642417, 4978983, 3308785,
8755439, 6943197, 6461331, -25583147, 8991218),
array(-17226263, 1816362, -1673288, -6086439, 31783888,
-8175991, -32948145, 7417950, -30242287, 1507265),
),
array(
array(29692663, 6829891, -10498800, 4334896, 20945975,
-11906496, -28887608, 8209391, 14606362, -10647073),
array(-3481570, 8707081, 32188102, 5672294, 22096700,
1711240, -33020695, 9761487, 4170404, -2085325),
array(-11587470, 14855945, -4127778, -1531857, -26649089,
15084046, 22186522, 16002000, -14276837, -8400798),
),
array(
array(-4811456, 13761029, -31703877, -2483919, -3312471,
7869047, -7113572, -9620092, 13240845, 10965870),
array(-7742563, -8256762, -14768334, -13656260, -23232383,
12387166, 4498947, 14147411, 29514390, 4302863),
array(-13413405, -12407859, 20757302, -13801832, 14785143,
8976368, -5061276, -2144373, 17846988, -13971927),
),
),
array(
array(
array(-2244452, -754728, -4597030, -1066309, -6247172,
1455299, -21647728, -9214789, -5222701, 12650267),
array(-9906797, -16070310, 21134160, 12198166, -27064575,
708126, 387813, 13770293, -19134326, 10958663),
array(22470984, 12369526, 23446014, -5441109, -21520802,
-9698723, -11772496, -11574455, -25083830, 4271862),
),
array(
array(-25169565, -10053642, -19909332, 15361595, -5984358,
2159192, 75375, -4278529, -32526221, 8469673),
array(15854970, 4148314, -8893890, 7259002, 11666551,
13824734, -30531198, 2697372, 24154791, -9460943),
array(15446137, -15806644, 29759747, 14019369, 30811221,
-9610191, -31582008, 12840104, 24913809, 9815020),
),
array(
array(-4709286, -5614269, -31841498, -12288893, -14443537,
10799414, -9103676, 13438769, 18735128, 9466238),
array(11933045, 9281483, 5081055, -5183824, -2628162,
-4905629, -7727821, -10896103, -22728655, 16199064),
array(14576810, 379472, -26786533, -8317236, -29426508,
-10812974, -102766, 1876699, 30801119, 2164795),
),
array(
array(15995086, 3199873, 13672555, 13712240, -19378835,
-4647646, -13081610, -15496269, -13492807, 1268052),
array(-10290614, -3659039, -3286592, 10948818, 23037027,
3794475, -3470338, -12600221, -17055369, 3565904),
array(29210088, -9419337, -5919792, -4952785, 10834811,
-13327726, -16512102, -10820713, -27162222, -14030531),
),
array(
array(-13161890, 15508588, 16663704, -8156150, -28349942,
9019123, -29183421, -3769423, 2244111, -14001979),
array(-5152875, -3800936, -9306475, -6071583, 16243069,
14684434, -25673088, -16180800, 13491506, 4641841),
array(10813417, 643330, -19188515, -728916, 30292062,
-16600078, 27548447, -7721242, 14476989, -12767431),
),
array(
array(10292079, 9984945, 6481436, 8279905, -7251514,
7032743, 27282937, -1644259, -27912810, 12651324),
array(-31185513, -813383, 22271204, 11835308, 10201545,
15351028, 17099662, 3988035, 21721536, -3148940),
array(10202177, -6545839, -31373232, -9574638, -32150642,
-8119683, -12906320, 3852694, 13216206, 14842320),
),
array(
array(-15815640, -10601066, -6538952, -7258995, -6984659,
-6581778, -31500847, 13765824, -27434397, 9900184),
array(14465505, -13833331, -32133984, -14738873, -27443187,
12990492, 33046193, 15796406, -7051866, -8040114),
array(30924417, -8279620, 6359016, -12816335, 16508377,
9071735, -25488601, 15413635, 9524356, -7018878),
),
array(
array(12274201, -13175547, 32627641, -1785326, 6736625,
13267305, 5237659, -5109483, 15663516, 4035784),
array(-2951309, 8903985, 17349946, 601635, -16432815,
-4612556, -13732739, -15889334, -22258478, 4659091),
array(-16916263, -4952973, -30393711, -15158821, 20774812,
15897498, 5736189, 15026997, -2178256, -13455585),
),
),
array(
array(
array(-8858980, -2219056, 28571666, -10155518, -474467,
-10105698, -3801496, 278095, 23440562, -290208),
array(10226241, -5928702, 15139956, 120818, -14867693,
5218603, 32937275, 11551483, -16571960, -7442864),
array(17932739, -12437276, -24039557, 10749060, 11316803,
7535897, 22503767, 5561594, -3646624, 3898661),
),
array(
array(7749907, -969567, -16339731, -16464, -25018111,
15122143, -1573531, 7152530, 21831162, 1245233),
array(26958459, -14658026, 4314586, 8346991, -5677764,
11960072, -32589295, -620035, -30402091, -16716212),
array(-12165896, 9166947, 33491384, 13673479, 29787085,
13096535, 6280834, 14587357, -22338025, 13987525),
),
array(
array(-24349909, 7778775, 21116000, 15572597, -4833266,
-5357778, -4300898, -5124639, -7469781, -2858068),
array(9681908, -6737123, -31951644, 13591838, -6883821,
386950, 31622781, 6439245, -14581012, 4091397),
array(-8426427, 1470727, -28109679, -1596990, 3978627,
-5123623, -19622683, 12092163, 29077877, -14741988),
),
array(
array(5269168, -6859726, -13230211, -8020715, 25932563,
1763552, -5606110, -5505881, -20017847, 2357889),
array(32264008, -15407652, -5387735, -1160093, -2091322,
-3946900, 23104804, -12869908, 5727338, 189038),
array(14609123, -8954470, -6000566, -16622781, -14577387,
-7743898, -26745169, 10942115, -25888931, -14884697),
),
array(
array(20513500, 5557931, -15604613, 7829531, 26413943,
-2019404, -21378968, 7471781, 13913677, -5137875),
array(-25574376, 11967826, 29233242, 12948236, -6754465,
4713227, -8940970, 14059180, 12878652, 8511905),
array(-25656801, 3393631, -2955415, -7075526, -2250709,
9366908, -30223418, 6812974, 5568676, -3127656),
),
array(
array(11630004, 12144454, 2116339, 13606037, 27378885,
15676917, -17408753, -13504373, -14395196, 8070818),
array(27117696, -10007378, -31282771, -5570088, 1127282,
12772488, -29845906, 10483306, -11552749, -1028714),
array(10637467, -5688064, 5674781, 1072708, -26343588,
-6982302, -1683975, 9177853, -27493162, 15431203),
),
array(
array(20525145, 10892566, -12742472, 12779443, -29493034,
16150075, -28240519, 14943142, -15056790, -7935931),
array(-30024462, 5626926, -551567, -9981087, 753598,
11981191, 25244767, -3239766, -3356550, 9594024),
array(-23752644, 2636870, -5163910, -10103818, 585134,
7877383, 11345683, -6492290, 13352335, -10977084),
),
array(
array(-1931799, -5407458, 3304649, -12884869, 17015806,
-4877091, -29783850, -7752482, -13215537, -319204),
array(20239939, 6607058, 6203985, 3483793, -18386976,
-779229, -20723742, 15077870, -22750759, 14523817),
array(27406042, -6041657, 27423596, -4497394, 4996214,
10002360, -28842031, -4545494, -30172742, -4805667),
),
),
array(
array(
array(11374242, 12660715, 17861383, -12540833, 10935568,
1099227, -13886076, -9091740, -27727044, 11358504),
array(-12730809, 10311867, 1510375, 10778093, -2119455,
-9145702, 32676003, 11149336, -26123651, 4985768),
array(-19096303, 341147, -6197485, -239033, 15756973,
-8796662, -983043, 13794114, -19414307, -15621255),
),
array(
array(6490081, 11940286, 25495923, -7726360, 8668373,
-8751316, 3367603, 6970005, -1691065, -9004790),
array(1656497, 13457317, 15370807, 6364910, 13605745,
8362338, -19174622, -5475723, -16796596, -5031438),
array(-22273315, -13524424, -64685, -4334223, -18605636,
-10921968, -20571065, -7007978, -99853, -10237333),
),
array(
array(17747465, 10039260, 19368299, -4050591, -20630635,
-16041286, 31992683, -15857976, -29260363, -5511971),
array(31932027, -4986141, -19612382, 16366580, 22023614,
88450, 11371999, -3744247, 4882242, -10626905),
array(29796507, 37186, 19818052, 10115756, -11829032,
3352736, 18551198, 3272828, -5190932, -4162409),
),
array(
array(12501286, 4044383, -8612957, -13392385, -32430052,
5136599, -19230378, -3529697, 330070, -3659409),
array(6384877, 2899513, 17807477, 7663917, -2358888,
12363165, 25366522, -8573892, -271295, 12071499),
array(-8365515, -4042521, 25133448, -4517355, -6211027,
2265927, -32769618, 1936675, -5159697, 3829363),
),
array(
array(28425966, -5835433, -577090, -4697198, -14217555,
6870930, 7921550, -6567787, 26333140, 14267664),
array(-11067219, 11871231, 27385719, -10559544, -4585914,
-11189312, 10004786, -8709488, -21761224, 8930324),
array(-21197785, -16396035, 25654216, -1725397, 12282012,
11008919, 1541940, 4757911, -26491501, -16408940),
),
array(
array(13537262, -7759490, -20604840, 10961927, -5922820,
-13218065, -13156584, 6217254, -15943699, 13814990),
array(-17422573, 15157790, 18705543, 29619, 24409717,
-260476, 27361681, 9257833, -1956526, -1776914),
array(-25045300, -10191966, 15366585, 15166509, -13105086,
8423556, -29171540, 12361135, -18685978, 4578290),
),
array(
array(24579768, 3711570, 1342322, -11180126, -27005135,
14124956, -22544529, 14074919, 21964432, 8235257),
array(-6528613, -2411497, 9442966, -5925588, 12025640,
-1487420, -2981514, -1669206, 13006806, 2355433),
array(-16304899, -13605259, -6632427, -5142349, 16974359,
-10911083, 27202044, 1719366, 1141648, -12796236),
),
array(
array(-12863944, -13219986, -8318266, -11018091, -6810145,
-4843894, 13475066, -3133972, 32674895, 13715045),
array(11423335, -5468059, 32344216, 8962751, 24989809,
9241752, -13265253, 16086212, -28740881, -15642093),
array(-1409668, 12530728, -6368726, 10847387, 19531186,
-14132160, -11709148, 7791794, -27245943, 4383347),
),
),
array(
array(
array(-28970898, 5271447, -1266009, -9736989, -12455236,
16732599, -4862407, -4906449, 27193557, 6245191),
array(-15193956, 5362278, -1783893, 2695834, 4960227,
12840725, 23061898, 3260492, 22510453, 8577507),
array(-12632451, 11257346, -32692994, 13548177, -721004,
10879011, 31168030, 13952092, -29571492, -3635906),
),
array(
array(3877321, -9572739, 32416692, 5405324, -11004407,
-13656635, 3759769, 11935320, 5611860, 8164018),
array(-16275802, 14667797, 15906460, 12155291, -22111149,
-9039718, 32003002, -8832289, 5773085, -8422109),
array(-23788118, -8254300, 1950875, 8937633, 18686727,
16459170, -905725, 12376320, 31632953, 190926),
),
array(
array(-24593607, -16138885, -8423991, 13378746, 14162407,
6901328, -8288749, 4508564, -25341555, -3627528),
array(8884438, -5884009, 6023974, 10104341, -6881569,
-4941533, 18722941, -14786005, -1672488, 827625),
array(-32720583, -16289296, -32503547, 7101210, 13354605,
2659080, -1800575, -14108036, -24878478, 1541286),
),
array(
array(2901347, -1117687, 3880376, -10059388, -17620940,
-3612781, -21802117, -3567481, 20456845, -1885033),
array(27019610, 12299467, -13658288, -1603234, -12861660,
-4861471, -19540150, -5016058, 29439641, 15138866),
array(21536104, -6626420, -32447818, -10690208, -22408077,
5175814, -5420040, -16361163, 7779328, 109896),
),
array(
array(30279744, 14648750, -8044871, 6425558, 13639621,
-743509, 28698390, 12180118, 23177719, -554075),
array(26572847, 3405927, -31701700, 12890905, -19265668,
5335866, -6493768, 2378492, 4439158, -13279347),
array(-22716706, 3489070, -9225266, -332753, 18875722,
-1140095, 14819434, -12731527, -17717757, -5461437),
),
array(
array(-5056483, 16566551, 15953661, 3767752, -10436499,
15627060, -820954, 2177225, 8550082, -15114165),
array(-18473302, 16596775, -381660, 15663611, 22860960,
15585581, -27844109, -3582739, -23260460, -8428588),
array(-32480551, 15707275, -8205912, -5652081, 29464558,
2713815, -22725137, 15860482, -21902570, 1494193),
),
array(
array(-19562091, -14087393, -25583872, -9299552, 13127842,
759709, 21923482, 16529112, 8742704, 12967017),
array(-28464899, 1553205, 32536856, -10473729, -24691605,
-406174, -8914625, -2933896, -29903758, 15553883),
array(21877909, 3230008, 9881174, 10539357, -4797115,
2841332, 11543572, 14513274, 19375923, -12647961),
),
array(
array(8832269, -14495485, 13253511, 5137575, 5037871,
4078777, 24880818, -6222716, 2862653, 9455043),
array(29306751, 5123106, 20245049, -14149889, 9592566,
8447059, -2077124, -2990080, 15511449, 4789663),
array(-20679756, 7004547, 8824831, -9434977, -4045704,
-3750736, -5754762, 108893, 23513200, 16652362),
),
),
array(
array(
array(-33256173, 4144782, -4476029, -6579123, 10770039,
-7155542, -6650416, -12936300, -18319198, 10212860),
array(2756081, 8598110, 7383731, -6859892, 22312759,
-1105012, 21179801, 2600940, -9988298, -12506466),
array(-24645692, 13317462, -30449259, -15653928, 21365574,
-10869657, 11344424, 864440, -2499677, -16710063),
),
array(
array(-26432803, 6148329, -17184412, -14474154, 18782929,
-275997, -22561534, 211300, 2719757, 4940997),
array(-1323882, 3911313, -6948744, 14759765, -30027150,
7851207, 21690126, 8518463, 26699843, 5276295),
array(-13149873, -6429067, 9396249, 365013, 24703301,
-10488939, 1321586, 149635, -15452774, 7159369),
),
array(
array(9987780, -3404759, 17507962, 9505530, 9731535,
-2165514, 22356009, 8312176, 22477218, -8403385),
array(18155857, -16504990, 19744716, 9006923, 15154154,
-10538976, 24256460, -4864995, -22548173, 9334109),
array(2986088, -4911893, 10776628, -3473844, 10620590,
-7083203, -21413845, 14253545, -22587149, 536906),
),
array(
array(4377756, 8115836, 24567078, 15495314, 11625074,
13064599, 7390551, 10589625, 10838060, -15420424),
array(-19342404, 867880, 9277171, -3218459, -14431572,
-1986443, 19295826, -15796950, 6378260, 699185),
array(7895026, 4057113, -7081772, -13077756, -17886831,
-323126, -716039, 15693155, -5045064, -13373962),
),
array(
array(-7737563, -5869402, -14566319, -7406919, 11385654,
13201616, 31730678, -10962840, -3918636, -9669325),
array(10188286, -15770834, -7336361, 13427543, 22223443,
14896287, 30743455, 7116568, -21786507, 5427593),
array(696102, 13206899, 27047647, -10632082, 15285305,
-9853179, 10798490, -4578720, 19236243, 12477404),
),
array(
array(-11229439, 11243796, -17054270, -8040865, -788228,
-8167967, -3897669, 11180504, -23169516, 7733644),
array(17800790, -14036179, -27000429, -11766671, 23887827,
3149671, 23466177, -10538171, 10322027, 15313801),
array(26246234, 11968874, 32263343, -5468728, 6830755,
-13323031, -15794704, -101982, -24449242, 10890804),
),
array(
array(-31365647, 10271363, -12660625, -6267268, 16690207,
-13062544, -14982212, 16484931, 25180797, -5334884),
array(-586574, 10376444, -32586414, -11286356, 19801893,
10997610, 2276632, 9482883, 316878, 13820577),
array(-9882808, -4510367, -2115506, 16457136, -11100081,
11674996, 30756178, -7515054, 30696930, -3712849),
),
array(
array(32988917, -9603412, 12499366, 7910787, -10617257,
-11931514, -7342816, -9985397, -32349517, 7392473),
array(-8855661, 15927861, 9866406, -3649411, -2396914,
-16655781, -30409476, -9134995, 25112947, -2926644),
array(-2504044, -436966, 25621774, -5678772, 15085042,
-5479877, -24884878, -13526194, 5537438, -13914319),
),
),
array(
array(
array(-11225584, 2320285, -9584280, 10149187, -33444663,
5808648, -14876251, -1729667, 31234590, 6090599),
array(-9633316, 116426, 26083934, 2897444, -6364437,
-2688086, 609721, 15878753, -6970405, -9034768),
array(-27757857, 247744, -15194774, -9002551, 23288161,
-10011936, -23869595, 6503646, 20650474, 1804084),
),
array(
array(-27589786, 15456424, 8972517, 8469608, 15640622,
4439847, 3121995, -10329713, 27842616, -202328),
array(-15306973, 2839644, 22530074, 10026331, 4602058,
5048462, 28248656, 5031932, -11375082, 12714369),
array(20807691, -7270825, 29286141, 11421711, -27876523,
-13868230, -21227475, 1035546, -19733229, 12796920),
),
array(
array(12076899, -14301286, -8785001, -11848922, -25012791,
16400684, -17591495, -12899438, 3480665, -15182815),
array(-32361549, 5457597, 28548107, 7833186, 7303070,
-11953545, -24363064, -15921875, -33374054, 2771025),
array(-21389266, 421932, 26597266, 6860826, 22486084,
-6737172, -17137485, -4210226, -24552282, 15673397),
),
array(
array(-20184622, 2338216, 19788685, -9620956, -4001265,
-8740893, -20271184, 4733254, 3727144, -12934448),
array(6120119, 814863, -11794402, -622716, 6812205,
-15747771, 2019594, 7975683, 31123697, -10958981),
array(30069250, -11435332, 30434654, 2958439, 18399564,
-976289, 12296869, 9204260, -16432438, 9648165),
),
array(
array(32705432, -1550977, 30705658, 7451065, -11805606,
9631813, 3305266, 5248604, -26008332, -11377501),
array(17219865, 2375039, -31570947, -5575615, -19459679,
9219903, 294711, 15298639, 2662509, -16297073),
array(-1172927, -7558695, -4366770, -4287744, -21346413,
-8434326, 32087529, -1222777, 32247248, -14389861),
),
array(
array(14312628, 1221556, 17395390, -8700143, -4945741,
-8684635, -28197744, -9637817, -16027623, -13378845),
array(-1428825, -9678990, -9235681, 6549687, -7383069,
-468664, 23046502, 9803137, 17597934, 2346211),
array(18510800, 15337574, 26171504, 981392, -22241552,
7827556, -23491134, -11323352, 3059833, -11782870),
),
array(
array(10141598, 6082907, 17829293, -1947643, 9830092,
13613136, -25556636, -5544586, -33502212, 3592096),
array(33114168, -15889352, -26525686, -13343397, 33076705,
8716171, 1151462, 1521897, -982665, -6837803),
array(-32939165, -4255815, 23947181, -324178, -33072974,
-12305637, -16637686, 3891704, 26353178, 693168),
),
array(
array(30374239, 1595580, -16884039, 13186931, 4600344,
406904, 9585294, -400668, 31375464, 14369965),
array(-14370654, -7772529, 1510301, 6434173, -18784789,
-6262728, 32732230, -13108839, 17901441, 16011505),
array(18171223, -11934626, -12500402, 15197122, -11038147,
-15230035, -19172240, -16046376, 8764035, 12309598),
),
),
array(
array(
array(5975908, -5243188, -19459362, -9681747, -11541277,
14015782, -23665757, 1228319, 17544096, -10593782),
array(5811932, -1715293, 3442887, -2269310, -18367348,
-8359541, -18044043, -15410127, -5565381, 12348900),
array(-31399660, 11407555, 25755363, 6891399, -3256938,
14872274, -24849353, 8141295, -10632534, -585479),
),
array(
array(-12675304, 694026, -5076145, 13300344, 14015258,
-14451394, -9698672, -11329050, 30944593, 1130208),
array(8247766, -6710942, -26562381, -7709309, -14401939,
-14648910, 4652152, 2488540, 23550156, -271232),
array(17294316, -3788438, 7026748, 15626851, 22990044,
113481, 2267737, -5908146, -408818, -137719),
),
array(
array(16091085, -16253926, 18599252, 7340678, 2137637,
-1221657, -3364161, 14550936, 3260525, -7166271),
array(-4910104, -13332887, 18550887, 10864893, -16459325,
-7291596, -23028869, -13204905, -12748722, 2701326),
array(-8574695, 16099415, 4629974, -16340524, -20786213,
-6005432, -10018363, 9276971, 11329923, 1862132),
),
array(
array(14763076, -15903608, -30918270, 3689867, 3511892,
10313526, -21951088, 12219231, -9037963, -940300),
array(8894987, -3446094, 6150753, 3013931, 301220,
15693451, -31981216, -2909717, -15438168, 11595570),
array(15214962, 3537601, -26238722, -14058872, 4418657,
-15230761, 13947276, 10730794, -13489462, -4363670),
),
array(
array(-2538306, 7682793, 32759013, 263109, -29984731,
-7955452, -22332124, -10188635, 977108, 699994),
array(-12466472, 4195084, -9211532, 550904, -15565337,
12917920, 19118110, -439841, -30534533, -14337913),
array(31788461, -14507657, 4799989, 7372237, 8808585,
-14747943, 9408237, -10051775, 12493932, -5409317),
),
array(
array(-25680606, 5260744, -19235809, -6284470, -3695942,
16566087, 27218280, 2607121, 29375955, 6024730),
array(842132, -2794693, -4763381, -8722815, 26332018,
-12405641, 11831880, 6985184, -9940361, 2854096),
array(-4847262, -7969331, 2516242, -5847713, 9695691,
-7221186, 16512645, 960770, 12121869, 16648078),
),
array(
array(-15218652, 14667096, -13336229, 2013717, 30598287,
-464137, -31504922, -7882064, 20237806, 2838411),
array(-19288047, 4453152, 15298546, -16178388, 22115043,
-15972604, 12544294, -13470457, 1068881, -12499905),
array(-9558883, -16518835, 33238498, 13506958, 30505848,
-1114596, -8486907, -2630053, 12521378, 4845654),
),
array(
array(-28198521, 10744108, -2958380, 10199664, 7759311,
-13088600, 3409348, -873400, -6482306, -12885870),
array(-23561822, 6230156, -20382013, 10655314, -24040585,
-11621172, 10477734, -1240216, -3113227, 13974498),
array(12966261, 15550616, -32038948, -1615346, 21025980,
-629444, 5642325, 7188737, 18895762, 12629579),
),
),
array(
array(
array(14741879, -14946887, 22177208, -11721237, 1279741,
8058600, 11758140, 789443, 32195181, 3895677),
array(10758205, 15755439, -4509950, 9243698, -4879422,
6879879, -2204575, -3566119, -8982069, 4429647),
array(-2453894, 15725973, -20436342, -10410672, -5803908,
-11040220, -7135870, -11642895, 18047436, -15281743),
),
array(
array(-25173001, -11307165, 29759956, 11776784, -22262383,
-15820455, 10993114, -12850837, -17620701, -9408468),
array(21987233, 700364, -24505048, 14972008, -7774265,
-5718395, 32155026, 2581431, -29958985, 8773375),
array(-25568350, 454463, -13211935, 16126715, 25240068,
8594567, 20656846, 12017935, -7874389, -13920155),
),
array(
array(6028182, 6263078, -31011806, -11301710, -818919,
2461772, -31841174, -5468042, -1721788, -2776725),
array(-12278994, 16624277, 987579, -5922598, 32908203,
1248608, 7719845, -4166698, 28408820, 6816612),
array(-10358094, -8237829, 19549651, -12169222, 22082623,
16147817, 20613181, 13982702, -10339570, 5067943),
),
array(
array(-30505967, -3821767, 12074681, 13582412, -19877972,
2443951, -19719286, 12746132, 5331210, -10105944),
array(30528811, 3601899, -1957090, 4619785, -27361822,
-15436388, 24180793, -12570394, 27679908, -1648928),
array(9402404, -13957065, 32834043, 10838634, -26580150,
-13237195, 26653274, -8685565, 22611444, -12715406),
),
array(
array(22190590, 1118029, 22736441, 15130463, -30460692,
-5991321, 19189625, -4648942, 4854859, 6622139),
array(-8310738, -2953450, -8262579, -3388049, -10401731,
-271929, 13424426, -3567227, 26404409, 13001963),
array(-31241838, -15415700, -2994250, 8939346, 11562230,
-12840670, -26064365, -11621720, -15405155, 11020693),
),
array(
array(1866042, -7949489, -7898649, -10301010, 12483315,
13477547, 3175636, -12424163, 28761762, 1406734),
array(-448555, -1777666, 13018551, 3194501, -9580420,
-11161737, 24760585, -4347088, 25577411, -13378680),
array(-24290378, 4759345, -690653, -1852816, 2066747,
10693769, -29595790, 9884936, -9368926, 4745410),
),
array(
array(-9141284, 6049714, -19531061, -4341411, -31260798,
9944276, -15462008, -11311852, 10931924, -11931931),
array(-16561513, 14112680, -8012645, 4817318, -8040464,
-11414606, -22853429, 10856641, -20470770, 13434654),
array(22759489, -10073434, -16766264, -1871422, 13637442,
-10168091, 1765144, -12654326, 28445307, -5364710),
),
array(
array(29875063, 12493613, 2795536, -3786330, 1710620,
15181182, -10195717, -8788675, 9074234, 1167180),
array(-26205683, 11014233, -9842651, -2635485, -26908120,
7532294, -18716888, -9535498, 3843903, 9367684),
array(-10969595, -6403711, 9591134, 9582310, 11349256,
108879, 16235123, 8601684, -139197, 4242895),
),
),
array(
array(
array(22092954, -13191123, -2042793, -11968512, 32186753,
-11517388, -6574341, 2470660, -27417366, 16625501),
array(-11057722, 3042016, 13770083, -9257922, 584236,
-544855, -7770857, 2602725, -27351616, 14247413),
array(6314175, -10264892, -32772502, 15957557, -10157730,
168750, -8618807, 14290061, 27108877, -1180880),
),
array(
array(-8586597, -7170966, 13241782, 10960156, -32991015,
-13794596, 33547976, -11058889, -27148451, 981874),
array(22833440, 9293594, -32649448, -13618667, -9136966,
14756819, -22928859, -13970780, -10479804, -16197962),
array(-7768587, 3326786, -28111797, 10783824, 19178761,
14905060, 22680049, 13906969, -15933690, 3797899),
),
array(
array(21721356, -4212746, -12206123, 9310182, -3882239,
-13653110, 23740224, -2709232, 20491983, -8042152),
array(9209270, -15135055, -13256557, -6167798, -731016,
15289673, 25947805, 15286587, 30997318, -6703063),
array(7392032, 16618386, 23946583, -8039892, -13265164,
-1533858, -14197445, -2321576, 17649998, -250080),
),
array(
array(-9301088, -14193827, 30609526, -3049543, -25175069,
-1283752, -15241566, -9525724, -2233253, 7662146),
array(-17558673, 1763594, -33114336, 15908610, -30040870,
-12174295, 7335080, -8472199, -3174674, 3440183),
array(-19889700, -5977008, -24111293, -9688870, 10799743,
-16571957, 40450, -4431835, 4862400, 1133),
),
array(
array(-32856209, -7873957, -5422389, 14860950, -16319031,
7956142, 7258061, 311861, -30594991, -7379421),
array(-3773428, -1565936, 28985340, 7499440, 24445838,
9325937, 29727763, 16527196, 18278453, 15405622),
array(-4381906, 8508652, -19898366, -3674424, -5984453,
15149970, -13313598, 843523, -21875062, 13626197),
),
array(
array(2281448, -13487055, -10915418, -2609910, 1879358,
16164207, -10783882, 3953792, 13340839, 15928663),
array(31727126, -7179855, -18437503, -8283652, 2875793,
-16390330, -25269894, -7014826, -23452306, 5964753),
array(4100420, -5959452, -17179337, 6017714, -18705837,
12227141, -26684835, 11344144, 2538215, -7570755),
),
array(
array(-9433605, 6123113, 11159803, -2156608, 30016280,
14966241, -20474983, 1485421, -629256, -15958862),
array(-26804558, 4260919, 11851389, 9658551, -32017107,
16367492, -20205425, -13191288, 11659922, -11115118),
array(26180396, 10015009, -30844224, -8581293, 5418197,
9480663, 2231568, -10170080, 33100372, -1306171),
),
array(
array(15121113, -5201871, -10389905, 15427821, -27509937,
-15992507, 21670947, 4486675, -5931810, -14466380),
array(16166486, -9483733, -11104130, 6023908, -31926798,
-1364923, 2340060, -16254968, -10735770, -10039824),
array(28042865, -3557089, -12126526, 12259706, -3717498,
-6945899, 6766453, -8689599, 18036436, 5803270),
),
),
array(
array(
array(-817581, 6763912, 11803561, 1585585, 10958447,
-2671165, 23855391, 4598332, -6159431, -14117438),
array(-31031306, -14256194, 17332029, -2383520, 31312682,
-5967183, 696309, 50292, -20095739, 11763584),
array(-594563, -2514283, -32234153, 12643980, 12650761,
14811489, 665117, -12613632, -19773211, -10713562),
),
array(
array(30464590, -11262872, -4127476, -12734478, 19835327,
-7105613, -24396175, 2075773, -17020157, 992471),
array(18357185, -6994433, 7766382, 16342475, -29324918,
411174, 14578841, 8080033, -11574335, -10601610),
array(19598397, 10334610, 12555054, 2555664, 18821899,
-10339780, 21873263, 16014234, 26224780, 16452269),
),
array(
array(-30223925, 5145196, 5944548, 16385966, 3976735,
2009897, -11377804, -7618186, -20533829, 3698650),
array(14187449, 3448569, -10636236, -10810935, -22663880,
-3433596, 7268410, -10890444, 27394301, 12015369),
array(19695761, 16087646, 28032085, 12999827, 6817792,
11427614, 20244189, -1312777, -13259127, -3402461),
),
array(
array(30860103, 12735208, -1888245, -4699734, -16974906,
2256940, -8166013, 12298312, -8550524, -10393462),
array(-5719826, -11245325, -1910649, 15569035, 26642876,
-7587760, -5789354, -15118654, -4976164, 12651793),
array(-2848395, 9953421, 11531313, -5282879, 26895123,
-12697089, -13118820, -16517902, 9768698, -2533218),
),
array(
array(-24719459, 1894651, -287698, -4704085, 15348719,
-8156530, 32767513, 12765450, 4940095, 10678226),
array(18860224, 15980149, -18987240, -1562570, -26233012,
-11071856, -7843882, 13944024, -24372348, 16582019),
array(-15504260, 4970268, -29893044, 4175593, -20993212,
-2199756, -11704054, 15444560, -11003761, 7989037),
),
array(
array(31490452, 5568061, -2412803, 2182383, -32336847,
4531686, -32078269, 6200206, -19686113, -14800171),
array(-17308668, -15879940, -31522777, -2831, -32887382,
16375549, 8680158, -16371713, 28550068, -6857132),
array(-28126887, -5688091, 16837845, -1820458, -6850681,
12700016, -30039981, 4364038, 1155602, 5988841),
),
array(
array(21890435, -13272907, -12624011, 12154349, -7831873,
15300496, 23148983, -4470481, 24618407, 8283181),
array(-33136107, -10512751, 9975416, 6841041, -31559793,
16356536, 3070187, -7025928, 1466169, 10740210),
array(-1509399, -15488185, -13503385, -10655916, 32799044,
909394, -13938903, -5779719, -32164649, -15327040),
),
array(
array(3960823, -14267803, -28026090, -15918051, -19404858,
13146868, 15567327, 951507, -3260321, -573935),
array(24740841, 5052253, -30094131, 8961361, 25877428,
6165135, -24368180, 14397372, -7380369, -6144105),
array(-28888365, 3510803, -28103278, -1158478, -11238128,
-10631454, -15441463, -14453128, -1625486, -6494814),
),
),
array(
array(
array(793299, -9230478, 8836302, -6235707, -27360908,
-2369593, 33152843, -4885251, -9906200, -621852),
array(5666233, 525582, 20782575, -8038419, -24538499,
14657740, 16099374, 1468826, -6171428, -15186581),
array(-4859255, -3779343, -2917758, -6748019, 7778750,
11688288, -30404353, -9871238, -1558923, -9863646),
),
array(
array(10896332, -7719704, 824275, 472601, -19460308,
3009587, 25248958, 14783338, -30581476, -15757844),
array(10566929, 12612572, -31944212, 11118703, -12633376,
12362879, 21752402, 8822496, 24003793, 14264025),
array(27713862, -7355973, -11008240, 9227530, 27050101,
2504721, 23886875, -13117525, 13958495, -5732453),
),
array(
array(-23481610, 4867226, -27247128, 3900521, 29838369,
-8212291, -31889399, -10041781, 7340521, -15410068),
array(4646514, -8011124, -22766023, -11532654, 23184553,
8566613, 31366726, -1381061, -15066784, -10375192),
array(-17270517, 12723032, -16993061, 14878794, 21619651,
-6197576, 27584817, 3093888, -8843694, 3849921),
),
array(
array(-9064912, 2103172, 25561640, -15125738, -5239824,
9582958, 32477045, -9017955, 5002294, -15550259),
array(-12057553, -11177906, 21115585, -13365155, 8808712,
-12030708, 16489530, 13378448, -25845716, 12741426),
array(-5946367, 10645103, -30911586, 15390284, -3286982,
-7118677, 24306472, 15852464, 28834118, -7646072),
),
array(
array(-17335748, -9107057, -24531279, 9434953, -8472084,
-583362, -13090771, 455841, 20461858, 5491305),
array(13669248, -16095482, -12481974, -10203039, -14569770,
-11893198, -24995986, 11293807, -28588204, -9421832),
array(28497928, 6272777, -33022994, 14470570, 8906179,
-1225630, 18504674, -14165166, 29867745, -8795943),
),
array(
array(-16207023, 13517196, -27799630, -13697798, 24009064,
-6373891, -6367600, -13175392, 22853429, -4012011),
array(24191378, 16712145, -13931797, 15217831, 14542237,
1646131, 18603514, -11037887, 12876623, -2112447),
array(17902668, 4518229, -411702, -2829247, 26878217,
5258055, -12860753, 608397, 16031844, 3723494),
),
array(
array(-28632773, 12763728, -20446446, 7577504, 33001348,
-13017745, 17558842, -7872890, 23896954, -4314245),
array(-20005381, -12011952, 31520464, 605201, 2543521,
5991821, -2945064, 7229064, -9919646, -8826859),
array(28816045, 298879, -28165016, -15920938, 19000928,
-1665890, -12680833, -2949325, -18051778, -2082915),
),
array(
array(16000882, -344896, 3493092, -11447198, -29504595,
-13159789, 12577740, 16041268, -19715240, 7847707),
array(10151868, 10572098, 27312476, 7922682, 14825339,
4723128, -32855931, -6519018, -10020567, 3852848),
array(-11430470, 15697596, -21121557, -4420647, 5386314,
15063598, 16514493, -15932110, 29330899, -15076224),
),
),
array(
array(
array(-25499735, -4378794, -15222908, -6901211, 16615731,
2051784, 3303702, 15490, -27548796, 12314391),
array(15683520, -6003043, 18109120, -9980648, 15337968,
-5997823, -16717435, 15921866, 16103996, -3731215),
array(-23169824, -10781249, 13588192, -1628807, -3798557,
-1074929, -19273607, 5402699, -29815713, -9841101),
),
array(
array(23190676, 2384583, -32714340, 3462154, -29903655,
-1529132, -11266856, 8911517, -25205859, 2739713),
array(21374101, -3554250, -33524649, 9874411, 15377179,
11831242, -33529904, 6134907, 4931255, 11987849),
array(-7732, -2978858, -16223486, 7277597, 105524, -322051,
-31480539, 13861388, -30076310, 10117930),
),
array(
array(-29501170, -10744872, -26163768, 13051539, -25625564,
5089643, -6325503, 6704079, 12890019, 15728940),
array(-21972360, -11771379, -951059, -4418840, 14704840,
2695116, 903376, -10428139, 12885167, 8311031),
array(-17516482, 5352194, 10384213, -13811658, 7506451,
13453191, 26423267, 4384730, 1888765, -5435404),
),
array(
array(-25817338, -3107312, -13494599, -3182506, 30896459,
-13921729, -32251644, -12707869, -19464434, -3340243),
array(-23607977, -2665774, -526091, 4651136, 5765089,
4618330, 6092245, 14845197, 17151279, -9854116),
array(-24830458, -12733720, -15165978, 10367250, -29530908,
-265356, 22825805, -7087279, -16866484, 16176525),
),
array(
array(-23583256, 6564961, 20063689, 3798228, -4740178,
7359225, 2006182, -10363426, -28746253, -10197509),
array(-10626600, -4486402, -13320562, -5125317, 3432136,
-6393229, 23632037, -1940610, 32808310, 1099883),
array(15030977, 5768825, -27451236, -2887299, -6427378,
-15361371, -15277896, -6809350, 2051441, -15225865),
),
array(
array(-3362323, -7239372, 7517890, 9824992, 23555850,
295369, 5148398, -14154188, -22686354, 16633660),
array(4577086, -16752288, 13249841, -15304328, 19958763,
-14537274, 18559670, -10759549, 8402478, -9864273),
array(-28406330, -1051581, -26790155, -907698, -17212414,
-11030789, 9453451, -14980072, 17983010, 9967138),
),
array(
array(-25762494, 6524722, 26585488, 9969270, 24709298,
1220360, -1677990, 7806337, 17507396, 3651560),
array(-10420457, -4118111, 14584639, 15971087, -15768321,
8861010, 26556809, -5574557, -18553322, -11357135),
array(2839101, 14284142, 4029895, 3472686, 14402957,
12689363, -26642121, 8459447, -5605463, -7621941),
),
array(
array(-4839289, -3535444, 9744961, 2871048, 25113978,
3187018, -25110813, -849066, 17258084, -7977739),
array(18164541, -10595176, -17154882, -1542417, 19237078,
-9745295, 23357533, -15217008, 26908270, 12150756),
array(-30264870, -7647865, 5112249, -7036672, -1499807,
-6974257, 43168, -5537701, -32302074, 16215819),
),
),
array(
array(
array(-6898905, 9824394, -12304779, -4401089, -31397141,
-6276835, 32574489, 12532905, -7503072, -8675347),
array(-27343522, -16515468, -27151524, -10722951, 946346,
16291093, 254968, 7168080, 21676107, -1943028),
array(21260961, -8424752, -16831886, -11920822, -23677961,
3968121, -3651949, -6215466, -3556191, -7913075),
),
array(
array(16544754, 13250366, -16804428, 15546242, -4583003,
12757258, -2462308, -8680336, -18907032, -9662799),
array(-2415239, -15577728, 18312303, 4964443, -15272530,
-12653564, 26820651, 16690659, 25459437, -4564609),
array(-25144690, 11425020, 28423002, -11020557, -6144921,
-15826224, 9142795, -2391602, -6432418, -1644817),
),
array(
array(-23104652, 6253476, 16964147, -3768872, -25113972,
-12296437, -27457225, -16344658, 6335692, 7249989),
array(-30333227, 13979675, 7503222, -12368314, -11956721,
-4621693, -30272269, 2682242, 25993170, -12478523),
array(4364628, 5930691, 32304656, -10044554, -8054781,
15091131, 22857016, -10598955, 31820368, 15075278),
),
array(
array(31879134, -8918693, 17258761, 90626, -8041836,
-4917709, 24162788, -9650886, -17970238, 12833045),
array(19073683, 14851414, -24403169, -11860168, 7625278,
11091125, -19619190, 2074449, -9413939, 14905377),
array(24483667, -11935567, -2518866, -11547418, -1553130,
15355506, -25282080, 9253129, 27628530, -7555480),
),
array(
array(17597607, 8340603, 19355617, 552187, 26198470,
-3176583, 4593324, -9157582, -14110875, 15297016),
array(510886, 14337390, -31785257, 16638632, 6328095,
2713355, -20217417, -11864220, 8683221, 2921426),
array(18606791, 11874196, 27155355, -5281482, -24031742,
6265446, -25178240, -1278924, 4674690, 13890525),
),
array(
array(13609624, 13069022, -27372361, -13055908, 24360586,
9592974, 14977157, 9835105, 4389687, 288396),
array(9922506, -519394, 13613107, 5883594, -18758345,
-434263, -12304062, 8317628, 23388070, 16052080),
array(12720016, 11937594, -31970060, -5028689, 26900120,
8561328, -20155687, -11632979, -14754271, -10812892),
),
array(
array(15961858, 14150409, 26716931, -665832, -22794328,
13603569, 11829573, 7467844, -28822128, 929275),
array(11038231, -11582396, -27310482, -7316562, -10498527,
-16307831, -23479533, -9371869, -21393143, 2465074),
array(20017163, -4323226, 27915242, 1529148, 12396362,
15675764, 13817261, -9658066, 2463391, -4622140),
),
array(
array(-16358878, -12663911, -12065183, 4996454, -1256422,
1073572, 9583558, 12851107, 4003896, 12673717),
array(-1731589, -15155870, -3262930, 16143082, 19294135,
13385325, 14741514, -9103726, 7903886, 2348101),
array(24536016, -16515207, 12715592, -3862155, 1511293,
10047386, -3842346, -7129159, -28377538, 10048127),
),
),
array(
array(
array(-12622226, -6204820, 30718825, 2591312, -10617028,
12192840, 18873298, -7297090, -32297756, 15221632),
array(-26478122, -11103864, 11546244, -1852483, 9180880,
7656409, -21343950, 2095755, 29769758, 6593415),
array(-31994208, -2907461, 4176912, 3264766, 12538965,
-868111, 26312345, -6118678, 30958054, 8292160),
),
array(
array(31429822, -13959116, 29173532, 15632448, 12174511,
-2760094, 32808831, 3977186, 26143136, -3148876),
array(22648901, 1402143, -22799984, 13746059, 7936347,
365344, -8668633, -1674433, -3758243, -2304625),
array(-15491917, 8012313, -2514730, -12702462, -23965846,
-10254029, -1612713, -1535569, -16664475, 8194478),
),
array(
array(27338066, -7507420, -7414224, 10140405, -19026427,
-6589889, 27277191, 8855376, 28572286, 3005164),
array(26287124, 4821776, 25476601, -4145903, -3764513,
-15788984, -18008582, 1182479, -26094821, -13079595),
array(-7171154, 3178080, 23970071, 6201893, -17195577,
-4489192, -21876275, -13982627, 32208683, -1198248),
),
array(
array(-16657702, 2817643, -10286362, 14811298, 6024667,
13349505, -27315504, -10497842, -27672585, -11539858),
array(15941029, -9405932, -21367050, 8062055, 31876073,
-238629, -15278393, -1444429, 15397331, -4130193),
array(8934485, -13485467, -23286397, -13423241, -32446090,
14047986, 31170398, -1441021, -27505566, 15087184),
),
array(
array(-18357243, -2156491, 24524913, -16677868, 15520427,
-6360776, -15502406, 11461896, 16788528, -5868942),
array(-1947386, 16013773, 21750665, 3714552, -17401782,
-16055433, -3770287, -10323320, 31322514, -11615635),
array(21426655, -5650218, -13648287, -5347537, -28812189,
-4920970, -18275391, -14621414, 13040862, -12112948),
),
array(
array(11293895, 12478086, -27136401, 15083750, -29307421,
14748872, 14555558, -13417103, 1613711, 4896935),
array(-25894883, 15323294, -8489791, -8057900, 25967126,
-13425460, 2825960, -4897045, -23971776, -11267415),
array(-15924766, -5229880, -17443532, 6410664, 3622847,
10243618, 20615400, 12405433, -23753030, -8436416),
),
array(
array(-7091295, 12556208, -20191352, 9025187, -17072479,
4333801, 4378436, 2432030, 23097949, -566018),
array(4565804, -16025654, 20084412, -7842817, 1724999,
189254, 24767264, 10103221, -18512313, 2424778),
array(366633, -11976806, 8173090, -6890119, 30788634,
5745705, -7168678, 1344109, -3642553, 12412659),
),
array(
array(-24001791, 7690286, 14929416, -168257, -32210835,
-13412986, 24162697, -15326504, -3141501, 11179385),
array(18289522, -14724954, 8056945, 16430056, -21729724,
7842514, -6001441, -1486897, -18684645, -11443503),
array(476239, 6601091, -6152790, -9723375, 17503545,
-4863900, 27672959, 13403813, 11052904, 5219329),
),
),
array(
array(
array(20678546, -8375738, -32671898, 8849123, -5009758,
14574752, 31186971, -3973730, 9014762, -8579056),
array(-13644050, -10350239, -15962508, 5075808, -1514661,
-11534600, -33102500, 9160280, 8473550, -3256838),
array(24900749, 14435722, 17209120, -15292541, -22592275,
9878983, -7689309, -16335821, -24568481, 11788948),
),
array(
array(-3118155, -11395194, -13802089, 14797441, 9652448,
-6845904, -20037437, 10410733, -24568470, -1458691),
array(-15659161, 16736706, -22467150, 10215878, -9097177,
7563911, 11871841, -12505194, -18513325, 8464118),
array(-23400612, 8348507, -14585951, -861714, -3950205,
-6373419, 14325289, 8628612, 33313881, -8370517),
),
array(
array(-20186973, -4967935, 22367356, 5271547, -1097117,
-4788838, -24805667, -10236854, -8940735, -5818269),
array(-6948785, -1795212, -32625683, -16021179, 32635414,
-7374245, 15989197, -12838188, 28358192, -4253904),
array(-23561781, -2799059, -32351682, -1661963, -9147719,
10429267, -16637684, 4072016, -5351664, 5596589),
),
array(
array(-28236598, -3390048, 12312896, 6213178, 3117142,
16078565, 29266239, 2557221, 1768301, 15373193),
array(-7243358, -3246960, -4593467, -7553353, -127927,
-912245, -1090902, -4504991, -24660491, 3442910),
array(-30210571, 5124043, 14181784, 8197961, 18964734,
-11939093, 22597931, 7176455, -18585478, 13365930),
),
array(
array(-7877390, -1499958, 8324673, 4690079, 6261860,
890446, 24538107, -8570186, -9689599, -3031667),
array(25008904, -10771599, -4305031, -9638010, 16265036,
15721635, 683793, -11823784, 15723479, -15163481),
array(-9660625, 12374379, -27006999, -7026148, -7724114,
-12314514, 11879682, 5400171, 519526, -1235876),
),
array(
array(22258397, -16332233, -7869817, 14613016, -22520255,
-2950923, -20353881, 7315967, 16648397, 7605640),
array(-8081308, -8464597, -8223311, 9719710, 19259459,
-15348212, 23994942, -5281555, -9468848, 4763278),
array(-21699244, 9220969, -15730624, 1084137, -25476107,
-2852390, 31088447, -7764523, -11356529, 728112),
),
array(
array(26047220, -11751471, -6900323, -16521798, 24092068,
9158119, -4273545, -12555558, -29365436, -5498272),
array(17510331, -322857, 5854289, 8403524, 17133918,
-3112612, -28111007, 12327945, 10750447, 10014012),
array(-10312768, 3936952, 9156313, -8897683, 16498692,
-994647, -27481051, -666732, 3424691, 7540221),
),
array(
array(30322361, -6964110, 11361005, -4143317, 7433304,
4989748, -7071422, -16317219, -9244265, 15258046),
array(13054562, -2779497, 19155474, 469045, -12482797,
4566042, 5631406, 2711395, 1062915, -5136345),
array(-19240248, -11254599, -29509029, -7499965, -5835763,
13005411, -6066489, 12194497, 32960380, 1459310),
),
),
array(
array(
array(19852034, 7027924, 23669353, 10020366, 8586503,
-6657907, 394197, -6101885, 18638003, -11174937),
array(31395534, 15098109, 26581030, 8030562, -16527914,
-5007134, 9012486, -7584354, -6643087, -5442636),
array(-9192165, -2347377, -1997099, 4529534, 25766844,
607986, -13222, 9677543, -32294889, -6456008),
),
array(
array(-2444496, -149937, 29348902, 8186665, 1873760,
12489863, -30934579, -7839692, -7852844, -8138429),
array(-15236356, -15433509, 7766470, 746860, 26346930,
-10221762, -27333451, 10754588, -9431476, 5203576),
array(31834314, 14135496, -770007, 5159118, 20917671,
-16768096, -7467973, -7337524, 31809243, 7347066),
),
array(
array(-9606723, -11874240, 20414459, 13033986, 13716524,
-11691881, 19797970, -12211255, 15192876, -2087490),
array(-12663563, -2181719, 1168162, -3804809, 26747877,
-14138091, 10609330, 12694420, 33473243, -13382104),
array(33184999, 11180355, 15832085, -11385430, -1633671,
225884, 15089336, -11023903, -6135662, 14480053),
),
array(
array(31308717, -5619998, 31030840, -1897099, 15674547,
-6582883, 5496208, 13685227, 27595050, 8737275),
array(-20318852, -15150239, 10933843, -16178022, 8335352,
-7546022, -31008351, -12610604, 26498114, 66511),
array(22644454, -8761729, -16671776, 4884562, -3105614,
-13559366, 30540766, -4286747, -13327787, -7515095),
),
array(
array(-28017847, 9834845, 18617207, -2681312, -3401956,
-13307506, 8205540, 13585437, -17127465, 15115439),
array(23711543, -672915, 31206561, -8362711, 6164647,
-9709987, -33535882, -1426096, 8236921, 16492939),
array(-23910559, -13515526, -26299483, -4503841, 25005590,
-7687270, 19574902, 10071562, 6708380, -6222424),
),
array(
array(2101391, -4930054, 19702731, 2367575, -15427167,
1047675, 5301017, 9328700, 29955601, -11678310),
array(3096359, 9271816, -21620864, -15521844, -14847996,
-7592937, -25892142, -12635595, -9917575, 6216608),
array(-32615849, 338663, -25195611, 2510422, -29213566,
-13820213, 24822830, -6146567, -26767480, 7525079),
),
array(
array(-23066649, -13985623, 16133487, -7896178, -3389565,
778788, -910336, -2782495, -19386633, 11994101),
array(21691500, -13624626, -641331, -14367021, 3285881,
-3483596, -25064666, 9718258, -7477437, 13381418),
array(18445390, -4202236, 14979846, 11622458, -1727110,
-3582980, 23111648, -6375247, 28535282, 15779576),
),
array(
array(30098053, 3089662, -9234387, 16662135, -21306940,
11308411, -14068454, 12021730, 9955285, -16303356),
array(9734894, -14576830, -7473633, -9138735, 2060392,
11313496, -18426029, 9924399, 20194861, 13380996),
array(-26378102, -7965207, -22167821, 15789297, -18055342,
-6168792, -1984914, 15707771, 26342023, 10146099),
),
),
array(
array(
array(-26016874, -219943, 21339191, -41388, 19745256,
-2878700, -29637280, 2227040, 21612326, -545728),
array(-13077387, 1184228, 23562814, -5970442, -20351244,
-6348714, 25764461, 12243797, -20856566, 11649658),
array(-10031494, 11262626, 27384172, 2271902, 26947504,
-15997771, 39944, 6114064, 33514190, 2333242),
),
array(
array(-21433588, -12421821, 8119782, 7219913, -21830522,
-9016134, -6679750, -12670638, 24350578, -13450001),
array(-4116307, -11271533, -23886186, 4843615, -30088339,
690623, -31536088, -10406836, 8317860, 12352766),
array(18200138, -14475911, -33087759, -2696619, -23702521,
-9102511, -23552096, -2287550, 20712163, 6719373),
),
array(
array(26656208, 6075253, -7858556, 1886072, -28344043,
4262326, 11117530, -3763210, 26224235, -3297458),
array(-17168938, -14854097, -3395676, -16369877, -19954045,
14050420, 21728352, 9493610, 18620611, -16428628),
array(-13323321, 13325349, 11432106, 5964811, 18609221,
6062965, -5269471, -9725556, -30701573, -16479657),
),
array(
array(-23860538, -11233159, 26961357, 1640861, -32413112,
-16737940, 12248509, -5240639, 13735342, 1934062),
array(25089769, 6742589, 17081145, -13406266, 21909293,
-16067981, -15136294, -3765346, -21277997, 5473616),
array(31883677, -7961101, 1083432, -11572403, 22828471,
13290673, -7125085, 12469656, 29111212, -5451014),
),
array(
array(24244947, -15050407, -26262976, 2791540, -14997599,
16666678, 24367466, 6388839, -10295587, 452383),
array(-25640782, -3417841, 5217916, 16224624, 19987036,
-4082269, -24236251, -5915248, 15766062, 8407814),
array(-20406999, 13990231, 15495425, 16395525, 5377168,
15166495, -8917023, -4388953, -8067909, 2276718),
),
array(
array(30157918, 12924066, -17712050, 9245753, 19895028,
3368142, -23827587, 5096219, 22740376, -7303417),
array(2041139, -14256350, 7783687, 13876377, -25946985,
-13352459, 24051124, 13742383, -15637599, 13295222),
array(33338237, -8505733, 12532113, 7977527, 9106186,
-1715251, -17720195, -4612972, -4451357, -14669444),
),
array(
array(-20045281, 5454097, -14346548, 6447146, 28862071,
1883651, -2469266, -4141880, 7770569, 9620597),
array(23208068, 7979712, 33071466, 8149229, 1758231,
-10834995, 30945528, -1694323, -33502340, -14767970),
array(1439958, -16270480, -1079989, -793782, 4625402,
10647766, -5043801, 1220118, 30494170, -11440799),
),
array(
array(-5037580, -13028295, -2970559, -3061767, 15640974,
-6701666, -26739026, 926050, -1684339, -13333647),
array(13908495, -3549272, 30919928, -6273825, -21521863,
7989039, 9021034, 9078865, 3353509, 4033511),
array(-29663431, -15113610, 32259991, -344482, 24295849,
-12912123, 23161163, 8839127, 27485041, 7356032),
),
),
array(
array(
array(9661027, 705443, 11980065, -5370154, -1628543,
14661173, -6346142, 2625015, 28431036, -16771834),
array(-23839233, -8311415, -25945511, 7480958, -17681669,
-8354183, -22545972, 14150565, 15970762, 4099461),
array(29262576, 16756590, 26350592, -8793563, 8529671,
-11208050, 13617293, -9937143, 11465739, 8317062),
),
array(
array(-25493081, -6962928, 32500200, -9419051, -23038724,
-2302222, 14898637, 3848455, 20969334, -5157516),
array(-20384450, -14347713, -18336405, 13884722, -33039454,
2842114, -21610826, -3649888, 11177095, 14989547),
array(-24496721, -11716016, 16959896, 2278463, 12066309,
10137771, 13515641, 2581286, -28487508, 9930240),
),
array(
array(-17751622, -2097826, 16544300, -13009300, -15914807,
-14949081, 18345767, -13403753, 16291481, -5314038),
array(-33229194, 2553288, 32678213, 9875984, 8534129,
6889387, -9676774, 6957617, 4368891, 9788741),
array(16660756, 7281060, -10830758, 12911820, 20108584,
-8101676, -21722536, -8613148, 16250552, -11111103),
),
array(
array(-19765507, 2390526, -16551031, 14161980, 1905286,
6414907, 4689584, 10604807, -30190403, 4782747),
array(-1354539, 14736941, -7367442, -13292886, 7710542,
-14155590, -9981571, 4383045, 22546403, 437323),
array(31665577, -12180464, -16186830, 1491339, -18368625,
3294682, 27343084, 2786261, -30633590, -14097016),
),
array(
array(-14467279, -683715, -33374107, 7448552, 19294360,
14334329, -19690631, 2355319, -19284671, -6114373),
array(15121312, -15796162, 6377020, -6031361, -10798111,
-12957845, 18952177, 15496498, -29380133, 11754228),
array(-2637277, -13483075, 8488727, -14303896, 12728761,
-1622493, 7141596, 11724556, 22761615, -10134141),
),
array(
array(16918416, 11729663, -18083579, 3022987, -31015732,
-13339659, -28741185, -12227393, 32851222, 11717399),
array(11166634, 7338049, -6722523, 4531520, -29468672,
-7302055, 31474879, 3483633, -1193175, -4030831),
array(-185635, 9921305, 31456609, -13536438, -12013818,
13348923, 33142652, 6546660, -19985279, -3948376),
),
array(
array(-32460596, 11266712, -11197107, -7899103, 31703694,
3855903, -8537131, -12833048, -30772034, -15486313),
array(-18006477, 12709068, 3991746, -6479188, -21491523,
-10550425, -31135347, -16049879, 10928917, 3011958),
array(-6957757, -15594337, 31696059, 334240, 29576716,
14796075, -30831056, -12805180, 18008031, 10258577),
),
array(
array(-22448644, 15655569, 7018479, -4410003, -30314266,
-1201591, -1853465, 1367120, 25127874, 6671743),
array(29701166, -14373934, -10878120, 9279288, -17568,
13127210, 21382910, 11042292, 25838796, 4642684),
array(-20430234, 14955537, -24126347, 8124619, -5369288,
-5990470, 30468147, -13900640, 18423289, 4177476),
),
)
);
/**
* See: libsodium's crypto_core/curve25519/ref10/base2.h
*
* @var array basically int[8][3]
*/
protected static $base2 = array(
array(
array(25967493, -14356035, 29566456, 3660896, -12694345,
4014787, 27544626, -11754271, -6079156, 2047605),
array(-12545711, 934262, -2722910, 3049990, -727428, 9406986,
12720692, 5043384, 19500929, -15469378),
array(-8738181, 4489570, 9688441, -14785194, 10184609,
-12363380, 29287919, 11864899, -24514362, -4438546),
),
array(
array(15636291, -9688557, 24204773, -7912398, 616977,
-16685262, 27787600, -14772189, 28944400, -1550024),
array(16568933, 4717097, -11556148, -1102322, 15682896,
-11807043, 16354577, -11775962, 7689662, 11199574),
array(30464156, -5976125, -11779434, -15670865, 23220365,
15915852, 7512774, 10017326, -17749093, -9920357),
),
array(
array(10861363, 11473154, 27284546, 1981175, -30064349,
12577861, 32867885, 14515107, -15438304, 10819380),
array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696,
-25653668, 12483688, -12668491, 5581306),
array(19563160, 16186464, -29386857, 4097519, 10237984,
-4348115, 28542350, 13850243, -23678021, -15815942),
),
array(
array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873,
19480852, 5230134, -23952439, -15175766),
array(-30269007, -3463509, 7665486, 10083793, 28475525,
1649722, 20654025, 16520125, 30598449, 7715701),
array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316,
-31400660, 1370708, 29794553, -1409300),
),
array(
array(-22518993, -6692182, 14201702, -8745502, -23510406,
8844726, 18474211, -1361450, -13062696, 13821877),
array(-6455177, -7839871, 3374702, -4740862, -27098617,
-10571707, 31655028, -7212327, 18853322, -14220951),
array(4566830, -12963868, -28974889, -12240689, -7602672,
-2830569, -8514358, -10431137, 2207753, -3209784),
),
array(
array(-25154831, -4185821, 29681144, 7868801, -6854661,
-9423865, -12437364, -663000, -31111463, -16132436),
array(25576264, -2703214, 7349804, -11814844, 16472782,
9300885, 3844789, 15725684, 171356, 6466918),
array(23103977, 13316479, 9739013, -16149481, 817875,
-15038942, 8965339, -14088058, -30714912, 16193877),
),
array(
array(-33521811, 3180713, -2394130, 14003687, -16903474,
-16270840, 17238398, 4729455, -18074513, 9256800),
array(-25182317, -4174131, 32336398, 5036987, -21236817,
11360617, 22616405, 9761698, -19827198, 630305),
array(-13720693, 2639453, -24237460, -7406481, 9494427,
-5774029, -6554551, -15960994, -2449256, -14291300),
),
array(
array(-3151181, -5046075, 9282714, 6866145, -31907062, -863023,
-18940575, 15033784, 25105118, -7894876),
array(-24326370, 15950226, -31801215, -14592823, -11662737,
-5090925, 1573892, -2625887, 2198790, -15804619),
array(-3099351, 10324967, -2241613, 7453183, -5446979,
-2735503, -13812022, -16236442, -32461234, -12290683),
)
);
/**
*
37095705934669439343138083508754565189542113879843219016388785533085940283555
*
* @var array<int, int>
*/
protected static $d = array(
-10913610,
13857413,
-15372611,
6949391,
114729,
-8787816,
-6275908,
-3247719,
-18696448,
-12055116
);
/**
* 2 * d =
16295367250680780974490674513165176452449235426866156013048779062215315747161
*
* @var array<int, int>
*/
protected static $d2 = array(
-21827239,
-5839606,
-30745221,
13898782,
229458,
15978800,
-12551817,
-6495438,
29715968,
9444199
);
/**
* sqrt(-1)
*
* @var array<int, int>
*/
protected static $sqrtm1 = array(
-32595792,
-7943725,
9377950,
3500415,
12389472,
-272473,
-25146209,
-2005654,
326686,
11406482
);
}
# Curve25519 Data Structures
These are PHP implementation of the [structs used in the ref10 curve25519
code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h).
<?php
if (class_exists('ParagonIE_Sodium_Core_Curve25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519
*
* Implements Curve25519 core functions
*
* Based on the ref10 curve25519 code provided by libsodium
*
* @ref
https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c
*/
abstract class ParagonIE_Sodium_Core_Curve25519 extends
ParagonIE_Sodium_Core_Curve25519_H
{
/**
* Get a field element of size 10 with a value of 0
*
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_0()
{
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
);
}
/**
* Get a field element of size 10 with a value of 1
*
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_1()
{
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
);
}
/**
* Add two field elements.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
public static function fe_add(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g
) {
/** @var array<int, int> $arr */
$arr = array();
for ($i = 0; $i < 10; ++$i) {
$arr[$i] = (int) ($f[$i] + $g[$i]);
}
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($arr);
}
/**
* Constant-time conditional move.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @psalm-suppress MixedAssignment
*/
public static function fe_cmov(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g,
$b = 0
) {
/** @var array<int, int> $h */
$h = array();
$b *= -1;
for ($i = 0; $i < 10; ++$i) {
/** @var int $x */
$x = (($f[$i] ^ $g[$i]) & $b);
$h[$i] = (int) ((int) ($f[$i]) ^ $x);
}
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h);
}
/**
* Create a copy of a field element.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_copy(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$h = clone $f;
return $h;
}
/**
* Give: 32-byte string.
* Receive: A field element object to use for internal calculations.
*
* @internal You should not use this directly from another application
*
* @param string $s
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @throws RangeException
* @throws TypeError
*/
public static function fe_frombytes($s)
{
if (self::strlen($s) !== 32) {
throw new RangeException('Expected a 32-byte
string.');
}
/** @var int $h0 */
$h0 = self::load_4($s);
/** @var int $h1 */
$h1 = self::load_3(self::substr($s, 4, 3)) << 6;
/** @var int $h2 */
$h2 = self::load_3(self::substr($s, 7, 3)) << 5;
/** @var int $h3 */
$h3 = self::load_3(self::substr($s, 10, 3)) << 3;
/** @var int $h4 */
$h4 = self::load_3(self::substr($s, 13, 3)) << 2;
/** @var int $h5 */
$h5 = self::load_4(self::substr($s, 16, 4));
/** @var int $h6 */
$h6 = self::load_3(self::substr($s, 20, 3)) << 7;
/** @var int $h7 */
$h7 = self::load_3(self::substr($s, 23, 3)) << 5;
/** @var int $h8 */
$h8 = self::load_3(self::substr($s, 26, 3)) << 4;
/** @var int $h9 */
$h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607)
<< 2;
/** @var int $carry9 */
$carry9 = ($h9 + (1 << 24)) >> 25;
$h0 += self::mul($carry9, 19, 5);
$h9 -= $carry9 << 25;
/** @var int $carry1 */
$carry1 = ($h1 + (1 << 24)) >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
/** @var int $carry3 */
$carry3 = ($h3 + (1 << 24)) >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
/** @var int $carry5 */
$carry5 = ($h5 + (1 << 24)) >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
/** @var int $carry7 */
$carry7 = ($h7 + (1 << 24)) >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
/** @var int $carry0 */
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
/** @var int $carry2 */
$carry2 = ($h2 + (1 << 25)) >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
/** @var int $carry4 */
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
/** @var int $carry6 */
$carry6 = ($h6 + (1 << 25)) >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
/** @var int $carry8 */
$carry8 = ($h8 + (1 << 25)) >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) $h0,
(int) $h1,
(int) $h2,
(int) $h3,
(int) $h4,
(int) $h5,
(int) $h6,
(int) $h7,
(int) $h8,
(int) $h9
)
);
}
/**
* Convert a field element to a byte string.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $h
* @return string
*/
public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe
$h)
{
/** @var int $h0 */
$h0 = (int) $h[0];
/** @var int $h1 */
$h1 = (int) $h[1];
/** @var int $h2 */
$h2 = (int) $h[2];
/** @var int $h3 */
$h3 = (int) $h[3];
/** @var int $h4 */
$h4 = (int) $h[4];
/** @var int $h5 */
$h5 = (int) $h[5];
/** @var int $h6 */
$h6 = (int) $h[6];
/** @var int $h7 */
$h7 = (int) $h[7];
/** @var int $h8 */
$h8 = (int) $h[8];
/** @var int $h9 */
$h9 = (int) $h[9];
/** @var int $q */
$q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25;
/** @var int $q */
$q = ($h0 + $q) >> 26;
/** @var int $q */
$q = ($h1 + $q) >> 25;
/** @var int $q */
$q = ($h2 + $q) >> 26;
/** @var int $q */
$q = ($h3 + $q) >> 25;
/** @var int $q */
$q = ($h4 + $q) >> 26;
/** @var int $q */
$q = ($h5 + $q) >> 25;
/** @var int $q */
$q = ($h6 + $q) >> 26;
/** @var int $q */
$q = ($h7 + $q) >> 25;
/** @var int $q */
$q = ($h8 + $q) >> 26;
/** @var int $q */
$q = ($h9 + $q) >> 25;
$h0 += self::mul($q, 19, 5);
/** @var int $carry0 */
$carry0 = $h0 >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
/** @var int $carry1 */
$carry1 = $h1 >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
/** @var int $carry2 */
$carry2 = $h2 >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
/** @var int $carry3 */
$carry3 = $h3 >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
/** @var int $carry4 */
$carry4 = $h4 >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
/** @var int $carry5 */
$carry5 = $h5 >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
/** @var int $carry6 */
$carry6 = $h6 >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
/** @var int $carry7 */
$carry7 = $h7 >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
/** @var int $carry8 */
$carry8 = $h8 >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
/** @var int $carry9 */
$carry9 = $h9 >> 25;
$h9 -= $carry9 << 25;
/**
* @var array<int, int>
*/
$s = array(
(int) (($h0 >> 0) & 0xff),
(int) (($h0 >> 8) & 0xff),
(int) (($h0 >> 16) & 0xff),
(int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
(int) (($h1 >> 6) & 0xff),
(int) (($h1 >> 14) & 0xff),
(int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
(int) (($h2 >> 5) & 0xff),
(int) (($h2 >> 13) & 0xff),
(int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
(int) (($h3 >> 3) & 0xff),
(int) (($h3 >> 11) & 0xff),
(int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
(int) (($h4 >> 2) & 0xff),
(int) (($h4 >> 10) & 0xff),
(int) (($h4 >> 18) & 0xff),
(int) (($h5 >> 0) & 0xff),
(int) (($h5 >> 8) & 0xff),
(int) (($h5 >> 16) & 0xff),
(int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
(int) (($h6 >> 7) & 0xff),
(int) (($h6 >> 15) & 0xff),
(int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
(int) (($h7 >> 5) & 0xff),
(int) (($h7 >> 13) & 0xff),
(int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
(int) (($h8 >> 4) & 0xff),
(int) (($h8 >> 12) & 0xff),
(int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
(int) (($h9 >> 2) & 0xff),
(int) (($h9 >> 10) & 0xff),
(int) (($h9 >> 18) & 0xff)
);
return self::intArrayToString($s);
}
/**
* Is a field element negative? (1 = yes, 0 = no. Used in
calculations.)
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function
fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$str = self::fe_tobytes($f);
return (int) (self::chrToInt($str[0]) & 1);
}
/**
* Returns 0 if this field element results in all NUL bytes.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe
$f)
{
static $zero;
if ($zero === null) {
$zero = str_repeat("\x00", 32);
}
/** @var string $zero */
/** @var string $str */
$str = self::fe_tobytes($f);
return !self::verify_32($str, (string) $zero);
}
/**
* Multiply two field elements
*
* h = f * g
*
* @internal You should not use this directly from another application
*
* @security Is multiplication a source of timing leaks? If so, can we
do
* anything to prevent that from happening?
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_mul(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g
) {
/** @var int $f0 */
$f0 = $f[0];
/** @var int $f1 */
$f1 = $f[1];
/** @var int $f2 */
$f2 = $f[2];
/** @var int $f3 */
$f3 = $f[3];
/** @var int $f4 */
$f4 = $f[4];
/** @var int $f5 */
$f5 = $f[5];
/** @var int $f6 */
$f6 = $f[6];
/** @var int $f7 */
$f7 = $f[7];
/** @var int $f8 */
$f8 = $f[8];
/** @var int $f9 */
$f9 = $f[9];
/** @var int $g0 */
$g0 = $g[0];
/** @var int $g1 */
$g1 = $g[1];
/** @var int $g2 */
$g2 = $g[2];
/** @var int $g3 */
$g3 = $g[3];
/** @var int $g4 */
$g4 = $g[4];
/** @var int $g5 */
$g5 = $g[5];
/** @var int $g6 */
$g6 = $g[6];
/** @var int $g7 */
$g7 = $g[7];
/** @var int $g8 */
$g8 = $g[8];
/** @var int $g9 */
$g9 = $g[9];
$g1_19 = self::mul($g1, 19, 5);
$g2_19 = self::mul($g2, 19, 5);
$g3_19 = self::mul($g3, 19, 5);
$g4_19 = self::mul($g4, 19, 5);
$g5_19 = self::mul($g5, 19, 5);
$g6_19 = self::mul($g6, 19, 5);
$g7_19 = self::mul($g7, 19, 5);
$g8_19 = self::mul($g8, 19, 5);
$g9_19 = self::mul($g9, 19, 5);
/** @var int $f1_2 */
$f1_2 = $f1 << 1;
/** @var int $f3_2 */
$f3_2 = $f3 << 1;
/** @var int $f5_2 */
$f5_2 = $f5 << 1;
/** @var int $f7_2 */
$f7_2 = $f7 << 1;
/** @var int $f9_2 */
$f9_2 = $f9 << 1;
$f0g0 = self::mul($f0, $g0, 26);
$f0g1 = self::mul($f0, $g1, 25);
$f0g2 = self::mul($f0, $g2, 26);
$f0g3 = self::mul($f0, $g3, 25);
$f0g4 = self::mul($f0, $g4, 26);
$f0g5 = self::mul($f0, $g5, 25);
$f0g6 = self::mul($f0, $g6, 26);
$f0g7 = self::mul($f0, $g7, 25);
$f0g8 = self::mul($f0, $g8, 26);
$f0g9 = self::mul($f0, $g9, 26);
$f1g0 = self::mul($f1, $g0, 26);
$f1g1_2 = self::mul($f1_2, $g1, 25);
$f1g2 = self::mul($f1, $g2, 26);
$f1g3_2 = self::mul($f1_2, $g3, 25);
$f1g4 = self::mul($f1, $g4, 26);
$f1g5_2 = self::mul($f1_2, $g5, 25);
$f1g6 = self::mul($f1, $g6, 26);
$f1g7_2 = self::mul($f1_2, $g7, 25);
$f1g8 = self::mul($f1, $g8, 26);
$f1g9_38 = self::mul($g9_19, $f1_2, 26);
$f2g0 = self::mul($f2, $g0, 26);
$f2g1 = self::mul($f2, $g1, 25);
$f2g2 = self::mul($f2, $g2, 26);
$f2g3 = self::mul($f2, $g3, 25);
$f2g4 = self::mul($f2, $g4, 26);
$f2g5 = self::mul($f2, $g5, 25);
$f2g6 = self::mul($f2, $g6, 26);
$f2g7 = self::mul($f2, $g7, 25);
$f2g8_19 = self::mul($g8_19, $f2, 26);
$f2g9_19 = self::mul($g9_19, $f2, 26);
$f3g0 = self::mul($f3, $g0, 26);
$f3g1_2 = self::mul($f3_2, $g1, 25);
$f3g2 = self::mul($f3, $g2, 26);
$f3g3_2 = self::mul($f3_2, $g3, 25);
$f3g4 = self::mul($f3, $g4, 26);
$f3g5_2 = self::mul($f3_2, $g5, 25);
$f3g6 = self::mul($f3, $g6, 26);
$f3g7_38 = self::mul($g7_19, $f3_2, 26);
$f3g8_19 = self::mul($g8_19, $f3, 25);
$f3g9_38 = self::mul($g9_19, $f3_2, 26);
$f4g0 = self::mul($f4, $g0, 26);
$f4g1 = self::mul($f4, $g1, 25);
$f4g2 = self::mul($f4, $g2, 26);
$f4g3 = self::mul($f4, $g3, 25);
$f4g4 = self::mul($f4, $g4, 26);
$f4g5 = self::mul($f4, $g5, 25);
$f4g6_19 = self::mul($g6_19, $f4, 26);
$f4g7_19 = self::mul($g7_19, $f4, 26);
$f4g8_19 = self::mul($g8_19, $f4, 26);
$f4g9_19 = self::mul($g9_19, $f4, 26);
$f5g0 = self::mul($f5, $g0, 26);
$f5g1_2 = self::mul($f5_2, $g1, 25);
$f5g2 = self::mul($f5, $g2, 26);
$f5g3_2 = self::mul($f5_2, $g3, 25);
$f5g4 = self::mul($f5, $g4, 26);
$f5g5_38 = self::mul($g5_19, $f5_2, 26);
$f5g6_19 = self::mul($g6_19, $f5, 25);
$f5g7_38 = self::mul($g7_19, $f5_2, 26);
$f5g8_19 = self::mul($g8_19, $f5, 25);
$f5g9_38 = self::mul($g9_19, $f5_2, 26);
$f6g0 = self::mul($f6, $g0, 26);
$f6g1 = self::mul($f6, $g1, 25);
$f6g2 = self::mul($f6, $g2, 26);
$f6g3 = self::mul($f6, $g3, 25);
$f6g4_19 = self::mul($g4_19, $f6, 26);
$f6g5_19 = self::mul($g5_19, $f6, 26);
$f6g6_19 = self::mul($g6_19, $f6, 26);
$f6g7_19 = self::mul($g7_19, $f6, 26);
$f6g8_19 = self::mul($g8_19, $f6, 26);
$f6g9_19 = self::mul($g9_19, $f6, 26);
$f7g0 = self::mul($f7, $g0, 26);
$f7g1_2 = self::mul($f7_2, $g1, 25);
$f7g2 = self::mul($f7, $g2, 26);
$f7g3_38 = self::mul($g3_19, $f7_2, 26);
$f7g4_19 = self::mul($g4_19, $f7, 26);
$f7g5_38 = self::mul($g5_19, $f7_2, 26);
$f7g6_19 = self::mul($g6_19, $f7, 25);
$f7g7_38 = self::mul($g7_19, $f7_2, 26);
$f7g8_19 = self::mul($g8_19, $f7, 25);
$f7g9_38 = self::mul($g9_19,$f7_2, 26);
$f8g0 = self::mul($f8, $g0, 26);
$f8g1 = self::mul($f8, $g1, 25);
$f8g2_19 = self::mul($g2_19, $f8, 26);
$f8g3_19 = self::mul($g3_19, $f8, 26);
$f8g4_19 = self::mul($g4_19, $f8, 26);
$f8g5_19 = self::mul($g5_19, $f8, 26);
$f8g6_19 = self::mul($g6_19, $f8, 26);
$f8g7_19 = self::mul($g7_19, $f8, 26);
$f8g8_19 = self::mul($g8_19, $f8, 26);
$f8g9_19 = self::mul($g9_19, $f8, 26);
$f9g0 = self::mul($f9, $g0, 26);
$f9g1_38 = self::mul($g1_19, $f9_2, 26);
$f9g2_19 = self::mul($g2_19, $f9, 25);
$f9g3_38 = self::mul($g3_19, $f9_2, 26);
$f9g4_19 = self::mul($g4_19, $f9, 25);
$f9g5_38 = self::mul($g5_19, $f9_2, 26);
$f9g6_19 = self::mul($g6_19, $f9, 25);
$f9g7_38 = self::mul($g7_19, $f9_2, 26);
$f9g8_19 = self::mul($g8_19, $f9, 25);
$f9g9_38 = self::mul($g9_19, $f9_2, 26);
$h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38
+ $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
$h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19
+ $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
$h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38
+ $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
$h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19
+ $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
$h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38
+ $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
$h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0
+ $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
$h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2
+ $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38;
$h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2
+ $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19;
$h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2
+ $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38;
$h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4
+ $f6g3 + $f7g2 + $f8g1 + $f9g0 ;
/** @var int $carry0 */
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
/** @var int $carry4 */
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
/** @var int $carry1 */
$carry1 = ($h1 + (1 << 24)) >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
/** @var int $carry5 */
$carry5 = ($h5 + (1 << 24)) >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
/** @var int $carry2 */
$carry2 = ($h2 + (1 << 25)) >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
/** @var int $carry6 */
$carry6 = ($h6 + (1 << 25)) >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
/** @var int $carry3 */
$carry3 = ($h3 + (1 << 24)) >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
/** @var int $carry7 */
$carry7 = ($h7 + (1 << 24)) >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
/** @var int $carry4 */
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
/** @var int $carry8 */
$carry8 = ($h8 + (1 << 25)) >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
/** @var int $carry9 */
$carry9 = ($h9 + (1 << 24)) >> 25;
$h0 += self::mul($carry9, 19, 5);
$h9 -= $carry9 << 25;
/** @var int $carry0 */
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) $h0,
(int) $h1,
(int) $h2,
(int) $h3,
(int) $h4,
(int) $h5,
(int) $h6,
(int) $h7,
(int) $h8,
(int) $h9
)
);
}
/**
* Get the negative values for each piece of the field element.
*
* h = -f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @psalm-suppress MixedAssignment
*/
public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$h = new ParagonIE_Sodium_Core_Curve25519_Fe();
for ($i = 0; $i < 10; ++$i) {
$h[$i] = -$f[$i];
}
return $h;
}
/**
* Square a field element
*
* h = f * f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$f0 = (int) $f[0];
$f1 = (int) $f[1];
$f2 = (int) $f[2];
$f3 = (int) $f[3];
$f4 = (int) $f[4];
$f5 = (int) $f[5];
$f6 = (int) $f[6];
$f7 = (int) $f[7];
$f8 = (int) $f[8];
$f9 = (int) $f[9];
/** @var int $f0_2 */
$f0_2 = $f0 << 1;
/** @var int $f1_2 */
$f1_2 = $f1 << 1;
/** @var int $f2_2 */
$f2_2 = $f2 << 1;
/** @var int $f3_2 */
$f3_2 = $f3 << 1;
/** @var int $f4_2 */
$f4_2 = $f4 << 1;
/** @var int $f5_2 */
$f5_2 = $f5 << 1;
/** @var int $f6_2 */
$f6_2 = $f6 << 1;
/** @var int $f7_2 */
$f7_2 = $f7 << 1;
$f5_38 = self::mul($f5, 38, 6);
$f6_19 = self::mul($f6, 19, 5);
$f7_38 = self::mul($f7, 38, 6);
$f8_19 = self::mul($f8, 19, 5);
$f9_38 = self::mul($f9, 38, 6);
$f0f0 = self::mul($f0, $f0, 25);
$f0f1_2 = self::mul($f0_2, $f1, 24);
$f0f2_2 = self::mul($f0_2, $f2, 25);
$f0f3_2 = self::mul($f0_2, $f3, 24);
$f0f4_2 = self::mul($f0_2, $f4, 25);
$f0f5_2 = self::mul($f0_2, $f5, 25);
$f0f6_2 = self::mul($f0_2, $f6, 25);
$f0f7_2 = self::mul($f0_2, $f7, 24);
$f0f8_2 = self::mul($f0_2, $f8, 25);
$f0f9_2 = self::mul($f0_2, $f9, 25);
$f1f1_2 = self::mul($f1_2, $f1, 24);
$f1f2_2 = self::mul($f1_2, $f2, 25);
$f1f3_4 = self::mul($f1_2, $f3_2, 25);
$f1f4_2 = self::mul($f1_2, $f4, 25);
$f1f5_4 = self::mul($f1_2, $f5_2, 26);
$f1f6_2 = self::mul($f1_2, $f6, 25);
$f1f7_4 = self::mul($f1_2, $f7_2, 25);
$f1f8_2 = self::mul($f1_2, $f8, 25);
$f1f9_76 = self::mul($f9_38, $f1_2, 25);
$f2f2 = self::mul($f2, $f2, 25);
$f2f3_2 = self::mul($f2_2, $f3, 24);
$f2f4_2 = self::mul($f2_2, $f4, 25);
$f2f5_2 = self::mul($f2_2, $f5, 25);
$f2f6_2 = self::mul($f2_2, $f6, 25);
$f2f7_2 = self::mul($f2_2, $f7, 24);
$f2f8_38 = self::mul($f8_19, $f2_2, 26);
$f2f9_38 = self::mul($f9_38, $f2, 25);
$f3f3_2 = self::mul($f3_2, $f3, 24);
$f3f4_2 = self::mul($f3_2, $f4, 25);
$f3f5_4 = self::mul($f3_2, $f5_2, 26);
$f3f6_2 = self::mul($f3_2, $f6, 25);
$f3f7_76 = self::mul($f7_38, $f3_2, 25);
$f3f8_38 = self::mul($f8_19, $f3_2, 25);
$f3f9_76 = self::mul($f9_38, $f3_2, 25);
$f4f4 = self::mul($f4, $f4, 25);
$f4f5_2 = self::mul($f4_2, $f5, 25);
$f4f6_38 = self::mul($f6_19, $f4_2, 26);
$f4f7_38 = self::mul($f7_38, $f4, 25);
$f4f8_38 = self::mul($f8_19, $f4_2, 26);
$f4f9_38 = self::mul($f9_38, $f4, 25);
$f5f5_38 = self::mul($f5_38, $f5, 25);
$f5f6_38 = self::mul($f6_19, $f5_2, 26);
$f5f7_76 = self::mul($f7_38, $f5_2, 26);
$f5f8_38 = self::mul($f8_19, $f5_2, 26);
$f5f9_76 = self::mul($f9_38, $f5_2, 26);
$f6f6_19 = self::mul($f6_19, $f6, 25);
$f6f7_38 = self::mul($f7_38, $f6, 25);
$f6f8_38 = self::mul($f8_19, $f6_2, 26);
$f6f9_38 = self::mul($f9_38, $f6, 25);
$f7f7_38 = self::mul($f7_38, $f7, 24);
$f7f8_38 = self::mul($f8_19, $f7_2, 25);
$f7f9_76 = self::mul($f9_38, $f7_2, 25);
$f8f8_19 = self::mul($f8_19, $f8, 25);
$f8f9_38 = self::mul($f9_38, $f8, 25);
$f9f9_38 = self::mul($f9_38, $f9, 25);
$h0 = $f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 +
$f5f5_38;
$h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38;
$h2 = $f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 +
$f6f6_19;
$h3 = $f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38;
$h4 = $f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 +
$f7f7_38;
$h5 = $f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38;
$h6 = $f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 +
$f8f8_19;
$h7 = $f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38;
$h8 = $f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 +
$f9f9_38;
$h9 = $f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2;
/** @var int $carry0 */
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
/** @var int $carry4 */
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
/** @var int $carry1 */
$carry1 = ($h1 + (1 << 24)) >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
/** @var int $carry5 */
$carry5 = ($h5 + (1 << 24)) >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
/** @var int $carry2 */
$carry2 = ($h2 + (1 << 25)) >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
/** @var int $carry6 */
$carry6 = ($h6 + (1 << 25)) >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
/** @var int $carry3 */
$carry3 = ($h3 + (1 << 24)) >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
/** @var int $carry7 */
$carry7 = ($h7 + (1 << 24)) >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
/** @var int $carry4 */
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
/** @var int $carry8 */
$carry8 = ($h8 + (1 << 25)) >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
/** @var int $carry9 */
$carry9 = ($h9 + (1 << 24)) >> 25;
$h0 += self::mul($carry9, 19, 5);
$h9 -= $carry9 << 25;
/** @var int $carry0 */
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) $h0,
(int) $h1,
(int) $h2,
(int) $h3,
(int) $h4,
(int) $h5,
(int) $h6,
(int) $h7,
(int) $h8,
(int) $h9
)
);
}
/**
* Square and double a field element
*
* h = 2 * f * f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$f0 = (int) $f[0];
$f1 = (int) $f[1];
$f2 = (int) $f[2];
$f3 = (int) $f[3];
$f4 = (int) $f[4];
$f5 = (int) $f[5];
$f6 = (int) $f[6];
$f7 = (int) $f[7];
$f8 = (int) $f[8];
$f9 = (int) $f[9];
/** @var int $f0_2 */
$f0_2 = $f0 << 1;
/** @var int $f1_2 */
$f1_2 = $f1 << 1;
/** @var int $f2_2 */
$f2_2 = $f2 << 1;
/** @var int $f3_2 */
$f3_2 = $f3 << 1;
/** @var int $f4_2 */
$f4_2 = $f4 << 1;
/** @var int $f5_2 */
$f5_2 = $f5 << 1;
/** @var int $f6_2 */
$f6_2 = $f6 << 1;
/** @var int $f7_2 */
$f7_2 = $f7 << 1;
$f5_38 = self::mul($f5, 38, 6); /* 1.959375*2^30 */
$f6_19 = self::mul($f6, 19, 5); /* 1.959375*2^30 */
$f7_38 = self::mul($f7, 38, 6); /* 1.959375*2^30 */
$f8_19 = self::mul($f8, 19, 5); /* 1.959375*2^30 */
$f9_38 = self::mul($f9, 38, 6); /* 1.959375*2^30 */
$f0f0 = self::mul($f0, $f0, 24);
$f0f1_2 = self::mul($f0_2, $f1, 24);
$f0f2_2 = self::mul($f0_2, $f2, 24);
$f0f3_2 = self::mul($f0_2, $f3, 24);
$f0f4_2 = self::mul($f0_2, $f4, 24);
$f0f5_2 = self::mul($f0_2, $f5, 24);
$f0f6_2 = self::mul($f0_2, $f6, 24);
$f0f7_2 = self::mul($f0_2, $f7, 24);
$f0f8_2 = self::mul($f0_2, $f8, 24);
$f0f9_2 = self::mul($f0_2, $f9, 24);
$f1f1_2 = self::mul($f1_2, $f1, 24);
$f1f2_2 = self::mul($f1_2, $f2, 24);
$f1f3_4 = self::mul($f1_2, $f3_2, 24);
$f1f4_2 = self::mul($f1_2, $f4, 24);
$f1f5_4 = self::mul($f1_2, $f5_2, 24);
$f1f6_2 = self::mul($f1_2, $f6, 24);
$f1f7_4 = self::mul($f1_2, $f7_2, 24);
$f1f8_2 = self::mul($f1_2, $f8, 24);
$f1f9_76 = self::mul($f9_38, $f1_2, 24);
$f2f2 = self::mul($f2, $f2, 24);
$f2f3_2 = self::mul($f2_2, $f3, 24);
$f2f4_2 = self::mul($f2_2, $f4, 24);
$f2f5_2 = self::mul($f2_2, $f5, 24);
$f2f6_2 = self::mul($f2_2, $f6, 24);
$f2f7_2 = self::mul($f2_2, $f7, 24);
$f2f8_38 = self::mul($f8_19, $f2_2, 25);
$f2f9_38 = self::mul($f9_38, $f2, 24);
$f3f3_2 = self::mul($f3_2, $f3, 24);
$f3f4_2 = self::mul($f3_2, $f4, 24);
$f3f5_4 = self::mul($f3_2, $f5_2, 24);
$f3f6_2 = self::mul($f3_2, $f6, 24);
$f3f7_76 = self::mul($f7_38, $f3_2, 24);
$f3f8_38 = self::mul($f8_19, $f3_2, 24);
$f3f9_76 = self::mul($f9_38, $f3_2, 24);
$f4f4 = self::mul($f4, $f4, 24);
$f4f5_2 = self::mul($f4_2, $f5, 24);
$f4f6_38 = self::mul($f6_19, $f4_2, 25);
$f4f7_38 = self::mul($f7_38, $f4, 24);
$f4f8_38 = self::mul($f8_19, $f4_2, 25);
$f4f9_38 = self::mul($f9_38, $f4, 24);
$f5f5_38 = self::mul($f5_38, $f5, 24);
$f5f6_38 = self::mul($f6_19, $f5_2, 24);
$f5f7_76 = self::mul($f7_38, $f5_2, 24);
$f5f8_38 = self::mul($f8_19, $f5_2, 24);
$f5f9_76 = self::mul($f9_38, $f5_2, 24);
$f6f6_19 = self::mul($f6_19, $f6, 24);
$f6f7_38 = self::mul($f7_38, $f6, 24);
$f6f8_38 = self::mul($f8_19, $f6_2, 25);
$f6f9_38 = self::mul($f9_38, $f6, 24);
$f7f7_38 = self::mul($f7_38, $f7, 24);
$f7f8_38 = self::mul($f8_19, $f7_2, 24);
$f7f9_76 = self::mul($f9_38, $f7_2, 24);
$f8f8_19 = self::mul($f8_19, $f8, 24);
$f8f9_38 = self::mul($f9_38, $f8, 24);
$f9f9_38 = self::mul($f9_38, $f9, 24);
/** @var int $h0 */
$h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 +
$f5f5_38) << 1;
/** @var int $h1 */
$h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38)
<< 1;
/** @var int $h2 */
$h2 = (int) ($f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 +
$f6f6_19) << 1;
/** @var int $h3 */
$h3 = (int) ($f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38)
<< 1;
/** @var int $h4 */
$h4 = (int) ($f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 +
$f7f7_38) << 1;
/** @var int $h5 */
$h5 = (int) ($f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38)
<< 1;
/** @var int $h6 */
$h6 = (int) ($f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 +
$f8f8_19) << 1;
/** @var int $h7 */
$h7 = (int) ($f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38)
<< 1;
/** @var int $h8 */
$h8 = (int) ($f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 +
$f9f9_38) << 1;
/** @var int $h9 */
$h9 = (int) ($f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2)
<< 1;
/** @var int $carry0 */
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
/** @var int $carry4 */
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
/** @var int $carry1 */
$carry1 = ($h1 + (1 << 24)) >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
/** @var int $carry5 */
$carry5 = ($h5 + (1 << 24)) >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
/** @var int $carry2 */
$carry2 = ($h2 + (1 << 25)) >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
/** @var int $carry6 */
$carry6 = ($h6 + (1 << 25)) >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
/** @var int $carry3 */
$carry3 = ($h3 + (1 << 24)) >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
/** @var int $carry7 */
$carry7 = ($h7 + (1 << 24)) >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
/** @var int $carry4 */
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
/** @var int $carry8 */
$carry8 = ($h8 + (1 << 25)) >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
/** @var int $carry9 */
$carry9 = ($h9 + (1 << 24)) >> 25;
$h0 += self::mul($carry9, 19, 5);
$h9 -= $carry9 << 25;
/** @var int $carry0 */
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) $h0,
(int) $h1,
(int) $h2,
(int) $h3,
(int) $h4,
(int) $h5,
(int) $h6,
(int) $h7,
(int) $h8,
(int) $h9
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $Z
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe
$Z)
{
$z = clone $Z;
$t0 = self::fe_sq($z);
$t1 = self::fe_sq($t0);
$t1 = self::fe_sq($t1);
$t1 = self::fe_mul($z, $t1);
$t0 = self::fe_mul($t0, $t1);
$t2 = self::fe_sq($t0);
$t1 = self::fe_mul($t1, $t2);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 5; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 10; ++$i) {
$t2 = self::fe_sq($t2);
}
$t2 = self::fe_mul($t2, $t1);
$t3 = self::fe_sq($t2);
for ($i = 1; $i < 20; ++$i) {
$t3 = self::fe_sq($t3);
}
$t2 = self::fe_mul($t3, $t2);
$t2 = self::fe_sq($t2);
for ($i = 1; $i < 10; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 50; ++$i) {
$t2 = self::fe_sq($t2);
}
$t2 = self::fe_mul($t2, $t1);
$t3 = self::fe_sq($t2);
for ($i = 1; $i < 100; ++$i) {
$t3 = self::fe_sq($t3);
}
$t2 = self::fe_mul($t3, $t2);
$t2 = self::fe_sq($t2);
for ($i = 1; $i < 50; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
for ($i = 1; $i < 5; ++$i) {
$t1 = self::fe_sq($t1);
}
return self::fe_mul($t1, $t0);
}
/**
* @internal You should not use this directly from another application
*
* @ref
https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $z
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe
$z)
{
# fe_sq(t0, z);
# fe_sq(t1, t0);
# fe_sq(t1, t1);
# fe_mul(t1, z, t1);
# fe_mul(t0, t0, t1);
# fe_sq(t0, t0);
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_sq($z);
$t1 = self::fe_sq($t0);
$t1 = self::fe_sq($t1);
$t1 = self::fe_mul($z, $t1);
$t0 = self::fe_mul($t0, $t1);
$t0 = self::fe_sq($t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 5; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 5; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 10; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 10; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t1, t1, t0);
# fe_sq(t2, t1);
$t1 = self::fe_mul($t1, $t0);
$t2 = self::fe_sq($t1);
# for (i = 1; i < 20; ++i) {
# fe_sq(t2, t2);
# }
for ($i = 1; $i < 20; ++$i) {
$t2 = self::fe_sq($t2);
}
# fe_mul(t1, t2, t1);
# fe_sq(t1, t1);
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
# for (i = 1; i < 10; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 10; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 50; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 50; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t1, t1, t0);
# fe_sq(t2, t1);
$t1 = self::fe_mul($t1, $t0);
$t2 = self::fe_sq($t1);
# for (i = 1; i < 100; ++i) {
# fe_sq(t2, t2);
# }
for ($i = 1; $i < 100; ++$i) {
$t2 = self::fe_sq($t2);
}
# fe_mul(t1, t2, t1);
# fe_sq(t1, t1);
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
# for (i = 1; i < 50; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 50; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t0, t0);
# fe_sq(t0, t0);
# fe_mul(out, t0, z);
$t0 = self::fe_mul($t1, $t0);
$t0 = self::fe_sq($t0);
$t0 = self::fe_sq($t0);
return self::fe_mul($t0, $z);
}
/**
* Subtract two field elements.
*
* h = f - g
*
* Preconditions:
* |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
* |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
*
* Postconditions:
* |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @psalm-suppress MixedOperand
*/
public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g)
{
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
array(
(int) ($f[0] - $g[0]),
(int) ($f[1] - $g[1]),
(int) ($f[2] - $g[2]),
(int) ($f[3] - $g[3]),
(int) ($f[4] - $g[4]),
(int) ($f[5] - $g[5]),
(int) ($f[6] - $g[6]),
(int) ($f[7] - $g[7]),
(int) ($f[8] - $g[8]),
(int) ($f[9] - $g[9])
)
);
}
/**
* Add two group elements.
*
* r = p + q
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_add(
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
) {
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->YplusX);
$r->Y = self::fe_mul($r->Y, $q->YminusX);
$r->T = self::fe_mul($q->T2d, $p->T);
$r->X = self::fe_mul($p->Z, $q->Z);
$t0 = self::fe_add($r->X, $r->X);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_add($t0, $r->T);
$r->T = self::fe_sub($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @ref
https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
* @param string $a
* @return array<int, mixed>
* @throws SodiumException
* @throws TypeError
*/
public static function slide($a)
{
if (self::strlen($a) < 256) {
if (self::strlen($a) < 16) {
$a = str_pad($a, 256, '0', STR_PAD_RIGHT);
}
}
/** @var array<int, int> $r */
$r = array();
/** @var int $i */
for ($i = 0; $i < 256; ++$i) {
$r[$i] = (int) (
1 & (
self::chrToInt($a[(int) ($i >> 3)])
>>
($i & 7)
)
);
}
for ($i = 0;$i < 256;++$i) {
if ($r[$i]) {
for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
if ($r[$i + $b]) {
if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
$r[$i] += $r[$i + $b] << $b;
$r[$i + $b] = 0;
} elseif ($r[$i] - ($r[$i + $b] << $b) >=
-15) {
$r[$i] -= $r[$i + $b] << $b;
for ($k = $i + $b; $k < 256; ++$k) {
if (!$r[$k]) {
$r[$k] = 1;
break;
}
$r[$k] = 0;
}
} else {
break;
}
}
}
}
}
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param string $s
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function ge_frombytes_negate_vartime($s)
{
static $d = null;
if (!$d) {
$d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
}
# fe_frombytes(h->Y,s);
# fe_1(h->Z);
$h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
self::fe_0(),
self::fe_frombytes($s),
self::fe_1()
);
# fe_sq(u,h->Y);
# fe_mul(v,u,d);
# fe_sub(u,u,h->Z); /* u = y^2-1 */
# fe_add(v,v,h->Z); /* v = dy^2+1 */
$u = self::fe_sq($h->Y);
/** @var ParagonIE_Sodium_Core_Curve25519_Fe $d */
$v = self::fe_mul($u, $d);
$u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */
$v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */
# fe_sq(v3,v);
# fe_mul(v3,v3,v); /* v3 = v^3 */
# fe_sq(h->X,v3);
# fe_mul(h->X,h->X,v);
# fe_mul(h->X,h->X,u); /* x = uv^7 */
$v3 = self::fe_sq($v);
$v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
$h->X = self::fe_sq($v3);
$h->X = self::fe_mul($h->X, $v);
$h->X = self::fe_mul($h->X, $u); /* x = uv^7 */
# fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
# fe_mul(h->X,h->X,v3);
# fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */
$h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
$h->X = self::fe_mul($h->X, $v3);
$h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8)
*/
# fe_sq(vxx,h->X);
# fe_mul(vxx,vxx,v);
# fe_sub(check,vxx,u); /* vx^2-u */
$vxx = self::fe_sq($h->X);
$vxx = self::fe_mul($vxx, $v);
$check = self::fe_sub($vxx, $u); /* vx^2 - u */
# if (fe_isnonzero(check)) {
# fe_add(check,vxx,u); /* vx^2+u */
# if (fe_isnonzero(check)) {
# return -1;
# }
# fe_mul(h->X,h->X,sqrtm1);
# }
if (self::fe_isnonzero($check)) {
$check = self::fe_add($vxx, $u); /* vx^2 + u */
if (self::fe_isnonzero($check)) {
throw new RangeException('Internal check
failed.');
}
$h->X = self::fe_mul(
$h->X,
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1)
);
}
# if (fe_isnegative(h->X) == (s[31] >> 7)) {
# fe_neg(h->X,h->X);
# }
$i = self::chrToInt($s[31]);
if (self::fe_isnegative($h->X) === ($i >> 7)) {
$h->X = self::fe_neg($h->X);
}
# fe_mul(h->T,h->X,h->Y);
$h->T = self::fe_mul($h->X, $h->Y);
return $h;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_madd(
ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
) {
$r = clone $R;
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->yplusx);
$r->Y = self::fe_mul($r->Y, $q->yminusx);
$r->T = self::fe_mul($q->xy2d, $p->T);
$t0 = self::fe_add(clone $p->Z, clone $p->Z);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_add($t0, $r->T);
$r->T = self::fe_sub($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_msub(
ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
) {
$r = clone $R;
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->yminusx);
$r->Y = self::fe_mul($r->Y, $q->yplusx);
$r->T = self::fe_mul($q->xy2d, $p->T);
$t0 = self::fe_add($p->Z, $p->Z);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_sub($t0, $r->T);
$r->T = self::fe_add($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
public static function
ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
{
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2();
$r->X = self::fe_mul($p->X, $p->T);
$r->Y = self::fe_mul($p->Y, $p->Z);
$r->Z = self::fe_mul($p->Z, $p->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
public static function
ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
{
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
$r->X = self::fe_mul($p->X, $p->T);
$r->Y = self::fe_mul($p->Y, $p->Z);
$r->Z = self::fe_mul($p->Z, $p->T);
$r->T = self::fe_mul($p->X, $p->Y);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
public static function ge_p2_0()
{
return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
self::fe_0(),
self::fe_1(),
self::fe_1()
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2
$p)
{
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
$r->X = self::fe_sq($p->X);
$r->Z = self::fe_sq($p->Y);
$r->T = self::fe_sq2($p->Z);
$r->Y = self::fe_add($p->X, $p->Y);
$t0 = self::fe_sq($r->Y);
$r->Y = self::fe_add($r->Z, $r->X);
$r->Z = self::fe_sub($r->Z, $r->X);
$r->X = self::fe_sub($t0, $r->Y);
$r->T = self::fe_sub($r->T, $r->Z);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
public static function ge_p3_0()
{
return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
self::fe_0(),
self::fe_1(),
self::fe_1(),
self::fe_0()
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
*/
public static function
ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
{
static $d2 = null;
if ($d2 === null) {
$d2 =
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2);
}
/** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
$r->YplusX = self::fe_add($p->Y, $p->X);
$r->YminusX = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_copy($p->Z);
$r->T2d = self::fe_mul($p->T, $d2);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
public static function
ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
{
return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
$p->X,
$p->Y,
$p->Z
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
{
$recip = self::fe_invert($h->Z);
$x = self::fe_mul($h->X, $recip);
$y = self::fe_mul($h->Y, $recip);
$s = self::fe_tobytes($y);
$s[31] = self::intToChr(
self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
);
return $s;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3
$p)
{
$q = self::ge_p3_to_p2($p);
return self::ge_p2_dbl($q);
}
/**
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
*/
public static function ge_precomp_0()
{
return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
self::fe_1(),
self::fe_1(),
self::fe_0()
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $b
* @param int $c
* @return int
*/
public static function equal($b, $c)
{
return (int) ((($b ^ $c) - 1 & 0xffffffff) >> 31);
}
/**
* @internal You should not use this directly from another application
*
* @param int|string $char
* @return int (1 = yes, 0 = no)
* @throws SodiumException
* @throws TypeError
*/
public static function negative($char)
{
if (is_int($char)) {
return $char < 0 ? 1 : 0;
}
$x = self::chrToInt(self::substr($char, 0, 1));
return (int) ($x >> 63);
}
/**
* Conditional move
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
*/
public static function cmov(
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t,
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u,
$b
) {
if (!is_int($b)) {
throw new InvalidArgumentException('Expected an
integer.');
}
return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
self::fe_cmov($t->yplusx, $u->yplusx, $b),
self::fe_cmov($t->yminusx, $u->yminusx, $b),
self::fe_cmov($t->xy2d, $u->xy2d, $b)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $pos
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayOffset
*/
public static function ge_select($pos = 0, $b = 0)
{
static $base = null;
if ($base === null) {
$base = array();
/** @var int $i */
foreach (self::$base as $i => $bas) {
for ($j = 0; $j < 8; ++$j) {
$base[$i][$j] = new
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]),
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]),
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2])
);
}
}
}
/** @var array<int, array<int,
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp>> $base */
if (!is_int($pos)) {
throw new InvalidArgumentException('Position must be an
integer');
}
if ($pos < 0 || $pos > 31) {
throw new RangeException('Position is out of range [0,
31]');
}
/** @var int $bnegative */
$bnegative = self::negative($b);
/** @var int $babs */
$babs = $b - (((-$bnegative) & $b) << 1);
$t = self::ge_precomp_0();
for ($i = 0; $i < 8; ++$i) {
$t = self::cmov(
$t,
$base[$pos][$i],
self::equal($babs, $i + 1)
);
}
$minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
self::fe_copy($t->yminusx),
self::fe_copy($t->yplusx),
self::fe_neg($t->xy2d)
);
return self::cmov($t, $minusT, $bnegative);
}
/**
* Subtract two group elements.
*
* r = p - q
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
public static function ge_sub(
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
) {
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->YminusX);
$r->Y = self::fe_mul($r->Y, $q->YplusX);
$r->T = self::fe_mul($q->T2d, $p->T);
$r->X = self::fe_mul($p->Z, $q->Z);
$t0 = self::fe_add($r->X, $r->X);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_sub($t0, $r->T);
$r->T = self::fe_add($t0, $r->T);
return $r;
}
/**
* Convert a group element to a byte string.
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h)
{
$recip = self::fe_invert($h->Z);
$x = self::fe_mul($h->X, $recip);
$y = self::fe_mul($h->Y, $recip);
$s = self::fe_tobytes($y);
$s[31] = self::intToChr(
self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
);
return $s;
}
/**
* @internal You should not use this directly from another application
*
* @param string $a
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
* @param string $b
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
*/
public static function ge_double_scalarmult_vartime(
$a,
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A,
$b
) {
/** @var array<int,
ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai */
$Ai = array();
/** @var array<int,
ParagonIE_Sodium_Core_Curve25519_Ge_Precomp> $Bi */
static $Bi = array();
if (!$Bi) {
for ($i = 0; $i < 8; ++$i) {
$Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]),
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]),
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2])
);
}
}
for ($i = 0; $i < 8; ++$i) {
$Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
self::fe_0(),
self::fe_0(),
self::fe_0(),
self::fe_0()
);
}
# slide(aslide,a);
# slide(bslide,b);
/** @var array<int, int> $aslide */
$aslide = self::slide($a);
/** @var array<int, int> $bslide */
$bslide = self::slide($b);
# ge_p3_to_cached(&Ai[0],A);
# ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
$Ai[0] = self::ge_p3_to_cached($A);
$t = self::ge_p3_dbl($A);
$A2 = self::ge_p1p1_to_p3($t);
# ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[1],&u);
# ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[2],&u);
# ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[3],&u);
# ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[4],&u);
# ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[5],&u);
# ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[6],&u);
# ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[7],&u);
for ($i = 0; $i < 7; ++$i) {
$t = self::ge_add($A2, $Ai[$i]);
$u = self::ge_p1p1_to_p3($t);
$Ai[$i + 1] = self::ge_p3_to_cached($u);
}
# ge_p2_0(r);
$r = self::ge_p2_0();
# for (i = 255;i >= 0;--i) {
# if (aslide[i] || bslide[i]) break;
# }
$i = 255;
for (; $i >= 0; --$i) {
if ($aslide[$i] || $bslide[$i]) {
break;
}
}
# for (;i >= 0;--i) {
for (; $i >= 0; --$i) {
# ge_p2_dbl(&t,r);
$t = self::ge_p2_dbl($r);
# if (aslide[i] > 0) {
if ($aslide[$i] > 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_add(&t,&u,&Ai[aslide[i]/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_add(
$u,
$Ai[(int) floor($aslide[$i] / 2)]
);
# } else if (aslide[i] < 0) {
} elseif ($aslide[$i] < 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_sub(
$u,
$Ai[(int) floor(-$aslide[$i] / 2)]
);
}
# if (bslide[i] > 0) {
if ($bslide[$i] > 0) {
/** @var int $index */
$index = (int) floor($bslide[$i] / 2);
# ge_p1p1_to_p3(&u,&t);
# ge_madd(&t,&u,&Bi[bslide[i]/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_madd($t, $u, $Bi[$index]);
# } else if (bslide[i] < 0) {
} elseif ($bslide[$i] < 0) {
/** @var int $index */
$index = (int) floor(-$bslide[$i] / 2);
# ge_p1p1_to_p3(&u,&t);
# ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_msub($t, $u, $Bi[$index]);
}
# ge_p1p1_to_p2(r,&t);
$r = self::ge_p1p1_to_p2($t);
}
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param string $a
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
public static function ge_scalarmult_base($a)
{
/** @var array<int, int> $e */
$e = array();
$r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
for ($i = 0; $i < 32; ++$i) {
/** @var int $dbl */
$dbl = (int) $i << 1;
$e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
$e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) &
15;
}
/** @var int $carry */
$carry = 0;
for ($i = 0; $i < 63; ++$i) {
$e[$i] += $carry;
/** @var int $carry */
$carry = $e[$i] + 8;
/** @var int $carry */
$carry >>= 4;
$e[$i] -= $carry << 4;
}
/** @var array<int, int> $e */
$e[63] += (int) $carry;
$h = self::ge_p3_0();
for ($i = 1; $i < 64; $i += 2) {
$t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
$r = self::ge_madd($r, $h, $t);
$h = self::ge_p1p1_to_p3($r);
}
$r = self::ge_p3_dbl($h);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$h = self::ge_p1p1_to_p3($r);
for ($i = 0; $i < 64; $i += 2) {
$t = self::ge_select($i >> 1, (int) $e[$i]);
$r = self::ge_madd($r, $h, $t);
$h = self::ge_p1p1_to_p3($r);
}
return $h;
}
/**
* Calculates (ab + c) mod l
* where l = 2^252 + 27742317777372353535851937790883648493
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @param string $c
* @return string
* @throws TypeError
*/
public static function sc_muladd($a, $b, $c)
{
/** @var int $a0 */
$a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
/** @var int $a1 */
$a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >>
5);
/** @var int $a2 */
$a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >>
2);
/** @var int $a3 */
$a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >>
7);
/** @var int $a4 */
$a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >>
4);
/** @var int $a5 */
$a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >>
1);
/** @var int $a6 */
$a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >>
6);
/** @var int $a7 */
$a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >>
3);
/** @var int $a8 */
$a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
/** @var int $a9 */
$a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >>
5);
/** @var int $a10 */
$a10 = 2097151 & (self::load_3(self::substr($a, 26, 3))
>> 2);
/** @var int $a11 */
$a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);
/** @var int $b0 */
$b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
/** @var int $b1 */
$b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >>
5);
/** @var int $b2 */
$b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >>
2);
/** @var int $b3 */
$b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >>
7);
/** @var int $b4 */
$b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >>
4);
/** @var int $b5 */
$b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >>
1);
/** @var int $b6 */
$b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >>
6);
/** @var int $b7 */
$b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >>
3);
/** @var int $b8 */
$b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
/** @var int $b9 */
$b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >>
5);
/** @var int $b10 */
$b10 = 2097151 & (self::load_3(self::substr($b, 26, 3))
>> 2);
/** @var int $b11 */
$b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);
/** @var int $c0 */
$c0 = 2097151 & self::load_3(self::substr($c, 0, 3));
/** @var int $c1 */
$c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >>
5);
/** @var int $c2 */
$c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >>
2);
/** @var int $c3 */
$c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >>
7);
/** @var int $c4 */
$c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >>
4);
/** @var int $c5 */
$c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >>
1);
/** @var int $c6 */
$c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >>
6);
/** @var int $c7 */
$c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >>
3);
/** @var int $c8 */
$c8 = 2097151 & self::load_3(self::substr($c, 21, 3));
/** @var int $c9 */
$c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >>
5);
/** @var int $c10 */
$c10 = 2097151 & (self::load_3(self::substr($c, 26, 3))
>> 2);
/** @var int $c11 */
$c11 = (self::load_4(self::substr($c, 28, 4)) >> 7);
/* Can't really avoid the pyramid here: */
$s0 = $c0 + self::mul($a0, $b0, 24);
$s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24);
$s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) +
self::mul($a2, $b0, 24);
$s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) +
self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24);
$s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) +
self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) +
self::mul($a4, $b0, 24);
$s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) +
self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) +
self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24);
$s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) +
self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) +
self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) +
self::mul($a6, $b0, 24);
$s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) +
self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) +
self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) +
self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24);
$s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) +
self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) +
self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) +
self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) +
self::mul($a8, $b0, 24);
$s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) +
self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) +
self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) +
self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) +
self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24);
$s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) +
self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) +
self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) +
self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) +
self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) +
self::mul($a10, $b0, 24);
$s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) +
self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) +
self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) +
self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) +
self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) +
self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24);
$s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) +
self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) +
self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) +
self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) +
self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) +
self::mul($a11, $b1, 24);
$s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) +
self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) +
self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) +
self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) +
self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24);
$s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) +
self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) +
self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) +
self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) +
self::mul($a11, $b3, 24);
$s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) +
self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) +
self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) +
self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24);
$s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) +
self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) +
self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) +
self::mul($a11, $b5, 24);
$s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) +
self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) +
self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24);
$s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) +
self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) +
self::mul($a11, $b7, 24);
$s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) +
self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24);
$s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) +
self::mul($a11, $b9, 24);
$s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24);
$s22 = self::mul($a11, $b11, 24);
$s23 = 0;
/** @var int $carry0 */
$carry0 = ($s0 + (1 << 20)) >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
/** @var int $carry2 */
$carry2 = ($s2 + (1 << 20)) >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
/** @var int $carry4 */
$carry4 = ($s4 + (1 << 20)) >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
/** @var int $carry6 */
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
/** @var int $carry8 */
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
/** @var int $carry10 */
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/** @var int $carry12 */
$carry12 = ($s12 + (1 << 20)) >> 21;
$s13 += $carry12;
$s12 -= $carry12 << 21;
/** @var int $carry14 */
$carry14 = ($s14 + (1 << 20)) >> 21;
$s15 += $carry14;
$s14 -= $carry14 << 21;
/** @var int $carry16 */
$carry16 = ($s16 + (1 << 20)) >> 21;
$s17 += $carry16;
$s16 -= $carry16 << 21;
/** @var int $carry18 */
$carry18 = ($s18 + (1 << 20)) >> 21;
$s19 += $carry18;
$s18 -= $carry18 << 21;
/** @var int $carry20 */
$carry20 = ($s20 + (1 << 20)) >> 21;
$s21 += $carry20;
$s20 -= $carry20 << 21;
/** @var int $carry22 */
$carry22 = ($s22 + (1 << 20)) >> 21;
$s23 += $carry22;
$s22 -= $carry22 << 21;
/** @var int $carry1 */
$carry1 = ($s1 + (1 << 20)) >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
/** @var int $carry3 */
$carry3 = ($s3 + (1 << 20)) >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
/** @var int $carry5 */
$carry5 = ($s5 + (1 << 20)) >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
/** @var int $carry7 */
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
/** @var int $carry9 */
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
/** @var int $carry11 */
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
/** @var int $carry13 */
$carry13 = ($s13 + (1 << 20)) >> 21;
$s14 += $carry13;
$s13 -= $carry13 << 21;
/** @var int $carry15 */
$carry15 = ($s15 + (1 << 20)) >> 21;
$s16 += $carry15;
$s15 -= $carry15 << 21;
/** @var int $carry17 */
$carry17 = ($s17 + (1 << 20)) >> 21;
$s18 += $carry17;
$s17 -= $carry17 << 21;
/** @var int $carry19 */
$carry19 = ($s19 + (1 << 20)) >> 21;
$s20 += $carry19;
$s19 -= $carry19 << 21;
/** @var int $carry21 */
$carry21 = ($s21 + (1 << 20)) >> 21;
$s22 += $carry21;
$s21 -= $carry21 << 21;
$s11 += self::mul($s23, 666643, 20);
$s12 += self::mul($s23, 470296, 19);
$s13 += self::mul($s23, 654183, 20);
$s14 -= self::mul($s23, 997805, 20);
$s15 += self::mul($s23, 136657, 18);
$s16 -= self::mul($s23, 683901, 20);
$s10 += self::mul($s22, 666643, 20);
$s11 += self::mul($s22, 470296, 19);
$s12 += self::mul($s22, 654183, 20);
$s13 -= self::mul($s22, 997805, 20);
$s14 += self::mul($s22, 136657, 18);
$s15 -= self::mul($s22, 683901, 20);
$s9 += self::mul($s21, 666643, 20);
$s10 += self::mul($s21, 470296, 19);
$s11 += self::mul($s21, 654183, 20);
$s12 -= self::mul($s21, 997805, 20);
$s13 += self::mul($s21, 136657, 18);
$s14 -= self::mul($s21, 683901, 20);
$s8 += self::mul($s20, 666643, 20);
$s9 += self::mul($s20, 470296, 19);
$s10 += self::mul($s20, 654183, 20);
$s11 -= self::mul($s20, 997805, 20);
$s12 += self::mul($s20, 136657, 18);
$s13 -= self::mul($s20, 683901, 20);
$s7 += self::mul($s19, 666643, 20);
$s8 += self::mul($s19, 470296, 19);
$s9 += self::mul($s19, 654183, 20);
$s10 -= self::mul($s19, 997805, 20);
$s11 += self::mul($s19, 136657, 18);
$s12 -= self::mul($s19, 683901, 20);
$s6 += self::mul($s18, 666643, 20);
$s7 += self::mul($s18, 470296, 19);
$s8 += self::mul($s18, 654183, 20);
$s9 -= self::mul($s18, 997805, 20);
$s10 += self::mul($s18, 136657, 18);
$s11 -= self::mul($s18, 683901, 20);
/** @var int $carry6 */
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
/** @var int $carry8 */
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
/** @var int $carry10 */
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/** @var int $carry12 */
$carry12 = ($s12 + (1 << 20)) >> 21;
$s13 += $carry12;
$s12 -= $carry12 << 21;
/** @var int $carry14 */
$carry14 = ($s14 + (1 << 20)) >> 21;
$s15 += $carry14;
$s14 -= $carry14 << 21;
/** @var int $carry16 */
$carry16 = ($s16 + (1 << 20)) >> 21;
$s17 += $carry16;
$s16 -= $carry16 << 21;
/** @var int $carry7 */
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
/** @var int $carry9 */
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
/** @var int $carry11 */
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
/** @var int $carry13 */
$carry13 = ($s13 + (1 << 20)) >> 21;
$s14 += $carry13;
$s13 -= $carry13 << 21;
/** @var int $carry15 */
$carry15 = ($s15 + (1 << 20)) >> 21;
$s16 += $carry15;
$s15 -= $carry15 << 21;
$s5 += self::mul($s17, 666643, 20);
$s6 += self::mul($s17, 470296, 19);
$s7 += self::mul($s17, 654183, 20);
$s8 -= self::mul($s17, 997805, 20);
$s9 += self::mul($s17, 136657, 18);
$s10 -= self::mul($s17, 683901, 20);
$s4 += self::mul($s16, 666643, 20);
$s5 += self::mul($s16, 470296, 19);
$s6 += self::mul($s16, 654183, 20);
$s7 -= self::mul($s16, 997805, 20);
$s8 += self::mul($s16, 136657, 18);
$s9 -= self::mul($s16, 683901, 20);
$s3 += self::mul($s15, 666643, 20);
$s4 += self::mul($s15, 470296, 19);
$s5 += self::mul($s15, 654183, 20);
$s6 -= self::mul($s15, 997805, 20);
$s7 += self::mul($s15, 136657, 18);
$s8 -= self::mul($s15, 683901, 20);
$s2 += self::mul($s14, 666643, 20);
$s3 += self::mul($s14, 470296, 19);
$s4 += self::mul($s14, 654183, 20);
$s5 -= self::mul($s14, 997805, 20);
$s6 += self::mul($s14, 136657, 18);
$s7 -= self::mul($s14, 683901, 20);
$s1 += self::mul($s13, 666643, 20);
$s2 += self::mul($s13, 470296, 19);
$s3 += self::mul($s13, 654183, 20);
$s4 -= self::mul($s13, 997805, 20);
$s5 += self::mul($s13, 136657, 18);
$s6 -= self::mul($s13, 683901, 20);
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
/** @var int $carry0 */
$carry0 = ($s0 + (1 << 20)) >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
/** @var int $carry2 */
$carry2 = ($s2 + (1 << 20)) >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
/** @var int $carry4 */
$carry4 = ($s4 + (1 << 20)) >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
/** @var int $carry6 */
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
/** @var int $carry8 */
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
/** @var int $carry10 */
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/** @var int $carry1 */
$carry1 = ($s1 + (1 << 20)) >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
/** @var int $carry3 */
$carry3 = ($s3 + (1 << 20)) >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
/** @var int $carry5 */
$carry5 = ($s5 + (1 << 20)) >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
/** @var int $carry7 */
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
/** @var int $carry9 */
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
/** @var int $carry11 */
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
/** @var int $carry0 */
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
/** @var int $carry1 */
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
/** @var int $carry2 */
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
/** @var int $carry3 */
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
/** @var int $carry4 */
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
/** @var int $carry5 */
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
/** @var int $carry6 */
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
/** @var int $carry7 */
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
/** @var int $carry8 */
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
/** @var int $carry9 */
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
/** @var int $carry10 */
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/** @var int $carry11 */
$carry11 = $s11 >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
/** @var int $carry0 */
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
/** @var int $carry1 */
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
/** @var int $carry2 */
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
/** @var int $carry3 */
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
/** @var int $carry4 */
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
/** @var int $carry5 */
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
/** @var int $carry6 */
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
/** @var int $carry7 */
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
/** @var int $carry8 */
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
/** @var int $carry9 */
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
/** @var int $carry10 */
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/**
* @var array<int, int>
*/
$arr = array(
(int) (0xff & ($s0 >> 0)),
(int) (0xff & ($s0 >> 8)),
(int) (0xff & (($s0 >> 16) | $s1 << 5)),
(int) (0xff & ($s1 >> 3)),
(int) (0xff & ($s1 >> 11)),
(int) (0xff & (($s1 >> 19) | $s2 << 2)),
(int) (0xff & ($s2 >> 6)),
(int) (0xff & (($s2 >> 14) | $s3 << 7)),
(int) (0xff & ($s3 >> 1)),
(int) (0xff & ($s3 >> 9)),
(int) (0xff & (($s3 >> 17) | $s4 << 4)),
(int) (0xff & ($s4 >> 4)),
(int) (0xff & ($s4 >> 12)),
(int) (0xff & (($s4 >> 20) | $s5 << 1)),
(int) (0xff & ($s5 >> 7)),
(int) (0xff & (($s5 >> 15) | $s6 << 6)),
(int) (0xff & ($s6 >> 2)),
(int) (0xff & ($s6 >> 10)),
(int) (0xff & (($s6 >> 18) | $s7 << 3)),
(int) (0xff & ($s7 >> 5)),
(int) (0xff & ($s7 >> 13)),
(int) (0xff & ($s8 >> 0)),
(int) (0xff & ($s8 >> 8)),
(int) (0xff & (($s8 >> 16) | $s9 << 5)),
(int) (0xff & ($s9 >> 3)),
(int) (0xff & ($s9 >> 11)),
(int) (0xff & (($s9 >> 19) | $s10 << 2)),
(int) (0xff & ($s10 >> 6)),
(int) (0xff & (($s10 >> 14) | $s11 << 7)),
(int) (0xff & ($s11 >> 1)),
(int) (0xff & ($s11 >> 9)),
0xff & ($s11 >> 17)
);
return self::intArrayToString($arr);
}
/**
* @internal You should not use this directly from another application
*
* @param string $s
* @return string
* @throws TypeError
*/
public static function sc_reduce($s)
{
/** @var int $s0 */
$s0 = 2097151 & self::load_3(self::substr($s, 0, 3));
/** @var int $s1 */
$s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >>
5);
/** @var int $s2 */
$s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >>
2);
/** @var int $s3 */
$s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >>
7);
/** @var int $s4 */
$s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >>
4);
/** @var int $s5 */
$s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >>
1);
/** @var int $s6 */
$s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >>
6);
/** @var int $s7 */
$s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >>
3);
/** @var int $s8 */
$s8 = 2097151 & self::load_3(self::substr($s, 21, 3));
/** @var int $s9 */
$s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >>
5);
/** @var int $s10 */
$s10 = 2097151 & (self::load_3(self::substr($s, 26, 3))
>> 2);
/** @var int $s11 */
$s11 = 2097151 & (self::load_4(self::substr($s, 28, 4))
>> 7);
/** @var int $s12 */
$s12 = 2097151 & (self::load_4(self::substr($s, 31, 4))
>> 4);
/** @var int $s13 */
$s13 = 2097151 & (self::load_3(self::substr($s, 34, 3))
>> 1);
/** @var int $s14 */
$s14 = 2097151 & (self::load_4(self::substr($s, 36, 4))
>> 6);
/** @var int $s15 */
$s15 = 2097151 & (self::load_3(self::substr($s, 39, 4))
>> 3);
/** @var int $s16 */
$s16 = 2097151 & self::load_3(self::substr($s, 42, 3));
/** @var int $s17 */
$s17 = 2097151 & (self::load_4(self::substr($s, 44, 4))
>> 5);
/** @var int $s18 */
$s18 = 2097151 & (self::load_3(self::substr($s, 47, 3))
>> 2);
/** @var int $s19 */
$s19 = 2097151 & (self::load_4(self::substr($s, 49, 4))
>> 7);
/** @var int $s20 */
$s20 = 2097151 & (self::load_4(self::substr($s, 52, 4))
>> 4);
/** @var int $s21 */
$s21 = 2097151 & (self::load_3(self::substr($s, 55, 3))
>> 1);
/** @var int $s22 */
$s22 = 2097151 & (self::load_4(self::substr($s, 57, 4))
>> 6);
/** @var int $s23 */
$s23 = (self::load_4(self::substr($s, 60, 4)) >> 3);
$s11 += self::mul($s23, 666643, 20);
$s12 += self::mul($s23, 470296, 19);
$s13 += self::mul($s23, 654183, 20);
$s14 -= self::mul($s23, 997805, 20);
$s15 += self::mul($s23, 136657, 18);
$s16 -= self::mul($s23, 683901, 20);
$s10 += self::mul($s22, 666643, 20);
$s11 += self::mul($s22, 470296, 19);
$s12 += self::mul($s22, 654183, 20);
$s13 -= self::mul($s22, 997805, 20);
$s14 += self::mul($s22, 136657, 18);
$s15 -= self::mul($s22, 683901, 20);
$s9 += self::mul($s21, 666643, 20);
$s10 += self::mul($s21, 470296, 19);
$s11 += self::mul($s21, 654183, 20);
$s12 -= self::mul($s21, 997805, 20);
$s13 += self::mul($s21, 136657, 18);
$s14 -= self::mul($s21, 683901, 20);
$s8 += self::mul($s20, 666643, 20);
$s9 += self::mul($s20, 470296, 19);
$s10 += self::mul($s20, 654183, 20);
$s11 -= self::mul($s20, 997805, 20);
$s12 += self::mul($s20, 136657, 18);
$s13 -= self::mul($s20, 683901, 20);
$s7 += self::mul($s19, 666643, 20);
$s8 += self::mul($s19, 470296, 19);
$s9 += self::mul($s19, 654183, 20);
$s10 -= self::mul($s19, 997805, 20);
$s11 += self::mul($s19, 136657, 18);
$s12 -= self::mul($s19, 683901, 20);
$s6 += self::mul($s18, 666643, 20);
$s7 += self::mul($s18, 470296, 19);
$s8 += self::mul($s18, 654183, 20);
$s9 -= self::mul($s18, 997805, 20);
$s10 += self::mul($s18, 136657, 18);
$s11 -= self::mul($s18, 683901, 20);
/** @var int $carry6 */
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
/** @var int $carry8 */
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
/** @var int $carry10 */
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/** @var int $carry12 */
$carry12 = ($s12 + (1 << 20)) >> 21;
$s13 += $carry12;
$s12 -= $carry12 << 21;
/** @var int $carry14 */
$carry14 = ($s14 + (1 << 20)) >> 21;
$s15 += $carry14;
$s14 -= $carry14 << 21;
/** @var int $carry16 */
$carry16 = ($s16 + (1 << 20)) >> 21;
$s17 += $carry16;
$s16 -= $carry16 << 21;
/** @var int $carry7 */
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
/** @var int $carry9 */
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
/** @var int $carry11 */
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
/** @var int $carry13 */
$carry13 = ($s13 + (1 << 20)) >> 21;
$s14 += $carry13;
$s13 -= $carry13 << 21;
/** @var int $carry15 */
$carry15 = ($s15 + (1 << 20)) >> 21;
$s16 += $carry15;
$s15 -= $carry15 << 21;
$s5 += self::mul($s17, 666643, 20);
$s6 += self::mul($s17, 470296, 19);
$s7 += self::mul($s17, 654183, 20);
$s8 -= self::mul($s17, 997805, 20);
$s9 += self::mul($s17, 136657, 18);
$s10 -= self::mul($s17, 683901, 20);
$s4 += self::mul($s16, 666643, 20);
$s5 += self::mul($s16, 470296, 19);
$s6 += self::mul($s16, 654183, 20);
$s7 -= self::mul($s16, 997805, 20);
$s8 += self::mul($s16, 136657, 18);
$s9 -= self::mul($s16, 683901, 20);
$s3 += self::mul($s15, 666643, 20);
$s4 += self::mul($s15, 470296, 19);
$s5 += self::mul($s15, 654183, 20);
$s6 -= self::mul($s15, 997805, 20);
$s7 += self::mul($s15, 136657, 18);
$s8 -= self::mul($s15, 683901, 20);
$s2 += self::mul($s14, 666643, 20);
$s3 += self::mul($s14, 470296, 19);
$s4 += self::mul($s14, 654183, 20);
$s5 -= self::mul($s14, 997805, 20);
$s6 += self::mul($s14, 136657, 18);
$s7 -= self::mul($s14, 683901, 20);
$s1 += self::mul($s13, 666643, 20);
$s2 += self::mul($s13, 470296, 19);
$s3 += self::mul($s13, 654183, 20);
$s4 -= self::mul($s13, 997805, 20);
$s5 += self::mul($s13, 136657, 18);
$s6 -= self::mul($s13, 683901, 20);
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
/** @var int $carry0 */
$carry0 = ($s0 + (1 << 20)) >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
/** @var int $carry2 */
$carry2 = ($s2 + (1 << 20)) >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
/** @var int $carry4 */
$carry4 = ($s4 + (1 << 20)) >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
/** @var int $carry6 */
$carry6 = ($s6 + (1 << 20)) >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
/** @var int $carry8 */
$carry8 = ($s8 + (1 << 20)) >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
/** @var int $carry10 */
$carry10 = ($s10 + (1 << 20)) >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/** @var int $carry1 */
$carry1 = ($s1 + (1 << 20)) >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
/** @var int $carry3 */
$carry3 = ($s3 + (1 << 20)) >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
/** @var int $carry5 */
$carry5 = ($s5 + (1 << 20)) >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
/** @var int $carry7 */
$carry7 = ($s7 + (1 << 20)) >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
/** @var int $carry9 */
$carry9 = ($s9 + (1 << 20)) >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
/** @var int $carry11 */
$carry11 = ($s11 + (1 << 20)) >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
$s12 = 0;
/** @var int $carry0 */
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
/** @var int $carry1 */
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
/** @var int $carry2 */
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
/** @var int $carry3 */
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
/** @var int $carry4 */
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
/** @var int $carry5 */
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
/** @var int $carry6 */
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
/** @var int $carry7 */
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
/** @var int $carry8 */
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
/** @var int $carry9 */
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
/** @var int $carry10 */
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/** @var int $carry11 */
$carry11 = $s11 >> 21;
$s12 += $carry11;
$s11 -= $carry11 << 21;
$s0 += self::mul($s12, 666643, 20);
$s1 += self::mul($s12, 470296, 19);
$s2 += self::mul($s12, 654183, 20);
$s3 -= self::mul($s12, 997805, 20);
$s4 += self::mul($s12, 136657, 18);
$s5 -= self::mul($s12, 683901, 20);
/** @var int $carry0 */
$carry0 = $s0 >> 21;
$s1 += $carry0;
$s0 -= $carry0 << 21;
/** @var int $carry1 */
$carry1 = $s1 >> 21;
$s2 += $carry1;
$s1 -= $carry1 << 21;
/** @var int $carry2 */
$carry2 = $s2 >> 21;
$s3 += $carry2;
$s2 -= $carry2 << 21;
/** @var int $carry3 */
$carry3 = $s3 >> 21;
$s4 += $carry3;
$s3 -= $carry3 << 21;
/** @var int $carry4 */
$carry4 = $s4 >> 21;
$s5 += $carry4;
$s4 -= $carry4 << 21;
/** @var int $carry5 */
$carry5 = $s5 >> 21;
$s6 += $carry5;
$s5 -= $carry5 << 21;
/** @var int $carry6 */
$carry6 = $s6 >> 21;
$s7 += $carry6;
$s6 -= $carry6 << 21;
/** @var int $carry7 */
$carry7 = $s7 >> 21;
$s8 += $carry7;
$s7 -= $carry7 << 21;
/** @var int $carry8 */
$carry8 = $s8 >> 21;
$s9 += $carry8;
$s8 -= $carry8 << 21;
/** @var int $carry9 */
$carry9 = $s9 >> 21;
$s10 += $carry9;
$s9 -= $carry9 << 21;
/** @var int $carry10 */
$carry10 = $s10 >> 21;
$s11 += $carry10;
$s10 -= $carry10 << 21;
/**
* @var array<int, int>
*/
$arr = array(
(int) ($s0 >> 0),
(int) ($s0 >> 8),
(int) (($s0 >> 16) | $s1 << 5),
(int) ($s1 >> 3),
(int) ($s1 >> 11),
(int) (($s1 >> 19) | $s2 << 2),
(int) ($s2 >> 6),
(int) (($s2 >> 14) | $s3 << 7),
(int) ($s3 >> 1),
(int) ($s3 >> 9),
(int) (($s3 >> 17) | $s4 << 4),
(int) ($s4 >> 4),
(int) ($s4 >> 12),
(int) (($s4 >> 20) | $s5 << 1),
(int) ($s5 >> 7),
(int) (($s5 >> 15) | $s6 << 6),
(int) ($s6 >> 2),
(int) ($s6 >> 10),
(int) (($s6 >> 18) | $s7 << 3),
(int) ($s7 >> 5),
(int) ($s7 >> 13),
(int) ($s8 >> 0),
(int) ($s8 >> 8),
(int) (($s8 >> 16) | $s9 << 5),
(int) ($s9 >> 3),
(int) ($s9 >> 11),
(int) (($s9 >> 19) | $s10 << 2),
(int) ($s10 >> 6),
(int) (($s10 >> 14) | $s11 << 7),
(int) ($s11 >> 1),
(int) ($s11 >> 9),
(int) $s11 >> 17
);
return self::intArrayToString($arr);
}
/**
* multiply by the order of the main subgroup l =
2^252+27742317777372353535851937790883648493
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
public static function ge_mul_l(ParagonIE_Sodium_Core_Curve25519_Ge_P3
$A)
{
/** @var array<int, int> $aslide */
$aslide = array(
13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0,
0, 0,
0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3,
0,
0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0,
0,
0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0,
-1,
0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0,
0,
0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
);
/** @var array<int,
ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai size 8 */
$Ai = array();
# ge_p3_to_cached(&Ai[0], A);
$Ai[0] = self::ge_p3_to_cached($A);
# ge_p3_dbl(&t, A);
$t = self::ge_p3_dbl($A);
# ge_p1p1_to_p3(&A2, &t);
$A2 = self::ge_p1p1_to_p3($t);
for ($i = 1; $i < 8; ++$i) {
# ge_add(&t, &A2, &Ai[0]);
$t = self::ge_add($A2, $Ai[$i - 1]);
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_p3_to_cached(&Ai[i], &u);
$Ai[$i] = self::ge_p3_to_cached($u);
}
$r = self::ge_p3_0();
for ($i = 252; $i >= 0; --$i) {
$t = self::ge_p3_dbl($r);
if ($aslide[$i] > 0) {
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_add(&t, &u, &Ai[aslide[i] / 2]);
$t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
} elseif ($aslide[$i] < 0) {
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
$t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
}
}
# ge_p1p1_to_p3(r, &t);
return self::ge_p1p1_to_p3($t);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Ed25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Ed25519
*/
abstract class ParagonIE_Sodium_Core_Ed25519 extends
ParagonIE_Sodium_Core_Curve25519
{
const KEYPAIR_BYTES = 96;
const SEED_BYTES = 32;
/**
* @internal You should not use this directly from another application
*
* @return string (96 bytes)
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function keypair()
{
$seed = random_bytes(self::SEED_BYTES);
$pk = '';
$sk = '';
self::seed_keypair($pk, $sk, $seed);
return $sk . $pk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $pk
* @param string $sk
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function seed_keypair(&$pk, &$sk, $seed)
{
if (self::strlen($seed) !== self::SEED_BYTES) {
throw new RangeException('crypto_sign keypair seed must be
32 bytes long');
}
/** @var string $pk */
$pk = self::publickey_from_secretkey($seed);
$sk = $seed . $pk;
return $sk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function secretkey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96
bytes long');
}
return self::substr($keypair, 0, 64);
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function publickey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96
bytes long');
}
return self::substr($keypair, 64, 32);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function publickey_from_secretkey($sk)
{
/** @var string $sk */
$sk = hash('sha512', self::substr($sk, 0, 32), true);
$sk[0] = self::intToChr(
self::chrToInt($sk[0]) & 248
);
$sk[31] = self::intToChr(
(self::chrToInt($sk[31]) & 63) | 64
);
return self::sk_to_pk($sk);
}
/**
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function pk_to_curve25519($pk)
{
if (self::small_order($pk)) {
throw new SodiumException('Public key is on a small
order');
}
$A = self::ge_frombytes_negate_vartime(self::substr($pk, 0, 32));
$p1 = self::ge_mul_l($A);
if (!self::fe_isnonzero($p1->X)) {
throw new SodiumException('Unexpected zero result');
}
# fe_1(one_minus_y);
# fe_sub(one_minus_y, one_minus_y, A.Y);
# fe_invert(one_minus_y, one_minus_y);
$one_minux_y = self::fe_invert(
self::fe_sub(
self::fe_1(),
$A->Y
)
);
# fe_1(x);
# fe_add(x, x, A.Y);
# fe_mul(x, x, one_minus_y);
$x = self::fe_mul(
self::fe_add(self::fe_1(), $A->Y),
$one_minux_y
);
# fe_tobytes(curve25519_pk, x);
return self::fe_tobytes($x);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sk_to_pk($sk)
{
return self::ge_p3_tobytes(
self::ge_scalarmult_base(
self::substr($sk, 0, 32)
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
/** @var string $signature */
$signature = self::sign_detached($message, $sk);
return $signature . $message;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message A signed message
* @param string $pk Public key
* @return string Message (without signature)
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($message, $pk)
{
/** @var string $signature */
$signature = self::substr($message, 0, 64);
/** @var string $message */
$message = self::substr($message, 64);
if (self::verify_detached($signature, $message, $pk)) {
return $message;
}
throw new SodiumException('Invalid signature');
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_detached($message, $sk)
{
# crypto_hash_sha512(az, sk, 32);
$az = hash('sha512', self::substr($sk, 0, 32), true);
# az[0] &= 248;
# az[31] &= 63;
# az[31] |= 64;
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, az + 32, 32);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, nonce);
$hs = hash_init('sha512');
hash_update($hs, self::substr($az, 32, 32));
hash_update($hs, $message);
$nonceHash = hash_final($hs, true);
# memmove(sig + 32, sk + 32, 32);
$pk = self::substr($sk, 32, 32);
# sc_reduce(nonce);
# ge_scalarmult_base(&R, nonce);
# ge_p3_tobytes(sig, &R);
$nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash,
32);
$sig = self::ge_p3_tobytes(
self::ge_scalarmult_base($nonce)
);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, sig, 64);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, hram);
$hs = hash_init('sha512');
hash_update($hs, self::substr($sig, 0, 32));
hash_update($hs, self::substr($pk, 0, 32));
hash_update($hs, $message);
$hramHash = hash_final($hs, true);
# sc_reduce(hram);
# sc_muladd(sig + 32, hram, az, nonce);
$hram = self::sc_reduce($hramHash);
$sigAfter = self::sc_muladd($hram, $az, $nonce);
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
ParagonIE_Sodium_Compat::memzero($az);
} catch (SodiumException $ex) {
$az = null;
}
return $sig;
}
/**
* @internal You should not use this directly from another application
*
* @param string $sig
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_detached($sig, $message, $pk)
{
if (self::strlen($sig) < 64) {
throw new SodiumException('Signature is too short');
}
if ((self::chrToInt($sig[63]) & 240) &&
self::check_S_lt_L(self::substr($sig, 32, 32))) {
throw new SodiumException('S < L - Invalid
signature');
}
if (self::small_order($sig)) {
throw new SodiumException('Signature is on too small of an
order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($pk[$i]);
}
if ($d === 0) {
throw new SodiumException('All zero public key');
}
/** @var bool The original value of
ParagonIE_Sodium_Compat::$fastMult */
$orig = ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up
verification.
ParagonIE_Sodium_Compat::$fastMult = true;
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */
$A = self::ge_frombytes_negate_vartime($pk);
/** @var string $hDigest */
$hDigest = hash(
'sha512',
self::substr($sig, 0, 32) .
self::substr($pk, 0, 32) .
$message,
true
);
/** @var string $h */
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */
$R = self::ge_double_scalarmult_vartime(
$h,
$A,
self::substr($sig, 32)
);
/** @var string $rcheck */
$rcheck = self::ge_tobytes($R);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* @internal You should not use this directly from another application
*
* @param string $S
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function check_S_lt_L($S)
{
if (self::strlen($S) < 32) {
throw new SodiumException('Signature must be 32
bytes');
}
$L = array(
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
);
$c = 0;
$n = 1;
$i = 32;
/** @var array<int, int> $L */
do {
--$i;
$x = self::chrToInt($S[$i]);
$c |= (
(($x - $L[$i]) >> 8) & $n
);
$n &= (
(($x ^ $L[$i]) - 1) >> 8
);
} while ($i !== 0);
return $c === 0;
}
/**
* @param string $R
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function small_order($R)
{
/** @var array<int, array<int, int>> $blocklist */
$blocklist = array(
/* 0 (order 4) */
array(
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/* 1 (order 1) */
array(
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/*
2707385501144840649318225287225658788936804267575313519463743609750303402022
(order 8) */
array(
0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05
),
/*
55188659117513257062467267217118295137698188065244968500265048394206261417927
(order 8) */
array(
0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a
),
/* p-1 (order 2) */
array(
0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85
),
/* p (order 4) */
array(
0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa
),
/* p+1 (order 1) */
array(
0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/*
p+2707385501144840649318225287225658788936804267575313519463743609750303402022
(order 8) */
array(
0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/*
p+55188659117513257062467267217118295137698188065244968500265048394206261417927
(order 8) */
array(
0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* 2p-1 (order 2) */
array(
0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p (order 4) */
array(
0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p+1 (order 1) */
array(
0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
)
);
/** @var int $countBlocklist */
$countBlocklist = count($blocklist);
for ($i = 0; $i < $countBlocklist; ++$i) {
$c = 0;
for ($j = 0; $j < 32; ++$j) {
$c |= self::chrToInt($R[$j]) ^ (int) $blocklist[$i][$j];
}
if ($c === 0) {
return true;
}
}
return false;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_HChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HChaCha20
*/
class ParagonIE_Sodium_Core_HChaCha20 extends
ParagonIE_Sodium_Core_ChaCha20
{
/**
* @param string $in
* @param string $key
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function hChaCha20($in = '', $key =
'', $c = null)
{
$ctx = array();
if ($c === null) {
$ctx[0] = 0x61707865;
$ctx[1] = 0x3320646e;
$ctx[2] = 0x79622d32;
$ctx[3] = 0x6b206574;
} else {
$ctx[0] = self::load_4(self::substr($c, 0, 4));
$ctx[1] = self::load_4(self::substr($c, 4, 4));
$ctx[2] = self::load_4(self::substr($c, 8, 4));
$ctx[3] = self::load_4(self::substr($c, 12, 4));
}
$ctx[4] = self::load_4(self::substr($key, 0, 4));
$ctx[5] = self::load_4(self::substr($key, 4, 4));
$ctx[6] = self::load_4(self::substr($key, 8, 4));
$ctx[7] = self::load_4(self::substr($key, 12, 4));
$ctx[8] = self::load_4(self::substr($key, 16, 4));
$ctx[9] = self::load_4(self::substr($key, 20, 4));
$ctx[10] = self::load_4(self::substr($key, 24, 4));
$ctx[11] = self::load_4(self::substr($key, 28, 4));
$ctx[12] = self::load_4(self::substr($in, 0, 4));
$ctx[13] = self::load_4(self::substr($in, 4, 4));
$ctx[14] = self::load_4(self::substr($in, 8, 4));
$ctx[15] = self::load_4(self::substr($in, 12, 4));
return self::hChaCha20Bytes($ctx);
}
/**
* @param array $ctx
* @return string
* @throws TypeError
*/
protected static function hChaCha20Bytes(array $ctx)
{
$x0 = (int) $ctx[0];
$x1 = (int) $ctx[1];
$x2 = (int) $ctx[2];
$x3 = (int) $ctx[3];
$x4 = (int) $ctx[4];
$x5 = (int) $ctx[5];
$x6 = (int) $ctx[6];
$x7 = (int) $ctx[7];
$x8 = (int) $ctx[8];
$x9 = (int) $ctx[9];
$x10 = (int) $ctx[10];
$x11 = (int) $ctx[11];
$x12 = (int) $ctx[12];
$x13 = (int) $ctx[13];
$x14 = (int) $ctx[14];
$x15 = (int) $ctx[15];
for ($i = 0; $i < 10; ++$i) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8,
$x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9,
$x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10,
$x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11,
$x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10,
$x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11,
$x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8,
$x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9,
$x14);
}
return self::store32_le((int) ($x0 & 0xffffffff)) .
self::store32_le((int) ($x1 & 0xffffffff)) .
self::store32_le((int) ($x2 & 0xffffffff)) .
self::store32_le((int) ($x3 & 0xffffffff)) .
self::store32_le((int) ($x12 & 0xffffffff)) .
self::store32_le((int) ($x13 & 0xffffffff)) .
self::store32_le((int) ($x14 & 0xffffffff)) .
self::store32_le((int) ($x15 & 0xffffffff));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_HSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HSalsa20
*/
abstract class ParagonIE_Sodium_Core_HSalsa20 extends
ParagonIE_Sodium_Core_Salsa20
{
/**
* Calculate an hsalsa20 hash of a single block
*
* HSalsa20 doesn't have a counter and will never be used for more
than
* one block (used to derive a subkey for xsalsa20).
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function hsalsa20($in, $k, $c = null)
{
if ($c === null) {
$x0 = 0x61707865;
$x5 = 0x3320646e;
$x10 = 0x79622d32;
$x15 = 0x6b206574;
} else {
$x0 = self::load_4(self::substr($c, 0, 4));
$x5 = self::load_4(self::substr($c, 4, 4));
$x10 = self::load_4(self::substr($c, 8, 4));
$x15 = self::load_4(self::substr($c, 12, 4));
}
$x1 = self::load_4(self::substr($k, 0, 4));
$x2 = self::load_4(self::substr($k, 4, 4));
$x3 = self::load_4(self::substr($k, 8, 4));
$x4 = self::load_4(self::substr($k, 12, 4));
$x11 = self::load_4(self::substr($k, 16, 4));
$x12 = self::load_4(self::substr($k, 20, 4));
$x13 = self::load_4(self::substr($k, 24, 4));
$x14 = self::load_4(self::substr($k, 28, 4));
$x6 = self::load_4(self::substr($in, 0, 4));
$x7 = self::load_4(self::substr($in, 4, 4));
$x8 = self::load_4(self::substr($in, 8, 4));
$x9 = self::load_4(self::substr($in, 12, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 ^= self::rotate($x0 + $x12, 7);
$x8 ^= self::rotate($x4 + $x0, 9);
$x12 ^= self::rotate($x8 + $x4, 13);
$x0 ^= self::rotate($x12 + $x8, 18);
$x9 ^= self::rotate($x5 + $x1, 7);
$x13 ^= self::rotate($x9 + $x5, 9);
$x1 ^= self::rotate($x13 + $x9, 13);
$x5 ^= self::rotate($x1 + $x13, 18);
$x14 ^= self::rotate($x10 + $x6, 7);
$x2 ^= self::rotate($x14 + $x10, 9);
$x6 ^= self::rotate($x2 + $x14, 13);
$x10 ^= self::rotate($x6 + $x2, 18);
$x3 ^= self::rotate($x15 + $x11, 7);
$x7 ^= self::rotate($x3 + $x15, 9);
$x11 ^= self::rotate($x7 + $x3, 13);
$x15 ^= self::rotate($x11 + $x7, 18);
$x1 ^= self::rotate($x0 + $x3, 7);
$x2 ^= self::rotate($x1 + $x0, 9);
$x3 ^= self::rotate($x2 + $x1, 13);
$x0 ^= self::rotate($x3 + $x2, 18);
$x6 ^= self::rotate($x5 + $x4, 7);
$x7 ^= self::rotate($x6 + $x5, 9);
$x4 ^= self::rotate($x7 + $x6, 13);
$x5 ^= self::rotate($x4 + $x7, 18);
$x11 ^= self::rotate($x10 + $x9, 7);
$x8 ^= self::rotate($x11 + $x10, 9);
$x9 ^= self::rotate($x8 + $x11, 13);
$x10 ^= self::rotate($x9 + $x8, 18);
$x12 ^= self::rotate($x15 + $x14, 7);
$x13 ^= self::rotate($x12 + $x15, 9);
$x14 ^= self::rotate($x13 + $x12, 13);
$x15 ^= self::rotate($x14 + $x13, 18);
}
return self::store32_le($x0) .
self::store32_le($x5) .
self::store32_le($x10) .
self::store32_le($x15) .
self::store32_le($x6) .
self::store32_le($x7) .
self::store32_le($x8) .
self::store32_le($x9);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Poly1305_State', false))
{
return;
}
/**
* Class ParagonIE_Sodium_Core_Poly1305_State
*/
class ParagonIE_Sodium_Core_Poly1305_State extends
ParagonIE_Sodium_Core_Util
{
/**
* @var array<int, int>
*/
protected $buffer = array();
/**
* @var bool
*/
protected $final = false;
/**
* @var array<int, int>
*/
public $h;
/**
* @var int
*/
protected $leftover = 0;
/**
* @var int[]
*/
public $r;
/**
* @var int[]
*/
public $pad;
/**
* ParagonIE_Sodium_Core_Poly1305_State constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '')
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Poly1305 requires a 32-byte key'
);
}
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
$this->r = array(
(int) ((self::load_4(self::substr($key, 0, 4))) &
0x3ffffff),
(int) ((self::load_4(self::substr($key, 3, 4)) >> 2)
& 0x3ffff03),
(int) ((self::load_4(self::substr($key, 6, 4)) >> 4)
& 0x3ffc0ff),
(int) ((self::load_4(self::substr($key, 9, 4)) >> 6)
& 0x3f03fff),
(int) ((self::load_4(self::substr($key, 12, 4)) >> 8)
& 0x00fffff)
);
/* h = 0 */
$this->h = array(0, 0, 0, 0, 0);
/* save pad for later */
$this->pad = array(
self::load_4(self::substr($key, 16, 4)),
self::load_4(self::substr($key, 20, 4)),
self::load_4(self::substr($key, 24, 4)),
self::load_4(self::substr($key, 28, 4)),
);
$this->leftover = 0;
$this->final = false;
}
/**
* Zero internal buffer upon destruction
*/
public function __destruct()
{
$this->r[0] ^= $this->r[0];
$this->r[1] ^= $this->r[1];
$this->r[2] ^= $this->r[2];
$this->r[3] ^= $this->r[3];
$this->r[4] ^= $this->r[4];
$this->h[0] ^= $this->h[0];
$this->h[1] ^= $this->h[1];
$this->h[2] ^= $this->h[2];
$this->h[3] ^= $this->h[3];
$this->h[4] ^= $this->h[4];
$this->pad[0] ^= $this->pad[0];
$this->pad[1] ^= $this->pad[1];
$this->pad[2] ^= $this->pad[2];
$this->pad[3] ^= $this->pad[3];
$this->leftover = 0;
$this->final = true;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function update($message = '')
{
$bytes = self::strlen($message);
if ($bytes < 1) {
return $this;
}
/* handle leftover */
if ($this->leftover) {
$want = ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE -
$this->leftover;
if ($want > $bytes) {
$want = $bytes;
}
for ($i = 0; $i < $want; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
// We snip off the leftmost bytes.
$message = self::substr($message, $want);
$bytes = self::strlen($message);
$this->leftover += $want;
if ($this->leftover <
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
// We still don't have enough to run
$this->blocks()
return $this;
}
$this->blocks(
self::intArrayToString($this->buffer),
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
$this->leftover = 0;
}
/* process full blocks */
if ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/** @var int $want */
$want = $bytes &
~(ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - 1);
if ($want >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$block = self::substr($message, 0, $want);
if (self::strlen($block) >=
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$this->blocks($block, $want);
$message = self::substr($message, $want);
$bytes = self::strlen($message);
}
}
}
/* store leftover */
if ($bytes) {
for ($i = 0; $i < $bytes; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
$this->leftover = (int) $this->leftover + $bytes;
}
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param int $bytes
* @return self
* @throws TypeError
*/
public function blocks($message, $bytes)
{
if (self::strlen($message) < 16) {
$message = str_pad($message, 16, "\x00",
STR_PAD_RIGHT);
}
/** @var int $hibit */
$hibit = $this->final ? 0 : 1 << 24; /* 1 << 128 */
$r0 = (int) $this->r[0];
$r1 = (int) $this->r[1];
$r2 = (int) $this->r[2];
$r3 = (int) $this->r[3];
$r4 = (int) $this->r[4];
$s1 = self::mul($r1, 5, 3);
$s2 = self::mul($r2, 5, 3);
$s3 = self::mul($r3, 5, 3);
$s4 = self::mul($r4, 5, 3);
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
while ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/* h += m[i] */
$h0 += self::load_4(self::substr($message, 0, 4)) &
0x3ffffff;
$h1 += (self::load_4(self::substr($message, 3, 4)) >> 2)
& 0x3ffffff;
$h2 += (self::load_4(self::substr($message, 6, 4)) >> 4)
& 0x3ffffff;
$h3 += (self::load_4(self::substr($message, 9, 4)) >> 6)
& 0x3ffffff;
$h4 += (self::load_4(self::substr($message, 12, 4)) >> 8)
| $hibit;
/* h *= r */
$d0 = (
self::mul($h0, $r0, 25) +
self::mul($s4, $h1, 26) +
self::mul($s3, $h2, 26) +
self::mul($s2, $h3, 26) +
self::mul($s1, $h4, 26)
);
$d1 = (
self::mul($h0, $r1, 25) +
self::mul($h1, $r0, 25) +
self::mul($s4, $h2, 26) +
self::mul($s3, $h3, 26) +
self::mul($s2, $h4, 26)
);
$d2 = (
self::mul($h0, $r2, 25) +
self::mul($h1, $r1, 25) +
self::mul($h2, $r0, 25) +
self::mul($s4, $h3, 26) +
self::mul($s3, $h4, 26)
);
$d3 = (
self::mul($h0, $r3, 25) +
self::mul($h1, $r2, 25) +
self::mul($h2, $r1, 25) +
self::mul($h3, $r0, 25) +
self::mul($s4, $h4, 26)
);
$d4 = (
self::mul($h0, $r4, 25) +
self::mul($h1, $r3, 25) +
self::mul($h2, $r2, 25) +
self::mul($h3, $r1, 25) +
self::mul($h4, $r0, 25)
);
/* (partial) h %= p */
/** @var int $c */
$c = $d0 >> 26;
/** @var int $h0 */
$h0 = $d0 & 0x3ffffff;
$d1 += $c;
/** @var int $c */
$c = $d1 >> 26;
/** @var int $h1 */
$h1 = $d1 & 0x3ffffff;
$d2 += $c;
/** @var int $c */
$c = $d2 >> 26;
/** @var int $h2 */
$h2 = $d2 & 0x3ffffff;
$d3 += $c;
/** @var int $c */
$c = $d3 >> 26;
/** @var int $h3 */
$h3 = $d3 & 0x3ffffff;
$d4 += $c;
/** @var int $c */
$c = $d4 >> 26;
/** @var int $h4 */
$h4 = $d4 & 0x3ffffff;
$h0 += (int) self::mul($c, 5, 3);
/** @var int $c */
$c = $h0 >> 26;
/** @var int $h0 */
$h0 &= 0x3ffffff;
$h1 += $c;
// Chop off the left 32 bytes.
$message = self::substr(
$message,
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
$bytes -= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE;
}
$this->h = array(
(int) ($h0 & 0xffffffff),
(int) ($h1 & 0xffffffff),
(int) ($h2 & 0xffffffff),
(int) ($h3 & 0xffffffff),
(int) ($h4 & 0xffffffff)
);
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @return string
* @throws TypeError
*/
public function finish()
{
/* process the remaining block */
if ($this->leftover) {
$i = $this->leftover;
$this->buffer[$i++] = 1;
for (; $i < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE;
++$i) {
$this->buffer[$i] = 0;
}
$this->final = true;
$this->blocks(
self::substr(
self::intArrayToString($this->buffer),
0,
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
),
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
}
$h0 = (int) $this->h[0];
$h1 = (int) $this->h[1];
$h2 = (int) $this->h[2];
$h3 = (int) $this->h[3];
$h4 = (int) $this->h[4];
/** @var int $c */
$c = $h1 >> 26;
/** @var int $h1 */
$h1 &= 0x3ffffff;
/** @var int $h2 */
$h2 += $c;
/** @var int $c */
$c = $h2 >> 26;
/** @var int $h2 */
$h2 &= 0x3ffffff;
$h3 += $c;
/** @var int $c */
$c = $h3 >> 26;
$h3 &= 0x3ffffff;
$h4 += $c;
/** @var int $c */
$c = $h4 >> 26;
$h4 &= 0x3ffffff;
/** @var int $h0 */
$h0 += self::mul($c, 5, 3);
/** @var int $c */
$c = $h0 >> 26;
/** @var int $h0 */
$h0 &= 0x3ffffff;
/** @var int $h1 */
$h1 += $c;
/* compute h + -p */
/** @var int $g0 */
$g0 = $h0 + 5;
/** @var int $c */
$c = $g0 >> 26;
/** @var int $g0 */
$g0 &= 0x3ffffff;
/** @var int $g1 */
$g1 = $h1 + $c;
/** @var int $c */
$c = $g1 >> 26;
$g1 &= 0x3ffffff;
/** @var int $g2 */
$g2 = $h2 + $c;
/** @var int $c */
$c = $g2 >> 26;
/** @var int $g2 */
$g2 &= 0x3ffffff;
/** @var int $g3 */
$g3 = $h3 + $c;
/** @var int $c */
$c = $g3 >> 26;
/** @var int $g3 */
$g3 &= 0x3ffffff;
/** @var int $g4 */
$g4 = ($h4 + $c - (1 << 26)) & 0xffffffff;
/* select h if h < p, or h + -p if h >= p */
/** @var int $mask */
$mask = ($g4 >> 31) - 1;
$g0 &= $mask;
$g1 &= $mask;
$g2 &= $mask;
$g3 &= $mask;
$g4 &= $mask;
/** @var int $mask */
$mask = ~$mask & 0xffffffff;
/** @var int $h0 */
$h0 = ($h0 & $mask) | $g0;
/** @var int $h1 */
$h1 = ($h1 & $mask) | $g1;
/** @var int $h2 */
$h2 = ($h2 & $mask) | $g2;
/** @var int $h3 */
$h3 = ($h3 & $mask) | $g3;
/** @var int $h4 */
$h4 = ($h4 & $mask) | $g4;
/* h = h % (2^128) */
/** @var int $h0 */
$h0 = (($h0) | ($h1 << 26)) & 0xffffffff;
/** @var int $h1 */
$h1 = (($h1 >> 6) | ($h2 << 20)) & 0xffffffff;
/** @var int $h2 */
$h2 = (($h2 >> 12) | ($h3 << 14)) & 0xffffffff;
/** @var int $h3 */
$h3 = (($h3 >> 18) | ($h4 << 8)) & 0xffffffff;
/* mac = (h + pad) % (2^128) */
$f = (int) ($h0 + $this->pad[0]);
$h0 = (int) $f;
$f = (int) ($h1 + $this->pad[1] + ($f >> 32));
$h1 = (int) $f;
$f = (int) ($h2 + $this->pad[2] + ($f >> 32));
$h2 = (int) $f;
$f = (int) ($h3 + $this->pad[3] + ($f >> 32));
$h3 = (int) $f;
return self::store32_le($h0 & 0xffffffff) .
self::store32_le($h1 & 0xffffffff) .
self::store32_le($h2 & 0xffffffff) .
self::store32_le($h3 & 0xffffffff);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Poly1305', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Poly1305
*/
abstract class ParagonIE_Sodium_Core_Poly1305 extends
ParagonIE_Sodium_Core_Util
{
const BLOCK_SIZE = 16;
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth($m, $key)
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
self::substr($key, 0, 32)
);
return $state
->update($m)
->finish();
}
/**
* @internal You should not use this directly from another application
*
* @param string $mac
* @param string $m
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth_verify($mac, $m, $key)
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
self::substr($key, 0, 32)
);
$calc = $state
->update($m)
->finish();
return self::verify_16($calc, $mac);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Salsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Salsa20
*/
abstract class ParagonIE_Sodium_Core_Salsa20 extends
ParagonIE_Sodium_Core_Util
{
const ROUNDS = 20;
/**
* Calculate an salsa20 hash of a single block
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function core_salsa20($in, $k, $c = null)
{
if (self::strlen($k) < 32) {
throw new RangeException('Key must be 32 bytes
long');
}
if ($c === null) {
$j0 = $x0 = 0x61707865;
$j5 = $x5 = 0x3320646e;
$j10 = $x10 = 0x79622d32;
$j15 = $x15 = 0x6b206574;
} else {
$j0 = $x0 = self::load_4(self::substr($c, 0, 4));
$j5 = $x5 = self::load_4(self::substr($c, 4, 4));
$j10 = $x10 = self::load_4(self::substr($c, 8, 4));
$j15 = $x15 = self::load_4(self::substr($c, 12, 4));
}
$j1 = $x1 = self::load_4(self::substr($k, 0, 4));
$j2 = $x2 = self::load_4(self::substr($k, 4, 4));
$j3 = $x3 = self::load_4(self::substr($k, 8, 4));
$j4 = $x4 = self::load_4(self::substr($k, 12, 4));
$j6 = $x6 = self::load_4(self::substr($in, 0, 4));
$j7 = $x7 = self::load_4(self::substr($in, 4, 4));
$j8 = $x8 = self::load_4(self::substr($in, 8, 4));
$j9 = $x9 = self::load_4(self::substr($in, 12, 4));
$j11 = $x11 = self::load_4(self::substr($k, 16, 4));
$j12 = $x12 = self::load_4(self::substr($k, 20, 4));
$j13 = $x13 = self::load_4(self::substr($k, 24, 4));
$j14 = $x14 = self::load_4(self::substr($k, 28, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 ^= self::rotate($x0 + $x12, 7);
$x8 ^= self::rotate($x4 + $x0, 9);
$x12 ^= self::rotate($x8 + $x4, 13);
$x0 ^= self::rotate($x12 + $x8, 18);
$x9 ^= self::rotate($x5 + $x1, 7);
$x13 ^= self::rotate($x9 + $x5, 9);
$x1 ^= self::rotate($x13 + $x9, 13);
$x5 ^= self::rotate($x1 + $x13, 18);
$x14 ^= self::rotate($x10 + $x6, 7);
$x2 ^= self::rotate($x14 + $x10, 9);
$x6 ^= self::rotate($x2 + $x14, 13);
$x10 ^= self::rotate($x6 + $x2, 18);
$x3 ^= self::rotate($x15 + $x11, 7);
$x7 ^= self::rotate($x3 + $x15, 9);
$x11 ^= self::rotate($x7 + $x3, 13);
$x15 ^= self::rotate($x11 + $x7, 18);
$x1 ^= self::rotate($x0 + $x3, 7);
$x2 ^= self::rotate($x1 + $x0, 9);
$x3 ^= self::rotate($x2 + $x1, 13);
$x0 ^= self::rotate($x3 + $x2, 18);
$x6 ^= self::rotate($x5 + $x4, 7);
$x7 ^= self::rotate($x6 + $x5, 9);
$x4 ^= self::rotate($x7 + $x6, 13);
$x5 ^= self::rotate($x4 + $x7, 18);
$x11 ^= self::rotate($x10 + $x9, 7);
$x8 ^= self::rotate($x11 + $x10, 9);
$x9 ^= self::rotate($x8 + $x11, 13);
$x10 ^= self::rotate($x9 + $x8, 18);
$x12 ^= self::rotate($x15 + $x14, 7);
$x13 ^= self::rotate($x12 + $x15, 9);
$x14 ^= self::rotate($x13 + $x12, 13);
$x15 ^= self::rotate($x14 + $x13, 18);
}
$x0 += $j0;
$x1 += $j1;
$x2 += $j2;
$x3 += $j3;
$x4 += $j4;
$x5 += $j5;
$x6 += $j6;
$x7 += $j7;
$x8 += $j8;
$x9 += $j9;
$x10 += $j10;
$x11 += $j11;
$x12 += $j12;
$x13 += $j13;
$x14 += $j14;
$x15 += $j15;
return self::store32_le($x0) .
self::store32_le($x1) .
self::store32_le($x2) .
self::store32_le($x3) .
self::store32_le($x4) .
self::store32_le($x5) .
self::store32_le($x6) .
self::store32_le($x7) .
self::store32_le($x8) .
self::store32_le($x9) .
self::store32_le($x10) .
self::store32_le($x11) .
self::store32_le($x12) .
self::store32_le($x13) .
self::store32_le($x14) .
self::store32_le($x15);
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20($len, $nonce, $key)
{
if (self::strlen($key) !== 32) {
throw new RangeException('Key must be 32 bytes
long');
}
$kcopy = '' . $key;
$in = self::substr($nonce, 0, 8) . str_repeat("\0", 8);
$c = '';
while ($len >= 64) {
$c .= self::core_salsa20($in, $kcopy, null);
$u = 1;
// Internal counter.
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$len -= 64;
}
if ($len > 0) {
$c .= self::substr(
self::core_salsa20($in, $kcopy, null),
0,
$len
);
}
try {
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException $ex) {
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $n
* @param int $ic
* @param string $k
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor_ic($m, $n, $ic, $k)
{
$mlen = self::strlen($m);
if ($mlen < 1) {
return '';
}
$kcopy = self::substr($k, 0, 32);
$in = self::substr($n, 0, 8);
// Initialize the counter
$in .= ParagonIE_Sodium_Core_Util::store64_le($ic);
$c = '';
while ($mlen >= 64) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(
self::substr($m, 0, 64),
self::substr($block, 0, 64)
);
$u = 1;
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$mlen -= 64;
$m = self::substr($m, 64);
}
if ($mlen) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(
self::substr($m, 0, $mlen),
self::substr($block, 0, $mlen)
);
}
try {
ParagonIE_Sodium_Compat::memzero($block);
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException $ex) {
$block = null;
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor($message, $nonce, $key)
{
return self::xorStrings(
$message,
self::salsa20(
self::strlen($message),
$nonce,
$key
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $u
* @param int $c
* @return int
*/
public static function rotate($u, $c)
{
$u &= 0xffffffff;
$c %= 32;
return (int) (0xffffffff & (
($u << $c)
|
($u >> (32 - $c))
)
);
}
}
<?php
/**
* Class ParagonIE_Sodium_Core_SecretStream_State
*/
class ParagonIE_Sodium_Core_SecretStream_State
{
/** @var string $key */
protected $key;
/** @var int $counter */
protected $counter;
/** @var string $nonce */
protected $nonce;
/** @var string $_pad */
protected $_pad;
/**
* ParagonIE_Sodium_Core_SecretStream_State constructor.
* @param string $key
* @param string|null $nonce
*/
public function __construct($key, $nonce = null)
{
$this->key = $key;
$this->counter = 1;
if (is_null($nonce)) {
$nonce = str_repeat("\0", 12);
}
$this->nonce = str_pad($nonce, 12, "\0",
STR_PAD_RIGHT);;
$this->_pad = str_repeat("\0", 4);
}
/**
* @return self
*/
public function counterReset()
{
$this->counter = 1;
$this->_pad = str_repeat("\0", 4);
return $this;
}
/**
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* @return string
*/
public function getCounter()
{
return ParagonIE_Sodium_Core_Util::store32_le($this->counter);
}
/**
* @return string
*/
public function getNonce()
{
if (!is_string($this->nonce)) {
$this->nonce = str_repeat("\0", 12);
}
if (ParagonIE_Sodium_Core_Util::strlen($this->nonce) !== 12) {
$this->nonce = str_pad($this->nonce, 12, "\0",
STR_PAD_RIGHT);
}
return $this->nonce;
}
/**
* @return string
*/
public function getCombinedNonce()
{
return $this->getCounter() .
ParagonIE_Sodium_Core_Util::substr($this->getNonce(), 0, 8);
}
/**
* @return self
*/
public function incrementCounter()
{
++$this->counter;
return $this;
}
/**
* @return bool
*/
public function needsRekey()
{
return ($this->counter & 0xffff) === 0;
}
/**
* @param string $newKeyAndNonce
* @return self
*/
public function rekey($newKeyAndNonce)
{
$this->key = ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce,
0, 32);
$this->nonce = str_pad(
ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 32),
12,
"\0",
STR_PAD_RIGHT
);
return $this;
}
/**
* @param string $str
* @return self
*/
public function xorNonce($str)
{
$this->nonce = ParagonIE_Sodium_Core_Util::xorStrings(
$this->getNonce(),
str_pad(
ParagonIE_Sodium_Core_Util::substr($str, 0, 8),
12,
"\0",
STR_PAD_RIGHT
)
);
return $this;
}
/**
* @param string $string
* @return self
*/
public static function fromString($string)
{
$state = new ParagonIE_Sodium_Core_SecretStream_State(
ParagonIE_Sodium_Core_Util::substr($string, 0, 32)
);
$state->counter = ParagonIE_Sodium_Core_Util::load_4(
ParagonIE_Sodium_Core_Util::substr($string, 32, 4)
);
$state->nonce = ParagonIE_Sodium_Core_Util::substr($string, 36,
12);
$state->_pad = ParagonIE_Sodium_Core_Util::substr($string, 48,
8);
return $state;
}
/**
* @return string
*/
public function toString()
{
return $this->key .
$this->getCounter() .
$this->nonce .
$this->_pad;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_SipHash', false)) {
return;
}
/**
* Class ParagonIE_SodiumCompat_Core_SipHash
*
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit
integers
*/
class ParagonIE_Sodium_Core_SipHash extends ParagonIE_Sodium_Core_Util
{
/**
* @internal You should not use this directly from another application
*
* @param array<array-key, int> $v
* @return array<array-key, int>
*
*/
public static function sipRound(array $v)
{
# v0 += v1;
list($v[0], $v[1]) = self::add(
array($v[0], $v[1]),
array($v[2], $v[3])
);
# v1=ROTL(v1,13);
list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 13);
# v1 ^= v0;
$v[2] = (int) $v[2] ^ (int) $v[0];
$v[3] = (int) $v[3] ^ (int) $v[1];
# v0=ROTL(v0,32);
list($v[0], $v[1]) = self::rotl_64((int) $v[0], (int) $v[1], 32);
# v2 += v3;
list($v[4], $v[5]) = self::add(
array((int) $v[4], (int) $v[5]),
array((int) $v[6], (int) $v[7])
);
# v3=ROTL(v3,16);
list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 16);
# v3 ^= v2;
$v[6] = (int) $v[6] ^ (int) $v[4];
$v[7] = (int) $v[7] ^ (int) $v[5];
# v0 += v3;
list($v[0], $v[1]) = self::add(
array((int) $v[0], (int) $v[1]),
array((int) $v[6], (int) $v[7])
);
# v3=ROTL(v3,21);
list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 21);
# v3 ^= v0;
$v[6] = (int) $v[6] ^ (int) $v[0];
$v[7] = (int) $v[7] ^ (int) $v[1];
# v2 += v1;
list($v[4], $v[5]) = self::add(
array((int) $v[4], (int) $v[5]),
array((int) $v[2], (int) $v[3])
);
# v1=ROTL(v1,17);
list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 17);
# v1 ^= v2;;
$v[2] = (int) $v[2] ^ (int) $v[4];
$v[3] = (int) $v[3] ^ (int) $v[5];
# v2=ROTL(v2,32)
list($v[4], $v[5]) = self::rotl_64((int) $v[4], (int) $v[5], 32);
return $v;
}
/**
* Add two 32 bit integers representing a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int[] $a
* @param int[] $b
* @return array<int, mixed>
*/
public static function add(array $a, array $b)
{
/** @var int $x1 */
$x1 = $a[1] + $b[1];
/** @var int $c */
$c = $x1 >> 32; // Carry if ($a + $b) > 0xffffffff
/** @var int $x0 */
$x0 = $a[0] + $b[0] + $c;
return array(
$x0 & 0xffffffff,
$x1 & 0xffffffff
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $int0
* @param int $int1
* @param int $c
* @return array<int, mixed>
*/
public static function rotl_64($int0, $int1, $c)
{
$int0 &= 0xffffffff;
$int1 &= 0xffffffff;
$c &= 63;
if ($c === 32) {
return array($int1, $int0);
}
if ($c > 31) {
$tmp = $int1;
$int1 = $int0;
$int0 = $tmp;
$c &= 31;
}
if ($c === 0) {
return array($int0, $int1);
}
return array(
0xffffffff & (
($int0 << $c)
|
($int1 >> (32 - $c))
),
0xffffffff & (
($int1 << $c)
|
($int0 >> (32 - $c))
),
);
}
/**
* Implements Siphash-2-4 using only 32-bit numbers.
*
* When we split an int into two, the higher bits go to the lower
index.
* e.g. 0xDEADBEEFAB10C92D becomes [
* 0 => 0xDEADBEEF,
* 1 => 0xAB10C92D
* ].
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sipHash24($in, $key)
{
$inlen = self::strlen($in);
# /* "somepseudorandomlygeneratedbytes" */
# u64 v0 = 0x736f6d6570736575ULL;
# u64 v1 = 0x646f72616e646f6dULL;
# u64 v2 = 0x6c7967656e657261ULL;
# u64 v3 = 0x7465646279746573ULL;
$v = array(
0x736f6d65, // 0
0x70736575, // 1
0x646f7261, // 2
0x6e646f6d, // 3
0x6c796765, // 4
0x6e657261, // 5
0x74656462, // 6
0x79746573 // 7
);
// v0 => $v[0], $v[1]
// v1 => $v[2], $v[3]
// v2 => $v[4], $v[5]
// v3 => $v[6], $v[7]
# u64 k0 = LOAD64_LE( k );
# u64 k1 = LOAD64_LE( k + 8 );
$k = array(
self::load_4(self::substr($key, 4, 4)),
self::load_4(self::substr($key, 0, 4)),
self::load_4(self::substr($key, 12, 4)),
self::load_4(self::substr($key, 8, 4))
);
// k0 => $k[0], $k[1]
// k1 => $k[2], $k[3]
# b = ( ( u64 )inlen ) << 56;
$b = array(
$inlen << 24,
0
);
// See docblock for why the 0th index gets the higher bits.
# v3 ^= k1;
$v[6] ^= $k[2];
$v[7] ^= $k[3];
# v2 ^= k0;
$v[4] ^= $k[0];
$v[5] ^= $k[1];
# v1 ^= k1;
$v[2] ^= $k[2];
$v[3] ^= $k[3];
# v0 ^= k0;
$v[0] ^= $k[0];
$v[1] ^= $k[1];
$left = $inlen;
# for ( ; in != end; in += 8 )
while ($left >= 8) {
# m = LOAD64_LE( in );
$m = array(
self::load_4(self::substr($in, 4, 4)),
self::load_4(self::substr($in, 0, 4))
);
# v3 ^= m;
$v[6] ^= $m[0];
$v[7] ^= $m[1];
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= m;
$v[0] ^= $m[0];
$v[1] ^= $m[1];
$in = self::substr($in, 8);
$left -= 8;
}
# switch( left )
# {
# case 7: b |= ( ( u64 )in[ 6] ) << 48;
# case 6: b |= ( ( u64 )in[ 5] ) << 40;
# case 5: b |= ( ( u64 )in[ 4] ) << 32;
# case 4: b |= ( ( u64 )in[ 3] ) << 24;
# case 3: b |= ( ( u64 )in[ 2] ) << 16;
# case 2: b |= ( ( u64 )in[ 1] ) << 8;
# case 1: b |= ( ( u64 )in[ 0] ); break;
# case 0: break;
# }
switch ($left) {
case 7:
$b[0] |= self::chrToInt($in[6]) << 16;
case 6:
$b[0] |= self::chrToInt($in[5]) << 8;
case 5:
$b[0] |= self::chrToInt($in[4]);
case 4:
$b[1] |= self::chrToInt($in[3]) << 24;
case 3:
$b[1] |= self::chrToInt($in[2]) << 16;
case 2:
$b[1] |= self::chrToInt($in[1]) << 8;
case 1:
$b[1] |= self::chrToInt($in[0]);
case 0:
break;
}
// See docblock for why the 0th index gets the higher bits.
# v3 ^= b;
$v[6] ^= $b[0];
$v[7] ^= $b[1];
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= b;
$v[0] ^= $b[0];
$v[1] ^= $b[1];
// Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our
implementation
# v2 ^= 0xff;
$v[5] ^= 0xff;
# SIPROUND;
# SIPROUND;
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
# b = v0 ^ v1 ^ v2 ^ v3;
# STORE64_LE( out, b );
return self::store32_le($v[1] ^ $v[3] ^ $v[5] ^ $v[7]) .
self::store32_le($v[0] ^ $v[2] ^ $v[4] ^ $v[6]);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_Util', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Util
*/
abstract class ParagonIE_Sodium_Core_Util
{
/**
* @param int $integer
* @param int $size (16, 32, 64)
* @return int
*/
public static function abs($integer, $size = 0)
{
/** @var int $realSize */
$realSize = (PHP_INT_SIZE << 3) - 1;
if ($size) {
--$size;
} else {
/** @var int $size */
$size = $realSize;
}
$negative = -(($integer >> $size) & 1);
return (int) (
($integer ^ $negative)
+
(($negative >> $realSize) & 1)
);
}
/**
* Convert a binary string into a hexadecimal string without
cache-timing
* leaks
*
* @internal You should not use this directly from another application
*
* @param string $binaryString (raw binary)
* @return string
* @throws TypeError
*/
public static function bin2hex($binaryString)
{
/* Type checks: */
if (!is_string($binaryString)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($binaryString) . ' given.');
}
$hex = '';
$len = self::strlen($binaryString);
for ($i = 0; $i < $len; ++$i) {
/** @var array<int, int> $chunk */
$chunk = unpack('C', $binaryString[$i]);
/** @var int $c */
$c = $chunk[1] & 0xf;
/** @var int $b */
$b = $chunk[1] >> 4;
$hex .= pack(
'CC',
(87 + $b + ((($b - 10) >> 8) & ~38)),
(87 + $c + ((($c - 10) >> 8) & ~38))
);
}
return $hex;
}
/**
* Convert a binary string into a hexadecimal string without
cache-timing
* leaks, returning uppercase letters (as per RFC 4648)
*
* @internal You should not use this directly from another application
*
* @param string $bin_string (raw binary)
* @return string
* @throws TypeError
*/
public static function bin2hexUpper($bin_string)
{
$hex = '';
$len = self::strlen($bin_string);
for ($i = 0; $i < $len; ++$i) {
/** @var array<int, int> $chunk */
$chunk = unpack('C', $bin_string[$i]);
/**
* Lower 16 bits
*
* @var int $c
*/
$c = $chunk[1] & 0xf;
/**
* Upper 16 bits
* @var int $b
*/
$b = $chunk[1] >> 4;
/**
* Use pack() and binary operators to turn the two integers
* into hexadecimal characters. We don't use chr() here,
because
* it uses a lookup table internally and we want to avoid
* cache-timing side-channels.
*/
$hex .= pack(
'CC',
(55 + $b + ((($b - 10) >> 8) & ~6)),
(55 + $c + ((($c - 10) >> 8) & ~6))
);
}
return $hex;
}
/**
* Cache-timing-safe variant of ord()
*
* @internal You should not use this directly from another application
*
* @param string $chr
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function chrToInt($chr)
{
/* Type checks: */
if (!is_string($chr)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($chr) . ' given.');
}
if (self::strlen($chr) !== 1) {
throw new SodiumException('chrToInt() expects a string
that is exactly 1 character long');
}
/** @var array<int, int> $chunk */
$chunk = unpack('C', $chr);
return (int) ($chunk[1]);
}
/**
* Compares two strings.
*
* @internal You should not use this directly from another application
*
* @param string $left
* @param string $right
* @param int $len
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function compare($left, $right, $len = null)
{
$leftLen = self::strlen($left);
$rightLen = self::strlen($right);
if ($len === null) {
$len = max($leftLen, $rightLen);
$left = str_pad($left, $len, "\x00", STR_PAD_RIGHT);
$right = str_pad($right, $len, "\x00",
STR_PAD_RIGHT);
}
$gt = 0;
$eq = 1;
$i = $len;
while ($i !== 0) {
--$i;
$gt |= ((self::chrToInt($right[$i]) -
self::chrToInt($left[$i])) >> 8) & $eq;
$eq &= ((self::chrToInt($right[$i]) ^
self::chrToInt($left[$i])) - 1) >> 8;
}
return ($gt + $gt + $eq) - 1;
}
/**
* If a variable does not match a given type, throw a TypeError.
*
* @param mixed $mixedVar
* @param string $type
* @param int $argumentIndex
* @throws TypeError
* @throws SodiumException
* @return void
*/
public static function declareScalarType(&$mixedVar = null, $type =
'void', $argumentIndex = 0)
{
if (func_num_args() === 0) {
/* Tautology, by default */
return;
}
if (func_num_args() === 1) {
throw new TypeError('Declared void, but passed a
variable');
}
$realType = strtolower(gettype($mixedVar));
$type = strtolower($type);
switch ($type) {
case 'null':
if ($mixedVar !== null) {
throw new TypeError('Argument ' .
$argumentIndex . ' must be null, ' . $realType . '
given.');
}
break;
case 'integer':
case 'int':
$allow = array('int', 'integer');
if (!in_array($type, $allow)) {
throw new TypeError('Argument ' .
$argumentIndex . ' must be an integer, ' . $realType . '
given.');
}
$mixedVar = (int) $mixedVar;
break;
case 'boolean':
case 'bool':
$allow = array('bool', 'boolean');
if (!in_array($type, $allow)) {
throw new TypeError('Argument ' .
$argumentIndex . ' must be a boolean, ' . $realType . '
given.');
}
$mixedVar = (bool) $mixedVar;
break;
case 'string':
if (!is_string($mixedVar)) {
throw new TypeError('Argument ' .
$argumentIndex . ' must be a string, ' . $realType . '
given.');
}
$mixedVar = (string) $mixedVar;
break;
case 'decimal':
case 'double':
case 'float':
$allow = array('decimal', 'double',
'float');
if (!in_array($type, $allow)) {
throw new TypeError('Argument ' .
$argumentIndex . ' must be a float, ' . $realType . '
given.');
}
$mixedVar = (float) $mixedVar;
break;
case 'object':
if (!is_object($mixedVar)) {
throw new TypeError('Argument ' .
$argumentIndex . ' must be an object, ' . $realType . '
given.');
}
break;
case 'array':
if (!is_array($mixedVar)) {
if (is_object($mixedVar)) {
if ($mixedVar instanceof ArrayAccess) {
return;
}
}
throw new TypeError('Argument ' .
$argumentIndex . ' must be an array, ' . $realType . '
given.');
}
break;
default:
throw new SodiumException('Unknown type (' .
$realType .') does not match expect type (' . $type .
')');
}
}
/**
* Evaluate whether or not two strings are equal (in constant-time)
*
* @param string $left
* @param string $right
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function hashEquals($left, $right)
{
/* Type checks: */
if (!is_string($left)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($left) . ' given.');
}
if (!is_string($right)) {
throw new TypeError('Argument 2 must be a string, ' .
gettype($right) . ' given.');
}
if (is_callable('hash_equals')) {
return hash_equals($left, $right);
}
$d = 0;
/** @var int $len */
$len = self::strlen($left);
if ($len !== self::strlen($right)) {
return false;
}
for ($i = 0; $i < $len; ++$i) {
$d |= self::chrToInt($left[$i]) ^ self::chrToInt($right[$i]);
}
if ($d !== 0) {
return false;
}
return $left === $right;
}
/**
* Convert a hexadecimal string into a binary string without
cache-timing
* leaks
*
* @internal You should not use this directly from another application
*
* @param string $hexString
* @param bool $strictPadding
* @return string (raw binary)
* @throws RangeException
* @throws TypeError
*/
public static function hex2bin($hexString, $strictPadding = false)
{
/* Type checks: */
if (!is_string($hexString)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($hexString) . ' given.');
}
/** @var int $hex_pos */
$hex_pos = 0;
/** @var string $bin */
$bin = '';
/** @var int $c_acc */
$c_acc = 0;
/** @var int $hex_len */
$hex_len = self::strlen($hexString);
/** @var int $state */
$state = 0;
if (($hex_len & 1) !== 0) {
if ($strictPadding) {
throw new RangeException(
'Expected an even number of hexadecimal
characters'
);
} else {
$hexString = '0' . $hexString;
++$hex_len;
}
}
$chunk = unpack('C*', $hexString);
while ($hex_pos < $hex_len) {
++$hex_pos;
/** @var int $c */
$c = $chunk[$hex_pos];
/** @var int $c_num */
$c_num = $c ^ 48;
/** @var int $c_num0 */
$c_num0 = ($c_num - 10) >> 8;
/** @var int $c_alpha */
$c_alpha = ($c & ~32) - 55;
/** @var int $c_alpha0 */
$c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
if (($c_num0 | $c_alpha0) === 0) {
throw new RangeException(
'hex2bin() only expects hexadecimal
characters'
);
}
/** @var int $c_val */
$c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
if ($state === 0) {
$c_acc = $c_val * 16;
} else {
$bin .= pack('C', $c_acc | $c_val);
}
$state ^= 1;
}
return $bin;
}
/**
* Turn an array of integers into a string
*
* @internal You should not use this directly from another application
*
* @param array<int, int> $ints
* @return string
*/
public static function intArrayToString(array $ints)
{
/** @var array<int, int> $args */
$args = $ints;
foreach ($args as $i => $v) {
$args[$i] = (int) ($v & 0xff);
}
array_unshift($args, str_repeat('C', count($ints)));
return (string) (call_user_func_array('pack', $args));
}
/**
* Cache-timing-safe variant of ord()
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function intToChr($int)
{
return pack('C', $int);
}
/**
* Load a 3 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws TypeError
*/
public static function load_3($string)
{
/* Type checks: */
if (!is_string($string)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($string) . ' given.');
}
/* Input validation: */
if (self::strlen($string) < 3) {
throw new RangeException(
'String must be 3 bytes or more; ' .
self::strlen($string) . ' given.'
);
}
/** @var array<int, int> $unpacked */
$unpacked = unpack('V', $string . "\0");
return (int) ($unpacked[1] & 0xffffff);
}
/**
* Load a 4 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws TypeError
*/
public static function load_4($string)
{
/* Type checks: */
if (!is_string($string)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($string) . ' given.');
}
/* Input validation: */
if (self::strlen($string) < 4) {
throw new RangeException(
'String must be 4 bytes or more; ' .
self::strlen($string) . ' given.'
);
}
/** @var array<int, int> $unpacked */
$unpacked = unpack('V', $string);
return (int) ($unpacked[1] & 0xffffffff);
}
/**
* Load a 8 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function load64_le($string)
{
/* Type checks: */
if (!is_string($string)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($string) . ' given.');
}
/* Input validation: */
if (self::strlen($string) < 4) {
throw new RangeException(
'String must be 4 bytes or more; ' .
self::strlen($string) . ' given.'
);
}
if (PHP_VERSION_ID >= 50603 && PHP_INT_SIZE === 8) {
/** @var array<int, int> $unpacked */
$unpacked = unpack('P', $string);
return (int) $unpacked[1];
}
/** @var int $result */
$result = (self::chrToInt($string[0]) & 0xff);
$result |= (self::chrToInt($string[1]) & 0xff) << 8;
$result |= (self::chrToInt($string[2]) & 0xff) << 16;
$result |= (self::chrToInt($string[3]) & 0xff) << 24;
$result |= (self::chrToInt($string[4]) & 0xff) << 32;
$result |= (self::chrToInt($string[5]) & 0xff) << 40;
$result |= (self::chrToInt($string[6]) & 0xff) << 48;
$result |= (self::chrToInt($string[7]) & 0xff) << 56;
return (int) $result;
}
/**
* @internal You should not use this directly from another application
*
* @param string $left
* @param string $right
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function memcmp($left, $right)
{
if (self::hashEquals($left, $right)) {
return 0;
}
return -1;
}
/**
* Multiply two integers in constant-time
*
* Micro-architecture timing side-channels caused by how your CPU
* implements multiplication are best prevented by never using the
* multiplication operators and ensuring that our code always takes
* the same number of operations to complete, regardless of the values
* of $a and $b.
*
* @internal You should not use this directly from another application
*
* @param int $a
* @param int $b
* @param int $size Limits the number of operations (useful for small,
* constant operands)
* @return int
*/
public static function mul($a, $b, $size = 0)
{
if (ParagonIE_Sodium_Compat::$fastMult) {
return (int) ($a * $b);
}
static $defaultSize = null;
/** @var int $defaultSize */
if (!$defaultSize) {
/** @var int $defaultSize */
$defaultSize = (PHP_INT_SIZE << 3) - 1;
}
if ($size < 1) {
/** @var int $size */
$size = $defaultSize;
}
/** @var int $size */
$c = 0;
/**
* Mask is either -1 or 0.
*
* -1 in binary looks like 0x1111 ... 1111
* 0 in binary looks like 0x0000 ... 0000
*
* @var int
*/
$mask = -(($b >> ((int) $defaultSize)) & 1);
/**
* Ensure $b is a positive integer, without creating
* a branching side-channel
*
* @var int $b
*/
$b = ($b & ~$mask) | ($mask & -$b);
/**
* Unless $size is provided:
*
* This loop always runs 32 times when PHP_INT_SIZE is 4.
* This loop always runs 64 times when PHP_INT_SIZE is 8.
*/
for ($i = $size; $i >= 0; --$i) {
$c += (int) ($a & -($b & 1));
$a <<= 1;
$b >>= 1;
}
/**
* If $b was negative, we then apply the same value to $c here.
* It doesn't matter much if $a was negative; the $c += above
would
* have produced a negative integer to begin with. But a negative
$b
* makes $b >>= 1 never return 0, so we would end up with
incorrect
* results.
*
* The end result is what we'd expect from integer
multiplication.
*/
return (int) (($c & ~$mask) | ($mask & -$c));
}
/**
* Convert any arbitrary numbers into two 32-bit integers that
represent
* a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int|float $num
* @return array<int, int>
*/
public static function numericTo64BitInteger($num)
{
$high = 0;
/** @var int $low */
$low = $num & 0xffffffff;
if ((+(abs($num))) >= 1) {
if ($num > 0) {
/** @var int $high */
$high = min((+(floor($num/4294967296))), 4294967295);
} else {
/** @var int $high */
$high = ~~((+(ceil(($num - (+((~~($num)))))/4294967296))));
}
}
return array((int) $high, (int) $low);
}
/**
* Store a 24-bit integer into a string, treating it as big-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store_3($int)
{
/* Type checks: */
if (!is_int($int)) {
if (is_numeric($int)) {
$int = (int) $int;
} else {
throw new TypeError('Argument 1 must be an integer,
' . gettype($int) . ' given.');
}
}
/** @var string $packed */
$packed = pack('N', $int);
return self::substr($packed, 1, 3);
}
/**
* Store a 32-bit integer into a string, treating it as little-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store32_le($int)
{
/* Type checks: */
if (!is_int($int)) {
if (is_numeric($int)) {
$int = (int) $int;
} else {
throw new TypeError('Argument 1 must be an integer,
' . gettype($int) . ' given.');
}
}
/** @var string $packed */
$packed = pack('V', $int);
return $packed;
}
/**
* Store a 32-bit integer into a string, treating it as big-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store_4($int)
{
/* Type checks: */
if (!is_int($int)) {
if (is_numeric($int)) {
$int = (int) $int;
} else {
throw new TypeError('Argument 1 must be an integer,
' . gettype($int) . ' given.');
}
}
/** @var string $packed */
$packed = pack('N', $int);
return $packed;
}
/**
* Stores a 64-bit integer as an string, treating it as little-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store64_le($int)
{
/* Type checks: */
if (!is_int($int)) {
if (is_numeric($int)) {
$int = (int) $int;
} else {
throw new TypeError('Argument 1 must be an integer,
' . gettype($int) . ' given.');
}
}
if (PHP_INT_SIZE === 8) {
if (PHP_VERSION_ID >= 50603) {
/** @var string $packed */
$packed = pack('P', $int);
return $packed;
}
return self::intToChr($int & 0xff) .
self::intToChr(($int >> 8) & 0xff) .
self::intToChr(($int >> 16) & 0xff) .
self::intToChr(($int >> 24) & 0xff) .
self::intToChr(($int >> 32) & 0xff) .
self::intToChr(($int >> 40) & 0xff) .
self::intToChr(($int >> 48) & 0xff) .
self::intToChr(($int >> 56) & 0xff);
}
if ($int > PHP_INT_MAX) {
list($hiB, $int) = self::numericTo64BitInteger($int);
} else {
$hiB = 0;
}
return
self::intToChr(($int ) & 0xff) .
self::intToChr(($int >> 8) & 0xff) .
self::intToChr(($int >> 16) & 0xff) .
self::intToChr(($int >> 24) & 0xff) .
self::intToChr($hiB & 0xff) .
self::intToChr(($hiB >> 8) & 0xff) .
self::intToChr(($hiB >> 16) & 0xff) .
self::intToChr(($hiB >> 24) & 0xff);
}
/**
* Safe string length
*
* @internal You should not use this directly from another application
*
* @ref mbstring.func_overload
*
* @param string $str
* @return int
* @throws TypeError
*/
public static function strlen($str)
{
/* Type checks: */
if (!is_string($str)) {
throw new TypeError('String expected');
}
return (int) (
self::isMbStringOverride()
? mb_strlen($str, '8bit')
: strlen($str)
);
}
/**
* Turn a string into an array of integers
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return array<int, int>
* @throws TypeError
*/
public static function stringToIntArray($string)
{
if (!is_string($string)) {
throw new TypeError('String expected');
}
/**
* @var array<int, int>
*/
$values = array_values(
unpack('C*', $string)
);
return $values;
}
/**
* Safe substring
*
* @internal You should not use this directly from another application
*
* @ref mbstring.func_overload
*
* @param string $str
* @param int $start
* @param int $length
* @return string
* @throws TypeError
*/
public static function substr($str, $start = 0, $length = null)
{
/* Type checks: */
if (!is_string($str)) {
throw new TypeError('String expected');
}
if ($length === 0) {
return '';
}
if (self::isMbStringOverride()) {
if (PHP_VERSION_ID < 50400 && $length === null) {
$length = self::strlen($str);
}
$sub = (string) mb_substr($str, $start, $length,
'8bit');
} elseif ($length === null) {
$sub = (string) substr($str, $start);
} else {
$sub = (string) substr($str, $start, $length);
}
if ($sub !== '') {
return $sub;
}
return '';
}
/**
* Compare a 16-character byte string in constant time.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_16($a, $b)
{
/* Type checks: */
if (!is_string($a)) {
throw new TypeError('String expected');
}
if (!is_string($b)) {
throw new TypeError('String expected');
}
return self::hashEquals(
self::substr($a, 0, 16),
self::substr($b, 0, 16)
);
}
/**
* Compare a 32-character byte string in constant time.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_32($a, $b)
{
/* Type checks: */
if (!is_string($a)) {
throw new TypeError('String expected');
}
if (!is_string($b)) {
throw new TypeError('String expected');
}
return self::hashEquals(
self::substr($a, 0, 32),
self::substr($b, 0, 32)
);
}
/**
* Calculate $a ^ $b for two strings.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return string
* @throws TypeError
*/
public static function xorStrings($a, $b)
{
/* Type checks: */
if (!is_string($a)) {
throw new TypeError('Argument 1 must be a string');
}
if (!is_string($b)) {
throw new TypeError('Argument 2 must be a string');
}
return (string) ($a ^ $b);
}
/**
* Returns whether or not mbstring.func_overload is in effect.
*
* @internal You should not use this directly from another application
*
* Note: MB_OVERLOAD_STRING === 2, but we don't reference the
constant
* (for nuisance-free PHP 8 support)
*
* @return bool
*/
protected static function isMbStringOverride()
{
static $mbstring = null;
if ($mbstring === null) {
$mbstring = extension_loaded('mbstring')
&& defined('MB_OVERLOAD_STRING')
&&
((int) (ini_get('mbstring.func_overload')) & 2);
// MB_OVERLOAD_STRING === 2
}
/** @var bool $mbstring */
return $mbstring;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_X25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_X25519
*/
abstract class ParagonIE_Sodium_Core_X25519 extends
ParagonIE_Sodium_Core_Curve25519
{
/**
* Alters the objects passed to this method in place.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @param int $b
* @return void
* @psalm-suppress MixedAssignment
*/
public static function fe_cswap(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g,
$b = 0
) {
$f0 = (int) $f[0];
$f1 = (int) $f[1];
$f2 = (int) $f[2];
$f3 = (int) $f[3];
$f4 = (int) $f[4];
$f5 = (int) $f[5];
$f6 = (int) $f[6];
$f7 = (int) $f[7];
$f8 = (int) $f[8];
$f9 = (int) $f[9];
$g0 = (int) $g[0];
$g1 = (int) $g[1];
$g2 = (int) $g[2];
$g3 = (int) $g[3];
$g4 = (int) $g[4];
$g5 = (int) $g[5];
$g6 = (int) $g[6];
$g7 = (int) $g[7];
$g8 = (int) $g[8];
$g9 = (int) $g[9];
$b = -$b;
$x0 = ($f0 ^ $g0) & $b;
$x1 = ($f1 ^ $g1) & $b;
$x2 = ($f2 ^ $g2) & $b;
$x3 = ($f3 ^ $g3) & $b;
$x4 = ($f4 ^ $g4) & $b;
$x5 = ($f5 ^ $g5) & $b;
$x6 = ($f6 ^ $g6) & $b;
$x7 = ($f7 ^ $g7) & $b;
$x8 = ($f8 ^ $g8) & $b;
$x9 = ($f9 ^ $g9) & $b;
$f[0] = $f0 ^ $x0;
$f[1] = $f1 ^ $x1;
$f[2] = $f2 ^ $x2;
$f[3] = $f3 ^ $x3;
$f[4] = $f4 ^ $x4;
$f[5] = $f5 ^ $x5;
$f[6] = $f6 ^ $x6;
$f[7] = $f7 ^ $x7;
$f[8] = $f8 ^ $x8;
$f[9] = $f9 ^ $x9;
$g[0] = $g0 ^ $x0;
$g[1] = $g1 ^ $x1;
$g[2] = $g2 ^ $x2;
$g[3] = $g3 ^ $x3;
$g[4] = $g4 ^ $x4;
$g[5] = $g5 ^ $x5;
$g[6] = $g6 ^ $x6;
$g[7] = $g7 ^ $x7;
$g[8] = $g8 ^ $x8;
$g[9] = $g9 ^ $x9;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_mul121666(ParagonIE_Sodium_Core_Curve25519_Fe
$f)
{
$h = array(
self::mul((int) $f[0], 121666, 17),
self::mul((int) $f[1], 121666, 17),
self::mul((int) $f[2], 121666, 17),
self::mul((int) $f[3], 121666, 17),
self::mul((int) $f[4], 121666, 17),
self::mul((int) $f[5], 121666, 17),
self::mul((int) $f[6], 121666, 17),
self::mul((int) $f[7], 121666, 17),
self::mul((int) $f[8], 121666, 17),
self::mul((int) $f[9], 121666, 17)
);
/** @var int $carry9 */
$carry9 = ($h[9] + (1 << 24)) >> 25;
$h[0] += self::mul($carry9, 19, 5);
$h[9] -= $carry9 << 25;
/** @var int $carry1 */
$carry1 = ($h[1] + (1 << 24)) >> 25;
$h[2] += $carry1;
$h[1] -= $carry1 << 25;
/** @var int $carry3 */
$carry3 = ($h[3] + (1 << 24)) >> 25;
$h[4] += $carry3;
$h[3] -= $carry3 << 25;
/** @var int $carry5 */
$carry5 = ($h[5] + (1 << 24)) >> 25;
$h[6] += $carry5;
$h[5] -= $carry5 << 25;
/** @var int $carry7 */
$carry7 = ($h[7] + (1 << 24)) >> 25;
$h[8] += $carry7;
$h[7] -= $carry7 << 25;
/** @var int $carry0 */
$carry0 = ($h[0] + (1 << 25)) >> 26;
$h[1] += $carry0;
$h[0] -= $carry0 << 26;
/** @var int $carry2 */
$carry2 = ($h[2] + (1 << 25)) >> 26;
$h[3] += $carry2;
$h[2] -= $carry2 << 26;
/** @var int $carry4 */
$carry4 = ($h[4] + (1 << 25)) >> 26;
$h[5] += $carry4;
$h[4] -= $carry4 << 26;
/** @var int $carry6 */
$carry6 = ($h[6] + (1 << 25)) >> 26;
$h[7] += $carry6;
$h[6] -= $carry6 << 26;
/** @var int $carry8 */
$carry8 = ($h[8] + (1 << 25)) >> 26;
$h[9] += $carry8;
$h[8] -= $carry8 << 26;
foreach ($h as $i => $value) {
$h[$i] = (int) $value;
}
return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h);
}
/**
* @internal You should not use this directly from another application
*
* Inline comments preceded by # are from libsodium's ref10 code.
*
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10($n, $p)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
# fe_frombytes(x1,p);
$x1 = self::fe_frombytes($p);
# fe_1(x2);
$x2 = self::fe_1();
# fe_0(z2);
$z2 = self::fe_0();
# fe_copy(x3,x1);
$x3 = self::fe_copy($x1);
# fe_1(z3);
$z3 = self::fe_1();
# swap = 0;
/** @var int $swap */
$swap = 0;
# for (pos = 254;pos >= 0;--pos) {
for ($pos = 254; $pos >= 0; --$pos) {
# b = e[pos / 8] >> (pos & 7);
/** @var int $b */
$b = self::chrToInt(
$e[(int) floor($pos / 8)]
) >> ($pos & 7);
# b &= 1;
$b &= 1;
# swap ^= b;
$swap ^= $b;
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# swap = b;
$swap = $b;
# fe_sub(tmp0,x3,z3);
$tmp0 = self::fe_sub($x3, $z3);
# fe_sub(tmp1,x2,z2);
$tmp1 = self::fe_sub($x2, $z2);
# fe_add(x2,x2,z2);
$x2 = self::fe_add($x2, $z2);
# fe_add(z2,x3,z3);
$z2 = self::fe_add($x3, $z3);
# fe_mul(z3,tmp0,x2);
$z3 = self::fe_mul($tmp0, $x2);
# fe_mul(z2,z2,tmp1);
$z2 = self::fe_mul($z2, $tmp1);
# fe_sq(tmp0,tmp1);
$tmp0 = self::fe_sq($tmp1);
# fe_sq(tmp1,x2);
$tmp1 = self::fe_sq($x2);
# fe_add(x3,z3,z2);
$x3 = self::fe_add($z3, $z2);
# fe_sub(z2,z3,z2);
$z2 = self::fe_sub($z3, $z2);
# fe_mul(x2,tmp1,tmp0);
$x2 = self::fe_mul($tmp1, $tmp0);
# fe_sub(tmp1,tmp1,tmp0);
$tmp1 = self::fe_sub($tmp1, $tmp0);
# fe_sq(z2,z2);
$z2 = self::fe_sq($z2);
# fe_mul121666(z3,tmp1);
$z3 = self::fe_mul121666($tmp1);
# fe_sq(x3,x3);
$x3 = self::fe_sq($x3);
# fe_add(tmp0,tmp0,z3);
$tmp0 = self::fe_add($tmp0, $z3);
# fe_mul(z3,x1,z2);
$z3 = self::fe_mul($x1, $z2);
# fe_mul(z2,tmp1,tmp0);
$z2 = self::fe_mul($tmp1, $tmp0);
}
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# fe_invert(z2,z2);
$z2 = self::fe_invert($z2);
# fe_mul(x2,x2,z2);
$x2 = self::fe_mul($x2, $z2);
# fe_tobytes(q,x2);
return self::fe_tobytes($x2);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY
* @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function edwards_to_montgomery(
ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY,
ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ
) {
$tempX = self::fe_add($edwardsZ, $edwardsY);
$tempZ = self::fe_sub($edwardsZ, $edwardsY);
$tempZ = self::fe_invert($tempZ);
return self::fe_mul($tempX, $tempZ);
}
/**
* @internal You should not use this directly from another application
*
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10_base($n)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
$A = self::ge_scalarmult_base($e);
if (
!($A->Y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)
||
!($A->Z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)
) {
throw new TypeError('Null points encountered');
}
$pk = self::edwards_to_montgomery($A->Y, $A->Z);
return self::fe_tobytes($pk);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_XChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_XChaCha20
*/
class ParagonIE_Sodium_Core_XChaCha20 extends
ParagonIE_Sodium_Core_HChaCha20
{
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key =
'')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes
long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx(
self::hChaCha20(
self::substr($nonce, 0, 16),
$key
),
self::substr($nonce, 16, 8)
),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStream($len = 64, $nonce = '',
$key = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes
long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx(
self::hChaCha20(
self::substr($nonce, 0, 16),
$key
),
"\x00\x00\x00\x00" . self::substr($nonce, 16, 8)
),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '',
$key = '', $ic = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes
long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx(
self::hChaCha20(self::substr($nonce, 0, 16), $key),
self::substr($nonce, 16, 8),
$ic
),
$message
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '',
$key = '', $ic = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes
long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx(
self::hChaCha20(self::substr($nonce, 0, 16), $key),
"\x00\x00\x00\x00" . self::substr($nonce, 16, 8),
$ic
),
$message
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_XSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_XSalsa20
*/
abstract class ParagonIE_Sodium_Core_XSalsa20 extends
ParagonIE_Sodium_Core_HSalsa20
{
/**
* Expand a key and nonce into an xsalsa20 keystream.
*
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20($len, $nonce, $key)
{
$ret = self::salsa20(
$len,
self::substr($nonce, 16, 8),
self::hsalsa20($nonce, $key)
);
return $ret;
}
/**
* Encrypt a string with XSalsa20. Doesn't provide integrity.
*
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20_xor($message, $nonce, $key)
{
return self::xorStrings(
$message,
self::xsalsa20(
self::strlen($message),
$nonce,
$key
)
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_BLAKE2b', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_BLAKE2b
*
* Based on the work of Devi Mandiri in devi/salt.
*/
abstract class ParagonIE_Sodium_Core32_BLAKE2b extends
ParagonIE_Sodium_Core_Util
{
/**
* @var SplFixedArray
*/
public static $iv;
/**
* @var array<int, array<int, int>>
*/
public static $sigma = array(
array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15),
array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5,
3),
array( 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9,
4),
array( 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15,
8),
array( 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3,
13),
array( 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1,
9),
array( 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8,
11),
array( 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2,
10),
array( 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10,
5),
array( 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 ,
0),
array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15),
array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5,
3)
);
const BLOCKBYTES = 128;
const OUTBYTES = 64;
const KEYBYTES = 64;
/**
* Turn two 32-bit integers into a fixed array representing a 64-bit
integer.
*
* @internal You should not use this directly from another application
*
* @param int $high
* @param int $low
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public static function new64($high, $low)
{
return ParagonIE_Sodium_Core32_Int64::fromInts($low, $high);
}
/**
* Convert an arbitrary number into an SplFixedArray of two 32-bit
integers
* that represents a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $num
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
protected static function to64($num)
{
list($hi, $lo) = self::numericTo64BitInteger($num);
return self::new64($hi, $lo);
}
/**
* Adds two 64-bit integers together, returning their sum as a
SplFixedArray
* containing two 32-bit integers (representing a 64-bit integer).
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param ParagonIE_Sodium_Core32_Int64 $y
* @return ParagonIE_Sodium_Core32_Int64
*/
protected static function add64($x, $y)
{
return $x->addInt64($y);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param ParagonIE_Sodium_Core32_Int64 $y
* @param ParagonIE_Sodium_Core32_Int64 $z
* @return ParagonIE_Sodium_Core32_Int64
*/
public static function add364($x, $y, $z)
{
return $x->addInt64($y)->addInt64($z);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param ParagonIE_Sodium_Core32_Int64 $y
* @return ParagonIE_Sodium_Core32_Int64
* @throws TypeError
*/
public static function xor64(ParagonIE_Sodium_Core32_Int64 $x,
ParagonIE_Sodium_Core32_Int64 $y)
{
return $x->xorInt64($y);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public static function rotr64(ParagonIE_Sodium_Core32_Int64 $x, $c)
{
return $x->rotateRight($c);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public static function load64($x, $i)
{
/** @var int $l */
$l = (int) ($x[$i])
| ((int) ($x[$i+1]) << 8)
| ((int) ($x[$i+2]) << 16)
| ((int) ($x[$i+3]) << 24);
/** @var int $h */
$h = (int) ($x[$i+4])
| ((int) ($x[$i+5]) << 8)
| ((int) ($x[$i+6]) << 16)
| ((int) ($x[$i+7]) << 24);
return self::new64($h, $l);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @param ParagonIE_Sodium_Core32_Int64 $u
* @return void
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
public static function store64(SplFixedArray $x, $i,
ParagonIE_Sodium_Core32_Int64 $u)
{
$v = clone $u;
$maxLength = $x->getSize() - 1;
for ($j = 0; $j < 8; ++$j) {
$k = 3 - ($j >> 1);
$x[$i] = $v->limbs[$k] & 0xff;
if (++$i > $maxLength) {
return;
}
$v->limbs[$k] >>= 8;
}
}
/**
* This just sets the $iv static variable.
*
* @internal You should not use this directly from another application
*
* @return void
* @throws SodiumException
* @throws TypeError
*/
public static function pseudoConstructor()
{
static $called = false;
if ($called) {
return;
}
self::$iv = new SplFixedArray(8);
self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908);
self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b);
self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b);
self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1);
self::$iv[4] = self::new64(0x510e527f, 0xade682d1);
self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f);
self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b);
self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179);
$called = true;
}
/**
* Returns a fresh BLAKE2 context.
*
* @internal You should not use this directly from another application
*
* @return SplFixedArray
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @throws SodiumException
* @throws TypeError
*/
protected static function context()
{
$ctx = new SplFixedArray(6);
$ctx[0] = new SplFixedArray(8); // h
$ctx[1] = new SplFixedArray(2); // t
$ctx[2] = new SplFixedArray(2); // f
$ctx[3] = new SplFixedArray(256); // buf
$ctx[4] = 0; // buflen
$ctx[5] = 0; // last_node (uint8_t)
for ($i = 8; $i--;) {
$ctx[0][$i] = self::$iv[$i];
}
for ($i = 256; $i--;) {
$ctx[3][$i] = 0;
}
$zero = self::new64(0, 0);
$ctx[1][0] = $zero;
$ctx[1][1] = $zero;
$ctx[2][0] = $zero;
$ctx[2][1] = $zero;
return $ctx;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $buf
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedAssignment
*/
protected static function compress(SplFixedArray $ctx, SplFixedArray
$buf)
{
$m = new SplFixedArray(16);
$v = new SplFixedArray(16);
for ($i = 16; $i--;) {
$m[$i] = self::load64($buf, $i << 3);
}
for ($i = 8; $i--;) {
$v[$i] = $ctx[0][$i];
}
$v[ 8] = self::$iv[0];
$v[ 9] = self::$iv[1];
$v[10] = self::$iv[2];
$v[11] = self::$iv[3];
$v[12] = self::xor64($ctx[1][0], self::$iv[4]);
$v[13] = self::xor64($ctx[1][1], self::$iv[5]);
$v[14] = self::xor64($ctx[2][0], self::$iv[6]);
$v[15] = self::xor64($ctx[2][1], self::$iv[7]);
for ($r = 0; $r < 12; ++$r) {
$v = self::G($r, 0, 0, 4, 8, 12, $v, $m);
$v = self::G($r, 1, 1, 5, 9, 13, $v, $m);
$v = self::G($r, 2, 2, 6, 10, 14, $v, $m);
$v = self::G($r, 3, 3, 7, 11, 15, $v, $m);
$v = self::G($r, 4, 0, 5, 10, 15, $v, $m);
$v = self::G($r, 5, 1, 6, 11, 12, $v, $m);
$v = self::G($r, 6, 2, 7, 8, 13, $v, $m);
$v = self::G($r, 7, 3, 4, 9, 14, $v, $m);
}
for ($i = 8; $i--;) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i], self::xor64($v[$i], $v[$i+8])
);
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $r
* @param int $i
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @param SplFixedArray $v
* @param SplFixedArray $m
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayOffset
*/
public static function G($r, $i, $a, $b, $c, $d, SplFixedArray $v,
SplFixedArray $m)
{
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i
<< 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24);
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i
<< 1) + 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param int $inc
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
public static function increment_counter($ctx, $inc)
{
if ($inc < 0) {
throw new SodiumException('Increasing by a negative number
makes no sense.');
}
$t = self::to64($inc);
# S->t is $ctx[1] in our implementation
# S->t[0] = ( uint64_t )( t >> 0 );
$ctx[1][0] = self::add64($ctx[1][0], $t);
# S->t[1] += ( S->t[0] < inc );
if (!($ctx[1][0] instanceof ParagonIE_Sodium_Core32_Int64)) {
throw new TypeError('Not an int64');
}
/** @var ParagonIE_Sodium_Core32_Int64 $c*/
$c = $ctx[1][0];
if ($c->isLessThanInt($inc)) {
$ctx[1][1] = self::add64($ctx[1][1], self::to64(1));
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $p
* @param int $plen
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedOperand
*/
public static function update(SplFixedArray $ctx, SplFixedArray $p,
$plen)
{
self::pseudoConstructor();
$offset = 0;
while ($plen > 0) {
$left = $ctx[4];
$fill = 256 - $left;
if ($plen > $fill) {
# memcpy( S->buf + left, in, fill ); /* Fill buffer */
for ($i = $fill; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
# S->buflen += fill;
$ctx[4] += $fill;
# blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
self::increment_counter($ctx, 128);
# blake2b_compress( S, S->buf ); /* Compress */
self::compress($ctx, $ctx[3]);
# memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES,
BLAKE2B_BLOCKBYTES ); /* Shift buffer left */
for ($i = 128; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
# S->buflen -= BLAKE2B_BLOCKBYTES;
$ctx[4] -= 128;
# in += fill;
$offset += $fill;
# inlen -= fill;
$plen -= $fill;
} else {
for ($i = $plen; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
$ctx[4] += $plen;
$offset += $plen;
$plen -= $plen;
}
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $out
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedOperand
*/
public static function finish(SplFixedArray $ctx, SplFixedArray $out)
{
self::pseudoConstructor();
if ($ctx[4] > 128) {
self::increment_counter($ctx, 128);
self::compress($ctx, $ctx[3]);
$ctx[4] -= 128;
if ($ctx[4] > 128) {
throw new SodiumException('Failed to assert that
buflen <= 128 bytes');
}
for ($i = $ctx[4]; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
}
self::increment_counter($ctx, $ctx[4]);
$ctx[2][0] = self::new64(0xffffffff, 0xffffffff);
for ($i = 256 - $ctx[4]; $i--;) {
/** @var int $i */
$ctx[3][$i + $ctx[4]] = 0;
}
self::compress($ctx, $ctx[3]);
$i = (int) (($out->getSize() - 1) / 8);
for (; $i >= 0; --$i) {
self::store64($out, $i << 3, $ctx[0][$i]);
}
return $out;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray|null $key
* @param int $outlen
* @param SplFixedArray|null $salt
* @param SplFixedArray|null $personal
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedMethodCall
*/
public static function init(
$key = null,
$outlen = 64,
$salt = null,
$personal = null
) {
self::pseudoConstructor();
$klen = 0;
if ($key !== null) {
if (count($key) > 64) {
throw new SodiumException('Invalid key size');
}
$klen = count($key);
}
if ($outlen > 64) {
throw new SodiumException('Invalid output size');
}
$ctx = self::context();
$p = new SplFixedArray(64);
// Zero our param buffer...
for ($i = 64; --$i;) {
$p[$i] = 0;
}
$p[0] = $outlen; // digest_length
$p[1] = $klen; // key_length
$p[2] = 1; // fanout
$p[3] = 1; // depth
if ($salt instanceof SplFixedArray) {
// salt: [32] through [47]
for ($i = 0; $i < 16; ++$i) {
$p[32 + $i] = (int) $salt[$i];
}
}
if ($personal instanceof SplFixedArray) {
// personal: [48] through [63]
for ($i = 0; $i < 16; ++$i) {
$p[48 + $i] = (int) $personal[$i];
}
}
$ctx[0][0] = self::xor64(
$ctx[0][0],
self::load64($p, 0)
);
if ($salt instanceof SplFixedArray || $personal instanceof
SplFixedArray) {
// We need to do what blake2b_init_param() does:
for ($i = 1; $i < 8; ++$i) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i],
self::load64($p, $i << 3)
);
}
}
if ($klen > 0 && $key instanceof SplFixedArray) {
$block = new SplFixedArray(128);
for ($i = 128; $i--;) {
$block[$i] = 0;
}
for ($i = $klen; $i--;) {
$block[$i] = $key[$i];
}
self::update($ctx, $block, 128);
$ctx[4] = 128;
}
return $ctx;
}
/**
* Convert a string into an SplFixedArray of integers
*
* @internal You should not use this directly from another application
*
* @param string $str
* @return SplFixedArray
*/
public static function stringToSplFixedArray($str = '')
{
$values = unpack('C*', $str);
return SplFixedArray::fromArray(array_values($values));
}
/**
* Convert an SplFixedArray of integers into a string
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $a
* @return string
*/
public static function SplFixedArrayToString(SplFixedArray $a)
{
/**
* @var array<int, string|int>
*/
$arr = $a->toArray();
$c = $a->count();
array_unshift($arr, str_repeat('C', $c));
return (string) (call_user_func_array('pack', $arr));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @return string
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedMethodCall
*/
public static function contextToString(SplFixedArray $ctx)
{
$str = '';
/** @var array<int, ParagonIE_Sodium_Core32_Int64> $ctxA */
$ctxA = $ctx[0]->toArray();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
if (!($ctxA[$i] instanceof ParagonIE_Sodium_Core32_Int64)) {
throw new TypeError('Not an instance of Int64');
}
/** @var ParagonIE_Sodium_Core32_Int64 $ctxAi */
$ctxAi = $ctxA[$i];
$str .= $ctxAi->toReverseString();
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
/** @var array<int, ParagonIE_Sodium_Core32_Int64> $ctxA
*/
$ctxA = $ctx[$i]->toArray();
/** @var ParagonIE_Sodium_Core32_Int64 $ctxA1 */
$ctxA1 = $ctxA[0];
/** @var ParagonIE_Sodium_Core32_Int64 $ctxA2 */
$ctxA2 = $ctxA[1];
$str .= $ctxA1->toReverseString();
$str .= $ctxA2->toReverseString();
}
# uint8_t buf[2 * 128];
$str .= self::SplFixedArrayToString($ctx[3]);
/** @var int $ctx4 */
$ctx4 = $ctx[4];
# size_t buflen;
$str .= implode('', array(
self::intToChr($ctx4 & 0xff),
self::intToChr(($ctx4 >> 8) & 0xff),
self::intToChr(($ctx4 >> 16) & 0xff),
self::intToChr(($ctx4 >> 24) & 0xff),
"\x00\x00\x00\x00"
/*
self::intToChr(($ctx4 >> 32) & 0xff),
self::intToChr(($ctx4 >> 40) & 0xff),
self::intToChr(($ctx4 >> 48) & 0xff),
self::intToChr(($ctx4 >> 56) & 0xff)
*/
));
# uint8_t last_node;
return $str . self::intToChr($ctx[5]) .
str_repeat("\x00", 23);
}
/**
* Creates an SplFixedArray containing other SplFixedArray elements,
from
* a string (compatible with \Sodium\crypto_generichash_{init, update,
final})
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
public static function stringToContext($string)
{
$ctx = self::context();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$ctx[0][$i] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($string, (($i << 3) + 0), 8)
);
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctx[$i][1] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($string, 72 + (($i - 1) << 4), 8)
);
$ctx[$i][0] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($string, 64 + (($i - 1) << 4), 8)
);
}
# uint8_t buf[2 * 128];
$ctx[3] = self::stringToSplFixedArray(self::substr($string, 96,
256));
# uint8_t buf[2 * 128];
$int = 0;
for ($i = 0; $i < 8; ++$i) {
$int |= self::chrToInt($string[352 + $i]) << ($i <<
3);
}
$ctx[4] = $int;
return $ctx;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20_Ctx
*/
class ParagonIE_Sodium_Core32_ChaCha20_Ctx extends
ParagonIE_Sodium_Core32_Util implements ArrayAccess
{
/**
* @var SplFixedArray internally, <int,
ParagonIE_Sodium_Core32_Int32>
*/
protected $container;
/**
* ParagonIE_Sodium_Core_ChaCha20_Ctx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 8 0x00 bytes.
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct($key = '', $iv = '',
$counter = '')
{
if (self::strlen($key) !== 32) {
throw new InvalidArgumentException('ChaCha20 expects a
256-bit key.');
}
if (self::strlen($iv) !== 8) {
throw new InvalidArgumentException('ChaCha20 expects a
64-bit nonce.');
}
$this->container = new SplFixedArray(16);
/* "expand 32-byte k" as per ChaCha20 spec */
$this->container[0] = new
ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
$this->container[1] = new
ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
$this->container[2] = new
ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
$this->container[3] = new
ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
$this->container[4] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4));
$this->container[5] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 4, 4));
$this->container[6] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 8, 4));
$this->container[7] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12,
4));
$this->container[8] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16,
4));
$this->container[9] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20,
4));
$this->container[10] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24,
4));
$this->container[11] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28,
4));
if (empty($counter)) {
$this->container[12] = new ParagonIE_Sodium_Core32_Int32();
$this->container[13] = new ParagonIE_Sodium_Core32_Int32();
} else {
$this->container[12] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 0,
4));
$this->container[13] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 4,
4));
}
$this->container[14] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 0, 4));
$this->container[15] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 4, 4));
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @param int|ParagonIE_Sodium_Core32_Int32 $value
* @return void
*/
public function offsetSet($offset, $value)
{
if (!is_int($offset)) {
throw new InvalidArgumentException('Expected an
integer');
}
if ($value instanceof ParagonIE_Sodium_Core32_Int32) {
/*
} elseif (is_int($value)) {
$value = ParagonIE_Sodium_Core32_Int32::fromInt($value);
*/
} else {
throw new InvalidArgumentException('Expected an
integer');
}
$this->container[$offset] = $value;
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
* @psalm-suppress MixedArrayOffset
*/
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return mixed|null
* @psalm-suppress MixedArrayOffset
*/
public function offsetGet($offset)
{
return isset($this->container[$offset])
? $this->container[$offset]
: null;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20_IetfCtx
*/
class ParagonIE_Sodium_Core32_ChaCha20_IetfCtx extends
ParagonIE_Sodium_Core32_ChaCha20_Ctx
{
/**
* ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 4 0x00 bytes.
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct($key = '', $iv = '',
$counter = '')
{
if (self::strlen($iv) !== 12) {
throw new InvalidArgumentException('ChaCha20 expects a
96-bit nonce in IETF mode.');
}
parent::__construct($key, self::substr($iv, 0, 8), $counter);
if (!empty($counter)) {
$this->container[12] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 0,
4));
}
$this->container[13] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 0, 4));
$this->container[14] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 4, 4));
$this->container[15] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 8, 4));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_ChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20
*/
class ParagonIE_Sodium_Core32_ChaCha20 extends ParagonIE_Sodium_Core32_Util
{
/**
* The ChaCha20 quarter round function. Works on four 32-bit integers.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int32 $a
* @param ParagonIE_Sodium_Core32_Int32 $b
* @param ParagonIE_Sodium_Core32_Int32 $c
* @param ParagonIE_Sodium_Core32_Int32 $d
* @return array<int, ParagonIE_Sodium_Core32_Int32>
* @throws SodiumException
* @throws TypeError
*/
protected static function quarterRound(
ParagonIE_Sodium_Core32_Int32 $a,
ParagonIE_Sodium_Core32_Int32 $b,
ParagonIE_Sodium_Core32_Int32 $c,
ParagonIE_Sodium_Core32_Int32 $d
) {
/** @var ParagonIE_Sodium_Core32_Int32 $a */
/** @var ParagonIE_Sodium_Core32_Int32 $b */
/** @var ParagonIE_Sodium_Core32_Int32 $c */
/** @var ParagonIE_Sodium_Core32_Int32 $d */
# a = PLUS(a,b); d = ROTATE(XOR(d,a),16);
$a = $a->addInt32($b);
$d = $d->xorInt32($a)->rotateLeft(16);
# c = PLUS(c,d); b = ROTATE(XOR(b,c),12);
$c = $c->addInt32($d);
$b = $b->xorInt32($c)->rotateLeft(12);
# a = PLUS(a,b); d = ROTATE(XOR(d,a), 8);
$a = $a->addInt32($b);
$d = $d->xorInt32($a)->rotateLeft(8);
# c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
$c = $c->addInt32($d);
$b = $b->xorInt32($c)->rotateLeft(7);
return array($a, $b, $c, $d);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx
* @param string $message
*
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function encryptBytes(
ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx,
$message = ''
) {
$bytes = self::strlen($message);
/** @var ParagonIE_Sodium_Core32_Int32 $x0 */
/** @var ParagonIE_Sodium_Core32_Int32 $x1 */
/** @var ParagonIE_Sodium_Core32_Int32 $x2 */
/** @var ParagonIE_Sodium_Core32_Int32 $x3 */
/** @var ParagonIE_Sodium_Core32_Int32 $x4 */
/** @var ParagonIE_Sodium_Core32_Int32 $x5 */
/** @var ParagonIE_Sodium_Core32_Int32 $x6 */
/** @var ParagonIE_Sodium_Core32_Int32 $x7 */
/** @var ParagonIE_Sodium_Core32_Int32 $x8 */
/** @var ParagonIE_Sodium_Core32_Int32 $x9 */
/** @var ParagonIE_Sodium_Core32_Int32 $x10 */
/** @var ParagonIE_Sodium_Core32_Int32 $x11 */
/** @var ParagonIE_Sodium_Core32_Int32 $x12 */
/** @var ParagonIE_Sodium_Core32_Int32 $x13 */
/** @var ParagonIE_Sodium_Core32_Int32 $x14 */
/** @var ParagonIE_Sodium_Core32_Int32 $x15 */
/*
j0 = ctx->input[0];
j1 = ctx->input[1];
j2 = ctx->input[2];
j3 = ctx->input[3];
j4 = ctx->input[4];
j5 = ctx->input[5];
j6 = ctx->input[6];
j7 = ctx->input[7];
j8 = ctx->input[8];
j9 = ctx->input[9];
j10 = ctx->input[10];
j11 = ctx->input[11];
j12 = ctx->input[12];
j13 = ctx->input[13];
j14 = ctx->input[14];
j15 = ctx->input[15];
*/
/** @var ParagonIE_Sodium_Core32_Int32 $j0 */
$j0 = $ctx[0];
/** @var ParagonIE_Sodium_Core32_Int32 $j1 */
$j1 = $ctx[1];
/** @var ParagonIE_Sodium_Core32_Int32 $j2 */
$j2 = $ctx[2];
/** @var ParagonIE_Sodium_Core32_Int32 $j3 */
$j3 = $ctx[3];
/** @var ParagonIE_Sodium_Core32_Int32 $j4 */
$j4 = $ctx[4];
/** @var ParagonIE_Sodium_Core32_Int32 $j5 */
$j5 = $ctx[5];
/** @var ParagonIE_Sodium_Core32_Int32 $j6 */
$j6 = $ctx[6];
/** @var ParagonIE_Sodium_Core32_Int32 $j7 */
$j7 = $ctx[7];
/** @var ParagonIE_Sodium_Core32_Int32 $j8 */
$j8 = $ctx[8];
/** @var ParagonIE_Sodium_Core32_Int32 $j9 */
$j9 = $ctx[9];
/** @var ParagonIE_Sodium_Core32_Int32 $j10 */
$j10 = $ctx[10];
/** @var ParagonIE_Sodium_Core32_Int32 $j11 */
$j11 = $ctx[11];
/** @var ParagonIE_Sodium_Core32_Int32 $j12 */
$j12 = $ctx[12];
/** @var ParagonIE_Sodium_Core32_Int32 $j13 */
$j13 = $ctx[13];
/** @var ParagonIE_Sodium_Core32_Int32 $j14 */
$j14 = $ctx[14];
/** @var ParagonIE_Sodium_Core32_Int32 $j15 */
$j15 = $ctx[15];
$c = '';
for (;;) {
if ($bytes < 64) {
$message .= str_repeat("\x00", 64 - $bytes);
}
$x0 = clone $j0;
$x1 = clone $j1;
$x2 = clone $j2;
$x3 = clone $j3;
$x4 = clone $j4;
$x5 = clone $j5;
$x6 = clone $j6;
$x7 = clone $j7;
$x8 = clone $j8;
$x9 = clone $j9;
$x10 = clone $j10;
$x11 = clone $j11;
$x12 = clone $j12;
$x13 = clone $j13;
$x14 = clone $j14;
$x15 = clone $j15;
# for (i = 20; i > 0; i -= 2) {
for ($i = 20; $i > 0; $i -= 2) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4,
$x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5,
$x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6,
$x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7,
$x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5,
$x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6,
$x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7,
$x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4,
$x9, $x14);
}
/*
x0 = PLUS(x0, j0);
x1 = PLUS(x1, j1);
x2 = PLUS(x2, j2);
x3 = PLUS(x3, j3);
x4 = PLUS(x4, j4);
x5 = PLUS(x5, j5);
x6 = PLUS(x6, j6);
x7 = PLUS(x7, j7);
x8 = PLUS(x8, j8);
x9 = PLUS(x9, j9);
x10 = PLUS(x10, j10);
x11 = PLUS(x11, j11);
x12 = PLUS(x12, j12);
x13 = PLUS(x13, j13);
x14 = PLUS(x14, j14);
x15 = PLUS(x15, j15);
*/
$x0 = $x0->addInt32($j0);
$x1 = $x1->addInt32($j1);
$x2 = $x2->addInt32($j2);
$x3 = $x3->addInt32($j3);
$x4 = $x4->addInt32($j4);
$x5 = $x5->addInt32($j5);
$x6 = $x6->addInt32($j6);
$x7 = $x7->addInt32($j7);
$x8 = $x8->addInt32($j8);
$x9 = $x9->addInt32($j9);
$x10 = $x10->addInt32($j10);
$x11 = $x11->addInt32($j11);
$x12 = $x12->addInt32($j12);
$x13 = $x13->addInt32($j13);
$x14 = $x14->addInt32($j14);
$x15 = $x15->addInt32($j15);
/*
x0 = XOR(x0, LOAD32_LE(m + 0));
x1 = XOR(x1, LOAD32_LE(m + 4));
x2 = XOR(x2, LOAD32_LE(m + 8));
x3 = XOR(x3, LOAD32_LE(m + 12));
x4 = XOR(x4, LOAD32_LE(m + 16));
x5 = XOR(x5, LOAD32_LE(m + 20));
x6 = XOR(x6, LOAD32_LE(m + 24));
x7 = XOR(x7, LOAD32_LE(m + 28));
x8 = XOR(x8, LOAD32_LE(m + 32));
x9 = XOR(x9, LOAD32_LE(m + 36));
x10 = XOR(x10, LOAD32_LE(m + 40));
x11 = XOR(x11, LOAD32_LE(m + 44));
x12 = XOR(x12, LOAD32_LE(m + 48));
x13 = XOR(x13, LOAD32_LE(m + 52));
x14 = XOR(x14, LOAD32_LE(m + 56));
x15 = XOR(x15, LOAD32_LE(m + 60));
*/
$x0 =
$x0->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
0, 4)));
$x1 =
$x1->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
4, 4)));
$x2 =
$x2->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
8, 4)));
$x3 =
$x3->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
12, 4)));
$x4 =
$x4->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
16, 4)));
$x5 =
$x5->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
20, 4)));
$x6 =
$x6->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
24, 4)));
$x7 =
$x7->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
28, 4)));
$x8 =
$x8->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
32, 4)));
$x9 =
$x9->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
36, 4)));
$x10 =
$x10->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
40, 4)));
$x11 =
$x11->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
44, 4)));
$x12 =
$x12->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
48, 4)));
$x13 =
$x13->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
52, 4)));
$x14 =
$x14->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
56, 4)));
$x15 =
$x15->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message,
60, 4)));
/*
j12 = PLUSONE(j12);
if (!j12) {
j13 = PLUSONE(j13);
}
*/
/** @var ParagonIE_Sodium_Core32_Int32 $j12 */
$j12 = $j12->addInt(1);
if ($j12->limbs[0] === 0 && $j12->limbs[1] === 0)
{
$j13 = $j13->addInt(1);
}
/*
STORE32_LE(c + 0, x0);
STORE32_LE(c + 4, x1);
STORE32_LE(c + 8, x2);
STORE32_LE(c + 12, x3);
STORE32_LE(c + 16, x4);
STORE32_LE(c + 20, x5);
STORE32_LE(c + 24, x6);
STORE32_LE(c + 28, x7);
STORE32_LE(c + 32, x8);
STORE32_LE(c + 36, x9);
STORE32_LE(c + 40, x10);
STORE32_LE(c + 44, x11);
STORE32_LE(c + 48, x12);
STORE32_LE(c + 52, x13);
STORE32_LE(c + 56, x14);
STORE32_LE(c + 60, x15);
*/
$block = $x0->toReverseString() .
$x1->toReverseString() .
$x2->toReverseString() .
$x3->toReverseString() .
$x4->toReverseString() .
$x5->toReverseString() .
$x6->toReverseString() .
$x7->toReverseString() .
$x8->toReverseString() .
$x9->toReverseString() .
$x10->toReverseString() .
$x11->toReverseString() .
$x12->toReverseString() .
$x13->toReverseString() .
$x14->toReverseString() .
$x15->toReverseString();
/* Partial block */
if ($bytes < 64) {
$c .= self::substr($block, 0, $bytes);
break;
}
/* Full block */
$c .= $block;
$bytes -= 64;
if ($bytes <= 0) {
break;
}
$message = self::substr($message, 64);
}
/* end for(;;) loop */
$ctx[12] = $j12;
$ctx[13] = $j13;
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key =
'')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStream($len, $nonce = '', $key =
'')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '',
$key = '', $ic = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce,
$ic),
$message
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '',
$key = '', $ic = '')
{
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce, $ic),
$message
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Fe', false))
{
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Fe
*
* This represents a Field Element
*/
class ParagonIE_Sodium_Core32_Curve25519_Fe implements ArrayAccess
{
/**
* @var array<int, ParagonIE_Sodium_Core32_Int32>
*/
protected $container = array();
/**
* @var int
*/
protected $size = 10;
/**
* @internal You should not use this directly from another application
*
* @param array<int, ParagonIE_Sodium_Core32_Int32> $array
* @param bool $save_indexes
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromArray($array, $save_indexes = null)
{
$count = count($array);
if ($save_indexes) {
$keys = array_keys($array);
} else {
$keys = range(0, $count - 1);
}
$array = array_values($array);
$obj = new ParagonIE_Sodium_Core32_Curve25519_Fe();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$array[$i]->overflow = 0;
$obj->offsetSet($keys[$i], $array[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$array[$i]->overflow = 0;
$obj->offsetSet($i, $array[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @param bool $save_indexes
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromIntArray($array, $save_indexes = null)
{
$count = count($array);
if ($save_indexes) {
$keys = array_keys($array);
} else {
$keys = range(0, $count - 1);
}
$array = array_values($array);
$set = array();
/** @var int $i */
/** @var int $v */
foreach ($array as $i => $v) {
$set[$i] = ParagonIE_Sodium_Core32_Int32::fromInt($v);
}
$obj = new ParagonIE_Sodium_Core32_Curve25519_Fe();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$set[$i]->overflow = 0;
$obj->offsetSet($keys[$i], $set[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$set[$i]->overflow = 0;
$obj->offsetSet($i, $set[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @param mixed $value
* @return void
* @throws SodiumException
* @throws TypeError
*/
public function offsetSet($offset, $value)
{
if (!($value instanceof ParagonIE_Sodium_Core32_Int32)) {
throw new InvalidArgumentException('Expected an instance
of ParagonIE_Sodium_Core32_Int32');
}
if (is_null($offset)) {
$this->container[] = $value;
} else {
ParagonIE_Sodium_Core32_Util::declareScalarType($offset,
'int', 1);
$this->container[(int) $offset] = $value;
}
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @return bool
* @psalm-suppress MixedArrayOffset
*/
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @return ParagonIE_Sodium_Core32_Int32
* @psalm-suppress MixedArrayOffset
*/
public function offsetGet($offset)
{
if (!isset($this->container[$offset])) {
$this->container[(int) $offset] = new
ParagonIE_Sodium_Core32_Int32();
}
/** @var ParagonIE_Sodium_Core32_Int32 $get */
$get = $this->container[$offset];
return $get;
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
if (empty($this->container)) {
return array();
}
$c = array(
(int) ($this->container[0]->toInt()),
(int) ($this->container[1]->toInt()),
(int) ($this->container[2]->toInt()),
(int) ($this->container[3]->toInt()),
(int) ($this->container[4]->toInt()),
(int) ($this->container[5]->toInt()),
(int) ($this->container[6]->toInt()),
(int) ($this->container[7]->toInt()),
(int) ($this->container[8]->toInt()),
(int) ($this->container[9]->toInt())
);
return array(implode(', ', $c));
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_Cached',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $YplusX;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $YminusX;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $T2d;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_Cached constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $YplusX
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $YminusX
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $Z
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $T2d
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $YplusX = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $YminusX = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $Z = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $T2d = null
) {
if ($YplusX === null) {
$YplusX = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->YplusX = $YplusX;
if ($YminusX === null) {
$YminusX = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->YminusX = $YminusX;
if ($Z === null) {
$Z = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Z = $Z;
if ($T2d === null) {
$T2d = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->T2d = $T2d;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $t
*
* @throws SodiumException
* @throws TypeError
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $x = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $y = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $z = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $t = null
) {
if ($x === null) {
$x = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->X = $x;
if ($y === null) {
$y = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->Y = $y;
if ($z === null) {
$z = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->Z = $z;
if ($t === null) {
$t = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->T = $t;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P2',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P2
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_P2
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_P2 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $x = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $y = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $z = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Z = $z;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P3',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P3
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_P3
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_P3 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $t
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $x = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $y = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $z = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $t = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Z = $z;
if ($t === null) {
$t = new ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->T = $t;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $yplusx;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $yminusx;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $xy2d;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $yplusx
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $yminusx
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $xy2d
* @throws SodiumException
* @throws TypeError
*/
public function __construct(
ParagonIE_Sodium_Core32_Curve25519_Fe $yplusx = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $yminusx = null,
ParagonIE_Sodium_Core32_Curve25519_Fe $xy2d = null
) {
if ($yplusx === null) {
$yplusx = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->yplusx = $yplusx;
if ($yminusx === null) {
$yminusx = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->yminusx = $yminusx;
if ($xy2d === null) {
$xy2d = ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->xy2d = $xy2d;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519_H', false))
{
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_H
*
* This just contains the constants in the ref10/base.h file
*/
class ParagonIE_Sodium_Core32_Curve25519_H extends
ParagonIE_Sodium_Core32_Util
{
/**
* See: libsodium's crypto_core/curve25519/ref10/base.h
*
* @var array<int, array<int, array<int, array<int,
int>>>> Basically, int[32][8][3][10]
*/
protected static $base = array(
array(
array(
array(25967493, -14356035, 29566456, 3660896, -12694345,
4014787, 27544626, -11754271, -6079156, 2047605),
array(-12545711, 934262, -2722910, 3049990, -727428,
9406986, 12720692, 5043384, 19500929, -15469378),
array(-8738181, 4489570, 9688441, -14785194, 10184609,
-12363380, 29287919, 11864899, -24514362, -4438546),
),
array(
array(-12815894, -12976347, -21581243, 11784320, -25355658,
-2750717, -11717903, -3814571, -358445, -10211303),
array(-21703237, 6903825, 27185491, 6451973, -29577724,
-9554005, -15616551, 11189268, -26829678, -5319081),
array(26966642, 11152617, 32442495, 15396054, 14353839,
-12752335, -3128826, -9541118, -15472047, -4166697),
),
array(
array(15636291, -9688557, 24204773, -7912398, 616977,
-16685262, 27787600, -14772189, 28944400, -1550024),
array(16568933, 4717097, -11556148, -1102322, 15682896,
-11807043, 16354577, -11775962, 7689662, 11199574),
array(30464156, -5976125, -11779434, -15670865, 23220365,
15915852, 7512774, 10017326, -17749093, -9920357),
),
array(
array(-17036878, 13921892, 10945806, -6033431, 27105052,
-16084379, -28926210, 15006023, 3284568, -6276540),
array(23599295, -8306047, -11193664, -7687416, 13236774,
10506355, 7464579, 9656445, 13059162, 10374397),
array(7798556, 16710257, 3033922, 2874086, 28997861,
2835604, 32406664, -3839045, -641708, -101325),
),
array(
array(10861363, 11473154, 27284546, 1981175, -30064349,
12577861, 32867885, 14515107, -15438304, 10819380),
array(4708026, 6336745, 20377586, 9066809, -11272109,
6594696, -25653668, 12483688, -12668491, 5581306),
array(19563160, 16186464, -29386857, 4097519, 10237984,
-4348115, 28542350, 13850243, -23678021, -15815942),
),
array(
array(-15371964, -12862754, 32573250, 4720197, -26436522,
5875511, -19188627, -15224819, -9818940, -12085777),
array(-8549212, 109983, 15149363, 2178705, 22900618,
4543417, 3044240, -15689887, 1762328, 14866737),
array(-18199695, -15951423, -10473290, 1707278, -17185920,
3916101, -28236412, 3959421, 27914454, 4383652),
),
array(
array(5153746, 9909285, 1723747, -2777874, 30523605,
5516873, 19480852, 5230134, -23952439, -15175766),
array(-30269007, -3463509, 7665486, 10083793, 28475525,
1649722, 20654025, 16520125, 30598449, 7715701),
array(28881845, 14381568, 9657904, 3680757, -20181635,
7843316, -31400660, 1370708, 29794553, -1409300),
),
array(
array(14499471, -2729599, -33191113, -4254652, 28494862,
14271267, 30290735, 10876454, -33154098, 2381726),
array(-7195431, -2655363, -14730155, 462251, -27724326,
3941372, -6236617, 3696005, -32300832, 15351955),
array(27431194, 8222322, 16448760, -3907995, -18707002,
11938355, -32961401, -2970515, 29551813, 10109425),
),
),
array(
array(
array(-13657040, -13155431, -31283750, 11777098, 21447386,
6519384, -2378284, -1627556, 10092783, -4764171),
array(27939166, 14210322, 4677035, 16277044, -22964462,
-12398139, -32508754, 12005538, -17810127, 12803510),
array(17228999, -15661624, -1233527, 300140, -1224870,
-11714777, 30364213, -9038194, 18016357, 4397660),
),
array(
array(-10958843, -7690207, 4776341, -14954238, 27850028,
-15602212, -26619106, 14544525, -17477504, 982639),
array(29253598, 15796703, -2863982, -9908884, 10057023,
3163536, 7332899, -4120128, -21047696, 9934963),
array(5793303, 16271923, -24131614, -10116404, 29188560,
1206517, -14747930, 4559895, -30123922, -10897950),
),
array(
array(-27643952, -11493006, 16282657, -11036493, 28414021,
-15012264, 24191034, 4541697, -13338309, 5500568),
array(12650548, -1497113, 9052871, 11355358, -17680037,
-8400164, -17430592, 12264343, 10874051, 13524335),
array(25556948, -3045990, 714651, 2510400, 23394682,
-10415330, 33119038, 5080568, -22528059, 5376628),
),
array(
array(-26088264, -4011052, -17013699, -3537628, -6726793,
1920897, -22321305, -9447443, 4535768, 1569007),
array(-2255422, 14606630, -21692440, -8039818, 28430649,
8775819, -30494562, 3044290, 31848280, 12543772),
array(-22028579, 2943893, -31857513, 6777306, 13784462,
-4292203, -27377195, -2062731, 7718482, 14474653),
),
array(
array(2385315, 2454213, -22631320, 46603, -4437935,
-15680415, 656965, -7236665, 24316168, -5253567),
array(13741529, 10911568, -33233417, -8603737, -20177830,
-1033297, 33040651, -13424532, -20729456, 8321686),
array(21060490, -2212744, 15712757, -4336099, 1639040,
10656336, 23845965, -11874838, -9984458, 608372),
),
array(
array(-13672732, -15087586, -10889693, -7557059, -6036909,
11305547, 1123968, -6780577, 27229399, 23887),
array(-23244140, -294205, -11744728, 14712571, -29465699,
-2029617, 12797024, -6440308, -1633405, 16678954),
array(-29500620, 4770662, -16054387, 14001338, 7830047,
9564805, -1508144, -4795045, -17169265, 4904953),
),
array(
array(24059557, 14617003, 19037157, -15039908, 19766093,
-14906429, 5169211, 16191880, 2128236, -4326833),
array(-16981152, 4124966, -8540610, -10653797, 30336522,
-14105247, -29806336, 916033, -6882542, -2986532),
array(-22630907, 12419372, -7134229, -7473371, -16478904,
16739175, 285431, 2763829, 15736322, 4143876),
),
array(
array(2379352, 11839345, -4110402, -5988665, 11274298,
794957, 212801, -14594663, 23527084, -16458268),
array(33431127, -11130478, -17838966, -15626900, 8909499,
8376530, -32625340, 4087881, -15188911, -14416214),
array(1767683, 7197987, -13205226, -2022635, -13091350,
448826, 5799055, 4357868, -4774191, -16323038),
),
),
array(
array(
array(6721966, 13833823, -23523388, -1551314, 26354293,
-11863321, 23365147, -3949732, 7390890, 2759800),
array(4409041, 2052381, 23373853, 10530217, 7676779,
-12885954, 21302353, -4264057, 1244380, -12919645),
array(-4421239, 7169619, 4982368, -2957590, 30256825,
-2777540, 14086413, 9208236, 15886429, 16489664),
),
array(
array(1996075, 10375649, 14346367, 13311202, -6874135,
-16438411, -13693198, 398369, -30606455, -712933),
array(-25307465, 9795880, -2777414, 14878809, -33531835,
14780363, 13348553, 12076947, -30836462, 5113182),
array(-17770784, 11797796, 31950843, 13929123, -25888302,
12288344, -30341101, -7336386, 13847711, 5387222),
),
array(
array(-18582163, -3416217, 17824843, -2340966, 22744343,
-10442611, 8763061, 3617786, -19600662, 10370991),
array(20246567, -14369378, 22358229, -543712, 18507283,
-10413996, 14554437, -8746092, 32232924, 16763880),
array(9648505, 10094563, 26416693, 14745928, -30374318,
-6472621, 11094161, 15689506, 3140038, -16510092),
),
array(
array(-16160072, 5472695, 31895588, 4744994, 8823515,
10365685, -27224800, 9448613, -28774454, 366295),
array(19153450, 11523972, -11096490, -6503142, -24647631,
5420647, 28344573, 8041113, 719605, 11671788),
array(8678025, 2694440, -6808014, 2517372, 4964326,
11152271, -15432916, -15266516, 27000813, -10195553),
),
array(
array(-15157904, 7134312, 8639287, -2814877, -7235688,
10421742, 564065, 5336097, 6750977, -14521026),
array(11836410, -3979488, 26297894, 16080799, 23455045,
15735944, 1695823, -8819122, 8169720, 16220347),
array(-18115838, 8653647, 17578566, -6092619, -8025777,
-16012763, -11144307, -2627664, -5990708, -14166033),
),
array(
array(-23308498, -10968312, 15213228, -10081214, -30853605,
-11050004, 27884329, 2847284, 2655861, 1738395),
array(-27537433, -14253021, -25336301, -8002780, -9370762,
8129821, 21651608, -3239336, -19087449, -11005278),
array(1533110, 3437855, 23735889, 459276, 29970501,
11335377, 26030092, 5821408, 10478196, 8544890),
),
array(
array(32173121, -16129311, 24896207, 3921497, 22579056,
-3410854, 19270449, 12217473, 17789017, -3395995),
array(-30552961, -2228401, -15578829, -10147201, 13243889,
517024, 15479401, -3853233, 30460520, 1052596),
array(-11614875, 13323618, 32618793, 8175907, -15230173,
12596687, 27491595, -4612359, 3179268, -9478891),
),
array(
array(31947069, -14366651, -4640583, -15339921, -15125977,
-6039709, -14756777, -16411740, 19072640, -9511060),
array(11685058, 11822410, 3158003, -13952594, 33402194,
-4165066, 5977896, -5215017, 473099, 5040608),
array(-20290863, 8198642, -27410132, 11602123, 1290375,
-2799760, 28326862, 1721092, -19558642, -3131606),
),
),
array(
array(
array(7881532, 10687937, 7578723, 7738378, -18951012,
-2553952, 21820786, 8076149, -27868496, 11538389),
array(-19935666, 3899861, 18283497, -6801568, -15728660,
-11249211, 8754525, 7446702, -5676054, 5797016),
array(-11295600, -3793569, -15782110, -7964573, 12708869,
-8456199, 2014099, -9050574, -2369172, -5877341),
),
array(
array(-22472376, -11568741, -27682020, 1146375, 18956691,
16640559, 1192730, -3714199, 15123619, 10811505),
array(14352098, -3419715, -18942044, 10822655, 32750596,
4699007, -70363, 15776356, -28886779, -11974553),
array(-28241164, -8072475, -4978962, -5315317, 29416931,
1847569, -20654173, -16484855, 4714547, -9600655),
),
array(
array(15200332, 8368572, 19679101, 15970074, -31872674,
1959451, 24611599, -4543832, -11745876, 12340220),
array(12876937, -10480056, 33134381, 6590940, -6307776,
14872440, 9613953, 8241152, 15370987, 9608631),
array(-4143277, -12014408, 8446281, -391603, 4407738,
13629032, -7724868, 15866074, -28210621, -8814099),
),
array(
array(26660628, -15677655, 8393734, 358047, -7401291,
992988, -23904233, 858697, 20571223, 8420556),
array(14620715, 13067227, -15447274, 8264467, 14106269,
15080814, 33531827, 12516406, -21574435, -12476749),
array(236881, 10476226, 57258, -14677024, 6472998, 2466984,
17258519, 7256740, 8791136, 15069930),
),
array(
array(1276410, -9371918, 22949635, -16322807, -23493039,
-5702186, 14711875, 4874229, -30663140, -2331391),
array(5855666, 4990204, -13711848, 7294284, -7804282,
1924647, -1423175, -7912378, -33069337, 9234253),
array(20590503, -9018988, 31529744, -7352666, -2706834,
10650548, 31559055, -11609587, 18979186, 13396066),
),
array(
array(24474287, 4968103, 22267082, 4407354, 24063882,
-8325180, -18816887, 13594782, 33514650, 7021958),
array(-11566906, -6565505, -21365085, 15928892, -26158305,
4315421, -25948728, -3916677, -21480480, 12868082),
array(-28635013, 13504661, 19988037, -2132761, 21078225,
6443208, -21446107, 2244500, -12455797, -8089383),
),
array(
array(-30595528, 13793479, -5852820, 319136, -25723172,
-6263899, 33086546, 8957937, -15233648, 5540521),
array(-11630176, -11503902, -8119500, -7643073, 2620056,
1022908, -23710744, -1568984, -16128528, -14962807),
array(23152971, 775386, 27395463, 14006635, -9701118,
4649512, 1689819, 892185, -11513277, -15205948),
),
array(
array(9770129, 9586738, 26496094, 4324120, 1556511,
-3550024, 27453819, 4763127, -19179614, 5867134),
array(-32765025, 1927590, 31726409, -4753295, 23962434,
-16019500, 27846559, 5931263, -29749703, -16108455),
array(27461885, -2977536, 22380810, 1815854, -23033753,
-3031938, 7283490, -15148073, -19526700, 7734629),
),
),
array(
array(
array(-8010264, -9590817, -11120403, 6196038, 29344158,
-13430885, 7585295, -3176626, 18549497, 15302069),
array(-32658337, -6171222, -7672793, -11051681, 6258878,
13504381, 10458790, -6418461, -8872242, 8424746),
array(24687205, 8613276, -30667046, -3233545, 1863892,
-1830544, 19206234, 7134917, -11284482, -828919),
),
array(
array(11334899, -9218022, 8025293, 12707519, 17523892,
-10476071, 10243738, -14685461, -5066034, 16498837),
array(8911542, 6887158, -9584260, -6958590, 11145641,
-9543680, 17303925, -14124238, 6536641, 10543906),
array(-28946384, 15479763, -17466835, 568876, -1497683,
11223454, -2669190, -16625574, -27235709, 8876771),
),
array(
array(-25742899, -12566864, -15649966, -846607, -33026686,
-796288, -33481822, 15824474, -604426, -9039817),
array(10330056, 70051, 7957388, -9002667, 9764902,
15609756, 27698697, -4890037, 1657394, 3084098),
array(10477963, -7470260, 12119566, -13250805, 29016247,
-5365589, 31280319, 14396151, -30233575, 15272409),
),
array(
array(-12288309, 3169463, 28813183, 16658753, 25116432,
-5630466, -25173957, -12636138, -25014757, 1950504),
array(-26180358, 9489187, 11053416, -14746161, -31053720,
5825630, -8384306, -8767532, 15341279, 8373727),
array(28685821, 7759505, -14378516, -12002860, -31971820,
4079242, 298136, -10232602, -2878207, 15190420),
),
array(
array(-32932876, 13806336, -14337485, -15794431, -24004620,
10940928, 8669718, 2742393, -26033313, -6875003),
array(-1580388, -11729417, -25979658, -11445023, -17411874,
-10912854, 9291594, -16247779, -12154742, 6048605),
array(-30305315, 14843444, 1539301, 11864366, 20201677,
1900163, 13934231, 5128323, 11213262, 9168384),
),
array(
array(-26280513, 11007847, 19408960, -940758, -18592965,
-4328580, -5088060, -11105150, 20470157, -16398701),
array(-23136053, 9282192, 14855179, -15390078, -7362815,
-14408560, -22783952, 14461608, 14042978, 5230683),
array(29969567, -2741594, -16711867, -8552442, 9175486,
-2468974, 21556951, 3506042, -5933891, -12449708),
),
array(
array(-3144746, 8744661, 19704003, 4581278, -20430686,
6830683, -21284170, 8971513, -28539189, 15326563),
array(-19464629, 10110288, -17262528, -3503892, -23500387,
1355669, -15523050, 15300988, -20514118, 9168260),
array(-5353335, 4488613, -23803248, 16314347, 7780487,
-15638939, -28948358, 9601605, 33087103, -9011387),
),
array(
array(-19443170, -15512900, -20797467, -12445323,
-29824447, 10229461, -27444329, -15000531, -5996870, 15664672),
array(23294591, -16632613, -22650781, -8470978, 27844204,
11461195, 13099750, -2460356, 18151676, 13417686),
array(-24722913, -4176517, -31150679, 5988919, -26858785,
6685065, 1661597, -12551441, 15271676, -15452665),
),
),
array(
array(
array(11433042, -13228665, 8239631, -5279517, -1985436,
-725718, -18698764, 2167544, -6921301, -13440182),
array(-31436171, 15575146, 30436815, 12192228, -22463353,
9395379, -9917708, -8638997, 12215110, 12028277),
array(14098400, 6555944, 23007258, 5757252, -15427832,
-12950502, 30123440, 4617780, -16900089, -655628),
),
array(
array(-4026201, -15240835, 11893168, 13718664, -14809462,
1847385, -15819999, 10154009, 23973261, -12684474),
array(-26531820, -3695990, -1908898, 2534301, -31870557,
-16550355, 18341390, -11419951, 32013174, -10103539),
array(-25479301, 10876443, -11771086, -14625140, -12369567,
1838104, 21911214, 6354752, 4425632, -837822),
),
array(
array(-10433389, -14612966, 22229858, -3091047, -13191166,
776729, -17415375, -12020462, 4725005, 14044970),
array(19268650, -7304421, 1555349, 8692754, -21474059,
-9910664, 6347390, -1411784, -19522291, -16109756),
array(-24864089, 12986008, -10898878, -5558584, -11312371,
-148526, 19541418, 8180106, 9282262, 10282508),
),
array(
array(-26205082, 4428547, -8661196, -13194263, 4098402,
-14165257, 15522535, 8372215, 5542595, -10702683),
array(-10562541, 14895633, 26814552, -16673850, -17480754,
-2489360, -2781891, 6993761, -18093885, 10114655),
array(-20107055, -929418, 31422704, 10427861, -7110749,
6150669, -29091755, -11529146, 25953725, -106158),
),
array(
array(-4234397, -8039292, -9119125, 3046000, 2101609,
-12607294, 19390020, 6094296, -3315279, 12831125),
array(-15998678, 7578152, 5310217, 14408357, -33548620,
-224739, 31575954, 6326196, 7381791, -2421839),
array(-20902779, 3296811, 24736065, -16328389, 18374254,
7318640, 6295303, 8082724, -15362489, 12339664),
),
array(
array(27724736, 2291157, 6088201, -14184798, 1792727,
5857634, 13848414, 15768922, 25091167, 14856294),
array(-18866652, 8331043, 24373479, 8541013, -701998,
-9269457, 12927300, -12695493, -22182473, -9012899),
array(-11423429, -5421590, 11632845, 3405020, 30536730,
-11674039, -27260765, 13866390, 30146206, 9142070),
),
array(
array(3924129, -15307516, -13817122, -10054960, 12291820,
-668366, -27702774, 9326384, -8237858, 4171294),
array(-15921940, 16037937, 6713787, 16606682, -21612135,
2790944, 26396185, 3731949, 345228, -5462949),
array(-21327538, 13448259, 25284571, 1143661, 20614966,
-8849387, 2031539, -12391231, -16253183, -13582083),
),
array(
array(31016211, -16722429, 26371392, -14451233, -5027349,
14854137, 17477601, 3842657, 28012650, -16405420),
array(-5075835, 9368966, -8562079, -4600902, -15249953,
6970560, -9189873, 16292057, -8867157, 3507940),
array(29439664, 3537914, 23333589, 6997794, -17555561,
-11018068, -15209202, -15051267, -9164929, 6580396),
),
),
array(
array(
array(-12185861, -7679788, 16438269, 10826160, -8696817,
-6235611, 17860444, -9273846, -2095802, 9304567),
array(20714564, -4336911, 29088195, 7406487, 11426967,
-5095705, 14792667, -14608617, 5289421, -477127),
array(-16665533, -10650790, -6160345, -13305760, 9192020,
-1802462, 17271490, 12349094, 26939669, -3752294),
),
array(
array(-12889898, 9373458, 31595848, 16374215, 21471720,
13221525, -27283495, -12348559, -3698806, 117887),
array(22263325, -6560050, 3984570, -11174646, -15114008,
-566785, 28311253, 5358056, -23319780, 541964),
array(16259219, 3261970, 2309254, -15534474, -16885711,
-4581916, 24134070, -16705829, -13337066, -13552195),
),
array(
array(9378160, -13140186, -22845982, -12745264, 28198281,
-7244098, -2399684, -717351, 690426, 14876244),
array(24977353, -314384, -8223969, -13465086, 28432343,
-1176353, -13068804, -12297348, -22380984, 6618999),
array(-1538174, 11685646, 12944378, 13682314, -24389511,
-14413193, 8044829, -13817328, 32239829, -5652762),
),
array(
array(-18603066, 4762990, -926250, 8885304, -28412480,
-3187315, 9781647, -10350059, 32779359, 5095274),
array(-33008130, -5214506, -32264887, -3685216, 9460461,
-9327423, -24601656, 14506724, 21639561, -2630236),
array(-16400943, -13112215, 25239338, 15531969, 3987758,
-4499318, -1289502, -6863535, 17874574, 558605),
),
array(
array(-13600129, 10240081, 9171883, 16131053, -20869254,
9599700, 33499487, 5080151, 2085892, 5119761),
array(-22205145, -2519528, -16381601, 414691, -25019550,
2170430, 30634760, -8363614, -31999993, -5759884),
array(-6845704, 15791202, 8550074, -1312654, 29928809,
-12092256, 27534430, -7192145, -22351378, 12961482),
),
array(
array(-24492060, -9570771, 10368194, 11582341, -23397293,
-2245287, 16533930, 8206996, -30194652, -5159638),
array(-11121496, -3382234, 2307366, 6362031, -135455,
8868177, -16835630, 7031275, 7589640, 8945490),
array(-32152748, 8917967, 6661220, -11677616, -1192060,
-15793393, 7251489, -11182180, 24099109, -14456170),
),
array(
array(5019558, -7907470, 4244127, -14714356, -26933272,
6453165, -19118182, -13289025, -6231896, -10280736),
array(10853594, 10721687, 26480089, 5861829, -22995819,
1972175, -1866647, -10557898, -3363451, -6441124),
array(-17002408, 5906790, 221599, -6563147, 7828208,
-13248918, 24362661, -2008168, -13866408, 7421392),
),
array(
array(8139927, -6546497, 32257646, -5890546, 30375719,
1886181, -21175108, 15441252, 28826358, -4123029),
array(6267086, 9695052, 7709135, -16603597, -32869068,
-1886135, 14795160, -7840124, 13746021, -1742048),
array(28584902, 7787108, -6732942, -15050729, 22846041,
-7571236, -3181936, -363524, 4771362, -8419958),
),
),
array(
array(
array(24949256, 6376279, -27466481, -8174608, -18646154,
-9930606, 33543569, -12141695, 3569627, 11342593),
array(26514989, 4740088, 27912651, 3697550, 19331575,
-11472339, 6809886, 4608608, 7325975, -14801071),
array(-11618399, -14554430, -24321212, 7655128, -1369274,
5214312, -27400540, 10258390, -17646694, -8186692),
),
array(
array(11431204, 15823007, 26570245, 14329124, 18029990,
4796082, -31446179, 15580664, 9280358, -3973687),
array(-160783, -10326257, -22855316, -4304997, -20861367,
-13621002, -32810901, -11181622, -15545091, 4387441),
array(-20799378, 12194512, 3937617, -5805892, -27154820,
9340370, -24513992, 8548137, 20617071, -7482001),
),
array(
array(-938825, -3930586, -8714311, 16124718, 24603125,
-6225393, -13775352, -11875822, 24345683, 10325460),
array(-19855277, -1568885, -22202708, 8714034, 14007766,
6928528, 16318175, -1010689, 4766743, 3552007),
array(-21751364, -16730916, 1351763, -803421, -4009670,
3950935, 3217514, 14481909, 10988822, -3994762),
),
array(
array(15564307, -14311570, 3101243, 5684148, 30446780,
-8051356, 12677127, -6505343, -8295852, 13296005),
array(-9442290, 6624296, -30298964, -11913677, -4670981,
-2057379, 31521204, 9614054, -30000824, 12074674),
array(4771191, -135239, 14290749, -13089852, 27992298,
14998318, -1413936, -1556716, 29832613, -16391035),
),
array(
array(7064884, -7541174, -19161962, -5067537, -18891269,
-2912736, 25825242, 5293297, -27122660, 13101590),
array(-2298563, 2439670, -7466610, 1719965, -27267541,
-16328445, 32512469, -5317593, -30356070, -4190957),
array(-30006540, 10162316, -33180176, 3981723, -16482138,
-13070044, 14413974, 9515896, 19568978, 9628812),
),
array(
array(33053803, 199357, 15894591, 1583059, 27380243,
-4580435, -17838894, -6106839, -6291786, 3437740),
array(-18978877, 3884493, 19469877, 12726490, 15913552,
13614290, -22961733, 70104, 7463304, 4176122),
array(-27124001, 10659917, 11482427, -16070381, 12771467,
-6635117, -32719404, -5322751, 24216882, 5944158),
),
array(
array(8894125, 7450974, -2664149, -9765752, -28080517,
-12389115, 19345746, 14680796, 11632993, 5847885),
array(26942781, -2315317, 9129564, -4906607, 26024105,
11769399, -11518837, 6367194, -9727230, 4782140),
array(19916461, -4828410, -22910704, -11414391, 25606324,
-5972441, 33253853, 8220911, 6358847, -1873857),
),
array(
array(801428, -2081702, 16569428, 11065167, 29875704,
96627, 7908388, -4480480, -13538503, 1387155),
array(19646058, 5720633, -11416706, 12814209, 11607948,
12749789, 14147075, 15156355, -21866831, 11835260),
array(19299512, 1155910, 28703737, 14890794, 2925026,
7269399, 26121523, 15467869, -26560550, 5052483),
),
),
array(
array(
array(-3017432, 10058206, 1980837, 3964243, 22160966,
12322533, -6431123, -12618185, 12228557, -7003677),
array(32944382, 14922211, -22844894, 5188528, 21913450,
-8719943, 4001465, 13238564, -6114803, 8653815),
array(22865569, -4652735, 27603668, -12545395, 14348958,
8234005, 24808405, 5719875, 28483275, 2841751),
),
array(
array(-16420968, -1113305, -327719, -12107856, 21886282,
-15552774, -1887966, -315658, 19932058, -12739203),
array(-11656086, 10087521, -8864888, -5536143, -19278573,
-3055912, 3999228, 13239134, -4777469, -13910208),
array(1382174, -11694719, 17266790, 9194690, -13324356,
9720081, 20403944, 11284705, -14013818, 3093230),
),
array(
array(16650921, -11037932, -1064178, 1570629, -8329746,
7352753, -302424, 16271225, -24049421, -6691850),
array(-21911077, -5927941, -4611316, -5560156, -31744103,
-10785293, 24123614, 15193618, -21652117, -16739389),
array(-9935934, -4289447, -25279823, 4372842, 2087473,
10399484, 31870908, 14690798, 17361620, 11864968),
),
array(
array(-11307610, 6210372, 13206574, 5806320, -29017692,
-13967200, -12331205, -7486601, -25578460, -16240689),
array(14668462, -12270235, 26039039, 15305210, 25515617,
4542480, 10453892, 6577524, 9145645, -6443880),
array(5974874, 3053895, -9433049, -10385191, -31865124,
3225009, -7972642, 3936128, -5652273, -3050304),
),
array(
array(30625386, -4729400, -25555961, -12792866, -20484575,
7695099, 17097188, -16303496, -27999779, 1803632),
array(-3553091, 9865099, -5228566, 4272701, -5673832,
-16689700, 14911344, 12196514, -21405489, 7047412),
array(20093277, 9920966, -11138194, -5343857, 13161587,
12044805, -32856851, 4124601, -32343828, -10257566),
),
array(
array(-20788824, 14084654, -13531713, 7842147, 19119038,
-13822605, 4752377, -8714640, -21679658, 2288038),
array(-26819236, -3283715, 29965059, 3039786, -14473765,
2540457, 29457502, 14625692, -24819617, 12570232),
array(-1063558, -11551823, 16920318, 12494842, 1278292,
-5869109, -21159943, -3498680, -11974704, 4724943),
),
array(
array(17960970, -11775534, -4140968, -9702530, -8876562,
-1410617, -12907383, -8659932, -29576300, 1903856),
array(23134274, -14279132, -10681997, -1611936, 20684485,
15770816, -12989750, 3190296, 26955097, 14109738),
array(15308788, 5320727, -30113809, -14318877, 22902008,
7767164, 29425325, -11277562, 31960942, 11934971),
),
array(
array(-27395711, 8435796, 4109644, 12222639, -24627868,
14818669, 20638173, 4875028, 10491392, 1379718),
array(-13159415, 9197841, 3875503, -8936108, -1383712,
-5879801, 33518459, 16176658, 21432314, 12180697),
array(-11787308, 11500838, 13787581, -13832590, -22430679,
10140205, 1465425, 12689540, -10301319, -13872883),
),
),
array(
array(
array(5414091, -15386041, -21007664, 9643570, 12834970,
1186149, -2622916, -1342231, 26128231, 6032912),
array(-26337395, -13766162, 32496025, -13653919, 17847801,
-12669156, 3604025, 8316894, -25875034, -10437358),
array(3296484, 6223048, 24680646, -12246460, -23052020,
5903205, -8862297, -4639164, 12376617, 3188849),
),
array(
array(29190488, -14659046, 27549113, -1183516, 3520066,
-10697301, 32049515, -7309113, -16109234, -9852307),
array(-14744486, -9309156, 735818, -598978, -20407687,
-5057904, 25246078, -15795669, 18640741, -960977),
array(-6928835, -16430795, 10361374, 5642961, 4910474,
12345252, -31638386, -494430, 10530747, 1053335),
),
array(
array(-29265967, -14186805, -13538216, -12117373,
-19457059, -10655384, -31462369, -2948985, 24018831, 15026644),
array(-22592535, -3145277, -2289276, 5953843, -13440189,
9425631, 25310643, 13003497, -2314791, -15145616),
array(-27419985, -603321, -8043984, -1669117, -26092265,
13987819, -27297622, 187899, -23166419, -2531735),
),
array(
array(-21744398, -13810475, 1844840, 5021428, -10434399,
-15911473, 9716667, 16266922, -5070217, 726099),
array(29370922, -6053998, 7334071, -15342259, 9385287,
2247707, -13661962, -4839461, 30007388, -15823341),
array(-936379, 16086691, 23751945, -543318, -1167538,
-5189036, 9137109, 730663, 9835848, 4555336),
),
array(
array(-23376435, 1410446, -22253753, -12899614, 30867635,
15826977, 17693930, 544696, -11985298, 12422646),
array(31117226, -12215734, -13502838, 6561947, -9876867,
-12757670, -5118685, -4096706, 29120153, 13924425),
array(-17400879, -14233209, 19675799, -2734756, -11006962,
-5858820, -9383939, -11317700, 7240931, -237388),
),
array(
array(-31361739, -11346780, -15007447, -5856218, -22453340,
-12152771, 1222336, 4389483, 3293637, -15551743),
array(-16684801, -14444245, 11038544, 11054958, -13801175,
-3338533, -24319580, 7733547, 12796905, -6335822),
array(-8759414, -10817836, -25418864, 10783769, -30615557,
-9746811, -28253339, 3647836, 3222231, -11160462),
),
array(
array(18606113, 1693100, -25448386, -15170272, 4112353,
10045021, 23603893, -2048234, -7550776, 2484985),
array(9255317, -3131197, -12156162, -1004256, 13098013,
-9214866, 16377220, -2102812, -19802075, -3034702),
array(-22729289, 7496160, -5742199, 11329249, 19991973,
-3347502, -31718148, 9936966, -30097688, -10618797),
),
array(
array(21878590, -5001297, 4338336, 13643897, -3036865,
13160960, 19708896, 5415497, -7360503, -4109293),
array(27736861, 10103576, 12500508, 8502413, -3413016,
-9633558, 10436918, -1550276, -23659143, -8132100),
array(19492550, -12104365, -29681976, -852630, -3208171,
12403437, 30066266, 8367329, 13243957, 8709688),
),
),
array(
array(
array(12015105, 2801261, 28198131, 10151021, 24818120,
-4743133, -11194191, -5645734, 5150968, 7274186),
array(2831366, -12492146, 1478975, 6122054, 23825128,
-12733586, 31097299, 6083058, 31021603, -9793610),
array(-2529932, -2229646, 445613, 10720828, -13849527,
-11505937, -23507731, 16354465, 15067285, -14147707),
),
array(
array(7840942, 14037873, -33364863, 15934016, -728213,
-3642706, 21403988, 1057586, -19379462, -12403220),
array(915865, -16469274, 15608285, -8789130, -24357026,
6060030, -17371319, 8410997, -7220461, 16527025),
array(32922597, -556987, 20336074, -16184568, 10903705,
-5384487, 16957574, 52992, 23834301, 6588044),
),
array(
array(32752030, 11232950, 3381995, -8714866, 22652988,
-10744103, 17159699, 16689107, -20314580, -1305992),
array(-4689649, 9166776, -25710296, -10847306, 11576752,
12733943, 7924251, -2752281, 1976123, -7249027),
array(21251222, 16309901, -2983015, -6783122, 30810597,
12967303, 156041, -3371252, 12331345, -8237197),
),
array(
array(8651614, -4477032, -16085636, -4996994, 13002507,
2950805, 29054427, -5106970, 10008136, -4667901),
array(31486080, 15114593, -14261250, 12951354, 14369431,
-7387845, 16347321, -13662089, 8684155, -10532952),
array(19443825, 11385320, 24468943, -9659068, -23919258,
2187569, -26263207, -6086921, 31316348, 14219878),
),
array(
array(-28594490, 1193785, 32245219, 11392485, 31092169,
15722801, 27146014, 6992409, 29126555, 9207390),
array(32382935, 1110093, 18477781, 11028262, -27411763,
-7548111, -4980517, 10843782, -7957600, -14435730),
array(2814918, 7836403, 27519878, -7868156, -20894015,
-11553689, -21494559, 8550130, 28346258, 1994730),
),
array(
array(-19578299, 8085545, -14000519, -3948622, 2785838,
-16231307, -19516951, 7174894, 22628102, 8115180),
array(-30405132, 955511, -11133838, -15078069, -32447087,
-13278079, -25651578, 3317160, -9943017, 930272),
array(-15303681, -6833769, 28856490, 1357446, 23421993,
1057177, 24091212, -1388970, -22765376, -10650715),
),
array(
array(-22751231, -5303997, -12907607, -12768866, -15811511,
-7797053, -14839018, -16554220, -1867018, 8398970),
array(-31969310, 2106403, -4736360, 1362501, 12813763,
16200670, 22981545, -6291273, 18009408, -15772772),
array(-17220923, -9545221, -27784654, 14166835, 29815394,
7444469, 29551787, -3727419, 19288549, 1325865),
),
array(
array(15100157, -15835752, -23923978, -1005098, -26450192,
15509408, 12376730, -3479146, 33166107, -8042750),
array(20909231, 13023121, -9209752, 16251778, -5778415,
-8094914, 12412151, 10018715, 2213263, -13878373),
array(32529814, -11074689, 30361439, -16689753, -9135940,
1513226, 22922121, 6382134, -5766928, 8371348),
),
),
array(
array(
array(9923462, 11271500, 12616794, 3544722, -29998368,
-1721626, 12891687, -8193132, -26442943, 10486144),
array(-22597207, -7012665, 8587003, -8257861, 4084309,
-12970062, 361726, 2610596, -23921530, -11455195),
array(5408411, -1136691, -4969122, 10561668, 24145918,
14240566, 31319731, -4235541, 19985175, -3436086),
),
array(
array(-13994457, 16616821, 14549246, 3341099, 32155958,
13648976, -17577068, 8849297, 65030, 8370684),
array(-8320926, -12049626, 31204563, 5839400, -20627288,
-1057277, -19442942, 6922164, 12743482, -9800518),
array(-2361371, 12678785, 28815050, 4759974, -23893047,
4884717, 23783145, 11038569, 18800704, 255233),
),
array(
array(-5269658, -1773886, 13957886, 7990715, 23132995,
728773, 13393847, 9066957, 19258688, -14753793),
array(-2936654, -10827535, -10432089, 14516793, -3640786,
4372541, -31934921, 2209390, -1524053, 2055794),
array(580882, 16705327, 5468415, -2683018, -30926419,
-14696000, -7203346, -8994389, -30021019, 7394435),
),
array(
array(23838809, 1822728, -15738443, 15242727, 8318092,
-3733104, -21672180, -3492205, -4821741, 14799921),
array(13345610, 9759151, 3371034, -16137791, 16353039,
8577942, 31129804, 13496856, -9056018, 7402518),
array(2286874, -4435931, -20042458, -2008336, -13696227,
5038122, 11006906, -15760352, 8205061, 1607563),
),
array(
array(14414086, -8002132, 3331830, -3208217, 22249151,
-5594188, 18364661, -2906958, 30019587, -9029278),
array(-27688051, 1585953, -10775053, 931069, -29120221,
-11002319, -14410829, 12029093, 9944378, 8024),
array(4368715, -3709630, 29874200, -15022983, -20230386,
-11410704, -16114594, -999085, -8142388, 5640030),
),
array(
array(10299610, 13746483, 11661824, 16234854, 7630238,
5998374, 9809887, -16694564, 15219798, -14327783),
array(27425505, -5719081, 3055006, 10660664, 23458024,
595578, -15398605, -1173195, -18342183, 9742717),
array(6744077, 2427284, 26042789, 2720740, -847906,
1118974, 32324614, 7406442, 12420155, 1994844),
),
array(
array(14012521, -5024720, -18384453, -9578469, -26485342,
-3936439, -13033478, -10909803, 24319929, -6446333),
array(16412690, -4507367, 10772641, 15929391, -17068788,
-4658621, 10555945, -10484049, -30102368, -4739048),
array(22397382, -7767684, -9293161, -12792868, 17166287,
-9755136, -27333065, 6199366, 21880021, -12250760),
),
array(
array(-4283307, 5368523, -31117018, 8163389, -30323063,
3209128, 16557151, 8890729, 8840445, 4957760),
array(-15447727, 709327, -6919446, -10870178, -29777922,
6522332, -21720181, 12130072, -14796503, 5005757),
array(-2114751, -14308128, 23019042, 15765735, -25269683,
6002752, 10183197, -13239326, -16395286, -2176112),
),
),
array(
array(
array(-19025756, 1632005, 13466291, -7995100, -23640451,
16573537, -32013908, -3057104, 22208662, 2000468),
array(3065073, -1412761, -25598674, -361432, -17683065,
-5703415, -8164212, 11248527, -3691214, -7414184),
array(10379208, -6045554, 8877319, 1473647, -29291284,
-12507580, 16690915, 2553332, -3132688, 16400289),
),
array(
array(15716668, 1254266, -18472690, 7446274, -8448918,
6344164, -22097271, -7285580, 26894937, 9132066),
array(24158887, 12938817, 11085297, -8177598, -28063478,
-4457083, -30576463, 64452, -6817084, -2692882),
array(13488534, 7794716, 22236231, 5989356, 25426474,
-12578208, 2350710, -3418511, -4688006, 2364226),
),
array(
array(16335052, 9132434, 25640582, 6678888, 1725628,
8517937, -11807024, -11697457, 15445875, -7798101),
array(29004207, -7867081, 28661402, -640412, -12794003,
-7943086, 31863255, -4135540, -278050, -15759279),
array(-6122061, -14866665, -28614905, 14569919, -10857999,
-3591829, 10343412, -6976290, -29828287, -10815811),
),
array(
array(27081650, 3463984, 14099042, -4517604, 1616303,
-6205604, 29542636, 15372179, 17293797, 960709),
array(20263915, 11434237, -5765435, 11236810, 13505955,
-10857102, -16111345, 6493122, -19384511, 7639714),
array(-2830798, -14839232, 25403038, -8215196, -8317012,
-16173699, 18006287, -16043750, 29994677, -15808121),
),
array(
array(9769828, 5202651, -24157398, -13631392, -28051003,
-11561624, -24613141, -13860782, -31184575, 709464),
array(12286395, 13076066, -21775189, -1176622, -25003198,
4057652, -32018128, -8890874, 16102007, 13205847),
array(13733362, 5599946, 10557076, 3195751, -5557991,
8536970, -25540170, 8525972, 10151379, 10394400),
),
array(
array(4024660, -16137551, 22436262, 12276534, -9099015,
-2686099, 19698229, 11743039, -33302334, 8934414),
array(-15879800, -4525240, -8580747, -2934061, 14634845,
-698278, -9449077, 3137094, -11536886, 11721158),
array(17555939, -5013938, 8268606, 2331751, -22738815,
9761013, 9319229, 8835153, -9205489, -1280045),
),
array(
array(-461409, -7830014, 20614118, 16688288, -7514766,
-4807119, 22300304, 505429, 6108462, -6183415),
array(-5070281, 12367917, -30663534, 3234473, 32617080,
-8422642, 29880583, -13483331, -26898490, -7867459),
array(-31975283, 5726539, 26934134, 10237677, -3173717,
-605053, 24199304, 3795095, 7592688, -14992079),
),
array(
array(21594432, -14964228, 17466408, -4077222, 32537084,
2739898, 6407723, 12018833, -28256052, 4298412),
array(-20650503, -11961496, -27236275, 570498, 3767144,
-1717540, 13891942, -1569194, 13717174, 10805743),
array(-14676630, -15644296, 15287174, 11927123, 24177847,
-8175568, -796431, 14860609, -26938930, -5863836),
),
),
array(
array(
array(12962541, 5311799, -10060768, 11658280, 18855286,
-7954201, 13286263, -12808704, -4381056, 9882022),
array(18512079, 11319350, -20123124, 15090309, 18818594,
5271736, -22727904, 3666879, -23967430, -3299429),
array(-6789020, -3146043, 16192429, 13241070, 15898607,
-14206114, -10084880, -6661110, -2403099, 5276065),
),
array(
array(30169808, -5317648, 26306206, -11750859, 27814964,
7069267, 7152851, 3684982, 1449224, 13082861),
array(10342826, 3098505, 2119311, 193222, 25702612,
12233820, 23697382, 15056736, -21016438, -8202000),
array(-33150110, 3261608, 22745853, 7948688, 19370557,
-15177665, -26171976, 6482814, -10300080, -11060101),
),
array(
array(32869458, -5408545, 25609743, 15678670, -10687769,
-15471071, 26112421, 2521008, -22664288, 6904815),
array(29506923, 4457497, 3377935, -9796444, -30510046,
12935080, 1561737, 3841096, -29003639, -6657642),
array(10340844, -6630377, -18656632, -2278430, 12621151,
-13339055, 30878497, -11824370, -25584551, 5181966),
),
array(
array(25940115, -12658025, 17324188, -10307374, -8671468,
15029094, 24396252, -16450922, -2322852, -12388574),
array(-21765684, 9916823, -1300409, 4079498, -1028346,
11909559, 1782390, 12641087, 20603771, -6561742),
array(-18882287, -11673380, 24849422, 11501709, 13161720,
-4768874, 1925523, 11914390, 4662781, 7820689),
),
array(
array(12241050, -425982, 8132691, 9393934, 32846760,
-1599620, 29749456, 12172924, 16136752, 15264020),
array(-10349955, -14680563, -8211979, 2330220, -17662549,
-14545780, 10658213, 6671822, 19012087, 3772772),
array(3753511, -3421066, 10617074, 2028709, 14841030,
-6721664, 28718732, -15762884, 20527771, 12988982),
),
array(
array(-14822485, -5797269, -3707987, 12689773, -898983,
-10914866, -24183046, -10564943, 3299665, -12424953),
array(-16777703, -15253301, -9642417, 4978983, 3308785,
8755439, 6943197, 6461331, -25583147, 8991218),
array(-17226263, 1816362, -1673288, -6086439, 31783888,
-8175991, -32948145, 7417950, -30242287, 1507265),
),
array(
array(29692663, 6829891, -10498800, 4334896, 20945975,
-11906496, -28887608, 8209391, 14606362, -10647073),
array(-3481570, 8707081, 32188102, 5672294, 22096700,
1711240, -33020695, 9761487, 4170404, -2085325),
array(-11587470, 14855945, -4127778, -1531857, -26649089,
15084046, 22186522, 16002000, -14276837, -8400798),
),
array(
array(-4811456, 13761029, -31703877, -2483919, -3312471,
7869047, -7113572, -9620092, 13240845, 10965870),
array(-7742563, -8256762, -14768334, -13656260, -23232383,
12387166, 4498947, 14147411, 29514390, 4302863),
array(-13413405, -12407859, 20757302, -13801832, 14785143,
8976368, -5061276, -2144373, 17846988, -13971927),
),
),
array(
array(
array(-2244452, -754728, -4597030, -1066309, -6247172,
1455299, -21647728, -9214789, -5222701, 12650267),
array(-9906797, -16070310, 21134160, 12198166, -27064575,
708126, 387813, 13770293, -19134326, 10958663),
array(22470984, 12369526, 23446014, -5441109, -21520802,
-9698723, -11772496, -11574455, -25083830, 4271862),
),
array(
array(-25169565, -10053642, -19909332, 15361595, -5984358,
2159192, 75375, -4278529, -32526221, 8469673),
array(15854970, 4148314, -8893890, 7259002, 11666551,
13824734, -30531198, 2697372, 24154791, -9460943),
array(15446137, -15806644, 29759747, 14019369, 30811221,
-9610191, -31582008, 12840104, 24913809, 9815020),
),
array(
array(-4709286, -5614269, -31841498, -12288893, -14443537,
10799414, -9103676, 13438769, 18735128, 9466238),
array(11933045, 9281483, 5081055, -5183824, -2628162,
-4905629, -7727821, -10896103, -22728655, 16199064),
array(14576810, 379472, -26786533, -8317236, -29426508,
-10812974, -102766, 1876699, 30801119, 2164795),
),
array(
array(15995086, 3199873, 13672555, 13712240, -19378835,
-4647646, -13081610, -15496269, -13492807, 1268052),
array(-10290614, -3659039, -3286592, 10948818, 23037027,
3794475, -3470338, -12600221, -17055369, 3565904),
array(29210088, -9419337, -5919792, -4952785, 10834811,
-13327726, -16512102, -10820713, -27162222, -14030531),
),
array(
array(-13161890, 15508588, 16663704, -8156150, -28349942,
9019123, -29183421, -3769423, 2244111, -14001979),
array(-5152875, -3800936, -9306475, -6071583, 16243069,
14684434, -25673088, -16180800, 13491506, 4641841),
array(10813417, 643330, -19188515, -728916, 30292062,
-16600078, 27548447, -7721242, 14476989, -12767431),
),
array(
array(10292079, 9984945, 6481436, 8279905, -7251514,
7032743, 27282937, -1644259, -27912810, 12651324),
array(-31185513, -813383, 22271204, 11835308, 10201545,
15351028, 17099662, 3988035, 21721536, -3148940),
array(10202177, -6545839, -31373232, -9574638, -32150642,
-8119683, -12906320, 3852694, 13216206, 14842320),
),
array(
array(-15815640, -10601066, -6538952, -7258995, -6984659,
-6581778, -31500847, 13765824, -27434397, 9900184),
array(14465505, -13833331, -32133984, -14738873, -27443187,
12990492, 33046193, 15796406, -7051866, -8040114),
array(30924417, -8279620, 6359016, -12816335, 16508377,
9071735, -25488601, 15413635, 9524356, -7018878),
),
array(
array(12274201, -13175547, 32627641, -1785326, 6736625,
13267305, 5237659, -5109483, 15663516, 4035784),
array(-2951309, 8903985, 17349946, 601635, -16432815,
-4612556, -13732739, -15889334, -22258478, 4659091),
array(-16916263, -4952973, -30393711, -15158821, 20774812,
15897498, 5736189, 15026997, -2178256, -13455585),
),
),
array(
array(
array(-8858980, -2219056, 28571666, -10155518, -474467,
-10105698, -3801496, 278095, 23440562, -290208),
array(10226241, -5928702, 15139956, 120818, -14867693,
5218603, 32937275, 11551483, -16571960, -7442864),
array(17932739, -12437276, -24039557, 10749060, 11316803,
7535897, 22503767, 5561594, -3646624, 3898661),
),
array(
array(7749907, -969567, -16339731, -16464, -25018111,
15122143, -1573531, 7152530, 21831162, 1245233),
array(26958459, -14658026, 4314586, 8346991, -5677764,
11960072, -32589295, -620035, -30402091, -16716212),
array(-12165896, 9166947, 33491384, 13673479, 29787085,
13096535, 6280834, 14587357, -22338025, 13987525),
),
array(
array(-24349909, 7778775, 21116000, 15572597, -4833266,
-5357778, -4300898, -5124639, -7469781, -2858068),
array(9681908, -6737123, -31951644, 13591838, -6883821,
386950, 31622781, 6439245, -14581012, 4091397),
array(-8426427, 1470727, -28109679, -1596990, 3978627,
-5123623, -19622683, 12092163, 29077877, -14741988),
),
array(
array(5269168, -6859726, -13230211, -8020715, 25932563,
1763552, -5606110, -5505881, -20017847, 2357889),
array(32264008, -15407652, -5387735, -1160093, -2091322,
-3946900, 23104804, -12869908, 5727338, 189038),
array(14609123, -8954470, -6000566, -16622781, -14577387,
-7743898, -26745169, 10942115, -25888931, -14884697),
),
array(
array(20513500, 5557931, -15604613, 7829531, 26413943,
-2019404, -21378968, 7471781, 13913677, -5137875),
array(-25574376, 11967826, 29233242, 12948236, -6754465,
4713227, -8940970, 14059180, 12878652, 8511905),
array(-25656801, 3393631, -2955415, -7075526, -2250709,
9366908, -30223418, 6812974, 5568676, -3127656),
),
array(
array(11630004, 12144454, 2116339, 13606037, 27378885,
15676917, -17408753, -13504373, -14395196, 8070818),
array(27117696, -10007378, -31282771, -5570088, 1127282,
12772488, -29845906, 10483306, -11552749, -1028714),
array(10637467, -5688064, 5674781, 1072708, -26343588,
-6982302, -1683975, 9177853, -27493162, 15431203),
),
array(
array(20525145, 10892566, -12742472, 12779443, -29493034,
16150075, -28240519, 14943142, -15056790, -7935931),
array(-30024462, 5626926, -551567, -9981087, 753598,
11981191, 25244767, -3239766, -3356550, 9594024),
array(-23752644, 2636870, -5163910, -10103818, 585134,
7877383, 11345683, -6492290, 13352335, -10977084),
),
array(
array(-1931799, -5407458, 3304649, -12884869, 17015806,
-4877091, -29783850, -7752482, -13215537, -319204),
array(20239939, 6607058, 6203985, 3483793, -18386976,
-779229, -20723742, 15077870, -22750759, 14523817),
array(27406042, -6041657, 27423596, -4497394, 4996214,
10002360, -28842031, -4545494, -30172742, -4805667),
),
),
array(
array(
array(11374242, 12660715, 17861383, -12540833, 10935568,
1099227, -13886076, -9091740, -27727044, 11358504),
array(-12730809, 10311867, 1510375, 10778093, -2119455,
-9145702, 32676003, 11149336, -26123651, 4985768),
array(-19096303, 341147, -6197485, -239033, 15756973,
-8796662, -983043, 13794114, -19414307, -15621255),
),
array(
array(6490081, 11940286, 25495923, -7726360, 8668373,
-8751316, 3367603, 6970005, -1691065, -9004790),
array(1656497, 13457317, 15370807, 6364910, 13605745,
8362338, -19174622, -5475723, -16796596, -5031438),
array(-22273315, -13524424, -64685, -4334223, -18605636,
-10921968, -20571065, -7007978, -99853, -10237333),
),
array(
array(17747465, 10039260, 19368299, -4050591, -20630635,
-16041286, 31992683, -15857976, -29260363, -5511971),
array(31932027, -4986141, -19612382, 16366580, 22023614,
88450, 11371999, -3744247, 4882242, -10626905),
array(29796507, 37186, 19818052, 10115756, -11829032,
3352736, 18551198, 3272828, -5190932, -4162409),
),
array(
array(12501286, 4044383, -8612957, -13392385, -32430052,
5136599, -19230378, -3529697, 330070, -3659409),
array(6384877, 2899513, 17807477, 7663917, -2358888,
12363165, 25366522, -8573892, -271295, 12071499),
array(-8365515, -4042521, 25133448, -4517355, -6211027,
2265927, -32769618, 1936675, -5159697, 3829363),
),
array(
array(28425966, -5835433, -577090, -4697198, -14217555,
6870930, 7921550, -6567787, 26333140, 14267664),
array(-11067219, 11871231, 27385719, -10559544, -4585914,
-11189312, 10004786, -8709488, -21761224, 8930324),
array(-21197785, -16396035, 25654216, -1725397, 12282012,
11008919, 1541940, 4757911, -26491501, -16408940),
),
array(
array(13537262, -7759490, -20604840, 10961927, -5922820,
-13218065, -13156584, 6217254, -15943699, 13814990),
array(-17422573, 15157790, 18705543, 29619, 24409717,
-260476, 27361681, 9257833, -1956526, -1776914),
array(-25045300, -10191966, 15366585, 15166509, -13105086,
8423556, -29171540, 12361135, -18685978, 4578290),
),
array(
array(24579768, 3711570, 1342322, -11180126, -27005135,
14124956, -22544529, 14074919, 21964432, 8235257),
array(-6528613, -2411497, 9442966, -5925588, 12025640,
-1487420, -2981514, -1669206, 13006806, 2355433),
array(-16304899, -13605259, -6632427, -5142349, 16974359,
-10911083, 27202044, 1719366, 1141648, -12796236),
),
array(
array(-12863944, -13219986, -8318266, -11018091, -6810145,
-4843894, 13475066, -3133972, 32674895, 13715045),
array(11423335, -5468059, 32344216, 8962751, 24989809,
9241752, -13265253, 16086212, -28740881, -15642093),
array(-1409668, 12530728, -6368726, 10847387, 19531186,
-14132160, -11709148, 7791794, -27245943, 4383347),
),
),
array(
array(
array(-28970898, 5271447, -1266009, -9736989, -12455236,
16732599, -4862407, -4906449, 27193557, 6245191),
array(-15193956, 5362278, -1783893, 2695834, 4960227,
12840725, 23061898, 3260492, 22510453, 8577507),
array(-12632451, 11257346, -32692994, 13548177, -721004,
10879011, 31168030, 13952092, -29571492, -3635906),
),
array(
array(3877321, -9572739, 32416692, 5405324, -11004407,
-13656635, 3759769, 11935320, 5611860, 8164018),
array(-16275802, 14667797, 15906460, 12155291, -22111149,
-9039718, 32003002, -8832289, 5773085, -8422109),
array(-23788118, -8254300, 1950875, 8937633, 18686727,
16459170, -905725, 12376320, 31632953, 190926),
),
array(
array(-24593607, -16138885, -8423991, 13378746, 14162407,
6901328, -8288749, 4508564, -25341555, -3627528),
array(8884438, -5884009, 6023974, 10104341, -6881569,
-4941533, 18722941, -14786005, -1672488, 827625),
array(-32720583, -16289296, -32503547, 7101210, 13354605,
2659080, -1800575, -14108036, -24878478, 1541286),
),
array(
array(2901347, -1117687, 3880376, -10059388, -17620940,
-3612781, -21802117, -3567481, 20456845, -1885033),
array(27019610, 12299467, -13658288, -1603234, -12861660,
-4861471, -19540150, -5016058, 29439641, 15138866),
array(21536104, -6626420, -32447818, -10690208, -22408077,
5175814, -5420040, -16361163, 7779328, 109896),
),
array(
array(30279744, 14648750, -8044871, 6425558, 13639621,
-743509, 28698390, 12180118, 23177719, -554075),
array(26572847, 3405927, -31701700, 12890905, -19265668,
5335866, -6493768, 2378492, 4439158, -13279347),
array(-22716706, 3489070, -9225266, -332753, 18875722,
-1140095, 14819434, -12731527, -17717757, -5461437),
),
array(
array(-5056483, 16566551, 15953661, 3767752, -10436499,
15627060, -820954, 2177225, 8550082, -15114165),
array(-18473302, 16596775, -381660, 15663611, 22860960,
15585581, -27844109, -3582739, -23260460, -8428588),
array(-32480551, 15707275, -8205912, -5652081, 29464558,
2713815, -22725137, 15860482, -21902570, 1494193),
),
array(
array(-19562091, -14087393, -25583872, -9299552, 13127842,
759709, 21923482, 16529112, 8742704, 12967017),
array(-28464899, 1553205, 32536856, -10473729, -24691605,
-406174, -8914625, -2933896, -29903758, 15553883),
array(21877909, 3230008, 9881174, 10539357, -4797115,
2841332, 11543572, 14513274, 19375923, -12647961),
),
array(
array(8832269, -14495485, 13253511, 5137575, 5037871,
4078777, 24880818, -6222716, 2862653, 9455043),
array(29306751, 5123106, 20245049, -14149889, 9592566,
8447059, -2077124, -2990080, 15511449, 4789663),
array(-20679756, 7004547, 8824831, -9434977, -4045704,
-3750736, -5754762, 108893, 23513200, 16652362),
),
),
array(
array(
array(-33256173, 4144782, -4476029, -6579123, 10770039,
-7155542, -6650416, -12936300, -18319198, 10212860),
array(2756081, 8598110, 7383731, -6859892, 22312759,
-1105012, 21179801, 2600940, -9988298, -12506466),
array(-24645692, 13317462, -30449259, -15653928, 21365574,
-10869657, 11344424, 864440, -2499677, -16710063),
),
array(
array(-26432803, 6148329, -17184412, -14474154, 18782929,
-275997, -22561534, 211300, 2719757, 4940997),
array(-1323882, 3911313, -6948744, 14759765, -30027150,
7851207, 21690126, 8518463, 26699843, 5276295),
array(-13149873, -6429067, 9396249, 365013, 24703301,
-10488939, 1321586, 149635, -15452774, 7159369),
),
array(
array(9987780, -3404759, 17507962, 9505530, 9731535,
-2165514, 22356009, 8312176, 22477218, -8403385),
array(18155857, -16504990, 19744716, 9006923, 15154154,
-10538976, 24256460, -4864995, -22548173, 9334109),
array(2986088, -4911893, 10776628, -3473844, 10620590,
-7083203, -21413845, 14253545, -22587149, 536906),
),
array(
array(4377756, 8115836, 24567078, 15495314, 11625074,
13064599, 7390551, 10589625, 10838060, -15420424),
array(-19342404, 867880, 9277171, -3218459, -14431572,
-1986443, 19295826, -15796950, 6378260, 699185),
array(7895026, 4057113, -7081772, -13077756, -17886831,
-323126, -716039, 15693155, -5045064, -13373962),
),
array(
array(-7737563, -5869402, -14566319, -7406919, 11385654,
13201616, 31730678, -10962840, -3918636, -9669325),
array(10188286, -15770834, -7336361, 13427543, 22223443,
14896287, 30743455, 7116568, -21786507, 5427593),
array(696102, 13206899, 27047647, -10632082, 15285305,
-9853179, 10798490, -4578720, 19236243, 12477404),
),
array(
array(-11229439, 11243796, -17054270, -8040865, -788228,
-8167967, -3897669, 11180504, -23169516, 7733644),
array(17800790, -14036179, -27000429, -11766671, 23887827,
3149671, 23466177, -10538171, 10322027, 15313801),
array(26246234, 11968874, 32263343, -5468728, 6830755,
-13323031, -15794704, -101982, -24449242, 10890804),
),
array(
array(-31365647, 10271363, -12660625, -6267268, 16690207,
-13062544, -14982212, 16484931, 25180797, -5334884),
array(-586574, 10376444, -32586414, -11286356, 19801893,
10997610, 2276632, 9482883, 316878, 13820577),
array(-9882808, -4510367, -2115506, 16457136, -11100081,
11674996, 30756178, -7515054, 30696930, -3712849),
),
array(
array(32988917, -9603412, 12499366, 7910787, -10617257,
-11931514, -7342816, -9985397, -32349517, 7392473),
array(-8855661, 15927861, 9866406, -3649411, -2396914,
-16655781, -30409476, -9134995, 25112947, -2926644),
array(-2504044, -436966, 25621774, -5678772, 15085042,
-5479877, -24884878, -13526194, 5537438, -13914319),
),
),
array(
array(
array(-11225584, 2320285, -9584280, 10149187, -33444663,
5808648, -14876251, -1729667, 31234590, 6090599),
array(-9633316, 116426, 26083934, 2897444, -6364437,
-2688086, 609721, 15878753, -6970405, -9034768),
array(-27757857, 247744, -15194774, -9002551, 23288161,
-10011936, -23869595, 6503646, 20650474, 1804084),
),
array(
array(-27589786, 15456424, 8972517, 8469608, 15640622,
4439847, 3121995, -10329713, 27842616, -202328),
array(-15306973, 2839644, 22530074, 10026331, 4602058,
5048462, 28248656, 5031932, -11375082, 12714369),
array(20807691, -7270825, 29286141, 11421711, -27876523,
-13868230, -21227475, 1035546, -19733229, 12796920),
),
array(
array(12076899, -14301286, -8785001, -11848922, -25012791,
16400684, -17591495, -12899438, 3480665, -15182815),
array(-32361549, 5457597, 28548107, 7833186, 7303070,
-11953545, -24363064, -15921875, -33374054, 2771025),
array(-21389266, 421932, 26597266, 6860826, 22486084,
-6737172, -17137485, -4210226, -24552282, 15673397),
),
array(
array(-20184622, 2338216, 19788685, -9620956, -4001265,
-8740893, -20271184, 4733254, 3727144, -12934448),
array(6120119, 814863, -11794402, -622716, 6812205,
-15747771, 2019594, 7975683, 31123697, -10958981),
array(30069250, -11435332, 30434654, 2958439, 18399564,
-976289, 12296869, 9204260, -16432438, 9648165),
),
array(
array(32705432, -1550977, 30705658, 7451065, -11805606,
9631813, 3305266, 5248604, -26008332, -11377501),
array(17219865, 2375039, -31570947, -5575615, -19459679,
9219903, 294711, 15298639, 2662509, -16297073),
array(-1172927, -7558695, -4366770, -4287744, -21346413,
-8434326, 32087529, -1222777, 32247248, -14389861),
),
array(
array(14312628, 1221556, 17395390, -8700143, -4945741,
-8684635, -28197744, -9637817, -16027623, -13378845),
array(-1428825, -9678990, -9235681, 6549687, -7383069,
-468664, 23046502, 9803137, 17597934, 2346211),
array(18510800, 15337574, 26171504, 981392, -22241552,
7827556, -23491134, -11323352, 3059833, -11782870),
),
array(
array(10141598, 6082907, 17829293, -1947643, 9830092,
13613136, -25556636, -5544586, -33502212, 3592096),
array(33114168, -15889352, -26525686, -13343397, 33076705,
8716171, 1151462, 1521897, -982665, -6837803),
array(-32939165, -4255815, 23947181, -324178, -33072974,
-12305637, -16637686, 3891704, 26353178, 693168),
),
array(
array(30374239, 1595580, -16884039, 13186931, 4600344,
406904, 9585294, -400668, 31375464, 14369965),
array(-14370654, -7772529, 1510301, 6434173, -18784789,
-6262728, 32732230, -13108839, 17901441, 16011505),
array(18171223, -11934626, -12500402, 15197122, -11038147,
-15230035, -19172240, -16046376, 8764035, 12309598),
),
),
array(
array(
array(5975908, -5243188, -19459362, -9681747, -11541277,
14015782, -23665757, 1228319, 17544096, -10593782),
array(5811932, -1715293, 3442887, -2269310, -18367348,
-8359541, -18044043, -15410127, -5565381, 12348900),
array(-31399660, 11407555, 25755363, 6891399, -3256938,
14872274, -24849353, 8141295, -10632534, -585479),
),
array(
array(-12675304, 694026, -5076145, 13300344, 14015258,
-14451394, -9698672, -11329050, 30944593, 1130208),
array(8247766, -6710942, -26562381, -7709309, -14401939,
-14648910, 4652152, 2488540, 23550156, -271232),
array(17294316, -3788438, 7026748, 15626851, 22990044,
113481, 2267737, -5908146, -408818, -137719),
),
array(
array(16091085, -16253926, 18599252, 7340678, 2137637,
-1221657, -3364161, 14550936, 3260525, -7166271),
array(-4910104, -13332887, 18550887, 10864893, -16459325,
-7291596, -23028869, -13204905, -12748722, 2701326),
array(-8574695, 16099415, 4629974, -16340524, -20786213,
-6005432, -10018363, 9276971, 11329923, 1862132),
),
array(
array(14763076, -15903608, -30918270, 3689867, 3511892,
10313526, -21951088, 12219231, -9037963, -940300),
array(8894987, -3446094, 6150753, 3013931, 301220,
15693451, -31981216, -2909717, -15438168, 11595570),
array(15214962, 3537601, -26238722, -14058872, 4418657,
-15230761, 13947276, 10730794, -13489462, -4363670),
),
array(
array(-2538306, 7682793, 32759013, 263109, -29984731,
-7955452, -22332124, -10188635, 977108, 699994),
array(-12466472, 4195084, -9211532, 550904, -15565337,
12917920, 19118110, -439841, -30534533, -14337913),
array(31788461, -14507657, 4799989, 7372237, 8808585,
-14747943, 9408237, -10051775, 12493932, -5409317),
),
array(
array(-25680606, 5260744, -19235809, -6284470, -3695942,
16566087, 27218280, 2607121, 29375955, 6024730),
array(842132, -2794693, -4763381, -8722815, 26332018,
-12405641, 11831880, 6985184, -9940361, 2854096),
array(-4847262, -7969331, 2516242, -5847713, 9695691,
-7221186, 16512645, 960770, 12121869, 16648078),
),
array(
array(-15218652, 14667096, -13336229, 2013717, 30598287,
-464137, -31504922, -7882064, 20237806, 2838411),
array(-19288047, 4453152, 15298546, -16178388, 22115043,
-15972604, 12544294, -13470457, 1068881, -12499905),
array(-9558883, -16518835, 33238498, 13506958, 30505848,
-1114596, -8486907, -2630053, 12521378, 4845654),
),
array(
array(-28198521, 10744108, -2958380, 10199664, 7759311,
-13088600, 3409348, -873400, -6482306, -12885870),
array(-23561822, 6230156, -20382013, 10655314, -24040585,
-11621172, 10477734, -1240216, -3113227, 13974498),
array(12966261, 15550616, -32038948, -1615346, 21025980,
-629444, 5642325, 7188737, 18895762, 12629579),
),
),
array(
array(
array(14741879, -14946887, 22177208, -11721237, 1279741,
8058600, 11758140, 789443, 32195181, 3895677),
array(10758205, 15755439, -4509950, 9243698, -4879422,
6879879, -2204575, -3566119, -8982069, 4429647),
array(-2453894, 15725973, -20436342, -10410672, -5803908,
-11040220, -7135870, -11642895, 18047436, -15281743),
),
array(
array(-25173001, -11307165, 29759956, 11776784, -22262383,
-15820455, 10993114, -12850837, -17620701, -9408468),
array(21987233, 700364, -24505048, 14972008, -7774265,
-5718395, 32155026, 2581431, -29958985, 8773375),
array(-25568350, 454463, -13211935, 16126715, 25240068,
8594567, 20656846, 12017935, -7874389, -13920155),
),
array(
array(6028182, 6263078, -31011806, -11301710, -818919,
2461772, -31841174, -5468042, -1721788, -2776725),
array(-12278994, 16624277, 987579, -5922598, 32908203,
1248608, 7719845, -4166698, 28408820, 6816612),
array(-10358094, -8237829, 19549651, -12169222, 22082623,
16147817, 20613181, 13982702, -10339570, 5067943),
),
array(
array(-30505967, -3821767, 12074681, 13582412, -19877972,
2443951, -19719286, 12746132, 5331210, -10105944),
array(30528811, 3601899, -1957090, 4619785, -27361822,
-15436388, 24180793, -12570394, 27679908, -1648928),
array(9402404, -13957065, 32834043, 10838634, -26580150,
-13237195, 26653274, -8685565, 22611444, -12715406),
),
array(
array(22190590, 1118029, 22736441, 15130463, -30460692,
-5991321, 19189625, -4648942, 4854859, 6622139),
array(-8310738, -2953450, -8262579, -3388049, -10401731,
-271929, 13424426, -3567227, 26404409, 13001963),
array(-31241838, -15415700, -2994250, 8939346, 11562230,
-12840670, -26064365, -11621720, -15405155, 11020693),
),
array(
array(1866042, -7949489, -7898649, -10301010, 12483315,
13477547, 3175636, -12424163, 28761762, 1406734),
array(-448555, -1777666, 13018551, 3194501, -9580420,
-11161737, 24760585, -4347088, 25577411, -13378680),
array(-24290378, 4759345, -690653, -1852816, 2066747,
10693769, -29595790, 9884936, -9368926, 4745410),
),
array(
array(-9141284, 6049714, -19531061, -4341411, -31260798,
9944276, -15462008, -11311852, 10931924, -11931931),
array(-16561513, 14112680, -8012645, 4817318, -8040464,
-11414606, -22853429, 10856641, -20470770, 13434654),
array(22759489, -10073434, -16766264, -1871422, 13637442,
-10168091, 1765144, -12654326, 28445307, -5364710),
),
array(
array(29875063, 12493613, 2795536, -3786330, 1710620,
15181182, -10195717, -8788675, 9074234, 1167180),
array(-26205683, 11014233, -9842651, -2635485, -26908120,
7532294, -18716888, -9535498, 3843903, 9367684),
array(-10969595, -6403711, 9591134, 9582310, 11349256,
108879, 16235123, 8601684, -139197, 4242895),
),
),
array(
array(
array(22092954, -13191123, -2042793, -11968512, 32186753,
-11517388, -6574341, 2470660, -27417366, 16625501),
array(-11057722, 3042016, 13770083, -9257922, 584236,
-544855, -7770857, 2602725, -27351616, 14247413),
array(6314175, -10264892, -32772502, 15957557, -10157730,
168750, -8618807, 14290061, 27108877, -1180880),
),
array(
array(-8586597, -7170966, 13241782, 10960156, -32991015,
-13794596, 33547976, -11058889, -27148451, 981874),
array(22833440, 9293594, -32649448, -13618667, -9136966,
14756819, -22928859, -13970780, -10479804, -16197962),
array(-7768587, 3326786, -28111797, 10783824, 19178761,
14905060, 22680049, 13906969, -15933690, 3797899),
),
array(
array(21721356, -4212746, -12206123, 9310182, -3882239,
-13653110, 23740224, -2709232, 20491983, -8042152),
array(9209270, -15135055, -13256557, -6167798, -731016,
15289673, 25947805, 15286587, 30997318, -6703063),
array(7392032, 16618386, 23946583, -8039892, -13265164,
-1533858, -14197445, -2321576, 17649998, -250080),
),
array(
array(-9301088, -14193827, 30609526, -3049543, -25175069,
-1283752, -15241566, -9525724, -2233253, 7662146),
array(-17558673, 1763594, -33114336, 15908610, -30040870,
-12174295, 7335080, -8472199, -3174674, 3440183),
array(-19889700, -5977008, -24111293, -9688870, 10799743,
-16571957, 40450, -4431835, 4862400, 1133),
),
array(
array(-32856209, -7873957, -5422389, 14860950, -16319031,
7956142, 7258061, 311861, -30594991, -7379421),
array(-3773428, -1565936, 28985340, 7499440, 24445838,
9325937, 29727763, 16527196, 18278453, 15405622),
array(-4381906, 8508652, -19898366, -3674424, -5984453,
15149970, -13313598, 843523, -21875062, 13626197),
),
array(
array(2281448, -13487055, -10915418, -2609910, 1879358,
16164207, -10783882, 3953792, 13340839, 15928663),
array(31727126, -7179855, -18437503, -8283652, 2875793,
-16390330, -25269894, -7014826, -23452306, 5964753),
array(4100420, -5959452, -17179337, 6017714, -18705837,
12227141, -26684835, 11344144, 2538215, -7570755),
),
array(
array(-9433605, 6123113, 11159803, -2156608, 30016280,
14966241, -20474983, 1485421, -629256, -15958862),
array(-26804558, 4260919, 11851389, 9658551, -32017107,
16367492, -20205425, -13191288, 11659922, -11115118),
array(26180396, 10015009, -30844224, -8581293, 5418197,
9480663, 2231568, -10170080, 33100372, -1306171),
),
array(
array(15121113, -5201871, -10389905, 15427821, -27509937,
-15992507, 21670947, 4486675, -5931810, -14466380),
array(16166486, -9483733, -11104130, 6023908, -31926798,
-1364923, 2340060, -16254968, -10735770, -10039824),
array(28042865, -3557089, -12126526, 12259706, -3717498,
-6945899, 6766453, -8689599, 18036436, 5803270),
),
),
array(
array(
array(-817581, 6763912, 11803561, 1585585, 10958447,
-2671165, 23855391, 4598332, -6159431, -14117438),
array(-31031306, -14256194, 17332029, -2383520, 31312682,
-5967183, 696309, 50292, -20095739, 11763584),
array(-594563, -2514283, -32234153, 12643980, 12650761,
14811489, 665117, -12613632, -19773211, -10713562),
),
array(
array(30464590, -11262872, -4127476, -12734478, 19835327,
-7105613, -24396175, 2075773, -17020157, 992471),
array(18357185, -6994433, 7766382, 16342475, -29324918,
411174, 14578841, 8080033, -11574335, -10601610),
array(19598397, 10334610, 12555054, 2555664, 18821899,
-10339780, 21873263, 16014234, 26224780, 16452269),
),
array(
array(-30223925, 5145196, 5944548, 16385966, 3976735,
2009897, -11377804, -7618186, -20533829, 3698650),
array(14187449, 3448569, -10636236, -10810935, -22663880,
-3433596, 7268410, -10890444, 27394301, 12015369),
array(19695761, 16087646, 28032085, 12999827, 6817792,
11427614, 20244189, -1312777, -13259127, -3402461),
),
array(
array(30860103, 12735208, -1888245, -4699734, -16974906,
2256940, -8166013, 12298312, -8550524, -10393462),
array(-5719826, -11245325, -1910649, 15569035, 26642876,
-7587760, -5789354, -15118654, -4976164, 12651793),
array(-2848395, 9953421, 11531313, -5282879, 26895123,
-12697089, -13118820, -16517902, 9768698, -2533218),
),
array(
array(-24719459, 1894651, -287698, -4704085, 15348719,
-8156530, 32767513, 12765450, 4940095, 10678226),
array(18860224, 15980149, -18987240, -1562570, -26233012,
-11071856, -7843882, 13944024, -24372348, 16582019),
array(-15504260, 4970268, -29893044, 4175593, -20993212,
-2199756, -11704054, 15444560, -11003761, 7989037),
),
array(
array(31490452, 5568061, -2412803, 2182383, -32336847,
4531686, -32078269, 6200206, -19686113, -14800171),
array(-17308668, -15879940, -31522777, -2831, -32887382,
16375549, 8680158, -16371713, 28550068, -6857132),
array(-28126887, -5688091, 16837845, -1820458, -6850681,
12700016, -30039981, 4364038, 1155602, 5988841),
),
array(
array(21890435, -13272907, -12624011, 12154349, -7831873,
15300496, 23148983, -4470481, 24618407, 8283181),
array(-33136107, -10512751, 9975416, 6841041, -31559793,
16356536, 3070187, -7025928, 1466169, 10740210),
array(-1509399, -15488185, -13503385, -10655916, 32799044,
909394, -13938903, -5779719, -32164649, -15327040),
),
array(
array(3960823, -14267803, -28026090, -15918051, -19404858,
13146868, 15567327, 951507, -3260321, -573935),
array(24740841, 5052253, -30094131, 8961361, 25877428,
6165135, -24368180, 14397372, -7380369, -6144105),
array(-28888365, 3510803, -28103278, -1158478, -11238128,
-10631454, -15441463, -14453128, -1625486, -6494814),
),
),
array(
array(
array(793299, -9230478, 8836302, -6235707, -27360908,
-2369593, 33152843, -4885251, -9906200, -621852),
array(5666233, 525582, 20782575, -8038419, -24538499,
14657740, 16099374, 1468826, -6171428, -15186581),
array(-4859255, -3779343, -2917758, -6748019, 7778750,
11688288, -30404353, -9871238, -1558923, -9863646),
),
array(
array(10896332, -7719704, 824275, 472601, -19460308,
3009587, 25248958, 14783338, -30581476, -15757844),
array(10566929, 12612572, -31944212, 11118703, -12633376,
12362879, 21752402, 8822496, 24003793, 14264025),
array(27713862, -7355973, -11008240, 9227530, 27050101,
2504721, 23886875, -13117525, 13958495, -5732453),
),
array(
array(-23481610, 4867226, -27247128, 3900521, 29838369,
-8212291, -31889399, -10041781, 7340521, -15410068),
array(4646514, -8011124, -22766023, -11532654, 23184553,
8566613, 31366726, -1381061, -15066784, -10375192),
array(-17270517, 12723032, -16993061, 14878794, 21619651,
-6197576, 27584817, 3093888, -8843694, 3849921),
),
array(
array(-9064912, 2103172, 25561640, -15125738, -5239824,
9582958, 32477045, -9017955, 5002294, -15550259),
array(-12057553, -11177906, 21115585, -13365155, 8808712,
-12030708, 16489530, 13378448, -25845716, 12741426),
array(-5946367, 10645103, -30911586, 15390284, -3286982,
-7118677, 24306472, 15852464, 28834118, -7646072),
),
array(
array(-17335748, -9107057, -24531279, 9434953, -8472084,
-583362, -13090771, 455841, 20461858, 5491305),
array(13669248, -16095482, -12481974, -10203039, -14569770,
-11893198, -24995986, 11293807, -28588204, -9421832),
array(28497928, 6272777, -33022994, 14470570, 8906179,
-1225630, 18504674, -14165166, 29867745, -8795943),
),
array(
array(-16207023, 13517196, -27799630, -13697798, 24009064,
-6373891, -6367600, -13175392, 22853429, -4012011),
array(24191378, 16712145, -13931797, 15217831, 14542237,
1646131, 18603514, -11037887, 12876623, -2112447),
array(17902668, 4518229, -411702, -2829247, 26878217,
5258055, -12860753, 608397, 16031844, 3723494),
),
array(
array(-28632773, 12763728, -20446446, 7577504, 33001348,
-13017745, 17558842, -7872890, 23896954, -4314245),
array(-20005381, -12011952, 31520464, 605201, 2543521,
5991821, -2945064, 7229064, -9919646, -8826859),
array(28816045, 298879, -28165016, -15920938, 19000928,
-1665890, -12680833, -2949325, -18051778, -2082915),
),
array(
array(16000882, -344896, 3493092, -11447198, -29504595,
-13159789, 12577740, 16041268, -19715240, 7847707),
array(10151868, 10572098, 27312476, 7922682, 14825339,
4723128, -32855931, -6519018, -10020567, 3852848),
array(-11430470, 15697596, -21121557, -4420647, 5386314,
15063598, 16514493, -15932110, 29330899, -15076224),
),
),
array(
array(
array(-25499735, -4378794, -15222908, -6901211, 16615731,
2051784, 3303702, 15490, -27548796, 12314391),
array(15683520, -6003043, 18109120, -9980648, 15337968,
-5997823, -16717435, 15921866, 16103996, -3731215),
array(-23169824, -10781249, 13588192, -1628807, -3798557,
-1074929, -19273607, 5402699, -29815713, -9841101),
),
array(
array(23190676, 2384583, -32714340, 3462154, -29903655,
-1529132, -11266856, 8911517, -25205859, 2739713),
array(21374101, -3554250, -33524649, 9874411, 15377179,
11831242, -33529904, 6134907, 4931255, 11987849),
array(-7732, -2978858, -16223486, 7277597, 105524, -322051,
-31480539, 13861388, -30076310, 10117930),
),
array(
array(-29501170, -10744872, -26163768, 13051539, -25625564,
5089643, -6325503, 6704079, 12890019, 15728940),
array(-21972360, -11771379, -951059, -4418840, 14704840,
2695116, 903376, -10428139, 12885167, 8311031),
array(-17516482, 5352194, 10384213, -13811658, 7506451,
13453191, 26423267, 4384730, 1888765, -5435404),
),
array(
array(-25817338, -3107312, -13494599, -3182506, 30896459,
-13921729, -32251644, -12707869, -19464434, -3340243),
array(-23607977, -2665774, -526091, 4651136, 5765089,
4618330, 6092245, 14845197, 17151279, -9854116),
array(-24830458, -12733720, -15165978, 10367250, -29530908,
-265356, 22825805, -7087279, -16866484, 16176525),
),
array(
array(-23583256, 6564961, 20063689, 3798228, -4740178,
7359225, 2006182, -10363426, -28746253, -10197509),
array(-10626600, -4486402, -13320562, -5125317, 3432136,
-6393229, 23632037, -1940610, 32808310, 1099883),
array(15030977, 5768825, -27451236, -2887299, -6427378,
-15361371, -15277896, -6809350, 2051441, -15225865),
),
array(
array(-3362323, -7239372, 7517890, 9824992, 23555850,
295369, 5148398, -14154188, -22686354, 16633660),
array(4577086, -16752288, 13249841, -15304328, 19958763,
-14537274, 18559670, -10759549, 8402478, -9864273),
array(-28406330, -1051581, -26790155, -907698, -17212414,
-11030789, 9453451, -14980072, 17983010, 9967138),
),
array(
array(-25762494, 6524722, 26585488, 9969270, 24709298,
1220360, -1677990, 7806337, 17507396, 3651560),
array(-10420457, -4118111, 14584639, 15971087, -15768321,
8861010, 26556809, -5574557, -18553322, -11357135),
array(2839101, 14284142, 4029895, 3472686, 14402957,
12689363, -26642121, 8459447, -5605463, -7621941),
),
array(
array(-4839289, -3535444, 9744961, 2871048, 25113978,
3187018, -25110813, -849066, 17258084, -7977739),
array(18164541, -10595176, -17154882, -1542417, 19237078,
-9745295, 23357533, -15217008, 26908270, 12150756),
array(-30264870, -7647865, 5112249, -7036672, -1499807,
-6974257, 43168, -5537701, -32302074, 16215819),
),
),
array(
array(
array(-6898905, 9824394, -12304779, -4401089, -31397141,
-6276835, 32574489, 12532905, -7503072, -8675347),
array(-27343522, -16515468, -27151524, -10722951, 946346,
16291093, 254968, 7168080, 21676107, -1943028),
array(21260961, -8424752, -16831886, -11920822, -23677961,
3968121, -3651949, -6215466, -3556191, -7913075),
),
array(
array(16544754, 13250366, -16804428, 15546242, -4583003,
12757258, -2462308, -8680336, -18907032, -9662799),
array(-2415239, -15577728, 18312303, 4964443, -15272530,
-12653564, 26820651, 16690659, 25459437, -4564609),
array(-25144690, 11425020, 28423002, -11020557, -6144921,
-15826224, 9142795, -2391602, -6432418, -1644817),
),
array(
array(-23104652, 6253476, 16964147, -3768872, -25113972,
-12296437, -27457225, -16344658, 6335692, 7249989),
array(-30333227, 13979675, 7503222, -12368314, -11956721,
-4621693, -30272269, 2682242, 25993170, -12478523),
array(4364628, 5930691, 32304656, -10044554, -8054781,
15091131, 22857016, -10598955, 31820368, 15075278),
),
array(
array(31879134, -8918693, 17258761, 90626, -8041836,
-4917709, 24162788, -9650886, -17970238, 12833045),
array(19073683, 14851414, -24403169, -11860168, 7625278,
11091125, -19619190, 2074449, -9413939, 14905377),
array(24483667, -11935567, -2518866, -11547418, -1553130,
15355506, -25282080, 9253129, 27628530, -7555480),
),
array(
array(17597607, 8340603, 19355617, 552187, 26198470,
-3176583, 4593324, -9157582, -14110875, 15297016),
array(510886, 14337390, -31785257, 16638632, 6328095,
2713355, -20217417, -11864220, 8683221, 2921426),
array(18606791, 11874196, 27155355, -5281482, -24031742,
6265446, -25178240, -1278924, 4674690, 13890525),
),
array(
array(13609624, 13069022, -27372361, -13055908, 24360586,
9592974, 14977157, 9835105, 4389687, 288396),
array(9922506, -519394, 13613107, 5883594, -18758345,
-434263, -12304062, 8317628, 23388070, 16052080),
array(12720016, 11937594, -31970060, -5028689, 26900120,
8561328, -20155687, -11632979, -14754271, -10812892),
),
array(
array(15961858, 14150409, 26716931, -665832, -22794328,
13603569, 11829573, 7467844, -28822128, 929275),
array(11038231, -11582396, -27310482, -7316562, -10498527,
-16307831, -23479533, -9371869, -21393143, 2465074),
array(20017163, -4323226, 27915242, 1529148, 12396362,
15675764, 13817261, -9658066, 2463391, -4622140),
),
array(
array(-16358878, -12663911, -12065183, 4996454, -1256422,
1073572, 9583558, 12851107, 4003896, 12673717),
array(-1731589, -15155870, -3262930, 16143082, 19294135,
13385325, 14741514, -9103726, 7903886, 2348101),
array(24536016, -16515207, 12715592, -3862155, 1511293,
10047386, -3842346, -7129159, -28377538, 10048127),
),
),
array(
array(
array(-12622226, -6204820, 30718825, 2591312, -10617028,
12192840, 18873298, -7297090, -32297756, 15221632),
array(-26478122, -11103864, 11546244, -1852483, 9180880,
7656409, -21343950, 2095755, 29769758, 6593415),
array(-31994208, -2907461, 4176912, 3264766, 12538965,
-868111, 26312345, -6118678, 30958054, 8292160),
),
array(
array(31429822, -13959116, 29173532, 15632448, 12174511,
-2760094, 32808831, 3977186, 26143136, -3148876),
array(22648901, 1402143, -22799984, 13746059, 7936347,
365344, -8668633, -1674433, -3758243, -2304625),
array(-15491917, 8012313, -2514730, -12702462, -23965846,
-10254029, -1612713, -1535569, -16664475, 8194478),
),
array(
array(27338066, -7507420, -7414224, 10140405, -19026427,
-6589889, 27277191, 8855376, 28572286, 3005164),
array(26287124, 4821776, 25476601, -4145903, -3764513,
-15788984, -18008582, 1182479, -26094821, -13079595),
array(-7171154, 3178080, 23970071, 6201893, -17195577,
-4489192, -21876275, -13982627, 32208683, -1198248),
),
array(
array(-16657702, 2817643, -10286362, 14811298, 6024667,
13349505, -27315504, -10497842, -27672585, -11539858),
array(15941029, -9405932, -21367050, 8062055, 31876073,
-238629, -15278393, -1444429, 15397331, -4130193),
array(8934485, -13485467, -23286397, -13423241, -32446090,
14047986, 31170398, -1441021, -27505566, 15087184),
),
array(
array(-18357243, -2156491, 24524913, -16677868, 15520427,
-6360776, -15502406, 11461896, 16788528, -5868942),
array(-1947386, 16013773, 21750665, 3714552, -17401782,
-16055433, -3770287, -10323320, 31322514, -11615635),
array(21426655, -5650218, -13648287, -5347537, -28812189,
-4920970, -18275391, -14621414, 13040862, -12112948),
),
array(
array(11293895, 12478086, -27136401, 15083750, -29307421,
14748872, 14555558, -13417103, 1613711, 4896935),
array(-25894883, 15323294, -8489791, -8057900, 25967126,
-13425460, 2825960, -4897045, -23971776, -11267415),
array(-15924766, -5229880, -17443532, 6410664, 3622847,
10243618, 20615400, 12405433, -23753030, -8436416),
),
array(
array(-7091295, 12556208, -20191352, 9025187, -17072479,
4333801, 4378436, 2432030, 23097949, -566018),
array(4565804, -16025654, 20084412, -7842817, 1724999,
189254, 24767264, 10103221, -18512313, 2424778),
array(366633, -11976806, 8173090, -6890119, 30788634,
5745705, -7168678, 1344109, -3642553, 12412659),
),
array(
array(-24001791, 7690286, 14929416, -168257, -32210835,
-13412986, 24162697, -15326504, -3141501, 11179385),
array(18289522, -14724954, 8056945, 16430056, -21729724,
7842514, -6001441, -1486897, -18684645, -11443503),
array(476239, 6601091, -6152790, -9723375, 17503545,
-4863900, 27672959, 13403813, 11052904, 5219329),
),
),
array(
array(
array(20678546, -8375738, -32671898, 8849123, -5009758,
14574752, 31186971, -3973730, 9014762, -8579056),
array(-13644050, -10350239, -15962508, 5075808, -1514661,
-11534600, -33102500, 9160280, 8473550, -3256838),
array(24900749, 14435722, 17209120, -15292541, -22592275,
9878983, -7689309, -16335821, -24568481, 11788948),
),
array(
array(-3118155, -11395194, -13802089, 14797441, 9652448,
-6845904, -20037437, 10410733, -24568470, -1458691),
array(-15659161, 16736706, -22467150, 10215878, -9097177,
7563911, 11871841, -12505194, -18513325, 8464118),
array(-23400612, 8348507, -14585951, -861714, -3950205,
-6373419, 14325289, 8628612, 33313881, -8370517),
),
array(
array(-20186973, -4967935, 22367356, 5271547, -1097117,
-4788838, -24805667, -10236854, -8940735, -5818269),
array(-6948785, -1795212, -32625683, -16021179, 32635414,
-7374245, 15989197, -12838188, 28358192, -4253904),
array(-23561781, -2799059, -32351682, -1661963, -9147719,
10429267, -16637684, 4072016, -5351664, 5596589),
),
array(
array(-28236598, -3390048, 12312896, 6213178, 3117142,
16078565, 29266239, 2557221, 1768301, 15373193),
array(-7243358, -3246960, -4593467, -7553353, -127927,
-912245, -1090902, -4504991, -24660491, 3442910),
array(-30210571, 5124043, 14181784, 8197961, 18964734,
-11939093, 22597931, 7176455, -18585478, 13365930),
),
array(
array(-7877390, -1499958, 8324673, 4690079, 6261860,
890446, 24538107, -8570186, -9689599, -3031667),
array(25008904, -10771599, -4305031, -9638010, 16265036,
15721635, 683793, -11823784, 15723479, -15163481),
array(-9660625, 12374379, -27006999, -7026148, -7724114,
-12314514, 11879682, 5400171, 519526, -1235876),
),
array(
array(22258397, -16332233, -7869817, 14613016, -22520255,
-2950923, -20353881, 7315967, 16648397, 7605640),
array(-8081308, -8464597, -8223311, 9719710, 19259459,
-15348212, 23994942, -5281555, -9468848, 4763278),
array(-21699244, 9220969, -15730624, 1084137, -25476107,
-2852390, 31088447, -7764523, -11356529, 728112),
),
array(
array(26047220, -11751471, -6900323, -16521798, 24092068,
9158119, -4273545, -12555558, -29365436, -5498272),
array(17510331, -322857, 5854289, 8403524, 17133918,
-3112612, -28111007, 12327945, 10750447, 10014012),
array(-10312768, 3936952, 9156313, -8897683, 16498692,
-994647, -27481051, -666732, 3424691, 7540221),
),
array(
array(30322361, -6964110, 11361005, -4143317, 7433304,
4989748, -7071422, -16317219, -9244265, 15258046),
array(13054562, -2779497, 19155474, 469045, -12482797,
4566042, 5631406, 2711395, 1062915, -5136345),
array(-19240248, -11254599, -29509029, -7499965, -5835763,
13005411, -6066489, 12194497, 32960380, 1459310),
),
),
array(
array(
array(19852034, 7027924, 23669353, 10020366, 8586503,
-6657907, 394197, -6101885, 18638003, -11174937),
array(31395534, 15098109, 26581030, 8030562, -16527914,
-5007134, 9012486, -7584354, -6643087, -5442636),
array(-9192165, -2347377, -1997099, 4529534, 25766844,
607986, -13222, 9677543, -32294889, -6456008),
),
array(
array(-2444496, -149937, 29348902, 8186665, 1873760,
12489863, -30934579, -7839692, -7852844, -8138429),
array(-15236356, -15433509, 7766470, 746860, 26346930,
-10221762, -27333451, 10754588, -9431476, 5203576),
array(31834314, 14135496, -770007, 5159118, 20917671,
-16768096, -7467973, -7337524, 31809243, 7347066),
),
array(
array(-9606723, -11874240, 20414459, 13033986, 13716524,
-11691881, 19797970, -12211255, 15192876, -2087490),
array(-12663563, -2181719, 1168162, -3804809, 26747877,
-14138091, 10609330, 12694420, 33473243, -13382104),
array(33184999, 11180355, 15832085, -11385430, -1633671,
225884, 15089336, -11023903, -6135662, 14480053),
),
array(
array(31308717, -5619998, 31030840, -1897099, 15674547,
-6582883, 5496208, 13685227, 27595050, 8737275),
array(-20318852, -15150239, 10933843, -16178022, 8335352,
-7546022, -31008351, -12610604, 26498114, 66511),
array(22644454, -8761729, -16671776, 4884562, -3105614,
-13559366, 30540766, -4286747, -13327787, -7515095),
),
array(
array(-28017847, 9834845, 18617207, -2681312, -3401956,
-13307506, 8205540, 13585437, -17127465, 15115439),
array(23711543, -672915, 31206561, -8362711, 6164647,
-9709987, -33535882, -1426096, 8236921, 16492939),
array(-23910559, -13515526, -26299483, -4503841, 25005590,
-7687270, 19574902, 10071562, 6708380, -6222424),
),
array(
array(2101391, -4930054, 19702731, 2367575, -15427167,
1047675, 5301017, 9328700, 29955601, -11678310),
array(3096359, 9271816, -21620864, -15521844, -14847996,
-7592937, -25892142, -12635595, -9917575, 6216608),
array(-32615849, 338663, -25195611, 2510422, -29213566,
-13820213, 24822830, -6146567, -26767480, 7525079),
),
array(
array(-23066649, -13985623, 16133487, -7896178, -3389565,
778788, -910336, -2782495, -19386633, 11994101),
array(21691500, -13624626, -641331, -14367021, 3285881,
-3483596, -25064666, 9718258, -7477437, 13381418),
array(18445390, -4202236, 14979846, 11622458, -1727110,
-3582980, 23111648, -6375247, 28535282, 15779576),
),
array(
array(30098053, 3089662, -9234387, 16662135, -21306940,
11308411, -14068454, 12021730, 9955285, -16303356),
array(9734894, -14576830, -7473633, -9138735, 2060392,
11313496, -18426029, 9924399, 20194861, 13380996),
array(-26378102, -7965207, -22167821, 15789297, -18055342,
-6168792, -1984914, 15707771, 26342023, 10146099),
),
),
array(
array(
array(-26016874, -219943, 21339191, -41388, 19745256,
-2878700, -29637280, 2227040, 21612326, -545728),
array(-13077387, 1184228, 23562814, -5970442, -20351244,
-6348714, 25764461, 12243797, -20856566, 11649658),
array(-10031494, 11262626, 27384172, 2271902, 26947504,
-15997771, 39944, 6114064, 33514190, 2333242),
),
array(
array(-21433588, -12421821, 8119782, 7219913, -21830522,
-9016134, -6679750, -12670638, 24350578, -13450001),
array(-4116307, -11271533, -23886186, 4843615, -30088339,
690623, -31536088, -10406836, 8317860, 12352766),
array(18200138, -14475911, -33087759, -2696619, -23702521,
-9102511, -23552096, -2287550, 20712163, 6719373),
),
array(
array(26656208, 6075253, -7858556, 1886072, -28344043,
4262326, 11117530, -3763210, 26224235, -3297458),
array(-17168938, -14854097, -3395676, -16369877, -19954045,
14050420, 21728352, 9493610, 18620611, -16428628),
array(-13323321, 13325349, 11432106, 5964811, 18609221,
6062965, -5269471, -9725556, -30701573, -16479657),
),
array(
array(-23860538, -11233159, 26961357, 1640861, -32413112,
-16737940, 12248509, -5240639, 13735342, 1934062),
array(25089769, 6742589, 17081145, -13406266, 21909293,
-16067981, -15136294, -3765346, -21277997, 5473616),
array(31883677, -7961101, 1083432, -11572403, 22828471,
13290673, -7125085, 12469656, 29111212, -5451014),
),
array(
array(24244947, -15050407, -26262976, 2791540, -14997599,
16666678, 24367466, 6388839, -10295587, 452383),
array(-25640782, -3417841, 5217916, 16224624, 19987036,
-4082269, -24236251, -5915248, 15766062, 8407814),
array(-20406999, 13990231, 15495425, 16395525, 5377168,
15166495, -8917023, -4388953, -8067909, 2276718),
),
array(
array(30157918, 12924066, -17712050, 9245753, 19895028,
3368142, -23827587, 5096219, 22740376, -7303417),
array(2041139, -14256350, 7783687, 13876377, -25946985,
-13352459, 24051124, 13742383, -15637599, 13295222),
array(33338237, -8505733, 12532113, 7977527, 9106186,
-1715251, -17720195, -4612972, -4451357, -14669444),
),
array(
array(-20045281, 5454097, -14346548, 6447146, 28862071,
1883651, -2469266, -4141880, 7770569, 9620597),
array(23208068, 7979712, 33071466, 8149229, 1758231,
-10834995, 30945528, -1694323, -33502340, -14767970),
array(1439958, -16270480, -1079989, -793782, 4625402,
10647766, -5043801, 1220118, 30494170, -11440799),
),
array(
array(-5037580, -13028295, -2970559, -3061767, 15640974,
-6701666, -26739026, 926050, -1684339, -13333647),
array(13908495, -3549272, 30919928, -6273825, -21521863,
7989039, 9021034, 9078865, 3353509, 4033511),
array(-29663431, -15113610, 32259991, -344482, 24295849,
-12912123, 23161163, 8839127, 27485041, 7356032),
),
),
array(
array(
array(9661027, 705443, 11980065, -5370154, -1628543,
14661173, -6346142, 2625015, 28431036, -16771834),
array(-23839233, -8311415, -25945511, 7480958, -17681669,
-8354183, -22545972, 14150565, 15970762, 4099461),
array(29262576, 16756590, 26350592, -8793563, 8529671,
-11208050, 13617293, -9937143, 11465739, 8317062),
),
array(
array(-25493081, -6962928, 32500200, -9419051, -23038724,
-2302222, 14898637, 3848455, 20969334, -5157516),
array(-20384450, -14347713, -18336405, 13884722, -33039454,
2842114, -21610826, -3649888, 11177095, 14989547),
array(-24496721, -11716016, 16959896, 2278463, 12066309,
10137771, 13515641, 2581286, -28487508, 9930240),
),
array(
array(-17751622, -2097826, 16544300, -13009300, -15914807,
-14949081, 18345767, -13403753, 16291481, -5314038),
array(-33229194, 2553288, 32678213, 9875984, 8534129,
6889387, -9676774, 6957617, 4368891, 9788741),
array(16660756, 7281060, -10830758, 12911820, 20108584,
-8101676, -21722536, -8613148, 16250552, -11111103),
),
array(
array(-19765507, 2390526, -16551031, 14161980, 1905286,
6414907, 4689584, 10604807, -30190403, 4782747),
array(-1354539, 14736941, -7367442, -13292886, 7710542,
-14155590, -9981571, 4383045, 22546403, 437323),
array(31665577, -12180464, -16186830, 1491339, -18368625,
3294682, 27343084, 2786261, -30633590, -14097016),
),
array(
array(-14467279, -683715, -33374107, 7448552, 19294360,
14334329, -19690631, 2355319, -19284671, -6114373),
array(15121312, -15796162, 6377020, -6031361, -10798111,
-12957845, 18952177, 15496498, -29380133, 11754228),
array(-2637277, -13483075, 8488727, -14303896, 12728761,
-1622493, 7141596, 11724556, 22761615, -10134141),
),
array(
array(16918416, 11729663, -18083579, 3022987, -31015732,
-13339659, -28741185, -12227393, 32851222, 11717399),
array(11166634, 7338049, -6722523, 4531520, -29468672,
-7302055, 31474879, 3483633, -1193175, -4030831),
array(-185635, 9921305, 31456609, -13536438, -12013818,
13348923, 33142652, 6546660, -19985279, -3948376),
),
array(
array(-32460596, 11266712, -11197107, -7899103, 31703694,
3855903, -8537131, -12833048, -30772034, -15486313),
array(-18006477, 12709068, 3991746, -6479188, -21491523,
-10550425, -31135347, -16049879, 10928917, 3011958),
array(-6957757, -15594337, 31696059, 334240, 29576716,
14796075, -30831056, -12805180, 18008031, 10258577),
),
array(
array(-22448644, 15655569, 7018479, -4410003, -30314266,
-1201591, -1853465, 1367120, 25127874, 6671743),
array(29701166, -14373934, -10878120, 9279288, -17568,
13127210, 21382910, 11042292, 25838796, 4642684),
array(-20430234, 14955537, -24126347, 8124619, -5369288,
-5990470, 30468147, -13900640, 18423289, 4177476),
),
)
);
/**
* See: libsodium's crypto_core/curve25519/ref10/base2.h
*
* @var array<int, array<int, array<int, int>>>
basically int[8][3]
*/
protected static $base2 = array(
array(
array(25967493, -14356035, 29566456, 3660896, -12694345,
4014787, 27544626, -11754271, -6079156, 2047605),
array(-12545711, 934262, -2722910, 3049990, -727428, 9406986,
12720692, 5043384, 19500929, -15469378),
array(-8738181, 4489570, 9688441, -14785194, 10184609,
-12363380, 29287919, 11864899, -24514362, -4438546),
),
array(
array(15636291, -9688557, 24204773, -7912398, 616977,
-16685262, 27787600, -14772189, 28944400, -1550024),
array(16568933, 4717097, -11556148, -1102322, 15682896,
-11807043, 16354577, -11775962, 7689662, 11199574),
array(30464156, -5976125, -11779434, -15670865, 23220365,
15915852, 7512774, 10017326, -17749093, -9920357),
),
array(
array(10861363, 11473154, 27284546, 1981175, -30064349,
12577861, 32867885, 14515107, -15438304, 10819380),
array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696,
-25653668, 12483688, -12668491, 5581306),
array(19563160, 16186464, -29386857, 4097519, 10237984,
-4348115, 28542350, 13850243, -23678021, -15815942),
),
array(
array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873,
19480852, 5230134, -23952439, -15175766),
array(-30269007, -3463509, 7665486, 10083793, 28475525,
1649722, 20654025, 16520125, 30598449, 7715701),
array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316,
-31400660, 1370708, 29794553, -1409300),
),
array(
array(-22518993, -6692182, 14201702, -8745502, -23510406,
8844726, 18474211, -1361450, -13062696, 13821877),
array(-6455177, -7839871, 3374702, -4740862, -27098617,
-10571707, 31655028, -7212327, 18853322, -14220951),
array(4566830, -12963868, -28974889, -12240689, -7602672,
-2830569, -8514358, -10431137, 2207753, -3209784),
),
array(
array(-25154831, -4185821, 29681144, 7868801, -6854661,
-9423865, -12437364, -663000, -31111463, -16132436),
array(25576264, -2703214, 7349804, -11814844, 16472782,
9300885, 3844789, 15725684, 171356, 6466918),
array(23103977, 13316479, 9739013, -16149481, 817875,
-15038942, 8965339, -14088058, -30714912, 16193877),
),
array(
array(-33521811, 3180713, -2394130, 14003687, -16903474,
-16270840, 17238398, 4729455, -18074513, 9256800),
array(-25182317, -4174131, 32336398, 5036987, -21236817,
11360617, 22616405, 9761698, -19827198, 630305),
array(-13720693, 2639453, -24237460, -7406481, 9494427,
-5774029, -6554551, -15960994, -2449256, -14291300),
),
array(
array(-3151181, -5046075, 9282714, 6866145, -31907062, -863023,
-18940575, 15033784, 25105118, -7894876),
array(-24326370, 15950226, -31801215, -14592823, -11662737,
-5090925, 1573892, -2625887, 2198790, -15804619),
array(-3099351, 10324967, -2241613, 7453183, -5446979,
-2735503, -13812022, -16236442, -32461234, -12290683),
)
);
/**
*
37095705934669439343138083508754565189542113879843219016388785533085940283555
*
* @var array<int, int>
*/
protected static $d = array(
-10913610,
13857413,
-15372611,
6949391,
114729,
-8787816,
-6275908,
-3247719,
-18696448,
-12055116
);
/**
* 2 * d =
16295367250680780974490674513165176452449235426866156013048779062215315747161
*
* @var array<int, int>
*/
protected static $d2 = array(
-21827239,
-5839606,
-30745221,
13898782,
229458,
15978800,
-12551817,
-6495438,
29715968,
9444199
);
/**
* sqrt(-1)
*
* @var array<int, int>
*/
protected static $sqrtm1 = array(
-32595792,
-7943725,
9377950,
3500415,
12389472,
-272473,
-25146209,
-2005654,
326686,
11406482
);
}
# Curve25519 Data Structures
These are PHP implementation of the [structs used in the ref10 curve25519
code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h).
<?php
if (class_exists('ParagonIE_Sodium_Core32_Curve25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519
*
* Implements Curve25519 core functions
*
* Based on the ref10 curve25519 code provided by libsodium
*
* @ref
https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c
*/
abstract class ParagonIE_Sodium_Core32_Curve25519 extends
ParagonIE_Sodium_Core32_Curve25519_H
{
/**
* Get a field element of size 10 with a value of 0
*
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function fe_0()
{
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32()
)
);
}
/**
* Get a field element of size 10 with a value of 1
*
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function fe_1()
{
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(1),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32(),
new ParagonIE_Sodium_Core32_Int32()
)
);
}
/**
* Add two field elements.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_add(
ParagonIE_Sodium_Core32_Curve25519_Fe $f,
ParagonIE_Sodium_Core32_Curve25519_Fe $g
) {
$arr = array();
for ($i = 0; $i < 10; ++$i) {
$arr[$i] = $f[$i]->addInt32($g[$i]);
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $arr */
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($arr);
}
/**
* Constant-time conditional move.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @param int $b
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_cmov(
ParagonIE_Sodium_Core32_Curve25519_Fe $f,
ParagonIE_Sodium_Core32_Curve25519_Fe $g,
$b = 0
) {
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
$h = array();
for ($i = 0; $i < 10; ++$i) {
if (!($f[$i] instanceof ParagonIE_Sodium_Core32_Int32)) {
throw new TypeError('Expected Int32');
}
if (!($g[$i] instanceof ParagonIE_Sodium_Core32_Int32)) {
throw new TypeError('Expected Int32');
}
$h[$i] = $f[$i]->xorInt32(
$f[$i]->xorInt32($g[$i])->mask($b)
);
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h);
}
/**
* Create a copy of a field element.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public static function fe_copy(ParagonIE_Sodium_Core32_Curve25519_Fe
$f)
{
$h = clone $f;
return $h;
}
/**
* Give: 32-byte string.
* Receive: A field element object to use for internal calculations.
*
* @internal You should not use this directly from another application
*
* @param string $s
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws RangeException
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
*/
public static function fe_frombytes($s)
{
if (self::strlen($s) !== 32) {
throw new RangeException('Expected a 32-byte
string.');
}
/** @var ParagonIE_Sodium_Core32_Int32 $h0 */
$h0 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_4($s)
);
/** @var ParagonIE_Sodium_Core32_Int32 $h1 */
$h1 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 4, 3)) << 6
);
/** @var ParagonIE_Sodium_Core32_Int32 $h2 */
$h2 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 7, 3)) << 5
);
/** @var ParagonIE_Sodium_Core32_Int32 $h3 */
$h3 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 10, 3)) << 3
);
/** @var ParagonIE_Sodium_Core32_Int32 $h4 */
$h4 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 13, 3)) << 2
);
/** @var ParagonIE_Sodium_Core32_Int32 $h5 */
$h5 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_4(self::substr($s, 16, 4))
);
/** @var ParagonIE_Sodium_Core32_Int32 $h6 */
$h6 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 20, 3)) << 7
);
/** @var ParagonIE_Sodium_Core32_Int32 $h7 */
$h7 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 23, 3)) << 5
);
/** @var ParagonIE_Sodium_Core32_Int32 $h8 */
$h8 = ParagonIE_Sodium_Core32_Int32::fromInt(
self::load_3(self::substr($s, 26, 3)) << 4
);
/** @var ParagonIE_Sodium_Core32_Int32 $h9 */
$h9 = ParagonIE_Sodium_Core32_Int32::fromInt(
(self::load_3(self::substr($s, 29, 3)) & 8388607) <<
2
);
$carry9 = $h9->addInt(1 << 24)->shiftRight(25);
$h0 = $h0->addInt32($carry9->mulInt(19, 5));
$h9 = $h9->subInt32($carry9->shiftLeft(25));
$carry1 = $h1->addInt(1 << 24)->shiftRight(25);
$h2 = $h2->addInt32($carry1);
$h1 = $h1->subInt32($carry1->shiftLeft(25));
$carry3 = $h3->addInt(1 << 24)->shiftRight(25);
$h4 = $h4->addInt32($carry3);
$h3 = $h3->subInt32($carry3->shiftLeft(25));
$carry5 = $h5->addInt(1 << 24)->shiftRight(25);
$h6 = $h6->addInt32($carry5);
$h5 = $h5->subInt32($carry5->shiftLeft(25));
$carry7 = $h7->addInt(1 << 24)->shiftRight(25);
$h8 = $h8->addInt32($carry7);
$h7 = $h7->subInt32($carry7->shiftLeft(25));
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt32($carry0);
$h0 = $h0->subInt32($carry0->shiftLeft(26));
$carry2 = $h2->addInt(1 << 25)->shiftRight(26);
$h3 = $h3->addInt32($carry2);
$h2 = $h2->subInt32($carry2->shiftLeft(26));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt32($carry4);
$h4 = $h4->subInt32($carry4->shiftLeft(26));
$carry6 = $h6->addInt(1 << 25)->shiftRight(26);
$h7 = $h7->addInt32($carry6);
$h6 = $h6->subInt32($carry6->shiftLeft(26));
$carry8 = $h8->addInt(1 << 25)->shiftRight(26);
$h9 = $h9->addInt32($carry8);
$h8 = $h8->subInt32($carry8->shiftLeft(26));
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array($h0, $h1, $h2,$h3, $h4, $h5, $h6, $h7, $h8, $h9)
);
}
/**
* Convert a field element to a byte string.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $h
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_tobytes(ParagonIE_Sodium_Core32_Curve25519_Fe
$h)
{
/**
* @var ParagonIE_Sodium_Core32_Int64[] $f
* @var ParagonIE_Sodium_Core32_Int64 $q
*/
$f = array();
for ($i = 0; $i < 10; ++$i) {
$f[$i] = $h[$i]->toInt64();
}
$q = $f[9]->mulInt(19, 5)->addInt(1 <<
14)->shiftRight(25)
->addInt64($f[0])->shiftRight(26)
->addInt64($f[1])->shiftRight(25)
->addInt64($f[2])->shiftRight(26)
->addInt64($f[3])->shiftRight(25)
->addInt64($f[4])->shiftRight(26)
->addInt64($f[5])->shiftRight(25)
->addInt64($f[6])->shiftRight(26)
->addInt64($f[7])->shiftRight(25)
->addInt64($f[8])->shiftRight(26)
->addInt64($f[9])->shiftRight(25);
$f[0] = $f[0]->addInt64($q->mulInt(19, 5));
$carry0 = $f[0]->shiftRight(26);
$f[1] = $f[1]->addInt64($carry0);
$f[0] = $f[0]->subInt64($carry0->shiftLeft(26));
$carry1 = $f[1]->shiftRight(25);
$f[2] = $f[2]->addInt64($carry1);
$f[1] = $f[1]->subInt64($carry1->shiftLeft(25));
$carry2 = $f[2]->shiftRight(26);
$f[3] = $f[3]->addInt64($carry2);
$f[2] = $f[2]->subInt64($carry2->shiftLeft(26));
$carry3 = $f[3]->shiftRight(25);
$f[4] = $f[4]->addInt64($carry3);
$f[3] = $f[3]->subInt64($carry3->shiftLeft(25));
$carry4 = $f[4]->shiftRight(26);
$f[5] = $f[5]->addInt64($carry4);
$f[4] = $f[4]->subInt64($carry4->shiftLeft(26));
$carry5 = $f[5]->shiftRight(25);
$f[6] = $f[6]->addInt64($carry5);
$f[5] = $f[5]->subInt64($carry5->shiftLeft(25));
$carry6 = $f[6]->shiftRight(26);
$f[7] = $f[7]->addInt64($carry6);
$f[6] = $f[6]->subInt64($carry6->shiftLeft(26));
$carry7 = $f[7]->shiftRight(25);
$f[8] = $f[8]->addInt64($carry7);
$f[7] = $f[7]->subInt64($carry7->shiftLeft(25));
$carry8 = $f[8]->shiftRight(26);
$f[9] = $f[9]->addInt64($carry8);
$f[8] = $f[8]->subInt64($carry8->shiftLeft(26));
$carry9 = $f[9]->shiftRight(25);
$f[9] = $f[9]->subInt64($carry9->shiftLeft(25));
/** @var int $h0 */
$h0 = $f[0]->toInt32()->toInt();
/** @var int $h1 */
$h1 = $f[1]->toInt32()->toInt();
/** @var int $h2 */
$h2 = $f[2]->toInt32()->toInt();
/** @var int $h3 */
$h3 = $f[3]->toInt32()->toInt();
/** @var int $h4 */
$h4 = $f[4]->toInt32()->toInt();
/** @var int $h5 */
$h5 = $f[5]->toInt32()->toInt();
/** @var int $h6 */
$h6 = $f[6]->toInt32()->toInt();
/** @var int $h7 */
$h7 = $f[7]->toInt32()->toInt();
/** @var int $h8 */
$h8 = $f[8]->toInt32()->toInt();
/** @var int $h9 */
$h9 = $f[9]->toInt32()->toInt();
/**
* @var array<int, int>
*/
$s = array(
(int) (($h0 >> 0) & 0xff),
(int) (($h0 >> 8) & 0xff),
(int) (($h0 >> 16) & 0xff),
(int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
(int) (($h1 >> 6) & 0xff),
(int) (($h1 >> 14) & 0xff),
(int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
(int) (($h2 >> 5) & 0xff),
(int) (($h2 >> 13) & 0xff),
(int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
(int) (($h3 >> 3) & 0xff),
(int) (($h3 >> 11) & 0xff),
(int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
(int) (($h4 >> 2) & 0xff),
(int) (($h4 >> 10) & 0xff),
(int) (($h4 >> 18) & 0xff),
(int) (($h5 >> 0) & 0xff),
(int) (($h5 >> 8) & 0xff),
(int) (($h5 >> 16) & 0xff),
(int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
(int) (($h6 >> 7) & 0xff),
(int) (($h6 >> 15) & 0xff),
(int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
(int) (($h7 >> 5) & 0xff),
(int) (($h7 >> 13) & 0xff),
(int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
(int) (($h8 >> 4) & 0xff),
(int) (($h8 >> 12) & 0xff),
(int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
(int) (($h9 >> 2) & 0xff),
(int) (($h9 >> 10) & 0xff),
(int) (($h9 >> 18) & 0xff)
);
return self::intArrayToString($s);
}
/**
* Is a field element negative? (1 = yes, 0 = no. Used in
calculations.)
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function
fe_isnegative(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
$str = self::fe_tobytes($f);
return (int) (self::chrToInt($str[0]) & 1);
}
/**
* Returns 0 if this field element results in all NUL bytes.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function
fe_isnonzero(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
static $zero;
if ($zero === null) {
$zero = str_repeat("\x00", 32);
}
/** @var string $str */
$str = self::fe_tobytes($f);
/** @var string $zero */
return !self::verify_32($str, $zero);
}
/**
* Multiply two field elements
*
* h = f * g
*
* @internal You should not use this directly from another application
*
* @security Is multiplication a source of timing leaks? If so, can we
do
* anything to prevent that from happening?
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function fe_mul(
ParagonIE_Sodium_Core32_Curve25519_Fe $f,
ParagonIE_Sodium_Core32_Curve25519_Fe $g
) {
/**
* @var ParagonIE_Sodium_Core32_Int32[] $f
* @var ParagonIE_Sodium_Core32_Int32[] $g
* @var ParagonIE_Sodium_Core32_Int64 $f0
* @var ParagonIE_Sodium_Core32_Int64 $f1
* @var ParagonIE_Sodium_Core32_Int64 $f2
* @var ParagonIE_Sodium_Core32_Int64 $f3
* @var ParagonIE_Sodium_Core32_Int64 $f4
* @var ParagonIE_Sodium_Core32_Int64 $f5
* @var ParagonIE_Sodium_Core32_Int64 $f6
* @var ParagonIE_Sodium_Core32_Int64 $f7
* @var ParagonIE_Sodium_Core32_Int64 $f8
* @var ParagonIE_Sodium_Core32_Int64 $f9
* @var ParagonIE_Sodium_Core32_Int64 $g0
* @var ParagonIE_Sodium_Core32_Int64 $g1
* @var ParagonIE_Sodium_Core32_Int64 $g2
* @var ParagonIE_Sodium_Core32_Int64 $g3
* @var ParagonIE_Sodium_Core32_Int64 $g4
* @var ParagonIE_Sodium_Core32_Int64 $g5
* @var ParagonIE_Sodium_Core32_Int64 $g6
* @var ParagonIE_Sodium_Core32_Int64 $g7
* @var ParagonIE_Sodium_Core32_Int64 $g8
* @var ParagonIE_Sodium_Core32_Int64 $g9
*/
$f0 = $f[0]->toInt64();
$f1 = $f[1]->toInt64();
$f2 = $f[2]->toInt64();
$f3 = $f[3]->toInt64();
$f4 = $f[4]->toInt64();
$f5 = $f[5]->toInt64();
$f6 = $f[6]->toInt64();
$f7 = $f[7]->toInt64();
$f8 = $f[8]->toInt64();
$f9 = $f[9]->toInt64();
$g0 = $g[0]->toInt64();
$g1 = $g[1]->toInt64();
$g2 = $g[2]->toInt64();
$g3 = $g[3]->toInt64();
$g4 = $g[4]->toInt64();
$g5 = $g[5]->toInt64();
$g6 = $g[6]->toInt64();
$g7 = $g[7]->toInt64();
$g8 = $g[8]->toInt64();
$g9 = $g[9]->toInt64();
$g1_19 = $g1->mulInt(19, 5); /* 2^4 <= 19 <= 2^5, but we
only want 5 bits */
$g2_19 = $g2->mulInt(19, 5);
$g3_19 = $g3->mulInt(19, 5);
$g4_19 = $g4->mulInt(19, 5);
$g5_19 = $g5->mulInt(19, 5);
$g6_19 = $g6->mulInt(19, 5);
$g7_19 = $g7->mulInt(19, 5);
$g8_19 = $g8->mulInt(19, 5);
$g9_19 = $g9->mulInt(19, 5);
/** @var ParagonIE_Sodium_Core32_Int64 $f1_2 */
$f1_2 = $f1->shiftLeft(1);
/** @var ParagonIE_Sodium_Core32_Int64 $f3_2 */
$f3_2 = $f3->shiftLeft(1);
/** @var ParagonIE_Sodium_Core32_Int64 $f5_2 */
$f5_2 = $f5->shiftLeft(1);
/** @var ParagonIE_Sodium_Core32_Int64 $f7_2 */
$f7_2 = $f7->shiftLeft(1);
/** @var ParagonIE_Sodium_Core32_Int64 $f9_2 */
$f9_2 = $f9->shiftLeft(1);
$f0g0 = $f0->mulInt64($g0, 27);
$f0g1 = $f0->mulInt64($g1, 27);
$f0g2 = $f0->mulInt64($g2, 27);
$f0g3 = $f0->mulInt64($g3, 27);
$f0g4 = $f0->mulInt64($g4, 27);
$f0g5 = $f0->mulInt64($g5, 27);
$f0g6 = $f0->mulInt64($g6, 27);
$f0g7 = $f0->mulInt64($g7, 27);
$f0g8 = $f0->mulInt64($g8, 27);
$f0g9 = $f0->mulInt64($g9, 27);
$f1g0 = $f1->mulInt64($g0, 27);
$f1g1_2 = $f1_2->mulInt64($g1, 27);
$f1g2 = $f1->mulInt64($g2, 27);
$f1g3_2 = $f1_2->mulInt64($g3, 27);
$f1g4 = $f1->mulInt64($g4, 30);
$f1g5_2 = $f1_2->mulInt64($g5, 30);
$f1g6 = $f1->mulInt64($g6, 30);
$f1g7_2 = $f1_2->mulInt64($g7, 30);
$f1g8 = $f1->mulInt64($g8, 30);
$f1g9_38 = $g9_19->mulInt64($f1_2, 30);
$f2g0 = $f2->mulInt64($g0, 30);
$f2g1 = $f2->mulInt64($g1, 29);
$f2g2 = $f2->mulInt64($g2, 30);
$f2g3 = $f2->mulInt64($g3, 29);
$f2g4 = $f2->mulInt64($g4, 30);
$f2g5 = $f2->mulInt64($g5, 29);
$f2g6 = $f2->mulInt64($g6, 30);
$f2g7 = $f2->mulInt64($g7, 29);
$f2g8_19 = $g8_19->mulInt64($f2, 30);
$f2g9_19 = $g9_19->mulInt64($f2, 30);
$f3g0 = $f3->mulInt64($g0, 30);
$f3g1_2 = $f3_2->mulInt64($g1, 30);
$f3g2 = $f3->mulInt64($g2, 30);
$f3g3_2 = $f3_2->mulInt64($g3, 30);
$f3g4 = $f3->mulInt64($g4, 30);
$f3g5_2 = $f3_2->mulInt64($g5, 30);
$f3g6 = $f3->mulInt64($g6, 30);
$f3g7_38 = $g7_19->mulInt64($f3_2, 30);
$f3g8_19 = $g8_19->mulInt64($f3, 30);
$f3g9_38 = $g9_19->mulInt64($f3_2, 30);
$f4g0 = $f4->mulInt64($g0, 30);
$f4g1 = $f4->mulInt64($g1, 30);
$f4g2 = $f4->mulInt64($g2, 30);
$f4g3 = $f4->mulInt64($g3, 30);
$f4g4 = $f4->mulInt64($g4, 30);
$f4g5 = $f4->mulInt64($g5, 30);
$f4g6_19 = $g6_19->mulInt64($f4, 30);
$f4g7_19 = $g7_19->mulInt64($f4, 30);
$f4g8_19 = $g8_19->mulInt64($f4, 30);
$f4g9_19 = $g9_19->mulInt64($f4, 30);
$f5g0 = $f5->mulInt64($g0, 30);
$f5g1_2 = $f5_2->mulInt64($g1, 30);
$f5g2 = $f5->mulInt64($g2, 30);
$f5g3_2 = $f5_2->mulInt64($g3, 30);
$f5g4 = $f5->mulInt64($g4, 30);
$f5g5_38 = $g5_19->mulInt64($f5_2, 30);
$f5g6_19 = $g6_19->mulInt64($f5, 30);
$f5g7_38 = $g7_19->mulInt64($f5_2, 30);
$f5g8_19 = $g8_19->mulInt64($f5, 30);
$f5g9_38 = $g9_19->mulInt64($f5_2, 30);
$f6g0 = $f6->mulInt64($g0, 30);
$f6g1 = $f6->mulInt64($g1, 30);
$f6g2 = $f6->mulInt64($g2, 30);
$f6g3 = $f6->mulInt64($g3, 30);
$f6g4_19 = $g4_19->mulInt64($f6, 30);
$f6g5_19 = $g5_19->mulInt64($f6, 30);
$f6g6_19 = $g6_19->mulInt64($f6, 30);
$f6g7_19 = $g7_19->mulInt64($f6, 30);
$f6g8_19 = $g8_19->mulInt64($f6, 30);
$f6g9_19 = $g9_19->mulInt64($f6, 30);
$f7g0 = $f7->mulInt64($g0, 30);
$f7g1_2 = $g1->mulInt64($f7_2, 30);
$f7g2 = $f7->mulInt64($g2, 30);
$f7g3_38 = $g3_19->mulInt64($f7_2, 30);
$f7g4_19 = $g4_19->mulInt64($f7, 30);
$f7g5_38 = $g5_19->mulInt64($f7_2, 30);
$f7g6_19 = $g6_19->mulInt64($f7, 30);
$f7g7_38 = $g7_19->mulInt64($f7_2, 30);
$f7g8_19 = $g8_19->mulInt64($f7, 30);
$f7g9_38 = $g9_19->mulInt64($f7_2, 30);
$f8g0 = $f8->mulInt64($g0, 30);
$f8g1 = $f8->mulInt64($g1, 29);
$f8g2_19 = $g2_19->mulInt64($f8, 30);
$f8g3_19 = $g3_19->mulInt64($f8, 30);
$f8g4_19 = $g4_19->mulInt64($f8, 30);
$f8g5_19 = $g5_19->mulInt64($f8, 30);
$f8g6_19 = $g6_19->mulInt64($f8, 30);
$f8g7_19 = $g7_19->mulInt64($f8, 30);
$f8g8_19 = $g8_19->mulInt64($f8, 30);
$f8g9_19 = $g9_19->mulInt64($f8, 30);
$f9g0 = $f9->mulInt64($g0, 30);
$f9g1_38 = $g1_19->mulInt64($f9_2, 30);
$f9g2_19 = $g2_19->mulInt64($f9, 30);
$f9g3_38 = $g3_19->mulInt64($f9_2, 30);
$f9g4_19 = $g4_19->mulInt64($f9, 30);
$f9g5_38 = $g5_19->mulInt64($f9_2, 30);
$f9g6_19 = $g6_19->mulInt64($f9, 30);
$f9g7_38 = $g7_19->mulInt64($f9_2, 30);
$f9g8_19 = $g8_19->mulInt64($f9, 30);
$f9g9_38 = $g9_19->mulInt64($f9_2, 30);
// $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 +
$f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
$h0 =
$f0g0->addInt64($f1g9_38)->addInt64($f2g8_19)->addInt64($f3g7_38)
->addInt64($f4g6_19)->addInt64($f5g5_38)->addInt64($f6g4_19)
->addInt64($f7g3_38)->addInt64($f8g2_19)->addInt64($f9g1_38);
// $h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 +
$f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
$h1 =
$f0g1->addInt64($f1g0)->addInt64($f2g9_19)->addInt64($f3g8_19)
->addInt64($f4g7_19)->addInt64($f5g6_19)->addInt64($f6g5_19)
->addInt64($f7g4_19)->addInt64($f8g3_19)->addInt64($f9g2_19);
// $h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 +
$f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
$h2 =
$f0g2->addInt64($f1g1_2)->addInt64($f2g0)->addInt64($f3g9_38)
->addInt64($f4g8_19)->addInt64($f5g7_38)->addInt64($f6g6_19)
->addInt64($f7g5_38)->addInt64($f8g4_19)->addInt64($f9g3_38);
// $h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 +
$f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
$h3 =
$f0g3->addInt64($f1g2)->addInt64($f2g1)->addInt64($f3g0)
->addInt64($f4g9_19)->addInt64($f5g8_19)->addInt64($f6g7_19)
->addInt64($f7g6_19)->addInt64($f8g5_19)->addInt64($f9g4_19);
// $h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 +
$f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
$h4 =
$f0g4->addInt64($f1g3_2)->addInt64($f2g2)->addInt64($f3g1_2)
->addInt64($f4g0)->addInt64($f5g9_38)->addInt64($f6g8_19)
->addInt64($f7g7_38)->addInt64($f8g6_19)->addInt64($f9g5_38);
// $h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0
+ $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
$h5 =
$f0g5->addInt64($f1g4)->addInt64($f2g3)->addInt64($f3g2)
->addInt64($f4g1)->addInt64($f5g0)->addInt64($f6g9_19)
->addInt64($f7g8_19)->addInt64($f8g7_19)->addInt64($f9g6_19);
// $h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 +
$f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38;
$h6 =
$f0g6->addInt64($f1g5_2)->addInt64($f2g4)->addInt64($f3g3_2)
->addInt64($f4g2)->addInt64($f5g1_2)->addInt64($f6g0)
->addInt64($f7g9_38)->addInt64($f8g8_19)->addInt64($f9g7_38);
// $h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2
+ $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19;
$h7 =
$f0g7->addInt64($f1g6)->addInt64($f2g5)->addInt64($f3g4)
->addInt64($f4g3)->addInt64($f5g2)->addInt64($f6g1)
->addInt64($f7g0)->addInt64($f8g9_19)->addInt64($f9g8_19);
// $h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 +
$f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38;
$h8 =
$f0g8->addInt64($f1g7_2)->addInt64($f2g6)->addInt64($f3g5_2)
->addInt64($f4g4)->addInt64($f5g3_2)->addInt64($f6g2)
->addInt64($f7g1_2)->addInt64($f8g0)->addInt64($f9g9_38);
// $h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4
+ $f6g3 + $f7g2 + $f8g1 + $f9g0 ;
$h9 =
$f0g9->addInt64($f1g8)->addInt64($f2g7)->addInt64($f3g6)
->addInt64($f4g5)->addInt64($f5g4)->addInt64($f6g3)
->addInt64($f7g2)->addInt64($f8g1)->addInt64($f9g0);
/**
* @var ParagonIE_Sodium_Core32_Int64 $h0
* @var ParagonIE_Sodium_Core32_Int64 $h1
* @var ParagonIE_Sodium_Core32_Int64 $h2
* @var ParagonIE_Sodium_Core32_Int64 $h3
* @var ParagonIE_Sodium_Core32_Int64 $h4
* @var ParagonIE_Sodium_Core32_Int64 $h5
* @var ParagonIE_Sodium_Core32_Int64 $h6
* @var ParagonIE_Sodium_Core32_Int64 $h7
* @var ParagonIE_Sodium_Core32_Int64 $h8
* @var ParagonIE_Sodium_Core32_Int64 $h9
* @var ParagonIE_Sodium_Core32_Int64 $carry0
* @var ParagonIE_Sodium_Core32_Int64 $carry1
* @var ParagonIE_Sodium_Core32_Int64 $carry2
* @var ParagonIE_Sodium_Core32_Int64 $carry3
* @var ParagonIE_Sodium_Core32_Int64 $carry4
* @var ParagonIE_Sodium_Core32_Int64 $carry5
* @var ParagonIE_Sodium_Core32_Int64 $carry6
* @var ParagonIE_Sodium_Core32_Int64 $carry7
* @var ParagonIE_Sodium_Core32_Int64 $carry8
* @var ParagonIE_Sodium_Core32_Int64 $carry9
*/
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry1 = $h1->addInt(1 << 24)->shiftRight(25);
$h2 = $h2->addInt64($carry1);
$h1 = $h1->subInt64($carry1->shiftLeft(25));
$carry5 = $h5->addInt(1 << 24)->shiftRight(25);
$h6 = $h6->addInt64($carry5);
$h5 = $h5->subInt64($carry5->shiftLeft(25));
$carry2 = $h2->addInt(1 << 25)->shiftRight(26);
$h3 = $h3->addInt64($carry2);
$h2 = $h2->subInt64($carry2->shiftLeft(26));
$carry6 = $h6->addInt(1 << 25)->shiftRight(26);
$h7 = $h7->addInt64($carry6);
$h6 = $h6->subInt64($carry6->shiftLeft(26));
$carry3 = $h3->addInt(1 << 24)->shiftRight(25);
$h4 = $h4->addInt64($carry3);
$h3 = $h3->subInt64($carry3->shiftLeft(25));
$carry7 = $h7->addInt(1 << 24)->shiftRight(25);
$h8 = $h8->addInt64($carry7);
$h7 = $h7->subInt64($carry7->shiftLeft(25));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry8 = $h8->addInt(1 << 25)->shiftRight(26);
$h9 = $h9->addInt64($carry8);
$h8 = $h8->subInt64($carry8->shiftLeft(26));
$carry9 = $h9->addInt(1 << 24)->shiftRight(25);
$h0 = $h0->addInt64($carry9->mulInt(19, 5));
$h9 = $h9->subInt64($carry9->shiftLeft(25));
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
$h0->toInt32(),
$h1->toInt32(),
$h2->toInt32(),
$h3->toInt32(),
$h4->toInt32(),
$h5->toInt32(),
$h6->toInt32(),
$h7->toInt32(),
$h8->toInt32(),
$h9->toInt32()
)
);
}
/**
* Get the negative values for each piece of the field element.
*
* h = -f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_neg(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
$h = new ParagonIE_Sodium_Core32_Curve25519_Fe();
for ($i = 0; $i < 10; ++$i) {
$h[$i] = $h[$i]->subInt32($f[$i]);
}
return $h;
}
/**
* Square a field element
*
* h = f * f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
*/
public static function fe_sq(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
/** @var ParagonIE_Sodium_Core32_Int64 $f0 */
$f0 = $f[0]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f1 */
$f1 = $f[1]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f2 */
$f2 = $f[2]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f3 */
$f3 = $f[3]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f4 */
$f4 = $f[4]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f5 */
$f5 = $f[5]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f6 */
$f6 = $f[6]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f7 */
$f7 = $f[7]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f8 */
$f8 = $f[8]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f9 */
$f9 = $f[9]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f0_2 */
$f0_2 = $f0->shiftLeft(1);
$f1_2 = $f1->shiftLeft(1);
$f2_2 = $f2->shiftLeft(1);
$f3_2 = $f3->shiftLeft(1);
$f4_2 = $f4->shiftLeft(1);
$f5_2 = $f5->shiftLeft(1);
$f6_2 = $f6->shiftLeft(1);
$f7_2 = $f7->shiftLeft(1);
$f5_38 = $f5->mulInt(38, 6);
$f6_19 = $f6->mulInt(19, 5);
$f7_38 = $f7->mulInt(38, 6);
$f8_19 = $f8->mulInt(19, 5);
$f9_38 = $f9->mulInt(38, 6);
/** @var ParagonIE_Sodium_Core32_Int64 $f0f0*/
$f0f0 = $f0->mulInt64($f0, 28);
$f0f1_2 = $f0_2->mulInt64($f1, 28);
$f0f2_2 = $f0_2->mulInt64($f2, 28);
$f0f3_2 = $f0_2->mulInt64($f3, 28);
$f0f4_2 = $f0_2->mulInt64($f4, 28);
$f0f5_2 = $f0_2->mulInt64($f5, 28);
$f0f6_2 = $f0_2->mulInt64($f6, 28);
$f0f7_2 = $f0_2->mulInt64($f7, 28);
$f0f8_2 = $f0_2->mulInt64($f8, 28);
$f0f9_2 = $f0_2->mulInt64($f9, 28);
$f1f1_2 = $f1_2->mulInt64($f1, 28);
$f1f2_2 = $f1_2->mulInt64($f2, 28);
$f1f3_4 = $f1_2->mulInt64($f3_2, 28);
$f1f4_2 = $f1_2->mulInt64($f4, 28);
$f1f5_4 = $f1_2->mulInt64($f5_2, 30);
$f1f6_2 = $f1_2->mulInt64($f6, 28);
$f1f7_4 = $f1_2->mulInt64($f7_2, 28);
$f1f8_2 = $f1_2->mulInt64($f8, 28);
$f1f9_76 = $f9_38->mulInt64($f1_2, 30);
$f2f2 = $f2->mulInt64($f2, 28);
$f2f3_2 = $f2_2->mulInt64($f3, 28);
$f2f4_2 = $f2_2->mulInt64($f4, 28);
$f2f5_2 = $f2_2->mulInt64($f5, 28);
$f2f6_2 = $f2_2->mulInt64($f6, 28);
$f2f7_2 = $f2_2->mulInt64($f7, 28);
$f2f8_38 = $f8_19->mulInt64($f2_2, 30);
$f2f9_38 = $f9_38->mulInt64($f2, 30);
$f3f3_2 = $f3_2->mulInt64($f3, 28);
$f3f4_2 = $f3_2->mulInt64($f4, 28);
$f3f5_4 = $f3_2->mulInt64($f5_2, 30);
$f3f6_2 = $f3_2->mulInt64($f6, 28);
$f3f7_76 = $f7_38->mulInt64($f3_2, 30);
$f3f8_38 = $f8_19->mulInt64($f3_2, 30);
$f3f9_76 = $f9_38->mulInt64($f3_2, 30);
$f4f4 = $f4->mulInt64($f4, 28);
$f4f5_2 = $f4_2->mulInt64($f5, 28);
$f4f6_38 = $f6_19->mulInt64($f4_2, 30);
$f4f7_38 = $f7_38->mulInt64($f4, 30);
$f4f8_38 = $f8_19->mulInt64($f4_2, 30);
$f4f9_38 = $f9_38->mulInt64($f4, 30);
$f5f5_38 = $f5_38->mulInt64($f5, 30);
$f5f6_38 = $f6_19->mulInt64($f5_2, 30);
$f5f7_76 = $f7_38->mulInt64($f5_2, 30);
$f5f8_38 = $f8_19->mulInt64($f5_2, 30);
$f5f9_76 = $f9_38->mulInt64($f5_2, 30);
$f6f6_19 = $f6_19->mulInt64($f6, 30);
$f6f7_38 = $f7_38->mulInt64($f6, 30);
$f6f8_38 = $f8_19->mulInt64($f6_2, 30);
$f6f9_38 = $f9_38->mulInt64($f6, 30);
$f7f7_38 = $f7_38->mulInt64($f7, 28);
$f7f8_38 = $f8_19->mulInt64($f7_2, 30);
$f7f9_76 = $f9_38->mulInt64($f7_2, 30);
$f8f8_19 = $f8_19->mulInt64($f8, 30);
$f8f9_38 = $f9_38->mulInt64($f8, 30);
$f9f9_38 = $f9_38->mulInt64($f9, 28);
$h0 =
$f0f0->addInt64($f1f9_76)->addInt64($f2f8_38)->addInt64($f3f7_76)->addInt64($f4f6_38)->addInt64($f5f5_38);
$h1 =
$f0f1_2->addInt64($f2f9_38)->addInt64($f3f8_38)->addInt64($f4f7_38)->addInt64($f5f6_38);
$h2 =
$f0f2_2->addInt64($f1f1_2)->addInt64($f3f9_76)->addInt64($f4f8_38)->addInt64($f5f7_76)->addInt64($f6f6_19);
$h3 =
$f0f3_2->addInt64($f1f2_2)->addInt64($f4f9_38)->addInt64($f5f8_38)->addInt64($f6f7_38);
$h4 =
$f0f4_2->addInt64($f1f3_4)->addInt64($f2f2)->addInt64($f5f9_76)->addInt64($f6f8_38)->addInt64($f7f7_38);
$h5 =
$f0f5_2->addInt64($f1f4_2)->addInt64($f2f3_2)->addInt64($f6f9_38)->addInt64($f7f8_38);
$h6 =
$f0f6_2->addInt64($f1f5_4)->addInt64($f2f4_2)->addInt64($f3f3_2)->addInt64($f7f9_76)->addInt64($f8f8_19);
$h7 =
$f0f7_2->addInt64($f1f6_2)->addInt64($f2f5_2)->addInt64($f3f4_2)->addInt64($f8f9_38);
$h8 =
$f0f8_2->addInt64($f1f7_4)->addInt64($f2f6_2)->addInt64($f3f5_4)->addInt64($f4f4)->addInt64($f9f9_38);
$h9 =
$f0f9_2->addInt64($f1f8_2)->addInt64($f2f7_2)->addInt64($f3f6_2)->addInt64($f4f5_2);
/**
* @var ParagonIE_Sodium_Core32_Int64 $h0
* @var ParagonIE_Sodium_Core32_Int64 $h1
* @var ParagonIE_Sodium_Core32_Int64 $h2
* @var ParagonIE_Sodium_Core32_Int64 $h3
* @var ParagonIE_Sodium_Core32_Int64 $h4
* @var ParagonIE_Sodium_Core32_Int64 $h5
* @var ParagonIE_Sodium_Core32_Int64 $h6
* @var ParagonIE_Sodium_Core32_Int64 $h7
* @var ParagonIE_Sodium_Core32_Int64 $h8
* @var ParagonIE_Sodium_Core32_Int64 $h9
*/
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry1 = $h1->addInt(1 << 24)->shiftRight(25);
$h2 = $h2->addInt64($carry1);
$h1 = $h1->subInt64($carry1->shiftLeft(25));
$carry5 = $h5->addInt(1 << 24)->shiftRight(25);
$h6 = $h6->addInt64($carry5);
$h5 = $h5->subInt64($carry5->shiftLeft(25));
$carry2 = $h2->addInt(1 << 25)->shiftRight(26);
$h3 = $h3->addInt64($carry2);
$h2 = $h2->subInt64($carry2->shiftLeft(26));
$carry6 = $h6->addInt(1 << 25)->shiftRight(26);
$h7 = $h7->addInt64($carry6);
$h6 = $h6->subInt64($carry6->shiftLeft(26));
$carry3 = $h3->addInt(1 << 24)->shiftRight(25);
$h4 = $h4->addInt64($carry3);
$h3 = $h3->subInt64($carry3->shiftLeft(25));
$carry7 = $h7->addInt(1 << 24)->shiftRight(25);
$h8 = $h8->addInt64($carry7);
$h7 = $h7->subInt64($carry7->shiftLeft(25));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry8 = $h8->addInt(1 << 25)->shiftRight(26);
$h9 = $h9->addInt64($carry8);
$h8 = $h8->subInt64($carry8->shiftLeft(26));
$carry9 = $h9->addInt(1 << 24)->shiftRight(25);
$h0 = $h0->addInt64($carry9->mulInt(19, 5));
$h9 = $h9->subInt64($carry9->shiftLeft(25));
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
$h0->toInt32(),
$h1->toInt32(),
$h2->toInt32(),
$h3->toInt32(),
$h4->toInt32(),
$h5->toInt32(),
$h6->toInt32(),
$h7->toInt32(),
$h8->toInt32(),
$h9->toInt32()
)
);
}
/**
* Square and double a field element
*
* h = 2 * f * f
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
*/
public static function fe_sq2(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
/** @var ParagonIE_Sodium_Core32_Int64 $f0 */
$f0 = $f[0]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f1 */
$f1 = $f[1]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f2 */
$f2 = $f[2]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f3 */
$f3 = $f[3]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f4 */
$f4 = $f[4]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f5 */
$f5 = $f[5]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f6 */
$f6 = $f[6]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f7 */
$f7 = $f[7]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f8 */
$f8 = $f[8]->toInt64();
/** @var ParagonIE_Sodium_Core32_Int64 $f9 */
$f9 = $f[9]->toInt64();
$f0_2 = $f0->shiftLeft(1);
$f1_2 = $f1->shiftLeft(1);
$f2_2 = $f2->shiftLeft(1);
$f3_2 = $f3->shiftLeft(1);
$f4_2 = $f4->shiftLeft(1);
$f5_2 = $f5->shiftLeft(1);
$f6_2 = $f6->shiftLeft(1);
$f7_2 = $f7->shiftLeft(1);
$f5_38 = $f5->mulInt(38, 6); /* 1.959375*2^30 */
$f6_19 = $f6->mulInt(19, 5); /* 1.959375*2^30 */
$f7_38 = $f7->mulInt(38, 6); /* 1.959375*2^30 */
$f8_19 = $f8->mulInt(19, 5); /* 1.959375*2^30 */
$f9_38 = $f9->mulInt(38, 6); /* 1.959375*2^30 */
$f0f0 = $f0->mulInt64($f0, 28);
$f0f1_2 = $f0_2->mulInt64($f1, 28);
$f0f2_2 = $f0_2->mulInt64($f2, 28);
$f0f3_2 = $f0_2->mulInt64($f3, 28);
$f0f4_2 = $f0_2->mulInt64($f4, 28);
$f0f5_2 = $f0_2->mulInt64($f5, 28);
$f0f6_2 = $f0_2->mulInt64($f6, 28);
$f0f7_2 = $f0_2->mulInt64($f7, 28);
$f0f8_2 = $f0_2->mulInt64($f8, 28);
$f0f9_2 = $f0_2->mulInt64($f9, 28);
$f1f1_2 = $f1_2->mulInt64($f1, 28);
$f1f2_2 = $f1_2->mulInt64($f2, 28);
$f1f3_4 = $f1_2->mulInt64($f3_2, 29);
$f1f4_2 = $f1_2->mulInt64($f4, 28);
$f1f5_4 = $f1_2->mulInt64($f5_2, 29);
$f1f6_2 = $f1_2->mulInt64($f6, 28);
$f1f7_4 = $f1_2->mulInt64($f7_2, 29);
$f1f8_2 = $f1_2->mulInt64($f8, 28);
$f1f9_76 = $f9_38->mulInt64($f1_2, 29);
$f2f2 = $f2->mulInt64($f2, 28);
$f2f3_2 = $f2_2->mulInt64($f3, 28);
$f2f4_2 = $f2_2->mulInt64($f4, 28);
$f2f5_2 = $f2_2->mulInt64($f5, 28);
$f2f6_2 = $f2_2->mulInt64($f6, 28);
$f2f7_2 = $f2_2->mulInt64($f7, 28);
$f2f8_38 = $f8_19->mulInt64($f2_2, 29);
$f2f9_38 = $f9_38->mulInt64($f2, 29);
$f3f3_2 = $f3_2->mulInt64($f3, 28);
$f3f4_2 = $f3_2->mulInt64($f4, 28);
$f3f5_4 = $f3_2->mulInt64($f5_2, 28);
$f3f6_2 = $f3_2->mulInt64($f6, 28);
$f3f7_76 = $f7_38->mulInt64($f3_2, 29);
$f3f8_38 = $f8_19->mulInt64($f3_2, 29);
$f3f9_76 = $f9_38->mulInt64($f3_2, 29);
$f4f4 = $f4->mulInt64($f4, 28);
$f4f5_2 = $f4_2->mulInt64($f5, 28);
$f4f6_38 = $f6_19->mulInt64($f4_2, 29);
$f4f7_38 = $f7_38->mulInt64($f4, 29);
$f4f8_38 = $f8_19->mulInt64($f4_2, 29);
$f4f9_38 = $f9_38->mulInt64($f4, 29);
$f5f5_38 = $f5_38->mulInt64($f5, 29);
$f5f6_38 = $f6_19->mulInt64($f5_2, 29);
$f5f7_76 = $f7_38->mulInt64($f5_2, 29);
$f5f8_38 = $f8_19->mulInt64($f5_2, 29);
$f5f9_76 = $f9_38->mulInt64($f5_2, 29);
$f6f6_19 = $f6_19->mulInt64($f6, 29);
$f6f7_38 = $f7_38->mulInt64($f6, 29);
$f6f8_38 = $f8_19->mulInt64($f6_2, 29);
$f6f9_38 = $f9_38->mulInt64($f6, 29);
$f7f7_38 = $f7_38->mulInt64($f7, 29);
$f7f8_38 = $f8_19->mulInt64($f7_2, 29);
$f7f9_76 = $f9_38->mulInt64($f7_2, 29);
$f8f8_19 = $f8_19->mulInt64($f8, 29);
$f8f9_38 = $f9_38->mulInt64($f8, 29);
$f9f9_38 = $f9_38->mulInt64($f9, 29);
$h0 =
$f0f0->addInt64($f1f9_76)->addInt64($f2f8_38)->addInt64($f3f7_76)->addInt64($f4f6_38)->addInt64($f5f5_38);
$h1 =
$f0f1_2->addInt64($f2f9_38)->addInt64($f3f8_38)->addInt64($f4f7_38)->addInt64($f5f6_38);
$h2 =
$f0f2_2->addInt64($f1f1_2)->addInt64($f3f9_76)->addInt64($f4f8_38)->addInt64($f5f7_76)->addInt64($f6f6_19);
$h3 =
$f0f3_2->addInt64($f1f2_2)->addInt64($f4f9_38)->addInt64($f5f8_38)->addInt64($f6f7_38);
$h4 =
$f0f4_2->addInt64($f1f3_4)->addInt64($f2f2)->addInt64($f5f9_76)->addInt64($f6f8_38)->addInt64($f7f7_38);
$h5 =
$f0f5_2->addInt64($f1f4_2)->addInt64($f2f3_2)->addInt64($f6f9_38)->addInt64($f7f8_38);
$h6 =
$f0f6_2->addInt64($f1f5_4)->addInt64($f2f4_2)->addInt64($f3f3_2)->addInt64($f7f9_76)->addInt64($f8f8_19);
$h7 =
$f0f7_2->addInt64($f1f6_2)->addInt64($f2f5_2)->addInt64($f3f4_2)->addInt64($f8f9_38);
$h8 =
$f0f8_2->addInt64($f1f7_4)->addInt64($f2f6_2)->addInt64($f3f5_4)->addInt64($f4f4)->addInt64($f9f9_38);
$h9 =
$f0f9_2->addInt64($f1f8_2)->addInt64($f2f7_2)->addInt64($f3f6_2)->addInt64($f4f5_2);
/**
* @var ParagonIE_Sodium_Core32_Int64 $h0
* @var ParagonIE_Sodium_Core32_Int64 $h1
* @var ParagonIE_Sodium_Core32_Int64 $h2
* @var ParagonIE_Sodium_Core32_Int64 $h3
* @var ParagonIE_Sodium_Core32_Int64 $h4
* @var ParagonIE_Sodium_Core32_Int64 $h5
* @var ParagonIE_Sodium_Core32_Int64 $h6
* @var ParagonIE_Sodium_Core32_Int64 $h7
* @var ParagonIE_Sodium_Core32_Int64 $h8
* @var ParagonIE_Sodium_Core32_Int64 $h9
*/
$h0 = $h0->shiftLeft(1);
$h1 = $h1->shiftLeft(1);
$h2 = $h2->shiftLeft(1);
$h3 = $h3->shiftLeft(1);
$h4 = $h4->shiftLeft(1);
$h5 = $h5->shiftLeft(1);
$h6 = $h6->shiftLeft(1);
$h7 = $h7->shiftLeft(1);
$h8 = $h8->shiftLeft(1);
$h9 = $h9->shiftLeft(1);
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry1 = $h1->addInt(1 << 24)->shiftRight(25);
$h2 = $h2->addInt64($carry1);
$h1 = $h1->subInt64($carry1->shiftLeft(25));
$carry5 = $h5->addInt(1 << 24)->shiftRight(25);
$h6 = $h6->addInt64($carry5);
$h5 = $h5->subInt64($carry5->shiftLeft(25));
$carry2 = $h2->addInt(1 << 25)->shiftRight(26);
$h3 = $h3->addInt64($carry2);
$h2 = $h2->subInt64($carry2->shiftLeft(26));
$carry6 = $h6->addInt(1 << 25)->shiftRight(26);
$h7 = $h7->addInt64($carry6);
$h6 = $h6->subInt64($carry6->shiftLeft(26));
$carry3 = $h3->addInt(1 << 24)->shiftRight(25);
$h4 = $h4->addInt64($carry3);
$h3 = $h3->subInt64($carry3->shiftLeft(25));
$carry7 = $h7->addInt(1 << 24)->shiftRight(25);
$h8 = $h8->addInt64($carry7);
$h7 = $h7->subInt64($carry7->shiftLeft(25));
$carry4 = $h4->addInt(1 << 25)->shiftRight(26);
$h5 = $h5->addInt64($carry4);
$h4 = $h4->subInt64($carry4->shiftLeft(26));
$carry8 = $h8->addInt(1 << 25)->shiftRight(26);
$h9 = $h9->addInt64($carry8);
$h8 = $h8->subInt64($carry8->shiftLeft(26));
$carry9 = $h9->addInt(1 << 24)->shiftRight(25);
$h0 = $h0->addInt64($carry9->mulInt(19, 5));
$h9 = $h9->subInt64($carry9->shiftLeft(25));
$carry0 = $h0->addInt(1 << 25)->shiftRight(26);
$h1 = $h1->addInt64($carry0);
$h0 = $h0->subInt64($carry0->shiftLeft(26));
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
$h0->toInt32(),
$h1->toInt32(),
$h2->toInt32(),
$h3->toInt32(),
$h4->toInt32(),
$h5->toInt32(),
$h6->toInt32(),
$h7->toInt32(),
$h8->toInt32(),
$h9->toInt32()
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $Z
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function fe_invert(ParagonIE_Sodium_Core32_Curve25519_Fe
$Z)
{
$z = clone $Z;
$t0 = self::fe_sq($z);
$t1 = self::fe_sq($t0);
$t1 = self::fe_sq($t1);
$t1 = self::fe_mul($z, $t1);
$t0 = self::fe_mul($t0, $t1);
$t2 = self::fe_sq($t0);
$t1 = self::fe_mul($t1, $t2);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 5; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 10; ++$i) {
$t2 = self::fe_sq($t2);
}
$t2 = self::fe_mul($t2, $t1);
$t3 = self::fe_sq($t2);
for ($i = 1; $i < 20; ++$i) {
$t3 = self::fe_sq($t3);
}
$t2 = self::fe_mul($t3, $t2);
$t2 = self::fe_sq($t2);
for ($i = 1; $i < 10; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t2 = self::fe_sq($t1);
for ($i = 1; $i < 50; ++$i) {
$t2 = self::fe_sq($t2);
}
$t2 = self::fe_mul($t2, $t1);
$t3 = self::fe_sq($t2);
for ($i = 1; $i < 100; ++$i) {
$t3 = self::fe_sq($t3);
}
$t2 = self::fe_mul($t3, $t2);
$t2 = self::fe_sq($t2);
for ($i = 1; $i < 50; ++$i) {
$t2 = self::fe_sq($t2);
}
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
for ($i = 1; $i < 5; ++$i) {
$t1 = self::fe_sq($t1);
}
return self::fe_mul($t1, $t0);
}
/**
* @internal You should not use this directly from another application
*
* @ref
https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $z
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function
fe_pow22523(ParagonIE_Sodium_Core32_Curve25519_Fe $z)
{
# fe_sq(t0, z);
# fe_sq(t1, t0);
# fe_sq(t1, t1);
# fe_mul(t1, z, t1);
# fe_mul(t0, t0, t1);
# fe_sq(t0, t0);
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_sq($z);
$t1 = self::fe_sq($t0);
$t1 = self::fe_sq($t1);
$t1 = self::fe_mul($z, $t1);
$t0 = self::fe_mul($t0, $t1);
$t0 = self::fe_sq($t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 5; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 5; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 10; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 10; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t1, t1, t0);
# fe_sq(t2, t1);
$t1 = self::fe_mul($t1, $t0);
$t2 = self::fe_sq($t1);
# for (i = 1; i < 20; ++i) {
# fe_sq(t2, t2);
# }
for ($i = 1; $i < 20; ++$i) {
$t2 = self::fe_sq($t2);
}
# fe_mul(t1, t2, t1);
# fe_sq(t1, t1);
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
# for (i = 1; i < 10; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 10; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t1, t0);
$t0 = self::fe_mul($t1, $t0);
$t1 = self::fe_sq($t0);
# for (i = 1; i < 50; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 50; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t1, t1, t0);
# fe_sq(t2, t1);
$t1 = self::fe_mul($t1, $t0);
$t2 = self::fe_sq($t1);
# for (i = 1; i < 100; ++i) {
# fe_sq(t2, t2);
# }
for ($i = 1; $i < 100; ++$i) {
$t2 = self::fe_sq($t2);
}
# fe_mul(t1, t2, t1);
# fe_sq(t1, t1);
$t1 = self::fe_mul($t2, $t1);
$t1 = self::fe_sq($t1);
# for (i = 1; i < 50; ++i) {
# fe_sq(t1, t1);
# }
for ($i = 1; $i < 50; ++$i) {
$t1 = self::fe_sq($t1);
}
# fe_mul(t0, t1, t0);
# fe_sq(t0, t0);
# fe_sq(t0, t0);
# fe_mul(out, t0, z);
$t0 = self::fe_mul($t1, $t0);
$t0 = self::fe_sq($t0);
$t0 = self::fe_sq($t0);
return self::fe_mul($t0, $z);
}
/**
* Subtract two field elements.
*
* h = f - g
*
* Preconditions:
* |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
* |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
*
* Postconditions:
* |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedTypeCoercion
*/
public static function fe_sub(ParagonIE_Sodium_Core32_Curve25519_Fe $f,
ParagonIE_Sodium_Core32_Curve25519_Fe $g)
{
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
$f[0]->subInt32($g[0]),
$f[1]->subInt32($g[1]),
$f[2]->subInt32($g[2]),
$f[3]->subInt32($g[3]),
$f[4]->subInt32($g[4]),
$f[5]->subInt32($g[5]),
$f[6]->subInt32($g[6]),
$f[7]->subInt32($g[7]),
$f[8]->subInt32($g[8]),
$f[9]->subInt32($g[9])
)
);
}
/**
* Add two group elements.
*
* r = p + q
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_add(
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
) {
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->YplusX);
$r->Y = self::fe_mul($r->Y, $q->YminusX);
$r->T = self::fe_mul($q->T2d, $p->T);
$r->X = self::fe_mul($p->Z, $q->Z);
$t0 = self::fe_add($r->X, $r->X);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_add($t0, $r->T);
$r->T = self::fe_sub($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @ref
https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
* @param string $a
* @return array<int, mixed>
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayOffset
*/
public static function slide($a)
{
if (self::strlen($a) < 256) {
if (self::strlen($a) < 16) {
$a = str_pad($a, 256, '0', STR_PAD_RIGHT);
}
}
/** @var array<int, int> $r */
$r = array();
for ($i = 0; $i < 256; ++$i) {
$r[$i] = (int) (1 &
(
self::chrToInt($a[$i >> 3])
>>
($i & 7)
)
);
}
for ($i = 0;$i < 256;++$i) {
if ($r[$i]) {
for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
if ($r[$i + $b]) {
if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
$r[$i] += $r[$i + $b] << $b;
$r[$i + $b] = 0;
} elseif ($r[$i] - ($r[$i + $b] << $b) >=
-15) {
$r[$i] -= $r[$i + $b] << $b;
for ($k = $i + $b; $k < 256; ++$k) {
if (!$r[$k]) {
$r[$k] = 1;
break;
}
$r[$k] = 0;
}
} else {
break;
}
}
}
}
}
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param string $s
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function ge_frombytes_negate_vartime($s)
{
static $d = null;
if (!$d) {
/** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d */
$d = ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[9])
)
);
}
# fe_frombytes(h->Y,s);
# fe_1(h->Z);
$h = new ParagonIE_Sodium_Core32_Curve25519_Ge_P3(
self::fe_0(),
self::fe_frombytes($s),
self::fe_1()
);
# fe_sq(u,h->Y);
# fe_mul(v,u,d);
# fe_sub(u,u,h->Z); /* u = y^2-1 */
# fe_add(v,v,h->Z); /* v = dy^2+1 */
$u = self::fe_sq($h->Y);
/** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d */
$v = self::fe_mul($u, $d);
$u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */
$v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */
# fe_sq(v3,v);
# fe_mul(v3,v3,v); /* v3 = v^3 */
# fe_sq(h->X,v3);
# fe_mul(h->X,h->X,v);
# fe_mul(h->X,h->X,u); /* x = uv^7 */
$v3 = self::fe_sq($v);
$v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
$h->X = self::fe_sq($v3);
$h->X = self::fe_mul($h->X, $v);
$h->X = self::fe_mul($h->X, $u); /* x = uv^7 */
# fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
# fe_mul(h->X,h->X,v3);
# fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */
$h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
$h->X = self::fe_mul($h->X, $v3);
$h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8)
*/
# fe_sq(vxx,h->X);
# fe_mul(vxx,vxx,v);
# fe_sub(check,vxx,u); /* vx^2-u */
$vxx = self::fe_sq($h->X);
$vxx = self::fe_mul($vxx, $v);
$check = self::fe_sub($vxx, $u); /* vx^2 - u */
# if (fe_isnonzero(check)) {
# fe_add(check,vxx,u); /* vx^2+u */
# if (fe_isnonzero(check)) {
# return -1;
# }
# fe_mul(h->X,h->X,sqrtm1);
# }
if (self::fe_isnonzero($check)) {
$check = self::fe_add($vxx, $u); /* vx^2 + u */
if (self::fe_isnonzero($check)) {
throw new RangeException('Internal check
failed.');
}
$h->X = self::fe_mul(
$h->X,
ParagonIE_Sodium_Core32_Curve25519_Fe::fromIntArray(self::$sqrtm1)
);
}
# if (fe_isnegative(h->X) == (s[31] >> 7)) {
# fe_neg(h->X,h->X);
# }
$i = self::chrToInt($s[31]);
if (self::fe_isnegative($h->X) === ($i >> 7)) {
$h->X = self::fe_neg($h->X);
}
# fe_mul(h->T,h->X,h->Y);
$h->T = self::fe_mul($h->X, $h->Y);
return $h;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_madd(
ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R,
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
) {
$r = clone $R;
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->yplusx);
$r->Y = self::fe_mul($r->Y, $q->yminusx);
$r->T = self::fe_mul($q->xy2d, $p->T);
$t0 = self::fe_add(clone $p->Z, clone $p->Z);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_add($t0, $r->T);
$r->T = self::fe_sub($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_msub(
ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R,
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q
) {
$r = clone $R;
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->yminusx);
$r->Y = self::fe_mul($r->Y, $q->yplusx);
$r->T = self::fe_mul($q->xy2d, $p->T);
$t0 = self::fe_add($p->Z, $p->Z);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_sub($t0, $r->T);
$r->T = self::fe_add($t0, $r->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_p1p1_to_p2(ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p)
{
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P2();
$r->X = self::fe_mul($p->X, $p->T);
$r->Y = self::fe_mul($p->Y, $p->Z);
$r->Z = self::fe_mul($p->Z, $p->T);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_p1p1_to_p3(ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p)
{
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P3();
$r->X = self::fe_mul($p->X, $p->T);
$r->Y = self::fe_mul($p->Y, $p->Z);
$r->Z = self::fe_mul($p->Z, $p->T);
$r->T = self::fe_mul($p->X, $p->Y);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p2_0()
{
return new ParagonIE_Sodium_Core32_Curve25519_Ge_P2(
self::fe_0(),
self::fe_1(),
self::fe_1()
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_p2_dbl(ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $p)
{
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
$r->X = self::fe_sq($p->X);
$r->Z = self::fe_sq($p->Y);
$r->T = self::fe_sq2($p->Z);
$r->Y = self::fe_add($p->X, $p->Y);
$t0 = self::fe_sq($r->Y);
$r->Y = self::fe_add($r->Z, $r->X);
$r->Z = self::fe_sub($r->Z, $r->X);
$r->X = self::fe_sub($t0, $r->Y);
$r->T = self::fe_sub($r->T, $r->Z);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function ge_p3_0()
{
return new ParagonIE_Sodium_Core32_Curve25519_Ge_P3(
self::fe_0(),
self::fe_1(),
self::fe_1(),
self::fe_0()
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_p3_to_cached(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p)
{
static $d2 = null;
if ($d2 === null) {
$d2 = ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[9])
)
);
}
/** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d2 */
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_Cached();
$r->YplusX = self::fe_add($p->Y, $p->X);
$r->YminusX = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_copy($p->Z);
$r->T2d = self::fe_mul($p->T, $d2);
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
*/
public static function
ge_p3_to_p2(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p)
{
return new ParagonIE_Sodium_Core32_Curve25519_Ge_P2(
$p->X,
$p->Y,
$p->Z
);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $h
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_p3_tobytes(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $h)
{
$recip = self::fe_invert($h->Z);
$x = self::fe_mul($h->X, $recip);
$y = self::fe_mul($h->Y, $recip);
$s = self::fe_tobytes($y);
$s[31] = self::intToChr(
self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
);
return $s;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_p3_dbl(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p)
{
$q = self::ge_p3_to_p2($p);
return self::ge_p2_dbl($q);
}
/**
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
* @throws SodiumException
* @throws TypeError
*/
public static function ge_precomp_0()
{
return new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
self::fe_1(),
self::fe_1(),
self::fe_0()
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $b
* @param int $c
* @return int
* @psalm-suppress MixedReturnStatement
*/
public static function equal($b, $c)
{
return (int) ((($b ^ $c) - 1 & 0xffffffff) >> 31);
}
/**
* @internal You should not use this directly from another application
*
* @param string|int $char
* @return int (1 = yes, 0 = no)
* @throws SodiumException
* @throws TypeError
*/
public static function negative($char)
{
if (is_int($char)) {
return $char < 0 ? 1 : 0;
}
/** @var string $char */
/** @var int $x */
$x = self::chrToInt(self::substr($char, 0, 1));
return (int) ($x >> 31);
}
/**
* Conditional move
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $t
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $u
* @param int $b
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
* @throws SodiumException
* @throws TypeError
*/
public static function cmov(
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $t,
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $u,
$b
) {
if (!is_int($b)) {
throw new InvalidArgumentException('Expected an
integer.');
}
return new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
self::fe_cmov($t->yplusx, $u->yplusx, $b),
self::fe_cmov($t->yminusx, $u->yminusx, $b),
self::fe_cmov($t->xy2d, $u->xy2d, $b)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $pos
* @param int $b
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedArgument
*/
public static function ge_select($pos = 0, $b = 0)
{
static $base = null;
if ($base === null) {
$base = array();
foreach (self::$base as $i => $bas) {
for ($j = 0; $j < 8; ++$j) {
$base[$i][$j] = new
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][0]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][1]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][2]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][3]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][4]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][5]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][6]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][7]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][8]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][9])
)
),
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][0]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][1]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][2]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][3]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][4]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][5]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][6]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][7]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][8]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][9])
)
),
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][0]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][1]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][2]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][3]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][4]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][5]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][6]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][7]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][8]),
ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][9])
)
)
);
}
}
}
if (!is_int($pos)) {
throw new InvalidArgumentException('Position must be an
integer');
}
if ($pos < 0 || $pos > 31) {
throw new RangeException('Position is out of range [0,
31]');
}
$bnegative = self::negative($b);
/** @var int $babs */
$babs = $b - (((-$bnegative) & $b) << 1);
$t = self::ge_precomp_0();
for ($i = 0; $i < 8; ++$i) {
$t = self::cmov(
$t,
$base[$pos][$i],
self::equal($babs, $i + 1)
);
}
$minusT = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
self::fe_copy($t->yminusx),
self::fe_copy($t->yplusx),
self::fe_neg($t->xy2d)
);
return self::cmov($t, $minusT, -$bnegative);
}
/**
* Subtract two group elements.
*
* r = p - q
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
* @throws SodiumException
* @throws TypeError
*/
public static function ge_sub(
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p,
ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q
) {
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
$r->X = self::fe_add($p->Y, $p->X);
$r->Y = self::fe_sub($p->Y, $p->X);
$r->Z = self::fe_mul($r->X, $q->YminusX);
$r->Y = self::fe_mul($r->Y, $q->YplusX);
$r->T = self::fe_mul($q->T2d, $p->T);
$r->X = self::fe_mul($p->Z, $q->Z);
$t0 = self::fe_add($r->X, $r->X);
$r->X = self::fe_sub($r->Z, $r->Y);
$r->Y = self::fe_add($r->Z, $r->Y);
$r->Z = self::fe_sub($t0, $r->T);
$r->T = self::fe_add($t0, $r->T);
return $r;
}
/**
* Convert a group element to a byte string.
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $h
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_tobytes(ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $h)
{
$recip = self::fe_invert($h->Z);
$x = self::fe_mul($h->X, $recip);
$y = self::fe_mul($h->Y, $recip);
$s = self::fe_tobytes($y);
$s[31] = self::intToChr(
self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
);
return $s;
}
/**
* @internal You should not use this directly from another application
*
* @param string $a
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A
* @param string $b
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public static function ge_double_scalarmult_vartime(
$a,
ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A,
$b
) {
/** @var array<int,
ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai */
$Ai = array();
static $Bi = array();
/** @var array<int,
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp> $Bi */
if (!$Bi) {
for ($i = 0; $i < 8; ++$i) {
$Bi[$i] = new
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp(
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][9])
)
),
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][9])
)
),
ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray(
array(
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][0]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][1]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][2]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][3]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][4]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][5]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][6]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][7]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][8]),
ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][9])
)
)
);
}
}
for ($i = 0; $i < 8; ++$i) {
$Ai[$i] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Cached(
self::fe_0(),
self::fe_0(),
self::fe_0(),
self::fe_0()
);
}
/** @var array<int,
ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai */
# slide(aslide,a);
# slide(bslide,b);
/** @var array<int, int> $aslide */
$aslide = self::slide($a);
/** @var array<int, int> $bslide */
$bslide = self::slide($b);
# ge_p3_to_cached(&Ai[0],A);
# ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
$Ai[0] = self::ge_p3_to_cached($A);
$t = self::ge_p3_dbl($A);
$A2 = self::ge_p1p1_to_p3($t);
# ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[1],&u);
# ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[2],&u);
# ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[3],&u);
# ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[4],&u);
# ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[5],&u);
# ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[6],&u);
# ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t);
ge_p3_to_cached(&Ai[7],&u);
for ($i = 0; $i < 7; ++$i) {
$t = self::ge_add($A2, $Ai[$i]);
$u = self::ge_p1p1_to_p3($t);
$Ai[$i + 1] = self::ge_p3_to_cached($u);
}
# ge_p2_0(r);
$r = self::ge_p2_0();
# for (i = 255;i >= 0;--i) {
# if (aslide[i] || bslide[i]) break;
# }
$i = 255;
for (; $i >= 0; --$i) {
if ($aslide[$i] || $bslide[$i]) {
break;
}
}
# for (;i >= 0;--i) {
for (; $i >= 0; --$i) {
# ge_p2_dbl(&t,r);
$t = self::ge_p2_dbl($r);
# if (aslide[i] > 0) {
if ($aslide[$i] > 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_add(&t,&u,&Ai[aslide[i]/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_add(
$u,
$Ai[(int) floor($aslide[$i] / 2)]
);
# } else if (aslide[i] < 0) {
} elseif ($aslide[$i] < 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
$u = self::ge_p1p1_to_p3($t);
$t = self::ge_sub(
$u,
$Ai[(int) floor(-$aslide[$i] / 2)]
);
}
/** @var array<int,
ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp> $Bi */
# if (bslide[i] > 0) {
if ($bslide[$i] > 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_madd(&t,&u,&Bi[bslide[i]/2]);
$u = self::ge_p1p1_to_p3($t);
/** @var int $index */
$index = (int) floor($bslide[$i] / 2);
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
$thisB */
$thisB = $Bi[$index];
$t = self::ge_madd($t, $u, $thisB);
# } else if (bslide[i] < 0) {
} elseif ($bslide[$i] < 0) {
# ge_p1p1_to_p3(&u,&t);
# ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
$u = self::ge_p1p1_to_p3($t);
/** @var int $index */
$index = (int) floor(-$bslide[$i] / 2);
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
$thisB */
$thisB = $Bi[$index];
$t = self::ge_msub($t, $u, $thisB);
}
# ge_p1p1_to_p2(r,&t);
$r = self::ge_p1p1_to_p2($t);
}
return $r;
}
/**
* @internal You should not use this directly from another application
*
* @param string $a
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
* @throws SodiumException
* @throws TypeError
*/
public static function ge_scalarmult_base($a)
{
/** @var array<int, int> $e */
$e = array();
$r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1();
for ($i = 0; $i < 32; ++$i) {
/** @var int $dbl */
$dbl = (int) $i << 1;
$e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
$e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) &
15;
}
/** @var int $carry */
$carry = 0;
for ($i = 0; $i < 63; ++$i) {
$e[$i] += $carry;
/** @var int $carry */
$carry = $e[$i] + 8;
/** @var int $carry */
$carry >>= 4;
$e[$i] -= $carry << 4;
}
/** @var array<int, int> $e */
$e[63] += (int) $carry;
$h = self::ge_p3_0();
for ($i = 1; $i < 64; $i += 2) {
$t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
$r = self::ge_madd($r, $h, $t);
$h = self::ge_p1p1_to_p3($r);
}
$r = self::ge_p3_dbl($h);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$s = self::ge_p1p1_to_p2($r);
$r = self::ge_p2_dbl($s);
$h = self::ge_p1p1_to_p3($r);
for ($i = 0; $i < 64; $i += 2) {
$t = self::ge_select($i >> 1, (int) $e[$i]);
$r = self::ge_madd($r, $h, $t);
$h = self::ge_p1p1_to_p3($r);
}
return $h;
}
/**
* Calculates (ab + c) mod l
* where l = 2^252 + 27742317777372353535851937790883648493
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @param string $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sc_muladd($a, $b, $c)
{
$a0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
self::load_3(self::substr($a, 0, 3)));
$a1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($a, 2, 4)) >> 5));
$a2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($a, 5, 3)) >> 2));
$a3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($a, 7, 4)) >> 7));
$a4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($a, 10, 4)) >> 4));
$a5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($a, 13, 3)) >> 1));
$a6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($a, 15, 4)) >> 6));
$a7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($a, 18, 3)) >> 3));
$a8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
self::load_3(self::substr($a, 21, 3)));
$a9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($a, 23, 4)) >> 5));
$a10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($a, 26, 3)) >> 2));
$a11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff &
(self::load_4(self::substr($a, 28, 4)) >> 7));
$b0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
self::load_3(self::substr($b, 0, 3)));
$b1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($b, 2, 4)) >> 5));
$b2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($b, 5, 3)) >> 2));
$b3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($b, 7, 4)) >> 7));
$b4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($b, 10, 4)) >> 4));
$b5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($b, 13, 3)) >> 1));
$b6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($b, 15, 4)) >> 6));
$b7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($b, 18, 3)) >> 3));
$b8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
self::load_3(self::substr($b, 21, 3)));
$b9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($b, 23, 4)) >> 5));
$b10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($b, 26, 3)) >> 2));
$b11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff &
(self::load_4(self::substr($b, 28, 4)) >> 7));
$c0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
self::load_3(self::substr($c, 0, 3)));
$c1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($c, 2, 4)) >> 5));
$c2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($c, 5, 3)) >> 2));
$c3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($c, 7, 4)) >> 7));
$c4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($c, 10, 4)) >> 4));
$c5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($c, 13, 3)) >> 1));
$c6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($c, 15, 4)) >> 6));
$c7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($c, 18, 3)) >> 3));
$c8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
self::load_3(self::substr($c, 21, 3)));
$c9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($c, 23, 4)) >> 5));
$c10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($c, 26, 3)) >> 2));
$c11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff &
(self::load_4(self::substr($c, 28, 4)) >> 7));
/* Can't really avoid the pyramid here: */
/**
* @var ParagonIE_Sodium_Core32_Int64 $s0
* @var ParagonIE_Sodium_Core32_Int64 $s1
* @var ParagonIE_Sodium_Core32_Int64 $s2
* @var ParagonIE_Sodium_Core32_Int64 $s3
* @var ParagonIE_Sodium_Core32_Int64 $s4
* @var ParagonIE_Sodium_Core32_Int64 $s5
* @var ParagonIE_Sodium_Core32_Int64 $s6
* @var ParagonIE_Sodium_Core32_Int64 $s7
* @var ParagonIE_Sodium_Core32_Int64 $s8
* @var ParagonIE_Sodium_Core32_Int64 $s9
* @var ParagonIE_Sodium_Core32_Int64 $s10
* @var ParagonIE_Sodium_Core32_Int64 $s11
* @var ParagonIE_Sodium_Core32_Int64 $s12
* @var ParagonIE_Sodium_Core32_Int64 $s13
* @var ParagonIE_Sodium_Core32_Int64 $s14
* @var ParagonIE_Sodium_Core32_Int64 $s15
* @var ParagonIE_Sodium_Core32_Int64 $s16
* @var ParagonIE_Sodium_Core32_Int64 $s17
* @var ParagonIE_Sodium_Core32_Int64 $s18
* @var ParagonIE_Sodium_Core32_Int64 $s19
* @var ParagonIE_Sodium_Core32_Int64 $s20
* @var ParagonIE_Sodium_Core32_Int64 $s21
* @var ParagonIE_Sodium_Core32_Int64 $s22
* @var ParagonIE_Sodium_Core32_Int64 $s23
*/
$s0 = $c0->addInt64($a0->mulInt64($b0, 24));
$s1 = $c1->addInt64($a0->mulInt64($b1,
24))->addInt64($a1->mulInt64($b0, 24));
$s2 = $c2->addInt64($a0->mulInt64($b2,
24))->addInt64($a1->mulInt64($b1,
24))->addInt64($a2->mulInt64($b0, 24));
$s3 = $c3->addInt64($a0->mulInt64($b3,
24))->addInt64($a1->mulInt64($b2,
24))->addInt64($a2->mulInt64($b1, 24))
->addInt64($a3->mulInt64($b0, 24));
$s4 = $c4->addInt64($a0->mulInt64($b4,
24))->addInt64($a1->mulInt64($b3,
24))->addInt64($a2->mulInt64($b2, 24))
->addInt64($a3->mulInt64($b1,
24))->addInt64($a4->mulInt64($b0, 24));
$s5 = $c5->addInt64($a0->mulInt64($b5,
24))->addInt64($a1->mulInt64($b4,
24))->addInt64($a2->mulInt64($b3, 24))
->addInt64($a3->mulInt64($b2,
24))->addInt64($a4->mulInt64($b1,
24))->addInt64($a5->mulInt64($b0, 24));
$s6 = $c6->addInt64($a0->mulInt64($b6,
24))->addInt64($a1->mulInt64($b5,
24))->addInt64($a2->mulInt64($b4, 24))
->addInt64($a3->mulInt64($b3,
24))->addInt64($a4->mulInt64($b2,
24))->addInt64($a5->mulInt64($b1, 24))
->addInt64($a6->mulInt64($b0, 24));
$s7 = $c7->addInt64($a0->mulInt64($b7,
24))->addInt64($a1->mulInt64($b6,
24))->addInt64($a2->mulInt64($b5, 24))
->addInt64($a3->mulInt64($b4,
24))->addInt64($a4->mulInt64($b3,
24))->addInt64($a5->mulInt64($b2, 24))
->addInt64($a6->mulInt64($b1,
24))->addInt64($a7->mulInt64($b0, 24));
$s8 = $c8->addInt64($a0->mulInt64($b8,
24))->addInt64($a1->mulInt64($b7,
24))->addInt64($a2->mulInt64($b6, 24))
->addInt64($a3->mulInt64($b5,
24))->addInt64($a4->mulInt64($b4,
24))->addInt64($a5->mulInt64($b3, 24))
->addInt64($a6->mulInt64($b2,
24))->addInt64($a7->mulInt64($b1,
24))->addInt64($a8->mulInt64($b0, 24));
$s9 = $c9->addInt64($a0->mulInt64($b9,
24))->addInt64($a1->mulInt64($b8,
24))->addInt64($a2->mulInt64($b7, 24))
->addInt64($a3->mulInt64($b6,
24))->addInt64($a4->mulInt64($b5,
24))->addInt64($a5->mulInt64($b4, 24))
->addInt64($a6->mulInt64($b3,
24))->addInt64($a7->mulInt64($b2,
24))->addInt64($a8->mulInt64($b1, 24))
->addInt64($a9->mulInt64($b0, 24));
$s10 = $c10->addInt64($a0->mulInt64($b10,
24))->addInt64($a1->mulInt64($b9,
24))->addInt64($a2->mulInt64($b8, 24))
->addInt64($a3->mulInt64($b7,
24))->addInt64($a4->mulInt64($b6,
24))->addInt64($a5->mulInt64($b5, 24))
->addInt64($a6->mulInt64($b4,
24))->addInt64($a7->mulInt64($b3,
24))->addInt64($a8->mulInt64($b2, 24))
->addInt64($a9->mulInt64($b1,
24))->addInt64($a10->mulInt64($b0, 24));
$s11 = $c11->addInt64($a0->mulInt64($b11,
24))->addInt64($a1->mulInt64($b10,
24))->addInt64($a2->mulInt64($b9, 24))
->addInt64($a3->mulInt64($b8,
24))->addInt64($a4->mulInt64($b7,
24))->addInt64($a5->mulInt64($b6, 24))
->addInt64($a6->mulInt64($b5,
24))->addInt64($a7->mulInt64($b4,
24))->addInt64($a8->mulInt64($b3, 24))
->addInt64($a9->mulInt64($b2,
24))->addInt64($a10->mulInt64($b1,
24))->addInt64($a11->mulInt64($b0, 24));
$s12 = $a1->mulInt64($b11,
24)->addInt64($a2->mulInt64($b10,
24))->addInt64($a3->mulInt64($b9, 24))
->addInt64($a4->mulInt64($b8,
24))->addInt64($a5->mulInt64($b7,
24))->addInt64($a6->mulInt64($b6, 24))
->addInt64($a7->mulInt64($b5,
24))->addInt64($a8->mulInt64($b4,
24))->addInt64($a9->mulInt64($b3, 24))
->addInt64($a10->mulInt64($b2,
24))->addInt64($a11->mulInt64($b1, 24));
$s13 = $a2->mulInt64($b11,
24)->addInt64($a3->mulInt64($b10,
24))->addInt64($a4->mulInt64($b9, 24))
->addInt64($a5->mulInt64($b8,
24))->addInt64($a6->mulInt64($b7,
24))->addInt64($a7->mulInt64($b6, 24))
->addInt64($a8->mulInt64($b5,
24))->addInt64($a9->mulInt64($b4,
24))->addInt64($a10->mulInt64($b3, 24))
->addInt64($a11->mulInt64($b2, 24));
$s14 = $a3->mulInt64($b11,
24)->addInt64($a4->mulInt64($b10,
24))->addInt64($a5->mulInt64($b9, 24))
->addInt64($a6->mulInt64($b8,
24))->addInt64($a7->mulInt64($b7,
24))->addInt64($a8->mulInt64($b6, 24))
->addInt64($a9->mulInt64($b5,
24))->addInt64($a10->mulInt64($b4,
24))->addInt64($a11->mulInt64($b3, 24));
$s15 = $a4->mulInt64($b11,
24)->addInt64($a5->mulInt64($b10,
24))->addInt64($a6->mulInt64($b9, 24))
->addInt64($a7->mulInt64($b8,
24))->addInt64($a8->mulInt64($b7,
24))->addInt64($a9->mulInt64($b6, 24))
->addInt64($a10->mulInt64($b5,
24))->addInt64($a11->mulInt64($b4, 24));
$s16 = $a5->mulInt64($b11,
24)->addInt64($a6->mulInt64($b10,
24))->addInt64($a7->mulInt64($b9, 24))
->addInt64($a8->mulInt64($b8,
24))->addInt64($a9->mulInt64($b7,
24))->addInt64($a10->mulInt64($b6, 24))
->addInt64($a11->mulInt64($b5, 24));
$s17 = $a6->mulInt64($b11,
24)->addInt64($a7->mulInt64($b10,
24))->addInt64($a8->mulInt64($b9, 24))
->addInt64($a9->mulInt64($b8,
24))->addInt64($a10->mulInt64($b7,
24))->addInt64($a11->mulInt64($b6, 24));
$s18 = $a7->mulInt64($b11,
24)->addInt64($a8->mulInt64($b10,
24))->addInt64($a9->mulInt64($b9, 24))
->addInt64($a10->mulInt64($b8,
24))->addInt64($a11->mulInt64($b7, 24));
$s19 = $a8->mulInt64($b11,
24)->addInt64($a9->mulInt64($b10,
24))->addInt64($a10->mulInt64($b9, 24))
->addInt64($a11->mulInt64($b8, 24));
$s20 = $a9->mulInt64($b11,
24)->addInt64($a10->mulInt64($b10,
24))->addInt64($a11->mulInt64($b9, 24));
$s21 = $a10->mulInt64($b11,
24)->addInt64($a11->mulInt64($b10, 24));
$s22 = $a11->mulInt64($b11, 24);
$s23 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->addInt(1 << 20)->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry2 = $s2->addInt(1 << 20)->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry4 = $s4->addInt(1 << 20)->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry12 = $s12->addInt(1 << 20)->shiftRight(21);
$s13 = $s13->addInt64($carry12);
$s12 = $s12->subInt64($carry12->shiftLeft(21));
$carry14 = $s14->addInt(1 << 20)->shiftRight(21);
$s15 = $s15->addInt64($carry14);
$s14 = $s14->subInt64($carry14->shiftLeft(21));
$carry16 = $s16->addInt(1 << 20)->shiftRight(21);
$s17 = $s17->addInt64($carry16);
$s16 = $s16->subInt64($carry16->shiftLeft(21));
$carry18 = $s18->addInt(1 << 20)->shiftRight(21);
$s19 = $s19->addInt64($carry18);
$s18 = $s18->subInt64($carry18->shiftLeft(21));
$carry20 = $s20->addInt(1 << 20)->shiftRight(21);
$s21 = $s21->addInt64($carry20);
$s20 = $s20->subInt64($carry20->shiftLeft(21));
$carry22 = $s22->addInt(1 << 20)->shiftRight(21);
$s23 = $s23->addInt64($carry22);
$s22 = $s22->subInt64($carry22->shiftLeft(21));
$carry1 = $s1->addInt(1 << 20)->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry3 = $s3->addInt(1 << 20)->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry5 = $s5->addInt(1 << 20)->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$carry13 = $s13->addInt(1 << 20)->shiftRight(21);
$s14 = $s14->addInt64($carry13);
$s13 = $s13->subInt64($carry13->shiftLeft(21));
$carry15 = $s15->addInt(1 << 20)->shiftRight(21);
$s16 = $s16->addInt64($carry15);
$s15 = $s15->subInt64($carry15->shiftLeft(21));
$carry17 = $s17->addInt(1 << 20)->shiftRight(21);
$s18 = $s18->addInt64($carry17);
$s17 = $s17->subInt64($carry17->shiftLeft(21));
$carry19 = $s19->addInt(1 << 20)->shiftRight(21);
$s20 = $s20->addInt64($carry19);
$s19 = $s19->subInt64($carry19->shiftLeft(21));
$carry21 = $s21->addInt(1 << 20)->shiftRight(21);
$s22 = $s22->addInt64($carry21);
$s21 = $s21->subInt64($carry21->shiftLeft(21));
$s11 = $s11->addInt64($s23->mulInt(666643, 20));
$s12 = $s12->addInt64($s23->mulInt(470296, 19));
$s13 = $s13->addInt64($s23->mulInt(654183, 20));
$s14 = $s14->subInt64($s23->mulInt(997805, 20));
$s15 = $s15->addInt64($s23->mulInt(136657, 18));
$s16 = $s16->subInt64($s23->mulInt(683901, 20));
$s10 = $s10->addInt64($s22->mulInt(666643, 20));
$s11 = $s11->addInt64($s22->mulInt(470296, 19));
$s12 = $s12->addInt64($s22->mulInt(654183, 20));
$s13 = $s13->subInt64($s22->mulInt(997805, 20));
$s14 = $s14->addInt64($s22->mulInt(136657, 18));
$s15 = $s15->subInt64($s22->mulInt(683901, 20));
$s9 = $s9->addInt64($s21->mulInt(666643, 20));
$s10 = $s10->addInt64($s21->mulInt(470296, 19));
$s11 = $s11->addInt64($s21->mulInt(654183, 20));
$s12 = $s12->subInt64($s21->mulInt(997805, 20));
$s13 = $s13->addInt64($s21->mulInt(136657, 18));
$s14 = $s14->subInt64($s21->mulInt(683901, 20));
$s8 = $s8->addInt64($s20->mulInt(666643, 20));
$s9 = $s9->addInt64($s20->mulInt(470296, 19));
$s10 = $s10->addInt64($s20->mulInt(654183, 20));
$s11 = $s11->subInt64($s20->mulInt(997805, 20));
$s12 = $s12->addInt64($s20->mulInt(136657, 18));
$s13 = $s13->subInt64($s20->mulInt(683901, 20));
$s7 = $s7->addInt64($s19->mulInt(666643, 20));
$s8 = $s8->addInt64($s19->mulInt(470296, 19));
$s9 = $s9->addInt64($s19->mulInt(654183, 20));
$s10 = $s10->subInt64($s19->mulInt(997805, 20));
$s11 = $s11->addInt64($s19->mulInt(136657, 18));
$s12 = $s12->subInt64($s19->mulInt(683901, 20));
$s6 = $s6->addInt64($s18->mulInt(666643, 20));
$s7 = $s7->addInt64($s18->mulInt(470296, 19));
$s8 = $s8->addInt64($s18->mulInt(654183, 20));
$s9 = $s9->subInt64($s18->mulInt(997805, 20));
$s10 = $s10->addInt64($s18->mulInt(136657, 18));
$s11 = $s11->subInt64($s18->mulInt(683901, 20));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry12 = $s12->addInt(1 << 20)->shiftRight(21);
$s13 = $s13->addInt64($carry12);
$s12 = $s12->subInt64($carry12->shiftLeft(21));
$carry14 = $s14->addInt(1 << 20)->shiftRight(21);
$s15 = $s15->addInt64($carry14);
$s14 = $s14->subInt64($carry14->shiftLeft(21));
$carry16 = $s16->addInt(1 << 20)->shiftRight(21);
$s17 = $s17->addInt64($carry16);
$s16 = $s16->subInt64($carry16->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$carry13 = $s13->addInt(1 << 20)->shiftRight(21);
$s14 = $s14->addInt64($carry13);
$s13 = $s13->subInt64($carry13->shiftLeft(21));
$carry15 = $s15->addInt(1 << 20)->shiftRight(21);
$s16 = $s16->addInt64($carry15);
$s15 = $s15->subInt64($carry15->shiftLeft(21));
$s5 = $s5->addInt64($s17->mulInt(666643, 20));
$s6 = $s6->addInt64($s17->mulInt(470296, 19));
$s7 = $s7->addInt64($s17->mulInt(654183, 20));
$s8 = $s8->subInt64($s17->mulInt(997805, 20));
$s9 = $s9->addInt64($s17->mulInt(136657, 18));
$s10 = $s10->subInt64($s17->mulInt(683901, 20));
$s4 = $s4->addInt64($s16->mulInt(666643, 20));
$s5 = $s5->addInt64($s16->mulInt(470296, 19));
$s6 = $s6->addInt64($s16->mulInt(654183, 20));
$s7 = $s7->subInt64($s16->mulInt(997805, 20));
$s8 = $s8->addInt64($s16->mulInt(136657, 18));
$s9 = $s9->subInt64($s16->mulInt(683901, 20));
$s3 = $s3->addInt64($s15->mulInt(666643, 20));
$s4 = $s4->addInt64($s15->mulInt(470296, 19));
$s5 = $s5->addInt64($s15->mulInt(654183, 20));
$s6 = $s6->subInt64($s15->mulInt(997805, 20));
$s7 = $s7->addInt64($s15->mulInt(136657, 18));
$s8 = $s8->subInt64($s15->mulInt(683901, 20));
$s2 = $s2->addInt64($s14->mulInt(666643, 20));
$s3 = $s3->addInt64($s14->mulInt(470296, 19));
$s4 = $s4->addInt64($s14->mulInt(654183, 20));
$s5 = $s5->subInt64($s14->mulInt(997805, 20));
$s6 = $s6->addInt64($s14->mulInt(136657, 18));
$s7 = $s7->subInt64($s14->mulInt(683901, 20));
$s1 = $s1->addInt64($s13->mulInt(666643, 20));
$s2 = $s2->addInt64($s13->mulInt(470296, 19));
$s3 = $s3->addInt64($s13->mulInt(654183, 20));
$s4 = $s4->subInt64($s13->mulInt(997805, 20));
$s5 = $s5->addInt64($s13->mulInt(136657, 18));
$s6 = $s6->subInt64($s13->mulInt(683901, 20));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$s12 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->addInt(1 << 20)->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry2 = $s2->addInt(1 << 20)->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry4 = $s4->addInt(1 << 20)->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry1 = $s1->addInt(1 << 20)->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry3 = $s3->addInt(1 << 20)->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry5 = $s5->addInt(1 << 20)->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$s12 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry1 = $s1->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry2 = $s2->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry3 = $s3->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry4 = $s4->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry5 = $s5->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry6 = $s6->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry7 = $s7->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry8 = $s8->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry9 = $s9->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry10 = $s10->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry11 = $s11->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$carry0 = $s0->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry1 = $s1->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry2 = $s2->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry3 = $s3->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry4 = $s4->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry5 = $s5->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry6 = $s6->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry7 = $s7->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry8 = $s10->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry9 = $s9->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry10 = $s10->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$S0 = $s0->toInt();
$S1 = $s1->toInt();
$S2 = $s2->toInt();
$S3 = $s3->toInt();
$S4 = $s4->toInt();
$S5 = $s5->toInt();
$S6 = $s6->toInt();
$S7 = $s7->toInt();
$S8 = $s8->toInt();
$S9 = $s9->toInt();
$S10 = $s10->toInt();
$S11 = $s11->toInt();
/**
* @var array<int, int>
*/
$arr = array(
(int) (0xff & ($S0 >> 0)),
(int) (0xff & ($S0 >> 8)),
(int) (0xff & (($S0 >> 16) | ($S1 << 5))),
(int) (0xff & ($S1 >> 3)),
(int) (0xff & ($S1 >> 11)),
(int) (0xff & (($S1 >> 19) | ($S2 << 2))),
(int) (0xff & ($S2 >> 6)),
(int) (0xff & (($S2 >> 14) | ($S3 << 7))),
(int) (0xff & ($S3 >> 1)),
(int) (0xff & ($S3 >> 9)),
(int) (0xff & (($S3 >> 17) | ($S4 << 4))),
(int) (0xff & ($S4 >> 4)),
(int) (0xff & ($S4 >> 12)),
(int) (0xff & (($S4 >> 20) | ($S5 << 1))),
(int) (0xff & ($S5 >> 7)),
(int) (0xff & (($S5 >> 15) | ($S6 << 6))),
(int) (0xff & ($S6 >> 2)),
(int) (0xff & ($S6 >> 10)),
(int) (0xff & (($S6 >> 18) | ($S7 << 3))),
(int) (0xff & ($S7 >> 5)),
(int) (0xff & ($S7 >> 13)),
(int) (0xff & ($S8 >> 0)),
(int) (0xff & ($S8 >> 8)),
(int) (0xff & (($S8 >> 16) | ($S9 << 5))),
(int) (0xff & ($S9 >> 3)),
(int) (0xff & ($S9 >> 11)),
(int) (0xff & (($S9 >> 19) | ($S10 << 2))),
(int) (0xff & ($S10 >> 6)),
(int) (0xff & (($S10 >> 14) | ($S11 << 7))),
(int) (0xff & ($S11 >> 1)),
(int) (0xff & ($S11 >> 9)),
(int) (0xff & ($S11 >> 17))
);
return self::intArrayToString($arr);
}
/**
* @internal You should not use this directly from another application
*
* @param string $s
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sc_reduce($s)
{
/**
* @var ParagonIE_Sodium_Core32_Int64 $s0
* @var ParagonIE_Sodium_Core32_Int64 $s1
* @var ParagonIE_Sodium_Core32_Int64 $s2
* @var ParagonIE_Sodium_Core32_Int64 $s3
* @var ParagonIE_Sodium_Core32_Int64 $s4
* @var ParagonIE_Sodium_Core32_Int64 $s5
* @var ParagonIE_Sodium_Core32_Int64 $s6
* @var ParagonIE_Sodium_Core32_Int64 $s7
* @var ParagonIE_Sodium_Core32_Int64 $s8
* @var ParagonIE_Sodium_Core32_Int64 $s9
* @var ParagonIE_Sodium_Core32_Int64 $s10
* @var ParagonIE_Sodium_Core32_Int64 $s11
* @var ParagonIE_Sodium_Core32_Int64 $s12
* @var ParagonIE_Sodium_Core32_Int64 $s13
* @var ParagonIE_Sodium_Core32_Int64 $s14
* @var ParagonIE_Sodium_Core32_Int64 $s15
* @var ParagonIE_Sodium_Core32_Int64 $s16
* @var ParagonIE_Sodium_Core32_Int64 $s17
* @var ParagonIE_Sodium_Core32_Int64 $s18
* @var ParagonIE_Sodium_Core32_Int64 $s19
* @var ParagonIE_Sodium_Core32_Int64 $s20
* @var ParagonIE_Sodium_Core32_Int64 $s21
* @var ParagonIE_Sodium_Core32_Int64 $s22
* @var ParagonIE_Sodium_Core32_Int64 $s23
*/
$s0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
self::load_3(self::substr($s, 0, 3)));
$s1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 2, 4)) >> 5));
$s2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($s, 5, 3)) >> 2));
$s3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 7, 4)) >> 7));
$s4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 10, 4)) >> 4));
$s5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($s, 13, 3)) >> 1));
$s6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 15, 4)) >> 6));
$s7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($s, 18, 4)) >> 3));
$s8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
self::load_3(self::substr($s, 21, 3)));
$s9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 23, 4)) >> 5));
$s10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($s, 26, 3)) >> 2));
$s11 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 28, 4)) >> 7));
$s12 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 31, 4)) >> 4));
$s13 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($s, 34, 3)) >> 1));
$s14 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 36, 4)) >> 6));
$s15 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($s, 39, 4)) >> 3));
$s16 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
self::load_3(self::substr($s, 42, 3)));
$s17 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 44, 4)) >> 5));
$s18 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($s, 47, 3)) >> 2));
$s19 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 49, 4)) >> 7));
$s20 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 52, 4)) >> 4));
$s21 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_3(self::substr($s, 55, 3)) >> 1));
$s22 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 &
(self::load_4(self::substr($s, 57, 4)) >> 6));
$s23 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff &
(self::load_4(self::substr($s, 60, 4)) >> 3));
$s11 = $s11->addInt64($s23->mulInt(666643, 20));
$s12 = $s12->addInt64($s23->mulInt(470296, 19));
$s13 = $s13->addInt64($s23->mulInt(654183, 20));
$s14 = $s14->subInt64($s23->mulInt(997805, 20));
$s15 = $s15->addInt64($s23->mulInt(136657, 18));
$s16 = $s16->subInt64($s23->mulInt(683901, 20));
$s10 = $s10->addInt64($s22->mulInt(666643, 20));
$s11 = $s11->addInt64($s22->mulInt(470296, 19));
$s12 = $s12->addInt64($s22->mulInt(654183, 20));
$s13 = $s13->subInt64($s22->mulInt(997805, 20));
$s14 = $s14->addInt64($s22->mulInt(136657, 18));
$s15 = $s15->subInt64($s22->mulInt(683901, 20));
$s9 = $s9->addInt64($s21->mulInt(666643, 20));
$s10 = $s10->addInt64($s21->mulInt(470296, 19));
$s11 = $s11->addInt64($s21->mulInt(654183, 20));
$s12 = $s12->subInt64($s21->mulInt(997805, 20));
$s13 = $s13->addInt64($s21->mulInt(136657, 18));
$s14 = $s14->subInt64($s21->mulInt(683901, 20));
$s8 = $s8->addInt64($s20->mulInt(666643, 20));
$s9 = $s9->addInt64($s20->mulInt(470296, 19));
$s10 = $s10->addInt64($s20->mulInt(654183, 20));
$s11 = $s11->subInt64($s20->mulInt(997805, 20));
$s12 = $s12->addInt64($s20->mulInt(136657, 18));
$s13 = $s13->subInt64($s20->mulInt(683901, 20));
$s7 = $s7->addInt64($s19->mulInt(666643, 20));
$s8 = $s8->addInt64($s19->mulInt(470296, 19));
$s9 = $s9->addInt64($s19->mulInt(654183, 20));
$s10 = $s10->subInt64($s19->mulInt(997805, 20));
$s11 = $s11->addInt64($s19->mulInt(136657, 18));
$s12 = $s12->subInt64($s19->mulInt(683901, 20));
$s6 = $s6->addInt64($s18->mulInt(666643, 20));
$s7 = $s7->addInt64($s18->mulInt(470296, 19));
$s8 = $s8->addInt64($s18->mulInt(654183, 20));
$s9 = $s9->subInt64($s18->mulInt(997805, 20));
$s10 = $s10->addInt64($s18->mulInt(136657, 18));
$s11 = $s11->subInt64($s18->mulInt(683901, 20));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry12 = $s12->addInt(1 << 20)->shiftRight(21);
$s13 = $s13->addInt64($carry12);
$s12 = $s12->subInt64($carry12->shiftLeft(21));
$carry14 = $s14->addInt(1 << 20)->shiftRight(21);
$s15 = $s15->addInt64($carry14);
$s14 = $s14->subInt64($carry14->shiftLeft(21));
$carry16 = $s16->addInt(1 << 20)->shiftRight(21);
$s17 = $s17->addInt64($carry16);
$s16 = $s16->subInt64($carry16->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$carry13 = $s13->addInt(1 << 20)->shiftRight(21);
$s14 = $s14->addInt64($carry13);
$s13 = $s13->subInt64($carry13->shiftLeft(21));
$carry15 = $s15->addInt(1 << 20)->shiftRight(21);
$s16 = $s16->addInt64($carry15);
$s15 = $s15->subInt64($carry15->shiftLeft(21));
$s5 = $s5->addInt64($s17->mulInt(666643, 20));
$s6 = $s6->addInt64($s17->mulInt(470296, 19));
$s7 = $s7->addInt64($s17->mulInt(654183, 20));
$s8 = $s8->subInt64($s17->mulInt(997805, 20));
$s9 = $s9->addInt64($s17->mulInt(136657, 18));
$s10 = $s10->subInt64($s17->mulInt(683901, 20));
$s4 = $s4->addInt64($s16->mulInt(666643, 20));
$s5 = $s5->addInt64($s16->mulInt(470296, 19));
$s6 = $s6->addInt64($s16->mulInt(654183, 20));
$s7 = $s7->subInt64($s16->mulInt(997805, 20));
$s8 = $s8->addInt64($s16->mulInt(136657, 18));
$s9 = $s9->subInt64($s16->mulInt(683901, 20));
$s3 = $s3->addInt64($s15->mulInt(666643, 20));
$s4 = $s4->addInt64($s15->mulInt(470296, 19));
$s5 = $s5->addInt64($s15->mulInt(654183, 20));
$s6 = $s6->subInt64($s15->mulInt(997805, 20));
$s7 = $s7->addInt64($s15->mulInt(136657, 18));
$s8 = $s8->subInt64($s15->mulInt(683901, 20));
$s2 = $s2->addInt64($s14->mulInt(666643, 20));
$s3 = $s3->addInt64($s14->mulInt(470296, 19));
$s4 = $s4->addInt64($s14->mulInt(654183, 20));
$s5 = $s5->subInt64($s14->mulInt(997805, 20));
$s6 = $s6->addInt64($s14->mulInt(136657, 18));
$s7 = $s7->subInt64($s14->mulInt(683901, 20));
$s1 = $s1->addInt64($s13->mulInt(666643, 20));
$s2 = $s2->addInt64($s13->mulInt(470296, 19));
$s3 = $s3->addInt64($s13->mulInt(654183, 20));
$s4 = $s4->subInt64($s13->mulInt(997805, 20));
$s5 = $s5->addInt64($s13->mulInt(136657, 18));
$s6 = $s6->subInt64($s13->mulInt(683901, 20));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$s12 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->addInt(1 << 20)->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry2 = $s2->addInt(1 << 20)->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry4 = $s4->addInt(1 << 20)->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry6 = $s6->addInt(1 << 20)->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry8 = $s8->addInt(1 << 20)->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry10 = $s10->addInt(1 << 20)->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry1 = $s1->addInt(1 << 20)->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry3 = $s3->addInt(1 << 20)->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry5 = $s5->addInt(1 << 20)->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry7 = $s7->addInt(1 << 20)->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry9 = $s9->addInt(1 << 20)->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry11 = $s11->addInt(1 << 20)->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$s12 = new ParagonIE_Sodium_Core32_Int64();
$carry0 = $s0->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry1 = $s1->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry2 = $s2->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry3 = $s3->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry4 = $s4->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry5 = $s5->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry6 = $s6->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry7 = $s7->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry8 = $s8->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry9 = $s9->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry10 = $s10->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$carry11 = $s11->shiftRight(21);
$s12 = $s12->addInt64($carry11);
$s11 = $s11->subInt64($carry11->shiftLeft(21));
$s0 = $s0->addInt64($s12->mulInt(666643, 20));
$s1 = $s1->addInt64($s12->mulInt(470296, 19));
$s2 = $s2->addInt64($s12->mulInt(654183, 20));
$s3 = $s3->subInt64($s12->mulInt(997805, 20));
$s4 = $s4->addInt64($s12->mulInt(136657, 18));
$s5 = $s5->subInt64($s12->mulInt(683901, 20));
$carry0 = $s0->shiftRight(21);
$s1 = $s1->addInt64($carry0);
$s0 = $s0->subInt64($carry0->shiftLeft(21));
$carry1 = $s1->shiftRight(21);
$s2 = $s2->addInt64($carry1);
$s1 = $s1->subInt64($carry1->shiftLeft(21));
$carry2 = $s2->shiftRight(21);
$s3 = $s3->addInt64($carry2);
$s2 = $s2->subInt64($carry2->shiftLeft(21));
$carry3 = $s3->shiftRight(21);
$s4 = $s4->addInt64($carry3);
$s3 = $s3->subInt64($carry3->shiftLeft(21));
$carry4 = $s4->shiftRight(21);
$s5 = $s5->addInt64($carry4);
$s4 = $s4->subInt64($carry4->shiftLeft(21));
$carry5 = $s5->shiftRight(21);
$s6 = $s6->addInt64($carry5);
$s5 = $s5->subInt64($carry5->shiftLeft(21));
$carry6 = $s6->shiftRight(21);
$s7 = $s7->addInt64($carry6);
$s6 = $s6->subInt64($carry6->shiftLeft(21));
$carry7 = $s7->shiftRight(21);
$s8 = $s8->addInt64($carry7);
$s7 = $s7->subInt64($carry7->shiftLeft(21));
$carry8 = $s8->shiftRight(21);
$s9 = $s9->addInt64($carry8);
$s8 = $s8->subInt64($carry8->shiftLeft(21));
$carry9 = $s9->shiftRight(21);
$s10 = $s10->addInt64($carry9);
$s9 = $s9->subInt64($carry9->shiftLeft(21));
$carry10 = $s10->shiftRight(21);
$s11 = $s11->addInt64($carry10);
$s10 = $s10->subInt64($carry10->shiftLeft(21));
$S0 = $s0->toInt32()->toInt();
$S1 = $s1->toInt32()->toInt();
$S2 = $s2->toInt32()->toInt();
$S3 = $s3->toInt32()->toInt();
$S4 = $s4->toInt32()->toInt();
$S5 = $s5->toInt32()->toInt();
$S6 = $s6->toInt32()->toInt();
$S7 = $s7->toInt32()->toInt();
$S8 = $s8->toInt32()->toInt();
$S9 = $s9->toInt32()->toInt();
$S10 = $s10->toInt32()->toInt();
$S11 = $s11->toInt32()->toInt();
/**
* @var array<int, int>
*/
$arr = array(
(int) ($S0 >> 0),
(int) ($S0 >> 8),
(int) (($S0 >> 16) | ($S1 << 5)),
(int) ($S1 >> 3),
(int) ($S1 >> 11),
(int) (($S1 >> 19) | ($S2 << 2)),
(int) ($S2 >> 6),
(int) (($S2 >> 14) | ($S3 << 7)),
(int) ($S3 >> 1),
(int) ($S3 >> 9),
(int) (($S3 >> 17) | ($S4 << 4)),
(int) ($S4 >> 4),
(int) ($S4 >> 12),
(int) (($S4 >> 20) | ($S5 << 1)),
(int) ($S5 >> 7),
(int) (($S5 >> 15) | ($S6 << 6)),
(int) ($S6 >> 2),
(int) ($S6 >> 10),
(int) (($S6 >> 18) | ($S7 << 3)),
(int) ($S7 >> 5),
(int) ($S7 >> 13),
(int) ($S8 >> 0),
(int) ($S8 >> 8),
(int) (($S8 >> 16) | ($S9 << 5)),
(int) ($S9 >> 3),
(int) ($S9 >> 11),
(int) (($S9 >> 19) | ($S10 << 2)),
(int) ($S10 >> 6),
(int) (($S10 >> 14) | ($S11 << 7)),
(int) ($S11 >> 1),
(int) ($S11 >> 9),
(int) $S11 >> 17
);
return self::intArrayToString($arr);
}
/**
* multiply by the order of the main subgroup l =
2^252+27742317777372353535851937790883648493
*
* @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A
* @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3
* @throws SodiumException
* @throws TypeError
*/
public static function
ge_mul_l(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A)
{
/** @var array<int, int> $aslide */
$aslide = array(
13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0,
0, 0,
0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3,
0,
0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0,
0,
0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0,
-1,
0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0,
0,
0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
);
/** @var array<int,
ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai size 8 */
$Ai = array();
# ge_p3_to_cached(&Ai[0], A);
$Ai[0] = self::ge_p3_to_cached($A);
# ge_p3_dbl(&t, A);
$t = self::ge_p3_dbl($A);
# ge_p1p1_to_p3(&A2, &t);
$A2 = self::ge_p1p1_to_p3($t);
for ($i = 1; $i < 8; ++$i) {
# ge_add(&t, &A2, &Ai[0]);
$t = self::ge_add($A2, $Ai[$i - 1]);
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_p3_to_cached(&Ai[i], &u);
$Ai[$i] = self::ge_p3_to_cached($u);
}
$r = self::ge_p3_0();
for ($i = 252; $i >= 0; --$i) {
$t = self::ge_p3_dbl($r);
if ($aslide[$i] > 0) {
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_add(&t, &u, &Ai[aslide[i] / 2]);
$t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
} elseif ($aslide[$i] < 0) {
# ge_p1p1_to_p3(&u, &t);
$u = self::ge_p1p1_to_p3($t);
# ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
$t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
}
}
# ge_p1p1_to_p3(r, &t);
return self::ge_p1p1_to_p3($t);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Ed25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Ed25519
*/
abstract class ParagonIE_Sodium_Core32_Ed25519 extends
ParagonIE_Sodium_Core32_Curve25519
{
const KEYPAIR_BYTES = 96;
const SEED_BYTES = 32;
/**
* @internal You should not use this directly from another application
*
* @return string (96 bytes)
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function keypair()
{
$seed = random_bytes(self::SEED_BYTES);
$pk = '';
$sk = '';
self::seed_keypair($pk, $sk, $seed);
return $sk . $pk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $pk
* @param string $sk
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function seed_keypair(&$pk, &$sk, $seed)
{
if (self::strlen($seed) !== self::SEED_BYTES) {
throw new RangeException('crypto_sign keypair seed must be
32 bytes long');
}
/** @var string $pk */
$pk = self::publickey_from_secretkey($seed);
$sk = $seed . $pk;
return $sk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function secretkey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96
bytes long');
}
return self::substr($keypair, 0, 64);
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function publickey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96
bytes long');
}
return self::substr($keypair, 64, 32);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function publickey_from_secretkey($sk)
{
/** @var string $sk */
$sk = hash('sha512', self::substr($sk, 0, 32), true);
$sk[0] = self::intToChr(
self::chrToInt($sk[0]) & 248
);
$sk[31] = self::intToChr(
(self::chrToInt($sk[31]) & 63) | 64
);
return self::sk_to_pk($sk);
}
/**
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function pk_to_curve25519($pk)
{
if (self::small_order($pk)) {
throw new SodiumException('Public key is on a small
order');
}
$A = self::ge_frombytes_negate_vartime($pk);
$p1 = self::ge_mul_l($A);
if (!self::fe_isnonzero($p1->X)) {
throw new SodiumException('Unexpected zero result');
}
# fe_1(one_minus_y);
# fe_sub(one_minus_y, one_minus_y, A.Y);
# fe_invert(one_minus_y, one_minus_y);
$one_minux_y = self::fe_invert(
self::fe_sub(
self::fe_1(),
$A->Y
)
);
# fe_1(x);
# fe_add(x, x, A.Y);
# fe_mul(x, x, one_minus_y);
$x = self::fe_mul(
self::fe_add(self::fe_1(), $A->Y),
$one_minux_y
);
# fe_tobytes(curve25519_pk, x);
return self::fe_tobytes($x);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sk_to_pk($sk)
{
return self::ge_p3_tobytes(
self::ge_scalarmult_base(
self::substr($sk, 0, 32)
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
/** @var string $signature */
$signature = self::sign_detached($message, $sk);
return $signature . $message;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message A signed message
* @param string $pk Public key
* @return string Message (without signature)
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($message, $pk)
{
/** @var string $signature */
$signature = self::substr($message, 0, 64);
/** @var string $message */
$message = self::substr($message, 64);
if (self::verify_detached($signature, $message, $pk)) {
return $message;
}
throw new SodiumException('Invalid signature');
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_detached($message, $sk)
{
# crypto_hash_sha512(az, sk, 32);
$az = hash('sha512', self::substr($sk, 0, 32), true);
# az[0] &= 248;
# az[31] &= 63;
# az[31] |= 64;
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, az + 32, 32);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, nonce);
$hs = hash_init('sha512');
hash_update($hs, self::substr($az, 32, 32));
hash_update($hs, $message);
$nonceHash = hash_final($hs, true);
# memmove(sig + 32, sk + 32, 32);
$pk = self::substr($sk, 32, 32);
# sc_reduce(nonce);
# ge_scalarmult_base(&R, nonce);
# ge_p3_tobytes(sig, &R);
$nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash,
32);
$sig = self::ge_p3_tobytes(
self::ge_scalarmult_base($nonce)
);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, sig, 64);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, hram);
$hs = hash_init('sha512');
hash_update($hs, self::substr($sig, 0, 32));
hash_update($hs, self::substr($pk, 0, 32));
hash_update($hs, $message);
$hramHash = hash_final($hs, true);
# sc_reduce(hram);
# sc_muladd(sig + 32, hram, az, nonce);
$hram = self::sc_reduce($hramHash);
$sigAfter = self::sc_muladd($hram, $az, $nonce);
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
ParagonIE_Sodium_Compat::memzero($az);
} catch (SodiumException $ex) {
$az = null;
}
return $sig;
}
/**
* @internal You should not use this directly from another application
*
* @param string $sig
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_detached($sig, $message, $pk)
{
if (self::strlen($sig) < 64) {
throw new SodiumException('Signature is too short');
}
if ((self::chrToInt($sig[63]) & 240) &&
self::check_S_lt_L(self::substr($sig, 32, 32))) {
throw new SodiumException('S < L - Invalid
signature');
}
if (self::small_order($sig)) {
throw new SodiumException('Signature is on too small of an
order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($pk[$i]);
}
if ($d === 0) {
throw new SodiumException('All zero public key');
}
/** @var bool The original value of
ParagonIE_Sodium_Compat::$fastMult */
$orig = ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up
verification.
ParagonIE_Sodium_Compat::$fastMult = true;
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */
$A = self::ge_frombytes_negate_vartime($pk);
/** @var string $hDigest */
$hDigest = hash(
'sha512',
self::substr($sig, 0, 32) .
self::substr($pk, 0, 32) .
$message,
true
);
/** @var string $h */
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */
$R = self::ge_double_scalarmult_vartime(
$h,
$A,
self::substr($sig, 32)
);
/** @var string $rcheck */
$rcheck = self::ge_tobytes($R);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* @internal You should not use this directly from another application
*
* @param string $S
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function check_S_lt_L($S)
{
if (self::strlen($S) < 32) {
throw new SodiumException('Signature must be 32
bytes');
}
static $L = array(
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
);
/** @var array<int, int> $L */
$c = 0;
$n = 1;
$i = 32;
do {
--$i;
$x = self::chrToInt($S[$i]);
$c |= (
(($x - $L[$i]) >> 8) & $n
);
$n &= (
(($x ^ $L[$i]) - 1) >> 8
);
} while ($i !== 0);
return $c === 0;
}
/**
* @param string $R
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function small_order($R)
{
static $blocklist = array(
/* 0 (order 4) */
array(
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/* 1 (order 1) */
array(
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/*
2707385501144840649318225287225658788936804267575313519463743609750303402022
(order 8) */
array(
0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05
),
/*
55188659117513257062467267217118295137698188065244968500265048394206261417927
(order 8) */
array(
0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a
),
/* p-1 (order 2) */
array(
0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85
),
/* p (order 4) */
array(
0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa
),
/* p+1 (order 1) */
array(
0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/*
p+2707385501144840649318225287225658788936804267575313519463743609750303402022
(order 8) */
array(
0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/*
p+55188659117513257062467267217118295137698188065244968500265048394206261417927
(order 8) */
array(
0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* 2p-1 (order 2) */
array(
0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p (order 4) */
array(
0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p+1 (order 1) */
array(
0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
)
);
/** @var array<int, array<int, int>> $blocklist */
$countBlocklist = count($blocklist);
for ($i = 0; $i < $countBlocklist; ++$i) {
$c = 0;
for ($j = 0; $j < 32; ++$j) {
$c |= self::chrToInt($R[$j]) ^ $blocklist[$i][$j];
}
if ($c === 0) {
return true;
}
}
return false;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_HChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HChaCha20
*/
class ParagonIE_Sodium_Core32_HChaCha20 extends
ParagonIE_Sodium_Core32_ChaCha20
{
/**
* @param string $in
* @param string $key
* @param string|null $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function hChaCha20($in = '', $key =
'', $c = null)
{
$ctx = array();
if ($c === null) {
$ctx[0] = new ParagonIE_Sodium_Core32_Int32(array(0x6170,
0x7865));
$ctx[1] = new ParagonIE_Sodium_Core32_Int32(array(0x3320,
0x646e));
$ctx[2] = new ParagonIE_Sodium_Core32_Int32(array(0x7962,
0x2d32));
$ctx[3] = new ParagonIE_Sodium_Core32_Int32(array(0x6b20,
0x6574));
} else {
$ctx[0] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4));
$ctx[1] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4));
$ctx[2] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4));
$ctx[3] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4));
}
$ctx[4] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4));
$ctx[5] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 4, 4));
$ctx[6] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 8, 4));
$ctx[7] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12,
4));
$ctx[8] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16,
4));
$ctx[9] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20,
4));
$ctx[10] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24,
4));
$ctx[11] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28,
4));
$ctx[12] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4));
$ctx[13] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4));
$ctx[14] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4));
$ctx[15] =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4));
return self::hChaCha20Bytes($ctx);
}
/**
* @param array $ctx
* @return string
* @throws SodiumException
* @throws TypeError
*/
protected static function hChaCha20Bytes(array $ctx)
{
/** @var ParagonIE_Sodium_Core32_Int32 $x0 */
$x0 = $ctx[0];
/** @var ParagonIE_Sodium_Core32_Int32 $x1 */
$x1 = $ctx[1];
/** @var ParagonIE_Sodium_Core32_Int32 $x2 */
$x2 = $ctx[2];
/** @var ParagonIE_Sodium_Core32_Int32 $x3 */
$x3 = $ctx[3];
/** @var ParagonIE_Sodium_Core32_Int32 $x4 */
$x4 = $ctx[4];
/** @var ParagonIE_Sodium_Core32_Int32 $x5 */
$x5 = $ctx[5];
/** @var ParagonIE_Sodium_Core32_Int32 $x6 */
$x6 = $ctx[6];
/** @var ParagonIE_Sodium_Core32_Int32 $x7 */
$x7 = $ctx[7];
/** @var ParagonIE_Sodium_Core32_Int32 $x8 */
$x8 = $ctx[8];
/** @var ParagonIE_Sodium_Core32_Int32 $x9 */
$x9 = $ctx[9];
/** @var ParagonIE_Sodium_Core32_Int32 $x10 */
$x10 = $ctx[10];
/** @var ParagonIE_Sodium_Core32_Int32 $x11 */
$x11 = $ctx[11];
/** @var ParagonIE_Sodium_Core32_Int32 $x12 */
$x12 = $ctx[12];
/** @var ParagonIE_Sodium_Core32_Int32 $x13 */
$x13 = $ctx[13];
/** @var ParagonIE_Sodium_Core32_Int32 $x14 */
$x14 = $ctx[14];
/** @var ParagonIE_Sodium_Core32_Int32 $x15 */
$x15 = $ctx[15];
for ($i = 0; $i < 10; ++$i) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8,
$x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9,
$x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10,
$x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11,
$x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10,
$x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11,
$x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8,
$x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9,
$x14);
}
return $x0->toReverseString() .
$x1->toReverseString() .
$x2->toReverseString() .
$x3->toReverseString() .
$x12->toReverseString() .
$x13->toReverseString() .
$x14->toReverseString() .
$x15->toReverseString();
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_HSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_HSalsa20
*/
abstract class ParagonIE_Sodium_Core32_HSalsa20 extends
ParagonIE_Sodium_Core32_Salsa20
{
/**
* Calculate an hsalsa20 hash of a single block
*
* HSalsa20 doesn't have a counter and will never be used for more
than
* one block (used to derive a subkey for xsalsa20).
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function hsalsa20($in, $k, $c = null)
{
/**
* @var ParagonIE_Sodium_Core32_Int32 $x0
* @var ParagonIE_Sodium_Core32_Int32 $x1
* @var ParagonIE_Sodium_Core32_Int32 $x2
* @var ParagonIE_Sodium_Core32_Int32 $x3
* @var ParagonIE_Sodium_Core32_Int32 $x4
* @var ParagonIE_Sodium_Core32_Int32 $x5
* @var ParagonIE_Sodium_Core32_Int32 $x6
* @var ParagonIE_Sodium_Core32_Int32 $x7
* @var ParagonIE_Sodium_Core32_Int32 $x8
* @var ParagonIE_Sodium_Core32_Int32 $x9
* @var ParagonIE_Sodium_Core32_Int32 $x10
* @var ParagonIE_Sodium_Core32_Int32 $x11
* @var ParagonIE_Sodium_Core32_Int32 $x12
* @var ParagonIE_Sodium_Core32_Int32 $x13
* @var ParagonIE_Sodium_Core32_Int32 $x14
* @var ParagonIE_Sodium_Core32_Int32 $x15
* @var ParagonIE_Sodium_Core32_Int32 $j0
* @var ParagonIE_Sodium_Core32_Int32 $j1
* @var ParagonIE_Sodium_Core32_Int32 $j2
* @var ParagonIE_Sodium_Core32_Int32 $j3
* @var ParagonIE_Sodium_Core32_Int32 $j4
* @var ParagonIE_Sodium_Core32_Int32 $j5
* @var ParagonIE_Sodium_Core32_Int32 $j6
* @var ParagonIE_Sodium_Core32_Int32 $j7
* @var ParagonIE_Sodium_Core32_Int32 $j8
* @var ParagonIE_Sodium_Core32_Int32 $j9
* @var ParagonIE_Sodium_Core32_Int32 $j10
* @var ParagonIE_Sodium_Core32_Int32 $j11
* @var ParagonIE_Sodium_Core32_Int32 $j12
* @var ParagonIE_Sodium_Core32_Int32 $j13
* @var ParagonIE_Sodium_Core32_Int32 $j14
* @var ParagonIE_Sodium_Core32_Int32 $j15
*/
if (self::strlen($k) < 32) {
throw new RangeException('Key must be 32 bytes
long');
}
if ($c === null) {
$x0 = new ParagonIE_Sodium_Core32_Int32(array(0x6170,
0x7865));
$x5 = new ParagonIE_Sodium_Core32_Int32(array(0x3320,
0x646e));
$x10 = new ParagonIE_Sodium_Core32_Int32(array(0x7962,
0x2d32));
$x15 = new ParagonIE_Sodium_Core32_Int32(array(0x6b20,
0x6574));
} else {
$x0 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4));
$x5 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4));
$x10 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4));
$x15 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4));
}
$x1 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 0, 4));
$x2 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 4, 4));
$x3 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 8, 4));
$x4 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 12, 4));
$x6 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4));
$x7 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4));
$x8 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4));
$x9 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4));
$x11 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 16, 4));
$x12 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 20, 4));
$x13 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 24, 4));
$x14 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 28, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 =
$x4->xorInt32($x0->addInt32($x12)->rotateLeft(7));
$x8 =
$x8->xorInt32($x4->addInt32($x0)->rotateLeft(9));
$x12 =
$x12->xorInt32($x8->addInt32($x4)->rotateLeft(13));
$x0 =
$x0->xorInt32($x12->addInt32($x8)->rotateLeft(18));
$x9 =
$x9->xorInt32($x5->addInt32($x1)->rotateLeft(7));
$x13 =
$x13->xorInt32($x9->addInt32($x5)->rotateLeft(9));
$x1 =
$x1->xorInt32($x13->addInt32($x9)->rotateLeft(13));
$x5 =
$x5->xorInt32($x1->addInt32($x13)->rotateLeft(18));
$x14 =
$x14->xorInt32($x10->addInt32($x6)->rotateLeft(7));
$x2 =
$x2->xorInt32($x14->addInt32($x10)->rotateLeft(9));
$x6 =
$x6->xorInt32($x2->addInt32($x14)->rotateLeft(13));
$x10 =
$x10->xorInt32($x6->addInt32($x2)->rotateLeft(18));
$x3 =
$x3->xorInt32($x15->addInt32($x11)->rotateLeft(7));
$x7 =
$x7->xorInt32($x3->addInt32($x15)->rotateLeft(9));
$x11 =
$x11->xorInt32($x7->addInt32($x3)->rotateLeft(13));
$x15 =
$x15->xorInt32($x11->addInt32($x7)->rotateLeft(18));
$x1 =
$x1->xorInt32($x0->addInt32($x3)->rotateLeft(7));
$x2 =
$x2->xorInt32($x1->addInt32($x0)->rotateLeft(9));
$x3 =
$x3->xorInt32($x2->addInt32($x1)->rotateLeft(13));
$x0 =
$x0->xorInt32($x3->addInt32($x2)->rotateLeft(18));
$x6 =
$x6->xorInt32($x5->addInt32($x4)->rotateLeft(7));
$x7 =
$x7->xorInt32($x6->addInt32($x5)->rotateLeft(9));
$x4 =
$x4->xorInt32($x7->addInt32($x6)->rotateLeft(13));
$x5 =
$x5->xorInt32($x4->addInt32($x7)->rotateLeft(18));
$x11 =
$x11->xorInt32($x10->addInt32($x9)->rotateLeft(7));
$x8 =
$x8->xorInt32($x11->addInt32($x10)->rotateLeft(9));
$x9 =
$x9->xorInt32($x8->addInt32($x11)->rotateLeft(13));
$x10 =
$x10->xorInt32($x9->addInt32($x8)->rotateLeft(18));
$x12 =
$x12->xorInt32($x15->addInt32($x14)->rotateLeft(7));
$x13 =
$x13->xorInt32($x12->addInt32($x15)->rotateLeft(9));
$x14 =
$x14->xorInt32($x13->addInt32($x12)->rotateLeft(13));
$x15 =
$x15->xorInt32($x14->addInt32($x13)->rotateLeft(18));
}
return $x0->toReverseString() .
$x5->toReverseString() .
$x10->toReverseString() .
$x15->toReverseString() .
$x6->toReverseString() .
$x7->toReverseString() .
$x8->toReverseString() .
$x9->toReverseString();
}
}
<?php
/**
* Class ParagonIE_Sodium_Core32_Int32
*
* Encapsulates a 32-bit integer.
*
* These are immutable. It always returns a new instance.
*/
class ParagonIE_Sodium_Core32_Int32
{
/**
* @var array<int, int> - two 16-bit integers
*
* 0 is the higher 16 bits
* 1 is the lower 16 bits
*/
public $limbs = array(0, 0);
/**
* @var int
*/
public $overflow = 0;
/**
* @var bool
*/
public $unsignedInt = false;
/**
* ParagonIE_Sodium_Core32_Int32 constructor.
* @param array $array
* @param bool $unsignedInt
*/
public function __construct($array = array(0, 0), $unsignedInt = false)
{
$this->limbs = array(
(int) $array[0],
(int) $array[1]
);
$this->overflow = 0;
$this->unsignedInt = $unsignedInt;
}
/**
* Adds two int32 objects
*
* @param ParagonIE_Sodium_Core32_Int32 $addend
* @return ParagonIE_Sodium_Core32_Int32
*/
public function addInt32(ParagonIE_Sodium_Core32_Int32 $addend)
{
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$j0 = $addend->limbs[0];
$j1 = $addend->limbs[1];
$r1 = $i1 + ($j1 & 0xffff);
$carry = $r1 >> 16;
$r0 = $i0 + ($j0 & 0xffff) + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$return = new ParagonIE_Sodium_Core32_Int32(
array($r0, $r1)
);
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* Adds a normal integer to an int32 object
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function addInt($int)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int,
'int', 1);
/** @var int $int */
$int = (int) $int;
$int = (int) $int;
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$r1 = $i1 + ($int & 0xffff);
$carry = $r1 >> 16;
$r0 = $i0 + (($int >> 16) & 0xffff) + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$return = new ParagonIE_Sodium_Core32_Int32(
array($r0, $r1)
);
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param int $b
* @return int
*/
public function compareInt($b = 0)
{
$gt = 0;
$eq = 1;
$i = 2;
$j = 0;
while ($i > 0) {
--$i;
/** @var int $x1 */
$x1 = $this->limbs[$i];
/** @var int $x2 */
$x2 = ($b >> ($j << 4)) & 0xffff;
/** @var int $gt */
$gt |= (($x2 - $x1) >> 8) & $eq;
/** @var int $eq */
$eq &= (($x2 ^ $x1) - 1) >> 8;
}
return ($gt + $gt - $eq) + 1;
}
/**
* @param int $m
* @return ParagonIE_Sodium_Core32_Int32
*/
public function mask($m = 0)
{
/** @var int $hi */
$hi = ($m >> 16) & 0xffff;
/** @var int $lo */
$lo = ($m & 0xffff);
return new ParagonIE_Sodium_Core32_Int32(
array(
(int) ($this->limbs[0] & $hi),
(int) ($this->limbs[1] & $lo)
),
$this->unsignedInt
);
}
/**
* @param array<int, int> $a
* @param array<int, int> $b
* @param int $baseLog2
* @return array<int, int>
*/
public function multiplyLong(array $a, array $b, $baseLog2 = 16)
{
$a_l = count($a);
$b_l = count($b);
/** @var array<int, int> $r */
$r = array_fill(0, $a_l + $b_l + 1, 0);
$base = 1 << $baseLog2;
for ($i = 0; $i < $a_l; ++$i) {
$a_i = $a[$i];
for ($j = 0; $j < $a_l; ++$j) {
$b_j = $b[$j];
$product = ($a_i * $b_j) + $r[$i + $j];
$carry = ($product >> $baseLog2 & 0xffff);
$r[$i + $j] = ($product - (int) ($carry * $base)) &
0xffff;
$r[$i + $j + 1] += $carry;
}
}
return array_slice($r, 0, 5);
}
/**
* @param int $int
* @return ParagonIE_Sodium_Core32_Int32
*/
public function mulIntFast($int)
{
// Handle negative numbers
$aNeg = ($this->limbs[0] >> 15) & 1;
$bNeg = ($int >> 31) & 1;
$a = array_reverse($this->limbs);
$b = array(
$int & 0xffff,
($int >> 16) & 0xffff
);
if ($aNeg) {
for ($i = 0; $i < 2; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 2; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
// Multiply
$res = $this->multiplyLong($a, $b);
// Re-apply negation to results
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 2; ++$i) {
$res[$i] = (0xffff ^ $res[$i]) & 0xffff;
}
// Handle integer overflow
$c = 1;
for ($i = 0; $i < 2; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
// Return our values
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs = array(
$res[1] & 0xffff,
$res[0] & 0xffff
);
if (count($res) > 2) {
$return->overflow = $res[2] & 0xffff;
}
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int32 $right
* @return ParagonIE_Sodium_Core32_Int32
*/
public function mulInt32Fast(ParagonIE_Sodium_Core32_Int32 $right)
{
$aNeg = ($this->limbs[0] >> 15) & 1;
$bNeg = ($right->limbs[0] >> 15) & 1;
$a = array_reverse($this->limbs);
$b = array_reverse($right->limbs);
if ($aNeg) {
for ($i = 0; $i < 2; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 2; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
$res = $this->multiplyLong($a, $b);
if ($aNeg !== $bNeg) {
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 2; ++$i) {
$res[$i] = ($res[$i] ^ 0xffff) & 0xffff;
}
$c = 1;
for ($i = 0; $i < 2; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
}
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs = array(
$res[1] & 0xffff,
$res[0] & 0xffff
);
if (count($res) > 2) {
$return->overflow = $res[2];
}
return $return;
}
/**
* @param int $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function mulInt($int = 0, $size = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int,
'int', 1);
ParagonIE_Sodium_Core32_Util::declareScalarType($size,
'int', 2);
if (ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulIntFast((int) $int);
}
/** @var int $int */
$int = (int) $int;
/** @var int $size */
$size = (int) $size;
if (!$size) {
$size = 31;
}
/** @var int $size */
$a = clone $this;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
/** @var int $size */
/** @var int $i */
for ($i = $size; $i >= 0; --$i) {
$m = (int) (-($int & 1));
$x0 = $a0 & $m;
$x1 = $a1 & $m;
$ret1 += $x1;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$a1 = ($a1 << 1);
$x1 = $a1 >> 16;
$a0 = ($a0 << 1) | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$int >>= 1;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int32 $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function mulInt32(ParagonIE_Sodium_Core32_Int32 $int, $size = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($size,
'int', 2);
if (ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulInt32Fast($int);
}
if (!$size) {
$size = 31;
}
/** @var int $size */
$a = clone $this;
$b = clone $int;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
$b0 = $b->limbs[0];
$b1 = $b->limbs[1];
/** @var int $size */
/** @var int $i */
for ($i = $size; $i >= 0; --$i) {
$m = (int) (-($b1 & 1));
$x0 = $a0 & $m;
$x1 = $a1 & $m;
$ret1 += $x1;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$a1 = ($a1 << 1);
$x1 = $a1 >> 16;
$a0 = ($a0 << 1) | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$x0 = ($b0 & 1) << 16;
$b0 = ($b0 >> 1);
$b1 = (($b1 | $x0) >> 1);
$b0 &= 0xffff;
$b1 &= 0xffff;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
return $return;
}
/**
* OR this 32-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int32 $b
* @return ParagonIE_Sodium_Core32_Int32
*/
public function orInt32(ParagonIE_Sodium_Core32_Int32 $b)
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array(
(int) ($this->limbs[0] | $b->limbs[0]),
(int) ($this->limbs[1] | $b->limbs[1])
);
/** @var int overflow */
$return->overflow = $this->overflow | $b->overflow;
return $return;
}
/**
* @param int $b
* @return bool
*/
public function isGreaterThan($b = 0)
{
return $this->compareInt($b) > 0;
}
/**
* @param int $b
* @return bool
*/
public function isLessThanInt($b = 0)
{
return $this->compareInt($b) < 0;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateLeft($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c,
'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 31;
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var int $c */
/** @var int $idx_shift */
$idx_shift = ($c >> 4) & 1;
/** @var int $sub_shift */
$sub_shift = $c & 15;
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
for ($i = 1; $i >= 0; --$i) {
/** @var int $j */
$j = ($i + $idx_shift) & 1;
/** @var int $k */
$k = ($i + $idx_shift + 1) & 1;
$limbs[$i] = (int) (
(
((int) ($myLimbs[$j]) << $sub_shift)
|
((int) ($myLimbs[$k]) >> (16 - $sub_shift))
) & 0xffff
);
}
}
return $return;
}
/**
* Rotate to the right
*
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateRight($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c,
'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 31;
/** @var int $c */
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var int $c */
/** @var int $idx_shift */
$idx_shift = ($c >> 4) & 1;
/** @var int $sub_shift */
$sub_shift = $c & 15;
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
for ($i = 1; $i >= 0; --$i) {
/** @var int $j */
$j = ($i - $idx_shift) & 1;
/** @var int $k */
$k = ($i - $idx_shift - 1) & 1;
$limbs[$i] = (int) (
(
((int) ($myLimbs[$j]) >> (int) ($sub_shift))
|
((int) ($myLimbs[$k]) << (16 - (int)
($sub_shift)))
) & 0xffff
);
}
}
return $return;
}
/**
* @param bool $bool
* @return self
*/
public function setUnsignedInt($bool = false)
{
$this->unsignedInt = !empty($bool);
return $this;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function shiftLeft($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c,
'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
/** @var int $c */
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
/** @var int $c */
return $this->shiftRight(-$c);
} else {
/** @var int $c */
/** @var int $tmp */
$tmp = $this->limbs[1] << $c;
$return->limbs[1] = (int)($tmp & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
/** @var int $tmp */
$tmp = ($this->limbs[0] << $c) | ($carry &
0xffff);
$return->limbs[0] = (int) ($tmp & 0xffff);
}
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
public function shiftRight($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c,
'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
/** @var int $c */
if ($c >= 16) {
$return->limbs = array(
(int) ($this->overflow & 0xffff),
(int) ($this->limbs[0])
);
$return->overflow = $this->overflow >> 16;
return $return->shiftRight($c & 15);
}
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
/** @var int $c */
return $this->shiftLeft(-$c);
} else {
if (!is_int($c)) {
throw new TypeError();
}
/** @var int $c */
// $return->limbs[0] = (int) (($this->limbs[0] >>
$c) & 0xffff);
$carryLeft = (int) ($this->overflow & ((1 << ($c +
1)) - 1));
$return->limbs[0] = (int) ((($this->limbs[0] >> $c)
| ($carryLeft << (16 - $c))) & 0xffff);
$carryRight = (int) ($this->limbs[0] & ((1 << ($c
+ 1)) - 1));
$return->limbs[1] = (int) ((($this->limbs[1] >> $c)
| ($carryRight << (16 - $c))) & 0xffff);
$return->overflow >>= $c;
}
return $return;
}
/**
* Subtract a normal integer from an int32 object.
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function subInt($int)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int,
'int', 1);
/** @var int $int */
$int = (int) $int;
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
/** @var int $tmp */
$tmp = $this->limbs[1] - ($int & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[1] = (int) ($tmp & 0xffff);
/** @var int $tmp */
$tmp = $this->limbs[0] - (($int >> 16) & 0xffff) +
$carry;
$return->limbs[0] = (int) ($tmp & 0xffff);
return $return;
}
/**
* Subtract two int32 objects from each other
*
* @param ParagonIE_Sodium_Core32_Int32 $b
* @return ParagonIE_Sodium_Core32_Int32
*/
public function subInt32(ParagonIE_Sodium_Core32_Int32 $b)
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
/** @var int $tmp */
$tmp = $this->limbs[1] - ($b->limbs[1] & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[1] = (int) ($tmp & 0xffff);
/** @var int $tmp */
$tmp = $this->limbs[0] - ($b->limbs[0] & 0xffff) +
$carry;
$return->limbs[0] = (int) ($tmp & 0xffff);
return $return;
}
/**
* XOR this 32-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int32 $b
* @return ParagonIE_Sodium_Core32_Int32
*/
public function xorInt32(ParagonIE_Sodium_Core32_Int32 $b)
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array(
(int) ($this->limbs[0] ^ $b->limbs[0]),
(int) ($this->limbs[1] ^ $b->limbs[1])
);
return $return;
}
/**
* @param int $signed
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromInt($signed)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($signed,
'int', 1);;
/** @var int $signed */
$signed = (int) $signed;
return new ParagonIE_Sodium_Core32_Int32(
array(
(int) (($signed >> 16) & 0xffff),
(int) ($signed & 0xffff)
)
);
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromString($string)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($string,
'string', 1);
$string = (string) $string;
if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) {
throw new RangeException(
'String must be 4 bytes; ' .
ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
);
}
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) <<
8);
$return->limbs[0] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff);
$return->limbs[1] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) <<
8);
$return->limbs[1] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff);
return $return;
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromReverseString($string)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($string,
'string', 1);
$string = (string) $string;
if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) {
throw new RangeException(
'String must be 4 bytes; ' .
ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
);
}
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) <<
8);
$return->limbs[0] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff);
$return->limbs[1] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) <<
8);
$return->limbs[1] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff);
return $return;
}
/**
* @return array<int, int>
*/
public function toArray()
{
return array((int) ($this->limbs[0] << 16 |
$this->limbs[1]));
}
/**
* @return string
* @throws TypeError
*/
public function toString()
{
return
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] &
0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] &
0xff);
}
/**
* @return int
*/
public function toInt()
{
return (int) (
(($this->limbs[0] & 0xffff) << 16)
|
($this->limbs[1] & 0xffff)
);
}
/**
* @return ParagonIE_Sodium_Core32_Int32
*/
public function toInt32()
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) ($this->limbs[0] & 0xffff);
$return->limbs[1] = (int) ($this->limbs[1] & 0xffff);
$return->unsignedInt = $this->unsignedInt;
$return->overflow = (int) ($this->overflow & 0x7fffffff);
return $return;
}
/**
* @return ParagonIE_Sodium_Core32_Int64
*/
public function toInt64()
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
if ($this->unsignedInt) {
$return->limbs[0] += (($this->overflow >> 16) &
0xffff);
$return->limbs[1] += (($this->overflow) & 0xffff);
} else {
$neg = -(($this->limbs[0] >> 15) & 1);
$return->limbs[0] = (int)($neg & 0xffff);
$return->limbs[1] = (int)($neg & 0xffff);
}
$return->limbs[2] = (int) ($this->limbs[0] & 0xffff);
$return->limbs[3] = (int) ($this->limbs[1] & 0xffff);
return $return;
}
/**
* @return string
* @throws TypeError
*/
public function toReverseString()
{
return ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1]
& 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] &
0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0]
>> 8) & 0xff);
}
/**
* @return string
*/
public function __toString()
{
try {
return $this->toString();
} catch (TypeError $ex) {
// PHP engine can't handle exceptions from __toString()
return '';
}
}
}
<?php
/**
* Class ParagonIE_Sodium_Core32_Int64
*
* Encapsulates a 64-bit integer.
*
* These are immutable. It always returns a new instance.
*/
class ParagonIE_Sodium_Core32_Int64
{
/**
* @var array<int, int> - four 16-bit integers
*/
public $limbs = array(0, 0, 0, 0);
/**
* @var int
*/
public $overflow = 0;
/**
* @var bool
*/
public $unsignedInt = false;
/**
* ParagonIE_Sodium_Core32_Int64 constructor.
* @param array $array
* @param bool $unsignedInt
*/
public function __construct($array = array(0, 0, 0, 0), $unsignedInt =
false)
{
$this->limbs = array(
(int) $array[0],
(int) $array[1],
(int) $array[2],
(int) $array[3]
);
$this->overflow = 0;
$this->unsignedInt = $unsignedInt;
}
/**
* Adds two int64 objects
*
* @param ParagonIE_Sodium_Core32_Int64 $addend
* @return ParagonIE_Sodium_Core32_Int64
*/
public function addInt64(ParagonIE_Sodium_Core32_Int64 $addend)
{
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$i2 = $this->limbs[2];
$i3 = $this->limbs[3];
$j0 = $addend->limbs[0];
$j1 = $addend->limbs[1];
$j2 = $addend->limbs[2];
$j3 = $addend->limbs[3];
$r3 = $i3 + ($j3 & 0xffff);
$carry = $r3 >> 16;
$r2 = $i2 + ($j2 & 0xffff) + $carry;
$carry = $r2 >> 16;
$r1 = $i1 + ($j1 & 0xffff) + $carry;
$carry = $r1 >> 16;
$r0 = $i0 + ($j0 & 0xffff) + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$r2 &= 0xffff;
$r3 &= 0xffff;
$return = new ParagonIE_Sodium_Core32_Int64(
array($r0, $r1, $r2, $r3)
);
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* Adds a normal integer to an int64 object
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function addInt($int)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int,
'int', 1);
/** @var int $int */
$int = (int) $int;
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$i2 = $this->limbs[2];
$i3 = $this->limbs[3];
$r3 = $i3 + ($int & 0xffff);
$carry = $r3 >> 16;
$r2 = $i2 + (($int >> 16) & 0xffff) + $carry;
$carry = $r2 >> 16;
$r1 = $i1 + $carry;
$carry = $r1 >> 16;
$r0 = $i0 + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$r2 &= 0xffff;
$r3 &= 0xffff;
$return = new ParagonIE_Sodium_Core32_Int64(
array($r0, $r1, $r2, $r3)
);
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param int $b
* @return int
*/
public function compareInt($b = 0)
{
$gt = 0;
$eq = 1;
$i = 4;
$j = 0;
while ($i > 0) {
--$i;
/** @var int $x1 */
$x1 = $this->limbs[$i];
/** @var int $x2 */
$x2 = ($b >> ($j << 4)) & 0xffff;
/** int */
$gt |= (($x2 - $x1) >> 8) & $eq;
/** int */
$eq &= (($x2 ^ $x1) - 1) >> 8;
}
return ($gt + $gt - $eq) + 1;
}
/**
* @param int $b
* @return bool
*/
public function isGreaterThan($b = 0)
{
return $this->compareInt($b) > 0;
}
/**
* @param int $b
* @return bool
*/
public function isLessThanInt($b = 0)
{
return $this->compareInt($b) < 0;
}
/**
* @param int $hi
* @param int $lo
* @return ParagonIE_Sodium_Core32_Int64
*/
public function mask64($hi = 0, $lo = 0)
{
/** @var int $a */
$a = ($hi >> 16) & 0xffff;
/** @var int $b */
$b = ($hi) & 0xffff;
/** @var int $c */
$c = ($lo >> 16) & 0xffff;
/** @var int $d */
$d = ($lo & 0xffff);
return new ParagonIE_Sodium_Core32_Int64(
array(
$this->limbs[0] & $a,
$this->limbs[1] & $b,
$this->limbs[2] & $c,
$this->limbs[3] & $d
),
$this->unsignedInt
);
}
/**
* @param int $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
*/
public function mulInt($int = 0, $size = 0)
{
if (ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulIntFast($int);
}
ParagonIE_Sodium_Core32_Util::declareScalarType($int,
'int', 1);
ParagonIE_Sodium_Core32_Util::declareScalarType($size,
'int', 2);
/** @var int $int */
$int = (int) $int;
/** @var int $size */
$size = (int) $size;
if (!$size) {
$size = 63;
}
$a = clone $this;
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$ret2 = 0;
$ret3 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
$a2 = $a->limbs[2];
$a3 = $a->limbs[3];
/** @var int $size */
/** @var int $i */
for ($i = $size; $i >= 0; --$i) {
$mask = -($int & 1);
$x0 = $a0 & $mask;
$x1 = $a1 & $mask;
$x2 = $a2 & $mask;
$x3 = $a3 & $mask;
$ret3 += $x3;
$c = $ret3 >> 16;
$ret2 += $x2 + $c;
$c = $ret2 >> 16;
$ret1 += $x1 + $c;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$ret2 &= 0xffff;
$ret3 &= 0xffff;
$a3 = $a3 << 1;
$x3 = $a3 >> 16;
$a2 = ($a2 << 1) | $x3;
$x2 = $a2 >> 16;
$a1 = ($a1 << 1) | $x2;
$x1 = $a1 >> 16;
$a0 = ($a0 << 1) | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$a2 &= 0xffff;
$a3 &= 0xffff;
$int >>= 1;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
$return->limbs[2] = $ret2;
$return->limbs[3] = $ret3;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int64 $A
* @param ParagonIE_Sodium_Core32_Int64 $B
* @return array<int, ParagonIE_Sodium_Core32_Int64>
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedInferredReturnType
*/
public static function ctSelect(
ParagonIE_Sodium_Core32_Int64 $A,
ParagonIE_Sodium_Core32_Int64 $B
) {
$a = clone $A;
$b = clone $B;
/** @var int $aNeg */
$aNeg = ($a->limbs[0] >> 15) & 1;
/** @var int $bNeg */
$bNeg = ($b->limbs[0] >> 15) & 1;
/** @var int $m */
$m = (-($aNeg & $bNeg)) | 1;
/** @var int $swap */
$swap = $bNeg & ~$aNeg;
/** @var int $d */
$d = -$swap;
/*
if ($bNeg && !$aNeg) {
$a = clone $int;
$b = clone $this;
} elseif($bNeg && $aNeg) {
$a = $this->mulInt(-1);
$b = $int->mulInt(-1);
}
*/
$x = $a->xorInt64($b)->mask64($d, $d);
return array(
$a->xorInt64($x)->mulInt($m),
$b->xorInt64($x)->mulInt($m)
);
}
/**
* @param array<int, int> $a
* @param array<int, int> $b
* @param int $baseLog2
* @return array<int, int>
*/
public function multiplyLong(array $a, array $b, $baseLog2 = 16)
{
$a_l = count($a);
$b_l = count($b);
/** @var array<int, int> $r */
$r = array_fill(0, $a_l + $b_l + 1, 0);
$base = 1 << $baseLog2;
for ($i = 0; $i < $a_l; ++$i) {
$a_i = $a[$i];
for ($j = 0; $j < $a_l; ++$j) {
$b_j = $b[$j];
$product = ($a_i * $b_j) + $r[$i + $j];
$carry = ($product >> $baseLog2 & 0xffff);
$r[$i + $j] = ($product - (int) ($carry * $base)) &
0xffff;
$r[$i + $j + 1] += $carry;
}
}
return array_slice($r, 0, 5);
}
/**
* @param int $int
* @return ParagonIE_Sodium_Core32_Int64
*/
public function mulIntFast($int)
{
// Handle negative numbers
$aNeg = ($this->limbs[0] >> 15) & 1;
$bNeg = ($int >> 31) & 1;
$a = array_reverse($this->limbs);
$b = array(
$int & 0xffff,
($int >> 16) & 0xffff,
-$bNeg & 0xffff,
-$bNeg & 0xffff
);
if ($aNeg) {
for ($i = 0; $i < 4; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 4; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
// Multiply
$res = $this->multiplyLong($a, $b);
// Re-apply negation to results
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 4; ++$i) {
$res[$i] = (0xffff ^ $res[$i]) & 0xffff;
}
// Handle integer overflow
$c = 1;
for ($i = 0; $i < 4; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
// Return our values
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs = array(
$res[3] & 0xffff,
$res[2] & 0xffff,
$res[1] & 0xffff,
$res[0] & 0xffff
);
if (count($res) > 4) {
$return->overflow = $res[4] & 0xffff;
}
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int64 $right
* @return ParagonIE_Sodium_Core32_Int64
*/
public function mulInt64Fast(ParagonIE_Sodium_Core32_Int64 $right)
{
$aNeg = ($this->limbs[0] >> 15) & 1;
$bNeg = ($right->limbs[0] >> 15) & 1;
$a = array_reverse($this->limbs);
$b = array_reverse($right->limbs);
if ($aNeg) {
for ($i = 0; $i < 4; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 4; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
$res = $this->multiplyLong($a, $b);
if ($aNeg !== $bNeg) {
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 4; ++$i) {
$res[$i] = ($res[$i] ^ 0xffff) & 0xffff;
}
$c = 1;
for ($i = 0; $i < 4; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
}
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs = array(
$res[3] & 0xffff,
$res[2] & 0xffff,
$res[1] & 0xffff,
$res[0] & 0xffff
);
if (count($res) > 4) {
$return->overflow = $res[4];
}
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int64 $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
*/
public function mulInt64(ParagonIE_Sodium_Core32_Int64 $int, $size = 0)
{
if (ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulInt64Fast($int);
}
ParagonIE_Sodium_Core32_Util::declareScalarType($size,
'int', 2);
if (!$size) {
$size = 63;
}
list($a, $b) = self::ctSelect($this, $int);
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$ret2 = 0;
$ret3 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
$a2 = $a->limbs[2];
$a3 = $a->limbs[3];
$b0 = $b->limbs[0];
$b1 = $b->limbs[1];
$b2 = $b->limbs[2];
$b3 = $b->limbs[3];
/** @var int $size */
/** @var int $i */
for ($i = (int) $size; $i >= 0; --$i) {
$mask = -($b3 & 1);
$x0 = $a0 & $mask;
$x1 = $a1 & $mask;
$x2 = $a2 & $mask;
$x3 = $a3 & $mask;
$ret3 += $x3;
$c = $ret3 >> 16;
$ret2 += $x2 + $c;
$c = $ret2 >> 16;
$ret1 += $x1 + $c;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$ret2 &= 0xffff;
$ret3 &= 0xffff;
$a3 = $a3 << 1;
$x3 = $a3 >> 16;
$a2 = ($a2 << 1) | $x3;
$x2 = $a2 >> 16;
$a1 = ($a1 << 1) | $x2;
$x1 = $a1 >> 16;
$a0 = ($a0 << 1) | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$a2 &= 0xffff;
$a3 &= 0xffff;
$x0 = ($b0 & 1) << 16;
$x1 = ($b1 & 1) << 16;
$x2 = ($b2 & 1) << 16;
$b0 = ($b0 >> 1);
$b1 = (($b1 | $x0) >> 1);
$b2 = (($b2 | $x1) >> 1);
$b3 = (($b3 | $x2) >> 1);
$b0 &= 0xffff;
$b1 &= 0xffff;
$b2 &= 0xffff;
$b3 &= 0xffff;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
$return->limbs[2] = $ret2;
$return->limbs[3] = $ret3;
return $return;
}
/**
* OR this 64-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int64 $b
* @return ParagonIE_Sodium_Core32_Int64
*/
public function orInt64(ParagonIE_Sodium_Core32_Int64 $b)
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array(
(int) ($this->limbs[0] | $b->limbs[0]),
(int) ($this->limbs[1] | $b->limbs[1]),
(int) ($this->limbs[2] | $b->limbs[2]),
(int) ($this->limbs[3] | $b->limbs[3])
);
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateLeft($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c,
'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
/** @var int $idx_shift */
$idx_shift = ($c >> 4) & 3;
/** @var int $sub_shift */
$sub_shift = $c & 15;
for ($i = 3; $i >= 0; --$i) {
/** @var int $j */
$j = ($i + $idx_shift) & 3;
/** @var int $k */
$k = ($i + $idx_shift + 1) & 3;
$limbs[$i] = (int) (
(
((int) ($myLimbs[$j]) << $sub_shift)
|
((int) ($myLimbs[$k]) >> (16 - $sub_shift))
) & 0xffff
);
}
}
return $return;
}
/**
* Rotate to the right
*
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateRight($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c,
'int', 1);
/** @var int $c */
$c = (int) $c;
/** @var ParagonIE_Sodium_Core32_Int64 $return */
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
/** @var int $c */
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
/** @var int $idx_shift */
$idx_shift = ($c >> 4) & 3;
/** @var int $sub_shift */
$sub_shift = $c & 15;
for ($i = 3; $i >= 0; --$i) {
/** @var int $j */
$j = ($i - $idx_shift) & 3;
/** @var int $k */
$k = ($i - $idx_shift - 1) & 3;
$limbs[$i] = (int) (
(
((int) ($myLimbs[$j]) >> (int) ($sub_shift))
|
((int) ($myLimbs[$k]) << (16 - (int)
($sub_shift)))
) & 0xffff
);
}
}
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function shiftLeft($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c,
'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
if ($c >= 16) {
if ($c >= 48) {
$return->limbs = array(
$this->limbs[3], 0, 0, 0
);
} elseif ($c >= 32) {
$return->limbs = array(
$this->limbs[2], $this->limbs[3], 0, 0
);
} else {
$return->limbs = array(
$this->limbs[1], $this->limbs[2],
$this->limbs[3], 0
);
}
return $return->shiftLeft($c & 15);
}
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
/** @var int $c */
return $this->shiftRight(-$c);
} else {
if (!is_int($c)) {
throw new TypeError();
}
/** @var int $carry */
$carry = 0;
for ($i = 3; $i >= 0; --$i) {
/** @var int $tmp */
$tmp = ($this->limbs[$i] << $c) | ($carry &
0xffff);
$return->limbs[$i] = (int) ($tmp & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
}
}
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function shiftRight($c = 0)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($c,
'int', 1);
$c = (int) $c;
/** @var int $c */
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
$negative = -(($this->limbs[0] >> 15) & 1);
if ($c >= 16) {
if ($c >= 48) {
$return->limbs = array(
(int) ($negative & 0xffff),
(int) ($negative & 0xffff),
(int) ($negative & 0xffff),
(int) $this->limbs[0]
);
} elseif ($c >= 32) {
$return->limbs = array(
(int) ($negative & 0xffff),
(int) ($negative & 0xffff),
(int) $this->limbs[0],
(int) $this->limbs[1]
);
} else {
$return->limbs = array(
(int) ($negative & 0xffff),
(int) $this->limbs[0],
(int) $this->limbs[1],
(int) $this->limbs[2]
);
}
return $return->shiftRight($c & 15);
}
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
return $this->shiftLeft(-$c);
} else {
if (!is_int($c)) {
throw new TypeError();
}
/** @var int $carryRight */
$carryRight = ($negative & 0xffff);
$mask = (int) (((1 << ($c + 1)) - 1) & 0xffff);
for ($i = 0; $i < 4; ++$i) {
$return->limbs[$i] = (int) (
(($this->limbs[$i] >> $c) | ($carryRight
<< (16 - $c))) & 0xffff
);
$carryRight = (int) ($this->limbs[$i] & $mask);
}
}
return $return;
}
/**
* Subtract a normal integer from an int64 object.
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function subInt($int)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($int,
'int', 1);
$int = (int) $int;
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
/** @var int $carry */
$carry = 0;
for ($i = 3; $i >= 0; --$i) {
/** @var int $tmp */
$tmp = $this->limbs[$i] - (($int >> 16) & 0xffff)
+ $carry;
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[$i] = (int) ($tmp & 0xffff);
}
return $return;
}
/**
* The difference between two Int64 objects.
*
* @param ParagonIE_Sodium_Core32_Int64 $b
* @return ParagonIE_Sodium_Core32_Int64
*/
public function subInt64(ParagonIE_Sodium_Core32_Int64 $b)
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
/** @var int $carry */
$carry = 0;
for ($i = 3; $i >= 0; --$i) {
/** @var int $tmp */
$tmp = $this->limbs[$i] - $b->limbs[$i] + $carry;
/** @var int $carry */
$carry = ($tmp >> 16);
$return->limbs[$i] = (int) ($tmp & 0xffff);
}
return $return;
}
/**
* XOR this 64-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int64 $b
* @return ParagonIE_Sodium_Core32_Int64
*/
public function xorInt64(ParagonIE_Sodium_Core32_Int64 $b)
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array(
(int) ($this->limbs[0] ^ $b->limbs[0]),
(int) ($this->limbs[1] ^ $b->limbs[1]),
(int) ($this->limbs[2] ^ $b->limbs[2]),
(int) ($this->limbs[3] ^ $b->limbs[3])
);
return $return;
}
/**
* @param int $low
* @param int $high
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromInts($low, $high)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($low,
'int', 1);
ParagonIE_Sodium_Core32_Util::declareScalarType($high,
'int', 2);
$high = (int) $high;
$low = (int) $low;
return new ParagonIE_Sodium_Core32_Int64(
array(
(int) (($high >> 16) & 0xffff),
(int) ($high & 0xffff),
(int) (($low >> 16) & 0xffff),
(int) ($low & 0xffff)
)
);
}
/**
* @param int $low
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromInt($low)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($low,
'int', 1);
$low = (int) $low;
return new ParagonIE_Sodium_Core32_Int64(
array(
0,
0,
(int) (($low >> 16) & 0xffff),
(int) ($low & 0xffff)
)
);
}
/**
* @return int
*/
public function toInt()
{
return (int) (
(($this->limbs[2] & 0xffff) << 16)
|
($this->limbs[3] & 0xffff)
);
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromString($string)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($string,
'string', 1);
$string = (string) $string;
if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 8) {
throw new RangeException(
'String must be 8 bytes; ' .
ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
);
}
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs[0] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) <<
8);
$return->limbs[0] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff);
$return->limbs[1] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) <<
8);
$return->limbs[1] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff);
$return->limbs[2] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[4]) & 0xff) <<
8);
$return->limbs[2] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[5]) & 0xff);
$return->limbs[3] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[6]) & 0xff) <<
8);
$return->limbs[3] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[7]) & 0xff);
return $return;
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromReverseString($string)
{
ParagonIE_Sodium_Core32_Util::declareScalarType($string,
'string', 1);
$string = (string) $string;
if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 8) {
throw new RangeException(
'String must be 8 bytes; ' .
ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.'
);
}
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs[0] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[7]) & 0xff) <<
8);
$return->limbs[0] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[6]) & 0xff);
$return->limbs[1] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[5]) & 0xff) <<
8);
$return->limbs[1] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[4]) & 0xff);
$return->limbs[2] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) <<
8);
$return->limbs[2] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff);
$return->limbs[3] = (int)
((ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) <<
8);
$return->limbs[3] |=
(ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff);
return $return;
}
/**
* @return array<int, int>
*/
public function toArray()
{
return array(
(int) ((($this->limbs[0] & 0xffff) << 16) |
($this->limbs[1] & 0xffff)),
(int) ((($this->limbs[2] & 0xffff) << 16) |
($this->limbs[3] & 0xffff))
);
}
/**
* @return ParagonIE_Sodium_Core32_Int32
*/
public function toInt32()
{
$return = new ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) ($this->limbs[2]);
$return->limbs[1] = (int) ($this->limbs[3]);
$return->unsignedInt = $this->unsignedInt;
$return->overflow = (int)
(ParagonIE_Sodium_Core32_Util::abs($this->limbs[1], 16) & 0xffff);
return $return;
}
/**
* @return ParagonIE_Sodium_Core32_Int64
*/
public function toInt64()
{
$return = new ParagonIE_Sodium_Core32_Int64();
$return->limbs[0] = (int) ($this->limbs[0]);
$return->limbs[1] = (int) ($this->limbs[1]);
$return->limbs[2] = (int) ($this->limbs[2]);
$return->limbs[3] = (int) ($this->limbs[3]);
$return->unsignedInt = $this->unsignedInt;
$return->overflow =
ParagonIE_Sodium_Core32_Util::abs($this->overflow);
return $return;
}
/**
* @param bool $bool
* @return self
*/
public function setUnsignedInt($bool = false)
{
$this->unsignedInt = !empty($bool);
return $this;
}
/**
* @return string
* @throws TypeError
*/
public function toString()
{
return ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] &
0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] &
0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[2]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] &
0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[3]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3] &
0xff);
}
/**
* @return string
* @throws TypeError
*/
public function toReverseString()
{
return ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3]
& 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[3]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] &
0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[2]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] &
0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1]
>> 8) & 0xff) .
ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] &
0xff) .
ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0]
>> 8) & 0xff);
}
/**
* @return string
*/
public function __toString()
{
try {
return $this->toString();
} catch (TypeError $ex) {
// PHP engine can't handle exceptions from __toString()
return '';
}
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Poly1305_State',
false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Poly1305_State
*/
class ParagonIE_Sodium_Core32_Poly1305_State extends
ParagonIE_Sodium_Core32_Util
{
/**
* @var array<int, int>
*/
protected $buffer = array();
/**
* @var bool
*/
protected $final = false;
/**
* @var array<int, ParagonIE_Sodium_Core32_Int32>
*/
public $h;
/**
* @var int
*/
protected $leftover = 0;
/**
* @var array<int, ParagonIE_Sodium_Core32_Int32>
*/
public $r;
/**
* @var array<int, ParagonIE_Sodium_Core32_Int64>
*/
public $pad;
/**
* ParagonIE_Sodium_Core32_Poly1305_State constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct($key = '')
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Poly1305 requires a 32-byte key'
);
}
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
$this->r = array(
// st->r[0] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4))
->setUnsignedInt(true)
->mask(0x3ffffff),
// st->r[1] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 3, 4))
->setUnsignedInt(true)
->shiftRight(2)
->mask(0x3ffff03),
// st->r[2] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 6, 4))
->setUnsignedInt(true)
->shiftRight(4)
->mask(0x3ffc0ff),
// st->r[3] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 9, 4))
->setUnsignedInt(true)
->shiftRight(6)
->mask(0x3f03fff),
// st->r[4] = ...
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4))
->setUnsignedInt(true)
->shiftRight(8)
->mask(0x00fffff)
);
/* h = 0 */
$this->h = array(
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true),
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true),
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true),
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true),
new ParagonIE_Sodium_Core32_Int32(array(0, 0), true)
);
/* save pad for later */
$this->pad = array(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4))
->setUnsignedInt(true)->toInt64(),
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4))
->setUnsignedInt(true)->toInt64(),
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4))
->setUnsignedInt(true)->toInt64(),
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4))
->setUnsignedInt(true)->toInt64(),
);
$this->leftover = 0;
$this->final = false;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function update($message = '')
{
$bytes = self::strlen($message);
/* handle leftover */
if ($this->leftover) {
/** @var int $want */
$want = ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE -
$this->leftover;
if ($want > $bytes) {
$want = $bytes;
}
for ($i = 0; $i < $want; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
// We snip off the leftmost bytes.
$message = self::substr($message, $want);
$bytes = self::strlen($message);
$this->leftover += $want;
if ($this->leftover <
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
// We still don't have enough to run
$this->blocks()
return $this;
}
$this->blocks(
self::intArrayToString($this->buffer),
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
);
$this->leftover = 0;
}
/* process full blocks */
if ($bytes >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
/** @var int $want */
$want = $bytes &
~(ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE - 1);
if ($want >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
/** @var string $block */
$block = self::substr($message, 0, $want);
if (self::strlen($block) >=
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
$this->blocks($block, $want);
$message = self::substr($message, $want);
$bytes = self::strlen($message);
}
}
}
/* store leftover */
if ($bytes) {
for ($i = 0; $i < $bytes; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
$this->leftover = (int) $this->leftover + $bytes;
}
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param int $bytes
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function blocks($message, $bytes)
{
if (self::strlen($message) < 16) {
$message = str_pad($message, 16, "\x00",
STR_PAD_RIGHT);
}
$hibit = ParagonIE_Sodium_Core32_Int32::fromInt((int)
($this->final ? 0 : 1 << 24)); /* 1 << 128 */
$hibit->setUnsignedInt(true);
$zero = new ParagonIE_Sodium_Core32_Int64(array(0, 0, 0, 0), true);
/**
* @var ParagonIE_Sodium_Core32_Int64 $d0
* @var ParagonIE_Sodium_Core32_Int64 $d1
* @var ParagonIE_Sodium_Core32_Int64 $d2
* @var ParagonIE_Sodium_Core32_Int64 $d3
* @var ParagonIE_Sodium_Core32_Int64 $d4
* @var ParagonIE_Sodium_Core32_Int64 $r0
* @var ParagonIE_Sodium_Core32_Int64 $r1
* @var ParagonIE_Sodium_Core32_Int64 $r2
* @var ParagonIE_Sodium_Core32_Int64 $r3
* @var ParagonIE_Sodium_Core32_Int64 $r4
*
* @var ParagonIE_Sodium_Core32_Int32 $h0
* @var ParagonIE_Sodium_Core32_Int32 $h1
* @var ParagonIE_Sodium_Core32_Int32 $h2
* @var ParagonIE_Sodium_Core32_Int32 $h3
* @var ParagonIE_Sodium_Core32_Int32 $h4
*/
$r0 = $this->r[0]->toInt64();
$r1 = $this->r[1]->toInt64();
$r2 = $this->r[2]->toInt64();
$r3 = $this->r[3]->toInt64();
$r4 = $this->r[4]->toInt64();
$s1 = $r1->toInt64()->mulInt(5, 3);
$s2 = $r2->toInt64()->mulInt(5, 3);
$s3 = $r3->toInt64()->mulInt(5, 3);
$s4 = $r4->toInt64()->mulInt(5, 3);
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
while ($bytes >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
/* h += m[i] */
$h0 = $h0->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 0,
4))
->mask(0x3ffffff)
)->toInt64();
$h1 = $h1->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 3,
4))
->shiftRight(2)
->mask(0x3ffffff)
)->toInt64();
$h2 = $h2->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 6,
4))
->shiftRight(4)
->mask(0x3ffffff)
)->toInt64();
$h3 = $h3->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 9,
4))
->shiftRight(6)
->mask(0x3ffffff)
)->toInt64();
$h4 = $h4->addInt32(
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 12,
4))
->shiftRight(8)
->orInt32($hibit)
)->toInt64();
/* h *= r */
$d0 = $zero
->addInt64($h0->mulInt64($r0, 25))
->addInt64($s4->mulInt64($h1, 26))
->addInt64($s3->mulInt64($h2, 26))
->addInt64($s2->mulInt64($h3, 26))
->addInt64($s1->mulInt64($h4, 26));
$d1 = $zero
->addInt64($h0->mulInt64($r1, 25))
->addInt64($h1->mulInt64($r0, 25))
->addInt64($s4->mulInt64($h2, 26))
->addInt64($s3->mulInt64($h3, 26))
->addInt64($s2->mulInt64($h4, 26));
$d2 = $zero
->addInt64($h0->mulInt64($r2, 25))
->addInt64($h1->mulInt64($r1, 25))
->addInt64($h2->mulInt64($r0, 25))
->addInt64($s4->mulInt64($h3, 26))
->addInt64($s3->mulInt64($h4, 26));
$d3 = $zero
->addInt64($h0->mulInt64($r3, 25))
->addInt64($h1->mulInt64($r2, 25))
->addInt64($h2->mulInt64($r1, 25))
->addInt64($h3->mulInt64($r0, 25))
->addInt64($s4->mulInt64($h4, 26));
$d4 = $zero
->addInt64($h0->mulInt64($r4, 25))
->addInt64($h1->mulInt64($r3, 25))
->addInt64($h2->mulInt64($r2, 25))
->addInt64($h3->mulInt64($r1, 25))
->addInt64($h4->mulInt64($r0, 25));
/* (partial) h %= p */
$c = $d0->shiftRight(26);
$h0 = $d0->toInt32()->mask(0x3ffffff);
$d1 = $d1->addInt64($c);
$c = $d1->shiftRight(26);
$h1 = $d1->toInt32()->mask(0x3ffffff);
$d2 = $d2->addInt64($c);
$c = $d2->shiftRight(26);
$h2 = $d2->toInt32()->mask(0x3ffffff);
$d3 = $d3->addInt64($c);
$c = $d3->shiftRight(26);
$h3 = $d3->toInt32()->mask(0x3ffffff);
$d4 = $d4->addInt64($c);
$c = $d4->shiftRight(26);
$h4 = $d4->toInt32()->mask(0x3ffffff);
$h0 = $h0->addInt32($c->toInt32()->mulInt(5, 3));
$c = $h0->shiftRight(26);
$h0 = $h0->mask(0x3ffffff);
$h1 = $h1->addInt32($c);
// Chop off the left 32 bytes.
$message = self::substr(
$message,
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
);
$bytes -= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE;
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
$this->h = array($h0, $h1, $h2, $h3, $h4);
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @return string
* @throws SodiumException
* @throws TypeError
*/
public function finish()
{
/* process the remaining block */
if ($this->leftover) {
$i = $this->leftover;
$this->buffer[$i++] = 1;
for (; $i < ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE;
++$i) {
$this->buffer[$i] = 0;
}
$this->final = true;
$this->blocks(
self::substr(
self::intArrayToString($this->buffer),
0,
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
),
$b = ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
);
}
/**
* @var ParagonIE_Sodium_Core32_Int32 $f
* @var ParagonIE_Sodium_Core32_Int32 $g0
* @var ParagonIE_Sodium_Core32_Int32 $g1
* @var ParagonIE_Sodium_Core32_Int32 $g2
* @var ParagonIE_Sodium_Core32_Int32 $g3
* @var ParagonIE_Sodium_Core32_Int32 $g4
* @var ParagonIE_Sodium_Core32_Int32 $h0
* @var ParagonIE_Sodium_Core32_Int32 $h1
* @var ParagonIE_Sodium_Core32_Int32 $h2
* @var ParagonIE_Sodium_Core32_Int32 $h3
* @var ParagonIE_Sodium_Core32_Int32 $h4
*/
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
$c = $h1->shiftRight(26); # $c = $h1 >> 26;
$h1 = $h1->mask(0x3ffffff); # $h1 &= 0x3ffffff;
$h2 = $h2->addInt32($c); # $h2 += $c;
$c = $h2->shiftRight(26); # $c = $h2 >> 26;
$h2 = $h2->mask(0x3ffffff); # $h2 &= 0x3ffffff;
$h3 = $h3->addInt32($c); # $h3 += $c;
$c = $h3->shiftRight(26); # $c = $h3 >> 26;
$h3 = $h3->mask(0x3ffffff); # $h3 &= 0x3ffffff;
$h4 = $h4->addInt32($c); # $h4 += $c;
$c = $h4->shiftRight(26); # $c = $h4 >> 26;
$h4 = $h4->mask(0x3ffffff); # $h4 &= 0x3ffffff;
$h0 = $h0->addInt32($c->mulInt(5, 3)); # $h0 += self::mul($c,
5);
$c = $h0->shiftRight(26); # $c = $h0 >> 26;
$h0 = $h0->mask(0x3ffffff); # $h0 &= 0x3ffffff;
$h1 = $h1->addInt32($c); # $h1 += $c;
/* compute h + -p */
$g0 = $h0->addInt(5);
$c = $g0->shiftRight(26);
$g0 = $g0->mask(0x3ffffff);
$g1 = $h1->addInt32($c);
$c = $g1->shiftRight(26);
$g1 = $g1->mask(0x3ffffff);
$g2 = $h2->addInt32($c);
$c = $g2->shiftRight(26);
$g2 = $g2->mask(0x3ffffff);
$g3 = $h3->addInt32($c);
$c = $g3->shiftRight(26);
$g3 = $g3->mask(0x3ffffff);
$g4 = $h4->addInt32($c)->subInt(1 << 26);
# $mask = ($g4 >> 31) - 1;
/* select h if h < p, or h + -p if h >= p */
$mask = (int) (($g4->toInt() >> 31) + 1);
$g0 = $g0->mask($mask);
$g1 = $g1->mask($mask);
$g2 = $g2->mask($mask);
$g3 = $g3->mask($mask);
$g4 = $g4->mask($mask);
/** @var int $mask */
$mask = (~$mask) & 0xffffffff;
$h0 = $h0->mask($mask)->orInt32($g0);
$h1 = $h1->mask($mask)->orInt32($g1);
$h2 = $h2->mask($mask)->orInt32($g2);
$h3 = $h3->mask($mask)->orInt32($g3);
$h4 = $h4->mask($mask)->orInt32($g4);
/* h = h % (2^128) */
$h0 = $h0->orInt32($h1->shiftLeft(26));
$h1 = $h1->shiftRight(6)->orInt32($h2->shiftLeft(20));
$h2 = $h2->shiftRight(12)->orInt32($h3->shiftLeft(14));
$h3 = $h3->shiftRight(18)->orInt32($h4->shiftLeft(8));
/* mac = (h + pad) % (2^128) */
$f = $h0->toInt64()->addInt64($this->pad[0]);
$h0 = $f->toInt32();
$f =
$h1->toInt64()->addInt64($this->pad[1])->addInt($h0->overflow);
$h1 = $f->toInt32();
$f =
$h2->toInt64()->addInt64($this->pad[2])->addInt($h1->overflow);
$h2 = $f->toInt32();
$f =
$h3->toInt64()->addInt64($this->pad[3])->addInt($h2->overflow);
$h3 = $f->toInt32();
return $h0->toReverseString() .
$h1->toReverseString() .
$h2->toReverseString() .
$h3->toReverseString();
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Poly1305', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Poly1305
*/
abstract class ParagonIE_Sodium_Core32_Poly1305 extends
ParagonIE_Sodium_Core32_Util
{
const BLOCK_SIZE = 16;
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth($m, $key)
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
self::substr($key, 0, 32)
);
return $state
->update($m)
->finish();
}
/**
* @internal You should not use this directly from another application
*
* @param string $mac
* @param string $m
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth_verify($mac, $m, $key)
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
self::substr($key, 0, 32)
);
$calc = $state
->update($m)
->finish();
return self::verify_16($calc, $mac);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Salsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Salsa20
*/
abstract class ParagonIE_Sodium_Core32_Salsa20 extends
ParagonIE_Sodium_Core32_Util
{
const ROUNDS = 20;
/**
* Calculate an salsa20 hash of a single block
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function core_salsa20($in, $k, $c = null)
{
/**
* @var ParagonIE_Sodium_Core32_Int32 $x0
* @var ParagonIE_Sodium_Core32_Int32 $x1
* @var ParagonIE_Sodium_Core32_Int32 $x2
* @var ParagonIE_Sodium_Core32_Int32 $x3
* @var ParagonIE_Sodium_Core32_Int32 $x4
* @var ParagonIE_Sodium_Core32_Int32 $x5
* @var ParagonIE_Sodium_Core32_Int32 $x6
* @var ParagonIE_Sodium_Core32_Int32 $x7
* @var ParagonIE_Sodium_Core32_Int32 $x8
* @var ParagonIE_Sodium_Core32_Int32 $x9
* @var ParagonIE_Sodium_Core32_Int32 $x10
* @var ParagonIE_Sodium_Core32_Int32 $x11
* @var ParagonIE_Sodium_Core32_Int32 $x12
* @var ParagonIE_Sodium_Core32_Int32 $x13
* @var ParagonIE_Sodium_Core32_Int32 $x14
* @var ParagonIE_Sodium_Core32_Int32 $x15
* @var ParagonIE_Sodium_Core32_Int32 $j0
* @var ParagonIE_Sodium_Core32_Int32 $j1
* @var ParagonIE_Sodium_Core32_Int32 $j2
* @var ParagonIE_Sodium_Core32_Int32 $j3
* @var ParagonIE_Sodium_Core32_Int32 $j4
* @var ParagonIE_Sodium_Core32_Int32 $j5
* @var ParagonIE_Sodium_Core32_Int32 $j6
* @var ParagonIE_Sodium_Core32_Int32 $j7
* @var ParagonIE_Sodium_Core32_Int32 $j8
* @var ParagonIE_Sodium_Core32_Int32 $j9
* @var ParagonIE_Sodium_Core32_Int32 $j10
* @var ParagonIE_Sodium_Core32_Int32 $j11
* @var ParagonIE_Sodium_Core32_Int32 $j12
* @var ParagonIE_Sodium_Core32_Int32 $j13
* @var ParagonIE_Sodium_Core32_Int32 $j14
* @var ParagonIE_Sodium_Core32_Int32 $j15
*/
if (self::strlen($k) < 32) {
throw new RangeException('Key must be 32 bytes
long');
}
if ($c === null) {
$x0 = new ParagonIE_Sodium_Core32_Int32(array(0x6170,
0x7865));
$x5 = new ParagonIE_Sodium_Core32_Int32(array(0x3320,
0x646e));
$x10 = new ParagonIE_Sodium_Core32_Int32(array(0x7962,
0x2d32));
$x15 = new ParagonIE_Sodium_Core32_Int32(array(0x6b20,
0x6574));
} else {
$x0 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4));
$x5 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4));
$x10 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4));
$x15 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4));
}
$x1 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 0, 4));
$x2 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 4, 4));
$x3 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 8, 4));
$x4 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 12, 4));
$x6 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4));
$x7 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4));
$x8 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4));
$x9 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4));
$x11 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 16, 4));
$x12 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 20, 4));
$x13 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 24, 4));
$x14 =
ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 28, 4));
$j0 = clone $x0;
$j1 = clone $x1;
$j2 = clone $x2;
$j3 = clone $x3;
$j4 = clone $x4;
$j5 = clone $x5;
$j6 = clone $x6;
$j7 = clone $x7;
$j8 = clone $x8;
$j9 = clone $x9;
$j10 = clone $x10;
$j11 = clone $x11;
$j12 = clone $x12;
$j13 = clone $x13;
$j14 = clone $x14;
$j15 = clone $x15;
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 =
$x4->xorInt32($x0->addInt32($x12)->rotateLeft(7));
$x8 =
$x8->xorInt32($x4->addInt32($x0)->rotateLeft(9));
$x12 =
$x12->xorInt32($x8->addInt32($x4)->rotateLeft(13));
$x0 =
$x0->xorInt32($x12->addInt32($x8)->rotateLeft(18));
$x9 =
$x9->xorInt32($x5->addInt32($x1)->rotateLeft(7));
$x13 =
$x13->xorInt32($x9->addInt32($x5)->rotateLeft(9));
$x1 =
$x1->xorInt32($x13->addInt32($x9)->rotateLeft(13));
$x5 =
$x5->xorInt32($x1->addInt32($x13)->rotateLeft(18));
$x14 =
$x14->xorInt32($x10->addInt32($x6)->rotateLeft(7));
$x2 =
$x2->xorInt32($x14->addInt32($x10)->rotateLeft(9));
$x6 =
$x6->xorInt32($x2->addInt32($x14)->rotateLeft(13));
$x10 =
$x10->xorInt32($x6->addInt32($x2)->rotateLeft(18));
$x3 =
$x3->xorInt32($x15->addInt32($x11)->rotateLeft(7));
$x7 =
$x7->xorInt32($x3->addInt32($x15)->rotateLeft(9));
$x11 =
$x11->xorInt32($x7->addInt32($x3)->rotateLeft(13));
$x15 =
$x15->xorInt32($x11->addInt32($x7)->rotateLeft(18));
$x1 =
$x1->xorInt32($x0->addInt32($x3)->rotateLeft(7));
$x2 =
$x2->xorInt32($x1->addInt32($x0)->rotateLeft(9));
$x3 =
$x3->xorInt32($x2->addInt32($x1)->rotateLeft(13));
$x0 =
$x0->xorInt32($x3->addInt32($x2)->rotateLeft(18));
$x6 =
$x6->xorInt32($x5->addInt32($x4)->rotateLeft(7));
$x7 =
$x7->xorInt32($x6->addInt32($x5)->rotateLeft(9));
$x4 =
$x4->xorInt32($x7->addInt32($x6)->rotateLeft(13));
$x5 =
$x5->xorInt32($x4->addInt32($x7)->rotateLeft(18));
$x11 =
$x11->xorInt32($x10->addInt32($x9)->rotateLeft(7));
$x8 =
$x8->xorInt32($x11->addInt32($x10)->rotateLeft(9));
$x9 =
$x9->xorInt32($x8->addInt32($x11)->rotateLeft(13));
$x10 =
$x10->xorInt32($x9->addInt32($x8)->rotateLeft(18));
$x12 =
$x12->xorInt32($x15->addInt32($x14)->rotateLeft(7));
$x13 =
$x13->xorInt32($x12->addInt32($x15)->rotateLeft(9));
$x14 =
$x14->xorInt32($x13->addInt32($x12)->rotateLeft(13));
$x15 =
$x15->xorInt32($x14->addInt32($x13)->rotateLeft(18));
}
$x0 = $x0->addInt32($j0);
$x1 = $x1->addInt32($j1);
$x2 = $x2->addInt32($j2);
$x3 = $x3->addInt32($j3);
$x4 = $x4->addInt32($j4);
$x5 = $x5->addInt32($j5);
$x6 = $x6->addInt32($j6);
$x7 = $x7->addInt32($j7);
$x8 = $x8->addInt32($j8);
$x9 = $x9->addInt32($j9);
$x10 = $x10->addInt32($j10);
$x11 = $x11->addInt32($j11);
$x12 = $x12->addInt32($j12);
$x13 = $x13->addInt32($j13);
$x14 = $x14->addInt32($j14);
$x15 = $x15->addInt32($j15);
return $x0->toReverseString() .
$x1->toReverseString() .
$x2->toReverseString() .
$x3->toReverseString() .
$x4->toReverseString() .
$x5->toReverseString() .
$x6->toReverseString() .
$x7->toReverseString() .
$x8->toReverseString() .
$x9->toReverseString() .
$x10->toReverseString() .
$x11->toReverseString() .
$x12->toReverseString() .
$x13->toReverseString() .
$x14->toReverseString() .
$x15->toReverseString();
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20($len, $nonce, $key)
{
if (self::strlen($key) !== 32) {
throw new RangeException('Key must be 32 bytes
long');
}
$kcopy = '' . $key;
$in = self::substr($nonce, 0, 8) . str_repeat("\0", 8);
$c = '';
while ($len >= 64) {
$c .= self::core_salsa20($in, $kcopy, null);
$u = 1;
// Internal counter.
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$len -= 64;
}
if ($len > 0) {
$c .= self::substr(
self::core_salsa20($in, $kcopy, null),
0,
$len
);
}
try {
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException $ex) {
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $n
* @param int $ic
* @param string $k
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor_ic($m, $n, $ic, $k)
{
$mlen = self::strlen($m);
if ($mlen < 1) {
return '';
}
$kcopy = self::substr($k, 0, 32);
$in = self::substr($n, 0, 8);
// Initialize the counter
$in .= ParagonIE_Sodium_Core32_Util::store64_le($ic);
$c = '';
while ($mlen >= 64) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(
self::substr($m, 0, 64),
self::substr($block, 0, 64)
);
$u = 1;
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$mlen -= 64;
$m = self::substr($m, 64);
}
if ($mlen) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(
self::substr($m, 0, $mlen),
self::substr($block, 0, $mlen)
);
}
try {
ParagonIE_Sodium_Compat::memzero($block);
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException $ex) {
$block = null;
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor($message, $nonce, $key)
{
return self::xorStrings(
$message,
self::salsa20(
self::strlen($message),
$nonce,
$key
)
);
}
}
<?php
/**
* Class ParagonIE_Sodium_Core32_SecretStream_State
*/
class ParagonIE_Sodium_Core32_SecretStream_State
{
/** @var string $key */
protected $key;
/** @var int $counter */
protected $counter;
/** @var string $nonce */
protected $nonce;
/** @var string $_pad */
protected $_pad;
/**
* ParagonIE_Sodium_Core32_SecretStream_State constructor.
* @param string $key
* @param string|null $nonce
*/
public function __construct($key, $nonce = null)
{
$this->key = $key;
$this->counter = 1;
if (is_null($nonce)) {
$nonce = str_repeat("\0", 12);
}
$this->nonce = str_pad($nonce, 12, "\0",
STR_PAD_RIGHT);;
$this->_pad = str_repeat("\0", 4);
}
/**
* @return self
*/
public function counterReset()
{
$this->counter = 1;
$this->_pad = str_repeat("\0", 4);
return $this;
}
/**
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* @return string
*/
public function getCounter()
{
return ParagonIE_Sodium_Core32_Util::store32_le($this->counter);
}
/**
* @return string
*/
public function getNonce()
{
if (!is_string($this->nonce)) {
$this->nonce = str_repeat("\0", 12);
}
if (ParagonIE_Sodium_Core32_Util::strlen($this->nonce) !== 12) {
$this->nonce = str_pad($this->nonce, 12, "\0",
STR_PAD_RIGHT);
}
return $this->nonce;
}
/**
* @return string
*/
public function getCombinedNonce()
{
return $this->getCounter() .
ParagonIE_Sodium_Core32_Util::substr($this->getNonce(), 0,
8);
}
/**
* @return self
*/
public function incrementCounter()
{
++$this->counter;
return $this;
}
/**
* @return bool
*/
public function needsRekey()
{
return ($this->counter & 0xffff) === 0;
}
/**
* @param string $newKeyAndNonce
* @return self
*/
public function rekey($newKeyAndNonce)
{
$this->key =
ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 0, 32);
$this->nonce = str_pad(
ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 32),
12,
"\0",
STR_PAD_RIGHT
);
return $this;
}
/**
* @param string $str
* @return self
*/
public function xorNonce($str)
{
$this->nonce = ParagonIE_Sodium_Core32_Util::xorStrings(
$this->getNonce(),
str_pad(
ParagonIE_Sodium_Core32_Util::substr($str, 0, 8),
12,
"\0",
STR_PAD_RIGHT
)
);
return $this;
}
/**
* @param string $string
* @return self
*/
public static function fromString($string)
{
$state = new ParagonIE_Sodium_Core32_SecretStream_State(
ParagonIE_Sodium_Core32_Util::substr($string, 0, 32)
);
$state->counter = ParagonIE_Sodium_Core32_Util::load_4(
ParagonIE_Sodium_Core32_Util::substr($string, 32, 4)
);
$state->nonce = ParagonIE_Sodium_Core32_Util::substr($string,
36, 12);
$state->_pad = ParagonIE_Sodium_Core32_Util::substr($string, 48,
8);
return $state;
}
/**
* @return string
*/
public function toString()
{
return $this->key .
$this->getCounter() .
$this->nonce .
$this->_pad;
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_SipHash', false)) {
return;
}
/**
* Class ParagonIE_SodiumCompat_Core32_SipHash
*
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit
integers
*/
class ParagonIE_Sodium_Core32_SipHash extends ParagonIE_Sodium_Core32_Util
{
/**
* @internal You should not use this directly from another application
*
* @param array<int, ParagonIE_Sodium_Core32_Int64> $v
* @return array<int, ParagonIE_Sodium_Core32_Int64>
*/
public static function sipRound(array $v)
{
# v0 += v1;
$v[0] = $v[0]->addInt64($v[1]);
# v1 = ROTL(v1, 13);
$v[1] = $v[1]->rotateLeft(13);
# v1 ^= v0;
$v[1] = $v[1]->xorInt64($v[0]);
# v0=ROTL(v0,32);
$v[0] = $v[0]->rotateLeft(32);
# v2 += v3;
$v[2] = $v[2]->addInt64($v[3]);
# v3=ROTL(v3,16);
$v[3] = $v[3]->rotateLeft(16);
# v3 ^= v2;
$v[3] = $v[3]->xorInt64($v[2]);
# v0 += v3;
$v[0] = $v[0]->addInt64($v[3]);
# v3=ROTL(v3,21);
$v[3] = $v[3]->rotateLeft(21);
# v3 ^= v0;
$v[3] = $v[3]->xorInt64($v[0]);
# v2 += v1;
$v[2] = $v[2]->addInt64($v[1]);
# v1=ROTL(v1,17);
$v[1] = $v[1]->rotateLeft(17);
# v1 ^= v2;
$v[1] = $v[1]->xorInt64($v[2]);
# v2=ROTL(v2,32)
$v[2] = $v[2]->rotateLeft(32);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sipHash24($in, $key)
{
$inlen = self::strlen($in);
# /* "somepseudorandomlygeneratedbytes" */
# u64 v0 = 0x736f6d6570736575ULL;
# u64 v1 = 0x646f72616e646f6dULL;
# u64 v2 = 0x6c7967656e657261ULL;
# u64 v3 = 0x7465646279746573ULL;
$v = array(
new ParagonIE_Sodium_Core32_Int64(
array(0x736f, 0x6d65, 0x7073, 0x6575)
),
new ParagonIE_Sodium_Core32_Int64(
array(0x646f, 0x7261, 0x6e64, 0x6f6d)
),
new ParagonIE_Sodium_Core32_Int64(
array(0x6c79, 0x6765, 0x6e65, 0x7261)
),
new ParagonIE_Sodium_Core32_Int64(
array(0x7465, 0x6462, 0x7974, 0x6573)
)
);
# u64 k0 = LOAD64_LE( k );
# u64 k1 = LOAD64_LE( k + 8 );
$k = array(
ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($key, 0, 8)
),
ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($key, 8, 8)
)
);
# b = ( ( u64 )inlen ) << 56;
$b = new ParagonIE_Sodium_Core32_Int64(
array(($inlen << 8) & 0xffff, 0, 0, 0)
);
# v3 ^= k1;
$v[3] = $v[3]->xorInt64($k[1]);
# v2 ^= k0;
$v[2] = $v[2]->xorInt64($k[0]);
# v1 ^= k1;
$v[1] = $v[1]->xorInt64($k[1]);
# v0 ^= k0;
$v[0] = $v[0]->xorInt64($k[0]);
$left = $inlen;
# for ( ; in != end; in += 8 )
while ($left >= 8) {
# m = LOAD64_LE( in );
$m = ParagonIE_Sodium_Core32_Int64::fromReverseString(
self::substr($in, 0, 8)
);
# v3 ^= m;
$v[3] = $v[3]->xorInt64($m);
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= m;
$v[0] = $v[0]->xorInt64($m);
$in = self::substr($in, 8);
$left -= 8;
}
# switch( left )
# {
# case 7: b |= ( ( u64 )in[ 6] ) << 48;
# case 6: b |= ( ( u64 )in[ 5] ) << 40;
# case 5: b |= ( ( u64 )in[ 4] ) << 32;
# case 4: b |= ( ( u64 )in[ 3] ) << 24;
# case 3: b |= ( ( u64 )in[ 2] ) << 16;
# case 2: b |= ( ( u64 )in[ 1] ) << 8;
# case 1: b |= ( ( u64 )in[ 0] ); break;
# case 0: break;
# }
switch ($left) {
case 7:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
0, self::chrToInt($in[6]) << 16
)
);
case 6:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
0, self::chrToInt($in[5]) << 8
)
);
case 5:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
0, self::chrToInt($in[4])
)
);
case 4:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
self::chrToInt($in[3]) << 24, 0
)
);
case 3:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
self::chrToInt($in[2]) << 16, 0
)
);
case 2:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
self::chrToInt($in[1]) << 8, 0
)
);
case 1:
$b = $b->orInt64(
ParagonIE_Sodium_Core32_Int64::fromInts(
self::chrToInt($in[0]), 0
)
);
case 0:
break;
}
# v3 ^= b;
$v[3] = $v[3]->xorInt64($b);
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= b;
$v[0] = $v[0]->xorInt64($b);
// Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our
implementation
# v2 ^= 0xff;
$v[2]->limbs[3] ^= 0xff;
# SIPROUND;
# SIPROUND;
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
# b = v0 ^ v1 ^ v2 ^ v3;
# STORE64_LE( out, b );
return $v[0]
->xorInt64($v[1])
->xorInt64($v[2])
->xorInt64($v[3])
->toReverseString();
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_Util', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Util
*/
abstract class ParagonIE_Sodium_Core32_Util extends
ParagonIE_Sodium_Core_Util
{
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_X25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_X25519
*/
abstract class ParagonIE_Sodium_Core32_X25519 extends
ParagonIE_Sodium_Core32_Curve25519
{
/**
* Alters the objects passed to this method in place.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @param int $b
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
*/
public static function fe_cswap(
ParagonIE_Sodium_Core32_Curve25519_Fe $f,
ParagonIE_Sodium_Core32_Curve25519_Fe $g,
$b = 0
) {
$f0 = (int) $f[0]->toInt();
$f1 = (int) $f[1]->toInt();
$f2 = (int) $f[2]->toInt();
$f3 = (int) $f[3]->toInt();
$f4 = (int) $f[4]->toInt();
$f5 = (int) $f[5]->toInt();
$f6 = (int) $f[6]->toInt();
$f7 = (int) $f[7]->toInt();
$f8 = (int) $f[8]->toInt();
$f9 = (int) $f[9]->toInt();
$g0 = (int) $g[0]->toInt();
$g1 = (int) $g[1]->toInt();
$g2 = (int) $g[2]->toInt();
$g3 = (int) $g[3]->toInt();
$g4 = (int) $g[4]->toInt();
$g5 = (int) $g[5]->toInt();
$g6 = (int) $g[6]->toInt();
$g7 = (int) $g[7]->toInt();
$g8 = (int) $g[8]->toInt();
$g9 = (int) $g[9]->toInt();
$b = -$b;
/** @var int $x0 */
$x0 = ($f0 ^ $g0) & $b;
/** @var int $x1 */
$x1 = ($f1 ^ $g1) & $b;
/** @var int $x2 */
$x2 = ($f2 ^ $g2) & $b;
/** @var int $x3 */
$x3 = ($f3 ^ $g3) & $b;
/** @var int $x4 */
$x4 = ($f4 ^ $g4) & $b;
/** @var int $x5 */
$x5 = ($f5 ^ $g5) & $b;
/** @var int $x6 */
$x6 = ($f6 ^ $g6) & $b;
/** @var int $x7 */
$x7 = ($f7 ^ $g7) & $b;
/** @var int $x8 */
$x8 = ($f8 ^ $g8) & $b;
/** @var int $x9 */
$x9 = ($f9 ^ $g9) & $b;
$f[0] = ParagonIE_Sodium_Core32_Int32::fromInt($f0 ^ $x0);
$f[1] = ParagonIE_Sodium_Core32_Int32::fromInt($f1 ^ $x1);
$f[2] = ParagonIE_Sodium_Core32_Int32::fromInt($f2 ^ $x2);
$f[3] = ParagonIE_Sodium_Core32_Int32::fromInt($f3 ^ $x3);
$f[4] = ParagonIE_Sodium_Core32_Int32::fromInt($f4 ^ $x4);
$f[5] = ParagonIE_Sodium_Core32_Int32::fromInt($f5 ^ $x5);
$f[6] = ParagonIE_Sodium_Core32_Int32::fromInt($f6 ^ $x6);
$f[7] = ParagonIE_Sodium_Core32_Int32::fromInt($f7 ^ $x7);
$f[8] = ParagonIE_Sodium_Core32_Int32::fromInt($f8 ^ $x8);
$f[9] = ParagonIE_Sodium_Core32_Int32::fromInt($f9 ^ $x9);
$g[0] = ParagonIE_Sodium_Core32_Int32::fromInt($g0 ^ $x0);
$g[1] = ParagonIE_Sodium_Core32_Int32::fromInt($g1 ^ $x1);
$g[2] = ParagonIE_Sodium_Core32_Int32::fromInt($g2 ^ $x2);
$g[3] = ParagonIE_Sodium_Core32_Int32::fromInt($g3 ^ $x3);
$g[4] = ParagonIE_Sodium_Core32_Int32::fromInt($g4 ^ $x4);
$g[5] = ParagonIE_Sodium_Core32_Int32::fromInt($g5 ^ $x5);
$g[6] = ParagonIE_Sodium_Core32_Int32::fromInt($g6 ^ $x6);
$g[7] = ParagonIE_Sodium_Core32_Int32::fromInt($g7 ^ $x7);
$g[8] = ParagonIE_Sodium_Core32_Int32::fromInt($g8 ^ $x8);
$g[9] = ParagonIE_Sodium_Core32_Int32::fromInt($g9 ^ $x9);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function
fe_mul121666(ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
/** @var array<int, ParagonIE_Sodium_Core32_Int64> $h */
$h = array();
for ($i = 0; $i < 10; ++$i) {
$h[$i] = $f[$i]->toInt64()->mulInt(121666, 17);
}
$carry9 = $h[9]->addInt(1 << 24)->shiftRight(25);
$h[0] = $h[0]->addInt64($carry9->mulInt(19, 5));
$h[9] = $h[9]->subInt64($carry9->shiftLeft(25));
$carry1 = $h[1]->addInt(1 << 24)->shiftRight(25);
$h[2] = $h[2]->addInt64($carry1);
$h[1] = $h[1]->subInt64($carry1->shiftLeft(25));
$carry3 = $h[3]->addInt(1 << 24)->shiftRight(25);
$h[4] = $h[4]->addInt64($carry3);
$h[3] = $h[3]->subInt64($carry3->shiftLeft(25));
$carry5 = $h[5]->addInt(1 << 24)->shiftRight(25);
$h[6] = $h[6]->addInt64($carry5);
$h[5] = $h[5]->subInt64($carry5->shiftLeft(25));
$carry7 = $h[7]->addInt(1 << 24)->shiftRight(25);
$h[8] = $h[8]->addInt64($carry7);
$h[7] = $h[7]->subInt64($carry7->shiftLeft(25));
$carry0 = $h[0]->addInt(1 << 25)->shiftRight(26);
$h[1] = $h[1]->addInt64($carry0);
$h[0] = $h[0]->subInt64($carry0->shiftLeft(26));
$carry2 = $h[2]->addInt(1 << 25)->shiftRight(26);
$h[3] = $h[3]->addInt64($carry2);
$h[2] = $h[2]->subInt64($carry2->shiftLeft(26));
$carry4 = $h[4]->addInt(1 << 25)->shiftRight(26);
$h[5] = $h[5]->addInt64($carry4);
$h[4] = $h[4]->subInt64($carry4->shiftLeft(26));
$carry6 = $h[6]->addInt(1 << 25)->shiftRight(26);
$h[7] = $h[7]->addInt64($carry6);
$h[6] = $h[6]->subInt64($carry6->shiftLeft(26));
$carry8 = $h[8]->addInt(1 << 25)->shiftRight(26);
$h[9] = $h[9]->addInt64($carry8);
$h[8] = $h[8]->subInt64($carry8->shiftLeft(26));
for ($i = 0; $i < 10; ++$i) {
$h[$i] = $h[$i]->toInt32();
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h2 */
$h2 = $h;
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h2);
}
/**
* @internal You should not use this directly from another application
*
* Inline comments preceded by # are from libsodium's ref10 code.
*
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10($n, $p)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
# fe_frombytes(x1,p);
$x1 = self::fe_frombytes($p);
# fe_1(x2);
$x2 = self::fe_1();
# fe_0(z2);
$z2 = self::fe_0();
# fe_copy(x3,x1);
$x3 = self::fe_copy($x1);
# fe_1(z3);
$z3 = self::fe_1();
# swap = 0;
/** @var int $swap */
$swap = 0;
# for (pos = 254;pos >= 0;--pos) {
for ($pos = 254; $pos >= 0; --$pos) {
# b = e[pos / 8] >> (pos & 7);
/** @var int $b */
$b = self::chrToInt(
$e[(int) floor($pos / 8)]
) >> ($pos & 7);
# b &= 1;
$b &= 1;
# swap ^= b;
$swap ^= $b;
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# swap = b;
/** @var int $swap */
$swap = $b;
# fe_sub(tmp0,x3,z3);
$tmp0 = self::fe_sub($x3, $z3);
# fe_sub(tmp1,x2,z2);
$tmp1 = self::fe_sub($x2, $z2);
# fe_add(x2,x2,z2);
$x2 = self::fe_add($x2, $z2);
# fe_add(z2,x3,z3);
$z2 = self::fe_add($x3, $z3);
# fe_mul(z3,tmp0,x2);
$z3 = self::fe_mul($tmp0, $x2);
# fe_mul(z2,z2,tmp1);
$z2 = self::fe_mul($z2, $tmp1);
# fe_sq(tmp0,tmp1);
$tmp0 = self::fe_sq($tmp1);
# fe_sq(tmp1,x2);
$tmp1 = self::fe_sq($x2);
# fe_add(x3,z3,z2);
$x3 = self::fe_add($z3, $z2);
# fe_sub(z2,z3,z2);
$z2 = self::fe_sub($z3, $z2);
# fe_mul(x2,tmp1,tmp0);
$x2 = self::fe_mul($tmp1, $tmp0);
# fe_sub(tmp1,tmp1,tmp0);
$tmp1 = self::fe_sub($tmp1, $tmp0);
# fe_sq(z2,z2);
$z2 = self::fe_sq($z2);
# fe_mul121666(z3,tmp1);
$z3 = self::fe_mul121666($tmp1);
# fe_sq(x3,x3);
$x3 = self::fe_sq($x3);
# fe_add(tmp0,tmp0,z3);
$tmp0 = self::fe_add($tmp0, $z3);
# fe_mul(z3,x1,z2);
$z3 = self::fe_mul($x1, $z2);
# fe_mul(z2,tmp1,tmp0);
$z2 = self::fe_mul($tmp1, $tmp0);
}
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# fe_invert(z2,z2);
$z2 = self::fe_invert($z2);
# fe_mul(x2,x2,z2);
$x2 = self::fe_mul($x2, $z2);
# fe_tobytes(q,x2);
return (string) self::fe_tobytes($x2);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsY
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsZ
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function edwards_to_montgomery(
ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsY,
ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsZ
) {
$tempX = self::fe_add($edwardsZ, $edwardsY);
$tempZ = self::fe_sub($edwardsZ, $edwardsY);
$tempZ = self::fe_invert($tempZ);
return self::fe_mul($tempX, $tempZ);
}
/**
* @internal You should not use this directly from another application
*
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10_base($n)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
$A = self::ge_scalarmult_base($e);
if (
!($A->Y instanceof ParagonIE_Sodium_Core32_Curve25519_Fe)
||
!($A->Z instanceof ParagonIE_Sodium_Core32_Curve25519_Fe)
) {
throw new TypeError('Null points encountered');
}
$pk = self::edwards_to_montgomery($A->Y, $A->Z);
return self::fe_tobytes($pk);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_XChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_XChaCha20
*/
class ParagonIE_Sodium_Core32_XChaCha20 extends
ParagonIE_Sodium_Core32_HChaCha20
{
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key =
'')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes
long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_Ctx(
self::hChaCha20(
self::substr($nonce, 0, 16),
$key
),
self::substr($nonce, 16, 8)
),
str_repeat("\x00", $len)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '',
$key = '', $ic = '')
{
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes
long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core32_ChaCha20_Ctx(
self::hChaCha20(self::substr($nonce, 0, 16), $key),
self::substr($nonce, 16, 8),
$ic
),
$message
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Core32_XSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_XSalsa20
*/
abstract class ParagonIE_Sodium_Core32_XSalsa20 extends
ParagonIE_Sodium_Core32_HSalsa20
{
/**
* Expand a key and nonce into an xsalsa20 keystream.
*
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20($len, $nonce, $key)
{
$ret = self::salsa20(
$len,
self::substr($nonce, 16, 8),
self::hsalsa20($nonce, $key)
);
return $ret;
}
/**
* Encrypt a string with XSalsa20. Doesn't provide integrity.
*
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20_xor($message, $nonce, $key)
{
return self::xorStrings(
$message,
self::xsalsa20(
self::strlen($message),
$nonce,
$key
)
);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Crypto', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Crypto
*
* ATTENTION!
*
* If you are using this library, you should be using
* ParagonIE_Sodium_Compat in your code, not this class.
*/
abstract class ParagonIE_Sodium_Crypto
{
const aead_chacha20poly1305_KEYBYTES = 32;
const aead_chacha20poly1305_NSECBYTES = 0;
const aead_chacha20poly1305_NPUBBYTES = 8;
const aead_chacha20poly1305_ABYTES = 16;
const aead_chacha20poly1305_IETF_KEYBYTES = 32;
const aead_chacha20poly1305_IETF_NSECBYTES = 0;
const aead_chacha20poly1305_IETF_NPUBBYTES = 12;
const aead_chacha20poly1305_IETF_ABYTES = 16;
const aead_xchacha20poly1305_IETF_KEYBYTES = 32;
const aead_xchacha20poly1305_IETF_NSECBYTES = 0;
const aead_xchacha20poly1305_IETF_NPUBBYTES = 24;
const aead_xchacha20poly1305_IETF_ABYTES = 16;
const box_curve25519xsalsa20poly1305_SEEDBYTES = 32;
const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32;
const box_curve25519xsalsa20poly1305_NONCEBYTES = 24;
const box_curve25519xsalsa20poly1305_MACBYTES = 16;
const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16;
const box_curve25519xsalsa20poly1305_ZEROBYTES = 32;
const onetimeauth_poly1305_BYTES = 16;
const onetimeauth_poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_NONCEBYTES = 24;
const secretbox_xsalsa20poly1305_MACBYTES = 16;
const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16;
const secretbox_xsalsa20poly1305_ZEROBYTES = 32;
const secretbox_xchacha20poly1305_KEYBYTES = 32;
const secretbox_xchacha20poly1305_NONCEBYTES = 24;
const secretbox_xchacha20poly1305_MACBYTES = 16;
const secretbox_xchacha20poly1305_BOXZEROBYTES = 16;
const secretbox_xchacha20poly1305_ZEROBYTES = 32;
const stream_salsa20_KEYBYTES = 32;
/**
* AEAD Decryption with ChaCha20-Poly1305
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of message (ciphertext + MAC) */
$len = ParagonIE_Sodium_Core_Util::strlen($message);
/** @var int $clen - Length of ciphertext */
$clen = $len - self::aead_chacha20poly1305_ABYTES;
/** @var int $adlen - Length of associated data */
$adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
/** @var string $mac - Message authentication code */
$mac = ParagonIE_Sodium_Core_Util::substr(
$message,
$clen,
self::aead_chacha20poly1305_ABYTES
);
/** @var string $ciphertext - The encrypted message (sans MAC) */
$ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 0,
$clen);
/** @var string The first block of the chacha20 keystream, used as
a poly1305 key */
$block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
32,
$nonce,
$key
);
/* Recalculate the Poly1305 authentication tag (MAC): */
$state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state->update($ad);
$state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
$state->update($ciphertext);
$state->update(ParagonIE_Sodium_Core_Util::store64_le($clen));
$computed_mac = $state->finish();
/* Compare the given MAC with the recalculated MAC: */
if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) {
throw new SodiumException('Invalid MAC');
}
// Here, we know that the MAC is valid, so we decrypt and return
the plaintext
return ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
$ciphertext,
$nonce,
$key,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
}
/**
* AEAD Encryption with ChaCha20-Poly1305
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of the plaintext message */
$len = ParagonIE_Sodium_Core_Util::strlen($message);
/** @var int $adlen - Length of the associated data */
$adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
/** @var string The first block of the chacha20 keystream, used as
a poly1305 key */
$block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
32,
$nonce,
$key
);
$state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
/** @var string $ciphertext - Raw encrypted data */
$ciphertext = ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
$message,
$nonce,
$key,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
$state->update($ad);
$state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
$state->update($ciphertext);
$state->update(ParagonIE_Sodium_Core_Util::store64_le($len));
return $ciphertext . $state->finish();
}
/**
* AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_ietf_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $adlen - Length of associated data */
$adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
/** @var int $len - Length of message (ciphertext + MAC) */
$len = ParagonIE_Sodium_Core_Util::strlen($message);
/** @var int $clen - Length of ciphertext */
$clen = $len - self::aead_chacha20poly1305_IETF_ABYTES;
/** @var string The first block of the chacha20 keystream, used as
a poly1305 key */
$block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream(
32,
$nonce,
$key
);
/** @var string $mac - Message authentication code */
$mac = ParagonIE_Sodium_Core_Util::substr(
$message,
$len - self::aead_chacha20poly1305_IETF_ABYTES,
self::aead_chacha20poly1305_IETF_ABYTES
);
/** @var string $ciphertext - The encrypted message (sans MAC) */
$ciphertext = ParagonIE_Sodium_Core_Util::substr(
$message,
0,
$len - self::aead_chacha20poly1305_IETF_ABYTES
);
/* Recalculate the Poly1305 authentication tag (MAC): */
$state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state->update($ad);
$state->update(str_repeat("\x00", ((0x10 - $adlen)
& 0xf)));
$state->update($ciphertext);
$state->update(str_repeat("\x00", (0x10 - $clen) &
0xf));
$state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
$state->update(ParagonIE_Sodium_Core_Util::store64_le($clen));
$computed_mac = $state->finish();
/* Compare the given MAC with the recalculated MAC: */
if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) {
throw new SodiumException('Invalid MAC');
}
// Here, we know that the MAC is valid, so we decrypt and return
the plaintext
return ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$ciphertext,
$nonce,
$key,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
}
/**
* AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_ietf_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of the plaintext message */
$len = ParagonIE_Sodium_Core_Util::strlen($message);
/** @var int $adlen - Length of the associated data */
$adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
/** @var string The first block of the chacha20 keystream, used as
a poly1305 key */
$block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream(
32,
$nonce,
$key
);
$state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
/** @var string $ciphertext - Raw encrypted data */
$ciphertext = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$message,
$nonce,
$key,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
$state->update($ad);
$state->update(str_repeat("\x00", ((0x10 - $adlen)
& 0xf)));
$state->update($ciphertext);
$state->update(str_repeat("\x00", ((0x10 - $len) &
0xf)));
$state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
$state->update(ParagonIE_Sodium_Core_Util::store64_le($len));
return $ciphertext . $state->finish();
}
/**
* AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_xchacha20poly1305_ietf_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = "\x00\x00\x00\x00" .
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_decrypt($message, $ad,
$nonceLast, $subkey);
}
/**
* AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_xchacha20poly1305_ietf_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = "\x00\x00\x00\x00" .
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_encrypt($message, $ad,
$nonceLast, $subkey);
}
/**
* HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $key
* @return string
* @throws TypeError
*/
public static function auth($message, $key)
{
return ParagonIE_Sodium_Core_Util::substr(
hash_hmac('sha512', $message, $key, true),
0,
32
);
}
/**
* HMAC-SHA-512-256 validation. Constant-time via hash_equals().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $mac
* @param string $message
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function auth_verify($mac, $message, $key)
{
return ParagonIE_Sodium_Core_Util::hashEquals(
$mac,
self::auth($message, $key)
);
}
/**
* X25519 key exchange followed by XSalsa20Poly1305 symmetric
encryption
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box($plaintext, $nonce, $keypair)
{
$c = self::secretbox(
$plaintext,
$nonce,
self::box_beforenm(
self::box_secretkey($keypair),
self::box_publickey($keypair)
)
);
return $c;
}
/**
* X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $publicKey
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal($message, $publicKey)
{
/** @var string $ephemeralKeypair */
$ephemeralKeypair = self::box_keypair();
/** @var string $ephemeralSK */
$ephemeralSK = self::box_secretkey($ephemeralKeypair);
/** @var string $ephemeralPK */
$ephemeralPK = self::box_publickey($ephemeralKeypair);
/** @var string $nonce */
$nonce = self::generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var string $keypair - The combined keypair used in
crypto_box() */
$keypair =
self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
/** @var string $ciphertext Ciphertext + MAC from crypto_box */
$ciphertext = self::box($message, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($ephemeralKeypair);
ParagonIE_Sodium_Compat::memzero($ephemeralSK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$ephemeralKeypair = null;
$ephemeralSK = null;
$nonce = null;
}
return $ephemeralPK . $ciphertext;
}
/**
* Opens a message encrypted via box_seal().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal_open($message, $keypair)
{
/** @var string $ephemeralPK */
$ephemeralPK = ParagonIE_Sodium_Core_Util::substr($message, 0, 32);
/** @var string $ciphertext (ciphertext + MAC) */
$ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 32);
/** @var string $secretKey */
$secretKey = self::box_secretkey($keypair);
/** @var string $publicKey */
$publicKey = self::box_publickey($keypair);
/** @var string $nonce */
$nonce = self::generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var string $keypair */
$keypair =
self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
/** @var string $m */
$m = self::box_open($ciphertext, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($secretKey);
ParagonIE_Sodium_Compat::memzero($ephemeralPK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$secretKey = null;
$ephemeralPK = null;
$nonce = null;
}
return $m;
}
/**
* Used by crypto_box() to get the crypto_secretbox() key.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sk
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_beforenm($sk, $pk)
{
return ParagonIE_Sodium_Core_HSalsa20::hsalsa20(
str_repeat("\x00", 16),
self::scalarmult($sk, $pk)
);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @return string
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function box_keypair()
{
$sKey = random_bytes(32);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
/**
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seed_keypair($seed)
{
$sKey = ParagonIE_Sodium_Core_Util::substr(
hash('sha512', $seed, true),
0,
32
);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @param string $pKey
* @return string
* @throws TypeError
*/
public static function box_keypair_from_secretkey_and_publickey($sKey,
$pKey)
{
return ParagonIE_Sodium_Core_Util::substr($sKey, 0, 32) .
ParagonIE_Sodium_Core_Util::substr($pKey, 0, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function box_secretkey($keypair)
{
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== 64) {
throw new RangeException(
'Must be
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
);
}
return ParagonIE_Sodium_Core_Util::substr($keypair, 0, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function box_publickey($keypair)
{
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new RangeException(
'Must be
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
);
}
return ParagonIE_Sodium_Core_Util::substr($keypair, 32, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function box_publickey_from_secretkey($sKey)
{
if (ParagonIE_Sodium_Core_Util::strlen($sKey) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) {
throw new RangeException(
'Must be
ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.'
);
}
return self::scalarmult_base($sKey);
}
/**
* Decrypt a message encrypted with box().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_open($ciphertext, $nonce, $keypair)
{
return self::secretbox_open(
$ciphertext,
$nonce,
self::box_beforenm(
self::box_secretkey($keypair),
self::box_publickey($keypair)
)
);
}
/**
* Calculate a BLAKE2b hash.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string|null $key
* @param int $outlen
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash($message, $key = '',
$outlen = 32)
{
// This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is
initialized
ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
/** @var SplFixedArray $k */
$k =
ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() >
ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
/** @var SplFixedArray $in */
$in =
ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message);
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outlen);
ParagonIE_Sodium_Core_BLAKE2b::update($ctx, $in, $in->count());
/** @var SplFixedArray $out */
$out = new SplFixedArray($outlen);
$out = ParagonIE_Sodium_Core_BLAKE2b::finish($ctx, $out);
/** @var array<int, int> */
$outArray = $out->toArray();
return ParagonIE_Sodium_Core_Util::intArrayToString($outArray);
}
/**
* Finalize a BLAKE2b hashing context, returning the hash.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ctx
* @param int $outlen
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_final($ctx, $outlen = 32)
{
if (!is_string($ctx)) {
throw new TypeError('Context must be a string');
}
$out = new SplFixedArray($outlen);
/** @var SplFixedArray $context */
$context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx);
/** @var SplFixedArray $out */
$out = ParagonIE_Sodium_Core_BLAKE2b::finish($context, $out);
/** @var array<int, int> */
$outArray = $out->toArray();
return ParagonIE_Sodium_Core_Util::intArrayToString($outArray);
}
/**
* Initialize a hashing context for BLAKE2b.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $key
* @param int $outputLength
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_init($key = '',
$outputLength = 32)
{
// This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is
initialized
ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k =
ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() >
ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength);
return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
}
/**
* Initialize a hashing context for BLAKE2b.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $key
* @param int $outputLength
* @param string $salt
* @param string $personal
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_init_salt_personal(
$key = '',
$outputLength = 32,
$salt = '',
$personal = ''
) {
// This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is
initialized
ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k =
ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() >
ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
if (!empty($salt)) {
$s =
ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($salt);
} else {
$s = null;
}
if (!empty($salt)) {
$p =
ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($personal);
} else {
$p = null;
}
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength, $s,
$p);
return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
}
/**
* Update a hashing context for BLAKE2b with $message
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ctx
* @param string $message
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_update($ctx, $message)
{
// This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is
initialized
ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
/** @var SplFixedArray $context */
$context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx);
/** @var SplFixedArray $in */
$in =
ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message);
ParagonIE_Sodium_Core_BLAKE2b::update($context, $in,
$in->count());
return ParagonIE_Sodium_Core_BLAKE2b::contextToString($context);
}
/**
* Libsodium's crypto_kx().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $my_sk
* @param string $their_pk
* @param string $client_pk
* @param string $server_pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function keyExchange($my_sk, $their_pk, $client_pk,
$server_pk)
{
return ParagonIE_Sodium_Compat::crypto_generichash(
ParagonIE_Sodium_Compat::crypto_scalarmult($my_sk, $their_pk) .
$client_pk .
$server_pk
);
}
/**
* ECDH over Curve25519
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @param string $pKey
* @return string
*
* @throws SodiumException
* @throws TypeError
*/
public static function scalarmult($sKey, $pKey)
{
$q =
ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10($sKey,
$pKey);
self::scalarmult_throw_if_zero($q);
return $q;
}
/**
* ECDH over Curve25519, using the basepoint.
* Used to get a secret key from a public key.
*
* @param string $secret
* @return string
*
* @throws SodiumException
* @throws TypeError
*/
public static function scalarmult_base($secret)
{
$q =
ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10_base($secret);
self::scalarmult_throw_if_zero($q);
return $q;
}
/**
* This throws an Error if a zero public key was passed to the
function.
*
* @param string $q
* @return void
* @throws SodiumException
* @throws TypeError
*/
protected static function scalarmult_throw_if_zero($q)
{
$d = 0;
for ($i = 0; $i <
self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) {
$d |= ParagonIE_Sodium_Core_Util::chrToInt($q[$i]);
}
/* branch-free variant of === 0 */
if (-(1 & (($d - 1) >> 8))) {
throw new SodiumException('Zero public key is not
allowed');
}
}
/**
* XSalsa20-Poly1305 authenticated symmetric-key encryption.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox($plaintext, $nonce, $key)
{
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0,
$mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor(
$block0,
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
$subkey
);
/** @var string $c */
$c = ParagonIE_Sodium_Core_Util::substr(
$block0,
self::secretbox_xsalsa20poly1305_ZEROBYTES
);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
ParagonIE_Sodium_Core_Util::substr(
$plaintext,
self::secretbox_xsalsa20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1,
$subkey
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_Util::substr(
$block0,
0,
self::onetimeauth_poly1305_KEYBYTES
)
);
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state->update($c);
/** @var string $c - MAC || ciphertext */
$c = $state->finish() . $c;
unset($state);
return $c;
}
/**
* Decrypt a ciphertext generated via secretbox().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_open($ciphertext, $nonce, $key)
{
/** @var string $mac */
$mac = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
0,
self::secretbox_xsalsa20poly1305_MACBYTES
);
/** @var string $c */
$c = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
self::secretbox_xsalsa20poly1305_MACBYTES
);
/** @var int $clen */
$clen = ParagonIE_Sodium_Core_Util::strlen($c);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20(
64,
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
$subkey
);
$verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify(
$mac,
$c,
ParagonIE_Sodium_Core_Util::substr($block0, 0, 32)
);
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
/** @var string $m - Decrypted message */
$m = ParagonIE_Sodium_Core_Util::xorStrings(
ParagonIE_Sodium_Core_Util::substr($block0,
self::secretbox_xsalsa20poly1305_ZEROBYTES),
ParagonIE_Sodium_Core_Util::substr($c, 0,
self::secretbox_xsalsa20poly1305_ZEROBYTES)
);
if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) {
// We had more than 1 block, so let's continue to decrypt
the rest.
$m .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
ParagonIE_Sodium_Core_Util::substr(
$c,
self::secretbox_xsalsa20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1,
(string) $subkey
);
}
return $m;
}
/**
* XChaCha20-Poly1305 authenticated symmetric-key encryption.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_xchacha20poly1305($plaintext, $nonce,
$key)
{
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0,
$mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
$block0,
$nonceLast,
$subkey
);
/** @var string $c */
$c = ParagonIE_Sodium_Core_Util::substr(
$block0,
self::secretbox_xchacha20poly1305_ZEROBYTES
);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
ParagonIE_Sodium_Core_Util::substr(
$plaintext,
self::secretbox_xchacha20poly1305_ZEROBYTES
),
$nonceLast,
$subkey,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_Util::substr(
$block0,
0,
self::onetimeauth_poly1305_KEYBYTES
)
);
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state->update($c);
/** @var string $c - MAC || ciphertext */
$c = $state->finish() . $c;
unset($state);
return $c;
}
/**
* Decrypt a ciphertext generated via secretbox_xchacha20poly1305().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_xchacha20poly1305_open($ciphertext,
$nonce, $key)
{
/** @var string $mac */
$mac = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
0,
self::secretbox_xchacha20poly1305_MACBYTES
);
/** @var string $c */
$c = ParagonIE_Sodium_Core_Util::substr(
$ciphertext,
self::secretbox_xchacha20poly1305_MACBYTES
);
/** @var int $clen */
$clen = ParagonIE_Sodium_Core_Util::strlen($c);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HChaCha20::hchacha20($nonce, $key);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
64,
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
$subkey
);
$verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify(
$mac,
$c,
ParagonIE_Sodium_Core_Util::substr($block0, 0, 32)
);
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
/** @var string $m - Decrypted message */
$m = ParagonIE_Sodium_Core_Util::xorStrings(
ParagonIE_Sodium_Core_Util::substr($block0,
self::secretbox_xchacha20poly1305_ZEROBYTES),
ParagonIE_Sodium_Core_Util::substr($c, 0,
self::secretbox_xchacha20poly1305_ZEROBYTES)
);
if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) {
// We had more than 1 block, so let's continue to decrypt
the rest.
$m .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
ParagonIE_Sodium_Core_Util::substr(
$c,
self::secretbox_xchacha20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
(string) $subkey,
ParagonIE_Sodium_Core_Util::store64_le(1)
);
}
return $m;
}
/**
* @param string $key
* @return array<int, string> Returns a state and a header.
* @throws Exception
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_init_push($key)
{
# randombytes_buf(out,
crypto_secretstream_xchacha20poly1305_HEADERBYTES);
$out = random_bytes(24);
# crypto_core_hchacha20(state->k, out, k, NULL);
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20($out, $key);
$state = new ParagonIE_Sodium_Core_SecretStream_State(
$subkey,
ParagonIE_Sodium_Core_Util::substr($out, 16, 8) .
str_repeat("\0", 4)
);
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
$state->counterReset();
# memcpy(STATE_INONCE(state), out +
crypto_core_hchacha20_INPUTBYTES,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
# memset(state->_pad, 0, sizeof state->_pad);
return array(
$state->toString(),
$out
);
}
/**
* @param string $key
* @param string $header
* @return string Returns a state.
* @throws Exception
*/
public static function secretstream_xchacha20poly1305_init_pull($key,
$header)
{
# crypto_core_hchacha20(state->k, in, k, NULL);
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core_Util::substr($header, 0, 16),
$key
);
$state = new ParagonIE_Sodium_Core_SecretStream_State(
$subkey,
ParagonIE_Sodium_Core_Util::substr($header, 16)
);
$state->counterReset();
# memcpy(STATE_INONCE(state), in +
crypto_core_hchacha20_INPUTBYTES,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
# memset(state->_pad, 0, sizeof state->_pad);
# return 0;
return $state->toString();
}
/**
* @param string $state
* @param string $msg
* @param string $aad
* @param int $tag
* @return string
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_push(&$state,
$msg, $aad = '', $tag = 0)
{
$st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
# crypto_onetimeauth_poly1305_state poly1305_state;
# unsigned char block[64U];
# unsigned char slen[8U];
# unsigned char *c;
# unsigned char *mac;
$msglen = ParagonIE_Sodium_Core_Util::strlen($msg);
$aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
if ((($msglen + 63) >> 6) > 0xfffffffe) {
throw new SodiumException(
'message cannot be larger than
SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
);
}
# if (outlen_p != NULL) {
# *outlen_p = 0U;
# }
# if (mlen >
crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
# sodium_misuse();
# }
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce,
state->k);
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
# sodium_memzero(block, sizeof block);
$auth = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_ChaCha20::ietfStream(32,
$st->getCombinedNonce(), $st->getKey())
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad,
adlen);
$auth->update($aad);
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
# (0x10 - adlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - $aadlen) &
0xf)));
# memset(block, 0, sizeof block);
# block[0] = tag;
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
# state->nonce, 1U,
state->k);
$block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
ParagonIE_Sodium_Core_Util::intToChr($tag) .
str_repeat("\0", 63),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(1)
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, block,
sizeof block);
$auth->update($block);
# out[0] = block[0];
$out = $block[0];
# c = out + (sizeof tag);
# crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce,
2U, state->k);
$cipher = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$msg,
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(2)
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
$auth->update($cipher);
$out .= $cipher;
unset($cipher);
# crypto_onetimeauth_poly1305_update
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) &
0xf);
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen)
& 0xf)));
# STORE64_LE(slen, (uint64_t) adlen);
$slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen,
sizeof slen);
$auth->update($slen);
# STORE64_LE(slen, (sizeof block) + mlen);
$slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen,
sizeof slen);
$auth->update($slen);
# mac = c + mlen;
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
$mac = $auth->finish();
$out .= $mac;
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
unset($auth);
# XOR_BUF(STATE_INONCE(state), mac,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
$st->xorNonce($mac);
# sodium_increment(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
$st->incrementCounter();
// Overwrite by reference:
$state = $st->toString();
/** @var bool $rekey */
$rekey = ($tag &
ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY)
!== 0;
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY)
!= 0 ||
# sodium_is_zero(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
# crypto_secretstream_xchacha20poly1305_rekey(state);
# }
if ($rekey || $st->needsRekey()) {
// DO REKEY
self::secretstream_xchacha20poly1305_rekey($state);
}
# if (outlen_p != NULL) {
# *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES +
mlen;
# }
return $out;
}
/**
* @param string $state
* @param string $cipher
* @param string $aad
* @return bool|array{0: string, 1: int}
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_pull(&$state,
$cipher, $aad = '')
{
$st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
$cipherlen = ParagonIE_Sodium_Core_Util::strlen($cipher);
# mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
$msglen = $cipherlen -
ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
$aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
# if (mlen >
crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
# sodium_misuse();
# }
if ((($msglen + 63) >> 6) > 0xfffffffe) {
throw new SodiumException(
'message cannot be larger than
SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
);
}
# crypto_stream_chacha20_ietf(block, sizeof block,
state->nonce, state->k);
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
# sodium_memzero(block, sizeof block);
$auth = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_ChaCha20::ietfStream(32,
$st->getCombinedNonce(), $st->getKey())
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad,
adlen);
$auth->update($aad);
# crypto_onetimeauth_poly1305_update(&poly1305_state,
_pad0,
# (0x10 - adlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - $aadlen) &
0xf)));
# memset(block, 0, sizeof block);
# block[0] = in[0];
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof
block,
# state->nonce, 1U,
state->k);
$block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$cipher[0] . str_repeat("\0", 63),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(1)
);
# tag = block[0];
# block[0] = in[0];
# crypto_onetimeauth_poly1305_update(&poly1305_state,
block, sizeof block);
$tag = ParagonIE_Sodium_Core_Util::chrToInt($block[0]);
$block[0] = $cipher[0];
$auth->update($block);
# c = in + (sizeof tag);
# crypto_onetimeauth_poly1305_update(&poly1305_state, c,
mlen);
$auth->update(ParagonIE_Sodium_Core_Util::substr($cipher, 1,
$msglen));
# crypto_onetimeauth_poly1305_update
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen)
& 0xf);
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen)
& 0xf)));
# STORE64_LE(slen, (uint64_t) adlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen,
sizeof slen);
$slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
$auth->update($slen);
# STORE64_LE(slen, (sizeof block) + mlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen,
sizeof slen);
$slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
$auth->update($slen);
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
$mac = $auth->finish();
# stored_mac = c + mlen;
# if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
# sodium_memzero(mac, sizeof mac);
# return -1;
# }
$stored = ParagonIE_Sodium_Core_Util::substr($cipher, $msglen + 1,
16);
if (!ParagonIE_Sodium_Core_Util::hashEquals($mac, $stored)) {
return false;
}
# crypto_stream_chacha20_ietf_xor_ic(m, c, mlen,
state->nonce, 2U, state->k);
$out = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(2)
);
# XOR_BUF(STATE_INONCE(state), mac,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
$st->xorNonce($mac);
# sodium_increment(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
$st->incrementCounter();
# if ((tag &
crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
# sodium_is_zero(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES))
{
# crypto_secretstream_xchacha20poly1305_rekey(state);
# }
// Overwrite by reference:
$state = $st->toString();
/** @var bool $rekey */
$rekey = ($tag &
ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY)
!== 0;
if ($rekey || $st->needsRekey()) {
// DO REKEY
self::secretstream_xchacha20poly1305_rekey($state);
}
return array($out, $tag);
}
/**
* @param string $state
* @return void
* @throws SodiumException
*/
public static function
secretstream_xchacha20poly1305_rekey(&$state)
{
$st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
# unsigned char
new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
# crypto_secretstream_xchacha20poly1305_INONCEBYTES];
# size_t i;
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
# new_key_and_inonce[i] = state->k[i];
# }
$new_key_and_inonce = $st->getKey();
# for (i = 0U; i <
crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i]
=
# STATE_INONCE(state)[i];
# }
$new_key_and_inonce .=
ParagonIE_Sodium_Core_Util::substR($st->getNonce(), 0, 8);
# crypto_stream_chacha20_ietf_xor(new_key_and_inonce,
new_key_and_inonce,
# sizeof new_key_and_inonce,
# state->nonce, state->k);
$st->rekey(ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
$new_key_and_inonce,
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core_Util::store64_le(0)
));
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
# state->k[i] = new_key_and_inonce[i];
# }
# for (i = 0U; i <
crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
# STATE_INONCE(state)[i] =
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES
+ i];
# }
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
$st->counterReset();
$state = $st->toString();
}
/**
* Detached Ed25519 signature.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_detached($message, $sk)
{
return ParagonIE_Sodium_Core_Ed25519::sign_detached($message, $sk);
}
/**
* Attached Ed25519 signature. (Returns a signed message.)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
return ParagonIE_Sodium_Core_Ed25519::sign($message, $sk);
}
/**
* Opens a signed message. If valid, returns the message.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $signedMessage
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($signedMessage, $pk)
{
return ParagonIE_Sodium_Core_Ed25519::sign_open($signedMessage,
$pk);
}
/**
* Verify a detached signature of a given message and public key.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $signature
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function sign_verify_detached($signature, $message, $pk)
{
return ParagonIE_Sodium_Core_Ed25519::verify_detached($signature,
$message, $pk);
}
}
<?php
if (class_exists('ParagonIE_Sodium_Crypto32', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Crypto
*
* ATTENTION!
*
* If you are using this library, you should be using
* ParagonIE_Sodium_Compat in your code, not this class.
*/
abstract class ParagonIE_Sodium_Crypto32
{
const aead_chacha20poly1305_KEYBYTES = 32;
const aead_chacha20poly1305_NSECBYTES = 0;
const aead_chacha20poly1305_NPUBBYTES = 8;
const aead_chacha20poly1305_ABYTES = 16;
const aead_chacha20poly1305_IETF_KEYBYTES = 32;
const aead_chacha20poly1305_IETF_NSECBYTES = 0;
const aead_chacha20poly1305_IETF_NPUBBYTES = 12;
const aead_chacha20poly1305_IETF_ABYTES = 16;
const aead_xchacha20poly1305_IETF_KEYBYTES = 32;
const aead_xchacha20poly1305_IETF_NSECBYTES = 0;
const aead_xchacha20poly1305_IETF_NPUBBYTES = 24;
const aead_xchacha20poly1305_IETF_ABYTES = 16;
const box_curve25519xsalsa20poly1305_SEEDBYTES = 32;
const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32;
const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32;
const box_curve25519xsalsa20poly1305_NONCEBYTES = 24;
const box_curve25519xsalsa20poly1305_MACBYTES = 16;
const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16;
const box_curve25519xsalsa20poly1305_ZEROBYTES = 32;
const onetimeauth_poly1305_BYTES = 16;
const onetimeauth_poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_KEYBYTES = 32;
const secretbox_xsalsa20poly1305_NONCEBYTES = 24;
const secretbox_xsalsa20poly1305_MACBYTES = 16;
const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16;
const secretbox_xsalsa20poly1305_ZEROBYTES = 32;
const secretbox_xchacha20poly1305_KEYBYTES = 32;
const secretbox_xchacha20poly1305_NONCEBYTES = 24;
const secretbox_xchacha20poly1305_MACBYTES = 16;
const secretbox_xchacha20poly1305_BOXZEROBYTES = 16;
const secretbox_xchacha20poly1305_ZEROBYTES = 32;
const stream_salsa20_KEYBYTES = 32;
/**
* AEAD Decryption with ChaCha20-Poly1305
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of message (ciphertext + MAC) */
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
/** @var int $clen - Length of ciphertext */
$clen = $len - self::aead_chacha20poly1305_ABYTES;
/** @var int $adlen - Length of associated data */
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
/** @var string $mac - Message authentication code */
$mac = ParagonIE_Sodium_Core32_Util::substr(
$message,
$clen,
self::aead_chacha20poly1305_ABYTES
);
/** @var string $ciphertext - The encrypted message (sans MAC) */
$ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0,
$clen);
/** @var string The first block of the chacha20 keystream, used as
a poly1305 key */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
32,
$nonce,
$key
);
/* Recalculate the Poly1305 authentication tag (MAC): */
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state->update($ad);
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state->update($ciphertext);
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
$computed_mac = $state->finish();
/* Compare the given MAC with the recalculated MAC: */
if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac))
{
throw new SodiumException('Invalid MAC');
}
// Here, we know that the MAC is valid, so we decrypt and return
the plaintext
return ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
$ciphertext,
$nonce,
$key,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
}
/**
* AEAD Encryption with ChaCha20-Poly1305
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of the plaintext message */
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
/** @var int $adlen - Length of the associated data */
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
/** @var string The first block of the chacha20 keystream, used as
a poly1305 key */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
32,
$nonce,
$key
);
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
/** @var string $ciphertext - Raw encrypted data */
$ciphertext = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
$message,
$nonce,
$key,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
$state->update($ad);
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state->update($ciphertext);
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
return $ciphertext . $state->finish();
}
/**
* AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_ietf_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $adlen - Length of associated data */
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
/** @var int $len - Length of message (ciphertext + MAC) */
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
/** @var int $clen - Length of ciphertext */
$clen = $len - self::aead_chacha20poly1305_IETF_ABYTES;
/** @var string The first block of the chacha20 keystream, used as
a poly1305 key */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(
32,
$nonce,
$key
);
/** @var string $mac - Message authentication code */
$mac = ParagonIE_Sodium_Core32_Util::substr(
$message,
$len - self::aead_chacha20poly1305_IETF_ABYTES,
self::aead_chacha20poly1305_IETF_ABYTES
);
/** @var string $ciphertext - The encrypted message (sans MAC) */
$ciphertext = ParagonIE_Sodium_Core32_Util::substr(
$message,
0,
$len - self::aead_chacha20poly1305_IETF_ABYTES
);
/* Recalculate the Poly1305 authentication tag (MAC): */
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
$state->update($ad);
$state->update(str_repeat("\x00", ((0x10 - $adlen)
& 0xf)));
$state->update($ciphertext);
$state->update(str_repeat("\x00", (0x10 - $clen) &
0xf));
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
$computed_mac = $state->finish();
/* Compare the given MAC with the recalculated MAC: */
if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac))
{
throw new SodiumException('Invalid MAC');
}
// Here, we know that the MAC is valid, so we decrypt and return
the plaintext
return ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$ciphertext,
$nonce,
$key,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
}
/**
* AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_chacha20poly1305_ietf_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
/** @var int $len - Length of the plaintext message */
$len = ParagonIE_Sodium_Core32_Util::strlen($message);
/** @var int $adlen - Length of the associated data */
$adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
/** @var string The first block of the chacha20 keystream, used as
a poly1305 key */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(
32,
$nonce,
$key
);
$state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
try {
ParagonIE_Sodium_Compat::memzero($block0);
} catch (SodiumException $ex) {
$block0 = null;
}
/** @var string $ciphertext - Raw encrypted data */
$ciphertext = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$message,
$nonce,
$key,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
$state->update($ad);
$state->update(str_repeat("\x00", ((0x10 - $adlen)
& 0xf)));
$state->update($ciphertext);
$state->update(str_repeat("\x00", ((0x10 - $len) &
0xf)));
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
$state->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
return $ciphertext . $state->finish();
}
/**
* AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_xchacha20poly1305_ietf_decrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = "\x00\x00\x00\x00" .
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_decrypt($message, $ad,
$nonceLast, $subkey);
}
/**
* AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $ad
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function aead_xchacha20poly1305_ietf_encrypt(
$message = '',
$ad = '',
$nonce = '',
$key = ''
) {
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = "\x00\x00\x00\x00" .
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
return self::aead_chacha20poly1305_ietf_encrypt($message, $ad,
$nonceLast, $subkey);
}
/**
* HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $key
* @return string
* @throws TypeError
*/
public static function auth($message, $key)
{
return ParagonIE_Sodium_Core32_Util::substr(
hash_hmac('sha512', $message, $key, true),
0,
32
);
}
/**
* HMAC-SHA-512-256 validation. Constant-time via hash_equals().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $mac
* @param string $message
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function auth_verify($mac, $message, $key)
{
return ParagonIE_Sodium_Core32_Util::hashEquals(
$mac,
self::auth($message, $key)
);
}
/**
* X25519 key exchange followed by XSalsa20Poly1305 symmetric
encryption
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box($plaintext, $nonce, $keypair)
{
return self::secretbox(
$plaintext,
$nonce,
self::box_beforenm(
self::box_secretkey($keypair),
self::box_publickey($keypair)
)
);
}
/**
* X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $publicKey
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal($message, $publicKey)
{
/** @var string $ephemeralKeypair */
$ephemeralKeypair = self::box_keypair();
/** @var string $ephemeralSK */
$ephemeralSK = self::box_secretkey($ephemeralKeypair);
/** @var string $ephemeralPK */
$ephemeralPK = self::box_publickey($ephemeralKeypair);
/** @var string $nonce */
$nonce = self::generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var string $keypair - The combined keypair used in
crypto_box() */
$keypair =
self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
/** @var string $ciphertext Ciphertext + MAC from crypto_box */
$ciphertext = self::box($message, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($ephemeralKeypair);
ParagonIE_Sodium_Compat::memzero($ephemeralSK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$ephemeralKeypair = null;
$ephemeralSK = null;
$nonce = null;
}
return $ephemeralPK . $ciphertext;
}
/**
* Opens a message encrypted via box_seal().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal_open($message, $keypair)
{
/** @var string $ephemeralPK */
$ephemeralPK = ParagonIE_Sodium_Core32_Util::substr($message, 0,
32);
/** @var string $ciphertext (ciphertext + MAC) */
$ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 32);
/** @var string $secretKey */
$secretKey = self::box_secretkey($keypair);
/** @var string $publicKey */
$publicKey = self::box_publickey($keypair);
/** @var string $nonce */
$nonce = self::generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var string $keypair */
$keypair =
self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
/** @var string $m */
$m = self::box_open($ciphertext, $nonce, $keypair);
try {
ParagonIE_Sodium_Compat::memzero($secretKey);
ParagonIE_Sodium_Compat::memzero($ephemeralPK);
ParagonIE_Sodium_Compat::memzero($nonce);
} catch (SodiumException $ex) {
$secretKey = null;
$ephemeralPK = null;
$nonce = null;
}
return $m;
}
/**
* Used by crypto_box() to get the crypto_secretbox() key.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sk
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_beforenm($sk, $pk)
{
return ParagonIE_Sodium_Core32_HSalsa20::hsalsa20(
str_repeat("\x00", 16),
self::scalarmult($sk, $pk)
);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @return string
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function box_keypair()
{
$sKey = random_bytes(32);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
/**
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_seed_keypair($seed)
{
$sKey = ParagonIE_Sodium_Core32_Util::substr(
hash('sha512', $seed, true),
0,
32
);
$pKey = self::scalarmult_base($sKey);
return $sKey . $pKey;
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @param string $pKey
* @return string
* @throws TypeError
*/
public static function box_keypair_from_secretkey_and_publickey($sKey,
$pKey)
{
return ParagonIE_Sodium_Core32_Util::substr($sKey, 0, 32) .
ParagonIE_Sodium_Core32_Util::substr($pKey, 0, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function box_secretkey($keypair)
{
if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== 64) {
throw new RangeException(
'Must be
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
);
}
return ParagonIE_Sodium_Core32_Util::substr($keypair, 0, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function box_publickey($keypair)
{
if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new RangeException(
'Must be
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
);
}
return ParagonIE_Sodium_Core32_Util::substr($keypair, 32, 32);
}
/**
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function box_publickey_from_secretkey($sKey)
{
if (ParagonIE_Sodium_Core32_Util::strlen($sKey) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) {
throw new RangeException(
'Must be
ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.'
);
}
return self::scalarmult_base($sKey);
}
/**
* Decrypt a message encrypted with box().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $keypair
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function box_open($ciphertext, $nonce, $keypair)
{
return self::secretbox_open(
$ciphertext,
$nonce,
self::box_beforenm(
self::box_secretkey($keypair),
self::box_publickey($keypair)
)
);
}
/**
* Calculate a BLAKE2b hash.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string|null $key
* @param int $outlen
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash($message, $key = '',
$outlen = 32)
{
// This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is
initialized
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
/** @var SplFixedArray $k */
$k =
ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() >
ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
/** @var SplFixedArray $in */
$in =
ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outlen);
ParagonIE_Sodium_Core32_BLAKE2b::update($ctx, $in,
$in->count());
/** @var SplFixedArray $out */
$out = new SplFixedArray($outlen);
$out = ParagonIE_Sodium_Core32_BLAKE2b::finish($ctx, $out);
/** @var array<int, int> */
$outArray = $out->toArray();
return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
}
/**
* Finalize a BLAKE2b hashing context, returning the hash.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ctx
* @param int $outlen
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_final($ctx, $outlen = 32)
{
if (!is_string($ctx)) {
throw new TypeError('Context must be a string');
}
$out = new SplFixedArray($outlen);
/** @var SplFixedArray $context */
$context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
/** @var SplFixedArray $out */
$out = ParagonIE_Sodium_Core32_BLAKE2b::finish($context, $out);
/** @var array<int, int> */
$outArray = $out->toArray();
return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
}
/**
* Initialize a hashing context for BLAKE2b.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $key
* @param int $outputLength
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_init($key = '',
$outputLength = 32)
{
// This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is
initialized
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k =
ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() >
ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength);
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
}
/**
* Initialize a hashing context for BLAKE2b.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $key
* @param int $outputLength
* @param string $salt
* @param string $personal
* @return string
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_init_salt_personal(
$key = '',
$outputLength = 32,
$salt = '',
$personal = ''
) {
// This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is
initialized
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
$k = null;
if (!empty($key)) {
$k =
ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
if ($k->count() >
ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
throw new RangeException('Invalid key size');
}
}
if (!empty($salt)) {
$s =
ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt);
} else {
$s = null;
}
if (!empty($salt)) {
$p =
ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal);
} else {
$p = null;
}
/** @var SplFixedArray $ctx */
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s,
$p);
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
}
/**
* Update a hashing context for BLAKE2b with $message
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ctx
* @param string $message
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function generichash_update($ctx, $message)
{
// This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is
initialized
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
/** @var SplFixedArray $context */
$context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
/** @var SplFixedArray $in */
$in =
ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in,
$in->count());
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context);
}
/**
* Libsodium's crypto_kx().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $my_sk
* @param string $their_pk
* @param string $client_pk
* @param string $server_pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function keyExchange($my_sk, $their_pk, $client_pk,
$server_pk)
{
return self::generichash(
self::scalarmult($my_sk, $their_pk) .
$client_pk .
$server_pk
);
}
/**
* ECDH over Curve25519
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $sKey
* @param string $pKey
* @return string
*
* @throws SodiumException
* @throws TypeError
*/
public static function scalarmult($sKey, $pKey)
{
$q =
ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10($sKey,
$pKey);
self::scalarmult_throw_if_zero($q);
return $q;
}
/**
* ECDH over Curve25519, using the basepoint.
* Used to get a secret key from a public key.
*
* @param string $secret
* @return string
*
* @throws SodiumException
* @throws TypeError
*/
public static function scalarmult_base($secret)
{
$q =
ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10_base($secret);
self::scalarmult_throw_if_zero($q);
return $q;
}
/**
* This throws an Error if a zero public key was passed to the
function.
*
* @param string $q
* @return void
* @throws SodiumException
* @throws TypeError
*/
protected static function scalarmult_throw_if_zero($q)
{
$d = 0;
for ($i = 0; $i <
self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) {
$d |= ParagonIE_Sodium_Core32_Util::chrToInt($q[$i]);
}
/* branch-free variant of === 0 */
if (-(1 & (($d - 1) >> 8))) {
throw new SodiumException('Zero public key is not
allowed');
}
}
/**
* XSalsa20-Poly1305 authenticated symmetric-key encryption.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox($plaintext, $nonce, $key)
{
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0,
$mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor(
$block0,
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
$subkey
);
/** @var string $c */
$c = ParagonIE_Sodium_Core32_Util::substr(
$block0,
self::secretbox_xsalsa20poly1305_ZEROBYTES
);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
ParagonIE_Sodium_Core32_Util::substr(
$plaintext,
self::secretbox_xsalsa20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1,
$subkey
);
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_Util::substr(
$block0,
0,
self::onetimeauth_poly1305_KEYBYTES
)
);
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state->update($c);
/** @var string $c - MAC || ciphertext */
$c = $state->finish() . $c;
unset($state);
return $c;
}
/**
* Decrypt a ciphertext generated via secretbox().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_open($ciphertext, $nonce, $key)
{
/** @var string $mac */
$mac = ParagonIE_Sodium_Core32_Util::substr(
$ciphertext,
0,
self::secretbox_xsalsa20poly1305_MACBYTES
);
/** @var string $c */
$c = ParagonIE_Sodium_Core32_Util::substr(
$ciphertext,
self::secretbox_xsalsa20poly1305_MACBYTES
);
/** @var int $clen */
$clen = ParagonIE_Sodium_Core32_Util::strlen($c);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20(
64,
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
$subkey
);
$verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify(
$mac,
$c,
ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32)
);
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
/** @var string $m - Decrypted message */
$m = ParagonIE_Sodium_Core32_Util::xorStrings(
ParagonIE_Sodium_Core32_Util::substr($block0,
self::secretbox_xsalsa20poly1305_ZEROBYTES),
ParagonIE_Sodium_Core32_Util::substr($c, 0,
self::secretbox_xsalsa20poly1305_ZEROBYTES)
);
if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) {
// We had more than 1 block, so let's continue to decrypt
the rest.
$m .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
ParagonIE_Sodium_Core32_Util::substr(
$c,
self::secretbox_xsalsa20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1,
(string) $subkey
);
}
return $m;
}
/**
* XChaCha20-Poly1305 authenticated symmetric-key encryption.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $plaintext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_xchacha20poly1305($plaintext, $nonce,
$key)
{
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
$key
);
$nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
$mlen0 = $mlen;
if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) {
$mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0,
$mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
$block0,
$nonceLast,
$subkey
);
/** @var string $c */
$c = ParagonIE_Sodium_Core32_Util::substr(
$block0,
self::secretbox_xchacha20poly1305_ZEROBYTES
);
if ($mlen > $mlen0) {
$c .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
ParagonIE_Sodium_Core32_Util::substr(
$plaintext,
self::secretbox_xchacha20poly1305_ZEROBYTES
),
$nonceLast,
$subkey,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
}
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_Util::substr(
$block0,
0,
self::onetimeauth_poly1305_KEYBYTES
)
);
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$state->update($c);
/** @var string $c - MAC || ciphertext */
$c = $state->finish() . $c;
unset($state);
return $c;
}
/**
* Decrypt a ciphertext generated via secretbox_xchacha20poly1305().
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $ciphertext
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_xchacha20poly1305_open($ciphertext,
$nonce, $key)
{
/** @var string $mac */
$mac = ParagonIE_Sodium_Core32_Util::substr(
$ciphertext,
0,
self::secretbox_xchacha20poly1305_MACBYTES
);
/** @var string $c */
$c = ParagonIE_Sodium_Core32_Util::substr(
$ciphertext,
self::secretbox_xchacha20poly1305_MACBYTES
);
/** @var int $clen */
$clen = ParagonIE_Sodium_Core32_Util::strlen($c);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce,
$key);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
64,
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
$subkey
);
$verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify(
$mac,
$c,
ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32)
);
if (!$verified) {
try {
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$subkey = null;
}
throw new SodiumException('Invalid MAC');
}
/** @var string $m - Decrypted message */
$m = ParagonIE_Sodium_Core32_Util::xorStrings(
ParagonIE_Sodium_Core32_Util::substr($block0,
self::secretbox_xchacha20poly1305_ZEROBYTES),
ParagonIE_Sodium_Core32_Util::substr($c, 0,
self::secretbox_xchacha20poly1305_ZEROBYTES)
);
if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) {
// We had more than 1 block, so let's continue to decrypt
the rest.
$m .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
ParagonIE_Sodium_Core32_Util::substr(
$c,
self::secretbox_xchacha20poly1305_ZEROBYTES
),
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
(string) $subkey,
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
}
return $m;
}
/**
* @param string $key
* @return array<int, string> Returns a state and a header.
* @throws Exception
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_init_push($key)
{
# randombytes_buf(out,
crypto_secretstream_xchacha20poly1305_HEADERBYTES);
$out = random_bytes(24);
# crypto_core_hchacha20(state->k, out, k, NULL);
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key);
$state = new ParagonIE_Sodium_Core32_SecretStream_State(
$subkey,
ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) .
str_repeat("\0", 4)
);
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
$state->counterReset();
# memcpy(STATE_INONCE(state), out +
crypto_core_hchacha20_INPUTBYTES,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
# memset(state->_pad, 0, sizeof state->_pad);
return array(
$state->toString(),
$out
);
}
/**
* @param string $key
* @param string $header
* @return string Returns a state.
* @throws Exception
*/
public static function secretstream_xchacha20poly1305_init_pull($key,
$header)
{
# crypto_core_hchacha20(state->k, in, k, NULL);
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
ParagonIE_Sodium_Core32_Util::substr($header, 0, 16),
$key
);
$state = new ParagonIE_Sodium_Core32_SecretStream_State(
$subkey,
ParagonIE_Sodium_Core32_Util::substr($header, 16)
);
$state->counterReset();
# memcpy(STATE_INONCE(state), in +
crypto_core_hchacha20_INPUTBYTES,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
# memset(state->_pad, 0, sizeof state->_pad);
# return 0;
return $state->toString();
}
/**
* @param string $state
* @param string $msg
* @param string $aad
* @param int $tag
* @return string
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_push(&$state,
$msg, $aad = '', $tag = 0)
{
$st =
ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
# crypto_onetimeauth_poly1305_state poly1305_state;
# unsigned char block[64U];
# unsigned char slen[8U];
# unsigned char *c;
# unsigned char *mac;
$msglen = ParagonIE_Sodium_Core32_Util::strlen($msg);
$aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
if ((($msglen + 63) >> 6) > 0xfffffffe) {
throw new SodiumException(
'message cannot be larger than
SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
);
}
# if (outlen_p != NULL) {
# *outlen_p = 0U;
# }
# if (mlen >
crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
# sodium_misuse();
# }
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce,
state->k);
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
# sodium_memzero(block, sizeof block);
$auth = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32,
$st->getCombinedNonce(), $st->getKey())
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad,
adlen);
$auth->update($aad);
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
# (0x10 - adlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - $aadlen) &
0xf)));
# memset(block, 0, sizeof block);
# block[0] = tag;
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
# state->nonce, 1U,
state->k);
$block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
ParagonIE_Sodium_Core32_Util::intToChr($tag) .
str_repeat("\0", 63),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, block,
sizeof block);
$auth->update($block);
# out[0] = block[0];
$out = $block[0];
# c = out + (sizeof tag);
# crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce,
2U, state->k);
$cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$msg,
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(2)
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
$auth->update($cipher);
$out .= $cipher;
unset($cipher);
# crypto_onetimeauth_poly1305_update
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) &
0xf);
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen)
& 0xf)));
# STORE64_LE(slen, (uint64_t) adlen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen,
sizeof slen);
$auth->update($slen);
# STORE64_LE(slen, (sizeof block) + mlen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen,
sizeof slen);
$auth->update($slen);
# mac = c + mlen;
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
$mac = $auth->finish();
$out .= $mac;
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
unset($auth);
# XOR_BUF(STATE_INONCE(state), mac,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
$st->xorNonce($mac);
# sodium_increment(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
$st->incrementCounter();
// Overwrite by reference:
$state = $st->toString();
/** @var bool $rekey */
$rekey = ($tag &
ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY)
!== 0;
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY)
!= 0 ||
# sodium_is_zero(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
# crypto_secretstream_xchacha20poly1305_rekey(state);
# }
if ($rekey || $st->needsRekey()) {
// DO REKEY
self::secretstream_xchacha20poly1305_rekey($state);
}
# if (outlen_p != NULL) {
# *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES +
mlen;
# }
return $out;
}
/**
* @param string $state
* @param string $cipher
* @param string $aad
* @return bool|array{0: string, 1: int}
* @throws SodiumException
*/
public static function secretstream_xchacha20poly1305_pull(&$state,
$cipher, $aad = '')
{
$st =
ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
$cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher);
# mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
$msglen = $cipherlen -
ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
$aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
# if (mlen >
crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
# sodium_misuse();
# }
if ((($msglen + 63) >> 6) > 0xfffffffe) {
throw new SodiumException(
'message cannot be larger than
SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
);
}
# crypto_stream_chacha20_ietf(block, sizeof block,
state->nonce, state->k);
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
# sodium_memzero(block, sizeof block);
$auth = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32,
$st->getCombinedNonce(), $st->getKey())
);
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad,
adlen);
$auth->update($aad);
# crypto_onetimeauth_poly1305_update(&poly1305_state,
_pad0,
# (0x10 - adlen) & 0xf);
$auth->update(str_repeat("\0", ((0x10 - $aadlen) &
0xf)));
# memset(block, 0, sizeof block);
# block[0] = in[0];
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof
block,
# state->nonce, 1U,
state->k);
$block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$cipher[0] . str_repeat("\0", 63),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(1)
);
# tag = block[0];
# block[0] = in[0];
# crypto_onetimeauth_poly1305_update(&poly1305_state,
block, sizeof block);
$tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]);
$block[0] = $cipher[0];
$auth->update($block);
# c = in + (sizeof tag);
# crypto_onetimeauth_poly1305_update(&poly1305_state, c,
mlen);
$auth->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1,
$msglen));
# crypto_onetimeauth_poly1305_update
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen)
& 0xf);
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen)
& 0xf)));
# STORE64_LE(slen, (uint64_t) adlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen,
sizeof slen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
$auth->update($slen);
# STORE64_LE(slen, (sizeof block) + mlen);
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen,
sizeof slen);
$slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
$auth->update($slen);
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
$mac = $auth->finish();
# stored_mac = c + mlen;
# if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
# sodium_memzero(mac, sizeof mac);
# return -1;
# }
$stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen +
1, 16);
if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) {
return false;
}
# crypto_stream_chacha20_ietf_xor_ic(m, c, mlen,
state->nonce, 2U, state->k);
$out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen),
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(2)
);
# XOR_BUF(STATE_INONCE(state), mac,
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
$st->xorNonce($mac);
# sodium_increment(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
$st->incrementCounter();
# if ((tag &
crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
# sodium_is_zero(STATE_COUNTER(state),
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES))
{
# crypto_secretstream_xchacha20poly1305_rekey(state);
# }
// Overwrite by reference:
$state = $st->toString();
/** @var bool $rekey */
$rekey = ($tag &
ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY)
!== 0;
if ($rekey || $st->needsRekey()) {
// DO REKEY
self::secretstream_xchacha20poly1305_rekey($state);
}
return array($out, $tag);
}
/**
* @param string $state
* @return void
* @throws SodiumException
*/
public static function
secretstream_xchacha20poly1305_rekey(&$state)
{
$st =
ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
# unsigned char
new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
# crypto_secretstream_xchacha20poly1305_INONCEBYTES];
# size_t i;
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
# new_key_and_inonce[i] = state->k[i];
# }
$new_key_and_inonce = $st->getKey();
# for (i = 0U; i <
crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i]
=
# STATE_INONCE(state)[i];
# }
$new_key_and_inonce .=
ParagonIE_Sodium_Core32_Util::substR($st->getNonce(), 0, 8);
# crypto_stream_chacha20_ietf_xor(new_key_and_inonce,
new_key_and_inonce,
# sizeof new_key_and_inonce,
# state->nonce, state->k);
$st->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
$new_key_and_inonce,
$st->getCombinedNonce(),
$st->getKey(),
ParagonIE_Sodium_Core32_Util::store64_le(0)
));
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
# state->k[i] = new_key_and_inonce[i];
# }
# for (i = 0U; i <
crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
# STATE_INONCE(state)[i] =
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES
+ i];
# }
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
$st->counterReset();
$state = $st->toString();
}
/**
* Detached Ed25519 signature.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_detached($message, $sk)
{
return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message,
$sk);
}
/**
* Attached Ed25519 signature. (Returns a signed message.)
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk);
}
/**
* Opens a signed message. If valid, returns the message.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $signedMessage
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($signedMessage, $pk)
{
return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage,
$pk);
}
/**
* Verify a detached signature of a given message and public key.
*
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
*
* @param string $signature
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function sign_verify_detached($signature, $message, $pk)
{
return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature,
$message, $pk);
}
}
<?php
if (class_exists('ParagonIE_Sodium_File', false)) {
return;
}
/**
* Class ParagonIE_Sodium_File
*/
class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
{
/* PHP's default buffer size is 8192 for fread()/fwrite(). */
const BUFFER_SIZE = 8192;
/**
* Box a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_box(), but produces
* the same result.
*
* @param string $inputFile Absolute path to a file on the filesystem
* @param string $outputFile Absolute path to a file on the filesystem
* @param string $nonce Number to be used only once
* @param string $keyPair ECDH secret key and ECDH public key
concatenated
*
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function box($inputFile, $outputFile, $nonce, $keyPair)
{
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' .
gettype($outputFile) . ' given.');
}
if (!is_string($nonce)) {
throw new TypeError('Argument 3 must be a string, ' .
gettype($nonce) . ' given.');
}
/* Input validation: */
if (!is_string($keyPair)) {
throw new TypeError('Argument 4 must be a string, ' .
gettype($keyPair) . ' given.');
}
if (self::strlen($nonce) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES) {
throw new TypeError('Argument 3 must be
CRYPTO_BOX_NONCEBYTES bytes');
}
if (self::strlen($keyPair) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new TypeError('Argument 4 must be
CRYPTO_BOX_KEYPAIRBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for
writing');
}
$res = self::box_encrypt($ifp, $ofp, $size, $nonce, $keyPair);
fclose($ifp);
fclose($ofp);
return $res;
}
/**
* Open a boxed file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_box_open(), but produces
* the same result.
*
* Warning: Does not protect against TOCTOU attacks. You should
* just load the file into memory and use crypto_box_open() if
* you are worried about those.
*
* @param string $inputFile
* @param string $outputFile
* @param string $nonce
* @param string $keypair
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function box_open($inputFile, $outputFile, $nonce,
$keypair)
{
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' .
gettype($outputFile) . ' given.');
}
if (!is_string($nonce)) {
throw new TypeError('Argument 3 must be a string, ' .
gettype($nonce) . ' given.');
}
if (!is_string($keypair)) {
throw new TypeError('Argument 4 must be a string, ' .
gettype($keypair) . ' given.');
}
/* Input validation: */
if (self::strlen($nonce) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_NONCEBYTES) {
throw new TypeError('Argument 4 must be
CRYPTO_BOX_NONCEBYTES bytes');
}
if (self::strlen($keypair) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new TypeError('Argument 4 must be
CRYPTO_BOX_KEYPAIRBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for
writing');
}
$res = self::box_decrypt($ifp, $ofp, $size, $nonce, $keypair);
fclose($ifp);
fclose($ofp);
try {
ParagonIE_Sodium_Compat::memzero($nonce);
ParagonIE_Sodium_Compat::memzero($ephKeypair);
} catch (SodiumException $ex) {
if (isset($ephKeypair)) {
unset($ephKeypair);
}
}
return $res;
}
/**
* Seal a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_box_seal(), but produces
* the same result.
*
* @param string $inputFile Absolute path to a file on the filesystem
* @param string $outputFile Absolute path to a file on the filesystem
* @param string $publicKey ECDH public key
*
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal($inputFile, $outputFile, $publicKey)
{
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' .
gettype($outputFile) . ' given.');
}
if (!is_string($publicKey)) {
throw new TypeError('Argument 3 must be a string, ' .
gettype($publicKey) . ' given.');
}
/* Input validation: */
if (self::strlen($publicKey) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new TypeError('Argument 3 must be
CRYPTO_BOX_PUBLICKEYBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for
writing');
}
/** @var string $ephKeypair */
$ephKeypair = ParagonIE_Sodium_Compat::crypto_box_keypair();
/** @var string $msgKeypair */
$msgKeypair =
ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey(
ParagonIE_Sodium_Compat::crypto_box_secretkey($ephKeypair),
$publicKey
);
/** @var string $ephemeralPK */
$ephemeralPK =
ParagonIE_Sodium_Compat::crypto_box_publickey($ephKeypair);
/** @var string $nonce */
$nonce = ParagonIE_Sodium_Compat::crypto_generichash(
$ephemeralPK . $publicKey,
'',
24
);
/** @var int $firstWrite */
$firstWrite = fwrite(
$ofp,
$ephemeralPK,
ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES
);
if (!is_int($firstWrite)) {
fclose($ifp);
fclose($ofp);
ParagonIE_Sodium_Compat::memzero($ephKeypair);
throw new SodiumException('Could not write to output
file');
}
if ($firstWrite !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) {
ParagonIE_Sodium_Compat::memzero($ephKeypair);
fclose($ifp);
fclose($ofp);
throw new SodiumException('Error writing public key to
output file');
}
$res = self::box_encrypt($ifp, $ofp, $size, $nonce, $msgKeypair);
fclose($ifp);
fclose($ofp);
try {
ParagonIE_Sodium_Compat::memzero($nonce);
ParagonIE_Sodium_Compat::memzero($ephKeypair);
} catch (SodiumException $ex) {
/** @psalm-suppress PossiblyUndefinedVariable */
unset($ephKeypair);
}
return $res;
}
/**
* Open a sealed file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_box_seal_open(), but produces
* the same result.
*
* Warning: Does not protect against TOCTOU attacks. You should
* just load the file into memory and use crypto_box_seal_open() if
* you are worried about those.
*
* @param string $inputFile
* @param string $outputFile
* @param string $ecdhKeypair
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function box_seal_open($inputFile, $outputFile,
$ecdhKeypair)
{
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' .
gettype($outputFile) . ' given.');
}
if (!is_string($ecdhKeypair)) {
throw new TypeError('Argument 3 must be a string, ' .
gettype($ecdhKeypair) . ' given.');
}
/* Input validation: */
if (self::strlen($ecdhKeypair) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
throw new TypeError('Argument 3 must be
CRYPTO_BOX_KEYPAIRBYTES bytes');
}
$publicKey =
ParagonIE_Sodium_Compat::crypto_box_publickey($ecdhKeypair);
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for
writing');
}
$ephemeralPK = fread($ifp,
ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES);
if (!is_string($ephemeralPK)) {
throw new SodiumException('Could not read input
file');
}
if (self::strlen($ephemeralPK) !==
ParagonIE_Sodium_Compat::CRYPTO_BOX_PUBLICKEYBYTES) {
fclose($ifp);
fclose($ofp);
throw new SodiumException('Could not read public key from
sealed file');
}
$nonce = ParagonIE_Sodium_Compat::crypto_generichash(
$ephemeralPK . $publicKey,
'',
24
);
$msgKeypair =
ParagonIE_Sodium_Compat::crypto_box_keypair_from_secretkey_and_publickey(
ParagonIE_Sodium_Compat::crypto_box_secretkey($ecdhKeypair),
$ephemeralPK
);
$res = self::box_decrypt($ifp, $ofp, $size, $nonce, $msgKeypair);
fclose($ifp);
fclose($ofp);
try {
ParagonIE_Sodium_Compat::memzero($nonce);
ParagonIE_Sodium_Compat::memzero($ephKeypair);
} catch (SodiumException $ex) {
if (isset($ephKeypair)) {
unset($ephKeypair);
}
}
return $res;
}
/**
* Calculate the BLAKE2b hash of a file.
*
* @param string $filePath Absolute path to a file on the
filesystem
* @param string|null $key BLAKE2b key
* @param int $outputLength Length of hash output
*
* @return string BLAKE2b hash
* @throws SodiumException
* @throws TypeError
* @psalm-suppress FailedTypeResolution
*/
public static function generichash($filePath, $key = '',
$outputLength = 32)
{
/* Type checks: */
if (!is_string($filePath)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($filePath) . ' given.');
}
if (!is_string($key)) {
if (is_null($key)) {
$key = '';
} else {
throw new TypeError('Argument 2 must be a string,
' . gettype($key) . ' given.');
}
}
if (!is_int($outputLength)) {
if (!is_numeric($outputLength)) {
throw new TypeError('Argument 3 must be an integer,
' . gettype($outputLength) . ' given.');
}
$outputLength = (int) $outputLength;
}
/* Input validation: */
if (!empty($key)) {
if (self::strlen($key) <
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
throw new TypeError('Argument 2 must be at least
CRYPTO_GENERICHASH_KEYBYTES_MIN bytes');
}
if (self::strlen($key) >
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
throw new TypeError('Argument 2 must be at most
CRYPTO_GENERICHASH_KEYBYTES_MAX bytes');
}
}
if ($outputLength <
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MIN) {
throw new SodiumException('Argument 3 must be at least
CRYPTO_GENERICHASH_BYTES_MIN');
}
if ($outputLength >
ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MAX) {
throw new SodiumException('Argument 3 must be at least
CRYPTO_GENERICHASH_BYTES_MAX');
}
/** @var int $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var resource $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for
reading');
}
$ctx = ParagonIE_Sodium_Compat::crypto_generichash_init($key,
$outputLength);
while ($size > 0) {
$blockSize = $size > 64
? 64
: $size;
$read = fread($fp, $blockSize);
if (!is_string($read)) {
throw new SodiumException('Could not read input
file');
}
ParagonIE_Sodium_Compat::crypto_generichash_update($ctx,
$read);
$size -= $blockSize;
}
fclose($fp);
return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx,
$outputLength);
}
/**
* Encrypt a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_secretbox(), but produces
* the same result.
*
* @param string $inputFile Absolute path to a file on the filesystem
* @param string $outputFile Absolute path to a file on the filesystem
* @param string $nonce Number to be used only once
* @param string $key Encryption key
*
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox($inputFile, $outputFile, $nonce, $key)
{
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($inputFile) . ' given..');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' .
gettype($outputFile) . ' given.');
}
if (!is_string($nonce)) {
throw new TypeError('Argument 3 must be a string, ' .
gettype($nonce) . ' given.');
}
/* Input validation: */
if (self::strlen($nonce) !==
ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new TypeError('Argument 3 must be
CRYPTO_SECRETBOX_NONCEBYTES bytes');
}
if (!is_string($key)) {
throw new TypeError('Argument 4 must be a string, ' .
gettype($key) . ' given.');
}
if (self::strlen($key) !==
ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) {
throw new TypeError('Argument 4 must be
CRYPTO_SECRETBOX_KEYBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for
writing');
}
$res = self::secretbox_encrypt($ifp, $ofp, $size, $nonce, $key);
fclose($ifp);
fclose($ofp);
return $res;
}
/**
* Seal a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_secretbox_open(), but produces
* the same result.
*
* Warning: Does not protect against TOCTOU attacks. You should
* just load the file into memory and use crypto_secretbox_open() if
* you are worried about those.
*
* @param string $inputFile
* @param string $outputFile
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function secretbox_open($inputFile, $outputFile, $nonce,
$key)
{
/* Type checks: */
if (!is_string($inputFile)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($inputFile) . ' given.');
}
if (!is_string($outputFile)) {
throw new TypeError('Argument 2 must be a string, ' .
gettype($outputFile) . ' given.');
}
if (!is_string($nonce)) {
throw new TypeError('Argument 3 must be a string, ' .
gettype($nonce) . ' given.');
}
if (!is_string($key)) {
throw new TypeError('Argument 4 must be a string, ' .
gettype($key) . ' given.');
}
/* Input validation: */
if (self::strlen($nonce) !==
ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new TypeError('Argument 4 must be
CRYPTO_SECRETBOX_NONCEBYTES bytes');
}
if (self::strlen($key) !==
ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) {
throw new TypeError('Argument 4 must be
CRYPTO_SECRETBOXBOX_KEYBYTES bytes');
}
/** @var int $size */
$size = filesize($inputFile);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var resource $ifp */
$ifp = fopen($inputFile, 'rb');
if (!is_resource($ifp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var resource $ofp */
$ofp = fopen($outputFile, 'wb');
if (!is_resource($ofp)) {
fclose($ifp);
throw new SodiumException('Could not open output file for
writing');
}
$res = self::secretbox_decrypt($ifp, $ofp, $size, $nonce, $key);
fclose($ifp);
fclose($ofp);
try {
ParagonIE_Sodium_Compat::memzero($key);
} catch (SodiumException $ex) {
/** @psalm-suppress PossiblyUndefinedVariable */
unset($key);
}
return $res;
}
/**
* Sign a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_sign_detached(), but produces
* the same result.
*
* @param string $filePath Absolute path to a file on the filesystem
* @param string $secretKey Secret signing key
*
* @return string Ed25519 signature
* @throws SodiumException
* @throws TypeError
*/
public static function sign($filePath, $secretKey)
{
/* Type checks: */
if (!is_string($filePath)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($filePath) . ' given.');
}
if (!is_string($secretKey)) {
throw new TypeError('Argument 2 must be a string, ' .
gettype($secretKey) . ' given.');
}
/* Input validation: */
if (self::strlen($secretKey) !==
ParagonIE_Sodium_Compat::CRYPTO_SIGN_SECRETKEYBYTES) {
throw new TypeError('Argument 2 must be
CRYPTO_SIGN_SECRETKEYBYTES bytes');
}
if (PHP_INT_SIZE === 4) {
return self::sign_core32($filePath, $secretKey);
}
/** @var int $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var resource $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var string $az */
$az = hash('sha512', self::substr($secretKey, 0, 32),
true);
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
$hs = hash_init('sha512');
hash_update($hs, self::substr($az, 32, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $nonceHash */
$nonceHash = hash_final($hs, true);
/** @var string $pk */
$pk = self::substr($secretKey, 32, 32);
/** @var string $nonce */
$nonce = ParagonIE_Sodium_Core_Ed25519::sc_reduce($nonceHash) .
self::substr($nonceHash, 32);
/** @var string $sig */
$sig = ParagonIE_Sodium_Core_Ed25519::ge_p3_tobytes(
ParagonIE_Sodium_Core_Ed25519::ge_scalarmult_base($nonce)
);
$hs = hash_init('sha512');
hash_update($hs, self::substr($sig, 0, 32));
hash_update($hs, self::substr($pk, 0, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $hramHash */
$hramHash = hash_final($hs, true);
/** @var string $hram */
$hram = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hramHash);
/** @var string $sigAfter */
$sigAfter = ParagonIE_Sodium_Core_Ed25519::sc_muladd($hram, $az,
$nonce);
/** @var string $sig */
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
ParagonIE_Sodium_Compat::memzero($az);
} catch (SodiumException $ex) {
$az = null;
}
fclose($fp);
return $sig;
}
/**
* Verify a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_sign_verify_detached(), but
* produces the same result.
*
* @param string $sig Ed25519 signature
* @param string $filePath Absolute path to a file on the filesystem
* @param string $publicKey Signing public key
*
* @return bool
* @throws SodiumException
* @throws TypeError
* @throws Exception
*/
public static function verify($sig, $filePath, $publicKey)
{
/* Type checks: */
if (!is_string($sig)) {
throw new TypeError('Argument 1 must be a string, ' .
gettype($sig) . ' given.');
}
if (!is_string($filePath)) {
throw new TypeError('Argument 2 must be a string, ' .
gettype($filePath) . ' given.');
}
if (!is_string($publicKey)) {
throw new TypeError('Argument 3 must be a string, ' .
gettype($publicKey) . ' given.');
}
/* Input validation: */
if (self::strlen($sig) !==
ParagonIE_Sodium_Compat::CRYPTO_SIGN_BYTES) {
throw new TypeError('Argument 1 must be CRYPTO_SIGN_BYTES
bytes');
}
if (self::strlen($publicKey) !==
ParagonIE_Sodium_Compat::CRYPTO_SIGN_PUBLICKEYBYTES) {
throw new TypeError('Argument 3 must be
CRYPTO_SIGN_PUBLICKEYBYTES bytes');
}
if (self::strlen($sig) < 64) {
throw new SodiumException('Signature is too short');
}
if (PHP_INT_SIZE === 4) {
return self::verify_core32($sig, $filePath, $publicKey);
}
/* Security checks */
if (
(ParagonIE_Sodium_Core_Ed25519::chrToInt($sig[63]) & 240)
&&
ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig,
32, 32))
) {
throw new SodiumException('S < L - Invalid
signature');
}
if (ParagonIE_Sodium_Core_Ed25519::small_order($sig)) {
throw new SodiumException('Signature is on too small of an
order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($publicKey[$i]);
}
if ($d === 0) {
throw new SodiumException('All zero public key');
}
/** @var int $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var resource $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var bool The original value of
ParagonIE_Sodium_Compat::$fastMult */
$orig = ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up
verification.
ParagonIE_Sodium_Compat::$fastMult = true;
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */
$A =
ParagonIE_Sodium_Core_Ed25519::ge_frombytes_negate_vartime($publicKey);
$hs = hash_init('sha512');
hash_update($hs, self::substr($sig, 0, 32));
hash_update($hs, self::substr($publicKey, 0, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $hDigest */
$hDigest = hash_final($hs, true);
/** @var string $h */
$h = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hDigest) .
self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */
$R = ParagonIE_Sodium_Core_Ed25519::ge_double_scalarmult_vartime(
$h,
$A,
self::substr($sig, 32)
);
/** @var string $rcheck */
$rcheck = ParagonIE_Sodium_Core_Ed25519::ge_tobytes($R);
// Close the file handle
fclose($fp);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $boxKeypair
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function box_encrypt($ifp, $ofp, $mlen, $nonce,
$boxKeypair)
{
if (PHP_INT_SIZE === 4) {
return self::secretbox_encrypt(
$ifp,
$ofp,
$mlen,
$nonce,
ParagonIE_Sodium_Crypto32::box_beforenm(
ParagonIE_Sodium_Crypto32::box_secretkey($boxKeypair),
ParagonIE_Sodium_Crypto32::box_publickey($boxKeypair)
)
);
}
return self::secretbox_encrypt(
$ifp,
$ofp,
$mlen,
$nonce,
ParagonIE_Sodium_Crypto::box_beforenm(
ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair),
ParagonIE_Sodium_Crypto::box_publickey($boxKeypair)
)
);
}
/**
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $boxKeypair
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function box_decrypt($ifp, $ofp, $mlen, $nonce,
$boxKeypair)
{
if (PHP_INT_SIZE === 4) {
return self::secretbox_decrypt(
$ifp,
$ofp,
$mlen,
$nonce,
ParagonIE_Sodium_Crypto32::box_beforenm(
ParagonIE_Sodium_Crypto32::box_secretkey($boxKeypair),
ParagonIE_Sodium_Crypto32::box_publickey($boxKeypair)
)
);
}
return self::secretbox_decrypt(
$ifp,
$ofp,
$mlen,
$nonce,
ParagonIE_Sodium_Crypto::box_beforenm(
ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair),
ParagonIE_Sodium_Crypto::box_publickey($boxKeypair)
)
);
}
/**
* Encrypt a file
*
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function secretbox_encrypt($ifp, $ofp, $mlen, $nonce,
$key)
{
if (PHP_INT_SIZE === 4) {
return self::secretbox_encrypt_core32($ifp, $ofp, $mlen,
$nonce, $key);
}
$plaintext = fread($ifp, 32);
if (!is_string($plaintext)) {
throw new SodiumException('Could not read input
file');
}
$first32 = self::ftell($ifp);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
/** @var string $realNonce */
$realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen0 = $mlen;
if ($mlen0 > 64 -
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) {
$mlen0 = 64 -
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0,
$mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor(
$block0,
$realNonce,
$subkey
);
$state = new ParagonIE_Sodium_Core_Poly1305_State(
ParagonIE_Sodium_Core_Util::substr(
$block0,
0,
ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES
)
);
// Pre-write 16 blank bytes for the Poly1305 tag
$start = self::ftell($ofp);
fwrite($ofp, str_repeat("\x00", 16));
/** @var string $c */
$cBlock = ParagonIE_Sodium_Core_Util::substr(
$block0,
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES
);
$state->update($cBlock);
fwrite($ofp, $cBlock);
$mlen -= 32;
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
/*
* Set the cursor to the end of the first half-block. All future
bytes will
* generated from salsa20_xor_ic, starting from 1 (second block).
*/
fseek($ifp, $first32, SEEK_SET);
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$plaintext = fread($ifp, $blockSize);
if (!is_string($plaintext)) {
throw new SodiumException('Could not read input
file');
}
$cBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
$plaintext,
$realNonce,
$iter,
$subkey
);
fwrite($ofp, $cBlock, $blockSize);
$state->update($cBlock);
$mlen -= $blockSize;
$iter += $incr;
}
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$end = self::ftell($ofp);
/*
* Write the Poly1305 authentication tag that provides integrity
* over the ciphertext (encrypt-then-MAC)
*/
fseek($ofp, $start, SEEK_SET);
fwrite($ofp, $state->finish(),
ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES);
fseek($ofp, $end, SEEK_SET);
unset($state);
return true;
}
/**
* Decrypt a file
*
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function secretbox_decrypt($ifp, $ofp, $mlen, $nonce,
$key)
{
if (PHP_INT_SIZE === 4) {
return self::secretbox_decrypt_core32($ifp, $ofp, $mlen,
$nonce, $key);
}
$tag = fread($ifp, 16);
if (!is_string($tag)) {
throw new SodiumException('Could not read input
file');
}
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
/** @var string $realNonce */
$realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core_Salsa20::salsa20(
64,
ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
$subkey
);
/* Verify the Poly1305 MAC -before- attempting to decrypt! */
$state = new
ParagonIE_Sodium_Core_Poly1305_State(self::substr($block0, 0, 32));
if (!self::onetimeauth_verify($state, $ifp, $tag, $mlen)) {
throw new SodiumException('Invalid MAC');
}
/*
* Set the cursor to the end of the first half-block. All future
bytes will
* generated from salsa20_xor_ic, starting from 1 (second block).
*/
$first32 = fread($ifp, 32);
if (!is_string($first32)) {
throw new SodiumException('Could not read input
file');
}
$first32len = self::strlen($first32);
fwrite(
$ofp,
self::xorStrings(
self::substr($block0, 32, $first32len),
self::substr($first32, 0, $first32len)
)
);
$mlen -= 32;
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
/* Decrypts ciphertext, writes to output file. */
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input
file');
}
$pBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
$ciphertext,
$realNonce,
$iter,
$subkey
);
fwrite($ofp, $pBlock, $blockSize);
$mlen -= $blockSize;
$iter += $incr;
}
return true;
}
/**
* @param ParagonIE_Sodium_Core_Poly1305_State $state
* @param resource $ifp
* @param string $tag
* @param int $mlen
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function onetimeauth_verify(
ParagonIE_Sodium_Core_Poly1305_State $state,
$ifp,
$tag = '',
$mlen = 0
) {
/** @var int $pos */
$pos = self::ftell($ifp);
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input
file');
}
$state->update($ciphertext);
$mlen -= $blockSize;
$iter += $incr;
}
$res = ParagonIE_Sodium_Core_Util::verify_16($tag,
$state->finish());
fseek($ifp, $pos, SEEK_SET);
return $res;
}
/**
* Update a hash context with the contents of a file, without
* loading the entire file into memory.
*
* @param resource|object $hash
* @param resource $fp
* @param int $size
* @return resource|object Resource on PHP < 7.2, HashContext object
on PHP >= 7.2
* @throws SodiumException
* @throws TypeError
* @psalm-suppress PossiblyInvalidArgument
* PHP 7.2 changes from a resource to an object,
* which causes Psalm to complain about an error.
* @psalm-suppress TypeCoercion
* Ditto.
*/
public static function updateHashWithFile($hash, $fp, $size = 0)
{
/* Type checks: */
if (PHP_VERSION_ID < 70200) {
if (!is_resource($hash)) {
throw new TypeError('Argument 1 must be a resource,
' . gettype($hash) . ' given.');
}
} else {
if (!is_object($hash)) {
throw new TypeError('Argument 1 must be an object (PHP
7.2+), ' . gettype($hash) . ' given.');
}
}
if (!is_resource($fp)) {
throw new TypeError('Argument 2 must be a resource, '
. gettype($fp) . ' given.');
}
if (!is_int($size)) {
throw new TypeError('Argument 3 must be an integer, '
. gettype($size) . ' given.');
}
/** @var int $originalPosition */
$originalPosition = self::ftell($fp);
// Move file pointer to beginning of file
fseek($fp, 0, SEEK_SET);
for ($i = 0; $i < $size; $i += self::BUFFER_SIZE) {
/** @var string|bool $message */
$message = fread(
$fp,
($size - $i) > self::BUFFER_SIZE
? $size - $i
: self::BUFFER_SIZE
);
if (!is_string($message)) {
throw new SodiumException('Unexpected error reading
from file.');
}
/** @var string $message */
/** @psalm-suppress InvalidArgument */
hash_update($hash, $message);
}
// Reset file pointer's position
fseek($fp, $originalPosition, SEEK_SET);
return $hash;
}
/**
* Sign a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_sign_detached(), but produces
* the same result. (32-bit)
*
* @param string $filePath Absolute path to a file on the filesystem
* @param string $secretKey Secret signing key
*
* @return string Ed25519 signature
* @throws SodiumException
* @throws TypeError
*/
private static function sign_core32($filePath, $secretKey)
{
/** @var int|bool $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var int $size */
/** @var resource|bool $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var resource $fp */
/** @var string $az */
$az = hash('sha512', self::substr($secretKey, 0, 32),
true);
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
$hs = hash_init('sha512');
hash_update($hs, self::substr($az, 32, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $nonceHash */
$nonceHash = hash_final($hs, true);
/** @var string $pk */
$pk = self::substr($secretKey, 32, 32);
/** @var string $nonce */
$nonce = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($nonceHash) .
self::substr($nonceHash, 32);
/** @var string $sig */
$sig = ParagonIE_Sodium_Core32_Ed25519::ge_p3_tobytes(
ParagonIE_Sodium_Core32_Ed25519::ge_scalarmult_base($nonce)
);
$hs = hash_init('sha512');
hash_update($hs, self::substr($sig, 0, 32));
hash_update($hs, self::substr($pk, 0, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $hramHash */
$hramHash = hash_final($hs, true);
/** @var string $hram */
$hram = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($hramHash);
/** @var string $sigAfter */
$sigAfter = ParagonIE_Sodium_Core32_Ed25519::sc_muladd($hram, $az,
$nonce);
/** @var string $sig */
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
ParagonIE_Sodium_Compat::memzero($az);
} catch (SodiumException $ex) {
$az = null;
}
fclose($fp);
return $sig;
}
/**
*
* Verify a file (rather than a string). Uses less memory than
* ParagonIE_Sodium_Compat::crypto_sign_verify_detached(), but
* produces the same result. (32-bit)
*
* @param string $sig Ed25519 signature
* @param string $filePath Absolute path to a file on the filesystem
* @param string $publicKey Signing public key
*
* @return bool
* @throws SodiumException
* @throws Exception
*/
public static function verify_core32($sig, $filePath, $publicKey)
{
/* Security checks */
if
(ParagonIE_Sodium_Core32_Ed25519::check_S_lt_L(self::substr($sig, 32, 32)))
{
throw new SodiumException('S < L - Invalid
signature');
}
if (ParagonIE_Sodium_Core32_Ed25519::small_order($sig)) {
throw new SodiumException('Signature is on too small of an
order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($publicKey[$i]);
}
if ($d === 0) {
throw new SodiumException('All zero public key');
}
/** @var int|bool $size */
$size = filesize($filePath);
if (!is_int($size)) {
throw new SodiumException('Could not obtain the file
size');
}
/** @var int $size */
/** @var resource|bool $fp */
$fp = fopen($filePath, 'rb');
if (!is_resource($fp)) {
throw new SodiumException('Could not open input file for
reading');
}
/** @var resource $fp */
/** @var bool The original value of
ParagonIE_Sodium_Compat::$fastMult */
$orig = ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up
verification.
ParagonIE_Sodium_Compat::$fastMult = true;
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */
$A =
ParagonIE_Sodium_Core32_Ed25519::ge_frombytes_negate_vartime($publicKey);
$hs = hash_init('sha512');
hash_update($hs, self::substr($sig, 0, 32));
hash_update($hs, self::substr($publicKey, 0, 32));
/** @var resource $hs */
$hs = self::updateHashWithFile($hs, $fp, $size);
/** @var string $hDigest */
$hDigest = hash_final($hs, true);
/** @var string $h */
$h = ParagonIE_Sodium_Core32_Ed25519::sc_reduce($hDigest) .
self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */
$R = ParagonIE_Sodium_Core32_Ed25519::ge_double_scalarmult_vartime(
$h,
$A,
self::substr($sig, 32)
);
/** @var string $rcheck */
$rcheck = ParagonIE_Sodium_Core32_Ed25519::ge_tobytes($R);
// Close the file handle
fclose($fp);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* Encrypt a file (32-bit)
*
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function secretbox_encrypt_core32($ifp, $ofp, $mlen,
$nonce, $key)
{
$plaintext = fread($ifp, 32);
if (!is_string($plaintext)) {
throw new SodiumException('Could not read input
file');
}
$first32 = self::ftell($ifp);
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
/** @var string $realNonce */
$realNonce = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = str_repeat("\x00", 32);
/** @var int $mlen - Length of the plaintext message */
$mlen0 = $mlen;
if ($mlen0 > 64 -
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) {
$mlen0 = 64 -
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES;
}
$block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0,
$mlen0);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor(
$block0,
$realNonce,
$subkey
);
$state = new ParagonIE_Sodium_Core32_Poly1305_State(
ParagonIE_Sodium_Core32_Util::substr(
$block0,
0,
ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES
)
);
// Pre-write 16 blank bytes for the Poly1305 tag
$start = self::ftell($ofp);
fwrite($ofp, str_repeat("\x00", 16));
/** @var string $c */
$cBlock = ParagonIE_Sodium_Core32_Util::substr(
$block0,
ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES
);
$state->update($cBlock);
fwrite($ofp, $cBlock);
$mlen -= 32;
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
/*
* Set the cursor to the end of the first half-block. All future
bytes will
* generated from salsa20_xor_ic, starting from 1 (second block).
*/
fseek($ifp, $first32, SEEK_SET);
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$plaintext = fread($ifp, $blockSize);
if (!is_string($plaintext)) {
throw new SodiumException('Could not read input
file');
}
$cBlock = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
$plaintext,
$realNonce,
$iter,
$subkey
);
fwrite($ofp, $cBlock, $blockSize);
$state->update($cBlock);
$mlen -= $blockSize;
$iter += $incr;
}
try {
ParagonIE_Sodium_Compat::memzero($block0);
ParagonIE_Sodium_Compat::memzero($subkey);
} catch (SodiumException $ex) {
$block0 = null;
$subkey = null;
}
$end = self::ftell($ofp);
/*
* Write the Poly1305 authentication tag that provides integrity
* over the ciphertext (encrypt-then-MAC)
*/
fseek($ofp, $start, SEEK_SET);
fwrite($ofp, $state->finish(),
ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES);
fseek($ofp, $end, SEEK_SET);
unset($state);
return true;
}
/**
* Decrypt a file (32-bit)
*
* @param resource $ifp
* @param resource $ofp
* @param int $mlen
* @param string $nonce
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function secretbox_decrypt_core32($ifp, $ofp, $mlen,
$nonce, $key)
{
$tag = fread($ifp, 16);
if (!is_string($tag)) {
throw new SodiumException('Could not read input
file');
}
/** @var string $subkey */
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
/** @var string $realNonce */
$realNonce = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
/** @var string $block0 */
$block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20(
64,
ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
$subkey
);
/* Verify the Poly1305 MAC -before- attempting to decrypt! */
$state = new
ParagonIE_Sodium_Core32_Poly1305_State(self::substr($block0, 0, 32));
if (!self::onetimeauth_verify_core32($state, $ifp, $tag, $mlen)) {
throw new SodiumException('Invalid MAC');
}
/*
* Set the cursor to the end of the first half-block. All future
bytes will
* generated from salsa20_xor_ic, starting from 1 (second block).
*/
$first32 = fread($ifp, 32);
if (!is_string($first32)) {
throw new SodiumException('Could not read input
file');
}
$first32len = self::strlen($first32);
fwrite(
$ofp,
self::xorStrings(
self::substr($block0, 32, $first32len),
self::substr($first32, 0, $first32len)
)
);
$mlen -= 32;
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
/* Decrypts ciphertext, writes to output file. */
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input
file');
}
$pBlock = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
$ciphertext,
$realNonce,
$iter,
$subkey
);
fwrite($ofp, $pBlock, $blockSize);
$mlen -= $blockSize;
$iter += $incr;
}
return true;
}
/**
* One-time message authentication for 32-bit systems
*
* @param ParagonIE_Sodium_Core32_Poly1305_State $state
* @param resource $ifp
* @param string $tag
* @param int $mlen
* @return bool
* @throws SodiumException
* @throws TypeError
*/
protected static function onetimeauth_verify_core32(
ParagonIE_Sodium_Core32_Poly1305_State $state,
$ifp,
$tag = '',
$mlen = 0
) {
/** @var int $pos */
$pos = self::ftell($ifp);
/** @var int $iter */
$iter = 1;
/** @var int $incr */
$incr = self::BUFFER_SIZE >> 6;
while ($mlen > 0) {
$blockSize = $mlen > self::BUFFER_SIZE
? self::BUFFER_SIZE
: $mlen;
$ciphertext = fread($ifp, $blockSize);
if (!is_string($ciphertext)) {
throw new SodiumException('Could not read input
file');
}
$state->update($ciphertext);
$mlen -= $blockSize;
$iter += $incr;
}
$res = ParagonIE_Sodium_Core32_Util::verify_16($tag,
$state->finish());
fseek($ifp, $pos, SEEK_SET);
return $res;
}
/**
* @param resource $resource
* @return int
* @throws SodiumException
*/
private static function ftell($resource)
{
$return = ftell($resource);
if (!is_int($return)) {
throw new SodiumException('ftell() returned false');
}
return (int) $return;
}
}
<?php
if (class_exists('SplFixedArray')) {
return;
}
/**
* The SplFixedArray class provides the main functionalities of array. The
* main differences between a SplFixedArray and a normal PHP array is that
* the SplFixedArray is of fixed length and allows only integers within
* the range as indexes. The advantage is that it allows a faster array
* implementation.
*/
class SplFixedArray implements Iterator, ArrayAccess, Countable
{
/** @var array<int, mixed> */
private $internalArray = array();
/** @var int $size */
private $size = 0;
/**
* SplFixedArray constructor.
* @param int $size
*/
public function __construct($size = 0)
{
$this->size = $size;
$this->internalArray = array();
}
/**
* @return int
*/
public function count()
{
return count($this->internalArray);
}
/**
* @return array
*/
public function toArray()
{
ksort($this->internalArray);
return (array) $this->internalArray;
}
/**
* @param array $array
* @param bool $save_indexes
* @return SplFixedArray
* @psalm-suppress MixedAssignment
*/
public static function fromArray(array $array, $save_indexes = true)
{
$self = new SplFixedArray(count($array));
if($save_indexes) {
foreach($array as $key => $value) {
$self[(int) $key] = $value;
}
} else {
$i = 0;
foreach (array_values($array) as $value) {
$self[$i] = $value;
$i++;
}
}
return $self;
}
/**
* @return int
*/
public function getSize()
{
return $this->size;
}
/**
* @param int $size
* @return bool
*/
public function setSize($size)
{
$this->size = $size;
return true;
}
/**
* @param string|int $index
* @return bool
*/
public function offsetExists($index)
{
return array_key_exists((int) $index, $this->internalArray);
}
/**
* @param string|int $index
* @return mixed
*/
public function offsetGet($index)
{
/** @psalm-suppress MixedReturnStatement */
return $this->internalArray[(int) $index];
}
/**
* @param string|int $index
* @param mixed $newval
* @psalm-suppress MixedAssignment
*/
public function offsetSet($index, $newval)
{
$this->internalArray[(int) $index] = $newval;
}
/**
* @param string|int $index
*/
public function offsetUnset($index)
{
unset($this->internalArray[(int) $index]);
}
/**
* Rewind iterator back to the start
* @link https://php.net/manual/en/splfixedarray.rewind.php
* @return void
* @since 5.3.0
*/
public function rewind()
{
reset($this->internalArray);
}
/**
* Return current array entry
* @link https://php.net/manual/en/splfixedarray.current.php
* @return mixed The current element value.
* @since 5.3.0
*/
public function current()
{
/** @psalm-suppress MixedReturnStatement */
return current($this->internalArray);
}
/**
* Return current array index
* @return int The current array index.
*/
public function key()
{
return key($this->internalArray);
}
/**
* @return void
*/
public function next()
{
next($this->internalArray);
}
/**
* Check whether the array contains more elements
* @link https://php.net/manual/en/splfixedarray.valid.php
* @return bool true if the array contains any more elements, false
otherwise.
*/
public function valid()
{
if (empty($this->internalArray)) {
return false;
}
$result = next($this->internalArray) !== false;
prev($this->internalArray);
return $result;
}
/**
* Do nothing.
*/
public function __wakeup()
{
// NOP
}
}<?php
if (!class_exists('SodiumException', false)) {
/**
* Class SodiumException
*/
class SodiumException extends Exception
{
}
}
{
"name": "psr/log",
"description": "Common interface for logging
libraries",
"keywords": ["psr", "psr-3",
"log"],
"homepage": "https://github.com/php-fig/log",
"license": "MIT",
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
}
}
Copyright (c) 2012 PHP Framework Interoperability Group
Permission is hereby granted, free of charge, to any person obtaining a
copy
of this software and associated documentation files (the
"Software"), to deal
in the Software without restriction, including without limitation the
rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?php
namespace Psr\Log;
/**
* This is a simple Logger implementation that other Loggers can inherit
from.
*
* It simply delegates all log-level-specific methods to the `log` method
to
* reduce boilerplate code that a simple Logger that does the same thing
with
* messages regardless of the error level has to implement.
*/
abstract class AbstractLogger implements LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should
typically
* be logged and monitored.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable
things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
}
<?php
namespace Psr\Log;
class InvalidArgumentException extends \InvalidArgumentException
{
}
<?php
namespace vendor\psr\log\Psr\Log;
/**
* Describes a logger-aware instance.
*/
interface LoggerAwareInterface
{
/**
* Sets a logger instance on the object.
*
* @param LoggerInterface $logger
*
* @return void
*/
public function setLogger(LoggerInterface $logger);
}
<?php
namespace vendor\psr\log\Psr\Log;
/**
* Basic Implementation of LoggerAwareInterface.
*/
trait LoggerAwareTrait
{
/**
* The logger instance.
*
* @var LoggerInterface
*/
protected $logger;
/**
* Sets a logger.
*
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
<?php
namespace vendor\psr\log\Psr\Log;
/**
* Describes a logger instance.
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data. The only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named
"exception".
*
* See
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*/
interface LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function emergency($message, array $context = array());
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function alert($message, array $context = array());
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function critical($message, array $context = array());
/**
* Runtime errors that do not require immediate action but should
typically
* be logged and monitored.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function error($message, array $context = array());
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable
things
* that are not necessarily wrong.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function warning($message, array $context = array());
/**
* Normal but significant events.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function notice($message, array $context = array());
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function info($message, array $context = array());
/**
* Detailed debug information.
*
* @param string $message
* @param mixed[] $context
*
* @return void
*/
public function debug($message, array $context = array());
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param mixed[] $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
public function log($level, $message, array $context = array());
}
<?php
namespace Psr\Log;
/**
* This is a simple Logger trait that classes unable to extend
AbstractLogger
* (because they extend another class, etc) can include.
*
* It simply delegates all log-level-specific methods to the `log` method
to
* reduce boilerplate code that a simple Logger that does the same thing
with
* messages regardless of the error level has to implement.
*/
trait LoggerTrait
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should
typically
* be logged and monitored.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable
things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
abstract public function log($level, $message, array $context =
array());
}
<?php
namespace vendor\psr\log\Psr\Log;
/**
* Describes log levels.
*/
class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}
<?php
namespace Psr\Log;
/**
* This Logger can be used to avoid conditional log calls.
*
* Logging should always be optional, and if no logger is provided to your
* library creating a NullLogger instance to have something to throw logs
at
* is a good way to avoid littering your code with `if ($this->logger) {
}`
* blocks.
*/
class NullLogger extends AbstractLogger
{
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
*
* @return void
*
* @throws \Psr\Log\InvalidArgumentException
*/
public function log($level, $message, array $context = array())
{
// noop
}
}
<?php
namespace Psr\Log\Test;
/**
* This class is internal and does not follow the BC promise.
*
* Do NOT use this class in any way.
*
* @internal
*/
class DummyTest
{
public function __toString()
{
return 'DummyTest';
}
}
<?php
namespace Psr\Log\Test;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use PHPUnit\Framework\TestCase;
/**
* Provides a base test class for ensuring compliance with the
LoggerInterface.
*
* Implementors can extend the class and implement abstract methods to run
this
* as part of their test suite.
*/
abstract class LoggerInterfaceTest extends TestCase
{
/**
* @return LoggerInterface
*/
abstract public function getLogger();
/**
* This must return the log messages in order.
*
* The simple formatting of the messages is: "<LOG LEVEL>
<MESSAGE>".
*
* Example ->error('Foo') would yield "error
Foo".
*
* @return string[]
*/
abstract public function getLogs();
public function testImplements()
{
$this->assertInstanceOf('Psr\Log\LoggerInterface',
$this->getLogger());
}
/**
* @dataProvider provideLevelsAndMessages
*/
public function testLogsAtAllLevels($level, $message)
{
$logger = $this->getLogger();
$logger->{$level}($message, array('user' =>
'Bob'));
$logger->log($level, $message, array('user' =>
'Bob'));
$expected = array(
$level.' message of level '.$level.' with
context: Bob',
$level.' message of level '.$level.' with
context: Bob',
);
$this->assertEquals($expected, $this->getLogs());
}
public function provideLevelsAndMessages()
{
return array(
LogLevel::EMERGENCY => array(LogLevel::EMERGENCY,
'message of level emergency with context: {user}'),
LogLevel::ALERT => array(LogLevel::ALERT, 'message of
level alert with context: {user}'),
LogLevel::CRITICAL => array(LogLevel::CRITICAL,
'message of level critical with context: {user}'),
LogLevel::ERROR => array(LogLevel::ERROR, 'message of
level error with context: {user}'),
LogLevel::WARNING => array(LogLevel::WARNING, 'message
of level warning with context: {user}'),
LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of
level notice with context: {user}'),
LogLevel::INFO => array(LogLevel::INFO, 'message of
level info with context: {user}'),
LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of
level debug with context: {user}'),
);
}
/**
* @expectedException \Psr\Log\InvalidArgumentException
*/
public function testThrowsOnInvalidLevel()
{
$logger = $this->getLogger();
$logger->log('invalid level', 'Foo');
}
public function testContextReplacement()
{
$logger = $this->getLogger();
$logger->info('{Message {nothing} {user} {foo.bar}
a}', array('user' => 'Bob', 'foo.bar'
=> 'Bar'));
$expected = array('info {Message {nothing} Bob Bar a}');
$this->assertEquals($expected, $this->getLogs());
}
public function testObjectCastToString()
{
if (method_exists($this, 'createPartialMock')) {
$dummy =
$this->createPartialMock('Psr\Log\Test\DummyTest',
array('__toString'));
} else {
$dummy = $this->getMock('Psr\Log\Test\DummyTest',
array('__toString'));
}
$dummy->expects($this->once())
->method('__toString')
->will($this->returnValue('DUMMY'));
$this->getLogger()->warning($dummy);
$expected = array('warning DUMMY');
$this->assertEquals($expected, $this->getLogs());
}
public function testContextCanContainAnything()
{
$closed = fopen('php://memory', 'r');
fclose($closed);
$context = array(
'bool' => true,
'null' => null,
'string' => 'Foo',
'int' => 0,
'float' => 0.5,
'nested' => array('with object' =>
new DummyTest),
'object' => new \DateTime,
'resource' => fopen('php://memory',
'r'),
'closed' => $closed,
);
$this->getLogger()->warning('Crazy context data',
$context);
$expected = array('warning Crazy context data');
$this->assertEquals($expected, $this->getLogs());
}
public function testContextExceptionKeyCanBeExceptionOrOtherValues()
{
$logger = $this->getLogger();
$logger->warning('Random message',
array('exception' => 'oops'));
$logger->critical('Uncaught Exception!',
array('exception' => new \LogicException('Fail')));
$expected = array(
'warning Random message',
'critical Uncaught Exception!'
);
$this->assertEquals($expected, $this->getLogs());
}
}
<?php
namespace Psr\Log\Test;
use Psr\Log\AbstractLogger;
/**
* Used for testing purposes.
*
* It records all records and gives you access to them for verification.
*
* @method bool hasEmergency($record)
* @method bool hasAlert($record)
* @method bool hasCritical($record)
* @method bool hasError($record)
* @method bool hasWarning($record)
* @method bool hasNotice($record)
* @method bool hasInfo($record)
* @method bool hasDebug($record)
*
* @method bool hasEmergencyRecords()
* @method bool hasAlertRecords()
* @method bool hasCriticalRecords()
* @method bool hasErrorRecords()
* @method bool hasWarningRecords()
* @method bool hasNoticeRecords()
* @method bool hasInfoRecords()
* @method bool hasDebugRecords()
*
* @method bool hasEmergencyThatContains($message)
* @method bool hasAlertThatContains($message)
* @method bool hasCriticalThatContains($message)
* @method bool hasErrorThatContains($message)
* @method bool hasWarningThatContains($message)
* @method bool hasNoticeThatContains($message)
* @method bool hasInfoThatContains($message)
* @method bool hasDebugThatContains($message)
*
* @method bool hasEmergencyThatMatches($message)
* @method bool hasAlertThatMatches($message)
* @method bool hasCriticalThatMatches($message)
* @method bool hasErrorThatMatches($message)
* @method bool hasWarningThatMatches($message)
* @method bool hasNoticeThatMatches($message)
* @method bool hasInfoThatMatches($message)
* @method bool hasDebugThatMatches($message)
*
* @method bool hasEmergencyThatPasses($message)
* @method bool hasAlertThatPasses($message)
* @method bool hasCriticalThatPasses($message)
* @method bool hasErrorThatPasses($message)
* @method bool hasWarningThatPasses($message)
* @method bool hasNoticeThatPasses($message)
* @method bool hasInfoThatPasses($message)
* @method bool hasDebugThatPasses($message)
*/
class TestLogger extends AbstractLogger
{
/**
* @var array
*/
public $records = [];
public $recordsByLevel = [];
/**
* @inheritdoc
*/
public function log($level, $message, array $context = [])
{
$record = [
'level' => $level,
'message' => $message,
'context' => $context,
];
$this->recordsByLevel[$record['level']][] = $record;
$this->records[] = $record;
}
public function hasRecords($level)
{
return isset($this->recordsByLevel[$level]);
}
public function hasRecord($record, $level)
{
if (is_string($record)) {
$record = ['message' => $record];
}
return $this->hasRecordThatPasses(function ($rec) use ($record)
{
if ($rec['message'] !== $record['message'])
{
return false;
}
if (isset($record['context']) &&
$rec['context'] !== $record['context']) {
return false;
}
return true;
}, $level);
}
public function hasRecordThatContains($message, $level)
{
return $this->hasRecordThatPasses(function ($rec) use ($message)
{
return strpos($rec['message'], $message) !== false;
}, $level);
}
public function hasRecordThatMatches($regex, $level)
{
return $this->hasRecordThatPasses(function ($rec) use ($regex) {
return preg_match($regex, $rec['message']) > 0;
}, $level);
}
public function hasRecordThatPasses(callable $predicate, $level)
{
if (!isset($this->recordsByLevel[$level])) {
return false;
}
foreach ($this->recordsByLevel[$level] as $i => $rec) {
if (call_user_func($predicate, $rec, $i)) {
return true;
}
}
return false;
}
public function __call($method, $args)
{
if
(preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/',
$method, $matches) > 0) {
$genericMethod = $matches[1] . ('Records' !==
$matches[3] ? 'Record' : '') . $matches[3];
$level = strtolower($matches[2]);
if (method_exists($this, $genericMethod)) {
$args[] = $level;
return call_user_func_array([$this, $genericMethod],
$args);
}
}
throw new \BadMethodCallException('Call to undefined method
' . get_class($this) . '::' . $method . '()');
}
public function reset()
{
$this->records = [];
$this->recordsByLevel = [];
}
}
PSR Log
=======
This repository holds all interfaces/classes/traits related to
[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md).
Note that this is not a logger of its own. It is merely an interface that
describes a logger. See the specification for more details.
Installation
------------
```bash
composer require psr/log
```
Usage
-----
If you need a logger, you can use the interface like this:
```php
<?php
use Psr\Log\LoggerInterface;
class Foo
{
private $logger;
public function __construct(LoggerInterface $logger = null)
{
$this->logger = $logger;
}
public function doSomething()
{
if ($this->logger) {
$this->logger->info('Doing work');
}
try {
$this->doSomethingElse();
} catch (Exception $exception) {
$this->logger->error('Oh no!',
array('exception' => $exception));
}
// do something useful
}
}
```
You can then pick one of the implementations of the interface to get a
logger.
If you want to implement the interface, you can require this package and
implement `Psr\Log\LoggerInterface` in your code. Please read the
[specification
text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
for details.
## 4.1.4 (2020-04-14)
[FIXED] Errors in the failure path of `get_...` methods revealed by
stricter type checking in PHP7.4
## 4.1.3 (2020-04-01)
No functional change, previous release was only partially successful
## 4.1.2 (2020-04-01)
[ADDED] option `encryption_master_key_base64`
[DEPRECATED] option `encryption_master_key`
## 4.1.1 (2019-12-03)
[ADDED] Support for PHP 7.4.
## 4.1.0 (2019-10-28)
[ADDED] `path` configuration option.
## 4.0.0 (2019-06-17)
[REMOVED] Support for PHP 5.x, PHP 7.0 and HHVM.
## 3.4.1 (2019-03-18)
[ADDED] Support for PHP 7.3.
## 3.4.0 (2019-03-11)
[ADDED] `get_users_info` method.
## 3.3.1 (2019-01-18)
[FIXED] PHP Notice for Undefined `socket_id` in triggerBatch
## 3.3.0 (2019-01-03)
[ADDED] Support for End-to-end encrypted channels for triggerbatch
[FIXED] trigger behavior with mixtures of encrypted and non-encrypted
channels
## 3.2.0 (2018-08-13)
[ADDED] This release adds support for end to end encrypted channels, a new
feature for Channels. Read more [in our
docs](https://pusher.com/docs/client_api_guide/client_encrypted_channels).
[DEPRECATED] Renamed `encrypted` option to `useTLS` - `encrypted` will
still work!
## 3.1.0 (2018-08-13)
[ADDED] This release adds Webhook validation as well as a data structure to
store Webhook payloads.
## 3.0.4 (2018-05-21)
[FIXED] Non zero indexed arrays of channels no longer get serialized as an
object.
## 3.0.3 (2018-04-26)
[ADDED] PSR-3 logger compatibility.
[CHANGED] Improved PHP docs.
## 3.0.2 (2018-04-23)
[FIXED] Insufficient check for un-initialized curl resource.
[FIXED] Acceptance tests.
## 3.0.1 (2017-10-20)
[CHANGED] Info messages are now prefixed with INFO and errors are now
prefixed with ERROR.
## 3.0.0 (2017-07-10)
[NEW] Added namespaces (thanks [@vinkla](https://github.com/vinkla)).
## 2.6.4 (2017-06-11)
[FIXED] Log the curl error in more circumstances
## 2.6.1 (2016-11-11)
[FIXED] Check for correct status code when POSTing to native push
notifications API.
## 2.6.0 (2016-08-23)
[ADDED] support for publishing push notifications on up to 10 interests.
## 2.5.0 (2016-08-15)
[REMOVED] Native push notifications payload validation in the client.
## 2.5.0-rc2 (2016-07-19)
[FIXED] DDN and Native Push endpoints were not assembled correctly.
## 2.5.0-rc1 (2016-07-18)
[NEW] Native push notifications
## 2.4.2 (2016-07-04)
[CHANGED] One curl instance per Pusher instance
## 2.4.1 (2016-05-27)
[FIXED] Presence data could not be submitted after the style changes
## 2.4.0 (2016-05-25)
[ADDED] Support for batch events
[ADDED] Curl options
[FIXED] Applied fixes from StyleCI
## 2.3.0 (2015-02-16)
[ADDED] A new `cluster` option for the Pusher constructor.
## 2.2.2 (2015-05-15)
[FIXED] Fixed a PHP 5.2 incompatibility caused by referencing a private
method in array_walk.
## 2.2.1 (2015-05-13)
[FIXED] Channel name and socket_id values are now validated.
[BROKE] Inadvertently broke PHP 5.2 compatibility by referencing a private
method in array_walk.
## 2.2.0 (2015-01-20)
[CHANGED] `new Pusher($app_key, $app_secret, $app_id, $options)` - The
`$options` parameter
has been added as the forth parameter to the constructor and other
additional
parameters are now deprecated.
## 2.1.3 (2012-12-22)
[NEW] `$pusher->trigger` can now take an `array` of channel names as a
first parameter to allow the same event to be published on multiple
channels.
[NEW] `$pusher->get` generic function can be used to make `GET` calls to
the REST API
[NEW] `$pusher->set_logger` to allow internal logging to be exposed and
logged in your own logs.
## 2.1.2 (2012-11-18)
[CHANGED] Debug response from `$pusher->trigger` call is now an
associative array in the form `array( 'body' => '{String}
body text of response', 'status' => '{Number} http
status of the response' )`
## 2.1.1 (2012-10-07)
[CHANGED] Added optional $options parameter to get_channel_info.
get_channel_info($channel, $options = array() )
## 2.1.0 (2012-09-28)
[CHANGED] Renamed get_channel_stats to get_channel_info
[CHANGED] get_channels now takes and $options parameter. get_channels(
$options = array() )
[REMOVED] get_presence_channels
## 2.0.1 (2012-09-18)
[FIXED] Overwritten socket_id parameter in trigger:
https://github.com/pusher/pusher-php-server/pull/3
## 2.0.0 (2012-08-30)
[NEW] Versioning introduced at 2.0.0
[NEW] Added composer.json for submission to http://packagist.org/
[CHANGED] `get_channels()` now returns an object which has a `channels`
property. This must be accessed to get the Array of channels in an
application.
[CHANGED] `get_presence_channels()` now returns an object which has a
`channels` property. This must be accessed to get the Array of channels in
an application.
{
"name": "pusher/pusher-php-server",
"description" : "Library for interacting with the Pusher
REST API",
"keywords": ["php-pusher-server",
"pusher", "rest", "realtime",
"real-time", "real time", "messaging",
"push", "trigger", "publish",
"events"],
"license": "MIT",
"require": {
"php": "^7.1",
"ext-curl": "*",
"psr/log": "^1.0",
"paragonie/sodium_compat": "^1.6"
},
"require-dev": {
"phpunit/phpunit": "^7.2"
},
"autoload": {
"psr-4": {
"Pusher\\": "src/"
}
},
"autoload-dev": {
"psr-4": { "": "tests/" }
},
"config": {
"preferred-install": "dist"
},
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
extension="sodium.so"
#!/usr/bin/env bash
set -e
curl -sSfL -o ~/.phpenv/versions/hhvm/bin/phpunit
https://phar.phpunit.de/phpunit-7.5.9.phar
composer install --no-interaction --prefer-source
if [ $INSTALL_LIBSODIUM = true ]; then
sudo add-apt-repository ppa:ondrej/php -y
sudo apt-get update && sudo apt-get install libsodium-dev -y
pecl install libsodium-2.0.11
fi
<?php
namespace vendor\pusher\pusherphpserver\src;
use vendor\psr\log\Psr\Log\LoggerAwareInterface;
use vendor\psr\log\Psr\Log\LoggerAwareTrait;
use vendor\psr\log\Psr\Log\LoggerInterface;
use vendor\psr\log\Psr\Log\LogLevel;
class Pusher implements LoggerAwareInterface
{
use LoggerAwareTrait;
/**
* @var string Version
*/
public static $VERSION = '4.1.4';
/**
* @var null|PusherCrypto
*/
private $crypto;
/**
* @var array Settings
*/
private $settings = array(
'scheme' => 'http',
'port' => 80,
'path' => '',
'timeout' => 30,
'debug' => false,
'curl_options' => array(),
);
/**
* @var null|resource
*/
private $ch = null; // Curl handler
/**
* Initializes a new Pusher instance with key, secret, app ID and
channel.
* You can optionally turn on debugging for all requests by setting
debug to true.
*
* @param string $auth_key
* @param string $secret
* @param int $app_id
* @param array $options [optional]
* Options to configure the Pusher instance.
* Was previously a debug flag. Legacy support
for this exists if a boolean is passed.
* scheme - e.g. http or https
* host - the host e.g. api.pusherapp.com. No
trailing forward slash.
* port - the http port
* timeout - the http timeout
* useTLS - quick option to use scheme of https
and port 443.
* encrypted - deprecated; renamed to `useTLS`.
* cluster - cluster name to connect to.
* encryption_master_key - deprecated; use
`encryption_master_key_base64`
* encryption_master_key_base64 - a 32 byte
key, encoded as base64. This key, along with the channel name, are used to
derive per-channel encryption keys. Per-channel keys are used to encrypt
event data on encrypted channels.
* debug - (default `false`) if `true`, every
`trigger()` and `triggerBatch()` call will return a `$response` object,
useful for logging/inspection purposes.
* curl_options - wrapper for curl_setopt, more
here: http://php.net/manual/en/function.curl-setopt.php
* notification_host - host to connect to for
native notifications.
* notification_scheme - scheme for the
notification_host.
* @param string $host [optional] - deprecated
* @param int $port [optional] - deprecated
* @param int $timeout [optional] - deprecated
*
* @throws PusherException Throws exception if any required
dependencies are missing
*/
public function __construct($auth_key, $secret, $app_id, $options =
array(), $host = null, $port = null, $timeout = null)
{
$this->check_compatibility();
/* Start backward compatibility with old constructor **/
if (is_bool($options) === true) {
$options = array(
'debug' => $options,
);
}
if (!is_null($host)) {
$match = null;
preg_match("/(http[s]?)\:\/\/(.*)/", $host, $match);
if (count($match) === 3) {
$this->settings['scheme'] = $match[1];
$host = $match[2];
}
$this->settings['host'] = $host;
$this->settings['path'] = '';
$this->log('Legacy $host parameter provided: {scheme}
host: {host}', array(
'scheme' =>
$this->settings['scheme'],
'host' =>
$this->settings['host'],
'path' =>
$this->settings['path'],
));
}
if (!is_null($port)) {
$options['port'] = $port;
}
if (!is_null($timeout)) {
$options['timeout'] = $timeout;
}
/* End backward compatibility with old constructor **/
$useTLS = false;
if (isset($options['useTLS'])) {
$useTLS = $options['useTLS'] === true;
} elseif (isset($options['encrypted'])) {
// `encrypted` deprecated in favor of `forceTLS`
$useTLS = $options['encrypted'] === true;
}
if (
$useTLS &&
!isset($options['scheme']) &&
!isset($options['port'])
) {
$options['scheme'] = 'https';
$options['port'] = 443;
}
$this->settings['auth_key'] = $auth_key;
$this->settings['secret'] = $secret;
$this->settings['app_id'] = $app_id;
$this->settings['base_path'] =
'/apps/'.$this->settings['app_id'];
foreach ($options as $key => $value) {
// only set if valid setting/option
if (isset($this->settings[$key])) {
$this->settings[$key] = $value;
}
}
// Set the native notification host
if (isset($options['notification_host'])) {
$this->settings['notification_host'] =
$options['notification_host'];
} else {
$this->settings['notification_host'] =
'nativepush-cluster1.pusher.com';
}
// Set scheme for native notifications
if (isset($options['notification_scheme'])) {
$this->settings['notification_scheme'] =
$options['notification_scheme'];
} else {
$this->settings['notification_scheme'] =
'https';
}
// handle the case when 'host' and 'cluster'
are specified in the options.
if (!array_key_exists('host', $this->settings)) {
if (array_key_exists('host', $options)) {
$this->settings['host'] =
$options['host'];
} elseif (array_key_exists('cluster', $options)) {
$this->settings['host'] =
'api-'.$options['cluster'].'.pusher.com';
} else {
$this->settings['host'] =
'api.pusherapp.com';
}
}
// ensure host doesn't have a scheme prefix
$this->settings['host'] =
preg_replace('/http[s]?\:\/\//', '',
$this->settings['host'], 1);
if (!array_key_exists('encryption_master_key', $options))
{
$options['encryption_master_key'] = '';
}
if (!array_key_exists('encryption_master_key_base64',
$options)) {
$options['encryption_master_key_base64'] =
'';
}
if ($options['encryption_master_key'] != '' or
$options['encryption_master_key_base64'] != '') {
$parsedKey = PusherCrypto::parse_master_key(
$options['encryption_master_key'],
$options['encryption_master_key_base64']
);
$this->crypto = new PusherCrypto($parsedKey);
}
}
/**
* Fetch the settings.
*
* @return array
*/
public function getSettings()
{
return $this->settings;
}
/**
* Set a logger to be informed of internal log messages.
*
* @deprecated Use the PSR-3 compliant Pusher::setLogger() instead.
This method will be removed in the next breaking release.
*
* @param object $logger A object with a public function log($message)
method
*
* @return void
*/
public function set_logger($logger)
{
$this->logger = $logger;
}
/**
* Log a string.
*
* @param string $msg The message to log
* @param array|\Exception $context [optional] Any extraneous
information that does not fit well in a string.
* @param string $level [optional] Importance of log
message, highly recommended to use Psr\Log\LogLevel::{level}
*
* @return void
*/
private function log($msg, array $context = array(), $level =
LogLevel::INFO)
{
if (is_null($this->logger)) {
return;
}
if ($this->logger instanceof LoggerInterface) {
$this->logger->log($level, $msg, $context);
return;
}
// Support old style logger (deprecated)
$msg = sprintf('Pusher: %s: %s', strtoupper($level),
$msg);
$replacement = array();
foreach ($context as $k => $v) {
$replacement['{'.$k.'}'] = $v;
}
$this->logger->log(strtr($msg, $replacement));
}
/**
* Check if the current PHP setup is sufficient to run this class.
*
* @throws PusherException If any required dependencies are missing
*
* @return void
*/
private function check_compatibility()
{
if (!extension_loaded('curl')) {
throw new PusherException('The Pusher library requires the
PHP cURL module. Please ensure it is installed');
}
if (!extension_loaded('json')) {
throw new PusherException('The Pusher library requires the
PHP JSON module. Please ensure it is installed');
}
if (!in_array('sha256', hash_algos())) {
throw new PusherException('SHA256 appears to be
unsupported - make sure you have support for it, or upgrade your version of
PHP.');
}
}
/**
* Validate number of channels and channel name format.
*
* @param string[] $channels An array of channel names to validate
*
* @throws PusherException If $channels is too big or any channel is
invalid
*
* @return void
*/
private function validate_channels($channels)
{
if (count($channels) > 100) {
throw new PusherException('An event can be triggered on a
maximum of 100 channels in a single call.');
}
foreach ($channels as $channel) {
$this->validate_channel($channel);
}
}
/**
* Ensure a channel name is valid based on our spec.
*
* @param string $channel The channel name to validate
*
* @throws PusherException If $channel is invalid
*
* @return void
*/
private function validate_channel($channel)
{
if (!preg_match('/\A[-a-zA-Z0-9_=@,.;]+\z/', $channel)) {
throw new PusherException('Invalid channel name
'.$channel);
}
}
/**
* Ensure a socket_id is valid based on our spec.
*
* @param string $socket_id The socket ID to validate
*
* @throws PusherException If $socket_id is invalid
*/
private function validate_socket_id($socket_id)
{
if ($socket_id !== null &&
!preg_match('/\A\d+\.\d+\z/', $socket_id)) {
throw new PusherException('Invalid socket ID
'.$socket_id);
}
}
/**
* Utility function used to create the curl object with common
settings.
*
* @param string $url_prefix
* @param string $path
* @param string [optional] $request_method
* @param array [optional] $query_params
*
* @throws PusherException Throws exception if curl wasn't
initialized correctly
*
* @return resource
*/
private function create_curl($url_prefix, $path, $request_method =
'GET', $query_params = array())
{
// Create the signed signature...
$signed_query = self::build_auth_query_string(
$this->settings['auth_key'],
$this->settings['secret'],
$request_method,
$path,
$query_params
);
$full_url = $url_prefix.$path.'?'.$signed_query;
$this->log('create_curl( {full_url} )',
array('full_url' => $full_url));
// Create or reuse existing curl handle
if (!is_resource($this->ch)) {
$this->ch = curl_init();
}
if ($this->ch === false) {
throw new PusherException('Could not initialise
cURL!');
}
$ch = $this->ch;
// curl handle is not reusable unless reset
if (function_exists('curl_reset')) {
curl_reset($ch);
}
// Set cURL opts and execute request
curl_setopt($ch, CURLOPT_URL, $full_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Expect:',
'X-Pusher-Library: pusher-http-php '.self::$VERSION,
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT,
$this->settings['timeout']);
if ($request_method === 'POST') {
curl_setopt($ch, CURLOPT_POST, 1);
} elseif ($request_method === 'GET') {
curl_setopt($ch, CURLOPT_POST, 0);
} // Otherwise let the user configure it
// Set custom curl options
if (!empty($this->settings['curl_options'])) {
foreach ($this->settings['curl_options'] as
$option => $value) {
curl_setopt($ch, $option, $value);
}
}
return $ch;
}
/**
* Utility function to execute curl and create capture response
information.
*
* @param $ch resource
*
* @return array
*/
private function exec_curl($ch)
{
$response = array();
$response['body'] = curl_exec($ch);
$response['status'] = curl_getinfo($ch,
CURLINFO_HTTP_CODE);
if ($response['body'] === false) {
$this->log('exec_curl error: {error}',
array('error' => curl_error($ch)), LogLevel::ERROR);
} elseif ($response['status'] < 200 || 400 <=
$response['status']) {
$this->log('exec_curl {status} error from server:
{body}', $response, LogLevel::ERROR);
} else {
$this->log('exec_curl {status} response: {body}',
$response);
}
$this->log('exec_curl response: {response}',
array('response' => print_r($response, true)));
return $response;
}
/**
* Build the notification url prefix.
*
* @return string
*/
private function notification_url_prefix()
{
return
$this->settings['notification_scheme'].'://'.$this->settings['notification_host'];
}
/**
* Build the Channels url prefix.
*
* @return string
*/
private function channels_url_prefix()
{
return
$this->settings['scheme'].'://'.$this->settings['host'].':'.$this->settings['port'].$this->settings['path'];
}
/**
* Build the required HMAC'd auth string.
*
* @param string $auth_key
* @param string $auth_secret
* @param string $request_method
* @param string $request_path
* @param array $query_params [optional]
* @param string $auth_version [optional]
* @param string $auth_timestamp [optional]
*
* @return string
*/
public static function build_auth_query_string(
$auth_key,
$auth_secret,
$request_method,
$request_path,
$query_params = array(),
$auth_version = '1.0',
$auth_timestamp = null
) {
$params = array();
$params['auth_key'] = $auth_key;
$params['auth_timestamp'] = (is_null($auth_timestamp) ?
time() : $auth_timestamp);
$params['auth_version'] = $auth_version;
$params = array_merge($params, $query_params);
ksort($params);
$string_to_sign =
"$request_method\n".$request_path."\n".self::array_implode('=',
'&', $params);
$auth_signature = hash_hmac('sha256', $string_to_sign,
$auth_secret, false);
$params['auth_signature'] = $auth_signature;
ksort($params);
$auth_query_string = self::array_implode('=',
'&', $params);
return $auth_query_string;
}
/**
* Implode an array with the key and value pair giving
* a glue, a separator between pairs and the array
* to implode.
*
* @param string $glue The glue between key and value
* @param string $separator Separator between pairs
* @param array|string $array The array to implode
*
* @return string The imploded array
*/
public static function array_implode($glue, $separator, $array)
{
if (!is_array($array)) {
return $array;
}
$string = array();
foreach ($array as $key => $val) {
if (is_array($val)) {
$val = implode(',', $val);
}
$string[] = "{$key}{$glue}{$val}";
}
return implode($separator, $string);
}
/**
* Trigger an event by providing event name and payload.
* Optionally provide a socket ID to exclude a client (most likely the
sender).
*
* @param array|string $channels A channel name or an array of
channel names to publish the event on.
* @param string $event
* @param mixed $data Event data
* @param string|null $socket_id [optional]
* @param bool $debug [optional]
* @param bool $already_encoded [optional]
*
* @throws PusherException Throws exception if $channels is an array of
size 101 or above or $socket_id is invalid
*
* @return bool|array
*/
public function trigger($channels, $event, $data, $socket_id = null,
$debug = false, $already_encoded = false)
{
if (is_string($channels) === true) {
$channels = array($channels);
}
$this->validate_channels($channels);
$this->validate_socket_id($socket_id);
$has_encrypted_channel = false;
foreach ($channels as $chan) {
if (PusherCrypto::is_encrypted_channel($chan)) {
$has_encrypted_channel = true;
}
}
if ($has_encrypted_channel) {
if (count($channels) > 1) {
// For rationale, see limitations of end-to-end encryption
in the README
throw new PusherException('You cannot trigger to
multiple channels when using encrypted channels');
} else {
$data_encoded =
$this->crypto->encrypt_payload($channels[0], $already_encoded ? $data
: json_encode($data));
}
} else {
$data_encoded = $already_encoded ? $data : json_encode($data);
}
$query_params = array();
$path =
$this->settings['base_path'].'/events';
// json_encode might return false on failure
if (!$data_encoded) {
$this->log('Failed to perform json_encode on the the
provided data: {error}', array(
'error' => print_r($data, true),
), LogLevel::ERROR);
}
$post_params = array();
$post_params['name'] = $event;
$post_params['data'] = $data_encoded;
$post_params['channels'] = array_values($channels);
if ($socket_id !== null) {
$post_params['socket_id'] = $socket_id;
}
$post_value = json_encode($post_params);
$query_params['body_md5'] = md5($post_value);
$ch = $this->create_curl($this->channels_url_prefix(), $path,
'POST', $query_params);
$this->log('trigger POST: {post_value}',
compact('post_value'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_value);
$response = $this->exec_curl($ch);
if ($debug === true || $this->settings['debug'] ===
true) {
return $response;
}
if ($response['status'] === 200) {
return true;
}
return false;
}
/**
* Trigger multiple events at the same time.
*
* @param array $batch [optional] An array of events to send
* @param bool $debug [optional]
* @param bool $already_encoded [optional]
*
* @throws PusherException Throws exception if curl wasn't
initialized correctly
*
* @return array|bool|string
*/
public function triggerBatch($batch = array(), $debug = false,
$already_encoded = false)
{
foreach ($batch as $key => $event) {
$this->validate_channel($event['channel']);
if (isset($event['socket_id'])) {
$this->validate_socket_id($event['socket_id']);
}
$data = $event['data'];
if (!is_string($data)) {
$data = $already_encoded ? $data : json_encode($data);
}
if
(PusherCrypto::is_encrypted_channel($event['channel'])) {
$batch[$key]['data'] =
$this->crypto->encrypt_payload($event['channel'], $data);
} else {
$batch[$key]['data'] = $data;
}
}
$post_params = array();
$post_params['batch'] = $batch;
$post_value = json_encode($post_params);
$query_params = array();
$query_params['body_md5'] = md5($post_value);
$path =
$this->settings['base_path'].'/batch_events';
$ch = $this->create_curl($this->channels_url_prefix(), $path,
'POST', $query_params);
$this->log('trigger POST: {post_value}',
compact('post_value'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_value);
$response = $this->exec_curl($ch);
if ($debug === true || $this->settings['debug'] ===
true) {
return $response;
}
if ($response['status'] === 200) {
return true;
}
return false;
}
/**
* Fetch channel information for a specific channel.
*
* @param string $channel The name of the channel
* @param array $params Additional parameters for the query e.g.
$params = array( 'info' => 'connection_count' )
*
* @throws PusherException If $channel is invalid or if curl
wasn't initialized correctly
*
* @return bool|object
*/
public function get_channel_info($channel, $params = array())
{
$this->validate_channel($channel);
$response = $this->get('/channels/'.$channel,
$params);
if ($response === false) {
return false;
}
return json_decode($response['body']);
}
/**
* Fetch a list containing all channels.
*
* @param array $params Additional parameters for the query e.g.
$params = array( 'info' => 'connection_count' )
*
* @throws PusherException Throws exception if curl wasn't
initialized correctly
*
* @return array|bool
*/
public function get_channels($params = array())
{
$response = $this->get('/channels', $params);
if ($response === false) {
return false;
}
$result = json_decode($response['body']);
$result->channels = get_object_vars($result->channels);
return $result;
}
/**
* Fetch user ids currently subscribed to a presence channel.
*
* @param string $channel The name of the channel
*
* @throws PusherException Throws exception if curl wasn't
initialized correctly
*
* @return array|bool
*/
public function get_users_info($channel)
{
$response =
$this->get('/channels/'.$channel.'/users');
if ($response === false) {
return false;
}
return json_decode($response['body']);
}
/**
* GET arbitrary REST API resource using a synchronous http client.
* All request signing is handled automatically.
*
* @param string $path Path excluding /apps/APP_ID
* @param array $params API params (see
http://pusher.com/docs/rest_api)
*
* @throws PusherException Throws exception if curl wasn't
initialized correctly
*
* @return array|bool See Pusher API docs
*/
public function get($path, $params = array())
{
$path = $this->settings['base_path'].$path;
$ch = $this->create_curl($this->channels_url_prefix(), $path,
'GET', $params);
$response = $this->exec_curl($ch);
if ($response['status'] === 200) {
$response['result'] =
json_decode($response['body'], true);
return $response;
}
return false;
}
/**
* Creates a socket signature.
*
* @param string $channel
* @param string $socket_id
* @param string $custom_data
*
* @throws PusherException Throws exception if $channel is invalid or
above or $socket_id is invalid
*
* @return string Json encoded authentication string.
*/
public function socket_auth($channel, $socket_id, $custom_data = null)
{
$this->validate_channel($channel);
$this->validate_socket_id($socket_id);
if ($custom_data) {
$signature = hash_hmac('sha256',
$socket_id.':'.$channel.':'.$custom_data,
$this->settings['secret'], false);
} else {
$signature = hash_hmac('sha256',
$socket_id.':'.$channel, $this->settings['secret'],
false);
}
$signature = array('auth' =>
$this->settings['auth_key'].':'.$signature);
// add the custom data if it has been supplied
if ($custom_data) {
$signature['channel_data'] = $custom_data;
}
if (PusherCrypto::is_encrypted_channel($channel)) {
if (!is_null($this->crypto)) {
$signature['shared_secret'] =
base64_encode($this->crypto->generate_shared_secret($channel));
} else {
throw new PusherException('You must specify an
encryption master key to authorize an encrypted channel');
}
}
return json_encode($signature, JSON_UNESCAPED_SLASHES);
}
/**
* Creates a presence signature (an extension of socket signing).
*
* @param string $channel
* @param string $socket_id
* @param string $user_id
* @param mixed $user_info
*
* @throws PusherException Throws exception if $channel is invalid or
above or $socket_id is invalid
*
* @return string
*/
public function presence_auth($channel, $socket_id, $user_id,
$user_info = null)
{
$user_data = array('user_id' => $user_id);
if ($user_info) {
$user_data['user_info'] = $user_info;
}
return $this->socket_auth($channel, $socket_id,
json_encode($user_data));
}
/**
* Send a native notification via the Push Notifications Api.
*
* @param array $interests
* @param array $data
* @param bool $debug
*
* @throws PusherException If validation fails
*
* @return array|bool|string
*/
public function notify($interests, $data = array(), $debug = false)
{
$query_params = array();
if (is_string($interests)) {
$this->log('->notify received string interests
"{interests}" Converting to array.',
compact('interests'));
$interests = array($interests);
}
if (count($interests) === 0) {
throw new PusherException('$interests array must not be
empty');
}
$data['interests'] = $interests;
$post_value = json_encode($data);
$query_params['body_md5'] = md5($post_value);
$path =
'/server_api/v1'.$this->settings['base_path'].'/notifications';
$ch = $this->create_curl($this->notification_url_prefix(),
$path, 'POST', $query_params);
$this->log('trigger POST (Native notifications):
{post_value}', compact('post_value'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_value);
$response = $this->exec_curl($ch);
if ($response['status'] === 202 && $debug ===
false) {
return true;
}
if ($debug === true || $this->settings['debug'] ===
true) {
return $response;
}
return false;
}
/**
* Verify that a webhook actually came from Pusher, decrypts any
encrypted events, and marshals them into a PHP object.
*
* @param array $headers a array of headers from the request (for
example, from getallheaders())
* @param string $body the body of the request (for example, from
file_get_contents('php://input'))
*
* @return array marshalled object with the properties time_ms (an int)
and events (an array of event objects)
*/
public function webhook($headers, $body)
{
$this->ensure_valid_signature($headers, $body);
$decoded_events = array();
$decoded_json = json_decode($body);
foreach ($decoded_json->events as $key => $event) {
if (PusherCrypto::is_encrypted_channel($event->channel)) {
if (!is_null($this->crypto)) {
$decryptedEvent =
$this->crypto->decrypt_event($event);
if ($decryptedEvent == false) {
$this->log('Unable to decrypt webhook event
payload. Wrong key? Ignoring.', null, LogLevel::WARNING);
continue;
}
array_push($decoded_events, $decryptedEvent);
} else {
$this->log('Got an encrypted webhook event
payload, but no master key specified. Ignoring.', null,
LogLevel::WARNING);
continue;
}
} else {
array_push($decoded_events, $event);
}
}
$webhookobj = new Webhook($decoded_json->time_ms,
$decoded_json->events);
return $webhookobj;
}
/**
* Verify that a given Pusher Signature is valid.
*
* @param array $headers an array of headers from the request (for
example, from getallheaders())
* @param string $body the body of the request (for example, from
file_get_contents('php://input'))
*
* @throws PusherException if signature is inccorrect.
*/
public function ensure_valid_signature($headers, $body)
{
$x_pusher_key = $headers['X-Pusher-Key'];
$x_pusher_signature = $headers['X-Pusher-Signature'];
if ($x_pusher_key == $this->settings['auth_key']) {
$expected = hash_hmac('sha256', $body,
$this->settings['secret']);
if ($expected === $x_pusher_signature) {
return;
}
}
throw new PusherException(sprintf('Received WebHook with
invalid signature: got %s.', $x_pusher_signature));
}
}
<?php
namespace vendor\pusher\pusherphpserver\src;
class PusherCrypto
{
private $encryption_master_key = '';
// The prefix any e2e channel must have
const ENCRYPTED_PREFIX = 'private-encrypted-';
/**
* Checks if a given channel is an encrypted channel.
*
* @param string $channel the name of the channel
*
* @return bool true if channel is an encrypted channel
*/
public static function is_encrypted_channel($channel)
{
return substr($channel, 0, strlen(self::ENCRYPTED_PREFIX)) ===
self::ENCRYPTED_PREFIX;
}
public static function parse_master_key($encryption_master_key,
$encryption_master_key_base64)
{
if (!function_exists('sodium_crypto_secretbox')) {
throw new PusherException('To use end to end encryption,
you must either be using PHP 7.2 or greater or have installed the
libsodium-php extension for php < 7.2.');
}
if ($encryption_master_key != '' and
$encryption_master_key_base64 != '') {
throw new PusherException('Do not specify both
encryption_master_key and encryption_master_key_base64.
encryption_master_key is deprecated, use only
encryption_master_key_base64');
}
if ($encryption_master_key != '') {
if (strlen($encryption_master_key) !=
SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
throw new PusherException('encryption_master_key must
be 32 bytes. It is also deprecated, use
encryption_master_key_base64');
}
return $encryption_master_key;
}
if ($encryption_master_key_base64 != '') {
$decoded_key = base64_decode($encryption_master_key_base64,
true);
if ($decoded_key === false) {
throw new
PusherException('encryption_master_key_base64 must be a valid base64
string');
}
if (strlen($decoded_key) != SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
throw new
PusherException('encryption_master_key_base64 must encode a key which
is 32 bytes long');
}
return $decoded_key;
}
return '';
}
/**
* Initialises a PusherCrypto instance.
*
* @param string $encryption_master_key the SECRET_KEY_LENGTH key that
will be used for key derivation.
*/
public function __construct($encryption_master_key)
{
$this->encryption_master_key = $encryption_master_key;
}
/**
* Decrypts a given event.
*
* @param object $event an object that has an encrypted data property
and a channel property.
*
* @return object the event with a decrypted payload, or false if
decryption was unsuccessful.
*/
public function decrypt_event($event)
{
$parsed_payload =
$this->parse_encrypted_message($event->data);
$shared_secret =
$this->generate_shared_secret($event->channel,
$this->encryption_master_key);
$decrypted_payload =
$this->decrypt_payload($parsed_payload->ciphertext,
$parsed_payload->nonce, $shared_secret);
if (!$decrypted_payload) {
throw new PusherException('Decryption of the payload
failed. Wrong key?');
}
$event->data = $decrypted_payload;
return $event;
}
/**
* Derives a shared secret from the secret key and the channel to
broadcast to.
*
* @param string $channel the name of the channel
*
* @return string a SHA256 hash (encoded as base64) of the channel name
appended to the encryption key
*/
public function generate_shared_secret($channel)
{
if (!self::is_encrypted_channel($channel)) {
throw new PusherException('You must specify a channel of
the form private-encrypted-* for E2E encryption. Got '.$channel);
}
return hash('sha256',
$channel.$this->encryption_master_key, true);
}
/**
* Encrypts a given plaintext for broadcast on a particular channel.
*
* @param string $channel the name of the channel the payloads event
will be broadcast on
* @param string $plaintext the data to encrypt
*
* @return string a string ready to be sent as the data of an event.
*/
public function encrypt_payload($channel, $plaintext)
{
if (!self::is_encrypted_channel($channel)) {
throw new PusherException('Cannot encrypt plaintext for a
channel that is not of the form private-encrypted-*. Got '.$channel);
}
$nonce = $this->generate_nonce();
$shared_secret = $this->generate_shared_secret($channel);
$cipher_text = sodium_crypto_secretbox($plaintext, $nonce,
$shared_secret);
return $this->format_encrypted_message($nonce, $cipher_text);
}
/**
* Decrypts a given payload using the nonce and shared secret.
*
* @param string $payload the ciphertext
* @param string $nonce the nonce used in the encryption
* @param string $shared_secret the shared_secret used in the
encryption
*
* @return string plaintext
*/
public function decrypt_payload($payload, $nonce, $shared_secret)
{
$plaintext = sodium_crypto_secretbox_open($payload, $nonce,
$shared_secret);
if (empty($plaintext)) {
return false;
}
return $plaintext;
}
/**
* Formats an encrypted message ready for broadcast.
*
* @param string $nonce the nonce used in the encryption process
(bytes)
* @param string $ciphertext the ciphertext (bytes)
*
* @return string JSON with base64 encoded nonce and ciphertext`
*/
private function format_encrypted_message($nonce, $ciphertext)
{
$encrypted_message = new \stdClass();
$encrypted_message->nonce = base64_encode($nonce);
$encrypted_message->ciphertext = base64_encode($ciphertext);
return json_encode($encrypted_message);
}
/**
* Parses an encrypted message into its nonce and ciphertext
components.
*
*
* @param string $payload the encrypted message payload
*
* @return string php object with decoded nonce and ciphertext
*/
private function parse_encrypted_message($payload)
{
$decoded_payload = json_decode($payload);
$decoded_payload->nonce =
base64_decode($decoded_payload->nonce);
$decoded_payload->ciphertext =
base64_decode($decoded_payload->ciphertext);
if (strlen($decoded_payload->nonce) !=
SODIUM_CRYPTO_SECRETBOX_NONCEBYTES || $decoded_payload->ciphertext ==
'') {
throw new PusherException('Received a payload that cannot
be parsed.');
}
return $decoded_payload;
}
/**
* Generates a nonce that is SODIUM_CRYPTO_SECRETBOX_NONCEBYTES long.
*/
private function generate_nonce()
{
return random_bytes(
SODIUM_CRYPTO_SECRETBOX_NONCEBYTES
);
}
}
<?php
namespace vendor\pusher\pusherphpserver\src;
use Exception;
class PusherException extends Exception
{
}
<?php
namespace vendor\pusher\pusherphpserver\src;
class PusherInstance
{
private static $instance = null;
private static $app_id = '';
private static $secret = '';
private static $api_key = '';
/**
* Get the pusher singleton instance.
*
* @return Pusher
*/
public static function get_pusher()
{
if (self::$instance !== null) {
return self::$instance;
}
self::$instance = new Pusher(
self::$api_key,
self::$secret,
self::$app_id
);
return self::$instance;
}
}
<?php
namespace vendor\pusher\pusherphpserver\src;
class Webhook
{
private $time_ms;
private $events = array();
public function __construct($time_ms, $events)
{
$this->time_ms = $time_ms;
$this->events = $events;
}
public function get_events()
{
return $this->events;
}
public function get_time_ms()
{
return $this->time_ms;
}
}