123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- <?php
- namespace Elliptic\EC;
- use Elliptic\Utils;
- use BN\BN;
- class Signature
- {
- public $r;
- public $s;
- public $recoveryParam;
- function __construct($options, $enc = false)
- {
- if ($options instanceof Signature) {
- $this->r = $options->r;
- $this->s = $options->s;
- $this->recoveryParam = $options->recoveryParam;
- return;
- }
-
- if (isset($options['r'])) {
- assert(isset($options["r"]) && isset($options["s"])); //, "Signature without r or s");
- $this->r = new BN($options["r"], 16);
- $this->s = new BN($options["s"], 16);
- if( isset($options["recoveryParam"]) )
- $this->recoveryParam = $options["recoveryParam"];
- else
- $this->recoveryParam = null;
- return;
- }
- if (!$this->_importDER($options, $enc))
- throw new \Exception('Unknown signature format');
- }
- private static function getLength($buf, &$pos)
- {
- $initial = $buf[$pos++];
- if( !($initial & 0x80) )
- return $initial;
- $octetLen = $initial & 0xf;
- $val = 0;
- for($i = 0; $i < $octetLen; $i++)
- {
- $val = $val << 8;
- $val = $val | $buf[$pos];
- $pos++;
- }
- return $val;
- }
- private static function rmPadding(&$buf)
- {
- $i = 0;
- $len = count($buf) - 1;
- while($i < $len && !$buf[$i] && !($buf[$i+1] & 0x80) )
- $i++;
- if( $i === 0 )
- return $buf;
- return array_slice($buf, $i);
- }
- private function _importDER($data, $enc)
- {
- $data = Utils::toArray($data, $enc);
- $dataLen = count($data);
- $place = 0;
- if( $data[$place++] !== 0x30)
- return false;
- $len = self::getLength($data, $place);
- if( ($len + $place) !== $dataLen )
- return false;
- if( $data[$place++] !== 0x02 )
- return false;
- $rlen = self::getLength($data, $place);
- $r = array_slice($data, $place, $rlen);
- $place += $rlen;
- if( $data[$place++] !== 0x02 )
- return false;
- $slen = self::getLength($data, $place);
- if( $dataLen !== $slen + $place )
- return false;
- $s = array_slice($data, $place, $slen);
- if( $r[0] === 0 && ($r[1] & 0x80 ) )
- $r = array_slice($r, 1);
- if( $s[0] === 0 && ($s[1] & 0x80 ) )
- $s = array_slice($s, 1);
- $this->r = new BN($r);
- $this->s = new BN($s);
- $this->recoveryParam = null;
- return true;
- }
- private static function constructLength(&$arr, $len)
- {
- if( $len < 0x80 )
- {
- array_push($arr, $len);
- return;
- }
- $octets = 1 + (log($len) / M_LN2 >> 3);
- array_push($arr, $octets | 0x80);
- while(--$octets)
- array_push($arr, ($len >> ($octets << 3)) & 0xff);
- array_push($arr, $len);
- }
- public function toDER($enc = false)
- {
- $r = $this->r->toArray();
- $s = $this->s->toArray();
- //Pad values
- if( $r[0] & 0x80 )
- array_unshift($r, 0);
- if( $s[0] & 0x80 )
- array_unshift($s, 0);
- $r = self::rmPadding($r);
- $s = self::rmPadding($s);
- while(!$s[0] && !($s[1] & 0x80))
- array_slice($s, 1);
- $arr = array(0x02);
- self::constructLength($arr, count($r));
- $arr = array_merge($arr, $r, array(0x02));
- self::constructLength($arr, count($s));
- $backHalf = array_merge($arr, $s);
- $res = array(0x30);
- self::constructLength($res, count($backHalf));
- $res = array_merge($res, $backHalf);
- return Utils::encode($res, $enc);
- }
- }
- ?>
|