UNPKG

61.8 kBJavaScriptView Raw
1/**
2 * Script Interpreter
3 * ==================
4 *
5 * Bitcoin transactions contain scripts. Each input has a script called the
6 * scriptSig, and each output has a script called the scriptPubKey. To validate
7 * an input, the ScriptSig is executed, then with the same stack, the
8 * scriptPubKey from the output corresponding to that input is run. The primary
9 * way to use this class is via the verify function:
10 *
11 * new Interp().verify( ... )
12 *
13 * In some ways, the script interpreter is one of the most poorly architected
14 * components of Yours Bitcoin because of the giant switch statement in step(). But
15 * that is deliberately so to make it similar to bitcoin core, and thus easier
16 * to audit.
17 */
18'use strict'
19
20import { Bn } from './bn'
21import { Bw } from './bw'
22import { cmp } from './cmp'
23import { Hash } from './hash'
24import { OpCode } from './op-code'
25import { PubKey } from './pub-key'
26import { Script } from './script'
27import { Sig } from './sig'
28import { Struct } from './struct'
29import { Tx } from './tx'
30import { TxIn } from './tx-in'
31
32 class Interp extends Struct {
33 constructor (
34 script,
35 tx,
36 nIn,
37 stack = [],
38 altStack = [],
39 pc = 0,
40 pBeginCodeHash = 0,
41 nOpCount = 0,
42 ifStack = [],
43 errStr = '',
44 flags = Interp.defaultFlags,
45 valueBn = new Bn(0)
46 ) {
47 super({
48 script,
49 tx,
50 nIn,
51 stack,
52 altStack,
53 pc,
54 pBeginCodeHash,
55 nOpCount,
56 ifStack,
57 errStr,
58 flags,
59 valueBn
60 })
61 }
62
63 initialize () {
64 this.script = new Script()
65 this.stack = []
66 this.altStack = []
67 this.pc = 0
68 this.pBeginCodeHash = 0
69 this.nOpCount = 0
70 this.ifStack = []
71 this.errStr = ''
72 this.flags = Interp.defaultFlags
73 return this
74 }
75
76 fromJSON (json) {
77 this.fromJSONNoTx(json)
78 this.tx = json.tx ? new Tx().fromJSON(json.tx) : undefined
79 return this
80 }
81 /**
82 * Convert JSON containing everything but the tx to an interp object.
83 */
84 fromJSONNoTx (json) {
85 this.fromObject({
86 script:
87 json.script !== undefined
88 ? new Script().fromJSON(json.script)
89 : undefined,
90 nIn: json.nIn
91 })
92 this.stack = []
93 json.stack.forEach(
94 function (hex) {
95 this.stack.push(Buffer.from(hex, 'hex'))
96 }.bind(this)
97 )
98 this.altStack = []
99 json.altStack.forEach(
100 function (hex) {
101 this.altStack.push(Buffer.from(hex, 'hex'))
102 }.bind(this)
103 )
104 this.fromObject({
105 pc: json.pc,
106 pBeginCodeHash: json.pBeginCodeHash,
107 nOpCount: json.nOpCount,
108 ifStack: json.ifStack,
109 errStr: json.errStr,
110 flags: json.flags
111 })
112 return this
113 }
114
115 fromBr (br) {
116 let jsonNoTxBufLEn = br.readVarIntNum()
117 let jsonNoTxBuf = br.read(jsonNoTxBufLEn)
118 this.fromJSONNoTx(JSON.parse(jsonNoTxBuf.toString()))
119 let txbuflen = br.readVarIntNum()
120 if (txbuflen > 0) {
121 let txbuf = br.read(txbuflen)
122 this.tx = new Tx().fromFastBuffer(txbuf)
123 }
124 return this
125 }
126
127 toJSON () {
128 let json = this.toJSONNoTx()
129 json.tx = this.tx ? this.tx.toJSON() : undefined
130 return json
131 }
132
133 /**
134 * Convert everything but the tx to JSON.
135 */
136 toJSONNoTx () {
137 let stack = []
138 this.stack.forEach(function (buf) {
139 stack.push(buf.toString('hex'))
140 })
141 let altStack = []
142 this.altStack.forEach(function (buf) {
143 altStack.push(buf.toString('hex'))
144 })
145 return {
146 script: this.script ? this.script.toJSON() : undefined,
147 nIn: this.nIn,
148 stack: stack,
149 altStack: altStack,
150 pc: this.pc,
151 pBeginCodeHash: this.pBeginCodeHash,
152 nOpCount: this.nOpCount,
153 ifStack: this.ifStack,
154 errStr: this.errStr,
155 flags: this.flags
156 }
157 }
158
159 toBw (bw) {
160 if (!bw) {
161 bw = new Bw()
162 }
163 let jsonNoTxBuf = Buffer.from(JSON.stringify(this.toJSONNoTx()))
164 bw.writeVarIntNum(jsonNoTxBuf.length)
165 bw.write(jsonNoTxBuf)
166 if (this.tx) {
167 let txbuf = this.tx.toFastBuffer()
168 bw.writeVarIntNum(txbuf.length)
169 bw.write(txbuf)
170 } else {
171 bw.writeVarIntNum(0)
172 }
173 return bw
174 }
175
176 /**
177 * In order to make auduting the script interpreter easier, we use the same
178 * constants as bitcoin core, including the flags, which customize the
179 * operation of the interpreter.
180 */
181 static getFlags (flagstr) {
182 let flags = 0
183 if (flagstr.indexOf('NONE') !== -1) {
184 flags = flags | Interp.SCRIPT_VERIFY_NONE
185 }
186 if (flagstr.indexOf('P2SH') !== -1) {
187 flags = flags | Interp.SCRIPT_VERIFY_P2SH
188 }
189 if (flagstr.indexOf('STRICTENC') !== -1) {
190 flags = flags | Interp.SCRIPT_VERIFY_STRICTENC
191 }
192 if (flagstr.indexOf('DERSIG') !== -1) {
193 flags = flags | Interp.SCRIPT_VERIFY_DERSIG
194 }
195 if (flagstr.indexOf('LOW_S') !== -1) {
196 flags = flags | Interp.SCRIPT_VERIFY_LOW_S
197 }
198 if (flagstr.indexOf('NULLDUMMY') !== -1) {
199 flags = flags | Interp.SCRIPT_VERIFY_NULLDUMMY
200 }
201 if (flagstr.indexOf('SIGPUSHONLY') !== -1) {
202 flags = flags | Interp.SCRIPT_VERIFY_SIGPUSHONLY
203 }
204 if (flagstr.indexOf('MINIMALDATA') !== -1) {
205 flags = flags | Interp.SCRIPT_VERIFY_MINIMALDATA
206 }
207 if (flagstr.indexOf('DISCOURAGE_UPGRADABLE_NOPS') !== -1) {
208 flags = flags | Interp.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS
209 }
210 if (flagstr.indexOf('CLEANSTACK') !== -1) {
211 flags = flags | Interp.SCRIPT_VERIFY_CLEANSTACK
212 }
213 if (flagstr.indexOf('CHECKLOCKTIMEVERIFY') !== -1) {
214 flags = flags | Interp.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
215 }
216 if (flagstr.indexOf('CHECKSEQUENCEVERIFY') !== -1) {
217 flags = flags | Interp.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY
218 }
219 if (flagstr.indexOf('SIGHASH_FORKID') !== -1) {
220 flags = flags | Interp.SCRIPT_ENABLE_SIGHASH_FORKID
221 }
222 return flags
223 }
224
225 static castToBool (buf) {
226 for (let i = 0; i < buf.length; i++) {
227 if (buf[i] !== 0) {
228 // can be negative zero
229 if (i === buf.length - 1 && buf[i] === 0x80) {
230 return false
231 }
232 return true
233 }
234 }
235 return false
236 }
237
238 /**
239 * Translated from bitcoin core's CheckSigEncoding
240 */
241 checkSigEncoding (buf) {
242 // Empty signature. Not strictly DER encoded, but allowed to provide a
243 // compact way to provide an invalid signature for use with CHECK(MULTI)SIG
244 if (buf.length === 0) {
245 return true
246 }
247 if (
248 (this.flags &
249 (Interp.SCRIPT_VERIFY_DERSIG |
250 Interp.SCRIPT_VERIFY_LOW_S |
251 Interp.SCRIPT_VERIFY_STRICTENC)) !==
252 0 &&
253 !Sig.IsTxDer(buf)
254 ) {
255 this.errStr = 'SCRIPT_ERR_SIG_DER'
256 return false
257 } else if ((this.flags & Interp.SCRIPT_VERIFY_LOW_S) !== 0) {
258 let sig = new Sig().fromTxFormat(buf)
259 if (!sig.hasLowS()) {
260 this.errStr = 'SCRIPT_ERR_SIG_DER'
261 return false
262 }
263 } else if ((this.flags & Interp.SCRIPT_VERIFY_STRICTENC) !== 0) {
264 let sig = new Sig().fromTxFormat(buf)
265 if (!sig.hasDefinedHashType()) {
266 this.errStr = 'SCRIPT_ERR_SIG_HASHTYPE'
267 return false
268 }
269 }
270 return true
271 }
272
273 /**
274 * Translated from bitcoin core's CheckPubKeyEncoding
275 */
276 checkPubKeyEncoding (buf) {
277 if (
278 (this.flags & Interp.SCRIPT_VERIFY_STRICTENC) !== 0 &&
279 !PubKey.isCompressedOrUncompressed(buf)
280 ) {
281 this.errStr = 'SCRIPT_ERR_PUBKEYTYPE'
282 return false
283 }
284 return true
285 }
286
287 /**
288 * Translated from bitcoin core's CheckLockTime
289 */
290 checkLockTime (nLockTime) {
291 // There are two kinds of nLockTime: lock-by-blockheight
292 // and lock-by-blocktime, distinguished by whether
293 // nLockTime < LOCKTIME_THRESHOLD.
294 //
295 // We want to compare apples to apples, so fail the script
296 // unless the type of nLockTime being tested is the same as
297 // the nLockTime in the transaction.
298 if (
299 !(
300 (this.tx.nLockTime < Interp.LOCKTIME_THRESHOLD &&
301 nLockTime < Interp.LOCKTIME_THRESHOLD) ||
302 (this.tx.nLockTime >= Interp.LOCKTIME_THRESHOLD &&
303 nLockTime >= Interp.LOCKTIME_THRESHOLD)
304 )
305 ) {
306 return false
307 }
308
309 // Now that we know we're comparing apples-to-apples, the
310 // comparison is a simple numeric one.
311 if (nLockTime > this.tx.nLockTime) {
312 return false
313 }
314
315 // Finally the nLockTime feature can be disabled and thus
316 // CHECKLOCKTIMEVERIFY bypassed if every txIn has been
317 // finalized by setting nSequence to maxint. The
318 // transaction would be allowed into the blockchain, making
319 // the opCode ineffective.
320 //
321 // Testing if this vin is not final is sufficient to
322 // prevent this condition. Alternatively we could test all
323 // inputs, but testing just this input minimizes the data
324 // required to prove correct CHECKLOCKTIMEVERIFY execution.
325 if (TxIn.SEQUENCE_FINAL === this.tx.txIns[this.nIn].nSequence) {
326 return false
327 }
328
329 return true
330 }
331
332 /**
333 * Translated from bitcoin core's CheckSequence.
334 */
335 checkSequence (nSequence) {
336 // Relative lock times are supported by comparing the passed
337 // in operand to the sequence number of the input.
338 let txToSequence = this.tx.txIns[this.nIn].nSequence
339
340 // Fail if the transaction's version number is not set high
341 // enough to trigger Bip 68 rules.
342 if (this.tx.versionBytesNum < 2) {
343 return false
344 }
345
346 // Sequence numbers with their most significant bit set are not
347 // consensus constrained. Testing that the transaction's sequence
348 // number do not have this bit set prevents using this property
349 // to get around a CHECKSEQUENCEVERIFY check.
350 if (txToSequence & TxIn.SEQUENCE_LOCKTIME_DISABLE_FLAG) {
351 return false
352 }
353
354 // Mask off any bits that do not have consensus-enforced meaning
355 // before doing the integer comparisons
356 let nLockTimeMask =
357 TxIn.SEQUENCE_LOCKTIME_TYPE_FLAG | TxIn.SEQUENCE_LOCKTIME_MASK
358 let txToSequenceMasked = txToSequence & nLockTimeMask
359 let nSequenceMasked = nSequence & nLockTimeMask
360
361 // There are two kinds of nSequence: lock-by-blockheight
362 // and lock-by-blocktime, distinguished by whether
363 // nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.
364 //
365 // We want to compare apples to apples, so fail the script
366 // unless the type of nSequenceMasked being tested is the same as
367 // the nSequenceMasked in the transaction.
368 if (
369 !(
370 (txToSequenceMasked < TxIn.SEQUENCE_LOCKTIME_TYPE_FLAG &&
371 nSequenceMasked < TxIn.SEQUENCE_LOCKTIME_TYPE_FLAG) ||
372 (txToSequenceMasked >= TxIn.SEQUENCE_LOCKTIME_TYPE_FLAG &&
373 nSequenceMasked >= TxIn.SEQUENCE_LOCKTIME_TYPE_FLAG)
374 )
375 ) {
376 return false
377 }
378
379 // Now that we know we're comparing apples-to-apples, the
380 // comparison is a simple numeric one.
381 if (nSequenceMasked > txToSequenceMasked) {
382 return false
383 }
384
385 return true
386 }
387
388 /**
389 * Based on bitcoin core's EvalScript function, with the inner loop moved to
390 * Interp.prototype.step()
391 * bitcoin core commit: b5d1b1092998bc95313856d535c632ea5a8f9104
392 */
393 * eval () {
394 if (this.script.toBuffer().length > 10000) {
395 this.errStr = 'SCRIPT_ERR_SCRIPT_SIZE'
396 yield false
397 }
398
399 try {
400 while (this.pc < this.script.chunks.length) {
401 let fSuccess = this.step()
402 if (!fSuccess) {
403 yield false
404 } else {
405 yield fSuccess
406 }
407 }
408
409 // Size limits
410 if (this.stack.length + this.altStack.length > 1000) {
411 this.errStr = 'SCRIPT_ERR_STACK_SIZE'
412 yield false
413 }
414 } catch (e) {
415 this.errStr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e
416 yield false
417 }
418
419 if (this.ifStack.length > 0) {
420 this.errStr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'
421 yield false
422 }
423
424 yield true
425 }
426
427 /**
428 * Based on the inner loop of bitcoin core's EvalScript function
429 */
430 step () {
431 let fRequireMinimal =
432 (this.flags & Interp.SCRIPT_VERIFY_MINIMALDATA) !== 0
433
434 // bool fExec = !count(ifStack.begin(), ifStack.end(), false)
435 let fExec = !(this.ifStack.indexOf(false) + 1)
436
437 //
438 // Read instruction
439 //
440 let chunk = this.script.chunks[this.pc]
441 this.pc++
442 let opCodeNum = chunk.opCodeNum
443 if (opCodeNum === undefined) {
444 this.errStr = 'SCRIPT_ERR_BAD_OPCODE'
445 return false
446 }
447 if (chunk.buf && chunk.buf.length > Interp.MAX_SCRIPT_ELEMENT_SIZE) {
448 this.errStr = 'SCRIPT_ERR_PUSH_SIZE'
449 return false
450 }
451
452 // Note how OpCode.OP_RESERVED does not count towards the opCode limit.
453 if (opCodeNum > OpCode.OP_16 && ++this.nOpCount > 201) {
454 this.errStr = 'SCRIPT_ERR_OP_COUNT'
455 return false
456 }
457
458 if (
459 opCodeNum === OpCode.OP_LEFT ||
460 opCodeNum === OpCode.OP_RIGHT ||
461 opCodeNum === OpCode.OP_2MUL ||
462 opCodeNum === OpCode.OP_2DIV
463 ) {
464 this.errStr = 'SCRIPT_ERR_DISABLED_OPCODE'
465 return false
466 }
467
468 if (fExec && opCodeNum >= 0 && opCodeNum <= OpCode.OP_PUSHDATA4) {
469 if (fRequireMinimal && !this.script.checkMinimalPush(this.pc - 1)) {
470 this.errStr = 'SCRIPT_ERR_MINIMALDATA'
471 return false
472 }
473 if (!chunk.buf) {
474 this.stack.push(Interp.false)
475 } else if (chunk.len !== chunk.buf.length) {
476 throw new Error('LEngth of push value not equal to length of data')
477 } else {
478 this.stack.push(chunk.buf)
479 }
480 } else if (
481 fExec ||
482 (OpCode.OP_IF <= opCodeNum && opCodeNum <= OpCode.OP_ENDIF)
483 ) {
484 switch (opCodeNum) {
485 //
486 // Push value
487 //
488 case OpCode.OP_1NEGATE:
489 case OpCode.OP_1:
490 case OpCode.OP_2:
491 case OpCode.OP_3:
492 case OpCode.OP_4:
493 case OpCode.OP_5:
494 case OpCode.OP_6:
495 case OpCode.OP_7:
496 case OpCode.OP_8:
497 case OpCode.OP_9:
498 case OpCode.OP_10:
499 case OpCode.OP_11:
500 case OpCode.OP_12:
501 case OpCode.OP_13:
502 case OpCode.OP_14:
503 case OpCode.OP_15:
504 case OpCode.OP_16:
505 {
506 // ( -- value)
507 // ScriptNum bn((int)opCode - (int)(OpCode.OP_1 - 1))
508 let n = opCodeNum - (OpCode.OP_1 - 1)
509 let buf = new Bn(n).toScriptNumBuffer()
510 this.stack.push(buf)
511 // The result of these opCodes should always be the minimal way to push the data
512 // they push, so no need for a CheckMinimalPush here.
513 }
514 break
515
516 //
517 // Control
518 //
519 case OpCode.OP_NOP:
520 break
521
522 case OpCode.OP_CHECKLOCKTIMEVERIFY:
523 {
524 if (!(this.flags & Interp.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
525 // not enabled; treat as a NOP2
526 if (
527 this.flags & Interp.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS
528 ) {
529 this.errStr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
530 return false
531 }
532 break
533 }
534
535 if (this.stack.length < 1) {
536 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
537 return false
538 }
539
540 // Note that elsewhere numeric opCodes are limited to
541 // operands in the range -2**31+1 to 2**31-1, however it is
542 // legal for opCodes to produce results exceeding that
543 // range. This limitation is implemented by CScriptNum's
544 // default 4-byte limit.
545 //
546 // If we kept to that limit we'd have a year 2038 problem,
547 // even though the nLockTime field in transactions
548 // themselves is uint32 which only becomes meaningless
549 // after the year 2106.
550 //
551 // Thus as a special case we tell CScriptNum to accept up
552 // to 5-byte bignums, which are good until 2**39-1, well
553 // beyond the 2**32-1 limit of the nLockTime field itself.
554 let nLockTimebuf = this.stack[this.stack.length - 1]
555 let nLockTimebn = new Bn().fromScriptNumBuffer(
556 nLockTimebuf,
557 fRequireMinimal,
558 5
559 )
560 let nLockTime = nLockTimebn.toNumber()
561
562 // In the rare event that the argument may be < 0 due to
563 // some arithmetic being done first, you can always use
564 // 0 MAX CHECKLOCKTIMEVERIFY.
565 if (nLockTime < 0) {
566 this.errStr = 'SCRIPT_ERR_NEGATIVE_LOCKTIME'
567 return false
568 }
569
570 // Actually compare the specified lock time with the transaction.
571 if (!this.checkLockTime(nLockTime)) {
572 this.errStr = 'SCRIPT_ERR_UNSATISFIED_LOCKTIME'
573 return false
574 }
575 }
576 break
577
578 case OpCode.OP_CHECKSEQUENCEVERIFY:
579 {
580 if (!(this.flags & Interp.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
581 // not enabled; treat as a NOP3
582 if (
583 this.flags & Interp.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS
584 ) {
585 this.errStr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
586 return false
587 }
588 break
589 }
590
591 if (this.stack.length < 1) {
592 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
593 return false
594 }
595
596 // nSequence, like nLockTime, is a 32-bit unsigned integer
597 // field. See the comment in CHECKLOCKTIMEVERIFY regarding
598 // 5-byte numeric operands.
599 let nSequencebuf = this.stack[this.stack.length - 1]
600 let nSequencebn = new Bn().fromScriptNumBuffer(
601 nSequencebuf,
602 fRequireMinimal,
603 5
604 )
605 let nSequence = nSequencebn.toNumber()
606
607 // In the rare event that the argument may be < 0 due to
608 // some arithmetic being done first, you can always use
609 // 0 MAX CHECKSEQUENCEVERIFY.
610 if (nSequence < 0) {
611 this.errStr = 'SCRIPT_ERR_NEGATIVE_LOCKTIME'
612 return false
613 }
614
615 // To provide for future soft-fork extensibility, if the
616 // operand has the disabled lock-time flag set,
617 // CHECKSEQUENCEVERIFY behaves as a NOP.
618 if ((nSequence & TxIn.SEQUENCE_LOCKTIME_DISABLE_FLAG) !== 0) {
619 break
620 }
621
622 // Compare the specified sequence number with the input.
623 if (!this.checkSequence(nSequence)) {
624 this.errStr = 'SCRIPT_ERR_UNSATISFIED_LOCKTIME'
625 return false
626 }
627 }
628 break
629
630 case OpCode.OP_NOP1:
631 case OpCode.OP_NOP3:
632 case OpCode.OP_NOP4:
633 case OpCode.OP_NOP5:
634 case OpCode.OP_NOP6:
635 case OpCode.OP_NOP7:
636 case OpCode.OP_NOP8:
637 case OpCode.OP_NOP9:
638 case OpCode.OP_NOP10:
639 if (this.flags & Interp.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
640 this.errStr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS'
641 return false
642 }
643 break
644
645 case OpCode.OP_IF:
646 case OpCode.OP_NOTIF:
647 {
648 // <expression> if [statements] [else [statements]] endif
649 // bool fValue = false
650 let fValue = false
651 if (fExec) {
652 if (this.stack.length < 1) {
653 this.errStr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'
654 return false
655 }
656 let buf = this.stack.pop()
657 fValue = Interp.castToBool(buf)
658 if (opCodeNum === OpCode.OP_NOTIF) {
659 fValue = !fValue
660 }
661 }
662 this.ifStack.push(fValue)
663 }
664 break
665
666 case OpCode.OP_ELSE:
667 if (this.ifStack.length === 0) {
668 this.errStr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'
669 return false
670 }
671 this.ifStack[this.ifStack.length - 1] = !this.ifStack[
672 this.ifStack.length - 1
673 ]
674 break
675
676 case OpCode.OP_ENDIF:
677 if (this.ifStack.length === 0) {
678 this.errStr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL'
679 return false
680 }
681 this.ifStack.pop()
682 break
683
684 case OpCode.OP_VERIFY:
685 {
686 // (true -- ) or
687 // (false -- false) and return
688 if (this.stack.length < 1) {
689 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
690 return false
691 }
692 let buf = this.stack[this.stack.length - 1]
693 let fValue = Interp.castToBool(buf)
694 if (fValue) {
695 this.stack.pop()
696 } else {
697 this.errStr = 'SCRIPT_ERR_VERIFY'
698 return false
699 }
700 }
701 break
702
703 case OpCode.OP_RETURN: {
704 this.errStr = 'SCRIPT_ERR_OP_RETURN'
705 return false
706 }
707 // unreachable code: break
708
709 //
710 // Stack ops
711 //
712 case OpCode.OP_TOALTSTACK:
713 if (this.stack.length < 1) {
714 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
715 return false
716 }
717 this.altStack.push(this.stack.pop())
718 break
719
720 case OpCode.OP_FROMALTSTACK:
721 if (this.altStack.length < 1) {
722 this.errStr = 'SCRIPT_ERR_INVALID_ALTSTACK_OPERATION'
723 return false
724 }
725 this.stack.push(this.altStack.pop())
726 break
727
728 case OpCode.OP_2DROP:
729 // (x1 x2 -- )
730 if (this.stack.length < 2) {
731 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
732 return false
733 }
734 this.stack.pop()
735 this.stack.pop()
736 break
737
738 case OpCode.OP_2DUP:
739 {
740 // (x1 x2 -- x1 x2 x1 x2)
741 if (this.stack.length < 2) {
742 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
743 return false
744 }
745 let buf1 = this.stack[this.stack.length - 2]
746 let buf2 = this.stack[this.stack.length - 1]
747 this.stack.push(buf1)
748 this.stack.push(buf2)
749 }
750 break
751
752 case OpCode.OP_3DUP:
753 {
754 // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
755 if (this.stack.length < 3) {
756 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
757 return false
758 }
759 let buf1 = this.stack[this.stack.length - 3]
760 let buf2 = this.stack[this.stack.length - 2]
761 let buf3 = this.stack[this.stack.length - 1]
762 this.stack.push(buf1)
763 this.stack.push(buf2)
764 this.stack.push(buf3)
765 }
766 break
767
768 case OpCode.OP_2OVER:
769 {
770 // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
771 if (this.stack.length < 4) {
772 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
773 return false
774 }
775 let buf1 = this.stack[this.stack.length - 4]
776 let buf2 = this.stack[this.stack.length - 3]
777 this.stack.push(buf1)
778 this.stack.push(buf2)
779 }
780 break
781
782 case OpCode.OP_2ROT:
783 {
784 // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
785 if (this.stack.length < 6) {
786 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
787 return false
788 }
789 let spliced = this.stack.splice(this.stack.length - 6, 2)
790 this.stack.push(spliced[0])
791 this.stack.push(spliced[1])
792 }
793 break
794
795 case OpCode.OP_2SWAP:
796 {
797 // (x1 x2 x3 x4 -- x3 x4 x1 x2)
798 if (this.stack.length < 4) {
799 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
800 return false
801 }
802 let spliced = this.stack.splice(this.stack.length - 4, 2)
803 this.stack.push(spliced[0])
804 this.stack.push(spliced[1])
805 }
806 break
807
808 case OpCode.OP_IFDUP:
809 {
810 // (x - 0 | x x)
811 if (this.stack.length < 1) {
812 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
813 return false
814 }
815 let buf = this.stack[this.stack.length - 1]
816 let fValue = Interp.castToBool(buf)
817 if (fValue) {
818 this.stack.push(buf)
819 }
820 }
821 break
822
823 case OpCode.OP_DEPTH:
824 {
825 // -- stacksize
826 let buf = new Bn(this.stack.length).toScriptNumBuffer()
827 this.stack.push(buf)
828 }
829 break
830
831 case OpCode.OP_DROP:
832 // (x -- )
833 if (this.stack.length < 1) {
834 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
835 return false
836 }
837 this.stack.pop()
838 break
839
840 case OpCode.OP_DUP:
841 // (x -- x x)
842 if (this.stack.length < 1) {
843 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
844 return false
845 }
846 this.stack.push(this.stack[this.stack.length - 1])
847 break
848
849 case OpCode.OP_NIP:
850 // (x1 x2 -- x2)
851 if (this.stack.length < 2) {
852 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
853 return false
854 }
855 this.stack.splice(this.stack.length - 2, 1)
856 break
857
858 case OpCode.OP_OVER:
859 // (x1 x2 -- x1 x2 x1)
860 if (this.stack.length < 2) {
861 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
862 return false
863 }
864 this.stack.push(this.stack[this.stack.length - 2])
865 break
866
867 case OpCode.OP_PICK:
868 case OpCode.OP_ROLL:
869 {
870 // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
871 // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
872 if (this.stack.length < 2) {
873 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
874 return false
875 }
876 let buf = this.stack[this.stack.length - 1]
877 let bn = new Bn().fromScriptNumBuffer(buf, fRequireMinimal)
878 let n = bn.toNumber()
879 this.stack.pop()
880 if (n < 0 || n >= this.stack.length) {
881 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
882 return false
883 }
884 buf = this.stack[this.stack.length - n - 1]
885 if (opCodeNum === OpCode.OP_ROLL) {
886 this.stack.splice(this.stack.length - n - 1, 1)
887 }
888 this.stack.push(buf)
889 }
890 break
891
892 case OpCode.OP_ROT:
893 {
894 // (x1 x2 x3 -- x2 x3 x1)
895 // x2 x1 x3 after first swap
896 // x2 x3 x1 after second swap
897 if (this.stack.length < 3) {
898 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
899 return false
900 }
901 let x1 = this.stack[this.stack.length - 3]
902 let x2 = this.stack[this.stack.length - 2]
903 let x3 = this.stack[this.stack.length - 1]
904 this.stack[this.stack.length - 3] = x2
905 this.stack[this.stack.length - 2] = x3
906 this.stack[this.stack.length - 1] = x1
907 }
908 break
909
910 case OpCode.OP_SWAP:
911 {
912 // (x1 x2 -- x2 x1)
913 if (this.stack.length < 2) {
914 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
915 return false
916 }
917 let x1 = this.stack[this.stack.length - 2]
918 let x2 = this.stack[this.stack.length - 1]
919 this.stack[this.stack.length - 2] = x2
920 this.stack[this.stack.length - 1] = x1
921 }
922 break
923
924 case OpCode.OP_TUCK:
925 // (x1 x2 -- x2 x1 x2)
926 if (this.stack.length < 2) {
927 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
928 return false
929 }
930 this.stack.splice(
931 this.stack.length - 2,
932 0,
933 this.stack[this.stack.length - 1]
934 )
935 break
936
937 case OpCode.OP_SIZE:
938 {
939 // (in -- in size)
940 if (this.stack.length < 1) {
941 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
942 return false
943 }
944 let bn = new Bn(this.stack[this.stack.length - 1].length)
945 this.stack.push(bn.toScriptNumBuffer())
946 }
947 break
948
949 //
950 // Bitwise logic
951 //
952 case OpCode.OP_OR:
953 case OpCode.OP_AND:
954 case OpCode.OP_XOR:
955 // (x1 x2 -- out)
956 if (this.stack.length < 2) {
957 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
958 return false
959 }
960 let buf1 = this.stack[this.stack.length - 2]
961 let buf2 = this.stack[this.stack.length - 1]
962
963 if (buf1.length != buf2.length) {
964 this.errStr = 'SCRIPT_ERR_INVALID_OPERAND_SIZE'
965 return false
966 }
967
968 switch (opCodeNum) {
969 case OpCode.OP_AND:
970 for(let i = 0; i < buf1.length; i++) {
971 buf1[i] &= buf2[i]
972 }
973 break
974 case OpCode.OP_OR:
975 for(let i = 0; i < buf1.length; i++) {
976 buf1[i] |= buf2[i]
977 }
978 break
979 case OpCode.OP_XOR:
980 for(let i = 0; i < buf1.length; i++) {
981 buf1[i] ^= buf2[i]
982 }
983 break
984 }
985
986 // pop out buf2
987 this.stack.pop();
988 break
989 case OpCode.OP_INVERT:
990 // (x -- out)
991 if (this.stack.length < 1) {
992 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
993 return false
994 }
995 let buf = this.stack[this.stack.length - 1]
996 for(let i = 0; i < buf.length; i++) {
997 buf[i] = ~buf[i]
998 }
999 break
1000 case OpCode.OP_LSHIFT:
1001 case OpCode.OP_RSHIFT:
1002 // (x n -- out)
1003 {
1004 if (this.stack.length < 2) {
1005 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1006 return false
1007 }
1008
1009 let buf1 = this.stack[this.stack.length - 2]
1010 let value = new Bn(buf1)
1011 let n = new Bn().fromScriptNumBuffer(
1012 this.stack[this.stack.length - 1],
1013 fRequireMinimal
1014 ).toNumber()
1015 if(n < 0) {
1016 this.errStr = 'SCRIPT_ERR_INVALID_NUMBER_RANGE'
1017 return false
1018 }
1019
1020 this.stack.pop()
1021 this.stack.pop()
1022
1023 switch(opCodeNum) {
1024 case OpCode.OP_LSHIFT:
1025 value = value.ushln(n)
1026 break
1027 case OpCode.OP_RSHIFT:
1028 value = value.ushrn(n)
1029 break
1030 }
1031
1032 let buf2 = value.toBuffer().slice(-buf1.length)
1033 if(buf2.length < buf1.length) {
1034 buf2 = Buffer.concat([Buffer.alloc(buf1.length - buf2.length), buf2])
1035 }
1036
1037 this.stack.push(buf2)
1038 break
1039 }
1040 case OpCode.OP_EQUAL:
1041 case OpCode.OP_EQUALVERIFY:
1042 // case OpCode.OP_NOTEQUAL: // use OpCode.OP_NUMNOTEQUAL
1043 {
1044 // (x1 x2 - bool)
1045 if (this.stack.length < 2) {
1046 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1047 return false
1048 }
1049 let buf1 = this.stack[this.stack.length - 2]
1050 let buf2 = this.stack[this.stack.length - 1]
1051 let fEqual = cmp(buf1, buf2)
1052 // OpCode.OP_NOTEQUAL is disabled because it would be too easy to say
1053 // something like n != 1 and have some wiseguy pass in 1 with extra
1054 // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)
1055 // if (opCode == OpCode.OP_NOTEQUAL)
1056 // fEqual = !fEqual
1057 this.stack.pop()
1058 this.stack.pop()
1059 this.stack.push(fEqual ? Interp.true : Interp.false)
1060 if (opCodeNum === OpCode.OP_EQUALVERIFY) {
1061 if (fEqual) {
1062 this.stack.pop()
1063 } else {
1064 this.errStr = 'SCRIPT_ERR_EQUALVERIFY'
1065 return false
1066 }
1067 }
1068 }
1069 break
1070
1071 //
1072 // Numeric
1073 //
1074 case OpCode.OP_1ADD:
1075 case OpCode.OP_1SUB:
1076 case OpCode.OP_NEGATE:
1077 case OpCode.OP_ABS:
1078 case OpCode.OP_NOT:
1079 case OpCode.OP_0NOTEQUAL:
1080 {
1081 // (in -- out)
1082 if (this.stack.length < 1) {
1083 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1084 return false
1085 }
1086 let buf = this.stack[this.stack.length - 1]
1087 let bn = new Bn().fromScriptNumBuffer(buf, fRequireMinimal)
1088 switch (opCodeNum) {
1089 case OpCode.OP_1ADD:
1090 bn = bn.add(1)
1091 break
1092 case OpCode.OP_1SUB:
1093 bn = bn.sub(1)
1094 break
1095 case OpCode.OP_NEGATE:
1096 bn = bn.neg()
1097 break
1098 case OpCode.OP_ABS:
1099 if (bn.lt(0)) bn = bn.neg()
1100 break
1101 case OpCode.OP_NOT:
1102 bn = new Bn(bn.eq(0) + 0)
1103 break
1104 case OpCode.OP_0NOTEQUAL:
1105 bn = new Bn(bn.neq(0) + 0)
1106 break
1107 // default: assert(!"invalid opCode"); break; // TODO: does this ever occur?
1108 }
1109 this.stack.pop()
1110 this.stack.push(bn.toScriptNumBuffer())
1111 }
1112 break
1113
1114 case OpCode.OP_ADD:
1115 case OpCode.OP_SUB:
1116 case OpCode.OP_MUL:
1117 case OpCode.OP_DIV:
1118 case OpCode.OP_MOD:
1119 case OpCode.OP_BOOLAND:
1120 case OpCode.OP_BOOLOR:
1121 case OpCode.OP_NUMEQUAL:
1122 case OpCode.OP_NUMEQUALVERIFY:
1123 case OpCode.OP_NUMNOTEQUAL:
1124 case OpCode.OP_LESSTHAN:
1125 case OpCode.OP_GREATERTHAN:
1126 case OpCode.OP_LESSTHANOREQUAL:
1127 case OpCode.OP_GREATERTHANOREQUAL:
1128 case OpCode.OP_MIN:
1129 case OpCode.OP_MAX:
1130 {
1131 // (x1 x2 -- out)
1132 if (this.stack.length < 2) {
1133 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1134 return false
1135 }
1136 let bn1 = new Bn().fromScriptNumBuffer(
1137 this.stack[this.stack.length - 2],
1138 fRequireMinimal
1139 )
1140 let bn2 = new Bn().fromScriptNumBuffer(
1141 this.stack[this.stack.length - 1],
1142 fRequireMinimal
1143 )
1144 let bn = new Bn(0)
1145
1146 switch (opCodeNum) {
1147 case OpCode.OP_ADD:
1148 bn = bn1.add(bn2)
1149 break
1150
1151 case OpCode.OP_SUB:
1152 bn = bn1.sub(bn2)
1153 break
1154
1155 case OpCode.OP_MUL:
1156 bn = bn1.mul(bn2)
1157 break
1158
1159 case OpCode.OP_DIV:
1160 if (bn2 == 0) {
1161 this.errStr = "SCRIPT_ERR_DIV_BY_ZERO"
1162 return false
1163 }
1164 bn = bn1.div(bn2)
1165 break
1166
1167 case OpCode.OP_MOD:
1168 if (bn2 == 0) {
1169 this.errStr = "SCRIPT_ERR_DIV_BY_ZERO"
1170 return false
1171 }
1172 bn = bn1.mod(bn2)
1173 break
1174
1175 // case OpCode.OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break
1176 case OpCode.OP_BOOLAND:
1177 bn = new Bn((bn1.neq(0) && bn2.neq(0)) + 0)
1178 break
1179 // case OpCode.OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break
1180 case OpCode.OP_BOOLOR:
1181 bn = new Bn((bn1.neq(0) || bn2.neq(0)) + 0)
1182 break
1183 // case OpCode.OP_NUMEQUAL: bn = (bn1 == bn2); break
1184 case OpCode.OP_NUMEQUAL:
1185 bn = new Bn(bn1.eq(bn2) + 0)
1186 break
1187 // case OpCode.OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break
1188 case OpCode.OP_NUMEQUALVERIFY:
1189 bn = new Bn(bn1.eq(bn2) + 0)
1190 break
1191 // case OpCode.OP_NUMNOTEQUAL: bn = (bn1 != bn2); break
1192 case OpCode.OP_NUMNOTEQUAL:
1193 bn = new Bn(bn1.neq(bn2) + 0)
1194 break
1195 // case OpCode.OP_LESSTHAN: bn = (bn1 < bn2); break
1196 case OpCode.OP_LESSTHAN:
1197 bn = new Bn(bn1.lt(bn2) + 0)
1198 break
1199 // case OpCode.OP_GREATERTHAN: bn = (bn1 > bn2); break
1200 case OpCode.OP_GREATERTHAN:
1201 bn = new Bn(bn1.gt(bn2) + 0)
1202 break
1203 // case OpCode.OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break
1204 case OpCode.OP_LESSTHANOREQUAL:
1205 bn = new Bn(bn1.leq(bn2) + 0)
1206 break
1207 // case OpCode.OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break
1208 case OpCode.OP_GREATERTHANOREQUAL:
1209 bn = new Bn(bn1.geq(bn2) + 0)
1210 break
1211 case OpCode.OP_MIN:
1212 bn = bn1.lt(bn2) ? bn1 : bn2
1213 break
1214 case OpCode.OP_MAX:
1215 bn = bn1.gt(bn2) ? bn1 : bn2
1216 break
1217 // default: assert(!"invalid opCode"); break; //TODO: does this ever occur?
1218 }
1219 this.stack.pop()
1220 this.stack.pop()
1221 this.stack.push(bn.toScriptNumBuffer())
1222
1223 if (opCodeNum === OpCode.OP_NUMEQUALVERIFY) {
1224 // if (CastToBool(stacktop(-1)))
1225 if (Interp.castToBool(this.stack[this.stack.length - 1])) {
1226 this.stack.pop()
1227 } else {
1228 this.errStr = 'SCRIPT_ERR_NUMEQUALVERIFY'
1229 return false
1230 }
1231 }
1232 }
1233 break
1234
1235 case OpCode.OP_WITHIN:
1236 {
1237 // (x min max -- out)
1238 if (this.stack.length < 3) {
1239 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1240 return false
1241 }
1242 let bn1 = new Bn().fromScriptNumBuffer(
1243 this.stack[this.stack.length - 3],
1244 fRequireMinimal
1245 )
1246 let bn2 = new Bn().fromScriptNumBuffer(
1247 this.stack[this.stack.length - 2],
1248 fRequireMinimal
1249 )
1250 let bn3 = new Bn().fromScriptNumBuffer(
1251 this.stack[this.stack.length - 1],
1252 fRequireMinimal
1253 )
1254 // bool fValue = (bn2 <= bn1 && bn1 < bn3)
1255 let fValue = bn2.leq(bn1) && bn1.lt(bn3)
1256 this.stack.pop()
1257 this.stack.pop()
1258 this.stack.pop()
1259 this.stack.push(fValue ? Interp.true : Interp.false)
1260 }
1261 break
1262
1263 //
1264 // Crypto
1265 //
1266 case OpCode.OP_RIPEMD160:
1267 case OpCode.OP_SHA1:
1268 case OpCode.OP_SHA256:
1269 case OpCode.OP_HASH160:
1270 case OpCode.OP_HASH256:
1271 {
1272 // (in -- hash)
1273 if (this.stack.length < 1) {
1274 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1275 return false
1276 }
1277 let buf = this.stack[this.stack.length - 1]
1278 // valtype vchnew Hash((opCode == OpCode.OP_RIPEMD160 || opCode == OpCode.OP_SHA1 || opCode == OpCode.OP_HASH160) ? 20 : 32)
1279 let bufHash
1280 if (opCodeNum === OpCode.OP_RIPEMD160) {
1281 bufHash = Hash.ripemd160(buf)
1282 } else if (opCodeNum === OpCode.OP_SHA1) {
1283 bufHash = Hash.sha1(buf)
1284 } else if (opCodeNum === OpCode.OP_SHA256) {
1285 bufHash = Hash.sha256(buf)
1286 } else if (opCodeNum === OpCode.OP_HASH160) {
1287 bufHash = Hash.sha256Ripemd160(buf)
1288 } else if (opCodeNum === OpCode.OP_HASH256) {
1289 bufHash = Hash.sha256Sha256(buf)
1290 }
1291 this.stack.pop()
1292 this.stack.push(bufHash)
1293 }
1294 break
1295
1296 case OpCode.OP_CODESEPARATOR:
1297 // Hash starts after the code separator
1298 this.pBeginCodeHash = this.pc
1299 break
1300
1301 case OpCode.OP_CHECKSIG:
1302 case OpCode.OP_CHECKSIGVERIFY:
1303 {
1304 // (sig pubKey -- bool)
1305 if (this.stack.length < 2) {
1306 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1307 return false
1308 }
1309
1310 let bufSig = this.stack[this.stack.length - 2]
1311 let bufPubKey = this.stack[this.stack.length - 1]
1312
1313 // Subset of script starting at the most recent codeseparator
1314 // CScript scriptCode(pBeginCodeHash, pend)
1315 let subScript = new Script().fromObject({
1316 chunks: this.script.chunks.slice(this.pBeginCodeHash)
1317 })
1318
1319 // https://github.com/Bitcoin-UAHF/spec/blob/master/replay-protected-sighash.md
1320 let nHashType =
1321 bufSig.length > 0 ? bufSig.readUInt8(bufSig.length - 1) : 0
1322 if (nHashType & Sig.SIGHASH_FORKID) {
1323 if (!(this.flags & Interp.SCRIPT_ENABLE_SIGHASH_FORKID)) {
1324 this.errStr = 'SCRIPT_ERR_ILLEGAL_FORKID'
1325 return false
1326 }
1327 } else {
1328 subScript.findAndDelete(new Script().writeBuffer(bufSig))
1329 }
1330
1331 if (
1332 !this.checkSigEncoding(bufSig) ||
1333 !this.checkPubKeyEncoding(bufPubKey)
1334 ) {
1335 // serror is set
1336 return false
1337 }
1338
1339 let fSuccess
1340 try {
1341 let sig = new Sig().fromTxFormat(bufSig)
1342 let pubKey = new PubKey().fromBuffer(bufPubKey, false)
1343 fSuccess = this.tx.verify(
1344 sig,
1345 pubKey,
1346 this.nIn,
1347 subScript,
1348 Boolean(this.flags & Interp.SCRIPT_VERIFY_LOW_S),
1349 this.valueBn,
1350 this.flags
1351 )
1352 } catch (e) {
1353 // invalid sig or pubKey
1354 fSuccess = false
1355 }
1356
1357 this.stack.pop()
1358 this.stack.pop()
1359 // stack.push_back(fSuccess ? vchTrue : vchFalse)
1360 this.stack.push(fSuccess ? Interp.true : Interp.false)
1361 if (opCodeNum === OpCode.OP_CHECKSIGVERIFY) {
1362 if (fSuccess) {
1363 this.stack.pop()
1364 } else {
1365 this.errStr = 'SCRIPT_ERR_CHECKSIGVERIFY'
1366 return false
1367 }
1368 }
1369 }
1370 break
1371
1372 case OpCode.OP_CHECKMULTISIG:
1373 case OpCode.OP_CHECKMULTISIGVERIFY:
1374 {
1375 // ([sig ...] num_of_signatures [pubKey ...] num_of_pubKeys -- bool)
1376
1377 let i = 1
1378 if (this.stack.length < i) {
1379 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1380 return false
1381 }
1382
1383 let nKeysCount = new Bn()
1384 .fromScriptNumBuffer(
1385 this.stack[this.stack.length - i],
1386 fRequireMinimal
1387 )
1388 .toNumber()
1389 if (nKeysCount < 0 || nKeysCount > 20) {
1390 this.errStr = 'SCRIPT_ERR_PUBKEY_COUNT'
1391 return false
1392 }
1393 this.nOpCount += nKeysCount
1394 if (this.nOpCount > 201) {
1395 this.errStr = 'SCRIPT_ERR_OP_COUNT'
1396 return false
1397 }
1398 // int ikey = ++i
1399 let ikey = ++i
1400 i += nKeysCount
1401 if (this.stack.length < i) {
1402 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1403 return false
1404 }
1405
1406 let nSigsCount = new Bn()
1407 .fromScriptNumBuffer(
1408 this.stack[this.stack.length - i],
1409 fRequireMinimal
1410 )
1411 .toNumber()
1412 if (nSigsCount < 0 || nSigsCount > nKeysCount) {
1413 this.errStr = 'SCRIPT_ERR_SIG_COUNT'
1414 return false
1415 }
1416 // int isig = ++i
1417 let isig = ++i
1418 i += nSigsCount
1419 if (this.stack.length < i) {
1420 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1421 return false
1422 }
1423
1424 // Subset of script starting at the most recent codeseparator
1425 let subScript = new Script().fromObject({
1426 chunks: this.script.chunks.slice(this.pBeginCodeHash)
1427 })
1428
1429 for (let k = 0; k < nSigsCount; k++) {
1430 let bufSig = this.stack[this.stack.length - isig - k]
1431
1432 // https://github.com/Bitcoin-UAHF/spec/blob/master/replay-protected-sighash.md
1433 let nHashType =
1434 bufSig.length > 0 ? bufSig.readUInt8(bufSig.length - 1) : 0
1435 if (nHashType & Sig.SIGHASH_FORKID) {
1436 if (!(this.flags & Interp.SCRIPT_ENABLE_SIGHASH_FORKID)) {
1437 this.errStr = 'SCRIPT_ERR_ILLEGAL_FORKID'
1438 return false
1439 }
1440 } else {
1441 // Drop the signature, since there's no way for a signature to sign itself
1442 subScript.findAndDelete(new Script().writeBuffer(bufSig))
1443 }
1444 }
1445
1446 let fSuccess = true
1447 while (fSuccess && nSigsCount > 0) {
1448 // valtype& vchSig = stacktop(-isig)
1449 let bufSig = this.stack[this.stack.length - isig]
1450 // valtype& vchPubKey = stacktop(-ikey)
1451 let bufPubKey = this.stack[this.stack.length - ikey]
1452
1453 if (
1454 !this.checkSigEncoding(bufSig) ||
1455 !this.checkPubKeyEncoding(bufPubKey)
1456 ) {
1457 // serror is set
1458 return false
1459 }
1460
1461 let fOk
1462 try {
1463 let sig = new Sig().fromTxFormat(bufSig)
1464 let pubKey = new PubKey().fromBuffer(bufPubKey, false)
1465 fOk = this.tx.verify(
1466 sig,
1467 pubKey,
1468 this.nIn,
1469 subScript,
1470 Boolean(this.flags & Interp.SCRIPT_VERIFY_LOW_S),
1471 this.valueBn,
1472 this.flags
1473 )
1474 } catch (e) {
1475 // invalid sig or pubKey
1476 fOk = false
1477 }
1478
1479 if (fOk) {
1480 isig++
1481 nSigsCount--
1482 }
1483 ikey++
1484 nKeysCount--
1485
1486 // If there are more signatures left than keys left,
1487 // then too many signatures have failed
1488 if (nSigsCount > nKeysCount) {
1489 fSuccess = false
1490 }
1491 }
1492
1493 // Clean up stack of actual arguments
1494 while (i-- > 1) {
1495 this.stack.pop()
1496 }
1497
1498 // A bug causes CHECKMULTISIG to consume one extra argument
1499 // whose contents were not checked in any way.
1500 //
1501 // Unfortunately this is a potential source of mutability,
1502 // so optionally verify it is exactly equal to zero prior
1503 // to removing it from the stack.
1504 if (this.stack.length < 1) {
1505 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1506 return false
1507 }
1508 if (
1509 this.flags & Interp.SCRIPT_VERIFY_NULLDUMMY &&
1510 this.stack[this.stack.length - 1].length
1511 ) {
1512 this.errStr = 'SCRIPT_ERR_SIG_NULLDUMMY'
1513 return false
1514 }
1515 this.stack.pop()
1516
1517 // stack.push_back(fSuccess ? vchTrue : vchFalse)
1518 this.stack.push(fSuccess ? Interp.true : Interp.false)
1519
1520 if (opCodeNum === OpCode.OP_CHECKMULTISIGVERIFY) {
1521 if (fSuccess) {
1522 this.stack.pop()
1523 } else {
1524 this.errStr = 'SCRIPT_ERR_CHECKMULTISIGVERIFY'
1525 return false
1526 }
1527 }
1528 }
1529 break
1530
1531 //
1532 // Byte string operations
1533 //
1534 case OpCode.OP_CAT:
1535 if (this.stack.length < 2) {
1536 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1537 return false
1538 }
1539
1540 let vch1 = this.stack[this.stack.length - 2]
1541 let vch2 = this.stack[this.stack.length - 1]
1542
1543 this.stack[this.stack.length - 2] = Buffer.concat([vch1, vch2])
1544 this.stack.pop()
1545 break
1546
1547 case OpCode.OP_SPLIT:
1548 if (this.stack.length < 2) {
1549 this.errStr = 'SCRIPT_ERR_INVALID_STACK_OPERATION'
1550 return false
1551 }
1552
1553 let data = this.stack[this.stack.length - 2]
1554 let position = new Bn().fromScriptNumBuffer(
1555 this.stack[this.stack.length - 1],
1556 fRequireMinimal
1557 )
1558
1559 if(position.lt(0) || position.gt(data.length)) {
1560 this.errStr = 'SCRIPT_ERR_INVALID_SPLIT_RANGE'
1561 return false
1562 }
1563
1564 let n1 = data.slice(0, position)
1565 let n2 = data.slice(position)
1566
1567 this.stack.pop()
1568 this.stack.pop()
1569
1570 this.stack.push(n1)
1571 this.stack.push(n2)
1572
1573 break
1574
1575 default:
1576 this.errStr = 'SCRIPT_ERR_BAD_OPCODE'
1577 return false
1578 }
1579 }
1580
1581 return true
1582 }
1583
1584 /**
1585 * This function has the same interface as bitcoin core's VerifyScript and is
1586 * the function you want to use to know if a particular input in a
1587 * transaction is valid or not. It simply iterates over the results generated
1588 * by the results method.
1589 */
1590 verify (scriptSig, scriptPubKey, tx, nIn, flags, valueBn) {
1591 let results = this.results(
1592 scriptSig,
1593 scriptPubKey,
1594 tx,
1595 nIn,
1596 flags,
1597 valueBn
1598 )
1599 for (let success of results) {
1600 if (!success) {
1601 return false
1602 }
1603 }
1604 return true
1605 }
1606
1607 /**
1608 * Gives you the results of the execution each operation of the scripSig and
1609 * scriptPubKey corresponding to a particular input (nIn) for the concerned
1610 * transaction (tx). Each result can be either true or false. If true, then
1611 * the operation did not invalidate the transaction. If false, then the
1612 * operation has invalidated the script, and the transaction is not valid.
1613 * flags is a number that can pass in some special flags, such as whether or
1614 * not to execute the redeemScript in a p2sh transaction.
1615 *
1616 * This method is translated from bitcoin core's VerifyScript. This function
1617 * is a generator, thus you can and need to iterate through it. To
1618 * automatically return true or false, use the verify method.
1619 */
1620 * results (scriptSig, scriptPubKey, tx, nIn, flags, valueBn) {
1621 let stackCopy
1622
1623 this.fromObject({
1624 script: scriptSig,
1625 tx: tx,
1626 nIn: nIn,
1627 flags: flags,
1628 valueBn: valueBn
1629 })
1630
1631 if (
1632 (flags & Interp.SCRIPT_VERIFY_SIGPUSHONLY) !== 0 &&
1633 !scriptSig.isPushOnly()
1634 ) {
1635 this.errStr = this.errStr || 'SCRIPT_ERR_SIG_PUSHONLY'
1636 yield false
1637 }
1638
1639 yield * this.eval()
1640
1641 if (flags & Interp.SCRIPT_VERIFY_P2SH) {
1642 stackCopy = this.stack.slice()
1643 }
1644
1645 let stack = this.stack
1646 this.initialize()
1647 this.fromObject({
1648 script: scriptPubKey,
1649 stack: stack,
1650 tx: tx,
1651 nIn: nIn,
1652 flags: flags,
1653 valueBn: valueBn
1654 })
1655
1656 yield * this.eval()
1657
1658 if (this.stack.length === 0) {
1659 this.errStr = this.errStr || 'SCRIPT_ERR_EVAL_FALSE'
1660 yield false
1661 }
1662
1663 let buf = this.stack[this.stack.length - 1]
1664 if (!Interp.castToBool(buf)) {
1665 this.errStr = this.errStr || 'SCRIPT_ERR_EVAL_FALSE'
1666 yield false
1667 }
1668
1669 // Additional validation for spend-to-script-hash transactions:
1670 if (flags & Interp.SCRIPT_VERIFY_P2SH && scriptPubKey.isScriptHashOut()) {
1671 // scriptSig must be literals-only or validation fails
1672 if (!scriptSig.isPushOnly()) {
1673 this.errStr = this.errStr || 'SCRIPT_ERR_SIG_PUSHONLY'
1674 yield false
1675 }
1676
1677 // Restore stack.
1678 let tmp = stack
1679 stack = stackCopy
1680 stackCopy = tmp
1681
1682 // stack cannot be empty here, because if it was the
1683 // P2SH HASH <> EQUAL scriptPubKey would be evaluated with
1684 // an empty stack and the EvalScript above would yield false.
1685 if (stack.length === 0) {
1686 throw new Error('internal error - stack copy empty')
1687 }
1688
1689 let pubKeySerialized = stack[stack.length - 1]
1690 let scriptPubKey2 = new Script().fromBuffer(pubKeySerialized)
1691 stack.pop()
1692
1693 this.initialize()
1694 this.fromObject({
1695 script: scriptPubKey2,
1696 stack: stack,
1697 tx: tx,
1698 nIn: nIn,
1699 flags: flags,
1700 valueBn: valueBn
1701 })
1702
1703 yield * this.eval()
1704
1705 if (stack.length === 0) {
1706 this.errStr = this.errStr || 'SCRIPT_ERR_EVAL_FALSE'
1707 yield false
1708 }
1709
1710 if (!Interp.castToBool(stack[stack.length - 1])) {
1711 this.errStr = this.errStr || 'SCRIPT_ERR_EVAL_FALSE'
1712 yield false
1713 } else {
1714 yield true
1715 }
1716 }
1717
1718 // The CLEANSTACK check is only performed after potential P2SH evaluation,
1719 // as the non-P2SH evaluation of a P2SH script will obviously not result in
1720 // a clean stack (the P2SH inputs remain).
1721 if ((flags & Interp.SCRIPT_VERIFY_CLEANSTACK) !== 0) {
1722 // Disallow CLEANSTACK without P2SH, as otherwise a switch
1723 // CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a softfork
1724 // (and P2SH should be one).
1725 if (!(flags & Interp.SCRIPT_VERIFY_P2SH)) {
1726 throw new Error('cannot use CLEANSTACK without P2SH')
1727 }
1728 if (stack.length !== 1) {
1729 this.errStr = this.errStr || 'SCRIPT_ERR_CLEANSTACK'
1730 yield false
1731 }
1732 }
1733
1734 yield true
1735 }
1736
1737 /**
1738 * If the script has failed, this methods returns valuable debug
1739 * information about exactly where the script failed. It is a
1740 * JSON-compatible object so it can be easily stringified. pc refers to the
1741 * currently executing opcode.
1742 */
1743 getDebugObject () {
1744 let pc = this.pc - 1 // pc is incremented immediately after getting
1745 return {
1746 errStr: this.errStr,
1747 scriptStr: this.script ? this.script.toString() : 'no script found',
1748 pc: pc,
1749 stack: this.stack.map(buf => buf.toString('hex')),
1750 altStack: this.altStack.map(buf => buf.toString('hex')),
1751 opCodeStr: this.script
1752 ? OpCode.fromNumber(this.script.chunks[pc].opCodeNum).toString()
1753 : 'no script found'
1754 }
1755 }
1756
1757 getDebugString () {
1758 return JSON.stringify(this.getDebugObject(), null, 2)
1759 }
1760 }
1761
1762 Interp.true = Buffer.from([1])
1763 Interp.false = Buffer.from([])
1764
1765 Interp.MAX_SCRIPT_ELEMENT_SIZE = 520
1766 Interp.LOCKTIME_THRESHOLD = 500000000 // Tue Nov 5 00:53:20 1985 UTC
1767
1768 // flags taken from bitcoin core
1769 // bitcoin core commit: b5d1b1092998bc95313856d535c632ea5a8f9104
1770 Interp.SCRIPT_VERIFY_NONE = 0
1771
1772 // Evaluate P2SH subScripts (softfork safe, Bip16).
1773 Interp.SCRIPT_VERIFY_P2SH = 1 << 0
1774
1775 // Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
1776 // Passing a pubKey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubKey to be
1777 // skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT).
1778 Interp.SCRIPT_VERIFY_STRICTENC = 1 << 1
1779
1780 // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, Bip62 rule 1)
1781 Interp.SCRIPT_VERIFY_DERSIG = 1 << 2
1782
1783 // Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
1784 // (softfork safe, Bip62 rule 5).
1785 Interp.SCRIPT_VERIFY_LOW_S = 1 << 3
1786
1787 // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, Bip62 rule 7).
1788 Interp.SCRIPT_VERIFY_NULLDUMMY = 1 << 4
1789
1790 // Using a non-push operator in the scriptSig causes script failure (softfork safe, Bip62 rule 2).
1791 Interp.SCRIPT_VERIFY_SIGPUSHONLY = 1 << 5
1792
1793 // Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
1794 // pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
1795 // any other push causes the script to fail (Bip62 rule 3).
1796 // In addition, whenever a stack element is interpreted as a number, it must be of minimal length (Bip62 rule 4).
1797 // (softfork safe)
1798 Interp.SCRIPT_VERIFY_MINIMALDATA = 1 << 6
1799
1800 // Discourage use of NOPs reserved for upgrades (NOP1-10)
1801 //
1802 // Provided so that nodes can avoid accepting or mining transactions
1803 // containing executed NOP's whose meaning may change after a soft-fork,
1804 // thus rendering the script invalid; with this flag set executing
1805 // discouraged NOPs fails the script. This verification flag will never be
1806 // a mandatory flag applied to scripts in a block. NOPs that are not
1807 // executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
1808 Interp.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = 1 << 7
1809
1810 // Require that only a single stack element remains after evaluation. This
1811 // changes the success criterion from "At least one stack element must
1812 // remain, and when interpreted as a boolean, it must be true" to "Exactly
1813 // one stack element must remain, and when interpreted as a boolean, it must
1814 // be true". (softfork safe, Bip62 rule 6)
1815 // Note: CLEANSTACK should never be used without P2SH.
1816 Interp.SCRIPT_VERIFY_CLEANSTACK = 1 << 8
1817
1818 // Verify CHECKLOCKTIMEVERIFY
1819 //
1820 // See Bip65 for details.
1821 Interp.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = 1 << 9
1822
1823 // support CHECKSEQUENCEVERIFY opCode
1824 //
1825 // See Bip112 for details
1826 Interp.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = 1 << 10
1827
1828 // used for UAHF
1829 // https://github.com/Bitcoin-UAHF/spec/blob/master/replay-protected-sighash.md
1830 Interp.SCRIPT_ENABLE_SIGHASH_FORKID = 1 << 16
1831
1832 // These are the things we wish to verify by default. At the time of writing,
1833 // P2SH and CHECKLOCKTIMEVERIFY are both active, but CHECKSEQUENCEVERIFY is
1834 // not.
1835 Interp.defaultFlags =
1836 Interp.SCRIPT_VERIFY_P2SH | Interp.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
1837 // Interp.defaultFlags = Interp.SCRIPT_VERIFY_P2SH | Interp.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | Interp.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY
1838
1839export { Interp }