module Botan.Hash.Skein
( Skein512(..)
, Skein512Digest(..)
, Skein512'(..)
, Skein512Digest'(..)
, skein512
, skein512Lazy
) where

import GHC.TypeLits

import Data.Maybe
import Data.Proxy

import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Char8 as Char8
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

-- Skein type

type Skein512 (n :: Nat) = Skein512' n ""
type Skein512Digest (n :: Nat) = Skein512Digest' n ""

data Skein512' (n :: Nat) (ps :: Symbol)
type Skein512Digest' (n :: Nat) (ps :: Symbol) = Digest (Skein512' n ps)

type SkeinSize (n :: Nat) = (KnownNat n, (1 <=? n) ~ True, Mod n 8 ~ 0, (n <=? 512) ~ True)
type SkeinPersonalizationString (ps :: Symbol) = (KnownSymbol ps)

newtype instance Digest (Skein512' n ps) = SkeinDigest
    { forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> ByteString
getSkeinByteString :: ByteString {- ByteVector n -} }
    deriving newtype (Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
(Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool)
-> (Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool)
-> Eq (Digest (Skein512' n ps))
forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
== :: Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
$c/= :: forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
/= :: Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
Eq, Eq (Digest (Skein512' n ps))
Eq (Digest (Skein512' n ps)) =>
(Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Ordering)
-> (Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool)
-> (Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool)
-> (Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool)
-> (Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool)
-> (Digest (Skein512' n ps)
    -> Digest (Skein512' n ps) -> Digest (Skein512' n ps))
-> (Digest (Skein512' n ps)
    -> Digest (Skein512' n ps) -> Digest (Skein512' n ps))
-> Ord (Digest (Skein512' n ps))
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Ordering
Digest (Skein512' n ps)
-> Digest (Skein512' n ps) -> Digest (Skein512' n ps)
forall (n :: Nat) (ps :: Symbol). Eq (Digest (Skein512' n ps))
forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Ordering
forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps)
-> Digest (Skein512' n ps) -> Digest (Skein512' n ps)
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) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Ordering
compare :: Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Ordering
$c< :: forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
< :: Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
$c<= :: forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
<= :: Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
$c> :: forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
> :: Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
$c>= :: forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
>= :: Digest (Skein512' n ps) -> Digest (Skein512' n ps) -> Bool
$cmax :: forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps)
-> Digest (Skein512' n ps) -> Digest (Skein512' n ps)
max :: Digest (Skein512' n ps)
-> Digest (Skein512' n ps) -> Digest (Skein512' n ps)
$cmin :: forall (n :: Nat) (ps :: Symbol).
Digest (Skein512' n ps)
-> Digest (Skein512' n ps) -> Digest (Skein512' n ps)
min :: Digest (Skein512' n ps)
-> Digest (Skein512' n ps) -> Digest (Skein512' n ps)
Ord)

instance Show (Digest (Skein512' n ps)) where
    show :: Digest (Skein512' n ps) -> String
    show :: Digest (Skein512' n ps) -> String
show (SkeinDigest 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 (SkeinSize n, SkeinPersonalizationString ps) => Hash (Skein512' n ps) where
    hash :: ByteString -> Digest (Skein512' n ps)
    hash :: ByteString -> Digest (Skein512' n ps)
hash = ByteString -> Digest (Skein512' n ps)
forall (n :: Nat) (ps :: Symbol).
ByteString -> Digest (Skein512' n ps)
SkeinDigest (ByteString -> Digest (Skein512' n ps))
-> (ByteString -> ByteString)
-> ByteString
-> Digest (Skein512' n ps)
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
        ps :: ByteString
ps = String -> ByteString
Char8.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Proxy ps -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (Proxy ps -> String) -> Proxy ps -> String
forall a b. (a -> b) -> a -> b
$ forall {k} (t :: k). Proxy t
forall (t :: Symbol). Proxy t
Proxy @ps
        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 -> ByteString -> Maybe Hash
Botan.skein512 Int
n ByteString
ps

instance (SkeinSize n, SkeinPersonalizationString ps) => IncrementalHash (Skein512' n ps) where
    hashLazy :: Lazy.ByteString -> Digest (Skein512' n ps)
    hashLazy :: ByteString -> Digest (Skein512' n ps)
hashLazy = ByteString -> Digest (Skein512' n ps)
forall (n :: Nat) (ps :: Symbol).
ByteString -> Digest (Skein512' n ps)
SkeinDigest (ByteString -> Digest (Skein512' n ps))
-> (ByteString -> ByteString)
-> ByteString
-> Digest (Skein512' n ps)
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
        ps :: ByteString
ps = String -> ByteString
Char8.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Proxy ps -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (Proxy ps -> String) -> Proxy ps -> String
forall a b. (a -> b) -> a -> b
$ forall {k} (t :: k). Proxy t
forall (t :: Symbol). Proxy t
Proxy @ps
        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 -> ByteString -> Maybe Hash
Botan.skein512 Int
n ByteString
ps

-- Skein hash

skein512 :: (SkeinSize n, SkeinPersonalizationString ps) => ByteString -> Skein512Digest' n ps
skein512 :: forall (n :: Nat) (ps :: Symbol).
(SkeinSize n, SkeinPersonalizationString ps) =>
ByteString -> Digest (Skein512' n ps)
skein512 = ByteString -> Digest (Skein512' n ps)
forall hash. Hash hash => ByteString -> Digest hash
hash

skein512Lazy :: (SkeinSize n, SkeinPersonalizationString ps) => Lazy.ByteString -> Skein512Digest' n ps
skein512Lazy :: forall (n :: Nat) (ps :: Symbol).
(SkeinSize n, SkeinPersonalizationString ps) =>
ByteString -> Digest (Skein512' n ps)
skein512Lazy = ByteString -> Digest (Skein512' n ps)
forall hash. IncrementalHash hash => ByteString -> Digest hash
hashLazy