{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE TemplateHaskell            #-}

module Cardano.Crypto.Signing.Redeem.Signature
  ( RedeemSignature(..)
  , redeemSign
  , redeemSignRaw
  , verifyRedeemSig
  , verifyRedeemSigDecoded
  , verifyRedeemSigRaw
  )
where

import Cardano.Prelude

import qualified Crypto.PubKey.Ed25519 as Ed25519
import Data.Aeson.TH (defaultOptions, deriveJSON)
import Data.Coerce (coerce)
import qualified Formatting.Buildable as B (Buildable(..))

import Cardano.Binary
  (Annotated, Decoded(..), FromCBOR, Raw, ToCBOR, serialize')
import Cardano.Crypto.Orphans ()
import Cardano.Crypto.ProtocolMagic (ProtocolMagicId)
import Cardano.Crypto.Signing.Redeem.VerificationKey (RedeemVerificationKey(..))
import Cardano.Crypto.Signing.Redeem.SigningKey (RedeemSigningKey(..))
import Cardano.Crypto.Signing.Tag (SignTag, signTag, signTagDecoded)


-- | Wrapper around 'Ed25519.Signature'
newtype RedeemSignature a =
  RedeemSignature Ed25519.Signature
  deriving (RedeemSignature a -> RedeemSignature a -> Bool
(RedeemSignature a -> RedeemSignature a -> Bool)
-> (RedeemSignature a -> RedeemSignature a -> Bool)
-> Eq (RedeemSignature a)
forall a. RedeemSignature a -> RedeemSignature a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RedeemSignature a -> RedeemSignature a -> Bool
$c/= :: forall a. RedeemSignature a -> RedeemSignature a -> Bool
== :: RedeemSignature a -> RedeemSignature a -> Bool
$c== :: forall a. RedeemSignature a -> RedeemSignature a -> Bool
Eq, Int -> RedeemSignature a -> ShowS
[RedeemSignature a] -> ShowS
RedeemSignature a -> String
(Int -> RedeemSignature a -> ShowS)
-> (RedeemSignature a -> String)
-> ([RedeemSignature a] -> ShowS)
-> Show (RedeemSignature a)
forall a. Int -> RedeemSignature a -> ShowS
forall a. [RedeemSignature a] -> ShowS
forall a. RedeemSignature a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RedeemSignature a] -> ShowS
$cshowList :: forall a. [RedeemSignature a] -> ShowS
show :: RedeemSignature a -> String
$cshow :: forall a. RedeemSignature a -> String
showsPrec :: Int -> RedeemSignature a -> ShowS
$cshowsPrec :: forall a. Int -> RedeemSignature a -> ShowS
Show, (forall x. RedeemSignature a -> Rep (RedeemSignature a) x)
-> (forall x. Rep (RedeemSignature a) x -> RedeemSignature a)
-> Generic (RedeemSignature a)
forall x. Rep (RedeemSignature a) x -> RedeemSignature a
forall x. RedeemSignature a -> Rep (RedeemSignature a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (RedeemSignature a) x -> RedeemSignature a
forall a x. RedeemSignature a -> Rep (RedeemSignature a) x
$cto :: forall a x. Rep (RedeemSignature a) x -> RedeemSignature a
$cfrom :: forall a x. RedeemSignature a -> Rep (RedeemSignature a) x
Generic, RedeemSignature a -> ()
(RedeemSignature a -> ()) -> NFData (RedeemSignature a)
forall a. RedeemSignature a -> ()
forall a. (a -> ()) -> NFData a
rnf :: RedeemSignature a -> ()
$crnf :: forall a. RedeemSignature a -> ()
NFData, Typeable (RedeemSignature a)
Decoder s (RedeemSignature a)
Typeable (RedeemSignature a)
-> (forall s. Decoder s (RedeemSignature a))
-> (Proxy (RedeemSignature a) -> Text)
-> FromCBOR (RedeemSignature a)
Proxy (RedeemSignature a) -> Text
forall s. Decoder s (RedeemSignature a)
forall a. Typeable a => Typeable (RedeemSignature a)
forall a. Typeable a => Proxy (RedeemSignature a) -> Text
forall a.
Typeable a
-> (forall s. Decoder s a) -> (Proxy a -> Text) -> FromCBOR a
forall a s. Typeable a => Decoder s (RedeemSignature a)
label :: Proxy (RedeemSignature a) -> Text
$clabel :: forall a. Typeable a => Proxy (RedeemSignature a) -> Text
fromCBOR :: Decoder s (RedeemSignature a)
$cfromCBOR :: forall a s. Typeable a => Decoder s (RedeemSignature a)
$cp1FromCBOR :: forall a. Typeable a => Typeable (RedeemSignature a)
FromCBOR, Typeable (RedeemSignature a)
Typeable (RedeemSignature a)
-> (RedeemSignature a -> Encoding)
-> ((forall t. ToCBOR t => Proxy t -> Size)
    -> Proxy (RedeemSignature a) -> Size)
-> ((forall t. ToCBOR t => Proxy t -> Size)
    -> Proxy [RedeemSignature a] -> Size)
-> ToCBOR (RedeemSignature a)
RedeemSignature a -> Encoding
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [RedeemSignature a] -> Size
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (RedeemSignature a) -> Size
forall a. Typeable a => Typeable (RedeemSignature a)
forall a. Typeable a => RedeemSignature a -> Encoding
forall a.
Typeable a
-> (a -> Encoding)
-> ((forall t. ToCBOR t => Proxy t -> Size) -> Proxy a -> Size)
-> ((forall t. ToCBOR t => Proxy t -> Size) -> Proxy [a] -> Size)
-> ToCBOR a
forall a.
Typeable a =>
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [RedeemSignature a] -> Size
forall a.
Typeable a =>
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (RedeemSignature a) -> Size
encodedListSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [RedeemSignature a] -> Size
$cencodedListSizeExpr :: forall a.
Typeable a =>
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [RedeemSignature a] -> Size
encodedSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (RedeemSignature a) -> Size
$cencodedSizeExpr :: forall a.
Typeable a =>
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (RedeemSignature a) -> Size
toCBOR :: RedeemSignature a -> Encoding
$ctoCBOR :: forall a. Typeable a => RedeemSignature a -> Encoding
$cp1ToCBOR :: forall a. Typeable a => Typeable (RedeemSignature a)
ToCBOR)

-- Note that there is deliberately no Ord instance. The crypto libraries
-- encourage using key /hashes/ not keys for things like sets, map etc.

instance B.Buildable (RedeemSignature a) where
  build :: RedeemSignature a -> Builder
build RedeemSignature a
_ = Builder
"<redeem signature>"

deriveJSON defaultOptions ''RedeemSignature

-- | Encode something with 'ToCBOR' and sign it
redeemSign
  :: ToCBOR a
  => ProtocolMagicId
  -> SignTag
  -> RedeemSigningKey
  -> a
  -> RedeemSignature a
redeemSign :: ProtocolMagicId
-> SignTag -> RedeemSigningKey -> a -> RedeemSignature a
redeemSign ProtocolMagicId
pm SignTag
tag RedeemSigningKey
k = RedeemSignature Raw -> RedeemSignature a
coerce (RedeemSignature Raw -> RedeemSignature a)
-> (a -> RedeemSignature Raw) -> a -> RedeemSignature a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ProtocolMagicId
-> Maybe SignTag
-> RedeemSigningKey
-> ByteString
-> RedeemSignature Raw
redeemSignRaw ProtocolMagicId
pm (SignTag -> Maybe SignTag
forall a. a -> Maybe a
Just SignTag
tag) RedeemSigningKey
k (ByteString -> RedeemSignature Raw)
-> (a -> ByteString) -> a -> RedeemSignature Raw
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. a -> ByteString
forall a. ToCBOR a => a -> ByteString
serialize'

-- | Alias for constructor
redeemSignRaw
  :: ProtocolMagicId
  -> Maybe SignTag
  -> RedeemSigningKey
  -> ByteString
  -> RedeemSignature Raw
redeemSignRaw :: ProtocolMagicId
-> Maybe SignTag
-> RedeemSigningKey
-> ByteString
-> RedeemSignature Raw
redeemSignRaw ProtocolMagicId
pm Maybe SignTag
mbTag (RedeemSigningKey SecretKey
k) ByteString
x =
  Signature -> RedeemSignature Raw
forall a. Signature -> RedeemSignature a
RedeemSignature (Signature -> RedeemSignature Raw)
-> Signature -> RedeemSignature Raw
forall a b. (a -> b) -> a -> b
$ SecretKey -> PublicKey -> ByteString -> Signature
forall ba.
ByteArrayAccess ba =>
SecretKey -> PublicKey -> ba -> Signature
Ed25519.sign SecretKey
k (SecretKey -> PublicKey
Ed25519.toPublic SecretKey
k) (ByteString -> Signature) -> ByteString -> Signature
forall a b. (a -> b) -> a -> b
$ ByteString
tag ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
x
  where tag :: ByteString
tag = ByteString
-> (SignTag -> ByteString) -> Maybe SignTag -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
forall a. Monoid a => a
mempty (ProtocolMagicId -> SignTag -> ByteString
signTag ProtocolMagicId
pm) Maybe SignTag
mbTag

-- | Verify a redeem signature
verifyRedeemSig
  :: ToCBOR a
  => ProtocolMagicId
  -> SignTag
  -> RedeemVerificationKey
  -> a
  -> RedeemSignature a
  -> Bool
verifyRedeemSig :: ProtocolMagicId
-> SignTag
-> RedeemVerificationKey
-> a
-> RedeemSignature a
-> Bool
verifyRedeemSig ProtocolMagicId
pm SignTag
tag RedeemVerificationKey
k a
x RedeemSignature a
s =
  RedeemVerificationKey -> ByteString -> RedeemSignature Raw -> Bool
verifyRedeemSigRaw RedeemVerificationKey
k (ProtocolMagicId -> SignTag -> ByteString
signTag ProtocolMagicId
pm SignTag
tag ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> a -> ByteString
forall a. ToCBOR a => a -> ByteString
serialize' a
x) (RedeemSignature a -> RedeemSignature Raw
coerce RedeemSignature a
s)

verifyRedeemSigDecoded
  :: Decoded t
  => Annotated ProtocolMagicId ByteString
  -> SignTag
  -> RedeemVerificationKey
  -> t
  -> RedeemSignature (BaseType t)
  -> Bool
verifyRedeemSigDecoded :: Annotated ProtocolMagicId ByteString
-> SignTag
-> RedeemVerificationKey
-> t
-> RedeemSignature (BaseType t)
-> Bool
verifyRedeemSigDecoded Annotated ProtocolMagicId ByteString
pm SignTag
tag RedeemVerificationKey
k t
x RedeemSignature (BaseType t)
s =
  RedeemVerificationKey -> ByteString -> RedeemSignature Raw -> Bool
verifyRedeemSigRaw RedeemVerificationKey
k (Annotated ProtocolMagicId ByteString -> SignTag -> ByteString
signTagDecoded Annotated ProtocolMagicId ByteString
pm SignTag
tag ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> t -> ByteString
forall t. Decoded t => t -> ByteString
recoverBytes t
x) (RedeemSignature (BaseType t) -> RedeemSignature Raw
coerce RedeemSignature (BaseType t)
s)

-- | Verify raw 'ByteString'
verifyRedeemSigRaw
  :: RedeemVerificationKey
  -> ByteString
  -> RedeemSignature Raw
  -> Bool
verifyRedeemSigRaw :: RedeemVerificationKey -> ByteString -> RedeemSignature Raw -> Bool
verifyRedeemSigRaw (RedeemVerificationKey PublicKey
k) ByteString
x (RedeemSignature Signature
s) =
  PublicKey -> ByteString -> Signature -> Bool
forall ba.
ByteArrayAccess ba =>
PublicKey -> ba -> Signature -> Bool
Ed25519.verify PublicKey
k ByteString
x Signature
s