-- | Key types and KeyPair abstraction for libp2p peer identity.
module LibP2P.Crypto.Key
  ( KeyType (..)
  , KeyPair (..)
  , PublicKey (..)
  , PrivateKey (..)
  , publicKey
  , sign
  , verify
  , keyPairFromPrivateKey
  , generateRSAKeyPair
  , generateSecp256k1KeyPair
  , generateECDSAKeyPair
  ) where

import qualified Crypto.Error as CE
import qualified Crypto.PubKey.Ed25519 as Ed
import Data.ByteArray (convert)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified LibP2P.Crypto.ECDSA as ECDSA
import qualified LibP2P.Crypto.RSA as RSA
import qualified LibP2P.Crypto.Secp256k1 as Secp256k1

-- | Supported key types per the libp2p spec.
data KeyType
  = Ed25519
  | RSA
  | Secp256k1
  | ECDSA
  deriving (Int -> KeyType -> ShowS
[KeyType] -> ShowS
KeyType -> String
(Int -> KeyType -> ShowS)
-> (KeyType -> String) -> ([KeyType] -> ShowS) -> Show KeyType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> KeyType -> ShowS
showsPrec :: Int -> KeyType -> ShowS
$cshow :: KeyType -> String
show :: KeyType -> String
$cshowList :: [KeyType] -> ShowS
showList :: [KeyType] -> ShowS
Show, KeyType -> KeyType -> Bool
(KeyType -> KeyType -> Bool)
-> (KeyType -> KeyType -> Bool) -> Eq KeyType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: KeyType -> KeyType -> Bool
== :: KeyType -> KeyType -> Bool
$c/= :: KeyType -> KeyType -> Bool
/= :: KeyType -> KeyType -> Bool
Eq, Eq KeyType
Eq KeyType =>
(KeyType -> KeyType -> Ordering)
-> (KeyType -> KeyType -> Bool)
-> (KeyType -> KeyType -> Bool)
-> (KeyType -> KeyType -> Bool)
-> (KeyType -> KeyType -> Bool)
-> (KeyType -> KeyType -> KeyType)
-> (KeyType -> KeyType -> KeyType)
-> Ord KeyType
KeyType -> KeyType -> Bool
KeyType -> KeyType -> Ordering
KeyType -> KeyType -> KeyType
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: KeyType -> KeyType -> Ordering
compare :: KeyType -> KeyType -> Ordering
$c< :: KeyType -> KeyType -> Bool
< :: KeyType -> KeyType -> Bool
$c<= :: KeyType -> KeyType -> Bool
<= :: KeyType -> KeyType -> Bool
$c> :: KeyType -> KeyType -> Bool
> :: KeyType -> KeyType -> Bool
$c>= :: KeyType -> KeyType -> Bool
>= :: KeyType -> KeyType -> Bool
$cmax :: KeyType -> KeyType -> KeyType
max :: KeyType -> KeyType -> KeyType
$cmin :: KeyType -> KeyType -> KeyType
min :: KeyType -> KeyType -> KeyType
Ord)

-- | A public key with its type.
data PublicKey = PublicKey
  { PublicKey -> KeyType
pkType :: KeyType
  , PublicKey -> ByteString
pkBytes :: ByteString
  }
  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)

-- | A private key with its type.
data PrivateKey = PrivateKey
  { PrivateKey -> KeyType
skType :: KeyType
  , PrivateKey -> ByteString
skBytes :: ByteString
  }

-- | A key pair containing both public and private keys.
data KeyPair = KeyPair
  { KeyPair -> PublicKey
kpPublic :: PublicKey
  , KeyPair -> PrivateKey
kpPrivate :: PrivateKey
  }

-- | Extract the public key from a key pair.
publicKey :: KeyPair -> PublicKey
publicKey :: KeyPair -> PublicKey
publicKey = KeyPair -> PublicKey
kpPublic

-- | Sign a message with a private key.
--
-- Signing is deterministic (and therefore pure) for every key type:
-- Ed25519 and RSA (PKCS#1 v1.5) are deterministic by construction, and
-- secp256k1/ECDSA use RFC 6979 deterministic nonces. Returns Left on
-- invalid key bytes.
sign :: PrivateKey -> ByteString -> Either String ByteString
sign :: PrivateKey -> ByteString -> Either String ByteString
sign (PrivateKey KeyType
Ed25519 ByteString
skRaw) ByteString
msg
  | ByteString -> Int
BS.length ByteString
skRaw Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
64 =
      String -> Either String ByteString
forall a b. a -> Either a b
Left String
"sign: Ed25519 private key must be 64 bytes (seed || public key)"
  | 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 (Int -> ByteString -> ByteString
BS.take Int
32 ByteString
skRaw)) of
        Left CryptoError
