module Botan.Hash.SHA3
( SHA3(..)
, SHA3Size(..)
, SHA3Digest(..)
, sha3
, sha3Lazy
, SHA3_224(..)
, SHA3_224Digest(..)
, sha3_224
, sha3_224Lazy
, SHA3_256(..)
, SHA3_256Digest(..)
, sha3_256
, sha3_256Lazy
, SHA3_384(..)
, SHA3_384Digest(..)
, sha3_384
, sha3_384Lazy
, SHA3_512(..)
, SHA3_512Digest(..)
, sha3_512
, sha3_512Lazy
) where

import GHC.TypeLits

import Data.Maybe
import Data.Proxy

import Data.Type.Bool
import Data.Type.Equality

import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as Lazy
import qualified Data.Text as Text

import qualified Botan.Hash as Botan
import qualified Botan.Utility as Botan

import Botan.Hash.Class
import Botan.Prelude

-- SHA3 type

data SHA3 (n :: Nat)

-- NOTE: This produces some nasty errors
type SHA3Size (n :: Nat) = (KnownNat n, (n == 224 || n == 256 || n == 384 || n == 512) ~ True)

type SHA3Digest n = Digest (SHA3 n)

newtype instance Digest (SHA3 n) = SHA3Digest
    { forall (n :: Nat). Digest (SHA3 n) -> ByteString
getSHA3ByteString :: ByteString {- ByteVector n -} }
    deriving newtype (Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
(Digest (SHA3 n) -> Digest (SHA3 n) -> Bool)
-> (Digest (SHA3 n) -> Digest (SHA3 n) -> Bool)
-> Eq (Digest (SHA3 n))
forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
== :: Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
$c/= :: forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
/= :: Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
Eq, Eq (Digest (SHA3 n))
Eq (Digest (SHA3 n)) =>
(Digest (SHA3 n) -> Digest (SHA3 n) -> Ordering)
-> (Digest (SHA3 n) -> Digest (SHA3 n) -> Bool)
-> (Digest (SHA3 n) -> Digest (SHA3 n) -> Bool)
-> (Digest (SHA3 n) -> Digest (SHA3 n) -> Bool)
-> (Digest (SHA3 n) -> Digest (SHA3 n) -> Bool)
-> (Digest (SHA3 n) -> Digest (SHA3 n) -> Digest (SHA3 n))
-> (Digest (SHA3 n) -> Digest (SHA3 n) -> Digest (SHA3 n))
-> Ord (Digest (SHA3 n))
Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
Digest (SHA3 n) -> Digest (SHA3 n) -> Ordering
Digest (SHA3 n) -> Digest (SHA3 n) -> Digest (SHA3 n)
forall (n :: Nat). Eq (Digest (SHA3 n))
forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Ordering
forall (n :: Nat).
Digest (SHA3 n) -> Digest (SHA3 n) -> Digest (SHA3 n)
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
$ccompare :: forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Ordering
compare :: Digest (SHA3 n) -> Digest (SHA3 n) -> Ordering
$c< :: forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
< :: Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
$c<= :: forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
<= :: Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
$c> :: forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
> :: Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
$c>= :: forall (n :: Nat). Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
>= :: Digest (SHA3 n) -> Digest (SHA3 n) -> Bool
$cmax :: forall (n :: Nat).
Digest (SHA3 n) -> Digest (SHA3 n) -> Digest (SHA3 n)
max :: Digest (SHA3 n) -> Digest (SHA3 n) -> Digest (SHA3 n)
$cmin :: forall (n :: Nat).
Digest (SHA3 n) -> Digest (SHA3 n) -> Digest (SHA3 n)
min :: Digest (SHA3 n) -> Digest (SHA3 n) -> Digest (SHA3 n)
Ord)

instance Show (Digest (SHA3 n)) where
    show :: Digest (SHA3 n) -> String
    show :: Digest (SHA3 n) -> String
show (SHA3Digest ByteString
bytes) = Text -> String
Text.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ ByteString -> HexCase -> Text
Botan.hexEncode ByteString
bytes HexCase
Botan.Lower

instance (SHA3Size n) => Hash (SHA3 n) where
    hash :: ByteString -> Digest (SHA3 n)
    hash :: ByteString -> Digest (SHA3 n)
