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