{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

{-| This module provides implementations of cryptographic utilities that only
    work for GHC (as opposed to GHCJS)
-}

module Dhall.Crypto (
      SHA256Digest(..)
    , sha256DigestFromByteString
    , sha256Hash
    , toString
    ) where

import Control.DeepSeq         (NFData)
import Data.ByteString         (ByteString)
import GHC.Generics            (Generic)

import qualified Crypto.Hash.SHA256
import qualified Data.ByteString        as ByteString
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Char8  as ByteString.Char8

-- | A SHA256 digest
newtype SHA256Digest = SHA256Digest { SHA256Digest -> ByteString
unSHA256Digest :: ByteString }
  deriving (SHA256Digest -> SHA256Digest -> Bool
(SHA256Digest -> SHA256Digest -> Bool)
-> (SHA256Digest -> SHA256Digest -> Bool) -> Eq SHA256Digest
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SHA256Digest -> SHA256Digest -> Bool
$c/= :: SHA256Digest -> SHA256Digest -> Bool
== :: SHA256Digest -> SHA256Digest -> Bool
$c== :: SHA256Digest -> SHA256Digest -> Bool
Eq, (forall x. SHA256Digest -> Rep SHA256Digest x)
-> (forall x. Rep SHA256Digest x -> SHA256Digest)
-> Generic SHA256Digest
forall x. Rep SHA256Digest x -> SHA256Digest
forall x. SHA256Digest -> Rep SHA256Digest x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep SHA256Digest x -> SHA256Digest
$cfrom :: forall x. SHA256Digest -> Rep SHA256Digest x
Generic, Eq SHA256Digest
Eq SHA256Digest
-> (SHA256Digest -> SHA256Digest -> Ordering)
-> (SHA256Digest -> SHA256Digest -> Bool)
-> (SHA256Digest -> SHA256Digest -> Bool)
-> (SHA256Digest -> SHA256Digest -> Bool)
-> (SHA256Digest -> SHA256Digest -> Bool)
-> (SHA256Digest -> SHA256Digest -> SHA256Digest)
-> (SHA256Digest -> SHA256Digest -> SHA256Digest)
-> Ord SHA256Digest
SHA256Digest -> SHA256Digest -> Bool
SHA256Digest -> SHA256Digest -> Ordering
SHA256Digest -> SHA256Digest -> SHA256Digest
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SHA256Digest -> SHA256Digest -> SHA256Digest
$cmin :: SHA256Digest -> SHA256Digest -> SHA256Digest
max :: SHA256Digest -> SHA256Digest -> SHA256Digest
$cmax :: SHA256Digest -> SHA256Digest -> SHA256Digest
>= :: SHA256Digest -> SHA256Digest -> Bool
$c>= :: SHA256Digest -> SHA256Digest -> Bool
> :: SHA256Digest -> SHA256Digest -> Bool
$c> :: SHA256Digest -> SHA256Digest -> Bool
<= :: SHA256Digest -> SHA256Digest -> Bool
$c<= :: SHA256Digest -> SHA256Digest -> Bool
< :: SHA256Digest -> SHA256Digest -> Bool
$c< :: SHA256Digest -> SHA256Digest -> Bool
compare :: SHA256Digest -> SHA256Digest -> Ordering
$ccompare :: SHA256Digest -> SHA256Digest -> Ordering
$cp1Ord :: Eq SHA256Digest
Ord, SHA256Digest -> ()
(SHA256Digest -> ()) -> NFData SHA256Digest
forall a. (a -> ()) -> NFData a
rnf :: SHA256Digest -> ()
$crnf :: SHA256Digest -> ()
NFData)

instance Show SHA256Digest where
  show :: SHA256Digest -> String
show = SHA256Digest -> String
toString

{-| Attempt to interpret a `ByteString` as a `SHA256Digest`, returning
    `Nothing` if the conversion fails
-}
sha256DigestFromByteString :: ByteString -> Maybe SHA256Digest
sha256DigestFromByteString :: ByteString -> Maybe SHA256Digest
sha256DigestFromByteString ByteString
bytes
  | ByteString -> Int
ByteString.length ByteString
bytes Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
32 = SHA256Digest -> Maybe SHA256Digest
forall a. a -> Maybe a
Just (ByteString -> SHA256Digest
SHA256Digest ByteString
bytes)
  | Bool
otherwise                     = Maybe SHA256Digest
forall a. Maybe a
Nothing

-- | Hash a `ByteString` and return the hash as a `SHA256Digest`
sha256Hash :: ByteString -> SHA256Digest
sha256Hash :: ByteString -> SHA256Digest
sha256Hash = ByteString -> SHA256Digest
SHA256Digest (ByteString -> SHA256Digest)
-> (ByteString -> ByteString) -> ByteString -> SHA256Digest
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
Crypto.Hash.SHA256.hash

-- | 'String' representation of a 'SHA256Digest'
toString :: SHA256Digest -> String
toString :: SHA256Digest -> String
toString (SHA256Digest ByteString
bytes) = ByteString -> String
ByteString.Char8.unpack (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
Base16.encode ByteString
bytes