Completed
Pull Request — master (#333)
by thomas
43:53 queued 39:08
created

Interpreter::verifyWitnessProgram()   C

Complexity

Conditions 12
Paths 22

Size

Total Lines 56
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 12.1081

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 33
c 1
b 0
f 0
nc 22
nop 4
dl 0
loc 56
ccs 30
cts 33
cp 0.9091
crap 12.1081
rs 6.7092

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Script\Classifier\OutputClassifier;
10
use BitWasp\Bitcoin\Script\Opcodes;
11
use BitWasp\Bitcoin\Script\Script;
12
use BitWasp\Bitcoin\Script\ScriptFactory;
13
use BitWasp\Bitcoin\Script\ScriptInterface;
14
use BitWasp\Bitcoin\Script\ScriptWitness;
15
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
16
use BitWasp\Bitcoin\Script\WitnessProgram;
17
use BitWasp\Bitcoin\Signature\TransactionSignature;
18
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
19
use BitWasp\Buffertools\Buffer;
20
use BitWasp\Buffertools\BufferInterface;
21
22
class Interpreter implements InterpreterInterface
23
{
24
25
    /**
26
     * @var \BitWasp\Bitcoin\Math\Math
27
     */
28
    private $math;
29
30
    /**
31
     * @var BufferInterface
32
     */
33
    private $vchFalse;
34
35
    /**
36
     * @var BufferInterface
37
     */
38
    private $vchTrue;
39
40
    /**
41
     * @var array
42
     */
43
    private $disabledOps = [
44
        Opcodes::OP_CAT,    Opcodes::OP_SUBSTR, Opcodes::OP_LEFT,  Opcodes::OP_RIGHT,
45
        Opcodes::OP_INVERT, Opcodes::OP_AND,    Opcodes::OP_OR,    Opcodes::OP_XOR,
46
        Opcodes::OP_2MUL,   Opcodes::OP_2DIV,   Opcodes::OP_MUL,   Opcodes::OP_DIV,
47
        Opcodes::OP_MOD,    Opcodes::OP_LSHIFT, Opcodes::OP_RSHIFT
48
    ];
49
50
    /**
51
     * @param EcAdapterInterface $ecAdapter
52
     */
53 408
    public function __construct(EcAdapterInterface $ecAdapter)
54
    {
55 408
        $this->math = $ecAdapter->getMath();
56 408
        $this->vchFalse = new Buffer("", 0, $this->math);
57 408
        $this->vchTrue = new Buffer("\x01", 1, $this->math);
58 408
    }
59
60
    /**
61
     * Cast the value to a boolean
62
     *
63
     * @param BufferInterface $value
64
     * @return bool
65
     */
66 2646
    public function castToBool(BufferInterface $value)
67
    {
68 2646
        $character = $value->getBinary();
0 ignored issues
show
Unused Code introduced by
$character is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
69 2646
        $characters = array_values(unpack("C*", $value->getBinary()));
70 2646
        $size = count($characters);
71
72 2646
        for ($i = 0; $i < $size; $i++) {
73 2439
            $chr = ord($characters[$i]);
74 2439
            if ($chr !== 0) {
75 2439
                if ($i === ($size - 1) && $chr === 0x80) {
76
                    return false;
77
                }
78
79 2439
                return true;
80
            }
81
        }
82
83 591
        return false;
84
    }
85
86
    /**
87
     * @param BufferInterface $signature
88
     * @return bool
89
     */
90
    public function isValidSignatureEncoding(BufferInterface $signature)
91
    {
92
        try {
93
            TransactionSignature::isDERSignature($signature);
94
            return true;
95
        } catch (SignatureNotCanonical $e) {
96
            /* In any case, we will return false outside this block */
97
        }
98
99
        return false;
100
    }
101
102
    /**
103
     * @param int $opCode
104
     * @param BufferInterface $pushData
105
     * @return bool
106
     * @throws \Exception
107
     */
108 351
    public function checkMinimalPush($opCode, BufferInterface $pushData)
109
    {
110 351
        $pushSize = $pushData->getSize();
111 351
        $binary = $pushData->getBinary();
112
113 351
        if ($pushSize === 0) {
114 165
            return $opCode === Opcodes::OP_0;
115 288
        } elseif ($pushSize === 1) {
116 69
            $first = ord($binary[0]);
117 69
            if ($first >= 1 && $first <= 16) {
118 51
                return $opCode === (Opcodes::OP_1 + ($first - 1));
119 21
            } elseif ($first === 0x81) {
120 11
                return $opCode === Opcodes::OP_1NEGATE;
121
            }
122 232
        } elseif ($pushSize <= 75) {
123 216
            return $opCode === $pushSize;
124 9
        } elseif ($pushSize <= 255) {
125 6
            return $opCode === Opcodes::OP_PUSHDATA1;
126 6
        } elseif ($pushSize <= 65535) {
127 6
            return $opCode === Opcodes::OP_PUSHDATA2;
128
        }
129
130 18
        return true;
131
    }
132
133
    /**
134
     * @param int $count
135
     * @return $this
136
     */
137 3447
    private function checkOpcodeCount($count)
138
    {
139 3447
        if ($count > 201) {
140 18
            throw new \RuntimeException('Error: Script op code count');
141
        }
142
143 3447
        return $this;
144
    }
145
146
    /**
147
     * @param WitnessProgram $witnessProgram
148
     * @param ScriptWitnessInterface $scriptWitness
149
     * @param int $flags
150
     * @param Checker $checker
151
     * @return bool
152
     */
153 72
    private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitnessInterface $scriptWitness, $flags, Checker $checker)
154
    {
155 72
        $witnessCount = count($scriptWitness);
156
157 72
        if ($witnessProgram->getVersion() == 0) {
158 69
            $buffer = $witnessProgram->getProgram();
159 69
            if ($buffer->getSize() === 32) {
160
                // Version 0 segregated witness program: SHA256(Script) in program, Script + inputs in witness
161 39
                if ($witnessCount === 0) {
162
                    // Must contain script at least
163 3
                    return false;
164
                }
165
166 36
                $scriptPubKey = new Script($scriptWitness[$witnessCount - 1]);
167 36
                $stackValues = $scriptWitness->slice(0, -1);
168 38
                $hashScriptPubKey = Hash::sha256($scriptPubKey->getBuffer());
169 36
                if (!$hashScriptPubKey->equals($buffer)) {
170 16
                    return false;
171
                }
172 50
            } elseif ($buffer->getSize() === 20) {
173
                // Version 0 special case for pay-to-pubkeyhash
174 27
                if ($witnessCount !== 2) {
175
                    // 2 items in witness - <signature> <pubkey>
176 3
                    return false;
177
                }
178
179 24
                $scriptPubKey = ScriptFactory::create()->sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $buffer, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG])->getScript();
180 24
                $stackValues = $scriptWitness;
181 16
            } else {
182 21
                return false;
183
            }
184 39
        } elseif ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
