init
This commit is contained in:
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
use Elliptic\Utils;
|
||||
use \Exception;
|
||||
use BN\BN;
|
||||
|
||||
abstract class BaseCurve
|
||||
{
|
||||
public $type;
|
||||
public $p;
|
||||
public $red;
|
||||
public $zero;
|
||||
public $one;
|
||||
public $two;
|
||||
public $n;
|
||||
public $g;
|
||||
protected $_wnafT1;
|
||||
protected $_wnafT2;
|
||||
protected $_wnafT3;
|
||||
protected $_wnafT4;
|
||||
public $redN;
|
||||
public $_maxwellTrick;
|
||||
|
||||
function __construct($type, $conf)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->p = new BN($conf["p"], 16);
|
||||
|
||||
//Use Montgomery, when there is no fast reduction for the prime
|
||||
$this->red = isset($conf["prime"]) ? BN::red($conf["prime"]) : BN::mont($this->p);
|
||||
|
||||
//Useful for many curves
|
||||
$this->zero = (new BN(0))->toRed($this->red);
|
||||
$this->one = (new BN(1))->toRed($this->red);
|
||||
$this->two = (new BN(2))->toRed($this->red);
|
||||
|
||||
//Curve configuration, optional
|
||||
$this->n = isset($conf["n"]) ? new BN($conf["n"], 16) : null;
|
||||
$this->g = isset($conf["g"]) ? $this->pointFromJSON($conf["g"], isset($conf["gRed"]) ? $conf["gRed"] : null) : null;
|
||||
|
||||
//Temporary arrays
|
||||
$this->_wnafT1 = array(0,0,0,0);
|
||||
$this->_wnafT2 = array(0,0,0,0);
|
||||
$this->_wnafT3 = array(0,0,0,0);
|
||||
$this->_wnafT4 = array(0,0,0,0);
|
||||
|
||||
//Generalized Greg Maxwell's trick
|
||||
$adjustCount = $this->n != null ? $this->p->div($this->n) : null;
|
||||
if( $adjustCount == null || $adjustCount->cmpn(100) > 0 )
|
||||
{
|
||||
$this->redN = null;
|
||||
$this->_maxwellTrick = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->redN = $this->n->toRed($this->red);
|
||||
$this->_maxwellTrick = true;
|
||||
}
|
||||
}
|
||||
|
||||
abstract public function point($x, $z);
|
||||
abstract public function validate($point);
|
||||
|
||||
public function _fixedNafMul($p, $k)
|
||||
{
|
||||
assert(isset($p->precomputed));
|
||||
|
||||
$doubles = $p->_getDoubles();
|
||||
$naf = Utils::getNAF($k, 1);
|
||||
$I = (1 << ($doubles["step"] + 1)) - ($doubles["step"] % 2 == 0 ? 2 : 1);
|
||||
$I = $I / 3;
|
||||
|
||||
//Translate to more windowed form
|
||||
$repr = array();
|
||||
for($j = 0; $j < count($naf); $j += $doubles["step"])
|
||||
{
|
||||
$nafW = 0;
|
||||
for($k = $j + $doubles["step"] - 1; $k >= $j; $k--)
|
||||
$nafW = ($nafW << 1) + (isset($naf[$k]) ? $naf[$k] : 0);
|
||||
array_push($repr, $nafW);
|
||||
}
|
||||
|
||||
$a = $this->jpoint(null, null, null);
|
||||
$b = $this->jpoint(null, null, null);
|
||||
|
||||
for($i = $I; $i > 0; $i--)
|
||||
{
|
||||
for($j = 0; $j < count($repr); $j++)
|
||||
{
|
||||
$nafW = $repr[$j];
|
||||
if ($nafW == $i) {
|
||||
$b = $b->mixedAdd($doubles["points"][$j]);
|
||||
} else if($nafW == -$i) {
|
||||
$b = $b->mixedAdd($doubles["points"][$j]->neg());
|
||||
}
|
||||
}
|
||||
$a = $a->add($b);
|
||||
}
|
||||
|
||||
return $a->toP();
|
||||
}
|
||||
|
||||
public function _wnafMul($p, $k)
|
||||
{
|
||||
$w = 4;
|
||||
|
||||
//Precompute window
|
||||
$nafPoints = $p->_getNAFPoints($w);
|
||||
$w = $nafPoints["wnd"];
|
||||
$wnd = $nafPoints["points"];
|
||||
|
||||
//Get NAF form
|
||||
$naf = Utils::getNAF($k, $w);
|
||||
|
||||
//Add `this`*(N+1) for every w-NAF index
|
||||
$acc = $this->jpoint(null, null, null);
|
||||
for($i = count($naf) - 1; $i >= 0; $i--)
|
||||
{
|
||||
//Count zeros
|
||||
for($k = 0; $i >= 0 && $naf[$i] == 0; $i--)
|
||||
$k++;
|
||||
|
||||
if($i >= 0)
|
||||
$k++;
|
||||
$acc = $acc->dblp($k);
|
||||
|
||||
if($i < 0)
|
||||
break;
|
||||
$z = $naf[$i];
|
||||
|
||||
assert($z != 0);
|
||||
|
||||
if( $p->type == "affine" )
|
||||
{
|
||||
//J +- P
|
||||
if( $z > 0 )
|
||||
$acc = $acc->mixedAdd($wnd[($z - 1) >> 1]);
|
||||
else
|
||||
$acc = $acc->mixedAdd($wnd[(-$z - 1) >> 1]->neg());
|
||||
}
|
||||
else
|
||||
{
|
||||
//J +- J
|
||||
if( $z > 0 )
|
||||
$acc = $acc->add($wnd[($z - 1) >> 1]);
|
||||
else
|
||||
$acc = $acc->add($wnd[(-$z - 1) >> 1]->neg());
|
||||
}
|
||||
}
|
||||
return $p->type == "affine" ? $acc->toP() : $acc;
|
||||
}
|
||||
|
||||
public function _wnafMulAdd($defW, $points, $coeffs, $len, $jacobianResult = false)
|
||||
{
|
||||
$wndWidth = &$this->_wnafT1;
|
||||
$wnd = &$this->_wnafT2;
|
||||
$naf = &$this->_wnafT3;
|
||||
|
||||
//Fill all arrays
|
||||
$max = 0;
|
||||
for($i = 0; $i < $len; $i++)
|
||||
{
|
||||
$p = $points[$i];
|
||||
$nafPoints = $p->_getNAFPoints($defW);
|
||||
$wndWidth[$i] = $nafPoints["wnd"];
|
||||
$wnd[$i] = $nafPoints["points"];
|
||||
}
|
||||
//Comb all window NAFs
|
||||
for($i = $len - 1; $i >= 1; $i -= 2)
|
||||
{
|
||||
$a = $i - 1;
|
||||
$b = $i;
|
||||
if( $wndWidth[$a] != 1 || $wndWidth[$b] != 1 )
|
||||
{
|
||||
$naf[$a] = Utils::getNAF($coeffs[$a], $wndWidth[$a]);
|
||||
$naf[$b] = Utils::getNAF($coeffs[$b], $wndWidth[$b]);
|
||||
$max = max(count($naf[$a]), $max);
|
||||
$max = max(count($naf[$b]), $max);
|
||||
continue;
|
||||
}
|
||||
|
||||
$comb = array(
|
||||
$points[$a], /* 1 */
|
||||
null, /* 3 */
|
||||
null, /* 5 */
|
||||
$points[$b] /* 7 */
|
||||
);
|
||||
|
||||
//Try to avoid Projective points, if possible
|
||||
if( $points[$a]->y->cmp($points[$b]->y) == 0 )
|
||||
{
|
||||
$comb[1] = $points[$a]->add($points[$b]);
|
||||
$comb[2] = $points[$a]->toJ()->mixedAdd($points[$b]->neg());
|
||||
}
|
||||
elseif( $points[$a]->y->cmp($points[$b]->y->redNeg()) == 0 )
|
||||
{
|
||||
$comb[1] = $points[$a]->toJ()->mixedAdd($points[$b]);
|
||||
$comb[2] = $points[$a]->add($points[$b]->neg());
|
||||
}
|
||||
else
|
||||
{
|
||||
$comb[1] = $points[$a]->toJ()->mixedAdd($points[$b]);
|
||||
$comb[2] = $points[$a]->toJ()->mixedAdd($points[$b]->neg());
|
||||
}
|
||||
|
||||
$index = array(
|
||||
-3, /* -1 -1 */
|
||||
-1, /* -1 0 */
|
||||
-5, /* -1 1 */
|
||||
-7, /* 0 -1 */
|
||||
0, /* 0 0 */
|
||||
7, /* 0 1 */
|
||||
5, /* 1 -1 */
|
||||
1, /* 1 0 */
|
||||
3 /* 1 1 */
|
||||
);
|
||||
|
||||
$jsf = Utils::getJSF($coeffs[$a], $coeffs[$b]);
|
||||
$max = max(count($jsf[0]), $max);
|
||||
if ($max > 0) {
|
||||
$naf[$a] = array_fill(0, $max, 0);
|
||||
$naf[$b] = array_fill(0, $max, 0);
|
||||
} else {
|
||||
$naf[$a] = [];
|
||||
$naf[$b] = [];
|
||||
}
|
||||
|
||||
for($j = 0; $j < $max; $j++)
|
||||
{
|
||||
$ja = isset($jsf[0][$j]) ? $jsf[0][$j] : 0;
|
||||
$jb = isset($jsf[1][$j]) ? $jsf[1][$j] : 0;
|
||||
|
||||
$naf[$a][$j] = $index[($ja + 1) * 3 + ($jb + 1)];
|
||||
$naf[$b][$j] = 0;
|
||||
$wnd[$a] = $comb;
|
||||
}
|
||||
}
|
||||
|
||||
$acc = $this->jpoint(null, null, null);
|
||||
$tmp = &$this->_wnafT4;
|
||||
for($i = $max; $i >= 0; $i--)
|
||||
{
|
||||
$k = 0;
|
||||
|
||||
while($i >= 0)
|
||||
{
|
||||
$zero = true;
|
||||
for($j = 0; $j < $len; $j++)
|
||||
{
|
||||
$tmp[$j] = isset($naf[$j][$i]) ? $naf[$j][$i] : 0;
|
||||
if( $tmp[$j] != 0 )
|
||||
$zero = false;
|
||||
}
|
||||
if( !$zero )
|
||||
break;
|
||||
$k++;
|
||||
$i--;
|
||||
}
|
||||
|
||||
if( $i >=0 )
|
||||
$k++;
|
||||
|
||||
$acc = $acc->dblp($k);
|
||||
if( $i < 0 )
|
||||
break;
|
||||
|
||||
for($j = 0; $j < $len; $j++)
|
||||
{
|
||||
$z = $tmp[$j];
|
||||
$p = null;
|
||||
if( $z == 0 )
|
||||
continue;
|
||||
elseif( $z > 0 )
|
||||
$p = $wnd[$j][($z - 1) >> 1];
|
||||
elseif( $z < 0 )
|
||||
$p = $wnd[$j][(-$z - 1) >> 1]->neg();
|
||||
|
||||
if( $p->type == "affine" )
|
||||
$acc = $acc->mixedAdd($p);
|
||||
else
|
||||
$acc = $acc->add($p);
|
||||
}
|
||||
}
|
||||
|
||||
//Zeroify references
|
||||
for($i = 0; $i < $len; $i++)
|
||||
$wnd[$i] = null;
|
||||
|
||||
if( $jacobianResult )
|
||||
return $acc;
|
||||
else
|
||||
return $acc->toP();
|
||||
}
|
||||
|
||||
public function decodePoint($bytes, $enc = false)
|
||||
{
|
||||
$bytes = Utils::toArray($bytes, $enc);
|
||||
$len = $this->p->byteLength();
|
||||
|
||||
$count = count($bytes);
|
||||
//uncompressed, hybrid-odd, hybrid-even
|
||||
if(($bytes[0] == 0x04 || $bytes[0] == 0x06 || $bytes[0] == 0x07) && ($count - 1) == (2 * $len) )
|
||||
{
|
||||
if( $bytes[0] == 0x06 )
|
||||
assert($bytes[$count - 1] % 2 == 0);
|
||||
elseif( $bytes[0] == 0x07 )
|
||||
assert($bytes[$count - 1] % 2 == 1);
|
||||
|
||||
return $this->point(array_slice($bytes, 1, $len), array_slice($bytes, 1 + $len, $len));
|
||||
}
|
||||
|
||||
if( ($bytes[0] == 0x02 || $bytes[0] == 0x03) && ($count - 1) == $len )
|
||||
return $this->pointFromX(array_slice($bytes, 1, $len), $bytes[0] == 0x03);
|
||||
|
||||
throw new Exception("Unknown point format");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve\BaseCurve;
|
||||
|
||||
use Elliptic\Utils;
|
||||
|
||||
abstract class Point
|
||||
{
|
||||
public $curve;
|
||||
public $type;
|
||||
public $precomputed;
|
||||
|
||||
function __construct($curve, $type)
|
||||
{
|
||||
$this->curve = $curve;
|
||||
$this->type = $type;
|
||||
$this->precomputed = null;
|
||||
}
|
||||
|
||||
abstract public function eq($other);
|
||||
|
||||
public function validate() {
|
||||
return $this->curve->validate($this);
|
||||
}
|
||||
|
||||
public function encodeCompressed($enc) {
|
||||
return $this->encode($enc, true);
|
||||
}
|
||||
|
||||
public function encode($enc, $compact = false) {
|
||||
return Utils::encode($this->_encode($compact), $enc);
|
||||
}
|
||||
|
||||
protected function _encode($compact)
|
||||
{
|
||||
$len = $this->curve->p->byteLength();
|
||||
$x = $this->getX()->toArray("be", $len);
|
||||
|
||||
if( $compact )
|
||||
{
|
||||
array_unshift($x, ($this->getY()->isEven() ? 0x02 : 0x03));
|
||||
return $x;
|
||||
}
|
||||
|
||||
return array_merge(array(0x04), $x, $this->getY()->toArray("be", $len));
|
||||
}
|
||||
|
||||
public function precompute($power = null)
|
||||
{
|
||||
if( isset($this->precomputed) )
|
||||
return $this;
|
||||
|
||||
$this->precomputed = array(
|
||||
"naf" => $this->_getNAFPoints(8),
|
||||
"doubles" => $this->_getDoubles(4, $power),
|
||||
"beta" => $this->_getBeta()
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function _hasDoubles($k)
|
||||
{
|
||||
if( !isset($this->precomputed) || !isset($this->precomputed["doubles"]) )
|
||||
return false;
|
||||
|
||||
return count($this->precomputed["doubles"]["points"]) >= ceil(($k->bitLength() + 1) / $this->precomputed["doubles"]["step"]);
|
||||
}
|
||||
|
||||
public function _getDoubles($step = null, $power = null)
|
||||
{
|
||||
if( isset($this->precomputed) && isset($this->precomputed["doubles"]) )
|
||||
return $this->precomputed["doubles"];
|
||||
|
||||
$doubles = array( $this );
|
||||
$acc = $this;
|
||||
for($i = 0; $i < $power; $i += $step)
|
||||
{
|
||||
for($j = 0; $j < $step; $j++)
|
||||
$acc = $acc->dbl();
|
||||
array_push($doubles, $acc);
|
||||
}
|
||||
|
||||
return array(
|
||||
"step" => $step,
|
||||
"points" => $doubles
|
||||
);
|
||||
}
|
||||
|
||||
public function _getNAFPoints($wnd)
|
||||
{
|
||||
if( isset($this->precomputed) && isset($this->precomputed["naf"]) )
|
||||
return $this->precomputed["naf"];
|
||||
|
||||
$res = array( $this );
|
||||
$max = (1 << $wnd) - 1;
|
||||
$dbl = $max === 1 ? null : $this->dbl();
|
||||
for($i = 1; $i < $max; $i++)
|
||||
array_push($res, $res[$i - 1]->add($dbl));
|
||||
|
||||
return array(
|
||||
"wnd" => $wnd,
|
||||
"points" => $res
|
||||
);
|
||||
}
|
||||
|
||||
public function _getBeta() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function dblp($k)
|
||||
{
|
||||
$r = $this;
|
||||
for($i = 0; $i < $k; $i++)
|
||||
$r = $r->dbl();
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
use Elliptic\Curve\EdwardsCurve\Point;
|
||||
use Elliptic\Utils;
|
||||
use BN\BN;
|
||||
|
||||
class EdwardsCurve extends BaseCurve
|
||||
{
|
||||
public $twisted;
|
||||
public $mOneA;
|
||||
public $extended;
|
||||
public $a;
|
||||
public $c;
|
||||
public $c2;
|
||||
public $d;
|
||||
public $d2;
|
||||
public $dd;
|
||||
public $oneC;
|
||||
|
||||
function __construct($conf)
|
||||
{
|
||||
// NOTE: Important as we are creating point in Base.call()
|
||||
$this->twisted = ($conf["a"] | 0) != 1;
|
||||
$this->mOneA = $this->twisted && ($conf["a"] | 0) == -1;
|
||||
$this->extended = $this->mOneA;
|
||||
parent::__construct("edward", $conf);
|
||||
|
||||
$this->a = (new BN($conf["a"], 16))->umod($this->red->m);
|
||||
$this->a = $this->a->toRed($this->red);
|
||||
$this->c = (new BN($conf["c"], 16))->toRed($this->red);
|
||||
$this->c2 = $this->c->redSqr();
|
||||
$this->d = (new BN($conf["d"], 16))->toRed($this->red);
|
||||
$this->dd = $this->d->redAdd($this->d);
|
||||
if (Utils::$ASSERT_ENABLED) {
|
||||
assert(!$this->twisted || $this->c->fromRed()->cmpn(1) == 0);
|
||||
}
|
||||
$this->oneC = ($conf["c"] | 0) == 1;
|
||||
}
|
||||
|
||||
public function _mulA($num) {
|
||||
if ($this->mOneA)
|
||||
return $num->redNeg();
|
||||
else
|
||||
return $this->a->redMul($num);
|
||||
}
|
||||
|
||||
public function _mulC($num) {
|
||||
if ($this->oneC)
|
||||
return $num;
|
||||
else
|
||||
return $this->c->redMul($num);
|
||||
}
|
||||
|
||||
// Just for compatibility with Short curve
|
||||
public function jpoint($x, $y, $z, $t = null) {
|
||||
return $this->point($x, $y, $z, $t);
|
||||
}
|
||||
|
||||
public function pointFromX($x, $odd = false) {
|
||||
$x = new BN($x, 16);
|
||||
if (!$x->red)
|
||||
$x = $x->toRed($this->red);
|
||||
|
||||
$x2 = $x->redSqr();
|
||||
$rhs = $this->c2->redSub($this->a->redMul($x2));
|
||||
$lhs = $this->one->redSub($this->c2->redMul($this->d)->redMul($x2));
|
||||
|
||||
$y2 = $rhs->redMul($lhs->redInvm());
|
||||
$y = $y2->redSqrt();
|
||||
if ($y->redSqr()->redSub($y2)->cmp($this->zero) != 0)
|
||||
throw new \Exception('invalid point');
|
||||
|
||||
$isOdd = $y->fromRed()->isOdd();
|
||||
if ($odd && !$isOdd || !$odd && $isOdd)
|
||||
$y = $y->redNeg();
|
||||
|
||||
return $this->point($x, $y);
|
||||
}
|
||||
|
||||
public function pointFromY($y, $odd = false) {
|
||||
$y = new BN($y, 16);
|
||||
if (!$y->red)
|
||||
$y = $y->toRed($this->red);
|
||||
|
||||
// x^2 = (y^2 - 1) / (d y^2 + 1)
|
||||
$y2 = $y->redSqr();
|
||||
$lhs = $y2->redSub($this->one);
|
||||
$rhs = $y2->redMul($this->d)->redAdd($this->one);
|
||||
$x2 = $lhs->redMul($rhs->redInvm());
|
||||
|
||||
if ($x2->cmp($this->zero) == 0) {
|
||||
if ($odd)
|
||||
throw new \Exception('invalid point');
|
||||
else
|
||||
return $this->point($this->zero, $y);
|
||||
}
|
||||
|
||||
$x = $x2->redSqrt();
|
||||
if ($x->redSqr()->redSub($x2)->cmp($this->zero) != 0)
|
||||
throw new \Exception('invalid point');
|
||||
|
||||
if ($x->isOdd() != $odd)
|
||||
$x = $x->redNeg();
|
||||
|
||||
return $this->point($x, $y);
|
||||
}
|
||||
|
||||
public function validate($point) {
|
||||
if ($point->isInfinity())
|
||||
return true;
|
||||
|
||||
// Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2)
|
||||
$point->normalize();
|
||||
|
||||
$x2 = $point->x->redSqr();
|
||||
$y2 = $point->y->redSqr();
|
||||
$lhs = $x2->redMul($this->a)->redAdd($y2);
|
||||
$rhs = $this->c2->redMul($this->one->redAdd($this->d->redMul($x2)->redMul($y2)));
|
||||
|
||||
return $lhs->cmp($rhs) == 0;
|
||||
}
|
||||
|
||||
public function pointFromJSON($obj) {
|
||||
return Point::fromJSON($this, $obj);
|
||||
}
|
||||
|
||||
public function point($x = null, $y = null, $z = null, $t = null) {
|
||||
return new Point($this, $x, $y, $z, $t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
namespace Elliptic\Curve\EdwardsCurve;
|
||||
|
||||
use BN\BN;
|
||||
|
||||
class Point extends \Elliptic\Curve\BaseCurve\Point
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
public $z;
|
||||
public $t;
|
||||
public $zOne;
|
||||
|
||||
function __construct($curve, $x = null, $y = null, $z = null, $t = null) {
|
||||
parent::__construct($curve, 'projective');
|
||||
if ($x == null && $y == null && $z == null) {
|
||||
$this->x = $this->curve->zero;
|
||||
$this->y = $this->curve->one;
|
||||
$this->z = $this->curve->one;
|
||||
$this->t = $this->curve->zero;
|
||||
$this->zOne = true;
|
||||
} else {
|
||||
$this->x = new BN($x, 16);
|
||||
$this->y = new BN($y, 16);
|
||||
$this->z = $z ? new BN($z, 16) : $this->curve->one;
|
||||
$this->t = $t ? new BN($t, 16) : null;
|
||||
if (!$this->x->red)
|
||||
$this->x = $this->x->toRed($this->curve->red);
|
||||
if (!$this->y->red)
|
||||
$this->y = $this->y->toRed($this->curve->red);
|
||||
if (!$this->z->red)
|
||||
$this->z = $this->z->toRed($this->curve->red);
|
||||
if ($this->t && !$this->t->red)
|
||||
$this->t = $this->t->toRed($this->curve->red);
|
||||
$this->zOne = $this->z == $this->curve->one;
|
||||
|
||||
// Use extended coordinates
|
||||
if ($this->curve->extended && !$this->t) {
|
||||
$this->t = $this->x->redMul($this->y);
|
||||
if (!$this->zOne)
|
||||
$this->t = $this->t->redMul($this->z->redInvm());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromJSON($curve, $obj) {
|
||||
return new Point($curve,
|
||||
isset($obj[0]) ? $obj[0] : null,
|
||||
isset($obj[1]) ? $obj[1] : null,
|
||||
isset($obj[2]) ? $obj[2] : null
|
||||
);
|
||||
}
|
||||
|
||||
public function inspect() {
|
||||
if ($this->isInfinity())
|
||||
return '<EC Point Infinity>';
|
||||
return '<EC Point x: ' . $this->x->fromRed()->toString(16, 2) .
|
||||
' y: ' . $this->y->fromRed()->toString(16, 2) .
|
||||
' z: ' . $this->z->fromRed()->toString(16, 2) . '>';
|
||||
}
|
||||
|
||||
public function isInfinity() {
|
||||
// XXX This code assumes that zero is always zero in red
|
||||
return $this->x->cmpn(0) == 0 &&
|
||||
$this->y->cmp($this->z) == 0;
|
||||
}
|
||||
|
||||
public function _extDbl() {
|
||||
// hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
// #doubling-dbl-2008-hwcd
|
||||
// 4M + 4S
|
||||
|
||||
// A = X1^2
|
||||
$a = $this->x->redSqr();
|
||||
// B = Y1^2
|
||||
$b = $this->y->redSqr();
|
||||
// C = 2 * Z1^2
|
||||
$c = $this->z->redSqr();
|
||||
$c = $c->redIAdd($c);
|
||||
// D = a * A
|
||||
$d = $this->curve->_mulA($a);
|
||||
// E = (X1 + Y1)^2 - A - B
|
||||
$e = $this->x->redAdd($this->y)->redSqr()->redISub($a)->redISub($b);
|
||||
// G = D + B
|
||||
$g = $d->redAdd($b);
|
||||
// F = G - C
|
||||
$f = $g->redSub($c);
|
||||
// H = D - B
|
||||
$h = $d->redSub($b);
|
||||
// X3 = E * F
|
||||
$nx = $e->redMul($f);
|
||||
// Y3 = G * H
|
||||
$ny = $g->redMul($h);
|
||||
// T3 = E * H
|
||||
$nt = $e->redMul($h);
|
||||
// Z3 = F * G
|
||||
$nz = $f->redMul($g);
|
||||
return $this->curve->point($nx, $ny, $nz, $nt);
|
||||
}
|
||||
|
||||
public function _projDbl() {
|
||||
// hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
|
||||
// #doubling-dbl-2008-bbjlp
|
||||
// #doubling-dbl-2007-bl
|
||||
// and others
|
||||
// Generally 3M + 4S or 2M + 4S
|
||||
|
||||
// B = (X1 + Y1)^2
|
||||
$b = $this->x->redAdd($this->y)->redSqr();
|
||||
// C = X1^2
|
||||
$c = $this->x->redSqr();
|
||||
// D = Y1^2
|
||||
$d = $this->y->redSqr();
|
||||
|
||||
if ($this->curve->twisted) {
|
||||
// E = a * C
|
||||
$e = $this->curve->_mulA($c);
|
||||
// F = E + D
|
||||
$f = $e->redAdd($d);
|
||||
if ($this->zOne) {
|
||||
// X3 = (B - C - D) * (F - 2)
|
||||
$nx = $b->redSub($c)->redSub($d)->redMul($f->redSub($this->curve->two));
|
||||
// Y3 = F * (E - D)
|
||||
$ny = $f->redMul($e->redSub($d));
|
||||
// Z3 = F^2 - 2 * F
|
||||
$nz = $f->redSqr()->redSub($f)->redSub($f);
|
||||
} else {
|
||||
// H = Z1^2
|
||||
$h = $this->z->redSqr();
|
||||
// J = F - 2 * H
|
||||
$j = $f->redSub($h)->redISub($h);
|
||||
// X3 = (B-C-D)*J
|
||||
$nx = $b->redSub($c)->redISub($d)->redMul($j);
|
||||
// Y3 = F * (E - D)
|
||||
$ny = $f->redMul($e->redSub($d));
|
||||
// Z3 = F * J
|
||||
$nz = $f->redMul($j);
|
||||
}
|
||||
} else {
|
||||
// E = C + D
|
||||
$e = $c->redAdd($d);
|
||||
// H = (c * Z1)^2
|
||||
$h = $this->curve->_mulC($this->c->redMul($this->z))->redSqr();
|
||||
// J = E - 2 * H
|
||||
$j = $e->redSub($h)->redSub($h);
|
||||
// X3 = c * (B - E) * J
|
||||
$nx = $this->curve->_mulC($b->redISub($e))->redMul($j);
|
||||
// Y3 = c * E * (C - D)
|
||||
$ny = $this->curve->_mulC($e)->redMul($c->redISub($d));
|
||||
// Z3 = E * J
|
||||
$nz = $e->redMul($j);
|
||||
}
|
||||
return $this->curve->point($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function dbl() {
|
||||
if ($this->isInfinity())
|
||||
return $this;
|
||||
|
||||
// Double in extended coordinates
|
||||
if ($this->curve->extended)
|
||||
return $this->_extDbl();
|
||||
else
|
||||
return $this->_projDbl();
|
||||
}
|
||||
|
||||
public function _extAdd($p) {
|
||||
// hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
// #addition-add-2008-hwcd-3
|
||||
// 8M
|
||||
|
||||
// A = (Y1 - X1) * (Y2 - X2)
|
||||
$a = $this->y->redSub($this->x)->redMul($p->y->redSub($p->x));
|
||||
// B = (Y1 + X1) * (Y2 + X2)
|
||||
$b = $this->y->redAdd($this->x)->redMul($p->y->redAdd($p->x));
|
||||
// C = T1 * k * T2
|
||||
$c = $this->t->redMul($this->curve->dd)->redMul($p->t);
|
||||
// D = Z1 * 2 * Z2
|
||||
$d = $this->z->redMul($p->z->redAdd($p->z));
|
||||
// E = B - A
|
||||
$e = $b->redSub($a);
|
||||
// F = D - C
|
||||
$f = $d->redSub($c);
|
||||
// G = D + C
|
||||
$g = $d->redAdd($c);
|
||||
// H = B + A
|
||||
$h = $b->redAdd($a);
|
||||
// X3 = E * F
|
||||
$nx = $e->redMul($f);
|
||||
// Y3 = G * H
|
||||
$ny = $g->redMul($h);
|
||||
// T3 = E * H
|
||||
$nt = $e->redMul($h);
|
||||
// Z3 = F * G
|
||||
$nz = $f->redMul($g);
|
||||
return $this->curve->point($nx, $ny, $nz, $nt);
|
||||
}
|
||||
|
||||
public function _projAdd($p) {
|
||||
// hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
|
||||
// #addition-add-2008-bbjlp
|
||||
// #addition-add-2007-bl
|
||||
// 10M + 1S
|
||||
|
||||
// A = Z1 * Z2
|
||||
$a = $this->z->redMul($p->z);
|
||||
// B = A^2
|
||||
$b = $a->redSqr();
|
||||
// C = X1 * X2
|
||||
$c = $this->x->redMul($p->x);
|
||||
// D = Y1 * Y2
|
||||
$d = $this->y->redMul($p->y);
|
||||
// E = d * C * D
|
||||
$e = $this->curve->d->redMul($c)->redMul($d);
|
||||
// F = B - E
|
||||
$f = $b->redSub($e);
|
||||
// G = B + E
|
||||
$g = $b->redAdd($e);
|
||||
// X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D)
|
||||
$tmp = $this->x->redAdd($this->y)->redMul($p->x->redAdd($p->y))->redISub($c)->redISub($d);
|
||||
$nx = $a->redMul($f)->redMul($tmp);
|
||||
if ($this->curve->twisted) {
|
||||
// Y3 = A * G * (D - a * C)
|
||||
$ny = $a->redMul($g)->redMul($d->redSub($this->curve->_mulA($c)));
|
||||
// Z3 = F * G
|
||||
$nz = $f->redMul($g);
|
||||
} else {
|
||||
// Y3 = A * G * (D - C)
|
||||
$ny = $a->redMul($g)->redMul($d->redSub($c));
|
||||
// Z3 = c * F * G
|
||||
$nz = $this->curve->_mulC($f)->redMul($g);
|
||||
}
|
||||
return $this->curve->point($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function add($p) {
|
||||
if ($this->isInfinity())
|
||||
return $p;
|
||||
if ($p->isInfinity())
|
||||
return $this;
|
||||
|
||||
if ($this->curve->extended)
|
||||
return $this->_extAdd($p);
|
||||
else
|
||||
return $this->_projAdd($p);
|
||||
}
|
||||
|
||||
public function mul($k) {
|
||||
if ($this->_hasDoubles($k))
|
||||
return $this->curve->_fixedNafMul($this, $k);
|
||||
else
|
||||
return $this->curve->_wnafMul($this, $k);
|
||||
}
|
||||
|
||||
public function mulAdd($k1, $p, $k2) {
|
||||
return $this->curve->_wnafMulAdd(1, [ $this, $p ], [ $k1, $k2 ], 2, false);
|
||||
}
|
||||
|
||||
public function jmulAdd($k1, $p, $k2) {
|
||||
return $this->curve->_wnafMulAdd(1, [ $this, $p ], [ $k1, $k2 ], 2, true);
|
||||
}
|
||||
|
||||
public function normalize() {
|
||||
if ($this->zOne)
|
||||
return $this;
|
||||
|
||||
// Normalize coordinates
|
||||
$zi = $this->z->redInvm();
|
||||
$this->x = $this->x->redMul($zi);
|
||||
$this->y = $this->y->redMul($zi);
|
||||
if ($this->t)
|
||||
$this->t = $this->t->redMul($zi);
|
||||
$this->z = $this->curve->one;
|
||||
$this->zOne = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function neg() {
|
||||
return $this->curve->point($this->x->redNeg(),
|
||||
$this->y,
|
||||
$this->z,
|
||||
($this->t != null) ? $this->t->redNeg() : null);
|
||||
}
|
||||
|
||||
public function getX() {
|
||||
$this->normalize();
|
||||
return $this->x->fromRed();
|
||||
}
|
||||
|
||||
public function getY() {
|
||||
$this->normalize();
|
||||
return $this->y->fromRed();
|
||||
}
|
||||
|
||||
public function eq($other) {
|
||||
return $this == $other ||
|
||||
$this->getX()->cmp($other->getX()) == 0 &&
|
||||
$this->getY()->cmp($other->getY()) == 0;
|
||||
}
|
||||
|
||||
public function eqXToP($x) {
|
||||
$rx = $x->toRed($this->curve->red)->redMul($this->z);
|
||||
if ($this->x->cmp($rx) == 0)
|
||||
return true;
|
||||
|
||||
$xc = $x->_clone();
|
||||
$t = $this->curve->redN->redMul($this->z);
|
||||
for (;;) {
|
||||
$xc->iadd($this->curve->n);
|
||||
if ($xc->cmp($this->curve->p) >= 0)
|
||||
return false;
|
||||
|
||||
$rx->redIAdd($t);
|
||||
if ($this->x->cmp($rx) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compatibility with BaseCurve
|
||||
public function toP() { return $this->normalize(); }
|
||||
public function mixedAdd($p) { return $this->add($p); }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
use Elliptic\Curve\MontCurve\Point;
|
||||
use Elliptic\Utils;
|
||||
use BN\BN;
|
||||
|
||||
class MontCurve extends BaseCurve
|
||||
{
|
||||
public $a;
|
||||
public $b;
|
||||
public $i4;
|
||||
public $a24;
|
||||
|
||||
function __construct($conf)
|
||||
{
|
||||
parent::__construct("mont", $conf);
|
||||
|
||||
$this->a = (new BN($conf["a"], 16))->toRed($this->red);
|
||||
$this->b = (new BN($conf["b"], 16))->toRed($this->red);
|
||||
$this->i4 = (new BN(4))->toRed($this->red)->redInvm();
|
||||
$this->a24 = $this->i4->redMul($this->a->redAdd($this->two));
|
||||
}
|
||||
|
||||
public function validate($point)
|
||||
{
|
||||
$x = $point->normalize()->x;
|
||||
$x2 = $x->redSqr();
|
||||
$rhs = $x2->redMul($x)->redAdd($x2->redMul($this->a))->redAdd($x);
|
||||
$y = $rhs->redSqr();
|
||||
|
||||
return $y->redSqr()->cmp($rhs) ===0;
|
||||
}
|
||||
|
||||
public function decodePoint($bytes, $enc = false) {
|
||||
return $this->point(Utils::toArray($bytes, $enc), 1);
|
||||
}
|
||||
|
||||
public function point($x, $z) {
|
||||
return new Point($this, $x, $z);
|
||||
}
|
||||
|
||||
public function pointFromJSON($obj) {
|
||||
return Point::fromJSON($this, $obj);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve\MontCurve;
|
||||
|
||||
use BN\BN;
|
||||
|
||||
class Point extends \Elliptic\Curve\BaseCurve\Point
|
||||
{
|
||||
public $x;
|
||||
public $z;
|
||||
|
||||
function __construct($curve, $x, $z)
|
||||
{
|
||||
parent::__construct($curve, "projective");
|
||||
if( $x == null && $z == null )
|
||||
{
|
||||
$this->x = $this->curve->one;
|
||||
$this->z = $this->curve->zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->x = new BN($x, 16);
|
||||
$this->z = new BN($z, 16);
|
||||
if( !$this->x->red )
|
||||
$this->x = $this->x->toRed($this->curve->red);
|
||||
if( !$this->z->red )
|
||||
$this->z = $this->z->toRed($this->curve->red);
|
||||
}
|
||||
}
|
||||
|
||||
public function precompute($power = null) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
protected function _encode($compact) {
|
||||
return $this->getX()->toArray("be", $this->curve->p->byteLength());
|
||||
}
|
||||
|
||||
public static function fromJSON($curve, $obj) {
|
||||
return new Point($curve, $obj[0], isset($obj[1]) ? $obj[1] : $curve->one);
|
||||
}
|
||||
|
||||
public function inspect()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return "<EC Point Infinity>";
|
||||
return "<EC Point x: " . $this->x->fromRed()->toString(16, 2) .
|
||||
" z: " . $this->z->fromRed()->toString(16, 2) . ">";
|
||||
}
|
||||
|
||||
public function isInfinity() {
|
||||
// XXX This code assumes that zero is always zero in red
|
||||
return $this->z->isZero();
|
||||
}
|
||||
|
||||
public function dbl()
|
||||
{
|
||||
// http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3
|
||||
// 2M + 2S + 4A
|
||||
|
||||
// A = X1 + Z1
|
||||
$a = $this->x->redAdd($this->z);
|
||||
// AA = A^2
|
||||
$aa = $a->redSqr();
|
||||
// B = X1 - Z1
|
||||
$b = $this->x->redSub($this->z);
|
||||
// BB = B^2
|
||||
$bb = $b->redSqr();
|
||||
// C = AA - BB
|
||||
$c = $aa->redSub($bb);
|
||||
// X3 = AA * BB
|
||||
$nx = $aa->redMul($bb);
|
||||
// Z3 = C * (BB + A24 * C)
|
||||
$nz = $c->redMul( $bb->redAdd($this->curve->a24->redMul($c)) );
|
||||
return $this->curve->point($nx, $nz);
|
||||
}
|
||||
|
||||
public function add($p) {
|
||||
throw new \Exception('Not supported on Montgomery curve');
|
||||
}
|
||||
|
||||
public function diffAdd($p, $diff)
|
||||
{
|
||||
// http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3
|
||||
// 4M + 2S + 6A
|
||||
|
||||
// A = X2 + Z2
|
||||
$a = $this->x->redAdd($this->z);
|
||||
// B = X2 - Z2
|
||||
$b = $this->x->redSub($this->z);
|
||||
// C = X3 + Z3
|
||||
$c = $p->x->redAdd($p->z);
|
||||
// D = X3 - Z3
|
||||
$d = $p->x->redSub($p->z);
|
||||
// DA = D * A
|
||||
$da = $d->redMul($a);
|
||||
// CB = C * B
|
||||
$cb = $c->redMul($b);
|
||||
// X5 = Z1 * (DA + CB)^2
|
||||
$nx = $diff->z->redMul($da->redAdd($cb)->redSqr());
|
||||
// Z5 = X1 * (DA - CB)^2
|
||||
$nz = $diff->x->redMul($da->redSub($cb)->redSqr());
|
||||
|
||||
return $this->curve->point($nx, $nz);
|
||||
}
|
||||
|
||||
public function mul($k)
|
||||
{
|
||||
$t = $k->_clone();
|
||||
$a = $this; // (N / 2) * Q + Q
|
||||
$b = $this->curve->point(null, null); // (N / 2) * Q
|
||||
$c = $this; // Q
|
||||
|
||||
$bits = array();
|
||||
while( !$t->isZero() )
|
||||
{
|
||||
// TODO: Maybe it is faster to use toString(2)?
|
||||
array_push($bits, $t->andln(1));
|
||||
$t->iushrn(1);
|
||||
}
|
||||
|
||||
for($i = count($bits) - 1; $i >= 0; $i--)
|
||||
{
|
||||
if( $bits[$i] === 0 )
|
||||
{
|
||||
// N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q
|
||||
$a = $a->diffAdd($b, $c);
|
||||
// N * Q = 2 * ((N / 2) * Q + Q))
|
||||
$b = $b->dbl();
|
||||
}
|
||||
else
|
||||
{
|
||||
// N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q)
|
||||
$b = $a->diffAdd($b, $c);
|
||||
// N * Q + Q = 2 * ((N / 2) * Q + Q)
|
||||
$a = $a->dbl();
|
||||
}
|
||||
}
|
||||
|
||||
return $b;
|
||||
}
|
||||
|
||||
public function eq($other) {
|
||||
return $this->getX()->cmp($other->getX()) === 0;
|
||||
}
|
||||
|
||||
public function normalize()
|
||||
{
|
||||
$this->x = $this->x->redMul($this->z->redInvm());
|
||||
$this->z = $this->curve->one;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getX() {
|
||||
$this->normalize();
|
||||
return $this->x->fromRed();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
class PresetCurve
|
||||
{
|
||||
public $curve;
|
||||
public $g;
|
||||
public $n;
|
||||
public $hash;
|
||||
|
||||
function __construct($options)
|
||||
{
|
||||
if ( $options["type"] === "short" )
|
||||
$this->curve = new ShortCurve($options);
|
||||
elseif ( $options["type"] === "edwards" )
|
||||
$this->curve = new EdwardsCurve($options);
|
||||
else
|
||||
$this->curve = new MontCurve($options);
|
||||
|
||||
$this->g = $this->curve->g;
|
||||
$this->n = $this->curve->n;
|
||||
$this->hash = isset($options["hash"]) ? $options["hash"] : null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve;
|
||||
|
||||
use Elliptic\Curve\ShortCurve\Point;
|
||||
use Elliptic\Curve\ShortCurve\JPoint;
|
||||
use Elliptic\Utils;
|
||||
use BN\BN;
|
||||
use \Exception;
|
||||
|
||||
class ShortCurve extends BaseCurve
|
||||
{
|
||||
public $a;
|
||||
public $b;
|
||||
public $tinv;
|
||||
public $zeroA;
|
||||
public $threeA;
|
||||
public $endo;
|
||||
private $_endoWnafT1;
|
||||
private $_endoWnafT2;
|
||||
|
||||
function __construct($conf)
|
||||
{
|
||||
parent::__construct("short", $conf);
|
||||
|
||||
$this->a = (new BN($conf["a"], 16))->toRed($this->red);
|
||||
$this->b = (new BN($conf["b"], 16))->toRed($this->red);
|
||||
$this->tinv = $this->two->redInvm();
|
||||
|
||||
$this->zeroA = $this->a->fromRed()->isZero();
|
||||
$this->threeA = $this->a->fromRed()->sub($this->p)->cmpn(-3) === 0;
|
||||
|
||||
// If curve is endomorphic, precalculate beta and lambda
|
||||
$this->endo = $this->_getEndomorphism($conf);
|
||||
$this->_endoWnafT1 = array(0,0,0,0);
|
||||
$this->_endoWnafT2 = array(0,0,0,0);
|
||||
}
|
||||
|
||||
private function _getEndomorphism($conf)
|
||||
{
|
||||
// No efficient endomorphism
|
||||
if( !$this->zeroA || !isset($this->g) || !isset($this->n) || $this->p->modn(3) != 1 )
|
||||
return null;
|
||||
|
||||
// Compute beta and lambda, that lambda * P = (beta * Px; Py)
|
||||
$beta = null;
|
||||
$lambda = null;
|
||||
if( isset($conf["beta"]) )
|
||||
$beta = (new BN($conf["beta"], 16))->toRed($this->red);
|
||||
else
|
||||
{
|
||||
$betas = $this->_getEndoRoots($this->p);
|
||||
// Choose smallest beta
|
||||
$beta = $betas[0]->cmp($betas[1]) < 0 ? $betas[0] : $betas[1];
|
||||
$beta = $beta->toRed($this->red);
|
||||
}
|
||||
|
||||
if( isset($conf["lambda"]) )
|
||||
$lambda = new BN($conf["lambda"], 16);
|
||||
else
|
||||
{
|
||||
// Choose the lambda that is matching selected beta
|
||||
$lambdas = $this->_getEndoRoots($this->n);
|
||||
if( $this->g->mul($lambdas[0])->x->cmp($this->g->x->redMul($beta)) == 0 )
|
||||
$lambda = $lambdas[0];
|
||||
else
|
||||
{
|
||||
$lambda = $lambdas[1];
|
||||
if (Utils::$ASSERT_ENABLED) {
|
||||
assert($this->g->mul($lambda)->x->cmp($this->g->x->redMul($beta)) === 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get basis vectors, used for balanced length-two representation
|
||||
$basis = null;
|
||||
if( !isset($conf["basis"]) )
|
||||
$basis = $this->_getEndoBasis($lambda);
|
||||
else
|
||||
{
|
||||
$callback = function($vector) {
|
||||
return array(
|
||||
"a" => new BN($vector["a"], 16),
|
||||
"b" => new BN($vector["b"], 16)
|
||||
);
|
||||
};
|
||||
$basis = array_map($callback, $conf["basis"]);
|
||||
}
|
||||
|
||||
return array(
|
||||
"beta" => $beta,
|
||||
"lambda" => $lambda,
|
||||
"basis" => $basis
|
||||
);
|
||||
}
|
||||
|
||||
private function _getEndoRoots($num)
|
||||
{
|
||||
// Find roots of for x^2 + x + 1 in F
|
||||
// Root = (-1 +- Sqrt(-3)) / 2
|
||||
//
|
||||
$red = $num === $this->p ? $this->red : BN::mont($num);
|
||||
$tinv = (new BN(2))->toRed($red)->redInvm();
|
||||
$ntinv = $tinv->redNeg();
|
||||
|
||||
$s = (new BN(3))->toRed($red)->redNeg()->redSqrt()->redMul($tinv);
|
||||
|
||||
return array(
|
||||
$ntinv->redAdd($s)->fromRed(),
|
||||
$ntinv->redSub($s)->fromRed()
|
||||
);
|
||||
}
|
||||
|
||||
private function _getEndoBasis($lambda)
|
||||
{
|
||||
// aprxSqrt >= sqrt(this.n)
|
||||
$aprxSqrt = $this->n->ushrn(intval($this->n->bitLength() / 2));
|
||||
|
||||
// 3.74
|
||||
// Run EGCD, until r(L + 1) < aprxSqrt
|
||||
$u = $lambda;
|
||||
$v = $this->n->_clone();
|
||||
$x1 = new BN(1);
|
||||
$y1 = new BN(0);
|
||||
$x2 = new BN(0);
|
||||
$y2 = new BN(1);
|
||||
|
||||
// NOTE: all vectors are roots of: a + b * lambda = 0 (mod n)
|
||||
$a0 = 0;
|
||||
$b0 = 0;
|
||||
// First vector
|
||||
$a1 = 0;
|
||||
$b1 = 0;
|
||||
// Second vector
|
||||
$a2 = 0;
|
||||
$b2 = 0;
|
||||
|
||||
$prevR = 0;
|
||||
$i = 0;
|
||||
$r = 0;
|
||||
$x = 0;
|
||||
|
||||
while( ! $u->isZero() )
|
||||
{
|
||||
$q = $v->div($u);
|
||||
$r = $v->sub($q->mul($u));
|
||||
$x = $x2->sub($q->mul($x1));
|
||||
$y = $y2->sub($q->mul($y2));
|
||||
|
||||
if( !$a1 && $r->cmp($aprxSqrt) < 0 )
|
||||
{
|
||||
$a0 = $prevR->neg();
|
||||
$b0 = $x1;
|
||||
$a1 = $r->neg();
|
||||
$b1 = $x;
|
||||
}
|
||||
elseif($a1 && ++$i === 2)
|
||||
break;
|
||||
|
||||
$prevR = $r;
|
||||
$v = $u;
|
||||
$u = $r;
|
||||
$x2 = $x1;
|
||||
$x1 = $x;
|
||||
$y2 = $y1;
|
||||
$y1 = $y;
|
||||
}
|
||||
$a2 = $r->neg();
|
||||
$b2 = $x;
|
||||
|
||||
$len1 = $a1->sqr()->add($b1->sqr());
|
||||
$len2 = $a2->sqr()->add($b2->sqr());
|
||||
if( $len2->cmp($len1) >= 0 )
|
||||
{
|
||||
$a2 = $a0;
|
||||
$b2 = $b0;
|
||||
}
|
||||
|
||||
// Normalize signs
|
||||
if( $a1->negative() )
|
||||
{
|
||||
$a1 = $a1->neg();
|
||||
$b1 = $b1->neg();
|
||||
}
|
||||
|
||||
if( $a2->negative() )
|
||||
{
|
||||
$a2 = $a2->neg();
|
||||
$b2 = $b2->neg();
|
||||
}
|
||||
|
||||
return array(
|
||||
array( "a" => $a1, "b" => $b1 ),
|
||||
array( "a" => $a2, "b" => $b2 ),
|
||||
);
|
||||
}
|
||||
|
||||
public function _endoSplit($k)
|
||||
{
|
||||
$basis = $this->endo["basis"];
|
||||
$v1 = $basis[0];
|
||||
$v2 = $basis[1];
|
||||
|
||||
$c1 = $v2["b"]->mul($k)->divRound($this->n);
|
||||
$c2 = $v1["b"]->neg()->mul($k)->divRound($this->n);
|
||||
|
||||
$p1 = $c1->mul($v1["a"]);
|
||||
$p2 = $c2->mul($v2["a"]);
|
||||
$q1 = $c1->mul($v1["b"]);
|
||||
$q2 = $c2->mul($v2["b"]);
|
||||
|
||||
//Calculate answer
|
||||
$k1 = $k->sub($p1)->sub($p2);
|
||||
$k2 = $q1->add($q2)->neg();
|
||||
|
||||
return array( "k1" => $k1, "k2" => $k2 );
|
||||
}
|
||||
|
||||
public function pointFromX($x, $odd)
|
||||
{
|
||||
$x = new BN($x, 16);
|
||||
if( !$x->red )
|
||||
$x = $x->toRed($this->red);
|
||||
|
||||
$y2 = $x->redSqr()->redMul($x)->redIAdd($x->redMul($this->a))->redIAdd($this->b);
|
||||
$y = $y2->redSqrt();
|
||||
if( $y->redSqr()->redSub($y2)->cmp($this->zero) !== 0 )
|
||||
throw new Exception("Invalid point");
|
||||
|
||||
// XXX Is there any way to tell if the number is odd without converting it
|
||||
// to non-red form?
|
||||
$isOdd = $y->fromRed()->isOdd();
|
||||
if( $odd != $isOdd )
|
||||
$y = $y->redNeg();
|
||||
|
||||
return $this->point($x, $y);
|
||||
}
|
||||
|
||||
public function validate($point)
|
||||
{
|
||||
if( $point->inf )
|
||||
return true;
|
||||
|
||||
$x = $point->x;
|
||||
$y = $point->y;
|
||||
|
||||
$ax = $this->a->redMul($x);
|
||||
$rhs = $x->redSqr()->redMul($x)->redIAdd($ax)->redIAdd($this->b);
|
||||
return $y->redSqr()->redISub($rhs)->isZero();
|
||||
}
|
||||
|
||||
public function _endoWnafMulAdd($points, $coeffs, $jacobianResult = false)
|
||||
{
|
||||
$npoints = &$this->_endoWnafT1;
|
||||
$ncoeffs = &$this->_endoWnafT2;
|
||||
|
||||
for($i = 0; $i < count($points); $i++)
|
||||
{
|
||||
$split = $this->_endoSplit($coeffs[$i]);
|
||||
$p = $points[$i];
|
||||
$beta = $p->_getBeta();
|
||||
|
||||
if( $split["k1"]->negative() )
|
||||
{
|
||||
$split["k1"]->ineg();
|
||||
$p = $p->neg(true);
|
||||
}
|
||||
|
||||
if( $split["k2"]->negative() )
|
||||
{
|
||||
$split["k2"]->ineg();
|
||||
$beta = $beta->neg(true);
|
||||
}
|
||||
|
||||
$npoints[$i * 2] = $p;
|
||||
$npoints[$i * 2 + 1] = $beta;
|
||||
$ncoeffs[$i * 2] = $split["k1"];
|
||||
$ncoeffs[$i * 2 + 1] = $split["k2"];
|
||||
}
|
||||
$res = $this->_wnafMulAdd(1, $npoints, $ncoeffs, $i * 2, $jacobianResult);
|
||||
|
||||
// Clean-up references to points and coefficients
|
||||
for($j = 0; $j < 2 * $i; $j++)
|
||||
{
|
||||
$npoints[$j] = null;
|
||||
$ncoeffs[$j] = null;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function point($x, $y, $isRed = false) {
|
||||
return new Point($this, $x, $y, $isRed);
|
||||
}
|
||||
|
||||
public function pointFromJSON($obj, $red) {
|
||||
return Point::fromJSON($this, $obj, $red);
|
||||
}
|
||||
|
||||
public function jpoint($x, $y, $z) {
|
||||
return new JPoint($this, $x, $y, $z);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,488 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve\ShortCurve;
|
||||
|
||||
use BN\BN;
|
||||
|
||||
class JPoint extends \Elliptic\Curve\BaseCurve\Point
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
public $z;
|
||||
public $zOne;
|
||||
|
||||
function __construct($curve, $x, $y, $z)
|
||||
{
|
||||
parent::__construct($curve, "jacobian");
|
||||
|
||||
if( $x == null && $y == null && $z == null )
|
||||
{
|
||||
$this->x = $this->curve->one;
|
||||
$this->y = $this->curve->one;
|
||||
$this->z = new BN(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->x = new BN($x, 16);
|
||||
$this->y = new BN($y, 16);
|
||||
$this->z = new BN($z, 16);
|
||||
}
|
||||
|
||||
if( !$this->x->red )
|
||||
$this->x = $this->x->toRed($this->curve->red);
|
||||
if( !$this->y->red )
|
||||
$this->y = $this->y->toRed($this->curve->red);
|
||||
if( !$this->z->red )
|
||||
$this->z = $this->z->toRed($this->curve->red);
|
||||
|
||||
return $this->zOne = $this->z == $this->curve->one;
|
||||
}
|
||||
|
||||
public function toP()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return $this->curve->point(null, null);
|
||||
|
||||
$zinv = $this->z->redInvm();
|
||||
$zinv2 = $zinv->redSqr();
|
||||
$ax = $this->x->redMul($zinv2);
|
||||
$ay = $this->y->redMul($zinv2)->redMul($zinv);
|
||||
|
||||
return $this->curve->point($ax, $ay);
|
||||
}
|
||||
|
||||
public function neg() {
|
||||
return $this->curve->jpoint($this->x, $this->y->redNeg(), $this->z);
|
||||
}
|
||||
|
||||
public function add($p)
|
||||
{
|
||||
// O + P = P
|
||||
if( $this->isInfinity() )
|
||||
return $p;
|
||||
|
||||
// P + O = P
|
||||
if( $p->isInfinity() )
|
||||
return $this;
|
||||
|
||||
// 12M + 4S + 7A
|
||||
$pz2 = $p->z->redSqr();
|
||||
$z2 = $this->z->redSqr();
|
||||
$u1 = $this->x->redMul($pz2);
|
||||
$u2 = $p->x->redMul($z2);
|
||||
$s1 = $this->y->redMul($pz2->redMul($p->z));
|
||||
$s2 = $p->y->redMul($z2->redMul($this->z));
|
||||
|
||||
$h = $u1->redSub($u2);
|
||||
$r = $s1->redSub($s2);
|
||||
|
||||
if( $h->isZero() )
|
||||
{
|
||||
if( ! $r->isZero() )
|
||||
return $this->curve->jpoint(null, null, null);
|
||||
else
|
||||
return $this->dbl();
|
||||
}
|
||||
|
||||
$h2 = $h->redSqr();
|
||||
$h3 = $h2->redMul($h);
|
||||
$v = $u1->redMul($h2);
|
||||
|
||||
$nx = $r->redSqr()->redIAdd($h3)->redISub($v)->redISub($v);
|
||||
$ny = $r->redMul($v->redISub($nx))->redISub($s1->redMul($h3));
|
||||
$nz = $this->z->redMul($p->z)->redMul($h);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function mixedAdd($p)
|
||||
{
|
||||
// O + P = P
|
||||
if( $this->isInfinity() )
|
||||
return $p->toJ();
|
||||
|
||||
// P + O = P
|
||||
if( $p->isInfinity() )
|
||||
return $this;
|
||||
|
||||
// 8M + 3S + 7A
|
||||
$z2 = $this->z->redSqr();
|
||||
$u1 = $this->x;
|
||||
$u2 = $p->x->redMul($z2);
|
||||
$s1 = $this->y;
|
||||
$s2 = $p->y->redMul($z2)->redMul($this->z);
|
||||
|
||||
$h = $u1->redSub($u2);
|
||||
$r = $s1->redSub($s2);
|
||||
|
||||
if( $h->isZero() )
|
||||
{
|
||||
if( ! $r->isZero() )
|
||||
return $this->curve->jpoint(null, null, null);
|
||||
else
|
||||
return $this->dbl();
|
||||
}
|
||||
|
||||
$h2 = $h->redSqr();
|
||||
$h3 = $h2->redMul($h);
|
||||
$v = $u1->redMul($h2);
|
||||
|
||||
$nx = $r->redSqr()->redIAdd($h3)->redISub($v)->redISub($v);
|
||||
$ny = $r->redMul($v->redISub($nx))->redISub($s1->redMul($h3));
|
||||
$nz = $this->z->redMul($h);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function dblp($pow = null)
|
||||
{
|
||||
if( $pow == 0 || $this->isInfinity() )
|
||||
return $this;
|
||||
|
||||
if( $pow == null )
|
||||
return $this->dbl();
|
||||
|
||||
if( $this->curve->zeroA || $this->curve->threeA )
|
||||
{
|
||||
$r = $this;
|
||||
for($i = 0; $i < $pow; $i++)
|
||||
$r = $r->dbl();
|
||||
return $r;
|
||||
}
|
||||
|
||||
// 1M + 2S + 1A + N * (4S + 5M + 8A)
|
||||
// N = 1 => 6M + 6S + 9A
|
||||
$jx = $this->x;
|
||||
$jy = $this->y;
|
||||
$jz = $this->z;
|
||||
$jz4 = $jz->redSqr()->redSqr();
|
||||
|
||||
//Reuse results
|
||||
$jyd = $jy->redAdd($jy);
|
||||
for($i = 0; $i < $pow; $i++)
|
||||
{
|
||||
$jx2 = $jx->redSqr();
|
||||
$jyd2 = $jyd->redSqr();
|
||||
$jyd4 = $jyd2->redSqr();
|
||||
$c = $jx2->redAdd($jx2)->redIAdd($jx2)->redIAdd($this->curve->a->redMul($jz4));
|
||||
|
||||
$t1 = $jx->redMul($jyd2);
|
||||
$nx = $c->redSqr()->redISub($t1->redAdd($t1));
|
||||
$t2 = $t1->redISub($nx);
|
||||
$dny = $c->redMul($t2);
|
||||
$dny = $dny->redIAdd($dny)->redISub($jyd4);
|
||||
$nz = $jyd->redMul($jz);
|
||||
if( ($i + 1) < $pow)
|
||||
$jz4 = $jz4->redMul($jyd4);
|
||||
|
||||
$jx = $nx;
|
||||
$jz = $nz;
|
||||
$jyd = $dny;
|
||||
}
|
||||
|
||||
return $this->curve->jpoint($jx, $jyd->redMul($this->curve->tinv), $jz);
|
||||
}
|
||||
|
||||
public function dbl()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return $this;
|
||||
|
||||
if( $this->curve->zeroA )
|
||||
return $this->_zeroDbl();
|
||||
elseif( $this->curve->threeA )
|
||||
return $this->_threeDbl();
|
||||
return $this->_dbl();
|
||||
}
|
||||
|
||||
private function _zOneDbl($withA)
|
||||
{
|
||||
$xx = $this->x->redSqr();
|
||||
$yy = $this->y->redSqr();
|
||||
$yyyy = $yy->redSqr();
|
||||
|
||||
// S = 2 * ((X1 + YY)^2 - XX - YYYY)
|
||||
$s = $this->x->redAdd($yy)->redSqr()->redISub($xx)->redISub($yyyy);
|
||||
$s = $s->redIAdd($s);
|
||||
|
||||
// M = 3 * XX + a; a = 0
|
||||
$m = null;
|
||||
if( $withA )
|
||||
$m = $xx->redAdd($xx)->redIAdd($xx)->redIAdd($this->curve->a);
|
||||
else
|
||||
$m = $xx->redAdd($xx)->redIAdd($xx);
|
||||
|
||||
// T = M ^ 2 - 2*S
|
||||
$t = $m->redSqr()->redISub($s)->redISub($s);
|
||||
|
||||
$yyyy8 = $yyyy->redIAdd($yyyy);
|
||||
$yyyy8 = $yyyy8->redIAdd($yyyy8);
|
||||
$yyyy8 = $yyyy8->redIAdd($yyyy8);
|
||||
|
||||
$ny = $m->redMul($s->redISub($t))->redISub($yyyy8);
|
||||
$nz = $this->y->redAdd($this->y);
|
||||
return $this->curve->jpoint($t, $ny, $nz);
|
||||
}
|
||||
|
||||
private function _zeroDbl()
|
||||
{
|
||||
// Z = 1
|
||||
if( $this->zOne )
|
||||
{
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
|
||||
// #doubling-mdbl-2007-bl
|
||||
// 1M + 5S + 14A
|
||||
return $this->_zOneDbl(false);
|
||||
}
|
||||
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
|
||||
// #doubling-dbl-2009-l
|
||||
// 2M + 5S + 13A
|
||||
|
||||
$a = $this->x->redSqr();
|
||||
$b = $this->y->redSqr();
|
||||
$c = $b->redSqr();
|
||||
// D = 2 * ((X1 + B)^2 - A - C)
|
||||
$d = $this->x->redAdd($b)->redSqr()->redISub($a)->redISub($c);
|
||||
$d = $d->redIAdd($d);
|
||||
$e = $a->redAdd($a)->redIAdd($a);
|
||||
$f = $e->redSqr();
|
||||
|
||||
$c8 = $c->redIAdd($c);
|
||||
$c8 = $c8->redIAdd($c8);
|
||||
$c8 = $c8->redIAdd($c8);
|
||||
|
||||
// X3 = F - 2 * D
|
||||
$nx = $f->redISub($d)->redISub($d);
|
||||
// Y3 = E * (D - X3) - 8 * C
|
||||
$ny = $e->redMul($d->redISub($nx))->redISub($c8);
|
||||
// Z3 = 2 * Y1 * Z1
|
||||
$nz = $this->y->redMul($this->z);
|
||||
$nz = $nz->redIAdd($nz);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
private function _threeDbl()
|
||||
{
|
||||
if( $this->zOne )
|
||||
{
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
|
||||
// #doubling-mdbl-2007-bl
|
||||
// 1M + 5S + 15A
|
||||
|
||||
// XX = X1^2
|
||||
$xx = $this->x->redSqr();
|
||||
// YY = Y1^2
|
||||
$yy = $this->y->redSqr();
|
||||
// YYYY = YY^2
|
||||
$yyyy = $yy->redSqr();
|
||||
// S = 2 * ((X1 + YY)^2 - XX - YYYY)
|
||||
$s = $this->x->redAdd($yy)->redSqr()->redISub($xx)->redISub($yyyy);
|
||||
$s = $s->redIAdd($s);
|
||||
// M = 3 * XX + a
|
||||
$m = $xx->redAdd($xx)->redIAdd($xx)->redIAdd($this->curve->a);
|
||||
// T = M^2 - 2 * S
|
||||
$t = $m->redSqr()->redISub($s)->redISub($s);
|
||||
// X3 = T
|
||||
$nx = $t;
|
||||
// Y3 = M * (S - T) - 8 * YYYY
|
||||
$yyyy8 = $yyyy->redIAdd($yyyy);
|
||||
$yyyy8 = $yyyy8->redIAdd($yyyy8);
|
||||
$yyyy8 = $yyyy8->redIAdd($yyyy8);
|
||||
$ny = $m->redMul($s->redISub($t))->redISub($yyyy8);
|
||||
// Z3 = 2 * Y1
|
||||
$nz = $this->y->redAdd($this->y);
|
||||
} else {
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
|
||||
// 3M + 5S
|
||||
|
||||
// delta = Z1^2
|
||||
$delta = $this->z->redSqr();
|
||||
// gamma = Y1^2
|
||||
$gamma = $this->y->redSqr();
|
||||
// beta = X1 * gamma
|
||||
$beta = $this->x->redMul($gamma);
|
||||
// alpha = 3 * (X1 - delta) * (X1 + delta)
|
||||
$alpha = $this->x->redSub($delta)->redMul($this->x->redAdd($delta));
|
||||
$alpha = $alpha->redAdd($alpha)->redIAdd($alpha);
|
||||
// X3 = alpha^2 - 8 * beta
|
||||
$beta4 = $beta->redIAdd($beta);
|
||||
$beta4 = $beta4->redIAdd($beta4);
|
||||
$beta8 = $beta4->redAdd($beta4);
|
||||
$nx = $alpha->redSqr()->redISub($beta8);
|
||||
// Z3 = (Y1 + Z1)^2 - gamma - delta
|
||||
$nz = $this->y->redAdd($this->z)->redSqr()->redISub($gamma)->redISub($delta);
|
||||
|
||||
$ggamma8 = $gamma->redSqr();
|
||||
$ggamma8 = $ggamma8->redIAdd($ggamma8);
|
||||
$ggamma8 = $ggamma8->redIAdd($ggamma8);
|
||||
$ggamma8 = $ggamma8->redIAdd($ggamma8);
|
||||
// Y3 = alpha * (4 * beta - X3) - 8 * gamma^2
|
||||
$ny = $alpha->redMul($beta4->redISub($nx))->redISub($ggamma8);
|
||||
}
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
private function _dbl()
|
||||
{
|
||||
// 4M + 6S + 10A
|
||||
$jx = $this->x;
|
||||
$jy = $this->y;
|
||||
$jz = $this->z;
|
||||
$jz4 = $jz->redSqr()->redSqr();
|
||||
|
||||
$jx2 = $jx->redSqr();
|
||||
$jy2 = $jy->redSqr();
|
||||
|
||||
$c = $jx2->redAdd($jx2)->redIAdd($jx2)->redIAdd($this->curve->a->redMul($jz4));
|
||||
$jxd4 = $jx->redAdd($jx);
|
||||
$jxd4 = $jxd4->redIAdd($jxd4);
|
||||
$t1 = $jxd4->redMul($jy2);
|
||||
$nx = $c->redSqr()->redISub($t1->redAdd($t1));
|
||||
$t2 = $t1->redISub($nx);
|
||||
|
||||
$jyd8 = $jy2->redSqr();
|
||||
$jyd8 = $jyd8->redIAdd($jyd8);
|
||||
$jyd8 = $jyd8->redIAdd($jyd8);
|
||||
$jyd8 = $jyd8->redIAdd($jyd8);
|
||||
|
||||
$ny = $c->redMul($t2)->redISub($jyd8);
|
||||
$nz = $jy->redAdd($jy)->redMul($jz);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function trpl()
|
||||
{
|
||||
if( !$this->curve->zeroA )
|
||||
return $this->dbl()->add($this);
|
||||
|
||||
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl
|
||||
// 5M + 10S + ...
|
||||
|
||||
$xx = $this->x->redSqr();
|
||||
$yy = $this->y->redSqr();
|
||||
$zz = $this->z->redSqr();
|
||||
// YYYY = YY^2
|
||||
$yyyy = $yy->redSqr();
|
||||
|
||||
// M = 3 * XX + a * ZZ2; a = 0
|
||||
$m = $xx->redAdd($xx)->redIAdd($xx);
|
||||
// MM = M^2
|
||||
$mm = $m->redSqr();
|
||||
|
||||
// E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM
|
||||
$e = $this->x->redAdd($yy)->redSqr()->redISub($xx)->redISub($yyyy);
|
||||
$e = $e->redIAdd($e);
|
||||
$e = $e->redAdd($e)->redIAdd($e);
|
||||
$e = $e->redISub($mm);
|
||||
|
||||
$ee = $e->redSqr();
|
||||
// T = 16*YYYY
|
||||
$t = $yyyy->redIAdd($yyyy);
|
||||
$t = $t->redIAdd($t);
|
||||
$t = $t->redIAdd($t);
|
||||
$t = $t->redIAdd($t);
|
||||
|
||||
// U = (M + E)^2 - MM - EE - T
|
||||
$u = $m->redAdd($e)->redSqr()->redISub($mm)->redISub($ee)->redISub($t);
|
||||
|
||||
$yyu4 = $yy->redMul($u);
|
||||
$yyu4 = $yyu4->redIAdd($yyu4);
|
||||
$yyu4 = $yyu4->redIAdd($yyu4);
|
||||
|
||||
// X3 = 4 * (X1 * EE - 4 * YY * U)
|
||||
$nx = $this->x->redMul($ee)->redISub($yyu4);
|
||||
$nx = $nx->redIAdd($nx);
|
||||
$nx = $nx->redIAdd($nx);
|
||||
|
||||
// Y3 = 8 * Y1 * (U * (T - U) - E * EE)
|
||||
$ny = $this->y->redMul($u->redMul($t->redISub($u))->redISub($e->redMul($ee)));
|
||||
$ny = $ny->redIAdd($ny);
|
||||
$ny = $ny->redIAdd($ny);
|
||||
$ny = $ny->redIAdd($ny);
|
||||
|
||||
// Z3 = (Z1 + E)^2 - ZZ - EE
|
||||
$nz = $this->z->redAdd($e)->redSqr()->redISub($zz)->redISub($ee);
|
||||
|
||||
return $this->curve->jpoint($nx, $ny, $nz);
|
||||
}
|
||||
|
||||
public function mul($k, $kbase) {
|
||||
return $this->curve->_wnafMul($this, new BN($k, $kbase));
|
||||
}
|
||||
|
||||
public function eq($p)
|
||||
{
|
||||
if( $p->type == "affine" )
|
||||
return $this->eq($p->toJ());
|
||||
|
||||
if( $this == $p )
|
||||
return true;
|
||||
|
||||
// x1 * z2^2 == x2 * z1^2
|
||||
$z2 = $this->z->redSqr();
|
||||
$pz2 = $p->z->redSqr();
|
||||
if( ! $this->x->redMul($pz2)->redISub($p->x->redMul($z2))->isZero() )
|
||||
return false;
|
||||
|
||||
// y1 * z2^3 == y2 * z1^3
|
||||
$z3 = $z2->redMul($this->z);
|
||||
$pz3 = $pz2->redMul($p->z);
|
||||
|
||||
return $this->y->redMul($pz3)->redISub($p->y->redMul($z3))->isZero();
|
||||
}
|
||||
|
||||
public function eqXToP($x)
|
||||
{
|
||||
$zs = $this->z->redSqr();
|
||||
$rx = $x->toRed($this->curve->red)->redMul($zs);
|
||||
if( $this->x->cmp($rx) == 0 )
|
||||
return true;
|
||||
|
||||
$xc = $x->_clone();
|
||||
$t = $this->curve->redN->redMul($zs);
|
||||
|
||||
while(true)
|
||||
{
|
||||
$xc->iadd($this->curve->n);
|
||||
if( $xc->cmp($this->curve->p) >= 0 )
|
||||
return false;
|
||||
|
||||
$rx->redIAdd($t);
|
||||
if( $this->x->cmp($rx) == 0 )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function inspect()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return "<EC JPoint Infinity>";
|
||||
|
||||
return "<EC JPoint x: " . $this->x->toString(16, 2) .
|
||||
" y: " . $this->y->toString(16, 2) .
|
||||
" z: " . $this->z->toString(16, 2) . ">";
|
||||
}
|
||||
|
||||
public function __debugInfo() {
|
||||
return [
|
||||
"EC JPoint" => ($this->isInfinity() ?
|
||||
"Infinity" :
|
||||
[
|
||||
"x" => $this->x->toString(16,2),
|
||||
"y" => $this->y->toString(16,2),
|
||||
"z" => $this->z->toString(16,2)
|
||||
]
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
public function isInfinity() {
|
||||
// XXX This code assumes that zero is always zero in red
|
||||
return $this->z->isZero();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
|
||||
namespace Elliptic\Curve\ShortCurve;
|
||||
|
||||
use JsonSerializable;
|
||||
use BN\BN;
|
||||
|
||||
class Point extends \Elliptic\Curve\BaseCurve\Point implements JsonSerializable
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
public $inf;
|
||||
|
||||
function __construct($curve, $x, $y, $isRed)
|
||||
{
|
||||
parent::__construct($curve, 'affine');
|
||||
|
||||
if( $x == null && $y == null )
|
||||
{
|
||||
$this->x = null;
|
||||
$this->y = null;
|
||||
$this->inf = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->x = new BN($x, 16);
|
||||
$this->y = new BN($y, 16);
|
||||
// Force redgomery representation when loading from JSON
|
||||
if( $isRed )
|
||||
{
|
||||
$this->x->forceRed($this->curve->red);
|
||||
$this->y->forceRed($this->curve->red);
|
||||
}
|
||||
|
||||
if( !$this->x->red )
|
||||
$this->x = $this->x->toRed($this->curve->red);
|
||||
if( !$this->y->red )
|
||||
$this->y = $this->y->toRed($this->curve->red);
|
||||
$this->inf = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function _getBeta()
|
||||
{
|
||||
if( !isset($this->curve->endo) )
|
||||
return null;
|
||||
|
||||
if( isset($this->precomputed) && isset($this->precomputed["beta"]) )
|
||||
return $this->precomputed["beta"];
|
||||
|
||||
$beta = $this->curve->point($this->x->redMul($this->curve->endo["beta"]), $this->y);
|
||||
if( isset($this->precomputed) )
|
||||
{
|
||||
$endoMul = function($p) {
|
||||
return $this->curve->point($p->x->redMul($this->curve->endo["beta"]), $p->y);
|
||||
};
|
||||
$beta->precomputed = array(
|
||||
"beta" => null,
|
||||
"naf" => null,
|
||||
"doubles" => null
|
||||
);
|
||||
|
||||
if( isset($this->precomputed["naf"]) )
|
||||
{
|
||||
$beta->precomputed["naf"] = array(
|
||||
"wnd" => $this->precomputed["naf"]["wnd"],
|
||||
"points" => array_map($endoMul, $this->precomputed["naf"]["points"])
|
||||
);
|
||||
}
|
||||
|
||||
if( isset($this->precomputed["doubles"]) )
|
||||
{
|
||||
$beta->precomputed["doubles"] = array(
|
||||
"step" => $this->precomputed["doubles"]["step"],
|
||||
"points" => array_map($endoMul, $this->precomputed["doubles"]["points"])
|
||||
);
|
||||
}
|
||||
$this->precomputed["beta"] = $beta;
|
||||
}
|
||||
return $beta;
|
||||
}
|
||||
|
||||
//toJSON()
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
$res = array($this->x, $this->y);
|
||||
|
||||
if( !isset($this->precomputed) )
|
||||
return $res;
|
||||
|
||||
$pre = array();
|
||||
$addPre = false;
|
||||
if( isset($this->precomputed["doubles"]) )
|
||||
{
|
||||
$pre["doubles"] = array(
|
||||
"step" => $this->precomputed["doubles"]["step"],
|
||||
"points" => array_slice($this->precomputed["doubles"]["points"], 1)
|
||||
);
|
||||
$addPre = true;
|
||||
}
|
||||
|
||||
if( isset($this->precomputed["naf"]) )
|
||||
{
|
||||
$pre["naf"] = array(
|
||||
"naf" => $this->precomputed["naf"]["wnd"],
|
||||
"points" => array_slice($this->precomputed["naf"]["points"], 1)
|
||||
);
|
||||
$addPre = true;
|
||||
}
|
||||
|
||||
if( $addPre )
|
||||
array_push($res, $pre);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function fromJSON($curve, $obj, $red)
|
||||
{
|
||||
if( is_string($obj) )
|
||||
$obj = json_decode($obj);
|
||||
|
||||
$point = $curve->point($obj[0], $obj[1], $red);
|
||||
if( count($obj) === 2 )
|
||||
return $point;
|
||||
|
||||
$pre = $obj[2];
|
||||
$point->precomputed = array("beta" => null);
|
||||
$obj2point = function($obj) use ($curve, $red) {
|
||||
return $curve->point($obj[0], $obj[1], $red);
|
||||
};
|
||||
|
||||
if( isset($pre["doubles"]) )
|
||||
{
|
||||
$tmp = array_map($obj2point, $pre["doubles"]["points"]);
|
||||
array_unshift($tmp, $point);
|
||||
$point->precomputed["doubles"] = array(
|
||||
"step" => $pre["doubles"]["step"],
|
||||
"points" => $tmp
|
||||
);
|
||||
}
|
||||
|
||||
if( isset($pre["naf"]) )
|
||||
{
|
||||
$tmp = array_map($obj2point, $pre["naf"]["points"]);
|
||||
array_unshift($tmp, $point);
|
||||
$point->precomputed["naf"] = array(
|
||||
"wnd" => $pre["naf"]["wnd"],
|
||||
"points" => $tmp
|
||||
);
|
||||
}
|
||||
|
||||
return $point;
|
||||
}
|
||||
|
||||
public function inspect()
|
||||
{
|
||||
if( $this->isInfinity() )
|
||||
return "<EC Point Infinity>";
|
||||
|
||||
return "<EC Point x: " . $this->x->fromRed()->toString(16, 2) .
|
||||
" y: " . $this->y->fromRed()->toString(16, 2) . ">";
|
||||
}
|
||||
|
||||
public function __debugInfo() {
|
||||
return [
|
||||
"EC Point" => ($this->isInfinity() ?
|
||||
"Infinity" :
|
||||
[
|
||||
"x" => $this->x->fromRed()->toString(16, 2),
|
||||
"y" => $this->y->fromRed()->toString(16, 2)
|
||||
])
|
||||
];
|
||||
}
|
||||
public function isInfinity() {
|
||||
return $this->inf;
|
||||
}
|
||||
|
||||
public function add($point)
|
||||
{
|
||||
// O + P = P
|
||||
if( $this->inf )
|
||||
return $point;
|
||||
|
||||
// P + O = P
|
||||
if( $point->inf )
|
||||
return $this;
|
||||
|
||||
// P + P = 2P
|
||||
if( $this->eq($point) )
|
||||
return $this->dbl();
|
||||
|
||||
// P + (-P) = O
|
||||
if( $this->neg()->eq($point) )
|
||||
return $this->curve->point(null, null);
|
||||
|
||||
// P + Q = O
|
||||
if( $this->x->cmp($point->x) === 0 )
|
||||
return $this->curve->point(null, null);
|
||||
|
||||
$c = $this->y->redSub($point->y);
|
||||
if( ! $c->isZero() )
|
||||
$c = $c->redMul($this->x->redSub($point->x)->redInvm());
|
||||
$nx = $c->redSqr()->redISub($this->x)->redISub($point->x);
|
||||
$ny = $c->redMul($this->x->redSub($nx))->redISub($this->y);
|
||||
|
||||
return $this->curve->point($nx, $ny);
|
||||
}
|
||||
|
||||
public function dbl()
|
||||
{
|
||||
if( $this->inf )
|
||||
return $this;
|
||||
|
||||
// 2P = 0
|
||||
$ys1 = $this->y->redAdd($this->y);
|
||||
if( $ys1->isZero() )
|
||||
return $this->curve->point(null, null);
|
||||
|
||||
$x2 = $this->x->redSqr();
|
||||
$dyinv = $ys1->redInvm();
|
||||
$c = $x2->redAdd($x2)->redIAdd($x2)->redIAdd($this->curve->a)->redMul($dyinv);
|
||||
|
||||
$nx = $c->redSqr()->redISub($this->x->redAdd($this->x));
|
||||
$ny = $c->redMul($this->x->redSub($nx))->redISub($this->y);
|
||||
|
||||
return $this->curve->point($nx, $ny);
|
||||
}
|
||||
|
||||
public function getX() {
|
||||
return $this->x->fromRed();
|
||||
}
|
||||
|
||||
public function getY() {
|
||||
return $this->y->fromRed();
|
||||
}
|
||||
|
||||
public function mul($k)
|
||||
{
|
||||
$k = new BN($k, 16);
|
||||
|
||||
if( $this->_hasDoubles($k) )
|
||||
return $this->curve->_fixedNafMul($this, $k);
|
||||
elseif( isset($this->curve->endo) )
|
||||
return $this->curve->_endoWnafMulAdd(array($this), array($k));
|
||||
|
||||
return $this->curve->_wnafMul($this, $k);
|
||||
}
|
||||
|
||||
public function mulAdd($k1, $p2, $k2, $j = false)
|
||||
{
|
||||
$points = array($this, $p2);
|
||||
$coeffs = array($k1, $k2);
|
||||
|
||||
if( isset($this->curve->endo) )
|
||||
return $this->curve->_endoWnafMulAdd($points, $coeffs, $j);
|
||||
|
||||
return $this->curve->_wnafMulAdd(1, $points, $coeffs, 2, $j);
|
||||
}
|
||||
|
||||
public function jmulAdd($k1, $p2, $k2) {
|
||||
return $this->mulAdd($k1, $p2, $k2, true);
|
||||
}
|
||||
|
||||
public function eq($point)
|
||||
{
|
||||
return (
|
||||
$this === $point ||
|
||||
$this->inf === $point->inf &&
|
||||
($this->inf || $this->x->cmp($point->x) === 0 && $this->y->cmp($point->y) === 0)
|
||||
);
|
||||
}
|
||||
|
||||
public function neg($precompute = false)
|
||||
{
|
||||
if( $this->inf )
|
||||
return $this;
|
||||
|
||||
$res = $this->curve->point($this->x, $this->y->redNeg());
|
||||
if( $precompute && isset($this->precomputed) )
|
||||
{
|
||||
$res->precomputed = array();
|
||||
$pre = $this->precomputed;
|
||||
$negate = function($point) {
|
||||
return $point->neg();
|
||||
};
|
||||
|
||||
if( isset($pre["naf"]) )
|
||||
{
|
||||
$res->precomputed["naf"] = array(
|
||||
"wnd" => $pre["naf"]["wnd"],
|
||||
"points" => array_map($negate, $pre["naf"]["points"])
|
||||
);
|
||||
}
|
||||
|
||||
if( isset($pre["doubles"]) )
|
||||
{
|
||||
$res->precomputed["doubles"] = array(
|
||||
"step" => $pre["doubles"]["step"],
|
||||
"points" => array_map($negate, $pre["doubles"]["points"])
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function toJ()
|
||||
{
|
||||
if( $this->inf )
|
||||
return $this->curve->jpoint(null, null, null);
|
||||
|
||||
return $this->curve->jpoint($this->x, $this->y, $this->curve->one);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user