{-# 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"