diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Leon Mergen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+haskell-bitcoin-script
+==================
+
+[![Build Status](https://travis-ci.org/solatis/haskell-bitcoin-script.png?branch=master)](https://travis-ci.org/solatis/haskell-bitcoin-script)
+[![Coverage Status](https://coveralls.io/repos/solatis/haskell-bitcoin-script/badge.svg?branch=master)](https://coveralls.io/r/solatis/haskell-bitcoin-script?branch=master)
+[![MIT](http://b.repl.ca/v1/license-MIT-blue.png)](http://en.wikipedia.org/wiki/MIT_License)
+[![Haskell](http://b.repl.ca/v1/language-haskell-lightgrey.png)](http://haskell.org)
+
+This library provides utilities for compiling, manipulation and decompiling of
+Bitcoin scripts.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+
+main = defaultMain
diff --git a/bitcoin-script.cabal b/bitcoin-script.cabal
new file mode 100644
--- /dev/null
+++ b/bitcoin-script.cabal
@@ -0,0 +1,61 @@
+name: bitcoin-script
+category: Network, Finance
+version: 0.9.0
+license: MIT
+license-file: LICENSE
+copyright: (c) 2015 Leon Mergen
+author: Leon Mergen
+maintainer: leon@solatis.com
+homepage: http://github.com/solatis/haskell-bitcoin-script
+bug-reports: http://github.com/solatis/haskell-bitcoin-script/issues
+stability: experimental
+synopsis: Compilation, manipulation and decompilation of Bitcoin scripts
+description:
+   Provides pure functions to compile, decompile and manipulate Bitcoin scripts.
+   This project relies heavily on the Haskoin project for the compiling and
+   decompiling of the script assembly, and continuously merges changes downstream.
+
+   The advantage this library has over Haskoin is that it uses very few
+   dependencies and doesn't rely on external libraries such as LevelDB and snappy.            
+                      
+build-type: Simple
+data-files: LICENSE, README.md
+cabal-version: >= 1.10
+tested-with: GHC == 7.6, GHC == 7.8, GHC == 7.10
+
+library
+  hs-source-dirs:      src
+  ghc-options:         -Wall -ferror-spans
+  default-language:    Haskell2010
+
+  exposed-modules:     Bitcoin.Script
+                       Bitcoin.Script.Types 
+
+  build-depends:       base                     >= 4.3          && < 5
+                     , text
+                     , bytestring
+                     , base16-bytestring
+                     , binary
+
+test-suite test-suite
+  type:                exitcode-stdio-1.0
+  ghc-options:         -Wall -ferror-spans -threaded -auto-all -caf-all -fno-warn-type-defaults
+  default-language:    Haskell2010
+  hs-source-dirs:      test
+  main-is:             Main.hs
+
+  other-modules:       Bitcoin.ScriptSpec
+                       Spec
+                       Main
+
+  build-depends:       base                     >= 4.3          && < 5
+                     , hspec
+                     , hspec-expectations
+
+                     , bytestring
+                     , bitcoin-script
+
+source-repository head
+  type: git
+  location: git://github.com/solatis/haskell-bitcoin-script.git
+  branch: master
diff --git a/src/Bitcoin/Script.hs b/src/Bitcoin/Script.hs
new file mode 100644
--- /dev/null
+++ b/src/Bitcoin/Script.hs
@@ -0,0 +1,17 @@
+module Bitcoin.Script where
+
+import qualified Data.Binary                 as B
+import qualified Data.ByteString.Base16.Lazy as BS16L
+import qualified Data.ByteString.Lazy        as BSL
+
+import           Bitcoin.Script.Types
+
+-- | Decodes a hex representation of a script into a 'Script' object.
+decode :: BSL.ByteString -> Script
+decode =
+  B.decode . fst . BS16L.decode
+
+-- | Encodes a 'Script' object into a hex representation
+encode :: Script -> BSL.ByteString
+encode =
+  BS16L.encode . B.encode
diff --git a/src/Bitcoin/Script/Types.hs b/src/Bitcoin/Script/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Bitcoin/Script/Types.hs
@@ -0,0 +1,528 @@
+module Bitcoin.Script.Types
+( ScriptOp(..)
+, Script(..)
+, PushDataType(..)
+, isPushOp
+, opPushData
+) where
+
+import Control.Monad (liftM2, unless, forM_)
+import Control.Applicative ((<$>))
+
+import Data.Word (Word8)
+import Data.Binary (Binary, get, put)
+import Data.Binary.Get
+    ( isEmpty
+    , getWord8
+    , getWord16le
+    , getWord32le
+    , getByteString
+    )
+import Data.Binary.Put
+    ( putWord8
+    , putWord16le
+    , putWord32le
+    , putByteString
+    )
+import qualified Data.ByteString as BS
+    ( ByteString
+    , length
+    )
+
+-- | Data type representing a transaction script. Scripts are defined as lists
+-- of script operators 'ScriptOp'. Scripts are used to:
+--
+-- * Define the spending conditions in the output of a transaction
+--
+-- * Provide the spending signatures in the input of a transaction
+data Script =
+    Script {
+             -- | List of script operators defining this script
+             scriptOps :: ![ScriptOp]
+           }
+    deriving (Eq, Show, Read)
+
+instance Binary Script where
+    get =
+        Script <$> getScriptOps
+      where
+        getScriptOps = do
+            empty <- isEmpty
+            if empty
+                then return []
+                else liftM2 (:) get getScriptOps
+
+    put (Script ops) = forM_ ops put
+
+-- | Data type representing the type of an OP_PUSHDATA opcode.
+data PushDataType
+    =
+      -- | The next opcode bytes is data to be pushed onto the stack
+      OPCODE
+      -- | The next byte contains the number of bytes to be pushed onto
+      -- the stack
+    | OPDATA1
+      -- | The next two bytes contains the number of bytes to be pushed onto
+      -- the stack
+    | OPDATA2
+      -- | The next four bytes contains the number of bytes to be pushed onto
+      -- the stack
+    | OPDATA4
+    deriving (Show, Read, Eq)
+
+-- | Data type representing all of the operators allowed inside a 'Script'.
+data ScriptOp
+      -- Pushing Data
+    = OP_PUSHDATA !BS.ByteString !PushDataType
+    | OP_0
+    | OP_1NEGATE
+    | OP_RESERVED
+    | OP_1  | 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
+
+      -- Flow control
+    | OP_NOP
+    | OP_VER        -- reserved
+    | OP_IF
+    | OP_NOTIF
+    | OP_VERIF      -- resreved
+    | OP_VERNOTIF   -- reserved
+    | OP_ELSE
+    | OP_ENDIF
+    | OP_VERIFY
+    | OP_RETURN
+
+      -- Stack operations
+    | OP_TOALTSTACK
+    | OP_FROMALTSTACK
+    | OP_IFDUP
+    | OP_DEPTH
+    | OP_DROP
+    | OP_DUP
+    | OP_NIP
+    | OP_OVER
+    | OP_PICK
+    | OP_ROLL
+    | OP_ROT
+    | OP_SWAP
+    | OP_TUCK
+    | OP_2DROP
+    | OP_2DUP
+    | OP_3DUP
+    | OP_2OVER
+    | OP_2ROT
+    | OP_2SWAP
+
+      -- Splice
+    | OP_CAT
+    | OP_SUBSTR
+    | OP_LEFT
+    | OP_RIGHT
+    | OP_SIZE
+
+      -- Bitwise logic
+    | OP_INVERT
+    | OP_AND
+    | OP_OR
+    | OP_XOR
+    | OP_EQUAL
+    | OP_EQUALVERIFY
+    | OP_RESERVED1
+    | OP_RESERVED2
+
+      -- Arithmetic
+    | 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_NOP2 | OP_NOP3 | OP_NOP4 | OP_NOP5
+    | OP_NOP6 | OP_NOP7 | OP_NOP8 | OP_NOP9 | OP_NOP10
+
+
+      -- Other
+    | OP_PUBKEYHASH
+    | OP_PUBKEY
+    | OP_INVALIDOPCODE !Word8
+
+        deriving (Show, Read, Eq)
+
+instance Binary ScriptOp where
+
+    get = go =<< (fromIntegral <$> getWord8)
+      where
+        go op
+            | op == 0x00 = return OP_0
+            | op <= 0x4b = do
+                payload <- getByteString (fromIntegral op)
+                return $ OP_PUSHDATA payload OPCODE
+            | op == 0x4c = do
+                len  <- getWord8
+                payload <- getByteString (fromIntegral len)
+                return $ OP_PUSHDATA payload OPDATA1
+            | op == 0x4d = do
+                len  <- getWord16le
+                payload <- getByteString (fromIntegral len)
+                return $ OP_PUSHDATA payload OPDATA2
+            | op == 0x4e = do
+                len  <- getWord32le
+                payload <- getByteString (fromIntegral len)
+                return $ OP_PUSHDATA payload OPDATA4
+
+            | op == 0x4f = return OP_1NEGATE
+            | op == 0x50 = return OP_RESERVED
+            | op == 0x51 = return OP_1
+            | op == 0x52 = return OP_2
+            | op == 0x53 = return OP_3
+            | op == 0x54 = return OP_4
+            | op == 0x55 = return OP_5
+            | op == 0x56 = return OP_6
+            | op == 0x57 = return OP_7
+            | op == 0x58 = return OP_8
+            | op == 0x59 = return OP_9
+            | op == 0x5a = return OP_10
+            | op == 0x5b = return OP_11
+            | op == 0x5c = return OP_12
+            | op == 0x5d = return OP_13
+            | op == 0x5e = return OP_14
+            | op == 0x5f = return OP_15
+            | op == 0x60 = return OP_16
+            -- Flow control
+            | op == 0x61 = return OP_NOP
+            | op == 0x62 = return OP_VER        -- reserved
+            | op == 0x63 = return OP_IF
+            | op == 0x64 = return OP_NOTIF
+            | op == 0x65 = return OP_VERIF      -- reserved
+            | op == 0x66 = return OP_VERNOTIF   -- reserved
+            | op == 0x67 = return OP_ELSE
+            | op == 0x68 = return OP_ENDIF
+            | op == 0x69 = return OP_VERIFY
+            | op == 0x6a = return OP_RETURN
+
+            -- Stack
+            | op == 0x6b = return OP_TOALTSTACK
+            | op == 0x6c = return OP_FROMALTSTACK
+            | op == 0x6d = return OP_2DROP
+            | op == 0x6e = return OP_2DUP
+            | op == 0x6f = return OP_3DUP
+            | op == 0x70 = return OP_2OVER
+            | op == 0x71 = return OP_2ROT
+            | op == 0x72 = return OP_2SWAP
+            | op == 0x73 = return OP_IFDUP
+            | op == 0x74 = return OP_DEPTH
+            | op == 0x75 = return OP_DROP
+            | op == 0x76 = return OP_DUP
+            | op == 0x77 = return OP_NIP
+            | op == 0x78 = return OP_OVER
+            | op == 0x79 = return OP_PICK
+            | op == 0x7a = return OP_ROLL
+            | op == 0x7b = return OP_ROT
+            | op == 0x7c = return OP_SWAP
+            | op == 0x7d = return OP_TUCK
+
+            -- Splice
+            | op == 0x7e = return OP_CAT
+            | op == 0x7f = return OP_SUBSTR
+            | op == 0x80 = return OP_LEFT
+            | op == 0x81 = return OP_RIGHT
+            | op == 0x82 = return OP_SIZE
+
+            -- Bitwise logic
+            | op == 0x83 = return OP_INVERT
+            | op == 0x84 = return OP_AND
+            | op == 0x85 = return OP_OR
+            | op == 0x86 = return OP_XOR
+            | op == 0x87 = return OP_EQUAL
+            | op == 0x88 = return OP_EQUALVERIFY
+            | op == 0x89 = return OP_RESERVED1
+            | op == 0x8a = return OP_RESERVED2
+
+            -- Arithmetic
+            | op == 0x8b = return OP_1ADD
+            | op == 0x8c = return OP_1SUB
+            | op == 0x8d = return OP_2MUL
+            | op == 0x8e = return OP_2DIV
+            | op == 0x8f = return OP_NEGATE
+            | op == 0x90 = return OP_ABS
+            | op == 0x91 = return OP_NOT
+            | op == 0x92 = return OP_0NOTEQUAL
+            | op == 0x93 = return OP_ADD
+            | op == 0x94 = return OP_SUB
+            | op == 0x95 = return OP_MUL
+            | op == 0x96 = return OP_DIV
+            | op == 0x97 = return OP_MOD
+            | op == 0x98 = return OP_LSHIFT
+            | op == 0x99 = return OP_RSHIFT
+            | op == 0x9a = return OP_BOOLAND
+            | op == 0x9b = return OP_BOOLOR
+            | op == 0x9c = return OP_NUMEQUAL
+            | op == 0x9d = return OP_NUMEQUALVERIFY
+            | op == 0x9e = return OP_NUMNOTEQUAL
+            | op == 0x9f = return OP_LESSTHAN
+            | op == 0xa0 = return OP_GREATERTHAN
+            | op == 0xa1 = return OP_LESSTHANOREQUAL
+            | op == 0xa2 = return OP_GREATERTHANOREQUAL
+            | op == 0xa3 = return OP_MIN
+            | op == 0xa4 = return OP_MAX
+            | op == 0xa5 = return OP_WITHIN
+
+            -- Crypto
+            | op == 0xa6 = return OP_RIPEMD160
+            | op == 0xa7 = return OP_SHA1
+            | op == 0xa8 = return OP_SHA256
+            | op == 0xa9 = return OP_HASH160
+            | op == 0xaa = return OP_HASH256
+            | op == 0xab = return OP_CODESEPARATOR
+            | op == 0xac = return OP_CHECKSIG
+            | op == 0xad = return OP_CHECKSIGVERIFY
+            | op == 0xae = return OP_CHECKMULTISIG
+            | op == 0xaf = return OP_CHECKMULTISIGVERIFY
+
+            -- More NOPs
+            | op == 0xb0 = return OP_NOP1
+            | op == 0xb1 = return OP_NOP2
+            | op == 0xb2 = return OP_NOP3
+            | op == 0xb3 = return OP_NOP4
+            | op == 0xb4 = return OP_NOP5
+            | op == 0xb5 = return OP_NOP6
+            | op == 0xb6 = return OP_NOP7
+            | op == 0xb7 = return OP_NOP8
+            | op == 0xb8 = return OP_NOP9
+            | op == 0xb9 = return OP_NOP10
+
+            -- Constants
+            | op == 0xfd = return OP_PUBKEYHASH
+            | op == 0xfe = return OP_PUBKEY
+
+            | otherwise = return $ OP_INVALIDOPCODE op
+
+    put op = case op of
+
+        (OP_PUSHDATA payload optype)-> do
+            let len = BS.length payload
+            case optype of
+                OPCODE -> do
+                    unless (len <= 0x4b) $ fail
+                        "OP_PUSHDATA OPCODE: Payload size too big"
+                    putWord8 $ fromIntegral len
+                OPDATA1 -> do
+                    unless (len <= 0xff) $ fail
+                        "OP_PUSHDATA OPDATA1: Payload size too big"
+                    putWord8 0x4c
+                    putWord8 $ fromIntegral len
+                OPDATA2 -> do
+                    unless (len <= 0xffff) $ fail
+                        "OP_PUSHDATA OPDATA2: Payload size too big"
+                    putWord8 0x4d
+                    putWord16le $ fromIntegral len
+                OPDATA4 -> do
+                    unless (len <= 0x7fffffff) $ fail
+                        "OP_PUSHDATA OPDATA4: Payload size too big"
+                    putWord8 0x4e
+                    putWord32le $ fromIntegral len
+            putByteString payload
+
+        -- Constants
+        OP_0                 -> putWord8 0x00
+        OP_1NEGATE           -> putWord8 0x4f
+        OP_RESERVED          -> putWord8 0x50
+        OP_1                 -> putWord8 0x51
+        OP_2                 -> putWord8 0x52
+        OP_3                 -> putWord8 0x53
+        OP_4                 -> putWord8 0x54
+        OP_5                 -> putWord8 0x55
+        OP_6                 -> putWord8 0x56
+        OP_7                 -> putWord8 0x57
+        OP_8                 -> putWord8 0x58
+        OP_9                 -> putWord8 0x59
+        OP_10                -> putWord8 0x5a
+        OP_11                -> putWord8 0x5b
+        OP_12                -> putWord8 0x5c
+        OP_13                -> putWord8 0x5d
+        OP_14                -> putWord8 0x5e
+        OP_15                -> putWord8 0x5f
+        OP_16                -> putWord8 0x60
+
+        -- Crypto Constants
+        OP_PUBKEY            -> putWord8 0xfe
+        OP_PUBKEYHASH        -> putWord8 0xfd
+
+        -- Invalid Opcodes
+        (OP_INVALIDOPCODE x) -> putWord8 x
+
+        -- Flow Control
+        OP_NOP               -> putWord8 0x61
+        OP_VER               -> putWord8 0x62
+        OP_IF                -> putWord8 0x63
+        OP_NOTIF             -> putWord8 0x64
+        OP_VERIF             -> putWord8 0x65
+        OP_VERNOTIF          -> putWord8 0x66
+        OP_ELSE              -> putWord8 0x67
+        OP_ENDIF             -> putWord8 0x68
+        OP_VERIFY            -> putWord8 0x69
+        OP_RETURN            -> putWord8 0x6a
+
+        -- Stack Operations
+        OP_TOALTSTACK        -> putWord8 0x6b
+        OP_FROMALTSTACK      -> putWord8 0x6c
+        OP_2DROP             -> putWord8 0x6d
+        OP_2DUP              -> putWord8 0x6e
+        OP_3DUP              -> putWord8 0x6f
+        OP_2OVER             -> putWord8 0x70
+        OP_2ROT              -> putWord8 0x71
+        OP_2SWAP             -> putWord8 0x72
+        OP_IFDUP             -> putWord8 0x73
+        OP_DEPTH             -> putWord8 0x74
+        OP_DROP              -> putWord8 0x75
+        OP_DUP               -> putWord8 0x76
+        OP_NIP               -> putWord8 0x77
+        OP_OVER              -> putWord8 0x78
+        OP_PICK              -> putWord8 0x79
+        OP_ROLL              -> putWord8 0x7a
+        OP_ROT               -> putWord8 0x7b
+        OP_SWAP              -> putWord8 0x7c
+        OP_TUCK              -> putWord8 0x7d
+
+        -- Splice
+        OP_CAT               -> putWord8 0x7e
+        OP_SUBSTR            -> putWord8 0x7f
+        OP_LEFT              -> putWord8 0x80
+        OP_RIGHT             -> putWord8 0x81
+        OP_SIZE              -> putWord8 0x82
+
+        -- Bitwise Logic
+        OP_INVERT            -> putWord8 0x83
+        OP_AND               -> putWord8 0x84
+        OP_OR                -> putWord8 0x85
+        OP_XOR               -> putWord8 0x86
+        OP_EQUAL             -> putWord8 0x87
+        OP_EQUALVERIFY       -> putWord8 0x88
+        OP_RESERVED1         -> putWord8 0x89
+        OP_RESERVED2         -> putWord8 0x8a
+
+        -- Arithmetic
+        OP_1ADD              -> putWord8 0x8b
+        OP_1SUB              -> putWord8 0x8c
+        OP_2MUL              -> putWord8 0x8d
+        OP_2DIV              -> putWord8 0x8e
+        OP_NEGATE            -> putWord8 0x8f
+        OP_ABS               -> putWord8 0x90
+        OP_NOT               -> putWord8 0x91
+        OP_0NOTEQUAL         -> putWord8 0x92
+        OP_ADD               -> putWord8 0x93
+        OP_SUB               -> putWord8 0x94
+        OP_MUL               -> putWord8 0x95
+        OP_DIV               -> putWord8 0x96
+        OP_MOD               -> putWord8 0x97
+        OP_LSHIFT            -> putWord8 0x98
+        OP_RSHIFT            -> putWord8 0x99
+        OP_BOOLAND           -> putWord8 0x9a
+        OP_BOOLOR            -> putWord8 0x9b
+        OP_NUMEQUAL          -> putWord8 0x9c
+        OP_NUMEQUALVERIFY    -> putWord8 0x9d
+        OP_NUMNOTEQUAL       -> putWord8 0x9e
+        OP_LESSTHAN          -> putWord8 0x9f
+        OP_GREATERTHAN       -> putWord8 0xa0
+        OP_LESSTHANOREQUAL   -> putWord8 0xa1
+        OP_GREATERTHANOREQUAL-> putWord8 0xa2
+        OP_MIN               -> putWord8 0xa3
+        OP_MAX               -> putWord8 0xa4
+        OP_WITHIN            -> putWord8 0xa5
+
+        -- Crypto
+        OP_RIPEMD160         -> putWord8 0xa6
+        OP_SHA1              -> putWord8 0xa7
+        OP_SHA256            -> putWord8 0xa8
+        OP_HASH160           -> putWord8 0xa9
+        OP_HASH256           -> putWord8 0xaa
+        OP_CODESEPARATOR     -> putWord8 0xab
+        OP_CHECKSIG          -> putWord8 0xac
+        OP_CHECKSIGVERIFY    -> putWord8 0xad
+        OP_CHECKMULTISIG     -> putWord8 0xae
+        OP_CHECKMULTISIGVERIFY -> putWord8 0xaf
+
+        -- More NOPs
+        OP_NOP1              -> putWord8 0xb0
+        OP_NOP2              -> putWord8 0xb1
+        OP_NOP3              -> putWord8 0xb2
+        OP_NOP4              -> putWord8 0xb3
+        OP_NOP5              -> putWord8 0xb4
+        OP_NOP6              -> putWord8 0xb5
+        OP_NOP7              -> putWord8 0xb6
+        OP_NOP8              -> putWord8 0xb7
+        OP_NOP9              -> putWord8 0xb8
+        OP_NOP10             -> putWord8 0xb9
+
+
+-- | Check whether opcode is only data.
+isPushOp :: ScriptOp -> Bool
+isPushOp op = case op of
+    OP_PUSHDATA _ _ -> True
+    OP_0            -> True
+    OP_1NEGATE      -> True
+    OP_1            -> True
+    OP_2            -> True
+    OP_3            -> True
+    OP_4            -> True
+    OP_5            -> True
+    OP_6            -> True
+    OP_7            -> True
+    OP_8            -> True
+    OP_9            -> True
+    OP_10           -> True
+    OP_11           -> True
+    OP_12           -> True
+    OP_13           -> True
+    OP_14           -> True
+    OP_15           -> True
+    OP_16           -> True
+    _               -> False
+
+-- | Optimally encode data using one of the 4 types of data pushing opcodes
+opPushData :: BS.ByteString -> ScriptOp
+opPushData bs
+    | len <= 0x4b       = OP_PUSHDATA bs OPCODE
+    | len <= 0xff       = OP_PUSHDATA bs OPDATA1
+    | len <= 0xffff     = OP_PUSHDATA bs OPDATA2
+    | len <= 0xffffffff = OP_PUSHDATA bs OPDATA4
+    | otherwise         = error "opPushData: payload size too big"
+  where
+    len = BS.length bs
diff --git a/test/Bitcoin/ScriptSpec.hs b/test/Bitcoin/ScriptSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Bitcoin/ScriptSpec.hs
@@ -0,0 +1,25 @@
+module Bitcoin.ScriptSpec where
+
+import           Bitcoin.Script             (decode, encode)
+import           Bitcoin.Script.Types
+
+import qualified Data.ByteString.Lazy.Char8 as BSL8 (pack)
+
+import           Test.Hspec
+import           Test.Hspec.Expectations    (expectationFailure)
+
+spec :: Spec
+spec = do
+  describe "when decompiling a specific script" $ do
+    it "encoding a decoding a script results in the original hex" $ do
+      let hex = BSL8.pack "76a914975efcba1e058667594dc57146022ec46560a63c88ac"
+
+      (encode . decode) hex `shouldBe` hex
+
+    it "succesfully parses a transaction into a meaningful object" $ do
+      let hex     = BSL8.pack "76a914975efcba1e058667594dc57146022ec46560a63c88ac"
+          decoded = decode hex
+
+      case decoded of
+       (Script [OP_DUP, OP_HASH160, OP_PUSHDATA _ OPCODE, OP_EQUALVERIFY, OP_CHECKSIG]) -> return ()
+       _                 -> expectationFailure ("Result does not match expected: " ++ show decoded)
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,8 @@
+module Main where
+
+import Test.Hspec.Runner
+import qualified Spec
+
+main :: IO ()
+main =
+  hspecWith defaultConfig Spec.spec
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover -optF --module-name=Spec #-}
