1<?php
2
3/**
4 * Curve methods common to all curves
5 *
6 * PHP version 5 and 7
7 *
8 * @category  Crypt
9 * @package   EC
10 * @author    Jim Wigginton <terrafrost@php.net>
11 * @copyright 2017 Jim Wigginton
12 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
13 * @link      http://pear.php.net/package/Math_BigInteger
14 */
15
16namespace phpseclib3\Crypt\EC\BaseCurves;
17
18use phpseclib3\Math\BigInteger;
19
20/**
21 * Base
22 *
23 * @package Prime
24 * @author  Jim Wigginton <terrafrost@php.net>
25 * @access  public
26 */
27abstract class Base
28{
29    /**
30     * Doubles
31     *
32     * @var object[]
33     */
34    protected $doubles;
35
36    /**
37     * NAF Points
38     *
39     * @var int[]
40     */
41    private $naf;
42
43    /**
44     * The Order
45     *
46     * @var BigInteger
47     */
48    protected $order;
49
50    /**
51     * Finite Field Integer factory
52     *
53     * @var \phpseclib3\Math\FiniteField\Integer
54     */
55    protected $factory;
56
57    /**
58     * Returns a random integer
59     *
60     * @return object
61     */
62    public function randomInteger()
63    {
64        return $this->factory->randomInteger();
65    }
66
67    /**
68     * Converts a BigInteger to a \phpseclib3\Math\FiniteField\Integer integer
69     *
70     * @return object
71     */
72    public function convertInteger(BigInteger $x)
73    {
74        return $this->factory->newInteger($x);
75    }
76
77    /**
78     * Returns the length, in bytes, of the modulo
79     *
80     * @return integer
81     */
82    public function getLengthInBytes()
83    {
84        return $this->factory->getLengthInBytes();
85    }
86
87    /**
88     * Returns the length, in bits, of the modulo
89     *
90     * @return integer
91     */
92    public function getLength()
93    {
94        return $this->factory->getLength();
95    }
96
97    /**
98     * Multiply a point on the curve by a scalar
99     *
100     * Uses the montgomery ladder technique as described here:
101     *
102     * https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Montgomery_ladder
103     * https://github.com/phpecc/phpecc/issues/16#issuecomment-59176772
104     *
105     * @return array
106     */
107    public function multiplyPoint(array $p, BigInteger $d)
108    {
109        $alreadyInternal = isset($p[2]);
110        $r = $alreadyInternal ?
111            [[], $p] :
112            [[], $this->convertToInternal($p)];
113
114        $d = $d->toBits();
115        for ($i = 0; $i < strlen($d); $i++) {
116            $d_i = (int) $d[$i];
117            $r[1 - $d_i] = $this->addPoint($r[0], $r[1]);
118            $r[$d_i] = $this->doublePoint($r[$d_i]);
119        }
120
121        return $alreadyInternal ? $r[0] : $this->convertToAffine($r[0]);
122    }
123
124    /**
125     * Creates a random scalar multiplier
126     *
127     * @return BigInteger
128     */
129    public function createRandomMultiplier()
130    {
131        static $one;
132        if (!isset($one)) {
133            $one = new BigInteger(1);
134        }
135
136        return BigInteger::randomRange($one, $this->order->subtract($one));
137    }
138
139    /**
140     * Performs range check
141     */
142    public function rangeCheck(BigInteger $x)
143    {
144        static $zero;
145        if (!isset($zero)) {
146            $zero = new BigInteger();
147        }
148
149        if (!isset($this->order)) {
150            throw new \RuntimeException('setOrder needs to be called before this method');
151        }
152        if ($x->compare($this->order) > 0 || $x->compare($zero) <= 0) {
153            throw new \RangeException('x must be between 1 and the order of the curve');
154        }
155    }
156
157    /**
158     * Sets the Order
159     */
160    public function setOrder(BigInteger $order)
161    {
162        $this->order = $order;
163    }
164
165    /**
166     * Returns the Order
167     *
168     * @return \phpseclib3\Math\BigInteger
169     */
170    public function getOrder()
171    {
172        return $this->order;
173    }
174
175    /**
176     * Use a custom defined modular reduction function
177     *
178     * @return object
179     */
180    public function setReduction(callable $func)
181    {
182        $this->factory->setReduction($func);
183    }
184
185    /**
186     * Returns the affine point
187     *
188     * @return object[]
189     */
190    public function convertToAffine(array $p)
191    {
192        return $p;
193    }
194
195    /**
196     * Converts an affine point to a jacobian coordinate
197     *
198     * @return object[]
199     */
200    public function convertToInternal(array $p)
201    {
202        return $p;
203    }
204
205    /**
206     * Negates a point
207     *
208     * @return object[]
209     */
210    public function negatePoint(array $p)
211    {
212        $temp = [
213            $p[0],
214            $p[1]->negate()
215        ];
216        if (isset($p[2])) {
217            $temp[] = $p[2];
218        }
219        return $temp;
220    }
221
222    /**
223     * Multiply and Add Points
224     *
225     * @return int[]
226     */
227    public function multiplyAddPoints(array $points, array $scalars)
228    {
229        $p1 = $this->convertToInternal($points[0]);
230        $p2 = $this->convertToInternal($points[1]);
231        $p1 = $this->multiplyPoint($p1, $scalars[0]);
232        $p2 = $this->multiplyPoint($p2, $scalars[1]);
233        $r = $this->addPoint($p1, $p2);
234        return $this->convertToAffine($r);
235    }
236}
237