xref: /dokuwiki/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/TwistedEdwards.php (revision 8e88a29b81301f78509349ab1152bb09c229123e)
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 * @author    Jim Wigginton <terrafrost@php.net>
22 * @copyright 2017 Jim Wigginton
23 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
24 * @link      http://pear.php.net/package/Math_BigInteger
25 */
26
27namespace phpseclib3\Crypt\EC\BaseCurves;
28
29use phpseclib3\Math\BigInteger;
30use phpseclib3\Math\PrimeField;
31use phpseclib3\Math\PrimeField\Integer as PrimeInteger;
32
33/**
34 * Curves over a*x^2 + y^2 = 1 + d*x^2*y^2
35 *
36 * @author  Jim Wigginton <terrafrost@php.net>
37 */
38class TwistedEdwards extends Base
39{
40    /**
41     * The modulo
42     *
43     * @var BigInteger
44     */
45    protected $modulo;
46
47    /**
48     * Cofficient for x^2
49     *
50     * @var object
51     */
52    protected $a;
53
54    /**
55     * Cofficient for x^2*y^2
56     *
57     * @var object
58     */
59    protected $d;
60
61    /**
62     * Base Point
63     *
64     * @var object[]
65     */
66    protected $p;
67
68    /**
69     * The number zero over the specified finite field
70     *
71     * @var object
72     */
73    protected $zero;
74
75    /**
76     * The number one over the specified finite field
77     *
78     * @var object
79     */
80    protected $one;
81
82    /**
83     * The number two over the specified finite field
84     *
85     * @var object
86     */
87    protected $two;
88
89    /**
90     * Sets the modulo
91     */
92    public function setModulo(BigInteger $modulo)
93    {
94        $this->modulo = $modulo;
95        $this->factory = new PrimeField($modulo);
96        $this->zero = $this->factory->newInteger(new BigInteger(0));
97        $this->one = $this->factory->newInteger(new BigInteger(1));
98        $this->two = $this->factory->newInteger(new BigInteger(2));
99    }
100
101    /**
102     * Set coefficients a and b
103     */
104    public function setCoefficients(BigInteger $a, BigInteger $d)
105    {
106        if (!isset($this->factory)) {
107            throw new \RuntimeException('setModulo needs to be called before this method');
108        }
109        $this->a = $this->factory->newInteger($a);
110        $this->d = $this->factory->newInteger($d);
111    }
112
113    /**
114     * Set x and y coordinates for the base point
115     */
116    public function setBasePoint($x, $y)
117    {
118        switch (true) {
119            case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
120                throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
121            case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
122                throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
123        }
124        if (!isset($this->factory)) {
125            throw new \RuntimeException('setModulo needs to be called before this method');
126        }
127        $this->p = [
128            $x instanceof BigInteger ? $this->factory->newInteger($x) : $x,
129            $y instanceof BigInteger ? $this->factory->newInteger($y) : $y
130        ];
131    }
132
133    /**
134     * Returns the a coefficient
135     *
136     * @return PrimeInteger
137     */
138    public function getA()
139    {
140        return $this->a;
141    }
142
143    /**
144     * Returns the a coefficient
145     *
146     * @return PrimeInteger
147     */
148    public function getD()
149    {
150        return $this->d;
151    }
152
153    /**
154     * Retrieve the base point as an array
155     *
156     * @return array
157     */
158    public function getBasePoint()
159    {
160        if (!isset($this->factory)) {
161            throw new \RuntimeException('setModulo needs to be called before this method');
162        }
163        /*
164        if (!isset($this->p)) {
165            throw new \RuntimeException('setBasePoint needs to be called before this method');
166        }
167        */
168        return $this->p;
169    }
170
171    /**
172     * Returns the affine point
173     *
174     * @return PrimeInteger[]
175     */
176    public function convertToAffine(array $p)
177    {
178        if (!isset($p[2])) {
179            return $p;
180        }
181        list($x, $y, $z) = $p;
182        $z = $this->one->divide($z);
183        return [
184            $x->multiply($z),
185            $y->multiply($z)
186        ];
187    }
188
189    /**
190     * Returns the modulo
191     *
192     * @return BigInteger
193     */
194    public function getModulo()
195    {
196        return $this->modulo;
197    }
198
199    /**
200     * Tests whether or not the x / y values satisfy the equation
201     *
202     * @return boolean
203     */
204    public function verifyPoint(array $p)
205    {
206        list($x, $y) = $p;
207        $x2 = $x->multiply($x);
208        $y2 = $y->multiply($y);
209
210        $lhs = $this->a->multiply($x2)->add($y2);
211        $rhs = $this->d->multiply($x2)->multiply($y2)->add($this->one);
212
213        return $lhs->equals($rhs);
214    }
215}
216