module Crypto.Saltine.Core.Sign (
SecretKey, PublicKey, Keypair,
newKeypair,
sign, signOpen,
signDetached, signVerifyDetached
) where
import Crypto.Saltine.Class
import Crypto.Saltine.Internal.Util
import qualified Crypto.Saltine.Internal.ByteSizes as Bytes
import Foreign.C
import Foreign.Ptr
import Foreign.Marshal.Alloc
import Foreign.Storable
import System.IO.Unsafe
import qualified Data.ByteString as S
import Data.ByteString (ByteString)
newtype SecretKey = SK ByteString deriving (Eq, Ord)
instance IsEncoding SecretKey where
decode v = if S.length v == Bytes.signSK
then Just (SK v)
else Nothing
{-# INLINE decode #-}
encode (SK v) = v
{-# INLINE encode #-}
newtype PublicKey = PK ByteString deriving (Eq, Ord)
instance IsEncoding PublicKey where
decode v = if S.length v == Bytes.signPK
then Just (PK v)
else Nothing
{-# INLINE decode #-}
encode (PK v) = v
{-# INLINE encode #-}
type Keypair = (SecretKey, PublicKey)
newKeypair :: IO Keypair
newKeypair = do
((_err, sk), pk) <- buildUnsafeByteString' Bytes.signPK $ \pkbuf ->
buildUnsafeByteString' Bytes.signSK $ \skbuf ->
c_sign_keypair pkbuf skbuf
return (SK sk, PK pk)
sign :: SecretKey
-> ByteString
-> ByteString
sign (SK k) m = unsafePerformIO $
alloca $ \psmlen -> do
(_err, sm) <- buildUnsafeByteString' (len + Bytes.sign) $ \psmbuf ->
constByteStrings [k, m] $ \[(pk, _), (pm, _)] ->
c_sign psmbuf psmlen pm (fromIntegral len) pk
smlen <- peek psmlen
return $ S.take (fromIntegral smlen) sm
where len = S.length m
signOpen :: PublicKey
-> ByteString
-> Maybe ByteString
signOpen (PK k) sm = unsafePerformIO $
alloca $ \pmlen -> do
(err, m) <- buildUnsafeByteString' smlen $ \pmbuf ->
constByteStrings [k, sm] $ \[(pk, _), (psm, _)] ->
c_sign_open pmbuf pmlen psm (fromIntegral smlen) pk
mlen <- peek pmlen
case err of
0 -> return $ Just $ S.take (fromIntegral mlen) m
_ -> return Nothing
where smlen = S.length sm
signDetached :: SecretKey
-> ByteString
-> ByteString
signDetached (SK k) m = unsafePerformIO $
alloca $ \psmlen -> do
(_err, sm) <- buildUnsafeByteString' Bytes.sign $ \sigbuf ->
constByteStrings [k, m] $ \[(pk, _), (pm, _)] ->
c_sign_detached sigbuf psmlen pm (fromIntegral len) pk
smlen <- peek psmlen
return $ S.take (fromIntegral smlen) sm
where len = S.length m
signVerifyDetached :: PublicKey
-> ByteString
-> ByteString
-> Bool
signVerifyDetached (PK k) sig sm = unsafePerformIO $
constByteStrings [k, sig, sm] $ \[(pk, _), (psig, _), (psm, _)] -> do
res <- c_sign_verify_detached psig psm (fromIntegral len) pk
return (res == 0)
where len = S.length sm
foreign import ccall "crypto_sign_keypair"
c_sign_keypair :: Ptr CChar
-> Ptr CChar
-> IO CInt
foreign import ccall "crypto_sign"
c_sign :: Ptr CChar
-> Ptr CULLong
-> Ptr CChar
-> CULLong
-> Ptr CChar
-> IO CInt
foreign import ccall "crypto_sign_open"
c_sign_open :: Ptr CChar
-> Ptr CULLong
-> Ptr CChar
-> CULLong
-> Ptr CChar
-> IO CInt
foreign import ccall "crypto_sign_detached"
c_sign_detached :: Ptr CChar
-> Ptr CULLong
-> Ptr CChar
-> CULLong
-> Ptr CChar
-> IO CInt
foreign import ccall "crypto_sign_verify_detached"
c_sign_verify_detached :: Ptr CChar
-> Ptr CChar
-> CULLong
-> Ptr CChar
-> IO CInt