module Data.Digest.Keccak (sha3_256, shake_128) where
import qualified Data.ByteString as B
#ifdef ghcjs_HOST_OS
import GHCJS.Marshal
import GHCJS.Types
import System.IO.Unsafe
#else
import qualified "cryptonite" Crypto.Hash as S
import qualified Data.ByteArray as S
#endif
shake_128 :: Int -> B.ByteString -> B.ByteString
shake_128 numBytes bs | numBytes <=0 || numBytes > 32 = error "shake128: Invalid number of bytes"
| otherwise = shake_128_ numBytes bs
sha3_256 :: Int -> B.ByteString -> B.ByteString
sha3_256 numBytes bs | numBytes <=0 || numBytes > 32 = error "sha3_256: Invalid number of bytes"
| otherwise = sha3_256_ numBytes bs
#ifdef ghcjs_HOST_OS
shake_128_ :: Int -> B.ByteString -> B.ByteString
shake_128_ numBytes = stat (js_shake128 $ numBytes*8) numBytes
sha3_256_ :: Int -> B.ByteString -> B.ByteString
sha3_256_ = stat js_sha3_256
stat f n bs = unsafePerformIO $ do
jbs <- toJSVal $ B.unpack $ bs
Just bs' <- fromJSVal $ f jbs
return . B.take n . B.pack $ bs'
foreign import javascript unsafe "shake_128.array($2, $1)" js_shake128 :: Int -> JSVal -> JSVal
foreign import javascript unsafe "sha3_224.array($1)" js_sha3_224 :: JSVal -> JSVal
foreign import javascript unsafe "sha3_256.array($1)" js_sha3_256 :: JSVal -> JSVal
foreign import javascript unsafe "keccak_256.array($1)" js_keccak256 :: JSVal -> JSVal
#else
shake_128_ :: Int -> B.ByteString -> B.ByteString
shake_128_ = stat (S.SHAKE128 :: S.SHAKE128 256)
sha3_256_ :: Int -> B.ByteString -> B.ByteString
sha3_256_ = stat S.SHA3_256
stat
:: (S.ByteArrayAccess ba, S.HashAlgorithm alg) =>
alg -> Int -> ba -> B.ByteString
stat f numBytes = B.take numBytes . S.convert . S.hashWith f
#endif