module Bloohm where

import Crypto.Hash (hashWith)
import Crypto.Hash.Algorithms ( MD5(MD5) )
import Data.Bits ( Bits((.|.), shiftL) )
import qualified Data.ByteArray.Encoding as B (Base (..), convertToBase)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BS8
import Data.List (sort)
import Data.Word (Word8)

doBloohm :: String
doBloohm :: String
doBloohm = String
"Bloohm"

findPos :: String -> [Integer]
findPos :: String -> [Integer]
findPos String
s = ByteString -> [Integer]
findBits (ByteString -> [Integer]) -> ByteString -> [Integer]
forall a b. (a -> b) -> a -> b
$ String -> ByteString
BS8.pack String
s

findBits :: ByteString -> [Integer]
findBits :: ByteString -> [Integer]
findBits ByteString
bs = [Integer] -> [Integer]
forall a. Ord a => [a] -> [a]
sort [Integer
int1, Integer
int2, Integer
int3]
    where wz :: [Word8]
wz = ByteString -> [Word8]
BS.unpack (ByteString -> [Word8]) -> ByteString -> [Word8]
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
runhashMD5 ByteString
bs
          wzThird :: Int
wzThird = [Word8] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
wz Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
3
          multipleOfThree :: [Word8]
multipleOfThree = Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
drop ([Word8] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word8]
wz Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
3) [Word8]
wz
          (Integer
int1,[Word8]
ws) = Int -> [Word8] -> (Integer, [Word8])
tritMod Int
wzThird [Word8]
multipleOfThree
          (Integer
int2,[Word8]
ws') = Int -> [Word8] -> (Integer, [Word8])
tritMod Int
wzThird [Word8]
ws
          (Integer
int3,[Word8]
_) = Int -> [Word8] -> (Integer, [Word8])
tritMod Int
wzThird [Word8]
ws'



tritMod :: Int -> [Word8] -> (Integer,[Word8])
tritMod :: Int -> [Word8] -> (Integer, [Word8])
tritMod Int
_ [] = String -> (Integer, [Word8])
forall a. HasCallStack => String -> a
error String
"tritMod got empty list"
tritMod Int
n [Word8]
ws = ([Word8] -> Integer
roll (Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
take Int
n [Word8]
ws) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
32, Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
drop Int
n [Word8]
ws)

roll :: [Word8] -> Integer
roll :: [Word8] -> Integer
roll = (Word8 -> Integer -> Integer) -> Integer -> [Word8] -> Integer
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Word8 -> Integer -> Integer
forall {a} {a}. (Bits a, Integral a, Num a) => a -> a -> a
unstep Integer
0
  where
    unstep :: a -> a -> a
unstep a
b a
a = a
a a -> Int -> a
forall a. Bits a => a -> Int -> a
`shiftL` Int
8 a -> a -> a
forall a. Bits a => a -> a -> a
.|. a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
b

runhashMD5 :: ByteString -> ByteString
runhashMD5 :: ByteString -> ByteString
runhashMD5 ByteString
v = Base -> Digest MD5 -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
Base -> bin -> bout
B.convertToBase Base
B.Base16 (Digest MD5 -> ByteString) -> Digest MD5 -> ByteString
forall a b. (a -> b) -> a -> b
$ MD5 -> ByteString -> Digest MD5
forall ba alg.
(ByteArrayAccess ba, HashAlgorithm alg) =>
alg -> ba -> Digest alg
hashWith MD5
MD5 ByteString
v