185 3
            return false;
186
        } else {
187
            return false;
188
        }
189
190 54
        $mainStack = new Stack();
191 54
        foreach ($stackValues as $value) {
192 51
            $mainStack->push($value);
193 36
        }
194
195 54
        if (!$this->evaluate($scriptPubKey, $mainStack, 1, $flags, $checker)) {
196
            return false;
197
        }
198
199 54
        if ($mainStack->count() !== 1) {
200
            return false;
201
        }
202
203 54
        if (!$this->castToBool($mainStack->bottom())) {
204 27
            return false;
205
        }
206
207 27
        return true;
208
    }
209
210
    /**
211
     * @param ScriptInterface $scriptSig
212
     * @param ScriptInterface $scriptPubKey
213
     * @param int $flags
214
     * @param Checker $checker
215
     * @param ScriptWitnessInterface|null $witness
216
     * @return bool
217
     */
218 3654
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $flags, Checker $checker, ScriptWitnessInterface $witness = null)
219
    {
220 3654
        static $emptyWitness = null;
221 3654
        if ($emptyWitness === null) {
222 3
            $emptyWitness = new ScriptWitness([]);
223 2
        }
224
225 3654
        $witness = is_null($witness) ? $emptyWitness : $witness;
226
227 3654
        if (($flags & self::VERIFY_SIGPUSHONLY) != 0 && !$scriptSig->isPushOnly()) {
228 6
            return false;
229
        }
230
231 3648
        $stack = new Stack();
232 3648
        if (!$this->evaluate($scriptSig, $stack, 0, $flags, $checker)) {
233 168
            return false;
234
        }
235
236 3480
        $backup = [];
237 3480
        if ($flags & self::VERIFY_P2SH) {
238 2328
            foreach ($stack as $s) {
239 1884
                $backup[] = $s;
240 1552
            }
241 1552
        }
242
243 3480
        if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
244 1140
            return false;
245
        }
246
247 2340
        if ($stack->isEmpty()) {
248 36
            return false;
249
        }
250
251 2304
        if (false === $this->castToBool($stack[-1])) {
252 147
            return false;
253
        }
254
255 2157
        $program = null;
256 2157
        if ($flags & self::VERIFY_WITNESS) {
257 102
            if ($scriptPubKey->isWitness($program)) {
258
                /** @var WitnessProgram $program */
259 51
                if ($scriptSig->getBuffer()->getSize() !== 0) {
260 3
                    return false;
261
                }
262
263 48
                if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
264 33
                    return false;
265
                }
266
267 15
                $stack->resize(1);
268 10
            }
269 44
        }