err -> String -> Either String ByteString
forall a b. a -> Either a b
Left (String -> Either String ByteString)
-> String -> Either String ByteString
forall a b. (a -> b) -> a -> b
$ String
"sign: invalid secret key: " String -> ShowS
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
              sig :: Signature
sig = SecretKey -> PublicKey -> ByteString -> Signature
forall ba.
ByteArrayAccess ba =>
SecretKey -> PublicKey -> ba -> Signature
Ed.sign SecretKey
sk PublicKey
pk ByteString
msg
           in ByteString -> Either String ByteString
forall a b. b -> Either a b
Right (Signature -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert Signature
sig)
sign (PrivateKey KeyType
RSA ByteString
skRaw) ByteString
msg = ByteString -> ByteString -> Either String ByteString
RSA.sign ByteString
skRaw ByteString
msg
sign (PrivateKey KeyType
Secp256k1 ByteString
skRaw) ByteString
msg = ByteString -> ByteString -> Either String ByteString
Secp256k1.sign ByteString
skRaw ByteString
msg
sign (PrivateKey KeyType
ECDSA ByteString
skRaw) ByteString
msg = ByteString -> ByteString -> Either String ByteString
ECDSA.sign ByteString
skRaw ByteString
msg

-- | Verify a signature against a public key and message.
-- Supports every libp2p key type so remote peers of any type can be authenticated.
verify :: PublicKey -> ByteString -> ByteString -> Bool
verify :: PublicKey -> ByteString -> ByteString -> Bool
verify (PublicKey KeyType
Ed25519 ByteString
pkRaw) ByteString
msg ByteString
sigRaw =
  case (CryptoFailable PublicKey -> Either CryptoError PublicKey
forall a. CryptoFailable a -> Either CryptoError a
CE.eitherCryptoError (ByteString -> CryptoFailable PublicKey
forall ba. ByteArrayAccess ba => ba -> CryptoFailable PublicKey
Ed.publicKey ByteString
pkRaw), CryptoFailable Signature -> Either CryptoError Signature
forall a. CryptoFailable a -> Either CryptoError a
CE.eitherCryptoError (ByteString -> CryptoFailable Signature
forall ba. ByteArrayAccess ba => ba -> CryptoFailable Signature
Ed.signature ByteString
sigRaw)) of
    (Right PublicKey
pk, Right Signature
sig) -> PublicKey -> ByteString -> Signature -> Bool
forall ba.
ByteArrayAccess ba =>
PublicKey -> ba -> Signature -> Bool
Ed.verify PublicKey
pk ByteString
msg Signature
sig
    (Either CryptoError PublicKey, Either CryptoError Signature)
_ -> Bool
False
verify (PublicKey KeyType
RSA ByteString
pkRaw) ByteString
msg ByteString
sigRaw = ByteString -> ByteString -> ByteString -> Bool
RSA.verify ByteString
pkRaw ByteString
msg ByteString
sigRaw
verify (PublicKey KeyType
Secp256k1 ByteString
pkRaw) ByteString
msg ByteString
sigRaw = ByteString -> ByteString -> ByteString -> Bool
Secp256k1.verify ByteString
pkRaw ByteString
msg ByteString
sigRaw
verify (PublicKey KeyType
ECDSA ByteString
pkRaw) ByteString
msg ByteString
sigRaw = ByteString -> ByteString -> ByteString -> Bool
ECDSA.verify ByteString
pkRaw ByteString
msg ByteString
sigRaw

-- | Reconstruct a full key pair from a private key in libp2p wire format,
-- deriving the public key. This is the import path for keys produced by
-- other implementations (the peer-ids spec requires that implementations
-- can produce the public key from the private key).
keyPairFromPrivateKey :: PrivateKey -> Either String KeyPair
keyPairFromPrivateKey :: PrivateKey -> Either String KeyPair
keyPairFromPrivateKey (PrivateKey KeyType
Ed25519 ByteString
raw) = do
  privBytes <- ByteString -> Either String ByteString
