{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Generics.MRSOP.HDiff.Digest where
import Data.Proxy
import Data.Functor.Const
import Data.Void
import Data.Word (Word8,Word64)
import Data.Bits
import Data.List (splitAt,foldl')
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BS8
import qualified Data.ByteArray as BA
import qualified Data.ByteArray.Mapping as BA
import qualified Crypto.Hash as Hash
import qualified Crypto.Hash.Algorithms as Hash (Blake2s_256)
import Generics.MRSOP.Base
newtype Digest
= Digest { getDigest :: Hash.Digest Hash.Blake2s_256 }
deriving (Eq , Show)
toW64s :: Digest -> [Word64]
toW64s = map combine . chunksOf 8 . BA.unpack . getDigest
where
chunksOf n l
| length l <= n = [l]
| otherwise = let (h , t) = splitAt n l
in h : chunksOf n t
combine :: [Word8] -> Word64
combine = foldl' (\acu (n , next)
-> shiftL (fromIntegral next) (8*n) .|. acu) 0
. zip [0,8,16,24,32,40,48,56]
snat2W64 :: SNat n -> Word64
snat2W64 SZ = 0
snat2W64 (SS c) = 1 + snat2W64 c
hash :: BS.ByteString -> Digest
hash = Digest . Hash.hash
hashStr :: String -> Digest
hashStr = hash . BS8.pack
digestConcat :: [Digest] -> Digest
digestConcat = hash . BA.concat . map getDigest
class Digestible (v :: *) where
digest :: v -> Digest
instance Digestible Word64 where
digest = hash . BA.fromW64BE
class DigestibleHO (f :: k -> *) where
digestHO :: forall ki . f ki -> Digest
instance DigestibleHO (Const Void) where
digestHO (Const _impossible) = error "DigestibleHO (Const Void)"
authPeel' :: forall sum ann i
. (forall ix . ann ix -> Digest)
-> Word64
-> Constr sum i
-> NP ann (Lkup i sum)
-> Digest
authPeel' proj salt cnstr p
= digestConcat $ ([digest (constr2W64 cnstr) , digest salt] ++)
$ elimNP proj p
where
constr2W64 :: Constr sum' n -> Word64
constr2W64 CZ = 0
constr2W64 (CS c) = 1 + constr2W64 c
authPeel :: forall codes ix ann i
. IsNat ix
=> (forall iy . ann iy -> Digest)
-> Proxy codes
-> Proxy ix
-> Constr (Lkup ix codes) i
-> NP ann (Lkup i (Lkup ix codes))
-> Digest
authPeel proj _ pix = authPeel' proj (snat2W64 $ getSNat pix)