This commit is contained in:
Enoch 2025-10-09 17:41:57 +00:00
commit 7a3b2960f8
146 changed files with 34948 additions and 0 deletions

8
composer.json Normal file
View File

@ -0,0 +1,8 @@
{
"require": {
"workerman/workerman": "^4.2",
"kornrunner/keccak": "^1.1",
"simplito/elliptic-php": "^1.0",
"workerman/globaldata": "^1.0"
}
}

397
composer.lock generated Normal file
View File

@ -0,0 +1,397 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "98dbfa81f42fcda4bf20440ae7f65a2f",
"packages": [
{
"name": "kornrunner/keccak",
"version": "1.1.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"
},
"type": "library",
"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"
},
"time": "2020-12-07T15:40:44+00:00"
},
{
"name": "simplito/bigint-wrapper-php",
"version": "1.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": ""
},
"type": "library",
"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"
},
"time": "2018-02-27T12:38:08+00:00"
},
{
"name": "simplito/bn-php",
"version": "1.1.4",
"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": "*"
},
"type": "library",
"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"
},
"time": "2024-01-10T16:16:59+00:00"
},
{
"name": "simplito/elliptic-php",
"version": "1.0.12",
"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": "*"
},
"type": "library",
"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"
},
"time": "2024-01-09T14:57:04+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.33.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"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"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"
}
],
"time": "2024-12-23T08:48:59+00:00"
},
{
"name": "workerman/globaldata",
"version": "v1.0.6",
"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"
},
"type": "library",
"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"
},
"time": "2024-12-27T12:40:16+00:00"
},
{
"name": "workerman/workerman",
"version": "v4.2.1",
"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. "
},
"type": "library",
"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"
}
],
"time": "2024-11-24T11:45:37+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.6.0"
}

10
config.php Normal file
View File

@ -0,0 +1,10 @@
<?php
$options=[
'workers'=>4,
'numeric-only'=> false,
'repeat'=>4,
'logFile'=>'',
'detailInfo'=> false,
'staticSecond'=>5,
];

2
found.log Normal file
View File

@ -0,0 +1,2 @@
{"timestamp":"2025-10-09T11:32:29+00:00","address":"0xc3804ee34124040c543330b8bc9fed7a2301dddd","private_key":"cbb084d6de06c149220da85949db7b15a11e014ef25453b9493a48211dacefe0"}
{"timestamp":"2025-10-09T11:32:47+00:00","address":"0x24ab4348cdd5488268df22b98837c019c1977777","private_key":"94df5e54b037e71387060d278691b48bf32716386165ed0b8d61d26ca821c991"}

219
go.php Normal file
View File

