packages feed

bitcoin-hs (empty) → 0.0.1

raw patch · 96 files changed

+20909/−0 lines, 96 filesdep +HTTPdep +QuickCheckdep +arraybuild-type:Customsetup-changed

Dependencies added: HTTP, QuickCheck, array, base, binary, bitcoin-hs, bytestring, containers, deepseq, directory, filepath, ghc-prim, json, mtl, network, network-uri, old-locale, random, tasty, tasty-hunit, tasty-quickcheck, time, transformers

Files

+ Bitcoin/BlockChain.hs view
@@ -0,0 +1,25 @@++-- | This module reexports most @Bitcoin.BlockChain.*@ modules++module Bitcoin.BlockChain +  ( module Bitcoin.BlockChain.Base+  , module Bitcoin.BlockChain.Cache+  , module Bitcoin.BlockChain.Chain+  , module Bitcoin.BlockChain.Checkpoint+  , module Bitcoin.BlockChain.Load+--  , module Bitcoin.BlockChain.Parser+  , module Bitcoin.BlockChain.Tx+  , module Bitcoin.BlockChain.TxLookup+  , module Bitcoin.BlockChain.Unspent+  )+  where++import Bitcoin.BlockChain.Base+import Bitcoin.BlockChain.Cache         -- note: Cache should be somewhere else, where all "runtime" maintained stuff will be+import Bitcoin.BlockChain.Chain+import Bitcoin.BlockChain.Checkpoint+import Bitcoin.BlockChain.Load+-- import Bitcoin.BlockChain.Parser+import Bitcoin.BlockChain.Tx+import Bitcoin.BlockChain.TxLookup+import Bitcoin.BlockChain.Unspent
+ Bitcoin/BlockChain/Base.hs view
@@ -0,0 +1,99 @@++-- | BlockChain data structures++{-# LANGUAGE BangPatterns, DeriveFunctor, DeriveFoldable, DeriveTraversable #-}+module Bitcoin.BlockChain.Base +  (+  -- * the block header +    BlockHeader(..)+  -- * one-parameter blocks+  , Block(..)+  , BlockChain(..)+  -- * two-parameter blocks+  , Block2(..)+  , BlockChain2(..)+  , module Bitcoin.BlockChain.Tx+  ) where++--------------------------------------------------------------------------------++import Prelude++import Data.Int+import Data.Word+import Data.List ( mapAccumL )++import Control.Monad+import Control.Applicative++import Data.Foldable ( Foldable(..) )+import Data.Traversable ( Traversable(..) )++import qualified Data.ByteString      as B+import qualified Data.ByteString.Lazy as L++import Data.Binary+import Data.Binary.Get++import Bitcoin.Misc.Bifunctor+import Bitcoin.Misc.HexString+import Bitcoin.Misc.UnixTime++import Bitcoin.Protocol.Hash++import Bitcoin.BlockChain.Tx++--------------------------------------------------------------------------------++newtype BlockChain tx = BlockChain [Block tx] deriving (Functor,Foldable,Traversable)++--------------------------------------------------------------------------------++data Block tx = Block+  { _blockHeader  :: !BlockHeader +  , _blockTxs     :: [tx]  +  }+  deriving (Eq,Show,Functor,Foldable,Traversable)++--------------------------------------------------------------------------------++-- | The header of a block+data BlockHeader = BlockHeader+  { _blkBlockVersion :: {-# UNPACK #-} !Word32         -- ^ block version (currently 1 or 2)+  , _blkPrevBlock    :: {-# UNPACK #-} !Hash256        -- ^ hash of the previous block +  , _blkMerkleRoot   :: {-# UNPACK #-} !Hash256        -- ^ merkle root of the transaction tree+  , _blkTimeStamp    :: {-# UNPACK #-} !UnixTimeStamp  -- ^ timestamp of the block+  , _blkDifficulty   :: {-# UNPACK #-} !Word32         -- ^ the difficulty (see "Bitcoin.Protocol.Difficulty")+  , _blkNonce        :: {-# UNPACK #-} !Word32         -- ^ the nonce+  , _blkBlockHash    :: Hash256                        -- ^ the hash of /this/ block. Note: the hash is not actually stored in the blockchain; but it is computed when the block is loaded+  }+  deriving (Eq,Show)++--------------------------------------------------------------------------------++-- | A two-parameter version of 'Block', with 'BiFunctor' etc instances. +-- It is a newtype only so that we can provide these instances...+newtype Block2 inscript outscript = Block2 { unBlock2 :: Block (Tx inscript outscript) }++-- | A two-parameter version of 'BlockChain', with 'BiFunctor' etc instances.+newtype BlockChain2 inscript outscript = BlockChain2 { unBlockChain2 :: [Block2 inscript outscript] }++instance BiFunctor BlockChain2 where+  fmapFst  f   (BlockChain2 blocks) = BlockChain2 (map (fmapFst  f  ) blocks)+  fmapSnd    g (BlockChain2 blocks) = BlockChain2 (map (fmapSnd    g) blocks)+  fmapBoth f g (BlockChain2 blocks) = BlockChain2 (map (fmapBoth f g) blocks)++instance BiFoldable BlockChain2 where+  bifoldl f g x0 (BlockChain2 blocks)    = Prelude.foldl (bifoldl f g) x0 blocks+  bifoldr f g    (BlockChain2 blocks) x0 = Prelude.foldr (bifoldr f g) x0 blocks++instance BiFunctor Block2 where+  fmapFst  f   (Block2 blk) = Block2 $ fmap (fmapFst f   ) blk+  fmapSnd    g (Block2 blk) = Block2 $ fmap (fmapSnd    g) blk+  fmapBoth f g (Block2 blk) = Block2 $ fmap (fmapBoth f g) blk++instance BiFoldable Block2 where+  bifoldl f g x0 (Block2 blk)    = Data.Foldable.foldl (bifoldl f g) x0 blk+  bifoldr f g    (Block2 blk) x0 = Data.Foldable.foldr (bifoldr f g) x0 blk++--------------------------------------------------------------------------------
+ Bitcoin/BlockChain/Cache.hs view
@@ -0,0 +1,111 @@+
+-- | Caching recently used blocks
+
+{-# LANGUAGE BangPatterns #-}
+module Bitcoin.BlockChain.Cache where
+
+--------------------------------------------------------------------------------
+
+import Control.Concurrent
+import System.IO.Unsafe as Unsafe
+
+import Data.IntMap        (IntMap) ; import qualified Data.IntMap        as IntMap
+import Bitcoin.Misc.BiMap (BiMap ) ; import qualified Bitcoin.Misc.BiMap as BiMap
+
+import Bitcoin.BlockChain.Base
+import Bitcoin.BlockChain.Tx
+import Bitcoin.BlockChain.Load
+
+import Bitcoin.Script.Base
+
+--------------------------------------------------------------------------------
+
+data BlockCache script = BlockCache
+  { _blkMap :: !(IntMap (Block (Tx script script)))
+  , _locMap :: !(BiMap BlockLocation Int)
+  }
+
+-- | How many blocks we cache (128 at the moment)
+theBlockCacheSize :: Int
+theBlockCacheSize = 128
+
+-- | if the largest key (approx equals the number of lookups) reaches this limit, we compactify
+theBlockCacheCompactLimit :: Int
+theBlockCacheCompactLimit = 1024 -- 2^30-1
+
+-- | The global block cache
+theBlockCache :: MVar (BlockCache RawScript)
+theBlockCache = Unsafe.unsafePerformIO $ newMVar (BlockCache IntMap.empty BiMap.empty)
+
+--------------------------------------------------------------------------------
+
+compactTheBlockCache :: IO ()
+compactTheBlockCache = do
+  BlockCache blks locs <- takeMVar theBlockCache
+  let oldlocs    = BiMap.toList locs
+  let locs'      = BiMap.fromList  $ zipWith (\(loc,j) i -> (loc,i)) oldlocs [1..]
+      translate  = IntMap.fromList $ zipWith (\(loc,j) i -> (j  ,i)) oldlocs [1..]
+      f (!j,blk) = case IntMap.lookup j translate of 
+                     Just !i -> (i,blk)
+                     Nothing -> error "compactTheBlockCache: fatal error, shouldn't happen"
+      blks'     = IntMap.fromList $ map f $ IntMap.toList blks
+  putMVar theBlockCache $! (BlockCache blks' locs')
+
+--------------------------------------------------------------------------------
+
+loadBlockCached :: BlockLocation -> IO (Block (Tx RawScript RawScript))
+loadBlockCached location = do
+
+  orig@(BlockCache blks locs) <- takeMVar theBlockCache
+  let n    = IntMap.size blks                                -- size
+      lmax = if n==0 then 0 else fst (IntMap.findMax blks)   -- largest key
+      l'   = lmax+1
+
+  if n >= theBlockCacheCompactLimit 
+
+    -- we have to compactify...
+    then do 
+      putMVar theBlockCache $! orig
+      compactTheBlockCache
+      loadBlockCached location
+
+    else case BiMap.lookup location locs of
+
+      -- it was in the cache
+      Just i -> case IntMap.lookup i blks of
+        Just block -> do
+
+          putStrLn $ "block at " ++ show location ++ " was in the cache at pos " ++ show i ++ " (max = " ++ show lmax ++ " ; size = " ++ show n ++ ")"
+
+          let blks' = IntMap.insert l' block $ IntMap.delete i $ blks
+              locs' = BiMap.insert location l' locs
+          putMVar theBlockCache $! (BlockCache blks' locs')
+          return block
+        Nothing    -> do
+          let locs' = BiMap.delete location locs
+          putMVar theBlockCache $! (BlockCache blks locs')         -- delete the location from the map (it was invalid anyway)
+          loadBlockCached location                                 -- and try again! now it will load and put it into the map
+
+      -- it was not in the cache
+      Nothing -> do
+
+        putStrLn $ "block at " ++ show location ++ " was not in the cache"
+
+        block <- loadBlockAt location
+        if n < theBlockCacheSize
+          then do
+            let blks' = IntMap.insert l' block blks
+                locs' = BiMap.insert location l' locs
+            putMVar theBlockCache $! BlockCache blks' locs'
+            return block
+          else
+            case IntMap.minViewWithKey blks of
+              Nothing -> error "loadBlockCached: fatal error, shouldn't happen; #1"
+              Just ((i,_),rest) -> do
+                let blks' = IntMap.insert l' block rest
+                    locs' = BiMap.insert location l' $ BiMap.deleteRev i $ locs
+                putMVar theBlockCache $! (BlockCache blks' locs')         -- delete the location from the map (it was invalid anyway) 
+                return block
+
+--------------------------------------------------------------------------------
+
+ Bitcoin/BlockChain/Chain.hs view
@@ -0,0 +1,261 @@++-- | In-memory cache for blockchain metadata++{-# LANGUAGE BangPatterns #-}+module Bitcoin.BlockChain.Chain where++--------------------------------------------------------------------------------++import Data.Array++import Data.Word+import Data.Ord+import Data.List ( sort , group , unfoldr , maximumBy , foldl' )+import Data.Maybe++import Data.Set (Set) ; import qualified Data.Set as Set+import Data.Map (Map) ; import qualified Data.Map as Map++import Control.Monad++import qualified Data.ByteString      as B+import qualified Data.ByteString.Lazy as L++import Data.Binary.Get+import Data.Binary.Put++import System.Mem ( performGC )++import Bitcoin.BlockChain.Base+import Bitcoin.BlockChain.Parser+import Bitcoin.BlockChain.Load+import Bitcoin.BlockChain.Checkpoint++import Bitcoin.Script.Base++import Bitcoin.Protocol.Hash+import Bitcoin.Protocol.Difficulty ++--------------------------------------------------------------------------------+-- * blockchain++-- | The block-chain as an (inverted) tree.+--+-- Note: The Ord instance compares the block hash (it defined only for internal reasons)+data Chain = Chain+  { _chainPrev      :: Maybe Chain                 -- ^ the previous block+  , _chainHeader    :: !BlockHeader                -- ^ the block header+  , _chainLocation  :: !BlockLocation              -- ^ the physical location on the harddisk where this block can be found+  , _chainHeight    :: {-# UNPACK #-} !Int         -- ^ the height of the block (the genesis block has height 0)+  , _chainTotalDiff :: {-# UNPACK #-} !Double      -- ^ the total summed difficulty on this branch+  }+  deriving (Eq,Show)++instance Ord Chain where+  compare ch1 ch2 = compare (chainBlockHash ch1) (chainBlockHash ch2)++chainBlockHash :: Chain -> Hash256+chainBlockHash = _blkBlockHash . _chainHeader++chainPrevHash :: Chain -> Hash256+chainPrevHash = _blkPrevBlock . _chainHeader++--------------------------------------------------------------------------------+-- * building the chain and related metadata++-- | BlockChain metadata+data ChainTable = ChainTable +  { _tablePrev    :: !(Map Hash256 Hash256)      -- ^ lookup table for the previous block hash (this is somewhat redundant)+  , _tableNext    :: !(Map Hash256 [Hash256])    -- ^ lookup table for the next block(s) hash(es)+  , _tableBlock   :: !(Map Hash256 Chain)        -- ^ lookup table for the blocks+  , _tableHeight  :: !(Map Hash256 Int)          -- ^ reverse lookup table for the longest chain+  , _tableLongest :: !(Array Int Chain)          -- ^ the longest chain itself+  }+  deriving Show++buildChainTable :: IO ChainTable +buildChainTable = blockDirectory >>= buildChainTable'++-- | The argument is the block directory+buildChainTable' :: FilePath -> IO ChainTable +buildChainTable' dir = do++  fnames <- blockFiles dir+  -- print fnames++  pre_chains <- liftM concat $ forM fnames $ \fn -> do+    -- print fn +    raw <- L.readFile fn+    let blockheaders = runGet getBlockHeadersOnly raw      +    -- print $ length blockheaders +    return [ Chain Nothing hdr (BlockLocation fn pos) 0 0 | (!pos,!hdr) <- blockheaders ]++  let pre_table = Map.fromList+        [ c `seq` this `seq` (this, c) +        | c <- pre_chains +        , let this = chainBlockHash c+        ]++  let prevtable :: Map Hash256 Hash256+      prevtable = Map.fromList +        [ prev `seq` this `seq` (this,prev)+        | chain <- pre_chains+        , let this = chainBlockHash chain+        , let prev = chainPrevHash  chain +        ]++  let nexttable :: Map Hash256 [Hash256]+      nexttable = buildMap (:[]) (:) +        [ this `seq` prev `seq` (prev,this) +        | chain <- pre_chains+        , let this = chainBlockHash chain+        , let prev = chainPrevHash  chain +        ]++  -- builds up the chain  +  let chainWorker :: Int -> Map Hash256 Chain -> [Chain] -> Map Hash256 Chain+      chainWorker !height !table ![] = table+      chainWorker !height !table !active = forceList_ active `seq` chainWorker height' table' active' where+        height' = height + 1+        table'  = foldl' add table active +        active' = {- setNub $ -} concatMap h active+        h !c = let almosth = Map.findWithDefault [] (chainBlockHash c) nexttable :: [Hash256]+                   almostc = map (\h -> fromJust $ Map.lookup h pre_table) almosth+               in  map ( \d -> d { _chainHeight = height' +                                 , _chainPrev   = Just c +                                 , _chainTotalDiff = _chainTotalDiff c + decimalDifficulty (_blkDifficulty (_chainHeader d))+                                 } ) almostc+        add !old !chain = Map.insert (chainBlockHash chain) chain old++  let genesis :: Chain+      genesis = case Map.lookup zeroHash256 nexttable of +        Just [h] -> if h == theGenesisBlock+                      then let c0 = fromJust $ Map.lookup h pre_table+                           in  c0 { _chainTotalDiff = decimalDifficulty (_blkDifficulty (_chainHeader c0)) }+                      else error "buildChainTables': genesis block hash does not match"+        Just []  -> error "buildChainTables'/genesis: shouldn't happen"+        Nothing  -> error "buildChainTables'/genesis: no genesis block candidate found"+        Just _   -> error "buildChainTables'/genesis: more than one genesis block candidate found"++  let fulltable = chainWorker 0 (Map.singleton (chainBlockHash genesis) genesis) [genesis]++  -- input: set of active heads+  -- output: the head of the longest chain +  let findLongestChain :: [Chain] -> Chain+      findLongestChain active = ++        -- it seems to be important to force the list here, +        -- otherwise stack overflow will happen...+        forceList_ active `seq` if all isLeft active'                        +          then maximumBy (comparing _chainTotalDiff) (map fromLeft active')+          else findLongestChain (concatMap ei active')++        where+          active' :: [Either Chain [Chain]]+          active' = map worker active++          worker :: Chain -> Either Chain [Chain]+          worker !ch = case Map.lookup (chainBlockHash ch) nexttable of+            Nothing -> Left ch    -- this is a "head", but it may be the longest, so we keep it+            Just [] -> error "buildChainTables'/longestChain: shouldn't happen"+            Just hs -> Right $ map (\h -> fromJust (Map.lookup h fulltable)) hs++          ei (Left  !x ) = [x]+          ei (Right !ys) = ys++          isLeft (Left _) = True+          isLeft _        = False++          fromLeft (Left !x) = x+          fromLeft _ = error "buildChainTables'/longestChain/fromLeft: Right"++  let longest_head = findLongestChain [genesis]+      longest_list = {- reverse -} (longest_head : unfoldr' f longest_head) where++        f !c = case _chainPrev c of+          Just !c' -> Just (c',c') +          Nothing  -> Nothing++      longest_lkp = Map.fromList +        [ height `seq` this `seq` (this,height)+        | c <- longest_list +        , let this = chainBlockHash c+        , let height = _chainHeight c+        ]++      longest_arr = array (0, _chainHeight longest_head)  +        [ c `seq` height `seq` (height, c) +        | c <- longest_list +        , let height = _chainHeight c+        ]++{-    +  print longest_head+  print (head longest_list)+  print (last longest_list)+-}++  let final = (Map.size prevtable) `seq` +              (Map.size nexttable) `seq` +              (Map.size fulltable) `seq` +              (Map.size longest_lkp) `seq` +              longest_arr `seq` +              ChainTable prevtable nexttable fulltable longest_lkp longest_arr++  final `seq` System.Mem.performGC `seq` (return final)++--------------------------------------------------------------------------------+-- * conveniance functions ++-- | Calls a user action for all blocks in the longest chain. The 'Int' is the block height+-- (with the genesis block having height zero).+forAllBlocks_ :: ChainTable -> (Int -> Block (Tx RawScript RawScript) -> IO ()) -> IO ()+forAllBlocks_ chTable userAction = do+  let (a,b) = bounds (_tableLongest chTable)+  forM_ [a..b] $ \(!blkIdx) -> do+    block <- loadBlockAt $! _chainLocation (_tableLongest chTable ! blkIdx)+    block `seq` userAction blkIdx block++forAllBlocks :: ChainTable -> (Int -> Block (Tx RawScript RawScript) -> IO a) -> IO [a]+forAllBlocks chTable userAction = do+  let (a,b) = bounds (_tableLongest chTable)+  forM [a..b] $ \(!blkIdx) -> do+    block <- loadBlockAt $! _chainLocation (_tableLongest chTable ! blkIdx)+    block `seq` userAction blkIdx block++--------------------------------------------------------------------------------+-- * misc helper functions (to be moved to some Misc.XXX modules)++buildMap :: Ord k => (b -> a) -> (b -> a -> a) -> [(k,b)] -> Map k a+buildMap f g xs = foldl worker Map.empty xs where+  worker old (k,y) = Map.alter h k old where+    h mb = case mb of+      Nothing -> Just (f y)+      Just x  -> Just (g y x)    ++sortNub :: Ord a => [a] -> [a]+sortNub = map head . group . sort++setNub :: Ord a => [a] -> [a]+setNub xs = Set.toList (go Set.empty xs) where+  go !old []     = old+  go !old (x:xs) = go (Set.insert x old) xs++forceList_ :: [a] -> ()+forceList_ (x:xs) = x `seq` forceList_ xs+forceList_ [] = ()++-- strict unfold?+unfoldr' :: (b -> Maybe (a, b)) -> b -> [a]+unfoldr' f = go where+  go !b = case f b of+    Just (!a,!b') -> a : go b'+    Nothing       -> []++--------------------------------------------------------------------------------++{-+main = do+  stuff <- (blockDirectory >>= buildChainFull')+  mapM_ print stuff+-}
+ Bitcoin/BlockChain/Checkpoint.hs view
@@ -0,0 +1,388 @@++-- | Checkpoints in the blockchain (every 1000th blocks)++{-# LANGUAGE CPP #-}+module Bitcoin.BlockChain.Checkpoint where++--------------------------------------------------------------------------------++import Bitcoin.Protocol.Hash++--------------------------------------------------------------------------------++#ifndef WITH_TESTNET++--------------------------------------------------------------------------------+-- * the real network++theGenesisBlock :: Hash256+theGenesisBlock = hash256FromTextBE "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"++theCheckpoints :: [(Int,Hash256)]+theCheckpoints =+  [ (0     , hash256FromTextBE "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" )+  , (1000  , hash256FromTextBE "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09" )+  , (2000  , hash256FromTextBE "00000000dfd5d65c9d8561b4b8f60a63018fe3933ecb131fb37f905f87da951a" )+  , (3000  , hash256FromTextBE "000000004a81b9aa469b11649996ecb0a452c16d1181e72f9f980850a1c5ecce" )+  , (4000  , hash256FromTextBE "00000000922e2aa9e84a474350a3555f49f06061fd49df50a9352f156692a842" )+  , (5000  , hash256FromTextBE "000000004d78d2a8a93a1d20a24d721268690bebd2b51f7e80657d57e226eef9" )+  , (6000  , hash256FromTextBE "00000000dbbb79792303bdd1c6c4d7ab9c21bba0667213c2eca955e11230c5a5" )+  , (7000  , hash256FromTextBE "00000000febe750c27cd55f8bead2b0d4faf33ba961f9e3c0314791ab90ade55" )+  , (8000  , hash256FromTextBE "0000000094fbacdffec05aea9847000522a258c269ae37a74a818afb96fc27d9" )+  , (9000  , hash256FromTextBE "00000000415c7a0f3e54ed29a3165414e5952fce6848b697696fcc840011a5b5" )+  , (10000 , hash256FromTextBE "0000000099c744455f58e6c6e98b671e1bf7f37346bfd4cf5d0274ad8ee660cb" )+  , (11000 , hash256FromTextBE "00000000ea47d068e0ba9b4d902ae291850ac59cf29c2b89b2bacf3db3c37e3a" )+  , (12000 , hash256FromTextBE "0000000011d1d9f1af3e1d038cebba251f933102dbe181d46a7966191b3299ee" )+  , (13000 , hash256FromTextBE "00000000d85a4cf33f325d339b43559df5c8aaa1c2af2c71a1255e95f6038b5a" )+  , (14000 , hash256FromTextBE "000000002d9050318ec8112057423e30b9570b39998aacd00ca648216525fce3" )+  , (15000 , hash256FromTextBE "000000005c3548bda7c3d3e2fb2db21f68b87f47dd8b7ed095dfeecee76038b7" )+  , (16000 , hash256FromTextBE "00000000679a1ab3af6da03f13a0bc96d7215e65458b2d2edfa030b5b431e8b3" )+  , (17000 , hash256FromTextBE "000000007778515cfe0665840b3697d542469ec21bef64cf44f4975690bc75dc" )+  , (18000 , hash256FromTextBE "00000000f914f0d0692e56bd06565ac4de668251b6a29fe0535d1e0031cfd0de" )+  , (19000 , hash256FromTextBE "00000000794894208a98d6a323f37e23ead638bcaf3a2718c80a4cf5e846fd32" )+  , (20000 , hash256FromTextBE "00000000770ebe897270ca5f6d539d8afb4ea4f4e757761a34ca82e17207d886" )+  , (21000 , hash256FromTextBE "00000000e435f35c8305e92dd2d4a9b9a29172a745bb7889cac6b5de4c643362" )+  , (22000 , hash256FromTextBE "000000004625a14242beccb38c63a1f770a76ee5788764e6c0abd4129bbc1b9d" )+  , (23000 , hash256FromTextBE "00000000034516e6053bcec513c978f3f83fa90f4e569044a59a2a7f3419d487" )+  , (24000 , hash256FromTextBE "00000000f04fccc81f37002707e9501a3f7bdcf25f65531f386a2da8af20122e" )+  , (25000 , hash256FromTextBE "00000000ae4b125eb183e689b7231eafa8c992d5b8c952d9f3cd30a79a788ddf" )+  , (26000 , hash256FromTextBE "000000006d6c151db6d4d67356d590a897a11cd7d8111ee989de6f2f548410bf" )+  , (27000 , hash256FromTextBE "000000002cc4a38b7e2e9d45b0fe677806d841835af340b10e5c8b51811e6572" )+  , (28000 , hash256FromTextBE "00000000172c5ed49d7dfc29bf9a18a53fa2d050fa37aa210d6d4080fd0c7e67" )+  , (29000 , hash256FromTextBE "00000000b8b9f3b66b43b045aedc3380780df7e492866683c59efa770bb9a3a9" )+  , (30000 , hash256FromTextBE "00000000de1250dc2df5cf4d877e055f338d6ed1ab504d5b71c097cdccd00e13" )+  , (31000 , hash256FromTextBE "00000000a6a6be6014fb079b06ee52c222d1897010c453f4ff7b40dad1c126c4" )+  , (32000 , hash256FromTextBE "00000000049172ba3ec1b673cf13e3d0049c1c07bb103ed3fa300e3833480055" )+  , (33000 , hash256FromTextBE "00000000942725dd706c453fd044c5542f638c02a6982732fcc32e35ae532f10" )+  , (34000 , hash256FromTextBE "00000000495968d19210d3be15bd24fdc19805a0ef15026b0bb4482b04a9da3c" )+  , (35000 , hash256FromTextBE "000000008f0cdb273d95e830c726b253b80be537cd21867b0a03ef0a326df91d" )+  , (36000 , hash256FromTextBE "0000000080c3deea35dc3df90a5fbe5f27db52f5e01018ae7d62f8b454c71335" )+  , (37000 , hash256FromTextBE "00000000ba03c2f33d1fbdbf2a03d2bb6aa7fb8cff5b5dc6424cf937a8fd4423" )+  , (38000 , hash256FromTextBE "000000002dfebce284d1e08b6cf04452530891579b7377669865889498de8f3f" )+  , (39000 , hash256FromTextBE "0000000081b8c41f27bf3955713105c9bdc5118ddf429a9aedc54b71114ad563" )+  , (40000 , hash256FromTextBE "00000000504d5fa0ad2cb90af16052a4eb2aea70fa1cba653b90a4583c5193e4" )+  , (41000 , hash256FromTextBE "000000001b8e5f1e2c451b0af5703e714d1c31dae10ac65614963f44e819e860" )+  , (42000 , hash256FromTextBE "000000000f80c09687893406279f62da437a6a0b95b8dc096b30c10ce088fc64" )+  , (43000 , hash256FromTextBE "00000000212265ec8de3a24751d355725f05370882e2162aa7a57d65d31c506b" )+  , (44000 , hash256FromTextBE "000000000122898b31073a770a97cf599c00672fc8d6ae15652235862f8b76d8" )+  , (45000 , hash256FromTextBE "0000000007758365e4eef39e396f257a3caebb2850906f054066a58ffe657e3b" )+  , (46000 , hash256FromTextBE "000000001dd39771dbe4f9fc6da07327f13f894dd2c1a46cdfcedf930fbbc52b" )+  , (47000 , hash256FromTextBE "0000000000e7189f8a21e7202826283ccfb276461fe5c5813b4778b708ae605c" )+  , (48000 , hash256FromTextBE "000000000f3d40ea2bfa8d779010e52cff4720c072ec4b12ed576cf5cf93c947" )+  , (49000 , hash256FromTextBE "00000000289418da0e84f10d9563c4f08d2b4265443b9b88045b13811999ea09" )+  , (50000 , hash256FromTextBE "000000001aeae195809d120b5d66a39c83eb48792e068f8ea1fea19d84a4278a" )+  , (51000 , hash256FromTextBE "0000000016aa231b566ce2d1e95405962d6a12d3690c0f01427ffd2b5f4b9df0" )+  , (52000 , hash256FromTextBE "00000000082bc4398c4aa5bd8d9fc452d60d533ef68baabf594c9e7d6649049f" )+  , (53000 , hash256FromTextBE "000000000bc96af7886cb12075ab1c79711d9589b5051b02f06553c62c22c971" )+  , (54000 , hash256FromTextBE "00000000144197f54afa21ae7db2bc93eee604432101fc0ebe7966a52bb27e61" )+  , (55000 , hash256FromTextBE "000000000a629716ce673212ea154bab57d7d2b62aca42683389dfcdfe747e1a" )+  , (56000 , hash256FromTextBE "000000000dfa452ea45e0426dd8914c35e24dfd4399037c5e6deb9f18f58d6d3" )+  , (57000 , hash256FromTextBE "0000000008ee3753c6dd237a3a3b4f6d19c2651a2ed26f63756e9f300073722d" )+  , (58000 , hash256FromTextBE "0000000013e3791d288d9db814c52fbdf240b2206eb8e19d7dc80013c60c0c00" )+  , (59000 , hash256FromTextBE "0000000006ddc481d2874ca7ca98ffaae9645b6c7e316bc80e0415a072277d27" )+  , (60000 , hash256FromTextBE "000000000b554c46f8eb7264d7d5e334382c6fc3098dabf734de37962ccd7495" )+  , (61000 , hash256FromTextBE "000000000045edc734e45c83cad9424f9946184026c9637527067340f3c7c65e" )+  , (62000 , hash256FromTextBE "0000000006dd4bc72daabef992f860e703820de119af3e24a1ea6f6c81521011" )+  , (63000 , hash256FromTextBE "000000000abcf1c5c959bfbbdf5ad13054a1c43e60e168d6ef790b8200e0891b" )+  , (64000 , hash256FromTextBE "0000000003d7055b51d7b9ab693de84c03201fe0396af61dbb30bf31445d3f55" )+  , (65000 , hash256FromTextBE "0000000006502bbeba998efd13a8dfa7fb6f213da62143f5cddc4b709daa2cc2" )+  , (66000 , hash256FromTextBE "00000000071d7e8a0f4895e60c1073df9311d65a85244be1ee6369c9506281af" )+  , (67000 , hash256FromTextBE "00000000052c31495cf4c2afcea5ad5762fded7444a2bba0dcf600fa3fc900b1" )+  , (68000 , hash256FromTextBE "0000000000d991791fdfdbccbbc2a73d2f86ccf78e2d0a7ce7675f40b5986b3e" )+  , (69000 , hash256FromTextBE "00000000000672cb3e0f7c83c90b505ecc9cee701747a50ed998dcf00c499746" )+  , (70000 , hash256FromTextBE "00000000002b8cd0faa58444df3ba2a22af2b5838c7e4a5b687444f913a575c2" )+  , (71000 , hash256FromTextBE "00000000003eea76022498376477294a921cfabeee70f0630ce0fd45dc22179b" )+  , (72000 , hash256FromTextBE "0000000000eb357d4c6fef6ad9a6fade126985ad36042a99cf215a4454545977" )+  , (73000 , hash256FromTextBE "00000000005936a8d5637765967ad4da3599596adf19879f5e65d6940da7fa64" )+  , (74000 , hash256FromTextBE "0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20" )+  , (75000 , hash256FromTextBE "00000000000ace2adaabf1baf9dc0ec54434db11e9fd63c1819d8d77df40afda" )+  , (76000 , hash256FromTextBE "0000000000571138ff757a28ddf9b56f28c4a461e170660bb5ae79a556069bb6" )+  , (77000 , hash256FromTextBE "00000000001bd84391562e354949ad0480b83f5058449cbcd9f249e9dbde91c7" )+  , (78000 , hash256FromTextBE "00000000001f3fe62641b473673c9ababbe207046a109f0861af95c905a918fa" )+  , (79000 , hash256FromTextBE "00000000002703587a4eb2b2b5595749f632ed78b3ef12fb1f5fcd3adcc61620" )+  , (80000 , hash256FromTextBE "000000000043a8c0fd1d6f726790caa2a406010d19efd2780db27bdbbd93baf6" )+  , (81000 , hash256FromTextBE "000000000030c11525e18d5083000ca58a6b1625ce54b48edf16b9b6dbd8f043" )+  , (82000 , hash256FromTextBE "00000000000c9d1c4acc114afb58d55db5ec44a963263cf6247220b7a3f85c5c" )+  , (83000 , hash256FromTextBE "0000000000230ee9fb4cf0933aba6c94e9c425636fe67c28366abcd8bd48b734" )+  , (84000 , hash256FromTextBE "00000000001385326e30864192ba84ed2f9cbfadf0698655b1c25f93c92f22ad" )+  , (85000 , hash256FromTextBE "000000000005dcaf122d18052c42041ce2afa1203a0c33b27a4be7a18e3e226f" )+  , (86000 , hash256FromTextBE "000000000000ff4e1adb14f07774dad6b34968a5e19d1a2fe1fc9157e7c2b85d" )+  , (87000 , hash256FromTextBE "00000000001e468674df93eb3897c3d7558fdf61991708231246e9002e9526cd" )+  , (88000 , hash256FromTextBE "00000000000ae9e98b82b39a912cdc0ebed97c26376780ac996c84d9ec3264a4" )+  , (89000 , hash256FromTextBE "0000000000078b8967aabc82021fe024484be7e2982dfe19c58a1b6462130da8" )+  , (90000 , hash256FromTextBE "0000000000071694daf735a6b5da101d77a04c7e6008c680e461f0025ba7b7af" )+  , (91000 , hash256FromTextBE "00000000000573bc13322a6c97ee0076e79ba38a8e57e8f1bf790d13190321d8" )+  , (92000 , hash256FromTextBE "0000000000001df90b0c523a4d7e4731336b00cf4ba9d8e02d111523df80998c" )+  , (93000 , hash256FromTextBE "0000000000015d5379547ad416695137953a85f5a059ea7023b5aa1d9fdc6f29" )+  , (94000 , hash256FromTextBE "000000000002a4c42580d51f0ddfd867eaaa790781c484c633a69167d17b48ec" )+  , (95000 , hash256FromTextBE "0000000000074a6f7e2d07cd8e5dd6dc8183993ee3b84666af499bc5b439d21b" )+  , (96000 , hash256FromTextBE "000000000002c86b568cdd2d0f4b0430cccf42bcde3361f63a32e23b5d839e99" )+  , (97000 , hash256FromTextBE "00000000000125d656e9f28543317f33fb1b66baaf90de44a375ce6c5564fe0c" )+  , (98000 , hash256FromTextBE "000000000002272a6dfb695d9db936d813bf0055ae92e920c2791d4c5f7290f1" )+  , (99000 , hash256FromTextBE "000000000001d216ee63e5910da39b56d4b15fd962951b08901bd520a0b2b6ea" )+  , (100000 , hash256FromTextBE "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" )+  , (101000 , hash256FromTextBE "0000000000009c11d2683ccbba6d1b8dd7985c3e693f55c95539156aa76a8d41" )+  , (102000 , hash256FromTextBE "00000000000335c47dd6ae953912d172a4d9839355f2083165043bb6f43c2f58" )+  , (103000 , hash256FromTextBE "000000000002de7f6fb9d9b6c03d948a26f31922738b87a658489bd800bcb17d" )+  , (104000 , hash256FromTextBE "000000000000a9887c91956b638bb3c0651321fdb24715354c3fc6633f5a16a3" )+  , (105000 , hash256FromTextBE "00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97" )+  , (106000 , hash256FromTextBE "00000000000058d919f52d255f394ed0aa3a344432676fd30f1aab4e10c22fad" )+  , (107000 , hash256FromTextBE "000000000000a29d57f3c6c6696e84d21de79463b7bf85a6ccfac39438291d64" )+  , (108000 , hash256FromTextBE "00000000000167cea0b43ff7ce22f330d3e302832187eb31c61b15bb1511e118" )+  , (109000 , hash256FromTextBE "0000000000018ae5c97cf968e269afe18f15c6cbaff0beff192126401dedb634" )+  , (110000 , hash256FromTextBE "000000000001bbda3f22ef8e476b470a2d3ae16821c23a6d22db77318d0799a9" )+  , (111000 , hash256FromTextBE "0000000000011a7786add1f89b77bbb9a50077e982b4fb6f9a706674a71b9735" )+  , (112000 , hash256FromTextBE "0000000000001d69b3899a49f37799c375a7471829953d5470f468f48ff70432" )+  , (113000 , hash256FromTextBE "00000000000032775da8b166cac99dba6685a5b582216bd94da0a820c07aa3a4" )+  , (114000 , hash256FromTextBE "0000000000003195a1e6dc48a540264d37e9ef79b552bd78ea4b93a3b6e7e449" )+  , (115000 , hash256FromTextBE "000000000000e58392f3b59350e72cdaa81655460a0bd5547319522702799993" )+  , (116000 , hash256FromTextBE "00000000000007ff257fb2edd3fdbd7b00c127a66dae1288fc5e26c402d13bf7" )+  , (117000 , hash256FromTextBE "0000000000001c78105335022027226fd1d4547293c2598b2e145dd96ef78505" )+  , (118000 , hash256FromTextBE "000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553" )+  , (119000 , hash256FromTextBE "000000000000499e09bdbe9b99dd44e202e5933919f578d6baf03dedca727d35" )+  , (120000 , hash256FromTextBE "0000000000000e07595fca57b37fea8522e95e0f6891779cfd34d7e537524471" )+  , (121000 , hash256FromTextBE "0000000000008addb06debe0ba6b11e220b14b2b531750fda710b62bb1d3d706" )+  , (122000 , hash256FromTextBE "0000000000002fe5f29af38282ac1c8f4ea2bf8a0855946150130419491b6c05" )+  , (123000 , hash256FromTextBE "00000000000069b73594b10aaa38beaeadc6d3f28cab8d76c4a6ac182694fd41" )+  , (124000 , hash256FromTextBE "00000000000023e9a0523cfac29afe07a07acf81e273cd892c51ff8318846620" )+  , (125000 , hash256FromTextBE "00000000000042391c3620056af66ca9ad7cb962424a9b34611915cebb9e1a2a" )+  , (126000 , hash256FromTextBE "000000000000166b7d480aada35af1e6f9a2835d68f9c2fbd272073dc6c9d5fb" )+  , (127000 , hash256FromTextBE "00000000000019ebf04316b28e56943e697b142edf332dff9faeae22e29dba99" )+  , (128000 , hash256FromTextBE "00000000000003b8ddd8692769e1965554a8bb030863e0566a28bc0dc952864e" )+  , (129000 , hash256FromTextBE "0000000000000b85f08e4fa7cea9dbd1a7ec5ecb9f644d214e3572e214b570a7" )+  , (130000 , hash256FromTextBE "00000000000011906b491883ab0f16f0e690b133ca860b199b775c3cf6581c21" )+  , (131000 , hash256FromTextBE "000000000000143b8959d6db75bf13d4f4789ddb0167888d819eea3d413d82a9" )+  , (132000 , hash256FromTextBE "00000000000000a7a0483857f0d951983ff2834a47c38fdcc22563ac0f8f707b" )+  , (133000 , hash256FromTextBE "00000000000008aebdeb747bdedab72548e3101cc17da53301085ba6362852b3" )+  , (134000 , hash256FromTextBE "00000000000007e3e442ce1423496a064a7c34342ba98be164ac0c9f9b872213" )+  , (135000 , hash256FromTextBE "00000000000001bf349e3e8195f95a080ea17efe012cf7f512664829f9d3772d" )+  , (136000 , hash256FromTextBE "00000000000004da0d6d69fd474fa08fe2ff3111ff1e9e01f72899dcd9d897f0" )+  , (137000 , hash256FromTextBE "00000000000007c0c0ed00db0a4b2ca07bac088209d8484dfbdbb3cfca52013f" )+  , (138000 , hash256FromTextBE "0000000000000044c7b6a5511c0b2ae64ec545abccac8053f31cf7bba23bb886" )+  , (139000 , hash256FromTextBE "000000000000032a64e8aea278290cd184efbb0a2516b3dc3753c2567153e5cb" )+  , (140000 , hash256FromTextBE "000000000000086e28cf4717a80066def0ec26c53d660582bd997221fef297db" )+  , (141000 , hash256FromTextBE "000000000000079c4c0873586e86365f5c003887bca2b5112f5a8950862accbe" )+  , (142000 , hash256FromTextBE "00000000000006379826f5f10cd23739b9c29f87ca10f199f9f4b72006311f85" )+  , (143000 , hash256FromTextBE "000000000000026bd2449a46b551c82b6657529d6cba61dd842bc1ba0cbc59f8" )+  , (144000 , hash256FromTextBE "0000000000000681a73f1bb50454cee419048d24e1091bcddadded89df53fd07" )+  , (145000 , hash256FromTextBE "000000000000087f9aa52a08d8ff065ebe1b6d12f03390fe771faa8720eb96cb" )+  , (146000 , hash256FromTextBE "0000000000000188cbeebda87456f040370995dc11eb3a1e76b1577b6e0b588d" )+  , (147000 , hash256FromTextBE "000000000000096aff3f9a2090e6bd9f0d0c545c9190914e3dd767fcb24ee284" )+  , (148000 , hash256FromTextBE "00000000000008be94b219a94752bde6a6a1c5b9d72abf2aaab53df7d93c5fa6" )+  , (149000 , hash256FromTextBE "00000000000003365798631f867fccb0eb0ac014e8bf2bb628d9e7a4479786c2" )+  , (150000 , hash256FromTextBE "0000000000000a3290f20e75860d505ce0e948a1d1d846bec7e39015d242884b" )+  , (151000 , hash256FromTextBE "0000000000000a6331baea34235c05eb12ad238a7a61c878cdfe348e03608541" )+  , (152000 , hash256FromTextBE "0000000000000aca2b3a267dab498adc48afd15b60cbf21fa58dc26c86a6dc13" )+  , (153000 , hash256FromTextBE "0000000000000bc97a18a07ee50430131ff934a09e550424ad85726ac42c7ab8" )+  , (154000 , hash256FromTextBE "0000000000000a7446d1a63b8229670aa02d1d9fdfd729b89107fe5d88dacd8e" )+  , (155000 , hash256FromTextBE "0000000000000984d00c9f2d51e6ad2b601b7b1df06deadbf62be24e49b8f486" )+  , (156000 , hash256FromTextBE "00000000000002adfcffbd5f09744ae3b930597dd0ea684cd37b816783ba3762" )+  , (157000 , hash256FromTextBE "00000000000007ebf3a6b6ebcf46d550de83636fefd0a4eb91a5367f2880fd4c" )+  , (158000 , hash256FromTextBE "00000000000000e50d56f13c7ce64183386abcac63462ca745b711be27568f52" )+  , (159000 , hash256FromTextBE "0000000000000de25617d0cdbfce23b41289abb01c46b78b0f8128126929ec00" )+  , (160000 , hash256FromTextBE "000000000000066c6e629b2fb49c7fcc52b82fe9833f328e0c3943856facf231" )+  , (161000 , hash256FromTextBE "000000000000041db1574dba07ab482e4e0da4a47f85d2149205562c55115e23" )+  , (162000 , hash256FromTextBE "00000000000001a83f5b20cd132f38f792fc02a17eb14d494c780ea9d1c82acc" )+  , (163000 , hash256FromTextBE "0000000000000d66c125aa33593716ecbf6ef26b6f4c1d74998a87cf502bfc36" )+  , (164000 , hash256FromTextBE "00000000000005a38f162cf308edea0a0a5d000bdb2073cba2386ebb1df7a2cf" )+  , (165000 , hash256FromTextBE "00000000000008863b4603ab6886773685d259c8bfb90a26243f76adf167ac5a" )+  , (166000 , hash256FromTextBE "00000000000003b3402f35327d144a465f3768d6e6cb06cd8a2d8fc1328b2477" )+  , (167000 , hash256FromTextBE "0000000000000a082a56845388ddcab7797b70f91e720d883c6794c7dbc49901" )+  , (168000 , hash256FromTextBE "000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763" )+  , (169000 , hash256FromTextBE "000000000000099e9f2a34b7780d71b1234e08a60afe229dc0aa822f9d841610" )+  , (170000 , hash256FromTextBE "000000000000051f68f43e9d455e72d9c4e4ce52e8a00c5e24c07340632405cb" )+  , (171000 , hash256FromTextBE "000000000000070e7585c214a2a9628c61d5be904d318e2cf5b2418a611bc8fd" )+  , (172000 , hash256FromTextBE "0000000000000837e82c3a4ebe35a1d1d943e056234dba7c629922c6d4052d4c" )+  , (173000 , hash256FromTextBE "000000000000077ff3de38ce09c0279dfd7746d07a476d72dd6323ffa2520ef0" )+  , (174000 , hash256FromTextBE "0000000000000504d3e701deb624eee4370f50c3d688fd1c27be5bbef07d76dd" )+  , (175000 , hash256FromTextBE "00000000000006b975c097e9a5235de03d9024ddb205fd24dfcd508403fa907c" )+  , (176000 , hash256FromTextBE "00000000000004659b5b8602b2132b62973994079a1c828df6ef8d6427e4686b" )+  , (177000 , hash256FromTextBE "0000000000000359be6774f86dec526367120cbfc7dadf6392b6ddbda2af3a3e" )+  , (178000 , hash256FromTextBE "00000000000009eae2697a7aaf57e730b707b9f4530449c16d924d534d41f297" )+  , (179000 , hash256FromTextBE "00000000000008dddc8b99d4bf1d3977e4ea15fa9900454148637f0d3ea8e410" )+  , (180000 , hash256FromTextBE "00000000000004ff83b6c10460b239ef4a6aa320e5fffd6c7bcedefa8c78593c" )+  , (181000 , hash256FromTextBE "000000000000089558f2de87ee02ba250391e964683ac7d867e09f66e65ebbab" )+  , (182000 , hash256FromTextBE "000000000000068dce12903c1447e4c5b60311b61e443a25d5fc82c77f4f9a8f" )+  , (183000 , hash256FromTextBE "00000000000007be8b15bd307b7bc04aa22369e4079c12914a415f6c96ab2844" )+  , (184000 , hash256FromTextBE "000000000000060405a235c6b968ccb18fd6b3800ae9742c2524e28863367359" )+  , (185000 , hash256FromTextBE "00000000000008e4a049f80eb23c83c71f3f2bd34f7a50caf66c17511c40dc13" )+  , (186000 , hash256FromTextBE "000000000000072ede9629fd1fd1af3cc2baa0e637f1959f34884be0e160dd1c" )+  , (187000 , hash256FromTextBE "000000000000095cc058085cf175b5f61427e0b505ce6444f2abf359f7d5542e" )+  , (188000 , hash256FromTextBE "000000000000004cf0c72d6dedfde88ca4c3dae129563210072ee68acded0ab1" )+  , (189000 , hash256FromTextBE "00000000000000cb70eababc6787d13fd1c157f487145b97a15339336855d797" )+  , (190000 , hash256FromTextBE "0000000000000708bf3b261ffc963b6a768d915f9cfc9ec0a6c2a09969efad1a" )+  , (191000 , hash256FromTextBE "00000000000008d64e842b503d05d2e863dac578127f726832295ec92428c27c" )+  , (192000 , hash256FromTextBE "00000000000000af130d565291ba49208c546685c69b48a293aaf06387fc22ef" )+  , (193000 , hash256FromTextBE "000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317" )+  , (194000 , hash256FromTextBE "000000000000046242d4984ecf2217e9afa113f2835bffbff118f2df4d80b216" )+  , (195000 , hash256FromTextBE "0000000000000716889a0c9c7d773f1cfa65cdd6a60a2a9da18b55c9a1f14a33" )+  , (196000 , hash256FromTextBE "00000000000006ae59396d4a289e83fe1b9967630752a5799f064620af7836a9" )+  , (197000 , hash256FromTextBE "000000000000012094fc2ea1b763742c424736748a4fafe59fdcf0cc92e1c15b" )+  , (198000 , hash256FromTextBE "000000000000000f2ad431ff18ab1673d911395c8fa1f6801e054c5dcb54f8fb" )+  , (199000 , hash256FromTextBE "0000000000000397e4ff8f223d31783dc80b3720cd77fca21effd39709e0c9d9" )+  , (200000 , hash256FromTextBE "000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf" )+  , (201000 , hash256FromTextBE "0000000000000350eb681b2b81513489c5b0a74f456cd9c8a773b92d7b4d53d3" )+  , (202000 , hash256FromTextBE "00000000000003282fe1d5533e4275fd9f51e6ba0352ec01f32914e9fbaeaf55" )+  , (203000 , hash256FromTextBE "0000000000000575e3b569cbacc02e284a292fca7872b37c433bb3a03a5de4fd" )+  , (204000 , hash256FromTextBE "0000000000000423eb625dc140272ab97fea3ba6baf1dc56de77deabcc492872" )+  , (205000 , hash256FromTextBE "00000000000002cec464aa21f8aee916b90e6c5c836efa25e4057b74ca6b921c" )+  , (206000 , hash256FromTextBE "0000000000000130b815d40fd6d8851438cd21ac9e428615ba03a1285ef1374c" )+  , (207000 , hash256FromTextBE "00000000000004bdd54a303529953b64a85eee5099acb965f53b577a1ceeca44" )+  , (208000 , hash256FromTextBE "000000000000001db5a1515a5f8534c941b1628f60466e6b709b3b320254afff" )+  , (209000 , hash256FromTextBE "000000000000002a356ffbd715fb0cd8f1003e8024801ac4e25dd41ceed5ba0e" )+  , (210000 , hash256FromTextBE "000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e" )+  , (211000 , hash256FromTextBE "0000000000000345b371caa3f829cacbe2b4d38ecd15a5a02031efae79934d15" )+  , (212000 , hash256FromTextBE "00000000000003d906e4131c39f7655b72df40146d2967f5d75113a09610de61" )+  , (213000 , hash256FromTextBE "0000000000000242076c882281337e58a657471868d12083b1d2621f41d4ee2a" )+  , (214000 , hash256FromTextBE "00000000000003e6427f9fafa8b0e1af0859f15cea90d911f64445d296a2781a" )+  , (215000 , hash256FromTextBE "000000000000032f64cb76edfb654062e7b94b152bb6458a59b979fabf99012b" )+  , (216000 , hash256FromTextBE "00000000000001f79a2db15d0ec6d951729e044749372caf504679bba5b1e65e" )+  , (217000 , hash256FromTextBE "000000000000036d1e5c410c393017277f8ccb59cb30a9143e818e788ecd2515" )+  , (218000 , hash256FromTextBE "0000000000000569070e338293af66258adba29dcdd5f33212314dff752ff458" )+  , (219000 , hash256FromTextBE "00000000000004b359c1cb685f9e39223cb76ee91929a1d1311df50d1f939e7f" )+  , (220000 , hash256FromTextBE "000000000000002fdd2c741ed50bc3975a640ca419081711f30f553939641303" )+  , (221000 , hash256FromTextBE "000000000000034588ba0f8771e2f48b4a3f1451bad40de0e8e04a5b6e5a65ed" )+  , (222000 , hash256FromTextBE "00000000000002c752a481ce0c45450ab046e640d38d6532178721e7700d8148" )+  , (223000 , hash256FromTextBE "000000000000012d0917dbac896a60746683db6a3a540856b89a22c64621e18d" )+  , (224000 , hash256FromTextBE "0000000000000107ee276d037218bf1780dbf6d4256bd7e05c66ca133bbc9ac5" )+  , (225000 , hash256FromTextBE "000000000000013d8781110987bf0e9f230e3cc85127d1ee752d5dd014f8a8e1" )+  , (226000 , hash256FromTextBE "000000000000012c614cf477c3b155d339f29d565c0258f9846c2f4dd402ff9b" )+  , (227000 , hash256FromTextBE "0000000000000303d872c9bffdf46429c40b41522a9b7c7de21dd192fefefd98" )+  , (228000 , hash256FromTextBE "00000000000000efc4311c93fafbccedb6fdc682b566cba9519f1736b9788a67" )+  , (229000 , hash256FromTextBE "0000000000000246d7f05f608a407caf6c6d99681a4f3da8388d5bf799448d50" )+  , (230000 , hash256FromTextBE "000000000000012cfb19f5662707816e122ad60dd9b1cd646c6c9899be2c9667" )+  , (231000 , hash256FromTextBE "00000000000000649995b9008d249e39da05135109ad938abcc01ac7383a2815" )+  , (232000 , hash256FromTextBE "000000000000018f47636e1c3a946db77624880ae484ffb0233f5aac6316b3bb" )+  , (233000 , hash256FromTextBE "0000000000000110df141cfd908d5652c32a417c27187169aa1567b383ae0575" )+  , (234000 , hash256FromTextBE "00000000000000597f9263ea97bed4d3b10fbd55733a73bd1027f1a9b6c1451a" )+  , (235000 , hash256FromTextBE "0000000000000051324ab4bdc1899c671cd340681ea814b2d4b6e141efec52b0" )+  , (236000 , hash256FromTextBE "00000000000000f2f5e55e89dde082cecc9b4a46a10bbb4197f5e35b16612db5" )+  , (237000 , hash256FromTextBE "000000000000000efb4eeccb046960b9117ace9db6b3b24f016246d3bf1c403a" )+  , (238000 , hash256FromTextBE "000000000000010014007d4b51ab60063684665401e448c6b0b1971a7398a442" )+  , (239000 , hash256FromTextBE "000000000000009457d1c7aef43436d3b5f67542b343b4b57835912c9ca718fa" )+  , (240000 , hash256FromTextBE "000000000000000e7ad69c72afc00dc4e05fc15ae3061c47d3591d07c09f2928" )+  , (241000 , hash256FromTextBE "000000000000002a2562421dc7814786d3595249f50fd4cd1fb7c41b4a848fd2" )+  , (242000 , hash256FromTextBE "00000000000000c95233d37a8c78dff10afecb14060347151b7eb7a04a2a5a3c" )+  , (243000 , hash256FromTextBE "000000000000004701942914ec40b88654862cd042f04fae98b7f3603a26e264" )+  , (244000 , hash256FromTextBE "000000000000006ded1526017d5b87ca22e1bd0da3921872cc99e9ec77ee5166" )+  , (245000 , hash256FromTextBE "0000000000000023bacb560accb704fcb94665d02f191ce56410b11b93a6636f" )+  , (246000 , hash256FromTextBE "000000000000004c318a3ad2ebac28d140fada215b11f5b7d8e9151ff0b000af" )+  , (247000 , hash256FromTextBE "000000000000003d64d714747fbfb615e056f533386d162f0bf5e049a9b6e0b2" )+  , (248000 , hash256FromTextBE "000000000000004d945017c14b75a3a58a2aa6772cacbfcaf907b3bee6d7f344" )+  ]++--------------------------------------------------------------------------------++#else++--------------------------------------------------------------------------------+-- * testnet3++theGenesisBlock :: Hash256+theGenesisBlock = hash256FromTextBE "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"+  +theCheckpoints :: [(Int,Hash256)]+theCheckpoints =+  [ (0     , hash256FromTextBE "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" )+  , (1000  , hash256FromTextBE "00000000373403049c5fff2cd653590e8cbe6f7ac639db270e7d1a7503d698df" )+  , (2000  , hash256FromTextBE "0000000005bdbddb59a3cd33b69db94fa67669c41d9d32751512b5d7b68c71cf" )+  , (3000  , hash256FromTextBE "000000007f0eaec313e119f8ba4ad2df1d9a617771058f25d65c1263bec75589" )+  , (4000  , hash256FromTextBE "00000000185b36fa6e406626a722793bea80531515e0b2a99ff05b73738901f1" )+  , (5000  , hash256FromTextBE "0000000035eed3d69cc0a2b36d98c7a33dd5e3f1a84b2c67bdcda3d21a0b7989" )+  , (6000  , hash256FromTextBE "000000001ab69b12b73ccdf46c9fbb4489e144b54f1565e42e481c8405077bdd" )+  , (7000  , hash256FromTextBE "00000000049990027a54c46fe388b37b52f72e13d3f37f6ed9b6ef2c8d916ae6" )+  , (8000  , hash256FromTextBE "000000000d26c2f4c4f6f6a75d1684e5468cb92a44bd06329cab55763cce3389" )+  , (9000  , hash256FromTextBE "0000000001f63b2b5489687289206b903d58bf028376d440eefae72ea2d28edd" )+  , (10000 , hash256FromTextBE "000000000058b74204bb9d59128e7975b683ac73910660b6531e59523fb4a102" )+  , (11000 , hash256FromTextBE "000000004713e5c20f719a8406ceca735d9909912598e83e6b2fb5b5312701da" )+  , (12000 , hash256FromTextBE "000000004ad8f1f39fa3e3eb43791b9283337b09b06b4e75164dc5a9cb0262ff" )+  , (13000 , hash256FromTextBE "0000000035d1dfc578e7b043a7e44a46b9e41462633867595a83cc1037799373" )+  , (14000 , hash256FromTextBE "00000000163f4cc163aa78d53a201ebc18035d2ccc8cf53b7acb0c27026e9dee" )+  , (15000 , hash256FromTextBE "00000000b4a283fd078500ef347c1646985261f925a4d4b67c143cc1ba2a3b57" )+  , (16000 , hash256FromTextBE "00000000add42ab5ebe18c689fba7375f7f8b13c1aad57781c277e3bbe83811b" )+  , (17000 , hash256FromTextBE "000000000edc30d7c7e1247b08bb840be6b6c8e248ae924888fbf40fddd2fb8f" )+  , (18000 , hash256FromTextBE "000000000347b4e61758a4e52cc53c8acbdaf3a246ba97993109fbd0f9988dd1" )+  , (19000 , hash256FromTextBE "00000000e6e52f9e5ff18e40116974d56eacdc00730b72a67dc775511c4fb9fc" )+  , (20000 , hash256FromTextBE "0000000008ca11392fa91c4786e59823a002f4868bdb0c1385b12a2844cbc11f" )+  , (21000 , hash256FromTextBE "0000000000cc441542df3f00075dc5154e2ad72b00fe80e0f25bab8967810447" )+  , (22000 , hash256FromTextBE "0000000021a6d163d8b57e70cdb3db193c10fb1f9f30700c3f14bd23ce915b12" )+  , (23000 , hash256FromTextBE "0000000024e74f49548ad8529beba341e97d2c52e3004c4e14f3e2f9fd078141" )+  , (24000 , hash256FromTextBE "000000005e6c627c2126e1e52f42d2f4112a89952d6d7bacea0f5b56271afc7e" )+  , (25000 , hash256FromTextBE "0000000022b23de294af24d922fb3f1ed21521a8b3bd7716861dcb5310b1b525" )+  , (26000 , hash256FromTextBE "000000000e0153bc9f2ea52740cf7ce20a12678d76f811bd9c91f7acbb3862ca" )+  , (27000 , hash256FromTextBE "0000000005508307f6696fd8f3bc171776c9940c8e957a064985260571c4c3f4" )+  , (28000 , hash256FromTextBE "0000000013bb07c6fe855814fcc92661b45022c843960b7760433319cddfae9e" )+  , (29000 , hash256FromTextBE "000000000e66824d176dba835f8e71292b0a8cebace08d0cd34ce2c8a4b06433" )+  , (30000 , hash256FromTextBE "000000001036e9539cc6ed03d7b265618004138eb378ddb3921ee93ba30817ab" )+  , (31000 , hash256FromTextBE "00000000015593007156b5efd0511a782b111183e5257356725cfc57e0729232" )+  , (32000 , hash256FromTextBE "00000000027602f65768306573a0a421bf19bb53b0bfc8bd1c731621749e6eba" )+  , (33000 , hash256FromTextBE "000000008b4e4533408c6c5fcf103fc83577612911cef119a7ce8715925e838e" )+  , (34000 , hash256FromTextBE "00000000dfc7f64478db7356addeae9e926c43461a71dca813ccab9a2949ce03" )+  , (35000 , hash256FromTextBE "0000000001d9441d996c60e742198205fa5edd14b1984b3fde565bf7389d66dd" )+  , (36000 , hash256FromTextBE "0000000000ac6b824ebe5d10bbe9f23d076611a3e648f20f8acd815e2f6478a2" )+  , (37000 , hash256FromTextBE "0000000001313d89af0a36b32b459a81eecf1ecfc0cf766062a269b02896e3b1" )+  , (38000 , hash256FromTextBE "00000000015ca58fcbd28cdb69e5c4d07a23a7d09a8979ba267cbf2ecf4b3331" )+  , (39000 , hash256FromTextBE "000000000131dc31c6d4473e0c6ad1dc79bf7a3cf8630703236ceef708d6ea73" )+  , (40000 , hash256FromTextBE "000000007c0cee02104b825bf341213a71776e64ad9b60b2d77d3d13381515ce" )+  , (41000 , hash256FromTextBE "0000000062bdf5c12b0a539abdf387a2d1320fcbb59784a7d6d2ce6a3b962d3b" )+  , (42000 , hash256FromTextBE "00000000a4b494f70fc3e62ff414da13f86d685aa5eb3b38c19d18baa147b280" )+  , (43000 , hash256FromTextBE "000000000340c46ac512ccdb28bbc1d36d6b0be46988aca61ff15d88ecf89b02" )+  , (44000 , hash256FromTextBE "0000000031d4f882dbb1c3ad85aee9d32927e0f83237b4ca4b55b6e5e273b66d" )+  , (45000 , hash256FromTextBE "00000000024124f3d4e326e457fe82d5c298782555c3d68fb8be66afba9f3ed8" )+  , (46000 , hash256FromTextBE "0000000091f89670093c9c4a168f73316908efbf8c4afb17291a5c15e03b4c5a" )+  , (47000 , hash256FromTextBE "0000000002c301cde6832cfd28945572d554c77df85057ca46ea0aa0dacb7428" )+  , (48000 , hash256FromTextBE "00000000ad1acdfd226da1f29066cc2c2dd0410dcd88f8f88d99294629733bbc" )+  , (49000 , hash256FromTextBE "0000000000aa263967ef7d2b6bcd1f8e95e3f2b40384181b6bdbed8c9a126b4f" )+  , (50000 , hash256FromTextBE "00000000077eacdd2c803a742195ba430a6d9545e43128ba55ec3c80beea6c0c" )+  , (51000 , hash256FromTextBE "000000000ba96cf383b6a372e843d61d00f461b2e67c2181938ba8a2ebe7f1d2" )+  , (52000 , hash256FromTextBE "00000000066aac1dd21f3dedb1cec98293c33c11233608401b3bf735f2112ebd" )+  , (53000 , hash256FromTextBE "00000000037170891f74afbb85c1283720520a89a2ee25fd72fadcd2cc574248" )+  , (54000 , hash256FromTextBE "00000000033e84807f59b92cbfe43c82c664b83404fcb949ae8f1d86a8202010" )+  , (55000 , hash256FromTextBE "00000000005b2295d35c39caa2a62c76ea7119523a0462061b6b0727d7ec1f8b" )+  , (56000 , hash256FromTextBE "0000000051fab0ee72d4781947713a1a957e6817f4161e2288cfd601501c3ed9" )+  , (57000 , hash256FromTextBE "00000000808d2d15619a6e8865c6250e231fad3f77182c40d9f2aa7232c61266" )+  , (58000 , hash256FromTextBE "000000001a89db3d0d5e7df84cef95438aeaa4745570a9cf4ff44d873c1ee9a4" )+  , (59000 , hash256FromTextBE "0000000006377f7e522f7c731f33532b7a627dee47d0d6d0dbf8da2b372bdc5f" )+  , (60000 , hash256FromTextBE "00000000dae158690123e5cb4f90e3195de4c4fa2642e22f245082eb088d088b" )+  , (61000 , hash256FromTextBE "00000000095d668acb751ebfefa98840f66ce3ea7d99fc7ed70d67e55e9a0cfb" )+  , (62000 , hash256FromTextBE "00000000658f8146fca55cc8b7050643b6dd45007f72b0b86560e611d2c49c11" )+  , (63000 , hash256FromTextBE "00000000025b1b443158863cc93b32c0e43bf98e4be4a12c6137bd0f2c0ad1fa" )+  , (64000 , hash256FromTextBE "00000000077cd6b47ad02323ed3757ab062bd5a97abf9545c4209e1db8d4cae6" )+  , (65000 , hash256FromTextBE "00000000012dce3baf1128c235f593fe3fd5bee7f848ce4f563454d135f3707f" )+  , (66000 , hash256FromTextBE "00000000029b121a98fc62a8aa25261ab7d065da5fa31ebb651df43acd5b8eb3" )+  , (67000 , hash256FromTextBE "00000000056dcf9cd7c5114d24cbf58576cc6d838c7830b0c9d585c1552de252" )+  , (68000 , hash256FromTextBE "000000009b4558923abf0ad00dc089ab9f229525dd3611333a620db960922790" )+  , (69000 , hash256FromTextBE "0000000000bd56c1a80c1d3db6da5d1d37c902e407e07baae4a8278deb7234b7" )+  , (70000 , hash256FromTextBE "000000000203019be35824f1be0a82b70e45202a2ab60022dd234a3fea2fa32e" )+  , (71000 , hash256FromTextBE "0000000000b94e8d5e840527ddf3fca9b5b3fe3255e1fb47daadac7892f955f7" )+  , (72000 , hash256FromTextBE "00000000cef003deed105421d2136420f7b74b62cf05912ecdac3cab6ed50a5a" )+  , (73000 , hash256FromTextBE "000000007e374a119be162f9a21f66bbdb71254416ff0bc3c162bdf0a6c68768" )+  , (74000 , hash256FromTextBE "0000000069a561a7eff87256bf3e3e8b58163814a9de11f30578b5a612fea38c" )+  , (75000 , hash256FromTextBE "0000000016b1f8b72b7a740e3f8f303b2a44d10addfb066ba37767ec764c9e2c" )+  , (76000 , hash256FromTextBE "000000002f36edaf3271bab17900b69755c6824c984fdffb4e13cfbad9918714" )+  , (77000 , hash256FromTextBE "0000000009616a173c29f5c82199338c3bce328ed573a0b768b4aa5f00ba09bd" )+  , (78000 , hash256FromTextBE "000000000b7c28a1c812deeae9ddbed915f81fb88425f8c6871662e6b0cffdaf" )+  , (79000 , hash256FromTextBE "0000000002cd91dc9863c2a9ace998a5771cadfb85ef9dceb1f017886484d943" )+  , (80000 , hash256FromTextBE "0000000001be84d00475b5cf0148c3dfb9b7c2a770f788f22b0d96085b0f0e84" )+  , (81000 , hash256FromTextBE "00000000004bd0c0c59ceca80bb2a5df3d6bd697809000f9f3067771337ecc04" )+  , (82000 , hash256FromTextBE "00000000010af9d40d84b9e741983e08503bf6d63fb6bc1f254be4161479df14" )+  , (83000 , hash256FromTextBE "00000000a4692483b21ee998eda5a54b1c1aa72821bc6964dde22cc17f3dbe85" )+  , (84000 , hash256FromTextBE "00000000008a2bcb79ce22049cc3cc869e7dde0c373e49045b3843427dfc8cf6" )+  , (85000 , hash256FromTextBE "0000000043fabfda605e035cdd32cd09fd847ebfab8e3c15cffb1c8476fe66c7" )+  , (86000 , hash256FromTextBE "0000000014b156d14491cb1e36160aec95f74f7284c181b8869bf788c05a53a5" )+  , (87000 , hash256FromTextBE "000000001f4648f067bde96c39f86d5b53dfc7fde70109d490b19298c25a368f" )+  , (88000 , hash256FromTextBE "000000002555aa6f075ddc8858c107228fe86725c7efe20494decca92ed62c1f" )+  , (89000 , hash256FromTextBE "00000000054ee2c8dbc8b5f38aa514a6044d60f595141244bad704b369d1609a" )+  , (90000 , hash256FromTextBE "000000000d3e7211e75a47d91e651249392c3003aa05591a4690af7fe121fcca" )+  , (91000 , hash256FromTextBE "0000000003515610d951cac19f9701560c363ff53144c2a5b8d15bd6099c97fb" )+  , (92000 , hash256FromTextBE "0000000000eb029a63c26c284a1fc3fc997fd6ebfc31ede436ab3925ccc0d95c" )+  , (93000 , hash256FromTextBE "00000000010751e3472d86112a0a3d7e28274e6e13335ea7f14c6b2e57ab2d7f" )+  , (94000 , hash256FromTextBE "00000000003860c9c0368ec09285edbb634ddb6359fd1463d11808c653b24402" )+  , (95000 , hash256FromTextBE "00000000004f8dd4fa96de576defb7a6a53333994cccde06a6bc4750a5747e49" )+  , (96000 , hash256FromTextBE "0000000000f94ddbf44e481aa47fd2f4dc4c870960b2fd8331eb41bd8296f0d4" )+  , (97000 , hash256FromTextBE "0000000000096581c7c0fe4d15ea0212f1087fc79f3735a892ee262c384b3741" )+  ]++#endif++--------------------------------------------------------------------------------
+ Bitcoin/BlockChain/Load.hs view
@@ -0,0 +1,186 @@++-- | Load the blockchain from the files downloaded by the Satoshi client (bitcoin-qt)++{-# LANGUAGE CPP #-}+module Bitcoin.BlockChain.Load where++--------------------------------------------------------------------------------++import Data.Char ( isDigit )+import Data.List ( sort )++import Control.Monad+import Control.Applicative ( (<$>) )++import System.FilePath+import System.Directory+import System.IO++import Foreign+import Foreign.Marshal+import Foreign.Storable++import qualified Data.ByteString      as B+import qualified Data.ByteString.Lazy as L++import Data.Binary.Get+import Data.Binary.Put++import Bitcoin.Misc.Endian++import Bitcoin.BlockChain.Base+import Bitcoin.BlockChain.Parser++import Bitcoin.Script.Base++import Bitcoin.Protocol.Hash++--------------------------------------------------------------------------------++-- | A file and a position within the file, pointing to the magic bytes of a block+data BlockLocation = BlockLocation+  { _blockFile    :: FilePath+  , _blockFilePos :: !Word64+  } +  deriving (Eq,Ord,Show)           -- ord is needed for BiMap++--------------------------------------------------------------------------------+-- * where to find the blocks++-- | Guess where the blocks are on the harddisk (as downloaded by the Satoshi client)+blockDirectory :: IO FilePath+blockDirectory = do++#ifdef linux_HOST_OS+  let appname = "bitcoin"+#else+  let appname = "Bitcoin"+#endif++  appdir <- getAppUserDataDirectory appname+#ifdef WITH_TESTNET+  return (appdir </> "testnet3" </> "blocks")+#else+  return (appdir </> "blocks")+#endif++--------------------------------------------------------------------------------++-- | Given the directory containing the blocks (blk000xx.dat), we return the+-- list of the block files (full paths)+--+-- For example on windows the directory is+-- +-- > C:/Users/<username>/Application Data/Bitcoin/blocks/+--+blockFiles :: FilePath -> IO [FilePath]+blockFiles dir = +  do+    files <- getDirectoryContents dir+    return $ map prepend $ sort $ filter cond files+  where+    prepend fn = dir </> fn+    cond fn = and +        [ take 3 base == "blk" +        , ext == ".dat" +        , length base == 8 +        , all isDigit (drop 3 base) +        ]+      where+        (base,ext) = splitExtension fn++--------------------------------------------------------------------------------+-- * load block headers++-- | Loads all block headers lazily.+--+-- Note: this will also load the out-of-longest-chain blocks' headers+--+loadAllHeaders_ :: IO [BlockHeader]+loadAllHeaders_ = map snd <$> loadAllHeaders++-- | Loads all block headers lazily.+loadAllHeaders :: IO [(BlockLocation, BlockHeader)]+loadAllHeaders = blockDirectory >>= loadAllHeaders'++-- | The argument is the block directory+loadAllHeaders' :: FilePath -> IO [(BlockLocation, BlockHeader)]+loadAllHeaders' dir = do+  fnames <- blockFiles dir+  hdrs <- forM fnames $ \fn -> do+    raw <- L.readFile fn+    let blockheaders = runGet getBlockHeadersOnly raw  +        f posblh = (BlockLocation fn (fst posblh), snd posblh)+    return $ map f blockheaders+  return (concat hdrs)   ++--------------------------------------------------------------------------------+-- * load blocks++-- | Lazily loads all blocks. Note 1: all blocks won't fit the memory, so you +-- must process this lazy stream immediately and let the GC free the old blocks.+--+-- Note 2: this will also load the out-of-longest-chain blocks+--+loadAllBlocks_ :: IO [Block (Tx RawScript RawScript)]+loadAllBlocks_ = map snd <$> loadAllBlocks ++-- | This version also returns the block file and the position within the file+loadAllBlocks :: IO [(BlockLocation, Block (Tx RawScript RawScript))]+loadAllBlocks = blockDirectory >>= loadAllBlocks'++-- | The argument is the block directory+loadAllBlocks' :: FilePath -> IO [(BlockLocation, Block (Tx RawScript RawScript))]+loadAllBlocks' dir = do+  fnames <- blockFiles dir+  blks <- forM fnames $ \fn -> do+    raw <- L.readFile fn+    let blocks = runGet getBlocks raw  +        f posbl = (BlockLocation fn (fst posbl), snd posbl)+    return $ map f blocks+  return (concat blks)   ++--------------------------------------------------------------------------------++-- | Tries to load a block from a file at the given position+loadBlockAt :: BlockLocation -> IO (Block (Tx RawScript RawScript))+loadBlockAt (BlockLocation fpath fpos) = do +  withBinaryFile fpath ReadMode $ \h -> do+    hSeek h AbsoluteSeek (fromIntegral fpos)+    alloca $ \pmagic -> alloca $ \pblocklen -> do+      hGetBuf h pmagic    4+      hGetBuf h pblocklen 4+      magic    <- (swapByteOrderToLE <$> peek pmagic   ) :: IO Word32+      blocklen <- (swapByteOrderToLE <$> peek pblocklen) :: IO Word32+      if magic /= theMagicWordLE+        then error "loadBlockAt: magic word does not match"+        else do+          chunk <- L.hGet h (fromIntegral blocklen)+          return $ flip runGet chunk $ do+            header <- getBlockHeader+            ntxs   <- getVarInt+            txs    <- header `seq` (replicateM (fromIntegral ntxs) getTx_)+            return (Block header txs)++--------------------------------------------------------------------------------+-- * load transactions++-- | Lazily loads all transactions. Note 1: these won't fit the memory, so you +-- must process this lazy stream immediately and let the GC free the old blocks.+--+-- Note 2: this will also load the out-of-longest-chain blocks+--+loadAllTxs_ :: IO [Tx RawScript RawScript]+loadAllTxs_ = concatMap snd <$> loadAllTxs++-- | With this function, the list transactions are partitioned by blocks,+-- and the file and file position containing the block is also returned+loadAllTxs :: IO [(BlockLocation, [Tx RawScript RawScript])]+loadAllTxs = blockDirectory >>= loadAllTxs'++-- | The argument is the block directory+loadAllTxs' :: FilePath -> IO [(BlockLocation, [Tx RawScript RawScript])]+loadAllTxs' dir = map f <$> loadAllBlocks' dir where+  f (blockloc, block) = (blockloc, _blockTxs block)++--------------------------------------------------------------------------------
+ Bitcoin/BlockChain/Parser.hs view
@@ -0,0 +1,426 @@++-- | Parsing the blockchain (as stored by bitcoind in the @blkNNNNN.dat@ files)++{-# LANGUAGE CPP, BangPatterns #-}+module Bitcoin.BlockChain.Parser where++--------------------------------------------------------------------------------++import Data.Int+import Data.Word+import Data.Bits++import Control.Monad+import Control.Applicative++import qualified Data.ByteString      as B+import qualified Data.ByteString.Lazy as L++import System.IO ( stderr , hPutStrLn )     -- for extreme warning messages+import System.IO.Unsafe as Unsafe++import Data.Binary+import Data.Binary.Get+import Data.Binary.Put++import Bitcoin.Misc.HexString+import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.UnixTime++import Bitcoin.Protocol.Hash++import Bitcoin.BlockChain.Base+import Bitcoin.BlockChain.Tx+import Bitcoin.Script.Base ++--------------------------------------------------------------------------------+-- debugging++{- ++import Debug.Trace+import System.IO.Unsafe -- debugging++getTrace' :: (a -> String) -> Get a -> Get a +getTrace' fmsg action = liftM f action where+  f x = x `seq` (trace (fmsg x) x)++getTrace :: String -> Get a -> Get a +getTrace msg = getTrace' (const msg)++getDebug' :: Show b => (a -> b) -> Get a -> Get a+getDebug' f action = do+  pos <- bytesRead +  let fmsg x = ("at position " ++ show pos ++ ": " ++ show (f x))+  getTrace' fmsg action++getDebug :: Show b => b -> Get a -> Get a+getDebug user = getDebug' (const user) ++debugPrefix :: Show a => String -> Get a -> Get a+debugPrefix prefix = getDebug' (\x -> prefix ++ " = " ++ show x)++-}++--------------------------------------------------------------------------------++-- | Computes the hash of a block+computeBlockHash :: BlockHeader -> Hash256+computeBlockHash hdr = doHash256 $ B.concat $ L.toChunks $ runPut (putBlockHeader hdr)++-- | Computes the hash of a transaction+computeTxHash :: Tx RawScript RawScript -> Hash256+computeTxHash tx = doHash256 $ B.concat $ L.toChunks $ runPut (putTx tx)++serializeTx :: Tx RawScript RawScript -> RawTx+serializeTx tx = RawTx $ B.concat $ L.toChunks $ runPut (putTx tx)++--------------------------------------------------------------------------------++-- | Returns @(Just x)@ if the input could be parsed in full. Input is a strict ByteString+runGetMaybeB :: Get a -> B.ByteString -> Maybe a+runGetMaybeB p b = runGetMaybeL p (L.fromChunks [b])++-- | Returns @(Just x)@ if the input could be parsed in full. Input is a lazy ByteString+runGetMaybeL :: Get a -> L.ByteString -> Maybe a+runGetMaybeL p b = case runGetOrFail p b of+  Right (remaining,ofs,y) | L.null remaining  -> Just y+  _ -> Nothing++--------------------------------------------------------------------------------++-- | Note: We copy the bytestring so that the stream can be garbage collected later+-- ("fromByteString" copies from the @ByteString@ to the @ForeignPtr@ - actually I think two copies...)+getHash160 :: Get Hash160+getHash160 = getByteString 20 >>= \bs -> return $ fromByteString bs++getHash256 :: Get Hash256+getHash256 = getByteString 32 >>= \bs -> return $ fromByteString bs++putHash160 :: Hash160 -> Put +putHash160 h = putByteString $ toByteString h++putHash256 :: Hash256 -> Put +putHash256 h = putByteString $ toByteString h++--------------------------------------------------------------------------------++getUnixTimeStamp :: Get UnixTimeStamp+getUnixTimeStamp = UnixTimeStamp <$> getWord32le++putUnixTimeStamp :: UnixTimeStamp -> Put+putUnixTimeStamp (UnixTimeStamp ts) = putWord32le ts++--------------------------------------------------------------------------------++getBlockHeader :: Get BlockHeader+getBlockHeader = do+  ver    <- getWord32le+  prev   <- getHash256+  merkle <- getHash256+  stamp  <- getUnixTimeStamp+  diff   <- getWord32le+  nonce  <- getWord32le+  let bhdr = BlockHeader ver prev merkle stamp diff nonce zeroHash256+  return $ bhdr { _blkBlockHash = computeBlockHash bhdr } ++putBlockHeader :: BlockHeader -> Put +putBlockHeader (BlockHeader ver prev merkle stamp diff nonce _) = do+  putWord32le      ver+  putHash256       prev+  putHash256       merkle+  putUnixTimeStamp stamp+  putWord32le      diff+  putWord32le      nonce++--------------------------------------------------------------------------------++-- | The magic word in big-endian+theMagicWordBE :: Word32+#ifdef WITH_TESTNET+theMagicWordBE = 0x0B110907 +#else+theMagicWordBE = 0xf9beb4d9 +#endif++-- | The magic word in little-endian+theMagicWordLE :: Word32+#ifdef WITH_TESTNET+theMagicWordLE = 0x0709110b+#else+theMagicWordLE = 0xd9b4bef9+#endif++-- | Returns "Nothing" if there are not enough bytes left+getMaybeWord32be :: Get (Maybe Word32)+getMaybeWord32be = do+  isEmpty >>= \eof -> if eof then return Nothing else do+    a <- getWord8+    isEmpty >>= \eof -> if eof then return Nothing else do+      b <- getWord8+      isEmpty >>= \eof -> if eof then return Nothing else do+        c <- getWord8+        isEmpty >>= \eof -> if eof then return Nothing else do+          d <- getWord8+          return $ Just $ shiftL (fromIntegral a) 24+                        + shiftL (fromIntegral b) 16+                        + shiftL (fromIntegral c) 8+                        +        (fromIntegral d) ++--------------------------------------------------------------------------------++-- | returns the number of zero bytes which were skipped ('Left' if the input ends)+skipZeroBytes :: Get (Either Int Int)+skipZeroBytes = go 0 where+  go !n = do+    isEmpty >>= \e -> if e+      then return (Left n)+      else do+        w <- lookAhead getWord8+        case w of+          0 -> skip 1 >> go (n+1)+          _ -> return (Right n)++-- | returns the next found \"magic bytes\" (which may be invalid) and their position, unless the file ends.+nextMagicBytes :: Get (Maybe (Word32,Word64))+nextMagicBytes = do+  ei <- skipZeroBytes                   -- sometimes (often) bitcoind puts zeros between blocks+  case ei of+    Left  _ -> return Nothing           -- end of file+    Right _ -> do                       -- not end of file+      pos   <- fromIntegral <$> bytesRead+      magic <- getWord32be+      return $ Just (magic,pos)++isValidMagic :: Word32 -> Bool+isValidMagic magic = +  case magic of+#ifdef WITH_TESTNET+    0x0B110907 -> True+#else+    0xf9beb4d9 -> True+#endif+    _          -> False++--------------------------------------------------------------------------------++unsafeGetChunk :: Get (Maybe (Word64, L.ByteString))+unsafeGetChunk = do+  ei <- saferGetChunk +  case ei of+    Left  badmagic -> fail "BlockParser/unsafeGetChunk: invalid magic bytes"+    Right mb       -> return mb++-- | Unfortunately, it can happen in practice that the chunk length is completely wrong... +-- (or maybe simply the blockchain data is corrupted?)+--+-- In that case we have to parse the block to find the correct size (because the next block will start within this block...)+--+-- But normally we don't want to always parse the block when it is unnecessary... +saferGetChunk :: Get (Either Word32 (Maybe (Word64,L.ByteString)))+saferGetChunk = do+  mbmagic <- nextMagicBytes+  case mbmagic of+    Nothing            -> return (Right Nothing)+    Just (!magic,!pos) -> case isValidMagic magic of+      False -> return (Left magic)+      True  -> do+        len  <- getWord32le+        !lbs <- getLazyByteString (fromIntegral len)+        return $! Right $! Just $! (pos,lbs)++--------------------------------------------------------------------------------++getVarInt :: Get Word64+getVarInt = do+  h <- getWord8+  case h of+    0xfd -> fromIntegral <$> getWord16le +    0xfe -> fromIntegral <$> getWord32le +    0xff ->                  getWord64le +    _    -> return (fromIntegral h)++putVarInt :: Word64 -> Put+putVarInt w+  | w <= 0xfc       =                  putWord8    (fromIntegral w)+  | w <= 0xffff     = putWord8 0xfd >> putWord16le (fromIntegral w)+  | w <= 0xffffffff = putWord8 0xfe >> putWord32le (fromIntegral w)+  | otherwise       = putWord8 0xff >> putWord64le (fromIntegral w)++-- | Note: we copy the bytestring so that the stream can be garbage collected later+getVarString :: Get B.ByteString+getVarString = do+  l  <- getVarInt  +  bs <- getByteString (fromIntegral l)+  return (B.copy bs)    ++putVarString :: B.ByteString -> Put+putVarString bs = do+  putVarInt (fromIntegral $ B.length bs)+  putByteString bs++--------------------------------------------------------------------------------++-- | Parses a lot of something, until the input ends+getMany :: Get (Maybe a) -> Get [a]+getMany getOne = go where+  go = do+    empty <- isEmpty+    if empty +      then return []+      else do+        mbx  <- getOne+        case mbx of+          Nothing -> return []+          Just x -> do +            xs <- x `seq` go+            return (x:xs) ++forceList :: [a] -> [a]+forceList (x:xs) = x `seq` (x : forceList xs)+forceList [] = []++--------------------------------------------------------------------------------++getTx_ :: Get (Tx RawScript RawScript)+getTx_ = fst <$> getTx+    +getTx :: Get (Tx RawScript RawScript, RawTx)+getTx = do+  pos <- bytesRead +  (siz,tx0)  <- lookAhead $ do+    ver  <- getWord32le+    nIn  <- getVarInt+    ins  <- replicateM (fromIntegral nIn) getTxInput+    nOut <- getVarInt+    outs <- replicateM (fromIntegral nOut) getTxOutput+    locktime <- getWord32le+    let tx0 = Tx ver (forceList ins) (forceList outs) (parseLockTime locktime) zeroHash256+    pos2 <- bytesRead +    return (pos2-pos, tx0)+  rawtx <- getByteString (fromIntegral siz)+  let hash = doHash256 rawtx+  let tx   = tx0 { _txHash = hash }+  return (tx, RawTx rawtx)++getTxInput :: Get (TxInput RawScript)+getTxInput = do+  prevHash <- getHash256+  prevIdx  <- getWord32le+  script   <- getVarString+  seqno    <- getWord32le+  return (TxInput prevHash prevIdx (RawScript script) seqno)++getTxOutput :: Get (TxOutput RawScript)+getTxOutput = do+  value  <- fromIntegral <$> getWord64le+  script <- getVarString  +  return (TxOutput value (RawScript script))++--------------------------------------------------------------------------------++putTx :: Tx RawScript RawScript -> Put+putTx (Tx ver ins outs locktime _) = do+  putWord32le ver+  putVarInt (fromIntegral $ length ins )+  forM_ ins putTxInput+  putVarInt (fromIntegral $ length outs)+  forM_ outs putTxOutput+  putWord32le (marshalLockTime locktime)++putTxInput :: TxInput RawScript -> Put+putTxInput (TxInput prevHash prevIdx (RawScript script) seqno) = do+  putHash256   prevHash+  putWord32le  prevIdx +  putVarString script+  putWord32le  seqno++putTxOutput :: TxOutput RawScript -> Put+putTxOutput (TxOutput value (RawScript script)) = do+  putWord64le  (fromIntegral value)+  putVarString script++--------------------------------------------------------------------------------++warn :: String -> a -> a+warn msg next = this `seq` next where+  this = Unsafe.unsafePerformIO $ hPutStrLn stderr ("warning: " ++ msg)++-- | Returns the position, the block size (which usually equals the chunk size, /but not always/ unfortunately, which+-- complicates the parsing considerably... though now it seems its simply corruption of the block data) and the block+-- itself+--+getBlock :: Get (Maybe (Word64, Int, Block (Tx RawScript RawScript)))+getBlock = do+  -- mbchunk <- getChunk      +  mbchunk <- lookAhead unsafeGetChunk       -- bitcoin blockchain can contain errorneous chunk lenghts :((((+  case mbchunk of+    Nothing          -> return Nothing +    Just (pos,chunk) -> do+      let (size,pos,block) = flip runGet chunk $ do+            header <- getBlockHeader+            ntxs   <- getVarInt+            txs    <- header `seq` (replicateM (fromIntegral ntxs) getTx_)+            size   <- (fromIntegral <$> bytesRead) :: Get Int+            return (size,pos,Block header txs)+      skip (8+size)                                   -- sometimes the chunk size is wrong... 8 is magic + chunk length+      if (size == fromIntegral (L.length chunk)) +        then return $ Just $ (pos,size,block)+        else warn "chunk size does not equals block size" $ +               return $ Just $ (pos,size,block)++getBlocks :: Get [(Word64, Block (Tx RawScript RawScript))]+getBlocks = getMany $ do+  mb <- getBlock+  return $ case mb of+    Nothing              -> Nothing+    Just (pos,siz,block) -> Just (pos,block)++--------------------------------------------------------------------------------++parseBlockHeader :: L.ByteString -> BlockHeader+parseBlockHeader chunk = flip runGet chunk $ getBlockHeader++-- | This parses the next block header, and checks the magic bytes after the chunk.+--+-- In the case they are invalid, we also parse the full block, and consume the block,+-- /not the chunk/, since the chunk size can be invalid in same cases... +-- (though not it seems that instead simply the blockchain data was really corrupted, but+-- how can bitcoind survive that?)+--+getBlockHeaderOnly :: Get (Maybe (Word64, BlockHeader))+getBlockHeaderOnly = do++  mbchunk <- lookAhead $ unsafeGetChunk    +  case mbchunk of+    Nothing -> return Nothing+    Just (!pos,!chunk) -> do+      let !header   = parseBlockHeader chunk+          !chunksiz = fromIntegral (L.length chunk) :: Int+          skipchunk = skip $! (8+chunksiz)+      mbmagic <- lookAhead (skipchunk >> nextMagicBytes)+      header `seq` pos `seq` case mbmagic of+        Nothing            -> skipchunk >> (return $! Just (pos,header))+        Just (nextmagic,_) -> case isValidMagic nextmagic of+          True  -> skipchunk >> (return $! Just (pos,header))+          False -> warn "bad chunk size" $ do+            -- invalid chunk length, parse the block+            mbblock <- getBlock+            case mbblock of+              Nothing                -> return Nothing+              Just (!pos,siz,!block) -> return $! Just $! (pos, _blockHeader block)++getBlockHeadersOnly :: Get [(Word64,BlockHeader)]+getBlockHeadersOnly = getMany getBlockHeaderOnly  +                +--------------------------------------------------------------------------------++{-+test :: IO ()+test = do+  raw <- L.readFile "C:/Users/bkomuves/Application Data/Bitcoin/blocks/blk00022.dat"++  let blocks = runGet getBlocks raw  +  print (length blocks)+  print $ last $ blocks+-}
+ Bitcoin/BlockChain/Tx.hs view
@@ -0,0 +1,146 @@++-- | Transaction data structures++{-# LANGUAGE BangPatterns, DeriveFunctor, DeriveFoldable #-}+module Bitcoin.BlockChain.Tx where++--------------------------------------------------------------------------------++import Prelude++import Data.Int+import Data.Word+import Data.List ( mapAccumL , foldl' )+import Data.Maybe++import Control.Monad+import Control.Applicative+import Data.Foldable ( Foldable(..) )++import qualified Data.ByteString      as B+import qualified Data.ByteString.Lazy as L++import Data.Binary+import Data.Binary.Get++import Bitcoin.Misc.Bifunctor+import Bitcoin.Misc.HexString+import Bitcoin.Misc.UnixTime++import Bitcoin.Protocol.Hash++--------------------------------------------------------------------------------++-- | \"Raw\" transaction (basically a ByteString)+newtype RawTx = RawTx { unRawTx :: B.ByteString } deriving Eq++instance Show RawTx where+  showsPrec d (RawTx rs) = showParen (d>10) $ showString "RawTx " . shows (toHexStringChars rs)++--------------------------------------------------------------------------------++-- | Lock time+data LockTime+  = LockImmed                                -- ^ immediate (0x00000000)+  | LockBlock {-# UNPACK #-} !Int            -- ^ not until block #+  | LockTime  {-# UNPACK #-} !UnixTimeStamp  -- ^ not before+  deriving (Eq,Show)++parseLockTime :: Word32 -> LockTime+parseLockTime !w+  | w == 0         = LockImmed+  | w < 500000000  = LockBlock (fromIntegral w)       -- note: 500000000 is on 1985/11/04+  | otherwise      = LockTime (UnixTimeStamp w)++marshalLockTime :: LockTime -> Word32+marshalLockTime lt = case lt of+  LockImmed                   -> 0+  LockBlock n                 -> fromIntegral n+  LockTime  (UnixTimeStamp w) -> w++--------------------------------------------------------------------------------++-- | Transactions, parametrized by the script types+data Tx inscript outscript = Tx+  { _txVersion  :: {-# UNPACK #-} !Word32+  , _txInputs   :: [TxInput  inscript ]+  , _txOutputs  :: [TxOutput outscript]+  , _txLockTime :: !LockTime+  , _txHash     :: Hash256      -- ^ note: the hash is not actually stored in the blockchain; but it is computed when the transaction is loaded+  }+  deriving (Eq,Show)++--------------------------------------------------------------------------------++instance BiFunctor Tx where+  fmapFst  f   (Tx ver ins outs lock hash) = Tx ver (map (fmap f) ins) outs lock hash+  fmapSnd    g (Tx ver ins outs lock hash) = Tx ver ins (map (fmap g) outs) lock hash+  fmapBoth f g (Tx ver ins outs lock hash) = Tx ver (map (fmap f) ins) (map (fmap g) outs) lock hash++instance BiFoldable Tx where+  bifoldl f g x0 (Tx ver ins outs lock hash)    = Prelude.foldl g (Prelude.foldl f x0 (map _txInScript  ins )) (map _txOutScript outs)+  bifoldr f g    (Tx ver ins outs lock hash) x0 = Prelude.foldr f (Prelude.foldr g x0 (map _txOutScript outs)) (map _txInScript  ins )++instance BiTraversable Tx where+  mapAccumLFst f acc (Tx ver ins outs lock hash) = (acc', Tx ver ins' outs lock hash) where+    (acc', ins' ) = mapAccumL h acc ins+    h a txin  = let (a',y) = f a (_txInScript  txin ) +                in  (a', txin  { _txInScript  = y })++  mapAccumLSnd g acc (Tx ver ins outs lock hash) = (acc', Tx ver ins outs' lock hash) where+    (acc', outs') = mapAccumL h  acc outs+    h a txout = let (a',y) = g a (_txOutScript txout) +                in  (a', txout { _txOutScript = y })++--------------------------------------------------------------------------------++data TxInput inscript = TxInput +  { _txInPrevOutHash :: {-# UNPACK #-} !Hash256       -- ^ hash of the previous transaction+  , _txInPrevOutIdx  :: {-# UNPACK #-} !Word32        -- ^ which output in that transaction+  , _txInScript      :: !inscript                     -- ^ signature script+  , _txInSeqNo       :: {-# UNPACK #-} !Word32        -- ^ sequence number is normally 0xffffffff, but only matters if locktime is nonzero; vica versa if all TxIn have 0xffffffff, then locktime doesn't matter+  }+  deriving (Eq,Show,Functor)++data TxOutput outscript = TxOutput+  { _txOutValue   :: {-# UNPACK #-} !Int64            -- ^ output amount (in satoshis)+  , _txOutScript  :: !outscript                       -- ^ public key script+  } +  deriving (Eq,Show,Functor)+    +--------------------------------------------------------------------------------++-- | Computes the transaction fee, in satoshis. +--+-- We return an 'Integer' so that+-- this can be used to check the validity of a transaction. See CVE-2010-5139 vulnerability:+-- <https://en.bitcoin.it/wiki/Common_Vulnerabilities_and_Exposures#CVE-2010-5139>+--+txFee :: Tx (Tx a b) c -> Integer+txFee txExt = totalInput - totalOutput where++  totalOutput = sum' [ fromIntegral (_txOutValue txout) | txout <- _txOutputs txExt ]+  totalInput  = sum' [ inputValue txin | txin <- _txInputs txExt ]++  inputValue :: TxInput (Tx a b) -> Integer+  inputValue txin = fromIntegral+                  $ _txOutValue ( (_txOutputs $ _txInScript txin) !! (fromIntegral $ _txInPrevOutIdx txin) ) ++  sum' :: [Integer] -> Integer+  sum' = Data.List.foldl' (+) 0++--------------------------------------------------------------------------------++-- | We recognize coinbase transactions.+isCoinBaseTx :: Tx a b -> Bool+isCoinBaseTx = isJust . isCoinBaseTx'++-- | We recognize coinbase transactions, and return the coinbase data.+isCoinBaseTx' :: Tx a b -> Maybe a+isCoinBaseTx' tx = case _txInputs tx of +  [inp] -> if _txInPrevOutHash inp == zeroHash256 +             then Just (_txInScript inp)+             else Nothing +  _     -> Nothing+  +--------------------------------------------------------------------------------
+ Bitcoin/BlockChain/TxLookup.hs view
@@ -0,0 +1,349 @@+
+-- | An simple but relatively compact data structure for looking up transactions in the blockchain
+-- (TODO: replace these data structures by a better one...)
+--
+-- Blockchain stats (as of 2013): 
+--
+-- * block heigh currently ~270,000, so 20 bits for that is enough for a while, 23 enough for ever basically.
+--
+-- * number of transaction is currently ~27,000,000 (2016 data: ~162 million)
+--
+-- * average number of transactions per block is currently ~300-350 (2016: ~2000)
+--
+-- Idea: index into a large dense array by the first few (say 24 or 26) bits of the hash, 
+-- then store a list (vector) of the possible block indices there. With 24 bit index there will be in 
+-- average 2 blocks per tx, of course sometimes more sometimes less.
+--
+-- An IOArray -> 16M pointers, on 32 bit that is 64M
+-- 30 million entries tx-s => 30 million entries, for short lists approx 1 word/entry, so let's say 150-200M on 32 bit.
+--
+-- On 64 bit we have more memory so it's ok :)
+--
+-- 2016 update: you will need more memory to store even 32 bits per transaction...
+-- The most compact estimation already gives 1+ gigs...
+--
+
+--
+
+{-# LANGUAGE UnboxedTuples, MagicHash, BangPatterns #-}
+module Bitcoin.BlockChain.TxLookup where
+
+--------------------------------------------------------------------------------
+
+import Control.Monad
+
+import Data.Bits
+import Data.Word
+import Data.List ( find )
+import Data.Maybe
+
+import Foreign
+import System.IO.Unsafe as Unsafe
+
+import GHC.Prim
+import GHC.Exts
+import GHC.Int
+
+import Data.Array
+import Data.Array.IO
+import Data.Array.MArray
+import Data.Array.Unsafe
+
+import Control.DeepSeq
+-- import GHC.DataSize
+
+import Bitcoin.Protocol.Hash
+
+import Bitcoin.BlockChain.Base
+import Bitcoin.BlockChain.Load
+import Bitcoin.BlockChain.Chain
+import Bitcoin.BlockChain.Tx
+
+import Bitcoin.Script.Base
+import Bitcoin.Script.Run ( checkTransaction )
+
+--------------------------------------------------------------------------------
+-- * interal stuff
+
+{-
+
+newtype Word24 = Word24 { fromWord24 :: Word32 } deriving (Eq,Ord,Show)
+
+instance Storable Word24 where
+  alignment _ = 1
+  sizeOf _    = 3
+  peek ptr = do
+    lo <- peek (castPtr  ptr              :: Ptr Word16)
+    hi <- peek (castPtr (ptr `plusPtr` 2) :: Ptr Word8 )              -- little endian
+    return $ Word24 $ fromIntegral lo + shiftL (fromIntegral hi) 16
+  poke ptr (Word24 w) = do
+    let lo = fromIntegral (w .&. 0xffff) :: Word16
+        hi = fromIntegral (shiftR w 16)  :: Word8
+    poke (castPtr  ptr              :: Ptr Word16) lo
+    poke (castPtr (ptr `plusPtr` 2) :: Ptr Word8 ) hi              -- little endian
+
+highestBit :: Word24 -> Bool
+highestBit (Word24 w) = (w .&. 0x800000) > 0
+
+lowerBits :: Word24 -> Int
+lowerBits (Word24 w) = fromIntegral (w .&. 0x7fffff)
+
+minus1 :: Word24
+minus1 = Word24 0xffffff
+
+-}
+
+--------------------------------------------------------------------------------
+
+toWord# :: Int -> Word#
+toWord# !(I# i) = int2Word# i
+
+fromWord# :: Word# -> Int
+fromWord# w = I# (word2Int# w)
+
+-- | A list which is more compact for a small number of elements
+data CompactList
+  = NilList
+  | OneList !Word#
+  | TwoList !Word# !Word#
+  | ThrList !Word# !Word# !Word#
+  | FouList !Word# !Word# !Word# !Word#
+  | GenList !IndexList
+
+instance NFData CompactList where
+  rnf cl = case cl of
+    NilList  -> ()
+    OneList _ -> ()
+    TwoList _ _ -> ()
+    ThrList _ _ _ -> ()
+    FouList _ _ _ _ -> ()
+    GenList il -> rnf il
+
+toCompactList :: [Int] -> CompactList
+toCompactList xs = case xs of
+  []        -> NilList
+  [x]       -> OneList (toWord# x)
+  [x,y]     -> TwoList (toWord# x) (toWord# y)
+  [x,y,z]   -> ThrList (toWord# x) (toWord# y) (toWord# z)
+  [x,y,z,w] -> FouList (toWord# x) (toWord# y) (toWord# z) (toWord# w)
+  _         -> GenList (toIndexList xs)
+
+fromCompactList :: CompactList -> [Int]
+fromCompactList cl = case cl of
+  NilList         -> []
+  OneList u       -> [ fromWord# u ]
+  TwoList u v     -> [ fromWord# u , fromWord# v ]
+  ThrList u v w   -> [ fromWord# u , fromWord# v , fromWord# w ]
+  FouList u v w z -> [ fromWord# u , fromWord# v , fromWord# w , fromWord# z ]
+  GenList il      -> fromIndexList il
+
+consCompactList :: Int -> CompactList -> CompactList 
+consCompactList x rest = case rest of
+    NilList       -> OneList (toWord# x) 
+    OneList y     -> TwoList (toWord# x) y  
+    TwoList y z   -> ThrList (toWord# x) y z 
+    ThrList y z w -> FouList (toWord# x) y z w
+    FouList {}    -> GenList $ toIndexList $ (x:) $ fromCompactList rest
+    GenList il    -> GenList $ consIndexList x il
+
+--------------------------------------------------------------------------------
+
+-- | Hack for a more compact list structure. Last element of the list has the highest bit set to 1.
+-- Empty list has all bits set to 1. Space consumption is 3 words per list entry instead of 5 for normal lists.
+-- 
+-- Note: compiling with -O1 seeems to create larger memory consumption than -O0 and -O2 ?!?!
+data IndexList = IndexList !Word# IndexList   
+
+instance NFData IndexList where
+  rnf (IndexList !w rest) = (if not (isNullIndexList rest) then rnf rest else ()) `seq` ()
+
+intToBool# :: Int# -> Bool
+intToBool# i = case i of 
+  0# -> False
+  _  -> True
+
+nullIndexList :: IndexList
+nullIndexList = IndexList (int2Word# 0xffffffff#) nullIndexList
+
+isNullIndexList :: IndexList -> Bool
+isNullIndexList (IndexList w _) = intToBool# (w `eqWord#` (int2Word# 0xffffffff#))
+
+isSingletonIndexList :: IndexList -> Bool
+isSingletonIndexList (IndexList w _) = not $ intToBool# ((w `and#` (int2Word# 0x80000000#)) `eqWord#` (int2Word# 0#))
+
+--------------------------------------------------------------------------------
+
+consIndexList :: Int -> IndexList -> IndexList
+consIndexList x rest = 
+  if isNullIndexList rest
+    then IndexList (w0 `or#` (int2Word# 0x80000000#)) rest
+    else IndexList  w0                                rest
+  where
+    !(W# w0) = fromIntegral x
+
+toIndexList :: [Int] -> IndexList
+toIndexList = go where
+  go (x : xs) = IndexList w (go xs) where
+                   !w = (w0 `or#` (if null xs then (int2Word# 0x80000000#) else (int2Word# 0#)))
+                   !(W# w0) = fromIntegral x
+  go []       = nullIndexList
+
+fromIndexList :: IndexList -> [Int]
+fromIndexList il@(IndexList !w rest) = 
+  if isNullIndexList il 
+    then []
+    else go il 
+  where 
+   go (IndexList w rest) = if intToBool# ((w `and#` (int2Word# 0x80000000#)) `eqWord#` (int2Word# 0#))
+     then (fromIntegral $ W# (w                               )) : go rest
+     else (fromIntegral $ W# (w `and#` (int2Word# 0x7fffffff#))) : []     
+
+--------------------------------------------------------------------------------
+
+newtype TxLookup = TxLookup (IOArray Word32 CompactList)
+
+newEmptyTxLookup :: IO TxLookup
+newEmptyTxLookup = do
+  arr <- Data.Array.MArray.newArray (0,0xffffff) NilList
+  return $ TxLookup arr
+
+insertIntoTxLookup' :: Word32 -> Int -> TxLookup -> IO ()
+insertIntoTxLookup' !key_ !value (TxLookup !arr) = do
+  let !key = key_ .&. 0x00ffffff    -- 24 bits
+  !old <- readArray arr key
+  unless (elem value $ fromCompactList old) $ writeArray arr key $! consCompactList value old
+  return () 
+  
+txLookupList' :: Word32 -> TxLookup -> IO [Int]
+txLookupList' key_ (TxLookup arr) = do
+  let key = key_ .&. 0x00ffffff    -- 24 bits
+  list <- readArray arr key
+  return $ fromCompactList list
+
+--------------------------------------------------------------------------------
+
+{- ForeignPtr version
+first24Bits :: Hash256 -> Word32
+first24Bits hash = Unsafe.unsafePerformIO (first24BitsIO hash)
+
+-- | Depends on the endianness, but it's used for a memory only structure anyway
+first24BitsIO :: Hash256 -> IO Word32
+first24BitsIO (Hash256 fptr) = do
+  w32 <- (withForeignPtr fptr $ \ptr -> peek (castPtr ptr :: Ptr Word32))
+  return (w32 .&. 0xffffff)
+-}
+
+first24Bits :: Hash256 -> Word32
+first24Bits (Hash256 !w1 _ _ _) = fromIntegral (w1 .&. 0xffffff)
+
+--------------------------------------------------------------------------------
+
+insertIntoTxLookup :: Hash256 -> Int -> TxLookup -> IO ()
+insertIntoTxLookup !hash !blockidx !table = insertIntoTxLookup' (first24Bits hash) blockidx table 
+
+txLookupList :: Hash256 -> TxLookup -> IO [Int]
+txLookupList !hash !table = txLookupList' (first24Bits hash) table
+
+--------------------------------------------------------------------------------
+-- * Build and use the 'TxLookup' table
+
+-- | Builds a 'TxLookup' table
+buildTxLookupTable :: ChainTable -> IO TxLookup
+buildTxLookupTable chTable = do
+  txlkptable <- newEmptyTxLookup
+
+  let (a,b) = bounds (_tableLongest chTable)
+  forM_ [a..b] $ \(!blkIdx) -> do
+    block <- loadBlockAt $! _chainLocation (_tableLongest chTable ! blkIdx)
+
+    -- when (mod blkIdx 500 == 0) $ print blkIdx   -- hPrint stderr blkIdx
+
+    let txs = _blockTxs block
+    forM_ txs $ \(!tx) -> insertIntoTxLookup (_txHash tx) blkIdx txlkptable
+
+  return txlkptable
+
+-- | Looks up a transaction by hash. First we check the 'TxLookup' table, then we load the possible blocks (if any),
+-- parse them and check them for the given transaction. We also return the block height.
+txLookup :: ChainTable -> TxLookup -> Hash256 -> IO (Maybe (Int, Tx RawScript RawScript))
+txLookup chTable txTable hash = do
+  possible <- txLookupList hash txTable 
+  results <- forM possible $ \blkIdx -> do
+    let loc = _chainLocation (_tableLongest chTable ! blkIdx)
+    block <- loadBlockAt loc
+    let txs = _blockTxs block
+    return $ case find (\tx -> hash == _txHash tx) txs of
+      Nothing -> Nothing
+      Just tx -> Just (blkIdx,tx)
+  case catMaybes results of
+    []    -> return $ Nothing
+    [!tx] -> return $ Just tx 
+    _     -> error "txLookup: fatal error, multiple transactions found in with the same hash"
+
+-- | does not return the block height
+txLookup_ :: ChainTable -> TxLookup -> Hash256 -> IO (Maybe (Tx RawScript RawScript))
+txLookup_ cht txt = liftM (liftM snd) . txLookup cht txt 
+
+--------------------------------------------------------------------------------
+
+-- | Given a transaction, we load all the previous transactions from the disk (using the cache),
+-- and add them the Tx structure (abusing the parametrized script field). The result can
+-- then be fed to 'checkTransaction'.
+--
+loadPrevTxs :: ChainTable -> TxLookup -> Tx a b -> IO (Tx (Tx RawScript RawScript, a) b)
+loadPrevTxs chTable txTable oldTx = 
+  do
+    newInputs <- mapM worker (_txInputs oldTx)
+    return $! oldTx { _txInputs = newInputs } 
+  where  
+    lkp = txLookup_ chTable txTable 
+    worker inp@(TxInput prevhash previdx script seqno) = do
+      mbprevtx <- lkp prevhash 
+      let !prevtx = case mbprevtx of
+            Just tx -> tx
+            Nothing -> error $ "loadPrevTxs: fatal error: previous tx not found; hash = " ++ show prevhash
+      return $! inp { _txInScript = (prevtx,script) }      
+
+--------------------------------------------------------------------------------
+
+-- | Checks a transaction. Note: this automatically accepts coinbase transactions 
+-- (does not check that that sum of reward and fees is the amount, since it has no access to the fees)
+--
+checkTx :: ChainTable -> TxLookup -> Tx RawScript RawScript -> IO (Either String Bool)
+checkTx chTable txTable tx =
+  case (isCoinBaseTx tx) of
+    True  -> return (Right True)
+    False -> do    
+      txExt <- loadPrevTxs chTable txTable tx 
+      return $ checkTransaction txExt 
+
+-- | Checks a transaction given by its hash
+checkTxByHash :: ChainTable -> TxLookup -> Hash256 -> IO (Either String Bool)
+checkTxByHash chTable txTable txid = do
+  mbtx <- txLookup_ chTable txTable txid
+  case mbtx of
+    Nothing -> error $ "checkTxByHash: tx not found (hash = " ++ show txid ++ ")"
+    Just tx -> checkTx chTable txTable tx
+
+--------------------------------------------------------------------------------
+
+{- 
+
+testCompactList = and
+  [ and [ (fromCompactList $                      toCompactList [1..n] ) ==     [1..n] | n<-[0..77] ]
+  , and [ (fromCompactList $ consCompactList 666 (toCompactList [1..n])) == 666:[1..n] | n<-[0..77] ]
+  ]
+
+main = do
+  forM_ [0..(10::Int)] $ \n -> do
+    let xs = [(1::Int)..n] 
+        il = toIndexList   xs :: IndexList
+        cl = toCompactList xs :: CompactList
+        b1 = xs == fromIndexList   il
+        b2 = xs == fromCompactList cl
+    k1 <- recursiveSize $!! xs
+    k2 <- recursiveSize $!! il
+    k3 <- recursiveSize $!! cl
+    print ( (length xs , k1,k2,k3, b1 , b2) :: (Int,Int,Int,Int,Bool,Bool) )
+
+-}  
+ Bitcoin/BlockChain/Unspent.hs view
@@ -0,0 +1,84 @@++-- | Build a table of unspent transactions outputs (the transactions are assumed to be valid!)++{-# LANGUAGE CPP, BangPatterns #-}+module Bitcoin.BlockChain.Unspent where++--------------------------------------------------------------------------------++import Control.Monad++import Data.Array+import Data.Maybe+import Data.Word+import Data.Int++import Data.Set (Set) ; import qualified Data.Set as Set+import Data.Map (Map) ; import qualified Data.Map as Map++import Data.IORef++import Bitcoin.Protocol++import Bitcoin.BlockChain.Base+import Bitcoin.BlockChain.Load+import Bitcoin.BlockChain.Tx+import Bitcoin.BlockChain.Cache+import Bitcoin.BlockChain.Chain+import Bitcoin.BlockChain.TxLookup++import Bitcoin.Script.Base++--------------------------------------------------------------------------------++-- | An unspent transaction output+data UnspentOutput = UnspentOutput+  { _unspentTxId    :: !Hash256                 -- ^ the transaction id+  , _unspentTxOut   :: {-# UNPACK #-} !Word32   -- ^ which output of that transaction +  }+  deriving (Eq,Ord,Show)++{-+data Unspent+  , _unspentAmount  :: !Amount               -- ^ the amount of bitcoins unspent+  , _unspentAddress :: !(Maybe Address)      -- ^ if it is on output to an address, we also store the address+  } +-}++--------------------------------------------------------------------------------++-- | Builds a table of unspent transactions outputs. Note that all transactions are assumed to be valid!+-- So you have to check them before, to be safe.+--+buildUnspentTable :: ChainTable -> TxLookup -> IO (Map UnspentOutput Amount)+buildUnspentTable chTable txTable = do++  let txLkp :: Hash256 -> IO (Maybe (Tx RawScript RawScript))+      txLkp = txLookup_ chTable txTable ++  let (a,b) = bounds (_tableLongest chTable)++  unspent <- newIORef Map.empty+  forM_ [a..b] $ \(!blkIdx) -> do+    block <- loadBlockAt $! _chainLocation (_tableLongest chTable ! blkIdx)++    -- As far as I know, it is required that a transaction which spends another transaction+    -- in the same block comes later within the block, thus this is safe to do:++    forM_ (_blockTxs block) $ \(!tx) -> do+      let !txhash = _txHash tx      +      forM_ (_txInputs  tx) $ \(TxInput !prevhash !prevout _ _) -> +        myModifyIORef' unspent $ Map.delete (UnspentOutput prevhash prevout)+      forM_ (zip [0..] (_txOutputs tx)) $ \(outidx, TxOutput !amount _) -> +        myModifyIORef' unspent $ Map.insert (UnspentOutput txhash   outidx ) (Amount $ fromIntegral amount)++  readIORef unspent++  where+    -- it is only present in newer versions of the base library...+    myModifyIORef' :: IORef a -> (a -> a) -> IO ()+    myModifyIORef' ref f = do+      !old <- readIORef ref+      writeIORef ref $! (f old)++--------------------------------------------------------------------------------
+ Bitcoin/Crypto/EC.hs view
@@ -0,0 +1,15 @@++-- | This module re-exports some of the Elliptic Curve submodules++module Bitcoin.Crypto.EC+  ( module Bitcoin.Crypto.EC.Curve+  , module Bitcoin.Crypto.EC.Projective+  , module Bitcoin.Crypto.EC.Key+  , module Bitcoin.Crypto.EC.DSA+  )+  where+       +import Bitcoin.Crypto.EC.Curve+import Bitcoin.Crypto.EC.Projective+import Bitcoin.Crypto.EC.Key+import Bitcoin.Crypto.EC.DSA
+ Bitcoin/Crypto/EC/Curve.hs view
@@ -0,0 +1,217 @@++-- | The @secp256k1@ Elliptic Curve.+--+-- At the moment somewhat slow :(+--+-- References:+--+--  * <http://en.wikipedia.org/wiki/Elliptic_curve_cryptography>+--+--  * <http://www.secg.org/collateral/sec2_final.pdf>+--+{-# LANGUAGE CPP, BangPatterns #-}+module Bitcoin.Crypto.EC.Curve where++--------------------------------------------------------------------------------++import Control.Monad++import Prelude hiding ( sqrt )++import Data.Char+import Data.Bits+import Data.Word+import Data.Maybe++import qualified Data.ByteString as B++import System.Random++import Bitcoin.Misc.HexString+import Bitcoin.Misc.BigInt+import Bitcoin.Misc.OctetStream++import Bitcoin.Protocol.Hash             +import Bitcoin.Crypto.FiniteField.Fast.Fp  hiding ( secp256k1_p )+import Bitcoin.Crypto.FiniteField.Naive.Fn hiding ( secp256k1_n )++--------------------------------------------------------------------------------++-- | A point on the elliptic curve secp256k1+data ECPoint +  = ECPoint !Fp !Fp    -- ^ a \"regular\" element of the elliptic curve+  | ECInfinity         -- ^ the point at infinity is the unit element+  deriving (Eq,Show)++mkECPoint :: Integer -> Integer -> ECPoint+mkECPoint x y = ECPoint (toFp x) (toFp y)++isECOnCurve :: ECPoint -> Bool+isECOnCurve ep = case ep of+  ECInfinity  -> True+  ECPoint x y -> (y2 == x3 + 7) where+    y2 = y*y+    x2 = x*x+    x3 = x2*x++--------------------------------------------------------------------------------+-- * secp256k1 curve parameters. ++-- | Parameters of the secp256k1 elliptic curve.+-- +--  * p is the order of the prime field we are working over+--  * a and b are the parameters in the curve equation @y^2 = x^3 + a*x + b@ (but @a=0@ here)+--  * G is the generator of the subgroup in the curve+--  * n is the order of G, equivalently the size of the subgroup+--  * H is the cofactor (size of the curve divided by the size of the subgroup)+--+-- See <http://www.secg.org/collateral/sec2_final.pdf>+secp256k1_p :: Integer++secp256k1_a, secp256k1_b, secp256k1_Gx, secp256k1_Gy, secp256k1_n, secp256k1_h :: Integer++secp256k1_p  = 115792089237316195423570985008687907853269984665640564039457584007908834671663+secp256k1_Gx =  55066263022277343669578718895168534326250603453777594175500187360389116729240+secp256k1_Gy =  32670510020758816978083085130507043184471273380659243275938904335757337482424+secp256k1_n  = 115792089237316195423570985008687907852837564279074904382605163141518161494337++secp256k1_a  = 0 +secp256k1_b  = 7 +secp256k1_h  = 1 ++-- | G is the base point, that is the generator; @E = { G^i | i\in Z } = { G^i | i<-[1..n] }@+secp256k1_G :: ECPoint+secp256k1_G = ECPoint (fromInteger secp256k1_Gx) (fromInteger secp256k1_Gy)++--------------------------------------------------------------------------------+-- specification of the curve directly from the SEC+-- however we opt for hardcoded constants intead of parsing the hex strings++{-++printSecp256k1 :: IO ()+printSecp256k1 = do+  putStrLn $ "p  = " ++ show _secp256k1_p+  putStrLn $ "a  = " ++ show _secp256k1_a+  putStrLn $ "b  = " ++ show _secp256k1_b+  putStrLn $ "Gx = " ++ show _secp256k1_Gx+  putStrLn $ "Gy = " ++ show _secp256k1_Gy+  putStrLn $ "n  = " ++ show _secp256k1_n+  putStrLn $ "h  = " ++ show _secp256k1_h++-- | We are working over the finite field of order p (p being a prime)+-- @p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1@+_secp256k1_p :: Integer+_secp256k1_p = parseSecInt "FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F"++-- | The curve is @y^2 = x^3 + ax + b = x^3 + b@ in this case+_secp256k1_a = 0 :: Integer+_secp256k1_b = 7 :: Integer++-- | uncompressed format: 04 <x> <y>, 1+32+32=65 bytes, x and y big-endian+_secp256k1_G_uncompr = parseSecData $+  "04 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9" +++     "59F2815B 16F81798 483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8"++-- | compressed format: 02 <x> if y is even, 03 <x> if y is odd (1+32+33 bytes, x big-endian)+_secp256k1_G_compr = parseSecData +  "02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798"++-- | Base point coordinates+_secp256k1_Gx, _secp256k1_Gy :: Integer+_secp256k1_Gx = parseSecInt "79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798" +_secp256k1_Gy = parseSecInt "483ADA77 26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8"++-- | n is the smallest number such that G^n = infinity, which means the order of the subgroup generated by G+_secp256k1_n :: Integer+_secp256k1_n = parseSecInt "FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141"++-- | Cofactor = 1 means that the subgroup generated by G is the whole curve.+_secp256k1_h = 1 :: Integer++data ECurve = ECurve +  { _ec_p :: Integer+  , _eg_a :: Integer+  , _eg_b :: Integer+  , _ec_G :: (Integer,Integer)+  , _eg_n :: Integer+  , _eg_h :: Integer+  } ++secp256k1 :: ECurve+secp256k1 = ECurve +  { _ec_p = _secp256k1_p+  , _eg_a = _secp256k1_a+  , _eg_b = _secp256k1_b+  , _ec_G = (_secp256k1_Gx,_secp256k1_Gy)+  , _eg_n = _secp256k1_n+  , _eg_h = _secp256k1_h+  } ++parseSecData :: String -> B.ByteString+parseSecData = fromHexString . HexString . ignoreSpaces where+  ignoreSpaces = filter (not . isSpace)++parseSecInt :: String -> Integer+parseSecInt = toIntegerBE . parseSecData where++-}++--------------------------------------------------------------------------------+-- * Operations on the secp256k1 curve++-- | Addition in the elliptic curve (or multiplication if you prefer to think it as a multiplicative group)+addEC :: ECPoint -> ECPoint -> ECPoint +addEC ECInfinity eq  = eq+addEC ep ECInfinity  = ep+addEC ep@(ECPoint xp yp) eq@(ECPoint xq yq) +  | ep == eq     = dblEC ep+  | yp+yq == 0   = ECInfinity+  | otherwise    = ECPoint xr yr +  where+    s  = (yp-yq) / (xp-xq)+    xr = s*s - (xp+xq)+    yr = s*(xp-xr) - yp++subEC :: ECPoint -> ECPoint -> ECPoint +subEC a b = addEC a (invEC b)++-- | Doubling a point in the elliptic curve (multiplication by the integer 2)+dblEC :: ECPoint -> ECPoint+dblEC ECInfinity = ECInfinity +dblEC (ECPoint xp yp) +  | yp == 0    = ECInfinity          -- P+P+0 = 0+  | otherwise  = ECPoint xr yr +  where+    s  = (3*xp*xp) / (2*yp)    -- NOTE: it should be (3*sqr x + a) / (2*y), however, in this specific curve a=0+    xr = s*s - 2*xp+    yr = s*(xp-xr) - yp++-- | Inverse (negation) in the elliptic curve+invEC :: ECPoint -> ECPoint+invEC (ECPoint x y) = ECPoint x (negate y)+invEC ECInfinity    = ECInfinity++-- | Multiplication by a positive integer (or exponentiation, if you think multiplicatively). This is slow, use the projective version instead!+mulEC :: ECPoint -> Integer -> ECPoint+mulEC !base !exp = go ECInfinity base exp where+  go !acc _  0  = acc+  go !acc !b !e = if (e .&. 1 > 0)+    then go (addEC acc b) (dblEC b) (shiftR e 1)+    else go        acc    (dblEC b) (shiftR e 1)++--------------------------------------------------------------------------------+-- * Num instance++instance Num ECPoint where+  (+) = addEC+  (-) = subEC+  negate = invEC+  (*)    = error "ECPoint/Num: (*) doesn't makes sense"+  abs    = error "ECPoint/Num: `abs' doesn't makes sense"+  signum = error "ECPoint/Num: `signum' doesn't makes sense"+  fromInteger n = case n of+    0 -> ECInfinity+    _ -> error "ECPoint/Num: `fromInteger' doesn't makes sense, apart from 0"++--------------------------------------------------------------------------------
+ Bitcoin/Crypto/EC/DSA.hs view
@@ -0,0 +1,231 @@++-- | Elliptic Curve Digital Signatura Algorithm (DSA), with the secp256k1 curve.+--+-- References:+--+--  * <http://en.wikipedia.org/wiki/Elliptic_curve_cryptography>+--+--  * <http://en.wikipedia.org/wiki/ECDSA>+--+--  * <http://www.secg.org/collateral/sec2_final.pdf>+--+{-# LANGUAGE BangPatterns #-}+module Bitcoin.Crypto.EC.DSA where++--------------------------------------------------------------------------------++import Control.Monad++import Prelude hiding ( sqrt )++import Data.Char+import Data.Bits+import Data.Word+import Data.Maybe++import qualified Data.ByteString as B++import System.Random++import Bitcoin.Misc.HexString+import Bitcoin.Misc.BigInt+import Bitcoin.Misc.OctetStream++import Bitcoin.Protocol.Hash++import Bitcoin.Crypto.FiniteField.Fast.Fp  hiding ( secp256k1_p )+import Bitcoin.Crypto.FiniteField.Naive.Fn hiding ( secp256k1_n )++import Bitcoin.Crypto.Hash.HMAC ( HMAC(..) , HMACKey , hmacSha256 , hmacKeyFromString64 )++import Bitcoin.Crypto.EC.Curve+import Bitcoin.Crypto.EC.Projective+import Bitcoin.Crypto.EC.Key++--------------------------------------------------------------------------------++-- | An ECDSA signature+data Signature = Signature { _signatureR :: !Integer , _signatureS :: !Integer } deriving (Eq,Show)++-- | Two extra bits of information, used to recover the public key from the signatures.+newtype SignBits = SignBits Word8 deriving (Eq,Show)++--------------------------------------------------------------------------------+-- * signing, verifying, recovering++-- | The integer representation of a hash. We should take the left log2[secp256k1_n] bits, +-- but both the hash and n has 256 bits, so we take the whole hash.+hashInteger :: Hash256 -> Integer+hashInteger = toIntegerBE++-- | Signs the /hash/ of a message (using the defaul random source - this probably shouldn't be used!)+signMessageHashIO :: PrivKey -> Hash256 -> IO (SignBits,Signature)+signMessageHashIO priv hash = getStdRandom (\gen -> signMessageHash priv hash gen)++-- | Signs the /hash/ of a message (given a random number source)+signMessageHash :: RandomGen gen => PrivKey -> Hash256 -> gen -> ((SignBits,Signature),gen)+signMessageHash (PrivKey !da) !hash oldgen = go oldgen where+  z    = hashInteger hash++  go gen = if (ep /= ECInfinity && r/=0 && s/=0) then ((SignBits w8, signature),gen') else go gen' where+    signature = Signature (fromFn r) (fromFn s)+    -- (k,gen') = randomR (1,secp256k1_n) gen+    (!k,gen') = hashedRandom gen+    epp = mulECP secp256k1_G_proj k      -- since k is in [1,n-1], this cannot be infinity+    ep  = fromECProj epp+    (!x,!y) = case ep of  +      ECPoint x y -> (x,y)+      ECInfinity  -> error "signMessageHash: shouldn't happen"+    r = fromInteger (fromFp x) :: Fn+    s = (fromInteger z + r * fromInteger da) / (fromInteger k)++    odd_y  = if even (fromFp y)      then 0 else 1+    add_n  = if fromFn r == fromFp x then 0 else 2+    w8 = odd_y + add_n++  -- ECDSA is vulnerable if the same K is reused, or if the randomness of K is weak. +  -- Hashing together the message, the private key, and some random numbers helps a +  -- lot in case of weak random generators (it should be more-or-less safe even with+  -- the classic "k=4", chosen with fair dice "random" generator :)+  hashedRandom gen = if k>1 && k<secp256k1_n then (k,gen'') else hashedRandom gen'' where+    (k0,gen' ) = randomR (1,secp256k1_n) gen+    (k1,gen'') = randomR (1,secp256k1_n) gen'+    k = toIntegerBE +       $ doHash256 +       $ (fromIntegerLE k0 ++ fromIntegerLE k1 ++ toWord8List hash ++ fromIntegerLE da ++ [0x12,0x34,0x56,0x78])++--------------------------------------------------------------------------------++-- | Deterministic signature as specified by RFC 6979: +-- <http://tools.ietf.org/html/rfc6979>, in particular section 3.2+--+signMessageHashRFC6979 :: PrivKey -> Hash256 -> (SignBits,Signature)+signMessageHashRFC6979 (PrivKey da) hash = result where++  hmac_k :: OctetStream a => a -> [Word8] -> [Word8]+  hmac_k key = toWord8List . unHMAC . hmacSha256 (hmacKeyFromString64 key)++  z    = mod (hashInteger hash) secp256k1_n           -- for z, it doesn't matter (it will be in Fn anyway), but for h1 it matters :(++  x1   = bigEndianInteger32 da    :: [Word8]          -- x = private key here+  h1   = bigEndianInteger32 z     :: [Word8]          -- step a++  v0   = replicate 32 0x01 :: [Word8]                 -- step b+  k0   = replicate 32 0x00 :: [Word8]                 -- step c+  k1   = hmac_k k0 $ v0 ++ [0x00] ++ x1 ++ h1         -- step d+  v1   = hmac_k k1 $ v0                               -- step e+  k2   = hmac_k k1 $ v1 ++ [0x01] ++ x1 ++ h1         -- step f+  v2   = hmac_k k2 $ v1                               -- step g+  +  result = step_h k2 v2++  halfn = div secp256k1_n 2++  step_h k v0 =                                       -- final step (step h)++    if dsa_k > 0 && dsa_k < secp256k1_n && ep /= ECInfinity && r/=0 && s/=0+      then (signbits,signature)+      else step_h k' v'++    where++      v = hmac_k k v0          -- step h/1 +      t = v                    -- step h/2 (always a single step in our case?)+      dsa_k = toIntegerBE t++      k' = hmac_k k  $ v ++ [0x00]+      v' = hmac_k k' $ v++      epp = mulECP secp256k1_G_proj dsa_k+      ep  = fromECProj epp+      (!x,!y) = case ep of  +        ECPoint x y -> (x,y)+        ECInfinity  -> error "signMessageHashRFC6979: shouldn't happen"    -- k is [1,n-1], this shouldn't ever happen++      r  = fromInteger (fromFp x)                                     :: Fn+      s0 = (fromInteger z + r * fromInteger da) / (fromInteger dsa_k) :: Fn++      -- hmm, it seems this extra rule is used for some reason ??+      -- quote: "The theory behind this is: if you negate K you get the same R and the negated S. +      --         Hence you need to negate S as a post-processing step, i.e., S' = prime - S in both cases"+      s = if (fromFn s0) > halfn then Fn (secp256k1_n - fromFn s0) else s0   ++      odd_y  = if even (fromFp y)      then 0 else 1+      add_n  = if fromFn r == fromFp x then 0 else 2+      w8 = odd_y + add_n +  +      signbits  = SignBits w8+      signature = Signature (fromFn r) (fromFn s)+    +--------------------------------------------------------------------------------+  +verifySignatureWithHash :: PubKey -> Signature -> Hash256 -> Bool+verifySignatureWithHash pubkey0 signature hash = isJust mbpubkey && isValidPubKey pubkey && check where+  mbpubkey = uncompressPubKey pubkey0  +  z     = (fromInteger $ hashInteger hash) :: Fn+  check = (r0>0 && r0 < secp256k1_n) && (s0>0 && s0 < secp256k1_n) && valid+  Signature r0 s0 = signature+  pubkey@(FullPubKey qx qy) = fromJust mbpubkey +  w  = recip (fromInteger s0 :: Fn)+  r  = fromInteger r0 :: Fn+  u1 = fromFn (z * w)+  u2 = fromFn (r * w)+  qp  = ECPoint (fromInteger qx :: Fp) (fromInteger qy :: Fp)+  qpp = toECProj qp+  ep = (mulECP secp256k1_G_proj u1) `addECP` (mulECP qpp u2) +  valid = case fromECProj ep of+    ECPoint x1 y1 -> fromFp x1 == r0        -- ??? !!! +    _             -> False   ++--------------------------------------------------------------------------------++-- | Recovers the public key from the (extended) signature and the /hash/ of the message.+-- +-- On the Word8 paramter: Bit 0 encodes whether the curve point R (which has x coordinate r from the signature) +-- has even or odd y coordinate; and bit 1 encodes how to reconstruct the x coordinate from r.+--+recoverPubKeyFromHash :: (PubKeyFormat,SignBits,Signature) -> Hash256 -> Maybe PubKey+recoverPubKeyFromHash (fmt, SignBits parities, Signature r s) hash = if isJust mbxy then Just cpubkey else Nothing where ++  z = hashInteger hash++  cpubkey = formatPubKey fmt pubkey+  pubkey  = FullPubKey (fromFp qx) (fromFp qy)  ++  x = if not add_n then r else modp (r + secp256k1_n) +  mbxy = uncompressPubKey $ ComprPubKey (if odd_y then 3 else 2) x+  Just (FullPubKey _ y) = mbxy++  rr = ECPoint (toFp x) (toFp y) +  rr_proj = toECProj rr  ++  -- rr1 = invEC rr                  -- (-R) corresponds to negating y, which is already encoded in odd_y+  +  inv_r = fromFn (recip $ Fn $ modn r)+  qqp   = mulECP (sR_proj `subECP` zG_proj) inv_r+  (!qx,!qy) = case fromECProj qqp of +    ECPoint qx qy -> (qx,qy)+    ECInfinity    -> error "recoverPubKeyFromHash: shouldn't happen (???)"++  sR_proj = mulECP rr_proj s+  zG_proj = mulECP secp256k1_G_proj z++  odd_y  = (parities .&. 1) > 0+  add_n  = (parities .&. 2) > 0++--------------------------------------------------------------------------------+-- * some tests++ectest1 = do+  let msg = B.pack $ map char_to_word8 $ "almafa kortefa"+  let priv = PrivKey 420324792348973434283974283942354354+      pub  = computeFullPubKey priv+  gen <- getStdGen+  let ((signbits,signat),gen') = signMessageHash priv (doHash256 msg) gen+  setStdGen gen'+  print signat+  let b = verifySignatureWithHash pub signat (doHash256 msg)+  print b+  when (not b) $ do+    error $ "ECDSA signature check test failed for " ++ show (signat,gen)+
+ Bitcoin/Crypto/EC/DiffieHellman.hs view
@@ -0,0 +1,47 @@++-- | Diffie-Hellman key exchange++{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Bitcoin.Crypto.EC.DiffieHellman where++--------------------------------------------------------------------------------++import Data.Word++import Bitcoin.Misc.OctetStream++import Bitcoin.Crypto.Word256+import Bitcoin.Crypto.FiniteField.Fast.Fp++import Bitcoin.Crypto.EC.Curve+import Bitcoin.Crypto.EC.Projective+import Bitcoin.Crypto.EC.Key++--------------------------------------------------------------------------------++newtype SharedSecret = SharedSecret [Word8] deriving (Eq,Ord,Show,OctetStream)++--------------------------------------------------------------------------------++-- | Given your private key and somebody else's public key, this compute+-- a (256 bit) shared secret. +--+-- This is actually very simple: since @pubkey = G * privkey@, the shared+-- secret will be simply @G * privkey1 * privkey2@.+--+-- This can fail if for example an invalid pubkey is given, and+-- in some other special circumstances.+--+diffieHellmanPrimitive :: PrivKey -> PubKey -> Maybe SharedSecret+diffieHellmanPrimitive (PrivKey d) pk = +  case uncompressPubKey pk of+    Nothing -> Nothing    +    Just full@(FullPubKey x y) -> case isValidPubKey full of +      False -> Nothing+      True  -> case fromECProj (mulECP (toECProj $ mkECPoint x y) d) of+        ECInfinity    -> Nothing+        ECPoint zx zy -> Just (SharedSecret $ word256ToWord8ListLE $ unFp zx)   -- zx=0 doesn't seem to be on the curve, so this is always nonzero+    _ -> Nothing                                                                -- shouldn't happen, but totality is always good.++--------------------------------------------------------------------------------+  
+ Bitcoin/Crypto/EC/Key.hs view
@@ -0,0 +1,146 @@++-- | Elliptic Curve cryptography keys+--+{-# LANGUAGE CPP, BangPatterns #-}+module Bitcoin.Crypto.EC.Key where++--------------------------------------------------------------------------------++import Control.Monad++import Prelude hiding ( sqrt )++import Data.Char+import Data.Bits+import Data.Word+import Data.Maybe++import qualified Data.ByteString as B++import System.Random++import Bitcoin.Misc.HexString+import Bitcoin.Misc.BigInt+import Bitcoin.Misc.OctetStream++import Bitcoin.Misc.BigInt++import Bitcoin.Protocol.Hash               ++import Bitcoin.Crypto.FiniteField.Fast.Fp  hiding ( secp256k1_p )+import Bitcoin.Crypto.FiniteField.Naive.Fn hiding ( secp256k1_n )++import Bitcoin.Crypto.EC.Curve+import Bitcoin.Crypto.EC.Projective++--------------------------------------------------------------------------------+-- * private and public keys.++-- | The private key is a random number in the interval [1,n-1] (n being secp256k1_n)+newtype PrivKey = PrivKey { fromPrivKey :: Integer } deriving (Eq,Show)++-- | The public key (which is the point @priv*G@ on the curve, @G@ being the generator), either in long format (both coordinates)+-- or short format (x coordinate plus parity of y) +data PubKey +  = FullPubKey  !Integer !Integer    -- ^ <x> <y>+  | ComprPubKey !Word8   !Integer    -- ^ only <x>; the single byte encodes the parity of @y@ (then we have the curve equation)+  deriving (Eq,Show)++-- | Unfortunately there is this mess with compressed/uncompressed formats :(+--+-- See <http://bitcoin.stackexchange.com/questions/7299/when-importing-private-keys-will-compressed-or-uncompressed-format-be-used>+data PubKeyFormat = Uncompressed | Compressed deriving (Eq,Show)++--------------------------------------------------------------------------------++-- | Generates a private key with the built-in random generator. +--+-- WARNING: this probably doesn't have enough entropy, use only for testing!+generatePrivKeyIO :: IO PrivKey+generatePrivKeyIO = getStdRandom generatePrivKey++-- | Generates a private key using the supplied random generator. +-- +-- WARNING! You are responsible for the random generator having enough entropy!+-- (be careful not to have a constant seed, for example...)+generatePrivKey :: RandomGen gen => gen -> (PrivKey,gen)+generatePrivKey = go where+  -- this isn't much help in case of weak random generators, but maybe better than nothing+  -- (for example, even if the original generator is predictable, this won't be easy to predict)+  go gen = if ( priv > 0 && priv < secp256k1_n ) then (PrivKey priv, gen'') else go gen'' where+    (priv0,gen' ) = randomR (1, secp256k1_n - 1) gen+    (priv1,gen'') = randomR (1, secp256k1_n - 1) gen'+    priv = toIntegerBE +         $ doHash256 +         $ (fromIntegerLE priv0 ++ fromIntegerLE priv1 ++ [0x12::Word8,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0])++{-+generatePrivKey :: RandomGen gen => gen -> (PrivKey,gen)+generatePrivKey gen = (PrivKey priv, gen') where+   (priv,gen') = randomR (1, secp256k1_n - 1) gen+-}++--------------------------------------------------------------------------------++pubKeyFormat :: PubKey -> PubKeyFormat+pubKeyFormat pk = case pk of +  FullPubKey  {} -> Uncompressed+  ComprPubKey {} -> Compressed++-- | Computes the public key in the given format+computePubKey :: PubKeyFormat -> PrivKey -> PubKey+computePubKey fmt priv = +  case fmt of+    Uncompressed -> full +    Compressed   -> compressPubKey full +  where+    full = computeFullPubKey priv++computeFullPubKey :: PrivKey -> PubKey+computeFullPubKey (PrivKey da) +  | da < 1 && da >= secp256k1_n = error "computePubKey: invalid private key"+  | otherwise = case fromECProj (mulECP secp256k1_G_proj da) of+      ECPoint x y -> FullPubKey (fromFp x) (fromFp y) where+      ECInfinity  -> error "computePubKey: invalid private key"++-- I think the condition @(n * ep = ECInfinity)@ is not necessary (follows from being on the curve), but cannot hurt.+-- On the other hand, I'm nut sure if @y==0@ is invalid, but it probably should...+isValidPubKey :: PubKey -> Bool+isValidPubKey pub = case uncompressPubKey pub of+  Nothing -> False+  Just (ComprPubKey _  _ ) -> error "isValidPubKey: this shouldn't happen"+  Just (FullPubKey  x0 y0) -> (y /= 0) && (y*y == x*x*x + 7) && (mulECP (toECProj ep) secp256k1_n =~= ecpInfinity) where+    x = fromInteger x0 :: Fp+    y = fromInteger y0 :: Fp+    ep = ECPoint x y++-- | Changes a pubkey to the given format+formatPubKey :: PubKeyFormat -> PubKey -> PubKey+formatPubKey fmt pk = case fmt of+  Compressed   -> compressPubKey   pk+  Uncompressed -> case uncompressPubKey pk of+                    Just new -> new+                    Nothing  -> error "formatPubKey: cannot expand compressed pubkey"++-- | Uncompresses a public key. This may actually fail if there is no point (x,y) on the curve for any y.+uncompressPubKey :: PubKey -> Maybe PubKey+uncompressPubKey full@(FullPubKey _ _)   = Just full+uncompressPubKey (ComprPubKey evenOdd x) = +  case my of +    Just y  -> let yi = fromFp y+               in  if even (evenOdd) == even yi+                     then Just ( FullPubKey x                yi  ) +                     else Just ( FullPubKey x (secp256k1_p - yi) )+    Nothing -> Nothing+  where+    x1 = fromInteger x :: Fp+    x3 = x1*x1*x1+    y2 = x3 + 7     -- NOTE: this should be @y2 = x3 + a*x + b@ but a=0 and b=7 for our curve+    my = sqrt_p y2++-- | Compresses a public key+compressPubKey :: PubKey -> PubKey+compressPubKey compr@(ComprPubKey _ _) = compr+compressPubKey (FullPubKey x y)        = ComprPubKey (if even y then 2 else 3) x++--------------------------------------------------------------------------------
+ Bitcoin/Crypto/EC/Projective.hs view
@@ -0,0 +1,221 @@+
+-- | Using (weighted) projective coordinates on the curve we can maybe avoid the division bottleneck.
+--
+-- Based on: Chae Hoon Lim, Hyo Sun Hwang: Fast implementation of Elliptic Curve arithmetic in GF(p\^n).
+--
+-- We will use (2,3,1) weighting, and a constant factor of 2 in Y:
+--
+-- > x = X/Z^2 
+-- > y = Y/(2*Z^3)
+-- > z = 1
+--
+-- Thus the curve equation @y^2 = x^3 + 7@ becomes
+--
+-- > Y^2/4 = X^3 + 7*Z^6
+--
+-- and then the infinity point on the curve is @(1,2,0)@.
+--
+--
+
+{-# LANGUAGE CPP, BangPatterns, ForeignFunctionInterface #-}
+module Bitcoin.Crypto.EC.Projective where
+
+--------------------------------------------------------------------------------
+
+import Data.Bits
+
+import Bitcoin.Crypto.FiniteField.Fast.Fp  hiding ( secp256k1_p )
+import Bitcoin.Crypto.FiniteField.Naive.Fn hiding ( secp256k1_n )
+
+import Bitcoin.Crypto.EC.Curve
+
+-- C stuff
+import Data.Word
+import Foreign
+import System.IO.Unsafe as Unsafe
+import Bitcoin.Crypto.Word256
+
+--------------------------------------------------------------------------------
+
+-- | Note: the "Eq" instance is equality of all coordinates, not equality on the projective plane (for that, use "(=~=)" instead)
+data ECProj = ECProj !Fp !Fp !Fp deriving (Eq,Show)
+
+toECProj :: ECPoint -> ECProj
+toECProj ep = case ep of
+  ECPoint x y -> ECProj x (y+y) 1
+  ECInfinity  -> ECProj 1 2 0       -- vertical infinity
+
+fromECProj :: ECProj -> ECPoint
+fromECProj (ECProj x@(Fp xrep) y@(Fp yrep) z@(Fp zrep)) = 
+  if zrep /= 0
+    then ECPoint (x/z2) (y/(z3+z3)) 
+    else if 2*xrep == yrep      
+      then ECInfinity
+      else error "fromECProj: infinity not on the curve"
+  where 
+    z2 = z*z 
+    z3 = z*z2
+
+--------------------------------------------------------------------------------
+
+foreign import ccall unsafe "c_ec.c c_addECP" c_addECP_ :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 
+                                                        -> Ptr Word32 -> Ptr Word32 -> Ptr Word32 
+                                                        -> Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()
+
+foreign import ccall unsafe "c_ec.c c_dblECP" c_dblECP_ :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 
+                                                        -> Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()
+
+foreign import ccall unsafe "c_ec.c c_mulECP" c_mulECP_ :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 
+                                                        -> Ptr Word32 
+                                                        -> Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()
+
+withECProj :: ECProj -> (Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO a) -> IO a
+withECProj (ECProj (Fp x) (Fp y) (Fp z)) action = 
+  withWord256 x $ \px -> withWord256 y $ \py -> withWord256 z $ \pz -> action px py pz
+
+withNewECProj :: (Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()) -> IO ECProj
+withNewECProj action = do
+  x <- newWord256
+  y <- newWord256
+  z <- newWord256
+  withWord256 x $ \px -> withWord256 y $ \py -> withWord256 z $ \pz -> action px py pz
+  return (ECProj (Fp x) (Fp y) (Fp z))  
+
+c_dblECP :: ECProj -> ECProj
+c_dblECP ep = Unsafe.unsafePerformIO $ do
+  withECProj ep $ \xp yp zp -> withNewECProj $ \xr yr zr -> c_dblECP_ xp yp zp xr yr zr
+
+c_addECP :: ECProj -> ECProj -> ECProj
+c_addECP ep eq = Unsafe.unsafePerformIO $ do
+  withECProj ep $ \xp yp zp -> withECProj eq $ \xq yq zq -> withNewECProj $ \xr yr zr -> c_addECP_ xp yp zp xq yq zq xr yr zr
+
+c_mulECP :: ECProj -> Integer -> ECProj
+c_mulECP ep m = Unsafe.unsafePerformIO $ do
+  w256 <- makeWord256 (mod m secp256k1_n)     -- mod !!
+  withECProj ep $ \xp yp zp -> withWord256 w256 $ \pw256 -> withNewECProj $ \xr yr zr -> c_mulECP_ xp yp zp pw256 xr yr zr  
+
+dblECP :: ECProj -> ECProj
+dblECP = c_dblECP
+
+addECP :: ECProj -> ECProj -> ECProj
+addECP = c_addECP
+
+mulECP :: ECProj -> Integer -> ECProj
+mulECP = c_mulECP
+
+--------------------------------------------------------------------------------
+-- * Num/Eq instances
+
+instance Num ECProj where
+  (+) = addECP
+  (-) = subECP
+  negate = invECP
+  (*)    = error "ECProj/Num: (*) doesn't makes sense"
+  abs    = error "ECProj/Num: `abs' doesn't makes sense"
+  signum = error "ECProj/Num: `signum' doesn't makes sense"
+  fromInteger n = case n of
+    0 -> ecpInfinity
+    _ -> error "ECProj/Num: `fromInteger' doesn't makes sense, apart from 0"
+
+--------------------------------------------------------------------------------
+
+infix 4 =~=
+
+(=~=) :: ECProj -> ECProj -> Bool
+(=~=) (ECProj xp yp zp) (ECProj xq yq zq) = ( zp==0 && zq==0 && z_zero) || z_nonzero 
+  where
+    zp2 = zp*zp
+    zq2 = zq*zq
+    zp3 = zp*zp2
+    zq3 = zq*zq2
+    z_zero    =  ( yp == 0 && yq == 0 ) || ( yq2*xp3 == yp2*xq3 )
+    z_nonzero = ( xp*zq2 == xq*zp2 ) && ( yp*zq3 == yq*zp3 ) 
+    xp2 = xp*xp
+    xq2 = xq*xq    
+    xp3 = xp2*xp
+    xq3 = xq2*xq    
+    yp2 = yp*xp
+    yq2 = yq*xq    
+
+ecpInfinity :: ECProj
+ecpInfinity = ECProj 1 2 0
+
+isECPInfinity :: ECProj -> Bool
+isECPInfinity (ECProj x@(Fp xrep) y@(Fp yrep) z@(Fp zrep)) = (zrep==0) && (xrep/=0) && (yrep/=0) && (y2==4*x3) where
+  y2 = y*y
+  x2 = x*x
+  x3 = x2*x
+
+isECPOnCurve :: ECProj -> Bool
+isECPOnCurve (ECProj x y z) = (y2 == 4 * (x3 + 7*z6)) where
+  y2 = y*y
+  x2 = x*x
+  x3 = x2*x
+  z2 = z*z
+  z3 = z2*z
+  z6 = z3*z3
+
+secp256k1_G_proj :: ECProj
+secp256k1_G_proj = ECProj (fromInteger secp256k1_Gx) (fromInteger secp256k1_Gy * 2) 1
+
+--------------------------------------------------------------------------------
+
+-- | Addition in the elliptic curve (or multiplication if you prefer to think it as a multiplicative group)
+hs_addECP :: ECProj -> ECProj -> ECProj
+hs_addECP ep@(ECProj xp yp zp) eq@(ECProj xq yq zq) 
+  | zp == 0           =  if isECPInfinity ep then eq else error "addECP: eq not on the curve"
+  | zq == 0           =  if isECPInfinity eq then ep else error "addECP: ep not on the curve"
+  | b == 0 && d == 0  =  dblECP ep
+  | otherwise         =  ECProj xr yr zr
+  where
+    zp2 = zp*zp
+    zq2 = zq*zq
+    zp3 = zp*zp2
+    zq3 = zq*zq2                                             
+    xpzq2 = xp*zq2
+    xqzp2 = xq*zp2
+    ypzq3 = yp*zq3
+    yqzp3 = yq*zp3
+    a = xpzq2 + xqzp2
+    b = xpzq2 - xqzp2
+    c = ypzq3 + yqzp3
+    d = ypzq3 - yqzp3
+    e = b+b
+    e2 = e*e
+    ae2 = a*e2
+    xr = d*d-ae2
+    yr = d*(ae2-(xr+xr)) - e2*b*c
+    zr = e*zp*zq
+    
+-- | Doubling a point in the elliptic curve (multiplication by the integer 2)
+hs_dblECP :: ECProj -> ECProj
+hs_dblECP (ECProj xp yp zp) = ECProj xr yr zr
+  where
+    yp2 = yp*yp
+    xp2 = xp*xp
+    a = xp2+xp2+xp2
+    xpyp2 = xp*yp2
+    b = xpyp2 + xpyp2
+    c = yp2*yp2
+    xr = a*a - b
+    yr = a*(b-(xr+xr)) - c
+    zr = yp*zp
+
+--------------------------------------------------------------------------------
+
+-- | Inverse (negation) in the elliptic curve
+invECP :: ECProj -> ECProj
+invECP (ECProj x y z) = ECProj x (negate y) z
+
+subECP :: ECProj -> ECProj -> ECProj
+subECP a b = addECP a (invECP b)
+
+-- | Multiplication by a positive integer (or exponentiation, if you think multiplicatively)
+hs_mulECP :: ECProj -> Integer -> ECProj
+hs_mulECP !base !exp = go ecpInfinity base exp where
+  go !acc _  0  = acc
+  go !acc !b !e = if (e .&. 1 > 0)
+    then go (hs_addECP acc b) (hs_dblECP b) (shiftR e 1)
+    else go            acc    (hs_dblECP b) (shiftR e 1)
+
+--------------------------------------------------------------------------------
+ Bitcoin/Crypto/FiniteField/Fast/Fp.hs view
@@ -0,0 +1,227 @@++-- | Finite field of order p, where p is the prime parameter of the+-- secp256k1 elliptic curve. Relatively fast arithmetic (written in C) +--+-- Should work on both little-endian and big-endian architectures,+-- but only tested on little-endian.++{-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns #-}+module Bitcoin.Crypto.FiniteField.Fast.Fp where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits++import Data.List ( unfoldr )++import Foreign+import Foreign.C++import qualified System.IO.Unsafe as Unsafe+import qualified Data.ByteString  as B++import Bitcoin.Crypto.Word256++--------------------------------------------------------------------------------++newtype Fp = Fp { unFp :: Word256 } deriving (Eq,Show)++fpDecimal :: Fp -> String+fpDecimal = word256Decimal . unFp++fpHex :: Fp -> String+fpHex = word256Hex . unFp++--------------------------------------------------------------------------------++toFp :: Integer -> Fp+toFp = Fp . toWord256 . modp++fromFp :: Fp -> Integer+fromFp = fromWord256 . unFp++--------------------------------------------------------------------------------++-- | Converts to a little-endian bytestring+fpToByteStringLE :: Fp -> B.ByteString+fpToByteStringLE = word256ToByteStringLE . unFp++-- | Converts to a big-endian bytestring+fpToByteStringBE :: Fp -> B.ByteString+fpToByteStringBE = word256ToByteStringBE . unFp++-- | Converts to a little-endian sequence of bytes+fpToWord8ListLE :: Fp -> [Word8]+fpToWord8ListLE = word256ToWord8ListLE . unFp++--------------------------------------------------------------------------------++foreign import ccall unsafe "c_modp.c neg_modp" c_neg_modp :: Ptr Word32 -> Ptr Word32 -> IO ()++foreign import ccall unsafe "c_modp.c inv_modp_power"    c_inv_modp_power    :: Ptr Word32 -> Ptr Word32 -> IO ()+foreign import ccall unsafe "c_modp.c inv_modp_pow_spec" c_inv_modp_pow_spec :: Ptr Word32 -> Ptr Word32 -> IO ()+foreign import ccall unsafe "c_modp.c inv_modp_euclid"   c_inv_modp_euclid   :: Ptr Word32 -> Ptr Word32 -> IO ()++foreign import ccall unsafe "c_modp.c add_modp"   c_add_modp   :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()+foreign import ccall unsafe "c_modp.c sub_modp"   c_sub_modp   :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()+foreign import ccall unsafe "c_modp.c mul_modp"   c_mul_modp   :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()+foreign import ccall unsafe "c_modp.c div_modp"   c_div_modp   :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()+foreign import ccall unsafe "c_modp.c pow_modp"   c_pow_modp   :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()++-- foreign import ccall unsafe "c_modp.c shiftl32_modp" c_shiftl32_modp :: Ptr Word32 -> Ptr Word32 -> IO ()+-- foreign import ccall unsafe "c_modp.c scale_modp"    c_scale_modp    :: Ptr Word32 ->     Word32 -> Ptr Word32 -> IO ()++--------------------------------------------------------------------------------++neg_modp :: Word256 -> Word256+neg_modp a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_neg_modp pa pc+  return c++inv_modp_power :: Word256 -> Word256+inv_modp_power a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_inv_modp_power pa pc+  return c++inv_modp_pow_spec :: Word256 -> Word256+inv_modp_pow_spec a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_inv_modp_pow_spec pa pc+  return c++inv_modp_euclid :: Word256 -> Word256+inv_modp_euclid a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_inv_modp_euclid pa pc+  return c++add_modp :: Word256 -> Word256 -> Word256+add_modp a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 b $ \pb -> withWord256 c $ \pc -> c_add_modp pa pb pc+  return c++sub_modp :: Word256 -> Word256 -> Word256+sub_modp a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 b $ \pb -> withWord256 c $ \pc -> c_sub_modp pa pb pc+  return c++mul_modp :: Word256 -> Word256 -> Word256+mul_modp a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 b $ \pb -> withWord256 c $ \pc -> c_mul_modp pa pb pc+  return c++div_modp :: Word256 -> Word256 -> Word256+div_modp a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 b $ \pb -> withWord256 c $ \pc -> c_div_modp pa pb pc+  return c++pow_modp :: Word256 -> Word256 -> Word256+pow_modp a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 b $ \pb -> withWord256 c $ \pc -> c_pow_modp pa pb pc+  return c++--------------------------------------------------------------------------------++{-+scale_modp :: Word256 -> Word32 -> Word256+scale_modp a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_scale_modp pa b pc+  return c+-}++--------------------------------------------------------------------------------++instance Num Fp where+  Fp a + Fp b = Fp (add_modp a b)+  Fp a - Fp b = Fp (sub_modp a b)+  Fp a * Fp b = Fp (mul_modp a b)+  negate (Fp a) = Fp (neg_modp a)+  fromInteger = toFp+  abs      = id+  signum _ = Fp (toWord256 1)++instance Fractional Fp where+  Fp a / Fp b  = Fp (div_modp a b)+  recip (Fp a) = Fp (inv_modp_euclid a)+  fromRational = error "Fp/fromRational: does not make much sense"++{-+-- | Fake instance for Integral+instance Real Fp where+  toRational = toRational . fromFp++-- | Fake instance for Integral+instance Enum Fp where+  toEnum   = error "Enum/Fp/toEnum: Enum range (Int) is too small for 256 bits..."+  fromEnum = error "Enum/Fp/fromEnum: Enum range (Int) is too small for 256 bits..."++-- | Well it's a field so division is always exact, but we need toInteger+instance Integral Fp where+  toInteger = fromFp+  div  a b = div_modp a b+  quot a b = div_modp a b+  rem a b = 0+  mod a b = 0+-}+  +pow_p :: Fp -> Word256 -> Fp+pow_p (Fp a) b = Fp (pow_modp a b) ++-- | Note that this gives only one of the possibly two square roots+sqrt_p :: Fp -> Maybe Fp+sqrt_p (Fp x2) = case sqrtFp x2 of+  Nothing -> Nothing+  Just y  -> Just (Fp y)++--------------------------------------------------------------------------------+-- * square root in Fp++secp256k1_ndiv4   = toWord256 $ 28948022309329048855892746252171976963317496166410141009864396001977208667915+secp256k1_ndiv4p1 = toWord256 $ 28948022309329048855892746252171976963317496166410141009864396001977208667916++-- | (One of the) square roots mod p (if any exists). Since p is a prime and @p = 4k+3@, +-- we have a fortunately a very easy solution by some quadratic reciprocity stuff I don't +-- remember how exactly works+-- (but it's elementary number theory)+--+-- <http://course1.winona.edu/eerrthum/13Spring/SquareRoots.pdf>+--+unsafeSqrtFp :: Word256 -> Word256+unsafeSqrtFp !a = pow_modp a secp256k1_ndiv4p1++-- | Note that square roots do not always exist in Fp: consider for example p=7,+-- then 3, 5 and 6 do not have square roots, while the rest has two (except 0).+-- +-- In general, if x is a square root then so is (p-x), since +--+-- > (p-x)*(p-x) = p*p - p*(2*x) + x*x = x*x (mod p)+--+-- And that should be all solutions, since it's a quadratic equation.+--+sqrtFp :: Word256 -> Maybe Word256+sqrtFp x2 = if mul_modp x x == x2 then Just x else Nothing +  where x = unsafeSqrtFp x2++--------------------------------------------------------------------------------+-- * useful++secp256k1_p :: Integer+secp256k1_p = 115792089237316195423570985008687907853269984665640564039457584007908834671663++instance Bounded Fp where+  minBound = toFp 0+  maxBound = toFp (secp256k1_p - 1)++modp :: Integer -> Integer+modp n = mod n secp256k1_p ++--------------------------------------------------------------------------------
+ Bitcoin/Crypto/FiniteField/Naive/Fn.hs view
@@ -0,0 +1,71 @@++-- | The finite field Fn of n elements, where n is the order of the elliptic curve secp256k1 (which happens to be a prime).+-- +-- Naive implementation.+-- +{-# LANGUAGE BangPatterns #-}+module Bitcoin.Crypto.FiniteField.Naive.Fn where++--------------------------------------------------------------------------------++import Prelude hiding ( sqrt )++import Data.Char+import Data.Bits+import Data.Word+import Data.Maybe++--------------------------------------------------------------------------------++secp256k1_n :: Integer+secp256k1_n = 115792089237316195423570985008687907852837564279074904382605163141518161494337++--------------------------------------------------------------------------------+-- * for the signatures, we also need mod n arithmetic, not only mod p...++-- | The prime field Fn (n seems to be a prime, after all)+newtype Fn = Fn Integer deriving (Eq,Show)++toFn :: Integer -> Fn+toFn x = Fn (modn x)++fromFn :: Fn -> Integer+fromFn (Fn x) = x ++instance Num Fn where+  Fn x + Fn y   = Fn $ modn (x+y)+  Fn x - Fn y   = Fn $ modn (x-y)+  Fn x * Fn y   = Fn $ modn (x*y)+  negate (Fn x) = Fn $ modn (secp256k1_n - x)+  fromInteger   = Fn . modn +  abs    = error "Fn/abs"+  signum = error "Fn/signum"++instance Fractional Fn where+  Fn x / Fn y  = Fn $ modn ( x * invFn y )+  recip (Fn x) = Fn $ invFn x+  fromRational = error "Fn/fromRational"++pow_n :: Fn -> Fn -> Fn+pow_n (Fn b) (Fn e) = Fn (powFn b e)++--------------------------------------------------------------------------------++-- | helper function: Modulo n+modn :: Integer -> Integer+modn !a = mod a secp256k1_n++-- | Multiplicative inverse in Fp+invFn :: Integer -> Integer +invFn !a = powFn a (secp256k1_n - 2)++-- | (Fast) exponentiation in Fn+powFn :: Integer -> Integer -> Integer+powFn !base !exp = go 1 base exp where+  go !acc _  0  = acc+  go !acc !b !e = if (e .&. 1 > 0)+    then go (modn (acc*b)) (modn (b*b)) (shiftR e 1)+    else go        acc     (modn (b*b)) (shiftR e 1)++--------------------------------------------------------------------------------+
+ Bitcoin/Crypto/FiniteField/Naive/Fp.hs view
@@ -0,0 +1,241 @@++-- | The finite field Fp of p elements, where p is the prime parameter of the elliptic curve secp256k1.+-- +-- Naive implementation.+-- +{-# LANGUAGE CPP, BangPatterns #-}+module Bitcoin.Crypto.FiniteField.Naive.Fp where++--------------------------------------------------------------------------------++import Control.Monad++import Prelude hiding ( sqrt )++import Data.Char+import Data.Bits+import Data.Word+import Data.Maybe++--------------------------------------------------------------------------------++-- import Debug.Trace+-- debug x y = trace (">>> " ++ show x) y++--------------------------------------------------------------------------------++secp256k1_p :: Integer+secp256k1_p  = 115792089237316195423570985008687907853269984665640564039457584007908834671663++--------------------------------------------------------------------------------+-- * Operations in the finite field Fp (p being the secp256k1 curve's p)++-- | helper function: Modulo p +modp :: Integer -> Integer+modp !a = mod a secp256k1_p++addFp :: Integer -> Integer -> Integer+addFp !a !b = modp (a+b)++subFp :: Integer -> Integer -> Integer+subFp !a !b = modp (a-b)++-- | Negation in Fp+negFp :: Integer -> Integer+negFp !a = modp (secp256k1_p - a)++-- | Multiplication in Fp+mulFp :: Integer -> Integer -> Integer+mulFp !a !b = modp (a*b)++-- | Square in Fp+sqrFp :: Integer -> Integer+sqrFp !a = modp (a*a)++-- | Division in Fp+divFp :: Integer -> Integer -> Integer+divFp !a !b = mulFp a (invFp b)++--------------------------------------------------------------------------------++-- | Multiplicative inverse in Fp+invFp :: Integer -> Integer +invFp = invFp_euclid++-- | Inverse using the power function (slower)+invFp_pow :: Integer -> Integer +invFp_pow !a = powFp a (secp256k1_p - 2)++-- | Inverse using a specialized power function (should about 2x faster than 'invFp_pow')+--+-- This uses the fact that+--+-- > p-2 == 45 + 1024 * (1023 + 1024 * (1023 + 1024 * (1019 + 1024 * ( ... * 63 ) ) )+--+-- Since on the exponential level, both doubling and multiplying has the same cost,+-- additions and doubling in this type of representation of @p-2@ has the same cost.+-- And because in @p-2@ almost all bits are set, the standard binary power function+-- is very far from being optimal.+-- +-- Total number of operations is +--+-- > 16 + (21+1+2+1)*(10+1) = 291+--+-- instead of almost @512@.+--+invFp_pow_spec :: Fp -> Fp+invFp_pow_spec a1 = inv where+ +  dbl :: Fp -> Fp+  dbl x = x*x++  pow1024 :: Fp -> Fp+  pow1024 = dbl . dbl . dbl . dbl . dbl +          . dbl . dbl . dbl . dbl . dbl++  iter :: Int -> (Fp -> Fp) -> Fp -> Fp+  iter n f = go n where+    go !n !x = case n of+      0 -> x+      _ -> go (n-1) (f x)++  inv =          (\x -> a45   * pow1024 x)+      $! iter  2 (\x -> a1023 * pow1024 x)+      $!         (\x -> a1019 * pow1024 x)+      $! iter 21 (\x -> a1023 * pow1024 x)+      $! a63++  a2    = a1    * a1+  a3    = a2    * a1+  a4    = a2    * a2+  a5    = a4    * a1+  a10   = a5    * a5++  a11   = a10   * a1+  a21   = a11   * a10+  a42   = a21   * a21+  a45   = a42   * a3+  a63   = a42   * a21++  a126  = a63   * a63+  a252  = a126  * a126+  a504  = a252  * a252+  a1008 = a504  * a504+  a1019 = a1008 * a11+  a1023 = a1019 * a4++-- | Inverse using the binary Euclidean algorithm (faster)+invFp_euclid :: Integer -> Integer +invFp_euclid a +  | a == 0     = 0+  | otherwise  = go 1 0 a secp256k1_p+  where++    go :: Integer -> Integer -> Integer -> Integer -> Integer+    go !x1 !x2 !u !v +      | u==1       = x1+      | v==1       = x2+      | otherwise  = stepU x1 x2 u v++    stepU :: Integer -> Integer -> Integer -> Integer -> Integer+    stepU !x1 !x2 !u !v = if even u +      then let u'  = shiftR u 1+               x1' = shiftR (if even x1 then x1 else x1 + secp256k1_p) 1                +           in  stepU x1' x2 u' v+      else     stepV x1  x2 u  v++    stepV :: Integer -> Integer -> Integer -> Integer -> Integer+    stepV !x1 !x2 !u !v = if even v+      then let v'  = shiftR v 1+               x2' = shiftR (if even x2 then x2 else x2 + secp256k1_p) 1               +           in  stepV x1 x2' u v' +      else     final x1 x2  u v++    final :: Integer -> Integer -> Integer -> Integer -> Integer+    final !x1 !x2 !u !v = if u>=v++      then let u'  = u-v+               x1' = modp (x1-x2)               +           in  go x1' x2  u' v ++      else let v'  = v-u+               x2' = modp (x2-x1)               +           in  go x1  x2' u  v'++--------------------------------------------------------------------------------++-- | (Fast) exponentiation in Fp+powFp :: Integer -> Integer -> Integer+powFp !base !exp = go 1 base exp where+  go !acc _  0  = acc+  go !acc !b !e = if (e .&. 1 > 0)+    then go (modp (acc*b)) (modp (b*b)) (shiftR e 1)+    else go        acc     (modp (b*b)) (shiftR e 1)++--------------------------------------------------------------------------------+-- * square root in Fp++secp256k1_ndiv4   = 28948022309329048855892746252171976963317496166410141009864396001977208667915+secp256k1_ndiv4p1 = 28948022309329048855892746252171976963317496166410141009864396001977208667916++-- | (One of the) square roots mod p (if any exists). Since p is a prime and @p = 4k+3@, +-- we have a fortunately a very easy solution by some quadratic reciprocity stuff I don't +-- remember how exactly works+-- (but it's elementary number theory)+--+-- <http://course1.winona.edu/eerrthum/13Spring/SquareRoots.pdf>+--+unsafeSqrtFp :: Integer -> Integer+unsafeSqrtFp !a = powFp (modp a) secp256k1_ndiv4p1++-- | Note that square roots do not always exist in Fp: consider for example p=7,+-- then 3, 5 and 6 do not have square roots, while the rest has two (except 0).+-- +-- In general, if x is a square root then so is (p-x), since +--+-- > (p-x)*(p-x) = p*p - p*(2*x) + x*x = x*x (mod p)+--+-- And that should be all solutions, since it's a quadratic equation.+--+sqrtFp :: Integer -> Maybe Integer+sqrtFp x2 = if mulFp x x == modp x2 then Just x else Nothing +  where x = unsafeSqrtFp x2++--------------------------------------------------------------------------------++-- | For simpler (and safer) code, we introduce a newtype for elements of Fp+newtype Fp = Fp { unFp :: Integer } deriving (Eq,Show)++toFp :: Integer -> Fp+toFp x = Fp (modp x)++fromFp :: Fp -> Integer+fromFp (Fp x) = x ++instance Num Fp where+  Fp x + Fp y   = Fp (addFp x y)+  Fp x - Fp y   = Fp (subFp x y)+  Fp x * Fp y   = Fp (mulFp x y)+  negate (Fp x) = Fp (negFp x)+  fromInteger   = Fp . modp+  abs    = error "Fp/abs"+  signum = error "Fp/signum"++instance Fractional Fp where+  Fp x / Fp y  = Fp (divFp x y)+  recip (Fp x) = Fp (invFp x)+  fromRational = error "Fp/fromRational: does not make much sense"++-- | Note that this gives only one of the possibly two square roots+sqrt_p :: Fp -> Maybe Fp+sqrt_p (Fp x2) = case sqrtFp x2 of+  Nothing -> Nothing+  Just y  -> Just (Fp y)++-- pow_p :: Fp -> Fp -> Fp+-- pow_p (Fp b) (Fp e) = Fp (powFp b e)++pow_p :: Fp -> Integer -> Fp+pow_p (Fp b) e = Fp (powFp b e)++--------------------------------------------------------------------------------
+ Bitcoin/Crypto/Hash/HMAC.hs view
@@ -0,0 +1,245 @@++-- | Hash-based message authentication code (HMAC).+-- +-- See <http://en.wikipedia.org/wiki/Hmac>++module Bitcoin.Crypto.Hash.HMAC where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits+import Data.Char  -- for testing only++import Bitcoin.Misc.BigInt+import Bitcoin.Misc.OctetStream++import Bitcoin.Crypto.Hash.SHA1+import Bitcoin.Crypto.Hash.SHA256+import Bitcoin.Crypto.Hash.SHA512+import Bitcoin.Crypto.Hash.MD5++--------------------------------------------------------------------------------++newtype HMAC a = HMAC { unHMAC :: a } deriving (Eq,Ord,Show)++-- | The HMAC key should be an integer between @1@ and @2^512-1@ +-- (or @2^1024-1@ in case of SHA512)+newtype HMACKey = HMACKey { unHMACKey :: Integer } deriving (Eq,Ord,Show)++--------------------------------------------------------------------------------++-- | Mainly for testing. 64 byte blocksize version.+--+-- Note: blocksize is 64 bytes (512 bits) for both SHA1 and SHA256 and even MD5,+-- but 128 bytes (1024 bits) for SHA512+--+-- Also it seems that according the spec long keys should be hashed.+-- Even though the hash is half as long (but we use zero padding anyway)+--+hmacKeyFromString64 :: OctetStream a => a -> HMACKey+hmacKeyFromString64 chars +  | n <= 64   = HMACKey $ (toIntegerLE          word8list) -- `mod` modulus+  | otherwise = HMACKey $ (toIntegerLE $ sha256 word8list) -- `mod` modulus+  where+    modulus = 2^(512::Int) :: Integer +    word8list = toWord8List chars+    n = length word8list++-- | Mainly for testing. 128 byte blocksize version+--+-- Note: blocksize is 64 bytes (512 bits) for both SHA1 and SHA256 and even MD5,+-- but 128 bytes (1024 bits) for SHA512+--+-- Also it seems that according the spec long keys should be hashed.+-- Even though the hash is half as long (but we use zero padding anyway)+--+hmacKeyFromString128 :: OctetStream a => a -> HMACKey+hmacKeyFromString128 chars +  | n <= 128   = HMACKey $ (toIntegerLE          word8list) -- `mod` modulus+  | otherwise  = HMACKey $ (toIntegerLE $ sha512 word8list) -- `mod` modulus+  where+    modulus = 2^(1024::Int) :: Integer +    word8list = toWord8List chars+    n = length word8list++--------------------------------------------------------------------------------++hmacSha1 :: OctetStream a => HMACKey -> a -> HMAC SHA1+hmacSha1 (HMACKey keyInt) msg = HMAC $ sha1 ( outer ++ inner_hash ) where++  blocksize = 64 :: Int++  key  = take blocksize (littleEndianUnrollInteger keyInt ++ replicate blocksize 0)++  opad = replicate blocksize 0x5c :: [Word8]+  ipad = replicate blocksize 0x36 :: [Word8]++  outer = zipWith xor key opad+  inner = zipWith xor key ipad++  inner_hash = toWord8List $ sha1 $ inner ++ toWord8List msg++--------------------------------------------------------------------------------++hmacSha256 :: OctetStream a => HMACKey -> a -> HMAC SHA256+hmacSha256 (HMACKey keyInt) msg = HMAC $ sha256 ( outer ++ inner_hash ) where++  blocksize = 64 :: Int++  key  = take blocksize (littleEndianUnrollInteger keyInt ++ replicate blocksize 0)++  opad = replicate blocksize 0x5c :: [Word8]+  ipad = replicate blocksize 0x36 :: [Word8]++  outer = zipWith xor key opad+  inner = zipWith xor key ipad++  inner_hash = toWord8List $ sha256 $ inner ++ toWord8List msg      ++--------------------------------------------------------------------------------++hmacSha512 :: OctetStream a => HMACKey -> a -> HMAC SHA512+hmacSha512 (HMACKey keyInt) msg = HMAC $ sha512 ( outer ++ inner_hash ) where++  blocksize = 128 :: Int++  key  = take blocksize (littleEndianUnrollInteger keyInt ++ replicate blocksize 0)++  opad = replicate blocksize 0x5c :: [Word8]+  ipad = replicate blocksize 0x36 :: [Word8]++  outer = zipWith xor key opad+  inner = zipWith xor key ipad++  inner_hash = toWord8List $ sha512 $ inner ++ toWord8List msg      ++--------------------------------------------------------------------------------++hmacMD5 :: OctetStream a => HMACKey -> a -> HMAC MD5+hmacMD5 (HMACKey keyInt) msg = HMAC $ md5 ( outer ++ inner_hash ) where++  blocksize = 64 :: Int++  key  = take blocksize (littleEndianUnrollInteger keyInt ++ replicate blocksize 0)++  opad = replicate blocksize 0x5c :: [Word8]+  ipad = replicate blocksize 0x36 :: [Word8]++  outer = zipWith xor key opad+  inner = zipWith xor key ipad++  inner_hash = toWord8List $ md5 $ inner ++ toWord8List msg      ++--------------------------------------------------------------------------------++{- +From wikipedia, some test vectors:++HMAC_MD5("", "") = 0x74e6f7298a9c2d168935f58c001bad88+HMAC_SHA1("", "") = 0xfbdb1d1b18aa6c08324b7d64b71fb76370690e1d+HMAC_SHA256("", "") = 0xb613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad++Here are some non-empty HMAC values, assuming 8-bit ASCII or UTF-8 encoding:++HMAC_MD5("key", "The quick brown fox jumps over the lazy dog") = 0x80070713463e7749b90c2dc24911e275+HMAC_SHA1("key", "The quick brown fox jumps over the lazy dog") = 0xde7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9+HMAC_SHA256("key", "The quick brown fox jumps over the lazy dog") = 0xf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8++-}++{-  +main = do+  let key0 = hmacKeyFromString64 ""+  let key1 = hmacKeyFromString64 "key"+  print key0+  print key1+  print $ hmacMD5    key0 ""+  print $ hmacSha1   key0 ""+  print $ hmacSha256 key0 ""+  print $ hmacMD5    key1 "The quick brown fox jumps over the lazy dog"+  print $ hmacSha1   key1 "The quick brown fox jumps over the lazy dog"+  print $ hmacSha256 key1 "The quick brown fox jumps over the lazy dog"+-}++--------------------------------------------------------------------------------++{-++hmacTestcase256 (keystring,msg,hmacstring256,hmacstring512) = myhmac where+  key    = hmacKeyFromString64 keystring+  myhmac = hmacSha256 key msg++hmacTestcase512 (keystring,msg,hmacstring256,hmacstring512) = myhmac where+  key    = hmacKeyFromString128 keystring+  myhmac = hmacSha512 key msg++checkTestcase256_512 inp@(keystring,msg,hmacstring256,hmacstring512) = ok where+  my256 = hmacTestcase256 inp+  my512 = hmacTestcase512 inp+  ok    =  ( ("HMAC SHA256<" ++ hmacstring256 ++ ">") == show my256 )+        && ( ("HMAC SHA512<" ++ hmacstring512 ++ ">") == show my512 )++-- | from <http://tools.ietf.org/html/rfc4231>, test vectors for hmac-sha256 and hmac-sha512 +testcases_hmac_sha256_sha512 =+  [ testcase1+  , testcase2+  , testcase3+  , testcase4+  , testcase5+  , testcase6+  , testcase7+  ]+  where++  testcase1 = ( replicate 20 '\x0b' , "Hi There" , hmac256 , hmac512 ) where+    hmac256 = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"+    hmac512 = "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"++  testcase2 = ( "Jefe" , "what do ya want for nothing?" , hmac256 , hmac512 ) where+    hmac256 = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"+    hmac512 = "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737"++  testcase3 = ( replicate 20 '\xaa' , replicate 50 '\xdd' , hmac256 , hmac512 ) where +    hmac256 = "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"+    hmac512 = "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb"++  testcase4 = ( map chr [1..25::Int] , replicate 50 '\xcd' , hmac256 , hmac512 ) where+    hmac256 = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"+    hmac512 = "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd"++  testcase5 = ( replicate 20 '\x0c' , "Test With Truncation" , hmac256 , hmac512 ) where+    hmac256_truncated+            = "a3b6167473100ee06e0c796c2955552b"+    hmac256 = "a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5"+    hmac512_truncated +            = "415fad6271580a531d4179bc891d87a6"  -- this is a truncation test, wtf. well, i don't care about truncation :)+    hmac512 = "415fad6271580a531d4179bc891d87a650188707922a4fbb36663a1eb16da008711c5b50ddd0fc235084eb9d3364a1454fb2ef67cd1d29fe6773068ea266e96b"++  testcase6 = ( replicate 131 '\xaa' , msg , hmac256 , hmac512 ) where +    msg = concat +     [ ("Test Using Large")+     , ("r Than Block-Siz")+     , ("e Key - Hash Key")+     , (" First") +     ]+    hmac256 = "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"+    hmac512 = "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598"++  testcase7 = ( replicate 131 '\xaa' , msg , hmac256 , hmac512 ) where +    msg = concat +      [ ("This is a test u")+      , ("sing a larger th")+      , ("an block-size ke")+      , ("y and a larger t")+      , ("han block-size d")+      , ("ata. The key nee")+      , ("ds to be hashed ")+      , ("before being use")+      , ("d by the HMAC al")+      , ("gorithm.")+      ]+    hmac256 = "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"+    hmac512 = "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"++-}
+ Bitcoin/Crypto/Hash/KDF.hs view
@@ -0,0 +1,90 @@++-- | Key Derivation Functions (KDF).+--+-- These are used to derive larger symmetric keys from a small (say, 256 bit) shared secret+-- generated using eg. Diffie-Hellman key exchange.++module Bitcoin.Crypto.Hash.KDF +  ( SharedSecret(..)+  , concatenatingKDF +  , foldingKDF+  ) +  where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits++import Bitcoin.Misc.OctetStream++import Bitcoin.Crypto.Hash.SHA256++import Bitcoin.Crypto.EC.DiffieHellman ( SharedSecret(..) )++import qualified Data.ByteString      as B+import qualified Data.ByteString.Lazy as L++--------------------------------------------------------------------------------++-- | Concatenation-based Key Derivation Function.+--+-- Basically:+--+-- > output = Hash[1] || Hash[2] || Hash[3] || ...+-- >+-- > Hash[counter] = H ( counter || Z || publicInfo )+--+-- where H is the SHA256 hash function, Z is the shared secret, +-- and the counter is a big-endian encoded 32 bit word.+--+-- This is more-or-less the NIST-800-56-Concatenation-KDF standard.+-- +concatenatingKDF +  :: OctetStream publicInfo +  => SharedSecret             -- ^ shared secret (for example estabilished by Diffie-Hellman key exchange)+  -> publicInfo               -- ^ publicly avaliable information about the parties (for example, the IDs of the two parties)+  -> Int                      -- ^ desired output length+  -> L.ByteString+concatenatingKDF z publicInfo len = L.take (fromIntegral len) (L.fromChunks $ take n hashes) where+  n       = div (len+31) 32+  zpublic = B.append (toByteString z) (toByteString publicInfo)+  hashes  = [ toByteString (sha256 (B.append (word32BE counter) zpublic)) | counter <- [1..] ]++--------------------------------------------------------------------------------++-- | This is similar to the previous, however, we also use the previous hash when+-- computing the next hash:+--+-- > Hash[counter] = H ( counter || Hash[counter-1] || Z || publicInfo )+--+-- @Hash[0]@ is set to ad-hoc value, presently @[0x5c,0x5c,0x5c...]@+--+foldingKDF :: OctetStream publicInfo +  => SharedSecret             -- ^ shared secret (for example estabilished by Diffie-Hellman key exchange)+  -> publicInfo               -- ^ publicly avaliable information about the parties (for example, the IDs of the two parties)+  -> Int                      -- ^ desired output length+  -> L.ByteString+foldingKDF z publicInfo len = L.take (fromIntegral len) (L.fromChunks $ take n hashes) where++  n       = div (len+31) 32+  zpublic = B.append (toByteString z) (toByteString publicInfo)+  hashes  = tail $ scanl worker initial [1..] ++  initial = toByteString $ replicate 32 (0x5c :: Word8)++  worker :: B.ByteString -> Word32 -> B.ByteString+  worker prevhash counter = toByteString $ sha256 $ B.concat [ word32BE counter , prevhash , zpublic ]++--------------------------------------------------------------------------------++-- | A 32 bit word as a big-endian bytestring+word32BE :: Word32 -> B.ByteString+word32BE w = B.pack+  [ fromIntegral (  shiftR w 24           )+  , fromIntegral ( (shiftR w 16) .&. 0xff )+  , fromIntegral ( (shiftR w  8) .&. 0xff )+  , fromIntegral (         w     .&. 0xff )+  ]++--------------------------------------------------------------------------------
+ Bitcoin/Crypto/Hash/MD5.hs view
@@ -0,0 +1,119 @@++-- | MD5 hash (for completeness)++{-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-}+module Bitcoin.Crypto.Hash.MD5 +  ( MD5(..)+  , md5+  )+  where++--------------------------------------------------------------------------------++import Data.Char (chr,ord)++import Data.Int+import Data.Word++import Control.Monad ( liftM , forM_ )++import qualified Data.ByteString        as B+import qualified Data.ByteString.Unsafe as B+import Data.ByteString (ByteString)++import Foreign+import Foreign.C+import Foreign.Marshal+import Foreign.Storable++import System.IO.Unsafe as Unsafe++import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.HexString++--------------------------------------------------------------------------------++{-+extern void MD5_Init(MD5_CTX *ctx);+extern void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size);+extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);+-}++data MD5CTX = MD5CTX++instance Storable MD5CTX where+  alignment _ = 8 +  sizeOf    _ = 64 + (16+4+2) * sizeOf (undefined :: CUInt)+  peek        = error "MD5CTX/Storable/peek: not implemented"+  poke        = error "MD5CTX/Storable/poke: not implemented"++foreign import ccall safe "md5.h MD5_Init"   c_MD5_Init   :: Ptr MD5CTX -> IO ()+foreign import ccall safe "md5.h MD5_Update" c_MD5_Update :: Ptr MD5CTX -> Ptr CChar -> CULong -> IO ()+foreign import ccall safe "md5.h MD5_Final"  c_MD5_Final  :: Ptr CUChar -> Ptr MD5CTX -> IO ()++withMD5CTX :: (Ptr MD5CTX -> IO ()) -> IO MD5+withMD5CTX action = do+  alloca $ \pctx -> do+    c_MD5_Init pctx+    action pctx+    allocaBytes 16 $ \pres -> do+      c_MD5_Final pres pctx+      bytes <- peekArray 16 (castPtr pres :: Ptr Word8)+      return $ MD5 $ B.pack bytes  ++--------------------------------------------------------------------------------++{-+newtype MD5 = MD5 ByteString deriving (Eq)++instance Show MD5 where+  show (MD5 bs) = concatMap showByte (B.unpack bs) where+    showByte b = let k = fromIntegral b :: Int in [ showNibble (shiftR k 4) , showNibble (k .&. 15) ] +    showNibble n = if n<10 then (chr (n+48)) else chr (n+97-10)+               +stringMD5 :: String -> MD5+stringMD5 s = Unsafe.unsafePerformIO $ do+  withMD5CTX $ \pctx -> do+    withCStringLen s $ \(ptr,len) -> c_MD5_Update pctx ptr (fromIntegral len)++bytestringMD5 :: ByteString -> MD5+bytestringMD5 bs = Unsafe.unsafePerformIO $ do+  withMD5CTX $ \pctx -> do+    B.unsafeUseAsCStringLen bs $ \(ptr,len) -> c_MD5_Update pctx ptr (fromIntegral len)+-}++--------------------------------------------------------------------------------++newtype MD5 = MD5 { unMD5 :: B.ByteString } deriving (Eq,Ord)++instance Show MD5 where show (MD5 bs) = "MD5<" ++ toHexStringChars bs ++ ">"++instance OctetStream MD5 where+  toByteString = unMD5+  fromByteString bs = case B.length bs of+    16 -> MD5 bs+    _  -> error "MD5/fromByteString: MD5 is expected to be 16 bytes"++--------------------------------------------------------------------------------++md5 :: OctetStream a => a -> MD5+md5 x = MD5 $ Unsafe.unsafePerformIO (md5_IO $ toByteString x)++md5_IO :: B.ByteString -> IO ByteString+md5_IO msg = liftM unMD5 $ do+  withMD5CTX $ \pctx -> do+    B.unsafeUseAsCStringLen msg $ \(ptr,len) -> c_MD5_Update pctx ptr (fromIntegral len)++--------------------------------------------------------------------------------++md5_test_vectors :: [(String,String)]+md5_test_vectors = +  [ ( "The quick brown fox jumps over the lazy dog"   , "9e107d9d372bb6826bd81d3542a419d6" )+  , ( "The quick brown fox jumps over the lazy dog."  , "e4d909c290d0fb1ca068ffaddf22cbd0" )+  , ( ""                                              , "d41d8cd98f00b204e9800998ecf8427e" )+  ]++md5_test = do+  forM_ (md5_test_vectors) $ \(msg,ref) -> do+    print (md5 msg)+    print ref
+ Bitcoin/Crypto/Hash/MD5/md5.c view
@@ -0,0 +1,295 @@+/*+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.+ * MD5 Message-Digest Algorithm (RFC 1321).+ *+ * Homepage:+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5+ *+ * Author:+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>+ *+ * This software was written by Alexander Peslyak in 2001.  No copyright is+ * claimed, and the software is hereby placed in the public domain.+ * In case this attempt to disclaim copyright and place the software in the+ * public domain is deemed null and void, then the software is+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the+ * general public under the following terms:+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted.+ *+ * There's ABSOLUTELY NO WARRANTY, express or implied.+ *+ * (This is a heavily cut-down "BSD license".)+ *+ * This differs from Colin Plumb's older public domain implementation in that+ * no exactly 32-bit integer data type is required (any 32-bit or wider+ * unsigned integer data type will do), there's no compile-time endianness+ * configuration, and the function prototypes match OpenSSL's.  No code from+ * Colin Plumb's implementation has been reused; this comment merely compares+ * the properties of the two independent implementations.+ *+ * The primary goals of this implementation are portability and ease of use.+ * It is meant to be fast, but not as fast as possible.  Some known+ * optimizations are not included to reduce source code size and avoid+ * compile-time configuration.+ */++#ifndef HAVE_OPENSSL++#include <string.h>++#include "md5.h"++/*+ * The basic MD5 functions.+ *+ * F and G are optimized compared to their RFC 1321 definitions for+ * architectures that lack an AND-NOT instruction, just like in Colin Plumb's+ * implementation.+ */+#define F(x, y, z)			((z) ^ ((x) & ((y) ^ (z))))+#define G(x, y, z)			((y) ^ ((z) & ((x) ^ (y))))+#define H(x, y, z)			((x) ^ (y) ^ (z))+#define I(x, y, z)			((y) ^ ((x) | ~(z)))++/*+ * The MD5 transformation for all four rounds.+ */+#define STEP(f, a, b, c, d, x, t, s) \+	(a) += f((b), (c), (d)) + (x) + (t); \+	(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \+	(a) += (b);++/*+ * SET reads 4 input bytes in little-endian byte order and stores them+ * in a properly aligned word in host byte order.+ *+ * The check for little-endian architectures that tolerate unaligned+ * memory accesses is just an optimization.  Nothing will break if it+ * doesn't work.+ */+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)+#define SET(n) \+	(*(MD5_u32plus *)&ptr[(n) * 4])+#define GET(n) \+	SET(n)+#else+#define SET(n) \+	(ctx->block[(n)] = \+	(MD5_u32plus)ptr[(n) * 4] | \+	((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \+	((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \+	((MD5_u32plus)ptr[(n) * 4 + 3] << 24))+#define GET(n) \+	(ctx->block[(n)])+#endif++/*+ * This processes one or more 64-byte data blocks, but does NOT update+ * the bit counters.  There are no alignment requirements.+ */+static void *body(MD5_CTX *ctx, void *data, unsigned long size)+{+	unsigned char *ptr;+	MD5_u32plus a, b, c, d;+	MD5_u32plus saved_a, saved_b, saved_c, saved_d;++	ptr = data;++	a = ctx->a;+	b = ctx->b;+	c = ctx->c;+	d = ctx->d;++	do {+		saved_a = a;+		saved_b = b;+		saved_c = c;+		saved_d = d;++/* Round 1 */+		STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)+		STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)+		STEP(F, c, d, a, b, SET(2), 0x242070db, 17)+		STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)+		STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)+		STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)+		STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)+		STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)+		STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)+		STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)+		STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)+		STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)+		STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)+		STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)+		STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)+		STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)++/* Round 2 */+		STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)+		STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)+		STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)+		STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)+		STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)+		STEP(G, d, a, b, c, GET(10), 0x02441453, 9)+		STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)+		STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)+		STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)+		STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)+		STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)+		STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)+		STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)+		STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)+		STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)+		STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)++/* Round 3 */+		STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)+		STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)+		STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)+		STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)+		STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)+		STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)+		STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)+		STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)+		STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)+		STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)+		STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)+		STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)+		STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)+		STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)+		STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)+		STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)++/* Round 4 */+		STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)+		STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)+		STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)+		STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)+		STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)+		STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)+		STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)+		STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)+		STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)+		STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)+		STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)+		STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)+		STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)+		STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)+		STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)+		STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)++		a += saved_a;+		b += saved_b;+		c += saved_c;+		d += saved_d;++		ptr += 64;+	} while (size -= 64);++	ctx->a = a;+	ctx->b = b;+	ctx->c = c;+	ctx->d = d;++	return ptr;+}++void MD5_Init(MD5_CTX *ctx)+{+	ctx->a = 0x67452301;+	ctx->b = 0xefcdab89;+	ctx->c = 0x98badcfe;+	ctx->d = 0x10325476;++	ctx->lo = 0;+	ctx->hi = 0;+}++void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size)+{+	MD5_u32plus saved_lo;+	unsigned long used, free;++	saved_lo = ctx->lo;+	if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)+		ctx->hi++;+	ctx->hi += size >> 29;++	used = saved_lo & 0x3f;++	if (used) {+		free = 64 - used;++		if (size < free) {+			memcpy(&ctx->buffer[used], data, size);+			return;+		}++		memcpy(&ctx->buffer[used], data, free);+		data = (unsigned char *)data + free;+		size -= free;+		body(ctx, ctx->buffer, 64);+	}++	if (size >= 64) {+		data = body(ctx, data, size & ~(unsigned long)0x3f);+		size &= 0x3f;+	}++	memcpy(ctx->buffer, data, size);+}++void MD5_Final(unsigned char *result, MD5_CTX *ctx)+{+	unsigned long used, free;++	used = ctx->lo & 0x3f;++	ctx->buffer[used++] = 0x80;++	free = 64 - used;++	if (free < 8) {+		memset(&ctx->buffer[used], 0, free);+		body(ctx, ctx->buffer, 64);+		used = 0;+		free = 64;+	}++	memset(&ctx->buffer[used], 0, free - 8);++	ctx->lo <<= 3;+	ctx->buffer[56] = ctx->lo;+	ctx->buffer[57] = ctx->lo >> 8;+	ctx->buffer[58] = ctx->lo >> 16;+	ctx->buffer[59] = ctx->lo >> 24;+	ctx->buffer[60] = ctx->hi;+	ctx->buffer[61] = ctx->hi >> 8;+	ctx->buffer[62] = ctx->hi >> 16;+	ctx->buffer[63] = ctx->hi >> 24;++	body(ctx, ctx->buffer, 64);++	result[0] = ctx->a;+	result[1] = ctx->a >> 8;+	result[2] = ctx->a >> 16;+	result[3] = ctx->a >> 24;+	result[4] = ctx->b;+	result[5] = ctx->b >> 8;+	result[6] = ctx->b >> 16;+	result[7] = ctx->b >> 24;+	result[8] = ctx->c;+	result[9] = ctx->c >> 8;+	result[10] = ctx->c >> 16;+	result[11] = ctx->c >> 24;+	result[12] = ctx->d;+	result[13] = ctx->d >> 8;+	result[14] = ctx->d >> 16;+	result[15] = ctx->d >> 24;++	memset(ctx, 0, sizeof(*ctx));+}++#endif
+ Bitcoin/Crypto/Hash/MD5/md5.h view
@@ -0,0 +1,45 @@+/*+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.+ * MD5 Message-Digest Algorithm (RFC 1321).+ *+ * Homepage:+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5+ *+ * Author:+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>+ *+ * This software was written by Alexander Peslyak in 2001.  No copyright is+ * claimed, and the software is hereby placed in the public domain.+ * In case this attempt to disclaim copyright and place the software in the+ * public domain is deemed null and void, then the software is+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the+ * general public under the following terms:+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted.+ *+ * There's ABSOLUTELY NO WARRANTY, express or implied.+ *+ * See md5.c for more information.+ */++#ifdef HAVE_OPENSSL+#include <openssl/md5.h>+#elif !defined(_MD5_H)+#define _MD5_H++/* Any 32-bit or wider unsigned integer data type will do */+typedef unsigned int MD5_u32plus;++typedef struct {+	MD5_u32plus lo, hi;+	MD5_u32plus a, b, c, d;+	unsigned char buffer[64];+	MD5_u32plus block[16];+} MD5_CTX;++extern void MD5_Init(MD5_CTX *ctx);+extern void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size);+extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);++#endif
+ Bitcoin/Crypto/Hash/RipEmd/rmd160.c view
@@ -0,0 +1,270 @@+/********************************************************************\+ *+ *      FILE:     rmd160.c+ *+ *      CONTENTS: A sample C-implementation of the RIPEMD-160+ *                hash-function.+ *      TARGET:   any computer with an ANSI C compiler+ *+ *      AUTHOR:   Antoon Bosselaers, ESAT-COSIC+ *      DATE:     1 March 1996+ *      VERSION:  1.0+ *+ *      Copyright (c) Katholieke Universiteit Leuven+ *      1996, All Rights Reserved+ *+\********************************************************************/++/*  header files */+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include "rmd160.h"      ++/********************************************************************/++void MDinit(dword *MDbuf)+{+   MDbuf[0] = 0x67452301UL;+   MDbuf[1] = 0xefcdab89UL;+   MDbuf[2] = 0x98badcfeUL;+   MDbuf[3] = 0x10325476UL;+   MDbuf[4] = 0xc3d2e1f0UL;++   return;+}++/********************************************************************/++void compress(dword *MDbuf, dword *X)+{+   dword aa = MDbuf[0],  bb = MDbuf[1],  cc = MDbuf[2],+         dd = MDbuf[3],  ee = MDbuf[4];+   dword aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2],+         ddd = MDbuf[3], eee = MDbuf[4];++   /* round 1 */+   FF(aa, bb, cc, dd, ee, X[ 0], 11);+   FF(ee, aa, bb, cc, dd, X[ 1], 14);+   FF(dd, ee, aa, bb, cc, X[ 2], 15);+   FF(cc, dd, ee, aa, bb, X[ 3], 12);+   FF(bb, cc, dd, ee, aa, X[ 4],  5);+   FF(aa, bb, cc, dd, ee, X[ 5],  8);+   FF(ee, aa, bb, cc, dd, X[ 6],  7);+   FF(dd, ee, aa, bb, cc, X[ 7],  9);+   FF(cc, dd, ee, aa, bb, X[ 8], 11);+   FF(bb, cc, dd, ee, aa, X[ 9], 13);+   FF(aa, bb, cc, dd, ee, X[10], 14);+   FF(ee, aa, bb, cc, dd, X[11], 15);+   FF(dd, ee, aa, bb, cc, X[12],  6);+   FF(cc, dd, ee, aa, bb, X[13],  7);+   FF(bb, cc, dd, ee, aa, X[14],  9);+   FF(aa, bb, cc, dd, ee, X[15],  8);+                             +   /* round 2 */+   GG(ee, aa, bb, cc, dd, X[ 7],  7);+   GG(dd, ee, aa, bb, cc, X[ 4],  6);+   GG(cc, dd, ee, aa, bb, X[13],  8);+   GG(bb, cc, dd, ee, aa, X[ 1], 13);+   GG(aa, bb, cc, dd, ee, X[10], 11);+   GG(ee, aa, bb, cc, dd, X[ 6],  9);+   GG(dd, ee, aa, bb, cc, X[15],  7);+   GG(cc, dd, ee, aa, bb, X[ 3], 15);+   GG(bb, cc, dd, ee, aa, X[12],  7);+   GG(aa, bb, cc, dd, ee, X[ 0], 12);+   GG(ee, aa, bb, cc, dd, X[ 9], 15);+   GG(dd, ee, aa, bb, cc, X[ 5],  9);+   GG(cc, dd, ee, aa, bb, X[ 2], 11);+   GG(bb, cc, dd, ee, aa, X[14],  7);+   GG(aa, bb, cc, dd, ee, X[11], 13);+   GG(ee, aa, bb, cc, dd, X[ 8], 12);++   /* round 3 */+   HH(dd, ee, aa, bb, cc, X[ 3], 11);+   HH(cc, dd, ee, aa, bb, X[10], 13);+   HH(bb, cc, dd, ee, aa, X[14],  6);+   HH(aa, bb, cc, dd, ee, X[ 4],  7);+   HH(ee, aa, bb, cc, dd, X[ 9], 14);+   HH(dd, ee, aa, bb, cc, X[15],  9);+   HH(cc, dd, ee, aa, bb, X[ 8], 13);+   HH(bb, cc, dd, ee, aa, X[ 1], 15);+   HH(aa, bb, cc, dd, ee, X[ 2], 14);+   HH(ee, aa, bb, cc, dd, X[ 7],  8);+   HH(dd, ee, aa, bb, cc, X[ 0], 13);+   HH(cc, dd, ee, aa, bb, X[ 6],  6);+   HH(bb, cc, dd, ee, aa, X[13],  5);+   HH(aa, bb, cc, dd, ee, X[11], 12);+   HH(ee, aa, bb, cc, dd, X[ 5],  7);+   HH(dd, ee, aa, bb, cc, X[12],  5);++   /* round 4 */+   II(cc, dd, ee, aa, bb, X[ 1], 11);+   II(bb, cc, dd, ee, aa, X[ 9], 12);+   II(aa, bb, cc, dd, ee, X[11], 14);+   II(ee, aa, bb, cc, dd, X[10], 15);+   II(dd, ee, aa, bb, cc, X[ 0], 14);+   II(cc, dd, ee, aa, bb, X[ 8], 15);+   II(bb, cc, dd, ee, aa, X[12],  9);+   II(aa, bb, cc, dd, ee, X[ 4],  8);+   II(ee, aa, bb, cc, dd, X[13],  9);+   II(dd, ee, aa, bb, cc, X[ 3], 14);+   II(cc, dd, ee, aa, bb, X[ 7],  5);+   II(bb, cc, dd, ee, aa, X[15],  6);+   II(aa, bb, cc, dd, ee, X[14],  8);+   II(ee, aa, bb, cc, dd, X[ 5],  6);+   II(dd, ee, aa, bb, cc, X[ 6],  5);+   II(cc, dd, ee, aa, bb, X[ 2], 12);++   /* round 5 */+   JJ(bb, cc, dd, ee, aa, X[ 4],  9);+   JJ(aa, bb, cc, dd, ee, X[ 0], 15);+   JJ(ee, aa, bb, cc, dd, X[ 5],  5);+   JJ(dd, ee, aa, bb, cc, X[ 9], 11);+   JJ(cc, dd, ee, aa, bb, X[ 7],  6);+   JJ(bb, cc, dd, ee, aa, X[12],  8);+   JJ(aa, bb, cc, dd, ee, X[ 2], 13);+   JJ(ee, aa, bb, cc, dd, X[10], 12);+   JJ(dd, ee, aa, bb, cc, X[14],  5);+   JJ(cc, dd, ee, aa, bb, X[ 1], 12);+   JJ(bb, cc, dd, ee, aa, X[ 3], 13);+   JJ(aa, bb, cc, dd, ee, X[ 8], 14);+   JJ(ee, aa, bb, cc, dd, X[11], 11);+   JJ(dd, ee, aa, bb, cc, X[ 6],  8);+   JJ(cc, dd, ee, aa, bb, X[15],  5);+   JJ(bb, cc, dd, ee, aa, X[13],  6);++   /* parallel round 1 */+   JJJ(aaa, bbb, ccc, ddd, eee, X[ 5],  8);+   JJJ(eee, aaa, bbb, ccc, ddd, X[14],  9);+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 7],  9);+   JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11);+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13);+   JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15);+   JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15);+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 4],  5);+   JJJ(ccc, ddd, eee, aaa, bbb, X[13],  7);+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 6],  7);+   JJJ(aaa, bbb, ccc, ddd, eee, X[15],  8);+   JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11);+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14);+   JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14);+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12);+   JJJ(aaa, bbb, ccc, ddd, eee, X[12],  6);++   /* parallel round 2 */+   III(eee, aaa, bbb, ccc, ddd, X[ 6],  9); +   III(ddd, eee, aaa, bbb, ccc, X[11], 13);+   III(ccc, ddd, eee, aaa, bbb, X[ 3], 15);+   III(bbb, ccc, ddd, eee, aaa, X[ 7],  7);+   III(aaa, bbb, ccc, ddd, eee, X[ 0], 12);+   III(eee, aaa, bbb, ccc, ddd, X[13],  8);+   III(ddd, eee, aaa, bbb, ccc, X[ 5],  9);+   III(ccc, ddd, eee, aaa, bbb, X[10], 11);+   III(bbb, ccc, ddd, eee, aaa, X[14],  7);+   III(aaa, bbb, ccc, ddd, eee, X[15],  7);+   III(eee, aaa, bbb, ccc, ddd, X[ 8], 12);+   III(ddd, eee, aaa, bbb, ccc, X[12],  7);+   III(ccc, ddd, eee, aaa, bbb, X[ 4],  6);+   III(bbb, ccc, ddd, eee, aaa, X[ 9], 15);+   III(aaa, bbb, ccc, ddd, eee, X[ 1], 13);+   III(eee, aaa, bbb, ccc, ddd, X[ 2], 11);++   /* parallel round 3 */+   HHH(ddd, eee, aaa, bbb, ccc, X[15],  9);+   HHH(ccc, ddd, eee, aaa, bbb, X[ 5],  7);+   HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15);+   HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11);+   HHH(eee, aaa, bbb, ccc, ddd, X[ 7],  8);+   HHH(ddd, eee, aaa, bbb, ccc, X[14],  6);+   HHH(ccc, ddd, eee, aaa, bbb, X[ 6],  6);+   HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14);+   HHH(aaa, bbb, ccc, ddd, eee, X[11], 12);+   HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13);+   HHH(ddd, eee, aaa, bbb, ccc, X[12],  5);+   HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14);+   HHH(bbb, ccc, ddd, eee, aaa, X[10], 13);+   HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13);+   HHH(eee, aaa, bbb, ccc, ddd, X[ 4],  7);+   HHH(ddd, eee, aaa, bbb, ccc, X[13],  5);++   /* parallel round 4 */   +   GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15);+   GGG(bbb, ccc, ddd, eee, aaa, X[ 6],  5);+   GGG(aaa, bbb, ccc, ddd, eee, X[ 4],  8);+   GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11);+   GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14);+   GGG(ccc, ddd, eee, aaa, bbb, X[11], 14);+   GGG(bbb, ccc, ddd, eee, aaa, X[15],  6);+   GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14);+   GGG(eee, aaa, bbb, ccc, ddd, X[ 5],  6);+   GGG(ddd, eee, aaa, bbb, ccc, X[12],  9);+   GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12);+   GGG(bbb, ccc, ddd, eee, aaa, X[13],  9);+   GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12);+   GGG(eee, aaa, bbb, ccc, ddd, X[ 7],  5);+   GGG(ddd, eee, aaa, bbb, ccc, X[10], 15);+   GGG(ccc, ddd, eee, aaa, bbb, X[14],  8);++   /* parallel round 5 */+   FFF(bbb, ccc, ddd, eee, aaa, X[12] ,  8);+   FFF(aaa, bbb, ccc, ddd, eee, X[15] ,  5);+   FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12);+   FFF(ddd, eee, aaa, bbb, ccc, X[ 4] ,  9);+   FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12);+   FFF(bbb, ccc, ddd, eee, aaa, X[ 5] ,  5);+   FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14);+   FFF(eee, aaa, bbb, ccc, ddd, X[ 7] ,  6);+   FFF(ddd, eee, aaa, bbb, ccc, X[ 6] ,  8);+   FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13);+   FFF(bbb, ccc, ddd, eee, aaa, X[13] ,  6);+   FFF(aaa, bbb, ccc, ddd, eee, X[14] ,  5);+   FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15);+   FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13);+   FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11);+   FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11);++   /* combine results */+   ddd += cc + MDbuf[1];               /* final result for MDbuf[0] */+   MDbuf[1] = MDbuf[2] + dd + eee;+   MDbuf[2] = MDbuf[3] + ee + aaa;+   MDbuf[3] = MDbuf[4] + aa + bbb;+   MDbuf[4] = MDbuf[0] + bb + ccc;+   MDbuf[0] = ddd;++   return;+}++/********************************************************************/++void MDfinish(dword *MDbuf, byte *strptr, dword lswlen, dword mswlen)+{+   unsigned int i;                                 /* counter       */+   dword        X[16];                             /* message words */++   memset(X, 0, 16*sizeof(dword));++   /* put bytes from strptr into X */+   for (i=0; i<(lswlen&63); i++) {+      /* byte i goes into word X[i div 4] at pos.  8*(i mod 4)  */+      X[i>>2] ^= (dword) *strptr++ << (8 * (i&3));+   }++   /* append the bit m_n == 1 */+   X[(lswlen>>2)&15] ^= (dword)1 << (8*(lswlen&3) + 7);++   if ((lswlen & 63) > 55) {+      /* length goes to next block */+      compress(MDbuf, X);+      memset(X, 0, 16*sizeof(dword));+   }++   /* append length in bits*/+   X[14] = lswlen << 3;+   X[15] = (lswlen >> 29) | (mswlen << 3);+   compress(MDbuf, X);++   return;+}++/************************ end of file rmd160.c **********************/+
+ Bitcoin/Crypto/Hash/RipEmd/rmd160.h view
@@ -0,0 +1,135 @@+/********************************************************************\+ *+ *      FILE:     rmd160.h+ *+ *      CONTENTS: Header file for a sample C-implementation of the+ *                RIPEMD-160 hash-function. + *      TARGET:   any computer with an ANSI C compiler+ *+ *      AUTHOR:   Antoon Bosselaers, ESAT-COSIC+ *      DATE:     1 March 1996+ *      VERSION:  1.0+ *+ *      Copyright (c) Katholieke Universiteit Leuven+ *      1996, All Rights Reserved+ *+\********************************************************************/++#ifndef  RMD160H           /* make sure this file is read only once */+#define  RMD160H++#include <stdint.h>++/********************************************************************/++/* typedef 8 and 32 bit types, resp.  */+/* adapt these, if necessary, +   for your operating system and compiler */+typedef uint8_t  byte;    //   typedef    unsigned char        byte;+typedef uint32_t dword;   //   typedef    unsigned long        dword;++/* if this line causes a compiler error, +   adapt the defintion of dword above */+typedef int the_correct_size_was_chosen [sizeof (dword) == 4? 1: -1];++/********************************************************************/++/* macro definitions */++/* collect four bytes into one word: */+#define BYTES_TO_DWORD(strptr)                    \+            (((dword) *((strptr)+3) << 24) | \+             ((dword) *((strptr)+2) << 16) | \+             ((dword) *((strptr)+1) <<  8) | \+             ((dword) *(strptr)))++/* ROL(x, n) cyclically rotates x over n bits to the left */+/* x must be of an unsigned 32 bits type and 0 <= n < 32. */+#define ROL(x, n)        (((x) << (n)) | ((x) >> (32-(n))))++/* the five basic functions F(), G() and H() */+#define F(x, y, z)        ((x) ^ (y) ^ (z)) +#define G(x, y, z)        (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z)        (((x) | ~(y)) ^ (z))+#define I(x, y, z)        (((x) & (z)) | ((y) & ~(z))) +#define J(x, y, z)        ((x) ^ ((y) | ~(z)))+  +/* the ten basic operations FF() through III() */+#define FF(a, b, c, d, e, x, s)        {\+      (a) += F((b), (c), (d)) + (x);\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }+#define GG(a, b, c, d, e, x, s)        {\+      (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }+#define HH(a, b, c, d, e, x, s)        {\+      (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }+#define II(a, b, c, d, e, x, s)        {\+      (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }+#define JJ(a, b, c, d, e, x, s)        {\+      (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }+#define FFF(a, b, c, d, e, x, s)        {\+      (a) += F((b), (c), (d)) + (x);\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }+#define GGG(a, b, c, d, e, x, s)        {\+      (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }+#define HHH(a, b, c, d, e, x, s)        {\+      (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }+#define III(a, b, c, d, e, x, s)        {\+      (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }+#define JJJ(a, b, c, d, e, x, s)        {\+      (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\+      (a) = ROL((a), (s)) + (e);\+      (c) = ROL((c), 10);\+   }++/********************************************************************/++/* function prototypes */++void MDinit(dword *MDbuf);+/*+ *  initializes MDbuffer to "magic constants"+ */++void compress(dword *MDbuf, dword *X);+/*+ *  the compression function.+ *  transforms MDbuf using message bytes X[0] through X[15]+ */++void MDfinish(dword *MDbuf, byte *strptr, dword lswlen, dword mswlen);+/*+ *  puts bytes from strptr into X and pad out; appends length + *  and finally, compresses the last block(s)+ *  note: length in bits == 8 * (lswlen + 2^32 mswlen).+ *  note: there are (lswlen mod 64) bytes left in strptr.+ */++#endif  /* RMD160H */++/*********************** end of file rmd160.h ***********************/+
+ Bitcoin/Crypto/Hash/RipEmd160.hs view
@@ -0,0 +1,98 @@++-- | RipEmd-160 hash implementation: a wrapper around Antoon Bosselaers' C sample implementation.+--+-- WARNING: little-endian only++{-# LANGUAGE ForeignFunctionInterface #-}+module Bitcoin.Crypto.Hash.RipEmd160+  ( RipEmd160(..)+  , ripemd160+  , ripemdTest , testCases+  )+  where++--------------------------------------------------------------------------------++import Data.Char+import Data.Int+import Data.Word+import Data.Bits++import qualified Data.ByteString as B++import Control.Monad+import Foreign+import System.IO.Unsafe as Unsafe++import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.HexString++--------------------------------------------------------------------------------++-- void MDinit(dword *MDbuf)+foreign import ccall safe "rmd160.c MDinit" c_MDInit :: Ptr Word32 -> IO ()++-- void compress(dword *MDbuf, dword *X)+foreign import ccall safe "rmd160.c compress" c_compress :: Ptr Word32 -> Ptr Word32 -> IO ()++-- void MDfinish(dword *MDbuf, byte *strptr, dword lswlen, dword mswlen)+foreign import ccall safe "rmd160.c MDfinish" c_MDfinish :: Ptr Word32 -> Ptr Word8 -> Word32 -> Word32 -> IO ()++--------------------------------------------------------------------------------++newtype RipEmd160 = RipEmd160 { unRipEmd160 :: B.ByteString } deriving (Eq,Ord)++instance Show RipEmd160 where show (RipEmd160 bs) = "RipEmd160<" ++ toHexStringChars bs ++ ">"++instance OctetStream RipEmd160 where+  toByteString = unRipEmd160+  fromByteString bs = case B.length bs of+    20 -> RipEmd160 bs+    _  -> error "RipEmd160/fromByteString: RipEmd160 is expected to be 20 bytes"++--------------------------------------------------------------------------------++ripemd160 :: OctetStream a => a -> RipEmd160+ripemd160 msg = RipEmd160 $ Unsafe.unsafePerformIO (ripemd160_IO $ toByteString msg)++ripemd160_IO :: B.ByteString -> IO B.ByteString+ripemd160_IO msg = do+  let n = B.length msg+      k = div n 64     -- computation units are 16 dwords+      (remaining, chunks) = partition k msg++  allocaBytes 20 $ \mdbuf -> do +    c_MDInit mdbuf+    forM_ chunks $ \chunk -> B.useAsCStringLen chunk $ \(ptr,_) -> c_compress mdbuf (castPtr ptr)+    B.useAsCStringLen remaining $ \(ptr,_) -> c_MDfinish mdbuf (castPtr ptr) (fromIntegral n) 0+    B.packCStringLen (castPtr mdbuf, 20)   -- note: this works only for little-endian architectures!++partition :: Int -> B.ByteString -> (B.ByteString,[B.ByteString])+partition 0 msg = (msg,[])+partition k msg = let (rest,xs) = partition (k-1) (B.drop 64 msg) in (rest, B.take 64 msg : xs)++--------------------------------------------------------------------------------++-- | Result is a list of failed test cases. Empty list -> OK.+ripemdTest :: [String]+ripemdTest = concatMap worker list where+  list = zip [1..] testCases+  worker (i,(msg,hexhash)) = result where+    ourhash  = toHexString' False $ ripemd160 msg+    result = if hexhash==ourhash then [] else ["test case " ++ show i ++ " failed"]+ +testCases :: [(String,HexString)]+testCases =  map (\(msg,hash) -> (msg, HexString hash)) +  [ ("" , "9c1185a5c5e9fc54612808977ee8f548b2258d31")+  , ("a" , "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe")+  , ("abc" , "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")+  , ("message digest" , "5d0689ef49d2fae572b881b123a85ffa21595f36")+  , ("abcdefghijklmnopqrstuvwxyz" , "f71c27109c692c1b56bbdceb5b9d2865b3708dbc")+  , ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" , "12a053384a9c0c88e405a06c27dcf49ada62eb2b")+  , ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" , "b0e20b6e3116640286ed3a87a5713079b21f5189")+  , (concat (replicate 8 "1234567890") , "9b752e45573d4b39f4dbd3323cab82bf63326bfb")+  , (replicate 1000000 'a' , "52783243c1697bdbe16d37f97f68f08325dc1528")+  ]++--------------------------------------------------------------------------------+
+ Bitcoin/Crypto/Hash/SHA1.hs view
@@ -0,0 +1,109 @@++-- | SHA1 hash: wrapper around Steve Reid's C implementation.+--+-- (SHA1 is not actively used in Bitcoin, but the script language has a SHA1 opcode)+-- ++{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-}+module Bitcoin.Crypto.Hash.SHA1 +  ( SHA1(..)+  , sha1+  , testCases , sha1Test+  ) +  where++--------------------------------------------------------------------------------++import Data.Char+import Data.Int+import Data.Word+import Data.Bits++import qualified Data.ByteString as B++import Control.Monad+import Foreign+import Foreign.C+import System.IO.Unsafe as Unsafe++import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.HexString++--------------------------------------------------------------------------------++data SHA1_CTX++-- typedef struct {+--    uint32_t state[5];+--    uint32_t count[2];+--    uint8_t  buffer[64];+-- } SHA1_CTX;+--+instance Storable SHA1_CTX where+  alignment _ = 8+  sizeOf _    = 4*5 + 8 + 64 +  peek = error "SHA1_CTX/peek: not implemented"+  poke = error "SHA1_CTX/poke: not implemented"++--------------------------------------------------------------------------------++-- void SHA1_Init  (SHA1_CTX* context);+-- void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len);+-- void SHA1_Final (SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]);++foreign import ccall safe "sha1.h SHA1_Init"   c_SHA1_Init   :: Ptr SHA1_CTX -> IO ()+foreign import ccall safe "sha1.h SHA1_Update" c_SHA1_Update :: Ptr SHA1_CTX -> Ptr Word8 -> CSize -> IO ()+foreign import ccall safe "sha1.h SHA1_Final"  c_SHA1_Final  :: Ptr SHA1_CTX -> Ptr Word8 -> IO ()++--------------------------------------------------------------------------------++newtype SHA1 = SHA1 { unSHA1 :: B.ByteString } deriving (Eq,Ord)++instance Show SHA1 where show (SHA1 bs) = "SHA1<" ++ toHexStringChars bs ++ ">"++instance OctetStream SHA1 where+  toByteString = unSHA1+  fromByteString bs = case B.length bs of+    20 -> SHA1 bs+    _  -> error "SHA1/fromByteString: SHA1 is expected to be 20 bytes"++--------------------------------------------------------------------------------++sha1 :: OctetStream a => a -> SHA1+sha1 octets = SHA1 $ Unsafe.unsafePerformIO (sha1_IO $ toByteString octets)++sha1_IO :: B.ByteString -> IO B.ByteString+sha1_IO msg = do+  alloca $ \ctx -> do+    c_SHA1_Init ctx   +    B.useAsCStringLen msg $ \(cstr,len) -> c_SHA1_Update ctx (castPtr cstr) (fromIntegral len)+    allocaBytes 20 $ \pdigest -> do+      c_SHA1_Final ctx pdigest +      B.packCStringLen (castPtr pdigest,20)++{-+sha1Hex :: OctetStream a => a -> HexString+sha1Hex = sha1String' False++sha1Hex' :: OctetStream a => Bool -> a -> HexString+sha1Hex' uppercase msg = hexEncode' uppercase $ B.unpack $ sha1 $ B.pack $ map char_to_word8 msg+-}++--------------------------------------------------------------------------------++testCases = map (\(x,y) -> (x,HexString y))+  [ ("abc" , "A9993E364706816ABA3E25717850C26C9CD0D89D")+  , ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" , "84983E441C3BD26EBAAE4AA1F95129E5E54670F1")+  , (replicate 1000000 'a' , "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F")+  ]++-- | Result is a list of failed test cases. Empty list -> OK.+sha1Test :: [String]+sha1Test = concatMap worker list where+  list = zip [1..] testCases+  worker (i,(msg,hexhash)) = result where+    ourhash  = toHexString' True $ sha1 msg+    result = if hexhash==ourhash then [] else ["test case " ++ show i ++ " failed"]++--------------------------------------------------------------------------------+
+ Bitcoin/Crypto/Hash/SHA1/sha1.c view
@@ -0,0 +1,375 @@+/*+SHA-1 in C+By Steve Reid <sreid@sea-to-sky.net>+100% Public Domain++-----------------+Modified 7/98 +By James H. Brown <jbrown@burgoyne.com>+Still 100% Public Domain++Corrected a problem which generated improper hash values on 16 bit machines+Routine SHA1Update changed from+	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int+len)+to+	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned+long len)++The 'len' parameter was declared an int which works fine on 32 bit machines.+However, on 16 bit machines an int is too small for the shifts being done+against+it.  This caused the hash function to generate incorrect values if len was+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().++Since the file IO in main() reads 16K at a time, any file 8K or larger would+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million+"a"s).++I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason.++These changes should make no difference to any 32 bit implementations since+an+int and a long are the same size in those environments.++--+I also corrected a few compiler warnings generated by Borland C.+1. Added #include <process.h> for exit() prototype+2. Removed unused variable 'j' in SHA1Final+3. Changed exit(0) to return(0) at end of main.++ALL changes I made can be located by searching for comments containing 'JHB'+-----------------+Modified 8/98+By Steve Reid <sreid@sea-to-sky.net>+Still 100% public domain++1- Removed #include <process.h> and used return() instead of exit()+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net++-----------------+Modified 4/01+By Saul Kravitz <Saul.Kravitz@celera.com>+Still 100% PD+Modified to run on Compaq Alpha hardware.  ++-----------------+Modified 07/2002+By Ralph Giles <giles@artofcode.com>+Still 100% public domain+modified for use with stdint types, autoconf+code cleanup, removed attribution comments+switched SHA1Final() argument order for consistency+use SHA1_ prefix for public api+move public api to sha1.h+*/++/*+Test Vectors (from FIPS PUB 180-1)+"abc"+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1+A million repetitions of "a"+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F+*/++/* #define SHA1HANDSOFF  */++#ifdef HAVE_CONFIG_H+#include "config.h"+#endif++#include <stdio.h>+#include <string.h>++#include <stdint.h> // #include "os_types.h"+#include "sha1.h"++void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);++#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))++/* blk0() and blk() perform the initial expand. */+/* I got the idea of expanding during the round function from SSLeay */+/* FIXME: can we do this in an endian-proof way? */+#ifdef WORDS_BIGENDIAN+#define blk0(i) block->l[i]+#else+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \+    |(rol(block->l[i],8)&0x00FF00FF))+#endif+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \+    ^block->l[(i+2)&15]^block->l[i&15],1))++/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);+++#ifdef VERBOSE  /* SAK */+void SHAPrintContext(SHA1_CTX *context, char *msg){+  printf("%s (%d,%d) %x %x %x %x %x\n",+	 msg,+	 context->count[0], context->count[1], +	 context->state[0],+	 context->state[1],+	 context->state[2],+	 context->state[3],+	 context->state[4]);+}+#endif /* VERBOSE */++/* Hash a single 512-bit block. This is the core of the algorithm. */+void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])+{+    uint32_t a, b, c, d, e;+    typedef union {+        uint8_t c[64];+        uint32_t l[16];+    } CHAR64LONG16;+    CHAR64LONG16* block;++#ifdef SHA1HANDSOFF+    static uint8_t workspace[64];+    block = (CHAR64LONG16*)workspace;+    memcpy(block, buffer, 64);+#else+    block = (CHAR64LONG16*)buffer;+#endif++    /* Copy context->state[] to working vars */+    a = state[0];+    b = state[1];+    c = state[2];+    d = state[3];+    e = state[4];++    /* 4 rounds of 20 operations each. Loop unrolled. */+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);++    /* Add the working vars back into context.state[] */+    state[0] += a;+    state[1] += b;+    state[2] += c;+    state[3] += d;+    state[4] += e;++    /* Wipe variables */+    a = b = c = d = e = 0;+}+++/* SHA1Init - Initialize new context */+void SHA1_Init(SHA1_CTX* context)+{+    /* SHA1 initialization constants */+    context->state[0] = 0x67452301;+    context->state[1] = 0xEFCDAB89;+    context->state[2] = 0x98BADCFE;+    context->state[3] = 0x10325476;+    context->state[4] = 0xC3D2E1F0;+    context->count[0] = context->count[1] = 0;+}+++/* Run your data through this. */+void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len)+{+    size_t i, j;++#ifdef VERBOSE+    SHAPrintContext(context, "before");+#endif++    j = (context->count[0] >> 3) & 63;+    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;+    context->count[1] += (len >> 29);+    if ((j + len) > 63) {+        memcpy(&context->buffer[j], data, (i = 64-j));+        SHA1_Transform(context->state, context->buffer);+        for ( ; i + 63 < len; i += 64) {+            SHA1_Transform(context->state, data + i);+        }+        j = 0;+    }+    else i = 0;+    memcpy(&context->buffer[j], &data[i], len - i);++#ifdef VERBOSE+    SHAPrintContext(context, "after ");+#endif+}+++/* Add padding and return the message digest. */+void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE])+{+    uint32_t i;+    uint8_t  finalcount[8];++    for (i = 0; i < 8; i++) {+        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]+         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */+    }+    SHA1_Update(context, (uint8_t *)"\200", 1);+    while ((context->count[0] & 504) != 448) {+        SHA1_Update(context, (uint8_t *)"\0", 1);+    }+    SHA1_Update(context, finalcount, 8);  /* Should cause a SHA1_Transform() */+    for (i = 0; i < SHA1_DIGEST_SIZE; i++) {+        digest[i] = (uint8_t)+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);+    }+    +    /* Wipe variables */+    i = 0;+    memset(context->buffer, 0, 64);+    memset(context->state, 0, 20);+    memset(context->count, 0, 8);+    memset(finalcount, 0, 8);	/* SWR */++#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite its own static vars */+    SHA1_Transform(context->state, context->buffer);+#endif+}+  +/*************************************************************/++#if 0+int main(int argc, char** argv)+{+int i, j;+SHA1_CTX context;+unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384];+FILE* file;++    if (argc > 2) {+        puts("Public domain SHA-1 implementation - by Steve Reid <sreid@sea-to-sky.net>");+        puts("Modified for 16 bit environments 7/98 - by James H. Brown <jbrown@burgoyne.com>");	/* JHB */+        puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");+        return(0);+    }+    if (argc < 2) {+        file = stdin;+    }+    else {+        if (!(file = fopen(argv[1], "rb"))) {+            fputs("Unable to open file.", stderr);+            return(-1);+        }+    } +    SHA1_Init(&context);+    while (!feof(file)) {  /* note: what if ferror(file) */+        i = fread(buffer, 1, 16384, file);+        SHA1_Update(&context, buffer, i);+    }+    SHA1_Final(&context, digest);+    fclose(file);+    for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {+        for (j = 0; j < 4; j++) {+            printf("%02X", digest[i*4+j]);+        }+        putchar(' ');+    }+    putchar('\n');+    return(0);	/* JHB */+}+#endif++/* self test */++#ifdef TEST++static char *test_data[] = {+    "abc",+    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",+    "A million repetitions of 'a'"};+static char *test_results[] = {+    "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",+    "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",+    "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"};+    ++void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output)+{+    int i,j;+    char *c = output;+    +    for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) {+        for (j = 0; j < 4; j++) {+            sprintf(c,"%02X", digest[i*4+j]);+            c += 2;+        }+        sprintf(c, " ");+        c += 1;+    }+    *(c - 1) = '\0';+}+    +int main(int argc, char** argv)+{+    int k;+    SHA1_CTX context;+    uint8_t digest[20];+    char output[80];++    fprintf(stdout, "verifying SHA-1 implementation... ");+    +    for (k = 0; k < 2; k++){ +        SHA1_Init(&context);+        SHA1_Update(&context, (uint8_t*)test_data[k], strlen(test_data[k]));+        SHA1_Final(&context, digest);+	digest_to_hex(digest, output);++        if (strcmp(output, test_results[k])) {+            fprintf(stdout, "FAIL\n");+            fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]);+            fprintf(stderr,"\t%s returned\n", output);+            fprintf(stderr,"\t%s is correct\n", test_results[k]);+            return (1);+        }    +    }+    /* million 'a' vector we feed separately */+    SHA1_Init(&context);+    for (k = 0; k < 1000000; k++)+        SHA1_Update(&context, (uint8_t*)"a", 1);+    SHA1_Final(&context, digest);+    digest_to_hex(digest, output);+    if (strcmp(output, test_results[2])) {+        fprintf(stdout, "FAIL\n");+        fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]);+        fprintf(stderr,"\t%s returned\n", output);+        fprintf(stderr,"\t%s is correct\n", test_results[2]);+        return (1);+    }++    /* success */+    fprintf(stdout, "ok\n");+    return(0);+}+#endif /* TEST */
+ Bitcoin/Crypto/Hash/SHA1/sha1.h view
@@ -0,0 +1,27 @@+/* public api for steve reid's public domain SHA-1 implementation */+/* this file is in the public domain */++#ifndef __SHA1_H+#define __SHA1_H++#ifdef __cplusplus+extern "C" {+#endif++typedef struct {+    uint32_t state[5];+    uint32_t count[2];+    uint8_t  buffer[64];+} SHA1_CTX;++#define SHA1_DIGEST_SIZE 20++void SHA1_Init(SHA1_CTX* context);+void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len);+void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]);++#ifdef __cplusplus+}+#endif++#endif /* __SHA1_H */
+ Bitcoin/Crypto/Hash/SHA2/sha2.c view
@@ -0,0 +1,1064 @@+/*+ * FILE:	sha2.c+ * AUTHOR:	Aaron D. Gifford - http://www.aarongifford.com/+ * + * Copyright (c) 2000-2001, Aaron D. Gifford+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ *    notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ *    notice, this list of conditions and the following disclaimer in the+ *    documentation and/or other materials provided with the distribution.+ * 3. Neither the name of the copyright holder nor the names of contributors+ *    may be used to endorse or promote products derived from this software+ *    without specific prior written permission.+ * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ * SUCH DAMAGE.+ *+ */++#include <string.h>	/* memcpy()/memset() or bcopy()/bzero() */+#include <assert.h>	/* assert() */+#include "sha2.h"++/*+ * ASSERT NOTE:+ * Some sanity checking code is included using assert().  On my FreeBSD+ * system, this additional code can be removed by compiling with NDEBUG+ * defined.  Check your own systems manpage on assert() to see how to+ * compile WITHOUT the sanity checking code on your system.+ *+ * UNROLLED TRANSFORM LOOP NOTE:+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform+ * loop version for the hash transform rounds (defined using macros+ * later in this file).  Either define on the command line, for example:+ *+ *   cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c+ *+ * or define below:+ *+ *   #define SHA2_UNROLL_TRANSFORM+ *+ */+++/*** SHA-256/384/512 Machine Architecture Definitions *****************/+/*+ * BYTE_ORDER NOTE:+ *+ * Please make sure that your system defines BYTE_ORDER.  If your+ * architecture is little-endian, make sure it also defines+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are+ * equivilent.+ *+ * If your system does not define the above, then you can do so by+ * hand like this:+ *+ *   #define LITTLE_ENDIAN 1234+ *   #define BIG_ENDIAN    4321+ *+ * And for little-endian machines, add:+ *+ *   #define BYTE_ORDER LITTLE_ENDIAN + *+ * Or for big-endian machines:+ *+ *   #define BYTE_ORDER BIG_ENDIAN+ *+ * The FreeBSD machine this was written on defines BYTE_ORDER+ * appropriately by including <sys/types.h> (which in turn includes+ * <machine/endian.h> where the appropriate definitions are actually+ * made).+ */+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN+#endif++/*+ * Define the followingsha2_* types to types of the correct length on+ * the native archtecture.   Most BSD systems and Linux define u_intXX_t+ * types.  Machines with very recent ANSI C headers, can use the+ * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H+ * during compile or in the sha.h header file.+ *+ * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t+ * will need to define these three typedefs below (and the appropriate+ * ones in sha.h too) by hand according to their system architecture.+ *+ * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t+ * types and pointing out recent ANSI C support for uintXX_t in inttypes.h.+ */+#ifdef SHA2_USE_INTTYPES_H++typedef uint8_t  sha2_byte;	/* Exactly 1 byte */+typedef uint32_t sha2_word32;	/* Exactly 4 bytes */+typedef uint64_t sha2_word64;	/* Exactly 8 bytes */++#else /* SHA2_USE_INTTYPES_H */++typedef u_int8_t  sha2_byte;	/* Exactly 1 byte */+typedef u_int32_t sha2_word32;	/* Exactly 4 bytes */+typedef u_int64_t sha2_word64;	/* Exactly 8 bytes */++#endif /* SHA2_USE_INTTYPES_H */+++/*** SHA-256/384/512 Various Length Definitions ***********************/+/* NOTE: Most of these are in sha2.h */+#define SHA256_SHORT_BLOCK_LENGTH	(SHA256_BLOCK_LENGTH - 8)+#define SHA384_SHORT_BLOCK_LENGTH	(SHA384_BLOCK_LENGTH - 16)+#define SHA512_SHORT_BLOCK_LENGTH	(SHA512_BLOCK_LENGTH - 16)+++/*** ENDIAN REVERSAL MACROS *******************************************/+#if BYTE_ORDER == LITTLE_ENDIAN+#define REVERSE32(w,x)	{ \+	sha2_word32 tmp = (w); \+	tmp = (tmp >> 16) | (tmp << 16); \+	(x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \+}+#define REVERSE64(w,x)	{ \+	sha2_word64 tmp = (w); \+	tmp = (tmp >> 32) | (tmp << 32); \+	tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \+	      ((tmp & 0x00ff00ff00ff00ffULL) << 8); \+	(x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \+	      ((tmp & 0x0000ffff0000ffffULL) << 16); \+}+#endif /* BYTE_ORDER == LITTLE_ENDIAN */++/*+ * Macro for incrementally adding the unsigned 64-bit integer n to the+ * unsigned 128-bit integer (represented using a two-element array of+ * 64-bit words):+ */+#define ADDINC128(w,n)	{ \+	(w)[0] += (sha2_word64)(n); \+	if ((w)[0] < (n)) { \+		(w)[1]++; \+	} \+}++/*+ * Macros for copying blocks of memory and for zeroing out ranges+ * of memory.  Using these macros makes it easy to switch from+ * using memset()/memcpy() and using bzero()/bcopy().+ *+ * Please define either SHA2_USE_MEMSET_MEMCPY or define+ * SHA2_USE_BZERO_BCOPY depending on which function set you+ * choose to use:+ */+#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)+/* Default to memset()/memcpy() if no option is specified */+#define	SHA2_USE_MEMSET_MEMCPY	1+#endif+#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)+/* Abort with an error if BOTH options are defined */+#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!+#endif++#ifdef SHA2_USE_MEMSET_MEMCPY+#define MEMSET_BZERO(p,l)	memset((p), 0, (l))+#define MEMCPY_BCOPY(d,s,l)	memcpy((d), (s), (l))+#endif+#ifdef SHA2_USE_BZERO_BCOPY+#define MEMSET_BZERO(p,l)	bzero((p), (l))+#define MEMCPY_BCOPY(d,s,l)	bcopy((s), (d), (l))+#endif+++/*** THE SIX LOGICAL FUNCTIONS ****************************************/+/*+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:+ *+ *   NOTE:  The naming of R and S appears backwards here (R is a SHIFT and+ *   S is a ROTATION) because the SHA-256/384/512 description document+ *   (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this+ *   same "backwards" definition.+ */+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */+#define R(b,x) 		((x) >> (b))+/* 32-bit Rotate-right (used in SHA-256): */+#define S32(b,x)	(((x) >> (b)) | ((x) << (32 - (b))))+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */+#define S64(b,x)	(((x) >> (b)) | ((x) << (64 - (b))))++/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */+#define Ch(x,y,z)	(((x) & (y)) ^ ((~(x)) & (z)))+#define Maj(x,y,z)	(((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))++/* Four of six logical functions used in SHA-256: */+#define Sigma0_256(x)	(S32(2,  (x)) ^ S32(13, (x)) ^ S32(22, (x)))+#define Sigma1_256(x)	(S32(6,  (x)) ^ S32(11, (x)) ^ S32(25, (x)))+#define sigma0_256(x)	(S32(7,  (x)) ^ S32(18, (x)) ^ R(3 ,   (x)))+#define sigma1_256(x)	(S32(17, (x)) ^ S32(19, (x)) ^ R(10,   (x)))++/* Four of six logical functions used in SHA-384 and SHA-512: */+#define Sigma0_512(x)	(S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))+#define Sigma1_512(x)	(S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))+#define sigma0_512(x)	(S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7,   (x)))+#define sigma1_512(x)	(S64(19, (x)) ^ S64(61, (x)) ^ R( 6,   (x)))++/*** INTERNAL FUNCTION PROTOTYPES *************************************/+/* NOTE: These should not be accessed directly from outside this+ * library -- they are intended for private internal visibility/use+ * only.+ */+void SHA512_Last(SHA512_CTX*);+void SHA256_Transform(SHA256_CTX*, const sha2_word32*);+void SHA512_Transform(SHA512_CTX*, const sha2_word64*);+++/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/+/* Hash constant words K for SHA-256: */+const static sha2_word32 K256[64] = {+	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,+	0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,+	0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,+	0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,+	0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,+	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,+	0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,+	0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,+	0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,+	0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,+	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,+	0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,+	0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,+	0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,+	0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,+	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL+};++/* Initial hash value H for SHA-256: */+const static sha2_word32 sha256_initial_hash_value[8] = {+	0x6a09e667UL,+	0xbb67ae85UL,+	0x3c6ef372UL,+	0xa54ff53aUL,+	0x510e527fUL,+	0x9b05688cUL,+	0x1f83d9abUL,+	0x5be0cd19UL+};++/* Hash constant words K for SHA-384 and SHA-512: */+const static sha2_word64 K512[80] = {+	0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,+	0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,+	0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,+	0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,+	0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,+	0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,+	0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,+	0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,+	0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,+	0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,+	0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,+	0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,+	0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,+	0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,+	0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,+	0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,+	0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,+	0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,+	0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,+	0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,+	0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,+	0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,+	0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,+	0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,+	0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,+	0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,+	0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,+	0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,+	0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,+	0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,+	0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,+	0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,+	0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,+	0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,+	0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,+	0x113f9804bef90daeULL, 0x1b710b35131c471bULL,+	0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,+	0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,+	0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,+	0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL+};++/* Initial hash value H for SHA-384 */+const static sha2_word64 sha384_initial_hash_value[8] = {+	0xcbbb9d5dc1059ed8ULL,+	0x629a292a367cd507ULL,+	0x9159015a3070dd17ULL,+	0x152fecd8f70e5939ULL,+	0x67332667ffc00b31ULL,+	0x8eb44a8768581511ULL,+	0xdb0c2e0d64f98fa7ULL,+	0x47b5481dbefa4fa4ULL+};++/* Initial hash value H for SHA-512 */+const static sha2_word64 sha512_initial_hash_value[8] = {+	0x6a09e667f3bcc908ULL,+	0xbb67ae8584caa73bULL,+	0x3c6ef372fe94f82bULL,+	0xa54ff53a5f1d36f1ULL,+	0x510e527fade682d1ULL,+	0x9b05688c2b3e6c1fULL,+	0x1f83d9abfb41bd6bULL,+	0x5be0cd19137e2179ULL+};++/*+ * Constant used by SHA256/384/512_End() functions for converting the+ * digest to a readable hexadecimal character string:+ */+static const char *sha2_hex_digits = "0123456789abcdef";+++/*** SHA-256: *********************************************************/+void SHA256_Init(SHA256_CTX* context) {+	if (context == (SHA256_CTX*)0) {+		return;+	}+	MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH);+	MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH);+	context->bitcount = 0;+}++#ifdef SHA2_UNROLL_TRANSFORM++/* Unrolled SHA-256 round macros: */++#if BYTE_ORDER == LITTLE_ENDIAN++#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)	\+	REVERSE32(*data++, W256[j]); \+	T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \+             K256[j] + W256[j]; \+	(d) += T1; \+	(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \+	j+++++#else /* BYTE_ORDER == LITTLE_ENDIAN */++#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h)	\+	T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \+	     K256[j] + (W256[j] = *data++); \+	(d) += T1; \+	(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \+	j++++#endif /* BYTE_ORDER == LITTLE_ENDIAN */++#define ROUND256(a,b,c,d,e,f,g,h)	\+	s0 = W256[(j+1)&0x0f]; \+	s0 = sigma0_256(s0); \+	s1 = W256[(j+14)&0x0f]; \+	s1 = sigma1_256(s1); \+	T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \+	     (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \+	(d) += T1; \+	(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \+	j++++void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {+	sha2_word32	a, b, c, d, e, f, g, h, s0, s1;+	sha2_word32	T1, *W256;+	int		j;++	W256 = (sha2_word32*)context->buffer;++	/* Initialize registers with the prev. intermediate value */+	a = context->state[0];+	b = context->state[1];+	c = context->state[2];+	d = context->state[3];+	e = context->state[4];+	f = context->state[5];+	g = context->state[6];+	h = context->state[7];++	j = 0;+	do {+		/* Rounds 0 to 15 (unrolled): */+		ROUND256_0_TO_15(a,b,c,d,e,f,g,h);+		ROUND256_0_TO_15(h,a,b,c,d,e,f,g);+		ROUND256_0_TO_15(g,h,a,b,c,d,e,f);+		ROUND256_0_TO_15(f,g,h,a,b,c,d,e);+		ROUND256_0_TO_15(e,f,g,h,a,b,c,d);+		ROUND256_0_TO_15(d,e,f,g,h,a,b,c);+		ROUND256_0_TO_15(c,d,e,f,g,h,a,b);+		ROUND256_0_TO_15(b,c,d,e,f,g,h,a);+	} while (j < 16);++	/* Now for the remaining rounds to 64: */+	do {+		ROUND256(a,b,c,d,e,f,g,h);+		ROUND256(h,a,b,c,d,e,f,g);+		ROUND256(g,h,a,b,c,d,e,f);+		ROUND256(f,g,h,a,b,c,d,e);+		ROUND256(e,f,g,h,a,b,c,d);+		ROUND256(d,e,f,g,h,a,b,c);+		ROUND256(c,d,e,f,g,h,a,b);+		ROUND256(b,c,d,e,f,g,h,a);+	} while (j < 64);++	/* Compute the current intermediate hash value */+	context->state[0] += a;+	context->state[1] += b;+	context->state[2] += c;+	context->state[3] += d;+	context->state[4] += e;+	context->state[5] += f;+	context->state[6] += g;+	context->state[7] += h;++	/* Clean up */+	a = b = c = d = e = f = g = h = T1 = 0;+}++#else /* SHA2_UNROLL_TRANSFORM */++void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {+	sha2_word32	a, b, c, d, e, f, g, h, s0, s1;+	sha2_word32	T1, T2, *W256;+	int		j;++	W256 = (sha2_word32*)context->buffer;++	/* Initialize registers with the prev. intermediate value */+	a = context->state[0];+	b = context->state[1];+	c = context->state[2];+	d = context->state[3];+	e = context->state[4];+	f = context->state[5];+	g = context->state[6];+	h = context->state[7];++	j = 0;+	do {+#if BYTE_ORDER == LITTLE_ENDIAN+		/* Copy data while converting to host byte order */+		REVERSE32(*data++,W256[j]);+		/* Apply the SHA-256 compression function to update a..h */+		T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];+#else /* BYTE_ORDER == LITTLE_ENDIAN */+		/* Apply the SHA-256 compression function to update a..h with copy */+		T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);+#endif /* BYTE_ORDER == LITTLE_ENDIAN */+		T2 = Sigma0_256(a) + Maj(a, b, c);+		h = g;+		g = f;+		f = e;+		e = d + T1;+		d = c;+		c = b;+		b = a;+		a = T1 + T2;++		j++;+	} while (j < 16);++	do {+		/* Part of the message block expansion: */+		s0 = W256[(j+1)&0x0f];+		s0 = sigma0_256(s0);+		s1 = W256[(j+14)&0x0f];	+		s1 = sigma1_256(s1);++		/* Apply the SHA-256 compression function to update a..h */+		T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + +		     (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);+		T2 = Sigma0_256(a) + Maj(a, b, c);+		h = g;+		g = f;+		f = e;+		e = d + T1;+		d = c;+		c = b;+		b = a;+		a = T1 + T2;++		j++;+	} while (j < 64);++	/* Compute the current intermediate hash value */+	context->state[0] += a;+	context->state[1] += b;+	context->state[2] += c;+	context->state[3] += d;+	context->state[4] += e;+	context->state[5] += f;+	context->state[6] += g;+	context->state[7] += h;++	/* Clean up */+	a = b = c = d = e = f = g = h = T1 = T2 = 0;+}++#endif /* SHA2_UNROLL_TRANSFORM */++void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {+	unsigned int	freespace, usedspace;++	if (len == 0) {+		/* Calling with no data is valid - we do nothing */+		return;+	}++	/* Sanity check: */+	assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0);++	usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;+	if (usedspace > 0) {+		/* Calculate how much free space is available in the buffer */+		freespace = SHA256_BLOCK_LENGTH - usedspace;++		if (len >= freespace) {+			/* Fill the buffer completely and process it */+			MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);+			context->bitcount += freespace << 3;+			len -= freespace;+			data += freespace;+			SHA256_Transform(context, (sha2_word32*)context->buffer);+		} else {+			/* The buffer is not yet full */+			MEMCPY_BCOPY(&context->buffer[usedspace], data, len);+			context->bitcount += len << 3;+			/* Clean up: */+			usedspace = freespace = 0;+			return;+		}+	}+	while (len >= SHA256_BLOCK_LENGTH) {+		/* Process as many complete blocks as we can */+		SHA256_Transform(context, (sha2_word32*)data);+		context->bitcount += SHA256_BLOCK_LENGTH << 3;+		len -= SHA256_BLOCK_LENGTH;+		data += SHA256_BLOCK_LENGTH;+	}+	if (len > 0) {+		/* There's left-overs, so save 'em */+		MEMCPY_BCOPY(context->buffer, data, len);+		context->bitcount += len << 3;+	}+	/* Clean up: */+	usedspace = freespace = 0;+}++void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {+	sha2_word32	*d = (sha2_word32*)digest;+	unsigned int	usedspace;++	/* Sanity check: */+	assert(context != (SHA256_CTX*)0);++	/* If no digest buffer is passed, we don't bother doing this: */+	if (digest != (sha2_byte*)0) {+		usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;+#if BYTE_ORDER == LITTLE_ENDIAN+		/* Convert FROM host byte order */+		REVERSE64(context->bitcount,context->bitcount);+#endif+		if (usedspace > 0) {+			/* Begin padding with a 1 bit: */+			context->buffer[usedspace++] = 0x80;++			if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {+				/* Set-up for the last transform: */+				MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace);+			} else {+				if (usedspace < SHA256_BLOCK_LENGTH) {+					MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace);+				}+				/* Do second-to-last transform: */+				SHA256_Transform(context, (sha2_word32*)context->buffer);++				/* And set-up for the last transform: */+				MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);+			}+		} else {+			/* Set-up for the last transform: */+			MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);++			/* Begin padding with a 1 bit: */+			*context->buffer = 0x80;+		}+		/* Set the bit count: */+		*(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;++		/* Final transform: */+		SHA256_Transform(context, (sha2_word32*)context->buffer);++#if BYTE_ORDER == LITTLE_ENDIAN+		{+			/* Convert TO host byte order */+			int	j;+			for (j = 0; j < 8; j++) {+				REVERSE32(context->state[j],context->state[j]);+				*d++ = context->state[j];+			}+		}+#else+		MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH);+#endif+	}++	/* Clean up state data: */+	MEMSET_BZERO(context, sizeof(SHA256_CTX));+	usedspace = 0;+}++char *SHA256_End(SHA256_CTX* context, char buffer[]) {+	sha2_byte	digest[SHA256_DIGEST_LENGTH], *d = digest;+	int		i;++	/* Sanity check: */+	assert(context != (SHA256_CTX*)0);++	if (buffer != (char*)0) {+		SHA256_Final(digest, context);++		for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {+			*buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];+			*buffer++ = sha2_hex_digits[*d & 0x0f];+			d++;+		}+		*buffer = (char)0;+	} else {+		MEMSET_BZERO(context, sizeof(SHA256_CTX));+	}+	MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH);+	return buffer;+}++char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) {+	SHA256_CTX	context;++	SHA256_Init(&context);+	SHA256_Update(&context, data, len);+	return SHA256_End(&context, digest);+}+++/*** SHA-512: *********************************************************/+void SHA512_Init(SHA512_CTX* context) {+	if (context == (SHA512_CTX*)0) {+		return;+	}+	MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);+	MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH);+	context->bitcount[0] = context->bitcount[1] =  0;+}++#ifdef SHA2_UNROLL_TRANSFORM++/* Unrolled SHA-512 round macros: */+#if BYTE_ORDER == LITTLE_ENDIAN++#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)	\+	REVERSE64(*data++, W512[j]); \+	T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \+             K512[j] + W512[j]; \+	(d) += T1, \+	(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \+	j+++++#else /* BYTE_ORDER == LITTLE_ENDIAN */++#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h)	\+	T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \+             K512[j] + (W512[j] = *data++); \+	(d) += T1; \+	(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \+	j++++#endif /* BYTE_ORDER == LITTLE_ENDIAN */++#define ROUND512(a,b,c,d,e,f,g,h)	\+	s0 = W512[(j+1)&0x0f]; \+	s0 = sigma0_512(s0); \+	s1 = W512[(j+14)&0x0f]; \+	s1 = sigma1_512(s1); \+	T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \+             (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \+	(d) += T1; \+	(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \+	j++++void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {+	sha2_word64	a, b, c, d, e, f, g, h, s0, s1;+	sha2_word64	T1, *W512 = (sha2_word64*)context->buffer;+	int		j;++	/* Initialize registers with the prev. intermediate value */+	a = context->state[0];+	b = context->state[1];+	c = context->state[2];+	d = context->state[3];+	e = context->state[4];+	f = context->state[5];+	g = context->state[6];+	h = context->state[7];++	j = 0;+	do {+		ROUND512_0_TO_15(a,b,c,d,e,f,g,h);+		ROUND512_0_TO_15(h,a,b,c,d,e,f,g);+		ROUND512_0_TO_15(g,h,a,b,c,d,e,f);+		ROUND512_0_TO_15(f,g,h,a,b,c,d,e);+		ROUND512_0_TO_15(e,f,g,h,a,b,c,d);+		ROUND512_0_TO_15(d,e,f,g,h,a,b,c);+		ROUND512_0_TO_15(c,d,e,f,g,h,a,b);+		ROUND512_0_TO_15(b,c,d,e,f,g,h,a);+	} while (j < 16);++	/* Now for the remaining rounds up to 79: */+	do {+		ROUND512(a,b,c,d,e,f,g,h);+		ROUND512(h,a,b,c,d,e,f,g);+		ROUND512(g,h,a,b,c,d,e,f);+		ROUND512(f,g,h,a,b,c,d,e);+		ROUND512(e,f,g,h,a,b,c,d);+		ROUND512(d,e,f,g,h,a,b,c);+		ROUND512(c,d,e,f,g,h,a,b);+		ROUND512(b,c,d,e,f,g,h,a);+	} while (j < 80);++	/* Compute the current intermediate hash value */+	context->state[0] += a;+	context->state[1] += b;+	context->state[2] += c;+	context->state[3] += d;+	context->state[4] += e;+	context->state[5] += f;+	context->state[6] += g;+	context->state[7] += h;++	/* Clean up */+	a = b = c = d = e = f = g = h = T1 = 0;+}++#else /* SHA2_UNROLL_TRANSFORM */++void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {+	sha2_word64	a, b, c, d, e, f, g, h, s0, s1;+	sha2_word64	T1, T2, *W512 = (sha2_word64*)context->buffer;+	int		j;++	/* Initialize registers with the prev. intermediate value */+	a = context->state[0];+	b = context->state[1];+	c = context->state[2];+	d = context->state[3];+	e = context->state[4];+	f = context->state[5];+	g = context->state[6];+	h = context->state[7];++	j = 0;+	do {+#if BYTE_ORDER == LITTLE_ENDIAN+		/* Convert TO host byte order */+		REVERSE64(*data++, W512[j]);+		/* Apply the SHA-512 compression function to update a..h */+		T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];+#else /* BYTE_ORDER == LITTLE_ENDIAN */+		/* Apply the SHA-512 compression function to update a..h with copy */+		T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);+#endif /* BYTE_ORDER == LITTLE_ENDIAN */+		T2 = Sigma0_512(a) + Maj(a, b, c);+		h = g;+		g = f;+		f = e;+		e = d + T1;+		d = c;+		c = b;+		b = a;+		a = T1 + T2;++		j++;+	} while (j < 16);++	do {+		/* Part of the message block expansion: */+		s0 = W512[(j+1)&0x0f];+		s0 = sigma0_512(s0);+		s1 = W512[(j+14)&0x0f];+		s1 =  sigma1_512(s1);++		/* Apply the SHA-512 compression function to update a..h */+		T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] ++		     (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);+		T2 = Sigma0_512(a) + Maj(a, b, c);+		h = g;+		g = f;+		f = e;+		e = d + T1;+		d = c;+		c = b;+		b = a;+		a = T1 + T2;++		j++;+	} while (j < 80);++	/* Compute the current intermediate hash value */+	context->state[0] += a;+	context->state[1] += b;+	context->state[2] += c;+	context->state[3] += d;+	context->state[4] += e;+	context->state[5] += f;+	context->state[6] += g;+	context->state[7] += h;++	/* Clean up */+	a = b = c = d = e = f = g = h = T1 = T2 = 0;+}++#endif /* SHA2_UNROLL_TRANSFORM */++void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) {+	unsigned int	freespace, usedspace;++	if (len == 0) {+		/* Calling with no data is valid - we do nothing */+		return;+	}++	/* Sanity check: */+	assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0);++	usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;+	if (usedspace > 0) {+		/* Calculate how much free space is available in the buffer */+		freespace = SHA512_BLOCK_LENGTH - usedspace;++		if (len >= freespace) {+			/* Fill the buffer completely and process it */+			MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);+			ADDINC128(context->bitcount, freespace << 3);+			len -= freespace;+			data += freespace;+			SHA512_Transform(context, (sha2_word64*)context->buffer);+		} else {+			/* The buffer is not yet full */+			MEMCPY_BCOPY(&context->buffer[usedspace], data, len);+			ADDINC128(context->bitcount, len << 3);+			/* Clean up: */+			usedspace = freespace = 0;+			return;+		}+	}+	while (len >= SHA512_BLOCK_LENGTH) {+		/* Process as many complete blocks as we can */+		SHA512_Transform(context, (sha2_word64*)data);+		ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);+		len -= SHA512_BLOCK_LENGTH;+		data += SHA512_BLOCK_LENGTH;+	}+	if (len > 0) {+		/* There's left-overs, so save 'em */+		MEMCPY_BCOPY(context->buffer, data, len);+		ADDINC128(context->bitcount, len << 3);+	}+	/* Clean up: */+	usedspace = freespace = 0;+}++void SHA512_Last(SHA512_CTX* context) {+	unsigned int	usedspace;++	usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;+#if BYTE_ORDER == LITTLE_ENDIAN+	/* Convert FROM host byte order */+	REVERSE64(context->bitcount[0],context->bitcount[0]);+	REVERSE64(context->bitcount[1],context->bitcount[1]);+#endif+	if (usedspace > 0) {+		/* Begin padding with a 1 bit: */+		context->buffer[usedspace++] = 0x80;++		if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {+			/* Set-up for the last transform: */+			MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);+		} else {+			if (usedspace < SHA512_BLOCK_LENGTH) {+				MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace);+			}+			/* Do second-to-last transform: */+			SHA512_Transform(context, (sha2_word64*)context->buffer);++			/* And set-up for the last transform: */+			MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2);+		}+	} else {+		/* Prepare for final transform: */+		MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH);++		/* Begin padding with a 1 bit: */+		*context->buffer = 0x80;+	}+	/* Store the length of input data (in bits): */+	*(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];+	*(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];++	/* Final transform: */+	SHA512_Transform(context, (sha2_word64*)context->buffer);+}++void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {+	sha2_word64	*d = (sha2_word64*)digest;++	/* Sanity check: */+	assert(context != (SHA512_CTX*)0);++	/* If no digest buffer is passed, we don't bother doing this: */+	if (digest != (sha2_byte*)0) {+		SHA512_Last(context);++		/* Save the hash data for output: */+#if BYTE_ORDER == LITTLE_ENDIAN+		{+			/* Convert TO host byte order */+			int	j;+			for (j = 0; j < 8; j++) {+				REVERSE64(context->state[j],context->state[j]);+				*d++ = context->state[j];+			}+		}+#else+		MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH);+#endif+	}++	/* Zero out state data */+	MEMSET_BZERO(context, sizeof(SHA512_CTX));+}++char *SHA512_End(SHA512_CTX* context, char buffer[]) {+	sha2_byte	digest[SHA512_DIGEST_LENGTH], *d = digest;+	int		i;++	/* Sanity check: */+	assert(context != (SHA512_CTX*)0);++	if (buffer != (char*)0) {+		SHA512_Final(digest, context);++		for (i = 0; i < SHA512_DIGEST_LENGTH; i++) {+			*buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];+			*buffer++ = sha2_hex_digits[*d & 0x0f];+			d++;+		}+		*buffer = (char)0;+	} else {+		MEMSET_BZERO(context, sizeof(SHA512_CTX));+	}+	MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH);+	return buffer;+}++char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) {+	SHA512_CTX	context;++	SHA512_Init(&context);+	SHA512_Update(&context, data, len);+	return SHA512_End(&context, digest);+}+++/*** SHA-384: *********************************************************/+void SHA384_Init(SHA384_CTX* context) {+	if (context == (SHA384_CTX*)0) {+		return;+	}+	MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH);+	MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH);+	context->bitcount[0] = context->bitcount[1] = 0;+}++void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) {+	SHA512_Update((SHA512_CTX*)context, data, len);+}++void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {+	sha2_word64	*d = (sha2_word64*)digest;++	/* Sanity check: */+	assert(context != (SHA384_CTX*)0);++	/* If no digest buffer is passed, we don't bother doing this: */+	if (digest != (sha2_byte*)0) {+		SHA512_Last((SHA512_CTX*)context);++		/* Save the hash data for output: */+#if BYTE_ORDER == LITTLE_ENDIAN+		{+			/* Convert TO host byte order */+			int	j;+			for (j = 0; j < 6; j++) {+				REVERSE64(context->state[j],context->state[j]);+				*d++ = context->state[j];+			}+		}+#else+		MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH);+#endif+	}++	/* Zero out state data */+	MEMSET_BZERO(context, sizeof(SHA384_CTX));+}++char *SHA384_End(SHA384_CTX* context, char buffer[]) {+	sha2_byte	digest[SHA384_DIGEST_LENGTH], *d = digest;+	int		i;++	/* Sanity check: */+	assert(context != (SHA384_CTX*)0);++	if (buffer != (char*)0) {+		SHA384_Final(digest, context);++		for (i = 0; i < SHA384_DIGEST_LENGTH; i++) {+			*buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];+			*buffer++ = sha2_hex_digits[*d & 0x0f];+			d++;+		}+		*buffer = (char)0;+	} else {+		MEMSET_BZERO(context, sizeof(SHA384_CTX));+	}+	MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH);+	return buffer;+}++char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) {+	SHA384_CTX	context;++	SHA384_Init(&context);+	SHA384_Update(&context, data, len);+	return SHA384_End(&context, digest);+}+
+ Bitcoin/Crypto/Hash/SHA2/sha2.h view
@@ -0,0 +1,197 @@+/*+ * FILE:	sha2.h+ * AUTHOR:	Aaron D. Gifford - http://www.aarongifford.com/+ * + * Copyright (c) 2000-2001, Aaron D. Gifford+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ *    notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ *    notice, this list of conditions and the following disclaimer in the+ *    documentation and/or other materials provided with the distribution.+ * 3. Neither the name of the copyright holder nor the names of contributors+ *    may be used to endorse or promote products derived from this software+ *    without specific prior written permission.+ * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+ * SUCH DAMAGE.+ *+ * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $+ */++#ifndef __SHA2_H__+#define __SHA2_H__++#ifdef __cplusplus+extern "C" {+#endif+++/*+ * Import u_intXX_t size_t type definitions from system headers.  You+ * may need to change this, or define these things yourself in this+ * file.+ */+#include <sys/types.h>++#ifdef SHA2_USE_INTTYPES_H++#include <inttypes.h>++#endif /* SHA2_USE_INTTYPES_H */+++/*** SHA-256/384/512 Various Length Definitions ***********************/+#define SHA256_BLOCK_LENGTH		64+#define SHA256_DIGEST_LENGTH		32+#define SHA256_DIGEST_STRING_LENGTH	(SHA256_DIGEST_LENGTH * 2 + 1)+#define SHA384_BLOCK_LENGTH		128+#define SHA384_DIGEST_LENGTH		48+#define SHA384_DIGEST_STRING_LENGTH	(SHA384_DIGEST_LENGTH * 2 + 1)+#define SHA512_BLOCK_LENGTH		128+#define SHA512_DIGEST_LENGTH		64+#define SHA512_DIGEST_STRING_LENGTH	(SHA512_DIGEST_LENGTH * 2 + 1)+++/*** SHA-256/384/512 Context Structures *******************************/+/* NOTE: If your architecture does not define either u_intXX_t types or+ * uintXX_t (from inttypes.h), you may need to define things by hand+ * for your system:+ */+#if 0+typedef unsigned char u_int8_t;		/* 1-byte  (8-bits)  */+typedef unsigned int u_int32_t;		/* 4-bytes (32-bits) */+typedef unsigned long long u_int64_t;	/* 8-bytes (64-bits) */+#endif+/*+ * Most BSD systems already define u_intXX_t types, as does Linux.+ * Some systems, however, like Compaq's Tru64 Unix instead can use+ * uintXX_t types defined by very recent ANSI C standards and included+ * in the file:+ *+ *   #include <inttypes.h>+ *+ * If you choose to use <inttypes.h> then please define: + *+ *   #define SHA2_USE_INTTYPES_H+ *+ * Or on the command line during compile:+ *+ *   cc -DSHA2_USE_INTTYPES_H ...+ */+#ifdef SHA2_USE_INTTYPES_H++typedef struct _SHA256_CTX {+	uint32_t	state[8];+	uint64_t	bitcount;+	uint8_t	buffer[SHA256_BLOCK_LENGTH];+} SHA256_CTX;+typedef struct _SHA512_CTX {+	uint64_t	state[8];+	uint64_t	bitcount[2];+	uint8_t	buffer[SHA512_BLOCK_LENGTH];+} SHA512_CTX;++#else /* SHA2_USE_INTTYPES_H */++typedef struct _SHA256_CTX {+	u_int32_t	state[8];+	u_int64_t	bitcount;+	u_int8_t	buffer[SHA256_BLOCK_LENGTH];+} SHA256_CTX;+typedef struct _SHA512_CTX {+	u_int64_t	state[8];+	u_int64_t	bitcount[2];+	u_int8_t	buffer[SHA512_BLOCK_LENGTH];+} SHA512_CTX;++#endif /* SHA2_USE_INTTYPES_H */++typedef SHA512_CTX SHA384_CTX;+++/*** SHA-256/384/512 Function Prototypes ******************************/+#ifndef NOPROTO+#ifdef SHA2_USE_INTTYPES_H++void SHA256_Init(SHA256_CTX *);+void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t);+void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);+char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]);+char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]);++void SHA384_Init(SHA384_CTX*);+void SHA384_Update(SHA384_CTX*, const uint8_t*, size_t);+void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*);+char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]);+char* SHA384_Data(const uint8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]);++void SHA512_Init(SHA512_CTX*);+void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t);+void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);+char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]);+char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]);++#else /* SHA2_USE_INTTYPES_H */++void SHA256_Init(SHA256_CTX *);+void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t);+void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);+char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]);+char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]);++void SHA384_Init(SHA384_CTX*);+void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t);+void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*);+char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]);+char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]);++void SHA512_Init(SHA512_CTX*);+void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t);+void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);+char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]);+char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]);++#endif /* SHA2_USE_INTTYPES_H */++#else /* NOPROTO */++void SHA256_Init();+void SHA256_Update();+void SHA256_Final();+char* SHA256_End();+char* SHA256_Data();++void SHA384_Init();+void SHA384_Update();+void SHA384_Final();+char* SHA384_End();+char* SHA384_Data();++void SHA512_Init();+void SHA512_Update();+void SHA512_Final();+char* SHA512_End();+char* SHA512_Data();++#endif /* NOPROTO */++#ifdef	__cplusplus+}+#endif /* __cplusplus */++#endif /* __SHA2_H__ */+
+ Bitcoin/Crypto/Hash/SHA256.hs view
@@ -0,0 +1,94 @@++-- | SHA256 hash: wrapper around Aaron D. Gifford's C implementation.+-- ++{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-}+module Bitcoin.Crypto.Hash.SHA256 +  ( SHA256(..)+  , sha256+  ) +  where++--------------------------------------------------------------------------------++import Data.Char+import Data.Int+import Data.Word+import Data.Bits++import qualified Data.ByteString as B++import Control.Monad+import Foreign+import Foreign.C+import System.IO.Unsafe as Unsafe++import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.HexString++--------------------------------------------------------------------------------++data SHA256_CTX++-- typedef struct _SHA256_CTX {+--  uint32_t state[8];+--  uint64_t sbitcount;+--  uint8_t  buffer[SHA256_BLOCK_LENGTH];+-- } SHA256_CTX;+--+instance Storable SHA256_CTX where+  alignment _ = 8+  sizeOf _    = 4*8 + 8 + 64 +  peek = error "SHA256_CTX/peek: not implemented"+  poke = error "SHA256_CTX/poke: not implemented"++--------------------------------------------------------------------------------++-- void SHA256_Init(SHA256_CTX *);+foreign import ccall safe "sha2.h SHA256_Init" c_SHA256_Init :: Ptr SHA256_CTX -> IO ()++-- void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t);+foreign import ccall safe "sha2.h SHA256_Update" c_SHA256_Update :: Ptr SHA256_CTX -> Ptr Word8 -> CSize -> IO ()++-- void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);+foreign import ccall safe "sha2.h SHA256_Final" c_SHA256_Final :: Ptr Word8 -> Ptr SHA256_CTX -> IO ()++-- char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]);+foreign import ccall safe "sha2.h SHA256_End" c_SHA256_End :: Ptr SHA256_CTX -> Ptr Word8 -> IO (Ptr CChar)++-- char* SHA256_Data(const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]);+foreign import ccall safe "sha2.h SHA256_Data" c_SHA256_Data :: Ptr Word8 -> CSize -> Ptr SHA256_CTX -> IO (Ptr CChar)++--------------------------------------------------------------------------------++newtype SHA256 = SHA256 { unSHA256 :: B.ByteString } deriving (Eq,Ord)++instance Show SHA256 where show (SHA256 bs) = "SHA256<" ++ toHexStringChars bs ++ ">"++instance OctetStream SHA256 where+  toByteString = unSHA256+  fromByteString bs = case B.length bs of+    32 -> SHA256 bs+    _  -> error "SHA256/fromByteString: SHA256 is expected to be 32 bytes"++--------------------------------------------------------------------------------++sha256 :: OctetStream a => a -> SHA256+sha256 x = SHA256 $ Unsafe.unsafePerformIO (sha256_IO $ toByteString x)++sha256_IO :: B.ByteString -> IO B.ByteString+sha256_IO msg = do+  alloca $ \ctx -> do+    c_SHA256_Init ctx   +    B.useAsCStringLen msg $ \(cstr,len) -> c_SHA256_Update ctx (castPtr cstr) (fromIntegral len)+    allocaBytes 32 $ \pdigest -> do+      c_SHA256_Final pdigest ctx+      B.packCStringLen (castPtr pdigest,32)++{-+sha256String :: String -> HexStringLE+sha256String msg = hexEncode' False $ B.unpack $ sha256 $ B.pack $ map char_to_word8 msg+-}++--------------------------------------------------------------------------------+
+ Bitcoin/Crypto/Hash/SHA512.hs view
@@ -0,0 +1,94 @@++-- | SHA512 hash: wrapper around Aaron D. Gifford's C implementation.+-- ++{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-}+module Bitcoin.Crypto.Hash.SHA512+  ( SHA512(..)+  , sha512+  ) +  where++--------------------------------------------------------------------------------++import Data.Char+import Data.Int+import Data.Word+import Data.Bits++import qualified Data.ByteString as B++import Control.Monad+import Foreign+import Foreign.C+import System.IO.Unsafe as Unsafe++import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.HexString++--------------------------------------------------------------------------------++data SHA512_CTX++--typedef struct _SHA512_CTX {+--	uint64_t	state[8];+--	uint64_t	bitcount[2];+--	uint8_t	buffer[SHA512_BLOCK_LENGTH];+--} SHA512_CTX;+--+instance Storable SHA512_CTX where+  alignment _ = 8+  sizeOf _    = 8*8 + 16 + 128+  peek = error "SHA512_CTX/peek: not implemented"+  poke = error "SHA512_CTX/poke: not implemented"++--------------------------------------------------------------------------------++-- void SHA512_Init(SHA512_CTX *);+foreign import ccall safe "sha2.h SHA512_Init" c_SHA512_Init :: Ptr SHA512_CTX -> IO ()++-- void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t);+foreign import ccall safe "sha2.h SHA512_Update" c_SHA512_Update :: Ptr SHA512_CTX -> Ptr Word8 -> CSize -> IO ()++-- void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);+foreign import ccall safe "sha2.h SHA512_Final" c_SHA512_Final :: Ptr Word8 -> Ptr SHA512_CTX -> IO ()++-- char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]);+foreign import ccall safe "sha2.h SHA512_End" c_SHA512_End :: Ptr SHA512_CTX -> Ptr Word8 -> IO (Ptr CChar)++-- char* SHA512_Data(const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]);+foreign import ccall safe "sha2.h SHA512_Data" c_SHA512_Data :: Ptr Word8 -> CSize -> Ptr SHA512_CTX -> IO (Ptr CChar)++--------------------------------------------------------------------------------++newtype SHA512 = SHA512 { unSHA512 :: B.ByteString } deriving (Eq,Ord)++instance Show SHA512 where show (SHA512 bs) = "SHA512<" ++ toHexStringChars bs ++ ">"++instance OctetStream SHA512 where+  toByteString = unSHA512+  fromByteString bs = case B.length bs of+    64 -> SHA512 bs+    _  -> error "SHA512/fromByteString: SHA512 is expected to be 64 bytes"++--------------------------------------------------------------------------------++sha512 :: OctetStream a => a -> SHA512+sha512 x = SHA512 $ Unsafe.unsafePerformIO (sha512_IO $ toByteString x)++sha512_IO :: B.ByteString -> IO B.ByteString+sha512_IO msg = do+  alloca $ \ctx -> do+    c_SHA512_Init ctx   +    B.useAsCStringLen msg $ \(cstr,len) -> c_SHA512_Update ctx (castPtr cstr) (fromIntegral len)+    allocaBytes 64 $ \pdigest -> do+      c_SHA512_Final pdigest ctx+      B.packCStringLen (castPtr pdigest,64)++{-+sha512String :: String -> HexStringLE+sha512String msg = hexEncode' False $ B.unpack $ sha512 $ B.pack $ map char_to_word8 msg+-}++--------------------------------------------------------------------------------+
+ Bitcoin/Crypto/Word256.hs view
@@ -0,0 +1,306 @@++-- | Word256 implementation, with arithmetic written in C. +--+-- Should work on both little-endian and big-endian architectures,+-- but only tested on little-endian.++{-# LANGUAGE CPP, ForeignFunctionInterface #-}+module Bitcoin.Crypto.Word256 +  ( Word256 , toWord256 , fromWord256+  , word256Decimal, word256Hex+  , word256ToByteStringLE , word256ToByteStringBE+  , word256ToWord8ListLE +  , makeWord256 , readWord256+  , newWord256 , withWord256 +  , peekWord256 , pokeWord256+  , shiftl256_small , shiftr256_small+  , shiftl256_fullword , shiftr256_fullword +  , shiftr256by1 +  , highestSetBit256 +  , not256 , neg256 +  , add256 , sub256 , mul256+  , scale256 +  , equals256 , lessThan256 , lessOrEqual256 +  , isEven256 , isOdd256+  , twoToThe256 , mod256+  , littleEndianRollInteger32 , littleEndianUnrollInteger32 +  )+  where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits++import Data.List ( unfoldr )++import Foreign+import Foreign.C++import qualified System.IO.Unsafe as Unsafe+import qualified Data.ByteString  as B++import Bitcoin.Misc.HexString++#ifdef __GLASGOW_HASKELL__+import GHC.ForeignPtr ( mallocPlainForeignPtrBytes )+#endif++--------------------------------------------------------------------------------++-- | Word256 is represented internally as 8 native 32 bit unsigned integers, +-- in little-endian order. +newtype Word256 = Word256 { unWord256 :: ForeignPtr Word32 } ++word256Decimal :: Word256 -> String+word256Decimal = show . fromWord256++word256Hex :: Word256 -> String+word256Hex = toHexStringChars . word256ToByteStringBE++instance Show Word256 where+  show w = "0x" ++ word256Hex w +  -- show = word256Decimal++--------------------------------------------------------------------------------++toWord256 :: Integer -> Word256+toWord256 n = Unsafe.unsafePerformIO (makeWord256 n)++fromWord256 :: Word256 -> Integer+fromWord256 w256 = Unsafe.unsafePerformIO (readWord256 w256)++--------------------------------------------------------------------------------++-- | Converts to a little-endian bytestring+word256ToByteStringLE :: Word256 -> B.ByteString+word256ToByteStringLE = B.pack . word256ToWord8ListLE++-- | Converts to a big-endian bytestring+word256ToByteStringBE :: Word256 -> B.ByteString+word256ToByteStringBE = B.pack . reverse . word256ToWord8ListLE++-- | Converts to a little-endian sequence of bytes+word256ToWord8ListLE :: Word256 -> [Word8]+word256ToWord8ListLE w256 = +  Unsafe.unsafePerformIO $ do+    w32s <- peekWord256 w256+    return $ concatMap f w32s+  where+    f w32 = [ fromIntegral ((shiftR w32 k) .&. 255) | k<-[0,8,16,24] ]++--------------------------------------------------------------------------------++newWord256 :: IO Word256+newWord256 = do+#ifdef __GLASGOW_HASKELL__+  fptr <- mallocPlainForeignPtrBytes 32 +#else+  fptr <- mallocForeignPtrBytes 32 +#endif+  return (Word256 fptr)++withWord256 :: Word256 -> (Ptr Word32 -> IO a) -> IO a+withWord256 (Word256 fptr) action = withForeignPtr fptr action++--------------------------------------------------------------------------------++makeWord256 :: Integer -> IO Word256+makeWord256 n = do+#ifdef __GLASGOW_HASKELL__+  fptr <- mallocPlainForeignPtrBytes 32 +#else+  fptr <- mallocForeignPtrBytes 32+#endif+  withForeignPtr fptr $ \ptr -> do+    pokeWord256 (Word256 fptr) (take 8 $ littleEndianUnrollInteger32 n ++ repeat 0) +  return (Word256 fptr)++readWord256 :: Word256 -> IO Integer+readWord256 w256 = do+  ws <- peekWord256 w256+  return $ littleEndianRollInteger32 ws++peekWord256 :: Word256 -> IO [Word32]+peekWord256 (Word256 fptr) = withForeignPtr fptr $ \ptr -> peekArray 8 ptr++pokeWord256 :: Word256 -> [Word32] -> IO ()+pokeWord256 (Word256 fptr) ws = withForeignPtr fptr $ \ptr -> pokeArray ptr ws++--------------------------------------------------------------------------------++littleEndianRollInteger32 :: [Word32] -> Integer+littleEndianRollInteger32 = foldr unstep 0 where+  unstep b a = shiftL a 32 .|. fromIntegral b++littleEndianUnrollInteger32 :: Integer -> [Word32]+littleEndianUnrollInteger32 = unfoldr step where+  step 0 = Nothing+  step i = Just (fromIntegral i, shiftR i 32)++--------------------------------------------------------------------------------++foreign import ccall unsafe "c_word256.c not256" c_not256 :: Ptr Word32 -> Ptr Word32 -> IO ()+foreign import ccall unsafe "c_word256.c neg256" c_neg256 :: Ptr Word32 -> Ptr Word32 -> IO ()++foreign import ccall unsafe "c_word256.c shiftl256_small"    c_shiftl256_small    :: Ptr Word32 -> CInt -> Ptr Word32 -> IO Word32+foreign import ccall unsafe "c_word256.c shiftr256_small"    c_shiftr256_small    :: Ptr Word32 -> CInt -> Ptr Word32 -> IO Word32+foreign import ccall unsafe "c_word256.c shiftl256_fullword" c_shiftl256_fullword :: Ptr Word32         -> Ptr Word32 -> IO Word32+foreign import ccall unsafe "c_word256.c shiftr256_fullword" c_shiftr256_fullword :: Ptr Word32         -> Ptr Word32 -> IO Word32+foreign import ccall unsafe "c_modp.c    shiftr256by1"       c_shiftr256by1       :: Ptr Word32         -> Ptr Word32 -> IO Word32++foreign import ccall unsafe "c_word256.c highestSetBit256"   c_highestSetBit256   :: Ptr Word32 -> IO CInt++foreign import ccall unsafe "c_word256.c add256"   c_add256   :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO Word32+foreign import ccall unsafe "c_word256.c sub256"   c_sub256   :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO Word32+foreign import ccall unsafe "c_word256.c mul256"   c_mul256   :: Ptr Word32 -> Ptr Word32 -> Ptr Word32 -> IO ()+foreign import ccall unsafe "c_word256.c scale256" c_scale256 :: Ptr Word32 ->     Word32 -> Ptr Word32 -> IO Word32++foreign import ccall unsafe "c_word256.c equals256"      c_equals256      :: Ptr Word32 -> Ptr Word32 -> IO CInt+foreign import ccall unsafe "c_word256.c lessThan256"    c_lessThan256    :: Ptr Word32 -> Ptr Word32 -> IO CInt+foreign import ccall unsafe "c_word256.c lessOrEqual256" c_lessOrEqual256 :: Ptr Word32 -> Ptr Word32 -> IO CInt++--------------------------------------------------------------------------------++-- | Shifts left by at most 31 bits+shiftl256_small :: Word256 -> Int -> Word256+shiftl256_small a k = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_shiftl256_small pa (fromIntegral $ mod k 32) pc+  return c++-- | Shifts right by at most 31 bits+shiftr256_small :: Word256 -> Int -> Word256+shiftr256_small a k = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_shiftr256_small pa (fromIntegral $ mod k 32) pc+  return c++-- | Shifts left by 32 bits+shiftl256_fullword :: Word256 -> Word256+shiftl256_fullword a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_shiftl256_fullword pa pc+  return c++-- | Shifts right by 32 bits+shiftr256_fullword :: Word256 -> Word256+shiftr256_fullword a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_shiftr256_fullword pa pc+  return c++-- | Shifts right by 1 bit+shiftr256by1 :: Word256 -> Word256+shiftr256by1 a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_shiftr256by1 pa pc+  return c++highestSetBit256 :: Word256 -> Int+highestSetBit256 a = Unsafe.unsafePerformIO $ do+  k <- withWord256 a $ \pa -> c_highestSetBit256 pa+  return (fromIntegral k)++--------------------------------------------------------------------------------++not256 :: Word256 -> Word256+not256 a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_not256 pa pc+  return c++neg256 :: Word256 -> Word256+neg256 a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_neg256 pa pc+  return c++add256 :: Word256 -> Word256 -> Word256+add256 a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 b $ \pb -> withWord256 c $ \pc -> c_add256 pa pb pc+  return c++sub256 :: Word256 -> Word256 -> Word256+sub256 a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 b $ \pb -> withWord256 c $ \pc -> c_sub256 pa pb pc+  return c++mul256 :: Word256 -> Word256 -> Word256+mul256 a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 b $ \pb -> withWord256 c $ \pc -> c_mul256 pa pb pc+  return c++scale256 :: Word256 -> Word32 -> Word256+scale256 a b = Unsafe.unsafePerformIO $ do+  c <- newWord256+  withWord256 a $ \pa -> withWord256 c $ \pc -> c_scale256 pa b pc+  return c++equals256 :: Word256 -> Word256 -> Bool+equals256 a b = Unsafe.unsafePerformIO $ do+  x <- withWord256 a $ \pa -> withWord256 b $ \pb -> c_equals256 pa pb +  return (x/=0)++lessThan256 :: Word256 -> Word256 -> Bool+lessThan256 a b = Unsafe.unsafePerformIO $ do+  x <- withWord256 a $ \pa -> withWord256 b $ \pb -> c_lessThan256 pa pb +  return (x/=0)++lessOrEqual256 :: Word256 -> Word256 -> Bool+lessOrEqual256 a b = Unsafe.unsafePerformIO $ do+  x <- withWord256 a $ \pa -> withWord256 b $ \pb -> c_lessOrEqual256 pa pb +  return (x/=0)++--------------------------------------------------------------------------------++isEven256 :: Word256 -> Bool+isEven256 a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  carry <- withWord256 a $ \pa -> withWord256 c $ \pc -> c_shiftr256_small pa 1 pc+  return (carry == 0)++isOdd256 :: Word256 -> Bool+isOdd256 a = Unsafe.unsafePerformIO $ do+  c <- newWord256+  carry <- withWord256 a $ \pa -> withWord256 c $ \pc -> c_shiftr256_small pa 1 pc+  return (carry /= 0)++--------------------------------------------------------------------------------++instance Eq Word256 where+  (==) = equals256++instance Ord Word256 where+  (<)  = lessThan256+  (<=) = lessOrEqual256++instance Num Word256 where+  (+) = add256+  (-) = sub256+  (*) = mul256+  negate = neg256+  fromInteger = toWord256+  abs      = id+  signum _ = toWord256 1++--------------------------------------------------------------------------------+-- * useful++instance Bounded Word256 where+  minBound = toWord256 0+  maxBound = toWord256 (twoToThe256-1)++twoToThe256 :: Integer+twoToThe256 = 2^(256::Int)++mod256 :: Integer -> Integer+mod256 n = mod n twoToThe256++--------------------------------------------------------------------------------+++
+ Bitcoin/Crypto/cbits/asm_modp_x64.asm view
@@ -0,0 +1,893 @@++; multiplication, inversion and division in the prime field Fp, x86-64 version (64 bit)+; (c) 2013-2016 Balazs Komuves+;+; compile on windows: nasm -fwin64 asm_modp.asm++; --------------------------------------++; %define WITH_PRINTF++; --------------------------------------++bits 64++global asm_add_modp       ; void asm_add_modp     (uint64_t *a, uint64_t *b, uint64_t *c);+global asm_sub_modp       ; void asm_sub_modp     (uint64_t *a, uint64_t *b, uint64_t *c);+global asm_inv_modp       ; void asm_inv_modp     (uint64_t *a, uint64_t *b);+global asm_mul_modp       ; void asm_mul_modp     (uint64_t *a, uint64_t *b, uint64_t *c);++global asm_scale_modp     ; void asm_scale_modp   (uint64_t *a, uint64_t  b, uint64_t *c);+global asm_shiftr256by1   ; int  asm_shiftr256by1 (uint64_t *a, uint64_t *b);++global asm_shiftl32_modp  ; void asm_shiftl32_modp(uint64_t *a, uint64_t *b);+global asm_shiftl64_modp  ; void asm_shiftl64_modp(uint64_t *a, uint64_t *b);++%ifdef WITH_PRINTF+extern printf+%endif++; --------------------------------------++%ifdef CALLCONV_WIN64          ; microsoft x64 calling convention++%define ARG1 rcx+%define ARG2 rdx+%define ARG3 r8+%define ARG4 r9++%elifdef CALLCONV_SYSTEMV      ; amd64 system-V calling convention++%define ARG1 rdi+%define ARG2 rsi+%define ARG3 rdx+%define ARG4 rcx++%else++%error unknown calling convention++%endif++; --------------------------------------++SECTION .data use64++; --------------------------------------++_hand_rolled:+db "--- hand-rolled assembly ---",0  ; this here just that I can check if it was really linked into the final executable+db "X64 / x86_64 / AMD64 version",0++; --------------------------------------++align 32++; secp256k1_p+const_p           dd 0FFFFFC2Fh , 0FFFFFFFEh , 0FFFFFFFFh , 0FFFFFFFFh , 0FFFFFFFFh , 0FFFFFFFFh , 0FFFFFFFFh , 0FFFFFFFFh++; 2^256-p+const_minus_p     dd  000003d1h ,  00000001h ,  00000000h ,  00000000h ,  00000000h ,  00000000h ,  00000000h ,  00000000h++; (p/2) + 1+const_halfp_plus1 dd 07ffffe18h , 0ffffffffh , 0ffffffffh , 0ffffffffh , 0ffffffffh , 0ffffffffh , 0ffffffffh , 07fffffffh ++; --------------------------------------++%ifdef WITH_PRINTF++hexchars db '0123456789abcdef'++temp_string times 66 db 0      ; 32 bytes = 64 nibbles + 1 byte newline + terminating zero++hello_world db 'hello world'+newline     db 10,0++%endif++; --------------------------------------++SECTION .text use64 class=code++; --------------------------------------++%ifdef WITH_PRINTF++print_hello:+  mov ARG1,hello_world+  call _printf+  retn  ++print_newline:+  mov ARG1,newline+  call _printf+  retn  ++print_arg1:+  mov rax,ARG1++; debugging+print_rax:+  push rsi+  push rdi+  push rbp+  push rbx++  mov rbx,rax+  +  add rbx,32+  mov rcx,4+  mov rdi,temp_string+.print_word_loop:+  push rcx+  sub rbx,8+  mov rcx,16+  mov rax,[rbx]+.print_inner_loop:+  push rax+  shr rax,(64-4)+  mov al,[hexchars+rax]+  stosb  +  pop rax+  shl rax,4+  loop .print_inner_loop+  pop rcx+  loop .print_word_loop+  +  mov al,10+  stosb+  mov al,0+  stosb+  +  mov ARG1,temp_string+  call _printf+  +  pop rbx+  pop rbp+  pop rdi+  pop rsi+  retn++%endif+  +; --------------------------------------++; return in ZF+is_u_one:+  mov rax,1+  cmp [rbp  ],rax+  jnz .no_u_is_not_one+  dec rax+  cmp [rbp+ 8],rax+  jnz .no_u_is_not_one+  cmp [rbp+16],rax+  jnz .no_u_is_not_one+  cmp [rbp+24],rax+.no_u_is_not_one:+  retn++; --------------------------------------++; return in ZF+is_v_one:+  mov rax,1+  cmp [rbp+32],rax+  jnz .no_v_is_not_one+  dec rax+  cmp [rbp+40],rax+  jnz .no_v_is_not_one+  cmp [rbp+48],rax+  jnz .no_v_is_not_one+  cmp [rbp+56],rax+.no_v_is_not_one:+  retn++; -------------------------------------++is_rsi_zero:+  xor rax,rax+  cmp [rsi   ],rax+  jnz .no_rsi_is_not_zero+  cmp [rsi+ 8],rax+  jnz .no_rsi_is_not_zero+  cmp [rsi+16],rax+  jnz .no_rsi_is_not_zero+  cmp [rsi+24],rax+.no_rsi_is_not_zero:+  retn  +  +; -------------------------------------+   +; [rbx] := [rbx] + halfp_plus1+add_rbx_halfp_plus1:+  mov rdx, const_halfp_plus1+  +; [rbx] := [rbx] + [rdx]+; returns carry in CF+add_rbx_rdx:         +  mov rax,[rbx]+  add rax,[rdx]+  mov [rbx],rax++  mov rax,[rbx+8]+  adc rax,[rdx+8]+  mov [rbx+8],rax++  mov rax,[rbx+16]+  adc rax,[rdx+16]+  mov [rbx+16],rax++  mov rax,[rbx+24]+  adc rax,[rdx+24]+  mov [rbx+24],rax+  +  retn++; --------------------------------------++; [rbx] := [rbx] - [rdx]+; returns carry in CF+sub_rbx_rdx:+  mov rax,[rbx]+  sub rax,[rdx]+  mov [rbx],rax++  mov rax,[rbx+8]+  sbb rax,[rdx+8]+  mov [rbx+8],rax++  mov rax,[rbx+16]+  sbb rax,[rdx+16]+  mov [rbx+16],rax++  mov rax,[rbx+24]+  sbb rax,[rdx+24]+  mov [rbx+24],rax+  +  retn++; --------------------------------------++asm_shiftr256by1:+  push rbx +  push rsi+  push rdi ++  push ARG1             ; first argument (input)+  push ARG2             ; second argument (output)+  pop rdi+  pop rsi+  mov rbx,rdi++  cmp rsi,rdi+  jz .dont_copy  +  mov rcx,4+  rep movsq+.dont_copy:++  xor rax,rax              +  shr qword [rbx+24],1+  rcr qword [rbx+16],1+  rcr qword [rbx+ 8],1+  rcr qword [rbx   ],1  +  setc al                  ; return carry in rax+  +  pop rdi+  pop rsi+  pop rbx+  retn  +  +  +; shift [rbx] right by 1+; returns carry in CF+shift_rbx_right:+  shr qword [rbx+24],1+  rcr qword [rbx+16],1+  rcr qword [rbx+ 8],1+  rcr qword [rbx   ],1+  retn++; --------------------------------------++; void asm_inv_modp (uint64_t *a, uint64_t *b);+;+; exported function, multiplicative inverse modulo p+; uses binary euclidean algorithm+asm_inv_modp:+  push rbx +  push rbp+  push rsi+  push rdi ++  push ARG1+  push ARG2+  pop rdi               ; second argument (output)+  pop rsi               ; first argument (input)++  sub rsp,128              ; we will put the 4 temporary 256-bit numbers to the stack+  mov rbp,rsp++  call is_rsi_zero+  jnz .ok_input_is_not_zero++.input_is_zero:  +  xor rax,rax+  mov rcx,4+  rep stosq+  jmp restore+  +.ok_input_is_not_zero: +  push rdi++  ; rbp    = u+  ; rbp+32 = v+  ; rbp+64 = x1+  ; rbp+96 = x2++  mov rdi,rbp +  mov rcx,4+  rep movsq                 ; u = a++  mov rsi,const_p+  mov rcx,4+  rep movsq                 ; v = p++  xor rax,rax+  mov rcx,8+  rep stosq                 ; x1 = x2 = 0+  inc rax+  mov [rbp+64],rax          ; x1 = 1++  pop rdi+++inv_outer_loop:  ++%ifdef WITH_PRINTF+    lea rax,[rbp+0]+    call print_rax+    lea rax,[rbp+32]+    call print_rax+    lea rax,[rbp+64]+    call print_rax+    lea rax,[rbp+96]+    call print_rax+    call print_newline+%endif ++  call is_u_one+  jz u_is_one+  call is_v_one+  jz v_is_one      ++u_loop:  +%ifdef WITH_PRINTF+    lea rax,[rbp+0]+    call print_rax+    lea rax,[rbp+64]+    call print_rax+    call print_newline+%endif    ++  lea rbx,[rbp]              ; rbx = u+  test qword [rbx],1         ; is u even?+  jnz v_loop +  call shift_rbx_right       ; u is even; u = u>>1+  lea rbx,[rbp+64]           ; rbx = x1+  call shift_rbx_right       ; x1 = x1>>1+  jnc u_loop                 ; no carry -> continue+  call add_rbx_halfp_plus1   ; x1 = (x1+p)>>1+  jmp u_loop++v_loop:+%ifdef WITH_PRINTF+     lea rax,[rbp+32]+     call print_rax+     lea rax,[rbp+96]+     call print_rax+     call print_newline+%endif     ++  lea rbx,[rbp+32]           ; rbx = v+  test qword [rbx],1         ; is v even?  +  jnz which_is_smaller_u_or_v+  call shift_rbx_right       ; v is even; v = v>>1+  lea rbx,[rbp+96]           ; rbx = x2+  call shift_rbx_right       ; x2 = x2>>1+  jnc v_loop                 ; no carry -> continue+  call add_rbx_halfp_plus1   ; x2 = (x2+p)>>1+  jmp v_loop++which_is_smaller_u_or_v:+  mov rax,[rbp   +24]+  cmp rax,[rbp+32+24]  +  jb u_is_smaller+  ja u_is_bigger+  mov rax,[rbp   +16]+  cmp rax,[rbp+32+16]  +  jb u_is_smaller+  ja u_is_bigger+  mov rax,[rbp   + 8]+  cmp rax,[rbp+32+ 8]  +  jb u_is_smaller+  ja u_is_bigger+  mov rax,[rbp      ]+  cmp rax,[rbp+32   ]  +  jb u_is_smaller++u_is_bigger:                ; u >= v+  lea rbx,[rbp   ]+  lea rdx,[rbp+32]     +  call sub_rbx_rdx          ; u = u-v+  lea rbx,[rbp+64]+  lea rdx,[rbp+96]          +  call sub_rbx_rdx_modp     ; x1 = x1-x2 (mod p)+  jmp inv_outer_loop++u_is_smaller:               ; u < v+  lea rbx,[rbp+32]+  lea rdx,[rbp   ]     +  call sub_rbx_rdx          ; v = v-u+  lea rbx,[rbp+96]+  lea rdx,[rbp+64]          +  call sub_rbx_rdx_modp     ; x2 = x2-x1 (mod p)+  jmp inv_outer_loop++u_is_one:+  lea rsi,[rbp+64]          ; out = x1+  mov rcx,4+  rep movsq+  jmp restore+v_is_one:+  lea rsi,[rbp+96]          ; out = x2+  mov rcx,4+  rep movsq+restore:+  add rsp,128+  pop rdi+  pop rsi+  pop rbp+  pop rbx+  retn++; --------------------------------------++; void asm_add_modp (uint64_t *a, uint64_t *b, uint64_t *c);+asm_add_modp:+  push rbx +  push rbp+  push rsi+  push rdi ++  push ARG1+  push ARG2+  push ARG3+  pop rdi                  ; third argument (output)+  pop rdx                  ; second argument (input)+  pop rsi                  ; first argument (input)+ +  sub rsp,32               ; we will put the temporary result to the stack +  mov rbp,rsp            +  +  push rdi+  mov rdi,rbp+  mov rcx,4+  rep movsq  +  pop rdi+  +  mov rbx,rbp+  call add_rbx_rdx_modp+ +  mov rsi,rbx              ; copy the result where it should be+  mov rcx,4+  rep movsq+  +  add rsp,32+  +  pop rdi+  pop rsi+  pop rbp+  pop rbx+  retn++; void asm_sub_modp (uint64_t *a, uint64_t *b, uint64_t *c);+asm_sub_modp:+  push rbx +  push rbp+  push rsi+  push rdi ++  push ARG1+  push ARG2+  push ARG3+  pop rdi                  ; third argument (output)+  pop rdx                  ; second argument (input)+  pop rsi                  ; first argument (input)+    +  sub rsp,32               ; we will put the temporary result to the stack +  mov rbp,rsp            ++  push rdi+  mov rdi,rbp+  mov rcx,4+  rep movsq+  pop rdi+  +  mov rbx,rbp+  call sub_rbx_rdx_modp+ +  mov rsi,rbx              ; copy the result where it should be+  mov rcx,4+  rep movsq++  add rsp,32+  +  pop rdi+  pop rsi+  pop rbp+  pop rbx+  retn++; --------------------------------------++compare_rbx_with_p:+  mov rax,[rbx    +24]+  cmp rax,[const_p+24]    +  jb .next+  ja .next+  mov rax,[rbx    +16]+  cmp rax,[const_p+16]    +  jb .next+  ja .next+  mov rax,[rbx    + 8]+  cmp rax,[const_p+ 8]    +  jb .next+  ja .next+  mov rax,[rbx       ]+  cmp rax,[const_p   ]    +  ; jb .next+  ; ja .next+.next:+  retn++; [rbx] := [rbx] + [rdx] (mod p)+add_rbx_rdx_modp:+  call add_rbx_rdx+  jc .subtract_back_p +  call compare_rbx_with_p        ; !!+  jae .subtract_back_p+  retn+.subtract_back_p:+  mov rdx, const_p+  jmp sub_rbx_rdx  ++; --------------------------------------++; [rbx] := [rbx] - [rdx] (mod p)+sub_rbx_rdx_modp:+  call sub_rbx_rdx+  jc .add_back_p +  retn+.add_back_p:+  mov rdx, const_p+  jmp add_rbx_rdx  ++; --------------------------------------++; void asm_mul_modp (uint64_t *a, uint64_t *b, uint64_t *c);+asm_mul_modp:++  push rbx +  push rbp+  push rsi+  push rdi +  +  push ARG1+  push ARG2+  push ARG3+  pop rdi             ; third argument (output)+  pop rdx             ; second argument (input)+  pop rsi             ; first argument (input)+ +  sub rsp,64               ; we will put the temporary results to the stack +  mov rbp,rsp              ; [rbp] = acc, [rbp+32] = tmp            ++  push rdi+  mov rcx,4+  xor rax,rax+  lea rdi,[rbp]+  rep stosq                ; acc = 0+  pop rdi+    +  mov rcx,4+.mul_loop:+  push rcx+  push rdx+  +  cmp rcx,4+  jz .dont_scale_zero+  +  push rcx+  push rdx+  lea rbx,[rbp]+  call shiftl64_rbx_modp   ; acc := acc * 2^64 (mod p)+  pop rdx+  pop rcx+  +.dont_scale_zero:++  mov rdx,[rdx+rcx*8-8]+  lea rbx,[rbp+32]+  call scale_rsi_by_rdx_into_rbx_modp+  lea rbx,[rbp]+  lea rdx,[rbp+32]+  call add_rbx_rdx_modp+  +  pop rdx+  pop rcx+  loop .mul_loop+  +  lea rsi,[rbp]            ; acc+  mov rcx,4+  rep movsq                ; copy the result into the output+  +  add rsp,64+  +  pop rdi+  pop rsi+  pop rbp+  pop rbx+  retn++; multiplies minus_p by the 64 bit number in rdx (mod 2^256)+scale256_minusp_by_rdx_into_rbx:+  mov rax,1+  shl rax,32+  add rax,3d1h  ; 0000 0001 0000 03d1 = lower 64 bits of (2^256 - p)+  mul rdx+  mov [rbx]  ,rax +  mov [rbx+8],rdx+  xor rax,rax+  mov [rbx+16],rax+  mov [rbx+24],rax+  retn+  +; multiplies [rbx] by the 64 bit number in rdx, and returns the "carry" in rax+scale256_rbx_by_rdx:  +  push rcx++  ; rcx = multiplier+  ; r8  = carry+  ; r9  = zero+  +  mov rcx,rdx+  xor r9,r9      +    +  mov rax,[rbx]+  mul rcx+  mov [rbx],rax  +  mov r8,rdx      ; carry+  +  mov rax,[rbx+8]+  mul rcx+  add rax,r8+  adc rdx,r9+  mov [rbx+8],rax+  mov r8,rdx+  +  mov rax,[rbx+16]+  mul rcx+  add rax,r8+  adc rdx,r9  +  mov [rbx+16],rax+  mov r8,rdx+  +  mov rax,[rbx+24]+  mul rcx+  add rax,r8+  adc rdx,r9+  mov [rbx+24],rax+  +  mov rax,rdx        ; final carry+ +  pop rcx+  retn+  +; multiplies [rbx] by 2^64 mod p+shiftl64_rbx_modp:+  push rbp+  +  mov rdx,[rbx+32-8]  ; 64 bit "carry"+  +  mov rcx,3   ; 3 = 4-1+  .shift_loop:+  mov rax,[rbx+rcx*8-8]+  mov [rbx+rcx*8],rax+  loop .shift_loop+  xor rax,rax+  mov [rbx],rax     ; shifted it left by 64 bits; what is shifted outside would be 2^256*carry == (p+minus_p)*carry == minus_p*carry (mod p)+  +  sub rsp,32+  mov rbp,rsp+  +  push rbx+  lea rbx,[rbp]+  call scale256_minusp_by_rdx_into_rbx+  pop rbx+  +  lea rdx,[rbp]+  call add_rbx_rdx_modp+  +  add rsp,32+  +  pop rbp+  retn++  +; for compatibility, we also provide a shift-by-32-bit version+; multiplies [rbx] by 2^32 mod p+shiftl32_rbx_modp:+  push rbp+  +  xor rdx,rdx+  mov edx,dword [rbx+32-4]  ; 32 bit "carry"+  +  mov rcx,7   ; 7 = 8-1+  .shift_loop:+  mov eax,dword [rbx+rcx*4-4]+  mov dword [rbx+rcx*4],eax+  loop .shift_loop+  xor eax,eax+  mov dword [rbx],eax     ; shifted it left by 32 bits; what is shifted outside would be 2^256*carry == (p+minus_p)*carry == minus_p*carry (mod p)+  +  sub rsp,32+  mov rbp,rsp+  +  push rbx+  lea rbx,[rbp]+  call scale256_minusp_by_rdx_into_rbx+  pop rbx+  +  lea rdx,[rbp]+  call add_rbx_rdx_modp+  +  add rsp,32+  +  pop rbp+  retn+++; multiplies [rsi] by the 64 bit number in rdx, into [rbx] (modulo p)+scale_rsi_by_rdx_into_rbx_modp:+  push rbx +  push rbp+  push rsi+  push rdi +  +  sub rsp,32+  mov rbp,rsp++  push rbx++  mov rdi,rbx+  cmp rdi,rsi+  jz .dont_copy+  mov rcx,4+  rep movsq                  ; copy [rsi] into [rbx]+.dont_copy:  +  +  call scale256_rbx_by_rdx   ; multiply [rbx] (which is now=[rsi]) by rdx+  +  mov rdx,rax                ; the carry+  lea rbx,[rbp]              ; put the result onto the stack here+  call scale256_minusp_by_rdx_into_rbx+  +  pop rbx                    +  lea rdx,[rbp]+  call add_rbx_rdx_modp      ; [rbx] := [rbx] + temp+  +  add rsp,32+  +  pop rdi+  pop rsi+  pop rbp+  pop rbx+  retn  ++;---------------------------------------++; void asm_scale_modp (uint64_t *a, uint64_t  b, uint64_t *c);  +asm_scale_modp:++  push rbx +  push rbp+  push rsi+  push rdi +  +  push ARG1+  push ARG2+  push ARG3+  pop rbx                  ; third argument (output)+  pop rdx                  ; second argument (input)+  pop rsi                  ; first argument (input)++  call scale_rsi_by_rdx_into_rbx_modp+  +  pop rdi+  pop rsi+  pop rbp+  pop rbx+  retn++;---------------------------------------++; void asm_shiftl64_modp(uint64_t *a, uint64_t *b);+asm_shiftl64_modp:++  push rbx +  push rbp+  push rsi+  push rdi +  +  push ARG1                 ; first argument (input)+  push ARG2                 ; second argument (output)+  pop rdi+  pop rsi++  cmp rsi,rdi+  jz .dont_copy+  +  push rsi+  push rdi+  mov rcx,4+  rep movsq+  pop rdi+  pop rsi+  +.dont_copy: +  +  mov rbx,rdi+  call shiftl64_rbx_modp+  +  pop rdi+  pop rsi+  pop rbp+  pop rbx+  retn+  +; void asm_shiftl32_modp(uint64_t *a, uint64_t *b);+asm_shiftl32_modp:++  push rbx +  push rbp+  push rsi+  push rdi +  +  push ARG1                 ; first argument (input)+  push ARG2                 ; second argument (output)+  pop rdi+  pop rsi++  cmp rsi,rdi+  jz .dont_copy+  +  push rsi+  push rdi+  mov rcx,4+  rep movsq+  pop rdi+  pop rsi+  +.dont_copy: +  +  mov rbx,rdi+  call shiftl32_rbx_modp+  +  pop rdi+  pop rsi+  pop rbp+  pop rbx+  retn++;---------------------------------------+  
+ Bitcoin/Crypto/cbits/asm_modp_x86.asm view
@@ -0,0 +1,953 @@+
+; multiplication, inversion and division in the prime field Fp, x86 (32 bit) version
+; (c) 2013 Balazs Komuves
+;
+; compile on windows: nasm -fwin32 asm_modp.asm
+
+; --------------------------------------
+
+; %define WITH_PRINTF
+
+; --------------------------------------
+
+bits 32
+
+global _asm_add_modp        ; void asm_add_modp (uint32_t *a, uint32_t *b, uint32_t *c);
+global _asm_sub_modp        ; void asm_sub_modp (uint32_t *a, uint32_t *b, uint32_t *c);
+global _asm_inv_modp        ; void asm_mul_modp (uint32_t *a, uint32_t *b, uint32_t *c);
+global _asm_mul_modp        ; void asm_inv_modp (uint32_t *a, uint32_t *b);
+
+global _asm_scale_modp      ; void asm_scale_modp   (uint32_t *a, uint32_t  b, uint32_t *c);
+global _asm_shiftr256by1    ; int  asm_shiftr256by1 (uint32_t *a, uint32_t *b);
+
+global _asm_shiftl32_modp   ; void asm_shiftl32_modp(uint32_t *a, uint32_t *b);
+global _asm_shiftl64_modp   ; void asm_shiftl64_modp(uint32_t *a, uint32_t *b);
+
+
+%ifdef WITH_PRINTF
+extern printf
+%endif
+
+; --------------------------------------
+
+SECTION .data use32
+
+; --------------------------------------
+
+_hand_rolled 
+db "--- hand-rolled assembly ---",0  ; this here just that I can check if it was really linked into the final executable
+db "X86 (32 bit) version",0
+
+; --------------------------------------
+
+align 32
+
+; secp256k1_p
+const_p           dd 0FFFFFC2Fh , 0FFFFFFFEh , 0FFFFFFFFh , 0FFFFFFFFh , 0FFFFFFFFh , 0FFFFFFFFh , 0FFFFFFFFh , 0FFFFFFFFh
+
+; 2^256-p
+const_minus_p     dd  000003d1h ,  00000001h ,  00000000h ,  00000000h ,  00000000h ,  00000000h ,  00000000h ,  00000000h
+
+; (p/2) + 1
+const_halfp_plus1 dd 07ffffe18h , 0ffffffffh , 0ffffffffh , 0ffffffffh , 0ffffffffh , 0ffffffffh , 0ffffffffh , 07fffffffh 
+
+; --------------------------------------
+
+%ifdef WITH_PRINTF
+
+hexchars db '0123456789abcdef'
+
+temp_string times 66 db 0
+
+hello_world db 'hello world'
+newline     db 10,0
+
+%endif
+
+; --------------------------------------
+
+SECTION .text use32 class=code
+
+; --------------------------------------
+
+%ifdef WITH_PRINTF
+
+print_hello:
+  pushad
+  mov eax,hello_world
+  push eax
+  call _printf
+  add esp,4
+  popad
+  retn  
+
+print_newline:
+  pushad
+  mov eax,newline
+  push eax
+  call _printf
+  add esp,4
+  popad
+  retn  
+
+; debugging
+print_ebx:
+  pushad
+  
+  add ebx,32
+  mov ecx,8
+  mov edi,temp_string
+.print_word_loop:
+  push ecx
+  sub ebx,4
+  mov ecx,8
+  mov eax,[ebx]
+.print_inner_loop:
+  push eax
+  shr eax,28
+  mov al,[hexchars+eax]
+  stosb  
+  pop eax
+  shl eax,4
+  loop .print_inner_loop
+  pop ecx
+  loop .print_word_loop
+  
+  mov al,10
+  stosb
+  mov al,0
+  stosb
+  
+  mov eax,temp_string
+  push eax
+  call _printf
+  add esp,4
+  
+  popad
+  retn
+
+%endif
+  
+; --------------------------------------
+
+; return in ZF
+is_u_one:
+  mov eax,1
+  cmp [ebp  ],eax
+  jnz .no_u_is_not_one
+  dec eax
+  cmp [ebp+ 4],eax
+  jnz .no_u_is_not_one
+  cmp [ebp+ 8],eax
+  jnz .no_u_is_not_one
+  cmp [ebp+12],eax
+  jnz .no_u_is_not_one
+  cmp [ebp+16],eax
+  jnz .no_u_is_not_one
+  cmp [ebp+20],eax
+  jnz .no_u_is_not_one
+  cmp [ebp+24],eax
+  jnz .no_u_is_not_one
+  cmp [ebp+28],eax
+.no_u_is_not_one:
+  retn
+
+; --------------------------------------
+
+; return in ZF
+is_v_one:
+  mov eax,1
+  cmp [ebp+32],eax
+  jnz .no_v_is_not_one
+  dec eax
+  cmp [ebp+36],eax
+  jnz .no_v_is_not_one
+  cmp [ebp+40],eax
+  jnz .no_v_is_not_one
+  cmp [ebp+44],eax
+  jnz .no_v_is_not_one
+  cmp [ebp+48],eax
+  jnz .no_v_is_not_one
+  cmp [ebp+52],eax
+  jnz .no_v_is_not_one
+  cmp [ebp+56],eax
+  jnz .no_v_is_not_one
+  cmp [ebp+60],eax
+.no_v_is_not_one:
+  retn
+
+; -------------------------------------
+
+is_esi_zero:
+  xor eax,eax
+  cmp [esi   ],eax
+  jnz .no_esi_is_not_zero
+  cmp [esi+ 4],eax
+  jnz .no_esi_is_not_zero
+  cmp [esi+ 8],eax
+  jnz .no_esi_is_not_zero
+  cmp [esi+12],eax
+  jnz .no_esi_is_not_zero
+  cmp [esi+16],eax
+  jnz .no_esi_is_not_zero
+  cmp [esi+20],eax
+  jnz .no_esi_is_not_zero
+  cmp [esi+24],eax
+  jnz .no_esi_is_not_zero
+  cmp [esi+28],eax
+.no_esi_is_not_zero:
+  retn  
+  
+; -------------------------------------
+
+; [ebx] := [ebx] + halfp_plus1
+add_ebx_halfp_plus1:
+  mov edx, const_halfp_plus1
+  
+; [ebx] := [ebx] + [edx]
+; returns carry in CF
+add_ebx_edx:         
+  mov eax,[ebx]
+  add eax,[edx]
+  mov [ebx],eax
+
+  mov eax,[ebx+4]
+  adc eax,[edx+4]
+  mov [ebx+4],eax
+
+  mov eax,[ebx+8]
+  adc eax,[edx+8]
+  mov [ebx+8],eax
+
+  mov eax,[ebx+12]
+  adc eax,[edx+12]
+  mov [ebx+12],eax
+
+  mov eax,[ebx+16]
+  adc eax,[edx+16]
+  mov [ebx+16],eax
+
+  mov eax,[ebx+20]
+  adc eax,[edx+20]
+  mov [ebx+20],eax
+
+  mov eax,[ebx+24]
+  adc eax,[edx+24]
+  mov [ebx+24],eax
+
+  mov eax,[ebx+28]
+  adc eax,[edx+28]
+  mov [ebx+28],eax
+  
+  retn
+
+; --------------------------------------
+
+; [ebx] := [ebx] - [edx]
+; returns carry in CF
+sub_ebx_edx:
+  mov eax,[ebx]
+  sub eax,[edx]
+  mov [ebx],eax
+
+  mov eax,[ebx+4]
+  sbb eax,[edx+4]
+  mov [ebx+4],eax
+
+  mov eax,[ebx+8]
+  sbb eax,[edx+8]
+  mov [ebx+8],eax
+
+  mov eax,[ebx+12]
+  sbb eax,[edx+12]
+  mov [ebx+12],eax
+
+  mov eax,[ebx+16]
+  sbb eax,[edx+16]
+  mov [ebx+16],eax
+
+  mov eax,[ebx+20]
+  sbb eax,[edx+20]
+  mov [ebx+20],eax
+
+  mov eax,[ebx+24]
+  sbb eax,[edx+24]
+  mov [ebx+24],eax
+
+  mov eax,[ebx+28]
+  sbb eax,[edx+28]
+  mov [ebx+28],eax
+  
+  retn
+
+; --------------------------------------
+
+; int  asm_shiftr256by1 (uint32_t *a, uint32_t *b);
+_asm_shiftr256by1:
+  push ebx 
+  push esi
+  push edi 
+
+  mov esi,[esp+16+0]       ; first argument, input (call 4 bytes, 3x push 12 bytes)
+  mov edi,[esp+16+4]       ; second argument, output
+  mov ebx,edi
+
+  cmp esi,edi
+  jz .dont_copy  
+  mov ecx,8
+  rep movsd
+.dont_copy:
+    
+  call shift_ebx_right
+  
+  mov eax,0                ; mov doesn't change the flags  
+  setc al                  ; return carry in eax
+  
+  pop edi
+  pop esi
+  pop ebx
+  retn  
+  
+  
+; shift [ebx] right by 1
+; returns carry in CF
+shift_ebx_right:
+  shr dword [ebx+28],1
+  rcr dword [ebx+24],1
+  rcr dword [ebx+20],1
+  rcr dword [ebx+16],1
+  rcr dword [ebx+12],1
+  rcr dword [ebx+ 8],1
+  rcr dword [ebx+ 4],1
+  rcr dword [ebx   ],1
+  retn
+
+; --------------------------------------
+
+; void asm_inv_modp (uint32_t *a, uint32_t *b);
+; cdecl function, multiplicative inverse modulo p
+; uses binary euclidean algorithm
+_asm_inv_modp:
+  push ebx 
+  push ebp
+  push esi
+  push edi 
+
+  mov esi,[esp+20+0]       ; first argument, input (call 4 bytes, 4x push 16 bytes)
+  mov edi,[esp+20+4]       ; second argument, output
+
+  sub esp,128              ; we will put the 4 temporary 256-bit numbers to the stack
+  mov ebp,esp
+
+  call is_esi_zero
+  jnz .ok_input_is_not_zero
+
+.input_is_zero:  
+  xor eax,eax
+  mov ecx,8
+  rep stosd
+  jmp restore
+  
+.ok_input_is_not_zero: 
+  ;push esi
+
+  push edi
+
+  ; ebp    = u
+  ; ebp+32 = v
+  ; ebp+64 = x1
+  ; ebp+96 = x2
+
+  mov edi,ebp 
+  mov ecx,8
+  rep movsd                 ; u = a
+
+  mov esi,const_p
+  mov ecx,8
+  rep movsd                 ; v = p
+
+  xor eax,eax
+  mov ecx,16
+  rep stosd                 ; x1 = x2 = 0
+  inc eax
+  mov [ebp+64],eax          ; x1 = 1
+
+  pop edi
+  ;pop esi
+
+
+inv_outer_loop:  
+
+%ifdef WITH_PRINTF
+    lea ebx,[ebp+0]
+    call print_ebx
+    lea ebx,[ebp+32]
+    call print_ebx
+    lea ebx,[ebp+64]
+    call print_ebx
+    lea ebx,[ebp+96]
+    call print_ebx
+    call print_newline
+%endif 
+
+  call is_u_one
+  jz u_is_one
+  call is_v_one
+  jz v_is_one      
+
+u_loop:  
+%ifdef WITH_PRINTF
+    lea ebx,[ebp+0]
+    call print_ebx
+    lea ebx,[ebp+64]
+    call print_ebx
+    call print_newline
+%endif    
+
+  lea ebx,[ebp]              ; ebx = u
+  test dword [ebx],1         ; is u even?
+  jnz v_loop 
+  call shift_ebx_right       ; u is even; u = u>>1
+  lea ebx,[ebp+64]           ; ebx = x1
+  call shift_ebx_right       ; x1 = x1>>1
+  jnc u_loop                 ; no carry -> continue
+  call add_ebx_halfp_plus1   ; x1 = (x1+p)>>1
+  jmp u_loop
+
+v_loop:
+%ifdef WITH_PRINTF
+     lea ebx,[ebp+32]
+     call print_ebx
+     lea ebx,[ebp+96]
+     call print_ebx
+     call print_newline
+%endif     
+
+  lea ebx,[ebp+32]           ; ebx = v
+  test dword [ebx],1         ; is v even?  
+  jnz which_is_smaller_u_or_v
+  call shift_ebx_right       ; v is even; v = v>>1
+  lea ebx,[ebp+96]           ; ebx = x2
+  call shift_ebx_right       ; x2 = x2>>1
+  jnc v_loop                 ; no carry -> continue
+  call add_ebx_halfp_plus1   ; x2 = (x2+p)>>1
+  jmp v_loop
+
+which_is_smaller_u_or_v:
+  mov eax,[ebp   +28]
+  cmp eax,[ebp+32+28]  
+  jb u_is_smaller
+  ja u_is_bigger
+  mov eax,[ebp   +24]
+  cmp eax,[ebp+32+24]  
+  jb u_is_smaller
+  ja u_is_bigger
+  mov eax,[ebp   +20]
+  cmp eax,[ebp+32+20]  
+  jb u_is_smaller
+  ja u_is_bigger
+  mov eax,[ebp   +16]
+  cmp eax,[ebp+32+16]  
+  jb u_is_smaller
+  ja u_is_bigger
+  mov eax,[ebp   +12]
+  cmp eax,[ebp+32+12]  
+  jb u_is_smaller
+  ja u_is_bigger
+  mov eax,[ebp   + 8]
+  cmp eax,[ebp+32+ 8]  
+  jb u_is_smaller
+  ja u_is_bigger
+  mov eax,[ebp   + 4]
+  cmp eax,[ebp+32+ 4]  
+  jb u_is_smaller
+  ja u_is_bigger
+  mov eax,[ebp      ]
+  cmp eax,[ebp+32   ]  
+  jb u_is_smaller
+
+u_is_bigger:                ; u >= v
+  lea ebx,[ebp   ]
+  lea edx,[ebp+32]     
+  call sub_ebx_edx          ; u = u-v
+  lea ebx,[ebp+64]
+  lea edx,[ebp+96]          
+  call sub_ebx_edx_modp     ; x1 = x1-x2 (mod p)
+  jmp inv_outer_loop
+
+u_is_smaller:               ; u < v
+  lea ebx,[ebp+32]
+  lea edx,[ebp   ]     
+  call sub_ebx_edx          ; v = v-u
+  lea ebx,[ebp+96]
+  lea edx,[ebp+64]          
+  call sub_ebx_edx_modp     ; x2 = x2-x1 (mod p)
+  jmp inv_outer_loop
+
+u_is_one:
+  lea esi,[ebp+64]          ; out = x1
+  mov ecx,8
+  rep movsd
+  jmp restore
+v_is_one:
+  lea esi,[ebp+96]          ; out = x2
+  mov ecx,8
+  rep movsd
+restore:
+  add esp,128
+  pop edi
+  pop esi
+  pop ebp
+  pop ebx
+  retn
+
+; --------------------------------------
+
+; void asm_add_modp (uint32_t *a, uint32_t *b, uint32_t *c);
+_asm_add_modp:
+  push ebx 
+  push ebp
+  push esi
+  push edi 
+  
+  mov esi,[esp+20+0]       ; first argument (call 4 bytes, 4x push 16 bytes)
+  mov edx,[esp+20+4]       ; second argument
+  mov edi,[esp+20+8]       ; third argument (output 
+ 
+  sub esp,32               ; we will put the temporary result to the stack 
+  mov ebp,esp            
+  
+  push edi
+  mov edi,ebp
+  mov ecx,8
+  rep movsd  
+  pop edi
+  
+  mov ebx,ebp
+  call add_ebx_edx_modp
+ 
+  mov esi,ebx              ; copy the result where it should be
+  mov ecx,8
+  rep movsd
+  
+  add esp,32
+  
+  pop edi
+  pop esi
+  pop ebp
+  pop ebx
+  retn
+
+; void asm_sub_modp (uint32_t *a, uint32_t *b, uint32_t *c);
+_asm_sub_modp:
+  push ebx 
+  push ebp
+  push esi
+  push edi 
+  
+  mov esi,[esp+20+0]       ; first argument (call 4 bytes, 4x push 16 bytes)
+  mov edx,[esp+20+4]       ; second argument
+  mov edi,[esp+20+8]       ; third argument (output 
+  
+  sub esp,32               ; we will put the temporary result to the stack 
+  mov ebp,esp            
+
+  push edi
+  mov edi,ebp
+  mov ecx,8
+  rep movsd  
+  pop edi
+  
+  mov ebx,ebp
+  call sub_ebx_edx_modp
+ 
+  mov esi,ebx              ; copy the result where it should be
+  mov ecx,8
+  rep movsd
+
+  add esp,32
+  
+  pop edi
+  pop esi
+  pop ebp
+  pop ebx
+  retn
+
+; --------------------------------------
+
+compare_ebx_with_p:
+  mov eax,[ebx    +28]
+  cmp eax,[const_p+28]    
+  jb .next
+  ja .next
+  mov eax,[ebx    +24]
+  cmp eax,[const_p+24]    
+  jb .next
+  ja .next
+  mov eax,[ebx    +20]
+  cmp eax,[const_p+20]    
+  jb .next
+  ja .next
+  mov eax,[ebx    +16]
+  cmp eax,[const_p+16]    
+  jb .next
+  ja .next
+  mov eax,[ebx    +12]
+  cmp eax,[const_p+12]    
+  jb .next
+  ja .next
+  mov eax,[ebx    + 8]
+  cmp eax,[const_p+ 8]    
+  jb .next
+  ja .next
+  mov eax,[ebx    + 4]
+  cmp eax,[const_p+ 4]    
+  jb .next
+  ja .next
+  mov eax,[ebx       ]
+  cmp eax,[const_p   ]    
+  ; jb .next
+  ; ja .next
+.next:
+  retn
+
+; [ebx] := [ebx] + [edx] (mod p)
+add_ebx_edx_modp:
+  call add_ebx_edx
+  jc .subtract_back_p 
+  call compare_ebx_with_p        ; !!
+  jae .subtract_back_p
+  retn
+.subtract_back_p:
+  mov edx, const_p
+  jmp sub_ebx_edx  
+
+; --------------------------------------
+
+; [ebx] := [ebx] - [edx] (mod p)
+sub_ebx_edx_modp:
+  call sub_ebx_edx
+  jc .add_back_p 
+  retn
+.add_back_p:
+  mov edx, const_p
+  jmp add_ebx_edx  
+
+; --------------------------------------
+
+; void asm_mul_modp (uint32_t *a, uint32_t *b, uint32_t *c);
+_asm_mul_modp:
+
+  push ebx 
+  push ebp
+  push esi
+  push edi 
+  
+  mov esi,[esp+20+0]       ; first argument (call 4 bytes, 4x push 16 bytes)
+  mov edx,[esp+20+4]       ; second argument
+  mov edi,[esp+20+8]       ; third argument (output)
+ 
+  sub esp,64               ; we will put the temporary results to the stack 
+  mov ebp,esp              ; ebp = acc, ebp+32 = tmp            
+
+  push edi
+  mov ecx,8
+  xor eax,eax
+  lea edi,[ebp]
+  rep stosd                ; acc = 0
+  pop edi
+    
+  mov ecx,8
+.mul_loop:
+  push ecx
+  push edx
+  
+  cmp ecx,8
+  jz .dont_scale_zero
+  
+  push edx
+  push ecx
+  lea ebx,[ebp]
+  call shiftl32_ebx_modp   ; acc := acc * 2^32 (mod p)
+  pop ecx
+  pop edx
+  
+.dont_scale_zero:
+
+  mov edx,[edx+ecx*4-4]
+  lea ebx,[ebp+32]
+  call scale_esi_by_edx_into_ebx_modp
+  lea ebx,[ebp]
+  lea edx,[ebp+32]
+  call add_ebx_edx_modp
+  
+  pop edx
+  pop ecx
+  loop .mul_loop
+  
+  lea esi,[ebp]            ; acc
+  mov ecx,8
+  rep movsd                ; copy the result into the output
+  
+  add esp,64
+  
+  pop edi
+  pop esi
+  pop ebp
+  pop ebx
+  retn
+
+; multiplies minus_p by the 32 bit number in edx (mod 2^256)
+scale256_minusp_by_edx_into_ebx:
+  push edx
+  mov eax,3d1h      ; 0000 03d1 = lower 32 bits of (2^256-p)
+  mul edx
+  mov [ebx],eax    
+  pop eax
+  add eax,edx       ; carry + orig edx (because 2^256-p = 0x01000003d1 ; this is the "1" in the 32th bit)
+  mov [ebx+4],eax
+  mov eax,0
+  setc al
+  mov [ebx+8],eax
+  xor eax,eax
+  mov [ebx+12],eax
+  mov [ebx+16],eax
+  mov [ebx+20],eax
+  mov [ebx+24],eax
+  mov [ebx+28],eax
+  retn
+  
+; multiplies [ebx] by the 32 bit number in edx, and returns the "carry" in eax
+scale256_ebx_by_edx:  
+  push ecx
+  push edi
+  push ebp
+  
+  mov ecx,edx
+  xor edi,edi
+    
+  mov eax,[ebx]
+  mul ecx
+  mov [ebx],eax  
+  mov ebp,edx    ; carry
+  
+  mov eax,[ebx+4]
+  mul ecx
+  add eax,ebp
+  adc edx,edi
+  mov [ebx+4],eax
+  mov ebp,edx
+  
+  mov eax,[ebx+8]
+  mul ecx
+  add eax,ebp
+  adc edx,edi
+  mov [ebx+8],eax
+  mov ebp,edx
+  
+  mov eax,[ebx+12]
+  mul ecx
+  add eax,ebp
+  adc edx,edi
+  mov [ebx+12],eax
+  mov ebp,edx
+  
+  mov eax,[ebx+16]
+  mul ecx
+  add eax,ebp
+  adc edx,edi
+  mov [ebx+16],eax
+  mov ebp,edx
+
+  mov eax,[ebx+20]
+  mul ecx
+  add eax,ebp
+  adc edx,edi
+  mov [ebx+20],eax
+  mov ebp,edx
+
+  mov eax,[ebx+24]
+  mul ecx
+  add eax,ebp
+  adc edx,edi
+  mov [ebx+24],eax
+  mov ebp,edx
+
+  mov eax,[ebx+28]
+  mul ecx
+  add eax,ebp
+  adc edx,edi
+  mov [ebx+28],eax
+  
+  mov eax,edx        ; final carry
+ 
+  pop ebp
+  pop edi
+  pop ecx
+  retn
+  
+; multiplies [ebx] by 2^64 mod p
+; for compatibility, we also provide a shift-by-64-bit version 
+; (simply by calling the 32 bit shift twice)
+shiftl64_ebx_modp:
+  call shiftl32_ebx_modp
+  jmp  shiftl32_ebx_modp
+
+; multiplies [ebx] by 2^32 mod p
+shiftl32_ebx_modp:
+  push ebp
+  
+  mov edx,[ebx+28]  ; 32 bit "carry" (28 = 32-4)
+  
+  mov ecx,7
+  .shift_loop:
+  mov eax,[ebx+ecx*4-4]
+  mov [ebx+ecx*4],eax
+  loop .shift_loop
+  xor eax,eax
+  mov [ebx],eax     ; shifted it left by 32 bits; what is shifted outside would be 2^256*carry == (p+minus_p)*carry == minus_p*carry (mod p)
+  
+  sub esp,32
+  mov ebp,esp
+  
+  push ebx
+  lea ebx,[ebp]
+  call scale256_minusp_by_edx_into_ebx
+  pop ebx
+  
+  lea edx,[ebp]
+  call add_ebx_edx_modp
+  
+  add esp,32
+  
+  pop ebp
+  retn
+  
+; multiplies [esi] by the 32 bit number in edx, into ebx (modulo p)
+scale_esi_by_edx_into_ebx_modp:
+  push ebx 
+  push ebp
+  push esi
+  push edi 
+  
+  sub esp,32
+  mov ebp,esp
+
+  push ebx
+  mov edi,ebx
+  cmp edi,esi
+  jz .dont_copy
+  mov ecx,8
+  rep movsd                  ; copy [esi] into [ebx]
+.dont_copy:  
+  
+  call scale256_ebx_by_edx   ; multiply [ebx] (which is now=[esi]) by edx
+  
+  mov edx,eax                ; the carry
+  lea ebx,[ebp]              ; put the result onto the stack here
+  call scale256_minusp_by_edx_into_ebx
+  
+  pop ebx                    
+  lea edx,[ebp]
+  call add_ebx_edx_modp      ; [ebx] := [ebx] + temp
+  
+  add esp,32
+  
+  pop edi
+  pop esi
+  pop ebp
+  pop ebx
+  retn  
+
+;---------------------------------------
+ 
+; void asm_scale_modp   (uint32_t *a, uint32_t  b, uint32_t *c); 
+_asm_scale_modp:
+
+  push ebx 
+  push ebp
+  push esi
+  push edi 
+  
+  mov esi,[esp+20+0]       ; first argument (call 4 bytes, 4x push 16 bytes)
+  mov edx,[esp+20+4]       ; second argument (which is a 32 bit number)
+  mov ebx,[esp+20+8]       ; third atgument (output)
+
+  call scale_esi_by_edx_into_ebx_modp
+  
+  pop edi
+  pop esi
+  pop ebp
+  pop ebx
+  retn
+
+;---------------------------------------
+
+; void asm_shiftl32_modp(uint32_t *a, uint32_t *b);  
+_asm_shiftl32_modp:
+
+  push ebx 
+  push ebp
+  push esi
+  push edi 
+  
+  mov esi,[esp+20+0]       ; first argument (call 4 bytes, 4x push 16 bytes)
+  mov edi,[esp+20+4]       ; second argument (output)
+
+  cmp esi,edi
+  jz .dont_copy
+  
+  push esi
+  push edi
+  mov ecx,8
+  rep movsd
+  pop edi
+  pop esi
+  
+.dont_copy: 
+  
+  mov ebx,edi
+  call shiftl32_ebx_modp
+  
+  pop edi
+  pop esi
+  pop ebp
+  pop ebx
+  retn
+
+;---------------------------------------
+  
+; void asm_shiftl64_modp(uint32_t *a, uint32_t *b);
+_asm_shiftl64_modp:
+
+  push ebx 
+  push ebp
+  push esi
+  push edi 
+  
+  mov esi,[esp+20+0]       ; first argument (call 4 bytes, 4x push 16 bytes)
+  mov edi,[esp+20+4]       ; second argument (output)
+
+  cmp esi,edi
+  jz .dont_copy
+  
+  push esi
+  push edi
+  mov ecx,8
+  rep movsd
+  pop edi
+  pop esi
+  
+.dont_copy: 
+  
+  mov ebx,edi
+  call shiftl64_ebx_modp
+  
+  pop edi
+  pop esi
+  pop ebp
+  pop ebx
+  retn
+
+;---------------------------------------
+  
+ Bitcoin/Crypto/cbits/c_ec.c view
@@ -0,0 +1,132 @@+
+// Bottleneck elliptic curve routines (namely, the exponentiation)
+
+#include "c_ec.h"
+
+// -----------------------------------------------------------------------------
+
+void c_dblECP( Fp xp , Fp yp , Fp zp
+             , Fp xr , Fp yr , Fp zr )
+{
+  Fp xp2,yp2,xpyp2,a,b,c,t,a2;
+
+  mul_modp(xp,xp,xp2);
+  mul_modp(yp,yp,yp2); 
+  add_modp(xp2,xp2,a);
+  add_modp(a  ,xp2,a);
+  mul_modp(xp,yp2,xpyp2);
+  add_modp(xpyp2,xpyp2,b);
+  mul_modp(yp2,yp2,c);
+  mul_modp(a,a,a2);
+  sub_modp(a2,b,xr);
+  mul_modp(yp,zp,zr);
+  add_modp(xr,xr,t);
+  sub_modp(b,t,t);
+  mul_modp(a,t,t);
+  sub_modp(t,c,t);
+  copy256(t,yr);
+}
+
+// -----------------------------------------------------------------------------
+
+void c_addECP( Fp xp , Fp yp , Fp zp
+             , Fp xq , Fp yq , Fp zq 
+             , Fp xr , Fp yr , Fp zr )
+{
+
+  if (equalsZero256(zp))
+  { 
+    copy256(xq,xr);
+    copy256(yq,yr);
+    copy256(zq,zr);
+    return;
+  }
+
+  if (equalsZero256(zq))
+  { 
+    copy256(xp,xr);
+    copy256(yp,yr);
+    copy256(zp,zr);
+    return;
+  }
+
+  Fp zp2,zp3,zq2,zq3,zpzq,xpzq2,xqzp2,ypzq3,yqzp3;
+  Fp a,b,c,d,e,d2,e2,ae2,e2bc;
+
+  mul_modp(zp,zp,zp2);
+  mul_modp(zq,zq,zq2);
+  mul_modp(zp,zp2,zp3);
+  mul_modp(zq,zq2,zq3);
+
+  mul_modp(xp,zq2,xpzq2);
+  mul_modp(xq,zp2,xqzp2);
+  mul_modp(yp,zq3,ypzq3);
+  mul_modp(yq,zp3,yqzp3);
+
+  sub_modp(xpzq2,xqzp2,b);
+  sub_modp(ypzq3,yqzp3,d);
+
+  if ( equalsZero256(b) && equalsZero256(d) )
+  {
+    c_dblECP ( xp,yp,zp, xr,yr,zr );
+    return;
+  }
+
+  add_modp(xpzq2,xqzp2,a);
+  add_modp(ypzq3,yqzp3,c);
+
+  add_modp(b,b,e);
+  mul_modp(e,e,e2);
+  mul_modp(a,e2,ae2);
+  mul_modp(d,d,d2);
+  sub_modp(d2,ae2,xr);
+  mul_modp(zp,zq,zpzq);
+  mul_modp(e,zpzq,zr);
+
+  mul_modp(b,c,e2bc);
+  mul_modp(e2bc,e2,e2bc);
+  
+  sub_modp(ae2,xr,yr);
+  sub_modp(yr ,xr,yr);
+  mul_modp(yr ,d ,yr);
+  sub_modp(yr ,e2bc,yr);
+}
+
+// -----------------------------------------------------------------------------
+
+void c_mulECP ( Fp xp, Fp yp, Fp zp, uint256 mult, Fp xr, Fp yr, Fp zr )
+{
+  Fp accx,accy,accz;
+  zero256(accx);  
+  zero256(accy);  
+  zero256(accz);  
+  accx[0] = 1;
+  accy[0] = 2;    // infinity is (1,2,0)
+
+  Fp bx,by,bz;
+  copy256(xp,bx);
+  copy256(yp,by);
+  copy256(zp,bz);
+
+  for(int k=0;k<8;k++)
+  {
+    uint32_t e = mult[k];
+    for(int j=0;j<32;j++)
+    {
+      if (e & 1)
+      {
+        c_addECP(accx,accy,accz, bx,by,bz, accx,accy,accz);
+      }      
+      c_dblECP(bx,by,bz, bx,by,bz);
+      e = (e>>1);
+    }
+  }
+
+  copy256(accx,xr);
+  copy256(accy,yr);
+  copy256(accz,zr);
+
+}
+
+// -----------------------------------------------------------------------------
+
+ Bitcoin/Crypto/cbits/c_ec.h view
@@ -0,0 +1,18 @@+
+// Bottleneck elliptic curve routines (namely, the exponentiation)
+
+#include "c_modp.h"
+
+// -----------------------------------------------------------------------------
+
+void c_dblECP ( Fp xp, Fp yp, Fp zp
+              , Fp xr, Fp yr, Fp zr );
+
+void c_addECP ( Fp xp, Fp yp, Fp zp
+              , Fp xq, Fp yq, Fp zq 
+              , Fp xr, Fp yr, Fp zr );
+
+void c_mulECP ( Fp xp, Fp yp, Fp zp, uint256 mult, Fp xr, Fp yr, Fp zr );
+
+// -----------------------------------------------------------------------------
+
+ Bitcoin/Crypto/cbits/c_modp.c view
@@ -0,0 +1,436 @@++// Relatively fast arithmetic operations mod secp256k1_p.+// Output is always the last argument, and it can optionally coincide with one of the inputs.++// (c) 2013 Balazs Komuves++//------------------------------------------------------------------------------++#include "c_word256.h"+#include "c_modp.h"++/*+#include <stdio.h>+void fake()+{ printf("fake\n");    // to ensure linking of printf?+}+*/++//------------------------------------------------------------------------------++#ifdef WITH_X86ASM++extern void     asm_add_modp     (uint32_t *a, uint32_t *b, uint32_t *c);+extern void     asm_sub_modp     (uint32_t *a, uint32_t *b, uint32_t *c);+extern void     asm_mul_modp     (uint32_t *a, uint32_t *b, uint32_t *c);+extern void     asm_inv_modp     (uint32_t *a, uint32_t *b);++extern void     asm_scale_modp   (uint32_t *a, uint32_t  b, uint32_t *c);+extern int      asm_shiftr256by1 (uint32_t *a, uint32_t *b);++extern void     asm_shiftl32_modp(uint32_t *a, uint32_t *b);+extern void     asm_shiftl64_modp(uint32_t *a, uint32_t *b);++#endif++//------------------------------------------------------------------------------++uint256 secp256k1_p  = { 0xFFFFFC2F , 0xFFFFFFFE , 0xFFFFFFFF , 0xFFFFFFFF , 0xFFFFFFFF , 0xFFFFFFFF , 0xFFFFFFFF , 0xFFFFFFFF };+uint256 minus_p      = { 0x000003d1 , 0x00000001 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 };+uint256 p_minus_2    = { 0xFFFFFC2D , 0xFFFFFFFE , 0xFFFFFFFF , 0xFFFFFFFF , 0xFFFFFFFF , 0xFFFFFFFF , 0xFFFFFFFF , 0xFFFFFFFF };+uint256 half_p       = { 0x7ffffe17 , 0xffffffff , 0xffffffff , 0xffffffff , 0xffffffff , 0xffffffff , 0xffffffff , 0x7fffffff };+uint256 half_p_plus1 = { 0x7ffffe18 , 0xffffffff , 0xffffffff , 0xffffffff , 0xffffffff , 0xffffffff , 0xffffffff , 0x7fffffff };++// minus_p = 2^256 - secp256k1_p++//------------------------------------------------------------------------------++// multiplies minus_p with a 32-bit number. +// Since minus_p is small, this should be faster than the generic routine+inline void scale_minusp(uint32_t b32, uint256 c)+{+  uint64_t tmp = (uint64_t)0x3d1 * (uint64_t)b32;+  c[0] = tmp;+  tmp = (tmp>>32) + b32;+  c[1] = tmp;+  c[2] = (tmp>>32);+  for(int i=3;i<8;i++) { c[i]=0; }+}++// multiplication of a 256-bit number with a 32-bit number (returns the carry)+// we copy it here so that maybe the C compiler can better inline or whatever+inline uint32_t local_scale256(uint256 a, uint32_t b32, uint256 c)+{+  uint64_t carry = 0;+  uint64_t b64   = b32;+  for(int i=0;i<8;i++)+  {+    uint64_t tmp = (uint64_t)(a[i])*b64 + carry;+    carry = tmp >> 32;+    c[i]  = tmp;+  }+  return carry;+}++// shifts right by 1.+inline uint32_t shiftr256by1(uint256 a, uint256 b)+{++#ifdef WITH_X86ASM++  return asm_shiftr256by1(a,b);+  +#else+ +  uint32_t carry = 0;+  for(int i=7;i>=0;i--)+  { +    uint32_t tmp = a[i] << 31;     // order is important when b and a points to the same place in the memory+    b[i] = (a[i] >> 1) | carry;+    carry = tmp; +  }+  return carry;+  +#endif++}++// we copy it here so that maybe the C compiler can better inline or whatever+inline uint32_t local_add256(uint256 a, uint256 b, uint256 c)+{+  uint64_t carry = 0;+  for(int i=0;i<8;i++)+  {+    uint64_t tmp = (uint64_t)(a[i]) + (uint64_t)(b[i]) + carry;+    carry = tmp >> 32;+    c[i]  = tmp;+  }+  return carry;+}++// we copy it here so that maybe the C compiler can better inline or whatever+inline uint32_t local_sub256(uint256 a, uint256 b, uint256 c)+{+  uint64_t carry = 1;+  for(int i=0;i<8;i++)+  {+    uint64_t tmp = (uint64_t)(a[i]) + (uint64_t)(~b[i]) + carry;+    carry = tmp >> 32;+    c[i]  = tmp;+  }+  return carry;+}++// we copy it here so that maybe the C compiler can better inline or whatever+inline int local_equalsOne256(uint256 a)+{ if (a[0]!=1) { return 0; } +  for(int i=1;i<8;i++) { if (a[i]) { return 0; } }+  return 1;+}++//------------------------------------------------------------------------------++// Addition mod p. We assume that the inputs are strictly in the range [0,p).+inline void add_modp(Fp a, Fp b, Fp c)+{++#ifdef WITH_X86ASM++  asm_add_modp(a,b,c);+  +#else++  uint32_t carry = local_add256(a,b,c);+  if ( (!carry) && lessThan256(c,secp256k1_p) ) +  {+    return; +  } +  else+  {+    local_sub256(c,secp256k1_p,c);+  } ++#endif++}++int is_zero256(uint256 a)+{+  for(int i=0;i<8;i++) { if (a[i]!=0) return 0; }+  return 1;+}++// Negation mod p. We assume that the inputs are strictly in the range [0,p).+void neg_modp(Fp a, Fp b)+{+  if (is_zero256(a))    // !!+  {+    zero256(b);+  }+  else+  {+    local_sub256(secp256k1_p,a,b);+  }+} ++// this could be faster...+inline void sub_modp(Fp a, Fp b, Fp c)+{++#ifdef WITH_X86ASM++  asm_sub_modp(a,b,c);++#else++  uint256 negb;+  neg_modp(b,negb);+  add_modp(a,negb,c);++#endif++}++// Multiplication of a number in [0,p) by a 32 bit number, mod p.+// The idea is that 2^256 = (p + minus_p) +inline void scale_modp(Fp a, uint32_t b, Fp c)+{+#ifdef WITH_X86ASM++  asm_scale_modp(a,b,c);+  +#else++  uint256 tmp1,tmp2;+  uint32_t carry = local_scale256(a,b,tmp1);   // carry * 2^256 + tmp1 = a*b+  scale_minusp(carry,tmp2);                    // carry * p = 0 (modp), thus what remains is carry*minus_p+  add_modp(tmp1,tmp2,c);+  +#endif  +}++// Multiply by 2^32 mod p+inline void shiftl32_modp(Fp a, Fp b)+{+#ifdef WITH_X86ASM++  asm_shiftl32_modp(a,b);+  +#else++  uint256 tmp1,tmp2;+  uint32_t carry = shiftl256_fullword(a,tmp1);+  scale_minusp(carry,tmp2);          // carry * p = 0 (modp), thus what remains is carry * minus_p  +  add_modp(tmp1,tmp2,b);           +  +#endif  +}++// Multiply by 2^64 mod p+inline void shiftl64_modp(Fp a, Fp b)+{+#ifdef WITH_X86ASM++  asm_shiftl64_modp(a,b);+  +#else++  uint256 tmp;+  shiftl32_modp(a,tmp);+  shiftl32_modp(tmp,b);+  +#endif  +}++// multiplication of two numbers in the range [0,p), mod p;+inline void mul_modp(Fp a, Fp b, Fp c)+{++#ifdef WITH_X86ASM++  asm_mul_modp(a,b,c);++#else++  uint256 tmp,acc;+  zero256(acc);++  uint32_t carry = 0;+  for (int i=7;i>=0;i--)+  {+    if (i<7) { shiftl32_modp(acc,acc); }+    scale_modp(a,b[i],tmp);+    add_modp(acc,tmp,acc);+  }++  copy256(acc,c);    // because c can coincide with a or b++#endif++}++//------------------------------------------------------------------------------++// Inverse of a number [0,p) mod p.+// This is implemented as exponentiation to the power of (p-2), +// since the multiplicative group has order (p-1).+//+// This is slow.+void inv_modp_power(Fp a, Fp b)+{+  pow_modp(a,p_minus_2,b);+} ++// Inverse using Euclidean algorithm. This is much faster than the power one+//+// Algorithm 2.22 computes a^-1 mod p by finding an integer x such that ax + py = 1.+// The algorithm maintains the invariants a*x1 + p*y1 = u, a*x2 + p*y2 = v where y1 and y2+// are not explicitly computed. The algorithm terminates when u = 1 or v = 1. In the +// former case, a*x1 + p*y1 = 1 and hence a^-1 = x1 mod p. In the latter case,+// a*x2 + p*y2 = 1 and a^-1 = x2 mod p. +//++void inv_modp_euclid(Fp a, Fp b)+{++#ifdef WITH_X86ASM++  asm_inv_modp(a,b);++#else++  uint256 u,v,x1,x2;++  if (equalsZero256(a)) { zero256(b); return; }++  zero256(x1); x1[0]=1;      // x1 = 1+  zero256(x2);               // x2 = 0+  copy256(a,u);              // u = a+  copy256(secp256k1_p,v);    // v = p+  +  while( (!local_equalsOne256(u)) && (!local_equalsOne256(v)) )+  {++    while (!(u[0] & 1))+    { shiftr256by1(u,u);+      uint32_t odd = shiftr256by1(x1,x1);+      if (odd) { local_add256(x1,half_p_plus1,x1); }+    }++    while (!(v[0] & 1))+    { shiftr256by1(v,v);+      uint32_t odd = shiftr256by1(x2,x2);+      if (odd) { local_add256(x2,half_p_plus1,x2); }+    }++    if (lessThan256(u,v))+    { local_sub256(v,u,v);+      sub_modp(x2,x1,x2);+    }+    else+    { local_sub256(u,v,u);+      sub_modp(x1,x2,x1);+    }+  }+  +  if (local_equalsOne256(u)) { copy256(x1,b); } else { copy256(x2,b); }++#endif // WITH_X86ASM++} ++//------------------------------------------------------------------------------++inline void sqr_modp(Fp a, Fp b)+{+#ifdef WITH_X86ASM+  asm_mul_modp(a,a,b);+#else+  mul_modp(a,a,b);+#endif+}++#ifdef WITH_X86ASM+#define MULP asm_mul_modp+#else+#define MULP mul_modp+#endif++void inv_modp_pow_spec(Fp a1, Fp out)+{+  Fp a2   ; MULP ( a1 , a1 , a2  );+  Fp a3   ; MULP ( a2 , a1 , a3  );+  Fp a4   ; MULP ( a2 , a2 , a4  );+  Fp a5   ; MULP ( a4 , a1 , a5  );+  Fp a10  ; MULP ( a5 , a5 , a10 );+            +  Fp a11  ; MULP ( a10 , a1  , a11 );+  Fp a21  ; MULP ( a10 , a11 , a21 );+  Fp a42  ; MULP ( a21 , a21 , a42 );+  Fp a45  ; MULP ( a42 , a3  , a45 );      +  Fp x    ; MULP ( a42 , a21 , x   );        // x = a63++  Fp a126  ; MULP ( x     , x    , a126  );   // x = a63+  Fp a252  ; MULP ( a126  , a126 , a252  );+  Fp a504  ; MULP ( a252  , a252 , a504  );+  Fp a1008 ; MULP ( a504  , a504 , a1008 );+  Fp a1019 ; MULP ( a1008 , a11  , a1019 );+  Fp a1023 ; MULP ( a1019 , a4   , a1023 );++  for (int i=0; i<21; i++) +  { for (int j=0; j<10; j++) { MULP (x,x,x); }+    MULP (x,a1023,x);+  }++  for (int j=0; j<10; j++) { MULP (x,x,x); }+  MULP (x,a1019,x);++  for (int i=0 ; i<2 ; i++) +  { for (int j=0 ; j<10 ; j++) { MULP (x,x,x); }+    MULP (x,a1023,x);+  }++  for (int j=0; j<10; j++) { MULP (x,x,x); }+  MULP (x,a45,out);+}++//------------------------------------------------------------------------------++void div_modp(Fp a, Fp b, Fp c)+{++#ifdef WITH_X86ASM++   uint256 binv;+   asm_inv_modp(b,binv);      // inv_modp_euclid(b,binv);+   asm_mul_modp(a,binv,c);    // mul_modp(a,binv,c);++#else++   uint256 binv;+   inv_modp_euclid(b,binv);+   mul_modp(a,binv,c);++#endif++}++void pow_modp(Fp base, Fp exp, Fp out)+{+  uint256 acc,b,e;++  zero256(acc); acc[0] = 1;        // acc = 1+  copy256(base,b);                 // b = base+  copy256(exp ,e);                 // e = exp++  int m = highestSetBit256(exp);+  for (int i=0;i<m;i++)+  {+    if (e[0] & 1) { mul_modp(acc,b,acc); }      // acc = acc*b, if the lowest bit of e is set+    mul_modp(b,b,b);                            // b = b^2+    shiftr256by1(e,e);                          // e = e>>1+  }+  copy256(acc,out);+}++//------------------------------------------------------------------------------
+ Bitcoin/Crypto/cbits/c_modp.h view
@@ -0,0 +1,40 @@++// Relatively fast arithmetic operations mod secp256k1_p.+// Output is always the last argument, and it can optionally coincide with one of the inputs.++// (c) 2013 Balazs Komuves++//------------------------------------------------------------------------------++#ifndef C_MODP_H_INCLUDED+#define C_MODP_H_INCLUDED++#include <stdint.h>+#include "c_word256.h"++//------------------------------------------------------------------------------++typedef uint256 Fp;++//------------------------------------------------------------------------------++void neg_modp(Fp a, Fp b);        // Negation mod p. We assume that the inputs are strictly in the range [0,p).++void inv_modp_power   (Fp a, Fp b);   // multiplicative inverse using x^(p-2)+void inv_modp_pow_spec(Fp a, Fp b);   // multiplicative inverse using x^(p-2), but power algo specialized to p-2+void inv_modp_euclid  (Fp a, Fp b);   // multiplicative inverse using Euclidean algorithm++void add_modp(Fp a, Fp b, Fp c);  // Addition mod p. We assume that the inputs are strictly in the range [0,p).+void sub_modp(Fp a, Fp b, Fp c);  // Subtraction mod p. We assume that the inputs are strictly in the range [0,p).+void mul_modp(Fp a, Fp b, Fp c);  // multiplication of two numbers in the range [0,p), mod p;+void div_modp(Fp a, Fp b, Fp c);  // division+void pow_modp(Fp a, Fp b, Fp c);  // exponentiation++uint32_t shiftr256by1(Fp a, Fp b);  // (n `div` 2) (exported for testing)++void scale_modp(Fp a, uint32_t b, Fp c);  // Multiplication of a number in [0,p) by a 32 bit number, mod p.+void shiftl32_modp(Fp a, Fp b);           // Multiply by 2^32 mod p++//------------------------------------------------------------------------------++#endif // C_MODP_H_INCLUDED
+ Bitcoin/Crypto/cbits/c_word256.c view
@@ -0,0 +1,221 @@++// Relatively fast arithmetic operations mod 2^256+// Output is always the last argument, and it can optionally coincide with one of the inputs.++// (c) 2013 Balazs Komuves++//------------------------------------------------------------------------------++#include "c_word256.h"++//------------------------------------------------------------------------------++void zero256(uint256 a)+{+  for(int i=0;i<8;i++) { a[i]=0; }+}++void copy256(uint256 a, uint256 b)+{+  for(int i=0;i<8;i++) { b[i] = a[i]; }+}++// bitwise not+void not256(uint256 a, uint256 b)+{+  for(int i=0;i<8;i++)+  { +    b[i] = ~a[i];+  }+} ++// shifts right by k bits. k must be between 0 and 31+uint32_t shiftr256_small(uint256 a, int k, uint256 b)+{+  if (k==0) { copy256(a,b); return 0; }+  uint32_t carry = 0;+  for(int i=7;i>=0;i--)+  { +    uint32_t tmp = a[i] << (32-k);     // order is important when b and a points to the same place in the memory+    b[i] = (a[i] >> k) | carry;+    carry = tmp; +  }+  return carry;+}++// shifts left by k bits. k must be between 0 and 31+uint32_t shiftl256_small(uint256 a, int k, uint256 b)+{+  if (k==0) { copy256(a,b); return 0; }+  uint32_t carry = 0;+  for(int i=0;i<8;i++)+  { +    uint32_t tmp = a[i] >> (32-k);     // order is important when b and a points to the same place in the memory+    b[i] = (a[i] << k) | carry;+    carry = tmp; +  }+  return carry;+}++// shifts right by 32 bits+uint32_t shiftr256_fullword(uint256 a, uint256 b)+{+  uint32_t carry = a[0];   +  for(int i=0;i<7;i++) { b[i] = a[i+1]; } +  b[7] = 0;+  return carry;+}++// shifts left by 32 bits+uint32_t shiftl256_fullword(uint256 a, uint256 b)+{+  uint32_t carry = a[7];   +  for(int i=6;i>=0;i--) { b[i+1] = a[i]; } +  b[0] = 0;+  return carry;+}++//------------------------------------------------------------------------------++// addition modulo 2^256 (returns the carry)+uint32_t add256(uint256 a, uint256 b, uint256 c)+{+  uint64_t carry = 0;+  for(int i=0;i<8;i++)+  {+    uint64_t tmp = (uint64_t)(a[i]) + (uint64_t)(b[i]) + carry;+    carry = tmp >> 32;+    c[i]  = tmp;+  }+  return carry;+}++// neg(x) = not(x)+1;+void neg256(uint256 a, uint256 b)+{+  uint64_t carry = 1;+  for(int i=0;i<8;i++)+  { +    uint64_t tmp = (uint64_t)(~a[i]) + carry;+    carry = tmp >> 32;+    b[i]  = tmp;+  }+} ++// subtraction mod 2^256+uint32_t sub256(uint256 a, uint256 b, uint256 c)+{+  uint64_t carry = 1;+  for(int i=0;i<8;i++)+  {+    uint64_t tmp = (uint64_t)(a[i]) + (uint64_t)(~b[i]) + carry;+    carry = tmp >> 32;+    c[i]  = tmp;+  }+  return carry;+}++// multiplication mod 2^256+void mul256(uint256 a, uint256 b, uint256 c)+{+  uint256 tmp,acc;+  zero256(acc);+  for(int i=7;i>=0;i--)+  {+    if (i<7) { shiftl256_fullword(acc,acc); }+    scale256(a,b[i],tmp);+    add256(acc,tmp,acc);+  }+  copy256(acc,c);    // because c can coincide with a or b++}++// multiplication of a 256-bit number with a 32-bit number (returns the carry)+uint32_t scale256(uint256 a, uint32_t b32, uint256 c)+{+  uint64_t carry = 0;+  uint64_t b64   = b32;+  for(int i=0;i<8;i++)+  {+    uint64_t tmp = (uint64_t)(a[i])*b64 + carry;+    carry = tmp >> 32;+    c[i]  = tmp;+  }+  return carry;+}++// a<b+int lessThan256(uint256 a, uint256 b)+{+  for(int i=7;i>=0;i--)+  {+    if (a[i] < b[i]) { return 1; }+    if (a[i] > b[i]) { return 0; }+  }+  // they are equal+  return 0;+}++// a<=b+int lessOrEqual256(uint256 a, uint256 b)+{+  for(int i=7;i>=0;i--)+  {+    if (a[i] < b[i]) { return 1; }+    if (a[i] > b[i]) { return 0; }+  }+  // they are equal+  return 1;+}++// a==b+int equals256(uint256 a, uint256 b)+{+  for(int i=7;i>=0;i--)+  {+    if (a[i] != b[i]) { return 0; }+  }+  // they are equal+  return 1;+}++//------------------------------------------------------------------------------++// index of the highest set bit = ceil(log2(x+1))+// log2(0) = 0         // 00000 +// log2(1) = 1         // 00001 +// log2(2) = 2         // 00010 +// log2(3) = 2         // 00011 +// log2(4) = 3         // 00100 +// log2(2^256-1) = 256++int highestSetBit256(uint256 a)+{+  int n = 0;+  for (int i=0;i<8;i++)+  { +    int n0 = i<<5;  // i*32+    uint32_t w = a[i];    +    for (int k=0;k<32;k++)+    { if (w==0) { break; }+      w = (w >> 1);+      n = n0 + k + 1;+    }       +  }+  return n;+}++// a==0+int equalsZero256(uint256 a)+{ for(int i=0;i<8;i++) { if (a[i]) { return 0; } }+  return 1;+}++// a==1 +int equalsOne256(uint256 a)+{ if (a[0]!=1) { return 0; } +  for(int i=1;i<8;i++) { if (a[i]) { return 0; } }+  return 1;+}++//------------------------------------------------------------------------------
+ Bitcoin/Crypto/cbits/c_word256.h view
@@ -0,0 +1,49 @@++// Relatively fast arithmetic operations mod 2^256, mod secp256k1_p and mod secp256k1_n.+// Output is always the last argument, and it can optionally coincide with one of the inputs.++// (c) 2013 Balazs Komuves++//------------------------------------------------------------------------------++#ifndef C_WORD256_H_INCLUDED+#define C_WORD256_H_INCLUDED++#include <stdint.h>++//------------------------------------------------------------------------------++// little-endian (first word is the lowest value)+typedef uint32_t uint256[8];++void zero256(uint256 a);+void copy256(uint256 a, uint256 b);+void not256 (uint256 a, uint256 b);      // bitwise not++uint32_t shiftr256_small(uint256 a, int k, uint256 b);  // shifts right by k bits. k must be between 0 and 31+uint32_t shiftl256_small(uint256 a, int k, uint256 b);  // shifts left by k bits. k must be between 0 and 31++uint32_t shiftl256_fullword(uint256 a, uint256 b);      // shifts left by 32 bits+uint32_t shiftr256_fullword(uint256 a, uint256 b);      // shifts right by 32 bits++void neg256(uint256 a, uint256 b);            // negation mod 2^256++int lessThan256   (uint256 a, uint256 b);       // a <  b comparison+int lessOrEqual256(uint256 a, uint256 b);       // a <= b+int equals256     (uint256 a, uint256 b);       // a == b++int equalsZero256(uint256 a);   // a==0+int equalsOne256 (uint256 a);   // a==1++uint32_t add256(uint256 a, uint256 b, uint256 c); // addition mod 2^256 (returns the carry)+uint32_t sub256(uint256 a, uint256 b, uint256 c); // subtraction mod 2^256+void     mul256(uint256 a, uint256 b, uint256 c); // multiplication mod 2^256++uint32_t scale256(uint256 a, uint32_t b, uint256 c);  // multiplication by a 32 bit number++int highestSetBit256(uint256 a);   // the index of the highest set bit++//------------------------------------------------------------------------------++#endif // C_WORD256_H_INCLUDED+
+ Bitcoin/Misc.hs view
@@ -0,0 +1,33 @@++-- | This module re-exports (almost) all the @Bitcoin.Misc.*@ submodules++module Bitcoin.Misc +  ( module Bitcoin.Misc.Bifunctor+  , module Bitcoin.Misc.BigInt+  , module Bitcoin.Misc.Endian+  , module Bitcoin.Misc.HexString+  , module Bitcoin.Misc.Monad+  , module Bitcoin.Misc.OctetStream+  , module Bitcoin.Misc.Strict+  , module Bitcoin.Misc.Tuple+  , module Bitcoin.Misc.Unique+  , module Bitcoin.Misc.UnixTime+  , module Bitcoin.Misc.Zipper+  )+  where++--------------------------------------------------------------------------------++import Bitcoin.Misc.Bifunctor+import Bitcoin.Misc.BigInt+import Bitcoin.Misc.Endian+import Bitcoin.Misc.HexString+import Bitcoin.Misc.Monad+import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.Strict+import Bitcoin.Misc.Tuple+import Bitcoin.Misc.Unique+import Bitcoin.Misc.UnixTime+import Bitcoin.Misc.Zipper++--------------------------------------------------------------------------------
+ Bitcoin/Misc/BiMap.hs view
@@ -0,0 +1,69 @@+
+-- | Bidirectional maps (bijections)
+
+{-# LANGUAGE BangPatterns #-}
+module Bitcoin.Misc.BiMap where
+
+--------------------------------------------------------------------------------
+
+import Data.List ( foldl' )
+
+import qualified Data.Map as Map
+import Data.Map (Map) 
+
+--------------------------------------------------------------------------------
+
+data BiMap a b = BiMap
+  { _forwardMap  :: !(Map a b)
+  , _backwardMap :: !(Map b a)
+  }
+
+--------------------------------------------------------------------------------
+
+empty :: (Ord a, Ord b) => BiMap a b
+empty = BiMap Map.empty Map.empty
+
+toList :: (Ord a, Ord b) => BiMap a b -> [(a,b)]
+toList (BiMap fwd bwd) = Map.toList fwd
+
+toListRev :: (Ord a, Ord b) => BiMap a b -> [(b,a)]
+toListRev (BiMap fwd bwd) = Map.toList bwd
+
+fromList :: (Ord a, Ord b) => [(a,b)] -> BiMap a b 
+fromList xys = foldl' f empty xys where
+  f !old (!x,!y) = insert x y old
+
+--------------------------------------------------------------------------------
+
+lookup :: (Ord a) => a -> BiMap a b -> Maybe b
+lookup !x (BiMap !fwd !bwd) = Map.lookup x fwd
+
+lookupRev :: (Ord b) => b -> BiMap a b -> Maybe a
+lookupRev !y (BiMap !fwd !bwd) = Map.lookup y bwd
+
+-- | In case there is a (partial) conflict with the existing 'BiMap', the conflicting
+-- pair is removed and the new pair is inserted.
+insert :: (Ord a, Ord b) => a -> b -> BiMap a b -> BiMap a b
+insert !x !y (BiMap !fwd !bwd) = 
+  case Map.lookup x fwd of
+    Nothing -> case Map.lookup y bwd of 
+      Nothing -> BiMap (Map.insert x y                 fwd) (Map.insert y x                 bwd)
+      Just x' -> BiMap (Map.insert x y $ Map.delete x' fwd) (Map.insert y x                 bwd)
+    Just y' -> case Map.lookup y bwd of 
+      Nothing -> BiMap (Map.insert x y                 fwd) (Map.insert y x $ Map.delete y' bwd)
+      Just x' -> BiMap (Map.insert x y $ Map.delete x' fwd) (Map.insert y x $ Map.delete y' bwd)
+
+delete :: (Ord a, Ord b) => a -> BiMap a b -> BiMap a b
+delete !x old@(BiMap !fwd !bwd) = 
+  case Map.lookup x fwd of
+    Nothing -> old
+    Just y  -> BiMap (Map.delete x fwd) (Map.delete y bwd)
+
+deleteRev :: (Ord a, Ord b) => b -> BiMap a b -> BiMap a b
+deleteRev !y old@(BiMap !fwd !bwd) = 
+  case Map.lookup y bwd of
+    Nothing -> old
+    Just x  -> BiMap (Map.delete x fwd) (Map.delete y bwd)
+
+--------------------------------------------------------------------------------
+
+ Bitcoin/Misc/Bifunctor.hs view
@@ -0,0 +1,65 @@++-- | Bifunctors and more. +--+-- Used primarily for transactions, which are parametrized+-- in both input scripts and output scripts.++module Bitcoin.Misc.Bifunctor where++--------------------------------------------------------------------------------++class BiFunctor f where+  fmapFst  :: (a -> b) -> f a c -> f b c+  fmapSnd  :: (b -> c) -> f a b -> f a c+  fmapBoth :: (a -> c) -> (b -> d) -> f a b -> f c d++  fmapFst f = fmapBoth f id+  fmapSnd g = fmapBoth id g+  fmapBoth f g = fmapSnd g . fmapFst f ++--------------------------------------------------------------------------------++class BiFoldable f where+  bifoldl :: (a -> b -> a) -> (a -> c -> a) -> a -> f b c -> a+  bifoldr :: (b -> a -> a) -> (c -> a -> a) -> f b c -> a -> a++toListFst :: BiFoldable f => f a b -> [a]+toListFst what = bifoldr (:) (const id) what []++toListSnd :: BiFoldable f => f a b -> [b]+toListSnd what = bifoldr (const id) (:) what []++--------------------------------------------------------------------------------++-- | This is a rather nonstandard version of traverseable, but this is what we need+class BiTraversable f where+  mapAccumLFst  :: (acc -> b -> (acc,c)) -> acc -> f b d -> (acc, f c d)+  mapAccumLSnd  :: (acc -> c -> (acc,d)) -> acc -> f b c -> (acc, f b d)+  mapAccumLBoth :: (acc -> b -> (acc,d)) -> (acc -> c -> (acc,e)) -> acc -> f b c -> (acc, f d e)+ +  mapAccumLFst f = mapAccumLBoth f (,)+  mapAccumLSnd g = mapAccumLBoth (,) g+  mapAccumLBoth f g acc x = let (acc',y) = mapAccumLFst f acc  x +                            in             mapAccumLSnd g acc' y++--------------------------------------------------------------------------------+  +mapAccumLFst_ :: BiTraversable f => (acc -> b -> (acc,c)) -> acc -> f b d -> f c d+mapAccumLFst_ f acc = snd . mapAccumLFst f acc++mapAccumLSnd_ :: BiTraversable f => (acc -> c -> (acc,d)) -> acc -> f b c -> f b d+mapAccumLSnd_ g acc = snd . mapAccumLSnd g acc++mapAccumLBoth_ :: BiTraversable f => (acc -> b -> (acc,d)) -> (acc -> c -> (acc,e)) -> acc -> f b c -> f d e+mapAccumLBoth_ f g acc = snd . mapAccumLBoth f g acc++--------------------------------------------------------------------------------++-- | Note: this is unsafe (the list must be long enough)+zipWithFst :: BiTraversable f => (x -> a -> b) -> [x] -> f a c -> f b c+zipWithFst f zs = mapAccumLFst_ (\(x:xs) a -> (xs, f x a)) zs++zipWithSnd :: BiTraversable f => (y -> b -> c) -> [y] -> f a b -> f a c+zipWithSnd g zs = mapAccumLSnd_ (\(y:ys) b -> (ys, g y b)) zs++--------------------------------------------------------------------------------
+ Bitcoin/Misc/BigInt.hs view
@@ -0,0 +1,53 @@++-- | Encoding and decoding of big /natural/ numbers as ByteString or [Word8]++module Bitcoin.Misc.BigInt where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits+import Data.List ( unfoldr )++--------------------------------------------------------------------------------+-- * encoding/decoding nonnegative integers++bigEndianRollInteger :: [Word8] -> Integer+bigEndianRollInteger = littleEndianRollInteger . reverse++littleEndianRollInteger :: [Word8] -> Integer+littleEndianRollInteger = foldr unstep 0 where+  unstep b a = shiftL a 8 .|. fromIntegral b++bigEndianUnrollInteger :: Integer -> [Word8]+bigEndianUnrollInteger = reverse . littleEndianUnrollInteger++littleEndianUnrollInteger :: Integer -> [Word8]+littleEndianUnrollInteger = unfoldr step where+  step 0 = Nothing+  step i = Just (fromIntegral i, shiftR i 8)++--------------------------------------------------------------------------------++-- | Always 32 byte long (if the integer was less than @2^256@)+bigEndianInteger32 :: Integer -> [Word8]+bigEndianInteger32 = extend32 . bigEndianUnrollInteger where+  extend32 what = replicate (32-n) 0 ++ what where n = length what++littleEndianInteger32 :: Integer -> [Word8]+littleEndianInteger32 = extend32 . littleEndianUnrollInteger where+  extend32 what = what ++ replicate (32-n) 0 where n = length what++--------------------------------------------------------------------------------++-- | Always 20 byte long (if the integer was less than @2^160@)+bigEndianInteger20 :: Integer -> [Word8]+bigEndianInteger20 = extend20 . bigEndianUnrollInteger where+  extend20 what = replicate (20-n) 0 ++ what where n = length what++littleEndianInteger20 :: Integer -> [Word8]+littleEndianInteger20 = extend20 . littleEndianUnrollInteger where+  extend20 what = what ++ replicate (20-n) 0 where n = length what++--------------------------------------------------------------------------------+
+ Bitcoin/Misc/Endian.hs view
@@ -0,0 +1,163 @@++-- | Dealing with endianness issues++{-# LANGUAGE BangPatterns #-}+module Bitcoin.Misc.Endian where++--------------------------------------------------------------------------------++import Data.Word+import Foreign++import qualified System.IO.Unsafe as Unsafe++--------------------------------------------------------------------------------++data Endian+  = LittleEndian +  | BigEndian +  deriving (Eq,Show)++isLittleEndian :: Endian -> Bool+isLittleEndian e = case e of+  LittleEndian -> True+  BigEndian    -> False++isBigEndian :: Endian -> Bool+isBigEndian e = case e of+  LittleEndian -> False+  BigEndian    -> True++--------------------------------------------------------------------------------++hostEndian :: Endian+hostEndian = Unsafe.unsafePerformIO detectHostEndian++detectHostEndian :: IO Endian+detectHostEndian = do+  let be = 0x12345678 :: Word32+      le = 0x78563412 :: Word32+      ws = [0x12,0x34,0x56,0x78] :: [Word8]+  allocaArray 4 $ \p_word8 -> do+    pokeArray p_word8 ws+    x <- peek (castPtr p_word8 :: Ptr Word32)+    if x == le +      then return LittleEndian+      else if x == be +        then return BigEndian+        else error "fatal error: cannot detect endianness of host (neither little-endian nor big-endian)"++--------------------------------------------------------------------------------++class HasByteOrder a where+  -- | swaps the byte order+  swapByteOrder :: a -> a    ++  toLilEndBytes  :: a -> [Word8]      -- ^ LE order+  toBigEndBytes  :: a -> [Word8]      -- ^ BE order++  fromLilEndBytes  :: [Word8] -> a      -- ^ LE order+  fromBigEndBytes  :: [Word8] -> a      -- ^ BE order++  toBigEndBytes  = reverse . toLilEndBytes+  toLilEndBytes = reverse . toBigEndBytes++  fromBigEndBytes  = fromLilEndBytes . reverse+  fromLilEndBytes  = fromBigEndBytes . reverse++--------------------------------------------------------------------------------++-- | Native memory order+toMachineBytes :: HasByteOrder a => a -> [Word8]      +toMachineBytes = case hostEndian of +  LittleEndian -> toLilEndBytes +  BigEndian    -> toBigEndBytes ++-- | Native memory order+fromMachineBytes :: HasByteOrder a => [Word8] -> a      +fromMachineBytes = case hostEndian of +  LittleEndian -> fromLilEndBytes+  BigEndian    -> fromBigEndBytes ++--------------------------------------------------------------------------------++-- | on little-endian hosts, this is identity; on big-endian hosts, it swaps the byte order+swapByteOrderToLE :: HasByteOrder a => a -> a        +swapByteOrderToLE = case hostEndian of+  LittleEndian -> id+  BigEndian    -> swapByteOrder++-- | on big-endian hosts, this is identity; on little-endian hosts, it swaps the byte order+swapByteOrderToBE :: HasByteOrder a => a -> a        +swapByteOrderToBE = case hostEndian of+  LittleEndian -> swapByteOrder+  BigEndian    -> id++--------------------------------------------------------------------------------++instance HasByteOrder Word16 where+  swapByteOrder x = shiftL (x .&. 0x00ff) 8+                  + shiftR (x .&. 0xff00) 8++  toLilEndBytes x = map fromIntegral [        x   , shiftR x 8 ]+  toBigEndBytes x = map fromIntegral [ shiftR x 8 ,        x   ]++  fromLilEndBytes [a,b] = shiftL (fromIntegral b) 8 +                        +         fromIntegral a++  fromBigEndBytes [b,a] = shiftL (fromIntegral b) 8 +                        +         fromIntegral a++instance HasByteOrder Word32 where+  swapByteOrder x = shiftL (x .&. 0x000000ff) 24+                  + shiftL (x .&. 0x0000ff00)  8+                  + shiftR (x .&. 0x00ff0000)  8+                  + shiftR (x .&. 0xff000000) 24++  toLilEndBytes x = map fromIntegral [        x    , shiftR x 8  , shiftR x 16 , shiftR x 24 ]+  toBigEndBytes x = map fromIntegral [ shiftR x 24 , shiftR x 16 , shiftR x 8  ,        x    ]++  fromLilEndBytes [a,b,c,d] = shiftL (fromIntegral d) 24+                            + shiftL (fromIntegral c) 16+                            + shiftL (fromIntegral b) 8 +                            +         fromIntegral a++  fromBigEndBytes [d,c,b,a] = shiftL (fromIntegral d) 24+                            + shiftL (fromIntegral c) 16+                            + shiftL (fromIntegral b) 8 +                            +         fromIntegral a++instance HasByteOrder Word64 where+  swapByteOrder x = shiftL (x .&. 0x00000000000000ff) 56+                  + shiftL (x .&. 0x000000000000ff00) 40+                  + shiftL (x .&. 0x0000000000ff0000) 24+                  + shiftL (x .&. 0x00000000ff000000)  8+                  + shiftR (x .&. 0x000000ff00000000)  8+                  + shiftR (x .&. 0x0000ff0000000000) 24+                  + shiftR (x .&. 0x00ff000000000000) 40+                  + shiftR (x .&. 0xff00000000000000) 56+  toLilEndBytes x = map fromIntegral [        x    , shiftR x 8  , shiftR x 16 , shiftR x 24 , shiftR x 32 , shiftR x 40 , shiftR x 48 , shiftR x 56 ]+  toBigEndBytes x = map fromIntegral [ shiftR x 56 , shiftR x 48 , shiftR x 40 , shiftR x 32 , shiftR x 24 , shiftR x 16 , shiftR x 8  ,        x    ]++  fromLilEndBytes [a,b,c,d,e,f,g,h]+                          = shiftL (fromIntegral h) 56+                          + shiftL (fromIntegral g) 48+                          + shiftL (fromIntegral f) 40+                          + shiftL (fromIntegral e) 32+                          + shiftL (fromIntegral d) 24+                          + shiftL (fromIntegral c) 16+                          + shiftL (fromIntegral b) 8 +                          +         fromIntegral a++  fromBigEndBytes [h,g,f,e,d,c,b,a]+                          = shiftL (fromIntegral h) 56+                          + shiftL (fromIntegral g) 48+                          + shiftL (fromIntegral f) 40+                          + shiftL (fromIntegral e) 32+                          + shiftL (fromIntegral d) 24+                          + shiftL (fromIntegral c) 16+                          + shiftL (fromIntegral b) 8 +                          +         fromIntegral a++--------------------------------------------------------------------------------+
+ Bitcoin/Misc/HexString.hs view
@@ -0,0 +1,106 @@++-- | Encoding and decoding hex strings++{-# LANGUAGE EmptyDataDecls #-}+module Bitcoin.Misc.HexString where ++--------------------------------------------------------------------------------++import Data.Array ++import Data.Char+import Data.Int+import Data.Word+import Data.Bits++-- import Control.Monad ( liftM )++import Bitcoin.Misc.OctetStream++--------------------------------------------------------------------------------++-- | The phantom type is used to encode endianness+newtype HexString = HexString { unHexString :: String } deriving (Eq,Show)++--------------------------------------------------------------------------------++toHexString :: OctetStream a => a -> HexString+toHexString = toHexString' False++toHexString' :: OctetStream a => Bool -> a -> HexString+toHexString' uppercase x = hexEncode' uppercase (toWord8List x)++toHexStringChars :: OctetStream a => a -> String+toHexStringChars = unHexString . toHexString++fromHexString :: OctetStream a => HexString -> a+fromHexString  = fromWord8List . hexDecode++--------------------------------------------------------------------------------++reverseHexString :: HexString -> HexString+reverseHexString = HexString . unsafeReverseHexString . unHexString++unsafeReverseHexString :: String -> String+unsafeReverseHexString = fromPairs . reverse . toPairs where+  toPairs :: [Char] -> [(Char,Char)]+  toPairs (x:y:rest) = (x,y) : toPairs rest+  toPairs [] = []  +  toPairs _  = error "unsafeReverseHexString/toPairs: odd number of characters"+  fromPairs :: [(Char,Char)] -> [Char]+  fromPairs = concatMap (\(x,y) -> [x,y])++--------------------------------------------------------------------------------+-- * encoding and decoding ByteStrings as (little-endian) hex strings++safeHexDecode :: String -> Maybe [Word8]+safeHexDecode s = if even (length s) && all isHexDigit s then Just (go s) else Nothing where ++  go (x:y:rest) = (shiftL (f x) 4 + f y) : go rest+  go [] = []+  go [x] = error "hexDecode: expecting even number of characters"++  f :: Char -> Word8+  f c | c >= '0' && c <= '9'  =  ordW c - 48+      | c >= 'A' && c <= 'F'  =  ordW c - 65 + 10+      | c >= 'a' && c <= 'f'  =  ordW c - 97 + 10+      | otherwise             =  error "hexDecode: unexpected character"++  ordW :: Char -> Word8+  ordW = fromIntegral . ord++{- +-- already implemented in Data.Char+isHexDigit :: Char -> Bool+isHexDigit c =  (c >= '0' && c <= '9') +             || (c >= 'a' && c <= 'f') +             || (c >= 'A' && c <= 'F') +-}+ +--------------------------------------------------------------------------------++-- | from "4142" to [0xAB]+hexDecode :: HexString -> [Word8]+hexDecode (HexString s) = case safeHexDecode s of+  Just ws -> ws+  Nothing -> error "hexDecode: input is not a hex string"++-- | from [0xAB] to "4142"+hexEncode :: [Word8] -> HexString +hexEncode = hexEncode' False++hexEncode' :: Bool -> [Word8] -> HexString +hexEncode' useCapitalLetters = HexString . concatMap worker where+  worker :: Word8 -> String+  worker w = [ table ! (fromIntegral $ shiftR w 4) , table ! (fromIntegral $ w .&. 15) ]+  table = if useCapitalLetters then capitalHexTable else smallHexTable++showHexWord8 :: Word8 -> String+showHexWord8 w = [ smallHexTable ! (fromIntegral $ shiftR w 4) , smallHexTable ! (fromIntegral $ w .&. 15) ]++capitalHexTable, smallHexTable :: Array Word8 Char+capitalHexTable = listArray (0,15) "0123456789ABCDEF"+smallHexTable   = listArray (0,15) "0123456789abcdef"++--------------------------------------------------------------------------------+
+ Bitcoin/Misc/Monad.hs view
@@ -0,0 +1,30 @@++-- | Monadic helper functions++module Bitcoin.Misc.Monad where++--------------------------------------------------------------------------------++import Control.Monad+import Control.Monad.State++--------------------------------------------------------------------------------++mapAccumM :: Monad m => (a -> b -> m (a, c)) -> a -> [b] -> m (a, [c])+mapAccumM act s0 xs +  = liftM swap +  $ runStateT (mapM (\x -> StateT (\s -> liftM swap $ act s x)) xs) s0 +  where+    swap (x,y) = (y,x)++mapAccumM_ :: Monad m => (a -> b -> m (a, c)) -> a -> [b] -> m [c]+mapAccumM_ act s0 xs = liftM snd (mapAccumM act s0 xs)++flippedMapAccumM :: Monad m => a -> [b] -> (a -> b -> m (a, c)) -> m (a, [c])+flippedMapAccumM s0 xs act = mapAccumM act s0 xs++flippedMapAccumM_ :: Monad m => a -> [b] -> (a -> b -> m (a, c)) -> m [c]+flippedMapAccumM_ s0 xs act = mapAccumM_ act s0 xs++--------------------------------------------------------------------------------+
+ Bitcoin/Misc/OctetStream.hs view
@@ -0,0 +1,81 @@++-- | Conversion between different "octet stream" formats for convenience.+--+-- TODO: utf8 handling for text++{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}+module Bitcoin.Misc.OctetStream where++--------------------------------------------------------------------------------++import Control.Monad ( liftM )++import Data.Char ( ord , chr )+import Data.Word++import qualified Data.ByteString as B++import Bitcoin.Misc.BigInt++--------------------------------------------------------------------------------++class OctetStream a where++  toByteString     :: a -> B.ByteString+  toWord8List      :: a -> [Word8]+  unsafeToCharList :: a -> [Char]+  toIntegerLE      :: a -> Integer+  toIntegerBE      :: a -> Integer++  fromByteString :: B.ByteString -> a+  fromWord8List  :: [Word8] -> a+  fromCharList   :: [Char]  -> a      +  fromIntegerLE  :: Integer -> a+  fromIntegerBE  :: Integer -> a++  toByteString     = B.pack . toWord8List+  toWord8List      = B.unpack . toByteString+  unsafeToCharList = map word8_to_char . toWord8List +  toIntegerLE      = littleEndianRollInteger . toWord8List+  toIntegerBE      = bigEndianRollInteger    . toWord8List   ++  fromByteString = fromWord8List  . B.unpack+  fromWord8List  = fromByteString . B.pack+  fromCharList   = fromWord8List . map char_to_word8+  fromIntegerLE  = fromWord8List . littleEndianUnrollInteger+  fromIntegerBE  = fromWord8List . bigEndianUnrollInteger++--------------------------------------------------------------------------------++instance OctetStream B.ByteString where+  toByteString   = id+  fromByteString = id+  toWord8List    = B.unpack+  fromWord8List  = B.pack+  +instance OctetStream [Word8] where+  toWord8List   = id+  fromWord8List = id+  toByteString   = B.pack+  fromByteString = B.unpack++-- | Note: we treat String as an ASCII string here, no fancy utf8 here (it's in the TODO)+instance OctetStream String where+  unsafeToCharList = id+  fromCharList     = id+  toWord8List      = map char_to_word8+  fromWord8List    = map word8_to_char+  toByteString     = B.pack . map char_to_word8+  fromByteString   = map word8_to_char . B.unpack++--------------------------------------------------------------------------------++{-# INLINE word8_to_char #-}+word8_to_char :: Word8 -> Char+word8_to_char = chr . fromIntegral++{-# INLINE char_to_word8 #-}+char_to_word8 :: Char -> Word8+char_to_word8 = fromIntegral . ord++--------------------------------------------------------------------------------
+ Bitcoin/Misc/Strict.hs view
@@ -0,0 +1,46 @@++-- | Strict version of common data types++{-# LANGUAGE BangPatterns #-}+module Bitcoin.Misc.Strict where++--------------------------------------------------------------------------------+-- * Maybe++data SMaybe a +  = SJust !a +  | SNothing+  deriving (Eq,Ord,Show)++catSMaybes :: [SMaybe a] -> [a]+catSMaybes = go where+  go mbs = case mbs of +    (mb:rest) -> case mb of+      SJust x  -> x : go rest+      SNothing ->     go rest+    [] -> [] ++--------------------------------------------------------------------------------+-- * Either++data SEither a b+  = SLeft  !a+  | SRight !b+  deriving (Eq,Ord,Show)++--------------------------------------------------------------------------------+-- * Tuples++data SPair   a b     = SPair   !a !b        deriving (Eq,Ord,Show)+data STriple a b c   = STriple !a !b !c     deriving (Eq,Ord,Show)+data SQuad   a b c d = SQuad   !a !b !c !d  deriving (Eq,Ord,Show)++--------------------------------------------------------------------------------+-- * List++data SList a +  = SCons !a !(SList a)+  | SNil+  deriving (Eq,Ord,Show)++--------------------------------------------------------------------------------
+ Bitcoin/Misc/Tuple.hs view
@@ -0,0 +1,22 @@++-- | Helper functions for tuples++module Bitcoin.Misc.Tuple where++--------------------------------------------------------------------------------++fst3 :: (a,b,c) -> a+fst3 (x,_,_) = x++snd3 :: (a,b,c) -> b+snd3 (_,y,_) = y++thd3 :: (a,b,c) -> c+thd3 (_,_,z) = z++--------------------------------------------------------------------------------++swap :: (a,b) -> (b,a)+swap (x,y) = (y,x)++--------------------------------------------------------------------------------
+ Bitcoin/Misc/Unique.hs view
@@ -0,0 +1,38 @@++-- | Unique id creation (used for the API calls)++module Bitcoin.Misc.Unique where++--------------------------------------------------------------------------------++import Data.Word++import Control.Concurrent.MVar+import System.IO.Unsafe as Unsafe++--------------------------------------------------------------------------------++theGlobalUniqueSupport :: MVar Word64+theGlobalUniqueSupport = Unsafe.unsafePerformIO (newMVar 1000000000)++theGlobalSink :: MVar a+theGlobalSink = Unsafe.unsafePerformIO (newMVar undefined)++--------------------------------------------------------------------------------++newUnique :: IO Word64+newUnique = do+  n <- takeMVar theGlobalUniqueSupport+  putMVar theGlobalUniqueSupport (n+1)+  return n++-- | We convert a \"sacrifice\" to a unique id. This is a hack, but+-- sacrificing a value prevents let-floating, also it somehow makes sense :)+convertToUnique :: a -> Word64+convertToUnique sacrifice = Unsafe.unsafePerformIO $ do+  _ <- takeMVar theGlobalSink+  n <- newUnique+  putMVar theGlobalSink (sacrifice,n)+  return n++--------------------------------------------------------------------------------
+ Bitcoin/Misc/UnixTime.hs view
@@ -0,0 +1,33 @@++-- | Dealing with Unix timestamps++{-# LANGUAGE PackageImports #-}+module Bitcoin.Misc.UnixTime where++--------------------------------------------------------------------------------++import Data.Word++import "time" Data.Time+import "time" Data.Time.Clock.POSIX++-- import "old-locale" System.Locale++--------------------------------------------------------------------------------++newtype UnixTimeStamp = UnixTimeStamp { fromUnixTimeStamp :: Word32 } deriving (Eq,Ord)++instance Show UnixTimeStamp where +  show ts = "UnixTimeStamp<" ++ isoDateStr ts ++ ">" ++unixTimeStampToUTC :: UnixTimeStamp -> UTCTime+unixTimeStampToUTC (UnixTimeStamp unixstamp) = utctime where+  ndifftime = fromIntegral unixstamp :: POSIXTime   -- type POSIXTime = NominalDiffTime+  utctime   = posixSecondsToUTCTime ndifftime++isoDateStr :: UnixTimeStamp -> String+isoDateStr unixstamp = formatTime locale "%Y-%m-%d %H:%M:%S" utctime where+  utctime = unixTimeStampToUTC unixstamp+  locale  = defaultTimeLocale++--------------------------------------------------------------------------------
+ Bitcoin/Misc/Zipper.hs view
@@ -0,0 +1,55 @@++-- | Simple zipper data structure++module Bitcoin.Misc.Zipper where++--------------------------------------------------------------------------------++import Data.Maybe+import Control.Monad ( liftM )++--------------------------------------------------------------------------------++-- | A linear zipper, where the focus can be optionally after the last element (but not before the first element).+-- That is, the focus is the first element (if exists) of the second list.+data Zipper a = Zipper [a] [a] deriving Show++--------------------------------------------------------------------------------++focus :: Zipper a -> Maybe a+focus (Zipper ys xs) = case xs of+  (x:_) -> Just x+  _     -> Nothing++moveRight_ :: Zipper a -> Maybe (Zipper a)+moveRight_ = liftM snd . moveRight++-- | returns the focus /before/ moving right+moveRight :: Zipper a -> Maybe (a, Zipper a)+moveRight (Zipper ys xs) = case xs of+  (x:zs) -> Just (x , Zipper (x:ys) zs)+  _      -> Nothing++moveLeft_ :: Zipper a -> Maybe (Zipper a)+moveLeft_ = liftM snd . moveLeft++-- | returns the focus /after/ moving left+moveLeft :: Zipper a -> Maybe (a, Zipper a)+moveLeft (Zipper ys xs) = case ys of+  (y:zs) -> Just (y , Zipper xs (y:xs))+  _      -> Nothing++zipperFromList :: [a] -> Zipper a+zipperFromList xs = Zipper [] xs++zipperToList :: Zipper a -> [a]+zipperToList (Zipper ys xs) = reverse ys ++ xs++mkZipper :: [a] -> [a] -> Zipper a+mkZipper left right = Zipper (reverse left) right++-- | Head of the second list is the focus (if it is not empty)+zipperView :: Zipper a -> ([a],[a])+zipperView (Zipper ys xs) = (reverse ys, xs)++--------------------------------------------------------------------------------
+ Bitcoin/Protocol.hs view
@@ -0,0 +1,40 @@++-- | This module re-exports all the @Bitcoin.Protocol.*@ submodules, +-- and also @Bitcoin.BlockChain.Base@, @Bitcoin.BlockChain.Tx@, and+-- @Bitcoin.Script.Base@.++module Bitcoin.Protocol +  ( module Bitcoin.Protocol.Address+  , module Bitcoin.Protocol.Amount+  , module Bitcoin.Protocol.Base58+  , module Bitcoin.Protocol.Base64+  , module Bitcoin.Protocol.Difficulty+  , module Bitcoin.Protocol.Hash+  , module Bitcoin.Protocol.Key+  , module Bitcoin.Protocol.MerkleTree+  , module Bitcoin.Protocol.Signature+  --+  , module Bitcoin.BlockChain.Base+  , module Bitcoin.BlockChain.Tx+  , module Bitcoin.Script.Base+  )+  where++--------------------------------------------------------------------------------++import Bitcoin.Protocol.Address+import Bitcoin.Protocol.Amount+import Bitcoin.Protocol.Base58+import Bitcoin.Protocol.Base64+import Bitcoin.Protocol.Difficulty+import Bitcoin.Protocol.Hash+import Bitcoin.Protocol.Key+import Bitcoin.Protocol.MerkleTree+import Bitcoin.Protocol.Signature++import Bitcoin.BlockChain.Base+import Bitcoin.BlockChain.Tx+import Bitcoin.Script.Base++--------------------------------------------------------------------------------+
+ Bitcoin/Protocol/Address.hs view
@@ -0,0 +1,75 @@++-- | Bitcoin addresses++{-# LANGUAGE CPP #-}+module Bitcoin.Protocol.Address+  (+  -- * addresses+    Address(..)+  , PubKeyHash(..)+  , pubKeyAddress+  , pubKeyHash+  , bitcoinAddressDecode+  , bitcoinAddressEncode, bitcoinAddressEncodeHash++  -- * version bytes+  , VersionByte(..)+  , bitcoinPubkeyHashVB  +  , bitcoinScriptHashVB  +  , namecoinPubkeyHashVB +  , privateKeyVB          +  , bitcoinTestNetPubkeyHashVB +  , bitcoinTextNetScriptHashVB ++  )+  where++--------------------------------------------------------------------------------++import qualified Data.ByteString as B++import Bitcoin.Misc.OctetStream++-- import Bitcoin.Crypto.EC.Curve++import Bitcoin.Script.Base++import Bitcoin.Protocol.Hash+import Bitcoin.Protocol.Base58+import Bitcoin.Protocol.Key++--------------------------------------------------------------------------------++-- | A bitcoin address+newtype Address = Address { unAddress :: String } deriving (Eq,Show)++--------------------------------------------------------------------------------++-- | Computes the address of a public key. +--+-- NOTE: compressed and uncompressed versions of the same public key result in+-- different addresses!+pubKeyAddress :: PubKey -> Address+pubKeyAddress pubkey = Address $ unBase58Check $ base58CheckEncode vb (doHash160 $ encodePubKeyNative pubkey) where+#ifdef WITH_TESTNET+  vb = (VersionByte 111) +#else+  vb = (VersionByte 0) +#endif++--------------------------------------------------------------------------------++bitcoinAddressDecode :: Address -> Maybe (VersionByte,PubKeyHash)+bitcoinAddressDecode (Address addr) = case base58CheckDecode (Base58Check addr) of+  Left  _            -> Nothing+  Right (vb,hash160) -> Just (vb, PubKeyHash hash160)++-- | The second argument can be either a script or an encoded public key+bitcoinAddressEncode :: OctetStream a => VersionByte -> a -> Address+bitcoinAddressEncode vb rawscript = Address $ unBase58Check $ base58CheckEncode vb (doHash160 $ rawscript)++bitcoinAddressEncodeHash :: VersionByte -> Hash160 -> Address+bitcoinAddressEncodeHash vb hash160 = Address $ unBase58Check $ base58CheckEncode vb hash160++--------------------------------------------------------------------------------+
+ Bitcoin/Protocol/Amount.hs view
@@ -0,0 +1,137 @@++-- | Amounts of BTC++module Bitcoin.Protocol.Amount +  ( +    Amount(..)+  -- * human-friendly definitions of amounts+  , btc , mbtc , ubtc , satoshi+  -- * constants  +  , amountMultiplier , amountExponent+  -- * conversion+  , integerAmount, doubleAmount+  , amountFromDouble+  , showAmount , parseAmount  +  ) where++--------------------------------------------------------------------------------++import Data.Word+import Data.List ( findIndex )+import Data.Maybe ++import Text.Show+import Text.Read+++--------------------------------------------------------------------------------++-- | A (nonnegative) amount of bitcoins.+--+-- Note: the Show/Read instances look like +-- +-- > newtype Amount = BTC Double+--+-- eg. @BTC 1.3@+--+-- However, the internal representation is different.+newtype Amount = Amount { unAmount :: Word64 } deriving (Eq,Ord)++--------------------------------------------------------------------------------++instance Show Amount where+  showsPrec d amt = showParen (d>10) $ showString "BTC " . showString (showAmount amt)++instance Read Amount where+  readsPrec d r = readParen (d > 10) +    (\r -> [ (fromJust mbAmt,t) +           | ("BTC",s) <- lex r+           , (m,t) <- lex s -- readsPrec 11 s+           , let mbAmt = parseAmount m+           , isJust mbAmt+           ]) r+  +--------------------------------------------------------------------------------+-- * constants++-- | @10^amountExponent == 10^8@+amountMultiplier :: Num a => a+amountMultiplier = 100000000       ++-- | The exponent is 8, as @10^(-8)@ is the smallest unit.+amountExponent :: Int+amountExponent = 8++--------------------------------------------------------------------------------+-- * easy amounts++-- | Whole BTCs+btc :: Double -> Amount+btc = amountFromDouble++-- | milli-BTCs+mbtc :: Double -> Amount+mbtc n = amountFromDouble (n/1000)++-- | micro-BTCs+ubtc :: Double -> Amount+ubtc n = amountFromDouble (n/1000000)++-- | \"satoshi\" is the smallest unit: 1 satoshi = 10\^(-8) BTC+satoshi :: Int -> Amount+satoshi n = Amount $ fromIntegral $ n++--------------------------------------------------------------------------------+-- * conversion++-- | The amount measured in smallest units (satoshis)+integerAmount :: Amount -> Integer+integerAmount (Amount n) = fromIntegral n++-- | The amount in BTCs as a "Double"+doubleAmount :: Amount -> Double+doubleAmount (Amount n) = fromIntegral n / amountMultiplier++-- | Convert whole BTCs to an Amount. Rounding to whole satoshis.+amountFromDouble :: Double -> Amount+amountFromDouble d = Amount $ round (d*amountMultiplier)++-- | Shows an amount in BTCs using the minimum necessary digits+showAmount :: Amount -> String+showAmount (Amount n) = show a ++ if (b==0) then "" else ("." ++ fr) where+  (a,b) = divMod n amountMultiplier+  fr = reverse $ dropWhile (=='0') $ reverse $ extend $ show b+  extend s = (replicate (amountExponent-k) '0' ++ s) where k = length s++-- | Note: unlike doubleAmount, this ignores all digits after the 8th decimal.+parseAmount :: String -> Maybe Amount+parseAmount s = +  case splitDecimalPoint s of+    [s]    -> case maybeReadWord64 s of+                Just n -> Just (Amount (n*amountMultiplier))+                _      -> Nothing+    [s,""] -> case maybeReadWord64 s of+                Just n -> Just (Amount (n*amountMultiplier))+                _      -> Nothing+    [s,t]  -> case (maybeReadWord64 s, maybeReadWord64 t) of+                (Just a, Just _) -> Just (Amount (a*amountMultiplier + b)) where +                                      b = read +                                        $ take amountExponent +                                        $ (t ++ replicate amountExponent '0')+                _                -> Nothing+    _ -> Nothing++--------------------------------------------------------------------------------+-- * helpers++maybeReadWord64 :: String -> Maybe Word64+maybeReadWord64 s = case reads s of+  [(w,"")] -> Just w+  _        -> Nothing++splitDecimalPoint :: String -> [String]+splitDecimalPoint s = case findIndex (=='.') s of+  Nothing -> [s]+  Just i  -> [take i s , drop (i+1) s]++--------------------------------------------------------------------------------
+ Bitcoin/Protocol/Base58.hs view
@@ -0,0 +1,146 @@++-- | Bitcoin-specific Base58 encoding, and related stuff ++module Bitcoin.Protocol.Base58 +  ( +  -- * base58 encoding+    Base58(..)+  , base58Decode, base58Encode+  , base58EncodeInteger , base58DecodeInteger++  -- * base58-check encoding+  , Base58Check(..) +  , base58CheckDecode, base58CheckEncode++  -- * version bytes+  , VersionByte(..)+  , bitcoinPubkeyHashVB  +  , bitcoinScriptHashVB  +  , namecoinPubkeyHashVB +  , privateKeyVB          +  , bitcoinTestNetPubkeyHashVB +  , bitcoinTextNetScriptHashVB ++  )+  where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits+import Data.List ( unfoldr )++import Data.Array.IArray+import Data.Array.Unboxed++import qualified Data.Map as Map+import Data.Map (Map)++import qualified Data.ByteString as B++import Bitcoin.Misc.BigInt+import Bitcoin.Misc.HexString ( toHexStringChars ) +import Bitcoin.Misc.OctetStream+import Bitcoin.Protocol.Hash++import Bitcoin.Script.Base++--------------------------------------------------------------------------------++alphabet :: UArray Int Char+alphabet = array (0,57) $ zip [0..57] stringAlphabet ++reverseAlphabet :: Map Char Int+reverseAlphabet = Map.fromList $ zip stringAlphabet [0..57]++stringAlphabet :: [Char]+stringAlphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"+--               "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"++--------------------------------------------------------------------------------+-- * base-58 encoding++-- | A raw base58 encoded octet stream (not base58-check!)+newtype Base58 = Base58 { unBase58 :: String } deriving (Eq,Show)++-- | Simple Base-58 encoding, without the leading \'1\'-s+base58Encode :: OctetStream a => a -> Base58+base58Encode = Base58 . base58EncodeInteger . toIntegerBE++-- | WARNING: @(base58Decode . base58Encode)@ is /NOT/ identity, because of the leading zero bytes.+base58Decode :: OctetStream a => Base58 -> Maybe a+base58Decode (Base58 input) = case base58DecodeInteger input of +  Just n  -> Just $ fromIntegerBE n   -- fromWord8List $ bigEndianUnrollInteger n+  Nothing -> Nothing ++-- | Without leading \'1\'-s+base58EncodeInteger :: Integer -> String+base58EncodeInteger bigint = dropWhile (=='1') $ reverse $ go bigint where+  go n = case k of { 0 -> [lkp r] ; _ -> lkp r : go k } where (k,r) = divMod n 58+  lkp :: Integer -> Char+  lkp k | k>=0 && k<58 = alphabet ! (fromIntegral k)+        | otherwise    = error "base58Encode: shouldn't happen"++base58DecodeInteger :: String -> Maybe Integer+base58DecodeInteger input = +  if and (map checkChar input) +    then Just (decode 0 input) +    else Nothing+  where+    checkChar x = Map.member x reverseAlphabet+    decode acc [] = acc+    decode acc (x:xs) = case Map.lookup x reverseAlphabet of+      Just i  -> decode (acc*58 + fromIntegral i) xs+      Nothing -> error "base58DecodeInteger: shouldn't happen"++--------------------------------------------------------------------------------+-- * base-58-check encoding++-- | A base58-check encoded octet stream+newtype Base58Check = Base58Check { unBase58Check :: String } deriving (Eq,Show)++-- | Base58Check encoding+-- <https://en.bitcoin.it/wiki/Base58Check_encoding>+base58CheckEncode :: OctetStream a => VersionByte -> a -> Base58Check+base58CheckEncode vb payload = Base58Check step5 where+  step1  = B.cons (fromVersionByte vb) $ toByteString payload+  step2  = B.take 4 (toByteString $ doHash256 step1)+  step3  = B.append step1 step2+  step4  = base58Encode step3 +  nzeros = B.length $ B.takeWhile (==0) $ step3+  step5  = replicate nzeros '1' ++ unBase58 step4++base58CheckDecode :: OctetStream a => Base58Check -> Either String (VersionByte,a)+base58CheckDecode (Base58Check input) = +  case base58Decode (Base58 input) of+    Nothing -> Left "input is not valid Base58-encoded data"+    Just bs -> eiresult where+      k = B.length bs+      (stuff0,checksum) = B.splitAt (k-4) bs+      stuff = B.append (B.pack $ replicate nzeros 0) stuff0+      fullhash = toByteString $ doHash256 $ stuff     +      inithash = B.take 4 fullhash+      eiresult = if inithash /= checksum +        then let aa = toHexStringChars $ inithash+                 bb = toHexStringChars $ checksum+             in  Left ("checksum mismatch: " ++ aa ++ " vs. " ++ bb) +        else Right (VersionByte vb , fromByteString orig)+      vb   = B.head stuff+      orig = B.tail stuff+  where+    nzeros = length (takeWhile (=='1') input)+++--------------------------------------------------------------------------------+-- * version bytes++newtype VersionByte = VersionByte { fromVersionByte :: Word8 } deriving (Eq,Show)++bitcoinPubkeyHashVB  = VersionByte 0 +bitcoinScriptHashVB  = VersionByte 5+namecoinPubkeyHashVB = VersionByte 52 +privateKeyVB         = VersionByte 128+bitcoinTestNetPubkeyHashVB = VersionByte 111+bitcoinTextNetScriptHashVB = VersionByte 196++--------------------------------------------------------------------------------
+ Bitcoin/Protocol/Base64.hs view
@@ -0,0 +1,122 @@++-- | Base64 encoding/decoding (used for signatures for example)++module Bitcoin.Protocol.Base64 +  ( Base64(..) +  , base64Encode, base64Decode+  , testCases , testErrors+  ) where++--------------------------------------------------------------------------------++import Control.Monad ( liftM )++import Data.Char ( isSpace )+import Data.Word+import Data.Bits+import Data.List ( unfoldr )+import Data.Maybe++import Data.Array.IArray+import Data.Array.Unboxed++import qualified Data.Map as Map+import Data.Map (Map)++import qualified Data.ByteString as B++import Bitcoin.Misc.OctetStream++--------------------------------------------------------------------------------++alphabet :: UArray Word8 Char+alphabet = array (0,63) $ zip [0..63] stringAlphabet ++reverseAlphabet :: Map Char Word8+reverseAlphabet = Map.fromList $ zip stringAlphabet [0..63]++stringAlphabet :: [Char]+stringAlphabet = ['A'..'Z'] ++ ['a'..'z'] ++ "0123456789+/"++--------------------------------------------------------------------------------++newtype Base64 = Base64 { unBase64 :: String } deriving (Eq,Show)++base64Encode :: OctetStream a => a -> Base64+base64Encode = Base64 . concatMap worker . partition . toWord8List where+  worker [a,b,c] = map lkp [ shiftR a 2 +                           , shiftL (a .&. 3)  4 + shiftR b 4+                           , shiftL (b .&. 15) 2 + shiftR c 6 +                           , c .&. 63 +                           ] +  worker [a,b  ] = take 3 (worker [a,b,0]) ++ "="+  worker [a    ] = take 2 (worker [a,0,0]) ++ "=="++  lkp :: Word8 -> Char+  lkp j = alphabet ! j++  -- partition into three-byte units+  partition :: [Word8] -> [[Word8]]+  partition [] = []+  partition xs = take 3 xs : partition (drop 3 xs)++--------------------------------------------------------------------------------+  +base64Decode :: OctetStream a => Base64 -> Maybe a+base64Decode = liftM fromByteString . returnMaybe . map worker . partition . filter (not . isSpace) . unBase64 where++  worker :: [Char] -> Maybe [Word8]+  worker abcd = case abcd of+    [a,b,'=','='] -> liftMaybe (take 1) $ worker [a,b,'A','A']+    [a,b,c,'=']   -> liftMaybe (take 2) $ worker [a,b,c,'A']+    [a,b,c,d]     -> if all isJust mws then Just [p,q,r] else Nothing where+      mws = map lkp abcd+      [u,v,w,z] = map fromJust mws+      p = shiftL  u         2 + shiftR v 4+      q = shiftL (v .&. 15) 4 + shiftR w 2+      r = shiftL (w .&.  3) 6 + z+    _ -> Nothing+  +  returnMaybe :: [Maybe [Word8]] -> Maybe B.ByteString+  returnMaybe mws = if all isJust mws +    then Just $ B.pack $ concatMap fromJust mws+    else Nothing+    +  lkp :: Char -> Maybe Word8 +  lkp c = Map.lookup c reverseAlphabet++  -- partition into four-byte units+  partition :: [Char] -> [[Char]]+  partition [] = []+  partition xs = take 4 xs : partition (drop 4 xs)++  liftMaybe :: ([Word8] -> [Word8]) -> (Maybe [Word8] -> Maybe [Word8])+  liftMaybe f mb = case mb of { Just xs -> Just (f xs) ; Nothing -> Nothing }+  +--------------------------------------------------------------------------------++testErrors :: [String]+testErrors = testErrorsEncode ++ testErrorsDecode++testErrorsEncode :: [String]+testErrorsEncode = concatMap (\(raw,base64) -> if (Base64 base64 == base64Encode raw) then [] else [raw]) testCases++testErrorsDecode :: [String]+testErrorsDecode = concatMap (\(raw,base64) -> if (Just raw == base64Decode (Base64 base64)) then [] else [raw]) testCases++testCases :: [(String,String)]+testCases =+  [ ("any carnal pleasure.", "YW55IGNhcm5hbCBwbGVhc3VyZS4=" )+  , ("any carnal pleasure" , "YW55IGNhcm5hbCBwbGVhc3VyZQ==" )+  , ("any carnal pleasur"  , "YW55IGNhcm5hbCBwbGVhc3Vy" )+  , ("any carnal pleasu"   , "YW55IGNhcm5hbCBwbGVhc3U=" )+  , ("any carnal pleas"    , "YW55IGNhcm5hbCBwbGVhcw==" )+  , ("pleasure."     , "cGxlYXN1cmUu" )+  , ("leasure."      , "bGVhc3VyZS4=" )+  , ("easure."       , "ZWFzdXJlLg==" )+  , ("asure."        , "YXN1cmUu" )+  , ("sure."         , "c3VyZS4=" )+  ]+  +--------------------------------------------------------------------------------+  
+ Bitcoin/Protocol/Difficulty.hs view
@@ -0,0 +1,48 @@++-- | Difficulty computation. See <https://en.bitcoin.it/wiki/Difficulty>++module Bitcoin.Protocol.Difficulty where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits++import Bitcoin.Misc.BigInt+import Bitcoin.Misc.OctetStream+import Bitcoin.Protocol.Hash++--------------------------------------------------------------------------------++-- | Computes the target from the packed difficulty representation+difficultyTarget :: Word32 -> Hash256+difficultyTarget hexdifficulty = fromWord8List (littleEndianInteger32 target) where+  msb  = fromIntegral (shiftR hexdifficulty 24)      :: Int+  base = fromIntegral (hexdifficulty .&. 0x00ffffff) :: Integer+  exponent = 8 * (msb - 3)+  target = base * 2 ^ exponent++-- | The highest (easiest) target+maximalTarget :: Hash256+maximalTarget = difficultyTarget 0x1d00ffff++-- | Computes the decimal difficulty from the packed representation+decimalDifficulty :: Word32 -> Double+decimalDifficulty = targetDecimalDifficulty . difficultyTarget++{-+decimalDifficulty :: Word32 -> Double+decimalDifficulty hexdifficulty = fromRational ratio where+  ratio = toRational (toIntegerLE maximalTarget) +        / toRational (toIntegerLE currentTarget)+  currentTarget = difficultyTarget hexdifficulty+-}++-- | Computes the decimal difficulty from a target+targetDecimalDifficulty :: Hash256 -> Double+targetDecimalDifficulty currentTarget = fromRational ratio where+  ratio = toRational (toIntegerLE maximalTarget) +        / toRational (toIntegerLE currentTarget)+++--------------------------------------------------------------------------------
+ Bitcoin/Protocol/Hash.hs view
@@ -0,0 +1,326 @@++{-# LANGUAGE CPP #-}+module Bitcoin.Protocol.Hash where++--------------------------------------------------------------------------------++import Data.Word+import Data.Maybe ++import Text.Show+import Text.Read++import qualified Data.ByteString as B+import qualified Data.ByteString.Internal as BI++import Foreign+import Foreign.ForeignPtr+import Foreign.Marshal+import Foreign.Storable+import System.IO.Unsafe as Unsafe++import Bitcoin.Misc.BigInt+import Bitcoin.Misc.HexString+import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.Endian++import Bitcoin.Crypto.Hash.SHA256+import Bitcoin.Crypto.Hash.RipEmd160++#ifdef __GLASGOW_HASKELL__+import GHC.ForeignPtr ( mallocPlainForeignPtrBytes )+#endif++import Debug.Trace++--------------------------------------------------------------------------------++{- ForeignPtr version++-- | Hash160(x) = RipEmd160(SHA256(x))+--+-- Note: the Show and Ord instances treat them as big-endian integers!+--+-- We use a ForeignPtr instead of a ByteString as it is 2 (or even 3?) words smaller.+newtype Hash160 = Hash160 { unHash160 :: ForeignPtr Word8 } ++-- | Hash256(x) = SHA256(SHA256(x))+-- +-- Note: the Show and Ord instances treat them as big-endian integers!+--+-- We use a ForeignPtr instead of a ByteString as it is 2 (or even 3?) words smaller.+newtype Hash256 = Hash256 { unHash256 :: ForeignPtr Word8 } ++-}++--------------------------------------------------------------------------------++-- | Hash160(x) = RipEmd160(SHA256(x))+--+-- Note: the Show and Ord instances treat them as /big-endian/ integers!+--+-- It seems that the most compact representation is unpacked machine words +-- ('ForeignPtr' has too much overhead even with 'mallocPlainForeignPtr').+--+-- In memory representation: @Hash160 w1 w2 w3@ means that the w1 represent the+-- first 8 bytes, in little-endian representation, then w2 the second 8 bytes,+-- finally w3 the last 4 bytes. This way, the /big-endian/ comparison can be+-- done fast (first compare @w3@, if equal compare @w2@, if that is also equal compare @w1@)+data Hash160 = Hash160 +       {-# UNPACK #-} !Word64+       {-# UNPACK #-} !Word64+       {-# UNPACK #-} !Word32++-- | Hash256(x) = SHA256(SHA256(x))+-- +-- Note: the Show and Ord instances treat them as /big-endian/ integers!+--+-- It seems that the most compact representation is unpacked machine words +-- ('ForeignPtr' has too much overhead even with 'mallocPlainForeignPtr').+--+data Hash256 = Hash256+       {-# UNPACK #-} !Word64+       {-# UNPACK #-} !Word64+       {-# UNPACK #-} !Word64+       {-# UNPACK #-} !Word64++--------------------------------------------------------------------------------++{- ForeignPtr +instance Eq Hash160 where a == b = (toWord8List a) == (toWord8List b)+instance Eq Hash256 where a == b = (toWord8List a) == (toWord8List b)+-}++{- ordering is big-endian!+instance Ord Hash160 where compare a b = compare (reverse $ toWord8List a) (reverse $ toWord8List b)+instance Ord Hash256 where compare a b = compare (reverse $ toWord8List a) (reverse $ toWord8List b)+-}++instance Eq Hash160 where (Hash160 a1 a2 a3   ) == (Hash160 b1 b2 b3   )  =  a1==b1 && a2==b2 && a3==b3+instance Eq Hash256 where (Hash256 a1 a2 a3 a4) == (Hash256 b1 b2 b3 b4)  =  a1==b1 && a2==b2 && a3==b3 && a4==b4++instance Ord Hash160 where +  compare (Hash160 a1 a2 a3) (Hash160 b1 b2 b3) = compare (a3,a2,a1) (b3,b2,b1)++instance Ord Hash256 where +  compare (Hash256 a1 a2 a3 a4) (Hash256 b1 b2 b3 b4) = compare (a4,a3,a2,a1) (b4,b3,b2,b1)++--------------------------------------------------------------------------------++instance Show Hash160 where+  showsPrec d h = showParen (d > 10) $+    showString "hash160FromTextBE " . showChar '"' . showString (toHexStringChars (B.reverse $ toByteString h)) . showChar '"'++instance Show Hash256 where+  showsPrec d h = showParen (d > 10) $+    showString "hash256FromTextBE " . showChar '"' . showString (toHexStringChars (B.reverse $ toByteString h)) . showChar '"'++instance Read Hash160 where+  readsPrec d r = readParen (d > 10) +    (\r -> [ (fromWord8List (reverse $ fromJust mws) , t) +           | ("hash160FromTextBE",s) <- lex r+           , (m,t) <- readsPrec 11 s+           , length m == 40 +           , let mws = safeHexDecode m+           , isJust mws+           ]) r++instance Read Hash256 where+  readsPrec d r = readParen (d > 10) +    (\r -> [ (fromWord8List (reverse $ fromJust mws) , t) +           | ("hash256FromTextBE",s) <- lex r+           , (m,t) <- readsPrec 11 s +           , length m == 64 +           , let mws = safeHexDecode m+           , isJust mws+           ]) r++--------------------------------------------------------------------------------++partitionList20 :: [Word8] -> ( [Word8] , [Word8] , [Word8] )+partitionList20 ws = (a,b,c) where+  (a,tmp1) = splitAt 8 ws+  (b,c   ) = splitAt 8 tmp1++partitionList32 :: [Word8] -> ( [Word8] , [Word8] , [Word8] , [Word8] )+partitionList32 ws = (a,b,c,d) where+  (a,tmp1) = splitAt 8 ws+  (b,tmp2) = splitAt 8 tmp1+  (c,d   ) = splitAt 8 tmp2+  +--------------------------------------------------------------------------------++instance OctetStream Hash160 where+  toWord8List (Hash160 w1 w2 w3) = toLilEndBytes w1 ++ toLilEndBytes w2 ++ toLilEndBytes w3+ +  fromWord8List ws = case length ws of+    20 -> Hash160 w1 w2 w3 where+            w1 = fromLilEndBytes xs1+            w2 = fromLilEndBytes xs2+            w3 = fromLilEndBytes xs3+            (xs1,xs2,xs3) = partitionList20 ws+    _ -> error "Hash160/fromWord8List: Hash160 is expected to be 20 bytes"++  toByteString (Hash160 w1 w2 w3) = do+          Unsafe.unsafePerformIO $ BI.create 20 $ \ptr -> do+            poke (castPtr  ptr               :: Ptr Word64) $ swapByteOrderToLE w1 +            poke (castPtr (ptr `plusPtr`  8) :: Ptr Word64) $ swapByteOrderToLE w2 +            poke (castPtr (ptr `plusPtr` 16) :: Ptr Word32) $ swapByteOrderToLE w3+                                    +  fromByteString bs = case B.length bs of+    20 -> Unsafe.unsafePerformIO $ B.useAsCString bs $ \src -> do+            w1 <- peek (castPtr  src               :: Ptr Word64)+            w2 <- peek (castPtr (src `plusPtr`  8) :: Ptr Word64)+            w3 <- peek (castPtr (src `plusPtr` 16) :: Ptr Word32)+            return $ Hash160 (swapByteOrderToLE w1) +                             (swapByteOrderToLE w2) +                             (swapByteOrderToLE w3)+    _  -> error "Hash160/fromByteString: Hash160 is expected to be 20 bytes"++  fromIntegerLE = fromWord8List . littleEndianInteger20+  fromIntegerBE = fromWord8List . bigEndianInteger20++----------------------------------------++instance OctetStream Hash256 where+  toWord8List (Hash256 w1 w2 w3 w4) = toLilEndBytes w1 ++ toLilEndBytes w2 ++ toLilEndBytes w3 ++ toLilEndBytes w4+ +  fromWord8List ws = case length ws of+    32 -> Hash256 w1 w2 w3 w4 where+            w1 = fromLilEndBytes xs1+            w2 = fromLilEndBytes xs2+            w3 = fromLilEndBytes xs3+            w4 = fromLilEndBytes xs4+            (xs1,xs2,xs3,xs4) = partitionList32 ws+    _ -> error "Hash256/fromWord8List: Hash256 is expected to be 32 bytes"++  toByteString (Hash256 w1 w2 w3 w4) = do+          Unsafe.unsafePerformIO $ BI.create 32 $ \ptr -> do+            poke (castPtr  ptr               :: Ptr Word64) $ swapByteOrderToLE w1 +            poke (castPtr (ptr `plusPtr`  8) :: Ptr Word64) $ swapByteOrderToLE w2 +            poke (castPtr (ptr `plusPtr` 16) :: Ptr Word64) $ swapByteOrderToLE w3+            poke (castPtr (ptr `plusPtr` 24) :: Ptr Word64) $ swapByteOrderToLE w4+                                    +  fromByteString bs = case B.length bs of+    32 -> Unsafe.unsafePerformIO $ B.useAsCString bs $ \src -> do+            w1 <- peek (castPtr  src               :: Ptr Word64)+            w2 <- peek (castPtr (src `plusPtr`  8) :: Ptr Word64)+            w3 <- peek (castPtr (src `plusPtr` 16) :: Ptr Word64)+            w4 <- peek (castPtr (src `plusPtr` 24) :: Ptr Word64)+            return $ Hash256 (swapByteOrderToLE w1) +                             (swapByteOrderToLE w2)+                             (swapByteOrderToLE w3) +                             (swapByteOrderToLE w4)+    _  -> error "Hash256/fromByteString: Hash256 is expected to be 32 bytes"++  fromIntegerLE = fromWord8List . littleEndianInteger32+  fromIntegerBE = fromWord8List . bigEndianInteger32++--------------------------------------------------------------------------------++{- ForeignPtr version++instance OctetStream Hash160 where+  toWord8List (Hash160 fptr) = Unsafe.unsafePerformIO $ withForeignPtr fptr $ \ptr -> peekArray 20 ptr +  fromWord8List ws = case length ws of+    20 -> Unsafe.unsafePerformIO $ do +#ifdef __GLASGOW_HASKELL__+            fptr <- mallocPlainForeignPtrBytes 20 +#else+            fptr <- mallocForeignPtrBytes 20 +#endif+            withForeignPtr fptr $ \ptr -> pokeArray ptr ws +            return (Hash160 fptr) +    _ -> error "Hash160/fromWord8List: Hash160 is expected to by 20 bytes"++  toByteString (Hash160 fptr) = Unsafe.unsafePerformIO $ withForeignPtr fptr $ \ptr -> B.packCStringLen (castPtr ptr, 20)+  fromByteString bs = case B.length bs of+    20 -> Unsafe.unsafePerformIO $ B.useAsCString bs $ \src -> do+#ifdef __GLASGOW_HASKELL__+            fptr <- mallocPlainForeignPtrBytes 20 +#else+            fptr <- mallocForeignPtrBytes 20 +#endif+            withForeignPtr fptr $ \tgt -> copyBytes tgt (castPtr src) 20+            return (Hash160 fptr) +    _  -> error "Hash160/fromByteString: Hash160 is expected to by 20 bytes"++  fromIntegerLE = fromWord8List . littleEndianInteger20+  fromIntegerBE = fromWord8List . bigEndianInteger20++----------------------------------------++instance OctetStream Hash256 where+  toWord8List (Hash256 fptr) = Unsafe.unsafePerformIO $ withForeignPtr fptr $ \ptr -> peekArray 32 ptr +  fromWord8List ws = case length ws of+    32 -> Unsafe.unsafePerformIO $ do +#ifdef __GLASGOW_HASKELL__+            fptr <- mallocPlainForeignPtrBytes 32+#else+            fptr <- mallocForeignPtrBytes 32+#endif+            withForeignPtr fptr $ \ptr -> pokeArray ptr ws +            return (Hash256 fptr) +    _ -> error "Hash256/fromWord8List: Hash256 is expected to by 32 bytes"++  toByteString (Hash256 fptr) = Unsafe.unsafePerformIO $ withForeignPtr fptr $ \ptr -> B.packCStringLen (castPtr ptr, 32)+  fromByteString bs = case B.length bs of+    32 -> Unsafe.unsafePerformIO $ B.useAsCString bs $ \src -> do+#ifdef __GLASGOW_HASKELL__+            fptr <- mallocPlainForeignPtrBytes 32+#else+            fptr <- mallocForeignPtrBytes 32+#endif+            withForeignPtr fptr $ \tgt -> copyBytes tgt (castPtr src) 32+            return (Hash256 fptr) ++  fromIntegerLE = fromWord8List . littleEndianInteger32+  fromIntegerBE = fromWord8List . bigEndianInteger32++-}+++--------------------------------------------------------------------------------++debugDoHash256 :: OctetStream a => a -> Hash256+debugDoHash256 x = Debug.Trace.trace (">>> " ++ toHexStringChars x ++ " <<<") $ doHash256 x++-- | SHA256(SHA256(x))+doHash256 :: OctetStream a => a -> Hash256+doHash256 = fromByteString . unSHA256 . sha256 . sha256 ++-- | RIPEMD160(SHA256(x))+doHash160 :: OctetStream a => a -> Hash160+doHash160 = fromByteString . unRipEmd160 . ripemd160 . sha256 ++--------------------------------------------------------------------------------++-- | The zero ripemd hash (not really used for anything)+zeroHash160 :: Hash160+zeroHash160 = fromWord8List (replicate 20 0)++-- | Generation (or \"coinbase\") transactions have hash set to zero+zeroHash256 :: Hash256+zeroHash256 = fromWord8List (replicate 32 0)++--------------------------------------------------------------------------------++-- | Creates a 256 bit hash from a /big-endian/ hex string (may fail with exception).+-- This is here primarily for convenience.+hash256FromTextBE :: String -> Hash256+hash256FromTextBE s +  | length s == 64  = case safeHexDecode s of+                        Just ws -> fromWord8List $ reverse ws+                        Nothing -> error "hash256FromText: not a hex string"+  | otherwise       = error "hash256FromTextBE: length should be 64 characters"++-- | Creates a 160 bit hash from a /big-endian/ hex string (may fail with exception).+-- This is here primarily for convenience.+hash160FromTextBE :: String -> Hash160+hash160FromTextBE s +  | length s == 40  = case safeHexDecode s of+                        Just ws -> fromWord8List $ reverse ws+                        Nothing -> error "hash160FromText: not a hex string"+  | otherwise       = error "hash160FromTextBE: length should be 40 characters"++--------------------------------------------------------------------------------
+ Bitcoin/Protocol/Key.hs view
@@ -0,0 +1,165 @@++-- | Encoding/decoding of public and private keys +--++{-# LANGUAGE CPP #-}+module Bitcoin.Protocol.Key +  ( +  -- * private keys+    PrivKey(..) +  , generatePrivKeyIO+  , generatePrivKey+  , encodePrivKey32 +  , decodePrivKey32+  -- * wallet import format for private keys+  , WIF(..)+  , privKeyWIFEncode+  , privKeyWIFDecode+  -- * public keys+  , PubKey(..) , PubKeyFormat(..) , pubKeyFormat +  , PubKeyHash(..) , pubKeyHash+  , decodePubKey+  , encodePubKeyNative+  , encodePubKey' +  , encodePubKeyLong +  , encodePubKeyShort +  -- * computations on keys+  , computePubKey +  , computeFullPubKey+  , isValidPubKey +  , formatPubKey +  , uncompressPubKey +  , compressPubKey+  )+  where++--------------------------------------------------------------------------------++import Control.Monad++import Data.Char+import Data.Bits+import Data.Word+import Data.Maybe++import qualified Data.ByteString as B++import Bitcoin.Misc.BigInt+import Bitcoin.Misc.OctetStream++import Bitcoin.Protocol.Base58+import Bitcoin.Protocol.Base64+import Bitcoin.Protocol.Hash++import Bitcoin.Crypto.EC.Key++--------------------------------------------------------------------------------+-- * trivial encoding of private keys ++-- | Simple 32 byte big-endian integer format+encodePrivKey32 :: PrivKey -> B.ByteString+encodePrivKey32 (PrivKey da) = B.pack $ bigEndianInteger32 da++-- | Simple 32 byte big-endian integer format+decodePrivKey32 :: B.ByteString -> PrivKey+decodePrivKey32 bs = if B.length bs == 32 +  then PrivKey $ bigEndianRollInteger $ B.unpack bs+  else error "decodePrivKey32: expected a 32 byte long bytestring"++--------------------------------------------------------------------------------+-- * wallet import format for private keys++-- | Wallet Import Format+newtype WIF = WIF { unWIF :: String } deriving (Eq,Show)++-- | Encode to Wallet Import Format (WIF)+privKeyWIFEncode :: PubKeyFormat -> PrivKey -> WIF+privKeyWIFEncode pkformat (PrivKey key) = WIF $ unBase58Check $+  case pkformat of+    Uncompressed -> base58CheckEncode vb $ B.pack $ bigEndianInteger32 key+    Compressed   -> base58CheckEncode vb $ B.pack $ bigEndianInteger32 key ++ [1]+  where+#ifndef WITH_TESTNET+    vb = VersionByte 128+#else+    vb = VersionByte 239+#endif+       +-- | Decode from Wallet Import Format (WIF)+privKeyWIFDecode :: WIF -> Maybe (PubKeyFormat,PrivKey)+privKeyWIFDecode (WIF str) = case base58CheckDecode (Base58Check str) of+  Right (vb, bs) | vb == vb0 -> +    case B.length bs of+      32 -> Just ( Uncompressed , PrivKey $ bigEndianRollInteger $ ws )+      33 -> case last ws of+              1 -> Just ( Compressed , PrivKey $ bigEndianRollInteger $ take 32 ws )+              _ -> Nothing+    where +      ws = B.unpack bs+  _ -> Nothing+  where+#ifndef WITH_TESTNET+    vb0 = VersionByte 128+#else+    vb0 = VersionByte 239+#endif++--------------------------------------------------------------------------------+-- * public keys+ +-- | Encodes the public key as it is represented (either compressed 33 bytes or uncompressed 65 bytes)+encodePubKeyNative :: PubKey -> B.ByteString+encodePubKeyNative pk = encodePubKey' (pubKeyFormat pk) pk++-- | Encodes a public key according to the specified format+encodePubKey' :: PubKeyFormat -> PubKey -> B.ByteString+encodePubKey' fmt pk = fromByteString $ case fmt of+  Uncompressed -> encodePubKeyLong  pk+  Compressed   -> encodePubKeyShort pk++-- | Encodes a public key as a 65 byte ByteString (uncompressed)+encodePubKeyLong :: PubKey -> B.ByteString+encodePubKeyLong       (FullPubKey  x y) = B.pack ( 4 : bigEndianInteger32 x ++ bigEndianInteger32 y )+encodePubKeyLong compr@(ComprPubKey _ _) = case uncompressPubKey compr of+  Just full -> encodePubKeyLong full+  Nothing   -> error "encodePubKeyLong: invalid compressed public key found"++-- | Encodes a public key as a 33 byte ByteString (compressed)+encodePubKeyShort :: PubKey -> B.ByteString+encodePubKeyShort      (ComprPubKey s x) = B.pack ( (if even s then 2 else 3) : bigEndianInteger32 x )+encodePubKeyShort full@(FullPubKey  _ _) = encodePubKeyShort (compressPubKey full)++-- | Decode public key from 33/65 bytes long (compressed/uncompressed) octet streams+decodePubKey :: OctetStream a => a -> Maybe PubKey+decodePubKey octets = +  case len of+    33 -> case head ws of+            02 -> Just (ComprPubKey 02 x)+            03 -> Just (ComprPubKey 03 x)+            _  -> Nothing+    65 -> case head ws of+            04 -> Just (FullPubKey x y)+            06 -> Just (FullPubKey x y)   -- testnet3 transaction cb2710fca03b99502f81d50a40690f160079459f6b1d27aeb13bbaf70ba976d2 ...+            _  -> Nothing +    _  -> Nothing  +  where+    len = length ws+    ws  = toWord8List octets+    x = bigEndianRollInteger $ take 32 $ drop 1  ws+    y = bigEndianRollInteger $ take 32 $ drop 33 ws  ++--------------------------------------------------------------------------------+-- * public key hashes++-- | The 160-bit hash of a public key+newtype PubKeyHash = PubKeyHash { fromPubKeyHash :: Hash160 } deriving (Eq,Show)++pubKeyHash :: PubKey -> PubKeyHash+pubKeyHash pubkey = PubKeyHash $ doHash160 (encodePubKeyNative pubkey :: B.ByteString)++instance OctetStream PubKeyHash where+  toByteString   = toByteString . fromPubKeyHash+  fromByteString = PubKeyHash . fromByteString++--------------------------------------------------------------------------------+
+ Bitcoin/Protocol/MerkleTree.hs view
@@ -0,0 +1,99 @@++-- | Merkle trees with double SHA-256+-- +-- See <https://en.bitcoin.it/wiki/Protocol_specification#Merkle_Trees>+--++module Bitcoin.Protocol.MerkleTree where++--------------------------------------------------------------------------------++import Control.Monad++import qualified Data.ByteString as B++import Bitcoin.Misc.HexString+import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.Endian++import Bitcoin.Protocol.Hash++-- import Bitcoin.Hash.SHA256++--------------------------------------------------------------------------------++data MerkleTree hash+  = MerkleNode   hash (MerkleTree hash) (MerkleTree hash)+  | MerkleSingle hash (MerkleTree hash)+  | MerkleLeaf   hash+  deriving Show++-- | The root of the tree+merkleRoot :: MerkleTree hash -> hash+merkleRoot t = case t of+  MerkleNode   hash _ _ -> hash+  MerkleSingle hash _   -> hash+  MerkleLeaf   hash     -> hash  ++--------------------------------------------------------------------------------++-- | Creates a Merkle tree from data+createMerkleTree :: OctetStream a => [a] -> MerkleTree Hash256+createMerkleTree = buildMerkleTree . map (MerkleLeaf . doHash256) where++-- | Builds a Merkle tree from data from a list of smaller Merkle trees+buildMerkleTree :: [MerkleTree Hash256] -> MerkleTree Hash256+buildMerkleTree = go where++  go xs = case xs of        +    []     -> error "createMerkleTree: empty input, shouldn't happen"+    [root] -> root+    _      -> go (map worker $ merklePairs xs)++  worker ei = case ei of+    Right (left,right) -> MerkleNode   (dhash left   right ) left right +    Left  single       -> MerkleSingle (dhash single single) single++  dhash t1 t2 = doHash256 (B.append (toByteString $ merkleRoot t1) (toByteString $ merkleRoot t2))++--------------------------------------------------------------------------------++merklePairs :: [a] -> [Either a (a,a)]+merklePairs (x:y:rest) = Right (x,y) : merklePairs rest+merklePairs [x]        = [Left x]+merklePairs []         = []++--------------------------------------------------------------------------------++-- | Converts the tree into a format easier to visualize for humans+merklePyramid :: MerkleTree hash -> [[hash]]+merklePyramid = go where+  go t = case t of+    MerkleLeaf   hash            -> [[hash]]+    MerkleSingle hash single     ->  [hash] : go single+    MerkleNode   hash left right ->  [hash] : (zipWith (++) (go left) (go right))++{-+-- | For debugging (similar output to blockexporer, at least when using @BigEndian@)+viewMerkleTree :: Endian -> MerkleTree Hash256 -> IO ()+viewMerkleTree endian tree = do+  forM_ (reverse $ zip [0..] pyramid) $ \(i,list) -> do+    putStrLn "" +    let indent = "" -- replicate (2*i) ' '+    forM_ list $ \hash -> putStrLn (indent ++ (toHexStringChars $ f $ toWord8List hash))+  where+    f = case endian of { LittleEndian -> id ; BigEndian -> reverse }+    pyramid = merklePyramid tree+-}++-- | For debugging (similar output to blockexporer)+viewMerkleTree :: Show hash => MerkleTree hash -> IO ()+viewMerkleTree tree = do+  forM_ (reverse $ zip [0..] pyramid) $ \(i,list) -> do+    putStrLn "" +    let indent = "" -- replicate (2*i) ' '+    forM_ list $ \hash -> putStrLn (indent ++ show hash)+  where+    pyramid = merklePyramid tree++--------------------------------------------------------------------------------
+ Bitcoin/Protocol/Signature.hs view
@@ -0,0 +1,391 @@++-- | Signing, verifying, and encoding\/decoding of signatures. ++{-+-- Signatures are typically Base64 encoded (yet another encoding, because why not...)+-- plus some special 65 byte encoding which allows reconstructing the public key,+-- plus a (not completely standard...) DER encoding again extended with an extra +-- special byte...+-}++{-# LANGUAGE PatternGuards #-}+module Bitcoin.Protocol.Signature+  ( +  -- * types+    Signature(..) , SignatureExt(..)+  , SignBits(..)+  , SigHash(..) , SigHashType(..) , sigHashAll+  , normalizeSigHashType , normalizeSigHash +  -- * SigHash encoding+  , encodeSigHash+  , decodeSigHash+  -- * DER signature encoding+  , encodeSignatureDER+  , decodeSignatureDER , decodeSignatureDER'+  -- * \"compact\" signature encoding+  , decodeCompactSigBase64+  , encodeCompactSigBase64+  , decodeCompactSig+  , encodeCompactSig+  -- * signing messages (user specified random generator)+  , signTextMessage +  , signRawMessage +  , signTextMessageAddr_+  , signTextMessageAddr+  -- * signing messages (default random generator in IO - primarily for testing)+  , signTextMessageIO+  , signRawMessageIO+  , signTextMessageAddrIO_+  , signTextMessageAddrIO+  -- * signing messages (RFC6979 deterministic signatures)+  , signTextMessageRFC6979+  , signRawMessageRFC6979+  , signTextMessageAddrRFC6979_+  , signTextMessageAddrRFC6979+  -- * verifying signatures+  , verifyTextSignatureAddr+  , verifyTextSignaturePK +  , verifyRawSignaturePK +  -- * public key recovery+  , recoverTextPubKey +  , recoverRawPubKey +  -- * text message signing (bitcoin-qt compatible) +  , messageMagic+  , prepareMessageForSigning +  , messageHash +  )+  where++--------------------------------------------------------------------------------++import Control.Monad++import Data.Char+import Data.Bits+import Data.Word+import Data.Maybe++import qualified Data.ByteString as B++import System.Random++-- import Bitcoin.Misc.HexString+import Bitcoin.Misc.BigInt+import Bitcoin.Misc.OctetStream++import Bitcoin.Protocol.Address+import Bitcoin.Protocol.Base58+import Bitcoin.Protocol.Base64+import Bitcoin.Protocol.Key+import Bitcoin.Protocol.Hash++import Bitcoin.Crypto.EC.Curve+import Bitcoin.Crypto.EC.DSA++--------------------------------------------------------------------------------+-- * Signature Hashtype++data SigHashType+  = SigHashAll+  | SigHashNone+  | SigHashSingle+  | SigHashAllZero     -- ^ 0 appears in the blockchain, should be handled as SigHashAll, but we must also properly serialize it back to 0 :(+  deriving (Eq,Show)++-- | Converts 'SigHashAllZero' to 'SigHashAll'+normalizeSigHashType :: SigHashType -> SigHashType+normalizeSigHashType t = case t of+  SigHashAllZero -> SigHashAll+  _              -> t ++normalizeSigHash :: SigHash -> SigHash+normalizeSigHash (SigHash t a) = SigHash (normalizeSigHashType t) a++-- | SigHash specifies how to the OP_CHECKSIG opcode should work (?)+data SigHash = SigHash +  { _sigHashType  :: !SigHashType+  , _anyOneCanPay :: !Bool+  } +  deriving (Eq,Show)++sigHashAll :: SigHash+sigHashAll = SigHash SigHashAll False++-- | \"Extended signature\": an ECDSA signature together with the sighash type+data SignatureExt = SignatureExt +  { _extSignature :: !Signature +  , _extSigHash   :: !SigHash +  } +  deriving (Eq,Show)++encodeSigHash :: SigHash -> Word8+encodeSigHash (SigHash typ anyflag) = f+t where+  f = if anyflag then 0x80 else 0x00+  t = case typ of+    SigHashAll     -> 1+    SigHashNone    -> 2+    SigHashSingle  -> 3+    SigHashAllZero -> 0        -- must serialize back to the original zero byte for tx checking...++decodeSigHash :: Word8 -> Maybe SigHash+decodeSigHash w = +  case (w .&. 31) of+    0 -> sighash SigHashAllZero      -- this is because this appears in the blockchain because of a bug in some earlier implementation...+    1 -> sighash SigHashAll  +    2 -> sighash SigHashNone +    3 -> sighash SigHashSingle  +    _ -> Nothing+  where+    f = (w .&. 0x80) > 0+    sighash t = Just (SigHash t f)++--------------------------------------------------------------------------------+-- * DER encoding/decoding of signatures++-- | Signatures use DER encoding to pack the r and s components into a single byte stream (this is also what OpenSSL produces by default).+-- (it seem that this is true only in the blockchain, not for signatures of messages, which use CompactSig?)+--+-- Howeever, there is an extra last byte appended, which is \"SIGHASH\"+--+encodeSignatureDER :: OctetStream a => SignatureExt -> a+encodeSignatureDER (SignatureExt (Signature r s) sighash) = fromWord8List (0x30 : fromIntegral (length rs) : rs ++ [encodeSigHash sighash]) where+  rs = derEncodeInteger r ++ derEncodeInteger s+  derEncodeInteger :: Integer -> [Word8]+  derEncodeInteger int = case ws of+    []    -> [0x02,0]+    (h:_) -> if h<0x80 +               then [0x02 ,     fromIntegral (length ws)     ] ++ ws+               else [0x02 , 1 + fromIntegral (length ws) , 0 ] ++ ws+    where+      ws = bigEndianUnrollInteger int++decodeSignatureDER :: OctetStream a => a -> Maybe SignatureExt+decodeSignatureDER = decodeSignatureDER' True++-- | DER encoding looks like this:+-- +-- > 0x30 len [ 0x02 lenR [ R ] 0x02 lenS [ S ] ] SIGHASH+--+-- so that's 7 extra bytes on top of R and S.+--+-- Except when it doesn't look it that... (mostly in MULTISIG transactions). +-- Of course nothing is documented anywhere.+-- +-- So the 'Bool' argument controls if we are playing strict ('True') or loose ('False')+--+decodeSignatureDER' :: OctetStream a => Bool -> a -> Maybe SignatureExt+decodeSignatureDER' strict bs +  | lws < 7     || (strict && lws > 73      ) = Nothing+  | lws < len+2 || (strict && lws /= len + 3) = Nothing+  | head ws /= 0x30                           = Nothing+  | isJust r , isJust s +    , len_r + len_s + 6 <= lws+    , not strict || (len_r + len_s + 7 == lws)+    , isJust mbsighash                        = Just $ SignatureExt (Signature (fromJust r) (fromJust s)) (fromJust mbsighash)+  | otherwise                                 = Nothing+  where+    mbsighash = decodeSigHash $ last ws -- (if strict then ws else ws++[0x01]) !! (len+2)+    len   = fromIntegral (ws!!1) :: Int+    xxx_r = drop 2 ws+    len_r = fromIntegral (xxx_r!!1) :: Int+    der_r = if head xxx_r == 0x02 then Just (take len_r $ drop 2 xxx_r) else Nothing+    xxx_s = drop (2 + len_r) xxx_r+    len_s = fromIntegral (xxx_s!!1) :: Int+    der_s = if head xxx_s == 0x02 then Just (take len_s $ drop 2 xxx_s) else Nothing+    r     = liftM bigEndianRollInteger der_r :: Maybe Integer+    s     = liftM bigEndianRollInteger der_s :: Maybe Integer+    ws    = toWord8List bs :: [Word8]+    lws   = length ws++--------------------------------------------------------------------------------+-- * \"compact\" encoding of signatures++-- | Decodes a base64-encoded \"compact\" signature+decodeCompactSigBase64 :: Base64 -> Maybe (PubKeyFormat,SignBits,Signature)+decodeCompactSigBase64 str = (base64Decode str :: Maybe [Word8]) >>= decodeCompactSig++encodeCompactSigBase64 :: (PubKeyFormat,SignBits,Signature) -> Base64+encodeCompactSigBase64 what = base64Encode (encodeCompactSig what :: [Word8])++-- | Decodes a 65 bytes long \"compact\" signature.+--+-- First byte is either one of 0x1b, 0x1c, 0x1d, 0x1e (uncompressed public key)+-- or 0x1f, 0x20, 0x21, 0x22 (compressed public key). This information is necessary+-- to recover the public key from the message hash and the signature. In the output +-- only the relevant two bits of information is retained.+--+-- After that comes 32 bytes R and 32 bytes S.+--+decodeCompactSig :: OctetStream a => a -> Maybe (PubKeyFormat,SignBits,Signature)+decodeCompactSig octets = ++  if n /= 65 || h < 0x1b || h > 0x23 +    then Nothing +    else Just (fmt,SignBits parities,signat)++  where++    signat = Signature r s++    fmt = if h < 0x1f then Uncompressed else Compressed+    parities = (h - 0x1b) .&. 3  + +    h  = head ws+    r  = bigEndianRollInteger (take 32 $ drop 1  $ ws)    -- these are without question big-endians. The (bitcoin-qt) source uses BN_bn2bin,+    s  = bigEndianRollInteger (take 32 $ drop 33 $ ws)    -- but it is clear even without that, because of the offsetting there+    n  = length ws+    ws = toWord8List octets++-- | About the Word8: +-- Bit 0 encodes whether the curve point R (which has x coordinate r from the signature) +-- has even or odd y coordinate; and bit 1 encodes how to reconstruct the x coordinate from r. The rest of the bits must be zero+--+encodeCompactSig :: OctetStream a => (PubKeyFormat,SignBits,Signature) -> a+encodeCompactSig (pkfmt , SignBits parities , Signature r s) = fromWord8List (h : rr ++ ss) where+  rr = bigEndianInteger32 r+  ss = bigEndianInteger32 s+  h0 = case pkfmt of+    Uncompressed -> 0x1b+    Compressed   -> 0x1f+  h = h0 + (parities .&. 3)++--------------------------------------------------------------------------------+-- * signing message++-- | Signing a bitcoin-QT compatible text message (using the default random number generator in IO).+-- +signTextMessageIO :: (OctetStream msg) => PrivKey -> msg -> IO (SignBits,Signature)+signTextMessageIO priv msg = getStdRandom $ \gen -> signTextMessage priv msg gen++signRawMessageIO :: (OctetStream msg) => PrivKey -> msg -> IO (SignBits,Signature)+signRawMessageIO priv msg = getStdRandom $ \gen -> signRawMessage priv msg gen++-- | Signing a bitcoin-QT compatible text message+signTextMessage :: (OctetStream msg, RandomGen gen) => PrivKey -> msg -> gen -> ((SignBits,Signature),gen)+signTextMessage priv msg gen = signMessageHash priv (doHash256 $ prepareMessageForSigning msg) gen++signRawMessage :: (OctetStream msg, RandomGen gen) => PrivKey -> msg -> gen -> ((SignBits,Signature),gen)+signRawMessage priv msg gen = signMessageHash priv (doHash256 msg) gen++signTextMessageAddrIO_ :: OctetStream msg => PubKeyFormat -> PrivKey -> msg -> IO Base64+signTextMessageAddrIO_ pkfmt privkey msg = getStdRandom $ \gen -> signTextMessageAddr_ pkfmt privkey msg gen++-- | Bitcoin-QT compatible message signing with the default random generator+-- (can be checked with the address instead of the public key)+-- +signTextMessageAddrIO :: OctetStream msg => PubKeyFormat -> PrivKey -> msg -> IO (Address,Base64)+signTextMessageAddrIO pkfmt privkey msg = getStdRandom $ \gen -> signTextMessageAddr pkfmt privkey msg gen++signTextMessageAddr_ :: (OctetStream msg, RandomGen gen) => PubKeyFormat -> PrivKey -> msg -> gen -> (Base64,gen)+signTextMessageAddr_ pkfmt privkey msg gen = +  case signTextMessageAddr pkfmt privkey msg gen of+    ((_,signature),gen') -> (signature,gen')++-- | Bitcoin-QT compatible message signing (can be checked with the address instead of the public key)+-- +signTextMessageAddr :: (OctetStream msg, RandomGen gen) => PubKeyFormat -> PrivKey -> msg -> gen -> ((Address,Base64),gen)+signTextMessageAddr pkfmt privkey msg gen = ((addr,base64),gen') where+  pubkey = computePubKey Uncompressed privkey+  addr   = pubKeyAddress pubkey+  ((bits,signat),gen') = signTextMessage privkey msg gen+  base64 = encodeCompactSigBase64 (pubKeyFormat pubkey,bits,signat)++--------------------------------------------------------------------------------+-- * signing messages (RFC6979 deterministic signatures)++-- | Signing a bitcoin-QT compatible text message using the deterministic RFC6979 signatures.+signTextMessageRFC6979 :: (OctetStream msg) => PrivKey -> msg -> (SignBits,Signature)+signTextMessageRFC6979 priv msg = signMessageHashRFC6979 priv (doHash256 $ prepareMessageForSigning msg) ++-- | Signing a raw (octet stream) message using the deterministic RFC6979 signatures.+signRawMessageRFC6979 :: (OctetStream msg) => PrivKey -> msg -> (SignBits,Signature)+signRawMessageRFC6979 priv msg = signMessageHashRFC6979 priv (doHash256 msg) ++signTextMessageAddrRFC6979_ :: (OctetStream msg) => PubKeyFormat -> PrivKey -> msg -> Base64+signTextMessageAddrRFC6979_ pkfmt privkey msg = snd $ signTextMessageAddrRFC6979 pkfmt privkey msg++-- | Bitcoin-QT compatible message signing (can be checked with the address instead of the public key),+-- using the deterministic RFC6979 signatures.+--+signTextMessageAddrRFC6979 :: (OctetStream msg) => PubKeyFormat -> PrivKey -> msg -> (Address,Base64)+signTextMessageAddrRFC6979 pkfmt privkey msg = (addr,base64) where+  pubkey = computePubKey Uncompressed privkey+  addr   = pubKeyAddress pubkey+  (bits,signat) = signTextMessageRFC6979 privkey msg +  base64 = encodeCompactSigBase64 (pubKeyFormat pubkey,bits,signat)++--------------------------------------------------------------------------------+-- * verifying signatures++-- | First argument is the address, second is the base64-encoded \"compact signature\", third is the message.+--+-- TODO: UTF8 encoding!+verifyTextSignatureAddr :: OctetStream msg => Address -> Base64 -> msg -> Bool +verifyTextSignatureAddr address base64signat text = isJust mbexsignat && isJust mbpubkey && cond1 && cond2 where+  message = toByteString text +  cond1 = (pubKeyAddress pubkey == address)+  cond2 = verifyTextSignaturePK pubkey signat message+  pubkey   = fromJust mbpubkey+  mbpubkey = recoverTextPubKey exsignat message+  exsignat@(_,_,signat) = fromJust mbexsignat+  mbexsignat            = decodeCompactSigBase64 base64signat++-- | Verifying a bitcoin-QT compatible text signature using the public key+verifyTextSignaturePK :: OctetStream msg => PubKey -> Signature -> msg -> Bool+verifyTextSignaturePK pk signat msg = verifySignatureWithHash pk signat (doHash256 $ prepareMessageForSigning msg)++-- | Verifying a signature for raw data (no bitcoin-QT magic wrapper around the message)+verifyRawSignaturePK :: OctetStream msg => PubKey -> Signature -> msg -> Bool+verifyRawSignaturePK pk signat msg = verifySignatureWithHash pk signat (doHash256 msg)++--------------------------------------------------------------------------------+-- * public key recovery++-- | Recovers the public key from the compact signature and the /text message/ (Bitcoin-QT compatible)+recoverTextPubKey :: OctetStream msg => (PubKeyFormat,SignBits,Signature) -> msg -> Maybe PubKey+recoverTextPubKey exsignat msg = recoverPubKeyFromHash exsignat (doHash256 $ prepareMessageForSigning msg)++-- | Recovers the public key from the compact signature and the raw message (no Bitcoin-QT magic)+recoverRawPubKey :: OctetStream msg => (PubKeyFormat,SignBits,Signature) -> msg -> Maybe PubKey+recoverRawPubKey exsignat msg = recoverPubKeyFromHash exsignat (doHash256 msg)++--------------------------------------------------------------------------------+-- * text message signing (bitcoin-qt compatible)++-- | This is prepended to the message. Only it is not simply prepended...+messageMagic :: B.ByteString+messageMagic = B.pack $ map (char_to_word8) $ "Bitcoin Signed Message:\n"++-- | Now, this is a seriously braindead and completely undocumented protocol+prepareMessageForSigning :: OctetStream a => a -> B.ByteString+prepareMessageForSigning origmsg = B.concat [sizMagic,messageMagic,siz,msg] where++  msg = toByteString origmsg++  sizMagic = B.pack $ encodeVarInt $ B.length messageMagic+  siz      = B.pack $ encodeVarInt $ B.length msg++  encodeVarInt :: Int -> [Word8]+  encodeVarInt n +    | n <  0           =  error "prepareMessageForSigning/encodeVarInt: negative input, shouldn't happen"+    | n <= 0xfc        =  [fromIntegral n]+    | n <= 0xffff      =  0xfd : leInt 2 n+    | n <= 0xffffffff  =  0xfe : leInt 4 n+    | otherwise        =  0xff : leInt 8 n++  leInt :: Int -> Int -> [Word8] +  leInt k n = take k $ littleEndianUnrollInteger (fromIntegral n) ++ replicate k 0++-- | The message hash function we use for signing message.+--+-- The bool parameter specifies whether to sign the raw message or the+-- really stupidly serialized and magic prefixed text version...++-- (fuck, I just spent a whole day trying to figure out why my +-- code doesn't give the same result as the official client...)+messageHash :: OctetStream msg => Bool -> msg -> Hash256+messageHash textmagic message +  = doHash256+  $ if textmagic then (prepareMessageForSigning message) else (toByteString message)++--------------------------------------------------------------------------------
+ Bitcoin/Protocol/Tx.hs view
@@ -0,0 +1,169 @@+
+-- | Create/sign standard transactions
+{-# LANGUAGE ScopedTypeVariables #-}
+module Bitcoin.Protocol.Tx where
+
+--------------------------------------------------------------------------------
+
+import Data.Word
+
+import qualified Data.ByteString as B
+
+import System.Random
+
+import Bitcoin.Protocol.Address
+import Bitcoin.Protocol.Amount 
+import Bitcoin.Protocol.Signature 
+import Bitcoin.Protocol.Key
+
+import Bitcoin.BlockChain.Tx
+import Bitcoin.BlockChain.Parser ( serializeTx )
+
+import Bitcoin.Script.Base
+import Bitcoin.Script.Standard
+import Bitcoin.Script.Run
+import Bitcoin.Script.Serialize
+
+import Bitcoin.Misc.Bifunctor
+import Bitcoin.Misc.Tuple
+
+--------------------------------------------------------------------------------
+
+data StdTxInput a = StdTxInput
+  { _prevTx         :: !(Tx a RawScript)
+  , _prevOutIndex   :: !Int
+  , _prevOutPrivKey :: !PrivKey
+  }
+
+data StdTxOutput = StdTxOutput
+  { _outAddress     :: !Address
+  , _outAmount      :: !Amount
+  }
+
+{-
+-- | Creates a standard transaction which spends outputs of previous standard transactions.
+spendStandardTx :: [StdInput] -> [StdOutput] -> Either String (Tx RawScript RawScript, Amount)
+spendStandardTx inputs outputs  
+-}
+
+--------------------------------------------------------------------------------
+
+{-
+-- | Creates a standard transaction which spends output(s) of previous standard transaction(s). Returns also the amount of fee.
+createStandardTx' :: Tx (Tx a RawScript, PrivKey) Address -> Either String (Tx RawScript RawScript, Amount)
+createStandardTx' preparedTx = 
+  case all isPayToAddress recInputs of
+    False -> Left "inputs are not all PayToAddress scripts"
+    True  -> preparedTx { _txInputs = newInputs , _txOutputs = newOutputs , _txHash = newHash }
+  where
+    inputs    = map (fmap fst         ) $ _txInputs preparedTx recognizeTxInput :: [TxInput (Tx a RawScript)]
+    privkeys  = map (snd . _txInScript) $ _txInputs preparedTx recognizeTxInput :: [PrivKey]
+    recInputs = map recognizeTxInput inputs :: [TxInput InputScript]
+  
+    flippedZipWith inputs privkeys $ \inp privkey -> 
+-}
+
+--------------------------------------------------------------------------------
+
+-- signRawMessage :: (OctetStream msg, RandomGen gen) => PrivKey -> msg -> gen -> ((SignBits,Signature),gen)
+
+{-
+signInputs :: forall a gen. RandomGen gen => Tx (Tx a RawScript, PrivKey) RawScript -> gen -> (Either String (SignatureExt,PubKey),gen)
+signInputs privkey txext gen = (result,gen') where
+
+  signOneInput :: Int -> Either (SignatureExt,PubKey)
+  signOneInput k = 
+    case subscript pkscript of
+      Left err -> Left err
+    inpExt = ((_txInputs txExt) !! k) :: TxInput (Tx a RawScript, PrivKey)
+    outidx = _txInPrevOutIdx inpExt
+    (prevtx, privkey) = _txInScript inpExt
+    pubkey = computePubKey Compressed privkey 
+    pkscript = (_txOutScript prevtx) !! outidx
+-}
+
+
+-- | Signs a (standard, and all previous outputs are pay-to-address) transaction
+signTransaction :: forall a gen. RandomGen gen => Tx (Tx a RawScript, PrivKey) RawScript -> gen -> (Either String (Tx RawScript RawScript) ,gen)
+signTransaction newTxExt gen0 = result where
+
+  result = case mapAccumLFst worker (Right 0, gen0) newTxExt of
+    ((Left err , gen1) , _      ) -> (Left err, gen1)
+    ((Right _  , gen1) , finalTx) -> 
+      let prevs      = map fst $ toListFst newTxExt :: [Tx a RawScript]
+          finalTxExt = zipWithFst (,) prevs finalTx
+      in  case checkTransaction finalTxExt of
+            Left err -> (Left err, gen1)
+            Right b  -> if b
+              then (Right finalTx, gen1)
+              else (Left "cannot verify the signed transaction", gen1)
+
+  undefRawScript :: RawScript
+  undefRawScript = error "signTransaction/undefRawScript: shouldn't be evaluated"
+
+  worker :: (Either String Int, gen) -> (Tx a RawScript, PrivKey) -> ((Either String Int, gen), RawScript)
+  worker (Left err, gen) _  = ((Left err,gen) , undefRawScript)
+  worker (Right k , gen) (prevtx,privkey) =
+    case signSingleInput privkey sigHashAll k prevtx newTxExt gen of
+      Left err -> ((Left err, gen), undefRawScript)
+      Right ((sigext,pubkey),gen') -> ((Right (k+1), gen') , sigScript) where
+        sigScript = createInputScript $ RedeemAddress sigext pubkey 
+
+-- | Signs a single input of a transaction
+signSingleInput :: forall a b gen. RandomGen gen => PrivKey -> SigHash -> Int -> Tx a RawScript -> Tx b RawScript -> gen -> Either String ((SignatureExt,PubKey),gen)
+signSingleInput privkey sighash inpidx prevtx thistx gen = result where
+
+  result = case safeLookup inpidx thisinps of
+    Nothing -> Left "signSingleInput: input index out of range"
+    Just inp -> 
+      let outidx = _txInPrevOutIdx inp
+      in  case safeLookup (fromIntegral outidx) prevouts of
+        Nothing -> Left "signSingleOutput: prev output index out of range"
+        Just prevout -> 
+          let pkscript = _txOutScript prevout
+          in  case getSubscript pkscript of
+                Left  err    -> Left err
+                Right subscript -> 
+                  let txcopy    = replaceTxIns emptyRawScript (inpidx,subscript) thistx
+                      RawTx raw = serializeTx txcopy
+                      msg = B.append raw (B.pack [encodeSigHash sighash, 0,0,0::Word8])
+                      ((signbits,signat),gen') = signRawMessage privkey msg gen
+                      sigext = SignatureExt signat sighash
+                  in  Right ((sigext,pubkey),gen')
+
+  thisinps = _txInputs  thistx :: [TxInput b]
+  prevouts = _txOutputs prevtx :: [TxOutput RawScript]
+  pubkey = computePubKey Compressed privkey 
+
+  safeLookup :: forall x. Int -> [x] -> Maybe x
+  safeLookup n xs 
+    | n<0   = Nothing
+    | n==0  = case xs of { (x:_) -> Just x              ; [] -> Nothing }
+    | True  = case xs of { (x:_) -> safeLookup (n-1) xs ; [] -> Nothing }      
+ 
+  -- not fully correct, as the full verification is braindeadly complicated because of the CODESEPARATOR mess :(
+  -- (which was never ever used as far as I know...)
+  getSubscript :: RawScript -> Either String RawScript
+  getSubscript full = case parseScript full of
+    Nothing -> Left    "signInput/subscript: cannot parse pkScript"
+    Just pk -> Right $ serializeScript $ Script $ reverse $ takeWhile (/=OP_CODESEPARATOR) $ reverse $ fromScript $ pk 
+  
+  -- | We replace all inputs with @def@ except the kth which we replace by @spec@
+  replaceTxIns :: forall a b c. b -> (Int,b) -> Tx a c -> Tx b c
+  replaceTxIns def (k,spec) tx = mapAccumLFst_ worker 0 tx where
+    worker j _ = if j==k then (j+1,spec) else (j+1,def)
+
+--------------------------------------------------------------------------------
+
+isPayToAddress :: OutputScript -> Bool
+isPayToAddress s = case s of
+  PayToAddress {} -> True
+  _               -> False
+
+isPayToPubKey :: OutputScript -> Bool
+isPayToPubKey s = case s of
+  PayToPubKey {} -> True
+  _              -> False
+
+--------------------------------------------------------------------------------
+  
+ Bitcoin/RPC/API.hs view
@@ -0,0 +1,838 @@++-- | bitcoind API access (via JSON-RPC over HTTP calls)+--+-- See <https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_calls_list>+--++{-# LANGUAGE PatternGuards #-}+module Bitcoin.RPC.API where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits+import Data.Maybe++import Control.Applicative++import Text.JSON+import Text.JSON.Types++import qualified Data.ByteString as B++import Bitcoin.Misc.HexString+import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.UnixTime++import Bitcoin.Protocol.Address+import Bitcoin.Protocol.Amount+import Bitcoin.Protocol.Base64+import Bitcoin.Protocol.Hash+import Bitcoin.Protocol.Key+import Bitcoin.Protocol.Signature++import Bitcoin.Script.Base+import Bitcoin.BlockChain.Base++import Bitcoin.RPC.JSON +import Bitcoin.RPC.Call++--------------------------------------------------------------------------------++-- | An account in the Satoshi client wallet  +type Account = String ++-- | A network node+type Node = String++-- | A transaction id+type TxId = Hash256++-- | A public key+type Key = Either PubKey Address ++-- | Minimum number of confirmations (default is usually 1)+type MinConf = Maybe Int +type MaxConf = Maybe Int++-- | A redeem script for a multi-sig address+type RedeemScript = RawScript++type PassPhrase = String++------------------++data AddNodeCmd +  = NodeAdd +  | NodeRemove +  | NodeOneTry +  deriving (Eq,Show)++--------------------------------------------------------------------------------++{-++-- | Subset of satoshi client API calls. +-- See <https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list>+--+data APICALL  +  --  client info+  = GetInfo                                            -- ^ Returns an object containing various state info.   +  | GetConnectionCount                                 -- ^ Returns the number of connections to other nodes.   +  | Stop                                               -- ^ Stop bitcoin server.   +  --  blockchain info+  | GetDifficulty                                      -- ^ Returns the proof-of-work difficulty as a multiple of the minimum difficulty.   +  | GetBlock               Hash256                     -- ^ Returns information about the given block hash.   +  | GetBlockCount                                      -- ^ Returns the number of blocks in the longest block chain.  +  | GetBlockHash           Int                         -- ^ Returns hash of block in best-block-chain at \<index\>    +  --  transaction info+  | GetTransaction         TxId                        -- ^ Returns an object about the given transaction containing: \"amount\", \"confirmations\", \"txid\", \"time\", \"details\" (details is an array of objects containing: \"account\", \"address\", \"category\", \"amount\", \"fee\")+  | DecodeRawTransaction   B.ByteString                -- ^ version 0.7 Produces a human-readable JSON object for a (hex string of a) raw transaction.   +  --  wallet info+  | ValidateAddress        Address                     -- ^ Return information about \<bitcoinaddress\>.   +  | DumpPrivKey            Address                     -- ^ Reveals the private key corresponding to \<bitcoinaddress\>. NOTE: Wallet needs to be unlocked! +  | GetBalance             (Maybe Account) MinConf     -- ^ If [account] is not specified, returns the server's total available balance. Int is # of minimum confirmations+  | GetAccountAddress      Account                     -- ^ Returns the current bitcoin address for receiving payments to this account.   +  | GetAddressesByAccount  Account                     -- ^ Returns the list of addresses for the given account.   +  | GetAccount             Address                     -- ^ Returns the account associated with the given address.   +  | ListAccounts           MinConf                     -- ^ Returns Object that has account names as keys, account balances as values. Int is number of minimal confirmations+  | ListAddressGroupings                               -- ^ version 0.7 Returns all addresses in the wallet and info used for coincontrol.   +  | ListReceivedByAccount  MinConf Bool                -- ^ Int is minconf. Bool is \"includeempty\". Returns an array of objects containing: \"account\", \"amount\", \"confirmations\"+  | ListReceivedByAddress  MinConf Bool                -- ^ Returns an array of objects containing: \"address\", \"account\", \"amount\", \"confirmations\". To get a list of accounts on the system, execute bitcoind listreceivedbyaddress 0 true   +  --  network info+  | GetRawMemPool                                      -- ^ version 0.7 Returns all transaction ids in memory pool                                   +  --  multi-sig+  | AddMultiSigAddress     Int [Key] (Maybe Account)   -- ^ Add a n-required-to-sign multisignature address to the wallet. Each key is a bitcoin address or hex-encoded public key. If [account] is specified, assign address to [account].  +  | CreateMultiSig         Int [Key]                   -- ^ Creates a multi-signature address and returns a json object +  --  sending coins+  | SendFrom               Account Address Amount MinConf (Maybe String) (Maybe String) -- ^ \<fromaccount\> \<tobitcoinaddress\> \<amount\> [minconf=1] [comment] [comment-to]. Will send the given amount to the given address, ensuring the account has a valid balance using [minconf] confirmations. Returns the transaction ID if successful (not in JSON object). NOTE: Wallet needs to be unlocked! +  | SendMany               Account [(Address,Amount)] MinConf (Maybe String)            -- ^ Amounts are double-precision floating point numbers. NOTE: Wallet needs to be unlocked! +  | SendRawTransaction     B.ByteString                                                 -- ^ version 0.7 Submits raw transaction (serialized, hex-encoded) to local node and network.   +  | SendToAddress          Address Amount (Maybe String) (Maybe String)                 -- ^ \<amount\> is a real and is rounded to 8 decimal places. Returns the transaction ID \<txid\> if successful. NOTE: Wallet needs to be unlocked! +  | Move                   Account Account Amount MinConf (Maybe String)                -- ^ \<fromaccount\> \<toaccount\> \<amount\> [minconf=1] [comment]. Move from one account in your wallet to another   +  | SetTxFee               Amount                                                       -- ^ \<amount\> is a real and is rounded to the nearest 0.00000001   +  --  signing+  | SignMessage            Address String              -- ^ Sign a message with the private key of an address. NOTE: Wallet needs to be unlocked! +  | VerifyMessage          Address Signature String    -- ^ Verify a signed message.   +  --  wallet operations+  | GetNewAddress          (Maybe Account)             -- ^ Returns a new bitcoin address for receiving payments. If [account] is specified (recommended), it is added to the address book so payments received with the address will be credited to [account].   +  | ImportPrivKey          PrivKey (Maybe String) Bool -- ^ Adds a private key (as returned by dumpprivkey) to your wallet. This may take a while, as a rescan is done, looking for existing transactions. Optional [rescan] parameter added in 0.8.0. NOTE: Wallet needs to be unlocked! +  | BackupWallet           FilePath                    -- ^ Safely copies wallet.dat to destination, which can be a directory or a path with filename.  +  | EncryptWallet          String                      -- ^ Encrypts the wallet with \<passphrase\>.   +  | WalletLock                                         -- ^ Removes the wallet encryption key from memory, locking the wallet. After calling this method, you will need to call walletpassphrase again before being able to call any methods which require the wallet to be unlocked.   +  | WalletPassPhrase       String Int                  -- ^ Stores the wallet decryption key in memory for \<timeout\> seconds.   +  | WalletPassPhraseChange String String               -- ^ Changes the wallet passphrase from \<oldpassphrase\> to \<newpassphrase\>.  +  | KeyPoolRefill                                      -- ^ Fills the keypool, requires wallet passphrase to be set. NOTE: Wallet needs to be unlocked! ++-}++--------------------------------------------------------------------------------+-- * client info++data ClientInfo = ClientInfo+  { _cliClientVersion     :: (Int,Int,Int)+  , _cliProtocolVersion   :: (Int,Int,Int)+  , _cliWalletVersion     :: (Int,Int,Int)+  , _cliTotalBalance      :: Amount+  , _cliNumberOfBlocks    :: Int+  , _cliTimeOffset        :: Double    -- ^ in hours, relative to GMT, but negated (?)+  , _cliNoConnections     :: Int+  , _cliProxy             :: String+  , _cliCurrentDifficulty :: Double+  , _cliOnTestnet         :: Bool+  , _cliKeyPoolOldest     :: UnixTimeStamp+  , _cliKeyPoolSize       :: Int+  , _cliPayTxFee          :: Amount +  } +  deriving Show++-- | Returns an object containing various state info.+getClientInfo :: Call ClientInfo+getClientInfo = makeCall "getinfo" () $ \js -> case js of+  JSObject obj -> +    case obj of+      _ | Just cver <- lkp "version"+        , Just pver <- lkp "protocolversion"+        , Just wver <- lkp "walletversion"   +        , Just bal  <- lkp "balance"+        , Just nblk <- lkp "blocks"+        , Just tofs <- lkp "timeoffset"         +        , Just ncon <- lkp "connections"+        , Just prxy <- lkp "proxy"+        , Just diff <- lkp "difficulty"+        , Just test <- lkp "testnet"+        , Just old  <- lkp "keypoololdest"+        , Just pool <- lkp "keypoolsize"+        , Just fee  <- lkp "paytxfee"+                                                -> Just $ ClientInfo +                                                     (parseVer cver) +                                                     (parseVer pver)+                                                     (parseVer wver)+                                                     bal+                                                     nblk+                                                     tofs+                                                     ncon+                                                     prxy+                                                     diff+                                                     test+                                                     old+                                                     pool+                                                     fee+      _ -> Nothing+    where++      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+{-+      lkp fld = case get_field obj fld of+        Just js -> case readJSON js of +          Ok x    -> Just x +          Error _ -> Nothing +        Nothing -> Nothing+-}++      parseVer :: Int -> (Int,Int,Int)+      parseVer n = (a,b,c) where +        (a,tmp) = divMod n 10000+        (b,c)   = divMod tmp 100++  _ -> Nothing++-- | Returns the number of connections to other nodes+getConnectionCount :: Call Int+getConnectionCount = makeCall "getconnectioncount" () myReadJSON++-- | Stops the bitcoin client+stopClient :: Call ()  +stopClient = makeCall "stop" () $ \_ -> Just ()++--------------------------------------------------------------------------------+-- * blockchain info++data BlockInfo = BlockInfo+  { _bliHash           :: Hash256+  , _bliConfirmations  :: Int+  , _bliSize           :: Int +  , _bliHeight         :: Int+  , _bliVersion        :: Int+  , _bliMerkleRoot     :: Hash256+  , _bliTxHashes       :: [Hash256]+  , _bliTime           :: UnixTimeStamp+  , _bliNonce          :: Word32+  , _bliDifficultyBits :: Word32 +  , _bliDifficulty     :: Double+  , _bliPrevHash       :: Maybe Hash256+  , _bliNextHash       :: Maybe Hash256+  }+  deriving Show++-- | Returns the proof-of-work difficulty as a multiple of the minimum difficulty.+getDifficulty :: Call Double+getDifficulty = makeCall "getdifficulty" () myReadJSON++-- | Returns the number of blocks in the longest block chain.+getBlockCount :: Call Int+getBlockCount = makeCall "getblockcount" () myReadJSON++-- | Returns hash of block in best-block-chain at \<index\> transaction info+getBlockHash :: Int -> Call Hash256+getBlockHash n = makeCall "getblockhash" [n] myReadJSON ++{-+ ("hash",JSString (JSONString {fromJSString = "00000000000000205868fe2a3147ac3ca6061e5d21a4cfdf345adc0282993c68"}))+,("confirmations",JSRational False (1 % 1))+,("size",JSRational False (138687 % 1))+,("height",JSRational False (249228 % 1))+,("version",JSRational False (2 % 1))+,("merkleroot",JSString (JSONString {fromJSString = "fe750a784090601e6bda1fbb9da8f5528706844877892545db2d78702d7172b5"}))+,("tx",JSArray [ ... ] )+,("time",JSRational False (1375184425 % 1))+,("nonce",JSRational False (3818843198 % 1))+,("bits",JSString (JSONString {fromJSString = "1a008968"}))+,("difficulty",JSRational False (3125696072776893 % 100000000))+,("previousblockhash",JSString (JSONString {fromJSString = "0000000000000077d150668c20f4ee2bfd19696b14a134cdaf7dc682e82bcbe5"}))]}))+-}++-- | Returns information about the given block hash.+getBlockInfo :: Hash256 -> Call BlockInfo+getBlockInfo blockhash = makeCall "getblock" [blockhash] $ \js -> case js of+  JSObject obj -> +    case obj of+      _ | Just hash <- lkp "hash"+        , Just conf <- lkp "confirmations"+        , Just size <- lkp "size"+        , Just hght <- lkp "height"+        , Just ver  <- lkp "version"+        , Just root <- lkp "merkleroot"+        , Just txs  <- lkp "tx"+        , Just time <- lkp "time"+        , Just nonc <- lkp "nonce"+        , Just bstr <- lkp "bits" , Just bits <- parseBits bstr+        , Just diff <- lkp "difficulty"+        , mbprev    <- lkp "previousblockhash"+        , mbnext    <- lkp "nextblockhash"+                                                -> Just $ BlockInfo +                                                     hash+                                                     conf+                                                     size+                                                     hght+                                                     ver+                                                     root+                                                     txs+                                                     time+                                                     nonc+                                                     bits+                                                     diff+                                                     mbprev+                                                     mbnext+      _ -> Nothing+    where++      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON++      parseBits bitstring = case safeHexDecode bitstring of+        Just [a,b,c,d] -> Just $ shiftL (fromIntegral a) 24 +                               + shiftL (fromIntegral b) 16+                               + shiftL (fromIntegral c)  8+                               +        (fromIntegral d) +        Nothing -> Nothing++  _ -> Nothing++--------------------------------------------------------------------------------+-- * transaction info++data TxDetail = TxDetail +  { _txdAccount  :: Account+  , _txdAddress  :: Address+  , _txdCategory :: String+  , _txdAmount   :: Amount+  , _txdFee      :: Amount+  } +  deriving Show++data TxInfo = TxInfo+  { _txiAmount        :: Amount+  , _txiConfirmations :: Int                                      +  , _txiId            :: TxId+  , _txiTime          :: UnixTimeStamp+  , _txiDetails       :: [TxDetail]+  } +  deriving Show++instance JSON TxDetail where+  readJSON jsv = case parseTxDetail jsv of+    Nothing -> Error "TxDetail/readJSON: cannot parse"+    Just x  -> Ok x  +  showJSON = error "TxDetail/showJSON: not implemented"++parseTxDetail :: JSValue -> Maybe TxDetail+parseTxDetail jsv = case jsv of+  JSObject obj -> +    case obj of+      _ | Just acc  <- lkp "account"+        , Just addr <- lkp "address"+        , Just cat  <- lkp "category"+        , Just amt  <- lkp "amount"+        , Just fee  <- lkp "fee"+           -> Just $ TxDetail acc addr cat amt fee+      _ -> Nothing+    where+      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+  _ -> Nothing++parseTxInfo :: JSValue -> Maybe TxInfo+parseTxInfo jsv = case jsv of+  JSObject obj -> +    case obj of+      _ | Just amt  <- lkp "amount"+        , Just conf <- lkp "confirmations"+        , Just txid <- lkp "txid"+        , Just time <- lkp "time"+        , Just (JSArray dets) <- lkp "details"+        , mbdetails <- map parseTxDetail dets+        , all isJust mbdetails+           -> Just $ TxInfo amt conf txid time (catMaybes mbdetails)+      _ -> Nothing+    where+      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+  _ -> Nothing++-- | Returns an object about the given transaction. Note: this only works for the transaction in the wallet.+-- For transactions out in the blockchain, use "getRawTransaction" or "getTransactionInfo"+getWalletTransaction :: TxId -> Call TxInfo+getWalletTransaction txid = makeCall "getrawtransaction" (txid, (0::Int)) parseTxInfo++--------------------------------------------------------------------------------++-- | A scriptSig as returned by \"getrawtransaction\" (verbose=1) API call+data ScriptSigVerbose = ScriptSigVerbose+  { _scriptSigAsm :: String      -- ^ human-readable script+  , _scriptSigHex :: !RawScript  -- ^ raw script+  }+  deriving (Eq,Show)++parseScriptSigVerbose :: JSValue -> Maybe ScriptSigVerbose+parseScriptSigVerbose jsv = case jsv of+  JSObject obj -> +    case obj of+      _ | Just asm <- lkp "asm"+        , Just hex <- lkp "hex"+           -> Just $ ScriptSigVerbose asm hex+      _ -> Nothing+    where+      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+  _ -> Nothing++-- | A transaction input as returned by \"getrawtransaction\" (verbose=1) API call+data TxVIn = TxVIn                    +  { _vinTxId         :: !TxId              -- ^ hash of the input transaction+  , _vinVOut         :: !Int               -- ^ which output of the input transaction we spend+  , _vinScriptSig    :: !ScriptSigVerbose  -- ^ script signature+  , _vinSequence     :: !Word32            -- ^ sequence no+  } +  deriving (Eq,Show)++parseTxVIn :: JSValue -> Maybe TxVIn+parseTxVIn jsv = case jsv of+  JSObject obj -> +    case obj of+      _ | Just txid <- lkp "txid"+        , Just vout <- lkp "vout"+        , Just ssig <- lkp "scriptSig" , Just scriptSig <- parseScriptSigVerbose ssig+        , Just seqn <- lkp "sequence"+           -> Just $ TxVIn txid vout scriptSig seqn+      _ -> Nothing+    where+      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+  _ -> Nothing++-- | A scriptPubKey as returned by \"getrawtransaction\" (verbose=1) API call+data ScriptPubKeyVerbose = ScriptPubKeyVerbose+  { _scriptPubKeyAsm        :: String      -- ^ human-readable script+  , _scriptPubKeyHex        :: !RawScript  -- ^ raw script+  , _scriptPubKeyReqSigs    :: !Int        -- ^ required number of signatures+  , _scriptPubKeyType       :: String      -- ^ script type (eg. \"pubkeyhash\")+  , _scriptPubKeyAddresses  :: [Address]   -- ^ list of addresses+  }+  deriving (Eq,Show)++parseScriptPubKeyVerbose :: JSValue -> Maybe ScriptPubKeyVerbose+parseScriptPubKeyVerbose jsv = case jsv of+  JSObject obj -> +    case obj of+      _ | Just asm <- lkp "asm"+        , Just hex <- lkp "hex"+        , Just req <- lkp "reqSigs"+        , Just typ <- lkp "type"+        , Just (JSArray adrs) <- lkp "addresses"+        , let mbaddresses = map myReadJSON adrs+        , all isJust mbaddresses+           -> Just $ ScriptPubKeyVerbose asm hex req typ (catMaybes mbaddresses)+      _ -> Nothing+    where+      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+  _ -> Nothing++-- | A transaction output as returned by \"getrawtransaction\" (verbose=1) API call+data TxVOut = TxVOut+  { _voutValue        :: !Amount+  , _voutN            :: !Int+  , _voutScriptPubKey :: !ScriptPubKeyVerbose+  }+  deriving (Eq,Show)++parseTxVOut :: JSValue -> Maybe TxVOut+parseTxVOut jsv = case jsv of+  JSObject obj -> +    case obj of+      _ | Just amt  <- lkp "value"+        , Just n    <- lkp "n"+        , Just spub <- lkp "scriptPubKey" , Just scriptPubKey <- parseScriptPubKeyVerbose spub+           -> Just $ TxVOut amt n scriptPubKey+      _ -> Nothing+    where+      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+  _ -> Nothing++-- | A transaction as decoded by the \"decoderawtransaction\" API call+data TxVerbose = TxVerbose+  { _txvTxId          :: !TxId           -- ^ hash of the transaction+  , _txvVersion       :: !Int            -- ^ tx version+  , _txvLockTime      :: !LockTime       -- ^ lock time+  , _txvVIn           :: [TxVIn]         -- ^ transaction inputs+  , _txvVOut          :: [TxVOut]        -- ^ transaction outputs+  }+  deriving (Eq,Show)++parseTxVerbose :: JSValue -> Maybe TxVerbose+parseTxVerbose jsv = case jsv of+  JSObject obj -> +    case obj of+      _ | Just txid <- lkp "txid"+        , Just ver  <- lkp "version" +        , Just lock <- lkp "locktime"+        , Just (JSArray vins)  <- lkp "vin"+        , Just (JSArray vouts) <- lkp "vout"+        , let mbins = map parseTxVIn vins+        , all isJust mbins+        , let mbouts = map parseTxVOut vouts+        , all isJust mbouts+           -> Just $ TxVerbose txid ver (parseLockTime lock) (catMaybes mbins) (catMaybes mbouts) +      _ -> Nothing+    where+      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+  _ -> Nothing++-- | A transaction as reported by the \"getrawtransaction\" (verbose=1) API call+data TxVerboseEx = TxVerboseEx+  { _txeHex           :: !RawTx          -- ^ full raw transaction +  , _txeTxVerbose     :: !TxVerbose      -- ^ common details of the transaction+  , _txeBlockHash     :: !Hash256        -- ^ hash of the block containing the transaction (?)+  , _txeConfirmations :: !Int            -- ^ number of confirmations+  , _txeTime          :: !UnixTimeStamp  -- ^ timestamp of the transaction+  , _txeBlockTime     :: !UnixTimeStamp  -- ^ timestamp of the block+  } +  deriving (Eq,Show)++parseTxVerboseEx :: JSValue -> Maybe TxVerboseEx+parseTxVerboseEx jsv = case jsv of+  JSObject obj -> +    case obj of+      _ | Just hex     <- lkp "hex"+        , Just txid <- lkp "txid"+        , Just ver  <- lkp "version" +        , Just lock <- lkp "locktime"+        , Just (JSArray vins)  <- lkp "vin"+        , Just (JSArray vouts) <- lkp "vout"+        , let mbins = map parseTxVIn vins+        , all isJust mbins+        , let mbouts = map parseTxVOut vouts+        , all isJust mbouts+        , Just bhsh <- lkp "blockhash"+        , Just conf <- lkp "confirmations"+        , Just time <- lkp "time"+        , Just btim <- lkp "blocktime" +           -> Just $ TxVerboseEx hex (TxVerbose txid ver (parseLockTime lock) (catMaybes mbins) (catMaybes mbouts)) bhsh conf time btim+      _ -> Nothing+    where+      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+  _ -> Nothing++-- | \"getrawtransaction\", verbose=0. Version 0.7. Returns raw transaction representation for given transaction id.+--+-- WARNING! Important note from the version 0.8 readme:+--+-- \"This release no longer maintains a full index of historical transaction ids+-- by default, so looking up an arbitrary transaction using the getrawtransaction+-- RPC call will not work. If you need that functionality, you must run once+-- with -txindex=1 -reindex=1 to rebuild block-chain indices (see below for+-- more details).\"+--+getRawTransaction :: TxId -> Call RawTx+getRawTransaction txid = makeCall "getrawtransaction" (txid, (0::Int)) $ \js -> myReadJSON js++-- | \"getrawtransaction\", verbose=1. Version 0.7. Returns transaction representation for given transaction id, +-- in human-understandable format.+getTransactionInfo :: TxId -> Call TxVerboseEx +getTransactionInfo txid = makeCall "getrawtransaction" (txid, (1::Int)) parseTxVerboseEx ++decodeRawTransaction :: RawTx -> Call TxVerbose+decodeRawTransaction rawtx = makeCall "decoderawtransaction" [rawtx] parseTxVerbose++--------------------------------------------------------------------------------+-- * wallet info++validateAddress :: Address -> Call (JSObject JSValue)+validateAddress address = makeCall "validateaddress" [address] mbJSObject++-- | Reveals the private key corresponding to \<bitcoinaddress\>. NOTE: Wallet needs to be unlocked! +dumpPrivKeyWIF :: Address -> Call WIF+dumpPrivKeyWIF address = makeCall "dumpprivkey" [address] $ myReadJSON ++-- | We decode the WIF and also compute the corresponding public key for convenience.+dumpPrivPubKey :: Address -> Call (PrivKey,PubKey)+dumpPrivPubKey address = makeCall "dumpprivkey" [address] $ \js -> myReadJSON js >>= \s -> (f <$> privKeyWIFDecode (WIF s)) where+  f (pfmt,priv) = (priv, computePubKey pfmt priv)++-- | If @[account]@ is not specified, returns the server\'s total available balance. @MinConf = Maybe Int@ is the number of minimum confirmations (default is 1)+getBalance :: Maybe Account -> MinConf -> Call Amount+getBalance mbacc minconf = makeCall "getbalance" (maybe "" id mbacc , maybe 1 id minconf) myReadJSON++-- | Returns the /current/ bitcoin address for receiving payments to this account.   +getAccountAddress :: Account -> Call Address+getAccountAddress account = makeCall "getaccountaddress" [account] myReadJSON++-- | Returns the list of addresses for the given account.   +getAddressesByAccount :: Account -> Call [Address]+getAddressesByAccount account = makeCall "getaddressesbyaccount" [account] myReadJSON++-- | Returns the account associated with the given address.   +getAccount :: Address -> Call Account+getAccount address = makeCall "getaccount" [address] myReadJSON++-- | Returns a list of pairs that has account names as keys, account balances as values. Maybe Int is number of minimal confirmations (default is 1)+listAccounts :: MinConf -> Call [(Account,Amount)]+listAccounts minconf = makeCall "listaccounts" [maybe 1 id minconf] $ \jsv -> (g . map f . fromJSObject) =<< mbJSObject jsv where+  f :: (String,JSValue) -> (String, Maybe Amount)+  f (s,x) = (s,amountFromDouble <$> myReadJSON x)+  g ambs = if all (isJust . snd) ambs +    then Just $ map (\(s,mb) -> (s,fromJust mb)) ambs +    else Nothing++-- | version 0.7 Returns all addresses in the wallet and info used for coincontrol.   +--+-- Lists groups of addresses which have had their common ownership made public by +-- common use as inputs or as the resulting change in past transactions.+listAddressGroupings :: Call JSValue --  (JSObject JSValue) [[(Address,Amount,Account)]]+listAddressGroupings = makeCall "listaddressgroupings" () Just -- mbJSObject++--------------------------------------------------------------------------------++data Received = Received+  { _rcvAddress       :: Maybe Address+  , _rcvAccount       :: Account+  , _rcvAmount        :: Amount+  , _rcvConfirmations :: Int+  }+  deriving Show++parseReceived :: JSValue -> Maybe Received+parseReceived jsv = case jsv of+  JSObject obj -> +    case obj of+      _ | mbaddr    <- lkp "address"+        , Just acc  <- lkp "account"+        , Just amt  <- lkp "amount"+        , Just conf <- lkp "confirmations"+           -> Just $ Received mbaddr acc amt conf+      _ -> Nothing+    where+      lkp :: JSON a => String -> Maybe a+      lkp fld = get_field obj fld >>= myReadJSON+  _ -> Nothing++-- | Bool is \"includeempty\". Returns an array of objects containing: \"account\", \"amount\", \"confirmations\"+listReceivedByAccount :: MinConf -> Bool -> Call [Received]   +listReceivedByAccount minconf includeempty = +  makeCall "listreceivedbyaccount" (maybe 1 id minconf, includeempty) $ \jsv -> case jsv of+    JSArray arr -> +      if all isJust mbs +        then Just (catMaybes mbs) +        else Nothing +      where+        mbs = map parseReceived arr+    _ -> Nothing+++-- | Returns an array of objects containing: \"address\", \"account\", \"amount\", \"confirmations\". +--+-- To get a list of accounts on the system, execute bitcoind listreceivedbyaddress 0 true   +listReceivedByAddress :: MinConf -> Bool -> Call [Received]  +listReceivedByAddress minconf includeempty = +  makeCall "listreceivedbyaddress" (maybe 1 id minconf, includeempty) $ \jsv -> case jsv of+    JSArray arr -> +      if all isJust mbs +        then Just (catMaybes mbs) +        else Nothing +      where+        mbs = map parseReceived arr+    _ -> Nothing++--------------------------------------------------------------------------------++-- | An unspent transactions as returned by the \"listunspent\" API call+data Unspent = Unspent+  { _unsTxId          :: !TxId       -- ^ txid is the hexadecimal transaction id+  , _unsOutput        :: !Int        -- ^ output is which output of that transaction +  , _unsScriptPubKey  :: !RawScript  -- ^ scriptPubKey is the hexadecimal-encoded CScript for that output +  , _unsAmount        :: !Amount     -- ^ amount is the value of that output +  , _unsConfirmations :: !Int        -- ^ confirmations is the transaction's depth in the chain.+  } +  deriving (Eq, Show)++-- | Returns an array of unspent transaction outputs in the wallet that have between minconf and maxconf (inclusive) confirmations. +-- Each output is a 5-element object with keys: txid, output, scriptPubKey, amount, confirmations. +-- txid is the hexadecimal transaction id, output is which output of that transaction, +-- scriptPubKey is the hexadecimal-encoded CScript for that output, +-- amount is the value of that output and confirmations is the transaction's depth in the chain.+--+-- Minimum confirmations default is 1 and maximum confirmation default is 999999.+--+listUnspent :: MinConf -> MaxConf -> Call [Unspent]+listUnspent minconf maxconf = +  makeCall "listunspent" [maybe 1 id minconf, maybe 999999 id maxconf] $ \jsv -> case jsv of+    JSArray arr -> +      if all isJust mbs+        then Just (catMaybes mbs) +        else Nothing +      where+        mbs = map parseUnspent arr+    _ -> Nothing++  where++    parseUnspent :: JSValue -> Maybe Unspent+    parseUnspent jsv = case jsv of+      JSObject obj -> +        case obj of+          _ | Just txid   <- lkp "txid"+            , Just out    <- lkp "output"+            , Just script <- lkp "scriptPubKey"+            , Just amt    <- lkp "amount"+            , Just conf   <- lkp "confirmations"+               -> Just $ Unspent txid out script amt conf+          _ -> Nothing+        where+          lkp :: JSON a => String -> Maybe a+          lkp fld = get_field obj fld >>= myReadJSON+      _ -> Nothing++--------------------------------------------------------------------------------+-- * network info++-- | version 0.7: Returns all transaction ids in memory pool                                   +getRawMemPool :: Call [TxId]+getRawMemPool = makeCall "getrawmempool" () myReadJSON++--------------------------------------------------------------------------------+-- * multi-sig++-- | Add a n-required-to-sign multisignature address to the wallet. +-- Each key is a bitcoin address or hex-encoded public key. +-- If [account] is specified, assign address to [account].  +addMultiSigAddress :: Int -> [Key] -> Maybe Account -> Call Address+addMultiSigAddress n keys mbacc =+  if n > length keys || n < 1 +    then error "addMultiSigAddress: <nrequired> must be least 1 and at most the number of keys"+    else makeCall "addmultisigaddress" ( n , jskeys , maybe "" id mbacc ) myReadJSON+  where +    jskeys = map eiShowJSON keys++-- | Creates a multi-signature address and returns a json object.+createMultiSig :: Int -> [Key] -> Call (Address,RedeemScript)+createMultiSig n keys = +  if n > length keys || n < 1+    then error "createMultiSig: <nrequired> must be least 1 and at most the number of keys"+    else makeCall "createmultisig" ( n , jskeys ) $ \jsv -> case jsv of+      JSObject obj -> +        case obj of+          _ | Just addr   <- lkp "address"+            , Just script <- lkp "redeemScript"+                -> Just (addr,script)         +          _ -> Nothing+        where+          lkp :: JSON a => String -> Maybe a+          lkp fld = get_field obj fld >>= myReadJSON+      _ -> Nothing  +  where +    jskeys = map eiShowJSON keys++--------------------------------------------------------------------------------+-- * sending coins++-- | Send coins from an account to an address+--+-- > <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]. +--+-- Will send the given amount to the given address, ensuring the account has a valid +-- balance using [minconf] confirmations. Returns the transaction ID if successful +-- (not in JSON object). NOTE: Wallet needs to be unlocked! +--+-- \"comment\" is the transaction comment, and \"comment-to\" is a local comment: a reminder that+-- who did we sent the coins to? (?)+sendFrom :: Account -> Address -> Amount -> MinConf -> Maybe String -> Maybe String -> Call TxId+sendFrom account address amount minconf comment comment_to = +  makeCall "sendfrom" (account, address, amount, maybe 1 id minconf, maybe "" id comment, maybe "" id comment_to) myReadJSON++-- | Send coins from an account to many addresses +-- NOTE: Wallet needs to be unlocked! +sendMany :: Account -> [(Address,Amount)] -> MinConf -> Maybe String -> Call TxId+sendMany account destinations minconf comment = +  makeCall "sendmany" (account,destinations,maybe 1 id minconf, maybe "" id comment) myReadJSON++-- | version 0.7. Submits raw transaction (serialized, hex-encoded) to local node and network.   +sendRawTransaction :: RawTx -> Call ()+sendRawTransaction rawtx = makeCall "sendrawtransaction" [rawtx] $ \_ -> Just ()++-- | > <bitcoinaddress> <amount> [comment] [comment-to]+sendToAddress :: Address -> Amount -> Maybe String -> Maybe String -> Call TxId+sendToAddress address amount comment comment_to = +  makeCall "sendtoaddress" (address,amount,maybe "" id comment, maybe "" id comment_to) myReadJSON++-- | Move from one account in your wallet to another   +--+-- > <fromaccount> <toaccount> <amount> [minconf=1] [comment]. +--+moveCoins :: Account -> Account -> Amount -> MinConf -> Maybe String -> Call ()+moveCoins accfrom accto amount minconf comment = +  makeCall "move" (accfrom, accto, amount, maybe 1 id minconf, maybe "" id comment) $ \_ -> Just ()++-- | Sets the transaction fee+setTxFee :: Amount -> Call ()+setTxFee amount = makeCall "settxfee" [amount] $ \_ -> Just ()++--------------------------------------------------------------------------------+-- * wallet operations++-- | Adds a private key (as returned by dumpprivkey) to your wallet. The second argument is an optional label (account???).+-- This may take a while, as a rescan is done, looking for existing transactions. Optional [rescan] parameter added in 0.8.0. +-- NOTE: Wallet needs to be unlocked! +importPrivKey :: (PubKeyFormat,PrivKey) -> Maybe String -> Bool -> Call ()+importPrivKey (pkfmt,privkey) mblabel rescan = +  makeCall "importprivkey" ( privKeyWIFEncode pkfmt privkey , maybe "" id mblabel , rescan ) $ \_ -> Just ()++-- | Imports a private key given as WIF (Wallet Import Format).+importPrivKeyWIF :: WIF -> Maybe String -> Bool -> Call ()+importPrivKeyWIF wif mblabel rescan = +  makeCall "importprivkey" ( wif , maybe "" id mblabel , rescan ) $ \_ -> Just ()++-- | Returns a new bitcoin address for receiving payments. +-- If [account] is specified (recommended), it is added to the address book so payments +-- received with the address will be credited to [account].   +getNewAddress :: Maybe Account -> Call Address+getNewAddress mbacc = +  makeCall "getnewaddress" [ maybe "" id mbacc ] myReadJSON++-- | Sets the account associated with the given address. +-- Assigning address that is already assigned to the same account will create a new address associated with that account.+setAccount :: Address -> Account -> Call ()+setAccount address account = makeCall "setaccount" (address,account) $ \_ -> Just ()++-- | Fills the keypool, requires wallet passphrase to be set. NOTE: Wallet needs to be unlocked! +keyPoolRefill :: Call ()+keyPoolRefill = makeCall "keypoolrefill" () $ \_ -> Just ()++-- | Safely copies wallet.dat to destination, which can be a directory or a path with filename.  +backupWallet :: FilePath -> Call ()+backupWallet fpath = makeCall "backupwallet" [fpath] $ \_ -> Just ()++-- | Removes the wallet encryption key from memory, locking the wallet. +-- After calling this method, you will need to call walletpassphrase again +-- before being able to call any methods which require the wallet to be unlocked.   +walletLock :: Call ()+walletLock = makeCall "walletlock" () $ \_ -> Just ()++-- | Stores the wallet decryption key in memory for \<timeout\> seconds.   +walletPassPhrase :: PassPhrase -> Int -> Call ()+walletPassPhrase pw seconds = makeCall "walletpassphrase" (pw,seconds) $ \_ -> Just ()++-- | Changes the wallet passphrase from \<oldpassphrase\> to \<newpassphrase\>.  +walletPassPhraseChange :: PassPhrase -> PassPhrase -> Call ()+walletPassPhraseChange old new = makeCall "walletpassphrasechange" (old,new) $ \_ -> Just ()++-- | Encrypts the wallet with \<passphrase\>.   +encryptWallet :: PassPhrase -> Call ()+encryptWallet pw = makeCall "encryptwallet" [pw] $ \_ -> Just ()++--------------------------------------------------------------------------------+
+ Bitcoin/RPC/Call.hs view
@@ -0,0 +1,87 @@++-- | wrappers around the RPC calls++{-# LANGUAGE PatternGuards #-}+module Bitcoin.RPC.Call where++--------------------------------------------------------------------------------++import Data.Word++import Text.JSON +import Text.JSON.Types++import Control.Monad.Reader++import System.Random++import Bitcoin.Misc.Unique++import Bitcoin.RPC.JSON+import Bitcoin.RPC.HTTP++--------------------------------------------------------------------------------++-- | Type of an RPC call (without arguments)+type Call a = ReaderT BitcoinURI IO (Either String a)++-- | Executes the "call monad"+runCalls :: BitcoinURI -> ReaderT BitcoinURI IO a -> IO a+runCalls uri action = runReaderT action uri++--------------------------------------------------------------------------------++-- | Creates a unique request id, using a combination of a counter and a random number.+newRequestId :: IO String+newRequestId = do+  a <- randomRIO (1000000000,9999999999::Word64)+  b <- newUnique+  return (show a ++ ":" ++ show b)++--------------------------------------------------------------------------------++-- | Things which can be converted to an RPC call parameter list. +class ParamList l where+  paramListJSON :: l -> [JSValue]++instance ParamList () where paramListJSON _ = []++instance JSON a => ParamList [a] where+  paramListJSON xs = map showJSON xs++instance (JSON a, JSON b) => ParamList (a,b) where+  paramListJSON (x,y) = [showJSON x, showJSON y]++instance (JSON a, JSON b, JSON c) => ParamList (a,b,c) where+  paramListJSON (x,y,z) = [showJSON x, showJSON y, showJSON z]++instance (JSON a, JSON b, JSON c, JSON d) => ParamList (a,b,c,d) where+  paramListJSON (x,y,z,w) = [showJSON x, showJSON y, showJSON z, showJSON w]++instance (JSON a, JSON b, JSON c, JSON d, JSON e) => ParamList (a,b,c,d,e) where+  paramListJSON (x,y,z,w,u) = [showJSON x, showJSON y, showJSON z, showJSON w, showJSON u]++instance (JSON a, JSON b, JSON c, JSON d, JSON e, JSON f) => ParamList (a,b,c,d,e,f) where+  paramListJSON (x,y,z,w,u,v) = [showJSON x, showJSON y, showJSON z, showJSON w, showJSON u, showJSON v]++--------------------------------------------------------------------------------++-- | Generic API call+makeCall :: ParamList l => String -> l -> (JSValue -> Maybe a) -> Call a+makeCall method params parseResponse = do+  uri <- ask+  lift $ do+    reqid <- newRequestId+    let pars = paramListJSON params+    let req  = Request method pars reqid :: Request JSValue+    -- print req +    eiresp <- rpcCall uri req+    case eiresp of+      Left  err -> return (Left err)+      Right (Response result mberror respid) +        | respid  /= reqid                  ->  return (Left "response id does not match request id")+        | Just err <- mberror               ->  return (Left "err")+        | Just x <- parseResponse result    ->  return (Right x)+        | otherwise                         ->  return (Left "cannot parse response")++--------------------------------------------------------------------------------
+ Bitcoin/RPC/HTTP.hs view
@@ -0,0 +1,78 @@++-- | JSON-RPC over HTTP. We only support Basic Authentication at the moment.++{-# LANGUAGE CPP #-}+module Bitcoin.RPC.HTTP where++--------------------------------------------------------------------------------++import Data.Maybe++-- import qualified Data.ByteString.Char8 as B++import qualified Network.URI       as HTTP+import qualified Network.Stream    as HTTP+import qualified Network.HTTP.Base as HTTP+import qualified Network.HTTP      as HTTP++import Text.JSON++import Bitcoin.Protocol.Base64+import Bitcoin.RPC.JSON++--------------------------------------------------------------------------------++-- | An URI plus username/password for basic auth+data BitcoinURI = BitcoinURI (String,String) HTTP.URI deriving Show++-- | Example:+--+-- > myuri = bitcoinURI username password host port+--+-- Default host is 127.0.0.1, default port is 8332+--+bitcoinURI :: String -> String -> Maybe String -> Maybe Int -> BitcoinURI+bitcoinURI username pw mbhost mbport = BitcoinURI (username,pw) (fromJust (HTTP.parseURI text)) where+  host = case mbhost of { Nothing -> "127.0.0.1" ; Just h -> h }+  port = case mbport of +    Just p  -> p +#ifdef WITH_TESTNET+    Nothing -> 18332   +#else+    Nothing -> 8332   +#endif+  text = "http://" ++ host ++ ":" ++ show port ++ "/"++--------------------------------------------------------------------------------++rpcCall :: JSON a => BitcoinURI -> Request a -> IO (Either String Response)+rpcCall (BitcoinURI (uname,pw) uri) request = do++  let text = (Text.JSON.encode $ encodeRequest request) +  let Base64 unpw = base64Encode (uname ++ ":" ++ pw)+      auth = "Basic " ++ unpw++  -- print    auth                   -- debugging !!!!!!!!!!!!!!+  -- putStrLn text++  let headers = +        [ HTTP.Header HTTP.HdrContentType   "application/json-rpc"+        , HTTP.Header HTTP.HdrContentLength (show $ length text)         -- now, seriously... why do i have to do this manually??+        , HTTP.Header HTTP.HdrAccept        "application/json-rpc"+        , HTTP.Header HTTP.HdrAuthorization auth+        ]++  let req = HTTP.Request uri HTTP.POST headers text+  result <- HTTP.simpleHTTP req :: IO (Either HTTP.ConnError (HTTP.Response String))++  case result of+    Left connerror -> return $ Left ("HTTP connection error - " ++ show connerror)+    Right rsp -> case HTTP.rspCode rsp of+      (2,0,0) -> return $ case (Text.JSON.decode $ HTTP.rspBody rsp) of+                   Text.JSON.Error msg  -> Left ("cannot parse JSON - " ++ show msg)+                   Text.JSON.Ok jsvalue -> case decodeResponse jsvalue of+                     Just x  -> Right x+                     Nothing -> Left "cannot decode JSON-RPC response"+      (a,b,c) -> return $ Left ("HTTP error code " ++ show a ++ show b ++ show c ++ " - "  ++ HTTP.rspReason rsp)++--------------------------------------------------------------------------------
+ Bitcoin/RPC/JSON.hs view
@@ -0,0 +1,189 @@++-- | Simple JSON-RPC stuff, and JSON helper functions++{-# LANGUAGE CPP #-}+module Bitcoin.RPC.JSON where++--------------------------------------------------------------------------------++import Data.List ( sort )++import Control.Applicative++import Text.JSON++import qualified Data.ByteString as B++import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.HexString+import Bitcoin.Misc.UnixTime++import Bitcoin.Protocol.Hash+import Bitcoin.Protocol.Address+import Bitcoin.Protocol.Amount+import Bitcoin.Protocol.Base64+import Bitcoin.Protocol.Hash+import Bitcoin.Protocol.Key+import Bitcoin.Protocol.Signature++import Bitcoin.Script.Base+import Bitcoin.BlockChain.Base++--------------------------------------------------------------------------------+-- * JSON-RPC++type RequestId = String ++data Request a = Request+  { requestMethod :: String+  , requestParams :: [a]+  , requestId     :: RequestId+  } +  deriving Show++data Response = Response+  { responseResult :: JSValue+  , responseError  :: Maybe JSValue+  , responseId     :: RequestId+  }+  deriving Show++data Notification a = Notification+  { notifMethod :: String+  , notifParams :: [a]+  } +  deriving Show++--------------------------------------------------------------------------------++encodeRequest :: JSON a => Request a -> JSValue+encodeRequest (Request method params rqid) = JSObject $ toJSObject+  [ ( "method" , jsString method )+  , ( "params" , JSArray (map showJSON params) )+--  , ( "id"     , jsNumber rqid )+  , ( "id"     , jsString rqid )+  ]++encodeNotification :: JSON a => Notification a -> JSValue+encodeNotification (Notification method params) = JSObject $ toJSObject+  [ ( "method" , jsString method )+  , ( "params" , JSArray (map showJSON params) )+  ]++decodeResponse :: JSValue -> Maybe Response+decodeResponse jv = case jv of+  JSObject obj -> +    case (sort keys) of+      [ "error" , "id" , "result" ] -> case lkp "id" of+        JSString rqid -> Just $ Response (lkp "result") mberr rqid where +          rqid  = case lkp "id" of+--            JSRational _ r -> round r+            JSString s -> fromJSString s+            _          -> error "decodeResponse: request id is not a string"+          mberr = case lkp "error" of+            JSNull -> Nothing+            err    -> Just err+        _ -> Nothing+      _ -> Nothing+    where+      kvs   = fromJSObject obj+      keys  = map fst kvs      +      lkp k = case lookup k kvs of+        Just x  -> x+        Nothing -> error "decodeResponse: shouldn't happen"+  _ -> Nothing++--------------------------------------------------------------------------------+-- * misc helper functions++jsString :: String -> JSValue+jsString = JSString . toJSString++jsNumber :: Int -> JSValue+jsNumber i = JSRational False (fromIntegral i)++myReadJSON :: JSON a => JSValue -> Maybe a+myReadJSON js = case readJSON js of+  Ok y    -> Just y    +  Error _ -> Nothing ++mbJSObject :: JSValue -> Maybe (JSObject JSValue)+mbJSObject js = case js of +  JSObject obj -> Just obj+  _            -> Nothing++eiShowJSON :: (JSON a, JSON b) => Either a b -> JSValue +eiShowJSON (Left  x) = showJSON x+eiShowJSON (Right y) = showJSON y++--------------------------------------------------------------------------------+-- * JSON parsing for special types++{- +-- already defined in Text.JSON+instance Applicative Result where+  pure x = Ok x+  rf <*> rx = case rf of+    Error e1 -> Error e1+    Ok f     -> case rx of+      Error e2 -> Error e2+      Ok x     -> Ok (f x)+-}++--------------------------------------------------------------------------------+-- * JSON instances++instance JSON Hash256 where+  showJSON hash = showJSON $ unsafeReverseHexString $ toHexStringChars hash+  readJSON jsv  = case (readJSON jsv :: Result String) of +    Ok s | even (length s) -> case safeHexDecode (unsafeReverseHexString s) of+                                Just x  -> Ok (fromWord8List x)+                                Nothing -> Error "invalid characters in hex string"+         | otherwise       -> Error $ "hex string of odd length"+    Error s                -> Error s++instance JSON UnixTimeStamp where+  showJSON (UnixTimeStamp x) = showJSON x+  readJSON jsv = UnixTimeStamp <$> readJSON jsv++instance JSON Address where+  showJSON (Address x) = showJSON x+  readJSON jsv = Address <$> readJSON jsv++instance JSON Amount where+  showJSON x   = showJSON (doubleAmount x)+  readJSON jsv = amountFromDouble <$> readJSON jsv++-- | Unfortunately, Text.JSON already have a ByteString instance, which is different from what we need; hence this newtype+newtype BS = BS { unBS :: B.ByteString }++instance JSON BS where+  showJSON (BS bs)  = showJSON (toHexStringChars bs)+  readJSON hex = case readJSON hex of+    Ok s | even (length s) ->  case safeHexDecode s of+                                Just x  -> Ok (BS (fromWord8List x))+                                Nothing -> Error "invalid characters in hex string"+         | otherwise       -> Error $ "hex string of odd length"+    Error s                -> Error s++instance JSON PubKey where+  showJSON pubkey = showJSON $ BS (encodePubKeyNative pubkey :: B.ByteString)+  readJSON jsv    = case (readJSON jsv :: Result BS) of+                      Error err -> Error err+                      Ok bs -> case decodePubKey (unBS bs) of+                        Nothing -> Error "readJSON/PubKey: cannot decode pubkey"+                        Just pk -> Ok pk++instance JSON RawScript where+  showJSON (RawScript bs) = showJSON (BS bs)+  readJSON jsv = (RawScript . unBS) <$> readJSON jsv++instance JSON RawTx where+  showJSON (RawTx bs) = showJSON (BS bs)+  readJSON jsv = (RawTx . unBS) <$> readJSON jsv++instance JSON WIF where+  showJSON (WIF wif) = showJSON wif  +  readJSON jsv = WIF <$> readJSON jsv++--------------------------------------------------------------------------------
+ Bitcoin/Script/Base.hs view
@@ -0,0 +1,266 @@++-- | Bitcoin scripts++{-# LANGUAGE PatternGuards #-}+module Bitcoin.Script.Base where++--------------------------------------------------------------------------------++import Data.Int+import Data.Word++import Text.Show++import qualified Data.ByteString as B++import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.HexString++import Bitcoin.Protocol.Hash++import Bitcoin.Script.Integer++--------------------------------------------------------------------------------++-- | A raw script (octet stream)+newtype RawScript = RawScript { fromRawScript :: B.ByteString } deriving Eq++-- | A parsed script (opcode stream)+newtype Script = Script { fromScript :: [Opcode] } deriving Eq++-- | The 160-bit hash of a (raw) script+newtype ScriptHash = ScriptHash { fromScriptHash  :: Hash160 } deriving (Eq,Show)++emptyRawScript :: RawScript+emptyRawScript = RawScript (B.empty)++emptyScript :: Script+emptyScript = Script []++scriptHash :: RawScript -> ScriptHash+scriptHash = ScriptHash . doHash160 . fromRawScript++instance OctetStream ScriptHash where+  toByteString   = toByteString . fromScriptHash+  fromByteString = ScriptHash . fromByteString++instance OctetStream RawScript where+  toByteString   = fromRawScript+  fromByteString = RawScript++instance Show RawScript where+  showsPrec d (RawScript rs) = showParen (d>10) $ showString "rawScriptFromString " . shows (toHexStringChars rs)++instance Show Script where+  showsPrec d (Script opcodes) = showParen (d>10) $ showString "Script " . (showOpcodeList opcodes)++rawScriptFromString :: String -> RawScript+rawScriptFromString s = if odd (length s)+  then error "rawScriptFromString: hex string should have even length"+  else RawScript $ fromHexString $ HexString s++--------------------------------------------------------------------------------+-- * shorthands++-- | @OP_FALSE@ = @OP_0@ = 0x00 = pushes an empty array to stack. +op_FALSE :: Opcode+op_FALSE = OP_SMALLNUM 0+-- | @OP_TRUE@ = @OP_1@ = 0x51 = pushes the number 1 onto the stack+op_TRUE :: Opcode+op_TRUE  = OP_SMALLNUM 1++-- | Pushes the corresponding number to the stack (0 is represented by an empty array)+op_0 :: Opcode+op_0 = OP_SMALLNUM 0+op_1 :: Opcode+op_1 = OP_SMALLNUM 1+op_2 :: Opcode+op_2 = OP_SMALLNUM 2+op_3 :: Opcode+op_3 = OP_SMALLNUM 3++-- | Handy shorthands for comparisons+op_LT :: Opcode+op_LT = OP_LESSTHAN+op_GT :: Opcode+op_GT = OP_GREATERTHAN+op_LE :: Opcode+op_LE = OP_LESSTHANOREQUAL+op_GE :: Opcode+op_GE = OP_GREATERTHANOREQUAL++-- | Figures out which opcode to use+op_PUSHDATA :: B.ByteString -> Opcode+op_PUSHDATA bs = let l = B.length bs in case l of+    0                  -> OP_SMALLNUM 0       -- OP_0 = push empty array+    _ | l>=1 && l<=75  -> OP_PUSHDATA (fromIntegral l) bs+    _ | l<=255         -> OP_PUSHDATA 76 bs+    _ | l<=65536       -> OP_PUSHDATA 77 bs +    _                  -> OP_PUSHDATA 78 bs++-- | Pushes a (signed) integer onto the stack, +-- never using OP_SMALLNUM (except for 0, which is represented by the empty array)+op_BIGNUMBER :: Integer -> Opcode+op_BIGNUMBER n = op_PUSHDATA (asByteString n)++--------------------------------------------------------------------------------+-- * opcodes++-- | See <https://en.bitcoin.it/wiki/Script>+data Opcode+  +  -- data+  = OP_SMALLNUM !Int                    -- ^ OP_0, OP_1 .. OP_16 (bytes 0,81,82..96). Pushes the number to the stack (0 is represented by an empty array)+  | OP_1NEGATE                          -- ^ The number -1 is pushed onto the stack.+  | OP_PUSHDATA !Word8 !B.ByteString    -- ^ Pushes data to the stack. The Word8 is the opcode: it can be 0, 1..75 and 76,77,78. ++  -- control flow+  | OP_NOP !Word8          -- ^ Does nothing. The argument is the opcode, either 0x61 or 0xb0-0xb9+  | OP_IF                  -- ^ If the top stack value is not 0, the statements are executed. The top stack value is removed.+  | OP_NOTIF               -- ^ If the top stack value is 0, the statements are executed. The top stack value is removed.+  | OP_ELSE                -- ^ If the preceding OP_IF or OP_NOTIF or OP_ELSE was not executed then these statements are and if the preceding OP_IF or OP_NOTIF or OP_ELSE was executed then these statements are not.+  | OP_ENDIF               -- ^ Ends an if/else block.+  | OP_VERIFY              -- ^ Marks transaction as invalid if top stack value is not true. True is removed, but false is not.+  | OP_RETURN              -- ^ Marks transaction as invalid.++  -- stack+  | OP_TOALTSTACK          -- ^ Puts the input onto the top of the alt stack. Removes it from the main stack. +  | OP_FROMALTSTACK        -- ^ Puts the input onto the top of the main stack. Removes it from the alt stack. +  | OP_IFDUP               -- ^ If the top stack value is not 0, duplicate it. +  | OP_DEPTH               -- ^ Puts the number of stack items onto the stack. +  | OP_DROP                -- ^ Removes the top stack item. +  | OP_DUP                 -- ^ Duplicates the top stack item. +  | OP_NIP                 -- ^ Removes the second-to-top stack item. +  | OP_OVER                -- ^ Copies the second-to-top stack item to the top. +  | OP_PICK                -- ^ The item n back in the stack is copied to the top. +  | OP_ROLL                -- ^ The item n back in the stack is moved to the top. +  | OP_ROT                 -- ^ The top three items on the stack are rotated to the left. +  | OP_SWAP                -- ^ The top two items on the stack are swapped. +  | OP_TUCK                -- ^ The item at the top of the stack is copied and inserted before the second-to-top item. +  | OP_2DROP               -- ^ Removes the top two stack items. +  | OP_2DUP                -- ^ Duplicates the top two stack items. +  | OP_3DUP                -- ^ Duplicates the top three stack items. +  | OP_2OVER               -- ^ Copies the pair of items two spaces back in the stack to the front. +  | OP_2ROT                -- ^ The fifth and sixth items back are moved to the top of the stack. +  | OP_2SWAP               -- ^ Swaps the top two pairs of items.++  -- splice+  | OP_CAT        -- ^ Concatenates two strings. Currently disabled. +  | OP_SUBSTR     -- ^ Returns a section of a string. Currently disabled. +  | OP_LEFT       -- ^ Keeps only characters left of the specified point in a string. Currently disabled. +  | OP_RIGHT      -- ^ Keeps only characters right of the specified point in a string. Currently disabled. +  | OP_SIZE       -- ^ Returns the length of the input string. ++  -- bitwise logic+  | OP_INVERT         -- ^ Flips all of the bits in the input. Currently disabled. +  | OP_AND            -- ^ Boolean and between each bit in the inputs. Currently disabled. +  | OP_OR             -- ^ Boolean or between each bit in the inputs. Currently disabled. +  | OP_XOR            -- ^ Boolean exclusive or between each bit in the inputs. Currently disabled. +  | OP_EQUAL          -- ^ Returns 1 if the inputs are exactly equal, 0 otherwise. +  | OP_EQUALVERIFY    -- ^ Same as OP_EQUAL, but runs OP_VERIFY afterward.++  -- arithmetic+  | OP_1ADD          -- ^ 1 is added to the input. +  | OP_1SUB          -- ^ 1 is subtracted from the input. +  | OP_2MUL          -- ^ The input is multiplied by 2. Currently disabled. +  | OP_2DIV          -- ^ The input is divided by 2. Currently disabled. +  | OP_NEGATE        -- ^ The sign of the input is flipped. +  | OP_ABS           -- ^ The input is made positive. +  | OP_NOT           -- ^ If the input is 0 or 1, it is flipped. Otherwise the output will be 0. +  | OP_0NOTEQUAL     -- ^ Returns 0 if the input is 0. 1 otherwise. +  | OP_ADD           -- ^ a is added to b. +  | OP_SUB           -- ^ b is subtracted from a. +  | OP_MUL           -- ^ a is multiplied by b. Currently disabled. +  | OP_DIV           -- ^ a is divided by b. Currently disabled. +  | OP_MOD           -- ^ Returns the remainder after dividing a by b. Currently disabled. +  | OP_LSHIFT            -- ^ Shifts a left b bits, preserving sign. Currently disabled. +  | OP_RSHIFT             -- ^ Shifts a right b bits, preserving sign. Currently disabled. +  | OP_BOOLAND            -- ^ If both a and b are not 0, the output is 1. Otherwise 0. +  | OP_BOOLOR             -- ^ If a or b is not 0, the output is 1. Otherwise 0. +  | OP_NUMEQUAL           -- ^ Returns 1 if the numbers are equal, 0 otherwise. +  | OP_NUMEQUALVERIFY     -- ^ Same as OP_NUMEQUAL, but runs OP_VERIFY afterward. +  | OP_NUMNOTEQUAL        -- ^ Returns 1 if the numbers are not equal, 0 otherwise. +  | OP_LESSTHAN           -- ^ Returns 1 if a is less than b, 0 otherwise. +  | OP_GREATERTHAN        -- ^ Returns 1 if a is greater than b, 0 otherwise. +  | OP_LESSTHANOREQUAL    -- ^ Returns 1 if a is less than or equal to b, 0 otherwise. +  | OP_GREATERTHANOREQUAL -- ^ Returns 1 if a is greater than or equal to b, 0 otherwise. +  | OP_MIN                -- ^ Returns the smaller of a and b. +  | OP_MAX                -- ^ Returns the larger of a and b. +  | OP_WITHIN             -- ^ Returns 1 if x is within the specified range (left-inclusive), 0 otherwise++  -- crypto+  | OP_RIPEMD160           -- ^ The input is hashed using RIPEMD-160. +  | OP_SHA1                -- ^ The input is hashed using SHA-1. +  | OP_SHA256              -- ^ The input is hashed using SHA-256. +  | OP_HASH160             -- ^ The input is hashed twice: first with SHA-256 and then with RIPEMD-160. +  | OP_HASH256             -- ^ The input is hashed two times with SHA-256. +  | OP_CODESEPARATOR       -- ^ All of the signature checking words will only match signatures to the data after the most recently-executed OP_CODESEPARATOR. +  | OP_CHECKSIG            -- ^ The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise. +  | OP_CHECKSIGVERIFY      -- ^ Same as OP_CHECKSIG, but OP_VERIFY is executed afterward. +  | OP_CHECKMULTISIG       -- ^ For each signature and public key pair, OP_CHECKSIG is executed. If more public keys than signatures are listed, some key/sig pairs can fail. All signatures need to match a public key. If all signatures are valid, 1 is returned, 0 otherwise. Due to a bug, one extra unused value is removed from the stack. +  | OP_CHECKMULTISIGVERIFY -- ^ Same as OP_CHECKMULTISIG, but OP_VERIFY is executed afterward.++  -- reserved words+  | OP_RESERVED           -- ^ Transaction is invalid unless occuring in an unexecuted OP_IF branch+  | OP_VER                -- ^ Transaction is invalid unless occuring in an unexecuted OP_IF branch+  | OP_VERIF              -- ^ Transaction is invalid even when occuring in an unexecuted OP_IF branch+  | OP_VERNOTIF           -- ^ Transaction is invalid even when occuring in an unexecuted OP_IF branch+  | OP_RESERVED1          -- ^ Transaction is invalid unless occuring in an unexecuted OP_IF branch+  | OP_RESERVED2          -- ^ Transaction is invalid unless occuring in an unexecuted OP_IF branch++  -- pseudo+  | OP_INVALIDOPCODE      -- ^ this is a pseudo opcode, but it appears in the testnet3 blockchain...+  | OP_UNKNOWN !Word8     -- ^ unknown opcodes also appear in the testnet, inside (unexecuted?) OP_IF branches...++  deriving (Eq,Show)++--------------------------------------------------------------------------------+-- * helper functions++-- | Note: this function returns 'Nothing' for @OP_0@ (which technically pushes an empty array to the stack).+-- Also we don't check for validity (see 'is_valid_pushdata')+is_op_pushdata :: Opcode -> Maybe B.ByteString+is_op_pushdata op = case op of { OP_PUSHDATA _ bs -> Just bs ; _ -> Nothing }++-- | Note that OP_0 = push empty array, so we accept that as a valid @OP_PUSHDATA@+is_valid_pushdata :: Word8 -> B.ByteString -> Bool+is_valid_pushdata op bs +  | op>=0 && op<=75   =  (n == fromIntegral op)    +  | op==76            =  (n <= 255) +  | op==77            =  (n <= 65535)+  | op==78            =  True+  | otherwise         =  False+  where+    n = B.length bs++is_op_smallnum :: Opcode -> Maybe Int+is_op_smallnum op = case op of { OP_SMALLNUM k  -> Just k  ; _ -> Nothing }++is_nop :: Word8 -> Bool+is_nop w8 = case w8 of+  0x61                         -> True             -- OP_NOP+  _ | w8 >= 0xb0 && w8 <= 0xb9 -> True             -- OP_NOP1 .. OP_NOP10+  _                            -> False++--------------------------------------------------------------------------------++showOpcode :: Opcode -> (String -> String)+showOpcode op = case op of+  OP_PUSHDATA w8 dat -> showString "OP_PUSHDATA <0x"+                          . showString (showHexWord8 w8) +                          . showString "> \"" +                          . showString (toHexStringChars dat) +                          . showChar '\"'+  _                  -> shows op++showList' :: (a -> (String -> String)) ->  [a] -> (String -> String)+showList' _     []     s = "[]" ++ s+showList' showx (x:xs) s = '[' : showx x (showl xs)+  where+    showl []     = ']' : s+    showl (y:ys) = ',' : showx y (showl ys)++showOpcodeList :: [Opcode] -> (String -> String)+showOpcodeList list = showList' showOpcode list ++--------------------------------------------------------------------------------
+ Bitcoin/Script/Integer.hs view
@@ -0,0 +1,81 @@++-- | Numbers in Bitcoin scripts++{-# LANGUAGE PatternGuards #-}+module Bitcoin.Script.Integer where++--------------------------------------------------------------------------------++import Data.Int+import Data.Word+import Data.Bits+import Data.List ( unfoldr , splitAt , mapAccumL )+import Data.Maybe++import Control.Monad+import Control.Applicative++import Data.ByteString (ByteString)+import qualified Data.ByteString as B++import Bitcoin.Misc.BigInt+import Bitcoin.Misc.OctetStream++--------------------------------------------------------------------------------+-- * signs++-- | Positive actually means non-negative here, but it looks better (and is easier to read) this way+data Sign = Positive | Negative  ++signOf :: Integer -> Sign+signOf n = if n<0 then Negative else Positive++toSignAbs :: Integer -> (Sign,Integer)+toSignAbs n = (signOf n, abs n)++fromSignAbs :: (Sign,Integer) -> Integer+fromSignAbs (sign,absn) = case sign of+  Positive -> absn+  Negative -> negate absn++--------------------------------------------------------------------------------+-- * Bitcoin's special ByteString <-> Integer conversion++-- | Byte vectors are interpreted as little-endian variable-length integers +-- with the most significant bit determining the sign of the integer. Thus +-- 0x81 represents -1. 0x80 is another representation of zero (so called +-- negative 0). Byte vectors are interpreted as Booleans where False is +-- represented by any representation of zero, and True is represented by +-- any representation of non-zero.+asInteger :: B.ByteString -> Integer+asInteger bs = +  case sign of+    Positive -> absn+    Negative -> negate absn+  where+    absn = littleEndianRollInteger ws+    (sign,ws) = decodeSign (B.unpack bs)++asByteString :: Integer -> B.ByteString+asByteString 0 = B.empty+asByteString n = B.pack $ encodeSign (signOf n) $ littleEndianUnrollInteger (abs n)++encodeSign :: Sign -> [Word8] -> [Word8]+encodeSign sign = go where+  go ws = case ws of+    (x:rest@(y:_)) -> x : go rest+    [last]         -> if last < 0x80 +                        then case sign of { Positive -> [last] ; Negative -> [last + 0x80] }+                        else last : go []+    []             -> [ case sign of { Positive -> 0 ; Negative -> 0x80 } ]++decodeSign :: [Word8] -> (Sign,[Word8])+decodeSign = go where+  go ws = case ws of+    (x:rest@(y:_)) -> let (sign,xs) = go rest in (sign,x:xs)+    [last]         -> if last < 0x80 +                        then (Positive, [last     ] )+                        else (Negative, [last-0x80] )+    []             -> ( Positive , [] )++--------------------------------------------------------------------------------
+ Bitcoin/Script/Run.hs view
@@ -0,0 +1,1048 @@++-- | Bitcoin script interpreter++{-# LANGUAGE PatternGuards, ScopedTypeVariables, PackageImports #-}+module Bitcoin.Script.Run+  ( +  -- * types+    Entry , InterpreterConfig(..) , InterpreterState(..) , ScriptMonad +  -- * high level functions+  , checkTransaction +  -- * medium level functions+  , isDisabledOpcode +  , initialState+  , executeScript , runScriptPre, runScriptFinal+  , scriptStep , scriptStep' +  , isFalse, isTrue+  -- * internal types+  , Stream(..) , Context(..) , Hole(..) +  , IfBranch(..) , IfType(..) , IfBlock(..)+  -- * some internal functions+  , streamMoveRight+  , fetchOpcode , fetchOpcodeWithinContext+  , fetchIfBlock+  , reconstructIfBlock+  -- * script monad+  , invalid+  , getState+  , putState+  -- * push\/pop+  , pushData , popData+  , pushAltData , popAltData+  , pushInteger , popInteger+  , pushBool , popBool+  -- * parsing (should be elsewhere)+  , parseTxScripts      +  , parseTxInScripts      +  , parseTxOutScripts      +  , parseSingleTxOutScript+  )  +  where++--------------------------------------------------------------------------------++import Data.Int+import Data.Word+import Data.Bits+import Data.List ( unfoldr , splitAt , mapAccumL )+import Data.Maybe++import Control.Monad+import Control.Applicative++import Control.Monad.Trans.Class+import Control.Monad.Trans.Except+import Control.Monad.Trans.Reader+import Control.Monad.Trans.State+import Control.Monad.Identity++import qualified Data.ByteString as B++import Bitcoin.Misc.Bifunctor+import Bitcoin.Misc.BigInt+import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.Zipper as Zipper++import Bitcoin.Crypto.Hash.SHA1+import Bitcoin.Crypto.Hash.SHA256+import Bitcoin.Crypto.Hash.RipEmd160++import Bitcoin.Crypto.EC.Curve+import Bitcoin.Crypto.EC.Key+import Bitcoin.Crypto.EC.DSA++import Bitcoin.Protocol.Hash+import Bitcoin.Protocol.Key+import Bitcoin.Protocol.Signature++import Bitcoin.BlockChain.Base+import Bitcoin.BlockChain.Parser ( serializeTx )+import Bitcoin.BlockChain.Tx++import Bitcoin.Script.Base+import Bitcoin.Script.Integer+import Bitcoin.Script.Serialize++--------------------------------------------------------------------------------++isDisabledOpcode :: Opcode -> Bool+isDisabledOpcode op = case op of++  -- splice+  OP_CAT       -> True+  OP_SUBSTR    -> True+  OP_LEFT      -> True+  OP_RIGHT     -> True++  -- bitwise logic+  OP_INVERT    -> True+  OP_AND       -> True+  OP_OR        -> True+  OP_XOR       -> True++  -- arithmetic+  OP_2MUL      -> True+  OP_2DIV      -> True+  OP_MUL       -> True+  OP_DIV       -> True+  OP_MOD       -> True+  OP_LSHIFT    -> True+  OP_RSHIFT    -> True++  _ -> False++--------------------------------------------------------------------------------++-- | An opcode stream consist of a zipper of opcodes, and a "Context" which+-- describes (possibly recursively) what is on the left and right side of +-- this zipper. This is used for executing (possibly nested) OP_IF blocks. +--+-- This may be overly complicated :)+--+data Stream = Stream +  { _streamContext :: Context+  , _streamZipper  :: Zipper Opcode+  }+  deriving Show++-- | A context of opcodes and (nested) if blocks+data Context +  = CtxEmpty                                         -- ^ we are the full opcode stream+  | CtxHole Context [Opcode] IfType Hole [Opcode]    -- ^ a hole has an outer context, opcodes on the left and right, and an if block in the middle+  deriving Show++data Hole +  = HoleThen  { _elsePart :: Maybe [Opcode] }    -- ^ we are in the \"then\" branch+  | HoleElse  { _thenPart   :: [Opcode] +              , _elseExists :: Bool }            -- ^ we are in the \"else\" branch (which may not physically exists - this is important when reconstructing)+  deriving Show++toListIfPart :: [Opcode] -> [Opcode]+toListIfPart ops = OP_IF : ops++toListElsePart :: Maybe [Opcode] -> [Opcode]+toListElsePart mbops = case mbops of +  Nothing  -> []+  Just ops -> OP_ELSE : ops++flattenStreamToList :: Stream -> [Opcode]+flattenStreamToList (Stream ctx zipper) = worker ctx (zipperToList zipper) where+  worker ctx list = case ctx of+    CtxEmpty                      -> list+    CtxHole outer left typ hole right -> worker outer $ case hole of +      HoleThen elsePart        -> ifOpcode typ : list     ++  toListElsePart elsePart                ++ [OP_ENDIF]+      HoleElse thenPart exists -> ifOpcode typ : thenPart ++ (if exists then (OP_ELSE:list) else []) ++ [OP_ENDIF]+      -- note: if `exists' is False then `list' must be empty++flattenStreamToZipper :: Stream -> Zipper Opcode+flattenStreamToZipper (Stream ctx zipper) = worker ctx zipper where+  worker ctx zip@(Zipper ys xs) = case ctx of+    CtxEmpty                      -> zip+    CtxHole outer left typ hole right -> worker outer $ case hole of +      HoleThen elsePart -> Zipper +        (ys ++ ifOpcode typ : reverse left)+        (xs ++ toListElsePart elsePart ++ OP_ENDIF : right)+      HoleElse thenPart exists -> Zipper +        (ys ++ (if exists then [OP_ELSE] else []) ++ reverse thenPart ++ ifOpcode typ : reverse left)   +        (xs ++ OP_ENDIF : right)+        -- note: if `exists' is False then `xs' and `ys' must be empty++-- | Even where there is nothing on the right, we can change the stream itself during the discovery of this fact!+streamMoveRight :: Stream -> Either Stream (Opcode,Stream)+streamMoveRight fullStream@(Stream ctx zipper) = +  case Zipper.moveRight zipper of +    Just (x,zipper') -> Right (x, Stream ctx zipper')+    Nothing -> case ctx of+      CtxEmpty -> Left fullStream+      CtxHole outer left typ hole right -> streamMoveRight $ Stream outer $ case hole of +        HoleThen elsePart        -> mkZipper (left ++ ifOpcode typ : zipperToList zipper ++  toListElsePart elsePart                               ++ [OP_ENDIF]) right+        HoleElse thenPart exists -> mkZipper (left ++ ifOpcode typ : thenPart            ++ (if exists then OP_ELSE : zipperToList zipper else []) ++ [OP_ENDIF]) right+        -- note: if `exists' is False then `zipperToList zipper' must be empty++--------------------------------------------------------------------------------+-- * Script interpreter++-- | Stack entry+type Entry = B.ByteString++-- | Two stacks, an opcode stream (the latter necessary for the somewhat convoluted IF parsing, and also for OP_CHECKSIG)+data InterpreterState = St +  { _mainStack    :: [Entry]                -- ^ the main stack+  , _altStack     :: [Entry]                -- ^ the alt stack+  , _opcodeStream :: Stream                 -- ^ the opcode stream+  }+  deriving Show++-- | Empty stacks, empty script+initialState :: InterpreterState+initialState = St [] [] (Stream CtxEmpty (Zipper [] []))++data InterpreterConfig = Cfg+  { _newTx      :: !(Tx RawScript RawScript)  -- ^ the /new/ tx we are running (containing the scriptSigs which are combined with the previous tx's pubKeyScripts)+  , _curTxInIdx :: !Int                       -- ^ the index of the current transaction input (within the /new/ tx) we are checking+  }+  deriving Show++-- | Interpreter monad+type ScriptMonad a = ExceptT String (StateT InterpreterState (ReaderT InterpreterConfig Identity)) a++--------------------------------------------------------------------------------++-- | Given a transaction together with its inputs, we check if it is valid or not.+-- This is done by combining the input scripts of this transaction with the output+-- scripts of the previous transactions, and running the resulting scripts+--+-- If any of the scripts fails, the cause of failure is returned; if the scripts runs correctly,+-- the result is returned (which should be 'True' for valid transactions)+--+checkTransaction :: forall a. Tx (Tx a RawScript, RawScript) RawScript -> Either String Bool+checkTransaction txExt = result where++  result = if fee >= 0 +    then (go 0 insExt)+    else Left "total transaction output is more than total input"++  newtx  = fmapFst snd txExt :: Tx RawScript RawScript+  insExt = _txInputs txExt :: [TxInput (Tx a RawScript, RawScript)]++  fee = txFee (fmapFst fst txExt)++  go :: Int -> [TxInput (Tx a RawScript, RawScript)] -> Either String Bool+  go _ []          = Right True+  go j (this:rest) = +    case parseSingleTxOutScript previdx prevtx_raw of+      Left err       -> Left err+      Right prevtxei -> case parseScript (_txInScript thisin_raw) of +        Nothing       -> Left $ "cannot parse input script #" ++ show j+        Just inscript -> case runScriptPre cfg initialState inscript of+          (Left  err, _    ) -> Left err+          (Right _  , St mainstack _ _) -> +            let prevout_raw = (_txOutputs prevtx_raw) !! previdx+                ei_prevout  = (_txOutputs prevtxei  ) !! previdx :: TxOutput (Either RawScript Script)+                -- NOTE: only the main stack is shared between sig and pk scripts, the alt stack is not!+                state'      = St mainstack [] (error "checkTransaction: stream shouldn't be evaluated")+            in  case _txOutScript ei_prevout of+                  Left  _raw_     -> Left "this shouldn't happen: parsed something else we wanted to parse"+                  Right outscript -> if _txHash prevtx_raw /= prevhash+                    then Left $ "fatal error: hash of input tx #" ++ show j ++ " does not match"+                    else case fst $ runScriptFinal cfg state' (outscript) of+                      Left err -> Left err+                      Right b  -> case b of+                        False -> Left $ "tx input #" ++ show j ++ " failed to check"+                        True  -> go (j+1) rest+    where+      cfg = Cfg newtx j+      prevtx_raw = fst (_txInScript this) :: Tx a RawScript+      thisin_raw = fmap snd this          :: TxInput RawScript+      previdx  = fromIntegral (_txInPrevOutIdx  thisin_raw) :: Int+      prevhash =               _txInPrevOutHash thisin_raw  :: Hash256++--------------------------------------------------------------------------------+    +-- | Tries to parse all scripts, both input and output. Since the output scripts can fail to parse (see below),+-- this may also fail.+parseTxScripts :: Tx RawScript RawScript -> Either String (Tx Script Script)+parseTxScripts tx = +  case mapAccumLBoth (parseHelperFun tx) (parseHelperFun tx) Nothing tx of+    (Nothing ,tx') -> Right tx'+    (Just err,_  ) -> Left  err++-- | Tries to parse all input scripts. This shouldn't fail for a valid transaction.+parseTxInScripts :: Tx RawScript a -> Either String (Tx Script a)+parseTxInScripts tx = +  case mapAccumLFst (parseHelperFun tx) Nothing tx of+    (Nothing ,tx') -> Right tx'+    (Just err,_  ) -> Left  err++-- | Tries to parse all output scripts. This may fail because invalid output scripts are allowed, just unspendable... :(+parseTxOutScripts :: Tx a RawScript -> Either String (Tx a Script)+parseTxOutScripts tx = +  case mapAccumLSnd (parseHelperFun tx) Nothing tx of+    (Nothing ,tx') -> Right tx'+    (Just err,_  ) -> Left  err++-- | Parses only a single output script, leaves the rest (reason: tx validation shouldn\'t fail just+-- because there are other invalid scripts in the prev tx unrelated to this one).+parseSingleTxOutScript :: Int -> Tx a RawScript -> Either String (Tx a (Either RawScript Script))+parseSingleTxOutScript j tx = +  case mapAccumLSnd worker (Nothing,0) tx of+    ((Nothing ,_),tx') -> Right tx'+    ((Just err,_),_  ) -> Left  err+  where+    worker :: (Maybe String,Int) -> RawScript -> ((Maybe String,Int),Either RawScript Script)+    worker (mberr,k) raw = case mberr of+      Just err -> ((mberr,k),undef)+      Nothing  -> if (k/=j) +        then ((mberr,k+1),Left raw)+        else case parseScript raw of +          Just script -> ((mberr,k+1),Right script)+          Nothing     -> ((Just ("cannot parse script in output " ++ show k ++ " of tx # " ++ show (_txHash tx)),k), undef) +    undef = error "parseSingleTxOutScript/worker: this shouldn't be evaluated"++-- | Helper function.+parseHelperFun :: Tx a b -> Maybe String -> RawScript -> (Maybe String, Script)+parseHelperFun tx mberr rawscript = +  case mberr of+    Just err -> (mberr,undef)+    Nothing  -> case parseScript rawscript of+      Just script -> (mberr, script)+      Nothing     -> (Just ("cannot parse script in tx # " ++ show (_txHash tx)), undef) +  where+    undef = error "parseHelperFun: this shouldn't be evaluated"+ +--------------------------------------------------------------------------------++-- | Runs the scriptSig +runScriptPre :: InterpreterConfig -> InterpreterState -> Script -> (Either String (), InterpreterState)+runScriptPre cfg st (Script opcodes) = runIdentity $ runReaderT (runStateT (runExceptT (executeScript opcodes)) st) cfg++-- | Runs the scriptPubKey+runScriptFinal :: InterpreterConfig -> InterpreterState -> Script -> (Either String Bool, InterpreterState)+runScriptFinal cfg st (Script opcodes) = runIdentity $ runReaderT (runStateT (runExceptT action) st) cfg+  where+    action :: ScriptMonad Bool+    action = do+      executeScript opcodes +      St main alt stream <- getState+      case stream of +        Stream CtxEmpty (Zipper finalRevOpcodes []) -> +          if reverse finalRevOpcodes /= opcodes+            then invalid "executeScript: shouldn't happen (script finished but the \"consumed opcodes\" are not the same as the original ones)"+            else case main of+              (top:_) -> return (asInteger top /= 0)                         -- if the top of the stack is TRUE, we are ok, otherwise we failed.+              []      -> invalid "script finished but the stack is empty"+        _ -> invalid $ "executeScript: shouldn't happen (script finished but there are remaining opcodes)"   -- (++ "\n" ++ show stream)++--------------------------------------------------------------------------------++-- | Executes a list of opcodes+executeScript :: [Opcode] -> ScriptMonad ()+executeScript opcodes = +  do+    when (any isDisabledOpcode opcodes) $ invalid "disabled opcode appearing in the script"+    St main alt _ <- getState+    putState (St main alt $ Stream CtxEmpty (zipperFromList opcodes))+    worker+  where+    worker = do+      finished <- scriptStep+      unless finished worker ++-- | Execute a single (except in case of conditionals) opcode +-- +-- \"The stacks hold byte vectors. Byte vectors are interpreted as little-endian +-- variable-length integers with the most significant bit determining the sign+-- of the integer. Thus 0x81 represents -1. 0x80 is another representation of +-- zero (so called negative 0). Byte vectors are interpreted as Booleans where +-- False is represented by any representation of zero, and True is represented +-- by any representation of non-zero.\"+--+-- Returns 'True' if the script finished.+--+scriptStep :: ScriptMonad Bool+scriptStep = fetchOpcode >>= \mbop -> case mbop of+  Nothing -> return True+  Just op -> do+    -- when (isDisabledOpcode op) $ invalid $ show op ++ ": disabled opcode"+    scriptStep' op+    return False++scriptStep' :: Opcode -> ScriptMonad ()+scriptStep' op = case op of++  OP_SMALLNUM n -> case n of +                       0 -> pushWords []+                       _ -> pushWords [fromIntegral n]++  OP_1NEGATE         -> pushWords [0x81]    -- "Thus 0x81 represents -1"+  OP_PUSHDATA w8 bs  -> if is_valid_pushdata w8 bs +                          then pushData bs +                          else invalid "fatal error: invalid PUSHDATA opcode"++  -- control flow+  OP_NOP w8   -> if is_nop w8 +                   then return () +                   else invalid "fatal error: invalid NOP opcode"+  OP_IF       -> do +                   b <- popBool+                   let branchTaken = if b then IfBranch else ElseBranch+                   ifblock@(IfBlock _ ifops mbelseops) <- fetchIfBlock If branchTaken+                   -- unless (checkForValidIfBlock ifblock) $ invalid "OP_VERIF or OP_VERNOTIF appearing in an if branch"                   +                   return ()+  OP_NOTIF    -> do +                   b <- popBool+                   let branchTaken = if not b then IfBranch else ElseBranch+                   ifblock@(IfBlock _ ifops mbelseops) <- fetchIfBlock NotIf branchTaken+                   -- unless (checkForValidIfBlock ifblock) $ invalid "OP_VERIF or OP_VERNOTIF appearing in an if branch"+                   return ()++  OP_ELSE     -> invalid "naked OP_ELSE found; this shouldn't happen"+  OP_ENDIF    -> invalid "naked OP_ENDIF found; this shouldn't happen"+  OP_VERIFY   -> do { x <- popData ; if isTrue x then return () else (pushData x >> invalid "OP_VERIFY: false") }+  OP_RETURN   -> invalid "OP_RETURN executed"++  -- stack+  OP_TOALTSTACK    -> do { x <- popData    ; pushAltData x } +  OP_FROMALTSTACK  -> do { x <- popAltData ; pushData    x } +  OP_IFDUP     -> do { x <- popData ; pushData x ; when (isTrue x) (pushData x) }+  OP_DEPTH     -> do { xs <- getMainStack ; pushInteger (fromIntegral $ length xs) }+  OP_DROP      -> do { _ <- popData ; return () }+  OP_DUP       -> do { x <- popData ; pushData x ; pushData x }+  OP_NIP       -> do { x <- popData ; _ <- popData ; pushData x }+  OP_OVER      -> do { x <- popData ; y <- popData ; pushData y ; pushData x ; pushData y }  -- Copies the second-to-top stack item to the top.++  -- The item n back in the stack is copied to the top. +  OP_PICK  -> do   +                n <- popInteger ; xs <- getMainStack +                when (n < 0)                         $ invalid "OP_PICK: negativ index"+                when (fromIntegral (length xs) <= n) $ invalid "OP_PICK: stack is not deep enough"+                putMainStack ( xs!!(fromIntegral n) : xs)                        +              +  -- The item n back in the stack is moved to the top.+  OP_ROLL  -> do+                n <- popInteger ; xs <- getMainStack +                when (n < 0)                         $ invalid "OP_ROLL: negativ index"+                when (fromIntegral (length xs) <= n) $ invalid "OP_ROLL: stack is not deep enough"+                let (hd,tl) = splitAt (fromIntegral n + 1) xs+                putMainStack (last hd : init hd ++ tl)                        ++  OP_ROT       -> do { (a,b,c) <- popTriple ; pushTriple (c,a,b) }+  OP_SWAP      -> do { x <- popData ; y <- popData ; pushData x ; pushData y }+  OP_TUCK      -> do { x <- popData ; y <- popData ; pushData x ; pushData y ; pushData x }  -- The item at the top of the stack is copied and inserted before the second-to-top item++  OP_2DROP     -> do { _   <- popPair ; return () }+  OP_2DUP      -> do { xy  <- popPair ; pushPair xy ; pushPair xy }+  OP_3DUP      -> do { xyz <- popTriple ; pushTriple xyz ; pushTriple xyz }+  OP_2OVER     -> do { xy  <- popPair ; zw <- popPair ; pushPair zw ; pushPair xy ; pushPair zw }  -- Copies the pair of items two spaces back in the stack to the front.++  OP_2ROT -> do+               a <- popPair ; b <- popPair ; c <- popPair+               pushPair b   ; pushPair a   ; pushPair c++  OP_2SWAP     -> do { xy <- popPair ; zw <- popPair ; pushPair xy ; pushPair zw }++  -- splice+  OP_CAT       -> do { b <- popData ; a <- popData ; pushData (B.append a b) }+  OP_SIZE      -> do { s <- popData ; pushData s ; pushInteger (dataLen s) }++  OP_SUBSTR    -> do+                    siz <- popInteger +                    bgn <- popInteger +                    str <- popData +                    let n = dataLen str+                    when (n < bgn+siz) $ invalid "OP_SUBSTR: string not long enough"+                    pushData (B.take (fromIntegral siz) $ B.drop (fromIntegral bgn) str)++  OP_LEFT      -> do+                    siz <- popInteger +                    str <- popData +                    let n = dataLen str+                    when (n < siz) $ invalid "OP_SUBSTR: string not long enough"+                    pushData (B.take (fromIntegral siz) str)++  OP_RIGHT     -> do+                    siz <- popInteger +                    str <- popData +                    let n = dataLen str+                    when (n < siz) $ invalid "OP_SUBSTR: string not long enough"+                    pushData (B.drop (fromIntegral (n-siz)) str)++  -- bitwise logic+  OP_INVERT      -> do { x <- popWords ; pushWords (map complement x) }+  OP_AND         -> do { y <- popWords ; x <- popWords ; pushWords (extendedZipWith (.&.) x y) }+  OP_OR          -> do { y <- popWords ; x <- popWords ; pushWords (extendedZipWith (.|.) x y) }+  OP_XOR         -> do { y <- popWords ; x <- popWords ; pushWords (extendedZipWith  xor  x y) }+  OP_EQUAL       -> do { y <- popData  ; x <- popData  ; pushBool (x==y) }+  OP_EQUALVERIFY -> scriptStep' OP_EQUAL >> scriptStep' OP_VERIFY++  -- arithmetic+  -- Note: Arithmetic inputs are limited to signed 32-bit integers, but may overflow their output. +  -- If any input value for any of these commands is longer than 4 bytes, the script must abort and fail. +  -- If any opcode marked as disabled is present in a script - it must also abort and fail.+  OP_1ADD           -> do { x <- popArith ; pushArith (x+1) }+  OP_1SUB           -> do { x <- popArith ; pushArith (x-1) }+  OP_2MUL           -> do { x <- popArith ; pushArith (x+x) }+  OP_2DIV           -> do { x <- popArith ; pushArith (div x 2) }+  OP_NEGATE         -> do { x <- popArith ; pushArith (negate x) }+  OP_ABS            -> do { x <- popArith ; pushArith (abs x) }+  OP_NOT            -> do { x <- popArith ; pushBool (x==0) }+  OP_0NOTEQUAL      -> do { x <- popArith ; pushBool (x/=0) }+  OP_ADD            -> do { y <- popArith ; x <- popArith ; pushArith (x+y) }+  OP_SUB            -> do { y <- popArith ; x <- popArith ; pushArith (x-y) }+  OP_MUL            -> do { y <- popArith ; x <- popArith ; pushArith (x*y) }+  OP_DIV            -> do { y <- popArith ; x <- popArith ; when (y==0) (invalid "OP_DIV: division by zero") ; pushArith (div x y) }+  OP_MOD            -> do { y <- popArith ; x <- popArith ; when (y==0) (invalid "OP_MOD: division by zero") ; pushArith (mod x y) }++  -- Shifts a left b bits, preserving sign+  OP_LSHIFT -> do  +                 -- k <- popArith +                 -- (sgn,absn) <- (toSignAbs . fromIntegral) <$> popArith+                 -- pushArith $ fromSignAbs (sgn, shiftL absn (fromIntegral k)) +                 k <- fromIntegral <$> popArith+                 n <- popArith+                 pushArith (shiftL n (mod k 32))++  -- Shifts a right b bits, preserving sign+  OP_RSHIFT -> do  +                 -- k <- popArith+                 -- (sgn,absn) <- (toSignAbs . fromIntegral) <$> popArith +                 -- pushArith $ fromSignAbs (sgn, shiftR absn (fromIntegral k)) +                 k <- fromIntegral <$> popArith+                 n <- popArith+                 pushArith (shiftR n (mod k 32))   -- Right shifts perform sign extension on /signed/ number types (here Integer)++  OP_BOOLAND         -> do { y <- popArith ; x <- popArith ; pushBool (x/=0 && y/=0) }+  OP_BOOLOR          -> do { y <- popArith ; x <- popArith ; pushBool (x/=0 || y/=0) }+  OP_NUMEQUAL        -> do { y <- popArith ; x <- popArith ; pushBool (x==y) }+  OP_NUMNOTEQUAL     -> do { y <- popArith ; x <- popArith ; pushBool (x/=y) }+  OP_NUMEQUALVERIFY  -> scriptStep' OP_NUMEQUAL >> scriptStep' OP_VERIFY+  OP_LESSTHAN            -> do { y <- popArith ; x <- popArith ; pushBool (x<y) }+  OP_GREATERTHAN         -> do { y <- popArith ; x <- popArith ; pushBool (x>y) }+  OP_LESSTHANOREQUAL     -> do { y <- popArith ; x <- popArith ; pushBool (x<=y) }+  OP_GREATERTHANOREQUAL  -> do { y <- popArith ; x <- popArith ; pushBool (x>=y) }+  OP_MIN                 -> do { y <- popArith ; x <- popArith ; pushArith (min x y) }+  OP_MAX                 -> do { y <- popArith ; x <- popArith ; pushArith (max x y) }+  OP_WITHIN              -> do { b <- popArith ; a <- popArith ; x <- popArith ; pushBool (x>=a && x<b) }  -- Returns 1 if x is within the specified range (left-inclusive), 0 otherwise++  -- crypto+  OP_RIPEMD160       -> do { x <- popData ; pushData (toByteString $ ripemd160 x) }+  OP_SHA1            -> do { x <- popData ; pushData (toByteString $ sha1      x) }+  OP_SHA256          -> do { x <- popData ; pushData (toByteString $ sha256    x) }+  OP_HASH160         -> do { x <- popData ; pushData (toByteString $ doHash160 x) }+  OP_HASH256         -> do { x <- popData ; pushData (toByteString $ doHash256 x) }+  OP_CODESEPARATOR   -> return ()   -- this one has only a meta meaning+  OP_CHECKSIG            -> execute_OP_CHECKSIG       -- invalid "OP_CHECKSIG: not implemented"+  OP_CHECKMULTISIG       -> execute_OP_CHECKMULTISIG  -- invalid "OP_CHECKMULTISIG: not implemented"+  OP_CHECKSIGVERIFY      -> scriptStep' OP_CHECKSIG      >> scriptStep' OP_VERIFY+  OP_CHECKMULTISIGVERIFY -> scriptStep' OP_CHECKMULTISIG >> scriptStep' OP_VERIFY+  +  -- reserved words+  OP_RESERVED           -> invalid "OP_RESERVED executed"+  OP_VER                -> invalid "OP_VER executed"+  OP_VERIF              -> invalid "OP_VERIF executed" +  OP_VERNOTIF           -> invalid "OP_VERNOTIF executed"+  OP_RESERVED1          -> invalid "OP_RESERVED1 executed"+  OP_RESERVED2          -> invalid "OP_RESERVED2 executed"++  -- pseudo+  OP_INVALIDOPCODE      -> invalid "OP_INVALIDOPCODE executed"+  OP_UNKNOWN w          -> invalid ("OP_UNKNOWN (decimal " ++ show w ++ ") executed")++  _  -> invalid ("unhandled or invalid opcode " ++ show op)++--------------------------------------------------------------------------------+-- * stack entries++dataLen :: Entry -> Integer+dataLen = fromIntegral . B.length++-- | zero-extended zipWith (the result will as long as the longer input)+extendedZipWith :: (Word8 -> Word8 -> Word8) -> [Word8] -> [Word8] -> [Word8] +extendedZipWith f = go where+  go (x:xs) (y:ys) = f x y : go xs ys+  go []     (y:ys) = f 0 y : go [] ys+  go (x:xs) []     = f x 0 : go xs []+  go []     []     = []++--------------------------------------------------------------------------------++isFalse :: Entry -> Bool+isFalse bs = (asInteger bs == 0)++isTrue :: Entry -> Bool+isTrue bs = (asInteger bs /= 0)++--------------------------------------------------------------------------------+-- * stack+++pushData :: Entry -> ScriptMonad ()+pushData bs = do+  St main alt stream <- getState+  putState (St (bs:main) alt stream)++popData :: ScriptMonad Entry+popData = do+  St main alt stream <- getState+  case main of +    (x:rest) -> do+      putState (St rest alt stream)+      return x+    [] -> invalid "cannot pop from main stack: it's empty"++pushAltData :: Entry -> ScriptMonad ()+pushAltData bs = do+  St main alt stream <- getState+  putState (St main (bs:alt) stream)++popAltData :: ScriptMonad Entry+popAltData = do+  St main alt stream <- getState+  case alt of +    (x:rest) -> do+      putState (St main rest stream)+      return x+    [] -> invalid "cannot pop from alt stack: it's empty"++----------------------------------------+-- arithmetic stupidity++{-+ok this is the craziest stupid fucking thing i ever seen. Inputs are limited to 32 bit signed +integers, but then they are treated as a bigint, and output can be more than 32 bit... +(let me bet here that they were originally implemented using @uint64_t@...)+-}++-- | Note: Arithmetic inputs are limited to signed 32-bit integers, but may overflow their output +-- (and by overflow they don't mean Int32 overflow, but that the result will not fit into an Int32...)+pushArith :: Integer -> ScriptMonad ()+pushArith = pushData . asByteString++-- | If any input value for any of these commands is longer than 4 bytes, the script must abort and fail. +-- If any opcode marked as disabled is present in a script - it must also abort and fail.+--+popArith :: ScriptMonad Integer+popArith = do+  bs <- popData+  when (B.length bs > 4) $ invalid "arithmetic operator with argument longer than 4 bytes"+  return $ asInteger bs++----------------------------------------++pushBool :: Bool -> ScriptMonad ()+pushBool b = pushWords $ case b of { True -> [1] ; False -> [] } ++popBool :: ScriptMonad Bool +popBool = do +  n <- popInteger+  return (n/=0)++pushWords :: [Word8] -> ScriptMonad ()+pushWords ws = pushData (B.pack ws)++popWords :: ScriptMonad [Word8]+popWords = B.unpack <$> popData++pushInteger :: Integer -> ScriptMonad ()+pushInteger = pushData . asByteString++popInteger ::  ScriptMonad Integer+popInteger = asInteger <$> popData++--------------------------------------------------------------------------------++popPair :: ScriptMonad (Entry,Entry)+popPair = do+  x <- popData+  y <- popData+  return (x,y)++pushPair :: (Entry,Entry) -> ScriptMonad ()+pushPair (x,y) = do+  pushData y+  pushData x++popTriple :: ScriptMonad (Entry,Entry,Entry)+popTriple = do+  x <- popData+  y <- popData+  z <- popData+  return (x,y,z)++pushTriple :: (Entry,Entry,Entry) -> ScriptMonad ()+pushTriple (x,y,z) = do+  pushData z+  pushData y+  pushData x++--------------------------------------------------------------------------------+-- * lifted monad operations++invalid :: String -> ScriptMonad a+invalid msg = throwE msg++askCfg :: ScriptMonad InterpreterConfig+askCfg = lift (lift ask)++getState :: ScriptMonad InterpreterState+getState = lift get++putState :: InterpreterState -> ScriptMonad ()+putState what = lift (put what)++getMainStack :: ScriptMonad [Entry]+getMainStack = _mainStack <$> getState++putMainStack :: [Entry] -> ScriptMonad ()+putMainStack main = do+  St _ alt stream <- getState+  putState (St main alt stream)  ++--------------------------------------------------------------------------------+-- * if blocks++data IfBranch +  = IfBranch      -- ^ \"if-then\"+  | ElseBranch    -- ^ \"else\"+  deriving (Eq,Show)++data IfType+  = If          -- ^ OP_IF+  | NotIf       -- ^ OP_NOTIF+  deriving Show++ifOpcode :: IfType -> Opcode+ifOpcode t = case t of+  If    -> OP_IF+  NotIf -> OP_NOTIF++data IfBlock = IfBlock +  { _ifType     :: IfType +  , _ifBranch   :: [Opcode]+  , _elseBranch :: Maybe [Opcode]+  } +  deriving Show++-- | Checks if OP_VER or OP_VERIF appears in any branch. Returns "True" if the block is valid.+checkForValidIfBlock :: IfBlock -> Bool+checkForValidIfBlock (IfBlock _ ifbr mbelsebr) = +  not $ or+    [ elem OP_VERIF    ifbr+    , elem OP_VERNOTIF ifbr +    , elem OP_VERIF    elsebr +    , elem OP_VERNOTIF elsebr +    ]+  where+    elsebr = maybe [] id mbelsebr++reconstructIfBlock :: IfBlock -> [Opcode]+reconstructIfBlock (IfBlock typ ifbranch mbelsebranch) = opcode : ifbranch ++ elsebranch ++ [OP_ENDIF] where+  opcode     = ifOpcode typ+  elsebranch = case mbelsebranch of +    Nothing -> [] +    Just es -> OP_ELSE : es++fetchIfBlock_ :: IfType -> IfBranch -> ScriptMonad ()+fetchIfBlock_ iftype branch = fetchIfBlock iftype branch >> return () ++-- | We fetch an if block *and* take the given branch (second argument)+--+-- Note: if blocks can be nested...+fetchIfBlock :: IfType -> IfBranch -> ScriptMonad IfBlock+fetchIfBlock topLevelIfType branchWeTook = +  do+    St main alt (Stream ctx (Zipper yys _)) <- getState+    case yys of+      []     -> invalid "fetchIfBlock: fatal error, shouldn't happen /1"+      (y:ys) -> if (y /= ifOpcode topLevelIfType) +        then invalid "fetchIfBlock: fatal error, shouldn't happen /2"+        else do+          ifblock <- fetch topLevelIfType+          let iftype = _ifType ifblock+          St _ _ (Stream _ctx (Zipper _ xs)) <- getState+          putState $ St main alt $ case branchWeTook of+            IfBranch   -> Stream (CtxHole ctx (reverse ys) iftype (HoleThen (_elseBranch ifblock)) xs)+                                 (Zipper [] (_ifBranch ifblock)) +            ElseBranch -> Stream (CtxHole ctx (reverse ys) iftype (HoleElse (_ifBranch ifblock) (isJust $ _elseBranch ifblock)) xs)+                                 (Zipper [] (maybe [] id (_elseBranch ifblock)))+          +          unless (checkForValidIfBlock ifblock) $ invalid "OP_VERIF or OP_VERNOTIF appearing in an if branch"+          return ifblock+  where++    fetch :: IfType -> ScriptMonad IfBlock+    fetch iftype = go IfBranch [] [] where++      -- first argument is which branch we are in right now+      -- second and third arguments accumulates the opcodes on the two branches+      go :: IfBranch -> [Opcode] -> [Opcode] -> ScriptMonad IfBlock+      go branch ifops elseops = do+        mbop <- fetchOpcodeWithinContext+        when (mbop == Nothing) $ invalid "unfinished IF (or NOTIF) block" +        let Just op = mbop+        case op of+          OP_IF    -> do+                        ifblock <- fetch If    +                        let ops = reconstructIfBlock ifblock +                        continue (reverse ops) +          OP_NOTIF -> do +                        ifblock <- fetch NotIf +                        let ops = reconstructIfBlock ifblock +                        continue (reverse ops) +          OP_ELSE  -> go ElseBranch ifops elseops+          OP_ENDIF -> return $ case branch of +                        IfBranch   -> IfBlock iftype (reverse ifops)  Nothing                +                        ElseBranch -> IfBlock iftype (reverse ifops) (Just $ reverse elseops)+          _ -> case branch of+            IfBranch   -> go branch (op : ifops) elseops+            ElseBranch -> go branch ifops (op : elseops) +        where +          continue ops = case branch of+            IfBranch   -> go branch (ops ++ ifops) elseops+            ElseBranch -> go branch ifops (ops ++ elseops) ++--------------------------------------------------------------------------------+-- * opcode stream manipulation++-- | Fetches an opcode, possibly exiting the current context+fetchOpcode :: ScriptMonad (Maybe Opcode)+fetchOpcode = do+  St main alt stream <- getState  +  case streamMoveRight stream of +    Left     stream'  -> putState (St main alt stream') >> return Nothing+    Right (x,stream') -> putState (St main alt stream') >> return (Just x)+           +-- | Fetches an opcode, but does not exit the current context+fetchOpcodeWithinContext :: ScriptMonad (Maybe Opcode)+fetchOpcodeWithinContext = do+  St main alt stream@(Stream ctx zipper) <- getState  +  case Zipper.moveRight zipper of +    Nothing          -> return Nothing+    Just (x,zipper') -> putState (St main alt (Stream ctx zipper')) >> return (Just x)++{-+getOpcodes :: ScriptMonad [Opcode]+getOpcodes = do+  St main alt stream <- getState+  return $ snd $ zipperView stream++putOpcodes :: [Opcode] -> ScriptMonad ()+putOpcodes stream = do+  St main alt _ <- getState+  putState (St main alt stream)+-}++--------------------------------------------------------------------------------+-- * CHECKSIG++{-+Hashtype SIGHASH_ALL (default)+  No special further handling occurs in the default case. +  Think of this as "sign all of the outputs." Which is already done by the default procedure. ++Procedure for Hashtype SIGHASH_NONE+  1. The output of txCopy is set to a vector of zero size. +  2. All other inputs aside from the current input in txCopy have their nSequence index set to zero +  Think of this as "sign none of the outputs -- I don't care where the bitcoins go."+ +Procedure for Hashtype SIGHASH_SINGLE+  1. The output of txCopy is resized to the size of the current input index+1. +  2. All other txCopy outputs aside from the output that is the same as the current input index are set to a blank script and a value of (long) -1. +  3. All other txCopy inputs aside from the current input are set to have an nSequence index of zero. +  Think of this as "sign one of the outputs-- I don't care where the other outputs go". ++  Note: The transaction that uses SIGHASH_SINGLE type of signature should not have more outputs than inputs. +  However if it does (because of the pre-existing implementation), it shall not be rejected, but instead +  for every "illegal" input (meaning: an input that has an index bigger than the maximum output index) +  the node should still verify it, though assuming the hash of 0000000000000000000000000000000000000000000000000000000000000001 +  <https://bitcointalk.org/index.php?topic=260595.0>++Procedure for Hashtype SIGHASH_ANYONECANPAY+  1. The txCopy input vector is resized to a length of one. +  2. The subScript (lead in by its length as a var-integer encoded!) is set as the first and only member of this vector. +  Think of this as "Let other people add inputs to this transaction, I don't care where the rest of the bitcoins come from."+-}++--------------------------------------------------------------------------------++codeSeparatorSubscript :: Stream -> RawScript+codeSeparatorSubscript fullStream = subscript where++  Zipper revbefore after = flattenStreamToZipper fullStream++  before' = reverse $ takeWhile (/= OP_CODESEPARATOR) revbefore+  after'  = filter (/= OP_CODESEPARATOR) after++  -- here, in theory, signatures should be deleted from subscript.+  -- however, in practice:+  --   1) signatures do not appear in pubKeyScripts (because self-signing is impossible?)+  --   2) it is theoretically impossible to distinguish a signature from some other data+  -- so we ignore this step++  subscript = serializeScript $ Script (before' ++ after') :: RawScript++--------------------------------------------------------------------------------++execute_OP_CHECKSIG :: ScriptMonad ()+execute_OP_CHECKSIG = do++  pubKeyStr <- popData  +  sigStr    <- popData++  St _ _ fullStream   <- getState+  Cfg tx inputidx <- askCfg++  let subscript = codeSeparatorSubscript fullStream++  case decodeSignatureDER' False sigStr of ++    Nothing -> pushBool False  -- invalid "OP_CHECKSIG: cannot decode DER signature"        +    Just (SignatureExt signature sighash) -> case decodePubKey pubKeyStr of++      Nothing -> pushBool False  -- invalid "OP_CHECKSIG: cannnot decode PubKey"     +      Just pubKey -> do++        let tx'    = mapAccumLFst_ (\i old -> (i+1 , if i==inputidx then subscript else RawScript B.empty)) 0 tx     +            ins'   = _txInputs  tx'+            outs'  = _txOutputs tx'+            nouts' = length outs'++        let (singleIssue,tx'') = case _sigHashType sighash of+                    SigHashAll     -> ( False, tx' )+                    SigHashAllZero -> ( False, tx' )+                    SigHashNone    -> ( False, setSeqNoToZeroTxExcept inputidx $ tx' { _txOutputs = [] } )+                    SigHashSingle  -> if nouts' > inputidx+                                        then (False, setSeqNoToZeroTxExcept inputidx $ tx' { _txOutputs = (replicate inputidx blankTxOutput) ++ [outs' !! inputidx] } )+                                        else (True , setSeqNoToZeroTxExcept inputidx $ tx' { _txOutputs = (replicate nouts'   blankTxOutput) } )++        let tx''' = case _anyOneCanPay sighash of+                      False -> tx''+                      True  -> tx'' { _txInputs = [ ins' !! inputidx ] }++        let RawTx rawtx = serializeTx tx'''+            hash = if singleIssue+              then fromIntegerLE 1       -- this works this way because of a stupid bug in the reference implementation...+              else doHash256 (rawtx `B.append` (fromWord8List [encodeSigHash sighash,0,0,0]))+        +        pushBool $ verifySignatureWithHash pubKey signature hash++--------------------------------------------------------------------------------++execute_OP_CHECKMULTISIG :: ScriptMonad ()+execute_OP_CHECKMULTISIG = do+                      +  n <- popInteger+  when (n > 20 || n < 1) $ invalid "OP_CHECKMULTISIG: n must be at least 1 and at most 20"+  pubKeyStrs <- reverse <$> replicateM (fromIntegral n) popData++  m <- popInteger+  when (m > n || m < 1) $ invalid "OP_CHECKMULTISIG: m must be at least 1 and at most n"+  sigStrs <- reverse <$> replicateM (fromIntegral m) popData++  _ <- popData     -- this is a bug in the original Satoshi client, which we must faithfully reproduce :(++  -- the first signature seems to have *another* extra byte at the end+  -- EXCEPT when it is missing, or EVEN the normal hashtype byte is missing!+  -- of course, there is precisely *ZERO* information about this on the net+  -- ok, fuck it, let's loose up the signature decoding...++  St _ _ fullStream   <- getState+  Cfg tx inputidx <- askCfg++  let subscript = codeSeparatorSubscript fullStream++  let mbSigs    = map (decodeSignatureDER' False) sigStrs     -- we allow non-standard encodings because they appear in the blockchain :(+      mbPubKeys = map  decodePubKey               pubKeyStrs++  case all isJust mbSigs of ++    False -> invalid $ "OP_CHECKMULTISIG: cannot decode DER signature" +               ++ "\n  pubkeys    = " ++ (show $ map RawScript pubKeyStrs)+               ++ "\n  signatures = " ++ (show $ map RawScript sigStrs)+              +    -- unfortunately, the original bitcoin client checks the pubkeys in order, and decodes on-the-fly, which means that+    -- it allows for invalid pubkeys after there is enough to satisfy the transaction :((( all these stupid on-the-fly+    -- validation issues (allowing partially-unparsable transaction in the blockchain) makes my nice code much more ugly :(+    --+    -- see (the output script of) testnet3 transaction 2e131d48f58cbb358cc53967a2fb89a80a6da337cb430fd719f5888af7a48507+{-+    True  -> case all isJust mbPubKeys of++      False -> invalid "OP_CHECKMULTISIG: cannnot decode PubKey"+      True  -> do+-}+    True -> do++        let -- pubKeys = map fromJust mbPubKeys+            sigExts = map fromJust mbSigs+            sigs      = map _extSignature sigExts+            hashtypes = map _extSigHash   sigExts++        let tx'    = mapAccumLFst_ (\i old -> (i+1 , if i==inputidx then subscript else RawScript B.empty)) 0 tx     +            ins'   = _txInputs  tx'+            outs'  = _txOutputs tx'+            nouts' = length outs'++        -- there are more signatures -> more hashtypes +        -- (but no documentation, fuck, who needs documentation for idiosyncratic code...)+        -- ok it seems that you have to recompute the hash for the different signatures because they can contain+        -- different hashtypes... (why isn't this documented anywhere?!)+        -- fuck all this overcomplicated shit+        +        -- this could be optimized since sighash is typically the same for all the signatures, but i don't care+        hashes <- forM hashtypes $ \sighash -> do++          let (singleIssue,tx'') = case _sigHashType sighash of+                     SigHashAll     -> ( False, tx' )+                     SigHashAllZero -> ( False, tx' )+                     SigHashNone    -> ( False, setSeqNoToZeroTxExcept inputidx $ tx' { _txOutputs = [] } )+                     SigHashSingle  -> if nouts' > inputidx+                                         then ( False, setSeqNoToZeroTxExcept inputidx $ tx' { _txOutputs = (replicate inputidx blankTxOutput) ++ [outs' !! inputidx] } )+                                         else ( True , setSeqNoToZeroTxExcept inputidx $ tx' { _txOutputs = (replicate nouts'   blankTxOutput) } )++          let tx''' = case _anyOneCanPay sighash of+                        False -> tx''+                        True  -> tx'' { _txInputs = [ ins' !! inputidx ] }++          let RawTx rawtx = serializeTx tx'''+              hash = if singleIssue+                then fromIntegerLE 1       -- this works this way because of a stupid bug in the reference implementation...+                else doHash256 (rawtx `B.append` (fromWord8List [encodeSigHash sighash,0,0,0]))++          return hash++        b <- worker mbPubKeys (zip hashes sigs)+        pushBool b++  where++    -- we have n pubkeys (some of them can be invalid...) and m signatures, n >= m+    worker :: [Maybe PubKey] -> [(Hash256,Signature)] -> ScriptMonad Bool+    worker = go where+      go _      []          = return True    -- there are no more signatures -> all of them matched+      go []     _           = return False   -- there are at least one signature but no more pubkey -> not all of them matched+      go (mbp:ps) (hs@(h,s):hss) = case mbp of+        Nothing -> go ps (hs:hss)+        Just p  -> case verifySignatureWithHash p s h of+                     True  -> go ps     hss+                     False -> go ps (hs:hss)++--------------------------------------------------------------------------------+-- helpers for CHECKSIG++blankTxOutput :: TxOutput RawScript+blankTxOutput = TxOutput (-1) (RawScript B.empty)++setSeqNoToZeroTxExcept :: Int -> Tx a b -> Tx a b+setSeqNoToZeroTxExcept idx tx = tx { _txInputs = setSeqNoToZeroListExcept idx (_txInputs tx) }++setSeqNoToZeroListExcept :: Int -> [TxInput a] -> [TxInput a]+setSeqNoToZeroListExcept idx = mapAccumL_ (\i txin -> (i+1, if i==idx then txin else txin { _txInSeqNo = 0 })) 0 ++--------------------------------------------------------------------------------++mapAccumL_ :: (acc -> x -> (acc,y)) -> acc -> [x] -> [y]+mapAccumL_ f acc = snd . mapAccumL f acc++--------------------------------------------------------------------------------+
+ Bitcoin/Script/Serialize.hs view
@@ -0,0 +1,307 @@++-- | Parsing and serializing Bitcoin scripts++{-# LANGUAGE PatternGuards #-}+module Bitcoin.Script.Serialize where++--------------------------------------------------------------------------------++import Data.Int+import Data.Word++import Control.Monad+import Control.Applicative++import qualified Data.ByteString      as B+import qualified Data.ByteString.Lazy as L+import Data.Binary+import Data.Binary.Get+import Data.Binary.Put++import Bitcoin.Script.Base++--------------------------------------------------------------------------------++{-+import Debug.Trace+debug      x y = trace ("---" ++ show x ++ "---") y+debug' pre x y = trace ("---" ++ pre ++ ":" ++ show x ++ "---") y+-}++--------------------------------------------------------------------------------++instance Binary Opcode where+  get = getOpcode+  put = putOpcode++--------------------------------------------------------------------------------++-- Notes: Scripts are big-endian.++getOpcode :: Get Opcode+getOpcode = getWord8 >>= \op -> case op of++  -- data+  0                      -> return (OP_SMALLNUM 0)+  _  | op>=1 && op<=75   -> OP_PUSHDATA op <$> getByteString (fromIntegral op)+  76                     -> getWord8    >>= \l -> OP_PUSHDATA op <$> getByteString (fromIntegral l)+  77                     -> getWord16le >>= \l -> OP_PUSHDATA op <$> getByteString (fromIntegral l)+  78                     -> getWord32le >>= \l -> OP_PUSHDATA op <$> getByteString (fromIntegral l)+  79                     -> return (OP_1NEGATE)+  81                     -> return (OP_SMALLNUM 1)+  _  | op>=82 && op<=96  -> return (OP_SMALLNUM (fromIntegral op-80))++  -- control flow+  97  -> return (OP_NOP op)+  99  -> return OP_IF+  100 -> return OP_NOTIF+  103 -> return OP_ELSE+  104 -> return OP_ENDIF+  105 -> return OP_VERIFY+  106 -> return OP_RETURN++  -- stack+  107 -> return OP_TOALTSTACK          -- Puts the input onto the top of the alt stack. Removes it from the main stack. +  108 -> return OP_FROMALTSTACK        -- Puts the input onto the top of the main stack. Removes it from the alt stack. +  115 -> return OP_IFDUP               -- If the top stack value is not 0, duplicate it. +  116 -> return OP_DEPTH               -- Puts the number of stack items onto the stack. +  117 -> return OP_DROP                -- Removes the top stack item. +  118 -> return OP_DUP                 -- Duplicates the top stack item. +  119 -> return OP_NIP                 -- Removes the second-to-top stack item. +  120 -> return OP_OVER                -- Copies the second-to-top stack item to the top. +  121 -> return OP_PICK                -- The item n back in the stack is copied to the top. +  122 -> return OP_ROLL                -- The item n back in the stack is moved to the top. +  123 -> return OP_ROT                 -- The top three items on the stack are rotated to the left. +  124 -> return OP_SWAP                -- The top two items on the stack are swapped. +  125 -> return OP_TUCK                -- The item at the top of the stack is copied and inserted before the second-to-top item. +  109 -> return OP_2DROP               -- Removes the top two stack items. +  110 -> return OP_2DUP                -- Duplicates the top two stack items. +  111 -> return OP_3DUP                -- Duplicates the top three stack items. +  112 -> return OP_2OVER               -- Copies the pair of items two spaces back in the stack to the front. +  113 -> return OP_2ROT                -- The fifth and sixth items back are moved to the top of the stack. +  114 -> return OP_2SWAP               -- Swaps the top two pairs of items.++  -- splice+  126 -> return OP_CAT        +  127 -> return OP_SUBSTR     +  128 -> return OP_LEFT       +  129 -> return OP_RIGHT      +  130 -> return OP_SIZE       ++  -- bitwise logic+  131 -> return OP_INVERT     +  132 -> return OP_AND        +  133 -> return OP_OR         +  134 -> return OP_XOR        +  135 -> return OP_EQUAL      +  136 -> return OP_EQUALVERIFY ++  -- arithmetic+  139 -> return OP_1ADD          +  140 -> return OP_1SUB          +  141 -> return OP_2MUL          +  142 -> return OP_2DIV          +  143 -> return OP_NEGATE        +  144 -> return OP_ABS           +  145 -> return OP_NOT           +  146 -> return OP_0NOTEQUAL     +  147 -> return OP_ADD           +  148 -> return OP_SUB           +  149 -> return OP_MUL           +  150 -> return OP_DIV           +  151 -> return OP_MOD           +  152 -> return OP_LSHIFT            +  153 -> return OP_RSHIFT             +  154 -> return OP_BOOLAND            +  155 -> return OP_BOOLOR             +  156 -> return OP_NUMEQUAL           +  157 -> return OP_NUMEQUALVERIFY     +  158 -> return OP_NUMNOTEQUAL        +  159 -> return OP_LESSTHAN           +  160 -> return OP_GREATERTHAN        +  161 -> return OP_LESSTHANOREQUAL    +  162 -> return OP_GREATERTHANOREQUAL +  163 -> return OP_MIN                +  164 -> return OP_MAX                +  165 -> return OP_WITHIN             ++  -- crypto+  166 -> return OP_RIPEMD160          +  167 -> return OP_SHA1                +  168 -> return OP_SHA256              +  169 -> return OP_HASH160             +  170 -> return OP_HASH256             +  171 -> return OP_CODESEPARATOR       +  172 -> return OP_CHECKSIG            +  173 -> return OP_CHECKSIGVERIFY      +  174 -> return OP_CHECKMULTISIG       +  175 -> return OP_CHECKMULTISIGVERIFY++  -- reserved words+  80  -> return OP_RESERVED  +  98  -> return OP_VER       +  101 -> return OP_VERIF     +  102 -> return OP_VERNOTIF  +  137 -> return OP_RESERVED1 +  138 -> return OP_RESERVED2 +  _ | op>=167 && op<=185 -> return (OP_NOP op)++  -- pseudo+  255 -> return OP_INVALIDOPCODE+  _   -> return (OP_UNKNOWN op)      -- fail ("getOpcode: unhandled or invalid opcode " ++ show op)++--------------------------------------------------------------------------------++putOpcode :: Opcode -> Put +putOpcode op = case op of++  -- data+  OP_SMALLNUM n   -> case n of +                       0                 -> putWord8 0+                       _ | n>=1 && n<=16 -> putWord8 (80 + fromIntegral n) +                       _                 -> fail ("putOpcode: OP_SMALLNUM can handle integers between 0 and 16")+  OP_1NEGATE      -> putWord8 79++  OP_PUSHDATA w8 bs  ->  if (is_valid_pushdata w8 bs) +                           then let l = B.length bs in case w8 of+                             0  -> putWord8 w8    +                             76 -> putWord8 w8 >> putWord8    (fromIntegral l) >> putByteString bs +                             77 -> putWord8 w8 >> putWord16le (fromIntegral l) >> putByteString bs +                             78 -> putWord8 w8 >> putWord32le (fromIntegral l) >> putByteString bs +                             _  -> putWord8 w8 >> putByteString bs+                           else fail "putOpcode: invalid OP_PUSHDATA"++  -- control flow+  OP_NOP w8   -> if is_nop w8 then putWord8 w8 else fail "putOpcode/OP_NOP: invalid NOP opcode"+  OP_IF       -> putWord8 99+  OP_NOTIF    -> putWord8 100+  OP_ELSE     -> putWord8 103+  OP_ENDIF    -> putWord8 104+  OP_VERIFY   -> putWord8 105+  OP_RETURN   -> putWord8 106++  -- stack+  OP_TOALTSTACK      -> putWord8 107+  OP_FROMALTSTACK    -> putWord8 108+  OP_IFDUP     -> putWord8 115+  OP_DEPTH     -> putWord8 116+  OP_DROP      -> putWord8 117+  OP_DUP       -> putWord8 118+  OP_NIP       -> putWord8 119+  OP_OVER      -> putWord8 120+  OP_PICK      -> putWord8 121+  OP_ROLL      -> putWord8 122+  OP_ROT       -> putWord8 123+  OP_SWAP      -> putWord8 124+  OP_TUCK      -> putWord8 125+  OP_2DROP     -> putWord8 109+  OP_2DUP      -> putWord8 110+  OP_3DUP      -> putWord8 111+  OP_2OVER     -> putWord8 112+  OP_2ROT      -> putWord8 113+  OP_2SWAP     -> putWord8 114++  -- splice+  OP_CAT       -> putWord8 126+  OP_SUBSTR    -> putWord8 127+  OP_LEFT      -> putWord8 128+  OP_RIGHT     -> putWord8 129 +  OP_SIZE      -> putWord8 130++  -- bitwise logic+  OP_INVERT      -> putWord8 131+  OP_AND         -> putWord8 132+  OP_OR          -> putWord8 133+  OP_XOR         -> putWord8 134+  OP_EQUAL       -> putWord8 135+  OP_EQUALVERIFY -> putWord8 136++  -- arithmetic+  OP_1ADD           -> putWord8 139+  OP_1SUB           -> putWord8 140+  OP_2MUL           -> putWord8 141+  OP_2DIV           -> putWord8 142+  OP_NEGATE         -> putWord8 143+  OP_ABS            -> putWord8 144+  OP_NOT            -> putWord8 145+  OP_0NOTEQUAL      -> putWord8 146+  OP_ADD            -> putWord8 147+  OP_SUB            -> putWord8 148+  OP_MUL            -> putWord8 149+  OP_DIV            -> putWord8 150+  OP_MOD            -> putWord8 151+  OP_LSHIFT              -> putWord8 152+  OP_RSHIFT              -> putWord8 153+  OP_BOOLAND             -> putWord8 154+  OP_BOOLOR              -> putWord8 155+  OP_NUMEQUAL            -> putWord8 156+  OP_NUMEQUALVERIFY      -> putWord8 157+  OP_NUMNOTEQUAL         -> putWord8 158+  OP_LESSTHAN            -> putWord8 159+  OP_GREATERTHAN         -> putWord8 160+  OP_LESSTHANOREQUAL     -> putWord8 161+  OP_GREATERTHANOREQUAL  -> putWord8 162+  OP_MIN                 -> putWord8 163+  OP_MAX                 -> putWord8 164+  OP_WITHIN              -> putWord8 165++  -- crypto+  OP_RIPEMD160       -> putWord8 166+  OP_SHA1            -> putWord8 167+  OP_SHA256          -> putWord8 168+  OP_HASH160         -> putWord8 169+  OP_HASH256         -> putWord8 170+  OP_CODESEPARATOR   -> putWord8 171+  OP_CHECKSIG        -> putWord8 172+  OP_CHECKSIGVERIFY      -> putWord8 173 +  OP_CHECKMULTISIG       -> putWord8 174+  OP_CHECKMULTISIGVERIFY -> putWord8 175++  -- reserved words+  OP_RESERVED       -> putWord8 80+  OP_VER            -> putWord8 98+  OP_VERIF          -> putWord8 101+  OP_VERNOTIF       -> putWord8 102+  OP_RESERVED1      -> putWord8 137+  OP_RESERVED2      -> putWord8 138++  -- pseudo+  OP_INVALIDOPCODE  -> putWord8 255       +  OP_UNKNOWN w8     -> putWord8 w8++  _  -> fail ("putOpcode: unhandled or invalid opcode " ++ show op)++--------------------------------------------------------------------------------++instance Binary Script where+  get = Script <$> getMany +  put (Script ops) = putMany ops++-- | The default Binry instance for lists (naturally) encodes the +-- length of the list at the start, so we need this...+getMany :: Binary a => Get [a]+getMany = do+  b <- isEmpty +  if b +    then return []+    else do+      x  <- get+      xs <- getMany+      return (x:xs)++putMany :: Binary a => [a] -> Put+putMany xs = mapM_ put xs++--------------------------------------------------------------------------------++parseScript :: RawScript -> Maybe Script   +parseScript (RawScript bs) = case decodeOrFail (L.fromChunks [bs]) of+  Left _ -> Nothing+  Right (remaining, consumedbytes, x) -> if L.null remaining+    then Just x+    else Nothing++serializeScript :: Script -> RawScript+serializeScript script = RawScript $ B.concat $ L.toChunks $ encode script++--------------------------------------------------------------------------------
+ Bitcoin/Script/Standard.hs view
@@ -0,0 +1,227 @@++-- | Standard scripts++{-# LANGUAGE PatternGuards #-}+module Bitcoin.Script.Standard where++---------------------------------------------------------------------------------++import Data.Int+import Data.Word+import Data.Maybe++import Control.Monad++import qualified Data.ByteString as B++import Bitcoin.Misc.OctetStream++import Bitcoin.Script.Base +import Bitcoin.Script.Serialize+import Bitcoin.BlockChain.Base ++-- import Bitcoin.Crypto.ECDSA++import Bitcoin.Protocol.Hash+import Bitcoin.Protocol.Key+import Bitcoin.Protocol.Signature++--------------------------------------------------------------------------------++-- | Standard input scripts (also known as \"scriptSig\")+data InputScript+  = CoinGeneration !RawScript                     -- ^ coin generation (the script has no meaning)+  | RedeemAddress  !SignatureExt !PubKey          -- ^ redeem a standard (to-address) transaction: \<sig\> \<pubKey\>+  | RedeemPubKey   !SignatureExt                  -- ^ redeem a to-pubkey transaction (?)+  | RedeemMultiSig [SignatureExt]                 -- ^ redeem a multisig transaction+  | RedeemP2SH     [SignatureExt] !RawScript      -- ^ redeem a pay-to-script-hash transaction (???)+  | RedeemEmpty                                   -- ^ OP_TRUE - accepts an AnyCanSpend script+  | UnknownInput   (Either RawScript Script)      -- ^ something else (that is, non-standard)+  deriving (Eq,Show)++isStandardInputScript :: InputScript -> Bool+isStandardInputScript input = case input of+  UnknownInput {} -> False+  _               -> True++--------------------------------------------------------------------------------++-- | Standard output scripts (also known as \"scriptSig\")+data OutputScript+  = PayToAddress    !PubKeyHash                -- ^ OP_DUP OP_HASH160 \<pubKeyHash\> OP_EQUALVERIFY OP_CHECKSIG+  | PayToPubKey     !PubKey                    -- ^ \<pubKey\> OP_CHECKSIG (accept generation, for example, but also others?)+  | PayToMultiSig   !Int [PubKey]              -- ^ eg. OP_2 \<pubkey1\> \<pubkey2\> \<pubkey3\> OP_3 OP_CHECKMULTISIG+  | PayToScriptHash !ScriptHash                -- ^ OP_HASH160 \<script-hash\> OP_EQUAL+  | Unspendable                                -- ^ OP_RETURN {zero or more ops}+  | AnyCanSpend                                -- ^ (empty)+  | UnknownOutput   (Either RawScript Script)  -- ^ something else (that is, non-standard)+  deriving (Eq,Show)++isStandardOutputScript :: OutputScript -> Bool+isStandardOutputScript output = case output of+  UnknownOutput {} -> False+  _                -> True++--------------------------------------------------------------------------------++-- | Note: RedeemP2SH is a hack. I should think again how that should work (certainly not this way...)+createInputScript :: InputScript -> RawScript+createInputScript input = case input of+  CoinGeneration raw -> raw+  RedeemAddress  sigext pubkey -> serializeScript $ Script [ op_PUSHDATA (encodeSignatureDER sigext) , op_PUSHDATA (encodePubKeyNative pubkey) ]+  RedeemPubKey   sigext        -> serializeScript $ Script [ op_PUSHDATA (encodeSignatureDER sigext) ]+  RedeemMultiSig sigexts       -> serializeScript $ Script $ op_0 : [ op_PUSHDATA (encodeSignatureDER sigext) | sigext <- sigexts ] +  RedeemP2SH     sigexts raw   -> case sigexts of+    [single] -> serializeScript $ Script          [ op_PUSHDATA (encodeSignatureDER single) , op_PUSHDATA (fromRawScript raw) ]+    many     -> serializeScript $ Script $ op_0 : [ op_PUSHDATA (encodeSignatureDER sigext) | sigext <- many ] ++ [ op_PUSHDATA (fromRawScript raw) ]+  RedeemEmpty                  -> serializeScript $ Script [ op_TRUE ]+  UnknownInput ei              -> case ei of { Left raw -> raw ; Right script -> serializeScript script }++createTxInput :: TxInput InputScript -> TxInput RawScript+createTxInput txin0 = +  case (_txInScript txin0) of+    CoinGeneration raw -> txin1 { _txInPrevOutHash = zeroHash256 , _txInPrevOutIdx = 0xffffffff, _txInSeqNo = 0xffffffff }+    _                  -> txin1+  where +    txin1 = fmap createInputScript txin0++--------------------------------------------------------------------------------++createOutputScript :: OutputScript -> RawScript+createOutputScript output = case output of+  PayToAddress (PubKeyHash hash)    -> serializeScript $ Script [ OP_DUP , OP_HASH160 , op_PUSHDATA (toByteString hash) , OP_EQUALVERIFY , OP_CHECKSIG ]+  PayToPubKey  pubkey               -> serializeScript $ Script [ op_PUSHDATA (encodePubKeyNative pubkey) , OP_CHECKSIG ]+  PayToMultiSig k pubkeys           -> serializeScript $ Script $ (OP_SMALLNUM k) : [ op_PUSHDATA (encodePubKeyNative pubkey) | pubkey <- pubkeys ] ++ [ OP_SMALLNUM (length pubkeys) , OP_CHECKMULTISIG ]+  PayToScriptHash (ScriptHash hash) -> serializeScript $ Script [ OP_HASH160 , op_PUSHDATA (toByteString hash) , OP_EQUAL ]+  Unspendable                       -> serializeScript $ Script [ OP_RETURN ]+  AnyCanSpend                       -> serializeScript $ Script [ ]+  UnknownOutput   ei                -> case ei of { Left raw -> raw ; Right script -> serializeScript script }++createTxOutput :: TxOutput OutputScript -> TxOutput RawScript+createTxOutput = fmap createOutputScript++--------------------------------------------------------------------------------++-- | Recognize standard input scripts (also known as \"scriptSig\"). +--+-- We need the whole TxInput since coinbase transactions are not possible to recognize only from the script (which can be anything).+recognizeTxInput :: TxInput RawScript -> TxInput InputScript+recognizeTxInput tx@(TxInput prevouthash prevoutidx rawscript seqno) +  | prevouthash == zeroHash256   =  final $ CoinGeneration rawscript+  | otherwise                    =  final $ recognizeInputScript rawscript+  where+    final new = tx { _txInScript = new }++-- | Note: this cannot recognize coinbase transactions.+recognizeInputScript :: RawScript -> InputScript+recognizeInputScript rawscript++  | Just [OP_PUSHDATA _ dersig, OP_PUSHDATA _ rawpubkey] <- mbscript+  , Just sig    <- decodeSignatureDER' False dersig+  , Just pubkey <- decodePubKey rawpubkey +       = RedeemAddress sig pubkey++  | Just [OP_PUSHDATA _ dersig] <- mbscript+  , Just sig    <- decodeSignatureDER' False dersig+       = RedeemPubKey sig ++  | Just (OP_SMALLNUM 0 : dersignatures) <- mbscript   -- OP_SMALLNUM 0 is there because of a bug in OP_CHECKMULTISIG (?!)+  , mbders  <- map is_op_pushdata dersignatures +  , mbsigs <- map (>>= decodeSignatureDER' False) mbders      +  , all isJust mbsigs+       = RedeemMultiSig (map fromJust mbsigs)++  -- p2sh, single signature+  | Just [OP_PUSHDATA _ dersig , OP_PUSHDATA _ rawscript] <- mbscript     +  , Just sig     <- decodeSignatureDER' False dersig+  , outputscript <- recognizeOutputScript (RawScript rawscript)+  , isStandardOutputScript outputscript+       = RedeemP2SH [sig] (RawScript rawscript)          ++  -- p2sh, multiple signatures and an OP_0 in the front (because we expect CHECK_MULTISIG, which needs an extra stack entry, typically OP_0)+  | Just (OP_SMALLNUM 0 : dersigs_and_rawscript) <- mbscript     +  , OP_PUSHDATA _ rawscript <- last dersigs_and_rawscript+  , mbders  <- map is_op_pushdata (init dersigs_and_rawscript)+  , mbsigs <- map (>>= decodeSignatureDER' False) mbders      +  , all isJust mbsigs+  , outputscript <- recognizeOutputScript (RawScript rawscript)+  , isStandardOutputScript outputscript+       = RedeemP2SH (map fromJust mbsigs) (RawScript rawscript)          +        +  | Just [OP_SMALLNUM 1] <- mbscript      -- OP_TRUE == OP_SMALLNUM 1+       = RedeemEmpty++  | otherwise+       = UnknownInput +       $ case mbscript of { Nothing -> Left rawscript ; Just ops -> Right (Script ops) } ++  where+    mbscript = liftM fromScript $ parseScript rawscript :: Maybe [Opcode]++--------------------------------------------------------------------------------++-- | Recognize standard output scripts (also known as \"scriptPubKey\")+recognizeTxOutput :: TxOutput RawScript -> TxOutput OutputScript+recognizeTxOutput tx@(TxOutput value rawscript) = tx { _txOutScript = recognizeOutputScript rawscript }++recognizeOutputScript :: RawScript -> OutputScript+recognizeOutputScript rawscript ++  | Just [OP_DUP, OP_HASH160, OP_PUSHDATA _ pubKeyHash, OP_EQUALVERIFY, OP_CHECKSIG] <- mbscript+  , B.length pubKeyHash == 20 +       = PayToAddress (PubKeyHash $ fromByteString pubKeyHash)++  | Just [OP_PUSHDATA _ rawPubKey, OP_CHECKSIG] <- mbscript+  , Just pubKey <- decodePubKey rawPubKey+       = PayToPubKey pubKey++  | Just [OP_HASH160, OP_PUSHDATA _ scriptHash, OP_EQUAL] <- mbscript+  , B.length scriptHash == 20 +       = PayToScriptHash (ScriptHash $ fromByteString scriptHash)++  | Just script <- mbscript+  , Just (m,pubkeys) <- recogPayToMultiSig script+       = PayToMultiSig m pubkeys++  | Just [] <- mbscript+       = AnyCanSpend++  | Just (OP_RETURN:_) <- mbscript+       = Unspendable++  | otherwise+       = UnknownOutput+       $ case mbscript of { Nothing -> Left rawscript ; Just ops -> Right (Script ops) } ++  where+    mbscript  = liftM fromScript $ parseScript rawscript :: Maybe [Opcode]++--------------------------------------------------------------------------------++recogPayToMultiSig :: [Opcode] -> Maybe (Int,[PubKey])+recogPayToMultiSig ops ++  | [ OP_SMALLNUM m ] <- take 1 ops+  , [ OP_CHECKMULTISIG , OP_SMALLNUM n ] <- take 2 (reverse ops)+  , length ops == n + 3+  , mbrawdats <- map is_op_pushdata $ take n $ drop 1 $ ops+  , all isJust mbrawdats+  , rawdats <- map fromJust mbrawdats+  , mbpubkey <- map decodePubKey rawdats+  , all isJust mbpubkey  +      = Just (m, map fromJust mbpubkey)++  | otherwise = Nothing++--------------------------------------------------------------------------------++recognizeTx :: Tx RawScript RawScript -> Tx InputScript OutputScript +recognizeTx tx@(Tx ver ins outs lock hash) = tx { _txInputs = ins' , _txOutputs = outs' } where+  ins'  = map recognizeTxInput  ins+  outs' = map recognizeTxOutput outs++recognizeBlockTxs :: Block (Tx RawScript RawScript) -> Block (Tx InputScript OutputScript)+recognizeBlockTxs (Block header txs) = Block header (map recognizeTx txs)++--------------------------------------------------------------------------------+
+ Bitcoin/Test/Crypto/Curve.hs view
@@ -0,0 +1,160 @@++{-# LANGUAGE CPP, BangPatterns #-}+module Bitcoin.Test.Crypto.Curve where++--------------------------------------------------------------------------------++import Test.Tasty+import Test.Tasty.QuickCheck +import Test.QuickCheck ( Arbitrary(..) , choose , quickCheckWith , stdArgs , maxSuccess , Testable )++import Bitcoin.Crypto.FiniteField.Fast.Fp  hiding ( secp256k1_p )+import Bitcoin.Crypto.FiniteField.Naive.Fn hiding ( secp256k1_n )+import Bitcoin.Crypto.EC.Curve++import Bitcoin.Test.Misc.QuickCheck++--------------------------------------------------------------------------------++testgroup_Curve :: TestTree+testgroup_Curve = testGroup "EC.Curve"+  [ testProperty "left unit"               prop_left_unit +  , testProperty "right unit"              prop_right_unit +  , testProperty "0 + 0 = 0"               prop_add_dbl_unit +  , testProperty "2*0 = 0"                 prop_dbl_unit +  , testProperty "inverse of 0 = 0"        prop_inv_unit +  , testProperty "(p+q)-q = p"             prop_add_sub+  , testProperty "(p-q)+q = p"             prop_add_sub1+  , testProperty "((p+q)-q)-p = 0"         prop_add_sub2+  , testProperty "(2*p) - p = p"           prop_dbl_sub+  , testProperty "(2*p) - p - p = 0"       prop_dbl_sub2+  , testProperty "addition is commutative" prop_add_commutative+  , testProperty "addition is associative" prop_add_associative+  , testProperty "(p-q)-r = p-(q+r)"       prop_add_sub_associative1+  , testProperty "(p-q)+r = p-(q-r)"       prop_add_sub_associative2+  , testProperty "a + (-a) = 0"            prop_add_inv+  , testProperty "k*p = (k mod n)*p"       prop_mul_big+  , testProperty "0*p = 0"                 prop_mul_0+  , testProperty "1*p = p"                 prop_mul_1+  , testProperty "2*p = p + p"             prop_mul_2+  , testProperty "n*p = 0"                 prop_mul_n+  , testProperty "(n-1)*p = -p"            prop_mul_nminus1+  ]++--------------------------------------------------------------------------------+-- * quickcheck++newtype NonZeroEC = NonZeroEC ECPoint deriving (Eq,Show)++instance Arbitrary ECPoint where+  arbitrary = do+    n <- choose (0,secp256k1_n-1)+    return $ mulEC (secp256k1_G) n++instance Arbitrary NonZeroEC where+  arbitrary = do+    n <- choose (1,secp256k1_n-1)+    return $ NonZeroEC $ mulEC (secp256k1_G) n++--------------------------------------------------------------------------------++{-+runAllTests_ec_curve :: IO ()+runAllTests_ec_curve = runAllTests_ec_curve' 1000++runAllTests_ec_curve' :: Int -> IO ()+runAllTests_ec_curve' n = do+  let args = stdArgs { maxSuccess = n }+  let qc :: Testable prop => prop -> IO ()+      qc = quickCheckWith args+ +  putStrLn "running all tests in Bitcoin.Crypto.EC.Curve"+  putStrLn "============================================"+  qc prop_left_unit +  qc prop_right_unit +  qc prop_add_dbl_unit +  qc prop_dbl_unit +  qc prop_inv_unit +  qc prop_add_sub+  qc prop_add_sub2+  qc prop_dbl_sub+  qc prop_dbl_sub2+  qc prop_add_commutative+  qc prop_add_associative+  qc prop_add_sub_associative1+  qc prop_add_sub_associative2+  qc prop_add_inv+  qc prop_mul_big+  qc prop_mul_0+  qc prop_mul_1+  qc prop_mul_2+  qc prop_mul_n+  qc prop_mul_nminus1+-}++--------------------------------------------------------------------------------++prop_left_unit :: ECPoint  -> Bool+prop_left_unit p = addEC p ECInfinity == p++prop_right_unit :: ECPoint  -> Bool+prop_right_unit q = addEC ECInfinity q == q++prop_add_dbl_unit :: Bool+prop_add_dbl_unit = ECInfinity + ECInfinity == ECInfinity++prop_dbl_unit :: Bool+prop_dbl_unit = dblEC ECInfinity == ECInfinity++prop_inv_unit :: Bool+prop_inv_unit = invEC ECInfinity == ECInfinity++prop_add_sub :: ECPoint -> ECPoint -> Bool+prop_add_sub p q  = subEC (addEC p q) q == p++prop_add_sub1 :: ECPoint -> ECPoint -> Bool+prop_add_sub1 p q  = addEC (subEC p q) q == p++prop_add_sub2 :: ECPoint -> ECPoint -> Bool+prop_add_sub2 p q  = subEC (subEC (addEC p q) q) p == ECInfinity++prop_dbl_sub :: ECPoint -> Bool+prop_dbl_sub p = subEC (dblEC p) p == p++prop_dbl_sub2 :: ECPoint -> Bool+prop_dbl_sub2 p = subEC (subEC (dblEC p) p) p == ECInfinity++prop_add_commutative :: ECPoint -> ECPoint -> Bool+prop_add_commutative p q  = (addEC p q) == (addEC q p)++prop_add_associative :: ECPoint -> ECPoint -> ECPoint -> Bool+prop_add_associative p q r = addEC (addEC p q) r == addEC p (addEC q r)++prop_add_sub_associative1 :: ECPoint -> ECPoint -> ECPoint -> Bool+prop_add_sub_associative1 p q r = subEC (subEC p q) r == subEC p (addEC q r)++prop_add_sub_associative2 :: ECPoint -> ECPoint -> ECPoint -> Bool+prop_add_sub_associative2 p q r = addEC (subEC p q) r == subEC p (subEC q r)++prop_add_inv :: ECPoint -> Bool+prop_add_inv p = addEC p (invEC p) == ECInfinity++prop_mul_big :: ECPoint -> BigInt -> Bool+prop_mul_big p (BigInt k) = mulEC p k == mulEC p (mod k secp256k1_n)++prop_mul_0 :: ECPoint -> Bool+prop_mul_0 p = mulEC p 0 == ECInfinity++prop_mul_1 :: ECPoint -> Bool+prop_mul_1 p = mulEC p 1 == p++prop_mul_2 :: ECPoint -> Bool+prop_mul_2 p = mulEC p 2 == addEC p p++prop_mul_n :: ECPoint -> Bool+prop_mul_n p = mulEC p secp256k1_n == ECInfinity++prop_mul_nminus1 :: ECPoint -> Bool+prop_mul_nminus1 p = mulEC p (secp256k1_n - 1) == invEC p++--------------------------------------------------------------------------------
+ Bitcoin/Test/Crypto/FiniteField/FastFp.hs view
@@ -0,0 +1,223 @@+++{-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns #-}+module Bitcoin.Test.Crypto.FiniteField.FastFp where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits++import Test.Tasty+import Test.Tasty.QuickCheck +import Test.QuickCheck ( Arbitrary(..) , choose , quickCheckWith , stdArgs , maxSuccess , Testable , Property , (==>) )++import Bitcoin.Crypto.Word256+import Bitcoin.Test.Crypto.Word256 ()+import Bitcoin.Crypto.FiniteField.Fast.Fp +import qualified Bitcoin.Crypto.FiniteField.Naive.Fp as Naive+import Bitcoin.Test.Misc.QuickCheck++--------------------------------------------------------------------------------++testgroup_FastFp :: TestTree+testgroup_FastFp = testGroup "Fast.Fp"+  [ testProperty "conversion /1a"         prop_convert1+  , testProperty "conversion /1b"         prop_convert1b+  , testProperty "conversion /2"          prop_convert2+  , testProperty "addition"               prop_add +  , testProperty "addition /2"            prop_add2+  , testProperty "subtraction"            prop_sub+  , testProperty "subtraction /2"         prop_sub2+  , testProperty "negation is involution" prop_doubleneg+  , testProperty "small multiplication"   prop_mul_small +  , testProperty "multiplication"         prop_mul +  , testProperty "multiplication /2"      prop_mul2 +  , testProperty "division"               prop_div+  , testProperty "division /2"            prop_div2+  , testProperty "reciprocal"             prop_recip+  , testProperty "mult. inverse /1"       prop_inv1+  , testProperty "mult. inverse /2"       prop_inv2+  , testProperty "mult. inverse /3"       prop_inv3+  , testProperty "square root"            prop_sqrt+  , testProperty "square root/2"          prop_sqrt2+  , testProperty "power"                  prop_pow+  , testProperty "exponent is additive"   prop_pow_add+  , testProperty "0th power"              prop_pow_0+  , testProperty "1st power"              prop_pow_1+  , testProperty "2nd power"              prop_pow_2+  , testProperty "3rd power"              prop_pow_3+  , testProperty "p-th power"             prop_pow_p+  , testProperty "(p-1)-th power"         prop_pow_pminus1+  , testProperty "small powers"           prop_pow_small+  ]++--------------------------------------------------------------------------------+-- * quickcheck++modP :: Integer -> Integer+modP k = mod k secp256k1_p++newtype NonZeroFp  = NonZeroFp Fp deriving (Eq,Show)  +newtype SmallFp    = SmallFp   Fp deriving (Eq,Show)  ++instance Arbitrary Fp where+  arbitrary = do+    n <- choose (0,secp256k1_p-1)+    return $ toFp n++instance Arbitrary NonZeroFp where+  arbitrary = do+    n <- choose (1,secp256k1_p-1)+    return $ NonZeroFp $ toFp n++instance Arbitrary SmallFp where+  arbitrary = do+    n <- choose (0,2^129-1)+    return $ SmallFp $ toFp n++naive :: Fp -> Naive.Fp+naive = Naive.toFp . fromFp ++--------------------------------------------------------------------------------++{-+runAllTests_fp_fast :: IO ()+runAllTests_fp_fast = runAllTests_fp_fast' 1000++runAllTests_fp_fast' :: Int -> IO ()+runAllTests_fp_fast' n = do+  let args = stdArgs { maxSuccess = n }+  let qc :: Testable prop => prop -> IO ()+      qc = quickCheckWith args+ +  putStrLn "running all tests in Bitcoin.Crypto.FiniteField.Fast.Fp"+  putStrLn "======================================================="+  qc prop_convert1+  qc prop_convert1b+  qc prop_convert2+  qc prop_add +  qc prop_add2+  qc prop_sub+  qc prop_sub2+  qc prop_doubleneg+  qc prop_mul_small+  qc prop_mul +  qc prop_mul2+  qc prop_div+  qc prop_div2+  qc prop_recip+  qc prop_inv1+  qc prop_inv2+  qc prop_inv3+  qc prop_sqrt+  qc prop_sqrt2+  qc prop_pow+  qc prop_pow_add+  qc prop_pow_0+  qc prop_pow_2+  qc prop_pow_3+  qc prop_pow_p+  qc prop_pow_pminus1+-}++--------------------------------------------------------------------------------++prop_convert1 :: Integer -> Bool+prop_convert1 n  =  fromFp (toFp n) == modP n++prop_convert1b :: BigInt -> Bool+prop_convert1b (BigInt n)  =  fromFp (toFp n) == modP n++prop_convert2 :: Fp -> Bool+prop_convert2 n  =  toFp (fromFp n) == n++prop_add :: Fp -> Fp -> Bool+prop_add a b = fromFp (a+b) == modP (fromFp a + fromFp b)++prop_sub :: Fp -> Fp -> Bool+prop_sub a b = fromFp (a-b) == modP (fromFp a - fromFp b)++prop_add2 :: Fp -> Fp -> Bool+prop_add2 a b = fromFp (a+b) == Naive.fromFp (naive a + naive b)++prop_sub2 :: Fp -> Fp -> Bool+prop_sub2 a b = fromFp (a-b) == Naive.fromFp (naive a - naive b)++prop_doubleneg :: Fp -> Bool+prop_doubleneg a = (-(-a)) == a++prop_mul :: Fp -> Fp -> Bool+prop_mul a b = fromFp (a*b) == modP (fromFp a * fromFp b)++prop_mul_small :: SmallFp -> SmallFp -> Bool+prop_mul_small (SmallFp a) (SmallFp b) = (fromFp (a*b) == modP (fromFp a * fromFp b)) +{-+  = debug "fast" (a*b)+  $ debug "gmp"  (toFp $ modP (fromFp a * fromFp b))+  $ (fromFp (a*b) == modP (fromFp a * fromFp b)) +  where+    debug :: String -> Fp -> a -> a+    debug !s !x y = trace ("\n >>> " ++ s ++ " -> " ++ show x ++ "\n") y+-}++prop_div :: Fp -> NonZeroFp -> Bool+prop_div a (NonZeroFp b) = (toFp $ fromFp (a/b)) * b == a++prop_mul2 :: Fp -> Fp -> Bool+prop_mul2 a b = fromFp (a*b) == Naive.fromFp (naive a * naive b)++prop_div2 :: Fp -> NonZeroFp -> Bool+prop_div2 a (NonZeroFp b) = fromFp (a/b) == Naive.fromFp (naive a / naive b)++prop_recip :: NonZeroFp -> Bool+prop_recip (NonZeroFp b) = (toFp $ fromFp (1/b)) * b == 1++prop_inv1 :: NonZeroFp -> Bool+prop_inv1 (NonZeroFp b) = (inv_modp_power (unFp b) == inv_modp_euclid (unFp b))++prop_inv2 :: NonZeroFp -> Bool+prop_inv2 (NonZeroFp b) = (inv_modp_pow_spec (unFp b) == inv_modp_euclid (unFp b))++prop_inv3 :: NonZeroFp -> Bool+prop_inv3 (NonZeroFp b) = (inv_modp_power (unFp b) == inv_modp_pow_spec (unFp b))++prop_sqrt :: Fp -> Bool+prop_sqrt a = case sqrtFp (unFp a) of+  Nothing -> True+  Just x  -> (Fp x)*(Fp x) == a++prop_sqrt2 :: Fp -> Bool+prop_sqrt2 a = (fromFp <$> sqrt_p a) == (Naive.fromFp <$> Naive.sqrt_p (naive a))++prop_pow :: Fp -> Word256 -> Bool+prop_pow a k = fromFp (pow_p a k) == Naive.fromFp (Naive.pow_p (naive a) (fromWord256 k))++prop_pow_add :: Fp -> MediumInt -> MediumInt -> Property    -- Bool+prop_pow_add a (MediumInt k) (MediumInt l) = +  (k+l < twoToThe256) ==> (fromFp (pow_p a (toWord256 k) * pow_p a (toWord256 l)) == fromFp (pow_p a (toWord256 (k+l))))++prop_pow_0 :: Fp -> Bool+prop_pow_0 a = fromFp (pow_p a 0) == 1++prop_pow_1 :: Fp -> Bool+prop_pow_1 a = (pow_p a 1) == a++prop_pow_2 :: Fp -> Bool+prop_pow_2 a = (pow_p a 2) == a*a++prop_pow_3 :: Fp -> Bool+prop_pow_3 a = (pow_p a 3) == a*a*a++prop_pow_p :: Fp -> Bool+prop_pow_p a = (pow_p a (toWord256 secp256k1_p)) == a++prop_pow_pminus1 :: Fp -> Bool+prop_pow_pminus1 a = fromFp (pow_p a (toWord256 (secp256k1_p-1))) == 1++prop_pow_small :: Fp -> SmallExpo -> Bool+prop_pow_small a (SmallExpo k) = pow_p a (fromIntegral k) == product (replicate k a)++--------------------------------------------------------------------------------++
+ Bitcoin/Test/Crypto/FiniteField/NaiveFp.hs view
@@ -0,0 +1,168 @@+++{-# LANGUAGE CPP, BangPatterns #-}+module Bitcoin.Test.Crypto.FiniteField.NaiveFp where++--------------------------------------------------------------------------------++import Prelude hiding ( sqrt )++import Test.Tasty+import Test.Tasty.QuickCheck +import Test.QuickCheck ( Arbitrary(..) , choose , quickCheckWith , stdArgs , maxSuccess , Testable )++import Bitcoin.Crypto.FiniteField.Naive.Fp +import Bitcoin.Test.Misc.QuickCheck++--------------------------------------------------------------------------------++testgroup_NaiveFp :: TestTree+testgroup_NaiveFp = testGroup "Naive.Fp"+  [ testProperty "conversion /1a"         prop_convert1+  , testProperty "conversion /1b"         prop_convert1b+  , testProperty "conversion /2"          prop_convert2+  , testProperty "addition"               prop_add +  , testProperty "subtraction"            prop_sub+  , testProperty "negation is involution" prop_doubleneg+  , testProperty "multiplication"         prop_mul +  , testProperty "division"               prop_div+  , testProperty "reciprocal"             prop_recip+  , testProperty "mult. inverse /1"       prop_inv_algos+  , testProperty "mult. inverse /2"       prop_inv_algos2+  , testProperty "mult. inverse /3"       prop_inv_algos3+  , testProperty "square root"            prop_sqrt+  , testProperty "exponent is additive"   prop_pow_add+  , testProperty "0th power"              prop_pow_0+  , testProperty "1st power"              prop_pow_1+  , testProperty "2nd power"              prop_pow_2+  , testProperty "3rd power"              prop_pow_3+  , testProperty "p-th power"             prop_pow_p+  , testProperty "(p-1)-th power"         prop_pow_pminus1+  , testProperty "small powers"           prop_pow_small+  ]++--------------------------------------------------------------------------------+-- * quickcheck++modP :: Integer -> Integer+modP k = mod k secp256k1_p++newtype NonZeroFp = NonZeroFp Fp deriving (Eq,Show)  ++instance Arbitrary Fp where+  arbitrary = do+    n <- choose (0,secp256k1_p-1)+    return $ toFp n++instance Arbitrary NonZeroFp where+  arbitrary = do+    n <- choose (1,secp256k1_p-1)+    return $ NonZeroFp $ toFp n++--------------------------------------------------------------------------------++{-+runAllTests_fp_naive :: IO ()+runAllTests_fp_naive = runAllTests_fp_naive' 1000++runAllTests_fp_naive' :: Int -> IO ()+runAllTests_fp_naive' n = do+  let args = stdArgs { maxSuccess = n }+  let qc :: Testable prop => prop -> IO ()+      qc = quickCheckWith args+ +  putStrLn "running all tests in Bitcoin.Crypto.FiniteField.Naive.Fp"+  putStrLn "========================================================"+  qc prop_convert1+  qc prop_convert1b+  qc prop_convert2+  qc prop_add +  qc prop_sub+  qc prop_doubleneg+  qc prop_mul +  qc prop_div+  qc prop_recip+  qc prop_inv_algos+  qc prop_inv_algos2+  qc prop_inv_algos3+  qc prop_sqrt+  qc prop_pow_add+  qc prop_pow_0+  qc prop_pow_1+  qc prop_pow_2+  qc prop_pow_3+  qc prop_pow_p+  qc prop_pow_pminus1+-}++--------------------------------------------------------------------------------++prop_convert1 :: Integer -> Bool+prop_convert1 n  =  fromFp (toFp n) == modP n++prop_convert1b :: BigInt -> Bool+prop_convert1b (BigInt n)  =  fromFp (toFp n) == modP n++prop_convert2 :: Fp -> Bool+prop_convert2 n  =  toFp (fromFp n) == n++prop_add :: Fp -> Fp -> Bool+prop_add a b = fromFp (a+b) == modP (fromFp a + fromFp b)++prop_sub :: Fp -> Fp -> Bool+prop_sub a b = fromFp (a-b) == modP (fromFp a - fromFp b)++prop_doubleneg :: Fp -> Bool+prop_doubleneg a = (-(-a)) == a++prop_mul :: Fp -> Fp -> Bool+prop_mul a b = fromFp (a*b) == modP (fromFp a * fromFp b)++prop_div :: Fp -> NonZeroFp -> Bool+prop_div a (NonZeroFp b) = (toFp $ fromFp (a/b)) * b == a++prop_recip :: NonZeroFp -> Bool+prop_recip (NonZeroFp b) = (toFp $ fromFp (1/b)) * b == 1++prop_inv_algos :: NonZeroFp -> Bool+prop_inv_algos (NonZeroFp (Fp a)) = (invFp_pow a == invFp_euclid a)++prop_inv_algos2 :: NonZeroFp -> Bool+prop_inv_algos2 (NonZeroFp (Fp a)) = (invFp_pow_spec (Fp a) == Fp (invFp_euclid a))++prop_inv_algos3 :: NonZeroFp -> Bool+prop_inv_algos3 (NonZeroFp (Fp a)) = (Fp (invFp_pow a) == invFp_pow_spec (Fp a))++-- prop_cmp :: Fp -> Fp -> Bool+-- prop_cmp a b = (a >= b) == (fromFp a >= fromFp b)++prop_sqrt :: Fp -> Bool+prop_sqrt a = case sqrtFp (unFp a) of+  Nothing -> True+  Just x  -> (Fp x)*(Fp x) == a++prop_pow_add :: Fp -> BigInt -> BigInt -> Bool+prop_pow_add a (BigInt k) (BigInt l) = fromFp (pow_p a k * pow_p a l) == fromFp (pow_p a (k+l)) ++prop_pow_0 :: Fp -> Bool+prop_pow_0 a = fromFp (pow_p a 0) == 1++prop_pow_1 :: Fp -> Bool+prop_pow_1 a = (pow_p a 1) == a++prop_pow_2 :: Fp -> Bool+prop_pow_2 a = (pow_p a 2) == a*a++prop_pow_3 :: Fp -> Bool+prop_pow_3 a = (pow_p a 3) == a*a*a++prop_pow_p :: Fp -> Bool+prop_pow_p a = pow_p a secp256k1_p == a++prop_pow_pminus1 :: Fp -> Bool+prop_pow_pminus1 a = fromFp (pow_p a (secp256k1_p-1)) == 1++prop_pow_small :: Fp -> SmallExpo -> Bool+prop_pow_small a (SmallExpo k) = pow_p a (fromIntegral k) == product (replicate k a)++--------------------------------------------------------------------------------
+ Bitcoin/Test/Crypto/Key.hs view
@@ -0,0 +1,77 @@++{-# LANGUAGE CPP, BangPatterns #-}+module Bitcoin.Test.Crypto.Key where++--------------------------------------------------------------------------------++import Test.Tasty+import Test.Tasty.QuickCheck +import Test.QuickCheck ( Arbitrary(..) , choose , quickCheckWith , stdArgs , maxSuccess , Testable )++import Bitcoin.Crypto.FiniteField.Fast.Fp  hiding ( secp256k1_p )+import Bitcoin.Crypto.FiniteField.Naive.Fn hiding ( secp256k1_n )++import Bitcoin.Crypto.EC.Curve+import Bitcoin.Crypto.EC.Key++import Bitcoin.Test.Crypto.Curve+import Bitcoin.Test.Misc.QuickCheck++--------------------------------------------------------------------------------++testgroup_Key :: TestTree+testgroup_Key = testGroup "EC.Key"+  [ testProperty "uncompress . compress == id"      prop_compr_uncompr       +  , testProperty "uncompressed pubkeys are valid"   prop_valid_pubkey    +  , testProperty "compressed pubkeys are valid"     prop_valid_compr_pubkey    +  , testProperty "calculated pubkeys are valid"     prop_valid_calc_pubkey +  ]++--------------------------------------------------------------------------------+-- quickcheck++instance Arbitrary PrivKey where+  arbitrary = do+    n <- choose (1,secp256k1_n-1)+    return (PrivKey n)++instance Arbitrary PubKey where+  arbitrary = do+    NonZeroEC (ECPoint x y) <- arbitrary+    return (FullPubKey (fromFp x) (fromFp y))  ++--------------------------------------------------------------------------------++{-+runAllTests_ec_key :: IO ()+runAllTests_ec_key = runAllTests_ec_key' 1000++runAllTests_ec_key' :: Int -> IO ()+runAllTests_ec_key' n = do+  let args = stdArgs { maxSuccess = n }+  let qc :: Testable prop => prop -> IO ()+      qc = quickCheckWith args+ +  putStrLn "running all tests in Bitcoin.Crypto.EC.Key"+  putStrLn "=========================================="+  qc prop_compr_uncompr+  qc prop_valid_pubkey+-}++--------------------------------------------------------------------------------++prop_compr_uncompr :: PubKey -> Bool+prop_compr_uncompr key = uncompressPubKey (compressPubKey key) == Just key++prop_valid_pubkey :: PubKey -> Bool+prop_valid_pubkey = isValidPubKey++prop_valid_compr_pubkey :: PubKey -> Bool+prop_valid_compr_pubkey = isValidPubKey . compressPubKey++prop_valid_calc_pubkey :: PrivKey -> Bool+prop_valid_calc_pubkey priv +  =  isValidPubKey (computePubKey Compressed   priv) +  && isValidPubKey (computePubKey Uncompressed priv) ++--------------------------------------------------------------------------------
+ Bitcoin/Test/Crypto/Projective.hs view
@@ -0,0 +1,268 @@+
+
+{-# LANGUAGE CPP, BangPatterns, ForeignFunctionInterface #-}
+module Bitcoin.Test.Crypto.Projective where
+
+--------------------------------------------------------------------------------
+
+import Test.Tasty
+import Test.Tasty.QuickCheck 
+import Test.QuickCheck ( Arbitrary(..) , choose , quickCheckWith , stdArgs , maxSuccess , Testable )
+
+import Bitcoin.Crypto.FiniteField.Fast.Fp  hiding ( secp256k1_p )
+import Bitcoin.Crypto.FiniteField.Naive.Fn hiding ( secp256k1_n )
+import Bitcoin.Crypto.EC.Curve
+import Bitcoin.Crypto.EC.Projective
+
+import Bitcoin.Test.Crypto.Curve ()
+import Bitcoin.Test.Misc.QuickCheck
+
+--------------------------------------------------------------------------------
+
+testgroup_Projective :: TestTree
+testgroup_Projective = testGroup "EC.Projective" [ testgroup_proj , testgroup_ecp ]
+
+testgroup_proj :: TestTree
+testgroup_proj = testGroup "proj (projective curve representation)"
+  [ testProperty "left unit"               prop_proj_left_unit
+  , testProperty "right unit"              prop_proj_right_unit
+  , testProperty "0 + 0 = 0"               prop_proj_add_dbl_unit 
+  , testProperty "2*0 = 0"                 prop_proj_dbl_unit 
+  , testProperty "-0 = 0"                  prop_proj_inv_unit  -- 5
+  , testProperty "(p+q)-q = p"             prop_proj_add_sub
+  , testProperty "((p+q)-q)-p = 0"         prop_proj_add_sub2
+  , testProperty "2*p - p = p"             prop_proj_dbl_sub
+  , testProperty "2*p - p - p = 0"         prop_proj_dbl_sub2
+  , testProperty "addition is commutative" prop_proj_add_commutative  -- 10
+  , testProperty "addition is associative" prop_proj_add_associative
+  , testProperty "(p-q)-r = p-(q+r)"       prop_proj_add_sub_associative1
+  , testProperty "(p-q)+r = p-(q-r)"       prop_proj_add_sub_associative2
+  , testProperty "p + (-p) = 0"            prop_proj_add_inv
+  , testProperty "k*p = (k mod n)*p"       prop_proj_mul_big  -- 15
+  , testProperty "0*p = 0"                 prop_proj_mul_0
+  , testProperty "1*p = p"                 prop_proj_mul_1
+  , testProperty "2*p = p + p"             prop_proj_mul_2
+  , testProperty "n*p = 0"                 prop_proj_mul_n    -- 20
+  , testProperty "(n-1)*p = -p"            prop_proj_mul_nminus1
+  , testProperty "hs add = c add"          prop_proj_add_chs
+  , testProperty "hs dbl = c dbl"          prop_proj_dbl_chs
+  , testProperty "hs mul = c mul"          prop_proj_mul_chs
+  ]
+
+testgroup_ecp :: TestTree
+testgroup_ecp = testGroup "ecp (projective vs. affine conversions)"
+  [ testProperty "fromP . toP = id"        prop_ecp_from_to
+  , testProperty "toP (fromP p) ~ p"       prop_ecp_to_from
+  , testProperty "proj. addition"          prop_ecp_add
+  , testProperty "proj. subtraction"       prop_ecp_sub
+  , testProperty "proj. doubling /1"       prop_ecp_add_dbl1
+  , testProperty "proj. doubling /2"       prop_ecp_add_dbl2
+  , testProperty "proj. doubling /3"       prop_ecp_add_dbl3
+  , testProperty "proj. doubling /4"       prop_ecp_add_dbl4
+  , testProperty "proj. doubling /5"       prop_ecp_dbl
+  , testProperty "proj. inverse /1"        prop_ecp_inv1
+  , testProperty "proj. inverse /2"        prop_ecp_inv2
+  , testProperty "proj. inverse /3"        prop_ecp_inv3
+  , testProperty "proj. multiplication"    prop_ecp_mul
+  ]
+
+--------------------------------------------------------------------------------
+-- * quickcheck
+
+scaleECProj :: Integer -> ECProj -> ECProj 
+scaleECProj n0 (ECProj x y z) = ECProj (x*n2) (y*n3) (z*n) where
+  n  = toFp n0
+  n2 = n*n
+  n3 = n2*n
+
+newtype NonZeroECP = NonZeroECP ECProj deriving (Eq,Show)
+
+data Same = Same ECProj ECProj deriving (Eq,Show)
+
+instance Arbitrary ECProj where
+  arbitrary = do
+    ec <- arbitrary 
+    z  <- toFp <$> choose (1,secp256k1_p-1)
+    let z2 = z*z
+    let z3 = z2*z
+    return $ case ec of
+      ECPoint x y -> ECProj (x*z2) (y*z3*2) z 
+      ECInfinity  -> ecpInfinity
+
+instance Arbitrary NonZeroECP where
+  arbitrary = do
+    n <- choose (1,secp256k1_n-1)
+    return $ NonZeroECP $ mulECP (secp256k1_G_proj) n
+
+instance Arbitrary Same where
+  arbitrary = do
+    ep@(ECProj x y z) <- arbitrary
+    m  <- toFp <$> choose (1,secp256k1_p-1)
+    return $ Same ep (ECProj (x*m*m) (y*m*m*m) (z*m))
+
+--------------------------------------------------------------------------------
+
+{- 
+runAllTests_ec_proj :: IO ()
+runAllTests_ec_proj = runAllTests_ec_proj' 1000
+
+runAllTests_ec_proj' :: Int -> IO ()
+runAllTests_ec_proj' n = do
+  let args = stdArgs { maxSuccess = n }
+  let qc :: Testable prop => prop -> IO ()
+      qc = quickCheckWith args
+ 
+  putStrLn "running all tests in Bitcoin.Crypto.EC.Projective"
+  putStrLn "================================================="
+  qc prop_proj_left_unit
+  qc prop_proj_right_unit
+  qc prop_proj_add_dbl_unit 
+  qc prop_proj_dbl_unit 
+  qc prop_proj_inv_unit  -- 5
+  qc prop_proj_add_sub
+  qc prop_proj_add_sub2
+  qc prop_proj_dbl_sub
+  qc prop_proj_dbl_sub2
+  qc prop_proj_add_commutative  -- 10
+  qc prop_proj_add_associative
+  qc prop_proj_add_sub_associative1
+  qc prop_proj_add_sub_associative2
+  qc prop_proj_add_inv
+  qc prop_proj_mul_big  -- 15
+  qc prop_proj_mul_0
+  qc prop_proj_mul_1
+  qc prop_proj_mul_2
+  qc prop_proj_mul_n    -- 20
+  qc prop_proj_mul_nminus1
+  qc prop_proj_add_chs
+  qc prop_proj_dbl_chs
+  qc prop_proj_mul_chs
+  putStrLn "-------------------------------------------------"
+  qc prop_ecp_from_to
+  qc prop_ecp_to_from
+  qc prop_ecp_add
+  qc prop_ecp_add_dbl1
+  qc prop_ecp_add_dbl2
+  qc prop_ecp_add_dbl3
+  qc prop_ecp_add_dbl4
+  qc prop_ecp_dbl
+  qc prop_ecp_sub
+  qc prop_ecp_inv1
+  qc prop_ecp_inv2
+  qc prop_ecp_inv3
+  qc prop_ecp_mul
+-}
+
+--------------------------------------------------------------------------------
+
+prop_proj_left_unit :: ECProj  -> Bool
+prop_proj_left_unit p = addECP p ecpInfinity =~= p
+
+prop_proj_right_unit :: ECProj  -> Bool
+prop_proj_right_unit q = addECP ecpInfinity q =~= q
+
+prop_proj_add_dbl_unit :: Bool
+prop_proj_add_dbl_unit = ecpInfinity + ecpInfinity =~= ecpInfinity
+
+prop_proj_dbl_unit :: Bool
+prop_proj_dbl_unit = dblECP ecpInfinity =~= ecpInfinity
+
+prop_proj_inv_unit :: Bool
+prop_proj_inv_unit = invECP ecpInfinity =~= ecpInfinity
+
+prop_proj_add_sub :: ECProj -> ECProj -> Bool
+prop_proj_add_sub p q  = subECP (addECP p q) q =~= p
+
+prop_proj_add_sub2 :: ECProj -> ECProj -> Bool
+prop_proj_add_sub2 p q  = subECP (subECP (addECP p q) q) p =~= ecpInfinity
+
+prop_proj_dbl_sub :: ECProj -> Bool
+prop_proj_dbl_sub p = subECP (dblECP p) p =~= p
+
+prop_proj_dbl_sub2 :: ECProj -> Bool
+prop_proj_dbl_sub2 p = subECP (subECP (dblECP p) p) p =~= ecpInfinity
+
+prop_proj_add_commutative :: ECProj -> ECProj -> Bool
+prop_proj_add_commutative p q  = (addECP p q) =~= (addECP q p)
+
+prop_proj_add_associative :: ECProj -> ECProj -> ECProj -> Bool
+prop_proj_add_associative p q r = addECP (addECP p q) r =~= addECP p (addECP q r)
+
+prop_proj_add_sub_associative1 :: ECProj -> ECProj -> ECProj -> Bool
+prop_proj_add_sub_associative1 p q r = subECP (subECP p q) r =~= subECP p (addECP q r)
+
+prop_proj_add_sub_associative2 :: ECProj -> ECProj -> ECProj -> Bool
+prop_proj_add_sub_associative2 p q r = addECP (subECP p q) r =~= subECP p (subECP q r)
+
+prop_proj_add_inv :: ECProj -> Bool
+prop_proj_add_inv p = addECP p (invECP p) =~= ecpInfinity
+
+prop_proj_mul_big :: ECProj -> BigInt -> Bool
+prop_proj_mul_big p (BigInt k) = mulECP p k =~= mulECP p (mod k secp256k1_n)
+
+prop_proj_mul_0 :: ECProj -> Bool
+prop_proj_mul_0 p = mulECP p 0 =~= ecpInfinity
+
+prop_proj_mul_1 :: ECProj -> Bool
+prop_proj_mul_1 p = mulECP p 1 =~= p
+
+prop_proj_mul_2 :: ECProj -> Bool
+prop_proj_mul_2 p = mulECP p 2 =~= addECP p p
+
+prop_proj_mul_n :: ECProj -> Bool
+prop_proj_mul_n p = mulECP p secp256k1_n =~= ecpInfinity
+
+prop_proj_mul_nminus1 :: ECProj -> Bool
+prop_proj_mul_nminus1 p = mulECP p (secp256k1_n - 1) =~= invECP p
+
+prop_proj_dbl_chs :: ECProj -> Bool
+prop_proj_dbl_chs p = hs_dblECP p == c_dblECP p
+
+prop_proj_add_chs :: ECProj -> ECProj -> Bool
+prop_proj_add_chs p q = hs_addECP p q == c_addECP p q
+
+prop_proj_mul_chs :: ECProj -> BigInt -> Bool
+prop_proj_mul_chs p (BigInt n) = c_mulECP p n =~= hs_mulECP p n
+
+--------------------------------------------------------------------------------
+
+prop_ecp_to_from :: ECPoint -> Bool
+prop_ecp_to_from p = fromECProj (toECProj p) == p
+
+prop_ecp_from_to :: ECProj -> Bool
+prop_ecp_from_to p = toECProj (fromECProj p) =~= p
+
+prop_ecp_add :: ECPoint -> ECPoint -> Bool
+prop_ecp_add p q = p + q == fromECProj (toECProj p + toECProj q) 
+
+prop_ecp_add_dbl1 :: ECPoint -> Bool
+prop_ecp_add_dbl1 p = p + p == fromECProj (toECProj p + toECProj p) 
+
+prop_ecp_add_dbl2 :: ECPoint -> Bool
+prop_ecp_add_dbl2 p = dblEC p == fromECProj (toECProj p + toECProj p) 
+
+prop_ecp_add_dbl3 :: Same -> Bool
+prop_ecp_add_dbl3 (Same p q) = fromECProj p + fromECProj q == fromECProj (p+q) 
+
+prop_ecp_add_dbl4 :: Same -> Bool
+prop_ecp_add_dbl4 (Same p q) = dblEC (fromECProj p) == fromECProj (p+q) 
+
+prop_ecp_sub :: ECPoint -> ECPoint -> Bool
+prop_ecp_sub p q = p - q == fromECProj (toECProj p - toECProj q) 
+
+prop_ecp_dbl :: ECPoint -> Bool
+prop_ecp_dbl p = dblEC p == fromECProj (dblECP $ toECProj p) 
+
+prop_ecp_inv1 :: ECPoint -> Bool
+prop_ecp_inv1 p = invEC p == fromECProj (invECP $ toECProj p) 
+
+prop_ecp_inv2 :: ECPoint -> Bool
+prop_ecp_inv2 p = ecpInfinity =~= (invECP $ toECProj p) + (toECProj p)
+
+prop_ecp_inv3 :: Same -> Bool
+prop_ecp_inv3 (Same p q) = (invECP p =~= invECP q) 
+
+prop_ecp_mul :: ECPoint -> BigInt -> Bool
+prop_ecp_mul p (BigInt n) = fromECProj (mulECP (toECProj p) n) == mulEC p n
+
+--------------------------------------------------------------------------------
+ Bitcoin/Test/Crypto/RFC6979.hs view
@@ -0,0 +1,251 @@+
+-- | Test vectors for the RFC 6979 based deterministic DSA
+
+module Bitcoin.Test.Crypto.RFC6979 where
+
+--------------------------------------------------------------------------------
+
+import Data.Word
+
+import Bitcoin.Crypto.EC.DSA  -- hiding ( signMessageHashRFC6979 )
+import Bitcoin.Protocol
+import Bitcoin.Misc
+import Bitcoin.Crypto.Hash.SHA256
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+--------------------------------------------------------------------------------
+
+testgroup_RFC6979 :: TestTree
+testgroup_RFC6979 = testGroup "RFC 6979 (deterministic DSA)" 
+  [ testgroup_Haskoin
+  , testgroup_FPGAMiner
+  ]
+
+testgroup_Haskoin :: TestTree
+testgroup_Haskoin = testGroup "Haskoin test vectors" 
+  [ testCase ("haskoin test vector #" ++ show i) (assertRight $ haskoin_test vec) 
+  | (i,vec) <- zip [1..] haskoin_test_vectors 
+  ]
+
+testgroup_FPGAMiner :: TestTree
+testgroup_FPGAMiner = testGroup "FPGAMiner test vectors"
+  [ testCase ("fpgaminer test vector #" ++ show i) (assertRight $ fpgaminer_test vec) 
+  | (i,vec) <- zip [1..] fpgaminer_test_vectors 
+  ]
+
+assertRight :: Either String a -> Assertion
+assertRight ei = case ei of
+  Left err -> assertFailure err
+  Right {} -> return ()
+
+--------------------------------------------------------------------------------
+
+{-
+runTestRFC6979 :: IO ()
+runTestRFC6979 = do
+  putStrLn "haskoin test vectors:"
+  mapM_ print $ map haskoin_test haskoin_test_vectors
+  putStrLn "fpgaminer test vectors:"
+  mapM_ print $ map fpgaminer_test fpgaminer_test_vectors
+-}
+
+--------------------------------------------------------------------------------
+
+{-  the (old - before projective) implementation (but the differences are very minor)
+
+import Bitcoin.Crypto.Hash.HMAC
+import Bitcoin.Crypto.EC.Base
+import Bitcoin.Crypto.FiniteField.Fast.Fp
+import Bitcoin.Crypto.FiniteField.Naive.Fn hiding ( secp256k1_n )
+
+-- | Deterministic signature as specified by RFC 6979: 
+-- <http://tools.ietf.org/html/rfc6979>, in particular section 3.2
+--
+signMessageHashRFC6979 :: PrivKey -> Hash256 -> (SignBits,Signature)
+signMessageHashRFC6979 (PrivKey da) hash = result where
+
+  hmac_k :: OctetStream a => a -> [Word8] -> [Word8]
+  hmac_k key = toWord8List . unHMAC . hmacSha256 (hmacKeyFromString64 key)
+
+  z    = mod (hashInteger hash) secp256k1_n           -- for z, it doesn't matter (it will be in Fn anyway), but for h1 it matters :(
+
+  x1   = bigEndianInteger32 da    :: [Word8]          -- x = private key here
+  h1   = bigEndianInteger32 z     :: [Word8]          -- step a
+
+  v0   = replicate 32 0x01 :: [Word8]                 -- step b
+  k0   = replicate 32 0x00 :: [Word8]                 -- step c
+  k1   = hmac_k k0 $ v0 ++ [0x00] ++ x1 ++ h1         -- step d
+  v1   = hmac_k k1 $ v0                               -- step e
+  k2   = hmac_k k1 $ v1 ++ [0x01] ++ x1 ++ h1         -- step f
+  v2   = hmac_k k2 $ v1                               -- step g
+  
+  result = step_h k2 v2
+
+  halfn = div secp256k1_n 2
+
+  step_h k v0 =                                       -- final step (step h)
+
+    if dsa_k > 0 && dsa_k < secp256k1_n && ep /= ECInfinity && r/=0 && s/=0
+      then (signbits,signature)
+      else step_h k' v'
+
+    where
+
+      v = hmac_k k v0          -- step h/1 
+      t = v                    -- step h/2 (always a single step in our case?)
+      dsa_k = toIntegerBE t
+
+      k' = hmac_k k  $ v ++ [0x00]
+      v' = hmac_k k' $ v
+
+      ep = mulEC secp256k1_G dsa_k
+      ECPoint x y = ep
+      r  = fromInteger (fromFp x)                                     :: Fn
+      s0 = (fromInteger z + r * fromInteger da) / (fromInteger dsa_k) :: Fn
+
+      -- hmm, it seems this extra rule is used for some reason ??
+      -- quote: "The theory behind this is: if you negate K you get the same R and the negated S. 
+      --         Hence you need to negate S as a post-processing step, i.e., S' = prime - S in both cases"
+      s = if (fromFn s0) > halfn then Fn (secp256k1_n - fromFn s0) else s0   
+
+      odd_y  = if even (fromFp y)      then 0 else 1
+      add_n  = if fromFn r == fromFp x then 0 else 2
+      w8 = odd_y + add_n 
+  
+      signbits  = SignBits w8
+      signature = Signature (fromFn r) (fromFn s)
+
+-}
+
+--------------------------------------------------------------------------------
+-- * Haskoin test vectors for RFC 6979 ECDSA (secp256k1, SHA-256)
+
+-- | As opposed to the double hash used in Bitcoin
+singleHash256 :: OctetStream a => a -> Hash256
+singleHash256 = fromByteString . unSHA256 . sha256
+
+-- | NOTE: because of the WIF encoding, this won't work when compileg with the testnet flag
+--
+haskoin_test :: (String,String,String,String,String) -> Either String ()
+haskoin_test (privstr, wifstr, msg, rsstr, dersig) = result where
+  Just (pkfmt,privkey1) 
+                = privKeyWIFDecode $ WIF wifstr
+  privkey2      = PrivKey 
+                $ toIntegerBE        ( fromHexString $ HexString privstr :: [Word8] )
+  Just (SignatureExt signat sighash)
+                = decodeSignatureDER ( (fromHexString $ HexString dersig) ++ [0x01] :: [Word8] )
+  msghash       = singleHash256 msg   -- doHash256 msg
+  rs            = fromHexString ( HexString rsstr ) :: [Word8]
+  r             = toIntegerBE (take 32 rs)
+  s             = toIntegerBE (drop 32 rs)
+
+  (mysignbits,mysignat) = signMessageHashRFC6979 privkey1 msghash
+  
+  result 
+    | privkey1 /= privkey2  = Left "rfc6979/haskoin_test: privkey decoding failed"
+    | signat   /= mysignat  = Left $ unlines $ 
+        [ "signature mismatch:"
+        , "  theirs: " ++ show signat 
+        , "  ours:   " ++ show mysignat
+        , "  (r,s):  " ++ show (r,s)
+        ]
+    | otherwise = Right ()
+    
+-- | Haskoin test vectors for RFC 6979 ECDSA (secp256k1, SHA-256)
+-- (PrvKey HEX, PrvKey WIF, message, R || S as HEX, sig as DER)
+--
+-- from: <https://bitcointalk.org/index.php?topic=285142.msg3300992#msg3300992>
+haskoin_test_vectors :: [(String,String,String,String,String)]
+haskoin_test_vectors = 
+  [ ( "0000000000000000000000000000000000000000000000000000000000000001"
+    , "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+    , "Everything should be made as simple as possible, but not simpler."
+    , "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
+    , "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
+    )
+    
+  , ( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"
+    , "L5oLkpV3aqBjhki6LmvChTCV6odsp4SXM6FfU2Gppt5kFLaHLuZ9"
+    , "Equations are more important to me, because politics is for the present, but an equation is something for eternity."
+    , "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
+    , "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
+    )
+    
+  , ( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"
+    , "L5oLkpV3aqBjhki6LmvChTCV6odsp4SXM6FfU2Gppt5kFLaHLuZ9"
+    , "Not only is the Universe stranger than we think, it is stranger than we can think."
+    , "ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd06fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"
+    , "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"
+    )
+    
+  , ( "0000000000000000000000000000000000000000000000000000000000000001"
+    , "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+    , "How wonderful that we have met with a paradox. Now we have some hope of making progress."
+    , "c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d375afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"
+    , "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"
+    )
+    
+  , ( "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64"
+    , "KzmcSTRmg8Gtoq8jbBCwsrvgiTKRrewQXniAHHTf7hsten8MZmBB"
+    , "Computer science is no more about computers than astronomy is about telescopes."
+    , "7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"
+    , "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"
+    )
+    
+  , ( "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637"
+    , "KwDiBf89QgGbjEhKnhXJwe1E2mCa8asowBrSKuCaBV6EsPYEAFZ8"
+    , "...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"
+    , "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"
+    )
+    
+  , ( "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3"
+    , "KwDiBf89QgGbjEhKnhXJuH7LrciVrZiib5S9h4knkymNojPUVsWN"
+    , "The question of whether computers can think is like the question of whether submarines can swim."
+    , "cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf906ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"
+    , "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"
+    )
+  ]
+  
+--------------------------------------------------------------------------------
+-- * fpgaminer test vectors 
+
+fpgaminer_test :: (Integer,String,Integer,String) -> Either String ()
+fpgaminer_test (privnum, msg, dsa_k, rsstr) = result where
+  privkey       = PrivKey privnum
+  msghash       = singleHash256 msg   -- doHash256 msg
+
+  rs = fromHexString $ HexString rsstr  :: [Word8]
+  r = toIntegerBE $ take 32 rs
+  s = toIntegerBE $ drop 32 rs
+  signat = Signature r s 
+
+  (mysignbits,mysignat) = signMessageHashRFC6979 privkey msghash
+  
+  result 
+    | signat   /= mysignat  = Left $ unlines $ 
+        [ "signature mismatch:"
+        , "  theirs: " ++ show signat 
+        , "  ours:   " ++ show mysignat
+        , "  k:      " ++ show dsa_k
+        ]
+    | otherwise = Right ()
+
+
+-- | Test Vectors for RFC 6979 ECDSA, secp256k1, SHA-256
+-- (private key, message, expected k, expected signature)
+--
+-- from <https://bitcointalk.org/index.php?topic=285142.msg3299061#msg3299061>
+fpgaminer_test_vectors :: [(Integer,String,Integer,String)]
+fpgaminer_test_vectors = 
+  [ (0x1, "Satoshi Nakamoto", 0x8F8A276C19F4149656B280621E358CCE24F5F52542772691EE69063B74F15D15, "934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d82442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5")
+  , (0x1, "All those moments will be lost in time, like tears in rain. Time to die...", 0x38AA22D72376B4DBC472E06C3BA403EE0A394DA63FC58D88686C611ABA98D6B3, "8600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21")
+  , (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140, "Satoshi Nakamoto", 0x33A19B60E25FB6F4435AF53A3D42D493644827367E6453928554F43E49AA6F90, "fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d06b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5")
+  , (0xf8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181, "Alan Turing", 0x525A82B70E67874398067543FD84C83D30C175FDC45FDEEE082FE13B1D7CFDF1, "7063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c58dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea")
+  , (0xe91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2, "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!", 0x1F4B84C23A86A221D233F2521BE018D9318639D5B8BBD6374A8A59232D16AD3D, "b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6")
+  ]
+  
+--------------------------------------------------------------------------------
+
+ Bitcoin/Test/Crypto/Word256.hs view
@@ -0,0 +1,136 @@++{-# LANGUAGE CPP, ForeignFunctionInterface #-}+module Bitcoin.Test.Crypto.Word256 where++--------------------------------------------------------------------------------++import Data.Word+import Data.Bits++-- import Bitcoin.Misc.BigInt++import Test.Tasty+import Test.Tasty.QuickCheck +import Test.QuickCheck ( Arbitrary(..) , choose , quickCheckWith , stdArgs , maxSuccess , Testable )++import Bitcoin.Test.Misc.QuickCheck+import Bitcoin.Crypto.Word256++--------------------------------------------------------------------------------++testgroup_Word256 :: TestTree+testgroup_Word256 = testGroup "Word256"+  [ testProperty "conversion /1a"         prop_convert1+  , testProperty "conversion /1b"         prop_convert1b+  , testProperty "conversion /2"          prop_convert2+  , testProperty "roll . unroll == id"    prop_unroll_roll+  , testProperty "addition"               prop_add +  , testProperty "subtraction"            prop_sub+  , testProperty "negation is involution" prop_doubleneg+  , testProperty "multiplication"         prop_mul +  , testProperty "scaling by 32 bit int"  prop_scale+  , testProperty "ordering"               prop_cmp+  , testProperty "is even"                prop_even +  , testProperty "is odd"                 prop_odd+  , testProperty "shift left by 32 bits"  prop_shiftl256_fullword +  , testProperty "shift left <= 31 bits"  prop_shiftl256_small +  , testProperty "shift right >= 32 bits" prop_shiftr256_fullword +  , testProperty "shift right by 32 bits" prop_shiftr256_small +  ]++--------------------------------------------------------------------------------+-- * quickcheck++modN :: Integer -> Integer+modN k = mod k twoToThe256++instance Arbitrary Word256 where+  arbitrary = do+    n <- choose (0,twoToThe256-1)+    return $ toWord256 n++--------------------------------------------------------------------------------++{-+runAllTests_word256 :: IO ()+runAllTests_word256 = runAllTests_word256' 1000++runAllTests_word256' :: Int -> IO ()+runAllTests_word256' n = do+  let args = stdArgs { maxSuccess = n }+  let qc :: Testable prop => prop -> IO ()+      qc = quickCheckWith args+ +  putStrLn "running all tests in Bitcoin.Crypto.Word256"+  putStrLn "==========================================="+  qc prop_convert1+  qc prop_convert1b+  qc prop_convert2+  qc prop_unroll_roll+  qc prop_add +  qc prop_sub+  qc prop_doubleneg+  qc prop_mul +  qc prop_scale+  qc prop_cmp+  qc prop_even +  qc prop_odd+  qc prop_shiftl256_fullword +  qc prop_shiftl256_small +  qc prop_shiftr256_fullword +  qc prop_shiftr256_small +-}++--------------------------------------------------------------------------------++prop_convert1 :: Integer -> Bool+prop_convert1 n  =  fromWord256 (toWord256 n) == modN n++prop_convert1b :: BigInt -> Bool+prop_convert1b (BigInt n)  =  fromWord256 (toWord256 n) == modN n++prop_convert2 :: Word256 -> Bool+prop_convert2 n  =  toWord256 (fromWord256 n) == n++prop_unroll_roll :: BigInt -> Bool+prop_unroll_roll (BigInt n)  = littleEndianRollInteger32 (littleEndianUnrollInteger32 n) == n++prop_add :: Word256 -> Word256 -> Bool+prop_add a b = fromWord256 (a+b) == modN (fromWord256 a + fromWord256 b)++prop_sub :: Word256 -> Word256 -> Bool+prop_sub a b = fromWord256 (a-b) == modN (fromWord256 a - fromWord256 b)++prop_doubleneg :: Word256 -> Bool+prop_doubleneg a = (-(-a)) == a++prop_mul :: Word256 -> Word256 -> Bool+prop_mul a b = fromWord256 (a*b) == modN (fromWord256 a * fromWord256 b)++prop_scale :: Word256 -> Word32 -> Bool+prop_scale n k = modN (fromWord256 n * fromIntegral k) == fromWord256 (scale256 n k)++prop_cmp :: Word256 -> Word256 -> Bool+prop_cmp a b = (a >= b) == (fromWord256 a >= fromWord256 b)++prop_even :: Word256 -> Bool+prop_even a = isEven256 a == even (fromWord256 a)++prop_odd :: Word256 -> Bool+prop_odd a = isOdd256 a == odd (fromWord256 a)++prop_shiftl256_fullword :: Word256 -> Bool+prop_shiftl256_fullword a = fromWord256 (shiftl256_fullword a) == modN (shiftL (fromWord256 a) 32)++prop_shiftl256_small :: Word256 -> SmallInt32 -> Bool+prop_shiftl256_small a (SmallInt32 k) = fromWord256 (shiftl256_small a (fromIntegral k)) == modN (shiftL (fromWord256 a) k)++prop_shiftr256_fullword :: Word256 -> Bool+prop_shiftr256_fullword a = fromWord256 (shiftr256_fullword a) == (shiftR (fromWord256 a) 32)++prop_shiftr256_small :: Word256 -> SmallInt32 -> Bool+prop_shiftr256_small a (SmallInt32 k) = fromWord256 (shiftr256_small a (fromIntegral k)) == (shiftR (fromWord256 a) k)++--------------------------------------------------------------------------------++
+ Bitcoin/Test/Misc/QuickCheck.hs view
@@ -0,0 +1,50 @@+
+-- | Common quickcheck stuff
+
+{-# LANGUAGE CPP, BangPatterns #-}
+module Bitcoin.Test.Misc.QuickCheck where
+
+--------------------------------------------------------------------------------
+
+import Test.QuickCheck
+
+--------------------------------------------------------------------------------
+
+-- | An integer in the interval @[0,2^1024]@
+newtype BigInt = BigInt Integer deriving (Eq,Ord,Show)                                     
+
+instance Arbitrary BigInt where
+  arbitrary = do
+    n <- choose (0,(2^(1024::Int)))
+    return $ BigInt n
+
+--------------------------------------------------------------------------------
+
+newtype MediumInt  = MediumInt  Integer deriving (Eq,Ord,Show)
+
+-- | An integer in the interval @[0,2^256-1]@
+instance Arbitrary MediumInt where
+  arbitrary = do
+    n <- choose (0,(2^(256::Int)-1))
+    return $ MediumInt n
+
+--------------------------------------------------------------------------------
+
+-- | An integer in the interval @[0,32)@ (closed-open, so 32 is excluded)
+newtype SmallInt32 = SmallInt32 Int deriving (Eq,Ord,Show)
+
+instance Arbitrary SmallInt32 where
+  arbitrary = do
+    k <- choose (0,31)
+    return $ SmallInt32 k
+
+--------------------------------------------------------------------------------
+
+newtype SmallExpo = SmallExpo Int deriving (Eq,Show)
+
+instance Arbitrary SmallExpo where
+  arbitrary = do
+    n <- choose (0,350)
+    return $ SmallExpo n
+
+--------------------------------------------------------------------------------
+ Bitcoin/Test/Protocol/Hash.hs view
@@ -0,0 +1,145 @@++{-# LANGUAGE CPP #-}+module Bitcoin.Test.Protocol.Hash where++--------------------------------------------------------------------------------++import Data.Word+import qualified Data.ByteString as B++import Test.Tasty+import Test.Tasty.QuickCheck +import Test.QuickCheck ( Arbitrary(..) , choose , quickCheckWith , stdArgs , maxSuccess , Testable , Gen )++import Bitcoin.Misc.BigInt+import Bitcoin.Misc.HexString+import Bitcoin.Misc.OctetStream+import Bitcoin.Misc.Endian++import Bitcoin.Protocol.Hash++--------------------------------------------------------------------------------++testgroup_ProtocolHash :: TestTree+testgroup_ProtocolHash = testGroup "Hash160 / Hash256"+  [ testGroup "conversions"+      [ testProperty ""            prop_Hash160_toFromBytestring +      , testProperty ""            prop_Hash160_toFromWord8List +      , testProperty ""            prop_Hash160_showRead +      , testProperty ""            prop_Hash256_toFromBytestring+      , testProperty ""            prop_Hash256_toFromWord8List+      , testProperty ""            prop_Hash256_showRead +      ]+  , testGroup "byte order"+      [ testProperty ""            prop_Hash160_show_byte_order +      , testProperty ""            prop_Hash256_show_byte_order +      ]+  , testGroup "comparisons"+      [ testProperty ""            prop_Hash160_cmp_Word8List+      , testProperty ""            prop_Hash160_cmp_ByteString+      , testProperty ""            prop_Hash256_cmp_Word8List +      , testProperty ""            prop_Hash256_cmp_ByteString +      ]+  ]++--------------------------------------------------------------------------------+-- quickcheck++-- 1/4 of the time it gives back the given constant, otherwise random+genMaybeKst :: Arbitrary a => a -> Gen a+genMaybeKst x = do+  j <- choose (1::Int,4)+  if j==4+    then return x+    else arbitrary++instance Arbitrary Hash160 where+  arbitrary = do+    w1 <- genMaybeKst (0x1234567890abcdef :: Word64)+    w2 <- genMaybeKst (0xfedcba0987654321 :: Word64)+    w3 <- genMaybeKst (0x345678cd         :: Word32)+    return $ Hash160 w1 w2 w3++instance Arbitrary Hash256 where+  arbitrary = do+    w1 <- genMaybeKst (0x1234567890abcdef :: Word64)+    w2 <- genMaybeKst (0xfedcba0987654321 :: Word64)+    w3 <- genMaybeKst (0xabcdef1234567890 :: Word64)+    w4 <- genMaybeKst (0x654321fedcba0987 :: Word64)+    return $ Hash256 w1 w2 w3 w4++--------------------------------------------------------------------------------++{-+runAllTests_hash :: IO ()+runAllTests_hash = runAllTests_hash' 1000++runAllTests_hash' :: Int -> IO ()+runAllTests_hash' n = do+  let args = stdArgs { maxSuccess = n }+  let qc :: Testable prop => prop -> IO ()+      qc = quickCheckWith args+ +  putStrLn "running all tests in Bitcoin.Protocol.Hash"+  putStrLn "=========================================="+--  putStrLn "testing conversions..."+  qc prop_Hash160_toFromBytestring +  qc prop_Hash160_toFromWord8List +  qc prop_Hash160_showRead +  qc prop_Hash256_toFromBytestring+  qc prop_Hash256_toFromWord8List+  qc prop_Hash256_showRead +--  putStrLn "testing byte order..."+  qc prop_Hash160_show_byte_order +  qc prop_Hash256_show_byte_order +--  putStrLn "testing comparisons..."+  qc prop_Hash160_cmp_Word8List+  qc prop_Hash160_cmp_ByteString+  qc prop_Hash256_cmp_Word8List +  qc prop_Hash256_cmp_ByteString +-}++--------------------------------------------------------------------------------+-- conversion++prop_Hash160_toFromBytestring :: Hash160 -> Bool+prop_Hash160_toFromBytestring h  =  h == fromByteString (toByteString h)++prop_Hash160_toFromWord8List :: Hash160 -> Bool+prop_Hash160_toFromWord8List h  =  h == fromWord8List (toWord8List h)++prop_Hash160_showRead :: Hash160 -> Bool+prop_Hash160_showRead h  =  h == read (show h)++prop_Hash256_toFromBytestring :: Hash256 -> Bool+prop_Hash256_toFromBytestring h  =  h == fromByteString (toByteString h)++prop_Hash256_toFromWord8List :: Hash256 -> Bool+prop_Hash256_toFromWord8List h  =  h == fromWord8List (toWord8List h)++prop_Hash256_showRead :: Hash256 -> Bool+prop_Hash256_showRead h  =  h == read (show h)++-- byte order++prop_Hash160_show_byte_order :: Bool+prop_Hash160_show_byte_order = show (fromWord8List [1..20] :: Hash160) == "hash160FromTextBE \"14131211100f0e0d0c0b0a090807060504030201\""++prop_Hash256_show_byte_order :: Bool+prop_Hash256_show_byte_order = show (fromWord8List [1..32] :: Hash256) == "hash256FromTextBE \"201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201\""++-- ordering++prop_Hash160_cmp_Word8List :: Hash160 -> Hash160 -> Bool+prop_Hash160_cmp_Word8List h1 h2  =  compare h1 h2 == compare (reverse $ toWord8List h1) (reverse $ toWord8List h2)++prop_Hash160_cmp_ByteString :: Hash160 -> Hash160 -> Bool+prop_Hash160_cmp_ByteString h1 h2  =  compare h1 h2 == compare (B.reverse $ toByteString h1) (B.reverse $ toByteString h2)++prop_Hash256_cmp_Word8List :: Hash256 -> Hash256 -> Bool+prop_Hash256_cmp_Word8List h1 h2  =  compare h1 h2 == compare (reverse $ toWord8List h1) (reverse $ toWord8List h2)++prop_Hash256_cmp_ByteString :: Hash256 -> Hash256 -> Bool+prop_Hash256_cmp_ByteString h1 h2  =  compare h1 h2 == compare (B.reverse $ toByteString h1) (B.reverse $ toByteString h2)++--------------------------------------------------------------------------------
+ Bitcoin/Test/Script/Invalid.hs view
@@ -0,0 +1,334 @@++-- | copy-paste from @\"script_invalid.json\"@ (from the Satoshi client's source)++module Bitcoin.Test.Script.Invalid where++--------------------------------------------------------------------------------++-- NOTE: these fail currently (we do not recognize them as invalid)+-- hence not included the main test suite yet++invalid_json_notrecognized = [++  ["NOP",+  "'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'",+  ">520 byte push"],+  ["0",+  "IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1",+  ">520 byte push in non-executed IF branch"],+  ["1",+  "0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",+  ">201 opcodes executed. 0x61 is NOP"],+  ["0",+  "IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1",+  ">201 opcodes including non-executed IF branch. 0x61 is NOP"],+  ["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+  "1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+  ">1,000 stack size (0x6f is 3DUP)"],+  ["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+  "1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+  ">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",+  "10,001-byte scriptPubKey"],+++  ["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Tests for Script.IsPushOnly()"],+  ["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"],++  ["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "OP_RESERVED in P2SH should fail"],+  ["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "OP_VER in P2SH should fail"]++  ]++--------------------------------------------------------------------------------++invalid_json = [+  ["", ""],+  ["", "NOP"],+  ["NOP", ""],+  ["NOP","NOP"],++  ["0x4c01","0x01 NOP", "PUSHDATA1 with not enough bytes"],+  ["0x4d0200ff","0x01 NOP", "PUSHDATA2 with not enough bytes"],+  ["0x4e03000000ffff","0x01 NOP", "PUSHDATA4 with not enough bytes"],++  ["1", "IF 0x50 ENDIF 1", "0x50 is reserved"],+  ["0x52", "0x5f ADD 0x60 EQUAL", "0x51 through 0x60 push 1 through 16 onto stack"],+  ["0","NOP"],+  ["1", "IF VER ELSE 1 ENDIF", "VER non-functional"],+  ["0", "IF VERIF ELSE 1 ENDIF", "VERIF illegal everywhere"],+  ["0", "IF VERNOTIF ELSE 1 ENDIF", "VERNOT illegal everywhere"],++  ["1 IF", "1 ENDIF", "IF/ENDIF can't span scriptSig/scriptPubKey"],+  ["1 IF 0 ENDIF", "1 ENDIF"],+  ["1 ELSE 0 ENDIF", "1"],+  ["0 NOTIF", "123"],++  ["0", "DUP IF ENDIF"],+  ["0", "IF 1 ENDIF"],+  ["0", "DUP IF ELSE ENDIF"],+  ["0", "IF 1 ELSE ENDIF"],+  ["0", "NOTIF ELSE 1 ENDIF"],++  ["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF"],+  ["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF"],+  ["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],+  ["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],++  ["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"],+  ["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"],+  ["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],+  ["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],++  ["1", "RETURN"],+  ["1", "DUP IF RETURN ENDIF"],++  ["1", "RETURN 'data'", "canonical prunable txout format"],+  ["0 IF", "RETURN ENDIF 1", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"],++  ["0", "VERIFY 1"],+  ["1", "VERIFY"],+  ["1", "VERIFY 0"],++  ["1 TOALTSTACK", "FROMALTSTACK 1", "alt stack not shared between sig/pubkey"],++  ["IFDUP", "DEPTH 0 EQUAL"],+  ["DROP", "DEPTH 0 EQUAL"],+  ["DUP", "DEPTH 0 EQUAL"],+  ["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL"],+  ["NOP", "NIP"],+  ["NOP", "1 NIP"],+  ["NOP", "1 0 NIP"],+  ["NOP", "OVER 1"],+  ["1", "OVER"],+  ["0 1", "OVER DEPTH 3 EQUALVERIFY"],+  ["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL"],+  ["NOP", "0 PICK"],+  ["1", "-1 PICK"],+  ["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL"],+  ["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL"],+  ["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL"],+  ["NOP", "0 ROLL"],+  ["1", "-1 ROLL"],+  ["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL"],+  ["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL"],+  ["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL"],+  ["NOP", "ROT 1"],+  ["NOP", "1 ROT 1"],+  ["NOP", "1 2 ROT 1"],+  ["NOP", "0 1 2 ROT"],+  ["NOP", "SWAP 1"],+  ["1", "SWAP 1"],+  ["0 1", "SWAP 1 EQUALVERIFY"],+  ["NOP", "TUCK 1"],+  ["1", "TUCK 1"],+  ["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP"],+  ["NOP", "2DUP 1"],+  ["1", "2DUP 1"],+  ["NOP", "3DUP 1"],+  ["1", "3DUP 1"],+  ["1 2", "3DUP 1"],+  ["NOP", "2OVER 1"],+  ["1", "2 3 2OVER 1"],+  ["NOP", "2SWAP 1"],+  ["1", "2 3 2SWAP 1"],++  ["'a' 'b'", "CAT", "CAT disabled"],+  ["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "CAT disabled"],+  ["'abc' 1 1", "SUBSTR", "SUBSTR disabled"],+  ["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "SUBSTR disabled"],+  ["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "LEFT disabled"],+  ["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "RIGHT disabled"],++  ["NOP", "SIZE 1"],++  ["'abc'", "IF INVERT ELSE 1 ENDIF", "INVERT disabled"],+  ["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "AND disabled"],+  ["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "OR disabled"],+  ["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "XOR disabled"],+  ["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "2MUL disabled"],+  ["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "2DIV disabled"],+  ["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "MUL disabled"],+  ["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "DIV disabled"],+  ["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "MOD disabled"],+  ["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "LSHIFT disabled"],+  ["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "RSHIFT disabled"],++  ["0 1","EQUAL"],+  ["1 1 ADD", "0 EQUAL"],+  ["11 1 ADD 12 SUB", "11 EQUAL"],++  ["2147483648 0 ADD", "NOP", "arithmetic operands must be in range [-2^31...2^31] "],+  ["-2147483648 0 ADD", "NOP", "arithmetic operands must be in range [-2^31...2^31] "],+  ["2147483647 DUP ADD", "4294967294 NUMEQUAL", "NUMEQUAL must be in numeric range"],+  ["'abcdef' NOT", "0 EQUAL", "NOT is an arithmetic operand"],++  ["2 DUP MUL", "4 EQUAL", "disabled"],+  ["2 DUP DIV", "1 EQUAL", "disabled"],+  ["2 2MUL", "4 EQUAL", "disabled"],+  ["2 2DIV", "1 EQUAL", "disabled"],+  ["7 3 MOD", "1 EQUAL", "disabled"],+  ["2 2 LSHIFT", "8 EQUAL", "disabled"],+  ["2 1 RSHIFT", "1 EQUAL", "disabled"],++  ["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL"],+  ["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL"],++  ["0x50","1", "opcode 0x50 is reserved"],+  ["1", "IF 0xba ELSE 1 ENDIF", "opcodes above NOP10 invalid if executed"],+  ["1", "IF 0xbb ELSE 1 ENDIF"],+  ["1", "IF 0xbc ELSE 1 ENDIF"],+  ["1", "IF 0xbd ELSE 1 ENDIF"],+  ["1", "IF 0xbe ELSE 1 ENDIF"],+  ["1", "IF 0xbf ELSE 1 ENDIF"],+  ["1", "IF 0xc0 ELSE 1 ENDIF"],+  ["1", "IF 0xc1 ELSE 1 ENDIF"],+  ["1", "IF 0xc2 ELSE 1 ENDIF"],+  ["1", "IF 0xc3 ELSE 1 ENDIF"],+  ["1", "IF 0xc4 ELSE 1 ENDIF"],+  ["1", "IF 0xc5 ELSE 1 ENDIF"],+  ["1", "IF 0xc6 ELSE 1 ENDIF"],+  ["1", "IF 0xc7 ELSE 1 ENDIF"],+  ["1", "IF 0xc8 ELSE 1 ENDIF"],+  ["1", "IF 0xc9 ELSE 1 ENDIF"],+  ["1", "IF 0xca ELSE 1 ENDIF"],+  ["1", "IF 0xcb ELSE 1 ENDIF"],+  ["1", "IF 0xcc ELSE 1 ENDIF"],+  ["1", "IF 0xcd ELSE 1 ENDIF"],+  ["1", "IF 0xce ELSE 1 ENDIF"],+  ["1", "IF 0xcf ELSE 1 ENDIF"],+  ["1", "IF 0xd0 ELSE 1 ENDIF"],+  ["1", "IF 0xd1 ELSE 1 ENDIF"],+  ["1", "IF 0xd2 ELSE 1 ENDIF"],+  ["1", "IF 0xd3 ELSE 1 ENDIF"],+  ["1", "IF 0xd4 ELSE 1 ENDIF"],+  ["1", "IF 0xd5 ELSE 1 ENDIF"],+  ["1", "IF 0xd6 ELSE 1 ENDIF"],+  ["1", "IF 0xd7 ELSE 1 ENDIF"],+  ["1", "IF 0xd8 ELSE 1 ENDIF"],+  ["1", "IF 0xd9 ELSE 1 ENDIF"],+  ["1", "IF 0xda ELSE 1 ENDIF"],+  ["1", "IF 0xdb ELSE 1 ENDIF"],+  ["1", "IF 0xdc ELSE 1 ENDIF"],+  ["1", "IF 0xdd ELSE 1 ENDIF"],+  ["1", "IF 0xde ELSE 1 ENDIF"],+  ["1", "IF 0xdf ELSE 1 ENDIF"],+  ["1", "IF 0xe0 ELSE 1 ENDIF"],+  ["1", "IF 0xe1 ELSE 1 ENDIF"],+  ["1", "IF 0xe2 ELSE 1 ENDIF"],+  ["1", "IF 0xe3 ELSE 1 ENDIF"],+  ["1", "IF 0xe4 ELSE 1 ENDIF"],+  ["1", "IF 0xe5 ELSE 1 ENDIF"],+  ["1", "IF 0xe6 ELSE 1 ENDIF"],+  ["1", "IF 0xe7 ELSE 1 ENDIF"],+  ["1", "IF 0xe8 ELSE 1 ENDIF"],+  ["1", "IF 0xe9 ELSE 1 ENDIF"],+  ["1", "IF 0xea ELSE 1 ENDIF"],+  ["1", "IF 0xeb ELSE 1 ENDIF"],+  ["1", "IF 0xec ELSE 1 ENDIF"],+  ["1", "IF 0xed ELSE 1 ENDIF"],+  ["1", "IF 0xee ELSE 1 ENDIF"],+  ["1", "IF 0xef ELSE 1 ENDIF"],+  ["1", "IF 0xf0 ELSE 1 ENDIF"],+  ["1", "IF 0xf1 ELSE 1 ENDIF"],+  ["1", "IF 0xf2 ELSE 1 ENDIF"],+  ["1", "IF 0xf3 ELSE 1 ENDIF"],+  ["1", "IF 0xf4 ELSE 1 ENDIF"],+  ["1", "IF 0xf5 ELSE 1 ENDIF"],+  ["1", "IF 0xf6 ELSE 1 ENDIF"],+  ["1", "IF 0xf7 ELSE 1 ENDIF"],+  ["1", "IF 0xf8 ELSE 1 ENDIF"],+  ["1", "IF 0xf9 ELSE 1 ENDIF"],+  ["1", "IF 0xfa ELSE 1 ENDIF"],+  ["1", "IF 0xfb ELSE 1 ENDIF"],+  ["1", "IF 0xfc ELSE 1 ENDIF"],+  ["1", "IF 0xfd ELSE 1 ENDIF"],+  ["1", "IF 0xfe ELSE 1 ENDIF"],+  ["1", "IF 0xff ELSE 1 ENDIF"],++  ["1 IF 1 ELSE", "0xff ENDIF", "invalid because scriptSig and scriptPubKey are processed separately"],++  ["NOP", "RIPEMD160"],+  ["NOP", "SHA1"],+  ["NOP", "SHA256"],+  ["NOP", "HASH160"],+  ["NOP", "HASH256"],++  ["NOP1","NOP10"],++  ["1","VER", "OP_VER is reserved"],+  ["1","VERIF", "OP_VERIF is reserved"],+  ["1","VERNOTIF", "OP_VERNOTIF is reserved"],+  ["1","RESERVED1", "OP_RESERVED1 is reserved"],+  ["1","RESERVED2", "OP_RESERVED2 is reserved"],+  ["1","0xba", "0xba == OP_NOP10 + 1"],++  ["2147483648", "1ADD 1", "We cannot do math on 5-byte integers"],+  ["-2147483648", "1ADD 1", "Because we use a sign bit, -2147483648 is also 5 bytes"],++  ["1", "1 ENDIF", "ENDIF without IF"],+  ["1", "IF 1", "IF without ENDIF"],+  ["1 IF 1", "ENDIF", "IFs don't carry over"],++  ["NOP", "IF 1 ENDIF", "The following tests check the if(stack.size() < N) tests in each opcode"],+  ["NOP", "NOTIF 1 ENDIF", "They are here to catch copy-and-paste errors"],+  ["NOP", "VERIFY 1", "Most of them are duplicated elsewhere,"],++  ["NOP", "TOALTSTACK 1", "but, hey, more is always better, right?"],+  ["1", "FROMALTSTACK"],+  ["1", "2DROP 1"],+  ["1", "2DUP"],+  ["1 1", "3DUP"],+  ["1 1 1", "2OVER"],+  ["1 1 1 1 1", "2ROT"],+  ["1 1 1", "2SWAP"],+  ["NOP", "IFDUP 1"],+  ["NOP", "DROP 1"],+  ["NOP", "DUP 1"],+  ["1", "NIP"],+  ["1", "OVER"],+  ["1 1 1 3", "PICK"],+  ["0", "PICK 1"],+  ["1 1 1 3", "ROLL"],+  ["0", "ROLL 1"],+  ["1 1", "ROT"],+  ["1", "SWAP"],+  ["1", "TUCK"],++  ["NOP", "SIZE 1"],++  ["1", "EQUAL 1"],+  ["1", "EQUALVERIFY 1"],++  ["NOP", "1ADD 1"],+  ["NOP", "1SUB 1"],+  ["NOP", "NEGATE 1"],+  ["NOP", "ABS 1"],+  ["NOP", "NOT 1"],+  ["NOP", "0NOTEQUAL 1"],++  ["1", "ADD"],+  ["1", "SUB"],+  ["1", "BOOLAND"],+  ["1", "BOOLOR"],+  ["1", "NUMEQUAL"],+  ["1", "NUMEQUALVERIFY 1"],+  ["1", "NUMNOTEQUAL"],+  ["1", "LESSTHAN"],+  ["1", "GREATERTHAN"],+  ["1", "LESSTHANOREQUAL"],+  ["1", "GREATERTHANOREQUAL"],+  ["1", "MIN"],+  ["1", "MAX"],+  ["1 1", "WITHIN"],++  ["NOP", "RIPEMD160 1"],+  ["NOP", "SHA1 1"],+  ["NOP", "SHA256 1"],+  ["NOP", "HASH160 1"],+  ["NOP", "HASH256 1"]++  ]++
+ Bitcoin/Test/Script/Parser.hs view
@@ -0,0 +1,224 @@++-- | Parse the script test cases from the Satoshi client (\"script_valid.json\" and \"script_invalid.json\")+--+-- Note that these do not test CHECKSIG / CHECKMULTISIG!+--+-- Fortunately the JSON readily parses as a Haskell type @[[String]]@ (inner lists are scriptSig, scriptPubKey+-- and an optional comment)+--++{-# LANGUAGE PatternGuards #-}+module Bitcoin.Test.Script.Parser where++--------------------------------------------------------------------------------++import Data.Word+import Data.Char ( isDigit )+import qualified Data.ByteString as B++import Bitcoin.Script.Base+import Bitcoin.Script.Run+import Bitcoin.Script.Serialize++import Bitcoin.Misc.HexString+import Bitcoin.Misc.OctetStream++--------------------------------------------------------------------------------++data TestCase = TestCase +  { _testScriptSig    :: Either [Word8] Script+  , _testScriptPubKey :: Either [Word8] Script+  , _testComment      :: Maybe String+  }+  deriving Show++--------------------------------------------------------------------------------++eiToRawScript :: Either [Word8] Script -> RawScript+eiToRawScript (Left ws) = fromWord8List ws+eiToRawScript (Right s) = serializeScript s++--------------------------------------------------------------------------------++parseInner :: [String] -> TestCase+parseInner ls = case ls of+  [a,b  ] -> TestCase (parseWords a) (parseWords b) Nothing+  [a,b,c] -> TestCase (parseWords a) (parseWords b) (Just c)+  _ -> error "Bitcoin.Test.Script.Parser.parseInner"++catEither :: [Either [a] [b]] -> [Either [a] [b]]+catEither = go where+  go []  = []+  go (Left  xs : Left  ys : rest) = go (Left  (xs++ys) : rest)+  go (Right xs : Right ys : rest) = go (Right (xs++ys) : rest)+  go (ei : rest) = ei : go rest++parseWords :: String -> Either [Word8] Script+parseWords input = +  case catEither eis of+    [Right ops] -> Right $ Script ops+    _           -> let ws = concatMap toW8 eis+                   in  case parseScript $ fromWord8List ws of+                         Just script -> Right script       -- it can happen that individually they don't parse, but together they parse +                         Nothing     -> Left  ws           -- (because of smallnums, for example)+  where++  toW8 :: Either [Word8] [Opcode] -> [Word8]+  toW8 (Left ws) = ws+  toW8 (Right ops) = toWord8List $ serializeScript $ Script ops+  +  eis = normalWorker $ words input++  normalWorker :: [String] -> [Either [Word8] [Opcode]]+  normalWorker [] = []+  normalWorker (w:rest) +    | sop /= OP_UNKNOWN 0     =  Right [sop] : normalWorker rest                               +    | isHex w                 =  handleStupidHexStuff (w:rest)  +    | otherwise               =  error $ "Bitcoin.Test.Script.Parser.parseWord: " ++ w+    where+      sop = singleOpcode w ++  isHex :: String -> Bool+  isHex w = take 2 w == "0x"++  -- 'gavin_was_here' - yeah, i can see that...    +  handleStupidHexStuff :: [String] -> [Either [Word8] [Opcode]]+  handleStupidHexStuff ws = this : normalWorker nonhex where+    (hex,nonhex) = span isHex ws+    bs = fromHexString $ HexString $ concat $ map (drop 2) hex+    this = case parseScript (RawScript bs) of+      Nothing               -> Left (toWord8List bs) -- error "parseWords: cannot parse stupid hex stuff"+      Just (Script opcodes) -> Right opcodes+      +  -- | if not a single opcode, we return OP_UNKNOWN 0, which should be otherwise never returned+  -- hack, but i don't care, especially after seeing what is present in the bitcoin codebase...+  singleOpcode :: String -> Opcode    +  singleOpcode w = case w of+    "0" -> OP_SMALLNUM 0+    "1" -> OP_SMALLNUM 1+    "2" -> OP_SMALLNUM 2+    "3" -> OP_SMALLNUM 3+    "4" -> OP_SMALLNUM 4+    "5" -> OP_SMALLNUM 5+    "6" -> OP_SMALLNUM 6+    "7" -> OP_SMALLNUM 7+    "8" -> OP_SMALLNUM 8+    "9" -> OP_SMALLNUM 9+    "10" -> OP_SMALLNUM 10+    "11" -> OP_SMALLNUM 11+    "12" -> OP_SMALLNUM 12+    "13" -> OP_SMALLNUM 13+    "14" -> OP_SMALLNUM 14+    "15" -> OP_SMALLNUM 15+    "16" -> OP_SMALLNUM 16++    "NOP"  -> OP_NOP 97+    "NOP1" -> OP_NOP 176+    "NOP2" -> OP_NOP 177+    "NOP3" -> OP_NOP 178+    "NOP4" -> OP_NOP 179+    "NOP5" -> OP_NOP 180+    "NOP6" -> OP_NOP 181+    "NOP7" -> OP_NOP 182+    "NOP8" -> OP_NOP 183+    "NOP9" -> OP_NOP 184+    "NOP10"-> OP_NOP 185++    "IF"     -> OP_IF+    "NOTIF"  -> OP_NOTIF+    "ELSE"   -> OP_ELSE+    "ENDIF"  -> OP_ENDIF+    "VERIFY" -> OP_VERIFY+    "RETURN" -> OP_RETURN++    "TOALTSTACK"   -> OP_TOALTSTACK          -- Puts the input onto the top of the alt stack. Removes it from the main stack. +    "FROMALTSTACK" -> OP_FROMALTSTACK        -- Puts the input onto the top of the main stack. Removes it from the alt stack. +    "IFDUP" -> OP_IFDUP               -- If the top stack value is not 0, duplicate it. +    "DEPTH" -> OP_DEPTH               -- Puts the number of stack items onto the stack. +    "DROP"  -> OP_DROP                -- Removes the top stack item. +    "DUP"   -> OP_DUP                 -- Duplicates the top stack item. +    "NIP"   -> OP_NIP                 -- Removes the second-to-top stack item. +    "OVER"  -> OP_OVER                -- Copies the second-to-top stack item to the top. +    "PICK"  -> OP_PICK                -- The item n back in the stack is copied to the top. +    "ROLL"  -> OP_ROLL                -- The item n back in the stack is moved to the top. +    "ROT"   -> OP_ROT                 -- The top three items on the stack are rotated to the left. +    "SWAP"  -> OP_SWAP                -- The top two items on the stack are swapped. +    "TUCK"  -> OP_TUCK                -- The item at the top of the stack is copied and inserted before the second-to-top item. +    "2DROP" -> OP_2DROP               -- Removes the top two stack items. +    "2DUP"  -> OP_2DUP                -- Duplicates the top two stack items. +    "3DUP"  -> OP_3DUP                -- Duplicates the top three stack items. +    "2OVER" -> OP_2OVER               -- Copies the pair of items two spaces back in the stack to the front. +    "2ROT"  -> OP_2ROT                -- The fifth and sixth items back are moved to the top of the stack. +    "2SWAP" -> OP_2SWAP               -- Swaps the top two pairs of items.++    -- splice+    "CAT"    -> OP_CAT        -- Concatenates two strings. Currently disabled. +    "SUBSTR" -> OP_SUBSTR     -- Returns a section of a string. Currently disabled. +    "LEFT"   -> OP_LEFT       -- Keeps only characters left of the specified point in a string. Currently disabled. +    "RIGHT"  -> OP_RIGHT      -- Keeps only characters right of the specified point in a string. Currently disabled. +    "SIZE"   -> OP_SIZE       -- Returns the length of the input string. ++    -- bitwise logic+    "INVERT" -> OP_INVERT         -- Flips all of the bits in the input. Currently disabled. +    "AND"    -> OP_AND            -- Boolean and between each bit in the inputs. Currently disabled. +    "OR"     -> OP_OR             -- Boolean or between each bit in the inputs. Currently disabled. +    "XOR"    -> OP_XOR            -- Boolean exclusive or between each bit in the inputs. Currently disabled. +    "EQUAL"  -> OP_EQUAL          -- Returns 1 if the inputs are exactly equal, 0 otherwise. +    "EQUALVERIFY" -> OP_EQUALVERIFY    -- Same as OP_EQUAL, but runs OP_VERIFY afterward.++    -- arithmetic+    "1ADD"   -> OP_1ADD          -- 1 is added to the input. +    "1SUB"   -> OP_1SUB          -- 1 is subtracted from the input. +    "2MUL"   -> OP_2MUL          -- The input is multiplied by 2. Currently disabled. +    "2DIV"   -> OP_2DIV          -- The input is divided by 2. Currently disabled. +    "NEGATE" -> OP_NEGATE        -- The sign of the input is flipped. +    "ABS"    -> OP_ABS           -- The input is made positive. +    "NOT"    -> OP_NOT           -- If the input is 0 or 1, it is flipped. Otherwise the output will be 0. +    "0NOTEQUAL" -> OP_0NOTEQUAL     -- Returns 0 if the input is 0. 1 otherwise. +    "ADD"    -> OP_ADD           -- a is added to b. +    "SUB"    -> OP_SUB           -- b is subtracted from a. +    "MUL"    -> OP_MUL           -- a is multiplied by b. Currently disabled. +    "DIV"    -> OP_DIV           -- a is divided by b. Currently disabled. +    "MOD"    -> OP_MOD           -- Returns the remainder after dividing a by b. Currently disabled. +    "LSHIFT" -> OP_LSHIFT            -- Shifts a left b bits, preserving sign. Currently disabled. +    "RSHIFT" -> OP_RSHIFT             -- Shifts a right b bits, preserving sign. Currently disabled. +    "BOOLAND"  -> OP_BOOLAND            -- If both a and b are not 0, the output is 1. Otherwise 0. +    "BOOLOR"   -> OP_BOOLOR             -- If a or b is not 0, the output is 1. Otherwise 0. +    "NUMEQUAL" -> OP_NUMEQUAL           -- Returns 1 if the numbers are equal, 0 otherwise. +    "NUMEQUALVERIFY" -> OP_NUMEQUALVERIFY     -- Same as OP_NUMEQUAL, but runs OP_VERIFY afterward. +    "NUMNOTEQUAL"    -> OP_NUMNOTEQUAL        -- Returns 1 if the numbers are not equal, 0 otherwise. +    "LESSTHAN"       -> OP_LESSTHAN           -- Returns 1 if a is less than b, 0 otherwise. +    "GREATERTHAN"    -> OP_GREATERTHAN        -- Returns 1 if a is greater than b, 0 otherwise. +    "LESSTHANOREQUAL"-> OP_LESSTHANOREQUAL    -- Returns 1 if a is less than or equal to b, 0 otherwise. +    "GREATERTHANOREQUAL" -> OP_GREATERTHANOREQUAL -- Returns 1 if a is greater than or equal to b, 0 otherwise. +    "MIN"    -> OP_MIN                -- Returns the smaller of a and b. +    "MAX"    -> OP_MAX                -- Returns the larger of a and b. +    "WITHIN" -> OP_WITHIN             -- Returns 1 if x is within the specified range (left-inclusive), 0 otherwise++    -- crypto+    "RIPEMD160" -> OP_RIPEMD160           -- The input is hashed using RIPEMD-160. +    "SHA1" -> OP_SHA1                -- The input is hashed using SHA-1. +    "SHA256" -> OP_SHA256              -- The input is hashed using SHA-256. +    "HASH160" -> OP_HASH160             -- The input is hashed twice: first with SHA-256 and then with RIPEMD-160. +    "HASH256" -> OP_HASH256             -- The input is hashed two times with SHA-256. +    "CODESEPARATOR" -> OP_CODESEPARATOR       -- All of the signature checking words will only match signatures to the data after the most recently-executed OP_CODESEPARATOR. +    "CHECKSIG" -> OP_CHECKSIG            -- The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise. +    "CHECKSIGVERIFY" -> OP_CHECKSIGVERIFY      -- Same as OP_CHECKSIG, but OP_VERIFY is executed afterward. +    "CHECKMULTISIG" -> OP_CHECKMULTISIG       -- For each signature and public key pair, OP_CHECKSIG is executed. If more public keys than signatures are listed, some key/sig pairs can fail. All signatures need to match a public key. If all signatures are valid, 1 is returned, 0 otherwise. Due to a bug, one extra unused value is removed from the stack. +    "CHECKMULTISIGVERIFY" -> OP_CHECKMULTISIGVERIFY -- Same as OP_CHECKMULTISIG, but OP_VERIFY is executed afterward.++    -- reserved words+    "RESERVED"  -> OP_RESERVED           -- Transaction is invalid unless occuring in an unexecuted OP_IF branch+    "VER"       -> OP_VER                -- Transaction is invalid unless occuring in an unexecuted OP_IF branch+    "VERIF"     -> OP_VERIF              -- Transaction is invalid even when occuring in an unexecuted OP_IF branch+    "VERNOTIF"  -> OP_VERNOTIF           -- Transaction is invalid even when occuring in an unexecuted OP_IF branch+    "RESERVED1" -> OP_RESERVED1          -- Transaction is invalid unless occuring in an unexecuted OP_IF branch+    "RESERVED2" -> OP_RESERVED2          -- Transaction is invalid unless occuring in an unexecuted OP_IF branch++    _ | head w == '\'' && last w == '\''      -> op_PUSHDATA (B.pack $ map char_to_word8 $ init $ tail w)   +    _ | all isDigit w                         -> op_BIGNUMBER (read w)+    _ | head w == '-' && all isDigit (tail w) -> op_BIGNUMBER (read w)    ++    _ -> OP_UNKNOWN 0++--------------------------------------------------------------------------------
+ Bitcoin/Test/Script/RunTests.hs view
@@ -0,0 +1,101 @@++-- | Running the script test+module Bitcoin.Test.Script.RunTests where++--------------------------------------------------------------------------------++import Test.Tasty+import Test.Tasty.HUnit++import Data.Word+import Data.Char ( isDigit )+import qualified Data.ByteString as B++import Bitcoin.Script.Base+import Bitcoin.Script.Run+import Bitcoin.Script.Serialize++import Bitcoin.Misc.HexString+import Bitcoin.Misc.OctetStream++import Bitcoin.Protocol.Hash+import Bitcoin.BlockChain.Base++import Bitcoin.Test.Script.Valid+import Bitcoin.Test.Script.Invalid+import Bitcoin.Test.Script.Parser++--------------------------------------------------------------------------------++testgroup_Script :: TestTree+testgroup_Script = testGroup "Script" +  [ testgroup_Valid+  , testgroup_Invalid+  ]++testgroup_Valid :: TestTree+testgroup_Valid = testGroup "valid scripts" +  [ testCase ("valid script #" ++ show i) (assertOK $ runTestCase scr) +  | (i,scr) <- zip [1..] valid_testcases+  ]++testgroup_Invalid :: TestTree+testgroup_Invalid = testGroup "invalid scripts"+  [ testCase ("invalid script #" ++ show i) (assertNotOK $ runTestCase scr) +  | (i,scr) <- zip [1..] invalid_testcases+  ]++assertOK :: (Bool,String) -> Assertion+assertOK (b,msg) = case b of+  False -> assertFailure msg+  True  -> return ()++assertNotOK :: (Bool,String) -> Assertion+assertNotOK (b,msg) = assertOK (not b, msg)++--------------------------------------------------------------------------------++-- | test cases which should pass+valid_testcases :: [TestCase]+valid_testcases   = map parseInner valid_json   ++-- | test cases which should not pass+invalid_testcases :: [TestCase]+invalid_testcases = map parseInner invalid_json ++--------------------------------------------------------------------------------++-- | True if passed, False if failed, +-- and possibly an explanation if failed (including the testcase comment if exists)+runTestCase :: TestCase -> (Bool, String)+runTestCase (TestCase eiSig eiPk mbcomment) = result where++  sig = eiToRawScript eiSig :: RawScript+  pk  = eiToRawScript eiPk  :: RawScript++  prevTx = Tx 0 [] [TxOutput 666 pk] LockImmed zeroHash256        :: Tx RawScript RawScript+  inExt  = TxInput zeroHash256 0 (prevTx,sig) 0                   :: TxInput (Tx RawScript RawScript, RawScript)+  fakeTx = Tx 0 [inExt] [TxOutput 666 sig] LockImmed zeroHash256  :: Tx (Tx RawScript RawScript, RawScript) RawScript++  result = case checkTransaction fakeTx of+    Left err -> (False , err ++ " | " ++ maybe "" id mbcomment)+    Right b  -> (b     ,        " | " ++ maybe "" id mbcomment) ++--------------------------------------------------------------------------------++{-+runValid   = mapM_ print $ map runTestCase valid_testcases+runInvalid = mapM_ print $ map runTestCase invalid_testcases++--------------------------------------------------------------------------------++-- | for testing the hacked-together parser for Gavin's custom test format...+-- and also manually checking the cases+runAndSaveTestCases = do+  writeFile "_valid.txt"       $ unlines $ map show valid_testcases+  writeFile "_invalid.txt"     $ unlines $ map show invalid_testcases+  writeFile "_valid_run.txt"   $ unlines $ map show $ map runTestCase valid_testcases+  writeFile "_invalid_run.txt" $ unlines $ map show $ map runTestCase invalid_testcases+-}++--------------------------------------------------------------------------------
+ Bitcoin/Test/Script/Valid.hs view
@@ -0,0 +1,386 @@++-- | copy-paste from @\"script_valid.json\"@ (from the Satoshi client's source)++module Bitcoin.Test.Script.Valid where++--------------------------------------------------------------------------------++valid_json = [+  ["0x01 0x0b", "11 EQUAL", "push 1 byte"],+  ["0x02 0x417a", "'Az' EQUAL"],+  ["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a",+   "'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "push 75 bytes"],++  ["0x4c 0x01 0x07","7 EQUAL", "0x4c is OP_PUSHDATA1"],+  ["0x4d 0x0100 0x08","8 EQUAL", "0x4d is OP_PUSHDATA2"],+  ["0x4e 0x01000000 0x09","9 EQUAL", "0x4e is OP_PUSHDATA4"],++  ["0x4c 0x00","0 EQUAL"],+  ["0x4d 0x0000","0 EQUAL"],+  ["0x4e 0x00000000","0 EQUAL"],+  ["0x4f 1000 ADD","999 EQUAL"],+  ["0", "IF 0x50 ENDIF 1", "0x50 is reserved (ok if not executed)"],+  ["0x51", "0x5f ADD 0x60 EQUAL", "0x51 through 0x60 push 1 through 16 onto stack"],+  ["1","NOP"],+  ["0", "IF VER ELSE 1 ENDIF", "VER non-functional (ok if not executed)"],+  ["0", "IF RESERVED1 RESERVED2 ELSE 1 ENDIF", "RESERVED ok in un-executed IF"],++  ["1", "DUP IF ENDIF"],+  ["1", "IF 1 ENDIF"],+  ["1", "DUP IF ELSE ENDIF"],+  ["1", "IF 1 ELSE ENDIF"],+  ["0", "IF ELSE 1 ENDIF"],++  ["1 1", "IF IF 1 ELSE 0 ENDIF ENDIF"],+  ["1 0", "IF IF 1 ELSE 0 ENDIF ENDIF"],+  ["1 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],+  ["0 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],++  ["1 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"],+  ["1 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"],+  ["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],+  ["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"],++  ["0", "IF RETURN ENDIF 1", "RETURN only works if executed"],++  ["1 1", "VERIFY"],++  ["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL"],+  ["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL"],++  ["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL"],+  ["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL"],+  ["0 DROP", "DEPTH 0 EQUAL"],+  ["0", "DUP 1 ADD 1 EQUALVERIFY 0 EQUAL"],+  ["0 1", "NIP"],+  ["1 0", "OVER DEPTH 3 EQUALVERIFY"],+  ["22 21 20", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL"],+  ["22 21 20", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL"],+  ["22 21 20", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL"],+  ["22 21 20", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL"],+  ["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL"],+  ["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL"],+  ["22 21 20", "ROT 22 EQUAL"],+  ["22 21 20", "ROT DROP 20 EQUAL"],+  ["22 21 20", "ROT DROP DROP 21 EQUAL"],+  ["22 21 20", "ROT ROT 21 EQUAL"],+  ["22 21 20", "ROT ROT ROT 20 EQUAL"],+  ["25 24 23 22 21 20", "2ROT 24 EQUAL"],+  ["25 24 23 22 21 20", "2ROT DROP 25 EQUAL"],+  ["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL"],+  ["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL"],+  ["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL"],+  ["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL"],+  ["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL"],+  ["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL"],+  ["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL"],+  ["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP"],+  ["13 14", "2DUP ROT EQUALVERIFY EQUAL"],+  ["-1 0 1 2", "3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY"],+  ["1 2 3 5", "2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL"],+  ["1 3 5 7", "2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL"],+  ["0", "SIZE 0 EQUAL"],+  ["1", "SIZE 1 EQUAL"],+  ["127", "SIZE 1 EQUAL"],+  ["128", "SIZE 2 EQUAL"],+  ["32767", "SIZE 2 EQUAL"],+  ["32768", "SIZE 3 EQUAL"],+  ["8388607", "SIZE 3 EQUAL"],+  ["8388608", "SIZE 4 EQUAL"],+  ["2147483647", "SIZE 4 EQUAL"],+  ["2147483648", "SIZE 5 EQUAL"],+  ["-1", "SIZE 1 EQUAL"],+  ["-127", "SIZE 1 EQUAL"],+  ["-128", "SIZE 2 EQUAL"],+  ["-32767", "SIZE 2 EQUAL"],+  ["-32768", "SIZE 3 EQUAL"],+  ["-8388607", "SIZE 3 EQUAL"],+  ["-8388608", "SIZE 4 EQUAL"],+  ["-2147483647", "SIZE 4 EQUAL"],+  ["-2147483648", "SIZE 5 EQUAL"],+  ["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL"],+++  ["2 -2 ADD", "0 EQUAL"],+  ["2147483647 -2147483647 ADD", "0 EQUAL"],+  ["-1 -1 ADD", "-2 EQUAL"],++  ["0 0","EQUAL"],+  ["1 1 ADD", "2 EQUAL"],+  ["1 1ADD", "2 EQUAL"],+  ["111 1SUB", "110 EQUAL"],+  ["111 1 ADD 12 SUB", "100 EQUAL"],+  ["0 ABS", "0 EQUAL"],+  ["16 ABS", "16 EQUAL"],+  ["-16 ABS", "-16 NEGATE EQUAL"],+  ["0 NOT", "NOP"],+  ["1 NOT", "0 EQUAL"],+  ["11 NOT", "0 EQUAL"],+  ["0 0NOTEQUAL", "0 EQUAL"],+  ["1 0NOTEQUAL", "1 EQUAL"],+  ["111 0NOTEQUAL", "1 EQUAL"],+  ["-111 0NOTEQUAL", "1 EQUAL"],+  ["1 1 BOOLAND", "NOP"],+  ["1 0 BOOLAND", "NOT"],+  ["0 1 BOOLAND", "NOT"],+  ["0 0 BOOLAND", "NOT"],+  ["16 17 BOOLAND", "NOP"],+  ["1 1 BOOLOR", "NOP"],+  ["1 0 BOOLOR", "NOP"],+  ["0 1 BOOLOR", "NOP"],+  ["0 0 BOOLOR", "NOT"],+  ["16 17 BOOLOR", "NOP"],+  ["11 10 1 ADD", "NUMEQUAL"],+  ["11 10 1 ADD", "NUMEQUALVERIFY 1"],+  ["11 10 1 ADD", "NUMNOTEQUAL NOT"],+  ["111 10 1 ADD", "NUMNOTEQUAL"],+  ["11 10", "LESSTHAN NOT"],+  ["4 4", "LESSTHAN NOT"],+  ["10 11", "LESSTHAN"],+  ["-11 11", "LESSTHAN"],+  ["-11 -10", "LESSTHAN"],+  ["11 10", "GREATERTHAN"],+  ["4 4", "GREATERTHAN NOT"],+  ["10 11", "GREATERTHAN NOT"],+  ["-11 11", "GREATERTHAN NOT"],+  ["-11 -10", "GREATERTHAN NOT"],+  ["11 10", "LESSTHANOREQUAL NOT"],+  ["4 4", "LESSTHANOREQUAL"],+  ["10 11", "LESSTHANOREQUAL"],+  ["-11 11", "LESSTHANOREQUAL"],+  ["-11 -10", "LESSTHANOREQUAL"],+  ["11 10", "GREATERTHANOREQUAL"],+  ["4 4", "GREATERTHANOREQUAL"],+  ["10 11", "GREATERTHANOREQUAL NOT"],+  ["-11 11", "GREATERTHANOREQUAL NOT"],+  ["-11 -10", "GREATERTHANOREQUAL NOT"],+  ["1 0 MIN", "0 NUMEQUAL"],+  ["0 1 MIN", "0 NUMEQUAL"],+  ["-1 0 MIN", "-1 NUMEQUAL"],+  ["0 -2147483647 MIN", "-2147483647 NUMEQUAL"],+  ["2147483647 0 MAX", "2147483647 NUMEQUAL"],+  ["0 100 MAX", "100 NUMEQUAL"],+  ["-100 0 MAX", "0 NUMEQUAL"],+  ["0 -2147483647 MAX", "0 NUMEQUAL"],+  ["0 0 1", "WITHIN"],+  ["1 0 1", "WITHIN NOT"],+  ["0 -2147483647 2147483647", "WITHIN"],+  ["-1 -100 100", "WITHIN"],+  ["11 -100 100", "WITHIN"],+  ["-2147483647 -100 100", "WITHIN NOT"],+  ["2147483647 -100 100", "WITHIN NOT"],++  ["2147483647 2147483647 SUB", "0 EQUAL"],+  ["2147483647 DUP ADD", "4294967294 EQUAL", ">32 bit EQUAL is valid"],+  ["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL"],++  ["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL"],+  ["'a'", "RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL"],+  ["'abcdefghijklmnopqrstuvwxyz'", "RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL"],+  ["''", "SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL"],+  ["'a'", "SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL"],+  ["'abcdefghijklmnopqrstuvwxyz'", "SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL"],+  ["''", "SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL"],+  ["'a'", "SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL"],+  ["'abcdefghijklmnopqrstuvwxyz'", "SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL"],+  ["''", "DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL"],+  ["''", "DUP HASH256 SWAP SHA256 SHA256 EQUAL"],+  ["''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL"],+  ["'a'", "HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL"],+  ["'abcdefghijklmnopqrstuvwxyz'", "HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL"],+  ["''", "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL"],+  ["'a'", "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL"],+  ["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL"],+++  ["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL"],+  ["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL"],++  ["0", "IF 0xba ELSE 1 ENDIF", "opcodes above NOP10 invalid if executed"],+  ["0", "IF 0xbb ELSE 1 ENDIF"],+  ["0", "IF 0xbc ELSE 1 ENDIF"],+  ["0", "IF 0xbd ELSE 1 ENDIF"],+  ["0", "IF 0xbe ELSE 1 ENDIF"],+  ["0", "IF 0xbf ELSE 1 ENDIF"],+  ["0", "IF 0xc0 ELSE 1 ENDIF"],+  ["0", "IF 0xc1 ELSE 1 ENDIF"],+  ["0", "IF 0xc2 ELSE 1 ENDIF"],+  ["0", "IF 0xc3 ELSE 1 ENDIF"],+  ["0", "IF 0xc4 ELSE 1 ENDIF"],+  ["0", "IF 0xc5 ELSE 1 ENDIF"],+  ["0", "IF 0xc6 ELSE 1 ENDIF"],+  ["0", "IF 0xc7 ELSE 1 ENDIF"],+  ["0", "IF 0xc8 ELSE 1 ENDIF"],+  ["0", "IF 0xc9 ELSE 1 ENDIF"],+  ["0", "IF 0xca ELSE 1 ENDIF"],+  ["0", "IF 0xcb ELSE 1 ENDIF"],+  ["0", "IF 0xcc ELSE 1 ENDIF"],+  ["0", "IF 0xcd ELSE 1 ENDIF"],+  ["0", "IF 0xce ELSE 1 ENDIF"],+  ["0", "IF 0xcf ELSE 1 ENDIF"],+  ["0", "IF 0xd0 ELSE 1 ENDIF"],+  ["0", "IF 0xd1 ELSE 1 ENDIF"],+  ["0", "IF 0xd2 ELSE 1 ENDIF"],+  ["0", "IF 0xd3 ELSE 1 ENDIF"],+  ["0", "IF 0xd4 ELSE 1 ENDIF"],+  ["0", "IF 0xd5 ELSE 1 ENDIF"],+  ["0", "IF 0xd6 ELSE 1 ENDIF"],+  ["0", "IF 0xd7 ELSE 1 ENDIF"],+  ["0", "IF 0xd8 ELSE 1 ENDIF"],+  ["0", "IF 0xd9 ELSE 1 ENDIF"],+  ["0", "IF 0xda ELSE 1 ENDIF"],+  ["0", "IF 0xdb ELSE 1 ENDIF"],+  ["0", "IF 0xdc ELSE 1 ENDIF"],+  ["0", "IF 0xdd ELSE 1 ENDIF"],+  ["0", "IF 0xde ELSE 1 ENDIF"],+  ["0", "IF 0xdf ELSE 1 ENDIF"],+  ["0", "IF 0xe0 ELSE 1 ENDIF"],+  ["0", "IF 0xe1 ELSE 1 ENDIF"],+  ["0", "IF 0xe2 ELSE 1 ENDIF"],+  ["0", "IF 0xe3 ELSE 1 ENDIF"],+  ["0", "IF 0xe4 ELSE 1 ENDIF"],+  ["0", "IF 0xe5 ELSE 1 ENDIF"],+  ["0", "IF 0xe6 ELSE 1 ENDIF"],+  ["0", "IF 0xe7 ELSE 1 ENDIF"],+  ["0", "IF 0xe8 ELSE 1 ENDIF"],+  ["0", "IF 0xe9 ELSE 1 ENDIF"],+  ["0", "IF 0xea ELSE 1 ENDIF"],+  ["0", "IF 0xeb ELSE 1 ENDIF"],+  ["0", "IF 0xec ELSE 1 ENDIF"],+  ["0", "IF 0xed ELSE 1 ENDIF"],+  ["0", "IF 0xee ELSE 1 ENDIF"],+  ["0", "IF 0xef ELSE 1 ENDIF"],+  ["0", "IF 0xf0 ELSE 1 ENDIF"],+  ["0", "IF 0xf1 ELSE 1 ENDIF"],+  ["0", "IF 0xf2 ELSE 1 ENDIF"],+  ["0", "IF 0xf3 ELSE 1 ENDIF"],+  ["0", "IF 0xf4 ELSE 1 ENDIF"],+  ["0", "IF 0xf5 ELSE 1 ENDIF"],+  ["0", "IF 0xf6 ELSE 1 ENDIF"],+  ["0", "IF 0xf7 ELSE 1 ENDIF"],+  ["0", "IF 0xf8 ELSE 1 ENDIF"],+  ["0", "IF 0xf9 ELSE 1 ENDIF"],+  ["0", "IF 0xfa ELSE 1 ENDIF"],+  ["0", "IF 0xfb ELSE 1 ENDIF"],+  ["0", "IF 0xfc ELSE 1 ENDIF"],+  ["0", "IF 0xfd ELSE 1 ENDIF"],+  ["0", "IF 0xfe ELSE 1 ENDIF"],+  ["0", "IF 0xff ELSE 1 ENDIF"],++  ["NOP",+  "'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'",+  "520 byte push"],+  ["1",+  "0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",+  "201 opcodes executed. 0x61 is NOP"],+  ["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+  "1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+  "1,000 stack size (0x6f is 3DUP)"],+  ["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+  "1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f",+  "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",+  "Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"],++  ["NOP","1"],++  ["1", "0x01 0x01 EQUAL", "The following is useful for checking implementations of BN_bn2mpi"],+  ["127", "0x01 0x7F EQUAL"],+  ["128", "0x02 0x8000 EQUAL", "Leave room for the sign bit"],+  ["32767", "0x02 0xFF7F EQUAL"],+  ["32768", "0x03 0x008000 EQUAL"],+  ["8388607", "0x03 0xFFFF7F EQUAL"],+  ["8388608", "0x04 0x00008000 EQUAL"],+  ["2147483647", "0x04 0xFFFFFF7F EQUAL"],+  ["2147483648", "0x05 0x0000008000 EQUAL"],+  ["-1", "0x01 0x81 EQUAL", "Numbers are little-endian with the MSB being a sign bit"],+  ["-127", "0x01 0xFF EQUAL"],+  ["-128", "0x02 0x8080 EQUAL"],+  ["-32767", "0x02 0xFFFF EQUAL"],+  ["-32768", "0x03 0x008080 EQUAL"],+  ["-8388607", "0x03 0xFFFFFF EQUAL"],+  ["-8388608", "0x04 0x00008080 EQUAL"],+  ["-2147483647", "0x04 0xFFFFFFFF EQUAL"],+  ["-2147483648", "0x05 0x0000008080 EQUAL"],++  ["2147483647", "1ADD 2147483648 EQUAL", "We can do math on 4-byte integers, and compare 5-byte ones"],+  ["2147483647", "1ADD 1"],+  ["-2147483647", "1ADD 1"],+++  ["NOP", "NOP 1", "The following tests check the if(stack.size() < N) tests in each opcode"],+  ["1", "IF 1 ENDIF", "They are here to catch copy-and-paste errors"],+  ["0", "NOTIF 1 ENDIF", "Most of them are duplicated elsewhere,"],+  ["1", "VERIFY 1", "but, hey, more is always better, right?"],++  ["0", "TOALTSTACK 1"],+  ["1", "TOALTSTACK FROMALTSTACK"],+  ["0 0", "2DROP 1"],+  ["0 1", "2DUP"],+  ["0 0 1", "3DUP"],+  ["0 1 0 0", "2OVER"],+  ["0 1 0 0 0 0", "2ROT"],+  ["0 1 0 0", "2SWAP"],+  ["1", "IFDUP"],+  ["NOP", "DEPTH 1"],+  ["0", "DROP 1"],+  ["1", "DUP"],+  ["0 1", "NIP"],+  ["1 0", "OVER"],+  ["1 0 0 0 3", "PICK"],+  ["1 0", "PICK"],+  ["1 0 0 0 3", "ROLL"],+  ["1 0", "ROLL"],+  ["1 0 0", "ROT"],+  ["1 0", "SWAP"],+  ["0 1", "TUCK"],++  ["1", "SIZE"],++  ["0 0", "EQUAL"],+  ["0 0", "EQUALVERIFY 1"],++  ["0", "1ADD"],+  ["2", "1SUB"],+  ["-1", "NEGATE"],+  ["-1", "ABS"],+  ["0", "NOT"],+  ["-1", "0NOTEQUAL"],++  ["1 0", "ADD"],+  ["1 0", "SUB"],+  ["-1 -1", "BOOLAND"],+  ["-1 0", "BOOLOR"],+  ["0 0", "NUMEQUAL"],+  ["0 0", "NUMEQUALVERIFY 1"],+  ["-1 0", "NUMNOTEQUAL"],+  ["-1 0", "LESSTHAN"],+  ["1 0", "GREATERTHAN"],+  ["0 0", "LESSTHANOREQUAL"],+  ["0 0", "GREATERTHANOREQUAL"],+  ["-1 0", "MIN"],+  ["1 0", "MAX"],+  ["-1 -1 0", "WITHIN"],++  ["0", "RIPEMD160"],+  ["0", "SHA1"],+  ["0", "SHA256"],+  ["0", "HASH160"],+  ["0", "HASH256"],+  ["NOP", "CODESEPARATOR 1"],++  ["NOP", "NOP1 1"],+  ["NOP", "NOP2 1"],+  ["NOP", "NOP3 1"],+  ["NOP", "NOP4 1"],+  ["NOP", "NOP5 1"],+  ["NOP", "NOP6 1"],+  ["NOP", "NOP7 1"],+  ["NOP", "NOP8 1"],+  ["NOP", "NOP9 1"],+  ["NOP", "NOP10 1"],++  ["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Very basic P2SH"],+  ["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"]+  ]
+ Bitcoin/Test/TxCheck.hs view
@@ -0,0 +1,76 @@+
+-- | Some tests for transaction validation
+
+module Bitcoin.Test.TxCheck where
+
+--------------------------------------------------------------------------------
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import Bitcoin.BlockChain.Tx
+import Bitcoin.Protocol
+
+import Bitcoin.Script.Run
+
+import Bitcoin.Test.TxCheck.TestNet3
+import Bitcoin.Test.TxCheck.MainNet
+
+import Bitcoin.Misc.HexString
+
+--------------------------------------------------------------------------------
+
+testgroup_TxCheck :: TestTree
+testgroup_TxCheck = testGroup "transaction checks"
+  [ testgroup_testnet3
+  , testgroup_mainnet
+  ]
+
+testgroup_testnet3 :: TestTree
+testgroup_testnet3 = testGroup "testnet3"
+  [ testCase ("testnet3 tx #" ++ show i ++ " | hash = " ++ show (_txHash tx)) (runSingle tx) 
+  | (i,tx) <- zip [1..] some_testnet3_txs
+  ]
+
+testgroup_mainnet :: TestTree
+testgroup_mainnet = testGroup "mainnet"
+  [ testCase ("mainnet tx #" ++ show i ++ " | hash = " ++ show (_txHash tx)) (runSingle tx) 
+  | (i,tx) <- zip [1..] some_mainnet_txs
+  ]
+
+--------------------------------------------------------------------------------
+
+runSingle :: Tx (Tx RawScript RawScript, RawScript) RawScript -> Assertion
+runSingle txExt = do
+  let ei = checkTransaction txExt
+  case ei of
+    Left err -> assertFailure err
+    Right b  -> case b of
+      True  -> return ()
+      False -> do
+        let msg = "tx " ++ unHexString (toHexString (_txHash txExt))
+        assertFailure ("failed: " ++ msg)
+
+--------------------------------------------------------------------------------
+
+{-
+runTxCheckTests :: IO ()
+runTxCheckTests = 
+  do
+    putStrLn "\nsome testnet transactions:"
+    mapM_ runSingle some_testnet3_txs
+    putStrLn "\nsome mainnet transactions:"
+    mapM_ runSingle some_mainnet_txs
+  where 
+    runSingle txExt = do
+      let ei = checkTransaction txExt
+          result = case ei of
+            Left err -> err
+            Right b  -> case b of
+              True  -> "ok"
+              False -> "failed"
+      putStrLn $ "tx " ++ unHexString (toHexString (_txHash txExt)) ++ " - " ++ result
+-}
+
+--------------------------------------------------------------------------------
+
+ Bitcoin/Test/TxCheck/MainNet.hs view
@@ -0,0 +1,1733 @@+
+-- | Some interesting (corner case) transactions from the main network, together with their 
+-- previous transactions
+
+module Bitcoin.Test.TxCheck.MainNet where
+
+--------------------------------------------------------------------------------
+
+import Bitcoin.BlockChain.Tx
+import Bitcoin.Protocol
+
+--------------------------------------------------------------------------------
+
+some_mainnet_txs = 
+
+    [ tx_730ee3ae 
+    , tx_05f35ee4       -- note: these ids are the *last* 8 characters of the hash (written in BE as usual), in reverse order 
+    , tx_4536b1ed       -- (i messed up, but it's not important so i'm leaving it as it is :)
+    , tx_c8b2c169
+    , tx_cd53d64c
+    , tx_1e8c0e2d
+    , tx_023ffe8f
+    , tx_4d8666fa
+    , tx_35078453
+    , tx_a2b9f88d
+    , tx_687eb861
+    , tx_d49ae9c6
+    , tx_a0f093d1
+    , tx_31a46ded
+    , tx_9183e7b3
+    , tx_e04baa84
+    , tx_604c747a
+    , tx_ebfa4562
+    , tx_091f8607
+    , tx_94bccdc5
+    , tx_5d4bfd57
+    , tx_bdc6230d
+    , tx_e3ba6bf1
+    , tx_0b773101
+    , tx_ceafe873
+    ]
+
+  where
+
+    tx_730ee3ae = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "4974d995c0291573caa216d538f2d79f27fe4f9fa351314e2c21b554dbdfd87f",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100b6a7fe5eea81894bbdd0df61043e42780543457fa5581ac1af023761a098e92202201d4752785be5f9d1b9f8d362b8cf3b05e298a78c4abff874b838bb500dcf2a120141042e3c4aeac1ffb1c86ce3621afb1ca92773e02badf0d4b1c836eb26bd27d0c2e59ffec3d6ab6b8bbeca81b0990ab5224ebdd73696c4255d1d0c6b3c518a1a053e",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 5000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914dc44b1164188067c3a32d4780f5996fa14a4f2d988ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602"},
+                       rawScriptFromString
+                         "493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5"),
+                    _txInSeqNo = 0}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 4000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"}
+
+
+    tx_05f35ee4 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "7af3b1301126cba1f27c074aa0ecf9ec1337568b46b5c15990fe392fecd6acfd",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "40f35ff0079448b9275c0b532ba839611afbe31eb98ecf406aa1fa8df1ee0103",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100e9bf207bfbd447a17cb6da9d2a6bafb083e6a7a77b7fb493a1a84dc603daafc402207c0518af5bf58fda038ba8b3c588badcfbabd48c3501c599a3a18a922496cae601410437b81272ac842590a9d75b74ddf11faf21e47f1fb42a207ea8a799d42bde1a33f007e6cc6c92a22494a4a0e1a46c71c7fc3ebfedd3e2be03fc27b0e4df69034b",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100de9eab2250e7cad8349d006d83a436475cc9d53f1b850ec11088524df7b1c9530220115e9f8c1a72f3efecce8551fb5b395fa5f329d915f07626255918731e05e5b2014104d7b6ff1469a6f5da3bc10961b488a0ab6484b800b77c069e4f71ed9b7f698d484845046b0fee8b043fe36dc345a1794f1c26447c45671d5b6012f864ef51a19f",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 5000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9144ad6b326f980e87c3c9e298cce9b773f329d428188ac"},
+                             TxOutput{_txOutValue = 3000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914a691714db17036d30e8b9e8dac9ac0e8e3dc449e88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "7af3b1301126cba1f27c074aa0ecf9ec1337568b46b5c15990fe392fecd6acfd"},
+                       rawScriptFromString
+                         "483045022033eb6fc4eee4f925bbe5df26ad8eb3b51ca8e5f599057bcc479aa2d450cb36ed0221009ed0ff46379f89b5f3d2444f715fcd056817d3303c5e3f6318a7d54673fb61ed004104a013b98715379a42aedb498e9b90d054530d01a12e48877267c2bcd169602a38a430ff4134536064f9034ba8fc5731648a8e8f03976e75e07bc114867dbb3446"),
+                    _txInSeqNo = 0}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 4000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "0ad07700151caa994c0bc3087ad79821adf071978b34b8b3f0838582e45ef305"}
+
+
+    tx_4536b1ed = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "04b63c92e931604c93ac4e09aa9e5cdb6d982c8773c8d55b0da541cb168be961",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "381e0933965cd2dc003d4a266d747805b4b90e01bf7b43afca42810963886259",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "4730440220151e5df30ca6b0a2c247cbc9c95a77dbede5954935c3cbd5f6cd91382339430f022059d88d225b09f11459487f61547cd1b4695af55badfdc0de0f5fba7e6a58d5bb014104a9fa929b669d576b25c1c78b1764cc211495655fb8d0591801cf0bb52c0bdacdebac1baeb58c8141b5359caa81d5cb532daf95667898cec3737b38b05c7b74ec",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 32000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9140ae18d248d2857f597c98e3929322f330e0d35c888ac"},
+                             TxOutput{_txOutValue = 10000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914dfe61ae656b348a1de565b04a5c906d6210fe48588ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "04b63c92e931604c93ac4e09aa9e5cdb6d982c8773c8d55b0da541cb168be961"},
+                       rawScriptFromString
+                         "483045022100b8136d33dcf791c5008b56dbf3ec88ac950d848913a703b6ef577986a3fed027022019b7c1e21d9c8d53257f48b7f0727bf8410525d524c1b594baca0a29311f7c9d0041040c367eea20dfa49a1aac1cef9b26e7e87e029c066bd78e3cf73e3fccbf5ba29987d8486a4cf31bc8297cea1c21d613074a01853811ae3e26ec56e063da51f324"),
+                    _txInSeqNo = 0}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 4000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"},
+            TxOutput{_txOutValue = 5000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9145f5b25b608df561037dfd06df5b4c75641df876f88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "7c451f68e15303ab3e28450405cfa70f2c2cc9fa29e92cb2d8ed6ca6edb13645"}
+
+
+    tx_c8b2c169 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "7c451f68e15303ab3e28450405cfa70f2c2cc9fa29e92cb2d8ed6ca6edb13645",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "04b63c92e931604c93ac4e09aa9e5cdb6d982c8773c8d55b0da541cb168be961",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100b8136d33dcf791c5008b56dbf3ec88ac950d848913a703b6ef577986a3fed027022019b7c1e21d9c8d53257f48b7f0727bf8410525d524c1b594baca0a29311f7c9d0041040c367eea20dfa49a1aac1cef9b26e7e87e029c066bd78e3cf73e3fccbf5ba29987d8486a4cf31bc8297cea1c21d613074a01853811ae3e26ec56e063da51f324",
+                                     _txInSeqNo = 0}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 4000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"},
+                             TxOutput{_txOutValue = 5000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145f5b25b608df561037dfd06df5b4c75641df876f88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "7c451f68e15303ab3e28450405cfa70f2c2cc9fa29e92cb2d8ed6ca6edb13645"},
+                       rawScriptFromString
+                         "4830450221009c3beea64e50cd952532411cac06f0ebedd314eb24869c50274af666ea5ec02b022065c36676885cb708f0706cbc87659a9210507cd6476457ebe44a8a5bbe48a3790041041a94acd54a2bcfc8ce8ec59a07ebc06ea4ec9a994f8927af4850dc6d9f95598aa93186529e0ba6a236c2c6f1c181377e537181f65eb79cb9c9b764c75788ff2e"),
+                    _txInSeqNo = 0}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 1500000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"},
+            TxOutput{_txOutValue = 2500000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914ba97ff48413d4de71c42ced7d9fec680192f367488ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "a6c116351836d9cc223321ba4b38d68c8f0db53661f8c2229acabbc269c1b2c8"}
+
+
+    tx_cd53d64c = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "6bd7acdefe329601ff7659138bde836569bd8f415a0a889582c3c14de26a87a1",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "cfd3b57199ed9d19b9b99256320f3be305adad771c85662184968f73c5d9acdf",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100dca97b7e358e1d81a0e4a647bdae3ff6f26aa763f3aa9b3dafa283bdae33a10a02200fd0bd4e7adffca854607d315c0093cd771eeec52bb58afc29171ebeb9e19fb90141046b8c76a1f34604ee741e6ec1deb3215bac12e101d3e24fc73dd6c3b143ae9ac40b93f677268093d06828675a02d43cc3132bd5e6fb3bb80701caba8f3bc8760f",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 100000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9148b30467657a145977bba903d84283b565ac185bf88ac"},
+                             TxOutput{_txOutValue = 223000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914b09207be0402a677fbc7af4e617245850ad9c16388ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "6bd7acdefe329601ff7659138bde836569bd8f415a0a889582c3c14de26a87a1"},
+                       rawScriptFromString
+                         "48304502206ec57ff846660ffe536d05e10020bb589875f7d1e5eeb5f080308e0f635f84060221009fec54bf52250fe7c999107e1c78f061a78016d51d49b8de04cf92a5de6365b900410458f16d4860d3e01e9a2b57e4e458c8f08ed61a94397aadf0c88e3dd237fbb510cb2760aef26a0c0dd6ba67248992051b2b2e047f0f88450648c2bc4f580921df"),
+                    _txInSeqNo = 0}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 49000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"},
+            TxOutput{_txOutValue = 50000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9143d2008fe12629cabf06e329720407835ab4a3fc788ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "f5efee46ccfa4191ccd9d9f645e2f5d09bbe195f95ef5608e992d6794cd653cd"}
+
+
+    tx_1e8c0e2d = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "f5efee46ccfa4191ccd9d9f645e2f5d09bbe195f95ef5608e992d6794cd653cd",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "6bd7acdefe329601ff7659138bde836569bd8f415a0a889582c3c14de26a87a1",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502206ec57ff846660ffe536d05e10020bb589875f7d1e5eeb5f080308e0f635f84060221009fec54bf52250fe7c999107e1c78f061a78016d51d49b8de04cf92a5de6365b900410458f16d4860d3e01e9a2b57e4e458c8f08ed61a94397aadf0c88e3dd237fbb510cb2760aef26a0c0dd6ba67248992051b2b2e047f0f88450648c2bc4f580921df",
+                                     _txInSeqNo = 0}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 49000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"},
+                             TxOutput{_txOutValue = 50000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9143d2008fe12629cabf06e329720407835ab4a3fc788ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "f5efee46ccfa4191ccd9d9f645e2f5d09bbe195f95ef5608e992d6794cd653cd"},
+                       rawScriptFromString
+                         "493046022100cf687b15278731ee0ddb392b1bc764d33fc3f2e35fcd8a929a81abec31af1d4b022100a156e6c070726ad6cd2880296ecd440d74cfdc5526c15171b33576c03ca84729004104ad9cec0f378f53270082d595d44da3d9259fdd6b856a000f2e8cf4be754f3bfd848e62ff8edf93204961c9da626b9d12db8d23cffc7ad32b119464fcedb369c5"),
+                    _txInSeqNo = 0}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 24000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"},
+            TxOutput{_txOutValue = 25000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91410a9055904cc30bcbaf5b9e97c1b49d4aa60f08d88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "904bda3a7d3e3b8402793334a75fb1ce5a6ff5cf1c2d3bcbd7bd25872d0e8c1e"}
+
+
+    tx_023ffe8f = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "904bda3a7d3e3b8402793334a75fb1ce5a6ff5cf1c2d3bcbd7bd25872d0e8c1e",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "f5efee46ccfa4191ccd9d9f645e2f5d09bbe195f95ef5608e992d6794cd653cd",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100cf687b15278731ee0ddb392b1bc764d33fc3f2e35fcd8a929a81abec31af1d4b022100a156e6c070726ad6cd2880296ecd440d74cfdc5526c15171b33576c03ca84729004104ad9cec0f378f53270082d595d44da3d9259fdd6b856a000f2e8cf4be754f3bfd848e62ff8edf93204961c9da626b9d12db8d23cffc7ad32b119464fcedb369c5",
+                                     _txInSeqNo = 0}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 24000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"},
+                             TxOutput{_txOutValue = 25000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a91410a9055904cc30bcbaf5b9e97c1b49d4aa60f08d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "904bda3a7d3e3b8402793334a75fb1ce5a6ff5cf1c2d3bcbd7bd25872d0e8c1e"},
+                       rawScriptFromString
+                         "48304502200800b74207bd708713893ee143370d78642ff45155d5533f09dc58b48bab08820221008216b942e1b1c44e8c08c1919cc30b06220b28e71228deb809322cb3827a2b02004104a4ead59a9952460a92272e62d6bfcd5551f645212a4b2b00e1181f14fed797a65d06cc8c8f4f25e3920f6be5fd0d6d73144c785939a60fa3cc6697c79cbe484e"),
+                    _txInSeqNo = 0}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 11500000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac"},
+            TxOutput{_txOutValue = 12500000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914abc43ef01ed21912bc6646d2c24136434f69de3588ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "8ac76995ce4ac10dd02aa819e7e6535854a2271e44f908570f71bc418ffe3f02"}
+
+
+    tx_4d8666fa = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "aa85c2dd8bc29ef4015ed110ba543ea8adbccee2d1f3f51af33fc145c4aa1623",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "d0634be008dcc5920d21c301130e53b157211b07749fb433ecd524d0498c98ba",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502200f18c2d1fe6513b90f44513e975e05cc498e7f5a565b46c65b1d448734392c6f022100917766d14f2e9933eb269c83b3ad440ed8432da8beb5733f34046509e48b1d850141049ba39856eec011b79f1acb997760ed9d3f90d477077d17df2571d94b2fa2137bf0976d786b6aabc903746e269628b2c28e4b5db753845e5713a48ee7d6b97aaf",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 3000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9147a2a3b481ca80c4ba7939c54d9278e50189d94f988ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "aa85c2dd8bc29ef4015ed110ba543ea8adbccee2d1f3f51af33fc145c4aa1623"},
+                       rawScriptFromString
+                         "4b3048022200002b83d59c1d23c08efd82ee0662fec23309c3adbcbd1f0b8695378db4b14e736602220000334a96676e58b1bb01784cb7c556dd8ce1c220171904da22e18fe1e7d1510db5014104d0fe07ff74c9ef5b00fed1104fad43ecf72dbab9e60733e4f56eacf24b20cf3b8cd945bcabcc73ba0158bf9ce769d43e94bd58c5c7e331a188922b3fe9ca1f5a"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 3000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9147a2a3b481ca80c4ba7939c54d9278e50189d94f988ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "fb0a1d8d34fa5537e461ac384bac761125e1bfa7fec286fa72511240fa66864d"}
+
+
+    tx_35078453 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "51f2a76c6f86f18079a9fde6e72c5694f392c7829eb9a93f6f6eb4eb9c692e16",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "f6e29be468b308c80d6b64121baa136a96e9ac5d685f644b4bbce2e8eb1ca715",
+                                     _txInPrevOutIdx = 49,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "4930460221008aa83ca31a71a65f429ae46bf216f9cae8ea4474771ec996950821660f4611e8022100e2de287ac2e0edfa90b1363fde96ff0698495eb71e1460ec1e34f56912d3949101410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "afc5a667734c637512010a647399b061b42d769209e59350651887f9d01c5e2a",
+                                     _txInPrevOutIdx = 35,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "4730440220329aba7a3d19d07d371e001a4d74ee14d69a25b98ac13e5726ae85ce8c90d1c7022035bdb358186091d258fddd7cdf78657d1ddd8adbefd4b245f81d9d34c833475901410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "fb6ed5c0fd0f4b54f512fe47e153bb5d0644afc192cbafe50753d55ef5f0223f",
+                                     _txInPrevOutIdx = 27,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100dd6496bf066835511a8d5c0ef640d339dfff51e0263843177e6ecce4db155e89022058f99badfeae1638e463a53e4baac75663482b5c367a9d79fa93cdb9d9349e1a01410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "475d1cf4d7ab81171e670d6c2c948d15c4a0d80e2aa1eaaea3b512343a5bf757",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "473044022037622097853da2b3f2757cb2d3776b5c0f88ec5aba4301c89cd933b02977185b02200c869b080e60b596b0f5540011be681b7b0b2cbead1730beca2653192481b50201410439363df8bfe1566aaa40c5812e9931df6d3cf97455c67dce7c1bf2f74f1564d5646ebae32a435015a68cb73ef14d8c1c8f311a19dbfb461cb161a9e2cfdad64f",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1002675,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914ef9b3d09be64c9372c99c6de18ca225e108e63c688ac"},
+                             TxOutput{_txOutValue = 50000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9146482d425dc43ff3890071f13c07c42236e50833888ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "51f2a76c6f86f18079a9fde6e72c5694f392c7829eb9a93f6f6eb4eb9c692e16"},
+                       rawScriptFromString
+                         "493045022100a9379b66c22432585cb2f5e1e85736c69cf5fdc9e1033ad583fc27f0b7c561d802202c7b5d9d92ceca742829ffbe28ba6565faa8f94556cb091cbc39d2f11d45946700014104650a9a1deb523f636379ec70c29b3e1e832e314dea0f791160f3dba628f4f509360e525318bf7892af9ffe2f585bf7b264aa31792744ec1885ce17f3b1ef50f3"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 45000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914ed2533122ffd7f0724c424599206ccb23e89d6f788ac"},
+            TxOutput{_txOutValue = 5000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914c0ac87c28c943caead3e6d64663449bfc9f0a5ce88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "a618dc10b8a1f9d9a1469b3bb84fc17da86df2d51c27e2aa16fa130953840735"}
+
+
+    tx_a2b9f88d = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "a618dc10b8a1f9d9a1469b3bb84fc17da86df2d51c27e2aa16fa130953840735",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "51f2a76c6f86f18079a9fde6e72c5694f392c7829eb9a93f6f6eb4eb9c692e16",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493045022100a9379b66c22432585cb2f5e1e85736c69cf5fdc9e1033ad583fc27f0b7c561d802202c7b5d9d92ceca742829ffbe28ba6565faa8f94556cb091cbc39d2f11d45946700014104650a9a1deb523f636379ec70c29b3e1e832e314dea0f791160f3dba628f4f509360e525318bf7892af9ffe2f585bf7b264aa31792744ec1885ce17f3b1ef50f3",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 45000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914ed2533122ffd7f0724c424599206ccb23e89d6f788ac"},
+                             TxOutput{_txOutValue = 5000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914c0ac87c28c943caead3e6d64663449bfc9f0a5ce88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "a618dc10b8a1f9d9a1469b3bb84fc17da86df2d51c27e2aa16fa130953840735"},
+                       rawScriptFromString
+                         "493045022034e4786cf22cd00b45faff8afc3b8789c924378176d934adee0d3b3f4a8bf0dc022100b658dd07beeede1f792d238c3ee29c25200f3b834662f9c900bb4d065526dac900014104b72ce98ffd246b2b52046394e6676b756272693a41c00a4f607bf61130c744b9725508fe33cdacb260ee9175bcfafca49f7544af7f0307a81f4840e6745a51e4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "ca4dcdc1d9d64c74593cc7020e0df54e8e5677cb32262112fea828c8d6b9e012",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "3ab74ed863772e882dd1c2a01318ebdcf5346ed862f43f7995591aef70da1b87",
+                                     _txInPrevOutIdx = 47,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502206a5009fb210db932fe138784c788ad8b420d153bdd42e6aa7e54ea03bb39c06e022100fc4034c40cfe985b60e11d59ac5118ce8ac7d6e3e58c259b7635514101b8005c01410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1137896,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9148bd403423a36dd650fb93c499f454ada2e64076b88ac"},
+                             TxOutput{_txOutValue = 1000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9146482d425dc43ff3890071f13c07c42236e50833888ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "ca4dcdc1d9d64c74593cc7020e0df54e8e5677cb32262112fea828c8d6b9e012"},
+                       rawScriptFromString
+                         "493045022052538ceefdadef44696559b5b135e48218403f10120bcf592825b924af804821022100ed30a2a2218ad85438fd6a38f909b5ac55bc322033b63ddf17b3b9db11cd618000014104650a9a1deb523f636379ec70c29b3e1e832e314dea0f791160f3dba628f4f509360e525318bf7892af9ffe2f585bf7b264aa31792744ec1885ce17f3b1ef50f3"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 6000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914ed2533122ffd7f0724c424599206ccb23e89d6f788ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "67e758b27df26ad609f943b30e5bbb270d835b737c8b3df1a7944ba08df8b9a2"}
+
+
+    tx_687eb861 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "d7161e20fde5d5c3fd2a050ed5ca4b5099630135e253e8c0347ca2e8516a7967",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "cd6dac2b078a477ec0ced1aac45dfc61cf36abc4dc14bd280b93ce1bb66e764e",
+                                     _txInPrevOutIdx = 15,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022060fe0c18b95e88eadb1329c6e70161a776b5ab7f88a3d5e1cd10f9e2b21d9d76022100bee91d1fc4e09b73c5adece74cd24c6def660b976becd3c167c145d4d372c67a01410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "83fc7eb1f2557093d49c3422c9af0621f5e36e1ee2c398edf7188d0960a78b46",
+                                     _txInPrevOutIdx = 35,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502204c5cc4f3d25311322db91a98ecf227f4b827b0763810a82be337a7277d767a91022100dd35036a5a1b3391ad03b4ce91ab9020c3e7edfe6f95934a4489d9fd660001df01410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "2e64b3af2794f18b9dd329ab6273818aebaf991423b7ac8216b73be6e721248d",
+                                     _txInPrevOutIdx = 35,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402203ca0caaf94dabf14d4a9142a769b64de57edadaccd7e896307040e37570bd7d8022056feb48a6ac657bf81f1895da7c503e80a8aa5c0ba6a97aac43403d91f8675a701410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1003890,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9149a51d178508a0129b4f7fabbb9471d33ca761d5288ac"},
+                             TxOutput{_txOutValue = 20000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914d00e78df206bb30c34b4ab01bb775af39def92a188ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "d7161e20fde5d5c3fd2a050ed5ca4b5099630135e253e8c0347ca2e8516a7967"},
+                       rawScriptFromString
+                         "493045022100eccb0785c18ecd405d37cd0369f7cdadf62c1c5afd8c2fb4a7748c20e3073c3802203f7b1e36de55b38abb4badf71679171c7fada67587dba7f5017f684a840d1c150001410430ed754f2ab8ef5ac46e4622a0e9e79922457fc62e3d2c3c8abccf3fe123ed338fa39be3695ebeafbb6dbd4cb94f81a8b0b738e09bf146af03d4d30135ef3c43"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 10000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914ed2533122ffd7f0724c424599206ccb23e89d6f788ac"},
+            TxOutput{_txOutValue = 10000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9146780e620b8e29804855dbbb6e604f5e38621feed88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "fa253ace4be5a4acde8a6c5e6adc808de965e09f16fc5b65b7cb58f961b87e68"}
+
+
+    tx_d49ae9c6 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "c92e4ac4a54f356d1d2956f952cce054098f0cf61d1e2618b6b090f200ed9ced",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "da475734568820a4c03cfd9e8237a45b47be3500a8869bd16a21933b46a04253",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "473044022073efdad5fcf4f63e5529038706baa99d317feebb12225d4f09516eb2faa0940b0220171cadd9b5bf6cfa87c87cf244e1fbd3ca295cb1c658c7ba78ebb07f11e717de0141043712320aaf75db9e016e7777f124c26283e85a58f6ff6a18d6d046bad17e6552355db60bd831bd0721e296b7173da2ab2f16beba09b66b964b593472b91c0a93",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 2741650000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9141991e869480afb2f35696c552546625310d827b288ac"},
+                             TxOutput{_txOutValue = 100000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "c92e4ac4a54f356d1d2956f952cce054098f0cf61d1e2618b6b090f200ed9ced"},
+                       rawScriptFromString
+                         "49304402206dde40f793d40a241a9d8957f529c82d1988cc53240a0b107741dc06e6753be302203b80dc2ee98c240d6c9bf1b1d03882b8aa8b53e55be480ee557d4c448178222300000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 100000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91407a2bc41a410629bf3055f6c73b0fc32aad822ac88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "bf4a7d685be994bc27ddd82cfd75fe27a8945544ef95e58b62a98c6dc6e99ad4"}
+
+
+    tx_a0f093d1 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "8f86c20eb02bc1d2eabf5d05f04ef3d7464e9e49bc243146188122b1d6eb7858",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "f11475d7de904e6a8238a72bea7b440ef5aad425c2a27225b352eed607f55382",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402204ed920cc2cf325366c90ec72c297db1d51f14294a457499f316171fe6e84aba8022034bc817c8b287ad5932e2626bb0d0beb28cf4f875adc4ab6f6fb57fa2f280be201410478fde041341ee1d124dd95aeba0bfc77a4bf8fcf8b51d6c1e749f2e833df2038dc132dca08d6a9c28d77116770afb07fd0a23ffa2a6f6f9f3760ba6a409ffcc0",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 2895550000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9146d771b9503b3417ac2903a81eb97eb07e3e8a61f88ac"},
+                             TxOutput{_txOutValue = 203000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "8f86c20eb02bc1d2eabf5d05f04ef3d7464e9e49bc243146188122b1d6eb7858"},
+                       rawScriptFromString
+                         "493045022100c8c0430c6266ed3d59932c6616a158af102787162d48fb29e84f20c87a9eeaa802202d71976d98b0eaebde10abd50d7076d9b1f58a80e7c00c3f4cb95efa28834af3000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "952b3173835462fff02cdf01032246372bc59d6c76563693fc61508a61ddf541",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "1ac1e6b01399fddff78ec578450fb6c6bbefa7cc499fd316c6fcc1a05a40c204",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100b665271efa9844b05fd53ba0c925266f3b1e268814605940eadc1b639a2f8475022100e71e18b7022c48c0b096b0e484ed44c2e21c589925ddb5d4149a00d1752a538c014104f5ba281f1335673f11bcb347d18c85f906b52dd49560d7851b722fb8cb290a4ffa8c46a459299b09f4c0c39d36312910f6ed70be2592ba3f6f0a2cfb6c52a253",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 4473900000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914a5f77f4cc8e084054f0b202c3ccf8ced2b63aa7c88ac"},
+                             TxOutput{_txOutValue = 202000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "952b3173835462fff02cdf01032246372bc59d6c76563693fc61508a61ddf541"},
+                       rawScriptFromString
+                         "493044022007733199509695d8d6cbf81401ce8256f2a90f298a8bd1b57f98fbb3562a86bd0220412f4d9aec3644a36922050ff28f5371b4a49542f6a214ba50beca9b33f2468e00000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "5f097c7f98f4e7c30ba45ac8558f2e0312734b20c3ba8eebed3c7a16f0cbb08d",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "73c4c02476ef6865a02f6e805611f8346fb3e33d24e79e402172dd4c091cdbec",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "473044022046822d74067f96a45ad9c882a020db0cde815c2464d4a3dc9ca99ba7ca5a37cb02201a90455d5da20cec3718fe2a4ae3323a5d70a89897aa31a2987a656a5cbdb85d014104de0117a204f91892e96170d38b2683f76a6892a3ea7878dce5604e55603eb36161d01e5046733866b763d9832ab2b2dde6ddd999af07b22d5bb365b9508991a3",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 2571100000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914f5e205e30e51a668fbb4d5fc4bda29addce525b588ac"},
+                             TxOutput{_txOutValue = 204000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "5f097c7f98f4e7c30ba45ac8558f2e0312734b20c3ba8eebed3c7a16f0cbb08d"},
+                       rawScriptFromString
+                         "49304402205cb326a8520a4bd15457052cb8958c3210f504db102b4df11ac214956066158d02202300c578f2c87ceac66b20ac1ab263d4c3da0cd721e4361c7454153788ec66f100000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 609000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91407a2bc41a410629bf3055f6c73b0fc32aad822ac88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "1514d862dac15a975ca8f24d0fe91c1207df6bcef84a33fbf34d61bdd193f0a0"}
+
+
+    tx_31a46ded = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "0e7a6d3b1db50702f878c7a4f7aee599055809dee3bf4fcae9dd7441d8e29742",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "0b468c6431c4fd5f20947e8377d1c2ff51e1b7a03e304d4a4ac038a2e066a8b4",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402204d93087c767244e82ec398dc450c9636c512d99c2f3a33314331a605374a29d502204b5eeae6322f14d38840cf259042e84796dd53386a1a4c0f714c6c27df8b1434014104ad842f4c519ab01398842706a255d91d707e55ec367b388ed6dcbffea6f4221b327150e5797f62ada089bbbda2f1d4ceeccf84af810d158d6a829054827f8830",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 20000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"},
+                             TxOutput{_txOutValue = 30000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914034cc996b2274be3869ea34b3367db543cef396888ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "0e7a6d3b1db50702f878c7a4f7aee599055809dee3bf4fcae9dd7441d8e29742"},
+                       rawScriptFromString
+                         "4930450220500b771d7750d8c27009f4e5544f16298cf9b8d9398634428d0b28712ed08206022100a57a1a51b5bdd72a867b4c59a4b8d53270965a543b0c815a1ba73dcbe4a7c427000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 20000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "5d998482db63386ed1d5e5162341cf4c4d66600530b4bb6bb379ae2ded6da431"}
+
+
+    tx_9183e7b3 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "fa253ace4be5a4acde8a6c5e6adc808de965e09f16fc5b65b7cb58f961b87e68",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "d7161e20fde5d5c3fd2a050ed5ca4b5099630135e253e8c0347ca2e8516a7967",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493045022100eccb0785c18ecd405d37cd0369f7cdadf62c1c5afd8c2fb4a7748c20e3073c3802203f7b1e36de55b38abb4badf71679171c7fada67587dba7f5017f684a840d1c150001410430ed754f2ab8ef5ac46e4622a0e9e79922457fc62e3d2c3c8abccf3fe123ed338fa39be3695ebeafbb6dbd4cb94f81a8b0b738e09bf146af03d4d30135ef3c43",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 10000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914ed2533122ffd7f0724c424599206ccb23e89d6f788ac"},
+                             TxOutput{_txOutValue = 10000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9146780e620b8e29804855dbbb6e604f5e38621feed88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "fa253ace4be5a4acde8a6c5e6adc808de965e09f16fc5b65b7cb58f961b87e68"},
+                       rawScriptFromString
+                         "493044022069d10669c2b9a44ee6c2fd65472bcf1c5289139d86d78f0a7e89aee1a2f708bd02206f75efe6b265c4557f4531eec6d3a5605eb94361bf3613539d2ecfcdcb260f20000001410406fd69f31ae65d787abe3fcbc1984092b67f14e39c11b98f08fb95a59b4ef9d1f738b7daac59dd72e53b878a29dafee5f4d8b29ee1f903e8703f61577d4f2478"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "107b6d106c172eec43c3e00d9b67149a7166acc66bcf554a94d035f3011ae033",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "953560a343fa2148d5ec119c82aa3a602b757188f2325a988991c2d16b7b8c3d",
+                                     _txInPrevOutIdx = 42,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100898505820e878f9decc73a5ce680ec21a02638166e09a07319a410e51814151c0221008d6ac3f693e1e403fcf5633eca32bbd879ab98f02e5bee1f4ee08cafdd7b1ff101410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "50f5bb0cd700f7f84cc21b91da8c176e58254e1c68127632998ada5d3b770bad",
+                                     _txInPrevOutIdx = 22,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502210097db607d138210576c9a1ce64921b1ca22a245c69f45aed2e6a1682f7f4eb3ef022009a7a8c07487a4689d6ddea101fc1e015ba647b80eee9f30b6fb1c2498b009f101410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "f186bda534dfebd9f6c30b48651a30d89b16fe650981824ecd4719ff076609c7",
+                                     _txInPrevOutIdx = 42,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "4830450221009b1d1b2a4436b1a133678e05e60ee6be757949d5434b41e1bdf7efed11605cfe02207e07db43fdcbdc703b701dad0a30d54b1e791e4e80edfaa38f310072ada6521101410431740cc7170cc597693a91662f4dcf78b3130900cf5f62f0104ae7f3d17856cc0f75780c7cfebd6bcce571fa3c69f2796fd3a7ab7b223750ffed25dabf198e85",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1005004,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914d86f419df0ffa113e03f50ea4863b7fd29f1bf6d88ac"},
+                             TxOutput{_txOutValue = 30000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9146482d425dc43ff3890071f13c07c42236e50833888ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "107b6d106c172eec43c3e00d9b67149a7166acc66bcf554a94d035f3011ae033"},
+                       rawScriptFromString
+                         "49304402201884e4345c43f844fec8223f48d0ec469f00361a5108f9b80d67e34cee01c179022047afec73d1a46b81d9156566dcd4808c2646c0367cf094e8d0a61cbab5bb5bc10000014104650a9a1deb523f636379ec70c29b3e1e832e314dea0f791160f3dba628f4f509360e525318bf7892af9ffe2f585bf7b264aa31792744ec1885ce17f3b1ef50f3"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 40000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914ed2533122ffd7f0724c424599206ccb23e89d6f788ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "f7caea2ca2497a0834e6796ca153a231fe4fcfac5655d3f24e7cdafbb3e78391"}
+
+
+    tx_e04baa84 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "142ecc76b7eb80deadecf613bd6d0c6769ce7a037a4cadfc5c6e85a8ad285b2b",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "a618dc10b8a1f9d9a1469b3bb84fc17da86df2d51c27e2aa16fa130953840735",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100819bf0ac422d50a53f08059883a2d7c973d2c8bc5437d647fb0653891d68140902205f14e0bbebd9d59266ec0bc045ae55dd4005b2f10c85fa11d506a2eaf08a63b1014104d45e87999dbda5813f4a49f1771089e0734934076edd56a80b5db776f9adb26a8b04e9fe96ff4b68c83ff73ee5593673ccb2ac66cdca839fc3ede154ca60f007",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "67e758b27df26ad609f943b30e5bbb270d835b737c8b3df1a7944ba08df8b9a2",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100f9796d57e3bc3b1f9dfbcf3e9fbae693b870256148e80ee2ff45fc073b872b27022100ef98653cc48a873aa60c1bc59a3d162c304185786043360ce905d86c9e350f00014104d45e87999dbda5813f4a49f1771089e0734934076edd56a80b5db776f9adb26a8b04e9fe96ff4b68c83ff73ee5593673ccb2ac66cdca839fc3ede154ca60f007",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9149eb05b74b8dddc42616aaea22f394c811f2b03ae88ac"},
+                             TxOutput{_txOutValue = 50000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9146780e620b8e29804855dbbb6e604f5e38621feed88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "142ecc76b7eb80deadecf613bd6d0c6769ce7a037a4cadfc5c6e85a8ad285b2b"},
+                       rawScriptFromString
+                         "49304402200c0d2dc9c18728ebbd3241dc2b1c96fee8811a92bea50baf677cfb8862022407022056ea02f73c0bc3933ae916df568d7fee33b5a3a38e7cf088c36654c158895bd8000001410406fd69f31ae65d787abe3fcbc1984092b67f14e39c11b98f08fb95a59b4ef9d1f738b7daac59dd72e53b878a29dafee5f4d8b29ee1f903e8703f61577d4f2478"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 29950000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914ed2533122ffd7f0724c424599206ccb23e89d6f788ac"},
+            TxOutput{_txOutValue = 20000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914366d23e8a4d8eec194fc5aed4809baea16d1cf1288ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "44eaf9d33e0afff32102bd9c68e4cbe510ae894135c253fd7ab1b31b84aa4be0"}
+
+
+    tx_604c747a = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "44eaf9d33e0afff32102bd9c68e4cbe510ae894135c253fd7ab1b31b84aa4be0",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "142ecc76b7eb80deadecf613bd6d0c6769ce7a037a4cadfc5c6e85a8ad285b2b",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "49304402200c0d2dc9c18728ebbd3241dc2b1c96fee8811a92bea50baf677cfb8862022407022056ea02f73c0bc3933ae916df568d7fee33b5a3a38e7cf088c36654c158895bd8000001410406fd69f31ae65d787abe3fcbc1984092b67f14e39c11b98f08fb95a59b4ef9d1f738b7daac59dd72e53b878a29dafee5f4d8b29ee1f903e8703f61577d4f2478",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 29950000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914ed2533122ffd7f0724c424599206ccb23e89d6f788ac"},
+                             TxOutput{_txOutValue = 20000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914366d23e8a4d8eec194fc5aed4809baea16d1cf1288ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "44eaf9d33e0afff32102bd9c68e4cbe510ae894135c253fd7ab1b31b84aa4be0"},
+                       rawScriptFromString
+                         "493045022075a7269ad5506a755ca2ccb586fbf4bcf4177546f0ba58aa65051a8efe840b43022100d99c68e841e9a495ada20d0c7f870b3388d724d3be5b0ada5768d75f62179fc600014104487e33b0220a1c5e07ee58eea30b495af1a3fcc792426be1d438a3fcb2b15975e2daba3ab003f92a341a0ce8f9f8631100ad518900deeeeda218d6214573ef70"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 20000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914ed2533122ffd7f0724c424599206ccb23e89d6f788ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "5d2bea10e0c490d9d2a22fd06afe0bbde9cb7992ce71795deb3ea55d7a744c60"}
+
+
+    tx_ebfa4562 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "ef6320d8d6526ce725dcc571e663a3fa0c56892e57b81596d255c427e978a5a9",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "243764be1475ed8a835d97c4d2c432e963641a03888955ec7fe1dbd513a718c7",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100ff5423db95f904d56ed6ed3c24bf702827d1ca37ce0eab434a86cc8e9755912402210080d493ee6f68869ce40f817a61df40423dd330eeb2dd369dbeae7b9f9d99b2de0141046858c3c7650e08d46f176ef7b4f6349b96170297bdba628df212940652f9205523548e82dc334d9114bbd8d8c1573aefc3c375b26fd41ce0b0b3e088b6fefc34",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1966600000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a91486d3a2725708a306599b7882192bd7e5b948864588ac"},
+                             TxOutput{_txOutValue = 111000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "ef6320d8d6526ce725dcc571e663a3fa0c56892e57b81596d255c427e978a5a9"},
+                       rawScriptFromString
+                         "4930450220592094e2a695e11d15f5df67e904b4d3ae0ab47ffa683f47523639ea87fc8f6a022100becbb1e41e308c772485bc1dc9ab636872775130f500a2ceda4e342745334512000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "f0d87a5e3aeb9323a77734ef681041ec790d728ac7a2f2e2b47cd66c0d57d2eb",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "9b780a438631841f6f531ade459325f074a950d2512be1c42bbeebdbcd4d736c",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "49304602210083f579b1014becd31b6e46d5bf5a9deebef8b03e9d905610f4bff305a285c60e0221009cf42cb4cd01da8c5571023365a20db512d709ed65bf07a7b8e4b4914a80040901410442134b142182118036b5ad0e92cf22adafb77b7b58a69f164509ee8d5649c6ce74953a6c8dbe8c41d362a31e1d2dc0a0b22206c8b2ebd88fc1868c21a1752483",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 4679000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914509211cc2aa109e14e935682e4365a75b6af10c288ac"},
+                             TxOutput{_txOutValue = 102000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "f0d87a5e3aeb9323a77734ef681041ec790d728ac7a2f2e2b47cd66c0d57d2eb"},
+                       rawScriptFromString
+                         "49304502210090e7ccf541d80ff2391770b0e55e7e8e7f1bf93391465d3a5452241e4bc7c32102207154d3b9c9acd3833a5fb73e2139398cd4961411148aae4681031570e3ddbf34000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "1d88d2da685244eaeb15a9f2fee7f138e707c9ec3d3a5e6b4aa1e18782d3246f",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "7b4b954187d67cfa3ababdc9290fc6532ff6ba746c936ed09951583f8a2e1498",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502210090f343095f72989c67a2805d39ac588a59d260a19a331203f27c9828e2a94a6802202bec6f44d079fa13844a4bdef7c7ba433fb7992f6089c5e6d4a2e663527a3562014104320f45acdf7fdff17db0e7bd7a1d60a74800a39123f787759f5f13f1d5d80961a957e8635cf183dca06e7caff95fb212f13dd3a461c15fc2fb7f3702692b1b91",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 829000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914959994a5dd96e8106bf95b52b8f3fd1b659f406f88ac"},
+                             TxOutput{_txOutValue = 100000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "1d88d2da685244eaeb15a9f2fee7f138e707c9ec3d3a5e6b4aa1e18782d3246f"},
+                       rawScriptFromString
+                         "49304502207228a087f90ba0837d4ec772c3ec75d16af0dd83c43a7a69300a2c451b8e46b1022100dfb13618538ae3c175d75196afd58b267eb34fbb992f040727027aaa04444c97000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "b8e2762a53932a03f4391fb8dbad8b6c569b3e6906cb0b1388fae467d3a62576",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "c8f683cd83f9588411d6be8e5dcd76b73b098ccaf91de07806c0a36a5218ef76",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100ecb2befc7136fe7136c8560ee5169e80e70ecf0e41708cd7fbca81f342c81dd002206b082be9cf05b10a48bed8de0b7a7ec143dc96268bae05c170f1a7050f9a82ac01410486813aa6043da060efb73832d98842c05dcde860ea261b5736698d4b3ffb105dd5a161b10aa42ed80ea8c5ffd17f2e51c9d5701f5ee0d889efcfd93ee3806f20",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 4476000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914fcf176ad6b1bc51d84952186f5c7999ac17f3c1d88ac"},
+                             TxOutput{_txOutValue = 103000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "b8e2762a53932a03f4391fb8dbad8b6c569b3e6906cb0b1388fae467d3a62576"},
+                       rawScriptFromString
+                         "493045022042a32d7a600f34c8d50adee2949eee6945ca84ebb3c7382d5917c4786869194e022100fa96b92d1d02354f3874bf30c0419378c2f0e2b12149ea00a8af2e55e87efd27000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "5d998482db63386ed1d5e5162341cf4c4d66600530b4bb6bb379ae2ded6da431",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "0e7a6d3b1db50702f878c7a4f7aee599055809dee3bf4fcae9dd7441d8e29742",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "4930450220500b771d7750d8c27009f4e5544f16298cf9b8d9398634428d0b28712ed08206022100a57a1a51b5bdd72a867b4c59a4b8d53270965a543b0c815a1ba73dcbe4a7c427000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 20000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "5d998482db63386ed1d5e5162341cf4c4d66600530b4bb6bb379ae2ded6da431"},
+                       rawScriptFromString
+                         "493044022072fcdbdda8f114cc9a2f3dacea580c5bbd7d9c0d0a9f0f11fe03055e79632f0f02205889578897993e42a9322514c34903838e9a45d39776a38178d263b8b84d38fe00000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "fc807e3afe8537c14985564b43daa7c91cc1c7763718e1fb6ec97f445889ecf2",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "193057432eb62013cf5340a4c9840c442dc387b944825a8f4ca9e6634204a87b",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022018a93b89749c1a585f1bba44bbac07baab067e06e8e85f2b6c74cf58b6c0dfca02210091ab2f613993566a47892e42aeb3b72ab0837a015538c4a731d59ed5a6c1e5a9014104dc0e0fb8fe0abed31501181387cbc0a5077742b83f3daf9b5d50108737b77ededa9af2e96a6d8af8bb34e9614743138f1b499e05059dc58792fb852cca9fd917",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1459700000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914da011bd8a24d8f05bc03b2eab13dafcabea7094788ac"},
+                             TxOutput{_txOutValue = 101000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "fc807e3afe8537c14985564b43daa7c91cc1c7763718e1fb6ec97f445889ecf2"},
+                       rawScriptFromString
+                         "493045022100b654d9f6b4dd6f61efc2b5cb60317163edd657c4c3271ffbfa70c4114d7e037202207d2898b8b6de69a8dddd16ce273c0a6b838a98b62d1131bf0c65b26876a7f651000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 537000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91407a2bc41a410629bf3055f6c73b0fc32aad822ac88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "b0da453243e44774165c58e2c0dc015523a0b026e8de6a0268c414526245faeb"}
+
+
+    tx_091f8607 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "e1fa331402e0300103a3ef146c36c8a335690276119cd875e0d19aeefdb8fdd2",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "b53634d338243b9594edafdb2eef5b6bbf7f962e23a3a80b595dae5b563fe193",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502206f084949a9799d0745a360512688125aed79d8e1fe92edc4365712b18b07fd5a022100addbddcb9d7dddfa1a43587d2e626412687ad15423171c55b08920658e0c77f901410401f9e29ee22afdc9da35cca2f8c6dc2872bafe6574e7264265f2bd479c76e96116e3faa136115322bf90863460b3437618566a82683df4a17f5ab5b006f0c767",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 4680000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914141be5d84d2dc5224c17f4abc1072f3e26e18f6988ac"},
+                             TxOutput{_txOutValue = 107000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "e1fa331402e0300103a3ef146c36c8a335690276119cd875e0d19aeefdb8fdd2"},
+                       rawScriptFromString
+                         "493046022100ef93d10c4e96163294b1f7a0fa6aa43e663ae0ef67fc7a28bb013990f7e67a82022100f33c6819559ad2798b84f532e10c9e6cd4c4f48429dc770b0b68ff437e31a99b0141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "b9d980377586cd6ea08f77c8a4a271e7c8e13b14ba491c716c6e9e99b6a4efea",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "6d7b8e19fa99be1297eb51c076ac74b6799ac0db1f2a7f21e9e204ae271aaf9f",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022027854976957927f55ea4b5ccf3e7c067451a8ca1f3f4a7c5303d185393a421a5022100a152a811fd72fceccb211d6c615836baf76e7478b5e95d9221dedaad504ca8a4014104d15a93cd6b9f85342e37a9ef97d9b9f014fb7b31d535501d0dea9f472332e62bc892dd267ed11517ba02f3766a2f2f4594c2454d425d8f5c11d95ecd32a3cc2b",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 3528400000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914172d73f7280673284d0c792e08d133c635a4796188ac"},
+                             TxOutput{_txOutValue = 105000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "b9d980377586cd6ea08f77c8a4a271e7c8e13b14ba491c716c6e9e99b6a4efea"},
+                       rawScriptFromString
+                         "493045022057a44f21fd2d0ef10fd61c6d55ed00bbd219a92e93d3b836b9a47d2233d68c3f022100cbe4e7d43f1b9b88faeb0a4c54f7e99132f316ea6ddb5bbf6bd54c67145c3c34000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "3817470b9dda6b351bdfd359fbb942a44bac813d3700f6131f95aff79847c950",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "0bd1a86d5bde99cdfe76688ef429a332e6570baaf823fcc21c90c573df7cede4",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502200153c83886cb49498d8f492783ab6c8a64454cf58e92bb9f01601cc534a194ae022100d43ee30c43de297b473a4aec9beeacb703abc62e68ca86ded67f57640f1ed271014104a4ca069784ba620949dd951a73334902532b44ff39114a4bf167f2a35ff41ad4550835caaabe1eabd2db51e13bfd46cee79bb663a0d4dd23cad01f25f2613615",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 4793950000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9144c952d87fdacb3efd71a77fff0b5bffbae55b41d88ac"},
+                             TxOutput{_txOutValue = 106000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "3817470b9dda6b351bdfd359fbb942a44bac813d3700f6131f95aff79847c950"},
+                       rawScriptFromString
+                         "493045022031b043ed0f2ea3527559f894a0194c441437ff64194c3241c4701c3d5728651a022100a936f61e5edc299161d219f17dbd81633a71f6915028e283c9d4c01203522e52000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 318000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91407a2bc41a410629bf3055f6c73b0fc32aad822ac88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "9e6b3f44fd66736c9cf21f74a5aaf83f2a7a55157754e90a7b98367107861f09"}
+
+
+    tx_94bccdc5 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "93410afe4caa118778129c7c47ff9dc62aa3fe0ba780730558ed933d3dcc3f73",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "124170dc17331e3b91727ff6d12d6477fe0aa27892b4860c30fa06916e7ac464",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402207caaa9f8b0c54320e18848ec0b38881b34820fca2e11e001c9e1521a3980928c0220296a40d49f2f8b6efd67560966ac9464c42f2d86aaeda7df278907c2ed732526014104822b31052b011b375ecfc9c02ad7775c271cde778cb2c159af4e8cbbee9879375012502f4aecd651105e7b1f54512cfd74efb5fde154a422e4a53ea6a710cfab",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 17391000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a91409999cd6449662dfc0445f66274eca425637049b88ac"},
+                             TxOutput{_txOutValue = 800000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9143094a64bfbd6b4d4b00616e8ddea4357cef046e888ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "93410afe4caa118778129c7c47ff9dc62aa3fe0ba780730558ed933d3dcc3f73"},
+                       rawScriptFromString
+                         "4c7b304502210099d6f5897eec6f2c4aeb3ccb43dc19f45f4a43372fd68a9e835bec463159e6620220365d554d87d656907af6a9c98768900c7e8cfbd3352d108c48d383cd6b08f6a02a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a014104bfe59667e7c6cae6dd44d8ed646c49a38186189cf4a84cbb6b563fa914d1549b4d1cad016dba65b06e154e1e6470af96d461931430355f6c0632ac8da5d5f026"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 30000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914f40b83ea6101795594e18532354cd57f824bb08388ac"},
+            TxOutput{_txOutValue = 770000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914f5be45a3b4988c4722a4a4086b44b436d640562388ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "23befff6eea3dded0e34574af65c266c9398e7d7d9d07022bf1cd526c5cdbc94"}
+
+
+    tx_5d4bfd57 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "7ee8db476fb0a606342894be732371d27c30e5fcf608648d0a3bfdfe2e971e2c",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "c82611d8caf383e3fafd22a94cea365a3a39d8649502f7385b48f38faf5457bc",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402206b467bbb7913ded004a76fbc8a7939f54acaac906e14e5d2f1a32e13b1acd5c50220238102e9f8a5b5e80370cdcdf30d790fa1cdca7e0e44ea15e3bcc0ff717c52aa014104f5cbd2a15a18a16de7b58f7948188f0a58b0272ee8ac94c9c2fbe2b40a1df9619fda8cfc2b756860b1180fc581d25454546d7cb36363bd57fbabd3d42451e4fb",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1639100000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a91441f45bc676c0e895e461ad91925e83ed5040210988ac"},
+                             TxOutput{_txOutValue = 108000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "7ee8db476fb0a606342894be732371d27c30e5fcf608648d0a3bfdfe2e971e2c"},
+                       rawScriptFromString
+                         "493045022100ed30336f7416e0631e4e7c80944dcebf0ece2916f42289d81ced9aa7a017a70602202f4c72f1f3dc749b3b04395b43328cb96d45f44ac78d2aea31e37b3772f61cfd000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "6b9579352579b10b17c1e3ccc7be80220592decd0c6f4da7d6611ac572643d57",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "fa5aaa915b7bf1cf7e5024bbb14c4af6d0c06bed16736113c31802bced802076",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502206267d09d04f9810f6a94d1cc3de6179889fe47473b4f307256edfd0664886dd7022100a02826e3ba893e9ca9a9b1a47cb75470219da5b65ff6cb32d653b9219b87728301410464edf34ced124b2d7bac27662cb49e29fbbccb47cdfc250d0c0774dce4937d5b0921f106e7ed63513be7844edf17ec0181ae490fd014b136601add707924726a",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1974950000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914f92d40956981e4968afc9d9cd755b117edd3392a88ac"},
+                             TxOutput{_txOutValue = 101000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "6b9579352579b10b17c1e3ccc7be80220592decd0c6f4da7d6611ac572643d57"},
+                       rawScriptFromString
+                         "493045022100d6413e381fde6a61c7c11d9dd36dcb14e5d14409301b70ba7e6b71d8e767f22c022041ba41e2a03f0f69760490de1d4ab7812f509dce16c642516b8c8bb1c00cc932000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 209000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91407a2bc41a410629bf3055f6c73b0fc32aad822ac88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "cdbfc6cd3b9a06c1d0449cecb90beaa03aaf88e55c3f150924c5d81f57fd4b5d"}
+
+
+    tx_bdc6230d = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "17240584a732a9e5f52a9bdabd2564117c4af36b659fda4def73a049db4213d7",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "8511749eb5b231b1a001a03424e6ecd4abb56116c4a4d220e1fd863d696495e6",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100a8ef023dc3bde77a2e129c7b6995bccf61406f0921e2a900f2404a66f702c726022100cc749a817a1fd4f2a34ab183fdc5808aa291d4ad601b55f9e8103ef27b45fbc9014104f83d42fbc7ef731d3fb71edfbb7873460213eca09e1bec98d913df447790b98f6974efdcc2b0b6fb89967023fac45dea4f9356f56d8c972d796b7755555e3ed6",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 2221350000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9147252727b63061be190a224a2f6cd9313930ee88c88ac"},
+                             TxOutput{_txOutValue = 103000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "17240584a732a9e5f52a9bdabd2564117c4af36b659fda4def73a049db4213d7"},
+                       rawScriptFromString
+                         "493045022100a6b39421a5af610aa67e5b6864ac755c91f4e68009c58edd285248329f0d3f510220332bfe7ea273dcffa28282dac06ddaf9eda17fefd5b699738f3204b75254414a000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 103000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91407a2bc41a410629bf3055f6c73b0fc32aad822ac88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "2b42ba68645d659b4868f32b9785c69115c5d06bacef26fb504e7dc40d23c6bd"}
+
+
+    tx_e3ba6bf1 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "917446e8d16aeb1402ea42b1f6af1a0c295447df3a4d8b1cc3245d4b23fa0554",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "d1e9fab307959a7c91f8a3008602da21e4e00a077577e34a7a81b6987ae79f1c",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502201f08c0b6bed12d359ae77ce6ffff3ea6bf661d51352b0ac1c30e9dda1409ea4e022100d6810ae25f3d63fa63487655bcf84bd916eaf783fc5f45cb0c321132920f13ae0141047812733c010f4f3ff41aaa20fffad25c085f1139e45ec7d29a0f0398262afd325a419911c209f4fafcc4afa58b81e4dd75aceff307ed19980e5d75eeb2a9a309",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1948500000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914a691b8089a7829f934a847f11a5137c91e8ef53c88ac"},
+                             TxOutput{_txOutValue = 121000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "917446e8d16aeb1402ea42b1f6af1a0c295447df3a4d8b1cc3245d4b23fa0554"},
+                       rawScriptFromString
+                         "49304402201dc5f9692b472b3383f86ef4dd7db6a3577ad58dee57104c35172ac0cedd46b302200bd6fb71ce91bfa9f626bf71324a6007c8bebc92433fee2fe48e8938b1c6909600000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "48f1ac1936de25270d1e3e35e2edf849509fe973c52c88447a92d479eac6979c",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "aff1644ed1675e54d5d0491c24259ebbc97d2791a2f6c1de18140679a9beb46e",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402206f81af43689d9af71e8fa2674d215611f6e4d14569f7a17be6c01988b6f7608202202928cc0bd062d590afae9470dbcaf8ef8506ba62af6ba51c4825dafb631c8e05014104823e757b4ef0be00c0f58f33f54b91a69bbd0b90ddc55d1649b93f07676324abe598c84edbb616134feaa65c21e6e18b5004f99b1126c42276dabed0cbf778c6",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 4586000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914e010cb78d29e1238d28c78dcfa9e16d1f795188188ac"},
+                             TxOutput{_txOutValue = 102000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "48f1ac1936de25270d1e3e35e2edf849509fe973c52c88447a92d479eac6979c"},
+                       rawScriptFromString
+                         "4930460221008d94fd7e87729e9bd61b08c7dd529850f798fbfa7db620a1ad6031e61b0c849c022100cce603da7ea742109834a38df1202afb5cbe8a9802c8a550e077874b1ba092420141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 223000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91407a2bc41a410629bf3055f6c73b0fc32aad822ac88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "bdc8af818b11a0ca0b2f3a61b1de5cc2ce7b7067b112ccb46857f713f16bbae3"}
+
+
+    tx_0b773101 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "67197f1178c44b3fa7ef6610b70836a8b04af0bea1d427db509f5f7068e3539e",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "a7632a1d2316c08b0fcea0e6344c4f83366b96a7e6507f064bb36576ce0d1ad9",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502203ab38d58c3bdb563aae2eb473f3a8f27a8867ef1f3274bccb91402fcec3a189e0221008fcc6232a3be6e6d318f8e5a4b03a020277c4cab5440afd7948fe9d21462ed950141048e8292b55f1f6bac5ac9bf1f3248778d13f654c0853030c372eeb2285bfb6cfebe1c9a4a0452d5e0659fab0ba2ea29c4c3fe262d8279973f8c8252fdb494ef7e",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 2064550000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9142315edf4844163b4deefd2131ac953a6ada81ce488ac"},
+                             TxOutput{_txOutValue = 102000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "67197f1178c44b3fa7ef6610b70836a8b04af0bea1d427db509f5f7068e3539e"},
+                       rawScriptFromString
+                         "49304502205d1d6cd5142d653191f35f79f8189003e872d9e0a989485dab9aebc226fe65a4022100aadaba6e50d418d7e13f1b40fabf56796b037ee14c9a15b58c9dc1055e09bc1c000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 102000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91407a2bc41a410629bf3055f6c73b0fc32aad822ac88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "389300df02f893990af44186a61da75ccf4ac2dcf93128ff413cb95c0131770b"}
+
+
+    tx_ceafe873 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "bed6395f6418a1583bd68f48aa0593dae6b47a765098dde25f4e955d6488b6fd",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "e6d403d46f7305df423192978763b62457d7ff8aebbe22b133b5bb8b52f4cb00",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402200ad59ee68ab7cccee7ea26815ab296364ae13fc9f38e7a6e94399a22c1e65b8702203dde6ca242748c8d51d4b30aa1940b6b70d449ea80cde7c6f2a5aff636ed9a3c0141045cb179a60883b27adf93c4509213ac267c1bcf4ffbe39856ff70f2d6be61c548e59c4ae5fb6c49c7c7191eb95c1dbebf8af4712448d5a1f069cf83ae5de5ac58",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 4744900000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9144c6fa7fbdcb3959010e6191e66904e39f815b0a988ac"},
+                             TxOutput{_txOutValue = 104000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "bed6395f6418a1583bd68f48aa0593dae6b47a765098dde25f4e955d6488b6fd"},
+                       rawScriptFromString
+                         "493046022100e66b38c011255bb133aada82914e682dca5ee169c215e31ae3603b5b54b862f8022100aff39a14e80be20dbc98ae3528a5e42f4a898f089102c7817ddc33602f2797650141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "d1e55fdf8b71ad4aecc5cc12840257d28e3b40c1ff9c6b2a7e2976deeb6611d2",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "5a65a7beb2c478d048c3eb18444ff9204f5f77a8fb3f5dbfb3f4e49b57f16b96",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100a6ac7e801d280eaf16339a078c33c7f712a0394e7ccecee306265c3bf60acc0c022100e221472d77ac1775268e4884e72eb5e5cc5b9c2b0951f1adc95ee9f92ef71063014104a4ca069784ba620949dd951a73334902532b44ff39114a4bf167f2a35ff41ad4550835caaabe1eabd2db51e13bfd46cee79bb663a0d4dd23cad01f25f2613615",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 4795950000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914ba1ca31dbab0e3870f4a263d2a4f0907f7b7bd2b88ac"},
+                             TxOutput{_txOutValue = 104000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "d1e55fdf8b71ad4aecc5cc12840257d28e3b40c1ff9c6b2a7e2976deeb6611d2"},
+                       rawScriptFromString
+                         "493046022100ff645e00619e1916d8cc7be33913108a0656194c45bd63cea132f12aa715edaa022100c75f64d96be527c3eddc7acac988cf3b1796c8c92e1918e71384dfb5c31ea0380141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "ea8dad09e629bab7f70959938603b387607b3dd0429a0354a06ba26db4662d5e",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "58ea922bda7baeb2eaf1e87770e02a553e95291f9d48aeea7a2394ed6cf15352",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100db7ac6a669cc3b7d23233b75dab4bbf9d5c19492f3cdd04d97edc0f0b71af85a022100a978c9edd7c2ba361dba5bccbda67bd169bb415ee9dcd13a2f0bc997477132fb0141042420ec3a32c7270c1ebee82876fdaf5995a6fa27b08f040e0274e79a8b7f7c4169141ef10aa79d14412cd0e3accef36064ca44809da324bb32a6115101b193d9",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 158850000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9143a0ff9a89e041243e08c922ec33fbe5b9f27394b88ac"},
+                             TxOutput{_txOutValue = 101000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145811cfd9bc24826c2ed456e14fbd79525387bc9d88ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "ea8dad09e629bab7f70959938603b387607b3dd0429a0354a06ba26db4662d5e"},
+                       rawScriptFromString
+                         "493045022025191f4eb012217583450e687dac1aded6a5b8c6fe9d9893d854eb2359f9debe022100fbd1fa96c1cb8a7fbe186fe52d080d8709bd2bc44143d1d02a5c4a14f1a098dd000141046bb99bb9e71205eb3e993db2274069eba9bac5627e546685aeb01a5acdefc3d704ebafa1a7bff71c8c2b480cc77ee29410d830e3a199546ef7be0a8861b49cf4"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 309000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91407a2bc41a410629bf3055f6c73b0fc32aad822ac88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "0f01472e25c7e6918f9ae36c6c0920e27d9cad1cab095ed7421f029773e8afce"}
+
+
+
+--------------------------------------------------------------------------------
+
+ Bitcoin/Test/TxCheck/TestNet3.hs view
@@ -0,0 +1,659 @@+
+-- | Some interesting (corner case) transactions from testnet3, together with their 
+-- previous transactions
+
+module Bitcoin.Test.TxCheck.TestNet3 where
+
+--------------------------------------------------------------------------------
+
+import Bitcoin.BlockChain.Tx
+import Bitcoin.Protocol
+
+--------------------------------------------------------------------------------
+
+some_testnet3_txs :: [ Tx (Tx RawScript RawScript, RawScript) RawScript ] 
+some_testnet3_txs = 
+
+    [ tx_d276a90b      -- note: these ids are the *last* 8 characters of the hash (written in BE as usual), in reverse order 
+    , tx_81d78c36      -- (i messed up, but it's not important so i'm leaving it as it is :)
+    , tx_e7e62a24
+    , tx_5ae6efb0
+    , tx_e1e1e1c1
+    , tx_21a22580
+    , tx_fc2e2bd9
+    , tx_fd5a626e
+    , tx_6b840973
+    , tx_84aeea31
+    , tx_d0d37b12
+    , tx_a825867d      
+    ]
+
+  where
+
+    tx_d276a90b = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "684d02b7766476fb7e9bfa63f6353dec5fff8f0d5cadadfb05b0768e5dcfb9c5",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "74ea059a63c7ebddaee6805e1560b15c937d99a9ee9745412cbc6d2a0a5f5305",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100c60678f073961429aed11d094f81ea7fdf7ca8fcf9740e9bd492dde43441a9ea022100f78e190f3894f114880c968e60f57f65c93f0ff948c2ebceedb33d6df3e66cff012103abac35cd4dbc714a65b28316527c925302fb2cf2bcdd0c4972c205b443dbd3b2",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 1788650000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914ef9825e91a283396438a88a88fa10da3d972acd188ac"},
+                             TxOutput{_txOutValue = 400000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914147a957a6a183db5c85c6f3ae3d21f158b66ac0388ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "684d02b7766476fb7e9bfa63f6353dec5fff8f0d5cadadfb05b0768e5dcfb9c5"},
+                       rawScriptFromString
+                         "493046022100b300f632d6f7109b4888638fdf3ba74e0102b6eabf220bcb4eb212c69a621eb1022100a1ed0a94c9b9253e645441ff96895d18568f2ec2014d35d470d7989b9b47e7c70141061285128c2063e6a670193f51d0050ea8d198f66c272a8c284985a4124a79dccaa92a7d9215c0cdef770a10241af93522848658f7fcfc29977f3462f6885f64e8"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 99950000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91421697b2358b62014db97788a995c9341b16d727b88ac"},
+            TxOutput{_txOutValue = 300000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9140fa575195351af1507607824b4817591b9ba8ae988ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "cb2710fca03b99502f81d50a40690f160079459f6b1d27aeb13bbaf70ba976d2"}
+
+
+    tx_81d78c36 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "2e131d48f58cbb358cc53967a2fb89a80a6da337cb430fd719f5888af7a48507",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "1d2e52f9916ad806a96d9a7ccd94494e3873a516483acb15a4d1d30623cec601",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100b5ab50db8119ccde0a6fc51837394358869f36bf8d00030f5d3b0153fd1b1cac02201e9bc491960157faf570e85722106e030631df4df2ef510bfa2c09b8e266b21f01210243203d811524ef8f3588e28b4f68b354322d317dca8c77da8a1c11d41a167a31",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 25000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "5121033d091990498104e71aa940771aa2b9946850591e6f4e3eac31d24078cdb20a4121000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2052ae"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "2e131d48f58cbb358cc53967a2fb89a80a6da337cb430fd719f5888af7a48507"},
+                       rawScriptFromString
+                         "004830450221009e3787c6d9d6c072093389ecf643975a122e7334b48880fa8c5e5be2473234dd0220041f3f0338f9db2ccde267ef25e7bad7b1e67bca84a837b419f3b501823e0a3b01"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 12500000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91417e0a7b539f7479ba80c8f40892ee514f723824388ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "bdefb2077a28d419425d8964f7d09eec89b334a258085f14ea60b71a368cd781"}
+
+
+    tx_e7e62a24 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "46f6c120965dec8151704d1a3b00fff5f58285dcc0cadea5bc8841b8b0a5197c",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "2cc4e5994d2244124035f502c6b89770eda8f622d2d7ad7da472e0369521d4d8",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "493046022100e17c17e406de953fee109993e982c11df7dd0a74be470f20cda256cbd47f02e9022100a94f19999223bd303127a33afd4b5f21cac608dcef845a2c709caf845364517b012102366665264a482107b204ddc3d0d730e13d838966c3e7675074bfbd6ebefeceff",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 100000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "6352210261411d0de63460bfed73cb871f868bc3064d1db2a09f27b2477852b1811a02ef210261411d0de63460bfed73cb871f868bc3064d1db2a09f27b2477852b1811a02ef52ae67a820080af0b0156c5dd12c820b2b1b4fbfa315d05ac5a0ea2f9a657d4c8881d0869f88a820080af0b0156c5dd12c820b2b1b4fbfa315d05ac5a0ea2f9a657d4c8881d0869f88210261411d0de63460bfed73cb871f868bc3064d1db2a09f27b2477852b1811a02efac68"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "46f6c120965dec8151704d1a3b00fff5f58285dcc0cadea5bc8841b8b0a5197c"},
+                       rawScriptFromString
+                         "0048304502207d02ce76875b1b3f2b7af9e45954af1ab531da6ab3edd471aa9148f139c8bad1022100f0f85fd987e90a131f2e311acdfe212925e218ffa5cf79e84e9890c2ddbdbd450148304502207d02ce76875b1b3f2b7af9e45954af1ab531da6ab3edd471aa9148f139c8bad1022100f0f85fd987e90a131f2e311acdfe212925e218ffa5cf79e84e9890c2ddbdbd450151"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 100000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a91403efb01790d098aef3752449a94a1dc593e527cd88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "4d0bbf6348726a49600171033e456548a09b246829d649e77b929caf242ae6e7"}
+
+
+    tx_5ae6efb0 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "4fed625bfe36c2d17d839a6407be374663ad823c2cde7073319bb51b8025a221",
+                    _txInPrevOutIdx = 1,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "c6498e51b170bb66d129a5eab51ead72c6fc7f35f36e78849875d7377a4be8b4",
+                                     _txInPrevOutIdx = 4,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "473044022023c374437ad0416763853830a2ae192f3bc4c49ffc251e0cabfe779ae2c3823c022071bfaa94518780ebf60f456569f8cdf2238577d4eaa1af0144047804778cbc500121032cf0450bb0013ab45b7feb67afe6313e47086b9c5bb13142c46bbb55dbc0d2cd",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 120000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "0130323066643366303435313438356531306633383837363437356630643265396130393739343332353534313766653139316438623963623230653430643863333030326431373463336539306366323433393231383761313037623634373337633937333135633932393264653431373731636565613062323563633534353732653302ae"},
+                             TxOutput{_txOutValue = 916990000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9145da359a8f618a3bef736ad51748a63a568b2e87188ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "4fed625bfe36c2d17d839a6407be374663ad823c2cde7073319bb51b8025a221"},
+                       rawScriptFromString
+                         "47304402200b2f1fd1ffa76514f6fcefd8d80c32a9d0be2b1117127eec831316ecba2ee72e022060b1a6fc82bebbea89d5108724029b956213968c25cbacd1186a83f689465f8c0121024872b6f9eeb8d8255be96d82f8c60885ef401e33a9a4ae680cb5148a8e491899"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 896980000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9146ab1d225f182cf669e7b27339ab133e3df93dc0b88ac"},
+            TxOutput{_txOutValue = 20000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "303230666433663034353134383565313066333838373634373566306432653961303937393433323535343137666531393164386239636232306534306438633330ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "69f319bc535f576fe2612ae5cae1477c606c3df771bf3f41bc9cfd2db0efe65a"}
+
+
+    tx_e1e1e1c1 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "cc5691f26713fdd9913390fddb2ef0b94b07ceaf7d6ecc8ea7bc20d5d92b2efc",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "a2bcedb144595b9b4d66272dc6927f3efaa251bc1af6f1df5ec599f341737b90",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100dfe55c79d56dfff12319bba3e48b09ba5255d15f9cbce4ea56e058fe820e33a202202cb9b1dcc9da346493aa60fda4170fd985daf920609719e9de647c63a93b5b4701210353b922941fa74bc9d192583041b3cfaadff4698cb1a5e31fbdcd06b63cb9bcdd",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 159980000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a9140345ac233f2115dfd3393c408f1ea79d7c5fe22888ac"},
+                             TxOutput{_txOutValue = 20000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "00783531213032306664336630343531343835653130663338383736343735663064326539613039373934333235353431376665313931643862396362323065343064386333302130326431373463336539306366323433393231383761313037623634373337633937333135633932393264653431373731636565613062323563633534353732653300783532aeac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "cc5691f26713fdd9913390fddb2ef0b94b07ceaf7d6ecc8ea7bc20d5d92b2efc"},
+                       rawScriptFromString
+                         "47304402200eb01c33a987bcf9e0c73e3f0325afaddef93a507541866c21125bab795ebb41022007b1d66a25ee16a5ba0033611a196a2532337fb506723bd9166fb545d2b3c1c80121022ef94776731427c07ae880d91206a9fcf3498b374ed9cc1e9f83b092ee02c372"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 20000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "51213032306664336630343531343835653130663338383736343735663064326539613039373934333235353431376665313931643862396362323065343064386333302130326431373463336539306366323433393231383761313037623634373337633937333135633932393264653431373731636565613062323563633534353732653352aeac"},
+            TxOutput{_txOutValue = 139970000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a914d540dac6f87b99bd9c69c75e2d23553b4946ba4e88ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "8e1ae606adfbd418874e151532d2f6a6160fab407f70ef9af2f2d593c1e1e1e1"}
+
+
+    tx_21a22580 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "c6498e51b170bb66d129a5eab51ead72c6fc7f35f36e78849875d7377a4be8b4",
+                    _txInPrevOutIdx = 4,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "18951a28f634decb404913045886b7f2c307d8fca7259ac5fa0d468bda9879f7",
+                                     _txInPrevOutIdx = 3,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402205ef3c3153be784f65503a47ef7f82a206a959ba2b468b99462a3b065a691fe710220386e1968ed208749c034583273707bd85e10f85bd06101fabead9a850e2ecdfa0121022a42b63c530a07d1a3c40c0f2f04db32fc344133c7fe433066e0970f8de5fec7",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 41000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914f1c14050fd77c1e50e2237f2caa985510aa3f43a88ac"},
+                             TxOutput{_txOutValue = 45000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914789fc2b709c4ca027d7dd19b10f9af349d73759288ac"},
+                             TxOutput{_txOutValue = 49000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a91496d3ab2cd639e9a2f925bd5b28c4b73676b91a5488ac"},
+                             TxOutput{_txOutValue = 55000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914789fc2b709c4ca027d7dd19b10f9af349d73759288ac"},
+                             TxOutput{_txOutValue = 1036990000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a91467ce23788087a8b827828a7a656681f9e5d6cb4188ac"},
+                             TxOutput{_txOutValue = 59000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a91496d3ab2cd639e9a2f925bd5b28c4b73676b91a5488ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "c6498e51b170bb66d129a5eab51ead72c6fc7f35f36e78849875d7377a4be8b4"},
+                       rawScriptFromString
+                         "473044022023c374437ad0416763853830a2ae192f3bc4c49ffc251e0cabfe779ae2c3823c022071bfaa94518780ebf60f456569f8cdf2238577d4eaa1af0144047804778cbc500121032cf0450bb0013ab45b7feb67afe6313e47086b9c5bb13142c46bbb55dbc0d2cd"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 120000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "0130323066643366303435313438356531306633383837363437356630643265396130393739343332353534313766653139316438623963623230653430643863333030326431373463336539306366323433393231383761313037623634373337633937333135633932393264653431373731636565613062323563633534353732653302ae"},
+            TxOutput{_txOutValue = 916990000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9145da359a8f618a3bef736ad51748a63a568b2e87188ac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "4fed625bfe36c2d17d839a6407be374663ad823c2cde7073319bb51b8025a221"}
+
+
+    tx_fc2e2bd9 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "a2bcedb144595b9b4d66272dc6927f3efaa251bc1af6f1df5ec599f341737b90",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "426fcd8e05ceef79a11f0af6f92e3a3415608ae314f1c4491a17190809dc5de1",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100d61262bd05042f074a6f1353a3e6d7791bdb04564598de31f64e6ca54ffd9573022019cec5e57d9e05a46a239632fb5cb8348eb48bd221515af284d972ff22c2a17f01210369e66687279fe6a4495b90b582ea24e2a80832938d796aa613c1f841060beecb",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 179990000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "76a914f4348d78d3488134665fab624776f9dc2063bafc88ac"},
+                             TxOutput{_txOutValue = 20000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "a914c694b8e6c34d5f0e80923e802a828de60a91d9de87"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "a2bcedb144595b9b4d66272dc6927f3efaa251bc1af6f1df5ec599f341737b90"},
+                       rawScriptFromString
+                         "483045022100dfe55c79d56dfff12319bba3e48b09ba5255d15f9cbce4ea56e058fe820e33a202202cb9b1dcc9da346493aa60fda4170fd985daf920609719e9de647c63a93b5b4701210353b922941fa74bc9d192583041b3cfaadff4698cb1a5e31fbdcd06b63cb9bcdd"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 159980000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "76a9140345ac233f2115dfd3393c408f1ea79d7c5fe22888ac"},
+            TxOutput{_txOutValue = 20000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "00783531213032306664336630343531343835653130663338383736343735663064326539613039373934333235353431376665313931643862396362323065343064386333302130326431373463336539306366323433393231383761313037623634373337633937333135633932393264653431373731636565613062323563633534353732653300783532aeac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "cc5691f26713fdd9913390fddb2ef0b94b07ceaf7d6ecc8ea7bc20d5d92b2efc"}
+
+
+    tx_fd5a626e = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "9df6bb44a582c0ab7b5b0bcf2fc8aa35eafe317b0d31dde3275c520f127bd3d0",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "2eac8420136633b93d74d87404e245e5ace80f6cb32024a2710cafabd68844e2",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402202f8d23cc52edac158e0ab8d57f0cad8dc2d2d62df67715a2b04e31cc5a32dabb022004dfc14a30b36decaa65da04eab9ee40c70a8eacdbc38f61600d68b072bad90001",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "0cdb223332975268f3a3e49461cf87654b355c88aae2d870bcc7ce643156be5f",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402203ec301ecb4d2c3ba3844b1e2197813ebb09516953dc9dbe654efb5aa4bbb3fa402201968be259975651609fe7366a14583f1a8acfc8ab918def369986dcb0d6f58f201201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 200000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "210333b572abbbd55e520833043492c496495b8794e0c9f2b50bccb1f7edd8bef8caac7c2103504413c2e4873548c4112988134cd633062e7e634549e3ed50fa4eb7bae81110ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a635379825379828779679a68"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "9df6bb44a582c0ab7b5b0bcf2fc8aa35eafe317b0d31dde3275c520f127bd3d0"},
+                       rawScriptFromString
+                         "20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f4730440220797afb2e2258ffc9681f353f410086ea331c58522d52bcabb0a8dcf800ab9e7f02202f22577bd839d905b8659d0bf248e81f0824d3974d4e63af22aeed31b36c18bd0100"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 100000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "21036ef62794066933b0790a59275ac5701bcd018b94d19df86a15bbd6df7c272c1dac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "19c0933970d3e516edfa3c961372b051f65c35eafb1fd7f14b0e1d486e625afd"}
+
+
+    tx_6b840973 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "3d33ab23b1f67e55ade4cddbaec642c3f6b2d8c6bf948e82dd2294b87d8625a8",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "35a2bd68babbea5d87a3c209076195a2c3d3d32aac06035ac90f62a74e9b3dd9",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100a6b83e0b4e21b5abebbf990b9933111927adfab94153a3c569646d934c562d31022042a2cd2842ad2a1263ea520093ceb8b4a90974955eeb9ee6ded97b9f13e9239c01",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "204c22154affccff4a5d53e85af0ef6f80788a732004adf0ba3c3c38c9365b4a",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "48304502210080b82a63b0c034f51b1841e27715878d26a2cab9edad489622df3ddf4a91409202203ba95f4b7e76b0ee091082864593b67f70ef7ec82645dea8b5a3f85e08453be501201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 19700000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "210333b572abbbd55e520833043492c496495b8794e0c9f2b50bccb1f7edd8bef8caac7c2103504413c2e4873548c4112988134cd633062e7e634549e3ed50fa4eb7bae81110ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a635379825379828779679a68"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "3d33ab23b1f67e55ade4cddbaec642c3f6b2d8c6bf948e82dd2294b87d8625a8"},
+                       rawScriptFromString
+                         "20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100849d542d29108ed748f57f6cf072668626755ca7d0150602c2f55cc350aee2d50220354f1ca87561e7b17a47eed221d25712f1038c22f38fcdaae5343d0b6e3bf09e0100"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 19600000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "21036ef62794066933b0790a59275ac5701bcd018b94d19df86a15bbd6df7c272c1dac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "bca9d833f529caa530cf6114d9c57b12e213487416e14091e95c62667309846b"}
+
+
+    tx_84aeea31 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "99b8b9962f25e246eb0a767ed60be7e4d5a9eff74c2479db8727ad2ce4c43c68",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "97b444c615877f7e64c1bb159c241afaacfedf458b08cc0a9ec8e514bbf33f16",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "473044022014908a4cf2cac6b8a143f26b26b38c0cb0885cb7b3db6c3e53c4608fd2657f050220388c960657f3bc6f8bdd7db8f4dd7321e72c3b5f05525fe505232624ee1111b801",
+                                     _txInSeqNo = 4294967295},
+                             TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "639e9e6fd8f1b03ccbe9302f2a74fa523fd2b2ea4cc1d7f94ab8205aae88208e",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100d3c77597af64cb514ec3a3b49c2838922863a910cd7751a8f4dc0b190324c598022011a4155e7e11873dc668c7e9a568f910586f8435d5d69e11273d4555a17a7f1c01201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 199987712,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "210333b572abbbd55e520833043492c496495b8794e0c9f2b50bccb1f7edd8bef8caac7c2103504413c2e4873548c4112988134cd633062e7e634549e3ed50fa4eb7bae81110ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "99b8b9962f25e246eb0a767ed60be7e4d5a9eff74c2479db8727ad2ce4c43c68"},
+                       rawScriptFromString
+                         "20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100d485c55bda525687f66ce22e54f2b37fbe0061e6bf0e405c02f679c920d4783202202cd8fcfd829b9e33dccaa1e2022853e8f34b4db4247833a02a473b40e1d12b3d0100"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 199983616,
+                     _txOutScript =
+                       rawScriptFromString
+                         "21036ef62794066933b0790a59275ac5701bcd018b94d19df86a15bbd6df7c272c1dac"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "cdb1f5870375adcbe2ea26fa00b06b5638843cfc00859d63d54c9e3c31eaae84"}
+
+
+    tx_d0d37b12 = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "2eac8420136633b93d74d87404e245e5ace80f6cb32024a2710cafabd68844e2",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "376fa876330c1e647f2eb3c9265040e44ab849b32888c4613424210b8fcb7d21",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "4730440220111d29b2168e0473b99a8cc1b01a8fffb5fd314ab2127b0a7ab42045ca1b159b02201d4970d6c0bc897110589185e4a8f43c5f2101c72e26bf21ce9c0684425d47d30121036ef62794066933b0790a59275ac5701bcd018b94d19df86a15bbd6df7c272c1d",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 100000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "2103504413c2e4873548c4112988134cd633062e7e634549e3ed50fa4eb7bae81110ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "2eac8420136633b93d74d87404e245e5ace80f6cb32024a2710cafabd68844e2"},
+                       rawScriptFromString
+                         "47304402202f8d23cc52edac158e0ab8d57f0cad8dc2d2d62df67715a2b04e31cc5a32dabb022004dfc14a30b36decaa65da04eab9ee40c70a8eacdbc38f61600d68b072bad90001"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "0cdb223332975268f3a3e49461cf87654b355c88aae2d870bcc7ce643156be5f",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "7573354a6facb91ff7510e6d975fd1b1347b35bdf53f3d5b95c56c0370936314",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "47304402207a6e5856219564b2c529d8b2ddc1026ce691c924750051c22b79aecd4afea2f002207fea340579adc47fa68193b940b44ba07d7ac62313df49fd38c50b1968043f45012103658f6f842e46eddf36d47a91f285e37f56540878bdb56045275b661832a56c0b",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 100000000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc55322688210333b572abbbd55e520833043492c496495b8794e0c9f2b50bccb1f7edd8bef8caac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "0cdb223332975268f3a3e49461cf87654b355c88aae2d870bcc7ce643156be5f"},
+                       rawScriptFromString
+                         "47304402203ec301ecb4d2c3ba3844b1e2197813ebb09516953dc9dbe654efb5aa4bbb3fa402201968be259975651609fe7366a14583f1a8acfc8ab918def369986dcb0d6f58f201201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 200000000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "210333b572abbbd55e520833043492c496495b8794e0c9f2b50bccb1f7edd8bef8caac7c2103504413c2e4873548c4112988134cd633062e7e634549e3ed50fa4eb7bae81110ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a635379825379828779679a68"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "9df6bb44a582c0ab7b5b0bcf2fc8aa35eafe317b0d31dde3275c520f127bd3d0"}
+
+
+    tx_a825867d = 
+      Tx{_txVersion = 1,
+         _txInputs =
+           [TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "35a2bd68babbea5d87a3c209076195a2c3d3d32aac06035ac90f62a74e9b3dd9",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "10b7d0506e41f72baa3801309f4835272968ee5db945cf7c76ed7be8d5796d4a",
+                                     _txInPrevOutIdx = 0,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "483045022100f6f9cd3681346597f5f7f4aa0191e5c93bfc0eb0968c57a2467f844f0393aff60220775385490d4600ed102cb2536bf445dc7580424ce59b4b0a87ae41de6d0c73050121036ef62794066933b0790a59275ac5701bcd018b94d19df86a15bbd6df7c272c1d",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 9900000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "2103504413c2e4873548c4112988134cd633062e7e634549e3ed50fa4eb7bae81110ac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "35a2bd68babbea5d87a3c209076195a2c3d3d32aac06035ac90f62a74e9b3dd9"},
+                       rawScriptFromString
+                         "483045022100a6b83e0b4e21b5abebbf990b9933111927adfab94153a3c569646d934c562d31022042a2cd2842ad2a1263ea520093ceb8b4a90974955eeb9ee6ded97b9f13e9239c01"),
+                    _txInSeqNo = 4294967295},
+            TxInput{_txInPrevOutHash =
+                      hash256FromTextBE
+                        "204c22154affccff4a5d53e85af0ef6f80788a732004adf0ba3c3c38c9365b4a",
+                    _txInPrevOutIdx = 0,
+                    _txInScript =
+                      (Tx{_txVersion = 1,
+                          _txInputs =
+                            [TxInput{_txInPrevOutHash =
+                                       hash256FromTextBE
+                                         "10b7d0506e41f72baa3801309f4835272968ee5db945cf7c76ed7be8d5796d4a",
+                                     _txInPrevOutIdx = 1,
+                                     _txInScript =
+                                       rawScriptFromString
+                                         "4730440220398d0c625c26acd9a0b8813aa91df606e1ea3d0b5751e33919383e9c9a9c4b3a0220027ec216c07f087e37b97c2c3fb41ce0f473d51f7f24486477e799c0c833096a012103658f6f842e46eddf36d47a91f285e37f56540878bdb56045275b661832a56c0b",
+                                     _txInSeqNo = 4294967295}],
+                          _txOutputs =
+                            [TxOutput{_txOutValue = 9900000,
+                                      _txOutScript =
+                                        rawScriptFromString
+                                          "a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc55322688210333b572abbbd55e520833043492c496495b8794e0c9f2b50bccb1f7edd8bef8caac"}],
+                          _txLockTime = LockImmed,
+                          _txHash =
+                            hash256FromTextBE
+                              "204c22154affccff4a5d53e85af0ef6f80788a732004adf0ba3c3c38c9365b4a"},
+                       rawScriptFromString
+                         "48304502210080b82a63b0c034f51b1841e27715878d26a2cab9edad489622df3ddf4a91409202203ba95f4b7e76b0ee091082864593b67f70ef7ec82645dea8b5a3f85e08453be501201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f"),
+                    _txInSeqNo = 4294967295}],
+         _txOutputs =
+           [TxOutput{_txOutValue = 19700000,
+                     _txOutScript =
+                       rawScriptFromString
+                         "210333b572abbbd55e520833043492c496495b8794e0c9f2b50bccb1f7edd8bef8caac7c2103504413c2e4873548c4112988134cd633062e7e634549e3ed50fa4eb7bae81110ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a635379825379828779679a68"}],
+         _txLockTime = LockImmed,
+         _txHash =
+           hash256FromTextBE
+             "3d33ab23b1f67e55ade4cddbaec642c3f6b2d8c6bf948e82dd2294b87d8625a8"}
+
+--------------------------------------------------------------------------------
+
+ Bitcoin/TestSuite.hs view
@@ -0,0 +1,51 @@++-- | Test-suite using Tasty.++module Main where++--------------------------------------------------------------------------------++import Test.Tasty+import Test.Tasty.QuickCheck+  +import Bitcoin.Test.Crypto.Word256              ( testgroup_Word256      )+import Bitcoin.Test.Crypto.FiniteField.NaiveFp  ( testgroup_NaiveFp      )+import Bitcoin.Test.Crypto.FiniteField.FastFp   ( testgroup_FastFp       )+import Bitcoin.Test.Crypto.Curve                ( testgroup_Curve        )+import Bitcoin.Test.Crypto.Projective           ( testgroup_Projective   )+import Bitcoin.Test.Crypto.Key                  ( testgroup_Key          )+import Bitcoin.Test.Crypto.RFC6979              ( testgroup_RFC6979      )++import Bitcoin.Test.Protocol.Hash               ( testgroup_ProtocolHash )+import Bitcoin.Test.Script.RunTests             ( testgroup_Script       )+import Bitcoin.Test.TxCheck                     ( testgroup_TxCheck      )++--------------------------------------------------------------------------------++main :: IO ()+main = defaultMain tests++setN :: Int -> TestTree -> TestTree+setN n = localOption (QuickCheckTests n)++tests :: TestTree+tests +  = setN 1000+  $ testGroup "all tests"+      [ testGroup "crypto" +          [ testgroup_Word256+          , testgroup_NaiveFp+          , testgroup_FastFp+          , setN 250 testgroup_Curve+          , setN 250 testgroup_Projective+          , testgroup_Key+          , testgroup_RFC6979+          ]+      , testGroup "protocol" +          [ testgroup_ProtocolHash+          ]+      , testgroup_Script+      , testgroup_TxCheck +      ]++--------------------------------------------------------------------------------
+ LICENSE view
@@ -0,0 +1,46 @@+Copyright (c) 2013, 2016 Balazs Komuves+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of the copyright holders nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++----------------------------------------------------------------------++The following third-party code is included in this distribution:++The MD5 implementation was written by Alexander Peslyak, and placed+into public domain.++The RIPEMD-160 implementation was written by Antoon Bosselaers, +copyright (c) Katholieke Universiteit Leuven++The SHA1 implementation was originally written by Steve Reid and +placed into public domain++The SHA2 implementation was written by Aaron D. Gifford and licensed+under the 3-clause BSD license, (c) 2000-2001, Aaron D. Gifford+
+ Setup.hs view
@@ -0,0 +1,196 @@++-- really fragile hack to build the assembly code into the library+-- unfortunately, cabal is not exactly helpful for this task, so to speak...++{-# LANGUAGE CPP #-}++import Control.Monad+import Data.Maybe++import Distribution.Simple+import Distribution.Simple.Setup+import Distribution.Simple.UserHooks+import Distribution.Simple.LocalBuildInfo+import Distribution.Simple.Program+import Distribution.PackageDescription++import System.Process   -- System.Cmd+import System.Exit+import System.FilePath+import System.Directory++--------------------------------------------------------------------------------+-- * system-dependent configuration++data OS +  = Linux +  | Windows +  | MacOSX +  deriving (Eq,Show)++data CallConv +  = CDecl +  | Win64 +  | SystemV +  deriving (Eq,Show)++host_bits :: Int +#if defined i386_HOST_ARCH+host_bits = 32+#elif defined x86_64_HOST_ARCH+host_bits = 64+#else+#error cannot figure out host architecture (for nasm)+#endif++host_os :: OS+#if defined mingw32_HOST_OS           +host_os = Windows+#elif defined linux_HOST_OS+host_os = Linux+#elif defined darwin_HOST_OS+host_os = MacOSX+#else+#error cannot figure out target operating system (for nasm)+#endif++objfmt :: String+objfmt = case host_os of+  Windows -> "-fwin"   ++ show host_bits+  Linux   -> "-felf"   ++ show host_bits+  MacOSX  -> "-fmacho" ++ show host_bits++callConv :: CallConv+callConv = case host_bits of+  32 -> CDecl+  64 -> case host_os of+    Windows -> Win64+    _       -> SystemV++--------------------------------------------------------------------------------++mySubDir :: FilePath+mySubDir = "Bitcoin/Crypto/cbits/"++theFlags :: LocalBuildInfo -> FlagAssignment+theFlags lbi = configConfigurationsFlags $ configFlags lbi++doCompileWithAsm :: LocalBuildInfo -> Bool+doCompileWithAsm lbi = +  case lookup (FlagName "x86asm") (theFlags lbi) of+    Nothing -> False+    Just b  -> b++targetDir :: LocalBuildInfo -> FilePath+targetDir lbi = buildDir lbi </> mySubDir ++--------------------------------------------------------------------------------++myBuildHook pkgdesc localbuildinfo userhooks buildflags = do  ++  when (doCompileWithAsm localbuildinfo) $ do+    putStrLn "now trying to run nasm to compile our sweet hand-written assembly code..."++    let nasmpath = "nasm"++    findExecutable nasmpath >>= \mb -> case mb of+      Nothing -> error "nasm executable not found in path - either install it or use the cabal flag -f-X86ASM"+      Just p  -> putStrLn $ "nasm executable is: " ++ p++    let srcdir = "." </> mySubDir+        tgtdir = targetDir localbuildinfo++    createDirectoryIfMissing True tgtdir  -- in a clean build, the dist/build directory doesn't exist yet...++    let dcallconv = case callConv of+          CDecl   -> "-DCALLCONV_CDECL"+          Win64   -> "-DCALLCONV_WIN64"+          SystemV -> "-DCALLCONV_SYSTEMV"++    let asmsrc = case host_bits of+          32 -> srcdir </> "asm_modp_x86.asm"+          64 -> srcdir </> "asm_modp_x64.asm"++    let objfile = case host_bits of+          32 -> tgtdir </> "asm_modp_x86.o"+          64 -> tgtdir </> "asm_modp_x64.o"++    let cmd = unwords [ nasmpath , objfmt , dcallconv , asmsrc , "-o" , objfile ]++    exitcode <- system cmd+    case exitcode of+      ExitSuccess   -> return ()+      ExitFailure k -> error ("nasm failed with exist code " ++ show k)++{-    +    putStrLn "now let's create a library out of the object file..."++    let cmd = unwords ["ar", "rcs" , tgtdir </> "libmodp.a" , tgtdir </> "asm_modp.o" ]+    exitcode <- system cmd+    case exitcode of+      ExitSuccess -> return ()+      ExitFailure k -> error ("ar failed with exist code " ++ show k)+-}++  -- print localbuildinfo++  (buildHook simpleUserHooks) pkgdesc localbuildinfo userhooks buildflags ++--------------------------------------------------------------------------------++myConfHook (genpkgdesc,hookbuildinfo) cfgflags = do+  lbi <- (confHook simpleUserHooks) (genpkgdesc,hookbuildinfo) cfgflags++  print $ theFlags lbi+  +  putStrLn $ "word size:  " ++ show host_bits ++ " bits"+  putStrLn $ "obj format: " ++ objfmt++  if (not $ doCompileWithAsm lbi) +    then return lbi+    else do++      putStrLn "now trying configure this mess to use our object file later on..."++      let lpd   = localPkgDescr lbi+          lib   = fromJust (library lpd)+          libbi = libBuildInfo lib++      let tgtdir = targetDir lbi+      createDirectoryIfMissing True tgtdir    -- in a clean build, the dist/build directory doesn't exist yet...++      fulltgtdir <- canonicalizePath tgtdir   -- this may fail if the directory does not exist???++      let objfile = case host_bits of+            32 -> fulltgtdir </> "asm_modp_x86.o"+            64 -> fulltgtdir </> "asm_modp_x64.o"++      -- now, seriously, cabal please...+      let progconf = withPrograms lbi+          progconf' = userSpecifyArgs "ar" [objfile] +                    $ userSpecifyArgs "ld" [objfile] +                    $ progconf+          libbi' = libbi++{-+      let libbi' = libbi { ldOptions = ldOptions libbi ++ [objfile] }+      let libbi' = libbi { options = options libbi ++ [(GHC,[objfile])] }+      let libbi' = libbi  +            { extraLibs    = extraLibs    libbi ++ ["modp"] +            , extraLibDirs = extraLibDirs libbi ++ [fulltgtdir] +            }+-}++      -- print libbi'++      let lib' = lib { libBuildInfo = libbi' }+          lpd' = lpd { library = Just lib' }++      return $ lbi { localPkgDescr = lpd' , withPrograms = progconf' }++--------------------------------------------------------------------------------++main :: IO ()+main = do+  defaultMainWithHooks $ simpleUserHooks { confHook = myConfHook , buildHook = myBuildHook }+
+ bitcoin-hs.cabal view
@@ -0,0 +1,196 @@++name:                bitcoin-hs+version:             0.0.1+synopsis:            Partial implementation of the Bitcoin protocol (as of 2013)+description:         Partial but self-contained implementation of the Bitcoin protocol (as of 2013). Use at your own risk!+license:             BSD3+license-file:        LICENSE+author:              Balazs Komuves+maintainer:          bkomuves (plus) hackage (at) gmail (dot) com+copyright:           (c) 2013, 2016 Balazs Komuves+Homepage:            http://code.haskell.org/~bkomuves/+category:            Bitcoin, Cryptography+stability:           Experimental+build-type:          Custom+tested-with:         GHC == 7.10.3+cabal-version:       >= 1.8++--------------------------------------------------------------------------------++extra-source-files:  Bitcoin/Crypto/Hash/RipEmd/rmd160.c+                     Bitcoin/Crypto/Hash/RipEmd/rmd160.h+                     Bitcoin/Crypto/Hash/SHA2/sha2.c+                     Bitcoin/Crypto/Hash/SHA2/sha2.h+                     Bitcoin/Crypto/Hash/SHA1/sha1.c+                     Bitcoin/Crypto/Hash/SHA1/sha1.h+                     Bitcoin/Crypto/Hash/MD5/md5.c+                     Bitcoin/Crypto/Hash/MD5/md5.h+                     Bitcoin/Crypto/cbits/c_word256.c+                     Bitcoin/Crypto/cbits/c_word256.h+                     Bitcoin/Crypto/cbits/c_modp.c+                     Bitcoin/Crypto/cbits/c_modp.h+                     Bitcoin/Crypto/cbits/c_ec.c+                     Bitcoin/Crypto/cbits/c_ec.h+                     Bitcoin/Crypto/cbits/asm_modp_x86.asm+                     Bitcoin/Crypto/cbits/asm_modp_x64.asm++--------------------------------------------------------------------------------++flag TestNet   +  Description:       Use the Bitcoin Testnet conventions+  Default:           False++-- This is disabled by default because I guess most users won't have nasm installed.+flag X86ASM+  Description:       Hand-written x86 / x86_64 assembly routines for modular arithmetic+  Default:           False++flag network-uri+  description: Get Network.URI from the network-uri package+  default: True++--------------------------------------------------------------------------------++source-repository head+  type:     git+  location: http://code.haskell.org/~bkomuves/projects/bitcoin-hs/++--------------------------------------------------------------------------------++library++  hs-source-dirs:    .+  exposed:           True++  build-depends:     base >= 4 && < 5, array, containers, bytestring, +                     transformers, mtl, random, +                     deepseq, ghc-prim,+                     directory, filepath, time, old-locale, +                     HTTP,+                     binary >= 0.7, json >= 0.7++  exposed-modules:   Bitcoin.BlockChain+                     Bitcoin.BlockChain.Base+                     Bitcoin.BlockChain.Tx+                     Bitcoin.BlockChain.Parser+                     Bitcoin.BlockChain.Load+                     Bitcoin.BlockChain.Chain+                     Bitcoin.BlockChain.Checkpoint+                     Bitcoin.BlockChain.TxLookup+                     Bitcoin.BlockChain.Cache+                     Bitcoin.BlockChain.Unspent+                     Bitcoin.Script.Base+                     Bitcoin.Script.Integer+                     Bitcoin.Script.Run+                     Bitcoin.Script.Serialize+                     Bitcoin.Script.Standard+                     Bitcoin.Crypto.Hash.RipEmd160+                     Bitcoin.Crypto.Hash.SHA1+                     Bitcoin.Crypto.Hash.SHA256+                     Bitcoin.Crypto.Hash.SHA512+                     Bitcoin.Crypto.Hash.MD5+                     Bitcoin.Crypto.Hash.HMAC+                     Bitcoin.Crypto.Hash.KDF+                     Bitcoin.Crypto.EC+                     Bitcoin.Crypto.EC.Curve+                     Bitcoin.Crypto.EC.Projective+                     Bitcoin.Crypto.EC.Key+                     Bitcoin.Crypto.EC.DSA+                     Bitcoin.Crypto.EC.DiffieHellman+                     Bitcoin.Crypto.Word256+                     Bitcoin.Crypto.FiniteField.Naive.Fp+                     Bitcoin.Crypto.FiniteField.Naive.Fn+                     Bitcoin.Crypto.FiniteField.Fast.Fp+                     Bitcoin.Protocol+                     Bitcoin.Protocol.Address+                     Bitcoin.Protocol.Amount+                     Bitcoin.Protocol.Base58+                     Bitcoin.Protocol.Base64+                     Bitcoin.Protocol.Hash+                     Bitcoin.Protocol.Key+                     Bitcoin.Protocol.Signature+                     Bitcoin.Protocol.MerkleTree+                     Bitcoin.Protocol.Difficulty+                     Bitcoin.Protocol.Tx+                     Bitcoin.Misc+                     Bitcoin.Misc.Bifunctor+                     Bitcoin.Misc.BigInt+                     Bitcoin.Misc.BiMap+                     Bitcoin.Misc.Endian+                     Bitcoin.Misc.HexString+                     Bitcoin.Misc.Monad+                     Bitcoin.Misc.OctetStream+                     Bitcoin.Misc.Strict+                     Bitcoin.Misc.Tuple+                     Bitcoin.Misc.Unique+                     Bitcoin.Misc.UnixTime                 +                     Bitcoin.Misc.Zipper+                     Bitcoin.RPC.API+                     Bitcoin.RPC.JSON+                     Bitcoin.RPC.HTTP+                     Bitcoin.RPC.Call++  if flag(network-uri)+    build-depends: network-uri >= 2.6, network >= 2.6+  else+    build-depends: network-uri <  2.6, network <  2.6++  c-sources:         Bitcoin/Crypto/Hash/RipEmd/rmd160.c+                     Bitcoin/Crypto/Hash/SHA2/sha2.c+                     Bitcoin/Crypto/Hash/SHA1/sha1.c+                     Bitcoin/Crypto/Hash/MD5/md5.c+                     Bitcoin/Crypto/cbits/c_word256.c+                     Bitcoin/Crypto/cbits/c_modp.c+                     Bitcoin/Crypto/cbits/c_ec.c++  if arch(i386)+    cpp-options:     -DARCH_X86+    cc-options:      -DARCH_X86 -m32+  if arch(x86_64)+    cpp-options:     -DARCH_X64+    cc-options:      -DARCH_X64 -m64++  cc-options:        -std=c99 -DSHA2_USE_INTTYPES_H -DBYTE_ORDER=LITTLE_ENDIAN++  if flag(x86asm)+    cpp-options:     -DWITH_X86ASM +    cc-options:      -DWITH_X86ASM++  if flag(testnet)+    cpp-options:     -DWITH_TESTNET++  extensions:        PackageImports, PatternGuards, CPP, EmptyDataDecls, FlexibleInstances, TypeSynonymInstances++--------------------------------------------------------------------------------++test-suite bitcoin-hs-tests+                      +  type:                exitcode-stdio-1.0+  hs-source-dirs:      .+  main-is:             Bitcoin/TestSuite.hs+  +  other-modules:       Bitcoin.Test.Crypto.Word256 +                       Bitcoin.Test.Crypto.FiniteField.NaiveFp+                       Bitcoin.Test.Crypto.FiniteField.FastFp+                       Bitcoin.Test.Crypto.Curve+                       Bitcoin.Test.Crypto.Projective+                       Bitcoin.Test.Crypto.Key+                       Bitcoin.Test.Crypto.RFC6979+                       Bitcoin.Test.Protocol.Hash+                       Bitcoin.Test.Script.Valid+                       Bitcoin.Test.Script.Invalid+                       Bitcoin.Test.Script.Parser+                       Bitcoin.Test.Script.RunTests+                       Bitcoin.Test.TxCheck+                       Bitcoin.Test.TxCheck.MainNet+                       Bitcoin.Test.TxCheck.TestNet3+                       Bitcoin.Test.Misc.QuickCheck++  build-depends:       base >= 4 && < 5, array, containers, bytestring, +                       transformers, mtl, random, binary, time, old-locale,+                       bitcoin-hs,+                       QuickCheck >= 2, tasty, tasty-quickcheck, tasty-hunit++  default-language:    Haskell2010+  default-extensions:  CPP, BangPatterns+