{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} -- | -- Copyright : 2018 Monadic GmbH -- License : BSD3 -- Maintainer : kim@monadic.xyz, team@monadic.xyz -- Stability : provisional -- Portability : non-portable (GHC extensions) -- -- A mapping of to CBOR. -- -- Instead of an opaque, multihash-encoded blob, this provides a tagged CBOR -- encoding where the hash algorithm used is a 'Word16' field containing the -- multihash code for the algorithm, followed by the digest bytes. module Codec.Serialise.Multihash ( encode , decode -- * Re-exports , 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(..)) -- | Multihash-like CBOR 'CBOR.Encoding' of a 'C.Digest'. encode :: Multihashable a => C.Digest a -> CBOR.Encoding encode dig = CBOR.encodeListLen 3 <> CBOR.encodeWord 0 -- constructor tag / version <> CBOR.encode (Multi.toCode (Multi.fromCryptonite dig)) <> CBOR.encodeBytes (convert dig) -- | CBOR 'CBOR.Decoder' to decode a 'C.Digest' encoded via 'encodeCBOR'. 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"