packages feed

haskoin-core (empty) → 0.2.0

raw patch · 61 files changed

+14625/−0 lines, 61 filesdep +HUnitdep +QuickCheckdep +aesonsetup-changed

Dependencies added: HUnit, QuickCheck, aeson, base, base16-bytestring, binary, byteable, bytestring, conduit, containers, cryptohash, deepseq, either, entropy, haskoin-core, largeword, mtl, murmur3, network, pbkdf, secp256k1, split, string-conversions, test-framework, test-framework-hunit, test-framework-quickcheck2, text, time, vector

Files

+ Network/Haskoin/Block.hs view
@@ -0,0 +1,40 @@+{-|+  This package provides block and block-related types.+-}+module Network.Haskoin.Block+(+  -- * Blocks+  Block(..)+, BlockLocator+, GetBlocks(..)++  -- * Block Headers+, headerHash+, BlockHeader(..)+, GetHeaders(..)+, Headers(..)+, BlockHeaderCount+, BlockHash(..)+, blockHashToHex+, hexToBlockHash++  -- * Merkle Blocks+, MerkleBlock(..)+, MerkleRoot+, FlagBits+, PartialMerkleTree+, calcTreeHeight+, calcTreeWidth+, buildMerkleRoot+, calcHash+, buildPartialMerkle+, extractMatches++  -- * Difficulty Target+, decodeCompact+, encodeCompact+) where++import Network.Haskoin.Block.Types+import Network.Haskoin.Block.Merkle+
+ Network/Haskoin/Block/Merkle.hs view
@@ -0,0 +1,209 @@+module Network.Haskoin.Block.Merkle+( MerkleBlock(..)+, MerkleRoot+, FlagBits+, PartialMerkleTree+, calcTreeHeight+, calcTreeWidth+, buildMerkleRoot+, calcHash+, buildPartialMerkle+, extractMatches+) where++import Control.Monad (forM_, replicateM)+import Control.DeepSeq (NFData, rnf)++import Data.Bits+import Data.Maybe+import Data.Word (Word8, Word32)+import Data.Binary (Binary, get, put)+import Data.Binary.Get (getWord8, getWord32le)+import Data.Binary.Put (putWord8, putWord32le)+import qualified Data.ByteString as BS++import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Block.Types+import Network.Haskoin.Transaction.Types+import Network.Haskoin.Util+import Network.Haskoin.Constants+import Network.Haskoin.Node.Types++type MerkleRoot        = Hash256+type FlagBits          = [Bool]+type PartialMerkleTree = [Hash256]++data MerkleBlock =+    MerkleBlock {+                -- | Header information for this merkle block.+                  merkleHeader :: !BlockHeader+                -- | Number of transactions in the block (including+                -- unmatched transactions).+                , merkleTotalTxns :: !Word32+                -- | Hashes in depth-first order. They are used to rebuild a+                -- partial merkle tree.+                , mHashes :: ![Hash256]+                -- | Flag bits, packed per 8 in a byte. Least significant bit+                -- first. Flag bits are used to rebuild a partial merkle+                -- tree.+                , mFlags :: ![Bool]+                } deriving (Eq, Show, Read)++instance NFData MerkleBlock where+    rnf (MerkleBlock m t h f) = rnf m `seq` rnf t `seq` rnf h `seq` rnf f++instance Binary MerkleBlock where++    get = do+        header <- get+        ntx    <- getWord32le+        (VarInt matchLen) <- get+        hashes <- replicateM (fromIntegral matchLen) get+        (VarInt flagLen)  <- get+        ws <- replicateM (fromIntegral flagLen) getWord8+        return $ MerkleBlock header ntx hashes (decodeMerkleFlags ws)++    put (MerkleBlock h ntx hashes flags) = do+        put h+        putWord32le ntx+        put $ VarInt $ fromIntegral $ length hashes+        forM_ hashes put+        let ws = encodeMerkleFlags flags+        put $ VarInt $ fromIntegral $ length ws+        forM_ ws putWord8++decodeMerkleFlags :: [Word8] -> [Bool]+decodeMerkleFlags ws =+    [ b | p <- [0..(length ws)*8-1]+    , b <- [testBit (ws !! (p `div` 8)) (p `mod` 8)]+    ]++encodeMerkleFlags :: [Bool] -> [Word8]+encodeMerkleFlags bs = map boolsToWord8 $ splitIn 8 bs++-- | Computes the height of a merkle tree.+calcTreeHeight :: Int -- ^ Number of transactions (leaf nodes).+               -> Int -- ^ Height of the merkle tree.+calcTreeHeight ntx | ntx < 2 = 0+                   | even ntx  = 1 + calcTreeHeight (ntx `div` 2)+                   | otherwise = calcTreeHeight $ ntx + 1++-- | Computes the width of a merkle tree at a specific height. The transactions+-- are at height 0.+calcTreeWidth :: Int -- ^ Number of transactions (leaf nodes).+              -> Int -- ^ Height at which we want to compute the width.+              -> Int -- ^ Width of the merkle tree.+calcTreeWidth ntx h = (ntx + (1 `shiftL` h) - 1) `shiftR` h++-- | Computes the root of a merkle tree from a list of leaf node hashes.+buildMerkleRoot :: [TxHash]   -- ^ List of transaction hashes (leaf nodes).+                -> MerkleRoot -- ^ Root of the merkle tree.+buildMerkleRoot txs = calcHash (calcTreeHeight $ length txs) 0 txs++hash2 :: Hash256 -> Hash256 -> Hash256+hash2 a b = doubleHash256 $ encode' a `BS.append` encode' b++-- | Computes the hash of a specific node in a merkle tree.+calcHash :: Int       -- ^ Height of the node in the merkle tree.+         -> Int       -- ^ Position of the node (0 for the leftmost node).+         -> [TxHash]  -- ^ Transaction hashes of the merkle tree (leaf nodes).+         -> Hash256   -- ^ Hash of the node at the specified position.+calcHash height pos txs+    | height < 0 || pos < 0 = error "calcHash: Invalid parameters"+    | height == 0 = getTxHash $ txs !! pos+    | otherwise = hash2 left right+  where+    left = calcHash (height-1) (pos*2) txs+    right | pos*2+1 < calcTreeWidth (length txs) (height-1) =+                calcHash (height-1) (pos*2+1) txs+          | otherwise = left++-- | Build a partial merkle tree.+buildPartialMerkle+    :: [(TxHash,Bool)]+    -- ^ List of transactions hashes forming the leaves of the merkle tree+    -- and a bool indicating if that transaction should be included in the+    -- partial merkle tree.+    -> (FlagBits, PartialMerkleTree)+    -- ^ Flag bits (used to parse the partial merkle tree) and the+    -- partial merkle tree.+buildPartialMerkle hs = traverseAndBuild (calcTreeHeight $ length hs) 0 hs++traverseAndBuild :: Int -> Int -> [(TxHash,Bool)]+                 -> (FlagBits, PartialMerkleTree)+traverseAndBuild height pos txs+    | height < 0 || pos < 0 = error "traverseAndBuild: Invalid parameters"+    | height == 0 || not match = ([match],[calcHash height pos t])+    | otherwise = (match : lb ++ rb, lh ++ rh)+  where+    t = map fst txs+    s = pos `shiftL` height+    e = min (length txs) $ (pos+1) `shiftL` height+    match = or $ map snd $ take (e-s) $ drop s txs+    (lb,lh) = traverseAndBuild (height-1) (pos*2) txs+    (rb,rh) | (pos*2+1) < calcTreeWidth (length txs) (height-1)+                = traverseAndBuild (height-1) (pos*2+1) txs+            | otherwise = ([],[])++traverseAndExtract :: Int -> Int -> Int -> FlagBits -> PartialMerkleTree+                   -> Maybe (MerkleRoot, [TxHash], Int, Int)+traverseAndExtract height pos ntx flags hashes+    | length flags == 0         = Nothing+    | height == 0 || not match = leafResult+    | isNothing leftM          = Nothing+    | (pos*2+1) >= calcTreeWidth ntx (height-1) =+        Just (hash2 lh lh, lm, lcf+1, lch)+    | isNothing rightM         = Nothing+    | otherwise =+        Just (hash2 lh rh, lm ++ rm, lcf+rcf+1, lch+rch)+  where+    leafResult+        | null hashes = Nothing+        | otherwise = Just+            (h, if height == 0 && match then [TxHash h] else [], 1, 1)+    (match:fs) = flags+    (h:_)     = hashes+    leftM  = traverseAndExtract (height-1) (pos*2) ntx fs hashes+    (lh,lm,lcf,lch) = fromMaybe e leftM+    rightM = traverseAndExtract (height-1) (pos*2+1) ntx+                (drop lcf fs) (drop lch hashes)+    (rh,rm,rcf,rch) = fromMaybe e rightM+    e = error "traverseAndExtract: unexpected error extracting a Maybe value"++-- | Extracts the matching hashes from a partial merkle tree. This will return+-- the list of transaction hashes that have been included (set to True) in+-- a call to 'buildPartialMerkle'.+extractMatches :: FlagBits -- ^ Flag bits (produced by buildPartialMerkle).+               -> PartialMerkleTree -- ^ Partial merkle tree.+               -> Int -- ^ Number of transaction at height 0 (leaf nodes).+               -> Either String (MerkleRoot, [TxHash])+               -- ^ Merkle root and the list of matching transaction hashes.+extractMatches flags hashes ntx+    | ntx == 0 = Left $+        "extractMatches: number of transactions can not be 0"+    | ntx > maxBlockSize `div` 60 = Left $+        "extractMatches: number of transactions excessively high"+    | length hashes > ntx = Left $+        "extractMatches: More hashes provided than the number of transactions"+    | length flags < length hashes = Left $+        "extractMatches: At least one bit per node and one bit per hash"+    | isNothing resM = Left $+        "extractMatches: traverseAndExtract failed"+    | (nBitsUsed+7) `div` 8 /= (length flags+7) `div` 8 = Left $+        "extractMatches: All bits were not consumed"+    | nHashUsed /= length hashes = Left $+        "extractMatches: All hashes were not consumed: " ++ (show nHashUsed)+    | otherwise = return (merkRoot, matches)+  where+    resM = traverseAndExtract (calcTreeHeight ntx) 0 ntx flags hashes+    (merkRoot, matches, nBitsUsed, nHashUsed) = fromMaybe e resM+    e = error "extractMatches: unexpected error extracting a Maybe value"++splitIn :: Int -> [a] -> [[a]]+splitIn _ [] = []+splitIn c xs = take c xs : (splitIn c $ drop c xs)++boolsToWord8 :: [Bool] -> Word8+boolsToWord8 [] = 0+boolsToWord8 xs = foldl setBit 0 (map snd $ filter fst $ zip xs [0..7])+
+ Network/Haskoin/Block/Types.hs view
@@ -0,0 +1,299 @@+module Network.Haskoin.Block.Types+( Block(..)+, BlockHeader(..)+, BlockLocator+, GetBlocks(..)+, GetHeaders(..)+, BlockHeaderCount+, BlockHash(..)+, blockHashToHex+, hexToBlockHash+, Headers(..)+, headerHash+, decodeCompact+, encodeCompact+) where++import Control.DeepSeq (NFData, rnf)+import Control.Monad (liftM2, replicateM, forM_, mzero)++import Data.Maybe (fromMaybe)+import Data.Aeson (Value(String), FromJSON, ToJSON, parseJSON, toJSON, withText)+import Data.Bits ((.&.), (.|.), shiftR, shiftL)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS (length, reverse)+import Data.Word (Word32)+import Data.Binary (Binary, get, put)+import Data.Binary.Get (getWord32le)+import Data.Binary.Put (putWord32le)+import Data.String (IsString, fromString)+import Data.String.Conversions (cs)+import Text.Read (readPrec, parens, lexP, pfail)+import qualified Text.Read as Read (Lexeme(Ident, String))++import Network.Haskoin.Util+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Node.Types+import Network.Haskoin.Transaction.Types++-- | Data type describing a block in the bitcoin protocol. Blocks are sent in+-- response to 'GetData' messages that are requesting information from a+-- block hash.+data Block =+    Block {+            -- | Header information for this block.+            blockHeader     :: !BlockHeader+            -- | Coinbase transaction of this block.+          , blockCoinbaseTx :: !CoinbaseTx+            -- | List of transactions pertaining to this block.+          , blockTxns       :: ![Tx]+          } deriving (Eq, Show, Read)++instance NFData Block where+    rnf (Block h c ts) = rnf h `seq` rnf c `seq` rnf ts++instance Binary Block where++    get = do+        header     <- get+        (VarInt c) <- get+        cb         <- get+        txs        <- replicateM (fromIntegral (c-1)) get+        return $ Block header cb txs++    put (Block h cb txs) = do+        put h+        put $ VarInt $ fromIntegral $ (length txs) + 1+        put cb+        forM_ txs put++newtype BlockHash = BlockHash { getBlockHash :: Hash256 }+    deriving (Eq, Ord)++instance NFData BlockHash where+    rnf (BlockHash h) = rnf $ getHash256 h++instance Show BlockHash where+    showsPrec d h = showParen (d > 10) $+        showString "BlockHash " . shows (blockHashToHex h)++instance Read BlockHash where+    readPrec = parens $ do+        Read.Ident "BlockHash" <- lexP+        Read.String str <- lexP+        maybe pfail return $ hexToBlockHash $ cs str++instance IsString BlockHash where+    fromString = fromMaybe e . hexToBlockHash . cs where+        e = error "Could not read block hash from hex string"++instance Binary BlockHash where+    get = BlockHash <$> get+    put = put . getBlockHash++instance FromJSON BlockHash where+    parseJSON = withText "Block hash" $ \t -> do+        maybe mzero return $ BlockHash <$> (bsToHash256 =<< decodeHex (cs t))++instance ToJSON BlockHash where+    toJSON h = String $ cs $ encodeHex $ getHash256 $ getBlockHash h++blockHashToHex :: BlockHash -> ByteString+blockHashToHex (BlockHash h) = encodeHex $ BS.reverse $ getHash256 h++hexToBlockHash :: ByteString -> Maybe BlockHash+hexToBlockHash hex = do+    bs <- BS.reverse <$> decodeHex hex+    h <- bsToHash256 bs+    return $ BlockHash h++-- | Compute the hash of a block header+headerHash :: BlockHeader -> BlockHash+headerHash = BlockHash . doubleHash256 . encode'++-- | Data type recording information on a 'Block'. The hash of a block is+-- defined as the hash of this data structure. The block mining process+-- involves finding a partial hash collision by varying the nonce in the+-- 'BlockHeader' and/or additional randomness in the 'CoinbaseTx' of this+-- 'Block'. Variations in the 'CoinbaseTx' will result in different merkle+-- roots in the 'BlockHeader'.+data BlockHeader =+    BlockHeader {+                  -- | Block version information, based on the version of the+                  -- software creating this block.+                  blockVersion   :: !Word32+                  -- | Hash of the previous block (parent) referenced by this+                  -- block.+                , prevBlock      :: !BlockHash+                  -- | Root of the merkle tree of all transactions pertaining+                  -- to this block.+                , merkleRoot     :: !Hash256+                  -- | Unix timestamp recording when this block was created+                , blockTimestamp :: !Word32+                  -- | The difficulty target being used for this block+                , blockBits      :: !Word32+                  -- | A random nonce used to generate this block. Additional+                  -- randomness is included in the coinbase transaction of+                  -- this block.+                , bhNonce        :: !Word32+                } deriving (Eq, Show, Read)++instance NFData BlockHeader where+    rnf (BlockHeader v p m t b n) =+        rnf v `seq` rnf p `seq` rnf m `seq` rnf t `seq` rnf b `seq` rnf n++instance Binary BlockHeader where++    get = BlockHeader <$> getWord32le+                      <*> get+                      <*> get+                      <*> getWord32le+                      <*> getWord32le+                      <*> getWord32le++    put (BlockHeader v p m bt bb n) = do+        putWord32le v+        put         p+        put         m+        putWord32le bt+        putWord32le bb+        putWord32le n++type BlockLocator = [BlockHash]++-- | Data type representing a GetBlocks message request. It is used in the+-- bitcoin protocol to retrieve blocks from a peer by providing it a+-- 'BlockLocator' object. The 'BlockLocator' is a sparse list of block hashes+-- from the caller node with the purpose of informing the receiving node+-- about the state of the caller's blockchain. The receiver node will detect+-- a wrong branch in the caller's main chain and send the caller appropriate+-- 'Blocks'. The response to a 'GetBlocks' message is an 'Inv' message+-- containing the list of block hashes pertaining to the request.+data GetBlocks =+    GetBlocks {+                -- | The protocol version+                getBlocksVersion  :: !Word32+                -- | Block locator object. It is a list of block hashes from the+                -- most recent block back to the genesis block. The list is+                -- dense at first and sparse towards the end.+              , getBlocksLocator  :: !BlockLocator+                -- | Hash of the last desired block. If set to zero, the+                -- maximum number of block hashes is returned (500).+              , getBlocksHashStop :: !BlockHash+              } deriving (Eq, Show, Read)++instance NFData GetBlocks where+    rnf (GetBlocks v l h) = rnf v `seq` rnf l `seq` rnf h++instance Binary GetBlocks where++    get = GetBlocks <$> getWord32le+                    <*> (repList =<< get)+                    <*> get+      where+        repList (VarInt c) = replicateM (fromIntegral c) get++    put (GetBlocks v xs h) = do+        putWord32le v+        put $ VarInt $ fromIntegral $ length xs+        forM_ xs put+        put h++-- | Similar to the 'GetBlocks' message type but for retrieving block headers+-- only. The response to a 'GetHeaders' request is a 'Headers' message+-- containing a list of block headers pertaining to the request. A maximum of+-- 2000 block headers can be returned. 'GetHeaders' is used by thin (SPV)+-- clients to exclude block contents when synchronizing the blockchain.+data GetHeaders =+    GetHeaders {+                 -- | The protocol version+                 getHeadersVersion  :: !Word32+                 -- | Block locator object. It is a list of block hashes from+                 -- the most recent block back to the Genesis block. The list+                 -- is dense at first and sparse towards the end.+               , getHeadersBL       :: !BlockLocator+                 -- | Hash of the last desired block header. When set to zero,+                 -- the maximum number of block headers is returned (2000)+               , getHeadersHashStop :: !BlockHash+               } deriving (Eq, Show, Read)++instance NFData GetHeaders where+    rnf (GetHeaders v l h) = rnf v `seq` rnf l `seq` rnf h++instance Binary GetHeaders where++    get = GetHeaders <$> getWord32le+                     <*> (repList =<< get)+                     <*> get+      where+        repList (VarInt c) = replicateM (fromIntegral c) get++    put (GetHeaders v xs h) = do+        putWord32le v+        put $ VarInt $ fromIntegral $ length xs+        forM_ xs put+        put h++-- | 'BlockHeader' type with a transaction count as 'VarInt'+type BlockHeaderCount = (BlockHeader, VarInt)++-- | The 'Headers' type is used to return a list of block headers in+-- response to a 'GetHeaders' message.+data Headers =+    Headers {+              -- | List of block headers with respective transaction counts+              headersList :: ![BlockHeaderCount]+            }+    deriving (Eq, Show, Read)++instance NFData Headers where+    rnf (Headers l) = rnf l++instance Binary Headers where++    get = Headers <$> (repList =<< get)+      where+        repList (VarInt c) = replicateM (fromIntegral c) action+        action = liftM2 (,) get get++    put (Headers xs) = do+        put $ VarInt $ fromIntegral $ length xs+        forM_ xs $ \(a,b) -> put a >> put b++-- | Decode the compact number used in the difficulty target of a block into an+-- Integer.+--+-- As described in the Satoshi reference implementation /src/bignum.h:+--+-- The "compact" format is a representation of a whole number N using an+-- unsigned 32bit number similar to a floating point format. The most+-- significant 8 bits are the unsigned exponent of base 256. This exponent can+-- be thought of as "number of bytes of N". The lower 23 bits are the mantissa.+-- Bit number 24 (0x800000) represents the sign of N.+--+-- >    N = (-1^sign) * mantissa * 256^(exponent-3)+decodeCompact :: Word32 -> Integer+decodeCompact c =+    if neg then (-res) else res+  where+    size = fromIntegral $ c `shiftR` 24+    neg  = (c .&. 0x00800000) /= 0+    wrd  = c .&. 0x007fffff+    res | size <= 3 = (toInteger wrd) `shiftR` (8*(3 - size))+        | otherwise = (toInteger wrd) `shiftL` (8*(size - 3))++-- | Encode an Integer to the compact number format used in the difficulty+-- target of a block.+encodeCompact :: Integer -> Word32+encodeCompact i+    | i < 0     = c3 .|. 0x00800000+    | otherwise = c3+  where+    posi = abs i+    s1 = BS.length $ integerToBS posi+    c1 | s1 < 3    = posi `shiftL` (8*(3 - s1))+       | otherwise = posi `shiftR` (8*(s1 - 3))+    (s2,c2) | c1 .&. 0x00800000 /= 0  = (s1 + 1, c1 `shiftR` 8)+            | otherwise               = (s1, c1)+    c3 = fromIntegral $ c2 .|. ((toInteger s2) `shiftL` 24)+
+ Network/Haskoin/Constants.hs view
@@ -0,0 +1,249 @@+{-# OPTIONS_GHC -fno-cse -fno-full-laziness #-}+{-|+  Network specific constants+-}+module Network.Haskoin.Constants+( -- ** Data+  Network(..)+  -- ** Functions+, switchToTestnet3+, setNetwork+, getNetwork+  -- ** Network parameters+, networkName+, addrPrefix+, scriptPrefix+, secretPrefix+, extPubKeyPrefix+, extSecretPrefix+, networkMagic+, genesisHeader+, maxBlockSize+, maxSatoshi+, haskoinUserAgent+, defaultPort+, allowMinDifficultyBlocks+, powLimit+, targetTimespan+, targetSpacing+, checkpoints+) where++import Data.Bits (shiftR)+import Data.ByteString (ByteString)+import Data.IORef (IORef, newIORef, readIORef, writeIORef)+import Data.Word (Word8, Word32, Word64)+import Data.LargeWord (Word256)+import Network.Haskoin.Block.Types+import System.IO.Unsafe (unsafePerformIO)++data Network = Network+    { getNetworkName                :: !String+    , getAddrPrefix                 :: !Word8+    , getScriptPrefix               :: !Word8+    , getSecretPrefix               :: !Word8+    , getExtPubKeyPrefix            :: !Word32+    , getExtSecretPrefix            :: !Word32+    , getNetworkMagic               :: !Word32+    , getGenesisHeader              :: !BlockHeader+    , getMaxBlockSize               :: !Int+    , getMaxSatoshi                 :: !Word64+    , getHaskoinUserAgent           :: !ByteString+    , getDefaultPort                :: !Int+    , getAllowMinDifficultyBlocks   :: !Bool+    , getPowLimit                   :: !Integer+    , getTargetTimespan             :: !Word32+    , getTargetSpacing              :: !Word32+    , getCheckpoints                :: ![(Int, BlockHash)]+    } deriving (Eq, Show, Read)++-- | Switch to Testnet3.  Do at start of program.+switchToTestnet3 :: IO ()+switchToTestnet3 = setNetwork testnet3++-- | Change network constants manually.  If switching to Testnet3, use+-- switchToTestnet3 instead.+setNetwork :: Network -> IO ()+setNetwork = writeIORef networkRef++{-# NOINLINE networkRef #-}+-- | Use this if you want to change constants to something other than Testnet3.+networkRef :: IORef Network+networkRef = unsafePerformIO $ newIORef prodnet++{-# NOINLINE getNetwork #-}+-- | Read current network constants record+getNetwork :: Network+getNetwork = unsafePerformIO $ readIORef networkRef++-- | Name of the bitcoin network+networkName :: String+networkName = getNetworkName getNetwork++-- | Prefix for base58 PubKey hash address+addrPrefix :: Word8+addrPrefix = getAddrPrefix getNetwork++-- | Prefix for base58 script hash address+scriptPrefix :: Word8+scriptPrefix = getScriptPrefix getNetwork++-- | Prefix for private key WIF format+secretPrefix :: Word8+secretPrefix = getSecretPrefix getNetwork++-- | Prefix for extended public keys (BIP32)+extPubKeyPrefix :: Word32+extPubKeyPrefix = getExtPubKeyPrefix getNetwork++-- | Prefix for extended private keys (BIP32)+extSecretPrefix :: Word32+extSecretPrefix = getExtSecretPrefix getNetwork++-- | Network magic bytes+networkMagic :: Word32+networkMagic = getNetworkMagic getNetwork++-- | Genesis block header information+genesisHeader :: BlockHeader+genesisHeader = getGenesisHeader getNetwork++-- | Maximum size of a block in bytes+maxBlockSize :: Int+maxBlockSize = getMaxBlockSize getNetwork++-- | Maximum number of satoshi+maxSatoshi :: Word64+maxSatoshi = getMaxSatoshi getNetwork++-- | User agent string+haskoinUserAgent :: ByteString+haskoinUserAgent = getHaskoinUserAgent getNetwork++-- | Default port+defaultPort :: Int+defaultPort = getDefaultPort getNetwork++-- | Allow relaxed difficulty transition rules+allowMinDifficultyBlocks :: Bool+allowMinDifficultyBlocks = getAllowMinDifficultyBlocks getNetwork++-- | Lower bound for the proof of work difficulty+powLimit :: Integer+powLimit = getPowLimit getNetwork++-- | Time between difficulty cycles (2 weeks on average)+targetTimespan :: Word32+targetTimespan = getTargetTimespan getNetwork++-- | Time between blocks (10 minutes per block)+targetSpacing :: Word32+targetSpacing = getTargetSpacing getNetwork++-- | Checkpoints to enfore+checkpoints :: [(Int, BlockHash)]+checkpoints = getCheckpoints getNetwork++prodnet :: Network+prodnet = Network+    { getNetworkName = "prodnet"+    , getAddrPrefix = 0+    , getScriptPrefix = 5+    , getSecretPrefix = 128+    , getExtPubKeyPrefix = 0x0488b21e+    , getExtSecretPrefix = 0x0488ade4+    , getNetworkMagic = 0xf9beb4d9+    , getGenesisHeader = BlockHeader+        -- Hash 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f+        { blockVersion   = 0x01+        , prevBlock      =+          "0000000000000000000000000000000000000000000000000000000000000000"+        , merkleRoot     =+          "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a"+        , blockTimestamp = 1231006505+        , blockBits      = 486604799+        , bhNonce        = 2083236893+        }+    , getMaxBlockSize = 1000000+    , getMaxSatoshi = 2100000000000000+    , getHaskoinUserAgent = "/haskoin:0.2.0/"+    , getDefaultPort = 8333+    , getAllowMinDifficultyBlocks = False+    , getPowLimit = fromIntegral (maxBound `shiftR` 32 :: Word256)+    , getTargetTimespan = 14 * 24 * 60 * 60+    , getTargetSpacing = 10 * 60+    , getCheckpoints =+        [ ( 11111+          , "0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"+          )+        , ( 33333+          , "000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"+          )+        , ( 74000+          , "0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"+          )+        , ( 105000+          , "00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"+          )+        , ( 134444+          , "00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"+          )+        , ( 168000+          , "000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"+          )+        , ( 193000+          , "000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"+          )+        , ( 210000+          , "000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"+          )+        , ( 216116+          , "00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"+          )+        , ( 225430+          , "00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932"+          )+        , ( 250000+          , "000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"+          )+        , ( 279000+          , "0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40"+          )+        ]+    }++testnet3 :: Network+testnet3 = Network+    { getNetworkName = "testnet"+    , getAddrPrefix = 111+    , getScriptPrefix = 196+    , getSecretPrefix = 239+    , getExtPubKeyPrefix = 0x043587cf+    , getExtSecretPrefix = 0x04358394+    , getNetworkMagic = 0x0b110907+    , getGenesisHeader = BlockHeader+        -- Hash 000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943+        { blockVersion   = 0x01+        , prevBlock      =+            "0000000000000000000000000000000000000000000000000000000000000000"+        , merkleRoot     =+            "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a"+        , blockTimestamp = 1296688602+        , blockBits      = 486604799+        , bhNonce        = 414098458+        }+    , getMaxBlockSize = 1000000+    , getMaxSatoshi = 2100000000000000+    , getHaskoinUserAgent = "/haskoin-testnet:0.2.0/"+    , getDefaultPort = 18333+    , getAllowMinDifficultyBlocks = True+    , getPowLimit = fromIntegral (maxBound `shiftR` 32 :: Word256)+    , getTargetTimespan = 14 * 24 * 60 * 60+    , getTargetSpacing = 10 * 60+    , getCheckpoints =+        [ ( 546+          , "000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"+          )+        ]+    }+
+ Network/Haskoin/Crypto.hs view
@@ -0,0 +1,172 @@+{-|+  This package provides the elliptic curve cryptography required for creating+  and validating bitcoin transactions. It also provides SHA-256 and RIPEMD-160+  hashing functions; as well as mnemonic keys from BIP-0039.+-}+module Network.Haskoin.Crypto+(+  -- *Elliptic Curve Keys++  -- **Public Keys+  PubKey, PubKeyC, PubKeyU+, makePubKey+, makePubKeyG+, makePubKeyC+, makePubKeyU+, toPubKeyG+, eitherPubKey+, maybePubKeyC+, maybePubKeyU+, derivePubKey+, pubKeyAddr+, tweakPubKeyC++  -- **Private Keys+, PrvKey, PrvKeyC, PrvKeyU+, makePrvKey+, makePrvKeyG+, makePrvKeyC+, makePrvKeyU+, toPrvKeyG+, eitherPrvKey+, maybePrvKeyC+, maybePrvKeyU+, encodePrvKey+, decodePrvKey+, prvKeyPutMonad+, prvKeyGetMonad+, fromWif+, toWif+, tweakPrvKeyC++  -- *ECDSA+  -- **SecretT Monad+  -- | The 'SecretT' monad is a monadic wrapper around  HMAC DRBG+  -- (deterministic random byte generator) using SHA-256. The specification is+  -- defined in+  -- <http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf>. The+  -- 'SecretT' monad is used to generate random private keys.+, SecretT+, withSource+, getEntropy+, genPrvKey++  -- **Signatures+  -- | Elliptic curve cryptography standards are defined in+  -- <http://www.secg.org/sec1-v2.pdf>+, Signature+, signMsg+, verifySig+, isCanonicalHalfOrder+, decodeDerSig+, decodeStrictSig++  -- *Hash functions+, CheckSum32(getCheckSum32)+, Hash512(getHash512)+, Hash256(getHash256)+, Hash160(getHash160)+, bsToCheckSum32+, bsToHash512+, bsToHash256+, bsToHash160+, checkSum32+, hash512+, hash256+, hash160+, sha1+, doubleHash256+, hmac512+, hmac256+, split512+, join512++  -- *Base58 and Addresses+, Address(..)+, base58ToAddr+, addrToBase58+, encodeBase58+, decodeBase58+, encodeBase58Check+, decodeBase58Check++  -- *Mnemonic keys (BIP-0039)+, Entropy+, Mnemonic+, Passphrase+, Seed+, toMnemonic+, mnemonicToSeed++  -- *Extended Keys+, KeyIndex+, ChainCode++  -- **Extended Private Keys+, XPrvKey(..)+, makeXPrvKey+, xPrvIsHard+, xPrvChild+, xPrvID+, xPrvFP+, xPrvExport+, xPrvImport+, xPrvWif++  -- **Extended Public Keys+, XPubKey(..)+, deriveXPubKey+, xPubIsHard+, xPubChild+, xPubID+, xPubFP+, xPubAddr+, xPubExport+, xPubImport++  -- **Child key derivations+, prvSubKey+, pubSubKey+, hardSubKey+, prvSubKeys+, pubSubKeys+, hardSubKeys++  -- ** Address derivations+, deriveAddr+, deriveAddrs+, deriveMSAddr+, deriveMSAddrs++  -- ** Custom path derivations+, DerivPathI((:|), (:/), Deriv, DerivPrv, DerivPub)+, DerivPath+, HardPath+, SoftPath+, pathToStr+, parsePath+, parseHard+, parseSoft+, toHard+, toSoft+, toMixed+, (++/), (++|)+, derivePath+, derivePubPath+, derivePathE++  -- * Custom path address derivations+, derivePathAddr+, derivePathAddrs+, derivePathMSAddr+, derivePathMSAddrs++) where++import Network.Haskoin.Crypto.ECDSA+import Network.Haskoin.Crypto.Keys+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Crypto.Base58+import Network.Haskoin.Crypto.Mnemonic+import Network.Haskoin.Crypto.ExtendedKeys+
+ Network/Haskoin/Crypto/Base58.hs view
@@ -0,0 +1,151 @@+module Network.Haskoin.Crypto.Base58+( Address(..)+, addrToBase58+, base58ToAddr+, encodeBase58+, decodeBase58+, encodeBase58Check+, decodeBase58Check+) where++import Control.DeepSeq (NFData, rnf)+import Control.Monad (guard, mzero)++import Data.Maybe (fromMaybe, isJust, listToMaybe)+import Numeric (showIntAtBase, readInt)+import Data.Aeson+    ( Value (String)+    , FromJSON+    , ToJSON+    , parseJSON+    , toJSON+    , withText+    )++import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as C+import Data.String (IsString, fromString)+import Data.String.Conversions (cs)++import Text.Read (readPrec, parens, lexP, pfail)+import qualified Text.Read as Read (Lexeme(Ident, String))++import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Constants+import Network.Haskoin.Util++b58Data :: ByteString+b58Data = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"++b58 :: Int -> Char+b58 = C.index b58Data++b58' :: Char -> Maybe Int+b58' = flip C.elemIndex b58Data++encodeBase58I :: Integer -> ByteString+encodeBase58I i = cs $ showIntAtBase 58 b58 i ""++decodeBase58I :: ByteString -> Maybe Integer+decodeBase58I s =+    case go of+        Just (r,[]) -> Just r+        _           -> Nothing+  where+    p = isJust . b58'+    f = fromMaybe e . b58'+    go = listToMaybe $ readInt 58 p f (cs s)+    e = error "Could not decode base58"++-- | Encode a 'ByteString' to a base 58 representation.+encodeBase58 :: ByteString -> ByteString+encodeBase58 bs =+    l `mappend` r+  where+    (z, b) = BS.span (== 0) bs+    l = BS.replicate (BS.length z) (BS.index b58Data 0) -- preserve leading 0's+    r | BS.null b = BS.empty+      | otherwise = encodeBase58I $ bsToInteger b++-- | Decode a base58-encoded 'ByteString'. This can fail if the input+-- 'ByteString' contains invalid base58 characters such as 0, O, l, I.+decodeBase58 :: ByteString -> Maybe ByteString+decodeBase58 t =+    BS.append prefix <$> r+  where+    (z, b)  = BS.span (== BS.index b58Data 0) t+    prefix = BS.replicate (BS.length z) 0 -- preserve leading 1's+    r | BS.null b = Just BS.empty+      | otherwise = integerToBS <$> decodeBase58I b++-- | Computes a checksum for the input 'ByteString' and encodes the input and+-- the checksum to a base58 representation.+encodeBase58Check :: ByteString -> ByteString+encodeBase58Check bs = encodeBase58 $ BS.append bs (encode' $ checkSum32 bs)++-- | Decode a base58-encoded string that contains a checksum. This function+-- returns 'Nothing' if the input string contains invalid base58 characters or+-- if the checksum fails.+decodeBase58Check :: ByteString -> Maybe ByteString+decodeBase58Check bs = do+    rs <- decodeBase58 bs+    let (res, chk) = BS.splitAt (BS.length rs - 4) rs+    guard $ chk == encode' (checkSum32 res)+    return res++-- | Data type representing a Bitcoin address+data Address+    -- | Public Key Hash Address+    = PubKeyAddress { getAddrHash :: !Hash160 }+    -- | Script Hash Address+    | ScriptAddress { getAddrHash :: !Hash160 }+       deriving (Eq, Ord)++-- TODO: Test+instance Show Address where+    showsPrec d a = showParen (d > 10) $+        showString "Address " . shows (addrToBase58 a)++-- TODO: Test+instance Read Address where+    readPrec = parens $ do+        Read.Ident "Address" <- lexP+        Read.String str <- lexP+        maybe pfail return $ base58ToAddr $ cs str++-- TODO: Test+instance IsString Address where+    fromString =+        fromMaybe e . base58ToAddr . cs+      where+        e = error "Could not decode bitcoin address"++instance NFData Address where+    rnf (PubKeyAddress h) = rnf h+    rnf (ScriptAddress h) = rnf h++instance FromJSON Address where+    parseJSON = withText "Address" $+        maybe mzero return . base58ToAddr . cs++instance ToJSON Address where+    toJSON = String . cs . addrToBase58++-- | Transforms an Address into a base58 encoded String+addrToBase58 :: Address -> ByteString+addrToBase58 addr = encodeBase58Check $ case addr of+    PubKeyAddress h -> BS.cons addrPrefix   $ getHash160 h+    ScriptAddress h -> BS.cons scriptPrefix $ getHash160 h++-- | Decodes an Address from a base58 encoded String. This function can fail+-- if the String is not properly encoded as base58 or the checksum fails.+base58ToAddr :: ByteString -> Maybe Address+base58ToAddr str = do+    val <- decodeBase58Check str+    guard $ BS.length val == 21+    let f | BS.head val == addrPrefix   = Just PubKeyAddress+          | BS.head val == scriptPrefix = Just ScriptAddress+          | otherwise = Nothing+    f <*> bsToHash160 (BS.tail val)+
+ Network/Haskoin/Crypto/ECDSA.hs view
@@ -0,0 +1,139 @@+-- | ECDSA Signatures+module Network.Haskoin.Crypto.ECDSA+( SecretT+, Signature(..)+, withSource+, getEntropy+, signMsg+, verifySig+, genPrvKey+, isCanonicalHalfOrder+, decodeDerSig+, decodeStrictSig+) where++import Numeric (showHex)++import Control.DeepSeq (NFData, rnf)+import Control.Monad (when, unless, guard)+import Control.Monad.Trans (lift)+import qualified Control.Monad.State as S+    ( StateT+    , evalStateT+    , get, put+    )++import Data.Maybe (fromMaybe)+import Data.Binary (Binary, get, put)+import Data.Binary.Put (putByteString, putByteString)+import Data.Binary.Get (getWord8, lookAhead, getByteString)+import Data.ByteString (ByteString)+import System.Entropy (getEntropy)++import qualified Crypto.Secp256k1 as EC++import Network.Haskoin.Constants+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Crypto.Keys++-- | Internal state of the 'SecretT' monad+type SecretState m = (WorkingState, Int -> m ByteString)++-- | StateT monad stack tracking the internal state of HMAC DRBG+-- pseudo random number generator using SHA-256. The 'SecretT' monad is+-- run with the 'withSource' function by providing it a source of entropy.+type SecretT m = S.StateT (SecretState m) m++-- | Run a 'SecretT' monad by providing it a source of entropy. You can+-- use 'getEntropy' or provide your own entropy source function.+withSource :: Monad m => (Int -> m ByteString) -> SecretT m a -> m a+withSource f m = do+    seed  <- f 32 -- Read 256 bits from the random source+    nonce <- f 16 -- Read 128 bits from the random source+    let ws = hmacDRBGNew seed nonce haskoinUserAgent+    S.evalStateT m (ws,f)++-- | Generate a new random 'EC.SecKey' value from the 'SecretT' monad. This+-- will invoke the HMAC DRBG routine. Of the internal entropy pool of the HMAC+-- DRBG was stretched too much, this function will reseed it.+nextSecret :: Monad m => SecretT m EC.SecKey+nextSecret = do+    (ws, f) <- S.get+    let (ws', randM) = hmacDRBGGen ws 32 haskoinUserAgent+    case randM of+        (Just rand) -> do+            S.put (ws', f)+            case EC.secKey rand of+                Just key -> return key+                Nothing  -> nextSecret+        Nothing -> do+            seed <- lift $ f 32 -- Read 256 bits to re-seed the PRNG+            let ws0 = hmacDRBGRsd ws' seed haskoinUserAgent+            S.put (ws0, f)+            nextSecret++-- | Produce a new 'PrvKey' randomly from the 'SecretT' monad.+genPrvKey :: Monad m => SecretT m PrvKey+genPrvKey = makePrvKey <$> nextSecret++-- | Data type representing an ECDSA signature.+newtype Signature = Signature { getSignature :: EC.Sig }+    deriving (Read, Show, Eq)++instance NFData Signature where+    rnf (Signature s) = s `seq` ()++hashToMsg :: Hash256 -> EC.Msg+hashToMsg =+    fromMaybe e . EC.msg . getHash256+  where+    e = error "Could not convert 32-byte hash to secp256k1 message"++-- <http://www.secg.org/sec1-v2.pdf Section 4.1.3>+-- | Sign a message+signMsg :: Hash256 -> PrvKey -> Signature+signMsg h d = Signature $ EC.signMsg (prvKeySecKey d) (hashToMsg h)++-- | Verify an ECDSA signature+verifySig :: Hash256 -> Signature -> PubKey -> Bool+verifySig h s q =+    EC.verifySig p g m+  where+    (g, _) = EC.normalizeSig $ getSignature s+    m = hashToMsg h+    p = pubKeyPoint q++instance Binary Signature where+    get = do+        l <- lookAhead $ do+            t <- getWord8+            -- 0x30 is DER sequence type+            unless (t == 0x30) $ fail $+                "Bad DER identifier byte 0x" ++ showHex t ". Expecting 0x30"+            l <- getWord8+            when (l == 0x00) $ fail "Indeterminate form unsupported"+            when (l >= 0x80) $ fail "Multi-octect length not supported"+            return $ fromIntegral l+        bs <- getByteString $ l + 2+        case decodeDerSig bs of+            Just s  -> return s+            Nothing -> fail "Invalid signature"++    put (Signature s) = putByteString $ EC.exportSig s++isCanonicalHalfOrder :: Signature -> Bool+isCanonicalHalfOrder = not . snd . EC.normalizeSig . getSignature++decodeDerSig :: ByteString -> Maybe Signature+decodeDerSig bs = Signature <$> EC.laxImportSig bs++decodeStrictSig :: ByteString -> Maybe Signature+decodeStrictSig bs = do+    g <- EC.importSig bs+    let compact = EC.exportCompactSig g+    -- <http://www.secg.org/sec1-v2.pdf Section 4.1.4>+    -- 4.1.4.1 (r and s can not be zero)+    guard $ EC.getCompactSigR compact /= 0+    guard $ EC.getCompactSigS compact /= 0+    return $ Signature g+
+ Network/Haskoin/Crypto/ExtendedKeys.hs view
@@ -0,0 +1,710 @@+{-# LANGUAGE GADTs #-}+module Network.Haskoin.Crypto.ExtendedKeys+( XPubKey(..)+, XPrvKey(..)+, ChainCode+, KeyIndex+, DerivationException(..)+, makeXPrvKey+, deriveXPubKey+, prvSubKey+, pubSubKey+, hardSubKey+, xPrvIsHard+, xPubIsHard+, xPrvChild+, xPubChild+, xPubID+, xPrvID+, xPubFP+, xPrvFP+, xPubAddr+, xPubExport+, xPrvExport+, xPubImport+, xPrvImport+, xPrvWif+  -- Helpers+, prvSubKeys+, pubSubKeys+, hardSubKeys+, deriveAddr+, deriveAddrs+, deriveMSAddr+, deriveMSAddrs+, cycleIndex+  -- Custom derivations+, DerivPathI(..)+, HardOrMixed+, MixedOrSoft+, DerivPath+, HardPath+, SoftPath+, pathToStr+, parsePath+, parseHard+, parseSoft+, toHard+, toSoft+, toMixed+, (++/), (++|)+, derivePath+, derivePubPath+, derivePathE+, derivePathAddr+, derivePathAddrs+, derivePathMSAddr+, derivePathMSAddrs+) where++import Control.DeepSeq (NFData, rnf)+import Control.Monad (mzero, guard, unless, (<=<))+import Control.Exception (Exception, throw)++import qualified Crypto.Secp256k1 as EC++import Data.Aeson (Value(String), FromJSON, ToJSON, parseJSON, toJSON, withText)+import Data.Binary (Binary, get, put)+import Data.Binary.Get (Get, getWord8, getWord32be)+import Data.Binary.Put (Put, putWord8, putWord32be)+import Data.Word (Word8, Word32)+import Data.Bits (setBit, testBit, clearBit)+import Data.List.Split (splitOn)+import Data.Maybe (fromMaybe)+import Data.String (IsString, fromString)+import Data.String.Conversions (cs)+import Data.Typeable (Typeable)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS (append, take)++import Text.Read (readPrec, parens, lexP, pfail)+import qualified Text.Read as Read (Lexeme(Ident, String))++import Network.Haskoin.Util+import Network.Haskoin.Constants+import Network.Haskoin.Script.Parser+import Network.Haskoin.Crypto.Keys+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Crypto.Base58++{- See BIP32 for details: https://en.bitcoin.it/wiki/BIP_0032 -}++-- | A derivation exception is thrown in the very unlikely event that a+-- derivation is invalid.+data DerivationException = DerivationException String+    deriving (Eq, Read, Show, Typeable)++instance Exception DerivationException++type ChainCode = Hash256+type KeyIndex = Word32++-- | Data type representing an extended BIP32 private key. An extended key+-- is a node in a tree of key derivations. It has a depth in the tree, a+-- parent node and an index to differentiate it from other siblings.+data XPrvKey = XPrvKey+    { xPrvDepth  :: !Word8     -- ^ Depth in the tree of key derivations.+    , xPrvParent :: !Word32    -- ^ Fingerprint of the parent key.+    , xPrvIndex  :: !KeyIndex  -- ^ Key derivation index.+    , xPrvChain  :: !ChainCode -- ^ Chain code.+    , xPrvKey    :: !PrvKeyC   -- ^ The private key of this extended key node.+    } deriving (Eq)++-- TODO: Test+instance Show XPrvKey where+    showsPrec d k = showParen (d > 10) $+        showString "XPrvKey " . shows (xPrvExport k)++-- TODO: Test+instance Read XPrvKey where+    readPrec = parens $ do+        Read.Ident "XPrvKey" <- lexP+        Read.String str <- lexP+        maybe pfail return $ xPrvImport $ cs str++-- TODO: Test+instance IsString XPrvKey where+    fromString =+        fromMaybe e . xPrvImport . cs+      where+        e = error "Could not decode extended private key"++instance NFData XPrvKey where+    rnf (XPrvKey d p i c k) =+        rnf d `seq` rnf p `seq` rnf i `seq` rnf c `seq` rnf k++instance ToJSON XPrvKey where+    toJSON = String . cs . xPrvExport++instance FromJSON XPrvKey where+    parseJSON = withText "xprvkey" $ maybe mzero return . xPrvImport . cs++-- | Data type representing an extended BIP32 public key.+data XPubKey = XPubKey+    { xPubDepth  :: !Word8     -- ^ Depth in the tree of key derivations.+    , xPubParent :: !Word32    -- ^ Fingerprint of the parent key.+    , xPubIndex  :: !KeyIndex  -- ^ Key derivation index.+    , xPubChain  :: !ChainCode -- ^ Chain code.+    , xPubKey    :: !PubKeyC   -- ^ The public key of this extended key node.+    } deriving (Eq)++-- TODO: Test+instance Show XPubKey where+    showsPrec d k = showParen (d > 10) $+        showString "XPubKey " . shows (xPubExport k)++-- TODO: Test+instance Read XPubKey where+    readPrec = parens $ do+        Read.Ident "XPubKey" <- lexP+        Read.String str <- lexP+        maybe pfail return $ xPubImport $ cs str++-- TODO: Test+instance IsString XPubKey where+    fromString =+        fromMaybe e . xPubImport . cs+      where+        e = error "Could not import extended public key"++instance NFData XPubKey where+    rnf (XPubKey d p i c k) =+        rnf d `seq` rnf p `seq` rnf i `seq` rnf c `seq` rnf k++instance ToJSON XPubKey where+    toJSON = String . cs . xPubExport++instance FromJSON XPubKey where+    parseJSON = withText "xpubkey" $ maybe mzero return . xPubImport . cs++-- | Build a BIP32 compatible extended private key from a bytestring. This will+-- produce a root node (depth=0 and parent=0).+makeXPrvKey :: ByteString -> XPrvKey+makeXPrvKey bs =+    XPrvKey 0 0 0 c k+  where+    (p, c) = split512 $ hmac512 "Bitcoin seed" bs+    k     = fromMaybe err $ makePrvKeyC <$> EC.secKey (getHash256 p)+    err   = throw $ DerivationException "Invalid seed"++-- | Derive an extended public key from an extended private key. This function+-- will preserve the depth, parent, index and chaincode fields of the extended+-- private keys.+deriveXPubKey :: XPrvKey -> XPubKey+deriveXPubKey (XPrvKey d p i c k) = XPubKey d p i c (derivePubKey k)++-- | Compute a private, soft child key derivation. A private soft derivation+-- will allow the equivalent extended public key to derive the public key for+-- this child. Given a parent key /m/ and a derivation index /i/, this function+-- will compute m\/i\/.+--+-- Soft derivations allow for more flexibility such as read-only wallets.+-- However, care must be taken not the leak both the parent extended public key+-- and one of the extended child private keys as this would compromise the+-- extended parent private key.+prvSubKey :: XPrvKey  -- ^ Extended parent private key+          -> KeyIndex -- ^ Child derivation index+          -> XPrvKey  -- ^ Extended child private key+prvSubKey xkey child+    | child >= 0 && child < 0x80000000 =+        XPrvKey (xPrvDepth xkey + 1) (xPrvFP xkey) child c k+    | otherwise = error "Invalid child derivation index"+  where+    pK     = xPubKey $ deriveXPubKey xkey+    msg    = BS.append (encode' pK) (encode' child)+    (a, c) = split512 $ hmac512 (encode' $ xPrvChain xkey) msg+    k      = fromMaybe err $ tweakPrvKeyC (xPrvKey xkey) a+    err    = throw $ DerivationException "Invalid prvSubKey derivation"++-- | Compute a public, soft child key derivation. Given a parent key /M/+-- and a derivation index /i/, this function will compute M\/i\/.+pubSubKey :: XPubKey  -- ^ Extended Parent public key+          -> KeyIndex -- ^ Child derivation index+          -> XPubKey  -- ^ Extended child public key+pubSubKey xKey child+    | child >= 0 && child < 0x80000000 =+        XPubKey (xPubDepth xKey + 1) (xPubFP xKey) child c pK+    | otherwise = error "Invalid child derivation index"+  where+    msg    = BS.append (encode' $ xPubKey xKey) (encode' child)+    (a, c) = split512 $ hmac512 (encode' $ xPubChain xKey) msg+    pK     = fromMaybe err $ tweakPubKeyC (xPubKey xKey) a+    err    = throw $ DerivationException "Invalid pubSubKey derivation"++-- | Compute a hard child key derivation. Hard derivations can only be computed+-- for private keys. Hard derivations do not allow the parent public key to+-- derive the child public keys. However, they are safer as a breach of the+-- parent public key and child private keys does not lead to a breach of the+-- parent private key. Given a parent key /m/ and a derivation index /i/, this+-- function will compute m\/i'\/.+hardSubKey :: XPrvKey  -- ^ Extended Parent private key+            -> KeyIndex -- ^ Child derivation index+            -> XPrvKey  -- ^ Extended child private key+hardSubKey xkey child+    | child >= 0 && child < 0x80000000 =+        XPrvKey (xPrvDepth xkey + 1) (xPrvFP xkey) i c k+    | otherwise = error "Invalid child derivation index"+  where+    i      = setBit child 31+    msg    = BS.append (bsPadPrvKey $ xPrvKey xkey) (encode' i)+    (a, c) = split512 $ hmac512 (encode' $ xPrvChain xkey) msg+    k      = fromMaybe err $ tweakPrvKeyC (xPrvKey xkey) a+    err    = throw $ DerivationException "Invalid hardSubKey derivation"++-- | Returns True if the extended private key was derived through a hard+-- derivation.+xPrvIsHard :: XPrvKey -> Bool+xPrvIsHard k = testBit (xPrvIndex k) 31++-- | Returns True if the extended public key was derived through a hard+-- derivation.+xPubIsHard :: XPubKey -> Bool+xPubIsHard k = testBit (xPubIndex k) 31++-- | Returns the derivation index of this extended private key without the hard+-- bit set.+xPrvChild :: XPrvKey -> KeyIndex+xPrvChild k = clearBit (xPrvIndex k) 31++-- | Returns the derivation index of this extended public key without the hard+-- bit set.+xPubChild :: XPubKey -> KeyIndex+xPubChild k = clearBit (xPubIndex k) 31++-- | Computes the key identifier of an extended private key.+xPrvID :: XPrvKey -> Hash160+xPrvID = xPubID . deriveXPubKey++-- | Computes the key identifier of an extended public key.+xPubID :: XPubKey -> Hash160+xPubID = hash160 . getHash256 . hash256 . encode' . xPubKey++-- | Computes the key fingerprint of an extended private key.+xPrvFP :: XPrvKey -> Word32+xPrvFP = decode' . BS.take 4 . getHash160 . xPrvID++-- | Computes the key fingerprint of an extended public key.+xPubFP :: XPubKey -> Word32+xPubFP = decode' . BS.take 4 . getHash160 . xPubID++-- | Computer the 'Address' of an extended public key.+xPubAddr :: XPubKey -> Address+xPubAddr = pubKeyAddr . xPubKey++-- | Exports an extended private key to the BIP32 key export format (base 58).+xPrvExport :: XPrvKey -> ByteString+xPrvExport = encodeBase58Check . encode'++-- | Exports an extended public key to the BIP32 key export format (base 58).+xPubExport :: XPubKey -> ByteString+xPubExport = encodeBase58Check . encode'++-- | Decodes a BIP32 encoded extended private key. This function will fail if+-- invalid base 58 characters are detected or if the checksum fails.+xPrvImport :: ByteString -> Maybe XPrvKey+xPrvImport = decodeToMaybe <=< decodeBase58Check++-- | Decodes a BIP32 encoded extended public key. This function will fail if+-- invalid base 58 characters are detected or if the checksum fails.+xPubImport :: ByteString -> Maybe XPubKey+xPubImport = decodeToMaybe <=< decodeBase58Check++-- | Export an extended private key to WIF (Wallet Import Format).+xPrvWif :: XPrvKey -> ByteString+xPrvWif = toWif . xPrvKey++instance Binary XPrvKey where++    get = do+        ver <- getWord32be+        unless (ver == extSecretPrefix) $ fail $+            "Get: Invalid version for extended private key"+        dep <- getWord8+        par <- getWord32be+        idx <- getWord32be+        chn <- get+        prv <- getPadPrvKey+        return $ XPrvKey dep par idx chn prv++    put k = do+        putWord32be  extSecretPrefix+        putWord8     $ xPrvDepth k+        putWord32be  $ xPrvParent k+        putWord32be  $ xPrvIndex k+        put          $ xPrvChain k+        putPadPrvKey $ xPrvKey k++instance Binary XPubKey where++    get = do+        ver <- getWord32be+        unless (ver == extPubKeyPrefix) $ fail $+            "Get: Invalid version for extended public key"+        dep <- getWord8+        par <- getWord32be+        idx <- getWord32be+        chn <- get+        pub <- get+        return $ XPubKey dep par idx chn pub++    put k = do+        putWord32be extPubKeyPrefix+        putWord8    $ xPubDepth k+        putWord32be $ xPubParent k+        putWord32be $ xPubIndex k+        put         $ xPubChain k+        put $ xPubKey k++{- Derivation helpers -}++-- | Cyclic list of all private soft child key derivations of a parent key+-- starting from an offset index.+prvSubKeys :: XPrvKey -> KeyIndex -> [(XPrvKey, KeyIndex)]+prvSubKeys k = map (\i -> (prvSubKey k i, i)) . cycleIndex++-- | Cyclic list of all public soft child key derivations of a parent key+-- starting from an offset index.+pubSubKeys :: XPubKey -> KeyIndex -> [(XPubKey, KeyIndex)]+pubSubKeys k = map (\i -> (pubSubKey k i, i)) . cycleIndex++-- | Cyclic list of all hard child key derivations of a parent key starting+-- from an offset index.+hardSubKeys :: XPrvKey -> KeyIndex -> [(XPrvKey, KeyIndex)]+hardSubKeys k = map (\i -> (hardSubKey k i, i)) . cycleIndex++-- | Derive an address from a public key and an index. The derivation type+-- is a public, soft derivation.+deriveAddr :: XPubKey -> KeyIndex -> (Address, PubKeyC)+deriveAddr k i =+    (xPubAddr key, xPubKey key)+  where+    key = pubSubKey k i++-- | Cyclic list of all addresses derived from a public key starting from an+-- offset index. The derivation types are public, soft derivations.+deriveAddrs :: XPubKey -> KeyIndex -> [(Address, PubKeyC, KeyIndex)]+deriveAddrs k =+    map f . cycleIndex+  where+    f i = let (a, key) = deriveAddr k i in (a, key, i)++-- | Derive a multisig address from a list of public keys, the number of+-- required signatures (m) and a derivation index. The derivation type is a+-- public, soft derivation.+deriveMSAddr :: [XPubKey] -> Int -> KeyIndex -> (Address, RedeemScript)+deriveMSAddr keys m i =+    (scriptAddr rdm, rdm)+  where+    rdm = sortMulSig $ PayMulSig k m+    k   = map (toPubKeyG . xPubKey . flip pubSubKey i) keys++-- | Cyclic list of all multisig addresses derived from a list of public keys,+-- a number of required signatures (m) and starting from an offset index. The+-- derivation type is a public, soft derivation.+deriveMSAddrs :: [XPubKey] -> Int -> KeyIndex+              -> [(Address, RedeemScript, KeyIndex)]+deriveMSAddrs keys m =+    map f . cycleIndex+  where+    f i = let (a, rdm) = deriveMSAddr keys m i in (a, rdm, i)++cycleIndex :: KeyIndex -> [KeyIndex]+cycleIndex i+    | i == 0         = cycle [0..0x7fffffff]+    | i < 0x80000000 = cycle $ [i..0x7fffffff] ++ [0..(i-1)]+    | otherwise      = error $ "cycleIndex: invalid index " ++ (show i)++{- Custom derivations -}++data Hard+data Mixed+data Soft++type HardPath = DerivPathI Hard+type DerivPath = DerivPathI Mixed+type SoftPath = DerivPathI Soft++class HardOrMixed a+instance HardOrMixed Hard+instance HardOrMixed Mixed++class MixedOrSoft a+instance MixedOrSoft Mixed+instance MixedOrSoft Soft++data DerivPathI t where+    (:|) :: HardOrMixed t => !HardPath -> !KeyIndex -> DerivPathI t+    (:/) :: MixedOrSoft t => !(DerivPathI t) -> !KeyIndex -> DerivPathI t+    Deriv :: DerivPathI t+    DerivPrv :: DerivPathI t+    DerivPub :: DerivPathI t++instance NFData (DerivPathI t) where+    rnf p = case p of+        next :| i -> rnf i `seq` rnf next+        next :/ i -> rnf i `seq` rnf next+        Deriv     -> ()+        DerivPrv  -> ()+        DerivPub  -> ()++instance Eq (DerivPathI t) where+    (nextA :| iA) == (nextB :| iB) = iA == iB && nextA == nextB+    (nextA :/ iA) == (nextB :/ iB) = iA == iB && nextA == nextB+    Deriv         == Deriv         = True+    DerivPrv      == DerivPrv      = True+    DerivPub      == DerivPub      = True+    _             == _             = False++-- TODO: Test+pathToStr :: DerivPathI t -> String+pathToStr p =+    case p of+        next :| i -> concat [ pathToStr next, "/", show i, "'" ]+        next :/ i -> concat [ pathToStr next, "/", show i ]+        Deriv     -> ""+        DerivPrv  -> "m"+        DerivPub  -> "M"++-- TODO: Test+instance Show DerivPath where+    showsPrec d p = showParen (d > 10) $+        showString "DerivPath " . shows (pathToStr p)++-- TODO: Test+instance Show HardPath where+    showsPrec d p = showParen (d > 10) $+        showString "HardPath " . shows (pathToStr p)++-- TODO: Test+instance Show SoftPath where+    showsPrec d p = showParen (d > 10) $+        showString "SoftPath " . shows (pathToStr p)++-- TODO: Test+instance Read DerivPath where+    readPrec = parens $ do+        Read.Ident "DerivPath" <- lexP+        Read.String str <- lexP+        maybe pfail return $ parsePath str++-- TODO: Test+instance Read HardPath where+    readPrec = parens $ do+        Read.Ident "HardPath" <- lexP+        Read.String str <- lexP+        maybe pfail return $ parseHard str++-- TODO: Test+instance Read SoftPath where+    readPrec = parens $ do+        Read.Ident "SoftPath" <- lexP+        Read.String str <- lexP+        maybe pfail return $ parseSoft str++-- TODO: Test+instance IsString DerivPath where+    fromString =+        fromMaybe e . parsePath+      where+        e = error "Could not parse derivation path"++-- TODO: Test+instance IsString HardPath where+    fromString =+        fromMaybe e . parseHard+      where+        e = error "Could not parse hard derivation path"++-- TODO: Test+instance IsString SoftPath where+    fromString =+        fromMaybe e . parseSoft+      where+        e = error "Could not parse soft derivation path"++instance FromJSON DerivPath where+    parseJSON = withText "DerivPath" $ \str -> case parsePath $ cs str of+        Just p -> return p+        _      -> mzero++instance FromJSON HardPath where+    parseJSON = withText "HardPath" $ \str -> case parseHard $ cs str of+        Just p -> return p+        _      -> mzero++instance FromJSON SoftPath where+    parseJSON = withText "SoftPath" $ \str -> case parseSoft $ cs str of+        Just p -> return p+        _      -> mzero++instance ToJSON (DerivPathI t) where+    toJSON = String . cs . pathToStr++-- | Parse derivation path string for extended key.+-- Forms: “m/0'/2”, “M/2/3/4”.+parsePath :: String -> Maybe DerivPath+parsePath str = do+    ds <- reverse <$> mapM f xs+    let (s,h) = break fst ds+    -- No soft derivations in the hard branch+    guard $ null $ filter (not . fst) h+    hPath <- pHard $ map snd h+    pSoft hPath $ map snd s+  where+    (x:xs) = splitOn "/" str+    f deriv = case reads deriv of+        [(i, "" )] -> (,) False <$> g i+        [(i, "'")] -> (,) True <$> g i+        _ -> Nothing+    g i = guard (i >=0 && i < 0x80000000) >> return i+    pSoft h (i:is) = (:/ i) <$> pSoft h is+    pSoft h [] = return h+    pHard :: HardOrMixed t => [KeyIndex] -> Maybe (DerivPathI t)+    pHard (i:is) = (:| i) <$> pHard is+    pHard [] = pEnd+    pEnd :: Maybe (DerivPathI t)+    pEnd = case x of+        ""  -> Just Deriv+        "m" -> Just DerivPrv+        "M" -> Just DerivPub+        _   -> Nothing++parseHard :: String -> Maybe HardPath+parseHard = toHard <=< parsePath++parseSoft :: String -> Maybe SoftPath+parseSoft = toSoft <=< parsePath++toHard :: DerivPathI t -> Maybe HardPath+toHard p = case p of+    _ :/ _    -> Nothing+    next :| i -> Just $ next :| i+    Deriv     -> Just Deriv+    DerivPrv  -> Just DerivPrv+    DerivPub  -> Just DerivPub++toSoft :: DerivPathI t -> Maybe SoftPath+toSoft p = case p of+    _ :| _    -> Nothing+    next :/ i -> (:/ i) <$> toSoft next+    Deriv     -> Just Deriv+    DerivPrv  -> Just DerivPrv+    DerivPub  -> Just DerivPub++toMixed :: DerivPathI t -> DerivPath+toMixed p = case p of+    next :/ i -> (toMixed next) :/ i+    next :| i -> next :| i+    Deriv     -> Deriv+    DerivPrv  -> DerivPrv+    DerivPub  -> DerivPub++-- | Append a SoftPath to any derivation path. It is always type-safe to+-- append a SoftPath to any derivation path. The result will be a mixed+-- derivation path.+(++/) :: DerivPathI t -> SoftPath -> DerivPath+(++/) p1 p2 =+    go id p2 $ toMixed p1+  where+    go f p = case p of+        next :/ i -> go (f . (:/ i)) next+        _ -> f++-- | Append any type of derivation to a HardPath. It is always type-safe to+-- append any type of path to a HardPath. The result will be a mixed derivation+-- path.+(++|) :: HardPath -> DerivPathI t -> DerivPath+(++|) p1 p2 =+    go id (toMixed p2) $ toMixed p1+  where+    go :: (DerivPath -> DerivPath) -> DerivPath -> (DerivPath -> DerivPath)+    go f p = case p of+        next :/ i -> go (f . (:/ i)) next+        next :| i -> go (f . (:| i) . fromMaybe err . toHard) $ toMixed next+        _ -> f+    err = error "Error while appending paths"++-- | Derive a private key from a derivation path+derivePath :: DerivPathI t -> XPrvKey -> XPrvKey+derivePath path key =+    go id path $ key+  where+    -- Build the full derivation function starting from the end+    go :: (XPrvKey -> XPrvKey) -> DerivPathI t -> (XPrvKey -> XPrvKey)+    go f p = case p of+        next :| i -> go (f . flip hardSubKey i) next+        next :/ i -> go (f . flip prvSubKey i) next+        _         -> f++-- | Derive a public key from a soft derivation path+derivePubPath :: SoftPath -> XPubKey -> XPubKey+derivePubPath path key =+    go id path $ key+  where+    -- Build the full derivation function starting from the end+    go f p = case p of+        next :/ i -> go (f . flip pubSubKey i) next+        _         -> f++-- | Derive a key from a derivation path and return either a private or public+-- key depending on the initial derivation constructor. If you parsed a string+-- as m/ you will get a private key and if you parsed a string as M/ you will+-- get a public key. If you used the neutral derivation constructor `Deriv`, a+-- private key will be returned.+derivePathE :: DerivPathI t -> XPrvKey -> Either XPubKey XPrvKey+derivePathE path key =+    go id path $ key+  where+    -- Build the full derivation function starting from the end+    go :: (XPrvKey -> XPrvKey)+       -> DerivPathI t+       -> (XPrvKey -> Either XPubKey XPrvKey)+    go f p = case p of+        next :| i -> go (f . flip hardSubKey i) next+        next :/ i -> go (f . flip prvSubKey i) next+        -- Derive a public key as the last function+        DerivPub  -> Left . deriveXPubKey . f+        _         -> Right . f++-- | Derive an address from a given parent path.+derivePathAddr :: XPubKey -> SoftPath -> KeyIndex -> (Address, PubKeyC)+derivePathAddr key path i = deriveAddr (derivePubPath path key) i++-- | Cyclic list of all addresses derived from a given parent path and starting+-- from the given offset index.+derivePathAddrs :: XPubKey -> SoftPath -> KeyIndex+                -> [(Address, PubKeyC, KeyIndex)]+derivePathAddrs key path i = deriveAddrs (derivePubPath path key) i++-- | Derive a multisig address from a given parent path. The number of required+-- signatures (m in m of n) is also needed.+derivePathMSAddr :: [XPubKey] -> SoftPath -> Int -> KeyIndex+                 -> (Address, RedeemScript)+derivePathMSAddr keys path m i =+    deriveMSAddr (map (derivePubPath path) keys) m i++-- | Cyclic list of all multisig addresses derived from a given parent path and+-- starting from the given offset index. The number of required signatures+-- (m in m of n) is also needed.+derivePathMSAddrs :: [XPubKey] -> SoftPath -> Int -> KeyIndex+                  -> [(Address, RedeemScript, KeyIndex)]+derivePathMSAddrs keys path m i =+    deriveMSAddrs (map (derivePubPath path) keys) m i++{- Utilities for extended keys -}++-- De-serialize HDW-specific private key+getPadPrvKey :: Get PrvKeyC+getPadPrvKey = do+    pad <- getWord8+    unless (pad == 0x00) $ fail $+        "Private key must be padded with 0x00"+    prvKeyGetMonad makePrvKeyC -- Compressed version++-- Serialize HDW-specific private key+putPadPrvKey :: PrvKeyC -> Put+putPadPrvKey p = putWord8 0x00 >> prvKeyPutMonad p++bsPadPrvKey :: PrvKeyC -> ByteString+bsPadPrvKey = runPut' . putPadPrvKey+
+ Network/Haskoin/Crypto/Hash.hs view
@@ -0,0 +1,316 @@+-- | Hashing functions and HMAC DRBG definition+module Network.Haskoin.Crypto.Hash+( Hash512(getHash512)+, Hash256(getHash256)+, Hash160(getHash160)+, CheckSum32(getCheckSum32)+, bsToHash512+, bsToHash256+, bsToHash160+, hash512+, hash256+, hash160+, sha1+, doubleHash256+, bsToCheckSum32+, checkSum32+, hmac512+, hmac256+, split512+, join512+, hmacDRBGNew+, hmacDRBGUpd+, hmacDRBGRsd+, hmacDRBGGen+, WorkingState+) where++import Crypto.Hash+    ( Digest+    , SHA512+    , SHA256+    , SHA1+    , RIPEMD160+    , hash+    )+import Crypto.MAC.HMAC (hmac)++import Control.DeepSeq (NFData, rnf)+import Control.Monad ((<=<), guard)+import Data.Byteable (toBytes)+import Data.Maybe (fromMaybe)+import Data.Word (Word16)+import Data.String (IsString, fromString)+import Data.String.Conversions (cs)+import Text.Read (Lexeme(String, Ident), readPrec, lexP, parens, pfail)+import Data.Binary (Binary, get, put)+import Data.Binary.Get (getByteString)+import Data.Binary.Put (putByteString)++import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+    ( null+    , append+    , cons+    , concat+    , take+    , empty+    , length+    , replicate+    , splitAt+    )++import Network.Haskoin.Util++newtype CheckSum32 = CheckSum32 { getCheckSum32 :: ByteString }+    deriving (Eq, Ord)++newtype Hash512 = Hash512 { getHash512 :: ByteString }+    deriving (Eq, Ord)++newtype Hash256 = Hash256 { getHash256 :: ByteString }+    deriving (Eq, Ord)++newtype Hash160 = Hash160 { getHash160 :: ByteString }+    deriving (Eq, Ord)+++instance NFData CheckSum32 where+    rnf (CheckSum32 bs) = rnf bs++instance Show CheckSum32 where+    showsPrec d (CheckSum32 bs) = showParen (d > 10) $+        showString "CheckSum32 " . shows (encodeHex bs)++instance Read CheckSum32 where+    readPrec = parens $ do+        Ident "CheckSum32" <- lexP+        String str <- lexP+        maybe pfail return $ bsToCheckSum32 =<< decodeHex (cs str)++instance IsString CheckSum32 where+    fromString =+        fromMaybe e . (bsToCheckSum32 <=< decodeHex) . cs+      where+        e = error "Could not decode checksum"++instance Binary CheckSum32 where+    get = CheckSum32 <$> getByteString 4+    put (CheckSum32 bs) = putByteString bs+++instance NFData Hash512 where+    rnf (Hash512 bs) = rnf bs++instance Show Hash512 where+    showsPrec d (Hash512 bs) = showParen (d > 10) $+        showString "Hash512 " . shows (encodeHex bs)++instance Read Hash512 where+    readPrec = parens $ do+        Ident "Hash512" <- lexP+        String str <- lexP+        maybe pfail return $ bsToHash512 =<< decodeHex (cs str)++instance IsString Hash512 where+    fromString =+        fromMaybe e . (bsToHash512 <=< decodeHex) . cs+      where+        e = error "Could not decode 64-byte hash"++instance Binary Hash512 where+    get = Hash512 <$> getByteString 64+    put (Hash512 bs) = putByteString bs+++instance NFData Hash256 where+    rnf (Hash256 bs) = rnf bs++instance Show Hash256 where+    showsPrec d (Hash256 bs) = showParen (d > 10) $+        showString "Hash256 " . shows (encodeHex bs)++instance Read Hash256 where+    readPrec = parens $ do+        Ident "Hash256" <- lexP+        String str <- lexP+        maybe pfail return $ bsToHash256 =<< decodeHex (cs str)++instance IsString Hash256 where+    fromString =+        fromMaybe e . (bsToHash256 <=< decodeHex) . cs+      where+        e = error "Could not decode 32-byte hash"++instance Binary Hash256 where+    get = Hash256 <$> getByteString 32+    put (Hash256 bs) = putByteString bs+++instance NFData Hash160 where+    rnf (Hash160 bs) = rnf bs++instance Show Hash160 where+    showsPrec d (Hash160 bs) = showParen (d > 10) $+        showString "Hash160 " . shows (encodeHex bs)++instance Read Hash160 where+    readPrec = parens $ do+        Ident "Hash160" <- lexP+        String str <- lexP+        maybe pfail return $ bsToHash160 =<< decodeHex (cs str)++instance IsString Hash160 where+    fromString =+        fromMaybe e . (bsToHash160 <=< decodeHex) . cs+      where+        e = error "Could not decode 20-byte hash"++instance Binary Hash160 where+    get = Hash160 <$> getByteString 20+    put (Hash160 bs) = putByteString bs+++bsToHash512 :: ByteString -> Maybe Hash512+bsToHash512 bs = guard (BS.length bs == 64) >> return (Hash512 bs)++bsToHash256 :: ByteString -> Maybe Hash256+bsToHash256 bs = guard (BS.length bs == 32) >> return (Hash256 bs)++bsToHash160 :: ByteString -> Maybe Hash160+bsToHash160 bs = guard (BS.length bs == 20) >> return (Hash160 bs)++-- | Compute SHA-512.+hash512 :: ByteString -> Hash512+hash512 = Hash512 . (toBytes :: Digest SHA512 -> ByteString) . hash++-- | Compute SHA-256.+hash256 :: ByteString -> Hash256+hash256 = Hash256 . (toBytes :: Digest SHA256 -> ByteString) . hash++-- | Compute RIPEMD-160.+hash160 :: ByteString -> Hash160+hash160 = Hash160 . (toBytes :: Digest RIPEMD160 -> ByteString) . hash++-- | Compute SHA1+sha1 :: ByteString -> Hash160+sha1 = Hash160 . (toBytes :: Digest SHA1 -> ByteString) . hash++-- | Compute two rounds of SHA-256.+doubleHash256 :: ByteString -> Hash256+doubleHash256 = hash256 . getHash256 . hash256++{- CheckSum -}++bsToCheckSum32 :: ByteString -> Maybe CheckSum32+bsToCheckSum32 bs = guard (BS.length bs == 4) >> return (CheckSum32 bs)++-- | Computes a 32 bit checksum.+checkSum32 :: ByteString -> CheckSum32+checkSum32 bs =+    CheckSum32 $ BS.take 4 bs'+  where+    Hash256 bs' = doubleHash256 bs++{- HMAC -}++-- | Computes HMAC over SHA-512.+hmac512 :: ByteString -> ByteString -> Hash512+hmac512 key msg =+    Hash512 $ hmac f 128 key msg+  where+    f bs = let Hash512 bs' = hash512 bs in bs'++-- | Computes HMAC over SHA-256.+hmac256 :: ByteString -> ByteString -> Hash256+hmac256 key msg =+    Hash256 $ hmac f 64 key msg+  where+    f bs = let Hash256 bs' = hash256 bs in bs'++-- | Split a 'Hash512' into a pair of 'Hash256'.+split512 :: Hash512 -> (Hash256, Hash256)+split512 (Hash512 bs) =+    (Hash256 a, Hash256 b)+  where+    (a, b) = BS.splitAt 32 bs++-- | Join a pair of 'Hash256' into a 'Hash512'.+join512 :: (Hash256, Hash256) -> Hash512+join512 (Hash256 a, Hash256 b) = Hash512 $ a `BS.append` b+++{- 10.1.2 HMAC_DRBG with HMAC-SHA256+   http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf+   Constants are based on recommentations in Appendix D section 2 (D.2)+-}++type WorkingState    = (ByteString, ByteString, Word16)+type AdditionalInput = ByteString+type ProvidedData    = ByteString+type EntropyInput    = ByteString+type Nonce           = ByteString+type PersString      = ByteString++-- 10.1.2.2 HMAC DRBG Update FUnction+hmacDRBGUpd :: ProvidedData -> ByteString -> ByteString+            -> (ByteString, ByteString)+hmacDRBGUpd info k0 v0+    | BS.null info = (k1, v1)        -- 10.1.2.2.3+    | otherwise    = (k2, v2)        -- 10.1.2.2.6+  where+    -- 10.1.2.2.1+    Hash256 k1 = hmac256 k0 $ v0 `BS.append` (0 `BS.cons` info)+    -- 10.1.2.2.2+    Hash256 v1 = hmac256 k1 v0+    -- 10.1.2.2.4+    Hash256 k2 = hmac256 k1 $ v1 `BS.append` (1 `BS.cons` info)+    -- 10.1.2.2.5+    Hash256 v2 = hmac256 k2 v1++-- 10.1.2.3 HMAC DRBG Instantiation+hmacDRBGNew :: EntropyInput -> Nonce -> PersString -> WorkingState+hmacDRBGNew seed nonce info+    | (BS.length seed + BS.length nonce) * 8 < 384  = error $+        "Entropy + nonce input length must be at least 384 bit"+    | (BS.length seed + BS.length nonce) * 8 > 1000 = error $+        "Entropy + nonce input length can not be greater than 1000 bit"+    | BS.length info * 8 > 256  = error $+        "Maximum personalization string length is 256 bit"+    | otherwise                = (k1, v1, 1)         -- 10.1.2.3.6+  where+    s        = BS.concat [seed, nonce, info] -- 10.1.2.3.1+    k0       = BS.replicate 32 0             -- 10.1.2.3.2+    v0       = BS.replicate 32 1             -- 10.1.2.3.3+    (k1,v1)  = hmacDRBGUpd s k0 v0           -- 10.1.2.3.4++-- 10.1.2.4 HMAC DRBG Reseeding+hmacDRBGRsd :: WorkingState -> EntropyInput -> AdditionalInput -> WorkingState+hmacDRBGRsd (k, v, _) seed info+    | BS.length seed * 8 < 256 = error $+        "Entropy input length must be at least 256 bit"+    | BS.length seed * 8 > 1000 = error $+        "Entropy input length can not be greater than 1000 bit"+    | otherwise   = (k0, v0, 1)             -- 10.1.2.4.4+  where+    s        = seed `BS.append` info -- 10.1.2.4.1+    (k0, v0) = hmacDRBGUpd s k v     -- 10.1.2.4.2++-- 10.1.2.5 HMAC DRBG Generation+hmacDRBGGen :: WorkingState -> Word16 -> AdditionalInput+            -> (WorkingState, Maybe ByteString)+hmacDRBGGen (k0, v0, c0) bytes info+    | bytes * 8 > 7500 = error "Maximum bits per request is 7500"+    | c0 > 10000       = ((k0, v0, c0), Nothing)  -- 10.1.2.5.1+    | otherwise        = ((k2, v3, c1), Just res) -- 10.1.2.5.8+  where+    (k1, v1)  | BS.null info = (k0, v0)+              | otherwise    = hmacDRBGUpd info k0 v0   -- 10.1.2.5.2+    (tmp, v2) = go (fromIntegral bytes) k1 v1 BS.empty -- 10.1.2.5.3/4+    res       = BS.take (fromIntegral bytes) tmp       -- 10.1.2.5.5+    (k2, v3)  = hmacDRBGUpd info k1 v2                 -- 10.1.2.5.6+    c1        = c0 + 1                                 -- 10.1.2.5.7+    go l k v acc | BS.length acc >= l = (acc,v)+                 | otherwise = let vn = getHash256 $ hmac256 k v+                               in go l k vn (acc `BS.append` vn)+
+ Network/Haskoin/Crypto/Keys.hs view
@@ -0,0 +1,406 @@+module Network.Haskoin.Crypto.Keys+( PubKeyI(pubKeyCompressed, pubKeyPoint)+, PubKey, PubKeyC, PubKeyU+, makePubKey+, makePubKeyG+, makePubKeyC+, makePubKeyU+, toPubKeyG+, eitherPubKey+, maybePubKeyC+, maybePubKeyU+, derivePubKey+, pubKeyAddr+, tweakPubKeyC+, PrvKeyI(prvKeyCompressed, prvKeySecKey)+, PrvKey, PrvKeyC, PrvKeyU+, makePrvKey+, makePrvKeyG+, makePrvKeyC+, makePrvKeyU+, toPrvKeyG+, eitherPrvKey+, maybePrvKeyC+, maybePrvKeyU+, encodePrvKey+, decodePrvKey+, prvKeyPutMonad+, prvKeyGetMonad+, fromWif+, toWif+, tweakPrvKeyC+) where++import Control.Applicative ((<|>))+import Control.Monad ((<=<), guard, mzero)+import Control.DeepSeq (NFData, rnf)++import Data.Aeson (Value(String), FromJSON, ToJSON, parseJSON, toJSON, withText)+import Data.Maybe (fromMaybe)+import Data.Binary (Binary, get, put)+import Data.Binary.Get (Get, getByteString)+import Data.Binary.Put (Put, putByteString)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+    ( head, tail+    , last, init+    , cons, snoc+    , length, elem, pack+    )+import Data.String (IsString, fromString)+import Data.String.Conversions (cs)++import qualified Crypto.Secp256k1 as EC++import Text.Read (readPrec, parens, lexP, pfail)+import qualified Text.Read as Read (Lexeme(Ident, String))++import Network.Haskoin.Crypto.Base58+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Constants+import Network.Haskoin.Util++data Generic+data Compressed+data Uncompressed++-- | Elliptic curve public key type. Two constructors are provided for creating+-- compressed and uncompressed public keys from a Point. The use of compressed+-- keys is preferred as it produces shorter keys without compromising security.+-- Uncompressed keys are supported for backwards compatibility.+type PubKey = PubKeyI Generic+type PubKeyC = PubKeyI Compressed+type PubKeyU = PubKeyI Uncompressed++-- Internal type for public keys+data PubKeyI c = PubKeyI+    { pubKeyPoint      :: !EC.PubKey+    , pubKeyCompressed :: !Bool+    } deriving (Eq)++-- TODO: Test+instance Show PubKey where+    showsPrec d k = showParen (d > 10) $+        showString "PubKey " . shows (encodeHex $ encode' k)++-- TODO: Test+instance Show PubKeyC where+    showsPrec d k = showParen (d > 10) $+        showString "PubKeyC " . shows (encodeHex $ encode' k)++-- TODO: Test+instance Show PubKeyU where+    showsPrec d k = showParen (d > 10) $+        showString "PubKeyU " . shows (encodeHex $ encode' k)++-- TODO: Test+instance Read PubKey where+    readPrec = parens $ do+        Read.Ident "PubKey" <- lexP+        Read.String str <- lexP+        maybe pfail return $ decodeToMaybe <=< decodeHex $ cs str++-- TODO: Test+instance Read PubKeyC where+    readPrec = parens $ do+        Read.Ident "PubKeyC" <- lexP+        Read.String str <- lexP+        maybe pfail return $ decodeToMaybe <=< decodeHex $ cs str++-- TODO: Test+instance Read PubKeyU where+    readPrec = parens $ do+        Read.Ident "PubKeyU" <- lexP+        Read.String str <- lexP+        maybe pfail return $ decodeToMaybe <=< decodeHex $ cs str++-- TODO: Test+instance IsString PubKey where+    fromString str =+        fromMaybe e $ decodeToMaybe <=< decodeHex $ cs str+      where+        e = error "Could not decode public key"++instance IsString PubKeyC where+    fromString str =+        fromMaybe e $ decodeToMaybe <=< decodeHex $ cs str+      where+        e = error "Could not decode compressed public key"++instance IsString PubKeyU where+    fromString str =+        fromMaybe e $ decodeToMaybe <=< decodeHex $ cs str+      where+        e = error "Could not decode uncompressed public key"++instance NFData (PubKeyI c) where+    rnf (PubKeyI p c) = p `seq` rnf c++instance ToJSON PubKey where+    toJSON = String . cs . encodeHex . encode'++instance FromJSON PubKey where+    parseJSON = withText "PubKey" $+        maybe mzero return . (decodeToMaybe =<<) . decodeHex . cs++instance ToJSON PubKeyC where+    toJSON = String . cs . encodeHex . encode'++instance FromJSON PubKeyC where+    parseJSON = withText "PubKeyC" $+        maybe mzero return . (decodeToMaybe =<<) . decodeHex . cs++instance ToJSON PubKeyU where+    toJSON = String . cs . encodeHex . encode'++instance FromJSON PubKeyU where+    parseJSON = withText "PubKeyU" $+        maybe mzero return . (decodeToMaybe =<<) . decodeHex . cs++-- Constructors for public keys+makePubKey :: EC.PubKey -> PubKey+makePubKey p = PubKeyI p True++makePubKeyG :: Bool -> EC.PubKey -> PubKey+makePubKeyG c p = PubKeyI p c++makePubKeyC :: EC.PubKey -> PubKeyC+makePubKeyC p = PubKeyI p True++makePubKeyU :: EC.PubKey -> PubKeyU+makePubKeyU p = PubKeyI p False++toPubKeyG :: PubKeyI c -> PubKey+toPubKeyG (PubKeyI p c) = makePubKeyG c p++eitherPubKey :: PubKeyI c -> Either PubKeyU PubKeyC+eitherPubKey pk+    | pubKeyCompressed pk = Right $ makePubKeyC $ pubKeyPoint pk+    | otherwise           = Left  $ makePubKeyU $ pubKeyPoint pk++maybePubKeyC :: PubKeyI c -> Maybe PubKeyC+maybePubKeyC pk+    | pubKeyCompressed pk = Just $ makePubKeyC $ pubKeyPoint pk+    | otherwise           = Nothing++maybePubKeyU :: PubKeyI c -> Maybe PubKeyU+maybePubKeyU pk+    | not (pubKeyCompressed pk) = Just $ makePubKeyU $ pubKeyPoint pk+    | otherwise                 = Nothing++-- | Derives a public key from a private key. This function will preserve+-- information on key compression ('PrvKey' becomes 'PubKey' and 'PrvKeyU'+-- becomes 'PubKeyU')+derivePubKey :: PrvKeyI c -> PubKeyI c+derivePubKey (PrvKeyI d c) = PubKeyI (EC.derivePubKey d) c++instance Binary PubKey where+    get =+        (toPubKeyG <$> getC) <|> (toPubKeyG <$> getU)+      where+        getC = get :: Get (PubKeyI Compressed)+        getU = get :: Get (PubKeyI Uncompressed)++    put pk = case eitherPubKey pk of+        Left k  -> put k+        Right k -> put k++instance Binary PubKeyC where+    get = do+        bs <- getByteString 33+        guard $ BS.head bs `BS.elem` BS.pack [0x02, 0x03]+        maybe mzero return $ makePubKeyC <$> EC.importPubKey bs++    put pk = putByteString $ EC.exportPubKey True $ pubKeyPoint pk++instance Binary PubKeyU where+    get = do+        bs <- getByteString 65+        guard $ BS.head bs == 0x04+        maybe mzero return $ makePubKeyU <$> EC.importPubKey bs++    put pk = putByteString $ EC.exportPubKey False $ pubKeyPoint pk++-- | Computes an 'Address' from a public key+pubKeyAddr :: Binary (PubKeyI c) => PubKeyI c -> Address+pubKeyAddr = PubKeyAddress . hash160 . getHash256 . hash256 . encode'++-- | Tweak a compressed public key+tweakPubKeyC :: PubKeyC -> Hash256 -> Maybe PubKeyC+tweakPubKeyC pub h =+    makePubKeyC <$> (EC.tweakAddPubKey point =<< tweak)+  where+    point = pubKeyPoint pub+    tweak = EC.tweak $ getHash256 h++{- Private Keys -}++-- | Elliptic curve private key type. Two constructors are provided for creating+-- compressed or uncompressed private keys. Compression information is stored+-- in private key WIF formats and needs to be preserved to generate the correct+-- addresses from the corresponding public key.++-- Internal private key type+data PrvKeyI c = PrvKeyI+    { prvKeySecKey     :: !EC.SecKey+    , prvKeyCompressed :: !Bool+    } deriving (Eq)++instance NFData (PrvKeyI c) where+    rnf (PrvKeyI s b) = s `seq` b `seq` ()++-- TODO: Test+instance Show PrvKey where+    showsPrec d k = showParen (d > 10) $+        showString "PrvKey " . shows (toWif k)++-- TODO: Test+instance Show PrvKeyC where+    showsPrec d k = showParen (d > 10) $+        showString "PrvKeyC " . shows (toWif k)++-- TODO: Test+instance Show PrvKeyU where+    showsPrec d k = showParen (d > 10) $+        showString "PrvKeyU " . shows (toWif k)++-- TODO: Test+instance Read PrvKey where+    readPrec = parens $ do+        Read.Ident "PrvKey" <- lexP+        Read.String str <- lexP+        maybe pfail return $ fromWif $ cs str++-- TODO: Test+instance Read PrvKeyC where+    readPrec = parens $ do+        Read.Ident "PrvKeyC" <- lexP+        Read.String str <- lexP+        key <- maybe pfail return $ fromWif $ cs str+        case eitherPrvKey key of+            Left _  -> pfail+            Right k -> return k++-- TODO: Test+instance Read PrvKeyU where+    readPrec = parens $ do+        Read.Ident "PrvKeyU" <- lexP+        Read.String str <- lexP+        key <- maybe pfail return $ fromWif $ cs str+        case eitherPrvKey key of+            Left k  -> return k+            Right _ -> pfail++-- TODO: Test+instance IsString PrvKey where+    fromString str =+        fromMaybe e $ fromWif $ cs str+      where+        e = error "Could not decode WIF"++-- TODO: Test+instance IsString PrvKeyC where+    fromString str =+        case eitherPrvKey key of+            Left _  -> undefined+            Right k -> k+      where+        key = fromMaybe e $ fromWif $ cs str+        e = error "Could not decode WIF"++-- TODO: Test+instance IsString PrvKeyU where+    fromString str =+        case eitherPrvKey key of+            Left k  -> k+            Right _ -> undefined+      where+        key = fromMaybe e $ fromWif $ cs str+        e = error "Could not decode WIF"++type PrvKey = PrvKeyI Generic+type PrvKeyC = PrvKeyI Compressed+type PrvKeyU = PrvKeyI Uncompressed++makePrvKeyI :: Bool -> EC.SecKey -> PrvKeyI c+makePrvKeyI c d = PrvKeyI d c++makePrvKey :: EC.SecKey -> PrvKey+makePrvKey d = makePrvKeyI True d++makePrvKeyG :: Bool -> EC.SecKey -> PrvKey+makePrvKeyG = makePrvKeyI++makePrvKeyC :: EC.SecKey -> PrvKeyC+makePrvKeyC d = makePrvKeyI True d++makePrvKeyU :: EC.SecKey -> PrvKeyU+makePrvKeyU d = makePrvKeyI False d++toPrvKeyG :: PrvKeyI c -> PrvKey+toPrvKeyG (PrvKeyI d c) = PrvKeyI d c++eitherPrvKey :: PrvKeyI c -> Either PrvKeyU PrvKeyC+eitherPrvKey (PrvKeyI d compressed)+    | compressed = Right $ PrvKeyI d compressed+    | otherwise  = Left  $ PrvKeyI d compressed++maybePrvKeyC :: PrvKeyI c -> Maybe PrvKeyC+maybePrvKeyC (PrvKeyI d compressed)+    | compressed = Just $ PrvKeyI d compressed+    | otherwise  = Nothing++maybePrvKeyU :: PrvKeyI c -> Maybe PrvKeyU+maybePrvKeyU (PrvKeyI d compressed)+    | not compressed = Just $ PrvKeyI d compressed+    | otherwise      = Nothing++-- | Serialize private key as 32-byte big-endian 'ByteString'+encodePrvKey :: PrvKeyI c -> ByteString+encodePrvKey (PrvKeyI d _) = EC.getSecKey d++-- | Deserialize private key as 32-byte big-endian 'ByteString'+decodePrvKey :: (EC.SecKey -> PrvKeyI c) -> ByteString -> Maybe (PrvKeyI c)+decodePrvKey f bs = f <$> EC.secKey bs++prvKeyGetMonad :: (EC.SecKey -> PrvKeyI c) -> Get (PrvKeyI c)+prvKeyGetMonad f = do+    bs <- getByteString 32+    fromMaybe err $ return <$> f <$> EC.secKey bs+  where+    err = fail "Get: Invalid private key"++prvKeyPutMonad :: PrvKeyI c -> Put+prvKeyPutMonad (PrvKeyI k _) = putByteString $ EC.getSecKey k++-- | Decodes a private key from a WIF encoded 'ByteString'. This function can+-- fail if the input string does not decode correctly as a base 58 string or if+-- the checksum fails.+-- <http://en.bitcoin.it/wiki/Wallet_import_format>+fromWif :: ByteString -> Maybe PrvKey+fromWif wif = do+    bs <- decodeBase58Check wif+    -- Check that this is a private key+    guard (BS.head bs == secretPrefix)+    case BS.length bs of+        33 -> do               -- Uncompressed format+            makePrvKeyG False <$> EC.secKey (BS.tail bs)+        34 -> do               -- Compressed format+            guard $ BS.last bs == 0x01+            makePrvKeyG True <$> EC.secKey (BS.tail $ BS.init bs)+        _  -> Nothing          -- Bad length++-- | Encodes a private key into WIF format+toWif :: PrvKeyI c -> ByteString+toWif (PrvKeyI k c) = encodeBase58Check $ BS.cons secretPrefix $+    if c then EC.getSecKey k `BS.snoc` 0x01 else EC.getSecKey k+++-- | Tweak a private key+tweakPrvKeyC :: PrvKeyC -> Hash256 -> Maybe PrvKeyC+tweakPrvKeyC key h =+    makePrvKeyC <$> (EC.tweakAddSecKey sec =<< tweak)+  where+    sec   = prvKeySecKey key+    tweak = EC.tweak $ getHash256 h+
+ Network/Haskoin/Crypto/Mnemonic.hs view
@@ -0,0 +1,499 @@+-- | Mnemonic keys (BIP-39). Only the English dictionary in the BIP is+-- supported.+module Network.Haskoin.Crypto.Mnemonic+(+  -- * Data types+  Entropy+, Mnemonic+, Passphrase+, Seed++  -- * Entropy encoding and decoding+, toMnemonic+, fromMnemonic++  -- * Generating 512-bit seeds+, mnemonicToSeed++  -- * Helper functions+, getBits+) where++import Control.Monad (when)+import qualified Crypto.Hash.SHA256 as SHA256+import Crypto.PBKDF.ByteString (sha512PBKDF2)+import Data.Bits ((.&.), shiftL, shiftR)+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as C (unwords, words)+import Data.String.Conversions (cs)+import qualified Data.ByteString as BS+import qualified Data.Map.Strict as M+import Data.List+import Data.Maybe+import Data.Vector ((!), Vector)+import qualified Data.Vector as V+import Network.Haskoin.Util++type Entropy = ByteString+type Mnemonic = ByteString+type Passphrase = ByteString+type Seed = ByteString+type Checksum = ByteString++-- | Provide intial entropy as a 'ByteString' of length multiple of 4 bytes.+-- Output a mnemonic sentence.+toMnemonic :: Entropy -> Either String Mnemonic+toMnemonic ent = do+    when (remainder /= 0) $+        Left "toMnemonic: entropy must be multiples of 4 bytes"+    when (cs_len > 16) $+        Left "toMnemonic: maximum entropy is 64 bytes (512 bits)"+    return ms+  where+    (cs_len, remainder) = BS.length ent `quotRem` 4+    c = calcCS cs_len ent+    indices = bsToIndices $ ent `BS.append` c+    ms = C.unwords $ map (wl!) indices++-- | Revert 'toMnemonic'. Do not use this to generate seeds. Instead use+-- 'mnemonicToSeed'. This outputs the original entropy used to generate a+-- mnemonic.+fromMnemonic :: Mnemonic -> Either String Entropy+fromMnemonic ms = do+    when (word_count > 48) $+        Left $ "fromMnemonic: too many words: " ++ show word_count+    when (word_count `mod` 3 /= 0) $+        Left $ "fromMnemonic: wrong number of words:" ++ show word_count+    ms_bs <- indicesToBS =<< getIndices ms_words+    let (ms_ent, ms_cs) = BS.splitAt (ent_len * 4) ms_bs+        ms_cs_num = numCS cs_len ms_cs+        ent_cs_num = numCS cs_len $ calcCS cs_len ms_ent+    when (ent_cs_num /= ms_cs_num) $+        Left $ "fromMnemonic: checksum failed: " ++ sh ent_cs_num ms_cs_num+    return ms_ent+  where+    ms_words = C.words ms+    word_count = length ms_words+    (ent_len, cs_len) = (word_count * 11) `quotRem` 32+    sh cs_a cs_b = show cs_a ++ " /= " ++ show cs_b++calcCS :: Int -> Entropy -> Checksum+calcCS len = getBits len . SHA256.hash++numCS :: Int -> Entropy -> Integer+numCS len =+    shiftCS . bsToInteger+  where+    shiftCS = case 8 - len `mod` 8 of+        0 -> id+        x -> flip shiftR x++-- | Turn any sequence of characters into a 512-bit seed.  Does not have to be+-- a mnemonic sentence generated from 'toMnemonic'.  Use 'mnemonicToSeed' to+-- get a seed from a mnemonic sentence.  Warning: Does not perform NFKD+-- normalization.+anyToSeed :: Passphrase -> Mnemonic -> Seed+anyToSeed pf ms =+    sha512PBKDF2 ms ("mnemonic" `mappend` pf) 2048 64++-- | Get a 512-bit seed from a mnemonic sentence.  Will calculate checksum.+-- Passphrase can be used to protect the mnemonic.  Use an empty string as+-- passphrase if none is required.+mnemonicToSeed :: Passphrase -> Mnemonic -> Either String Seed+mnemonicToSeed pf ms = do+    ent <- fromMnemonic ms+    mnm <- toMnemonic ent+    return $ anyToSeed pf mnm++-- | Obtain 'Int' bits from beginning of 'ByteString'. Resulting 'ByteString'+-- will be smallest required to hold that many bits, padded with zeroes to the+-- right.+getBits :: Int -> ByteString -> ByteString+getBits b bs+    | r == 0 = BS.take q bs+    | otherwise = i `BS.snoc` l+  where+    (q, r) = b `quotRem` 8+    s = (BS.take (q + 1) bs)+    i = BS.init s+    l = BS.last s .&. (0xff `shiftL` (8 - r))    -- zero unneeded bits++-- | Get indices of words in word list.+getIndices :: [ByteString] -> Either String [Int]+getIndices ws+    | null n = return $ catMaybes i+    | otherwise = Left $ "getIndices: words not found: " ++ cs w+  where+    i = map (`M.lookup` wl') ws+    n = elemIndices Nothing i+    w = C.unwords $ map (ws!!) n++indicesToBS :: [Int] -> Either String ByteString+indicesToBS is = do+    when lrg $ Left "indicesToBS: index larger or equal than 2048"+    return . pad . integerToBS $ foldl' f 0 is `shiftL` shift_width+  where+    lrg = not . isNothing $ find (>= 2048) is+    (q, r) = (length is * 11) `quotRem` 8+    shift_width = if r == 0 then 0 else 8 - r+    bl = if r == 0 then q else q + 1   -- length of resulting ByteString+    pad bs = BS.append (BS.replicate (bl - BS.length bs) 0x00) bs+    f acc x = (acc `shiftL` 11) + fromIntegral x++bsToIndices :: ByteString -> [Int]+bsToIndices bs =+    reverse . go q $ bsToInteger bs `shiftR` r+  where+    (q, r) = (BS.length bs * 8) `quotRem` 11+    go 0 _ = []+    go n i = (fromIntegral $ i `mod` 2048) : go (n - 1) (i `shiftR` 11)++wl' :: M.Map ByteString Int+wl' = V.ifoldr' (\i w m -> M.insert w i m) M.empty wl++-- | Standard English dictionary from BIP-39 specification.+wl :: Vector ByteString+wl = V.fromListN 2048+    [ "abandon", "ability", "able", "about", "above", "absent"+    , "absorb", "abstract", "absurd", "abuse", "access", "accident"+    , "account", "accuse", "achieve", "acid", "acoustic", "acquire"+    , "across", "act", "action", "actor", "actress", "actual"+    , "adapt", "add", "addict", "address", "adjust", "admit"+    , "adult", "advance", "advice", "aerobic", "affair", "afford"+    , "afraid", "again", "age", "agent", "agree", "ahead"+    , "aim", "air", "airport", "aisle", "alarm", "album"+    , "alcohol", "alert", "alien", "all", "alley", "allow"+    , "almost", "alone", "alpha", "already", "also", "alter"+    , "always", "amateur", "amazing", "among", "amount", "amused"+    , "analyst", "anchor", "ancient", "anger", "angle", "angry"+    , "animal", "ankle", "announce", "annual", "another", "answer"+    , "antenna", "antique", "anxiety", "any", "apart", "apology"+    , "appear", "apple", "approve", "april", "arch", "arctic"+    , "area", "arena", "argue", "arm", "armed", "armor"+    , "army", "around", "arrange", "arrest", "arrive", "arrow"+    , "art", "artefact", "artist", "artwork", "ask", "aspect"+    , "assault", "asset", "assist", "assume", "asthma", "athlete"+    , "atom", "attack", "attend", "attitude", "attract", "auction"+    , "audit", "august", "aunt", "author", "auto", "autumn"+    , "average", "avocado", "avoid", "awake", "aware", "away"+    , "awesome", "awful", "awkward", "axis", "baby", "bachelor"+    , "bacon", "badge", "bag", "balance", "balcony", "ball"+    , "bamboo", "banana", "banner", "bar", "barely", "bargain"+    , "barrel", "base", "basic", "basket", "battle", "beach"+    , "bean", "beauty", "because", "become", "beef", "before"+    , "begin", "behave", "behind", "believe", "below", "belt"+    , "bench", "benefit", "best", "betray", "better", "between"+    , "beyond", "bicycle", "bid", "bike", "bind", "biology"+    , "bird", "birth", "bitter", "black", "blade", "blame"+    , "blanket", "blast", "bleak", "bless", "blind", "blood"+    , "blossom", "blouse", "blue", "blur", "blush", "board"+    , "boat", "body", "boil", "bomb", "bone", "bonus"+    , "book", "boost", "border", "boring", "borrow", "boss"+    , "bottom", "bounce", "box", "boy", "bracket", "brain"+    , "brand", "brass", "brave", "bread", "breeze", "brick"+    , "bridge", "brief", "bright", "bring", "brisk", "broccoli"+    , "broken", "bronze", "broom", "brother", "brown", "brush"+    , "bubble", "buddy", "budget", "buffalo", "build", "bulb"+    , "bulk", "bullet", "bundle", "bunker", "burden", "burger"+    , "burst", "bus", "business", "busy", "butter", "buyer"+    , "buzz", "cabbage", "cabin", "cable", "cactus", "cage"+    , "cake", "call", "calm", "camera", "camp", "can"+    , "canal", "cancel", "candy", "cannon", "canoe", "canvas"+    , "canyon", "capable", "capital", "captain", "car", "carbon"+    , "card", "cargo", "carpet", "carry", "cart", "case"+    , "cash", "casino", "castle", "casual", "cat", "catalog"+    , "catch", "category", "cattle", "caught", "cause", "caution"+    , "cave", "ceiling", "celery", "cement", "census", "century"+    , "cereal", "certain", "chair", "chalk", "champion", "change"+    , "chaos", "chapter", "charge", "chase", "chat", "cheap"+    , "check", "cheese", "chef", "cherry", "chest", "chicken"+    , "chief", "child", "chimney", "choice", "choose", "chronic"+    , "chuckle", "chunk", "churn", "cigar", "cinnamon", "circle"+    , "citizen", "city", "civil", "claim", "clap", "clarify"+    , "claw", "clay", "clean", "clerk", "clever", "click"+    , "client", "cliff", "climb", "clinic", "clip", "clock"+    , "clog", "close", "cloth", "cloud", "clown", "club"+    , "clump", "cluster", "clutch", "coach", "coast", "coconut"+    , "code", "coffee", "coil", "coin", "collect", "color"+    , "column", "combine", "come", "comfort", "comic", "common"+    , "company", "concert", "conduct", "confirm", "congress", "connect"+    , "consider", "control", "convince", "cook", "cool", "copper"+    , "copy", "coral", "core", "corn", "correct", "cost"+    , "cotton", "couch", "country", "couple", "course", "cousin"+    , "cover", "coyote", "crack", "cradle", "craft", "cram"+    , "crane", "crash", "crater", "crawl", "crazy", "cream"+    , "credit", "creek", "crew", "cricket", "crime", "crisp"+    , "critic", "crop", "cross", "crouch", "crowd", "crucial"+    , "cruel", "cruise", "crumble", "crunch", "crush", "cry"+    , "crystal", "cube", "culture", "cup", "cupboard", "curious"+    , "current", "curtain", "curve", "cushion", "custom", "cute"+    , "cycle", "dad", "damage", "damp", "dance", "danger"+    , "daring", "dash", "daughter", "dawn", "day", "deal"+    , "debate", "debris", "decade", "december", "decide", "decline"+    , "decorate", "decrease", "deer", "defense", "define", "defy"+    , "degree", "delay", "deliver", "demand", "demise", "denial"+    , "dentist", "deny", "depart", "depend", "deposit", "depth"+    , "deputy", "derive", "describe", "desert", "design", "desk"+    , "despair", "destroy", "detail", "detect", "develop", "device"+    , "devote", "diagram", "dial", "diamond", "diary", "dice"+    , "diesel", "diet", "differ", "digital", "dignity", "dilemma"+    , "dinner", "dinosaur", "direct", "dirt", "disagree", "discover"+    , "disease", "dish", "dismiss", "disorder", "display", "distance"+    , "divert", "divide", "divorce", "dizzy", "doctor", "document"+    , "dog", "doll", "dolphin", "domain", "donate", "donkey"+    , "donor", "door", "dose", "double", "dove", "draft"+    , "dragon", "drama", "drastic", "draw", "dream", "dress"+    , "drift", "drill", "drink", "drip", "drive", "drop"+    , "drum", "dry", "duck", "dumb", "dune", "during"+    , "dust", "dutch", "duty", "dwarf", "dynamic", "eager"+    , "eagle", "early", "earn", "earth", "easily", "east"+    , "easy", "echo", "ecology", "economy", "edge", "edit"+    , "educate", "effort", "egg", "eight", "either", "elbow"+    , "elder", "electric", "elegant", "element", "elephant", "elevator"+    , "elite", "else", "embark", "embody", "embrace", "emerge"+    , "emotion", "employ", "empower", "empty", "enable", "enact"+    , "end", "endless", "endorse", "enemy", "energy", "enforce"+    , "engage", "engine", "enhance", "enjoy", "enlist", "enough"+    , "enrich", "enroll", "ensure", "enter", "entire", "entry"+    , "envelope", "episode", "equal", "equip", "era", "erase"+    , "erode", "erosion", "error", "erupt", "escape", "essay"+    , "essence", "estate", "eternal", "ethics", "evidence", "evil"+    , "evoke", "evolve", "exact", "example", "excess", "exchange"+    , "excite", "exclude", "excuse", "execute", "exercise", "exhaust"+    , "exhibit", "exile", "exist", "exit", "exotic", "expand"+    , "expect", "expire", "explain", "expose", "express", "extend"+    , "extra", "eye", "eyebrow", "fabric", "face", "faculty"+    , "fade", "faint", "faith", "fall", "false", "fame"+    , "family", "famous", "fan", "fancy", "fantasy", "farm"+    , "fashion", "fat", "fatal", "father", "fatigue", "fault"+    , "favorite", "feature", "february", "federal", "fee", "feed"+    , "feel", "female", "fence", "festival", "fetch", "fever"+    , "few", "fiber", "fiction", "field", "figure", "file"+    , "film", "filter", "final", "find", "fine", "finger"+    , "finish", "fire", "firm", "first", "fiscal", "fish"+    , "fit", "fitness", "fix", "flag", "flame", "flash"+    , "flat", "flavor", "flee", "flight", "flip", "float"+    , "flock", "floor", "flower", "fluid", "flush", "fly"+    , "foam", "focus", "fog", "foil", "fold", "follow"+    , "food", "foot", "force", "forest", "forget", "fork"+    , "fortune", "forum", "forward", "fossil", "foster", "found"+    , "fox", "fragile", "frame", "frequent", "fresh", "friend"+    , "fringe", "frog", "front", "frost", "frown", "frozen"+    , "fruit", "fuel", "fun", "funny", "furnace", "fury"+    , "future", "gadget", "gain", "galaxy", "gallery", "game"+    , "gap", "garage", "garbage", "garden", "garlic", "garment"+    , "gas", "gasp", "gate", "gather", "gauge", "gaze"+    , "general", "genius", "genre", "gentle", "genuine", "gesture"+    , "ghost", "giant", "gift", "giggle", "ginger", "giraffe"+    , "girl", "give", "glad", "glance", "glare", "glass"+    , "glide", "glimpse", "globe", "gloom", "glory", "glove"+    , "glow", "glue", "goat", "goddess", "gold", "good"+    , "goose", "gorilla", "gospel", "gossip", "govern", "gown"+    , "grab", "grace", "grain", "grant", "grape", "grass"+    , "gravity", "great", "green", "grid", "grief", "grit"+    , "grocery", "group", "grow", "grunt", "guard", "guess"+    , "guide", "guilt", "guitar", "gun", "gym", "habit"+    , "hair", "half", "hammer", "hamster", "hand", "happy"+    , "harbor", "hard", "harsh", "harvest", "hat", "have"+    , "hawk", "hazard", "head", "health", "heart", "heavy"+    , "hedgehog", "height", "hello", "helmet", "help", "hen"+    , "hero", "hidden", "high", "hill", "hint", "hip"+    , "hire", "history", "hobby", "hockey", "hold", "hole"+    , "holiday", "hollow", "home", "honey", "hood", "hope"+    , "horn", "horror", "horse", "hospital", "host", "hotel"+    , "hour", "hover", "hub", "huge", "human", "humble"+    , "humor", "hundred", "hungry", "hunt", "hurdle", "hurry"+    , "hurt", "husband", "hybrid", "ice", "icon", "idea"+    , "identify", "idle", "ignore", "ill", "illegal", "illness"+    , "image", "imitate", "immense", "immune", "impact", "impose"+    , "improve", "impulse", "inch", "include", "income", "increase"+    , "index", "indicate", "indoor", "industry", "infant", "inflict"+    , "inform", "inhale", "inherit", "initial", "inject", "injury"+    , "inmate", "inner", "innocent", "input", "inquiry", "insane"+    , "insect", "inside", "inspire", "install", "intact", "interest"+    , "into", "invest", "invite", "involve", "iron", "island"+    , "isolate", "issue", "item", "ivory", "jacket", "jaguar"+    , "jar", "jazz", "jealous", "jeans", "jelly", "jewel"+    , "job", "join", "joke", "journey", "joy", "judge"+    , "juice", "jump", "jungle", "junior", "junk", "just"+    , "kangaroo", "keen", "keep", "ketchup", "key", "kick"+    , "kid", "kidney", "kind", "kingdom", "kiss", "kit"+    , "kitchen", "kite", "kitten", "kiwi", "knee", "knife"+    , "knock", "know", "lab", "label", "labor", "ladder"+    , "lady", "lake", "lamp", "language", "laptop", "large"+    , "later", "latin", "laugh", "laundry", "lava", "law"+    , "lawn", "lawsuit", "layer", "lazy", "leader", "leaf"+    , "learn", "leave", "lecture", "left", "leg", "legal"+    , "legend", "leisure", "lemon", "lend", "length", "lens"+    , "leopard", "lesson", "letter", "level", "liar", "liberty"+    , "library", "license", "life", "lift", "light", "like"+    , "limb", "limit", "link", "lion", "liquid", "list"+    , "little", "live", "lizard", "load", "loan", "lobster"+    , "local", "lock", "logic", "lonely", "long", "loop"+    , "lottery", "loud", "lounge", "love", "loyal", "lucky"+    , "luggage", "lumber", "lunar", "lunch", "luxury", "lyrics"+    , "machine", "mad", "magic", "magnet", "maid", "mail"+    , "main", "major", "make", "mammal", "man", "manage"+    , "mandate", "mango", "mansion", "manual", "maple", "marble"+    , "march", "margin", "marine", "market", "marriage", "mask"+    , "mass", "master", "match", "material", "math", "matrix"+    , "matter", "maximum", "maze", "meadow", "mean", "measure"+    , "meat", "mechanic", "medal", "media", "melody", "melt"+    , "member", "memory", "mention", "menu", "mercy", "merge"+    , "merit", "merry", "mesh", "message", "metal", "method"+    , "middle", "midnight", "milk", "million", "mimic", "mind"+    , "minimum", "minor", "minute", "miracle", "mirror", "misery"+    , "miss", "mistake", "mix", "mixed", "mixture", "mobile"+    , "model", "modify", "mom", "moment", "monitor", "monkey"+    , "monster", "month", "moon", "moral", "more", "morning"+    , "mosquito", "mother", "motion", "motor", "mountain", "mouse"+    , "move", "movie", "much", "muffin", "mule", "multiply"+    , "muscle", "museum", "mushroom", "music", "must", "mutual"+    , "myself", "mystery", "myth", "naive", "name", "napkin"+    , "narrow", "nasty", "nation", "nature", "near", "neck"+    , "need", "negative", "neglect", "neither", "nephew", "nerve"+    , "nest", "net", "network", "neutral", "never", "news"+    , "next", "nice", "night", "noble", "noise", "nominee"+    , "noodle", "normal", "north", "nose", "notable", "note"+    , "nothing", "notice", "novel", "now", "nuclear", "number"+    , "nurse", "nut", "oak", "obey", "object", "oblige"+    , "obscure", "observe", "obtain", "obvious", "occur", "ocean"+    , "october", "odor", "off", "offer", "office", "often"+    , "oil", "okay", "old", "olive", "olympic", "omit"+    , "once", "one", "onion", "online", "only", "open"+    , "opera", "opinion", "oppose", "option", "orange", "orbit"+    , "orchard", "order", "ordinary", "organ", "orient", "original"+    , "orphan", "ostrich", "other", "outdoor", "outer", "output"+    , "outside", "oval", "oven", "over", "own", "owner"+    , "oxygen", "oyster", "ozone", "pact", "paddle", "page"+    , "pair", "palace", "palm", "panda", "panel", "panic"+    , "panther", "paper", "parade", "parent", "park", "parrot"+    , "party", "pass", "patch", "path", "patient", "patrol"+    , "pattern", "pause", "pave", "payment", "peace", "peanut"+    , "pear", "peasant", "pelican", "pen", "penalty", "pencil"+    , "people", "pepper", "perfect", "permit", "person", "pet"+    , "phone", "photo", "phrase", "physical", "piano", "picnic"+    , "picture", "piece", "pig", "pigeon", "pill", "pilot"+    , "pink", "pioneer", "pipe", "pistol", "pitch", "pizza"+    , "place", "planet", "plastic", "plate", "play", "please"+    , "pledge", "pluck", "plug", "plunge", "poem", "poet"+    , "point", "polar", "pole", "police", "pond", "pony"+    , "pool", "popular", "portion", "position", "possible", "post"+    , "potato", "pottery", "poverty", "powder", "power", "practice"+    , "praise", "predict", "prefer", "prepare", "present", "pretty"+    , "prevent", "price", "pride", "primary", "print", "priority"+    , "prison", "private", "prize", "problem", "process", "produce"+    , "profit", "program", "project", "promote", "proof", "property"+    , "prosper", "protect", "proud", "provide", "public", "pudding"+    , "pull", "pulp", "pulse", "pumpkin", "punch", "pupil"+    , "puppy", "purchase", "purity", "purpose", "purse", "push"+    , "put", "puzzle", "pyramid", "quality", "quantum", "quarter"+    , "question", "quick", "quit", "quiz", "quote", "rabbit"+    , "raccoon", "race", "rack", "radar", "radio", "rail"+    , "rain", "raise", "rally", "ramp", "ranch", "random"+    , "range", "rapid", "rare", "rate", "rather", "raven"+    , "raw", "razor", "ready", "real", "reason", "rebel"+    , "rebuild", "recall", "receive", "recipe", "record", "recycle"+    , "reduce", "reflect", "reform", "refuse", "region", "regret"+    , "regular", "reject", "relax", "release", "relief", "rely"+    , "remain", "remember", "remind", "remove", "render", "renew"+    , "rent", "reopen", "repair", "repeat", "replace", "report"+    , "require", "rescue", "resemble", "resist", "resource", "response"+    , "result", "retire", "retreat", "return", "reunion", "reveal"+    , "review", "reward", "rhythm", "rib", "ribbon", "rice"+    , "rich", "ride", "ridge", "rifle", "right", "rigid"+    , "ring", "riot", "ripple", "risk", "ritual", "rival"+    , "river", "road", "roast", "robot", "robust", "rocket"+    , "romance", "roof", "rookie", "room", "rose", "rotate"+    , "rough", "round", "route", "royal", "rubber", "rude"+    , "rug", "rule", "run", "runway", "rural", "sad"+    , "saddle", "sadness", "safe", "sail", "salad", "salmon"+    , "salon", "salt", "salute", "same", "sample", "sand"+    , "satisfy", "satoshi", "sauce", "sausage", "save", "say"+    , "scale", "scan", "scare", "scatter", "scene", "scheme"+    , "school", "science", "scissors", "scorpion", "scout", "scrap"+    , "screen", "script", "scrub", "sea", "search", "season"+    , "seat", "second", "secret", "section", "security", "seed"+    , "seek", "segment", "select", "sell", "seminar", "senior"+    , "sense", "sentence", "series", "service", "session", "settle"+    , "setup", "seven", "shadow", "shaft", "shallow", "share"+    , "shed", "shell", "sheriff", "shield", "shift", "shine"+    , "ship", "shiver", "shock", "shoe", "shoot", "shop"+    , "short", "shoulder", "shove", "shrimp", "shrug", "shuffle"+    , "shy", "sibling", "sick", "side", "siege", "sight"+    , "sign", "silent", "silk", "silly", "silver", "similar"+    , "simple", "since", "sing", "siren", "sister", "situate"+    , "six", "size", "skate", "sketch", "ski", "skill"+    , "skin", "skirt", "skull", "slab", "slam", "sleep"+    , "slender", "slice", "slide", "slight", "slim", "slogan"+    , "slot", "slow", "slush", "small", "smart", "smile"+    , "smoke", "smooth", "snack", "snake", "snap", "sniff"+    , "snow", "soap", "soccer", "social", "sock", "soda"+    , "soft", "solar", "soldier", "solid", "solution", "solve"+    , "someone", "song", "soon", "sorry", "sort", "soul"+    , "sound", "soup", "source", "south", "space", "spare"+    , "spatial", "spawn", "speak", "special", "speed", "spell"+    , "spend", "sphere", "spice", "spider", "spike", "spin"+    , "spirit", "split", "spoil", "sponsor", "spoon", "sport"+    , "spot", "spray", "spread", "spring", "spy", "square"+    , "squeeze", "squirrel", "stable", "stadium", "staff", "stage"+    , "stairs", "stamp", "stand", "start", "state", "stay"+    , "steak", "steel", "stem", "step", "stereo", "stick"+    , "still", "sting", "stock", "stomach", "stone", "stool"+    , "story", "stove", "strategy", "street", "strike", "strong"+    , "struggle", "student", "stuff", "stumble", "style", "subject"+    , "submit", "subway", "success", "such", "sudden", "suffer"+    , "sugar", "suggest", "suit", "summer", "sun", "sunny"+    , "sunset", "super", "supply", "supreme", "sure", "surface"+    , "surge", "surprise", "surround", "survey", "suspect", "sustain"+    , "swallow", "swamp", "swap", "swarm", "swear", "sweet"+    , "swift", "swim", "swing", "switch", "sword", "symbol"+    , "symptom", "syrup", "system", "table", "tackle", "tag"+    , "tail", "talent", "talk", "tank", "tape", "target"+    , "task", "taste", "tattoo", "taxi", "teach", "team"+    , "tell", "ten", "tenant", "tennis", "tent", "term"+    , "test", "text", "thank", "that", "theme", "then"+    , "theory", "there", "they", "thing", "this", "thought"+    , "three", "thrive", "throw", "thumb", "thunder", "ticket"+    , "tide", "tiger", "tilt", "timber", "time", "tiny"+    , "tip", "tired", "tissue", "title", "toast", "tobacco"+    , "today", "toddler", "toe", "together", "toilet", "token"+    , "tomato", "tomorrow", "tone", "tongue", "tonight", "tool"+    , "tooth", "top", "topic", "topple", "torch", "tornado"+    , "tortoise", "toss", "total", "tourist", "toward", "tower"+    , "town", "toy", "track", "trade", "traffic", "tragic"+    , "train", "transfer", "trap", "trash", "travel", "tray"+    , "treat", "tree", "trend", "trial", "tribe", "trick"+    , "trigger", "trim", "trip", "trophy", "trouble", "truck"+    , "true", "truly", "trumpet", "trust", "truth", "try"+    , "tube", "tuition", "tumble", "tuna", "tunnel", "turkey"+    , "turn", "turtle", "twelve", "twenty", "twice", "twin"+    , "twist", "two", "type", "typical", "ugly", "umbrella"+    , "unable", "unaware", "uncle", "uncover", "under", "undo"+    , "unfair", "unfold", "unhappy", "uniform", "unique", "unit"+    , "universe", "unknown", "unlock", "until", "unusual", "unveil"+    , "update", "upgrade", "uphold", "upon", "upper", "upset"+    , "urban", "urge", "usage", "use", "used", "useful"+    , "useless", "usual", "utility", "vacant", "vacuum", "vague"+    , "valid", "valley", "valve", "van", "vanish", "vapor"+    , "various", "vast", "vault", "vehicle", "velvet", "vendor"+    , "venture", "venue", "verb", "verify", "version", "very"+    , "vessel", "veteran", "viable", "vibrant", "vicious", "victory"+    , "video", "view", "village", "vintage", "violin", "virtual"+    , "virus", "visa", "visit", "visual", "vital", "vivid"+    , "vocal", "voice", "void", "volcano", "volume", "vote"+    , "voyage", "wage", "wagon", "wait", "walk", "wall"+    , "walnut", "want", "warfare", "warm", "warrior", "wash"+    , "wasp", "waste", "water", "wave", "way", "wealth"+    , "weapon", "wear", "weasel", "weather", "web", "wedding"+    , "weekend", "weird", "welcome", "west", "wet", "whale"+    , "what", "wheat", "wheel", "when", "where", "whip"+    , "whisper", "wide", "width", "wife", "wild", "will"+    , "win", "window", "wine", "wing", "wink", "winner"+    , "winter", "wire", "wisdom", "wise", "wish", "witness"+    , "wolf", "woman", "wonder", "wood", "wool", "word"+    , "work", "world", "worry", "worth", "wrap", "wreck"+    , "wrestle", "wrist", "write", "wrong", "yard", "year"+    , "yellow", "you", "young", "youth", "zebra", "zero"+    , "zone", "zoo"+    ]
+ Network/Haskoin/Internals.hs view
@@ -0,0 +1,60 @@+{-|+  This module expose haskoin internals. No guarantee is made on the+  stability of the interface of these internal modules.+-}+module Network.Haskoin.Internals+( module Network.Haskoin.Util+, module Network.Haskoin.Constants+, module Network.Haskoin.Crypto.Hash+, module Network.Haskoin.Crypto.Base58+, module Network.Haskoin.Crypto.Keys+, module Network.Haskoin.Crypto.ExtendedKeys+, module Network.Haskoin.Crypto.ECDSA+, module Network.Haskoin.Crypto.Mnemonic+, module Network.Haskoin.Node.Types+, module Network.Haskoin.Node.Message+, module Network.Haskoin.Node.Bloom+, module Network.Haskoin.Script.Types+, module Network.Haskoin.Script.Parser+, module Network.Haskoin.Script.SigHash+, module Network.Haskoin.Script.Evaluator+, module Network.Haskoin.Transaction.Types+, module Network.Haskoin.Transaction.Builder+, module Network.Haskoin.Block.Types+, module Network.Haskoin.Block.Merkle+, module Network.Haskoin.Test.Util+, module Network.Haskoin.Test.Crypto+, module Network.Haskoin.Test.Node+, module Network.Haskoin.Test.Message+, module Network.Haskoin.Test.Script+, module Network.Haskoin.Test.Transaction+, module Network.Haskoin.Test.Block+) where++import Network.Haskoin.Util+import Network.Haskoin.Constants+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Crypto.Base58+import Network.Haskoin.Crypto.Keys+import Network.Haskoin.Crypto.ExtendedKeys+import Network.Haskoin.Crypto.ECDSA+import Network.Haskoin.Crypto.Mnemonic+import Network.Haskoin.Node.Types+import Network.Haskoin.Node.Message+import Network.Haskoin.Node.Bloom+import Network.Haskoin.Script.Types+import Network.Haskoin.Script.Parser+import Network.Haskoin.Script.SigHash+import Network.Haskoin.Script.Evaluator+import Network.Haskoin.Transaction.Types+import Network.Haskoin.Transaction.Builder+import Network.Haskoin.Block.Types+import Network.Haskoin.Block.Merkle+import Network.Haskoin.Test.Util+import Network.Haskoin.Test.Crypto+import Network.Haskoin.Test.Node+import Network.Haskoin.Test.Message+import Network.Haskoin.Test.Script+import Network.Haskoin.Test.Transaction+import Network.Haskoin.Test.Block+
+ Network/Haskoin/Node.hs view
@@ -0,0 +1,52 @@+{-|+  This package provides basic types used for the Bitcoin networking protocol+  together with Data.Binary instances for efficiently serializing and+  de-serializing them. More information on the bitcoin protocol is available+  here: <http://en.bitcoin.it/wiki/Protocol_specification>+-}+module Network.Haskoin.Node+(+  -- * Requesting data+  GetData(..)+, Inv(..)+, InvVector(..)+, InvType(..)+, NotFound(..)++  -- * Network types+, VarInt(..)+, VarString(..)+, NetworkAddress(..)+, Addr(..)+, NetworkAddressTime+, Version(..)+, Ping(..)+, Pong(..)+, Alert(..)+, Reject(..)+, RejectCode(..)+, reject++  -- * Messages+, Message(..)+, MessageHeader(..)+, MessageCommand(..)++  -- * Bloom filters+, BloomFlags(..)+, BloomFilter(..)+, FilterLoad(..)+, FilterAdd(..)+, bloomCreate+, bloomInsert+, bloomContains+, isBloomValid+, isBloomEmpty+, isBloomFull++) where++import Network.Haskoin.Node.Message+import Network.Haskoin.Node.Types+import Network.Haskoin.Node.Bloom+
+ Network/Haskoin/Node/Bloom.hs view
@@ -0,0 +1,222 @@+module Network.Haskoin.Node.Bloom+( BloomFlags(..)+, BloomFilter(..)+, FilterLoad(..)+, FilterAdd(..)+, bloomCreate+, bloomInsert+, bloomContains+, isBloomValid+, isBloomEmpty+, isBloomFull+) where++import Control.Monad (replicateM, forM_)+import Control.DeepSeq (NFData, rnf)++import Data.Word+import Data.Bits+import Data.Hash.Murmur (murmur3)+import Data.Binary (Binary, get, put)+import Data.Binary.Get+    ( getWord8+    , getWord32le+    , getByteString+    )+import Data.Binary.Put+    ( putWord8+    , putWord32le+    , putByteString+    )+import qualified Data.Foldable as F+import qualified Data.Sequence as S+import qualified Data.ByteString as BS++import Network.Haskoin.Node.Types++-- 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001%+maxBloomSize :: Int+maxBloomSize = 36000++maxHashFuncs :: Word32+maxHashFuncs = 50++ln2Squared :: Double+ln2Squared = 0.4804530139182014246671025263266649717305529515945455++ln2 :: Double+ln2 = 0.6931471805599453094172321214581765680755001343602552++bitMask :: [Word8]+bitMask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]++-- | The bloom flags are used to tell the remote peer how to auto-update+-- the provided bloom filter.+data BloomFlags+    = BloomUpdateNone         -- ^ Never update+    | BloomUpdateAll          -- ^ Auto-update on all outputs+    | BloomUpdateP2PubKeyOnly+    -- ^ Only auto-update on outputs that are pay-to-pubkey or pay-to-multisig.+    -- This is the default setting.+    deriving (Eq, Show, Read)++instance NFData BloomFlags where rnf x = seq x ()++instance Binary BloomFlags where+    get = go =<< getWord8+      where+        go 0 = return BloomUpdateNone+        go 1 = return BloomUpdateAll+        go 2 = return BloomUpdateP2PubKeyOnly+        go _ = fail "BloomFlags get: Invalid bloom flag"++    put f = putWord8 $ case f of+        BloomUpdateNone         -> 0+        BloomUpdateAll          -> 1+        BloomUpdateP2PubKeyOnly -> 2++-- | A bloom filter is a probabilistic data structure that SPV clients send to+-- other peers to filter the set of transactions received from them. Bloom+-- filters are probabilistic and have a false positive rate. Some transactions+-- that pass the filter may not be relevant to the receiving peer. By+-- controlling the false positive rate, SPV nodes can trade off bandwidth+-- versus privacy.+data BloomFilter = BloomFilter+    { bloomData      :: !(S.Seq Word8)+    -- ^ Bloom filter data+    , bloomHashFuncs :: !Word32+    -- ^ Number of hash functions for this filter+    , bloomTweak     :: !Word32+    -- ^ Hash function random nonce+    , bloomFlags     :: !BloomFlags+    -- ^ Bloom filter auto-update flags+    }+    deriving (Eq, Show, Read)++instance NFData BloomFilter where+    rnf (BloomFilter d h t g) =+        rnf d `seq` rnf h `seq` rnf t `seq` rnf g++instance Binary BloomFilter where++    get = BloomFilter <$> (S.fromList <$> (readDat =<< get))+                      <*> getWord32le <*> getWord32le+                      <*> get+      where+        readDat (VarInt len) = replicateM (fromIntegral len) getWord8++    put (BloomFilter dat hashFuncs tweak flags) = do+        put $ VarInt $ fromIntegral $ S.length dat+        forM_ (F.toList dat) putWord8+        putWord32le hashFuncs+        putWord32le tweak+        put flags++-- | Set a new bloom filter on the peer connection.+newtype FilterLoad = FilterLoad { filterLoadBloomFilter :: BloomFilter }+    deriving (Eq, Show, Read)++instance NFData FilterLoad where+    rnf (FilterLoad f) = rnf f++instance Binary FilterLoad where+    get = FilterLoad <$> get+    put (FilterLoad f) = put f++-- | Add the given data element to the connections current filter without+-- requiring a completely new one to be set.+newtype FilterAdd = FilterAdd { getFilterData :: BS.ByteString }+    deriving (Eq, Show, Read)++instance NFData FilterAdd where+    rnf (FilterAdd f) = rnf f++instance Binary FilterAdd where+    get = do+        (VarInt len) <- get+        dat <- getByteString $ fromIntegral len+        return $ FilterAdd dat++    put (FilterAdd bs) = do+        put $ VarInt $ fromIntegral $ BS.length bs+        putByteString bs+++-- | Build a bloom filter that will provide the given false positive rate when+-- the given number of elements have been inserted.+bloomCreate :: Int          -- ^ Number of elements+            -> Double       -- ^ False positive rate+            -> Word32+             -- ^ A random nonce (tweak) for the hash function. It should be+             -- a random number but the secureness of the random value is not+             -- of geat consequence.+            -> BloomFlags   -- ^ Bloom filter flags+            -> BloomFilter  -- ^ Bloom filter+bloomCreate numElem fpRate tweak flags =+    BloomFilter (S.replicate bloomSize 0) numHashF tweak flags+  where+    -- Bloom filter size in bytes+    bloomSize = truncate $ (min a b) / 8+    -- Suggested size in bits+    a         = -1 / ln2Squared * (fromIntegral numElem) * log fpRate+    -- Maximum size in bits+    b         = fromIntegral $ maxBloomSize * 8+    numHashF  = truncate $ min c (fromIntegral maxHashFuncs)+    -- Suggested number of hash functions+    c         = (fromIntegral bloomSize) * 8 / (fromIntegral numElem) * ln2++bloomHash :: BloomFilter -> Word32 -> BS.ByteString -> Word32+bloomHash bfilter hashNum bs =+    murmur3 seed bs `mod` (fromIntegral (S.length (bloomData bfilter)) * 8)+  where+    seed = hashNum * 0xfba4c795 + (bloomTweak bfilter)++-- | Insert arbitrary data into a bloom filter. Returns the new bloom filter+-- containing the new data.+bloomInsert :: BloomFilter    -- ^ Original bloom filter+            -> BS.ByteString  -- ^ New data to insert+            -> BloomFilter    -- ^ Bloom filter containing the new data+bloomInsert bfilter bs+    | isBloomFull bfilter = bfilter+    | otherwise = bfilter { bloomData = newData }+  where+    idxs    = map (\i -> bloomHash bfilter i bs) [0..bloomHashFuncs bfilter - 1]+    upd s i = S.adjust (.|. bitMask !! fromIntegral (7 .&. i))+                       (fromIntegral $ i `shiftR` 3) s+    newData = foldl upd (bloomData bfilter) idxs++-- | Tests if some arbitrary data matches the filter. This can be either because+-- the data was inserted into the filter or because it is a false positive.+bloomContains :: BloomFilter    -- ^ Bloom filter+              -> BS.ByteString+              -- ^ Data that will be checked against the given bloom filter+              -> Bool+              -- ^ Returns True if the data matches the filter+bloomContains bfilter bs+    | isBloomFull bfilter  = True+    | isBloomEmpty bfilter = False+    | otherwise            = and $ map isSet idxs+  where+    s       = bloomData bfilter+    idxs    = map (\i -> bloomHash bfilter i bs) [0..bloomHashFuncs bfilter - 1]+    isSet i = (S.index s (fromIntegral $ i `shiftR` 3))+          .&. (bitMask !! fromIntegral (7 .&. i)) /= 0++-- TODO: Write bloomRelevantUpdate+-- bloomRelevantUpdate :: BloomFilter -> Tx -> Hash256 -> Maybe BloomFilter++-- | Returns True if the filter is empty (all bytes set to 0x00)+isBloomEmpty :: BloomFilter -> Bool+isBloomEmpty bfilter = all (== 0x00) $ F.toList $ bloomData bfilter++-- | Returns True if the filter is full (all bytes set to 0xff)+isBloomFull :: BloomFilter -> Bool+isBloomFull bfilter = all (== 0xff) $ F.toList $ bloomData bfilter++-- | Tests if a given bloom filter is valid.+isBloomValid :: BloomFilter -- ^ Bloom filter to test+             -> Bool        -- ^ True if the given filter is valid+isBloomValid bfilter =+    (S.length $ bloomData bfilter) <= maxBloomSize &&+    (bloomHashFuncs bfilter) <= maxHashFuncs+
+ Network/Haskoin/Node/Message.hs view
@@ -0,0 +1,163 @@+module Network.Haskoin.Node.Message+( Message(..)+, MessageHeader(..)+) where++import Control.DeepSeq (NFData, rnf)+import Control.Monad (unless)++import Data.Word (Word32)+import Data.Binary (Binary, get, put)+import Data.Binary.Get+    ( lookAhead+    , getByteString+    , getWord32le+    , getWord32be+    )+import Data.Binary.Put+    ( putByteString+    , putWord32le+    , putWord32be+    )+import qualified Data.ByteString as BS+    ( length+    , append+    , empty+    )++import Network.Haskoin.Node.Types+import Network.Haskoin.Transaction.Types+import Network.Haskoin.Block.Types+import Network.Haskoin.Block.Merkle+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Node.Bloom+import Network.Haskoin.Constants+import Network.Haskoin.Util++-- | Data type representing the header of a 'Message'. All messages sent between+-- nodes contain a message header.+data MessageHeader =+    MessageHeader {+                  -- | Network magic bytes. It is used to differentiate+                  -- messages meant for different bitcoin networks, such as+                  -- prodnet and testnet.+                    headMagic       :: !Word32+                  -- | Message command identifying the type of message.+                  -- included in the payload.+                  , headCmd         :: !MessageCommand+                  -- | Byte length of the payload.+                  , headPayloadSize :: !Word32+                  -- | Checksum of the payload.+                  , headChecksum    :: !CheckSum32+                  } deriving (Eq, Show, Read)++instance NFData MessageHeader where+    rnf (MessageHeader m c p s) = rnf m `seq` rnf c `seq` rnf p `seq` rnf s++instance Binary MessageHeader where++    get = MessageHeader <$> getWord32be+                        <*> get+                        <*> getWord32le+                        <*> get++    put (MessageHeader m c l chk) = do+        putWord32be m+        put         c+        putWord32le l+        put         chk++-- | The 'Message' type is used to identify all the valid messages that can be+-- sent between bitcoin peers. Only values of type 'Message' will be accepted+-- by other bitcoin peers as bitcoin protocol messages need to be correctly+-- serialized with message headers. Serializing a 'Message' value will+-- include the 'MessageHeader' with the correct checksum value automatically.+-- No need to add the 'MessageHeader' separately.+data Message+    = MVersion !Version+    | MVerAck+    | MAddr !Addr+    | MInv !Inv+    | MGetData !GetData+    | MNotFound !NotFound+    | MGetBlocks !GetBlocks+    | MGetHeaders !GetHeaders+    | MTx !Tx+    | MBlock !Block+    | MMerkleBlock !MerkleBlock+    | MHeaders !Headers+    | MGetAddr+    | MFilterLoad !FilterLoad+    | MFilterAdd !FilterAdd+    | MFilterClear+    | MPing !Ping+    | MPong !Pong+    | MAlert !Alert+    | MMempool+    | MReject !Reject+    deriving (Eq, Show)++instance Binary Message where++    get = do+        (MessageHeader mgc cmd len chk) <- get+        bs <- lookAhead $ getByteString $ fromIntegral len+        unless (mgc == networkMagic)+            (fail $ "get: Invalid network magic bytes: " ++ (show mgc))+        unless (checkSum32 bs == chk)+            (fail $ "get: Invalid message checksum: " ++ (show chk))+        if len > 0+            then isolate (fromIntegral len) $ case cmd of+                MCVersion     -> MVersion <$> get+                MCAddr        -> MAddr <$> get+                MCInv         -> MInv <$> get+                MCGetData     -> MGetData <$> get+                MCNotFound    -> MNotFound <$> get+                MCGetBlocks   -> MGetBlocks <$> get+                MCGetHeaders  -> MGetHeaders <$> get+                MCTx          -> MTx <$> get+                MCBlock       -> MBlock <$> get+                MCMerkleBlock -> MMerkleBlock <$> get+                MCHeaders     -> MHeaders <$> get+                MCFilterLoad  -> MFilterLoad <$> get+                MCFilterAdd   -> MFilterAdd <$> get+                MCPing        -> MPing <$> get+                MCPong        -> MPong <$> get+                MCAlert       -> MAlert <$> get+                MCReject      -> MReject <$> get+                _             -> fail $ "get: Invalid command " ++ (show cmd)+            else case cmd of+                MCGetAddr     -> return MGetAddr+                MCVerAck      -> return MVerAck+                MCFilterClear -> return MFilterClear+                MCMempool     -> return MMempool+                _             -> fail $ "get: Invalid command " ++ (show cmd)++    put msg = do+        let (cmd, payload) = case msg of+                MVersion m     -> (MCVersion, encode' m)+                MVerAck        -> (MCVerAck, BS.empty)+                MAddr m        -> (MCAddr, encode' m)+                MInv m         -> (MCInv, encode' m)+                MGetData m     -> (MCGetData, encode' m)+                MNotFound m    -> (MCNotFound, encode' m)+                MGetBlocks m   -> (MCGetBlocks, encode' m)+                MGetHeaders m  -> (MCGetHeaders, encode' m)+                MTx m          -> (MCTx, encode' m)+                MBlock m       -> (MCBlock, encode' m)+                MMerkleBlock m -> (MCMerkleBlock, encode' m)+                MHeaders m     -> (MCHeaders, encode' m)+                MGetAddr       -> (MCGetAddr, BS.empty)+                MFilterLoad m  -> (MCFilterLoad, encode' m)+                MFilterAdd m   -> (MCFilterAdd, encode' m)+                MFilterClear   -> (MCFilterClear, BS.empty)+                MPing m        -> (MCPing, encode' m)+                MPong m        -> (MCPong, encode' m)+                MAlert m       -> (MCAlert, encode' m)+                MMempool       -> (MCMempool, BS.empty)+                MReject m      -> (MCReject, encode' m)+            chk = checkSum32 payload+            len = fromIntegral $ BS.length payload+            header = MessageHeader networkMagic cmd len chk+        putByteString $ (encode' header) `BS.append` payload+
+ Network/Haskoin/Node/Types.hs view
@@ -0,0 +1,599 @@+module Network.Haskoin.Node.Types+( Addr(..)+, NetworkAddressTime+, Alert(..)+, GetData(..)+, Inv(..)+, InvVector(..)+, InvType(..)+, NetworkAddress(..)+, NotFound(..)+, Ping(..)+, Pong(..)+, Reject(..)+, RejectCode(..)+, reject+, VarInt(..)+, VarString(..)+, Version(..)+, MessageCommand(..)+) where++import Control.DeepSeq (NFData, rnf)+import Control.Monad (replicateM, liftM2, forM_, unless)++import Data.Word (Word32, Word64)+import Data.Binary (Binary, get, put)+import Data.Binary.Get+    ( Get+    , getWord8+    , getWord16le+    , getWord16be+    , getWord32be+    , getWord32host+    , getWord32le+    , getWord64le+    , getByteString+    , isEmpty+    )+import Data.Binary.Put+    ( Put+    , putWord8+    , putWord16le+    , putWord16be+    , putWord32be+    , putWord32host+    , putWord32le+    , putWord64le+    , putByteString+    )+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+    ( length+    , takeWhile+    , empty+    , null+    , take+    )+import Data.ByteString.Char8 as C (replicate)+import Data.String.Conversions (cs)+import Network.Socket (SockAddr (SockAddrInet, SockAddrInet6))++import Network.Haskoin.Crypto.Hash++-- | Network address with a timestamp+type NetworkAddressTime = (Word32, NetworkAddress)++-- | Provides information on known nodes in the bitcoin network. An 'Addr'+-- type is sent inside a 'Message' as a response to a 'GetAddr' message.+data Addr =+    Addr {+           -- List of addresses of other nodes on the network with timestamps.+           addrList :: ![NetworkAddressTime]+         }+    deriving (Eq, Show)++instance Binary Addr where++    get = Addr <$> (repList =<< get)+      where+        repList (VarInt c) = replicateM (fromIntegral c) action+        action             = liftM2 (,) getWord32le get++    put (Addr xs) = do+        put $ VarInt $ fromIntegral $ length xs+        forM_ xs $ \(a,b) -> putWord32le a >> put b++-- | Data type describing signed messages that can be sent between bitcoin+-- nodes to display important notifications to end users about the health of+-- the network.+data Alert =+    Alert {+          -- | Alert payload.+            alertPayload   :: !VarString+          -- | ECDSA signature of the payload+          , alertSignature :: !VarString+          } deriving (Eq, Show, Read)++instance NFData Alert where+    rnf (Alert p s) = rnf p `seq` rnf s++instance Binary Alert where+    get = Alert <$> get <*> get+    put (Alert p s) = put p >> put s++-- | The 'GetData' type is used to retrieve information on a specific object+-- ('Block' or 'Tx') identified by the objects hash. The payload of a 'GetData'+-- request is a list of 'InvVector' which represent all the hashes for which a+-- node wants to request information. The response to a 'GetBlock' message+-- wille be either a 'Block' or a 'Tx' message depending on the type of the+-- object referenced by the hash. Usually, 'GetData' messages are sent after a+-- node receives an 'Inv' message to obtain information on unknown object+-- hashes.+data GetData =+    GetData {+              -- | List of object hashes+              getDataList :: ![InvVector]+            } deriving (Eq, Show, Read)++instance NFData GetData where+    rnf (GetData l) = rnf l++instance Binary GetData where++    get = GetData <$> (repList =<< get)+      where+        repList (VarInt c) = replicateM (fromIntegral c) get++    put (GetData xs) = do+        put $ VarInt $ fromIntegral $ length xs+        forM_ xs put++-- | 'Inv' messages are used by nodes to advertise their knowledge of new+-- objects by publishing a list of hashes. 'Inv' messages can be sent+-- unsolicited or in response to a 'GetBlocks' message.+data Inv =+    Inv {+        -- | Inventory vectors+          invList :: ![InvVector]+        } deriving (Eq, Show, Read)++instance NFData Inv where+    rnf (Inv l) = rnf l++instance Binary Inv where++    get = Inv <$> (repList =<< get)+      where+        repList (VarInt c) = replicateM (fromIntegral c) get++    put (Inv xs) = do+        put $ VarInt $ fromIntegral $ length xs+        forM_ xs put++-- | Data type identifying the type of an inventory vector.+data InvType+    = InvError -- ^ Error. Data containing this type can be ignored.+    | InvTx    -- ^ InvVector hash is related to a transaction+    | InvBlock -- ^ InvVector hash is related to a block+    | InvMerkleBlock -- ^ InvVector has is related to a merkle block+    deriving (Eq, Show, Read)++instance NFData InvType where rnf x = seq x ()++instance Binary InvType where++    get = go =<< getWord32le+      where+        go x = case x of+            0 -> return InvError+            1 -> return InvTx+            2 -> return InvBlock+            3 -> return InvMerkleBlock+            _ -> fail "bitcoinGet InvType: Invalid Type"++    put x = putWord32le $ case x of+                InvError       -> 0+                InvTx          -> 1+                InvBlock       -> 2+                InvMerkleBlock -> 3++-- | Invectory vectors represent hashes identifying objects such as a 'Block'+-- or a 'Tx'. They are sent inside messages to notify other peers about+-- new data or data they have requested.+data InvVector =+    InvVector {+                -- | Type of the object referenced by this inventory vector+                invType :: !InvType+                -- | Hash of the object referenced by this inventory vector+              , invHash :: !Hash256+              } deriving (Eq, Show, Read)++instance NFData InvVector where+    rnf (InvVector t h) = rnf t `seq` rnf h++instance Binary InvVector where+    get = InvVector <$> get <*> get+    put (InvVector t h) = put t >> put h++-- | Data type describing a bitcoin network address. Addresses are stored in+-- IPv6. IPv4 addresses are mapped to IPv6 using IPv4 mapped IPv6 addresses:+-- <http://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses>. Sometimes,+-- timestamps are sent together with the 'NetworkAddress' such as in the 'Addr'+-- data type.+data NetworkAddress =+    NetworkAddress {+                   -- | Bitmask of services available for this address+                     naServices :: !Word64+                   -- | IPv6 address and port+                   , naAddress  :: !SockAddr+                   } deriving (Eq, Show)++instance NFData NetworkAddress where+    rnf NetworkAddress{..} = rnf naServices `seq` naAddress `seq` ()++instance Binary NetworkAddress where++    get = NetworkAddress <$> getWord64le+                         <*> getAddrPort+      where+        getAddrPort = do+            a <- getWord32be+            b <- getWord32be+            c <- getWord32be+            if a == 0x00000000 && b == 0x00000000 && c == 0x0000ffff+              then do+                d <- getWord32host+                p <- getWord16be+                return $ SockAddrInet (fromIntegral p) d+              else do+                d <- getWord32be+                p <- getWord16be+                return $ SockAddrInet6 (fromIntegral p) 0 (a,b,c,d) 0++    put (NetworkAddress s (SockAddrInet6 p _ (a,b,c,d) _)) = do+        putWord64le s+        putWord32be a+        putWord32be b+        putWord32be c+        putWord32be d+        putWord16be (fromIntegral p)++    put (NetworkAddress s (SockAddrInet p a)) = do+        putWord64le s+        putWord32be 0x00000000+        putWord32be 0x00000000+        putWord32be 0x0000ffff+        putWord32host a+        putWord16be (fromIntegral p)++    put _ = error "NetworkAddress can onle be IPv4 or IPv6"++-- | A 'NotFound' message is returned as a response to a 'GetData' message+-- whe one of the requested objects could not be retrieved. This could happen,+-- for example, if a tranasaction was requested and was not available in the+-- memory pool of the receiving node.+data NotFound =+    NotFound {+             -- | Inventory vectors related to this request+               notFoundList :: ![InvVector]+             } deriving (Eq, Show, Read)++instance NFData NotFound where+    rnf (NotFound l) = rnf l++instance Binary NotFound where++    get = NotFound <$> (repList =<< get)+      where+        repList (VarInt c) = replicateM (fromIntegral c) get++    put (NotFound xs) = do+        put $ VarInt $ fromIntegral $ length xs+        forM_ xs put++-- | A Ping message is sent to bitcoin peers to check if a TCP\/IP connection+-- is still valid.+newtype Ping =+    Ping {+           -- | A random nonce used to identify the recipient of the ping+           -- request once a Pong response is received.+           pingNonce :: Word64+         } deriving (Eq, Show, Read)++instance NFData Ping where+    rnf (Ping n) = rnf n++-- | A Pong message is sent as a response to a ping message.+newtype Pong =+    Pong {+           -- | When responding to a Ping request, the nonce from the Ping+           -- is copied in the Pong response.+           pongNonce :: Word64+         } deriving (Eq, Show, Read)++instance NFData Pong where+    rnf (Pong n) = rnf n++instance Binary Ping where+    get = Ping <$> getWord64le+    put (Ping n) = putWord64le n++instance Binary Pong where+    get = Pong <$> getWord64le+    put (Pong n) = putWord64le n++-- | The reject message is sent when messages are rejected by a peer.+data Reject =+    Reject {+             -- | Type of message rejected+             rejectMessage :: !MessageCommand+             -- | Code related to the rejected message+           , rejectCode    :: !RejectCode+             -- | Text version of rejected reason+           , rejectReason  :: !VarString+             -- | Optional extra data provided by some errors+           , rejectData    :: !ByteString+           } deriving (Eq, Show, Read)+++data RejectCode+    = RejectMalformed+    | RejectInvalid+    | RejectObsolete+    | RejectDuplicate+    | RejectNonStandard+    | RejectDust+    | RejectInsufficientFee+    | RejectCheckpoint+    deriving (Eq, Show, Read)++instance Binary RejectCode where++    get = getWord8 >>= \code -> case code of+        0x01 -> return RejectMalformed+        0x10 -> return RejectInvalid+        0x11 -> return RejectObsolete+        0x12 -> return RejectDuplicate+        0x40 -> return RejectNonStandard+        0x41 -> return RejectDust+        0x42 -> return RejectInsufficientFee+        0x43 -> return RejectCheckpoint+        _    -> fail $ unwords+            [ "Reject get: Invalid code"+            , show code+            ]++    put code = putWord8 $ case code of+        RejectMalformed       -> 0x01+        RejectInvalid         -> 0x10+        RejectObsolete        -> 0x11+        RejectDuplicate       -> 0x12+        RejectNonStandard     -> 0x40+        RejectDust            -> 0x41+        RejectInsufficientFee -> 0x42+        RejectCheckpoint      -> 0x43++-- | Convenience function to build a Reject message+reject :: MessageCommand -> RejectCode -> ByteString -> Reject+reject cmd code reason =+    Reject cmd code (VarString reason) BS.empty++instance Binary Reject where++    get = get >>= \(VarString bs) -> case stringToCommand bs of+        Just cmd -> Reject cmd <$> get <*> get <*> maybeData+        _ -> fail $ unwords+            ["Reason get: Invalid message command" ,cs bs]+      where+        maybeData = isEmpty >>= \done ->+            if done then return BS.empty else getByteString 32++    put (Reject cmd code reason dat) = do+        put $ VarString $ commandToString cmd+        put code+        put reason+        unless (BS.null dat) $ putByteString dat++-- | Data type representing a variable length integer. The 'VarInt' type+-- usually precedes an array or a string that can vary in length.+newtype VarInt = VarInt { getVarInt :: Word64 }+    deriving (Eq, Show, Read)++instance NFData VarInt where+    rnf (VarInt w) = rnf w++instance Binary VarInt where++    get = VarInt <$> ( getWord8 >>= go )+      where+        go 0xff = getWord64le+        go 0xfe = fromIntegral <$> getWord32le+        go 0xfd = fromIntegral <$> getWord16le+        go x    = fromIntegral <$> return x++    put (VarInt x)+        | x < 0xfd =+            putWord8 $ fromIntegral x+        | x <= 0xffff = do+            putWord8 0xfd+            putWord16le $ fromIntegral x+        | x <= 0xffffffff = do+            putWord8 0xfe+            putWord32le $ fromIntegral x+        | otherwise = do+            putWord8 0xff+            putWord64le x++-- | Data type for variable length strings. Variable length strings are+-- serialized as a 'VarInt' followed by a bytestring.+newtype VarString = VarString { getVarString :: ByteString }+    deriving (Eq, Show, Read)++instance NFData VarString where+    rnf (VarString s) = rnf s++instance Binary VarString where++    get = VarString <$> (readBS =<< get)+      where+        readBS (VarInt len) = getByteString (fromIntegral len)++    put (VarString bs) = do+        put $ VarInt $ fromIntegral $ BS.length bs+        putByteString bs++-- | When a bitcoin node creates an outgoing connection to another node,+-- the first message it will send is a 'Version' message. The other node+-- will similarly respond with it's own 'Version' message.+data Version =+    Version {+              -- | Protocol version being used by the node.+              version     :: !Word32+              -- | Bitmask of features to enable for this connection.+            , services    :: !Word64+              -- | UNIX timestamp+            , timestamp   :: !Word64+              -- | Network address of the node receiving this message.+            , addrRecv    :: !NetworkAddress+              -- | Network address of the node sending this message.+            , addrSend    :: !NetworkAddress+              -- | Randomly generated identifying sent with every version+              -- message. This nonce is used to detect connection to self.+            , verNonce    :: !Word64+              -- | User agent+            , userAgent   :: !VarString+              -- | The height of the last block received by the sending node.+            , startHeight :: !Word32+              -- | Wether the remote peer should announce relaying transactions+              -- or not. This feature is enabled since version >= 70001. See+              -- BIP37 for more details.+            , relay       :: !Bool+            } deriving (Eq, Show)++instance NFData Version where+    rnf Version{..} =+        rnf version `seq`+        rnf services `seq`+        rnf timestamp `seq`+        rnf addrRecv `seq`+        rnf addrSend `seq`+        rnf verNonce `seq`+        rnf userAgent `seq`+        rnf startHeight `seq`+        rnf relay++instance Binary Version where++    get = Version <$> getWord32le+                  <*> getWord64le+                  <*> getWord64le+                  <*> get+                  <*> get+                  <*> getWord64le+                  <*> get+                  <*> getWord32le+                  <*> (go =<< isEmpty)+      where+        go True  = return True+        go False = getBool++    put (Version v s t ar as n ua sh r) = do+        putWord32le v+        putWord64le s+        putWord64le t+        put         ar+        put         as+        putWord64le n+        put         ua+        putWord32le sh+        putBool     r++getBool :: Get Bool+getBool = go =<< getWord8+  where+    go 0 = return False+    go _ = return True++putBool :: Bool -> Put+putBool True  = putWord8 1+putBool False = putWord8 0++-- | A 'MessageCommand' is included in a 'MessageHeader' in order to identify+-- the type of message present in the payload. This allows the message+-- de-serialization code to know how to decode a particular message payload.+-- Every valid 'Message' constructor has a corresponding 'MessageCommand'+-- constructor.+data MessageCommand+    = MCVersion+    | MCVerAck+    | MCAddr+    | MCInv+    | MCGetData+    | MCNotFound+    | MCGetBlocks+    | MCGetHeaders+    | MCTx+    | MCBlock+    | MCMerkleBlock+    | MCHeaders+    | MCGetAddr+    | MCFilterLoad+    | MCFilterAdd+    | MCFilterClear+    | MCPing+    | MCPong+    | MCAlert+    | MCMempool+    | MCReject+    deriving (Eq, Show, Read)++instance NFData MessageCommand where rnf x = seq x ()++instance Binary MessageCommand where++    get = go =<< getByteString 12+      where+        go bs = case stringToCommand $ unpackCommand bs of+            Just cmd -> return cmd+            Nothing  -> fail "get MessageCommand : Invalid command"++    put mc = putByteString $ packCommand $ commandToString mc+++stringToCommand :: ByteString -> Maybe MessageCommand+stringToCommand str = case str of+    "version"     -> Just MCVersion+    "verack"      -> Just MCVerAck+    "addr"        -> Just MCAddr+    "inv"         -> Just MCInv+    "getdata"     -> Just MCGetData+    "notfound"    -> Just MCNotFound+    "getblocks"   -> Just MCGetBlocks+    "getheaders"  -> Just MCGetHeaders+    "tx"          -> Just MCTx+    "block"       -> Just MCBlock+    "merkleblock" -> Just MCMerkleBlock+    "headers"     -> Just MCHeaders+    "getaddr"     -> Just MCGetAddr+    "filterload"  -> Just MCFilterLoad+    "filteradd"   -> Just MCFilterAdd+    "filterclear" -> Just MCFilterClear+    "ping"        -> Just MCPing+    "pong"        -> Just MCPong+    "alert"       -> Just MCAlert+    "mempool"     -> Just MCMempool+    "reject"      -> Just MCReject+    _             -> Nothing++commandToString :: MessageCommand -> ByteString+commandToString mc = case mc of+    MCVersion     -> "version"+    MCVerAck      -> "verack"+    MCAddr        -> "addr"+    MCInv         -> "inv"+    MCGetData     -> "getdata"+    MCNotFound    -> "notfound"+    MCGetBlocks   -> "getblocks"+    MCGetHeaders  -> "getheaders"+    MCTx          -> "tx"+    MCBlock       -> "block"+    MCMerkleBlock -> "merkleblock"+    MCHeaders     -> "headers"+    MCGetAddr     -> "getaddr"+    MCFilterLoad  -> "filterload"+    MCFilterAdd   -> "filteradd"+    MCFilterClear -> "filterclear"+    MCPing        -> "ping"+    MCPong        -> "pong"+    MCAlert       -> "alert"+    MCMempool     -> "mempool"+    MCReject      -> "reject"++packCommand :: ByteString -> ByteString+packCommand s = BS.take 12 $+    s `mappend` C.replicate 12 '\NUL'++unpackCommand :: ByteString -> ByteString+unpackCommand = BS.takeWhile (/= 0)+
+ Network/Haskoin/Script.hs view
@@ -0,0 +1,73 @@+{-|+  This package provides functions for parsing and evaluating bitcoin+  transaction scripts. Data types are provided for building and+  deconstructing all of the standard input and output script types.+-}+module Network.Haskoin.Script+(+  -- *Scripts+  -- | More informations on scripts is available here:+  -- <http://en.bitcoin.it/wiki/Script>+  Script(..)+, ScriptOp(..)+, PushDataType(..)+, opPushData++  -- *Script Parsing+  -- **Script Outputs+, ScriptOutput(..)+, encodeOutput+, encodeOutputBS+, decodeOutput+, decodeOutputBS+, isPayPK+, isPayPKHash+, isPayMulSig+, isPayScriptHash+, scriptAddr+, sortMulSig++  -- **Script Inputs+, ScriptInput(..)+, SimpleInput(..)+, RedeemScript+, encodeInput+, encodeInputBS+, decodeInput+, decodeInputBS+, isSpendPK+, isSpendPKHash+, isSpendMulSig+, isScriptHashInput++  -- * Helpers+, scriptRecipient+, scriptSender+, intToScriptOp+, scriptOpToInt++-- *SigHash+-- | For additional information on sighashes, see:+-- <http://en.bitcoin.it/wiki/OP_CHECKSIG>+, SigHash(..)+, txSigHash+, encodeSigHash32+, isSigAll+, isSigNone+, isSigSingle+, isSigUnknown+, TxSignature(..)+, encodeSig+, decodeSig+, decodeCanonicalSig++-- *Evaluation+, evalScript+, verifySpend+, SigCheck+) where++import Network.Haskoin.Script.Types+import Network.Haskoin.Script.Parser+import Network.Haskoin.Script.SigHash+import Network.Haskoin.Script.Evaluator
+ Network/Haskoin/Script/Evaluator.hs view
@@ -0,0 +1,778 @@+{-# LANGUAGE LambdaCase #-}+{-|++Module providing Bitcoin script evaluation.  See+<https://github.com/bitcoin/bitcoin/blob/master/src/script.cpp>+EvalScript and <https://en.bitcoin.it/wiki/Script>++-}+module Network.Haskoin.Script.Evaluator+(+-- * Script evaluation+  verifySpend+, evalScript+, SigCheck+, Flag+-- * Evaluation data types+, ProgramData+, Stack+-- * Helper functions+, encodeInt+, decodeInt+, encodeBool+, decodeBool+, runStack+, checkStack+, dumpScript+, dumpStack+, execScript+) where++import Control.Monad.State+import Control.Monad.Reader+import Control.Monad.Except+import Control.Monad.Identity++import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BSL+import Data.String.Conversions (cs)++import Data.Bits (shiftR, shiftL, testBit, setBit, clearBit, (.&.))+import Data.Int (Int64)+import Data.Word (Word8, Word64)+import Data.Either (rights)+import Data.Maybe (mapMaybe, isJust)++import Network.Haskoin.Crypto+import Network.Haskoin.Script.Types+import Network.Haskoin.Script.SigHash+import Network.Haskoin.Util+import Network.Haskoin.Transaction.Types++import Data.Binary (encode, decodeOrFail)+++maxScriptSize :: Int+maxScriptSize = 10000++maxScriptElementSize :: Int+maxScriptElementSize = 520++maxStackSize :: Int+maxStackSize = 1000++maxOpcodes :: Int+maxOpcodes = 200++maxKeysMultisig :: Int+maxKeysMultisig = 20++data Flag = P2SH+          | STRICTENC+          | DERSIG+          | LOW_S+          | NULLDUMMY+          | SIGPUSHONLY+          | MINIMALDATA+          | DISCOURAGE_UPGRADABLE_NOPS+     deriving ( Show, Read, Eq )++type FlagSet = [ Flag ]++data EvalError =+    EvalError String+    | ProgramError String ProgramData+    | StackError ScriptOp+    | DisabledOp ScriptOp++instance Show EvalError where+    show (EvalError m) = m+    show (ProgramError m prog) = m ++ " - ProgramData: " ++ show prog+    show (StackError op) = show op ++ ": Stack Error"+    show (DisabledOp op) = show op ++ ": disabled"++type StackValue = [Word8]+type AltStack = [StackValue]+type Stack = [StackValue]+type HashOps = [ScriptOp] -- the code that is verified by OP_CHECKSIG++-- | Defines the type of function required by script evaluating+-- functions to check transaction signatures.+type SigCheck = [ScriptOp] -> TxSignature -> PubKey -> Bool++-- | Data type of the evaluation state.+data ProgramData = ProgramData {+    stack        :: Stack,+    altStack     :: AltStack,+    hashOps      :: HashOps,+    sigCheck     :: SigCheck,+    opCount      :: Int+}++dumpOp :: ScriptOp -> ByteString+dumpOp (OP_PUSHDATA payload optype) = mconcat+  [ "OP_PUSHDATA(", cs (show optype), ")", " 0x", encodeHex payload ]+dumpOp op = cs $ show op++dumpList :: [ByteString] -> ByteString+dumpList xs = mconcat [ "[", BS.intercalate "," xs, "]" ]++dumpScript :: [ScriptOp] -> ByteString+dumpScript script = dumpList $ map dumpOp script++dumpStack :: Stack -> ByteString+dumpStack s = dumpList $ map (encodeHex . BS.pack) s++-- TODO: Test+instance Show ProgramData where+    show p = "stack: " ++ (cs $ dumpStack $ stack p)++type ProgramState = ExceptT EvalError Identity+type IfStack = [Bool]++-- | Monad of actions independent of conditional statements.+type StackOperation = ReaderT FlagSet ( StateT ProgramData ProgramState )+-- | Monad of actions which taking if statements into account.+-- Separate state type from StackOperation for type safety+type Program a = StateT IfStack StackOperation a++evalStackOperation :: StackOperation a -> ProgramData -> FlagSet -> Either EvalError a+evalStackOperation m s f = runIdentity . runExceptT $ evalStateT ( runReaderT m f ) s++evalProgram :: Program a                      -- ^ ProgramData monad+            -> [ Bool ]                       -- ^ Initial if state stack+            -> ProgramData                    -- ^ Initial computation data+            -> FlagSet                        -- ^ Evaluation Flags+            -> Either EvalError a+evalProgram m s = evalStackOperation ( evalStateT m s )++--------------------------------------------------------------------------------+-- Error utils++programError :: String -> StackOperation a+programError s = get >>= throwError . ProgramError s++disabled :: ScriptOp -> StackOperation ()+disabled op = throwError . DisabledOp $ op++--------------------------------------------------------------------------------+-- Type Conversions++-- | Encoding function for the stack value format of integers.  Most+-- significant bit defines sign.+encodeInt :: Int64 -> StackValue+encodeInt i = prefix $ encod (fromIntegral $ abs i) []+    where encod :: Word64 -> StackValue -> StackValue+          encod 0 bytes = bytes+          encod j bytes = fromIntegral j:encod (j `shiftR` 8) bytes+          prefix :: StackValue -> StackValue+          prefix [] = []+          prefix xs | testBit (last xs) 7 = prefix $ xs ++ [0]+                    | i < 0 = init xs ++ [setBit (last xs) 7]+                    | otherwise = xs++-- | Inverse of `encodeInt`.+decodeInt :: StackValue -> Maybe Int64+decodeInt bytes | length bytes > 4 = Nothing+                | otherwise = Just $ sign' (decodeW bytes)+                  where decodeW [] = 0+                        decodeW [x] = fromIntegral $ clearBit x 7+                        decodeW (x:xs) = fromIntegral x + decodeW xs `shiftL` 8+                        sign' i | null bytes = 0+                                | testBit (last bytes) 7 = -i+                                | otherwise = i++-- | Conversion of StackValue to Bool (true if non-zero).+decodeBool :: StackValue -> Bool+decodeBool []     = False+decodeBool [0x00] = False+decodeBool [0x80] = False+decodeBool (0x00:vs) = decodeBool vs+decodeBool _ = True++encodeBool :: Bool -> StackValue+encodeBool True = [1]+encodeBool False = []++constValue :: ScriptOp -> Maybe StackValue+constValue op = case op of+    OP_0  -> Just $ encodeInt 0+    OP_1  -> Just $ encodeInt 1+    OP_2  -> Just $ encodeInt 2+    OP_3  -> Just $ encodeInt 3+    OP_4  -> Just $ encodeInt 4+    OP_5  -> Just $ encodeInt 5+    OP_6  -> Just $ encodeInt 6+    OP_7  -> Just $ encodeInt 7+    OP_8  -> Just $ encodeInt 8+    OP_9  -> Just $ encodeInt 9+    OP_10 -> Just $ encodeInt 10+    OP_11 -> Just $ encodeInt 11+    OP_12 -> Just $ encodeInt 12+    OP_13 -> Just $ encodeInt 13+    OP_14 -> Just $ encodeInt 14+    OP_15 -> Just $ encodeInt 15+    OP_16 -> Just $ encodeInt 16+    OP_1NEGATE -> Just $ encodeInt $ -1+    (OP_PUSHDATA string _) -> Just $ BS.unpack string+    _ -> Nothing+++-- | Check if OpCode is constant+isConstant :: ScriptOp -> Bool+isConstant = isJust . constValue++-- | Check if OpCode is disabled+isDisabled :: ScriptOp -> Bool+isDisabled op = op `elem` [ OP_CAT+                          , OP_SUBSTR+                          , OP_LEFT+                          , OP_RIGHT+                          , OP_INVERT+                          , OP_AND+                          , OP_OR+                          , OP_XOR+                          , OP_2MUL+                          , OP_2DIV+                          , OP_MUL+                          , OP_DIV+                          , OP_MOD+                          , OP_LSHIFT+                          , OP_RSHIFT+                          , OP_VER+                          , OP_VERIF+                          , OP_VERNOTIF ]++-- | Check if OpCode counts towards opcount limit++countOp :: ScriptOp -> Bool+countOp op | isConstant op     = False+           | op == OP_RESERVED = False+           | otherwise         = True++popInt :: StackOperation Int64+popInt = minimalStackValEnforcer >> decodeInt <$> popStack >>= \case+    Nothing -> programError "popInt: data > nMaxNumSize"+    Just i -> return i++pushInt :: Int64 -> StackOperation ()+pushInt = pushStack . encodeInt++popBool :: StackOperation Bool+popBool = decodeBool <$> popStack++pushBool :: Bool -> StackOperation ()+pushBool = pushStack . encodeBool++opToSv :: StackValue -> BS.ByteString+opToSv = BS.pack++bsToSv :: BS.ByteString -> StackValue+bsToSv = BS.unpack++--------------------------------------------------------------------------------+-- Stack Primitives++getStack :: StackOperation Stack+getStack = stack <$> get++getCond :: Program [Bool]+getCond = get++popCond :: Program Bool+popCond = get >>= \condStack -> case condStack of+    [] -> lift $ programError "popCond: empty condStack"+    (x:xs) -> put xs >> return x++pushCond :: Bool -> Program ()+pushCond c = get >>= \s ->+    put (c:s)++flipCond :: Program ()+flipCond = popCond >>= pushCond . not++withStack :: StackOperation Stack+withStack = getStack >>= \case+    [] -> stackError+    s  -> return s++putStack :: Stack -> StackOperation ()+putStack st = modify $ \p -> p { stack = st }++prependStack :: Stack -> StackOperation ()+prependStack s = getStack >>= \s' -> putStack $ s ++ s'++checkPushData :: ScriptOp -> StackOperation ()+checkPushData (OP_PUSHDATA v _) | BS.length v > fromIntegral maxScriptElementSize+                                  = programError "OP_PUSHDATA > maxScriptElementSize"+                                | otherwise = return ()+checkPushData _ = return ()++checkStackSize :: StackOperation ()+checkStackSize = do n <- length <$> stack <$> get+                    m <- length <$> altStack <$> get+                    when ((n + m) > fromIntegral maxStackSize) $+                         programError "stack > maxStackSize"++pushStack :: StackValue -> StackOperation ()+pushStack v = getStack >>= \s -> putStack (v:s)++popStack :: StackOperation StackValue+popStack = withStack >>= \(s:ss) -> putStack ss >> return s++popStackN :: Integer -> StackOperation [StackValue]+popStackN n | n < 0     = programError "popStackN: negative argument"+            | n == 0    = return []+            | otherwise = (:) <$> popStack <*> popStackN (n - 1)++pickStack :: Bool -> Int -> StackOperation ()+pickStack remove n = do+    st <- getStack++    when (n < 0) $+        programError "pickStack: n < 0"+    when (n > length st - 1) $+        programError "pickStack: n > size"++    let v = st !! n+    when remove $ putStack $ take n st ++ drop (n+1) st+    pushStack v++getHashOps :: StackOperation HashOps+getHashOps = hashOps <$> get++-- | Function to track the verified OPs signed by OP_CHECK(MULTI) sig.+-- Dependent on the sequence of `OP_CODESEPARATOR`+dropHashOpsSeparatedCode :: StackOperation ()+dropHashOpsSeparatedCode = modify $ \p ->+   let tryDrop = dropWhile ( /= OP_CODESEPARATOR ) $ hashOps p in+   case tryDrop of+     -- If no OP_CODESEPARATOR, take the whole script.  This case is+     -- possible when there is no OP_CODESEPARATOR in scriptPubKey but+     -- one exists in scriptSig+     [] -> p+     _  -> p { hashOps = tail tryDrop }++-- | Filters out `OP_CODESEPARATOR` from the output script used by+-- OP_CHECK(MULTI)SIG+preparedHashOps :: StackOperation HashOps+preparedHashOps = filter ( /= OP_CODESEPARATOR ) <$> getHashOps++-- | Removes any PUSHDATA that contains the signatures.  Used in+-- CHECK(MULTI)SIG so that signatures can be contained in output+-- scripts.  See FindAndDelete() in Bitcoin Core.+findAndDelete :: [ StackValue ] -> [ ScriptOp ] -> [ ScriptOp ]+findAndDelete [] ops = ops+findAndDelete (s:ss) ops = let pushOp = opPushData . opToSv $ s in+  findAndDelete ss $ filter ( /= pushOp ) ops++checkMultiSig :: SigCheck -- ^ Signature checking function+              -> [ StackValue ] -- ^ PubKeys+              -> [ StackValue ] -- ^ Signatures+              -> [ ScriptOp ]   -- ^ CODESEPARATOR'd hashops+              -> Bool+checkMultiSig f encPubKeys encSigs hOps =+  let pubKeys = mapMaybe ( decodeToMaybe . opToSv ) encPubKeys+      sigs = rights $ map ( decodeSig . opToSv ) encSigs+      cleanHashOps = findAndDelete encSigs hOps+  in (length sigs == length encSigs) && -- check for bad signatures+     orderedSatisfy (f cleanHashOps) sigs pubKeys++-- | Tests whether a function is satisfied for every a with some b "in+-- order".  By "in order" we mean, if a pair satisfies the function,+-- any other satisfying pair must be deeper in each list.  Designed to+-- return as soon as the result is known to minimize expensive+-- function calls.  Used in checkMultiSig to verify signature/pubKey+-- pairs with a values as signatures and b values as pubkeys+orderedSatisfy :: ( a -> b -> Bool )+                    -> [ a ]+                    -> [ b ]+                    -> Bool+orderedSatisfy _ [] _ = True+orderedSatisfy _ (_:_) [] = False+orderedSatisfy f x@(a:as) y@(b:bs) | length x > length y = False+                                   | f a b     = orderedSatisfy f as bs+                                   | otherwise = orderedSatisfy f x bs++tStack1 :: (StackValue -> Stack) -> StackOperation ()+tStack1 f = f <$> popStack >>= prependStack++tStack2 :: (StackValue -> StackValue -> Stack) -> StackOperation ()+tStack2 f = f <$> popStack <*> popStack >>= prependStack++tStack3 :: (StackValue -> StackValue -> StackValue -> Stack) -> StackOperation ()+tStack3 f = f <$> popStack <*> popStack <*> popStack >>= prependStack++tStack4 :: (StackValue -> StackValue -> StackValue -> StackValue -> Stack)+            -> StackOperation ()+tStack4 f = f <$> popStack <*> popStack <*> popStack <*> popStack+              >>= prependStack++tStack6 :: (StackValue -> StackValue -> StackValue ->+            StackValue -> StackValue -> StackValue -> Stack) -> StackOperation ()+tStack6 f = f <$> popStack <*> popStack <*> popStack+              <*> popStack <*> popStack <*> popStack >>= prependStack++arith1 :: (Int64 -> Int64) -> StackOperation ()+arith1 f = do+    i <- popInt+    pushStack $ encodeInt (f i)++arith2 :: (Int64 -> Int64 -> Int64) -> StackOperation ()+arith2 f = do+    i <- popInt+    j <- popInt+    pushStack $ encodeInt (f i j)++stackError :: StackOperation a+stackError = programError "stack error"++-- AltStack Primitives++pushAltStack :: StackValue -> StackOperation ()+pushAltStack op = modify $ \p -> p { altStack = op:altStack p }++popAltStack :: StackOperation StackValue+popAltStack = get >>= \p -> case altStack p of+    a:as -> put p { altStack = as } >> return a+    []   -> programError "popAltStack: empty stack"+++incrementOpCount :: Int -> StackOperation ()+incrementOpCount i | i > maxOpcodes = programError "reached opcode limit"+                   | otherwise      = modify $ \p -> p { opCount = i + 1 }++nopDiscourager :: StackOperation ()+nopDiscourager = do+    flgs <- ask+    if DISCOURAGE_UPGRADABLE_NOPS `elem` flgs+        then programError "Discouraged OP used."+        else return ()++-- Instruction Evaluation+eval :: ScriptOp -> StackOperation ()+eval OP_NOP     = return ()+eval OP_NOP1    = nopDiscourager >> return ()+eval OP_NOP2    = nopDiscourager >> return ()+eval OP_NOP3    = nopDiscourager >> return ()+eval OP_NOP4    = nopDiscourager >> return ()+eval OP_NOP5    = nopDiscourager >> return ()+eval OP_NOP6    = nopDiscourager >> return ()+eval OP_NOP7    = nopDiscourager >> return ()+eval OP_NOP8    = nopDiscourager >> return ()+eval OP_NOP9    = nopDiscourager >> return ()+eval OP_NOP10   = nopDiscourager >> return ()++eval OP_VERIFY = popBool >>= \case+    True  -> return ()+    False -> programError "OP_VERIFY failed"++eval OP_RETURN = programError "explicit OP_RETURN"++-- Stack++eval OP_TOALTSTACK = popStack >>= pushAltStack+eval OP_FROMALTSTACK = popAltStack >>= pushStack+eval OP_IFDUP   = tStack1 $ \a -> if decodeBool a then [a, a] else [a]+eval OP_DEPTH   = getStack >>= pushStack . encodeInt . fromIntegral . length+eval OP_DROP    = void popStack+eval OP_DUP     = tStack1 $ \a -> [a, a]+eval OP_NIP     = tStack2 $ \a _ -> [a]+eval OP_OVER    = tStack2 $ \a b -> [b, a, b]+eval OP_PICK    = popInt >>= (pickStack False . fromIntegral)+eval OP_ROLL    = popInt >>= (pickStack True . fromIntegral)+eval OP_ROT     = tStack3 $ \a b c -> [c, a, b]+eval OP_SWAP    = tStack2 $ \a b -> [b, a]+eval OP_TUCK    = tStack2 $ \a b -> [a, b, a]+eval OP_2DROP   = tStack2 $ \_ _ -> []+eval OP_2DUP    = tStack2 $ \a b -> [a, b, a, b]+eval OP_3DUP    = tStack3 $ \a b c -> [a, b, c, a, b, c]+eval OP_2OVER   = tStack4 $ \a b c d -> [c, d, a, b, c, d]+eval OP_2ROT    = tStack6 $ \a b c d e f -> [e, f, a, b, c, d]+eval OP_2SWAP   = tStack4 $ \a b c d -> [c, d, a, b]++-- Splice++eval OP_SIZE   = (fromIntegral . length <$> head <$> withStack) >>= pushInt++-- Bitwise Logic++eval OP_EQUAL   = tStack2 $ \a b -> [encodeBool (a == b)]+eval OP_EQUALVERIFY = eval OP_EQUAL >> eval OP_VERIFY++-- Arithmetic++eval OP_1ADD    = arith1 (+1)+eval OP_1SUB    = arith1 (subtract 1)+eval OP_NEGATE  = arith1 negate+eval OP_ABS     = arith1 abs+eval OP_NOT         = arith1 $ \case 0 -> 1; _ -> 0+eval OP_0NOTEQUAL   = arith1 $ \case 0 -> 0; _ -> 1+eval OP_ADD     = arith2 (+)+eval OP_SUB     = arith2 $ flip (-)+eval OP_BOOLAND     = (&&) <$> ((0 /=) <$> popInt)+                           <*> ((0 /=) <$> popInt) >>= pushBool+eval OP_BOOLOR      = (||) <$> ((0 /=) <$> popInt)+                           <*> ((0 /=) <$> popInt) >>= pushBool+eval OP_NUMEQUAL    = (==) <$> popInt <*> popInt >>= pushBool+eval OP_NUMEQUALVERIFY = eval OP_NUMEQUAL >> eval OP_VERIFY+eval OP_NUMNOTEQUAL         = (/=) <$> popInt <*> popInt >>= pushBool+eval OP_LESSTHAN            = (>)  <$> popInt <*> popInt >>= pushBool+eval OP_GREATERTHAN         = (<)  <$> popInt <*> popInt >>= pushBool+eval OP_LESSTHANOREQUAL     = (>=) <$> popInt <*> popInt >>= pushBool+eval OP_GREATERTHANOREQUAL  = (<=) <$> popInt <*> popInt >>= pushBool+eval OP_MIN     = min <$> popInt <*> popInt >>= pushInt+eval OP_MAX     = max <$> popInt <*> popInt >>= pushInt+eval OP_WITHIN  = within <$> popInt <*> popInt <*> popInt >>= pushBool+                  where within y x a = (x <= a) && (a < y)++eval OP_RIPEMD160 = tStack1 $ return . bsToSv . getHash160 . hash160 . opToSv+eval OP_SHA1 = tStack1 $ return . bsToSv . getHash160 . sha1 . opToSv++eval OP_SHA256 = tStack1 $ return . bsToSv . getHash256 . hash256 . opToSv+eval OP_HASH160 = tStack1 $+    return . bsToSv . getHash160 . hash160 . getHash256 . hash256 . opToSv+eval OP_HASH256 = tStack1 $+    return . bsToSv . getHash256 . doubleHash256  . opToSv+eval OP_CODESEPARATOR = dropHashOpsSeparatedCode+eval OP_CHECKSIG = do+    pubKey <- popStack+    sig <- popStack+    checker <- sigCheck <$> get+    hOps <- preparedHashOps+    -- Reuse checkMultiSig code+    pushBool $ checkMultiSig checker [ pubKey ] [ sig ] hOps++eval OP_CHECKMULTISIG =+    do nPubKeys <- fromIntegral <$> popInt+       when (nPubKeys < 0 || nPubKeys > maxKeysMultisig)+            $ programError $ "nPubKeys outside range: " ++ show nPubKeys+       pubKeys <- popStackN $ toInteger nPubKeys++       nSigs <- fromIntegral <$> popInt+       when (nSigs < 0 || nSigs > nPubKeys)+            $ programError $ "nSigs outside range: " ++ show nSigs+       sigs <- popStackN $ toInteger nSigs++       nullDummyEnforcer+       void popStack -- spec bug+       checker <- sigCheck <$> get+       hOps <- preparedHashOps+       pushBool $ checkMultiSig checker pubKeys sigs hOps+       modify $ \p -> p { opCount = opCount p + length pubKeys }++eval OP_CHECKSIGVERIFY      = eval OP_CHECKSIG      >> eval OP_VERIFY+eval OP_CHECKMULTISIGVERIFY = eval OP_CHECKMULTISIG >> eval OP_VERIFY++eval op = case constValue op of+    Just sv -> minimalPushEnforcer op >> pushStack sv+    Nothing -> programError $ "unexpected op " ++ show op++minimalPushEnforcer :: ScriptOp -> StackOperation ()+minimalPushEnforcer op = do+    flgs <- ask+    if not $ MINIMALDATA `elem` flgs+        then return ()+        else case checkMinimalPush op of+            True -> return ()+            False -> programError $ "Non-minimal data: " ++ (show op)++checkMinimalPush :: ScriptOp -> Bool -- Putting in a maybe monad to avoid elif chain+checkMinimalPush ( OP_PUSHDATA payload optype ) =+  let l = BS.length payload+      v = ( BS.unpack payload ) !! 0 in+  if+     (BS.null payload)                     -- Check if could have used OP_0+     || (l == 1 && v <= 16 && v >= 1)   -- Could have used OP_{1,..,16}+     || (l == 1 && v == 0x81)           -- Could have used OP_1NEGATE+     || (l <= 75 && optype /= OPCODE)   -- Could have used direct push+     || (l <= 255 && l > 75 && optype /= OPDATA1)+     || (l > 255 && l <= 65535 && optype /= OPDATA2)+  then False else True+checkMinimalPush _ = True++-- | Checks the top of the stack for a minimal numeric representation+-- if flagged to do so+minimalStackValEnforcer :: StackOperation ()+minimalStackValEnforcer = do+    flgs <- ask+    s <- getStack+    let topStack = if null s then [] else head s+    if not $ MINIMALDATA `elem` flgs || null topStack+        then return ()+        else case checkMinimalNumRep topStack  of+            True -> return ()+            False -> programError $ "Non-minimal stack value: " ++ (show topStack)++-- | Checks if a stack value is the minimal numeric representation of+-- the integer to which it decoes.  Based on CScriptNum from Bitcoin+-- Core.+checkMinimalNumRep :: StackValue -> Bool+checkMinimalNumRep [] = True+checkMinimalNumRep s =+    let msb = last s+        l = length s in+    if+         -- If the MSB except sign bit is zero, then nonMinimal+         ( msb .&. 0x7f == 0 )+         -- With the exception of when a new byte is forced by a filled last bit+      && ( l <= 1 || ( s !! (l-2) ) .&. 0x80 == 0 )+    then False+    else True++nullDummyEnforcer :: StackOperation ()+nullDummyEnforcer = do+    flgs <- ask+    topStack <- ( getStack >>= headOrError )+    if ( NULLDUMMY `elem` flgs ) && ( not . null $ topStack )+        then programError $ "Non-null dummy stack in multi-sig"+        else return ()+    where+        headOrError s = if null s+          then programError "Empty stack where dummy op should be."+          else return ( head s )++--------------------------------------------------------------------------------+-- | Based on the IfStack, returns whether the script is within an+-- evaluating if-branch.+getExec :: Program Bool+getExec = and <$> getCond++-- | Converts a `ScriptOp` to a ProgramData monad.+conditionalEval :: ScriptOp -> Program ()+conditionalEval scrpOp = do+   -- lift $ checkOpEnabled scrpOp+   lift $ checkPushData scrpOp++   e  <- getExec+   eval' e scrpOp++   when (countOp scrpOp) $ lift $ join $ incrementOpCount <$> opCount <$> get++   lift checkStackSize++   where+     eval' :: Bool -> ScriptOp -> Program ()++     eval' True  OP_IF      = lift popStack >>= pushCond . decodeBool+     eval' True  OP_NOTIF   = lift popStack >>= pushCond . not . decodeBool+     eval' True  OP_ELSE    = flipCond+     eval' True  OP_ENDIF   = void popCond+     eval' True  op = lift $ eval op++     eval' False OP_IF    = pushCond False+     eval' False OP_NOTIF = pushCond False+     eval' False OP_ELSE  = flipCond+     eval' False OP_ENDIF = void popCond+     eval' False OP_CODESEPARATOR = lift $ eval OP_CODESEPARATOR+     eval' False OP_VER = return ()+     eval' False op | isDisabled op = lift $ disabled op+                    | otherwise = return ()++-- | Builds a Script evaluation monad.+evalOps :: [ ScriptOp ] -> Program ()+evalOps ops = do mapM_ conditionalEval ops+                 cond <- getCond+                 unless (null cond) (lift $ programError "ifStack not empty")+++checkPushOnly :: [ ScriptOp ] -> Program ()+checkPushOnly ops+      | not (all checkPushOp ops) = lift $ programError "only push ops allowed"+      | otherwise = return ()+      where checkPushOp op = case constValue op of+                                  Just _ -> True+                                  Nothing -> False++checkStack :: Stack -> Bool+checkStack (x:_) = decodeBool x+checkStack []  = False+++isPayToScriptHash :: [ ScriptOp ] -> [ Flag ]  -> Bool+isPayToScriptHash [OP_HASH160, OP_PUSHDATA bytes OPCODE, OP_EQUAL] flgs+                    = ( P2SH `elem` flgs ) && ( BS.length bytes == 20 )+isPayToScriptHash _ _ = False++stackToScriptOps :: StackValue -> [ ScriptOp ]+stackToScriptOps sv = let script = decodeOrFail $ BSL.pack sv in+  case script of+    Left _ -> []  -- Maybe should propogate the error some how+    Right (_,_,s) -> scriptOps s++--+-- exported functions++execScript :: Script -- ^ scriptSig ( redeemScript )+           -> Script -- ^ scriptPubKey+           -> SigCheck -- ^ signature verification Function+           -> [ Flag ] -- ^ Evaluation flags+           -> Either EvalError ProgramData+execScript scriptSig scriptPubKey sigCheckFcn flags =+  let sigOps = scriptOps scriptSig+      pubKeyOps = scriptOps scriptPubKey+      initData = ProgramData {+        stack = [],+        altStack = [],+        hashOps = pubKeyOps,+        sigCheck = sigCheckFcn,+        opCount = 0+      }+++      checkSig | isPayToScriptHash pubKeyOps flags = checkPushOnly sigOps+               | SIGPUSHONLY `elem` flags = checkPushOnly sigOps+               | otherwise = return ()++      checkKey | BSL.length (encode scriptPubKey) > fromIntegral maxScriptSize+                 = lift $ programError "pubKey > maxScriptSize"+               | otherwise = return ()+++      redeemEval = checkSig >> evalOps sigOps >> lift (stack <$> get)+      pubKeyEval = checkKey >> evalOps pubKeyOps >> lift get++      in do s <- evalProgram redeemEval [] initData flags+            p <- evalProgram pubKeyEval [] initData { stack = s } flags+            if ( not . null $ s )+                   && ( isPayToScriptHash pubKeyOps flags )+                   && ( checkStack . runStack $ p )+              then evalProgram (evalP2SH s) [] initData { stack = drop 1 s,+                      hashOps = stackToScriptOps $ head s } flags+              else return p+++-- | Evaluates a P2SH style script from its serialization in the stack+evalP2SH :: Stack -> Program ProgramData+evalP2SH [] = lift $ programError "PayToScriptHash: no script on stack"+evalP2SH (sv:_) = evalOps (stackToScriptOps sv) >> lift get++evalScript :: Script -> Script -> SigCheck -> [ Flag ] -> Bool+evalScript scriptSig scriptPubKey sigCheckFcn flags =+              case execScript scriptSig scriptPubKey sigCheckFcn flags of+                  Left _ -> False+                  Right p -> checkStack . runStack $ p++runStack :: ProgramData -> Stack+runStack = stack++-- | A wrapper around 'verifySig' which handles grabbing the hash type+verifySigWithType :: Tx -> Int -> [ ScriptOp ] -> TxSignature -> PubKey -> Bool+verifySigWithType tx i outOps txSig pubKey =+  let outScript = Script outOps+      h = txSigHash tx outScript i ( sigHashType txSig ) in+  verifySig h ( txSignature txSig ) pubKey++-- | Uses `evalScript` to check that the input script of a spending+-- transaction satisfies the output script.+verifySpend :: Tx     -- ^ The spending transaction+            -> Int    -- ^ The input index+            -> Script -- ^ The output script we are spending+            -> [ Flag ] -- ^ Evaluation flags+            -> Bool+verifySpend tx i outscript flags =+  let scriptSig = decode' . scriptInput $ txIn tx !! i+      verifyFcn = verifySigWithType tx i+  in+  evalScript scriptSig outscript verifyFcn flags
+ Network/Haskoin/Script/Parser.hs view
@@ -0,0 +1,334 @@+module Network.Haskoin.Script.Parser+( ScriptOutput(..)+, ScriptInput(..)+, SimpleInput(..)+, RedeemScript+, scriptAddr+, scriptRecipient+, scriptSender+, encodeInput+, encodeInputBS+, decodeInput+, decodeInputBS+, encodeOutput+, encodeOutputBS+, decodeOutput+, decodeOutputBS+, sortMulSig+, intToScriptOp+, scriptOpToInt+, isPayPK+, isPayPKHash+, isPayMulSig+, isPayScriptHash+, isSpendPK+, isSpendPKHash+, isSpendMulSig+, isScriptHashInput+) where++import Control.DeepSeq (NFData, rnf)+import Control.Monad (liftM2, guard)+import Control.Applicative ((<|>))++import Data.List (sortBy)+import Data.Foldable (foldrM)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+    ( head+    , singleton+    )+import Data.String.Conversions (cs)+import Data.Aeson+    ( Value (String)+    , FromJSON+    , ToJSON+    , parseJSON+    , toJSON+    , withText+    )+import Network.Haskoin.Util+import Network.Haskoin.Crypto.Keys+import Network.Haskoin.Crypto.Base58+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Script.Types+import Network.Haskoin.Script.SigHash++-- | Data type describing standard transaction output scripts. Output scripts+-- provide the conditions that must be fulfilled for someone to spend the+-- output coins.+data ScriptOutput =+      -- | Pay to a public key.+      PayPK         { getOutputPubKey   :: !PubKey }+      -- | Pay to a public key hash.+    | PayPKHash     { getOutputAddress  :: !Address }+      -- | Pay to multiple public keys.+    | PayMulSig     { getOutputMulSigKeys     :: ![PubKey]+                    , getOutputMulSigRequired :: !Int+                    }+      -- | Pay to a script hash.+    | PayScriptHash { getOutputAddress  :: !Address }+    deriving (Eq, Show, Read)++instance FromJSON ScriptOutput where+    parseJSON = withText "scriptoutput" $ \t -> either fail return $+        maybeToEither "scriptoutput not hex" (decodeHex $ cs t) >>=+        decodeOutputBS++instance ToJSON ScriptOutput where+    toJSON = String . cs . encodeHex . encodeOutputBS++instance NFData ScriptOutput where+    rnf (PayPK k) = rnf k+    rnf (PayPKHash a) = rnf a+    rnf (PayMulSig k r) = rnf k `seq` rnf r+    rnf (PayScriptHash a) = rnf a++-- | Returns True if the script is a pay to public key output.+isPayPK :: ScriptOutput -> Bool+isPayPK (PayPK _) = True+isPayPK _ = False++-- | Returns True if the script is a pay to public key hash output.+isPayPKHash :: ScriptOutput -> Bool+isPayPKHash (PayPKHash _) = True+isPayPKHash _ = False++-- | Returns True if the script is a pay to multiple public keys output.+isPayMulSig :: ScriptOutput -> Bool+isPayMulSig (PayMulSig _ _) = True+isPayMulSig _ = False++-- | Returns true if the script is a pay to script hash output.+isPayScriptHash :: ScriptOutput -> Bool+isPayScriptHash (PayScriptHash _) = True+isPayScriptHash _ = False++-- | Computes a script address from a script output. This address can be used+-- in a pay to script hash output.+scriptAddr :: ScriptOutput -> Address+scriptAddr = ScriptAddress . hash160 . getHash256 . hash256 . encodeOutputBS++-- | Sorts the public keys of a multisignature output in ascending order by+-- comparing their serialized representations. This feature allows for easier+-- multisignature account management as participants in a multisignature wallet+-- will blindly agree on an ordering of the public keys without having to+-- communicate.+sortMulSig :: ScriptOutput -> ScriptOutput+sortMulSig out = case out of+    PayMulSig keys r -> PayMulSig (sortBy f keys) r+    _ -> error "Can only call orderMulSig on PayMulSig scripts"+  where+    f a b = encode' a `compare` encode' b++-- | Computes a 'Script' from a 'ScriptOutput'. The 'Script' is a list of+-- 'ScriptOp' can can be used to build a 'Tx'.+encodeOutput :: ScriptOutput -> Script+encodeOutput s = Script $ case s of+    -- Pay to PubKey+    (PayPK k) -> [opPushData $ encode' k, OP_CHECKSIG]+    -- Pay to PubKey Hash Address+    (PayPKHash a) -> case a of+        (PubKeyAddress h) -> [ OP_DUP, OP_HASH160, opPushData $ encode' h+                             , OP_EQUALVERIFY, OP_CHECKSIG+                             ]+        (ScriptAddress _) ->+            error "encodeOutput: ScriptAddress is invalid in PayPKHash"+    -- Pay to MultiSig Keys+    (PayMulSig ps r)+      | r <= length ps ->+        let opM = intToScriptOp r+            opN = intToScriptOp $ length ps+            keys = map (opPushData . encode') ps+            in opM : keys ++ [opN, OP_CHECKMULTISIG]+      | otherwise -> error "encodeOutput: PayMulSig r must be <= than pkeys"+    -- Pay to Script Hash Address+    (PayScriptHash a) -> case a of+        (ScriptAddress h) -> [ OP_HASH160+                             , opPushData $ encode' h, OP_EQUAL+                             ]+        (PubKeyAddress _) ->+            error "encodeOutput: PubKeyAddress is invalid in PayScriptHash"++-- | Similar to 'encodeOutput' but encodes to a ByteString+encodeOutputBS :: ScriptOutput -> ByteString+encodeOutputBS = encode' . encodeOutput++-- | Tries to decode a 'ScriptOutput' from a 'Script'. This can fail if the+-- script is not recognized as any of the standard output types.+decodeOutput :: Script -> Either String ScriptOutput+decodeOutput s = case scriptOps s of+    -- Pay to PubKey+    [OP_PUSHDATA bs _, OP_CHECKSIG] -> PayPK <$> decodeToEither bs+    -- Pay to PubKey Hash+    [OP_DUP, OP_HASH160, OP_PUSHDATA bs _, OP_EQUALVERIFY, OP_CHECKSIG] ->+        (PayPKHash . PubKeyAddress) <$> decodeToEither bs+    -- Pay to Script Hash+    [OP_HASH160, OP_PUSHDATA bs _, OP_EQUAL] ->+        (PayScriptHash . ScriptAddress) <$> decodeToEither bs+    -- Pay to MultiSig Keys+    _ -> matchPayMulSig s++-- | Similar to 'decodeOutput' but decodes from a ByteString+decodeOutputBS :: ByteString -> Either String ScriptOutput+decodeOutputBS = (decodeOutput =<<) . decodeToEither++-- Match [ OP_N, PubKey1, ..., PubKeyM, OP_M, OP_CHECKMULTISIG ]+matchPayMulSig :: Script -> Either String ScriptOutput+matchPayMulSig (Script ops) = case splitAt (length ops - 2) ops of+    (m:xs,[n,OP_CHECKMULTISIG]) -> do+        (intM,intN) <- liftM2 (,) (scriptOpToInt m) (scriptOpToInt n)+        if intM <= intN && length xs == intN+            then liftM2 PayMulSig (go xs) (return intM)+            else Left "matchPayMulSig: Invalid M or N parameters"+    _ -> Left "matchPayMulSig: script did not match output template"+  where+    go (OP_PUSHDATA bs _:xs) = liftM2 (:) (decodeToEither bs) (go xs)+    go [] = return []+    go  _ = Left "matchPayMulSig: invalid multisig opcode"++-- | Transforms integers [1 .. 16] to 'ScriptOp' [OP_1 .. OP_16]+intToScriptOp :: Int -> ScriptOp+intToScriptOp i+    | i `elem` [1..16] = op+    |        otherwise = error $ "intToScriptOp: Invalid integer " ++ (show i)+  where+    op = decode' $ BS.singleton $ fromIntegral $ i + 0x50++-- | Decode 'ScriptOp' [OP_1 .. OP_16] to integers [1 .. 16]. This functions+-- fails for other values of 'ScriptOp'+scriptOpToInt :: ScriptOp -> Either String Int+scriptOpToInt s+    | res `elem` [1..16] = return res+    | otherwise          = Left $ "scriptOpToInt: invalid opcode " ++ (show s)+  where+    res = (fromIntegral $ BS.head $ encode' s) - 0x50++-- | Computes the recipient address of a script. This function fails if the+-- script could not be decoded as a pay to public key hash or pay to script+-- hash.+scriptRecipient :: Script -> Either String Address+scriptRecipient s = case decodeOutput s of+    Right (PayPKHash a)     -> return a+    Right (PayScriptHash a) -> return a+    Right _                 -> Left "scriptRecipient: bad output script type"+    _                       -> Left "scriptRecipient: non-standard script type"++-- | Computes the sender address of a script. This function fails if the+-- script could not be decoded as a spend public key hash or script hash+-- input.+scriptSender :: Script -> Either String Address+scriptSender s = case decodeInput s of+    Right (RegularInput (SpendPKHash _ key)) -> return $ pubKeyAddr key+    Right (ScriptHashInput _ rdm)            -> return $ scriptAddr rdm+    Right _ -> Left "scriptSender: bad input script type"+    _ -> Left "scriptSender: non-standard script type"++-- | Data type describing standard transaction input scripts. Input scripts+-- provide the signing data required to unlock the coins of the output they are+-- trying to spend.+data SimpleInput+      -- | Spend the coins of a PayPK output.+    = SpendPK     { getInputSig :: !TxSignature }+      -- | Spend the coins of a PayPKHash output.+    | SpendPKHash { getInputSig :: !TxSignature+                  , getInputKey :: !PubKey+                  }+      -- | Spend the coins of a PayMulSig output.+    | SpendMulSig { getInputMulSigKeys :: ![TxSignature] }+    deriving (Eq, Show, Read)++instance NFData SimpleInput where+    rnf (SpendPK i) = rnf i+    rnf (SpendPKHash i k) = rnf i `seq` rnf k+    rnf (SpendMulSig k) = rnf k++-- | Returns True if the input script is spending a public key.+isSpendPK :: ScriptInput -> Bool+isSpendPK (RegularInput (SpendPK _)) = True+isSpendPK _ = False++-- | Returns True if the input script is spending a public key hash.+isSpendPKHash :: ScriptInput -> Bool+isSpendPKHash (RegularInput (SpendPKHash _ _)) = True+isSpendPKHash _ = False++-- | Returns True if the input script is spending a multisignature output.+isSpendMulSig :: ScriptInput -> Bool+isSpendMulSig (RegularInput (SpendMulSig _)) = True+isSpendMulSig _ = False++isScriptHashInput :: ScriptInput -> Bool+isScriptHashInput (ScriptHashInput _ _) = True+isScriptHashInput _ = False++type RedeemScript = ScriptOutput++data ScriptInput+    = RegularInput    { getRegularInput     :: SimpleInput }+    | ScriptHashInput { getScriptHashInput  :: SimpleInput+                      , getScriptHashRedeem :: RedeemScript+                      }+    deriving (Eq, Show, Read)++instance NFData ScriptInput where+    rnf (RegularInput i) = rnf i+    rnf (ScriptHashInput i o) = rnf i `seq` rnf o++-- | Computes a 'Script' from a 'SimpleInput'. The 'Script' is a list of+-- 'ScriptOp' that can be used to build a 'Tx'.+encodeSimpleInput :: SimpleInput -> Script+encodeSimpleInput s = Script $ case s of+    SpendPK ts       -> [ opPushData $ encodeSig ts ]+    SpendPKHash ts p -> [ opPushData $ encodeSig ts+                        , opPushData $ encode' p+                        ]+    SpendMulSig ts   -> OP_0 : map (opPushData . encodeSig) ts++decodeSimpleInput :: Script -> Either String SimpleInput+decodeSimpleInput (Script ops) = maybeToEither errMsg $+    matchPK ops <|> matchPKHash ops <|> matchMulSig ops+  where+    matchPK [OP_PUSHDATA bs _] = SpendPK <$> eitherToMaybe (decodeSig bs)+    matchPK _ = Nothing+    matchPKHash [OP_PUSHDATA sig _, OP_PUSHDATA pub _] =+        liftM2 SpendPKHash (eitherToMaybe $ decodeSig sig) (decodeToMaybe pub)+    matchPKHash _ = Nothing+    matchMulSig (x:xs) = do+        guard $ isPushOp x+        SpendMulSig <$> foldrM f [] xs+    matchMulSig _ = Nothing+    f (OP_PUSHDATA bs _) acc =+        liftM2 (:) (eitherToMaybe $ decodeSig bs) (Just acc)+    f _ _ = Nothing+    errMsg = "decodeInput: Could not decode script input"++encodeInput :: ScriptInput -> Script+encodeInput s = case s of+    RegularInput ri -> encodeSimpleInput ri+    ScriptHashInput i o -> Script $+        (scriptOps $ encodeSimpleInput i) ++ [opPushData $ encodeOutputBS o]++-- | Similar to 'encodeInput' but encodes to a ByteString+encodeInputBS :: ScriptInput -> ByteString+encodeInputBS = encode' . encodeInput++-- | Decodes a 'ScriptInput' from a 'Script'. This function fails if the+-- script can not be parsed as a standard script input.+decodeInput :: Script -> Either String ScriptInput+decodeInput s@(Script ops) = maybeToEither errMsg $+    matchSimpleInput <|> matchPayScriptHash+  where+    matchSimpleInput = RegularInput <$> (eitherToMaybe $ decodeSimpleInput s)+    matchPayScriptHash = case splitAt (length (scriptOps s) - 1) ops of+        (is, [OP_PUSHDATA bs _]) -> do+            rdm <- eitherToMaybe $ decodeOutputBS bs+            inp <- eitherToMaybe $ decodeSimpleInput $ Script is+            return $ ScriptHashInput inp rdm+        _ -> Nothing+    errMsg = "decodeInput: Could not decode script input"++-- | Similar to 'decodeInput' but decodes from a ByteString+decodeInputBS :: ByteString -> Either String ScriptInput+decodeInputBS = (decodeInput =<<) . decodeToEither+
+ Network/Haskoin/Script/SigHash.hs view
@@ -0,0 +1,197 @@+module Network.Haskoin.Script.SigHash+( SigHash(..)+, encodeSigHash32+, isSigAll+, isSigNone+, isSigSingle+, isSigUnknown+, txSigHash+, TxSignature(..)+, encodeSig+, decodeSig+, decodeCanonicalSig+) where++import Control.DeepSeq (NFData, rnf)+import Control.Monad (liftM2, mzero, (<=<))++import Data.Word (Word8)+import Data.Bits (testBit, clearBit)+import Data.Maybe (fromMaybe)+import Data.Binary (Binary, get, put, getWord8, putWord8)+import Data.Aeson (Value(String), FromJSON, ToJSON, parseJSON, toJSON, withText)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+    ( init+    , singleton+    , length+    , last+    , append+    , pack+    , splitAt+    , empty+    )+import Data.String.Conversions (cs)++import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Crypto.ECDSA+import Network.Haskoin.Script.Types+import Network.Haskoin.Transaction.Types+import Network.Haskoin.Util++-- | Data type representing the different ways a transaction can be signed.+-- When producing a signature, a hash of the transaction is used as the message+-- to be signed. The 'SigHash' parameter controls which parts of the+-- transaction are used or ignored to produce the transaction hash. The idea is+-- that if some part of a transaction is not used to produce the transaction+-- hash, then you can change that part of the transaction after producing a+-- signature without invalidating that signature.+--+-- If the anyoneCanPay flag is True, then only the current input is signed.+-- Otherwise, all of the inputs of a transaction are signed. The default value+-- for anyoneCanPay is False.+data SigHash+    -- | Sign all of the outputs of a transaction (This is the default value).+    -- Changing any of the outputs of the transaction will invalidate the+    -- signature.+    = SigAll     { anyoneCanPay :: !Bool }+    -- | Sign none of the outputs of a transaction. This allows anyone to+    -- change any of the outputs of the transaction.+    | SigNone    { anyoneCanPay :: !Bool }+    -- | Sign only the output corresponding the the current transaction input.+    -- You care about your own output in the transaction but you don't+    -- care about any of the other outputs.+    | SigSingle  { anyoneCanPay :: !Bool }+    -- | Unrecognized sighash types will decode to SigUnknown.+    | SigUnknown { anyoneCanPay :: !Bool+                 , getSigCode   :: !Word8+                 }+    deriving (Eq, Show, Read)++instance NFData SigHash where+    rnf (SigAll a) = rnf a+    rnf (SigNone a) = rnf a+    rnf (SigSingle a) = rnf a+    rnf (SigUnknown a c) = rnf a `seq` rnf c++-- | Returns True if the 'SigHash' has the value SigAll.+isSigAll :: SigHash -> Bool+isSigAll sh = case sh of+    SigAll _ -> True+    _ -> False++-- | Returns True if the 'SigHash' has the value SigNone.+isSigNone :: SigHash -> Bool+isSigNone sh = case sh of+    SigNone _ -> True+    _ -> False++-- | Returns True if the 'SigHash' has the value SigSingle.+isSigSingle :: SigHash -> Bool+isSigSingle sh = case sh of+    SigSingle _ -> True+    _ -> False++-- | Returns True if the 'SigHash' has the value SigUnknown.+isSigUnknown :: SigHash -> Bool+isSigUnknown sh = case sh of+    SigUnknown _ _ -> True+    _ -> False++instance Binary SigHash where++    get = getWord8 >>= \w ->+        let acp = testBit w 7+            in return $ case clearBit w 7 of+                1 -> SigAll acp+                2 -> SigNone acp+                3 -> SigSingle acp+                _ -> SigUnknown acp w++    put sh = putWord8 $ case sh of+        SigAll acp -> if acp then 0x81 else 0x01+        SigNone acp -> if acp then 0x82 else 0x02+        SigSingle acp -> if acp then 0x83 else 0x03+        SigUnknown _ w -> w++instance ToJSON SigHash where+    toJSON = String . cs . encodeHex . encode'++instance FromJSON SigHash where+    parseJSON = withText "sighash" $+        maybe mzero return . (decodeToMaybe <=< decodeHex) . cs++-- | Encodes a 'SigHash' to a 32 bit-long bytestring.+encodeSigHash32 :: SigHash -> ByteString+encodeSigHash32 sh = encode' sh `BS.append` BS.pack [0,0,0]++-- | Computes the hash that will be used for signing a transaction.+txSigHash :: Tx      -- ^ Transaction to sign.+          -> Script  -- ^ Output script that is being spent.+          -> Int     -- ^ Index of the input that is being signed.+          -> SigHash -- ^ What parts of the transaction should be signed.+          -> Hash256 -- ^ Result hash to be signed.+txSigHash tx out i sh = do+    let newIn = buildInputs (txIn tx) out i sh+    -- When SigSingle and input index > outputs, then sign integer 1+    fromMaybe one $ do+        newOut <- buildOutputs (txOut tx) i sh+        let newTx = tx{ txIn = newIn, txOut = newOut }+        return $ doubleHash256 $ encode' newTx `BS.append` encodeSigHash32 sh+  where+    one = "0100000000000000000000000000000000000000000000000000000000000000"++-- Builds transaction inputs for computing SigHashes+buildInputs :: [TxIn] -> Script -> Int -> SigHash -> [TxIn]+buildInputs txins out i sh+    | anyoneCanPay sh   = (txins !! i) { scriptInput = encode' out } : []+    | isSigAll sh || isSigUnknown sh = single+    | otherwise         = map noSeq $ zip single [0..]+  where+    empty  = map (\ti -> ti{ scriptInput = BS.empty }) txins+    single = updateIndex i empty $ \ti -> ti{ scriptInput = encode' out }+    noSeq (ti,j) = if i == j then ti else ti{ txInSequence = 0 }++-- Build transaction outputs for computing SigHashes+buildOutputs :: [TxOut] -> Int -> SigHash -> Maybe [TxOut]+buildOutputs txos i sh+    | isSigAll sh || isSigUnknown sh = return txos+    | isSigNone sh = return []+    | i >= length txos = Nothing+    | otherwise = return $ buffer ++ [txos !! i]+  where+    buffer = replicate i $ TxOut (-1) BS.empty++-- | Data type representing a 'Signature' together with a 'SigHash'. The+-- 'SigHash' is serialized as one byte at the end of a regular ECDSA+-- 'Signature'. All signatures in transaction inputs are of type 'TxSignature'.+data TxSignature = TxSignature+    { txSignature :: !Signature+    , sigHashType :: !SigHash+    } deriving (Eq, Show, Read)++instance NFData TxSignature where+    rnf (TxSignature s h) = rnf s `seq` rnf h++-- | Serialize a 'TxSignature' to a ByteString.+encodeSig :: TxSignature -> ByteString+encodeSig (TxSignature sig sh) = runPut' $ put sig >> put sh++-- | Decode a 'TxSignature' from a ByteString.+decodeSig :: ByteString -> Either String TxSignature+decodeSig bs = do+    let (h, l) = BS.splitAt (BS.length bs - 1) bs+    liftM2 TxSignature (decodeToEither h) (decodeToEither l)++decodeCanonicalSig :: ByteString -> Either String TxSignature+decodeCanonicalSig bs+    | hashtype < 1 || hashtype > 3 =+        Left "Non-canonical signature: unknown hashtype byte"+    | otherwise =+        case decodeStrictSig $ BS.init bs of+            Just sig ->+                TxSignature sig <$> decodeToEither (BS.singleton $ BS.last bs)+            Nothing  ->+                Left "Non-canonical signature: could not parse signature"+  where+    hashtype = clearBit (BS.last bs) 7
+ Network/Haskoin/Script/Types.hs view
@@ -0,0 +1,541 @@+module Network.Haskoin.Script.Types+( ScriptOp(..)+, Script(..)+, PushDataType(..)+, isPushOp+, opPushData+) where++import Control.DeepSeq (NFData, rnf)+import Control.Monad (liftM2, unless, forM_)++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 NFData Script where+    rnf (Script o) = rnf o++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)++instance NFData PushDataType where rnf x = seq x ()++-- | 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 NFData ScriptOp where+    rnf (OP_PUSHDATA b t) = rnf b `seq` rnf t+    rnf (OP_INVALIDOPCODE c) = rnf c+    rnf x = x `seq` ()+++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+
+ Network/Haskoin/Test.hs view
@@ -0,0 +1,119 @@+{-|+  This package provides test types for Network.Haskoin+-}+module Network.Haskoin.Test+(+  -- * Util Arbitrary instances+  ArbitraryByteString(..)+, ArbitraryNotNullByteString(..)+, ArbitraryUTCTime(..)+, ArbitraryHash512(..)+, ArbitraryHash256(..)+, ArbitraryHash160(..)+, ArbitraryCheckSum32(..)++  -- * Crypto Arbitrary instances+, ArbitraryPrvKey(..)+, ArbitraryPrvKeyC(..)+, ArbitraryPrvKeyU(..)+, ArbitraryPubKey(..)+, ArbitraryPubKeyC(..)+, ArbitraryPubKeyU(..)+, ArbitraryAddress(..)+, ArbitraryPubKeyAddress(..)+, ArbitraryScriptAddress(..)+, ArbitrarySignature(..)+, ArbitraryXPrvKey(..)+, ArbitraryXPubKey(..)+, ArbitraryHardPath(..)+, ArbitrarySoftPath(..)+, ArbitraryDerivPath(..)++  -- * Node Arbitrary instances+, ArbitraryVarInt(..)+, ArbitraryVarString(..)+, ArbitraryNetworkAddress(..)+, ArbitraryNetworkAddressTime(..)+, ArbitraryInvType(..)+, ArbitraryInvVector(..)+, ArbitraryInv(..)+, ArbitraryVersion(..)+, ArbitraryAddr(..)+, ArbitraryAlert(..)+, ArbitraryReject(..)+, ArbitraryRejectCode(..)+, ArbitraryGetData(..)+, ArbitraryNotFound(..)+, ArbitraryPing(..)+, ArbitraryPong(..)+, ArbitraryBloomFlags(..)+, ArbitraryBloomFilter(..)+, ArbitraryFilterLoad(..)+, ArbitraryFilterAdd(..)+, ArbitraryMessageCommand(..)++  -- * Message Arbitrary instances+, ArbitraryMessageHeader(..)+, ArbitraryMessage(..)++  -- * Script Arbitrary instances+, ArbitraryScriptOp(..)+, ArbitraryScript(..)+, ArbitraryIntScriptOp(..)+, ArbitraryPushDataType(..)+, ArbitraryTxSignature(..)+, ArbitrarySigHash(..)+, ArbitraryValidSigHash(..)+, ArbitraryMSParam(..)+, ArbitraryScriptOutput(..)+, ArbitrarySimpleOutput(..)+, ArbitraryPKOutput(..)+, ArbitraryPKHashOutput(..)+, ArbitraryMSOutput(..)+, ArbitraryMSCOutput(..)+, ArbitrarySHOutput(..)+, ArbitraryScriptInput(..)+, ArbitrarySimpleInput(..)+, ArbitraryPKInput(..)+, ArbitraryPKHashInput(..)+, ArbitraryPKHashCInput(..)+, ArbitraryMSInput(..)+, ArbitrarySHInput(..)+, ArbitraryMulSigSHCInput(..)++  -- * Transaction Arbitrary instances+, ArbitrarySatoshi(..)+, ArbitraryTx(..)+, ArbitraryTxHash(..)+, ArbitraryTxIn(..)+, ArbitraryTxOut(..)+, ArbitraryOutPoint(..)+, ArbitraryCoinbaseTx(..)+, ArbitraryAddrOnlyTx(..)+, ArbitraryAddrOnlyTxIn(..)+, ArbitraryAddrOnlyTxOut(..)+, ArbitrarySigInput(..)+, ArbitraryPKSigInput(..)+, ArbitraryPKHashSigInput(..)+, ArbitraryMSSigInput(..)+, ArbitrarySHSigInput(..)+, ArbitrarySigningData(..)+, ArbitraryPartialTxs(..)++  -- * Block Arbitrary instances+, ArbitraryBlock(..)+, ArbitraryBlockHeader(..)+, ArbitraryBlockHash(..)+, ArbitraryGetBlocks(..)+, ArbitraryGetHeaders(..)+, ArbitraryHeaders(..)+, ArbitraryMerkleBlock(..)+) where++import Network.Haskoin.Test.Util+import Network.Haskoin.Test.Crypto+import Network.Haskoin.Test.Node+import Network.Haskoin.Test.Message+import Network.Haskoin.Test.Script+import Network.Haskoin.Test.Transaction+import Network.Haskoin.Test.Block
+ Network/Haskoin/Test/Block.hs view
@@ -0,0 +1,111 @@+{-|+  Arbitrary types for Network.Haskoin.Block+-}+module Network.Haskoin.Test.Block+( ArbitraryBlock(..)+, ArbitraryBlockHeader(..)+, ArbitraryBlockHash(..)+, ArbitraryGetBlocks(..)+, ArbitraryGetHeaders(..)+, ArbitraryHeaders(..)+, ArbitraryMerkleBlock(..)+) where++import Test.QuickCheck+    ( Arbitrary+    , arbitrary+    , choose+    , vectorOf+    , listOf1+    )++import Network.Haskoin.Test.Crypto+import Network.Haskoin.Test.Transaction+import Network.Haskoin.Test.Node++import Network.Haskoin.Block.Types+import Network.Haskoin.Block.Merkle++-- | Arbitrary Block+newtype ArbitraryBlock = ArbitraryBlock Block+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryBlock where+    arbitrary = do+        ArbitraryBlockHeader h <- arbitrary+        ArbitraryCoinbaseTx cb <- arbitrary+        c <- choose (0,10)+        txs <- map (\(ArbitraryTx x) -> x) <$> vectorOf c arbitrary+        return $ ArbitraryBlock $ Block h cb txs++-- | Arbitrary BlockHeader+newtype ArbitraryBlockHeader = ArbitraryBlockHeader BlockHeader+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryBlockHeader where+    arbitrary = do+        ArbitraryBlockHash h1 <- arbitrary+        ArbitraryHash256 h2 <- arbitrary+        h <- BlockHeader <$> arbitrary <*> return h1 <*> return h2+                         <*> arbitrary <*> arbitrary <*> arbitrary+        return $ ArbitraryBlockHeader h++newtype ArbitraryBlockHash = ArbitraryBlockHash BlockHash+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryBlockHash where+    arbitrary = do+        ArbitraryHash256 h <- arbitrary+        return $ ArbitraryBlockHash $ BlockHash h++-- | Arbitrary GetBlocks+newtype ArbitraryGetBlocks = ArbitraryGetBlocks GetBlocks+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryGetBlocks where+    arbitrary = do+        hs <- listOf1 arbitrary+        let hs' = map (\(ArbitraryBlockHash h) -> h) hs+        ArbitraryBlockHash h <- arbitrary+        b <- GetBlocks <$> arbitrary <*> return hs' <*> return h+        return $ ArbitraryGetBlocks b++-- | Arbitrary GetHeaders+newtype ArbitraryGetHeaders = ArbitraryGetHeaders GetHeaders+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryGetHeaders where+    arbitrary = do+        hs <- listOf1 arbitrary+        let hs' = map (\(ArbitraryBlockHash h) -> h) hs+        ArbitraryBlockHash h' <- arbitrary+        h <- GetHeaders <$> arbitrary <*> return hs' <*> return h'+        return $ ArbitraryGetHeaders h++-- | Arbitrary Headers+newtype ArbitraryHeaders = ArbitraryHeaders Headers+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryHeaders where+    arbitrary = ArbitraryHeaders <$> do+        xs <- listOf1 $ do+            ArbitraryBlockHeader h <- arbitrary+            ArbitraryVarInt v <- arbitrary+            return (h,v)+        return $ Headers xs++-- | Arbitrary MerkleBlock+newtype ArbitraryMerkleBlock = ArbitraryMerkleBlock MerkleBlock+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryMerkleBlock where+    arbitrary = ArbitraryMerkleBlock <$> do+        ArbitraryBlockHeader bh <- arbitrary+        ntx <- arbitrary+        hashes <- listOf1 arbitrary+        let hashes' = map (\(ArbitraryHash256 h) -> h) hashes+        c <- choose (1,10)+        flags <- vectorOf (c*8) arbitrary+        return $ MerkleBlock bh ntx hashes' flags++
+ Network/Haskoin/Test/Crypto.hs view
@@ -0,0 +1,249 @@+{-|+  Arbitrary types for Network.Haskoin.Crypto+-}+module Network.Haskoin.Test.Crypto+( ArbitraryHash512(..)+, ArbitraryHash256(..)+, ArbitraryHash160(..)+, ArbitraryCheckSum32(..)+, ArbitraryByteString(..)+, ArbitraryNotNullByteString(..)+, ArbitraryPrvKey(..)+, ArbitraryPrvKeyC(..)+, ArbitraryPrvKeyU(..)+, ArbitraryPubKey(..)+, ArbitraryPubKeyC(..)+, ArbitraryPubKeyU(..)+, ArbitraryAddress(..)+, ArbitraryPubKeyAddress(..)+, ArbitraryScriptAddress(..)+, ArbitrarySignature(..)+, ArbitraryXPrvKey(..)+, ArbitraryXPubKey(..)+, ArbitraryHardPath(..)+, ArbitrarySoftPath(..)+, ArbitraryDerivPath(..)+) where++import Test.QuickCheck+    ( Arbitrary+    , Gen+    , arbitrary+    , elements+    , oneof+    , vectorOf+    , listOf+    )++import Crypto.Secp256k1 ()++import Data.Bits (clearBit)+import qualified Data.ByteString as BS (pack)+import Data.Maybe (fromMaybe)+import Data.Word (Word32)++import Network.Haskoin.Test.Util+import Network.Haskoin.Crypto.ECDSA+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Crypto.Keys+import Network.Haskoin.Crypto.Base58+import Network.Haskoin.Crypto.ExtendedKeys++newtype ArbitraryHash160 = ArbitraryHash160 Hash160+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryHash160 where+    arbitrary = (ArbitraryHash160 . fromMaybe e . bsToHash160 . BS.pack) <$>+        vectorOf 20 arbitrary+      where+        e = error "Could not read arbitrary 20-byte hash"++newtype ArbitraryHash256 = ArbitraryHash256 Hash256+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryHash256 where+    arbitrary = (ArbitraryHash256 . fromMaybe e . bsToHash256 . BS.pack) <$>+        vectorOf 32 arbitrary+      where+        e = error "Could not read arbitrary 32-byte hash"++newtype ArbitraryHash512 = ArbitraryHash512 Hash512+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryHash512 where+    arbitrary = (ArbitraryHash512 . fromMaybe e . bsToHash512 . BS.pack) <$>+        vectorOf 64 arbitrary+      where+        e = error "Could not read arbitrary 64-byte hash"++newtype ArbitraryCheckSum32 = ArbitraryCheckSum32 CheckSum32+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryCheckSum32 where+    arbitrary = (ArbitraryCheckSum32 . fromMaybe e . bsToCheckSum32 . BS.pack) <$>+        vectorOf 4 arbitrary+      where+        e = error "Could not read arbitrary checksum"++-- | Arbitrary private key (can be both compressed or uncompressed)+newtype ArbitraryPrvKey = ArbitraryPrvKey PrvKey+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPrvKey where+    arbitrary = ArbitraryPrvKey <$> oneof+        [ arbitrary >>= \(ArbitraryPrvKeyC k) -> return (toPrvKeyG k)+        , arbitrary >>= \(ArbitraryPrvKeyU k) -> return (toPrvKeyG k)+        ]++-- | Arbitrary compressed private key+newtype ArbitraryPrvKeyC = ArbitraryPrvKeyC PrvKeyC+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPrvKeyC where+    arbitrary = do+        i <- arbitrary+        return $ ArbitraryPrvKeyC $ makePrvKeyC i++-- | Arbitrary uncompressed private key+newtype ArbitraryPrvKeyU = ArbitraryPrvKeyU PrvKeyU+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPrvKeyU where+    arbitrary = do+        i <- arbitrary+        return $ ArbitraryPrvKeyU $ makePrvKeyU i++-- | Arbitrary public key (can be both compressed or uncompressed) with its+-- corresponding private key.+data ArbitraryPubKey = ArbitraryPubKey PrvKey PubKey+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPubKey where+    arbitrary = oneof+        [ arbitrary >>= \(ArbitraryPubKeyC k p) ->+            return $ ArbitraryPubKey (toPrvKeyG k) (toPubKeyG p)+        , arbitrary >>= \(ArbitraryPubKeyU k p) ->+            return $ ArbitraryPubKey (toPrvKeyG k) (toPubKeyG p)+        ]++-- | Arbitrary compressed public key with its corresponding private key.+data ArbitraryPubKeyC = ArbitraryPubKeyC PrvKeyC PubKeyC+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPubKeyC where+    arbitrary = do+        ArbitraryPrvKeyC k <- arbitrary+        return $ ArbitraryPubKeyC k $ derivePubKey k++-- | Arbitrary uncompressed public key with its corresponding private key.+data ArbitraryPubKeyU = ArbitraryPubKeyU PrvKeyU PubKeyU+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPubKeyU where+    arbitrary = do+        ArbitraryPrvKeyU k <- arbitrary+        return $ ArbitraryPubKeyU k $ derivePubKey k++-- | Arbitrary address (can be a pubkey or script hash address)+newtype ArbitraryAddress = ArbitraryAddress Address+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryAddress where+    arbitrary = ArbitraryAddress <$> oneof+        [ arbitrary >>= \(ArbitraryPubKeyAddress a) -> return a+        , arbitrary >>= \(ArbitraryScriptAddress a) -> return a+        ]++-- | Arbitrary public key hash address+newtype ArbitraryPubKeyAddress = ArbitraryPubKeyAddress Address+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPubKeyAddress where+    arbitrary = do+        ArbitraryHash160 i <- arbitrary+        return $ ArbitraryPubKeyAddress $ PubKeyAddress i++-- | Arbitrary script hash address+newtype ArbitraryScriptAddress = ArbitraryScriptAddress Address+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryScriptAddress where+    arbitrary = do+        ArbitraryHash160 i <- arbitrary+        return $ ArbitraryScriptAddress $ ScriptAddress i++-- | Arbitrary message hash, private key, nonce and corresponding signature.+-- The signature is generated with a random message, random private key and a+-- random nonce.+data ArbitrarySignature = ArbitrarySignature Hash256 PrvKey Signature+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySignature where+    arbitrary = do+        ArbitraryHash256 msg <- arbitrary+        ArbitraryPrvKey key <- arbitrary+        let sig = signMsg msg key+        return $ ArbitrarySignature msg key sig++-- | Arbitrary extended private key.+data ArbitraryXPrvKey = ArbitraryXPrvKey XPrvKey+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryXPrvKey where+    arbitrary = do+        d <- arbitrary+        p <- arbitrary+        i <- arbitrary+        ArbitraryHash256 c <- arbitrary+        ArbitraryPrvKeyC k <- arbitrary+        return $ ArbitraryXPrvKey $ XPrvKey d p i c k++-- | Arbitrary extended public key with its corresponding private key.+data ArbitraryXPubKey = ArbitraryXPubKey XPrvKey XPubKey+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryXPubKey where+    arbitrary = do+        ArbitraryXPrvKey k <- arbitrary+        return $ ArbitraryXPubKey k $ deriveXPubKey k++{- Custom derivations -}++genIndex :: Gen Word32+genIndex = (`clearBit` 31) <$> arbitrary++data ArbitraryHardPath = ArbitraryHardPath HardPath+    deriving (Show, Eq)++instance Arbitrary ArbitraryHardPath where+    arbitrary =+        ArbitraryHardPath <$> (go =<< listOf genIndex)+      where+        go []     = elements [ Deriv, DerivPrv, DerivPub ]+        go (i:is) = (:| i) <$> go is++data ArbitrarySoftPath = ArbitrarySoftPath SoftPath+    deriving (Show, Eq)++instance Arbitrary ArbitrarySoftPath where+    arbitrary =+        ArbitrarySoftPath <$> (go =<< listOf genIndex)+      where+        go []     = elements [ Deriv, DerivPrv, DerivPub ]+        go (i:is) = (:/ i) <$> go is++data ArbitraryDerivPath = ArbitraryDerivPath DerivPath+    deriving (Show, Eq)++instance Arbitrary ArbitraryDerivPath where+    arbitrary = do+        xs  <- listOf genIndex+        ys  <- listOf genIndex+        return . ArbitraryDerivPath . goSoft ys =<< goHard xs+      where+        goSoft [] h     = h+        goSoft (i:is) h = (goSoft is h) :/ i+        goHard :: HardOrMixed t => [Word32] -> Gen (DerivPathI t)+        goHard (i:is) = (:| i) <$> goHard is+        goHard []     = elements [ Deriv, DerivPrv, DerivPub ]+
+ Network/Haskoin/Test/Message.hs view
@@ -0,0 +1,61 @@+{-|+  Arbitrary types for Network.Haskoin.Node.Message+-}+module Network.Haskoin.Test.Message+( ArbitraryMessageHeader(..)+, ArbitraryMessage(..)+) where++import Test.QuickCheck+    ( Arbitrary+    , arbitrary+    , oneof+    )++import Network.Haskoin.Test.Crypto+import Network.Haskoin.Test.Node+import Network.Haskoin.Test.Transaction+import Network.Haskoin.Test.Block++import Network.Haskoin.Node.Message++-- | Arbitrary MessageHeader+newtype ArbitraryMessageHeader = ArbitraryMessageHeader MessageHeader+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryMessageHeader where+    arbitrary = ArbitraryMessageHeader <$> do+        m <- arbitrary+        ArbitraryMessageCommand mc <- arbitrary+        p <- arbitrary+        ArbitraryCheckSum32 c <- arbitrary+        return $ MessageHeader m mc p c++-- | Arbitrary Message+newtype ArbitraryMessage = ArbitraryMessage Message+    deriving (Eq, Show)++instance Arbitrary ArbitraryMessage where+    arbitrary = ArbitraryMessage <$> oneof+        [ arbitrary >>= \(ArbitraryVersion x) -> return $ MVersion x+        , return MVerAck+        , arbitrary >>= \(ArbitraryAddr x) -> return $ MAddr x+        , arbitrary >>= \(ArbitraryInv x) -> return $ MInv x+        , arbitrary >>= \(ArbitraryGetData x) -> return $ MGetData x+        , arbitrary >>= \(ArbitraryNotFound x) -> return $ MNotFound x+        , arbitrary >>= \(ArbitraryGetBlocks x) -> return $ MGetBlocks x+        , arbitrary >>= \(ArbitraryGetHeaders x) -> return $ MGetHeaders x+        , arbitrary >>= \(ArbitraryTx x) -> return $ MTx x+        , arbitrary >>= \(ArbitraryBlock x) -> return $ MBlock x+        , arbitrary >>= \(ArbitraryMerkleBlock x) -> return $ MMerkleBlock x+        , arbitrary >>= \(ArbitraryHeaders x) -> return $ MHeaders x+        , return MGetAddr+        , arbitrary >>= \(ArbitraryFilterLoad x) -> return $ MFilterLoad x+        , arbitrary >>= \(ArbitraryFilterAdd x) -> return $ MFilterAdd x+        , return MFilterClear+        , arbitrary >>= \(ArbitraryPing x) -> return $ MPing x+        , arbitrary >>= \(ArbitraryPong x) -> return $ MPong x+        , arbitrary >>= \(ArbitraryAlert x) -> return $ MAlert x+        , arbitrary >>= \(ArbitraryReject x) -> return $ MReject x+        ]+
+ Network/Haskoin/Test/Node.hs view
@@ -0,0 +1,288 @@+{-|+  Arbitrary types for Network.Haskoin.Node+-}+module Network.Haskoin.Test.Node+( ArbitraryVarInt(..)+, ArbitraryVarString(..)+, ArbitraryNetworkAddress(..)+, ArbitraryNetworkAddressTime(..)+, ArbitraryInvType(..)+, ArbitraryInvVector(..)+, ArbitraryInv(..)+, ArbitraryVersion(..)+, ArbitraryAddr(..)+, ArbitraryAlert(..)+, ArbitraryReject(..)+, ArbitraryRejectCode(..)+, ArbitraryGetData(..)+, ArbitraryNotFound(..)+, ArbitraryPing(..)+, ArbitraryPong(..)+, ArbitraryBloomFlags(..)+, ArbitraryBloomFilter(..)+, ArbitraryFilterLoad(..)+, ArbitraryFilterAdd(..)+, ArbitraryMessageCommand(..)+) where++import Test.QuickCheck+    ( Arbitrary+    , arbitrary+    , elements+    , listOf1+    , oneof+    , choose+    , vectorOf+    )++import Data.Word (Word16, Word32)+import qualified Data.ByteString as BS (pack, empty)++import Network.Socket (SockAddr(..))++import Network.Haskoin.Test.Crypto+import Network.Haskoin.Node++-- | Arbitrary VarInt+newtype ArbitraryVarInt = ArbitraryVarInt VarInt+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryVarInt where+    arbitrary = ArbitraryVarInt . VarInt <$> arbitrary++-- | Arbitrary VarString+newtype ArbitraryVarString = ArbitraryVarString VarString+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryVarString where+    arbitrary = do+        ArbitraryByteString bs <- arbitrary+        return $ ArbitraryVarString $ VarString bs++-- | Arbitrary NetworkAddress+newtype ArbitraryNetworkAddress = ArbitraryNetworkAddress NetworkAddress+    deriving (Eq, Show)++instance Arbitrary ArbitraryNetworkAddress where+    arbitrary = do+        s <- arbitrary+        a <- arbitrary+        p <- arbitrary+        ArbitraryNetworkAddress . (NetworkAddress s) <$> oneof+            [ do+                b <- arbitrary+                c <- arbitrary+                d <- arbitrary+                return $ SockAddrInet6 (fromIntegral p) 0 (a,b,c,d) 0+            , return $ SockAddrInet (fromIntegral (p :: Word16)) a+            ]++-- | Arbitrary NetworkAddressTime+newtype ArbitraryNetworkAddressTime+    = ArbitraryNetworkAddressTime (Word32, NetworkAddress)++instance Arbitrary ArbitraryNetworkAddressTime where+    arbitrary = do+        w <- arbitrary+        ArbitraryNetworkAddress a <- arbitrary+        return $ ArbitraryNetworkAddressTime (w,a)++-- | Arbitrary InvType+newtype ArbitraryInvType = ArbitraryInvType InvType+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryInvType where+    arbitrary = ArbitraryInvType <$> elements+        [InvError, InvTx, InvBlock, InvMerkleBlock]++-- | Arbitrary InvVector+newtype ArbitraryInvVector = ArbitraryInvVector InvVector+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryInvVector where+    arbitrary = do+        ArbitraryInvType t <- arbitrary+        ArbitraryHash256 h <- arbitrary+        return $ ArbitraryInvVector $ InvVector t h++-- | Arbitrary non-empty Inv+newtype ArbitraryInv = ArbitraryInv Inv+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryInv where+    arbitrary = do+        vs <- listOf1 arbitrary+        return $ ArbitraryInv $ Inv $ map (\(ArbitraryInvVector v) -> v) vs++-- | Arbitrary Version+newtype ArbitraryVersion = ArbitraryVersion Version+    deriving (Eq, Show)++instance Arbitrary ArbitraryVersion where+    arbitrary = do+        v <- arbitrary+        s <- arbitrary+        t <- arbitrary+        ArbitraryNetworkAddress nr <- arbitrary+        ArbitraryNetworkAddress ns <- arbitrary+        n <- arbitrary+        ArbitraryVarString a <- arbitrary+        h <- arbitrary+        r <- arbitrary+        return $ ArbitraryVersion $ Version v s t nr ns n a h r++-- | Arbitrary non-empty Addr+newtype ArbitraryAddr = ArbitraryAddr Addr+    deriving (Eq, Show)++instance Arbitrary ArbitraryAddr where+    arbitrary = do+       vs <- listOf1 arbitrary+       return $ ArbitraryAddr $ Addr $+           map (\(ArbitraryNetworkAddressTime x) -> x) vs++-- | Arbitrary alert with random payload and signature. Signature is not+-- valid.+newtype ArbitraryAlert = ArbitraryAlert Alert+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryAlert where+    arbitrary = do+        ArbitraryVarString p <- arbitrary+        ArbitraryVarString s <- arbitrary+        return $ ArbitraryAlert $ Alert p s++-- | Arbitrary Reject+newtype ArbitraryReject = ArbitraryReject Reject+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryReject where+    arbitrary = do+        ArbitraryMessageCommand m <- arbitrary+        ArbitraryRejectCode c <- arbitrary+        ArbitraryVarString s <- arbitrary+        d <- oneof [ return BS.empty+                   , BS.pack <$> vectorOf 32 arbitrary+                   ]+        return $ ArbitraryReject $ Reject m c s d++-- | Arbitrary RejectCode+newtype ArbitraryRejectCode = ArbitraryRejectCode RejectCode+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryRejectCode where+    arbitrary = ArbitraryRejectCode <$> elements+        [ RejectMalformed+        , RejectInvalid+        , RejectInvalid+        , RejectDuplicate+        , RejectNonStandard+        , RejectDust+        , RejectInsufficientFee+        , RejectCheckpoint+        ]++-- | Arbitrary non-empty GetData+newtype ArbitraryGetData = ArbitraryGetData GetData+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryGetData where+    arbitrary = do+        vs <- listOf1 arbitrary+        return $ ArbitraryGetData $ GetData $+            map (\(ArbitraryInvVector x) -> x) vs++-- | Arbitrary NotFound+newtype ArbitraryNotFound = ArbitraryNotFound NotFound+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryNotFound where+    arbitrary = do+        vs <- listOf1 arbitrary+        return $ ArbitraryNotFound $ NotFound $+            map (\(ArbitraryInvVector x) -> x) vs++-- | Arbitrary Ping+newtype ArbitraryPing = ArbitraryPing Ping+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPing where+    arbitrary = ArbitraryPing . Ping <$> arbitrary++-- | Arbitrary Pong+newtype ArbitraryPong = ArbitraryPong Pong+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPong where+    arbitrary = ArbitraryPong . Pong <$> arbitrary++-- | Arbitrary bloom filter flags+data ArbitraryBloomFlags = ArbitraryBloomFlags BloomFlags+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryBloomFlags where+    arbitrary = ArbitraryBloomFlags <$> elements+        [ BloomUpdateNone+        , BloomUpdateAll+        , BloomUpdateP2PubKeyOnly+        ]++-- | Arbitrary bloom filter with its corresponding number of elements+-- and false positive rate.+data ArbitraryBloomFilter = ArbitraryBloomFilter Int Double BloomFilter+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryBloomFilter where+    arbitrary = do+        n     <- choose (0,100000)+        fp    <- choose (1e-8,1)+        tweak <- arbitrary+        ArbitraryBloomFlags fl <- arbitrary+        return $ ArbitraryBloomFilter n fp $ bloomCreate n fp tweak fl++-- | Arbitrary FilterLoad+data ArbitraryFilterLoad = ArbitraryFilterLoad FilterLoad+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryFilterLoad where+    arbitrary = do+        ArbitraryBloomFilter _ _ bf <- arbitrary+        return $ ArbitraryFilterLoad $ FilterLoad bf++-- | Arbitrary FilterAdd+data ArbitraryFilterAdd = ArbitraryFilterAdd FilterAdd+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryFilterAdd where+    arbitrary = do+        ArbitraryByteString bs <- arbitrary+        return $ ArbitraryFilterAdd $ FilterAdd bs+++-- | Arbitrary MessageCommand+newtype ArbitraryMessageCommand = ArbitraryMessageCommand MessageCommand+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryMessageCommand where+    arbitrary = ArbitraryMessageCommand <$> elements+        [ MCVersion+        , MCVerAck+        , MCAddr+        , MCInv+        , MCGetData+        , MCNotFound+        , MCGetBlocks+        , MCGetHeaders+        , MCTx+        , MCBlock+        , MCMerkleBlock+        , MCHeaders+        , MCGetAddr+        , MCFilterLoad+        , MCFilterAdd+        , MCFilterClear+        , MCPing+        , MCPong+        , MCAlert+        ]+
+ Network/Haskoin/Test/Script.hs view
@@ -0,0 +1,413 @@+{-|+  Arbitrary types for Network.Haskoin.Script+-}+module Network.Haskoin.Test.Script+( ArbitraryScriptOp(..)+, ArbitraryScript(..)+, ArbitraryIntScriptOp(..)+, ArbitraryPushDataType(..)+, ArbitraryTxSignature(..)+, ArbitrarySigHash(..)+, ArbitraryValidSigHash(..)+, ArbitraryMSParam(..)+, ArbitraryScriptOutput(..)+, ArbitrarySimpleOutput(..)+, ArbitraryPKOutput(..)+, ArbitraryPKHashOutput(..)+, ArbitraryMSOutput(..)+, ArbitraryMSCOutput(..)+, ArbitrarySHOutput(..)+, ArbitraryScriptInput(..)+, ArbitrarySimpleInput(..)+, ArbitraryPKInput(..)+, ArbitraryPKHashInput(..)+, ArbitraryPKHashCInput(..)+, ArbitraryMSInput(..)+, ArbitrarySHInput(..)+, ArbitraryMulSigSHCInput(..)+) where++import Test.QuickCheck+    ( Arbitrary+    , arbitrary+    , oneof+    , choose+    , vectorOf+    , elements+    )++import Data.Bits (testBit)++import Network.Haskoin.Transaction.Types+import Network.Haskoin.Test.Crypto+import Network.Haskoin.Script+import Network.Haskoin.Crypto++-- | Arbitrary Script with random script ops+newtype ArbitraryScript = ArbitraryScript Script+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryScript where+    arbitrary = do+        vs <- arbitrary+        return $ ArbitraryScript $ Script $ map f vs+      where+        f (ArbitraryScriptOp op) = op++-- | Arbitrary ScriptOp (push operations have random data)+newtype ArbitraryScriptOp = ArbitraryScriptOp ScriptOp+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryScriptOp where+    arbitrary = ArbitraryScriptOp <$> oneof+        [ -- Pushing Data+         arbitrary >>= \(ArbitraryNotNullByteString bs) ->+            return $ opPushData bs+        ,return OP_0+        ,return OP_1NEGATE+        ,return OP_RESERVED+        ,return OP_1 , return OP_2 , return OP_3 , return OP_4+        ,return OP_5 , return OP_6 , return OP_7 , return OP_8+        ,return OP_9 , return OP_10, return OP_11, return OP_12+        ,return OP_13, return OP_14, return OP_15, return OP_16++        -- Flow control+        ,return OP_NOP+        ,return OP_VER+        ,return OP_IF+        ,return OP_NOTIF+        ,return OP_VERIF+        ,return OP_VERNOTIF+        ,return OP_ELSE+        ,return OP_ENDIF+        ,return OP_VERIFY+        ,return OP_RETURN++        -- Stack operations+        ,return OP_TOALTSTACK+        ,return OP_FROMALTSTACK+        ,return OP_IFDUP+        ,return OP_DEPTH+        ,return OP_DROP+        ,return OP_DUP+        ,return OP_NIP+        ,return OP_OVER+        ,return OP_PICK+        ,return OP_ROLL+        ,return OP_ROT+        ,return OP_SWAP+        ,return OP_TUCK+        ,return OP_2DROP+        ,return OP_2DUP+        ,return OP_3DUP+        ,return OP_2OVER+        ,return OP_2ROT+        ,return OP_2SWAP++        -- Splice+        ,return OP_CAT+        ,return OP_SUBSTR+        ,return OP_LEFT+        ,return OP_RIGHT+        ,return OP_SIZE++        -- Bitwise logic+        ,return OP_INVERT+        ,return OP_AND+        ,return OP_OR+        ,return OP_XOR+        ,return OP_EQUAL+        ,return OP_EQUALVERIFY+        ,return OP_RESERVED1+        ,return OP_RESERVED2++        -- Arithmetic+        ,return OP_1ADD+        ,return OP_1SUB+        ,return OP_2MUL+        ,return OP_2DIV+        ,return OP_NEGATE+        ,return OP_ABS+        ,return OP_NOT+        ,return OP_0NOTEQUAL+        ,return OP_ADD+        ,return OP_SUB+        ,return OP_MUL+        ,return OP_DIV+        ,return OP_MOD+        ,return OP_LSHIFT+        ,return OP_RSHIFT+        ,return OP_BOOLAND+        ,return OP_BOOLOR+        ,return OP_NUMEQUAL+        ,return OP_NUMEQUALVERIFY+        ,return OP_NUMNOTEQUAL+        ,return OP_LESSTHAN+        ,return OP_GREATERTHAN+        ,return OP_LESSTHANOREQUAL+        ,return OP_GREATERTHANOREQUAL+        ,return OP_MIN+        ,return OP_MAX+        ,return OP_WITHIN++        -- Crypto+        ,return OP_RIPEMD160+        ,return OP_SHA1+        ,return OP_SHA256+        ,return OP_HASH160+        ,return OP_HASH256+        ,return OP_CODESEPARATOR+        ,return OP_CHECKSIG+        ,return OP_CHECKSIGVERIFY+        ,return OP_CHECKMULTISIG+        ,return OP_CHECKMULTISIGVERIFY++        -- Expansion+        ,return OP_NOP1, return OP_NOP2+        ,return OP_NOP3, return OP_NOP4+        ,return OP_NOP5, return OP_NOP6+        ,return OP_NOP7, return OP_NOP8+        ,return OP_NOP9, return OP_NOP10++        -- Other+        ,return OP_PUBKEYHASH+        ,return OP_PUBKEY+        ,return $ OP_INVALIDOPCODE 0xff+        ]++-- | Arbtirary ScriptOp with a value in [OP_1 .. OP_16]+newtype ArbitraryIntScriptOp = ArbitraryIntScriptOp ScriptOp+    deriving (Eq, Show)++instance Arbitrary ArbitraryIntScriptOp where+    arbitrary = ArbitraryIntScriptOp <$> elements+        [ 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+        ]++-- | Arbitrary PushDataType+newtype ArbitraryPushDataType = ArbitraryPushDataType PushDataType+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPushDataType where+    arbitrary = ArbitraryPushDataType <$> elements+        [ OPCODE, OPDATA1, OPDATA2, OPDATA4 ]++-- | Arbitrary SigHash (including invalid/unknown sighash codes)+newtype ArbitrarySigHash = ArbitrarySigHash SigHash+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySigHash where+    arbitrary = ArbitrarySigHash <$> oneof+        [ SigAll    <$> arbitrary+        , SigNone   <$> arbitrary+        , SigSingle <$> arbitrary+        , f+        ]+      where+        f = do+            -- avoid valid SigHash bytes+            w <- elements $ 0x00 : 0x80 : [0x04..0x7f] ++ [0x84..0xff]+            return $ SigUnknown (testBit w 7) w++-- | Arbitrary valid SigHash+newtype ArbitraryValidSigHash = ArbitraryValidSigHash SigHash+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryValidSigHash where+    arbitrary = ArbitraryValidSigHash <$> oneof+        [ SigAll    <$> arbitrary+        , SigNone   <$> arbitrary+        , SigSingle <$> arbitrary+        ]++-- | Arbitrary message hash, private key and corresponding TxSignature. The+-- signature is generated deterministically using a random message and a+-- random private key.+data ArbitraryTxSignature =+    ArbitraryTxSignature TxHash PrvKey TxSignature+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryTxSignature where+    arbitrary = do+        ArbitrarySignature msg key sig <- arbitrary+        ArbitrarySigHash sh <- arbitrary+        let txsig = TxSignature sig sh+        return $ ArbitraryTxSignature (TxHash msg) key txsig++-- | Arbitrary m of n parameters+data ArbitraryMSParam = ArbitraryMSParam Int Int+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryMSParam where+    arbitrary = do+        m <- choose (1,16)+        n <- choose (m,16)+        return $ ArbitraryMSParam m n++-- | Arbitrary ScriptOutput (Can by any valid type)+newtype ArbitraryScriptOutput = ArbitraryScriptOutput ScriptOutput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryScriptOutput where+    arbitrary = ArbitraryScriptOutput <$> oneof+        [ arbitrary >>= \(ArbitraryPKOutput o) -> return o+        , arbitrary >>= \(ArbitraryPKHashOutput o) -> return o+        , arbitrary >>= \(ArbitraryMSOutput o) -> return o+        , arbitrary >>= \(ArbitrarySHOutput o) -> return o+        ]++-- | Arbitrary ScriptOutput of type PayPK, PayPKHash or PayMS+-- (Not PayScriptHash)+newtype ArbitrarySimpleOutput = ArbitrarySimpleOutput ScriptOutput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySimpleOutput where+    arbitrary = ArbitrarySimpleOutput <$> oneof+        [ arbitrary >>= \(ArbitraryPKOutput o) -> return o+        , arbitrary >>= \(ArbitraryPKHashOutput o) -> return o+        , arbitrary >>= \(ArbitraryMSOutput o) -> return o+        ]++-- | Arbitrary ScriptOutput of type PayPK+newtype ArbitraryPKOutput = ArbitraryPKOutput ScriptOutput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPKOutput where+    arbitrary = do+        ArbitraryPubKey _ key <- arbitrary+        return $ ArbitraryPKOutput $ PayPK key++-- | Arbitrary ScriptOutput of type PayPKHash+newtype ArbitraryPKHashOutput = ArbitraryPKHashOutput ScriptOutput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPKHashOutput where+    arbitrary = do+        ArbitraryPubKeyAddress a <- arbitrary+        return $ ArbitraryPKHashOutput $ PayPKHash a++-- | Arbitrary ScriptOutput of type PayMS+newtype ArbitraryMSOutput = ArbitraryMSOutput ScriptOutput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryMSOutput where+    arbitrary = do+        ArbitraryMSParam m n <- arbitrary+        keys <- map f <$> vectorOf n arbitrary+        return $ ArbitraryMSOutput $ PayMulSig keys m+      where+        f (ArbitraryPubKey _ key) = key++-- | Arbitrary ScriptOutput of type PayMS containing only compressed keys+newtype ArbitraryMSCOutput = ArbitraryMSCOutput ScriptOutput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryMSCOutput where+    arbitrary = do+        ArbitraryMSParam m n <- arbitrary+        keys <- map f <$> vectorOf n arbitrary+        return $ ArbitraryMSCOutput $ PayMulSig keys m+      where+        f (ArbitraryPubKeyC _ key) = toPubKeyG key++-- | Arbitrary ScriptOutput of type PayScriptHash+newtype ArbitrarySHOutput = ArbitrarySHOutput ScriptOutput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySHOutput where+    arbitrary = do+        ArbitraryScriptAddress a <- arbitrary+        return $ ArbitrarySHOutput $ PayScriptHash a++-- | Arbitrary ScriptInput+newtype ArbitraryScriptInput = ArbitraryScriptInput ScriptInput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryScriptInput where+    arbitrary = ArbitraryScriptInput <$> oneof+        [ arbitrary >>= \(ArbitraryPKInput i) -> return i+        , arbitrary >>= \(ArbitraryPKHashInput i) -> return i+        , arbitrary >>= \(ArbitraryMSInput i) -> return i+        , arbitrary >>= \(ArbitrarySHInput i) -> return i+        ]++-- | Arbitrary ScriptInput of type SpendPK, SpendPKHash or SpendMulSig+-- (not ScriptHashInput)+newtype ArbitrarySimpleInput = ArbitrarySimpleInput ScriptInput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySimpleInput where+    arbitrary = ArbitrarySimpleInput <$> oneof+        [ arbitrary >>= \(ArbitraryPKInput i) -> return i+        , arbitrary >>= \(ArbitraryPKHashInput i) -> return i+        , arbitrary >>= \(ArbitraryMSInput i) -> return i+        ]++-- | Arbitrary ScriptInput of type SpendPK+newtype ArbitraryPKInput = ArbitraryPKInput ScriptInput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPKInput where+    arbitrary = ArbitraryPKInput . RegularInput . SpendPK <$>+        (arbitrary >>= \(ArbitraryTxSignature _ _ sig) -> return sig)++-- | Arbitrary ScriptInput of type SpendPK+newtype ArbitraryPKHashInput = ArbitraryPKHashInput ScriptInput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPKHashInput where+    arbitrary = do+        sig <- arbitrary >>= \(ArbitraryTxSignature _ _ sig) -> return sig+        ArbitraryPubKey _ key <- arbitrary+        return $ ArbitraryPKHashInput $ RegularInput $ SpendPKHash sig key++-- | Arbitrary ScriptInput of type SpendPK with a compressed public key+newtype ArbitraryPKHashCInput = ArbitraryPKHashCInput ScriptInput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPKHashCInput where+    arbitrary = do+        sig <- arbitrary >>= \(ArbitraryTxSignature _ _ sig) -> return sig+        ArbitraryPubKeyC _ key <- arbitrary+        return $ ArbitraryPKHashCInput $ RegularInput $+            SpendPKHash sig $ toPubKeyG key++-- | Arbitrary ScriptInput of type SpendMulSig+newtype ArbitraryMSInput = ArbitraryMSInput ScriptInput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryMSInput where+    arbitrary = do+        ArbitraryMSParam m _ <- arbitrary+        sigs <- vectorOf m f+        return $ ArbitraryMSInput $ RegularInput $ SpendMulSig sigs+      where+        f = arbitrary >>= \(ArbitraryTxSignature _ _ sig) -> return sig++-- | Arbitrary ScriptInput of type ScriptHashInput+newtype ArbitrarySHInput = ArbitrarySHInput ScriptInput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySHInput where+    arbitrary = do+        ArbitrarySimpleInput i <- arbitrary+        ArbitrarySimpleOutput o <- arbitrary+        return $ ArbitrarySHInput $ ScriptHashInput (getRegularInput i) o++-- | Arbitrary ScriptInput of type ScriptHashInput containing a RedeemScript+-- of type PayMulSig and an input of type SpendMulSig. Only compressed keys+-- are used.+newtype ArbitraryMulSigSHCInput = ArbitraryMulSigSHCInput ScriptInput+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryMulSigSHCInput where+    arbitrary = do+        ArbitraryMSCOutput rdm@(PayMulSig _ m) <- arbitrary+        sigs <- vectorOf m f+        return $ ArbitraryMulSigSHCInput $ ScriptHashInput (SpendMulSig sigs) rdm+      where+        f = arbitrary >>= \(ArbitraryTxSignature _ _ sig) -> return sig+
+ Network/Haskoin/Test/Transaction.hs view
@@ -0,0 +1,307 @@+{-|+  Arbitrary types for Network.Haskoin.Transaction+-}+module Network.Haskoin.Test.Transaction+( ArbitrarySatoshi(..)+, ArbitraryTx(..)+, ArbitraryTxHash(..)+, ArbitraryTxIn(..)+, ArbitraryTxOut(..)+, ArbitraryOutPoint(..)+, ArbitraryCoinbaseTx(..)+, ArbitraryAddrOnlyTx(..)+, ArbitraryAddrOnlyTxIn(..)+, ArbitraryAddrOnlyTxOut(..)+, ArbitrarySigInput(..)+, ArbitraryPKSigInput(..)+, ArbitraryPKHashSigInput(..)+, ArbitraryMSSigInput(..)+, ArbitrarySHSigInput(..)+, ArbitrarySigningData(..)+, ArbitraryPartialTxs(..)+) where++import Test.QuickCheck+    ( Arbitrary+    , arbitrary+    , vectorOf+    , oneof+    , choose+    , elements+    )++import Control.Monad (forM)++import Data.Word (Word64)+import Data.List (permutations, nubBy, nub)+import qualified Data.ByteString as BS (empty)++import Network.Haskoin.Test.Crypto+import Network.Haskoin.Test.Script++import Network.Haskoin.Transaction+import Network.Haskoin.Script+import Network.Haskoin.Crypto+import Network.Haskoin.Constants+import Network.Haskoin.Util++newtype ArbitraryTxHash = ArbitraryTxHash TxHash+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryTxHash where+    arbitrary = do+        ArbitraryHash256 h <- arbitrary+        return $ ArbitraryTxHash $ TxHash h++-- | Arbitrary amount of Satoshi as Word64 (Between 1 and 21e14)+newtype ArbitrarySatoshi = ArbitrarySatoshi Word64+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySatoshi where+    arbitrary = ArbitrarySatoshi <$> choose (1, maxSatoshi)++instance Coin ArbitrarySatoshi where+    coinValue (ArbitrarySatoshi v) = v++-- | Arbitrary OutPoint+newtype ArbitraryOutPoint = ArbitraryOutPoint OutPoint+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryOutPoint where+    arbitrary = do+        op <- do+            ArbitraryTxHash tx <- arbitrary+            i  <- arbitrary+            return $ OutPoint tx i+        return $ ArbitraryOutPoint op++-- | Arbitrary TxOut+newtype ArbitraryTxOut = ArbitraryTxOut TxOut+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryTxOut where+    arbitrary = do+        ArbitrarySatoshi v <- arbitrary+        ArbitraryScriptOutput out <- arbitrary+        return $ ArbitraryTxOut $ TxOut v $ encodeOutputBS out++-- | Arbitrary TxIn+newtype ArbitraryTxIn = ArbitraryTxIn TxIn+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryTxIn where+    arbitrary = do+        ArbitraryOutPoint o <- arbitrary+        ArbitraryScriptInput inp <- arbitrary+        s <- arbitrary+        return $ ArbitraryTxIn $ TxIn o (encodeInputBS inp) s++-- | Arbitrary Tx+newtype ArbitraryTx = ArbitraryTx Tx+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryTx where+    arbitrary = do+        v <- arbitrary+        ni <- choose (0,5)+        no <- choose (0,5)+        inps <- vectorOf ni $ arbitrary >>= \(ArbitraryTxIn i) -> return i+        outs <- vectorOf no $ arbitrary >>= \(ArbitraryTxOut o) -> return o+        let uniqueInps = nubBy (\a b -> prevOutput a == prevOutput b) inps+        t <- arbitrary+        return $ ArbitraryTx $ Tx v uniqueInps outs t++-- | Arbitrary CoinbaseTx+newtype ArbitraryCoinbaseTx = ArbitraryCoinbaseTx CoinbaseTx+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryCoinbaseTx where+    arbitrary = do+        v <- arbitrary+        ArbitraryOutPoint op <- arbitrary+        ArbitraryByteString d <- arbitrary+        s <- arbitrary+        no <- choose (0,5)+        outs <- vectorOf no $ arbitrary >>= \(ArbitraryTxOut o) -> return o+        t <- arbitrary+        return $ ArbitraryCoinbaseTx $ CoinbaseTx v op d s outs t++-- | Arbitrary Tx containing only inputs of type SpendPKHash, SpendScriptHash+-- (multisig) and outputs of type PayPKHash and PaySH. Only compressed+-- public keys are used.+newtype ArbitraryAddrOnlyTx = ArbitraryAddrOnlyTx Tx+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryAddrOnlyTx where+    arbitrary = do+        v <- arbitrary+        ni <- choose (0,5)+        no <- choose (0,5)+        inps <- vectorOf ni $+            arbitrary >>= \(ArbitraryAddrOnlyTxIn i) -> return i+        outs <- vectorOf no $+            arbitrary >>= \(ArbitraryAddrOnlyTxOut o) -> return o+        t <- arbitrary+        return $ ArbitraryAddrOnlyTx $ Tx v inps outs t++-- | Arbitrary TxIn that can only be of type SpendPKHash or+-- SpendScriptHash (multisig). Only compressed public keys are used.+newtype ArbitraryAddrOnlyTxIn = ArbitraryAddrOnlyTxIn TxIn+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryAddrOnlyTxIn where+    arbitrary = do+        ArbitraryOutPoint o <- arbitrary+        inp <- oneof+            [ arbitrary >>= \(ArbitraryPKHashCInput i) -> return i+            , arbitrary >>= \(ArbitraryMulSigSHCInput i) -> return i+            ]+        s <- arbitrary+        return $ ArbitraryAddrOnlyTxIn $ TxIn o (encodeInputBS inp) s++-- | Arbitrary TxOut that can only be of type PayPKHash or PaySH+newtype ArbitraryAddrOnlyTxOut = ArbitraryAddrOnlyTxOut TxOut+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryAddrOnlyTxOut where+    arbitrary = do+        ArbitrarySatoshi v <- arbitrary+        out <- oneof+            [ arbitrary >>= \(ArbitraryPKHashOutput o) -> return o+            , arbitrary >>= \(ArbitrarySHOutput o) -> return o+            ]+        return $ ArbitraryAddrOnlyTxOut $ TxOut v $ encodeOutputBS out++-- | Arbitrary SigInput with the corresponding private keys used+-- to generate the ScriptOutput or RedeemScript+data ArbitrarySigInput = ArbitrarySigInput SigInput [PrvKey]+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySigInput where+    arbitrary = do+        (si, ks) <- oneof+            [ arbitrary >>= \(ArbitraryPKSigInput si k) -> return (si, [k])+            , arbitrary >>= \(ArbitraryPKHashSigInput si k) -> return (si, [k])+            , arbitrary >>= \(ArbitraryMSSigInput si ks) -> return (si, ks)+            , arbitrary >>= \(ArbitrarySHSigInput si ks) -> return (si, ks)+            ]+        return $ ArbitrarySigInput si ks++-- | Arbitrary SigInput with a ScriptOutput of type PayPK+data ArbitraryPKSigInput = ArbitraryPKSigInput SigInput PrvKey+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPKSigInput where+    arbitrary = do+        ArbitraryPrvKey k <- arbitrary+        let out = PayPK $ derivePubKey k+        ArbitraryOutPoint op <- arbitrary+        ArbitraryValidSigHash sh <- arbitrary+        return $ ArbitraryPKSigInput (SigInput out op sh Nothing) k++-- | Arbitrary SigInput with a ScriptOutput of type PayPKHash+data ArbitraryPKHashSigInput = ArbitraryPKHashSigInput SigInput PrvKey+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPKHashSigInput where+    arbitrary = do+        ArbitraryPrvKey k <- arbitrary+        let out = PayPKHash $ pubKeyAddr $ derivePubKey k+        ArbitraryOutPoint op <- arbitrary+        ArbitraryValidSigHash sh <- arbitrary+        return $ ArbitraryPKHashSigInput (SigInput out op sh Nothing) k++-- | Arbitrary SigInput with a ScriptOutput of type PayMulSig+data ArbitraryMSSigInput = ArbitraryMSSigInput SigInput [PrvKey]+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryMSSigInput where+    arbitrary = do+        ArbitraryMSParam m n <- arbitrary+        ks <- map (\(ArbitraryPrvKey k) -> k) <$> vectorOf n arbitrary+        let out = PayMulSig (map derivePubKey ks) m+        ArbitraryOutPoint op <- arbitrary+        ArbitraryValidSigHash sh <- arbitrary+        perm <- choose (0,n-1)+        let ksPerm = take m $ permutations ks !! perm+        return $ ArbitraryMSSigInput (SigInput out op sh Nothing) ksPerm++-- | Arbitrary SigInput with  ScriptOutput of type PaySH and a RedeemScript+data ArbitrarySHSigInput = ArbitrarySHSigInput SigInput [PrvKey]+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySHSigInput where+    arbitrary = do+        (rdm, ks, op, sh) <- oneof+            [ a <$> arbitrary, b <$> arbitrary, c <$> arbitrary ]+        let out = PayScriptHash $ scriptAddr rdm+        return $ ArbitrarySHSigInput (SigInput out op sh $ Just rdm) ks+      where+        a (ArbitraryPKSigInput (SigInput o op sh _) k) = (o, [k], op, sh)+        b (ArbitraryPKHashSigInput (SigInput o op sh _) k) = (o, [k], op, sh)+        c (ArbitraryMSSigInput (SigInput o op sh _) ks) = (o, ks, op, sh)++-- | Arbitrary Tx (empty TxIn), SigInputs and PrvKeys that can be passed to+-- signTx or detSignTx to fully sign the Tx.+data ArbitrarySigningData = ArbitrarySigningData Tx [SigInput] [PrvKey]+    deriving (Eq, Show, Read)++instance Arbitrary ArbitrarySigningData where+    arbitrary = do+        v <- arbitrary+        ni <- choose (1,5)+        no <- choose (1,5)+        sigis <- map f <$> vectorOf ni arbitrary+        let uSigis = nubBy (\(a,_) (b,_) -> sigDataOP a == sigDataOP b) sigis+        inps <- forM uSigis $ \(s,_) -> do+            sq <- arbitrary+            return $ TxIn (sigDataOP s) BS.empty sq+        outs <- map (\(ArbitraryTxOut o) -> o) <$> vectorOf no arbitrary+        l <- arbitrary+        perm <- choose (0, length inps - 1)+        let tx   = Tx v (permutations inps !! perm) outs l+            keys = concat $ map snd uSigis+        return $ ArbitrarySigningData tx (map fst uSigis) keys+      where+        f (ArbitrarySigInput s ks) = (s,ks)++data ArbitraryPartialTxs =+    ArbitraryPartialTxs [Tx] [(ScriptOutput, OutPoint, Int, Int)]+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryPartialTxs where+    arbitrary = do+        tx <- arbitraryEmptyTx+        res <- forM (map prevOutput $ txIn tx) $ \op -> do+            (so, rdmM, prvs, m, n) <- arbitraryData+            txs <- mapM (singleSig so rdmM tx op) prvs+            return (txs, (so, op, m, n))+        return $ ArbitraryPartialTxs (concat $ map fst res) (map snd res)+      where+        singleSig so rdmM tx op prv = do+            ArbitraryValidSigHash sh <- arbitrary+            let sigi = SigInput so op sh rdmM+            return $ fromRight $ signTx tx [sigi] [prv]+        arbitraryData = do+            ArbitraryMSParam m n <- arbitrary+            nPrv <- choose (m,n)+            keys <- vectorOf n $+                (\(ArbitraryPubKey k p) -> (k, p)) <$> arbitrary+            perm <- choose (0, length keys - 1)+            let pubKeys = map snd keys+                prvKeys = take nPrv $ permutations (map fst keys) !! perm+            let so = PayMulSig pubKeys m+            elements [ (so, Nothing, prvKeys, m, n)+                     , (PayScriptHash $ scriptAddr so, Just so, prvKeys, m, n)+                     ]+        arbitraryEmptyTx = do+            v <- arbitrary+            no <- choose (1,5)+            ni <- choose (1,5)+            outs <- vectorOf no $ (\(ArbitraryTxOut o) -> o) <$> arbitrary+            ops <- vectorOf ni $ (\(ArbitraryOutPoint op) -> op) <$> arbitrary+            t <- arbitrary+            s <- arbitrary+            return $ Tx v (map (\op -> TxIn op BS.empty s) (nub ops)) outs t++
+ Network/Haskoin/Test/Util.hs view
@@ -0,0 +1,48 @@+module Network.Haskoin.Test.Util+( ArbitraryByteString(..)+, ArbitraryNotNullByteString(..)+, ArbitraryUTCTime(..)+) where++import Test.QuickCheck+    ( Arbitrary+    , Gen+    , arbitrary+    , choose+    , listOf1+    )++import Data.Word (Word32)+import Data.Time.Clock (UTCTime(..))+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)+import qualified Data.ByteString as BS (ByteString, pack, drop)++-- | Arbitrary strict ByteString+data ArbitraryByteString = ArbitraryByteString BS.ByteString+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryByteString where+    arbitrary = do+        bs <- BS.pack `fmap` arbitrary+        n <- choose (0, 2)+        -- to give us some with non-0 offset+        return $ ArbitraryByteString $ BS.drop n bs++-- | Arbitrary strict ByteString that is not empty+data ArbitraryNotNullByteString = ArbitraryNotNullByteString BS.ByteString+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryNotNullByteString where+    arbitrary = do+        bs <- BS.pack `fmap` (listOf1 arbitrary)+        return $ ArbitraryNotNullByteString bs++-- | Arbitrary UTCTime that generates dates after 01 Jan 1970 01:00:00 CET+newtype ArbitraryUTCTime = ArbitraryUTCTime UTCTime+    deriving (Eq, Show, Read)++instance Arbitrary ArbitraryUTCTime where+    arbitrary = do+        w <- (arbitrary :: Gen Word32)+        return $ ArbitraryUTCTime $ posixSecondsToUTCTime $ realToFrac w+
+ Network/Haskoin/Transaction.hs view
@@ -0,0 +1,46 @@+{-|+  This package provides functions for building and signing both simple+  transactions and multisignature transactions.+-}+module Network.Haskoin.Transaction+(+  -- *Transaction Types+  Tx(..)+, TxIn(..)+, TxOut(..)+, OutPoint(..)+, CoinbaseTx(..)+, TxHash(..)+, txHash+, hexToTxHash+, txHashToHex+, nosigTxHash+, cbHash++  -- *Build Transactions+, buildTx+, buildAddrTx++  -- *Sign Transactions+, SigInput(..)+, signTx+, signInput+, mergeTxs+, verifyStdTx+, verifyStdInput++  -- *Coin selection+, Coin(..)+, chooseCoins+, chooseCoinsSink+, chooseMSCoins+, chooseMSCoinsSink+, guessTxSize+, getFee+, getMSFee++) where++import Network.Haskoin.Transaction.Builder+import Network.Haskoin.Transaction.Types+
+ Network/Haskoin/Transaction/Builder.hs view
@@ -0,0 +1,430 @@+module Network.Haskoin.Transaction.Builder+( Coin(..)+, buildTx+, buildAddrTx+, SigInput(..)+, signTx+, signInput+, mergeTxs+, verifyStdTx+, verifyStdInput+, guessTxSize+, chooseCoins+, chooseCoinsSink+, chooseMSCoins+, chooseMSCoinsSink+, getFee+, getMSFee+) where++import Control.Arrow (first)+import Control.Monad (mzero, foldM, unless)+import Control.Monad.Identity (runIdentity)+import Control.DeepSeq (NFData, rnf)++import Data.Maybe (catMaybes, maybeToList, isJust, fromJust, fromMaybe)+import Data.List (find, nub)+import Data.Word (Word64)+import Data.Conduit (Sink, await, ($$))+import Data.Conduit.List (sourceList)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS (length, replicate, empty, null)+import Data.String.Conversions (cs)+import Data.Aeson+    ( Value (Object)+    , FromJSON+    , ToJSON+    , (.=), (.:), (.:?)+    , object+    , parseJSON+    , toJSON+    )++import Network.Haskoin.Util+import Network.Haskoin.Crypto+import Network.Haskoin.Node.Types+import Network.Haskoin.Script+import Network.Haskoin.Transaction.Types++-- | Any type can be used as a Coin if it can provide a value in Satoshi.+-- The value is used in coin selection algorithms.+class Coin c where+    coinValue :: c -> Word64++-- | Coin selection algorithm for normal (non-multisig) transactions. This+-- function returns the selected coins together with the amount of change to+-- send back to yourself, taking the fee into account.+chooseCoins :: Coin c+            => Word64 -- ^ Target price to pay.+            -> Word64 -- ^ Fee price per 1000 bytes.+            -> Bool   -- ^ Try to find better solution when one is found+            -> [c]    -- ^ List of ordered coins to choose from.+            -> Either String ([c], Word64)+               -- ^ Coin selection result and change amount.+chooseCoins target kbfee continue coins =+    runIdentity $ sourceList coins $$ chooseCoinsSink target kbfee continue++-- | Coin selection algorithm for normal (non-multisig) transactions. This+-- function returns the selected coins together with the amount of change to+-- send back to yourself, taking the fee into account. This version uses a+-- Sink if you need conduit-based coin selection.+chooseCoinsSink :: (Monad m, Coin c)+                => Word64 -- ^ Target price to pay.+                -> Word64 -- ^ Fee price per 1000 bytes.+                -> Bool   -- ^ Try to find better solution when one is found+                -> Sink c m (Either String ([c], Word64))+                   -- ^ Coin selection result and change amount.+chooseCoinsSink target kbfee continue+    | target > 0 =+        maybeToEither err <$> greedyAddSink target (getFee kbfee) continue+    | otherwise = return $ Left "chooseCoins: Target must be > 0"+  where+    err = "chooseCoins: No solution found"++-- | Coin selection algorithm for multisignature transactions. This function+-- returns the selected coins together with the amount of change to send back+-- to yourself, taking the fee into account. This function assumes all the+-- coins are script hash outputs that send funds to a multisignature address.+chooseMSCoins :: Coin c+              => Word64     -- ^ Target price to pay.+              -> Word64     -- ^ Fee price per 1000 bytes.+              -> (Int, Int) -- ^ Multisig parameters m of n (m,n).+              -> Bool -- ^ Try to find better solution when one is found+              -> [c]+              -> Either String ([c], Word64)+                 -- ^ Coin selection result and change amount.+chooseMSCoins target kbfee ms continue coins =+    runIdentity $ sourceList coins $$ chooseMSCoinsSink target kbfee ms continue++-- | Coin selection algorithm for multisignature transactions. This function+-- returns the selected coins together with the amount of change to send back+-- to yourself, taking the fee into account. This function assumes all the+-- coins are script hash outputs that send funds to a multisignature address.+-- This version uses a Sink if you need conduit-based coin selection.+chooseMSCoinsSink :: (Monad m, Coin c)+                  => Word64     -- ^ Target price to pay.+                  -> Word64     -- ^ Fee price per 1000 bytes.+                  -> (Int, Int) -- ^ Multisig parameters m of n (m,n).+                  -> Bool -- ^ Try to find better solution when one is found+                  -> Sink c m (Either String ([c], Word64))+                     -- ^ Coin selection result and change amount.+chooseMSCoinsSink target kbfee ms continue+    | target > 0 =+        maybeToEither err <$> greedyAddSink target (getMSFee kbfee ms) continue+    | otherwise = return $ Left "chooseMSCoins: Target must be > 0"+  where+    err = "chooseMSCoins: No solution found"++-- Select coins greedily by starting from an empty solution. If the continue+-- value is set to True, the algorithm will try to find a better solution in+-- the stream once a solution is found. If the next solution found is not+-- strictly better than the previously found solution, the algorithm stops and+-- returns the previous solution. If the continue value is set to False, the+-- algorithm will return the first solution it finds in the stream.+greedyAddSink :: (Monad m, Coin c)+              => Word64          -- ^ Target to reach+              -> (Int -> Word64) -- ^ Coin count to fee function+              -> Bool            -- ^ Try to find better solutions+              -> Sink c m (Maybe ([c], Word64)) -- (Selected coins, change)+greedyAddSink target fee continue =+    go [] 0 [] 0+  where+    -- The goal is the value we must reach (including the fee) for a certain+    -- amount of selected coins.+    goal c = target + fee c+    go acc aTot ps pTot = await >>= \coinM -> case coinM of+        -- A coin is available in the stream+        Just coin -> do+            let val = coinValue coin+            -- We have reached the goal using this coin+            if val + aTot >= (goal $ length acc + 1)+                -- If we want to continue searching for better solutions+                then if continue+                    -- This solution is the first one or+                    -- This solution is better than the previous one+                    then if pTot == 0 || val + aTot < pTot+                        -- Continue searching for better solutions in the stream+                        then go [] 0 (coin:acc) (val + aTot)+                        -- Otherwise, we stop here and return the previous+                        -- solution+                        else return $ Just (ps, pTot - (goal $ length ps))+                    -- Otherwise, return this solution+                    else return $+                        Just (coin:acc, val + aTot - (goal $ length acc + 1))+                -- We have not yet reached the goal. Add the coin to the+                -- accumulator+                else go (coin:acc) (val + aTot) ps pTot+        -- We reached the end of the stream+        Nothing ->+            return $ if null ps+                -- If no solution was found, return Nothing+                then Nothing+                -- If we have a solution, return it+                else Just (ps, pTot - (goal $ length ps))++getFee :: Word64 -> Int -> Word64+getFee kbfee count =+    kbfee*((len + 999) `div` 1000)+  where+    len = fromIntegral $ guessTxSize count [] 2 0++getMSFee :: Word64 -> (Int, Int) -> Int -> Word64+getMSFee kbfee ms count =+    kbfee*((len + 999) `div` 1000)+  where+    len = fromIntegral $ guessTxSize 0 (replicate count ms) 2 0++-- | Computes an upper bound on the size of a transaction based on some known+-- properties of the transaction.+guessTxSize :: Int         -- ^ Number of regular transaction inputs.+            -> [(Int,Int)]+               -- ^ For every multisig input in the transaction, provide+               -- the multisig parameters m of n (m,n) for that input.+            -> Int         -- ^ Number of pay to public key hash outputs.+            -> Int         -- ^ Number of pay to script hash outputs.+            -> Int         -- ^ Upper bound on the transaction size.+guessTxSize pki msi pkout msout =+    8 + inpLen + inp + outLen + out+  where+    inpLen = BS.length $ encode' $ VarInt $ fromIntegral $ (length msi) + pki+    outLen = BS.length $ encode' $ VarInt $ fromIntegral $ pkout + msout+    inp    = pki*148 + (sum $ map guessMSSize msi)+             -- (20: hash160) + (5: opcodes) ++             -- (1: script len) + (8: Word64)+    out    = pkout*34 ++             -- (20: hash160) + (3: opcodes) ++             -- (1: script len) + (8: Word64)+             msout*32++-- Size of a multisig pay2sh input+guessMSSize :: (Int,Int) -> Int+guessMSSize (m,n) =+    -- OutPoint (36) + Sequence (4) + Script+    40 + (BS.length $ encode' $ VarInt $ fromIntegral scp) + scp+  where+    -- OP_M + n*PubKey + OP_N + OP_CHECKMULTISIG+    rdm = BS.length $ encode' $ opPushData $ BS.replicate (n*34 + 3) 0+    -- Redeem + m*sig + OP_0+    scp = rdm + m*73 + 1++{- Build a new Tx -}++-- | Build a transaction by providing a list of outpoints as inputs+-- and a list of recipients addresses and amounts as outputs.+buildAddrTx :: [OutPoint] -> [(ByteString, Word64)] -> Either String Tx+buildAddrTx xs ys =+    buildTx xs =<< mapM f ys+  where+    f (s, v) = case base58ToAddr s of+        Just a@(PubKeyAddress _) -> return (PayPKHash a,v)+        Just a@(ScriptAddress _) -> return (PayScriptHash a,v)+        _ -> Left $ "buildAddrTx: Invalid address " ++ cs s++-- | Build a transaction by providing a list of outpoints as inputs+-- and a list of 'ScriptOutput' and amounts as outputs.+buildTx :: [OutPoint] -> [(ScriptOutput, Word64)] -> Either String Tx+buildTx xs ys =+    mapM fo ys >>= \os -> return $ Tx 1 (map fi xs) os 0+  where+    fi outPoint = TxIn outPoint BS.empty maxBound+    fo (o, v)+        | v <= 2100000000000000 = return $ TxOut v $ encodeOutputBS o+        | otherwise =+            Left $ "buildTx: Invalid amount " ++ show v++-- | Data type used to specify the signing parameters of a transaction input.+-- To sign an input, the previous output script, outpoint and sighash are+-- required. When signing a pay to script hash output, an additional redeem+-- script is required.+data SigInput = SigInput+    { sigDataOut    :: !ScriptOutput -- ^ Output script to spend.+    , sigDataOP     :: !OutPoint     -- ^ Spending tranasction OutPoint+    , sigDataSH     :: !SigHash      -- ^ Signature type.+    , sigDataRedeem :: !(Maybe RedeemScript) -- ^ Redeem script+    } deriving (Eq, Read, Show)++instance NFData SigInput where+    rnf (SigInput o p h b) = rnf o `seq` rnf p `seq` rnf h `seq` rnf b++instance ToJSON SigInput where+    toJSON (SigInput so op sh rdm) = object $+        [ "pkscript" .= so+        , "outpoint" .= op+        , "sighash"  .= sh+        ] ++ [ "redeem" .= r | r <- maybeToList rdm ]++instance FromJSON SigInput where+    parseJSON (Object o) = do+        so  <- o .: "pkscript"+        op  <- o .: "outpoint"+        sh  <- o .: "sighash"+        rdm <- o .:? "redeem"+        return $ SigInput so op sh rdm+    parseJSON _ = mzero++-- | Sign a transaction by providing the 'SigInput' signing paramters and+-- a list of private keys. The signature is computed deterministically as+-- defined in RFC-6979.+signTx :: Tx               -- ^ Transaction to sign+          -> [SigInput]       -- ^ SigInput signing parameters+          -> [PrvKey]         -- ^ List of private keys to use for signing+          -> Either String Tx -- ^ Signed transaction+signTx otx@(Tx _ ti _ _) sigis allKeys+    | null ti   = Left "signTx: Transaction has no inputs"+    | otherwise = foldM go otx $ findSigInput sigis ti+  where+    go tx (sigi@(SigInput so _ _ rdmM), i) = do+        keys <- sigKeys so rdmM allKeys+        foldM (\t k -> signInput t i sigi k) tx keys++-- | Sign a single input in a transaction deterministically (RFC-6979).+signInput :: Tx -> Int -> SigInput -> PrvKey -> Either String Tx+signInput tx i (SigInput so _ sh rdmM) key = do+    let sig = TxSignature (signMsg msg key) sh+    si <- buildInput tx i so rdmM sig $ derivePubKey key+    return tx{ txIn = updateIndex i (txIn tx) (f si) }+  where+    f si x = x{ scriptInput = encodeInputBS si }+    msg = txSigHash tx (encodeOutput $ fromMaybe so rdmM) i sh++-- Order the SigInput with respect to the transaction inputs. This allow the+-- users to provide the SigInput in any order. Users can also provide only a+-- partial set of SigInputs.+findSigInput :: [SigInput] -> [TxIn] -> [(SigInput, Int)]+findSigInput si ti =+    catMaybes $ map g $ zip (matchTemplate si ti f) [0..]+  where+    f s txin = sigDataOP s == prevOutput txin+    g (Just s, i)  = Just (s,i)+    g (Nothing, _) = Nothing++-- Find from the list of private keys which one is required to sign the+-- provided ScriptOutput.+sigKeys :: ScriptOutput -> (Maybe RedeemScript) -> [PrvKey]+        -> Either String [PrvKey]+sigKeys so rdmM keys = do+    case (so, rdmM) of+        (PayPK p, Nothing) -> return $+            map fst $ maybeToList $ find ((== p) . snd) zipKeys+        (PayPKHash a, Nothing) -> return $+            map fst $ maybeToList $ find ((== a) . pubKeyAddr . snd) zipKeys+        (PayMulSig ps r, Nothing) -> return $+            map fst $ take r $ filter ((`elem` ps) . snd) zipKeys+        (PayScriptHash _, Just rdm) ->+            sigKeys rdm Nothing keys+        _ -> Left "sigKeys: Could not decode output script"+  where+    zipKeys = zip keys (map derivePubKey keys)++-- Construct an input, given a signature and a public key+buildInput :: Tx -> Int -> ScriptOutput -> (Maybe RedeemScript)+           -> TxSignature -> PubKey -> Either String ScriptInput+buildInput tx i so rdmM sig pub = case (so, rdmM) of+    (PayPK _, Nothing) ->+        return $ RegularInput $ SpendPK sig+    (PayPKHash _, Nothing) ->+        return $ RegularInput $ SpendPKHash sig pub+    (PayMulSig msPubs r, Nothing) -> do+        let mSigs = take r $ catMaybes $ matchTemplate allSigs msPubs f+        return $ RegularInput $ SpendMulSig mSigs+    (PayScriptHash _, Just rdm) -> do+        inp  <- buildInput tx i rdm Nothing sig pub+        return $ ScriptHashInput (getRegularInput inp) rdm+    _ -> Left "buildInput: Invalid output/redeem script combination"+  where+    scp     = scriptInput $ txIn tx !! i+    allSigs = nub $ sig : case decodeInputBS scp of+        Right (ScriptHashInput (SpendMulSig xs) _) -> xs+        Right (RegularInput    (SpendMulSig xs))   -> xs+        _ -> []+    out = encodeOutput so+    f (TxSignature x sh) p = verifySig (txSigHash tx out i sh) x p++{- Merge multisig transactions -}++mergeTxs :: [Tx] -> [(ScriptOutput, OutPoint)] -> Either String Tx+mergeTxs txs os+    | null txs = error "Transaction list is empty"+    | length (nub emptyTxs) /= 1 = Left "Transactions do not match"+    | length txs == 1 = return $ head txs+    | otherwise = foldM (mergeTxInput txs) (head emptyTxs) outs+  where+    zipOp = zip (matchTemplate os (txIn $ head txs) f) [0..]+    outs = map (first $ fst . fromJust) $ filter (isJust . fst) zipOp+    f (_,o) txin = o == prevOutput txin+    emptyTxs = map (\tx -> foldl clearInput tx outs) txs+    clearInput tx (_, i) = tx{ txIn =+        updateIndex i (txIn tx) (\ti -> ti{ scriptInput = BS.empty }) }++mergeTxInput :: [Tx] -> Tx -> (ScriptOutput, Int) -> Either String Tx+mergeTxInput txs tx (so, i) = do+    -- Ignore transactions with empty inputs+    let ins = map (scriptInput . (!! i) . txIn) txs+    sigRes <- mapM extractSigs $ filter (not . BS.null) ins+    let rdm = snd $ head sigRes+    unless (all (== rdm) $ map snd sigRes) $+        Left "Redeem scripts do not match"+    si <- encodeInputBS <$> go (nub $ concat $ map fst sigRes) so rdm+    return tx{ txIn = updateIndex i (txIn tx) (\ti -> ti{ scriptInput = si }) }+  where+    go allSigs out rdmM = case out of+        PayMulSig msPubs r ->+            let sigs = take r $ catMaybes $ matchTemplate allSigs msPubs $ f out+            in return $ RegularInput $ SpendMulSig sigs+        PayScriptHash _ -> case rdmM of+            Just rdm -> do+                si <- go allSigs rdm Nothing+                return $ ScriptHashInput (getRegularInput si) rdm+            _ -> Left "Invalid output script type"+        _ -> Left "Invalid output script type"+    extractSigs si = case decodeInputBS si of+        Right (RegularInput (SpendMulSig sigs)) -> Right (sigs, Nothing)+        Right (ScriptHashInput (SpendMulSig sigs) rdm) -> Right (sigs, Just rdm)+        _ -> Left "Invalid script input type"+    f out (TxSignature x sh) p =+        verifySig (txSigHash tx (encodeOutput out) i sh) x p++{- Tx verification -}++-- | Verify if a transaction is valid and all of its inputs are standard.+verifyStdTx :: Tx -> [(ScriptOutput, OutPoint)] -> Bool+verifyStdTx tx xs =+    all go $ zip (matchTemplate xs (txIn tx) f) [0..]+  where+    f (_,o) txin        = o == prevOutput txin+    go (Just (so,_), i) = verifyStdInput tx i so+    go _                = False++-- | Verify if a transaction input is valid and standard.+verifyStdInput :: Tx -> Int -> ScriptOutput -> Bool+verifyStdInput tx i so' =+    go (scriptInput $ txIn tx !! i) so'+  where+    go inp so = case decodeInputBS inp of+        Right (RegularInput (SpendPK (TxSignature sig sh))) ->+            let pub = getOutputPubKey so+            in  verifySig (txSigHash tx out i sh) sig pub+        Right (RegularInput (SpendPKHash (TxSignature sig sh) pub)) ->+            let a = getOutputAddress so+            in pubKeyAddr pub == a &&+                verifySig (txSigHash tx out i sh) sig pub+        Right (RegularInput (SpendMulSig sigs)) ->+            let pubs = getOutputMulSigKeys so+                r    = getOutputMulSigRequired so+            in  countMulSig tx out i pubs sigs == r+        Right (ScriptHashInput si rdm) ->+            scriptAddr rdm == getOutputAddress so &&+            go (encodeInputBS $ RegularInput si) rdm+        _ -> False+      where+        out = encodeOutput so++-- Count the number of valid signatures+countMulSig :: Tx -> Script -> Int -> [PubKey] -> [TxSignature] -> Int+countMulSig _ _ _ [] _  = 0+countMulSig _ _ _ _  [] = 0+countMulSig tx out i (pub:pubs) sigs@(TxSignature sig sh:rest)+    | verifySig (txSigHash tx out i sh) sig pub =+         1 + countMulSig tx out i pubs rest+    | otherwise = countMulSig tx out i pubs sigs+
+ Network/Haskoin/Transaction/Types.hs view
@@ -0,0 +1,294 @@+module Network.Haskoin.Transaction.Types+( Tx(..)+, TxIn(..)+, TxOut(..)+, OutPoint(..)+, CoinbaseTx(..)+, TxHash(..)+, txHash+, hexToTxHash+, txHashToHex+, nosigTxHash+, cbHash+) where++import Control.DeepSeq (NFData, rnf)+import Control.Monad (liftM2, replicateM, forM_, unless, mzero, (<=<))++import Data.Aeson (Value(String), FromJSON, ToJSON, parseJSON, toJSON, withText)+import Data.Word (Word32, Word64)+import Data.Binary (Binary, get, put)+import Data.Binary.Get+    ( getWord32le+    , getWord64le+    , getByteString+    )+import Data.Binary.Put+    ( putWord32le+    , putWord64le+    , putByteString+    )+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+    ( length+    , empty+    , reverse+    )+import Data.Maybe (fromMaybe)+import Data.String (IsString, fromString)+import Data.String.Conversions (cs)+import Text.Read (readPrec, parens, lexP, pfail)+import qualified Text.Read as Read (Lexeme(Ident, String))+import Network.Haskoin.Util+import Network.Haskoin.Crypto.Hash+import Network.Haskoin.Node.Types++newtype TxHash = TxHash { getTxHash :: Hash256 }+    deriving (Eq, Ord)++instance NFData TxHash where+    rnf  = rnf . getHash256 . getTxHash++instance Read TxHash where+    readPrec = parens $ do+        Read.Ident "TxHash" <- lexP+        Read.String str <- lexP+        maybe pfail return $ hexToTxHash $ cs str++instance Show TxHash where+    showsPrec d h = showParen (d > 10) $+        showString "TxHash " . shows (txHashToHex h)++instance IsString TxHash where+    fromString =+        TxHash . fromMaybe e . bsToHash256+               . BS.reverse . fromMaybe e' . decodeHex . cs+      where+        e = error "Could not read transaction hash from decoded hex string"+        e' = error "Colud not decode hex string with transaction hash"++instance Binary TxHash where+    get = TxHash <$> get+    put = put . getTxHash++-- | Computes the hash of a transaction.+txHash :: Tx -> TxHash+txHash = TxHash . doubleHash256 . encode'++nosigTxHash :: Tx -> TxHash+nosigTxHash tx =+    txHash tx{ txIn = map clearInput $ txIn tx }+  where+    clearInput ti = ti{ scriptInput = BS.empty }++-- | Computes the hash of a coinbase transaction.+cbHash :: CoinbaseTx -> TxHash+cbHash = TxHash . doubleHash256 . encode'++txHashToHex :: TxHash -> ByteString+txHashToHex (TxHash h) = encodeHex $ BS.reverse $ getHash256 h++hexToTxHash :: ByteString -> Maybe TxHash+hexToTxHash hex = do+    bs <- BS.reverse <$> decodeHex hex+    h <- bsToHash256 bs+    return $ TxHash h++instance FromJSON TxHash where+    parseJSON = withText "Transaction id" $ \t ->+        maybe mzero return $ hexToTxHash $ cs t++instance ToJSON TxHash where+    toJSON h = String $ cs $ txHashToHex h++-- | Data type representing a bitcoin transaction+data Tx =+    Tx { -- | Transaction data format version+         txVersion  :: !Word32+         -- | List of transaction inputs+       , txIn       :: ![TxIn]+         -- | List of transaction outputs+       , txOut      :: ![TxOut]+         -- | The block number of timestamp at which this transaction is locked+       , txLockTime :: !Word32+       } deriving (Eq)++instance Show Tx where+    showsPrec d tx = showParen (d > 10) $+        showString "Tx " . shows (encodeHex $ encode' tx)++instance Read Tx where+    readPrec = parens $ do+        Read.Ident "Tx" <- lexP+        Read.String str <- lexP+        maybe pfail return $ decodeToMaybe =<< decodeHex (cs str)++instance IsString Tx where+    fromString =+        fromMaybe e . (decodeToMaybe <=< decodeHex) . cs+      where+        e = error "Could not read transaction from hex string"++instance NFData Tx where+    rnf (Tx v i o l) = rnf v `seq` rnf i `seq` rnf o `seq` rnf l++instance Binary Tx where+    get =+        Tx <$> getWord32le+           <*> (replicateList =<< get)+           <*> (replicateList =<< get)+           <*> getWord32le+      where+        replicateList (VarInt c) = replicateM (fromIntegral c) get++    put (Tx v is os l) = do+        putWord32le v+        put $ VarInt $ fromIntegral $ length is+        forM_ is put+        put $ VarInt $ fromIntegral $ length os+        forM_ os put+        putWord32le l++instance FromJSON Tx where+    parseJSON = withText "Tx" $+        maybe mzero return . (decodeToMaybe <=< decodeHex) . cs++instance ToJSON Tx where+    toJSON = String . cs . encodeHex . encode'++-- | Data type representing the coinbase transaction of a 'Block'. Coinbase+-- transactions are special types of transactions which are created by miners+-- when they find a new block. Coinbase transactions have no inputs. They have+-- outputs sending the newly generated bitcoins together with all the block's+-- fees to a bitcoin address (usually the miners address). Data can be embedded+-- in a Coinbase transaction which can be chosen by the miner of a block. This+-- data also typically contains some randomness which is used, together with+-- the nonce, to find a partial hash collision on the block's hash.+data CoinbaseTx = CoinbaseTx+    { -- | Transaction data format version.+      cbVersion    :: !Word32+      -- | Previous outpoint. This is ignored for+      -- coinbase transactions but preserved for computing+      -- the correct txid.+    , cbPrevOutput :: !OutPoint+      -- | Data embedded inside the coinbase transaction.+    , cbData       :: !ByteString+      -- | Transaction sequence number. This is ignored for+      -- coinbase transactions but preserved for computing+      -- the correct txid.+    , cbInSequence :: !Word32+      -- | List of transaction outputs.+    , cbOut        :: ![TxOut]+      -- | The block number of timestamp at which this+      -- transaction is locked.+    , cbLockTime   :: !Word32+    } deriving (Eq, Show, Read)++instance NFData CoinbaseTx where+    rnf (CoinbaseTx v p d i o l) =+        rnf v `seq` rnf p `seq` rnf d `seq` rnf i `seq` rnf o `seq` rnf l++instance Binary CoinbaseTx where++    get = do+        v <- getWord32le+        (VarInt len) <- get+        unless (len == 1) $ fail "CoinbaseTx get: Input size is not 1"+        op <- get+        (VarInt cbLen) <- get+        cb <- getByteString (fromIntegral cbLen)+        sq <- getWord32le+        (VarInt oLen) <- get+        os <- replicateM (fromIntegral oLen) get+        lt <- getWord32le+        return $ CoinbaseTx v op cb sq os lt++    put (CoinbaseTx v op cb sq os lt) = do+        putWord32le v+        put $ VarInt 1+        put op+        put $ VarInt $ fromIntegral $ BS.length cb+        putByteString cb+        putWord32le sq+        put $ VarInt $ fromIntegral $ length os+        forM_ os put+        putWord32le lt++-- | Data type representing a transaction input.+data TxIn =+    TxIn {+           -- | Reference the previous transaction output (hash + position)+           prevOutput   :: !OutPoint+           -- | Script providing the requirements of the previous transaction+           -- output to spend those coins.+         , scriptInput  :: !ByteString+           -- | Transaction version as defined by the sender of the+           -- transaction. The intended use is for replacing transactions with+           -- new information before the transaction is included in a block.+         , txInSequence :: !Word32+         } deriving (Eq, Show, Read)++instance NFData TxIn where+    rnf (TxIn p i s) = rnf p `seq` rnf i `seq` rnf s++instance Binary TxIn where+    get =+        TxIn <$> get <*> (readBS =<< get) <*> getWord32le+      where+        readBS (VarInt len) = getByteString $ fromIntegral len++    put (TxIn o s q) = do+        put o+        put $ VarInt $ fromIntegral $ BS.length s+        putByteString s+        putWord32le q++-- | Data type representing a transaction output.+data TxOut =+    TxOut {+            -- | Transaction output value.+            outValue     :: !Word64+            -- | Script specifying the conditions to spend this output.+          , scriptOutput :: !ByteString+          } deriving (Eq, Show, Read)++instance NFData TxOut where+    rnf (TxOut v o) = rnf v `seq` rnf o++instance Binary TxOut where+    get = do+        val <- getWord64le+        (VarInt len) <- get+        TxOut val <$> (getByteString $ fromIntegral len)++    put (TxOut o s) = do+        putWord64le o+        put $ VarInt $ fromIntegral $ BS.length s+        putByteString s++-- | The OutPoint is used inside a transaction input to reference the previous+-- transaction output that it is spending.+data OutPoint = OutPoint+    { -- | The hash of the referenced transaction.+      outPointHash  :: !TxHash+      -- | The position of the specific output in the transaction.+      -- The first output position is 0.+    , outPointIndex :: !Word32+    } deriving (Read, Show, Eq)++instance NFData OutPoint where+    rnf (OutPoint h i) = rnf h `seq` rnf i++instance FromJSON OutPoint where+    parseJSON = withText "OutPoint" $+        maybe mzero return . (decodeToMaybe <=< decodeHex) . cs++instance ToJSON OutPoint where+    toJSON = String . cs . encodeHex . encode'++instance Binary OutPoint where+    get = do+        (h,i) <- liftM2 (,) get getWord32le+        return $ OutPoint h i+    put (OutPoint h i) = put h >> putWord32le i+
+ Network/Haskoin/Util.hs view
@@ -0,0 +1,281 @@+{-|+  This module defines various utility functions used across the+  Network.Haskoin modules.+-}+module Network.Haskoin.Util+(+  -- * ByteString helpers+  bsToInteger+, integerToBS+, encodeHex+, decodeHex++  -- * Data.Binary helpers+, encode'+, decode'+, runPut'+, runGet'+, decodeOrFail'+, runGetOrFail'+, fromDecode+, fromRunGet+, decodeToEither+, decodeToMaybe+, isolate++  -- * Maybe and Either monad helpers+, isLeft+, isRight+, fromRight+, fromLeft+, eitherToMaybe+, maybeToEither+, liftEither+, liftMaybe++  -- * Various helpers+, updateIndex+, matchTemplate++  -- * Triples+, fst3+, snd3+, lst3++  -- * MonadState+, modify'++  -- * JSON Utilities+, dropFieldLabel+, dropSumLabels++) where++import Control.Monad (guard)+import Control.Monad.Trans.Either (EitherT, hoistEither)+import Control.Monad.State (MonadState, get, put)++import Data.Word (Word8)+import Data.Bits ((.|.), shiftL, shiftR)+import Data.Char (toLower)+import Data.Binary.Put (Put, runPut)+import Data.Binary (Binary, encode, decode, decodeOrFail)+import Data.Binary.Get (Get, runGetOrFail, getByteString, ByteOffset, runGet)+import Data.Aeson.Types+    (Options(..), SumEncoding(..), defaultOptions, defaultTaggedObject)++import Data.ByteString (ByteString)+import qualified Data.ByteString.Lazy as BL (toStrict, fromStrict)+import qualified Data.ByteString.Base16 as B16+import qualified Data.ByteString as BS+    (pack, null, empty, foldr', reverse, unfoldr)++-- ByteString helpers++-- | Decode a big endian Integer from a bytestring.+bsToInteger :: ByteString -> Integer+bsToInteger = BS.foldr' f 0 . BS.reverse+  where+    f w n = (toInteger w) .|. shiftL n 8++-- | Encode an Integer to a bytestring as big endian+integerToBS :: Integer -> ByteString+integerToBS 0 = BS.pack [0]+integerToBS i+    | i > 0     = BS.reverse $ BS.unfoldr f i+    | otherwise = error "integerToBS not defined for negative values"+  where+    f 0 = Nothing+    f x = Just $ (fromInteger x :: Word8, x `shiftR` 8)++encodeHex :: ByteString -> ByteString+encodeHex = B16.encode++-- | Decode hexadecimal 'ByteString'. This function can fail if the string+-- contains invalid hexadecimal (0-9, a-f, A-F) characters+decodeHex :: ByteString -> Maybe ByteString+decodeHex bs =+    let (x, b) = B16.decode bs+    in guard (b == BS.empty) >> return x++-- Data.Binary helpers++-- | Strict version of 'Data.Binary.encode'+encode' :: Binary a => a -> ByteString+encode' = BL.toStrict . encode++-- | Strict version of 'Data.Binary.decode'+decode' :: Binary a => ByteString -> a+decode' = decode . BL.fromStrict++-- | Strict version of 'Data.Binary.runGet'+runGet' :: Binary a => Get a -> ByteString -> a+runGet' m = (runGet m) . BL.fromStrict++-- | Strict version of 'Data.Binary.runPut'+runPut' :: Put -> ByteString+runPut' = BL.toStrict . runPut++-- | Strict version of 'Data.Binary.decodeOrFail'+decodeOrFail' ::+    Binary a =>+    ByteString ->+    Either (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)+decodeOrFail' bs = case decodeOrFail $ BL.fromStrict bs of+    Left  (lbs, o, err) -> Left  (BL.toStrict lbs, o, err)+    Right (lbs, o, res) -> Right (BL.toStrict lbs, o, res)++-- | Strict version of 'Data.Binary.runGetOrFail'+runGetOrFail' ::+    Get a -> ByteString ->+    Either (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)+runGetOrFail' m bs = case runGetOrFail m $ BL.fromStrict bs of+    Left  (lbs, o, err) -> Left  (BL.toStrict lbs, o, err)+    Right (lbs, o, res) -> Right (BL.toStrict lbs, o, res)++-- | Try to decode a 'Data.Binary' value. If decoding succeeds, apply the+-- function to the result. Otherwise, return the default value.+fromDecode :: Binary a+           => ByteString    -- ^ The bytestring to decode+           -> b             -- ^ Default value to return when decoding fails+           -> (a -> b)      -- ^ Function to apply when decoding succeeds+           -> b             -- ^ Final result+fromDecode bs def f = either (const def) (f . lst) $ decodeOrFail' bs+  where+    lst (_,_,c) = c++-- | Try to run a 'Data.Binary.Get' monad. If decoding succeeds, apply a+-- function to the result. Otherwise, return the default value.+fromRunGet :: Binary a+           => Get a         -- ^ The Get monad to run+           -> ByteString    -- ^ The bytestring to decode+           -> b             -- ^ Default value to return when decoding fails+           -> (a -> b)      -- ^ Function to apply when decoding succeeds+           -> b             -- ^ Final result+fromRunGet m bs def f = either (const def) (f . lst) $ runGetOrFail' m bs+  where+    lst (_,_,c) = c++-- | Decode a 'Data.Binary' value. A 'Right' value is returned with the result+-- upon success. Otherwise a 'Left' value with the error message is returned.+decodeToEither :: Binary a => ByteString -> Either String a+decodeToEither bs = case decodeOrFail' bs of+    Left  (_,_,err) -> Left err+    Right (_,_,res) -> Right res++-- | Decode a 'Data.Binary' value. A 'Just' value is returned with the result+-- upon success. Otherwise, 'Nothing' is returned.+decodeToMaybe :: Binary a => ByteString -> Maybe a+decodeToMaybe bs = fromDecode bs Nothing Just++-- | Isolate a 'Data.Binary.Get' monad for the next 'Int' bytes. Only the next+-- 'Int' bytes of the input 'ByteString' will be available for the 'Get' monad+-- to consume. This function will fail if the Get monad fails or some of the+-- input is not consumed.+isolate :: Binary a => Int -> Get a -> Get a+isolate i g = do+    bs <- getByteString i+    case runGetOrFail' g bs of+        Left (_, _, err) -> fail err+        Right (unconsumed, _, res)+            | BS.null unconsumed -> return res+            | otherwise          -> fail "Isolate: unconsumed input"++-- Maybe and Either monad helpers++-- | Returns 'True' if the 'Either' value is 'Right'+isRight :: Either a b -> Bool+isRight (Right _) = True+isRight _         = False++-- | Returns 'True' if the 'Either' value is 'Left'+isLeft :: Either a b -> Bool+isLeft = not . isRight++-- | Extract the 'Right' value from an 'Either' value. Fails if the value is+-- 'Left'+fromRight :: Either a b -> b+fromRight (Right b) = b+fromRight _ = error "Either.fromRight: Left"++-- | Extract the 'Left' value from an 'Either' value. Fails if the value is 'Right'+fromLeft :: Either a b -> a+fromLeft (Left a) = a+fromLeft _ = error "Either.fromLeft: Right"++-- | Transforms an 'Either' value into a 'Maybe' value. 'Right' is mapped to 'Just'+-- and 'Left' is mapped to 'Nothing'. The value inside 'Left' is lost.+eitherToMaybe :: Either a b -> Maybe b+eitherToMaybe (Right b) = Just b+eitherToMaybe _ = Nothing++-- | Transforms a 'Maybe' value into an 'Either' value. 'Just' is mapped to+-- 'Right' and 'Nothing' is mapped to 'Left'. You also pass in an error value+-- in case 'Left' is returned.+maybeToEither :: b -> Maybe a -> Either b a+maybeToEither err m = maybe (Left err) Right m++-- | Lift a 'Either' computation into the 'EitherT' monad+liftEither :: Monad m => Either b a -> EitherT b m a+liftEither = hoistEither++-- | Lift a 'Maybe' computation into the 'EitherT' monad+liftMaybe :: Monad m => b -> Maybe a -> EitherT b m a+liftMaybe err = liftEither . (maybeToEither err)++-- Various helpers++-- | Applies a function to only one element of a list defined by its index.  If+-- the index is out of the bounds of the list, the original list is returned.+updateIndex :: Int      -- ^ The index of the element to change+            -> [a]      -- ^ The list of elements+            -> (a -> a) -- ^ The function to apply+            -> [a]      -- ^ The result with one element changed+updateIndex i xs f+    | i < 0 || i >= length xs = xs+    | otherwise = l ++ (f h : r)+  where+    (l,h:r) = splitAt i xs++-- | Use the list @[b]@ as a template and try to match the elements of @[a]@+-- against it. For each element of @[b]@ return the (first) matching element of+-- @[a]@, or 'Nothing'. Output list has same size as @[b]@ and contains results+-- in same order. Elements of @[a]@ can only appear once.+matchTemplate :: [a]              -- ^ The input list+              -> [b]              -- ^ The list to serve as a template+              -> (a -> b -> Bool) -- ^ The comparison function+              -> [Maybe a]        -- ^ Results of the template matching+matchTemplate [] bs _ = replicate (length bs) Nothing+matchTemplate _  [] _ = []+matchTemplate as (b:bs) f = case break (flip f b) as of+    (l,(r:rs)) -> (Just r) : matchTemplate (l ++ rs) bs f+    _          -> Nothing  : matchTemplate as bs f++-- | Returns the first value of a triple.+fst3 :: (a,b,c) -> a+fst3 (a,_,_) = a++-- | Returns the second value of a triple.+snd3 :: (a,b,c) -> b+snd3 (_,b,_) = b++-- | Returns the last value of a triple.+lst3 :: (a,b,c) -> c+lst3 (_,_,c) = c++-- | Strict evaluation of the new state+modify' :: MonadState s m => (s -> s) -> m ()+modify' f = get >>= \x -> put $! f x++dropFieldLabel :: Int -> Options+dropFieldLabel n = defaultOptions+    { fieldLabelModifier = map toLower . drop n+    , omitNothingFields  = True+    }++dropSumLabels :: Int -> Int -> String -> Options+dropSumLabels c f tag = (dropFieldLabel f)+    { constructorTagModifier = map toLower . drop c+    , sumEncoding = defaultTaggedObject { tagFieldName = tag }+    }+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMainWithHooks autoconfUserHooks
+ UNLICENSE view
@@ -0,0 +1,24 @@+This is free and unencumbered software released into the public domain.++Anyone is free to copy, modify, publish, use, compile, sell, or+distribute this software, either in source code form or as a compiled+binary, for any purpose, commercial or non-commercial, and by any+means.++In jurisdictions that recognize copyright laws, the author or authors+of this software dedicate any and all copyright interest in the+software to the public domain. We make this dedication for the benefit+of the public at large and to the detriment of our heirs and+successors. We intend this dedication to be an overt act of+relinquishment in perpetuity of all present and future rights to this+software under copyright law.++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 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.++For more information, please refer to <http://unlicense.org/>
+ haskoin-core.cabal view
@@ -0,0 +1,159 @@+name:                  haskoin-core+version:               0.2.0+synopsis:+    Implementation of the core Bitcoin protocol features.+description:+    Haskoin is a package implementing the core functionalities of the Bitcoin+    protocol specifications. The following features are provided:+    .+    * Hashing functions (sha-256, ripemd-160)+    * Base58 encoding+    * BIP32 extended key derivation and parsing (m/1'/2/3)+    * BIP39 mnemonic keys+    * ECDSA cryptographic primitives (using the C library libsecp256k1)+    * Script parsing and evaluation+    * Building and signing of standard transactions (regular, multisig, p2sh)+    * Parsing and manipulation of all Bitcoin protocol types+    * Bloom filters and partial merkle tree library (used in SPV wallets)+    * Comprehensive test suite+    .+    A wallet implementation is available in haskoin-wallet which uses both this+    package and the node implementation in haskoin-node.++homepage:              http://github.com/haskoin/haskoin+bug-reports:           http://github.com/haskoin/haskoin/issues+stability:             stable+license:               PublicDomain+license-file:          UNLICENSE+author:                Philippe Laprade, Jean-Pierre Rupp+maintainer:            plaprade+hackage@gmail.com+category:              Bitcoin, Finance, Network+build-type:            Simple+cabal-version:         >= 1.9.2+extra-source-files:    tests/data/*.json, stack.yaml++source-repository head+    type:     git+    location: git://github.com/haskoin/haskoin.git++library+    exposed-modules: Network.Haskoin.Util+                     Network.Haskoin.Crypto+                     Network.Haskoin.Node+                     Network.Haskoin.Script+                     Network.Haskoin.Transaction+                     Network.Haskoin.Block+                     Network.Haskoin.Constants+                     Network.Haskoin.Test+                     Network.Haskoin.Internals++    other-modules: Network.Haskoin.Crypto.Hash+                   Network.Haskoin.Crypto.Base58+                   Network.Haskoin.Crypto.Keys+                   Network.Haskoin.Crypto.ExtendedKeys+                   Network.Haskoin.Crypto.ECDSA+                   Network.Haskoin.Crypto.Mnemonic+                   Network.Haskoin.Node.Types+                   Network.Haskoin.Node.Message+                   Network.Haskoin.Node.Bloom+                   Network.Haskoin.Script.Types+                   Network.Haskoin.Script.Parser+                   Network.Haskoin.Script.SigHash+                   Network.Haskoin.Script.Evaluator+                   Network.Haskoin.Transaction.Types+                   Network.Haskoin.Transaction.Builder+                   Network.Haskoin.Block.Types+                   Network.Haskoin.Block.Merkle+                   Network.Haskoin.Test.Util+                   Network.Haskoin.Test.Crypto+                   Network.Haskoin.Test.Node+                   Network.Haskoin.Test.Message+                   Network.Haskoin.Test.Script+                   Network.Haskoin.Test.Transaction+                   Network.Haskoin.Test.Block++    extensions: EmptyDataDecls+                OverloadedStrings+                FlexibleInstances+                FlexibleContexts+                RecordWildCards+                DeriveDataTypeable+                GADTs++    build-depends: aeson                    >= 0.7          && < 0.9+                 , base                     >= 4.8          && < 5+                 , binary                   >= 0.7          && < 0.8+                 , byteable                 >= 0.1          && < 0.2+                 , bytestring               >= 0.10         && < 0.11+                 , base16-bytestring        >= 0.1          && < 0.2+                 , conduit                  >= 1.2          && < 1.3+                 , containers               >= 0.5          && < 0.6+                 , cryptohash               >= 0.11         && < 0.12+                 , deepseq                  >= 1.4          && < 1.5+                 , either                   >= 4.3          && < 4.5+                 , mtl                      >= 2.2          && < 2.3+                 , murmur3                  >= 1.0          && < 1.1+                 , network                  >= 2.6          && < 2.7+                 , pbkdf                    >= 1.1          && < 1.2+                 , QuickCheck               >= 2.6          && < 2.9+                 , split                    >= 0.2          && < 0.3+                 , text                     >= 0.11         && < 1.3+                 , time                     >= 1.4          && < 1.6+                 , string-conversions       >= 0.4          && < 0.5+                 , vector                   >= 0.10         && < 0.11+                 , secp256k1                >= 0.4          && < 0.5+                 , largeword                >= 1.2.4        && < 1.3+                 , entropy                  >= 0.3          && < 0.4++    ghc-options:       -Wall++test-suite test-haskoin-core+    type:              exitcode-stdio-1.0+    main-is:           Main.hs++    extensions: EmptyDataDecls+                OverloadedStrings++    other-modules: Network.Haskoin.Util.Tests+                   Network.Haskoin.Crypto.ECDSA.Tests+                   Network.Haskoin.Crypto.Base58.Tests+                   Network.Haskoin.Crypto.Base58.Units+                   Network.Haskoin.Crypto.Keys.Tests+                   Network.Haskoin.Crypto.ExtendedKeys.Tests+                   Network.Haskoin.Crypto.ExtendedKeys.Units+                   Network.Haskoin.Crypto.Hash.Tests+                   Network.Haskoin.Crypto.Hash.Units+                   Network.Haskoin.Crypto.Mnemonic.Tests+                   Network.Haskoin.Crypto.Mnemonic.Units+                   Network.Haskoin.Crypto.Units+                   Network.Haskoin.Node.Units+                   Network.Haskoin.Script.Tests+                   Network.Haskoin.Script.Units+                   Network.Haskoin.Transaction.Tests+                   Network.Haskoin.Transaction.Units+                   Network.Haskoin.Block.Tests+                   Network.Haskoin.Block.Units+                   Network.Haskoin.Json.Tests+                   Network.Haskoin.Binary.Tests++    build-depends: aeson                          >= 0.7        && < 0.9+                 , base                           >= 4.8        && < 5+                 , binary                         >= 0.7        && < 0.8+                 , bytestring                     >= 0.10       && < 0.11+                 , containers                     >= 0.5        && < 0.6+                 , haskoin-core+                 , mtl                            >= 2.2        && < 2.3+                 , split                          >= 0.2        && < 0.3+                 , HUnit                          >= 1.2        && < 1.3+                 , QuickCheck                     >= 2.6        && < 2.9+                 , test-framework                 >= 0.8        && < 0.9+                 , test-framework-quickcheck2     >= 0.3        && < 0.4+                 , test-framework-hunit           >= 0.3        && < 0.4+                 , text                           >= 0.11       && < 1.3+                 , string-conversions             >= 0.4        && < 0.5+                 , largeword                      >= 1.2        && < 1.3+                 , secp256k1                      >= 0.4        && < 0.5++    ghc-options: -Wall+    hs-source-dirs: tests+
+ stack.yaml view
@@ -0,0 +1,12 @@+flags: {}+packages:+- '.'+- location:+    git: https://github.com/haskoin/secp256k1.git+    commit: 5ee603061b3c1eaf2943e8d2c08e6effe85f38e7+  extra-dep: true+extra-deps:+- murmur3-1.0.0+- pbkdf-1.1.1.1+- largeword-1.2.4+resolver: lts-3.4
+ tests/Main.hs view
@@ -0,0 +1,66 @@+module Main where++import Test.Framework (defaultMain)++-- Util tests+import qualified Network.Haskoin.Util.Tests (tests)++-- Crypto tests+import qualified Network.Haskoin.Crypto.ECDSA.Tests (tests)+import qualified Network.Haskoin.Crypto.Base58.Tests (tests)+import qualified Network.Haskoin.Crypto.Base58.Units (tests)+import qualified Network.Haskoin.Crypto.Keys.Tests (tests)+import qualified Network.Haskoin.Crypto.ExtendedKeys.Tests (tests)+import qualified Network.Haskoin.Crypto.ExtendedKeys.Units (tests)+import qualified Network.Haskoin.Crypto.Hash.Tests (tests)+import qualified Network.Haskoin.Crypto.Hash.Units (tests)+import qualified Network.Haskoin.Crypto.Mnemonic.Tests (tests)+import qualified Network.Haskoin.Crypto.Mnemonic.Units (tests)+import qualified Network.Haskoin.Crypto.Units (tests)++-- Node tests+import qualified Network.Haskoin.Node.Units (tests)++-- Script tests+import qualified Network.Haskoin.Script.Tests (tests)+import qualified Network.Haskoin.Script.Units (tests)++-- Transaction tests+import qualified Network.Haskoin.Transaction.Tests (tests)+import qualified Network.Haskoin.Transaction.Units (tests)++-- Block tests+import qualified Network.Haskoin.Block.Tests (tests)+import qualified Network.Haskoin.Block.Units (tests)++-- Json tests+import qualified Network.Haskoin.Json.Tests (tests)++-- Binary tests+import qualified Network.Haskoin.Binary.Tests (tests)++main :: IO ()+main = defaultMain+    (  Network.Haskoin.Json.Tests.tests+    ++ Network.Haskoin.Binary.Tests.tests+    ++ Network.Haskoin.Util.Tests.tests+    ++ Network.Haskoin.Crypto.ECDSA.Tests.tests+    ++ Network.Haskoin.Crypto.Base58.Tests.tests+    ++ Network.Haskoin.Crypto.Base58.Units.tests+    ++ Network.Haskoin.Crypto.Hash.Tests.tests+    ++ Network.Haskoin.Crypto.Hash.Units.tests+    ++ Network.Haskoin.Crypto.Keys.Tests.tests+    ++ Network.Haskoin.Crypto.ExtendedKeys.Tests.tests+    ++ Network.Haskoin.Crypto.ExtendedKeys.Units.tests+    ++ Network.Haskoin.Crypto.Mnemonic.Tests.tests+    ++ Network.Haskoin.Crypto.Mnemonic.Units.tests+    ++ Network.Haskoin.Crypto.Units.tests+    ++ Network.Haskoin.Node.Units.tests+    ++ Network.Haskoin.Script.Tests.tests+    ++ Network.Haskoin.Script.Units.tests+    ++ Network.Haskoin.Transaction.Tests.tests+    ++ Network.Haskoin.Transaction.Units.tests+    ++ Network.Haskoin.Block.Tests.tests+    ++ Network.Haskoin.Block.Units.tests+    )+
+ tests/Network/Haskoin/Binary/Tests.hs view
@@ -0,0 +1,74 @@+module Network.Haskoin.Binary.Tests (tests) where++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.Binary (Binary)++import Network.Haskoin.Test+import Network.Haskoin.Util++tests :: [Test]+tests =+    [ testGroup "Binary encoding and decoding of utility types"+        [ testProperty "ByteString" $ \(ArbitraryByteString x) -> metaBinary x ]+    , testGroup "Binary encoding and decoding of hash types"+        [ testProperty "Hash160" $ \(ArbitraryHash160 x) -> metaBinary x+        , testProperty "Hash256" $ \(ArbitraryHash256 x) -> metaBinary x+        , testProperty "Hash512" $ \(ArbitraryHash512 x) -> metaBinary x+        ]+    , testGroup "Binary encoding and decoding of crypto types"+        [ testProperty "Signature" $ \(ArbitrarySignature _ _ x) -> metaBinary x+        , testProperty "PubKey" $ \(ArbitraryPubKey _ x) -> metaBinary x+        , testProperty "XPrvKey" $ \(ArbitraryXPrvKey x) -> metaBinary x+        , testProperty "XPubKey" $ \(ArbitraryXPubKey _ x) -> metaBinary x+        ]+    , testGroup "Binary encoding and decoding of protocol types"+        [ testProperty "VarInt" $ \(ArbitraryVarInt x) -> metaBinary x+        , testProperty "VarString" $ \(ArbitraryVarString x) -> metaBinary x+        , testProperty "NetworkAddress" $ \(ArbitraryNetworkAddress x) -> metaBinary x+        , testProperty "InvType" $ \(ArbitraryInvType x) -> metaBinary x+        , testProperty "InvVector" $ \(ArbitraryInvVector x) -> metaBinary x+        , testProperty "Inv" $ \(ArbitraryInv x) -> metaBinary x+        , testProperty "Version" $ \(ArbitraryVersion x) -> metaBinary x+        , testProperty "Addr" $ \(ArbitraryAddr x) -> metaBinary x+        , testProperty "Alert" $ \(ArbitraryAlert x) -> metaBinary x+        , testProperty "Reject" $ \(ArbitraryReject x) -> metaBinary x+        , testProperty "GetData" $ \(ArbitraryGetData x) -> metaBinary x+        , testProperty "NotFound" $ \(ArbitraryNotFound x) -> metaBinary x+        , testProperty "Ping" $ \(ArbitraryPing x) -> metaBinary x+        , testProperty "Pong" $ \(ArbitraryPong x) -> metaBinary x+        , testProperty "MessageCommand" $ \(ArbitraryMessageCommand x) -> metaBinary x+        , testProperty "MessageHeader" $ \(ArbitraryMessageHeader x) -> metaBinary x+        , testProperty "Message" $ \(ArbitraryMessage x) -> metaBinary x+        ]+    , testGroup "Binary encoding and decoding of script types"+        [ testProperty "ScriptOp" $ \(ArbitraryScriptOp x) -> metaBinary x+        , testProperty "Script" $ \(ArbitraryScript x) -> metaBinary x+        , testProperty "SigHash" $ \(ArbitrarySigHash x) -> metaBinary x+        ]+    , testGroup "Binary encoding and decoding of transaction types"+        [ testProperty "TxIn" $ \(ArbitraryTxIn x) -> metaBinary x+        , testProperty "TxOut" $ \(ArbitraryTxOut x) -> metaBinary x+        , testProperty "OutPoint" $ \(ArbitraryOutPoint x) -> metaBinary x+        , testProperty "Tx" $ \(ArbitraryTx x) -> metaBinary x+        , testProperty "CoinbaseTx" $ \(ArbitraryCoinbaseTx x) -> metaBinary x+        ]+    , testGroup "Binary encoding and decoding of block types"+        [ testProperty "Block" $ \(ArbitraryBlock x) -> metaBinary x+        , testProperty "BlockHeader" $ \(ArbitraryBlockHeader x) -> metaBinary x+        , testProperty "GetBlocks" $ \(ArbitraryGetBlocks x) -> metaBinary x+        , testProperty "GetHeaders" $ \(ArbitraryGetHeaders x) -> metaBinary x+        , testProperty "Headers" $ \(ArbitraryHeaders x) -> metaBinary x+        , testProperty "MerkleBlock" $ \(ArbitraryMerkleBlock x) -> metaBinary x+        ]+    , testGroup "Binary encoding and decoding of bloom types"+        [ testProperty "BloomFlags" $ \(ArbitraryBloomFlags x) -> metaBinary x+        , testProperty "BloomFilter" $ \(ArbitraryBloomFilter _ _ x) -> metaBinary x+        , testProperty "FilterLoad" $ \(ArbitraryFilterLoad x) -> metaBinary x+        , testProperty "FilterAdd" $ \(ArbitraryFilterAdd x) -> metaBinary x+        ]+    ]++metaBinary :: (Binary a, Eq a) => a -> Bool+metaBinary x = decode' (encode' x) == x
+ tests/Network/Haskoin/Block/Tests.hs view
@@ -0,0 +1,63 @@+module Network.Haskoin.Block.Tests (tests) where++import Control.Arrow++import Data.String (fromString)+import Data.String.Conversions (cs)+import Test.QuickCheck (Property, (==>))+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.Maybe (fromJust)++import Network.Haskoin.Block+import Network.Haskoin.Util+import Network.Haskoin.Test++tests :: [Test]+tests =+    [ testGroup "Block tests"+        [ testProperty "decode . encode BlockHash id" decEncBlockHashid ]+    , testGroup "Merkle trees"+        [ testProperty "Width of tree at maxmum height = 1" testTreeWidth+        , testProperty "Width of tree at height 0 is # txns" testBaseWidth+        , testProperty "extract . build partial merkle tree" buildExtractTree+        ]+    , testGroup "Block hashes"+        [ testProperty "Read/Show block hash" testReadShowBlockHash+        , testProperty "From string block hash" fromStringBlockHash+        ]+    ]++decEncBlockHashid :: ArbitraryBlockHash -> Bool+decEncBlockHashid (ArbitraryBlockHash h) =+    fromJust (hexToBlockHash $ blockHashToHex h) == h++{- Merkle Trees -}++testTreeWidth :: Int -> Property+testTreeWidth i = i /= 0 ==>+    calcTreeWidth i' (calcTreeHeight i') == 1+  where+    i' = abs i++testBaseWidth :: Int -> Property+testBaseWidth i = i /= 0 ==>+    calcTreeWidth i' 0 == i'+  where+    i' = abs i++buildExtractTree :: [(ArbitraryTxHash, Bool)] -> Property+buildExtractTree txs = not (null txs) ==>+    r == (buildMerkleRoot hashes) && m == (map (txh . fst) $ filter snd txs)+  where+    (f, h) = buildPartialMerkle $ map (first txh) txs+    (r, m) = fromRight $ extractMatches f h (length txs)+    hashes = map (txh . fst) txs+    txh (ArbitraryTxHash t) = t++testReadShowBlockHash :: ArbitraryBlockHash -> Bool+testReadShowBlockHash (ArbitraryBlockHash h) = read (show h) == h++fromStringBlockHash :: ArbitraryBlockHash -> Bool+fromStringBlockHash (ArbitraryBlockHash h) = fromString (cs $ blockHashToHex h) == h
+ tests/Network/Haskoin/Block/Units.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Block.Units (tests) where++import Data.ByteString (ByteString)++import Test.HUnit (Assertion, assertBool)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)++import Data.Maybe (fromJust)++import Network.Haskoin.Block+import Network.Haskoin.Transaction++tests :: [Test]+tests =+    [ testGroup "Merkle Roots"+        (map mapMerkleVectors $ zip merkleVectors [0..])+    ]++mapMerkleVectors :: ((ByteString, [ByteString]), Int) -> Test.Framework.Test+mapMerkleVectors (v, i) =+    testCase name $ runMerkleVector v+  where+    name = "MerkleRoot vector " ++ (show i)++runMerkleVector :: (ByteString, [ByteString]) -> Assertion+runMerkleVector (r, hs) = do+    assertBool "    >  Merkle Vector" $+        buildMerkleRoot (map f hs) == getTxHash (f r)+  where+    f = fromJust . hexToTxHash++merkleVectors :: [(ByteString, [ByteString])]+merkleVectors =+      -- Block 000000000000cd7e8cf6510303dde76121a1a791c15dba0be4be7022b07cf9e1+    [ ( "fb6698ac95b754256c5e71b4fbe07638cb6ca83ee67f44e181b91727f09f4b1f"+      , [ "dd96fdcfaec994bf583af650ff6022980ee0ba1686d84d0a3a2d24eabf34bc52"+        , "1bc216f786a564378710ae589916fc8e092ddfb9f24fe6c47b733550d476d5d9"+        , "a1db0b0194426064b067899ff2d975fb277fd52dbb1a38370800c76dd6503d41"+        , "d69f7fb0e668fbd437d1bf5211cc34d7eb8746f50cfddf705fe10bc2f8f7035f"+        , "5b4057cd80be7df5ed2ac42b776897ed3c26e3a01e4072075b8129c587094ef6"+        , "ed6dabcfba0ef43c50d89a8a0e4b236b1bc6585d4c3bbf49728b55f44312d6bc"+        , "056aaa9a3c635909c794e9b0acc7dccb0456c59a84c6b08417335bee4515e3d3"+        , "05bae5f1d1c874171692e1fc06f664e63eb143d3f096601ef938e4a9012eee66"+        , "b5e48e94e3f2fba197b3f591e01f47e185d7834d669529d44078e41c671aab0f"+        , "3b56aeadfc0c5484fd507bc89f13f2e5f61c42e0a4ae9062eda9a9aeef7db6a4"+        , "2affa187e1ebb94a2a86578b9f64951e854ff3d346fef259acfb6d0f5212e0d3"+        ]+      )+      -- Block 00000000000007cc4b6f07bfed72bccc1ed8dd031a93969a4c22211f784457d4+    , ( "886fea311d2dc64c315519f2d647e43998d780d2170f77e53dc0d85bf2ee680c"+      , [ "c9c9e5211512629fd111cc071d745b8c79bf486b4ea95489eb5de08b5d786b8e"+        , "20beb0ee30dfd323ade790ce9a46ae7a174f9ea44ce22a17c4d4eb23b7016f51"+        , "d4cb7dd741e78a8f57e12f6c8ddb0361ff2a5bf9365bd7d7df761060847daf9a"+        , "ddbfa6fdd29d4b47aeaadf82a4bf0a93d58cd7d8401fabf860a1ae8eeb51f42e"+        , "9d82bafe44abee248b968c86f165051c8413482c232659795335c52922dab471"+        , "86035372d31b53efd848cea7231aa9738c209aff64d3c59b1619341afb5b6ba3"+        , "11e7a7393d9658813dfaebc04fa6d4b73bac8d641bffa7067da879523d43d030"+        , "2f676b9aa5bc0ebf3395032c84c466e40cac29f80434cd1138e31c2d0fcc5c13"+        , "37567d559fbfae07fda9a90de0ce30b202128bc8ebdfef5ad2b53e865a3478c2"+        , "0b8e6c1200c454361e94e261738429e9c9b8dcffd85ec8511bbf5dc7e2e0ada8"+        ]+      )+      -- Block 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048+    , ( "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"+      , [ "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098" ]+      )+      -- Block 000000000004d160ac1f7b775d7c1823345aeadd5fcb29ca2ad2403bb7babd4c+    , ( "aae018650f513fc42d55b2210ec3ceeeb194fb1261d37989de07451fc0cbac5c"+      , [ "a4454f22831acd7904a9902c5070a3ee4bf4c2b13bc6b2dc66735dd3c4414028"+        , "45297f334278885108dd38a0b689ed95a4373dd3f7e4413e6aebdc2654fb771b"+        ]+      )+      -- Block 000000000001d1b13a7e86ddb20da178f20d6da5cd037a29c2a15b8b84cc774e+    , ( "ca3580505feb87544760ac14a5859659e23be05f765bbed9f86a3c9aad1a5d0c"+      , [ "60702384c6e9d34ff03c2b3e726bdc649befe603216815bd0a2974921d0d9549"+        , "11f40f58941d2a81a1616a3b84b7dd8b9d07e68750827de488c11a18f54220bb"+        , "d78e82527aa8cf16e375010bc666362c0258d3c0da1885a1871121706da8b633"+        ]+      )+      -- Block 0000000000000630a4e2266a31776e952a19b7c99a6387917d9de9032f608021+    , ( "dcce8be0a9a41e7bb726c5b49d957d90b5308e3dc5dce070ccbc8996e265a6c2"+      , [ "c0f58ff12cd1023b05f8f7035cc62bf50958ddb216a4e0eb5471deb7ef25fe81"+        , "24e5bbf9008641b8fcf3d076fef66c28c695362ba9f6a6042f8275a98414ee92"+        , "e8e1f72abad5e34dabc0f6de46a484b17a9af857d1c41de19482fadf6f7f4b27"+        , "540e4d34d9fd9e5ec02853054be7ad9260379bc23388489049cca1b0f7cf518a"+        , "324444835c5fe0545f98c4240011b75e6ea1bb76f41829e4cfbe7f75b6cee924"+        , "e7d31437ac21bceb0c222a82b2723e2b8a7654147e33397679f041537022a4b2"+        , "a8b5768d8b33525ee89d546a6a6897f8e42ba9d56a2c5e871a5d2ab40258dc95"+        , "7ba712b31bae8d45810a5cda3838c7e7fb9abd6e88bb4b3ee79be9ea2f714bb4"+        , "2ae1c4d927b06edaa626b230976ad8062bbae24da9378d1de2409da5ab08a26d"+        , "3c417dc8087d6878003624b74431e17fec9ca761389034b1b1e0f32cbfb11f4f"+        , "de6de7beae8d8c98c7d46b4409d5460e58e3204d8b4caed256c7471998595909"+        , "c7c3c211402b7c4379f7b01fadc67260ee58d11e8d0bcce3d68cb45f3467e99d"+        , "77aa2717e727a096d81074bd46ae59462692d20a1acc1a01b2535518ae5aeb53"+        , "4859a710bb673aca46208bbd59d1000ae990dafff5f70b56f0853aeeaea3948b"+        , "38deca6991988e461b83aa0d49ffef0f304c4b760371682d152eeb8c56a48174"+        , "648f4f50dada3574e2dfe2dc68956b01dd97d543859a3540bbe1ef5418d0e494"+        , "9cd7be42c2f0cd8bf38738c162cd05108e213ec7958bf2571cb627872963f5c4"+        , "6740e0dd8b97e23864af41839fc197238d2f0dbefce9a82c657556be65c465fa"+        , "f75c2e4b70db4b0aabc44b77af1ae75d305340fcf6e7b5f806ddcba4aa42b55d"+        , "e125c488636749da68e6696b97525a77146c0777c7946927e37afd513d74a4e6"+        , "c20526f119aea10880af631eba7f0b60385a22e0b0c402fe8508d41952e58be9"+        , "6456c023c7e245f5c57a168633a23f57f4fadb651115f807694a6bed14ae3b55"+        , "98b26e364e2888c9f264e4b5e13103c89608609774eb07ce933d8a2a45d19776"+        , "2efaa4f167bb65ba5684f8076cd9279fd67fd9c67388c8862809bab5542e637d"+        , "ec44eeb84d8d976d77079a822710b4dfdb11a2d9a03d8cc00bab0ae424e84666"+        , "410730d9f807d81ac48b8eafac6f1d36642c1c370241b367a35f0bac6ac7c05f"+        , "e95a7d0d477fd3db22756a3fd390a50c7bc48dc9e946fea9d24bd0866b3bb0e9"+        , "a72fec99d14939216628aaf7a0afc4c017113bcae964e777e6b508864eeaacc4"+        , "8548433310fcf75dbbc042121e8318c678e0a017534786dd322a91cebe8d213f"+        ]+      )+    ]+
+ tests/Network/Haskoin/Crypto/Base58/Tests.hs view
@@ -0,0 +1,39 @@+module Network.Haskoin.Crypto.Base58.Tests (tests) where++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.String (fromString)+import Data.String.Conversions (cs)++import Network.Haskoin.Test+import Network.Haskoin.Crypto++tests :: [Test]+tests =+    [ testGroup "Address and Base58"+        [ testProperty "decode58( encode58(i) ) = i" decodeEncode58+        , testProperty "decode58Chk( encode58Chk(i) ) = i" decodeEncode58Check+        , testProperty "decode58( encode58(address) ) = address" decEncAddr+        , testProperty "Read/Show address" testReadShowAddress+        , testProperty "From string address" testFromStringAddress+        ]+    ]++decodeEncode58 :: ArbitraryByteString -> Bool+decodeEncode58 (ArbitraryByteString bs) =+    decodeBase58 (encodeBase58 bs) == Just bs++decodeEncode58Check :: ArbitraryByteString -> Bool+decodeEncode58Check (ArbitraryByteString bs) =+    decodeBase58Check (encodeBase58Check bs) == Just bs++decEncAddr :: ArbitraryAddress -> Bool+decEncAddr (ArbitraryAddress a) = base58ToAddr (addrToBase58 a) == Just a+++testReadShowAddress :: ArbitraryAddress -> Bool+testReadShowAddress (ArbitraryAddress a) = read (show a) == a++testFromStringAddress :: ArbitraryAddress -> Bool+testFromStringAddress (ArbitraryAddress a) = fromString (cs $ addrToBase58 a) == a
+ tests/Network/Haskoin/Crypto/Base58/Units.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Crypto.Base58.Units (tests) where++import Test.HUnit (Assertion, assertBool)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)++import Data.ByteString (ByteString)+import qualified Data.ByteString as BS (append, pack, empty)++import Network.Haskoin.Crypto++tests :: [Test]+tests =+    [ testGroup "Test base58 encodings"+        ( map mapBase58Vec $ zip vectors [0..] )+    ]++mapBase58Vec :: ((ByteString, ByteString, ByteString), Int) -> Test.Framework.Test+mapBase58Vec (v, i) =+    testCase (unwords [ "Test base58 vector", show i ]) $ runVector v++runVector :: (ByteString, ByteString, ByteString) -> Assertion+runVector (bs, e, chk) = do+    assertBool "encodeBase58" $ e == b58+    assertBool "encodeBase58Check" $ chk == b58Chk+    assertBool "decodeBase58" $ Just bs == decodeBase58 b58+    assertBool "decodeBase58Check" $ Just bs == decodeBase58Check b58Chk+  where+    b58    = encodeBase58 bs+    b58Chk = encodeBase58Check bs++vectors :: [(ByteString, ByteString, ByteString)]+vectors =+    [ ( BS.empty, "", "3QJmnh" )+    , ( BS.pack [0], "1", "1Wh4bh" )+    , ( BS.pack [0,0,0,0], "1111", "11114bdQda" )+    , ( BS.pack [0,0,1,0,0], "11LUw", "113CUwsFVuo" )+    , ( BS.pack [255], "5Q", "VrZDWwe" )+    , ( BS.pack [0,0,0,0] `BS.append` BS.pack [1..255]+      , "1111cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5NsBgNiFpWgAnEx6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vccXWqKDvGv3u1GxFKPuAkn8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMvH3ZNLmP5fSG6DGbbi2tuwMWPthr4boWwCxf7ewSgNQeacyozhKDDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTcaB723LchjeKun7MuGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2pQPmHz4xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY"+      , "111151KWPPBRzdWPr1ASeu172gVgLf1YfUp6VJyk6K9t4cLqYtFHcMa2iX8S3NJEprUcW7W5LvaPRpz7UG7puBj5STE3nKhCGt5eckYq7mMn5nT7oTTic2BAX6zDdqrmGCnkszQkzkz8e5QLGDjf7KeQgtEDm4UER6DMSdBjFQVa6cHrrJn9myVyyhUrsVnfUk2WmNFZvkWv3Tnvzo2cJ1xW62XDfUgYz1pd97eUGGPuXvDFfLsBVd1dfdUhPwxW7pMPgdWHTmg5uqKGFF6vE4xXpAqZTbTxRZjCDdTn68c2wrcxApm8hq3JX65Hix7VtcD13FF8b7BzBtwjXq1ze6NMjKgUcqpJTN9vt"+      )+    ]+
+ tests/Network/Haskoin/Crypto/ECDSA/Tests.hs view
@@ -0,0 +1,81 @@+module Network.Haskoin.Crypto.ECDSA.Tests (tests) where++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.Bits (testBit)+import qualified Data.ByteString as BS (index, length)++import Network.Haskoin.Test+import Network.Haskoin.Crypto+import Network.Haskoin.Util++tests :: [Test]+tests =+    [ testGroup "ECDSA signatures"+        [ testProperty "Verify signature" testVerifySig+        , testProperty "S component <= order/2" $+            \(ArbitrarySignature _ _ sig) -> halfOrderSig sig+        ]+    , testGroup "ECDSA Binary"+        [ testProperty "Encoded signature is canonical" $+            \(ArbitrarySignature _ _ sig) -> testIsCanonical sig+        ]+    ]++{- ECDSA Signatures -}++halfOrderSig :: Signature -> Bool+halfOrderSig = isCanonicalHalfOrder++testVerifySig :: ArbitrarySignature -> Bool+testVerifySig (ArbitrarySignature msg key sig) =+    verifySig msg sig pubkey+  where+    pubkey = derivePubKey key++{- ECDSA Binary -}++-- github.com/bitcoin/bitcoin/blob/master/src/script.cpp+-- from function IsCanonicalSignature+testIsCanonical :: Signature -> Bool+testIsCanonical sig = not $+    -- Non-canonical signature: too short+    (len < 8) ||+    -- Non-canonical signature: too long+    (len > 72) ||+    -- Non-canonical signature: wrong type+    (BS.index s 0 /= 0x30) ||+    -- Non-canonical signature: wrong length marker+    (BS.index s 1 /= len - 2) ||+    -- Non-canonical signature: S length misplaced+    (5 + rlen >= len) ||+    -- Non-canonical signature: R+S length mismatch+    (rlen + slen + 6 /= len) ||+    -- Non-canonical signature: R value type mismatch+    (BS.index s 2 /= 0x02) ||+    -- Non-canonical signature: R length is zero+    (rlen == 0) ||+    -- Non-canonical signature: R value negative+    (testBit (BS.index s 4) 7) ||+    -- Non-canonical signature: R value excessively padded+    (  rlen > 1+    && BS.index s 4 == 0+    && not (testBit (BS.index s 5) 7)+    ) ||+    -- Non-canonical signature: S value type mismatch+    (BS.index s (fromIntegral rlen+4) /= 0x02) ||+    -- Non-canonical signature: S length is zero+    (slen == 0) ||+    -- Non-canonical signature: S value negative+    (testBit (BS.index s (fromIntegral rlen+6)) 7) ||+    -- Non-canonical signature: S value excessively padded+    (  slen > 1+    && BS.index s (fromIntegral rlen+6) == 0+    && not (testBit (BS.index s (fromIntegral rlen+7)) 7)+    )+  where+    s = encode' sig+    len = fromIntegral $ BS.length s+    rlen = BS.index s 3+    slen = BS.index s (fromIntegral rlen + 5)
+ tests/Network/Haskoin/Crypto/ExtendedKeys/Tests.hs view
@@ -0,0 +1,79 @@+module Network.Haskoin.Crypto.ExtendedKeys.Tests (tests) where++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.String (fromString)+import Data.String.Conversions (cs)+import Data.Word (Word32)+import Data.Bits ((.&.))++import Network.Haskoin.Test+import Network.Haskoin.Crypto++tests :: [Test]+tests =+    [ testGroup "HDW Extended Keys"+        [ testProperty "prvSubKey(k,c)*G = pubSubKey(k*G,c)" subkeyTest+        , testProperty "fromB58 . toB58 prvKey" b58PrvKey+        , testProperty "fromB58 . toB58 pubKey" b58PubKey+        ]+    , testGroup "From/To strings"+        [ testProperty "Read/Show extended public key" testReadShowPubKey+        , testProperty "Read/Show extended private key" testReadShowPrvKey+        , testProperty "Read/Show derivation path" testReadShowDerivPath+        , testProperty "Read/Show hard derivation path" testReadShowHardPath+        , testProperty "Read/Show soft derivation path" testReadShowSoftPath+        , testProperty "From string extended public key" testFromStringPubKey+        , testProperty "From string extended private key" testFromStringPrvKey+        , testProperty "From string derivation path" testFromStringDerivPath+        , testProperty "From string hard derivation path" testFromStringHardPath+        , testProperty "From string soft derivation path" testFromStringSoftPath+        ]+    ]++{- HDW Extended Keys -}++subkeyTest :: ArbitraryXPrvKey -> Word32 -> Bool+subkeyTest (ArbitraryXPrvKey k) i =+    (deriveXPubKey $ prvSubKey k i') == (pubSubKey (deriveXPubKey k) i')+  where+    i' = fromIntegral $ i .&. 0x7fffffff -- make it a public derivation++b58PrvKey :: ArbitraryXPrvKey -> Bool+b58PrvKey (ArbitraryXPrvKey k) = (xPrvImport $ xPrvExport k) == Just k++b58PubKey :: ArbitraryXPubKey -> Bool+b58PubKey (ArbitraryXPubKey _ k) = (xPubImport $ xPubExport k) == Just k++{- Strings -}++testReadShowPubKey :: ArbitraryXPubKey -> Bool+testReadShowPubKey (ArbitraryXPubKey _ k) = read (show k) == k++testReadShowPrvKey :: ArbitraryXPrvKey -> Bool+testReadShowPrvKey (ArbitraryXPrvKey k) = read (show k) == k++testFromStringPubKey :: ArbitraryXPubKey -> Bool+testFromStringPubKey (ArbitraryXPubKey _ k) = fromString (cs $ xPubExport k) == k++testFromStringPrvKey :: ArbitraryXPrvKey -> Bool+testFromStringPrvKey (ArbitraryXPrvKey k) = fromString (cs $ xPrvExport k) == k++testReadShowDerivPath :: ArbitraryDerivPath -> Bool+testReadShowDerivPath (ArbitraryDerivPath p) = read (show p) == p++testReadShowHardPath :: ArbitraryHardPath -> Bool+testReadShowHardPath (ArbitraryHardPath p) = read (show p) == p++testReadShowSoftPath :: ArbitrarySoftPath -> Bool+testReadShowSoftPath (ArbitrarySoftPath p) = read (show p) == p++testFromStringDerivPath :: ArbitraryDerivPath -> Bool+testFromStringDerivPath (ArbitraryDerivPath k) = fromString (cs $ pathToStr k) == k++testFromStringHardPath :: ArbitraryHardPath -> Bool+testFromStringHardPath (ArbitraryHardPath k) = fromString (cs $ pathToStr k) == k++testFromStringSoftPath :: ArbitrarySoftPath -> Bool+testFromStringSoftPath (ArbitrarySoftPath k) = fromString (cs $ pathToStr k) == k
+ tests/Network/Haskoin/Crypto/ExtendedKeys/Units.hs view
@@ -0,0 +1,403 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Crypto.ExtendedKeys.Units (tests) where++import Test.HUnit (Assertion, assertBool, assertEqual)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)++import Data.Aeson (decode, encode)+import Data.Maybe (isJust, isNothing, fromJust)+import Data.String (fromString)+import Data.ByteString (ByteString)+import qualified Data.ByteString.Lazy.Char8 as B8++import Network.Haskoin.Crypto+import Network.Haskoin.Util++tests :: [Test]+tests =+    [ testGroup "BIP32 derivation vector 1"+        [ testCase "Chain m" $ runXKeyVec (xKeyVec !! 0)+        , testCase "Chain m/0'" $ runXKeyVec (xKeyVec !! 1)+        , testCase "Chain m/0'/1" $ runXKeyVec (xKeyVec !! 2)+        , testCase "Chain m/0'/1/2'" $ runXKeyVec (xKeyVec !! 3)+        , testCase "Chain m/0'/1/2'/2" $ runXKeyVec (xKeyVec !! 4)+        , testCase "Chain m/0'/1/2'/2/1000000000" $+            runXKeyVec (xKeyVec !! 5)+        ]+    , testGroup "BIP32 subkey derivation vector 2"+        [ testCase "Chain m" $ runXKeyVec (xKeyVec2 !! 0)+        , testCase "Chain m/0" $ runXKeyVec (xKeyVec2 !! 1)+        , testCase "Chain m/0/2147483647'" $+            runXKeyVec (xKeyVec2 !! 2)+        , testCase "Chain m/0/2147483647'/1" $+            runXKeyVec (xKeyVec2 !! 3)+        , testCase "Chain m/0/2147483647'/1/2147483646'" $+            runXKeyVec (xKeyVec2 !! 4)+        , testCase "Chain m/0/2147483647'/1/2147483646'/2" $+            runXKeyVec (xKeyVec2 !! 5)+        ]+    , testGroup "BIP32 subkey derivation using string path"+        [ testGroup "Either Derivations" testDerivePathE+        , testGroup "Public Derivations" testDerivePubPath+        , testGroup "Private Derivations" testDerivePrvPath+        , testGroup "Path Parsing" testParsePath+        , testGroup "FromJSON" testFromJsonPath+        , testGroup "ToJSON" testToJsonPath+        ]+    ]++testFromJsonPath :: [Test]+testFromJsonPath = do+    path <- jsonPathVectors+    return $ testCase ("Path " ++ path) $+        assertEqual path (Just [fromString path :: DerivPath])+            (decode $ B8.pack $ "[\"" ++ path ++ "\"]")++testToJsonPath :: [Test]+testToJsonPath = do+    path <- jsonPathVectors+    return $ testCase ("Path " ++ path) $+        assertEqual path (B8.pack $ "[\"" ++ path ++ "\"]")+            (encode [fromString path :: DerivPath])++jsonPathVectors :: [String]+jsonPathVectors =+    [ "m"+    , "m/0"+    , "m/0'"+    , "M/0'"+    , "m/2147483647"+    , "M/2147483647"+    , "m/1/2/3/4/5/6/7/8"+    , "M/1/2/3/4/5/6/7/8"+    , "m/1'/2'/3/4"+    , "M/1'/2'/3/4"+    ]++testParsePath :: [Test]+testParsePath = do+    (path, t) <- parsePathVectors+    return $ testCase ("Path " ++ path) $+        assertBool path (t $ parsePath path)++parsePathVectors :: [(String, Maybe DerivPath -> Bool)]+parsePathVectors =+    [ ("m", isJust)+    , ("m/0'", isJust)+    , ("M/0'", isJust)+    , ("m/2147483648", isNothing)+    , ("m/2147483647", isJust)+    , ("M/2147483648", isNothing)+    , ("M/2147483647", isJust)+    , ("M/-1", isNothing)+    , ("M/-2147483648", isNothing)+    , ("m/1/2/3/4/5/6/7/8", isJust)+    , ("M/1/2/3/4/5/6/7/8", isJust)+    , ("m/1'/2'/3/4", isJust)+    , ("M/1'/2'/3/4", isJust)+    , ("m/1/2'/3/4'", isNothing)+    , ("M/1/2'/3/4'", isNothing)+    , ("meh", isNothing)+    , ("infinity", isNothing)+    , ("NaN", isNothing)+    ]++testDerivePathE :: [Test]+testDerivePathE = do+    (key, path, final) <- derivePathVectors+    return $ testCase ("Path " ++ path) $+        assertEqual path final $+            derivePathE (fromString path :: DerivPath) key++testDerivePubPath :: [Test]+testDerivePubPath = do+    (key, path, final) <- derivePubPathVectors+    return $ testCase ("Path " ++ path) $+        assertEqual path final $+            derivePubPath (fromString path :: SoftPath) key++testDerivePrvPath :: [Test]+testDerivePrvPath = do+    (key, path, final) <- derivePrvPathVectors+    return $ testCase ("Path " ++ path) $+        assertEqual path final $+            derivePath (fromString path :: DerivPath) key++derivePubPathVectors :: [(XPubKey, String, XPubKey)]+derivePubPathVectors =+    [ ( xpub, "M", xpub )+    , ( xpub, "M/8", pubSubKey xpub 8 )+    , ( xpub, "M/8/30/1", foldl pubSubKey xpub [8,30,1] )+    ]+  where+    xprv = fromJust $ xPrvImport+        "xprv9s21ZrQH143K46iDVRSyFfGfMgQjzC4BV3ZUfNbG7PHQrJjE53ofAn5gYkp6KQ\+        \WzGmb8oageSRxBY8s4rjr9VXPVp2HQDbwPt4H31Gg4LpB"+    xpub = deriveXPubKey xprv++derivePrvPathVectors :: [(XPrvKey, String, XPrvKey)]+derivePrvPathVectors =+    [ ( xprv, "m", xprv )+    , ( xprv, "M", xprv )+    , ( xprv, "m/8'", hardSubKey xprv 8 )+    , ( xprv, "M/8'", hardSubKey xprv 8 )+    , ( xprv, "m/8'/30/1"+      , foldl prvSubKey (hardSubKey xprv 8) [30,1]+      )+    , ( xprv, "M/8'/30/1"+      , foldl prvSubKey (hardSubKey xprv 8) [30,1]+      )+    , ( xprv, "m/3/20"+      , foldl prvSubKey xprv [3,20]+      )+    , ( xprv, "M/3/20"+      , foldl prvSubKey xprv [3,20]+      )+    ]+  where+    xprv = fromJust $ xPrvImport+        "xprv9s21ZrQH143K46iDVRSyFfGfMgQjzC4BV3ZUfNbG7PHQrJjE53ofAn5gYkp6KQ\+        \WzGmb8oageSRxBY8s4rjr9VXPVp2HQDbwPt4H31Gg4LpB"++derivePathVectors :: [(XPrvKey, String, Either XPubKey XPrvKey)]+derivePathVectors =+    [ ( xprv, "m", Right xprv )+    , ( xprv, "M", Left xpub )+    , ( xprv, "m/8'", Right $ hardSubKey xprv 8 )+    , ( xprv, "M/8'", Left $ deriveXPubKey $ hardSubKey xprv 8 )+    , ( xprv, "m/8'/30/1"+      , Right $ foldl prvSubKey (hardSubKey xprv 8) [30,1]+      )+    , ( xprv, "M/8'/30/1"+      , Left $ deriveXPubKey $ foldl prvSubKey (hardSubKey xprv 8) [30,1]+      )+    , ( xprv, "m/3/20"+      , Right $ foldl prvSubKey xprv [3,20]+      )+    , ( xprv, "M/3/20"+      , Left $ deriveXPubKey $ foldl prvSubKey xprv [3,20]+      )+    ]+  where+    xprv = fromJust $ xPrvImport+        "xprv9s21ZrQH143K46iDVRSyFfGfMgQjzC4BV3ZUfNbG7PHQrJjE53ofAn5gYkp6KQ\+        \WzGmb8oageSRxBY8s4rjr9VXPVp2HQDbwPt4H31Gg4LpB"+    xpub = deriveXPubKey xprv++runXKeyVec :: ([ByteString], XPrvKey) -> Assertion+runXKeyVec (v, m) = do+    assertBool "xPrvID" $ (encodeHex $ encode' $ xPrvID m) == v !! 0+    assertBool "xPrvFP" $ (encodeHex $ encode' $ xPrvFP m) == v !! 1+    assertBool "xPrvAddr" $+        (addrToBase58 $ xPubAddr $ deriveXPubKey m) == v !! 2+    assertBool "prvKey" $+        (encodeHex $ encodePrvKey $ xPrvKey m) == v !! 3+    assertBool "xPrvWIF" $ xPrvWif m == v !! 4+    assertBool "pubKey" $+        (encodeHex $ encode' $ xPubKey $ deriveXPubKey m) == v !! 5+    assertBool "chain code" $+        (encodeHex $ encode' $ xPrvChain m) == v !! 6+    assertBool "Hex PubKey" $+        (encodeHex $ encode' $ deriveXPubKey m) == v !! 7+    assertBool "Hex PrvKey" $ (encodeHex $ encode' m) == v !! 8+    assertBool "Base58 PubKey" $ (xPubExport $ deriveXPubKey m) == v !! 9+    assertBool "Base58 PrvKey" $ xPrvExport m == v !! 10++-- BIP 0032 Test Vectors+-- https://en.bitcoin.it/wiki/BIP_0032_TestVectors++xKeyVec :: [([ByteString], XPrvKey)]+xKeyVec = zip xKeyResVec $ foldl f [m] der+    where f acc d = acc ++ [d $ last acc]+          m   = makeXPrvKey $ fromJust $ decodeHex m0+          der = [ flip hardSubKey 0+                , flip prvSubKey 1+                , flip hardSubKey 2+                , flip prvSubKey 2+                , flip prvSubKey 1000000000+                ]++xKeyVec2 :: [([ByteString], XPrvKey)]+xKeyVec2 = zip xKeyResVec2 $ foldl f [m] der+    where f acc d = acc ++ [d $ last acc]+          m   = makeXPrvKey $ fromJust $ decodeHex m1+          der = [ flip prvSubKey 0+                , flip hardSubKey 2147483647+                , flip prvSubKey 1+                , flip hardSubKey 2147483646+                , flip prvSubKey 2+                ]++m0 :: ByteString+m0 = "000102030405060708090a0b0c0d0e0f"++xKeyResVec :: [[ByteString]]+xKeyResVec =+    [+      -- m+      [ "3442193e1bb70916e914552172cd4e2dbc9df811"+      , "3442193e"+      , "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"+      , "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"+      , "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW"+      , "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"+      , "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"+      , "0488b21e000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d5080339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"+      , "0488ade4000000000000000000873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d50800e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"+      , "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"+      , "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"+      ]+      -- m/0'+    , [ "5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7"+      , "5c1bd648"+      , "19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh"+      , "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"+      , "L5BmPijJjrKbiUfG4zbiFKNqkvuJ8usooJmzuD7Z8dkRoTThYnAT"+      , "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"+      , "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"+      , "0488b21e013442193e8000000047fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"+      , "0488ade4013442193e8000000047fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae623614100edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"+      , "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"+      , "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"+      ]+      -- m/0'/1+    , [ "bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe"+      , "bef5a2f9"+      , "1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj"+      , "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"+      , "KyFAjQ5rgrKvhXvNMtFB5PCSKUYD1yyPEe3xr3T34TZSUHycXtMM"+      , "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"+      , "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"+      , "0488b21e025c1bd648000000012a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c1903501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"+      , "0488ade4025c1bd648000000012a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19003c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"+      , "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"+      , "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"+      ]+      -- m/0'/1/2'+    , [ "ee7ab90cde56a8c0e2bb086ac49748b8db9dce72"+      , "ee7ab90c"+      , "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x"+      , "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"+      , "L43t3od1Gh7Lj55Bzjj1xDAgJDcL7YFo2nEcNaMGiyRZS1CidBVU"+      , "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"+      , "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"+      , "0488b21e03bef5a2f98000000204466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"+      , "0488ade403bef5a2f98000000204466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f00cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"+      , "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"+      , "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"+      ]+      -- m/0'/1/2'/2+    , [ "d880d7d893848509a62d8fb74e32148dac68412f"+      , "d880d7d8"+      , "1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt"+      , "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"+      , "KwjQsVuMjbCP2Zmr3VaFaStav7NvevwjvvkqrWd5Qmh1XVnCteBR"+      , "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"+      , "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"+      , "0488b21e04ee7ab90c00000002cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"+      , "0488ade404ee7ab90c00000002cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd000f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"+      , "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"+      , "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"+      ]+      -- m/0'/1/2'/2/1000000000+    , [ "d69aa102255fed74378278c7812701ea641fdf32"+      , "d69aa102"+      , "1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam"+      , "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"+      , "Kybw8izYevo5xMh1TK7aUr7jHFCxXS1zv8p3oqFz3o2zFbhRXHYs"+      , "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"+      , "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"+      , "0488b21e05d880d7d83b9aca00c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"+      , "0488ade405d880d7d83b9aca00c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e00471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"+      , "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"+      , "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"+      ]+    ]++m1 :: ByteString+m1 = "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"++xKeyResVec2 :: [[ByteString]]+xKeyResVec2 =+    [+      -- m+      [ "bd16bee53961a47d6ad888e29545434a89bdfe95"+      , "bd16bee5"+      , "1JEoxevbLLG8cVqeoGKQiAwoWbNYSUyYjg"+      , "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"+      , "KyjXhyHF9wTphBkfpxjL8hkDXDUSbE3tKANT94kXSyh6vn6nKaoy"+      , "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"+      , "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689"+      , "0488b21e00000000000000000060499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd968903cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"+      , "0488ade400000000000000000060499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689004b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"+      , "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"+      , "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"+      ]+      -- m/0+    , [ "5a61ff8eb7aaca3010db97ebda76121610b78096"+      , "5a61ff8e"+      , "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"+      , "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"+      , "L2ysLrR6KMSAtx7uPqmYpoTeiRzydXBattRXjXz5GDFPrdfPzKbj"+      , "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"+      , "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c"+      , "0488b21e01bd16bee500000000f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"+      , "0488ade401bd16bee500000000f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c00abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"+      , "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"+      , "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"+      ]+      -- m/0/2147483647'+    , [ "d8ab493736da02f11ed682f88339e720fb0379d1"+      , "d8ab4937"+      , "1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk"+      , "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"+      , "L1m5VpbXmMp57P3knskwhoMTLdhAAaXiHvnGLMribbfwzVRpz2Sr"+      , "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"+      , "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9"+      , "0488b21e025a61ff8effffffffbe17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d903c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"+      , "0488ade4025a61ff8effffffffbe17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d900877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"+      , "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"+      , "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"+      ]+      -- m/0/2147483647'/1+    , [ "78412e3a2296a40de124307b6485bd19833e2e34"+      , "78412e3a"+      , "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW"+      , "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"+      , "KzyzXnznxSv249b4KuNkBwowaN3akiNeEHy5FWoPCJpStZbEKXN2"+      , "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"+      , "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb"+      , "0488b21e03d8ab493700000001f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"+      , "0488ade403d8ab493700000001f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb00704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"+      , "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"+      , "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"+      ]+      -- m/0/2147483647'/1/2147483646'+    , [ "31a507b815593dfc51ffc7245ae7e5aee304246e"+      , "31a507b8"+      , "15XVotxCAV7sRx1PSCkQNsGw3W9jT9A94R"+      , "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"+      , "L5KhaMvPYRW1ZoFmRjUtxxPypQ94m6BcDrPhqArhggdaTbbAFJEF"+      , "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"+      , "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29"+      , "0488b21e0478412e3afffffffe637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e2902d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"+      , "0488ade40478412e3afffffffe637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e2900f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"+      , "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"+      , "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"+      ]+      -- m/0/2147483647'/1/2147483646'/2+    , [ "26132fdbe7bf89cbc64cf8dafa3f9f88b8666220"+      , "26132fdb"+      , "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt"+      , "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"+      , "L3WAYNAZPxx1fr7KCz7GN9nD5qMBnNiqEJNJMU1z9MMaannAt4aK"+      , "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"+      , "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271"+      , "0488b21e0531a507b8000000029452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"+      , "0488ade40531a507b8000000029452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed27100bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"+      , "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"+      , "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"+      ]+    ]+
+ tests/Network/Haskoin/Crypto/Hash/Tests.hs view
@@ -0,0 +1,70 @@+module Network.Haskoin.Crypto.Hash.Tests (tests) where++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.String (fromString)+import Data.String.Conversions (cs)+import Network.Haskoin.Block+import Network.Haskoin.Crypto+import Network.Haskoin.Test+import Network.Haskoin.Util++tests :: [Test]+tests =+    [ testGroup "Hash tests"+        [ testProperty "join512( split512(h) ) == h" joinSplit512+        , testProperty "decodeCompact . encodeCompact i == i" decEncCompact+        , testProperty "Read/Show 64-byte hash" testReadShowHash512+        , testProperty "From string 64-byte hash" testFromStringHash512+        , testProperty "Read/Show 32-byte hash" testReadShowHash256+        , testProperty "From string 32-byte hash" testFromStringHash256+        , testProperty "Read/Show 20-byte hash" testReadShowHash160+        , testProperty "From string 20-byte hash" testFromStringHash160+        , testProperty "Read/Show checksum" testReadShowCheckSum32+        , testProperty "From string checksum" testFromStringCheckSum32+        ]+    ]++joinSplit512 :: (ArbitraryHash256, ArbitraryHash256) -> Bool+joinSplit512 (ArbitraryHash256 a, ArbitraryHash256 b) =+    (split512 $ join512 (a, b)) == (a, b)++-- After encoding and decoding, we may loose precision so the new result is >=+-- to the old one.+decEncCompact :: Integer -> Bool+decEncCompact i+    -- Integer completely fits inside the mantisse+    | (abs i) <= 0x007fffff = (decodeCompact $ encodeCompact i) == i+    -- Otherwise precision will be lost and the decoded result will+    -- be smaller than the original number+    | i >= 0                = (decodeCompact $ encodeCompact i) < i+    | otherwise             = (decodeCompact $ encodeCompact i) > i+++testReadShowHash512 :: ArbitraryHash512 -> Bool+testReadShowHash512 (ArbitraryHash512 k) = read (show k) == k++testFromStringHash512 :: ArbitraryHash512 -> Bool+testFromStringHash512 (ArbitraryHash512 k) = fromString (cs $ encodeHex $ encode' k) == k+++testReadShowHash256 :: ArbitraryHash256 -> Bool+testReadShowHash256 (ArbitraryHash256 k) = read (show k) == k++testFromStringHash256 :: ArbitraryHash256 -> Bool+testFromStringHash256 (ArbitraryHash256 k) = fromString (cs $ encodeHex $ encode' k) == k+++testReadShowHash160 :: ArbitraryHash160 -> Bool+testReadShowHash160 (ArbitraryHash160 k) = read (show k) == k++testFromStringHash160 :: ArbitraryHash160 -> Bool+testFromStringHash160 (ArbitraryHash160 k) = fromString (cs $ encodeHex $ encode' k) == k+++testReadShowCheckSum32 :: ArbitraryCheckSum32 -> Bool+testReadShowCheckSum32 (ArbitraryCheckSum32 k) = read (show k) == k++testFromStringCheckSum32 :: ArbitraryCheckSum32 -> Bool+testFromStringCheckSum32 (ArbitraryCheckSum32 k) = fromString (cs $ encodeHex $ encode' k) == k
+ tests/Network/Haskoin/Crypto/Hash/Units.hs view
@@ -0,0 +1,1270 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Crypto.Hash.Units (tests) where++import Test.HUnit (assertBool, Assertion)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)++import Data.Maybe (fromJust)+import Data.ByteString (ByteString)++import Network.Haskoin.Block+import Network.Haskoin.Util+import Network.Haskoin.Internals (hmacDRBGNew, hmacDRBGGen, hmacDRBGRsd)++-- Test vectors from NIST+-- http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip+-- About 1/3 of HMAC DRBG SHA-256 test vectors are tested here++tests :: [Test]+tests =+    [ testGroup "HMAC DRBG Suite 1" [mapDRBG t1]+    , testGroup "HMAC DRBG Suite 2" [mapDRBG t2]+    , testGroup "HMAC DRBG Suite 3" [mapDRBG t3]+    , testGroup "HMAC DRBG Suite 4" [mapDRBG t4]+    , testGroup "HMAC DRBG Suite 5 (Reseed)" [mapDRBGRsd r1]+    , testGroup "HMAC DRBG Suite 6 (Reseed)" [mapDRBGRsd r2]+    , testGroup "HMAC DRBG Suite 7 (Reseed)" [mapDRBGRsd r3]+    , testGroup "HMAC DRBG Suite 8 (Reseed)" [mapDRBGRsd r4]+    , testGroup "Compact number representation"+        [ testCase "Compact number representations" testCompact ]+    ]++type TestVector = [ByteString]++mapDRBG :: [TestVector] -> Test.Framework.Test+mapDRBG vs = testCase "HMAC DRBG Vectors" $ mapM_ testDRBG $ zip vs [0..]++mapDRBGRsd :: [TestVector] -> Test.Framework.Test+mapDRBGRsd vs = testCase "HMAC DRBG Vectors" $ mapM_ testDRBGRsd $ zip vs [0..]++testDRBG :: (TestVector, Int) -> Assertion+testDRBG (s,i) = do+    let w1     = hmacDRBGNew (v !! 0) (v !! 1) (v !! 2)+        (w2,_) = hmacDRBGGen w1 128 (v !! 3)+        (_,r)  = hmacDRBGGen w2 128 (v !! 4)+    assertBool name $ fromJust r == (v !! 5)+    where v = map (fromJust . decodeHex) s+          name = "    > HMAC DRBG Vector " ++ (show i)++testDRBGRsd :: (TestVector, Int) -> Assertion+testDRBGRsd (s,i) = do+    let w1 = hmacDRBGNew (v !! 0) (v !! 1) (v !! 2)+        w2 = hmacDRBGRsd w1 (v !! 3) (v !! 4)+        (w3,_) = hmacDRBGGen w2 128 (v !! 5)+        (_,r)  = hmacDRBGGen w3 128 (v !! 6)+    assertBool name $ fromJust r == (v !! 7)+    where v = map (fromJust . decodeHex) s+          name = "    > HMAC DRBG Vector " ++ (show i)++testCompact :: Assertion+testCompact = do+    assertBool "Vector 1" $ (encodeCompact 0x1234560000)    == 0x05123456+    assertBool "Vector 2" $ (decodeCompact 0x05123456)      == 0x1234560000+    assertBool "Vector 3" $ (encodeCompact 0xc0de000000)    == 0x0600c0de+    assertBool "Vector 4" $ (decodeCompact 0x0600c0de)      == 0xc0de000000+    assertBool "Vector 5" $ (encodeCompact (-0x40de000000)) == 0x05c0de00+    assertBool "Vector 6" $ (decodeCompact 0x05c0de00)      == (-0x40de000000)++{-+    [SHA-256]+    [PredictionResistance = False]+    [EntropyInputLen = 256]+    [NonceLen = 128]+    [PersonalizationStringLen = 0]+    [AdditionalInputLen = 0]+    [ReturnedBitsLen = 1024]+-}++t1 :: [TestVector]+t1 =+    [+    -- COUNT = 0+    [ "ca851911349384bffe89de1cbdc46e6831e44d34a4fb935ee285dd14b71a7488"+    , "659ba96c601dc69fc902940805ec0ca8"+    , ""+    , ""+    , ""+    , "e528e9abf2dece54d47c7e75e5fe302149f817ea9fb4bee6f4199697d04d5b89d54fbb978a15b5c443c9ec21036d2460b6f73ebad0dc2aba6e624abf07745bc107694bb7547bb0995f70de25d6b29e2d3011bb19d27676c07162c8b5ccde0668961df86803482cb37ed6d5c0bb8d50cf1f50d476aa0458bdaba806f48be9dcb8"+    ],+    -- COUNT = 1+    [ "79737479ba4e7642a221fcfd1b820b134e9e3540a35bb48ffae29c20f5418ea3"+    , "3593259c092bef4129bc2c6c9e19f343"+    , ""+    , ""+    , ""+    , "cf5ad5984f9e43917aa9087380dac46e410ddc8a7731859c84e9d0f31bd43655b924159413e2293b17610f211e09f770f172b8fb693a35b85d3b9e5e63b1dc252ac0e115002e9bedfb4b5b6fd43f33b8e0eafb2d072e1a6fee1f159df9b51e6c8da737e60d5032dd30544ec51558c6f080bdbdab1de8a939e961e06b5f1aca37"+    ],+    -- COUNT = 2+    [ "b340907445b97a8b589264de4a17c0bea11bb53ad72f9f33297f05d2879d898d"+    , "65cb27735d83c0708f72684ea58f7ee5"+    , ""+    , ""+    , ""+    , "75183aaaf3574bc68003352ad655d0e9ce9dd17552723b47fab0e84ef903694a32987eeddbdc48efd24195dbdac8a46ba2d972f5808f23a869e71343140361f58b243e62722088fe10a98e43372d252b144e00c89c215a76a121734bdc485486f65c0b16b8963524a3a70e6f38f169c12f6cbdd169dd48fe4421a235847a23ff"+    ],+    -- COUNT = 3+    [ "8e159f60060a7d6a7e6fe7c9f769c30b98acb1240b25e7ee33f1da834c0858e7"+    , "c39d35052201bdcce4e127a04f04d644"+    , ""+    , ""+    , ""+    , "62910a77213967ea93d6457e255af51fc79d49629af2fccd81840cdfbb4910991f50a477cbd29edd8a47c4fec9d141f50dfde7c4d8fcab473eff3cc2ee9e7cc90871f180777a97841597b0dd7e779eff9784b9cc33689fd7d48c0dcd341515ac8fecf5c55a6327aea8d58f97220b7462373e84e3b7417a57e80ce946d6120db5"+    ],+    -- COUNT = 4+    [ "74755f196305f7fb6689b2fe6835dc1d81484fc481a6b8087f649a1952f4df6a"+    , "c36387a544a5f2b78007651a7b74b749"+    , ""+    , ""+    , ""+    , "b2896f3af4375dab67e8062d82c1a005ef4ed119d13a9f18371b1b873774418684805fd659bfd69964f83a5cfe08667ddad672cafd16befffa9faed49865214f703951b443e6dca22edb636f3308380144b9333de4bcb0735710e4d9266786342fc53babe7bdbe3c01a3addb7f23c63ce2834729fabbd419b47beceb4a460236"+    ],+    -- COUNT = 5+    [ "4b222718f56a3260b3c2625a4cf80950b7d6c1250f170bd5c28b118abdf23b2f"+    , "7aed52d0016fcaef0b6492bc40bbe0e9"+    , ""+    , ""+    , ""+    , "a6da029b3665cd39fd50a54c553f99fed3626f4902ffe322dc51f0670dfe8742ed48415cf04bbad5ed3b23b18b7892d170a7dcf3ef8052d5717cb0c1a8b3010d9a9ea5de70ae5356249c0e098946030c46d9d3d209864539444374d8fbcae068e1d6548fa59e6562e6b2d1acbda8da0318c23752ebc9be0c1c1c5b3cf66dd967"+    ],+    -- COUNT = 6+    [ "b512633f27fb182a076917e39888ba3ff35d23c3742eb8f3c635a044163768e0"+    , "e2c39b84629a3de5c301db5643af1c21"+    , ""+    , ""+    , ""+    , "fb931d0d0194a97b48d5d4c231fdad5c61aedf1c3a55ac24983ecbf38487b1c93396c6b86ff3920cfa8c77e0146de835ea5809676e702dee6a78100da9aa43d8ec0bf5720befa71f82193205ac2ea403e8d7e0e6270b366dc4200be26afd9f63b7e79286a35c688c57cbff55ac747d4c28bb80a2b2097b3b62ea439950d75dff"+    ],+    -- COUNT = 7+    [ "aae3ffc8605a975befefcea0a7a286642bc3b95fb37bd0eb0585a4cabf8b3d1e"+    , "9504c3c0c4310c1c0746a036c91d9034"+    , ""+    , ""+    , ""+    , "2819bd3b0d216dad59ddd6c354c4518153a2b04374b07c49e64a8e4d055575dfbc9a8fcde68bd257ff1ba5c6000564b46d6dd7ecd9c5d684fd757df62d85211575d3562d7814008ab5c8bc00e7b5a649eae2318665b55d762de36eba00c2906c0e0ec8706edb493e51ca5eb4b9f015dc932f262f52a86b11c41e9a6d5b3bd431"+    ],+    -- COUNT = 8+    [ "b9475210b79b87180e746df704b3cbc7bf8424750e416a7fbb5ce3ef25a82cc6"+    , "24baf03599c10df6ef44065d715a93f7"+    , ""+    , ""+    , ""+    , "ae12d784f796183c50db5a1a283aa35ed9a2b685dacea97c596ff8c294906d1b1305ba1f80254eb062b874a8dfffa3378c809ab2869aa51a4e6a489692284a25038908a347342175c38401193b8afc498077e10522bec5c70882b7f760ea5946870bd9fc72961eedbe8bff4fd58c7cc1589bb4f369ed0d3bf26c5bbc62e0b2b2"+    ],+    -- COUNT = 9+    [ "27838eb44ceccb4e36210703ebf38f659bc39dd3277cd76b7a9bcd6bc964b628"+    , "39cfe0210db2e7b0eb52a387476e7ea1"+    , ""+    , ""+    , ""+    , "e5e72a53605d2aaa67832f97536445ab774dd9bff7f13a0d11fd27bf6593bfb52309f2d4f09d147192199ea584503181de87002f4ee085c7dc18bf32ce5315647a3708e6f404d6588c92b2dda599c131aa350d18c747b33dc8eda15cf40e95263d1231e1b4b68f8d829f86054d49cfdb1b8d96ab0465110569c8583a424a099a"+    ],+    -- COUNT = 10+    [ "d7129e4f47008ad60c9b5d081ff4ca8eb821a6e4deb91608bf4e2647835373a5"+    , "a72882773f78c2fc4878295840a53012"+    , ""+    , ""+    , ""+    , "0cbf48585c5de9183b7ff76557f8fc9ebcfdfde07e588a8641156f61b7952725bbee954f87e9b937513b16bba0f2e523d095114658e00f0f3772175acfcb3240a01de631c19c5a834c94cc58d04a6837f0d2782fa53d2f9f65178ee9c837222494c799e64c60406069bd319549b889fa00a0032dd7ba5b1cc9edbf58de82bfcd"+    ],+    -- COUNT = 11+    [ "67fe5e300c513371976c80de4b20d4473889c9f1214bce718bc32d1da3ab7532"+    , "e256d88497738a33923aa003a8d7845c"+    , ""+    , ""+    , ""+    , "b44660d64ef7bcebc7a1ab71f8407a02285c7592d755ae6766059e894f694373ed9c776c0cfc8594413eefb400ed427e158d687e28da3ecc205e0f7370fb089676bbb0fa591ec8d916c3d5f18a3eb4a417120705f3e2198154cd60648dbfcfc901242e15711cacd501b2c2826abe870ba32da785ed6f1fdc68f203d1ab43a64f"+    ],+    -- COUNT = 12+    [ "de8142541255c46d66efc6173b0fe3ffaf5936c897a3ce2e9d5835616aafa2cb"+    , "d01f9002c407127bc3297a561d89b81d"+    , ""+    , ""+    , ""+    , "64d1020929d74716446d8a4e17205d0756b5264867811aa24d0d0da8644db25d5cde474143c57d12482f6bf0f31d10af9d1da4eb6d701bdd605a8db74fb4e77f79aaa9e450afda50b18d19fae68f03db1d7b5f1738d2fdce9ad3ee9461b58ee242daf7a1d72c45c9213eca34e14810a9fca5208d5c56d8066bab1586f1513de7"+    ],+    -- COUNT = 13+    [ "4a8e0bd90bdb12f7748ad5f147b115d7385bb1b06aee7d8b76136a25d779bcb7"+    , "7f3cce4af8c8ce3c45bdf23c6b181a00"+    , ""+    , ""+    , ""+    , "320c7ca4bbeb7af977bc054f604b5086a3f237aa5501658112f3e7a33d2231f5536d2c85c1dad9d9b0bf7f619c81be4854661626839c8c10ae7fdc0c0b571be34b58d66da553676167b00e7d8e49f416aacb2926c6eb2c66ec98bffae20864cf92496db15e3b09e530b7b9648be8d3916b3c20a3a779bec7d66da63396849aaf"+    ],+    -- COUNT = 14+    [ "451ed024bc4b95f1025b14ec3616f5e42e80824541dc795a2f07500f92adc665"+    , "2f28e6ee8de5879db1eccd58c994e5f0"+    , ""+    , ""+    , ""+    , "3fb637085ab75f4e95655faae95885166a5fbb423bb03dbf0543be063bcd48799c4f05d4e522634d9275fe02e1edd920e26d9accd43709cb0d8f6e50aa54a5f3bdd618be23cf73ef736ed0ef7524b0d14d5bef8c8aec1cf1ed3e1c38a808b35e61a44078127c7cb3a8fd7addfa50fcf3ff3bc6d6bc355d5436fe9b71eb44f7fd"+    ]+    ]++{-+    [SHA-256]+    [PredictionResistance = False]+    [EntropyInputLen = 256]+    [NonceLen = 128]+    [PersonalizationStringLen = 0]+    [AdditionalInputLen = 256]+    [ReturnedBitsLen = 1024]+-}++t2 :: [TestVector]+t2 =+    [+    -- COUNT = 0+    [ "d3cc4d1acf3dde0c4bd2290d262337042dc632948223d3a2eaab87da44295fbd"+    , "0109b0e729f457328aa18569a9224921"+    , ""+    , "3c311848183c9a212a26f27f8c6647e40375e466a0857cc39c4e47575d53f1f6"+    , "fcb9abd19ccfbccef88c9c39bfb3dd7b1c12266c9808992e305bc3cff566e4e4"+    , "9c7b758b212cd0fcecd5daa489821712e3cdea4467b560ef5ddc24ab47749a1f1ffdbbb118f4e62fcfca3371b8fbfc5b0646b83e06bfbbab5fac30ea09ea2bc76f1ea568c9be0444b2cc90517b20ca825f2d0eccd88e7175538b85d90ab390183ca6395535d34473af6b5a5b88f5a59ee7561573337ea819da0dcc3573a22974"+    ],+    -- COUNT = 1+    [ "f97a3cfd91faa046b9e61b9493d436c4931f604b22f1081521b3419151e8ff06"+    , "11f3a7d43595357d58120bd1e2dd8aed"+    , ""+    , "517289afe444a0fe5ed1a41dbbb5eb17150079bdd31e29cf2ff30034d8268e3b"+    , "88028d29ef80b4e6f0fe12f91d7449fe75062682e89c571440c0c9b52c42a6e0"+    , "c6871cff0824fe55ea7689a52229886730450e5d362da5bf590dcf9acd67fed4cb32107df5d03969a66b1f6494fdf5d63d5b4d0d34ea7399a07d0116126d0d518c7c55ba46e12f62efc8fe28a51c9d428e6d371d7397ab319fc73ded4722e5b4f30004032a6128df5e7497ecf82ca7b0a50e867ef6728a4f509a8c859087039c"+    ],+    -- COUNT = 2+    [ "0f2f23d64f481cabec7abb01db3aabf125c3173a044b9bf26844300b69dcac8b"+    , "9a5ae13232b43aa19cfe8d7958b4b590"+    , ""+    , "ec4c7a62acab73385f567da10e892ff395a0929f959231a5628188ce0c26e818"+    , "6b97b8c6b6bb8935e676c410c17caa8042aa3145f856d0a32b641e4ae5298648"+    , "7480a361058bd9afa3db82c9d7586e42269102013f6ec5c269b6d05f17987847748684766b44918fd4b65e1648622fc0e0954178b0279dfc9fa99b66c6f53e51c4860131e9e0644287a4afe4ca8e480417e070db68008a97c3397e4b320b5d1a1d7e1d18a95cfedd7d1e74997052bf649d132deb9ec53aae7dafdab55e6dae93"+    ],+    -- COUNT = 3+    [ "53c56660c78481be9c63284e005fcc14fbc7fb27732c9bf1366d01a426765a31"+    , "dc7a14d0eb5b0b3534e717a0b3c64614"+    , ""+    , "3aa848706ecb877f5bedf4ffc332d57c22e08747a47e75cff6f0fd1316861c95"+    , "9a401afa739b8f752fddacd291e0b854f5eff4a55b515e20cb319852189d3722"+    , "5c0eb420e0bf41ce9323e815310e4e8303cd677a8a8b023f31f0d79f0ca15aeb636099a369fd074d69889865eac1b72ab3cbfebdb8cf460b00072802e2ec648b1349a5303be4ccaadd729f1a9ea17482fd026aaeb93f1602bc1404b9853adde40d6c34b844cf148bc088941ecfc1642c8c0b9778e45f3b07e06e21ee2c9e0300"+    ],+    -- COUNT = 4+    [ "f63c804404902db334c54bb298fc271a21d7acd9f770278e089775710bf4fdd7"+    , "3e45009ea9cb2a36ba1aa4bf39178200"+    , ""+    , "d165a13dc8cc43f3f0952c3f5d3de4136954d983683d4a3e6d2dc4c89bf23423"+    , "75106bc86d0336df85097f6af8e80e2da59046a03fa65b06706b8bbc7ffc6785"+    , "6363139bba32c22a0f5cd23ca6d437b5669b7d432f786b8af445471bee0b2d24c9d5f2f93717cbe00d1f010cc3b9c515fc9f7336d53d4d26ba5c0d76a90186663c8582eb739c7b6578a3328bf68dc2cec2cd89b3a90201f6993adcc854df0f5c6974d0f5570765a15fe03dbce28942dd2fd16ba2027e68abac83926969349af8"+    ],+    -- COUNT = 5+    [ "2aaca9147da66c176615726b69e3e851cc3537f5f279fe7344233d8e44cfc99d"+    , "4e171f080af9a6081bee9f183ac9e340"+    , ""+    , "d75a2a6eb66c3833e50f5ec3d2e434cf791448d618026d0c360806d120ded669"+    , "b643b74c15b37612e6577ed7ca2a4c67a78d560af9eb50a4108fca742e87b8d6"+    , "501dcdc977f4ba856f24eaa4968b374bebb3166b280334cb510232c31ebffde10fa47b7840ef3fe3b77725c2272d3a1d4219baf23e0290c622271edcced58838cf428f0517425d2e19e0d8c89377eecfc378245f283236fafa466c914b99672ceafab369e8889a0c866d8bd639db9fb797254262c6fd44cfa9045ad6340a60ef"+    ],+    -- COUNT = 6+    [ "a2e4cd48a5cf918d6f55942d95fcb4e8465cdc4f77b7c52b6fae5b16a25ca306"+    , "bef036716440db6e6d333d9d760b7ca8"+    , ""+    , "bfa591c7287f3f931168f95e38869441d1f9a11035ad8ea625bb61b9ea17591c"+    , "c00c735463bca215adc372cb892b05e939bf669583341c06d4e31d0e5b363a37"+    , "e7d136af69926a5421d4266ee0420fd729f2a4f7c295d3c966bdfa05268180b508b8a2852d1b3a06fd2ab3e13c54005123ef319f42d0c6d3a575e6e7e1496cb28aacadbcf83740fba8f35fcee04bb2ed8a51db3d3362b01094a62fb57e33c99a432f29fce6676cffbbcc05107e794e75e44a02d5e6d9d748c5fbff00a0178d65"+    ],+    -- COUNT = 7+    [ "95a67771cba69011a79776e713145d309edae56fad5fd6d41d83eaff89df6e5e"+    , "be5b5164e31ecc51ba6f7c3c5199eb33"+    , ""+    , "065f693b229a7c4fd373cd15b3807552dd9bf98c5485cef361949d4e7d774b53"+    , "9afb62406f0e812c4f156d58b19a656c904813c1b4a45a0029ae7f50731f8014"+    , "f61b61a6e79a41183e8ed6647899d2dc85cdaf5c3abf5c7f3bf37685946dc28f4923dc842f2d4326bd6ce0d50a84cb3ba869d72a36e246910eba6512ba36cd7ed3a5437c9245b00a344308c792b668b458d3c3e16dee2fbec41867da31084d46d8ec168de2148ef64fc5b72069abf5a6ada1ead2b7146bb793ff1c9c3690fa56"+    ],+    -- COUNT = 8+    [ "a459e1815cbca4514ec8094d5ab2414a557ba6fe10e613c345338d0521e4bf90"+    , "62221392e2552e76cd0d36df6e6068eb"+    , ""+    , "0a3642b02b23b3ef62c701a63401124022f5b896de86dab6e6c7451497aa1dcc"+    , "c80514865901371c45ba92d9f95d50bb7c9dd1768cb3dfbc45b968da94965c6e"+    , "464e6977b8adaef307c9623e41c357013249c9ffd77f405f3925cebb69f151ce8fbb6a277164002aee7858fc224f6499042aa1e6322deee9a5d133c31d640e12a7487c731ba03ad866a24675badb1d79220c40be689f79c2a0be93cb4dada3e0eac4ab140cb91998b6f11953e68f2319b050c40f71c34de9905ae41b2de1c2f6"+    ],+    -- COUNT = 9+    [ "252c2cad613e002478162861880979ee4e323025eebb6fb2e0aa9f200e28e0a1"+    , "d001bc9a8f2c8c242e4369df0c191989"+    , ""+    , "9bcfc61cb2bc000034bb3db980eb47c76fb5ecdd40553eff113368d639b947fd"+    , "8b0565c767c2610ee0014582e9fbecb96e173005b60e9581503a6dca5637a26e"+    , "e96c15fe8a60692b0a7d67171e0195ff6e1c87aab844221e71700d1bbee75feea695f6a740c9760bbe0e812ecf4061d8f0955bc0195e18c4fd1516ebca50ba6a6db86881737dbab8321707675479b87611db6af2c97ea361a5484555ead454defb1a64335de964fc803d40f3a6f057893d2afc25725754f4f00abc51920743dc"+    ],+    -- COUNT = 10+    [ "8be0ca6adc8b3870c9d69d6021bc1f1d8eb9e649073d35ee6c5aa0b7e56ad8a5"+    , "9d1265f7d51fdb65377f1e6edd6ae0e4"+    , ""+    , "da86167ac997c406bb7979f423986a84ec6614d6caa7afc10aff0699a9b2cf7f"+    , "e4baa3c555950b53e2bfdba480cb4c94b59381bac1e33947e0c22e838a9534cf"+    , "64384ecc4ea6b458efc227ca697eac5510092265520c0a0d8a0ccf9ed3ca9d58074671188c6a7ad16d0b050cdc072c125d7298d3a31d9f044a9ee40da0089a84fea28cc7f05f1716db952fad29a0e779635cb7a912a959be67be2f0a4170aace2981802e2ff6467e5b46f0ffbff3b42ba5935fd553c82482ac266acf1cd247d7"+    ],+    -- COUNT = 11+    [ "d43a75b6adf26d60322284cb12ac38327792442aa8f040f60a2f331b33ac4a8f"+    , "0682f8b091f811afacaacaec9b04d279"+    , ""+    , "7fd3b8f512940da7de5d80199d9a7b42670c04a945775a3dba869546cbb9bc65"+    , "2575db20bc7aafc2a90a5dabab760db851d754777bc9f05616af1858b24ff3da"+    , "0da7a8dc73c163014bf0841913d3067806456bbca6d5de92b85534c6545467313648d71ef17c923d090dc92cff8d4d1a9a2bb63e001dc2e8ab1a597999be3d6cf70ff63fee9985801395fbd4f4990430c4259fcae4fa1fcd73dc3187ccc102d04af7c07532885e5a226fc42809c48f22eecf4f6ab996ae4fcb144786957d9f41"+    ],+    -- COUNT = 12+    [ "64352f236af5d32067a529a8fd05ba00a338c9de306371a0b00c36e610a48d18"+    , "df99ed2c7608c870624b962a5dc68acd"+    , ""+    , "da416335e7aaf60cf3d06fb438735ce796aad09034f8969c8f8c3f81e32fef24"+    , "a28c07c21a2297311adf172c19e83ca0a87731bdffb80548978d2d1cd82cf8a3"+    , "132b9f25868729e3853d3c51f99a3b5fae6d4204bea70890daf62e042b776a526c8fb831b80a6d5d3f153237df1fd39b6fd9137963f5516d9cdd4e3f9195c46e9972c15d3edc6606e3368bde1594977fb88d0ca6e6f5f3d057ccadc7d7dab77dfc42658a1e972aa446b20d418286386a52dfc1c714d2ac548713268b0b709729"+    ],+    -- COUNT = 13+    [ "282f4d2e05a2cd30e9087f5633089389449f04bac11df718c90bb351cd3653a5"+    , "90a7daf3c0de9ea286081efc4a684dfb"+    , ""+    , "2630b4ccc7271cc379cb580b0aaede3d3aa8c1c7ba002cf791f0752c3d739007"+    , "c31d69de499f1017be44e3d4fa77ecebc6a9b9934749fcf136f267b29115d2cc"+    , "c899094520e0197c37b91dd50778e20a5b950decfb308d39f1db709447ae48f6101d9abe63a783fbb830eec1d359a5f61a2013728966d349213ee96382614aa4135058a967627183810c6622a2158cababe3b8ab99169c89e362108bf5955b4ffc47440f87e4bad0d36bc738e737e072e64d8842e7619f1be0af1141f05afe2d"+    ],+    -- COUNT = 14+    [ "13c752b9e745ce77bbc7c0dbda982313d3fe66f903e83ebd8dbe4ff0c11380e9"+    , "f1a533095d6174164bd7c82532464ae7"+    , ""+    , "4f53db89b9ba7fc00767bc751fb8f3c103fe0f76acd6d5c7891ab15b2b7cf67c"+    , "582c2a7d34679088cca6bd28723c99aac07db46c332dc0153d1673256903b446"+    , "6311f4c0c4cd1f86bd48349abb9eb930d4f63df5e5f7217d1d1b91a71d8a6938b0ad2b3e897bd7e3d8703db125fab30e03464fad41e5ddf5bf9aeeb5161b244468cfb26a9d956931a5412c97d64188b0da1bd907819c686f39af82e91cfeef0cbffb5d1e229e383bed26d06412988640706815a6e820796876f416653e464961"+    ]+    ]++{-+    [SHA-256]+    [PredictionResistance = False]+    [EntropyInputLen = 256]+    [NonceLen = 128]+    [PersonalizationStringLen = 256]+    [AdditionalInputLen = 0]+    [ReturnedBitsLen = 1024]+-}++t3 :: [TestVector]+t3 =+    [+    -- COUNT = 0+    [ "5cacc68165a2e2ee20812f35ec73a79dbf30fd475476ac0c44fc6174cdac2b55"+    , "6f885496c1e63af620becd9e71ecb824"+    , "e72dd8590d4ed5295515c35ed6199e9d211b8f069b3058caa6670b96ef1208d0"+    , ""+    , ""+    , "f1012cf543f94533df27fedfbf58e5b79a3dc517a9c402bdbfc9a0c0f721f9d53faf4aafdc4b8f7a1b580fcaa52338d4bd95f58966a243cdcd3f446ed4bc546d9f607b190dd69954450d16cd0e2d6437067d8b44d19a6af7a7cfa8794e5fbd728e8fb2f2e8db5dd4ff1aa275f35886098e80ff844886060da8b1e7137846b23b"+    ],+    -- COUNT = 1+    [ "8df013b4d103523073917ddf6a869793059e9943fc8654549e7ab22f7c29f122"+    , "da2625af2ddd4abcce3cf4fa4659d84e"+    , "b571e66d7c338bc07b76ad3757bb2f9452bf7e07437ae8581ce7bc7c3ac651a9"+    , ""+    , ""+    , "b91cba4cc84fa25df8610b81b641402768a2097234932e37d590b1154cbd23f97452e310e291c45146147f0da2d81761fe90fba64f94419c0f662b28c1ed94da487bb7e73eec798fbcf981b791d1be4f177a8907aa3c401643a5b62b87b89d66b3a60e40d4a8e4e9d82af6d2700e6f535cdb51f75c321729103741030ccc3a56"+    ],+    -- COUNT = 2+    [ "565b2b77937ba46536b0f693b3d5e4a8a24563f9ef1f676e8b5b2ef17823832f"+    , "4ef3064ec29f5b7f9686d75a23d170e3"+    , "3b722433226c9dba745087270ab3af2c909425ba6d39f5ce46f07256068319d9"+    , ""+    , ""+    , "d144ee7f8363d128872f82c15663fe658413cd42651098e0a7c51a970de75287ec943f9061e902280a5a9e183a7817a44222d198fbfab184881431b4adf35d3d1019da5a90b3696b2349c8fba15a56d0f9d010a88e3f9eeedb67a69bcaa71281b41afa11af576b765e66858f0eb2e4ec4081609ec81da81df0a0eb06787340ea"+    ],+    -- COUNT = 3+    [ "fc3832a91b1dcdcaa944f2d93cbceb85c267c491b7b59d017cde4add79a836b6"+    , "d5e76ce9eabafed06e33a913e395c5e0"+    , "ffc5f6eefd51da64a0f67b5f0cf60d7ab43fc7836bca650022a0cee57a43c148"+    , ""+    , ""+    , "0e713c6cc9a4dbd4249201d12b7bf5c69c3e18eb504bf3252db2f43675e17d99b6a908400cea304011c2e54166dae1f20260008efe4e06a87e0ce525ca482bca223a902a14adcf2374a739a5dfeaf14cadd72efa4d55d15154c974d9521535bcb70658c5b6c944020afb04a87b223b4b8e5d89821704a9985bb010405ba8f3d4"+    ],+    -- COUNT = 4+    [ "8009eb2cb49fdf16403bcdfd4a9f952191062acb9cc111eca019f957fb9f4451"+    , "355598866952394b1eddd85d59f81c9d"+    , "09ff1d4b97d83b223d002e05f754be480d13ba968e5aac306d71cc9fc49cc2dd"+    , ""+    , ""+    , "9550903c2f02cf77c8f9c9a37041d0040ee1e3ef65ba1a1fbbcf44fb7a2172bd6b3aaabe850281c3a1778277bacd09614dfefececac64338ae24a1bf150cbf9d9541173a82ecba08aa19b75abb779eb10efa4257d5252e8afcac414bc3bb5d3006b6f36fb9daea4c8c359ef6cdbeff27c1068571dd3c89dc87eda9190086888d"+    ],+    -- COUNT = 5+    [ "a6e4c9a8bd6da23b9c2b10a7748fd08c4f782fadbac7ea501c17efdc6f6087bd"+    , "acdc47edf1d3b21d0aec7631abb6d7d5"+    , "c16ee0908a5886dccf332fbc61de9ec7b7972d2c4c83c477409ce8a15c623294"+    , ""+    , ""+    , "a52f93ccb363e2bdf0903622c3caedb7cffd04b726052b8d455744c71b76dee1b71db9880dc3c21850489cb29e412d7d80849cfa9151a151dcbf32a32b4a54cac01d3200200ed66a3a5e5c131a49655ffbf1a8824ff7f265690dffb4054df46a707b9213924c631c5bce379944c856c4f7846e281ac89c64fad3a49909dfb92b"+    ],+    -- COUNT = 6+    [ "59d6307460a9bdd392dfc0904973991d585696010a71e52d590a5039b4849fa4"+    , "34a0aafb95917cbf8c38fc5548373c05"+    , "0407b7c57bc11361747c3d67526c36e228028a5d0b145d66ab9a2fe4b07507a0"+    , ""+    , ""+    , "299aba0661315211b09d2861855d0b4b125ab24649461341af6abd903ed6f025223b3299f2126fcad44c675166d800619cf49540946b12138989417904324b0ddad121327211a297f11259c9c34ce4c70c322a653675f78d385e4e2443f8058d141195e17e0bd1b9d44bf3e48c376e6eb44ef020b11cf03eb141c46ecb43cf3d"+    ],+    -- COUNT = 7+    [ "9ae3506aadbc8358696ba1ba17e876e1157b7048235921503d36d9211b430342"+    , "9abf7d66afee5d2b811cba358bbc527d"+    , "0d645f6238e9ceb038e4af9772426ca110c5be052f8673b8b5a65c4e53d2f519"+    , ""+    , ""+    , "5f032c7fec6320fe423b6f38085cbad59d826085afe915247b3d546c4c6b174554dd4877c0d671de9554b505393a44e71f209b70f991ac8aa6e08f983fff2a4c817b0cd26c12b2c929378506489a75b2025b358cb5d0400821e7e252ac6376cd94a40c911a7ed8b6087e3de5fa39fa6b314c3ba1c593b864ce4ff281a97c325b"+    ],+    -- COUNT = 8+    [ "96ae3b8775b36da2a29b889ad878941f43c7d51295d47440cd0e3c4999193109"+    , "1fe022a6fc0237b055d4d6a7036b18d5"+    , "1e40e97362d0a823d3964c26b81ab53825c56446c5261689011886f19b08e5c2"+    , ""+    , ""+    , "e707cd14b06ce1e6dbcceaedbf08d88891b03f44ad6a797bd12fdeb557d0151df9346a028dec004844ca46adec3051dafb345895fa9f4604d8a13c8ff66ae093fa63c4d9c0816d55a0066d31e8404c841e87b6b2c7b5ae9d7afb6840c2f7b441bf2d3d8bd3f40349c1c014347c1979213c76103e0bece26ad7720601eff42275"+    ],+    -- COUNT = 9+    [ "33f5120396336e51ee3b0b619b5f873db05ca57cda86aeae2964f51480d14992"+    , "6f1f6e9807ba5393edcf3cb4e4bb6113"+    , "3709605af44d90196867c927512aa8ba31837063337b4879408d91a05c8efa9f"+    , ""+    , ""+    , "8b8291126ded9acef12516025c99ccce225d844308b584b872c903c7bc6467599a1cead003dc4c70f6d519f5b51ce0da57f53da90dbe8f666a1a1dde297727fee2d44cebd1301fc1ca75956a3fcae0d374e0df6009b668fd21638d2b733e6902d22d5bfb4af1b455975e08eef0ebe4dc87705801e7776583c8de11672729f723"+    ],+    -- COUNT = 10+    [ "ad300b799005f290fee7f930eebce158b98fb6cb449987fe433f955456b35300"+    , "06aa2514e4bd114edf7ac105cfef2772"+    , "87ada711465e4169da2a74c931afb9b5a5b190d07b7af342aa99570401c3ee8a"+    , ""+    , ""+    , "80d7c606ff49415a3a92ba1f2943235c01339c8f9cd0b0511fbfdf3ef23c42ffff008524193faaa4b7f2f2eb0cfa221d9df89bd373fe4e158ec06fad3ecf1eb48b8239b0bb826ee69d773883a3e8edac66254610ff70b6609836860e39ea1f3bfa04596fee1f2baca6cebb244774c6c3eb4af1f02899eba8f4188f91776de16f"+    ],+    -- COUNT = 11+    [ "130b044e2c15ab89375e54b72e7baae6d4cad734b013a090f4df057e634f6ff0"+    , "65fd6ac602cd44107d705dbc066e52b6"+    , "f374aba16f34d54aae5e494505b67d3818ef1c08ea24967a76876d4361379aec"+    , ""+    , ""+    , "5d179534fb0dba3526993ed8e27ec9f915183d967336bb24352c67f4ab5d7935d3168e57008da851515efbaecb69904b6d899d3bfa6e9805659aef2942c4903875b8fcbc0d1d24d1c075f0ff667c1fc240d8b410dff582fa71fa30878955ce2ed786ef32ef852706e62439b69921f26e84e0f54f62b938f04905f05fcd7c2204"+    ],+    -- COUNT = 12+    [ "716430e999964b35459c17921fe5f60e09bd9ab234cb8f4ba4932bec4a60a1d5"+    , "9533b711e061b07d505da707cafbca03"+    , "372ae616d1a1fc45c5aecad0939c49b9e01c93bfb40c835eebd837af747f079d"+    , ""+    , ""+    , "a80d6a1b2d0ce01fe0d26e70fb73da20d45841cf01bfbd50b90d2751a46114c0e758cb787d281a0a9cf62f5c8ce2ee7ca74fefff330efe74926acca6d6f0646e4e3c1a1e52fce1d57b88beda4a5815896f25f38a652cc240deb582921c8b1d03a1da966dd04c2e7eee274df2cd1837096b9f7a0d89a82434076bc30173229a60"+    ],+    -- COUNT = 13+    [ "7679f154296e6d580854826539003a82d1c54e2e062c619d00da6c6ac820789b"+    , "55d12941b0896462e7d888e5322a99a3"+    , "ba4d1ed696f58ef64596c76cee87cc1ca83069a79e7982b9a06f9d62f4209faf"+    , ""+    , ""+    , "10dc7cd2bb68c2c28f76d1b04ae2aa287071e04c3b688e1986b05cc1209f691daa55868ebb05b633c75a40a32b49663185fe5bb8f906008347ef51590530948b87613920014802e5864e0758f012e1eae31f0c4c031ef823aecfb2f8a73aaa946fc507037f9050b277bdeaa023123f9d22da1606e82cb7e56de34bf009eccb46"+    ],+    -- COUNT = 14+    [ "8ca4a964e1ff68753db86753d09222e09b888b500be46f2a3830afa9172a1d6d"+    , "a59394e0af764e2f21cf751f623ffa6c"+    , "eb8164b3bf6c1750a8de8528af16cffdf400856d82260acd5958894a98afeed5"+    , ""+    , ""+    , "fc5701b508f0264f4fdb88414768e1afb0a5b445400dcfdeddd0eba67b4fea8c056d79a69fd050759fb3d626b29adb8438326fd583f1ba0475ce7707bd294ab01743d077605866425b1cbd0f6c7bba972b30fbe9fce0a719b044fcc1394354895a9f8304a2b5101909808ddfdf66df6237142b6566588e4e1e8949b90c27fc1f"+    ]+    ]++{-+    [SHA-256]+    [PredictionResistance = False]+    [EntropyInputLen = 256]+    [NonceLen = 128]+    [PersonalizationStringLen = 256]+    [AdditionalInputLen = 256]+    [ReturnedBitsLen = 1024]+-}++t4 :: [TestVector]+t4 =+    [+    -- COUNT = 0+    [ "5d3286bc53a258a53ba781e2c4dcd79a790e43bbe0e89fb3eed39086be34174b"+    , "c5422294b7318952ace7055ab7570abf"+    , "2dba094d008e150d51c4135bb2f03dcde9cbf3468a12908a1b025c120c985b9d"+    , "793a7ef8f6f0482beac542bb785c10f8b7b406a4de92667ab168ecc2cf7573c6"+    , "2238cdb4e23d629fe0c2a83dd8d5144ce1a6229ef41dabe2a99ff722e510b530"+    , "d04678198ae7e1aeb435b45291458ffde0891560748b43330eaf866b5a6385e74c6fa5a5a44bdb284d436e98d244018d6acedcdfa2e9f499d8089e4db86ae89a6ab2d19cb705e2f048f97fb597f04106a1fa6a1416ad3d859118e079a0c319eb95686f4cbcce3b5101c7a0b010ef029c4ef6d06cdfac97efb9773891688c37cf"+    ],+    -- COUNT = 1+    [ "c2a566a9a1817b15c5c3b778177ac87c24e797be0a845f11c2fe399dd37732f2"+    , "cb1894eb2b97b3c56e628329516f86ec"+    , "13ce4d8dd2db9796f94156c8e8f0769b0aa1c82c1323b61536603bca37c9ee29"+    , "413dd83fe56835abd478cb9693d67635901c40239a266462d3133b83e49c820b"+    , "d5c4a71f9d6d95a1bedf0bd2247c277d1f84a4e57a4a8825b82a2d097de63ef1"+    , "b3a3698d777699a0dd9fa3f0a9fa57832d3cefac5df24437c6d73a0fe41040f1729038aef1e926352ea59de120bfb7b073183a34106efed6278ff8ad844ba0448115dfddf3319a82de6bb11d80bd871a9acd35c73645e1270fb9fe4fa88ec0e465409ea0cba809fe2f45e04943a2e396bbb7dd2f4e0795303524cc9cc5ea54a1"+    ],+    -- COUNT = 2+    [ "a33288a96f41dd54b945e060c8bd0c094f1e28267cc1dcbba52063c1a9d54c4d"+    , "36918c977e1a7276a2bb475591c367b7"+    , "6aa528c940962638dc2201738850fd1fe6f5d0eb9f687ff1af39d9c7b36830d9"+    , "37ee633a635e43af59abdb1762c7ea45bfe060ec1d9077ecd2a43a658673f3c7"+    , "2eb96f2e28fa9f674bb03ade703b8f791ee5356e2ee85c7ed5bda96325256c61"+    , "db2f91932767eb846961ce5321c7003431870508e8c6f8d432ca1f9cee5cdc1aed6e0f133d317eb6990c4b3b0a360cdfb5b43a6e712bd46bca04c414868fab22c6a49c4b89c812697c3a7fbfc8ddf10c8aa5ebf13a09fd114eb2a02a07f69786f3ce7fd30231f22779bc8db103b13fa546dbc45a89a86275281172761683d384"+    ],+    -- COUNT = 3+    [ "5f37b6e47e1776e735adc03d4b999879477ff4a206231924033d94c0114f911b"+    , "7d12d62c79c9f6234ae0314156947459"+    , "92d4d9fab5f8bf5119f2663a9df7334f50dcde74fb9d7732f7eba56501e60d54"+    , "c9aef0d7a9ba7345d08b6d5b5ce5645c7495b8685e6b93846ffcf470f5abd40d"+    , "50d9d1f5074f7d9f1a24a9c63aa47b94da5ba78db1b0f18e4d4fe45c6875813c"+    , "20d942bbd7d98700faa37e94d53bf74f2d6bd1d8c95c0b88d842c4857797d59e7c8788aeeac29740122f208f703bf35dc32b0035db0648384feb6aa17a3274bc09b2d2b746c5a06fd82f4469fb86131a49482cb7be7d9b4b95042394cfb18b13f333ec0fe5c227bf1d8f33ecb2e42e358b6c3e034cb585331bd1d27f638029b9"+    ],+    -- COUNT = 4+    [ "2311c5afd64c584484b2729e84db80c0b4063fe9ca7edc83350488d7e67264a0"+    , "6a6dfd975a0dc7b72df1f107c4b3b3a6"+    , "2abd870ec5fe26ed14dfa57a3309f920131b70580c3639af2645cd1af93db1b1"+    , "c6e532a3b25653b6002aed5269cc2118749306e736bde039d4d569d4f967773f"+    , "5e7d26c4da769c373092b2b4f72b109fe34bdb7d169ea38f78ebae5df4a15759"+    , "cacaeb1b4ac2305d8714eb50cbe1c67c5a2c0bbc7938fdfdcafef7c85fc40becbf777a4cfb6f14c6eee320943a493d2b0a744a6eb3c256ee9a3763037437df9adce3e2260f0c35e958af0edb5a81debd8bdaf2b8bb2b98b9186e5a222a21609ff58df4cbe1d4898d10d6e7c46f31f5cb1041bfd83a5fb27d5c56c961e91403fc"+    ],+    -- COUNT = 5+    [ "362ece9d330e1172a8f9e50258476d0c79c3ee50346524ba12d970ee3a6ef8c5"+    , "cf11bcb4d9d51311ceacfca8705e833f"+    , "abb5a8edde02e526449284ecc31bc713383df3ed085f752e3b6a32f305861eed"+    , "746302ab1f4a86b17546bea762e929360f2e95c7788a63545a264ef997c8c65e"+    , "b907c5b2a8833a48e56e819228ce9a050b41b3309f5ca37bed720311d92b33af"+    , "73c7131a558350590053580873ef956ff952f2aa6ff1bea452e013d1bc2afddea2311756dbe756e63ba6258480c48f3f6c1319b5f572f67ca530af09e39413d1d432bea8f89206619618cb0e7c88e9f2033639d0eb0efc20616b64f940da99b88231984c3fb23f19e890576f555fde394dbd4351f17a7ffd5c369379001bda03"+    ],+    -- COUNT = 6+    [ "cf614bc29946bc0095f415e8bdeda10aab05392f9cc9187a86ea6ec95ee422e1"+    , "77fb5ec22dc0432cc13f4693e2e3bd9a"+    , "e4ce77914ffbc5fddf1fb51edfafdc196109139b84c741354135ec8d314c7c43"+    , "e1e83ee1205acaf6164dc287aec08e5b32789e5be818078db39e53cad589db51"+    , "4e20c0226d5e1e7e805679f03f72452b5bea2d0ba41e0c12329bf60eb3016dd1"+    , "838fdf1418a746aa52ae4005d90c3fd301f648c5770ffef2a9f3912e37a93850cc4b8bfcce910aead0cb75958823b1a62e283901c5e4a3980e4ea36257458e2e4953555819b8852a26489b1d74821f80c9908469b43f124ff7ea62497c36159a47353098a1b9ec32e54800d6704371cc37f357ad74aacc203e9b6db97f94d0c4"+    ],+    -- COUNT = 7+    [ "a8da1d3e233f393fd44d204c200202f7d01896e72c5ac652940cfd15b5d4b0bd"+    , "0a112b4cb0890af0a495e0f49fcf6874"+    , "d2e32799bc822b8d033299bdf63dc35774f7649e935d25be5b10512c430d1bda"+    , "920a82d76fcd2cd106ada64bba232b7b2344f3afe6b1d1d20ee8795144571009"+    , "eeaac5878275372025f8231febed64db6a11273c3c00d625fc80a95f18ad7d3f"+    , "5f6dae489b53d89027b2cc333c700f090152d77b3eaf01d47f56ce6eca9893ef877b4cb560fab0fbdb34e3d1c6cd8480b33c053d2661a10aa531df4961b97d659c7492584236582b3fe701055efa59c328194cd1e07fcffd910d9ee01b7b9e8c8fda7f7ac01a8e203b8b26eb8078a9b9a5021562c44af24089e3ef84c1d5a6bd"+    ],+    -- COUNT = 8+    [ "a77b1ed4ecaa650374e1052c405f1d88881c25c87d13dbe1334d8c1a847fa76b"+    , "05c143e2f145db216fe7be9ed23635d0"+    , "b5c750968ff09ed251d4a1c05342ac843db5246b19045728a634fa4f6e752e54"+    , "ff5937bcd01a363696bf8e40adc8e4ab3e56dbf7e7d09451c99e538785fe6697"+    , "4acb34eea8266badcf8f6557a0eecf3eb4d7a295c876d6175598cb66a388efb8"+    , "ec13eadfcc84e77d2a2efa1a2cd8b1355587cb27feb3d19d75b37f0446333ddb8236e751c63b7a6e595ec24a25051a696dbe8c062dd8896d1446db228a2f10e8094ee07e7ee648ed6bebb2f5ec5aae24c9c640665c28355cc11c116795ecc070790f7fdfc4398900311b6695d5da0175091ed1828d2731085bfb4a20bd86cce0"+    ],+    -- COUNT = 9+    [ "491686c781e83eb4e21d9989e8d718100b0d21a2c56295888baef1a65f219651"+    , "499085296d21065feabf3106101c8d6f"+    , "d208a72f9ae34f0817669fb04f49239dd31700f3dc9a93db8d75fb79f9b686c1"+    , "9ffc61893a293a864008fdd56d3292600d9e2ec8a1ea8f34ac5931e968905a23"+    , "4ff3a397dfdae0912032a302a5e7a07dceca8d9013a21545689319b7c024cd07"+    , "3c258ebf2203fca3b322ad1b016e21c7f5c148425f81e4fb0a0e462dce9dfa569c37a006527768297a5b68461b08912642a341b88c85597e30e7561206886098c4e2d861f11513f0ffdbbc78d3a2dd60c105abbb33c5e05ae27081b690fb8b3610917aa9bf1a4ad74481b5ff8334f14e5ad6a6a1eb2259476078076fb7e3a992"+    ],+    -- COUNT = 10+    [ "36a5267eeeb5a1a7d46de0f8f9281f73cd9611f01198fdaa78c5315205e5a177"+    , "b66b5337970df36219321badacc624eb"+    , "c2a7b164949da102bece44a423197682ff97627d1fe9654266b8527f64e5b386"+    , "a977e2d8637b019c74063d163bb25387dc56f4eb40e502cefc5ae6ad26a6abdc"+    , "c5c9819557b1e7d8a86fa8c60be42993edc3ef539c13d9a51fb64b0de06e145e"+    , "b471711a4fc7ab7247e65d2c2fe49a50169187187b7978cd2fdb0f8318be3ec55fc68ed4577ad9b42cbb57100b5d35ac86c244c4c93a5b28c1a11c2dfe905d608ec7804dec5bb15cf8d79695534d5e13a6a7e18a887ec9cf184da0cbbc6267f3a952a769403bafcdbb559401be0d8b3300ea7258b4026fc892175efd55ba1a67"+    ],+    -- COUNT = 11+    [ "a76b0366df89e4073a6b6b9c04da1d6817ce26f1c4825cad4097bdf4d7b9445e"+    , "773d3cc3290176773847869be528d1a4"+    , "1bfd3bcfb9287a5ad055d1b2b8615fa81c94ac24bc1c219a0f8de58789e0404a"+    , "edd879fa56f21d93029da875b683ce50f6fdc4c0da41da051d000eed2afefefa"+    , "f528ffd29160039260133ed9654589ce60e39e7f667c34f82cda65ddcf5fff14"+    , "39d1ff8848e74dd2cdc6b818ad69823878062116fdf1679942f892c7e191be1c4b6ea268ecdff001b22af0d510f30c2c25b90fc34927f46e3f45d36b0e1848b3a5d54c36c7c65ee7287d325dfbb51b56a438feb6650ce13df88bf06b87ac4a35d2a199ea888629fb0d83f82f0ea160dc79ed220d8ef195b9e80c542f60c2d320"+    ],+    -- COUNT = 12+    [ "46571e1df43e5e141235e2a9ec85bb0faf1dc0566031e14d41a2fbd0315653ec"+    , "b60ef6a3347967519aabeaf748e4e991"+    , "759fd8593e3688b23c4a003b655311770d670789878570eb3b155a8e6c2d8c45"+    , "033128460b449e1accb0e9c54508759ddc2538bc64b51e6277553f0c60a02723"+    , "a5e4a717240bdeac18a0c0e231a11dc04a47d7550f342fa9a7a5ff334eb9327d"+    , "9d222df1d530ea7f8f2297a0c79d637da570b48042ecddded75956bba0f0e70b271ffa3c9a53bada6ee1b8a4203c22bfde82a5e2eb1b150f54c6483458569422c1a34a8997d42cc09750167a78bf52a0bd158397af9f83caabe689185c099bf0a9a4853dd3cf8b8e89efebb6a27dba873e65e9927741b22968f2875789b44e01"+    ],+    -- COUNT = 13+    [ "d63980e63bbe4ac08d2ac5646bf085b82c75995e3fdfc23bb9cc734cd85ca7d2"+    , "d33ed1dcae13fb634ba08272d6697590"+    , "acd0da070072a5340c4f5f4395568e1a36374e074196ae87f3692ee40487e1df"+    , "f567677b5e12e26f3544be3da9314c88fc475bf84804a89a51f12b191392c02b"+    , "c01cc7873e93c86e2bfb8fc984cfc2eab5cc58eeef018fedb5cba5aedd386156"+    , "b133446f633bcb40724bbf9fa187c39a44b9c094a0a0d40e98977e5466dc2c9adf62a5f4551eeb6406a14658de8a0ed7487c3bf6277e811101284a941745ce16176acc875f1435e14161772fa84609e8123c53dd03cbb868030835c0d11d8d6aa04a1b6f908248b028997737f54735ec4ed7a81fc868199ffb61a779d9340334"+    ],+    -- COUNT = 14+    [ "3d99f9b7ac3a2fbe9cf15d960bf41f5588fc4db1e0d2a5c9c0fe9059f03593fb"+    , "411f504bb63a9b3afa7ffa1357bb48be"+    , "0bb5ebd55981a25ba69164da49fa92f2871fd3fc65eb30d0f0d0b8d798a4f8f2"+    , "288e948a551284eb3cb23e26299955c2fb8f063c132a92683c1615ecaed80f30"+    , "d975b22f79e34acf5db25a2a167ef60a10682dd9964e15533d75f7fa9efc5dcb"+    , "ee8d707eea9bc7080d58768c8c64a991606bb808600cafab834db8bc884f866941b4a7eb8d0334d876c0f1151bccc7ce8970593dad0c1809075ce6dbca54c4d4667227331eeac97f83ccb76901762f153c5e8562a8ccf12c8a1f2f480ec6f1975ac097a49770219107d4edea54fb5ee23a8403874929d073d7ef0526a647011a"+    ]+    ]++{- Reseed test vectors -}++{-+    [SHA-256]+    [PredictionResistance = False]+    [EntropyInputLen = 256]+    [NonceLen = 128]+    [PersonalizationStringLen = 0]+    [AdditionalInputLen = 0]+    [ReturnedBitsLen = 1024]+-}++r1 :: [TestVector]+r1 =+    [+    -- COUNT = 0+    [ "06032cd5eed33f39265f49ecb142c511da9aff2af71203bffaf34a9ca5bd9c0d"+    , "0e66f71edc43e42a45ad3c6fc6cdc4df"+    , ""+    , "01920a4e669ed3a85ae8a33b35a74ad7fb2a6bb4cf395ce00334a9c9a5a5d552"+    , ""+    , ""+    , ""+    , "76fc79fe9b50beccc991a11b5635783a83536add03c157fb30645e611c2898bb2b1bc215000209208cd506cb28da2a51bdb03826aaf2bd2335d576d519160842e7158ad0949d1a9ec3e66ea1b1a064b005de914eac2e9d4f2d72a8616a80225422918250ff66a41bd2f864a6a38cc5b6499dc43f7f2bd09e1e0f8f5885935124"+    ],+    -- COUNT = 1+    [ "aadcf337788bb8ac01976640726bc51635d417777fe6939eded9ccc8a378c76a"+    , "9ccc9d80c89ac55a8cfe0f99942f5a4d"+    , ""+    , "03a57792547e0c98ea1776e4ba80c007346296a56a270a35fd9ea2845c7e81e2"+    , ""+    , ""+    , ""+    , "17d09f40a43771f4a2f0db327df637dea972bfff30c98ebc8842dc7a9e3d681c61902f71bffaf5093607fbfba9674a70d048e562ee88f027f630a78522ec6f706bb44ae130e05c8d7eac668bf6980d99b4c0242946452399cb032cc6f9fd96284709bd2fa565b9eb9f2004be6c9ea9ff9128c3f93b60dc30c5fc8587a10de68c"+    ],+    -- COUNT = 2+    [ "62cda441dd802c7652c00b99cac3652a64fc75388dc9adcf763530ac31df9214"+    , "5fdc897a0c1c482204ef07e0805c014b"+    , ""+    , "bd9bbf717467bf4b5db2aa344dd0d90997c8201b2265f4451270128f5ac05a1a"+    , ""+    , ""+    , ""+    , "7e41f9647a5e6750eb8acf13a02f23f3be77611e51992cedb6602c314531aff2a6e4c557da0777d4e85faefcb143f1a92e0dbac8de8b885ced62a124f0b10620f1409ae87e228994b830eca638ccdceedd3fcd07d024b646704f44d5d9c4c3a7b705f37104b45b9cfc2d933ae43c12f53e3e6f798c51be5f640115d45cf919a4"+    ],+    -- COUNT = 3+    [ "6bdc6ca8eef0e3533abd02580ebbc8a92f382c5b1c8e3eaa12566ecfb90389a3"+    , "8f8481cc7735827477e0e4acb7f4a0fa"+    , ""+    , "72eca6f1560720e6bd1ff0152c12eeff1f959462fd62c72b7dde96abcb7f79fb"+    , ""+    , ""+    , ""+    , "d5a2e2f254b5ae65590d4fd1ff5c758e425be4bacdeede7989669f0a22d34274fdfc2bf87135e30abdae2691629c2f6f425bd4e119904d4785ecd9328f15259563e5a71f915ec0c02b66655471067b01016fdf934a47b017e07c21332641400bbe5719050dba22c020b9b2d2cdb933dbc70f76fec4b1d83980fd1a13c4565836"+    ],+    -- COUNT = 4+    [ "096ef37294d369face1add3eb8b425895e921626495705c5a03ee566b34158ec"+    , "6e2e0825534d2989715cc85956e0148d"+    , ""+    , "1b4f7125f472c253837fa787d5acf0382a3b89c3f41c211d263052402dcc62c5"+    , ""+    , ""+    , ""+    , "4541f24f759b5f2ac2b57b51125077cc740b3859a719a9bab1196e6c0ca2bd057af9d3892386a1813fc8875d8d364f15e7fd69d1cc6659470415278164df656295ba9cfcee79f6cbe26ee136e6b45ec224ad379c6079b10a2e0cb5f7f785ef0ab7a7c3fcd9cb6506054d20e2f3ec610cbba9b045a248af56e4f6d3f0c8d96a23"+    ],+    -- COUNT = 5+    [ "a7dccdd431ae5726b83585b54eae4108f7b7a25c70187c0acbb94c96cc277aa8"+    , "94c8f4b8e195a47356a89a50d1389ab5"+    , ""+    , "51733eee2e922f4055e53939e222e71fae730eb037443db2c7679708abb86a65"+    , ""+    , ""+    , ""+    , "99ba2691a622afecc9472418e6a8f9f1cdc1e3583c3bc7a2a650a1ab79dcbccbd656636c573179276e782569420c97438c06be898867f628b1c01eb570263d2c0f09c7aab536f6fba7df6aad19e05c236b645674667c03d1b6a04d7fc11177fe78933b309679f5bf26a4632b9a13e314c4bf4532428d3d95c689002b6dc1fbb1"+    ],+    -- COUNT = 6+    [ "c286425ecf543a49bcc9196b0db1a80bc54e4948adba6f41712a350a02891fa6"+    , "957a659a4ec2e0b7ad185483c220fd61"+    , ""+    , "08c2129813eea0776fba72788fdf2718759cc3c4207fa20a5fe23ac6e32cc28e"+    , ""+    , ""+    , ""+    , "8e1020a4fd84c99e0fc7e3f7ce48de5ed9ec9a5c2ccd624dbe6f30e2f688a31dc55957630357a5d48ca2a456241a28bfb16d8bb000877697a7ce24d9ad4d22b0c15117996f1f270b94f46d7a9bdfa7608fa1dd849177a9b8049e51b6b7a2742623854a1fddb5efc447eed1ea1aed6f02b4b2754ecf71ea0509da2e54f524a7e7"+    ],+    -- COUNT = 7+    [ "02818bd7c1ec456ace55beeba99f646a6d3aa0ea78356ea726b763ff0dd2d656"+    , "c482687d508c9b5c2a75f7ce390014e8"+    , ""+    , "cf319bfa63980e3cb997fd28771bb5614e3acb1149ba45c133ffbbab17433193"+    , ""+    , ""+    , ""+    , "19a231ff26c1865ce75d7a7185c30dd0b333126433d0c8cbf1be0d2b384d4eb3a8aff03540fbfa5f5496521a4e4a64071b44c78bd0b7e68fac9e5695c5c13fd3b9dbe7f7739781a4c8f0b980f1b17d99bce17ceb52b56866ae02456ffef83399c8cf7826f3c45c8a19315890919d20f40fc4e18d07e9c8ccd16c3327b5988f71"+    ],+    -- COUNT = 8+    [ "77a5c86d99be7bc2502870f4025f9f7563e9174ec67c5f481f21fcf2b41cae4b"+    , "ed044ad72ee822506a6d0b1211502967"+    , ""+    , "778100749f01a4d35c3b4a958aafe296877e0acafd089f50bc7797a42a33ab71"+    , ""+    , ""+    , ""+    , "831a4da566f46289904893ef1cc1cd4ad19ee48f3857e2b69e936d10afbdc29822e85d02663d346ef3e09a848b1d9cc04f4c4c6e3b3b0e56a034e2334d34ca08f8097be307ba41d020bc94f8c1937fe85644eeb5592c2b5a2138f7ded9a5b44b200c8b5beb27597c790f94d660eb61e8248391edc3ae2d77656cbe8354275b13"+    ],+    -- COUNT = 9+    [ "0ea458cff8bfd1dd8b1addcba9c01317d53039e533104e32f96e7d342e6c7b9b"+    , "935a4b66fc74c2a48757a99c399e64e3"+    , ""+    , "6c5f3708e7b714c4ed139b4fa9e8c763af01773484005109a85e33653bb0ce98"+    , ""+    , ""+    , ""+    , "373a37af84fddec13645a9768d6a785ae5a2589d64cd9b37980dde2541499210c4f408335de1d585349064f3f53a2b4c5ec6dc2a09591f99ad9fad528ac83474164b45497bf167f81e66fa08463ffea917f6891e48f149fafc20622bb1172f34886feb45c26fd446a4a4e2891b4bc594186896141aaaeeb301b49e7c1a26fec7"+    ],+    -- COUNT = 10+    [ "bfb68be4ce1756d25bdfad5e0c2f8bec29360901cc4da51d423d1591cc57e1ba"+    , "98afe4bd194c143e099680c504cceaab"+    , ""+    , "b97caf210e82498c3408790d41c320dd4a72007778389b44b7bc3c1c4b8c53f8"+    , ""+    , ""+    , ""+    , "409e0aa949fb3b38231bf8732e7959e943a338ea399026b744df15cbfeff8d71b3da023dcce059a88cf0d4b7475f628e4764c8bef13c70cfbbbb6da2a18aabcad919db09d04fc59765edb165147c88dd473a0f3c5ee19237ca955697e001ba654c5ee0bd26761b49333154426bc63286298a8be634fe0d72cfdeef0f3fc48eca"+    ],+    -- COUNT = 11+    [ "4f6880a64610004463031d67d7924fa446c39138d4d41007e8df3d65691a9367"+    , "6b33b2c13600f4b1df6ca3d1960e8dd4"+    , ""+    , "57b87b8c8f48312b5333d43b367730c0a5ad4725a16778fcb53fe136d136cbfd"+    , ""+    , ""+    , ""+    , "73d0f324ed186e2ad06bd1800e262bdbda79ba54e626761bd60f74f43e3bb62958ec1e2f1d940af163e1cadc124e7ebaba2f72e67efd746c7f6d0cad53ef03d859d93cff778a32ee5be172fe7fdbdc232ded360d704a6fa0f70bebe942e56478345492f49dc5c6fc346b88a58947ad250e688e8c626fe1efe7624620e571976e"+    ],+    -- COUNT = 12+    [ "aae352e111843219cae8f70e7b8f6eb9bb53d246cbec1e4f07d42757143295b4"+    , "b84485dccd1bf93210e322eafcbebcd9"+    , ""+    , "f9237f00d744d8fbff21b9d0043c258e8731817e6a5fb7b4bf5011680e5bc642"+    , ""+    , ""+    , ""+    , "cfb28b93522c7d61d8d3ce3f080e435e4c83c7e13a9dab788db8fef0407267a14fbc9324e090e24df5491fedfa81116869983938d4d4d7324a310c3af33a6f7938f602c5e4e63f1771cdaabdab0782b5affb54eb53047c109a9606739dd0065bd21eca33132986554878354f5f9f852e674dd690163b0ff74c7a25e6bae8ce39"+    ],+    -- COUNT = 13+    [ "589e79e339b7d2a1b879f0b0e1a7d1ad2474eaa8025b070f1ffa877b7124d4ff"+    , "0961ed64dbd62065d96e75de6d2ff9d6"+    , ""+    , "e928388d3af48c2968527a4d2f9c2626fbc3f3f5a5d84e0583ab6f78e7f8b081"+    , ""+    , ""+    , ""+    , "fce6ced1ecf474d181ab331f79c3d2cc8a768ec2818de5b3fc7cf418322716d6a6853733561a497c0c25cb288d2c9fcfbca891bafd5a834c85f3603f402acf1a7b1ea92db847ed5c252a862ad4ab5e259715f1fc81da67f5230bf8be50ee8069758095f7d0e559e03f2c6072290e61794458437609e473eb66580cddaad19b71"+    ],+    -- COUNT = 14+    [ "714277d408ad87fde317f0a94732fce62f1352bdc90936673b4f1daa0925aa26"+    , "d16582a99f23010b4248b88d86485419"+    , ""+    , "bd9fc7cb2fd5063b2c3c0c4f346ad2e3879371a9c805e59b9f2cd2cc2a40894f"+    , ""+    , ""+    , ""+    , "62ef7a431288252e0d736c1d4e36cc9ac37107dcd0d0e971a22444a4adae73a41eff0b11c8625e118dbc9226142fd0a6aa10ac9b190919bda44e7248d6c88874612abd77fb3716ea515a2d563237c446e2a282e7c3b0a3aef27d3427cc7d0a7d38714659c3401dbc91d3595159318ebca01ae7d7fd1c89f6ad6b604173b0c744"+    ]+    ]++{-+    [SHA-256]+    [PredictionResistance = False]+    [EntropyInputLen = 256]+    [NonceLen = 128]+    [PersonalizationStringLen = 0]+    [AdditionalInputLen = 256]+    [ReturnedBitsLen = 1024]+-}++r2 :: [TestVector]+r2 =+    [+    -- COUNT = 0+    [ "05ac9fc4c62a02e3f90840da5616218c6de5743d66b8e0fbf833759c5928b53d"+    , "2b89a17904922ed8f017a63044848545"+    , ""+    , "2791126b8b52ee1fd9392a0a13e0083bed4186dc649b739607ac70ec8dcecf9b"+    , "43bac13bae715092cf7eb280a2e10a962faf7233c41412f69bc74a35a584e54c"+    , "3f2fed4b68d506ecefa21f3f5bb907beb0f17dbc30f6ffbba5e5861408c53a1e"+    , "529030df50f410985fde068df82b935ec23d839cb4b269414c0ede6cffea5b68"+    , "02ddff5173da2fcffa10215b030d660d61179e61ecc22609b1151a75f1cbcbb4363c3a89299b4b63aca5e581e73c860491010aa35de3337cc6c09ebec8c91a6287586f3a74d9694b462d2720ea2e11bbd02af33adefb4a16e6b370fa0effd57d607547bdcfbb7831f54de7073ad2a7da987a0016a82fa958779a168674b56524"+    ],+    -- COUNT = 1+    [ "1bea3296f24e9242b96ed00648ac6255007c91f7c1a5088b2482c28c834942bf"+    , "71073136a5cc1eb5b5fa09e1790a0bed"+    , ""+    , "d714329f3fbea1df9d0b0b0d88dfe3774beb63d011935923d048e521b710dc6f"+    , "4ef872fd211a426ea1085ab39eb220cc698fdfeabe49b8835d620ab7885de7a4"+    , "d74d1669e89875852d9ccbf11c20fe3c13a621ebcb3f7edeea39a2b3379fdcf5"+    , "0c8aa67ca310bd8e58c16aba35880f747266dbf624e88ec8f9ee9be5d08fdeb1"+    , "ce95b98f13adcdf7a32aa34709d6e02f658ae498d2ab01ce920f69e7e42c4be1d005acf0ca6b17891dfafc620dd4cd3894f8492a5c846089b9b452483eb0b91f3649ec0b6f98d1aaabc2e42cd39c2b25081b85ab50cb723007a0fd83550f32c210b7c4150b5a6bb3b0c9e3c971a09d43acb48e410a77f824b957092aa8ef98bc"+    ],+    -- COUNT = 2+    [ "a7ea449b49db48601fc3a3d5d77081fab092b8d420ed1b266f704f94352dd726"+    , "d11a159b60af8d20a0e37d27e6c74aa3"+    , ""+    , "50916ab47e8cb5dc843f9fba80639103711f86be8e3aa94f8a64a3fe0e6e5b35"+    , "e2bb6768120555e7b9e0d573537a82f8f32f54560e1050b6abb1588fb3441e66"+    , "a50cec9d1ecddb2c163d24019e81c31a2b350ccd3ad8181fd31bb8d1f64fa50e"+    , "591dbbd48b51abced67f9c6269cf0133cd3dcbb5cfafcb6ef758569c555a5773"+    , "0a464abcc8685158372d544635b953fcb1d3821c30aaa93982f9b788935f00f88115aad61d5cee003b3d1cb50f3e961a501e2dd0fc7e1724778b184a4bdf9f64e110dda7446e5544a30bd49a400ea1a5411800e1edfeea349323618afc5dc5782dc4b71d2da4d6a4785f8dd346feb9c8740ffd26bf644e3e4323ff24c30b9f10"+    ],+    -- COUNT = 3+    [ "14683ec508a29d7812e0f04a3e9d87897000dc07b4fbcfda58eb7cdabc492e58"+    , "b2243e744eb980b3ece25ce76383fd46"+    , ""+    , "18590e0ef4ee2bdae462f76d9324b3002559f74c370cfccf96a571d6955703a7"+    , "9ea3ccca1e8d791d22fcda621fc4d51b882df32d94ea8f20ee449313e6909b78"+    , "16366a578b5ea4d0cb547790ef5b4fd45d7cd845bc8a7c45e99419c8737debb4"+    , "a68caa29a53f1ba857e484d095805dc319fe6963e4c4daaf355f722eba746b92"+    , "c4e7532ee816789c2d3da9ff9f4b37139a8515dbf8f9e1d0bf00c12addd79ebbd76236f75f2aa705a09f7955038ebff0d566911c5ea13214e2c2eeb46d23ad86a33b60f7b9448d63eec3e1d59f48b39552857447dc5d7944667a230e3dbfa30ca322f6eacaf7536a286706a627c5083c32de0658b9073857c30fb1d86eb8ad1b"+    ],+    -- COUNT = 4+    [ "fa261fb230e2822458532ca2d5c39758750e6819a6fcebef10579ba995096959"+    , "564e1c9fbcb12878df2bd49202cbf821"+    , ""+    , "bf7de29e99e7f0e1b9f96f3b1902fb4049c8c6234d20de8316ebe66d97725457"+    , "8b7326621f6afbd44a726de48d03bcc5331f7306026c229ea9523497fbeaa88d"+    , "33b00b31623d6160c4c6740363a96481be14b19bc47be95641227284c366922a"+    , "2d812c8203575790ad6b6f2ed91a49d57460de779a3e881bef3be12e8766dc91"+    , "5574e0b4efc17e8ce136e592beabfe32551072bddd740929e698467b40b3991f028a22c760f7034853cc53007e3793e3c4a600d9e9d94528f8dc09aeba86146cdde2b7f71255ae0efc529b49be2205979dba6525bfe155e8819e8e2aeeaa285704242da90b4c4535101cc47d94b0e388a1b2e63ad0cbe158b9e1bbae9cc0007c"+    ],+    -- COUNT = 5+    [ "61f1471ced56aa04c57e1b512307d4cb92497d9592d7e9e35356e99d585cab1b"+    , "84714e960c403a4fac06b2828cc564d9"+    , ""+    , "7bf97db3c102edc81596d4757045fe6bdc008f35792fc6290b77d889c09c33a8"+    , "5b8bdc41f76d98cfa71ed976ea3994706375c8841adb8b6b3b6418e3132e8832"+    , "94c8a8fdf38a6ccb8571c89420d899adab169214bb0dfcd43a04622e289935b2"+    , "8a4b46e0a7a55907365f82d4ab9376509bd44728cab8cbafb0da901012ad8dcd"+    , "933eb159a6af7455b60e40586c064f05f1970f564281b1ebc4662701ac1f299e4eb908c4afcb2e065191281ab576f684aefedd6904bad04d96bd93c0516c62a496c3073a0cda0676a11cc08866b0cc74f62cb9d3db48673b2c3fbeada69f922b4b795ccba22df12ef7125909381f7d681f6b9caba02fb913c5437b98c040c576"+    ],+    -- COUNT = 6+    [ "a1d5bb7d70621dee6b668b28c56d5610c2f8ced30284cc3e0e48de331af05062"+    , "88a49e3e54c5ea54c98b95de81bcc807"+    , ""+    , "b4e2426e98f6eed97a6cdf690a89ee109e84c3dca16c883c26fa4ac671638d8d"+    , "5bd1e086ed228cfd8b55c1731fea40c3a63d022599ca2da4bb23118f4821ba62"+    , "b754b53ac226e8ebe47a3d31496ec822de06fca2e7ef5bf1dec6c83d05368ec3"+    , "fa7e76b2805d90b3d89fff545010d84f67aa3a2c9eb2ba232e75f4d53267dac3"+    , "df6b2460688fa537df3ddfe5575fca5eb8abad56cbc4e5a618a2b4a7daf6e215c3a497974c502f9d0ec35de3fc2ea5d4f10de9b2aee66dcc7e7ae6357983095959b817f0383e3030771bd2ed97406acf78a1a4a5f30fa0992289c9202e69e3eb1eabe227c11409ff430f6dfca1a923a8b17bc4b87e908007f5e9759c41482b01"+    ],+    -- COUNT = 7+    [ "68f21d14525d56233c7e263482d344c388a840103a77fb20ac60ce463cabdc79"+    , "59fa80ae570f3e0c60ac7e2578cec3cb"+    , ""+    , "7584b4166530442f06e241dd904f562167e2fdae3247ab853a4a9d4884a5fa46"+    , "f6a5482f139045c5389c9246d772c782c4ebf79c3a84b5cf779f458a69a52914"+    , "9d37b1ce99f8079993ddf0bd54bab218016685b22655a678ce4300105f3a45b7"+    , "4c97c67026ff43c2ee730e7b2ce8cce4794fd0588deb16185fa6792ddd0d46de"+    , "e5f8874be0a8345aabf2f829a7c06bb40e60869508c2bdef071d73692c0265f6a5bf9ca6cf47d75cbd9df88b9cb236cdfce37d2fd4913f177dbd41887dae116edfbdad4fd6e4c1a51aad9f9d6afe7fcafced45a4913d742a7ec00fd6170d63a68f986d8c2357765e4d38835d3fea301afab43a50bd9edd2dec6a979732b25292"+    ],+    -- COUNT = 8+    [ "7988146cbf9598d74cf88dc314af6b25c3f7de96ae9892fb0756318cea01987e"+    , "280bc1ae9bfdf8a73c2df07b82a32c9c"+    , ""+    , "2bbc607085232e5e12ccf7c0c19a5dc80e45eb4b3d4a147fe941fa6c13333474"+    , "f3f5c1bb5da59252861753c4980c23f72be1732f899fdea7183b5c024c858a12"+    , "44d0cfc4f56ab38fa465a659151b3461b65b2462d1ad6b3463b5cf96ad9dc577"+    , "34fb9a3cdacc834ff6241474c4f6e73ed6f5d9ea0337ab2b7468f01ad8a26e93"+    , "4caec9e760c4d468e47613fe50de4a366ae20ba76793744a4e14433ea4de79dc188601eb86c803b094641ab2337b99d459d37decc7d27473057be45ba848868ee0fb5f1cf303d2fcd0b3e0c36f65a65f81b3fee8778a1f22302e25dfe34e6d587fa8864e621121880f7cd55f350531c4ce0530099eec2d0059706dcd657708d9"+    ],+    -- COUNT = 9+    [ "1c974c953fa2a057c9fc9409a6843f6f839aa544bca4fa11e48afd77931d4656"+    , "ed7c08285464af7a5dbdc10b944a1270"+    , ""+    , "78146ad135acb836360d36afc50653dcc36c21662da2a6f6ae05222e75f34000"+    , "263c4984c238ded333c86472866353817379502157172cfa51371d82b1efd7b5"+    , "79b591529f9a26a0d7c8f8fd64e354b0c134ef1f757e43f9463b3dbb7a3da1ab"+    , "7d8f7204b0b5401ddce9e88dcf5facb9a44660a9f5f1c862748e7269c29f7964"+    , "72e2ca257b9edaf59b50e05a144f56fb517832fb9ad3489b1e664e3d5412cbf6b2883e891703b2e73aff9ab56da1009fcdef010ab4cdab996795c8f7c47fb1192bb160353997ad39d7d5fd0e2efc9103a7c3f158246afd53fe53ca6782f809698ef5f1f0d85536780a3fd6a8bafa475891c09213088bd1a3dc169257c34a517a"+    ],+    -- COUNT = 10+    [ "56216d71984a77154569122c777ce57e1d101a6025b28163a25971d39c1c5d0f"+    , "5cd148ba7e54f4975ac8e3e0f9b5d06a"+    , ""+    , "3580f8ca974626c77259c6e37383cb8150b4d0ab0b30e377bed0dc9d1ff1a1bf"+    , "15633e3a62b21594d49d3d26c4c3509f96011d4dbb9d48bbbea1b61c453f6abe"+    , "6068eaca85c14165b101bb3e8c387c41d3f298918c7f3da2a28786ab0738a6fc"+    , "e34f92d2b6aeeeea4ff49bfe7e4b1f462eabb853f0e86fbae0e8b3d51409ce49"+    , "587fdb856abc19ede9078797ecb44099e07aadcd83acdcb2b090601d653f4a14c68ab2ebdda63578c5633a825bae4c0c818f89aac58d30fd7b0b5d459a0f3d86fcad78f4bb14dfff08ad81e4ea9f487cb426e91d6e80dfed436ba38fce8d6f21ca2151c92dd5c323b077d6139c66395558f0537026c4a028affa271ef4e7ea23"+    ],+    -- COUNT = 11+    [ "83eb48bedc1e9294866ab8e5322ef83f6f271f8188e8fdabe5817788bd31570d"+    , "d6ed90bc692237f132441ede857a6629"+    , ""+    , "a4e5e127f992bd5ca79ee56bb8a9bccf74c21814bfaf97ffd052211e802e12e4"+    , "84136e403d9ed7f4515c188213abcfaca35715fa55de6d734aec63c4606a68f1"+    , "fe9d8ef26e2d2e94b99943148392b2b33a581b4b97a8d7a0ecd41660a61dd10b"+    , "594dad642183ce2cdc9494d6bcb358e0e7b767c5a0fa33e456971b8754a9abd5"+    , "86715d43ba95fbbca9b7193ea977a820f4b61ba1b7e3b8d161b6c51b09dfd5040d94c04338b14d97ed25af577186b36ae7251a486c8a2d24a35e84a95c89d669d49e307b4a368b72164135ac54d020a970a180dfbed135d2c86f01270846d5301bd73db2c431a8aa10a0a3d03d146e5fafb9a2aa0b4efc80edab06ff3b532236"+    ],+    -- COUNT = 12+    [ "ba2c94203dab2e6499d8c50dca7b5c34a6b4764834f9816631aa21b9f9c37361"+    , "67db133bdefb25e395085bceee5a0afc"+    , ""+    , "fa8984d16d35302cda35a3a355ab9242ec96fec0652d39282d4a0abf0a80df87"+    , "b6fed10255a3fea6772ae1ae6d9f6cbb9bfaa34804e58a5b786f9bc60b348ccd"+    , "445e072244edc716d3528f0e0a20ff0cd8f819c0d031736c8da122748f24d6c6"+    , "1f856e403c4fa035bac9aa81a20e347c7d8b213aab699d69d9d6186a06ac45c1"+    , "79f33fc36b3b47d9ac805bdbbe699909a8d0beb689a8b2723c291bd5bf7f3ce61343d4722a14e4add36312dbb0594910c8828aff1abc159915d498106f9ffb31147478d8c9ef75d1536ba5036506b313f6e85033f8f6fea2a4de817c867a59378c53c70a2f108275daedd415c05b61c4fd5d48c54be9adb9dea6c40a2ec99ee0"+    ],+    -- COUNT = 13+    [ "0db4c51492db4fe973b4bb1c52a1e873b58fc6bb37a3a4bfc252b03b994495d1"+    , "a2a3900f169bba3f78a42526c700de62"+    , ""+    , "29d5aab356876447e3a20d81c7e3fc6975e2b984180a91493044442999e1ca3a"+    , "40b34183b4e72cdff5952b317b3d45943d0fdcfa0527f3563055f7c73ae8f892"+    , "dc94220c99ffb595c7c4d6de8de5a6bb4b38847169e24a557ef6d879ad84149d"+    , "b2376626fd2f5218b3ed4a5609b43aa24d371cd2176ea017c2b99cf868060021"+    , "f0bd6bc4c506d9427a09352d9c1970b146360732841a6323f4cb602c87dedfb5ff7e6964b9144933af3c5c83017ccd6a94bdca467a504564aaa7b452591a16ff6a1e7e94ddc98f9a58016cdcb8caaed6c80671ba48cc81a832d341093dda1d4e5001ec6bf66348b21e3692a13df92538ad572bb2023822072fc95f9590293ffc"+    ],+    --  COUNT = 14+    [ "593845f0adfeffa7c169f8a610147ae8a08c0072fc0c14c3977d3de0d00b55af"+    , "9e0eb2507342ee01c02beadee7d077bd"+    , ""+    , "aefe591697eab678c52e20013aa424b95cfd217b259757fbe17335563f5b5706"+    , "cbb5be0ef9bf0555ee58955c4d971fb9baa6d6070c3f7244a4eb88b48f0793bf"+    , "6dd878394abdc0402146ba07005327c55f4d821bfebca08d04e66824e3760ab4"+    , "ba86a691d6cbf452b1e2fd1dfb5d31ef9ea5b8be92c4988dc5f560733b371f69"+    , "00735cbfafac5df82e5cb28fc619b01e2ba9571dc0023d26f09c37fb37d0e809066165a97e532bf86fa7d148078e865fe1a09e27a6889be1533b459cd9cd229494b5cf4d2abf28c38180278d47281f13820276ec85effb8d45284eb9eef5d179ab4880023ab2bd08ee3f766f990286bf32430c042f5521bbfd0c7ee09e2254d7"+    ]+    ]++{-+    [SHA-256]+    [PredictionResistance = False]+    [EntropyInputLen = 256]+    [NonceLen = 128]+    [PersonalizationStringLen = 256]+    [AdditionalInputLen = 0]+    [ReturnedBitsLen = 1024]+-}++r3 :: [TestVector]+r3 =+    [+    -- COUNT = 0+    [ "fa0ee1fe39c7c390aa94159d0de97564342b591777f3e5f6a4ba2aea342ec840"+    , "dd0820655cb2ffdb0da9e9310a67c9e5"+    , "f2e58fe60a3afc59dad37595415ffd318ccf69d67780f6fa0797dc9aa43e144c"+    , "e0629b6d7975ddfa96a399648740e60f1f9557dc58b3d7415f9ba9d4dbb501f6"+    , ""+    , ""+    , ""+    , "f92d4cf99a535b20222a52a68db04c5af6f5ffc7b66a473a37a256bd8d298f9b4aa4af7e8d181e02367903f93bdb744c6c2f3f3472626b40ce9bd6a70e7b8f93992a16a76fab6b5f162568e08ee6c3e804aefd952ddd3acb791c50f2ad69e9a04028a06a9c01d3a62aca2aaf6efe69ed97a016213a2dd642b4886764072d9cbe"+    ],+    -- COUNT = 1+    [ "cff72f345115376a57f4db8a5c9f64053e7379171a5a1e81e82aad3448d17d44"+    , "d1e971ec795d098b3dae14ffcbeecfd9"+    , "6ec0c798c240f22740cad7e27b41f5e42dccaf66def3b7f341c4d827294f83c9"+    , "45ec80f0c00cad0ff0b7616d2a930af3f5cf23cd61be7fbf7c65be0031e93e38"+    , ""+    , ""+    , ""+    , "17a7901e2550de088f472518d377cc4cc6979f4a64f4975c74344215e4807a1234eefef99f64cb8abc3fb86209f6fc7ddd03e94f83746c5abe5360cdde4f2525ccf7167e6f0befae05b38fd6089a2ab83719874ce8f670480d5f3ed9bf40538a15aaad112db1618a58b10687b68875f00f139a72bdf043f736e4a320c06efd2c"+    ],+    -- COUNT = 2+    [ "b7099b06fc7a8a74c58219729db6b0f780d7b4fa307bc3d3f9f22bfb763596a3"+    , "b8772059a135a6b61da72f375411de26"+    , "2ac1bfb24e0b8c6ac2803e89261822b7f72a0320df2b199171b79bcbdb40b719"+    , "9aec4f56ec5e96fbd96048b9a63ac8d047aedbbeea7712e241133b1a357ecfc4"+    , ""+    , ""+    , ""+    , "0e1f2bfef778f5e5be671ecb4971624ec784ed2732abc4fbb98a8b482fb68737df91fd15acfad2951403ac77c5ca3edffc1e03398ae6cf6ac24a91678db5c7290abc3fa001aa02d50399326f85d2b8942199a1575f6746364740a5910552c639804d7530c0d41339345a58ff0080eccf1711895192a3817a8dc3f00f28cc10cc"+    ],+    -- COUNT = 3+    [ "7ba02a734c8744b15ef8b4074fe639b32e4431762ab5b7cd4d5df675ea90672b"+    , "8a424f32108607c8f1f45d97f500ee12"+    , "3ad627433f465187c48141e30c2678106091e7a680229a534b851b8d46feb957"+    , "d8f02b59b6a3dd276bc69cba68efcf11ab83ead1397afd9841786bd1bb5da97a"+    , ""+    , ""+    , ""+    , "1fb91186ba4b4459d994b4b9f4ca252c7be6294d6cdb5fe56f8ff784d4b190a1c6456e0a41223bbbdf83ed8e7cfbfa765d9d8bc7ea5f4d79ea7eccb4928081a21de4cca36620d6267f55d9a352b76fc0a57375884112c31f65ff28e76d315698c29e6c4c05cb58b0a07ae66143b4abc78b9d25c78b4121e1e45bef1a6c1793e2"+    ],+    -- COUNT = 4+    [ "9a8865dfe053ae77cb6a9365b88f34eec17ea5cbfb0b1f04d1459e7fa9c4f3cb"+    , "180c0a74da3ec464df11fac172d1c632"+    , "336372ec82d0d68befad83691966ef6ffc65105388eb2d6eed826c2285037c77"+    , "75b95108eff1fabe83613e1c4de575e72a5cdc4bb9311dd006f971a052386692"+    , ""+    , ""+    , ""+    , "3c683f6d4f8f5a4018d01633dfee74266aaa68ed6fc649e81b64dfdf5f75e75d5c058d66cf5fd01a4f143a6ff695517a4a43bd3adfd1fb2c28ba9a41063140bedbffdb4d21b1ace1550d59209ec61f1e2dbacb2a9116a79cb1410bf2deca5218080aacd9c68e1d6557721a8913e23f617e30f2e594f61267d5ed81464ee730b2"+    ],+    -- COUNT = 5+    [ "22c1af2f2a4c885f06988567da9fc90f34f80f6dd5101c281beef497a6a1b2f8"+    , "3fafdecf79a4174801f133131629037b"+    , "80327dac486111b8a8b2c8e8381fb2d713a67695c2e660b2b0d4af696cc3e1de"+    , "f95a0e4bd24f0e2e9e444f511b7632868ead0d5bb3846771264e03f8ab8ed074"+    , ""+    , ""+    , ""+    , "77a7fea2f35a188f6d1bfdd49b569d8c45e2dd431d35a18c6f432c724f1e33ae92cb89a9cf91519e50705a53199f5b572dc85c1aef8f28fb52dc7986228f66954d54eda84a86962cf25cf765bd9949876349291b1aae5f88fcf4b376912d205add4f53b2770c657946c0d824281f441509153f48356d9d43f8a927e0693db8fc"+    ],+    -- COUNT = 6+    [ "d0840e3a8d629d5b883d33e053a341b21c674e67e1999f068c497ecfaabfd6f6"+    , "071de7244ecb2fdf7ab27f2d84aa7b7a"+    , "90d609527fad96ffe64ab153860346f3d237c8940555ae17b47842d82d3b0943"+    , "1dd1a8b59856c49a388f594c5f42cc2e4a56b3ccb8a65e7066e44c12f4344d50"+    , ""+    , ""+    , ""+    , "7ab28a9b2d3ae999195553e6550cced4c2daccbe7ec9dcbb0d467fabba185b727fbfd9830242cd098f4db3cf4a85e8bf8e8d5974b62b28550922b32ed5bfc1a522b6605cf93bf8d90bdec1c5b9e59c6fc37a817d437068a87254be1f7c4618ada46fbc3a2efb02e44524e21d91be7534cf05fbfd858304b706d6a91ea1cc6ad5"+    ],+    -- COUNT = 7+    [ "2e2dd56869104492767a59778652831919e1c8b970f84e824ae4116597a0ab7f"+    , "01c42a7e983641de46c82fd09b4f2f76"+    , "bcd9e1508fcc22820a8be07180fea5045367333b569e111b011cd57dc1858765"+    , "7306507cd3ca7eec667e640d270cfbb033063d97520b6b7e38ff3cea0e79d12b"+    , ""+    , ""+    , ""+    , "b915726c7b8c5dc3975f1a334684b973abf6a9495d930088cf5d071548e4fd29a67b55cc561ed6949ad28150a9fb4307c1fa5f783a7ea872e8d7c7e67ff0c2906081ee915737d813c25be5c30b952a36f393e6baa56ab01adc2b4776ad7b5d036a53659877c7a4e5220a897d6c0799af37beeed91173fbe9c613c3b6b9bb28e5"+    ],+    -- COUNT = 8+    [ "d1aab0f16bd47a5ccd67c22e094daa3735eae21aa57f0bcd9e053d9d0d545cb8"+    , "199310dfe1b01265b8c0d2b46d6c7c9f"+    , "625b4b8f4de72ea9cb6f70556322dc2a19d6b2b32de623f557e419a084ba60fd"+    , "f50cabae4e060f3971096b78e550cda2837a26a693d905db2d992d589b268f44"+    , ""+    , ""+    , ""+    , "987e1fdfe004c619cf1e9034576707eccd849400e19c87a1fef5b0179ec51c42a2f8c45d7942d0023a023c89f188b2634362703985695369863322f58619c50a7385a2dc91fc78f94b59f0131dc2b56a0d7c699d427285da1c104b0ad1739da10d8071c23993787045dc21f0070e1e9aa1658fc8e3add73dac7262e80e0aa2ee"+    ],+    -- COUNT = 9+    [ "449480eaa100aff6f48dc6286a5a81b9728b084864f78a9da98f606a00a6a41f"+    , "e53c6c5ac3da9f4726389a03f97bb640"+    , "6b8fedc084d8e28d333aef6db3702b6351f0d24e30908cccb63794282655886b"+    , "73a6d64e1966ae324388dc12c14544e9dc5ae4fcb331e99d350c456ff16f9aa0"+    , ""+    , ""+    , ""+    , "a06912d362da7eb25598857f6d65344c3e23ec3deb80c6e43158845b95eaeca241c0bbbd67ac385e24693444455cc1c2c08c1134d956b8bc93b28be9c2d3322b3e09252979dfb8d39d04c94f81bebda5c73110605a237b561216bda9ee9bdee1cc0c7728bcc8304682334ca944e467a27a85313fa5395a9c790e35defd2edb12"+    ],+    -- COUNT = 10+    [ "9a6174166e97aa4981ddf580bc01c96754b9f0ba042750aabfda1cffe56e8581"+    , "d7512ff6b7db7ce141b2bb01dcd0425e"+    , "ed75288f23275f9422444da5d3b53ccb3c4ac8acfb659a1e9b7655c2db52f879"+    , "6888b9277e57dc57663d402eba8d03cf56a070dc868e6a128b18040002baf690"+    , ""+    , ""+    , ""+    , "03519dfb2ff88cc2b53eecc48ae2a18ddcf91a5d69d5aefcdda8444e6df790a5240e67b2a4de75b4bb8a31f0f8aeb5e785ffb7a1341bb52fe00a05ee66fa2d44ea9956e055f9ffa6647c3bfe851ab364ade71a0d356de710ddafb7622b1da1bc53fd4d3210407289c68d8aeb346bf15806dbe787e781b94f63da3e1f61b5ac60"+    ],+    -- COUNT = 11+    [ "9c6ae1002ee1b0add0be563ce50f899da936e13efa620d08c2688c192514763a"+    , "fde7db5160c73044be73e9d4c1b22d86"+    , "8fdaaeffd64e53f7b4374d902d441209964e12b65d29afec258e65db6de167ca"+    , "bcc28fd58e397f53f494ad8132df82c5d8c4c22ea0b7139bd81eeba65667bb69"+    , ""+    , ""+    , ""+    , "021d938c9b4db780c7d8134aeff1053e5b8843370b8ae9a6749fca7199d809810f1bc8dfa49426470c30c3616f903e35fbacb23420a32f1bee567cc32300f704246ddc0217f236ef52c3ec9e2433ca66f05c25721f7661c43f22c1a125ed5db531bd0836eb435c27eefc7424ce9d845e1d4cc4c503097b4ffca788e674a5cb53"+    ],+    -- COUNT = 12+    [ "fe96a85b69d46b540918927bb609dc57642eeaefd46bb5da2163a0bc60294b58"+    , "22195a410d24db45589448dfe979d3fd"+    , "20f698833a4472fd7b78fb9b0c4eb68604f166a2694c4af48dac2b2376790e1e"+    , "09cb870879d3f734214f6a4bd2e08c62a2a954bebe559416d8c3551aafe71d6a"+    , ""+    , ""+    , ""+    , "d3e96dbe29e1fcb8ed83b19dbfb240e6f41679fbe83853aa71446617e63e5af78cf98b331d15bccb8c673c4e5d5dcec467a1fe26a6cd1696d0c9bc49f78139d051287df7f3ae0dbb4bbf581cb8211931063c3f4612ced53f59d1b4ebb875729139f5d2a7d60642e8f2835eed888b7e3e49c0dffd012cd746abfa3e1c5c2308c6"+    ],+    -- COUNT = 13+    [ "a4fd693ff0a8af24bcec352d3196549fd0da5ee5d99ca58416ca03ce4c50f38e"+    , "8cd67f2bf71d4366ce61396642531ff5"+    , "368969c15a4849d7593be8b162113b9298a535c148ff668a9e8b147fb3af4eba"+    , "83d2be9a0d74e6a42159ae630acebf4e15271ef7f14f3de14752be0e0e822b11"+    , ""+    , ""+    , ""+    , "e9188fc0eaec74b2608e21e3a40be94aaf4ae08eb684de8f8bba2d5fd3b073aa5531c938c0fc628da65725c54b5c68bb91d7d326565e96685e0a4e7b220c50e0caf1628edba5bd755b31894f8cb90afa76e88c5eb9e61b4932444c1397dee3e32241a3fb70a3929e49f6da02eea54812abb3d6b5cee18f03af1e0b4958430ab3"+    ],+    -- COUNT = 14+    [ "254ff5687a6dad3f1d237dc762f58d24ef2e2c084d0a48d26a3dc81e5490cda3"+    , "f2ec392acca491e03ce47b95963a49fc"+    , "f806b9b4a56682c61b55cb6a334caf87ffe135adfea6d0c3fc22b39898fbd078"+    , "b8494b1c1f1752fb6f80d732a89b08115857f7cc96e7dff05ebb822706889917"+    , ""+    , ""+    , ""+    , "0e527e00494d55564f9d9b28e7110f9a61ce36c883b5be2dcb055444164cdddd1a9f2731716f22d6ff476ce413c77abfc0e946871d5481345c2e97b4bfdd12ac03df606fc56bdb99ac7b71a69b5b9160373bbec3e9dde477180af454e7acc6bc58dc0afb4281c0de4354c1bf599054e3800c6d60d892858865b5361f50bfca9b"+    ]+    ]++{-+    [SHA-256]+    [PredictionResistance = False]+    [EntropyInputLen = 256]+    [NonceLen = 128]+    [PersonalizationStringLen = 256]+    [AdditionalInputLen = 256]+    [ReturnedBitsLen = 1024]+-}++r4 :: [TestVector]+r4 =+    [+    -- COUNT = 0+    [ "cdb0d9117cc6dbc9ef9dcb06a97579841d72dc18b2d46a1cb61e314012bdf416"+    , "d0c0d01d156016d0eb6b7e9c7c3c8da8"+    , "6f0fb9eab3f9ea7ab0a719bfa879bf0aaed683307fda0c6d73ce018b6e34faaa"+    , "8ec6f7d5a8e2e88f43986f70b86e050d07c84b931bcf18e601c5a3eee3064c82"+    , "1ab4ca9014fa98a55938316de8ba5a68c629b0741bdd058c4d70c91cda5099b3"+    , "16e2d0721b58d839a122852abd3bf2c942a31c84d82fca74211871880d7162ff"+    , "53686f042a7b087d5d2eca0d2a96de131f275ed7151189f7ca52deaa78b79fb2"+    , "dda04a2ca7b8147af1548f5d086591ca4fd951a345ce52b3cd49d47e84aa31a183e31fbc42a1ff1d95afec7143c8008c97bc2a9c091df0a763848391f68cb4a366ad89857ac725a53b303ddea767be8dc5f605b1b95f6d24c9f06be65a973a089320b3cc42569dcfd4b92b62a993785b0301b3fc452445656fce22664827b88f"+    ],+    -- COUNT = 1+    [ "3e42348bf76c0559cce9a44704308c85d9c205b676af0ac6ba377a5da12d3244"+    , "9af783973c632a490f03dbb4b4852b1e"+    , "2e51c7a8ac70adc37fc7e40d59a8e5bf8dfd8f7b027c77e6ec648bd0c41a78de"+    , "45718ac567fd2660b91c8f5f1f8f186c58c6284b6968eadc9810b7beeca148a1"+    , "63a107246a2070739aa4bed6746439d8c2ce678a54fc887c5aba29c502da7ba9"+    , "e4576291b1cde51c5044fdc5375624cebf63333c58c7457ca7490da037a9556e"+    , "b5a3fbd57784b15fd875e0b0c5e59ec5f089829fac51620aa998fff003534d6f"+    , "c624d26087ffb8f39836c067ba37217f1977c47172d5dcb7d40193a1cfe20158b774558cbee8eb6f9c62d629e1bcf70a1439e46c5709ba4c94a006ba94994796e10660d6cb1e150a243f7ba5d35c8572fd96f43c08490131797e86d3ed8467b692f92f668631b1d32862c3dc43bfba686fe72fdd947db2792463e920522eb4bc"+    ],+    -- COUNT = 2+    [ "b63fdd83c674699ba473faab9c358434771c5fa0348ca0faf7ebd7cf5891826b"+    , "5fd204e2598d9626edab4158a8cfd95f"+    , "2a5dfad8494306d9d4648a805c4602216a746ae3493492693a50a86d1ba05c64"+    , "adea5ba92f8010bb1a6a4b6fae2caa0b384165adf721253afd635d6021f764af"+    , "07c69d8d2b8aa1454c5c48083dd41477fda6bfcf0385638379933a60ed2e0a77"+    , "a14e902247a3d6493d3fbc8519518b71a660e5502cf7ecfc796cfaa5b4ee4baa"+    , "60e690e4a1eba14aec5187112a383e9991347fab7bac7cb2a40a52579a0d2718"+    , "792b47b6ed221623bb187d63e3f039c6983d94efd5771dc9b4c40bee65924513485a6332baeda6a96f9bb431f592d73462b61d9d914a72b56fa9d87597426fb246424ebcd7abd51b2eefec8f5b839c0b3c34015342ace296b5f2218fa194b50aea1c89663460292c92c45f112ddbf6b9406f6e7ccee9c47ed2d90a27be5dd73e"+    ],+    -- COUNT = 3+    [ "dab85f98eaf0cfba013b97de4d9c264ca6fe120366cb83e8b3113c68b34e39d5"+    , "d05108e1028ae67b4ea63bdc6d75eb88"+    , "09fed3822f6f5e5b9e575d31dc215de1607b0dfc927412618c2d8f79166dbaba"+    , "1794885a64470744198b7d0bc24472ffe8daf3c7eb219df6ddf180e484fe0aa5"+    , "8d74d01b582f70b92f53b43468084e1586d9b36465d333d5faaf6911e62fe40e"+    , "ef7f6b6eb479ab05b3f9ab6dd72eac8b1e86d887f1bcae363cae386d0275a06f"+    , "7442b2a792a6a29559bb8a515d56916ee18200580aa02e1237dd358619382d8f"+    , "49d2cbfa0897b7d961c293c1e572fb26f28e7b956e746f6eda90454c1370a29e25303ceadc7837514dc638553b487ef9487c977c10625409178ad6506d103c487a66655d08659d92a4d5994d1c8ddb28fe60f2e49577d6e80cae1478068c98268f45e6293c9326c7f726ec89601351c0a26fd3a6549f8a41c6f58692c86594c0"+    ],+    -- COUNT = 4+    [ "0f0aa84ef12e10ae2b279e799c683441862457b9bc25581c2cd3d5b58a5b3246"+    , "f74f4230c2427a52f01f39e825d250ac"+    , "d02b2f53da48b923c2921e0f75bd7e6139d7030aead5aeebe46c20b9ca47a38a"+    , "5222b26e79f7c3b7066d581185b1a1f6376796f3d67f59d025dd2a7b1886d258"+    , "d11512457bf3b92d1b1c0923989911f58f74e136b1436f00bad440dd1d6f1209"+    , "54d9ea7d40b7255ef3d0ab16ea9fdf29b9a281920962b5c72d97b0e371b9d816"+    , "601cef261da8864f1e30196c827143e4c363d3fa865b808e9450b13e251d47fa"+    , "e9847cefea3b88062ea63f92dc9e96767ce9202a6e049c98dc1dcbc6d707687bd0e98ed2cc215780c454936292e44a7c6856d664581220b8c8ca1d413a2b81120380bfd0da5ff2bf737b602727709523745c2ced8daef6f47d1e93ef9bc141a135674cba23045e1f99aa78f8cead12eeffff20de2008878b1f806a2652db565a"+    ],+    -- COUNT = 5+    [ "6a868ce39a3adcd189bd704348ba732936628f083de8208640dbd42731447d4e"+    , "efdde4e22b376e5e7385e79024350699"+    , "f7285cd5647ff0e2c71a9b54b57f04392641a4bde4a4024fa11c859fecaad713"+    , "0174f7f456ac06c1d789facc071701f8b60e9accebced73a634a6ad0e1a697d4"+    , "5463bb2241d10c970b68c3abc356c0fe5ef87439fc6457c5ee94be0a3fb89834"+    , "3ab62cdbc638c1b2b50533d28f31b1758c3b8435fe24bb6d4740005a73e54ce6"+    , "2dbf4c9123e97177969139f5d06466c272f60d067fefadf326ccc47971115469"+    , "8afce49dccc4ff64c65a83d8c0638bd8e3b7c13c52c3c59d110a8198753e96da512c7e03aeed30918706f3ad3b819e6571cfa87369c179fb9c9bbc88110baa490032a9d41f9931434e80c40ae0051400b7498810d769fb42dddbc7aa19bdf79603172efe9c0f5d1a65372b463a31178cbae581fa287f39c4fbf8434051b7419f"+    ],+    -- COUNT = 6+    [ "bb6b339eae26072487084ec9e4b53f2f1d4267d205042e74c77fb9ca0591ba50"+    , "c0e7bf6eb07feccbc494af4098e59d30"+    , "34aeec7ed0cae83701b6477709c8654a1114212401dc91cbe7de39d71f0c06e1"+    , "f47fc60afbeb807236f7974d837335bc0b22288ef09ddfcb684e16b4c36a050b"+    , "e8071ccd84ac4527e5c6e85b0709ed867776f25ae0e04180dcb7105ecd3e3490"+    , "fbac45b5952200ad7c4232500f2417a1c14723bdd1cc078821bc2fe138b86597"+    , "c4292d7dbef3ba7c18bf46bcf26776add22ab8ee206d6c722665dec6576b1bc0"+    , "228aa2a314fcbfe63089ce953ac457093deaa39dd9ce2a4ece56a6028a476a98129be516d6979eff5587c032cdf4739d7ac712970f600fa781a8e542e399661183e34e4b90c59ec5dc5cad86f91083529d41c77b8f36c5a8e28ba1a548223a02eaed8426f6fe9f349ebec11bc743e767482e3472ec2799c1f530ebdc6c03bc4b"+    ],+    -- COUNT = 7+    [ "be658e56f80436039e2a9c0a62952dd7d70842244b5ab10f3b8a87d36104e629"+    , "33c9627455dfde91865aee93e5071147"+    , "d3a6eb29b180b791984deb056d72c0608a2c9044237aecf100ccb03700064c5e"+    , "bef24dc9a5aa23003d3825f9b2b00e7dab571ea6ad86415dbd30c0bbdce7b972"+    , "047c29e4d1584fa70cb66e2aa148a2aa29837c5eee64dcac60fdba356cdf90bb"+    , "41c4792161b1b00d410cb79cd56bd311a714fb78dc3471c25bdd7479f2e9a952"+    , "cd4936d7bc3ea0e7201bcbefbc908215a97680ca6ce8672360aea600b6564308"+    , "2c25557f6db07db057f56ad5b6dc0427d1a0e825c48c19a526f9a65087c6d1ead7c78363a61616c84f1022653af65173a3f9ec3275f2b0a0d0bc750194673c0eaa6c623cd88abb0c8979baee4cd85bfce2e4a20bfebf2c3be61676563767dfe229e0b7be67ad6fcd116dd0b460708b1b0e5c3d60f3dd8138030404d197375d75"+    ],+    -- COUNT = 8+    [ "ae537f31a28ca14500e759716bc207983bfeab60b25079fa30b77b8d41244cb9"+    , "fca9e27d8ab84cf9b9ce491ec5d8cb67"+    , "8c9cb2b19aa3abe83c8fe7da96e9c11648252653a29dcd5bf0ac334ac587f032"+    , "1eb52777be480f05115ae6370f30159a94d50ffcc64454678ab1d1ac6f166fa7"+    , "9cdf6f1a2bc07acd4b0f43b5f2b892a1153e2669f237d257923636094fb40b54"+    , "692d512722de6ba720fd23c8994ac63179b5f7e611addf9cfacd60e06e144a6a"+    , "bbeea7b2bea821f339f494947c0b4bae8056119db69a3cbef21914953729cdef"+    , "c0c4fb7080c0fbe425c1b756fb3a090cb0d08c7027d1bb82ed3b07613e2a757f83a78d42f9d8653954b489f800a5e058ebc4f5a1747526541d8448cb72e2232db20569dc96342c36672c4be625b363b4587f44557e58cedb4597cb57d006fda27e027818ae89e15b4c6382b9e7a4453290ea43163b4f9cae38b1023de6a47f7b"+    ],+    -- COUNT = 9+    [ "2f8994c949e08862db0204008f55d3561f3e0362df13b9d9a70fda39938f2d33"+    , "1bf3e94ea858160b832fe85d301256f5"+    , "b46671cf7fa142e7012ed261e1fe86714711c246c7d1c0330fa692141e86d5d1"+    , "5ecdb1e8fe12260b9bfe12d6e6f161474fa2311e12e39b0beb0fcd92a6737b73"+    , "3ce9a29f0207d079e6dc81fb830356e555f96a23ea71424972ea9308965786d3"+    , "db950000c0776cc0e049929ce021020adc42d29cd9b5d8f7117fbe6bde3e594f"+    , "fc18ee6dd3dac2306774f0ac36cd789e33462d72a8c75df9057123db33e5f7bc"+    , "8546362cc8af9b78dd6e8eb2c37db96e70708852bfd9380abedc7f324575a167bea18f632f3e19d099cfbf310773f9719eec036d2e09f393a023add8ebdc4fb87af43b2fe6c7eaa4d39f8022ce247aa45fdc84d1b92cacce6eae8252a03ec2ec5330c01f56d113fd2ec3d0240af0afcf13ddde205bb5e7c2d912dcb4aee5dcf3"+    ],+    -- COUNT = 10+    [ "0c85e31487de1d7ba4a7b998ac56dc42c6dc0eae7bf5c8aaf1e4e78875f5fb47"+    , "de878f728f73f83dc2a2f550b96c8b97"+    , "9aac37bce1a6a81dc7934e23747991e3cf48c55ffe5a57781c41768a35220a01"+    , "2d5ca8af1a70cfdccd015ee3bf0665dd1941fc6a7317b9d0d06658f5744cfbd9"+    , "db881e6d0dc3b62793d7da5fe5a18e33be9b93f4a63a00a878dfbecf0d383bd2"+    , "f743ce1b72f3de4c901369eed581c626ed3081ca707e6634fdaff46721ce0878"+    , "cd52da3ec8a839c537dacdea8506a3eeee879de388ff5e513322d6d1bb3ff694"+    , "a5bdd57cb8fde6298e7c5e563afcca60dd472eca484bd8c3cc17f3307be09b601744dd3ab9e8a44107c5868824575f850c0f399b280cf198006f83ede8c0b537e9be227fa140b65995ad9dfa1f2303d560c3b7f59bedd93c1282ea263924469411c2653f87fd814c74cb91c148430481d64bad0fec3cbb3dd1f39aa55c36f81b"+    ],+    -- COUNT = 11+    [ "93161b2dc08cb0fd50171141c865a841ca935cfdd2b5907d6ff8ab0348c4ceb0"+    , "5cb9f6e5912b90c3349a50ab881b35a1"+    , "0dceb4a36326c4df1685df43fddeecb5d0c76f00eb44826694f27e610290f6e1"+    , "d8e9be44b5f293482548d4787762ebfb03c73c40e45385e8b98907cd66f493dd"+    , "105a8f85d6959f3e043ef508cfea21d52123f03b7aea8034c4eec761eaba1fee"+    , "bf781f7e489d9b4b5aa5ee6d1796468af672a8d25f311edf3c4b4dbf433d703f"+    , "c81d6bcf1e5bf37e39dda1735c6f193df115b1a854a12e7cafe060afe4589335"+    , "4306628124d0100fade7eaaf5edf227d50771f9e5f2e1e983800eef9a39fde0b0c280e63c8728d836b5b93ea794a32c1c04cfc54bd5300e3febb5fe2e1023eded8d7cd180279a598f76823e8d5a7dffcc93a09deec5d1f80838e938fba4de9f47e94b99382ae55f116df9c3b3ddf7e50516e203645852a415796f03a86418107"+    ],+    -- COUNT = 12+    [ "1ae12a5e4e9a4a5bfa79da30a9e6c62ffc639572ef1254194d129a16eb53c716"+    , "5399b3481fdf24d373222267790a0fec"+    , "8280cfdcd7a575816e0199e115da0ea77cae9d30b49c891a6c225e9037ba67e2"+    , "681554ff702658122e91ba017450cfdfc8e3f4911153f7bcc428403e9c7b9d68"+    , "226732b7a457cf0ac0ef09fd4f81296573b49a68de5e7ac3070e148c95e8e323"+    , "45942b5e9a1a128e85e12c34596374ddc85fd7502e5633c7390fc6e6f1e5ef56"+    , "6fc59929b41e77072886aff45f737b449b105ed7eacbd74c7cbfedf533dbeaa1"+    , "b7547332e1509663fcfea2128f7f3a3df484cd8df034b00199157d35d61e35f1a9d481c7d2e81305616d70fc371ee459b0b2267d627e928590edcac3231898b24ef378aa9c3d381619f665379be76c7c1bd535505c563db3725f034786e35bdd90429305fd71d7bf680e8cdd6d4c348d97078f5cf5e89dee2dc410fad4f2a30f"+    ],+    -- COUNT = 13+    [ "29e20d724dfa459960df21c6ec76b1e6cabd23a9e9456d6c591d7e4529da0ef8"+    , "95df1f837eba47a1687aa5c4ddcf8aaf"+    , "3713b601e164b1a51dda1ca9242ff477514648e90d311a06e10ce5aa15da5d7f"+    , "2a2a312626ca3e20034fc4f28033c7d573f66ef61ab2ea0c7bf0411a9d247264"+    , "ec68be33ac8ff3dd127e051604898c0f9a501271859376653a0516336180993d"+    , "9935499661d699a00c622a875441b4df5204958fe95892c8ce67f7dfb2be3e4a"+    , "256a4ba9e8f439d5487fa5eb45efcf1bc1120491724db3abe328d951f2739fc9"+    , "73114cb3624d687d4cd49a6e769dfc7a3f8901dc41f6ad1df4ce480536fa82e52ae958d0528640d92b8bb981b755058e32c4733682e5c4c0df41f3505a1643a0dd49cfdeaf7a18adffca88256c6d2cceb838af6c92a64bc21cb7a760a0391291bfe3575e014fc156323f8eb5e86518c669dad8d29ad5fd4ef6e296f4a0764c26"+    ],+    -- COUNT = 14+    [ "1353f3543eb1134980e061fc4382394975dbc74f1f1ea5ecc02780a813ac5ee6"+    , "cf584db2447afbe2c8fa0c15575ee391"+    , "345b0cc016f2765a8c33fc24f1dcfa182cbe29d7eacbcdc9bcda988521458fc2"+    , "ba60219332a67b95d90ec9de6b8453d4c8af991ae9277461ff3af1b92fc985d3"+    , "6964b9b9842aec9c7ec2aad926d701f30eec76fe699265ae2a7765d716958069"+    , "6a03c28a9365c558c33d3fdc7e5ebf0b4d32caac70df71403fd70ced09757528"+    , "a58546c72a0b4d47c9bd6c19e7cf4ab73b2d7ba36c6c6dc08606f608795ebd29"+    , "5b029ef68b6799868b04dc28dbea26bc2fa9fcc8c2b2795aafeed0127b7297fa19a4ef2ba60c42ff8259d5a759f92bd90fdfb27145e82d798bb3ab7fd60bfaefb7aefb116ca2a4fa8b01d96a03c47c8d987fdd33c460e560b138891278313bb619d0c3c6f9d7c5a37e88fce83e94943705c6ff68e00484e74ad4097b0c9e5f10"+    ]+    ]+
+ tests/Network/Haskoin/Crypto/Keys/Tests.hs view
@@ -0,0 +1,143 @@+module Network.Haskoin.Crypto.Keys.Tests (tests) where++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.String (fromString)+import Data.String.Conversions (cs)+import Data.Binary.Get (runGet)+import Data.Binary.Put (runPut)+import qualified Data.ByteString as BS (length, index)++import qualified Crypto.Secp256k1 as EC++import Network.Haskoin.Test+import Network.Haskoin.Crypto+import Network.Haskoin.Util+import Network.Haskoin.Internals (PubKeyI(..), PrvKeyI(..))++tests :: [Test]+tests =+    [ testGroup "PubKey Binary"+        [ testProperty "is public key canonical" isCanonicalPubKey+        , testProperty "makeKey . toKey" makeToKey+        , testProperty "makeKeyU . toKey" makeToKeyU+        ]+    , testGroup "Key formats"+        [ testProperty "fromWif . toWif PrvKey" fromToWIF+        , testProperty "constant 32-byte encoding PrvKey" binaryPrvKey+        ]+    , testGroup "Key compression"+        [ testProperty "Compressed public key" testCompressed+        , testProperty "Uncompressed public key" testUnCompressed+        , testProperty "Compressed private key" testPrivateCompressed+        , testProperty "Uncompressed private key" testPrivateUnCompressed+        ]+    , testGroup "From/To strings"+        [ testProperty "Read/Show public key" testReadShowPubKey+        , testProperty "Read/Show compressed public key" testReadShowPubKeyC+        , testProperty "Read/Show uncompressed public key" testReadShowPubKeyU+        , testProperty "Read/Show private key" testReadShowPrvKey+        , testProperty "Read/Show private key" testReadShowPrvKeyC+        , testProperty "Read/Show private key" testReadShowPrvKeyU+        , testProperty "From string public key" testFromStringPubKey+        , testProperty "From string compressed public key" testFromStringPubKeyC+        , testProperty "From string uncompressed public key" testFromStringPubKeyU+        , testProperty "From string private key" testFromStringPrvKey+        , testProperty "From string compressed private key" testFromStringPrvKeyC+        , testProperty "From string uncompressed private key" testFromStringPrvKeyU+        ]+    ]++-- github.com/bitcoin/bitcoin/blob/master/src/script.cpp+-- from function IsCanonicalPubKey+isCanonicalPubKey :: ArbitraryPubKey -> Bool+isCanonicalPubKey (ArbitraryPubKey _ p) = not $+    -- Non-canonical public key: too short+    (BS.length bs < 33) ||+    -- Non-canonical public key: invalid length for uncompressed key+    (BS.index bs 0 == 4 && BS.length bs /= 65) ||+    -- Non-canonical public key: invalid length for compressed key+    (BS.index bs 0 `elem` [2,3] && BS.length bs /= 33) ||+    -- Non-canonical public key: compressed nor uncompressed+    (not $ BS.index bs 0 `elem` [2,3,4])+  where+    bs = encode' p++makeToKey :: EC.SecKey -> Bool+makeToKey i = prvKeySecKey (makePrvKey i) == i++makeToKeyU :: EC.SecKey -> Bool+makeToKeyU i = prvKeySecKey (makePrvKeyU i) == i++{- Key formats -}++fromToWIF :: ArbitraryPrvKey -> Bool+fromToWIF (ArbitraryPrvKey pk) = (fromWif $ toWif pk) == Just pk++binaryPrvKey :: ArbitraryPrvKey -> Bool+binaryPrvKey (ArbitraryPrvKey k) =+    (k == runGet (prvKeyGetMonad f) (runPut $ prvKeyPutMonad k)) &&+    (Just k == decodePrvKey f (encodePrvKey k))+  where+    f = makePrvKeyG (prvKeyCompressed k)++{- Key Compression -}++testCompressed :: EC.SecKey -> Bool+testCompressed n =+    (pubKeyCompressed $ derivePubKey $ makePrvKey n) &&+    (pubKeyCompressed $ derivePubKey $ makePrvKeyG True n)++testUnCompressed :: EC.SecKey -> Bool+testUnCompressed n =+    (not $ pubKeyCompressed $ derivePubKey $ makePrvKeyG False n) &&+    (not $ pubKeyCompressed $ derivePubKey $ makePrvKeyU n)++testPrivateCompressed :: EC.SecKey -> Bool+testPrivateCompressed n =+    (prvKeyCompressed $ makePrvKey n) &&+    (prvKeyCompressed $ makePrvKeyC n)++testPrivateUnCompressed :: EC.SecKey -> Bool+testPrivateUnCompressed n =+    (not $ prvKeyCompressed $ makePrvKeyG False n) &&+    (not $ prvKeyCompressed $ makePrvKeyU n)++{- Strings -}++testReadShowPubKey :: ArbitraryPubKey -> Bool+testReadShowPubKey (ArbitraryPubKey _ k) = read (show k) == k++testReadShowPubKeyC :: ArbitraryPubKeyC -> Bool+testReadShowPubKeyC (ArbitraryPubKeyC _ k) = read (show k) == k++testReadShowPubKeyU :: ArbitraryPubKeyU -> Bool+testReadShowPubKeyU (ArbitraryPubKeyU _ k) = read (show k) == k++testReadShowPrvKey :: ArbitraryPrvKey -> Bool+testReadShowPrvKey (ArbitraryPrvKey k) = read (show k) == k++testReadShowPrvKeyC :: ArbitraryPrvKeyC -> Bool+testReadShowPrvKeyC (ArbitraryPrvKeyC k) = read (show k) == k++testReadShowPrvKeyU :: ArbitraryPrvKeyU -> Bool+testReadShowPrvKeyU (ArbitraryPrvKeyU k) = read (show k) == k++testFromStringPubKey :: ArbitraryPubKey -> Bool+testFromStringPubKey (ArbitraryPubKey _ k) = fromString (cs . encodeHex $ encode' k) == k++testFromStringPubKeyC :: ArbitraryPubKeyC -> Bool+testFromStringPubKeyC (ArbitraryPubKeyC _ k) = fromString (cs . encodeHex $ encode' k) == k++testFromStringPubKeyU :: ArbitraryPubKeyU -> Bool+testFromStringPubKeyU (ArbitraryPubKeyU _ k) = fromString (cs . encodeHex $ encode' k) == k++testFromStringPrvKey :: ArbitraryPrvKey -> Bool+testFromStringPrvKey (ArbitraryPrvKey k) = fromString (cs $ toWif k) == k++testFromStringPrvKeyC :: ArbitraryPrvKeyC -> Bool+testFromStringPrvKeyC (ArbitraryPrvKeyC k) = fromString (cs $ toWif k) == k++testFromStringPrvKeyU :: ArbitraryPrvKeyU -> Bool+testFromStringPrvKeyU (ArbitraryPrvKeyU k) = fromString (cs $ toWif k) == k
+ tests/Network/Haskoin/Crypto/Mnemonic/Tests.hs view
@@ -0,0 +1,200 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Crypto.Mnemonic.Tests (tests) where++import Test.QuickCheck (Arbitrary, Property, arbitrary, choose, (==>))+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.Bits ((.&.), shiftR)+import Data.Binary (Binary)+import Data.Word (Word32, Word64)+import qualified Data.ByteString as BS+    ( ByteString+    , empty+    , append+    , concat+    , length+    , last+    )+import qualified Data.ByteString.Char8 as C (words)++import Network.Haskoin.Test+import Network.Haskoin.Crypto+import Network.Haskoin.Util+import Network.Haskoin.Internals (fromMnemonic, getBits)+++tests :: [Test]+tests =+    [ testGroup "Encode mnemonic"+        [ testProperty "128-bit entropy -> 12 words" toMnemonic128+        , testProperty "160-bit entropy -> 18 words" toMnemonic160+        , testProperty "256-bit entropy -> 24 words" toMnemonic256+        , testProperty "512-bit entropy -> 48 words" toMnemonic512+        , testProperty "n-bit entropy -> m words" toMnemonicVar+        ]+    , testGroup "Encode/Decode Mnemonic"+        [ testProperty "128-bit entropy" fromToMnemonic128+        , testProperty "160-bit entropy" fromToMnemonic160+        , testProperty "256-bit entropy" fromToMnemonic256+        , testProperty "512-bit entropy" fromToMnemonic512+        , testProperty "n-bit entropy" fromToMnemonicVar+        ]+    , testGroup "Mnemonic to seed"+        [ testProperty "128-bit entropy" mnemonicToSeed128+        , testProperty "160-bit entropy" mnemonicToSeed160+        , testProperty "256-bit entropy" mnemonicToSeed256+        , testProperty "512-bit entropy" mnemonicToSeed512+        , testProperty "n-bit entropy" mnemonicToSeedVar+        ]+    , testGroup "Get bits from ByteString"+        [ testProperty "Byte count" getBitsByteCount+        , testProperty "End bits" getBitsEndBits+        ]+    ]++binWordsToBS :: Binary a => [a] -> BS.ByteString+binWordsToBS = foldr f BS.empty+  where+    f b a = a `BS.append` encode' b++{- Encode mnemonic -}++toMnemonic128 :: (Word64, Word64) -> Bool+toMnemonic128 (a, b) = l == 12+  where+    bs = encode' a `BS.append` encode' b+    l = length . C.words . fromRight $ toMnemonic bs++toMnemonic160 :: (Word32, Word64, Word64) -> Bool+toMnemonic160 (a, b, c) = l == 15+  where+    bs = BS.concat [encode' a, encode' b, encode' c]+    l = length . C.words . fromRight $ toMnemonic bs++toMnemonic256 :: (Word64, Word64, Word64, Word64) -> Bool+toMnemonic256 (a, b, c, d) = l == 24+  where+    bs = BS.concat [encode' a, encode' b, encode' c, encode' d]+    l = length . C.words . fromRight $ toMnemonic bs++toMnemonic512 ::+    ((Word64, Word64, Word64, Word64), (Word64, Word64, Word64, Word64)) -> Bool+toMnemonic512 ((a, b, c, d), (e, f, g, h)) = l == 48+  where+    bs = BS.concat+        [ encode' a, encode' b, encode' c, encode' d+        , encode' e, encode' f, encode' g, encode' h+        ]+    l = length . C.words . fromRight $ toMnemonic bs++toMnemonicVar :: [Word32] -> Property+toMnemonicVar ls = not (length ls > 8) ==> l == wc+  where+    bs = binWordsToBS ls+    bl = BS.length bs+    cb = bl `div` 4+    wc = (cb + bl * 8) `div` 11+    l = length . C.words . fromRight $ toMnemonic bs++{- Encode/Decode -}++fromToMnemonic128 :: (Word64, Word64) -> Bool+fromToMnemonic128 (a, b) = bs == bs'+  where+    bs = encode' a `BS.append` encode' b+    bs' = fromRight (fromMnemonic =<< toMnemonic bs)++fromToMnemonic160 :: (Word32, Word64, Word64) -> Bool+fromToMnemonic160 (a, b, c) = bs == bs'+  where+    bs = BS.concat [encode' a, encode' b, encode' c]+    bs' = fromRight (fromMnemonic =<< toMnemonic bs)++fromToMnemonic256 :: (Word64, Word64, Word64, Word64) -> Bool+fromToMnemonic256 (a, b, c, d) = bs == bs'+  where+    bs = BS.concat [encode' a, encode' b, encode' c, encode' d]+    bs' = fromRight (fromMnemonic =<< toMnemonic bs)++fromToMnemonic512 ::+    ((Word64, Word64, Word64, Word64), (Word64, Word64, Word64, Word64)) -> Bool+fromToMnemonic512 ((a, b, c, d), (e, f, g, h)) = bs == bs'+  where+    bs = BS.concat+        [ encode' a, encode' b, encode' c, encode' d+        , encode' e, encode' f, encode' g, encode' h+        ]+    bs' = fromRight (fromMnemonic =<< toMnemonic bs)++fromToMnemonicVar :: [Word32] -> Property+fromToMnemonicVar ls = not (length ls > 8) ==> bs == bs'+  where+    bs = binWordsToBS ls+    bs' = fromRight (fromMnemonic =<< toMnemonic bs)++{- Mnemonic to seed -}++mnemonicToSeed128 :: (Word64, Word64) -> Bool+mnemonicToSeed128 (a, b) = l == 64+  where+    bs = encode' a `BS.append` encode' b+    seed = fromRight (mnemonicToSeed "" =<< toMnemonic bs)+    l = BS.length seed++mnemonicToSeed160 :: (Word32, Word64, Word64) -> Bool+mnemonicToSeed160 (a, b, c) = l == 64+  where+    bs = BS.concat [encode' a, encode' b, encode' c]+    seed = fromRight (mnemonicToSeed "" =<< toMnemonic bs)+    l = BS.length seed++mnemonicToSeed256 :: (Word64, Word64, Word64, Word64) -> Bool+mnemonicToSeed256 (a, b, c, d) = l == 64+  where+    bs = BS.concat [encode' a, encode' b, encode' c, encode' d]+    seed = fromRight (mnemonicToSeed "" =<< toMnemonic bs)+    l = BS.length seed++mnemonicToSeed512 ::+    ((Word64, Word64, Word64, Word64), (Word64, Word64, Word64, Word64)) -> Bool+mnemonicToSeed512 ((a, b, c, d), (e, f, g, h)) = l == 64+  where+    bs = BS.concat+        [ encode' a, encode' b, encode' c, encode' d+        , encode' e, encode' f, encode' g, encode' h+        ]+    seed = fromRight (mnemonicToSeed "" =<< toMnemonic bs)+    l = BS.length seed++mnemonicToSeedVar :: [Word32] -> Property+mnemonicToSeedVar ls = not (length ls > 16) ==> l == 64+  where+    bs = binWordsToBS ls+    seed = fromRight (mnemonicToSeed "" =<< toMnemonic bs)+    l = BS.length seed++{- Get bits from ByteString -}++data ByteCountGen = ByteCountGen BS.ByteString Int deriving Show++instance Arbitrary ByteCountGen where+    arbitrary = do+        ArbitraryByteString bs <- arbitrary+        i <- choose (0, BS.length bs * 8)+        return $ ByteCountGen bs i++getBitsByteCount :: ByteCountGen -> Bool+getBitsByteCount (ByteCountGen bs i) = BS.length bits == l+  where+    (q, r) = i `quotRem` 8+    bits = getBits i bs+    l = if r == 0 then q else q + 1++getBitsEndBits :: ByteCountGen -> Bool+getBitsEndBits (ByteCountGen bs i) = mask+  where+    r = i `mod` 8+    bits = getBits i bs+    mask = if r == 0 then True else BS.last bits .&. (0xff `shiftR` r) == 0x00+
+ tests/Network/Haskoin/Crypto/Mnemonic/Units.hs view
@@ -0,0 +1,181 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Crypto.Mnemonic.Units (tests) where++import Test.HUnit (assertEqual)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)++import Data.Maybe (fromJust)+import Data.String.Conversions (cs)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS++import Network.Haskoin.Crypto+import Network.Haskoin.Util+import Network.Haskoin.Internals (fromMnemonic)++tests :: [Test]+tests =+    [ testGroup "Entropy to mnemonic sentence" toMnemonicTest+    , testGroup "Mnemonic sentence to entropy" fromMnemonicTest+    , testGroup "Mnemonic sentence to seed" mnemonicToSeedTest+    ]++toMnemonicTest :: [Test]+toMnemonicTest = map f $ zip ents mss+  where+    f (e, m) = g (cs e) . assertEqual "" m . h $ e+    g = testCase+    h = fromRight . toMnemonic . fromJust . decodeHex++fromMnemonicTest :: [Test]+fromMnemonicTest = map f $ zip ents mss+  where+    f (e, m) = g (cs e) . assertEqual "" e . h $ m+    g = testCase+    h = encodeHex . fromRight . fromMnemonic++mnemonicToSeedTest :: [Test]+mnemonicToSeedTest = map f $ zip mss seeds+  where+    f (m, s) = g s . assertEqual "" s . h $ m+    g = testCase . (++ "...") . cs . BS.take 50+    h = encodeHex . fromRight . mnemonicToSeed "TREZOR"+++ents :: [ByteString]+ents =+    [ "00000000000000000000000000000000"+    , "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f"+    , "80808080808080808080808080808080"+    , "ffffffffffffffffffffffffffffffff"+    , "000000000000000000000000000000000000000000000000"+    , "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f"+    , "808080808080808080808080808080808080808080808080"+    , "ffffffffffffffffffffffffffffffffffffffffffffffff"+    , "0000000000000000000000000000000000000000000000000000000000000000"+    , "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f"+    , "8080808080808080808080808080808080808080808080808080808080808080"+    , "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+    , "77c2b00716cec7213839159e404db50d"+    , "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b"+    , "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982"+    , "0460ef47585604c5660618db2e6a7e7f"+    , "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f"+    , "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416"+    , "eaebabb2383351fd31d703840b32e9e2"+    , "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78"+    , "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef"+    , "18ab19a9f54a9274f03e5209a2ac8a91"+    , "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4"+    , "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419"+    ]++mss :: [Mnemonic]+mss =+    [ "abandon abandon abandon abandon abandon abandon abandon abandon abandon\+      \ abandon abandon about"+    , "legal winner thank year wave sausage worth useful legal winner thank\+      \ yellow"+    , "letter advice cage absurd amount doctor acoustic avoid letter advice\+      \ cage above"+    , "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong"+    , "abandon abandon abandon abandon abandon abandon abandon abandon abandon\+      \ abandon abandon abandon abandon abandon abandon abandon abandon agent"+    , "legal winner thank year wave sausage worth useful legal winner thank\+      \ year wave sausage worth useful legal will"+    , "letter advice cage absurd amount doctor acoustic avoid letter advice\+      \ cage absurd amount doctor acoustic avoid letter always"+    , "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo\+      \ when"+    , "abandon abandon abandon abandon abandon abandon abandon abandon abandon\+      \ abandon abandon abandon abandon abandon abandon abandon abandon abandon\+      \ abandon abandon abandon abandon abandon art"+    , "legal winner thank year wave sausage worth useful legal winner thank\+      \ year wave sausage worth useful legal winner thank year wave sausage\+      \ worth title"+    , "letter advice cage absurd amount doctor acoustic avoid letter advice\+      \ cage absurd amount doctor acoustic avoid letter advice cage absurd\+      \ amount doctor acoustic bless"+    , "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo\+      \ zoo zoo zoo zoo zoo vote"+    , "jelly better achieve collect unaware mountain thought cargo oxygen act\+      \ hood bridge"+    , "renew stay biology evidence goat welcome casual join adapt armor shuffle\+      \ fault little machine walk stumble urge swap"+    , "dignity pass list indicate nasty swamp pool script soccer toe leaf photo\+      \ multiply desk host tomato cradle drill spread actor shine dismiss\+      \ champion exotic"+    , "afford alter spike radar gate glance object seek swamp infant panel\+      \ yellow"+    , "indicate race push merry suffer human cruise dwarf pole review arch keep\+      \ canvas theme poem divorce alter left"+    , "clutch control vehicle tonight unusual clog visa ice plunge glimpse\+      \ recipe series open hour vintage deposit universe tip job dress radar\+      \ refuse motion taste"+    , "turtle front uncle idea crush write shrug there lottery flower risk\+      \ shell"+    , "kiss carry display unusual confirm curtain upgrade antique rotate hello\+      \ void custom frequent obey nut hole price segment"+    , "exile ask congress lamp submit jacket era scheme attend cousin alcohol\+      \ catch course end lucky hurt sentence oven short ball bird grab wing top"+    , "board flee heavy tunnel powder denial science ski answer betray cargo\+      \ cat"+    , "board blade invite damage undo sun mimic interest slam gaze truly\+      \ inherit resist great inject rocket museum chief"+    , "beyond stage sleep clip because twist token leaf atom beauty genius food\+      \ business side grid unable middle armed observe pair crouch tonight away\+      \ coconut"+    ]++seeds :: [ByteString]+seeds =+    [ "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a69\+      \87599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04"+    , "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1\+      \296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607"+    , "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f1\+      \2eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8"+    , "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a133325729\+      \17f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069"+    , "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9\+      \a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa"+    , "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c3\+      \92d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd"+    , "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913f\+      \fb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65"+    , "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43\+      \348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528"+    , "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4\+      \d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8"+    , "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146a\+      \d717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87"+    , "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61a\+      \f0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f"+    , "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0\+      \a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad"+    , "b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f6\+      \72a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff"+    , "9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941\+      \c69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5"+    , "ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da2\+      \0af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67"+    , "65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41\+      \f8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4"+    , "3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349db\+      \e2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba"+    , "fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f\+      \86360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449"+    , "bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c4\+      \04f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c"+    , "ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b079\+      \403485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79"+    , "095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b\+      \14d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c"+    , "6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe0\+      \05831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8"+    , "f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf0\+      \7c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9"+    , "b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb\+      \86a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd"+    ]
+ tests/Network/Haskoin/Crypto/Units.hs view
@@ -0,0 +1,247 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Crypto.Units (tests) where++import Test.HUnit (Assertion, assertBool)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)++import Control.Monad (replicateM_)+import Control.Monad.Trans (liftIO)++import Data.Maybe (fromJust, isJust, isNothing)+import Data.Binary (put)+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as C (pack)++import qualified Crypto.Secp256k1 as EC (SecKey, exportCompactSig)++import Network.Haskoin.Crypto+import Network.Haskoin.Util+import Network.Haskoin.Internals (PrvKeyI(..), PubKeyI(..), Signature(..))++-- Unit tests copied from bitcoind implementation+-- https://github.com/bitcoin/bitcoin/blob/master/src/test/key_tests.cpp++strSecret1 :: ByteString+strSecret1  = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"++strSecret2 :: ByteString+strSecret2  = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"++strSecret1C :: ByteString+strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"++strSecret2C :: ByteString+strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"++addr1 :: ByteString+addr1  = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"++addr2 :: ByteString+addr2  = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"++addr1C :: ByteString+addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"++addr2C :: ByteString+addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"++strAddressBad :: ByteString+strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"++sigMsg :: [ByteString]+sigMsg =+    [ mconcat ["Very secret message ", (C.pack $ show (i :: Int)), ": 11"]+    | i <- [0..15]+    ]++sec1 :: PrvKey+sec1  = fromJust $ fromWif strSecret1++sec2 :: PrvKey+sec2  = fromJust $ fromWif strSecret2++sec1C :: PrvKey+sec1C = fromJust $ fromWif strSecret1C++sec2C :: PrvKey+sec2C = fromJust $ fromWif strSecret2C++pub1 :: PubKey+pub1  = derivePubKey sec1++pub2 :: PubKey+pub2  = derivePubKey sec2++pub1C :: PubKey+pub1C = derivePubKey sec1C++pub2C :: PubKey+pub2C = derivePubKey sec2C++tests :: [Test]+tests =+    [ testGroup "ECDSA PRNG unit tests"+        [ testCase "genPrvKey produces unique keys" uniqueKeys+        ]+    , testGroup "bitcoind /src/test/key_tests.cpp" $+        [ testCase "Decode Valid WIF" checkPrivkey+        , testCase "Decode Invalid WIF" checkInvalidKey+        , testCase "Check private key compression" checkPrvKeyCompressed+        , testCase "Check public key compression" checkKeyCompressed+        , testCase "Check matching address" checkMatchingAddress+        ] +++        ( map (\x -> (testCase ("Check sig: " ++ (show x))+                (checkSignatures $ doubleHash256 x))) sigMsg )+    , testGroup "Trezor RFC 6979 Test Vectors"+        [ testCase "RFC 6979 Test Vector 1" (testSigning $ detVec !! 0)+        , testCase "RFC 6979 Test Vector 2" (testSigning $ detVec !! 1)+        , testCase "RFC 6979 Test Vector 3" (testSigning $ detVec !! 2)+        , testCase "RFC 6979 Test Vector 4" (testSigning $ detVec !! 3)+        , testCase "RFC 6979 Test Vector 5" (testSigning $ detVec !! 4)+        , testCase "RFC 6979 Test Vector 6" (testSigning $ detVec !! 5)+        , testCase "RFC 6979 Test Vector 7" (testSigning $ detVec !! 6)+        , testCase "RFC 6979 Test Vector 8" (testSigning $ detVec !! 7)+        , testCase "RFC 6979 Test Vector 9" (testSigning $ detVec !! 8)+        , testCase "RFC 6979 Test Vector 10" (testSigning $ detVec !! 9)+        , testCase "RFC 6979 Test Vector 11" (testSigning $ detVec !! 10)+        , testCase "RFC 6979 Test Vector 12" (testSigning $ detVec !! 11)+        ]+    ]++{- ECDSA PRNG unit tests -}++uniqueKeys :: Assertion+uniqueKeys = do+    (k1,k2,k3) <- liftIO $ withSource getEntropy $ do+        a <- genPrvKey+        b <- genPrvKey+        replicateM_ 20 genPrvKey+        c <- genPrvKey+        return (a,b,c)+    assertBool "DiffKey" $ k1 /= k2 && k1 /= k3 && k2 /= k3++{- bitcoind /src/test/key_tests.cpp -}++checkPrivkey :: Assertion+checkPrivkey = do+    assertBool "Key 1"  $ isJust $ fromWif strSecret1+    assertBool "Key 2"  $ isJust $ fromWif strSecret2+    assertBool "Key 1C" $ isJust $ fromWif strSecret1C+    assertBool "Key 2C" $ isJust $ fromWif strSecret2C++checkInvalidKey :: Assertion+checkInvalidKey =+    assertBool "Bad key" $ isNothing $ fromWif strAddressBad++checkPrvKeyCompressed :: Assertion+checkPrvKeyCompressed = do+    assertBool "Key 1"  $ not $ prvKeyCompressed sec1+    assertBool "Key 2"  $ not $ prvKeyCompressed sec2+    assertBool "Key 1C" $ prvKeyCompressed sec1C+    assertBool "Key 2C" $ prvKeyCompressed sec2C++checkKeyCompressed :: Assertion+checkKeyCompressed = do+    assertBool "Key 1"  $ not $ pubKeyCompressed pub1+    assertBool "Key 2"  $ not $ pubKeyCompressed pub2+    assertBool "Key 1C" $ pubKeyCompressed pub1C+    assertBool "Key 2C" $ pubKeyCompressed pub2C++checkMatchingAddress :: Assertion+checkMatchingAddress = do+    assertBool "Key 1"  $ addr1  == (addrToBase58 $ pubKeyAddr pub1)+    assertBool "Key 2"  $ addr2  == (addrToBase58 $ pubKeyAddr pub2)+    assertBool "Key 1C" $ addr1C == (addrToBase58 $ pubKeyAddr pub1C)+    assertBool "Key 2C" $ addr2C == (addrToBase58 $ pubKeyAddr pub2C)++checkSignatures :: Hash256 -> Assertion+checkSignatures h = do+    let sign1  = signMsg h sec1+        sign2  = signMsg h sec2+        sign1C = signMsg h sec1C+        sign2C = signMsg h sec2C+    assertBool "Key 1, Sign1"   $ verifySig h sign1 pub1+    assertBool "Key 1, Sign2"   $ not $ verifySig h sign2 pub1+    assertBool "Key 1, Sign1C"  $ verifySig h sign1C pub1+    assertBool "Key 1, Sign2C"  $ not $ verifySig h sign2C pub1+    assertBool "Key 2, Sign1"   $ not $ verifySig h sign1 pub2+    assertBool "Key 2, Sign2"   $ verifySig h sign2 pub2+    assertBool "Key 2, Sign1C"  $ not $ verifySig h sign1C pub2+    assertBool "Key 2, Sign2C"  $ verifySig h sign2C pub2+    assertBool "Key 1C, Sign1"  $ verifySig h sign1 pub1C+    assertBool "Key 1C, Sign2"  $ not $ verifySig h sign2 pub1C+    assertBool "Key 1C, Sign1C" $ verifySig h sign1C pub1C+    assertBool "Key 1C, Sign2C" $ not $ verifySig h sign2C pub1C+    assertBool "Key 2C, Sign1"  $ not $ verifySig h sign1 pub2C+    assertBool "Key 2C, Sign2"  $ verifySig h sign2 pub2C+    assertBool "Key 2C, Sign1C" $ not $ verifySig h sign1C pub2C+    assertBool "Key 2C, Sign2C" $ verifySig h sign2C pub2C+++{- Trezor RFC 6979 Test Vectors -}+-- github.com/trezor/python-ecdsa/blob/master/ecdsa/test_pyecdsa.py++detVec :: [(EC.SecKey, ByteString, ByteString)]+detVec =+    [+      ( "0000000000000000000000000000000000000000000000000000000000000001"+      , "Satoshi Nakamoto"+      , "934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d82442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5"+      )+    , ( "0000000000000000000000000000000000000000000000000000000000000001"+      , "All those moments will be lost in time, like tears in rain. Time to die..."+      , "8600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21"+      )+    , ( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"+      , "Satoshi Nakamoto"+      , "fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d06b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5"+      )+    , ( "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181"+      , "Alan Turing"+      , "7063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c58dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea"+      )+    , ( "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2"+      , "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!"+      , "b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6"+      )+    , ( "0000000000000000000000000000000000000000000000000000000000000001"+      , "Everything should be made as simple as possible, but not simpler."+      , "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"+      )+    , ( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"+      , "Equations are more important to me, because politics is for the present, but an equation is something for eternity."+      , "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"+      )+    , ( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"+      , "Not only is the Universe stranger than we think, it is stranger than we can think."+      , "ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd06fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"+      )+    , ( "0000000000000000000000000000000000000000000000000000000000000001"+      , "How wonderful that we have met with a paradox. Now we have some hope of making progress."+      , "c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d375afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"+      )+    , ( "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64"+      , "Computer science is no more about computers than astronomy is about telescopes."+      , "7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"+      )+    , ( "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637"+      , "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough"+      , "fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda4870e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"+      )+    , ( "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3"+      , "The question of whether computers can think is like the question of whether submarines can swim."+      , "cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf906ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"+      )+    ]++testSigning :: (EC.SecKey, ByteString, ByteString) -> Assertion+testSigning (prv, msg, str) = do+    assertBool "RFC 6979 Vector" $ res == fromJust (decodeHex str)+    assertBool "Valid sig" $ verifySig msg' sig (derivePubKey prv')+  where+    sig@(Signature g) = signMsg msg' prv'+    msg' = hash256 msg+    prv' = makePrvKey prv+    compact = EC.exportCompactSig g+    res = runPut' $ put compact
+ tests/Network/Haskoin/Json/Tests.hs view
@@ -0,0 +1,32 @@+module Network.Haskoin.Json.Tests (tests) where++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.Aeson (FromJSON, ToJSON, decode, encode)++import Network.Haskoin.Test++tests :: [Test]+tests =+    [ testGroup "Serialize & de-serialize haskoin types to JSON"+        [ testProperty "ScriptOutput" $ \(ArbitraryScriptOutput x) -> metaID x+        , testProperty "OutPoint" $ \(ArbitraryOutPoint x) -> metaID x+        , testProperty "Address" $ \(ArbitraryAddress x) -> metaID x+        , testProperty "Tx" $ \(ArbitraryTx x) -> metaID x+        , testProperty "TxHash" $ \(ArbitraryTxHash x) -> metaID x+        , testProperty "BlockHash" $ \(ArbitraryBlockHash x) -> metaID x+        , testProperty "SigHash" $ \(ArbitrarySigHash x) -> metaID x+        , testProperty "SigInput" $ \(ArbitrarySigInput x _) -> metaID x+        , testProperty "PubKey" $ \(ArbitraryPubKey _ x) -> metaID x+        , testProperty "PubKeyC" $ \(ArbitraryPubKeyC _ x) -> metaID x+        , testProperty "PubKeyU" $ \(ArbitraryPubKeyU _ x) -> metaID x+        , testProperty "XPrvKey" $ \(ArbitraryXPrvKey x) -> metaID x+        , testProperty "XPubKey" $ \(ArbitraryXPubKey _ x) -> metaID x+        , testProperty "DerivPath" $ \(ArbitraryDerivPath x) -> metaID x+        ]+    ]++metaID :: (FromJSON a, ToJSON a, Eq a) => a -> Bool+metaID x = (decode . encode) [x] == Just [x]+
+ tests/Network/Haskoin/Node/Units.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Node.Units (tests) where++import Test.HUnit (Assertion, assertBool)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)++import Data.Maybe (fromJust)++import Network.Haskoin.Crypto+import Network.Haskoin.Node+import Network.Haskoin.Util++tests :: [Test]+tests =+    [ -- Test cases come from bitcoind /src/test/bloom_tests.cpp+      testGroup "Bloom Filters"+        [ testCase "Bloom Filter Vector 1" bloomFilter1+        , testCase "Bloom Filter Vector 2" bloomFilter2+        , testCase "Bloom Filter Vector 3" bloomFilter3+        ]+    ]++bloomFilter1 :: Assertion+bloomFilter1 = do+    assertBool "Bloom filter doesn't contain vector 1" $ bloomContains f1 v1+    assertBool "Bloom filter contains something it should not" $+        not $ bloomContains f1 v2+    assertBool "Bloom filter doesn't contain vector 3" $ bloomContains f3 v3+    assertBool "Bloom filter doesn't contain vector 4" $ bloomContains f4 v4+    assertBool "Bloom filter serialization is incorrect" $ (encode' f4) == bs+  where+    f0 = bloomCreate 3 0.01 0 BloomUpdateAll+    f1 = bloomInsert f0 v1+    f3 = bloomInsert f1 v3+    f4 = bloomInsert f3 v4+    v1 = fromJust $ decodeHex "99108ad8ed9bb6274d3980bab5a85c048f0950c8"+    v2 = fromJust $ decodeHex "19108ad8ed9bb6274d3980bab5a85c048f0950c8"+    v3 = fromJust $ decodeHex "b5a2c786d9ef4658287ced5914b37a1b4aa32eee"+    v4 = fromJust $ decodeHex "b9300670b4c5366e95b2699e8b18bc75e5f729c5"+    bs = fromJust $ decodeHex "03614e9b050000000000000001"++bloomFilter2 :: Assertion+bloomFilter2 = do+    assertBool "Bloom filter doesn't contain vector 1" $ bloomContains f1 v1+    assertBool "Bloom filter contains something it should not" $+        not $ bloomContains f1 v2+    assertBool "Bloom filter doesn't contain vector 3" $ bloomContains f3 v3+    assertBool "Bloom filter doesn't contain vector 4" $ bloomContains f4 v4+    assertBool "Bloom filter serialization is incorrect" $ (encode' f4) == bs+  where+    f0 = bloomCreate 3 0.01 2147483649 BloomUpdateAll+    f1 = bloomInsert f0 v1+    f3 = bloomInsert f1 v3+    f4 = bloomInsert f3 v4+    v1 = fromJust $ decodeHex "99108ad8ed9bb6274d3980bab5a85c048f0950c8"+    v2 = fromJust $ decodeHex "19108ad8ed9bb6274d3980bab5a85c048f0950c8"+    v3 = fromJust $ decodeHex "b5a2c786d9ef4658287ced5914b37a1b4aa32eee"+    v4 = fromJust $ decodeHex "b9300670b4c5366e95b2699e8b18bc75e5f729c5"+    bs = fromJust $ decodeHex "03ce4299050000000100008001"++bloomFilter3 :: Assertion+bloomFilter3 = do+    assertBool "Bloom filter serialization is incorrect" $ (encode' f2) == bs+  where+    f0 = bloomCreate 2 0.001 0 BloomUpdateAll+    f1 = bloomInsert f0 $ encode' p+    f2 = bloomInsert f1 $ encode' $ getAddrHash $ pubKeyAddr p+    k = fromJust $ fromWif "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"+    p = derivePubKey k+    bs = fromJust $ decodeHex "038fc16b080000000000000001"+
+ tests/Network/Haskoin/Script/Tests.hs view
@@ -0,0 +1,392 @@+module Network.Haskoin.Script.Tests+( tests+, execScriptIO+, testValid+, testInvalid+, runTests+) where++import Test.QuickCheck.Property (Property, (==>))+import Test.Framework (Test, testGroup, buildTest)+import Test.Framework.Providers.HUnit (testCase)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.Framework.Runners.Console (defaultMainWithArgs)+import qualified Test.HUnit as HUnit (assertFailure, assertBool)++import Control.Monad (when)++import Data.Bits (testBit)+import Data.List (isPrefixOf)+import Data.List.Split ( splitOn )+import Data.Char (ord)+import Data.Maybe (catMaybes, isNothing)+import Data.Int (Int64)+import Data.Word (Word8, Word32)+import Data.Binary (encode, decode, decodeOrFail)+import qualified Data.Aeson as A (decode)+import qualified Data.ByteString.Lazy as LBS (pack, unpack)+import qualified Data.ByteString.Lazy.Char8 as C (readFile)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+    ( singleton+    , length+    , tail+    , head+    , pack+    , empty+    )+import qualified Data.ByteString.Char8 as C (putStrLn)++import Numeric (readHex)+import Text.Read (readMaybe)++import Network.Haskoin.Test+import Network.Haskoin.Transaction+import Network.Haskoin.Script+import Network.Haskoin.Crypto+import Network.Haskoin.Util+import Network.Haskoin.Internals+    ( Flag+    , runStack+    , dumpStack+    , decodeInt+    , encodeInt+    , decodeBool+    , encodeBool+    , execScript+    )++tests :: [Test]+tests =+    [ testGroup "Script Parser"+        [ testProperty "decode . encode OP_1 .. OP_16" testScriptOpInt+        , testProperty "decode . encode ScriptOutput" testScriptOutput+        , testProperty "decode . encode ScriptInput" testScriptInput+        , testProperty "sorting MultiSig scripts" testSortMulSig+        ]+    , testGroup "Script SigHash"+        [ testProperty "canonical signatures" $+            \(ArbitraryTxSignature _ _ sig) -> testCanonicalSig sig+        , testProperty "decode SigHash from Word8" binSigHashByte+        , testProperty "encodeSigHash32 is 4 bytes long" testEncodeSH32+        , testProperty "decode . encode TxSignature" $+            \(ArbitraryTxSignature _ _ sig) -> binTxSig sig+        , testProperty "decodeCanonical . encode TxSignature" $+            \(ArbitraryTxSignature _ _ sig) -> binTxSigCanonical sig+        , testProperty "Testing txSigHash with SigSingle" testSigHashOne+        ]+    , testGroup "Integer Types"+        [ testProperty "decodeInt . encodeInt Int"  testEncodeInt+        , testProperty "decodeBool . encodeBool Bool" testEncodeBool+        ]+    , testFile "Canonical Valid Script Test Cases"+               "tests/data/script_valid.json"+               True+    , testFile "Canonical Invalid Script Test Cases"+               "tests/data/script_invalid.json"+               False+    ]++{- Script Parser -}++testScriptOpInt :: ArbitraryIntScriptOp -> Bool+testScriptOpInt (ArbitraryIntScriptOp i) =+    (intToScriptOp <$> scriptOpToInt i) == Right i++testScriptOutput :: ArbitraryScriptOutput -> Bool+testScriptOutput (ArbitraryScriptOutput so) =+    decodeOutput (encodeOutput so) == Right so++testScriptInput :: ArbitraryScriptInput -> Bool+testScriptInput (ArbitraryScriptInput si) =+    decodeInput (encodeInput si) == Right si++testSortMulSig :: ArbitraryMSOutput -> Bool+testSortMulSig (ArbitraryMSOutput out) =+    snd $ foldl f (head pubs,True) $ tail pubs+  where+    pubs = getOutputMulSigKeys $ sortMulSig out+    f (a,t) b | t && encode' a <= encode' b = (b,True)+              | otherwise                   = (b,False)++{- Script SigHash -}++testCanonicalSig :: TxSignature -> Bool+testCanonicalSig ts@(TxSignature _ sh)+    | isSigUnknown sh = isLeft $ decodeCanonicalSig bs+    | otherwise =+        isRight (decodeCanonicalSig bs) && isCanonicalHalfOrder (txSignature ts)+  where+    bs = encodeSig ts++binSigHashByte :: Word8 -> Bool+binSigHashByte w+    | w == 0x01 = res == SigAll False+    | w == 0x02 = res == SigNone False+    | w == 0x03 = res == SigSingle False+    | w == 0x81 = res == SigAll True+    | w == 0x82 = res == SigNone True+    | w == 0x83 = res == SigSingle True+    | testBit w 7 = res == SigUnknown True w+    | otherwise = res == SigUnknown False w+  where+    res = decode' $ BS.singleton w++testEncodeSH32 :: ArbitrarySigHash -> Bool+testEncodeSH32 (ArbitrarySigHash sh) =+    BS.length bs == 4 &&+    BS.head bs == (BS.head $ encode' sh) &&+    BS.tail bs == BS.pack [0,0,0]+  where+    bs = encodeSigHash32 sh++binTxSig :: TxSignature -> Bool+binTxSig ts = decodeSig (encodeSig ts) == Right ts++binTxSigCanonical :: TxSignature -> Bool+binTxSigCanonical ts@(TxSignature _ sh)+    | isSigUnknown sh = isLeft $ decodeCanonicalSig $ encodeSig ts+    | otherwise = (fromRight $ decodeCanonicalSig $ encodeSig ts) == ts++testSigHashOne :: ArbitraryTx -> ArbitraryScript -> Bool -> Property+testSigHashOne (ArbitraryTx tx) (ArbitraryScript s) acp = not (null $ txIn tx) ==>+    if length (txIn tx) > length (txOut tx)+        then res == one+        else res /= one+  where+    res = txSigHash tx s (length (txIn tx) - 1) (SigSingle acp)+    one = "0100000000000000000000000000000000000000000000000000000000000000"++{- Script Evaluation Primitives -}++testEncodeInt :: Int64 -> Bool+testEncodeInt i+    | i >  0x7fffffff = isNothing i'+    | i < -0x7fffffff = isNothing i'+    | otherwise       = i' == Just i+  where+    i' = decodeInt $ encodeInt i++testEncodeBool :: Bool -> Bool+testEncodeBool b = decodeBool (encodeBool b) == b++{- Script Evaluation -}++rejectSignature :: SigCheck+rejectSignature _ _ _ = False++{- Parse tests from bitcoin-qt repository -}++type ParseError = String++parseHex' :: String -> Maybe [Word8]+parseHex' (a:b:xs) = case readHex $ [a, b] :: [(Integer, String)] of+                      [(i, "")] -> case parseHex' xs of+                                    Just ops -> Just $ fromIntegral i:ops+                                    Nothing -> Nothing+                      _ -> Nothing+parseHex' [_] = Nothing+parseHex' [] = Just []++parseFlags :: String -> [ Flag ]+parseFlags "" = []+parseFlags s = map read . splitOn "," $ s++parseScript :: String -> Either ParseError Script+parseScript scriptString =+      do bytes <- LBS.pack <$> parseBytes scriptString+         script <- decodeScript bytes+         when (encode script /= bytes) $+            Left "encode script /= bytes"+         when (decode (encode script) /= script) $+            Left "decode (encode script) /= script"+         return script+      where+          decodeScript bytes = case decodeOrFail bytes of+            Left (_, _, e) -> Left $ "decode error: " ++ e+            Right (_, _, Script s) -> Right $ Script s+          parseBytes :: String -> Either ParseError [Word8]+          parseBytes string = concat <$> mapM parseToken (words string)+          parseToken :: String -> Either ParseError [Word8]+          parseToken tok =+              case alternatives of+                    (ops:_) -> Right ops+                    _ -> Left $ "unknown token " ++ tok+              where alternatives :: [[Word8]]+                    alternatives = catMaybes  [ parseHex+                                              , parseInt+                                              , parseQuote+                                              , parseOp+                                              ]+                    parseHex | "0x" `isPrefixOf` tok = parseHex' (drop 2 tok)+                             | otherwise = Nothing+                    parseInt = fromInt . fromIntegral <$>+                               (readMaybe tok :: Maybe Integer)+                    parseQuote | tok == "''" = Just [0]+                               | (head tok) == '\'' && (last tok) == '\'' =+                                 Just $ encodeBytes $ opPushData $ BS.pack+                                      $ map (fromIntegral . ord)+                                      $ init . tail $ tok+                               | otherwise = Nothing+                    fromInt :: Int64 -> [Word8]+                    fromInt n | n ==  0 = [0x00]+                              | n == -1 = [0x4f]+                              | 1 <= n && n <= 16 = [0x50 + fromIntegral n]+                              | otherwise = encodeBytes+                                                $ opPushData $ BS.pack+                                                $ encodeInt n+                    parseOp = encodeBytes <$> (readMaybe $ "OP_" ++ tok)+                    encodeBytes = LBS.unpack . encode++testFile :: String -> String -> Bool -> Test+testFile groupLabel path expected = buildTest $ do+    dat <- C.readFile path+    case (A.decode dat) :: Maybe [[String]] of+        Nothing -> return $+                    testCase groupLabel $+                    HUnit.assertFailure $ "can't read test file " ++ path+        Just testDefs -> return $ testGroup groupLabel+                                $ map parseTest+                                $ filterPureComments testDefs++    where   parseTest :: [String] -> Test+            parseTest s = case testParts s of+                Nothing -> testCase "can't parse test case" $+                               HUnit.assertFailure $ "json element " ++ show s+                Just ( sig, pubKey, flags, label ) -> makeTest label sig pubKey flags++            makeTest :: String -> String -> String -> String -> Test+            makeTest label sig pubKey flags =+                testCase label' $ case (parseScript sig, parseScript pubKey) of+                    (Left e, _) -> parseError $ "can't parse sig: " +++                                                show sig ++ " error: " ++ e+                    (_, Left e) -> parseError $ "can't parse key: " +++                                                show pubKey ++ " error: " ++ e+                    (Right scriptSig, Right scriptPubKey) ->+                        runTest scriptSig scriptPubKey ( parseFlags flags )++                where label' =  if null label+                                    then "sig: [" ++ sig ++ "] " +++                                        " pubKey: [" ++ pubKey ++ "] "+                                    else " label: " ++ label++            parseError message = HUnit.assertBool+                                ("parse error in valid script: " ++ message)+                                (expected == False)++            filterPureComments = filter ( not . null . tail )++            runTest scriptSig scriptPubKey scriptFlags =+                HUnit.assertBool+                  (" eval error: " ++ errorMessage)+                  (expected == scriptPairTestExec scriptSig scriptPubKey scriptFlags)++                where run f = f scriptSig scriptPubKey rejectSignature scriptFlags+                      errorMessage = case run execScript of+                        Left e -> show e+                        Right _ -> " none"++-- | Splits the JSON test into the different parts.  No processing,+-- just handling the fact that comments may not be there or might have+-- junk before it.  Output is the tuple ( sig, pubKey, flags, comment+-- ) as strings+testParts :: [String] -> Maybe (String, String, String, String)+testParts l = let ( x, r ) = splitAt 3 l+                  comment = if null r then "" else last r+              in if length x < 3+                 then Nothing+                 else let ( sig:pubKey:flags:[] ) = x in+                      Just ( sig, pubKey, flags, comment )++-- repl utils++execScriptIO :: String -> String -> String -> IO ()+execScriptIO sig key flgs = case (parseScript sig, parseScript key) of+  (Left e, _) -> print $ "sig parse error: " ++ e+  (_, Left e) -> print $ "key parse error: " ++ e+  (Right scriptSig, Right scriptPubKey) ->+      case execScript scriptSig scriptPubKey rejectSignature ( parseFlags flgs ) of+          Left e -> putStrLn $ "error " ++ show e+          Right p -> do putStrLn $ "successful execution"+                        C.putStrLn $ dumpStack $ runStack p++testValid :: Test+testValid = testFile "Canonical Valid Script Test Cases"+            "tests/data/script_valid.json" True++testInvalid :: Test+testInvalid = testFile "Canonical Valid Script Test Cases"+              "tests/data/script_invalid.json" False++-- | Maximum value of sequence number+maxSeqNum :: Word32+maxSeqNum = 0xffffffff -- Perhaps this should be moved to constants.++-- | Null output used to create CoinbaseTx+nullOutPoint :: OutPoint+nullOutPoint =+    OutPoint+        { outPointHash  =+            "0000000000000000000000000000000000000000000000000000000000000000"+        , outPointIndex = -1+        }++-- | Some of the scripts tests require transactions be built in a+-- standard way.  This function builds the crediting transaction.+-- Quoting the top comment of script_valid.json: "It is evaluated as+-- if there was a crediting coinbase transaction with two 0 pushes as+-- scriptSig, and one output of 0 satoshi and given scriptPubKey,+-- followed by a spending transaction which spends this output as only+-- input (and correct prevout hash), using the given scriptSig. All+-- nLockTimes are 0, all nSequences are max."+buildCreditTx :: ByteString -> Tx+buildCreditTx scriptPubKey = Tx {+                 txVersion    = 1+               , txIn         = [ txI ]+               , txOut        = [ txO ]+               , txLockTime   = 0+               }+    where txO = TxOut {+                       outValue = 0+                     , scriptOutput = scriptPubKey+                     }+          txI = TxIn {+                        prevOutput = nullOutPoint+                      , scriptInput = encode' $ Script [ OP_0, OP_0 ]+                      , txInSequence = maxSeqNum+                      }++-- | Build a spending transaction for the tests.  Takes as input the+-- crediting transaction+buildSpendTx :: ByteString  -- ScriptSig+             -> Tx     -- Creditting Tx+             -> Tx+buildSpendTx scriptSig creditTx = Tx {+         txVersion  = 1+       , txIn       = [ txI ]+       , txOut      = [ txO ]+       , txLockTime = 0+       }+    where txI = TxIn {+               prevOutput   = OutPoint { outPointHash = txHash creditTx , outPointIndex = 0 }+             , scriptInput  = scriptSig+             , txInSequence = maxSeqNum+             }+          txO = TxOut { outValue = 0, scriptOutput = BS.empty }++-- | Executes the test of a scriptSig, pubKeyScript pair, including+-- building the required transactions and verifying the spending+-- transaction.+scriptPairTestExec :: Script    -- scriptSig+                   -> Script    -- pubKey+                   -> [ Flag ] -- Evaluation flags+                   -> Bool+scriptPairTestExec scriptSig pubKey flags =+    let bsScriptSig = encode' scriptSig+        bsPubKey = encode' pubKey+        spendTx = buildSpendTx bsScriptSig ( buildCreditTx bsPubKey )+    in verifySpend spendTx 0 pubKey flags++runTests :: [Test] -> IO ()+runTests ts = defaultMainWithArgs ts ["--hide-success"]+
+ tests/Network/Haskoin/Script/Units.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Script.Units (tests) where++import Test.HUnit (Assertion, assertBool)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)++import Data.Maybe (fromJust)+import Data.ByteString (ByteString)++import Network.Haskoin.Script+import Network.Haskoin.Crypto+import Network.Haskoin.Util++tests :: [Test]+tests =+    [ testGroup "Canonical signatures"+        (map canonicalVectorsMap $ zip canonicalVectors [0..])+    , testGroup "Non-canonical signatures"+        (map notCanonicalVectorsMap $ zip notCanonicalVectors [0..])+    , testGroup "Multi Signatures"+        (map mapMulSigVector $ zip mulSigVectors [0..])+    , testGroup "Signature decoding"+        (map sigDecodeMap $ zip scriptSigSignatures [0..])+    ]++canonicalVectorsMap :: (ByteString, Int) -> Test.Framework.Test+canonicalVectorsMap (_, i) =+    testCase ("Canonical Sig " ++ (show i)) func+  where+    func = testCanonicalSig $ canonicalVectors !! i++notCanonicalVectorsMap :: (ByteString, Int) -> Test.Framework.Test+notCanonicalVectorsMap (_, i) =+    testCase ("Not canonical Sig " ++ show i) func+  where+    func = testNotCanonicalSig $ notCanonicalVectors !! i++sigDecodeMap :: (ByteString, Int) -> Test.Framework.Test+sigDecodeMap (_, i) =+    testCase ("Signature " ++ show i) func+  where+    func = testSigDecode $ scriptSigSignatures !! i++testCanonicalSig :: ByteString -> Assertion+testCanonicalSig str =+    assertBool "    > Canonical Sig" $ isRight $ decodeCanonicalSig bs+  where+    bs = fromJust $ decodeHex str++testNotCanonicalSig :: ByteString -> Assertion+testNotCanonicalSig str =+    assertBool "    > Not canonical sig" $ isLeft $ decodeCanonicalSig bs+  where+    bs = fromJust $ decodeHex str++mapMulSigVector :: ((ByteString, ByteString), Int) -> Test.Framework.Test+mapMulSigVector (v, i) =+    testCase name $ runMulSigVector v+  where+    name = "MultiSignature vector " ++ (show i)++runMulSigVector :: (ByteString, ByteString) -> Assertion+runMulSigVector (a, ops) =+    assertBool "    >  MultiSig Vector" $ a == b+  where+    s = decode' $ fromJust $ decodeHex ops+    b = addrToBase58 $ scriptAddr $ fromRight $ decodeOutput s++testSigDecode :: ByteString -> Assertion+testSigDecode str =+  let bs = fromJust $ decodeHex str+      eitherSig = decodeSig bs+  in+  assertBool (unwords ["Decode failed:", fromLeft eitherSig]) $ isRight eitherSig++{- Canonical Signatures -}++-- Test vectors from bitcoind+-- http://github.com/bitcoin/bitcoin/blob/master/src/test/data/sig_canonical.json++canonicalVectors :: [ByteString]+canonicalVectors =+    [ "300602010102010101" -- Changed 0x00 to 0x01 as 0x00 is invalid+    , "3008020200ff020200ff01"+    , "304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001"+    , "30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01"+    , "3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01"+    ]++notCanonicalVectors :: [ByteString]+notCanonicalVectors =+    [ "30050201ff020001"+    , "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    , "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11"+    , "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    , "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    , "301f01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101"+    , "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001"+    , "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    , "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    , "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    , "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    , "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    , "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001"+    , "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    , "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01"+    ]++mulSigVectors :: [(ByteString, ByteString)]+mulSigVectors =+    [ ( "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC"+      , "52410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353ae"+      )+    ]++scriptSigSignatures :: [ByteString]+scriptSigSignatures =+     -- Signature in input of txid 1983a69265920c24f89aac81942b1a59f7eb30821a8b3fb258f88882b6336053+    [ "304402205ca6249f43538908151fe67b26d020306c0e59fa206cf9f3ccf641f33357119d02206c82f244d04ac0a48024fb9cc246b66e58598acf206139bdb7b75a2941a2b1e401"+      -- Signature in input of txid fb0a1d8d34fa5537e461ac384bac761125e1bfa7fec286fa72511240fa66864d  Strange DER sizes. But in Blockchain+    , "3048022200002b83d59c1d23c08efd82ee0662fec23309c3adbcbd1f0b8695378db4b14e736602220000334a96676e58b1bb01784cb7c556dd8ce1c220171904da22e18fe1e7d1510db501"+    ]
+ tests/Network/Haskoin/Transaction/Tests.hs view
@@ -0,0 +1,133 @@+module Network.Haskoin.Transaction.Tests (tests) where++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.String (fromString)+import Data.String.Conversions (cs)+import Data.Word (Word64)+import qualified Data.ByteString as BS (length)++import Network.Haskoin.Test+import Network.Haskoin.Transaction+import Network.Haskoin.Script+import Network.Haskoin.Crypto+import Network.Haskoin.Util++tests :: [Test]+tests =+    [ testGroup "Transaction tests"+        [ testProperty "decode . encode Txid" decEncTxid+        , testProperty "Read/Show transaction id" testReadShowTxHash+        , testProperty "From string transaction id" testFromStringTxHash+        ]+    , testGroup "Building Transactions"+        [ testProperty "building address tx" testBuildAddrTx+        , testProperty "testing guessTxSize function" testGuessSize+        , testProperty "testing chooseCoins function" testChooseCoins+        , testProperty "testing chooseMSCoins function" testChooseMSCoins+        ]+    , testGroup "Signing Transactions"+        [ testProperty "Sign and validate transactions" testDetSignTx+        , testProperty "Merge partially signed transactions" testMergeTx+        ]+    ]++{- Transaction Tests -}++decEncTxid :: ArbitraryTxHash -> Bool+decEncTxid (ArbitraryTxHash h) = hexToTxHash (txHashToHex h) == Just h++testReadShowTxHash :: ArbitraryTxHash -> Bool+testReadShowTxHash (ArbitraryTxHash h) = read (show h) == h++testFromStringTxHash :: ArbitraryTxHash -> Bool+testFromStringTxHash (ArbitraryTxHash h) = fromString (cs $ txHashToHex h) == h++{- Building Transactions -}++testBuildAddrTx :: ArbitraryAddress -> ArbitrarySatoshi -> Bool+testBuildAddrTx (ArbitraryAddress a) (ArbitrarySatoshi v) = case a of+    x@(PubKeyAddress _) -> Right (PayPKHash x) == out+    x@(ScriptAddress _) -> Right (PayScriptHash x) == out+  where+    tx  = buildAddrTx [] [(addrToBase58 a,v)]+    out = decodeOutputBS $ scriptOutput $ txOut (fromRight tx) !! 0++testGuessSize :: ArbitraryAddrOnlyTx -> Bool+testGuessSize (ArbitraryAddrOnlyTx tx) =+    -- We compute an upper bound but it should be close enough to the real size+    -- We give 2 bytes of slack on every signature (1 on r and 1 on s)+    guess >= len && guess <= len + 2*delta+  where+    delta    = pki + (sum $ map fst msi)+    guess    = guessTxSize pki msi pkout msout+    len      = BS.length $ encode' tx+    ins      = map f $ txIn tx+    f i      = fromRight $ decodeInputBS $ scriptInput i+    pki      = length $ filter isSpendPKHash ins+    msi      = concat $ map shData ins+    shData (ScriptHashInput _ (PayMulSig keys r)) = [(r,length keys)]+    shData _ = []+    out      = map (fromRight . decodeOutputBS . scriptOutput) $ txOut tx+    pkout    = length $ filter isPayPKHash out+    msout    = length $ filter isPayScriptHash out++testChooseCoins :: Word64 -> Word64 -> [ArbitrarySatoshi] -> Bool+testChooseCoins target kbfee coins = case chooseCoins target kbfee True coins of+    Right (chosen, change) ->+        let outSum = sum $ map coinValue chosen+            fee    = getFee kbfee (length chosen)+        in outSum == target + change + fee+    Left _ ->+        let fee = getFee kbfee (length coins)+        in target == 0 || s < target || s < target + fee+  where+    s  = sum $ map coinValue coins++testChooseMSCoins :: Word64 -> Word64+                  -> ArbitraryMSParam -> [ArbitrarySatoshi] -> Bool+testChooseMSCoins target kbfee (ArbitraryMSParam m n) coins =+    case chooseMSCoins target kbfee (m,n) True coins of+        Right (chosen,change) ->+            let outSum = sum $ map coinValue chosen+                fee    = getMSFee kbfee (m,n) (length chosen)+            in outSum == target + change + fee+        Left _ ->+            let fee = getMSFee kbfee (m,n) (length coins)+            in target == 0 || s < target + fee+  where+    s  = sum $ map coinValue coins++{- Signing Transactions -}++testDetSignTx :: ArbitrarySigningData -> Bool+testDetSignTx (ArbitrarySigningData tx sigis prv) =+    (not $ verifyStdTx tx verData)+        && (not $ verifyStdTx txSigP verData)+        && verifyStdTx txSigC verData+  where+    txSigP  = fromRight $ signTx tx sigis (tail prv)+    txSigC  = fromRight $ signTx txSigP sigis [head prv]+    verData = map (\(SigInput s o _ _) -> (s,o)) sigis++testMergeTx :: ArbitraryPartialTxs -> Bool+testMergeTx (ArbitraryPartialTxs txs os) = and+    [ isRight mergeRes+    , length (txIn mergedTx) == length os+    , if enoughSigs then isValid else not isValid+    -- Signature count == min (length txs) (sum required signatures)+    , sum (map snd sigMap) == min (length txs) (sum (map fst sigMap))+    ]+  where+    outs = map (\(so, op, _, _) -> (so, op)) os+    mergeRes = mergeTxs txs outs+    mergedTx = fromRight mergeRes+    isValid = verifyStdTx mergedTx outs+    enoughSigs = and $ map (\(m,c) -> c >= m) sigMap+    sigMap = map (\((_,_,m,_), inp) -> (m, sigCnt inp)) $ zip os $ txIn mergedTx+    sigCnt inp = case decodeInputBS $ scriptInput inp of+        Right (RegularInput (SpendMulSig sigs)) -> length sigs+        Right (ScriptHashInput (SpendMulSig sigs) _) -> length sigs+        _ -> error "Invalid input script type"+
+ tests/Network/Haskoin/Transaction/Units.hs view
@@ -0,0 +1,247 @@+{-# LANGUAGE OverloadedStrings #-}+module Network.Haskoin.Transaction.Units (tests) where++import Test.HUnit (Assertion, assertBool)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)++import Data.Word (Word32, Word64)+import Data.Maybe (fromJust)+import Data.Binary.Get (getWord32le)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS (reverse)++import Network.Haskoin.Transaction+import Network.Haskoin.Script+import Network.Haskoin.Util++tests :: [Test]+tests =+    [ testGroup "Computing TxID from Tx"+        ( map mapTxIDVec $ zip txIDVec [0..] )+    , testGroup "Build PKHash Transaction (generated from bitcoind)"+        ( map mapPKHashVec $ zip pkHashVec [0..] )+    , testGroup "Verify transaction (bitcoind /test/data/tx_valid.json)"+        ( map mapVerifyVec $ zip verifyVec [0..] )+    ]++mapTxIDVec :: ((ByteString, ByteString), Int) -> Test.Framework.Test+mapTxIDVec (v,i) = testCase name $ runTxIDVec v+  where+    name = "Compute TxID " ++ (show i)++runTxIDVec :: (ByteString, ByteString) -> Assertion+runTxIDVec (tid,tx) = assertBool "TxID" $+    (txHashToHex $ txHash txBS) == tid+  where+    txBS = decode' $ fromJust $ decodeHex tx++txIDVec :: [(ByteString, ByteString)]+txIDVec =+    [ ( "23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"+      , "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"+      )+    , ( "c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"+      , "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000"+      )+    , ( "f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"+      , "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000"+      )+    , ( "afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae"+      , "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"+      )+    ]++mapPKHashVec :: (([(ByteString, Word32)], [(ByteString, Word64)], ByteString), Int)+            -> Test.Framework.Test+mapPKHashVec (v, i) = testCase name $ runPKHashVec v+    where name = "Build PKHash Tx " ++ (show i)++runPKHashVec :: ([(ByteString, Word32)], [(ByteString, Word64)], ByteString) -> Assertion+runPKHashVec (xs, ys, res) =+    assertBool "Build PKHash Tx" $ (encodeHex $ encode' tx) == res+    where tx = fromRight $ buildAddrTx (map f xs) ys+          f (tid,ix) = OutPoint (fromJust $ hexToTxHash tid) ix+++mapVerifyVec :: (([(ByteString, ByteString, ByteString)], ByteString), Int)+             -> Test.Framework.Test+mapVerifyVec (v, i) = testCase name $ runVerifyVec v i+    where name = "Verify Tx " ++ (show i)++runVerifyVec :: ([(ByteString, ByteString, ByteString)], ByteString) -> Int -> Assertion+runVerifyVec (is, bsTx) i =+    assertBool name $ verifyStdTx tx $ map f is+  where+    name = "    > Verify transaction " ++ (show i)+    tx  = decode' (fromJust $ decodeHex bsTx)+    f (o1, o2, bsScript) =+        let s = fromRight $ decodeOutputBS $ fromJust $ decodeHex $ bsScript+            op = OutPoint+                (decode' $ BS.reverse $ fromJust $ decodeHex o1)+                (runGet' getWord32le $ fromJust $ decodeHex o2)+        in (s, op)++-- These test vectors have been generated from bitcoind raw transaction api++pkHashVec :: [([(ByteString, Word32)], [(ByteString, Word64)], ByteString)]+pkHashVec =+    [+      ( [("eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db",14)]+      , [("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb",90000000)]+      , "0100000001db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a1eb29eb0e00000000ffffffff01804a5d05000000001976a91424aa604689cc582292b97668bedd91dd5bf9374c88ac00000000"+      )+    , ( [ ("eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db",0)+        , ("0001000000000000000000000000000000000000000000000000000000000000",2147483647)+        ]+      , [ ("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb",1)+        , ("19VCgS642vzEA1sdByoSn6GsWBwraV8D4n",2100000000000000)+        ]+      , "0100000002db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a1eb29eb0000000000ffffffff0000000000000000000000000000000000000000000000000000000000000100ffffff7f00ffffffff0201000000000000001976a91424aa604689cc582292b97668bedd91dd5bf9374c88ac0040075af07507001976a9145d16672f53981ff21c5f42b40d1954993cbca54f88ac00000000"+      )+    , ( [ ("eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db",0)+        , ("0001000000000000000000000000000000000000000000000000000000000000",2147483647)+        ]+      , []+      , "0100000002db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a1eb29eb0000000000ffffffff0000000000000000000000000000000000000000000000000000000000000100ffffff7f00ffffffff0000000000"+      )+    , ( []+      , [ ("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb",1)+        , ("19VCgS642vzEA1sdByoSn6GsWBwraV8D4n",2100000000000000)+        ]+      , "01000000000201000000000000001976a91424aa604689cc582292b97668bedd91dd5bf9374c88ac0040075af07507001976a9145d16672f53981ff21c5f42b40d1954993cbca54f88ac00000000"+      )+    ]++{- Test vectors from bitcoind -}+-- github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json++verifyVec :: [([(ByteString, ByteString, ByteString)], ByteString)]+verifyVec =+    [+      -- It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts+      ( [+          ( "60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1"+          , "00000000"+          , "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae"+          )+        ]+      , "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"+      )+      -- It has an arbitrary extra byte stuffed into the signature at pos length - 2+    , ( [+          ( "60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1"+          , "00000000"+          , "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae"+          )+        ]+      , "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004A0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"+      )+      -- it is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)+    , ( [+          ( "406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602"+          , "00000000"+          , "76a914dc44b1164188067c3a32d4780f5996fa14a4f2d988ac"+          )+        ]+      , "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000"+      )+      -- It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation+    , ( [+          ( "b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d"+          , "00000000"+          , "76a914bef80ecf3a44500fda1bc92176e442891662aed288ac"+          )+        , ( "b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21"+          , "01000000"+          , "76a914bef80ecf3a44500fda1bc92176e442891662aed288ac"+          )+        ]+      , "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000"+      )+      -- It results in signing the constant 1, instead of something generated based on the transaction,+      -- when the input doing the signing has an index greater than the maximum output index+    , ( [+          ( "0000000000000000000000000000000000000000000000000000000000000100"+          , "00000000"+          , "76a914e52b482f2faa8ecbf0db344f93c84ac908557f3388ac"+          )+        , ( "0000000000000000000000000000000000000000000000000000000000000200"+          , "00000000"+          , "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac"+          )+        ]+        , "01000000020002000000000000000000000000000000000000000000000000000000000000000000006a47304402200469f169b8091cd18a2770136be7411f079b3ac2b5c199885eb66a80aa3ed75002201fa89f3e6f80974e1b3474e70a0fbe907c766137ff231e4dd05a555d8544536701210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000"+      )+      -- A valid P2SH Transaction using the standard transaction type put forth in BIP 16+    , ( [+          ( "0000000000000000000000000000000000000000000000000000000000000100"+          , "00000000"+          , "a9148febbed40483661de6958d957412f82deed8e2f787"+          )+        ]+      , "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000"+      )+      -- MAX_MONEY output+    , ( [+          ( "0000000000000000000000000000000000000000000000000000000000000100"+          , "00000000"+          , "a91432afac281462b822adbec5094b8d4d337dd5bd6a87"+          )+        ]+      , "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000"+      )+      -- MAX_MONEY output + 0 output+    , ( [+          ( "0000000000000000000000000000000000000000000000000000000000000100"+          , "00000000"+          , "a914b558cbf4930954aa6a344363a15668d7477ae71687"+          )+        ]+      , "01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000"+      )+      -- Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY+    , ( [+          ( "0000000000000000000000000000000000000000000000000000000000000100"+          , "00000000"+          , "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac"+          )+        , ( "0000000000000000000000000000000000000000000000000000000000000200"+          , "00000000"+          , "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac"+          )+        ]+      , "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000"+      )+      -- Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed+    , ( [+          ( "0000000000000000000000000000000000000000000000000000000000000100"+          , "00000000"+          , "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac"+          )+        , ( "0000000000000000000000000000000000000000000000000000000000000200"+          , "00000000"+          , "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac"+          )+        ]+      , "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000"+      )+      -- several SIGHASH_SINGLE signatures+    , ( [+          ( "63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70"+          , "00000000"+          , "76a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88ac"+          )+        , ( "04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d"+          , "01000000"+          , "76a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88ac"+          )+        , ( "ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f"+          , "01000000"+          , "76a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88ac"+          )+        ]+      , "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"+      )+    ]+
+ tests/Network/Haskoin/Util/Tests.hs view
@@ -0,0 +1,77 @@+module Network.Haskoin.Util.Tests (tests) where++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)++import Data.List (permutations)+import Data.Maybe (fromJust, catMaybes)+import Data.Foldable (toList)+import qualified Data.Sequence as Seq (update, fromList)++import Network.Haskoin.Test+import Network.Haskoin.Util++tests :: [Test]+tests =+    [ testGroup "Utility functions"+        [ testProperty "bsToInteger . integerToBS" getPutInteger+        , testProperty "decodeOrFail' . encode'" decEncFailBS+        , testProperty "decodeHex . encodeHex" fromToHex+        , testProperty "fromDecode" testFromDecode+        , testProperty "compare updateIndex with Data.Sequence" testUpdateIndex+        , testProperty "matchTemplate" testMatchTemplate+        , testProperty+            "testing matchTemplate with two lists" testMatchTemplateLen+        , testProperty "Testing Either helper functions" testEither+        ]+    ]++{- Various utilities -}++decEncFailBS :: ArbitraryByteString -> Bool+decEncFailBS (ArbitraryByteString bs) = case (decodeOrFail' $ encode' bs) of+    (Left _)            -> False+    (Right (_, _, res)) -> res == bs++getPutInteger :: Integer -> Bool+getPutInteger i = (bsToInteger $ integerToBS p) == p+  where+    p = abs i++fromToHex :: ArbitraryByteString -> Bool+fromToHex (ArbitraryByteString bs) = (fromJust $ decodeHex $ encodeHex bs) == bs++testFromDecode :: ArbitraryByteString -> Integer -> Integer -> Bool+testFromDecode (ArbitraryByteString bs) def v = case decodeOrFail' bs of+    (Left _)          -> fromDecode bs def (*v) == def+    (Right (_,_,res)) -> fromDecode bs def (*v) == res*v++testUpdateIndex :: [Int] -> Int -> Int -> Bool+testUpdateIndex xs v i =+    (updateIndex i xs $ const v) == (toList $ Seq.update i v s)+  where+    s = Seq.fromList xs++testMatchTemplate :: [Int] -> Int -> Bool+testMatchTemplate as i = catMaybes res == bs+  where+    res = matchTemplate as bs (==)+    idx = if length as == 0 then 0 else i `mod` length as+    bs  = (permutations as) !! idx++testMatchTemplateLen :: [Int] -> [Int] -> Bool+testMatchTemplateLen as bs = length bs == length res+  where+    res = matchTemplate as bs (==)++testEither :: Either String Int -> Bool+testEither e = case e of+    (Right v) -> (isRight e)+              && (not $ isLeft e)+              && (fromRight e == v)+              && (eitherToMaybe e == Just v)+    (Left v)  -> (isLeft e)+              && (not $ isRight e)+              && (fromLeft e == v)+              && (eitherToMaybe e == Nothing)+
+ tests/data/script_invalid.json view
@@ -0,0 +1,598 @@+[+["+Format is: [scriptPubKey, scriptSig, flags, ... comments]+It is evaluated as if there was a crediting coinbase transaction with two 0+pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,+followed by a spending transaction which spends this output as only input (and+correct prevout hash), using the given scriptSig. All nLockTimes are 0, all+nSequences are max.+"],++["", "DEPTH", "P2SH,STRICTENC",   "Test the test: we should have an empty stack after scriptSig evaluation"],+["  ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that."],+["   ", "DEPTH", "P2SH,STRICTENC"],+["    ", "DEPTH", "P2SH,STRICTENC"],++["", "", "P2SH,STRICTENC"],+["", "NOP", "P2SH,STRICTENC"],+["", "NOP DEPTH", "P2SH,STRICTENC"],+["NOP", "", "P2SH,STRICTENC"],+["NOP", "DEPTH", "P2SH,STRICTENC"],+["NOP","NOP", "P2SH,STRICTENC"],+["NOP","NOP DEPTH", "P2SH,STRICTENC"],++["DEPTH", "", "P2SH,STRICTENC"],++["0x4c01","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA1 with not enough bytes"],+["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA2 with not enough bytes"],+["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA4 with not enough bytes"],++["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved"],+["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"],+["0","NOP", "P2SH,STRICTENC"],+["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional"],+["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"],+["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"],+["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"],+["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"],++["1 IF", "1 ENDIF", "P2SH,STRICTENC", "IF/ENDIF can't span scriptSig/scriptPubKey"],+["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC"],+["1 ELSE 0 ENDIF", "1", "P2SH,STRICTENC"],+["0 NOTIF", "123", "P2SH,STRICTENC"],++["0", "DUP IF ENDIF", "P2SH,STRICTENC"],+["0", "IF 1 ENDIF", "P2SH,STRICTENC"],+["0", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"],+["0", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"],+["0", "NOTIF ELSE 1 ENDIF", "P2SH,STRICTENC"],++["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],+["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],+["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],+["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],++["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],+["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],+["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],+["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],++["1", "IF RETURN ELSE ELSE 1 ENDIF", "P2SH,STRICTENC", "Multiple ELSEs"],+["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC"],++["1", "ENDIF", "P2SH,STRICTENC", "Malformed IF/ELSE/ENDIF sequence"],+["1", "ELSE ENDIF", "P2SH,STRICTENC"],+["1", "ENDIF ELSE", "P2SH,STRICTENC"],+["1", "ENDIF ELSE IF", "P2SH,STRICTENC"],+["1", "IF ELSE ENDIF ELSE", "P2SH,STRICTENC"],+["1", "IF ELSE ENDIF ELSE ENDIF", "P2SH,STRICTENC"],+["1", "IF ENDIF ENDIF", "P2SH,STRICTENC"],+["1", "IF ELSE ELSE ENDIF ENDIF", "P2SH,STRICTENC"],++["1", "RETURN", "P2SH,STRICTENC"],+["1", "DUP IF RETURN ENDIF", "P2SH,STRICTENC"],++["1", "RETURN 'data'", "P2SH,STRICTENC", "canonical prunable txout format"],+["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"],++["0", "VERIFY 1", "P2SH,STRICTENC"],+["1", "VERIFY", "P2SH,STRICTENC"],+["1", "VERIFY 0", "P2SH,STRICTENC"],++["1 TOALTSTACK", "FROMALTSTACK 1", "P2SH,STRICTENC", "alt stack not shared between sig/pubkey"],++["IFDUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["DUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"],+["NOP", "NIP", "P2SH,STRICTENC"],+["NOP", "1 NIP", "P2SH,STRICTENC"],+["NOP", "1 0 NIP", "P2SH,STRICTENC"],+["NOP", "OVER 1", "P2SH,STRICTENC"],+["1", "OVER", "P2SH,STRICTENC"],+["0 1", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"],+["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],+["NOP", "0 PICK", "P2SH,STRICTENC"],+["1", "-1 PICK", "P2SH,STRICTENC"],+["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"],+["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"],+["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"],+["NOP", "0 ROLL", "P2SH,STRICTENC"],+["1", "-1 ROLL", "P2SH,STRICTENC"],+["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],+["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],+["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],+["NOP", "ROT 1", "P2SH,STRICTENC"],+["NOP", "1 ROT 1", "P2SH,STRICTENC"],+["NOP", "1 2 ROT 1", "P2SH,STRICTENC"],+["NOP", "0 1 2 ROT", "P2SH,STRICTENC"],+["NOP", "SWAP 1", "P2SH,STRICTENC"],+["1", "SWAP 1", "P2SH,STRICTENC"],+["0 1", "SWAP 1 EQUALVERIFY", "P2SH,STRICTENC"],+["NOP", "TUCK 1", "P2SH,STRICTENC"],+["1", "TUCK 1", "P2SH,STRICTENC"],+["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"],+["NOP", "2DUP 1", "P2SH,STRICTENC"],+["1", "2DUP 1", "P2SH,STRICTENC"],+["NOP", "3DUP 1", "P2SH,STRICTENC"],+["1", "3DUP 1", "P2SH,STRICTENC"],+["1 2", "3DUP 1", "P2SH,STRICTENC"],+["NOP", "2OVER 1", "P2SH,STRICTENC"],+["1", "2 3 2OVER 1", "P2SH,STRICTENC"],+["NOP", "2SWAP 1", "P2SH,STRICTENC"],+["1", "2 3 2SWAP 1", "P2SH,STRICTENC"],++["'a' 'b'", "CAT", "P2SH,STRICTENC", "CAT disabled"],+["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "CAT disabled"],+["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "SUBSTR disabled"],+["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "SUBSTR disabled"],+["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "LEFT disabled"],+["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "RIGHT disabled"],++["NOP", "SIZE 1", "P2SH,STRICTENC"],++["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "INVERT disabled"],+["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "AND disabled"],+["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "OR disabled"],+["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "XOR disabled"],+["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2MUL disabled"],+["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2DIV disabled"],+["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MUL disabled"],+["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DIV disabled"],+["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MOD disabled"],+["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "LSHIFT disabled"],+["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "RSHIFT disabled"],++["0 1","EQUAL", "P2SH,STRICTENC"],+["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC"],+["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC"],++["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "],+["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "],+["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "NUMEQUAL must be in numeric range"],+["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "NOT is an arithmetic operand"],++["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"],+["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"],+["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"],+["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"],+["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "disabled"],+["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled"],+["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled"],++["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"],+["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"],++["Ensure 100% coverage of discouraged NOPS"],+["1", "NOP1",  "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],+["1", "NOP2",  "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],+["1", "NOP3",  "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],+["1", "NOP4",  "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],+["1", "NOP5",  "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],+["1", "NOP6",  "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],+["1", "NOP7",  "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],+["1", "NOP8",  "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],+["1", "NOP9",  "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],+["1", "NOP10", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],++["NOP10", "1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in scriptSig"],++["1 0x01 0xb9", "HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL",+ "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"],++["0x50","1", "P2SH,STRICTENC", "opcode 0x50 is reserved"],+["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"],+["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"],++["1 IF 1 ELSE", "0xff ENDIF", "P2SH,STRICTENC", "invalid because scriptSig and scriptPubKey are processed separately"],++["NOP", "RIPEMD160", "P2SH,STRICTENC"],+["NOP", "SHA1", "P2SH,STRICTENC"],+["NOP", "SHA256", "P2SH,STRICTENC"],+["NOP", "HASH160", "P2SH,STRICTENC"],+["NOP", "HASH256", "P2SH,STRICTENC"],++["NOP",+"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'",+"P2SH,STRICTENC",+">520 byte push"],+["0",+"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1",+"P2SH,STRICTENC",+">520 byte push in non-executed IF branch"],+["1",+"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",+"P2SH,STRICTENC",+">201 opcodes executed. 0x61 is NOP"],+["0",+"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1",+"P2SH,STRICTENC",+">201 opcodes including non-executed IF branch. 0x61 is NOP"],+["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+"P2SH,STRICTENC",+">1,000 stack size (0x6f is 3DUP)"],+["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+"P2SH,STRICTENC",+">1,000 stack+altstack size"],+["NOP",+"0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",+"P2SH,STRICTENC",+"10,001-byte scriptPubKey"],++["NOP1","NOP10", "P2SH,STRICTENC"],++["1","VER", "P2SH,STRICTENC", "OP_VER is reserved"],+["1","VERIF", "P2SH,STRICTENC", "OP_VERIF is reserved"],+["1","VERNOTIF", "P2SH,STRICTENC", "OP_VERNOTIF is reserved"],+["1","RESERVED", "P2SH,STRICTENC", "OP_RESERVED is reserved"],+["1","RESERVED1", "P2SH,STRICTENC", "OP_RESERVED1 is reserved"],+["1","RESERVED2", "P2SH,STRICTENC", "OP_RESERVED2 is reserved"],+["1","0xba", "P2SH,STRICTENC", "0xba == OP_NOP10 + 1"],++["2147483648", "1ADD 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"],+["2147483648", "NEGATE 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"],+["-2147483648", "1ADD 1", "P2SH,STRICTENC", "Because we use a sign bit, -2147483648 is also 5 bytes"],+["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"],+["2147483648", "1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"],++["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"],+["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "We cannot do BOOLAND on 5-byte integers"],++["1", "1 ENDIF", "P2SH,STRICTENC", "ENDIF without IF"],+["1", "IF 1", "P2SH,STRICTENC", "IF without ENDIF"],+["1 IF 1", "ENDIF", "P2SH,STRICTENC", "IFs don't carry over"],++["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"],+["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"],+["NOP", "VERIFY 1", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"],++["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"],+["1", "FROMALTSTACK", "P2SH,STRICTENC"],+["1", "2DROP 1", "P2SH,STRICTENC"],+["1", "2DUP", "P2SH,STRICTENC"],+["1 1", "3DUP", "P2SH,STRICTENC"],+["1 1 1", "2OVER", "P2SH,STRICTENC"],+["1 1 1 1 1", "2ROT", "P2SH,STRICTENC"],+["1 1 1", "2SWAP", "P2SH,STRICTENC"],+["NOP", "IFDUP 1", "P2SH,STRICTENC"],+["NOP", "DROP 1", "P2SH,STRICTENC"],+["NOP", "DUP 1", "P2SH,STRICTENC"],+["1", "NIP", "P2SH,STRICTENC"],+["1", "OVER", "P2SH,STRICTENC"],+["1 1 1 3", "PICK", "P2SH,STRICTENC"],+["0", "PICK 1", "P2SH,STRICTENC"],+["1 1 1 3", "ROLL", "P2SH,STRICTENC"],+["0", "ROLL 1", "P2SH,STRICTENC"],+["1 1", "ROT", "P2SH,STRICTENC"],+["1", "SWAP", "P2SH,STRICTENC"],+["1", "TUCK", "P2SH,STRICTENC"],++["NOP", "SIZE 1", "P2SH,STRICTENC"],++["1", "EQUAL 1", "P2SH,STRICTENC"],+["1", "EQUALVERIFY 1", "P2SH,STRICTENC"],++["NOP", "1ADD 1", "P2SH,STRICTENC"],+["NOP", "1SUB 1", "P2SH,STRICTENC"],+["NOP", "NEGATE 1", "P2SH,STRICTENC"],+["NOP", "ABS 1", "P2SH,STRICTENC"],+["NOP", "NOT 1", "P2SH,STRICTENC"],+["NOP", "0NOTEQUAL 1", "P2SH,STRICTENC"],++["1", "ADD", "P2SH,STRICTENC"],+["1", "SUB", "P2SH,STRICTENC"],+["1", "BOOLAND", "P2SH,STRICTENC"],+["1", "BOOLOR", "P2SH,STRICTENC"],+["1", "NUMEQUAL", "P2SH,STRICTENC"],+["1", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"],+["1", "NUMNOTEQUAL", "P2SH,STRICTENC"],+["1", "LESSTHAN", "P2SH,STRICTENC"],+["1", "GREATERTHAN", "P2SH,STRICTENC"],+["1", "LESSTHANOREQUAL", "P2SH,STRICTENC"],+["1", "GREATERTHANOREQUAL", "P2SH,STRICTENC"],+["1", "MIN", "P2SH,STRICTENC"],+["1", "MAX", "P2SH,STRICTENC"],+["1 1", "WITHIN", "P2SH,STRICTENC"],++["NOP", "RIPEMD160 1", "P2SH,STRICTENC"],+["NOP", "SHA1 1", "P2SH,STRICTENC"],+["NOP", "SHA256 1", "P2SH,STRICTENC"],+["NOP", "HASH160 1", "P2SH,STRICTENC"],+["NOP", "HASH256 1", "P2SH,STRICTENC"],++["",+"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG",+"P2SH,STRICTENC",+"202 CHECKMULTISIGS, fails due to 201 op limit"],++["1",+"0 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY",+"P2SH,STRICTENC"],++["",+"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG",+"P2SH,STRICTENC",+"Fails due to 201 sig op limit"],++["1",+"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY",+"P2SH,STRICTENC"],+++["0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21", "21 CHECKMULTISIG 1", "P2SH,STRICTENC", "nPubKeys > 20"],+["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "nSigs > nPubKeys"],+++["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Tests for Script.IsPushOnly()"],+["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"],++["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "OP_RESERVED in P2SH should fail"],+["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "OP_VER in P2SH should fail"],++["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],++["MINIMALDATA enforcement for PUSHDATAs"],++["0x4c 0x00", "DROP 1", "MINIMALDATA", "Empty vector minimally represented by OP_0"],+["0x01 0x81", "DROP 1", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE"],+["0x01 0x01", "DROP 1", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16"],+["0x01 0x02", "DROP 1", "MINIMALDATA"],+["0x01 0x03", "DROP 1", "MINIMALDATA"],+["0x01 0x04", "DROP 1", "MINIMALDATA"],+["0x01 0x05", "DROP 1", "MINIMALDATA"],+["0x01 0x06", "DROP 1", "MINIMALDATA"],+["0x01 0x07", "DROP 1", "MINIMALDATA"],+["0x01 0x08", "DROP 1", "MINIMALDATA"],+["0x01 0x09", "DROP 1", "MINIMALDATA"],+["0x01 0x0a", "DROP 1", "MINIMALDATA"],+["0x01 0x0b", "DROP 1", "MINIMALDATA"],+["0x01 0x0c", "DROP 1", "MINIMALDATA"],+["0x01 0x0d", "DROP 1", "MINIMALDATA"],+["0x01 0x0e", "DROP 1", "MINIMALDATA"],+["0x01 0x0f", "DROP 1", "MINIMALDATA"],+["0x01 0x10", "DROP 1", "MINIMALDATA"],++["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",+ "PUSHDATA1 of 72 bytes minimally represented by direct push"],++["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",+ "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"],++["0x4f 0x00100000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",+ "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"],+++["MINIMALDATA enforcement for numeric arguments"],++["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "numequals 0"],+["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "numequals 0"],+["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0"],+["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "numequals 0"],+["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "numequals 5"],+["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "numequals 5"],+["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "numequals -5"],+["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "numequals -5"],+["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff"],+["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xff7f"],+["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffffff"],+["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff7f"],++["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"],++["1 0x02 0x0000", "PICK DROP", "MINIMALDATA"],+["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA"],+["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA"],+["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA"],+["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA"],+["0x02 0x0000", "ABS DROP 1", "MINIMALDATA"],+["0x02 0x0000", "NOT DROP 1", "MINIMALDATA"],+["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA"],++["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA"],+["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA"],+["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA"],+["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA"],+["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA"],+["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA"],++["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA"],+["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA"],+["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA"],++["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA"],+["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA"],+["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA"],+["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"],+["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"],+++[+    "0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001",+    "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",+    "",+    "P2PK, bad sig"+],+[+    "0x47 0x3044022037fcdb8e08f41e27588de8bc036d2c4b16eb3d09c1ba53b8f47a0a9c27722a39022058664b7a53b507e71dfafb77193e3786c3f0c119d78ce9104480ee7ece04f09301 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640",+    "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG",+    "",+    "P2PKH, bad pubkey"+],+[+    "0x47 0x3044022035e5b6742d299861c84cebaf2ea64145ee427a95facab39e2594d6deebb0c1d602200acb16778faa2e467a59006f342f2535b1418d55ba63a8605b387b7f9ac86d9a01",+    "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",+    "",+    "P2PK anyonecanpay marked with normal hashtype"+],+[+    "0x47 0x3044022029b2b8765ca950cf75a69e80b73b7ddfcaa8b27080c2db4c23b36aae60688e790220598ff368e17872ee065aa54d7d3a590682ca5204325b23b31d7da3c4a21ae67901 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",+    "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",+    "P2SH",+    "P2SH(P2PK), bad redeemscript"+],+[+    "0x47 0x30440220647f906e63890df5ef1d3fed47ba892b31976c634281079e2bd38504fb54a1fb022021e8811f38fbe90efb6b74cb78da01d9badbac3bafdf70a861d7538a220d0b2601 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",+    "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",+    "P2SH",+    "P2SH(P2PKH), bad sig"+],+[+    "0 0x47 0x304402203ef170402f8887f2ac183f31b1f503b0bc60bfc968dd469b097ea6124aefac5002200612febadc4e4cacc086982cb85830a17af3680c1b6a3cf77c1708af7621cf1301 0 0x47 0x304402207821838251a24a2234844f68e7169e6d11945cdf052ea12bd3e4e37457aceb4402200b6b46c81361e314c740ae5133c072af5fa5c209d65d2db1679e1716f19a538101",+    "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",+    "",+    "3-of-3, 2 sigs"+],+[+    "0 0 0x47 0x304402204661f7795e8db7be3132e8974e9a76d1d24b31f23df94c6fbcea07d1c205789102203f5e45a1c0b085279b58d11b36d5fea5449c3cf16f844ad10124e9b65e8777d201 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",+    "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",+    "P2SH",+    "P2SH(2-of-3), 1 sig"+],+[+    "0x47 0x30440220005d727e2a82d6e8a98a6da6fbc281325644d1a40455e386fdb17883a8e6bc4d02202d15cca42ce136047a980d288e60c679d7e84cce18c3ceffb6bc81b9e9ba517801",+    "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",+    "",+    "P2PK NOT with too much R padding but no DERSIG"+],+[+    "0x47 0x30440220006e8bc4f82032b12bd594847c16d8b2986de734aa3b0528bd89d664d41e6d1c02200cfd582694891bcfa2e630e899bda257486eba00a007222fae71144dba07dc2901",+    "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",+    "DERSIG",+    "P2PK NOT with too much R padding"+],+[+    "0x47 0x304402203aab50cd7c30cc1e1475dee615b295bcee6ccf8aa8a7f6cda6b696c70d79cbb40220558e43fe7596c31146e2d077698d5a9c38351d8ba567549a2ae43ca97231c39501",+    "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",+    "STRICTENC",+    "P2PK with hybrid pubkey"+],++["+Order of CHECKMULTISIG evaluation tests, inverted by swapping the order of+pubkeys/signatures so they fail due to the STRICTENC rules on validly encoded+signatures and pubkeys.+"],++[+    "0x01 0x01 0x47 0x304402200e48ba1cf4d7182db94ffb57bd72ea31b5545dc0d1c512e665779b4fb2badc52022054b8388dfc074c708a75b62359b7be46402751ee40c0a111aef38a837b6ed09801 0x47 0x304402201c9820f59c49107bb30e6175cfc9ec95f897b03beb628b4bc854d2b80392aa0602200235d986ae418bcd111b8814f4c26a0ab5f475fb542a44884fc14912a97a252301 0x47 0x304402204cd7894c6f10a871f5b0c1f9c13228f8cdd4050248f0d0f498ee86be69ee3080022051bd2932c7d585eb600c7194235c74da820935f0d67972fd9545673aa1fd023301",+    "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",+    "NULLDUMMY",+    "3-of-3 with nonzero dummy"+],+[+    "0x01 0x01 0x47 0x304402201847fc3b8f7597768e7f543c58da1fca6e8e35eb28979431e6b637572ce6eaa4022048dd58608e040841d0bf52a70cfb70e1a9c8d2826fad068f4e9d2bf5c87766a501 0x47 0x30440220711311a72516affed73363763983d05c3d6a06a2eadf5d76b90b4354162ba94302204841a69e5955a7dc8e4ab3105fd0c86040c1dac6016297a51ddbf5079c28756801 0x47 0x30440220267e331a378191e7282fd10d61c97bf74bc97c233c5833d677936424ac08dee502201eee83d88b91988e1c4d9b979df2404aa190e0987a8ca09c4e5cd61da1d48ecc01",+    "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",+    "NULLDUMMY",+    "3-of-3 NOT with invalid sig with nonzero dummy"+],+[+    "0 0x47 0x3044022035341cc377b19138f944f90c45772cb06338c6d56a4c0c31a65bf1a8a105fadc022046dd232850b6bacb25879c9da82a7a628982aa19d055f1753468f68047662e0301 DUP",+    "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",+    "SIGPUSHONLY",+    "2-of-2 with two identical keys and sigs pushed using OP_DUP"+],+[+    "0x47 0x304402204d8b99eea2f53382fd67e0dbc8ed0596bd614aa0dad6bc6843c7860c79b901c3022062f022a71993013e3d9b22302a8e4b40109d7bb057aeb250b9aab2197b3e96b801 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",+    "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",+    "",+    "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY"+],+[+    "0x47 0x30440220078c887c33abc67fbbd827ceb3f661c1c459e78218161b652f23e3ca76cfabbd022047df245eacb8a88d8c5ca7b5228e3b4d070c102d2f542433362d3f443cd24eda01 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",+    "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",+    "SIGPUSHONLY",+    "P2SH(P2PK) with non-push scriptSig"+],++["The End"]+]
+ tests/data/script_valid.json view
@@ -0,0 +1,821 @@+[+["+Format is: [scriptPubKey, scriptSig, flags, ... comments]+It is evaluated as if there was a crediting coinbase transaction with two 0+pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey,+followed by a spending transaction which spends this output as only input (and+correct prevout hash), using the given scriptSig. All nLockTimes are 0, all+nSequences are max.+"],++["", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"],+["  ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "and multiple spaces should not change that."],+["   ", "DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["    ", "DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "Similarly whitespace around and between symbols"],+["1  2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"],+["  1  2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"],+["1  2  ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"],+["  1  2  ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"],++["1", "", "P2SH,STRICTENC"],+["0x02 0x01 0x00", "", "P2SH,STRICTENC", "all bytes are significant, not only the last one"],+["0x09 0x00000000 0x00000000 0x10", "", "P2SH,STRICTENC", "equals zero when cast to Int64"],++["0x01 0x0b", "11 EQUAL", "P2SH,STRICTENC", "push 1 byte"],+["0x02 0x417a", "'Az' EQUAL", "P2SH,STRICTENC"],+["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a",+ "'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "P2SH,STRICTENC", "push 75 bytes"],++["0x4c 0x01 0x07","7 EQUAL", "P2SH,STRICTENC", "0x4c is OP_PUSHDATA1"],+["0x4d 0x0100 0x08","8 EQUAL", "P2SH,STRICTENC", "0x4d is OP_PUSHDATA2"],+["0x4e 0x01000000 0x09","9 EQUAL", "P2SH,STRICTENC", "0x4e is OP_PUSHDATA4"],++["0x4c 0x00","0 EQUAL", "P2SH,STRICTENC"],+["0x4d 0x0000","0 EQUAL", "P2SH,STRICTENC"],+["0x4e 0x00000000","0 EQUAL", "P2SH,STRICTENC"],+["0x4f 1000 ADD","999 EQUAL", "P2SH,STRICTENC"],+["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok if not executed)"],+["0x51", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"],+["1","NOP", "P2SH,STRICTENC"],+["0", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional (ok if not executed)"],+["0", "IF RESERVED RESERVED1 RESERVED2 ELSE 1 ENDIF", "P2SH,STRICTENC", "RESERVED ok in un-executed IF"],++["1", "DUP IF ENDIF", "P2SH,STRICTENC"],+["1", "IF 1 ENDIF", "P2SH,STRICTENC"],+["1", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"],+["1", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"],+["0", "IF ELSE 1 ENDIF", "P2SH,STRICTENC"],++["1 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],+["1 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],+["1 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],+["0 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],++["1 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],+["1 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"],+["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],+["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"],++["0", "IF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "Multiple ELSE's are valid and executed inverts on each ELSE encountered"],+["1", "IF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC"],+["1", "IF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["1", "IF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"],+["'' 1", "IF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL", "P2SH,STRICTENC"],++["1", "NOTIF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "Multiple ELSE's are valid and execution inverts on each ELSE encountered"],+["0", "NOTIF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC"],+["0", "NOTIF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "NOTIF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"],+["'' 0", "NOTIF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL", "P2SH,STRICTENC"],++["0", "IF 1 IF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 1 IF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "Nested ELSE ELSE"],+["1", "NOTIF 0 NOTIF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 0 NOTIF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"],++["0", "IF RETURN ENDIF 1", "P2SH,STRICTENC", "RETURN only works if executed"],++["1 1", "VERIFY", "P2SH,STRICTENC"],+["1 0x05 0x01 0x00 0x00 0x00 0x00", "VERIFY", "P2SH,STRICTENC", "values >4 bytes can be cast to boolean"],++["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL", "P2SH,STRICTENC"],+["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL", "P2SH,STRICTENC"],++["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"],+["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"],+["0 DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["0", "DUP 1 ADD 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"],+["0 1", "NIP", "P2SH,STRICTENC"],+["1 0", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"],+["22 21 20", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "ROT 22 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "ROT DROP 20 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "ROT DROP DROP 21 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "ROT ROT 21 EQUAL", "P2SH,STRICTENC"],+["22 21 20", "ROT ROT ROT 20 EQUAL", "P2SH,STRICTENC"],+["25 24 23 22 21 20", "2ROT 24 EQUAL", "P2SH,STRICTENC"],+["25 24 23 22 21 20", "2ROT DROP 25 EQUAL", "P2SH,STRICTENC"],+["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL", "P2SH,STRICTENC"],+["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL", "P2SH,STRICTENC"],+["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL", "P2SH,STRICTENC"],+["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL", "P2SH,STRICTENC"],+["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL", "P2SH,STRICTENC"],+["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL", "P2SH,STRICTENC"],+["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"],+["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"],+["13 14", "2DUP ROT EQUALVERIFY EQUAL", "P2SH,STRICTENC"],+["-1 0 1 2", "3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY", "P2SH,STRICTENC"],+["1 2 3 5", "2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL", "P2SH,STRICTENC"],+["1 3 5 7", "2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL", "P2SH,STRICTENC"],+["0", "SIZE 0 EQUAL", "P2SH,STRICTENC"],+["1", "SIZE 1 EQUAL", "P2SH,STRICTENC"],+["127", "SIZE 1 EQUAL", "P2SH,STRICTENC"],+["128", "SIZE 2 EQUAL", "P2SH,STRICTENC"],+["32767", "SIZE 2 EQUAL", "P2SH,STRICTENC"],+["32768", "SIZE 3 EQUAL", "P2SH,STRICTENC"],+["8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC"],+["8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC"],+["2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC"],+["2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC"],+["549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC"],+["549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC"],+["9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC"],+["-1", "SIZE 1 EQUAL", "P2SH,STRICTENC"],+["-127", "SIZE 1 EQUAL", "P2SH,STRICTENC"],+["-128", "SIZE 2 EQUAL", "P2SH,STRICTENC"],+["-32767", "SIZE 2 EQUAL", "P2SH,STRICTENC"],+["-32768", "SIZE 3 EQUAL", "P2SH,STRICTENC"],+["-8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC"],+["-8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC"],+["-2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC"],+["-2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC"],+["-549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC"],+["-549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC"],+["-9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC"],+["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL", "P2SH,STRICTENC"],++["42", "SIZE 1 EQUALVERIFY 42 EQUAL", "P2SH,STRICTENC", "SIZE does not consume argument"],++["2 -2 ADD", "0 EQUAL", "P2SH,STRICTENC"],+["2147483647 -2147483647 ADD", "0 EQUAL", "P2SH,STRICTENC"],+["-1 -1 ADD", "-2 EQUAL", "P2SH,STRICTENC"],++["0 0","EQUAL", "P2SH,STRICTENC"],+["1 1 ADD", "2 EQUAL", "P2SH,STRICTENC"],+["1 1ADD", "2 EQUAL", "P2SH,STRICTENC"],+["111 1SUB", "110 EQUAL", "P2SH,STRICTENC"],+["111 1 ADD 12 SUB", "100 EQUAL", "P2SH,STRICTENC"],+["0 ABS", "0 EQUAL", "P2SH,STRICTENC"],+["16 ABS", "16 EQUAL", "P2SH,STRICTENC"],+["-16 ABS", "-16 NEGATE EQUAL", "P2SH,STRICTENC"],+["0 NOT", "NOP", "P2SH,STRICTENC"],+["1 NOT", "0 EQUAL", "P2SH,STRICTENC"],+["11 NOT", "0 EQUAL", "P2SH,STRICTENC"],+["0 0NOTEQUAL", "0 EQUAL", "P2SH,STRICTENC"],+["1 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"],+["111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"],+["-111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"],+["1 1 BOOLAND", "NOP", "P2SH,STRICTENC"],+["1 0 BOOLAND", "NOT", "P2SH,STRICTENC"],+["0 1 BOOLAND", "NOT", "P2SH,STRICTENC"],+["0 0 BOOLAND", "NOT", "P2SH,STRICTENC"],+["16 17 BOOLAND", "NOP", "P2SH,STRICTENC"],+["1 1 BOOLOR", "NOP", "P2SH,STRICTENC"],+["1 0 BOOLOR", "NOP", "P2SH,STRICTENC"],+["0 1 BOOLOR", "NOP", "P2SH,STRICTENC"],+["0 0 BOOLOR", "NOT", "P2SH,STRICTENC"],+["16 17 BOOLOR", "NOP", "P2SH,STRICTENC"],+["11 10 1 ADD", "NUMEQUAL", "P2SH,STRICTENC"],+["11 10 1 ADD", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"],+["11 10 1 ADD", "NUMNOTEQUAL NOT", "P2SH,STRICTENC"],+["111 10 1 ADD", "NUMNOTEQUAL", "P2SH,STRICTENC"],+["11 10", "LESSTHAN NOT", "P2SH,STRICTENC"],+["4 4", "LESSTHAN NOT", "P2SH,STRICTENC"],+["10 11", "LESSTHAN", "P2SH,STRICTENC"],+["-11 11", "LESSTHAN", "P2SH,STRICTENC"],+["-11 -10", "LESSTHAN", "P2SH,STRICTENC"],+["11 10", "GREATERTHAN", "P2SH,STRICTENC"],+["4 4", "GREATERTHAN NOT", "P2SH,STRICTENC"],+["10 11", "GREATERTHAN NOT", "P2SH,STRICTENC"],+["-11 11", "GREATERTHAN NOT", "P2SH,STRICTENC"],+["-11 -10", "GREATERTHAN NOT", "P2SH,STRICTENC"],+["11 10", "LESSTHANOREQUAL NOT", "P2SH,STRICTENC"],+["4 4", "LESSTHANOREQUAL", "P2SH,STRICTENC"],+["10 11", "LESSTHANOREQUAL", "P2SH,STRICTENC"],+["-11 11", "LESSTHANOREQUAL", "P2SH,STRICTENC"],+["-11 -10", "LESSTHANOREQUAL", "P2SH,STRICTENC"],+["11 10", "GREATERTHANOREQUAL", "P2SH,STRICTENC"],+["4 4", "GREATERTHANOREQUAL", "P2SH,STRICTENC"],+["10 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"],+["-11 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"],+["-11 -10", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"],+["1 0 MIN", "0 NUMEQUAL", "P2SH,STRICTENC"],+["0 1 MIN", "0 NUMEQUAL", "P2SH,STRICTENC"],+["-1 0 MIN", "-1 NUMEQUAL", "P2SH,STRICTENC"],+["0 -2147483647 MIN", "-2147483647 NUMEQUAL", "P2SH,STRICTENC"],+["2147483647 0 MAX", "2147483647 NUMEQUAL", "P2SH,STRICTENC"],+["0 100 MAX", "100 NUMEQUAL", "P2SH,STRICTENC"],+["-100 0 MAX", "0 NUMEQUAL", "P2SH,STRICTENC"],+["0 -2147483647 MAX", "0 NUMEQUAL", "P2SH,STRICTENC"],+["0 0 1", "WITHIN", "P2SH,STRICTENC"],+["1 0 1", "WITHIN NOT", "P2SH,STRICTENC"],+["0 -2147483647 2147483647", "WITHIN", "P2SH,STRICTENC"],+["-1 -100 100", "WITHIN", "P2SH,STRICTENC"],+["11 -100 100", "WITHIN", "P2SH,STRICTENC"],+["-2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC"],+["2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC"],++["2147483647 2147483647 SUB", "0 EQUAL", "P2SH,STRICTENC"],+["2147483647 DUP ADD", "4294967294 EQUAL", "P2SH,STRICTENC", ">32 bit EQUAL is valid"],+["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL", "P2SH,STRICTENC"],++["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL", "P2SH,STRICTENC"],+["'a'", "RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL", "P2SH,STRICTENC"],+["'abcdefghijklmnopqrstuvwxyz'", "RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL", "P2SH,STRICTENC"],+["''", "SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL", "P2SH,STRICTENC"],+["'a'", "SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL", "P2SH,STRICTENC"],+["'abcdefghijklmnopqrstuvwxyz'", "SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL", "P2SH,STRICTENC"],+["''", "SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL", "P2SH,STRICTENC"],+["'a'", "SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL", "P2SH,STRICTENC"],+["'abcdefghijklmnopqrstuvwxyz'", "SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL", "P2SH,STRICTENC"],+["''", "DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL", "P2SH,STRICTENC"],+["''", "DUP HASH256 SWAP SHA256 SHA256 EQUAL", "P2SH,STRICTENC"],+["''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL", "P2SH,STRICTENC"],+["'a'", "HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL", "P2SH,STRICTENC"],+["'abcdefghijklmnopqrstuvwxyz'", "HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL", "P2SH,STRICTENC"],+["''", "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL", "P2SH,STRICTENC"],+["'a'", "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL", "P2SH,STRICTENC"],+["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC"],+++["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC"],+["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC"],++["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "Discourage NOPx flag allows OP_NOP"],++["0", "IF NOP10 ENDIF 1", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS",+ "Discouraged NOPs are allowed if not executed"],++["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"],+["0", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"],+["0", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"],++["NOP",+"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'",+"P2SH,STRICTENC",+"520 byte push"],+["1",+"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",+"P2SH,STRICTENC",+"201 opcodes executed. 0x61 is NOP"],+["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+"P2SH,STRICTENC",+"1,000 stack size (0x6f is 3DUP)"],+["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+"1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+"P2SH,STRICTENC",+"1,000 stack size (altstack cleared between scriptSig/scriptPubKey)"],+["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",+"P2SH,STRICTENC",+"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"],++["0",+"IF 0x5050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 ENDIF 1",+"P2SH,STRICTENC",+">201 opcodes, but RESERVED (0x50) doesn't count towards opcode limit."],++["NOP","1", "P2SH,STRICTENC"],++["1", "0x01 0x01 EQUAL", "P2SH,STRICTENC", "The following is useful for checking implementations of BN_bn2mpi"],+["127", "0x01 0x7F EQUAL", "P2SH,STRICTENC"],+["128", "0x02 0x8000 EQUAL", "P2SH,STRICTENC", "Leave room for the sign bit"],+["32767", "0x02 0xFF7F EQUAL", "P2SH,STRICTENC"],+["32768", "0x03 0x008000 EQUAL", "P2SH,STRICTENC"],+["8388607", "0x03 0xFFFF7F EQUAL", "P2SH,STRICTENC"],+["8388608", "0x04 0x00008000 EQUAL", "P2SH,STRICTENC"],+["2147483647", "0x04 0xFFFFFF7F EQUAL", "P2SH,STRICTENC"],+["2147483648", "0x05 0x0000008000 EQUAL", "P2SH,STRICTENC"],+["549755813887", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC"],+["549755813888", "0x06 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC"],+["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC"],+["-1", "0x01 0x81 EQUAL", "P2SH,STRICTENC", "Numbers are little-endian with the MSB being a sign bit"],+["-127", "0x01 0xFF EQUAL", "P2SH,STRICTENC"],+["-128", "0x02 0x8080 EQUAL", "P2SH,STRICTENC"],+["-32767", "0x02 0xFFFF EQUAL", "P2SH,STRICTENC"],+["-32768", "0x03 0x008080 EQUAL", "P2SH,STRICTENC"],+["-8388607", "0x03 0xFFFFFF EQUAL", "P2SH,STRICTENC"],+["-8388608", "0x04 0x00008080 EQUAL", "P2SH,STRICTENC"],+["-2147483647", "0x04 0xFFFFFFFF EQUAL", "P2SH,STRICTENC"],+["-2147483648", "0x05 0x0000008080 EQUAL", "P2SH,STRICTENC"],+["-4294967295", "0x05 0xFFFFFFFF80 EQUAL", "P2SH,STRICTENC"],+["-549755813887", "0x05 0xFFFFFFFFFF EQUAL", "P2SH,STRICTENC"],+["-549755813888", "0x06 0x000000008080 EQUAL", "P2SH,STRICTENC"],+["-9223372036854775807", "0x08 0xFFFFFFFFFFFFFFFF EQUAL", "P2SH,STRICTENC"],++["2147483647", "1ADD 2147483648 EQUAL", "P2SH,STRICTENC", "We can do math on 4-byte integers, and compare 5-byte ones"],+["2147483647", "1ADD 1", "P2SH,STRICTENC"],+["-2147483647", "1ADD 1", "P2SH,STRICTENC"],++["1", "0x02 0x0100 EQUAL NOT", "P2SH,STRICTENC", "Not the same byte array..."],+["1", "0x02 0x0100 NUMEQUAL", "P2SH,STRICTENC", "... but they are numerically equal"],+["11", "0x4c 0x03 0x0b0000 NUMEQUAL", "P2SH,STRICTENC"],+["0", "0x01 0x80 EQUAL NOT", "P2SH,STRICTENC"],+["0", "0x01 0x80 NUMEQUAL", "P2SH,STRICTENC", "Zero numerically equals negative zero"],+["0", "0x02 0x0080 NUMEQUAL", "P2SH,STRICTENC"],+["0x03 0x000080", "0x04 0x00000080 NUMEQUAL", "P2SH,STRICTENC"],+["0x03 0x100080", "0x04 0x10000080 NUMEQUAL", "P2SH,STRICTENC"],+["0x03 0x100000", "0x04 0x10000000 NUMEQUAL", "P2SH,STRICTENC"],++["NOP", "NOP 1", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"],+["1", "IF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"],+["0", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"],+["1", "VERIFY 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"],++["0", "TOALTSTACK 1", "P2SH,STRICTENC"],+["1", "TOALTSTACK FROMALTSTACK", "P2SH,STRICTENC"],+["0 0", "2DROP 1", "P2SH,STRICTENC"],+["0 1", "2DUP", "P2SH,STRICTENC"],+["0 0 1", "3DUP", "P2SH,STRICTENC"],+["0 1 0 0", "2OVER", "P2SH,STRICTENC"],+["0 1 0 0 0 0", "2ROT", "P2SH,STRICTENC"],+["0 1 0 0", "2SWAP", "P2SH,STRICTENC"],+["1", "IFDUP", "P2SH,STRICTENC"],+["NOP", "DEPTH 1", "P2SH,STRICTENC"],+["0", "DROP 1", "P2SH,STRICTENC"],+["1", "DUP", "P2SH,STRICTENC"],+["0 1", "NIP", "P2SH,STRICTENC"],+["1 0", "OVER", "P2SH,STRICTENC"],+["1 0 0 0 3", "PICK", "P2SH,STRICTENC"],+["1 0", "PICK", "P2SH,STRICTENC"],+["1 0 0 0 3", "ROLL", "P2SH,STRICTENC"],+["1 0", "ROLL", "P2SH,STRICTENC"],+["1 0 0", "ROT", "P2SH,STRICTENC"],+["1 0", "SWAP", "P2SH,STRICTENC"],+["0 1", "TUCK", "P2SH,STRICTENC"],++["1", "SIZE", "P2SH,STRICTENC"],++["0 0", "EQUAL", "P2SH,STRICTENC"],+["0 0", "EQUALVERIFY 1", "P2SH,STRICTENC"],++["0", "1ADD", "P2SH,STRICTENC"],+["2", "1SUB", "P2SH,STRICTENC"],+["-1", "NEGATE", "P2SH,STRICTENC"],+["-1", "ABS", "P2SH,STRICTENC"],+["0", "NOT", "P2SH,STRICTENC"],+["-1", "0NOTEQUAL", "P2SH,STRICTENC"],++["1 0", "ADD", "P2SH,STRICTENC"],+["1 0", "SUB", "P2SH,STRICTENC"],+["-1 -1", "BOOLAND", "P2SH,STRICTENC"],+["-1 0", "BOOLOR", "P2SH,STRICTENC"],+["0 0", "NUMEQUAL", "P2SH,STRICTENC"],+["0 0", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"],+["-1 0", "NUMNOTEQUAL", "P2SH,STRICTENC"],+["-1 0", "LESSTHAN", "P2SH,STRICTENC"],+["1 0", "GREATERTHAN", "P2SH,STRICTENC"],+["0 0", "LESSTHANOREQUAL", "P2SH,STRICTENC"],+["0 0", "GREATERTHANOREQUAL", "P2SH,STRICTENC"],+["-1 0", "MIN", "P2SH,STRICTENC"],+["1 0", "MAX", "P2SH,STRICTENC"],+["-1 -1 0", "WITHIN", "P2SH,STRICTENC"],++["0", "RIPEMD160", "P2SH,STRICTENC"],+["0", "SHA1", "P2SH,STRICTENC"],+["0", "SHA256", "P2SH,STRICTENC"],+["0", "HASH160", "P2SH,STRICTENC"],+["0", "HASH256", "P2SH,STRICTENC"],+["NOP", "CODESEPARATOR 1", "P2SH,STRICTENC"],++["NOP", "NOP1 1", "P2SH,STRICTENC"],+["NOP", "NOP2 1", "P2SH,STRICTENC"],+["NOP", "NOP3 1", "P2SH,STRICTENC"],+["NOP", "NOP4 1", "P2SH,STRICTENC"],+["NOP", "NOP5 1", "P2SH,STRICTENC"],+["NOP", "NOP6 1", "P2SH,STRICTENC"],+["NOP", "NOP7 1", "P2SH,STRICTENC"],+["NOP", "NOP8 1", "P2SH,STRICTENC"],+["NOP", "NOP9 1", "P2SH,STRICTENC"],+["NOP", "NOP10 1", "P2SH,STRICTENC"],++["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "CHECKMULTISIG is allowed to have zero keys and/or sigs"],+["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Zero sigs means no sigs are checked"],+["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],++["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "CHECKMULTISIG is allowed to have zero keys and/or sigs"],+["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Zero sigs means no sigs are checked"],+["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],++["", "0 0 'a' 'b' 2 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test from up to 20 pubkeys, all not checked"],+["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 2 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],+["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"],++["",+"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG",+"P2SH,STRICTENC",+"nOpCount is incremented by the number of keys evaluated in addition to the usual one op per op. In this case we have zero keys, so we can execute 201 CHECKMULTISIGS"],++["1",+"0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY",+"P2SH,STRICTENC"],++["",+"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG",+"P2SH,STRICTENC",+"Even though there are no signatures being checked nOpCount is incremented by the number of keys."],++["1",+"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY",+"P2SH,STRICTENC"],++["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Very basic P2SH"],+["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"],++["0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242",+"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL",+"P2SH,STRICTENC",+"Basic PUSH signedness check"],++["0x4c 0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242",+"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL",+"P2SH,STRICTENC",+"Basic PUSHDATA1 signedness check"],++["all PUSHDATA forms are equivalent"],++["0x4c 0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA1 of 75 bytes equals direct push of it"],+["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"],++["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],++["Numeric pushes"],++["0x01 0x81", "0x4f EQUAL", "", "OP1_NEGATE pushes 0x81"],+["0x01 0x01", "0x51 EQUAL", "", "OP_1  pushes 0x01"],+["0x01 0x02", "0x52 EQUAL", "", "OP_2  pushes 0x02"],+["0x01 0x03", "0x53 EQUAL", "", "OP_3  pushes 0x03"],+["0x01 0x04", "0x54 EQUAL", "", "OP_4  pushes 0x04"],+["0x01 0x05", "0x55 EQUAL", "", "OP_5  pushes 0x05"],+["0x01 0x06", "0x56 EQUAL", "", "OP_6  pushes 0x06"],+["0x01 0x07", "0x57 EQUAL", "", "OP_7  pushes 0x07"],+["0x01 0x08", "0x58 EQUAL", "", "OP_8  pushes 0x08"],+["0x01 0x09", "0x59 EQUAL", "", "OP_9  pushes 0x09"],+["0x01 0x0a", "0x5a EQUAL", "", "OP_10 pushes 0x0a"],+["0x01 0x0b", "0x5b EQUAL", "", "OP_11 pushes 0x0b"],+["0x01 0x0c", "0x5c EQUAL", "", "OP_12 pushes 0x0c"],+["0x01 0x0d", "0x5d EQUAL", "", "OP_13 pushes 0x0d"],+["0x01 0x0e", "0x5e EQUAL", "", "OP_14 pushes 0x0e"],+["0x01 0x0f", "0x5f EQUAL", "", "OP_15 pushes 0x0f"],+["0x01 0x10", "0x60 EQUAL", "", "OP_16 pushes 0x10"],++["Equivalency of different numeric encodings"],++["0x02 0x8000", "128 NUMEQUAL", "", "0x8000 equals 128"],+["0x01 0x00", "0 NUMEQUAL", "", "0x00 numequals 0"],+["0x01 0x80", "0 NUMEQUAL", "", "0x80 (negative zero) numequals 0"],+["0x02 0x0080", "0 NUMEQUAL", "", "0x0080 numequals 0"],+["0x02 0x0500", "5 NUMEQUAL", "", "0x0500 numequals 5"],+["0x03 0xff7f80", "0x02 0xffff NUMEQUAL", "", ""],+["0x03 0xff7f00", "0x02 0xff7f NUMEQUAL", "", ""],+["0x04 0xffff7f80", "0x03 0xffffff NUMEQUAL", "", ""],+["0x04 0xffff7f00", "0x03 0xffff7f NUMEQUAL", "", ""],++["Unevaluated non-minimal pushes are ignored"],++["0 IF 0x4c 0x00 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA1 ignored"],+["0 IF 0x4d 0x0000 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA2 ignored"],+["0 IF 0x4c 0x00000000 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA4 ignored"],+["0 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "1NEGATE equiv"],+["0 IF 0x01 0x01 ENDIF 1", "", "MINIMALDATA", "OP_1  equiv"],+["0 IF 0x01 0x02 ENDIF 1", "", "MINIMALDATA", "OP_2  equiv"],+["0 IF 0x01 0x03 ENDIF 1", "", "MINIMALDATA", "OP_3  equiv"],+["0 IF 0x01 0x04 ENDIF 1", "", "MINIMALDATA", "OP_4  equiv"],+["0 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "OP_5  equiv"],+["0 IF 0x01 0x06 ENDIF 1", "", "MINIMALDATA", "OP_6  equiv"],+["0 IF 0x01 0x07 ENDIF 1", "", "MINIMALDATA", "OP_7  equiv"],+["0 IF 0x01 0x08 ENDIF 1", "", "MINIMALDATA", "OP_8  equiv"],+["0 IF 0x01 0x09 ENDIF 1", "", "MINIMALDATA", "OP_9  equiv"],+["0 IF 0x01 0x0a ENDIF 1", "", "MINIMALDATA", "OP_10 equiv"],+["0 IF 0x01 0x0b ENDIF 1", "", "MINIMALDATA", "OP_11 equiv"],+["0 IF 0x01 0x0c ENDIF 1", "", "MINIMALDATA", "OP_12 equiv"],+["0 IF 0x01 0x0d ENDIF 1", "", "MINIMALDATA", "OP_13 equiv"],+["0 IF 0x01 0x0e ENDIF 1", "", "MINIMALDATA", "OP_14 equiv"],+["0 IF 0x01 0x0f ENDIF 1", "", "MINIMALDATA", "OP_15 equiv"],+["0 IF 0x01 0x10 ENDIF 1", "", "MINIMALDATA", "OP_16 equiv"],++["Numeric minimaldata rules are only applied when a stack item is numerically evaluated; the push itself is allowed"],++["0x01 0x00", "1", "MINIMALDATA"],+["0x01 0x80", "1", "MINIMALDATA"],+["0x02 0x0180", "1", "MINIMALDATA"],+["0x02 0x0100", "1", "MINIMALDATA"],+["0x02 0x0200", "1", "MINIMALDATA"],+["0x02 0x0300", "1", "MINIMALDATA"],+["0x02 0x0400", "1", "MINIMALDATA"],+["0x02 0x0500", "1", "MINIMALDATA"],+["0x02 0x0600", "1", "MINIMALDATA"],+["0x02 0x0700", "1", "MINIMALDATA"],+["0x02 0x0800", "1", "MINIMALDATA"],+["0x02 0x0900", "1", "MINIMALDATA"],+["0x02 0x0a00", "1", "MINIMALDATA"],+["0x02 0x0b00", "1", "MINIMALDATA"],+["0x02 0x0c00", "1", "MINIMALDATA"],+["0x02 0x0d00", "1", "MINIMALDATA"],+["0x02 0x0e00", "1", "MINIMALDATA"],+["0x02 0x0f00", "1", "MINIMALDATA"],+["0x02 0x1000", "1", "MINIMALDATA"],++["Valid version of the 'Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule' script_invalid test"],++["1 0x02 0x0000", "PICK DROP", ""],+["1 0x02 0x0000", "ROLL DROP 1", ""],+["0x02 0x0000", "1ADD DROP 1", ""],+["0x02 0x0000", "1SUB DROP 1", ""],+["0x02 0x0000", "NEGATE DROP 1", ""],+["0x02 0x0000", "ABS DROP 1", ""],+["0x02 0x0000", "NOT DROP 1", ""],+["0x02 0x0000", "0NOTEQUAL DROP 1", ""],++["0 0x02 0x0000", "ADD DROP 1", ""],+["0x02 0x0000 0", "ADD DROP 1", ""],+["0 0x02 0x0000", "SUB DROP 1", ""],+["0x02 0x0000 0", "SUB DROP 1", ""],+["0 0x02 0x0000", "BOOLAND DROP 1", ""],+["0x02 0x0000 0", "BOOLAND DROP 1", ""],+["0 0x02 0x0000", "BOOLOR DROP 1", ""],+["0x02 0x0000 0", "BOOLOR DROP 1", ""],+["0 0x02 0x0000", "NUMEQUAL DROP 1", ""],+["0x02 0x0000 1", "NUMEQUAL DROP 1", ""],+["0 0x02 0x0000", "NUMEQUALVERIFY 1", ""],+["0x02 0x0000 0", "NUMEQUALVERIFY 1", ""],+["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", ""],+["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", ""],+["0 0x02 0x0000", "LESSTHAN DROP 1", ""],+["0x02 0x0000 0", "LESSTHAN DROP 1", ""],+["0 0x02 0x0000", "GREATERTHAN DROP 1", ""],+["0x02 0x0000 0", "GREATERTHAN DROP 1", ""],+["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", ""],+["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", ""],+["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", ""],+["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", ""],+["0 0x02 0x0000", "MIN DROP 1", ""],+["0x02 0x0000 0", "MIN DROP 1", ""],+["0 0x02 0x0000", "MAX DROP 1", ""],+["0x02 0x0000 0", "MAX DROP 1", ""],++["0x02 0x0000 0 0", "WITHIN DROP 1", ""],+["0 0x02 0x0000 0", "WITHIN DROP 1", ""],+["0 0 0x02 0x0000", "WITHIN DROP 1", ""],++["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", ""],+["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", ""],+["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", ""],+["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", ""],+["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", ""],+++[+    "0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501",+    "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",+    "",+    "P2PK"+],+[+    "0x47 0x3044022069d40999786aeb2fd874f9eb2636461a062dc963471627ed8390a3a5f9556f640220350132a52415ce622f2aadd07f791c591500917ec1f8c5edbc5381ef7942534d01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508",+    "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG",+    "",+    "P2PKH"+],+[+    "0x47 0x30440220519f2a6632ffa134c7811ea2819e9dcc951f0c7baf461f2dffdd09133f3b080a02203ec6bab5eb6619ed7f41b8701d7c6d70cfc83bb26c5c97f54b2ca6e304fc2bb581",+    "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",+    "",+    "P2PK anyonecanpay"+],+[+    "0x47 0x30440220279dad2170ffb5639f0a1ea71fc462ee37d75d420d86f84c978bac523c09b7f20220683b2789f5c5528a9e0a0d78f6e40db3f616cf1adb5a5fdef117d5974795cfe201 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",+    "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL",+    "P2SH",+    "P2SH(P2PK)"+],+[+    "0x47 0x3044022066acbfb5ac96b7cbf3f05a2aaf358c32438c45d1d7359dee9fc1ee636940735f02205606a03fd8cbf6a6fcbcba60c8abb1e385c0b5753cb57a97538159106fd3684e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",+    "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",+    "",+    "P2SH(P2PKH), bad sig but no VERIFY_P2SH"+],+[+    "0 0x47 0x3044022004e791dd30a64c70e55e84e150c002af9feb3ce0ab1f20e86c53d1209003927502205a60453987fcd72aebaaacebc8ce4b15449cdd79e54cc82cefb83e69dbcfeabf01 0x47 0x304402201d021808ce93dd8574cc4f99ae4f11b44305528b0aecbd9f156f08315173643802200944a0ea5c884bd86180aef76d8b1e444860776b251e47d2d6c651a1c6f9930801 0x47 0x30440220446336d7b7de05ebb5683b82b05248ec7d78e88ae8d6125985f5776c887a4cf90220674ab2b2c2f954ba1cf35457d273c90d0c0c1c224d0ae128628740e81129486801",+    "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",+    "",+    "3-of-3"+],+[+    "0 0x47 0x30440220288b06d057cf0eac434ed0c3be9257cc0ca144dd99c11cc8f1a49467a37d8e8002203c496c72253c528e6bc81c42e683aba974d46041a96ef7b00915c863eb2a702901 0x47 0x304402207ffb4da33f40cac839a43000a187bd76a1ee5bf95e46dc1534b38bb7bd0321db022038c078f29d1831f8eb68ffdc2634c654fb01c3467b6457b98ad220653bb2478501 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae",+    "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL",+    "P2SH",+    "P2SH(2-of-3)"+],+[+    "0x47 0x30440220001fff8863c84c0efc8eea5bffb7f388313f966f23a00ad3c0acc30ff5339684022016e6d78f51a3a1c362745931ca40b24f71cba2903dbfe5a6d392a9189127d83701",+    "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",+    "",+    "P2PK with too much R padding but no DERSIG"+],+[+    "0x48 0x304502202323d56f293842b544cacedd06baafb999196dfa1c2975314848c158ac606655022100514bd98186b8a3a1cc87f4aff76aed797781389f13f50d87bf95b2df6e488fcc01",+    "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",+    "",+    "P2PK with too much S padding but no DERSIG"+],+[+    "0x47 0x30440220d31c24bb6c08a496e7698a08fd41975115d7b55bfaa31cb2d573e09481e59a6702206a691239996434076b78a4e1cf46fc8e993b468a9c77fb1832186aa8040a61a201",+    "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",+    "",+    "P2PK with too little R padding but no DERSIG"+],+[+    "0x47 0x30440220007c2cc7aef1801c2937447703c87ef2a3744209ad98da2abadd4ba8bb2e3ea00220503a275582c9f9e9ff30260c81b7f64b8b696f22105605cc8241fb76a797316201",+    "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT",+    "",+    "P2PK NOT with bad sig with too much R padding but no DERSIG"+],+[+    "0x48 0x3045022021bf9184d94f208ac9f4757ebca9b1cbebf008cfc244fe5be1360b1b9aba0e92022100e55074f72f3a1bfddf2ea4ea7ba984f78822e136fe04c8f9c1363238e0233bd801",+    "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",+    "STRICTENC",+    "P2PK with high S but no LOW_S"+],+[+    "0x47 0x3044022078d6c447887e88dcbe1bc5b613645280df6f4e5935648bc226e9d91da71b3216022047d6b7ef0949b228fc1b359afb8d50500268711354298217b983c26970790c7601",+    "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT",+    "",+    "P2PK NOT with invalid hybrid pubkey but no STRICTENC"+],+[+    "0 0x47 0x304402203b269b9fbc0936877bf855b5fb41757218d9548b246370d991442a5f5bd1c3440220235268a4eaa8c67e543c6e37da81dd36d3b1be2de6b4fef04113389ca6ddc04501",+    "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",+    "",+    "1-of-2 with the second 1 hybrid pubkey and no STRICTENC"+],+[+    "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",+    "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",+    "STRICTENC",+    "1-of-2 with the second 1 hybrid pubkey"+],++["+CHECKMULTISIG evaluation order tests. CHECKMULTISIG evaluates signatures and+pubkeys in a specific order, and will exit early if the number of signatures+left to check is greater than the number of keys left. As STRICTENC fails the+script when it reaches an invalidly encoded signature or pubkey, we can use it+to test the exact order in which signatures and pubkeys are evaluated by+distinguishing CHECKMULTISIG returning false on the stack and the script as a+whole failing.++See also the corresponding inverted versions of these tests in script_invalid.json+"],+[+    "0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",+    "2 0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",+    "STRICTENC",+    "2-of-2 CHECKMULTISIG NOT with the second pubkey invalid, and both signatures validly encoded. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid pubkey."+],+[+    "0 0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501",+    "2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT",+    "STRICTENC",+    "2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but second signature invalid. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid signature."+],++[+    "0x47 0x304402204649e9517ef0377a8f8270bd423053fd98ddff62d74ea553e9579558abbb75e4022044a2b2344469c12e35ed898987711272b634733dd0f5e051288eceb04bd4669e05",+    "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG",+    "",+    "P2PK with undefined hashtype but no STRICTENC"+],+[+    "0x47 0x304402207f1cf1866a2df0bb4b8d84d0ade72aa3abb6aaab0639d608b23d9e10ead0c48202203caa97f22c3439443eea4b89f7f6729854df0f567a8184d6ecc6e8b6c68c3e9d05",+    "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT",+    "",+    "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC"+],+[+    "1 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01",+    "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",+    "",+    "3-of-3 with nonzero dummy but no NULLDUMMY"+],+[+    "1 0x47 0x30440220195038dbc6b2ae1199f86a6777824f7c5149789d85f655a3534a4422b8fba38c02204df9db87d2eb9fe06edc66870d9ac4c9ce673459f9d43cee0347ce4ffb02ee5a01 0x47 0x3044022010a45f30c6fa97a186eba9e6b595ab87d3dfcbf05dcaf1f1b8e3e7bf39515bb802203474e78d3d372e5f5c0f8c257ce8300c4bb8f37c51d4a894e11a91b5817da6ed01 0x47 0x30440220039cffd8e39850f95112662b1220b14b3c0d3d8a2772e13c947bfbf96345a64e02204154bfa77e2c0134d5434353bed82141e5da1cc479954aa288d5f0671480a04b01",+    "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",+    "",+    "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"+],+[+    "0 0x47 0x3044022002a27769ee33db258bdf7a3792e7da4143ec4001b551f73e6a190b8d1bde449d02206742c56ccd94a7a2e16ca52fc1ae4a0aa122b0014a867a80de104f9cb18e472c01 DUP",+    "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",+    "",+    "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY"+],+[+    "0 0x47 0x304402203acf75dd59bbef171aeeedae4f1020b824195820db82575c2b323b8899f95de9022067df297d3a5fad049ba0bb81255d0e495643cbcf9abae9e396988618bc0c6dfe01 0x47 0x304402205f8b859230c1cab7d4e8de38ff244d2ebe046b64e8d3f4219b01e483c203490a022071bdc488e31b557f7d9e5c8a8bec90dc92289ca70fa317685f4f140e38b30c4601",+    "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",+    "SIGPUSHONLY",+    "2-of-2 with two identical keys and sigs pushed"+],++["The End"]+]