{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}

module PlutusCore.Crypto.Ed25519 (verifyEd25519Signature)
where

import PlutusCore.Builtin.KnownType (BuiltinResult)
import PlutusCore.Crypto.Utils

import Cardano.Crypto.DSIGN.Class qualified as DSIGN
import Cardano.Crypto.DSIGN.Ed25519 (Ed25519DSIGN)
import Data.ByteString qualified as BS
import Data.Text (Text)

{-| Ed25519 signature verification
This will fail if the key or the signature are not of the expected length.
This version uses the cardano-crypto-class implementation of the verification
function (using libsodium). -}
verifyEd25519Signature
  :: BS.ByteString
  -- ^ Public Key (32 bytes)
  -> BS.ByteString
  -- ^ Message    (arbitrary length)
  -> BS.ByteString
  -- ^ Signature  (64 bytes)
  -> BuiltinResult Bool
verifyEd25519Signature :: ByteString -> ByteString -> ByteString -> BuiltinResult Bool
verifyEd25519Signature ByteString
pk ByteString
msg ByteString
sig =
  case forall v. DSIGNAlgorithm v => ByteString -> Maybe (VerKeyDSIGN v)
DSIGN.rawDeserialiseVerKeyDSIGN @Ed25519DSIGN ByteString
pk of
    Maybe (VerKeyDSIGN Ed25519DSIGN)
Nothing -> Text -> Text -> BuiltinResult Bool
forall a. Text -> Text -> BuiltinResult a
failWithMessage Text
loc Text
"Invalid verification key."
    Just VerKeyDSIGN Ed25519DSIGN
pk' -> case forall v. DSIGNAlgorithm v => ByteString -> Maybe (SigDSIGN v)
DSIGN.rawDeserialiseSigDSIGN @Ed25519DSIGN ByteString
sig of
      Maybe (SigDSIGN Ed25519DSIGN)
Nothing -> Text -> Text -> BuiltinResult Bool
forall a. Text -> Text -> BuiltinResult a
failWithMessage Text
loc Text
"Invalid signature."
      Just SigDSIGN Ed25519DSIGN
sig' ->
        Bool -> BuiltinResult Bool
forall a. a -> BuiltinResult a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> BuiltinResult Bool) -> Bool -> BuiltinResult Bool
forall a b. (a -> b) -> a -> b
$
          case ContextDSIGN Ed25519DSIGN
-> VerKeyDSIGN Ed25519DSIGN
-> ByteString
-> SigDSIGN Ed25519DSIGN
-> Either String ()
forall v a.
(DSIGNAlgorithm v, Signable v a, HasCallStack) =>
ContextDSIGN v
-> VerKeyDSIGN v -> a -> SigDSIGN v -> Either String ()
forall a.
(Signable Ed25519DSIGN a, HasCallStack) =>
ContextDSIGN Ed25519DSIGN
-> VerKeyDSIGN Ed25519DSIGN
-> a
-> SigDSIGN Ed25519DSIGN
-> Either String ()
DSIGN.verifyDSIGN () VerKeyDSIGN Ed25519DSIGN
pk' ByteString
msg SigDSIGN Ed25519DSIGN
sig' of
            Left String
_ -> Bool
False
            Right () -> Bool
True
  where
    loc :: Text
    loc :: Text
loc = Text
"Ed25519 signature verification"