123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- <?php
- namespace Elliptic\Curve;
- use Elliptic\Utils;
- use \Exception;
- use BN\BN;
- abstract class BaseCurve
- {
- public $type;
- public $p;
- public $red;
- public $zero;
- public $one;
- public $two;
- public $n;
- public $g;
- protected $_wnafT1;
- protected $_wnafT2;
- protected $_wnafT3;
- protected $_wnafT4;
- public $redN;
- public $_maxwellTrick;
- function __construct($type, $conf)
- {
- $this->type = $type;
- $this->p = new BN($conf["p"], 16);
- //Use Montgomery, when there is no fast reduction for the prime
- $this->red = isset($conf["prime"]) ? BN::red($conf["prime"]) : BN::mont($this->p);
- //Useful for many curves
- $this->zero = (new BN(0))->toRed($this->red);
- $this->one = (new BN(1))->toRed($this->red);
- $this->two = (new BN(2))->toRed($this->red);
- //Curve configuration, optional
- $this->n = isset($conf["n"]) ? new BN($conf["n"], 16) : null;
- $this->g = isset($conf["g"]) ? $this->pointFromJSON($conf["g"], isset($conf["gRed"]) ? $conf["gRed"] : null) : null;
- //Temporary arrays
- $this->_wnafT1 = array(0,0,0,0);
- $this->_wnafT2 = array(0,0,0,0);
- $this->_wnafT3 = array(0,0,0,0);
- $this->_wnafT4 = array(0,0,0,0);
- //Generalized Greg Maxwell's trick
- $adjustCount = $this->n != null ? $this->p->div($this->n) : null;
- if( $adjustCount == null || $adjustCount->cmpn(100) > 0 )
- {
- $this->redN = null;
- $this->_maxwellTrick = false;
- }
- else
- {
- $this->redN = $this->n->toRed($this->red);
- $this->_maxwellTrick = true;
- }
- }
- abstract public function point($x, $z);
- abstract public function validate($point);
- public function _fixedNafMul($p, $k)
- {
- assert(isset($p->precomputed));
- $doubles = $p->_getDoubles();
- $naf = Utils::getNAF($k, 1);
- $I = (1 << ($doubles["step"] + 1)) - ($doubles["step"] % 2 == 0 ? 2 : 1);
- $I = $I / 3;
- //Translate to more windowed form
- $repr = array();
- for($j = 0; $j < count($naf); $j += $doubles["step"])
- {
- $nafW = 0;
- for($k = $j + $doubles["step"] - 1; $k >= $j; $k--)
- $nafW = ($nafW << 1) + (isset($naf[$k]) ? $naf[$k] : 0);
- array_push($repr, $nafW);
- }
- $a = $this->jpoint(null, null, null);
- $b = $this->jpoint(null, null, null);
- for($i = $I; $i > 0; $i--)
- {
- for($j = 0; $j < count($repr); $j++)
- {
- $nafW = $repr[$j];
- if ($nafW == $i) {
- $b = $b->mixedAdd($doubles["points"][$j]);
- } else if($nafW == -$i) {
- $b = $b->mixedAdd($doubles["points"][$j]->neg());
- }
- }
- $a = $a->add($b);
- }
- return $a->toP();
- }
- public function _wnafMul($p, $k)
- {
- $w = 4;
- //Precompute window
- $nafPoints = $p->_getNAFPoints($w);
- $w = $nafPoints["wnd"];
- $wnd = $nafPoints["points"];
- //Get NAF form
- $naf = Utils::getNAF($k, $w);
- //Add `this`*(N+1) for every w-NAF index
- $acc = $this->jpoint(null, null, null);
- for($i = count($naf) - 1; $i >= 0; $i--)
- {
- //Count zeros
- for($k = 0; $i >= 0 && $naf[$i] == 0; $i--)
- $k++;
- if($i >= 0)
- $k++;
- $acc = $acc->dblp($k);
- if($i < 0)
- break;
- $z = $naf[$i];
- assert($z != 0);
- if( $p->type == "affine" )
- {
- //J +- P
- if( $z > 0 )
- $acc = $acc->mixedAdd($wnd[($z - 1) >> 1]);
- else
- $acc = $acc->mixedAdd($wnd[(-$z - 1) >> 1]->neg());
- }
- else
- {
- //J +- J
- if( $z > 0 )
- $acc = $acc->add($wnd[($z - 1) >> 1]);
- else
- $acc = $acc->add($wnd[(-$z - 1) >> 1]->neg());
- }
- }
- return $p->type == "affine" ? $acc->toP() : $acc;
- }
- public function _wnafMulAdd($defW, $points, $coeffs, $len, $jacobianResult = false)
- {
- $wndWidth = &$this->_wnafT1;
- $wnd = &$this->_wnafT2;
- $naf = &$this->_wnafT3;
- //Fill all arrays
- $max = 0;
- for($i = 0; $i < $len; $i++)
- {
- $p = $points[$i];
- $nafPoints = $p->_getNAFPoints($defW);
- $wndWidth[$i] = $nafPoints["wnd"];
- $wnd[$i] = $nafPoints["points"];
- }
- //Comb all window NAFs
- for($i = $len - 1; $i >= 1; $i -= 2)
- {
- $a = $i - 1;
- $b = $i;
- if( $wndWidth[$a] != 1 || $wndWidth[$b] != 1 )
- {
- $naf[$a] = Utils::getNAF($coeffs[$a], $wndWidth[$a]);
- $naf[$b] = Utils::getNAF($coeffs[$b], $wndWidth[$b]);
- $max = max(count($naf[$a]), $max);
- $max = max(count($naf[$b]), $max);
- continue;
- }
- $comb = array(
- $points[$a], /* 1 */
- null, /* 3 */
- null, /* 5 */
- $points[$b] /* 7 */
- );
- //Try to avoid Projective points, if possible
- if( $points[$a]->y->cmp($points[$b]->y) == 0 )
- {
- $comb[1] = $points[$a]->add($points[$b]);
- $comb[2] = $points[$a]->toJ()->mixedAdd($points[$b]->neg());
- }
- elseif( $points[$a]->y->cmp($points[$b]->y->redNeg()) == 0 )
- {
- $comb[1] = $points[$a]->toJ()->mixedAdd($points[$b]);
- $comb[2] = $points[$a]->add($points[$b]->neg());
- }
- else
- {
- $comb[1] = $points[$a]->toJ()->mixedAdd($points[$b]);
- $comb[2] = $points[$a]->toJ()->mixedAdd($points[$b]->neg());
- }
-
- $index = array(
- -3, /* -1 -1 */
- -1, /* -1 0 */
- -5, /* -1 1 */
- -7, /* 0 -1 */
- 0, /* 0 0 */
- 7, /* 0 1 */
- 5, /* 1 -1 */
- 1, /* 1 0 */
- 3 /* 1 1 */
- );
- $jsf = Utils::getJSF($coeffs[$a], $coeffs[$b]);
- $max = max(count($jsf[0]), $max);
- if ($max > 0) {
- $naf[$a] = array_fill(0, $max, 0);
- $naf[$b] = array_fill(0, $max, 0);
- } else {
- $naf[$a] = [];
- $naf[$b] = [];
- }
- for($j = 0; $j < $max; $j++)
- {
- $ja = isset($jsf[0][$j]) ? $jsf[0][$j] : 0;
- $jb = isset($jsf[1][$j]) ? $jsf[1][$j] : 0;
- $naf[$a][$j] = $index[($ja + 1) * 3 + ($jb + 1)];
- $naf[$b][$j] = 0;
- $wnd[$a] = $comb;
- }
- }
- $acc = $this->jpoint(null, null, null);
- $tmp = &$this->_wnafT4;
- for($i = $max; $i >= 0; $i--)
- {
- $k = 0;
- while($i >= 0)
- {
- $zero = true;
- for($j = 0; $j < $len; $j++)
- {
- $tmp[$j] = isset($naf[$j][$i]) ? $naf[$j][$i] : 0;
- if( $tmp[$j] != 0 )
- $zero = false;
- }
- if( !$zero )
- break;
- $k++;
- $i--;
- }
- if( $i >=0 )
- $k++;
- $acc = $acc->dblp($k);
- if( $i < 0 )
- break;
- for($j = 0; $j < $len; $j++)
- {
- $z = $tmp[$j];
- $p = null;
- if( $z == 0 )
- continue;
- elseif( $z > 0 )
- $p = $wnd[$j][($z - 1) >> 1];
- elseif( $z < 0 )
- $p = $wnd[$j][(-$z - 1) >> 1]->neg();
- if( $p->type == "affine" )
- $acc = $acc->mixedAdd($p);
- else
- $acc = $acc->add($p);
- }
- }
- //Zeroify references
- for($i = 0; $i < $len; $i++)
- $wnd[$i] = null;
- if( $jacobianResult )
- return $acc;
- else
- return $acc->toP();
- }
- public function decodePoint($bytes, $enc = false)
- {
- $bytes = Utils::toArray($bytes, $enc);
- $len = $this->p->byteLength();
- $count = count($bytes);
- //uncompressed, hybrid-odd, hybrid-even
- if(($bytes[0] == 0x04 || $bytes[0] == 0x06 || $bytes[0] == 0x07) && ($count - 1) == (2 * $len) )
- {
- if( $bytes[0] == 0x06 )
- assert($bytes[$count - 1] % 2 == 0);
- elseif( $bytes[0] == 0x07 )
- assert($bytes[$count - 1] % 2 == 1);
- return $this->point(array_slice($bytes, 1, $len), array_slice($bytes, 1 + $len, $len));
- }
- if( ($bytes[0] == 0x02 || $bytes[0] == 0x03) && ($count - 1) == $len )
- return $this->pointFromX(array_slice($bytes, 1, $len), $bytes[0] == 0x03);
- throw new Exception("Unknown point format");
- }
- }
- ?>
|