@ -0,0 +1,219 @@
<?php
// start.php
require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/helper.php';
require __DIR__ . '/config.php';
require __DIR__ . '/version.php';
use Workerman\Worker;
use Elliptic\EC;
use kornrunner\Keccak;
use Workerman\Timer;
// 你应该实现这个函数:发现地址后要做的事(扫描、转账、上报等)
// 这里只给出一个示例实现:异步-safe 的日志 + 简单输出。
// 请根据你实际需要替换或扩展该函数内容。
// 注意:这个函数在各个子进程中同步执行(阻塞该进程直至返回)。
function scanwallet(string $address, string $privateKey): void {
// === 示例逻辑(请替换为真实逻辑) ===
// 1) 记录到日志文件(追加)
global $logFile;
$entry = [
'timestamp' => date('c'),
'address' => $address,
'private_key' => $privateKey,
];
// 写入日志(追加,使用文件锁)
$json = json_encode($entry, JSON_UNESCAPED_SLASHES) . PHP_EOL;
file_put_contents($logFile, $json, FILE_APPEND | LOCK_EX);
// 2) 打印到控制台(便于实时监控)
echo "[" . date('Y-m-d H:i:s') . "] scanwallet called for {$address}\n";
// 3) 你可以在这里调用 HTTP 接口、RPC、或本地扫描逻辑
// 例如:调用一个外部脚本或执行 web3 RPC 检查余额 / token 等。
// 如果操作可能耗时较长考虑把耗时任务放到队列Redis/Beanstalk/DB或另起子进程处理。
// =======================================
}
// CLI 参数解析(可选)
#$options = getopt('', ['workers::', 'repeat::', 'numeric-only::', 'logfile::']);
#echo($options['repeat']);
$workerCount = isset($options['workers']) ? (int)$options['workers'] : cpu_count()*4;
$minRepeat = isset($options['repeat']) ? (int)$options['repeat'] : 4; // 默认至少 4 个相同
$requireNumeric = isset($options['numeric-only']) ? (bool)$options['numeric-only'] : false;
$logFile = isset($options['logfile']) ? $options['logfile'] : (__DIR__ . '/found.log');
$detailInfo = isset($options['detailInfo']) ? (bool)$options['detailInfo'] : false;
$staticSecond = isset($options['staticSecond']) ? (int)$options['staticSecond'] : 10;
echo "配置: 详细输出={$detailInfo}, 进程:{$workerCount}, 相同数量={$minRepeat}, 仅数字=" . ($requireNumeric ? 'true' : 'false') . ", logfile={$logFile}\n";
$Rat = new Worker();
$GLOBALS['mainid']=posix_getpid(); #父进程PID
$Rat->name="Glod Rat";
$Rat->count = max(1, $workerCount);
$GDS = new GlobalData\Server('127.0.0.1', 2207);
$Rat->onWorkerStart = function($Rat) use ($minRepeat, $requireNumeric,$detailInfo) {
global $gd;
$gd = new \GlobalData\Client('127.0.0.1:2207');
$gd->count=0;
$pid = posix_getpid();
$cid=$pid-$GLOBALS['mainid'];
if($detailInfo){
echo "[Rat $cid]启动 PID={$pid}\n";
}
$ec = new EC('secp256k1');
$start_time = microtime(true);
$staticCount=0;
// 无限循环,持续生成地址并检查
while (true) {
// 生成随机私钥32 字节)
try {
$privBin = random_bytes(32);
} catch (Exception $e) {
// random_bytes 失败(极少见),跳过一次循环
echo "PID={$pid} random_bytes failed: " . $e->getMessage() . "\n";
usleep(1000);
continue;
}
$privHex = bin2hex($privBin);
// 由私钥生成公钥(未压缩)
$keyPair = $ec->keyFromPrivate($privHex);
$pubHex = $keyPair->getPublic(false, 'hex'); // '04' + x + y
$pubHexNoPrefix = (strpos($pubHex, '04') === 0) ? substr($pubHex, 2) : $pubHex;
// keccak256 公钥并取地址
$hash = Keccak::hash(hex2bin($pubHexNoPrefix), 256); // 返回 hex
$address = '0x' . substr($hash, -40);
$staticCount=$staticCount+1;
if (microtime(true) - $start_time >= 5) {
if($detailInfo){
echo "[Rat $cid] digged $staticCount address in past 5s \n";
}
$gd->count=$gd->count+$staticCount;
$staticCount=0;
$start_time = microtime(true);
}
// 检查末尾连续相同字符(只检查尾部连续段)
$addrRaw = strtolower(substr($address, 2)); // 纯 hex40 chars
$len = strlen($addrRaw);
$lastChar = $addrRaw[$len - 1];
$count = 1;
for ($i = $len - 2; $i >= 0; $i--) {
if ($addrRaw[$i] === $lastChar) $count++;
else break;
}
// 如果满足重复数量,并且(可选)最后字符为数字
if ($count >= $minRepeat) {
if ($requireNumeric && !ctype_digit($lastChar)) {
// 不满足数字要求,继续
} else {
// 匹配成功 —— 调用 scanwallet 并记录(但不退出,继续寻找)
try {
// 记录到控制台(便于监控)
if($detailInfo){
echo " [Rat $cid] PID={$pid} 找到匹配地址 {$address} (尾部 {$count} 个 '{$lastChar}'), 调用 scanwallet\n";
}
$gd->scount=$gd->scount+1;
// 可选:把结果也写入一个单独的结果文件(便于批处理)
$result = [
'pid' => $pid,
'private_key' => $privHex,
'address' => $address,
'repeat_char' => $lastChar,
'repeat_count' => $count,
'timestamp' => date('c'),
'count'=> $count,
'char'=> $lastChar,
];
// 调用用户实现的扫描函数(可能阻塞当前进程)
# toCache($result);
/**
// 追加到 found.log同 scanwallet 中的 global logfile
global $logFile;
file_put_contents($logFile, json_encode($result, JSON_UNESCAPED_SLASHES) . PHP_EOL, FILE_APPEND | LOCK_EX);
*/
// 继续寻找(不要退出)
} catch (Throwable $t) {
// 避免 scanwallet 中的异常导致进程崩溃
if($detailInfo){
echo "PID={$pid} scanwallet 抛出异常: " . $t->getMessage() . "\n";
}
}
}
}
// 若想降低 CPU 占用可在这里加短暂 sleep但会降低查找速度
// usleep(0); // 等同于 yield
}
if($detailInfo){
echo "PID={$pid} 退出循环(理论上不应到达)\n";
}
};
$Rat->onWorkerStop = function($Rat) {
$pid = posix_getpid();
$cid=$pid-$GLOBALS['mainid'];
echo "[Rat $cid]启动 PID={$pid} 已终止\n";
};
$Static = new Worker();
$Static->name='Static Server';
$Static->onWorkerStart = function($Static)use($staticSecond,$detailInfo) {
$GLOBALS['starttime']=microtime(true);
$GLOBALS['lc']=0;
$GLOBALS['lsc']=0;
Timer::add($staticSecond, function()use($staticSecond,$detailInfo){
$gda = new \GlobalData\Client('127.0.0.1:2207');
$staticCount=$gda->count;
$avgCount=($staticCount-$GLOBALS['lc'])/$staticSecond;
$successCount=$gda->scount;
$avgsCount=($successCount-$GLOBALS['lsc']);
$totalSpeed= ($successCount / (microtime(true)-$GLOBALS['starttime'])) * 3600;
$running=formatSeconds(microtime(true)-$GLOBALS['starttime']);
if(!$detailInfo){
echo "\033[H"; // 光标回到左上角
echo "\033[J";
echo "
.88888. dP dP 888888ba dP
d8' `88 88 88 88 `8b 88
88 .d8888b. 88 .d888b88 a88aaaa8P' .d8888b. d8888P
88 YP88 88' `88 88 88' `88 88 `8b. 88' `88 88
Y8. .88 88. .88 88 88. .88 88 88 88. .88 88
`88888' `88888P' dP `88888P8 dP dP `88888P8 dP
====================================================
|| Gold Rat v".GR_VERSION." Build ".GR_BUILD." ||
||Dig out wallet address with the beautiful number||
|| As well as a CPU Benchmark tool ||
====================================================
";
}
echo "[STATIC] in last $staticSecond s:
Avg: $avgCount adds/s, Total: $staticCount adds
Succeed: $avgsCount adds, Total: $successCount adds
Total Diging Speed: $totalSpeed adds/hour
Total Runing Time: $running
====================================================
Enter Ctrl+C to Exit.
————————————————————————————————————————————————————
©Gold Rat by LayFi.de
\n";
$GLOBALS['lc']=$staticCount;
$GLOBALS['lsc']=$successCount;
});
};
Worker::runAll();

