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