pssht  latest
SSH server library written in PHP
Point.php
1 <?php
2 
3 /*
4 * This file is part of pssht.
5 *
6 * (c) François Poirotte <clicky@erebot.net>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 
12 namespace fpoirotte\Pssht\ECC;
13 
17 class Point implements \ArrayAccess
18 {
20  protected $coordinates;
21 
22  public function __construct($x = null, $y = null)
23  {
24  $this->coordinates = array(
25  'x' => null,
26  'y' => null
27  );
28 
29  $this['x'] = $x;
30  $this['y'] = $y;
31  }
32 
33  public function __get($name)
34  {
35  return $this[$name];
36  }
37 
38  public function __set($name, $value)
39  {
40  $this[$name] = $value;
41  }
42 
43  public function offsetExists($offset)
44  {
45  return array_key_exists($offset, $this->coordinates);
46  }
47 
48  public function offsetGet($offset)
49  {
50  if (!array_key_exists($offset, $this->coordinates)) {
51  throw new \InvalidArgumentException();
52  }
53 
54  return $this->coordinates[$offset];
55  }
56 
57  public function offsetSet($offset, $value)
58  {
59  if (!array_key_exists($offset, $this->coordinates)) {
60  throw new \InvalidArgumentException();
61  }
62 
63  if (!(is_null($value) ||
64  (is_resource($value) && get_resource_type($value) === 'GMP integer') ||
65  (is_object($value) && ($value instanceof \GMP)))) {
66  $value = @gmp_init($value);
67  if ($value === false) {
68  throw new \InvalidArgumentException();
69  }
70  }
71 
72  $this->coordinates[$offset] = $value;
73  }
74 
75  public function offsetUnset($offset)
76  {
77  throw new \InvalidArgumentException();
78  }
79 
80  public function serialize(\fpoirotte\Pssht\ECC\Curve $curve)
81  {
82  if ($this->coordinates['x'] === null ||
83  $this->coordinates['y'] === null) {
84  return "\x00";
85  }
86 
87  $mlen = gmp_init(strlen(gmp_strval($curve->getModulus(), 2)));
88  $mlen = gmp_intval(gmp_div_q($mlen, 8, GMP_ROUND_PLUSINF)) * 2;
89 
90  $x = gmp_strval($this->coordinates['x'], 16);
91  $x = pack('H*', str_pad($x, $mlen, '0', STR_PAD_LEFT));
92 
93  $y = gmp_strval($this->coordinates['y'], 16);
94  $y = pack('H*', str_pad($y, $mlen, '0', STR_PAD_LEFT));
95 
96  return "\x04" . $x . $y;
97  }
98 
99  public static function unserialize(\fpoirotte\Pssht\ECC\Curve $curve, $s)
100  {
101  $len = strlen($s);
102 
103  if ($len === 0) {
104  throw new \InvalidArgumentException();
105  }
106 
107  if ($s[0] === "\x00" && $len === 1) {
108  return new static(null, null);
109  }
110 
112 
113  if ($s[0] !== "\x04") {
114  throw new \InvalidArgumentException();
115  }
116 
117  $mod = $curve->getModulus();
118  $mlen = gmp_init(strlen(gmp_strval($mod, 2)));
119  $mlen = gmp_intval(gmp_div_q($mlen, 8, GMP_ROUND_PLUSINF)) * 2;
120 
121  if ($len !== $mlen + 1) {
122  throw new \InvalidArgumentException();
123  }
124 
125  $x = gmp_init(bin2hex(substr($s, 1, $mlen / 2)), 16);
126  $y = gmp_init(bin2hex(substr($s, 1 + $mlen / 2)), 16);
127  if (gmp_cmp($x, $mod) >= 0 || gmp_cmp($y, $mod) >= 0) {
128  throw new \InvalidArgumentException();
129  }
130 
131  return new static($x, $y);
132  }
133 
134  public static function add(
135  \fpoirotte\Pssht\ECC\Curve $curve,
136  \fpoirotte\Pssht\ECC\Point $P,
137  \fpoirotte\Pssht\ECC\Point $Q
138  ) {
139  $mod = $curve->getModulus();
140  $xP = $P->coordinates['x'];
141  $yP = $P->coordinates['y'];
142  $xQ = $Q->coordinates['x'];
143  $yQ = $Q->coordinates['y'];
144 
145  if (!gmp_cmp($xP, $xQ) && !gmp_cmp($yP, $yQ)) {
146  $alphanum = gmp_add(gmp_mul('3', gmp_pow($xP, '2')), $curve->getA());
147  $alphaden = gmp_mul('2', $yP);
148  } else {
149  $alphanum = gmp_sub($yQ, $yP);
150  $alphaden = gmp_sub($xQ, $xP);
151  }
152 
153  $bezout = gmp_gcdext($alphaden, $mod);
154  $alpha = gmp_mod(gmp_mul($alphanum, $bezout['s']), $mod);
155  $xR = gmp_sub(gmp_sub(gmp_pow($alpha, '2'), $xP), $xQ);
156  $yR = gmp_sub(gmp_mul($alpha, gmp_sub($xP, $xR)), $yP);
157 
158  return new static(
159  gmp_mod(gmp_add($xR, $mod), $mod),
160  gmp_mod(gmp_add($yR, $mod), $mod)
161  );
162  }
163 
164  public function multiply(\fpoirotte\Pssht\ECC\Curve $curve, $n)
165  {
166  if (!((is_resource($n) && get_resource_type($n) === 'GMP integer') ||
167  (is_object($n) && ($n instanceof \GMP)))) {
168  $n = @gmp_init($n);
169  if ($n === false) {
170  throw new \InvalidArgumentException();
171  }
172  }
173 
174  if (gmp_cmp($n, '1') === 0) {
175  return $this;
176  }
177 
178  $s = gmp_strval($n, 2);
179  $len = strlen($s);
180 
181  $res = $this;
182  for ($i = 1; $i < $len; $i++) {
183  $res = static::add($curve, $res, $res);
184  if ($s[$i] === '1') {
185  $res = static::add($curve, $res, $this);
186  }
187  }
188  return $res;
189  }
190 
191  public function isIdentity(\fpoirotte\Pssht\ECC\Curve $curve)
192  {
193  $n = self::multiply($curve, 2);
194  return (!gmp_cmp($this['x'], $n['x']) &&
195  !gmp_cmp($this['y'], $n['y']));
196  }
197 }
Interface to provide accessing objects as arrays.
Definition: ArrayAccess.php:10
offsetSet($offset, $value)
Definition: Point.php:57
$coordinates
The points coordinates (x, y).
Definition: Point.php:20