36
helper.php Normal file
View File

@ -0,0 +1,36 @@
<?php
function cpu_count(): int
{
// Windows does not support the number of processes setting.
if (DIRECTORY_SEPARATOR === '\\') {
return 1;
}
$count = 4;
if (is_callable('shell_exec')) {
if (strtolower(PHP_OS) === 'darwin') {
$count = (int)shell_exec('sysctl -n machdep.cpu.core_count');
} else {
try {
$count = (int)shell_exec('nproc');
} catch (\Throwable $ex) {
// Do nothing
}
}
}
return $count > 0 ? $count : 4;
}
function formatSeconds($seconds) {
$days = floor($seconds / 86400);
$hours = floor(($seconds % 86400) / 3600);
$minutes = floor(($seconds % 3600) / 60);
$secs = $seconds % 60;
$result = '';
if ($days > 0) $result .= $days."D ";
if ($hours > 0) $result .= $hours."H ";
if ($minutes > 0) $result .= $minutes."M ";
if ($secs > 0 || $result === '') $result .= $secs."S";
return $result;
}

16
readme.md Normal file
View File

@ -0,0 +1,16 @@
```
.88888. dP dP 888888ba dP
d8' `88 88 88 88 `8b 88
88 .d8888b. 88 .d888b88 a88aaaa8P' .d8888b. d8888P
88 YP88 88' `88 88 88' `88 88 `8b. 88' `88 88
Y8. .88 88. .88 88 88. .88 88 88 88. .88 88
`88888' `88888P' dP `88888P8 dP dP `88888P8 dP
```
# GOLD RAT
## What is Gold Rat?
---
---

0
start.php Normal file
View File

4
toCache.php Normal file
View File

@ -0,0 +1,4 @@
<?php
function toCache($result){
}

25
vendor/autoload.php vendored Normal file
View File

@ -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();

579
vendor/composer/ClassLoader.php vendored Normal file
View File

@ -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
vendor/composer/InstalledVersions.php vendored Normal file
View File

@ -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;
}
}

21
vendor/composer/LICENSE vendored Normal file
View File

@ -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
vendor/composer/autoload_classmap.php vendored Normal file
View File

@ -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',
);

10
vendor/composer/autoload_files.php vendored Normal file
View File

@ -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',
);

View File

@ -0,0 +1,9 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);

16
vendor/composer/autoload_psr4.php vendored Normal file
View File

@ -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'),
);

50
vendor/composer/autoload_real.php vendored Normal file
View File

@ -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;
}
}

85
vendor/composer/autoload_static.php vendored Normal file
View File

@ -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);
}
}

405
vendor/composer/installed.json vendored Normal file
View File

@ -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": []
}

86
vendor/composer/installed.php vendored Normal file
View File

@ -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,
),
),
);

26
vendor/composer/platform_check.php vendored Normal file
View File

@ -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
);
}

View File

@ -0,0 +1,3 @@
service_name: travis-ci
coverage_clover: build/logs/clover.xml
json_path: coveralls-upload.json

10
vendor/kornrunner/keccak/.gitignore vendored Normal file
View File

@ -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

23
vendor/kornrunner/keccak/.travis.yml vendored Normal file
View File

@ -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

21
vendor/kornrunner/keccak/LICENSE vendored Normal file
View File

@ -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.

32
vendor/kornrunner/keccak/README.md vendored Normal file
View File

@ -0,0 +1,32 @@
# php-keccak [![Build Status](https://travis-ci.org/kornrunner/php-keccak.svg?branch=master)](https://travis-ci.org/kornrunner/php-keccak) [![Build status](https://ci.appveyor.com/api/projects/status/48isd8g6gov29wba/branch/master?svg=true)](https://ci.appveyor.com/project/kornrunner/php-keccak/branch/master) [![Coverage Status](https://coveralls.io/repos/github/kornrunner/php-keccak/badge.svg?branch=master)](https://coveralls.io/github/kornrunner/php-keccak?branch=master) [![Latest Stable Version](https://poser.pugx.org/kornrunner/keccak/v/stable)](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
```
[![Ethereum](https://user-images.githubusercontent.com/725986/61891022-0d0c7f00-af09-11e9-829f-096c039bbbfa.png) 0x9c7b7a00972121fb843af7af74526d7eb585b171][Ethereum]
[Ethereum]: https://etherscan.io/address/0x9c7b7a00972121fb843af7af74526d7eb585b171 "Donate with Ethereum"

48
vendor/kornrunner/keccak/appveyor.yml vendored Normal file
View File

@ -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
vendor/kornrunner/keccak/composer.json vendored Normal file
View File

@ -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
vendor/kornrunner/keccak/composer.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
{
"timeout": 10,
"source": {
"directories": [
"src"
]
},
"logs": {
"text": "infection.log"
},
"mutators": {
"@default": true
}
}

View File

@ -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
vendor/kornrunner/keccak/src/Keccak.php vendored Normal file
View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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

View File

@ -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/"
}
}
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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();

