Completed
Push — master ( 838d3a...3b658f )
by thomas
22:41 queued 01:10
created

Interpreter::checkMinimalPush()   C

Complexity

Conditions 9
Paths 8

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 27.4851

Importance

Changes 4
Bugs 3 Features 0
Metric Value
c 4
b 3
f 0
dl 0
loc 24
ccs 7
cts 18
cp 0.3889
rs 5.3563
cc 9
eloc 18
nc 8
nop 2
crap 27.4851
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\Script\Classifier\OutputClassifier;
13
use BitWasp\Bitcoin\Script\Opcodes;
14
use BitWasp\Bitcoin\Script\Script;
15
use BitWasp\Bitcoin\Script\ScriptInterface;
16
use BitWasp\Bitcoin\Signature\TransactionSignature;
17
use BitWasp\Bitcoin\Signature\TransactionSignatureFactory;
18
use BitWasp\Bitcoin\Transaction\SignatureHash\SignatureHashInterface;
19
use BitWasp\Bitcoin\Transaction\TransactionInterface;
20
use BitWasp\Buffertools\Buffer;
21
22
class Interpreter implements InterpreterInterface
23
{
24
    /**
25
     * @var int|string
26
     */
27
    private $inputToSign;
28
29
    /**
30
     * @var ScriptInterface
31
     */
32
    private $script;
33
34
    /**
35
     * @var TransactionInterface
36
     */
37
    private $transaction;
38
39
    /**
40
     * Position of OP_CODESEPARATOR, for calculating SigHash
41
     * @var int
42
     */
43
    private $hashStartPos;
44
45
    /**
46
     * @var int
47
     */
48
    private $opCount;
49
50
    /**
51
     * @var \BitWasp\Bitcoin\Flags
52
     */
53
    private $flags;
54
55
    /**
56
     * @var EcAdapterInterface
57
     */
58
    private $ecAdapter;
59
60
    /**
61
     * @var \BitWasp\Bitcoin\Math\Math
62
     */
63
    private $math;
64
65
    /**
66
     * @var State
67
     */
68
    private $state;
69
70
    /**
71
     * @var array
72
     */
73
    private $disabledOps = [
74
        Opcodes::OP_CAT,    Opcodes::OP_SUBSTR, Opcodes::OP_LEFT,  Opcodes::OP_RIGHT,
75
        Opcodes::OP_INVERT, Opcodes::OP_AND,    Opcodes::OP_OR,    Opcodes::OP_XOR,
76
        Opcodes::OP_2MUL,   Opcodes::OP_2DIV,   Opcodes::OP_MUL,   Opcodes::OP_DIV,
77
        Opcodes::OP_MOD,    Opcodes::OP_LSHIFT, Opcodes::OP_RSHIFT
78
    ];
79
80
    public $checkDisabledOpcodes = true;
81
82
    /**
83
     * @param EcAdapterInterface $ecAdapter
84
     * @param TransactionInterface $transaction
85
     * @param \BitWasp\Bitcoin\Flags $flags
86
     */
87 774
    public function __construct(EcAdapterInterface $ecAdapter, TransactionInterface $transaction, Flags $flags)
88
    {
89 774
        $this->ecAdapter = $ecAdapter;
90 774
        $this->math = $ecAdapter->getMath();
91 774
        $this->transaction = $transaction;
92 774
        $this->flags = $flags;
93 774
        $this->script = new Script();
94 774
        $this->state = new State();
95 774
        $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...
96 774
        $this->vchTrue = Buffer::hex("01", 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...
97 774
        $this->int0 = new ScriptNum($this->math, new Flags(0), $this->vchFalse, 4);
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...
98 774
        $this->int1 = new ScriptNum($this->math, new Flags(0), $this->vchTrue, 1);
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...
99 774
    }
100
101
    /**
102
     * @return State
103
     */
104 6
    public function getStackState()
105
    {
106 6
        return $this->state;
107
    }
108
109
    /**
110
     * @param ScriptInterface $script
111
     * @return $this
112
     */
113 684
    public function setScript(ScriptInterface $script)
114
    {
115 684
        $this->script = $script;
116 684
        return $this;
117
    }
118
119
    /**
120
     * @return array
121
     */
122
    public function getDisabledOps()
123
    {
124
        return $this->disabledOps;
125
    }
126
127
    /**
128
     * @param int $op
129
     * @return bool
130
     */
131 684
    public function isDisabledOp($op)
132
    {
133 684
        return in_array($op, $this->disabledOps, true);
134
    }
135
136
    /**
137
     * Cast the value to a boolean
138
     *
139
     * @param $value
140
     * @return bool
141
     */
142 432
    public function castToBool(Buffer $value)
143
    {
144 432
        if ($value->getSize() === 0) {
145 66
            return true;
146
        }
147
148
        // Since we're using buffers, lets try ensuring the contents are not 0.
149 366
        return $this->math->cmp($value->getInt(), 0) > 0; // cscriptNum or edge case.
150
    }
151
152
    /**
153
     * @param Buffer $signature
154
     * @return bool
155
     */
156 54
    public function isValidSignatureEncoding(Buffer $signature)
157
    {
158
        try {
159 54
            TransactionSignature::isDERSignature($signature);
160 36
            return true;
161 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...
162
            /* In any case, we will return false outside this block */
163
        }
164
165 18
        return false;
166
    }
167
168
    /**
169
     * @param Buffer $signature
170
     * @return bool
171
     * @throws ScriptRuntimeException
172
     * @throws \Exception
173
     */
174 30
    public function isLowDerSignature(Buffer $signature)
175
    {
176 30
        if (!$this->isValidSignatureEncoding($signature)) {
177 6
            throw new ScriptRuntimeException(InterpreterInterface::VERIFY_DERSIG, 'Signature with incorrect encoding');
178
        }
179
180 24
        $binary = $signature->getBinary();
181 24
        $nLenR = ord($binary[3]);
182 24
        $nLenS = ord($binary[5 + $nLenR]);
183 24
        $s = $signature->slice(6 + $nLenR, $nLenS)->getInt();
184
185 24
        return $this->ecAdapter->validateSignatureElement($s, true);
186
    }
187
188
    /**
189
     * Determine whether the sighash byte appended to the signature encodes
190
     * a valid sighash type.
191
     *
192
     * @param Buffer $signature
193
     * @return bool
194
     */
195 36
    public function isDefinedHashtypeSignature(Buffer $signature)
196
    {
197 36
        if ($signature->getSize() === 0) {
198 6
            return false;
199
        }
200
201 30
        $binary = $signature->getBinary();
202 30
        $nHashType = ord(substr($binary, -1)) & (~(SignatureHashInterface::SIGHASH_ANYONECANPAY));
203
204 30
        $math = $this->math;
205 30
        return ! ($math->cmp($nHashType, SignatureHashInterface::SIGHASH_ALL) < 0 || $math->cmp($nHashType, SignatureHashInterface::SIGHASH_SINGLE) > 0);
206
    }
207
208
    /**
209
     * @param Buffer $signature
210
     * @return $this
211
     * @throws \BitWasp\Bitcoin\Exceptions\ScriptRuntimeException
212
     */
213 60
    public function checkSignatureEncoding(Buffer $signature)
214
    {
215 60
        if ($signature->getSize() === 0) {
216 6
            return $this;
217
        }
218
219 54
        if ($this->flags->checkFlags(InterpreterInterface::VERIFY_DERSIG | InterpreterInterface::VERIFY_LOW_S | InterpreterInterface::VERIFY_STRICTENC) && !$this->isValidSignatureEncoding($signature)) {
220 12
            throw new ScriptRuntimeException(InterpreterInterface::VERIFY_DERSIG, 'Signature with incorrect encoding');
221 42
        } else if ($this->flags->checkFlags(InterpreterInterface::VERIFY_LOW_S) && !$this->isLowDerSignature($signature)) {
222 6
            throw new ScriptRuntimeException(InterpreterInterface::VERIFY_LOW_S, 'Signature s element was not low');
223 36
        } else if ($this->flags->checkFlags(InterpreterInterface::VERIFY_STRICTENC) && !$this->isDefinedHashtypeSignature($signature)) {
224 6
            throw new ScriptRuntimeException(InterpreterInterface::VERIFY_STRICTENC, 'Signature with invalid hashtype');
225
        }
226
227 30
        return $this;
228
    }
229
230
    /**
231
     * @param Buffer $publicKey
232
     * @return $this
233
     * @throws \Exception
234
     */
235 24
    public function checkPublicKeyEncoding(Buffer $publicKey)
236
    {
237 24
        if ($this->flags->checkFlags(InterpreterInterface::VERIFY_STRICTENC) && !PublicKey::isCompressedOrUncompressed($publicKey)) {
238 6
            throw new ScriptRuntimeException(InterpreterInterface::VERIFY_STRICTENC, 'Public key with incorrect encoding');
239
        }
240
241 18
        return $this;
242
    }
243
244
    /**
245
     * @param $opCode
246
     * @param Buffer $pushData
247
     * @return bool
248
     * @throws \Exception
249
     */
250 6
    public function checkMinimalPush($opCode, Buffer $pushData)
251
    {
252 6
        $pushSize = $pushData->getSize();
253 6
        $binary = $pushData->getBinary();
254
255 6
        if ($pushSize === 0) {
256
            return $opCode === Opcodes::OP_0;
257 6
        } elseif ($pushSize === 1) {
258
            $first = ord($binary[0]);
259
            if ($first >= 1 && $first <= 16) {
260
                return $opCode === (Opcodes::OP_1 + ($first - 1));
261
            } elseif ($first === 0x81) {
262
                return $opCode === Opcodes::OP_1NEGATE;
263
            }
264 6
        } elseif ($pushSize <= 75) {
265 6
            return $opCode === $pushSize;
266
        } elseif ($pushSize <= 255) {
267
            return $opCode === Opcodes::OP_PUSHDATA1;
268
        } elseif ($pushSize <= 65535) {
269
            return $opCode === Opcodes::OP_PUSHDATA2;
270
        }
271
272
        return true;
273
    }
274
275
    /**
276
     * @return $this
277
     * @throws \Exception
278
     */
279 672
    private function checkOpcodeCount()
280
    {
281 672
        if ($this->math->cmp($this->opCount, 201) > 0) {
282 6
            throw new \RuntimeException('Error: Script op code count');
283
        }
284
285 672
        return $this;
286
    }
287
288
    /**
289
     * @param ScriptInterface $script
290
     * @param Buffer $sigBuf
291
     * @param Buffer $keyBuf
292
     * @return bool
293
     * @throws ScriptRuntimeException
294
     * @throws \Exception
295
     */
296 18
    private function checkSig(ScriptInterface $script, Buffer $sigBuf, Buffer $keyBuf)
297
    {
298 18
        $this
299 18
            ->checkSignatureEncoding($sigBuf)
300 12
            ->checkPublicKeyEncoding($keyBuf);
301
302
        try {
303 12
            $txSignature = TransactionSignatureFactory::fromHex($sigBuf->getHex());
304 12
            $publicKey = PublicKeyFactory::fromHex($keyBuf->getHex());
305
306 12
            return $this->ecAdapter->verify(
307 12
                $this
308
                    ->transaction
309 12
                    ->getSignatureHash()
310 12
                    ->calculate($script, $this->inputToSign, $txSignature->getHashType()),
311 12
                $publicKey,
312 12
                $txSignature->getSignature()
313 12
            );
314
        } catch (\Exception $e) {
315
            return false;
316
        }
317
    }
318
319
    /**
320
     * @param ScriptInterface $scriptSig
321
     * @param ScriptInterface $scriptPubKey
322
     * @param int $nInputToSign
323
     * @return bool
324
     * @throws \Exception
325
     */
326 684
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $nInputToSign)
327
    {
328 684
        $this->inputToSign = $nInputToSign;
329 684
        if (!$this->setScript($scriptSig)->run()) {
330
            return false;
331
        }
332
333 684
        $mainStack = $this->state->getMainStack();
334 684
        $stackCopy = new Stack;
335 684
        if ($this->flags->checkFlags(InterpreterInterface::VERIFY_P2SH)) {
336 156
            $stackCopy = $this->state->cloneMainStack();
337 156
        }
338
339 684
        if (!$this->setScript($scriptPubKey)->run()) {
340 258
            return false;
341
        }
342
343 426
        if ($mainStack->isEmpty()) {
344
            return false;
345
        }
346
347 426
        if (false === $this->castToBool($mainStack[-1])) {
348
            return false;
349
        }
350
351 426
        $verifier = new OutputClassifier($scriptPubKey);
352
353 426
        if ($this->flags->checkFlags(InterpreterInterface::VERIFY_P2SH) && $verifier->isPayToScriptHash()) {
354 6
            if (!$scriptSig->isPushOnly()) {
355
                return false;
356
            }
357
358
            // Restore mainStack to how it was after evaluating scriptSig
359 6
            $mainStack = $this->state->restoreMainStack($stackCopy)->getMainStack();
360 6
            if ($mainStack->isEmpty()) {
361
                return false;
362
            }
363
364
            // Load redeemscript as the scriptPubKey
365 6
            $scriptPubKey = new Script($mainStack->bottom());
366 6
            $mainStack->pop();
367
368 6
            if (!$this->setScript($scriptPubKey)->run()) {
369
                return false;
370
            }
371 6
        }
372
373 426
        return true;
374
    }
375
376
    /**
377
     * @return bool
378
     */
379 684
    private function checkExec()
380
    {
381 684
        $vfStack = $this->state->getVfStack();
382 684
        $c = 0;
383 684
        $len = $vfStack->end();
384 684
        for ($i = 0; $i < $len; $i++) {
385
            if ($vfStack[0 - $len - $i] === true) {
386
                $c++;
387
            }
388
        }
389 684
        return !(bool)$c;
390
    }
391
392
    /**
393
     * @return bool
394
     */
395 684
    public function run()
396
    {
397 684
        $math = $this->math;
398
399 684
        $flags = $this->flags;
400 684
        $mainStack = $this->state->getMainStack();
401 684
        $altStack = $this->state->getAltStack();
402 684
        $vfStack = $this->state->getVfStack();
403
404 684
        $this->hashStartPos = 0;
405 684
        $this->opCount = 0;
406 684
        $parser = $this->script->getScriptParser();
407
        
408
409 684
        if ($this->script->getBuffer()->getSize() > 10000) {
410
            return false;
411
        }
412
413
        try {
414 684
            foreach ($parser as $exec) {
415 684
                $opCode = $exec->getOp();
416 684
                $pushData = $exec->getData();
417 684
                $fExec = $this->checkExec();
418
419
                // If pushdata was written to,
420 684
                if ($pushData instanceof Buffer && $pushData->getSize() > InterpreterInterface::MAX_SCRIPT_ELEMENT_SIZE) {
421
                    throw new \RuntimeException('Error - push size');
422
                }
423
424
                // OP_RESERVED should not count towards opCount
425 684
                if ($opCode > Opcodes::OP_16 && ++$this->opCount) {
426 672
                    $this->checkOpcodeCount();
427 672
                }
428
429 684
                if ($this->checkDisabledOpcodes && $this->isDisabledOp($opCode)) {
430 12
                    throw new \RuntimeException('Disabled Opcode');
431
                }
432
433 684
                if ($fExec && $opCode >= 0 && $opCode <= Opcodes::OP_PUSHDATA4) {
434
                    // In range of a pushdata opcode
435 426
                    if ($flags->checkFlags(InterpreterInterface::VERIFY_MINIMALDATA) && !$this->checkMinimalPush($opCode, $pushData)) {
0 ignored issues
show
Bug introduced by
It seems like $pushData defined by $exec->getData() on line 416 can be null; however, BitWasp\Bitcoin\Script\I...ter::checkMinimalPush() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
436 6
                        throw new ScriptRuntimeException(InterpreterInterface::VERIFY_MINIMALDATA, 'Minimal pushdata required');
437
                    }
438
439 420
                    $mainStack->push($pushData);
440
                    // echo " - [pushed '" . $pushData->getHex() . "']\n";
441 678
                } elseif ($fExec || ($opCode !== Opcodes::OP_IF && $opCode !== Opcodes::OP_ENDIF)) {
442
                    // echo "OPCODE - " . $this->script->getOpCodes()->getOp($opCode) . "\n";
443
                    switch ($opCode) {
444 660
                        case Opcodes::OP_1:
445 660
                        case Opcodes::OP_2:
446 660
                        case Opcodes::OP_3:
447 660
                        case Opcodes::OP_4:
448 660
                        case Opcodes::OP_5:
449 660
                        case Opcodes::OP_6:
450 660
                        case Opcodes::OP_7:
451 660
                        case Opcodes::OP_8:
452 660
                        case Opcodes::OP_9:
453 660
                        case Opcodes::OP_10:
454 660
                        case Opcodes::OP_11:
455 660
                        case Opcodes::OP_12:
456 660
                        case Opcodes::OP_13:
457 660
                        case Opcodes::OP_14:
458 660
                        case Opcodes::OP_15:
459 660
                        case Opcodes::OP_16:
460 186
                            $num = $opCode - (Opcodes::OP_1 - 1);
461 186
                            $mainStack->push(new ScriptNum($math, new Flags(0), new Buffer(chr($num), 4), 4));
462 186
                            break;
463
464 660
                        case $opCode >= Opcodes::OP_NOP1 && $opCode <= Opcodes::OP_NOP10:
465 6
                            if ($flags->checkFlags(InterpreterInterface::VERIFY_DISCOURAGE_UPGRADABLE_NOPS)) {
466 6
                                throw new ScriptRuntimeException(InterpreterInterface::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOPS found - this is discouraged');
467
                            }
468
                            break;
469
470 654
                        case Opcodes::OP_NOP:
471 12
                            break;
472
473 642
                        case Opcodes::OP_IF:
474 642
                        case Opcodes::OP_NOTIF:
475
                            // <expression> if [statements] [else [statements]] endif
476 18
                            $value = false;
477 18
                            if ($fExec) {
478 18
                                if ($mainStack->isEmpty()) {
479 6
                                    throw new \RuntimeException('Unbalanced conditional');
480
                                }
481
                                // todo
482 12
                                $buffer = new ScriptNum($math, $this->flags, $mainStack->pop(), 4);
483 12
                                $value = $this->castToBool($buffer);
484 12
                                if ($opCode === Opcodes::OP_NOTIF) {
485 6
                                    $value = !$value;
486 6
                                }
487 12
                            }
488 12
                            $vfStack->push($value ? $this->vchTrue : $this->vchFalse);
489 12
                            break;
490
491 636
                        case Opcodes::OP_ELSE:
492 18
                            if ($vfStack->isEmpty()) {
493 6
                                throw new \RuntimeException('Unbalanced conditional');
494
                            }
495 12
                            $vfStack[-1] = !$vfStack->end() ? $this->vchTrue : $this->vchFalse;
496 12
                            break;
497
498 630
                        case Opcodes::OP_ENDIF:
499 18
                            if ($vfStack->isEmpty()) {
500 6
                                throw new \RuntimeException('Unbalanced conditional');
501
                            }
502 12
                            break;
503
504 624
                        case Opcodes::OP_VERIFY:
505 24
                            if ($mainStack->isEmpty()) {
506 6
                                throw new \RuntimeException('Invalid stack operation');
507
                            }
508 18
                            $value = $this->castToBool($mainStack[-1]);
509 18
                            if (!$value) {
510 6
                                throw new \RuntimeException('Error: verify');
511
                            }
512 12
                            $mainStack->pop();
513 12
                            break;
514
515 600
                        case Opcodes::OP_RESERVED:
516
                            // todo
517 12
                            break;
518
519 588
                        case Opcodes::OP_TOALTSTACK:
520 18
                            if ($mainStack->isEmpty()) {
521 6
                                throw new \RuntimeException('Invalid stack operation OP_TOALTSTACK');
522
                            }
523 12
                            $altStack->push($mainStack->pop());
524 12
                            break;
525
526 582
                        case Opcodes::OP_FROMALTSTACK:
527 12
                            if ($altStack->isEmpty()) {
528 6
                                throw new \RuntimeException('Invalid alt-stack operation OP_FROMALTSTACK');
529
                            }
530 6
                            $mainStack->push($altStack->pop());
531 6
                            break;
532
533 576
                        case Opcodes::OP_IFDUP:
534
                            // If top value not zero, duplicate it.
535 12
                            if ($mainStack->isEmpty()) {
536 6
                                throw new \RuntimeException('Invalid stack operation OP_IFDUP');
537
                            }
538 6
                            $vch = $mainStack[-1];
539 6
                            if ($this->castToBool($vch)) {
540 6
                                $mainStack->push($vch);
541 6
                            }
542 6
                            break;
543
544 570
                        case Opcodes::OP_DEPTH:
545 72
                            $num = count($mainStack);
546 72
                            if ($num === 0) {
547 24
                                $depth = $this->vchFalse;
548 24
                            } else {
549 54
                                $depth = (new ScriptNum($math, $this->flags, Buffer::int($num), 4));
550
                            }
551
552 72
                            $mainStack->push($depth);
553 72
                            break;
554
555 570
                        case Opcodes::OP_DROP:
556 6
                            if ($mainStack->isEmpty()) {
557 6
                                throw new \RuntimeException('Invalid stack operation OP_DROP');
558
                            }
559
                            $mainStack->pop();
560
                            break;
561 564
                        case Opcodes::OP_DUP:
562 18
                            if ($mainStack->isEmpty()) {
563 6
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
564
                            }
565 12
                            $vch = $mainStack[-1];
566 12
                            $mainStack->push($vch);
567 12
                            break;
568
569 558
                        case Opcodes::OP_NIP:
570 18
                            if (count($mainStack) < 2) {
571 6
                                throw new \RuntimeException('Invalid stack operation OP_NIP');
572
                            }
573 12
                            unset($mainStack[-2]);
574 12
                            break;
575
576 552
                        case Opcodes::OP_OVER:
577 18
                            if (count($mainStack) < 2) {
578 6
                                throw new \RuntimeException('Invalid stack operation OP_OVER');
579
                            }
580 12
                            $vch = $mainStack[-2];
581 12
                            $mainStack->push($vch);
582 12
                            break;
583
    
584 546
                        case Opcodes::OP_ROT:
585 12
                            if (count($mainStack) < 3) {
586 6
                                throw new \RuntimeException('Invalid stack operation OP_ROT');
587
                            }
588 6
                            $mainStack->swap(-3, -2);
589 6
                            $mainStack->swap(-2, -1);
590 6
                            break;
591
592 540
                        case Opcodes::OP_SWAP:
593 12
                            if (count($mainStack) < 2) {
594 6
                                throw new \RuntimeException('Invalid stack operation OP_SWAP');
595
                            }
596 6
                            $mainStack->swap(-2, -1);
597 6
                            break;
598
599 534
                        case Opcodes::OP_TUCK:
600 12
                            if (count($mainStack) < 2) {
601 6
                                throw new \RuntimeException('Invalid stack operation OP_TUCK');
602
                            }
603 6
                            $vch = $mainStack[-1];
604 6
                            $mainStack->add(count($mainStack) - 1 - 2, $vch);
605
                            break;
606
607 522
                        case Opcodes::OP_PICK:
608 522
                        case Opcodes::OP_ROLL:
609 24
                            if (count($mainStack) < 2) {
610 6
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
611
                            }
612
613 18
                            $n = (new ScriptNum($math, $this->flags, $mainStack[-1], 4))->getInt();
614 18
                            $mainStack->pop();
615 18
                            if ($math->cmp($n, 0) < 0 || $math->cmp($n, count($mainStack)) >= 0) {
616 6
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
617
                            }
618
619 12
                            $pos = (int) $math->sub($math->sub(0, $n), 1);
620 12
                            $vch = $mainStack[$pos];
621 12
                            if ($opCode === Opcodes::OP_ROLL) {
622 6
                                unset($mainStack[$pos]);
623 6
                            }
624 12
                            $mainStack->push($vch);
625 12
                            break;
626
627 510
                        case Opcodes::OP_2DROP:
628 12
                            if (count($mainStack) < 2) {
629 6
                                throw new \RuntimeException('Invalid stack operation OP_2DROP');
630
                            }
631 6
                            $mainStack->pop();
632 6
                            $mainStack->pop();
633 6
                            break;
634
635 504
                        case Opcodes::OP_2DUP:
636 18
                            if (count($mainStack) < 2) {
637 6
                                throw new \RuntimeException('Invalid stack operation OP_2DUP');
638
                            }
639 12
                            $string1 = $mainStack[-2];
640 12
                            $string2 = $mainStack[-1];
641 12
                            $mainStack->push($string1);
642 12
                            $mainStack->push($string2);
643 12
                            break;
644
645 498
                        case Opcodes::OP_3DUP:
646 18
                            if (count($mainStack) < 3) {
647 6
                                throw new \RuntimeException('Invalid stack operation OP_3DUP');
648
                            }
649 12
                            $string1 = $mainStack[-3];
650 12
                            $string2 = $mainStack[-2];
651 12
                            $string3 = $mainStack[-1];
652 12
                            $mainStack->push($string1);
653 12
                            $mainStack->push($string2);
654 12
                            $mainStack->push($string3);
655 12
                            break;
656
657 492
                        case Opcodes::OP_2OVER:
658 18
                            if (count($mainStack) < 4) {
659 6
                                throw new \RuntimeException('Invalid stack operation OP_2OVER');
660
                            }
661 12
                            $string1 = $mainStack[-4];
662 12
                            $string2 = $mainStack[-3];
663 12
                            $mainStack->push($string1);
664 12
                            $mainStack->push($string2);
665 12
                            break;
666
667 486
                        case Opcodes::OP_2ROT:
668 12
                            if (count($mainStack) < 6) {
669 6
                                throw new \RuntimeException('Invalid stack operation OP_2ROT');
670
                            }
671 6
                            $string1 = $mainStack[-6];
672 6
                            $string2 = $mainStack[-5];
673 6
                            unset($mainStack[-6], $mainStack[-5]);
674 6
                            $mainStack->push($string1);
675 6
                            $mainStack->push($string2);
676 6
                            break;
677
678 480
                        case Opcodes::OP_2SWAP:
679 12
                            if (count($mainStack) < 4) {
680 6
                                throw new \RuntimeException('Invalid stack operation OP_2SWAP');
681
                            }
682 6
                            $mainStack->swap(-3, -1);
683 6
                            $mainStack->swap(-4, -2);
684 6
                            break;
685
686 474
                        case Opcodes::OP_SIZE:
687 12
                            if ($mainStack->isEmpty()) {
688 6
                                throw new \RuntimeException('Invalid stack operation OP_SIZE');
689
                            }
690
                            // todo: Int sizes?
691 6
                            $vch = $mainStack[-1];
692 6
                            $size = Buffer::int($vch->getSize(), null, $math);
693
694 6
                            $mainStack->push($size);
695 6
                            break;
696
697 468
                        case Opcodes::OP_EQUAL:
698 468
                        case Opcodes::OP_EQUALVERIFY:
699 396
                            if (count($mainStack) < 2) {
700 6
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
701
                            }
702 390
                            $vch1 = $mainStack[-2];
703 390
                            $vch2 = $mainStack[-1];
704
705 390
                            $equal = ($vch1->getBinary() === $vch2->getBinary());
706
707 390
                            $mainStack->pop();
708 390
                            $mainStack->pop();
709 390
                            $mainStack->push(($equal ? $this->vchTrue : $this->vchFalse));
710 390
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
711 114
                                if ($equal) {
712 102
                                    $mainStack->pop();
713 102
                                } else {
714 12
                                    throw new \RuntimeException('Error EQUALVERIFY');
715
                                }
716 102
                            }
717
718 378
                            break;
719
720
                        // Arithmetic operations
721 282
                        case $opCode >= Opcodes::OP_1ADD && $opCode <= Opcodes::OP_0NOTEQUAL:
722 48
                            if ($mainStack->isEmpty()) {
723 6
                                throw new \Exception('Invalid stack operation 1ADD-OP_0NOTEQUAL');
724
                            }
725
726 42
                            $num = (new ScriptNum($math, $this->flags, $mainStack[-1], 4))->getInt();
727
728 42
                            if ($opCode === Opcodes::OP_1ADD) { // cscriptnum
729 6
                                $num = $math->add($num, '1');
730 42
                            } elseif ($opCode === Opcodes::OP_1SUB) {
731 6
                                $num = $math->sub($num, '1');
732 36
                            } elseif ($opCode === Opcodes::OP_2MUL) {
733
                                $num = $math->mul(2, $num);
734 30
                            } elseif ($opCode === Opcodes::OP_NEGATE) {
735
                                $num = $math->sub(0, $num);
736 30
                            } elseif ($opCode === Opcodes::OP_ABS) {
737
                                if ($math->cmp($num, '0') < 0) {
738
                                    $num = $math->sub(0, $num);
739
                                }
740 30
                            } elseif ($opCode === Opcodes::OP_NOT) {
741 18
                                $num = ($math->cmp($num, '0') === 0);
742 18
                            } else {
743
                                // is OP_0NOTEQUAL
744 12
                                $num = ($math->cmp($num, '0') !== 0);
745
                            }
746
747 42
                            $mainStack->pop();
748
749 42
                            $buffer = Buffer::int($num, 4, $math);
750 42
                            $mainStack->push($buffer);
751 42
                            break;
752
753 234
                        case $opCode >= Opcodes::OP_ADD && $opCode <= Opcodes::OP_MAX:
754 150
                            if (count($mainStack) < 2) {
755 24
                                throw new \Exception('Invalid stack operation (OP_ADD - OP_MAX)');
756
                            }
757
758 126
                            $num1 = (new ScriptNum($math, $this->flags, $mainStack[-2], 4))->getInt();
759 126
                            $num2 = (new ScriptNum($math, $this->flags, $mainStack[-1], 4))->getInt();
760
761 126
                            if ($opCode === Opcodes::OP_ADD) {
762 6
                                $num = $math->add($num1, $num2);
763 126
                            } else if ($opCode === Opcodes::OP_SUB) {
764 6
                                $num = $math->sub($num1, $num2);
765 120
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
766 12
                                $num = $math->cmp($num1, $this->int0->getInt()) !== 0 && $math->cmp($num2, $this->int0->getInt()) !== 0;
767 114
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
768 18
                                $num = $math->cmp($num1, $this->int0->getInt()) !== 0 || $math->cmp($num2, $this->int0->getInt()) !== 0;
769 102
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
770 18
                                $num = $math->cmp($num1, $num2) === 0;
771 84
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
772
                                $num = $math->cmp($num1, $num2) === 0;
773 66
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
774 6
                                $num = $math->cmp($num1, $num2) !== 0;
775 66
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) { // cscriptnum
776 12
                                $num = $math->cmp($num1, $num2) < 0;
777 60
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
778 12
                                $num = $math->cmp($num1, $num2) > 0;
779 48
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) { // cscriptnum
780 12
                                $num = $math->cmp($num1, $num2) <= 0;
781 36
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
782 12
                                $num = $math->cmp($num1, $num2) >= 0;
783 24
                            } elseif ($opCode === Opcodes::OP_MIN) {
784 6
                                $num = ($math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
785 6
                            } else {
786 6
                                $num = ($math->cmp($num1, $num2) >= 0) ? $num1 : $num2;
787
                            }
788
789 126
                            $mainStack->pop();
790 126
                            $mainStack->pop();
791 126
                            $buffer = Buffer::int($num, 4, $math);
792 126
                            $mainStack->push($buffer);
793
794 126
                            if ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
795
                                if ($this->castToBool($mainStack[-1])) {
796
                                    $mainStack->pop();
797
                                } else {
798
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
799
                                }
800
                            }
801 126
                            break;
802
803 84
                        case Opcodes::OP_WITHIN:
804 12
                            if (count($mainStack) < 3) {
805 6
                                throw new \RuntimeException('Invalid stack operation');
806
                            }
807
808 6
                            $num1 = (new ScriptNum($math, $this->flags, $mainStack[-3], 4))->getInt();
809 6
                            $num2 = (new ScriptNum($math, $this->flags, $mainStack[-2], 4))->getInt();
810 6
                            $num3 = (new ScriptNum($math, $this->flags, $mainStack[-1], 4))->getInt();
811
812 6
                            $value = $math->cmp($num2, $num1) <= 0 && $math->cmp($num1, $num3) < 0;
813 6
                            $mainStack->pop();
814 6
                            $mainStack->pop();
815 6
                            $mainStack->pop();
816 6
                            $mainStack->push($value ? $this->vchFalse : $this->vchTrue);
817 6
                            break;
818
819
                        // Hash operation
820 72
                        case Opcodes::OP_RIPEMD160:
821 72
                        case Opcodes::OP_SHA1:
822 72
                        case Opcodes::OP_SHA256:
823 72
                        case Opcodes::OP_HASH160:
824 72
                        case Opcodes::OP_HASH256:
825 48
                            if ($mainStack->isEmpty()) {
826 6
                                throw new \RuntimeException('Invalid stack operation');
827
                            }
828
829 42
                            $buffer = $mainStack[-1];
830 42
                            if ($opCode === Opcodes::OP_RIPEMD160) {
831 6
                                $hash = Hash::ripemd160($buffer);
832 42
                            } elseif ($opCode === Opcodes::OP_SHA1) {
833 6
                                $hash = Hash::sha1($buffer);
834 36
                            } elseif ($opCode === Opcodes::OP_SHA256) {
835 6
                                $hash = Hash::sha256($buffer);
836 30
                            } elseif ($opCode === Opcodes::OP_HASH160) {
837 18
                                $hash = Hash::sha256ripe160($buffer);
838 18
                            } else {
839 6
                                $hash = Hash::sha256d($buffer);
840
                            }
841
842 42
                            $mainStack->pop();
843 42
                            $mainStack->push($hash);
844 42
                            break;
845
846 30
                        case Opcodes::OP_CODESEPARATOR:
847
                            $this->hashStartPos = $parser->getPosition();
848
                            break;
849
850 30
                        case Opcodes::OP_CHECKSIG:
851 30
                        case Opcodes::OP_CHECKSIGVERIFY:
852 24
                            if (count($mainStack) < 2) {
853 6
                                throw new \RuntimeException('Invalid stack operation');
854
                            }
855
856 18
                            $vchPubKey = $mainStack[-1];
857 18
                            $vchSig = $mainStack[-2];
858
859 18
                            $scriptCode = new Script($this->script->getBuffer()->slice($this->hashStartPos));
860
861 18
                            $success = $this->checkSig($scriptCode, $vchSig, $vchPubKey);
862
863 12
                            $mainStack->pop();
864 12
                            $mainStack->pop();
865 12
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
866
867 12
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
868
                                if ($success) {
869
                                    $mainStack->pop();
870
                                } else {
871
                                    throw new \RuntimeException('Checksig verify');
872
                                }
873
                            }
874
875 12
                            break;
876
877 6
                        case Opcodes::OP_CHECKMULTISIG:
878 6
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
879
                            $i = 1;
880
                            if (count($mainStack) < $i) {
881
                                throw new \RuntimeException('Invalid stack operation');
882
                            }
883
884
                            $keyCount = $mainStack[-$i]->getInt();
885
                            if ($math->cmp($keyCount, 0) < 0 || $math->cmp($keyCount, 20) > 0) {
886
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
887
                            }
888
                            $this->opCount += $keyCount;
889
                            $this->checkOpcodeCount();
890
891
                            // Extract positions of the keys, and signatures, from the stack.
892
                            $ikey = ++$i;
893
                            $i += $keyCount; /** @var int $i */
894
                            if (count($mainStack) < $i) {
895
                                throw new \RuntimeException('Invalid stack operation');
896
                            }
897
898
                            $sigCount = $mainStack[-$i]->getInt(); // cscriptnum
899
                            if ($math->cmp($sigCount, 0) < 0 || $math->cmp($sigCount, $keyCount) > 0) {
900
                                throw new \RuntimeException('Invalid Signature count');
901
                            }
902
                            $isig = ++$i;
903
                            $i += $sigCount;
904
905
                            // Extract the script since the last OP_CODESEPARATOR
906
                            $scriptCode = new Script($this->script->getBuffer()->slice($this->hashStartPos));
907
908
                            $fSuccess = true;
909
                            while ($fSuccess && $sigCount > 0) {
910
                                // Fetch the signature and public key
911
                                $sig = $mainStack[-$isig];
912
                                $pubkey = $mainStack[-$ikey];
913
914
                                // Erase the signature and public key.
915
                                unset($mainStack[-$isig], $mainStack[-$ikey]);
916
917
                                // Decrement $i, since we are consuming stack values.
918
                                $i -= 2;
919
920
                                if ($this->checkSig($scriptCode, $sig, $pubkey)) {
921
                                    $isig++;
922
                                    $sigCount--;
923
                                }
924
925
                                $ikey++;
926
                                $keyCount--;
927
928
                                // If there are more signatures left than keys left,
929
                                // then too many signatures have failed. Exit early,
930
                                // without checking any further signatures.
931
                                if ($sigCount > $keyCount) {
932
                                    $fSuccess = false;
933
                                }
934
                            }
935
936
                            while ($i-- > 1) {
937
                                $mainStack->pop();
938
                            }
939
940
                            // A bug causes CHECKMULTISIG to consume one extra argument
941
                            // whose contents were not checked in any way.
942
                            //
943
                            // Unfortunately this is a potential source of mutability,
944
                            // so optionally verify it is exactly equal to zero prior
945
                            // to removing it from the stack.
946
                            if ($mainStack->isEmpty()) {
947
                                throw new \RuntimeException('Invalid stack operation');
948
                            }
949
950
                            if ($flags->checkFlags(InterpreterInterface::VERIFY_NULL_DUMMY) && $mainStack[-1]->getSize()) {
951
                                throw new ScriptRuntimeException(InterpreterInterface::VERIFY_NULL_DUMMY, 'Extra P2SH stack value should be OP_0');
952
                            }
953
954
                            $mainStack->pop();
955
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
956
957
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
958
                                if ($fSuccess) {
959
                                    $mainStack->pop();
960
                                } else {
961
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
962
                                }
963
                            }
964
                            break;
965
966 6
                        default:
967 6
                            throw new \RuntimeException('Opcode not found');
968 6
                    }
969
970 426
                    if (count($mainStack) + count($altStack) > 1000) {
971
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
972
                    }
973 426
                }
974 684
            }
975
976 684
            if (!$vfStack->end() === 0) {
977
                throw new \RuntimeException('Unbalanced conditional at script end');
978
            }
979
980 684
            return true;
981 258
        } catch (ScriptRuntimeException $e) {
982
            // echo "\n Runtime: " . $e->getMessage() . "\n";
983
            // Failure due to script tags, can access flag: $e->getFailureFlag()
984 18
            return false;
985 240
        } catch (\Exception $e) {
986
            // echo "\n General: " . $e->getMessage() ;
987 240
            return false;
988
        }
989
    }
990
}
991