longshot 0.1.0.2 → 0.1.0.3
raw patch · 9 files changed
+167/−107 lines, 9 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Crypto.Longshot: byteChars :: String -> [ByteString]
- Crypto.Longshot: bytePrefixes :: Int -> String -> [ByteString]
- Crypto.Longshot: defChars :: String
- Crypto.Longshot: defNumBind :: Int
- Crypto.Longshot: defNumPrefix :: Int
- Crypto.Longshot: defSearchLength :: Int
- Crypto.Longshot: image :: String -> ByteString
- Crypto.Longshot: limitSearchLength :: Int
- Crypto.Longshot: toKey :: ByteString -> String
+ Crypto.Longshot.Const: defChars :: String
+ Crypto.Longshot.Const: defNumPrefix :: Int
+ Crypto.Longshot.Const: defSearchLength :: Int
+ Crypto.Longshot.Const: limitSearchLength :: Int
+ Crypto.Longshot.Const: maxNumBind :: Int
+ Crypto.Longshot.Internal: (<%>) :: (NFData a, NFData b) => (a -> b) -> [a] -> [b]
+ Crypto.Longshot.Internal: bruteforcePar :: Int -> [ByteString] -> ByteString -> Hasher -> ByteString -> Maybe String
+ Crypto.Longshot.Internal: byteChars :: String -> [ByteString]
+ Crypto.Longshot.Internal: bytePrefixes :: Int -> String -> [ByteString]
+ Crypto.Longshot.Internal: image :: String -> ByteString
Files
- ChangeLog.md +4/−0
- README.md +6/−3
- app/Main.hs +3/−3
- longshot.cabal +3/−2
- src/Crypto/Longshot.hs +16/−51
- src/Crypto/Longshot/Const.hs +39/−0
- src/Crypto/Longshot/Hasher.hs +16/−17
- src/Crypto/Longshot/Internal.hs +70/−18
- src/Crypto/Longshot/TH.hs +10/−13
ChangeLog.md view
@@ -7,3 +7,7 @@ ## 0.1.0.2 * Fixed Hackage metadata++## 0.1.0.3+* Up to 10% performance improvement+* Additional explanations on the arguments of the core function
README.md view
@@ -52,7 +52,10 @@ ``` ## How to build-```bash+```shell+## Install 'stack' if not any+$ brew install stack+ $ git clone https://github.com/thyeem/longshot.git $ make build @@ -65,7 +68,7 @@ ``` ## Quick start-```bash+```shell ## Refer to the following usage: ## Note that the order of arguments and options matter. $ ./longshot -h@@ -96,7 +99,7 @@ See below for more interesting detailed examples. ## More examples-```bash+```shell ## Generate a example image using Blake2b hash algorithm ## Blake2b-hashed sofia (my first daughter!) $ ./longshot image -a blake2b sofia
app/Main.hs view
@@ -1,13 +1,13 @@ {-# LANGUAGE QuasiQuotes #-} module Main where -import Control.Monad-import System.Environment+import Control.Monad ( when )+import System.Environment ( getArgs ) import System.Console.Docopt import qualified Data.ByteString.Char8 as C import qualified Data.ByteString.Base16 as H import Crypto.Longshot.Internal-import Crypto.Longshot.Hasher+import Crypto.Longshot.Hasher ( getHasher ) patterns :: Docopt patterns = [docopt|
longshot.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 4cf3d32f97b4605f2bd729574881eb5df14e31adef0431f928343ea04e268c38+-- hash: 950eaac57e913aaa5d3f38ed066cb8aefb07851a8072f2686280220fd76aa711 name: longshot-version: 0.1.0.2+version: 0.1.0.3 synopsis: Fast Brute-force search using parallelism description: Longshot enables to search for preimages from a given hash value using a brute-force method based on parallelism.@@ -41,6 +41,7 @@ library exposed-modules: Crypto.Longshot+ Crypto.Longshot.Const Crypto.Longshot.Hasher Crypto.Longshot.Internal Crypto.Longshot.TH
src/Crypto/Longshot.hs view
@@ -5,56 +5,21 @@ -- Stability : experimental -- Portability : unknown ----- How big is the search space? The space consists of two axes.------ * X-axis: Number of characters available--- * Y-axis: Search length of preimage to find------ Note that it's proportional to @(X ^ Y)@ rather than @(X * Y)@------ The values below are defined by default.------ When not provided as options in CUI, the following values are used.+-- Fast Brute-force search using parallelism ---module Crypto.Longshot where--import Control.Monad-import qualified Data.ByteString.Char8 as C-import qualified Data.ByteString.Base16 as H---- | Characters available in a preimage-defChars :: String-defChars = "0123456789"---- | Search length of preimage-defSearchLength :: Int-defSearchLength = 8---- | Limit search length of preimage-limitSearchLength :: Int-limitSearchLength = 20---- | Value related to the number of sparks-defNumPrefix :: Int-defNumPrefix = 3---- | Number of actions in TH bruteforceN-defNumBind :: Int-defNumBind = limitSearchLength - defNumPrefix------------------------------------------------------------------------- | Image bytestring: target hash value to find-image :: String -> C.ByteString-image = fst . H.decode . C.pack---- | Bytestring usable for preimage-byteChars :: String -> [C.ByteString]-byteChars chars = C.pack . (: []) <$> chars---- | Combination of prefixes possible: size of (length of chars) ^ (numPrefix)-bytePrefixes :: Int -> String -> [C.ByteString]-bytePrefixes numPrefix chars = C.pack <$> replicateM numPrefix chars+-- Longshot enables to search for preimages from a given hash value+-- using a brute-force method based on parallelism.+-- +module Crypto.Longshot+ ( module Crypto.Longshot+ , module Crypto.Longshot.Const+ , module Crypto.Longshot.Internal+ , module Crypto.Longshot.TH+ , module Crypto.Longshot.Hasher+ )+where --- | Convert preimage found into key string-toKey :: C.ByteString -> String-toKey = C.unpack+import Crypto.Longshot.Const+import Crypto.Longshot.Internal+import Crypto.Longshot.TH+import Crypto.Longshot.Hasher
+ src/Crypto/Longshot/Const.hs view
@@ -0,0 +1,39 @@+-- |+-- Module : Crypto.Longshot.Const+-- License : MIT+-- Maintainer : Francis Lim <thyeem@gmail.com>+-- Stability : experimental+-- Portability : unknown+--+-- How big is the search space? The space consists of two axes.+--+-- * @X-axis@: Number of characters available+-- * @Y-axis@: Search length of preimage to find+--+-- Note that it's proportional to @(X ^ Y)@ rather than @(X * Y)@+--+-- The values below are defined by default.+--+-- When not provided as options in CUI, the following values are used.+--+module Crypto.Longshot.Const where++-- | Default characters available in a preimage+defChars :: String+defChars = "0123456789"++-- | Default search length of preimage+defSearchLength :: Int+defSearchLength = 8++-- | Limit search length of preimage+limitSearchLength :: Int+limitSearchLength = 20++-- | Default value related to the number of sparks+defNumPrefix :: Int+defNumPrefix = 3++-- | Maximum number of actions in bruteforceN+maxNumBind :: Int+maxNumBind = limitSearchLength - defNumPrefix
src/Crypto/Longshot/Hasher.hs view
@@ -11,22 +11,21 @@ ) where -import GHC.TypeLits-import Numeric.Natural+import GHC.TypeLits ( Nat )+import Data.ByteString ( ByteString ) import qualified Data.ByteArray as B-import qualified Data.ByteString.Char8 as C import qualified Crypto.Hash as X import qualified Crypto.Hash.SHA256 as S-import qualified Crypto.Hash.BLAKE2.BLAKE2s as B2s-import qualified Crypto.Hash.BLAKE2.BLAKE2b as B2b-import qualified BLAKE3 as B3+import qualified Crypto.Hash.BLAKE2.BLAKE2s as Blake2s+import qualified Crypto.Hash.BLAKE2.BLAKE2b as Blake2b+import qualified BLAKE3 as Blake3 -- | Type for hash functions available-type Hasher = C.ByteString -> C.ByteString+type Hasher = ByteString -> ByteString -type Blake3_256 = C.ByteString -> B3.Digest (32 :: Nat)-type Blake3_384 = C.ByteString -> B3.Digest (48 :: Nat)-type Blake3_512 = C.ByteString -> B3.Digest (64 :: Nat)+type Blake3_256 = ByteString -> Blake3.Digest (32 :: Nat)+type Blake3_384 = ByteString -> Blake3.Digest (48 :: Nat)+type Blake3_512 = ByteString -> Blake3.Digest (64 :: Nat) -- | Select hasher by defined name getHasher :: String -> Hasher@@ -39,13 +38,13 @@ "sha3_256" -> B.convert . X.hashWith X.SHA3_256 "sha3_384" -> B.convert . X.hashWith X.SHA3_384 "sha3_512" -> B.convert . X.hashWith X.SHA3_512- "blake2s_256" -> B2s.hash 32 mempty- "blake2b_256" -> B2b.hash 32 mempty- "blake2b_384" -> B2b.hash 48 mempty- "blake2b_512" -> B2b.hash 64 mempty- "blake3_256" -> B.convert . (B3.hash . (: []) :: Blake3_256)- "blake3_384" -> B.convert . (B3.hash . (: []) :: Blake3_384)- "blake3_512" -> B.convert . (B3.hash . (: []) :: Blake3_512)+ "blake2s_256" -> Blake2s.hash 32 mempty+ "blake2b_256" -> Blake2b.hash 32 mempty+ "blake2b_384" -> Blake2b.hash 48 mempty+ "blake2b_512" -> Blake2b.hash 64 mempty+ "blake3_256" -> B.convert . (Blake3.hash . (: []) :: Blake3_256)+ "blake3_384" -> B.convert . (Blake3.hash . (: []) :: Blake3_384)+ "blake3_512" -> B.convert . (Blake3.hash . (: []) :: Blake3_512) "keccak_256" -> B.convert . X.hashWith X.Keccak_256 "keccak_384" -> B.convert . X.hashWith X.Keccak_384 "keccak_512" -> B.convert . X.hashWith X.Keccak_512
src/Crypto/Longshot/Internal.hs view
@@ -8,23 +8,59 @@ module Crypto.Longshot.Internal ( bruteforce , bruteforceDeep+ , bruteforcePar+ , (<%>)+ , image+ , byteChars+ , bytePrefixes ) where -import Control.Applicative-import Control.DeepSeq-import Control.Parallel-import Data.Foldable+import Control.Monad ( replicateM )+import Control.Applicative ( (<|>)+ , empty+ )+import Control.Parallel ( par+ , pseq+ )+import Control.DeepSeq ( NFData+ , force+ )+import Data.Foldable ( foldl' )+import Data.ByteString ( ByteString ) import qualified Data.ByteString.Char8 as C-import Language.Haskell.TH-import Crypto.Longshot-import Crypto.Longshot.TH+import qualified Data.ByteString.Base16 as H import Crypto.Longshot.Hasher+import Crypto.Longshot.TH+import Crypto.Longshot.Const --- Declaration of bruteforceN: generating code by splicing+-- | Each bruteforceN declaration: generating code through splicing.+-- Number of functions declared == 'maxNumBind'+-- $( funcGenerator ) -- | Brute-force search only for a given exact length+--+-- @+-- ------------------------------------------------------------------------------+-- size | Preimage length to search+-- ------------------------------------------------------------------------------+-- chars | Given character set like "0123456789"+-- ------------------------------------------------------------------------------+-- hex | Given hex-string like "17da1ae431f965d839ec8eb93087fb2b"+-- ------------------------------------------------------------------------------+-- hasher | Hash functions in 'Hasher' module. Get it using 'getHasher'+-- ------------------------------------------------------------------------------+-- numBind | Number of bound variables defined by search length and prefix size+-- ------------------------------------------------------------------------------+-- runPar | A partially applied function for parallel execution+-- ------------------------------------------------------------------------------+-- prefixes | All possible combinations of given prefix characters.+-- | The search space is equally partioned based on these prefixes.+-- | length of prefixes == number of sparks+-- ------------------------------------------------------------------------------+-- @+-- bruteforce :: Int -> String -> String -> Hasher -> Maybe String bruteforce size chars hex hasher = found where@@ -36,27 +72,43 @@ prefixes = bytePrefixes numPrefix chars -- | Pick up an appropriate search function+--+-- Returns a partial application corresponding to the given numBind+-- bruteforcePar- :: Int- -> [C.ByteString]- -> C.ByteString- -> Hasher- -> C.ByteString- -> Maybe String-bruteforcePar n- | n `elem` [0 .. defNumBind] = $( funcList ) !! n+ :: Int -> [ByteString] -> ByteString -> Hasher -> ByteString -> Maybe String+bruteforcePar numBind+ | numBind `elem` [0 .. maxNumBind] = $( funcList ) !! numBind | otherwise = errorWithoutStackTrace "Not available search length" -- | Deep Brute-force search including less than a given search size+--+-- See the 'bruteforce' function for the arguments used+-- bruteforceDeep :: Int -> String -> String -> Hasher -> Maybe String-bruteforceDeep size x y z = foldl' (<|>) empty found+bruteforceDeep size chars hex hasher = foldl' (<|>) empty found where- found = deep x y z <%> [1 .. size]+ found = deep chars hex hasher <%> [1 .. size] deep a b c d = bruteforce d a b c -- | Parallel map using deepseq, par and pseq+--+-- Type of any argument in this map should be instance of 'NFData'.+-- (<%>) :: (NFData a, NFData b) => (a -> b) -> [a] -> [b] f <%> [] = [] f <%> (x : xs) = y `par` ys `pseq` (y : ys) where y = force $ f x ys = f <%> xs++-- | Image bytestring: target hash value to find+image :: String -> ByteString+image = fst . H.decode . C.pack++-- | Bytestring usable for preimage+byteChars :: String -> [ByteString]+byteChars chars = C.pack . (: []) <$> chars++-- | Combination of prefixes possible: size of @(length of chars) ^ (numPrefix)@+bytePrefixes :: Int -> String -> [ByteString]+bytePrefixes numPrefix chars = C.pack <$> replicateM numPrefix chars
src/Crypto/Longshot/TH.hs view
@@ -7,31 +7,28 @@ -- module Crypto.Longshot.TH where -import Control.Monad-import Data.Foldable+import Control.Monad ( replicateM )+import Data.Foldable ( foldl' )+import Data.ByteString.Char8 ( unpack ) import Language.Haskell.TH-import Crypto.Longshot+import Crypto.Longshot.Const -- | Brute-force with N-search-length using TH bruteforceN :: Int -> Q Exp -> Q Exp -> Q Exp -> Q Exp -> Q Exp bruteforceN numBind chars hex hasher prefix = do names <- replicateM numBind (newName "names") let pats = varP <$> names- let bytes = [| $( prefix ) <>- $( foldl' (\a b -> [| $a <> $b |])- [| mempty |]- (varE <$> names)- )- |]- let cond = condE [| $( appE hasher bytes ) == $(hex) |]- [| Just (toKey $( bytes )) |]+ let bytes = prefix : (varE <$> names)+ let preimage = [| $( foldl' (\a b -> [| $a <> $b |]) [| mempty |] bytes ) |]+ let cond = condE [| $( appE hasher preimage ) == $( hex ) |]+ [| Just (unpack $( preimage )) |] [| Nothing |] let stmts = ((`bindS` chars) <$> pats) <> [noBindS cond] [| foldl' (<|>) empty $( compE stmts ) |] -- | Declare functions to run in parallel for search funcGenerator :: Q [Dec]-funcGenerator = forM [0 .. defNumBind] funcG where +funcGenerator = mapM funcG [0 .. maxNumBind] where funcG numBind = do let name = mkName $ "bruteforce" <> show numBind chars <- newName "chars"@@ -46,4 +43,4 @@ -- | Get list of functions to run in parallel for search funcList :: Q Exp-funcList = listE (varE . mkName . ("bruteforce" <>) . show <$> [0 .. defNumBind])+funcList = listE (varE . mkName . ("bruteforce" <>) . show <$> [0 .. maxNumBind])