commit 0e514a791b2070a79f073c765b0a1eff14f8c17c
Author: William Casarin <jb55@jb55.com>
Date: Sat, 21 Oct 2017 22:43:48 -0700
Initial commit
Diffstat:
A | .gitignore | | | 6 | ++++++ |
A | Makefile | | | 27 | +++++++++++++++++++++++++++ |
A | lexer.l | | | 24 | ++++++++++++++++++++++++ |
A | mph-opcodes | | | 101 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | opcodes | | | 122 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | oplookup.h | | | 156 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | parser.y | | | 57 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | script.c | | | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | script.h | | | 155 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
9 files changed, 928 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,6 @@
+*.o
+/parser.tab.h
+/parser.tab.c
+/oplookup.c
+/lex.yy.c
+/bcs
diff --git a/Makefile b/Makefile
@@ -0,0 +1,27 @@
+
+
+GEN=parser.tab.c parser.tab.h lex.yy.c oplookup.c
+DEPS=script.c parser.tab.c lex.yy.c oplookup.c
+PREFIX ?= /usr/local
+BIN=bcs
+
+all: $(BIN)
+
+oplookup.c: opcodes
+ @./mph-opcodes opcodes > $@
+
+parser.tab.c parser.tab.h: parser.y
+ bison -d parser.y
+
+lex.yy.c: lexer.l parser.tab.h
+ flex lexer.l
+
+install: $(BIN)
+ mkdir -p $(PREFIX)/bin
+ cp $(BIN) $(PREFIX)/bin
+
+$(BIN): $(GEN) $(DEPS)
+ $(CC) -O0 -g -o $@ $(DEPS)
+
+clean:
+ rm -f $(GEN)
diff --git a/lexer.l b/lexer.l
@@ -0,0 +1,24 @@
+%option noyywrap
+
+%{
+#include <stdio.h>
+#include "script.h"
+
+#define YY_DECL int yylex()
+
+
+#include "parser.tab.h"
+
+%}
+
+%%
+
+[ \t] ; // ignore all whitespace
+\n {return T_NEWLINE;}
+
+(op_)?[a-zA-Z0-9]+ {
+ yylval = op_tokenize(yytext);
+ return T_OP;
+}
+
+%%
diff --git a/mph-opcodes b/mph-opcodes
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+# Easy Perfect Minimal Hashing
+# By Steve Hanov. Released to the public domain.
+#
+# Based on:
+# Edward A. Fox, Lenwood S. Heath, Qi Fan Chen and Amjad M. Daoud,
+# "Practical minimal perfect hash functions for large databases", CACM, 35(1):105-121
+# also a good reference:
+# Compress, Hash, and Displace algorithm by Djamal Belazzougui,
+# Fabiano C. Botelho, and Martin Dietzfelbinger
+import sys
+
+DICTIONARY = sys.argv[1]
+
+# Calculates a distinct hash function for a given string. Each value of the
+# integer d results in a different hash value.
+def hash( d, str ):
+ if d == 0: d = 0x01000193
+
+ # Use the FNV algorithm from http://isthe.com/chongo/tech/comp/fnv/
+ for c in str:
+ d = ( (d * 0x01000193) ^ ord(c) ) & 0xffffffff;
+
+ return d
+
+# Computes a minimal perfect hash table using the given python dictionary. It
+# returns a tuple (G, V). G and V are both arrays. G contains the intermediate
+# table of values needed to compute the index of the value in V. V contains the
+# values of the dictionary.
+def CreateMinimalPerfectHash( dict ):
+ size = len(dict)
+
+ # Step 1: Place all of the keys into buckets
+ buckets = [ [] for i in range(size) ]
+ G = [0] * size
+ values = [None] * size
+
+ for key in dict.keys():
+ buckets[hash(0, key) % size].append( key )
+
+ # Step 2: Sort the buckets and process the ones with the most items first.
+ buckets.sort( key=len, reverse=True )
+ for b in xrange( size ):
+ bucket = buckets[b]
+ if len(bucket) <= 1: break
+
+ d = 1
+ item = 0
+ slots = []
+
+ # Repeatedly try different values of d until we find a hash function
+ # that places all items in the bucket into free slots
+ while item < len(bucket):
+ slot = hash( d, bucket[item] ) % size
+ if values[slot] != None or slot in slots:
+ d += 1
+ item = 0
+ slots = []
+ else:
+ slots.append( slot )
+ item += 1
+
+ G[hash(0, bucket[0]) % size] = d
+ for i in range(len(bucket)):
+ values[slots[i]] = dict[bucket[i]]
+
+ # Only buckets with 1 item remain. Process them more quickly by directly
+ # placing them into a free slot. Use a negative value of d to indicate
+ # this.
+ freelist = []
+ for i in xrange(size):
+ if values[i] == None: freelist.append( i )
+
+ for b in xrange( b, size ):
+ bucket = buckets[b]
+ if len(bucket) == 0: break
+ slot = freelist.pop()
+ # We subtract one to ensure it's negative even if the zeroeth slot was
+ # used.
+ G[hash(0, bucket[0]) % size] = -slot-1
+ values[slot] = dict[bucket[0]]
+
+ return (G, values)
+
+# Look up a value in the hash table, defined by G and V.
+def PerfectHashLookup( G, V, key ):
+ d = G[hash(0,key) % len(G)]
+ if d < 0: return V[-d-1]
+ return V[hash(d, key) % len(V)]
+
+dict = {}
+line = 1
+keys = map(lambda x: x.strip(), open(DICTIONARY, "rt").readlines())
+for key in keys:
+ dict[key] = line
+ line += 1
+
+(G, V) = CreateMinimalPerfectHash( dict )
+
+print G
+print V
diff --git a/opcodes b/opcodes
@@ -0,0 +1,121 @@
+0
+FALSE
+PUSHDATA1
+PUSHDATA2
+PUSHDATA4
+1NEGATE
+RESERVED
+1
+TRUE
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+NOP
+VER
+IF
+NOTIF
+VERIF
+VERNOTIF
+ELSE
+ENDIF
+VERIFY
+RETURN
+TOALTSTACK
+FROMALTSTACK
+2DROP
+2DUP
+3DUP
+2OVER
+2ROT
+2SWAP
+IFDUP
+DEPTH
+DROP
+DUP
+NIP
+OVER
+PICK
+ROLL
+ROT
+SWAP
+TUCK
+CAT
+SUBSTR
+LEFT
+RIGHT
+SIZE
+INVERT
+AND
+OR
+XOR
+EQUAL
+EQUALVERIFY
+RESERVED1
+RESERVED2
+numeric
+1ADD
+1SUB
+2MUL
+2DIV
+NEGATE
+ABS
+NOT
+0NOTEQUAL
+ADD
+SUB
+MUL
+DIV
+MOD
+LSHIFT
+RSHIFT
+BOOLAND
+BOOLOR
+NUMEQUAL
+NUMEQUALVERIFY
+NUMNOTEQUAL
+LESSTHAN
+GREATERTHAN
+LESSTHANOREQUAL
+GREATERTHANOREQUAL
+MIN
+MAX
+WITHIN
+RIPEMD160
+SHA1
+SHA256
+HASH160
+HASH256
+CODESEPARATOR
+CHECKSIG
+CHECKSIGVERIFY
+CHECKMULTISIG
+CHECKMULTISIGVERIFY
+NOP1
+CHECKLOCKTIMEVERIFY
+NOP2
+CHECKSEQUENCEVERIFY
+NOP3
+NOP4
+NOP5
+NOP6
+NOP7
+NOP8
+NOP9
+NOP10
+SMALLINTEGER
+PUBKEYS
+PUBKEYHASH
+PUBKEY
+INVALIDOPCODE+
\ No newline at end of file
diff --git a/oplookup.h b/oplookup.h
@@ -0,0 +1,156 @@
+
+#ifndef BCS_OPLOOKUP_H
+#define BCS_OPLOOKUP_H
+
+enum opcode_token
+{
+ // push value
+ _OP_0,
+ _OP_FALSE,
+ _OP_PUSHDATA1,
+ _OP_PUSHDATA2,
+ _OP_PUSHDATA4,
+ _OP_1NEGATE,
+ _OP_RESERVED,
+ _OP_1,
+ _OP_TRUE,
+ _OP_2,
+ _OP_3,
+ _OP_4,
+ _OP_5,
+ _OP_6,
+ _OP_7,
+ _OP_8,
+ _OP_9,
+ _OP_10,
+ _OP_11,
+ _OP_12,
+ _OP_13,
+ _OP_14,
+ _OP_15,
+ _OP_16,
+
+ // control
+ _OP_NOP,
+ _OP_VER,
+ _OP_IF,
+ _OP_NOTIF,
+ _OP_VERIF,
+ _OP_VERNOTIF,
+ _OP_ELSE,
+ _OP_ENDIF,
+ _OP_VERIFY,
+ _OP_RETURN,
+
+ // stack ops
+ _OP_TOALTSTACK,
+ _OP_FROMALTSTACK,
+ _OP_2DROP,
+ _OP_2DUP,
+ _OP_3DUP,
+ _OP_2OVER,
+ _OP_2ROT,
+ _OP_2SWAP,
+ _OP_IFDUP,
+ _OP_DEPTH,
+ _OP_DROP,
+ _OP_DUP,
+ _OP_NIP,
+ _OP_OVER,
+ _OP_PICK,
+ _OP_ROLL,
+ _OP_ROT,
+ _OP_SWAP,
+ _OP_TUCK,
+
+ // splice ops
+ _OP_CAT,
+ _OP_SUBSTR,
+ _OP_LEFT,
+ _OP_RIGHT,
+ _OP_SIZE,
+
+ // bit logic
+ _OP_INVERT,
+ _OP_AND,
+ _OP_OR,
+ _OP_XOR,
+ _OP_EQUAL,
+ _OP_EQUALVERIFY,
+ _OP_RESERVED1,
+ _OP_RESERVED2,
+
+ // numeric
+ _OP_1ADD,
+ _OP_1SUB,
+ _OP_2MUL,
+ _OP_2DIV,
+ _OP_NEGATE,
+ _OP_ABS,
+ _OP_NOT,
+ _OP_0NOTEQUAL,
+
+ _OP_ADD,
+ _OP_SUB,
+ _OP_MUL,
+ _OP_DIV,
+ _OP_MOD,
+ _OP_LSHIFT,
+ _OP_RSHIFT,
+
+ _OP_BOOLAND,
+ _OP_BOOLOR,
+ _OP_NUMEQUAL,
+ _OP_NUMEQUALVERIFY,
+ _OP_NUMNOTEQUAL,
+ _OP_LESSTHAN,
+ _OP_GREATERTHAN,
+ _OP_LESSTHANOREQUAL,
+ _OP_GREATERTHANOREQUAL,
+ _OP_MIN,
+ _OP_MAX,
+
+ _OP_WITHIN,
+
+ // crypto
+ _OP_RIPEMD160,
+ _OP_SHA1,
+ _OP_SHA256,
+ _OP_HASH160,
+ _OP_HASH256,
+ _OP_CODESEPARATOR,
+ _OP_CHECKSIG,
+ _OP_CHECKSIGVERIFY,
+ _OP_CHECKMULTISIG,
+ _OP_CHECKMULTISIGVERIFY,
+
+ // expansion
+ _OP_NOP1,
+ _OP_CHECKLOCKTIMEVERIFY,
+ _OP_NOP2,
+ _OP_CHECKSEQUENCEVERIFY,
+ _OP_NOP3,
+ _OP_NOP4,
+ _OP_NOP5,
+ _OP_NOP6,
+ _OP_NOP7,
+ _OP_NOP8,
+ _OP_NOP9,
+ _OP_NOP10,
+
+
+ // template matching params
+ _OP_SMALLINTEGER,
+ _OP_PUBKEYS,
+ _OP_PUBKEYHASH,
+ _OP_PUBKEY,
+
+ _OP_INVALIDOPCODE,
+};
+
+
+enum opcode_token op_mph(const char *);
+
+
+#endif /* BCS_OPLOOKUP_H */
+
diff --git a/parser.y b/parser.y
@@ -0,0 +1,57 @@
+
+%{
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "script.h"
+
+extern int yylex();
+extern int yyparse();
+extern FILE* yyin;
+
+char buffer[255];
+
+void yyerror(const char* s);
+%}
+
+%union {
+ enum opcode opcode;
+}
+
+%token T_OP
+%token T_NEWLINE T_QUIT
+
+%type<opcode> T_OP
+
+%start script
+
+%%
+
+script:
+ | script line
+;
+
+line: T_NEWLINE
+ | T_OP line { printf("%s\n", op_str($1)); }
+
+/* opcode: */
+/* | T_OP { op_add($$); } */
+/* ; */
+
+
+%%
+
+int main() {
+ yyin = stdin;
+
+ do {
+ yyparse();
+ } while(!feof(yyin));
+
+ return 0;
+}
+
+void yyerror(const char* s) {
+ fprintf(stderr, "Parse error: %s\n", s);
+ exit(1);
+}
diff --git a/script.c b/script.c
@@ -0,0 +1,280 @@
+
+#include "script.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+
+
+enum opcode
+op_tokenize(char *str) {
+ int len,i;
+ char *p;
+
+ p = str;
+ len = strlen(str);
+
+ for (i = 0; i < len; ++i)
+ str[i] = toupper(str[i]);
+
+ // upper all all
+ if (len >= 3)
+ if (str[0] == 'O')
+ if (str[1] == 'P')
+ if (str[2] == '_') {
+ p = &str[3];
+ len -= 3;
+ }
+
+ return op_mph(str);
+}
+
+
+enum opcode op_from_token(enum opcode_token opcode) {
+ switch (opcode) {
+ case _OP_0: return OP_0;
+ case _OP_FALSE: return OP_FALSE;
+ case _OP_PUSHDATA1: return OP_PUSHDATA1;
+ case _OP_PUSHDATA2: return OP_PUSHDATA2;
+ case _OP_PUSHDATA4: return OP_PUSHDATA4;
+ case _OP_1NEGATE: return OP_1NEGATE;
+ case _OP_RESERVED: return OP_RESERVED;
+ case _OP_1: return OP_1;
+ case _OP_TRUE: return OP_TRUE;
+ case _OP_2: return OP_2;
+ case _OP_3: return OP_3;
+ case _OP_4: return OP_4;
+ case _OP_5: return OP_5;
+ case _OP_6: return OP_6;
+ case _OP_7: return OP_7;
+ case _OP_8: return OP_8;
+ case _OP_9: return OP_9;
+ case _OP_10: return OP_10;
+ case _OP_11: return OP_11;
+ case _OP_12: return OP_12;
+ case _OP_13: return OP_13;
+ case _OP_14: return OP_14;
+ case _OP_15: return OP_15;
+ case _OP_16: return OP_16;
+ case _OP_NOP: return OP_NOP;
+ case _OP_VER: return OP_VER;
+ case _OP_IF: return OP_IF;
+ case _OP_NOTIF: return OP_NOTIF;
+ case _OP_VERIF: return OP_VERIF;
+ case _OP_VERNOTIF: return OP_VERNOTIF;
+ case _OP_ELSE: return OP_ELSE;
+ case _OP_ENDIF: return OP_ENDIF;
+ case _OP_VERIFY: return OP_VERIFY;
+ case _OP_RETURN: return OP_RETURN;
+ case _OP_TOALTSTACK: return OP_TOALTSTACK;
+ case _OP_FROMALTSTACK: return OP_FROMALTSTACK;
+ case _OP_2DROP: return OP_2DROP;
+ case _OP_2DUP: return OP_2DUP;
+ case _OP_3DUP: return OP_3DUP;
+ case _OP_2OVER: return OP_2OVER;
+ case _OP_2ROT: return OP_2ROT;
+ case _OP_2SWAP: return OP_2SWAP;
+ case _OP_IFDUP: return OP_IFDUP;
+ case _OP_DEPTH: return OP_DEPTH;
+ case _OP_DROP: return OP_DROP;
+ case _OP_DUP: return OP_DUP;
+ case _OP_NIP: return OP_NIP;
+ case _OP_OVER: return OP_OVER;
+ case _OP_PICK: return OP_PICK;
+ case _OP_ROLL: return OP_ROLL;
+ case _OP_ROT: return OP_ROT;
+ case _OP_SWAP: return OP_SWAP;
+ case _OP_TUCK: return OP_TUCK;
+ case _OP_CAT: return OP_CAT;
+ case _OP_SUBSTR: return OP_SUBSTR;
+ case _OP_LEFT: return OP_LEFT;
+ case _OP_RIGHT: return OP_RIGHT;
+ case _OP_SIZE: return OP_SIZE;
+ case _OP_INVERT: return OP_INVERT;
+ case _OP_AND: return OP_AND;
+ case _OP_OR: return OP_OR;
+ case _OP_XOR: return OP_XOR;
+ case _OP_EQUAL: return OP_EQUAL;
+ case _OP_EQUALVERIFY: return OP_EQUALVERIFY;
+ case _OP_RESERVED1: return OP_RESERVED1;
+ case _OP_RESERVED2: return OP_RESERVED2;
+ case _OP_1ADD: return OP_1ADD;
+ case _OP_1SUB: return OP_1SUB;
+ case _OP_2MUL: return OP_2MUL;
+ case _OP_2DIV: return OP_2DIV;
+ case _OP_NEGATE: return OP_NEGATE;
+ case _OP_ABS: return OP_ABS;
+ case _OP_NOT: return OP_NOT;
+ case _OP_0NOTEQUAL: return OP_0NOTEQUAL;
+ case _OP_ADD: return OP_ADD;
+ case _OP_SUB: return OP_SUB;
+ case _OP_MUL: return OP_MUL;
+ case _OP_DIV: return OP_DIV;
+ case _OP_MOD: return OP_MOD;
+ case _OP_LSHIFT: return OP_LSHIFT;
+ case _OP_RSHIFT: return OP_RSHIFT;
+ case _OP_BOOLAND: return OP_BOOLAND;
+ case _OP_BOOLOR: return OP_BOOLOR;
+ case _OP_NUMEQUAL: return OP_NUMEQUAL;
+ case _OP_NUMEQUALVERIFY: return OP_NUMEQUALVERIFY;
+ case _OP_NUMNOTEQUAL: return OP_NUMNOTEQUAL;
+ case _OP_LESSTHAN: return OP_LESSTHAN;
+ case _OP_GREATERTHAN: return OP_GREATERTHAN;
+ case _OP_LESSTHANOREQUAL: return OP_LESSTHANOREQUAL;
+ case _OP_GREATERTHANOREQUAL: return OP_GREATERTHANOREQUAL;
+ case _OP_MIN: return OP_MIN;
+ case _OP_MAX: return OP_MAX;
+ case _OP_WITHIN: return OP_WITHIN;
+ case _OP_RIPEMD160: return OP_RIPEMD160;
+ case _OP_SHA1: return OP_SHA1;
+ case _OP_SHA256: return OP_SHA256;
+ case _OP_HASH160: return OP_HASH160;
+ case _OP_HASH256: return OP_HASH256;
+ case _OP_CODESEPARATOR: return OP_CODESEPARATOR;
+ case _OP_CHECKSIG: return OP_CHECKSIG;
+ case _OP_CHECKSIGVERIFY: return OP_CHECKSIGVERIFY;
+ case _OP_CHECKMULTISIG: return OP_CHECKMULTISIG;
+ case _OP_CHECKMULTISIGVERIFY: return OP_CHECKMULTISIGVERIFY;
+ case _OP_NOP1: return OP_NOP1;
+ case _OP_CHECKLOCKTIMEVERIFY: return OP_CHECKLOCKTIMEVERIFY;
+ case _OP_NOP2: return OP_NOP2;
+ case _OP_CHECKSEQUENCEVERIFY: return OP_CHECKSEQUENCEVERIFY;
+ case _OP_NOP3: return OP_NOP3;
+ case _OP_NOP4: return OP_NOP4;
+ case _OP_NOP5: return OP_NOP5;
+ case _OP_NOP6: return OP_NOP6;
+ case _OP_NOP7: return OP_NOP7;
+ case _OP_NOP8: return OP_NOP8;
+ case _OP_NOP9: return OP_NOP9;
+ case _OP_NOP10: return OP_NOP10;
+ case _OP_SMALLINTEGER: return OP_SMALLINTEGER;
+ case _OP_PUBKEYS: return OP_PUBKEYS;
+ case _OP_PUBKEYHASH: return OP_PUBKEYHASH;
+ case _OP_PUBKEY: return OP_PUBKEY;
+ case _OP_INVALIDOPCODE: return OP_INVALIDOPCODE;
+ }
+}
+
+
+const char* op_str(enum opcode opcode)
+{
+ switch (opcode)
+ {
+ // push value
+ case OP_0 : return "0";
+ case OP_PUSHDATA1 : return "OP_PUSHDATA1";
+ case OP_PUSHDATA2 : return "OP_PUSHDATA2";
+ case OP_PUSHDATA4 : return "OP_PUSHDATA4";
+ case OP_1NEGATE : return "-1";
+ case OP_RESERVED : return "OP_RESERVED";
+ case OP_1 : return "1";
+ case OP_2 : return "2";
+ case OP_3 : return "3";
+ case OP_4 : return "4";
+ case OP_5 : return "5";
+ case OP_6 : return "6";
+ case OP_7 : return "7";
+ case OP_8 : return "8";
+ case OP_9 : return "9";
+ case OP_10 : return "10";
+ case OP_11 : return "11";
+ case OP_12 : return "12";
+ case OP_13 : return "13";
+ case OP_14 : return "14";
+ case OP_15 : return "15";
+ case OP_16 : return "16";
+
+ // control
+ case OP_NOP : return "OP_NOP";
+ case OP_VER : return "OP_VER";
+ case OP_IF : return "OP_IF";
+ case OP_NOTIF : return "OP_NOTIF";
+ case OP_VERIF : return "OP_VERIF";
+ case OP_VERNOTIF : return "OP_VERNOTIF";
+ case OP_ELSE : return "OP_ELSE";
+ case OP_ENDIF : return "OP_ENDIF";
+ case OP_VERIFY : return "OP_VERIFY";
+ case OP_RETURN : return "OP_RETURN";
+
+ // stack ops
+ case OP_TOALTSTACK : return "OP_TOALTSTACK";
+ case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
+ case OP_2DROP : return "OP_2DROP";
+ case OP_2DUP : return "OP_2DUP";
+ case OP_3DUP : return "OP_3DUP";
+ case OP_2OVER : return "OP_2OVER";
+ case OP_2ROT : return "OP_2ROT";
+ case OP_2SWAP : return "OP_2SWAP";
+ case OP_IFDUP : return "OP_IFDUP";
+ case OP_DEPTH : return "OP_DEPTH";
+ case OP_DROP : return "OP_DROP";
+ case OP_DUP : return "OP_DUP";
+ case OP_NIP : return "OP_NIP";
+ case OP_OVER : return "OP_OVER";
+ case OP_PICK : return "OP_PICK";
+ case OP_ROLL : return "OP_ROLL";
+ case OP_ROT : return "OP_ROT";
+ case OP_SWAP : return "OP_SWAP";
+ case OP_TUCK : return "OP_TUCK";
+
+ // splice ops
+ case OP_CAT : return "OP_CAT";
+ case OP_NOT : return "OP_NOT";
+ case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
+ case OP_ADD : return "OP_ADD";
+ case OP_SUB : return "OP_SUB";
+ case OP_MUL : return "OP_MUL";
+ case OP_DIV : return "OP_DIV";
+ case OP_MOD : return "OP_MOD";
+ case OP_LSHIFT : return "OP_LSHIFT";
+ case OP_RSHIFT : return "OP_RSHIFT";
+ case OP_BOOLAND : return "OP_BOOLAND";
+ case OP_BOOLOR : return "OP_BOOLOR";
+ case OP_NUMEQUAL : return "OP_NUMEQUAL";
+ case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
+ case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
+ case OP_LESSTHAN : return "OP_LESSTHAN";
+ case OP_GREATERTHAN : return "OP_GREATERTHAN";
+ case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
+ case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
+ case OP_MIN : return "OP_MIN";
+ case OP_MAX : return "OP_MAX";
+ case OP_WITHIN : return "OP_WITHIN";
+
+ // crypto
+ case OP_RIPEMD160 : return "OP_RIPEMD160";
+ case OP_SHA1 : return "OP_SHA1";
+ case OP_SHA256 : return "OP_SHA256";
+ case OP_HASH160 : return "OP_HASH160";
+ case OP_HASH256 : return "OP_HASH256";
+ case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
+ case OP_CHECKSIG : return "OP_CHECKSIG";
+ case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
+ case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
+ case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
+
+ // expansion
+ case OP_NOP1 : return "OP_NOP1";
+ case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
+ case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY";
+ case OP_NOP4 : return "OP_NOP4";
+ case OP_NOP5 : return "OP_NOP5";
+ case OP_NOP6 : return "OP_NOP6";
+ case OP_NOP7 : return "OP_NOP7";
+ case OP_NOP8 : return "OP_NOP8";
+ case OP_NOP9 : return "OP_NOP9";
+ case OP_NOP10 : return "OP_NOP10";
+
+ case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
+
+ // Note:
+ // The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum
+ // as kind of implementation hack, they are *NOT* real opcodes. If found in real
+ // Script, just let the default: case deal with them.
+
+ default:
+ return "OP_UNKNOWN";
+ }
+}
+
+
diff --git a/script.h b/script.h
@@ -0,0 +1,155 @@
+
+#ifndef BCS_SCRIPT_H
+#define BCS_SCRIPT_H
+
+enum opcode
+{
+ // push value
+ OP_0 = 0x00,
+ OP_FALSE = OP_0,
+ OP_PUSHDATA1 = 0x4c,
+ OP_PUSHDATA2 = 0x4d,
+ OP_PUSHDATA4 = 0x4e,
+ OP_1NEGATE = 0x4f,
+ OP_RESERVED = 0x50,
+ OP_1 = 0x51,
+ OP_TRUE=OP_1,
+ OP_2 = 0x52,
+ OP_3 = 0x53,
+ OP_4 = 0x54,
+ OP_5 = 0x55,
+ OP_6 = 0x56,
+ OP_7 = 0x57,
+ OP_8 = 0x58,
+ OP_9 = 0x59,
+ OP_10 = 0x5a,
+ OP_11 = 0x5b,
+ OP_12 = 0x5c,
+ OP_13 = 0x5d,
+ OP_14 = 0x5e,
+ OP_15 = 0x5f,
+ OP_16 = 0x60,
+
+ // control
+ OP_NOP = 0x61,
+ OP_VER = 0x62,
+ OP_IF = 0x63,
+ OP_NOTIF = 0x64,
+ OP_VERIF = 0x65,
+ OP_VERNOTIF = 0x66,
+ OP_ELSE = 0x67,
+ OP_ENDIF = 0x68,
+ OP_VERIFY = 0x69,
+ OP_RETURN = 0x6a,
+
+ // stack ops
+ OP_TOALTSTACK = 0x6b,
+ OP_FROMALTSTACK = 0x6c,
+ OP_2DROP = 0x6d,
+ OP_2DUP = 0x6e,
+ OP_3DUP = 0x6f,
+ OP_2OVER = 0x70,
+ OP_2ROT = 0x71,
+ OP_2SWAP = 0x72,
+ OP_IFDUP = 0x73,
+ OP_DEPTH = 0x74,
+ OP_DROP = 0x75,
+ OP_DUP = 0x76,
+ OP_NIP = 0x77,
+ OP_OVER = 0x78,
+ OP_PICK = 0x79,
+ OP_ROLL = 0x7a,
+ OP_ROT = 0x7b,
+ OP_SWAP = 0x7c,
+ OP_TUCK = 0x7d,
+
+ // splice ops
+ OP_CAT = 0x7e,
+ OP_SUBSTR = 0x7f,
+ OP_LEFT = 0x80,
+ OP_RIGHT = 0x81,
+ OP_SIZE = 0x82,
+
+ // bit logic
+ OP_INVERT = 0x83,
+ OP_AND = 0x84,
+ OP_OR = 0x85,
+ OP_XOR = 0x86,
+ OP_EQUAL = 0x87,
+ OP_EQUALVERIFY = 0x88,
+ OP_RESERVED1 = 0x89,
+ OP_RESERVED2 = 0x8a,
+
+ // numeric
+ OP_1ADD = 0x8b,
+ OP_1SUB = 0x8c,
+ OP_2MUL = 0x8d,
+ OP_2DIV = 0x8e,
+ OP_NEGATE = 0x8f,
+ OP_ABS = 0x90,
+ OP_NOT = 0x91,
+ OP_0NOTEQUAL = 0x92,
+
+ OP_ADD = 0x93,
+ OP_SUB = 0x94,
+ OP_MUL = 0x95,
+ OP_DIV = 0x96,
+ OP_MOD = 0x97,
+ OP_LSHIFT = 0x98,
+ OP_RSHIFT = 0x99,
+
+ OP_BOOLAND = 0x9a,
+ OP_BOOLOR = 0x9b,
+ OP_NUMEQUAL = 0x9c,
+ OP_NUMEQUALVERIFY = 0x9d,
+ OP_NUMNOTEQUAL = 0x9e,
+ OP_LESSTHAN = 0x9f,
+ OP_GREATERTHAN = 0xa0,
+ OP_LESSTHANOREQUAL = 0xa1,
+ OP_GREATERTHANOREQUAL = 0xa2,
+ OP_MIN = 0xa3,
+ OP_MAX = 0xa4,
+
+ OP_WITHIN = 0xa5,
+
+ // crypto
+ OP_RIPEMD160 = 0xa6,
+ OP_SHA1 = 0xa7,
+ OP_SHA256 = 0xa8,
+ OP_HASH160 = 0xa9,
+ OP_HASH256 = 0xaa,
+ OP_CODESEPARATOR = 0xab,
+ OP_CHECKSIG = 0xac,
+ OP_CHECKSIGVERIFY = 0xad,
+ OP_CHECKMULTISIG = 0xae,
+ OP_CHECKMULTISIGVERIFY = 0xaf,
+
+ // expansion
+ OP_NOP1 = 0xb0,
+ OP_CHECKLOCKTIMEVERIFY = 0xb1,
+ OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,
+ OP_CHECKSEQUENCEVERIFY = 0xb2,
+ OP_NOP3 = OP_CHECKSEQUENCEVERIFY,
+ OP_NOP4 = 0xb3,
+ OP_NOP5 = 0xb4,
+ OP_NOP6 = 0xb5,
+ OP_NOP7 = 0xb6,
+ OP_NOP8 = 0xb7,
+ OP_NOP9 = 0xb8,
+ OP_NOP10 = 0xb9,
+
+
+ // template matching params
+ OP_SMALLINTEGER = 0xfa,
+ OP_PUBKEYS = 0xfb,
+ OP_PUBKEYHASH = 0xfd,
+ OP_PUBKEY = 0xfe,
+
+ OP_INVALIDOPCODE = 0xff,
+};
+
+void op_add(enum opcode);
+const char * op_str(enum opcode);
+enum opcode op_tokenize(char *);
+
+#endif /* BCS_SCRIPT_H */