270
271 2121
        if ($flags & self::VERIFY_P2SH && (new OutputClassifier())->isPayToScriptHash($scriptPubKey)) {
272 93
            if (!$scriptSig->isPushOnly()) {
273 12
                return false;
274
            }
275
276 81
            $stack = new Stack();
277 81
            foreach ($backup as $i) {
278 81
                $stack->push($i);
279 54
            }
280
281
            // Restore mainStack to how it was after evaluating scriptSig
282 81
            if ($stack->isEmpty()) {
283
                return false;
284
            }
285
286
            // Load redeemscript as the scriptPubKey
287 81
            $scriptPubKey = new Script($stack->bottom());
288 81
            $stack->pop();
289
290 81
            if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
291 15
                return false;
292
            }
293
294 66
            if ($stack->isEmpty()) {
295
                return false;
296
            }
297
298 66
            if (!$this->castToBool($stack->bottom())) {
299 3
                return false;
300
            }
301
302 63
            if ($flags & self::VERIFY_WITNESS) {
303 33
                if ($scriptPubKey->isWitness($program)) {
304
                    /** @var WitnessProgram $program */
305 27
                    if ($scriptSig != (ScriptFactory::create()->push($scriptPubKey->getBuffer())->getScript())) {
306 3
                        return false; // SCRIPT_ERR_WITNESS_MALLEATED_P2SH
307
                    }
308
309 24
                    if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
310 12
                        return false;
311
                    }
312
313 12
                    $stack->resize(1);
314 8
                }
315 12
            }
316 32
        }
317
318 2076
        if ($flags & self::VERIFY_CLEAN_STACK) {
319 18
            if (!($flags & self::VERIFY_P2SH != 0 && $flags & self::VERIFY_WITNESS != 0)) {
320
                return false; // implied flags required
321
            }
322
323 18
            if (count($stack) != 1) {
324 6
                return false; // Cleanstack
325
            }
326 8
        }
327
328 2070
        if ($flags & self::VERIFY_WITNESS) {
329 51
            if (!$flags & self::VERIFY_P2SH) {
330
                return false; //
331
            }
332
333 51
            if ($program === null && !$witness->isNull()) {
334 3
                return false; // SCRIPT_ERR_WITNESS_UNEXPECTED
335
            }
336 32
        }
337
338 2067
        return true;
339
    }
340
341
    /**
342
     * @param Stack $vfStack
343
     * @return bool
344
     */
345 3636
    private function checkExec(Stack $vfStack)
346
    {
347 3636
        $ret = 0;
348 3636
        foreach ($vfStack as $item) {
349 726
            if ($item === false) {
350 556
                $ret++;
351 314
            }
352 2424
        }
353
354 3636
        return $ret;
355
    }
356
357
    /**
358
     * @param ScriptInterface $script
359
     * @param Stack $mainStack
360
     * @param int $sigVersion
361
     * @param int $flags
362
     * @param Checker $checker
363
     * @return bool
364
     */
365 3651
    public function evaluate(ScriptInterface $script, Stack $mainStack, $sigVersion, $flags, Checker $checker)
