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

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

import Cardano.Binary
  ( Annotated,
    Decoded (..),
    FromCBOR,
    Raw,
    ToCBOR,
    serialize',
  )
import Cardano.Crypto.Orphans ()
import Cardano.Crypto.ProtocolMagic (ProtocolMagicId)
import Cardano.Crypto.Signing.Redeem.SigningKey (RedeemSigningKey (..))
import Cardano.Crypto.Signing.Redeem.VerificationKey (RedeemVerificationKey (..))
import Cardano.Crypto.Signing.Tag (SignTag, signTag, signTagDecoded)
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 (..))

-- | 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