hash = ByteString -> Digest (SHA3 n)
forall (n :: Nat). ByteString -> Digest (SHA3 n)
SHA3Digest (ByteString -> Digest (SHA3 n))
-> (ByteString -> ByteString) -> ByteString -> Digest (SHA3 n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> ByteString -> ByteString
Botan.hash Hash
h where
        n :: Int
n = Integer -> Int
forall a. Num a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n -> Integer) -> Proxy n -> Integer
forall a b. (a -> b) -> a -> b
$ forall (t :: Nat). Proxy t
forall {k} (t :: k). Proxy t
Proxy @n
        h :: Hash
h = Maybe Hash -> Hash
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Hash -> Hash) -> Maybe Hash -> Hash
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Hash
Botan.sha3 Int
n

instance (SHA3Size n) => IncrementalHash (SHA3 n) where
    hashLazy :: Lazy.ByteString -> Digest (SHA3 n)
    hashLazy :: ByteString -> Digest (SHA3 n)
hashLazy = ByteString -> Digest (SHA3 n)
forall (n :: Nat). ByteString -> Digest (SHA3 n)
SHA3Digest (ByteString -> Digest (SHA3 n))
-> (ByteString -> ByteString) -> ByteString -> Digest (SHA3 n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Hash -> ByteString -> ByteString
Botan.hashLazy Hash
h where
        n :: Int
n = Integer -> Int
forall a. Num a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n -> Integer) -> Proxy n -> Integer
forall a b. (a -> b) -> a -> b
$ forall (t :: Nat). Proxy t
forall {k} (t :: k). Proxy t
Proxy @n
        h :: Hash
h = Maybe Hash -> Hash
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Hash -> Hash) -> Maybe Hash -> Hash
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Hash
Botan.sha3 Int
n

-- SHA3 hash

sha3 :: (SHA3Size n) => ByteString -> SHA3Digest n
sha3 :: forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3 = ByteString -> Digest (SHA3 n)
forall hash. Hash hash => ByteString -> Digest hash
hash

sha3Lazy :: (SHA3Size n) => Lazy.ByteString -> SHA3Digest n
sha3Lazy :: forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3Lazy = ByteString -> Digest (SHA3 n)
forall hash. IncrementalHash hash => ByteString -> Digest hash
hashLazy

type SHA3_224 = SHA3 224
type SHA3_224Digest = SHA3Digest 224

sha3_224 :: ByteString -> SHA3_224Digest
sha3_224 :: ByteString -> SHA3_224Digest
sha3_224 = forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3 @224

sha3_224Lazy :: Lazy.ByteString -> SHA3_224Digest
sha3_224Lazy :: ByteString -> SHA3_224Digest
sha3_224Lazy = forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3Lazy @224

type SHA3_256 = SHA3 256
type SHA3_256Digest = SHA3Digest 256

sha3_256 :: ByteString -> SHA3_256Digest
sha3_256 :: ByteString -> SHA3_256Digest
sha3_256 = forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3 @256

sha3_256Lazy :: Lazy.ByteString -> SHA3_256Digest
sha3_256Lazy :: ByteString -> SHA3_256Digest
sha3_256Lazy = forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3Lazy @256

type SHA3_384 = SHA3 384
type SHA3_384Digest = SHA3Digest 384

sha3_384 :: ByteString -> SHA3_384Digest
sha3_384 :: ByteString -> SHA3_384Digest
sha3_384 = forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3 @384

sha3_384Lazy :: Lazy.ByteString -> SHA3_384Digest
sha3_384Lazy :: ByteString -> SHA3_384Digest
sha3_384Lazy = forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3Lazy @384

type SHA3_512 = SHA3 512
type SHA3_512Digest = SHA3Digest 512

sha3_512 :: ByteString -> SHA3_512Digest
sha3_512 :: ByteString -> SHA3_512Digest
sha3_512 = forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3 @512

sha3_512Lazy :: Lazy.ByteString -> SHA3_512Digest
sha3_512Lazy :: ByteString -> SHA3_512Digest
sha3_512Lazy = forall (n :: Nat). SHA3Size n => ByteString -> Digest (SHA3 n)
sha3Lazy @512