#if __GLASGOW_HASKELL__ >= 702
#endif
module Crypto.Sign.Ed25519
(
PublicKey(..)
, SecretKey(..)
, createKeypair
, createKeypairFromSeed
, toPublicKey
, sign
, verify
, Signature(..)
, sign'
, verify'
) where
import Foreign.C.Types
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Marshal.Alloc (alloca)
import Foreign.Ptr
import Foreign.Storable
import System.IO.Unsafe (unsafePerformIO)
import Control.Monad (unless)
import Data.ByteString as S
import Data.ByteString.Internal as SI
import Data.ByteString.Unsafe as SU
import Data.Word
#if __GLASGOW_HASKELL__ >= 702
import GHC.Generics (Generic)
#endif
newtype SecretKey = SecretKey { unSecretKey :: ByteString }
deriving (Eq, Show, Ord)
newtype PublicKey = PublicKey { unPublicKey :: ByteString }
deriving (Eq, Show, Ord)
#if __GLASGOW_HASKELL__ >= 702
deriving instance Generic PublicKey
deriving instance Generic SecretKey
#endif
createKeypair :: IO (PublicKey, SecretKey)
createKeypair = do
pk <- SI.mallocByteString cryptoSignPUBLICKEYBYTES
sk <- SI.mallocByteString cryptoSignSECRETKEYBYTES
_ <- withForeignPtr pk $ \ppk -> do
_ <- withForeignPtr sk $ \psk -> do
_ <- c_crypto_sign_keypair ppk psk
return ()
return ()
return (PublicKey $ SI.fromForeignPtr pk 0 cryptoSignPUBLICKEYBYTES,
SecretKey $ SI.fromForeignPtr sk 0 cryptoSignSECRETKEYBYTES)
createKeypairFromSeed :: ByteString
-> (PublicKey, SecretKey)
createKeypairFromSeed seed = unsafePerformIO $ do
unless (S.length seed == cryptoSignSEEDBYTES)
(fail "seed has incorrect length")
pk <- SI.mallocByteString cryptoSignPUBLICKEYBYTES
sk <- SI.mallocByteString cryptoSignSECRETKEYBYTES
_ <- SU.unsafeUseAsCString seed $ \pseed -> do
_ <- withForeignPtr pk $ \ppk -> do
_ <- withForeignPtr sk $ \psk -> do
_ <- c_crypto_sign_seed_keypair ppk psk pseed
return ()
return ()
return ()
return (PublicKey $ SI.fromForeignPtr pk 0 cryptoSignPUBLICKEYBYTES,
SecretKey $ SI.fromForeignPtr sk 0 cryptoSignSECRETKEYBYTES)
toPublicKey :: SecretKey
-> PublicKey
toPublicKey = PublicKey . S.drop prefixBytes . unSecretKey
where prefixBytes = cryptoSignSECRETKEYBYTES cryptoSignPUBLICKEYBYTES
sign :: SecretKey
-> ByteString
-> ByteString
sign (SecretKey sk) xs =
unsafePerformIO . SU.unsafeUseAsCStringLen xs $ \(mstr,mlen) ->
SU.unsafeUseAsCString sk $ \psk ->
SI.createAndTrim (mlen+cryptoSignBYTES) $ \out ->
alloca $ \smlen -> do
_ <- c_crypto_sign out smlen mstr (fromIntegral mlen) psk
fromIntegral `fmap` peek smlen
verify :: PublicKey
-> ByteString
-> Bool
verify (PublicKey pk) xs =
unsafePerformIO . SU.unsafeUseAsCStringLen xs $ \(smstr,smlen) ->
SU.unsafeUseAsCString pk $ \ppk ->
alloca $ \pmlen -> do
out <- SI.mallocByteString smlen
r <- withForeignPtr out $ \pout ->
c_crypto_sign_open pout pmlen smstr (fromIntegral smlen) ppk
return (r == 0)
newtype Signature = Signature { unSignature :: ByteString }
deriving (Eq, Show, Ord)
sign' :: SecretKey
-> ByteString
-> Signature
sign' sk xs =
let sm = sign sk xs
l = S.length sm
in Signature $! S.take (l S.length xs) sm
verify' :: PublicKey
-> ByteString
-> Signature
-> Bool
verify' pk xs (Signature sig) = verify pk (sig `S.append` xs)
cryptoSignSECRETKEYBYTES :: Int
cryptoSignSECRETKEYBYTES = 64
cryptoSignPUBLICKEYBYTES :: Int
cryptoSignPUBLICKEYBYTES = 32
cryptoSignBYTES :: Int
cryptoSignBYTES = 64
cryptoSignSEEDBYTES :: Int
cryptoSignSEEDBYTES = 32
foreign import ccall unsafe "ed25519_sign_seed_keypair"
c_crypto_sign_seed_keypair :: Ptr Word8 -> Ptr Word8
-> Ptr CChar -> IO CInt
foreign import ccall unsafe "ed25519_sign_keypair"
c_crypto_sign_keypair :: Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "ed25519_sign"
c_crypto_sign :: Ptr Word8 -> Ptr CULLong ->
Ptr CChar -> CULLong -> Ptr CChar -> IO CULLong
foreign import ccall unsafe "ed25519_sign_open"
c_crypto_sign_open :: Ptr Word8 -> Ptr CULLong ->
Ptr CChar -> CULLong -> Ptr CChar -> IO CInt