{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Codec.Serialise.Multihash
( encode
, decode
, Multihashable
)
where
import qualified Codec.Serialise as CBOR
import qualified Codec.Serialise.Decoding as CBOR
import qualified Codec.Serialise.Encoding as CBOR
import Control.Applicative (liftA2)
import qualified Crypto.Hash as C
import Data.ByteArray (convert)
import Data.Multihash (Multihashable)
import qualified Data.Multihash as Multi
import Data.Proxy (Proxy(..))
encode :: Multihashable a => C.Digest a -> CBOR.Encoding
encode dig =
CBOR.encodeListLen 3
<> CBOR.encodeWord 0
<> CBOR.encode (Multi.toCode (Multi.fromCryptonite dig))
<> CBOR.encodeBytes (convert dig)
decode :: forall s a. Multihashable a => CBOR.Decoder s (C.Digest a)
decode = do
pre <- liftA2 (,) CBOR.decodeListLen CBOR.decodeWord
case pre of
(3, 0) -> do
rithm <- Multi.fromCode <$> CBOR.decode
case rithm of
Nothing -> fail "Unknown HashAlgorithm"
Just a
| Multi.fromCryptonite (Proxy @a) /= a ->
fail "Algorithm Mismatch"
| otherwise -> do
bytes <- CBOR.decodeBytes
maybe (fail "Invalid Digest") pure
$ C.digestFromByteString bytes
_ -> fail "Multihash: Invalid Tag"