saltine-0.2.2.0: src/Crypto/Saltine/Internal/Sign.hs
{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, DeriveGeneric, ForeignFunctionInterface #-}
-- |
-- Module : Crypto.Saltine.Internal.Sign
-- Copyright : (c) Max Amanshauser 2021
-- License : MIT
--
-- Maintainer : max@lambdalifting.org
-- Stability : experimental
-- Portability : non-portable
--
module Crypto.Saltine.Internal.Sign (
sign_bytes
, sign_publickeybytes
, sign_secretkeybytes
, c_sign_keypair
, c_sign
, c_sign_open
, c_sign_detached
, c_sign_verify_detached
, c_sign_ed25519_pk_to_curve25519
, c_sign_ed25519_sk_to_curve25519
, SecretKey(..)
, PublicKey(..)
, Keypair(..)
, Signature(..)
) where
import Control.DeepSeq (NFData)
import Crypto.Saltine.Class
import Crypto.Saltine.Core.Hash (shorthash)
import Crypto.Saltine.Internal.Hash (nullShKey)
import Crypto.Saltine.Internal.Util as U
import Data.ByteString (ByteString)
import Data.Data (Data, Typeable)
import Data.Hashable (Hashable)
import Data.Monoid
import Foreign.C
import Foreign.Ptr
import GHC.Generics (Generic)
import qualified Data.ByteString as S
-- | An opaque 'box' cryptographic secret key.
newtype SecretKey = SK { unSK :: ByteString } deriving (Ord, Hashable, Data, Typeable, Generic, NFData)
instance Eq SecretKey where
SK a == SK b = U.compare a b
instance Show SecretKey where
show k = "Sign.SecretKey {hashesTo = \"" <> (bin2hex . shorthash nullShKey $ encode k) <> "\"}"
instance IsEncoding SecretKey where
decode v = if S.length v == sign_secretkeybytes
then Just (SK v)
else Nothing
{-# INLINE decode #-}
encode (SK v) = v
{-# INLINE encode #-}
-- | An opaque 'box' cryptographic public key.
newtype PublicKey = PK { unPK :: ByteString } deriving (Ord, Data, Typeable, Hashable, Generic, NFData)
instance Eq PublicKey where
PK a == PK b = U.compare a b
instance Show PublicKey where
show k = "Sign.PublicKey {hashesTo = \"" <> (bin2hex . shorthash nullShKey $ encode k) <> "\"}"
instance IsEncoding PublicKey where
decode v = if S.length v == sign_publickeybytes
then Just (PK v)
else Nothing
{-# INLINE decode #-}
encode (PK v) = v
{-# INLINE encode #-}
-- | A convenience type for keypairs
data Keypair = Keypair {
secretKey :: SecretKey
, publicKey :: PublicKey
} deriving (Ord, Data, Typeable, Generic)
instance Eq Keypair where
kp1 == kp2 = U.compare (encode $ secretKey kp1) (encode $ secretKey kp2)
!&&! U.compare (encode $ publicKey kp1) (encode $ publicKey kp2)
instance Show Keypair where
show k = "Sign.Keypair {secretKey = " <> show (secretKey k) <> ", publicKey = " <> show (publicKey k) <> "}"
instance Hashable Keypair
instance NFData Keypair
-- | A signature for a Message
newtype Signature = Signature { unSignature :: ByteString } deriving (Ord, Data, Typeable, Hashable, Generic, NFData)
instance Eq Signature where
Signature a == Signature b = U.compare a b
instance Show Signature where
show k = "Sign.Signature " <> bin2hex (encode k)
-- | Actual signatures may be shorter, but not when generated with saltine.
instance IsEncoding Signature where
decode v = if S.length v == sign_bytes
then Just (Signature v)
else Nothing
{-# INLINE decode #-}
encode (Signature s) = s
{-# INLINE encode #-}
sign_bytes, sign_publickeybytes, sign_secretkeybytes :: Int
-- Signatures
-- | The maximum size of a signature prepended to a message to form a
-- signed message.
sign_bytes = fromIntegral c_crypto_sign_bytes
-- | The size of a public key for signing verification
sign_publickeybytes = fromIntegral c_crypto_sign_publickeybytes
-- | The size of a secret key for signing
sign_secretkeybytes = fromIntegral c_crypto_sign_secretkeybytes
-- src/libsodium/crypto_sign/crypto_sign.c
foreign import ccall "crypto_sign_bytes"
c_crypto_sign_bytes :: CSize
foreign import ccall "crypto_sign_publickeybytes"
c_crypto_sign_publickeybytes :: CSize
foreign import ccall "crypto_sign_secretkeybytes"
c_crypto_sign_secretkeybytes :: CSize
foreign import ccall "crypto_sign_keypair"
c_sign_keypair :: Ptr CChar
-- ^ Public key output buffer
-> Ptr CChar
-- ^ Secret key output buffer
-> IO CInt
-- ^ Always 0
foreign import ccall "crypto_sign"
c_sign :: Ptr CChar
-- ^ Signed message output buffer
-> Ptr CULLong
-- ^ Length of signed message
-> Ptr CChar
-- ^ Constant message buffer
-> CULLong
-- ^ Length of message input buffer
-> Ptr CChar
-- ^ Constant secret key buffer
-> IO CInt
-- ^ Always 0
foreign import ccall "crypto_sign_open"
c_sign_open :: Ptr CChar
-- ^ Message output buffer
-> Ptr CULLong
-- ^ Length of message
-> Ptr CChar
-- ^ Constant signed message buffer
-> CULLong
-- ^ Length of signed message buffer
-> Ptr CChar
-- ^ Public key buffer
-> IO CInt
-- ^ 0 if signature is verifiable, -1 otherwise
foreign import ccall "crypto_sign_detached"
c_sign_detached :: Ptr CChar
-- ^ Signature output buffer
-> Ptr CULLong
-- ^ Length of the signature
-> Ptr CChar
-- ^ Constant message buffer
-> CULLong
-- ^ Length of message buffer
-> Ptr CChar
-- ^ Constant secret key buffer
-> IO CInt
foreign import ccall "crypto_sign_verify_detached"
c_sign_verify_detached :: Ptr CChar
-- ^ Signature buffer
-> Ptr CChar
-- ^ Constant signed message buffer
-> CULLong
-- ^ Length of signed message buffer
-> Ptr CChar
-- ^ Public key buffer
-> IO CInt
foreign import ccall "crypto_sign_ed25519_pk_to_curve25519"
c_sign_ed25519_pk_to_curve25519 :: Ptr CChar
-- ^ X25519 public key output buffer
-> Ptr CChar
-- ^ Ed25519 public key buffer
-> IO CInt
foreign import ccall "crypto_sign_ed25519_sk_to_curve25519"
c_sign_ed25519_sk_to_curve25519 :: Ptr CChar
-- ^ X25519 secret key output buffer
-> Ptr CChar
-- ^ Ed25519 secret key buffer
-> IO CInt