Subversion Repositories oidplus

Rev

Rev 874 | 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 + b
5
 *
6
 * These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf
7
 * The curve is a weierstrass curve with a[1], a[3] and a[2] set to 0.
8
 *
9
 * Uses Jacobian Coordinates for speed if able:
10
 *
11
 * https://en.wikipedia.org/wiki/Jacobian_curve
12
 * https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
13
 *
14
 * PHP version 5 and 7
15
 *
16
 * @author    Jim Wigginton <terrafrost@php.net>
17
 * @copyright 2017 Jim Wigginton
18
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
19
 * @link      http://pear.php.net/package/Math_BigInteger
20
 */
21
 
22
namespace phpseclib3\Crypt\EC\BaseCurves;
23
 
24
use phpseclib3\Common\Functions\Strings;
25
use phpseclib3\Math\BigInteger;
26
use phpseclib3\Math\Common\FiniteField\Integer;
27
use phpseclib3\Math\PrimeField;
28
use phpseclib3\Math\PrimeField\Integer as PrimeInteger;
29
 
30
/**
31
 * Curves over y^2 = x^3 + a*x + b
32
 *
33
 * @author  Jim Wigginton <terrafrost@php.net>
34
 */
35
class Prime extends Base
36
{
37
    /**
38
     * Prime Field Integer factory
39
     *
40
     * @var \phpseclib3\Math\PrimeFields
41
     */
42
    protected $factory;
43
 
44
    /**
45
     * Cofficient for x^1
46
     *
47
     * @var object
48
     */
49
    protected $a;
50
 
51
    /**
52
     * Cofficient for x^0
53
     *
54
     * @var object
55
     */
56
    protected $b;
57
 
58
    /**
59
     * Base Point
60
     *
61
     * @var object
62
     */
63
    protected $p;
64
 
65
    /**
66
     * The number one over the specified finite field
67
     *
68
     * @var object
69
     */
70
    protected $one;
71
 
72
    /**
73
     * The number two over the specified finite field
74
     *
75
     * @var object
76
     */
77
    protected $two;
78
 
79
    /**
80
     * The number three over the specified finite field
81
     *
82
     * @var object
83
     */
84
    protected $three;
85
 
86
    /**
87
     * The number four over the specified finite field
88
     *
89
     * @var object
90
     */
91
    protected $four;
92
 
93
    /**
94
     * The number eight over the specified finite field
95
     *
96
     * @var object
97
     */
98
    protected $eight;
99
 
100
    /**
101
     * The modulo
102
     *
103
     * @var BigInteger
104
     */
105
    protected $modulo;
106
 
107
    /**
108
     * The Order
109
     *
110
     * @var BigInteger
111
     */
112
    protected $order;
113
 
114
    /**
115
     * Sets the modulo
116
     */
117
    public function setModulo(BigInteger $modulo)
118
    {
119
        $this->modulo = $modulo;
120
        $this->factory = new PrimeField($modulo);
121
        $this->two = $this->factory->newInteger(new BigInteger(2));
122
        $this->three = $this->factory->newInteger(new BigInteger(3));
123
        // used by jacobian coordinates
124
        $this->one = $this->factory->newInteger(new BigInteger(1));
125
        $this->four = $this->factory->newInteger(new BigInteger(4));
126
        $this->eight = $this->factory->newInteger(new BigInteger(8));
127
    }
128
 
129
    /**
130
     * Set coefficients a and b
131
     */
132
    public function setCoefficients(BigInteger $a, BigInteger $b)
133
    {
134
        if (!isset($this->factory)) {
135
            throw new \RuntimeException('setModulo needs to be called before this method');
136
        }
137
        $this->a = $this->factory->newInteger($a);
138
        $this->b = $this->factory->newInteger($b);
139
    }
140
 
141
    /**
142
     * Set x and y coordinates for the base point
143
     *
144
     * @param BigInteger|PrimeInteger $x
145
     * @param BigInteger|PrimeInteger $y
146
     * @return PrimeInteger[]
147
     */
148
    public function setBasePoint($x, $y)
149
    {
150
        switch (true) {
151
            case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
152
                throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
153
            case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
154
                throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
155
        }
156
        if (!isset($this->factory)) {
157
            throw new \RuntimeException('setModulo needs to be called before this method');
158
        }
159
        $this->p = [
160
            $x instanceof BigInteger ? $this->factory->newInteger($x) : $x,
161
            $y instanceof BigInteger ? $this->factory->newInteger($y) : $y
162
        ];
163
    }
164
 
165
    /**
166
     * Retrieve the base point as an array
167
     *
168
     * @return array
169
     */
170
    public function getBasePoint()
171
    {
172
        if (!isset($this->factory)) {
173
            throw new \RuntimeException('setModulo needs to be called before this method');
174
        }
175
        /*
176
        if (!isset($this->p)) {
177
            throw new \RuntimeException('setBasePoint needs to be called before this method');
178
        }
179
        */
180
        return $this->p;
181
    }
182
 
183
    /**
184
     * Adds two "fresh" jacobian form on the curve
185
     *
186
     * @return FiniteField[]
187
     */
188
    protected function jacobianAddPointMixedXY(array $p, array $q)
189
    {
190
        list($u1, $s1) = $p;
191
        list($u2, $s2) = $q;
192
        if ($u1->equals($u2)) {
193
            if (!$s1->equals($s2)) {
194
                return [];
195
            } else {
196
                return $this->doublePoint($p);
197
            }
198
        }
199
        $h = $u2->subtract($u1);
200
        $r = $s2->subtract($s1);
201
        $h2 = $h->multiply($h);
202
        $h3 = $h2->multiply($h);
203
        $v = $u1->multiply($h2);
204
        $x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
205
        $y3 = $r->multiply(
206
            $v->subtract($x3)
207
        )->subtract(
208
            $s1->multiply($h3)
209
        );
210
        return [$x3, $y3, $h];
211
    }
212
 
213
    /**
214
     * Adds one "fresh" jacobian form on the curve
215
     *
216
     * The second parameter should be the "fresh" one
217
     *
218
     * @return FiniteField[]
219
     */
220
    protected function jacobianAddPointMixedX(array $p, array $q)
221
    {
222
        list($u1, $s1, $z1) = $p;
223
        list($x2, $y2) = $q;
224
 
225
        $z12 = $z1->multiply($z1);
226
 
227
        $u2 = $x2->multiply($z12);
228
        $s2 = $y2->multiply($z12->multiply($z1));
229
        if ($u1->equals($u2)) {
230
            if (!$s1->equals($s2)) {
231
                return [];
232
            } else {
233
                return $this->doublePoint($p);
234
            }
235
        }
236
        $h = $u2->subtract($u1);
237
        $r = $s2->subtract($s1);
238
        $h2 = $h->multiply($h);
239
        $h3 = $h2->multiply($h);
240
        $v = $u1->multiply($h2);
241
        $x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
242
        $y3 = $r->multiply(
243
            $v->subtract($x3)
244
        )->subtract(
245
            $s1->multiply($h3)
246
        );
247
        $z3 = $h->multiply($z1);
248
        return [$x3, $y3, $z3];
249
    }
250
 
251
    /**
252
     * Adds two jacobian coordinates on the curve
253
     *
254
     * @return FiniteField[]
255
     */
256
    protected function jacobianAddPoint(array $p, array $q)
257
    {
258
        list($x1, $y1, $z1) = $p;
259
        list($x2, $y2, $z2) = $q;
260
 
261
        $z12 = $z1->multiply($z1);
262
        $z22 = $z2->multiply($z2);
263
 
264
        $u1 = $x1->multiply($z22);
265
        $u2 = $x2->multiply($z12);
266
        $s1 = $y1->multiply($z22->multiply($z2));
267
        $s2 = $y2->multiply($z12->multiply($z1));
268
        if ($u1->equals($u2)) {
269
            if (!$s1->equals($s2)) {
270
                return [];
271
            } else {
272
                return $this->doublePoint($p);
273
            }
274
        }
275
        $h = $u2->subtract($u1);
276
        $r = $s2->subtract($s1);
277
        $h2 = $h->multiply($h);
278
        $h3 = $h2->multiply($h);
279
        $v = $u1->multiply($h2);
280
        $x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
281
        $y3 = $r->multiply(
282
            $v->subtract($x3)
283
        )->subtract(
284
            $s1->multiply($h3)
285
        );
286
        $z3 = $h->multiply($z1)->multiply($z2);
287
        return [$x3, $y3, $z3];
288
    }
289
 
290
    /**
291
     * Adds two points on the curve
292
     *
293
     * @return FiniteField[]
294
     */
295
    public function addPoint(array $p, array $q)
296
    {
297
        if (!isset($this->factory)) {
298
            throw new \RuntimeException('setModulo needs to be called before this method');
299
        }
300
 
301
        if (!count($p) || !count($q)) {
302
            if (count($q)) {
303
                return $q;
304
            }
305
            if (count($p)) {
306
                return $p;
307
            }
308
            return [];
309
        }
310
 
311
        // use jacobian coordinates
312
        if (isset($p[2]) && isset($q[2])) {
313
            if (isset($p['fresh']) && isset($q['fresh'])) {
314
                return $this->jacobianAddPointMixedXY($p, $q);
315
            }
316
            if (isset($p['fresh'])) {
317
                return $this->jacobianAddPointMixedX($q, $p);
318
            }
319
            if (isset($q['fresh'])) {
320
                return $this->jacobianAddPointMixedX($p, $q);
321
            }
322
            return $this->jacobianAddPoint($p, $q);
323
        }
324
 
325
        if (isset($p[2]) || isset($q[2])) {
326
            throw new \RuntimeException('Affine coordinates need to be manually converted to Jacobi coordinates or vice versa');
327
        }
328
 
329
        if ($p[0]->equals($q[0])) {
330
            if (!$p[1]->equals($q[1])) {
331
                return [];
332
            } else { // eg. doublePoint
333
                list($numerator, $denominator) = $this->doublePointHelper($p);
334
            }
335
        } else {
336
            $numerator = $q[1]->subtract($p[1]);
337
            $denominator = $q[0]->subtract($p[0]);
338
        }
339
        $slope = $numerator->divide($denominator);
340
        $x = $slope->multiply($slope)->subtract($p[0])->subtract($q[0]);
341
        $y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]);
