Commit | Line | Data |
---|---|---|
14d4f286 S |
1 | <?php |
2 | /** | |
3 | * A class for arbitrary precision math functions implemented in PHP | |
4 | * | |
5 | * PHP version 5.3 | |
6 | * | |
7 | * @category PHPCryptLib | |
8 | * @package Core | |
9 | * @subpackage BigMath | |
10 | * @author Anthony Ferrara <ircmaxell@ircmaxell.com> | |
11 | * @copyright 2011 The Authors | |
12 | * @license http://www.opensource.org/licenses/mit-license.html MIT License | |
13 | * @version Build @@version@@ | |
14 | */ | |
15 | namespace CryptLib\Core\BigMath; | |
16 | ||
17 | use CryptLib\Core\BaseConverter; | |
18 | ||
19 | /** | |
20 | * A class for arbitrary precision math functions implemented in PHP | |
21 | * | |
22 | * @category PHPCryptLib | |
23 | * @package Core | |
24 | * @subpackage BigMath | |
25 | */ | |
26 | class PHPMath extends \CryptLib\Core\BigMath { | |
27 | ||
28 | /** | |
29 | * Add two numbers together | |
30 | * | |
31 | * @param string $left The left argument | |
32 | * @param string $right The right argument | |
33 | * | |
34 | * @return A base-10 string of the sum of the two arguments | |
35 | */ | |
36 | public function add($left, $right) { | |
37 | if (empty($left)) { | |
38 | return $right; | |
39 | } elseif (empty($right)) { | |
40 | return $left; | |
41 | } | |
42 | $negative = ''; | |
43 | if ($left[0] == '-' && $right[0] == '-') { | |
44 | $negative = '-'; | |
45 | $left = substr($left, 1); | |
46 | $right = substr($right, 1); | |
47 | } elseif ($left[0] == '-') { | |
48 | return $this->subtract($right, substr($left, 1)); | |
49 | } elseif ($right[0] == '-') { | |
50 | return $this->subtract($left, substr($right, 1)); | |
51 | } | |
52 | $left = $this->normalize($left); | |
53 | $right = $this->normalize($right); | |
54 | $result = BaseConverter::convertFromBinary( | |
55 | $this->addBinary($left, $right), | |
56 | '0123456789' | |
57 | ); | |
58 | return $negative . $result; | |
59 | } | |
60 | ||
61 | /** | |
62 | * Subtract two numbers | |
63 | * | |
64 | * @param string $left The left argument | |
65 | * @param string $right The right argument | |
66 | * | |
67 | * @return A base-10 string of the difference of the two arguments | |
68 | */ | |
69 | public function subtract($left, $right) { | |
70 | if (empty($left)) { | |
71 | return $right; | |
72 | } elseif (empty($right)) { | |
73 | return $left; | |
74 | } elseif ($right[0] == '-') { | |
75 | return $this->add($left, substr($right, 1)); | |
76 | } elseif ($left[0] == '-') { | |
77 | return '-' . $this->add(ltrim($left, '-'), $right); | |
78 | } | |
79 | $left = $this->normalize($left); | |
80 | $right = $this->normalize($right); | |
81 | $results = $this->subtractBinary($left, $right); | |
82 | $result = BaseConverter::convertFromBinary($results[1], '0123456789'); | |
83 | return $results[0] . $result; | |
84 | } | |
85 | ||
86 | /** | |
87 | * Add two binary strings together | |
88 | * | |
89 | * @param string $left The left argument | |
90 | * @param string $right The right argument | |
91 | * | |
92 | * @return string The binary result | |
93 | */ | |
94 | protected function addBinary($left, $right) { | |
95 | $len = max(strlen($left), strlen($right)); | |
96 | $left = str_pad($left, $len, chr(0), STR_PAD_LEFT); | |
97 | $right = str_pad($right, $len, chr(0), STR_PAD_LEFT); | |
98 | $result = ''; | |
99 | $carry = 0; | |
100 | for ($i = 0; $i < $len; $i++) { | |
101 | $sum = ord($left[$len - $i - 1]) | |
102 | + ord($right[$len - $i - 1]) | |
103 | + $carry; | |
104 | $result .= chr($sum % 256); | |
105 | $carry = $sum >> 8; | |
106 | } | |
107 | while ($carry) { | |
108 | $result .= chr($carry % 256); | |
109 | $carry >>= 8; | |
110 | } | |
111 | return strrev($result); | |
112 | } | |
113 | ||
114 | /** | |
115 | * Subtract two binary strings using 256's compliment | |
116 | * | |
117 | * @param string $left The left argument | |
118 | * @param string $right The right argument | |
119 | * | |
120 | * @return string The binary result | |
121 | */ | |
122 | protected function subtractBinary($left, $right) { | |
123 | $len = max(strlen($left), strlen($right)); | |
124 | $left = str_pad($left, $len, chr(0), STR_PAD_LEFT); | |
125 | $right = str_pad($right, $len, chr(0), STR_PAD_LEFT); | |
126 | $right = $this->compliment($right); | |
127 | $result = $this->addBinary($left, $right); | |
128 | if (strlen($result) > $len) { | |
129 | // Positive Result | |
130 | $carry = substr($result, 0, -1 * $len); | |
131 | $result = substr($result, strlen($carry)); | |
132 | return array( | |
133 | '', | |
134 | $this->addBinary($result, $carry) | |
135 | ); | |
136 | } | |
137 | return array('-', $this->compliment($result)); | |
138 | } | |
139 | ||
140 | /** | |
141 | * Take the 256 base compliment | |
142 | * | |
143 | * @param string $string The binary string to compliment | |
144 | * | |
145 | * @return string The complimented string | |
146 | */ | |
147 | protected function compliment($string) { | |
148 | $result = ''; | |
149 | $len = strlen($string); | |
150 | for ($i = 0; $i < $len; $i++) { | |
151 | $result .= chr(255 - ord($string[$i])); | |
152 | } | |
153 | return $result; | |
154 | } | |
155 | ||
156 | /** | |
157 | * Transform a string number into a binary string using base autodetection | |
158 | * | |
159 | * @param string $string The string to transform | |
160 | * | |
161 | * @return string The binary transformed number | |
162 | */ | |
163 | protected function normalize($string) { | |
164 | return BaseConverter::convertToBinary( | |
165 | $string, | |
166 | '0123456789' | |
167 | ); | |
168 | } | |
169 | ||
170 | } |