Curve   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 201
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 96
dl 0
loc 201
rs 10
c 0
b 0
f 0
wmc 27

12 Methods

Rating   Name   Duplication   Size   Complexity  
A mul() 0 34 5
A getB() 0 3 1
A add() 0 37 5
A getPoint() 0 18 3
A __toString() 0 3 1
A getSize() 0 3 1
A getA() 0 3 1
A getPrime() 0 3 1
A contains() 0 18 1
A getPublicKeyFrom() 0 9 5
A __construct() 0 7 1
A getDouble() 0 28 2
1
<?php
2
declare(strict_types=1);
3
4
namespace SKien\PNServer\Utils;
5
6
/*
7
 * extracted required classes and functions from package
8
 *		spomky-labs/jose
9
 *		https://github.com/Spomky-Labs/Jose 
10
 *
11
 * @package PNServer
12
 * @version 1.0.0
13
 * @copyright MIT License - see the copyright below and LICENSE file for details
14
 */
15
16
/*
17
 * *********************************************************************
18
 * Copyright (c) 2014-2016 Spomky-Labs
19
 *
20
 * Permission is hereby granted, free of charge, to any person obtaining
21
 * a copy of this software and associated documentation files (the "Software"),
22
 * to deal in the Software without restriction, including without limitation
23
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
24
 * and/or sell copies of the Software, and to permit persons to whom the
25
 * Software is furnished to do so, subject to the following conditions:
26
 *
27
 * The above copyright notice and this permission notice shall be included
28
 * in all copies or substantial portions of the Software.
29
 *
30
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
31
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
33
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
34
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
35
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
36
 * OTHER DEALINGS IN THE SOFTWARE.
37
 * ***********************************************************************
38
 */
39
40
/**
41
 * @internal
42
 */