342
 
343
        return [$x, $y];
344
    }
345
 
346
    /**
347
     * Returns the numerator and denominator of the slope
348
     *
349
     * @return FiniteField[]
350
     */
351
    protected function doublePointHelper(array $p)
352
    {
353
        $numerator = $this->three->multiply($p[0])->multiply($p[0])->add($this->a);
354
        $denominator = $this->two->multiply($p[1]);
355
        return [$numerator, $denominator];
356
    }
357
 
358
    /**
359
     * Doubles a jacobian coordinate on the curve
360
     *
361
     * @return FiniteField[]
362
     */
363
    protected function jacobianDoublePoint(array $p)
364
    {
365
        list($x, $y, $z) = $p;
366
        $x2 = $x->multiply($x);
367
        $y2 = $y->multiply($y);
368
        $z2 = $z->multiply($z);
369
        $s = $this->four->multiply($x)->multiply($y2);
370
        $m1 = $this->three->multiply($x2);
371
        $m2 = $this->a->multiply($z2->multiply($z2));
372
        $m = $m1->add($m2);
373
        $x1 = $m->multiply($m)->subtract($this->two->multiply($s));
374
        $y1 = $m->multiply($s->subtract($x1))->subtract(
375
            $this->eight->multiply($y2->multiply($y2))
376
        );
377
        $z1 = $this->two->multiply($y)->multiply($z);
378
        return [$x1, $y1, $z1];
379
    }
