1<?php
2
3/**
4 * Curves over a*x^2 + y^2 = 1 + d*x^2*y^2
5 *
6 * http://www.secg.org/SEC2-Ver-1.0.pdf provides for curves with custom parameters.
7 * ie. the coefficients can be arbitrary set through specially formatted keys, etc.
8 * As such, Prime.php is built very generically and it's not able to take full
9 * advantage of curves with 0 coefficients to produce simplified point doubling,
10 * point addition. Twisted Edwards curves, in contrast, do not have a way, currently,
11 * to customize them. As such, we can omit the super generic stuff from this class
12 * and let the named curves (Ed25519 and Ed448) define their own custom tailored
13 * point addition and point doubling methods.
14 *
15 * More info:
16 *
17 * https://en.wikipedia.org/wiki/Twisted_Edwards_curve
18 *
19 * PHP version 5 and 7
20 *
21 * @category  Crypt
22 * @package   EC
23 * @author    Jim Wigginton <terrafrost@php.net>
24 * @copyright 2017 Jim Wigginton
25 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
26 * @link      http://pear.php.net/package/Math_BigInteger
27 */
28
29namespace phpseclib3\Crypt\EC\BaseCurves;
30
31use phpseclib3\Math\BigInteger;
32use phpseclib3\Math\PrimeField;
33use phpseclib3\Math\PrimeField\Integer as PrimeInteger;
34
35/**
36 * Curves over a*x^2 + y^2 = 1 + d*x^2*y^2
37 *
38 * @package Prime
39 * @author  Jim Wigginton <terrafrost@php.net>
40 * @access  public
41 */
42class TwistedEdwards extends Base
43{
44    /**
45     * The modulo
46     *
47     * @var BigInteger
48     */
49    protected $modulo;
50
51    /**
52     * Cofficient for x^2
53     *
54     * @var object
55     */
56    protected $a;
57
58    /**
59     * Cofficient for x^2*y^2
60     *
61     * @var object
62     */
63    protected $d;
64
65    /**
66     * Base Point
67     *
68     * @var object[]
69     */
70    protected $p;
71
72    /**
73     * The number zero over the specified finite field
74     *
75     * @var object
76     */
77    protected $zero;
78
79    /**
80     * The number one over the specified finite field
81     *
82     * @var object
83     */
84    protected $one;
85
86    /**
87     * The number two over the specified finite field
88     *
89     * @var object
90     */
91    protected $two;
92
93    /**
94     * Sets the modulo
95     */
96    public function setModulo(BigInteger $modulo)
97    {
98        $this->modulo = $modulo;
99        $this->factory = new PrimeField($modulo);
100        $this->zero = $this->factory->newInteger(new BigInteger(0));
101        $this->one = $this->factory->newInteger(new BigInteger(1));
102        $this->two = $this->factory->newInteger(new BigInteger(2));
103    }
104
105    /**
106     * Set coefficients a and b
107     */
108    public function setCoefficients(BigInteger $a, BigInteger $d)
109    {
110        if (!isset($this->factory)) {
111            throw new \RuntimeException('setModulo needs to be called before this method');
112        }
113        $this->a = $this->factory->newInteger($a);
114        $this->d = $this->factory->newInteger($d);
115    }
116
117    /**
118     * Set x and y coordinates for the base point
119     */
120    public function setBasePoint($x, $y)
121    {
122        switch (true) {
123            case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
124                throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
125            case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
126                throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
127        }
128        if (!isset($this->factory)) {
129            throw new \RuntimeException('setModulo needs to be called before this method');
130        }
131        $this->p = [
132            $x instanceof BigInteger ? $this->factory->newInteger($x) : $x,
133            $y instanceof BigInteger ? $this->factory->newInteger($y) : $y
134        ];
135    }
136
137    /**
138     * Returns the a coefficient
139     *
140     * @return \phpseclib3\Math\PrimeField\Integer
141     */
142    public function getA()
143    {
144        return $this->a;
145    }
146
147    /**
148     * Returns the a coefficient
149     *
150     * @return \phpseclib3\Math\PrimeField\Integer
151     */
152    public function getD()
153    {
154        return $this->d;
155    }
156
157    /**
158     * Retrieve the base point as an array
159     *
160     * @return array
161     */
162    public function getBasePoint()
163    {
164        if (!isset($this->factory)) {
165            throw new \RuntimeException('setModulo needs to be called before this method');
166        }
167        /*
168        if (!isset($this->p)) {
169            throw new \RuntimeException('setBasePoint needs to be called before this method');
170        }
171        */
172        return $this->p;
173    }
174
175    /**
176     * Returns the affine point
177     *
178     * @return \phpseclib3\Math\PrimeField\Integer[]
179     */
180    public function convertToAffine(array $p)
181    {
182        if (!isset($p[2])) {
183            return $p;
184        }
185        list($x, $y, $z) = $p;
186        $z = $this->one->divide($z);
187        return [
188            $x->multiply($z),
189            $y->multiply($z)
190        ];
191    }
192
193    /**
194     * Returns the modulo
195     *
196     * @return \phpseclib3\Math\BigInteger
197     */
198    public function getModulo()
199    {
200        return $this->modulo;
201    }
202
203    /**
204     * Tests whether or not the x / y values satisfy the equation
205     *
206     * @return boolean
207     */
208    public function verifyPoint(array $p)
209    {
210        list($x, $y) = $p;
211        $x2 = $x->multiply($x);
212        $y2 = $y->multiply($y);
213
214        $lhs = $this->a->multiply($x2)->add($y2);
215        $rhs = $this->d->multiply($x2)->multiply($y2)->add($this->one);
216
217        return $lhs->equals($rhs);
218    }
219}
220