43
class Curve
44
{
45
    /** @var \GMP Elliptic curve over the field of integers modulo a prime.     */
46
    private \GMP $a;
47
    /** @var \GMP     */
48
    private \GMP $b;
49
    /** @var \GMP     */
50
    private \GMP $prime;
51
    /** @var int Binary length of keys associated with these curve parameters.     */
52
    private int $size;
53
    /** @var Point     */
54
    private Point $generator;
55
56
    public function __construct(int $size, \GMP $prime, \GMP $a, \GMP $b, Point $generator)
57
    {
58
        $this->size = $size;
59
        $this->prime = $prime;
60
        $this->a = $a;
61
        $this->b = $b;
62
        $this->generator = $generator;
63
    }
64
65
    public function getA() : \GMP
66
    {
67
        return $this->a;
68
    }
69
70
    public function getB() : \GMP
71
    {
72
        return $this->b;
73
    }
74
75
    public function getPrime() : \GMP
76
    {
77
        return $this->prime;
78
    }
79
80
    public function getSize() : int
81
    {
82
        return $this->size;
83
    }
84
85
    public function getPoint(\GMP $x, \GMP $y, \GMP $order = null) : Point
86
    {
87
        if (!$this->contains($x, $y)) {
88
            throw new \RuntimeException('Curve ' . $this->__toString() . ' does not contain point (' . Math::toString($x) . ', ' . Math::toString($y) . ')');
89
        }
90
        $point = Point::create($x, $y, $order);
91
        
92
        if (!\is_null($order)) {
93
            $this->mul($point, $order);
94
            /* RuntimeException never reached - even with abstruse values in UnitTest 
95
            $mul = $this->mul($point, $order);
96
            if (!$mul->isInfinity()) {
97
                throw new \RuntimeException('SELF * ORDER MUST EQUAL INFINITY. (' . (string) $mul . ' found instead)');
98
            }
99
            */
100
        }
101
102
        return $point;
103
    }
104
    
105
    public function getPublicKeyFrom(\GMP $x, \GMP $y) : Point
106
    {
107
        $zero = \gmp_init(0, 10);
108
        if (Math::cmp($x, $zero) < 0 || Math::cmp($this->generator->getOrder(), $x) <= 0 || Math::cmp($y, $zero) < 0 || Math::cmp($this->generator->getOrder(), $y) <= 0) {
0 ignored issues
show
Bug introduced by
It seems like $zero can also be of type resource; however, parameter $other of SKien\PNServer\Utils\Math::cmp() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

108
        if (Math::cmp($x, /** @scrutinizer ignore-type */ $zero) < 0 || Math::cmp($this->generator->getOrder(), $x) <= 0 || Math::cmp($y, $zero) < 0 || Math::cmp($this->generator->getOrder(), $y) <= 0) {
Loading history...
109
            throw new \RuntimeException('Generator point has x and y out of range.');
110
        }
111
        $point = $this->getPoint($x, $y);
112
113
        return $point;
114
    }
115
116
    public function contains(\GMP $x, \GMP $y) : bool
117
    {
118
        $eq_zero = Math::equals(
119
            Math::modSub(
120
                Math::pow($y, 2),
121
                Math::add(
122
                    Math::add(
123
                        Math::pow($x, 3),
124
                        Math::mul($this->getA(), $x)
125
                    ),
126
                    $this->getB()
127
                ),
128
                $this->getPrime()
129
            ),
130
            \gmp_init(0, 10)
0 ignored issues
show
Bug introduced by
It seems like gmp_init(0, 10) can also be of type resource; however, parameter $other of SKien\PNServer\Utils\Math::equals() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
            /** @scrutinizer ignore-type */ \gmp_init(0, 10)
Loading history...
131
        );
132
133
        return $eq_zero;
134
    }
135
136
    public function add(Point $one, Point $two) : Point
137
    {
138
        if ($two->isInfinity()) {
139
            return clone $one;
140
        }
141
142
        if ($one->isInfinity()) {
143
            return clone $two;
144
        }
145
146
        if (Math::equals($two->getX(), $one->getX())) {
147
            if (Math::equals($two->getY(), $one->getY())) {
148
                return $this->getDouble($one);
149
            } else {
150
                return Point::infinity();
151
            }
152
        }
153
154
        $slope = Math::modDiv(
155
            Math::sub($two->getY(), $one->getY()),
156
            Math::sub($two->getX(), $one->getX()),
157
            $this->getPrime()
158
        );
159
160
        $xR = Math::modSub(
161
            Math::sub(Math::pow($slope, 2), $one->getX()),
162
            $two->getX(),
163
            $this->getPrime()
164
        );
165
166
        $yR = Math::modSub(
167
            Math::mul($slope, Math::sub($one->getX(), $xR)),
168
            $one->getY(),
169
            $this->getPrime()
170
        );
171
172
        return $this->getPoint($xR, $yR, $one->getOrder());
173
    }
174
175
    public function mul(Point $one, \GMP $n) : Point
176
    {
177
        if ($one->isInfinity()) {
178
            return Point::infinity();
179
        }
180
181
        /** @var \GMP $zero */
182
        $zero = \gmp_init(0, 10);
183
        if (Math::cmp($one->getOrder(), $zero) > 0) {
184
            $n = Math::mod($n, $one->getOrder());
185
        }
186
187
        if (Math::equals($n, $zero)) {
188
            return Point::infinity();
189
        }
190
191
        /** @var Point[] $r */
192
        $r = [
193
            Point::infinity(),
194
            clone $one,
195
        ];
196
197
        $k = $this->getSize();
198
        $n = \str_pad(Math::baseConvert(Math::toString($n), 10, 2), $k, '0', STR_PAD_LEFT);
199
200
        for ($i = 0; $i < $k; ++$i) {
201
            $j = (int) $n[$i];
202
            Point::cswap($r[0], $r[1], $j ^ 1);
203
            $r[0] = $this->add($r[0], $r[1]);
204
            $r[1] = $this->getDouble($r[1]);
205
            Point::cswap($r[0], $r[1], $j ^ 1);
206
        }
207
208
        return $r[0];
209
    }
210
211
    public function __toString() : string
212
    {
213
        return 'curve(' . Math::toString($this->getA()) . ', ' . Math::toString($this->getB()) . ', ' . Math::toString($this->getPrime()) . ')';
214
    }
215
216
    public function getDouble(Point $point) : Point
217
    {
218
        if ($point->isInfinity()) {
219
            return Point::infinity();
220
        }
221
222
        $a = $this->getA();
223
        $threeX2 = Math::mul(\gmp_init(3, 10), Math::pow($point->getX(), 2));
0 ignored issues
show
Bug introduced by
It seems like gmp_init(3, 10) can also be of type resource; however, parameter $multiplier of SKien\PNServer\Utils\Math::mul() does only seem to accept GMP, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

223
        $threeX2 = Math::mul(/** @scrutinizer ignore-type */ \gmp_init(3, 10), Math::pow($point->getX(), 2));
Loading history...
224
225
        $tangent = Math::modDiv(
226
            Math::add($threeX2, $a),
227
            Math::mul(\gmp_init(2, 10), $point->getY()),
228
            $this->getPrime()
229
        );
230
231
        $x3 = Math::modSub(
232
            Math::pow($tangent, 2),
233
            Math::mul(\gmp_init(2, 10), $point->getX()),
234
            $this->getPrime()
235
        );
236
237
        $y3 = Math::modSub(
238
            Math::mul($tangent, Math::sub($point->getX(), $x3)),
239
            $point->getY(),
240
            $this->getPrime()
241
        );
242
243
        return $this->getPoint($x3, $y3, $point->getOrder());
244
    }
245
}
246