380
 
381
    /**
382
     * Doubles a "fresh" jacobian coordinate on the curve
383
     *
384
     * @return FiniteField[]
385
     */
386
    protected function jacobianDoublePointMixed(array $p)
387
    {
388
        list($x, $y) = $p;
389
        $x2 = $x->multiply($x);
390
        $y2 = $y->multiply($y);
391
        $s = $this->four->multiply($x)->multiply($y2);
392
        $m1 = $this->three->multiply($x2);
393
        $m = $m1->add($this->a);
394
        $x1 = $m->multiply($m)->subtract($this->two->multiply($s));
395
        $y1 = $m->multiply($s->subtract($x1))->subtract(
396
            $this->eight->multiply($y2->multiply($y2))
397
        );
398
        $z1 = $this->two->multiply($y);
399
        return [$x1, $y1, $z1];
400
    }
401
 
402
    /**
403
     * Doubles a point on a curve
404
     *
405
     * @return FiniteField[]
406
     */
407
    public function doublePoint(array $p)
408
    {
409
        if (!isset($this->factory)) {
410
            throw new \RuntimeException('setModulo needs to be called before this method');
411
        }
412
 
413
        if (!count($p)) {
414
            return [];
415
        }
416
 
417
        // use jacobian coordinates
418
        if (isset($p[2])) {
419
            if (isset($p['fresh'])) {
420
                return $this->jacobianDoublePointMixed($p);
421
            }
422
            return $this->jacobianDoublePoint($p);
423
        }
424
 
425
        list($numerator, $denominator) = $this->doublePointHelper($p);
426
 
427
        $slope = $numerator->divide($denominator);
428
 
429
        $x = $slope->multiply($slope)->subtract($p[0])->subtract($p[0]);
430
        $y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]);
