init
This commit is contained in:
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, $err);
|
||||
} elseif (!headers_sent()) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit54847d6030d29731b0e767d050d22a36::getLoader();
|
||||
Vendored
+579
@@ -0,0 +1,579 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
self::initializeIncludeClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
$includeFile = self::$includeFile;
|
||||
$includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return array<string, self>
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private static function initializeIncludeClosure()
|
||||
{
|
||||
if (self::$includeFile !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
self::$includeFile = \Closure::bind(static function($file) {
|
||||
include $file;
|
||||
}, null, null);
|
||||
}
|
||||
}
|
||||
+359
@@ -0,0 +1,359 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints((string) $constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = $required;
|
||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[count($installed) - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require __DIR__ . '/installed.php';
|
||||
self::$installed = $required;
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array()) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
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.
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
);
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
);
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'kornrunner\\' => array($vendorDir . '/kornrunner/keccak/src'),
|
||||
'Workerman\\' => array($vendorDir . '/workerman/workerman'),
|
||||
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
||||
'GlobalData\\' => array($vendorDir . '/workerman/globaldata/src'),
|
||||
'Elliptic\\' => array($vendorDir . '/simplito/elliptic-php/lib'),
|
||||
'BN\\' => array($vendorDir . '/simplito/bn-php/lib'),
|
||||
'BI\\' => array($vendorDir . '/simplito/bigint-wrapper-php/lib'),
|
||||
);
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit54847d6030d29731b0e767d050d22a36
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit54847d6030d29731b0e767d050d22a36', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit54847d6030d29731b0e767d050d22a36', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit54847d6030d29731b0e767d050d22a36::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit54847d6030d29731b0e767d050d22a36::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
||||
require $file;
|
||||
}
|
||||
}, null, null);
|
||||
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||
$requireFile($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
Vendored
+85
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit54847d6030d29731b0e767d050d22a36
|
||||
{
|
||||
public static $files = array (
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'k' =>
|
||||
array (
|
||||
'kornrunner\\' => 11,
|
||||
),
|
||||
'W' =>
|
||||
array (
|
||||
'Workerman\\' => 10,
|
||||
),
|
||||
'S' =>
|
||||
array (
|
||||
'Symfony\\Polyfill\\Mbstring\\' => 26,
|
||||
),
|
||||
'G' =>
|
||||
array (
|
||||
'GlobalData\\' => 11,
|
||||
),
|
||||
'E' =>
|
||||
array (
|
||||
'Elliptic\\' => 9,
|
||||
),
|
||||
'B' =>
|
||||
array (
|
||||
'BN\\' => 3,
|
||||
'BI\\' => 3,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'kornrunner\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/kornrunner/keccak/src',
|
||||
),
|
||||
'Workerman\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/workerman/workerman',
|
||||
),
|
||||
'Symfony\\Polyfill\\Mbstring\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
|
||||
),
|
||||
'GlobalData\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/workerman/globaldata/src',
|
||||
),
|
||||
'Elliptic\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/simplito/elliptic-php/lib',
|
||||
),
|
||||
'BN\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/simplito/bn-php/lib',
|
||||
),
|
||||
'BI\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/simplito/bigint-wrapper-php/lib',
|
||||
),
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit54847d6030d29731b0e767d050d22a36::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit54847d6030d29731b0e767d050d22a36::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit54847d6030d29731b0e767d050d22a36::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
||||
Vendored
+405
@@ -0,0 +1,405 @@
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "kornrunner/keccak",
|
||||
"version": "1.1.0",
|
||||
"version_normalized": "1.1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kornrunner/php-keccak.git",
|
||||
"reference": "433749d28e117fb97baf9f2631b92b5d9ab3c890"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/kornrunner/php-keccak/zipball/433749d28e117fb97baf9f2631b92b5d9ab3c890",
|
||||
"reference": "433749d28e117fb97baf9f2631b92b5d9ab3c890",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.3",
|
||||
"symfony/polyfill-mbstring": "^1.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.2"
|
||||
},
|
||||
"time": "2020-12-07T15:40:44+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"kornrunner\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Boris Momcilovic",
|
||||
"homepage": "https://github.com/kornrunner/php-keccak"
|
||||
}
|
||||
],
|
||||
"description": "Pure PHP implementation of Keccak",
|
||||
"keywords": [
|
||||
"keccak",
|
||||
"sha-3",
|
||||
"sha3-256"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/kornrunner/php-keccak/issues",
|
||||
"source": "https://github.com/kornrunner/php-keccak/tree/1.1.0"
|
||||
},
|
||||
"install-path": "../kornrunner/keccak"
|
||||
},
|
||||
{
|
||||
"name": "simplito/bigint-wrapper-php",
|
||||
"version": "1.0.0",
|
||||
"version_normalized": "1.0.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/simplito/bigint-wrapper-php.git",
|
||||
"reference": "cf21ec76d33f103add487b3eadbd9f5033a25930"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/simplito/bigint-wrapper-php/zipball/cf21ec76d33f103add487b3eadbd9f5033a25930",
|
||||
"reference": "cf21ec76d33f103add487b3eadbd9f5033a25930",
|
||||
"shasum": ""
|
||||
},
|
||||
"time": "2018-02-27T12:38:08+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BI\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Simplito Team",
|
||||
"email": "s.smyczynski@simplito.com",
|
||||
"homepage": "https://simplito.com"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for php_gmp and php_bcmath modules",
|
||||
"support": {
|
||||
"issues": "https://github.com/simplito/bigint-wrapper-php/issues",
|
||||
"source": "https://github.com/simplito/bigint-wrapper-php/tree/1.0.0"
|
||||
},
|
||||
"install-path": "../simplito/bigint-wrapper-php"
|
||||
},
|
||||
{
|
||||
"name": "simplito/bn-php",
|
||||
"version": "1.1.4",
|
||||
"version_normalized": "1.1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/simplito/bn-php.git",
|
||||
"reference": "83446756a81720eacc2ffb87ff97958431451fd6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/simplito/bn-php/zipball/83446756a81720eacc2ffb87ff97958431451fd6",
|
||||
"reference": "83446756a81720eacc2ffb87ff97958431451fd6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"simplito/bigint-wrapper-php": "~1.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*"
|
||||
},
|
||||
"time": "2024-01-10T16:16:59+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BN\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Simplito Team",
|
||||
"email": "s.smyczynski@simplito.com",
|
||||
"homepage": "https://simplito.com"
|
||||
}
|
||||
],
|
||||
"description": "Big number implementation compatible with bn.js",
|
||||
"support": {
|
||||
"issues": "https://github.com/simplito/bn-php/issues",
|
||||
"source": "https://github.com/simplito/bn-php/tree/1.1.4"
|
||||
},
|
||||
"install-path": "../simplito/bn-php"
|
||||
},
|
||||
{
|
||||
"name": "simplito/elliptic-php",
|
||||
"version": "1.0.12",
|
||||
"version_normalized": "1.0.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/simplito/elliptic-php.git",
|
||||
"reference": "be321666781be2be2c89c79c43ffcac834bc8868"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/simplito/elliptic-php/zipball/be321666781be2be2c89c79c43ffcac834bc8868",
|
||||
"reference": "be321666781be2be2c89c79c43ffcac834bc8868",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gmp": "*",
|
||||
"simplito/bn-php": "~1.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpbench/phpbench": "@dev",
|
||||
"phpunit/phpunit": "*"
|
||||
},
|
||||
"time": "2024-01-09T14:57:04+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Elliptic\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Simplito Team",
|
||||
"email": "s.smyczynski@simplito.com",
|
||||
"homepage": "https://simplito.com"
|
||||
}
|
||||
],
|
||||
"description": "Fast elliptic curve cryptography",
|
||||
"homepage": "https://github.com/simplito/elliptic-php",
|
||||
"keywords": [
|
||||
"Curve25519",
|
||||
"ECDSA",
|
||||
"Ed25519",
|
||||
"EdDSA",
|
||||
"cryptography",
|
||||
"curve",
|
||||
"curve25519-weier",
|
||||
"ecc",
|
||||
"ecdh",
|
||||
"elliptic",
|
||||
"nistp192",
|
||||
"nistp224",
|
||||
"nistp256",
|
||||
"nistp384",
|
||||
"nistp521",
|
||||
"secp256k1"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/simplito/elliptic-php/issues",
|
||||
"source": "https://github.com/simplito/elliptic-php/tree/1.0.12"
|
||||
},
|
||||
"install-path": "../simplito/elliptic-php"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.33.0",
|
||||
"version_normalized": "1.33.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-iconv": "*",
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"time": "2024-12-23T08:48:59+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"install-path": "../symfony/polyfill-mbstring"
|
||||
},
|
||||
{
|
||||
"name": "workerman/globaldata",
|
||||
"version": "v1.0.6",
|
||||
"version_normalized": "1.0.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/walkor/GlobalData.git",
|
||||
"reference": "9f5082ad712d98c0deedfbfe244661dce151926f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/walkor/GlobalData/zipball/9f5082ad712d98c0deedfbfe244661dce151926f",
|
||||
"reference": "9f5082ad712d98c0deedfbfe244661dce151926f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"workerman/workerman": ">=3.3.0"
|
||||
},
|
||||
"time": "2024-12-27T12:40:16+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GlobalData\\": "./src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"homepage": "http://www.workerman.net",
|
||||
"support": {
|
||||
"issues": "https://github.com/walkor/GlobalData/issues",
|
||||
"source": "https://github.com/walkor/GlobalData/tree/v1.0.6"
|
||||
},
|
||||
"install-path": "../workerman/globaldata"
|
||||
},
|
||||
{
|
||||
"name": "workerman/workerman",
|
||||
"version": "v4.2.1",
|
||||
"version_normalized": "4.2.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/walkor/workerman.git",
|
||||
"reference": "cafb5a43d93d7d30a16b32a57948581cca993562"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/walkor/workerman/zipball/cafb5a43d93d7d30a16b32a57948581cca993562",
|
||||
"reference": "cafb5a43d93d7d30a16b32a57948581cca993562",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-event": "For better performance. "
|
||||
},
|
||||
"time": "2024-11-24T11:45:37+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Workerman\\": "./"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "walkor",
|
||||
"email": "walkor@workerman.net",
|
||||
"homepage": "http://www.workerman.net",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.",
|
||||
"homepage": "http://www.workerman.net",
|
||||
"keywords": [
|
||||
"asynchronous",
|
||||
"event-loop"
|
||||
],
|
||||
"support": {
|
||||
"email": "walkor@workerman.net",
|
||||
"forum": "http://wenda.workerman.net/",
|
||||
"issues": "https://github.com/walkor/workerman/issues",
|
||||
"source": "https://github.com/walkor/workerman",
|
||||
"wiki": "http://doc.workerman.net/"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/workerman",
|
||||
"type": "open_collective"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/walkor",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"install-path": "../workerman/workerman"
|
||||
}
|
||||
],
|
||||
"dev": true,
|
||||
"dev-package-names": []
|
||||
}
|
||||
Vendored
+86
@@ -0,0 +1,86 @@
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => '__root__',
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => NULL,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev' => true,
|
||||
),
|
||||
'versions' => array(
|
||||
'__root__' => array(
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => NULL,
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'kornrunner/keccak' => array(
|
||||
'pretty_version' => '1.1.0',
|
||||
'version' => '1.1.0.0',
|
||||
'reference' => '433749d28e117fb97baf9f2631b92b5d9ab3c890',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../kornrunner/keccak',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'simplito/bigint-wrapper-php' => array(
|
||||
'pretty_version' => '1.0.0',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => 'cf21ec76d33f103add487b3eadbd9f5033a25930',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../simplito/bigint-wrapper-php',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'simplito/bn-php' => array(
|
||||
'pretty_version' => '1.1.4',
|
||||
'version' => '1.1.4.0',
|
||||
'reference' => '83446756a81720eacc2ffb87ff97958431451fd6',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../simplito/bn-php',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'simplito/elliptic-php' => array(
|
||||
'pretty_version' => '1.0.12',
|
||||
'version' => '1.0.12.0',
|
||||
'reference' => 'be321666781be2be2c89c79c43ffcac834bc8868',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../simplito/elliptic-php',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/polyfill-mbstring' => array(
|
||||
'pretty_version' => 'v1.33.0',
|
||||
'version' => '1.33.0.0',
|
||||
'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'workerman/globaldata' => array(
|
||||
'pretty_version' => 'v1.0.6',
|
||||
'version' => '1.0.6.0',
|
||||
'reference' => '9f5082ad712d98c0deedfbfe244661dce151926f',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../workerman/globaldata',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'workerman/workerman' => array(
|
||||
'pretty_version' => 'v4.2.1',
|
||||
'version' => '4.2.1.0',
|
||||
'reference' => 'cafb5a43d93d7d30a16b32a57948581cca993562',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../workerman/workerman',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 80000)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
service_name: travis-ci
|
||||
coverage_clover: build/logs/clover.xml
|
||||
json_path: coveralls-upload.json
|
||||
@@ -0,0 +1,10 @@
|
||||
composer.phar
|
||||
/vendor/
|
||||
|
||||
# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
|
||||
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
|
||||
# composer.lock
|
||||
nbproject/
|
||||
build/
|
||||
.phpunit.result.cache
|
||||
infection.log
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.3
|
||||
- 7.4
|
||||
- 8.0
|
||||
- nightly
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: nightly
|
||||
|
||||
install:
|
||||
- phpenv config-rm xdebug.ini || true
|
||||
- travis_retry composer install --prefer-dist -n
|
||||
|
||||
script:
|
||||
- mkdir -p build/logs
|
||||
- phpdbg -qrr vendor/bin/phpunit
|
||||
|
||||
after_success:
|
||||
- composer require php-coveralls/php-coveralls
|
||||
- travis_retry vendor/bin/php-coveralls -v
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Boris Momčilović
|
||||
|
||||
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.
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
# php-keccak [](https://travis-ci.org/kornrunner/php-keccak) [](https://ci.appveyor.com/project/kornrunner/php-keccak/branch/master) [](https://coveralls.io/github/kornrunner/php-keccak?branch=master) [](https://packagist.org/packages/kornrunner/keccak)
|
||||
Pure PHP implementation of Keccak (SHA-3)
|
||||
|
||||
## Usage
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use kornrunner\Keccak;
|
||||
|
||||
Keccak::hash('', 224);
|
||||
// f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd
|
||||
|
||||
Keccak::hash('', 256);
|
||||
// c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
|
||||
|
||||
Keccak::hash('', 384);
|
||||
// 2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff
|
||||
|
||||
Keccak::hash('', 512);
|
||||
// 0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e
|
||||
|
||||
Keccak::shake('', 128, 256);
|
||||
// 7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26
|
||||
|
||||
Keccak::shake('', 256, 512);
|
||||
// 46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be
|
||||
```
|
||||
|
||||
[ 0x9c7b7a00972121fb843af7af74526d7eb585b171][Ethereum]
|
||||
|
||||
[Ethereum]: https://etherscan.io/address/0x9c7b7a00972121fb843af7af74526d7eb585b171 "Donate with Ethereum"
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
build: false
|
||||
shallow_clone: true
|
||||
clone_folder: c:\php-keccak
|
||||
platform: x64
|
||||
|
||||
cache:
|
||||
- c:\php -> appveyor.yml
|
||||
- vendor -> composer.lock
|
||||
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- PHP_VERSION: '7.3.7'
|
||||
PHP_DOWNLOAD_URL: 'https://windows.php.net/downloads/releases/archives/php-7.3.7-nts-Win32-VC15-x64.zip'
|
||||
- PHP_VERSION: '7.4.3'
|
||||
PHP_DOWNLOAD_URL: 'https://windows.php.net/downloads/releases/archives/php-7.4.3-nts-Win32-vc15-x64.zip'
|
||||
- PHP_VERSION: '8.0.0'
|
||||
PHP_DOWNLOAD_URL: 'https://windows.php.net/downloads/releases/php-8.0.0-nts-Win32-vs16-x64.zip'
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
init:
|
||||
- SET PATH=c:\php\%PHP_VERSION%;%PATH%
|
||||
- set COMPOSER_NO_INTERACTION=1
|
||||
|
||||
install:
|
||||
- IF NOT EXIST c:\php mkdir c:\php
|
||||
- IF NOT EXIST c:\php\%PHP_VERSION% mkdir c:\php\%PHP_VERSION%
|
||||
- cd c:\php\%PHP_VERSION%
|
||||
- IF NOT EXIST php-installed.txt curl --fail --location --silent --show-error -o php.zip %PHP_DOWNLOAD_URL%
|
||||
- IF NOT EXIST php-installed.txt 7z x php.zip -y
|
||||
- IF NOT EXIST php-installed.txt del /Q *.zip
|
||||
- IF NOT EXIST php-installed.txt copy /Y php.ini-development php.ini
|
||||
- IF NOT EXIST php-installed.txt echo max_execution_time=1200 >> php.ini
|
||||
- IF NOT EXIST php-installed.txt echo date.timezone="UTC" >> php.ini
|
||||
- IF NOT EXIST php-installed.txt echo extension_dir=ext >> php.ini
|
||||
- IF NOT EXIST php-installed.txt echo extension=php_openssl.dll >> php.ini
|
||||
- IF NOT EXIST php-installed.txt echo extension=php_mbstring.dll >> php.ini
|
||||
- IF NOT EXIST php-installed.txt appveyor DownloadFile https://getcomposer.org/composer.phar
|
||||
- IF NOT EXIST php-installed.txt echo @php %%~dp0composer.phar %%* > composer.bat
|
||||
- IF NOT EXIST php-installed.txt type nul >> php-installed.txt
|
||||
- cd c:\php-keccak
|
||||
|
||||
test_script:
|
||||
- composer install
|
||||
- vendor/bin/phpunit.bat --coverage-text
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "kornrunner/keccak",
|
||||
"description": "Pure PHP implementation of Keccak",
|
||||
"keywords": ["keccak", "sha-3", "sha3-256"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Boris Momcilovic",
|
||||
"homepage": "https://github.com/kornrunner/php-keccak"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.3",
|
||||
"symfony/polyfill-mbstring": "^1.8"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"kornrunner\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"kornrunner\\": "test"
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.2"
|
||||
}
|
||||
}
|
||||
+1870
File diff suppressed because it is too large
Load Diff
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"timeout": 10,
|
||||
"source": {
|
||||
"directories": [
|
||||
"src"
|
||||
]
|
||||
},
|
||||
"logs": {
|
||||
"text": "infection.log"
|
||||
},
|
||||
"mutators": {
|
||||
"@default": true
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="vendor/autoload.php"
|
||||
backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
verbose="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false">
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Keccak Test Suite">
|
||||
<directory>test</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
<logging>
|
||||
<log type="tap" target="build/report.tap"/>
|
||||
<log type="junit" target="build/report.junit.xml"/>
|
||||
<log type="coverage-html" target="build/coverage"/>
|
||||
<log type="coverage-text" target="build/coverage.txt"/>
|
||||
<log type="coverage-clover" target="build/logs/clover.xml"/>
|
||||
</logging>
|
||||
</phpunit>
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
<?php
|
||||
|
||||
namespace kornrunner;
|
||||
|
||||
use Exception;
|
||||
use function mb_strlen;
|
||||
use function mb_substr;
|
||||
|
||||
final class Keccak
|
||||
{
|
||||
private const KECCAK_ROUNDS = 24;
|
||||
private const LFSR = 0x01;
|
||||
private const ENCODING = '8bit';
|
||||
private static $keccakf_rotc = [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44];
|
||||
private static $keccakf_piln = [10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12,2, 20, 14, 22, 9, 6, 1];
|
||||
private static $x64 = (PHP_INT_SIZE === 8);
|
||||
|
||||
private static function keccakf64(&$st, $rounds): void {
|
||||
$keccakf_rndc = [
|
||||
[0x00000000, 0x00000001], [0x00000000, 0x00008082], [0x80000000, 0x0000808a], [0x80000000, 0x80008000],
|
||||
[0x00000000, 0x0000808b], [0x00000000, 0x80000001], [0x80000000, 0x80008081], [0x80000000, 0x00008009],
|
||||
[0x00000000, 0x0000008a], [0x00000000, 0x00000088], [0x00000000, 0x80008009], [0x00000000, 0x8000000a],
|
||||
[0x00000000, 0x8000808b], [0x80000000, 0x0000008b], [0x80000000, 0x00008089], [0x80000000, 0x00008003],
|
||||
[0x80000000, 0x00008002], [0x80000000, 0x00000080], [0x00000000, 0x0000800a], [0x80000000, 0x8000000a],
|
||||
[0x80000000, 0x80008081], [0x80000000, 0x00008080], [0x00000000, 0x80000001], [0x80000000, 0x80008008]
|
||||
];
|
||||
|
||||
$bc = [];
|
||||
for ($round = 0; $round < $rounds; $round++) {
|
||||
|
||||
// Theta
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$bc[$i] = [
|
||||
$st[$i][0] ^ $st[$i + 5][0] ^ $st[$i + 10][0] ^ $st[$i + 15][0] ^ $st[$i + 20][0],
|
||||
$st[$i][1] ^ $st[$i + 5][1] ^ $st[$i + 10][1] ^ $st[$i + 15][1] ^ $st[$i + 20][1]
|
||||
];
|
||||
}
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$t = [
|
||||
$bc[($i + 4) % 5][0] ^ (($bc[($i + 1) % 5][0] << 1) | ($bc[($i + 1) % 5][1] >> 31)) & (0xFFFFFFFF),
|
||||
$bc[($i + 4) % 5][1] ^ (($bc[($i + 1) % 5][1] << 1) | ($bc[($i + 1) % 5][0] >> 31)) & (0xFFFFFFFF)
|
||||
];
|
||||
|
||||
for ($j = 0; $j < 25; $j += 5) {
|
||||
$st[$j + $i] = [
|
||||
$st[$j + $i][0] ^ $t[0],
|
||||
$st[$j + $i][1] ^ $t[1]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Rho Pi
|
||||
$t = $st[1];
|
||||
for ($i = 0; $i < 24; $i++) {
|
||||
$j = self::$keccakf_piln[$i];
|
||||
|
||||
$bc[0] = $st[$j];
|
||||
|
||||
$n = self::$keccakf_rotc[$i];
|
||||
$hi = $t[0];
|
||||
$lo = $t[1];
|
||||
if ($n >= 32) {
|
||||
$n -= 32;
|
||||
$hi = $t[1];
|
||||
$lo = $t[0];
|
||||
}
|
||||
|
||||
$st[$j] =[
|
||||
(($hi << $n) | ($lo >> (32 - $n))) & (0xFFFFFFFF),
|
||||
(($lo << $n) | ($hi >> (32 - $n))) & (0xFFFFFFFF)
|
||||
];
|
||||
|
||||
$t = $bc[0];
|
||||
}
|
||||
|
||||
// Chi
|
||||
for ($j = 0; $j < 25; $j += 5) {
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$bc[$i] = $st[$j + $i];
|
||||
}
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$st[$j + $i] = [
|
||||
$st[$j + $i][0] ^ ~$bc[($i + 1) % 5][0] & $bc[($i + 2) % 5][0],
|
||||
$st[$j + $i][1] ^ ~$bc[($i + 1) % 5][1] & $bc[($i + 2) % 5][1]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Iota
|
||||
$st[0] = [
|
||||
$st[0][0] ^ $keccakf_rndc[$round][0],
|
||||
$st[0][1] ^ $keccakf_rndc[$round][1]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private static function keccak64($in_raw, int $capacity, int $outputlength, $suffix, bool $raw_output): string {
|
||||
$capacity /= 8;
|
||||
|
||||
$inlen = mb_strlen($in_raw, self::ENCODING);
|
||||
|
||||
$rsiz = 200 - 2 * $capacity;
|
||||
$rsizw = $rsiz / 8;
|
||||
|
||||
$st = [];
|
||||
for ($i = 0; $i < 25; $i++) {
|
||||
$st[] = [0, 0];
|
||||
}
|
||||
|
||||
for ($in_t = 0; $inlen >= $rsiz; $inlen -= $rsiz, $in_t += $rsiz) {
|
||||
for ($i = 0; $i < $rsizw; $i++) {
|
||||
$t = unpack('V*', mb_substr($in_raw, intval($i * 8 + $in_t), 8, self::ENCODING));
|
||||
|
||||
$st[$i] = [
|
||||
$st[$i][0] ^ $t[2],
|
||||
$st[$i][1] ^ $t[1]
|
||||
];
|
||||
}
|
||||
|
||||
self::keccakf64($st, self::KECCAK_ROUNDS);
|
||||
}
|
||||
|
||||
$temp = mb_substr($in_raw, (int) $in_t, (int) $inlen, self::ENCODING);
|
||||
$temp = str_pad($temp, (int) $rsiz, "\x0", STR_PAD_RIGHT);
|
||||
$temp = substr_replace($temp, chr($suffix), $inlen, 1);
|
||||
$temp = substr_replace($temp, chr(ord($temp[intval($rsiz - 1)]) | 0x80), $rsiz - 1, 1);
|
||||
|
||||
for ($i = 0; $i < $rsizw; $i++) {
|
||||
$t = unpack('V*', mb_substr($temp, $i * 8, 8, self::ENCODING));
|
||||
|
||||
$st[$i] = [
|
||||
$st[$i][0] ^ $t[2],
|
||||
$st[$i][1] ^ $t[1]
|
||||
];
|
||||
}
|
||||
|
||||
self::keccakf64($st, self::KECCAK_ROUNDS);
|
||||
|
||||
$out = '';
|
||||
for ($i = 0; $i < 25; $i++) {
|
||||
$out .= $t = pack('V*', $st[$i][1], $st[$i][0]);
|
||||
}
|
||||
$r = mb_substr($out, 0, intval($outputlength / 8), self::ENCODING);
|
||||
|
||||
return $raw_output ? $r : bin2hex($r);
|
||||
}
|
||||
|
||||
private static function keccakf32(&$st, $rounds): void {
|
||||
$keccakf_rndc = [
|
||||
[0x0000, 0x0000, 0x0000, 0x0001], [0x0000, 0x0000, 0x0000, 0x8082], [0x8000, 0x0000, 0x0000, 0x0808a], [0x8000, 0x0000, 0x8000, 0x8000],
|
||||
[0x0000, 0x0000, 0x0000, 0x808b], [0x0000, 0x0000, 0x8000, 0x0001], [0x8000, 0x0000, 0x8000, 0x08081], [0x8000, 0x0000, 0x0000, 0x8009],
|
||||
[0x0000, 0x0000, 0x0000, 0x008a], [0x0000, 0x0000, 0x0000, 0x0088], [0x0000, 0x0000, 0x8000, 0x08009], [0x0000, 0x0000, 0x8000, 0x000a],
|
||||
[0x0000, 0x0000, 0x8000, 0x808b], [0x8000, 0x0000, 0x0000, 0x008b], [0x8000, 0x0000, 0x0000, 0x08089], [0x8000, 0x0000, 0x0000, 0x8003],
|
||||
[0x8000, 0x0000, 0x0000, 0x8002], [0x8000, 0x0000, 0x0000, 0x0080], [0x0000, 0x0000, 0x0000, 0x0800a], [0x8000, 0x0000, 0x8000, 0x000a],
|
||||
[0x8000, 0x0000, 0x8000, 0x8081], [0x8000, 0x0000, 0x0000, 0x8080], [0x0000, 0x0000, 0x8000, 0x00001], [0x8000, 0x0000, 0x8000, 0x8008]
|
||||
];
|
||||
|
||||
$bc = [];
|
||||
for ($round = 0; $round < $rounds; $round++) {
|
||||
|
||||
// Theta
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$bc[$i] = [
|
||||
$st[$i][0] ^ $st[$i + 5][0] ^ $st[$i + 10][0] ^ $st[$i + 15][0] ^ $st[$i + 20][0],
|
||||
$st[$i][1] ^ $st[$i + 5][1] ^ $st[$i + 10][1] ^ $st[$i + 15][1] ^ $st[$i + 20][1],
|
||||
$st[$i][2] ^ $st[$i + 5][2] ^ $st[$i + 10][2] ^ $st[$i + 15][2] ^ $st[$i + 20][2],
|
||||
$st[$i][3] ^ $st[$i + 5][3] ^ $st[$i + 10][3] ^ $st[$i + 15][3] ^ $st[$i + 20][3]
|
||||
];
|
||||
}
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$t = [
|
||||
$bc[($i + 4) % 5][0] ^ ((($bc[($i + 1) % 5][0] << 1) | ($bc[($i + 1) % 5][1] >> 15)) & (0xFFFF)),
|
||||
$bc[($i + 4) % 5][1] ^ ((($bc[($i + 1) % 5][1] << 1) | ($bc[($i + 1) % 5][2] >> 15)) & (0xFFFF)),
|
||||
$bc[($i + 4) % 5][2] ^ ((($bc[($i + 1) % 5][2] << 1) | ($bc[($i + 1) % 5][3] >> 15)) & (0xFFFF)),
|
||||
$bc[($i + 4) % 5][3] ^ ((($bc[($i + 1) % 5][3] << 1) | ($bc[($i + 1) % 5][0] >> 15)) & (0xFFFF))
|
||||
];
|
||||
|
||||
for ($j = 0; $j < 25; $j += 5) {
|
||||
$st[$j + $i] = [
|
||||
$st[$j + $i][0] ^ $t[0],
|
||||
$st[$j + $i][1] ^ $t[1],
|
||||
$st[$j + $i][2] ^ $t[2],
|
||||
$st[$j + $i][3] ^ $t[3]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Rho Pi
|
||||
$t = $st[1];
|
||||
for ($i = 0; $i < 24; $i++) {
|
||||
$j = self::$keccakf_piln[$i];
|
||||
$bc[0] = $st[$j];
|
||||
|
||||
|
||||
$n = self::$keccakf_rotc[$i] >> 4;
|
||||
$m = self::$keccakf_rotc[$i] % 16;
|
||||
|
||||
$st[$j] = [
|
||||
((($t[(0+$n) %4] << $m) | ($t[(1+$n) %4] >> (16-$m))) & (0xFFFF)),
|
||||
((($t[(1+$n) %4] << $m) | ($t[(2+$n) %4] >> (16-$m))) & (0xFFFF)),
|
||||
((($t[(2+$n) %4] << $m) | ($t[(3+$n) %4] >> (16-$m))) & (0xFFFF)),
|
||||
((($t[(3+$n) %4] << $m) | ($t[(0+$n) %4] >> (16-$m))) & (0xFFFF))
|
||||
];
|
||||
|
||||
$t = $bc[0];
|
||||
}
|
||||
|
||||
// Chi
|
||||
for ($j = 0; $j < 25; $j += 5) {
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$bc[$i] = $st[$j + $i];
|
||||
}
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$st[$j + $i] = [
|
||||
$st[$j + $i][0] ^ ~$bc[($i + 1) % 5][0] & $bc[($i + 2) % 5][0],
|
||||
$st[$j + $i][1] ^ ~$bc[($i + 1) % 5][1] & $bc[($i + 2) % 5][1],
|
||||
$st[$j + $i][2] ^ ~$bc[($i + 1) % 5][2] & $bc[($i + 2) % 5][2],
|
||||
$st[$j + $i][3] ^ ~$bc[($i + 1) % 5][3] & $bc[($i + 2) % 5][3]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Iota
|
||||
$st[0] = [
|
||||
$st[0][0] ^ $keccakf_rndc[$round][0],
|
||||
$st[0][1] ^ $keccakf_rndc[$round][1],
|
||||
$st[0][2] ^ $keccakf_rndc[$round][2],
|
||||
$st[0][3] ^ $keccakf_rndc[$round][3]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private static function keccak32($in_raw, int $capacity, int $outputlength, $suffix, bool $raw_output): string {
|
||||
$capacity /= 8;
|
||||
|
||||
$inlen = mb_strlen($in_raw, self::ENCODING);
|
||||
|
||||
$rsiz = 200 - 2 * $capacity;
|
||||
$rsizw = $rsiz / 8;
|
||||
|
||||
$st = [];
|
||||
for ($i = 0; $i < 25; $i++) {
|
||||
$st[] = [0, 0, 0, 0];
|
||||
}
|
||||
|
||||
for ($in_t = 0; $inlen >= $rsiz; $inlen -= $rsiz, $in_t += $rsiz) {
|
||||
for ($i = 0; $i < $rsizw; $i++) {
|
||||
$t = unpack('v*', mb_substr($in_raw, intval($i * 8 + $in_t), 8, self::ENCODING));
|
||||
|
||||
$st[$i] = [
|
||||
$st[$i][0] ^ $t[4],
|
||||
$st[$i][1] ^ $t[3],
|
||||
$st[$i][2] ^ $t[2],
|
||||
$st[$i][3] ^ $t[1]
|
||||
];
|
||||
}
|
||||
|
||||
self::keccakf32($st, self::KECCAK_ROUNDS);
|
||||
}
|
||||
|
||||
$temp = mb_substr($in_raw, (int) $in_t, (int) $inlen, self::ENCODING);
|
||||
$temp = str_pad($temp, (int) $rsiz, "\x0", STR_PAD_RIGHT);
|
||||
$temp = substr_replace($temp, chr($suffix), $inlen, 1);
|
||||
$temp = substr_replace($temp, chr((int) $temp[intval($rsiz - 1)] | 0x80), $rsiz - 1, 1);
|
||||
|
||||
for ($i = 0; $i < $rsizw; $i++) {
|
||||
$t = unpack('v*', mb_substr($temp, $i * 8, 8, self::ENCODING));
|
||||
|
||||
$st[$i] = [
|
||||
$st[$i][0] ^ $t[4],
|
||||
$st[$i][1] ^ $t[3],
|
||||
$st[$i][2] ^ $t[2],
|
||||
$st[$i][3] ^ $t[1]
|
||||
];
|
||||
}
|
||||
|
||||
self::keccakf32($st, self::KECCAK_ROUNDS);
|
||||
|
||||
$out = '';
|
||||
for ($i = 0; $i < 25; $i++) {
|
||||
$out .= $t = pack('v*', $st[$i][3],$st[$i][2], $st[$i][1], $st[$i][0]);
|
||||
}
|
||||
$r = mb_substr($out, 0, intval($outputlength / 8), self::ENCODING);
|
||||
|
||||
return $raw_output ? $r: bin2hex($r);
|
||||
}
|
||||
|
||||
private static function keccak($in_raw, int $capacity, int $outputlength, $suffix, bool $raw_output): string {
|
||||
return self::$x64
|
||||
? self::keccak64($in_raw, $capacity, $outputlength, $suffix, $raw_output)
|
||||
: self::keccak32($in_raw, $capacity, $outputlength, $suffix, $raw_output);
|
||||
}
|
||||
|
||||
public static function hash($in, int $mdlen, bool $raw_output = false): string {
|
||||
if (!in_array($mdlen, [224, 256, 384, 512], true)) {
|
||||
throw new Exception('Unsupported Keccak Hash output size.');
|
||||
}
|
||||
|
||||
return self::keccak($in, $mdlen, $mdlen, self::LFSR, $raw_output);
|
||||
}
|
||||
|
||||
public static function shake($in, int $security_level, int $outlen, bool $raw_output = false): string {
|
||||
if (!in_array($security_level, [128, 256], true)) {
|
||||
throw new Exception('Unsupported Keccak Shake security level.');
|
||||
}
|
||||
|
||||
return self::keccak($in, $security_level, $outlen, 0x1f, $raw_output);
|
||||
}
|
||||
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace kornrunner;
|
||||
|
||||
/**
|
||||
*@see https://gist.github.com/Souptacular/f50128d63b5188490fa2
|
||||
*/
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class KeccakTest extends TestCase
|
||||
{
|
||||
private const SHORT = "52A608AB21CCDD8A4457A57EDE782176";
|
||||
private const LONG = "3A3A819C48EFDE2AD914FBF00E18AB6BC4F14513AB27D0C178A188B61431E7F5623CB66B23346775D386B50E982C493ADBBFC54B9A3CD383382336A1A0B2150A15358F336D03AE18F666C7573D55C4FD181C29E6CCFDE63EA35F0ADF5885CFC0A3D84A2B2E4DD24496DB789E663170CEF74798AA1BBCD4574EA0BBA40489D764B2F83AADC66B148B4A0CD95246C127D5871C4F11418690A5DDF01246A0C80A43C70088B6183639DCFDA4125BD113A8F49EE23ED306FAAC576C3FB0C1E256671D817FC2534A52F5B439F72E424DE376F4C565CCA82307DD9EF76DA5B7C4EB7E085172E328807C02D011FFBF33785378D79DC266F6A5BE6BB0E4A92ECEEBAEB1";
|
||||
private static $x64;
|
||||
|
||||
public static function setUpBeforeClass(): void {
|
||||
parent::setUpBeforeClass();
|
||||
$class = new \ReflectionClass(Keccak::class);
|
||||
self::$x64 = $class->getProperty('x64');
|
||||
self::$x64->setAccessible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hash
|
||||
*/
|
||||
public function testHash($level, $tests) {
|
||||
$x64_values = [true, false];
|
||||
foreach ($x64_values as $x64_bit) {
|
||||
self::$x64->setValue($x64_bit);
|
||||
|
||||
foreach($tests as $test) {
|
||||
$message = $test[0];
|
||||
$expected = $test[1];
|
||||
$this->assertEquals($expected, Keccak::hash($message, $level));
|
||||
$this->assertEquals(hex2bin($expected), Keccak::hash($message, $level, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function hash(): array {
|
||||
return [
|
||||
/**
|
||||
* @see https://emn178.github.io/online-tools/keccak_512.html
|
||||
*/
|
||||
[512, [
|
||||
['','0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e'],
|
||||
['testing', '9558a7ba9ac74b33b347703ffe33f8d561d86d9fcad1cfd63225fb55dfea50a0953a0efafd6072377f4c396e806d5bda0294cba28762740d8446fee45a276e4a'],
|
||||
['The quick brown fox jumps over the lazy dog', 'd135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609'],
|
||||
['The quick brown fox jumps over the lazy dog.','ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760'],
|
||||
[hex2bin(self::SHORT), '4b39d3da5bcdf4d9b769015995644311c14c435bf72b1009d6dd71b01a63b97cfb596418e8e42342d117e07471a8914314ba7b0e264dadf0cea381868cbd43d1'],
|
||||
[hex2bin(self::LONG), '81950e7096d31d4f22e3db71cac725bf59e81af54c7ca9e6aeee71c010fc5467466312a01aa5c137cfb140646941556796f612c9351268737c7e9a2b9631d1fa']
|
||||
]],
|
||||
/**
|
||||
* @see https://emn178.github.io/online-tools/keccak_384.html
|
||||
*/
|
||||
[384, [
|
||||
['', '2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff'],
|
||||
['testing', '1020b1c91956efe79b89c387b54de4f7a9c187c3970552f9f48c0da176f6326b7aa694795d2c9adcf2bdd20aec605588'],
|
||||
['The quick brown fox jumps over the lazy dog', '283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3'],
|
||||
['The quick brown fox jumps over the lazy dog.', '9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b'],
|
||||
[hex2bin(self::SHORT), '18422ac1d3a1e54bad876883d2d6dd65f65c1d5f33a7125cc4c186405a12ed64ba96672eedda8c5a6331d28683f488eb'],
|
||||
[hex2bin(self::LONG), '6bff1c8405a3fe594e360e3bccea1ebcd509310dc79b9e45c263783d7a5dd662c6789b18bd567dbdda1554f5bee6a860'],
|
||||
[hex2bin('E35780EB9799AD4C77535D4DDB683CF33EF367715327CF4C4A58ED9CBDCDD486F669F80189D549A9364FA82A51A52654EC721BB3AAB95DCEB4A86A6AFA93826DB923517E928F33E3FBA850D45660EF83B9876ACCAFA2A9987A254B137C6E140A21691E1069413848'), '9fb5700502e01926824f46e9f61894f9487dbcf8ae6217203c85606f975566539376d6239db04aef9bf48ca4f191a90b'],
|
||||
]],
|
||||
/**
|
||||
* @see https://emn178.github.io/online-tools/keccak_256.html
|
||||
*/
|
||||
[256, [
|
||||
['', 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'],
|
||||
['testing', '5f16f4c7f149ac4f9510d9cf8cf384038ad348b3bcdc01915f95de12df9d1b02'],
|
||||
['The quick brown fox jumps over the lazy dog', '4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15'],
|
||||
['The quick brown fox jumps over the lazy dog.', '578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d'],
|
||||
[hex2bin(self::SHORT), '0e32defa2071f0b5ac0e6a108b842ed0f1d3249712f58ee0ddf956fe332a5f95'],
|
||||
[hex2bin(self::LONG), '348fb774adc970a16b1105669442625e6adaa8257a89effdb5a802f161b862ea'],
|
||||
[hex2bin('9F2FCC7C90DE090D6B87CD7E9718C1EA6CB21118FC2D5DE9F97E5DB6AC1E9C10'), '24dd2ee02482144f539f810d2caa8a7b75d0fa33657e47932122d273c3f6f6d1'],
|
||||
]],
|
||||
/**
|
||||
* @see https://emn178.github.io/online-tools/keccak_224.html
|
||||
*/
|
||||
[224, [
|
||||
['', 'f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd'],
|
||||
['testing', '7b77b0b01d9b669ec7637ae75fd2f0ce234c8c8c835723b6715f4b59'],
|
||||
['The quick brown fox jumps over the lazy dog', '310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe'],
|
||||
['The quick brown fox jumps over the lazy dog.', 'c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab'],
|
||||
[hex2bin(self::SHORT), '5679cd509c5120af54795cf477149641cf27b2ebb6a5f90340704e57'],
|
||||
[hex2bin(self::LONG), '5af56987ea9cf11fcd0eac5ebc14b037365e9b1123e31cb2dfc7929a'],
|
||||
]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider Shake
|
||||
*/
|
||||
public function testShake($level, $size, $tests)
|
||||
{
|
||||
$x64_values = [true, false];
|
||||
foreach ($x64_values as $x64_bit) {
|
||||
self::$x64->setValue($x64_bit);
|
||||
|
||||
foreach($tests as $test) {
|
||||
$message = $test[0];
|
||||
$expected = $test[1];
|
||||
$this->assertEquals($expected, Keccak::shake($message, $level, $size));
|
||||
$this->assertEquals(hex2bin($expected), Keccak::shake($message, $level, $size, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function shake(): array {
|
||||
return [
|
||||
[128, 256, [
|
||||
['', '7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26'],
|
||||
[hex2bin(self::SHORT), '3a0faca70c9d2b81d1064d429ea3b05ad27366f64985379ddd75bc73d6a83810'],
|
||||
[hex2bin(self::LONG), '14236e75b9784df4f57935f945356cbe383fe513ed30286f91060759bcb0ef4b'],
|
||||
['The quick brown fox jumps over the lazy dog', 'f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e'],
|
||||
['The quick brown fox jumps over the lazy dof', '853f4538be0db9621a6cea659a06c1107b1f83f02b13d18297bd39d7411cf10c'],
|
||||
]],
|
||||
[256, 512, [
|
||||
['', '46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be'],
|
||||
[hex2bin(self::SHORT), '57119c4507f975ad0e9ea4f1166e5f9b590bf2671aaeb41d130d2c570bafc579b0b9ec485cc736a0a848bbc886cbaa79ffcd067ce64b3b410741ab011c544225'],
|
||||
[hex2bin(self::LONG), '8a5199b4a7e133e264a86202720655894d48cff344a928cf8347f48379cef347dfc5bcffab99b27b1f89aa2735e23d30088ffa03b9edb02b9635470ab9f10389'],
|
||||
]],
|
||||
];
|
||||
}
|
||||
|
||||
public function testUnsupportedHashOutputSize()
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
$this->expectExceptionMessage('Unsupported Keccak Hash output size.');
|
||||
Keccak::hash('', 225);
|
||||
}
|
||||
|
||||
public function testUnsupportedShakeSecurityLevel()
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
$this->expectExceptionMessage('Unsupported Keccak Shake security level.');
|
||||
Keccak::shake('', 129, 256);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
|
||||
## MIT LICENSE
|
||||
|
||||
Copyright (C) 2018 Simplito
|
||||
|
||||
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.
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
|
||||
# BigInteger wrapper library for PHP
|
||||
|
||||
## Information
|
||||
|
||||
This library is a common interface for php_gmp and php_bcmath modules. It automatically detects supported modules and uses the best of them (gmp>bcmath). Gmp is a lot faster, but is also missing on many hosting services -- that is why this wrapper has been created. It is used for example in encryption functions of the [PrivMX WebMail](https://privmx.com) software.
|
||||
|
||||
## Installation
|
||||
|
||||
You can install this library via Composer:
|
||||
```
|
||||
composer require simplito/bigint-wrapper-php
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
If you want to force using a specific implementation, then define constant S_MATH_BIGINTEGER_MODE - set it to "gmp" or "bcmath". If you do not do this, mode of operation and the constant will be set automatically.
|
||||
|
||||
If there are no gmp and bcmath modules, an exception will be thrown. If you want to prevent this, then simply define S_MATH_BIGINTEGER_QUIET constant.
|
||||
|
||||
All functions of this library are implemented as members of class BigInteger, which is located under BI namespace. Instances of BigInteger are immutable - member functions usually return new instances of the BigInteger class.
|
||||
|
||||
|
||||
### ConvertibleToBi - a placeholder type
|
||||
|
||||
To make the below documentation more readable we use the "ConvertibleToBi" type symbol, which in reality can be one of the following types:
|
||||
- an instance of the BigInteger class
|
||||
- an integer
|
||||
- a decimal string
|
||||
- a gmp resource or class (only when you are in gmp mode)
|
||||
|
||||
If you have a non-decimal string and want to use it -- first you have to convert it to BigInteger class using:
|
||||
```
|
||||
new BigInteger($myNonDecimalString, $baseOfMyNonDecimalString)
|
||||
```
|
||||
|
||||
### BI\BigInteger class members
|
||||
|
||||
#### construct(ConvertibleToBi $value = 0, int $base = 10)
|
||||
Creates a new instance of BigInteger. If you pass an invalid value, an exception will be thrown. If $base === true then passed $value will be used without any check and conversion. Supported bases: 2, 10, 16, 256.
|
||||
- **GMP implementation:** gmp_init + bin2hex for 256 base
|
||||
- **Bcmath implementation:** custom(bcadd + bcmul)
|
||||
|
||||
#### static BigInteger|false createSafe(ConvertibleToBi $value = 0, int $base = 10)
|
||||
Creates a new BigInteger instance in the same way as constructor, but if there is an error, false will be returned instead of throwing an exception.
|
||||
|
||||
#### BigInteger add(ConvertibleToBi $x)
|
||||
Adds numbers
|
||||
- **GMP implementation:** gmp_add
|
||||
- **Bcmath implementation:** bcadd
|
||||
|
||||
#### BigInteger sub(ConvertibleToBi $x)
|
||||
Subtracts numbers
|
||||
- **GMP implementation:** gmp_sub
|
||||
- **Bcmath implementation:** bcsub
|
||||
|
||||
#### BigInteger mul(ConvertibleToBi $x)
|
||||
Multiplies numbers
|
||||
- **GMP implementation:** gmp_mul
|
||||
- **Bcmath implementation:** bcmul
|
||||
|
||||
#### BigInteger div(ConvertibleToBi $x)
|
||||
Divides numbers
|
||||
- **GMP implementation:** gmp_div_q
|
||||
- **Bcmath implementation:** bcdiv
|
||||
|
||||
#### BigInteger divR(ConvertibleToBi $x)
|
||||
Returns a remainder of the division of numbers. The remainder has the sign of the divided number.
|
||||
- **GMP implementation:** gmp_div_r
|
||||
- **Bcmath implementation:** bcmod
|
||||
|
||||
#### array(BigInteger, BigInteger) divQR(ConvertibleToBi $x)
|
||||
Divides numbers and returns quotient and remainder. Returns an array(), with the first element being quotient, and the second being remainder.
|
||||
- **GMP implementation:** gmp_div_qr
|
||||
- **Bcmath implementation:** div + divR
|
||||
|
||||
#### BigInteger mod(ConvertibleToBi $x)
|
||||
The "division modulo" operation. The result is always non-negative, the sign of divider is ignored.
|
||||
- **GMP implementation:** gmp_mod
|
||||
- **Bcmath implementation:** custom (bcmod + bcadd)
|
||||
|
||||
#### BigInteger gcd(ConvertibleToBi $x)
|
||||
Calculates greatest common divisor
|
||||
- **GMP implementation:** gmp_gcd
|
||||
- **Bcmath implementation:** custom (bccomp + bcdiv + bcsub + bcmul)
|
||||
|
||||
#### BigInteger|false modInverse(ConvertibleToBi $x)
|
||||
Inverses by modulo, returns false if inversion does not exist.
|
||||
- **GMP implementation:** gmp_invert
|
||||
- **Bcmath implementation:** custom (gcd)
|
||||
|
||||
#### BigInteger pow(ConvertibleToBi $x)
|
||||
The power function.
|
||||
- **GMP implementation:** gmp_pow
|
||||
- **Bcmath implementation:** bcpow
|
||||
|
||||
#### BigInteger powMod(ConvertibleToBi $x, ConvertibleToBi $n)
|
||||
The modular power function.
|
||||
- **GMP implementation:** gmp_powm
|
||||
- **Bcmath implementation:** bcpowmod
|
||||
|
||||
#### BigInteger abs()
|
||||
Returns absolute value.
|
||||
- **GMP implementation:** gmp_abs
|
||||
- **Bcmath implementation:** check first character
|
||||
|
||||
#### BigInteger neg()
|
||||
Negates the number
|
||||
- **GMP implementation:** gmp_neg
|
||||
- **Bcmath implementation:** check first character
|
||||
|
||||
#### BigInteger binaryAnd(ConvertibleToBi $x)
|
||||
Bitwise AND.
|
||||
- **GMP implementation:** gmp_and
|
||||
- **Bcmath implementation:** custom (toBytes + php string and)
|
||||
|
||||
#### BigInteger binaryOr(ConvertibleToBi $x)
|
||||
Bitwise OR
|
||||
- **GMP implementation:** gmp_or
|
||||
- **Bcmath implementation:** custom (toBytes + php string or)
|
||||
|
||||
#### BigInteger binaryXor(ConvertibleToBi $x)
|
||||
Bitwise XOR
|
||||
- **GMP implementation:** gmp_xor
|
||||
- **Bcmath implementation:** custom (toBytes + php string xor)
|
||||
|
||||
#### BigInteger setbit($index, $bitOn = true)
|
||||
Sets bit at given index
|
||||
- **GMP implementation:** gmp_setbit
|
||||
- **Bcmath implementation:** custom (toBits)
|
||||
|
||||
#### bool testbit($index)
|
||||
Tests if a bit at given index is set
|
||||
- **GMP implementation:** gmp_testbit
|
||||
- **Bcmath implementation:** custom (toBits)
|
||||
|
||||
#### int scan0($start)
|
||||
Scans for 0, and returns index of first found bit
|
||||
- **GMP implementation:** gmp_scan0
|
||||
- **Bcmath implementation:** custom (toBits)
|
||||
|
||||
#### int scan1($start)
|
||||
Scans for 1, and returns index of first found bit
|
||||
- **GMP implementation:** gmp_scan1
|
||||
- **Bcmath implementation:** custom (toBits)
|
||||
|
||||
#### int cmp(ConvertibleToBi $x)
|
||||
Compares numbers, returns <0, 0, >0
|
||||
- **GMP implementation:** gmp_cmp
|
||||
- **Bcmath implementation:** bccomp
|
||||
|
||||
#### bool equals(ConvertibleToBi $x)
|
||||
Checks if numbers are equal
|
||||
- **GMP implementation:** gmp_cmp
|
||||
- **Bcmath implementation:** bccomp
|
||||
|
||||
#### int sign()
|
||||
Sign of number, returns -1, 0, 1
|
||||
- **GMP implementation:** gmp_sign
|
||||
- **Bcmath implementation:** check first character
|
||||
|
||||
#### int toNumber()
|
||||
Converts to number (use only with small 32/64bit numbers)
|
||||
- **GMP implementation:** gmp_intval
|
||||
- **Bcmath implementation:** intval
|
||||
|
||||
#### string toDec()
|
||||
Converts to decimal string
|
||||
- **GMP implementation:** gmp_strval
|
||||
- **Bcmath implementation:** just the value
|
||||
|
||||
#### string toHex()
|
||||
Converts to hex string
|
||||
- **GMP implementation:** gmp_strval
|
||||
- **Bcmath implementation:** toBytes + bin2hex
|
||||
|
||||
#### string toBytes
|
||||
Converts to binary string
|
||||
- **GMP implementation:** gmp_strval + hex2bin
|
||||
- **Bcmath implementation:** custom (bcmod + bcdiv + bccomp)
|
||||
|
||||
#### string toBits()
|
||||
Converts to bits string (0 and 1 characters)
|
||||
- **GMP implementation:** gmp_strval
|
||||
- **Bcmath implementation:** toBytes + decbin
|
||||
|
||||
#### string toString(int $base = 10)
|
||||
Converts to string using given base (supported bases 2-62, 256)
|
||||
- **GMP implementation:** all above toX functions, and for non standard gmp_strval
|
||||
- **Bcmath implementation:** all above toX functions, and for non standard bcmod + bcdiv + bccomp
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "simplito/bigint-wrapper-php",
|
||||
"description": "Common interface for php_gmp and php_bcmath modules",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Simplito Team",
|
||||
"email": "s.smyczynski@simplito.com",
|
||||
"homepage": "https://simplito.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BI\\": "lib/"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,635 @@
|
||||
<?php
|
||||
|
||||
namespace BI;
|
||||
|
||||
if (!defined("S_MATH_BIGINTEGER_MODE")) {
|
||||
if (extension_loaded("gmp")) {
|
||||
define("S_MATH_BIGINTEGER_MODE", "gmp");
|
||||
}
|
||||
else if (extension_loaded("bcmath")) {
|
||||
define("S_MATH_BIGINTEGER_MODE", "bcmath");
|
||||
}
|
||||
else {
|
||||
if (!defined("S_MATH_BIGINTEGER_QUIET")) {
|
||||
throw new \Exception("Cannot use BigInteger. Neither gmp nor bcmath module is loaded");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (S_MATH_BIGINTEGER_MODE == "gmp") {
|
||||
|
||||
if (!extension_loaded("gmp")) {
|
||||
throw new \Exception("Extension gmp not loaded");
|
||||
}
|
||||
|
||||
class BigInteger {
|
||||
|
||||
public $value;
|
||||
|
||||
public function __construct($value = 0, $base = 10) {
|
||||
$this->value = $base === true ? $value : BigInteger::getGmp($value, $base);
|
||||
}
|
||||
|
||||
public static function createSafe($value = 0, $base = 10) {
|
||||
try {
|
||||
return new BigInteger($value, $base);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function isGmp($var) {
|
||||
if (is_resource($var)) {
|
||||
return get_resource_type($var) == "GMP integer";
|
||||
}
|
||||
if (class_exists("GMP") && $var instanceof \GMP) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function getGmp($value = 0, $base = 10) {
|
||||
if ($value instanceof BigInteger) {
|
||||
return $value->value;
|
||||
}
|
||||
if (BigInteger::isGmp($value)) {
|
||||
return $value;
|
||||
}
|
||||
$type = gettype($value);
|
||||
if ($type == "integer") {
|
||||
$gmp = gmp_init($value);
|
||||
if ($gmp === false) {
|
||||
throw new \Exception("Cannot initialize");
|
||||
}
|
||||
return $gmp;
|
||||
}
|
||||
if ($type == "string") {
|
||||
if ($base != 2 && $base != 10 && $base != 16 && $base != 256) {
|
||||
throw new \Exception("Unsupported BigInteger base");
|
||||
}
|
||||
if ($base == 256) {
|
||||
$value = bin2hex($value);
|
||||
$base = 16;
|
||||
}
|
||||
$level = error_reporting();
|
||||
error_reporting(0);
|
||||
$gmp = gmp_init($value, $base);
|
||||
error_reporting($level);
|
||||
if ($gmp === false) {
|
||||
throw new \Exception("Cannot initialize");
|
||||
}
|
||||
return $gmp;
|
||||
}
|
||||
throw new \Exception("Unsupported value, only string and integer are allowed, receive " . $type . ($type == "object" ? ", class: " . get_class($value) : ""));
|
||||
}
|
||||
|
||||
public function toDec() {
|
||||
return gmp_strval($this->value, 10);
|
||||
}
|
||||
|
||||
public function toHex() {
|
||||
$hex = gmp_strval($this->value, 16);
|
||||
return strlen($hex) % 2 == 1 ? "0". $hex : $hex;
|
||||
}
|
||||
|
||||
public function toBytes() {
|
||||
return hex2bin($this->toHex());
|
||||
}
|
||||
|
||||
public function toBase($base) {
|
||||
if ($base < 2 || $base > 62) {
|
||||
throw new \Exception("Invalid base");
|
||||
}
|
||||
return gmp_strval($this->value, $base);
|
||||
}
|
||||
|
||||
public function toBits() {
|
||||
return gmp_strval($this->value, 2);
|
||||
}
|
||||
|
||||
public function toString($base = 10) {
|
||||
if ($base == 2) {
|
||||
return $this->toBits();
|
||||
}
|
||||
if ($base == 10) {
|
||||
return $this->toDec();
|
||||
}
|
||||
if ($base == 16) {
|
||||
return $this->toHex();
|
||||
}
|
||||
if ($base == 256) {
|
||||
return $this->toBytes();
|
||||
}
|
||||
return $this->toBase($base);
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return $this->toString();
|
||||
}
|
||||
|
||||
public function toNumber() {
|
||||
return gmp_intval($this->value);
|
||||
}
|
||||
|
||||
public function add($x) {
|
||||
return new BigInteger(gmp_add($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function sub($x) {
|
||||
return new BigInteger(gmp_sub($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function mul($x) {
|
||||
return new BigInteger(gmp_mul($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function div($x) {
|
||||
return new BigInteger(gmp_div_q($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function divR($x) {
|
||||
return new BigInteger(gmp_div_r($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function divQR($x) {
|
||||
$res = gmp_div_qr($this->value, BigInteger::getGmp($x));
|
||||
return array(new BigInteger($res[0], true), new BigInteger($res[1], true));
|
||||
}
|
||||
|
||||
public function mod($x) {
|
||||
return new BigInteger(gmp_mod($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function gcd($x) {
|
||||
return new BigInteger(gmp_gcd($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function modInverse($x) {
|
||||
$res = gmp_invert($this->value, BigInteger::getGmp($x));
|
||||
return $res === false ? false : new BigInteger($res, true);
|
||||
}
|
||||
|
||||
public function pow($x) {
|
||||
return new BigInteger(gmp_pow($this->value, (new BigInteger($x))->toNumber()), true);
|
||||
}
|
||||
|
||||
public function powMod($x, $n) {
|
||||
return new BigInteger(gmp_powm($this->value, BigInteger::getGmp($x), BigInteger::getGmp($n)), true);
|
||||
}
|
||||
|
||||
public function abs() {
|
||||
return new BigInteger(gmp_abs($this->value), true);
|
||||
}
|
||||
|
||||
public function neg() {
|
||||
return new BigInteger(gmp_neg($this->value), true);
|
||||
}
|
||||
|
||||
public function binaryAnd($x) {
|
||||
return new BigInteger(gmp_and($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function binaryOr($x) {
|
||||
return new BigInteger(gmp_or($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function binaryXor($x) {
|
||||
return new BigInteger(gmp_xor($this->value, BigInteger::getGmp($x)), true);
|
||||
}
|
||||
|
||||
public function setbit($index, $bitOn = true) {
|
||||
$cpy = gmp_init(gmp_strval($this->value, 16), 16);
|
||||
gmp_setbit($cpy, $index, $bitOn);
|
||||
return new BigInteger($cpy, true);
|
||||
}
|
||||
|
||||
public function testbit($index) {
|
||||
return gmp_testbit($this->value, $index);
|
||||
}
|
||||
|
||||
public function scan0($start) {
|
||||
return gmp_scan0($this->value, $start);
|
||||
}
|
||||
|
||||
public function scan1($start) {
|
||||
return gmp_scan1($this->value, $start);
|
||||
}
|
||||
|
||||
public function cmp($x) {
|
||||
return gmp_cmp($this->value, BigInteger::getGmp($x));
|
||||
}
|
||||
|
||||
public function equals($x) {
|
||||
return $this->cmp($x) === 0;
|
||||
}
|
||||
|
||||
public function sign() {
|
||||
return gmp_sign($this->value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (S_MATH_BIGINTEGER_MODE == "bcmath") {
|
||||
|
||||
if (!extension_loaded("bcmath")) {
|
||||
throw new \Exception("Extension bcmath not loaded");
|
||||
}
|
||||
|
||||
class BigInteger{
|
||||
|
||||
public static $chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv";
|
||||
public $value;
|
||||
|
||||
public function __construct($value = 0, $base = 10) {
|
||||
$this->value = $base === true ? $value : BigInteger::getBC($value, $base);
|
||||
}
|
||||
|
||||
public static function createSafe($value = 0, $base = 10) {
|
||||
try {
|
||||
return new BigInteger($value, $base);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function checkBinary($str) {
|
||||
$len = strlen($str);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$c = ord($str[$i]);
|
||||
if (($i != 0 || $c != 45) && ($c < 48 || $c > 49)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function checkDecimal($str) {
|
||||
$len = strlen($str);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$c = ord($str[$i]);
|
||||
if (($i != 0 || $c != 45) && ($c < 48 || $c > 57)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function checkHex($str) {
|
||||
$len = strlen($str);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$c = ord($str[$i]);
|
||||
if (($i != 0 || $c != 45) && ($c < 48 || $c > 57) && ($c < 65 || $c > 70) && ($c < 97 || $c > 102)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getBC($value = 0, $base = 10) {
|
||||
if ($value instanceof BigInteger) {
|
||||
return $value->value;
|
||||
}
|
||||
$type = gettype($value);
|
||||
if ($type == "integer") {
|
||||
return strval($value);
|
||||
}
|
||||
if ($type == "string") {
|
||||
if ($base == 2) {
|
||||
$value = str_replace(" ", "", $value);
|
||||
if (!BigInteger::checkBinary($value)) {
|
||||
throw new \Exception("Invalid characters");
|
||||
}
|
||||
$minus = $value[0] == "-";
|
||||
if ($minus) {
|
||||
$value = substr($value, 1);
|
||||
}
|
||||
$len = strlen($value);
|
||||
$m = 1;
|
||||
$res = "0";
|
||||
for ($i = $len - 1; $i >= 0; $i -= 8) {
|
||||
$h = $i - 7 < 0 ? substr($value, 0, $i + 1) : substr($value, $i - 7, 8);
|
||||
$res = bcadd($res, bcmul(bindec($h), $m, 0), 0);
|
||||
$m = bcmul($m, "256", 0);
|
||||
}
|
||||
return ($minus ? "-" : "") . $res;
|
||||
}
|
||||
if ($base == 10) {
|
||||
$value = str_replace(" ", "", $value);
|
||||
if (!BigInteger::checkDecimal($value)) {
|
||||
throw new \Exception("Invalid characters");
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
if ($base == 16) {
|
||||
$value = str_replace(" ", "", $value);
|
||||
if (!BigInteger::checkHex($value)) {
|
||||
throw new \Exception("Invalid characters");
|
||||
}
|
||||
$minus = $value[0] == "-";
|
||||
if ($minus) {
|
||||
$value = substr($value, 1);
|
||||
}
|
||||
$len = strlen($value);
|
||||
$m = 1;
|
||||
$res = "0";
|
||||
for ($i = $len - 1; $i >= 0; $i -= 2) {
|
||||
$h = $i == 0 ? "0" . substr($value, 0, 1) : substr($value, $i - 1, 2);
|
||||
$res = bcadd($res, bcmul(hexdec($h), $m, 0), 0);
|
||||
$m = bcmul($m, "256", 0);
|
||||
}
|
||||
return ($minus ? "-" : "") . $res;
|
||||
}
|
||||
if ($base == 256) {
|
||||
$len = strlen($value);
|
||||
$m = 1;
|
||||
$res = "0";
|
||||
for ($i = $len - 1; $i >= 0; $i -= 6) {
|
||||
$h = $i - 5 < 0 ? substr($value, 0, $i + 1) : substr($value, $i - 5, 6);
|
||||
$res = bcadd($res, bcmul(base_convert(bin2hex($h), 16, 10), $m, 0), 0);
|
||||
$m = bcmul($m, "281474976710656", 0);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
throw new \Exception("Unsupported BigInteger base");
|
||||
}
|
||||
throw new \Exception("Unsupported value, only string and integer are allowed, receive " . $type . ($type == "object" ? ", class: " . get_class($value) : ""));
|
||||
}
|
||||
|
||||
public function toDec() {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function toHex() {
|
||||
return bin2hex($this->toBytes());
|
||||
}
|
||||
|
||||
public function toBytes() {
|
||||
$value = "";
|
||||
$current = $this->value;
|
||||
if ($current[0] == "-") {
|
||||
$current = substr($current, 1);
|
||||
}
|
||||
while (bccomp($current, "0", 0) > 0) {
|
||||
$temp = bcmod($current, "281474976710656");
|
||||
$value = hex2bin(str_pad(base_convert($temp, 10, 16), 12, "0", STR_PAD_LEFT)) . $value;
|
||||
$current = bcdiv($current, "281474976710656", 0);
|
||||
}
|
||||
return ltrim($value, chr(0));
|
||||
}
|
||||
|
||||
public function toBase($base) {
|
||||
if ($base < 2 || $base > 62) {
|
||||
throw new \Exception("Invalid base");
|
||||
}
|
||||
$value = '';
|
||||
$current = $this->value;
|
||||
$base = BigInteger::getBC($base);
|
||||
|
||||
if ($current[0] == '-') {
|
||||
$current = substr($current, 1);
|
||||
}
|
||||
|
||||
while (bccomp($current, '0', 0) > 0) {
|
||||
$v = bcmod($current, $base);
|
||||
$value = BigInteger::$chars[$v] . $value;
|
||||
$current = bcdiv($current, $base, 0);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function toBits() {
|
||||
$bytes = $this->toBytes();
|
||||
$res = "";
|
||||
$len = strlen($bytes);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$b = decbin(ord($bytes[$i]));
|
||||
$res .= strlen($b) != 8 ? str_pad($b, 8, "0", STR_PAD_LEFT) : $b;
|
||||
}
|
||||
$res = ltrim($res, "0");
|
||||
return strlen($res) == 0 ? "0" : $res;
|
||||
}
|
||||
|
||||
public function toString($base = 10) {
|
||||
if ($base == 2) {
|
||||
return $this->toBits();
|
||||
}
|
||||
if ($base == 10) {
|
||||
return $this->toDec();
|
||||
}
|
||||
if ($base == 16) {
|
||||
return $this->toHex();
|
||||
}
|
||||
if ($base == 256) {
|
||||
return $this->toBytes();
|
||||
}
|
||||
return $this->toBase($base);
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return $this->toString();
|
||||
}
|
||||
|
||||
public function toNumber() {
|
||||
return intval($this->value);
|
||||
}
|
||||
|
||||
public function add($x) {
|
||||
return new BigInteger(bcadd($this->value, BigInteger::getBC($x), 0), true);
|
||||
}
|
||||
|
||||
public function sub($x) {
|
||||
return new BigInteger(bcsub($this->value, BigInteger::getBC($x), 0), true);
|
||||
}
|
||||
|
||||
public function mul($x) {
|
||||
return new BigInteger(bcmul($this->value, BigInteger::getBC($x), 0), true);
|
||||
}
|
||||
|
||||
public function div($x) {
|
||||
return new BigInteger(bcdiv($this->value, BigInteger::getBC($x), 0), true);
|
||||
}
|
||||
|
||||
public function divR($x) {
|
||||
return new BigInteger(bcmod($this->value, BigInteger::getBC($x)), true);
|
||||
}
|
||||
|
||||
public function divQR($x) {
|
||||
return array(
|
||||
$this->div($x),
|
||||
$this->divR($x)
|
||||
);
|
||||
}
|
||||
|
||||
public function mod($x) {
|
||||
$xv = BigInteger::getBC($x);
|
||||
$mod = bcmod($this->value, $xv);
|
||||
if ($mod[0] == "-") {
|
||||
$mod = bcadd($mod, $xv[0] == "-" ? substr($xv, 1) : $xv, 0);
|
||||
}
|
||||
return new BigInteger($mod, true);
|
||||
}
|
||||
|
||||
public function extendedGcd($n) {
|
||||
$u = $this->value;
|
||||
$v = (new BigInteger($n))->abs()->value;
|
||||
|
||||
$a = "1";
|
||||
$b = "0";
|
||||
$c = "0";
|
||||
$d = "1";
|
||||
|
||||
while (bccomp($v, "0", 0) != 0) {
|
||||
$q = bcdiv($u, $v, 0);
|
||||
|
||||
$temp = $u;
|
||||
$u = $v;
|
||||
$v = bcsub($temp, bcmul($v, $q, 0), 0);
|
||||
|
||||
$temp = $a;
|
||||
$a = $c;
|
||||
$c = bcsub($temp, bcmul($a, $q, 0), 0);
|
||||
|
||||
$temp = $b;
|
||||
$b = $d;
|
||||
$d = bcsub($temp, bcmul($b, $q, 0), 0);
|
||||
}
|
||||
|
||||
return array(
|
||||
"gcd" => new BigInteger($u, true),
|
||||
"x" => new BigInteger($a, true),
|
||||
"y" => new BigInteger($b, true)
|
||||
);
|
||||
}
|
||||
|
||||
public function gcd($x) {
|
||||
return $this->extendedGcd($x)["gcd"];
|
||||
}
|
||||
|
||||
public function modInverse($n) {
|
||||
$n = (new BigInteger($n))->abs();
|
||||
|
||||
if ($this->sign() < 0) {
|
||||
$temp = $this->abs();
|
||||
$temp = $temp->modInverse($n);
|
||||
return $n->sub($temp);
|
||||
}
|
||||
|
||||
extract($this->extendedGcd($n));
|
||||
|
||||
if (!$gcd->equals(1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$x = $x->sign() < 0 ? $x->add($n) : $x;
|
||||
|
||||
return $this->sign() < 0 ? $n->sub($x) : $x;
|
||||
}
|
||||
|
||||
public function pow($x) {
|
||||
return new BigInteger(bcpow($this->value, BigInteger::getBC($x), 0), true);
|
||||
}
|
||||
|
||||
public function powMod($x, $n) {
|
||||
return new BigInteger(bcpowmod($this->value, BigInteger::getBC($x), BigInteger::getBC($n), 0), true);
|
||||
}
|
||||
|
||||
public function abs() {
|
||||
return new BigInteger($this->value[0] == "-" ? substr($this->value, 1) : $this->value, true);
|
||||
}
|
||||
|
||||
public function neg() {
|
||||
return new BigInteger($this->value[0] == "-" ? substr($this->value, 1) : "-" . $this->value, true);
|
||||
}
|
||||
|
||||
public function binaryAnd($x) {
|
||||
$left = $this->toBytes();
|
||||
$right = (new BigInteger($x))->toBytes();
|
||||
|
||||
$length = max(strlen($left), strlen($right));
|
||||
|
||||
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
|
||||
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
|
||||
|
||||
return new BigInteger($left & $right, 256);
|
||||
}
|
||||
|
||||
public function binaryOr($x) {
|
||||
$left = $this->toBytes();
|
||||
$right = (new BigInteger($x))->toBytes();
|
||||
|
||||
$length = max(strlen($left), strlen($right));
|
||||
|
||||
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
|
||||
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
|
||||
|
||||
return new BigInteger($left | $right, 256);
|
||||
}
|
||||
|
||||
public function binaryXor($x) {
|
||||
$left = $this->toBytes();
|
||||
$right = (new BigInteger($x))->toBytes();
|
||||
|
||||
$length = max(strlen($left), strlen($right));
|
||||
|
||||
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
|
||||
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
|
||||
|
||||
return new BigInteger($left ^ $right, 256);
|
||||
}
|
||||
|
||||
public function setbit($index, $bitOn = true) {
|
||||
$bits = $this->toBits();
|
||||
$bits[strlen($bits) - $index - 1] = $bitOn ? "1" : "0";
|
||||
return new BigInteger($bits, 2);
|
||||
}
|
||||
|
||||
public function testbit($index) {
|
||||
$bytes = $this->toBytes();
|
||||
$bytesIndex = intval($index / 8);
|
||||
$len = strlen($bytes);
|
||||
$b = $bytesIndex >= $len ? 0 : ord($bytes[$len - $bytesIndex - 1]);
|
||||
$v = 1 << ($index % 8);
|
||||
return ($b & $v) === $v;
|
||||
}
|
||||
|
||||
public function scan0($start) {
|
||||
$bits = $this->toBits();
|
||||
$len = strlen($bits);
|
||||
if ($start < 0 || $start >= $len) {
|
||||
return -1;
|
||||
}
|
||||
$pos = strrpos($bits, "0", -1 - $start);
|
||||
return $pos === false ? -1 : $len - $pos - 1;
|
||||
}
|
||||
|
||||
public function scan1($start) {
|
||||
$bits = $this->toBits();
|
||||
$len = strlen($bits);
|
||||
if ($start < 0 || $start >= $len) {
|
||||
return -1;
|
||||
}
|
||||
$pos = strrpos($bits, "1", -1 - $start);
|
||||
return $pos === false ? -1 : $len - $pos - 1;
|
||||
}
|
||||
|
||||
public function cmp($x) {
|
||||
return bccomp($this->value, BigInteger::getBC($x));
|
||||
}
|
||||
|
||||
public function equals($x) {
|
||||
return $this->value === BigInteger::getBC($x);
|
||||
}
|
||||
|
||||
public function sign() {
|
||||
return $this->value[0] === "-" ? -1 : ($this->value === "0" ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
if (!defined("S_MATH_BIGINTEGER_QUIET")) {
|
||||
throw new \Exception("Unsupported S_MATH_BIGINTEGER_MODE " . S_MATH_BIGINTEGER_MODE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
define('S_MATH_BIGINTEGER_MODE', "bcmath");
|
||||
|
||||
require(__DIR__ . "/../lib/BigInteger.php");
|
||||
|
||||
use BI\BigInteger;
|
||||
|
||||
$a = new BigInteger("4547395333333333333333333333333333333333333343587493875493579375498759837593574935739857");
|
||||
$b = new BigInteger("-4547395333333333333333333333333333333333333343587493875493579375498759837593574935739857");
|
||||
$c = new BigInteger("0");
|
||||
$hex = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3";
|
||||
$bytes = hex2bin($hex);
|
||||
|
||||
function test($v, $b) {
|
||||
$start = microtime(true);
|
||||
$count = 10000;
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$v->binaryAnd($b);
|
||||
//$v->toBytes();
|
||||
//BigInteger::getBC($v, 256);
|
||||
}
|
||||
$end = microtime(true);
|
||||
error_log($end - $start);
|
||||
}
|
||||
|
||||
test($a, $a);
|
||||
test($b, $b);
|
||||
//test($bytes, $b);
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
use BI\BigInteger;
|
||||
|
||||
function test($a, $b, $message = "") {
|
||||
error_log(($a === $b ? "PASS" : "FAIL get: " . $a . ", expected: " . $b) . " " . $message);
|
||||
}
|
||||
|
||||
function testB($a, $b, $message = "") {
|
||||
error_log(($a->toString() === $b ? "PASS" : "FAIL get: " . $a . ", expected: " . $b) . " " . $message);
|
||||
}
|
||||
|
||||
function testSerialization($b, $msg = "") {
|
||||
test($b->toBits(), "1010000", $msg . " toBits");
|
||||
test($b->toBytes(), hex2bin("50"), $msg . " toBytes");
|
||||
test($b->toHex(), "50", $msg . " toHex");
|
||||
test($b->toDec(), "80", $msg . " toDec");
|
||||
test($b->toNumber(), 80, $msg . " toNumber");
|
||||
test($b->toBase(58), "1M", $msg . " to58");
|
||||
}
|
||||
|
||||
function testCreate() {
|
||||
error_log("=============\nTest serialization\n=============");
|
||||
testSerialization(new BigInteger("1010000", 2), "bits");
|
||||
testSerialization(new BigInteger(hex2bin("50"), 256), "bytes");
|
||||
testSerialization(new BigInteger("50", 16), "hex");
|
||||
testSerialization(new BigInteger("80", 10), "dec");
|
||||
testSerialization(new BigInteger("80"), "dec2");
|
||||
testSerialization(new BigInteger(80), "number");
|
||||
}
|
||||
|
||||
function testCreateSafeSingle($value, $base, $msg) {
|
||||
try {
|
||||
$z = new BigInteger($value, $base);
|
||||
error_log("FAIL exception during create " . $msg);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
error_log("PASS exception during create " . $msg);
|
||||
}
|
||||
test(BigInteger::createSafe($value, $base), false, "createSafe " . $msg);
|
||||
}
|
||||
|
||||
function testCreateSafe() {
|
||||
error_log("=============\nTest create safe\n=============");
|
||||
testCreateSafeSingle("zz", 2, "bin");
|
||||
testCreateSafeSingle("zz", 10, "dec");
|
||||
testCreateSafeSingle("zz", 16, "hex");
|
||||
}
|
||||
|
||||
function testSpaces() {
|
||||
error_log("=============\nTest spaces\n=============");
|
||||
test((new BigInteger("11 0 1", 2))->toBits(), "1101", "bin");
|
||||
test((new BigInteger("6 2 0 6", 10))->toDec(), "6206", "dec");
|
||||
test((new BigInteger("f3 5 12 ac 0", 16))->toHex(), "f3512ac0", "hex");
|
||||
}
|
||||
|
||||
function testOp() {
|
||||
error_log("=============\nTest op\n=============");
|
||||
testB((new BigInteger(20))->add(34), "54", "add");
|
||||
testB((new BigInteger(20))->sub(14), "6", "sub");
|
||||
testB((new BigInteger(20))->mul(12), "240", "mul");
|
||||
testB((new BigInteger(20))->div(4), "5", "div");
|
||||
testB((new BigInteger(20))->divR(7), "6", "divR");
|
||||
$qr = (new BigInteger(20))->divQR(6);
|
||||
testB($qr[0], "3", "divQR[0]");
|
||||
testB($qr[1], "2", "divQR[1]");
|
||||
testB((new BigInteger(20))->mod(3), "2", "mod");
|
||||
testB((new BigInteger(54))->gcd(81), "27", "gcd");
|
||||
testB((new BigInteger(3))->modInverse(10), "7", "modInverse");
|
||||
testB((new BigInteger(3))->pow(4), "81", "pow");
|
||||
testB((new BigInteger(3))->powMod(4, 10), "1", "powMod");
|
||||
testB((new BigInteger(20))->abs(), "20", "abs");
|
||||
testB((new BigInteger(20))->neg(), "-20", "neg");
|
||||
testB((new BigInteger(20))->binaryAnd(18), "16", "binaryAnd");
|
||||
testB((new BigInteger(20))->binaryOr(18), "22", "binaryOr");
|
||||
testB((new BigInteger(20))->binaryXor(18), "6", "binaryXor");
|
||||
testB((new BigInteger(20))->setbit(3), "28", "setbit");
|
||||
test((new BigInteger(20))->testbit(4), true, "testbit true");
|
||||
test((new BigInteger(20))->testbit(3), false, "testbit false");
|
||||
test((new BigInteger(5))->testbit(0), true, "testbit 0 true");
|
||||
test((new BigInteger(6))->testbit(0), false, "testbit 0 false");
|
||||
test((new BigInteger(6))->testbit(1), true, "testbit 1 true");
|
||||
test((new BigInteger(5))->testbit(1), false, "testbit 1 false");
|
||||
test((new BigInteger(132))->testbit(7), true, "testbit 7 true");
|
||||
test((new BigInteger(81))->testbit(7), false, "testbit 7 false");
|
||||
test((new BigInteger(258))->testbit(8), true, "testbit 8 true");
|
||||
test((new BigInteger(253))->testbit(8), false, "testbit 8 false");
|
||||
test((new BigInteger(20))->scan0(2), 3, "scan0");
|
||||
test((new BigInteger(20))->scan1(3), 4, "scan1");
|
||||
test((new BigInteger(20))->cmp(22), -1, "cmp -1");
|
||||
test((new BigInteger(20))->cmp(20), 0, "cmp 0");
|
||||
test((new BigInteger(20))->cmp(18), 1, "cmp 1");
|
||||
test((new BigInteger(20))->equals(20), true, "equals true");
|
||||
test((new BigInteger(20))->equals(21), false, "equals false");
|
||||
test((new BigInteger(-20))->sign(), -1, "sign -1");
|
||||
test((new BigInteger(0))->sign(), 0, "sign 0");
|
||||
test((new BigInteger(20))->sign(), 1, "sign 1");
|
||||
testB(new BigInteger("-20"), "-20", "minus");
|
||||
testB(new BigInteger("-14", 16), "-20", "minus");
|
||||
testB(new BigInteger("-10100", 2), "-20", "minus");
|
||||
}
|
||||
|
||||
function testBig() {
|
||||
error_log("=============\nTest big\n=============");
|
||||
$bits = "1001010111010010100001000101110110100001000101101000110101010101001";
|
||||
$hex = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3";
|
||||
$dec = "436529472098746319073192837123683467019263172846";
|
||||
$bytes = hex2bin($hex);
|
||||
test((new BigInteger($bits, 2))->toBits(), $bits, "init big from binary");
|
||||
test((new BigInteger($dec, 10))->toDec(), $dec, "init big from dec");
|
||||
test((new BigInteger($hex, 16))->toHex(), $hex, "init big from hex");
|
||||
test((new BigInteger($bytes, 256))->toBytes(), $bytes, "init big from buffer");
|
||||
}
|
||||
|
||||
testCreate();
|
||||
testCreateSafe();
|
||||
testSpaces();
|
||||
testOp();
|
||||
testBig();
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
define('S_MATH_BIGINTEGER_MODE', "bcmath");
|
||||
|
||||
require(__DIR__ . "/../lib/BigInteger.php");
|
||||
require(__DIR__ . "/test.php");
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
define('S_MATH_BIGINTEGER_MODE', "gmp");
|
||||
|
||||
require(__DIR__ . "/../lib/BigInteger.php");
|
||||
require(__DIR__ . "/test.php");
|
||||
@@ -0,0 +1,4 @@
|
||||
/vendor/
|
||||
.settings
|
||||
.project
|
||||
.buildpath
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
|
||||
## MIT LICENSE
|
||||
|
||||
Copyright (C) 2018 Simplito
|
||||
|
||||
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.
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
|
||||
# BigNum library for PHP
|
||||
|
||||
|
||||
## Information
|
||||
|
||||
This library provides a PHP Big Number API compatible with [bn.js](https://github.com/indutny/bn.js) and is used in Fast PHP ECC library [elliptic-php](https://github.com/simplito/elliptic-php).
|
||||
|
||||
This software is licensed under the MIT License.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
You can install this library via Composer:
|
||||
```
|
||||
composer require simplito/bn-php
|
||||
```
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "simplito/bn-php",
|
||||
"description": "Big number implementation compatible with bn.js",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Simplito Team",
|
||||
"email": "s.smyczynski@simplito.com",
|
||||
"homepage": "https://simplito.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"simplito/bigint-wrapper-php": "~1.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BN\\": "lib/"
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+768
@@ -0,0 +1,768 @@
|
||||
<?php
|
||||
namespace BN;
|
||||
|
||||
use \JsonSerializable;
|
||||
use \Exception;
|
||||
use \BI\BigInteger;
|
||||
|
||||
class BN implements JsonSerializable
|
||||
{
|
||||
public static $ASSERT_ENABLED;
|
||||
public $bi;
|
||||
public $red;
|
||||
|
||||
function __construct($number, $base = 10, $endian = null)
|
||||
{
|
||||
if( $number instanceof BN ) {
|
||||
$this->bi = $number->bi;
|
||||
$this->red = $number->red;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reduction context
|
||||
$this->red = null;
|
||||
|
||||
if ( $number instanceof BigInteger ) {
|
||||
$this->bi = $number;
|
||||
return;
|
||||
}
|
||||
|
||||
if( is_array($number) )
|
||||
{
|
||||
$number = call_user_func_array("pack", array_merge(array("C*"), $number));
|
||||
$number = bin2hex($number);
|
||||
$base = 16;
|
||||
}
|
||||
|
||||
if( $base == "hex" )
|
||||
$base = 16;
|
||||
|
||||
if ($endian == 'le') {
|
||||
if ($base != 16)
|
||||
throw new \Exception("Not implemented");
|
||||
$number = bin2hex(strrev(hex2bin($number)));
|
||||
}
|
||||
|
||||
$this->bi = new BigInteger($number, $base);
|
||||
}
|
||||
|
||||
public function negative() {
|
||||
return $this->bi->sign() < 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
public static function isBN($num) {
|
||||
return ($num instanceof BN);
|
||||
}
|
||||
|
||||
public static function max($left, $right) {
|
||||
return ( $left->cmp($right) > 0 ) ? $left : $right;
|
||||
}
|
||||
|
||||
public static function min($left, $right) {
|
||||
return ( $left->cmp($right) < 0 ) ? $left : $right;
|
||||
}
|
||||
|
||||
public function copy($dest)
|
||||
{
|
||||
$dest->bi = $this->bi;
|
||||
$dest->red = $this->red;
|
||||
}
|
||||
|
||||
public function _clone() {
|
||||
return clone($this);
|
||||
}
|
||||
|
||||
public function toString($base = 10, $padding = 0)
|
||||
{
|
||||
if( $base == "hex" )
|
||||
$base = 16;
|
||||
$str = $this->bi->abs()->toString($base);
|
||||
if ($padding > 0) {
|
||||
$len = strlen($str);
|
||||
$mod = $len % $padding;
|
||||
if ($mod > 0)
|
||||
$len = $len + $padding - $mod;
|
||||
$str = str_pad($str, $len, "0", STR_PAD_LEFT);
|
||||
}
|
||||
if( $this->negative() )
|
||||
return "-" . $str;
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function toNumber() {
|
||||
return $this->bi->toNumber();
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize() {
|
||||
return $this->toString(16);
|
||||
}
|
||||
|
||||
public function toArray($endian = "be", $length = -1)
|
||||
{
|
||||
$hex = $this->toString(16);
|
||||
if( $hex[0] === "-" )
|
||||
$hex = substr($hex, 1);
|
||||
|
||||
if( strlen($hex) % 2 )
|
||||
$hex = "0" . $hex;
|
||||
|
||||
$bytes = array_map(
|
||||
function($v) { return hexdec($v); },
|
||||
str_split($hex, 2)
|
||||
);
|
||||
|
||||
if( $length > 0 )
|
||||
{
|
||||
$count = count($bytes);
|
||||
if( $count > $length )
|
||||
throw new Exception("Byte array longer than desired length");
|
||||
|
||||
for($i = $count; $i < $length; $i++)
|
||||
array_unshift($bytes, 0);
|
||||
}
|
||||
|
||||
if( $endian === "le" )
|
||||
$bytes = array_reverse($bytes);
|
||||
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
public function bitLength() {
|
||||
$bin = $this->toString(2);
|
||||
return strlen($bin) - ( $bin[0] === "-" ? 1 : 0 );
|
||||
}
|
||||
|
||||
public function zeroBits() {
|
||||
return $this->bi->scan1(0);
|
||||
}
|
||||
|
||||
public function byteLength() {
|
||||
return ceil($this->bitLength() / 8);
|
||||
}
|
||||
|
||||
//TODO toTwos, fromTwos
|
||||
|
||||
public function isNeg() {
|
||||
return $this->negative() !== 0;
|
||||
}
|
||||
|
||||
// Return negative clone of `this`
|
||||
public function neg() {
|
||||
return $this->_clone()->ineg();
|
||||
}
|
||||
|
||||
public function ineg() {
|
||||
$this->bi = $this->bi->neg();
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Or `num` with `this` in-place
|
||||
public function iuor(BN $num) {
|
||||
$this->bi = $this->bi->binaryOr($num->bi);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ior(BN $num) {
|
||||
if (BN::$ASSERT_ENABLED) assert(!$this->negative() && !$num->negative());
|
||||
return $this->iuor($num);
|
||||
}
|
||||
|
||||
// Or `num` with `this`
|
||||
public function _or(BN $num) {
|
||||
if( $this->ucmp($num) > 0 )
|
||||
return $this->_clone()->ior($num);
|
||||
return $num->_clone()->ior($this);
|
||||
}
|
||||
|
||||
public function uor(BN $num) {
|
||||
if( $this->ucmp($num) > 0 )
|
||||
return $this->_clone()->iuor($num);
|
||||
return $num->_clone()->ior($this);
|
||||
}
|
||||
|
||||
// And `num` with `this` in-place
|
||||
public function iuand(BN $num) {
|
||||
$this->bi = $this->bi->binaryAnd($num->bi);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function iand(BN $num) {
|
||||
if (BN::$ASSERT_ENABLED) assert(!$this->negative() && !$num->negative());
|
||||
return $this->iuand($num);
|
||||
}
|
||||
|
||||
// And `num` with `this`
|
||||
public function _and(BN $num) {
|
||||
if( $this->ucmp($num) > 0 )
|
||||
return $this->_clone()->iand($num);
|
||||
return $num->_clone()->iand($this);
|
||||
}
|
||||
|
||||
public function uand(BN $num) {
|
||||
if( $this->ucmp($num) > 0 )
|
||||
return $this->_clone()->iuand($num);
|
||||
return $num->_clone()->iuand($this);
|
||||
}
|
||||
|
||||
// Xor `num` with `this` in-place
|
||||
public function iuxor(BN $num) {
|
||||
$this->bi = $this->bi->binaryXor($num->bi);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ixor(BN $num) {
|
||||
if (BN::$ASSERT_ENABLED) assert(!$this->negative() && !$num->negative());
|
||||
return $this->iuxor($num);
|
||||
}
|
||||
|
||||
// Xor `num` with `this`
|
||||
public function _xor(BN $num) {
|
||||
if( $this->ucmp($num) > 0 )
|
||||
return $this->_clone()->ixor($num);
|
||||
return $num->_clone()->ixor($this);
|
||||
}
|
||||
|
||||
public function uxor(BN $num) {
|
||||
if( $this->ucmp($num) > 0 )
|
||||
return $this->_clone()->iuxor($num);
|
||||
return $num->_clone()->iuxor($this);
|
||||
}
|
||||
|
||||
// Not ``this`` with ``width`` bitwidth
|
||||
public function inotn($width)
|
||||
{
|
||||
assert(is_integer($width) && $width >= 0);
|
||||
$neg = false;
|
||||
if( $this->isNeg() )
|
||||
{
|
||||
$this->negi();
|
||||
$neg = true;
|
||||
}
|
||||
|
||||
for($i = 0; $i < $width; $i++)
|
||||
$this->bi = $this->bi->setbit($i, !$this->bi->testbit($i));
|
||||
|
||||
return $neg ? $this->negi() : $this;
|
||||
}
|
||||
|
||||
public function notn($width) {
|
||||
return $this->_clone()->inotn($width);
|
||||
}
|
||||
|
||||
// Set `bit` of `this`
|
||||
public function setn($bit, $val) {
|
||||
assert(is_integer($bit) && $bit > 0);
|
||||
$this->bi = $this->bi->setbit($bit, !!$val);
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Add `num` to `this` in-place
|
||||
public function iadd(BN $num) {
|
||||
$this->bi = $this->bi->add($num->bi);
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Add `num` to `this`
|
||||
public function add(BN $num) {
|
||||
return $this->_clone()->iadd($num);
|
||||
}
|
||||
|
||||
// Subtract `num` from `this` in-place
|
||||
public function isub(BN $num) {
|
||||
$this->bi = $this->bi->sub($num->bi);
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Subtract `num` from `this`
|
||||
public function sub(BN $num) {
|
||||
return $this->_clone()->isub($num);
|
||||
}
|
||||
|
||||
// Multiply `this` by `num`
|
||||
public function mul(BN $num) {
|
||||
return $this->_clone()->imul($num);
|
||||
}
|
||||
|
||||
// In-place Multiplication
|
||||
public function imul(BN $num) {
|
||||
$this->bi = $this->bi->mul($num->bi);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function imuln($num)
|
||||
{
|
||||
assert(is_numeric($num));
|
||||
$int = intval($num);
|
||||
$res = $this->bi->mul($int);
|
||||
|
||||
if( ($num - $int) > 0 )
|
||||
{
|
||||
$mul = 10;
|
||||
$frac = ($num - $int) * $mul;
|
||||
$int = intval($frac);
|
||||
while( ($frac - $int) > 0 )
|
||||
{
|
||||
$mul *= 10;
|
||||
$frac *= 10;
|
||||
$int = intval($frac);
|
||||
}
|
||||
|
||||
$tmp = $this->bi->mul($int);
|
||||
$tmp = $tmp->div($mul);
|
||||
$res = $res->add($tmp);
|
||||
}
|
||||
|
||||
$this->bi = $res;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function muln($num) {
|
||||
return $this->_clone()->imuln($num);
|
||||
}
|
||||
|
||||
// `this` * `this`
|
||||
public function sqr() {
|
||||
return $this->mul($this);
|
||||
}
|
||||
|
||||
// `this` * `this` in-place
|
||||
public function isqr() {
|
||||
return $this->imul($this);
|
||||
}
|
||||
|
||||
// Math.pow(`this`, `num`)
|
||||
public function pow(BN $num) {
|
||||
$res = clone($this);
|
||||
$res->bi = $res->bi->pow($num->bi);
|
||||
return $res;
|
||||
}
|
||||
|
||||
// Shift-left in-place
|
||||
public function iushln($bits) {
|
||||
assert(is_integer($bits) && $bits >= 0);
|
||||
if ($bits < 54) {
|
||||
$this->bi = $this->bi->mul(1 << $bits);
|
||||
} else {
|
||||
$this->bi = $this->bi->mul((new BigInteger(2))->pow($bits));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ishln($bits) {
|
||||
if (BN::$ASSERT_ENABLED) assert(!$this->negative());
|
||||
return $this->iushln($bits);
|
||||
}
|
||||
|
||||
// Shift-right in-place
|
||||
// NOTE: `hint` is a lowest bit before trailing zeroes
|
||||
// NOTE: if `extended` is present - it will be filled with destroyed bits
|
||||
public function iushrn($bits, $hint = 0, &$extended = null) {
|
||||
if( $hint != 0 )
|
||||
throw new Exception("Not implemented");
|
||||
|
||||
assert(is_integer($bits) && $bits >= 0);
|
||||
|
||||
if( $extended != null )
|
||||
$extended = $this->maskn($bits);
|
||||
|
||||
if ($bits < 54) {
|
||||
$this->bi = $this->bi->div(1 << $bits);
|
||||
} else {
|
||||
$this->bi = $this->bi->div((new BigInteger(2))->pow($bits));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ishrn($bits, $hint = null, $extended = null) {
|
||||
if (BN::$ASSERT_ENABLED) assert(!$this->negative());
|
||||
return $this->iushrn($bits, $hint, $extended);
|
||||
}
|
||||
|
||||
// Shift-left
|
||||
public function shln($bits) {
|
||||
return $this->_clone()->ishln($bits);
|
||||
}
|
||||
|
||||
public function ushln($bits) {
|
||||
return $this->_clone()->iushln($bits);
|
||||
}
|
||||
|
||||
// Shift-right
|
||||
public function shrn($bits) {
|
||||
return $this->_clone()->ishrn($bits);
|
||||
}
|
||||
|
||||
public function ushrn($bits) {
|
||||
return $this->_clone()->iushrn($bits);
|
||||
}
|
||||
|
||||
// Test if n bit is set
|
||||
public function testn($bit) {
|
||||
assert(is_integer($bit) && $bit >= 0);
|
||||
return $this->bi->testbit($bit);
|
||||
}
|
||||
|
||||
// Return only lowers bits of number (in-place)
|
||||
public function imaskn($bits) {
|
||||
assert(is_integer($bits) && $bits >= 0);
|
||||
if (BN::$ASSERT_ENABLED) assert(!$this->negative());
|
||||
$mask = "";
|
||||
for($i = 0; $i < $bits; $i++)
|
||||
$mask .= "1";
|
||||
return $this->iand(new BN($mask, 2));
|
||||
}
|
||||
|
||||
// Return only lowers bits of number
|
||||
public function maskn($bits) {
|
||||
return $this->_clone()->imaskn($bits);
|
||||
}
|
||||
|
||||
// Add plain number `num` to `this`
|
||||
public function iaddn($num) {
|
||||
assert(is_numeric($num));
|
||||
$this->bi = $this->bi->add(intval($num));
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Subtract plain number `num` from `this`
|
||||
public function isubn($num) {
|
||||
assert(is_numeric($num));
|
||||
$this->bi = $this->bi->sub(intval($num));
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addn($num) {
|
||||
return $this->_clone()->iaddn($num);
|
||||
}
|
||||
|
||||
public function subn($num) {
|
||||
return $this->_clone()->isubn($num);
|
||||
}
|
||||
|
||||
public function iabs() {
|
||||
if ($this->bi->sign() < 0) {
|
||||
$this->bi = $this->bi->abs();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function abs() {
|
||||
$res = clone($this);
|
||||
if ($res->bi->sign() < 0)
|
||||
$res->bi = $res->bi->abs();
|
||||
return $res;
|
||||
}
|
||||
|
||||
// Find `this` / `num`
|
||||
public function div(BN $num) {
|
||||
if (BN::$ASSERT_ENABLED) assert(!$num->isZero());
|
||||
$res = clone($this);
|
||||
$res->bi = $res->bi->div($num->bi);
|
||||
return $res;
|
||||
}
|
||||
|
||||
// Find `this` % `num`
|
||||
public function mod(BN $num) {
|
||||
if (BN::$ASSERT_ENABLED) assert(!$num->isZero());
|
||||
$res = clone($this);
|
||||
$res->bi = $res->bi->divR($num->bi);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function umod(BN $num) {
|
||||
if (BN::$ASSERT_ENABLED) assert(!$num->isZero());
|
||||
$tmp = $num->bi->sign() < 0 ? $num->bi->abs() : $num->bi;
|
||||
$res = clone($this);
|
||||
$res->bi = $this->bi->mod($tmp);
|
||||
return $res;
|
||||
}
|
||||
|
||||
// Find Round(`this` / `num`)
|
||||
public function divRound(BN $num)
|
||||
{
|
||||
if (BN::$ASSERT_ENABLED) assert(!$num->isZero());
|
||||
|
||||
$negative = $this->negative() !== $num->negative();
|
||||
|
||||
$res = $this->_clone()->abs();
|
||||
$arr = $res->bi->divQR($num->bi->abs());
|
||||
$res->bi = $arr[0];
|
||||
$tmp = $num->bi->sub($arr[1]->mul(2));
|
||||
if( $tmp->cmp(0) <= 0 && (!$negative || $this->negative() === 0) )
|
||||
$res->iaddn(1);
|
||||
return $negative ? $res->negi() : $res;
|
||||
}
|
||||
|
||||
public function modn($num) {
|
||||
assert(is_numeric($num) && $num != 0);
|
||||
return $this->bi->divR(intval($num))->toNumber();
|
||||
}
|
||||
|
||||
// In-place division by number
|
||||
public function idivn($num) {
|
||||
assert(is_numeric($num) && $num != 0);
|
||||
$this->bi = $this->bi->div(intval($num));
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function divn($num) {
|
||||
return $this->_clone()->idivn($num);
|
||||
}
|
||||
|
||||
public function gcd(BN $num) {
|
||||
$res = clone($this);
|
||||
$res->bi = $this->bi->gcd($num->bi);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function invm(BN $num) {
|
||||
$res = clone($this);
|
||||
$res->bi = $res->bi->modInverse($num->bi);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function isEven() {
|
||||
return !$this->bi->testbit(0);
|
||||
}
|
||||
|
||||
public function isOdd() {
|
||||
return $this->bi->testbit(0);
|
||||
}
|
||||
|
||||
public function andln($num) {
|
||||
assert(is_numeric($num));
|
||||
return $this->bi->binaryAnd($num)->toNumber();
|
||||
}
|
||||
|
||||
public function bincn($num) {
|
||||
$tmp = (new BN(1))->iushln($num);
|
||||
return $this->add($tmp);
|
||||
}
|
||||
|
||||
public function isZero() {
|
||||
return $this->bi->sign() == 0;
|
||||
}
|
||||
|
||||
public function cmpn($num) {
|
||||
assert(is_numeric($num));
|
||||
return $this->bi->cmp($num);
|
||||
}
|
||||
|
||||
// Compare two numbers and return:
|
||||
// 1 - if `this` > `num`
|
||||
// 0 - if `this` == `num`
|
||||
// -1 - if `this` < `num`
|
||||
public function cmp(BN $num) {
|
||||
return $this->bi->cmp($num->bi);
|
||||
}
|
||||
|
||||
public function ucmp(BN $num) {
|
||||
return $this->bi->abs()->cmp($num->bi->abs());
|
||||
}
|
||||
|
||||
public function gtn($num) {
|
||||
return $this->cmpn($num) > 0;
|
||||
}
|
||||
|
||||
public function gt(BN $num) {
|
||||
return $this->cmp($num) > 0;
|
||||
}
|
||||
|
||||
public function gten($num) {
|
||||
return $this->cmpn($num) >= 0;
|
||||
}
|
||||
|
||||
public function gte(BN $num) {
|
||||
return $this->cmp($num) >= 0;
|
||||
}
|
||||
|
||||
public function ltn($num) {
|
||||
return $this->cmpn($num) < 0;
|
||||
}
|
||||
|
||||
public function lt(BN $num) {
|
||||
return $this->cmp($num) < 0;
|
||||
}
|
||||
|
||||
public function lten($num) {
|
||||
return $this->cmpn($num) <= 0;
|
||||
}
|
||||
|
||||
public function lte(BN $num) {
|
||||
return $this->cmp($num) <= 0;
|
||||
}
|
||||
|
||||
public function eqn($num) {
|
||||
return $this->cmpn($num) === 0;
|
||||
}
|
||||
|
||||
public function eq(BN $num) {
|
||||
return $this->cmp($num) === 0;
|
||||
}
|
||||
|
||||
public function toRed(Red &$ctx) {
|
||||
if( $this->red !== null )
|
||||
throw new Exception("Already a number in reduction context");
|
||||
if( $this->negative() !== 0 )
|
||||
throw new Exception("red works only with positives");
|
||||
return $ctx->convertTo($this)->_forceRed($ctx);
|
||||
}
|
||||
|
||||
public function fromRed() {
|
||||
if( $this->red === null )
|
||||
throw new Exception("fromRed works only with numbers in reduction context");
|
||||
return $this->red->convertFrom($this);
|
||||
}
|
||||
|
||||
public function _forceRed(Red &$ctx) {
|
||||
$this->red = $ctx;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function forceRed(Red &$ctx) {
|
||||
if( $this->red !== null )
|
||||
throw new Exception("Already a number in reduction context");
|
||||
return $this->_forceRed($ctx);
|
||||
}
|
||||
|
||||
public function redAdd(BN $num) {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redAdd works only with red numbers");
|
||||
|
||||
$res = clone($this);
|
||||
$res->bi = $res->bi->add($num->bi);
|
||||
if ($res->bi->cmp($this->red->m->bi) >= 0)
|
||||
$res->bi = $res->bi->sub($this->red->m->bi);
|
||||
return $res;
|
||||
// return $this->red->add($this, $num);
|
||||
}
|
||||
|
||||
public function redIAdd(BN $num) {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redIAdd works only with red numbers");
|
||||
$res = $this;
|
||||
$res->bi = $res->bi->add($num->bi);
|
||||
if ($res->bi->cmp($this->red->m->bi) >= 0)
|
||||
$res->bi = $res->bi->sub($this->red->m->bi);
|
||||
return $res;
|
||||
//return $this->red->iadd($this, $num);
|
||||
}
|
||||
|
||||
public function redSub(BN $num) {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redSub works only with red numbers");
|
||||
$res = clone($this);
|
||||
$res->bi = $this->bi->sub($num->bi);
|
||||
if ($res->bi->sign() < 0)
|
||||
$res->bi = $res->bi->add($this->red->m->bi);
|
||||
return $res;
|
||||
//return $this->red->sub($this, $num);
|
||||
}
|
||||
|
||||
public function redISub(BN $num) {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redISub works only with red numbers");
|
||||
$this->bi = $this->bi->sub($num->bi);
|
||||
if ($this->bi->sign() < 0)
|
||||
$this->bi = $this->bi->add($this->red->m->bi);
|
||||
return $this;
|
||||
|
||||
// return $this->red->isub($this, $num);
|
||||
}
|
||||
|
||||
public function redShl(BN $num) {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redShl works only with red numbers");
|
||||
return $this->red->shl($this, $num);
|
||||
}
|
||||
|
||||
public function redMul(BN $num) {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redMul works only with red numbers");
|
||||
$res = clone($this);
|
||||
$res->bi = $this->bi->mul($num->bi)->mod($this->red->m->bi);
|
||||
return $res;
|
||||
/*
|
||||
return $this->red->mul($this, $num);
|
||||
*/
|
||||
}
|
||||
|
||||
public function redIMul(BN $num) {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redIMul works only with red numbers");
|
||||
$this->bi = $this->bi->mul($num->bi)->mod($this->red->m->bi);
|
||||
return $this;
|
||||
//return $this->red->imul($this, $num);
|
||||
}
|
||||
|
||||
public function redSqr() {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redSqr works only with red numbers");
|
||||
$res = clone($this);
|
||||
$res->bi = $this->bi->mul($this->bi)->mod($this->red->m->bi);
|
||||
return $res;
|
||||
/*
|
||||
$this->red->verify1($this);
|
||||
return $this->red->sqr($this);
|
||||
*/
|
||||
}
|
||||
|
||||
public function redISqr() {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redISqr works only with red numbers");
|
||||
$res = $this;
|
||||
$res->bi = $this->bi->mul($this->bi)->mod($this->red->m->bi);
|
||||
return $res;
|
||||
/* $this->red->verify1($this);
|
||||
return $this->red->isqr($this);
|
||||
*/
|
||||
}
|
||||
|
||||
public function redSqrt() {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redSqrt works only with red numbers");
|
||||
$this->red->verify1($this);
|
||||
return $this->red->sqrt($this);
|
||||
}
|
||||
|
||||
public function redInvm() {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redInvm works only with red numbers");
|
||||
$this->red->verify1($this);
|
||||
return $this->red->invm($this);
|
||||
}
|
||||
|
||||
public function redNeg() {
|
||||
if( $this->red === null )
|
||||
throw new Exception("redNeg works only with red numbers");
|
||||
$this->red->verify1($this);
|
||||
return $this->red->neg($this);
|
||||
}
|
||||
|
||||
public function redPow(BN $num) {
|
||||
$this->red->verify2($this, $num);
|
||||
return $this->red->pow($this, $num);
|
||||
}
|
||||
|
||||
public static function red($num) {
|
||||
return new Red($num);
|
||||
}
|
||||
|
||||
public static function mont($num) {
|
||||
return new Red($num);
|
||||
}
|
||||
|
||||
public function inspect() {
|
||||
return ($this->red == null ? "<BN: " : "<BN-R: ") . $this->toString(16) . ">";
|
||||
}
|
||||
|
||||
public function __debugInfo() {
|
||||
if ($this->red != null) {
|
||||
return ["BN-R" => $this->toString(16)];
|
||||
} else {
|
||||
return ["BN" => $this->toString(16)];
|
||||
}
|
||||
}
|
||||
}
|
||||
BN::$ASSERT_ENABLED = ini_get("zend.assertions") === "1";
|
||||
Vendored
+221
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
namespace BN;
|
||||
|
||||
use \Exception;
|
||||
use \BI\BigInteger;
|
||||
|
||||
class Red
|
||||
{
|
||||
public static $ASSERT_ENABLED;
|
||||
public $m;
|
||||
|
||||
function __construct($m) {
|
||||
if( is_string($m) )
|
||||
$this->m = Red::primeByName($m);
|
||||
else
|
||||
$this->m = $m;
|
||||
|
||||
if( !$this->m->gtn(1) )
|
||||
throw new Exception("Modulus must be greater than 1");
|
||||
}
|
||||
|
||||
|
||||
public static function primeByName($name)
|
||||
{
|
||||
switch($name) {
|
||||
case "k256":
|
||||
return new BN("ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f", 16);
|
||||
case "p224":
|
||||
return new BN("ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001", 16);
|
||||
case "p192":
|
||||
return new BN("ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff", 16);
|
||||
case "p25519":
|
||||
return new BN("7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed", 16);
|
||||
default:
|
||||
throw new Exception("Unknown prime name " . $name);
|
||||
}
|
||||
}
|
||||
|
||||
public function verify1(BN $num)
|
||||
{
|
||||
if (Red::$ASSERT_ENABLED) assert(!$num->negative()); //,"red works only with positives");
|
||||
assert($num->red); //, "red works only with red numbers");
|
||||
}
|
||||
|
||||
public function verify2(BN $a, BN $b)
|
||||
{
|
||||
if (Red::$ASSERT_ENABLED) assert(!$a->negative() && !$b->negative()); //, "red works only with positives");
|
||||
assert($a->red && ($a->red == $b->red)); //, "red works only with red numbers");
|
||||
}
|
||||
|
||||
public function imod(BN &$a) {
|
||||
return $a->umod($this->m)->_forceRed($this);
|
||||
}
|
||||
|
||||
public function neg(BN $a)
|
||||
{
|
||||
if( $a->isZero() )
|
||||
return $a->_clone();
|
||||
return $this->m->sub($a)->_forceRed($this);
|
||||
}
|
||||
|
||||
public function add(BN $a, BN $b)
|
||||
{
|
||||
$this->verify2($a, $b);
|
||||
|
||||
$res = $a->add($b);
|
||||
if( $res->cmp($this->m) >= 0 )
|
||||
$res->isub($this->m);
|
||||
return $res->_forceRed($this);
|
||||
}
|
||||
|
||||
public function iadd(BN &$a, BN $b)
|
||||
{
|
||||
$this->verify2($a, $b);
|
||||
|
||||
$a->iadd($b);
|
||||
if( $a->cmp($this->m) >= 0 )
|
||||
$a->isub($this->m);
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
public function sub(BN $a, BN $b)
|
||||
{
|
||||
$this->verify2($a, $b);
|
||||
|
||||
$res = $a->sub($b);
|
||||
if( $res->negative() )
|
||||
$res->iadd($this->m);
|
||||
|
||||
return $res->_forceRed($this);
|
||||
}
|
||||
|
||||
public function isub(BN &$a, $b)
|
||||
{
|
||||
$this->verify2($a, $b);
|
||||
|
||||
$a->isub($b);
|
||||
if( $a->negative() )
|
||||
$a->iadd($this->m);
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
public function shl(BN $a, $num) {
|
||||
$this->verify1($a);
|
||||
return $this->imod($a->ushln($num));
|
||||
}
|
||||
|
||||
public function imul(BN &$a, BN $b) {
|
||||
$this->verify2($a, $b);
|
||||
$res = $a->imul($b);
|
||||
return $this->imod($res);
|
||||
}
|
||||
|
||||
public function mul(BN $a, BN $b) {
|
||||
$this->verify2($a, $b);
|
||||
$res = $a->mul($b);
|
||||
return $this->imod($res);
|
||||
}
|
||||
|
||||
public function sqr(BN $a) {
|
||||
$res = $a->_clone();
|
||||
return $this->imul($res, $a);
|
||||
}
|
||||
|
||||
public function isqr(BN &$a) {
|
||||
return $this->imul($a, $a);
|
||||
}
|
||||
|
||||
public function sqrt(BN $a) {
|
||||
if ($a->isZero())
|
||||
return $a->_clone();
|
||||
|
||||
$mod3 = $this->m->andln(3);
|
||||
assert($mod3 % 2 == 1);
|
||||
|
||||
// Fast case
|
||||
if ($mod3 == 3) {
|
||||
$pow = $this->m->add(new BN(1))->iushrn(2);
|
||||
return $this->pow($a, $pow);
|
||||
}
|
||||
|
||||
// Tonelli-Shanks algorithm (Totally unoptimized and slow)
|
||||
//
|
||||
// Find Q and S, that Q * 2 ^ S = (P - 1)
|
||||
$q = $this->m->subn(1);
|
||||
$s = 0;
|
||||
while (!$q->isZero() && $q->andln(1) == 0) {
|
||||
$s++;
|
||||
$q->iushrn(1);
|
||||
}
|
||||
if (Red::$ASSERT_ENABLED) assert(!$q->isZero());
|
||||
|
||||
$one = (new BN(1))->toRed($this);
|
||||
$nOne = $one->redNeg();
|
||||
|
||||
// Find quadratic non-residue
|
||||
// NOTE: Max is such because of generalized Riemann hypothesis.
|
||||
$lpow = $this->m->subn(1)->iushrn(1);
|
||||
$z = $this->m->bitLength();
|
||||
$z = (new BN(2 * $z * $z))->toRed($this);
|
||||
|
||||
while ($this->pow($z, $lpow)->cmp($nOne) != 0) {
|
||||
$z->redIAdd($nOne);
|
||||
}
|
||||
|
||||
$c = $this->pow($z, $q);
|
||||
$r = $this->pow($a, $q->addn(1)->iushrn(1));
|
||||
$t = $this->pow($a, $q);
|
||||
$m = $s;
|
||||
while ($t->cmp($one) != 0) {
|
||||
$tmp = $t;
|
||||
for ($i = 0; $tmp->cmp($one) != 0; $i++) {
|
||||
$tmp = $tmp->redSqr();
|
||||
}
|
||||
if ($i >= $m) {
|
||||
throw new \Exception("Assertion failed");
|
||||
}
|
||||
if ($m - $i - 1 > 54) {
|
||||
$b = $this->pow($c, (new BN(1))->iushln($m - $i - 1));
|
||||
} else {
|
||||
$b = clone($c);
|
||||
$b->bi = $c->bi->powMod(1 << ($m - $i - 1), $this->m->bi);
|
||||
}
|
||||
|
||||
$r = $r->redMul($b);
|
||||
$c = $b->redSqr();
|
||||
$t = $t->redMul($c);
|
||||
$m = $i;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
public function invm(BN &$a) {
|
||||
$res = $a->invm($this->m);
|
||||
return $this->imod($res);
|
||||
}
|
||||
|
||||
public function pow(BN $a, BN $num) {
|
||||
$r = clone($a);
|
||||
$r->bi = $a->bi->powMod($num->bi, $this->m->bi);
|
||||
return $r;
|
||||
}
|
||||
|
||||
public function convertTo(BN $num) {
|
||||
$r = $num->umod($this->m);
|
||||
return $r === $num ? $r->_clone() : $r;
|
||||
}
|
||||
|
||||
public function convertFrom(BN $num) {
|
||||
$res = $num->_clone();
|
||||
$res->red = null;
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
Red::$ASSERT_ENABLED = ini_get("zend.assertions") === "1";
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,8 @@
|
||||
.vscode
|
||||
/vendor/
|
||||
node_modules
|
||||
composer.lock
|
||||
.project
|
||||
.settings
|
||||
.buildpath
|
||||
/.idea
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
|
||||
## MIT LICENSE
|
||||
|
||||
Copyright (C) 2016 Simplito
|
||||
|
||||
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.
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
all: test bench coverage
|
||||
|
||||
test:
|
||||
vendor/bin/phpunit --testdox
|
||||
|
||||
bench:
|
||||
vendor/bin/phpbench run --report=simple
|
||||
|
||||
coverage:
|
||||
sudo php5enmod xdebug
|
||||
vendor/bin/phpunit --coverage-html=coverage
|
||||
sudo php5dismod xdebug
|
||||
xdg-open coverage/index.html
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
|
||||
# Fast Elliptic Curve Cryptography in PHP
|
||||
|
||||
|
||||
## Information
|
||||
|
||||
This library is a PHP port of [elliptic](https://github.com/indutny/elliptic), a great JavaScript ECC library.
|
||||
|
||||
* Supported curve types: Short Weierstrass, Montgomery, Edwards, Twisted Edwards.
|
||||
* Curve 'presets': `secp256k1`, `p192`, `p224`, `p256`, `p384`, `p521`, `curve25519`, `ed25519`.
|
||||
|
||||
This software is licensed under the MIT License.
|
||||
|
||||
Projects which use Fast ECC PHP library: [PrivMX WebMail](https://privmx.com), ...
|
||||
|
||||
|
||||
## Benchmarks
|
||||
|
||||
```
|
||||
+------------------------+----------------+--------+-----+------+
|
||||
| subject | mode | rstdev | its | revs |
|
||||
+------------------------+----------------+--------+-----+------+
|
||||
| elliptic#genKeyPair | 323.682ops/s | 2.72% | 5 | 50 |
|
||||
| mdanter#genKeyPair | 13.794ops/s | 3.18% | 5 | 50 |
|
||||
+------------------------+----------------+--------+-----+------+
|
||||
| elliptic#sign | 307.228ops/s | 3.82% | 5 | 50 |
|
||||
| mdanter#sign | 14.118ops/s | 2.12% | 5 | 50 |
|
||||
+------------------------+----------------+--------+-----+------+
|
||||
| elliptic#verify | 93.913ops/s | 5.93% | 5 | 50 |
|
||||
| mdanter#verify | 6.859ops/s | 2.95% | 5 | 50 |
|
||||
+------------------------+----------------+--------+-----+------+
|
||||
| elliptic#dh | 135.166ops/s | 1.67% | 5 | 50 |
|
||||
| mdanter#dh | 14.302ops/s | 0.89% | 5 | 50 |
|
||||
+------------------------+----------------+--------+-----+------+
|
||||
| elliptic#EdDSASign | 296.756ops/s | 1.09% | 5 | 50 |
|
||||
+------------------------+----------------+--------+-----+------+
|
||||
| elliptic#EdDSAVerify | 67.481ops/s | 2.76% | 5 | 50 |
|
||||
+------------------------+----------------+--------+-----+------+
|
||||
```
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
You can install this library via Composer:
|
||||
```
|
||||
composer require simplito/elliptic-php
|
||||
```
|
||||
|
||||
|
||||
## Implementation details
|
||||
|
||||
ECDSA is using deterministic `k` value generation as per [RFC6979][0]. Most of
|
||||
the curve operations are performed on non-affine coordinates (either projective
|
||||
or extended), various windowing techniques are used for different cases.
|
||||
|
||||
NOTE: `curve25519` could not be used for ECDSA, use `ed25519` instead.
|
||||
|
||||
All operations are performed in reduction context using [bn-php][1].
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### ECDSA
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Elliptic\EC;
|
||||
|
||||
// Create and initialize EC context
|
||||
// (better do it once and reuse it)
|
||||
$ec = new EC('secp256k1');
|
||||
|
||||
// Generate keys
|
||||
$key = $ec->genKeyPair();
|
||||
|
||||
// Sign message (can be hex sequence or array)
|
||||
$msg = 'ab4c3451';
|
||||
$signature = $key->sign($msg);
|
||||
|
||||
// Export DER encoded signature to hex string
|
||||
$derSign = $signature->toDER('hex');
|
||||
|
||||
// Verify signature
|
||||
echo "Verified: " . (($key->verify($msg, $derSign) == TRUE) ? "true" : "false") . "\n";
|
||||
|
||||
// CHECK WITH NO PRIVATE KEY
|
||||
|
||||
// Public key as '04 + x + y'
|
||||
$pub = "049a1eedae838f2f8ad94597dc4368899ecc751342b464862da80c280d841875ab4607fb6ce14100e71dd7648dd6b417c7872a6ff1ff29195dabd99f15eff023e5";
|
||||
|
||||
// Signature MUST be either:
|
||||
// 1) hex-string of DER-encoded signature; or
|
||||
// 2) DER-encoded signature as byte array; or
|
||||
// 3) object with two hex-string properties (r and s)
|
||||
|
||||
// case 1
|
||||
$sig = '30450220233f8bab3f5df09e3d02f45914b0b519d2c04d13ac6964495623806a015df1cd022100c0c279c989b79885b3cc0f117643317bc59414bfb581f38e03557b8532f06603';
|
||||
|
||||
// case 2
|
||||
$sig = [48,69,2,32,35,63,139,171,63,93,240,158,61,2,244,89,20,176,181,25,210,192,77,19,172,105,100,73,86,35,128,106,1,93,241,205,2,33,0,192,194,121,201,137,183,152,133,179,204,15,17,118,67,49,123,197,148,20,191,181,129,243,142,3,85,123,133,50,240,102,3];
|
||||
|
||||
// case 3
|
||||
$sig = ['r' => '233f8bab3f5df09e3d02f45914b0b519d2c04d13ac6964495623806a015df1cd', 's' => 'c0c279c989b79885b3cc0f117643317bc59414bfb581f38e03557b8532f06603'];
|
||||
|
||||
|
||||
// Import public key
|
||||
$key = $ec->keyFromPublic($pub, 'hex');
|
||||
|
||||
// Verify signature
|
||||
echo "Verified: " . (($key->verify($msg, $sig) == TRUE) ? "true" : "false") . "\n";
|
||||
```
|
||||
|
||||
### EdDSA
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Elliptic\EdDSA;
|
||||
|
||||
// Create and initialize EdDSA context
|
||||
// (better do it once and reuse it)
|
||||
$ec = new EdDSA('ed25519');
|
||||
|
||||
// Create key pair from secret
|
||||
$key = $ec->keyFromSecret('61233ca4590acd'); // hex string or array of bytes
|
||||
|
||||
// Sign message (can be hex sequence or array)
|
||||
$msg = 'ab4c3451';
|
||||
$signature = $key->sign($msg)->toHex();
|
||||
|
||||
// Verify signature
|
||||
echo "Verified: " . (($key->verify($msg, $signature) == TRUE) ? "true" : "false") . "\n";
|
||||
|
||||
// CHECK WITH NO PRIVATE KEY
|
||||
|
||||
// Import public key
|
||||
$pub = '2763d01c334250d3e2dda459e5e3f949f667c6bbf0a35012c77ad40b00f0374d';
|
||||
$key = $ec->keyFromPublic($pub, 'hex');
|
||||
|
||||
// Verify signature
|
||||
$signature = '93899915C2919181A3D244AAAC032CE78EF76D2FFC0355D4BE2C70F48202EBC5F2BB0541D236182F55B11AC6346B524150695E5DE1FEA570786E1CC1F7999404';
|
||||
echo "Verified: " . (($key->verify($msg, $signature) == TRUE) ? "true" : "false") . "\n";
|
||||
```
|
||||
|
||||
### ECDH
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Elliptic\EC;
|
||||
|
||||
$ec = new EC('curve25519');
|
||||
|
||||
// Generate keys
|
||||
$key1 = $ec->genKeyPair();
|
||||
$key2 = $ec->genKeyPair();
|
||||
|
||||
$shared1 = $key1->derive($key2->getPublic());
|
||||
$shared2 = $key2->derive($key1->getPublic());
|
||||
|
||||
echo "Both shared secrets are BN instances\n";
|
||||
echo $shared1->toString(16) . "\n";
|
||||
echo $shared2->toString(16) . "\n";
|
||||
```
|
||||
|
||||
NOTE: `.derive()` returns a [BN][1] instance. The resulting hex string is not zero-padded to constant size. Note that when interoperating with other libraries or using the result in a hash function.
|
||||
|
||||
### Using EC directly
|
||||
|
||||
Use case examples:
|
||||
|
||||
#### Computing public key from private
|
||||
|
||||
```php
|
||||
use Elliptic\EC;
|
||||
|
||||
$ec = new EC('secp256k1');
|
||||
|
||||
$priv_hex = "751ce088f64404e5889bf7e9e5c280b200b2dc158461e96b921df39a1dbc6635";
|
||||
$pub_hex = "03a319a1d10a91ada9a01ab121b81ae5f14580083a976e74945cdb014a4a52bae6";
|
||||
|
||||
$priv = $ec->keyFromPrivate($priv_hex);
|
||||
if ($pub_hex == $priv->getPublic(true, "hex")) {
|
||||
echo "Success\n";
|
||||
} else {
|
||||
echo "Fail\n";
|
||||
}
|
||||
```
|
||||
|
||||
#### Verifying Bitcoin Message Signature
|
||||
|
||||
```php
|
||||
use Elliptic\EC;
|
||||
use StephenHill\Base58;
|
||||
|
||||
// see: https://en.bitcoin.it/wiki/List_of_address_prefixes
|
||||
const MainNetId = "\x00";
|
||||
const TestNetId = "\x6F";
|
||||
const PrefixNetIdMap = [ "1" => MainNetId, "m" => TestNetId ];
|
||||
|
||||
function pubKeyAddress($pubkey, $netid = MainNetId) {
|
||||
$b58 = new Base58();
|
||||
|
||||
$pubenc = hex2bin($pubkey->encode("hex", true));
|
||||
$pubhash = $netid . hash('ripemd160', hash('sha256', $pubenc, true), true);
|
||||
$checksum = substr( hash('sha256', hash('sha256', $pubhash, true), true), 0, 4);
|
||||
|
||||
return $b58->encode($pubhash . $checksum);
|
||||
}
|
||||
|
||||
function verifySignature($message, $signature, $address) {
|
||||
$signbin = base64_decode($signature);
|
||||
|
||||
$signarr = [ "r" => bin2hex(substr($signbin, 1, 32)),
|
||||
"s" => bin2hex(substr($signbin, 33, 32)) ];
|
||||
|
||||
$nv = ord(substr($signbin, 0, 1)) - 27;
|
||||
if ($nv != ($nv & 7))
|
||||
return false;
|
||||
|
||||
$recid = ($nv & 3);
|
||||
$compressed = ($nv & 4) != 0;
|
||||
|
||||
$msglen = strlen($message);
|
||||
$hash = hash('sha256', hash('sha256', "\x18Bitcoin Signed Message:\n" . chr($msglen) . $message, true));
|
||||
|
||||
$ec = new EC('secp256k1');
|
||||
$pub = $ec->recoverPubKey($hash, $signarr, $recid);
|
||||
|
||||
$result = pubKeyAddress($pub, PrefixNetIdMap[$address[0]]);
|
||||
return $result == $address;
|
||||
}
|
||||
|
||||
$message = "I like signatures";
|
||||
$signature = "H/zugYITIQTk8ZFWeXkbGCV2MzvMtbh+CnKBctbM9tP2UCb1B4LdyWFQuTZKxLdIDgP8Vsvl+0AEkBlY1HoyVw8=";
|
||||
$address = "mxQadqtYQXYeUsSqdMdJxZwkzxbd2tuMdc";
|
||||
|
||||
if (verifySignature($message, $signature, $address)) {
|
||||
echo "Success\n";
|
||||
} else {
|
||||
echo "Fail\n";
|
||||
}
|
||||
```
|
||||
|
||||
#### Verifying Ethereum Signature
|
||||
|
||||
```php
|
||||
use Elliptic\EC;
|
||||
use kornrunner\Keccak;
|
||||
|
||||
function pubKeyToAddress($pubkey) {
|
||||
return "0x" . substr(Keccak::hash(substr(hex2bin($pubkey->encode("hex")), 1), 256), 24);
|
||||
}
|
||||
|
||||
function verifySignature($message, $signature, $address) {
|
||||
$msglen = strlen($message);
|
||||
$hash = Keccak::hash("\x19Ethereum Signed Message:\n{$msglen}{$message}", 256);
|
||||
$sign = ["r" => substr($signature, 2, 64),
|
||||
"s" => substr($signature, 66, 64)];
|
||||
$recid = ord(hex2bin(substr($signature, 130, 2))) - 27;
|
||||
if ($recid != ($recid & 1))
|
||||
return false;
|
||||
|
||||
$ec = new EC('secp256k1');
|
||||
$pubkey = $ec->recoverPubKey($hash, $sign, $recid);
|
||||
|
||||
return $address == pubKeyToAddress($pubkey);
|
||||
}
|
||||
|
||||
$address = "0x5a214a45585b336a776b62a3a61dbafd39f9fa2a";
|
||||
$message = "I like signatures";
|
||||
// signature returned by eth.sign(address, message)
|
||||
$signature = "0xacb175089543ac060ed48c3e25ada5ffeed6f008da9eaca3806e4acb707b9481401409ae1f5f9f290f54f29684e7bac1d79b2964e0edcb7f083bacd5fc48882e1b";
|
||||
|
||||
if (verifySignature($message, $signature, $address)) {
|
||||
echo "Success\n";
|
||||
} else {
|
||||
echo "Fail\n";
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### ECDH (secret based, base58 format)
|
||||
|
||||
For usage in ed25519 oriented platforms like e.g. BigChainDB who use base58 encoded public / private keys.
|
||||
|
||||
```php
|
||||
use Elliptic\EdDSA;
|
||||
use StephenHill\Base58;
|
||||
|
||||
$mnemonic = "scheme spot photo card baby mountain device kick cradle pact join borrow";
|
||||
$secret = hash_pbkdf2('sha512', $mnemonic, 'mnemonic', 2048);
|
||||
|
||||
$ec = new EdDSA('ed25519');
|
||||
$kp = $ec->keyFromSecret($secret);
|
||||
|
||||
assert($secret == $kp->getSecret('hex'));
|
||||
echo "Secret: " . $kp->getSecret('hex') . PHP_EOL;
|
||||
|
||||
echo "Private: " . $kp->priv()->toString('hex') . PHP_EOL;
|
||||
echo "Public: " . $kp->getPublic('hex') . PHP_EOL;
|
||||
|
||||
$b58 = new Base58();
|
||||
echo PHP_EOL;
|
||||
echo "B58 Private: " . $b58->encode(hex2bin($kp->priv()->toString('hex'))) . PHP_EOL;
|
||||
echo "B58 Public: " . $b58->encode(hex2bin($kp->getPublic('hex'))) . PHP_EOL;
|
||||
```
|
||||
|
||||
#### BIP32 Public Parent Key -> Public Child Key derivation example
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Elliptic\EC;
|
||||
use BN\BN;
|
||||
|
||||
$ec = new EC('secp256k1');
|
||||
|
||||
// See: http://bip32.org using Derive From BIP32 Key
|
||||
// xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8
|
||||
$c_par = "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508";
|
||||
$K_par = "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2";
|
||||
|
||||
// Derived public child key
|
||||
// Derivation path Simple: m/i
|
||||
// Keypair index i: 2018
|
||||
// xpub68Gmy5EVb2Begkah8BxugKchT5SExW5p9gEHBLnEvYSuwVppt2TzD3WTjxNk14R8pmHbz3MHB9n75M2zNYgkJUCwV9pYwU9Z21Awj7Cr5U9
|
||||
$expected_c_child = "a7470737ffde1458292e19e838534f400ad3c0f72e12f08eff79dee4fce11bed";
|
||||
$expected_K_child = "0376499d06f9e9df71d7ee08d13a91337fa2b92182d4afcddf917b8d9983eb4615";
|
||||
|
||||
$i = 2018;
|
||||
$I_key = hex2bin($c_par);
|
||||
$I_data = hex2bin($K_par) . pack("N", $i);
|
||||
$I = hash_hmac("sha512", $I_data, $I_key);
|
||||
$I_L = substr($I, 0, 64);
|
||||
$I_R = substr($I, 64, 64);
|
||||
$c_i = $I_R;
|
||||
|
||||
$K_par_point = $ec->curve->decodePoint($K_par, "hex");
|
||||
$I_L_point = $ec->g->mul(new BN($I_L, 16));
|
||||
$K_i = $K_par_point->add($I_L_point);
|
||||
$K_i = $K_i->encodeCompressed("hex");
|
||||
|
||||
if ($expected_c_child == $c_i && $expected_K_child == $K_i) {
|
||||
echo "Success!\n";
|
||||
} else {
|
||||
echo "Failure!\n";
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
[0]: http://tools.ietf.org/html/rfc6979
|
||||
[1]: https://github.com/simplito/bn-php
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
/**
|
||||
* @BeforeMethods({"init"})
|
||||
*
|
||||
* @Iterations(5)
|
||||
* @Revs(50)
|
||||
* @OutputTimeUnit("seconds")
|
||||
* @OutputMode("throughput")
|
||||
*/
|
||||
class EllipticBench {
|
||||
private $ec;
|
||||
private $keys;
|
||||
private $hash;
|
||||
|
||||
static $msg = [ 0xB, 0xE, 0xE, 0xF ];
|
||||
|
||||
public function init() {
|
||||
$this->ec = new \Elliptic\EC('secp256k1');
|
||||
$this->priv = $this->ec->genKeyPair();
|
||||
$this->pub = $this->priv->getPublic();
|
||||
$this->hash = hash('sha256', 'hello world');
|
||||
$this->sign = $this->priv->sign($this->hash);
|
||||
$this->priv2 = $this->ec->genKeyPair();
|
||||
$this->pub2 = $this->priv2->getPublic();
|
||||
|
||||
$this->ed25519 = new \Elliptic\EdDSA('ed25519');
|
||||
$secret = array_fill(0, 32, 0);
|
||||
$this->edkey = $this->ed25519->keyFromSecret($secret);
|
||||
$this->edsig = $this->edkey->sign(self::$msg);
|
||||
}
|
||||
|
||||
public function benchGenKeyPair() {
|
||||
$this->ec->genKeyPair();
|
||||
}
|
||||
|
||||
public function benchGenKeyPairWithPublicKey() {
|
||||
$priv = $this->ec->genKeyPair();
|
||||
$pub = $priv->getPublic();
|
||||
}
|
||||
|
||||
public function benchSign() {
|
||||
$this->priv->sign($this->hash);
|
||||
}
|
||||
|
||||
public function benchVerify() {
|
||||
if ( !$this->ec->verify($this->hash, $this->sign, $this->pub) )
|
||||
throw new \Exception("unexpected");
|
||||
}
|
||||
|
||||
public function benchDH() {
|
||||
$this->priv->derive($this->pub2);
|
||||
}
|
||||
|
||||
public function benchEdDSASign() {
|
||||
$this->edkey->sign(self::$msg);
|
||||
}
|
||||
|
||||
public function benchEdDSAVerify() {
|
||||
if ( !$this->edkey->verify(self::$msg, $this->edsig) )
|
||||
throw new \Exception("unexpected");
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "simplito/elliptic-php",
|
||||
"description": "Fast elliptic curve cryptography",
|
||||
"type": "library",
|
||||
"homepage": "https://github.com/simplito/elliptic-php",
|
||||
"keywords": ["elliptic", "curve", "cryptography", "ECC",
|
||||
"ECDH", "ECDSA", "EdDSA",
|
||||
"secp256k1", "curve25519", "curve25519-weier", "ed25519",
|
||||
"nistp192", "nistp224", "nistp256", "nistp384", "nistp521"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Simplito Team",
|
||||
"email": "s.smyczynski@simplito.com",
|
||||
"homepage": "https://simplito.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"ext-gmp": "*",
|
||||
"simplito/bn-php": "~1.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*",
|
||||
"phpbench/phpbench": "@dev"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Elliptic\\": "lib/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit --verbose"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
use Elliptic\Utils;
|
||||
use \Exception;
|
||||
use BN\BN;
|
||||
|
||||
abstract class BaseCurve
|
||||
{
|
||||
public $type;
|
||||
public $p;
|
||||
public $red;
|
||||
public $zero;
|
||||
public $one;
|
||||
public $two;
|
||||
public $n;
|
||||
public $g;
|
||||
protected $_wnafT1;
|
||||
protected $_wnafT2;
|
||||
protected $_wnafT3;
|
||||
protected $_wnafT4;
|
||||
public $redN;
|
||||
public $_maxwellTrick;
|
||||
|
||||
function __construct($type, $conf)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->p = new BN($conf["p"], 16);
|
||||
|
||||
//Use Montgomery, when there is no fast reduction for the prime
|
||||
$this->red = isset($conf["prime"]) ? BN::red($conf["prime"]) : BN::mont($this->p);
|
||||
|
||||
//Useful for many curves
|
||||
$this->zero = (new BN(0))->toRed($this->red);
|
||||
$this->one = (new BN(1))->toRed($this->red);
|
||||
$this->two = (new BN(2))->toRed($this->red);
|
||||
|
||||
//Curve configuration, optional
|
||||
$this->n = isset($conf["n"]) ? new BN($conf["n"], 16) : null;
|
||||
$this->g = isset($conf["g"]) ? $this->pointFromJSON($conf["g"], isset($conf["gRed"]) ? $conf["gRed"] : null) : null;
|
||||
|
||||
//Temporary arrays
|
||||
$this->_wnafT1 = array(0,0,0,0);
|
||||
$this->_wnafT2 = array(0,0,0,0);
|
||||
$this->_wnafT3 = array(0,0,0,0);
|
||||
$this->_wnafT4 = array(0,0,0,0);
|
||||
|
||||
//Generalized Greg Maxwell's trick
|
||||
$adjustCount = $this->n != null ? $this->p->div($this->n) : null;
|
||||
if( $adjustCount == null || $adjustCount->cmpn(100) > 0 )
|
||||
{
|
||||
$this->redN = null;
|
||||
$this->_maxwellTrick = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->redN = $this->n->toRed($this->red);
|
||||
$this->_maxwellTrick = true;
|
||||
}
|
||||
}
|
||||
|
||||
abstract public function point($x, $z);
|
||||
abstract public function validate($point);
|
||||
|
||||
public function _fixedNafMul($p, $k)
|
||||
{
|
||||
assert(isset($p->precomputed));
|
||||
|
||||
$doubles = $p->_getDoubles();
|
||||
$naf = Utils::getNAF($k, 1);
|
||||
$I = (1 << ($doubles["step"] + 1)) - ($doubles["step"] % 2 == 0 ? 2 : 1);
|
||||
$I = $I / 3;
|
||||
|
||||
//Translate to more windowed form
|
||||
$repr = array();
|
||||
for($j = 0; $j < count($naf); $j += $doubles["step"])
|
||||
{
|
||||
$nafW = 0;
|
||||
for($k = $j + $doubles["step"] - 1; $k >= $j; $k--)
|
||||
$nafW = ($nafW << 1) + (isset($naf[$k]) ? $naf[$k] : 0);
|
||||
array_push($repr, $nafW);
|
||||
}
|
||||
|
||||
$a = $this->jpoint(null, null, null);
|
||||
$b = $this->jpoint(null, null, null);
|
||||
|
||||
for($i = $I; $i > 0; $i--)
|
||||
{
|
||||
for($j = 0; $j < count($repr); $j++)
|
||||
{
|
||||
$nafW = $repr[$j];
|
||||
if ($nafW == $i) {
|
||||
$b = $b->mixedAdd($doubles["points"][$j]);
|
||||
} else if($nafW == -$i) {
|
||||
$b = $b->mixedAdd($doubles["points"][$j]->neg());
|
||||
}
|
||||
}
|
||||
$a = $a->add($b);
|
||||
}
|
||||
|
||||
return $a->toP();
|
||||
}
|
||||
|
||||
public function _wnafMul($p, $k)
|
||||
{
|
||||
$w = 4;
|
||||
|
||||
//Precompute window
|
||||
$nafPoints = $p->_getNAFPoints($w);
|
||||
$w = $nafPoints["wnd"];
|
||||
$wnd = $nafPoints["points"];
|
||||
|
||||
//Get NAF form
|
||||
$naf = Utils::getNAF($k, $w);
|
||||
|
||||
//Add `this`*(N+1) for every w-NAF index
|
||||
$acc = $this->jpoint(null, null, null);
|
||||
for($i = count($naf) - 1; $i >= 0; $i--)
|
||||
{
|
||||
//Count zeros
|
||||
for($k = 0; $i >= 0 && $naf[$i] == 0; $i--)
|
||||
$k++;
|
||||
|
||||
if($i >= 0)
|
||||
$k++;
|
||||
$acc = $acc->dblp($k);
|
||||
|
||||
if($i < 0)
|
||||
break;
|
||||
$z = $naf[$i];
|
||||
|
||||
assert($z != 0);
|
||||
|
||||
if( $p->type == "affine" )
|
||||
{
|
||||
//J +- P
|
||||
if( $z > 0 )
|
||||
$acc = $acc->mixedAdd($wnd[($z - 1) >> 1]);
|
||||
else
|
||||
$acc = $acc->mixedAdd($wnd[(-$z - 1) >> 1]->neg());
|
||||
}
|
||||
else
|
||||
{
|
||||
//J +- J
|
||||
if( $z > 0 )
|
||||
$acc = $acc->add($wnd[($z - 1) >> 1]);
|
||||
else
|
||||
$acc = $acc->add($wnd[(-$z - 1) >> 1]->neg());
|
||||
}
|
||||
}
|
||||
return $p->type == "affine" ? $acc->toP() : $acc;
|
||||
}
|
||||
|
||||
public function _wnafMulAdd($defW, $points, $coeffs, $len, $jacobianResult = false)
|
||||
{
|
||||
$wndWidth = &$this->_wnafT1;
|
||||
$wnd = &$this->_wnafT2;
|
||||
$naf = &$this->_wnafT3;
|
||||
|
||||
//Fill all arrays
|
||||
$max = 0;
|
||||
for($i = 0; $i < $len; $i++)
|
||||
{
|
||||
$p = $points[$i];
|
||||
$nafPoints = $p->_getNAFPoints($defW);
|
||||
$wndWidth[$i] = $nafPoints["wnd"];
|
||||
$wnd[$i] = $nafPoints["points"];
|
||||
}
|
||||
//Comb all window NAFs
|
||||
for($i = $len - 1; $i >= 1; $i -= 2)
|
||||
{
|
||||
$a = $i - 1;
|
||||
$b = $i;
|
||||
if( $wndWidth[$a] != 1 || $wndWidth[$b] != 1 )
|
||||
{
|
||||
$naf[$a] = Utils::getNAF($coeffs[$a], $wndWidth[$a]);
|
||||
$naf[$b] = Utils::getNAF($coeffs[$b], $wndWidth[$b]);
|
||||
$max = max(count($naf[$a]), $max);
|
||||
$max = max(count($naf[$b]), $max);
|
||||
continue;
|
||||
}
|
||||
|
||||
$comb = array(
|
||||
$points[$a], /* 1 */
|
||||
null, /* 3 */
|
||||
null, /* 5 */
|
||||
$points[$b] /* 7 */
|
||||
);
|
||||
|
||||
//Try to avoid Projective points, if possible
|
||||
if( $points[$a]->y->cmp($points[$b]->y) == 0 )
|
||||
{
|
||||
$comb[1] = $points[$a]->add($points[$b]);
|
||||
$comb[2] = $points[$a]->toJ()->mixedAdd($points[$b]->neg());
|
||||
}
|
||||
elseif( $points[$a]->y->cmp($points[$b]->y->redNeg()) == 0 )
|
||||
{
|
||||
$comb[1] = $points[$a]->toJ()->mixedAdd($points[$b]);
|
||||
$comb[2] = $points[$a]->add($points[$b]->neg());
|
||||
}
|
||||
else
|
||||
{
|
||||
$comb[1] = $points[$a]->toJ()->mixedAdd($points[$b]);
|
||||
$comb[2] = $points[$a]->toJ()->mixedAdd($points[$b]->neg());
|
||||
}
|
||||
|
||||
$index = array(
|
||||
-3, /* -1 -1 */
|
||||
-1, /* -1 0 */
|
||||
-5, /* -1 1 */
|
||||
-7, /* 0 -1 */
|
||||
0, /* 0 0 */
|
||||
7, /* 0 1 */
|
||||
5, /* 1 -1 */
|
||||
1, /* 1 0 */
|
||||
3 /* 1 1 */
|
||||
);
|
||||
|
||||
$jsf = Utils::getJSF($coeffs[$a], $coeffs[$b]);
|
||||
$max = max(count($jsf[0]), $max);
|
||||
if ($max > 0) {
|
||||
$naf[$a] = array_fill(0, $max, 0);
|
||||
$naf[$b] = array_fill(0, $max, 0);
|
||||
} else {
|
||||
$naf[$a] = [];
|
||||
$naf[$b] = [];
|
||||
}
|
||||
|
||||
for($j = 0; $j < $max; $j++)
|
||||
{
|
||||
$ja = isset($jsf[0][$j]) ? $jsf[0][$j] : 0;
|
||||
$jb = isset($jsf[1][$j]) ? $jsf[1][$j] : 0;
|
||||
|
||||
$naf[$a][$j] = $index[($ja + 1) * 3 + ($jb + 1)];
|
||||
$naf[$b][$j] = 0;
|
||||
$wnd[$a] = $comb;
|
||||
}
|
||||
}
|
||||
|
||||
$acc = $this->jpoint(null, null, null);
|
||||
$tmp = &$this->_wnafT4;
|
||||
for($i = $max; $i >= 0; $i--)
|
||||
{
|
||||
$k = 0;
|
||||
|
||||
while($i >= 0)
|
||||
{
|
||||
$zero = true;
|
||||
for($j = 0; $j < $len; $j++)
|
||||
{
|
||||
$tmp[$j] = isset($naf[$j][$i]) ? $naf[$j][$i] : 0;
|
||||
if( $tmp[$j] != 0 )
|
||||
$zero = false;
|
||||
}
|
||||
if( !$zero )
|
||||
break;
|
||||
$k++;
|
||||
$i--;
|
||||
}
|
||||
|
||||
if( $i >=0 )
|
||||
$k++;
|
||||
|
||||
$acc = $acc->dblp($k);
|
||||
if( $i < 0 )
|
||||
break;
|
||||
|
||||
for($j = 0; $j < $len; $j++)
|
||||
{
|
||||
$z = $tmp[$j];
|
||||
$p = null;
|
||||
if( $z == 0 )
|
||||
continue;
|
||||
elseif( $z > 0 )
|
||||
$p = $wnd[$j][($z - 1) >> 1];
|
||||
elseif( $z < 0 )
|
||||
$p = $wnd[$j][(-$z - 1) >> 1]->neg();
|
||||
|
||||
if( $p->type == "affine" )
|
||||
$acc = $acc->mixedAdd($p);
|
||||
else
|
||||
$acc = $acc->add($p);
|
||||
}
|
||||
}
|
||||
|
||||
//Zeroify references
|
||||
for($i = 0; $i < $len; $i++)
|
||||
$wnd[$i] = null;
|
||||
|
||||
if( $jacobianResult )
|
||||
return $acc;
|
||||
else
|
||||
return $acc->toP();
|
||||
}
|
||||
|
||||
public function decodePoint($bytes, $enc = false)
|
||||
{
|
||||
$bytes = Utils::toArray($bytes, $enc);
|
||||
$len = $this->p->byteLength();
|
||||
|
||||
$count = count($bytes);
|
||||
//uncompressed, hybrid-odd, hybrid-even
|
||||
if(($bytes[0] == 0x04 || $bytes[0] == 0x06 || $bytes[0] == 0x07) && ($count - 1) == (2 * $len) )
|
||||
{
|
||||
if( $bytes[0] == 0x06 )
|
||||
assert($bytes[$count - 1] % 2 == 0);
|
||||
elseif( $bytes[0] == 0x07 )
|
||||
assert($bytes[$count - 1] % 2 == 1);
|
||||
|
||||
return $this->point(array_slice($bytes, 1, $len), array_slice($bytes, 1 + $len, $len));
|
||||
}
|
||||
|
||||
if( ($bytes[0] == 0x02 || $bytes[0] == 0x03) && ($count - 1) == $len )
|
||||
return $this->pointFromX(array_slice($bytes, 1, $len), $bytes[0] == 0x03);
|
||||
|
||||
throw new Exception("Unknown point format");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve\BaseCurve;
|
||||
|
||||
use Elliptic\Utils;
|
||||
|
||||
abstract class Point
|
||||
{
|
||||
public $curve;
|
||||
public $type;
|
||||
public $precomputed;
|
||||
|
||||
function __construct($curve, $type)
|
||||
{
|
||||
$this->curve = $curve;
|
||||
$this->type = $type;
|
||||
$this->precomputed = null;
|
||||
}
|
||||
|
||||
abstract public function eq($other);
|
||||
|
||||
public function validate() {
|
||||
return $this->curve->validate($this);
|
||||
}
|
||||
|
||||
public function encodeCompressed($enc) {
|
||||
return $this->encode($enc, true);
|
||||
}
|
||||
|
||||
public function encode($enc, $compact = false) {
|
||||
return Utils::encode($this->_encode($compact), $enc);
|
||||
}
|
||||
|
||||
protected function _encode($compact)
|
||||
{
|
||||
$len = $this->curve->p->byteLength();
|
||||
$x = $this->getX()->toArray("be", $len);
|
||||
|
||||
if( $compact )
|
||||
{
|
||||
array_unshift($x, ($this->getY()->isEven() ? 0x02 : 0x03));
|
||||
return $x;
|
||||
}
|
||||
|
||||
return array_merge(array(0x04), $x, $this->getY()->toArray("be", $len));
|
||||
}
|
||||
|
||||
public function precompute($power = null)
|
||||
{
|
||||
if( isset($this->precomputed) )
|
||||
return $this;
|
||||
|
||||
$this->precomputed = array(
|
||||
"naf" => $this->_getNAFPoints(8),
|
||||
"doubles" => $this->_getDoubles(4, $power),
|
||||
"beta" => $this->_getBeta()
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function _hasDoubles($k)
|
||||
{
|
||||
if( !isset($this->precomputed) || !isset($this->precomputed["doubles"]) )
|
||||
return false;
|
||||
|
||||
return count($this->precomputed["doubles"]["points"]) >= ceil(($k->bitLength() + 1) / $this->precomputed["doubles"]["step"]);
|
||||
}
|
||||
|
||||
public function _getDoubles($step = null, $power = null)
|
||||
{
|
||||
if( isset($this->precomputed) && isset($this->precomputed["doubles"]) )
|
||||
return $this->precomputed["doubles"];
|
||||
|
||||
$doubles = array( $this );
|
||||
$acc = $this;
|
||||
for($i = 0; $i < $power; $i += $step)
|
||||
{
|
||||
for($j = 0; $j < $step; $j++)
|
||||
$acc = $acc->dbl();
|
||||
array_push($doubles, $acc);
|
||||
}
|
||||
|
||||
return array(
|
||||
"step" => $step,
|
||||
"points" => $doubles
|
||||
);
|
||||
}
|
||||
|
||||
public function _getNAFPoints($wnd)
|
||||
{
|
||||
if( isset($this->precomputed) && isset($this->precomputed["naf"]) )
|
||||
return $this->precomputed["naf"];
|
||||
|
||||
$res = array( $this );
|
||||
$max = (1 << $wnd) - 1;
|
||||
$dbl = $max === 1 ? null : $this->dbl();
|
||||
for($i = 1; $i < $max; $i++)
|
||||
array_push($res, $res[$i - 1]->add($dbl));
|
||||
|
||||
return array(
|
||||
"wnd" => $wnd,
|
||||
"points" => $res
|
||||
);
|
||||
}
|
||||
|
||||
public function _getBeta() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function dblp($k)
|
||||
{
|
||||
$r = $this;
|
||||
for($i = 0; $i < $k; $i++)
|
||||
$r = $r->dbl();
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
use Elliptic\Curve\EdwardsCurve\Point;
|
||||
use Elliptic\Utils;
|
||||
use BN\BN;
|
||||
|
||||
class EdwardsCurve extends BaseCurve
|
||||
{
|
||||
public $twisted;
|
||||
public $mOneA;
|
||||
public $extended;
|
||||
public $a;
|
||||
public $c;
|
||||
public $c2;
|
||||
public $d;
|
||||
public $d2;
|
||||
public $dd;
|
||||
public $oneC;
|
||||
|
||||
function __construct($conf)
|
||||
{
|
||||
// NOTE: Important as we are creating point in Base.call()
|
||||
$this->twisted = ($conf["a"] | 0) != 1;
|
||||
$this->mOneA = $this->twisted && ($conf["a"] | 0) == -1;
|
||||
$this->extended = $this->mOneA;
|
||||
parent::__construct("edward", $conf);
|
||||
|
||||
$this->a = (new BN($conf["a"], 16))->umod($this->red->m);
|
||||
$this->a = $this->a->toRed($this->red);
|
||||
$this->c = (new BN($conf["c"], 16))->toRed($this->red);
|
||||
$this->c2 = $this->c->redSqr();
|
||||
$this->d = (new BN($conf["d"], 16))->toRed($this->red);
|
||||
$this->dd = $this->d->redAdd($this->d);
|
||||
if (Utils::$ASSERT_ENABLED) {
|
||||
assert(!$this->twisted || $this->c->fromRed()->cmpn(1) == 0);
|
||||
}
|
||||
$this->oneC = ($conf["c"] | 0) == 1;
|
||||
}
|
||||
|
||||
public function _mulA($num) {
|
||||
if ($this->mOneA)
|
||||
return $num->redNeg();
|
||||
else
|
||||
return $this->a->redMul($num);
|
||||
}
|
||||
|
||||
public function _mulC($num) {
|
||||
if ($this->oneC)
|
||||
return $num;
|
||||
else
|
||||
return $this->c->redMul($num);
|
||||
}
|
||||
|
||||
// Just for compatibility with Short curve
|
||||
public function jpoint($x, $y, $z, $t = null) {
|
||||
return $this->point($x, $y, $z, $t);
|
||||
}
|
||||
|
||||
public function pointFromX($x, $odd = false) {
|
||||
$x = new BN($x, 16);
|
||||
if (!$x->red)
|
||||
$x = $x->toRed($this->red);
|
||||
|
||||
$x2 = $x->redSqr();
|
||||
$rhs = $this->c2->redSub($this->a->redMul($x2));
|
||||
$lhs = $this->one->redSub($this->c2->redMul($this->d)->redMul($x2));
|
||||
|
||||
$y2 = $rhs->redMul($lhs->redInvm());
|
||||
$y = $y2->redSqrt();
|
||||
if ($y->redSqr()->redSub($y2)->cmp($this->zero) != 0)
|
||||
throw new \Exception('invalid point');
|
||||
|
||||
$isOdd = $y->fromRed()->isOdd();
|
||||
if ($odd && !$isOdd || !$odd && $isOdd)
|
||||
$y = $y->redNeg();
|
||||
|
||||
return $this->point($x, $y);
|
||||
}
|
||||
|
||||
public function pointFromY($y, $odd = false) {
|
||||
$y = new BN($y, 16);
|
||||
if (!$y->red)
|
||||
$y = $y->toRed($this->red);
|
||||
|
||||
// x^2 = (y^2 - 1) / (d y^2 + 1)
|
||||
$y2 = $y->redSqr();
|
||||
$lhs = $y2->redSub($this->one);
|
||||
$rhs = $y2->redMul($this->d)->redAdd($this->one);
|
||||
$x2 = $lhs->redMul($rhs->redInvm());
|
||||
|
||||
if ($x2->cmp($this->zero) == 0) {
|
||||
if ($odd)
|
||||
throw new \Exception('invalid point');
|
||||
else
|
||||
return $this->point($this->zero, $y);
|
||||
}
|
||||
|
||||
$x = $x2->redSqrt();
|
||||
if ($x->redSqr()->redSub($x2)->cmp($this->zero) != 0)
|
||||
throw new \Exception('invalid point');
|
||||
|
||||
if ($x->isOdd() != $odd)
|
||||
$x = $x->redNeg();
|
||||
|
||||
return $this->point($x, $y);
|
||||
}
|
||||
|
||||
public function validate($point) {
|
||||
if ($point->isInfinity())
|
||||
return true;
|
||||
|
||||
// Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2)
|
||||
$point->normalize();
|
||||
|
||||
$x2 = $point->x->redSqr();
|
||||
$y2 = $point->y->redSqr();
|
||||
$lhs = $x2->redMul($this->a)->redAdd($y2);
|
||||
$rhs = $this->c2->redMul($this->one->redAdd($this->d->redMul($x2)->redMul($y2)));
|
||||
|
||||
return $lhs->cmp($rhs) == 0;
|
||||
}
|
||||
|
||||
public function pointFromJSON($obj) {
|
||||
return Point::fromJSON($this, $obj);
|
||||
}
|
||||
|
||||
public function point($x = null, $y = null, $z = null, $t = null) {
|
||||
return new Point($this, $x, $y, $z, $t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
namespace Elliptic\Curve\EdwardsCurve;
|
||||
|
||||
use BN\BN;
|
||||
|
||||
class Point extends \Elliptic\Curve\BaseCurve\Point
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
public $z;
|
||||
public $t;
|
||||
public $zOne;
|
||||
|
||||
function __construct($curve, $x = null, $y = null, $z = null, $t = null) {
|
||||
parent::__construct($curve, 'projective');
|
||||
if ($x == null && $y == null && $z == null) {
|
||||
$this->x = $this->curve->zero;
|
||||
$this->y = $this->curve->one;
|
||||
$this->z = $this->curve->one;
|
||||
$this->t = $this->curve->zero;
|
||||
$this->zOne = true;
|
||||
} else {
|
||||
$this->x = new BN($x, 16);
|
||||
$this->y = new BN($y, 16);
|
||||
$this->z = $z ? new BN($z, 16) : $this->curve->one;
|
||||
$this->t = $t ? new BN($t, 16) : null;
|
||||
if (!$this->x->red)
|
||||
$this->x = $this->x->toRed($this->curve->red);
|
||||
if (!$this->y->red)
|
||||
$this->y = $this->y->toRed($this->curve->red);
|
||||
if (!$this->z->red)
|
||||
$this->z = $this->z->toRed($this->curve->red);
|
||||
if ($this->t && !$this->t->red)
|
||||
$this->t = $this->t->toRed($this->curve->red);
|
||||
$this->zOne = $this->z == $this->curve->one;
|
||||
|
||||
// Use extended coordinates
|
||||
if ($this->curve->extended && !$this->t) {
|
||||
$this->t = $this->x->redMul($this->y);
|
||||
if (!$this->zOne)
|
||||
$this->t = $this->t->redMul($this->z->redInvm());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromJSON($curve, $obj) {
|
||||
return new Point($curve,
|
||||
isset($obj[0]) ? $obj[0] : null,
|
||||
isset($obj[1]) ? $obj[1] : null,
|
||||
isset($obj[2]) ? $obj[2] : null
|
||||
);
|
||||
}
|
||||
|
||||
public function inspect() {
|
||||
if ($this->isInfinity())
|
||||
return '<EC Point Infinity>';
|
||||
return '<EC Point x: ' . $this->x->fromRed()->toString(16, 2) .
|
||||
' y: ' . $this->y->fromRed()->toString(16, 2) .
|
||||
' z: ' . $this->z->fromRed()->toString(16, 2) . '>';
|
||||
}
|
||||
|
||||
public function isInfinity() {
|
||||
// XXX This code assumes that zero is always zero in red
|
||||
return $this->x->cmpn(0) == 0 &&
|
||||
$this->y->cmp($this->z) == 0;
|
||||
}
|
||||
|
||||
public function _extDbl() {
|
||||
// hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
// #doubling-dbl-2008-hwcd
|
||||
// 4M + 4S
|
||||
|
||||
// A = X1^2
|
||||
$a = $this->x->redSqr();
|
||||
// B = Y1^2
|
||||
$b = $this->y->redSqr();
|
||||
// C = 2 * Z1^2
|
||||
$c = $this->z->redSqr();
|
||||
$c = $c->redIAdd($c);
|
||||
// D = a * A
|
||||
$d = $this->curve->_mulA($a);
|
||||
// E = (X1 + Y1)^2 - A - B
|
||||
$e = $this->x->redAdd($this->y)->redSqr()->redISub($a)->redISub($b);
|
||||
// G = D + B
|
||||
$g = $d->redAdd($b);
|
||||
// F = G - C
|
||||
$f = $g->redSub($c);
|
||||
// H = D - B
|
||||
$h = $d->redSub($b);
|
||||
// X3 = E * F
|
||||
$nx = $e->redMul($f);
|
||||
// Y3 = G * H
|
||||
$ny = $g->redMul($h);
|
||||
// T3 = E * H
|
||||
$nt = $e->redMul($h);
|
||||
// Z3 = F * G
|
||||
$nz = $f->redMul($g);
|
||||
return $this->curve->point($nx, $ny, $nz, $nt);
|
||||
}
|
||||
|
||||
public function _projDbl() {
|
||||
// hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
|
||||
// #doubling-dbl-2008-bbjlp
|
||||
// #doubling-dbl-2007-bl
|
||||
// and others
|
||||
// Generally 3M + 4S or 2M + 4S
|
||||
|
||||
// B = (X1 + Y1)^2
|
||||
$b = $this->x->redAdd($this->y)->redSqr();
|
||||
// C = X1^2
|
||||
$c = $this->x->redSqr();
|
||||
// D = Y1^2
|
||||
$d = $this->y->redSqr();
|
||||
|
||||
if ($this->curve->twisted) {
|
||||
// E = a * C
|
||||
$e = $this->curve->_mulA($c);
|
||||
// F = E + D
|
||||
$f = $e->redAdd($d);
|
||||
if ($this->zOne) {
|
||||
// X3 = (B - C - D) * (F - 2)
|
||||
$nx = $b->redSub($c)->redSub($d)->redMul($f->redSub($this->curve->two));
|
||||
// Y3 = F * (E - D)
|
||||
$ny = $f->redMul($e->redSub($d));
|
||||
// Z3 = F^2 - 2 * F
|
||||
$nz = $f->redSqr()->redSub($f)->redSub($f);
|
||||
} else {
|
||||
// H = Z1^2
|
||||
$h = $this->z->redSqr();
|
||||
// J = F - 2 * H
|
||||
$j = $f->redSub($h)->redISub($h);
|
||||
// X3 = (B-C-D)*J
|
||||
$nx = $b->redSub($c)->redISub($d)->redMul($j);
|
||||
// Y3 = F * (E - D)
|
||||
$ny = $f->redMul($e->redSub($d));
|
||||
// Z3 = F * J
|
||||
$nz = $f->redMul($j);
|
||||
}
|
||||
} else {
|
||||
// E = C + D
|
||||
$e = $c->redAdd($d);
|
||||
// H = (c * Z1)^2
|
||||
$h = $this->curve->_mulC($this->c->redMul($this->z))->redSqr();
|
||||
// J = E - 2 * H
|
||||
$j = $e->redSub($h)->redSub($h);
|
||||
// X3 = c * (B - E) * J
|
||||
$nx = $this->curve->_mulC($b->redISub($e))->redMul($j);
|
||||
// Y3 = c * E * (C - D)
|
||||
$ny = $this->curve->_mulC($e)->redMul($c->redISub($d));
|
||||
// Z3 = E * J
|
||||
$nz = $e->redMul($j);
|
||||
}
|
||||
return $this->curve->point($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function dbl() {
|
||||
if ($this->isInfinity())
|
||||
return $this;
|
||||
|
||||
// Double in extended coordinates
|
||||
if ($this->curve->extended)
|
||||
return $this->_extDbl();
|
||||
else
|
||||
return $this->_projDbl();
|
||||
}
|
||||
|
||||
public function _extAdd($p) {
|
||||
// hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
// #addition-add-2008-hwcd-3
|
||||
// 8M
|
||||
|
||||
// A = (Y1 - X1) * (Y2 - X2)
|
||||
$a = $this->y->redSub($this->x)->redMul($p->y->redSub($p->x));
|
||||
// B = (Y1 + X1) * (Y2 + X2)
|
||||
$b = $this->y->redAdd($this->x)->redMul($p->y->redAdd($p->x));
|
||||
// C = T1 * k * T2
|
||||
$c = $this->t->redMul($this->curve->dd)->redMul($p->t);
|
||||
// D = Z1 * 2 * Z2
|
||||
$d = $this->z->redMul($p->z->redAdd($p->z));
|
||||
// E = B - A
|
||||
$e = $b->redSub($a);
|
||||
// F = D - C
|
||||
$f = $d->redSub($c);
|
||||
// G = D + C
|
||||
$g = $d->redAdd($c);
|
||||
// H = B + A
|
||||
$h = $b->redAdd($a);
|
||||
// X3 = E * F
|
||||
$nx = $e->redMul($f);
|
||||
// Y3 = G * H
|
||||
$ny = $g->redMul($h);
|
||||
// T3 = E * H
|
||||
$nt = $e->redMul($h);
|
||||
// Z3 = F * G
|
||||
$nz = $f->redMul($g);
|
||||
return $this->curve->point($nx, $ny, $nz, $nt);
|
||||
}
|
||||
|
||||
public function _projAdd($p) {
|
||||
// hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
|
||||
// #addition-add-2008-bbjlp
|
||||
// #addition-add-2007-bl
|
||||
// 10M + 1S
|
||||
|
||||
// A = Z1 * Z2
|
||||
$a = $this->z->redMul($p->z);
|
||||
// B = A^2
|
||||
$b = $a->redSqr();
|
||||
// C = X1 * X2
|
||||
$c = $this->x->redMul($p->x);
|
||||
// D = Y1 * Y2
|
||||
$d = $this->y->redMul($p->y);
|
||||
// E = d * C * D
|
||||
$e = $this->curve->d->redMul($c)->redMul($d);
|
||||
// F = B - E
|
||||
$f = $b->redSub($e);
|
||||
// G = B + E
|
||||
$g = $b->redAdd($e);
|
||||
// X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D)
|
||||
$tmp = $this->x->redAdd($this->y)->redMul($p->x->redAdd($p->y))->redISub($c)->redISub($d);
|
||||
$nx = $a->redMul($f)->redMul($tmp);
|
||||
if ($this->curve->twisted) {
|
||||
// Y3 = A * G * (D - a * C)
|
||||
$ny = $a->redMul($g)->redMul($d->redSub($this->curve->_mulA($c)));
|
||||
// Z3 = F * G
|
||||
$nz = $f->redMul($g);
|
||||
} else {
|
||||
// Y3 = A * G * (D - C)
|
||||
$ny = $a->redMul($g)->redMul($d->redSub($c));
|
||||
// Z3 = c * F * G
|
||||
$nz = $this->curve->_mulC($f)->redMul($g);
|
||||
}
|
||||
return $this->curve->point($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function add($p) {
|
||||
if ($this->isInfinity())
|
||||
return $p;
|
||||
if ($p->isInfinity())
|
||||
return $this;
|
||||
|
||||
if ($this->curve->extended)
|
||||
return $this->_extAdd($p);
|
||||
else
|
||||
return $this->_projAdd($p);
|
||||
}
|
||||
|
||||
public function mul($k) {
|
||||
if ($this->_hasDoubles($k))
|
||||
return $this->curve->_fixedNafMul($this, $k);
|
||||
else
|
||||
return $this->curve->_wnafMul($this, $k);
|
||||
}
|
||||
|
||||
public function mulAdd($k1, $p, $k2) {
|
||||
return $this->curve->_wnafMulAdd(1, [ $this, $p ], [ $k1, $k2 ], 2, false);
|
||||
}
|
||||
|
||||
public function jmulAdd($k1, $p, $k2) {
|
||||
return $this->curve->_wnafMulAdd(1, [ $this, $p ], [ $k1, $k2 ], 2, true);
|
||||
}
|
||||
|
||||
public function normalize() {
|
||||
if ($this->zOne)
|
||||
return $this;
|
||||
|
||||
// Normalize coordinates
|
||||
$zi = $this->z->redInvm();
|
||||
$this->x = $this->x->redMul($zi);
|
||||
$this->y = $this->y->redMul($zi);
|
||||
if ($this->t)
|
||||
$this->t = $this->t->redMul($zi);
|
||||
$this->z = $this->curve->one;
|
||||
$this->zOne = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function neg() {
|
||||
return $this->curve->point($this->x->redNeg(),
|
||||
$this->y,
|
||||
$this->z,
|
||||
($this->t != null) ? $this->t->redNeg() : null);
|
||||
}
|
||||
|
||||
public function getX() {
|
||||
$this->normalize();
|
||||
return $this->x->fromRed();
|
||||
}
|
||||
|
||||
public function getY() {
|
||||
$this->normalize();
|
||||
return $this->y->fromRed();
|
||||
}
|
||||
|
||||
public function eq($other) {
|
||||
return $this == $other ||
|
||||
$this->getX()->cmp($other->getX()) == 0 &&
|
||||
$this->getY()->cmp($other->getY()) == 0;
|
||||
}
|
||||
|
||||
public function eqXToP($x) {
|
||||
$rx = $x->toRed($this->curve->red)->redMul($this->z);
|
||||
if ($this->x->cmp($rx) == 0)
|
||||
return true;
|
||||
|
||||
$xc = $x->_clone();
|
||||
$t = $this->curve->redN->redMul($this->z);
|
||||
for (;;) {
|
||||
$xc->iadd($this->curve->n);
|
||||
if ($xc->cmp($this->curve->p) >= 0)
|
||||
return false;
|
||||
|
||||
$rx->redIAdd($t);
|
||||
if ($this->x->cmp($rx) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compatibility with BaseCurve
|
||||
public function toP() { return $this->normalize(); }
|
||||
public function mixedAdd($p) { return $this->add($p); }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
use Elliptic\Curve\MontCurve\Point;
|
||||
use Elliptic\Utils;
|
||||
use BN\BN;
|
||||
|
||||
class MontCurve extends BaseCurve
|
||||
{
|
||||
public $a;
|
||||
public $b;
|
||||
public $i4;
|
||||
public $a24;
|
||||
|
||||
function __construct($conf)
|
||||
{
|
||||
parent::__construct("mont", $conf);
|
||||
|
||||
$this->a = (new BN($conf["a"], 16))->toRed($this->red);
|
||||
$this->b = (new BN($conf["b"], 16))->toRed($this->red);
|
||||
$this->i4 = (new BN(4))->toRed($this->red)->redInvm();
|
||||
$this->a24 = $this->i4->redMul($this->a->redAdd($this->two));
|
||||
}
|
||||
|
||||
public function validate($point)
|
||||
{
|
||||
$x = $point->normalize()->x;
|
||||
$x2 = $x->redSqr();
|
||||
$rhs = $x2->redMul($x)->redAdd($x2->redMul($this->a))->redAdd($x);
|
||||
$y = $rhs->redSqr();
|
||||
|
||||
return $y->redSqr()->cmp($rhs) ===0;
|
||||
}
|
||||
|
||||
public function decodePoint($bytes, $enc = false) {
|
||||
return $this->point(Utils::toArray($bytes, $enc), 1);
|
||||
}
|
||||
|
||||
public function point($x, $z) {
|
||||
return new Point($this, $x, $z);
|
||||
}
|
||||
|
||||
public function pointFromJSON($obj) {
|
||||
return Point::fromJSON($this, $obj);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve\MontCurve;
|
||||
|
||||
use BN\BN;
|
||||
|
||||
class Point extends \Elliptic\Curve\BaseCurve\Point
|
||||
{
|
||||
public $x;
|
||||
public $z;
|
||||
|
||||
function __construct($curve, $x, $z)
|
||||
{
|
||||
parent::__construct($curve, "projective");
|
||||
if( $x == null && $z == null )
|
||||
{
|
||||
$this->x = $this->curve->one;
|
||||
$this->z = $this->curve->zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->x = new BN($x, 16);
|
||||
$this->z = new BN($z, 16);
|
||||
if( !$this->x->red )
|
||||
$this->x = $this->x->toRed($this->curve->red);
|
||||
if( !$this->z->red )
|
||||
$this->z = $this->z->toRed($this->curve->red);
|
||||
}
|
||||
}
|
||||
|
||||
public function precompute($power = null) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
protected function _encode($compact) {
|
||||
return $this->getX()->toArray("be", $this->curve->p->byteLength());
|
||||
}
|
||||
|
||||
public static function fromJSON($curve, $obj) {
|
||||
return new Point($curve, $obj[0], isset($obj[1]) ? $obj[1] : $curve->one);
|
||||
}
|
||||
|
||||
public function inspect()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return "<EC Point Infinity>";
|
||||
return "<EC Point x: " . $this->x->fromRed()->toString(16, 2) .
|
||||
" z: " . $this->z->fromRed()->toString(16, 2) . ">";
|
||||
}
|
||||
|
||||
public function isInfinity() {
|
||||
// XXX This code assumes that zero is always zero in red
|
||||
return $this->z->isZero();
|
||||
}
|
||||
|
||||
public function dbl()
|
||||
{
|
||||
// http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3
|
||||
// 2M + 2S + 4A
|
||||
|
||||
// A = X1 + Z1
|
||||
$a = $this->x->redAdd($this->z);
|
||||
// AA = A^2
|
||||
$aa = $a->redSqr();
|
||||
// B = X1 - Z1
|
||||
$b = $this->x->redSub($this->z);
|
||||
// BB = B^2
|
||||
$bb = $b->redSqr();
|
||||
// C = AA - BB
|
||||
$c = $aa->redSub($bb);
|
||||
// X3 = AA * BB
|
||||
$nx = $aa->redMul($bb);
|
||||
// Z3 = C * (BB + A24 * C)
|
||||
$nz = $c->redMul( $bb->redAdd($this->curve->a24->redMul($c)) );
|
||||
return $this->curve->point($nx, $nz);
|
||||
}
|
||||
|
||||
public function add($p) {
|
||||
throw new \Exception('Not supported on Montgomery curve');
|
||||
}
|
||||
|
||||
public function diffAdd($p, $diff)
|
||||
{
|
||||
// http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3
|
||||
// 4M + 2S + 6A
|
||||
|
||||
// A = X2 + Z2
|
||||
$a = $this->x->redAdd($this->z);
|
||||
// B = X2 - Z2
|
||||
$b = $this->x->redSub($this->z);
|
||||
// C = X3 + Z3
|
||||
$c = $p->x->redAdd($p->z);
|
||||
// D = X3 - Z3
|
||||
$d = $p->x->redSub($p->z);
|
||||
// DA = D * A
|
||||
$da = $d->redMul($a);
|
||||
// CB = C * B
|
||||
$cb = $c->redMul($b);
|
||||
// X5 = Z1 * (DA + CB)^2
|
||||
$nx = $diff->z->redMul($da->redAdd($cb)->redSqr());
|
||||
// Z5 = X1 * (DA - CB)^2
|
||||
$nz = $diff->x->redMul($da->redSub($cb)->redSqr());
|
||||
|
||||
return $this->curve->point($nx, $nz);
|
||||
}
|
||||
|
||||
public function mul($k)
|
||||
{
|
||||
$t = $k->_clone();
|
||||
$a = $this; // (N / 2) * Q + Q
|
||||
$b = $this->curve->point(null, null); // (N / 2) * Q
|
||||
$c = $this; // Q
|
||||
|
||||
$bits = array();
|
||||
while( !$t->isZero() )
|
||||
{
|
||||
// TODO: Maybe it is faster to use toString(2)?
|
||||
array_push($bits, $t->andln(1));
|
||||
$t->iushrn(1);
|
||||
}
|
||||
|
||||
for($i = count($bits) - 1; $i >= 0; $i--)
|
||||
{
|
||||
if( $bits[$i] === 0 )
|
||||
{
|
||||
// N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q
|
||||
$a = $a->diffAdd($b, $c);
|
||||
// N * Q = 2 * ((N / 2) * Q + Q))
|
||||
$b = $b->dbl();
|
||||
}
|
||||
else
|
||||
{
|
||||
// N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q)
|
||||
$b = $a->diffAdd($b, $c);
|
||||
// N * Q + Q = 2 * ((N / 2) * Q + Q)
|
||||
$a = $a->dbl();
|
||||
}
|
||||
}
|
||||
|
||||
return $b;
|
||||
}
|
||||
|
||||
public function eq($other) {
|
||||
return $this->getX()->cmp($other->getX()) === 0;
|
||||
}
|
||||
|
||||
public function normalize()
|
||||
{
|
||||
$this->x = $this->x->redMul($this->z->redInvm());
|
||||
$this->z = $this->curve->one;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getX() {
|
||||
$this->normalize();
|
||||
return $this->x->fromRed();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
class PresetCurve
|
||||
{
|
||||
public $curve;
|
||||
public $g;
|
||||
public $n;
|
||||
public $hash;
|
||||
|
||||
function __construct($options)
|
||||
{
|
||||
if ( $options["type"] === "short" )
|
||||
$this->curve = new ShortCurve($options);
|
||||
elseif ( $options["type"] === "edwards" )
|
||||
$this->curve = new EdwardsCurve($options);
|
||||
else
|
||||
$this->curve = new MontCurve($options);
|
||||
|
||||
$this->g = $this->curve->g;
|
||||
$this->n = $this->curve->n;
|
||||
$this->hash = isset($options["hash"]) ? $options["hash"] : null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
use Elliptic\Curve\ShortCurve\Point;
|
||||
use Elliptic\Curve\ShortCurve\JPoint;
|
||||
use Elliptic\Utils;
|
||||
use BN\BN;
|
||||
use \Exception;
|
||||
|
||||
class ShortCurve extends BaseCurve
|
||||
{
|
||||
public $a;
|
||||
public $b;
|
||||
public $tinv;
|
||||
public $zeroA;
|
||||
public $threeA;
|
||||
public $endo;
|
||||
private $_endoWnafT1;
|
||||
private $_endoWnafT2;
|
||||
|
||||
function __construct($conf)
|
||||
{
|
||||
parent::__construct("short", $conf);
|
||||
|
||||
$this->a = (new BN($conf["a"], 16))->toRed($this->red);
|
||||
$this->b = (new BN($conf["b"], 16))->toRed($this->red);
|
||||
$this->tinv = $this->two->redInvm();
|
||||
|
||||
$this->zeroA = $this->a->fromRed()->isZero();
|
||||
$this->threeA = $this->a->fromRed()->sub($this->p)->cmpn(-3) === 0;
|
||||
|
||||
// If curve is endomorphic, precalculate beta and lambda
|
||||
$this->endo = $this->_getEndomorphism($conf);
|
||||
$this->_endoWnafT1 = array(0,0,0,0);
|
||||
$this->_endoWnafT2 = array(0,0,0,0);
|
||||
}
|
||||
|
||||
private function _getEndomorphism($conf)
|
||||
{
|
||||
// No efficient endomorphism
|
||||
if( !$this->zeroA || !isset($this->g) || !isset($this->n) || $this->p->modn(3) != 1 )
|
||||
return null;
|
||||
|
||||
// Compute beta and lambda, that lambda * P = (beta * Px; Py)
|
||||
$beta = null;
|
||||
$lambda = null;
|
||||
if( isset($conf["beta"]) )
|
||||
$beta = (new BN($conf["beta"], 16))->toRed($this->red);
|
||||
else
|
||||
{
|
||||
$betas = $this->_getEndoRoots($this->p);
|
||||
// Choose smallest beta
|
||||
$beta = $betas[0]->cmp($betas[1]) < 0 ? $betas[0] : $betas[1];
|
||||
$beta = $beta->toRed($this->red);
|
||||
}
|
||||
|
||||
if( isset($conf["lambda"]) )
|
||||
$lambda = new BN($conf["lambda"], 16);
|
||||
else
|
||||
{
|
||||
// Choose the lambda that is matching selected beta
|
||||
$lambdas = $this->_getEndoRoots($this->n);
|
||||
if( $this->g->mul($lambdas[0])->x->cmp($this->g->x->redMul($beta)) == 0 )
|
||||
$lambda = $lambdas[0];
|
||||
else
|
||||
{
|
||||
$lambda = $lambdas[1];
|
||||
if (Utils::$ASSERT_ENABLED) {
|
||||
assert($this->g->mul($lambda)->x->cmp($this->g->x->redMul($beta)) === 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get basis vectors, used for balanced length-two representation
|
||||
$basis = null;
|
||||
if( !isset($conf["basis"]) )
|
||||
$basis = $this->_getEndoBasis($lambda);
|
||||
else
|
||||
{
|
||||
$callback = function($vector) {
|
||||
return array(
|
||||
"a" => new BN($vector["a"], 16),
|
||||
"b" => new BN($vector["b"], 16)
|
||||
);
|
||||
};
|
||||
$basis = array_map($callback, $conf["basis"]);
|
||||
}
|
||||
|
||||
return array(
|
||||
"beta" => $beta,
|
||||
"lambda" => $lambda,
|
||||
"basis" => $basis
|
||||
);
|
||||
}
|
||||
|
||||
private function _getEndoRoots($num)
|
||||
{
|
||||
// Find roots of for x^2 + x + 1 in F
|
||||
// Root = (-1 +- Sqrt(-3)) / 2
|
||||
//
|
||||
$red = $num === $this->p ? $this->red : BN::mont($num);
|
||||
$tinv = (new BN(2))->toRed($red)->redInvm();
|
||||
$ntinv = $tinv->redNeg();
|
||||
|
||||
$s = (new BN(3))->toRed($red)->redNeg()->redSqrt()->redMul($tinv);
|
||||
|
||||
return array(
|
||||
$ntinv->redAdd($s)->fromRed(),
|
||||
$ntinv->redSub($s)->fromRed()
|
||||
);
|
||||
}
|
||||
|
||||
private function _getEndoBasis($lambda)
|
||||
{
|
||||
// aprxSqrt >= sqrt(this.n)
|
||||
$aprxSqrt = $this->n->ushrn(intval($this->n->bitLength() / 2));
|
||||
|
||||
// 3.74
|
||||
// Run EGCD, until r(L + 1) < aprxSqrt
|
||||
$u = $lambda;
|
||||
$v = $this->n->_clone();
|
||||
$x1 = new BN(1);
|
||||
$y1 = new BN(0);
|
||||
$x2 = new BN(0);
|
||||
$y2 = new BN(1);
|
||||
|
||||
// NOTE: all vectors are roots of: a + b * lambda = 0 (mod n)
|
||||
$a0 = 0;
|
||||
$b0 = 0;
|
||||
// First vector
|
||||
$a1 = 0;
|
||||
$b1 = 0;
|
||||
// Second vector
|
||||
$a2 = 0;
|
||||
$b2 = 0;
|
||||
|
||||
$prevR = 0;
|
||||
$i = 0;
|
||||
$r = 0;
|
||||
$x = 0;
|
||||
|
||||
while( ! $u->isZero() )
|
||||
{
|
||||
$q = $v->div($u);
|
||||
$r = $v->sub($q->mul($u));
|
||||
$x = $x2->sub($q->mul($x1));
|
||||
$y = $y2->sub($q->mul($y2));
|
||||
|
||||
if( !$a1 && $r->cmp($aprxSqrt) < 0 )
|
||||
{
|
||||
$a0 = $prevR->neg();
|
||||
$b0 = $x1;
|
||||
$a1 = $r->neg();
|
||||
$b1 = $x;
|
||||
}
|
||||
elseif($a1 && ++$i === 2)
|
||||
break;
|
||||
|
||||
$prevR = $r;
|
||||
$v = $u;
|
||||
$u = $r;
|
||||
$x2 = $x1;
|
||||
$x1 = $x;
|
||||
$y2 = $y1;
|
||||
$y1 = $y;
|
||||
}
|
||||
$a2 = $r->neg();
|
||||
$b2 = $x;
|
||||
|
||||
$len1 = $a1->sqr()->add($b1->sqr());
|
||||
$len2 = $a2->sqr()->add($b2->sqr());
|
||||
if( $len2->cmp($len1) >= 0 )
|
||||
{
|
||||
$a2 = $a0;
|
||||
$b2 = $b0;
|
||||
}
|
||||
|
||||
// Normalize signs
|
||||
if( $a1->negative() )
|
||||
{
|
||||
$a1 = $a1->neg();
|
||||
$b1 = $b1->neg();
|
||||
}
|
||||
|
||||
if( $a2->negative() )
|
||||
{
|
||||
$a2 = $a2->neg();
|
||||
$b2 = $b2->neg();
|
||||
}
|
||||
|
||||
return array(
|
||||
array( "a" => $a1, "b" => $b1 ),
|
||||
array( "a" => $a2, "b" => $b2 ),
|
||||
);
|
||||
}
|
||||
|
||||
public function _endoSplit($k)
|
||||
{
|
||||
$basis = $this->endo["basis"];
|
||||
$v1 = $basis[0];
|
||||
$v2 = $basis[1];
|
||||
|
||||
$c1 = $v2["b"]->mul($k)->divRound($this->n);
|
||||
$c2 = $v1["b"]->neg()->mul($k)->divRound($this->n);
|
||||
|
||||
$p1 = $c1->mul($v1["a"]);
|
||||
$p2 = $c2->mul($v2["a"]);
|
||||
$q1 = $c1->mul($v1["b"]);
|
||||
$q2 = $c2->mul($v2["b"]);
|
||||
|
||||
//Calculate answer
|
||||
$k1 = $k->sub($p1)->sub($p2);
|
||||
$k2 = $q1->add($q2)->neg();
|
||||
|
||||
return array( "k1" => $k1, "k2" => $k2 );
|
||||
}
|
||||
|
||||
public function pointFromX($x, $odd)
|
||||
{
|
||||
$x = new BN($x, 16);
|
||||
if( !$x->red )
|
||||
$x = $x->toRed($this->red);
|
||||
|
||||
$y2 = $x->redSqr()->redMul($x)->redIAdd($x->redMul($this->a))->redIAdd($this->b);
|
||||
$y = $y2->redSqrt();
|
||||
if( $y->redSqr()->redSub($y2)->cmp($this->zero) !== 0 )
|
||||
throw new Exception("Invalid point");
|
||||
|
||||
// XXX Is there any way to tell if the number is odd without converting it
|
||||
// to non-red form?
|
||||
$isOdd = $y->fromRed()->isOdd();
|
||||
if( $odd != $isOdd )
|
||||
$y = $y->redNeg();
|
||||
|
||||
return $this->point($x, $y);
|
||||
}
|
||||
|
||||
public function validate($point)
|
||||
{
|
||||
if( $point->inf )
|
||||
return true;
|
||||
|
||||
$x = $point->x;
|
||||
$y = $point->y;
|
||||
|
||||
$ax = $this->a->redMul($x);
|
||||
$rhs = $x->redSqr()->redMul($x)->redIAdd($ax)->redIAdd($this->b);
|
||||
return $y->redSqr()->redISub($rhs)->isZero();
|
||||
}
|
||||
|
||||
public function _endoWnafMulAdd($points, $coeffs, $jacobianResult = false)
|
||||
{
|
||||
$npoints = &$this->_endoWnafT1;
|
||||
$ncoeffs = &$this->_endoWnafT2;
|
||||
|
||||
for($i = 0; $i < count($points); $i++)
|
||||
{
|
||||
$split = $this->_endoSplit($coeffs[$i]);
|
||||
$p = $points[$i];
|
||||
$beta = $p->_getBeta();
|
||||
|
||||
if( $split["k1"]->negative() )
|
||||
{
|
||||
$split["k1"]->ineg();
|
||||
$p = $p->neg(true);
|
||||
}
|
||||
|
||||
if( $split["k2"]->negative() )
|
||||
{
|
||||
$split["k2"]->ineg();
|
||||
$beta = $beta->neg(true);
|
||||
}
|
||||
|
||||
$npoints[$i * 2] = $p;
|
||||
$npoints[$i * 2 + 1] = $beta;
|
||||
$ncoeffs[$i * 2] = $split["k1"];
|
||||
$ncoeffs[$i * 2 + 1] = $split["k2"];
|
||||
}
|
||||
$res = $this->_wnafMulAdd(1, $npoints, $ncoeffs, $i * 2, $jacobianResult);
|
||||
|
||||
// Clean-up references to points and coefficients
|
||||
for($j = 0; $j < 2 * $i; $j++)
|
||||
{
|
||||
$npoints[$j] = null;
|
||||
$ncoeffs[$j] = null;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function point($x, $y, $isRed = false) {
|
||||
return new Point($this, $x, $y, $isRed);
|
||||
}
|
||||
|
||||
public function pointFromJSON($obj, $red) {
|
||||
return Point::fromJSON($this, $obj, $red);
|
||||
}
|
||||
|
||||
public function jpoint($x, $y, $z) {
|
||||
return new JPoint($this, $x, $y, $z);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,488 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve\ShortCurve;
|
||||
|
||||
use BN\BN;
|
||||
|
||||
class JPoint extends \Elliptic\Curve\BaseCurve\Point
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
public $z;
|
||||
public $zOne;
|
||||
|
||||
function __construct($curve, $x, $y, $z)
|
||||
{
|
||||
parent::__construct($curve, "jacobian");
|
||||
|
||||
if( $x == null && $y == null && $z == null )
|
||||
{
|
||||
$this->x = $this->curve->one;
|
||||
$this->y = $this->curve->one;
|
||||
$this->z = new BN(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->x = new BN($x, 16);
|
||||
$this->y = new BN($y, 16);
|
||||
$this->z = new BN($z, 16);
|
||||
}
|
||||
|
||||
if( !$this->x->red )
|
||||
$this->x = $this->x->toRed($this->curve->red);
|
||||
if( !$this->y->red )
|
||||
$this->y = $this->y->toRed($this->curve->red);
|
||||
if( !$this->z->red )
|
||||
$this->z = $this->z->toRed($this->curve->red);
|
||||
|
||||
return $this->zOne = $this->z == $this->curve->one;
|
||||
}
|
||||
|
||||
public function toP()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return $this->curve->point(null, null);
|
||||
|
||||
$zinv = $this->z->redInvm();
|
||||
$zinv2 = $zinv->redSqr();
|
||||
$ax = $this->x->redMul($zinv2);
|
||||
$ay = $this->y->redMul($zinv2)->redMul($zinv);
|
||||
|
||||
return $this->curve->point($ax, $ay);
|
||||
}
|
||||
|
||||
public function neg() {
|
||||
return $this->curve->jpoint($this->x, $this->y->redNeg(), $this->z);
|
||||
}
|
||||
|
||||
public function add($p)
|
||||
{
|
||||
// O + P = P
|
||||
if( $this->isInfinity() )
|
||||
return $p;
|
||||
|
||||
// P + O = P
|
||||
if( $p->isInfinity() )
|
||||
return $this;
|
||||
|
||||
// 12M + 4S + 7A
|
||||
$pz2 = $p->z->redSqr();
|
||||
$z2 = $this->z->redSqr();
|
||||
$u1 = $this->x->redMul($pz2);
|
||||
$u2 = $p->x->redMul($z2);
|
||||
$s1 = $this->y->redMul($pz2->redMul($p->z));
|
||||
$s2 = $p->y->redMul($z2->redMul($this->z));
|
||||
|
||||
$h = $u1->redSub($u2);
|
||||
$r = $s1->redSub($s2);
|
||||
|
||||
if( $h->isZero() )
|
||||
{
|
||||
if( ! $r->isZero() )
|
||||
return $this->curve->jpoint(null, null, null);
|
||||
else
|
||||
return $this->dbl();
|
||||
}
|
||||
|
||||
$h2 = $h->redSqr();
|
||||
$h3 = $h2->redMul($h);
|
||||
$v = $u1->redMul($h2);
|
||||
|
||||
$nx = $r->redSqr()->redIAdd($h3)->redISub($v)->redISub($v);
|
||||
$ny = $r->redMul($v->redISub($nx))->redISub($s1->redMul($h3));
|
||||
$nz = $this->z->redMul($p->z)->redMul($h);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function mixedAdd($p)
|
||||
{
|
||||
// O + P = P
|
||||
if( $this->isInfinity() )
|
||||
return $p->toJ();
|
||||
|
||||
// P + O = P
|
||||
if( $p->isInfinity() )
|
||||
return $this;
|
||||
|
||||
// 8M + 3S + 7A
|
||||
$z2 = $this->z->redSqr();
|
||||
$u1 = $this->x;
|
||||
$u2 = $p->x->redMul($z2);
|
||||
$s1 = $this->y;
|
||||
$s2 = $p->y->redMul($z2)->redMul($this->z);
|
||||
|
||||
$h = $u1->redSub($u2);
|
||||
$r = $s1->redSub($s2);
|
||||
|
||||
if( $h->isZero() )
|
||||
{
|
||||
if( ! $r->isZero() )
|
||||
return $this->curve->jpoint(null, null, null);
|
||||
else
|
||||
return $this->dbl();
|
||||
}
|
||||
|
||||
$h2 = $h->redSqr();
|
||||
$h3 = $h2->redMul($h);
|
||||
$v = $u1->redMul($h2);
|
||||
|
||||
$nx = $r->redSqr()->redIAdd($h3)->redISub($v)->redISub($v);
|
||||
$ny = $r->redMul($v->redISub($nx))->redISub($s1->redMul($h3));
|
||||
$nz = $this->z->redMul($h);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function dblp($pow = null)
|
||||
{
|
||||
if( $pow == 0 || $this->isInfinity() )
|
||||
return $this;
|
||||
|
||||
if( $pow == null )
|
||||
return $this->dbl();
|
||||
|
||||
if( $this->curve->zeroA || $this->curve->threeA )
|
||||
{
|
||||
$r = $this;
|
||||
for($i = 0; $i < $pow; $i++)
|
||||
$r = $r->dbl();
|
||||
return $r;
|
||||
}
|
||||
|
||||
// 1M + 2S + 1A + N * (4S + 5M + 8A)
|
||||
// N = 1 => 6M + 6S + 9A
|
||||
$jx = $this->x;
|
||||
$jy = $this->y;
|
||||
$jz = $this->z;
|
||||
$jz4 = $jz->redSqr()->redSqr();
|
||||
|
||||
//Reuse results
|
||||
$jyd = $jy->redAdd($jy);
|
||||
for($i = 0; $i < $pow; $i++)
|
||||
{
|
||||
$jx2 = $jx->redSqr();
|
||||
$jyd2 = $jyd->redSqr();
|
||||
$jyd4 = $jyd2->redSqr();
|
||||
$c = $jx2->redAdd($jx2)->redIAdd($jx2)->redIAdd($this->curve->a->redMul($jz4));
|
||||
|
||||
$t1 = $jx->redMul($jyd2);
|
||||
$nx = $c->redSqr()->redISub($t1->redAdd($t1));
|
||||
$t2 = $t1->redISub($nx);
|
||||
$dny = $c->redMul($t2);
|
||||
$dny = $dny->redIAdd($dny)->redISub($jyd4);
|
||||
$nz = $jyd->redMul($jz);
|
||||
if( ($i + 1) < $pow)
|
||||
$jz4 = $jz4->redMul($jyd4);
|
||||
|
||||
$jx = $nx;
|
||||
$jz = $nz;
|
||||
$jyd = $dny;
|
||||
}
|
||||
|
||||
return $this->curve->jpoint($jx, $jyd->redMul($this->curve->tinv), $jz);
|
||||
}
|
||||
|
||||
public function dbl()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return $this;
|
||||
|
||||
if( $this->curve->zeroA )
|
||||
return $this->_zeroDbl();
|
||||
elseif( $this->curve->threeA )
|
||||
return $this->_threeDbl();
|
||||
return $this->_dbl();
|
||||
}
|
||||
|
||||
private function _zOneDbl($withA)
|
||||
{
|
||||
$xx = $this->x->redSqr();
|
||||
$yy = $this->y->redSqr();
|
||||
$yyyy = $yy->redSqr();
|
||||
|
||||
// S = 2 * ((X1 + YY)^2 - XX - YYYY)
|
||||
$s = $this->x->redAdd($yy)->redSqr()->redISub($xx)->redISub($yyyy);
|
||||
$s = $s->redIAdd($s);
|
||||
|
||||
// M = 3 * XX + a; a = 0
|
||||
$m = null;
|
||||
if( $withA )
|
||||
$m = $xx->redAdd($xx)->redIAdd($xx)->redIAdd($this->curve->a);
|
||||
else
|
||||
$m = $xx->redAdd($xx)->redIAdd($xx);
|
||||
|
||||
// T = M ^ 2 - 2*S
|
||||
$t = $m->redSqr()->redISub($s)->redISub($s);
|
||||
|
||||
$yyyy8 = $yyyy->redIAdd($yyyy);
|
||||
$yyyy8 = $yyyy8->redIAdd($yyyy8);
|
||||
$yyyy8 = $yyyy8->redIAdd($yyyy8);
|
||||
|
||||
$ny = $m->redMul($s->redISub($t))->redISub($yyyy8);
|
||||
$nz = $this->y->redAdd($this->y);
|
||||
return $this->curve->jpoint($t, $ny, $nz);
|
||||
}
|
||||
|
||||
private function _zeroDbl()
|
||||
{
|
||||
// Z = 1
|
||||
if( $this->zOne )
|
||||
{
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
|
||||
// #doubling-mdbl-2007-bl
|
||||
// 1M + 5S + 14A
|
||||
return $this->_zOneDbl(false);
|
||||
}
|
||||
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
|
||||
// #doubling-dbl-2009-l
|
||||
// 2M + 5S + 13A
|
||||
|
||||
$a = $this->x->redSqr();
|
||||
$b = $this->y->redSqr();
|
||||
$c = $b->redSqr();
|
||||
// D = 2 * ((X1 + B)^2 - A - C)
|
||||
$d = $this->x->redAdd($b)->redSqr()->redISub($a)->redISub($c);
|
||||
$d = $d->redIAdd($d);
|
||||
$e = $a->redAdd($a)->redIAdd($a);
|
||||
$f = $e->redSqr();
|
||||
|
||||
$c8 = $c->redIAdd($c);
|
||||
$c8 = $c8->redIAdd($c8);
|
||||
$c8 = $c8->redIAdd($c8);
|
||||
|
||||
// X3 = F - 2 * D
|
||||
$nx = $f->redISub($d)->redISub($d);
|
||||
// Y3 = E * (D - X3) - 8 * C
|
||||
$ny = $e->redMul($d->redISub($nx))->redISub($c8);
|
||||
// Z3 = 2 * Y1 * Z1
|
||||
$nz = $this->y->redMul($this->z);
|
||||
$nz = $nz->redIAdd($nz);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
private function _threeDbl()
|
||||
{
|
||||
if( $this->zOne )
|
||||
{
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
|
||||
// #doubling-mdbl-2007-bl
|
||||
// 1M + 5S + 15A
|
||||
|
||||
// XX = X1^2
|
||||
$xx = $this->x->redSqr();
|
||||
// YY = Y1^2
|
||||
$yy = $this->y->redSqr();
|
||||
// YYYY = YY^2
|
||||
$yyyy = $yy->redSqr();
|
||||
// S = 2 * ((X1 + YY)^2 - XX - YYYY)
|
||||
$s = $this->x->redAdd($yy)->redSqr()->redISub($xx)->redISub($yyyy);
|
||||
$s = $s->redIAdd($s);
|
||||
// M = 3 * XX + a
|
||||
$m = $xx->redAdd($xx)->redIAdd($xx)->redIAdd($this->curve->a);
|
||||
// T = M^2 - 2 * S
|
||||
$t = $m->redSqr()->redISub($s)->redISub($s);
|
||||
// X3 = T
|
||||
$nx = $t;
|
||||
// Y3 = M * (S - T) - 8 * YYYY
|
||||
$yyyy8 = $yyyy->redIAdd($yyyy);
|
||||
$yyyy8 = $yyyy8->redIAdd($yyyy8);
|
||||
$yyyy8 = $yyyy8->redIAdd($yyyy8);
|
||||
$ny = $m->redMul($s->redISub($t))->redISub($yyyy8);
|
||||
// Z3 = 2 * Y1
|
||||
$nz = $this->y->redAdd($this->y);
|
||||
} else {
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
|
||||
// 3M + 5S
|
||||
|
||||
// delta = Z1^2
|
||||
$delta = $this->z->redSqr();
|
||||
// gamma = Y1^2
|
||||
$gamma = $this->y->redSqr();
|
||||
// beta = X1 * gamma
|
||||
$beta = $this->x->redMul($gamma);
|
||||
// alpha = 3 * (X1 - delta) * (X1 + delta)
|
||||
$alpha = $this->x->redSub($delta)->redMul($this->x->redAdd($delta));
|
||||
$alpha = $alpha->redAdd($alpha)->redIAdd($alpha);
|
||||
// X3 = alpha^2 - 8 * beta
|
||||
$beta4 = $beta->redIAdd($beta);
|
||||
$beta4 = $beta4->redIAdd($beta4);
|
||||
$beta8 = $beta4->redAdd($beta4);
|
||||
$nx = $alpha->redSqr()->redISub($beta8);
|
||||
// Z3 = (Y1 + Z1)^2 - gamma - delta
|
||||
$nz = $this->y->redAdd($this->z)->redSqr()->redISub($gamma)->redISub($delta);
|
||||
|
||||
$ggamma8 = $gamma->redSqr();
|
||||
$ggamma8 = $ggamma8->redIAdd($ggamma8);
|
||||
$ggamma8 = $ggamma8->redIAdd($ggamma8);
|
||||
$ggamma8 = $ggamma8->redIAdd($ggamma8);
|
||||
// Y3 = alpha * (4 * beta - X3) - 8 * gamma^2
|
||||
$ny = $alpha->redMul($beta4->redISub($nx))->redISub($ggamma8);
|
||||
}
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
private function _dbl()
|
||||
{
|
||||
// 4M + 6S + 10A
|
||||
$jx = $this->x;
|
||||
$jy = $this->y;
|
||||
$jz = $this->z;
|
||||
$jz4 = $jz->redSqr()->redSqr();
|
||||
|
||||
$jx2 = $jx->redSqr();
|
||||
$jy2 = $jy->redSqr();
|
||||
|
||||
$c = $jx2->redAdd($jx2)->redIAdd($jx2)->redIAdd($this->curve->a->redMul($jz4));
|
||||
$jxd4 = $jx->redAdd($jx);
|
||||
$jxd4 = $jxd4->redIAdd($jxd4);
|
||||
$t1 = $jxd4->redMul($jy2);
|
||||
$nx = $c->redSqr()->redISub($t1->redAdd($t1));
|
||||
$t2 = $t1->redISub($nx);
|
||||
|
||||
$jyd8 = $jy2->redSqr();
|
||||
$jyd8 = $jyd8->redIAdd($jyd8);
|
||||
$jyd8 = $jyd8->redIAdd($jyd8);
|
||||
$jyd8 = $jyd8->redIAdd($jyd8);
|
||||
|
||||
$ny = $c->redMul($t2)->redISub($jyd8);
|
||||
$nz = $jy->redAdd($jy)->redMul($jz);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function trpl()
|
||||
{
|
||||
if( !$this->curve->zeroA )
|
||||
return $this->dbl()->add($this);
|
||||
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl
|
||||
// 5M + 10S + ...
|
||||
|
||||
$xx = $this->x->redSqr();
|
||||
$yy = $this->y->redSqr();
|
||||
$zz = $this->z->redSqr();
|
||||
// YYYY = YY^2
|
||||
$yyyy = $yy->redSqr();
|
||||
|
||||
// M = 3 * XX + a * ZZ2; a = 0
|
||||
$m = $xx->redAdd($xx)->redIAdd($xx);
|
||||
// MM = M^2
|
||||
$mm = $m->redSqr();
|
||||
|
||||
// E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM
|
||||
$e = $this->x->redAdd($yy)->redSqr()->redISub($xx)->redISub($yyyy);
|
||||
$e = $e->redIAdd($e);
|
||||
$e = $e->redAdd($e)->redIAdd($e);
|
||||
$e = $e->redISub($mm);
|
||||
|
||||
$ee = $e->redSqr();
|
||||
// T = 16*YYYY
|
||||
$t = $yyyy->redIAdd($yyyy);
|
||||
$t = $t->redIAdd($t);
|
||||
$t = $t->redIAdd($t);
|
||||
$t = $t->redIAdd($t);
|
||||
|
||||
// U = (M + E)^2 - MM - EE - T
|
||||
$u = $m->redAdd($e)->redSqr()->redISub($mm)->redISub($ee)->redISub($t);
|
||||
|
||||
$yyu4 = $yy->redMul($u);
|
||||
$yyu4 = $yyu4->redIAdd($yyu4);
|
||||
$yyu4 = $yyu4->redIAdd($yyu4);
|
||||
|
||||
// X3 = 4 * (X1 * EE - 4 * YY * U)
|
||||
$nx = $this->x->redMul($ee)->redISub($yyu4);
|
||||
$nx = $nx->redIAdd($nx);
|
||||
$nx = $nx->redIAdd($nx);
|
||||
|
||||
// Y3 = 8 * Y1 * (U * (T - U) - E * EE)
|
||||
$ny = $this->y->redMul($u->redMul($t->redISub($u))->redISub($e->redMul($ee)));
|
||||
$ny = $ny->redIAdd($ny);
|
||||
$ny = $ny->redIAdd($ny);
|
||||
$ny = $ny->redIAdd($ny);
|
||||
|
||||
// Z3 = (Z1 + E)^2 - ZZ - EE
|
||||
$nz = $this->z->redAdd($e)->redSqr()->redISub($zz)->redISub($ee);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function mul($k, $kbase) {
|
||||
return $this->curve->_wnafMul($this, new BN($k, $kbase));
|
||||
}
|
||||
|
||||
public function eq($p)
|
||||
{
|
||||
if( $p->type == "affine" )
|
||||
return $this->eq($p->toJ());
|
||||
|
||||
if( $this == $p )
|
||||
return true;
|
||||
|
||||
// x1 * z2^2 == x2 * z1^2
|
||||
$z2 = $this->z->redSqr();
|
||||
$pz2 = $p->z->redSqr();
|
||||
if( ! $this->x->redMul($pz2)->redISub($p->x->redMul($z2))->isZero() )
|
||||
return false;
|
||||
|
||||
// y1 * z2^3 == y2 * z1^3
|
||||
$z3 = $z2->redMul($this->z);
|
||||
$pz3 = $pz2->redMul($p->z);
|
||||
|
||||
return $this->y->redMul($pz3)->redISub($p->y->redMul($z3))->isZero();
|
||||
}
|
||||
|
||||
public function eqXToP($x)
|
||||
{
|
||||
$zs = $this->z->redSqr();
|
||||
$rx = $x->toRed($this->curve->red)->redMul($zs);
|
||||
if( $this->x->cmp($rx) == 0 )
|
||||
return true;
|
||||
|
||||
$xc = $x->_clone();
|
||||
$t = $this->curve->redN->redMul($zs);
|
||||
|
||||
while(true)
|
||||
{
|
||||
$xc->iadd($this->curve->n);
|
||||
if( $xc->cmp($this->curve->p) >= 0 )
|
||||
return false;
|
||||
|
||||
$rx->redIAdd($t);
|
||||
if( $this->x->cmp($rx) == 0 )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function inspect()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return "<EC JPoint Infinity>";
|
||||
|
||||
return "<EC JPoint x: " . $this->x->toString(16, 2) .
|
||||
" y: " . $this->y->toString(16, 2) .
|
||||
" z: " . $this->z->toString(16, 2) . ">";
|
||||
}
|
||||
|
||||
public function __debugInfo() {
|
||||
return [
|
||||
"EC JPoint" => ($this->isInfinity() ?
|
||||
"Infinity" :
|
||||
[
|
||||
"x" => $this->x->toString(16,2),
|
||||
"y" => $this->y->toString(16,2),
|
||||
"z" => $this->z->toString(16,2)
|
||||
]
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
public function isInfinity() {
|
||||
// XXX This code assumes that zero is always zero in red
|
||||
return $this->z->isZero();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve\ShortCurve;
|
||||
|
||||
use JsonSerializable;
|
||||
use BN\BN;
|
||||
|
||||
class Point extends \Elliptic\Curve\BaseCurve\Point implements JsonSerializable
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
public $inf;
|
||||
|
||||
function __construct($curve, $x, $y, $isRed)
|
||||
{
|
||||
parent::__construct($curve, 'affine');
|
||||
|
||||
if( $x == null && $y == null )
|
||||
{
|
||||
$this->x = null;
|
||||
$this->y = null;
|
||||
$this->inf = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->x = new BN($x, 16);
|
||||
$this->y = new BN($y, 16);
|
||||
// Force redgomery representation when loading from JSON
|
||||
if( $isRed )
|
||||
{
|
||||
$this->x->forceRed($this->curve->red);
|
||||
$this->y->forceRed($this->curve->red);
|
||||
}
|
||||
|
||||
if( !$this->x->red )
|
||||
$this->x = $this->x->toRed($this->curve->red);
|
||||
if( !$this->y->red )
|
||||
$this->y = $this->y->toRed($this->curve->red);
|
||||
$this->inf = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function _getBeta()
|
||||
{
|
||||
if( !isset($this->curve->endo) )
|
||||
return null;
|
||||
|
||||
if( isset($this->precomputed) && isset($this->precomputed["beta"]) )
|
||||
return $this->precomputed["beta"];
|
||||
|
||||
$beta = $this->curve->point($this->x->redMul($this->curve->endo["beta"]), $this->y);
|
||||
if( isset($this->precomputed) )
|
||||
{
|
||||
$endoMul = function($p) {
|
||||
return $this->curve->point($p->x->redMul($this->curve->endo["beta"]), $p->y);
|
||||
};
|
||||
$beta->precomputed = array(
|
||||
"beta" => null,
|
||||
"naf" => null,
|
||||
"doubles" => null
|
||||
);
|
||||
|
||||
if( isset($this->precomputed["naf"]) )
|
||||
{
|
||||
$beta->precomputed["naf"] = array(
|
||||
"wnd" => $this->precomputed["naf"]["wnd"],
|
||||
"points" => array_map($endoMul, $this->precomputed["naf"]["points"])
|
||||
);
|
||||
}
|
||||
|
||||
if( isset($this->precomputed["doubles"]) )
|
||||
{
|
||||
$beta->precomputed["doubles"] = array(
|
||||
"step" => $this->precomputed["doubles"]["step"],
|
||||
"points" => array_map($endoMul, $this->precomputed["doubles"]["points"])
|
||||
);
|
||||
}
|
||||
$this->precomputed["beta"] = $beta;
|
||||
}
|
||||
return $beta;
|
||||
}
|
||||
|
||||
//toJSON()
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
$res = array($this->x, $this->y);
|
||||
|
||||
if( !isset($this->precomputed) )
|
||||
return $res;
|
||||
|
||||
$pre = array();
|
||||
$addPre = false;
|
||||
if( isset($this->precomputed["doubles"]) )
|
||||
{
|
||||
$pre["doubles"] = array(
|
||||
"step" => $this->precomputed["doubles"]["step"],
|
||||
"points" => array_slice($this->precomputed["doubles"]["points"], 1)
|
||||
);
|
||||
$addPre = true;
|
||||
}
|
||||
|
||||
if( isset($this->precomputed["naf"]) )
|
||||
{
|
||||
$pre["naf"] = array(
|
||||
"naf" => $this->precomputed["naf"]["wnd"],
|
||||
"points" => array_slice($this->precomputed["naf"]["points"], 1)
|
||||
);
|
||||
$addPre = true;
|
||||
}
|
||||
|
||||
if( $addPre )
|
||||
array_push($res, $pre);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function fromJSON($curve, $obj, $red)
|
||||
{
|
||||
if( is_string($obj) )
|
||||
$obj = json_decode($obj);
|
||||
|
||||
$point = $curve->point($obj[0], $obj[1], $red);
|
||||
if( count($obj) === 2 )
|
||||
return $point;
|
||||
|
||||
$pre = $obj[2];
|
||||
$point->precomputed = array("beta" => null);
|
||||
$obj2point = function($obj) use ($curve, $red) {
|
||||
return $curve->point($obj[0], $obj[1], $red);
|
||||
};
|
||||
|
||||
if( isset($pre["doubles"]) )
|
||||
{
|
||||
$tmp = array_map($obj2point, $pre["doubles"]["points"]);
|
||||
array_unshift($tmp, $point);
|
||||
$point->precomputed["doubles"] = array(
|
||||
"step" => $pre["doubles"]["step"],
|
||||
"points" => $tmp
|
||||
);
|
||||
}
|
||||
|
||||
if( isset($pre["naf"]) )
|
||||
{
|
||||
$tmp = array_map($obj2point, $pre["naf"]["points"]);
|
||||
array_unshift($tmp, $point);
|
||||
$point->precomputed["naf"] = array(
|
||||
"wnd" => $pre["naf"]["wnd"],
|
||||
"points" => $tmp
|
||||
);
|
||||
}
|
||||
|
||||
return $point;
|
||||
}
|
||||
|
||||
public function inspect()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return "<EC Point Infinity>";
|
||||
|
||||
return "<EC Point x: " . $this->x->fromRed()->toString(16, 2) .
|
||||
" y: " . $this->y->fromRed()->toString(16, 2) . ">";
|
||||
}
|
||||
|
||||
public function __debugInfo() {
|
||||
return [
|
||||
"EC Point" => ($this->isInfinity() ?
|
||||
"Infinity" :
|
||||
[
|
||||
"x" => $this->x->fromRed()->toString(16, 2),
|
||||
"y" => $this->y->fromRed()->toString(16, 2)
|
||||
])
|
||||
];
|
||||
}
|
||||
public function isInfinity() {
|
||||
return $this->inf;
|
||||
}
|
||||
|
||||
public function add($point)
|
||||
{
|
||||
// O + P = P
|
||||
if( $this->inf )
|
||||
return $point;
|
||||
|
||||
// P + O = P
|
||||
if( $point->inf )
|
||||
return $this;
|
||||
|
||||
// P + P = 2P
|
||||
if( $this->eq($point) )
|
||||
return $this->dbl();
|
||||
|
||||
// P + (-P) = O
|
||||
if( $this->neg()->eq($point) )
|
||||
return $this->curve->point(null, null);
|
||||
|
||||
// P + Q = O
|
||||
if( $this->x->cmp($point->x) === 0 )
|
||||
return $this->curve->point(null, null);
|
||||
|
||||
$c = $this->y->redSub($point->y);
|
||||
if( ! $c->isZero() )
|
||||
$c = $c->redMul($this->x->redSub($point->x)->redInvm());
|
||||
$nx = $c->redSqr()->redISub($this->x)->redISub($point->x);
|
||||
$ny = $c->redMul($this->x->redSub($nx))->redISub($this->y);
|
||||
|
||||
return $this->curve->point($nx, $ny);
|
||||
}
|
||||
|
||||
public function dbl()
|
||||
{
|
||||
if( $this->inf )
|
||||
return $this;
|
||||
|
||||
// 2P = 0
|
||||
$ys1 = $this->y->redAdd($this->y);
|
||||
if( $ys1->isZero() )
|
||||
return $this->curve->point(null, null);
|
||||
|
||||
$x2 = $this->x->redSqr();
|
||||
$dyinv = $ys1->redInvm();
|
||||
$c = $x2->redAdd($x2)->redIAdd($x2)->redIAdd($this->curve->a)->redMul($dyinv);
|
||||
|
||||
$nx = $c->redSqr()->redISub($this->x->redAdd($this->x));
|
||||
$ny = $c->redMul($this->x->redSub($nx))->redISub($this->y);
|
||||
|
||||
return $this->curve->point($nx, $ny);
|
||||
}
|
||||
|
||||
public function getX() {
|
||||
return $this->x->fromRed();
|
||||
}
|
||||
|
||||
public function getY() {
|
||||
return $this->y->fromRed();
|
||||
}
|
||||
|
||||
public function mul($k)
|
||||
{
|
||||
$k = new BN($k, 16);
|
||||
|
||||
if( $this->_hasDoubles($k) )
|
||||
return $this->curve->_fixedNafMul($this, $k);
|
||||
elseif( isset($this->curve->endo) )
|
||||
return $this->curve->_endoWnafMulAdd(array($this), array($k));
|
||||
|
||||
return $this->curve->_wnafMul($this, $k);
|
||||
}
|
||||
|
||||
public function mulAdd($k1, $p2, $k2, $j = false)
|
||||
{
|
||||
$points = array($this, $p2);
|
||||
$coeffs = array($k1, $k2);
|
||||
|
||||
if( isset($this->curve->endo) )
|
||||
return $this->curve->_endoWnafMulAdd($points, $coeffs, $j);
|
||||
|
||||
return $this->curve->_wnafMulAdd(1, $points, $coeffs, 2, $j);
|
||||
}
|
||||
|
||||
public function jmulAdd($k1, $p2, $k2) {
|
||||
return $this->mulAdd($k1, $p2, $k2, true);
|
||||
}
|
||||
|
||||
public function eq($point)
|
||||
{
|
||||
return (
|
||||
$this === $point ||
|
||||
$this->inf === $point->inf &&
|
||||
($this->inf || $this->x->cmp($point->x) === 0 && $this->y->cmp($point->y) === 0)
|
||||
);
|
||||
}
|
||||
|
||||
public function neg($precompute = false)
|
||||
{
|
||||
if( $this->inf )
|
||||
return $this;
|
||||
|
||||
$res = $this->curve->point($this->x, $this->y->redNeg());
|
||||
if( $precompute && isset($this->precomputed) )
|
||||
{
|
||||
$res->precomputed = array();
|
||||
$pre = $this->precomputed;
|
||||
$negate = function($point) {
|
||||
return $point->neg();
|
||||
};
|
||||
|
||||
if( isset($pre["naf"]) )
|
||||
{
|
||||
$res->precomputed["naf"] = array(
|
||||
"wnd" => $pre["naf"]["wnd"],
|
||||
"points" => array_map($negate, $pre["naf"]["points"])
|
||||
);
|
||||
}
|
||||
|
||||
if( isset($pre["doubles"]) )
|
||||
{
|
||||
$res->precomputed["doubles"] = array(
|
||||
"step" => $pre["doubles"]["step"],
|
||||
"points" => array_map($negate, $pre["doubles"]["points"])
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function toJ()
|
||||
{
|
||||
if( $this->inf )
|
||||
return $this->curve->jpoint(null, null, null);
|
||||
|
||||
return $this->curve->jpoint($this->x, $this->y, $this->curve->one);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
+990
@@ -0,0 +1,990 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic;
|
||||
|
||||
use Elliptic\Curve\PresetCurve;
|
||||
|
||||
class Curves
|
||||
{
|
||||
private static $curves;
|
||||
|
||||
public static function hasCurve($name) {
|
||||
return isset(self::$curves[$name]);
|
||||
}
|
||||
public static function getCurve($name) {
|
||||
if (!isset(self::$curves[$name])) {
|
||||
throw new \Exception('Unknown curve ' . $name);
|
||||
}
|
||||
return self::$curves[$name];
|
||||
}
|
||||
|
||||
public static function defineCurve($name, $options)
|
||||
{
|
||||
self::$curves[$name] = new PresetCurve($options);
|
||||
}
|
||||
}
|
||||
|
||||
$sha256 = [ "blockSize" => 512, "outSize" => 256, "hmacStrength" => 192, "padLength" => 64, "algo" => 'sha256' ];
|
||||
$sha224 = [ "blockSize" => 512, "outSize" => 224, "hmacStrength" => 192, "padLength" => 64, "algo" => 'sha224' ];
|
||||
$sha512 = [ "blockSize" => 1024, "outSize" => 512, "hmacStrength" => 192, "padLength" => 128, "algo" => 'sha512' ];
|
||||
$sha384 = [ "blockSize" => 1024, "outSize" => 384, "hmacStrength" => 192, "padLength" => 128, "algo" => 'sha384' ];
|
||||
$sha1 = [ "blockSize" => 512, "outSize" => 160, "hmacStrength" => 80, "padLength" => 64, "algo" => 'sha1' ];
|
||||
|
||||
Curves::defineCurve("p192", array(
|
||||
"type" => "short",
|
||||
"prime" => "p192",
|
||||
"p" => "ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff",
|
||||
"a" => "ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc",
|
||||
"b" => "64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1",
|
||||
"n" => "ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831",
|
||||
"hash" => $sha256,
|
||||
"gRed" => false,
|
||||
"g" => array(
|
||||
"188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012",
|
||||
"07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811"
|
||||
)
|
||||
));
|
||||
|
||||
Curves::defineCurve("p224", array(
|
||||
"type" => "short",
|
||||
"prime" => "p224",
|
||||
"p" => "ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001",
|
||||
"a" => "ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe",
|
||||
"b" => "b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4",
|
||||
"n" => "ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d",
|
||||
"hash" => $sha256,
|
||||
"gRed" => false,
|
||||
"g" => array(
|
||||
"b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21",
|
||||
"bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34"
|
||||
)
|
||||
));
|
||||
|
||||
Curves::defineCurve("p256", array(
|
||||
"type" => "short",
|
||||
"prime" => null,
|
||||
"p" => "ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff",
|
||||
"a" => "ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc",
|
||||
"b" => "5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b",
|
||||
"n" => "ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551",
|
||||
"hash" => $sha256,
|
||||
"gRed" => false,
|
||||
"g" => array(
|
||||
"6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296",
|
||||
"4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5"
|
||||
)
|
||||
));
|
||||
|
||||
Curves::defineCurve("p384", array(
|
||||
"type" => "short",
|
||||
"prime" => null,
|
||||
"p" => "ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff " .
|
||||
"fffffffe ffffffff 00000000 00000000 ffffffff",
|
||||
"a" => "ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff " .
|
||||
"fffffffe ffffffff 00000000 00000000 fffffffc",
|
||||
"b" => "b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f " .
|
||||
"5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef",
|
||||
"n" => "ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 " .
|
||||
"f4372ddf 581a0db2 48b0a77a ecec196a ccc52973",
|
||||
"hash" => $sha384,
|
||||
"gRed" => false,
|
||||
"g" => array(
|
||||
"aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 " .
|
||||
"5502f25d bf55296c 3a545e38 72760ab7",
|
||||
"3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 " .
|
||||
"0a60b1ce 1d7e819d 7a431d7c 90ea0e5f"
|
||||
)
|
||||
));
|
||||
|
||||
Curves::defineCurve("p521", array(
|
||||
"type" => "short",
|
||||
"prime" => null,
|
||||
"p" => "000001ff ffffffff ffffffff ffffffff ffffffff ffffffff " .
|
||||
"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff " .
|
||||
"ffffffff ffffffff ffffffff ffffffff ffffffff",
|
||||
"a" => "000001ff ffffffff ffffffff ffffffff ffffffff ffffffff " .
|
||||
"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff " .
|
||||
"ffffffff ffffffff ffffffff ffffffff fffffffc",
|
||||
"b" => "00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b " .
|
||||
"99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd " .
|
||||
"3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00",
|
||||
"n" => "000001ff ffffffff ffffffff ffffffff ffffffff ffffffff " .
|
||||
"ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 " .
|
||||
"f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409",
|
||||
"hash" => $sha512,
|
||||
"gRed" => false,
|
||||
"g" => array(
|
||||
"000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 " .
|
||||
"053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 " .
|
||||
"a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66",
|
||||
"00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 " .
|
||||
"579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 " .
|
||||
"3fad0761 353c7086 a272c240 88be9476 9fd16650"
|
||||
)
|
||||
));
|
||||
|
||||
Curves::defineCurve("curve25519", array(
|
||||
"type" => "mont",
|
||||
"prime" => "p25519",
|
||||
"p" => "7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed",
|
||||
"a" => "76d06",
|
||||
"b" => "0",
|
||||
"n" => "1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed",
|
||||
"hash" => $sha256,
|
||||
"gRed" => false,
|
||||
"g" => array(
|
||||
"9"
|
||||
)
|
||||
));
|
||||
|
||||
Curves:: defineCurve("curve25519-weier", array(
|
||||
"type" => "short",
|
||||
"prime" => "p25519",
|
||||
"p" => "7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed",
|
||||
"a" => "2aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa aaaaaa984914a144",
|
||||
"b" => "7b425ed097b425ed 097b425ed097b425 ed097b425ed097b4 260b5e9c7710c864",
|
||||
"n" => "1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed",
|
||||
"hash" => $sha256,
|
||||
"gRed" => false,
|
||||
"g" => array(
|
||||
"2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaad245a",
|
||||
"20ae19a1b8a086b4e01edd2c7748d14c923d4d7e6d7c61b229e9c5a27eced3d9"
|
||||
)
|
||||
));
|
||||
|
||||
Curves::defineCurve("ed25519", array(
|
||||
"type" => "edwards",
|
||||
"prime" => "p25519",
|
||||
"p" => "7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed",
|
||||
"a" => "-1",
|
||||
"c" => "1",
|
||||
// -121665 * (121666^(-1)) (mod P)
|
||||
"d" => "52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3",
|
||||
"n" => "1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed",
|
||||
"hash" => $sha256,
|
||||
"gRed" => false,
|
||||
"g" => array(
|
||||
"216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a",
|
||||
// 4/5
|
||||
"6666666666666666666666666666666666666666666666666666666666666658"
|
||||
)
|
||||
));
|
||||
|
||||
$pre = array(
|
||||
"doubles" => array(
|
||||
"step" => 4,
|
||||
"points" => array(
|
||||
array(
|
||||
"e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a",
|
||||
"f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821"
|
||||
),
|
||||
array(
|
||||
"8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508",
|
||||
"11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf"
|
||||
),
|
||||
array(
|
||||
"175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739",
|
||||
"d3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695"
|
||||
),
|
||||
array(
|
||||
"363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640",
|
||||
"4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9"
|
||||
),
|
||||
array(
|
||||
"8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c",
|
||||
"4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36"
|
||||
),
|
||||
array(
|
||||
"723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda",
|
||||
"96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f"
|
||||
),
|
||||
array(
|
||||
"eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa",
|
||||
"5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999"
|
||||
),
|
||||
array(
|
||||
"100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0",
|
||||
"cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09"
|
||||
),
|
||||
array(
|
||||
"e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d",
|
||||
"9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d"
|
||||
),
|
||||
array(
|
||||
"feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d",
|
||||
"e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088"
|
||||
),
|
||||
array(
|
||||
"da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1",
|
||||
"9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d"
|
||||
),
|
||||
array(
|
||||
"53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0",
|
||||
"5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8"
|
||||
),
|
||||
array(
|
||||
"8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047",
|
||||
"10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a"
|
||||
),
|
||||
array(
|
||||
"385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862",
|
||||
"283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453"
|
||||
),
|
||||
array(
|
||||
"6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7",
|
||||
"7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160"
|
||||
),
|
||||
array(
|
||||
"3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd",
|
||||
"56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0"
|
||||
),
|
||||
array(
|
||||
"85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83",
|
||||
"7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6"
|
||||
),
|
||||
array(
|
||||
"948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a",
|
||||
"53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589"
|
||||
),
|
||||
array(
|
||||
"6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8",
|
||||
"bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17"
|
||||
),
|
||||
array(
|
||||
"e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d",
|
||||
"4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda"
|
||||
),
|
||||
array(
|
||||
"e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725",
|
||||
"7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd"
|
||||
),
|
||||
array(
|
||||
"213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754",
|
||||
"4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2"
|
||||
),
|
||||
array(
|
||||
"4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c",
|
||||
"17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6"
|
||||
),
|
||||
array(
|
||||
"fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6",
|
||||
"6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f"
|
||||
),
|
||||
array(
|
||||
"76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39",
|
||||
"c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01"
|
||||
),
|
||||
array(
|
||||
"c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891",
|
||||
"893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3"
|
||||
),
|
||||
array(
|
||||
"d895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b",
|
||||
"febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f"
|
||||
),
|
||||
array(
|
||||
"b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03",
|
||||
"2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7"
|
||||
),
|
||||
array(
|
||||
"e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d",
|
||||
"eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78"
|
||||
),
|
||||
array(
|
||||
"a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070",
|
||||
"7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1"
|
||||
),
|
||||
array(
|
||||
"90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4",
|
||||
"e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150"
|
||||
),
|
||||
array(
|
||||
"8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da",
|
||||
"662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82"
|
||||
),
|
||||
array(
|
||||
"e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11",
|
||||
"1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc"
|
||||
),
|
||||
array(
|
||||
"8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e",
|
||||
"efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b"
|
||||
),
|
||||
array(
|
||||
"e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41",
|
||||
"2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51"
|
||||
),
|
||||
array(
|
||||
"b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef",
|
||||
"67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45"
|
||||
),
|
||||
array(
|
||||
"d68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8",
|
||||
"db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120"
|
||||
),
|
||||
array(
|
||||
"324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d",
|
||||
"648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84"
|
||||
),
|
||||
array(
|
||||
"4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96",
|
||||
"35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d"
|
||||
),
|
||||
array(
|
||||
"9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd",
|
||||
"ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d"
|
||||
),
|
||||
array(
|
||||
"6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5",
|
||||
"9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8"
|
||||
),
|
||||
array(
|
||||
"a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266",
|
||||
"40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8"
|
||||
),
|
||||
array(
|
||||
"7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71",
|
||||
"34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac"
|
||||
),
|
||||
array(
|
||||
"928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac",
|
||||
"c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f"
|
||||
),
|
||||
array(
|
||||
"85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751",
|
||||
"1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962"
|
||||
),
|
||||
array(
|
||||
"ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e",
|
||||
"493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907"
|
||||
),
|
||||
array(
|
||||
"827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241",
|
||||
"c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec"
|
||||
),
|
||||
array(
|
||||
"eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3",
|
||||
"be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d"
|
||||
),
|
||||
array(
|
||||
"e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f",
|
||||
"4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414"
|
||||
),
|
||||
array(
|
||||
"1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19",
|
||||
"aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd"
|
||||
),
|
||||
array(
|
||||
"146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be",
|
||||
"b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0"
|
||||
),
|
||||
array(
|
||||
"fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9",
|
||||
"6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811"
|
||||
),
|
||||
array(
|
||||
"da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2",
|
||||
"8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1"
|
||||
),
|
||||
array(
|
||||
"a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13",
|
||||
"7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c"
|
||||
),
|
||||
array(
|
||||
"174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c",
|
||||
"ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73"
|
||||
),
|
||||
array(
|
||||
"959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba",
|
||||
"2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd"
|
||||
),
|
||||
array(
|
||||
"d2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151",
|
||||
"e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405"
|
||||
),
|
||||
array(
|
||||
"64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073",
|
||||
"d99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589"
|
||||
),
|
||||
array(
|
||||
"8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458",
|
||||
"38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e"
|
||||
),
|
||||
array(
|
||||
"13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b",
|
||||
"69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27"
|
||||
),
|
||||
array(
|
||||
"bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366",
|
||||
"d3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1"
|
||||
),
|
||||
array(
|
||||
"8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa",
|
||||
"40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482"
|
||||
),
|
||||
array(
|
||||
"8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0",
|
||||
"620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945"
|
||||
),
|
||||
array(
|
||||
"dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787",
|
||||
"7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573"
|
||||
),
|
||||
array(
|
||||
"f710d79d9eb962297e4f6232b40e8f7feb2bc63814614d692c12de752408221e",
|
||||
"ea98e67232d3b3295d3b535532115ccac8612c721851617526ae47a9c77bfc82"
|
||||
)
|
||||
)
|
||||
),
|
||||
"naf" => array(
|
||||
"wnd" => 7,
|
||||
"points" => array(
|
||||
array(
|
||||
"f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9",
|
||||
"388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672"
|
||||
),
|
||||
array(
|
||||
"2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4",
|
||||
"d8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6"
|
||||
),
|
||||
array(
|
||||
"5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc",
|
||||
"6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da"
|
||||
),
|
||||
array(
|
||||
"acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe",
|
||||
"cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37"
|
||||
),
|
||||
array(
|
||||
"774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb",
|
||||
"d984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b"
|
||||
),
|
||||
array(
|
||||
"f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8",
|
||||
"ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81"
|
||||
),
|
||||
array(
|
||||
"d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e",
|
||||
"581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58"
|
||||
),
|
||||
array(
|
||||
"defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34",
|
||||
"4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77"
|
||||
),
|
||||
array(
|
||||
"2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c",
|
||||
"85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a"
|
||||
),
|
||||
array(
|
||||
"352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5",
|
||||
"321eb4075348f534d59c18259dda3e1f4a1b3b2e71b1039c67bd3d8bcf81998c"
|
||||
),
|
||||
array(
|
||||
"2fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f",
|
||||
"2de1068295dd865b64569335bd5dd80181d70ecfc882648423ba76b532b7d67"
|
||||
),
|
||||
array(
|
||||
"9248279b09b4d68dab21a9b066edda83263c3d84e09572e269ca0cd7f5453714",
|
||||
"73016f7bf234aade5d1aa71bdea2b1ff3fc0de2a887912ffe54a32ce97cb3402"
|
||||
),
|
||||
array(
|
||||
"daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729",
|
||||
"a69dce4a7d6c98e8d4a1aca87ef8d7003f83c230f3afa726ab40e52290be1c55"
|
||||
),
|
||||
array(
|
||||
"c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db",
|
||||
"2119a460ce326cdc76c45926c982fdac0e106e861edf61c5a039063f0e0e6482"
|
||||
),
|
||||
array(
|
||||
"6a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4",
|
||||
"e022cf42c2bd4a708b3f5126f16a24ad8b33ba48d0423b6efd5e6348100d8a82"
|
||||
),
|
||||
array(
|
||||
"1697ffa6fd9de627c077e3d2fe541084ce13300b0bec1146f95ae57f0d0bd6a5",
|
||||
"b9c398f186806f5d27561506e4557433a2cf15009e498ae7adee9d63d01b2396"
|
||||
),
|
||||
array(
|
||||
"605bdb019981718b986d0f07e834cb0d9deb8360ffb7f61df982345ef27a7479",
|
||||
"2972d2de4f8d20681a78d93ec96fe23c26bfae84fb14db43b01e1e9056b8c49"
|
||||
),
|
||||
array(
|
||||
"62d14dab4150bf497402fdc45a215e10dcb01c354959b10cfe31c7e9d87ff33d",
|
||||
"80fc06bd8cc5b01098088a1950eed0db01aa132967ab472235f5642483b25eaf"
|
||||
),
|
||||
array(
|
||||
"80c60ad0040f27dade5b4b06c408e56b2c50e9f56b9b8b425e555c2f86308b6f",
|
||||
"1c38303f1cc5c30f26e66bad7fe72f70a65eed4cbe7024eb1aa01f56430bd57a"
|
||||
),
|
||||
array(
|
||||
"7a9375ad6167ad54aa74c6348cc54d344cc5dc9487d847049d5eabb0fa03c8fb",
|
||||
"d0e3fa9eca8726909559e0d79269046bdc59ea10c70ce2b02d499ec224dc7f7"
|
||||
),
|
||||
array(
|
||||
"d528ecd9b696b54c907a9ed045447a79bb408ec39b68df504bb51f459bc3ffc9",
|
||||
"eecf41253136e5f99966f21881fd656ebc4345405c520dbc063465b521409933"
|
||||
),
|
||||
array(
|
||||
"49370a4b5f43412ea25f514e8ecdad05266115e4a7ecb1387231808f8b45963",
|
||||
"758f3f41afd6ed428b3081b0512fd62a54c3f3afbb5b6764b653052a12949c9a"
|
||||
),
|
||||
array(
|
||||
"77f230936ee88cbbd73df930d64702ef881d811e0e1498e2f1c13eb1fc345d74",
|
||||
"958ef42a7886b6400a08266e9ba1b37896c95330d97077cbbe8eb3c7671c60d6"
|
||||
),
|
||||
array(
|
||||
"f2dac991cc4ce4b9ea44887e5c7c0bce58c80074ab9d4dbaeb28531b7739f530",
|
||||
"e0dedc9b3b2f8dad4da1f32dec2531df9eb5fbeb0598e4fd1a117dba703a3c37"
|
||||
),
|
||||
array(
|
||||
"463b3d9f662621fb1b4be8fbbe2520125a216cdfc9dae3debcba4850c690d45b",
|
||||
"5ed430d78c296c3543114306dd8622d7c622e27c970a1de31cb377b01af7307e"
|
||||
),
|
||||
array(
|
||||
"f16f804244e46e2a09232d4aff3b59976b98fac14328a2d1a32496b49998f247",
|
||||
"cedabd9b82203f7e13d206fcdf4e33d92a6c53c26e5cce26d6579962c4e31df6"
|
||||
),
|
||||
array(
|
||||
"caf754272dc84563b0352b7a14311af55d245315ace27c65369e15f7151d41d1",
|
||||
"cb474660ef35f5f2a41b643fa5e460575f4fa9b7962232a5c32f908318a04476"
|
||||
),
|
||||
array(
|
||||
"2600ca4b282cb986f85d0f1709979d8b44a09c07cb86d7c124497bc86f082120",
|
||||
"4119b88753c15bd6a693b03fcddbb45d5ac6be74ab5f0ef44b0be9475a7e4b40"
|
||||
),
|
||||
array(
|
||||
"7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435",
|
||||
"91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61"
|
||||
),
|
||||
array(
|
||||
"754e3239f325570cdbbf4a87deee8a66b7f2b33479d468fbc1a50743bf56cc18",
|
||||
"673fb86e5bda30fb3cd0ed304ea49a023ee33d0197a695d0c5d98093c536683"
|
||||
),
|
||||
array(
|
||||
"e3e6bd1071a1e96aff57859c82d570f0330800661d1c952f9fe2694691d9b9e8",
|
||||
"59c9e0bba394e76f40c0aa58379a3cb6a5a2283993e90c4167002af4920e37f5"
|
||||
),
|
||||
array(
|
||||
"186b483d056a033826ae73d88f732985c4ccb1f32ba35f4b4cc47fdcf04aa6eb",
|
||||
"3b952d32c67cf77e2e17446e204180ab21fb8090895138b4a4a797f86e80888b"
|
||||
),
|
||||
array(
|
||||
"df9d70a6b9876ce544c98561f4be4f725442e6d2b737d9c91a8321724ce0963f",
|
||||
"55eb2dafd84d6ccd5f862b785dc39d4ab157222720ef9da217b8c45cf2ba2417"
|
||||
),
|
||||
array(
|
||||
"5edd5cc23c51e87a497ca815d5dce0f8ab52554f849ed8995de64c5f34ce7143",
|
||||
"efae9c8dbc14130661e8cec030c89ad0c13c66c0d17a2905cdc706ab7399a868"
|
||||
),
|
||||
array(
|
||||
"290798c2b6476830da12fe02287e9e777aa3fba1c355b17a722d362f84614fba",
|
||||
"e38da76dcd440621988d00bcf79af25d5b29c094db2a23146d003afd41943e7a"
|
||||
),
|
||||
array(
|
||||
"af3c423a95d9f5b3054754efa150ac39cd29552fe360257362dfdecef4053b45",
|
||||
"f98a3fd831eb2b749a93b0e6f35cfb40c8cd5aa667a15581bc2feded498fd9c6"
|
||||
),
|
||||
array(
|
||||
"766dbb24d134e745cccaa28c99bf274906bb66b26dcf98df8d2fed50d884249a",
|
||||
"744b1152eacbe5e38dcc887980da38b897584a65fa06cedd2c924f97cbac5996"
|
||||
),
|
||||
array(
|
||||
"59dbf46f8c94759ba21277c33784f41645f7b44f6c596a58ce92e666191abe3e",
|
||||
"c534ad44175fbc300f4ea6ce648309a042ce739a7919798cd85e216c4a307f6e"
|
||||
),
|
||||
array(
|
||||
"f13ada95103c4537305e691e74e9a4a8dd647e711a95e73cb62dc6018cfd87b8",
|
||||
"e13817b44ee14de663bf4bc808341f326949e21a6a75c2570778419bdaf5733d"
|
||||
),
|
||||
array(
|
||||
"7754b4fa0e8aced06d4167a2c59cca4cda1869c06ebadfb6488550015a88522c",
|
||||
"30e93e864e669d82224b967c3020b8fa8d1e4e350b6cbcc537a48b57841163a2"
|
||||
),
|
||||
array(
|
||||
"948dcadf5990e048aa3874d46abef9d701858f95de8041d2a6828c99e2262519",
|
||||
"e491a42537f6e597d5d28a3224b1bc25df9154efbd2ef1d2cbba2cae5347d57e"
|
||||
),
|
||||
array(
|
||||
"7962414450c76c1689c7b48f8202ec37fb224cf5ac0bfa1570328a8a3d7c77ab",
|
||||
"100b610ec4ffb4760d5c1fc133ef6f6b12507a051f04ac5760afa5b29db83437"
|
||||
),
|
||||
array(
|
||||
"3514087834964b54b15b160644d915485a16977225b8847bb0dd085137ec47ca",
|
||||
"ef0afbb2056205448e1652c48e8127fc6039e77c15c2378b7e7d15a0de293311"
|
||||
),
|
||||
array(
|
||||
"d3cc30ad6b483e4bc79ce2c9dd8bc54993e947eb8df787b442943d3f7b527eaf",
|
||||
"8b378a22d827278d89c5e9be8f9508ae3c2ad46290358630afb34db04eede0a4"
|
||||
),
|
||||
array(
|
||||
"1624d84780732860ce1c78fcbfefe08b2b29823db913f6493975ba0ff4847610",
|
||||
"68651cf9b6da903e0914448c6cd9d4ca896878f5282be4c8cc06e2a404078575"
|
||||
),
|
||||
array(
|
||||
"733ce80da955a8a26902c95633e62a985192474b5af207da6df7b4fd5fc61cd4",
|
||||
"f5435a2bd2badf7d485a4d8b8db9fcce3e1ef8e0201e4578c54673bc1dc5ea1d"
|
||||
),
|
||||
array(
|
||||
"15d9441254945064cf1a1c33bbd3b49f8966c5092171e699ef258dfab81c045c",
|
||||
"d56eb30b69463e7234f5137b73b84177434800bacebfc685fc37bbe9efe4070d"
|
||||
),
|
||||
array(
|
||||
"a1d0fcf2ec9de675b612136e5ce70d271c21417c9d2b8aaaac138599d0717940",
|
||||
"edd77f50bcb5a3cab2e90737309667f2641462a54070f3d519212d39c197a629"
|
||||
),
|
||||
array(
|
||||
"e22fbe15c0af8ccc5780c0735f84dbe9a790badee8245c06c7ca37331cb36980",
|
||||
"a855babad5cd60c88b430a69f53a1a7a38289154964799be43d06d77d31da06"
|
||||
),
|
||||
array(
|
||||
"311091dd9860e8e20ee13473c1155f5f69635e394704eaa74009452246cfa9b3",
|
||||
"66db656f87d1f04fffd1f04788c06830871ec5a64feee685bd80f0b1286d8374"
|
||||
),
|
||||
array(
|
||||
"34c1fd04d301be89b31c0442d3e6ac24883928b45a9340781867d4232ec2dbdf",
|
||||
"9414685e97b1b5954bd46f730174136d57f1ceeb487443dc5321857ba73abee"
|
||||
),
|
||||
array(
|
||||
"f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63",
|
||||
"4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1"
|
||||
),
|
||||
array(
|
||||
"d7b8740f74a8fbaab1f683db8f45de26543a5490bca627087236912469a0b448",
|
||||
"fa77968128d9c92ee1010f337ad4717eff15db5ed3c049b3411e0315eaa4593b"
|
||||
),
|
||||
array(
|
||||
"32d31c222f8f6f0ef86f7c98d3a3335ead5bcd32abdd94289fe4d3091aa824bf",
|
||||
"5f3032f5892156e39ccd3d7915b9e1da2e6dac9e6f26e961118d14b8462e1661"
|
||||
),
|
||||
array(
|
||||
"7461f371914ab32671045a155d9831ea8793d77cd59592c4340f86cbc18347b5",
|
||||
"8ec0ba238b96bec0cbdddcae0aa442542eee1ff50c986ea6b39847b3cc092ff6"
|
||||
),
|
||||
array(
|
||||
"ee079adb1df1860074356a25aa38206a6d716b2c3e67453d287698bad7b2b2d6",
|
||||
"8dc2412aafe3be5c4c5f37e0ecc5f9f6a446989af04c4e25ebaac479ec1c8c1e"
|
||||
),
|
||||
array(
|
||||
"16ec93e447ec83f0467b18302ee620f7e65de331874c9dc72bfd8616ba9da6b5",
|
||||
"5e4631150e62fb40d0e8c2a7ca5804a39d58186a50e497139626778e25b0674d"
|
||||
),
|
||||
array(
|
||||
"eaa5f980c245f6f038978290afa70b6bd8855897f98b6aa485b96065d537bd99",
|
||||
"f65f5d3e292c2e0819a528391c994624d784869d7e6ea67fb18041024edc07dc"
|
||||
),
|
||||
array(
|
||||
"78c9407544ac132692ee1910a02439958ae04877151342ea96c4b6b35a49f51",
|
||||
"f3e0319169eb9b85d5404795539a5e68fa1fbd583c064d2462b675f194a3ddb4"
|
||||
),
|
||||
array(
|
||||
"494f4be219a1a77016dcd838431aea0001cdc8ae7a6fc688726578d9702857a5",
|
||||
"42242a969283a5f339ba7f075e36ba2af925ce30d767ed6e55f4b031880d562c"
|
||||
),
|
||||
array(
|
||||
"a598a8030da6d86c6bc7f2f5144ea549d28211ea58faa70ebf4c1e665c1fe9b5",
|
||||
"204b5d6f84822c307e4b4a7140737aec23fc63b65b35f86a10026dbd2d864e6b"
|
||||
),
|
||||
array(
|
||||
"c41916365abb2b5d09192f5f2dbeafec208f020f12570a184dbadc3e58595997",
|
||||
"4f14351d0087efa49d245b328984989d5caf9450f34bfc0ed16e96b58fa9913"
|
||||
),
|
||||
array(
|
||||
"841d6063a586fa475a724604da03bc5b92a2e0d2e0a36acfe4c73a5514742881",
|
||||
"73867f59c0659e81904f9a1c7543698e62562d6744c169ce7a36de01a8d6154"
|
||||
),
|
||||
array(
|
||||
"5e95bb399a6971d376026947f89bde2f282b33810928be4ded112ac4d70e20d5",
|
||||
"39f23f366809085beebfc71181313775a99c9aed7d8ba38b161384c746012865"
|
||||
),
|
||||
array(
|
||||
"36e4641a53948fd476c39f8a99fd974e5ec07564b5315d8bf99471bca0ef2f66",
|
||||
"d2424b1b1abe4eb8164227b085c9aa9456ea13493fd563e06fd51cf5694c78fc"
|
||||
),
|
||||
array(
|
||||
"336581ea7bfbbb290c191a2f507a41cf5643842170e914faeab27c2c579f726",
|
||||
"ead12168595fe1be99252129b6e56b3391f7ab1410cd1e0ef3dcdcabd2fda224"
|
||||
),
|
||||
array(
|
||||
"8ab89816dadfd6b6a1f2634fcf00ec8403781025ed6890c4849742706bd43ede",
|
||||
"6fdcef09f2f6d0a044e654aef624136f503d459c3e89845858a47a9129cdd24e"
|
||||
),
|
||||
array(
|
||||
"1e33f1a746c9c5778133344d9299fcaa20b0938e8acff2544bb40284b8c5fb94",
|
||||
"60660257dd11b3aa9c8ed618d24edff2306d320f1d03010e33a7d2057f3b3b6"
|
||||
),
|
||||
array(
|
||||
"85b7c1dcb3cec1b7ee7f30ded79dd20a0ed1f4cc18cbcfcfa410361fd8f08f31",
|
||||
"3d98a9cdd026dd43f39048f25a8847f4fcafad1895d7a633c6fed3c35e999511"
|
||||
),
|
||||
array(
|
||||
"29df9fbd8d9e46509275f4b125d6d45d7fbe9a3b878a7af872a2800661ac5f51",
|
||||
"b4c4fe99c775a606e2d8862179139ffda61dc861c019e55cd2876eb2a27d84b"
|
||||
),
|
||||
array(
|
||||
"a0b1cae06b0a847a3fea6e671aaf8adfdfe58ca2f768105c8082b2e449fce252",
|
||||
"ae434102edde0958ec4b19d917a6a28e6b72da1834aff0e650f049503a296cf2"
|
||||
),
|
||||
array(
|
||||
"4e8ceafb9b3e9a136dc7ff67e840295b499dfb3b2133e4ba113f2e4c0e121e5",
|
||||
"cf2174118c8b6d7a4b48f6d534ce5c79422c086a63460502b827ce62a326683c"
|
||||
),
|
||||
array(
|
||||
"d24a44e047e19b6f5afb81c7ca2f69080a5076689a010919f42725c2b789a33b",
|
||||
"6fb8d5591b466f8fc63db50f1c0f1c69013f996887b8244d2cdec417afea8fa3"
|
||||
),
|
||||
array(
|
||||
"ea01606a7a6c9cdd249fdfcfacb99584001edd28abbab77b5104e98e8e3b35d4",
|
||||
"322af4908c7312b0cfbfe369f7a7b3cdb7d4494bc2823700cfd652188a3ea98d"
|
||||
),
|
||||
array(
|
||||
"af8addbf2b661c8a6c6328655eb96651252007d8c5ea31be4ad196de8ce2131f",
|
||||
"6749e67c029b85f52a034eafd096836b2520818680e26ac8f3dfbcdb71749700"
|
||||
),
|
||||
array(
|
||||
"e3ae1974566ca06cc516d47e0fb165a674a3dabcfca15e722f0e3450f45889",
|
||||
"2aeabe7e4531510116217f07bf4d07300de97e4874f81f533420a72eeb0bd6a4"
|
||||
),
|
||||
array(
|
||||
"591ee355313d99721cf6993ffed1e3e301993ff3ed258802075ea8ced397e246",
|
||||
"b0ea558a113c30bea60fc4775460c7901ff0b053d25ca2bdeee98f1a4be5d196"
|
||||
),
|
||||
array(
|
||||
"11396d55fda54c49f19aa97318d8da61fa8584e47b084945077cf03255b52984",
|
||||
"998c74a8cd45ac01289d5833a7beb4744ff536b01b257be4c5767bea93ea57a4"
|
||||
),
|
||||
array(
|
||||
"3c5d2a1ba39c5a1790000738c9e0c40b8dcdfd5468754b6405540157e017aa7a",
|
||||
"b2284279995a34e2f9d4de7396fc18b80f9b8b9fdd270f6661f79ca4c81bd257"
|
||||
),
|
||||
array(
|
||||
"cc8704b8a60a0defa3a99a7299f2e9c3fbc395afb04ac078425ef8a1793cc030",
|
||||
"bdd46039feed17881d1e0862db347f8cf395b74fc4bcdc4e940b74e3ac1f1b13"
|
||||
),
|
||||
array(
|
||||
"c533e4f7ea8555aacd9777ac5cad29b97dd4defccc53ee7ea204119b2889b197",
|
||||
"6f0a256bc5efdf429a2fb6242f1a43a2d9b925bb4a4b3a26bb8e0f45eb596096"
|
||||
),
|
||||
array(
|
||||
"c14f8f2ccb27d6f109f6d08d03cc96a69ba8c34eec07bbcf566d48e33da6593",
|
||||
"c359d6923bb398f7fd4473e16fe1c28475b740dd098075e6c0e8649113dc3a38"
|
||||
),
|
||||
array(
|
||||
"a6cbc3046bc6a450bac24789fa17115a4c9739ed75f8f21ce441f72e0b90e6ef",
|
||||
"21ae7f4680e889bb130619e2c0f95a360ceb573c70603139862afd617fa9b9f"
|
||||
),
|
||||
array(
|
||||
"347d6d9a02c48927ebfb86c1359b1caf130a3c0267d11ce6344b39f99d43cc38",
|
||||
"60ea7f61a353524d1c987f6ecec92f086d565ab687870cb12689ff1e31c74448"
|
||||
),
|
||||
array(
|
||||
"da6545d2181db8d983f7dcb375ef5866d47c67b1bf31c8cf855ef7437b72656a",
|
||||
"49b96715ab6878a79e78f07ce5680c5d6673051b4935bd897fea824b77dc208a"
|
||||
),
|
||||
array(
|
||||
"c40747cc9d012cb1a13b8148309c6de7ec25d6945d657146b9d5994b8feb1111",
|
||||
"5ca560753be2a12fc6de6caf2cb489565db936156b9514e1bb5e83037e0fa2d4"
|
||||
),
|
||||
array(
|
||||
"4e42c8ec82c99798ccf3a610be870e78338c7f713348bd34c8203ef4037f3502",
|
||||
"7571d74ee5e0fb92a7a8b33a07783341a5492144cc54bcc40a94473693606437"
|
||||
),
|
||||
array(
|
||||
"3775ab7089bc6af823aba2e1af70b236d251cadb0c86743287522a1b3b0dedea",
|
||||
"be52d107bcfa09d8bcb9736a828cfa7fac8db17bf7a76a2c42ad961409018cf7"
|
||||
),
|
||||
array(
|
||||
"cee31cbf7e34ec379d94fb814d3d775ad954595d1314ba8846959e3e82f74e26",
|
||||
"8fd64a14c06b589c26b947ae2bcf6bfa0149ef0be14ed4d80f448a01c43b1c6d"
|
||||
),
|
||||
array(
|
||||
"b4f9eaea09b6917619f6ea6a4eb5464efddb58fd45b1ebefcdc1a01d08b47986",
|
||||
"39e5c9925b5a54b07433a4f18c61726f8bb131c012ca542eb24a8ac07200682a"
|
||||
),
|
||||
array(
|
||||
"d4263dfc3d2df923a0179a48966d30ce84e2515afc3dccc1b77907792ebcc60e",
|
||||
"62dfaf07a0f78feb30e30d6295853ce189e127760ad6cf7fae164e122a208d54"
|
||||
),
|
||||
array(
|
||||
"48457524820fa65a4f8d35eb6930857c0032acc0a4a2de422233eeda897612c4",
|
||||
"25a748ab367979d98733c38a1fa1c2e7dc6cc07db2d60a9ae7a76aaa49bd0f77"
|
||||
),
|
||||
array(
|
||||
"dfeeef1881101f2cb11644f3a2afdfc2045e19919152923f367a1767c11cceda",
|
||||
"ecfb7056cf1de042f9420bab396793c0c390bde74b4bbdff16a83ae09a9a7517"
|
||||
),
|
||||
array(
|
||||
"6d7ef6b17543f8373c573f44e1f389835d89bcbc6062ced36c82df83b8fae859",
|
||||
"cd450ec335438986dfefa10c57fea9bcc521a0959b2d80bbf74b190dca712d10"
|
||||
),
|
||||
array(
|
||||
"e75605d59102a5a2684500d3b991f2e3f3c88b93225547035af25af66e04541f",
|
||||
"f5c54754a8f71ee540b9b48728473e314f729ac5308b06938360990e2bfad125"
|
||||
),
|
||||
array(
|
||||
"eb98660f4c4dfaa06a2be453d5020bc99a0c2e60abe388457dd43fefb1ed620c",
|
||||
"6cb9a8876d9cb8520609af3add26cd20a0a7cd8a9411131ce85f44100099223e"
|
||||
),
|
||||
array(
|
||||
"13e87b027d8514d35939f2e6892b19922154596941888336dc3563e3b8dba942",
|
||||
"fef5a3c68059a6dec5d624114bf1e91aac2b9da568d6abeb2570d55646b8adf1"
|
||||
),
|
||||
array(
|
||||
"ee163026e9fd6fe017c38f06a5be6fc125424b371ce2708e7bf4491691e5764a",
|
||||
"1acb250f255dd61c43d94ccc670d0f58f49ae3fa15b96623e5430da0ad6c62b2"
|
||||
),
|
||||
array(
|
||||
"b268f5ef9ad51e4d78de3a750c2dc89b1e626d43505867999932e5db33af3d80",
|
||||
"5f310d4b3c99b9ebb19f77d41c1dee018cf0d34fd4191614003e945a1216e423"
|
||||
),
|
||||
array(
|
||||
"ff07f3118a9df035e9fad85eb6c7bfe42b02f01ca99ceea3bf7ffdba93c4750d",
|
||||
"438136d603e858a3a5c440c38eccbaddc1d2942114e2eddd4740d098ced1f0d8"
|
||||
),
|
||||
array(
|
||||
"8d8b9855c7c052a34146fd20ffb658bea4b9f69e0d825ebec16e8c3ce2b526a1",
|
||||
"cdb559eedc2d79f926baf44fb84ea4d44bcf50fee51d7ceb30e2e7f463036758"
|
||||
),
|
||||
array(
|
||||
"52db0b5384dfbf05bfa9d472d7ae26dfe4b851ceca91b1eba54263180da32b63",
|
||||
"c3b997d050ee5d423ebaf66a6db9f57b3180c902875679de924b69d84a7b375"
|
||||
),
|
||||
array(
|
||||
"e62f9490d3d51da6395efd24e80919cc7d0f29c3f3fa48c6fff543becbd43352",
|
||||
"6d89ad7ba4876b0b22c2ca280c682862f342c8591f1daf5170e07bfd9ccafa7d"
|
||||
),
|
||||
array(
|
||||
"7f30ea2476b399b4957509c88f77d0191afa2ff5cb7b14fd6d8e7d65aaab1193",
|
||||
"ca5ef7d4b231c94c3b15389a5f6311e9daff7bb67b103e9880ef4bff637acaec"
|
||||
),
|
||||
array(
|
||||
"5098ff1e1d9f14fb46a210fada6c903fef0fb7b4a1dd1d9ac60a0361800b7a00",
|
||||
"9731141d81fc8f8084d37c6e7542006b3ee1b40d60dfe5362a5b132fd17ddc0"
|
||||
),
|
||||
array(
|
||||
"32b78c7de9ee512a72895be6b9cbefa6e2f3c4ccce445c96b9f2c81e2778ad58",
|
||||
"ee1849f513df71e32efc3896ee28260c73bb80547ae2275ba497237794c8753c"
|
||||
),
|
||||
array(
|
||||
"e2cb74fddc8e9fbcd076eef2a7c72b0ce37d50f08269dfc074b581550547a4f7",
|
||||
"d3aa2ed71c9dd2247a62df062736eb0baddea9e36122d2be8641abcb005cc4a4"
|
||||
),
|
||||
array(
|
||||
"8438447566d4d7bedadc299496ab357426009a35f235cb141be0d99cd10ae3a8",
|
||||
"c4e1020916980a4da5d01ac5e6ad330734ef0d7906631c4f2390426b2edd791f"
|
||||
),
|
||||
array(
|
||||
"4162d488b89402039b584c6fc6c308870587d9c46f660b878ab65c82c711d67e",
|
||||
"67163e903236289f776f22c25fb8a3afc1732f2b84b4e95dbda47ae5a0852649"
|
||||
),
|
||||
array(
|
||||
"3fad3fa84caf0f34f0f89bfd2dcf54fc175d767aec3e50684f3ba4a4bf5f683d",
|
||||
"cd1bc7cb6cc407bb2f0ca647c718a730cf71872e7d0d2a53fa20efcdfe61826"
|
||||
),
|
||||
array(
|
||||
"674f2600a3007a00568c1a7ce05d0816c1fb84bf1370798f1c69532faeb1a86b",
|
||||
"299d21f9413f33b3edf43b257004580b70db57da0b182259e09eecc69e0d38a5"
|
||||
),
|
||||
array(
|
||||
"d32f4da54ade74abb81b815ad1fb3b263d82d6c692714bcff87d29bd5ee9f08f",
|
||||
"f9429e738b8e53b968e99016c059707782e14f4535359d582fc416910b3eea87"
|
||||
),
|
||||
array(
|
||||
"30e4e670435385556e593657135845d36fbb6931f72b08cb1ed954f1e3ce3ff6",
|
||||
"462f9bce619898638499350113bbc9b10a878d35da70740dc695a559eb88db7b"
|
||||
),
|
||||
array(
|
||||
"be2062003c51cc3004682904330e4dee7f3dcd10b01e580bf1971b04d4cad297",
|
||||
"62188bc49d61e5428573d48a74e1c655b1c61090905682a0d5558ed72dccb9bc"
|
||||
),
|
||||
array(
|
||||
"93144423ace3451ed29e0fb9ac2af211cb6e84a601df5993c419859fff5df04a",
|
||||
"7c10dfb164c3425f5c71a3f9d7992038f1065224f72bb9d1d902a6d13037b47c"
|
||||
),
|
||||
array(
|
||||
"b015f8044f5fcbdcf21ca26d6c34fb8197829205c7b7d2a7cb66418c157b112c",
|
||||
"ab8c1e086d04e813744a655b2df8d5f83b3cdc6faa3088c1d3aea1454e3a1d5f"
|
||||
),
|
||||
array(
|
||||
"d5e9e1da649d97d89e4868117a465a3a4f8a18de57a140d36b3f2af341a21b52",
|
||||
"4cb04437f391ed73111a13cc1d4dd0db1693465c2240480d8955e8592f27447a"
|
||||
),
|
||||
array(
|
||||
"d3ae41047dd7ca065dbf8ed77b992439983005cd72e16d6f996a5316d36966bb",
|
||||
"bd1aeb21ad22ebb22a10f0303417c6d964f8cdd7df0aca614b10dc14d125ac46"
|
||||
),
|
||||
array(
|
||||
"463e2763d885f958fc66cdd22800f0a487197d0a82e377b49f80af87c897b065",
|
||||
"bfefacdb0e5d0fd7df3a311a94de062b26b80c61fbc97508b79992671ef7ca7f"
|
||||
),
|
||||
array(
|
||||
"7985fdfd127c0567c6f53ec1bb63ec3158e597c40bfe747c83cddfc910641917",
|
||||
"603c12daf3d9862ef2b25fe1de289aed24ed291e0ec6708703a5bd567f32ed03"
|
||||
),
|
||||
array(
|
||||
"74a1ad6b5f76e39db2dd249410eac7f99e74c59cb83d2d0ed5ff1543da7703e9",
|
||||
"cc6157ef18c9c63cd6193d83631bbea0093e0968942e8c33d5737fd790e0db08"
|
||||
),
|
||||
array(
|
||||
"30682a50703375f602d416664ba19b7fc9bab42c72747463a71d0896b22f6da3",
|
||||
"553e04f6b018b4fa6c8f39e7f311d3176290d0e0f19ca73f17714d9977a22ff8"
|
||||
),
|
||||
array(
|
||||
"9e2158f0d7c0d5f26c3791efefa79597654e7a2b2464f52b1ee6c1347769ef57",
|
||||
"712fcdd1b9053f09003a3481fa7762e9ffd7c8ef35a38509e2fbf2629008373"
|
||||
),
|
||||
array(
|
||||
"176e26989a43c9cfeba4029c202538c28172e566e3c4fce7322857f3be327d66",
|
||||
"ed8cc9d04b29eb877d270b4878dc43c19aefd31f4eee09ee7b47834c1fa4b1c3"
|
||||
),
|
||||
array(
|
||||
"75d46efea3771e6e68abb89a13ad747ecf1892393dfc4f1b7004788c50374da8",
|
||||
"9852390a99507679fd0b86fd2b39a868d7efc22151346e1a3ca4726586a6bed8"
|
||||
),
|
||||
array(
|
||||
"809a20c67d64900ffb698c4c825f6d5f2310fb0451c869345b7319f645605721",
|
||||
"9e994980d9917e22b76b061927fa04143d096ccc54963e6a5ebfa5f3f8e286c1"
|
||||
),
|
||||
array(
|
||||
"1b38903a43f7f114ed4500b4eac7083fdefece1cf29c63528d563446f972c180",
|
||||
"4036edc931a60ae889353f77fd53de4a2708b26b6f5da72ad3394119daf408f9"
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
Curves::defineCurve("secp256k1", array(
|
||||
"type" => "short",
|
||||
"prime" => "k256",
|
||||
"p" => "ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f",
|
||||
"a" => "0",
|
||||
"b" => "7",
|
||||
"n" => "ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141",
|
||||
"h" => "1",
|
||||
"hash" => array(
|
||||
"outSize" => 256,
|
||||
"hmacStrength" => 192,
|
||||
"algo" => "sha256"
|
||||
),
|
||||
|
||||
// Precomputed endomorphism
|
||||
"beta" => "7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee",
|
||||
"lambda" => "5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72",
|
||||
"basis" => array(
|
||||
array(
|
||||
"a" => "3086d221a7d46bcde86c90e49284eb15",
|
||||
"b" => "-e4437ed6010e88286f547fa90abfe4c3"
|
||||
),
|
||||
array(
|
||||
"a" => "114ca50f7a8e2f3f657c1108d9d44cfd8",
|
||||
"b" => "3086d221a7d46bcde86c90e49284eb15"
|
||||
)
|
||||
),
|
||||
|
||||
"gRed" => false,
|
||||
"g" => array(
|
||||
"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
||||
"483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
|
||||
$pre
|
||||
)
|
||||
));
|
||||
|
||||
?>
|
||||
+278
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic;
|
||||
|
||||
use Elliptic\Curve\PresetCurve;
|
||||
use Elliptic\EC\KeyPair;
|
||||
use Elliptic\EC\Signature;
|
||||
use BN\BN;
|
||||
|
||||
class EC
|
||||
{
|
||||
public $curve;
|
||||
public $n;
|
||||
public $nh;
|
||||
public $g;
|
||||
public $hash;
|
||||
|
||||
function __construct($options)
|
||||
{
|
||||
if( is_string($options) )
|
||||
{
|
||||
$options = Curves::getCurve($options);
|
||||
}
|
||||
|
||||
if( $options instanceof PresetCurve )
|
||||
$options = array("curve" => $options);
|
||||
|
||||
$this->curve = $options["curve"]->curve;
|
||||
$this->n = $this->curve->n;
|
||||
$this->nh = $this->n->ushrn(1);
|
||||
|
||||
//Point on curve
|
||||
$this->g = $options["curve"]->g;
|
||||
$this->g->precompute($options["curve"]->n->bitLength() + 1);
|
||||
|
||||
//Hash for function for DRBG
|
||||
if( isset($options["hash"]) )
|
||||
$this->hash = $options["hash"];
|
||||
else
|
||||
$this->hash = $options["curve"]->hash;
|
||||
}
|
||||
|
||||
public function keyPair(#[\SensitiveParameter]
|
||||
$options) {
|
||||
return new KeyPair($this, $options);
|
||||
}
|
||||
|
||||
public function keyFromPrivate(#[\SensitiveParameter]
|
||||
$priv, $enc = false) {
|
||||
return KeyPair::fromPrivate($this, $priv, $enc);
|
||||
}
|
||||
|
||||
public function keyFromPublic($pub, $enc = false) {
|
||||
return KeyPair::fromPublic($this, $pub, $enc);
|
||||
}
|
||||
|
||||
public function genKeyPair($options = null)
|
||||
{
|
||||
// Instantiate HmacDRBG
|
||||
$drbg = new HmacDRBG(array(
|
||||
"hash" => $this->hash,
|
||||
"pers" => isset($options["pers"]) ? $options["pers"] : "",
|
||||
"entropy" => isset($options["entropy"]) ? $options["entropy"] : Utils::randBytes($this->hash["hmacStrength"]),
|
||||
"nonce" => $this->n->toArray()
|
||||
));
|
||||
|
||||
$bytes = $this->n->byteLength();
|
||||
$ns2 = $this->n->sub(new BN(2));
|
||||
while(true)
|
||||
{
|
||||
$priv = new BN($drbg->generate($bytes));
|
||||
if( $priv->cmp($ns2) > 0 )
|
||||
continue;
|
||||
|
||||
$priv->iaddn(1);
|
||||
return $this->keyFromPrivate($priv);
|
||||
}
|
||||
}
|
||||
|
||||
private function _truncateToN($msg, $truncOnly = false)
|
||||
{
|
||||
$delta = intval(($msg->byteLength() * 8) - $this->n->bitLength());
|
||||
if( $delta > 0 ) {
|
||||
$msg = $msg->ushrn($delta);
|
||||
}
|
||||
if( $truncOnly || $msg->cmp($this->n) < 0 )
|
||||
return $msg;
|
||||
|
||||
return $msg->sub($this->n);
|
||||
}
|
||||
|
||||
public function sign($msg, #[\SensitiveParameter]
|
||||
$key, $enc = null, $options = null)
|
||||
{
|
||||
if( !is_string($enc) )
|
||||
{
|
||||
$options = $enc;
|
||||
$enc = null;
|
||||
}
|
||||
|
||||
$key = $this->keyFromPrivate($key, $enc);
|
||||
$msg = $this->_truncateToN(new BN($msg, 16));
|
||||
|
||||
// Zero-extend key to provide enough entropy
|
||||
$bytes = $this->n->byteLength();
|
||||
$bkey = $key->getPrivate()->toArray("be", $bytes);
|
||||
|
||||
// Zero-extend nonce to have the same byte size as N
|
||||
$nonce = $msg->toArray("be", $bytes);
|
||||
|
||||
$kFunc = null;
|
||||
if( isset($options["k"]) )
|
||||
$kFunc = $options["k"];
|
||||
else
|
||||
{
|
||||
// Instatiate HmacDRBG
|
||||
$drbg = new HmacDRBG(array(
|
||||
"hash" => $this->hash,
|
||||
"entropy" => $bkey,
|
||||
"nonce" => $nonce,
|
||||
"pers" => isset($options["pers"]) ? $options["pers"] : "",
|
||||
"persEnc" => isset($options["persEnc"]) ? $options["persEnc"] : false
|
||||
));
|
||||
|
||||
$kFunc = function($iter) use ($drbg, $bytes) {
|
||||
return new BN($drbg->generate($bytes));
|
||||
};
|
||||
}
|
||||
|
||||
// Number of bytes to generate
|
||||
$ns1 = $this->n->sub(new BN(1));
|
||||
|
||||
$canonical = isset($options["canonical"]) ? $options["canonical"] : false;
|
||||
for($iter = 0; true; $iter++)
|
||||
{
|
||||
$k = $kFunc($iter);
|
||||
$k = $this->_truncateToN($k, true);
|
||||
|
||||
if( $k->cmpn(1) <= 0 || $k->cmp($ns1) >= 0 )
|
||||
continue;
|
||||
|
||||
// Fix the bit-length of the random nonce,
|
||||
// so that it doesn't leak via timing.
|
||||
// This does not change that ks = k mod k
|
||||
$ks = $k->add($this->n);
|
||||
$kt = $ks->add($this->n);
|
||||
if ($ks->bitLength() === $this->n->bitLength()) {
|
||||
$kp = $this->g->mul($kt);
|
||||
} else {
|
||||
$kp = $this->g->mul($ks);
|
||||
}
|
||||
|
||||
if( $kp->isInfinity() )
|
||||
continue;
|
||||
|
||||
$kpX = $kp->getX();
|
||||
$r = $kpX->umod($this->n);
|
||||
if( $r->isZero() )
|
||||
continue;
|
||||
|
||||
$s = $k->invm($this->n)->mul($r->mul($key->getPrivate())->iadd($msg));
|
||||
$s = $s->umod($this->n);
|
||||
if( $s->isZero() )
|
||||
continue;
|
||||
|
||||
$recoveryParam = ($kp->getY()->isOdd() ? 1 : 0) | ($kpX->cmp($r) !== 0 ? 2 : 0);
|
||||
|
||||
// Use complement of `s`, if it is > `n / 2`
|
||||
if( $canonical && $s->cmp($this->nh) > 0 )
|
||||
{
|
||||
$s = $this->n->sub($s);
|
||||
$recoveryParam ^= 1;
|
||||
}
|
||||
|
||||
return new Signature(array(
|
||||
"r" => $r,
|
||||
"s" => $s,
|
||||
"recoveryParam" => $recoveryParam
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function verify($msg, $signature, $key, $enc = false)
|
||||
{
|
||||
$msg = $this->_truncateToN(new BN($msg, 16));
|
||||
$key = $this->keyFromPublic($key, $enc);
|
||||
$signature = new Signature($signature, "hex");
|
||||
|
||||
// Perform primitive values validation
|
||||
$r = $signature->r;
|
||||
$s = $signature->s;
|
||||
|
||||
if( $r->cmpn(1) < 0 || $r->cmp($this->n) >= 0 )
|
||||
return false;
|
||||
if( $s->cmpn(1) < 0 || $s->cmp($this->n) >= 0 )
|
||||
return false;
|
||||
|
||||
// Validate signature
|
||||
$sinv = $s->invm($this->n);
|
||||
$u1 = $sinv->mul($msg)->umod($this->n);
|
||||
$u2 = $sinv->mul($r)->umod($this->n);
|
||||
|
||||
if( !$this->curve->_maxwellTrick )
|
||||
{
|
||||
$p = $this->g->mulAdd($u1, $key->getPublic(), $u2);
|
||||
if( $p->isInfinity() )
|
||||
return false;
|
||||
|
||||
return $p->getX()->umod($this->n)->cmp($r) === 0;
|
||||
}
|
||||
|
||||
// NOTE: Greg Maxwell's trick, inspired by:
|
||||
// https://git.io/vad3K
|
||||
|
||||
$p = $this->g->jmulAdd($u1, $key->getPublic(), $u2);
|
||||
if( $p->isInfinity() )
|
||||
return false;
|
||||
|
||||
// Compare `p.x` of Jacobian point with `r`,
|
||||
// this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the
|
||||
// inverse of `p.z^2`
|
||||
return $p->eqXToP($r);
|
||||
}
|
||||
|
||||
public function recoverPubKey($msg, $signature, $j, $enc = false)
|
||||
{
|
||||
assert((3 & $j) === $j); //, "The recovery param is more than two bits");
|
||||
$signature = new Signature($signature, $enc);
|
||||
|
||||
$e = new BN($msg, 16);
|
||||
$r = $signature->r;
|
||||
$s = $signature->s;
|
||||
|
||||
// A set LSB signifies that the y-coordinate is odd
|
||||
$isYOdd = ($j & 1) == 1;
|
||||
$isSecondKey = $j >> 1;
|
||||
|
||||
if ($r->cmp($this->curve->p->umod($this->curve->n)) >= 0 && $isSecondKey)
|
||||
throw new \Exception("Unable to find second key candinate");
|
||||
|
||||
// 1.1. Let x = r + jn.
|
||||
if( $isSecondKey )
|
||||
$r = $this->curve->pointFromX($r->add($this->curve->n), $isYOdd);
|
||||
else
|
||||
$r = $this->curve->pointFromX($r, $isYOdd);
|
||||
|
||||
$eNeg = $this->n->sub($e);
|
||||
|
||||
// 1.6.1 Compute Q = r^-1 (sR - eG)
|
||||
// Q = r^-1 (sR + -eG)
|
||||
$rInv = $signature->r->invm($this->n);
|
||||
return $this->g->mulAdd($eNeg, $r, $s)->mul($rInv);
|
||||
}
|
||||
|
||||
public function getKeyRecoveryParam($e, $signature, $Q, $enc = false)
|
||||
{
|
||||
$signature = new Signature($signature, $enc);
|
||||
if( $signature->recoveryParam != null )
|
||||
return $signature->recoveryParam;
|
||||
|
||||
for($i = 0; $i < 4; $i++)
|
||||
{
|
||||
$Qprime = null;
|
||||
try {
|
||||
$Qprime = $this->recoverPubKey($e, $signature, $i);
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if( $Qprime->eq($Q))
|
||||
return $i;
|
||||
}
|
||||
throw new \Exception("Unable to find valid recovery factor");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\EC;
|
||||
|
||||
use BN\BN;
|
||||
|
||||
class KeyPair
|
||||
{
|
||||
public $ec;
|
||||
public $pub;
|
||||
public $priv;
|
||||
|
||||
function __construct($ec, #[\SensitiveParameter]
|
||||
$options)
|
||||
{
|
||||
$this->ec = $ec;
|
||||
|
||||
$this->priv = null;
|
||||
$this->pub = null;
|
||||
|
||||
if( isset($options["priv"]) )
|
||||
$this->_importPrivate($options["priv"], $options["privEnc"]);
|
||||
|
||||
if( isset($options["pub"]) )
|
||||
$this->_importPublic($options["pub"], $options["pubEnc"]);
|
||||
}
|
||||
|
||||
public static function fromPublic($ec, $pub, $enc)
|
||||
{
|
||||
if( $pub instanceof KeyPair )
|
||||
return $pub;
|
||||
|
||||
return new KeyPair($ec, array(
|
||||
"pub" => $pub,
|
||||
"pubEnc" => $enc
|
||||
));
|
||||
}
|
||||
|
||||
public static function fromPrivate($ec, #[\SensitiveParameter]
|
||||
$priv, $enc)
|
||||
{
|
||||
if( $priv instanceof KeyPair )
|
||||
return $priv;
|
||||
|
||||
return new KeyPair($ec, array(
|
||||
"priv" => $priv,
|
||||
"privEnc" => $enc
|
||||
));
|
||||
}
|
||||
|
||||
public function validate()
|
||||
{
|
||||
$pub = $this->getPublic();
|
||||
|
||||
if( $pub->isInfinity() )
|
||||
return array( "result" => false, "reason" => "Invalid public key" );
|
||||
|
||||
if( !$pub->validate() )
|
||||
return array( "result" => false, "reason" => "Public key is not a point" );
|
||||
|
||||
if( !$pub->mul($this->ec->curve->n)->isInfinity() )
|
||||
return array( "result" => false, "reason" => "Public key * N != O" );
|
||||
|
||||
return array( "result" => true, "reason" => null );
|
||||
}
|
||||
|
||||
public function getPublic($compact = false, $enc = "")
|
||||
{
|
||||
//compact is optional argument
|
||||
if( is_string($compact) )
|
||||
{
|
||||
$enc = $compact;
|
||||
$compact = false;
|
||||
}
|
||||
|
||||
if( $this->pub === null )
|
||||
$this->pub = $this->ec->g->mul($this->priv);
|
||||
|
||||
if( !$enc )
|
||||
return $this->pub;
|
||||
|
||||
return $this->pub->encode($enc, $compact);
|
||||
}
|
||||
|
||||
public function getPrivate($enc = false)
|
||||
{
|
||||
if( $enc === "hex" )
|
||||
return $this->priv->toString(16, 2);
|
||||
|
||||
return $this->priv;
|
||||
}
|
||||
|
||||
private function _importPrivate(#[\SensitiveParameter]
|
||||
$key, $enc)
|
||||
{
|
||||
$this->priv = new BN($key, (isset($enc) && $enc) ? $enc : 16);
|
||||
|
||||
// Ensure that the priv won't be bigger than n, otherwise we may fail
|
||||
// in fixed multiplication method
|
||||
$this->priv = $this->priv->umod($this->ec->curve->n);
|
||||
}
|
||||
|
||||
private function _importPublic($key, $enc)
|
||||
{
|
||||
$x = $y = null;
|
||||
if ( is_object($key) ) {
|
||||
$x = $key->x;
|
||||
$y = $key->y;
|
||||
} elseif ( is_array($key) ) {
|
||||
$x = isset($key["x"]) ? $key["x"] : null;
|
||||
$y = isset($key["y"]) ? $key["y"] : null;
|
||||
}
|
||||
|
||||
if( $x != null || $y != null )
|
||||
$this->pub = $this->ec->curve->point($x, $y);
|
||||
else
|
||||
$this->pub = $this->ec->curve->decodePoint($key, $enc);
|
||||
}
|
||||
|
||||
//ECDH
|
||||
public function derive($pub) {
|
||||
return $pub->mul($this->priv)->getX();
|
||||
}
|
||||
|
||||
//ECDSA
|
||||
public function sign($msg, $enc = false, $options = false) {
|
||||
return $this->ec->sign($msg, $this, $enc, $options);
|
||||
}
|
||||
|
||||
public function verify($msg, $signature) {
|
||||
return $this->ec->verify($msg, $signature, $this);
|
||||
}
|
||||
|
||||
public function inspect() {
|
||||
return "<Key priv: " . (isset($this->priv) ? $this->priv->toString(16, 2) : "") .
|
||||
" pub: " . (isset($this->pub) ? $this->pub->inspect() : "") . ">";
|
||||
}
|
||||
|
||||
public function __debugInfo() {
|
||||
return ["priv" => $this->priv, "pub" => $this->pub];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\EC;
|
||||
|
||||
use Elliptic\Utils;
|
||||
use BN\BN;
|
||||
|
||||
class Signature
|
||||
{
|
||||
public $r;
|
||||
public $s;
|
||||
public $recoveryParam;
|
||||
|
||||
function __construct($options, $enc = false)
|
||||
{
|
||||
if ($options instanceof Signature) {
|
||||
$this->r = $options->r;
|
||||
$this->s = $options->s;
|
||||
$this->recoveryParam = $options->recoveryParam;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($options['r'])) {
|
||||
assert(isset($options["r"]) && isset($options["s"])); //, "Signature without r or s");
|
||||
$this->r = new BN($options["r"], 16);
|
||||
$this->s = new BN($options["s"], 16);
|
||||
|
||||
if( isset($options["recoveryParam"]) )
|
||||
$this->recoveryParam = $options["recoveryParam"];
|
||||
else
|
||||
$this->recoveryParam = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->_importDER($options, $enc))
|
||||
throw new \Exception('Unknown signature format');
|
||||
|
||||
}
|
||||
|
||||
private static function getLength($buf, &$pos)
|
||||
{
|
||||
$initial = $buf[$pos++];
|
||||
if( !($initial & 0x80) )
|
||||
return $initial;
|
||||
|
||||
$octetLen = $initial & 0xf;
|
||||
$val = 0;
|
||||
for($i = 0; $i < $octetLen; $i++)
|
||||
{
|
||||
$val = $val << 8;
|
||||
$val = $val | $buf[$pos];
|
||||
$pos++;
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
|
||||
private static function rmPadding(&$buf)
|
||||
{
|
||||
$i = 0;
|
||||
$len = count($buf) - 1;
|
||||
while($i < $len && !$buf[$i] && !($buf[$i+1] & 0x80) )
|
||||
$i++;
|
||||
|
||||
if( $i === 0 )
|
||||
return $buf;
|
||||
|
||||
return array_slice($buf, $i);
|
||||
}
|
||||
|
||||
private function _importDER($data, $enc)
|
||||
{
|
||||
$data = Utils::toArray($data, $enc);
|
||||
$dataLen = count($data);
|
||||
$place = 0;
|
||||
|
||||
if( $data[$place++] !== 0x30)
|
||||
return false;
|
||||
|
||||
$len = self::getLength($data, $place);
|
||||
if( ($len + $place) !== $dataLen )
|
||||
return false;
|
||||
|
||||
if( $data[$place++] !== 0x02 )
|
||||
return false;
|
||||
|
||||
$rlen = self::getLength($data, $place);
|
||||
$r = array_slice($data, $place, $rlen);
|
||||
$place += $rlen;
|
||||
|
||||
if( $data[$place++] !== 0x02 )
|
||||
return false;
|
||||
|
||||
$slen = self::getLength($data, $place);
|
||||
if( $dataLen !== $slen + $place )
|
||||
return false;
|
||||
$s = array_slice($data, $place, $slen);
|
||||
|
||||
if( $r[0] === 0 && ($r[1] & 0x80 ) )
|
||||
$r = array_slice($r, 1);
|
||||
if( $s[0] === 0 && ($s[1] & 0x80 ) )
|
||||
$s = array_slice($s, 1);
|
||||
|
||||
$this->r = new BN($r);
|
||||
$this->s = new BN($s);
|
||||
$this->recoveryParam = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function constructLength(&$arr, $len)
|
||||
{
|
||||
if( $len < 0x80 )
|
||||
{
|
||||
array_push($arr, $len);
|
||||
return;
|
||||
}
|
||||
|
||||
$octets = 1 + (log($len) / M_LN2 >> 3);
|
||||
array_push($arr, $octets | 0x80);
|
||||
while(--$octets)
|
||||
array_push($arr, ($len >> ($octets << 3)) & 0xff);
|
||||
array_push($arr, $len);
|
||||
}
|
||||
|
||||
public function toDER($enc = false)
|
||||
{
|
||||
$r = $this->r->toArray();
|
||||
$s = $this->s->toArray();
|
||||
|
||||
//Pad values
|
||||
if( $r[0] & 0x80 )
|
||||
array_unshift($r, 0);
|
||||
if( $s[0] & 0x80 )
|
||||
array_unshift($s, 0);
|
||||
|
||||
$r = self::rmPadding($r);
|
||||
$s = self::rmPadding($s);
|
||||
|
||||
while(!$s[0] && !($s[1] & 0x80))
|
||||
array_slice($s, 1);
|
||||
|
||||
$arr = array(0x02);
|
||||
self::constructLength($arr, count($r));
|
||||
$arr = array_merge($arr, $r, array(0x02));
|
||||
self::constructLength($arr, count($s));
|
||||
$backHalf = array_merge($arr, $s);
|
||||
$res = array(0x30);
|
||||
self::constructLength($res, count($backHalf));
|
||||
$res = array_merge($res, $backHalf);
|
||||
|
||||
return Utils::encode($res, $enc);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
namespace Elliptic;
|
||||
|
||||
use Elliptic\EdDSA\KeyPair;
|
||||
use Elliptic\EdDSA\Signature;
|
||||
|
||||
class EdDSA {
|
||||
|
||||
public $curve;
|
||||
public $g;
|
||||
public $pointClass;
|
||||
public $encodingLength;
|
||||
public $hash;
|
||||
|
||||
function __construct($curve) {
|
||||
assert($curve == "ed25519"); //, 'only tested with ed25519 so far');
|
||||
|
||||
$curve = \Elliptic\Curves::getCurve($curve)->curve;
|
||||
$this->curve = $curve;
|
||||
$this->g = $curve->g;
|
||||
$this->g->precompute($curve->n->bitLength() + 1);
|
||||
|
||||
$this->pointClass = get_class($curve->point());
|
||||
$this->encodingLength = intval(ceil($curve->n->bitLength() / 8));
|
||||
// TODO: !!!
|
||||
$this->hash = [ "algo" => "sha512" ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array|String} message - message bytes
|
||||
* @param {Array|String|KeyPair} secret - secret bytes or a keypair
|
||||
* @returns {Signature} - signature
|
||||
*/
|
||||
public function sign($message, #[\SensitiveParameter]
|
||||
$secret) {
|
||||
$message = Utils::parseBytes($message);
|
||||
$key = $this->keyFromSecret($secret);
|
||||
$r = $this->hashInt($key->messagePrefix(), $message);
|
||||
$R = $this->g->mul($r);
|
||||
$Rencoded = $this->encodePoint($R);
|
||||
$s_ = $this->hashInt($Rencoded, $key->pubBytes(), $message)
|
||||
->mul($key->priv());
|
||||
$S = $r->add($s_)->umod($this->curve->n);
|
||||
return $this->makeSignature([ "R" => $R, "S" => $S, "Rencoded" => $Rencoded ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} message - message bytes
|
||||
* @param {Array|String|Signature} sig - sig bytes
|
||||
* @param {Array|String|Point|KeyPair} pub - public key
|
||||
* @returns {Boolean} - true if public key matches sig of message
|
||||
*/
|
||||
public function verify($message, $sig, $pub) {
|
||||
$message = Utils::parseBytes($message);
|
||||
$sig = $this->makeSignature($sig);
|
||||
$key = $this->keyFromPublic($pub);
|
||||
$h = $this->hashInt($sig->Rencoded(), $key->pubBytes(), $message);
|
||||
$SG = $this->g->mul($sig->S());
|
||||
$RplusAh = $sig->R()->add($key->pub()->mul($h));
|
||||
return $RplusAh->eq($SG);
|
||||
}
|
||||
|
||||
public function hashInt() {
|
||||
$arguments = func_get_args();
|
||||
// TODO: refactor when hash-php is ready
|
||||
$hash = hash_init($this->hash["algo"]);
|
||||
for ($i = 0; $i < count($arguments); $i++)
|
||||
hash_update($hash, Utils::toBin($arguments[$i]));
|
||||
return Utils::intFromLE(hash_final($hash))->umod($this->curve->n);
|
||||
}
|
||||
|
||||
public function keyFromPublic($pub) {
|
||||
return KeyPair::fromPublic($this, $pub);
|
||||
}
|
||||
|
||||
public function keyFromSecret(#[\SensitiveParameter]
|
||||
$secret) {
|
||||
return KeyPair::fromSecret($this, $secret);
|
||||
}
|
||||
|
||||
public function makeSignature($sig) {
|
||||
if ($sig instanceof Signature)
|
||||
return $sig;
|
||||
return new Signature($this, $sig);
|
||||
}
|
||||
|
||||
/**
|
||||
* * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2
|
||||
*
|
||||
* EdDSA defines methods for encoding and decoding points and integers. These are
|
||||
* helper convenience methods, that pass along to utility functions implied
|
||||
* parameters.
|
||||
*
|
||||
*/
|
||||
public function encodePoint($point) {
|
||||
$enc = $point->getY()->toArray('le', $this->encodingLength);
|
||||
$enc[$this->encodingLength - 1] |= $point->getX()->isOdd() ? 0x80 : 0;
|
||||
return $enc;
|
||||
}
|
||||
|
||||
public function decodePoint($bytes) {
|
||||
$bytes = Utils::parseBytes($bytes);
|
||||
|
||||
$lastIx = count($bytes) - 1;
|
||||
$normed = $bytes;
|
||||
$normed[$lastIx] = $bytes[$lastIx] & ~0x80;
|
||||
$xIsOdd = ($bytes[$lastIx] & 0x80) !== 0;
|
||||
|
||||
$y = Utils::intFromLE($normed);
|
||||
return $this->curve->pointFromY($y, $xIsOdd);
|
||||
}
|
||||
|
||||
public function encodeInt($num) {
|
||||
return $num->toArray('le', $this->encodingLength);
|
||||
}
|
||||
|
||||
public function decodeInt($bytes) {
|
||||
return Utils::intFromLE($bytes);
|
||||
}
|
||||
|
||||
public function isPoint($val) {
|
||||
return is_a($val, $this->pointClass);
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
namespace Elliptic\EdDSA;
|
||||
|
||||
use Elliptic\Utils;
|
||||
|
||||
class KeyPair {
|
||||
public $eddsa;
|
||||
public $_pubBytes;
|
||||
/**
|
||||
* @param {\Elliptic\EdDSA} eddsa - instance
|
||||
* @param {Object} params - public/private key parameters
|
||||
*
|
||||
* @param {Array<Byte>} [params.secret] - secret seed bytes
|
||||
* @param {Point} [params.pub] - public key point (aka `A` in eddsa terms)
|
||||
* @param {Array<Byte>} [params.pub] - public key point encoded as bytes
|
||||
*
|
||||
*/
|
||||
function __construct($eddsa, #[\SensitiveParameter]
|
||||
$params) {
|
||||
$this->eddsa = $eddsa;
|
||||
$this->_secret = isset($params["secret"]) ? Utils::parseBytes($params["secret"]) : null;
|
||||
if (!isset($params["pub"])) {
|
||||
$this->_pub = null;
|
||||
$this->_pubBytes = null;
|
||||
return;
|
||||
}
|
||||
if ($eddsa->isPoint($params["pub"]))
|
||||
$this->_pub = $params["pub"];
|
||||
else
|
||||
$this->_pubBytes = Utils::parseBytes($params["pub"]);
|
||||
}
|
||||
|
||||
public static function fromPublic($eddsa, $pub) {
|
||||
if ($pub instanceof KeyPair)
|
||||
return $pub;
|
||||
return new KeyPair($eddsa, [ "pub" => $pub ]);
|
||||
}
|
||||
|
||||
public static function fromSecret($eddsa, #[\SensitiveParameter]
|
||||
$secret) {
|
||||
if ($secret instanceof KeyPair)
|
||||
return $secret;
|
||||
return new KeyPair($eddsa, [ "secret" => $secret ]);
|
||||
}
|
||||
|
||||
private $_secret;
|
||||
public function secret() {
|
||||
return $this->_secret;
|
||||
}
|
||||
|
||||
public function pubBytes() {
|
||||
if (!$this->_pubBytes)
|
||||
$this->_pubBytes = $this->eddsa->encodePoint($this->pub());
|
||||
return $this->_pubBytes;
|
||||
}
|
||||
|
||||
private $_pub;
|
||||
public function pub() {
|
||||
if (!$this->_pub) {
|
||||
if ($this->_pubBytes)
|
||||
$this->_pub = $this->eddsa->decodePoint($this->_pubBytes);
|
||||
else
|
||||
$this->_pub = $this->eddsa->g->mul($this->priv());
|
||||
}
|
||||
return $this->_pub;
|
||||
}
|
||||
|
||||
private $_privBytes;
|
||||
public function privBytes() {
|
||||
if (!$this->_privBytes) {
|
||||
$eddsa = $this->eddsa;
|
||||
$hash = $this->hash();
|
||||
$lastIx = $eddsa->encodingLength - 1;
|
||||
|
||||
$a = array_slice($hash, 0, $eddsa->encodingLength);
|
||||
$a[0] &= 248;
|
||||
$a[$lastIx] &= 127;
|
||||
$a[$lastIx] |= 64;
|
||||
$this->_privBytes = $a;
|
||||
}
|
||||
return $this->_privBytes;
|
||||
}
|
||||
|
||||
private $_priv;
|
||||
public function priv() {
|
||||
if (!$this->_priv) {
|
||||
$this->_priv = $this->eddsa->decodeInt($this->privBytes());
|
||||
}
|
||||
return $this->_priv;
|
||||
}
|
||||
|
||||
private $_hash;
|
||||
public function hash() {
|
||||
if (!$this->_hash) {
|
||||
// TODO: !!!
|
||||
$hash = hash_init('sha512');
|
||||
hash_update($hash, Utils::toBin($this->secret()));
|
||||
$this->_hash = Utils::toArray( hash_final($hash), 'hex' );
|
||||
}
|
||||
return $this->_hash;
|
||||
}
|
||||
|
||||
private $_messagePrefix;
|
||||
public function messagePrefix() {
|
||||
if (!$this->_messagePrefix) {
|
||||
$this->_messagePrefix = array_slice($this->hash(), $this->eddsa->encodingLength);
|
||||
}
|
||||
return $this->_messagePrefix;
|
||||
}
|
||||
|
||||
public function sign($message) {
|
||||
assert($this->_secret); //, 'KeyPair can only verify');
|
||||
return $this->eddsa->sign($message, $this);
|
||||
}
|
||||
|
||||
public function verify($message, $sig) {
|
||||
return $this->eddsa->verify($message, $sig, $this);
|
||||
}
|
||||
|
||||
public function getSecret($enc = false) {
|
||||
assert($this->_secret); //, 'KeyPair is public only');
|
||||
return Utils::encode($this->secret(), $enc);
|
||||
}
|
||||
|
||||
public function getPublic($enc = false) {
|
||||
return Utils::encode($this->pubBytes(), $enc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
namespace Elliptic\EdDSA;
|
||||
|
||||
use Elliptic\Utils;
|
||||
use BN\BN;
|
||||
|
||||
class Signature {
|
||||
|
||||
public $eddsa;
|
||||
|
||||
/**
|
||||
* @param {EdDSA} eddsa - eddsa instance
|
||||
* @param {Array<Bytes>|Object} sig -
|
||||
* @param {Array<Bytes>|Point} [sig.R] - R point as Point or bytes
|
||||
* @param {Array<Bytes>|bn} [sig.S] - S scalar as bn or bytes
|
||||
* @param {Array<Bytes>} [sig.Rencoded] - R point encoded
|
||||
* @param {Array<Bytes>} [sig.Sencoded] - S scalar encoded
|
||||
*/
|
||||
function __construct($eddsa, $sig) {
|
||||
$this->eddsa = $eddsa;
|
||||
|
||||
if (is_string($sig))
|
||||
$sig = Utils::parseBytes($sig);
|
||||
|
||||
if (is_array($sig) && !isset($sig["R"])) {
|
||||
$sig = [
|
||||
"R" => array_slice($sig, 0, $eddsa->encodingLength),
|
||||
"S" => array_slice($sig, $eddsa->encodingLength)
|
||||
];
|
||||
}
|
||||
|
||||
assert($sig["R"] && $sig["S"]); //, 'Signature without R or S');
|
||||
|
||||
if ($eddsa->isPoint($sig["R"]))
|
||||
$this->_R = $sig["R"];
|
||||
if ($sig["S"] instanceof BN)
|
||||
$this->_S = $sig["S"];
|
||||
|
||||
$this->_Rencoded = is_array($sig["R"]) ? $sig["R"] : (isset($sig["Rencoded"]) ?$sig["Rencoded"] : null);
|
||||
$this->_Sencoded = is_array($sig["S"]) ? $sig["S"] : (isset($sig["Sencoded"]) ?$sig["Sencoded"] : null);
|
||||
}
|
||||
|
||||
private $_S;
|
||||
public function S() {
|
||||
if (!$this->_S) {
|
||||
$this->_S = $this->eddsa->decodeInt($this->Sencoded());
|
||||
}
|
||||
return $this->_S;
|
||||
}
|
||||
|
||||
private $_R;
|
||||
public function R() {
|
||||
if (!$this->_R) {
|
||||
$this->_R = $this->eddsa->decodePoint($this->Rencoded());
|
||||
}
|
||||
return $this->_R;
|
||||
}
|
||||
|
||||
private $_Rencoded;
|
||||
public function Rencoded() {
|
||||
if (!$this->_Rencoded) {
|
||||
$this->_Rencoded = $this->eddsa->encodePoint($this->R());
|
||||
}
|
||||
return $this->_Rencoded;
|
||||
}
|
||||
|
||||
private $_Sencoded;
|
||||
public function Sencoded() {
|
||||
if (!$this->_Sencoded) {
|
||||
$this->_Sencoded = $this->eddsa->encodeInt($this->S());
|
||||
}
|
||||
return $this->_Sencoded;
|
||||
}
|
||||
|
||||
public function toBytes() {
|
||||
return array_merge($this->Rencoded(), $this->Sencoded());
|
||||
}
|
||||
|
||||
public function toHex() {
|
||||
return strtoupper(Utils::encode($this->toBytes(), 'hex'));
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic;
|
||||
|
||||
class HmacDRBG
|
||||
{
|
||||
private $hash;
|
||||
private $predResist;
|
||||
private $outLen;
|
||||
private $minEntropy;
|
||||
private $reseed;
|
||||
private $reseedInterval;
|
||||
private $K;
|
||||
private $V;
|
||||
|
||||
function __construct($options)
|
||||
{
|
||||
Utils::optionAssert($options, "predResist");
|
||||
Utils::optionAssert($options, "hash", null, true);
|
||||
Utils::optionAssert($options["hash"], "outSize", null, true);
|
||||
Utils::optionAssert($options["hash"], "hmacStrength", null, true);
|
||||
Utils::optionAssert($options["hash"], "algo", null, true);
|
||||
Utils::optionAssert($options, "minEntropy");
|
||||
Utils::optionAssert($options, "entropy", null, true);
|
||||
Utils::optionAssert($options, "entropyEnc");
|
||||
Utils::optionAssert($options, "nonce", "");
|
||||
Utils::optionAssert($options, "nonceEnc");
|
||||
Utils::optionAssert($options, "pers", "");
|
||||
Utils::optionAssert($options, "persEnc");
|
||||
|
||||
$this->hash = $options["hash"];
|
||||
$this->predResist = $options["predResist"];
|
||||
|
||||
$this->outLen = $this->hash["outSize"];
|
||||
$this->minEntropy = $options["minEntropy"] ?: $this->hash["hmacStrength"];
|
||||
|
||||
$this->reseed = null;
|
||||
$this->reseedInterval = null;
|
||||
$this->K = null;
|
||||
$this->V = null;
|
||||
|
||||
$entropy = Utils::toBin($options["entropy"], $options["entropyEnc"]);
|
||||
$nonce = Utils::toBin($options["nonce"], $options["nonceEnc"]);
|
||||
$pers = Utils::toBin($options["pers"], $options["persEnc"]);
|
||||
|
||||
if (Utils::$ASSERT_ENABLED) {
|
||||
assert(strlen($entropy) >= ($this->minEntropy / 8));
|
||||
}
|
||||
$this->_init($entropy, $nonce, $pers);
|
||||
}
|
||||
|
||||
private function _init($entropy, $nonce, $pers)
|
||||
{
|
||||
$seed = $entropy . $nonce . $pers;
|
||||
|
||||
$this->K = str_repeat(chr(0x00), $this->outLen / 8);
|
||||
$this->V = str_repeat(chr(0x01), $this->outLen / 8);
|
||||
|
||||
$this->_update($seed);
|
||||
$this->reseed = 1;
|
||||
$this->reseedInterval = 0x1000000000000; // 2^48
|
||||
}
|
||||
|
||||
private function _hmac()
|
||||
{
|
||||
return hash_init($this->hash["algo"], HASH_HMAC, $this->K);
|
||||
}
|
||||
|
||||
private function _update($seed = false)
|
||||
{
|
||||
$kmac = $this->_hmac();
|
||||
hash_update($kmac, $this->V);
|
||||
hash_update($kmac, chr(0x00));
|
||||
|
||||
if( $seed )
|
||||
hash_update($kmac, $seed);
|
||||
$this->K = hash_final($kmac, true);
|
||||
|
||||
$kmac = $this->_hmac();
|
||||
hash_update($kmac, $this->V);
|
||||
$this->V = hash_final($kmac, true);
|
||||
|
||||
if(!$seed)
|
||||
return;
|
||||
|
||||
$kmac = $this->_hmac();
|
||||
hash_update($kmac, $this->V);
|
||||
hash_update($kmac, chr(0x01));
|
||||
hash_update($kmac, $seed);
|
||||
$this->K = hash_final($kmac, true);
|
||||
|
||||
$kmac = $this->_hmac();
|
||||
hash_update($kmac, $this->V);
|
||||
$this->V = hash_final($kmac, true);
|
||||
}
|
||||
|
||||
// TODO: reseed()
|
||||
|
||||
public function generate($len, $enc = null, $add = null, $addEnc = null)
|
||||
{
|
||||
if ($this->reseed > $this->reseedInterval)
|
||||
throw new \Exception("Reseed is required");
|
||||
|
||||
// Optional encoding
|
||||
if( !is_string($enc) )
|
||||
{
|
||||
$addEnc = $enc;
|
||||
$add = $enc;
|
||||
$enc = null;
|
||||
}
|
||||
|
||||
// Optional additional data
|
||||
if( $add != null ) {
|
||||
$add = Utils::toBin($add, $addEnc);
|
||||
$this->_update($add);
|
||||
}
|
||||
|
||||
$temp = "";
|
||||
while( strlen($temp) < $len )
|
||||
{
|
||||
$hmac = $this->_hmac();
|
||||
hash_update($hmac, $this->V);
|
||||
$this->V = hash_final($hmac, true);
|
||||
$temp .= $this->V;
|
||||
}
|
||||
|
||||
$res = substr($temp, 0, $len);
|
||||
$this->_update($add);
|
||||
$this->reseed++;
|
||||
|
||||
return Utils::encode(Utils::toArray($res), $enc);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic;
|
||||
|
||||
use \Exception;
|
||||
use BN\BN;
|
||||
|
||||
if (!function_exists("random_int")) {
|
||||
function random_int($a, $b) {
|
||||
return rand($a, $b);
|
||||
}
|
||||
}
|
||||
|
||||
class Utils
|
||||
{
|
||||
public static $ASSERT_ENABLED;
|
||||
|
||||
public static function toArray($msg, $enc = false)
|
||||
{
|
||||
if( is_array($msg) )
|
||||
return array_slice($msg, 0);
|
||||
|
||||
if( !$msg )
|
||||
return array();
|
||||
|
||||
if( !is_string($msg) )
|
||||
throw new Exception("Not implemented");
|
||||
|
||||
if( !$enc )
|
||||
return array_slice(unpack("C*", $msg), 0);
|
||||
|
||||
if( $enc === "hex" )
|
||||
return array_slice(unpack("C*", hex2bin($msg)), 0);
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
public static function toHex($msg)
|
||||
{
|
||||
if( is_string($msg) )
|
||||
return bin2hex($msg);
|
||||
|
||||
if( !is_array($msg) )
|
||||
throw new Exception("Not implemented");
|
||||
|
||||
$binary = call_user_func_array("pack", array_merge(["C*"], $msg));
|
||||
return bin2hex($binary);
|
||||
}
|
||||
|
||||
public static function toBin($msg, $enc = false)
|
||||
{
|
||||
if( is_array($msg) )
|
||||
return call_user_func_array("pack", array_merge(["C*"], $msg));
|
||||
|
||||
if( $enc === "hex" )
|
||||
return hex2bin($msg);
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
public static function encode($arr, $enc)
|
||||
{
|
||||
if( $enc === "hex" )
|
||||
return self::toHex($arr);
|
||||
return $arr;
|
||||
}
|
||||
|
||||
// Represent num in a w-NAF form
|
||||
public static function getNAF($num, $w)
|
||||
{
|
||||
$naf = array();
|
||||
$ws = 1 << ($w + 1);
|
||||
$k = clone($num);
|
||||
|
||||
while( $k->cmpn(1) >= 0 )
|
||||
{
|
||||
if( !$k->isOdd() )
|
||||
array_push($naf, 0);
|
||||
else
|
||||
{
|
||||
$mod = $k->andln($ws - 1);
|
||||
$z = $mod;
|
||||
if( $mod > (($ws >> 1) - 1))
|
||||
$z = ($ws >> 1) - $mod;
|
||||
$k->isubn($z);
|
||||
array_push($naf, $z);
|
||||
}
|
||||
|
||||
// Optimization, shift by word if possible
|
||||
$shift = (!$k->isZero() && $k->andln($ws - 1) === 0) ? ($w + 1) : 1;
|
||||
for($i = 1; $i < $shift; $i++)
|
||||
array_push($naf, 0);
|
||||
$k->iushrn($shift);
|
||||
}
|
||||
|
||||
return $naf;
|
||||
}
|
||||
|
||||
// Represent k1, k2 in a Joint Sparse Form
|
||||
public static function getJSF($k1, $k2)
|
||||
{
|
||||
$jsf = array( array(), array() );
|
||||
$k1 = $k1->_clone();
|
||||
$k2 = $k2->_clone();
|
||||
$d1 = 0;
|
||||
$d2 = 0;
|
||||
|
||||
while( $k1->cmpn(-$d1) > 0 || $k2->cmpn(-$d2) > 0 )
|
||||
{
|
||||
// First phase
|
||||
$m14 = ($k1->andln(3) + $d1) & 3;
|
||||
$m24 = ($k2->andln(3) + $d2) & 3;
|
||||
if( $m14 === 3 )
|
||||
$m14 = -1;
|
||||
if( $m24 === 3 )
|
||||
$m24 = -1;
|
||||
|
||||
$u1 = 0;
|
||||
if( ($m14 & 1) !== 0 )
|
||||
{
|
||||
$m8 = ($k1->andln(7) + $d1) & 7;
|
||||
$u1 = ( ($m8 === 3 || $m8 === 5) && $m24 === 2 ) ? -$m14 : $m14;
|
||||
}
|
||||
array_push($jsf[0], $u1);
|
||||
|
||||
$u2 = 0;
|
||||
if( ($m24 & 1) !== 0 )
|
||||
{
|
||||
$m8 = ($k2->andln(7) + $d2) & 7;
|
||||
$u2 = ( ($m8 === 3 || $m8 === 5) && $m14 === 2 ) ? -$m24 : $m24;
|
||||
}
|
||||
array_push($jsf[1], $u2);
|
||||
|
||||
// Second phase
|
||||
if( (2 * $d1) === ($u1 + 1) )
|
||||
$d1 = 1 - $d1;
|
||||
if( (2 * $d2) === ($u2 + 1) )
|
||||
$d2 = 1 - $d2;
|
||||
$k1->iushrn(1);
|
||||
$k2->iushrn(1);
|
||||
}
|
||||
|
||||
return $jsf;
|
||||
}
|
||||
|
||||
public static function intFromLE($bytes) {
|
||||
return new BN($bytes, 'hex', 'le');
|
||||
}
|
||||
|
||||
public static function parseBytes($bytes) {
|
||||
if (is_string($bytes))
|
||||
return self::toArray($bytes, 'hex');
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
public static function randBytes($count)
|
||||
{
|
||||
$res = "";
|
||||
for($i = 0; $i < $count; $i++)
|
||||
$res .= chr(random_int(0, 255));
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function optionAssert(&$array, $key, $value = false, $required = false)
|
||||
{
|
||||
if( isset($array[$key]) )
|
||||
return;
|
||||
if( $required )
|
||||
throw new Exception("Missing option " . $key);
|
||||
$array[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
Utils::$ASSERT_ENABLED = ini_get("zend.assertions") === "1";
|
||||
|
||||
?>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"bootstrap": "vendor/autoload.php",
|
||||
"path": "benchmarks",
|
||||
"reports": {
|
||||
"simple": {
|
||||
"generator": "table",
|
||||
"cols": ["subject", "mode", "rstdev", "its", "revs"]
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
stopOnFailure="false"
|
||||
verbose="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="AllTests">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<coverage>
|
||||
<exclude>
|
||||
<directory suffix=".php">lib/</directory>
|
||||
</exclude>
|
||||
</coverage>
|
||||
</phpunit>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
class ApiTest extends \PHPUnit\Framework\TestCase {
|
||||
public function test_should_instatiate_with_valid_curve_secp256k1() {
|
||||
$ec = new \Elliptic\EC('secp256k1');
|
||||
|
||||
$this->assertNotNull($ec);
|
||||
$this->assertInstanceOf(\Elliptic\EC::class, $ec);
|
||||
}
|
||||
|
||||
|
||||
public function test_should_throw_error_with_invalid_curve() {
|
||||
$this->expectException(\Exception::class);
|
||||
$ec = new \Elliptic\EC('nonexistent-curve');
|
||||
}
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
use BN\BN;
|
||||
|
||||
class CurveTest extends \PHPUnit\Framework\TestCase {
|
||||
public function test_should_work_with_example_curve() {
|
||||
$curve = new \Elliptic\Curve\ShortCurve(array(
|
||||
"p" => '1d',
|
||||
"a" => '4',
|
||||
"b" => '14'
|
||||
));
|
||||
|
||||
$p = $curve->point('18', '16');
|
||||
$this->assertTrue($p->validate());
|
||||
$this->assertTrue($p->dbl()->validate());
|
||||
$this->assertTrue($p->dbl()->add($p)->validate());
|
||||
$this->assertTrue($p->dbl()->add($p->dbl())->validate());
|
||||
$this->assertTrue($p->dbl()->add($p->dbl())->eq($p->add($p)->add($p)->add($p)));
|
||||
}
|
||||
|
||||
public function test_should_work_with_secp112k1() {
|
||||
$curve = new \Elliptic\Curve\ShortCurve(array(
|
||||
"p" => 'db7c 2abf62e3 5e668076 bead208b',
|
||||
"a" => 'db7c 2abf62e3 5e668076 bead2088',
|
||||
"b" => '659e f8ba0439 16eede89 11702b22'
|
||||
));
|
||||
|
||||
$p = $curve->point(
|
||||
'0948 7239995a 5ee76b55 f9c2f098',
|
||||
'a89c e5af8724 c0a23e0e 0ff77500');
|
||||
$this->assertTrue($p->validate());
|
||||
$this->assertTrue($p->dbl()->validate());
|
||||
}
|
||||
|
||||
public function test_should_work_with_secp256k1() {
|
||||
$curve = new \Elliptic\Curve\ShortCurve(array(
|
||||
"p" => 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe ' .
|
||||
'fffffc2f',
|
||||
"a" => '0',
|
||||
"b" => '7',
|
||||
"n" => 'ffffffff ffffffff ffffffff fffffffe ' .
|
||||
'baaedce6 af48a03b bfd25e8c d0364141',
|
||||
"g" => [
|
||||
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
|
||||
'483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
|
||||
]
|
||||
));
|
||||
|
||||
$p = $curve->point(
|
||||
'79be667e f9dcbbac 55a06295 ce870b07 029bfcdb 2dce28d9 59f2815b 16f81798',
|
||||
'483ada77 26a3c465 5da4fbfc 0e1108a8 fd17b448 a6855419 9c47d08f fb10d4b8'
|
||||
);
|
||||
$this->assertTrue($p->validate());
|
||||
$this->assertTrue($p->dbl()->validate());
|
||||
$this->assertTrue($p->toJ()->dbl()->toP()->validate());
|
||||
$this->assertTrue($p->mul(new BN('79be667e f9dcbbac 55a06295 ce870b07', 16))->validate());
|
||||
|
||||
$j = $p->toJ();
|
||||
$this->assertTrue($j->trpl()->eq($j->dbl()->add($j)));
|
||||
|
||||
// Endomorphism test
|
||||
$this->assertNotNull($curve->endo);
|
||||
$this->assertEquals(
|
||||
$curve->endo["beta"]->fromRed()->toString(16),
|
||||
'7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee');
|
||||
$this->assertEquals(
|
||||
$curve->endo["lambda"]->toString(16),
|
||||
'5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72');
|
||||
|
||||
$k = new BN('1234567890123456789012345678901234', 16);
|
||||
$split = $curve->_endoSplit($k);
|
||||
|
||||
$testK = $split["k1"]->add($split["k2"]->mul($curve->endo["lambda"]))->umod($curve->n);
|
||||
$this->assertEquals($testK->toString(16), $k->toString(16));
|
||||
}
|
||||
|
||||
public function test_should_compute_this_problematic_secp256k1_multiplication() {
|
||||
$curve = \Elliptic\Curves::getCurve("secp256k1")->curve;
|
||||
$g1 = $curve->g; // precomputed g
|
||||
$this->assertNotNull($g1->precomputed);
|
||||
$g2 = $curve->point($g1->getX(), $g1->getY()); // not precomputed g
|
||||
$this->assertNull($g2->precomputed);
|
||||
$a = new BN(
|
||||
'6d1229a6b24c2e775c062870ad26bc261051e0198c67203167273c7c62538846', 16);
|
||||
$p1 = $g1->mul($a);
|
||||
$p2 = $g2->mul($a);
|
||||
$this->assertTrue($p1->eq($p2));
|
||||
}
|
||||
|
||||
public function test_should_not_use_fixed_NAF_when_k_is_too_large() {
|
||||
$curve = \Elliptic\Curves::getCurve("secp256k1")->curve;
|
||||
$g1 = $curve->g; // precomputed g
|
||||
$this->assertNotNull($g1->precomputed);
|
||||
$g2 = $curve->point($g1->getX(), $g1->getY()); // not precomputed g
|
||||
$this->assertNull($g2->precomputed);
|
||||
|
||||
$a = new BN(
|
||||
'6d1229a6b24c2e775c062870ad26bc26' .
|
||||
'1051e0198c67203167273c7c6253884612345678',
|
||||
16);
|
||||
$p1 = $g1->mul($a);
|
||||
$p2 = $g2->mul($a);
|
||||
$this->assertTrue($p1->eq($p2));
|
||||
}
|
||||
|
||||
public function test_should_not_fail_on_secp256k1_regression() {
|
||||
$curve = \Elliptic\Curves::getCurve("secp256k1")->curve;
|
||||
$k1 = new BN(
|
||||
'32efeba414cd0c830aed727749e816a01c471831536fd2fce28c56b54f5a3bb1', 16);
|
||||
$k2 = new BN(
|
||||
'5f2e49b5d64e53f9811545434706cde4de528af97bfd49fde1f6cf792ee37a8c', 16);
|
||||
|
||||
$p1 = $curve->g->mul($k1);
|
||||
$p2 = $curve->g->mul($k2);
|
||||
|
||||
// 2 + 2 + 1 = 2 + 1 + 2
|
||||
$two = $p2->dbl();
|
||||
$five = $two->dbl()->add($p2);
|
||||
$three = $two->add($p2);
|
||||
$maybeFive = $three->add($two);
|
||||
|
||||
$this->assertTrue($maybeFive->eq($five));
|
||||
|
||||
$p1 = $p1->mul($k2);
|
||||
$p2 = $p2->mul($k1);
|
||||
|
||||
$this->assertTrue($p1->validate());
|
||||
$this->assertTrue($p2->validate());
|
||||
$this->assertTrue($p1->eq($p2));
|
||||
}
|
||||
|
||||
public function test_should_correctly_double_the_affine_point_on_secp256k1() {
|
||||
$bad = new ArrayObject(array(
|
||||
"x" => '026a2073b1ef6fab47ace18e60e728a05180a82755bbcec9a0abc08ad9f7a3d4',
|
||||
"y" => '9cd8cb48c3281596139f147c1364a3ede88d3f310fdb0eb98c924e599ca1b3c9',
|
||||
"z" => 'd78587ad45e4102f48b54b5d85598296e069ce6085002e169c6bad78ddc6d9bd'
|
||||
), ArrayObject::ARRAY_AS_PROPS);
|
||||
|
||||
$good = new ArrayObject(array(
|
||||
"x" => 'e7789226739ac2eb3c7ccb2a9a910066beeed86cdb4e0f8a7fee8eeb29dc7016',
|
||||
"y" => '4b76b191fd6d47d07828ea965e275b76d0e3e0196cd5056d38384fbb819f9fcb',
|
||||
"z" => 'cbf8d99056618ba132d6145b904eee1ce566e0feedb9595139c45f84e90cfa7d'
|
||||
), ArrayObject::ARRAY_AS_PROPS);
|
||||
|
||||
$curve = \Elliptic\Curves::getCurve("secp256k1")->curve;
|
||||
$bad = $curve->jpoint($bad->x, $bad->y, $bad->z);
|
||||
$good = $curve->jpoint($good->x, $good->y, $good->z);
|
||||
|
||||
// They are the same points
|
||||
$this->assertTrue($bad->add($good->neg())->isInfinity());
|
||||
|
||||
// But doubling borks them out
|
||||
$this->assertTrue($bad->dbl()->add($good->dbl()->neg())->isInfinity());
|
||||
}
|
||||
|
||||
public function test_should_store_precomputed_values_correctly_on_negation() {
|
||||
$curve = \Elliptic\Curves::getCurve("secp256k1")->curve;
|
||||
$p = $curve->g->mul('2');
|
||||
$p->precompute();
|
||||
$neg = $p->neg(true);
|
||||
$neg2 = $neg->neg(true);
|
||||
$this->assertTrue($p->eq($neg2));
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
class ECDHTest extends \PHPUnit\Framework\TestCase {
|
||||
public function test_should_work_with_secp256k1_curve() {
|
||||
$this->doTest('secp256k1');
|
||||
}
|
||||
|
||||
public function test_should_work_with_p256_curve() {
|
||||
$this->doTest('p256');
|
||||
}
|
||||
|
||||
public function test_should_work_with_curve25519_curve() {
|
||||
$this->doTest('curve25519');
|
||||
}
|
||||
|
||||
public function test_should_work_with_ed25519_curve() {
|
||||
$this->doTest('ed25519');
|
||||
}
|
||||
|
||||
function doTest($name) {
|
||||
$ecdh = new \Elliptic\EC($name);
|
||||
$s1 = $ecdh->genKeyPair();
|
||||
$s2 = $ecdh->genKeyPair();
|
||||
$sh1 = $s1->derive($s2->getPublic());
|
||||
$sh2 = $s2->derive($s1->getPublic());
|
||||
|
||||
$this->assertEquals($sh1->toString(16), $sh2->toString(16));
|
||||
|
||||
$sh1 = $s1->derive($ecdh->keyFromPublic($s2->getPublic('hex'), 'hex')
|
||||
->getPublic());
|
||||
$sh2 = $s2->derive($ecdh->keyFromPublic($s1->getPublic('hex'), 'hex')
|
||||
->getPublic());
|
||||
$this->assertEquals($sh1->toString(16), $sh2->toString(16));
|
||||
}
|
||||
}
|
||||
+321
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
use BN\BN;
|
||||
|
||||
class ECDSATest extends \PHPUnit\Framework\TestCase {
|
||||
|
||||
function ECDSACurveNames() {
|
||||
return [
|
||||
['secp256k1']
|
||||
, ['ed25519']
|
||||
, ['p256']
|
||||
, ['p384']
|
||||
, ['p521']
|
||||
];
|
||||
}
|
||||
|
||||
static $entropy = [
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
21, 22, 23, 24, 25
|
||||
];
|
||||
|
||||
static $msg = 'deadbeef';
|
||||
|
||||
protected $curve;
|
||||
protected $ecdsa;
|
||||
protected $keys;
|
||||
|
||||
public function prepare($name) {
|
||||
$this->curve = \Elliptic\Curves::getCurve($name);
|
||||
$this->assertNotNull($this->curve);
|
||||
|
||||
$this->ecdsa = new \Elliptic\EC($this->curve);
|
||||
$this->keys = $this->ecdsa->genKeyPair([ "entropy" => self::$entropy ]);
|
||||
return [$this->curve, $this->ecdsa, $this->keys];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_generate_proper_key_pair($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$keylen = 64;
|
||||
if ($name == 'p384') {
|
||||
$keylen = 96;
|
||||
} else if ($name == 'p521') {
|
||||
$keylen = 132;
|
||||
}
|
||||
// Get keys out of pair
|
||||
$this->assertTrue( $keys->getPublic()->x && $keys->getPublic()->y );
|
||||
$this->assertTrue( $keys->getPrivate()->byteLength() > 0);
|
||||
$this->assertEquals( strlen($keys->getPrivate('hex')), $keylen);
|
||||
$this->assertTrue( strlen($keys->getPublic('hex')) > 0);
|
||||
$this->assertTrue( strlen($keys->getPrivate('hex')) > 0);
|
||||
$this->assertTrue( $keys->validate()["result"], 'key validate' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_sign_and_verify($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$signature = $ecdsa->sign(self::$msg, $keys);
|
||||
$this->assertTrue($ecdsa->verify(self::$msg, $signature, $keys), 'Normal verify');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_sign_and_verify_using_keys_methods($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$signature = $keys->sign(self::$msg);
|
||||
$this->assertTrue($keys->verify(self::$msg, $signature), 'On-key verify');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_load_private_key_from_the_hex_value($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$copy = $ecdsa->keyFromPrivate($keys->getPrivate('hex'), 'hex');
|
||||
$signature = $ecdsa->sign(self::$msg, $copy);
|
||||
$this->assertTrue($ecdsa->verify(self::$msg, $signature, $copy), 'hex-private verify');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_have_signature_s_leq_keys_ec_nh($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
// key.sign(msg, options)
|
||||
$sign = $keys->sign('deadbeef', [ "canonical" => true ]);
|
||||
$this->assertTrue($sign->s->cmp($keys->ec->nh) <= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_support_options_k($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$sign = $keys->sign(self::$msg, [
|
||||
"k" => function($iter) {
|
||||
$this->assertTrue($iter >= 0);
|
||||
return new BN(1358);
|
||||
}
|
||||
]);
|
||||
$this->assertTrue($ecdsa->verify(self::$msg, $sign, $keys), 'custom-k verify');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_have_another_signature_with_pers($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$sign1 = $keys->sign(self::$msg);
|
||||
$sign2 = $keys->sign(self::$msg, [ "pers" => '1234', "persEnc" => 'hex' ]);
|
||||
$this->assertNotEquals($sign1->r->toString('hex') . $sign1->s->toString('hex'),
|
||||
$sign2->r->toString('hex') . $sign2->s->toString('hex'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_load_public_key_from_compact_hex_value($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$pub = $keys->getPublic(true, 'hex');
|
||||
$copy = $ecdsa->keyFromPublic($pub, 'hex');
|
||||
$this->assertEquals($copy->getPublic(true, 'hex'), $pub);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_load_public_key_from_hex_value($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$pub = $keys->getPublic('hex');
|
||||
$copy = $ecdsa->keyFromPublic($pub, 'hex');
|
||||
$this->assertEquals($copy->getPublic('hex'), $pub);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_support_hex_DER_encoding_of_signatures($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$signature = $ecdsa->sign(self::$msg, $keys);
|
||||
$dsign = $signature->toDER('hex');
|
||||
$this->assertTrue($ecdsa->verify(self::$msg, $dsign, $keys), 'hex-DER encoded verify');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_support_DER_encoding_of_signatures($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$signature = $ecdsa->sign(self::$msg, $keys);
|
||||
$dsign = $signature->toDER();
|
||||
$this->assertTrue($ecdsa->verify(self::$msg, $dsign, $keys), 'DER encoded verify');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_not_verify_signature_with_wrong_public_key($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$signature = $ecdsa->sign(self::$msg, $keys);
|
||||
|
||||
$wrong = $ecdsa->genKeyPair();
|
||||
$this->assertNotTrue($ecdsa->verify(self::$msg, $signature, $wrong), 'Wrong key verify');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider ECDSACurveNames
|
||||
*/
|
||||
public function test_should_not_verify_signature_with_wrong_private_key($name) {
|
||||
list($curve, $ecdsa, $keys) = $this->prepare($name);
|
||||
$signature = $ecdsa->sign(self::$msg, $keys);
|
||||
|
||||
$wrong = $ecdsa->keyFromPrivate($keys->getPrivate('hex') .
|
||||
$keys->getPrivate('hex'), 'hex');
|
||||
$this->assertNotTrue($ecdsa->verify(self::$msg, $signature, $wrong), 'Wrong key verify');
|
||||
}
|
||||
|
||||
|
||||
// TODO: Implement RFC6979 vectors test
|
||||
|
||||
|
||||
function MaxwellsTrickVector() {
|
||||
$p256 = \Elliptic\Curves::getCurve("p256");
|
||||
$p384 = \Elliptic\Curves::getCurve("p384");
|
||||
$msg = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
|
||||
return [
|
||||
[[
|
||||
"curve" => $p256,
|
||||
"pub" => '041548fc88953e06cd34d4b300804c5322cb48c24aaaa4d0' .
|
||||
'7a541b0f0ccfeedeb0ae4991b90519ea405588bdf699f5e6' .
|
||||
'd0c6b2d5217a5c16e8371062737aa1dae1',
|
||||
"message" => $msg,
|
||||
"sig" => '3006020106020104',
|
||||
"result" => true
|
||||
]],
|
||||
[[
|
||||
"curve" => $p256,
|
||||
"pub" => '04ad8f60e4ec1ebdb6a260b559cb55b1e9d2c5ddd43a41a2' .
|
||||
'd11b0741ef2567d84e166737664104ebbc337af3d861d352' .
|
||||
'4cfbc761c12edae974a0759750c8324f9a',
|
||||
"message" => $msg,
|
||||
"sig" => '3006020106020104',
|
||||
"result" => true
|
||||
]],
|
||||
[[
|
||||
"curve" => $p256,
|
||||
"pub" => '0445bd879143a64af5746e2e82aa65fd2ea07bba4e355940' .
|
||||
'95a981b59984dacb219d59697387ac721b1f1eccf4b11f43' .
|
||||
'ddc39e8367147abab3084142ed3ea170e4',
|
||||
"message" => $msg,
|
||||
"sig" => '301502104319055358e8617b0c46353d039cdaae020104',
|
||||
"result" => true
|
||||
]],
|
||||
[[
|
||||
"curve" => $p256,
|
||||
"pub" => '040feb5df4cc78b35ec9c180cc0de5842f75f088b4845697' .
|
||||
'8ffa98e716d94883e1e6500b2a1f6c1d9d493428d7ae7d9a' .
|
||||
'8a560fff30a3d14aa160be0c5e7edcd887',
|
||||
"message" => $msg,
|
||||
"sig" => '301502104319055358e8617b0c46353d039cdaae020104',
|
||||
"result" => false
|
||||
]],
|
||||
[[
|
||||
"curve" => $p384,
|
||||
"pub" => '0425e299eea9927b39fa92417705391bf17e8110b4615e9e' .
|
||||
'b5da471b57be0c30e7d89dbdc3e5da4eae029b300344d385' .
|
||||
'1548b59ed8be668813905105e673319d59d32f574e180568' .
|
||||
'463c6186864888f6c0b67b304441f82aab031279e48f047c31',
|
||||
"message" => $msg,
|
||||
"sig" => '3006020103020104',
|
||||
"result" => true
|
||||
]],
|
||||
[[
|
||||
"curve" => $p384,
|
||||
"pub" => '04a328f65c22307188b4af65779c1d2ec821c6748c6bd8dc' .
|
||||
'0e6a008135f048f832df501f7f3f79966b03d5bef2f187ec' .
|
||||
'34d85f6a934af465656fb4eea8dd9176ab80fbb4a27a649f' .
|
||||
'526a7dfe616091b78d293552bc093dfde9b31cae69d51d3afb',
|
||||
"message" => $msg,
|
||||
"sig" => '3006020103020104',
|
||||
"result" => true
|
||||
]],
|
||||
[[
|
||||
"curve" => $p384,
|
||||
"pub" => '04242e8585eaa7a28cc6062cab4c9c5fd536f46b17be1728' .
|
||||
'288a2cda5951df4941aed1d712defda023d10aca1c5ee014' .
|
||||
'43e8beacd821f7efa27847418ab95ce2c514b2b6b395ee73' .
|
||||
'417c83dbcad631421f360d84d64658c98a62d685b220f5aad4',
|
||||
"message" => $msg,
|
||||
"sig" => '301d0218389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68e020104',
|
||||
"result" => true
|
||||
]],
|
||||
[[
|
||||
"curve" => $p384,
|
||||
"pub" => '04cdf865dd743fe1c23757ec5e65fd5e4038b472ded2af26' .
|
||||
'1e3d8343c595c8b69147df46379c7ca40e60e80170d34a11' .
|
||||
'88dbb2b6f7d3934c23d2f78cfb0db3f3219959fad63c9b61' .
|
||||
'2ef2f20d679777b84192ce86e781c14b1bbb77eacd6e0520e2',
|
||||
"message" => $msg,
|
||||
"sig" => '301d0218389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68e020104',
|
||||
"result" => false
|
||||
]]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider MaxwellsTrickVector
|
||||
*/
|
||||
public function test_should_pass_on_Maxwells_trick_vectors($vector) {
|
||||
$ecdsa = new \Elliptic\EC($vector["curve"]);
|
||||
$key = $ecdsa->keyFromPublic($vector["pub"], 'hex');
|
||||
$msg = $vector["message"];
|
||||
$sig = $vector["sig"];
|
||||
|
||||
$actual = $ecdsa->verify($msg, $sig, $key);
|
||||
$this->assertEquals($actual, $vector["result"]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function test_should_deterministically_generate_private_key() {
|
||||
$curve = \Elliptic\Curves::getCurve("secp256k1");
|
||||
$this->assertNotNull($curve);
|
||||
|
||||
$ecdsa = new \Elliptic\EC($curve);
|
||||
$keys = $ecdsa->genKeyPair(array(
|
||||
"pers" => 'my.pers.string',
|
||||
"entropy" => hash('sha256', 'hello world', true)
|
||||
));
|
||||
$this->assertEquals(
|
||||
$keys->getPrivate('hex'),
|
||||
'6160edb2b218b7f1394b9ca8eb65a72831032a1f2f3dc2d99291c2f7950ed887');
|
||||
}
|
||||
|
||||
public function test_should_recover_the_public_key_from_a_signature() {
|
||||
$ec = new \Elliptic\EC('secp256k1');
|
||||
$key = $ec->genKeyPair();
|
||||
$msg = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
|
||||
$signature = $key->sign($msg);
|
||||
$recid = $ec->getKeyRecoveryParam($msg, $signature, $key->getPublic());
|
||||
$r = $ec->recoverPubKey($msg, $signature, $recid);
|
||||
$this->assertTrue($key->getPublic()->eq($r), 'the keys should match');
|
||||
}
|
||||
|
||||
public function test_should_fail_to_recover_key_when_no_quadratic_residue_available() {
|
||||
$ec = new \Elliptic\EC('secp256k1');
|
||||
$message =
|
||||
'f75c6b18a72fabc0f0b888c3da58e004f0af1fe14f7ca5d8c897fe164925d5e9';
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
$ec->recoverPubKey($message, [
|
||||
"r" => 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
|
||||
"s" => '8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3'
|
||||
], 0);
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
use \Elliptic\EdDSA;
|
||||
use \Elliptic\Utils;
|
||||
|
||||
function toHex($arg) { return strtoupper(Utils::toHex($arg)); }
|
||||
|
||||
class ED25519Test extends \PHPUnit\Framework\TestCase {
|
||||
public function derivations() {
|
||||
$data = json_decode( file_get_contents(__DIR__ . "/fixtures/derivation-fixtures"), true);
|
||||
$data = array_slice($data, 0, 50);
|
||||
return array_map(function($set) { return [$set]; }, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider derivations
|
||||
*/
|
||||
public function test_derivations_can_compute_correct_a_and_A_from_secret($test) {
|
||||
$ed25519 = new EdDSA("ed25519");
|
||||
$secret = Utils::toArray($test["secret_hex"], 'hex');
|
||||
$key = $ed25519->keyFromSecret($secret);
|
||||
$this->assertEquals( toHex($key->privBytes()), $test["a_hex"] );
|
||||
$xRecovered = toHex( $ed25519->encodeInt(
|
||||
$ed25519->decodePoint( $key->pubBytes() )->getX()) );
|
||||
$this->assertEquals( $xRecovered, $test["A_P"]["x"] );
|
||||
$this->assertEquals( toHex( $key->pubBytes() ), $test["A_hex"] );
|
||||
}
|
||||
|
||||
public function signLines() {
|
||||
$data = file_get_contents(__DIR__ . "/fixtures/sign.input");
|
||||
$lines = array_filter( explode("\n", $data), function($line) { return strlen($line) > 0; });
|
||||
$lines = array_slice($lines, 0, 50);
|
||||
return array_map(function($line) { return [$line]; }, $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider signLines
|
||||
*/
|
||||
public function test_sign_input_test_vectors($line) {
|
||||
$split = explode(':', strtoupper($line));
|
||||
$ed25519 = new EdDSA("ed25519");
|
||||
$key = $ed25519->keyFromSecret(substr($split[0], 0, 64));
|
||||
$expectedPk = substr($split[0], 64);
|
||||
$this->assertEquals( toHex($key->pubBytes()), $expectedPk);
|
||||
|
||||
$msg = Utils::toArray($split[2], 'hex');
|
||||
$sig = $key->sign($msg)->toHex();
|
||||
$sigR = substr($sig, 0, 64);
|
||||
$sigS = substr($sig, 64);
|
||||
|
||||
$this->assertEquals($sigR, substr($split[3], 0, 64));
|
||||
$this->assertEquals($sigS, substr($split[3], 64, 64));
|
||||
$this->assertTrue($key->verify($msg, $sig));
|
||||
|
||||
if (count($msg) == 0) {
|
||||
$forged = [ 0x78 ] /* ord('x') */;
|
||||
} else {
|
||||
$forged = $msg;
|
||||
$forged[count($msg) - 1] = ($msg[count($msg) - 1] + 1) % 256;
|
||||
}
|
||||
|
||||
$this->assertNotTrue($key->verify($forged, $sig));
|
||||
}
|
||||
|
||||
public function test_eddsa_has_encodingLength_of_32() {
|
||||
$ed25519 = new EdDSA("ed25519");
|
||||
$this->assertEquals(32, $ed25519->encodingLength);
|
||||
}
|
||||
|
||||
public function test_eddsa_can_sign_and_verify_messages() {
|
||||
$ed25519 = new EdDSA("ed25519");
|
||||
$secret = array_fill(0, 32, 0);
|
||||
$msg = [ 0xB, 0xE, 0xE, 0xF ];
|
||||
$key = $ed25519->keyFromSecret($secret);
|
||||
$sig = $key->sign($msg)->toHex();
|
||||
|
||||
$R = '8F1B9A7FDB22BCD2C15D4695B1CE2B063CBFAEC9B00BE360427BAC9533943F6C';
|
||||
$S = '5F0B380FD7F2E43B70AB2FA29F6C6E3FFC1012710E174786814012324BF19B0C';
|
||||
|
||||
$this->assertEquals(substr($sig, 0, 64), $R);
|
||||
$this->assertEquals(substr($sig, 64), $S);
|
||||
|
||||
$this->assertTrue($key->verify($msg, $sig));
|
||||
}
|
||||
|
||||
static $secret = '0000000000000000000000000000000000000000000000000000000000000000';
|
||||
public function test_eddsa_keypair_can_be_created_with_keyFromSecret_or_keyFromPublic() {
|
||||
$ed25519 = new EdDSA("ed25519");
|
||||
$pair = $ed25519->keyFromSecret(self::$secret);
|
||||
$pubKey = $ed25519->keyFromPublic( toHex($pair->pubBytes()) );
|
||||
$this->assertTrue( is_a($pubKey->pub(), $ed25519->pointClass) );
|
||||
$this->assertTrue( $pubKey->pub()->eq($pair->pub()));
|
||||
}
|
||||
|
||||
public function test_eddsa_keypair_getSecret_returns_bytes_with_optional_encoding() {
|
||||
$ed25519 = new EdDSA("ed25519");
|
||||
$pair = $ed25519->keyFromSecret(self::$secret);
|
||||
$this->assertTrue( is_array($pair->getSecret()) );
|
||||
$this->assertTrue( $pair->getSecret('hex') == self::$secret);
|
||||
}
|
||||
|
||||
public function test_eddsa_keypair_getPub_returns_bytes_with_optional_encoding() {
|
||||
$ed25519 = new EdDSA("ed25519");
|
||||
$pair = $ed25519->keyFromSecret(self::$secret);
|
||||
$this->assertTrue( is_array($pair->getPublic()) );
|
||||
$this->assertEquals( $pair->getPublic('hex'),
|
||||
'3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
class HmacDRBGTest extends \PHPUnit\Framework\TestCase {
|
||||
|
||||
public function test_should_support_hmac_drbg_sha256() {
|
||||
function doDrbg($opt) {
|
||||
$drbg = new \Elliptic\HmacDRBG([
|
||||
"hash" => ["algo" => 'sha256', 'outSize' => 256, 'hmacStrength' => 192],//hash.sha256,
|
||||
"entropy" => $opt["entropy"],
|
||||
"nonce" => $opt["nonce"],
|
||||
"pers" => $opt["pers"]
|
||||
]);
|
||||
return $drbg->generate($opt["size"], 'hex');
|
||||
}
|
||||
|
||||
$test = [
|
||||
[
|
||||
"entropy" => 'totally random0123456789',
|
||||
"nonce" => 'secret nonce',
|
||||
"pers" => 'my drbg',
|
||||
"size" => 32,
|
||||
"res" => '018ec5f8e08c41e5ac974eb129ac297c5388ee1864324fa13d9b15cf98d9a157'
|
||||
],
|
||||
[
|
||||
"entropy" => 'totally random0123456789',
|
||||
"nonce" => 'secret nonce',
|
||||
"pers" => null,
|
||||
"size" => 32,
|
||||
"res" => 'ed5d61ecf0ef38258e62f03bbb49f19f2cd07ba5145a840d83b134d5963b3633'
|
||||
]
|
||||
];
|
||||
for ($i = 0; $i < count($test); $i++)
|
||||
$this->assertEquals(doDrbg($test[$i]), $test[$i]["res"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider NISTVector
|
||||
*/
|
||||
public function test_should_not_fail_at_NIST_vector($opt) {
|
||||
$drbg = new \Elliptic\HmacDRBG([
|
||||
"hash" => ["algo" => 'sha256', 'outSize' => 256, 'hmacStrength' => 192],//hash.sha256,
|
||||
"entropy" => $opt["entropy"],
|
||||
"entropyEnc" => 'hex',
|
||||
"nonce" => $opt["nonce"],
|
||||
"nonceEnc" => 'hex',
|
||||
"pers" => $opt["pers"],
|
||||
"persEnc" => 'hex'
|
||||
]);
|
||||
|
||||
for ($i = 0; $i < count($opt["add"]); $i++) {
|
||||
$last = $drbg->generate(strlen($opt["expected"]) / 2,
|
||||
'hex',
|
||||
$opt["add"][$i],
|
||||
'hex');
|
||||
}
|
||||
$this->assertEquals($last, $opt["expected"]);
|
||||
}
|
||||
|
||||
function NISTVector() {
|
||||
$data = json_decode(file_get_contents(__DIR__."/fixtures/hmac-drbg-nist.json"), true);
|
||||
$cases = array();
|
||||
for($i = 0; $i < count($data); ++$i) {
|
||||
$cases[ $data[$i]["name"] ] = [ $data[$i] ];
|
||||
}
|
||||
return $cases;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
require_once __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
class PointCodecTest extends \PHPUnit\Framework\TestCase {
|
||||
function makeShortTest($definition) {
|
||||
$curve = \Elliptic\Curves::getCurve("secp256k1")->curve;
|
||||
|
||||
return function() use($curve, $definition) {
|
||||
$co = $definition["coordinates"];
|
||||
$p = $curve->point($co["x"], $co["y"]);
|
||||
|
||||
// Encodes as expected
|
||||
$this->assertEquals($p->encode('hex'), $definition["encoded"]);
|
||||
$this->assertEquals($p->encodeCompressed('hex'), $definition["compactEncoded"]);
|
||||
|
||||
// Decodes as expected
|
||||
$this->assertTrue($curve->decodePoint($definition["encoded"], 'hex')->eq($p));
|
||||
$this->assertTrue($curve->decodePoint($definition["compactEncoded"], 'hex')->eq($p));
|
||||
$this->assertTrue($curve->decodePoint($definition["hybrid"], 'hex')->eq($p));
|
||||
};
|
||||
}
|
||||
|
||||
function makeMontTest($definition) {
|
||||
$curve = \Elliptic\Curves::getCurve("curve25519")->curve;
|
||||
return function() use ($definition, $curve) {
|
||||
$co = $definition["coordinates"];
|
||||
$p = $curve->point($co["x"], $co["z"]);
|
||||
$encoded = $p->encode('hex');
|
||||
$decoded = $curve->decodePoint($encoded, 'hex');
|
||||
$this->assertTrue($decoded->eq($p));
|
||||
$this->assertEquals($encoded, $definition["encoded"]);
|
||||
};
|
||||
}
|
||||
|
||||
static $shortPointEvenY;
|
||||
static $shortPointOddY;
|
||||
|
||||
public function test_should_throw_when_trying_to_decode_random_bytes() {
|
||||
$this->expectException(\Exception::class);
|
||||
\Elliptic\Curves::getCurve("secp256k1")->curve->decodePoint(
|
||||
'05' .
|
||||
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798');
|
||||
}
|
||||
|
||||
public function test_should_be_able_to_encode_and_decode_a_short_curve_point_with_even_Y() {
|
||||
$f = $this->makeShortTest(self::$shortPointEvenY);
|
||||
$f();
|
||||
}
|
||||
|
||||
public function test_should_be_able_to_encode_and_decode_a_short_curve_point_with_odd_Y() {
|
||||
$f = $this->makeShortTest(self::$shortPointOddY);
|
||||
$f();
|
||||
}
|
||||
|
||||
public function test_should_be_able_to_encode_and_decode_a_mont_curve_point() {
|
||||
$f = $this->makeMontTest([
|
||||
"coordinates" => [
|
||||
// curve25519.curve.g.mul(new BN('6')).getX().toString(16, 2)
|
||||
"x" => '26954ccdc99ebf34f8f1dde5e6bb080685fec73640494c28f9fe0bfa8c794531',
|
||||
"z" => '1'
|
||||
],
|
||||
"encoded" =>
|
||||
'26954ccdc99ebf34f8f1dde5e6bb080685fec73640494c28f9fe0bfa8c794531'
|
||||
]);
|
||||
$f();
|
||||
}
|
||||
}
|
||||
|
||||
PointCodecTest::$shortPointEvenY = [
|
||||
"coordinates" => [
|
||||
"x" => '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
|
||||
"y" => '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
|
||||
],
|
||||
"compactEncoded" =>
|
||||
'02' .
|
||||
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
|
||||
"encoded" =>
|
||||
'04' .
|
||||
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' .
|
||||
'483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8',
|
||||
"hybrid" =>
|
||||
'06' .
|
||||
'79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' .
|
||||
'483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
|
||||
];
|
||||
|
||||
|
||||
PointCodecTest::$shortPointOddY = [
|
||||
"coordinates" => [
|
||||
"x" => 'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556',
|
||||
"y" => 'ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297'
|
||||
],
|
||||
"compactEncoded" =>
|
||||
'03' .
|
||||
'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556',
|
||||
"encoded" =>
|
||||
'04' .
|
||||
'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556' .
|
||||
'ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297',
|
||||
"hybrid" =>
|
||||
'07' .
|
||||
'fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556' .
|
||||
'ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297'
|
||||
];
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,332 @@
|
||||
[
|
||||
{
|
||||
"name": "0",
|
||||
"entropy": "ca851911349384bffe89de1cbdc46e6831e44d34a4fb935ee285dd14b71a7488",
|
||||
"nonce": "659ba96c601dc69fc902940805ec0ca8",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "e528e9abf2dece54d47c7e75e5fe302149f817ea9fb4bee6f4199697d04d5b89d54fbb978a15b5c443c9ec21036d2460b6f73ebad0dc2aba6e624abf07745bc107694bb7547bb0995f70de25d6b29e2d3011bb19d27676c07162c8b5ccde0668961df86803482cb37ed6d5c0bb8d50cf1f50d476aa0458bdaba806f48be9dcb8"
|
||||
},
|
||||
{
|
||||
"name": "1",
|
||||
"entropy": "79737479ba4e7642a221fcfd1b820b134e9e3540a35bb48ffae29c20f5418ea3",
|
||||
"nonce": "3593259c092bef4129bc2c6c9e19f343",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "cf5ad5984f9e43917aa9087380dac46e410ddc8a7731859c84e9d0f31bd43655b924159413e2293b17610f211e09f770f172b8fb693a35b85d3b9e5e63b1dc252ac0e115002e9bedfb4b5b6fd43f33b8e0eafb2d072e1a6fee1f159df9b51e6c8da737e60d5032dd30544ec51558c6f080bdbdab1de8a939e961e06b5f1aca37"
|
||||
},
|
||||
{
|
||||
"name": "2",
|
||||
"entropy": "b340907445b97a8b589264de4a17c0bea11bb53ad72f9f33297f05d2879d898d",
|
||||
"nonce": "65cb27735d83c0708f72684ea58f7ee5",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "75183aaaf3574bc68003352ad655d0e9ce9dd17552723b47fab0e84ef903694a32987eeddbdc48efd24195dbdac8a46ba2d972f5808f23a869e71343140361f58b243e62722088fe10a98e43372d252b144e00c89c215a76a121734bdc485486f65c0b16b8963524a3a70e6f38f169c12f6cbdd169dd48fe4421a235847a23ff"
|
||||
},
|
||||
{
|
||||
"name": "3",
|
||||
"entropy": "8e159f60060a7d6a7e6fe7c9f769c30b98acb1240b25e7ee33f1da834c0858e7",
|
||||
"nonce": "c39d35052201bdcce4e127a04f04d644",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "62910a77213967ea93d6457e255af51fc79d49629af2fccd81840cdfbb4910991f50a477cbd29edd8a47c4fec9d141f50dfde7c4d8fcab473eff3cc2ee9e7cc90871f180777a97841597b0dd7e779eff9784b9cc33689fd7d48c0dcd341515ac8fecf5c55a6327aea8d58f97220b7462373e84e3b7417a57e80ce946d6120db5"
|
||||
},
|
||||
{
|
||||
"name": "4",
|
||||
"entropy": "74755f196305f7fb6689b2fe6835dc1d81484fc481a6b8087f649a1952f4df6a",
|
||||
"nonce": "c36387a544a5f2b78007651a7b74b749",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "b2896f3af4375dab67e8062d82c1a005ef4ed119d13a9f18371b1b873774418684805fd659bfd69964f83a5cfe08667ddad672cafd16befffa9faed49865214f703951b443e6dca22edb636f3308380144b9333de4bcb0735710e4d9266786342fc53babe7bdbe3c01a3addb7f23c63ce2834729fabbd419b47beceb4a460236"
|
||||
},
|
||||
{
|
||||
"name": "5",
|
||||
"entropy": "4b222718f56a3260b3c2625a4cf80950b7d6c1250f170bd5c28b118abdf23b2f",
|
||||
"nonce": "7aed52d0016fcaef0b6492bc40bbe0e9",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "a6da029b3665cd39fd50a54c553f99fed3626f4902ffe322dc51f0670dfe8742ed48415cf04bbad5ed3b23b18b7892d170a7dcf3ef8052d5717cb0c1a8b3010d9a9ea5de70ae5356249c0e098946030c46d9d3d209864539444374d8fbcae068e1d6548fa59e6562e6b2d1acbda8da0318c23752ebc9be0c1c1c5b3cf66dd967"
|
||||
},
|
||||
{
|
||||
"name": "6",
|
||||
"entropy": "b512633f27fb182a076917e39888ba3ff35d23c3742eb8f3c635a044163768e0",
|
||||
"nonce": "e2c39b84629a3de5c301db5643af1c21",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "fb931d0d0194a97b48d5d4c231fdad5c61aedf1c3a55ac24983ecbf38487b1c93396c6b86ff3920cfa8c77e0146de835ea5809676e702dee6a78100da9aa43d8ec0bf5720befa71f82193205ac2ea403e8d7e0e6270b366dc4200be26afd9f63b7e79286a35c688c57cbff55ac747d4c28bb80a2b2097b3b62ea439950d75dff"
|
||||
},
|
||||
{
|
||||
"name": "7",
|
||||
"entropy": "aae3ffc8605a975befefcea0a7a286642bc3b95fb37bd0eb0585a4cabf8b3d1e",
|
||||
"nonce": "9504c3c0c4310c1c0746a036c91d9034",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "2819bd3b0d216dad59ddd6c354c4518153a2b04374b07c49e64a8e4d055575dfbc9a8fcde68bd257ff1ba5c6000564b46d6dd7ecd9c5d684fd757df62d85211575d3562d7814008ab5c8bc00e7b5a649eae2318665b55d762de36eba00c2906c0e0ec8706edb493e51ca5eb4b9f015dc932f262f52a86b11c41e9a6d5b3bd431"
|
||||
},
|
||||
{
|
||||
"name": "8",
|
||||
"entropy": "b9475210b79b87180e746df704b3cbc7bf8424750e416a7fbb5ce3ef25a82cc6",
|
||||
"nonce": "24baf03599c10df6ef44065d715a93f7",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "ae12d784f796183c50db5a1a283aa35ed9a2b685dacea97c596ff8c294906d1b1305ba1f80254eb062b874a8dfffa3378c809ab2869aa51a4e6a489692284a25038908a347342175c38401193b8afc498077e10522bec5c70882b7f760ea5946870bd9fc72961eedbe8bff4fd58c7cc1589bb4f369ed0d3bf26c5bbc62e0b2b2"
|
||||
},
|
||||
{
|
||||
"name": "9",
|
||||
"entropy": "27838eb44ceccb4e36210703ebf38f659bc39dd3277cd76b7a9bcd6bc964b628",
|
||||
"nonce": "39cfe0210db2e7b0eb52a387476e7ea1",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "e5e72a53605d2aaa67832f97536445ab774dd9bff7f13a0d11fd27bf6593bfb52309f2d4f09d147192199ea584503181de87002f4ee085c7dc18bf32ce5315647a3708e6f404d6588c92b2dda599c131aa350d18c747b33dc8eda15cf40e95263d1231e1b4b68f8d829f86054d49cfdb1b8d96ab0465110569c8583a424a099a"
|
||||
},
|
||||
{
|
||||
"name": "10",
|
||||
"entropy": "d7129e4f47008ad60c9b5d081ff4ca8eb821a6e4deb91608bf4e2647835373a5",
|
||||
"nonce": "a72882773f78c2fc4878295840a53012",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "0cbf48585c5de9183b7ff76557f8fc9ebcfdfde07e588a8641156f61b7952725bbee954f87e9b937513b16bba0f2e523d095114658e00f0f3772175acfcb3240a01de631c19c5a834c94cc58d04a6837f0d2782fa53d2f9f65178ee9c837222494c799e64c60406069bd319549b889fa00a0032dd7ba5b1cc9edbf58de82bfcd"
|
||||
},
|
||||
{
|
||||
"name": "11",
|
||||
"entropy": "67fe5e300c513371976c80de4b20d4473889c9f1214bce718bc32d1da3ab7532",
|
||||
"nonce": "e256d88497738a33923aa003a8d7845c",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "b44660d64ef7bcebc7a1ab71f8407a02285c7592d755ae6766059e894f694373ed9c776c0cfc8594413eefb400ed427e158d687e28da3ecc205e0f7370fb089676bbb0fa591ec8d916c3d5f18a3eb4a417120705f3e2198154cd60648dbfcfc901242e15711cacd501b2c2826abe870ba32da785ed6f1fdc68f203d1ab43a64f"
|
||||
},
|
||||
{
|
||||
"name": "12",
|
||||
"entropy": "de8142541255c46d66efc6173b0fe3ffaf5936c897a3ce2e9d5835616aafa2cb",
|
||||
"nonce": "d01f9002c407127bc3297a561d89b81d",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "64d1020929d74716446d8a4e17205d0756b5264867811aa24d0d0da8644db25d5cde474143c57d12482f6bf0f31d10af9d1da4eb6d701bdd605a8db74fb4e77f79aaa9e450afda50b18d19fae68f03db1d7b5f1738d2fdce9ad3ee9461b58ee242daf7a1d72c45c9213eca34e14810a9fca5208d5c56d8066bab1586f1513de7"
|
||||
},
|
||||
{
|
||||
"name": "13",
|
||||
"entropy": "4a8e0bd90bdb12f7748ad5f147b115d7385bb1b06aee7d8b76136a25d779bcb7",
|
||||
"nonce": "7f3cce4af8c8ce3c45bdf23c6b181a00",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "320c7ca4bbeb7af977bc054f604b5086a3f237aa5501658112f3e7a33d2231f5536d2c85c1dad9d9b0bf7f619c81be4854661626839c8c10ae7fdc0c0b571be34b58d66da553676167b00e7d8e49f416aacb2926c6eb2c66ec98bffae20864cf92496db15e3b09e530b7b9648be8d3916b3c20a3a779bec7d66da63396849aaf"
|
||||
},
|
||||
{
|
||||
"name": "14",
|
||||
"entropy": "451ed024bc4b95f1025b14ec3616f5e42e80824541dc795a2f07500f92adc665",
|
||||
"nonce": "2f28e6ee8de5879db1eccd58c994e5f0",
|
||||
"pers": null,
|
||||
"add": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"expected": "3fb637085ab75f4e95655faae95885166a5fbb423bb03dbf0543be063bcd48799c4f05d4e522634d9275fe02e1edd920e26d9accd43709cb0d8f6e50aa54a5f3bdd618be23cf73ef736ed0ef7524b0d14d5bef8c8aec1cf1ed3e1c38a808b35e61a44078127c7cb3a8fd7addfa50fcf3ff3bc6d6bc355d5436fe9b71eb44f7fd"
|
||||
},
|
||||
{
|
||||
"name": "0 with additional data",
|
||||
"entropy": "d3cc4d1acf3dde0c4bd2290d262337042dc632948223d3a2eaab87da44295fbd",
|
||||
"nonce": "0109b0e729f457328aa18569a9224921",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"3c311848183c9a212a26f27f8c6647e40375e466a0857cc39c4e47575d53f1f6",
|
||||
"fcb9abd19ccfbccef88c9c39bfb3dd7b1c12266c9808992e305bc3cff566e4e4"
|
||||
],
|
||||
"expected": "9c7b758b212cd0fcecd5daa489821712e3cdea4467b560ef5ddc24ab47749a1f1ffdbbb118f4e62fcfca3371b8fbfc5b0646b83e06bfbbab5fac30ea09ea2bc76f1ea568c9be0444b2cc90517b20ca825f2d0eccd88e7175538b85d90ab390183ca6395535d34473af6b5a5b88f5a59ee7561573337ea819da0dcc3573a22974"
|
||||
},
|
||||
{
|
||||
"name": "1 with additional data",
|
||||
"entropy": "f97a3cfd91faa046b9e61b9493d436c4931f604b22f1081521b3419151e8ff06",
|
||||
"nonce": "11f3a7d43595357d58120bd1e2dd8aed",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"517289afe444a0fe5ed1a41dbbb5eb17150079bdd31e29cf2ff30034d8268e3b",
|
||||
"88028d29ef80b4e6f0fe12f91d7449fe75062682e89c571440c0c9b52c42a6e0"
|
||||
],
|
||||
"expected": "c6871cff0824fe55ea7689a52229886730450e5d362da5bf590dcf9acd67fed4cb32107df5d03969a66b1f6494fdf5d63d5b4d0d34ea7399a07d0116126d0d518c7c55ba46e12f62efc8fe28a51c9d428e6d371d7397ab319fc73ded4722e5b4f30004032a6128df5e7497ecf82ca7b0a50e867ef6728a4f509a8c859087039c"
|
||||
},
|
||||
{
|
||||
"name": "2 with additional data",
|
||||
"entropy": "0f2f23d64f481cabec7abb01db3aabf125c3173a044b9bf26844300b69dcac8b",
|
||||
"nonce": "9a5ae13232b43aa19cfe8d7958b4b590",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"ec4c7a62acab73385f567da10e892ff395a0929f959231a5628188ce0c26e818",
|
||||
"6b97b8c6b6bb8935e676c410c17caa8042aa3145f856d0a32b641e4ae5298648"
|
||||
],
|
||||
"expected": "7480a361058bd9afa3db82c9d7586e42269102013f6ec5c269b6d05f17987847748684766b44918fd4b65e1648622fc0e0954178b0279dfc9fa99b66c6f53e51c4860131e9e0644287a4afe4ca8e480417e070db68008a97c3397e4b320b5d1a1d7e1d18a95cfedd7d1e74997052bf649d132deb9ec53aae7dafdab55e6dae93"
|
||||
},
|
||||
{
|
||||
"name": "3 with additional data",
|
||||
"entropy": "53c56660c78481be9c63284e005fcc14fbc7fb27732c9bf1366d01a426765a31",
|
||||
"nonce": "dc7a14d0eb5b0b3534e717a0b3c64614",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"3aa848706ecb877f5bedf4ffc332d57c22e08747a47e75cff6f0fd1316861c95",
|
||||
"9a401afa739b8f752fddacd291e0b854f5eff4a55b515e20cb319852189d3722"
|
||||
],
|
||||
"expected": "5c0eb420e0bf41ce9323e815310e4e8303cd677a8a8b023f31f0d79f0ca15aeb636099a369fd074d69889865eac1b72ab3cbfebdb8cf460b00072802e2ec648b1349a5303be4ccaadd729f1a9ea17482fd026aaeb93f1602bc1404b9853adde40d6c34b844cf148bc088941ecfc1642c8c0b9778e45f3b07e06e21ee2c9e0300"
|
||||
},
|
||||
{
|
||||
"name": "4 with additional data",
|
||||
"entropy": "f63c804404902db334c54bb298fc271a21d7acd9f770278e089775710bf4fdd7",
|
||||
"nonce": "3e45009ea9cb2a36ba1aa4bf39178200",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"d165a13dc8cc43f3f0952c3f5d3de4136954d983683d4a3e6d2dc4c89bf23423",
|
||||
"75106bc86d0336df85097f6af8e80e2da59046a03fa65b06706b8bbc7ffc6785"
|
||||
],
|
||||
"expected": "6363139bba32c22a0f5cd23ca6d437b5669b7d432f786b8af445471bee0b2d24c9d5f2f93717cbe00d1f010cc3b9c515fc9f7336d53d4d26ba5c0d76a90186663c8582eb739c7b6578a3328bf68dc2cec2cd89b3a90201f6993adcc854df0f5c6974d0f5570765a15fe03dbce28942dd2fd16ba2027e68abac83926969349af8"
|
||||
},
|
||||
{
|
||||
"name": "5 with additional data",
|
||||
"entropy": "2aaca9147da66c176615726b69e3e851cc3537f5f279fe7344233d8e44cfc99d",
|
||||
"nonce": "4e171f080af9a6081bee9f183ac9e340",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"d75a2a6eb66c3833e50f5ec3d2e434cf791448d618026d0c360806d120ded669",
|
||||
"b643b74c15b37612e6577ed7ca2a4c67a78d560af9eb50a4108fca742e87b8d6"
|
||||
],
|
||||
"expected": "501dcdc977f4ba856f24eaa4968b374bebb3166b280334cb510232c31ebffde10fa47b7840ef3fe3b77725c2272d3a1d4219baf23e0290c622271edcced58838cf428f0517425d2e19e0d8c89377eecfc378245f283236fafa466c914b99672ceafab369e8889a0c866d8bd639db9fb797254262c6fd44cfa9045ad6340a60ef"
|
||||
},
|
||||
{
|
||||
"name": "6 with additional data",
|
||||
"entropy": "a2e4cd48a5cf918d6f55942d95fcb4e8465cdc4f77b7c52b6fae5b16a25ca306",
|
||||
"nonce": "bef036716440db6e6d333d9d760b7ca8",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"bfa591c7287f3f931168f95e38869441d1f9a11035ad8ea625bb61b9ea17591c",
|
||||
"c00c735463bca215adc372cb892b05e939bf669583341c06d4e31d0e5b363a37"
|
||||
],
|
||||
"expected": "e7d136af69926a5421d4266ee0420fd729f2a4f7c295d3c966bdfa05268180b508b8a2852d1b3a06fd2ab3e13c54005123ef319f42d0c6d3a575e6e7e1496cb28aacadbcf83740fba8f35fcee04bb2ed8a51db3d3362b01094a62fb57e33c99a432f29fce6676cffbbcc05107e794e75e44a02d5e6d9d748c5fbff00a0178d65"
|
||||
},
|
||||
{
|
||||
"name": "7 with additional data",
|
||||
"entropy": "95a67771cba69011a79776e713145d309edae56fad5fd6d41d83eaff89df6e5e",
|
||||
"nonce": "be5b5164e31ecc51ba6f7c3c5199eb33",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"065f693b229a7c4fd373cd15b3807552dd9bf98c5485cef361949d4e7d774b53",
|
||||
"9afb62406f0e812c4f156d58b19a656c904813c1b4a45a0029ae7f50731f8014"
|
||||
],
|
||||
"expected": "f61b61a6e79a41183e8ed6647899d2dc85cdaf5c3abf5c7f3bf37685946dc28f4923dc842f2d4326bd6ce0d50a84cb3ba869d72a36e246910eba6512ba36cd7ed3a5437c9245b00a344308c792b668b458d3c3e16dee2fbec41867da31084d46d8ec168de2148ef64fc5b72069abf5a6ada1ead2b7146bb793ff1c9c3690fa56"
|
||||
},
|
||||
{
|
||||
"name": "8 with additional data",
|
||||
"entropy": "a459e1815cbca4514ec8094d5ab2414a557ba6fe10e613c345338d0521e4bf90",
|
||||
"nonce": "62221392e2552e76cd0d36df6e6068eb",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"0a3642b02b23b3ef62c701a63401124022f5b896de86dab6e6c7451497aa1dcc",
|
||||
"c80514865901371c45ba92d9f95d50bb7c9dd1768cb3dfbc45b968da94965c6e"
|
||||
],
|
||||
"expected": "464e6977b8adaef307c9623e41c357013249c9ffd77f405f3925cebb69f151ce8fbb6a277164002aee7858fc224f6499042aa1e6322deee9a5d133c31d640e12a7487c731ba03ad866a24675badb1d79220c40be689f79c2a0be93cb4dada3e0eac4ab140cb91998b6f11953e68f2319b050c40f71c34de9905ae41b2de1c2f6"
|
||||
},
|
||||
{
|
||||
"name": "9 with additional data",
|
||||
"entropy": "252c2cad613e002478162861880979ee4e323025eebb6fb2e0aa9f200e28e0a1",
|
||||
"nonce": "d001bc9a8f2c8c242e4369df0c191989",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"9bcfc61cb2bc000034bb3db980eb47c76fb5ecdd40553eff113368d639b947fd",
|
||||
"8b0565c767c2610ee0014582e9fbecb96e173005b60e9581503a6dca5637a26e"
|
||||
],
|
||||
"expected": "e96c15fe8a60692b0a7d67171e0195ff6e1c87aab844221e71700d1bbee75feea695f6a740c9760bbe0e812ecf4061d8f0955bc0195e18c4fd1516ebca50ba6a6db86881737dbab8321707675479b87611db6af2c97ea361a5484555ead454defb1a64335de964fc803d40f3a6f057893d2afc25725754f4f00abc51920743dc"
|
||||
},
|
||||
{
|
||||
"name": "10 with additional data",
|
||||
"entropy": "8be0ca6adc8b3870c9d69d6021bc1f1d8eb9e649073d35ee6c5aa0b7e56ad8a5",
|
||||
"nonce": "9d1265f7d51fdb65377f1e6edd6ae0e4",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"da86167ac997c406bb7979f423986a84ec6614d6caa7afc10aff0699a9b2cf7f",
|
||||
"e4baa3c555950b53e2bfdba480cb4c94b59381bac1e33947e0c22e838a9534cf"
|
||||
],
|
||||
"expected": "64384ecc4ea6b458efc227ca697eac5510092265520c0a0d8a0ccf9ed3ca9d58074671188c6a7ad16d0b050cdc072c125d7298d3a31d9f044a9ee40da0089a84fea28cc7f05f1716db952fad29a0e779635cb7a912a959be67be2f0a4170aace2981802e2ff6467e5b46f0ffbff3b42ba5935fd553c82482ac266acf1cd247d7"
|
||||
},
|
||||
{
|
||||
"name": "11 with additional data",
|
||||
"entropy": "d43a75b6adf26d60322284cb12ac38327792442aa8f040f60a2f331b33ac4a8f",
|
||||
"nonce": "0682f8b091f811afacaacaec9b04d279",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"7fd3b8f512940da7de5d80199d9a7b42670c04a945775a3dba869546cbb9bc65",
|
||||
"2575db20bc7aafc2a90a5dabab760db851d754777bc9f05616af1858b24ff3da"
|
||||
],
|
||||
"expected": "0da7a8dc73c163014bf0841913d3067806456bbca6d5de92b85534c6545467313648d71ef17c923d090dc92cff8d4d1a9a2bb63e001dc2e8ab1a597999be3d6cf70ff63fee9985801395fbd4f4990430c4259fcae4fa1fcd73dc3187ccc102d04af7c07532885e5a226fc42809c48f22eecf4f6ab996ae4fcb144786957d9f41"
|
||||
},
|
||||
{
|
||||
"name": "12 with additional data",
|
||||
"entropy": "64352f236af5d32067a529a8fd05ba00a338c9de306371a0b00c36e610a48d18",
|
||||
"nonce": "df99ed2c7608c870624b962a5dc68acd",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"da416335e7aaf60cf3d06fb438735ce796aad09034f8969c8f8c3f81e32fef24",
|
||||
"a28c07c21a2297311adf172c19e83ca0a87731bdffb80548978d2d1cd82cf8a3"
|
||||
],
|
||||
"expected": "132b9f25868729e3853d3c51f99a3b5fae6d4204bea70890daf62e042b776a526c8fb831b80a6d5d3f153237df1fd39b6fd9137963f5516d9cdd4e3f9195c46e9972c15d3edc6606e3368bde1594977fb88d0ca6e6f5f3d057ccadc7d7dab77dfc42658a1e972aa446b20d418286386a52dfc1c714d2ac548713268b0b709729"
|
||||
},
|
||||
{
|
||||
"name": "13 with additional data",
|
||||
"entropy": "282f4d2e05a2cd30e9087f5633089389449f04bac11df718c90bb351cd3653a5",
|
||||
"nonce": "90a7daf3c0de9ea286081efc4a684dfb",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"2630b4ccc7271cc379cb580b0aaede3d3aa8c1c7ba002cf791f0752c3d739007",
|
||||
"c31d69de499f1017be44e3d4fa77ecebc6a9b9934749fcf136f267b29115d2cc"
|
||||
],
|
||||
"expected": "c899094520e0197c37b91dd50778e20a5b950decfb308d39f1db709447ae48f6101d9abe63a783fbb830eec1d359a5f61a2013728966d349213ee96382614aa4135058a967627183810c6622a2158cababe3b8ab99169c89e362108bf5955b4ffc47440f87e4bad0d36bc738e737e072e64d8842e7619f1be0af1141f05afe2d"
|
||||
},
|
||||
{
|
||||
"name": "14 with additional data",
|
||||
"entropy": "13c752b9e745ce77bbc7c0dbda982313d3fe66f903e83ebd8dbe4ff0c11380e9",
|
||||
"nonce": "f1a533095d6174164bd7c82532464ae7",
|
||||
"pers": null,
|
||||
"add": [
|
||||
"4f53db89b9ba7fc00767bc751fb8f3c103fe0f76acd6d5c7891ab15b2b7cf67c",
|
||||
"582c2a7d34679088cca6bd28723c99aac07db46c332dc0153d1673256903b446"
|
||||
],
|
||||
"expected": "6311f4c0c4cd1f86bd48349abb9eb930d4f63df5e5f7217d1d1b91a71d8a6938b0ad2b3e897bd7e3d8703db125fab30e03464fad41e5ddf5bf9aeeb5161b244468cfb26a9d956931a5412c97d64188b0da1bd907819c686f39af82e91cfeef0cbffb5d1e229e383bed26d06412988640706815a6e820796876f416653e464961"
|
||||
}
|
||||
]
|
||||
+1024
File diff suppressed because it is too large
Load Diff
+19
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2015-present Fabien Potencier
|
||||
|
||||
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.
|
||||
+1045
File diff suppressed because it is too large
Load Diff
+13
@@ -0,0 +1,13 @@
|
||||
Symfony Polyfill / Mbstring
|
||||
===========================
|
||||
|
||||
This component provides a partial, native PHP implementation for the
|
||||
[Mbstring](https://php.net/mbstring) extension.
|
||||
|
||||
More information can be found in the
|
||||
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
This library is released under the [MIT license](LICENSE).
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'İ' => 'i̇',
|
||||
'µ' => 'μ',
|
||||
'ſ' => 's',
|
||||
'ͅ' => 'ι',
|
||||
'ς' => 'σ',
|
||||
'ϐ' => 'β',
|
||||
'ϑ' => 'θ',
|
||||
'ϕ' => 'φ',
|
||||
'ϖ' => 'π',
|
||||
'ϰ' => 'κ',
|
||||
'ϱ' => 'ρ',
|
||||
'ϵ' => 'ε',
|
||||
'ẛ' => 'ṡ',
|
||||
'ι' => 'ι',
|
||||
'ß' => 'ss',
|
||||
'ʼn' => 'ʼn',
|
||||
'ǰ' => 'ǰ',
|
||||
'ΐ' => 'ΐ',
|
||||
'ΰ' => 'ΰ',
|
||||
'և' => 'եւ',
|
||||
'ẖ' => 'ẖ',
|
||||
'ẗ' => 'ẗ',
|
||||
'ẘ' => 'ẘ',
|
||||
'ẙ' => 'ẙ',
|
||||
'ẚ' => 'aʾ',
|
||||
'ẞ' => 'ss',
|
||||
'ὐ' => 'ὐ',
|
||||
'ὒ' => 'ὒ',
|
||||
'ὔ' => 'ὔ',
|
||||
'ὖ' => 'ὖ',
|
||||
'ᾀ' => 'ἀι',
|
||||
'ᾁ' => 'ἁι',
|
||||
'ᾂ' => 'ἂι',
|
||||
'ᾃ' => 'ἃι',
|
||||
'ᾄ' => 'ἄι',
|
||||
'ᾅ' => 'ἅι',
|
||||
'ᾆ' => 'ἆι',
|
||||
'ᾇ' => 'ἇι',
|
||||
'ᾈ' => 'ἀι',
|
||||
'ᾉ' => 'ἁι',
|
||||
'ᾊ' => 'ἂι',
|
||||
'ᾋ' => 'ἃι',
|
||||
'ᾌ' => 'ἄι',
|
||||
'ᾍ' => 'ἅι',
|
||||
'ᾎ' => 'ἆι',
|
||||
'ᾏ' => 'ἇι',
|
||||
'ᾐ' => 'ἠι',
|
||||
'ᾑ' => 'ἡι',
|
||||
'ᾒ' => 'ἢι',
|
||||
'ᾓ' => 'ἣι',
|
||||
'ᾔ' => 'ἤι',
|
||||
'ᾕ' => 'ἥι',
|
||||
'ᾖ' => 'ἦι',
|
||||
'ᾗ' => 'ἧι',
|
||||
'ᾘ' => 'ἠι',
|
||||
'ᾙ' => 'ἡι',
|
||||
'ᾚ' => 'ἢι',
|
||||
'ᾛ' => 'ἣι',
|
||||
'ᾜ' => 'ἤι',
|
||||
'ᾝ' => 'ἥι',
|
||||
'ᾞ' => 'ἦι',
|
||||
'ᾟ' => 'ἧι',
|
||||
'ᾠ' => 'ὠι',
|
||||
'ᾡ' => 'ὡι',
|
||||
'ᾢ' => 'ὢι',
|
||||
'ᾣ' => 'ὣι',
|
||||
'ᾤ' => 'ὤι',
|
||||
'ᾥ' => 'ὥι',
|
||||
'ᾦ' => 'ὦι',
|
||||
'ᾧ' => 'ὧι',
|
||||
'ᾨ' => 'ὠι',
|
||||
'ᾩ' => 'ὡι',
|
||||
'ᾪ' => 'ὢι',
|
||||
'ᾫ' => 'ὣι',
|
||||
'ᾬ' => 'ὤι',
|
||||
'ᾭ' => 'ὥι',
|
||||
'ᾮ' => 'ὦι',
|
||||
'ᾯ' => 'ὧι',
|
||||
'ᾲ' => 'ὰι',
|
||||
'ᾳ' => 'αι',
|
||||
'ᾴ' => 'άι',
|
||||
'ᾶ' => 'ᾶ',
|
||||
'ᾷ' => 'ᾶι',
|
||||
'ᾼ' => 'αι',
|
||||
'ῂ' => 'ὴι',
|
||||
'ῃ' => 'ηι',
|
||||
'ῄ' => 'ήι',
|
||||
'ῆ' => 'ῆ',
|
||||
'ῇ' => 'ῆι',
|
||||
'ῌ' => 'ηι',
|
||||
'ῒ' => 'ῒ',
|
||||
'ῖ' => 'ῖ',
|
||||
'ῗ' => 'ῗ',
|
||||
'ῢ' => 'ῢ',
|
||||
'ῤ' => 'ῤ',
|
||||
'ῦ' => 'ῦ',
|
||||
'ῧ' => 'ῧ',
|
||||
'ῲ' => 'ὼι',
|
||||
'ῳ' => 'ωι',
|
||||
'ῴ' => 'ώι',
|
||||
'ῶ' => 'ῶ',
|
||||
'ῷ' => 'ῶι',
|
||||
'ῼ' => 'ωι',
|
||||
'ff' => 'ff',
|
||||
'fi' => 'fi',
|
||||
'fl' => 'fl',
|
||||
'ffi' => 'ffi',
|
||||
'ffl' => 'ffl',
|
||||
'ſt' => 'st',
|
||||
'st' => 'st',
|
||||
'ﬓ' => 'մն',
|
||||
'ﬔ' => 'մե',
|
||||
'ﬕ' => 'մի',
|
||||
'ﬖ' => 'վն',
|
||||
'ﬗ' => 'մխ',
|
||||
];
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
+172
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Polyfill\Mbstring as p;
|
||||
|
||||
if (\PHP_VERSION_ID >= 80000) {
|
||||
return require __DIR__.'/bootstrap80.php';
|
||||
}
|
||||
|
||||
if (!function_exists('mb_convert_encoding')) {
|
||||
function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }
|
||||
}
|
||||
if (!function_exists('mb_decode_mimeheader')) {
|
||||
function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); }
|
||||
}
|
||||
if (!function_exists('mb_encode_mimeheader')) {
|
||||
function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); }
|
||||
}
|
||||
if (!function_exists('mb_decode_numericentity')) {
|
||||
function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_encode_numericentity')) {
|
||||
function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }
|
||||
}
|
||||
if (!function_exists('mb_convert_case')) {
|
||||
function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_internal_encoding')) {
|
||||
function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); }
|
||||
}
|
||||
if (!function_exists('mb_language')) {
|
||||
function mb_language($language = null) { return p\Mbstring::mb_language($language); }
|
||||
}
|
||||
if (!function_exists('mb_list_encodings')) {
|
||||
function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
|
||||
}
|
||||
if (!function_exists('mb_encoding_aliases')) {
|
||||
function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
|
||||
}
|
||||
if (!function_exists('mb_check_encoding')) {
|
||||
function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_detect_encoding')) {
|
||||
function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); }
|
||||
}
|
||||
if (!function_exists('mb_detect_order')) {
|
||||
function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); }
|
||||
}
|
||||
if (!function_exists('mb_parse_str')) {
|
||||
function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; }
|
||||
}
|
||||
if (!function_exists('mb_strlen')) {
|
||||
function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strpos')) {
|
||||
function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strtolower')) {
|
||||
function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strtoupper')) {
|
||||
function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_substitute_character')) {
|
||||
function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); }
|
||||
}
|
||||
if (!function_exists('mb_substr')) {
|
||||
function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_stripos')) {
|
||||
function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_stristr')) {
|
||||
function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strrchr')) {
|
||||
function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strrichr')) {
|
||||
function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strripos')) {
|
||||
function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strrpos')) {
|
||||
function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strstr')) {
|
||||
function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_get_info')) {
|
||||
function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
|
||||
}
|
||||
if (!function_exists('mb_http_output')) {
|
||||
function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strwidth')) {
|
||||
function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_substr_count')) {
|
||||
function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_output_handler')) {
|
||||
function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); }
|
||||
}
|
||||
if (!function_exists('mb_http_input')) {
|
||||
function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_convert_variables')) {
|
||||
function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_ord')) {
|
||||
function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_chr')) {
|
||||
function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_scrub')) {
|
||||
function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_str_split')) {
|
||||
function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_str_pad')) {
|
||||
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_ucfirst')) {
|
||||
function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_lcfirst')) {
|
||||
function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_trim')) {
|
||||
function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_ltrim')) {
|
||||
function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_rtrim')) {
|
||||
function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
|
||||
}
|
||||
|
||||
|
||||
if (extension_loaded('mbstring')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!defined('MB_CASE_UPPER')) {
|
||||
define('MB_CASE_UPPER', 0);
|
||||
}
|
||||
if (!defined('MB_CASE_LOWER')) {
|
||||
define('MB_CASE_LOWER', 1);
|
||||
}
|
||||
if (!defined('MB_CASE_TITLE')) {
|
||||
define('MB_CASE_TITLE', 2);
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Polyfill\Mbstring as p;
|
||||
|
||||
if (!function_exists('mb_convert_encoding')) {
|
||||
function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); }
|
||||
}
|
||||
if (!function_exists('mb_decode_mimeheader')) {
|
||||
function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); }
|
||||
}
|
||||
if (!function_exists('mb_encode_mimeheader')) {
|
||||
function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); }
|
||||
}
|
||||
if (!function_exists('mb_decode_numericentity')) {
|
||||
function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_encode_numericentity')) {
|
||||
function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); }
|
||||
}
|
||||
if (!function_exists('mb_convert_case')) {
|
||||
function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_internal_encoding')) {
|
||||
function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); }
|
||||
}
|
||||
if (!function_exists('mb_language')) {
|
||||
function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); }
|
||||
}
|
||||
if (!function_exists('mb_list_encodings')) {
|
||||
function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); }
|
||||
}
|
||||
if (!function_exists('mb_encoding_aliases')) {
|
||||
function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_check_encoding')) {
|
||||
function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_detect_encoding')) {
|
||||
function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); }
|
||||
}
|
||||
if (!function_exists('mb_detect_order')) {
|
||||
function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); }
|
||||
}
|
||||
if (!function_exists('mb_parse_str')) {
|
||||
function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; }
|
||||
}
|
||||
if (!function_exists('mb_strlen')) {
|
||||
function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strpos')) {
|
||||
function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strtolower')) {
|
||||
function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strtoupper')) {
|
||||
function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_substitute_character')) {
|
||||
function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); }
|
||||
}
|
||||
if (!function_exists('mb_substr')) {
|
||||
function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_stripos')) {
|
||||
function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_stristr')) {
|
||||
function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strrchr')) {
|
||||
function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strrichr')) {
|
||||
function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strripos')) {
|
||||
function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strrpos')) {
|
||||
function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strstr')) {
|
||||
function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_get_info')) {
|
||||
function mb_get_info(?string $type = 'all'): array|string|int|false|null { return p\Mbstring::mb_get_info((string) $type); }
|
||||
}
|
||||
if (!function_exists('mb_http_output')) {
|
||||
function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); }
|
||||
}
|
||||
if (!function_exists('mb_strwidth')) {
|
||||
function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_substr_count')) {
|
||||
function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_output_handler')) {
|
||||
function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); }
|
||||
}
|
||||
if (!function_exists('mb_http_input')) {
|
||||
function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_convert_variables')) {
|
||||
function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_ord')) {
|
||||
function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_chr')) {
|
||||
function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_scrub')) {
|
||||
function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); }
|
||||
}
|
||||
if (!function_exists('mb_str_split')) {
|
||||
function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_str_pad')) {
|
||||
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_ucfirst')) {
|
||||
function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_lcfirst')) {
|
||||
function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_trim')) {
|
||||
function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_ltrim')) {
|
||||
function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); }
|
||||
}
|
||||
|
||||
if (!function_exists('mb_rtrim')) {
|
||||
function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); }
|
||||
}
|
||||
|
||||
if (extension_loaded('mbstring')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!defined('MB_CASE_UPPER')) {
|
||||
define('MB_CASE_UPPER', 0);
|
||||
}
|
||||
if (!defined('MB_CASE_LOWER')) {
|
||||
define('MB_CASE_LOWER', 1);
|
||||
}
|
||||
if (!defined('MB_CASE_TITLE')) {
|
||||
define('MB_CASE_TITLE', 2);
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"type": "library",
|
||||
"description": "Symfony polyfill for the Mbstring extension",
|
||||
"keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"],
|
||||
"homepage": "https://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"ext-iconv": "*"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" },
|
||||
"files": [ "bootstrap.php" ]
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
# GlobalData
|
||||
进程间数据共享组件,用于分布式数据共享。服务端基于[Workerman](https://github.com/walkor/Workerman)。客户端可用于任何PHP项目。
|
||||
|
||||
# 服务端
|
||||
```php
|
||||
use Workerman\Worker;
|
||||
require_once __DIR__ . '/../../Workerman/Autoloader.php';
|
||||
require_once __DIR__ . '/../src/Server.php';
|
||||
|
||||
$worker = new GlobalData\Server('127.0.0.1', 2207);
|
||||
|
||||
Worker::runAll();
|
||||
```
|
||||
|
||||
# 客户端
|
||||
```php
|
||||
require_once __DIR__ . '/../src/Client.php';
|
||||
|
||||
$global = new GlobalData\Client('127.0.0.1:2207');
|
||||
|
||||
var_export(isset($global->abc));
|
||||
$global->abc = array(1,2,3);
|
||||
var_export($global->abc);
|
||||
unset($global->abc);
|
||||
var_export($global->abc);
|
||||
$global->abc = array(1,2,3);
|
||||
var_export($global->abc);
|
||||
var_export($global->cas('abc', array(1,2,3), array(5,6,7)));
|
||||
var_export($global->abc);
|
||||
```
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name" : "workerman/globaldata",
|
||||
"type" : "library",
|
||||
"homepage": "http://www.workerman.net",
|
||||
"license" : "MIT",
|
||||
"require": {
|
||||
"workerman/workerman" : ">=3.3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {"GlobalData\\": "./src"}
|
||||
}
|
||||
}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
namespace GlobalData;
|
||||
/**
|
||||
* Global data client.
|
||||
* @version 1.0.3
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
/**
|
||||
* Timeout.
|
||||
* @var int
|
||||
*/
|
||||
public $timeout = 5;
|
||||
|
||||
/**
|
||||
* Heartbeat interval.
|
||||
* @var int
|
||||
*/
|
||||
public $pingInterval = 25;
|
||||
|
||||
/**
|
||||
* Global data server address.
|
||||
* @var array
|
||||
*/
|
||||
protected $_globalServers = array();
|
||||
|
||||
/**
|
||||
* Connection to global server.
|
||||
* @var resource
|
||||
*/
|
||||
protected $_globalConnections = null;
|
||||
|
||||
/**
|
||||
* Cache.
|
||||
* @var array
|
||||
*/
|
||||
protected $_cache = array();
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
* @param array | string $servers
|
||||
*/
|
||||
public function __construct($servers)
|
||||
{
|
||||
if(empty($servers))
|
||||
{
|
||||
throw new \Exception('servers empty');
|
||||
}
|
||||
$this->_globalServers = array_values((array)$servers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to global server.
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getConnection($key)
|
||||
{
|
||||
$offset = crc32($key)%count($this->_globalServers);
|
||||
if($offset < 0)
|
||||
{
|
||||
$offset = -$offset;
|
||||
}
|
||||
|
||||
if(!isset($this->_globalConnections[$offset]) || !is_resource($this->_globalConnections[$offset]) || feof($this->_globalConnections[$offset]))
|
||||
{
|
||||
$address = $this->_globalServers[$offset];
|
||||
if(strpos($address,'unix://')!==0){
|
||||
$address = "tcp://{$address}";
|
||||
}
|
||||
|
||||
$connection = stream_socket_client($address, $code, $msg, $this->timeout);
|
||||
if(!$connection)
|
||||
{
|
||||
throw new \Exception($msg);
|
||||
}
|
||||
stream_set_timeout($connection, $this->timeout);
|
||||
if(class_exists('\Workerman\Timer') && php_sapi_name() === 'cli')
|
||||
{
|
||||
$timer_id = \Workerman\Timer::add($this->pingInterval, function($connection)use(&$timer_id)
|
||||
{
|
||||
$buffer = pack('N', 8)."ping";
|
||||
if(strlen($buffer) !== @fwrite($connection, $buffer))
|
||||
{
|
||||
@fclose($connection);
|
||||
\Workerman\Timer::del($timer_id);
|
||||
}
|
||||
}, array($connection));
|
||||
}
|
||||
$this->_globalConnections[$offset] = $connection;
|
||||
}
|
||||
return $this->_globalConnections[$offset];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Magic methods __set.
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __set($key, $value)
|
||||
{
|
||||
$connection = $this->getConnection($key);
|
||||
$this->writeToRemote(array(
|
||||
'cmd' => 'set',
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
), $connection);
|
||||
$this->readFromRemote($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic methods __isset.
|
||||
* @param string $key
|
||||
*/
|
||||
public function __isset($key)
|
||||
{
|
||||
return null !== $this->__get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic methods __unset.
|
||||
* @param string $key
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __unset($key)
|
||||
{
|
||||
$connection = $this->getConnection($key);
|
||||
$this->writeToRemote(array(
|
||||
'cmd' => 'delete',
|
||||
'key' => $key
|
||||
), $connection);
|
||||
$this->readFromRemote($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic methods __get.
|
||||
* @param string $key
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
$connection = $this->getConnection($key);
|
||||
$this->writeToRemote(array(
|
||||
'cmd' => 'get',
|
||||
'key' => $key,
|
||||
), $connection);
|
||||
return $this->readFromRemote($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cas.
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function cas($key, $old_value, $new_value)
|
||||
{
|
||||
$connection = $this->getConnection($key);
|
||||
$this->writeToRemote(array(
|
||||
'cmd' => 'cas',
|
||||
'md5' => md5(serialize($old_value)),
|
||||
'key' => $key,
|
||||
'value' => $new_value,
|
||||
),$connection);
|
||||
return $this->readFromRemote($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add.
|
||||
* @param string $key
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function add($key, $value)
|
||||
{
|
||||
$connection = $this->getConnection($key);
|
||||
$this->writeToRemote(array(
|
||||
'cmd' => 'add',
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
), $connection);
|
||||
return $this->readFromRemote($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment.
|
||||
* @param string $key
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function increment($key, $step = 1)
|
||||
{
|
||||
$connection = $this->getConnection($key);
|
||||
$this->writeToRemote(array(
|
||||
'cmd' => 'increment',
|
||||
'key' => $key,
|
||||
'step' => $step,
|
||||
), $connection);
|
||||
return $this->readFromRemote($connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to global server.
|
||||
* @param string $buffer
|
||||
*/
|
||||
protected function writeToRemote($data, $connection)
|
||||
{
|
||||
$buffer = serialize($data);
|
||||
$buffer = pack('N',4 + strlen($buffer)) . $buffer;
|
||||
$len = fwrite($connection, $buffer);
|
||||
if($len !== strlen($buffer))
|
||||
{
|
||||
throw new \Exception('writeToRemote fail');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from global server.
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function readFromRemote($connection)
|
||||
{
|
||||
$all_buffer = '';
|
||||
$total_len = 4;
|
||||
$head_read = false;
|
||||
while(1)
|
||||
{
|
||||
$buffer = fread($connection, 8192);
|
||||
if($buffer === '' || $buffer === false)
|
||||
{
|
||||
throw new \Exception('readFromRemote fail');
|
||||
}
|
||||
$all_buffer .= $buffer;
|
||||
$recv_len = strlen($all_buffer);
|
||||
if($recv_len >= $total_len)
|
||||
{
|
||||
if($head_read)
|
||||
{
|
||||
break;
|
||||
}
|
||||
$unpack_data = unpack('Ntotal_length', $all_buffer);
|
||||
$total_len = $unpack_data['total_length'];
|
||||
if($recv_len >= $total_len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
$head_read = true;
|
||||
}
|
||||
}
|
||||
return unserialize(substr($all_buffer, 4));
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
namespace GlobalData;
|
||||
use Workerman\Protocols\Frame;
|
||||
use Workerman\Worker;
|
||||
|
||||
/**
|
||||
* Global data server.
|
||||
*/
|
||||
class Server
|
||||
{
|
||||
/**
|
||||
* Worker instance.
|
||||
* @var worker
|
||||
*/
|
||||
protected $_worker = null;
|
||||
|
||||
/**
|
||||
* All data.
|
||||
* @var array
|
||||
*/
|
||||
protected $_dataArray = array();
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
* @param string $ip
|
||||
* @param int $port
|
||||
*/
|
||||
public function __construct($ip = '0.0.0.0', $port = 2207)
|
||||
{
|
||||
if (strpos($ip, 'unix://') === 0) {
|
||||
$worker = new Worker($ip);
|
||||
$worker->protocol = Frame::class;
|
||||
} else {
|
||||
$worker = new Worker("frame://$ip:$port");
|
||||
}
|
||||
|
||||
$worker->count = 1;
|
||||
$worker->name = 'globalDataServer';
|
||||
$worker->onMessage = array($this, 'onMessage');
|
||||
$worker->reloadable = false;
|
||||
$this->_worker = $worker;
|
||||
}
|
||||
|
||||
/**
|
||||
* onMessage.
|
||||
* @param TcpConnection $connection
|
||||
* @param string $buffer
|
||||
*/
|
||||
public function onMessage($connection, $buffer)
|
||||
{
|
||||
if($buffer === 'ping')
|
||||
{
|
||||
return;
|
||||
}
|
||||
$data = unserialize($buffer);
|
||||
if(!$buffer || !isset($data['cmd']) || !isset($data['key']))
|
||||
{
|
||||
return $connection->close(serialize('bad request'));
|
||||
}
|
||||
$cmd = $data['cmd'];
|
||||
$key = $data['key'];
|
||||
switch($cmd)
|
||||
{
|
||||
case 'get':
|
||||
if(!isset($this->_dataArray[$key]))
|
||||
{
|
||||
return $connection->send('N;');
|
||||
}
|
||||
return $connection->send(serialize($this->_dataArray[$key]));
|
||||
break;
|
||||
case 'set':
|
||||
$this->_dataArray[$key] = $data['value'];
|
||||
$connection->send('b:1;');
|
||||
break;
|
||||
case 'add':
|
||||
if(isset($this->_dataArray[$key]))
|
||||
{
|
||||
return $connection->send('b:0;');
|
||||
}
|
||||
$this->_dataArray[$key] = $data['value'];
|
||||
return $connection->send('b:1;');
|
||||
break;
|
||||
case 'increment':
|
||||
if(!isset($this->_dataArray[$key]))
|
||||
{
|
||||
return $connection->send('b:0;');
|
||||
}
|
||||
if(!is_numeric($this->_dataArray[$key]))
|
||||
{
|
||||
$this->_dataArray[$key] = 0;
|
||||
}
|
||||
$this->_dataArray[$key] = $this->_dataArray[$key]+$data['step'];
|
||||
return $connection->send(serialize($this->_dataArray[$key]));
|
||||
break;
|
||||
case 'cas':
|
||||
$old_value = !isset($this->_dataArray[$key]) ? null : $this->_dataArray[$key];
|
||||
if(md5(serialize($old_value)) === $data['md5'])
|
||||
{
|
||||
$this->_dataArray[$key] = $data['value'];
|
||||
return $connection->send('b:1;');
|
||||
}
|
||||
$connection->send('b:0;');
|
||||
break;
|
||||
case 'delete':
|
||||
unset($this->_dataArray[$key]);
|
||||
$connection->send('b:1;');
|
||||
break;
|
||||
default:
|
||||
$connection->close(serialize('bad cmd '. $cmd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
use GlobalData\Client;
|
||||
require_once __DIR__ . '/../src/Client.php';
|
||||
|
||||
$global = new Client('127.0.0.1:2207');
|
||||
|
||||
$i = $j = 10000;
|
||||
$t = microtime(true);
|
||||
while($i--)
|
||||
{
|
||||
$global->a = array(1,3);
|
||||
}
|
||||
|
||||
echo ceil($j/(microtime(true)-$t))."qps\n";
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
use Workerman\Worker;
|
||||
use GlobalData\Server;
|
||||
require_once __DIR__ . '/../../Workerman/Autoloader.php';
|
||||
require_once __DIR__ . '/../src/Server.php';
|
||||
$worker = new Server();
|
||||
Worker::runAll();
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
use GlobalData\Client;
|
||||
require_once __DIR__ . '/../src/Client.php';
|
||||
|
||||
$global = new Client('127.0.0.1:2207');
|
||||
|
||||
echo "\n\nisset(\$global->abc)=";
|
||||
var_export(isset($global->abc));
|
||||
|
||||
echo "\n\n\$global->add('abc', 10)=";
|
||||
var_export($global->add('abc', 10));
|
||||
echo "\nnow \$global->abc=";
|
||||
var_export($global->abc);
|
||||
|
||||
echo "\n\n\$global->increment('abc', 2)=";
|
||||
var_export($global->increment('abc', 2));
|
||||
echo "\nnow \$global->abc=";
|
||||
var_export($global->abc);
|
||||
|
||||
echo ";\n\nset \$global->abc=";
|
||||
$global->abc = array(1,2,3);
|
||||
var_export($global->abc);
|
||||
|
||||
echo ";\n\nunset(\$global->abc)\n";
|
||||
unset($global->abc);
|
||||
echo "\nnow \$global->abc=";
|
||||
var_export($global->abc);
|
||||
|
||||
echo "\n\nisset(\$global->abc)=";
|
||||
var_export(isset($global->abc));
|
||||
|
||||
echo ";\n\nset \$global->abc=";
|
||||
$global->abc = array(1,2,3);
|
||||
var_export($global->abc);
|
||||
|
||||
echo ";\n\n\$global->cas('abc', array(1,2,3), array(5,6,7))=";
|
||||
var_export($global->cas('abc', array(1,2,3), array(5,6,7)));
|
||||
|
||||
echo ";\n\nnow \$global->abc=";
|
||||
var_export($global->abc);
|
||||
Vendored
+789
@@ -0,0 +1,789 @@
|
||||
2025-10-09 11:16:29 pid:1316085 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:16:30 pid:1316087 Error: Class "Elliptic\EC" not found in /www/goldrat/go.php:54
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(561): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/go.php(134): Workerman\Worker::runAll()
|
||||
#6 {main}
|
||||
2025-10-09 11:16:30 pid:1316085 worker[none:1316087] exit with status 64000
|
||||
2025-10-09 11:16:31 pid:1316098 Error: Class "Elliptic\EC" not found in /www/goldrat/go.php:54
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(134): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 11:16:31 pid:1316085 worker[none:1316098] exit with status 64000
|
||||
2025-10-09 11:16:32 pid:1316105 Error: Class "Elliptic\EC" not found in /www/goldrat/go.php:54
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(134): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 11:16:32 pid:1316085 worker[none:1316105] exit with status 64000
|
||||
2025-10-09 11:16:32 pid:1316085 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:16:32 pid:1316116 Error: Class "Elliptic\EC" not found in /www/goldrat/go.php:54
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(134): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 11:16:32 pid:1316085 worker[none:1316116] exit with status 64000
|
||||
2025-10-09 11:16:32 pid:1316085 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:16:53 pid:1316249 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:17:04 pid:1316249 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:17:06 pid:1316249 worker[none:1316251] exit with status 9
|
||||
2025-10-09 11:17:06 pid:1316249 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:22:16 pid:1316422 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:22:17 pid:1316422 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:22:18 pid:1316422 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:22:19 pid:1316422 worker[none:1316424] exit with status 9
|
||||
2025-10-09 11:22:19 pid:1316422 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:22:36 pid:1316478 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:22:43 pid:1316478 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:22:45 pid:1316478 worker[none:1316480] exit with status 9
|
||||
2025-10-09 11:22:45 pid:1316478 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:22:55 pid:1316550 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:23:34 pid:1316550 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:23:36 pid:1316550 worker[none:1316554] exit with status 9
|
||||
2025-10-09 11:23:36 pid:1316550 worker[none:1316555] exit with status 9
|
||||
2025-10-09 11:23:36 pid:1316550 worker[none:1316553] exit with status 9
|
||||
2025-10-09 11:23:36 pid:1316550 worker[none:1316552] exit with status 9
|
||||
2025-10-09 11:23:36 pid:1316550 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:23:49 pid:1316733 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:23:52 pid:1316733 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:23:54 pid:1316733 worker[none:1316735] exit with status 9
|
||||
2025-10-09 11:23:54 pid:1316733 worker[none:1316736] exit with status 9
|
||||
2025-10-09 11:23:54 pid:1316733 worker[none:1316738] exit with status 9
|
||||
2025-10-09 11:23:54 pid:1316733 worker[none:1316737] exit with status 9
|
||||
2025-10-09 11:23:54 pid:1316733 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:24:03 pid:1316810 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:24:03 pid:1316810 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:24:05 pid:1316810 worker[none:1316812] exit with status 9
|
||||
2025-10-09 11:24:05 pid:1316810 worker[none:1316815] exit with status 9
|
||||
2025-10-09 11:24:05 pid:1316810 worker[none:1316813] exit with status 9
|
||||
2025-10-09 11:24:05 pid:1316810 worker[none:1316814] exit with status 9
|
||||
2025-10-09 11:24:05 pid:1316810 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:27:29 pid:1316963 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:27:30 pid:1316963 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:31 pid:1316963 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:31 pid:1316963 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:32 pid:1316963 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:32 pid:1316963 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:32 pid:1316963 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:32 pid:1316963 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:32 pid:1316963 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:32 pid:1316963 worker[none:1316964] exit with status 9
|
||||
2025-10-09 11:27:32 pid:1316963 worker[none:1316969] exit with status 9
|
||||
2025-10-09 11:27:32 pid:1316963 worker[none:1316968] exit with status 9
|
||||
2025-10-09 11:27:32 pid:1316963 worker[none:1316967] exit with status 9
|
||||
2025-10-09 11:27:32 pid:1316963 worker[none:1316965] exit with status 9
|
||||
2025-10-09 11:27:32 pid:1316963 worker[none:1316966] exit with status 9
|
||||
2025-10-09 11:27:32 pid:1316963 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:27:51 pid:1317014 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:27:51 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:52 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:52 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:52 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:52 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:53 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:53 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:53 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:53 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:53 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:53 pid:1317014 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:27:53 pid:1317014 worker[none:1317017] exit with status 9
|
||||
2025-10-09 11:27:53 pid:1317014 worker[none:1317020] exit with status 9
|
||||
2025-10-09 11:27:53 pid:1317014 worker[none:1317016] exit with status 9
|
||||
2025-10-09 11:27:53 pid:1317014 worker[none:1317018] exit with status 9
|
||||
2025-10-09 11:27:53 pid:1317014 worker[none:1317019] exit with status 9
|
||||
2025-10-09 11:27:53 pid:1317014 worker[none:1317015] exit with status 9
|
||||
2025-10-09 11:27:54 pid:1317014 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:28:20 pid:1317064 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:28:21 pid:1317064 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:28:23 pid:1317064 worker[none:1317068] exit with status 9
|
||||
2025-10-09 11:28:23 pid:1317064 worker[none:1317069] exit with status 9
|
||||
2025-10-09 11:28:23 pid:1317064 worker[none:1317070] exit with status 9
|
||||
2025-10-09 11:28:23 pid:1317064 worker[none:1317065] exit with status 9
|
||||
2025-10-09 11:28:23 pid:1317064 worker[none:1317067] exit with status 9
|
||||
2025-10-09 11:28:23 pid:1317064 worker[none:1317066] exit with status 9
|
||||
2025-10-09 11:28:23 pid:1317064 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:29:40 pid:1317153 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:29:41 pid:1317153 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:43 pid:1317153 worker[none:1317157] exit with status 9
|
||||
2025-10-09 11:29:43 pid:1317153 worker[none:1317158] exit with status 9
|
||||
2025-10-09 11:29:43 pid:1317153 worker[none:1317156] exit with status 9
|
||||
2025-10-09 11:29:43 pid:1317153 worker[none:1317154] exit with status 9
|
||||
2025-10-09 11:29:43 pid:1317153 worker[none:1317155] exit with status 9
|
||||
2025-10-09 11:29:43 pid:1317153 worker[none:1317159] exit with status 9
|
||||
2025-10-09 11:29:43 pid:1317153 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:29:53 pid:1317208 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:29:54 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:55 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:55 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:55 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:55 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:55 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:55 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:56 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:56 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:56 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:56 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:56 pid:1317208 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:29:56 pid:1317208 worker[none:1317211] exit with status 9
|
||||
2025-10-09 11:29:56 pid:1317208 worker[none:1317213] exit with status 9
|
||||
2025-10-09 11:29:56 pid:1317208 worker[none:1317212] exit with status 9
|
||||
2025-10-09 11:29:56 pid:1317208 worker[none:1317209] exit with status 9
|
||||
2025-10-09 11:29:56 pid:1317208 worker[none:1317214] exit with status 9
|
||||
2025-10-09 11:29:56 pid:1317208 worker[none:1317210] exit with status 9
|
||||
2025-10-09 11:29:56 pid:1317208 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:30:21 pid:1317274 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:30:23 pid:1317274 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:30:25 pid:1317274 worker[none:1317279] exit with status 9
|
||||
2025-10-09 11:30:25 pid:1317274 worker[none:1317277] exit with status 9
|
||||
2025-10-09 11:30:25 pid:1317274 worker[none:1317278] exit with status 9
|
||||
2025-10-09 11:30:25 pid:1317274 worker[none:1317280] exit with status 9
|
||||
2025-10-09 11:30:25 pid:1317274 worker[none:1317275] exit with status 9
|
||||
2025-10-09 11:30:25 pid:1317274 worker[none:1317276] exit with status 9
|
||||
2025-10-09 11:30:25 pid:1317274 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:30:48 pid:1317360 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:30:49 pid:1317360 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:30:51 pid:1317360 worker[none:1317361] exit with status 9
|
||||
2025-10-09 11:30:51 pid:1317360 worker[none:1317363] exit with status 9
|
||||
2025-10-09 11:30:51 pid:1317360 worker[none:1317364] exit with status 9
|
||||
2025-10-09 11:30:51 pid:1317360 worker[none:1317365] exit with status 9
|
||||
2025-10-09 11:30:51 pid:1317360 worker[none:1317362] exit with status 9
|
||||
2025-10-09 11:30:51 pid:1317360 worker[none:1317366] exit with status 9
|
||||
2025-10-09 11:30:51 pid:1317360 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:31:45 pid:1317424 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:31:53 pid:1317424 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:31:55 pid:1317424 worker[none:1317428] exit with status 9
|
||||
2025-10-09 11:31:55 pid:1317424 worker[none:1317425] exit with status 9
|
||||
2025-10-09 11:31:55 pid:1317424 worker[none:1317426] exit with status 9
|
||||
2025-10-09 11:31:55 pid:1317424 worker[none:1317430] exit with status 9
|
||||
2025-10-09 11:31:55 pid:1317424 worker[none:1317429] exit with status 9
|
||||
2025-10-09 11:31:55 pid:1317424 worker[none:1317427] exit with status 9
|
||||
2025-10-09 11:31:55 pid:1317424 Workerman[go.php] has been stopped
|
||||
2025-10-09 11:32:09 pid:1317541 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 11:33:25 pid:1317541 Workerman[go.php] stopping ...
|
||||
2025-10-09 11:33:27 pid:1317541 worker[none:1317545] exit with status 9
|
||||
2025-10-09 11:33:27 pid:1317541 worker[none:1317546] exit with status 9
|
||||
2025-10-09 11:33:27 pid:1317541 worker[none:1317544] exit with status 9
|
||||
2025-10-09 11:33:27 pid:1317541 worker[none:1317542] exit with status 9
|
||||
2025-10-09 11:33:27 pid:1317541 worker[none:1317543] exit with status 9
|
||||
2025-10-09 11:33:27 pid:1317541 worker[none:1317547] exit with status 9
|
||||
2025-10-09 11:33:27 pid:1317541 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:11:41 pid:1320946 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:11:49 pid:1320946 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:11:51 pid:1320946 worker[none:1320951] exit with status 9
|
||||
2025-10-09 15:11:51 pid:1320946 worker[none:1320950] exit with status 9
|
||||
2025-10-09 15:11:51 pid:1320946 worker[none:1320949] exit with status 9
|
||||
2025-10-09 15:11:51 pid:1320946 worker[none:1320952] exit with status 9
|
||||
2025-10-09 15:11:51 pid:1320946 worker[none:1320947] exit with status 9
|
||||
2025-10-09 15:11:51 pid:1320946 worker[none:1320948] exit with status 9
|
||||
2025-10-09 15:11:51 pid:1320946 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:12:05 pid:1321071 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:12:39 pid:1321071 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:12:41 pid:1321071 worker[none:1321077] exit with status 9
|
||||
2025-10-09 15:12:41 pid:1321071 worker[none:1321075] exit with status 9
|
||||
2025-10-09 15:12:41 pid:1321071 worker[none:1321073] exit with status 9
|
||||
2025-10-09 15:12:41 pid:1321071 worker[none:1321076] exit with status 9
|
||||
2025-10-09 15:12:41 pid:1321071 worker[none:1321074] exit with status 9
|
||||
2025-10-09 15:12:41 pid:1321071 worker[none:1321072] exit with status 9
|
||||
2025-10-09 15:12:41 pid:1321071 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:13:28 pid:1321172 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:14:10 pid:1321172 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:14:12 pid:1321172 worker[none:1321176] exit with status 9
|
||||
2025-10-09 15:14:12 pid:1321172 worker[none:1321174] exit with status 9
|
||||
2025-10-09 15:14:12 pid:1321172 worker[none:1321177] exit with status 9
|
||||
2025-10-09 15:14:12 pid:1321172 worker[none:1321178] exit with status 9
|
||||
2025-10-09 15:14:12 pid:1321172 worker[none:1321173] exit with status 9
|
||||
2025-10-09 15:14:12 pid:1321172 worker[none:1321175] exit with status 9
|
||||
2025-10-09 15:14:12 pid:1321172 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:15:14 pid:1321458 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:15:26 pid:1321458 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:15:28 pid:1321458 worker[none:1321464] exit with status 9
|
||||
2025-10-09 15:15:28 pid:1321458 worker[none:1321463] exit with status 9
|
||||
2025-10-09 15:15:28 pid:1321458 worker[none:1321461] exit with status 9
|
||||
2025-10-09 15:15:28 pid:1321458 worker[none:1321462] exit with status 9
|
||||
2025-10-09 15:15:28 pid:1321458 worker[none:1321459] exit with status 9
|
||||
2025-10-09 15:15:28 pid:1321458 worker[none:1321460] exit with status 9
|
||||
2025-10-09 15:15:28 pid:1321458 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:16:56 pid:1321619 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:17:01 pid:1321619 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:17:03 pid:1321619 worker[none:1321623] exit with status 9
|
||||
2025-10-09 15:17:03 pid:1321619 worker[none:1321622] exit with status 9
|
||||
2025-10-09 15:17:03 pid:1321619 worker[none:1321624] exit with status 9
|
||||
2025-10-09 15:17:03 pid:1321619 worker[none:1321625] exit with status 9
|
||||
2025-10-09 15:17:03 pid:1321619 worker[none:1321621] exit with status 9
|
||||
2025-10-09 15:17:03 pid:1321619 worker[none:1321620] exit with status 9
|
||||
2025-10-09 15:17:03 pid:1321619 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:20:11 pid:1321781 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:20:13 pid:1321781 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:20:14 pid:1321781 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:20:14 pid:1321781 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:20:14 pid:1321781 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:20:14 pid:1321781 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:20:15 pid:1321781 worker[none:1321787] exit with status 9
|
||||
2025-10-09 15:20:15 pid:1321781 worker[none:1321784] exit with status 9
|
||||
2025-10-09 15:20:15 pid:1321781 worker[none:1321786] exit with status 9
|
||||
2025-10-09 15:20:15 pid:1321781 worker[none:1321782] exit with status 9
|
||||
2025-10-09 15:20:15 pid:1321781 worker[none:1321783] exit with status 9
|
||||
2025-10-09 15:20:15 pid:1321781 worker[none:1321785] exit with status 9
|
||||
2025-10-09 15:20:15 pid:1321781 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:27:17 pid:1322084 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:27:18 pid:1322084 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:27:20 pid:1322084 worker[none:1322085] exit with status 9
|
||||
2025-10-09 15:27:20 pid:1322084 worker[none:1322086] exit with status 9
|
||||
2025-10-09 15:27:20 pid:1322084 worker[none:1322087] exit with status 9
|
||||
2025-10-09 15:27:20 pid:1322084 worker[none:1322088] exit with status 9
|
||||
2025-10-09 15:27:20 pid:1322084 worker[none:1322090] exit with status 9
|
||||
2025-10-09 15:27:20 pid:1322084 worker[none:1322089] exit with status 9
|
||||
2025-10-09 15:27:20 pid:1322084 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:29:02 pid:1322213 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:29:03 pid:1322213 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:29:05 pid:1322213 worker[none:1322215] exit with status 9
|
||||
2025-10-09 15:29:05 pid:1322213 worker[none:1322217] exit with status 9
|
||||
2025-10-09 15:29:05 pid:1322213 worker[none:1322219] exit with status 9
|
||||
2025-10-09 15:29:05 pid:1322213 worker[none:1322214] exit with status 9
|
||||
2025-10-09 15:29:05 pid:1322213 worker[none:1322216] exit with status 9
|
||||
2025-10-09 15:29:05 pid:1322213 worker[none:1322218] exit with status 9
|
||||
2025-10-09 15:29:05 pid:1322213 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:39:37 pid:1322485 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:39:38 pid:1322487 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(561): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#6 {main}
|
||||
2025-10-09 15:39:38 pid:1322489 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(561): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#6 {main}
|
||||
2025-10-09 15:39:38 pid:1322490 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(561): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#6 {main}
|
||||
2025-10-09 15:39:38 pid:1322488 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(561): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#6 {main}
|
||||
2025-10-09 15:39:38 pid:1322491 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(561): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#6 {main}
|
||||
2025-10-09 15:39:38 pid:1322486 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(561): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#6 {main}
|
||||
2025-10-09 15:39:38 pid:1322493 Error: Class "Timer" not found in /www/goldrat/go.php:160
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(561): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#6 {main}
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322490] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322487] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322488] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322486] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322491] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322489] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322493] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322515 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 15:39:38 pid:1322514 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 15:39:38 pid:1322513 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 15:39:38 pid:1322511 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 15:39:38 pid:1322512 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 15:39:38 pid:1322485 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:39:38 pid:1322516 Error: Class "Timer" not found in /www/goldrat/go.php:59
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 15:39:38 pid:1322517 Error: Class "Timer" not found in /www/goldrat/go.php:160
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Worker.php(2582): {closure}()
|
||||
#1 /www/goldrat/vendor/workerman/workerman/Worker.php(1717): Workerman\Worker->run()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1869): Workerman\Worker::forkWorkers()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1805): Workerman\Worker::monitorWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(563): Workerman\Worker::monitorWorkers()
|
||||
#7 /www/goldrat/go.php(169): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322512] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322511] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322515] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322513] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322516] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322514] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 worker[none:1322517] exit with status 64000
|
||||
2025-10-09 15:39:38 pid:1322485 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:39:59 pid:1322568 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:40:11 pid:1322568 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:40:13 pid:1322568 worker[none:1322573] exit with status 9
|
||||
2025-10-09 15:40:13 pid:1322568 worker[none:1322569] exit with status 9
|
||||
2025-10-09 15:40:13 pid:1322568 worker[none:1322571] exit with status 9
|
||||
2025-10-09 15:40:13 pid:1322568 worker[none:1322570] exit with status 9
|
||||
2025-10-09 15:40:13 pid:1322568 worker[none:1322574] exit with status 9
|
||||
2025-10-09 15:40:13 pid:1322568 worker[none:1322572] exit with status 9
|
||||
2025-10-09 15:40:13 pid:1322568 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:40:29 pid:1322749 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:40:57 pid:1322749 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:40:59 pid:1322749 worker[none:1322751] exit with status 9
|
||||
2025-10-09 15:40:59 pid:1322749 worker[none:1322753] exit with status 9
|
||||
2025-10-09 15:40:59 pid:1322749 worker[none:1322754] exit with status 9
|
||||
2025-10-09 15:40:59 pid:1322749 worker[none:1322750] exit with status 9
|
||||
2025-10-09 15:40:59 pid:1322749 worker[none:1322752] exit with status 9
|
||||
2025-10-09 15:40:59 pid:1322749 worker[none:1322755] exit with status 9
|
||||
2025-10-09 15:40:59 pid:1322749 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:42:29 pid:1323027 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:42:34 pid:1323027 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:42:36 pid:1323027 worker[none:1323033] exit with status 9
|
||||
2025-10-09 15:42:36 pid:1323027 worker[none:1323031] exit with status 9
|
||||
2025-10-09 15:42:36 pid:1323027 worker[none:1323030] exit with status 9
|
||||
2025-10-09 15:42:36 pid:1323027 worker[none:1323028] exit with status 9
|
||||
2025-10-09 15:42:36 pid:1323027 worker[none:1323032] exit with status 9
|
||||
2025-10-09 15:42:36 pid:1323027 worker[none:1323029] exit with status 9
|
||||
2025-10-09 15:42:36 pid:1323027 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:43:09 pid:1323129 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:43:11 pid:1323129 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:43:13 pid:1323129 worker[none:1323135] exit with status 9
|
||||
2025-10-09 15:43:13 pid:1323129 worker[none:1323134] exit with status 9
|
||||
2025-10-09 15:43:13 pid:1323129 worker[none:1323130] exit with status 9
|
||||
2025-10-09 15:43:13 pid:1323129 worker[none:1323133] exit with status 9
|
||||
2025-10-09 15:43:13 pid:1323129 worker[none:1323132] exit with status 9
|
||||
2025-10-09 15:43:13 pid:1323129 worker[none:1323131] exit with status 9
|
||||
2025-10-09 15:43:13 pid:1323129 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:43:40 pid:1323236 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:43:51 pid:1323236 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:43:53 pid:1323236 worker[none:1323239] exit with status 9
|
||||
2025-10-09 15:43:53 pid:1323236 worker[none:1323241] exit with status 9
|
||||
2025-10-09 15:43:53 pid:1323236 worker[none:1323238] exit with status 9
|
||||
2025-10-09 15:43:53 pid:1323236 worker[none:1323242] exit with status 9
|
||||
2025-10-09 15:43:53 pid:1323236 worker[none:1323237] exit with status 9
|
||||
2025-10-09 15:43:53 pid:1323236 worker[none:1323240] exit with status 9
|
||||
2025-10-09 15:43:53 pid:1323236 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:44:02 pid:1323407 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:44:05 pid:1323407 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:44:07 pid:1323407 worker[none:1323411] exit with status 9
|
||||
2025-10-09 15:44:07 pid:1323407 worker[none:1323410] exit with status 9
|
||||
2025-10-09 15:44:07 pid:1323407 worker[none:1323413] exit with status 9
|
||||
2025-10-09 15:44:07 pid:1323407 worker[none:1323409] exit with status 9
|
||||
2025-10-09 15:44:07 pid:1323407 worker[none:1323408] exit with status 9
|
||||
2025-10-09 15:44:07 pid:1323407 worker[none:1323412] exit with status 9
|
||||
2025-10-09 15:44:07 pid:1323407 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:44:16 pid:1323506 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:44:23 pid:1323506 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:44:25 pid:1323506 worker[none:1323512] exit with status 9
|
||||
2025-10-09 15:44:25 pid:1323506 worker[none:1323507] exit with status 9
|
||||
2025-10-09 15:44:25 pid:1323506 worker[none:1323508] exit with status 9
|
||||
2025-10-09 15:44:25 pid:1323506 worker[none:1323510] exit with status 9
|
||||
2025-10-09 15:44:25 pid:1323506 worker[none:1323509] exit with status 9
|
||||
2025-10-09 15:44:25 pid:1323506 worker[none:1323511] exit with status 9
|
||||
2025-10-09 15:44:25 pid:1323506 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:45:21 pid:1323643 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:45:29 pid:1323643 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:45:31 pid:1323643 worker[none:1323646] exit with status 9
|
||||
2025-10-09 15:45:31 pid:1323643 worker[none:1323648] exit with status 9
|
||||
2025-10-09 15:45:31 pid:1323643 worker[none:1323649] exit with status 9
|
||||
2025-10-09 15:45:31 pid:1323643 worker[none:1323647] exit with status 9
|
||||
2025-10-09 15:45:31 pid:1323643 worker[none:1323644] exit with status 9
|
||||
2025-10-09 15:45:31 pid:1323643 worker[none:1323645] exit with status 9
|
||||
2025-10-09 15:45:31 pid:1323643 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:46:04 pid:1323790 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:46:11 pid:1323790 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:46:13 pid:1323790 worker[none:1323794] exit with status 9
|
||||
2025-10-09 15:46:13 pid:1323790 worker[none:1323797] exit with status 9
|
||||
2025-10-09 15:46:13 pid:1323790 worker[none:1323793] exit with status 9
|
||||
2025-10-09 15:46:13 pid:1323790 worker[none:1323795] exit with status 9
|
||||
2025-10-09 15:46:13 pid:1323790 worker[none:1323798] exit with status 9
|
||||
2025-10-09 15:46:13 pid:1323790 worker[none:1323796] exit with status 9
|
||||
2025-10-09 15:46:13 pid:1323790 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:50:31 pid:1324002 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:50:48 pid:1324002 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:50:50 pid:1324002 worker[none:1324003] exit with status 9
|
||||
2025-10-09 15:50:50 pid:1324002 worker[none:1324004] exit with status 9
|
||||
2025-10-09 15:50:50 pid:1324002 worker[none:1324008] exit with status 9
|
||||
2025-10-09 15:50:50 pid:1324002 worker[none:1324006] exit with status 9
|
||||
2025-10-09 15:50:50 pid:1324002 worker[none:1324007] exit with status 9
|
||||
2025-10-09 15:50:50 pid:1324002 worker[none:1324005] exit with status 9
|
||||
2025-10-09 15:50:50 pid:1324002 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:51:40 pid:1324215 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:51:49 pid:1324215 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:51:51 pid:1324215 worker[none:1324221] exit with status 9
|
||||
2025-10-09 15:51:51 pid:1324215 worker[none:1324217] exit with status 9
|
||||
2025-10-09 15:51:51 pid:1324215 worker[none:1324220] exit with status 9
|
||||
2025-10-09 15:51:51 pid:1324215 worker[none:1324219] exit with status 9
|
||||
2025-10-09 15:51:51 pid:1324215 worker[none:1324218] exit with status 9
|
||||
2025-10-09 15:51:51 pid:1324215 worker[none:1324216] exit with status 9
|
||||
2025-10-09 15:51:51 pid:1324215 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:52:19 pid:1324351 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:52:24 pid:1324351 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:52:25 pid:1324351 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:52:26 pid:1324351 worker[none:1324352] exit with status 9
|
||||
2025-10-09 15:52:26 pid:1324351 worker[none:1324355] exit with status 9
|
||||
2025-10-09 15:52:26 pid:1324351 worker[none:1324356] exit with status 9
|
||||
2025-10-09 15:52:26 pid:1324351 worker[none:1324353] exit with status 9
|
||||
2025-10-09 15:52:26 pid:1324351 worker[none:1324357] exit with status 9
|
||||
2025-10-09 15:52:26 pid:1324351 worker[none:1324354] exit with status 9
|
||||
2025-10-09 15:52:26 pid:1324351 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:52:35 pid:1324456 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:53:01 pid:1324456 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:53:03 pid:1324456 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:53:03 pid:1324456 worker[none:1324457] exit with status 9
|
||||
2025-10-09 15:53:03 pid:1324456 worker[none:1324458] exit with status 9
|
||||
2025-10-09 15:53:03 pid:1324456 worker[none:1324459] exit with status 9
|
||||
2025-10-09 15:53:03 pid:1324456 worker[none:1324460] exit with status 9
|
||||
2025-10-09 15:53:03 pid:1324456 worker[none:1324461] exit with status 9
|
||||
2025-10-09 15:53:03 pid:1324456 worker[none:1324462] exit with status 9
|
||||
2025-10-09 15:53:03 pid:1324456 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:56:19 pid:1324799 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:56:29 pid:1324799 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:56:31 pid:1324799 worker[none:1324802] exit with status 9
|
||||
2025-10-09 15:56:31 pid:1324799 worker[none:1324805] exit with status 9
|
||||
2025-10-09 15:56:31 pid:1324799 worker[none:1324801] exit with status 9
|
||||
2025-10-09 15:56:31 pid:1324799 worker[none:1324800] exit with status 9
|
||||
2025-10-09 15:56:31 pid:1324799 worker[none:1324803] exit with status 9
|
||||
2025-10-09 15:56:31 pid:1324799 worker[none:1324804] exit with status 9
|
||||
2025-10-09 15:56:31 pid:1324799 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:56:34 pid:1324918 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 15:56:54 pid:1324918 Workerman[go.php] stopping ...
|
||||
2025-10-09 15:56:56 pid:1324918 worker[none:1324921] exit with status 9
|
||||
2025-10-09 15:56:56 pid:1324918 worker[none:1324919] exit with status 9
|
||||
2025-10-09 15:56:56 pid:1324918 worker[none:1324923] exit with status 9
|
||||
2025-10-09 15:56:56 pid:1324918 worker[none:1324924] exit with status 9
|
||||
2025-10-09 15:56:56 pid:1324918 worker[none:1324922] exit with status 9
|
||||
2025-10-09 15:56:56 pid:1324918 worker[none:1324920] exit with status 9
|
||||
2025-10-09 15:56:56 pid:1324918 Workerman[go.php] has been stopped
|
||||
2025-10-09 15:59:16 pid:1325175 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:00:09 pid:1325175 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:00:11 pid:1325175 worker[none:1325179] exit with status 9
|
||||
2025-10-09 16:00:11 pid:1325175 worker[none:1325178] exit with status 9
|
||||
2025-10-09 16:00:11 pid:1325175 worker[none:1325181] exit with status 9
|
||||
2025-10-09 16:00:11 pid:1325175 worker[none:1325176] exit with status 9
|
||||
2025-10-09 16:00:11 pid:1325175 worker[none:1325180] exit with status 9
|
||||
2025-10-09 16:00:11 pid:1325175 worker[none:1325177] exit with status 9
|
||||
2025-10-09 16:00:11 pid:1325175 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:02:33 pid:1325703 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:03:19 pid:1325703 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:03:21 pid:1325703 worker[none:1325709] exit with status 9
|
||||
2025-10-09 16:03:21 pid:1325703 worker[none:1325705] exit with status 9
|
||||
2025-10-09 16:03:21 pid:1325703 worker[none:1325707] exit with status 9
|
||||
2025-10-09 16:03:21 pid:1325703 worker[none:1325708] exit with status 9
|
||||
2025-10-09 16:03:21 pid:1325703 worker[none:1325704] exit with status 9
|
||||
2025-10-09 16:03:21 pid:1325703 worker[none:1325706] exit with status 9
|
||||
2025-10-09 16:03:21 pid:1325703 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:06:20 pid:1326170 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:08:02 pid:1326170 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:08:04 pid:1326170 worker[none:1326172] exit with status 9
|
||||
2025-10-09 16:08:04 pid:1326170 worker[none:1326176] exit with status 9
|
||||
2025-10-09 16:08:04 pid:1326170 worker[none:1326171] exit with status 9
|
||||
2025-10-09 16:08:04 pid:1326170 worker[none:1326173] exit with status 9
|
||||
2025-10-09 16:08:04 pid:1326170 worker[none:1326174] exit with status 9
|
||||
2025-10-09 16:08:04 pid:1326170 worker[none:1326175] exit with status 9
|
||||
2025-10-09 16:08:04 pid:1326170 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:16:24 pid:1327142 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:16:34 pid:1327150 DivisionByZeroError: Division by zero in /www/goldrat/go.php:169
|
||||
Stack trace:
|
||||
#0 /www/goldrat/vendor/workerman/workerman/Events/Event.php(167): {closure}()
|
||||
#1 [internal function]: Workerman\Events\Event->timerCallback()
|
||||
#2 /www/goldrat/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
|
||||
#3 /www/goldrat/vendor/workerman/workerman/Worker.php(1719): Workerman\Events\Event->loop()
|
||||
#4 /www/goldrat/vendor/workerman/workerman/Worker.php(1510): Workerman\Worker::forkOneWorkerForLinux()
|
||||
#5 /www/goldrat/vendor/workerman/workerman/Worker.php(1484): Workerman\Worker::forkWorkersForLinux()
|
||||
#6 /www/goldrat/vendor/workerman/workerman/Worker.php(561): Workerman\Worker::forkWorkers()
|
||||
#7 /www/goldrat/go.php(192): Workerman\Worker::runAll()
|
||||
#8 {main}
|
||||
2025-10-09 16:16:34 pid:1327142 worker[none:1327150] exit with status 64000
|
||||
2025-10-09 16:16:36 pid:1327142 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:16:38 pid:1327142 worker[none:1327145] exit with status 9
|
||||
2025-10-09 16:16:38 pid:1327142 worker[none:1327143] exit with status 9
|
||||
2025-10-09 16:16:38 pid:1327142 worker[none:1327144] exit with status 9
|
||||
2025-10-09 16:16:38 pid:1327142 worker[none:1327146] exit with status 9
|
||||
2025-10-09 16:16:38 pid:1327142 worker[none:1327147] exit with status 9
|
||||
2025-10-09 16:16:38 pid:1327142 worker[none:1327148] exit with status 9
|
||||
2025-10-09 16:16:38 pid:1327142 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:17:08 pid:1327315 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:17:34 pid:1327315 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:17:36 pid:1327315 worker[none:1327316] exit with status 9
|
||||
2025-10-09 16:17:36 pid:1327315 worker[none:1327317] exit with status 9
|
||||
2025-10-09 16:17:36 pid:1327315 worker[none:1327318] exit with status 9
|
||||
2025-10-09 16:17:36 pid:1327315 worker[none:1327319] exit with status 9
|
||||
2025-10-09 16:17:36 pid:1327315 worker[none:1327321] exit with status 9
|
||||
2025-10-09 16:17:36 pid:1327315 worker[none:1327320] exit with status 9
|
||||
2025-10-09 16:17:36 pid:1327315 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:17:40 pid:1327557 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:19:07 pid:1327557 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:19:09 pid:1327557 worker[none:1327562] exit with status 9
|
||||
2025-10-09 16:19:09 pid:1327557 worker[none:1327559] exit with status 9
|
||||
2025-10-09 16:19:09 pid:1327557 worker[none:1327560] exit with status 9
|
||||
2025-10-09 16:19:09 pid:1327557 worker[none:1327558] exit with status 9
|
||||
2025-10-09 16:19:09 pid:1327557 worker[none:1327563] exit with status 9
|
||||
2025-10-09 16:19:09 pid:1327557 worker[none:1327561] exit with status 9
|
||||
2025-10-09 16:19:09 pid:1327557 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:19:10 pid:1328307 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:20:18 pid:1328307 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:20:20 pid:1328307 worker[none:1328310] exit with status 9
|
||||
2025-10-09 16:20:20 pid:1328307 worker[none:1328313] exit with status 9
|
||||
2025-10-09 16:20:20 pid:1328307 worker[none:1328311] exit with status 9
|
||||
2025-10-09 16:20:20 pid:1328307 worker[none:1328309] exit with status 9
|
||||
2025-10-09 16:20:20 pid:1328307 worker[none:1328308] exit with status 9
|
||||
2025-10-09 16:20:20 pid:1328307 worker[none:1328312] exit with status 9
|
||||
2025-10-09 16:20:20 pid:1328307 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:20:22 pid:1328888 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:21:58 pid:1328888 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:22:00 pid:1328888 worker[none:1328892] exit with status 9
|
||||
2025-10-09 16:22:00 pid:1328888 worker[none:1328894] exit with status 9
|
||||
2025-10-09 16:22:00 pid:1328888 worker[none:1328891] exit with status 9
|
||||
2025-10-09 16:22:00 pid:1328888 worker[none:1328890] exit with status 9
|
||||
2025-10-09 16:22:00 pid:1328888 worker[none:1328889] exit with status 9
|
||||
2025-10-09 16:22:00 pid:1328888 worker[none:1328893] exit with status 9
|
||||
2025-10-09 16:22:00 pid:1328888 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:22:04 pid:1329671 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:22:46 pid:1329671 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:22:48 pid:1329671 worker[none:1329672] exit with status 9
|
||||
2025-10-09 16:22:48 pid:1329671 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:22:50 pid:1329918 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:29:04 pid:1329918 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:29:06 pid:1329918 worker[none:1329920] exit with status 9
|
||||
2025-10-09 16:29:06 pid:1329918 worker[none:1329922] exit with status 9
|
||||
2025-10-09 16:29:06 pid:1329918 worker[none:1329921] exit with status 9
|
||||
2025-10-09 16:29:06 pid:1329918 worker[none:1329919] exit with status 9
|
||||
2025-10-09 16:29:06 pid:1329918 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:37:11 pid:1332641 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:37:17 pid:1332641 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:37:19 pid:1332641 worker[Glod Rat:1332642] exit with status 9
|
||||
2025-10-09 16:37:19 pid:1332641 worker[Glod Rat:1332644] exit with status 9
|
||||
2025-10-09 16:37:19 pid:1332641 worker[Glod Rat:1332645] exit with status 9
|
||||
2025-10-09 16:37:19 pid:1332641 worker[Glod Rat:1332643] exit with status 9
|
||||
2025-10-09 16:37:19 pid:1332641 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:38:32 pid:1332778 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:38:41 pid:1332778 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:38:43 pid:1332778 worker[Glod Rat:1332781] exit with status 9
|
||||
2025-10-09 16:38:43 pid:1332778 worker[Glod Rat:1332782] exit with status 9
|
||||
2025-10-09 16:38:43 pid:1332778 worker[Glod Rat:1332780] exit with status 9
|
||||
2025-10-09 16:38:43 pid:1332778 worker[Glod Rat:1332779] exit with status 9
|
||||
2025-10-09 16:38:43 pid:1332778 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:39:11 pid:1332906 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:40:35 pid:1332906 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:40:37 pid:1332906 worker[Glod Rat:1332910] exit with status 9
|
||||
2025-10-09 16:40:37 pid:1332906 worker[Glod Rat:1332909] exit with status 9
|
||||
2025-10-09 16:40:37 pid:1332906 worker[Glod Rat:1332908] exit with status 9
|
||||
2025-10-09 16:40:37 pid:1332906 worker[Glod Rat:1332907] exit with status 9
|
||||
2025-10-09 16:40:37 pid:1332906 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:41:51 pid:1333520 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:42:16 pid:1333520 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:42:18 pid:1333520 worker[Glod Rat:1333521] exit with status 9
|
||||
2025-10-09 16:42:18 pid:1333520 worker[Glod Rat:1333522] exit with status 9
|
||||
2025-10-09 16:42:18 pid:1333520 worker[Glod Rat:1333523] exit with status 9
|
||||
2025-10-09 16:42:18 pid:1333520 worker[Glod Rat:1333524] exit with status 9
|
||||
2025-10-09 16:42:18 pid:1333520 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:42:35 pid:1333740 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:43:56 pid:1333740 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:43:58 pid:1333740 worker[Glod Rat:1333743] exit with status 9
|
||||
2025-10-09 16:43:58 pid:1333740 worker[Glod Rat:1333742] exit with status 9
|
||||
2025-10-09 16:43:58 pid:1333740 worker[Glod Rat:1333744] exit with status 9
|
||||
2025-10-09 16:43:58 pid:1333740 worker[Glod Rat:1333741] exit with status 9
|
||||
2025-10-09 16:43:58 pid:1333740 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:44:14 pid:1334316 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:51:49 pid:1334316 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:51:51 pid:1334316 worker[Glod Rat:1334318] exit with status 9
|
||||
2025-10-09 16:51:51 pid:1334316 worker[Glod Rat:1334319] exit with status 9
|
||||
2025-10-09 16:51:51 pid:1334316 worker[Glod Rat:1334320] exit with status 9
|
||||
2025-10-09 16:51:51 pid:1334316 worker[Glod Rat:1334317] exit with status 9
|
||||
2025-10-09 16:51:51 pid:1334316 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:51:53 pid:1337260 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:53:17 pid:1337260 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:53:19 pid:1337260 worker[Glod Rat:1337263] exit with status 9
|
||||
2025-10-09 16:53:19 pid:1337260 worker[Glod Rat:1337261] exit with status 9
|
||||
2025-10-09 16:53:19 pid:1337260 worker[Glod Rat:1337262] exit with status 9
|
||||
2025-10-09 16:53:19 pid:1337260 worker[Glod Rat:1337264] exit with status 9
|
||||
2025-10-09 16:53:19 pid:1337260 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:53:20 pid:1337801 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:56:08 pid:1337801 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:10 pid:1337801 worker[Glod Rat:1337804] exit with status 9
|
||||
2025-10-09 16:56:10 pid:1337801 worker[Glod Rat:1337802] exit with status 9
|
||||
2025-10-09 16:56:10 pid:1337801 worker[Glod Rat:1337805] exit with status 9
|
||||
2025-10-09 16:56:10 pid:1337801 worker[Glod Rat:1337803] exit with status 9
|
||||
2025-10-09 16:56:10 pid:1337801 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:56:15 pid:1338961 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:56:28 pid:1338961 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:30 pid:1338961 worker[Glod Rat:1338962] exit with status 9
|
||||
2025-10-09 16:56:30 pid:1338961 worker[Glod Rat:1338965] exit with status 9
|
||||
2025-10-09 16:56:30 pid:1338961 worker[Glod Rat:1338963] exit with status 9
|
||||
2025-10-09 16:56:30 pid:1338961 worker[Glod Rat:1338964] exit with status 9
|
||||
2025-10-09 16:56:30 pid:1338961 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:56:30 pid:1339091 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:56:30 pid:1339091 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:32 pid:1339091 worker[Glod Rat:1339094] exit with status 9
|
||||
2025-10-09 16:56:32 pid:1339091 worker[Glod Rat:1339092] exit with status 9
|
||||
2025-10-09 16:56:32 pid:1339091 worker[Glod Rat:1339093] exit with status 9
|
||||
2025-10-09 16:56:32 pid:1339091 worker[Glod Rat:1339095] exit with status 9
|
||||
2025-10-09 16:56:32 pid:1339091 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:56:32 pid:1339121 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:56:33 pid:1339121 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:33 pid:1339121 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:34 pid:1339121 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:34 pid:1339121 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:35 pid:1339121 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:35 pid:1339121 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:35 pid:1339121 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:35 pid:1339121 worker[Glod Rat:1339125] exit with status 9
|
||||
2025-10-09 16:56:35 pid:1339121 worker[Glod Rat:1339124] exit with status 9
|
||||
2025-10-09 16:56:35 pid:1339121 worker[Glod Rat:1339123] exit with status 9
|
||||
2025-10-09 16:56:35 pid:1339121 worker[Glod Rat:1339122] exit with status 9
|
||||
2025-10-09 16:56:35 pid:1339121 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:56:37 pid:1339165 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:56:39 pid:1339165 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:56:41 pid:1339165 worker[Glod Rat:1339167] exit with status 9
|
||||
2025-10-09 16:56:41 pid:1339165 worker[Glod Rat:1339166] exit with status 9
|
||||
2025-10-09 16:56:41 pid:1339165 worker[Glod Rat:1339168] exit with status 9
|
||||
2025-10-09 16:56:41 pid:1339165 worker[Glod Rat:1339169] exit with status 9
|
||||
2025-10-09 16:56:41 pid:1339165 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:56:56 pid:1339250 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:57:00 pid:1339250 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:57:02 pid:1339250 worker[Glod Rat:1339254] exit with status 9
|
||||
2025-10-09 16:57:02 pid:1339250 worker[Glod Rat:1339251] exit with status 9
|
||||
2025-10-09 16:57:02 pid:1339250 worker[Glod Rat:1339252] exit with status 9
|
||||
2025-10-09 16:57:02 pid:1339250 worker[Glod Rat:1339253] exit with status 9
|
||||
2025-10-09 16:57:02 pid:1339250 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:57:09 pid:1339342 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:57:23 pid:1339342 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:57:25 pid:1339342 worker[Glod Rat:1339343] exit with status 9
|
||||
2025-10-09 16:57:25 pid:1339342 worker[Glod Rat:1339344] exit with status 9
|
||||
2025-10-09 16:57:25 pid:1339342 worker[Glod Rat:1339346] exit with status 9
|
||||
2025-10-09 16:57:25 pid:1339342 worker[Glod Rat:1339345] exit with status 9
|
||||
2025-10-09 16:57:25 pid:1339342 Workerman[go.php] has been stopped
|
||||
2025-10-09 16:57:30 pid:1339522 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 16:58:15 pid:1339522 Workerman[go.php] stopping ...
|
||||
2025-10-09 16:58:17 pid:1339522 worker[Glod Rat:1339524] exit with status 9
|
||||
2025-10-09 16:58:17 pid:1339522 worker[Glod Rat:1339523] exit with status 9
|
||||
2025-10-09 16:58:17 pid:1339522 worker[Glod Rat:1339526] exit with status 9
|
||||
2025-10-09 16:58:17 pid:1339522 worker[Glod Rat:1339525] exit with status 9
|
||||
2025-10-09 16:58:17 pid:1339522 Workerman[go.php] has been stopped
|
||||
2025-10-09 17:00:34 pid:1339955 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 17:00:58 pid:1339955 Workerman[go.php] stopping ...
|
||||
2025-10-09 17:01:00 pid:1339955 worker[Glod Rat:1339958] exit with status 9
|
||||
2025-10-09 17:01:00 pid:1339955 worker[Glod Rat:1339956] exit with status 9
|
||||
2025-10-09 17:01:00 pid:1339955 worker[Glod Rat:1339957] exit with status 9
|
||||
2025-10-09 17:01:00 pid:1339955 worker[Glod Rat:1339959] exit with status 9
|
||||
2025-10-09 17:01:00 pid:1339955 Workerman[go.php] has been stopped
|
||||
2025-10-09 17:01:01 pid:1340142 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 17:05:01 pid:1340142 Workerman[go.php] stopping ...
|
||||
2025-10-09 17:05:03 pid:1340142 worker[Glod Rat:1340143] exit with status 9
|
||||
2025-10-09 17:05:03 pid:1340142 worker[Glod Rat:1340144] exit with status 9
|
||||
2025-10-09 17:05:03 pid:1340142 worker[Glod Rat:1340145] exit with status 9
|
||||
2025-10-09 17:05:03 pid:1340142 worker[Glod Rat:1340146] exit with status 9
|
||||
2025-10-09 17:05:03 pid:1340142 Workerman[go.php] has been stopped
|
||||
2025-10-09 17:05:13 pid:1341830 Workerman[go.php] start in DEBUG mode
|
||||
2025-10-09 17:07:02 pid:1341830 Workerman[go.php] stopping ...
|
||||
2025-10-09 17:07:04 pid:1341830 worker[Glod Rat:1341831] exit with status 9
|
||||
2025-10-09 17:07:04 pid:1341830 worker[Glod Rat:1341832] exit with status 9
|
||||
2025-10-09 17:07:04 pid:1341830 worker[Glod Rat:1341834] exit with status 9
|
||||
2025-10-09 17:07:04 pid:1341830 worker[Glod Rat:1341833] exit with status 9
|
||||
2025-10-09 17:07:04 pid:1341830 Workerman[go.php] has been stopped
|
||||
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
open_collective: workerman
|
||||
patreon: walkor
|
||||
@@ -0,0 +1,6 @@
|
||||
logs
|
||||
.buildpath
|
||||
.project
|
||||
.settings
|
||||
.idea
|
||||
.DS_Store
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of workerman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Workerman;
|
||||
|
||||
/**
|
||||
* Autoload.
|
||||
*/
|
||||
class Autoloader
|
||||
{
|
||||
/**
|
||||
* Autoload root path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $_autoloadRootPath = '';
|
||||
|
||||
/**
|
||||
* Set autoload root path.
|
||||
*
|
||||
* @param string $root_path
|
||||
* @return void
|
||||
*/
|
||||
public static function setRootPath($root_path)
|
||||
{
|
||||
self::$_autoloadRootPath = $root_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load files by namespace.
|
||||
*
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
public static function loadByNamespace($name)
|
||||
{
|
||||
$class_path = \str_replace('\\', \DIRECTORY_SEPARATOR, $name);
|
||||
if (\strpos($name, 'Workerman\\') === 0) {
|
||||
$class_file = __DIR__ . \substr($class_path, \strlen('Workerman')) . '.php';
|
||||
} else {
|
||||
if (self::$_autoloadRootPath) {
|
||||
$class_file = self::$_autoloadRootPath . \DIRECTORY_SEPARATOR . $class_path . '.php';
|
||||
}
|
||||
if (empty($class_file) || !\is_file($class_file)) {
|
||||
$class_file = __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . "$class_path.php";
|
||||
}
|
||||
}
|
||||
|
||||
if (\is_file($class_file)) {
|
||||
require_once($class_file);
|
||||
if (\class_exists($name, false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
\spl_autoload_register('\Workerman\Autoloader::loadByNamespace');
|
||||
@@ -0,0 +1,382 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of workerman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Workerman\Connection;
|
||||
|
||||
use StdClass;
|
||||
use Workerman\Events\EventInterface;
|
||||
use Workerman\Lib\Timer;
|
||||
use Workerman\Worker;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* AsyncTcpConnection.
|
||||
*/
|
||||
class AsyncTcpConnection extends TcpConnection
|
||||
{
|
||||
/**
|
||||
* Emitted when socket connection is successfully established.
|
||||
*
|
||||
* @var callable|null
|
||||
*/
|
||||
public $onConnect = null;
|
||||
|
||||
/**
|
||||
* Transport layer protocol.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $transport = 'tcp';
|
||||
|
||||
/**
|
||||
* Status.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_status = self::STATUS_INITIAL;
|
||||
|
||||
/**
|
||||
* Remote host.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_remoteHost = '';
|
||||
|
||||
/**
|
||||
* Remote port.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_remotePort = 80;
|
||||
|
||||
/**
|
||||
* Connect start time.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
protected $_connectStartTime = 0;
|
||||
|
||||
/**
|
||||
* Remote URI.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_remoteURI = '';
|
||||
|
||||
/**
|
||||
* Context option.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_contextOption = null;
|
||||
|
||||
/**
|
||||
* Reconnect timer.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_reconnectTimer = null;
|
||||
|
||||
|
||||
/**
|
||||
* PHP built-in protocols.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $_builtinTransports = array(
|
||||
'tcp' => 'tcp',
|
||||
'udp' => 'udp',
|
||||
'unix' => 'unix',
|
||||
'ssl' => 'ssl',
|
||||
'sslv2' => 'sslv2',
|
||||
'sslv3' => 'sslv3',
|
||||
'tls' => 'tls'
|
||||
);
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param string $remote_address
|
||||
* @param array $context_option
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($remote_address, array $context_option = array())
|
||||
{
|
||||
$address_info = \parse_url($remote_address);
|
||||
if (!$address_info) {
|
||||
list($scheme, $this->_remoteAddress) = \explode(':', $remote_address, 2);
|
||||
if('unix' === strtolower($scheme)) {
|
||||
$this->_remoteAddress = substr($remote_address, strpos($remote_address, '/') + 2);
|
||||
}
|
||||
if (!$this->_remoteAddress) {
|
||||
Worker::safeEcho(new \Exception('bad remote_address'));
|
||||
}
|
||||
} else {
|
||||
if (!isset($address_info['port'])) {
|
||||
$address_info['port'] = 0;
|
||||
}
|
||||
if (!isset($address_info['path'])) {
|
||||
$address_info['path'] = '/';
|
||||
}
|
||||
if (!isset($address_info['query'])) {
|
||||
$address_info['query'] = '';
|
||||
} else {
|
||||
$address_info['query'] = '?' . $address_info['query'];
|
||||
}
|
||||
$this->_remoteHost = $address_info['host'];
|
||||
$this->_remotePort = $address_info['port'];
|
||||
$this->_remoteURI = "{$address_info['path']}{$address_info['query']}";
|
||||
$scheme = isset($address_info['scheme']) ? $address_info['scheme'] : 'tcp';
|
||||
$this->_remoteAddress = 'unix' === strtolower($scheme)
|
||||
? substr($remote_address, strpos($remote_address, '/') + 2)
|
||||
: $this->_remoteHost . ':' . $this->_remotePort;
|
||||
}
|
||||
|
||||
$this->id = $this->_id = self::$_idRecorder++;
|
||||
if(\PHP_INT_MAX === self::$_idRecorder){
|
||||
self::$_idRecorder = 0;
|
||||
}
|
||||
// Check application layer protocol class.
|
||||
if (!isset(self::$_builtinTransports[$scheme])) {
|
||||
$scheme = \ucfirst($scheme);
|
||||
$this->protocol = '\\Protocols\\' . $scheme;
|
||||
if (!\class_exists($this->protocol)) {
|
||||
$this->protocol = "\\Workerman\\Protocols\\$scheme";
|
||||
if (!\class_exists($this->protocol)) {
|
||||
throw new Exception("class \\Protocols\\$scheme not exist");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->transport = self::$_builtinTransports[$scheme];
|
||||
}
|
||||
|
||||
// For statistics.
|
||||
++self::$statistics['connection_count'];
|
||||
$this->maxSendBufferSize = self::$defaultMaxSendBufferSize;
|
||||
$this->maxPackageSize = self::$defaultMaxPackageSize;
|
||||
$this->_contextOption = $context_option;
|
||||
$this->context = new StdClass;
|
||||
static::$connections[$this->_id] = $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do connect.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
if ($this->_status !== self::STATUS_INITIAL && $this->_status !== self::STATUS_CLOSING &&
|
||||
$this->_status !== self::STATUS_CLOSED) {
|
||||
return;
|
||||
}
|
||||
$this->_status = self::STATUS_CONNECTING;
|
||||
$this->_connectStartTime = \microtime(true);
|
||||
set_error_handler(function() {
|
||||
return false;
|
||||
});
|
||||
if ($this->transport !== 'unix') {
|
||||
if (!$this->_remotePort) {
|
||||
$this->_remotePort = $this->transport === 'ssl' ? 443 : 80;
|
||||
$this->_remoteAddress = $this->_remoteHost.':'.$this->_remotePort;
|
||||
}
|
||||
// Open socket connection asynchronously.
|
||||
if ($this->_contextOption) {
|
||||
$context = \stream_context_create($this->_contextOption);
|
||||
$this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}",
|
||||
$errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT, $context);
|
||||
} else {
|
||||
$this->_socket = \stream_socket_client("tcp://{$this->_remoteHost}:{$this->_remotePort}",
|
||||
$errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT);
|
||||
}
|
||||
} else {
|
||||
$this->_socket = \stream_socket_client("{$this->transport}://{$this->_remoteAddress}", $errno, $errstr, 0,
|
||||
\STREAM_CLIENT_ASYNC_CONNECT);
|
||||
}
|
||||
restore_error_handler();
|
||||
// If failed attempt to emit onError callback.
|
||||
if (!$this->_socket || !\is_resource($this->_socket)) {
|
||||
$this->emitError(\WORKERMAN_CONNECT_FAIL, $errstr);
|
||||
if ($this->_status === self::STATUS_CLOSING) {
|
||||
$this->destroy();
|
||||
}
|
||||
if ($this->_status === self::STATUS_CLOSED) {
|
||||
$this->onConnect = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Add socket to global event loop waiting connection is successfully established or faild.
|
||||
Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'checkConnection'));
|
||||
// For windows.
|
||||
if(\DIRECTORY_SEPARATOR === '\\') {
|
||||
Worker::$globalEvent->add($this->_socket, EventInterface::EV_EXCEPT, array($this, 'checkConnection'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconnect.
|
||||
*
|
||||
* @param int $after
|
||||
* @return void
|
||||
*/
|
||||
public function reconnect($after = 0)
|
||||
{
|
||||
$this->_status = self::STATUS_INITIAL;
|
||||
static::$connections[$this->_id] = $this;
|
||||
if ($this->_reconnectTimer) {
|
||||
Timer::del($this->_reconnectTimer);
|
||||
}
|
||||
if ($after > 0) {
|
||||
$this->_reconnectTimer = Timer::add($after, array($this, 'connect'), null, false);
|
||||
return;
|
||||
}
|
||||
$this->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* CancelReconnect.
|
||||
*/
|
||||
public function cancelReconnect()
|
||||
{
|
||||
if ($this->_reconnectTimer) {
|
||||
Timer::del($this->_reconnectTimer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote address.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRemoteHost()
|
||||
{
|
||||
return $this->_remoteHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote URI.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRemoteURI()
|
||||
{
|
||||
return $this->_remoteURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to emit onError callback.
|
||||
*
|
||||
* @param int $code
|
||||
* @param string $msg
|
||||
* @return void
|
||||
*/
|
||||
protected function emitError($code, $msg)
|
||||
{
|
||||
$this->_status = self::STATUS_CLOSING;
|
||||
if ($this->onError) {
|
||||
try {
|
||||
\call_user_func($this->onError, $this, $code, $msg);
|
||||
} catch (\Exception $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
} catch (\Error $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check connection is successfully established or faild.
|
||||
*
|
||||
* @param resource $socket
|
||||
* @return void
|
||||
*/
|
||||
public function checkConnection()
|
||||
{
|
||||
// Remove EV_EXPECT for windows.
|
||||
if(\DIRECTORY_SEPARATOR === '\\') {
|
||||
Worker::$globalEvent->del($this->_socket, EventInterface::EV_EXCEPT);
|
||||
}
|
||||
|
||||
// Remove write listener.
|
||||
Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
|
||||
|
||||
if ($this->_status !== self::STATUS_CONNECTING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check socket state.
|
||||
if ($address = \stream_socket_get_name($this->_socket, true)) {
|
||||
// Nonblocking.
|
||||
\stream_set_blocking($this->_socket, false);
|
||||
// Compatible with hhvm
|
||||
if (\function_exists('stream_set_read_buffer')) {
|
||||
\stream_set_read_buffer($this->_socket, 0);
|
||||
}
|
||||
// Try to open keepalive for tcp and disable Nagle algorithm.
|
||||
if (\function_exists('socket_import_stream') && $this->transport === 'tcp') {
|
||||
$raw_socket = \socket_import_stream($this->_socket);
|
||||
\socket_set_option($raw_socket, \SOL_SOCKET, \SO_KEEPALIVE, 1);
|
||||
\socket_set_option($raw_socket, \SOL_TCP, \TCP_NODELAY, 1);
|
||||
}
|
||||
|
||||
// SSL handshake.
|
||||
if ($this->transport === 'ssl') {
|
||||
$this->_sslHandshakeCompleted = $this->doSslHandshake($this->_socket);
|
||||
if ($this->_sslHandshakeCompleted === false) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// There are some data waiting to send.
|
||||
if ($this->_sendBuffer) {
|
||||
Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));
|
||||
}
|
||||
}
|
||||
|
||||
// Register a listener waiting read event.
|
||||
Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
|
||||
|
||||
$this->_status = self::STATUS_ESTABLISHED;
|
||||
$this->_remoteAddress = $address;
|
||||
|
||||
// Try to emit onConnect callback.
|
||||
if ($this->onConnect) {
|
||||
try {
|
||||
\call_user_func($this->onConnect, $this);
|
||||
} catch (\Exception $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
} catch (\Error $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
}
|
||||
}
|
||||
// Try to emit protocol::onConnect
|
||||
if ($this->protocol && \method_exists($this->protocol, 'onConnect')) {
|
||||
try {
|
||||
\call_user_func(array($this->protocol, 'onConnect'), $this);
|
||||
} catch (\Exception $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
} catch (\Error $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Connection failed.
|
||||
$this->emitError(\WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(\microtime(true) - $this->_connectStartTime, 4) . ' seconds');
|
||||
if ($this->_status === self::STATUS_CLOSING) {
|
||||
$this->destroy();
|
||||
}
|
||||
if ($this->_status === self::STATUS_CLOSED) {
|
||||
$this->onConnect = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of workerman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Workerman\Connection;
|
||||
|
||||
use Workerman\Events\EventInterface;
|
||||
use Workerman\Worker;
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* AsyncUdpConnection.
|
||||
*/
|
||||
class AsyncUdpConnection extends UdpConnection
|
||||
{
|
||||
/**
|
||||
* Emitted when socket connection is successfully established.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
public $onConnect = null;
|
||||
|
||||
/**
|
||||
* Emitted when socket connection closed.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
public $onClose = null;
|
||||
|
||||
/**
|
||||
* Connected or not.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $connected = false;
|
||||
|
||||
/**
|
||||
* Context option.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_contextOption = null;
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param string $remote_address
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($remote_address, $context_option = null)
|
||||
{
|
||||
// Get the application layer communication protocol and listening address.
|
||||
list($scheme, $address) = \explode(':', $remote_address, 2);
|
||||
// Check application layer protocol class.
|
||||
if ($scheme !== 'udp') {
|
||||
$scheme = \ucfirst($scheme);
|
||||
$this->protocol = '\\Protocols\\' . $scheme;
|
||||
if (!\class_exists($this->protocol)) {
|
||||
$this->protocol = "\\Workerman\\Protocols\\$scheme";
|
||||
if (!\class_exists($this->protocol)) {
|
||||
throw new Exception("class \\Protocols\\$scheme not exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->_remoteAddress = \substr($address, 2);
|
||||
$this->_contextOption = $context_option;
|
||||
}
|
||||
|
||||
/**
|
||||
* For udp package.
|
||||
*
|
||||
* @param resource $socket
|
||||
* @return bool
|
||||
*/
|
||||
public function baseRead($socket)
|
||||
{
|
||||
$recv_buffer = \stream_socket_recvfrom($socket, Worker::MAX_UDP_PACKAGE_SIZE, 0, $remote_address);
|
||||
if (false === $recv_buffer || empty($remote_address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->onMessage) {
|
||||
if ($this->protocol) {
|
||||
$parser = $this->protocol;
|
||||
$recv_buffer = $parser::decode($recv_buffer, $this);
|
||||
}
|
||||
++ConnectionInterface::$statistics['total_request'];
|
||||
try {
|
||||
\call_user_func($this->onMessage, $this, $recv_buffer);
|
||||
} catch (\Exception $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
} catch (\Error $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends data on the connection.
|
||||
*
|
||||
* @param string $send_buffer
|
||||
* @param bool $raw
|
||||
* @return void|boolean
|
||||
*/
|
||||
public function send($send_buffer, $raw = false)
|
||||
{
|
||||
if (false === $raw && $this->protocol) {
|
||||
$parser = $this->protocol;
|
||||
$send_buffer = $parser::encode($send_buffer, $this);
|
||||
if ($send_buffer === '') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ($this->connected === false) {
|
||||
$this->connect();
|
||||
}
|
||||
return \strlen($send_buffer) === \stream_socket_sendto($this->_socket, $send_buffer, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close connection.
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param bool $raw
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function close($data = null, $raw = false)
|
||||
{
|
||||
if ($data !== null) {
|
||||
$this->send($data, $raw);
|
||||
}
|
||||
Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ);
|
||||
\fclose($this->_socket);
|
||||
$this->connected = false;
|
||||
// Try to emit onClose callback.
|
||||
if ($this->onClose) {
|
||||
try {
|
||||
\call_user_func($this->onClose, $this);
|
||||
} catch (\Exception $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
} catch (\Error $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
}
|
||||
}
|
||||
$this->onConnect = $this->onMessage = $this->onClose = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
if ($this->connected === true) {
|
||||
return;
|
||||
}
|
||||
if ($this->_contextOption) {
|
||||
$context = \stream_context_create($this->_contextOption);
|
||||
$this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg,
|
||||
30, \STREAM_CLIENT_CONNECT, $context);
|
||||
} else {
|
||||
$this->_socket = \stream_socket_client("udp://{$this->_remoteAddress}", $errno, $errmsg);
|
||||
}
|
||||
|
||||
if (!$this->_socket) {
|
||||
Worker::safeEcho(new \Exception($errmsg));
|
||||
return;
|
||||
}
|
||||
|
||||
\stream_set_blocking($this->_socket, false);
|
||||
|
||||
if ($this->onMessage) {
|
||||
Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
|
||||
}
|
||||
$this->connected = true;
|
||||
// Try to emit onConnect callback.
|
||||
if ($this->onConnect) {
|
||||
try {
|
||||
\call_user_func($this->onConnect, $this);
|
||||
} catch (\Exception $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
} catch (\Error $e) {
|
||||
Worker::stopAll(250, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of workerman.
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @author walkor<walkor@workerman.net>
|
||||
* @copyright walkor<walkor@workerman.net>
|
||||
* @link http://www.workerman.net/
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
namespace Workerman\Connection;
|
||||
|
||||
/**
|
||||
* ConnectionInterface.
|
||||
*/
|
||||
#[\AllowDynamicProperties]
|
||||
abstract class ConnectionInterface
|
||||
{
|
||||
/**
|
||||
* Statistics for status command.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $statistics = array(
|
||||
'connection_count' => 0,
|
||||
'total_request' => 0,
|
||||
'throw_exception' => 0,
|
||||
'send_fail' => 0,
|
||||
);
|
||||
|
||||
/**
|
||||
* Emitted when data is received.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
public $onMessage = null;
|
||||
|
||||
/**
|
||||
* Emitted when the other end of the socket sends a FIN packet.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
public $onClose = null;
|
||||
|
||||
/**
|
||||
* Emitted when an error occurs with connection.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
public $onError = null;
|
||||
|
||||
/**
|
||||
* Sends data on the connection.
|
||||
*
|
||||
* @param mixed $send_buffer
|
||||
* @return void|boolean
|
||||
*/
|
||||
abstract public function send($send_buffer);
|
||||
|
||||
/**
|
||||
* Get remote IP.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getRemoteIp();
|
||||
|
||||
/**
|
||||
* Get remote port.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getRemotePort();
|
||||
|
||||
/**
|
||||
* Get remote address.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getRemoteAddress();
|
||||
|
||||
/**
|
||||
* Get local IP.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getLocalIp();
|
||||
|
||||
/**
|
||||
* Get local port.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getLocalPort();
|
||||
|
||||
/**
|
||||
* Get local address.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getLocalAddress();
|
||||
|
||||
/**
|
||||
* Is ipv4.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function isIPv4();
|
||||
|
||||
/**
|
||||
* Is ipv6.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function isIPv6();
|
||||
|
||||
/**
|
||||
* Close connection.
|
||||
*
|
||||
* @param string|null $data
|
||||
* @return void
|
||||
*/
|
||||
abstract public function close($data = null);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user