161 lines
4.2 KiB
PHP
161 lines
4.2 KiB
PHP
<?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();
|
|
}
|
|
}
|
|
|
|
?>
|