PageRenderTime 53ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/google-listings-and-ads/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Binary.php

https://gitlab.com/remyvianne/krowkaramel
PHP | 378 lines | 188 code | 45 blank | 145 comment | 21 complexity | e82fbd1471e14e1e5f87d4ec11610bef MD5 | raw file
  1. <?php
  2. /**
  3. * Curves over y^2 + x*y = x^3 + a*x^2 + b
  4. *
  5. * These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf
  6. * The curve is a weierstrass curve with a[3] and a[2] set to 0.
  7. *
  8. * Uses Jacobian Coordinates for speed if able:
  9. *
  10. * https://en.wikipedia.org/wiki/Jacobian_curve
  11. * https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
  12. *
  13. * PHP version 5 and 7
  14. *
  15. * @category Crypt
  16. * @package EC
  17. * @author Jim Wigginton <terrafrost@php.net>
  18. * @copyright 2017 Jim Wigginton
  19. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  20. * @link http://pear.php.net/package/Math_BigInteger
  21. */
  22. namespace phpseclib3\Crypt\EC\BaseCurves;
  23. use phpseclib3\Common\Functions\Strings;
  24. use phpseclib3\Math\BinaryField;
  25. use phpseclib3\Math\BigInteger;
  26. use phpseclib3\Math\BinaryField\Integer as BinaryInteger;
  27. /**
  28. * Curves over y^2 + x*y = x^3 + a*x^2 + b
  29. *
  30. * @package Binary
  31. * @author Jim Wigginton <terrafrost@php.net>
  32. * @access public
  33. */
  34. class Binary extends Base
  35. {
  36. /**
  37. * Binary Field Integer factory
  38. *
  39. * @var \phpseclib3\Math\BinaryField
  40. */
  41. protected $factory;
  42. /**
  43. * Cofficient for x^1
  44. *
  45. * @var object
  46. */
  47. protected $a;
  48. /**
  49. * Cofficient for x^0
  50. *
  51. * @var object
  52. */
  53. protected $b;
  54. /**
  55. * Base Point
  56. *
  57. * @var object
  58. */
  59. protected $p;
  60. /**
  61. * The number one over the specified finite field
  62. *
  63. * @var object
  64. */
  65. protected $one;
  66. /**
  67. * The modulo
  68. *
  69. * @var BigInteger
  70. */
  71. protected $modulo;
  72. /**
  73. * The Order
  74. *
  75. * @var BigInteger
  76. */
  77. protected $order;
  78. /**
  79. * Sets the modulo
  80. */
  81. public function setModulo(...$modulo)
  82. {
  83. $this->modulo = $modulo;
  84. $this->factory = new BinaryField(...$modulo);
  85. $this->one = $this->factory->newInteger("\1");
  86. }
  87. /**
  88. * Set coefficients a and b
  89. *
  90. * @param string $a
  91. * @param string $b
  92. */
  93. public function setCoefficients($a, $b)
  94. {
  95. if (!isset($this->factory)) {
  96. throw new \RuntimeException('setModulo needs to be called before this method');
  97. }
  98. $this->a = $this->factory->newInteger(pack('H*', $a));
  99. $this->b = $this->factory->newInteger(pack('H*', $b));
  100. }
  101. /**
  102. * Set x and y coordinates for the base point
  103. *
  104. * @param string|BinaryInteger $x
  105. * @param string|BinaryInteger $y
  106. */
  107. public function setBasePoint($x, $y)
  108. {
  109. switch (true) {
  110. case !is_string($x) && !$x instanceof BinaryInteger:
  111. throw new \UnexpectedValueException('Argument 1 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\Integer');
  112. case !is_string($y) && !$y instanceof BinaryInteger:
  113. throw new \UnexpectedValueException('Argument 2 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\Integer');
  114. }
  115. if (!isset($this->factory)) {
  116. throw new \RuntimeException('setModulo needs to be called before this method');
  117. }
  118. $this->p = [
  119. is_string($x) ? $this->factory->newInteger(pack('H*', $x)) : $x,
  120. is_string($y) ? $this->factory->newInteger(pack('H*', $y)) : $y
  121. ];
  122. }
  123. /**
  124. * Retrieve the base point as an array
  125. *
  126. * @return array
  127. */
  128. public function getBasePoint()
  129. {
  130. if (!isset($this->factory)) {
  131. throw new \RuntimeException('setModulo needs to be called before this method');
  132. }
  133. /*
  134. if (!isset($this->p)) {
  135. throw new \RuntimeException('setBasePoint needs to be called before this method');
  136. }
  137. */
  138. return $this->p;
  139. }
  140. /**
  141. * Adds two points on the curve
  142. *
  143. * @return FiniteField[]
  144. */
  145. public function addPoint(array $p, array $q)
  146. {
  147. if (!isset($this->factory)) {
  148. throw new \RuntimeException('setModulo needs to be called before this method');
  149. }
  150. if (!count($p) || !count($q)) {
  151. if (count($q)) {
  152. return $q;
  153. }
  154. if (count($p)) {
  155. return $p;
  156. }
  157. return [];
  158. }
  159. if (!isset($p[2]) || !isset($q[2])) {
  160. throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
  161. }
  162. if ($p[0]->equals($q[0])) {
  163. return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
  164. }
  165. // formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html
  166. list($x1, $y1, $z1) = $p;
  167. list($x2, $y2, $z2) = $q;
  168. $o1 = $z1->multiply($z1);
  169. $b = $x2->multiply($o1);
  170. if ($z2->equals($this->one)) {
  171. $d = $y2->multiply($o1)->multiply($z1);
  172. $e = $x1->add($b);
  173. $f = $y1->add($d);
  174. $z3 = $e->multiply($z1);
  175. $h = $f->multiply($x2)->add($z3->multiply($y2));
  176. $i = $f->add($z3);
  177. $g = $z3->multiply($z3);
  178. $p1 = $this->a->multiply($g);
  179. $p2 = $f->multiply($i);
  180. $p3 = $e->multiply($e)->multiply($e);
  181. $x3 = $p1->add($p2)->add($p3);
  182. $y3 = $i->multiply($x3)->add($g->multiply($h));
  183. return [$x3, $y3, $z3];
  184. }
  185. $o2 = $z2->multiply($z2);
  186. $a = $x1->multiply($o2);
  187. $c = $y1->multiply($o2)->multiply($z2);
  188. $d = $y2->multiply($o1)->multiply($z1);
  189. $e = $a->add($b);
  190. $f = $c->add($d);
  191. $g = $e->multiply($z1);
  192. $h = $f->multiply($x2)->add($g->multiply($y2));
  193. $z3 = $g->multiply($z2);
  194. $i = $f->add($z3);
  195. $p1 = $this->a->multiply($z3->multiply($z3));
  196. $p2 = $f->multiply($i);
  197. $p3 = $e->multiply($e)->multiply($e);
  198. $x3 = $p1->add($p2)->add($p3);
  199. $y3 = $i->multiply($x3)->add($g->multiply($g)->multiply($h));
  200. return [$x3, $y3, $z3];
  201. }
  202. /**
  203. * Doubles a point on a curve
  204. *
  205. * @return FiniteField[]
  206. */
  207. public function doublePoint(array $p)
  208. {
  209. if (!isset($this->factory)) {
  210. throw new \RuntimeException('setModulo needs to be called before this method');
  211. }
  212. if (!count($p)) {
  213. return [];
  214. }
  215. if (!isset($p[2])) {
  216. throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
  217. }
  218. // formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html
  219. list($x1, $y1, $z1) = $p;
  220. $a = $x1->multiply($x1);
  221. $b = $a->multiply($a);
  222. if ($z1->equals($this->one)) {
  223. $x3 = $b->add($this->b);
  224. $z3 = clone $x1;
  225. $p1 = $a->add($y1)->add($z3)->multiply($this->b);
  226. $p2 = $a->add($y1)->multiply($b);
  227. $y3 = $p1->add($p2);
  228. return [$x3, $y3, $z3];
  229. }
  230. $c = $z1->multiply($z1);
  231. $d = $c->multiply($c);
  232. $x3 = $b->add($this->b->multiply($d->multiply($d)));
  233. $z3 = $x1->multiply($c);
  234. $p1 = $b->multiply($z3);
  235. $p2 = $a->add($y1->multiply($z1))->add($z3)->multiply($x3);
  236. $y3 = $p1->add($p2);
  237. return [$x3, $y3, $z3];
  238. }
  239. /**
  240. * Returns the X coordinate and the derived Y coordinate
  241. *
  242. * Not supported because it is covered by patents.
  243. * Quoting https://www.openssl.org/docs/man1.1.0/apps/ecparam.html ,
  244. *
  245. * "Due to patent issues the compressed option is disabled by default for binary curves
  246. * and can be enabled by defining the preprocessor macro OPENSSL_EC_BIN_PT_COMP at
  247. * compile time."
  248. *
  249. * @return array
  250. */
  251. public function derivePoint($m)
  252. {
  253. throw new \RuntimeException('Point compression on binary finite field elliptic curves is not supported');
  254. }
  255. /**
  256. * Tests whether or not the x / y values satisfy the equation
  257. *
  258. * @return boolean
  259. */
  260. public function verifyPoint(array $p)
  261. {
  262. list($x, $y) = $p;
  263. $lhs = $y->multiply($y);
  264. $lhs = $lhs->add($x->multiply($y));
  265. $x2 = $x->multiply($x);
  266. $x3 = $x2->multiply($x);
  267. $rhs = $x3->add($this->a->multiply($x2))->add($this->b);
  268. return $lhs->equals($rhs);
  269. }
  270. /**
  271. * Returns the modulo
  272. *
  273. * @return \phpseclib3\Math\BigInteger
  274. */
  275. public function getModulo()
  276. {
  277. return $this->modulo;
  278. }
  279. /**
  280. * Returns the a coefficient
  281. *
  282. * @return \phpseclib3\Math\PrimeField\Integer
  283. */
  284. public function getA()
  285. {
  286. return $this->a;
  287. }
  288. /**
  289. * Returns the a coefficient
  290. *
  291. * @return \phpseclib3\Math\PrimeField\Integer
  292. */
  293. public function getB()
  294. {
  295. return $this->b;
  296. }
  297. /**
  298. * Returns the affine point
  299. *
  300. * A Jacobian Coordinate is of the form (x, y, z).
  301. * To convert a Jacobian Coordinate to an Affine Point
  302. * you do (x / z^2, y / z^3)
  303. *
  304. * @return \phpseclib3\Math\PrimeField\Integer[]
  305. */
  306. public function convertToAffine(array $p)
  307. {
  308. if (!isset($p[2])) {
  309. return $p;
  310. }
  311. list($x, $y, $z) = $p;
  312. $z = $this->one->divide($z);
  313. $z2 = $z->multiply($z);
  314. return [
  315. $x->multiply($z2),
  316. $y->multiply($z2)->multiply($z)
  317. ];
  318. }
  319. /**
  320. * Converts an affine point to a jacobian coordinate
  321. *
  322. * @return \phpseclib3\Math\PrimeField\Integer[]
  323. */
  324. public function convertToInternal(array $p)
  325. {
  326. if (isset($p[2])) {
  327. return $p;
  328. }
  329. $p[2] = clone $this->one;
  330. $p['fresh'] = true;
  331. return $p;
  332. }
  333. }