{-# LANGUAGE FlexibleInstances, OverloadedStrings #-} module Hash where import Types import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as C8 import qualified Crypto.Hash as H class Hashable a where hash :: a -> Hash instance Hashable B.ByteString where -- Encodes the SHA256 using base16 format hash = Hash SHA256 . Val . C8.pack . show . sha256 instance Hashable Val where hash (Val v) = hash v instance Hashable Hash where hash = id sha256 :: B.ByteString -> H.Digest H.SHA256 sha256 = H.hash -- | A value tagged with a ByteString describing the type of value. -- This is hashed by hashing the concacenation of the hash of the -- bytestring and the hash of the value. This way, items of different types -- but with the same internal content will hash differently. For example, -- a Seen "foo" and a Entered "foo" should not hash the same. data Tagged a = Tagged B.ByteString a instance Hashable a => Hashable (Tagged a) where hash (Tagged b a) = hash [hash b, hash a] instance Hashable a => Hashable (Activity a) where hash (Activity a mp s) = hash $ Tagged "Activity" [hash a, hash mp, hash s] instance Hashable Entered where hash v = hash $ Tagged "Entered" [hash (enteredData v), hash (echoData v)] instance Hashable Seen where hash v = hash $ Tagged "Seen" [hash (seenData v)] instance Hashable Signature where hash (Ed25519Signature s) = hash $ Tagged "Ed25519Signature" s hash (OtherSignature s) = hash $ Tagged "OtherSignature" s instance Hashable PublicKey where hash (PublicKey v gpgsig) = hash $ Tagged "PublicKey" [hash v, hash gpgsig] instance Hashable GpgSig where hash (GpgSig v) = hash $ Tagged "GpgSig" v -- | Hash a list of hashes by hashing the concacenation of the hashes. instance Hashable [Hash] where hash = hash . B.concat . map (val . hashValue) -- | Hash empty string for Nothing instance Hashable v => Hashable (Maybe v) where hash Nothing = hash () hash (Just v) = hash v instance Hashable () where hash () = hash (mempty :: B.ByteString)