PageRenderTime 53ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/package/app/dwh/etlsource/scripts/BigInteger.php

https://bitbucket.org/pandaos/kaltura
PHP | 1971 lines | 1001 code | 290 blank | 680 comment | 169 complexity | e5fe550769e6148c3758e888d84db493 MD5 | raw file
Possible License(s): AGPL-3.0, GPL-3.0, BSD-3-Clause, LGPL-2.1, GPL-2.0, LGPL-3.0, JSON, MPL-2.0-no-copyleft-exception, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Pure-PHP arbitrary precision integer arithmetic library.
  5. *
  6. * Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available,
  7. * and an internal implementation, otherwise.
  8. *
  9. * PHP versions 4 and 5
  10. *
  11. * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
  12. * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
  13. *
  14. * Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
  15. * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction. Because the largest possible
  16. * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
  17. * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
  18. * used. As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
  19. * which only supports integers. Although this fact will slow this library down, the fact that such a high
  20. * base is being used should more than compensate.
  21. *
  22. * When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again,
  23. * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /
  24. * subtraction).
  25. *
  26. * Useful resources are as follows:
  27. *
  28. * - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
  29. * - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
  30. * - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
  31. *
  32. * One idea for optimization is to use the comba method to reduce the number of operations performed.
  33. * MPM uses this quite extensively. The following URL elaborates:
  34. *
  35. * {@link http://www.everything2.com/index.pl?node_id=1736418}}}
  36. *
  37. * Here's a quick 'n dirty example of how to use this library:
  38. * <code>
  39. * <?php
  40. * include('Math/BigInteger.php');
  41. *
  42. * $a = new Math_BigInteger(2);
  43. * $b = new Math_BigInteger(3);
  44. *
  45. * $c = $a->add($b);
  46. *
  47. * echo $c->toString(); // outputs 5
  48. * ?>
  49. * </code>
  50. *
  51. * LICENSE: This library is free software; you can redistribute it and/or
  52. * modify it under the terms of the GNU Lesser General Public
  53. * License as published by the Free Software Foundation; either
  54. * version 2.1 of the License, or (at your option) any later version.
  55. *
  56. * This library is distributed in the hope that it will be useful,
  57. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  58. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  59. * Lesser General Public License for more details.
  60. *
  61. * You should have received a copy of the GNU Lesser General Public
  62. * License along with this library; if not, write to the Free Software
  63. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  64. * MA 02111-1307 USA
  65. *
  66. * @category Math
  67. * @package Math_BigInteger
  68. * @author Jim Wigginton <terrafrost@php.net>
  69. * @copyright MMVI Jim Wigginton
  70. * @license http://www.gnu.org/licenses/lgpl.txt
  71. * @version CVS: $Id: BigInteger.php,v 1.4 2007/01/29 17:19:11 terrafrost Exp $
  72. * @link http://pear.php.net/package/Math_BigInteger
  73. */
  74. // array_fill requires PHP 4.2.0+, per http://php.net/function.array_fill
  75. // see http://www.frostjedi.com/terra/scripts/pear/array_fill.phps
  76. // require_once 'PHP/Compat/Function/array_fill.php';
  77. /**#@+
  78. * @access private
  79. * @see Math_BigInteger::_slidingWindow()
  80. */
  81. /**
  82. * @see Math_BigInteger::_montgomery()
  83. * @see Math_BigInteger::_undoMontgomery()
  84. */
  85. define('MATH_BIGINTEGER_MONTGOMERY', 0);
  86. /**
  87. * @see Math_BigInteger::_barrett()
  88. */
  89. define('MATH_BIGINTEGER_BARRETT', 1);
  90. /**
  91. * @see Math_BigInteger::_mod2()
  92. */
  93. define('MATH_BIGINTEGER_POWEROF2', 2);
  94. /**
  95. * @see Math_BigInteger::_remainder()
  96. */
  97. define('MATH_BIGINTEGER_CLASSIC', 3);
  98. /**
  99. * @see Math_BigInteger::_copy()
  100. */
  101. define('MATH_BIGINTEGER_NONE', 4);
  102. /**#@-*/
  103. /**#@+
  104. * @access private
  105. * @see Math_BigInteger::_montgomery()
  106. * @see Math_BigInteger::_barrett()
  107. */
  108. /**
  109. * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
  110. */
  111. define('MATH_BIGINTEGER_VARIABLE', 0);
  112. /**
  113. * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
  114. */
  115. define('MATH_BIGINTEGER_DATA', 1);
  116. /**#@-*/
  117. /**#@+
  118. * @access private
  119. * @see Math_BigInteger::Math_BigInteger()
  120. */
  121. /**
  122. * To use the pure-PHP implementation
  123. */
  124. define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
  125. /**
  126. * To use the BCMath library
  127. *
  128. * (if enabled; otherwise, the internal implementation will be used)
  129. */
  130. define('MATH_BIGINTEGER_MODE_BCMATH', 2);
  131. /**
  132. * To use the GMP library
  133. *
  134. * (if present; otherwise, either the BCMath or the internal implementation will be used)
  135. */
  136. define('MATH_BIGINTEGER_MODE_GMP', 3);
  137. /**#@-*/
  138. /**
  139. * Pure-PHP arbitrary precission integer arithmetic library. Supports base-2, base-10, base-16, and base-256
  140. * numbers. Negative numbers are supported in all publically accessable functions save for modPow
  141. * and modInverse.
  142. *
  143. * @author Jim Wigginton <terrafrost@php.net>
  144. * @version 1.0.0RC3
  145. * @access public
  146. * @package Math_BigInteger
  147. */
  148. class Math_BigInteger {
  149. /**
  150. * Holds the BigInteger's value.
  151. *
  152. * @var Array
  153. * @access private
  154. */
  155. var $value;
  156. /**
  157. * Holds the BigInteger's magnitude.
  158. *
  159. * @var Boolean
  160. * @access private
  161. */
  162. var $is_negative = false;
  163. /**
  164. * Converts base-2, base-10, base-16, and binary strings (eg. base-256) to BigIntegers.
  165. *
  166. * Here's a quick 'n dirty example:
  167. * <code>
  168. * <?php
  169. * include('Math/BigInteger.php');
  170. *
  171. * $a = new Math_BigInteger('0x32', 16); // 50 in base-16
  172. *
  173. * echo $a->toString(); // outputs 50
  174. * ?>
  175. * </code>
  176. *
  177. * @param optional $x base-10 number or base-$base number if $base set.
  178. * @param optional integer $base
  179. * @return Math_BigInteger
  180. * @access public
  181. */
  182. function Math_BigInteger($x = 0, $base = 10)
  183. {
  184. if ( !defined('MATH_BIGINTEGER_MODE') ) {
  185. switch (true) {
  186. case extension_loaded('gmp'):
  187. define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
  188. break;
  189. case extension_loaded('bcmath'):
  190. define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
  191. break;
  192. default:
  193. define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
  194. }
  195. }
  196. switch ( MATH_BIGINTEGER_MODE ) {
  197. case MATH_BIGINTEGER_MODE_GMP:
  198. $this->value = gmp_init(0);
  199. break;
  200. case MATH_BIGINTEGER_MODE_BCMATH:
  201. $this->value = '0';
  202. break;
  203. default:
  204. $this->value = array();
  205. }
  206. if ($x === 0) {
  207. return;
  208. }
  209. switch ($base) {
  210. case 256:
  211. switch ( MATH_BIGINTEGER_MODE ) {
  212. case MATH_BIGINTEGER_MODE_GMP:
  213. $temp = unpack('H*hex', $x);
  214. $this->value = gmp_init('0x' . $temp['hex']);
  215. break;
  216. case MATH_BIGINTEGER_MODE_BCMATH:
  217. $len = strlen($x);
  218. $len+= (3 * $len) % 4; // rounds $len to the nearest 4.
  219. $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
  220. for ($i = 0; $i < $len; $i+= 4) {
  221. $this->value = bcmul($this->value, '4294967296'); // 4294967296 == 2**32
  222. $this->value = bcadd($this->value, 0x1000000 * ord($x{$i}) + ((ord($x{$i + 1}) << 16) | (ord($x{$i + 2}) << 8) | ord($x{$i + 3})));
  223. }
  224. break;
  225. // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
  226. case MATH_BIGINTEGER_MODE_INTERNAL:
  227. while (strlen($x)) {
  228. $this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26));
  229. }
  230. }
  231. break;
  232. case 16:
  233. if ($x{0} == '-') {
  234. $this->is_negative = true;
  235. $x = substr($x, 1);
  236. }
  237. $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
  238. switch ( MATH_BIGINTEGER_MODE ) {
  239. case MATH_BIGINTEGER_MODE_GMP:
  240. $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
  241. $this->value = gmp_init($temp);
  242. $this->is_negative = false;
  243. break;
  244. case MATH_BIGINTEGER_MODE_BCMATH:
  245. $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
  246. $temp = new Math_BigInteger(pack('H*', $x), 256);
  247. $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
  248. $this->is_negative = false;
  249. break;
  250. case MATH_BIGINTEGER_MODE_INTERNAL:
  251. $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
  252. $temp = new Math_BigInteger(pack('H*', $x), 256);
  253. $this->value = $temp->value;
  254. }
  255. break;
  256. case 10:
  257. $x = preg_replace('#^(-?[0-9]*).*#','$1',$x);
  258. switch ( MATH_BIGINTEGER_MODE ) {
  259. case MATH_BIGINTEGER_MODE_GMP:
  260. $this->value = gmp_init($x);
  261. break;
  262. case MATH_BIGINTEGER_MODE_BCMATH:
  263. // explicitly casting $x to a string is necessary, here, since doing $x{0} on -1 yields different
  264. // results then doing it on '-1' does (modInverse does $x{0})
  265. $this->value = (string) $x;
  266. break;
  267. case MATH_BIGINTEGER_MODE_INTERNAL:
  268. $temp = new Math_BigInteger();
  269. // array(10000000) is 10**7 in base-2**26. 10**7 is the closest to 2**26 we can get without passing it.
  270. $multiplier = new Math_BigInteger();
  271. $multiplier->value = array(10000000);
  272. if ($x{0} == '-') {
  273. $this->is_negative = true;
  274. $x = substr($x, 1);
  275. }
  276. $x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT);
  277. while (strlen($x)) {
  278. $temp = $temp->multiply($multiplier);
  279. $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256));
  280. $x = substr($x, 7);
  281. }
  282. $this->value = $temp->value;
  283. }
  284. break;
  285. case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
  286. if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP) {
  287. $this->value = gmp_init($x, 2);
  288. break;
  289. }
  290. if ($x{0} == '-') {
  291. $this->is_negative = true;
  292. $x = substr($x, 1);
  293. }
  294. $x = preg_replace('#^([01]*).*#', '$1', $x);
  295. $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
  296. $str = '0x';
  297. while (strlen($x)) {
  298. $part = substr($x, 0, 4);
  299. $str.= dechex(bindec($part));
  300. $x = substr($x, 4);
  301. }
  302. $temp = new Math_BigInteger($str, 16);
  303. $this->value = $temp->value;
  304. if (MATH_BINGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH && $this->is_negative) {
  305. $this->value = '-' . $this->value;
  306. $this->is_negative = false;
  307. }
  308. break;
  309. default:
  310. // base not supported, so we'll let $this == 0
  311. }
  312. }
  313. /**
  314. * Converts a BigInteger to a byte string (eg. base-256).
  315. *
  316. * Here's a quick 'n dirty example:
  317. * <code>
  318. * <?php
  319. * include('Math/BigInteger.php');
  320. *
  321. * $a = new Math_BigInteger('65');
  322. *
  323. * echo $a->toBytes(); // outputs chr(65)
  324. * ?>
  325. * </code>
  326. *
  327. * @return String
  328. * @access public
  329. * @internal Converts a base-2**26 number to base-2**8
  330. */
  331. function toBytes()
  332. {
  333. switch ( MATH_BIGINTEGER_MODE ) {
  334. case MATH_BIGINTEGER_MODE_GMP:
  335. if (gmp_cmp($this->value, gmp_init(0)) == 0) {
  336. return '';
  337. }
  338. $temp = gmp_strval(gmp_abs($this->value), 16);
  339. $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
  340. return ltrim(pack('H*', $temp), chr(0));
  341. case MATH_BIGINTEGER_MODE_BCMATH:
  342. if ($this->value === '0') {
  343. return '';
  344. }
  345. $value = '';
  346. $current = $this->value;
  347. // we don't do four bytes at a time because then numbers larger than 1<<31 would be negative
  348. // two's complimented numbers, which would break chr.
  349. while (bccomp($current, '0') > 0) {
  350. $temp = bcmod($current, 0x1000000);
  351. $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
  352. $current = bcdiv($current, 0x1000000);
  353. }
  354. return ltrim($value, chr(0));
  355. }
  356. if (!count($this->value)) {
  357. return '';
  358. }
  359. $result = $this->_int2bytes($this->value[count($this->value) - 1]);
  360. $temp = $this->_copy();
  361. for ($i = count($temp->value) - 2; $i >= 0; $i--) {
  362. $temp->_base256_lshift($result, 26);
  363. $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
  364. }
  365. return $result;
  366. }
  367. /**
  368. * Converts a BigInteger to a base-10 number.
  369. *
  370. * Here's a quick 'n dirty example:
  371. * <code>
  372. * <?php
  373. * include('Math/BigInteger.php');
  374. *
  375. * $a = new Math_BigInteger('50');
  376. *
  377. * echo $a->toString(); // outputs 50
  378. * ?>
  379. * </code>
  380. *
  381. * @return String
  382. * @access public
  383. * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
  384. */
  385. function toString()
  386. {
  387. switch ( MATH_BIGINTEGER_MODE ) {
  388. case MATH_BIGINTEGER_MODE_GMP:
  389. return gmp_strval($this->value);
  390. case MATH_BIGINTEGER_MODE_BCMATH:
  391. if ($this->value === '0') {
  392. return '0';
  393. }
  394. return ltrim($this->value, '0');
  395. }
  396. if (!count($this->value)) {
  397. return '0';
  398. }
  399. $result = ($this->is_negative) ? '-' : '';
  400. $temp = $this->_copy();
  401. $divisor = new Math_BigInteger();
  402. $divisor->value = array(10000000); // eg. 10**7
  403. while (count($temp->value)) {
  404. list($temp, $mod) = $temp->divide($divisor);
  405. $result = str_pad($this->_bytes2int($mod->toBytes()), 7, '0', STR_PAD_LEFT) . $result;
  406. }
  407. return ltrim($result, '0');
  408. }
  409. /**
  410. * Adds two BigIntegers.
  411. *
  412. * Here's a quick 'n dirty example:
  413. * <code>
  414. * <?php
  415. * include('Math/BigInteger.php');
  416. *
  417. * $a = new Math_BigInteger('10');
  418. * $b = new Math_BigInteger('20');
  419. *
  420. * $c = $a->add($b);
  421. *
  422. * echo $c->toString(); // outputs 30
  423. * ?>
  424. * </code>
  425. *
  426. * @param Math_BigInteger $y
  427. * @return Math_BigInteger
  428. * @access public
  429. * @internal Performs base-2**52 addition
  430. */
  431. function add($y)
  432. {
  433. switch ( MATH_BIGINTEGER_MODE ) {
  434. case MATH_BIGINTEGER_MODE_GMP:
  435. $temp = new Math_BigInteger();
  436. $temp->value = gmp_add($this->value, $y->value);
  437. return $temp;
  438. case MATH_BIGINTEGER_MODE_BCMATH:
  439. $temp = new Math_BigInteger();
  440. $temp->value = bcadd($this->value, $y->value);
  441. return $temp;
  442. }
  443. // subtract, if appropriate
  444. if ( $this->is_negative != $y->is_negative ) {
  445. // is $y the negative number?
  446. $y_negative = $this->compare($y) > 0;
  447. $temp = $this->_copy();
  448. $y = $y->_copy();
  449. $temp->is_negative = $y->is_negative = false;
  450. $diff = $temp->compare($y);
  451. if ( !$diff ) {
  452. return new Math_BigInteger();
  453. }
  454. $temp = $temp->subtract($y);
  455. $temp->is_negative = ($diff > 0) ? !$y_negative : $y_negative;
  456. return $temp;
  457. }
  458. $result = new Math_BigInteger();
  459. $carry = 0;
  460. $size = max(count($this->value), count($y->value));
  461. $size+= $size % 2; // rounds $size to the nearest 2.
  462. $x = array_pad($this->value, $size,0);
  463. $y = array_pad($y->value, $size, 0);
  464. for ($i = 0; $i < $size - 1; $i+=2) {
  465. $sum = $x[$i + 1] * 0x4000000 + $x[$i] + $y[$i + 1] * 0x4000000 + $y[$i] + $carry;
  466. $carry = $sum >= 4503599627370496; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
  467. $sum = $carry ? $sum - 4503599627370496 : $sum;
  468. $temp = floor($sum / 0x4000000);
  469. $result->value[] = $sum - 0x4000000 * $temp; // eg. a faster alternative to fmod($sum, 0x4000000)
  470. $result->value[] = $temp;
  471. }
  472. if ($carry) {
  473. $result->value[] = $carry;
  474. }
  475. $result->is_negative = $this->is_negative;
  476. return $result->_normalize();
  477. }
  478. /**
  479. * Subtracts two BigIntegers.
  480. *
  481. * Here's a quick 'n dirty example:
  482. * <code>
  483. * <?php
  484. * include('Math/BigInteger.php');
  485. *
  486. * $a = new Math_BigInteger('10');
  487. * $b = new Math_BigInteger('20');
  488. *
  489. * $c = $a->subtract($b);
  490. *
  491. * echo $c->toString(); // outputs -10
  492. * ?>
  493. * </code>
  494. *
  495. * @param Math_BigInteger $y
  496. * @return Math_BigInteger
  497. * @access public
  498. * @internal Performs base-2**52 subtraction
  499. */
  500. function subtract($y)
  501. {
  502. switch ( MATH_BIGINTEGER_MODE ) {
  503. case MATH_BIGINTEGER_MODE_GMP:
  504. $temp = new Math_BigInteger();
  505. $temp->value = gmp_sub($this->value, $y->value);
  506. return $temp;
  507. case MATH_BIGINTEGER_MODE_BCMATH:
  508. $temp = new Math_BigInteger();
  509. $temp->value = bcsub($this->value, $y->value);
  510. return $temp;
  511. }
  512. // add, if appropriate
  513. if ( $this->is_negative != $y->is_negative ) {
  514. $is_negative = $y->compare($this) > 0;
  515. $temp = $this->_copy();
  516. $y = $y->_copy();
  517. $temp->is_negative = $y->is_negative = false;
  518. $temp = $temp->add($y);
  519. $temp->is_negative = $is_negative;
  520. return $temp;
  521. }
  522. $diff = $this->compare($y);
  523. if ( !$diff ) {
  524. return new Math_BigInteger();
  525. }
  526. // switch $this and $y around, if appropriate.
  527. if ( (!$this->is_negative && $diff < 0) || ($this->is_negative && $diff > 0) ) {
  528. $is_negative = $y->is_negative;
  529. $temp = $this->_copy();
  530. $y = $y->_copy();
  531. $temp->is_negative = $y->is_negative = false;
  532. $temp = $y->subtract($temp);
  533. $temp->is_negative = !$is_negative;
  534. return $temp;
  535. }
  536. $result = new Math_BigInteger();
  537. $carry = 0;
  538. $size = max(count($this->value), count($y->value));
  539. $size+= $size % 2;
  540. $x = array_pad($this->value, $size, 0);
  541. $y = array_pad($y->value, $size, 0);
  542. for ($i = 0; $i < $size - 1;$i+=2) {
  543. $sum = $x[$i + 1] * 0x4000000 + $x[$i] - $y[$i + 1] * 0x4000000 - $y[$i] + $carry;
  544. $carry = $sum < 0 ? -1 : 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
  545. $sum = $carry ? $sum + 4503599627370496 : $sum;
  546. $temp = floor($sum / 0x4000000);
  547. $result->value[] = $sum - 0x4000000 * $temp;
  548. $result->value[] = $temp;
  549. }
  550. // $carry shouldn't be anything other than zero, at this point, since we already made sure that $this
  551. // was bigger than $y.
  552. $result->is_negative = $this->is_negative;
  553. return $result->_normalize();
  554. }
  555. /**
  556. * Multiplies two BigIntegers
  557. *
  558. * Here's a quick 'n dirty example:
  559. * <code>
  560. * <?php
  561. * include('Math/BigInteger.php');
  562. *
  563. * $a = new Math_BigInteger('10');
  564. * $b = new Math_BigInteger('20');
  565. *
  566. * $c = $a->multiply($b);
  567. *
  568. * echo $c->toString(); // outputs 200
  569. * ?>
  570. * </code>
  571. *
  572. * @param Math_BigInteger $x
  573. * @return Math_BigInteger
  574. * @access public
  575. * @internal Modeled after 'multiply' in MutableBigInteger.java.
  576. */
  577. function multiply($x)
  578. {
  579. switch ( MATH_BIGINTEGER_MODE ) {
  580. case MATH_BIGINTEGER_MODE_GMP:
  581. $temp = new Math_BigInteger();
  582. $temp->value = gmp_mul($this->value, $x->value);
  583. return $temp;
  584. case MATH_BIGINTEGER_MODE_BCMATH:
  585. $temp = new Math_BigInteger();
  586. $temp->value = bcmul($this->value, $x->value);
  587. return $temp;
  588. }
  589. if ( !$this->compare($x) ) {
  590. return $this->_square();
  591. }
  592. $this_length = count($this->value);
  593. $x_length = count($x->value);
  594. if ( !$this_length || !$x_length ) { // a 0 is being multiplied
  595. return new Math_BigInteger();
  596. }
  597. $product = new Math_BigInteger();
  598. $product->value = $this->_array_repeat(0, $this_length + $x_length);
  599. // the following for loop could be removed if the for loop following it
  600. // (the one with nested for loops) initially set $i to 0, but
  601. // doing so would also make the result in one set of unnecessary adds,
  602. // since on the outermost loops first pass, $product->value[$k] is going
  603. // to always be 0
  604. $carry = 0;
  605. $i = 0;
  606. for ($j = 0, $k = $i; $j < $this_length; $j++, $k++) {
  607. $temp = $product->value[$k] + $this->value[$j] * $x->value[$i] + $carry;
  608. $carry = floor($temp / 0x4000000);
  609. $product->value[$k] = $temp - 0x4000000 * $carry;
  610. }
  611. $product->value[$k] = $carry;
  612. // the above for loop is what the previous comment was talking about. the
  613. // following for loop is the "one with nested for loops"
  614. for ($i = 1; $i < $x_length; $i++) {
  615. $carry = 0;
  616. for ($j = 0, $k = $i; $j < $this_length; $j++, $k++) {
  617. $temp = $product->value[$k] + $this->value[$j] * $x->value[$i] + $carry;
  618. $carry = floor($temp / 0x4000000);
  619. $product->value[$k] = $temp - 0x4000000 * $carry;
  620. }
  621. $product->value[$k] = $carry;
  622. }
  623. $product->is_negative = $this->is_negative != $x->is_negative;
  624. return $product->_normalize();
  625. }
  626. /**
  627. * Squares a BigInteger
  628. *
  629. * Squaring can be done faster than multiplying a number by itself can be. See
  630. * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
  631. * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
  632. *
  633. * @return Math_BigInteger
  634. * @access private
  635. */
  636. function _square()
  637. {
  638. if ( empty($this->value) ) {
  639. return new Math_BigInteger();
  640. }
  641. $max_index = count($this->value) - 1;
  642. $square = new Math_BigInteger();
  643. $square->value = $this->_array_repeat(0, 2 * $max_index);
  644. for ($i = 0; $i <= $max_index; $i++) {
  645. $temp = $square->value[2 * $i] + $this->value[$i] * $this->value[$i];
  646. $carry = floor($temp / 0x4000000);
  647. $square->value[2 * $i] = $temp - 0x4000000 * $carry;
  648. // note how we start from $i+1 instead of 0 as we do in multiplication.
  649. for ($j = $i + 1; $j <= $max_index; $j++) {
  650. $temp = $square->value[$i + $j] + 2 * $this->value[$j] * $this->value[$i] + $carry;
  651. $carry = floor($temp / 0x4000000);
  652. $square->value[$i + $j] = $temp - 0x4000000 * $carry;
  653. }
  654. // the following line can yield values larger 2**15. at this point, PHP should switch
  655. // over to floats.
  656. $square->value[$i + $max_index + 1] = $carry;
  657. }
  658. return $square->_normalize();
  659. }
  660. /**
  661. * Divides two BigIntegers.
  662. *
  663. * Returns an array whose first element contains the quotient and whose second element contains the
  664. * "common residue". If the remainder would be positive, the "common residue" and the remainder are the
  665. * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
  666. * and the divisor.
  667. *
  668. * Here's a quick 'n dirty example:
  669. * <code>
  670. * <?php
  671. * include('Math/BigInteger.php');
  672. *
  673. * $a = new Math_BigInteger('10');
  674. * $b = new Math_BigInteger('20');
  675. *
  676. * list($quotient,$remainder) = $a->divide($b);
  677. *
  678. * echo $quotient->toString(); // outputs 0
  679. * echo "\r\n";
  680. * echo $remainder->toString(); // outputs 10
  681. * ?>
  682. * </code>
  683. *
  684. * @param Math_BigInteger $y
  685. * @return Array
  686. * @access public
  687. * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}
  688. * with a slight variation due to the fact that this script, initially, did not support negative numbers. Now,
  689. * it does, but I don't want to change that which already works.
  690. */
  691. function divide($y)
  692. {
  693. switch ( MATH_BIGINTEGER_MODE ) {
  694. case MATH_BIGINTEGER_MODE_GMP:
  695. $quotient = new Math_BigInteger();
  696. $remainder = new Math_BigInteger();
  697. list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
  698. if (gmp_sign($remainder->value) < 0) {
  699. $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
  700. }
  701. return array($quotient, $remainder);
  702. case MATH_BIGINTEGER_MODE_BCMATH:
  703. $quotient = new Math_BigInteger();
  704. $remainder = new Math_BigInteger();
  705. $quotient->value = bcdiv($this->value, $y->value);
  706. $remainder->value = bcmod($this->value, $y->value);
  707. if ($remainder->value{0} == '-') {
  708. $remainder->value = bcadd($remainder->value, $y->value{0} == '-' ? substr($y->value,1) : $y->value);
  709. }
  710. return array($quotient, $remainder);
  711. }
  712. $x = $this->_copy();
  713. $y = $y->_copy();
  714. $x_sign = $x->is_negative;
  715. $y_sign = $y->is_negative;
  716. $x->is_negative = $y->is_negative = false;
  717. $diff = $x->compare($y);
  718. if ( !$diff ) {
  719. $temp = new Math_BigInteger();
  720. $temp->value = array(1);
  721. $temp->is_negative = $x_sign != $y_sign;
  722. return array($temp, new Math_BigInteger());
  723. }
  724. if ( $diff < 0 ) {
  725. // if $x is negative, "add" $y.
  726. if ( $x_sign ) {
  727. $x = $y->subtract($x);
  728. }
  729. return array(new Math_BigInteger(), $x);
  730. }
  731. // normalize $x and $y as described in HAC 14.23 / 14.24
  732. // (incidently, i haven't been able to find a definitive example showing that this
  733. // results in worth-while speedup, but whatever)
  734. $msb = $y->value[count($y->value) - 1];
  735. for ($shift = 0; !($msb & 0x2000000); $shift++) {
  736. $msb <<= 1;
  737. }
  738. $x->_lshift($shift);
  739. $y->_lshift($shift);
  740. $x_max = count($x->value) - 1;
  741. $y_max = count($y->value) - 1;
  742. $quotient = new Math_BigInteger();
  743. $quotient->value = $this->_array_repeat(0, $x_max - $y_max + 1);
  744. // $temp = $y << ($x_max - $y_max-1) in base 2**26
  745. $temp = new Math_BigInteger();
  746. $temp->value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y->value);
  747. while ( $x->compare($temp) >= 0 ) {
  748. // calculate the "common residue"
  749. $quotient->value[$x_max - $y_max]++;
  750. $x = $x->subtract($temp);
  751. $x_max = count($x->value) - 1;
  752. }
  753. for ($i = $x_max; $i >= $y_max + 1; $i--) {
  754. $x_value = array(
  755. $x->value[$i],
  756. ( $i > 0 ) ? $x->value[$i - 1] : 0,
  757. ( $i - 1 > 0 ) ? $x->value[$i - 2] : 0
  758. );
  759. $y_value = array(
  760. $y->value[$y_max],
  761. ( $y_max > 0 ) ? $y_max - 1 : 0
  762. );
  763. $q_index = $i - $y_max - 1;
  764. if ($x_value[0] == $y_value[0]) {
  765. $quotient->value[$q_index] = 0x3FFFFFF;
  766. } else {
  767. $quotient->value[$q_index] = floor(
  768. ($x_value[0] * 0x4000000 + $x_value[1])
  769. /
  770. $y_value[0]
  771. );
  772. }
  773. $temp = new Math_BigInteger();
  774. $temp->value = array($y_value[1], $y_value[0]);
  775. $lhs = new Math_BigInteger();
  776. $lhs->value = array($quotient->value[$q_index]);
  777. $lhs = $lhs->multiply($temp);
  778. $rhs = new Math_BigInteger();
  779. $rhs->value = array($x_value[2], $x_value[1], $x_value[0]);
  780. while ( $lhs->compare($rhs) > 0 ) {
  781. $quotient->value[$q_index]--;
  782. $lhs = new Math_BigInteger();
  783. $lhs->value = array($quotient->value[$q_index]);
  784. $lhs = $lhs->multiply($temp);
  785. }
  786. $corrector = new Math_BigInteger();
  787. $temp = new Math_BigInteger();
  788. $corrector->value = $temp->value = $this->_array_repeat(0, $q_index);
  789. $temp->value[] = $quotient->value[$q_index];
  790. $temp = $temp->multiply($y);
  791. if ( $x->compare($temp) < 0 ) {
  792. $corrector->value[] = 1;
  793. $x = $x->add($corrector->multiply($y));
  794. $quotient->value[$q_index]--;
  795. }
  796. $x = $x->subtract($temp);
  797. $x_max = count($x->value) - 1;
  798. }
  799. // unnormalize the remainder
  800. $x->_rshift($shift);
  801. $quotient->is_negative = $x_sign != $y_sign;
  802. // calculate the "common residue", if appropriate
  803. if ( $x_sign ) {
  804. $y->_rshift($shift);
  805. $x = $y->subtract($x);
  806. }
  807. return array($quotient->_normalize(), $x);
  808. }
  809. /**
  810. * Performs modular exponentiation.
  811. *
  812. * Here's a quick 'n dirty example:
  813. * <code>
  814. * <?php
  815. * include('Math/BigInteger.php');
  816. *
  817. * $a = new Math_BigInteger('10');
  818. * $b = new Math_BigInteger('20');
  819. * $c = new Math_BigInteger('30');
  820. *
  821. * $c = $a->modPow($b, $c);
  822. *
  823. * echo $c->toString(); // outputs 10
  824. * ?>
  825. * </code>
  826. *
  827. * @param Math_BigInteger $e
  828. * @param Math_BigInteger $n
  829. * @return Math_BigInteger
  830. * @access public
  831. * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
  832. * and although the approach involving repeated squaring does vastly better, it, too, is impractical
  833. * for our purposes. The reason being that division - by far the most complicated and time-consuming
  834. * of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
  835. *
  836. * Modular reductions resolve this issue. Although an individual modular reduction takes more time
  837. * then an individual division, when performed in succession (with the same modulo), they're a lot faster.
  838. *
  839. * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
  840. * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
  841. * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
  842. * the product of two odd numbers is odd), but what about when RSA isn't used?
  843. *
  844. * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
  845. * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
  846. * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
  847. * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
  848. * the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
  849. * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
  850. */
  851. function modPow($e, $n)
  852. {
  853. $n = $n->abs();
  854. if ($e->compare(new Math_BigInteger()) < 0) {
  855. $e = $e->abs();
  856. $temp = $this->modInverse($n);
  857. if ($temp === false) {
  858. return false;
  859. }
  860. return $temp->modPow($e,$n);
  861. }
  862. switch ( MATH_BIGINTEGER_MODE ) {
  863. case MATH_BIGINTEGER_MODE_GMP:
  864. $temp = new Math_BigInteger();
  865. $temp->value = gmp_powm($this->value, $e->value, $n->value);
  866. return $temp;
  867. case MATH_BIGINTEGER_MODE_BCMATH:
  868. // even though the last parameter is optional, according to php.net, it's not optional in
  869. // PHP_Compat 1.5.0 when running PHP 4.
  870. $temp = new Math_BigInteger();
  871. $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
  872. return $temp;
  873. }
  874. if ( empty($e->value) ) {
  875. $temp = new Math_BigInteger();
  876. $temp->value = array(1);
  877. return $temp;
  878. }
  879. if ( $e->value == array(1) ) {
  880. list(, $temp) = $this->divide($n);
  881. return $temp;
  882. }
  883. if ( $e->value == array(2) ) {
  884. $temp = $this->_square();
  885. list(, $temp) = $temp->divide($n);
  886. return $temp;
  887. }
  888. // is the modulo odd?
  889. if ( $n->value[0] & 1 ) {
  890. return $this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY);
  891. }
  892. // if it's not, it's even
  893. // find the lowest set bit (eg. the max pow of 2 that divides $n)
  894. for ($i = 0; $i < count($n->value); $i++) {
  895. if ( $n->value[$i] ) {
  896. $temp = decbin($n->value[$i]);
  897. $j = strlen($temp) - strrpos($temp, '1') - 1;
  898. $j+= 26 * $i;
  899. break;
  900. }
  901. }
  902. // at this point, 2^$j * $n/(2^$j) == $n
  903. $mod1 = $n->_copy();
  904. $mod1->_rshift($j);
  905. $mod2 = new Math_BigInteger();
  906. $mod2->value = array(1);
  907. $mod2->_lshift($j);
  908. $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
  909. $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
  910. $y1 = $mod2->modInverse($mod1);
  911. $y2 = $mod1->modInverse($mod2);
  912. $result = $part1->multiply($mod2);
  913. $result = $result->multiply($y1);
  914. $temp = $part2->multiply($mod1);
  915. $temp = $temp->multiply($y2);
  916. $result = $result->add($temp);
  917. list(, $result) = $result->divide($n);
  918. return $result;
  919. }
  920. /**
  921. * Sliding Window k-ary Modular Exponentiation
  922. *
  923. * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
  924. * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims,
  925. * however, this function performs a modular reduction after every multiplication and squaring operation.
  926. * As such, this function has the same preconditions that the reductions being used do.
  927. *
  928. * The window size is calculated in the same fashion that the window size in BigInteger.java's oddModPow
  929. * function is.
  930. *
  931. * @param Math_BigInteger $e
  932. * @param Math_BigInteger $n
  933. * @param Integer $mode
  934. * @return Math_BigInteger
  935. * @access private
  936. */
  937. function _slidingWindow($e, $n, $mode)
  938. {
  939. static $window_ranges = array(7, 25, 81, 241, 673, 1793);
  940. $e_length = count($e->value) - 1;
  941. $e_bits = decbin($e->value[$e_length]);
  942. for ($i = $e_length - 1; $i >= 0; $i--) {
  943. $e_bits.= str_pad(decbin($e->value[$i]), 26, '0', STR_PAD_LEFT);
  944. }
  945. $e_length = strlen($e_bits);
  946. // calculate the appropriate window size.
  947. // $window_size == 3 if $window_ranges is between 25 and 81, for example.
  948. for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); $window_size++, $i++);
  949. switch ($mode) {
  950. case MATH_BIGINTEGER_MONTGOMERY:
  951. $reduce = '_montgomery';
  952. $undo = '_undoMontgomery';
  953. break;
  954. case MATH_BIGINTEGER_BARRETT:
  955. $reduce = '_barrett';
  956. $undo = '_barrett';
  957. break;
  958. case MATH_BIGINTEGER_POWEROF2:
  959. $reduce = '_mod2';
  960. $undo = '_mod2';
  961. break;
  962. case MATH_BIGINTEGER_CLASSIC:
  963. $reduce = '_remainder';
  964. $undo = '_remainder';
  965. break;
  966. case MATH_BIGINTEGER_NONE:
  967. // ie. do no modular reduction. useful if you want to just do pow as opposed to modPow.
  968. $reduce = '_copy';
  969. $undo = '_copy';
  970. break;
  971. default:
  972. // an invalid $mode was provided
  973. }
  974. // precompute $this^0 through $this^$window_size
  975. $powers = array();
  976. $powers[1] = $this->$undo($n);
  977. $powers[2] = $powers[1]->_square();
  978. $powers[2] = $powers[2]->$reduce($n);
  979. // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
  980. // in a 1. ie. it's supposed to be odd.
  981. $temp = 1 << ($window_size - 1);
  982. for ($i = 1; $i < $temp; $i++) {
  983. $powers[2 * $i + 1] = $powers[2 * $i - 1]->multiply($powers[2]);
  984. $powers[2 * $i + 1] = $powers[2 * $i + 1]->$reduce($n);
  985. }
  986. $result = new Math_BigInteger();
  987. $result->value = array(1);
  988. $result = $result->$undo($n);
  989. for ($i = 0; $i < $e_length; ) {
  990. if ( !$e_bits{$i} ) {
  991. $result = $result->_square();
  992. $result = $result->$reduce($n);
  993. $i++;
  994. } else {
  995. for ($j = $window_size - 1; $j >= 0; $j--) {
  996. if ( $e_bits{$i + $j} ) {
  997. break;
  998. }
  999. }
  1000. for ($k = 0; $k <= $j; $k++) {// eg. the length of substr($e_bits, $i, $j+1)
  1001. $result = $result->_square();
  1002. $result = $result->$reduce($n);
  1003. }
  1004. $result = $result->multiply($powers[bindec(substr($e_bits, $i, $j + 1))]);
  1005. $result = $result->$reduce($n);
  1006. $i+=$j + 1;
  1007. }
  1008. }
  1009. $result = $result->$reduce($n);
  1010. return $result->_normalize();
  1011. }
  1012. /**
  1013. * Remainder
  1014. *
  1015. * A wrapper for the divide function.
  1016. *
  1017. * @see divide()
  1018. * @see _slidingWindow()
  1019. * @access private
  1020. * @param Math_BigInteger
  1021. * @return Math_BigInteger
  1022. */
  1023. function _remainder($n)
  1024. {
  1025. list(, $temp) = $this->divide($n);
  1026. return $temp;
  1027. }
  1028. /**
  1029. * Modulos for Powers of Two
  1030. *
  1031. * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
  1032. * we'll just use this function as a wrapper for doing that.
  1033. *
  1034. * @see _slidingWindow()
  1035. * @access private
  1036. * @param Math_BigInteger
  1037. * @return Math_BigInteger
  1038. */
  1039. function _mod2($n)
  1040. {
  1041. $temp = new Math_BigInteger();
  1042. $temp->value = array(1);
  1043. return $this->bitwise_and($n->subtract($temp));
  1044. }
  1045. /**
  1046. * Barrett Modular Reduction
  1047. *
  1048. * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
  1049. * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
  1050. * so as not to require negative numbers (initially, this script didn't support negative numbers).
  1051. *
  1052. * @see _slidingWindow()
  1053. * @access private
  1054. * @param Math_BigInteger
  1055. * @return Math_BigInteger
  1056. */
  1057. function _barrett($n)
  1058. {
  1059. static $cache;
  1060. $n_length = count($n->value);
  1061. if ( !isset($cache[MATH_BIGINTEGER_VARIABLE]) || $n->compare($cache[MATH_BIGINTEGER_VARIABLE]) ) {
  1062. $cache[MATH_BIGINTEGER_VARIABLE] = $n;
  1063. $temp = new Math_BigInteger();
  1064. $temp->value = $this->_array_repeat(0, 2 * $n_length);
  1065. $temp->value[] = 1;
  1066. list($cache[MATH_BIGINTEGER_DATA], ) = $temp->divide($n);
  1067. }
  1068. $temp = new Math_BigInteger();
  1069. $temp->value = array_slice($this->value, $n_length - 1);
  1070. $temp = $temp->multiply($cache[MATH_BIGINTEGER_DATA]);
  1071. $temp->value = array_slice($temp->value, $n_length + 1);
  1072. $result = new Math_BigInteger();
  1073. $result->value = array_slice($this->value, 0, $n_length + 1);
  1074. $temp = $temp->multiply($n);
  1075. $temp->value = array_slice($temp->value, 0, $n_length + 1);
  1076. if ($result->compare($temp) < 0) {
  1077. $corrector = new Math_BigInteger();
  1078. $corrector->value = $this->_array_repeat(0, $n_length + 1);
  1079. $corrector->value[] = 1;
  1080. $result = $result->add($corrector);
  1081. }
  1082. $result = $result->subtract($temp);
  1083. while ($result->compare($n) > 0) {
  1084. $result = $result->subtract($n);
  1085. }
  1086. return $result;
  1087. }
  1088. /**
  1089. * Montgomery Modular Reduction
  1090. *
  1091. * ($this->_montgomery($n))->_undoMontgomery($n) yields $x%$n.
  1092. * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
  1093. * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
  1094. * to work correctly.
  1095. *
  1096. * @see _undoMontgomery()
  1097. * @see _slidingWindow()
  1098. * @access private
  1099. * @param Math_BigInteger
  1100. * @return Math_BigInteger
  1101. */
  1102. function _montgomery($n)
  1103. {
  1104. static $cache;
  1105. if ( !isset($cache[MATH_BIGINTEGER_VARIABLE]) || $n->compare($cache[MATH_BIGINTEGER_VARIABLE]) ) {
  1106. $cache[MATH_BIGINTEGER_VARIABLE] = $n;
  1107. $cache[MATH_BIGINTEGER_DATA] = $n->_modInverse67108864();
  1108. }
  1109. $result = $this->_copy();
  1110. $n_length = count($n->value);
  1111. for ($i = 0; $i < $n_length; $i++) {
  1112. $digit = $result->value[$i] * $cache[MATH_BIGINTEGER_DATA];
  1113. $temp = new Math_BigInteger();
  1114. $temp->value = array(
  1115. $digit - floor($digit / 0x4000000) * 0x4000000
  1116. );
  1117. $temp = $temp->multiply($n);
  1118. $temp->value = array_merge($this->_array_repeat(0, $i), $temp->value);
  1119. $result = $result->add($temp);
  1120. }
  1121. $result->value = array_slice($result->value, $n_length);
  1122. if ($result->compare($n) >= 0) {
  1123. $result = $result->subtract($n);
  1124. }
  1125. return $result->_normalize();
  1126. }
  1127. /**
  1128. * Undo Montgomery Modular Reduction
  1129. *
  1130. * @see _montgomery()
  1131. * @see _slidingWindow()
  1132. * @access private
  1133. * @param Math_BigInteger
  1134. * @return Math_BigInteger
  1135. */
  1136. function _undoMontgomery($n)
  1137. {
  1138. $temp = new Math_BigInteger();
  1139. $temp->value = array_merge($this->_array_repeat(0, count($n->value)), $this->value);
  1140. list(, $temp) = $temp->divide($n);
  1141. return $temp->_normalize();
  1142. }
  1143. /**
  1144. * Modular Inverse of a number mod 2**26 (eg. 67108864)
  1145. *
  1146. * Based off of the bnpInvDigit function implemented and justified in the following URL:
  1147. *
  1148. * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
  1149. *
  1150. * The following URL provides more info:
  1151. *
  1152. * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
  1153. *
  1154. * As for why we do all the bitmasking... strange things can happen when converting from flots to ints. For
  1155. * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
  1156. * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarntee that ints aren't
  1157. * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
  1158. * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
  1159. * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
  1160. * 40 bits, which only 64-bit floating points will support.
  1161. *
  1162. * Thanks to Pedro Gimeno Fortea for input!
  1163. *
  1164. * @see _montgomery()
  1165. * @access private
  1166. * @return Integer
  1167. */
  1168. function _modInverse67108864() // 2**26 == 67108864
  1169. {
  1170. $x = -$this->value[0];
  1171. $result = $x & 0x3; // x**-1 mod 2**2
  1172. $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
  1173. $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
  1174. $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
  1175. $result = fmod($result * (2 - fmod($x * $result, 0x4000000)), 0x4000000); // x**-1 mod 2**26
  1176. return $result & 0x3FFFFFF;
  1177. }
  1178. /**
  1179. * Calculates modular inverses.
  1180. *
  1181. * Here's a quick 'n dirty example:
  1182. * <code>
  1183. * <?php
  1184. * include('Math/BigInteger.php');
  1185. *
  1186. * $a = new Math_BigInteger(30);
  1187. * $b = new Math_BigInteger(17);
  1188. *
  1189. * $c = $a->modInverse($b);
  1190. *
  1191. * echo $c->toString(); // outputs 4
  1192. * ?>
  1193. * </code>
  1194. *
  1195. * @param Math_BigInteger $n
  1196. * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise.
  1197. * @access public
  1198. * @internal Calculates the modular inverse of $this mod $n using the binary xGCD algorithim described in
  1199. * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes,
  1200. * the more traditional algorithim requires "relatively costly multiple-precision divisions". See
  1201. * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
  1202. */
  1203. function modInverse($n)
  1204. {
  1205. switch ( MATH_BIGINTEGER_MODE ) {
  1206. case MATH_BIGINTEGER_MODE_GMP:
  1207. $temp = new Math_BigInteger();
  1208. $temp->value = gmp_invert($this->value, $n->value);
  1209. return ( $temp->value === false ) ? false : $temp;
  1210. case MATH_BIGINTEGER_MODE_BCMATH:
  1211. // it might b…

Large files files are truncated, but you can click here to view the full file