431
 
432
        return [$x, $y];
433
    }
434
 
435
    /**
436
     * Returns the X coordinate and the derived Y coordinate
437
     *
438
     * @return array
439
     */
440
    public function derivePoint($m)
441
    {
442
        $y = ord(Strings::shift($m));
443
        $x = new BigInteger($m, 256);
444
        $xp = $this->convertInteger($x);
445
        switch ($y) {
446
            case 2:
447
                $ypn = false;
448
                break;
449
            case 3:
450
                $ypn = true;
451
                break;
452
            default:
453
                throw new \RuntimeException('Coordinate not in recognized format');
454
        }
455
        $temp = $xp->multiply($this->a);
456
        $temp = $xp->multiply($xp)->multiply($xp)->add($temp);
457
        $temp = $temp->add($this->b);
458
        $b = $temp->squareRoot();
459
        if (!$b) {
460
            throw new \RuntimeException('Unable to derive Y coordinate');
461
        }
462
        $bn = $b->isOdd();
463
        $yp = $ypn == $bn ? $b : $b->negate();
464
        return [$xp, $yp];
465
    }
466
 
467
    /**
468
     * Tests whether or not the x / y values satisfy the equation
469
     *
470
     * @return boolean
471
     */
472
    public function verifyPoint(array $p)
473
    {
474
        list($x, $y) = $p;
475
        $lhs = $y->multiply($y);
476
        $temp = $x->multiply($this->a);
477
        $temp = $x->multiply($x)->multiply($x)->add($temp);
478
        $rhs = $temp->add($this->b);
479
 
480
        return $lhs->equals($rhs);
481
    }
482
 
483
    /**
484
     * Returns the modulo
485
     *
486
     * @return \phpseclib3\Math\BigInteger
487
     */
488
    public function getModulo()
489
    {
490
        return $this->modulo;
491
    }
492
 
493
    /**
494
     * Returns the a coefficient
495
     *
496
     * @return \phpseclib3\Math\PrimeField\Integer
497
     */
498
    public function getA()
499
    {
500
        return $this->a;
501
    }
502
 
503
    /**
504
     * Returns the a coefficient
505
     *
506
     * @return \phpseclib3\Math\PrimeField\Integer
507
     */
508
    public function getB()
509
    {
510
        return $this->b;
511
    }
512
 
513
    /**
514
     * Multiply and Add Points
515
     *
1042 daniel-mar 516
     * Adapted from:
517
     * https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/curve/base.js#L125
827 daniel-mar 518
     *
519
     * @return int[]
520
     */
521
    public function multiplyAddPoints(array $points, array $scalars)
