{-# 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 Crypto.Hash             (SHA256)
import Data.ByteArray          (ByteArrayAccess, convert)
import Data.ByteArray.Encoding (Base (Base16), convertToBase)
import Data.ByteString         (ByteString)
import GHC.Generics            (Generic)

import qualified Crypto.Hash
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, SHA256Digest -> Int
SHA256Digest -> Ptr p -> IO ()
SHA256Digest -> (Ptr p -> IO a) -> IO a
(SHA256Digest -> Int)
-> (forall p a. SHA256Digest -> (Ptr p -> IO a) -> IO a)
-> (forall p. SHA256Digest -> Ptr p -> IO ())
-> ByteArrayAccess SHA256Digest
forall p. SHA256Digest -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. SHA256Digest -> (Ptr p -> IO a) -> IO a
copyByteArrayToPtr :: SHA256Digest -> Ptr p -> IO ()
$ccopyByteArrayToPtr :: forall p. SHA256Digest -> Ptr p -> IO ()
withByteArray :: SHA256Digest -> (Ptr p -> IO a) -> IO a
$cwithByteArray :: forall p a. SHA256Digest -> (Ptr p -> IO a) -> IO a
length :: SHA256Digest -> Int
$clength :: SHA256Digest -> Int
ByteArrayAccess)

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 -> SHA256Digest
SHA256Digest (ByteString -> SHA256Digest)
-> (Digest SHA256 -> ByteString) -> Digest SHA256 -> SHA256Digest
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Digest SHA256 -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert (Digest SHA256 -> SHA256Digest)
-> Maybe (Digest SHA256) -> Maybe SHA256Digest
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Digest SHA256)
mh
  where
    mh :: Maybe (Digest SHA256)
mh = ByteString -> Maybe (Digest SHA256)
forall a ba.
(HashAlgorithm a, ByteArrayAccess ba) =>
ba -> Maybe (Digest a)
Crypto.Hash.digestFromByteString ByteString
bytes :: Maybe (Crypto.Hash.Digest SHA256)

-- | Hash a `ByteString` and return the hash as a `SHA256Digest`
sha256Hash :: ByteString -> SHA256Digest
sha256Hash :: ByteString -> SHA256Digest
sha256Hash ByteString
bytes = ByteString -> SHA256Digest
SHA256Digest (ByteString -> SHA256Digest) -> ByteString -> SHA256Digest
forall a b. (a -> b) -> a -> b
$ Digest SHA256 -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert Digest SHA256
h
  where
    h :: Digest SHA256
h = ByteString -> Digest SHA256
forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
ba -> Digest a
Crypto.Hash.hash ByteString
bytes :: Crypto.Hash.Digest SHA256

-- | '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
$ Base -> ByteString -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
Base -> bin -> bout
convertToBase Base
Base16 ByteString
bytes