normalizeEd25519Private ByteString
raw
  let (seed, embeddedPk) = BS.splitAt 32 privBytes
  case CE.eitherCryptoError (Ed.secretKey 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
"keyPairFromPrivateKey: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> CryptoError -> String
forall a. Show a => a -> String
show CryptoError
err
    Right SecretKey
sk
      | ByteString
pkRaw ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
embeddedPk ->
          String -> Either String KeyPair
forall a b. a -> Either a b
Left String
"keyPairFromPrivateKey: Ed25519 public key does not match the seed"
      | Bool
otherwise ->
          KeyPair -> Either String KeyPair
forall a b. b -> Either a b
Right (PublicKey -> PrivateKey -> KeyPair
KeyPair (KeyType -> ByteString -> PublicKey
PublicKey KeyType
Ed25519 ByteString
pkRaw) (KeyType -> ByteString -> PrivateKey
PrivateKey KeyType
Ed25519 ByteString
privBytes))
      where
        pkRaw :: ByteString
pkRaw = PublicKey -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert (SecretKey -> PublicKey
Ed.toPublic SecretKey
sk)
keyPairFromPrivateKey (PrivateKey KeyType
RSA ByteString
raw) =
  (\ByteString
pub -> PublicKey -> PrivateKey -> KeyPair
KeyPair (KeyType -> ByteString -> PublicKey
PublicKey KeyType
RSA ByteString
pub) (KeyType -> ByteString -> PrivateKey
PrivateKey KeyType
RSA ByteString
raw)) (ByteString -> KeyPair)
-> Either String ByteString -> Either String KeyPair
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ByteString -> Either String ByteString
RSA.derivePublicKey ByteString
raw
keyPairFromPrivateKey (PrivateKey KeyType
Secp256k1 ByteString
raw) =
  (\ByteString
pub -> PublicKey -> PrivateKey -> KeyPair
KeyPair (KeyType -> ByteString -> PublicKey
PublicKey KeyType
Secp256k1 ByteString
pub) (KeyType -> ByteString -> PrivateKey
PrivateKey KeyType
Secp256k1 ByteString
raw))
    (ByteString -> KeyPair)
-> Either String ByteString -> Either String KeyPair
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ByteString -> Either String ByteString
Secp256k1.derivePublicKey ByteString
raw
keyPairFromPrivateKey (PrivateKey KeyType
ECDSA ByteString
raw) =
  (\ByteString
pub -> PublicKey -> PrivateKey -> KeyPair
KeyPair (KeyType -> ByteString -> PublicKey
PublicKey KeyType
ECDSA ByteString
pub) (KeyType -> ByteString -> PrivateKey
PrivateKey KeyType
ECDSA ByteString
raw)) (ByteString -> KeyPair)
-> Either String ByteString -> Either String KeyPair
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ByteString -> Either String ByteString
ECDSA.derivePublicKey ByteString
raw

-- | Normalize Ed25519 private key bytes to the preferred 64-byte form
-- (seed || public key). The legacy 96-byte form (seed || pub || pub) is
-- accepted after verifying that both embedded public keys are identical,
-- per the peer-ids spec.
normalizeEd25519Private :: ByteString -> Either String ByteString
normalizeEd25519Private :: ByteString -> Either String ByteString
normalizeEd25519Private ByteString
raw
  | ByteString -> Int
BS.length ByteString
raw Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
64 = ByteString -> Either String ByteString
forall a b. b -> Either a b
Right ByteString
raw
  | ByteString -> Int
BS.length ByteString
raw Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
96 =
      let (ByteString
privBytes, ByteString
redundantPk) = Int -> ByteString -> (ByteString, ByteString)
BS.splitAt Int
64 ByteString
raw
       in if Int -> ByteString -> ByteString
BS.drop Int
32 ByteString
privBytes ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
redundantPk
            then ByteString -> Either String ByteString
forall a b. b -> Either a b
Right ByteString
privBytes
            else String -> Either String ByteString
forall a b. a -> Either a b
Left String
"normalizeEd25519Private: legacy 96-byte key has mismatched public keys"
  | Bool
otherwise =
      String -> Either String ByteString
forall a b. a -> Either a b
Left (String -> Either String ByteString)
-> String -> Either String ByteString
forall a b. (a -> b) -> a -> b
$
        String
"normalizeEd25519Private: private key must be 64 or 96 bytes, got "
          String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show (ByteString -> Int
BS.length ByteString
raw)

-- | Generate a new RSA key pair (2048-bit) with libp2p wire-format key bytes.
generateRSAKeyPair :: IO KeyPair
generateRSAKeyPair :: IO KeyPair
generateRSAKeyPair = do
  (pub, priv) <- IO (ByteString, ByteString)
RSA.generate
  pure $ KeyPair (PublicKey RSA pub) (PrivateKey RSA priv)

-- | Generate a new secp256k1 key pair with libp2p wire-format key bytes.
generateSecp256k1KeyPair :: IO KeyPair
generateSecp256k1KeyPair :: IO KeyPair
generateSecp256k1KeyPair = do
  (pub, priv) <- IO (ByteString, ByteString)
Secp256k1.generate
  pure $ KeyPair (PublicKey Secp256k1 pub) (PrivateKey Secp256k1 priv)

-- | Generate a new ECDSA (P-256) key pair with libp2p wire-format key bytes.
generateECDSAKeyPair :: IO KeyPair
generateECDSAKeyPair :: IO KeyPair
generateECDSAKeyPair = do
  (pub, priv) <- IO (ByteString, ByteString)
ECDSA.generate
  pure $ KeyPair (PublicKey ECDSA pub) (PrivateKey ECDSA priv)