Completed
Pull Request — master (#199)
by thomas
21:24 queued 35s
created

Interpreter::isValidSignatureEncoding()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 1
Metric Value
dl 0
loc 11
ccs 5
cts 5
cp 1
rs 9.4286
c 3
b 0
f 1
cc 2
eloc 6
nc 2
nop 1
crap 2
1
<?php
2
3
namespace BitWasp\Bitcoin\Script\Interpreter;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\Hash;
7
use BitWasp\Bitcoin\Exceptions\SignatureNotCanonical;
8
use BitWasp\Bitcoin\Exceptions\ScriptRuntimeException;
9
use BitWasp\Bitcoin\Flags;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Key\PublicKey;
11
use BitWasp\Bitcoin\Key\PublicKeyFactory;
12
use BitWasp\Bitcoin\Locktime;
13
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
14
use BitWasp\Bitcoin\Script\Opcodes;
15
use BitWasp\Bitcoin\Script\Script;
16
use BitWasp\Bitcoin\Script\ScriptInterface;
17
use BitWasp\Bitcoin\Signature\TransactionSignature;
18
use BitWasp\Bitcoin\Signature\TransactionSignatureFactory;
19
use BitWasp\Bitcoin\Transaction\SignatureHash\SignatureHashInterface;
20
use BitWasp\Bitcoin\Transaction\TransactionInterface;
21
use BitWasp\Buffertools\Buffer;
22
23
class Interpreter implements InterpreterInterface
24
{
25
    /**
26
     * @var int|string
27
     */
28
    private $inputToSign;
29
30
    /**
31
     * @var ScriptInterface
32
     */
33
    private $script;
34
35
    /**
36
     * @var TransactionInterface
37
     */
38
    private $transaction;
39
40
    /**
41
     * Position of OP_CODESEPARATOR, for calculating SigHash
42
     * @var int
43
     */
44
    private $hashStartPos;
45
46
    /**
47
     * @var int
48
     */
49
    private $opCount;
50
51
    /**
52
     * @var \BitWasp\Bitcoin\Flags
53
     */
54
    private $flags;
55
56
    /**
57
     * @var EcAdapterInterface
58
     */
59
    private $ecAdapter;
60
61
    /**
62
     * @var \BitWasp\Bitcoin\Math\Math
63
     */
64
    private $math;
65
66
    /**
67
     * @var State
68
     */
69
    private $state;
70
71
    /**
72
     * @var bool
73
     */
74
    private $minimalPush;
75
76
    /**
77
     * @var array
78
     */
79
    private $disabledOps = [
80
        Opcodes::OP_CAT,    Opcodes::OP_SUBSTR, Opcodes::OP_LEFT,  Opcodes::OP_RIGHT,
81
        Opcodes::OP_INVERT, Opcodes::OP_AND,    Opcodes::OP_OR,    Opcodes::OP_XOR,
82
        Opcodes::OP_2MUL,   Opcodes::OP_2DIV,   Opcodes::OP_MUL,   Opcodes::OP_DIV,
83
        Opcodes::OP_MOD,    Opcodes::OP_LSHIFT, Opcodes::OP_RSHIFT
84
    ];
85
86
    public $checkDisabledOpcodes = true;
87
88
    /**
89
     * @param EcAdapterInterface $ecAdapter
90
     * @param TransactionInterface $transaction
91
     * @param \BitWasp\Bitcoin\Flags $flags
92
     */
93 762
    public function __construct(EcAdapterInterface $ecAdapter, TransactionInterface $transaction, Flags $flags)
94
    {
95 762
        $this->ecAdapter = $ecAdapter;
96 762
        $this->math = $ecAdapter->getMath();
97 762
        $this->transaction = $transaction;
98 762
        $this->flags = $flags;
99 762
        $this->script = new Script();
100 762
        $this->minimalPush = $this->flags->checkFlags(self::VERIFY_MINIMALDATA) === true;
101 762
        $this->state = new State();
102 762
        $this->vchFalse = new Buffer("", 0, $this->math);
0 ignored issues
show
Bug introduced by
The property vchFalse does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
103 762
        $this->vchTrue = new Buffer("\x01", 1, $this->math);
0 ignored issues
show
Bug introduced by
The property vchTrue does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
104
105 762
        $this->int0 = Number::buffer($this->vchFalse, false, 4, $this->math)->getBuffer();
0 ignored issues
show
Bug introduced by
The property int0 does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
106 762
        $this->int1 = Number::buffer($this->vchTrue, false, 1, $this->math)->getBuffer();
0 ignored issues
show
Bug introduced by
The property int1 does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
107 762
    }
108
109
    /**
110
     * @return State
111
     */
112 6
    public function getStackState()
113
    {
114 6
        return $this->state;
115
    }
116
117
    /**
118
     * @param ScriptInterface $script
119
     * @return $this
120
     */
121 684
    public function setScript(ScriptInterface $script)
122
    {
123 684
        $this->script = $script;
124 684
        return $this;
125
    }
126
127
    /**
128
     * @return array
129
     */
130
    public function getDisabledOps()
131
    {
132
        return $this->disabledOps;
133
    }
134
135
    /**
136
     * @param int $op
137
     * @return bool
138
     */
139 684
    public function isDisabledOp($op)
140
    {
141 684
        return in_array($op, $this->disabledOps, true);
142
    }
143
144
    /**
145
     * Cast the value to a boolean
146
     *
147
     * @param $value
148
     * @return bool
149
     */
150 432
    public function castToBool(Buffer $value)
151
    {
152 432
        if ($value->getSize() === 0) {
153 72
            return true;
154
        }
155
156
        // Since we're using buffers, lets try ensuring the contents are not 0.
157 360
        return $this->math->cmp($value->getInt(), 0) > 0;
158
    }
159
160
    /**
161
     * @param Buffer $signature
162
     * @return bool
163
     */
164 54
    public function isValidSignatureEncoding(Buffer $signature)
165
    {
166
        try {
167 54
            TransactionSignature::isDERSignature($signature);
168 36
            return true;
169 18
        } catch (SignatureNotCanonical $e) {
1 ignored issue
show
Unused Code introduced by
This catchblock is empty and will swallow any caught exception.

This check looks for ``catch` blocks that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Empty catch blocks will swallow any caught exception, sometimes causing bugs in your code that are very hard to debug. Consider logging the exception to a debug log or re-throwing it in some way, shape or form.

Loading history...
170
            /* In any case, we will return false outside this block */
171
        }
172
173 18
        return false;
174
    }
175
176
    /**
177
     * @param Buffer $signature
178
     * @return bool
179
     * @throws ScriptRuntimeException
180
     * @throws \Exception
181
     */
182 30
    public function isLowDerSignature(Buffer $signature)
183
    {
184 30
        if (!$this->isValidSignatureEncoding($signature)) {
185 6
            throw new ScriptRuntimeException(self::VERIFY_DERSIG, 'Signature with incorrect encoding');
186
        }
187
188 24
        $binary = $signature->getBinary();
189 24
        $nLenR = ord($binary[3]);
190 24
        $nLenS = ord($binary[5 + $nLenR]);
191 24
        $s = $signature->slice(6 + $nLenR, $nLenS)->getInt();
192
193 24
        return $this->ecAdapter->validateSignatureElement($s, true);
194
    }
195
196
    /**
197
     * Determine whether the sighash byte appended to the signature encodes
198
     * a valid sighash type.
199
     *
200
     * @param Buffer $signature
201
     * @return bool
202
     */
203 36
    public function isDefinedHashtypeSignature(Buffer $signature)
204
    {
205 36
        if ($signature->getSize() === 0) {
206 6
            return false;
207
        }
208
209 30
        $binary = $signature->getBinary();
210 30
        $nHashType = ord(substr($binary, -1)) & (~(SignatureHashInterface::SIGHASH_ANYONECANPAY));
211
212 30
        $math = $this->math;
213 30
        return ! ($math->cmp($nHashType, SignatureHashInterface::SIGHASH_ALL) < 0 || $math->cmp($nHashType, SignatureHashInterface::SIGHASH_SINGLE) > 0);
214
    }
215
216
    /**
217
     * @param Buffer $signature
218
     * @return $this
219
     * @throws \BitWasp\Bitcoin\Exceptions\ScriptRuntimeException
220
     */
221 60
    public function checkSignatureEncoding(Buffer $signature)
222
    {
223 60
        if ($signature->getSize() === 0) {
224 6
            return $this;
225
        }
226
227 54
        if ($this->flags->checkFlags(self::VERIFY_DERSIG | self::VERIFY_LOW_S | self::VERIFY_STRICTENC) && !$this->isValidSignatureEncoding($signature)) {
228 12
            throw new ScriptRuntimeException(self::VERIFY_DERSIG, 'Signature with incorrect encoding');
229 42
        } else if ($this->flags->checkFlags(self::VERIFY_LOW_S) && !$this->isLowDerSignature($signature)) {
230 6
            throw new ScriptRuntimeException(self::VERIFY_LOW_S, 'Signature s element was not low');
231 36
        } else if ($this->flags->checkFlags(self::VERIFY_STRICTENC) && !$this->isDefinedHashtypeSignature($signature)) {
232 6
            throw new ScriptRuntimeException(self::VERIFY_STRICTENC, 'Signature with invalid hashtype');
233
        }
234
235 30
        return $this;
236
    }
237
238
    /**
239
     * @param Buffer $publicKey
240
     * @return $this
241
     * @throws \Exception
242
     */
243 24
    public function checkPublicKeyEncoding(Buffer $publicKey)
244
    {
245 24
        if ($this->flags->checkFlags(self::VERIFY_STRICTENC) && !PublicKey::isCompressedOrUncompressed($publicKey)) {
246 6
            throw new ScriptRuntimeException(self::VERIFY_STRICTENC, 'Public key with incorrect encoding');
247
        }
248
249 18
        return $this;
250
    }
251
252
    /**
253
     * @param $opCode
254
     * @param Buffer $pushData
255
     * @return bool
256
     * @throws \Exception
257
     */
258 6
    public function checkMinimalPush($opCode, Buffer $pushData)
259
    {
260 6
        $pushSize = $pushData->getSize();
261 6
        $binary = $pushData->getBinary();
262
263 6
        if ($pushSize === 0) {
264
            return $opCode === Opcodes::OP_0;
265 6
        } elseif ($pushSize === 1) {
266
            $first = ord($binary[0]);
267
            if ($first >= 1 && $first <= 16) {
268
                return $opCode === (Opcodes::OP_1 + ($first - 1));
269
            } elseif ($first === 0x81) {
270
                return $opCode === Opcodes::OP_1NEGATE;
271
            }
272 6
        } elseif ($pushSize <= 75) {
273 6
            return $opCode === $pushSize;
274
        } elseif ($pushSize <= 255) {
275
            return $opCode === Opcodes::OP_PUSHDATA1;
276
        } elseif ($pushSize <= 65535) {
277
            return $opCode === Opcodes::OP_PUSHDATA2;
278
        }
279
280
        return true;
281
    }
282
283
    /**
284
     * @return $this
285
     * @throws \Exception
286
     */
287 672
    private function checkOpcodeCount()
288
    {
289 672
        if ($this->math->cmp($this->opCount, 201) > 0) {
290 6
            throw new \RuntimeException('Error: Script op code count');
291
        }
292
293 672
        return $this;
294
    }
295
296
    /**
297
     * @param ScriptInterface $script
298
     * @param Buffer $sigBuf
299
     * @param Buffer $keyBuf
300
     * @return bool
301
     * @throws ScriptRuntimeException
302
     * @throws \Exception
303
     */
304 18
    private function checkSig(ScriptInterface $script, Buffer $sigBuf, Buffer $keyBuf)
305
    {
306 18
        $this
307 18
            ->checkSignatureEncoding($sigBuf)
308 12
            ->checkPublicKeyEncoding($keyBuf);
309
310
        try {
311 12
            $txSignature = TransactionSignatureFactory::fromHex($sigBuf->getHex());
312 12
            $publicKey = PublicKeyFactory::fromHex($keyBuf->getHex());
313
314 12
            return $this->ecAdapter->verify(
315 12
                $this
316
                    ->transaction
317 12
                    ->getSignatureHash()
318 12
                    ->calculate($script, $this->inputToSign, $txSignature->getHashType()),
319 12
                $publicKey,
320 12
                $txSignature->getSignature()
321 12
            );
322
        } catch (\Exception $e) {
323
            return false;
324
        }
325
    }
326
327
    /**
328
     * @param int $lockTime
329
     * @return bool
330
     */
331
    private function checkLockTime($lockTime)
332
    {
333
        $txLockTime = $this->transaction->getLockTime();
334
        if (($this->math->cmp($txLockTime, Locktime::BLOCK_MAX) < 0 && $this->math->cmp($lockTime, Locktime::BLOCK_MAX) < 0) ||
335
            ($this->math->cmp($txLockTime, Locktime::BLOCK_MAX) >= 0 && $this->math->cmp($lockTime, Locktime::BLOCK_MAX) >= 0)
336
        ) {
337
            return false;
338
        }
339
340
        if ($this->math->cmp($lockTime, $txLockTime) > 0) {
341
            return false;
342
        }
343
344
        if ($this->transaction->getInput($this->inputToSign)->isFinal()) {
345
            return false;
346
        }
347
348
        return true;
349
    }
350
351
    /**
352
     * @param ScriptInterface $scriptSig
353
     * @param ScriptInterface $scriptPubKey
354
     * @param int $nInputToSign
355
     * @return bool
356
     * @throws \Exception
357
     */
358 684
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $nInputToSign)
359
    {
360 684
        $this->inputToSign = $nInputToSign;
361 684
        if (!$this->setScript($scriptSig)->run()) {
362
            return false;
363
        }
364
365 684
        $mainStack = $this->state->getMainStack();
366 684
        $stackCopy = new Stack;
367 684
        if ($this->flags->checkFlags(self::VERIFY_P2SH)) {
368 156
            $stackCopy = $this->state->cloneMainStack();
369 156
        }
370
371 684
        if (!$this->setScript($scriptPubKey)->run()) {
372 258
            return false;
373
        }
374
375 426
        if ($mainStack->isEmpty()) {
376
            return false;
377
        }
378
379 426
        if (false === $this->castToBool($mainStack[-1])) {
380
            return false;
381
        }
382
383 426
        $verifier = new OutputClassifier($scriptPubKey);
384
385 426
        if ($this->flags->checkFlags(self::VERIFY_P2SH) && $verifier->isPayToScriptHash()) {
386 6
            if (!$scriptSig->isPushOnly()) {
387
                return false;
388
            }
389
390
            // Restore mainStack to how it was after evaluating scriptSig
391 6
            $mainStack = $this->state->restoreMainStack($stackCopy)->getMainStack();
392 6
            if ($mainStack->isEmpty()) {
393
                return false;
394
            }
395
396
            // Load redeemscript as the scriptPubKey
397 6
            $scriptPubKey = new Script($mainStack->bottom());
398 6
            $mainStack->pop();
399
400 6
            if (!$this->setScript($scriptPubKey)->run()) {
401
                return false;
402
            }
403 6
        }
404
405 426
        return true;
406
    }
407
408
    /**
409
     * @return bool
410
     */
411 684
    private function checkExec()
412
    {
413 684
        $vfStack = $this->state->getVfStack();
414 684
        $c = 0;
415 684
        $len = $vfStack->end();
416 684
        for ($i = 0; $i < $len; $i++) {
417
            if ($vfStack[0 - $len - $i] === true) {
418
                $c++;
419
            }
420
        }
421 684
        return !(bool)$c;
422
    }
423
424
    /**
425
     * @return bool
426
     */
427 684
    private function run()
428
    {
429 684
        $math = $this->math;
430
431 684
        $flags = $this->flags;
432 684
        $mainStack = $this->state->getMainStack();
433 684
        $altStack = $this->state->getAltStack();
434 684
        $vfStack = $this->state->getVfStack();
435
436 684
        $this->hashStartPos = 0;
437 684
        $this->opCount = 0;
438 684
        $parser = $this->script->getScriptParser();
439
440 684
        if ($this->script->getBuffer()->getSize() > 10000) {
441
            return false;
442
        }
443
444
        try {
445 684
            foreach ($parser as $exec) {
446 684
                $opCode = $exec->getOp();
447 684
                $pushData = $exec->getData();
448 684
                $fExec = $this->checkExec();
449
450
                // If pushdata was written to,
451 684
                if ($exec->isPush() && $exec->getDataSize() > InterpreterInterface::MAX_SCRIPT_ELEMENT_SIZE) {
452
                    throw new \RuntimeException('Error - push size');
453
                }
454
455
                // OP_RESERVED should not count towards opCount
456 684
                if ($opCode > Opcodes::OP_16 && ++$this->opCount) {
457 672
                    $this->checkOpcodeCount();
458 672
                }
459
460 684
                if ($this->checkDisabledOpcodes && $this->isDisabledOp($opCode)) {
461 12
                    throw new \RuntimeException('Disabled Opcode');
462
                }
463
464 684
                if ($fExec && $exec->isPush()) {
465
                    // In range of a pushdata opcode
466 426
                    if ($this->minimalPush && !$this->checkMinimalPush($opCode, $pushData)) {
467 6
                        throw new ScriptRuntimeException(self::VERIFY_MINIMALDATA, 'Minimal pushdata required');
468
                    }
469
470 420
                    $mainStack->push($pushData);
471
                    // echo " - [pushed '" . $pushData->getHex() . "']\n";
472 678
                } elseif ($fExec || ($opCode !== Opcodes::OP_IF && $opCode !== Opcodes::OP_ENDIF)) {
473
                    // echo "OPCODE - " . $this->script->getOpCodes()->getOp($opCode) . "\n";
474
                    switch ($opCode) {
475 660
                        case Opcodes::OP_1NEGATE:
476 660
                        case Opcodes::OP_1:
477 660
                        case Opcodes::OP_2:
478 660
                        case Opcodes::OP_3:
479 660
                        case Opcodes::OP_4:
480 660
                        case Opcodes::OP_5:
481 660
                        case Opcodes::OP_6:
482 660
                        case Opcodes::OP_7:
483 660
                        case Opcodes::OP_8:
484 660
                        case Opcodes::OP_9:
485 660
                        case Opcodes::OP_10:
486 660
                        case Opcodes::OP_11:
487 660
                        case Opcodes::OP_12:
488 660
                        case Opcodes::OP_13:
489 660
                        case Opcodes::OP_14:
490 660
                        case Opcodes::OP_15:
491 660
                        case Opcodes::OP_16:
492 192
                            $num = $opCode - (Opcodes::OP_1 - 1);
493 192
                            $mainStack->push(Number::int($num)->getBuffer());
494 192
                            break;
495
496 660
                        case Opcodes::OP_CHECKLOCKTIMEVERIFY:
497
                            if (!$this->flags->checkFlags(self::VERIFY_CHECKLOCKTIMEVERIFY)) {
498
                                if ($this->flags->checkFlags(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS)) {
499
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
500
                                }
501
                                break;
502
                            }
503
504
                            if ($mainStack->isEmpty()) {
505
                                throw new \RuntimeException('Invalid stack operation - CLTV');
506
                            }
507
508
                            $lockTime = Number::buffer($mainStack[-1], $this->minimalPush, 5, $math)->getInt();
509
                            if (!$this->checkLockTime($lockTime)) {
510
                                throw new ScriptRuntimeException(self::VERIFY_CHECKLOCKTIMEVERIFY, 'Unsatisfied locktime');
511
                            }
512
513
                            break;
514
515 660
                        case Opcodes::OP_NOP1:
516 660
                        case Opcodes::OP_NOP3:
517 660
                        case Opcodes::OP_NOP4:
518 660
                        case Opcodes::OP_NOP5:
519 660
                        case Opcodes::OP_NOP6:
520 660
                        case Opcodes::OP_NOP7:
521 660
                        case Opcodes::OP_NOP8:
522 660
                        case Opcodes::OP_NOP9:
523 660
                        case Opcodes::OP_NOP10:
524 6
                            if ($flags->checkFlags(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS)) {
525 6
                                throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
526
                            }
527
                            break;
528
529 654
                        case Opcodes::OP_NOP:
530 12
                            break;
531
532 642
                        case Opcodes::OP_IF:
533 642
                        case Opcodes::OP_NOTIF:
534
                            // <expression> if [statements] [else [statements]] endif
535 18
                            $value = false;
536 18
                            if ($fExec) {
537 18
                                if ($mainStack->isEmpty()) {
538 6
                                    throw new \RuntimeException('Unbalanced conditional');
539
                                }
540
                                // todo
541 12
                                $buffer = Number::buffer($mainStack->pop(), $this->minimalPush)->getBuffer();
542 12
                                $value = $this->castToBool($buffer);
543 12
                                if ($opCode === Opcodes::OP_NOTIF) {
544 6
                                    $value = !$value;
545 6
                                }
546 12
                            }
547 12
                            $vfStack->push($value ? $this->vchTrue : $this->vchFalse);
548 12
                            break;
549
550 636
                        case Opcodes::OP_ELSE:
551 18
                            if ($vfStack->isEmpty()) {
552 6
                                throw new \RuntimeException('Unbalanced conditional');
553
                            }
554 12
                            $vfStack[-1] = !$vfStack->end() ? $this->vchTrue : $this->vchFalse;
555 12
                            break;
556
557 630
                        case Opcodes::OP_ENDIF:
558 18
                            if ($vfStack->isEmpty()) {
559 6
                                throw new \RuntimeException('Unbalanced conditional');
560
                            }
561 12
                            break;
562
563 624
                        case Opcodes::OP_VERIFY:
564 24
                            if ($mainStack->isEmpty()) {
565 6
                                throw new \RuntimeException('Invalid stack operation');
566
                            }
567 18
                            $value = $this->castToBool($mainStack[-1]);
568 18
                            if (!$value) {
569 6
                                throw new \RuntimeException('Error: verify');
570
                            }
571 12
                            $mainStack->pop();
572 12
                            break;
573
574 600
                        case Opcodes::OP_RESERVED:
575
                            // todo
576 12
                            break;
577
578 588
                        case Opcodes::OP_TOALTSTACK:
579 18
                            if ($mainStack->isEmpty()) {
580 6
                                throw new \RuntimeException('Invalid stack operation OP_TOALTSTACK');
581
                            }
582 12
                            $altStack->push($mainStack->pop());
583 12
                            break;
584
585 582
                        case Opcodes::OP_FROMALTSTACK:
586 12
                            if ($altStack->isEmpty()) {
587 6
                                throw new \RuntimeException('Invalid alt-stack operation OP_FROMALTSTACK');
588
                            }
589 6
                            $mainStack->push($altStack->pop());
590 6
                            break;
591
592 576
                        case Opcodes::OP_IFDUP:
593
                            // If top value not zero, duplicate it.
594 12
                            if ($mainStack->isEmpty()) {
595 6
                                throw new \RuntimeException('Invalid stack operation OP_IFDUP');
596
                            }
597 6
                            $vch = $mainStack[-1];
598 6
                            if ($this->castToBool($vch)) {
599 6
                                $mainStack->push($vch);
600 6
                            }
601 6
                            break;
602
603 570
                        case Opcodes::OP_DEPTH:
604 72
                            $num = count($mainStack);
605 72
                            if ($num === 0) {
606 24
                                $depth = $this->vchFalse;
607 24
                            } else {
608 54
                                $depth = Number::int($num)->getBuffer();
609
                            }
610
611 72
                            $mainStack->push($depth);
612 72
                            break;
613
614 570
                        case Opcodes::OP_DROP:
615 6
                            if ($mainStack->isEmpty()) {
616 6
                                throw new \RuntimeException('Invalid stack operation OP_DROP');
617
                            }
618
                            $mainStack->pop();
619
                            break;
620
621 564
                        case Opcodes::OP_DUP:
622 18
                            if ($mainStack->isEmpty()) {
623 6
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
624
                            }
625 12
                            $vch = $mainStack[-1];
626 12
                            $mainStack->push($vch);
627 12
                            break;
628
629 558
                        case Opcodes::OP_NIP:
630 18
                            if (count($mainStack) < 2) {
631 6
                                throw new \RuntimeException('Invalid stack operation OP_NIP');
632
                            }
633 12
                            unset($mainStack[-2]);
634 12
                            break;
635
636 552
                        case Opcodes::OP_OVER:
637 18
                            if (count($mainStack) < 2) {
638 6
                                throw new \RuntimeException('Invalid stack operation OP_OVER');
639
                            }
640 12
                            $vch = $mainStack[-2];
641 12
                            $mainStack->push($vch);
642 12
                            break;
643
    
644 546
                        case Opcodes::OP_ROT:
645 12
                            if (count($mainStack) < 3) {
646 6
                                throw new \RuntimeException('Invalid stack operation OP_ROT');
647
                            }
648 6
                            $mainStack->swap(-3, -2);
649 6
                            $mainStack->swap(-2, -1);
650 6
                            break;
651
652 540
                        case Opcodes::OP_SWAP:
653 12
                            if (count($mainStack) < 2) {
654 6
                                throw new \RuntimeException('Invalid stack operation OP_SWAP');
655
                            }
656 6
                            $mainStack->swap(-2, -1);
657 6
                            break;
658
659 534
                        case Opcodes::OP_TUCK:
660 12
                            if (count($mainStack) < 2) {
661 6
                                throw new \RuntimeException('Invalid stack operation OP_TUCK');
662
                            }
663 6
                            $vch = $mainStack[-1];
664 6
                            $mainStack->add(count($mainStack) - 1 - 2, $vch);
665
                            break;
666
667 522
                        case Opcodes::OP_PICK:
668 522
                        case Opcodes::OP_ROLL:
669 24
                            if (count($mainStack) < 2) {
670 6
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
671
                            }
672
673 18
                            $n = Number::buffer($mainStack[-1], $this->minimalPush, 4)->getInt();
674 18
                            $mainStack->pop();
675 18
                            if ($math->cmp($n, 0) < 0 || $math->cmp($n, count($mainStack)) >= 0) {
676 6
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
677
                            }
678
679 12
                            $pos = (int) $math->sub($math->sub(0, $n), 1);
680 12
                            $vch = $mainStack[$pos];
681 12
                            if ($opCode === Opcodes::OP_ROLL) {
682 6
                                unset($mainStack[$pos]);
683 6
                            }
684 12
                            $mainStack->push($vch);
685 12
                            break;
686
687 510
                        case Opcodes::OP_2DROP:
688 12
                            if (count($mainStack) < 2) {
689 6
                                throw new \RuntimeException('Invalid stack operation OP_2DROP');
690
                            }
691 6
                            $mainStack->pop();
692 6
                            $mainStack->pop();
693 6
                            break;
694
695 504
                        case Opcodes::OP_2DUP:
696 18
                            if (count($mainStack) < 2) {
697 6
                                throw new \RuntimeException('Invalid stack operation OP_2DUP');
698
                            }
699 12
                            $string1 = $mainStack[-2];
700 12
                            $string2 = $mainStack[-1];
701 12
                            $mainStack->push($string1);
702 12
                            $mainStack->push($string2);
703 12
                            break;
704
705 498
                        case Opcodes::OP_3DUP:
706 18
                            if (count($mainStack) < 3) {
707 6
                                throw new \RuntimeException('Invalid stack operation OP_3DUP');
708
                            }
709 12
                            $string1 = $mainStack[-3];
710 12
                            $string2 = $mainStack[-2];
711 12
                            $string3 = $mainStack[-1];
712 12
                            $mainStack->push($string1);
713 12
                            $mainStack->push($string2);
714 12
                            $mainStack->push($string3);
715 12
                            break;
716
717 492
                        case Opcodes::OP_2OVER:
718 18
                            if (count($mainStack) < 4) {
719 6
                                throw new \RuntimeException('Invalid stack operation OP_2OVER');
720
                            }
721 12
                            $string1 = $mainStack[-4];
722 12
                            $string2 = $mainStack[-3];
723 12
                            $mainStack->push($string1);
724 12
                            $mainStack->push($string2);
725 12
                            break;
726
727 486
                        case Opcodes::OP_2ROT:
728 12
                            if (count($mainStack) < 6) {
729 6
                                throw new \RuntimeException('Invalid stack operation OP_2ROT');
730
                            }
731 6
                            $string1 = $mainStack[-6];
732 6
                            $string2 = $mainStack[-5];
733 6
                            unset($mainStack[-6], $mainStack[-5]);
734 6
                            $mainStack->push($string1);
735 6
                            $mainStack->push($string2);
736 6
                            break;
737
738 480
                        case Opcodes::OP_2SWAP:
739 12
                            if (count($mainStack) < 4) {
740 6
                                throw new \RuntimeException('Invalid stack operation OP_2SWAP');
741
                            }
742 6
                            $mainStack->swap(-3, -1);
743 6
                            $mainStack->swap(-4, -2);
744 6
                            break;
745
746 474
                        case Opcodes::OP_SIZE:
747 12
                            if ($mainStack->isEmpty()) {
748 6
                                throw new \RuntimeException('Invalid stack operation OP_SIZE');
749
                            }
750
                            // todo: Int sizes?
751 6
                            $vch = $mainStack[-1];
752 6
                            $mainStack->push(Number::int($vch->getSize())->getBuffer());
753 6
                            break;
754
755 468
                        case Opcodes::OP_EQUAL:
756 468
                        case Opcodes::OP_EQUALVERIFY:
757 396
                            if (count($mainStack) < 2) {
758 6
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
759
                            }
760 390
                            $vch1 = $mainStack[-2];
761 390
                            $vch2 = $mainStack[-1];
762
763 390
                            $equal = ($vch1->getBinary() === $vch2->getBinary());
764
765 390
                            $mainStack->pop();
766 390
                            $mainStack->pop();
767 390
                            $mainStack->push(($equal ? $this->vchTrue : $this->vchFalse));
768 390
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
769 114
                                if ($equal) {
770 102
                                    $mainStack->pop();
771 102
                                } else {
772 12
                                    throw new \RuntimeException('Error EQUALVERIFY');
773
                                }
774 102
                            }
775
776 378
                            break;
777
778
                        // Arithmetic operations
779 282
                        case $opCode >= Opcodes::OP_1ADD && $opCode <= Opcodes::OP_0NOTEQUAL:
780 48
                            if ($mainStack->isEmpty()) {
781 6
                                throw new \Exception('Invalid stack operation 1ADD-OP_0NOTEQUAL');
782
                            }
783
784 42
                            $num = Number::buffer($mainStack[-1], $this->minimalPush)->getInt();
785
786 42
                            if ($opCode === Opcodes::OP_1ADD) {
787 6
                                $num = $math->add($num, '1');
788 42
                            } elseif ($opCode === Opcodes::OP_1SUB) {
789 6
                                $num = $math->sub($num, '1');
790 36
                            } elseif ($opCode === Opcodes::OP_2MUL) {
791
                                $num = $math->mul(2, $num);
792 30
                            } elseif ($opCode === Opcodes::OP_NEGATE) {
793
                                $num = $math->sub(0, $num);
794 30
                            } elseif ($opCode === Opcodes::OP_ABS) {
795
                                if ($math->cmp($num, '0') < 0) {
796
                                    $num = $math->sub(0, $num);
797
                                }
798 30
                            } elseif ($opCode === Opcodes::OP_NOT) {
799 18
                                $num = (int) $math->cmp($num, '0') === 0;
800 18
                            } else {
801
                                // is OP_0NOTEQUAL
802 12
                                $num = (int) ($math->cmp($num, '0') !== 0);
803
                            }
804
805 42
                            $mainStack->pop();
806
807 42
                            $buffer = Number::int($num)->getBuffer();
808
809 42
                            $mainStack->push($buffer);
810 42
                            break;
811
812 234
                        case $opCode >= Opcodes::OP_ADD && $opCode <= Opcodes::OP_MAX:
813 150
                            if (count($mainStack) < 2) {
814 24
                                throw new \Exception('Invalid stack operation (OP_ADD - OP_MAX)');
815
                            }
816
817 126
                            $num1 = Number::buffer($mainStack[-2], $this->minimalPush)->getInt();
818 126
                            $num2 = Number::buffer($mainStack[-1], $this->minimalPush)->getInt();
819
820 126
                            if ($opCode === Opcodes::OP_ADD) {
821 6
                                $num = $math->add($num1, $num2);
822 126
                            } else if ($opCode === Opcodes::OP_SUB) {
823 6
                                $num = $math->sub($num1, $num2);
824 120
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
825 12
                                $num = $math->cmp($num1, $this->int0->getInt()) !== 0 && $math->cmp($num2, $this->int0->getInt()) !== 0;
826 114
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
827 18
                                $num = $math->cmp($num1, $this->int0->getInt()) !== 0 || $math->cmp($num2, $this->int0->getInt()) !== 0;
828 102
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
829 18
                                $num = $math->cmp($num1, $num2) === 0;
830 84
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
831
                                $num = $math->cmp($num1, $num2) === 0;
832 66
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
833 6
                                $num = $math->cmp($num1, $num2) !== 0;
834 66
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) {
835 12
                                $num = $math->cmp($num1, $num2) < 0;
836 60
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
837 12
                                $num = $math->cmp($num1, $num2) > 0;
838 48
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) {
839 12
                                $num = $math->cmp($num1, $num2) <= 0;
840 36
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
841 12
                                $num = $math->cmp($num1, $num2) >= 0;
842 24
                            } elseif ($opCode === Opcodes::OP_MIN) {
843 6
                                $num = ($math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
844 6
                            } else {
845 6
                                $num = ($math->cmp($num1, $num2) >= 0) ? $num1 : $num2;
846
                            }
847
848 126
                            $mainStack->pop();
849 126
                            $mainStack->pop();
850 126
                            $buffer = Number::int($num)->getBuffer();
851 126
                            $mainStack->push($buffer);
852
853 126
                            if ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
854
                                if ($this->castToBool($mainStack[-1])) {
855
                                    $mainStack->pop();
856
                                } else {
857
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
858
                                }
859
                            }
860 126
                            break;
861
862 84
                        case Opcodes::OP_WITHIN:
863 12
                            if (count($mainStack) < 3) {
864 6
                                throw new \RuntimeException('Invalid stack operation');
865
                            }
866
867 6
                            $num1 = Number::buffer($mainStack[-3], $this->minimalPush)->getInt();
868 6
                            $num2 = Number::buffer($mainStack[-2], $this->minimalPush)->getInt();
869 6
                            $num3 = Number::buffer($mainStack[-1], $this->minimalPush)->getInt();
870
871 6
                            $value = $math->cmp($num2, $num1) <= 0 && $math->cmp($num1, $num3) < 0;
872 6
                            $mainStack->pop();
873 6
                            $mainStack->pop();
874 6
                            $mainStack->pop();
875 6
                            $mainStack->push($value ? $this->vchFalse : $this->vchTrue);
876 6
                            break;
877
878
                        // Hash operation
879 72
                        case Opcodes::OP_RIPEMD160:
880 72
                        case Opcodes::OP_SHA1:
881 72
                        case Opcodes::OP_SHA256:
882 72
                        case Opcodes::OP_HASH160:
883 72
                        case Opcodes::OP_HASH256:
884 48
                            if ($mainStack->isEmpty()) {
885 6
                                throw new \RuntimeException('Invalid stack operation');
886
                            }
887
888 42
                            $buffer = $mainStack[-1];
889 42
                            if ($opCode === Opcodes::OP_RIPEMD160) {
890 6
                                $hash = Hash::ripemd160($buffer);
891 42
                            } elseif ($opCode === Opcodes::OP_SHA1) {
892 6
                                $hash = Hash::sha1($buffer);
893 36
                            } elseif ($opCode === Opcodes::OP_SHA256) {
894 6
                                $hash = Hash::sha256($buffer);
895 30
                            } elseif ($opCode === Opcodes::OP_HASH160) {
896 18
                                $hash = Hash::sha256ripe160($buffer);
897 18
                            } else {
898 6
                                $hash = Hash::sha256d($buffer);
899
                            }
900
901 42
                            $mainStack->pop();
902 42
                            $mainStack->push($hash);
903 42
                            break;
904
905 30
                        case Opcodes::OP_CODESEPARATOR:
906
                            $this->hashStartPos = $parser->getPosition();
907
                            break;
908
909 30
                        case Opcodes::OP_CHECKSIG:
910 30
                        case Opcodes::OP_CHECKSIGVERIFY:
911 24
                            if (count($mainStack) < 2) {
912 6
                                throw new \RuntimeException('Invalid stack operation');
913
                            }
914
915 18
                            $vchPubKey = $mainStack[-1];
916 18
                            $vchSig = $mainStack[-2];
917
918 18
                            $scriptCode = new Script($this->script->getBuffer()->slice($this->hashStartPos));
919 18
                            $success = $this->checkSig($scriptCode, $vchSig, $vchPubKey);
920
921 12
                            $mainStack->pop();
922 12
                            $mainStack->pop();
923 12
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
924
925 12
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
926
                                if ($success) {
927
                                    $mainStack->pop();
928
                                } else {
929
                                    throw new \RuntimeException('Checksig verify');
930
                                }
931
                            }
932 12
                            break;
933
934 6
                        case Opcodes::OP_CHECKMULTISIG:
935 6
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
936
                            $i = 1;
937
                            if (count($mainStack) < $i) {
938
                                throw new \RuntimeException('Invalid stack operation');
939
                            }
940
941
                            $keyCount = Number::buffer($mainStack[-$i], $this->minimalPush)->getInt();
942
                            if ($math->cmp($keyCount, 0) < 0 || $math->cmp($keyCount, 20) > 0) {
943
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
944
                            }
945
                            $this->opCount += $keyCount;
946
                            $this->checkOpcodeCount();
947
948
                            // Extract positions of the keys, and signatures, from the stack.
949
                            $ikey = ++$i;
950
                            $i += $keyCount; /** @var int $i */
951
                            if (count($mainStack) < $i) {
952
                                throw new \RuntimeException('Invalid stack operation');
953
                            }
954
955
                            $sigCount = Number::buffer($mainStack[-$i], $this->minimalPush)->getInt();
956
                            if ($math->cmp($sigCount, 0) < 0 || $math->cmp($sigCount, $keyCount) > 0) {
957
                                throw new \RuntimeException('Invalid Signature count');
958
                            }
959
                            $isig = ++$i;
960
                            $i += $sigCount;
961
962
                            // Extract the script since the last OP_CODESEPARATOR
963
                            $scriptCode = new Script($this->script->getBuffer()->slice($this->hashStartPos));
964
965
                            $fSuccess = true;
966
                            while ($fSuccess && $sigCount > 0) {
967
                                // Fetch the signature and public key
968
                                $sig = $mainStack[-$isig];
969
                                $pubkey = $mainStack[-$ikey];
970
971
                                // Erase the signature and public key.
972
                                unset($mainStack[-$isig], $mainStack[-$ikey]);
973
974
                                // Decrement $i, since we are consuming stack values.
975
                                $i -= 2;
976
977
                                if ($this->checkSig($scriptCode, $sig, $pubkey)) {
978
                                    $isig++;
979
                                    $sigCount--;
980
                                }
981
982
                                $ikey++;
983
                                $keyCount--;
984
985
                                // If there are more signatures left than keys left,
986
                                // then too many signatures have failed. Exit early,
987
                                // without checking any further signatures.
988
                                if ($sigCount > $keyCount) {
989
                                    $fSuccess = false;
990
                                }
991
                            }
992
993
                            while ($i-- > 1) {
994
                                $mainStack->pop();
995
                            }
996
997
                            // A bug causes CHECKMULTISIG to consume one extra argument
998
                            // whose contents were not checked in any way.
999
                            //
1000
                            // Unfortunately this is a potential source of mutability,
1001
                            // so optionally verify it is exactly equal to zero prior
1002
                            // to removing it from the stack.
1003
                            if ($mainStack->isEmpty()) {
1004
                                throw new \RuntimeException('Invalid stack operation');
1005
                            }
1006
1007
                            if ($flags->checkFlags(self::VERIFY_NULL_DUMMY) && $mainStack[-1]->getSize()) {
1008
                                throw new ScriptRuntimeException(self::VERIFY_NULL_DUMMY, 'Extra P2SH stack value should be OP_0');
1009
                            }
1010
1011
                            $mainStack->pop();
1012
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
1013
1014
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
1015
                                if ($fSuccess) {
1016
                                    $mainStack->pop();
1017
                                } else {
1018
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
1019
                                }
1020
                            }
1021
                            break;
1022
1023 6
                        default:
1024 6
                            throw new \RuntimeException('Opcode not found');
1025 6
                    }
1026
1027 426
                    if (count($mainStack) + count($altStack) > 1000) {
1028
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
1029
                    }
1030 426
                }
1031 684
            }
1032
1033 684
            if (!$vfStack->end() === 0) {
1034
                throw new \RuntimeException('Unbalanced conditional at script end');
1035
            }
1036
1037 684
            return true;
1038 258
        } catch (ScriptRuntimeException $e) {
1039
            // echo "\n Runtime: " . $e->getMessage() . "\n";
1040
            // Failure due to script tags, can access flag: $e->getFailureFlag()
1041 18
            return false;
1042 240
        } catch (\Exception $e) {
1043
            // echo "\n General: " . $e->getMessage() ;
1044 240
            return false;
1045
        }
1046
    }
1047
}
1048