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