// Copyright (c) 2013-2015 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

import (
	"bytes"
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"hash"
	"math/big"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/fastsha256"
	"github.com/btcsuite/golangcrypto/ripemd160"
)

// An opcode defines the information related to a txscript opcode.
// opfunc if present is the function to call to perform the opcode on
// the script. The current script is passed in as a slice with the firs
// member being the opcode itself.
type opcode struct {
	value     byte
	name      string
	length    int
	opfunc    func(*parsedOpcode, *Engine) error
	parsefunc func(*opcode, *Engine, []byte) error
}

// These constants are the values of the official opcode used on the btc wiki,
// in bitcoind and in most if not all other references and software related to
// handling BTC scripts.
const (
	OP_FALSE               = 0 // AKA OP_0
	OP_0                   = 0
	OP_DATA_1              = 1
	OP_DATA_2              = 2
	OP_DATA_3              = 3
	OP_DATA_4              = 4
	OP_DATA_5              = 5
	OP_DATA_6              = 6
	OP_DATA_7              = 7
	OP_DATA_8              = 8
	OP_DATA_9              = 9
	OP_DATA_10             = 10
	OP_DATA_11             = 11
	OP_DATA_12             = 12
	OP_DATA_13             = 13
	OP_DATA_14             = 14
	OP_DATA_15             = 15
	OP_DATA_16             = 16
	OP_DATA_17             = 17
	OP_DATA_18             = 18
	OP_DATA_19             = 19
	OP_DATA_20             = 20
	OP_DATA_21             = 21
	OP_DATA_22             = 22
	OP_DATA_23             = 23
	OP_DATA_24             = 24
	OP_DATA_25             = 25
	OP_DATA_26             = 26
	OP_DATA_27             = 27
	OP_DATA_28             = 28
	OP_DATA_29             = 29
	OP_DATA_30             = 30
	OP_DATA_31             = 31
	OP_DATA_32             = 32
	OP_DATA_33             = 33
	OP_DATA_34             = 34
	OP_DATA_35             = 35
	OP_DATA_36             = 36
	OP_DATA_37             = 37
	OP_DATA_38             = 38
	OP_DATA_39             = 39
	OP_DATA_40             = 40
	OP_DATA_41             = 41
	OP_DATA_42             = 42
	OP_DATA_43             = 43
	OP_DATA_44             = 44
	OP_DATA_45             = 45
	OP_DATA_46             = 46
	OP_DATA_47             = 47
	OP_DATA_48             = 48
	OP_DATA_49             = 49
	OP_DATA_50             = 50
	OP_DATA_51             = 51
	OP_DATA_52             = 52
	OP_DATA_53             = 53
	OP_DATA_54             = 54
	OP_DATA_55             = 55
	OP_DATA_56             = 56
	OP_DATA_57             = 57
	OP_DATA_58             = 58
	OP_DATA_59             = 59
	OP_DATA_60             = 60
	OP_DATA_61             = 61
	OP_DATA_62             = 62
	OP_DATA_63             = 63
	OP_DATA_64             = 64
	OP_DATA_65             = 65
	OP_DATA_66             = 66
	OP_DATA_67             = 67
	OP_DATA_68             = 68
	OP_DATA_69             = 69
	OP_DATA_70             = 70
	OP_DATA_71             = 71
	OP_DATA_72             = 72
	OP_DATA_73             = 73
	OP_DATA_74             = 74
	OP_DATA_75             = 75
	OP_PUSHDATA1           = 76
	OP_PUSHDATA2           = 77
	OP_PUSHDATA4           = 78
	OP_1NEGATE             = 79
	OP_RESERVED            = 80
	OP_1                   = 81 // AKA OP_TRUE
	OP_TRUE                = 81
	OP_2                   = 82
	OP_3                   = 83
	OP_4                   = 84
	OP_5                   = 85
	OP_6                   = 86
	OP_7                   = 87
	OP_8                   = 88
	OP_9                   = 89
	OP_10                  = 90
	OP_11                  = 91
	OP_12                  = 92
	OP_13                  = 93
	OP_14                  = 94
	OP_15                  = 95
	OP_16                  = 96
	OP_NOP                 = 97
	OP_VER                 = 98
	OP_IF                  = 99
	OP_NOTIF               = 100
	OP_VERIF               = 101
	OP_VERNOTIF            = 102
	OP_ELSE                = 103
	OP_ENDIF               = 104
	OP_VERIFY              = 105
	OP_RETURN              = 106
	OP_TOALTSTACK          = 107
	OP_FROMALTSTACK        = 108
	OP_2DROP               = 109
	OP_2DUP                = 110
	OP_3DUP                = 111
	OP_2OVER               = 112
	OP_2ROT                = 113
	OP_2SWAP               = 114
	OP_IFDUP               = 115
	OP_DEPTH               = 116
	OP_DROP                = 117
	OP_DUP                 = 118
	OP_NIP                 = 119
	OP_OVER                = 120
	OP_PICK                = 121
	OP_ROLL                = 122
	OP_ROT                 = 123
	OP_SWAP                = 124
	OP_TUCK                = 125
	OP_CAT                 = 126
	OP_SUBSTR              = 127
	OP_LEFT                = 128
	OP_RIGHT               = 129
	OP_SIZE                = 130
	OP_INVERT              = 131
	OP_AND                 = 132
	OP_OR                  = 133
	OP_XOR                 = 134
	OP_EQUAL               = 135
	OP_EQUALVERIFY         = 136
	OP_RESERVED1           = 137
	OP_RESERVED2           = 138
	OP_1ADD                = 139
	OP_1SUB                = 140
	OP_2MUL                = 141
	OP_2DIV                = 142
	OP_NEGATE              = 143
	OP_ABS                 = 144
	OP_NOT                 = 145
	OP_0NOTEQUAL           = 146
	OP_ADD                 = 147
	OP_SUB                 = 148
	OP_MUL                 = 149
	OP_DIV                 = 150
	OP_MOD                 = 151
	OP_LSHIFT              = 152
	OP_RSHIFT              = 153
	OP_BOOLAND             = 154
	OP_BOOLOR              = 155
	OP_NUMEQUAL            = 156
	OP_NUMEQUALVERIFY      = 157
	OP_NUMNOTEQUAL         = 158
	OP_LESSTHAN            = 159
	OP_GREATERTHAN         = 160
	OP_LESSTHANOREQUAL     = 161
	OP_GREATERTHANOREQUAL  = 162
	OP_MIN                 = 163
	OP_MAX                 = 164
	OP_WITHIN              = 165
	OP_RIPEMD160           = 166
	OP_SHA1                = 167
	OP_SHA256              = 168
	OP_HASH160             = 169
	OP_HASH256             = 170
	OP_CODESEPARATOR       = 171
	OP_CHECKSIG            = 172
	OP_CHECKSIGVERIFY      = 173
	OP_CHECKMULTISIG       = 174
	OP_CHECKMULTISIGVERIFY = 175
	OP_NOP1                = 176
	OP_NOP2                = 177
	OP_NOP3                = 178
	OP_NOP4                = 179
	OP_NOP5                = 180
	OP_NOP6                = 181
	OP_NOP7                = 182
	OP_NOP8                = 183
	OP_NOP9                = 184
	OP_NOP10               = 185
	OP_UNKNOWN186          = 186
	OP_UNKNOWN187          = 187
	OP_UNKNOWN188          = 188
	OP_UNKNOWN189          = 189
	OP_UNKNOWN190          = 190
	OP_UNKNOWN191          = 191
	OP_UNKNOWN192          = 192
	OP_UNKNOWN193          = 193
	OP_UNKNOWN194          = 194
	OP_UNKNOWN195          = 195
	OP_UNKNOWN196          = 196
	OP_UNKNOWN197          = 197
	OP_UNKNOWN198          = 198
	OP_UNKNOWN199          = 199
	OP_UNKNOWN200          = 200
	OP_UNKNOWN201          = 201
	OP_UNKNOWN202          = 202
	OP_UNKNOWN203          = 203
	OP_UNKNOWN204          = 204
	OP_UNKNOWN205          = 205
	OP_UNKNOWN206          = 206
	OP_UNKNOWN207          = 207
	OP_UNKNOWN208          = 208
	OP_UNKNOWN209          = 209
	OP_UNKNOWN210          = 210
	OP_UNKNOWN211          = 211
	OP_UNKNOWN212          = 212
	OP_UNKNOWN213          = 213
	OP_UNKNOWN214          = 214
	OP_UNKNOWN215          = 215
	OP_UNKNOWN216          = 216
	OP_UNKNOWN217          = 217
	OP_UNKNOWN218          = 218
	OP_UNKNOWN219          = 219
	OP_UNKNOWN220          = 220
	OP_UNKNOWN221          = 221
	OP_UNKNOWN222          = 222
	OP_UNKNOWN223          = 223
	OP_UNKNOWN224          = 224
	OP_UNKNOWN225          = 225
	OP_UNKNOWN226          = 226
	OP_UNKNOWN227          = 227
	OP_UNKNOWN228          = 228
	OP_UNKNOWN229          = 229
	OP_UNKNOWN230          = 230
	OP_UNKNOWN231          = 231
	OP_UNKNOWN232          = 232
	OP_UNKNOWN233          = 233
	OP_UNKNOWN234          = 234
	OP_UNKNOWN235          = 235
	OP_UNKNOWN236          = 236
	OP_UNKNOWN237          = 237
	OP_UNKNOWN238          = 238
	OP_UNKNOWN239          = 239
	OP_UNKNOWN240          = 240
	OP_UNKNOWN241          = 241
	OP_UNKNOWN242          = 242
	OP_UNKNOWN243          = 243
	OP_UNKNOWN244          = 244
	OP_UNKNOWN245          = 245
	OP_UNKNOWN246          = 246
	OP_UNKNOWN247          = 247
	OP_UNKNOWN248          = 248
	OP_UNKNOWN249          = 249
	OP_UNKNOWN250          = 250
	OP_UNKNOWN251          = 251
	OP_UNKNOWN252          = 252
	OP_PUBKEYHASH          = 253 // bitcoind internal, for completeness
	OP_PUBKEY              = 254 // bitcoind internal, for completeness
	OP_INVALIDOPCODE       = 255 // bitcoind internal, for completeness
)

