Failed Conditions
Push — v7 ( 896db9...bffd87 )
by Florent
03:38
created

Point::__toString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace Jose\Component\Core\Util\Ecc\Primitives;
4
5
use Jose\Component\Core\Util\Ecc\Math\GmpMath;
6
use Jose\Component\Core\Util\Ecc\Math\ModularArithmetic;
7
8
/**
9
 * *********************************************************************
10
 * Copyright (C) 2012 Matyas Danter
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining
13
 * a copy of this software and associated documentation files (the "Software"),
14
 * to deal in the Software without restriction, including without limitation
15
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16
 * and/or sell copies of the Software, and to permit persons to whom the
17
 * Software is furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included
20
 * in all copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
26
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28
 * OTHER DEALINGS IN THE SOFTWARE.
29
 * ***********************************************************************
30
 */
31
32
/**
33
 * This class is where the elliptic curve arithmetic takes place.
34
 * The important methods are:
35
 * - add: adds two points according to ec arithmetic
36
 * - double: doubles a point on the ec field mod p
37
 * - mul: uses double and add to achieve multiplication The rest of the methods are there for supporting the ones above.
38
 */
39
class Point
40
{
41
    /**
42
     * @var CurveFp
43
     */
44
    private $curve;
45
46
    /**
47
     * @var GmpMath
48
     */
49
    protected $adapter;
50
51
    /**
52
     * @var ModularArithmetic
53
     */
54
    private $modAdapter;
55
56
    /**
57
     * @var \GMP
58
     */
59
    private $x;
60
61
    /**
62
     * @var \GMP
63
     */
64
    private $y;
65
66
    /**
67
     * @var \GMP
68
     */
69
    private $order;
70
71
    /**
72
     * @var bool
73
     */
74
    private $infinity = false;
75
76
    /**
77
     * Initialize a new instance
78
     *
79
     * @param CurveFp     $curve
80
     * @param \GMP        $x
81
     * @param \GMP        $y
82
     * @param \GMP        $order
83
     * @param bool                 $infinity
84
     *
85
     * @throws \RuntimeException    when either the curve does not contain the given coordinates or
86
     *                                      when order is not null and P(x, y) * order is not equal to infinity.
87
     */
88
    public function __construct(CurveFp $curve, \GMP $x, \GMP $y, ?\GMP $order = null, bool $infinity = false)
89
    {
90
        $this->adapter    = new GmpMath();
91
        $this->modAdapter = $curve->getModAdapter();
92
        $this->curve      = $curve;
93
        $this->x          = $x;
94
        $this->y          = $y;
95
        $this->order      = null === $order ? gmp_init(0, 10) : $order;
96
        $this->infinity   = (bool) $infinity;
97
        if (! $infinity && ! $curve->contains($x, $y)) {
98
            throw new \RuntimeException("Curve " . $curve . " does not contain point (" . $this->adapter->toString($x) . ", " . $this->adapter->toString($y) . ")");
99
        }
100
101
        if (!is_null($order)) {
102
            $mul = $this->mul($order);
103
            if (!$mul->isInfinity()) {
104
                throw new \RuntimeException("SELF * ORDER MUST EQUAL INFINITY. (" . (string)$mul . " found instead)");
105
            }
106
        }
107
    }
108
109
    /**
110
     * @return bool
111
     */
112
    public function isInfinity(): bool
113
    {
114
        return (bool) $this->infinity;
115
    }
116
117
    /**
118
     * @return CurveFp
119
     */
120
    public function getCurve(): CurveFp
121
    {
122
        return $this->curve;
123
    }
124
125
    /**
126
     * @return \GMP
127
     */
128
    public function getOrder(): \GMP
129
    {
130
        return $this->order;
131
    }
132
133
    /**
134
     * @return \GMP
135
     */
136
    public function getX(): \GMP
137
    {
138
        return $this->x;
139
    }
140
141
    /**
142
     * @return \GMP
143
     */
144
    public function getY(): \GMP
145
    {
146
        return $this->y;
147
    }
148
149
    /**
150
     * @param Point $addend
151
     *
152
     * @return Point
153
     */
154
    public function add(Point $addend): Point
155
    {
156
        if (! $this->curve->equals($addend->getCurve())) {
157
            throw new \RuntimeException("The Elliptic Curves do not match.");
158
        }
159
160
        if ($addend->isInfinity()) {
161
            return clone $this;
162
        }
163
164
        if ($this->isInfinity()) {
165
            return clone $addend;
166
        }
167
168
        if ($this->adapter->equals($addend->getX(), $this->x)) {
169
            if ($this->adapter->equals($addend->getY(), $this->y)) {
170
                return $this->getDouble();
171
            } else {
172
                return $this->curve->getInfinity();
173
            }
174
        }
175
176
        $slope = $this->modAdapter->div(
177
            $this->adapter->sub($addend->getY(), $this->y),
178
            $this->adapter->sub($addend->getX(), $this->x)
179
        );
180
181
        $xR = $this->modAdapter->sub(
182
            $this->adapter->sub($this->adapter->pow($slope, 2), $this->x),
183
            $addend->getX()
184
        );
185
186
        $yR = $this->modAdapter->sub(
187
            $this->adapter->mul($slope, $this->adapter->sub($this->x, $xR)),
188
            $this->y
189
        );
190
191
        return $this->curve->getPoint($xR, $yR, $this->order);
192
    }
193
194
    /**
195
     * @param Point $other
196
     *
197
     * @return int
198
     */
199
    public function cmp(Point $other): int
200
    {
201
        if ($other->isInfinity() && $this->isInfinity()) {
202
            return 0;
203
        }
204
205
        if ($other->isInfinity() || $this->isInfinity()) {
206
            return 1;
207
        }
208
209
        $equal = ($this->adapter->equals($this->x, $other->getX()));
210
        $equal &= ($this->adapter->equals($this->y, $other->getY()));
211
        $equal &= $this->isInfinity() == $other->isInfinity();
212
        $equal &= $this->curve->equals($other->getCurve());
213
214
        return $equal ? 0 : 1;
215
    }
216
217
    /**
218
     * @param Point $other
219
     * @return bool
220
     */
221
    public function equals(Point $other): bool
222
    {
223
        return $this->cmp($other) === 0;
224
    }
225
226
    /**
227
     * @param \GMP $n
228
     *
229
     * @return Point
230
     */
231
    public function mul(\GMP $n): Point
232
    {
233
        if ($this->isInfinity()) {
234
            return $this->curve->getInfinity();
235
        }
236
237
        /** @var \GMP $zero */
238
        $zero = gmp_init(0, 10);
239
        if ($this->adapter->cmp($this->order, $zero) > 0) {
240
            $n = $this->adapter->mod($n, $this->order);
241
        }
242
243
        if ($this->adapter->equals($n, $zero)) {
244
            return $this->curve->getInfinity();
245
        }
246
247
        /** @var Point[] $r */
248
        $r = [
249
            $this->curve->getInfinity(),
250
            clone $this
251
        ];
252
253
        $k = $this->curve->getSize();
254
        $n = str_pad($this->adapter->baseConvert($this->adapter->toString($n), 10, 2), $k, '0', STR_PAD_LEFT);
255
256
        for ($i = 0; $i < $k; $i++) {
257
            $j = $n[$i];
258
259
            $this->cswap($r[0], $r[1], $j ^ 1);
260
261
            $r[0] = $r[0]->add($r[1]);
262
            $r[1] = $r[1]->getDouble();
263
264
            $this->cswap($r[0], $r[1], $j ^ 1);
265
        }
266
267
        $r[0]->validate();
268
269
        return $r[0];
270
    }
271
272
    /**
273
     * @param Point $a
274
     * @param Point $b
275
     * @param int $cond
276
     */
277
    private function cswap(Point $a, Point $b, int $cond)
278
    {
279
        $this->cswapValue($a->x, $b->x, $cond);
280
        $this->cswapValue($a->y, $b->y, $cond);
281
        $this->cswapValue($a->order, $b->order, $cond);
282
        $this->cswapValue($a->infinity, $b->infinity, $cond);
283
    }
284
285
    /**
286
     * @param $a
287
     * @param $b
288
     * @param $cond
289
     */
290
    private function cswapValue(& $a, & $b, int $cond)
291
    {
292
        $isGMP = is_object($a) && $a instanceof \GMP;
0 ignored issues
show
Bug introduced by
The class GMP does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
293
294
        /** @var \GMP $sa */
295
        $sa = $isGMP ? $a : gmp_init(intval($a), 10);
296
297
        /** @var \GMP $sb */
298
        $sb = $isGMP ? $b : gmp_init(intval($b), 10);
299
        $size = max(mb_strlen(gmp_strval($sa, 2), '8bit'), mb_strlen(gmp_strval($sb, 2), '8bit'));
300
301
        $mask = 1 - intval($cond);
302
        $mask = str_pad('', $size, $mask, STR_PAD_LEFT);
303
304
        /** @var \GMP $mask */
305
        $mask = gmp_init($mask, 2);
306
307
        $taA = $this->adapter->bitwiseAnd($sa, $mask);
308
        $taB = $this->adapter->bitwiseAnd($sb, $mask);
309
310
        $sa = $this->adapter->bitwiseXor($this->adapter->bitwiseXor($sa, $sb), $taB);
311
        $sb = $this->adapter->bitwiseXor($this->adapter->bitwiseXor($sa, $sb), $taA);
312
        $sa = $this->adapter->bitwiseXor($this->adapter->bitwiseXor($sa, $sb), $taB);
313
314
        $a = $isGMP ? $sa : (bool) gmp_strval($sa, 10);
315
        $b = $isGMP ? $sb : (bool) gmp_strval($sb, 10);
316
    }
317
318
    /**
319
     *
320
     */
321
    private function validate()
322
    {
323
        if (! $this->infinity && ! $this->curve->contains($this->x, $this->y)) {
324
            throw new \RuntimeException('Invalid point');
325
        }
326
    }
327
328
    /**
329
     * @return Point
330
     */
331
    public function getDouble(): Point
332
    {
333
        if ($this->isInfinity()) {
334
            return $this->curve->getInfinity();
335
        }
336
337
        $math = $this->adapter;
338
        $modMath = $this->modAdapter;
339
340
        $a = $this->curve->getA();
341
        $threeX2 = $math->mul(gmp_init(3, 10), $math->pow($this->x, 2));
342
343
        $tangent = $modMath->div(
344
            $math->add($threeX2, $a),
345
            $math->mul(gmp_init(2, 10), $this->y)
346
        );
347
348
        $x3 = $modMath->sub(
349
            $math->pow($tangent, 2),
350
            $math->mul(gmp_init(2, 10), $this->x)
351
        );
352
353
        $y3 = $modMath->sub(
354
            $math->mul($tangent, $math->sub($this->x, $x3)),
355
            $this->y
356
        );
357
358
        return $this->curve->getPoint($x3, $y3, $this->order);
359
    }
360
}
361