1 | <?php |
||
21 | class EcAdapter implements EcAdapterInterface |
||
22 | { |
||
23 | /** |
||
24 | * @var Math |
||
25 | */ |
||
26 | private $math; |
||
27 | |||
28 | /** |
||
29 | * @var GeneratorPoint |
||
30 | */ |
||
31 | private $generator; |
||
32 | |||
33 | /** |
||
34 | * @param Math $math |
||
35 | * @param GeneratorPoint $generator |
||
36 | */ |
||
37 | 23 | public function __construct(Math $math, GeneratorPoint $generator) |
|
42 | |||
43 | /** |
||
44 | * @return Math |
||
45 | */ |
||
46 | 328 | public function getMath() |
|
50 | |||
51 | /** |
||
52 | * @return GeneratorPoint |
||
53 | */ |
||
54 | 149 | public function getGenerator() |
|
58 | |||
59 | /** |
||
60 | * @param int|string $scalar |
||
61 | * @param bool|false $compressed |
||
62 | * @return PrivateKey |
||
63 | */ |
||
64 | 65 | public function getPrivateKey($scalar, $compressed = false) |
|
68 | |||
69 | /** |
||
70 | * @param PointInterface $point |
||
71 | * @param bool|false $compressed |
||
72 | * @return PublicKey |
||
73 | */ |
||
74 | 55 | public function getPublicKey(PointInterface $point, $compressed = false) |
|
78 | |||
79 | /** |
||
80 | * @param int|string $r |
||
81 | * @param int|string $s |
||
82 | * @return Signature |
||
83 | */ |
||
84 | public function getSignature($r, $s) |
||
88 | |||
89 | /** |
||
90 | * @param BufferInterface $messageHash |
||
91 | * @param PublicKey $publicKey |
||
92 | * @param Signature $signature |
||
93 | * @return bool |
||
94 | */ |
||
95 | 26 | private function doVerify(BufferInterface $messageHash, PublicKey $publicKey, Signature $signature) |
|
117 | |||
118 | /** |
||
119 | * @param BufferInterface $messageHash |
||
120 | * @param PublicKeyInterface $publicKey |
||
121 | * @param SignatureInterface $signature |
||
122 | * @return bool |
||
123 | */ |
||
124 | 26 | public function verify(BufferInterface $messageHash, PublicKeyInterface $publicKey, SignatureInterface $signature) |
|
130 | |||
131 | /** |
||
132 | * @param BufferInterface $messageHash |
||
133 | * @param PrivateKey $privateKey |
||
134 | * @param RbgInterface|null $rbg |
||
135 | * @return Signature |
||
136 | */ |
||
137 | 23 | private function doSign(BufferInterface $messageHash, PrivateKey $privateKey, RbgInterface $rbg = null) |
|
138 | { |
||
139 | 23 | $rbg = $rbg ?: new Rfc6979($this, $privateKey, $messageHash); |
|
140 | 23 | $randomK = $rbg->bytes(32); |
|
141 | |||
142 | 23 | $math = $this->getMath(); |
|
143 | 23 | $generator = $this->getGenerator(); |
|
144 | 23 | $n = $generator->getOrder(); |
|
145 | |||
146 | 23 | $k = $math->mod($randomK->getInt(), $n); |
|
147 | 23 | $r = $generator->mul($k)->getX(); |
|
148 | |||
149 | 23 | if ($math->cmp($r, 0) === 0) { |
|
150 | throw new \RuntimeException('Random number r = 0'); |
||
151 | } |
||
152 | |||
153 | 23 | $s = $math->mod( |
|
154 | 23 | $math->mul( |
|
155 | 23 | $math->inverseMod($k, $n), |
|
156 | 23 | $math->mod( |
|
157 | 23 | $math->add( |
|
158 | 23 | $messageHash->getInt(), |
|
159 | 23 | $math->mul( |
|
160 | 23 | $privateKey->getSecretMultiplier(), |
|
161 | $r |
||
162 | ) |
||
163 | ), |
||
164 | $n |
||
165 | ) |
||
166 | ), |
||
167 | $n |
||
168 | ); |
||
169 | |||
170 | 23 | if ($math->cmp($s, 0) === 0) { |
|
171 | throw new \RuntimeException('Signature s = 0'); |
||
172 | } |
||
173 | |||
174 | // if s is less than half the curve order, invert s |
||
175 | 23 | if (!$this->validateSignatureElement($s, true)) { |
|
176 | 9 | $s = $math->sub($n, $s); |
|
177 | } |
||
178 | |||
179 | 23 | return new Signature($this, $r, $s); |
|
180 | } |
||
181 | |||
182 | /** |
||
183 | * @param BufferInterface $messageHash |
||
184 | * @param PrivateKeyInterface $privateKey |
||
185 | * @param RbgInterface $rbg |
||
186 | * @return SignatureInterface |
||
187 | * @throws \BitWasp\Bitcoin\Exceptions\RandomBytesFailure |
||
188 | */ |
||
189 | 23 | public function sign(BufferInterface $messageHash, PrivateKeyInterface $privateKey, RbgInterface $rbg = null) |
|
194 | |||
195 | /** |
||
196 | * @param BufferInterface $messageHash |
||
197 | * @param CompactSignatureInterface $signature |
||
198 | * @return PublicKey |
||
199 | * @throws \Exception |
||
200 | */ |
||
201 | 11 | public function recover(BufferInterface $messageHash, CompactSignatureInterface $signature) |
|
252 | |||
253 | /** |
||
254 | * Attempt to calculate the public key recovery param by trial and error |
||
255 | * |
||
256 | * @param integer|string $r |
||
257 | * @param integer|string $s |
||
258 | * @param BufferInterface $messageHash |
||
259 | * @param PublicKey $publicKey |
||
260 | * @return int |
||
261 | * @throws \Exception |
||
262 | */ |
||
263 | 10 | public function calcPubKeyRecoveryParam($r, $s, BufferInterface $messageHash, PublicKey $publicKey) |
|
264 | { |
||
265 | 10 | $Q = $publicKey->getPoint(); |
|
266 | 10 | for ($i = 0; $i < 4; $i++) { |
|
267 | try { |
||
268 | 10 | $recover = $this->recover($messageHash, new CompactSignature($this, $r, $s, $i, $publicKey->isCompressed())); |
|
269 | 6 | if ($recover->getPoint()->equals($Q)) { |
|
270 | 6 | return $i; |
|
271 | } |
||
272 | 4 | } catch (\Exception $e) { |
|
273 | 4 | continue; |
|
274 | } |
||
275 | } |
||
276 | |||
277 | 4 | throw new \Exception('Failed to find valid recovery factor'); |
|
278 | } |
||
279 | |||
280 | /** |
||
281 | * @param BufferInterface $messageHash |
||
282 | * @param PrivateKey $privateKey |
||
283 | * @param RbgInterface|null $rbg |
||
284 | * @return CompactSignature |
||
285 | * @throws \Exception |
||
286 | */ |
||
287 | 6 | private function doSignCompact(BufferInterface $messageHash, PrivateKey $privateKey, RbgInterface $rbg = null) |
|
288 | { |
||
289 | 6 | $sign = $this->sign($messageHash, $privateKey, $rbg); |
|
290 | |||
291 | // calculate the recovery param |
||
292 | // there should be a way to get this when signing too, but idk how ... |
||
293 | 6 | return new CompactSignature( |
|
294 | $this, |
||
295 | 6 | $sign->getR(), |
|
296 | 6 | $sign->getS(), |
|
297 | 6 | $this->calcPubKeyRecoveryParam($sign->getR(), $sign->getS(), $messageHash, $privateKey->getPublicKey()), |
|
298 | 6 | $privateKey->isCompressed() |
|
299 | ); |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * @param PrivateKeyInterface $privateKey |
||
304 | * @param BufferInterface $messageHash |
||
305 | * @param RbgInterface $rbg |
||
306 | * @return CompactSignature |
||
307 | */ |
||
308 | 6 | public function signCompact(BufferInterface $messageHash, PrivateKeyInterface $privateKey, RbgInterface $rbg = null) |
|
313 | |||
314 | /** |
||
315 | * @param BufferInterface $privateKey |
||
316 | * @return bool |
||
317 | */ |
||
318 | 67 | public function validatePrivateKey(BufferInterface $privateKey) |
|
324 | |||
325 | /** |
||
326 | * @param int|string $element |
||
327 | * @param bool $half |
||
328 | * @return bool |
||
329 | */ |
||
330 | 25 | public function validateSignatureElement($element, $half = false) |
|
340 | |||
341 | /** |
||
342 | * @param BufferInterface $publicKey |
||
343 | * @return PublicKeyInterface |
||
344 | * @throws \Exception |
||
345 | */ |
||
346 | 79 | public function publicKeyFromBuffer(BufferInterface $publicKey) |
|
364 | |||
365 | /** |
||
366 | * @param int|string $xCoord |
||
367 | * @param string $prefix |
||
368 | * @return int|string |
||
369 | * @throws \Exception |
||
370 | */ |
||
371 | 51 | public function recoverYfromX($xCoord, $prefix) |
|
400 | } |
||
401 |
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.
Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.