522
    {
523
        $length = count($points);
524
 
525
        foreach ($points as &$point) {
526
            $point = $this->convertToInternal($point);
527
        }
528
 
529
        $wnd = [$this->getNAFPoints($points[0], 7)];
530
        $wndWidth = [isset($points[0]['nafwidth']) ? $points[0]['nafwidth'] : 7];
531
        for ($i = 1; $i < $length; $i++) {
532
            $wnd[] = $this->getNAFPoints($points[$i], 1);
533
            $wndWidth[] = isset($points[$i]['nafwidth']) ? $points[$i]['nafwidth'] : 1;
534
        }
535
 
536
        $naf = [];
537
 
538
        // comb all window NAFs
539
 
540
        $max = 0;
541
        for ($i = $length - 1; $i >= 1; $i -= 2) {
542
            $a = $i - 1;
543
            $b = $i;
544
            if ($wndWidth[$a] != 1 || $wndWidth[$b] != 1) {
545
                $naf[$a] = $scalars[$a]->getNAF($wndWidth[$a]);
546
                $naf[$b] = $scalars[$b]->getNAF($wndWidth[$b]);
547
                $max = max(count($naf[$a]), count($naf[$b]), $max);
548
                continue;
549
            }
550
 
551
            $comb = [
552
                $points[$a], // 1
553
                null,        // 3
554
                null,        // 5
555
                $points[$b]  // 7
556
            ];
557
 
558
            $comb[1] = $this->addPoint($points[$a], $points[$b]);
559
            $comb[2] = $this->addPoint($points[$a], $this->negatePoint($points[$b]));
560
 
561
            $index = [
562
                -3, /* -1 -1 */
563
                -1, /* -1  0 */
564
                -5, /* -1  1 */
565
                -7, /*  0 -1 */
566
                 0, /*  0 -1 */
567
                 7, /*  0  1 */
568
                 5, /*  1 -1 */
569
                 1, /*  1  0 */
570
                 3  /*  1  1 */
571
            ];
572
 
573
            $jsf = self::getJSFPoints($scalars[$a], $scalars[$b]);
574
 
575
            $max = max(count($jsf[0]), $max);
576
            if ($max > 0) {
577
                $naf[$a] = array_fill(0, $max, 0);
578
                $naf[$b] = array_fill(0, $max, 0);
579
            } else {
580
                $naf[$a] = [];
581
                $naf[$b] = [];
582
            }
583
 
584
            for ($j = 0; $j < $max; $j++) {
585
                $ja = isset($jsf[0][$j]) ? $jsf[0][$j] : 0;
586
                $jb = isset($jsf[1][$j]) ? $jsf[1][$j] : 0;
587
 
588
                $naf[$a][$j] = $index[3 * ($ja + 1) + $jb + 1];
589
                $naf[$b][$j] = 0;
590
                $wnd[$a] = $comb;
591
            }
592
        }
593
 
594
        $acc = [];
595
        $temp = [0, 0, 0, 0];
596
        for ($i = $max; $i >= 0; $i--) {
597
            $k = 0;
598
            while ($i >= 0) {
599
                $zero = true;
600
                for ($j = 0; $j < $length; $j++) {
601
                    $temp[$j] = isset($naf[$j][$i]) ? $naf[$j][$i] : 0;
602
                    if ($temp[$j] != 0) {
603
                        $zero = false;
604
                    }
605
                }
606
                if (!$zero) {
607
                    break;
608
                }
609
                $k++;
610
                $i--;
611
            }
612
 
613
            if ($i >= 0) {
614
                $k++;
615
            }
616
            while ($k--) {
617
                $acc = $this->doublePoint($acc);
618
            }
619
 
620
            if ($i < 0) {
621
                break;
622
            }
623
 
624
            for ($j = 0; $j < $length; $j++) {
625
                $z = $temp[$j];
626
                $p = null;
627
                if ($z == 0) {
628
                    continue;
629
                }
630
                $p = $z > 0 ?
631
                    $wnd[$j][($z - 1) >> 1] :
632
                    $this->negatePoint($wnd[$j][(-$z - 1) >> 1]);
633
                $acc = $this->addPoint($acc, $p);
634
            }
635
        }
636
 
637
        return $this->convertToAffine($acc);
638
    }
639
 
640
    /**
641
     * Precomputes NAF points
642
     *
1042 daniel-mar 643
     * Adapted from:
644
     * https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/curve/base.js#L351
827 daniel-mar 645
     *
646
     * @return int[]
647
     */
1042 daniel-mar 648
    private function getNAFPoints(array $point, $wnd)
827 daniel-mar 649
    {
650
        if (isset($point['naf'])) {
651
            return $point['naf'];
652
        }
653
 
654
        $res = [$point];
655
        $max = (1 << $wnd) - 1;
656
        $dbl = $max == 1 ? null : $this->doublePoint($point);
657
        for ($i = 1; $i < $max; $i++) {
658
            $res[] = $this->addPoint($res[$i - 1], $dbl);
659
        }
660
 
661
        $point['naf'] = $res;
662
 
663
        /*
664
        $str = '';
665
        foreach ($res as $re) {
666
            $re[0] = bin2hex($re[0]->toBytes());
667
            $re[1] = bin2hex($re[1]->toBytes());
668
            $str.= "            ['$re[0]', '$re[1]'],\r\n";
669
        }
670
        file_put_contents('temp.txt', $str);
671
        exit;
672
        */
673
 
674
        return $res;
675
    }
