]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/OStatus/extlib/Math/BigInteger.php
685e3edd0880851bdfbd5bc32d89a4bd591f49f1
[quix0rs-gnu-social.git] / plugins / OStatus / extlib / Math / BigInteger.php
1 <?php\r
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */\r
3 \r
4 /**\r
5  * Pure-PHP arbitrary precision integer arithmetic library.\r
6  *\r
7  * Supports base-2, base-10, base-16, and base-256 numbers.  Uses the GMP or BCMath extensions, if available,\r
8  * and an internal implementation, otherwise.\r
9  *\r
10  * PHP versions 4 and 5\r
11  *\r
12  * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the \r
13  * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)\r
14  *\r
15  * Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and\r
16  * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction.  Because the largest possible\r
17  * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating\r
18  * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are\r
19  * used.  As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,\r
20  * which only supports integers.  Although this fact will slow this library down, the fact that such a high\r
21  * base is being used should more than compensate.\r
22  *\r
23  * When PHP version 6 is officially released, we'll be able to use 64-bit integers.  This should, once again,\r
24  * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /\r
25  * subtraction).\r
26  *\r
27  * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format.  ie.\r
28  * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)\r
29  *\r
30  * Useful resources are as follows:\r
31  *\r
32  *  - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}\r
33  *  - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}\r
34  *  - Java's BigInteger classes.  See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip\r
35  *\r
36  * Here's an example of how to use this library:\r
37  * <code>\r
38  * <?php\r
39  *    include('Math/BigInteger.php');\r
40  *\r
41  *    $a = new Math_BigInteger(2);\r
42  *    $b = new Math_BigInteger(3);\r
43  *\r
44  *    $c = $a->add($b);\r
45  *\r
46  *    echo $c->toString(); // outputs 5\r
47  * ?>\r
48  * </code>\r
49  *\r
50  * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy\r
51  * of this software and associated documentation files (the "Software"), to deal\r
52  * in the Software without restriction, including without limitation the rights\r
53  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
54  * copies of the Software, and to permit persons to whom the Software is\r
55  * furnished to do so, subject to the following conditions:\r
56  * \r
57  * The above copyright notice and this permission notice shall be included in\r
58  * all copies or substantial portions of the Software.\r
59  * \r
60  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
61  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
62  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
63  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
64  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
65  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
66  * THE SOFTWARE.\r
67  *\r
68  * @category   Math\r
69  * @package    Math_BigInteger\r
70  * @author     Jim Wigginton <terrafrost@php.net>\r
71  * @copyright  MMVI Jim Wigginton\r
72  * @license    http://www.opensource.org/licenses/mit-license.html  MIT License\r
73  * @link       http://pear.php.net/package/Math_BigInteger\r
74  */\r
75 \r
76 /**#@+\r
77  * Reduction constants\r
78  *\r
79  * @access private\r
80  * @see Math_BigInteger::_reduce()\r
81  */\r
82 /**\r
83  * @see Math_BigInteger::_montgomery()\r
84  * @see Math_BigInteger::_prepMontgomery()\r
85  */\r
86 define('MATH_BIGINTEGER_MONTGOMERY', 0);\r
87 /**\r
88  * @see Math_BigInteger::_barrett()\r
89  */\r
90 define('MATH_BIGINTEGER_BARRETT', 1);\r
91 /**\r
92  * @see Math_BigInteger::_mod2()\r
93  */\r
94 define('MATH_BIGINTEGER_POWEROF2', 2);\r
95 /**\r
96  * @see Math_BigInteger::_remainder()\r
97  */\r
98 define('MATH_BIGINTEGER_CLASSIC', 3);\r
99 /**\r
100  * @see Math_BigInteger::__clone()\r
101  */\r
102 define('MATH_BIGINTEGER_NONE', 4);\r
103 /**#@-*/\r
104 \r
105 /**#@+\r
106  * Array constants\r
107  *\r
108  * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and\r
109  * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.\r
110  *\r
111  * @access private\r
112  */\r
113 /**\r
114  * $result[MATH_BIGINTEGER_VALUE] contains the value.\r
115  */\r
116 define('MATH_BIGINTEGER_VALUE', 0);\r
117 /**\r
118  * $result[MATH_BIGINTEGER_SIGN] contains the sign.\r
119  */\r
120 define('MATH_BIGINTEGER_SIGN', 1);\r
121 /**#@-*/\r
122 \r
123 /**#@+\r
124  * @access private\r
125  * @see Math_BigInteger::_montgomery()\r
126  * @see Math_BigInteger::_barrett()\r
127  */\r
128 /**\r
129  * Cache constants\r
130  *\r
131  * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.\r
132  */\r
133 define('MATH_BIGINTEGER_VARIABLE', 0);\r
134 /**\r
135  * $cache[MATH_BIGINTEGER_DATA] contains the cached data.\r
136  */\r
137 define('MATH_BIGINTEGER_DATA', 1);\r
138 /**#@-*/\r
139 \r
140 /**#@+\r
141  * Mode constants.\r
142  *\r
143  * @access private\r
144  * @see Math_BigInteger::Math_BigInteger()\r
145  */\r
146 /**\r
147  * To use the pure-PHP implementation\r
148  */\r
149 define('MATH_BIGINTEGER_MODE_INTERNAL', 1);\r
150 /**\r
151  * To use the BCMath library\r
152  *\r
153  * (if enabled; otherwise, the internal implementation will be used)\r
154  */\r
155 define('MATH_BIGINTEGER_MODE_BCMATH', 2);\r
156 /**\r
157  * To use the GMP library\r
158  *\r
159  * (if present; otherwise, either the BCMath or the internal implementation will be used)\r
160  */\r
161 define('MATH_BIGINTEGER_MODE_GMP', 3);\r
162 /**#@-*/\r
163 \r
164 /**\r
165  * Karatsuba Cutoff\r
166  *\r
167  * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?\r
168  *\r
169  * @access private\r
170  */\r
171 define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);\r
172 \r
173 /**\r
174  * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256\r
175  * numbers.\r
176  *\r
177  * @author  Jim Wigginton <terrafrost@php.net>\r
178  * @version 1.0.0RC4\r
179  * @access  public\r
180  * @package Math_BigInteger\r
181  */\r
182 class Math_BigInteger {\r
183     /**\r
184      * Holds the BigInteger's value.\r
185      *\r
186      * @var Array\r
187      * @access private\r
188      */\r
189     var $value;\r
190 \r
191     /**\r
192      * Holds the BigInteger's magnitude.\r
193      *\r
194      * @var Boolean\r
195      * @access private\r
196      */\r
197     var $is_negative = false;\r
198 \r
199     /**\r
200      * Random number generator function\r
201      *\r
202      * @see setRandomGenerator()\r
203      * @access private\r
204      */\r
205     var $generator = 'mt_rand';\r
206 \r
207     /**\r
208      * Precision\r
209      *\r
210      * @see setPrecision()\r
211      * @access private\r
212      */\r
213     var $precision = -1;\r
214 \r
215     /**\r
216      * Precision Bitmask\r
217      *\r
218      * @see setPrecision()\r
219      * @access private\r
220      */\r
221     var $bitmask = false;\r
222 \r
223     /**\r
224      * Mode independent value used for serialization.\r
225      *\r
226      * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for \r
227      * a variable that'll be serializable regardless of whether or not extensions are being used.  Unlike $this->value,\r
228      * however, $this->hex is only calculated when $this->__sleep() is called.\r
229      *\r
230      * @see __sleep()\r
231      * @see __wakeup()\r
232      * @var String\r
233      * @access private\r
234      */\r
235     var $hex;\r
236 \r
237     /**\r
238      * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.\r
239      *\r
240      * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using\r
241      * two's compliment.  The sole exception to this is -10, which is treated the same as 10 is.\r
242      *\r
243      * Here's an example:\r
244      * <code>\r
245      * &lt;?php\r
246      *    include('Math/BigInteger.php');\r
247      *\r
248      *    $a = new Math_BigInteger('0x32', 16); // 50 in base-16\r
249      *\r
250      *    echo $a->toString(); // outputs 50\r
251      * ?&gt;\r
252      * </code>\r
253      *\r
254      * @param optional $x base-10 number or base-$base number if $base set.\r
255      * @param optional integer $base\r
256      * @return Math_BigInteger\r
257      * @access public\r
258      */\r
259     function Math_BigInteger($x = 0, $base = 10)\r
260     {\r
261         if ( !defined('MATH_BIGINTEGER_MODE') ) {\r
262             switch (true) {\r
263                 case extension_loaded('gmp'):\r
264                     define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);\r
265                     break;\r
266                 case extension_loaded('bcmath'):\r
267                     define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);\r
268                     break;\r
269                 default:\r
270                     define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);\r
271             }\r
272         }\r
273 \r
274         if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {\r
275             define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);\r
276         }\r
277 \r
278         if (!defined('PHP_INT_SIZE')) {\r
279             define('PHP_INT_SIZE', 4);\r
280         }\r
281 \r
282         if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {\r
283             switch (PHP_INT_SIZE) {\r
284                 case 8: // use 64-bit integers if int size is 8 bytes\r
285                     define('MATH_BIGINTEGER_BASE',       31);\r
286                     define('MATH_BIGINTEGER_BASE_FULL',  0x80000000);\r
287                     define('MATH_BIGINTEGER_MAX_DIGIT',  0x7FFFFFFF);\r
288                     define('MATH_BIGINTEGER_MSB',        0x40000000);\r
289                     // 10**9 is the closest we can get to 2**31 without passing it\r
290                     define('MATH_BIGINTEGER_MAX10',      1000000000);\r
291                     define('MATH_BIGINTEGER_MAX10_LEN',  9);\r
292                     // the largest digit that may be used in addition / subtraction\r
293                     define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62));\r
294                     break;\r
295                 //case 4: // use 64-bit floats if int size is 4 bytes\r
296                 default:\r
297                     define('MATH_BIGINTEGER_BASE',       26);\r
298                     define('MATH_BIGINTEGER_BASE_FULL',  0x4000000);\r
299                     define('MATH_BIGINTEGER_MAX_DIGIT',  0x3FFFFFF);\r
300                     define('MATH_BIGINTEGER_MSB',        0x2000000);\r
301                     // 10**7 is the closest to 2**26 without passing it\r
302                     define('MATH_BIGINTEGER_MAX10',      10000000);\r
303                     define('MATH_BIGINTEGER_MAX10_LEN',  7);\r
304                     // the largest digit that may be used in addition / subtraction\r
305                     // we do pow(2, 52) instead of using 4503599627370496 directly because some\r
306                     // PHP installations will truncate 4503599627370496.\r
307                     define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52));\r
308             }\r
309         }\r
310 \r
311         switch ( MATH_BIGINTEGER_MODE ) {\r
312             case MATH_BIGINTEGER_MODE_GMP:\r
313                 if (is_resource($x) && get_resource_type($x) == 'GMP integer') {\r
314                     $this->value = $x;\r
315                     return;\r
316                 }\r
317                 $this->value = gmp_init(0);\r
318                 break;\r
319             case MATH_BIGINTEGER_MODE_BCMATH:\r
320                 $this->value = '0';\r
321                 break;\r
322             default:\r
323                 $this->value = array();\r
324         }\r
325 \r
326         // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48\r
327         // '0' is the only value like this per http://php.net/empty\r
328         if (empty($x) && (abs($base) != 256 || $x !== '0')) {\r
329             return;\r
330         }\r
331 \r
332         switch ($base) {\r
333             case -256:\r
334                 if (ord($x[0]) & 0x80) {\r
335                     $x = ~$x;\r
336                     $this->is_negative = true;\r
337                 }\r
338             case  256:\r
339                 switch ( MATH_BIGINTEGER_MODE ) {\r
340                     case MATH_BIGINTEGER_MODE_GMP:\r
341                         $sign = $this->is_negative ? '-' : '';\r
342                         $this->value = gmp_init($sign . '0x' . bin2hex($x));\r
343                         break;\r
344                     case MATH_BIGINTEGER_MODE_BCMATH:\r
345                         // round $len to the nearest 4 (thanks, DavidMJ!)\r
346                         $len = (strlen($x) + 3) & 0xFFFFFFFC;\r
347 \r
348                         $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);\r
349 \r
350                         for ($i = 0; $i < $len; $i+= 4) {\r
351                             $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32\r
352                             $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);\r
353                         }\r
354 \r
355                         if ($this->is_negative) {\r
356                             $this->value = '-' . $this->value;\r
357                         }\r
358 \r
359                         break;\r
360                     // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)\r
361                     default:\r
362                         while (strlen($x)) {\r
363                             $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));\r
364                         }\r
365                 }\r
366 \r
367                 if ($this->is_negative) {\r
368                     if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {\r
369                         $this->is_negative = false;\r
370                     }\r
371                     $temp = $this->add(new Math_BigInteger('-1'));\r
372                     $this->value = $temp->value;\r
373                 }\r
374                 break;\r
375             case  16:\r
376             case -16:\r
377                 if ($base > 0 && $x[0] == '-') {\r
378                     $this->is_negative = true;\r
379                     $x = substr($x, 1);\r
380                 }\r
381 \r
382                 $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);\r
383 \r
384                 $is_negative = false;\r
385                 if ($base < 0 && hexdec($x[0]) >= 8) {\r
386                     $this->is_negative = $is_negative = true;\r
387                     $x = bin2hex(~pack('H*', $x));\r
388                 }\r
389 \r
390                 switch ( MATH_BIGINTEGER_MODE ) {\r
391                     case MATH_BIGINTEGER_MODE_GMP:\r
392                         $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;\r
393                         $this->value = gmp_init($temp);\r
394                         $this->is_negative = false;\r
395                         break;\r
396                     case MATH_BIGINTEGER_MODE_BCMATH:\r
397                         $x = ( strlen($x) & 1 ) ? '0' . $x : $x;\r
398                         $temp = new Math_BigInteger(pack('H*', $x), 256);\r
399                         $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;\r
400                         $this->is_negative = false;\r
401                         break;\r
402                     default:\r
403                         $x = ( strlen($x) & 1 ) ? '0' . $x : $x;\r
404                         $temp = new Math_BigInteger(pack('H*', $x), 256);\r
405                         $this->value = $temp->value;\r
406                 }\r
407 \r
408                 if ($is_negative) {\r
409                     $temp = $this->add(new Math_BigInteger('-1'));\r
410                     $this->value = $temp->value;\r
411                 }\r
412                 break;\r
413             case  10:\r
414             case -10:\r
415                 // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that\r
416                 // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)\r
417                 // [^-0-9].*: find any non-numeric characters and then any characters that follow that\r
418                 $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);\r
419 \r
420                 switch ( MATH_BIGINTEGER_MODE ) {\r
421                     case MATH_BIGINTEGER_MODE_GMP:\r
422                         $this->value = gmp_init($x);\r
423                         break;\r
424                     case MATH_BIGINTEGER_MODE_BCMATH:\r
425                         // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different\r
426                         // results then doing it on '-1' does (modInverse does $x[0])\r
427                         $this->value = $x === '-' ? '0' : (string) $x;\r
428                         break;\r
429                     default:\r
430                         $temp = new Math_BigInteger();\r
431 \r
432                         $multiplier = new Math_BigInteger();\r
433                         $multiplier->value = array(MATH_BIGINTEGER_MAX10);\r
434 \r
435                         if ($x[0] == '-') {\r
436                             $this->is_negative = true;\r
437                             $x = substr($x, 1);\r
438                         }\r
439 \r
440                         $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);\r
441 \r
442                         while (strlen($x)) {\r
443                             $temp = $temp->multiply($multiplier);\r
444                             $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));\r
445                             $x = substr($x, MATH_BIGINTEGER_MAX10_LEN);\r
446                         }\r
447 \r
448                         $this->value = $temp->value;\r
449                 }\r
450                 break;\r
451             case  2: // base-2 support originally implemented by Lluis Pamies - thanks!\r
452             case -2:\r
453                 if ($base > 0 && $x[0] == '-') {\r
454                     $this->is_negative = true;\r
455                     $x = substr($x, 1);\r
456                 }\r
457 \r
458                 $x = preg_replace('#^([01]*).*#', '$1', $x);\r
459                 $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);\r
460 \r
461                 $str = '0x';\r
462                 while (strlen($x)) {\r
463                     $part = substr($x, 0, 4);\r
464                     $str.= dechex(bindec($part));\r
465                     $x = substr($x, 4);\r
466                 }\r
467 \r
468                 if ($this->is_negative) {\r
469                     $str = '-' . $str;\r
470                 }\r
471 \r
472                 $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16\r
473                 $this->value = $temp->value;\r
474                 $this->is_negative = $temp->is_negative;\r
475 \r
476                 break;\r
477             default:\r
478                 // base not supported, so we'll let $this == 0\r
479         }\r
480     }\r
481 \r
482     /**\r
483      * Converts a BigInteger to a byte string (eg. base-256).\r
484      *\r
485      * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're\r
486      * saved as two's compliment.\r
487      *\r
488      * Here's an example:\r
489      * <code>\r
490      * <?php\r
491      *    include('Math/BigInteger.php');\r
492      *\r
493      *    $a = new Math_BigInteger('65');\r
494      *\r
495      *    echo $a->toBytes(); // outputs chr(65)\r
496      * ?>\r
497      * </code>\r
498      *\r
499      * @param Boolean $twos_compliment\r
500      * @return String\r
501      * @access public\r
502      * @internal Converts a base-2**26 number to base-2**8\r
503      */\r
504     function toBytes($twos_compliment = false)\r
505     {\r
506         if ($twos_compliment) {\r
507             $comparison = $this->compare(new Math_BigInteger());\r
508             if ($comparison == 0) {\r
509                 return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';\r
510             }\r
511 \r
512             $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();\r
513             $bytes = $temp->toBytes();\r
514 \r
515             if (empty($bytes)) { // eg. if the number we're trying to convert is -1\r
516                 $bytes = chr(0);\r
517             }\r
518 \r
519             if (ord($bytes[0]) & 0x80) {\r
520                 $bytes = chr(0) . $bytes;\r
521             }\r
522 \r
523             return $comparison < 0 ? ~$bytes : $bytes;\r
524         }\r
525 \r
526         switch ( MATH_BIGINTEGER_MODE ) {\r
527             case MATH_BIGINTEGER_MODE_GMP:\r
528                 if (gmp_cmp($this->value, gmp_init(0)) == 0) {\r
529                     return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';\r
530                 }\r
531 \r
532                 $temp = gmp_strval(gmp_abs($this->value), 16);\r
533                 $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;\r
534                 $temp = pack('H*', $temp);\r
535 \r
536                 return $this->precision > 0 ?\r
537                     substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :\r
538                     ltrim($temp, chr(0));\r
539             case MATH_BIGINTEGER_MODE_BCMATH:\r
540                 if ($this->value === '0') {\r
541                     return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';\r
542                 }\r
543 \r
544                 $value = '';\r
545                 $current = $this->value;\r
546 \r
547                 if ($current[0] == '-') {\r
548                     $current = substr($current, 1);\r
549                 }\r
550 \r
551                 while (bccomp($current, '0', 0) > 0) {\r
552                     $temp = bcmod($current, '16777216');\r
553                     $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;\r
554                     $current = bcdiv($current, '16777216', 0);\r
555                 }\r
556 \r
557                 return $this->precision > 0 ?\r
558                     substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :\r
559                     ltrim($value, chr(0));\r
560         }\r
561 \r
562         if (!count($this->value)) {\r
563             return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';\r
564         }\r
565         $result = $this->_int2bytes($this->value[count($this->value) - 1]);\r
566 \r
567         $temp = $this->copy();\r
568 \r
569         for ($i = count($temp->value) - 2; $i >= 0; --$i) {\r
570             $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);\r
571             $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);\r
572         }\r
573 \r
574         return $this->precision > 0 ?\r
575             str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :\r
576             $result;\r
577     }\r
578 \r
579     /**\r
580      * Converts a BigInteger to a hex string (eg. base-16)).\r
581      *\r
582      * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're\r
583      * saved as two's compliment.\r
584      *\r
585      * Here's an example:\r
586      * <code>\r
587      * <?php\r
588      *    include('Math/BigInteger.php');\r
589      *\r
590      *    $a = new Math_BigInteger('65');\r
591      *\r
592      *    echo $a->toHex(); // outputs '41'\r
593      * ?>\r
594      * </code>\r
595      *\r
596      * @param Boolean $twos_compliment\r
597      * @return String\r
598      * @access public\r
599      * @internal Converts a base-2**26 number to base-2**8\r
600      */\r
601     function toHex($twos_compliment = false)\r
602     {\r
603         return bin2hex($this->toBytes($twos_compliment));\r
604     }\r
605 \r
606     /**\r
607      * Converts a BigInteger to a bit string (eg. base-2).\r
608      *\r
609      * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're\r
610      * saved as two's compliment.\r
611      *\r
612      * Here's an example:\r
613      * <code>\r
614      * <?php\r
615      *    include('Math/BigInteger.php');\r
616      *\r
617      *    $a = new Math_BigInteger('65');\r
618      *\r
619      *    echo $a->toBits(); // outputs '1000001'\r
620      * ?>\r
621      * </code>\r
622      *\r
623      * @param Boolean $twos_compliment\r
624      * @return String\r
625      * @access public\r
626      * @internal Converts a base-2**26 number to base-2**2\r
627      */\r
628     function toBits($twos_compliment = false)\r
629     {\r
630         $hex = $this->toHex($twos_compliment);\r
631         $bits = '';\r
632         for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {\r
633             $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;\r
634         }\r
635         if ($start) { // hexdec('') == 0\r
636             $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;\r
637         }\r
638         $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');\r
639 \r
640         if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {\r
641             return '0' . $result;\r
642         }\r
643 \r
644         return $result;\r
645     }\r
646 \r
647     /**\r
648      * Converts a BigInteger to a base-10 number.\r
649      *\r
650      * Here's an example:\r
651      * <code>\r
652      * <?php\r
653      *    include('Math/BigInteger.php');\r
654      *\r
655      *    $a = new Math_BigInteger('50');\r
656      *\r
657      *    echo $a->toString(); // outputs 50\r
658      * ?>\r
659      * </code>\r
660      *\r
661      * @return String\r
662      * @access public\r
663      * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)\r
664      */\r
665     function toString()\r
666     {\r
667         switch ( MATH_BIGINTEGER_MODE ) {\r
668             case MATH_BIGINTEGER_MODE_GMP:\r
669                 return gmp_strval($this->value);\r
670             case MATH_BIGINTEGER_MODE_BCMATH:\r
671                 if ($this->value === '0') {\r
672                     return '0';\r
673                 }\r
674 \r
675                 return ltrim($this->value, '0');\r
676         }\r
677 \r
678         if (!count($this->value)) {\r
679             return '0';\r
680         }\r
681 \r
682         $temp = $this->copy();\r
683         $temp->is_negative = false;\r
684 \r
685         $divisor = new Math_BigInteger();\r
686         $divisor->value = array(MATH_BIGINTEGER_MAX10);\r
687         $result = '';\r
688         while (count($temp->value)) {\r
689             list($temp, $mod) = $temp->divide($divisor);\r
690             $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result;\r
691         }\r
692         $result = ltrim($result, '0');\r
693         if (empty($result)) {\r
694             $result = '0';\r
695         }\r
696 \r
697         if ($this->is_negative) {\r
698             $result = '-' . $result;\r
699         }\r
700 \r
701         return $result;\r
702     }\r
703 \r
704     /**\r
705      * Copy an object\r
706      *\r
707      * PHP5 passes objects by reference while PHP4 passes by value.  As such, we need a function to guarantee\r
708      * that all objects are passed by value, when appropriate.  More information can be found here:\r
709      *\r
710      * {@link http://php.net/language.oop5.basic#51624}\r
711      *\r
712      * @access public\r
713      * @see __clone()\r
714      * @return Math_BigInteger\r
715      */\r
716     function copy()\r
717     {\r
718         $temp = new Math_BigInteger();\r
719         $temp->value = $this->value;\r
720         $temp->is_negative = $this->is_negative;\r
721         $temp->generator = $this->generator;\r
722         $temp->precision = $this->precision;\r
723         $temp->bitmask = $this->bitmask;\r
724         return $temp;\r
725     }\r
726 \r
727     /**\r
728      *  __toString() magic method\r
729      *\r
730      * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call\r
731      * toString().\r
732      *\r
733      * @access public\r
734      * @internal Implemented per a suggestion by Techie-Michael - thanks!\r
735      */\r
736     function __toString()\r
737     {\r
738         return $this->toString();\r
739     }\r
740 \r
741     /**\r
742      * __clone() magic method\r
743      *\r
744      * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()\r
745      * directly in PHP5.  You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5\r
746      * only syntax of $y = clone $x.  As such, if you're trying to write an application that works on both PHP4 and PHP5,\r
747      * call Math_BigInteger::copy(), instead.\r
748      *\r
749      * @access public\r
750      * @see copy()\r
751      * @return Math_BigInteger\r
752      */\r
753     function __clone()\r
754     {\r
755         return $this->copy();\r
756     }\r
757 \r
758     /**\r
759      *  __sleep() magic method\r
760      *\r
761      * Will be called, automatically, when serialize() is called on a Math_BigInteger object.\r
762      *\r
763      * @see __wakeup()\r
764      * @access public\r
765      */\r
766     function __sleep()\r
767     {\r
768         $this->hex = $this->toHex(true);\r
769         $vars = array('hex');\r
770         if ($this->generator != 'mt_rand') {\r
771             $vars[] = 'generator';\r
772         }\r
773         if ($this->precision > 0) {\r
774             $vars[] = 'precision';\r
775         }\r
776         return $vars;\r
777         \r
778     }\r
779 \r
780     /**\r
781      *  __wakeup() magic method\r
782      *\r
783      * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.\r
784      *\r
785      * @see __sleep()\r
786      * @access public\r
787      */\r
788     function __wakeup()\r
789     {\r
790         $temp = new Math_BigInteger($this->hex, -16);\r
791         $this->value = $temp->value;\r
792         $this->is_negative = $temp->is_negative;\r
793         $this->setRandomGenerator($this->generator);\r
794         if ($this->precision > 0) {\r
795             // recalculate $this->bitmask\r
796             $this->setPrecision($this->precision);\r
797         }\r
798     }\r
799 \r
800     /**\r
801      * Adds two BigIntegers.\r
802      *\r
803      * Here's an example:\r
804      * <code>\r
805      * <?php\r
806      *    include('Math/BigInteger.php');\r
807      *\r
808      *    $a = new Math_BigInteger('10');\r
809      *    $b = new Math_BigInteger('20');\r
810      *\r
811      *    $c = $a->add($b);\r
812      *\r
813      *    echo $c->toString(); // outputs 30\r
814      * ?>\r
815      * </code>\r
816      *\r
817      * @param Math_BigInteger $y\r
818      * @return Math_BigInteger\r
819      * @access public\r
820      * @internal Performs base-2**52 addition\r
821      */\r
822     function add($y)\r
823     {\r
824         switch ( MATH_BIGINTEGER_MODE ) {\r
825             case MATH_BIGINTEGER_MODE_GMP:\r
826                 $temp = new Math_BigInteger();\r
827                 $temp->value = gmp_add($this->value, $y->value);\r
828 \r
829                 return $this->_normalize($temp);\r
830             case MATH_BIGINTEGER_MODE_BCMATH:\r
831                 $temp = new Math_BigInteger();\r
832                 $temp->value = bcadd($this->value, $y->value, 0);\r
833 \r
834                 return $this->_normalize($temp);\r
835         }\r
836 \r
837         $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);\r
838 \r
839         $result = new Math_BigInteger();\r
840         $result->value = $temp[MATH_BIGINTEGER_VALUE];\r
841         $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];\r
842 \r
843         return $this->_normalize($result);\r
844     }\r
845 \r
846     /**\r
847      * Performs addition.\r
848      *\r
849      * @param Array $x_value\r
850      * @param Boolean $x_negative\r
851      * @param Array $y_value\r
852      * @param Boolean $y_negative\r
853      * @return Array\r
854      * @access private\r
855      */\r
856     function _add($x_value, $x_negative, $y_value, $y_negative)\r
857     {\r
858         $x_size = count($x_value);\r
859         $y_size = count($y_value);\r
860 \r
861         if ($x_size == 0) {\r
862             return array(\r
863                 MATH_BIGINTEGER_VALUE => $y_value,\r
864                 MATH_BIGINTEGER_SIGN => $y_negative\r
865             );\r
866         } else if ($y_size == 0) {\r
867             return array(\r
868                 MATH_BIGINTEGER_VALUE => $x_value,\r
869                 MATH_BIGINTEGER_SIGN => $x_negative\r
870             );\r
871         }\r
872 \r
873         // subtract, if appropriate\r
874         if ( $x_negative != $y_negative ) {\r
875             if ( $x_value == $y_value ) {\r
876                 return array(\r
877                     MATH_BIGINTEGER_VALUE => array(),\r
878                     MATH_BIGINTEGER_SIGN => false\r
879                 );\r
880             }\r
881 \r
882             $temp = $this->_subtract($x_value, false, $y_value, false);\r
883             $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?\r
884                                           $x_negative : $y_negative;\r
885 \r
886             return $temp;\r
887         }\r
888 \r
889         if ($x_size < $y_size) {\r
890             $size = $x_size;\r
891             $value = $y_value;\r
892         } else {\r
893             $size = $y_size;\r
894             $value = $x_value;\r
895         }\r
896 \r
897         $value[] = 0; // just in case the carry adds an extra digit\r
898 \r
899         $carry = 0;\r
900         for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {\r
901             $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;\r
902             $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1\r
903             $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;\r
904 \r
905             $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);\r
906 \r
907             $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)\r
908             $value[$j] = $temp;\r
909         }\r
910 \r
911         if ($j == $size) { // ie. if $y_size is odd\r
912             $sum = $x_value[$i] + $y_value[$i] + $carry;\r
913             $carry = $sum >= MATH_BIGINTEGER_BASE_FULL;\r
914             $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;\r
915             ++$i; // ie. let $i = $j since we've just done $value[$i]\r
916         }\r
917 \r
918         if ($carry) {\r
919             for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {\r
920                 $value[$i] = 0;\r
921             }\r
922             ++$value[$i];\r
923         }\r
924 \r
925         return array(\r
926             MATH_BIGINTEGER_VALUE => $this->_trim($value),\r
927             MATH_BIGINTEGER_SIGN => $x_negative\r
928         );\r
929     }\r
930 \r
931     /**\r
932      * Subtracts two BigIntegers.\r
933      *\r
934      * Here's an example:\r
935      * <code>\r
936      * <?php\r
937      *    include('Math/BigInteger.php');\r
938      *\r
939      *    $a = new Math_BigInteger('10');\r
940      *    $b = new Math_BigInteger('20');\r
941      *\r
942      *    $c = $a->subtract($b);\r
943      *\r
944      *    echo $c->toString(); // outputs -10\r
945      * ?>\r
946      * </code>\r
947      *\r
948      * @param Math_BigInteger $y\r
949      * @return Math_BigInteger\r
950      * @access public\r
951      * @internal Performs base-2**52 subtraction\r
952      */\r
953     function subtract($y)\r
954     {\r
955         switch ( MATH_BIGINTEGER_MODE ) {\r
956             case MATH_BIGINTEGER_MODE_GMP:\r
957                 $temp = new Math_BigInteger();\r
958                 $temp->value = gmp_sub($this->value, $y->value);\r
959 \r
960                 return $this->_normalize($temp);\r
961             case MATH_BIGINTEGER_MODE_BCMATH:\r
962                 $temp = new Math_BigInteger();\r
963                 $temp->value = bcsub($this->value, $y->value, 0);\r
964 \r
965                 return $this->_normalize($temp);\r
966         }\r
967 \r
968         $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);\r
969 \r
970         $result = new Math_BigInteger();\r
971         $result->value = $temp[MATH_BIGINTEGER_VALUE];\r
972         $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];\r
973 \r
974         return $this->_normalize($result);\r
975     }\r
976 \r
977     /**\r
978      * Performs subtraction.\r
979      *\r
980      * @param Array $x_value\r
981      * @param Boolean $x_negative\r
982      * @param Array $y_value\r
983      * @param Boolean $y_negative\r
984      * @return Array\r
985      * @access private\r
986      */\r
987     function _subtract($x_value, $x_negative, $y_value, $y_negative)\r
988     {\r
989         $x_size = count($x_value);\r
990         $y_size = count($y_value);\r
991 \r
992         if ($x_size == 0) {\r
993             return array(\r
994                 MATH_BIGINTEGER_VALUE => $y_value,\r
995                 MATH_BIGINTEGER_SIGN => !$y_negative\r
996             );\r
997         } else if ($y_size == 0) {\r
998             return array(\r
999                 MATH_BIGINTEGER_VALUE => $x_value,\r
1000                 MATH_BIGINTEGER_SIGN => $x_negative\r
1001             );\r
1002         }\r
1003 \r
1004         // add, if appropriate (ie. -$x - +$y or +$x - -$y)\r
1005         if ( $x_negative != $y_negative ) {\r
1006             $temp = $this->_add($x_value, false, $y_value, false);\r
1007             $temp[MATH_BIGINTEGER_SIGN] = $x_negative;\r
1008 \r
1009             return $temp;\r
1010         }\r
1011 \r
1012         $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);\r
1013 \r
1014         if ( !$diff ) {\r
1015             return array(\r
1016                 MATH_BIGINTEGER_VALUE => array(),\r
1017                 MATH_BIGINTEGER_SIGN => false\r
1018             );\r
1019         }\r
1020 \r
1021         // switch $x and $y around, if appropriate.\r
1022         if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {\r
1023             $temp = $x_value;\r
1024             $x_value = $y_value;\r
1025             $y_value = $temp;\r
1026 \r
1027             $x_negative = !$x_negative;\r
1028 \r
1029             $x_size = count($x_value);\r
1030             $y_size = count($y_value);\r
1031         }\r
1032 \r
1033         // at this point, $x_value should be at least as big as - if not bigger than - $y_value\r
1034 \r
1035         $carry = 0;\r
1036         for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {\r
1037             $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;\r
1038             $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1\r
1039             $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;\r
1040 \r
1041             $temp = (int) ($sum / MATH_BIGINTEGER_BASE_FULL);\r
1042 \r
1043             $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);\r
1044             $x_value[$j] = $temp;\r
1045         }\r
1046 \r
1047         if ($j == $y_size) { // ie. if $y_size is odd\r
1048             $sum = $x_value[$i] - $y_value[$i] - $carry;\r
1049             $carry = $sum < 0;\r
1050             $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;\r
1051             ++$i;\r
1052         }\r
1053 \r
1054         if ($carry) {\r
1055             for (; !$x_value[$i]; ++$i) {\r
1056                 $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;\r
1057             }\r
1058             --$x_value[$i];\r
1059         }\r
1060 \r
1061         return array(\r
1062             MATH_BIGINTEGER_VALUE => $this->_trim($x_value),\r
1063             MATH_BIGINTEGER_SIGN => $x_negative\r
1064         );\r
1065     }\r
1066 \r
1067     /**\r
1068      * Multiplies two BigIntegers\r
1069      *\r
1070      * Here's an example:\r
1071      * <code>\r
1072      * <?php\r
1073      *    include('Math/BigInteger.php');\r
1074      *\r
1075      *    $a = new Math_BigInteger('10');\r
1076      *    $b = new Math_BigInteger('20');\r
1077      *\r
1078      *    $c = $a->multiply($b);\r
1079      *\r
1080      *    echo $c->toString(); // outputs 200\r
1081      * ?>\r
1082      * </code>\r
1083      *\r
1084      * @param Math_BigInteger $x\r
1085      * @return Math_BigInteger\r
1086      * @access public\r
1087      */\r
1088     function multiply($x)\r
1089     {\r
1090         switch ( MATH_BIGINTEGER_MODE ) {\r
1091             case MATH_BIGINTEGER_MODE_GMP:\r
1092                 $temp = new Math_BigInteger();\r
1093                 $temp->value = gmp_mul($this->value, $x->value);\r
1094 \r
1095                 return $this->_normalize($temp);\r
1096             case MATH_BIGINTEGER_MODE_BCMATH:\r
1097                 $temp = new Math_BigInteger();\r
1098                 $temp->value = bcmul($this->value, $x->value, 0);\r
1099 \r
1100                 return $this->_normalize($temp);\r
1101         }\r
1102 \r
1103         $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);\r
1104 \r
1105         $product = new Math_BigInteger();\r
1106         $product->value = $temp[MATH_BIGINTEGER_VALUE];\r
1107         $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];\r
1108 \r
1109         return $this->_normalize($product);\r
1110     }\r
1111 \r
1112     /**\r
1113      * Performs multiplication.\r
1114      *\r
1115      * @param Array $x_value\r
1116      * @param Boolean $x_negative\r
1117      * @param Array $y_value\r
1118      * @param Boolean $y_negative\r
1119      * @return Array\r
1120      * @access private\r
1121      */\r
1122     function _multiply($x_value, $x_negative, $y_value, $y_negative)\r
1123     {\r
1124         //if ( $x_value == $y_value ) {\r
1125         //    return array(\r
1126         //        MATH_BIGINTEGER_VALUE => $this->_square($x_value),\r
1127         //        MATH_BIGINTEGER_SIGN => $x_sign != $y_value\r
1128         //    );\r
1129         //}\r
1130 \r
1131         $x_length = count($x_value);\r
1132         $y_length = count($y_value);\r
1133 \r
1134         if ( !$x_length || !$y_length ) { // a 0 is being multiplied\r
1135             return array(\r
1136                 MATH_BIGINTEGER_VALUE => array(),\r
1137                 MATH_BIGINTEGER_SIGN => false\r
1138             );\r
1139         }\r
1140 \r
1141         return array(\r
1142             MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?\r
1143                 $this->_trim($this->_regularMultiply($x_value, $y_value)) :\r
1144                 $this->_trim($this->_karatsuba($x_value, $y_value)),\r
1145             MATH_BIGINTEGER_SIGN => $x_negative != $y_negative\r
1146         );\r
1147     }\r
1148 \r
1149     /**\r
1150      * Performs long multiplication on two BigIntegers\r
1151      *\r
1152      * Modeled after 'multiply' in MutableBigInteger.java.\r
1153      *\r
1154      * @param Array $x_value\r
1155      * @param Array $y_value\r
1156      * @return Array\r
1157      * @access private\r
1158      */\r
1159     function _regularMultiply($x_value, $y_value)\r
1160     {\r
1161         $x_length = count($x_value);\r
1162         $y_length = count($y_value);\r
1163 \r
1164         if ( !$x_length || !$y_length ) { // a 0 is being multiplied\r
1165             return array();\r
1166         }\r
1167 \r
1168         if ( $x_length < $y_length ) {\r
1169             $temp = $x_value;\r
1170             $x_value = $y_value;\r
1171             $y_value = $temp;\r
1172 \r
1173             $x_length = count($x_value);\r
1174             $y_length = count($y_value);\r
1175         }\r
1176 \r
1177         $product_value = $this->_array_repeat(0, $x_length + $y_length);\r
1178 \r
1179         // the following for loop could be removed if the for loop following it\r
1180         // (the one with nested for loops) initially set $i to 0, but\r
1181         // doing so would also make the result in one set of unnecessary adds,\r
1182         // since on the outermost loops first pass, $product->value[$k] is going\r
1183         // to always be 0\r
1184 \r
1185         $carry = 0;\r
1186 \r
1187         for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0\r
1188             $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0\r
1189             $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);\r
1190             $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);\r
1191         }\r
1192 \r
1193         $product_value[$j] = $carry;\r
1194 \r
1195         // the above for loop is what the previous comment was talking about.  the\r
1196         // following for loop is the "one with nested for loops"\r
1197         for ($i = 1; $i < $y_length; ++$i) {\r
1198             $carry = 0;\r
1199 \r
1200             for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {\r
1201                 $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;\r
1202                 $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);\r
1203                 $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);\r
1204             }\r
1205 \r
1206             $product_value[$k] = $carry;\r
1207         }\r
1208 \r
1209         return $product_value;\r
1210     }\r
1211 \r
1212     /**\r
1213      * Performs Karatsuba multiplication on two BigIntegers\r
1214      *\r
1215      * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and\r
1216      * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.\r
1217      *\r
1218      * @param Array $x_value\r
1219      * @param Array $y_value\r
1220      * @return Array\r
1221      * @access private\r
1222      */\r
1223     function _karatsuba($x_value, $y_value)\r
1224     {\r
1225         $m = min(count($x_value) >> 1, count($y_value) >> 1);\r
1226 \r
1227         if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {\r
1228             return $this->_regularMultiply($x_value, $y_value);\r
1229         }\r
1230 \r
1231         $x1 = array_slice($x_value, $m);\r
1232         $x0 = array_slice($x_value, 0, $m);\r
1233         $y1 = array_slice($y_value, $m);\r
1234         $y0 = array_slice($y_value, 0, $m);\r
1235 \r
1236         $z2 = $this->_karatsuba($x1, $y1);\r
1237         $z0 = $this->_karatsuba($x0, $y0);\r
1238 \r
1239         $z1 = $this->_add($x1, false, $x0, false);\r
1240         $temp = $this->_add($y1, false, $y0, false);\r
1241         $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);\r
1242         $temp = $this->_add($z2, false, $z0, false);\r
1243         $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);\r
1244 \r
1245         $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);\r
1246         $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);\r
1247 \r
1248         $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);\r
1249         $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);\r
1250 \r
1251         return $xy[MATH_BIGINTEGER_VALUE];\r
1252     }\r
1253 \r
1254     /**\r
1255      * Performs squaring\r
1256      *\r
1257      * @param Array $x\r
1258      * @return Array\r
1259      * @access private\r
1260      */\r
1261     function _square($x = false)\r
1262     {\r
1263         return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?\r
1264             $this->_trim($this->_baseSquare($x)) :\r
1265             $this->_trim($this->_karatsubaSquare($x));\r
1266     }\r
1267 \r
1268     /**\r
1269      * Performs traditional squaring on two BigIntegers\r
1270      *\r
1271      * Squaring can be done faster than multiplying a number by itself can be.  See\r
1272      * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /\r
1273      * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.\r
1274      *\r
1275      * @param Array $value\r
1276      * @return Array\r
1277      * @access private\r
1278      */\r
1279     function _baseSquare($value)\r
1280     {\r
1281         if ( empty($value) ) {\r
1282             return array();\r
1283         }\r
1284         $square_value = $this->_array_repeat(0, 2 * count($value));\r
1285 \r
1286         for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {\r
1287             $i2 = $i << 1;\r
1288 \r
1289             $temp = $square_value[$i2] + $value[$i] * $value[$i];\r
1290             $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);\r
1291             $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);\r
1292 \r
1293             // note how we start from $i+1 instead of 0 as we do in multiplication.\r
1294             for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {\r
1295                 $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;\r
1296                 $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);\r
1297                 $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);\r
1298             }\r
1299 \r
1300             // the following line can yield values larger 2**15.  at this point, PHP should switch\r
1301             // over to floats.\r
1302             $square_value[$i + $max_index + 1] = $carry;\r
1303         }\r
1304 \r
1305         return $square_value;\r
1306     }\r
1307 \r
1308     /**\r
1309      * Performs Karatsuba "squaring" on two BigIntegers\r
1310      *\r
1311      * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and\r
1312      * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.\r
1313      *\r
1314      * @param Array $value\r
1315      * @return Array\r
1316      * @access private\r
1317      */\r
1318     function _karatsubaSquare($value)\r
1319     {\r
1320         $m = count($value) >> 1;\r
1321 \r
1322         if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {\r
1323             return $this->_baseSquare($value);\r
1324         }\r
1325 \r
1326         $x1 = array_slice($value, $m);\r
1327         $x0 = array_slice($value, 0, $m);\r
1328 \r
1329         $z2 = $this->_karatsubaSquare($x1);\r
1330         $z0 = $this->_karatsubaSquare($x0);\r
1331 \r
1332         $z1 = $this->_add($x1, false, $x0, false);\r
1333         $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);\r
1334         $temp = $this->_add($z2, false, $z0, false);\r
1335         $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);\r
1336 \r
1337         $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);\r
1338         $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);\r
1339 \r
1340         $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);\r
1341         $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);\r
1342 \r
1343         return $xx[MATH_BIGINTEGER_VALUE];\r
1344     }\r
1345 \r
1346     /**\r
1347      * Divides two BigIntegers.\r
1348      *\r
1349      * Returns an array whose first element contains the quotient and whose second element contains the\r
1350      * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the\r
1351      * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder\r
1352      * and the divisor (basically, the "common residue" is the first positive modulo).\r
1353      *\r
1354      * Here's an example:\r
1355      * <code>\r
1356      * <?php\r
1357      *    include('Math/BigInteger.php');\r
1358      *\r
1359      *    $a = new Math_BigInteger('10');\r
1360      *    $b = new Math_BigInteger('20');\r
1361      *\r
1362      *    list($quotient, $remainder) = $a->divide($b);\r
1363      *\r
1364      *    echo $quotient->toString(); // outputs 0\r
1365      *    echo "\r\n";\r
1366      *    echo $remainder->toString(); // outputs 10\r
1367      * ?>\r
1368      * </code>\r
1369      *\r
1370      * @param Math_BigInteger $y\r
1371      * @return Array\r
1372      * @access public\r
1373      * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.\r
1374      */\r
1375     function divide($y)\r
1376     {\r
1377         switch ( MATH_BIGINTEGER_MODE ) {\r
1378             case MATH_BIGINTEGER_MODE_GMP:\r
1379                 $quotient = new Math_BigInteger();\r
1380                 $remainder = new Math_BigInteger();\r
1381 \r
1382                 list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);\r
1383 \r
1384                 if (gmp_sign($remainder->value) < 0) {\r
1385                     $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));\r
1386                 }\r
1387 \r
1388                 return array($this->_normalize($quotient), $this->_normalize($remainder));\r
1389             case MATH_BIGINTEGER_MODE_BCMATH:\r
1390                 $quotient = new Math_BigInteger();\r
1391                 $remainder = new Math_BigInteger();\r
1392 \r
1393                 $quotient->value = bcdiv($this->value, $y->value, 0);\r
1394                 $remainder->value = bcmod($this->value, $y->value);\r
1395 \r
1396                 if ($remainder->value[0] == '-') {\r
1397                     $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);\r
1398                 }\r
1399 \r
1400                 return array($this->_normalize($quotient), $this->_normalize($remainder));\r
1401         }\r
1402 \r
1403         if (count($y->value) == 1) {\r
1404             list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);\r
1405             $quotient = new Math_BigInteger();\r
1406             $remainder = new Math_BigInteger();\r
1407             $quotient->value = $q;\r
1408             $remainder->value = array($r);\r
1409             $quotient->is_negative = $this->is_negative != $y->is_negative;\r
1410             return array($this->_normalize($quotient), $this->_normalize($remainder));\r
1411         }\r
1412 \r
1413         static $zero;\r
1414         if ( !isset($zero) ) {\r
1415             $zero = new Math_BigInteger();\r
1416         }\r
1417 \r
1418         $x = $this->copy();\r
1419         $y = $y->copy();\r
1420 \r
1421         $x_sign = $x->is_negative;\r
1422         $y_sign = $y->is_negative;\r
1423 \r
1424         $x->is_negative = $y->is_negative = false;\r
1425 \r
1426         $diff = $x->compare($y);\r
1427 \r
1428         if ( !$diff ) {\r
1429             $temp = new Math_BigInteger();\r
1430             $temp->value = array(1);\r
1431             $temp->is_negative = $x_sign != $y_sign;\r
1432             return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));\r
1433         }\r
1434 \r
1435         if ( $diff < 0 ) {\r
1436             // if $x is negative, "add" $y.\r
1437             if ( $x_sign ) {\r
1438                 $x = $y->subtract($x);\r
1439             }\r
1440             return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));\r
1441         }\r
1442 \r
1443         // normalize $x and $y as described in HAC 14.23 / 14.24\r
1444         $msb = $y->value[count($y->value) - 1];\r
1445         for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {\r
1446             $msb <<= 1;\r
1447         }\r
1448         $x->_lshift($shift);\r
1449         $y->_lshift($shift);\r
1450         $y_value = &$y->value;\r
1451 \r
1452         $x_max = count($x->value) - 1;\r
1453         $y_max = count($y->value) - 1;\r
1454 \r
1455         $quotient = new Math_BigInteger();\r
1456         $quotient_value = &$quotient->value;\r
1457         $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);\r
1458 \r
1459         static $temp, $lhs, $rhs;\r
1460         if (!isset($temp)) {\r
1461             $temp = new Math_BigInteger();\r
1462             $lhs =  new Math_BigInteger();\r
1463             $rhs =  new Math_BigInteger();\r
1464         }\r
1465         $temp_value = &$temp->value;\r
1466         $rhs_value =  &$rhs->value;\r
1467 \r
1468         // $temp = $y << ($x_max - $y_max-1) in base 2**26\r
1469         $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);\r
1470 \r
1471         while ( $x->compare($temp) >= 0 ) {\r
1472             // calculate the "common residue"\r
1473             ++$quotient_value[$x_max - $y_max];\r
1474             $x = $x->subtract($temp);\r
1475             $x_max = count($x->value) - 1;\r
1476         }\r
1477 \r
1478         for ($i = $x_max; $i >= $y_max + 1; --$i) {\r
1479             $x_value = &$x->value;\r
1480             $x_window = array(\r
1481                 isset($x_value[$i]) ? $x_value[$i] : 0,\r
1482                 isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,\r
1483                 isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0\r
1484             );\r
1485             $y_window = array(\r
1486                 $y_value[$y_max],\r
1487                 ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0\r
1488             );\r
1489 \r
1490             $q_index = $i - $y_max - 1;\r
1491             if ($x_window[0] == $y_window[0]) {\r
1492                 $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;\r
1493             } else {\r
1494                 $quotient_value[$q_index] = (int) (\r
1495                     ($x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1])\r
1496                     /\r
1497                     $y_window[0]\r
1498                 );\r
1499             }\r
1500 \r
1501             $temp_value = array($y_window[1], $y_window[0]);\r
1502 \r
1503             $lhs->value = array($quotient_value[$q_index]);\r
1504             $lhs = $lhs->multiply($temp);\r
1505 \r
1506             $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);\r
1507 \r
1508             while ( $lhs->compare($rhs) > 0 ) {\r
1509                 --$quotient_value[$q_index];\r
1510 \r
1511                 $lhs->value = array($quotient_value[$q_index]);\r
1512                 $lhs = $lhs->multiply($temp);\r
1513             }\r
1514 \r
1515             $adjust = $this->_array_repeat(0, $q_index);\r
1516             $temp_value = array($quotient_value[$q_index]);\r
1517             $temp = $temp->multiply($y);\r
1518             $temp_value = &$temp->value;\r
1519             $temp_value = array_merge($adjust, $temp_value);\r
1520 \r
1521             $x = $x->subtract($temp);\r
1522 \r
1523             if ($x->compare($zero) < 0) {\r
1524                 $temp_value = array_merge($adjust, $y_value);\r
1525                 $x = $x->add($temp);\r
1526 \r
1527                 --$quotient_value[$q_index];\r
1528             }\r
1529 \r
1530             $x_max = count($x_value) - 1;\r
1531         }\r
1532 \r
1533         // unnormalize the remainder\r
1534         $x->_rshift($shift);\r
1535 \r
1536         $quotient->is_negative = $x_sign != $y_sign;\r
1537 \r
1538         // calculate the "common residue", if appropriate\r
1539         if ( $x_sign ) {\r
1540             $y->_rshift($shift);\r
1541             $x = $y->subtract($x);\r
1542         }\r
1543 \r
1544         return array($this->_normalize($quotient), $this->_normalize($x));\r
1545     }\r
1546 \r
1547     /**\r
1548      * Divides a BigInteger by a regular integer\r
1549      *\r
1550      * abc / x = a00 / x + b0 / x + c / x\r
1551      *\r
1552      * @param Array $dividend\r
1553      * @param Array $divisor\r
1554      * @return Array\r
1555      * @access private\r
1556      */\r
1557     function _divide_digit($dividend, $divisor)\r
1558     {\r
1559         $carry = 0;\r
1560         $result = array();\r
1561 \r
1562         for ($i = count($dividend) - 1; $i >= 0; --$i) {\r
1563             $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];\r
1564             $result[$i] = (int) ($temp / $divisor);\r
1565             $carry = (int) ($temp - $divisor * $result[$i]);\r
1566         }\r
1567 \r
1568         return array($result, $carry);\r
1569     }\r
1570 \r
1571     /**\r
1572      * Performs modular exponentiation.\r
1573      *\r
1574      * Here's an example:\r
1575      * <code>\r
1576      * <?php\r
1577      *    include('Math/BigInteger.php');\r
1578      *\r
1579      *    $a = new Math_BigInteger('10');\r
1580      *    $b = new Math_BigInteger('20');\r
1581      *    $c = new Math_BigInteger('30');\r
1582      *\r
1583      *    $c = $a->modPow($b, $c);\r
1584      *\r
1585      *    echo $c->toString(); // outputs 10\r
1586      * ?>\r
1587      * </code>\r
1588      *\r
1589      * @param Math_BigInteger $e\r
1590      * @param Math_BigInteger $n\r
1591      * @return Math_BigInteger\r
1592      * @access public\r
1593      * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and\r
1594      *    and although the approach involving repeated squaring does vastly better, it, too, is impractical\r
1595      *    for our purposes.  The reason being that division - by far the most complicated and time-consuming\r
1596      *    of the basic operations (eg. +,-,*,/) - occurs multiple times within it.\r
1597      *\r
1598      *    Modular reductions resolve this issue.  Although an individual modular reduction takes more time\r
1599      *    then an individual division, when performed in succession (with the same modulo), they're a lot faster.\r
1600      *\r
1601      *    The two most commonly used modular reductions are Barrett and Montgomery reduction.  Montgomery reduction,\r
1602      *    although faster, only works when the gcd of the modulo and of the base being used is 1.  In RSA, when the\r
1603      *    base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because\r
1604      *    the product of two odd numbers is odd), but what about when RSA isn't used?\r
1605      *\r
1606      *    In contrast, Barrett reduction has no such constraint.  As such, some bigint implementations perform a\r
1607      *    Barrett reduction after every operation in the modpow function.  Others perform Barrett reductions when the\r
1608      *    modulo is even and Montgomery reductions when the modulo is odd.  BigInteger.java's modPow method, however,\r
1609      *    uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and\r
1610      *    the other, a power of two - and recombine them, later.  This is the method that this modPow function uses.\r
1611      *    {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.\r
1612      */\r
1613     function modPow($e, $n)\r
1614     {\r
1615         $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();\r
1616 \r
1617         if ($e->compare(new Math_BigInteger()) < 0) {\r
1618             $e = $e->abs();\r
1619 \r
1620             $temp = $this->modInverse($n);\r
1621             if ($temp === false) {\r
1622                 return false;\r
1623             }\r
1624 \r
1625             return $this->_normalize($temp->modPow($e, $n));\r
1626         }\r
1627 \r
1628         if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) {\r
1629             $temp = new Math_BigInteger();\r
1630             $temp->value = gmp_powm($this->value, $e->value, $n->value);\r
1631 \r
1632             return $this->_normalize($temp);\r
1633         }\r
1634 \r
1635         if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {\r
1636             list(, $temp) = $this->divide($n);\r
1637             return $temp->modPow($e, $n);\r
1638         }\r
1639 \r
1640         if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {\r
1641             $components = array(\r
1642                 'modulus' => $n->toBytes(true),\r
1643                 'publicExponent' => $e->toBytes(true)\r
1644             );\r
1645 \r
1646             $components = array(\r
1647                 'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),\r
1648                 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])\r
1649             );\r
1650 \r
1651             $RSAPublicKey = pack('Ca*a*a*',\r
1652                 48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),\r
1653                 $components['modulus'], $components['publicExponent']\r
1654             );\r
1655 \r
1656             $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA\r
1657             $RSAPublicKey = chr(0) . $RSAPublicKey;\r
1658             $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;\r
1659 \r
1660             $encapsulated = pack('Ca*a*',\r
1661                 48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey\r
1662             );\r
1663 \r
1664             $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .\r
1665                              chunk_split(base64_encode($encapsulated)) .\r
1666                              '-----END PUBLIC KEY-----';\r
1667 \r
1668             $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);\r
1669 \r
1670             if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {\r
1671                 return new Math_BigInteger($result, 256);\r
1672             }\r
1673         }\r
1674 \r
1675         if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {\r
1676                 $temp = new Math_BigInteger();\r
1677                 $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);\r
1678 \r
1679                 return $this->_normalize($temp);\r
1680         }\r
1681 \r
1682         if ( empty($e->value) ) {\r
1683             $temp = new Math_BigInteger();\r
1684             $temp->value = array(1);\r
1685             return $this->_normalize($temp);\r
1686         }\r
1687 \r
1688         if ( $e->value == array(1) ) {\r
1689             list(, $temp) = $this->divide($n);\r
1690             return $this->_normalize($temp);\r
1691         }\r
1692 \r
1693         if ( $e->value == array(2) ) {\r
1694             $temp = new Math_BigInteger();\r
1695             $temp->value = $this->_square($this->value);\r
1696             list(, $temp) = $temp->divide($n);\r
1697             return $this->_normalize($temp);\r
1698         }\r
1699 \r
1700         return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));\r
1701 \r
1702         // is the modulo odd?\r
1703         if ( $n->value[0] & 1 ) {\r
1704             return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));\r
1705         }\r
1706         // if it's not, it's even\r
1707 \r
1708         // find the lowest set bit (eg. the max pow of 2 that divides $n)\r
1709         for ($i = 0; $i < count($n->value); ++$i) {\r
1710             if ( $n->value[$i] ) {\r
1711                 $temp = decbin($n->value[$i]);\r
1712                 $j = strlen($temp) - strrpos($temp, '1') - 1;\r
1713                 $j+= 26 * $i;\r
1714                 break;\r
1715             }\r
1716         }\r
1717         // at this point, 2^$j * $n/(2^$j) == $n\r
1718 \r
1719         $mod1 = $n->copy();\r
1720         $mod1->_rshift($j);\r
1721         $mod2 = new Math_BigInteger();\r
1722         $mod2->value = array(1);\r
1723         $mod2->_lshift($j);\r
1724 \r
1725         $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();\r
1726         $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);\r
1727 \r
1728         $y1 = $mod2->modInverse($mod1);\r
1729         $y2 = $mod1->modInverse($mod2);\r
1730 \r
1731         $result = $part1->multiply($mod2);\r
1732         $result = $result->multiply($y1);\r
1733 \r
1734         $temp = $part2->multiply($mod1);\r
1735         $temp = $temp->multiply($y2);\r
1736 \r
1737         $result = $result->add($temp);\r
1738         list(, $result) = $result->divide($n);\r
1739 \r
1740         return $this->_normalize($result);\r
1741     }\r
1742 \r
1743     /**\r
1744      * Performs modular exponentiation.\r
1745      *\r
1746      * Alias for Math_BigInteger::modPow()\r
1747      *\r
1748      * @param Math_BigInteger $e\r
1749      * @param Math_BigInteger $n\r
1750      * @return Math_BigInteger\r
1751      * @access public\r
1752      */\r
1753     function powMod($e, $n)\r
1754     {\r
1755         return $this->modPow($e, $n);\r
1756     }\r
1757 \r
1758     /**\r
1759      * Sliding Window k-ary Modular Exponentiation\r
1760      *\r
1761      * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /\r
1762      * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}.  In a departure from those algorithims,\r
1763      * however, this function performs a modular reduction after every multiplication and squaring operation.\r
1764      * As such, this function has the same preconditions that the reductions being used do.\r
1765      *\r
1766      * @param Math_BigInteger $e\r
1767      * @param Math_BigInteger $n\r
1768      * @param Integer $mode\r
1769      * @return Math_BigInteger\r
1770      * @access private\r
1771      */\r
1772     function _slidingWindow($e, $n, $mode)\r
1773     {\r
1774         static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function\r
1775         //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1\r
1776 \r
1777         $e_value = $e->value;\r
1778         $e_length = count($e_value) - 1;\r
1779         $e_bits = decbin($e_value[$e_length]);\r
1780         for ($i = $e_length - 1; $i >= 0; --$i) {\r
1781             $e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT);\r
1782         }\r
1783 \r
1784         $e_length = strlen($e_bits);\r
1785 \r
1786         // calculate the appropriate window size.\r
1787         // $window_size == 3 if $window_ranges is between 25 and 81, for example.\r
1788         for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);\r
1789 \r
1790         $n_value = $n->value;\r
1791 \r
1792         // precompute $this^0 through $this^$window_size\r
1793         $powers = array();\r
1794         $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);\r
1795         $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);\r
1796 \r
1797         // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end\r
1798         // in a 1.  ie. it's supposed to be odd.\r
1799         $temp = 1 << ($window_size - 1);\r
1800         for ($i = 1; $i < $temp; ++$i) {\r
1801             $i2 = $i << 1;\r
1802             $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);\r
1803         }\r
1804 \r
1805         $result = array(1);\r
1806         $result = $this->_prepareReduce($result, $n_value, $mode);\r
1807 \r
1808         for ($i = 0; $i < $e_length; ) {\r
1809             if ( !$e_bits[$i] ) {\r
1810                 $result = $this->_squareReduce($result, $n_value, $mode);\r
1811                 ++$i;\r
1812             } else {\r
1813                 for ($j = $window_size - 1; $j > 0; --$j) {\r
1814                     if ( !empty($e_bits[$i + $j]) ) {\r
1815                         break;\r
1816                     }\r
1817                 }\r
1818 \r
1819                 for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)\r
1820                     $result = $this->_squareReduce($result, $n_value, $mode);\r
1821                 }\r
1822 \r
1823                 $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);\r
1824 \r
1825                 $i+=$j + 1;\r
1826             }\r
1827         }\r
1828 \r
1829         $temp = new Math_BigInteger();\r
1830         $temp->value = $this->_reduce($result, $n_value, $mode);\r
1831 \r
1832         return $temp;\r
1833     }\r
1834 \r
1835     /**\r
1836      * Modular reduction\r
1837      *\r
1838      * For most $modes this will return the remainder.\r
1839      *\r
1840      * @see _slidingWindow()\r
1841      * @access private\r
1842      * @param Array $x\r
1843      * @param Array $n\r
1844      * @param Integer $mode\r
1845      * @return Array\r
1846      */\r
1847     function _reduce($x, $n, $mode)\r
1848     {\r
1849         switch ($mode) {\r
1850             case MATH_BIGINTEGER_MONTGOMERY:\r
1851                 return $this->_montgomery($x, $n);\r
1852             case MATH_BIGINTEGER_BARRETT:\r
1853                 return $this->_barrett($x, $n);\r
1854             case MATH_BIGINTEGER_POWEROF2:\r
1855                 $lhs = new Math_BigInteger();\r
1856                 $lhs->value = $x;\r
1857                 $rhs = new Math_BigInteger();\r
1858                 $rhs->value = $n;\r
1859                 return $x->_mod2($n);\r
1860             case MATH_BIGINTEGER_CLASSIC:\r
1861                 $lhs = new Math_BigInteger();\r
1862                 $lhs->value = $x;\r
1863                 $rhs = new Math_BigInteger();\r
1864                 $rhs->value = $n;\r
1865                 list(, $temp) = $lhs->divide($rhs);\r
1866                 return $temp->value;\r
1867             case MATH_BIGINTEGER_NONE:\r
1868                 return $x;\r
1869             default:\r
1870                 // an invalid $mode was provided\r
1871         }\r
1872     }\r
1873 \r
1874     /**\r
1875      * Modular reduction preperation\r
1876      *\r
1877      * @see _slidingWindow()\r
1878      * @access private\r
1879      * @param Array $x\r
1880      * @param Array $n\r
1881      * @param Integer $mode\r
1882      * @return Array\r
1883      */\r
1884     function _prepareReduce($x, $n, $mode)\r
1885     {\r
1886         if ($mode == MATH_BIGINTEGER_MONTGOMERY) {\r
1887             return $this->_prepMontgomery($x, $n);\r
1888         }\r
1889         return $this->_reduce($x, $n, $mode);\r
1890     }\r
1891 \r
1892     /**\r
1893      * Modular multiply\r
1894      *\r
1895      * @see _slidingWindow()\r
1896      * @access private\r
1897      * @param Array $x\r
1898      * @param Array $y\r
1899      * @param Array $n\r
1900      * @param Integer $mode\r
1901      * @return Array\r
1902      */\r
1903     function _multiplyReduce($x, $y, $n, $mode)\r
1904     {\r
1905         if ($mode == MATH_BIGINTEGER_MONTGOMERY) {\r
1906             return $this->_montgomeryMultiply($x, $y, $n);\r
1907         }\r
1908         $temp = $this->_multiply($x, false, $y, false);\r
1909         return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);\r
1910     }\r
1911 \r
1912     /**\r
1913      * Modular square\r
1914      *\r
1915      * @see _slidingWindow()\r
1916      * @access private\r
1917      * @param Array $x\r
1918      * @param Array $n\r
1919      * @param Integer $mode\r
1920      * @return Array\r
1921      */\r
1922     function _squareReduce($x, $n, $mode)\r
1923     {\r
1924         if ($mode == MATH_BIGINTEGER_MONTGOMERY) {\r
1925             return $this->_montgomeryMultiply($x, $x, $n);\r
1926         }\r
1927         return $this->_reduce($this->_square($x), $n, $mode);\r
1928     }\r
1929 \r
1930     /**\r
1931      * Modulos for Powers of Two\r
1932      *\r
1933      * Calculates $x%$n, where $n = 2**$e, for some $e.  Since this is basically the same as doing $x & ($n-1),\r
1934      * we'll just use this function as a wrapper for doing that.\r
1935      *\r
1936      * @see _slidingWindow()\r
1937      * @access private\r
1938      * @param Math_BigInteger\r
1939      * @return Math_BigInteger\r
1940      */\r
1941     function _mod2($n)\r
1942     {\r
1943         $temp = new Math_BigInteger();\r
1944         $temp->value = array(1);\r
1945         return $this->bitwise_and($n->subtract($temp));\r
1946     }\r
1947 \r
1948     /**\r
1949      * Barrett Modular Reduction\r
1950      *\r
1951      * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /\r
1952      * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information.  Modified slightly,\r
1953      * so as not to require negative numbers (initially, this script didn't support negative numbers).\r
1954      *\r
1955      * Employs "folding", as described at\r
1956      * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}.  To quote from\r
1957      * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."\r
1958      *\r
1959      * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that\r
1960      * usable on account of (1) its not using reasonable radix points as discussed in\r
1961      * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable\r
1962      * radix points, it only works when there are an even number of digits in the denominator.  The reason for (2) is that\r
1963      * (x >> 1) + (x >> 1) != x / 2 + x / 2.  If x is even, they're the same, but if x is odd, they're not.  See the in-line\r
1964      * comments for details.\r
1965      *\r
1966      * @see _slidingWindow()\r
1967      * @access private\r
1968      * @param Array $n\r
1969      * @param Array $m\r
1970      * @return Array\r
1971      */\r
1972     function _barrett($n, $m)\r
1973     {\r
1974         static $cache = array(\r
1975             MATH_BIGINTEGER_VARIABLE => array(),\r
1976             MATH_BIGINTEGER_DATA => array()\r
1977         );\r
1978 \r
1979         $m_length = count($m);\r
1980 \r
1981         // if ($this->_compare($n, $this->_square($m)) >= 0) {\r
1982         if (count($n) > 2 * $m_length) {\r
1983             $lhs = new Math_BigInteger();\r
1984             $rhs = new Math_BigInteger();\r
1985             $lhs->value = $n;\r
1986             $rhs->value = $m;\r
1987             list(, $temp) = $lhs->divide($rhs);\r
1988             return $temp->value;\r
1989         }\r
1990 \r
1991         // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced\r
1992         if ($m_length < 5) {\r
1993             return $this->_regularBarrett($n, $m);\r
1994         }\r
1995 \r
1996         // n = 2 * m.length\r
1997 \r
1998         if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {\r
1999             $key = count($cache[MATH_BIGINTEGER_VARIABLE]);\r
2000             $cache[MATH_BIGINTEGER_VARIABLE][] = $m;\r
2001 \r
2002             $lhs = new Math_BigInteger();\r
2003             $lhs_value = &$lhs->value;\r
2004             $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));\r
2005             $lhs_value[] = 1;\r
2006             $rhs = new Math_BigInteger();\r
2007             $rhs->value = $m;\r
2008 \r
2009             list($u, $m1) = $lhs->divide($rhs);\r
2010             $u = $u->value;\r
2011             $m1 = $m1->value;\r
2012 \r
2013             $cache[MATH_BIGINTEGER_DATA][] = array(\r
2014                 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)\r
2015                 'm1'=> $m1 // m.length\r
2016             );\r
2017         } else {\r
2018             extract($cache[MATH_BIGINTEGER_DATA][$key]);\r
2019         }\r
2020 \r
2021         $cutoff = $m_length + ($m_length >> 1);\r
2022         $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)\r
2023         $msd = array_slice($n, $cutoff);    // m.length >> 1\r
2024         $lsd = $this->_trim($lsd);\r
2025         $temp = $this->_multiply($msd, false, $m1, false);\r
2026         $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1\r
2027 \r
2028         if ($m_length & 1) {\r
2029             return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);\r
2030         }\r
2031 \r
2032         // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2\r
2033         $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);\r
2034         // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2\r
2035         // if odd:  ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1\r
2036         $temp = $this->_multiply($temp, false, $u, false);\r
2037         // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1\r
2038         // if odd:  (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)\r
2039         $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);\r
2040         // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1\r
2041         // if odd:  (m.length - (m.length >> 1)) + m.length     = 2 * m.length - (m.length >> 1)\r
2042         $temp = $this->_multiply($temp, false, $m, false);\r
2043 \r
2044         // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit\r
2045         // number from a m.length + (m.length >> 1) + 1 digit number.  ie. there'd be an extra digit and the while loop\r
2046         // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).\r
2047 \r
2048         $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);\r
2049 \r
2050         while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {\r
2051             $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);\r
2052         }\r
2053 \r
2054         return $result[MATH_BIGINTEGER_VALUE];\r
2055     }\r
2056 \r
2057     /**\r
2058      * (Regular) Barrett Modular Reduction\r
2059      *\r
2060      * For numbers with more than four digits Math_BigInteger::_barrett() is faster.  The difference between that and this\r
2061      * is that this function does not fold the denominator into a smaller form.\r
2062      *\r
2063      * @see _slidingWindow()\r
2064      * @access private\r
2065      * @param Array $x\r
2066      * @param Array $n\r
2067      * @return Array\r
2068      */\r
2069     function _regularBarrett($x, $n)\r
2070     {\r
2071         static $cache = array(\r
2072             MATH_BIGINTEGER_VARIABLE => array(),\r
2073             MATH_BIGINTEGER_DATA => array()\r
2074         );\r
2075 \r
2076         $n_length = count($n);\r
2077 \r
2078         if (count($x) > 2 * $n_length) {\r
2079             $lhs = new Math_BigInteger();\r
2080             $rhs = new Math_BigInteger();\r
2081             $lhs->value = $x;\r
2082             $rhs->value = $n;\r
2083             list(, $temp) = $lhs->divide($rhs);\r
2084             return $temp->value;\r
2085         }\r
2086 \r
2087         if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {\r
2088             $key = count($cache[MATH_BIGINTEGER_VARIABLE]);\r
2089             $cache[MATH_BIGINTEGER_VARIABLE][] = $n;\r
2090             $lhs = new Math_BigInteger();\r
2091             $lhs_value = &$lhs->value;\r
2092             $lhs_value = $this->_array_repeat(0, 2 * $n_length);\r
2093             $lhs_value[] = 1;\r
2094             $rhs = new Math_BigInteger();\r
2095             $rhs->value = $n;\r
2096             list($temp, ) = $lhs->divide($rhs); // m.length\r
2097             $cache[MATH_BIGINTEGER_DATA][] = $temp->value;\r
2098         }\r
2099 \r
2100         // 2 * m.length - (m.length - 1) = m.length + 1\r
2101         $temp = array_slice($x, $n_length - 1);\r
2102         // (m.length + 1) + m.length = 2 * m.length + 1\r
2103         $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);\r
2104         // (2 * m.length + 1) - (m.length - 1) = m.length + 2\r
2105         $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);\r
2106 \r
2107         // m.length + 1\r
2108         $result = array_slice($x, 0, $n_length + 1);\r
2109         // m.length + 1\r
2110         $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);\r
2111         // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)\r
2112 \r
2113         if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {\r
2114             $corrector_value = $this->_array_repeat(0, $n_length + 1);\r
2115             $corrector_value[] = 1;\r
2116             $result = $this->_add($result, false, $corrector_value, false);\r
2117             $result = $result[MATH_BIGINTEGER_VALUE];\r
2118         }\r
2119 \r
2120         // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits\r
2121         $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);\r
2122         while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {\r
2123             $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);\r
2124         }\r
2125 \r
2126         return $result[MATH_BIGINTEGER_VALUE];\r
2127     }\r
2128 \r
2129     /**\r
2130      * Performs long multiplication up to $stop digits\r
2131      *\r
2132      * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.\r
2133      *\r
2134      * @see _regularBarrett()\r
2135      * @param Array $x_value\r
2136      * @param Boolean $x_negative\r
2137      * @param Array $y_value\r
2138      * @param Boolean $y_negative\r
2139      * @param Integer $stop\r
2140      * @return Array\r
2141      * @access private\r
2142      */\r
2143     function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)\r
2144     {\r
2145         $x_length = count($x_value);\r
2146         $y_length = count($y_value);\r
2147 \r
2148         if ( !$x_length || !$y_length ) { // a 0 is being multiplied\r
2149             return array(\r
2150                 MATH_BIGINTEGER_VALUE => array(),\r
2151                 MATH_BIGINTEGER_SIGN => false\r
2152             );\r
2153         }\r
2154 \r
2155         if ( $x_length < $y_length ) {\r
2156             $temp = $x_value;\r
2157             $x_value = $y_value;\r
2158             $y_value = $temp;\r
2159 \r
2160             $x_length = count($x_value);\r
2161             $y_length = count($y_value);\r
2162         }\r
2163 \r
2164         $product_value = $this->_array_repeat(0, $x_length + $y_length);\r
2165 \r
2166         // the following for loop could be removed if the for loop following it\r
2167         // (the one with nested for loops) initially set $i to 0, but\r
2168         // doing so would also make the result in one set of unnecessary adds,\r
2169         // since on the outermost loops first pass, $product->value[$k] is going\r
2170         // to always be 0\r
2171 \r
2172         $carry = 0;\r
2173 \r
2174         for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i\r
2175             $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0\r
2176             $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);\r
2177             $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);\r
2178         }\r
2179 \r
2180         if ($j < $stop) {\r
2181             $product_value[$j] = $carry;\r
2182         }\r
2183 \r
2184         // the above for loop is what the previous comment was talking about.  the\r
2185         // following for loop is the "one with nested for loops"\r
2186 \r
2187         for ($i = 1; $i < $y_length; ++$i) {\r
2188             $carry = 0;\r
2189 \r
2190             for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {\r
2191                 $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;\r
2192                 $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);\r
2193                 $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);\r
2194             }\r
2195 \r
2196             if ($k < $stop) {\r
2197                 $product_value[$k] = $carry;\r
2198             }\r
2199         }\r
2200 \r
2201         return array(\r
2202             MATH_BIGINTEGER_VALUE => $this->_trim($product_value),\r
2203             MATH_BIGINTEGER_SIGN => $x_negative != $y_negative\r
2204         );\r
2205     }\r
2206 \r
2207     /**\r
2208      * Montgomery Modular Reduction\r
2209      *\r
2210      * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.\r
2211      * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be\r
2212      * improved upon (basically, by using the comba method).  gcd($n, 2) must be equal to one for this function\r
2213      * to work correctly.\r
2214      *\r
2215      * @see _prepMontgomery()\r
2216      * @see _slidingWindow()\r
2217      * @access private\r
2218      * @param Array $x\r
2219      * @param Array $n\r
2220      * @return Array\r
2221      */\r
2222     function _montgomery($x, $n)\r
2223     {\r
2224         static $cache = array(\r
2225             MATH_BIGINTEGER_VARIABLE => array(),\r
2226             MATH_BIGINTEGER_DATA => array()\r
2227         );\r
2228 \r
2229         if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {\r
2230             $key = count($cache[MATH_BIGINTEGER_VARIABLE]);\r
2231             $cache[MATH_BIGINTEGER_VARIABLE][] = $x;\r
2232             $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);\r
2233         }\r
2234 \r
2235         $k = count($n);\r
2236 \r
2237         $result = array(MATH_BIGINTEGER_VALUE => $x);\r
2238 \r
2239         for ($i = 0; $i < $k; ++$i) {\r
2240             $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];\r
2241             $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));\r
2242             $temp = $this->_regularMultiply(array($temp), $n);\r
2243             $temp = array_merge($this->_array_repeat(0, $i), $temp);\r
2244             $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);\r
2245         }\r
2246 \r
2247         $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);\r
2248 \r
2249         if ($this->_compare($result, false, $n, false) >= 0) {\r
2250             $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);\r
2251         }\r
2252 \r
2253         return $result[MATH_BIGINTEGER_VALUE];\r
2254     }\r
2255 \r
2256     /**\r
2257      * Montgomery Multiply\r
2258      *\r
2259      * Interleaves the montgomery reduction and long multiplication algorithms together as described in \r
2260      * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}\r
2261      *\r
2262      * @see _prepMontgomery()\r
2263      * @see _montgomery()\r
2264      * @access private\r
2265      * @param Array $x\r
2266      * @param Array $y\r
2267      * @param Array $m\r
2268      * @return Array\r
2269      */\r
2270     function _montgomeryMultiply($x, $y, $m)\r
2271     {\r
2272         $temp = $this->_multiply($x, false, $y, false);\r
2273         return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);\r
2274 \r
2275         static $cache = array(\r
2276             MATH_BIGINTEGER_VARIABLE => array(),\r
2277             MATH_BIGINTEGER_DATA => array()\r
2278         );\r
2279 \r
2280         if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {\r
2281             $key = count($cache[MATH_BIGINTEGER_VARIABLE]);\r
2282             $cache[MATH_BIGINTEGER_VARIABLE][] = $m;\r
2283             $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);\r
2284         }\r
2285 \r
2286         $n = max(count($x), count($y), count($m));\r
2287         $x = array_pad($x, $n, 0);\r
2288         $y = array_pad($y, $n, 0);\r
2289         $m = array_pad($m, $n, 0);\r
2290         $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));\r
2291         for ($i = 0; $i < $n; ++$i) {\r
2292             $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];\r
2293             $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));\r
2294             $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];\r
2295             $temp = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * ((int) ($temp / MATH_BIGINTEGER_BASE_FULL)));\r
2296             $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);\r
2297             $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);\r
2298             $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);\r
2299         }\r
2300         if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {\r
2301             $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);\r
2302         }\r
2303         return $a[MATH_BIGINTEGER_VALUE];\r
2304     }\r
2305 \r
2306     /**\r
2307      * Prepare a number for use in Montgomery Modular Reductions\r
2308      *\r
2309      * @see _montgomery()\r
2310      * @see _slidingWindow()\r
2311      * @access private\r
2312      * @param Array $x\r
2313      * @param Array $n\r
2314      * @return Array\r
2315      */\r
2316     function _prepMontgomery($x, $n)\r
2317     {\r
2318         $lhs = new Math_BigInteger();\r
2319         $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);\r
2320         $rhs = new Math_BigInteger();\r
2321         $rhs->value = $n;\r
2322 \r
2323         list(, $temp) = $lhs->divide($rhs);\r
2324         return $temp->value;\r
2325     }\r
2326 \r
2327     /**\r
2328      * Modular Inverse of a number mod 2**26 (eg. 67108864)\r
2329      *\r
2330      * Based off of the bnpInvDigit function implemented and justified in the following URL:\r
2331      *\r
2332      * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}\r
2333      *\r
2334      * The following URL provides more info:\r
2335      *\r
2336      * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}\r
2337      *\r
2338      * As for why we do all the bitmasking...  strange things can happen when converting from floats to ints. For\r
2339      * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields \r
2340      * int(-2147483648).  To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't\r
2341      * auto-converted to floats.  The outermost bitmask is present because without it, there's no guarantee that\r
2342      * the "residue" returned would be the so-called "common residue".  We use fmod, in the last step, because the\r
2343      * maximum possible $x is 26 bits and the maximum $result is 16 bits.  Thus, we have to be able to handle up to\r
2344      * 40 bits, which only 64-bit floating points will support.\r
2345      *\r
2346      * Thanks to Pedro Gimeno Fortea for input!\r
2347      *\r
2348      * @see _montgomery()\r
2349      * @access private\r
2350      * @param Array $x\r
2351      * @return Integer\r
2352      */\r
2353     function _modInverse67108864($x) // 2**26 == 67,108,864\r
2354     {\r
2355         $x = -$x[0];\r
2356         $result = $x & 0x3; // x**-1 mod 2**2\r
2357         $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4\r
2358         $result = ($result * (2 - ($x & 0xFF) * $result))  & 0xFF; // x**-1 mod 2**8\r
2359         $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16\r
2360         $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26\r
2361         return $result & MATH_BIGINTEGER_MAX_DIGIT;\r
2362     }\r
2363 \r
2364     /**\r
2365      * Calculates modular inverses.\r
2366      *\r
2367      * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.\r
2368      *\r
2369      * Here's an example:\r
2370      * <code>\r
2371      * <?php\r
2372      *    include('Math/BigInteger.php');\r
2373      *\r
2374      *    $a = new Math_BigInteger(30);\r
2375      *    $b = new Math_BigInteger(17);\r
2376      *\r
2377      *    $c = $a->modInverse($b);\r
2378      *    echo $c->toString(); // outputs 4\r
2379      *\r
2380      *    echo "\r\n";\r
2381      *\r
2382      *    $d = $a->multiply($c);\r
2383      *    list(, $d) = $d->divide($b);\r
2384      *    echo $d; // outputs 1 (as per the definition of modular inverse)\r
2385      * ?>\r
2386      * </code>\r
2387      *\r
2388      * @param Math_BigInteger $n\r
2389      * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise.\r
2390      * @access public\r
2391      * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.\r
2392      */\r
2393     function modInverse($n)\r
2394     {\r
2395         switch ( MATH_BIGINTEGER_MODE ) {\r
2396             case MATH_BIGINTEGER_MODE_GMP:\r
2397                 $temp = new Math_BigInteger();\r
2398                 $temp->value = gmp_invert($this->value, $n->value);\r
2399 \r
2400                 return ( $temp->value === false ) ? false : $this->_normalize($temp);\r
2401         }\r
2402 \r
2403         static $zero, $one;\r
2404         if (!isset($zero)) {\r
2405             $zero = new Math_BigInteger();\r
2406             $one = new Math_BigInteger(1);\r
2407         }\r
2408 \r
2409         // $x mod -$n == $x mod $n.\r
2410         $n = $n->abs();\r
2411 \r
2412         if ($this->compare($zero) < 0) {\r
2413             $temp = $this->abs();\r
2414             $temp = $temp->modInverse($n);\r
2415             return $this->_normalize($n->subtract($temp));\r
2416         }\r
2417 \r
2418         extract($this->extendedGCD($n));\r
2419 \r
2420         if (!$gcd->equals($one)) {\r
2421             return false;\r
2422         }\r
2423 \r
2424         $x = $x->compare($zero) < 0 ? $x->add($n) : $x;\r
2425 \r
2426         return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);\r
2427     }\r
2428 \r
2429     /**\r
2430      * Calculates the greatest common divisor and Bezout's identity.\r
2431      *\r
2432      * Say you have 693 and 609.  The GCD is 21.  Bezout's identity states that there exist integers x and y such that\r
2433      * 693*x + 609*y == 21.  In point of fact, there are actually an infinite number of x and y combinations and which\r
2434      * combination is returned is dependant upon which mode is in use.  See\r
2435      * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.\r
2436      *\r
2437      * Here's an example:\r
2438      * <code>\r
2439      * <?php\r
2440      *    include('Math/BigInteger.php');\r
2441      *\r
2442      *    $a = new Math_BigInteger(693);\r
2443      *    $b = new Math_BigInteger(609);\r
2444      *\r
2445      *    extract($a->extendedGCD($b));\r
2446      *\r
2447      *    echo $gcd->toString() . "\r\n"; // outputs 21\r
2448      *    echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21\r
2449      * ?>\r
2450      * </code>\r
2451      *\r
2452      * @param Math_BigInteger $n\r
2453      * @return Math_BigInteger\r
2454      * @access public\r
2455      * @internal Calculates the GCD using the binary xGCD algorithim described in\r
2456      *    {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}.  As the text above 14.61 notes,\r
2457      *    the more traditional algorithim requires "relatively costly multiple-precision divisions".\r
2458      */\r
2459     function extendedGCD($n)\r
2460     {\r
2461         switch ( MATH_BIGINTEGER_MODE ) {\r
2462             case MATH_BIGINTEGER_MODE_GMP:\r
2463                 extract(gmp_gcdext($this->value, $n->value));\r
2464 \r
2465                 return array(\r
2466                     'gcd' => $this->_normalize(new Math_BigInteger($g)),\r
2467                     'x'   => $this->_normalize(new Math_BigInteger($s)),\r
2468                     'y'   => $this->_normalize(new Math_BigInteger($t))\r
2469                 );\r
2470             case MATH_BIGINTEGER_MODE_BCMATH:\r
2471                 // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works\r
2472                 // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway.  as is,\r
2473                 // the basic extended euclidean algorithim is what we're using.\r
2474 \r
2475                 $u = $this->value;\r
2476                 $v = $n->value;\r
2477 \r
2478                 $a = '1';\r
2479                 $b = '0';\r
2480                 $c = '0';\r
2481                 $d = '1';\r
2482 \r
2483                 while (bccomp($v, '0', 0) != 0) {\r
2484                     $q = bcdiv($u, $v, 0);\r
2485 \r
2486                     $temp = $u;\r
2487                     $u = $v;\r
2488                     $v = bcsub($temp, bcmul($v, $q, 0), 0);\r
2489 \r
2490                     $temp = $a;\r
2491                     $a = $c;\r
2492                     $c = bcsub($temp, bcmul($a, $q, 0), 0);\r
2493 \r
2494                     $temp = $b;\r
2495                     $b = $d;\r
2496                     $d = bcsub($temp, bcmul($b, $q, 0), 0);\r
2497                 }\r
2498 \r
2499                 return array(\r
2500                     'gcd' => $this->_normalize(new Math_BigInteger($u)),\r
2501                     'x'   => $this->_normalize(new Math_BigInteger($a)),\r
2502                     'y'   => $this->_normalize(new Math_BigInteger($b))\r
2503                 );\r
2504         }\r
2505 \r
2506         $y = $n->copy();\r
2507         $x = $this->copy();\r
2508         $g = new Math_BigInteger();\r
2509         $g->value = array(1);\r
2510 \r
2511         while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {\r
2512             $x->_rshift(1);\r
2513             $y->_rshift(1);\r
2514             $g->_lshift(1);\r
2515         }\r
2516 \r
2517         $u = $x->copy();\r
2518         $v = $y->copy();\r
2519 \r
2520         $a = new Math_BigInteger();\r
2521         $b = new Math_BigInteger();\r
2522         $c = new Math_BigInteger();\r
2523         $d = new Math_BigInteger();\r
2524 \r
2525         $a->value = $d->value = $g->value = array(1);\r
2526         $b->value = $c->value = array();\r
2527 \r
2528         while ( !empty($u->value) ) {\r
2529             while ( !($u->value[0] & 1) ) {\r
2530                 $u->_rshift(1);\r
2531                 if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) {\r
2532                     $a = $a->add($y);\r
2533                     $b = $b->subtract($x);\r
2534                 }\r
2535                 $a->_rshift(1);\r
2536                 $b->_rshift(1);\r
2537             }\r
2538 \r
2539             while ( !($v->value[0] & 1) ) {\r
2540                 $v->_rshift(1);\r
2541                 if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) {\r
2542                     $c = $c->add($y);\r
2543                     $d = $d->subtract($x);\r
2544                 }\r
2545                 $c->_rshift(1);\r
2546                 $d->_rshift(1);\r
2547             }\r
2548 \r
2549             if ($u->compare($v) >= 0) {\r
2550                 $u = $u->subtract($v);\r
2551                 $a = $a->subtract($c);\r
2552                 $b = $b->subtract($d);\r
2553             } else {\r
2554                 $v = $v->subtract($u);\r
2555                 $c = $c->subtract($a);\r
2556                 $d = $d->subtract($b);\r
2557             }\r
2558         }\r
2559 \r
2560         return array(\r
2561             'gcd' => $this->_normalize($g->multiply($v)),\r
2562             'x'   => $this->_normalize($c),\r
2563             'y'   => $this->_normalize($d)\r
2564         );\r
2565     }\r
2566 \r
2567     /**\r
2568      * Calculates the greatest common divisor\r
2569      *\r
2570      * Say you have 693 and 609.  The GCD is 21.\r
2571      *\r
2572      * Here's an example:\r
2573      * <code>\r
2574      * <?php\r
2575      *    include('Math/BigInteger.php');\r
2576      *\r
2577      *    $a = new Math_BigInteger(693);\r
2578      *    $b = new Math_BigInteger(609);\r
2579      *\r
2580      *    $gcd = a->extendedGCD($b);\r
2581      *\r
2582      *    echo $gcd->toString() . "\r\n"; // outputs 21\r
2583      * ?>\r
2584      * </code>\r
2585      *\r
2586      * @param Math_BigInteger $n\r
2587      * @return Math_BigInteger\r
2588      * @access public\r
2589      */\r
2590     function gcd($n)\r
2591     {\r
2592         extract($this->extendedGCD($n));\r
2593         return $gcd;\r
2594     }\r
2595 \r
2596     /**\r
2597      * Absolute value.\r
2598      *\r
2599      * @return Math_BigInteger\r
2600      * @access public\r
2601      */\r
2602     function abs()\r
2603     {\r
2604         $temp = new Math_BigInteger();\r
2605 \r
2606         switch ( MATH_BIGINTEGER_MODE ) {\r
2607             case MATH_BIGINTEGER_MODE_GMP:\r
2608                 $temp->value = gmp_abs($this->value);\r
2609                 break;\r
2610             case MATH_BIGINTEGER_MODE_BCMATH:\r
2611                 $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;\r
2612                 break;\r
2613             default:\r
2614                 $temp->value = $this->value;\r
2615         }\r
2616 \r
2617         return $temp;\r
2618     }\r
2619 \r
2620     /**\r
2621      * Compares two numbers.\r
2622      *\r
2623      * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this is\r
2624      * demonstrated thusly:\r
2625      *\r
2626      * $x  > $y: $x->compare($y)  > 0\r
2627      * $x  < $y: $x->compare($y)  < 0\r
2628      * $x == $y: $x->compare($y) == 0\r
2629      *\r
2630      * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).\r
2631      *\r
2632      * @param Math_BigInteger $y\r
2633      * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.\r
2634      * @access public\r
2635      * @see equals()\r
2636      * @internal Could return $this->subtract($x), but that's not as fast as what we do do.\r
2637      */\r
2638     function compare($y)\r
2639     {\r
2640         switch ( MATH_BIGINTEGER_MODE ) {\r
2641             case MATH_BIGINTEGER_MODE_GMP:\r
2642                 return gmp_cmp($this->value, $y->value);\r
2643             case MATH_BIGINTEGER_MODE_BCMATH:\r
2644                 return bccomp($this->value, $y->value, 0);\r
2645         }\r
2646 \r
2647         return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);\r
2648     }\r
2649 \r
2650     /**\r
2651      * Compares two numbers.\r
2652      *\r
2653      * @param Array $x_value\r
2654      * @param Boolean $x_negative\r
2655      * @param Array $y_value\r
2656      * @param Boolean $y_negative\r
2657      * @return Integer\r
2658      * @see compare()\r
2659      * @access private\r
2660      */\r
2661     function _compare($x_value, $x_negative, $y_value, $y_negative)\r
2662     {\r
2663         if ( $x_negative != $y_negative ) {\r
2664             return ( !$x_negative && $y_negative ) ? 1 : -1;\r
2665         }\r
2666 \r
2667         $result = $x_negative ? -1 : 1;\r
2668 \r
2669         if ( count($x_value) != count($y_value) ) {\r
2670             return ( count($x_value) > count($y_value) ) ? $result : -$result;\r
2671         }\r
2672         $size = max(count($x_value), count($y_value));\r
2673 \r
2674         $x_value = array_pad($x_value, $size, 0);\r
2675         $y_value = array_pad($y_value, $size, 0);\r
2676 \r
2677         for ($i = count($x_value) - 1; $i >= 0; --$i) {\r
2678             if ($x_value[$i] != $y_value[$i]) {\r
2679                 return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;\r
2680             }\r
2681         }\r
2682 \r
2683         return 0;\r
2684     }\r
2685 \r
2686     /**\r
2687      * Tests the equality of two numbers.\r
2688      *\r
2689      * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()\r
2690      *\r
2691      * @param Math_BigInteger $x\r
2692      * @return Boolean\r
2693      * @access public\r
2694      * @see compare()\r
2695      */\r
2696     function equals($x)\r
2697     {\r
2698         switch ( MATH_BIGINTEGER_MODE ) {\r
2699             case MATH_BIGINTEGER_MODE_GMP:\r
2700                 return gmp_cmp($this->value, $x->value) == 0;\r
2701             default:\r
2702                 return $this->value === $x->value && $this->is_negative == $x->is_negative;\r
2703         }\r
2704     }\r
2705 \r
2706     /**\r
2707      * Set Precision\r
2708      *\r
2709      * Some bitwise operations give different results depending on the precision being used.  Examples include left\r
2710      * shift, not, and rotates.\r
2711      *\r
2712      * @param Integer $bits\r
2713      * @access public\r
2714      */\r
2715     function setPrecision($bits)\r
2716     {\r
2717         $this->precision = $bits;\r
2718         if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {\r
2719             $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);\r
2720         } else {\r
2721             $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));\r
2722         }\r
2723 \r
2724         $temp = $this->_normalize($this);\r
2725         $this->value = $temp->value;\r
2726     }\r
2727 \r
2728     /**\r
2729      * Logical And\r
2730      *\r
2731      * @param Math_BigInteger $x\r
2732      * @access public\r
2733      * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>\r
2734      * @return Math_BigInteger\r
2735      */\r
2736     function bitwise_and($x)\r
2737     {\r
2738         switch ( MATH_BIGINTEGER_MODE ) {\r
2739             case MATH_BIGINTEGER_MODE_GMP:\r
2740                 $temp = new Math_BigInteger();\r
2741                 $temp->value = gmp_and($this->value, $x->value);\r
2742 \r
2743                 return $this->_normalize($temp);\r
2744             case MATH_BIGINTEGER_MODE_BCMATH:\r
2745                 $left = $this->toBytes();\r
2746                 $right = $x->toBytes();\r
2747 \r
2748                 $length = max(strlen($left), strlen($right));\r
2749 \r
2750                 $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);\r
2751                 $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);\r
2752 \r
2753                 return $this->_normalize(new Math_BigInteger($left & $right, 256));\r
2754         }\r
2755 \r
2756         $result = $this->copy();\r
2757 \r
2758         $length = min(count($x->value), count($this->value));\r
2759 \r
2760         $result->value = array_slice($result->value, 0, $length);\r
2761 \r
2762         for ($i = 0; $i < $length; ++$i) {\r
2763             $result->value[$i]&= $x->value[$i];\r
2764         }\r
2765 \r
2766         return $this->_normalize($result);\r
2767     }\r
2768 \r
2769     /**\r
2770      * Logical Or\r
2771      *\r
2772      * @param Math_BigInteger $x\r
2773      * @access public\r
2774      * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>\r
2775      * @return Math_BigInteger\r
2776      */\r
2777     function bitwise_or($x)\r
2778     {\r
2779         switch ( MATH_BIGINTEGER_MODE ) {\r
2780             case MATH_BIGINTEGER_MODE_GMP:\r
2781                 $temp = new Math_BigInteger();\r
2782                 $temp->value = gmp_or($this->value, $x->value);\r
2783 \r
2784                 return $this->_normalize($temp);\r
2785             case MATH_BIGINTEGER_MODE_BCMATH:\r
2786                 $left = $this->toBytes();\r
2787                 $right = $x->toBytes();\r
2788 \r
2789                 $length = max(strlen($left), strlen($right));\r
2790 \r
2791                 $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);\r
2792                 $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);\r
2793 \r
2794                 return $this->_normalize(new Math_BigInteger($left | $right, 256));\r
2795         }\r
2796 \r
2797         $length = max(count($this->value), count($x->value));\r
2798         $result = $this->copy();\r
2799         $result->value = array_pad($result->value, $length, 0);\r
2800         $x->value = array_pad($x->value, $length, 0);\r
2801 \r
2802         for ($i = 0; $i < $length; ++$i) {\r
2803             $result->value[$i]|= $x->value[$i];\r
2804         }\r
2805 \r
2806         return $this->_normalize($result);\r
2807     }\r
2808 \r
2809     /**\r
2810      * Logical Exclusive-Or\r
2811      *\r
2812      * @param Math_BigInteger $x\r
2813      * @access public\r
2814      * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>\r
2815      * @return Math_BigInteger\r
2816      */\r
2817     function bitwise_xor($x)\r
2818     {\r
2819         switch ( MATH_BIGINTEGER_MODE ) {\r
2820             case MATH_BIGINTEGER_MODE_GMP:\r
2821                 $temp = new Math_BigInteger();\r
2822                 $temp->value = gmp_xor($this->value, $x->value);\r
2823 \r
2824                 return $this->_normalize($temp);\r
2825             case MATH_BIGINTEGER_MODE_BCMATH:\r
2826                 $left = $this->toBytes();\r
2827                 $right = $x->toBytes();\r
2828 \r
2829                 $length = max(strlen($left), strlen($right));\r
2830 \r
2831                 $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);\r
2832                 $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);\r
2833 \r
2834                 return $this->_normalize(new Math_BigInteger($left ^ $right, 256));\r
2835         }\r
2836 \r
2837         $length = max(count($this->value), count($x->value));\r
2838         $result = $this->copy();\r
2839         $result->value = array_pad($result->value, $length, 0);\r
2840         $x->value = array_pad($x->value, $length, 0);\r
2841 \r
2842         for ($i = 0; $i < $length; ++$i) {\r
2843             $result->value[$i]^= $x->value[$i];\r
2844         }\r
2845 \r
2846         return $this->_normalize($result);\r
2847     }\r
2848 \r
2849     /**\r
2850      * Logical Not\r
2851      *\r
2852      * @access public\r
2853      * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>\r
2854      * @return Math_BigInteger\r
2855      */\r
2856     function bitwise_not()\r
2857     {\r
2858         // calculuate "not" without regard to $this->precision\r
2859         // (will always result in a smaller number.  ie. ~1 isn't 1111 1110 - it's 0)\r
2860         $temp = $this->toBytes();\r
2861         $pre_msb = decbin(ord($temp[0]));\r
2862         $temp = ~$temp;\r
2863         $msb = decbin(ord($temp[0]));\r
2864         if (strlen($msb) == 8) {\r
2865             $msb = substr($msb, strpos($msb, '0'));\r
2866         }\r
2867         $temp[0] = chr(bindec($msb));\r
2868 \r
2869         // see if we need to add extra leading 1's\r
2870         $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;\r
2871         $new_bits = $this->precision - $current_bits;\r
2872         if ($new_bits <= 0) {\r
2873             return $this->_normalize(new Math_BigInteger($temp, 256));\r
2874         }\r
2875 \r
2876         // generate as many leading 1's as we need to.\r
2877         $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);\r
2878         $this->_base256_lshift($leading_ones, $current_bits);\r
2879 \r
2880         $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT);\r
2881 \r
2882         return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));\r
2883     }\r
2884 \r
2885     /**\r
2886      * Logical Right Shift\r
2887      *\r
2888      * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.\r
2889      *\r
2890      * @param Integer $shift\r
2891      * @return Math_BigInteger\r
2892      * @access public\r
2893      * @internal The only version that yields any speed increases is the internal version.\r
2894      */\r
2895     function bitwise_rightShift($shift)\r
2896     {\r
2897         $temp = new Math_BigInteger();\r
2898 \r
2899         switch ( MATH_BIGINTEGER_MODE ) {\r
2900             case MATH_BIGINTEGER_MODE_GMP:\r
2901                 static $two;\r
2902 \r
2903                 if (!isset($two)) {\r
2904                     $two = gmp_init('2');\r
2905                 }\r
2906 \r
2907                 $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));\r
2908 \r
2909                 break;\r
2910             case MATH_BIGINTEGER_MODE_BCMATH:\r
2911                 $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);\r
2912 \r
2913                 break;\r
2914             default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten\r
2915                      // and I don't want to do that...\r
2916                 $temp->value = $this->value;\r
2917                 $temp->_rshift($shift);\r
2918         }\r
2919 \r
2920         return $this->_normalize($temp);\r
2921     }\r
2922 \r
2923     /**\r
2924      * Logical Left Shift\r
2925      *\r
2926      * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.\r
2927      *\r
2928      * @param Integer $shift\r
2929      * @return Math_BigInteger\r
2930      * @access public\r
2931      * @internal The only version that yields any speed increases is the internal version.\r
2932      */\r
2933     function bitwise_leftShift($shift)\r
2934     {\r
2935         $temp = new Math_BigInteger();\r
2936 \r
2937         switch ( MATH_BIGINTEGER_MODE ) {\r
2938             case MATH_BIGINTEGER_MODE_GMP:\r
2939                 static $two;\r
2940 \r
2941                 if (!isset($two)) {\r
2942                     $two = gmp_init('2');\r
2943                 }\r
2944 \r
2945                 $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));\r
2946 \r
2947                 break;\r
2948             case MATH_BIGINTEGER_MODE_BCMATH:\r
2949                 $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);\r
2950 \r
2951                 break;\r
2952             default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten\r
2953                      // and I don't want to do that...\r
2954                 $temp->value = $this->value;\r
2955                 $temp->_lshift($shift);\r
2956         }\r
2957 \r
2958         return $this->_normalize($temp);\r
2959     }\r
2960 \r
2961     /**\r
2962      * Logical Left Rotate\r
2963      *\r
2964      * Instead of the top x bits being dropped they're appended to the shifted bit string.\r
2965      *\r
2966      * @param Integer $shift\r
2967      * @return Math_BigInteger\r
2968      * @access public\r
2969      */\r
2970     function bitwise_leftRotate($shift)\r
2971     {\r
2972         $bits = $this->toBytes();\r
2973 \r
2974         if ($this->precision > 0) {\r
2975             $precision = $this->precision;\r
2976             if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {\r
2977                 $mask = $this->bitmask->subtract(new Math_BigInteger(1));\r
2978                 $mask = $mask->toBytes();\r
2979             } else {\r
2980                 $mask = $this->bitmask->toBytes();\r
2981             }\r
2982         } else {\r
2983             $temp = ord($bits[0]);\r
2984             for ($i = 0; $temp >> $i; ++$i);\r
2985             $precision = 8 * strlen($bits) - 8 + $i;\r
2986             $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);\r
2987         }\r
2988 \r
2989         if ($shift < 0) {\r
2990             $shift+= $precision;\r
2991         }\r
2992         $shift%= $precision;\r
2993 \r
2994         if (!$shift) {\r
2995             return $this->copy();\r
2996         }\r
2997 \r
2998         $left = $this->bitwise_leftShift($shift);\r
2999         $left = $left->bitwise_and(new Math_BigInteger($mask, 256));\r
3000         $right = $this->bitwise_rightShift($precision - $shift);\r
3001         $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);\r
3002         return $this->_normalize($result);\r
3003     }\r
3004 \r
3005     /**\r
3006      * Logical Right Rotate\r
3007      *\r
3008      * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.\r
3009      *\r
3010      * @param Integer $shift\r
3011      * @return Math_BigInteger\r
3012      * @access public\r
3013      */\r
3014     function bitwise_rightRotate($shift)\r
3015     {\r
3016         return $this->bitwise_leftRotate(-$shift);\r
3017     }\r
3018 \r
3019     /**\r
3020      * Set random number generator function\r
3021      *\r
3022      * This function is deprecated.\r
3023      *\r
3024      * @param String $generator\r
3025      * @access public\r
3026      */\r
3027     function setRandomGenerator($generator)\r
3028     {\r
3029     }\r
3030 \r
3031     /**\r
3032      * Generate a random number\r
3033      *\r
3034      * @param optional Integer $min\r
3035      * @param optional Integer $max\r
3036      * @return Math_BigInteger\r
3037      * @access public\r
3038      */\r
3039     function random($min = false, $max = false)\r
3040     {\r
3041         if ($min === false) {\r
3042             $min = new Math_BigInteger(0);\r
3043         }\r
3044 \r
3045         if ($max === false) {\r
3046             $max = new Math_BigInteger(0x7FFFFFFF);\r
3047         }\r
3048 \r
3049         $compare = $max->compare($min);\r
3050 \r
3051         if (!$compare) {\r
3052             return $this->_normalize($min);\r
3053         } else if ($compare < 0) {\r
3054             // if $min is bigger then $max, swap $min and $max\r
3055             $temp = $max;\r
3056             $max = $min;\r
3057             $min = $temp;\r
3058         }\r
3059 \r
3060         $max = $max->subtract($min);\r
3061         $max = ltrim($max->toBytes(), chr(0));\r
3062         $size = strlen($max) - 1;\r
3063 \r
3064         $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string'));\r
3065         if ($crypt_random) {\r
3066             $random = crypt_random_string($size);\r
3067         } else {\r
3068             $random = '';\r
3069 \r
3070             if ($size & 1) {\r
3071                 $random.= chr(mt_rand(0, 255));\r
3072             }\r
3073 \r
3074             $blocks = $size >> 1;\r
3075             for ($i = 0; $i < $blocks; ++$i) {\r
3076                 // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems\r
3077                 $random.= pack('n', mt_rand(0, 0xFFFF));\r
3078             }\r
3079         }\r
3080 \r
3081         $fragment = new Math_BigInteger($random, 256);\r
3082         $leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ?\r
3083             ord($max[0]) - 1 : ord($max[0]);\r
3084 \r
3085         if (!$crypt_random) {\r
3086             $msb = chr(mt_rand(0, $leading));\r
3087         } else {\r
3088             $cutoff = floor(0xFF / $leading) * $leading;\r
3089             while (true) {\r
3090                 $msb = ord(crypt_random_string(1));\r
3091                 if ($msb <= $cutoff) {\r
3092                     $msb%= $leading;\r
3093                     break;\r
3094                 }\r
3095             }\r
3096             $msb = chr($msb);\r
3097         }\r
3098 \r
3099         $random = new Math_BigInteger($msb . $random, 256);\r
3100 \r
3101         return $this->_normalize($random->add($min));\r
3102     }\r
3103 \r
3104     /**\r
3105      * Generate a random prime number.\r
3106      *\r
3107      * If there's not a prime within the given range, false will be returned.  If more than $timeout seconds have elapsed,\r
3108      * give up and return false.\r
3109      *\r
3110      * @param optional Integer $min\r
3111      * @param optional Integer $max\r
3112      * @param optional Integer $timeout\r
3113      * @return Math_BigInteger\r
3114      * @access public\r
3115      * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.\r
3116      */\r
3117     function randomPrime($min = false, $max = false, $timeout = false)\r
3118     {\r
3119         if ($min === false) {\r
3120             $min = new Math_BigInteger(0);\r
3121         }\r
3122 \r
3123         if ($max === false) {\r
3124             $max = new Math_BigInteger(0x7FFFFFFF);\r
3125         }\r
3126 \r
3127         $compare = $max->compare($min);\r
3128 \r
3129         if (!$compare) {\r
3130             return $min->isPrime() ? $min : false;\r
3131         } else if ($compare < 0) {\r
3132             // if $min is bigger then $max, swap $min and $max\r
3133             $temp = $max;\r
3134             $max = $min;\r
3135             $min = $temp;\r
3136         }\r
3137 \r
3138         static $one, $two;\r
3139         if (!isset($one)) {\r
3140             $one = new Math_BigInteger(1);\r
3141             $two = new Math_BigInteger(2);\r
3142         }\r
3143 \r
3144         $start = time();\r
3145 \r
3146         $x = $this->random($min, $max);\r
3147 \r
3148         // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.\r
3149         if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {\r
3150             $p->value = gmp_nextprime($x->value);\r
3151 \r
3152             if ($p->compare($max) <= 0) {\r
3153                 return $p;\r
3154             }\r
3155 \r
3156             if (!$min->equals($x)) {\r
3157                 $x = $x->subtract($one);\r
3158             }\r
3159 \r
3160             return $x->randomPrime($min, $x);\r
3161         }\r
3162 \r
3163         if ($x->equals($two)) {\r
3164             return $x;\r
3165         }\r
3166 \r
3167         $x->_make_odd();\r
3168         if ($x->compare($max) > 0) {\r
3169             // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range\r
3170             if ($min->equals($max)) {\r
3171                 return false;\r
3172             }\r
3173             $x = $min->copy();\r
3174             $x->_make_odd();\r
3175         }\r
3176 \r
3177         $initial_x = $x->copy();\r
3178 \r
3179         while (true) {\r
3180             if ($timeout !== false && time() - $start > $timeout) {\r
3181                 return false;\r
3182             }\r
3183 \r
3184             if ($x->isPrime()) {\r
3185                 return $x;\r
3186             }\r
3187 \r
3188             $x = $x->add($two);\r
3189 \r
3190             if ($x->compare($max) > 0) {\r
3191                 $x = $min->copy();\r
3192                 if ($x->equals($two)) {\r
3193                     return $x;\r
3194                 }\r
3195                 $x->_make_odd();\r
3196             }\r
3197 \r
3198             if ($x->equals($initial_x)) {\r
3199                 return false;\r
3200             }\r
3201         }\r
3202     }\r
3203 \r
3204     /**\r
3205      * Make the current number odd\r
3206      *\r
3207      * If the current number is odd it'll be unchanged.  If it's even, one will be added to it.\r
3208      *\r
3209      * @see randomPrime()\r
3210      * @access private\r
3211      */\r
3212     function _make_odd()\r
3213     {\r
3214         switch ( MATH_BIGINTEGER_MODE ) {\r
3215             case MATH_BIGINTEGER_MODE_GMP:\r
3216                 gmp_setbit($this->value, 0);\r
3217                 break;\r
3218             case MATH_BIGINTEGER_MODE_BCMATH:\r
3219                 if ($this->value[strlen($this->value) - 1] % 2 == 0) {\r
3220                     $this->value = bcadd($this->value, '1');\r
3221                 }\r
3222                 break;\r
3223             default:\r
3224                 $this->value[0] |= 1;\r
3225         }\r
3226     }\r
3227 \r
3228     /**\r
3229      * Checks a numer to see if it's prime\r
3230      *\r
3231      * Assuming the $t parameter is not set, this function has an error rate of 2**-80.  The main motivation for the\r
3232      * $t parameter is distributability.  Math_BigInteger::randomPrime() can be distributed accross multiple pageloads\r
3233      * on a website instead of just one.\r
3234      *\r
3235      * @param optional Integer $t\r
3236      * @return Boolean\r
3237      * @access public\r
3238      * @internal Uses the\r
3239      *     {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}.  See \r
3240      *     {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.\r
3241      */\r
3242     function isPrime($t = false)\r
3243     {\r
3244         $length = strlen($this->toBytes());\r
3245 \r
3246         if (!$t) {\r
3247             // see HAC 4.49 "Note (controlling the error probability)"\r
3248                  if ($length >= 163) { $t =  2; } // floor(1300 / 8)\r
3249             else if ($length >= 106) { $t =  3; } // floor( 850 / 8)\r
3250             else if ($length >= 81 ) { $t =  4; } // floor( 650 / 8)\r
3251             else if ($length >= 68 ) { $t =  5; } // floor( 550 / 8)\r
3252             else if ($length >= 56 ) { $t =  6; } // floor( 450 / 8)\r
3253             else if ($length >= 50 ) { $t =  7; } // floor( 400 / 8)\r
3254             else if ($length >= 43 ) { $t =  8; } // floor( 350 / 8)\r
3255             else if ($length >= 37 ) { $t =  9; } // floor( 300 / 8)\r
3256             else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)\r
3257             else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)\r
3258             else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)\r
3259             else                     { $t = 27; }\r
3260         }\r
3261 \r
3262         // ie. gmp_testbit($this, 0)\r
3263         // ie. isEven() or !isOdd()\r
3264         switch ( MATH_BIGINTEGER_MODE ) {\r
3265             case MATH_BIGINTEGER_MODE_GMP:\r
3266                 return gmp_prob_prime($this->value, $t) != 0;\r
3267             case MATH_BIGINTEGER_MODE_BCMATH:\r
3268                 if ($this->value === '2') {\r
3269                     return true;\r
3270                 }\r
3271                 if ($this->value[strlen($this->value) - 1] % 2 == 0) {\r
3272                     return false;\r
3273                 }\r
3274                 break;\r
3275             default:\r
3276                 if ($this->value == array(2)) {\r
3277                     return true;\r
3278                 }\r
3279                 if (~$this->value[0] & 1) {\r
3280                     return false;\r
3281                 }\r
3282         }\r
3283 \r
3284         static $primes, $zero, $one, $two;\r
3285 \r
3286         if (!isset($primes)) {\r
3287             $primes = array(\r
3288                 3,    5,    7,    11,   13,   17,   19,   23,   29,   31,   37,   41,   43,   47,   53,   59,   \r
3289                 61,   67,   71,   73,   79,   83,   89,   97,   101,  103,  107,  109,  113,  127,  131,  137,  \r
3290                 139,  149,  151,  157,  163,  167,  173,  179,  181,  191,  193,  197,  199,  211,  223,  227,  \r
3291                 229,  233,  239,  241,  251,  257,  263,  269,  271,  277,  281,  283,  293,  307,  311,  313,  \r
3292                 317,  331,  337,  347,  349,  353,  359,  367,  373,  379,  383,  389,  397,  401,  409,  419,  \r
3293                 421,  431,  433,  439,  443,  449,  457,  461,  463,  467,  479,  487,  491,  499,  503,  509,  \r
3294                 521,  523,  541,  547,  557,  563,  569,  571,  577,  587,  593,  599,  601,  607,  613,  617,  \r
3295                 619,  631,  641,  643,  647,  653,  659,  661,  673,  677,  683,  691,  701,  709,  719,  727,  \r
3296                 733,  739,  743,  751,  757,  761,  769,  773,  787,  797,  809,  811,  821,  823,  827,  829,  \r
3297                 839,  853,  857,  859,  863,  877,  881,  883,  887,  907,  911,  919,  929,  937,  941,  947,  \r
3298                 953,  967,  971,  977,  983,  991,  997\r
3299             );\r
3300 \r
3301             if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {\r
3302                 for ($i = 0; $i < count($primes); ++$i) {\r
3303                     $primes[$i] = new Math_BigInteger($primes[$i]);\r
3304                 }\r
3305             }\r
3306 \r
3307             $zero = new Math_BigInteger();\r
3308             $one = new Math_BigInteger(1);\r
3309             $two = new Math_BigInteger(2);\r
3310         }\r
3311 \r
3312         if ($this->equals($one)) {\r
3313             return false;\r
3314         }\r
3315 \r
3316         // see HAC 4.4.1 "Random search for probable primes"\r
3317         if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {\r
3318             foreach ($primes as $prime) {\r
3319                 list(, $r) = $this->divide($prime);\r
3320                 if ($r->equals($zero)) {\r
3321                     return $this->equals($prime);\r
3322                 }\r
3323             }\r
3324         } else {\r
3325             $value = $this->value;\r
3326             foreach ($primes as $prime) {\r
3327                 list(, $r) = $this->_divide_digit($value, $prime);\r
3328                 if (!$r) {\r
3329                     return count($value) == 1 && $value[0] == $prime;\r
3330                 }\r
3331             }\r
3332         }\r
3333 \r
3334         $n   = $this->copy();\r
3335         $n_1 = $n->subtract($one);\r
3336         $n_2 = $n->subtract($two);\r
3337 \r
3338         $r = $n_1->copy();\r
3339         $r_value = $r->value;\r
3340         // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));\r
3341         if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {\r
3342             $s = 0;\r
3343             // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier\r
3344             while ($r->value[strlen($r->value) - 1] % 2 == 0) {\r
3345                 $r->value = bcdiv($r->value, '2', 0);\r
3346                 ++$s;\r
3347             }\r
3348         } else {\r
3349             for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {\r
3350                 $temp = ~$r_value[$i] & 0xFFFFFF;\r
3351                 for ($j = 1; ($temp >> $j) & 1; ++$j);\r
3352                 if ($j != 25) {\r
3353                     break;\r
3354                 }\r
3355             }\r
3356             $s = 26 * $i + $j - 1;\r
3357             $r->_rshift($s);\r
3358         }\r
3359 \r
3360         for ($i = 0; $i < $t; ++$i) {\r
3361             $a = $this->random($two, $n_2);\r
3362             $y = $a->modPow($r, $n);\r
3363 \r
3364             if (!$y->equals($one) && !$y->equals($n_1)) {\r
3365                 for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {\r
3366                     $y = $y->modPow($two, $n);\r
3367                     if ($y->equals($one)) {\r
3368                         return false;\r
3369                     }\r
3370                 }\r
3371 \r
3372                 if (!$y->equals($n_1)) {\r
3373                     return false;\r
3374                 }\r
3375             }\r
3376         }\r
3377         return true;\r
3378     }\r
3379 \r
3380     /**\r
3381      * Logical Left Shift\r
3382      *\r
3383      * Shifts BigInteger's by $shift bits.\r
3384      *\r
3385      * @param Integer $shift\r
3386      * @access private\r
3387      */\r
3388     function _lshift($shift)\r
3389     {\r
3390         if ( $shift == 0 ) {\r
3391             return;\r
3392         }\r
3393 \r
3394         $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);\r
3395         $shift %= MATH_BIGINTEGER_BASE;\r
3396         $shift = 1 << $shift;\r
3397 \r
3398         $carry = 0;\r
3399 \r
3400         for ($i = 0; $i < count($this->value); ++$i) {\r
3401             $temp = $this->value[$i] * $shift + $carry;\r
3402             $carry = (int) ($temp / MATH_BIGINTEGER_BASE_FULL);\r
3403             $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);\r
3404         }\r
3405 \r
3406         if ( $carry ) {\r
3407             $this->value[] = $carry;\r
3408         }\r
3409 \r
3410         while ($num_digits--) {\r
3411             array_unshift($this->value, 0);\r
3412         }\r
3413     }\r
3414 \r
3415     /**\r
3416      * Logical Right Shift\r
3417      *\r
3418      * Shifts BigInteger's by $shift bits.\r
3419      *\r
3420      * @param Integer $shift\r
3421      * @access private\r
3422      */\r
3423     function _rshift($shift)\r
3424     {\r
3425         if ($shift == 0) {\r
3426             return;\r
3427         }\r
3428 \r
3429         $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);\r
3430         $shift %= MATH_BIGINTEGER_BASE;\r
3431         $carry_shift = MATH_BIGINTEGER_BASE - $shift;\r
3432         $carry_mask = (1 << $shift) - 1;\r
3433 \r
3434         if ( $num_digits ) {\r
3435             $this->value = array_slice($this->value, $num_digits);\r
3436         }\r
3437 \r
3438         $carry = 0;\r
3439 \r
3440         for ($i = count($this->value) - 1; $i >= 0; --$i) {\r
3441             $temp = $this->value[$i] >> $shift | $carry;\r
3442             $carry = ($this->value[$i] & $carry_mask) << $carry_shift;\r
3443             $this->value[$i] = $temp;\r
3444         }\r
3445 \r
3446         $this->value = $this->_trim($this->value);\r
3447     }\r
3448 \r
3449     /**\r
3450      * Normalize\r
3451      *\r
3452      * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision\r
3453      *\r
3454      * @param Math_BigInteger\r
3455      * @return Math_BigInteger\r
3456      * @see _trim()\r
3457      * @access private\r
3458      */\r
3459     function _normalize($result)\r
3460     {\r
3461         $result->precision = $this->precision;\r
3462         $result->bitmask = $this->bitmask;\r
3463 \r
3464         switch ( MATH_BIGINTEGER_MODE ) {\r
3465             case MATH_BIGINTEGER_MODE_GMP:\r
3466                 if (!empty($result->bitmask->value)) {\r
3467                     $result->value = gmp_and($result->value, $result->bitmask->value);\r
3468                 }\r
3469 \r
3470                 return $result;\r
3471             case MATH_BIGINTEGER_MODE_BCMATH:\r
3472                 if (!empty($result->bitmask->value)) {\r
3473                     $result->value = bcmod($result->value, $result->bitmask->value);\r
3474                 }\r
3475 \r
3476                 return $result;\r
3477         }\r
3478 \r
3479         $value = &$result->value;\r
3480 \r
3481         if ( !count($value) ) {\r
3482             return $result;\r
3483         }\r
3484 \r
3485         $value = $this->_trim($value);\r
3486 \r
3487         if (!empty($result->bitmask->value)) {\r
3488             $length = min(count($value), count($this->bitmask->value));\r
3489             $value = array_slice($value, 0, $length);\r
3490 \r
3491             for ($i = 0; $i < $length; ++$i) {\r
3492                 $value[$i] = $value[$i] & $this->bitmask->value[$i];\r
3493             }\r
3494         }\r
3495 \r
3496         return $result;\r
3497     }\r
3498 \r
3499     /**\r
3500      * Trim\r
3501      *\r
3502      * Removes leading zeros\r
3503      *\r
3504      * @param Array $value\r
3505      * @return Math_BigInteger\r
3506      * @access private\r
3507      */\r
3508     function _trim($value)\r
3509     {\r
3510         for ($i = count($value) - 1; $i >= 0; --$i) {\r
3511             if ( $value[$i] ) {\r
3512                 break;\r
3513             }\r
3514             unset($value[$i]);\r
3515         }\r
3516 \r
3517         return $value;\r
3518     }\r
3519 \r
3520     /**\r
3521      * Array Repeat\r
3522      *\r
3523      * @param $input Array\r
3524      * @param $multiplier mixed\r
3525      * @return Array\r
3526      * @access private\r
3527      */\r
3528     function _array_repeat($input, $multiplier)\r
3529     {\r
3530         return ($multiplier) ? array_fill(0, $multiplier, $input) : array();\r
3531     }\r
3532 \r
3533     /**\r
3534      * Logical Left Shift\r
3535      *\r
3536      * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.\r
3537      *\r
3538      * @param $x String\r
3539      * @param $shift Integer\r
3540      * @return String\r
3541      * @access private\r
3542      */\r
3543     function _base256_lshift(&$x, $shift)\r
3544     {\r
3545         if ($shift == 0) {\r
3546             return;\r
3547         }\r
3548 \r
3549         $num_bytes = $shift >> 3; // eg. floor($shift/8)\r
3550         $shift &= 7; // eg. $shift % 8\r
3551 \r
3552         $carry = 0;\r
3553         for ($i = strlen($x) - 1; $i >= 0; --$i) {\r
3554             $temp = ord($x[$i]) << $shift | $carry;\r
3555             $x[$i] = chr($temp);\r
3556             $carry = $temp >> 8;\r
3557         }\r
3558         $carry = ($carry != 0) ? chr($carry) : '';\r
3559         $x = $carry . $x . str_repeat(chr(0), $num_bytes);\r
3560     }\r
3561 \r
3562     /**\r
3563      * Logical Right Shift\r
3564      *\r
3565      * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.\r
3566      *\r
3567      * @param $x String\r
3568      * @param $shift Integer\r
3569      * @return String\r
3570      * @access private\r
3571      */\r
3572     function _base256_rshift(&$x, $shift)\r
3573     {\r
3574         if ($shift == 0) {\r
3575             $x = ltrim($x, chr(0));\r
3576             return '';\r
3577         }\r
3578 \r
3579         $num_bytes = $shift >> 3; // eg. floor($shift/8)\r
3580         $shift &= 7; // eg. $shift % 8\r
3581 \r
3582         $remainder = '';\r
3583         if ($num_bytes) {\r
3584             $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;\r
3585             $remainder = substr($x, $start);\r
3586             $x = substr($x, 0, -$num_bytes);\r
3587         }\r
3588 \r
3589         $carry = 0;\r
3590         $carry_shift = 8 - $shift;\r
3591         for ($i = 0; $i < strlen($x); ++$i) {\r
3592             $temp = (ord($x[$i]) >> $shift) | $carry;\r
3593             $carry = (ord($x[$i]) << $carry_shift) & 0xFF;\r
3594             $x[$i] = chr($temp);\r
3595         }\r
3596         $x = ltrim($x, chr(0));\r
3597 \r
3598         $remainder = chr($carry >> $carry_shift) . $remainder;\r
3599 \r
3600         return ltrim($remainder, chr(0));\r
3601     }\r
3602 \r
3603     // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long\r
3604     // at 32-bits, while java's longs are 64-bits.\r
3605 \r
3606     /**\r
3607      * Converts 32-bit integers to bytes.\r
3608      *\r
3609      * @param Integer $x\r
3610      * @return String\r
3611      * @access private\r
3612      */\r
3613     function _int2bytes($x)\r
3614     {\r
3615         return ltrim(pack('N', $x), chr(0));\r
3616     }\r
3617 \r
3618     /**\r
3619      * Converts bytes to 32-bit integers\r
3620      *\r
3621      * @param String $x\r
3622      * @return Integer\r
3623      * @access private\r
3624      */\r
3625     function _bytes2int($x)\r
3626     {\r
3627         $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));\r
3628         return $temp['int'];\r
3629     }\r
3630 \r
3631     /**\r
3632      * DER-encode an integer\r
3633      *\r
3634      * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL\r
3635      *\r
3636      * @see modPow()\r
3637      * @access private\r
3638      * @param Integer $length\r
3639      * @return String\r
3640      */\r
3641     function _encodeASN1Length($length)\r
3642     {\r
3643         if ($length <= 0x7F) {\r
3644             return chr($length);\r
3645         }\r
3646 \r
3647         $temp = ltrim(pack('N', $length), chr(0));\r
3648         return pack('Ca*', 0x80 | strlen($temp), $temp);\r
3649     }\r
3650 }\r