Completed
Pull Request — master (#525)
by thomas
26:53
created

Interpreter::isValidSignatureEncoding()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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