{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}

module Nats.Nkeys.Pairs where

import Crypto.Sign.Ed25519 (PublicKey (unPublicKey), SecretKey (unSecretKey), Signature, createKeypair, createKeypairFromSeed_, dsign, dverify)
import Data.ByteString (drop, index)
import Data.ByteString hiding (unpack)
import Data.Text (pack, unpack)
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import Nats.Nkeys.Codec (KeyPrefix (..), decode, encode, encodeSeed, extractSeedPrefix, fromByte)

-- | Represents an ed25519 key pair with NATS string encoding
data KeyPair = KeyPair {KeyPair -> KeyPrefix
prefixByte :: KeyPrefix, KeyPair -> PublicKey
pk :: PublicKey, KeyPair -> SecretKey
sk :: SecretKey} deriving (KeyPair -> KeyPair -> Bool
(KeyPair -> KeyPair -> Bool)
-> (KeyPair -> KeyPair -> Bool) -> Eq KeyPair
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: KeyPair -> KeyPair -> Bool
== :: KeyPair -> KeyPair -> Bool
$c/= :: KeyPair -> KeyPair -> Bool
/= :: KeyPair -> KeyPair -> Bool
Eq)

instance Show KeyPair where
  show :: KeyPair -> String
show KeyPair
p = Text -> String
unpack (Text -> String) -> (ByteString -> Text) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
decodeUtf8 (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ KeyPair -> ByteString
publicKey KeyPair
p

-- | Returns the public key of the pair as a prefixed byte string
publicKey :: KeyPair -> ByteString
publicKey :: KeyPair -> ByteString
publicKey (KeyPair {KeyPrefix
prefixByte :: KeyPair -> KeyPrefix
prefixByte :: KeyPrefix
prefixByte, PublicKey
pk :: KeyPair -> PublicKey
pk :: PublicKey
pk, SecretKey
sk :: KeyPair -> SecretKey
sk :: SecretKey
..}) = KeyPrefix -> ByteString -> ByteString
encode KeyPrefix
prefixByte (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ PublicKey -> ByteString
unPublicKey PublicKey
pk

-- | Returns the seed (private) key of the pair as a prefixed string starting with S
seed :: KeyPair -> ByteString
seed :: KeyPair -> ByteString
seed (KeyPair {KeyPrefix
prefixByte :: KeyPair -> KeyPrefix
prefixByte :: KeyPrefix
prefixByte, SecretKey
sk :: KeyPair -> SecretKey
sk :: SecretKey
sk, PublicKey
pk :: KeyPair -> PublicKey
pk :: PublicKey
..}) = KeyPrefix -> ByteString -> ByteString
encodeSeed KeyPrefix
prefixByte (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ SecretKey -> ByteString
unSecretKey SecretKey
sk

-- | Creates a new keypair from an encoded seed with an appropriate prefix. Do not
-- call this function with unencoded ed25519 seeds
createFromSeed :: ByteString -> Maybe KeyPair
createFromSeed :: ByteString -> Maybe KeyPair
createFromSeed ByteString
input =
  let decoded :: Either Text ByteString
decoded = ByteString -> Either Text ByteString
decode ByteString
input
      prefix :: KeyPrefix
prefix = case ByteString -> KeyPrefix
extractSeedPrefix (ByteString -> KeyPrefix)
-> Either Text ByteString -> Either Text KeyPrefix
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either Text ByteString
decoded of
        Left Text
_ -> KeyPrefix
Unknown
        Right KeyPrefix
p -> KeyPrefix
p
      rawkp :: Either Text (Maybe (PublicKey, SecretKey))
rawkp = ByteString -> Maybe (PublicKey, SecretKey)
createKeypairFromSeed_ (ByteString -> Maybe (PublicKey, SecretKey))
-> (ByteString -> ByteString)
-> ByteString
-> Maybe (PublicKey, SecretKey)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ByteString -> ByteString
Data.ByteString.drop Int
2 (ByteString -> Maybe (PublicKey, SecretKey))
-> Either Text ByteString
-> Either Text (Maybe (PublicKey, SecretKey))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either Text ByteString
decoded
   in case Either Text (Maybe (PublicKey, SecretKey))
rawkp of
        Left Text
x -> Maybe KeyPair
forall a. Maybe a
Nothing
        Right Maybe (PublicKey, SecretKey)
Nothing -> Maybe KeyPair
forall a. Maybe a
Nothing
        Right (Just (PublicKey
p, SecretKey
s)) ->
          KeyPair -> Maybe KeyPair
forall a. a -> Maybe a
Just KeyPair {prefixByte :: KeyPrefix
prefixByte = KeyPrefix
prefix, pk :: PublicKey
pk = PublicKey
p, sk :: SecretKey
sk = SecretKey
s}

-- | This IO action creates a new key pair from a randomly generated 32-byte seed
create :: KeyPrefix -> IO KeyPair
create :: KeyPrefix -> IO KeyPair
create KeyPrefix
prefix = do
  (PublicKey
pk, SecretKey
sk) <- IO (PublicKey, SecretKey)
createKeypair
  KeyPair -> IO KeyPair
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return KeyPair {prefixByte :: KeyPrefix
prefixByte = KeyPrefix
prefix, pk :: PublicKey
pk = PublicKey
pk, sk :: SecretKey
sk = SecretKey
sk}

-- | Signs the given input bytes using the key pair's seed key
sign :: KeyPair -> ByteString -> Maybe Signature
sign :: KeyPair -> ByteString -> Maybe Signature
sign (KeyPair {prefixByte :: KeyPair -> KeyPrefix
prefixByte = KeyPrefix
Curve, SecretKey
PublicKey
pk :: KeyPair -> PublicKey
sk :: KeyPair -> SecretKey
pk :: PublicKey
sk :: SecretKey
..}) = Maybe Signature -> ByteString -> Maybe Signature
forall a b. a -> b -> a
const Maybe Signature
forall a. Maybe a
Nothing
sign (KeyPair {SecretKey
sk :: KeyPair -> SecretKey
sk :: SecretKey
sk, PublicKey
KeyPrefix
prefixByte :: KeyPair -> KeyPrefix
pk :: KeyPair -> PublicKey
prefixByte :: KeyPrefix
pk :: PublicKey
..}) = Signature -> Maybe Signature
forall a. a -> Maybe a
Just (Signature -> Maybe Signature)
-> (ByteString -> Signature) -> ByteString -> Maybe Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecretKey -> ByteString -> Signature
Crypto.Sign.Ed25519.dsign SecretKey
sk

-- | Verifies a signature against the key pair's public key and the input bytes
verify :: KeyPair -> ByteString -> Signature -> Bool
verify :: KeyPair -> ByteString -> Signature -> Bool
verify (KeyPair {prefixByte :: KeyPair -> KeyPrefix
prefixByte = KeyPrefix
Curve, SecretKey
PublicKey
pk :: KeyPair -> PublicKey
sk :: KeyPair -> SecretKey
pk :: PublicKey
sk :: SecretKey
..}) = \ ByteString
_ Signature
_ -> Bool
False
verify (KeyPair {PublicKey
pk :: KeyPair -> PublicKey
pk :: PublicKey
pk, SecretKey
KeyPrefix
prefixByte :: KeyPair -> KeyPrefix
sk :: KeyPair -> SecretKey
prefixByte :: KeyPrefix
sk :: SecretKey
..}) = PublicKey -> ByteString -> Signature -> Bool
Crypto.Sign.Ed25519.dverify PublicKey
pk