-- | Ed25519 key operations using crypton.
module Network.LibP2P.Crypto.Ed25519
  ( generateKeyPair
  , keyPairFromSeed
  ) where

import qualified Crypto.Error as CE
import qualified Crypto.PubKey.Ed25519 as Ed
import Crypto.Random (getRandomBytes)
import Data.ByteArray (convert)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Network.LibP2P.Crypto.Key

-- | Generate a new random Ed25519 key pair.
-- Returns Left on cryptographic failure (should not occur with proper RNG).
generateKeyPair :: IO (Either String KeyPair)
generateKeyPair :: IO (Either String KeyPair)
generateKeyPair = do
  seed <- Int -> IO ByteString
forall byteArray. ByteArray byteArray => Int -> IO byteArray
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes Int
32 :: IO ByteString
  pure (keyPairFromSeed seed)

-- | Create an Ed25519 key pair from a 32-byte seed.
keyPairFromSeed :: ByteString -> Either String KeyPair
keyPairFromSeed :: ByteString -> Either String KeyPair
keyPairFromSeed ByteString
seed
  | ByteString -> Int
BS.length ByteString
seed Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
32 = String -> Either String KeyPair
forall a b. a -> Either a b
Left String
"keyPairFromSeed: seed must be 32 bytes"
  | Bool
otherwise =
      case CryptoFailable SecretKey -> Either CryptoError SecretKey
forall a. CryptoFailable a -> Either CryptoError a
CE.eitherCryptoError (ByteString -> CryptoFailable SecretKey
forall ba. ByteArrayAccess ba => ba -> CryptoFailable SecretKey
Ed.secretKey ByteString
seed) of
        Left CryptoError
err -> String -> Either String KeyPair
forall a b. a -> Either a b
Left (String -> Either String KeyPair)
-> String -> Either String KeyPair
forall a b. (a -> b) -> a -> b
$ String
"keyPairFromSeed: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> CryptoError -> String
forall a. Show a => a -> String
show CryptoError
err
        Right SecretKey
sk ->
          let pk :: PublicKey
pk = SecretKey -> PublicKey
Ed.toPublic SecretKey
sk
           in KeyPair -> Either String KeyPair
forall a b. b -> Either a b
Right (KeyPair -> Either String KeyPair)
-> KeyPair -> Either String KeyPair
forall a b. (a -> b) -> a -> b
$
                KeyPair
                  { kpPublic :: PublicKey
kpPublic = KeyType -> ByteString -> PublicKey
PublicKey KeyType
Ed25519 (PublicKey -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert PublicKey
pk)
                  , kpPrivate :: PrivateKey
kpPrivate = KeyType -> ByteString -> PrivateKey
PrivateKey KeyType
Ed25519 (SecretKey -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert SecretKey
sk)
                  }