-- |
-- Module      : Crypto.PubKey.Ed448
-- License     : BSD-style
-- Maintainer  : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability   : experimental
-- Portability : unknown
--
-- Ed448 support
--
-- Internally uses Decaf point compression to omit the cofactor
-- and implementation by Mike Hamburg.  Externally API and
-- data types are compatible with the encoding specified in RFC 8032.
--
{-# LANGUAGE BangPatterns               #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.PubKey.Ed448
    ( SecretKey
    , PublicKey
    , Signature
    -- * Size constants
    , publicKeySize
    , secretKeySize
    , signatureSize
    -- * Smart constructors
    , signature
    , publicKey
    , secretKey
    -- * Methods
    , 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

-- | An Ed448 Secret key
newtype SecretKey = SecretKey ScrubbedBytes
    deriving (Int -> SecretKey -> ShowS
[SecretKey] -> ShowS
SecretKey -> String
(Int -> SecretKey -> ShowS)
-> (SecretKey -> String)
-> ([SecretKey] -> ShowS)
-> Show SecretKey
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SecretKey -> ShowS
showsPrec :: Int -> SecretKey -> ShowS
$cshow :: SecretKey -> String
show :: SecretKey -> String
$cshowList :: [SecretKey] -> ShowS
showList :: [SecretKey] -> ShowS
Show,SecretKey -> SecretKey -> Bool
(SecretKey -> SecretKey -> Bool)
-> (SecretKey -> SecretKey -> Bool) -> Eq SecretKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SecretKey -> SecretKey -> Bool
== :: SecretKey -> SecretKey -> Bool
$c/= :: SecretKey -> SecretKey -> Bool
/= :: SecretKey -> SecretKey -> Bool
Eq,SecretKey -> Int
(SecretKey -> Int)
-> (forall p a. SecretKey -> (Ptr p -> IO a) -> IO a)
-> (forall p. SecretKey -> Ptr p -> IO ())
-> ByteArrayAccess SecretKey
forall p. SecretKey -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
$clength :: SecretKey -> Int
length :: SecretKey -> Int
$cwithByteArray :: forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
withByteArray :: forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
$ccopyByteArrayToPtr :: forall p. SecretKey -> Ptr p -> IO ()
copyByteArrayToPtr :: forall p. SecretKey -> Ptr p -> IO ()
ByteArrayAccess,SecretKey -> ()
(SecretKey -> ()) -> NFData SecretKey
forall a. (a -> ()) -> NFData a
$crnf :: SecretKey -> ()
rnf :: SecretKey -> ()
NFData)

-- | An Ed448 public key
newtype PublicKey = PublicKey Bytes
    deriving (Int -> PublicKey -> ShowS
[PublicKey] -> ShowS
PublicKey -> String
(Int -> PublicKey -> ShowS)
-> (PublicKey -> String)
-> ([PublicKey] -> ShowS)
-> Show PublicKey
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PublicKey -> ShowS
showsPrec :: Int -> PublicKey -> ShowS
$cshow :: PublicKey -> String
show :: PublicKey -> String
$cshowList :: [PublicKey] -> ShowS
showList :: [PublicKey] -> ShowS
Show,PublicKey -> PublicKey -> Bool
(PublicKey -> PublicKey -> Bool)
-> (PublicKey -> PublicKey -> Bool) -> Eq PublicKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PublicKey -> PublicKey -> Bool
== :: PublicKey -> PublicKey -> Bool
$c/= :: PublicKey -> PublicKey -> Bool
/= :: PublicKey -> PublicKey -> Bool
Eq,PublicKey -> Int
(PublicKey -> Int)
-> (forall p a. PublicKey -> (Ptr p -> IO a) -> IO a)
-> (forall p. PublicKey -> Ptr p -> IO ())
-> ByteArrayAccess PublicKey
forall p. PublicKey -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
$clength :: PublicKey -> Int
length :: PublicKey -> Int
$cwithByteArray :: forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
withByteArray :: forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
$ccopyByteArrayToPtr :: forall p. PublicKey -> Ptr p -> IO ()
copyByteArrayToPtr :: forall p. PublicKey -> Ptr p -> IO ()
ByteArrayAccess,PublicKey -> ()
(PublicKey -> ()) -> NFData PublicKey
forall a. (a -> ()) -> NFData a
$crnf :: PublicKey -> ()
rnf :: PublicKey -> ()
NFData)

-- | An Ed448 signature
newtype Signature = Signature Bytes
    deriving (Int -> Signature -> ShowS
[Signature] -> ShowS
Signature -> String
(Int -> Signature -> ShowS)
-> (Signature -> String)
-> ([Signature] -> ShowS)
-> Show Signature
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Signature -> ShowS
showsPrec :: Int -> Signature -> ShowS
$cshow :: Signature -> String
show :: Signature -> String
$cshowList :: [Signature] -> ShowS
showList :: [Signature] -> ShowS
Show,Signature -> Signature -> Bool
(Signature -> Signature -> Bool)
-> (Signature -> Signature -> Bool) -> Eq Signature
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Signature -> Signature -> Bool
== :: Signature -> Signature -> Bool
$c/= :: Signature -> Signature -> Bool
/= :: Signature -> Signature -> Bool
Eq,Signature -> Int
(Signature -> Int)
-> (forall p a. Signature -> (Ptr p -> IO a) -> IO a)
-> (forall p. Signature -> Ptr p -> IO ())
-> ByteArrayAccess Signature
forall p. Signature -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. Signature -> (Ptr p -> IO a) -> IO a
$clength :: Signature -> Int
length :: Signature -> Int
$cwithByteArray :: forall p a. Signature -> (Ptr p -> IO a) -> IO a
withByteArray :: forall p a. Signature -> (Ptr p -> IO a) -> IO a
$ccopyByteArrayToPtr :: forall p. Signature -> Ptr p -> IO ()
copyByteArrayToPtr :: forall p. Signature -> Ptr p -> IO ()
ByteArrayAccess,Signature -> ()
(Signature -> ()) -> NFData Signature
forall a. (a -> ()) -> NFData a
$crnf :: Signature -> ()
rnf :: Signature -> ()
NFData)

-- | Try to build a public key from a bytearray
publicKey :: ByteArrayAccess ba => ba -> CryptoFailable PublicKey
publicKey :: forall ba. ByteArrayAccess ba => ba -> CryptoFailable PublicKey
publicKey ba
bs
    | ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
publicKeySize =
        PublicKey -> CryptoFailable PublicKey
forall a. a -> CryptoFailable a
CryptoPassed (PublicKey -> CryptoFailable PublicKey)
-> PublicKey -> CryptoFailable PublicKey
forall a b. (a -> b) -> a -> b
$ Bytes -> PublicKey
PublicKey (Bytes -> PublicKey) -> Bytes -> PublicKey
forall a b. (a -> b) -> a -> b
$ ba -> (Ptr Any -> IO ()) -> Bytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze ba
bs (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
    | Bool
otherwise =
        CryptoError -> CryptoFailable PublicKey
forall a. CryptoError -> CryptoFailable a
CryptoFailed (CryptoError -> CryptoFailable PublicKey)
-> CryptoError -> CryptoFailable PublicKey
forall a b. (a -> b) -> a -> b
$ CryptoError
CryptoError_PublicKeySizeInvalid

-- | Try to build a secret key from a bytearray
secretKey :: ByteArrayAccess ba => ba -> CryptoFailable SecretKey
secretKey :: forall ba. ByteArrayAccess ba => ba -> CryptoFailable SecretKey
secretKey ba
bs
    | ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
secretKeySize = IO (CryptoFailable SecretKey) -> CryptoFailable SecretKey
forall a. IO a -> a
unsafeDoIO (IO (CryptoFailable SecretKey) -> CryptoFailable SecretKey)
-> IO (CryptoFailable SecretKey) -> CryptoFailable SecretKey
forall a b. (a -> b) -> a -> b
$ ba
-> (Ptr Any -> IO (CryptoFailable SecretKey))
-> IO (CryptoFailable SecretKey)
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
bs Ptr Any -> IO (CryptoFailable SecretKey)
forall {p}. p -> IO (CryptoFailable SecretKey)
initialize
    | Bool
otherwise                    = CryptoError -> CryptoFailable SecretKey
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SecretKeyStructureInvalid
  where
        initialize :: p -> IO (CryptoFailable SecretKey)
initialize p
inp = do
            Bool
valid <- p -> IO Bool
forall {m :: * -> *} {p}. Monad m => p -> m Bool
isValidPtr p
inp
            if Bool
valid
                then (SecretKey -> CryptoFailable SecretKey
forall a. a -> CryptoFailable a
CryptoPassed (SecretKey -> CryptoFailable SecretKey)
-> (ScrubbedBytes -> SecretKey)
-> ScrubbedBytes
-> CryptoFailable SecretKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScrubbedBytes -> SecretKey
SecretKey) (ScrubbedBytes -> CryptoFailable SecretKey)
-> IO ScrubbedBytes -> IO (CryptoFailable SecretKey)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ba -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> IO bs2
B.copy ba
bs (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
                else CryptoFailable SecretKey -> IO (CryptoFailable SecretKey)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CryptoFailable SecretKey -> IO (CryptoFailable SecretKey))
-> CryptoFailable SecretKey -> IO (CryptoFailable SecretKey)
forall a b. (a -> b) -> a -> b
$ CryptoError -> CryptoFailable SecretKey
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SecretKeyStructureInvalid
        isValidPtr :: p -> m Bool
isValidPtr p
_ =
            Bool -> m Bool
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
{-# NOINLINE secretKey #-}

-- | Try to build a signature from a bytearray
signature :: ByteArrayAccess ba => ba -> CryptoFailable Signature
signature :: forall ba. ByteArrayAccess ba => ba -> CryptoFailable Signature
signature ba
bs
    | ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
signatureSize =
        Signature -> CryptoFailable Signature
forall a. a -> CryptoFailable a
CryptoPassed (Signature -> CryptoFailable Signature)
-> Signature -> CryptoFailable Signature
forall a b. (a -> b) -> a -> b
$ Bytes -> Signature
Signature (Bytes -> Signature) -> Bytes -> Signature
forall a b. (a -> b) -> a -> b
$ ba -> (Ptr Any -> IO ()) -> Bytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze ba
bs (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
    | Bool
otherwise =
        CryptoError -> CryptoFailable Signature
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SecretKeyStructureInvalid

-- | Create a public key from a secret key
toPublic :: SecretKey -> PublicKey
toPublic :: SecretKey -> PublicKey
toPublic (SecretKey ScrubbedBytes
sec) = Bytes -> PublicKey
PublicKey (Bytes -> PublicKey)
-> ((Ptr PublicKey -> IO ()) -> Bytes)
-> (Ptr PublicKey -> IO ())
-> PublicKey
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
    Int -> (Ptr PublicKey -> IO ()) -> Bytes
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
publicKeySize ((Ptr PublicKey -> IO ()) -> PublicKey)
-> (Ptr PublicKey -> IO ()) -> PublicKey
forall a b. (a -> b) -> a -> b
$ \Ptr PublicKey
result ->
    ScrubbedBytes -> (Ptr SecretKey -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
sec              ((Ptr SecretKey -> IO ()) -> IO ())
-> (Ptr SecretKey -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr SecretKey
psec   ->
        Ptr PublicKey -> Ptr SecretKey -> IO ()
decaf_ed448_derive_public_key Ptr PublicKey
result Ptr SecretKey
psec
{-# NOINLINE toPublic #-}

-- | Sign a message using the key pair
sign :: ByteArrayAccess ba => SecretKey -> PublicKey -> ba -> Signature
sign :: forall ba.
ByteArrayAccess ba =>
SecretKey -> PublicKey -> ba -> Signature
sign SecretKey
secret PublicKey
public ba
message =
    Bytes -> Signature
Signature (Bytes -> Signature) -> Bytes -> Signature
forall a b. (a -> b) -> a -> b
$ Int -> (Ptr Signature -> IO ()) -> Bytes
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
signatureSize ((Ptr Signature -> IO ()) -> Bytes)
-> (Ptr Signature -> IO ()) -> Bytes
forall a b. (a -> b) -> a -> b
$ \Ptr Signature
sig ->
        SecretKey -> (Ptr SecretKey -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
withByteArray SecretKey
secret  ((Ptr SecretKey -> IO ()) -> IO ())
-> (Ptr SecretKey -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr SecretKey
sec ->
        PublicKey -> (Ptr PublicKey -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
withByteArray PublicKey
public  ((Ptr PublicKey -> IO ()) -> IO ())
-> (Ptr PublicKey -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr PublicKey
pub ->
        ba -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
message ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
msg ->
             Ptr Signature
-> Ptr SecretKey
-> Ptr PublicKey
-> Ptr Word8
-> CSize
-> Word8
-> Ptr Word8
-> Word8
-> IO ()
decaf_ed448_sign Ptr Signature
sig Ptr SecretKey
sec Ptr PublicKey
pub Ptr Word8
msg (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
msgLen) Word8
0 Ptr Word8
no_context Word8
0
  where
    !msgLen :: Int
msgLen = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
message

-- | Verify a message
verify :: ByteArrayAccess ba => PublicKey -> ba -> Signature -> Bool
verify :: forall ba.
ByteArrayAccess ba =>
PublicKey -> ba -> Signature -> Bool
verify PublicKey
public ba
message Signature
signatureVal = IO Bool -> Bool
forall a. IO a -> a
unsafeDoIO (IO Bool -> Bool) -> IO Bool -> Bool
forall a b. (a -> b) -> a -> b
$
    Signature -> (Ptr Signature -> IO Bool) -> IO Bool
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. Signature -> (Ptr p -> IO a) -> IO a
withByteArray Signature
signatureVal ((Ptr Signature -> IO Bool) -> IO Bool)
-> (Ptr Signature -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr Signature
sig ->
    PublicKey -> (Ptr PublicKey -> IO Bool) -> IO Bool
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
withByteArray PublicKey
public       ((Ptr PublicKey -> IO Bool) -> IO Bool)
-> (Ptr PublicKey -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr PublicKey
pub ->
    ba -> (Ptr Word8 -> IO Bool) -> IO Bool
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
message      ((Ptr Word8 -> IO Bool) -> IO Bool)
-> (Ptr Word8 -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
msg -> do
      CInt
r <- Ptr Signature
-> Ptr PublicKey
-> Ptr Word8
-> CSize
-> Word8
-> Ptr Word8
-> Word8
-> IO CInt
decaf_ed448_verify Ptr Signature
sig Ptr PublicKey
pub Ptr Word8
msg (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
msgLen) Word8
0 Ptr Word8
no_context Word8
0
      Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CInt
r CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
/= CInt
0)
  where
    !msgLen :: Int
msgLen = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
message

-- | Generate a secret key
generateSecretKey :: MonadRandom m => m SecretKey
generateSecretKey :: forall (m :: * -> *). MonadRandom m => m SecretKey
generateSecretKey = ScrubbedBytes -> SecretKey
SecretKey (ScrubbedBytes -> SecretKey) -> m ScrubbedBytes -> m SecretKey
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> m ScrubbedBytes
forall byteArray. ByteArray byteArray => Int -> m byteArray
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes Int
secretKeySize

-- | A public key is 57 bytes
publicKeySize :: Int
publicKeySize :: Int
publicKeySize = Int
57

-- | A secret key is 57 bytes
secretKeySize :: Int
secretKeySize :: Int
secretKeySize = Int
57

-- | A signature is 114 bytes
signatureSize :: Int
signatureSize :: Int
signatureSize = Int
114

no_context :: Ptr Word8
no_context :: Ptr Word8
no_context = Ptr Word8
forall a. Ptr a
nullPtr -- not supported yet

foreign import ccall "cryptonite_decaf_ed448_derive_public_key"
    decaf_ed448_derive_public_key :: Ptr PublicKey -- public key
                                  -> Ptr SecretKey -- secret key
                                  -> IO ()

foreign import ccall "cryptonite_decaf_ed448_sign"
    decaf_ed448_sign :: Ptr Signature -- signature
                     -> Ptr SecretKey -- secret
                     -> Ptr PublicKey -- public
                     -> Ptr Word8     -- message
                     -> CSize         -- message len
                     -> Word8         -- prehashed
                     -> Ptr Word8     -- context
                     -> Word8         -- context len
                     -> IO ()

foreign import ccall "cryptonite_decaf_ed448_verify"
    decaf_ed448_verify :: Ptr Signature -- signature
                       -> Ptr PublicKey -- public
                       -> Ptr Word8     -- message
                       -> CSize         -- message len
                       -> Word8         -- prehashed
                       -> Ptr Word8     -- context
                       -> Word8         -- context len
                       -> IO CInt