init
This commit is contained in:
+144
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\EC;
|
||||
|
||||
use BN\BN;
|
||||
|
||||
class KeyPair
|
||||
{
|
||||
public $ec;
|
||||
public $pub;
|
||||
public $priv;
|
||||
|
||||
function __construct($ec, #[\SensitiveParameter]
|
||||
$options)
|
||||
{
|
||||
$this->ec = $ec;
|
||||
|
||||
$this->priv = null;
|
||||
$this->pub = null;
|
||||
|
||||
if( isset($options["priv"]) )
|
||||
$this->_importPrivate($options["priv"], $options["privEnc"]);
|
||||
|
||||
if( isset($options["pub"]) )
|
||||
$this->_importPublic($options["pub"], $options["pubEnc"]);
|
||||
}
|
||||
|
||||
public static function fromPublic($ec, $pub, $enc)
|
||||
{
|
||||
if( $pub instanceof KeyPair )
|
||||
return $pub;
|
||||
|
||||
return new KeyPair($ec, array(
|
||||
"pub" => $pub,
|
||||
"pubEnc" => $enc
|
||||
));
|
||||
}
|
||||
|
||||
public static function fromPrivate($ec, #[\SensitiveParameter]
|
||||
$priv, $enc)
|
||||
{
|
||||
if( $priv instanceof KeyPair )
|
||||
return $priv;
|
||||
|
||||
return new KeyPair($ec, array(
|
||||
"priv" => $priv,
|
||||
"privEnc" => $enc
|
||||
));
|
||||
}
|
||||
|
||||
public function validate()
|
||||
{
|
||||
$pub = $this->getPublic();
|
||||
|
||||
if( $pub->isInfinity() )
|
||||
return array( "result" => false, "reason" => "Invalid public key" );
|
||||
|
||||
if( !$pub->validate() )
|
||||
return array( "result" => false, "reason" => "Public key is not a point" );
|
||||
|
||||
if( !$pub->mul($this->ec->curve->n)->isInfinity() )
|
||||
return array( "result" => false, "reason" => "Public key * N != O" );
|
||||
|
||||
return array( "result" => true, "reason" => null );
|
||||
}
|
||||
|
||||
public function getPublic($compact = false, $enc = "")
|
||||
{
|
||||
//compact is optional argument
|
||||
if( is_string($compact) )
|
||||
{
|
||||
$enc = $compact;
|
||||
$compact = false;
|
||||
}
|
||||
|
||||
if( $this->pub === null )
|
||||
$this->pub = $this->ec->g->mul($this->priv);
|
||||
|
||||
if( !$enc )
|
||||
return $this->pub;
|
||||
|
||||
return $this->pub->encode($enc, $compact);
|
||||
}
|
||||
|
||||
public function getPrivate($enc = false)
|
||||
{
|
||||
if( $enc === "hex" )
|
||||
return $this->priv->toString(16, 2);
|
||||
|
||||
return $this->priv;
|
||||
}
|
||||
|
||||
private function _importPrivate(#[\SensitiveParameter]
|
||||
$key, $enc)
|
||||
{
|
||||
$this->priv = new BN($key, (isset($enc) && $enc) ? $enc : 16);
|
||||
|
||||
// Ensure that the priv won't be bigger than n, otherwise we may fail
|
||||
// in fixed multiplication method
|
||||
$this->priv = $this->priv->umod($this->ec->curve->n);
|
||||
}
|
||||
|
||||
private function _importPublic($key, $enc)
|
||||
{
|
||||
$x = $y = null;
|
||||
if ( is_object($key) ) {
|
||||
$x = $key->x;
|
||||
$y = $key->y;
|
||||
} elseif ( is_array($key) ) {
|
||||
$x = isset($key["x"]) ? $key["x"] : null;
|
||||
$y = isset($key["y"]) ? $key["y"] : null;
|
||||
}
|
||||
|
||||
if( $x != null || $y != null )
|
||||
$this->pub = $this->ec->curve->point($x, $y);
|
||||
else
|
||||
$this->pub = $this->ec->curve->decodePoint($key, $enc);
|
||||
}
|
||||
|
||||
//ECDH
|
||||
public function derive($pub) {
|
||||
return $pub->mul($this->priv)->getX();
|
||||
}
|
||||
|
||||
//ECDSA
|
||||
public function sign($msg, $enc = false, $options = false) {
|
||||
return $this->ec->sign($msg, $this, $enc, $options);
|
||||
}
|
||||
|
||||
public function verify($msg, $signature) {
|
||||
return $this->ec->verify($msg, $signature, $this);
|
||||
}
|
||||
|
||||
public function inspect() {
|
||||
return "<Key priv: " . (isset($this->priv) ? $this->priv->toString(16, 2) : "") .
|
||||
" pub: " . (isset($this->pub) ? $this->pub->inspect() : "") . ">";
|
||||
}
|
||||
|
||||
public function __debugInfo() {
|
||||
return ["priv" => $this->priv, "pub" => $this->pub];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\EC;
|
||||
|
||||
use Elliptic\Utils;
|
||||
use BN\BN;
|
||||
|
||||
class Signature
|
||||
{
|
||||
public $r;
|
||||
public $s;
|
||||
public $recoveryParam;
|
||||
|
||||
function __construct($options, $enc = false)
|
||||
{
|
||||
if ($options instanceof Signature) {
|
||||
$this->r = $options->r;
|
||||
$this->s = $options->s;
|
||||
$this->recoveryParam = $options->recoveryParam;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($options['r'])) {
|
||||
assert(isset($options["r"]) && isset($options["s"])); //, "Signature without r or s");
|
||||
$this->r = new BN($options["r"], 16);
|
||||
$this->s = new BN($options["s"], 16);
|
||||
|
||||
if( isset($options["recoveryParam"]) )
|
||||
$this->recoveryParam = $options["recoveryParam"];
|
||||
else
|
||||
$this->recoveryParam = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->_importDER($options, $enc))
|
||||
throw new \Exception('Unknown signature format');
|
||||
|
||||
}
|
||||
|
||||
private static function getLength($buf, &$pos)
|
||||
{
|
||||
$initial = $buf[$pos++];
|
||||
if( !($initial & 0x80) )
|
||||
return $initial;
|
||||
|
||||
$octetLen = $initial & 0xf;
|
||||
$val = 0;
|
||||
for($i = 0; $i < $octetLen; $i++)
|
||||
{
|
||||
$val = $val << 8;
|
||||
$val = $val | $buf[$pos];
|
||||
$pos++;
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
|
||||
private static function rmPadding(&$buf)
|
||||
{
|
||||
$i = 0;
|
||||
$len = count($buf) - 1;
|
||||
while($i < $len && !$buf[$i] && !($buf[$i+1] & 0x80) )
|
||||
$i++;
|
||||
|
||||
if( $i === 0 )
|
||||
return $buf;
|
||||
|
||||
return array_slice($buf, $i);
|
||||
}
|
||||
|
||||
private function _importDER($data, $enc)
|
||||
{
|
||||
$data = Utils::toArray($data, $enc);
|
||||
$dataLen = count($data);
|
||||
$place = 0;
|
||||
|
||||
if( $data[$place++] !== 0x30)
|
||||
return false;
|
||||
|
||||
$len = self::getLength($data, $place);
|
||||
if( ($len + $place) !== $dataLen )
|
||||
return false;
|
||||
|
||||
if( $data[$place++] !== 0x02 )
|
||||
return false;
|
||||
|
||||
$rlen = self::getLength($data, $place);
|
||||
$r = array_slice($data, $place, $rlen);
|
||||
$place += $rlen;
|
||||
|
||||
if( $data[$place++] !== 0x02 )
|
||||
return false;
|
||||
|
||||
$slen = self::getLength($data, $place);
|
||||
if( $dataLen !== $slen + $place )
|
||||
return false;
|
||||
$s = array_slice($data, $place, $slen);
|
||||
|
||||
if( $r[0] === 0 && ($r[1] & 0x80 ) )
|
||||
$r = array_slice($r, 1);
|
||||
if( $s[0] === 0 && ($s[1] & 0x80 ) )
|
||||
$s = array_slice($s, 1);
|
||||
|
||||
$this->r = new BN($r);
|
||||
$this->s = new BN($s);
|
||||
$this->recoveryParam = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function constructLength(&$arr, $len)
|
||||
{
|
||||
if( $len < 0x80 )
|
||||
{
|
||||
array_push($arr, $len);
|
||||
return;
|
||||
}
|
||||
|
||||
$octets = 1 + (log($len) / M_LN2 >> 3);
|
||||
array_push($arr, $octets | 0x80);
|
||||
while(--$octets)
|
||||
array_push($arr, ($len >> ($octets << 3)) & 0xff);
|
||||
array_push($arr, $len);
|
||||
}
|
||||
|
||||
public function toDER($enc = false)
|
||||
{
|
||||
$r = $this->r->toArray();
|
||||
$s = $this->s->toArray();
|
||||
|
||||
//Pad values
|
||||
if( $r[0] & 0x80 )
|
||||
array_unshift($r, 0);
|
||||
if( $s[0] & 0x80 )
|
||||
array_unshift($s, 0);
|
||||
|
||||
$r = self::rmPadding($r);
|
||||
$s = self::rmPadding($s);
|
||||
|
||||
while(!$s[0] && !($s[1] & 0x80))
|
||||
array_slice($s, 1);
|
||||
|
||||
$arr = array(0x02);
|
||||
self::constructLength($arr, count($r));
|
||||
$arr = array_merge($arr, $r, array(0x02));
|
||||
self::constructLength($arr, count($s));
|
||||
$backHalf = array_merge($arr, $s);
|
||||
$res = array(0x30);
|
||||
self::constructLength($res, count($backHalf));
|
||||
$res = array_merge($res, $backHalf);
|
||||
|
||||
return Utils::encode($res, $enc);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user