View File

@ -0,0 +1,6 @@
<?php
define('S_MATH_BIGINTEGER_MODE', "bcmath");
require(__DIR__ . "/../lib/BigInteger.php");
require(__DIR__ . "/test.php");

View File

@ -0,0 +1,6 @@
<?php
define('S_MATH_BIGINTEGER_MODE', "gmp");
require(__DIR__ . "/../lib/BigInteger.php");
require(__DIR__ . "/test.php");

4
vendor/simplito/bn-php/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/vendor/
.settings
.project
.buildpath

23
vendor/simplito/bn-php/LICENSE.md vendored Normal file
View File

@ -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.

17
vendor/simplito/bn-php/README.md vendored Normal file
View File

@ -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
```

23
vendor/simplito/bn-php/composer.json vendored Normal file
View File

@ -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/"
}
}
}

768
vendor/simplito/bn-php/lib/BN.php vendored Normal file
View File

@ -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";

221
vendor/simplito/bn-php/lib/Red.php vendored Normal file
View File

@ -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";
?>

View File

@ -0,0 +1,8 @@
.vscode
/vendor/
node_modules
composer.lock
.project
.settings
.buildpath
/.idea

23
vendor/simplito/elliptic-php/LICENSE.md vendored Normal file
View File

@ -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
vendor/simplito/elliptic-php/Makefile vendored Normal file
View File

@ -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
vendor/simplito/elliptic-php/README.md vendored Normal file
View File

@ -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

View File

@ -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");
}
}

View File

@ -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"
}
}

View File

@ -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");
}
}
?>

View File

@ -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;
}
}
?>

View File

@ -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);
}
}

View File

@ -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); }
}

View File

@ -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);
}
}
?>

View File

@ -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();
}
}
?>

View File

@ -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;
}
}
?>

View File

@ -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);
}
}
?>

View File

@ -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();
}
}
?>

View File

@ -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);
}
}
?>

View File

@ -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
vendor/simplito/elliptic-php/lib/EC.php vendored Normal file
View File

@ -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");
}
}
?>

View File

@ -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];
}
}
?>

View File

@ -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);
}
}
?>

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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'));
}
}

View File

@ -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);
}
}
?>

View File

@ -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";
?>

View File

@ -0,0 +1,10 @@
{
"bootstrap": "vendor/autoload.php",
"path": "benchmarks",
"reports": {
"simple": {
"generator": "table",
"cols": ["subject", "mode", "rstdev", "its", "revs"]
}
}
}

View File

@ -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>

View File

@ -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');
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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');
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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"
}
]

File diff suppressed because it is too large Load Diff

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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).

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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
vendor/workerman/globaldata/README.md vendored Normal file
View File

@ -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);
```

View File

@ -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"}
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}
}

View File

@ -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";

Some files were not shown because too many files have changed in this diff Show More