// conditional execution constants
const (
	OpCondFalse = 0
	OpCondTrue  = 1
	OpCondSkip  = 2
)

// Some of the functions in opcodemap call things that themselves then will
// reference the opcodemap to make decisions (things like op_checksig which
// needs to parse scripts to remove opcodes, for example).
// The go compiler is very conservative in this matter and will think there
// is an initialisation loop. In order to work around this we have the fake
// ``prevariable'' opcodemapPreinit and then set the real variable to the
// preinit in init()
var opcodemap map[byte]*opcode

func init() {
	opcodemap = opcodemapPreinit
}

var opcodemapPreinit = map[byte]*opcode{
	OP_FALSE: {value: OP_FALSE, name: "OP_0", length: 1,
		opfunc: opcodeFalse},
	OP_DATA_1: {value: OP_DATA_1, name: "OP_DATA_1", length: 2,
		opfunc: opcodePushData},
	OP_DATA_2: {value: OP_DATA_2, name: "OP_DATA_2", length: 3,
		opfunc: opcodePushData},
	OP_DATA_3: {value: OP_DATA_3, name: "OP_DATA_3", length: 4,
		opfunc: opcodePushData},
	OP_DATA_4: {value: OP_DATA_4, name: "OP_DATA_4", length: 5,
		opfunc: opcodePushData},
	OP_DATA_5: {value: OP_DATA_5, name: "OP_DATA_5", length: 6,
		opfunc: opcodePushData},
	OP_DATA_6: {value: OP_DATA_6, name: "OP_DATA_6", length: 7,
		opfunc: opcodePushData},
	OP_DATA_7: {value: OP_DATA_7, name: "OP_DATA_7", length: 8,
		opfunc: opcodePushData},
	OP_DATA_8: {value: OP_DATA_8, name: "OP_DATA_8", length: 9,
		opfunc: opcodePushData},
	OP_DATA_9: {value: OP_DATA_9, name: "OP_DATA_9", length: 10,
		opfunc: opcodePushData},
	OP_DATA_10: {value: OP_DATA_10, name: "OP_DATA_10", length: 11,
		opfunc: opcodePushData},
	OP_DATA_11: {value: OP_DATA_11, name: "OP_DATA_11", length: 12,
		opfunc: opcodePushData},
	OP_DATA_12: {value: OP_DATA_12, name: "OP_DATA_12", length: 13,
		opfunc: opcodePushData},
	OP_DATA_13: {value: OP_DATA_13, name: "OP_DATA_13", length: 14,
		opfunc: opcodePushData},
	OP_DATA_14: {value: OP_DATA_14, name: "OP_DATA_14", length: 15,
		opfunc: opcodePushData},
	OP_DATA_15: {value: OP_DATA_15, name: "OP_DATA_15", length: 16,
		opfunc: opcodePushData},
	OP_DATA_16: {value: OP_DATA_16, name: "OP_DATA_16", length: 17,
		opfunc: opcodePushData},
	OP_DATA_17: {value: OP_DATA_17, name: "OP_DATA_17", length: 18,
		opfunc: opcodePushData},
	OP_DATA_18: {value: OP_DATA_18, name: "OP_DATA_18", length: 19,
		opfunc: opcodePushData},
	OP_DATA_19: {value: OP_DATA_19, name: "OP_DATA_19", length: 20,
		opfunc: opcodePushData},
	OP_DATA_20: {value: OP_DATA_20, name: "OP_DATA_20", length: 21,
		opfunc: opcodePushData},
	OP_DATA_21: {value: OP_DATA_21, name: "OP_DATA_21", length: 22,
		opfunc: opcodePushData},
	OP_DATA_22: {value: OP_DATA_22, name: "OP_DATA_22", length: 23,
		opfunc: opcodePushData},
	OP_DATA_23: {value: OP_DATA_23, name: "OP_DATA_23", length: 24,
		opfunc: opcodePushData},
	OP_DATA_24: {value: OP_DATA_24, name: "OP_DATA_24", length: 25,
		opfunc: opcodePushData},
	OP_DATA_25: {value: OP_DATA_25, name: "OP_DATA_25", length: 26,
		opfunc: opcodePushData},
	OP_DATA_26: {value: OP_DATA_26, name: "OP_DATA_26", length: 27,
		opfunc: opcodePushData},
	OP_DATA_27: {value: OP_DATA_27, name: "OP_DATA_27", length: 28,
		opfunc: opcodePushData},
	OP_DATA_28: {value: OP_DATA_28, name: "OP_DATA_28", length: 29,
		opfunc: opcodePushData},
	OP_DATA_29: {value: OP_DATA_29, name: "OP_DATA_29", length: 30,
		opfunc: opcodePushData},
	OP_DATA_30: {value: OP_DATA_30, name: "OP_DATA_30", length: 31,
		opfunc: opcodePushData},
	OP_DATA_31: {value: OP_DATA_31, name: "OP_DATA_31", length: 32,
		opfunc: opcodePushData},
	OP_DATA_32: {value: OP_DATA_32, name: "OP_DATA_32", length: 33,
		opfunc: opcodePushData},
	OP_DATA_33: {value: OP_DATA_33, name: "OP_DATA_33", length: 34,
		opfunc: opcodePushData},
	OP_DATA_34: {value: OP_DATA_34, name: "OP_DATA_34", length: 35,
		opfunc: opcodePushData},
	OP_DATA_35: {value: OP_DATA_35, name: "OP_DATA_35", length: 36,
		opfunc: opcodePushData},
	OP_DATA_36: {value: OP_DATA_36, name: "OP_DATA_36", length: 37,
		opfunc: opcodePushData},
	OP_DATA_37: {value: OP_DATA_37, name: "OP_DATA_37", length: 38,
		opfunc: opcodePushData},
	OP_DATA_38: {value: OP_DATA_38, name: "OP_DATA_38", length: 39,
		opfunc: opcodePushData},
	OP_DATA_39: {value: OP_DATA_39, name: "OP_DATA_39", length: 40,
		opfunc: opcodePushData},
	OP_DATA_40: {value: OP_DATA_40, name: "OP_DATA_40", length: 41,
		opfunc: opcodePushData},
	OP_DATA_41: {value: OP_DATA_41, name: "OP_DATA_41", length: 42,
		opfunc: opcodePushData},
	OP_DATA_42: {value: OP_DATA_42, name: "OP_DATA_42", length: 43,
		opfunc: opcodePushData},
	OP_DATA_43: {value: OP_DATA_43, name: "OP_DATA_43", length: 44,
		opfunc: opcodePushData},
	OP_DATA_44: {value: OP_DATA_44, name: "OP_DATA_44", length: 45,
		opfunc: opcodePushData},
	OP_DATA_45: {value: OP_DATA_45, name: "OP_DATA_45", length: 46,
		opfunc: opcodePushData},
	OP_DATA_46: {value: OP_DATA_46, name: "OP_DATA_46", length: 47,
		opfunc: opcodePushData},
	OP_DATA_47: {value: OP_DATA_47, name: "OP_DATA_47", length: 48,
		opfunc: opcodePushData},
	OP_DATA_48: {value: OP_DATA_48, name: "OP_DATA_48", length: 49,
		opfunc: opcodePushData},
	OP_DATA_49: {value: OP_DATA_49, name: "OP_DATA_49", length: 50,
		opfunc: opcodePushData},
	OP_DATA_50: {value: OP_DATA_50, name: "OP_DATA_50", length: 51,
		opfunc: opcodePushData},
	OP_DATA_51: {value: OP_DATA_51, name: "OP_DATA_51", length: 52,
		opfunc: opcodePushData},
	OP_DATA_52: {value: OP_DATA_52, name: "OP_DATA_52", length: 53,
		opfunc: opcodePushData},
	OP_DATA_53: {value: OP_DATA_53, name: "OP_DATA_53", length: 54,
		opfunc: opcodePushData},
	OP_DATA_54: {value: OP_DATA_54, name: "OP_DATA_54", length: 55,
		opfunc: opcodePushData},
	OP_DATA_55: {value: OP_DATA_55, name: "OP_DATA_55", length: 56,
		opfunc: opcodePushData},
	OP_DATA_56: {value: OP_DATA_56, name: "OP_DATA_56", length: 57,
		opfunc: opcodePushData},
	OP_DATA_57: {value: OP_DATA_57, name: "OP_DATA_57", length: 58,
		opfunc: opcodePushData},
	OP_DATA_58: {value: OP_DATA_58, name: "OP_DATA_58", length: 59,
		opfunc: opcodePushData},
	OP_DATA_59: {value: OP_DATA_59, name: "OP_DATA_59", length: 60,
		opfunc: opcodePushData},
	OP_DATA_60: {value: OP_DATA_60, name: "OP_DATA_60", length: 61,
		opfunc: opcodePushData},
	OP_DATA_61: {value: OP_DATA_61, name: "OP_DATA_61", length: 62,
		opfunc: opcodePushData},
	OP_DATA_62: {value: OP_DATA_62, name: "OP_DATA_62", length: 63,
		opfunc: opcodePushData},
	OP_DATA_63: {value: OP_DATA_63, name: "OP_DATA_63", length: 64,
		opfunc: opcodePushData},
	OP_DATA_64: {value: OP_DATA_64, name: "OP_DATA_64", length: 65,
		opfunc: opcodePushData},
	OP_DATA_65: {value: OP_DATA_65, name: "OP_DATA_65", length: 66,
		opfunc: opcodePushData},
	OP_DATA_66: {value: OP_DATA_66, name: "OP_DATA_66", length: 67,
		opfunc: opcodePushData},
	OP_DATA_67: {value: OP_DATA_67, name: "OP_DATA_67", length: 68,
		opfunc: opcodePushData},
	OP_DATA_68: {value: OP_DATA_68, name: "OP_DATA_68", length: 69,
		opfunc: opcodePushData},
	OP_DATA_69: {value: OP_DATA_69, name: "OP_DATA_69", length: 70,
		opfunc: opcodePushData},
	OP_DATA_70: {value: OP_DATA_70, name: "OP_DATA_70", length: 71,
		opfunc: opcodePushData},
	OP_DATA_71: {value: OP_DATA_71, name: "OP_DATA_71", length: 72,
		opfunc: opcodePushData},
	OP_DATA_72: {value: OP_DATA_72, name: "OP_DATA_72", length: 73,
		opfunc: opcodePushData},
	OP_DATA_73: {value: OP_DATA_73, name: "OP_DATA_73", length: 74,
		opfunc: opcodePushData},
	OP_DATA_74: {value: OP_DATA_74, name: "OP_DATA_74", length: 75,
		opfunc: opcodePushData},
	OP_DATA_75: {value: OP_DATA_75, name: "OP_DATA_75", length: 76,
		opfunc: opcodePushData},
	OP_PUSHDATA1: {value: OP_PUSHDATA1, name: "OP_PUSHDATA1", length: -1,
		opfunc: opcodePushData},
	OP_PUSHDATA2: {value: OP_PUSHDATA2, name: "OP_PUSHDATA2", length: -2,
		opfunc: opcodePushData},
	OP_PUSHDATA4: {value: OP_PUSHDATA4, name: "OP_PUSHDATA4", length: -4,
		opfunc: opcodePushData},
	OP_1NEGATE: {value: OP_1NEGATE, name: "OP_1NEGATE", length: 1,
		opfunc: opcode1Negate},
	OP_RESERVED: {value: OP_RESERVED, name: "OP_RESERVED", length: 1,
		opfunc: opcodeReserved},
	OP_TRUE: {value: OP_TRUE, name: "OP_1", length: 1,
		opfunc: opcodeN},
	OP_2: {value: OP_2, name: "OP_2", length: 1,
		opfunc: opcodeN},
	OP_3: {value: OP_3, name: "OP_3", length: 1,
		opfunc: opcodeN},
	OP_4: {value: OP_4, name: "OP_4", length: 1,
		opfunc: opcodeN},
	OP_5: {value: OP_5, name: "OP_5", length: 1,
		opfunc: opcodeN},
	OP_6: {value: OP_6, name: "OP_6", length: 1,
		opfunc: opcodeN},
	OP_7: {value: OP_7, name: "OP_7", length: 1,
		opfunc: opcodeN},
	OP_8: {value: OP_8, name: "OP_8", length: 1,
		opfunc: opcodeN},
	OP_9: {value: OP_9, name: "OP_9", length: 1,
		opfunc: opcodeN},
	OP_10: {value: OP_10, name: "OP_10", length: 1,
		opfunc: opcodeN},
	OP_11: {value: OP_11, name: "OP_11", length: 1,
		opfunc: opcodeN},
	OP_12: {value: OP_12, name: "OP_12", length: 1,
		opfunc: opcodeN},
	OP_13: {value: OP_13, name: "OP_13", length: 1,
		opfunc: opcodeN},
	OP_14: {value: OP_14, name: "OP_14", length: 1,
		opfunc: opcodeN},
	OP_15: {value: OP_15, name: "OP_15", length: 1,
		opfunc: opcodeN},
	OP_16: {value: OP_16, name: "OP_16", length: 1,
		opfunc: opcodeN},
	OP_NOP: {value: OP_NOP, name: "OP_NOP", length: 1,
		opfunc: opcodeNop},
	OP_VER: {value: OP_VER, name: "OP_VER", length: 1,
		opfunc: opcodeReserved},
	OP_IF: {value: OP_IF, name: "OP_IF", length: 1,
		opfunc: opcodeIf},
	OP_NOTIF: {value: OP_NOTIF, name: "OP_NOTIF", length: 1,
		opfunc: opcodeNotIf},
	OP_VERIF: {value: OP_VERIF, name: "OP_VERIF", length: 1,
		opfunc: opcodeReserved},
	OP_VERNOTIF: {value: OP_VERNOTIF, name: "OP_VERNOTIF", length: 1,
		opfunc: opcodeReserved},
	OP_ELSE: {value: OP_ELSE, name: "OP_ELSE", length: 1,
		opfunc: opcodeElse},
	OP_ENDIF: {value: OP_ENDIF, name: "OP_ENDIF", length: 1,
		opfunc: opcodeEndif},
	OP_VERIFY: {value: OP_VERIFY, name: "OP_VERIFY", length: 1,
		opfunc: opcodeVerify},
	OP_RETURN: {value: OP_RETURN, name: "OP_RETURN", length: 1,
		opfunc: opcodeReturn},
	OP_TOALTSTACK: {value: OP_TOALTSTACK, name: "OP_TOALTSTACK", length: 1,
		opfunc: opcodeToAltStack},
	OP_FROMALTSTACK: {value: OP_FROMALTSTACK, name: "OP_FROMALTSTACK", length: 1,
		opfunc: opcodeFromAltStack},
	OP_2DROP: {value: OP_2DROP, name: "OP_2DROP", length: 1,
		opfunc: opcode2Drop},
	OP_2DUP: {value: OP_2DUP, name: "OP_2DUP", length: 1,
		opfunc: opcode2Dup},
	OP_3DUP: {value: OP_3DUP, name: "OP_3DUP", length: 1,
		opfunc: opcode3Dup},
	OP_2OVER: {value: OP_2OVER, name: "OP_2OVER", length: 1,
		opfunc: opcode2Over},
	OP_2ROT: {value: OP_2ROT, name: "OP_2ROT", length: 1,
		opfunc: opcode2Rot},
	OP_2SWAP: {value: OP_2SWAP, name: "OP_2SWAP", length: 1,
		opfunc: opcode2Swap},
	OP_IFDUP: {value: OP_IFDUP, name: "OP_IFDUP", length: 1,
		opfunc: opcodeIfDup},
	OP_DEPTH: {value: OP_DEPTH, name: "OP_DEPTH", length: 1,
		opfunc: opcodeDepth},
	OP_DROP: {value: OP_DROP, name: "OP_DROP", length: 1,
		opfunc: opcodeDrop},
	OP_DUP: {value: OP_DUP, name: "OP_DUP", length: 1,
		opfunc: opcodeDup},
	OP_NIP: {value: OP_NIP, name: "OP_NIP", length: 1,
		opfunc: opcodeNip},
	OP_OVER: {value: OP_OVER, name: "OP_OVER", length: 1,
		opfunc: opcodeOver},
	OP_PICK: {value: OP_PICK, name: "OP_PICK", length: 1,
		opfunc: opcodePick},
	OP_ROLL: {value: OP_ROLL, name: "OP_ROLL", length: 1,
		opfunc: opcodeRoll},
	OP_ROT: {value: OP_ROT, name: "OP_ROT", length: 1,
		opfunc: opcodeRot},
	OP_SWAP: {value: OP_SWAP, name: "OP_SWAP", length: 1,
		opfunc: opcodeSwap},
	OP_TUCK: {value: OP_TUCK, name: "OP_TUCK", length: 1,
		opfunc: opcodeTuck},
	OP_CAT: {value: OP_CAT, name: "OP_CAT", length: 1,
		opfunc: opcodeDisabled},
	OP_SUBSTR: {value: OP_SUBSTR, name: "OP_SUBSTR", length: 1,
		opfunc: opcodeDisabled},
	OP_LEFT: {value: OP_LEFT, name: "OP_LEFT", length: 1,
		opfunc: opcodeDisabled},
	OP_RIGHT: {value: OP_RIGHT, name: "OP_RIGHT", length: 1,
		opfunc: opcodeDisabled},
	OP_SIZE: {value: OP_SIZE, name: "OP_SIZE", length: 1,
		opfunc: opcodeSize},
	OP_INVERT: {value: OP_INVERT, name: "OP_INVERT", length: 1,
		opfunc: opcodeDisabled},
	OP_AND: {value: OP_AND, name: "OP_AND", length: 1,
		opfunc: opcodeDisabled},
	OP_OR: {value: OP_OR, name: "OP_OR", length: 1,
		opfunc: opcodeDisabled},
	OP_XOR: {value: OP_XOR, name: "OP_XOR", length: 1,
		opfunc: opcodeDisabled},
	OP_EQUAL: {value: OP_EQUAL, name: "OP_EQUAL", length: 1,
		opfunc: opcodeEqual},
	OP_EQUALVERIFY: {value: OP_EQUALVERIFY, name: "OP_EQUALVERIFY", length: 1,
		opfunc: opcodeEqualVerify},
	OP_RESERVED1: {value: OP_RESERVED1, name: "OP_RESERVED1", length: 1,
		opfunc: opcodeReserved},
	OP_RESERVED2: {value: OP_RESERVED2, name: "OP_RESERVED2", length: 1,
		opfunc: opcodeReserved},
	OP_1ADD: {value: OP_1ADD, name: "OP_1ADD", length: 1,
		opfunc: opcode1Add},
	OP_1SUB: {value: OP_1SUB, name: "OP_1SUB", length: 1,
		opfunc: opcode1Sub},
	OP_2MUL: {value: OP_2MUL, name: "OP_2MUL", length: 1,
		opfunc: opcodeDisabled},
	OP_2DIV: {value: OP_2DIV, name: "OP_2DIV", length: 1,
		opfunc: opcodeDisabled},
	OP_NEGATE: {value: OP_NEGATE, name: "OP_NEGATE", length: 1,
		opfunc: opcodeNegate},
	OP_ABS: {value: OP_ABS, name: "OP_ABS", length: 1,
		opfunc: opcodeAbs},
	OP_NOT: {value: OP_NOT, name: "OP_NOT", length: 1,
		opfunc: opcodeNot},
	OP_0NOTEQUAL: {value: OP_0NOTEQUAL, name: "OP_0NOTEQUAL", length: 1,
		opfunc: opcode0NotEqual},
	OP_ADD: {value: OP_ADD, name: "OP_ADD", length: 1,
		opfunc: opcodeAdd},
	OP_SUB: {value: OP_SUB, name: "OP_SUB", length: 1,
		opfunc: opcodeSub},
	OP_MUL: {value: OP_MUL, name: "OP_MUL", length: 1,
		opfunc: opcodeDisabled},
	OP_DIV: {value: OP_DIV, name: "OP_DIV", length: 1,
		opfunc: opcodeDisabled},
	OP_MOD: {value: OP_MOD, name: "OP_MOD", length: 1,
		opfunc: opcodeDisabled},
	OP_LSHIFT: {value: OP_LSHIFT, name: "OP_LSHIFT", length: 1,
		opfunc: opcodeDisabled},
	OP_RSHIFT: {value: OP_RSHIFT, name: "OP_RSHIFT", length: 1,
		opfunc: opcodeDisabled},
	OP_BOOLAND: {value: OP_BOOLAND, name: "OP_BOOLAND", length: 1,
		opfunc: opcodeBoolAnd},
	OP_BOOLOR: {value: OP_BOOLOR, name: "OP_BOOLOR", length: 1,
		opfunc: opcodeBoolOr},
	OP_NUMEQUAL: {value: OP_NUMEQUAL, name: "OP_NUMEQUAL", length: 1,
		opfunc: opcodeNumEqual},
	OP_NUMEQUALVERIFY: {value: OP_NUMEQUALVERIFY, name: "OP_NUMEQUALVERIFY", length: 1,
		opfunc: opcodeNumEqualVerify},
	OP_NUMNOTEQUAL: {value: OP_NUMNOTEQUAL, name: "OP_NUMNOTEQUAL", length: 1,
		opfunc: opcodeNumNotEqual},
	OP_LESSTHAN: {value: OP_LESSTHAN, name: "OP_LESSTHAN", length: 1,
		opfunc: opcodeLessThan},
	OP_GREATERTHAN: {value: OP_GREATERTHAN, name: "OP_GREATERTHAN", length: 1,
		opfunc: opcodeGreaterThan},
	OP_LESSTHANOREQUAL: {value: OP_LESSTHANOREQUAL, name: "OP_LESSTHANOREQUAL", length: 1,
		opfunc: opcodeLessThanOrEqual},
	OP_GREATERTHANOREQUAL: {value: OP_GREATERTHANOREQUAL, name: "OP_GREATERTHANOREQUAL", length: 1,
		opfunc: opcodeGreaterThanOrEqual},
	OP_MIN: {value: OP_MIN, name: "OP_MIN", length: 1,
		opfunc: opcodeMin},
	OP_MAX: {value: OP_MAX, name: "OP_MAX", length: 1,
		opfunc: opcodeMax},
	OP_WITHIN: {value: OP_WITHIN, name: "OP_WITHIN", length: 1,
		opfunc: opcodeWithin},
	OP_RIPEMD160: {value: OP_RIPEMD160, name: "OP_RIPEMD160", length: 1,
		opfunc: opcodeRipemd160},
	OP_SHA1: {value: OP_SHA1, name: "OP_SHA1", length: 1,
		opfunc: opcodeSha1},
	OP_SHA256: {value: OP_SHA256, name: "OP_SHA256", length: 1,
		opfunc: opcodeSha256},
	OP_HASH160: {value: OP_HASH160, name: "OP_HASH160", length: 1,
		opfunc: opcodeHash160},
	OP_HASH256: {value: OP_HASH256, name: "OP_HASH256", length: 1,
		opfunc: opcodeHash256},
	OP_CODESEPARATOR: {value: OP_CODESEPARATOR, name: "OP_CODESEPARATOR", length: 1,
		opfunc: opcodeCodeSeparator},
	OP_CHECKSIG: {value: OP_CHECKSIG, name: "OP_CHECKSIG", length: 1,
		opfunc: opcodeCheckSig},
	OP_CHECKSIGVERIFY: {value: OP_CHECKSIGVERIFY, name: "OP_CHECKSIGVERIFY", length: 1,
		opfunc: opcodeCheckSigVerify},
	OP_CHECKMULTISIG: {value: OP_CHECKMULTISIG, name: "OP_CHECKMULTISIG", length: 1,
		opfunc: opcodeCheckMultiSig},
	OP_CHECKMULTISIGVERIFY: {value: OP_CHECKMULTISIGVERIFY, name: "OP_CHECKMULTISIGVERIFY", length: 1,

		opfunc: opcodeCheckMultiSigVerify},
	OP_NOP1: {value: OP_NOP1, name: "OP_NOP1", length: 1,
		opfunc: opcodeNop},
	OP_NOP2: {value: OP_NOP2, name: "OP_NOP2", length: 1,
		opfunc: opcodeNop},
	OP_NOP3: {value: OP_NOP3, name: "OP_NOP3", length: 1,
		opfunc: opcodeNop},
	OP_NOP4: {value: OP_NOP4, name: "OP_NOP4", length: 1,
		opfunc: opcodeNop},
	OP_NOP5: {value: OP_NOP5, name: "OP_NOP5", length: 1,
		opfunc: opcodeNop},
	OP_NOP6: {value: OP_NOP6, name: "OP_NOP6", length: 1,
		opfunc: opcodeNop},
	OP_NOP7: {value: OP_NOP7, name: "OP_NOP7", length: 1,
		opfunc: opcodeNop},
	OP_NOP8: {value: OP_NOP8, name: "OP_NOP8", length: 1,
		opfunc: opcodeNop},
	OP_NOP9: {value: OP_NOP9, name: "OP_NOP9", length: 1,
		opfunc: opcodeNop},
	OP_NOP10: {value: OP_NOP10, name: "OP_NOP10", length: 1,
		opfunc: opcodeNop},
	OP_UNKNOWN186: {value: OP_UNKNOWN186, name: "OP_UNKNOWN186", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN187: {value: OP_UNKNOWN187, name: "OP_UNKNOWN187", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN188: {value: OP_UNKNOWN188, name: "OP_UNKNOWN188", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN189: {value: OP_UNKNOWN189, name: "OP_UNKNOWN189", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN190: {value: OP_UNKNOWN190, name: "OP_UNKNOWN190", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN191: {value: OP_UNKNOWN191, name: "OP_UNKNOWN191", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN192: {value: OP_UNKNOWN192, name: "OP_UNKNOWN192", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN193: {value: OP_UNKNOWN193, name: "OP_UNKNOWN193", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN194: {value: OP_UNKNOWN194, name: "OP_UNKNOWN194", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN195: {value: OP_UNKNOWN195, name: "OP_UNKNOWN195", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN196: {value: OP_UNKNOWN196, name: "OP_UNKNOWN196", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN197: {value: OP_UNKNOWN197, name: "OP_UNKNOWN197", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN198: {value: OP_UNKNOWN198, name: "OP_UNKNOWN198", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN199: {value: OP_UNKNOWN199, name: "OP_UNKNOWN199", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN200: {value: OP_UNKNOWN200, name: "OP_UNKNOWN200", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN201: {value: OP_UNKNOWN201, name: "OP_UNKNOWN201", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN202: {value: OP_UNKNOWN202, name: "OP_UNKNOWN202", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN203: {value: OP_UNKNOWN203, name: "OP_UNKNOWN203", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN204: {value: OP_UNKNOWN204, name: "OP_UNKNOWN204", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN205: {value: OP_UNKNOWN205, name: "OP_UNKNOWN205", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN206: {value: OP_UNKNOWN206, name: "OP_UNKNOWN206", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN207: {value: OP_UNKNOWN207, name: "OP_UNKNOWN207", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN208: {value: OP_UNKNOWN208, name: "OP_UNKNOWN208", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN209: {value: OP_UNKNOWN209, name: "OP_UNKNOWN209", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN210: {value: OP_UNKNOWN210, name: "OP_UNKNOWN210", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN211: {value: OP_UNKNOWN211, name: "OP_UNKNOWN211", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN212: {value: OP_UNKNOWN212, name: "OP_UNKNOWN212", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN213: {value: OP_UNKNOWN213, name: "OP_UNKNOWN213", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN214: {value: OP_UNKNOWN214, name: "OP_UNKNOWN214", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN215: {value: OP_UNKNOWN215, name: "OP_UNKNOWN215", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN216: {value: OP_UNKNOWN216, name: "OP_UNKNOWN216", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN217: {value: OP_UNKNOWN217, name: "OP_UNKNOWN217", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN218: {value: OP_UNKNOWN218, name: "OP_UNKNOWN218", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN219: {value: OP_UNKNOWN219, name: "OP_UNKNOWN219", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN220: {value: OP_UNKNOWN220, name: "OP_UNKNOWN220", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN221: {value: OP_UNKNOWN221, name: "OP_UNKNOWN221", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN222: {value: OP_UNKNOWN222, name: "OP_UNKNOWN222", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN223: {value: OP_UNKNOWN223, name: "OP_UNKNOWN223", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN224: {value: OP_UNKNOWN224, name: "OP_UNKNOWN224", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN225: {value: OP_UNKNOWN225, name: "OP_UNKNOWN225", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN226: {value: OP_UNKNOWN226, name: "OP_UNKNOWN226", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN227: {value: OP_UNKNOWN227, name: "OP_UNKNOWN227", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN228: {value: OP_UNKNOWN228, name: "OP_UNKNOWN228", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN229: {value: OP_UNKNOWN229, name: "OP_UNKNOWN229", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN230: {value: OP_UNKNOWN230, name: "OP_UNKNOWN230", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN231: {value: OP_UNKNOWN231, name: "OP_UNKNOWN231", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN232: {value: OP_UNKNOWN232, name: "OP_UNKNOWN232", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN233: {value: OP_UNKNOWN233, name: "OP_UNKNOWN233", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN234: {value: OP_UNKNOWN234, name: "OP_UNKNOWN234", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN235: {value: OP_UNKNOWN235, name: "OP_UNKNOWN235", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN236: {value: OP_UNKNOWN236, name: "OP_UNKNOWN236", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN237: {value: OP_UNKNOWN237, name: "OP_UNKNOWN237", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN238: {value: OP_UNKNOWN238, name: "OP_UNKNOWN238", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN239: {value: OP_UNKNOWN239, name: "OP_UNKNOWN239", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN240: {value: OP_UNKNOWN240, name: "OP_UNKNOWN240", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN241: {value: OP_UNKNOWN241, name: "OP_UNKNOWN241", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN242: {value: OP_UNKNOWN242, name: "OP_UNKNOWN242", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN243: {value: OP_UNKNOWN243, name: "OP_UNKNOWN243", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN244: {value: OP_UNKNOWN244, name: "OP_UNKNOWN244", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN245: {value: OP_UNKNOWN245, name: "OP_UNKNOWN245", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN246: {value: OP_UNKNOWN246, name: "OP_UNKNOWN246", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN247: {value: OP_UNKNOWN247, name: "OP_UNKNOWN247", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN248: {value: OP_UNKNOWN248, name: "OP_UNKNOWN248", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN249: {value: OP_UNKNOWN249, name: "OP_UNKNOWN249", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN250: {value: OP_UNKNOWN250, name: "OP_UNKNOWN250", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN251: {value: OP_UNKNOWN251, name: "OP_UNKNOWN251", length: 1,
		opfunc: opcodeInvalid},
	OP_UNKNOWN252: {value: OP_UNKNOWN252, name: "OP_UNKNOWN252", length: 1,
		opfunc: opcodeInvalid},
	OP_PUBKEYHASH: {value: OP_PUBKEYHASH, name: "OP_PUBKEYHASH", length: 1,
		opfunc: opcodeInvalid},
	OP_PUBKEY: {value: OP_PUBKEY, name: "OP_PUBKEY", length: 1,
		opfunc: opcodeInvalid},
	OP_INVALIDOPCODE: {value: OP_INVALIDOPCODE, name: "OP_INVALIDOPCODE", length: 1,
		opfunc: opcodeInvalid},
}

// opcodeOnelineRepls defines opcode names which are replaced when doing a
// one-line disassembly.  This is done to match the output of the reference
// implementation while not changing the opcode names in the nicer full
// disassembly.
var opcodeOnelineRepls = map[string]string{
	"OP_1NEGATE": "-1",
	"OP_0":       "0",
	"OP_1":       "1",
	"OP_2":       "2",
	"OP_3":       "3",
	"OP_4":       "4",
	"OP_5":       "5",
	"OP_6":       "6",
	"OP_7":       "7",
	"OP_8":       "8",
	"OP_9":       "9",
	"OP_10":      "10",
	"OP_11":      "11",
	"OP_12":      "12",
	"OP_13":      "13",
	"OP_14":      "14",
	"OP_15":      "15",
	"OP_16":      "16",
}

type parsedOpcode struct {
	opcode *opcode
	data   []byte
}

// The following opcodes are disabled and are thus always bad to see in the
// instruction stream (even if turned off by a conditional).
func (pop *parsedOpcode) disabled() bool {
	switch pop.opcode.value {
	case OP_CAT:
		return true
	case OP_SUBSTR:
		return true
	case OP_LEFT:
		return true
	case OP_RIGHT:
		return true
	case OP_INVERT:
		return true
	case OP_AND:
		return true
	case OP_OR:
		return true
	case OP_XOR:
		return true
	case OP_2MUL:
		return true
	case OP_2DIV:
		return true
	case OP_MUL:
		return true
	case OP_DIV:
		return true
	case OP_MOD:
		return true
	case OP_LSHIFT:
		return true
	case OP_RSHIFT:
		return true
	default:
		return false
	}
}

// The following opcodes are always illegal when passed over by the program
// counter even if in a non-executed branch. (it isn't a coincidence that they
// are conditionals).
func (pop *parsedOpcode) alwaysIllegal() bool {
	switch pop.opcode.value {
	case OP_VERIF:
		return true
	case OP_VERNOTIF:
		return true
	default:
		return false
	}
}

// The following opcode are conditional and thus change the conditional
// execution stack state when passed.
func (pop *parsedOpcode) conditional() bool {
	switch pop.opcode.value {
	case OP_IF:
		return true
	case OP_NOTIF:
		return true
	case OP_ELSE:
		return true
	case OP_ENDIF:
		return true
	default:
		return false
	}
}

// checkMinimalDataPush returns whether or not the current data
// push uses the correct opcode.
func (pop *parsedOpcode) checkMinimalDataPush() error {
	data := pop.data
	dataLen := len(data)
	opcode := pop.opcode.value

	if dataLen == 0 && opcode != OP_0 {
		return ErrStackMinimalData
	} else if dataLen == 1 && data[0] >= 1 && data[0] <= 16 {
		if opcode != OP_1+data[0]-1 {
			// Should have used OP_1 .. OP_16
			return ErrStackMinimalData
		}
	} else if dataLen == 1 && data[0] == 0x81 {
		if opcode != OP_1NEGATE {
			return ErrStackMinimalData
		}
	} else if dataLen <= 75 {
		if int(opcode) != dataLen {
			// Should have used a direct push
			return ErrStackMinimalData
		}
	} else if dataLen <= 255 {
		if opcode != OP_PUSHDATA1 {
			return ErrStackMinimalData
		}
	} else if dataLen <= 65535 {
		if opcode != OP_PUSHDATA2 {
			return ErrStackMinimalData
		}
	}
	return nil
}

// exec peforms execution on the opcode. It takes into account whether or not
// it is hidden by conditionals, but some rules still must be tested in this
// case.
func (pop *parsedOpcode) exec(vm *Engine) error {
	// Disabled opcodes are ``fail on program counter''.
	if pop.disabled() {
		return ErrStackOpDisabled
	}

	// Always-illegal opcodes are ``fail on program counter''.
	if pop.alwaysIllegal() {
		return ErrStackReservedOpcode
	}

	// Note that this includes OP_RESERVED which counts as a push operation.
	if pop.opcode.value > OP_16 {
		vm.numOps++
		if vm.numOps > MaxOpsPerScript {
			return ErrStackTooManyOperations
		}

	} else if len(pop.data) > MaxScriptElementSize {
		return ErrStackElementTooBig
	}

	// If we are not a conditional opcode and we aren't executing, then
	// we are done now.
	if vm.condStack[0] != OpCondTrue && !pop.conditional() {
		return nil
	}

	// Ensure all executed data push opcodes use the minimal encoding when
	// the minimal data verification is set.
	if vm.dstack.verifyMinimalData && vm.condStack[0] == OpCondTrue &&
		pop.opcode.value >= 0 && pop.opcode.value <= OP_PUSHDATA4 {
		if err := pop.checkMinimalDataPush(); err != nil {
			return err
		}
	}

	return pop.opcode.opfunc(pop, vm)
}

func (pop *parsedOpcode) print(oneline bool) string {
	// The reference implementation one-line disassembly replaces opcodes
	// which represent values (e.g. OP_0 through OP_16 and OP_1NEGATE)
	// with the raw value.  However, when not doing a one-line dissassembly,
	// we prefer to show the actual opcode names.  Thus, only replace the
	// opcodes in question when the oneline flag is set.
	opcodeName := pop.opcode.name
	if oneline {
		if replName, ok := opcodeOnelineRepls[opcodeName]; ok {
			opcodeName = replName
		}
	}

	retString := opcodeName
	if pop.opcode.length == 1 {
		return retString
	}
	if oneline {
		retString = ""
	}
	if !oneline && pop.opcode.length < 0 {
		//add length to the end of retString
		retString += fmt.Sprintf(" 0x%0*x", 2*-pop.opcode.length,
			len(pop.data))
	}
	for _, val := range pop.data {
		if !oneline {
			retString += " "
		}
		retString += fmt.Sprintf("%02x", val)
	}
	return retString
}

func (pop *parsedOpcode) bytes() ([]byte, error) {
	var retbytes []byte
	if pop.opcode.length > 0 {
		retbytes = make([]byte, 1, pop.opcode.length)
	} else {
		retbytes = make([]byte, 1, 1+len(pop.data)-
			pop.opcode.length)
	}

	retbytes[0] = pop.opcode.value
	if pop.opcode.length == 1 {
		if len(pop.data) != 0 {
			return nil, ErrStackInvalidOpcode
		}
		return retbytes, nil
	}
	nbytes := pop.opcode.length
	if pop.opcode.length < 0 {
		l := len(pop.data)
		// tempting just to hardcode to avoid the complexity here.
		switch pop.opcode.length {
		case -1:
			retbytes = append(retbytes, byte(l))
			nbytes = int(retbytes[1]) + len(retbytes)
		case -2:
			retbytes = append(retbytes, byte(l&0xff),
				byte(l>>8&0xff))
			nbytes = int(binary.LittleEndian.Uint16(retbytes[1:])) +
				len(retbytes)
		case -4:
			retbytes = append(retbytes, byte(l&0xff),
				byte((l>>8)&0xff), byte((l>>16)&0xff),
				byte((l>>24)&0xff))
			nbytes = int(binary.LittleEndian.Uint32(retbytes[1:])) +
				len(retbytes)
		}
	}

	retbytes = append(retbytes, pop.data...)

	if len(retbytes) != nbytes {
		return nil, ErrStackInvalidOpcode
	}

	return retbytes, nil
}

// opcode implementation functions from here

func opcodeDisabled(op *parsedOpcode, vm *Engine) error {
	return ErrStackOpDisabled
}

func opcodeReserved(op *parsedOpcode, vm *Engine) error {
	return ErrStackReservedOpcode
}

// Recognised opcode, but for bitcoind internal use only.
func opcodeInvalid(op *parsedOpcode, vm *Engine) error {
	return ErrStackInvalidOpcode
}

func opcodeFalse(op *parsedOpcode, vm *Engine) error {
	vm.dstack.PushByteArray([]byte(""))

	return nil
}

func opcodePushData(op *parsedOpcode, vm *Engine) error {
	vm.dstack.PushByteArray(op.data)
	return nil
}

func opcode1Negate(op *parsedOpcode, vm *Engine) error {
	vm.dstack.PushInt(big.NewInt(-1))
	return nil
}

func opcodeN(op *parsedOpcode, vm *Engine) error {
	// 16 consecutive opcodes add increasing numbers to the stack.
	vm.dstack.PushInt(big.NewInt(int64(op.opcode.value - (OP_1 - 1))))
	return nil
}

func opcodeNop(op *parsedOpcode, vm *Engine) error {
	switch op.opcode.value {
	case OP_NOP1, OP_NOP2, OP_NOP3, OP_NOP4, OP_NOP5,
		OP_NOP6, OP_NOP7, OP_NOP8, OP_NOP9, OP_NOP10:
		if vm.discourageUpgradableNops {
			return fmt.Errorf("%s reserved for soft-fork upgrades", opcodemap[op.opcode.value].name)
		}
	}
	return nil
}

// opcodeIf computes true/false based on the value on the stack and pushes
// the condition on the condStack (conditional execution stack)
func opcodeIf(op *parsedOpcode, vm *Engine) error {
	// opcodeIf will be executed even if it is on the non-execute side
	// of the conditional, this is so proper nesting is maintained
	var condval int
	if vm.condStack[0] == OpCondTrue {
		ok, err := vm.dstack.PopBool()
		if err != nil {
			return err
		}
		if ok {
			condval = OpCondTrue
		}
	} else {
		condval = OpCondSkip
	}
	cond := []int{condval}
	// push condition to the 'head' of the slice
	vm.condStack = append(cond, vm.condStack...)
	// TODO(drahn) check if a maximum condtitional stack limit exists
	return nil
}

// opcodeNotIf computes true/false based on the value on the stack and pushes
// the (inverted) condition on the condStack (conditional execution stack)
func opcodeNotIf(op *parsedOpcode, vm *Engine) error {
	// opcodeIf will be executed even if it is on the non-execute side
	// of the conditional, this is so proper nesting is maintained
	var condval int
	if vm.condStack[0] == OpCondTrue {
		ok, err := vm.dstack.PopBool()
		if err != nil {
			return err
		}
		if !ok {
			condval = OpCondTrue
		}
	} else {
		condval = OpCondSkip
	}
	cond := []int{condval}
	// push condition to the 'head' of the slice
	vm.condStack = append(cond, vm.condStack...)
	// TODO(drahn) check if a maximum condtitional stack limit exists
	return nil
}

// opcodeElse inverts conditional execution for other half of if/else/endif
func opcodeElse(op *parsedOpcode, vm *Engine) error {
	if len(vm.condStack) < 2 {
		// intial true cannot be toggled, only pushed conditionals
		return ErrStackNoIf
	}

	switch vm.condStack[0] {
	case OpCondTrue:
		vm.condStack[0] = OpCondFalse
	case OpCondFalse:
		vm.condStack[0] = OpCondTrue
	case OpCondSkip:
		// value doesn't change in skip
	}
	return nil
}

// opcodeEndif terminates a conditional block, removing the  value from the
// conditional execution stack.
func opcodeEndif(op *parsedOpcode, vm *Engine) error {
	if len(vm.condStack) < 2 {
		// intial true cannot be popped, only pushed conditionals
		return ErrStackNoIf
	}

	stk := make([]int, len(vm.condStack)-1, len(vm.condStack)-1)
	copy(stk, vm.condStack[1:])
	vm.condStack = stk
	return nil
}

func opcodeVerify(op *parsedOpcode, vm *Engine) error {
	verified, err := vm.dstack.PopBool()
	if err != nil {
		return err
	}

	if verified != true {
		return ErrStackVerifyFailed
	}
	return nil
}

func opcodeReturn(op *parsedOpcode, vm *Engine) error {
	return ErrStackEarlyReturn
}

func opcodeToAltStack(op *parsedOpcode, vm *Engine) error {
	so, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}
	vm.astack.PushByteArray(so)

	return nil
}

func opcodeFromAltStack(op *parsedOpcode, vm *Engine) error {
	so, err := vm.astack.PopByteArray()
	if err != nil {
		return err
	}
	vm.dstack.PushByteArray(so)

	return nil
}

func opcode2Drop(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.DropN(2)
}

func opcode2Dup(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.DupN(2)
}

func opcode3Dup(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.DupN(3)
}

func opcode2Over(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.OverN(2)
}

func opcode2Rot(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.RotN(2)
}

func opcode2Swap(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.SwapN(2)
}

func opcodeIfDup(op *parsedOpcode, vm *Engine) error {
	val, err := vm.dstack.PeekInt(0)
	if err != nil {
		return err
	}

	// Push copy of data iff it isn't zero
	if val.Sign() != 0 {
		vm.dstack.PushInt(val)
	}

	return nil
}

func opcodeDepth(op *parsedOpcode, vm *Engine) error {
	vm.dstack.PushInt(big.NewInt(int64(vm.dstack.Depth())))
	return nil
}

func opcodeDrop(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.DropN(1)
}

func opcodeDup(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.DupN(1)
}

func opcodeNip(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.NipN(1)
}

func opcodeOver(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.OverN(1)
}

// Copy object N items back in the stack to the top. Where N is the value in
// the top of the stack.
func opcodePick(op *parsedOpcode, vm *Engine) error {
	pidx, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	// PopInt promises that the int returned is 32 bit.
	val := int(pidx.Int64())

	return vm.dstack.PickN(val)
}

// Move object N items back in the stack to the top. Where N is the value in
// the top of the stack.
func opcodeRoll(op *parsedOpcode, vm *Engine) error {
	ridx, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	// PopInt promises that the int returned is 32 bit.
	val := int(ridx.Int64())

	return vm.dstack.RollN(val)
}

// Rotate top three items on the stack to the left.
// e.g. 1,2,3 -> 2,3,1
func opcodeRot(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.RotN(1)
}

// Swap the top two items on the stack: 1,2 -> 2,1
func opcodeSwap(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.SwapN(1)
}

// The item at the top of the stack is copied and inserted before the
// second-to-top item. e.g.: 2,1, -> 2,1,2
func opcodeTuck(op *parsedOpcode, vm *Engine) error {
	return vm.dstack.Tuck()
}

// Push the size of the item on top of the stack onto the stack.
func opcodeSize(op *parsedOpcode, vm *Engine) error {
	i, err := vm.dstack.PeekByteArray(0)
	if err != nil {
		return err
	}

	vm.dstack.PushInt(big.NewInt(int64(len(i))))
	return nil
}

func opcodeEqual(op *parsedOpcode, vm *Engine) error {
	a, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}
	b, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}

	vm.dstack.PushBool(bytes.Equal(a, b))
	return nil
}

func opcodeEqualVerify(op *parsedOpcode, vm *Engine) error {
	err := opcodeEqual(op, vm)
	if err == nil {
		err = opcodeVerify(op, vm)
	}
	return err
}

func opcode1Add(op *parsedOpcode, vm *Engine) error {
	m, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	vm.dstack.PushInt(new(big.Int).Add(m, big.NewInt(1)))

	return nil
}

func opcode1Sub(op *parsedOpcode, vm *Engine) error {
	m, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}
	vm.dstack.PushInt(new(big.Int).Sub(m, big.NewInt(1)))

	return nil
}

func opcodeNegate(op *parsedOpcode, vm *Engine) error {
	// XXX when we remove types just flip the 0x80 bit of msb
	m, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	vm.dstack.PushInt(new(big.Int).Neg(m))
	return nil
}

func opcodeAbs(op *parsedOpcode, vm *Engine) error {
	// XXX when we remove types just &= ~0x80 on msb
	m, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	vm.dstack.PushInt(new(big.Int).Abs(m))

	return nil
}

// If then input is 0 or 1, it is flipped. Otherwise the output will be 0.
// (n.b. official client just has 1 is 0, else 0)
func opcodeNot(op *parsedOpcode, vm *Engine) error {
	m, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}
	if m.Sign() == 0 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}
	return nil
}

// opcode returns 0 if the input is 0, 1 otherwise.
func opcode0NotEqual(op *parsedOpcode, vm *Engine) error {
	m, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}
	if m.Sign() != 0 {
		m.SetInt64(1)
	}
	vm.dstack.PushInt(m)

	return nil
}

// Push result of adding top two entries on stack
func opcodeAdd(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	vm.dstack.PushInt(new(big.Int).Add(v0, v1))
	return nil
}

// Push result of subtracting 2nd entry on stack from first.
func opcodeSub(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	vm.dstack.PushInt(new(big.Int).Sub(v1, v0))
	return nil
}

// If both of the top two entries on the stack are not zero output is 1.
// Otherwise, 0.
func opcodeBoolAnd(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v0.Sign() != 0 && v1.Sign() != 0 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}

	return nil
}

// If either of the top two entries on the stack are not zero output is 1.
// Otherwise, 0.
func opcodeBoolOr(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v0.Sign() != 0 || v1.Sign() != 0 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}

	return nil
}

func opcodeNumEqual(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v0.Cmp(v1) == 0 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}

	return nil
}

func opcodeNumEqualVerify(op *parsedOpcode, vm *Engine) error {
	err := opcodeNumEqual(op, vm)
	if err == nil {
		err = opcodeVerify(op, vm)
	}
	return err
}

func opcodeNumNotEqual(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v0.Cmp(v1) != 0 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}

	return nil
}

func opcodeLessThan(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v1.Cmp(v0) == -1 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}

	return nil
}

func opcodeGreaterThan(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v1.Cmp(v0) == 1 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}
	return nil
}

func opcodeLessThanOrEqual(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v1.Cmp(v0) <= 0 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}
	return nil
}

func opcodeGreaterThanOrEqual(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v1.Cmp(v0) >= 0 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}

	return nil
}

func opcodeMin(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v1.Cmp(v0) == -1 {
		vm.dstack.PushInt(new(big.Int).Set(v1))
	} else {
		vm.dstack.PushInt(new(big.Int).Set(v0))
	}

	return nil
}

func opcodeMax(op *parsedOpcode, vm *Engine) error {
	v0, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	v1, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if v1.Cmp(v0) == 1 {
		vm.dstack.PushInt(new(big.Int).Set(v1))
	} else {
		vm.dstack.PushInt(new(big.Int).Set(v0))
	}

	return nil
}

// stack input: x, min, max. Returns 1 if x is within specified range
// (left inclusive), 0 otherwise
func opcodeWithin(op *parsedOpcode, vm *Engine) error {
	maxVal, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	minVal, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	x, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	if x.Cmp(minVal) >= 0 && x.Cmp(maxVal) == -1 {
		vm.dstack.PushInt(big.NewInt(1))
	} else {
		vm.dstack.PushInt(big.NewInt(0))
	}
	return nil
}

// Calculate the hash of hasher over buf.
func calcHash(buf []byte, hasher hash.Hash) []byte {
	hasher.Write(buf)
	return hasher.Sum(nil)
}

// calculate hash160 which is ripemd160(sha256(data))
func calcHash160(buf []byte) []byte {
	return calcHash(calcHash(buf, fastsha256.New()), ripemd160.New())
}

func opcodeRipemd160(op *parsedOpcode, vm *Engine) error {
	buf, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}

	vm.dstack.PushByteArray(calcHash(buf, ripemd160.New()))
	return nil
}

func opcodeSha1(op *parsedOpcode, vm *Engine) error {
	buf, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}

	vm.dstack.PushByteArray(calcHash(buf, sha1.New()))
	return nil
}

func opcodeSha256(op *parsedOpcode, vm *Engine) error {
	buf, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}

	vm.dstack.PushByteArray(calcHash(buf, fastsha256.New()))
	return nil
}

func opcodeHash160(op *parsedOpcode, vm *Engine) error {
	buf, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}

	vm.dstack.PushByteArray(calcHash160(buf))
	return nil
}

func opcodeHash256(op *parsedOpcode, vm *Engine) error {
	buf, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}

	vm.dstack.PushByteArray(wire.DoubleSha256(buf))
	return nil
}

func opcodeCodeSeparator(op *parsedOpcode, vm *Engine) error {
	vm.lastcodesep = vm.scriptOff

	return nil
}

func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {

	pkStr, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}

	sigStr, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}

	// Signature actually needs needs to be longer than this, but we need
	// at least  1 byte for the below. btcec will check full length upon
	// parsing the signature.
	if len(sigStr) < 1 {
		vm.dstack.PushBool(false)
		return nil
	}

	// Trim off hashtype from the signature string.
	hashType := SigHashType(sigStr[len(sigStr)-1])
	sigStr = sigStr[:len(sigStr)-1]

	if err := vm.checkHashTypeEncoding(hashType); err != nil {
		return err
	}
	if err := vm.checkSignatureEncoding(sigStr); err != nil {
		return err
	}
	if err := vm.checkPubKeyEncoding(pkStr); err != nil {
		return err
	}

	// Get script from the last OP_CODESEPARATOR and without any subsequent
	// OP_CODESEPARATORs
	subScript := vm.subScript()

	// Unlikely to hit any cases here, but remove the signature from
	// the script if present.
	subScript = removeOpcodeByData(subScript, sigStr)

	hash := calcScriptHash(subScript, hashType, &vm.tx, vm.txIdx)

	pubKey, err := btcec.ParsePubKey(pkStr, btcec.S256())
	if err != nil {
		vm.dstack.PushBool(false)
		return nil
	}

	var signature *btcec.Signature
	if vm.verifyStrictEncoding || vm.verifyDERSignatures {
		signature, err = btcec.ParseDERSignature(sigStr, btcec.S256())
	} else {
		signature, err = btcec.ParseSignature(sigStr, btcec.S256())
	}
	if err != nil {
		vm.dstack.PushBool(false)
		return nil
	}

	log.Tracef("%v", newLogClosure(func() string {
		return fmt.Sprintf("op_checksig\n"+
			"pubKey:\n%v"+
			"pubKey.X: %v\n"+
			"pubKey.Y: %v\n"+
			"signature.R: %v\n"+
			"signature.S: %v\n"+
			"checkScriptHash:\n%v",
			hex.Dump(pkStr), pubKey.X, pubKey.Y,
			signature.R, signature.S, hex.Dump(hash))
	}))
	ok := signature.Verify(hash, pubKey)
	vm.dstack.PushBool(ok)
	return nil
}

func opcodeCheckSigVerify(op *parsedOpcode, vm *Engine) error {
	err := opcodeCheckSig(op, vm)
	if err == nil {
		err = opcodeVerify(op, vm)
	}
	return err
}

// parsedSigInfo houses a raw signature along with its parsed form and a flag
// for whether or not it has already been parsed.  It is used to prevent parsing
// the same signature multiple times when verify a multisig.
type parsedSigInfo struct {
	signature       []byte
	parsedSignature *btcec.Signature
	parsed          bool
}

// stack; sigs <numsigs> pubkeys <numpubkeys>
func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
	numKeys, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}

	// PopInt promises that the int returned is 32 bit.
	numPubKeys := int(numKeys.Int64())
	if numPubKeys < 0 || numPubKeys > MaxPubKeysPerMultiSig {
		return ErrStackTooManyPubkeys
	}
	vm.numOps += numPubKeys
	if vm.numOps > MaxOpsPerScript {
		return ErrStackTooManyOperations
	}

	pubKeys := make([][]byte, 0, numPubKeys)
	for i := 0; i < numPubKeys; i++ {
		pubKey, err := vm.dstack.PopByteArray()
		if err != nil {
			return err
		}
		pubKeys = append(pubKeys, pubKey)
	}

	numSigs, err := vm.dstack.PopInt()
	if err != nil {
		return err
	}
	// PopInt promises that the int returned is 32 bit.
	numSignatures := int(numSigs.Int64())
	if numSignatures < 0 {
		return fmt.Errorf("number of signatures '%d' is less than 0",
			numSignatures)
	}
	if numSignatures > numPubKeys {
		return fmt.Errorf("more signatures than pubkeys: %d > %d",
			numSignatures, numPubKeys)
	}

	signatures := make([]*parsedSigInfo, 0, numSignatures)
	for i := 0; i < numSignatures; i++ {
		signature, err := vm.dstack.PopByteArray()
		if err != nil {
			return err
		}
		sigInfo := &parsedSigInfo{signature: signature}
		signatures = append(signatures, sigInfo)
	}

	// bug in bitcoind means we pop one more stack value than should be
	// used.
	dummy, err := vm.dstack.PopByteArray()
	if err != nil {
		return err
	}

	if vm.strictMultiSig && len(dummy) != 0 {
		return fmt.Errorf("multisig dummy argument is not zero length: %d",
			len(dummy))
	}

	// Trim OP_CODESEPARATORs
	script := vm.subScript()

	// Remove any of the signatures that happen to be in the script.
	// can't sign somthing containing the signature you're making, after
	// all
	for _, sigInfo := range signatures {
		script = removeOpcodeByData(script, sigInfo.signature)
	}

	success := true
	numPubKeys++
	pubKeyIdx := -1
	signatureIdx := 0
	for numSignatures > 0 {
		// When there are more signatures than public keys remaining,
		// there is no way to succeed since too many signatures are
		// invalid, so exit early.
		pubKeyIdx++
		numPubKeys--
		if numSignatures > numPubKeys {
			success = false
			break
		}

		sigInfo := signatures[signatureIdx]
		pubKey := pubKeys[pubKeyIdx]

		// The order of the signature and public key evaluation is
		// important here since it can be distinguished by an
		// OP_CHECKMULTISIG NOT when the strict encoding flag is set.

		rawSig := sigInfo.signature
		if len(rawSig) == 0 {
			// Skip to the next pubkey if signature is empty.
			continue
		}

		// Split the signature into hash type and signature components.
		hashType := SigHashType(rawSig[len(rawSig)-1])
		signature := rawSig[:len(rawSig)-1]

		// Only parse and check the signature encoding once.
		var parsedSig *btcec.Signature
		if !sigInfo.parsed {
			if err := vm.checkHashTypeEncoding(hashType); err != nil {
				return err
			}
			if err := vm.checkSignatureEncoding(signature); err != nil {
				return err
			}

			// Parse the signature.
			var err error
			if vm.verifyStrictEncoding || vm.verifyDERSignatures {
				parsedSig, err = btcec.ParseDERSignature(signature,
					btcec.S256())
			} else {
				parsedSig, err = btcec.ParseSignature(signature,
					btcec.S256())
			}
			sigInfo.parsed = true
			if err != nil {
				continue
			}
			sigInfo.parsedSignature = parsedSig
		} else {
			// Skip to the next pubkey if the signature is invalid.
			if sigInfo.parsedSignature == nil {
				continue
			}

			// Use the already parsed signature.
			parsedSig = sigInfo.parsedSignature
		}

		if err := vm.checkPubKeyEncoding(pubKey); err != nil {
			return err
		}

		// Parse the pubkey.
		parsedPubKey, err := btcec.ParsePubKey(pubKey, btcec.S256())
		if err != nil {
			continue
		}

		hash := calcScriptHash(script, hashType, &vm.tx, vm.txIdx)

		if parsedSig.Verify(hash, parsedPubKey) {
			// PubKey verified, move on to the next signature.
			signatureIdx++
			numSignatures--
		}
	}

	vm.dstack.PushBool(success)
	return nil
}

func opcodeCheckMultiSigVerify(op *parsedOpcode, vm *Engine) error {
	err := opcodeCheckMultiSig(op, vm)
	if err == nil {
		err = opcodeVerify(op, vm)
	}
	return err
}
