module Crypto.Multihash.Internal where
import Data.ByteArray (ByteArrayAccess(..))
import qualified Data.ByteArray as BA
import qualified Data.ByteArray.Encoding as BE
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base58 as B58
import Data.List (elemIndices)
import Data.Word (Word8)
import Crypto.Multihash.Internal.Types
maybeToEither :: l -> Maybe r -> Either l r
maybeToEither _ (Just res) = Right res
maybeToEither err _ = Left err
hashCodes :: [Word8]
hashCodes = map fromIntegral
([0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x40, 0x41]::[Int])
convertFromBase :: Base -> BS.ByteString -> Either String BS.ByteString
convertFromBase b bs = case b of
Base2 -> Left "This is not supposed to happen"
Base16 -> BE.convertFromBase BE.Base16 bs
Base32 -> BE.convertFromBase BE.Base32 bs
Base58 -> do
dec <- maybeToEither "Base58 decoding error" (B58.decodeBase58 B58.bitcoinAlphabet bs)
return (BA.convert dec)
Base64 -> BE.convertFromBase BE.Base64 bs
getBase :: BS.ByteString -> Either String Base
getBase h = if len == 0
then
Left "Unable to infer an encoding"
else
pure $ [Base16, Base32, Base58, Base64] !! head bsi
where
len = Prelude.length bsi
bsi = elemIndices 0 $ map (unmatch h) [b16Alphabet, b32Alphabet, b58Alphabet, b64Alphabet]
unmatch str alphabet = BS.length $ BS.filter (`BS.notElem` alphabet) str
b16Alphabet :: BS.ByteString
b16Alphabet = "0123456789abcdef"
b32Alphabet :: BS.ByteString
b32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567="
b58Alphabet :: BS.ByteString
b58Alphabet = B58.unAlphabet B58.bitcoinAlphabet
b64Alphabet :: BS.ByteString
b64Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
encoder :: ByteArrayAccess a => Base -> a -> Either String BA.Bytes
encoder base bs = case base of
Base2 -> return $ BA.convert bs
Base16 -> return $ BE.convertToBase BE.Base16 bs
Base32 -> return $ BE.convertToBase BE.Base32 bs
Base58 -> return $ BA.convert $ B58.encodeBase58 B58.bitcoinAlphabet
(BA.convert bs :: BS.ByteString)
Base64 -> return $ BE.convertToBase BE.Base64 bs
badLength :: ByteArrayAccess bs => bs -> Bool
badLength mh =
case BA.length mh of
n | n <= 2 -> True
n | BA.index mh 1 /= (fromIntegral n2) -> True
_ -> False