676
 
677
    /**
678
     * Precomputes points in Joint Sparse Form
679
     *
1042 daniel-mar 680
     * Adapted from:
681
     * https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/utils.js#L96
827 daniel-mar 682
     *
683
     * @return int[]
684
     */
685
    private static function getJSFPoints(Integer $k1, Integer $k2)
686
    {
687
        static $three;
688
        if (!isset($three)) {
689
            $three = new BigInteger(3);
690
        }
691
 
692
        $jsf = [[], []];
693
        $k1 = $k1->toBigInteger();
694
        $k2 = $k2->toBigInteger();
695
        $d1 = 0;
696
        $d2 = 0;
697
 
698
        while ($k1->compare(new BigInteger(-$d1)) > 0 || $k2->compare(new BigInteger(-$d2)) > 0) {
699
            // first phase
700
            $m14 = $k1->testBit(0) + 2 * $k1->testBit(1);
701
            $m14 += $d1;
702
            $m14 &= 3;
703
 
704
            $m24 = $k2->testBit(0) + 2 * $k2->testBit(1);
705
            $m24 += $d2;
706
            $m24 &= 3;
707
 
708
            if ($m14 == 3) {
709
                $m14 = -1;
710
            }
711
            if ($m24 == 3) {
712
                $m24 = -1;
713
            }
714
 
715
            $u1 = 0;
716
            if ($m14 & 1) { // if $m14 is odd
717
                $m8 = $k1->testBit(0) + 2 * $k1->testBit(1) + 4 * $k1->testBit(2);
718
                $m8 += $d1;
719
                $m8 &= 7;
720
                $u1 = ($m8 == 3 || $m8 == 5) && $m24 == 2 ? -$m14 : $m14;
721
            }
722
            $jsf[0][] = $u1;
723
 
724
            $u2 = 0;
725
            if ($m24 & 1) { // if $m24 is odd
726
                $m8 = $k2->testBit(0) + 2 * $k2->testBit(1) + 4 * $k2->testBit(2);
727
                $m8 += $d2;
728
                $m8 &= 7;
729
                $u2 = ($m8 == 3 || $m8 == 5) && $m14 == 2 ? -$m24 : $m24;
730
            }
731
            $jsf[1][] = $u2;
732
 
733
            // second phase
734
            if (2 * $d1 == $u1 + 1) {
735
                $d1 = 1 - $d1;
736
            }
737
            if (2 * $d2 == $u2 + 1) {
738
                $d2 = 1 - $d2;
739
            }
740
            $k1 = $k1->bitwise_rightShift(1);
741
            $k2 = $k2->bitwise_rightShift(1);
742
        }
743
 
744
        return $jsf;
745
    }
746
 
747
    /**
748
     * Returns the affine point
749
     *
750
     * A Jacobian Coordinate is of the form (x, y, z).
751
     * To convert a Jacobian Coordinate to an Affine Point
752
     * you do (x / z^2, y / z^3)
753
     *
754
     * @return \phpseclib3\Math\PrimeField\Integer[]
755
     */
756
    public function convertToAffine(array $p)
757
    {
758
        if (!isset($p[2])) {
759
            return $p;
760
        }
761
        list($x, $y, $z) = $p;
762
        $z = $this->one->divide($z);
763
        $z2 = $z->multiply($z);
764
        return [
765
            $x->multiply($z2),
766
            $y->multiply($z2)->multiply($z)
767
        ];
768
    }
769
 
770
    /**
771
     * Converts an affine point to a jacobian coordinate
772
     *
773
     * @return \phpseclib3\Math\PrimeField\Integer[]
774
     */
775
    public function convertToInternal(array $p)
776
    {
777
        if (isset($p[2])) {
778
            return $p;
779
        }
780
 
781
        $p[2] = clone $this->one;
782
        $p['fresh'] = true;
783
        return $p;
784
    }
785
}