{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.PubKey.Ed448
( SecretKey
, PublicKey
, Signature
, publicKeySize
, secretKeySize
, signatureSize
, signature
, publicKey
, secretKey
, toPublic
, sign
, verify
, generateSecretKey
) where
import Data.Word
import Foreign.C.Types
import Foreign.Ptr
import Crypto.Error
import Crypto.Internal.ByteArray (ByteArrayAccess, Bytes,
ScrubbedBytes, withByteArray)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.Compat
import Crypto.Internal.Imports
import Crypto.Random
newtype SecretKey = SecretKey ScrubbedBytes
deriving (Show,Eq,ByteArrayAccess,NFData)
newtype PublicKey = PublicKey Bytes
deriving (Show,Eq,ByteArrayAccess,NFData)
newtype Signature = Signature Bytes
deriving (Show,Eq,ByteArrayAccess,NFData)
publicKey :: ByteArrayAccess ba => ba -> CryptoFailable PublicKey
publicKey bs
| B.length bs == publicKeySize =
CryptoPassed $ PublicKey $ B.copyAndFreeze bs (\_ -> return ())
| otherwise =
CryptoFailed $ CryptoError_PublicKeySizeInvalid
secretKey :: ByteArrayAccess ba => ba -> CryptoFailable SecretKey
secretKey bs
| B.length bs == secretKeySize = unsafeDoIO $ withByteArray bs initialize
| otherwise = CryptoFailed CryptoError_SecretKeyStructureInvalid
where
initialize inp = do
valid <- isValidPtr inp
if valid
then (CryptoPassed . SecretKey) <$> B.copy bs (\_ -> return ())
else return $ CryptoFailed CryptoError_SecretKeyStructureInvalid
isValidPtr _ =
return True
{-# NOINLINE secretKey #-}
signature :: ByteArrayAccess ba => ba -> CryptoFailable Signature
signature bs
| B.length bs == signatureSize =
CryptoPassed $ Signature $ B.copyAndFreeze bs (\_ -> return ())
| otherwise =
CryptoFailed CryptoError_SecretKeyStructureInvalid
toPublic :: SecretKey -> PublicKey
toPublic (SecretKey sec) = PublicKey <$>
B.allocAndFreeze publicKeySize $ \result ->
withByteArray sec $ \psec ->
decaf_ed448_derive_public_key result psec
{-# NOINLINE toPublic #-}
sign :: ByteArrayAccess ba => SecretKey -> PublicKey -> ba -> Signature
sign secret public message =
Signature $ B.allocAndFreeze signatureSize $ \sig ->
withByteArray secret $ \sec ->
withByteArray public $ \pub ->
withByteArray message $ \msg ->
decaf_ed448_sign sig sec pub msg (fromIntegral msgLen) 0 no_context 0
where
!msgLen = B.length message
verify :: ByteArrayAccess ba => PublicKey -> ba -> Signature -> Bool
verify public message signatureVal = unsafeDoIO $
withByteArray signatureVal $ \sig ->
withByteArray public $ \pub ->
withByteArray message $ \msg -> do
r <- decaf_ed448_verify sig pub msg (fromIntegral msgLen) 0 no_context 0
return (r /= 0)
where
!msgLen = B.length message
generateSecretKey :: MonadRandom m => m SecretKey
generateSecretKey = SecretKey <$> getRandomBytes secretKeySize
publicKeySize :: Int
publicKeySize = 57
secretKeySize :: Int
secretKeySize = 57
signatureSize :: Int
signatureSize = 114
no_context :: Ptr Word8
no_context = nullPtr
foreign import ccall "cryptonite_decaf_ed448_derive_public_key"
decaf_ed448_derive_public_key :: Ptr PublicKey
-> Ptr SecretKey
-> IO ()
foreign import ccall "cryptonite_decaf_ed448_sign"
decaf_ed448_sign :: Ptr Signature
-> Ptr SecretKey
-> Ptr PublicKey
-> Ptr Word8
-> CSize
-> Word8
-> Ptr Word8
-> Word8
-> IO ()
foreign import ccall "cryptonite_decaf_ed448_verify"
decaf_ed448_verify :: Ptr Signature
-> Ptr PublicKey
-> Ptr Word8
-> CSize
-> Word8
-> Ptr Word8
-> Word8
-> IO CInt