diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index f38b8036..300eebf9 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -144,416 +144,533 @@ script.execute = function execute(s, stack, tx, index) { if (Array.isArray(o)) { stack.push(o); - } else if (typeof o === 'number' && o >= 1 && o <= 16) { + continue; + } + + if (typeof o === 'number' && o >= 1 && o <= 16) { stack.push([o]); - } else if (o === 'dup') { - if (stack.length === 0) - return false; + continue; + } - stack.push(stack[stack.length - 1]); - } else if (o === 'drop') { - if (stack.length === 0) - return false; + switch (o) { + case 'dup': { + if (stack.length === 0) + return false; - stack.pop(); - } else if (o === 'nop1' || o === 'nop3' || o === 'nop4' - || o === 'nop5' || o === 'nop6' || o === 'nop7' - || o === 'nop8' || o === 'nop9' || o === 'nop10') { - ; - // OP_EVAL - // if (o === 'nop1') { - // var evalScript = script.decode(stack.pop()); - // if (!Array.isArray(evalScript)) - // return false; - // var res = script.execute(evalScript, stack, tx, index); - // if (!res) - // return false; - // } - } else if (o === 'verify') { - if (stack.length === 0) - return false; - if (new bn(stack[stack.length - 1]).cmp(0) === 0) - return false; - } else if (o === 'return') { - return false; - } else if (o === 'toaltstack') { - if (stack.length === 0) - return false; - stack.alt.push(stack.pop()); - } else if (o === 'fromaltstack') { - if (stack.alt.length === 0) - return false; - stack.push(stack.alt.pop()); - } else if (o === 'ifdup') { - if (stack.length === 0) - return false; - if (new bn(stack[stack.length - 1]).cmp(0) !== 0) - stack.push(new bn(stack[stack.length - 1]).toArray()); - } else if (o === 'depth') { - stack.push(new bn(stack.length).toArray()); - } else if (o === 'nip') { - if (stack.length < 2) - return false; - stack.splice(stack.length - 2, 1); - } else if (o === 'over') { - if (stack.length < 2) - return false; - stack.push(stack[stack.length - 2]); - } else if (o === 'pick' || o === 'roll') { - if (stack.length < 2) - return false; - var n = new bn(stack.pop()).toNumber(); - if (n < 0 || n >= stack.length) - return false; - var v = stack[-n - 1]; - if (o === 'roll') - stack.splice(stack.length - n - 1, 1); - stack.push(v); - } else if (o === 'rot') { - if (stack.length < 3) - return false; - var v3 = stack[stack.length - 3]; - var v2 = stack[stack.length - 2]; - var v1 = stack[stack.length - 1]; - stack[stack.length - 3] = v2; - stack[stack.length - 2] = v3; + stack.push(stack[stack.length - 1]); - v2 = stack[stack.length - 2]; - stack[stack.length - 2] = v1; - stack[stack.length - 1] = v2; - } else if (o === 'swap') { - if (stack.length < 2) + break; + } + case 'drop': { + if (stack.length === 0) + return false; + + stack.pop(); + + break; + } + case 'nop1': + case 'nop3': + case 'nop4': + case 'nop5': + case 'nop6': + case 'nop7': + case 'nop8': + case 'nop9': + case 'nop10': { + ; + // OP_EVAL + // if (o === 'nop1') { + // var evalScript = script.decode(stack.pop()); + // if (!Array.isArray(evalScript)) + // return false; + // var res = script.execute(evalScript, stack, tx, index); + // if (!res) + // return false; + // } + break; + } + case 'verify': { + if (stack.length === 0) + return false; + if (new bn(stack[stack.length - 1]).cmp(0) === 0) + return false; + + break; + } + case 'ret': { return false; - var v2 = stack[stack.length - 2]; - var v1 = stack[stack.length - 1]; - stack[stack.length - 2] = v1; - stack[stack.length - 1] = v2; - } else if (o === 'tuck') { - if (stack.length < 2) - return false; - stack.splice(stack.length - 2, 0, stack[stack.length - 1]); - } else if (o === 'drop2') { - if (stack.length < 2) - return false; - stack.pop(); - stack.pop(); - } else if (o === 'dup2') { - if (stack.length < 2) - return false; - var v1 = stack[stack.length - 1]; - var v2 = stack[stack.length - 2]; - stack.push(v1); - stack.push(v2); - } else if (o === 'dup3') { - if (stack.length < 3) - return false; - var v1 = stack[stack.length - 1]; - var v2 = stack[stack.length - 2]; - var v3 = stack[stack.length - 3]; - stack.push(v1); - stack.push(v2); - stack.push(v3); - } else if (o === 'over2') { - if (stack.length < 4) - return false; - var v1 = stack[stack.length - 4]; - var v2 = stack[stack.length - 3]; - stack.push(v1); - stack.push(v2); - } else if (o === 'rot2') { - if (stack.length < 6) - return false; - var v1 = stack[stack.length - 6]; - var v2 = stack[stack.length - 5]; - stack.splice(stack.length - 6, 2); - stack.push(v1); - stack.push(v2); - } else if (o === 'swap2') { - if (stack.length < 4) - return false; - var v4 = stack[stack.length - 4]; - var v3 = stack[stack.length - 3]; - var v2 = stack[stack.length - 2]; - var v1 = stack[stack.length - 1]; - stack[stack.length - 4] = v2; - stack[stack.length - 2] = v4; - stack[stack.length - 3] = v1; - stack[stack.length - 1] = v3; - } else if (o === 'size') { - if (stack.length < 1) - return false; - stack.push(new bn(stack[stack.length - 1].length || 0).toArray()); - } else if (o === 'add1' - || o === 'sub1' - || o === 'negate' - || o === 'abs' - || o === 'not' - || o === 'noteq0') { - if (stack.length < 1) - return false; - var n = new bn(stack.pop()); - switch (o) { - case 'add1': - n.iadd(1); - break; - case 'sub1': - n.isub(1); - break; - case 'negate': - n = n.neg(); - break; - case 'abs': - if (n.cmp(0) < 0) + } + case 'toaltstack': { + if (stack.length === 0) + return false; + stack.alt.push(stack.pop()); + + break; + } + case 'fromaltstack': { + if (stack.alt.length === 0) + return false; + stack.push(stack.alt.pop()); + + break; + } + case 'ifdup': { + if (stack.length === 0) + return false; + if (new bn(stack[stack.length - 1]).cmp(0) !== 0) + stack.push(new bn(stack[stack.length - 1]).toArray()); + + break; + } + case 'depth': { + stack.push(new bn(stack.length).toArray()); + + break; + } + case 'nip': { + if (stack.length < 2) + return false; + stack.splice(stack.length - 2, 1); + + break; + } + case 'over': { + if (stack.length < 2) + return false; + stack.push(stack[stack.length - 2]); + + break; + } + case 'pick': + case 'roll': { + if (stack.length < 2) + return false; + var n = new bn(stack.pop()).toNumber(); + if (n < 0 || n >= stack.length) + return false; + var v = stack[-n - 1]; + if (o === 'roll') + stack.splice(stack.length - n - 1, 1); + stack.push(v); + + break; + } + case 'rot': { + if (stack.length < 3) + return false; + var v3 = stack[stack.length - 3]; + var v2 = stack[stack.length - 2]; + var v1 = stack[stack.length - 1]; + stack[stack.length - 3] = v2; + stack[stack.length - 2] = v3; + + v2 = stack[stack.length - 2]; + stack[stack.length - 2] = v1; + stack[stack.length - 1] = v2; + + break; + } + case 'swap': { + if (stack.length < 2) + return false; + var v2 = stack[stack.length - 2]; + var v1 = stack[stack.length - 1]; + stack[stack.length - 2] = v1; + stack[stack.length - 1] = v2; + + break; + } + case 'tuck': { + if (stack.length < 2) + return false; + stack.splice(stack.length - 2, 0, stack[stack.length - 1]); + + break; + } + case 'drop2': { + if (stack.length < 2) + return false; + stack.pop(); + stack.pop(); + + break; + } + case 'dup2': { + if (stack.length < 2) + return false; + var v1 = stack[stack.length - 1]; + var v2 = stack[stack.length - 2]; + stack.push(v1); + stack.push(v2); + + break; + } + case 'dup3': { + if (stack.length < 3) + return false; + var v1 = stack[stack.length - 1]; + var v2 = stack[stack.length - 2]; + var v3 = stack[stack.length - 3]; + stack.push(v1); + stack.push(v2); + stack.push(v3); + + break; + } + case 'over2': { + if (stack.length < 4) + return false; + var v1 = stack[stack.length - 4]; + var v2 = stack[stack.length - 3]; + stack.push(v1); + stack.push(v2); + + break; + } + case 'rot2': { + if (stack.length < 6) + return false; + var v1 = stack[stack.length - 6]; + var v2 = stack[stack.length - 5]; + stack.splice(stack.length - 6, 2); + stack.push(v1); + stack.push(v2); + + break; + } + case 'swap2': { + if (stack.length < 4) + return false; + var v4 = stack[stack.length - 4]; + var v3 = stack[stack.length - 3]; + var v2 = stack[stack.length - 2]; + var v1 = stack[stack.length - 1]; + stack[stack.length - 4] = v2; + stack[stack.length - 2] = v4; + stack[stack.length - 3] = v1; + stack[stack.length - 1] = v3; + + break; + } + case 'size': { + if (stack.length < 1) + return false; + stack.push(new bn(stack[stack.length - 1].length || 0).toArray()); + + break; + } + case 'add1': + case 'sub1': + case 'negate': + case 'abs': + case 'not': + case 'noteq0': { + if (stack.length < 1) + return false; + var n = new bn(stack.pop()); + switch (o) { + case 'add1': + n.iadd(1); + break; + case 'sub1': + n.isub(1); + break; + case 'negate': n = n.neg(); - break; - case 'not': - n = n.cmp(0) === 0; - break; - case 'noteq0': - n = n.cmp(0) !== 0; - break; - default: - return false; - } - stack.push(n.toArray()); - } else if (o === 'add' - || o === 'sub' - || o === 'booland' - || o === 'boolor' - || o === 'numeq' - || o === 'numeqverify' - || o === 'numneq' - || o === 'lt' - || o === 'gt' - || o === 'lte' - || o === 'gte' - || o === 'min' - || o === 'max') { - switch (o) { - case 'add': - case 'sub': - case 'booland': - case 'boolor': - case 'numeq': - case 'numeqverify': - case 'numneq': - case 'lt': - case 'gt': - case 'lte': - case 'gte': - case 'min': - case 'max': - if (stack.length < 2) + break; + case 'abs': + if (n.cmp(0) < 0) + n = n.neg(); + break; + case 'not': + n = n.cmp(0) === 0; + break; + case 'noteq0': + n = n.cmp(0) !== 0; + break; + default: return false; - var n2 = new bn(stack.pop()); - var n1 = new bn(stack.pop()); - var n = new bn(0); - switch (o) { - case 'add': - n = n1.add(b2); - break; - case 'sub': - n = n1.sub(n2); - break; - case 'booland': - n = n1.cmp(0) !== 0 && n2.cmp(0) !== 0; - break; - case 'boolor': - n = n1.cmp(0) !== 0 || n2.cmp(0) !== 0; - break; - case 'numeq': - n = n1.cmp(n2) === 0; - break; - case 'numeqverify': - n = n1.cmp(n2) === 0; - break; - case 'numneq': - n = n1.cmp(n2) !== 0; - break; - case 'lt': - n = n1.cmp(n2) < 0; - break; - case 'gt': - n = n1.cmp(n2) > 0; - break; - case 'lte': - n = n1.cmp(n2) <= 0; - break; - case 'gte': - n = n1.cmp(n2) >= 0; - break; - case 'min': - n = n1.cmp(n2) < 0 ? n1 : n2; - break; - case 'max': - n = n1.cmp(n2) > 0 ? n1 : n2; - break; - default: + } + stack.push(n.toArray()); + + break; + } + case 'add': + case 'sub': + case 'booland': + case 'boolor': + case 'numeq': + case 'numeqverify': + case 'numneq': + case 'lt': + case 'gt': + case 'lte': + case 'gte': + case 'min': + case 'max': { + switch (o) { + case 'add': + case 'sub': + case 'booland': + case 'boolor': + case 'numeq': + case 'numeqverify': + case 'numneq': + case 'lt': + case 'gt': + case 'lte': + case 'gte': + case 'min': + case 'max': + if (stack.length < 2) return false; - } - var res = n.cmp(0) !== 0; - if (o === 'numeqverify') { - if (!res) + var n2 = new bn(stack.pop()); + var n1 = new bn(stack.pop()); + var n = new bn(0); + switch (o) { + case 'add': + n = n1.add(b2); + break; + case 'sub': + n = n1.sub(n2); + break; + case 'booland': + n = n1.cmp(0) !== 0 && n2.cmp(0) !== 0; + break; + case 'boolor': + n = n1.cmp(0) !== 0 || n2.cmp(0) !== 0; + break; + case 'numeq': + n = n1.cmp(n2) === 0; + break; + case 'numeqverify': + n = n1.cmp(n2) === 0; + break; + case 'numneq': + n = n1.cmp(n2) !== 0; + break; + case 'lt': + n = n1.cmp(n2) < 0; + break; + case 'gt': + n = n1.cmp(n2) > 0; + break; + case 'lte': + n = n1.cmp(n2) <= 0; + break; + case 'gte': + n = n1.cmp(n2) >= 0; + break; + case 'min': + n = n1.cmp(n2) < 0 ? n1 : n2; + break; + case 'max': + n = n1.cmp(n2) > 0 ? n1 : n2; + break; + default: + return false; + } + var res = n.cmp(0) !== 0; + if (o === 'numeqverify') { + if (!res) + return false; + } else { + stack.push(n.toArray()); + // stack.push(res ? [ 1 ] : []); + } + break; + case 'within': + if (stack.length < 3) return false; - } else { - stack.push(n.toArray()); - // stack.push(res ? [ 1 ] : []); - } - break; - case 'within': - if (stack.length < 3) + var n3 = new bn(stack.pop()); + var n2 = new bn(stack.pop()); + var n1 = new bn(stack.pop()); + var val = n2.cmp(n1) <= 0 && n1.cmp(n3) < 0; + stack.push(val.cmp(0) !== 0 ? [ 1 ] : []); + break; + } + + break; + } + case 'codesep': { + lastSep = pc; + + break; + } + case 'ripemd160': { + if (stack.length === 0) + return false; + stack.push(utils.ripemd160(stack.pop())); + + break; + } + case 'sha1': { + if (stack.length === 0) + return false; + stack.push(utils.sha1(stack.pop())); + + break; + } + case 'sha256': { + if (stack.length === 0) + return false; + stack.push(utils.sha256(stack.pop())); + + break; + } + case 'hash256': { + if (stack.length === 0) + return false; + stack.push(utils.dsha256(stack.pop())); + + break; + } + case 'hash160': { + if (stack.length === 0) + return false; + + stack.push(utils.ripesha(stack.pop())); + + break; + } + case 'eqverify': + case 'eq': { + if (stack.length < 2) + return false; + + var res = utils.isEqual(stack.pop(), stack.pop()); + if (o === 'eqverify') { + if (!res) return false; - var n3 = new bn(stack.pop()); - var n2 = new bn(stack.pop()); - var n1 = new bn(stack.pop()); - var val = n2.cmp(n1) <= 0 && n1.cmp(n3) < 0; - stack.push(val.cmp(0) !== 0 ? [ 1 ] : []); - break; + } else { + stack.push(res ? [ 1 ] : []); + } + + break; } - } else if (o === 'codesep') { - lastSep = pc; - } else if (o === 'ripemd160') { - if (stack.length === 0) - return false; - stack.push(utils.ripemd160(stack.pop())); - } else if (o === 'sha1') { - if (stack.length === 0) - return false; - stack.push(utils.sha1(stack.pop())); - } else if (o === 'sha256') { - if (stack.length === 0) - return false; - stack.push(utils.sha256(stack.pop())); - } else if (o === 'hash256') { - if (stack.length === 0) - return false; - stack.push(utils.dsha256(stack.pop())); - } else if (o === 'hash160') { - if (stack.length === 0) - return false; - - stack.push(utils.ripesha(stack.pop())); - } else if (o === 'eqverify' || o === 'eq') { - if (stack.length < 2) - return false; - - var res = utils.isEqual(stack.pop(), stack.pop()); - if (o === 'eqverify') { - if (!res) - return false; - } else { - stack.push(res ? [ 1 ] : []); - } - } else if (o === 'checksigverify' || o === 'checksig') { - if (!tx || stack.length < 2) - return false; - - var pub = stack.pop(); - var sig = stack.pop(); - var type = sig[sig.length - 1]; - if (!constants.rhashType[type & 0x7f]) - return false; - - if (!script.isValidSig(sig)) - return false; - - var subscript = s.slice(lastSep + 1); - var hash = tx.subscriptHash(index, subscript, type); - - var res = script.verify(hash, sig.slice(0, -1), pub); - if (o === 'checksigverify') { - if (!res) - return false; - } else { - stack.push(res ? [ 1 ] : []); - } - } else if (o === 'checkmultisigverify' || o === 'checkmultisig') { - if (!tx || stack.length < 3) - return false; - - var n = stack.pop(); - if (n.length !== 1 || !(1 <= n[0] && n[0] <= 3)) - return false; - n = n[0]; - - if (stack.length < n + 1) - return false; - - var keys = []; - for (var i = 0; i < n; i++) { - var key = stack.pop(); - if (!(33 <= key.length && key.length <= 65)) + case 'checksigverify': + case 'checksig': { + if (!tx || stack.length < 2) return false; - keys.push(key); - } - - var m = stack.pop(); - if (m.length !== 1 || !(1 <= m[0] && m[0] <= n)) - return false; - m = m[0]; - - if (stack.length < m + 1) - return false; - - // Get signatures - var succ = 0; - for (var i = 0; i < m; i++) { + var pub = stack.pop(); var sig = stack.pop(); var type = sig[sig.length - 1]; if (!constants.rhashType[type & 0x7f]) return false; - var subscript = s.slice(lastSep + 1); - var hash = tx.subscriptHash(index, subscript, type); - if (!script.isValidSig(sig)) return false; - // Strict order: - var res = script.verify(hash, sig.slice(0, -1), keys.pop()); - if (res) - succ++; + var subscript = s.slice(lastSep + 1); + var hash = tx.subscriptHash(index, subscript, type); + + var res = script.verify(hash, sig.slice(0, -1), pub); + if (o === 'checksigverify') { + if (!res) + return false; + } else { + stack.push(res ? [ 1 ] : []); + } + + break; } - - // Extra value - stack.pop(); - - var res = succ >= m; - if (o === 'checkmultisigverify') { - if (!res) + case 'checkmultisigverify': + case 'checkmultisig': { + if (!tx || stack.length < 3) return false; - } else { - stack.push(res ? [ 1 ] : []); + + var n = stack.pop(); + if (n.length !== 1 || !(1 <= n[0] && n[0] <= 3)) + return false; + n = n[0]; + + if (stack.length < n + 1) + return false; + + var keys = []; + for (var i = 0; i < n; i++) { + var key = stack.pop(); + if (!(33 <= key.length && key.length <= 65)) + return false; + + keys.push(key); + } + + var m = stack.pop(); + if (m.length !== 1 || !(1 <= m[0] && m[0] <= n)) + return false; + m = m[0]; + + if (stack.length < m + 1) + return false; + + // Get signatures + var succ = 0; + for (var i = 0; i < m; i++) { + var sig = stack.pop(); + var type = sig[sig.length - 1]; + if (!constants.rhashType[type & 0x7f]) + return false; + + var subscript = s.slice(lastSep + 1); + var hash = tx.subscriptHash(index, subscript, type); + + if (!script.isValidSig(sig)) + return false; + + // Strict order: + var res = script.verify(hash, sig.slice(0, -1), keys.pop()); + if (res) + succ++; + } + + // Extra value + stack.pop(); + + var res = succ >= m; + if (o === 'checkmultisigverify') { + if (!res) + return false; + } else { + stack.push(res ? [ 1 ] : []); + } + + break; } - } else if (o === 'checklocktimeverify') { - // input: [[], sig1, sig2, 1] - // prev_out: [[lock], 'checklocktimeverify', 'drop', - // 'dup', 'hash160', pubkey, 'equalverify', 'checksig'] - if (stack.length === 0) - return false; + case 'checklocktimeverify': { + // input: [[], sig1, sig2, 1] + // prev_out: [[lock], 'checklocktimeverify', 'drop', + // 'dup', 'hash160', pubkey, 'equalverify', 'checksig'] + if (stack.length === 0) + return false; - var lock = new bn(stack[stack.length - 1]).toNumber(); + var lock = new bn(stack[stack.length - 1]).toNumber(); - if (lock < 0) - return false; + if (lock < 0) + return false; - var threshold = constants.locktimeThreshold; - if (!( - (tx.lock < threshold && lock < threshold) || - (tx.lock >= threshold && lock >= threshold) - )) { + var threshold = constants.locktimeThreshold; + if (!( + (tx.lock < threshold && lock < threshold) || + (tx.lock >= threshold && lock >= threshold) + )) { + return false; + } + + if (lock > tx.lock) + return false; + + if (input.seq === 0xffffffff) + return false; + + break; + } + default: { + // Unknown operation return false; } - - if (lock > tx.lock) - return false; - - if (input.seq === 0xffffffff) - return false; - } else { - // Unknown operation - return false; } }