packages feed

multihash (empty) → 0.1.0

raw patch · 7 files changed

+323/−0 lines, 7 filesdep +attoparsecdep +basedep +base58-bytestringsetup-changed

Dependencies added: attoparsec, base, base58-bytestring, base64-bytestring, byteable, bytestring, cryptohash, hex, io-streams, multihash, optparse-applicative

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015, Luke Hoersten++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 Luke Hoersten 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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ main/Main.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import           Crypto.Hash              (Digest)+import qualified Crypto.Hash              as CH+import           Data.Byteable            (toBytes)+import           Data.ByteString          (ByteString)+import           Data.ByteString.Lazy     (fromStrict, toStrict)+import           Options.Applicative+import           System.Exit              (exitFailure, exitSuccess)++import           System.IO.Streams        (InputStream, stdin, stdout,+                                           withFileAsInput, write)+import           System.IO.Streams.Crypto (hashInputStream)++import qualified Data.Multihash.Base      as MB+import qualified Data.Multihash.Digest    as MH+++data Termination = Null | Newline deriving (Show, Eq)+data Config =+    Config+    { cfFile :: Maybe FilePath+    , cfAlgo :: MH.HashAlgorithm+    , cfBase :: MB.BaseEncoding+    , cfHash :: Maybe MH.Digest+    , cfTerm :: Termination+    } deriving Show+++main :: IO ()+main = do+    -- TODO add file checking+    config <- execParser opts+    digest <- maybe (hashStdin config) (hashFile config) $ cfFile config+    write (multihash config digest) stdout+  where+    hashStdin config = hash (cfAlgo config) stdin+    hashFile config file = withFileAsInput file . hash $ cfAlgo config+    multihash (Config _file algo base _hash term) =+        Just . toStrict . line term . MB.encode base . MH.encode algo++    line Null    = (<> "\0")+    line Newline = (<> "\n")+++-- TODO add BLAKE support+hash :: MH.HashAlgorithm -> InputStream ByteString -> IO MH.Digest+hash MH.SHA1 is   = toBytes <$> (hashInputStream is :: IO (Digest CH.SHA1))+hash MH.SHA256 is = toBytes <$> (hashInputStream is :: IO (Digest CH.SHA256))+hash MH.SHA512 is = toBytes <$> (hashInputStream is :: IO (Digest CH.SHA512))+hash MH.SHA3 is   = toBytes <$> (hashInputStream is :: IO (Digest CH.SHA3_256))+hash MH.BLAKE2B _ = undefined+hash MH.BLAKE2S _ = undefined+++opts :: ParserInfo Config+opts = info+       (helper <*> (Config+                    <$> fileArg+                    <*> algoOpt+                    <*> baseOpt+                    <*> checkOpt+                    <*> nullTermFlag+                   ))+       (fullDesc+        <> header "Generate a multihash for the given input."+        <> progDesc "Hash from FILE or stdin if not given.")+++algoOpt :: Parser MH.HashAlgorithm+algoOpt =+    option auto+    $  long "algorithm"+    <> short 'a'+    <> metavar "ALGO"+    <> showDefault <> value MH.SHA256+    <> help ("Hash algorithm to apply to input, ignored if checking hash " <> show ([minBound..] :: [MH.HashAlgorithm]))+++baseOpt :: Parser MB.BaseEncoding+baseOpt =+    option auto+    $  long "encoding"+    <> short 'e'+    <> metavar "ENCODING"+    <> showDefault <> value MB.Base58+    <> help ("Base encoding of output digest, ignored if checking hash " <> show ([minBound..] :: [MB.BaseEncoding]))+++checkOpt :: Parser (Maybe MH.Digest)+checkOpt =+    optional . option auto+    $  long "check"+    <> short 'c'+    <> metavar "DIGEST"+    <> help "Check for matching digest"+++nullTermFlag :: Parser Termination+nullTermFlag =+    flag Newline Null+    $  long "print0"+    <> short '0'+    <> help "End filenames with NUL, for use with xargs"+++fileArg :: Parser (Maybe FilePath)+fileArg = optional . argument str $ metavar "FILE"
+ multihash.cabal view
@@ -0,0 +1,60 @@+name:                multihash+version:             0.1.0+synopsis:            Multihash library and CLI executable+description:         Multihash is a protocol for encoding the hash algorithm+                     and digest length at the start of the digest.+                     More information available at https:\/\/github.com\/jbenet\/multihash\/.+                     .+                     Base32 encoding, Blake hashing, and file checking still to be added.+                     .+license:             BSD3+license-file:        LICENSE+author:              Luke Hoersten+maintainer:          luke@hoersten.org+copyright:           2015 Luke Hoersten+category:            Data+build-type:          Simple+cabal-version:       >=1.10++source-repository head+  type: git+  location: git://github.com/LukeHoersten/multihash.git+++library+  exposed-modules: Data.Multihash.Base+                 , Data.Multihash.Digest+                 , System.IO.Streams.Crypto++  hs-source-dirs:      src+  default-language:    Haskell2010++  build-depends: attoparsec        >= 0.12 && < 0.13+               , base              >= 4.8  && < 4.9+               -- , base32-bytestring >= 0.2  && < 0.3+               , base58-bytestring >= 0.1  && < 0.2+               , base64-bytestring >= 1.0  && < 1.1+               , bytestring        >= 0.10 && < 0.11+               , cryptohash        >= 0.11 && < 0.12+               , hex               >= 0.1  && < 0.2+               , io-streams        >= 1.2  && < 1.3+++executable multihash+  main-is:           Main.hs+  hs-source-dirs:    main+  default-language:  Haskell2010+  ghc-options:       -threaded -Wall -fwarn-tabs -funbox-strict-fields -O2 -fdicts-cheap+                     -fno-warn-orphans -fno-warn-unused-do-bind -rtsopts++  build-depends: base                 >= 4.8  && < 4.9+               -- , base32-bytestring >= 0.2  && < 0.3+               , base64-bytestring    >= 1.0  && < 1.1+               , base58-bytestring    >= 0.1  && < 0.2+               , byteable             >= 0.1  && < 0.2+               , bytestring           >= 0.10 && < 0.11+               , cryptohash           >= 0.11 && < 0.12+               , hex                  >= 0.1  && < 0.2+               , io-streams           >= 1.2  && < 1.3+               , multihash            >= 0.1  && < 0.2+               , optparse-applicative >= 0.11 && < 0.12
+ src/Data/Multihash/Base.hs view
@@ -0,0 +1,33 @@+module Data.Multihash.Base where++-- import qualified Data.ByteString.Base32      as B32+import qualified Data.ByteString.Base58      as B58+import qualified Data.ByteString.Base64.Lazy as B64+import           Data.ByteString.Lazy        (ByteString, fromStrict, toStrict)+import           Data.Either                 (Either)+import qualified Data.Hex                    as B16+++-- TODO add Base32 encoding+data BaseEncoding+    = Base2  -- ^ Raw binary encoding+    | Base16 -- ^ Hexadecimal encoding+    | Base58 -- ^ Bitcoin encoding+    | Base64+    deriving (Show, Read, Eq, Enum, Bounded)+++encode :: BaseEncoding -> ByteString -> ByteString+encode Base2  = id+encode Base16 = B16.hex+-- encode Base32 = B32.encode+encode Base58 = fromStrict . B58.encodeBase58 B58.bitcoinAlphabet . toStrict+encode Base64 = B64.encode+++decode :: BaseEncoding -> ByteString -> Either String ByteString+decode Base2  = return . id+decode Base16 = B16.unhex+-- decode Base32 = B32.decode+decode Base58 = maybe (Left "Failed to parse") (Right . fromStrict) . B58.decodeBase58 B58.bitcoinAlphabet . toStrict+decode Base64 = B64.decode
+ src/Data/Multihash/Digest.hs view
@@ -0,0 +1,76 @@+module Data.Multihash.Digest where+++import           Data.Attoparsec.ByteString (Parser, parseOnly)+import qualified Data.Attoparsec.ByteString as A+import qualified Data.ByteString            as BS+import           Data.ByteString.Builder    (Builder, byteString,+                                             toLazyByteString)+import qualified Data.ByteString.Builder    as BB+import qualified Data.ByteString.Lazy       as BL+import           Data.Monoid                ((<>))+import           Data.Word                  (Word8)+++data MultihashDigest =+    MultihashDigest+    { algorithm :: !HashAlgorithm+    , lenght    :: !Length+    , digest    :: !Digest+    } deriving (Show, Eq)+++type Length = Int+type Digest = BS.ByteString+++data HashAlgorithm+    = SHA1+    | SHA256+    | SHA512+    | SHA3+    | BLAKE2B+    | BLAKE2S+    deriving (Show, Read, Eq, Enum, Bounded)+++fromCode :: Int -> HashAlgorithm+fromCode 0x11 = SHA1+fromCode 0x12 = SHA256+fromCode 0x13 = SHA512+fromCode 0x14 = SHA3+fromCode 0x40 = BLAKE2B+fromCode 0x41 = BLAKE2S+fromCode _ = error "Unknown hash funciton code"+++toCode :: HashAlgorithm -> Int+toCode SHA1    = 0x11+toCode SHA256  = 0x12+toCode SHA512  = 0x13+toCode SHA3    = 0x14+toCode BLAKE2B = 0x40+toCode BLAKE2S = 0x41+++encode :: HashAlgorithm -> Digest -> BL.ByteString+encode h d = toLazyByteString $ encoder h d+++encoder :: HashAlgorithm -> Digest -> Builder+encoder h d+    =  (BB.word8 . fromIntegral $ toCode h)+    <> (BB.word8 . fromIntegral $ BS.length d)+    <> byteString d+++decode :: BS.ByteString -> Either String MultihashDigest+decode = parseOnly decoder+++decoder :: Parser MultihashDigest+decoder = do+    h <- (fromCode . fromIntegral <$> A.anyWord8)+    l <- (fromIntegral <$> A.anyWord8)+    d <- A.take l+    return $ MultihashDigest h l d
+ src/System/IO/Streams/Crypto.hs view
@@ -0,0 +1,12 @@+module System.IO.Streams.Crypto where++import           Control.Exception     (bracket)+import           Crypto.Hash           (Digest, HashAlgorithm (..))+import           Data.ByteString       (ByteString)+import           Data.Multihash.Digest (decoder)+import           System.IO.Streams     (InputStream, fold, inputFoldM)+++hashInputStream :: (HashAlgorithm h) => InputStream ByteString -> IO (Digest h)+hashInputStream = fmap hashFinalize . fold update hashInit+  where update ctx bs = hashUpdates ctx [bs]