Rev 846 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
827 | daniel-mar | 1 | <?php |
2 | |||
3 | /** |
||
4 | * Curves over y^2 = x^3 + a*x + x |
||
5 | * |
||
6 | * Technically, a Montgomery curve has a coefficient for y^2 but for Curve25519 and Curve448 that |
||
7 | * coefficient is 1. |
||
8 | * |
||
9 | * Curve25519 and Curve448 do not make use of the y coordinate, which makes it unsuitable for use |
||
10 | * with ECDSA / EdDSA. A few other differences between Curve25519 and Ed25519 are discussed at |
||
11 | * https://crypto.stackexchange.com/a/43058/4520 |
||
12 | * |
||
13 | * More info: |
||
14 | * |
||
15 | * https://en.wikipedia.org/wiki/Montgomery_curve |
||
16 | * |
||
17 | * PHP version 5 and 7 |
||
18 | * |
||
874 | daniel-mar | 19 | * @category Crypt |
20 | * @package EC |
||
827 | daniel-mar | 21 | * @author Jim Wigginton <terrafrost@php.net> |
22 | * @copyright 2019 Jim Wigginton |
||
23 | * @license http://www.opensource.org/licenses/mit-license.html MIT License |
||
24 | * @link http://pear.php.net/package/Math_BigInteger |
||
25 | */ |
||
26 | |||
27 | namespace phpseclib3\Crypt\EC\BaseCurves; |
||
28 | |||
29 | use phpseclib3\Crypt\EC\Curves\Curve25519; |
||
30 | use phpseclib3\Math\BigInteger; |
||
31 | use phpseclib3\Math\PrimeField; |
||
32 | use phpseclib3\Math\PrimeField\Integer as PrimeInteger; |
||
33 | |||
34 | /** |
||
35 | * Curves over y^2 = x^3 + a*x + x |
||
36 | * |
||
874 | daniel-mar | 37 | * @package EC |
827 | daniel-mar | 38 | * @author Jim Wigginton <terrafrost@php.net> |
874 | daniel-mar | 39 | * @access public |
827 | daniel-mar | 40 | */ |
41 | class Montgomery extends Base |
||
42 | { |
||
43 | /** |
||
44 | * Prime Field Integer factory |
||
45 | * |
||
46 | * @var \phpseclib3\Math\PrimeField |
||
47 | */ |
||
48 | protected $factory; |
||
49 | |||
50 | /** |
||
51 | * Cofficient for x |
||
52 | * |
||
53 | * @var object |
||
54 | */ |
||
55 | protected $a; |
||
56 | |||
57 | /** |
||
58 | * Constant used for point doubling |
||
59 | * |
||
60 | * @var object |
||
61 | */ |
||
62 | protected $a24; |
||
63 | |||
64 | /** |
||
65 | * The Number Zero |
||
66 | * |
||
67 | * @var object |
||
68 | */ |
||
69 | protected $zero; |
||
70 | |||
71 | /** |
||
72 | * The Number One |
||
73 | * |
||
74 | * @var object |
||
75 | */ |
||
76 | protected $one; |
||
77 | |||
78 | /** |
||
79 | * Base Point |
||
80 | * |
||
81 | * @var object |
||
82 | */ |
||
83 | protected $p; |
||
84 | |||
85 | /** |
||
86 | * The modulo |
||
87 | * |
||
88 | * @var BigInteger |
||
89 | */ |
||
90 | protected $modulo; |
||
91 | |||
92 | /** |
||
93 | * The Order |
||
94 | * |
||
95 | * @var BigInteger |
||
96 | */ |
||
97 | protected $order; |
||
98 | |||
99 | /** |
||
100 | * Sets the modulo |
||
101 | */ |
||
102 | public function setModulo(BigInteger $modulo) |
||
103 | { |
||
104 | $this->modulo = $modulo; |
||
105 | $this->factory = new PrimeField($modulo); |
||
106 | $this->zero = $this->factory->newInteger(new BigInteger()); |
||
107 | $this->one = $this->factory->newInteger(new BigInteger(1)); |
||
108 | } |
||
109 | |||
110 | /** |
||
111 | * Set coefficients a |
||
112 | */ |
||
113 | public function setCoefficients(BigInteger $a) |
||
114 | { |
||
115 | if (!isset($this->factory)) { |
||
116 | throw new \RuntimeException('setModulo needs to be called before this method'); |
||
117 | } |
||
118 | $this->a = $this->factory->newInteger($a); |
||
119 | $two = $this->factory->newInteger(new BigInteger(2)); |
||
120 | $four = $this->factory->newInteger(new BigInteger(4)); |
||
121 | $this->a24 = $this->a->subtract($two)->divide($four); |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * Set x and y coordinates for the base point |
||
126 | * |
||
127 | * @param BigInteger|PrimeInteger $x |
||
128 | * @param BigInteger|PrimeInteger $y |
||
129 | * @return PrimeInteger[] |
||
130 | */ |
||
131 | public function setBasePoint($x, $y) |
||
132 | { |
||
133 | switch (true) { |
||
134 | case !$x instanceof BigInteger && !$x instanceof PrimeInteger: |
||
135 | throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer'); |
||
136 | case !$y instanceof BigInteger && !$y instanceof PrimeInteger: |
||
137 | throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer'); |
||
138 | } |
||
139 | if (!isset($this->factory)) { |
||
140 | throw new \RuntimeException('setModulo needs to be called before this method'); |
||
141 | } |
||
142 | $this->p = [ |
||
143 | $x instanceof BigInteger ? $this->factory->newInteger($x) : $x, |
||
144 | $y instanceof BigInteger ? $this->factory->newInteger($y) : $y |
||
145 | ]; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Retrieve the base point as an array |
||
150 | * |
||
151 | * @return array |
||
152 | */ |
||
153 | public function getBasePoint() |
||
154 | { |
||
155 | if (!isset($this->factory)) { |
||
156 | throw new \RuntimeException('setModulo needs to be called before this method'); |
||
157 | } |
||
158 | /* |
||
159 | if (!isset($this->p)) { |
||
160 | throw new \RuntimeException('setBasePoint needs to be called before this method'); |
||
161 | } |
||
162 | */ |
||
163 | return $this->p; |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * Doubles and adds a point on a curve |
||
168 | * |
||
169 | * See https://tools.ietf.org/html/draft-ietf-tls-curve25519-01#appendix-A.1.3 |
||
170 | * |
||
171 | * @return FiniteField[][] |
||
172 | */ |
||
173 | private function doubleAndAddPoint(array $p, array $q, PrimeInteger $x1) |
||
174 | { |
||
175 | if (!isset($this->factory)) { |
||
176 | throw new \RuntimeException('setModulo needs to be called before this method'); |
||
177 | } |
||
178 | |||
179 | if (!count($p) || !count($q)) { |
||
180 | return []; |
||
181 | } |
||
182 | |||
183 | if (!isset($p[1])) { |
||
184 | throw new \RuntimeException('Affine coordinates need to be manually converted to XZ coordinates'); |
||
185 | } |
||
186 | |||
187 | list($x2, $z2) = $p; |
||
188 | list($x3, $z3) = $q; |
||
189 | |||
190 | $a = $x2->add($z2); |
||
191 | $aa = $a->multiply($a); |
||
192 | $b = $x2->subtract($z2); |
||
193 | $bb = $b->multiply($b); |
||
194 | $e = $aa->subtract($bb); |
||
195 | $c = $x3->add($z3); |
||
196 | $d = $x3->subtract($z3); |
||
197 | $da = $d->multiply($a); |
||
198 | $cb = $c->multiply($b); |
||
199 | $temp = $da->add($cb); |
||
200 | $x5 = $temp->multiply($temp); |
||
201 | $temp = $da->subtract($cb); |
||
202 | $z5 = $x1->multiply($temp->multiply($temp)); |
||
203 | $x4 = $aa->multiply($bb); |
||
204 | $temp = static::class == Curve25519::class ? $bb : $aa; |
||
205 | $z4 = $e->multiply($temp->add($this->a24->multiply($e))); |
||
206 | |||
207 | return [ |
||
208 | [$x4, $z4], |
||
209 | [$x5, $z5] |
||
210 | ]; |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * Multiply a point on the curve by a scalar |
||
215 | * |
||
216 | * Uses the montgomery ladder technique as described here: |
||
217 | * |
||
218 | * https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Montgomery_ladder |
||
219 | * https://github.com/phpecc/phpecc/issues/16#issuecomment-59176772 |
||
220 | * |
||
221 | * @return array |
||
222 | */ |
||
223 | public function multiplyPoint(array $p, BigInteger $d) |
||
224 | { |
||
225 | $p1 = [$this->one, $this->zero]; |
||
226 | $alreadyInternal = isset($x[1]); |
||
227 | $p2 = $this->convertToInternal($p); |
||
228 | $x = $p[0]; |
||
229 | |||
230 | $b = $d->toBits(); |
||
231 | $b = str_pad($b, 256, '0', STR_PAD_LEFT); |
||
232 | for ($i = 0; $i < strlen($b); $i++) { |
||
233 | $b_i = (int) $b[$i]; |
||
234 | if ($b_i) { |
||
235 | list($p2, $p1) = $this->doubleAndAddPoint($p2, $p1, $x); |
||
236 | } else { |
||
237 | list($p1, $p2) = $this->doubleAndAddPoint($p1, $p2, $x); |
||
238 | } |
||
239 | } |
||
240 | |||
241 | return $alreadyInternal ? $p1 : $this->convertToAffine($p1); |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Converts an affine point to an XZ coordinate |
||
246 | * |
||
247 | * From https://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html |
||
248 | * |
||
249 | * XZ coordinates represent x y as X Z satsfying the following equations: |
||
250 | * |
||
251 | * x=X/Z |
||
252 | * |
||
253 | * @return \phpseclib3\Math\PrimeField\Integer[] |
||
254 | */ |
||
255 | public function convertToInternal(array $p) |
||
256 | { |
||
257 | if (empty($p)) { |
||
258 | return [clone $this->zero, clone $this->one]; |
||
259 | } |
||
260 | |||
261 | if (isset($p[1])) { |
||
262 | return $p; |
||
263 | } |
||
264 | |||
265 | $p[1] = clone $this->one; |
||
266 | |||
267 | return $p; |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * Returns the affine point |
||
272 | * |
||
273 | * @return \phpseclib3\Math\PrimeField\Integer[] |
||
274 | */ |
||
275 | public function convertToAffine(array $p) |
||
276 | { |
||
277 | if (!isset($p[1])) { |
||
278 | return $p; |
||
279 | } |
||
280 | list($x, $z) = $p; |
||
281 | return [$x->divide($z)]; |
||
282 | } |
||
283 | } |