366
    {
367 3651
        $hashStartPos = 0;
368 3651
        $opCount = 0;
369 3651
        $altStack = new Stack();
370 3651
        $vfStack = new Stack();
371 3651
        $minimal = ($flags & self::VERIFY_MINIMALDATA) > 0;
372 3651
        $parser = $script->getScriptParser();
373
374 3651
        if ($script->getBuffer()->getSize() > 10000) {
375 3
            return false;
376
        }
377
378
        try {
379 3651
            foreach ($parser as $operation) {
380 3636
                $opCode = $operation->getOp();
381 3636
                $pushData = $operation->getData();
382 3636
                $fExec = !$this->checkExec($vfStack);
383
384
                // If pushdata was written to
385 3636
                if ($operation->isPush() && $operation->getDataSize() > InterpreterInterface::MAX_SCRIPT_ELEMENT_SIZE) {
386 9
                    throw new \RuntimeException('Error - push size');
387
                }
388
389
                // OP_RESERVED should not count towards opCount
390 3633
                if ($opCode > Opcodes::OP_16 && ++$opCount) {
391 3447
                    $this->checkOpcodeCount($opCount);
392 2298
                }
393
394 3633
                if (in_array($opCode, $this->disabledOps, true)) {
395 78
                    throw new \RuntimeException('Disabled Opcode');
396
                }
397
398 3633
                if ($fExec && $operation->isPush()) {
399 2604
                    var_dump($minimal);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($minimal); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
400
                    // In range of a pushdata opcode
401 2604
                    if ($minimal && !$this->checkMinimalPush($opCode, $pushData)) {
402 66
                        throw new ScriptRuntimeException(self::VERIFY_MINIMALDATA, 'Minimal pushdata required');
403
                    }
404
405 2538
                    $mainStack->push($pushData);
406 2538
                     echo " - [pushed '" . $pushData->getHex() . "']\n";
407 3549
                } elseif ($fExec || (Opcodes::OP_IF <= $opCode && $opCode <= Opcodes::OP_ENDIF)) {
408 3513
                     echo "OPCODE - " . $script->getOpcodes()->getOp($opCode) . "\n";
409
                    switch ($opCode) {
410 3513
                        case Opcodes::OP_1NEGATE:
411 3513
                        case Opcodes::OP_1:
412 3490
                        case Opcodes::OP_2:
413 3486
                        case Opcodes::OP_3:
414 3486
                        case Opcodes::OP_4:
415 3486
                        case Opcodes::OP_5:
416 3486
                        case Opcodes::OP_6:
417 3486
                        case Opcodes::OP_7:
418 3485
                        case Opcodes::OP_8:
419 3485
                        case Opcodes::OP_9:
420 3485
                        case Opcodes::OP_10:
421 3485
                        case Opcodes::OP_11:
422 3484
                        case Opcodes::OP_12:
423 3484
                        case Opcodes::OP_13:
424 3484
                        case Opcodes::OP_14:
425 3484
                        case Opcodes::OP_15:
426 3484
                        case Opcodes::OP_16:
427 2088
                            $num = Number::int((int) $opCode - (Opcodes::OP_1 - 1))->getBuffer();
428 2088
                            $mainStack->push($num);
429 2088
                            break;
430
431 3426
                        case Opcodes::OP_CHECKLOCKTIMEVERIFY:
432 18
                            if (!($flags & self::VERIFY_CHECKLOCKTIMEVERIFY)) {
433 18
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
434 3
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
435
                                }
436 15
                                break;
437
                            }
438
439
                            if ($mainStack->isEmpty()) {
440
                                throw new \RuntimeException('Invalid stack operation - CLTV');
441
                            }
442
443
                            $lockTime = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
444
                            if (!$checker->checkLockTime($lockTime)) {
445
                                throw new ScriptRuntimeException(self::VERIFY_CHECKLOCKTIMEVERIFY, 'Unsatisfied locktime');
446
                            }
447
448
                            break;
449
450 3423
                        case Opcodes::OP_CHECKSEQUENCEVERIFY:
451 36
                            if (!($flags & self::VERIFY_CHECKSEQUENCEVERIFY)) {
452 18
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
453 3
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
454
                                }
455 15
                                break;
456
                            }
457
458 18
                            if ($mainStack->isEmpty()) {
459 3
                                throw new \RuntimeException('Invalid stack operation - CSV');
460
                            }
461
462 15
                            $sequence = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
463 12
                            $nSequence = $sequence->getGmp();
464 12
                            if ($this->math->cmp($nSequence, gmp_init(0)) < 0) {
465 3
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Negative locktime');
466
                            }
467
468 9
                            if (($nSequence & TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) {
469 3
                                break;
470
                            }
471
472 6
                            if (!$checker->checkSequence($sequence)) {
473 6
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Unsatisfied sequence locks');
474
                            }
475
                            break;
476
477 3402
                        case Opcodes::OP_NOP1:
478 3400
                        case Opcodes::OP_NOP4:
479 3399
                        case Opcodes::OP_NOP5:
480 3398
                        case Opcodes::OP_NOP6:
481 3397
                        case Opcodes::OP_NOP7:
482 3396
                        case Opcodes::OP_NOP8:
483 3395
                        case Opcodes::OP_NOP9:
484 3394
                        case Opcodes::OP_NOP10:
485 84
                            if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
486 33
                                throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
487
                            }
488 51
                            break;
489
490 3369
                        case Opcodes::OP_NOP:
491 258
                            break;
492
493 3294
                        case Opcodes::OP_IF:
494 3204
                        case Opcodes::OP_NOTIF:
495
                            // <expression> if [statements] [else [statements]] endif
496
497 744
                            $value = false;
498 744
                            if ($fExec) {
499 744
                                if ($mainStack->isEmpty()) {
500 9
                                    throw new \RuntimeException('Unbalanced conditional: IF/NOTIF');
501
                                }
502
503 735
                                $value = $this->castToBool($mainStack->pop());
504 735
                                if ($opCode === Opcodes::OP_NOTIF) {
505 51
                                    $value = !$value;
506 34
                                }
507 490
                            }
508
509 735
                            $vfStack->push($value);
510 735
                            break;
511
512
513 3018
                        case Opcodes::OP_ELSE:
514 348
                            if ($vfStack->isEmpty()) {
515 15
                                throw new \RuntimeException('Unbalanced conditional: ELSE');
516
                            }
517
518 339
                            $vfStack->push(!$vfStack->pop());
519 339
                            break;
520
521 3006
                        case Opcodes::OP_ENDIF:
522 444
                            if ($vfStack->isEmpty()) {
523 24
                                throw new \RuntimeException('Unbalanced conditional: ENDIF');
524
                            }
525 429
                            $vfStack->pop();
526 429
                            break;
527
528 2595
                        case Opcodes::OP_VERIFY:
529 102
                            if ($mainStack->isEmpty()) {
530 6
                                throw new \RuntimeException('Invalid stack operation');
531
                            }
532 96
                            $value = $this->castToBool($mainStack[-1]);
533 96
                            if (!$value) {
534 3
                                throw new \RuntimeException('Error: verify');
535
                            }
536 93
                            $mainStack->pop();
537 93
                            break;
538
539 2562
                        case Opcodes::OP_TOALTSTACK:
540 33
                            if ($mainStack->isEmpty()) {
541 6
                                throw new \RuntimeException('Invalid stack operation OP_TOALTSTACK');
542
                            }
543 27
                            $altStack->push($mainStack->pop());
544 27
                            break;
545
546 2553
                        case Opcodes::OP_FROMALTSTACK:
547 21
                            if ($altStack->isEmpty()) {
548 9
                                throw new \RuntimeException('Invalid alt-stack operation OP_FROMALTSTACK');
549
                            }
550 12
                            $mainStack->push($altStack->pop());
551 12
                            break;
552
553 2541
                        case Opcodes::OP_IFDUP:
554
                            // If top value not zero, duplicate it.
555 24
                            if ($mainStack->isEmpty()) {
556 9
                                throw new \RuntimeException('Invalid stack operation OP_IFDUP');
557
                            }
558 15
                            $vch = $mainStack[-1];
559 15
                            if ($this->castToBool($vch)) {
560 12
                                $mainStack->push($vch);
561 8
                            }
562 15
                            break;
563
564 2529
                        case Opcodes::OP_DEPTH:
565 270
                            $num = count($mainStack);
566 270
                            $depth = Number::int($num)->getBuffer();
567 270
                            $mainStack->push($depth);
568 270
                            break;
569
570 2499
                        case Opcodes::OP_DROP:
571 147
                            if ($mainStack->isEmpty()) {
572 9
                                throw new \RuntimeException('Invalid stack operation OP_DROP');
573
                            }
574 138
                            $mainStack->pop();
575 138
                            break;
576
577 2487
                        case Opcodes::OP_DUP:
578 105
                            if ($mainStack->isEmpty()) {
579 9
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
580
                            }
581 96
                            $vch = $mainStack[-1];
582 96
                            $mainStack->push($vch);
583 96
                            break;
584
585 2457
                        case Opcodes::OP_NIP:
586 27
                            if (count($mainStack) < 2) {
587 12
                                throw new \RuntimeException('Invalid stack operation OP_NIP');
588
                            }
589 15
                            unset($mainStack[-2]);
590 15
                            break;
591
592 2436
                        case Opcodes::OP_OVER:
593 27
                            if (count($mainStack) < 2) {
594 12
                                throw new \RuntimeException('Invalid stack operation OP_OVER');
595
                            }
596 15
                            $vch = $mainStack[-2];
597 15
                            $mainStack->push($vch);
598 15
                            break;
599
600 2421
                        case Opcodes::OP_ROT:
601 42
                            if (count($mainStack) < 3) {
602 15
                                throw new \RuntimeException('Invalid stack operation OP_ROT');
603
                            }
604 27
                            $mainStack->swap(-3, -2);
605 27
                            $mainStack->swap(-2, -1);
606 27
                            break;
607
608 2400
                        case Opcodes::OP_SWAP:
609 36
                            if (count($mainStack) < 2) {
610 12
                                throw new \RuntimeException('Invalid stack operation OP_SWAP');
611
                            }
612 24
                            $mainStack->swap(-2, -1);
613 24
                            break;
614
615 2385
                        case Opcodes::OP_TUCK:
616 24
                            if (count($mainStack) < 2) {
617 12
                                throw new \RuntimeException('Invalid stack operation OP_TUCK');
618
                            }
619 12
                            $vch = $mainStack[-1];
620 12
                            $mainStack->add(count($mainStack) - 2, $vch);
621 12
                            break;
622
623 2370
                        case Opcodes::OP_PICK:
624 2359
                        case Opcodes::OP_ROLL:
625 99
                            if (count($mainStack) < 2) {
626 15
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
627
                            }
628
629 84
                            $n = Number::buffer($mainStack[-1], $minimal, 4)->getGmp();
630 78
                            $mainStack->pop();
631 78
                            if ($this->math->cmp($n, gmp_init(0)) < 0 || $this->math->cmp($n, gmp_init(count($mainStack))) >= 0) {
632 18
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
633
                            }
634
635 60
                            $pos = (int) gmp_strval($this->math->sub($this->math->sub(gmp_init(0), $n), gmp_init(1)), 10);
636 60
                            $vch = $mainStack[$pos];
637 60
                            if ($opCode === Opcodes::OP_ROLL) {
638 30
                                unset($mainStack[$pos]);
639 20
                            }
640 60
                            $mainStack->push($vch);
641 60
                            break;
642
643 2313
                        case Opcodes::OP_2DROP:
644 33
                            if (count($mainStack) < 2) {
645 6
                                throw new \RuntimeException('Invalid stack operation OP_2DROP');
646
                            }
647 27
                            $mainStack->pop();
648 27
                            $mainStack->pop();
649 27
                            break;
650
651 2304
                        case Opcodes::OP_2DUP:
652 27
                            if (count($mainStack) < 2) {
653 12
                                throw new \RuntimeException('Invalid stack operation OP_2DUP');
654
                            }
655 15
                            $string1 = $mainStack[-2];
656 15
                            $string2 = $mainStack[-1];
657 15
                            $mainStack->push($string1);
658 15
                            $mainStack->push($string2);
659 15
                            break;
660
661 2289
                        case Opcodes::OP_3DUP:
662 42
                            if (count($mainStack) < 3) {
663 15
                                throw new \RuntimeException('Invalid stack operation OP_3DUP');
664
                            }
665 27
                            $string1 = $mainStack[-3];
666 27
                            $string2 = $mainStack[-2];
667 27
                            $string3 = $mainStack[-1];
668 27
                            $mainStack->push($string1);
669 27
                            $mainStack->push($string2);
670 27
                            $mainStack->push($string3);
671 27
                            break;
672
673 2256
                        case Opcodes::OP_2OVER:
674 24
                            if (count($mainStack) < 4) {
675 12
                                throw new \RuntimeException('Invalid stack operation OP_2OVER');
676
                            }
677 12
                            $string1 = $mainStack[-4];
678 12
                            $string2 = $mainStack[-3];
679 12
                            $mainStack->push($string1);
680 12
                            $mainStack->push($string2);
681 12
                            break;
682
683 2241
                        case Opcodes::OP_2ROT:
684 36
                            if (count($mainStack) < 6) {
685 6
                                throw new \RuntimeException('Invalid stack operation OP_2ROT');
686
                            }
687 30
                            $string1 = $mainStack[-6];
688 30
                            $string2 = $mainStack[-5];
689 30
                            unset($mainStack[-6], $mainStack[-5]);
690 30
                            $mainStack->push($string1);
691 30
                            $mainStack->push($string2);
692 30
                            break;
693
694 2232
                        case Opcodes::OP_2SWAP:
695 21
                            if (count($mainStack) < 4) {
696 12
                                throw new \RuntimeException('Invalid stack operation OP_2SWAP');
697
                            }
698 9
                            $mainStack->swap(-3, -1);
699 9
                            $mainStack->swap(-4, -2);
700 9
                            break;
701
702 2217
                        case Opcodes::OP_SIZE:
703 99
                            if ($mainStack->isEmpty()) {
704 9
                                throw new \RuntimeException('Invalid stack operation OP_SIZE');
705
                            }
706 90
                            $size = Number::int($mainStack[-1]->getSize());
707 90
                            $mainStack->push($size->getBuffer());
708 90
                            break;
709
710 2205
                        case Opcodes::OP_EQUAL:
711 2080
                        case Opcodes::OP_EQUALVERIFY:
712 1059
                            if (count($mainStack) < 2) {
713 15
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
714
                            }
715
716 1044
                            $equal = $mainStack[-2]->equals($mainStack[-1]);
717 1044
                            $mainStack->pop();
718 1044
                            $mainStack->pop();
719 1044
                            $mainStack->push($equal ? $this->vchTrue : $this->vchFalse);
720 1044
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
721 207
                                if ($equal) {
722 174
                                    $mainStack->pop();
723 116
                                } else {
724 36
                                    throw new \RuntimeException('Error EQUALVERIFY');
725
                                }
726 116
                            }
727
728 1014
                            break;
729
730
                        // Arithmetic operations
731 1683
                        case $opCode >= Opcodes::OP_1ADD && $opCode <= Opcodes::OP_0NOTEQUAL:
732 336
                            if ($mainStack->isEmpty()) {
733 21
                                throw new \Exception('Invalid stack operation 1ADD-OP_0NOTEQUAL');
734
                            }
735
736 315
                            $num = Number::buffer($mainStack[-1], $minimal)->getGmp();
737
738 246
                            if ($opCode === Opcodes::OP_1ADD) {
739 24
                                $num = $this->math->add($num, gmp_init(1));
740 238
                            } elseif ($opCode === Opcodes::OP_1SUB) {
741 12
                                $num = $this->math->sub($num, gmp_init(1));
742 218
                            } elseif ($opCode === Opcodes::OP_2MUL) {
743
                                $num = $this->math->mul(gmp_init(2), $num);
744 210
                            } elseif ($opCode === Opcodes::OP_NEGATE) {
745 12
                                $num = $this->math->sub(gmp_init(0), $num);
746 207
                            } elseif ($opCode === Opcodes::OP_ABS) {
747 15
                                if ($this->math->cmp($num, gmp_init(0)) < 0) {
748 9
                                    $num = $this->math->sub(gmp_init(0), $num);
749 4
                                }
750 196
                            } elseif ($opCode === Opcodes::OP_NOT) {
751 162
                                $num = gmp_init($this->math->cmp($num, gmp_init(0)) == 0 ? 1 : 0);
752 108
                            } else {
753
                                // is OP_0NOTEQUAL
754 24
                                $num = gmp_init($this->math->cmp($num, gmp_init(0)) !== 0 ? 1 : 0);
755
                            }
756
757 246
                            $mainStack->pop();
758
759 246
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
760
761 246
                            $mainStack->push($buffer);
762 246
                            break;
763
764 1482
                        case $opCode >= Opcodes::OP_ADD && $opCode <= Opcodes::OP_MAX:
765 567
                            if (count($mainStack) < 2) {
766 51
                                throw new \Exception('Invalid stack operation (OP_ADD - OP_MAX)');
767
                            }
768
769 516
                            $num1 = Number::buffer($mainStack[-2], $minimal)->getGmp();
770 465
                            $num2 = Number::buffer($mainStack[-1], $minimal)->getGmp();
771
772 426
                            if ($opCode === Opcodes::OP_ADD) {
773 93
                                $num = $this->math->add($num1, $num2);
774 401
                            } else if ($opCode === Opcodes::OP_SUB) {
775 21
                                $num = $this->math->sub($num1, $num2);
776 344
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
777 30
                                $num = $this->math->cmp($num1, gmp_init(0)) !== 0 && $this->math->cmp($num2, gmp_init(0)) !== 0;
778 320
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
779 33
                                $num = $this->math->cmp($num1, gmp_init(0)) !== 0 || $this->math->cmp($num2, gmp_init(0)) !== 0;
780 289
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
781 93
                                $num = $this->math->cmp($num1, $num2) === 0;
782 244
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
783 12
                                $num = $this->math->cmp($num1, $num2) === 0;
784 194
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
785 18
                                $num = $this->math->cmp($num1, $num2) !== 0;
786 180
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) {
787 30
                                $num = $this->math->cmp($num1, $num2) < 0;
788 158
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
789 30
                                $num = $this->math->cmp($num1, $num2) > 0;
790 128
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) {
791 30
                                $num = $this->math->cmp($num1, $num2) <= 0;
792 98
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
793 30
                                $num = $this->math->cmp($num1, $num2) >= 0;
794 68
                            } elseif ($opCode === Opcodes::OP_MIN) {
795 24
                                $num = ($this->math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
796 16
                            } else {
797 24
                                $num = ($this->math->cmp($num1, $num2) >= 0) ? $num1 : $num2;
798
                            }
799
800 426
                            $mainStack->pop();
801 426
                            $mainStack->pop();
802 426
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
803 426
                            $mainStack->push($buffer);
804
805 426
                            if ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
806 12
                                if ($this->castToBool($mainStack[-1])) {
807 12
                                    $mainStack->pop();
808 8
                                } else {
809
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
810
                                }
811 8
                            }
812 426
                            break;
813
814 915
                        case Opcodes::OP_WITHIN:
815 51
                            if (count($mainStack) < 3) {
816 6
                                throw new \RuntimeException('Invalid stack operation');
817
                            }
818
819 45
                            $num1 = Number::buffer($mainStack[-3], $minimal)->getGmp();
820 42
                            $num2 = Number::buffer($mainStack[-2], $minimal)->getGmp();
821 39
                            $num3 = Number::buffer($mainStack[-1], $minimal)->getGmp();
822
823 36
                            $value = $this->math->cmp($num2, $num1) <= 0 && $this->math->cmp($num1, $num3) < 0;
824 36
                            $mainStack->pop();
825 36
                            $mainStack->pop();
826 36
                            $mainStack->pop();
827 36
                            $mainStack->push($value ? $this->vchTrue : $this->vchFalse);
828 36
                            break;
829
830
                        // Hash operation
831 864
                        case Opcodes::OP_RIPEMD160:
832 856
                        case Opcodes::OP_SHA1:
833 847
                        case Opcodes::OP_SHA256:
834 840
                        case Opcodes::OP_HASH160:
835 816
                        case Opcodes::OP_HASH256:
836 252
                            if ($mainStack->isEmpty()) {
837 36
                                throw new \RuntimeException('Invalid stack operation');
838
                            }
839
840 216
                            $buffer = $mainStack[-1];
841 216
                            if ($opCode === Opcodes::OP_RIPEMD160) {
842 18
                                $hash = Hash::ripemd160($buffer);
843 211
                            } elseif ($opCode === Opcodes::OP_SHA1) {
844 21
                                $hash = Hash::sha1($buffer);
845 194
                            } elseif ($opCode === Opcodes::OP_SHA256) {
846 21
                                $hash = Hash::sha256($buffer);
847 175
                            } elseif ($opCode === Opcodes::OP_HASH160) {
848 147
                                $hash = Hash::sha256ripe160($buffer);
849 98
                            } else {
850 18
                                $hash = Hash::sha256d($buffer);
851
                            }
852
853 216
                            $mainStack->pop();
854 216
                            $mainStack->push($hash);
855 216
                            break;
856
857 696
                        case Opcodes::OP_CODESEPARATOR:
858 3
                            $hashStartPos = $parser->getPosition();
859 3
                            break;
860
861 693
                        case Opcodes::OP_CHECKSIG:
862 603
                        case Opcodes::OP_CHECKSIGVERIFY:
863 270
                            if (count($mainStack) < 2) {
864 9
                                throw new \RuntimeException('Invalid stack operation');
865
                            }
866
867 261
                            $vchPubKey = $mainStack[-1];
868 261
                            $vchSig = $mainStack[-2];
869
870 261
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
871
872 261
                            $success = $checker->checkSig($scriptCode, $vchSig, $vchPubKey, $sigVersion, $flags);
873
874 186
                            $mainStack->pop();
875 186
                            $mainStack->pop();
876 186
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
877
878 186
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
879
                                if ($success) {
880
                                    $mainStack->pop();
881
                                } else {
882
                                    throw new \RuntimeException('Checksig verify');
883
                                }
884
                            }
885 186
                            break;
886
887 423
                        case Opcodes::OP_CHECKMULTISIG:
888 346
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
889 327
                            $i = 1;
890 327
                            if (count($mainStack) < $i) {
891 3
                                throw new \RuntimeException('Invalid stack operation');
892
                            }
893
894 324
                            $keyCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
895 318
                            if ($keyCount < 0 || $keyCount > 20) {
896 6
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
897
                            }
898
899 312
                            $opCount += $keyCount;
900 312
                            $this->checkOpcodeCount($opCount);
901
902
                            // Extract positions of the keys, and signatures, from the stack.
903 312
                            $ikey = ++$i;
904 312
                            $i += $keyCount; /** @var int $i */
905 312
                            if (count($mainStack) < $i) {
906 3
                                throw new \RuntimeException('Invalid stack operation');
907
                            }
908
909 309
                            $sigCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
910 300
                            if ($sigCount < 0 || $sigCount > $keyCount) {
911 6
                                throw new \RuntimeException('Invalid Signature count');
912
                            }
913
914 294
                            $isig = ++$i;
915 294
                            $i += $sigCount;
916
917
                            // Extract the script since the last OP_CODESEPARATOR
918 294
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
919
920 294
                            $fSuccess = true;
921 294
                            while ($fSuccess && $sigCount > 0) {
922
                                // Fetch the signature and public key
923 114
                                $sig = $mainStack[-$isig];
924 111
                                $pubkey = $mainStack[-$ikey];
925
926 111
                                if ($checker->checkSig($scriptCode, $sig, $pubkey, $sigVersion, $flags)) {
927 55
                                    $isig++;
928 55
                                    $sigCount--;
929 36
                                }
930
931 93
                                $ikey++;
932 93
                                $keyCount--;
933
934
                                // If there are more signatures left than keys left,
935
                                // then too many signatures have failed. Exit early,
936
                                // without checking any further signatures.
937 93
                                if ($sigCount > $keyCount) {
938 44
                                    $fSuccess = false;
939 30
                                }
940 62
                            }
941
942 267
                            while ($i-- > 1) {
943 267
                                $mainStack->pop();
944 178
                            }
945
946
                            // A bug causes CHECKMULTISIG to consume one extra argument
947
                            // whose contents were not checked in any way.
948
                            //
949
                            // Unfortunately this is a potential source of mutability,
950
                            // so optionally verify it is exactly equal to zero prior
951
                            // to removing it from the stack.
952 267
                            if ($mainStack->isEmpty()) {
953 3
                                throw new \RuntimeException('Invalid stack operation');
954
                            }
955
956 267
                            if ($flags & self::VERIFY_NULL_DUMMY && $mainStack[-1]->getSize() !== 0) {
957 6
                                throw new ScriptRuntimeException(self::VERIFY_NULL_DUMMY, 'Extra P2SH stack value should be OP_0');
958
                            }
959
960 261
                            $mainStack->pop();
961 261
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
962
963 261
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
964 90
                                if ($fSuccess) {
965 90
                                    $mainStack->pop();
966 60
                                } else {
967
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
968
                                }
969 60
                            }
970 261
                            break;
971
972 64
                        default:
973 96
                            throw new \RuntimeException('Opcode not found');
974 64
                    }
975
976 3087
                    if (count($mainStack) + count($altStack) > 1000) {
977 1153
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
978
                    }
979 2058
                }
980 2374
            }
981
982 3498
            if (count($vfStack) !== 0) {
983 18
                throw new \RuntimeException('Unbalanced conditional at script end');
984
            }
985
986 3483
            return true;
987 1323
        } catch (ScriptRuntimeException $e) {
988 219
             echo "\n Runtime: " . $e->getMessage() . "\n";
989
            // Failure due to script tags, can access flag: $e->getFailureFlag()
990 219
            return false;
991 1104
        } catch (\Exception $e) {
992 1104
             echo "\n General: " . $e->getMessage()  . PHP_EOL . $e->getTraceAsString();
993 1104
            return false;
994
        }
995
    }
996
}
997