JPoint.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <?php
  2. namespace Elliptic\Curve\ShortCurve;
  3. use BN\BN;
  4. class JPoint extends \Elliptic\Curve\BaseCurve\Point
  5. {
  6. public $x;
  7. public $y;
  8. public $z;
  9. public $zOne;
  10. function __construct($curve, $x, $y, $z)
  11. {
  12. parent::__construct($curve, "jacobian");
  13. if( $x == null && $y == null && $z == null )
  14. {
  15. $this->x = $this->curve->one;
  16. $this->y = $this->curve->one;
  17. $this->z = new BN(0);
  18. }
  19. else
  20. {
  21. $this->x = new BN($x, 16);
  22. $this->y = new BN($y, 16);
  23. $this->z = new BN($z, 16);
  24. }
  25. if( !$this->x->red )
  26. $this->x = $this->x->toRed($this->curve->red);
  27. if( !$this->y->red )
  28. $this->y = $this->y->toRed($this->curve->red);
  29. if( !$this->z->red )
  30. $this->z = $this->z->toRed($this->curve->red);
  31. return $this->zOne = $this->z == $this->curve->one;
  32. }
  33. public function toP()
  34. {
  35. if( $this->isInfinity() )
  36. return $this->curve->point(null, null);
  37. $zinv = $this->z->redInvm();
  38. $zinv2 = $zinv->redSqr();
  39. $ax = $this->x->redMul($zinv2);
  40. $ay = $this->y->redMul($zinv2)->redMul($zinv);
  41. return $this->curve->point($ax, $ay);
  42. }
  43. public function neg() {
  44. return $this->curve->jpoint($this->x, $this->y->redNeg(), $this->z);
  45. }
  46. public function add($p)
  47. {
  48. // O + P = P
  49. if( $this->isInfinity() )
  50. return $p;
  51. // P + O = P
  52. if( $p->isInfinity() )
  53. return $this;
  54. // 12M + 4S + 7A
  55. $pz2 = $p->z->redSqr();
  56. $z2 = $this->z->redSqr();
  57. $u1 = $this->x->redMul($pz2);
  58. $u2 = $p->x->redMul($z2);
  59. $s1 = $this->y->redMul($pz2->redMul($p->z));
  60. $s2 = $p->y->redMul($z2->redMul($this->z));
  61. $h = $u1->redSub($u2);
  62. $r = $s1->redSub($s2);
  63. if( $h->isZero() )
  64. {
  65. if( ! $r->isZero() )
  66. return $this->curve->jpoint(null, null, null);
  67. else
  68. return $this->dbl();
  69. }
  70. $h2 = $h->redSqr();
  71. $h3 = $h2->redMul($h);
  72. $v = $u1->redMul($h2);
  73. $nx = $r->redSqr()->redIAdd($h3)->redISub($v)->redISub($v);
  74. $ny = $r->redMul($v->redISub($nx))->redISub($s1->redMul($h3));
  75. $nz = $this->z->redMul($p->z)->redMul($h);
  76. return $this->curve->jpoint($nx, $ny, $nz);
  77. }
  78. public function mixedAdd($p)
  79. {
  80. // O + P = P
  81. if( $this->isInfinity() )
  82. return $p->toJ();
  83. // P + O = P
  84. if( $p->isInfinity() )
  85. return $this;
  86. // 8M + 3S + 7A
  87. $z2 = $this->z->redSqr();
  88. $u1 = $this->x;
  89. $u2 = $p->x->redMul($z2);
  90. $s1 = $this->y;
  91. $s2 = $p->y->redMul($z2)->redMul($this->z);
  92. $h = $u1->redSub($u2);
  93. $r = $s1->redSub($s2);
  94. if( $h->isZero() )
  95. {
  96. if( ! $r->isZero() )
  97. return $this->curve->jpoint(null, null, null);
  98. else
  99. return $this->dbl();
  100. }
  101. $h2 = $h->redSqr();
  102. $h3 = $h2->redMul($h);
  103. $v = $u1->redMul($h2);
  104. $nx = $r->redSqr()->redIAdd($h3)->redISub($v)->redISub($v);
  105. $ny = $r->redMul($v->redISub($nx))->redISub($s1->redMul($h3));
  106. $nz = $this->z->redMul($h);
  107. return $this->curve->jpoint($nx, $ny, $nz);
  108. }
  109. public function dblp($pow = null)
  110. {
  111. if( $pow == 0 || $this->isInfinity() )
  112. return $this;
  113. if( $pow == null )
  114. return $this->dbl();
  115. if( $this->curve->zeroA || $this->curve->threeA )
  116. {
  117. $r = $this;
  118. for($i = 0; $i < $pow; $i++)
  119. $r = $r->dbl();
  120. return $r;
  121. }
  122. // 1M + 2S + 1A + N * (4S + 5M + 8A)
  123. // N = 1 => 6M + 6S + 9A
  124. $jx = $this->x;
  125. $jy = $this->y;
  126. $jz = $this->z;
  127. $jz4 = $jz->redSqr()->redSqr();
  128. //Reuse results
  129. $jyd = $jy->redAdd($jy);
  130. for($i = 0; $i < $pow; $i++)
  131. {
  132. $jx2 = $jx->redSqr();
  133. $jyd2 = $jyd->redSqr();
  134. $jyd4 = $jyd2->redSqr();
  135. $c = $jx2->redAdd($jx2)->redIAdd($jx2)->redIAdd($this->curve->a->redMul($jz4));
  136. $t1 = $jx->redMul($jyd2);
  137. $nx = $c->redSqr()->redISub($t1->redAdd($t1));
  138. $t2 = $t1->redISub($nx);
  139. $dny = $c->redMul($t2);
  140. $dny = $dny->redIAdd($dny)->redISub($jyd4);
  141. $nz = $jyd->redMul($jz);
  142. if( ($i + 1) < $pow)
  143. $jz4 = $jz4->redMul($jyd4);
  144. $jx = $nx;
  145. $jz = $nz;
  146. $jyd = $dny;
  147. }
  148. return $this->curve->jpoint($jx, $jyd->redMul($this->curve->tinv), $jz);
  149. }
  150. public function dbl()
  151. {
  152. if( $this->isInfinity() )
  153. return $this;
  154. if( $this->curve->zeroA )
  155. return $this->_zeroDbl();
  156. elseif( $this->curve->threeA )
  157. return $this->_threeDbl();
  158. return $this->_dbl();
  159. }
  160. private function _zOneDbl($withA)
  161. {
  162. $xx = $this->x->redSqr();
  163. $yy = $this->y->redSqr();
  164. $yyyy = $yy->redSqr();
  165. // S = 2 * ((X1 + YY)^2 - XX - YYYY)
  166. $s = $this->x->redAdd($yy)->redSqr()->redISub($xx)->redISub($yyyy);
  167. $s = $s->redIAdd($s);
  168. // M = 3 * XX + a; a = 0
  169. $m = null;
  170. if( $withA )
  171. $m = $xx->redAdd($xx)->redIAdd($xx)->redIAdd($this->curve->a);
  172. else
  173. $m = $xx->redAdd($xx)->redIAdd($xx);
  174. // T = M ^ 2 - 2*S
  175. $t = $m->redSqr()->redISub($s)->redISub($s);
  176. $yyyy8 = $yyyy->redIAdd($yyyy);
  177. $yyyy8 = $yyyy8->redIAdd($yyyy8);
  178. $yyyy8 = $yyyy8->redIAdd($yyyy8);
  179. $ny = $m->redMul($s->redISub($t))->redISub($yyyy8);
  180. $nz = $this->y->redAdd($this->y);
  181. return $this->curve->jpoint($t, $ny, $nz);
  182. }
  183. private function _zeroDbl()
  184. {
  185. // Z = 1
  186. if( $this->zOne )
  187. {
  188. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
  189. // #doubling-mdbl-2007-bl
  190. // 1M + 5S + 14A
  191. return $this->_zOneDbl(false);
  192. }
  193. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
  194. // #doubling-dbl-2009-l
  195. // 2M + 5S + 13A
  196. $a = $this->x->redSqr();
  197. $b = $this->y->redSqr();
  198. $c = $b->redSqr();
  199. // D = 2 * ((X1 + B)^2 - A - C)
  200. $d = $this->x->redAdd($b)->redSqr()->redISub($a)->redISub($c);
  201. $d = $d->redIAdd($d);
  202. $e = $a->redAdd($a)->redIAdd($a);
  203. $f = $e->redSqr();
  204. $c8 = $c->redIAdd($c);
  205. $c8 = $c8->redIAdd($c8);
  206. $c8 = $c8->redIAdd($c8);
  207. // X3 = F - 2 * D
  208. $nx = $f->redISub($d)->redISub($d);
  209. // Y3 = E * (D - X3) - 8 * C
  210. $ny = $e->redMul($d->redISub($nx))->redISub($c8);
  211. // Z3 = 2 * Y1 * Z1
  212. $nz = $this->y->redMul($this->z);
  213. $nz = $nz->redIAdd($nz);
  214. return $this->curve->jpoint($nx, $ny, $nz);
  215. }
  216. private function _threeDbl()
  217. {
  218. if( $this->zOne )
  219. {
  220. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
  221. // #doubling-mdbl-2007-bl
  222. // 1M + 5S + 15A
  223. // XX = X1^2
  224. $xx = $this->x->redSqr();
  225. // YY = Y1^2
  226. $yy = $this->y->redSqr();
  227. // YYYY = YY^2
  228. $yyyy = $yy->redSqr();
  229. // S = 2 * ((X1 + YY)^2 - XX - YYYY)
  230. $s = $this->x->redAdd($yy)->redSqr()->redISub($xx)->redISub($yyyy);
  231. $s = $s->redIAdd($s);
  232. // M = 3 * XX + a
  233. $m = $xx->redAdd($xx)->redIAdd($xx)->redIAdd($this->curve->a);
  234. // T = M^2 - 2 * S
  235. $t = $m->redSqr()->redISub($s)->redISub($s);
  236. // X3 = T
  237. $nx = $t;
  238. // Y3 = M * (S - T) - 8 * YYYY
  239. $yyyy8 = $yyyy->redIAdd($yyyy);
  240. $yyyy8 = $yyyy8->redIAdd($yyyy8);
  241. $yyyy8 = $yyyy8->redIAdd($yyyy8);
  242. $ny = $m->redMul($s->redISub($t))->redISub($yyyy8);
  243. // Z3 = 2 * Y1
  244. $nz = $this->y->redAdd($this->y);
  245. } else {
  246. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
  247. // 3M + 5S
  248. // delta = Z1^2
  249. $delta = $this->z->redSqr();
  250. // gamma = Y1^2
  251. $gamma = $this->y->redSqr();
  252. // beta = X1 * gamma
  253. $beta = $this->x->redMul($gamma);
  254. // alpha = 3 * (X1 - delta) * (X1 + delta)
  255. $alpha = $this->x->redSub($delta)->redMul($this->x->redAdd($delta));
  256. $alpha = $alpha->redAdd($alpha)->redIAdd($alpha);
  257. // X3 = alpha^2 - 8 * beta
  258. $beta4 = $beta->redIAdd($beta);
  259. $beta4 = $beta4->redIAdd($beta4);
  260. $beta8 = $beta4->redAdd($beta4);
  261. $nx = $alpha->redSqr()->redISub($beta8);
  262. // Z3 = (Y1 + Z1)^2 - gamma - delta
  263. $nz = $this->y->redAdd($this->z)->redSqr()->redISub($gamma)->redISub($delta);
  264. $ggamma8 = $gamma->redSqr();
  265. $ggamma8 = $ggamma8->redIAdd($ggamma8);
  266. $ggamma8 = $ggamma8->redIAdd($ggamma8);
  267. $ggamma8 = $ggamma8->redIAdd($ggamma8);
  268. // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2
  269. $ny = $alpha->redMul($beta4->redISub($nx))->redISub($ggamma8);
  270. }
  271. return $this->curve->jpoint($nx, $ny, $nz);
  272. }
  273. private function _dbl()
  274. {
  275. // 4M + 6S + 10A
  276. $jx = $this->x;
  277. $jy = $this->y;
  278. $jz = $this->z;
  279. $jz4 = $jz->redSqr()->redSqr();
  280. $jx2 = $jx->redSqr();
  281. $jy2 = $jy->redSqr();
  282. $c = $jx2->redAdd($jx2)->redIAdd($jx2)->redIAdd($this->curve->a->redMul($jz4));
  283. $jxd4 = $jx->redAdd($jx);
  284. $jxd4 = $jxd4->redIAdd($jxd4);
  285. $t1 = $jxd4->redMul($jy2);
  286. $nx = $c->redSqr()->redISub($t1->redAdd($t1));
  287. $t2 = $t1->redISub($nx);
  288. $jyd8 = $jy2->redSqr();
  289. $jyd8 = $jyd8->redIAdd($jyd8);
  290. $jyd8 = $jyd8->redIAdd($jyd8);
  291. $jyd8 = $jyd8->redIAdd($jyd8);
  292. $ny = $c->redMul($t2)->redISub($jyd8);
  293. $nz = $jy->redAdd($jy)->redMul($jz);
  294. return $this->curve->jpoint($nx, $ny, $nz);
  295. }
  296. public function trpl()
  297. {
  298. if( !$this->curve->zeroA )
  299. return $this->dbl()->add($this);
  300. // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl
  301. // 5M + 10S + ...
  302. $xx = $this->x->redSqr();
  303. $yy = $this->y->redSqr();
  304. $zz = $this->z->redSqr();
  305. // YYYY = YY^2
  306. $yyyy = $yy->redSqr();
  307. // M = 3 * XX + a * ZZ2; a = 0
  308. $m = $xx->redAdd($xx)->redIAdd($xx);
  309. // MM = M^2
  310. $mm = $m->redSqr();
  311. // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM
  312. $e = $this->x->redAdd($yy)->redSqr()->redISub($xx)->redISub($yyyy);
  313. $e = $e->redIAdd($e);
  314. $e = $e->redAdd($e)->redIAdd($e);
  315. $e = $e->redISub($mm);
  316. $ee = $e->redSqr();
  317. // T = 16*YYYY
  318. $t = $yyyy->redIAdd($yyyy);
  319. $t = $t->redIAdd($t);
  320. $t = $t->redIAdd($t);
  321. $t = $t->redIAdd($t);
  322. // U = (M + E)^2 - MM - EE - T
  323. $u = $m->redAdd($e)->redSqr()->redISub($mm)->redISub($ee)->redISub($t);
  324. $yyu4 = $yy->redMul($u);
  325. $yyu4 = $yyu4->redIAdd($yyu4);
  326. $yyu4 = $yyu4->redIAdd($yyu4);
  327. // X3 = 4 * (X1 * EE - 4 * YY * U)
  328. $nx = $this->x->redMul($ee)->redISub($yyu4);
  329. $nx = $nx->redIAdd($nx);
  330. $nx = $nx->redIAdd($nx);
  331. // Y3 = 8 * Y1 * (U * (T - U) - E * EE)
  332. $ny = $this->y->redMul($u->redMul($t->redISub($u))->redISub($e->redMul($ee)));
  333. $ny = $ny->redIAdd($ny);
  334. $ny = $ny->redIAdd($ny);
  335. $ny = $ny->redIAdd($ny);
  336. // Z3 = (Z1 + E)^2 - ZZ - EE
  337. $nz = $this->z->redAdd($e)->redSqr()->redISub($zz)->redISub($ee);
  338. return $this->curve->jpoint($nx, $ny, $nz);
  339. }
  340. public function mul($k, $kbase) {
  341. return $this->curve->_wnafMul($this, new BN($k, $kbase));
  342. }
  343. public function eq($p)
  344. {
  345. if( $p->type == "affine" )
  346. return $this->eq($p->toJ());
  347. if( $this == $p )
  348. return true;
  349. // x1 * z2^2 == x2 * z1^2
  350. $z2 = $this->z->redSqr();
  351. $pz2 = $p->z->redSqr();
  352. if( ! $this->x->redMul($pz2)->redISub($p->x->redMul($z2))->isZero() )
  353. return false;
  354. // y1 * z2^3 == y2 * z1^3
  355. $z3 = $z2->redMul($this->z);
  356. $pz3 = $pz2->redMul($p->z);
  357. return $this->y->redMul($pz3)->redISub($p->y->redMul($z3))->isZero();
  358. }
  359. public function eqXToP($x)
  360. {
  361. $zs = $this->z->redSqr();
  362. $rx = $x->toRed($this->curve->red)->redMul($zs);
  363. if( $this->x->cmp($rx) == 0 )
  364. return true;
  365. $xc = $x->_clone();
  366. $t = $this->curve->redN->redMul($zs);
  367. while(true)
  368. {
  369. $xc->iadd($this->curve->n);
  370. if( $xc->cmp($this->curve->p) >= 0 )
  371. return false;
  372. $rx->redIAdd($t);
  373. if( $this->x->cmp($rx) == 0 )
  374. return true;
  375. }
  376. }
  377. public function inspect()
  378. {
  379. if( $this->isInfinity() )
  380. return "<EC JPoint Infinity>";
  381. return "<EC JPoint x: " . $this->x->toString(16, 2) .
  382. " y: " . $this->y->toString(16, 2) .
  383. " z: " . $this->z->toString(16, 2) . ">";
  384. }
  385. public function __debugInfo() {
  386. return [
  387. "EC JPoint" => ($this->isInfinity() ?
  388. "Infinity" :
  389. [
  390. "x" => $this->x->toString(16,2),
  391. "y" => $this->y->toString(16,2),
  392. "z" => $this->z->toString(16,2)
  393. ]
  394. )
  395. ];
  396. }
  397. public function isInfinity() {
  398. // XXX This code assumes that zero is always zero in red
  399. return $this->z->isZero();
  400. }
  401. }
  402. ?>