{-# LANGUAGE TemplateHaskell #-}

module Test.Cardano.Crypto.Signing.Signing (tests, genData) where

import Cardano.Crypto.Signing (SignTag (..), sign, toVerification, verifySignature)
import Cardano.Ledger.Binary (encCBOR)
import Cardano.Prelude
import Hedgehog (
  Gen,
  Property,
  assert,
  checkParallel,
  discover,
  forAll,
  property,
 )
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import qualified Test.Cardano.Crypto.Dummy as Dummy
import Test.Cardano.Crypto.Gen (
  genKeypair,
  genSigningKey,
  genVerificationKey,
 )

--------------------------------------------------------------------------------
-- Main Test Action
--------------------------------------------------------------------------------

tests :: IO Bool
tests :: IO Bool
tests = Group -> IO Bool
forall (m :: * -> *). MonadIO m => Group -> m Bool
checkParallel $$String
[(PropertyName, Property)]
Property
String -> GroupName
String -> PropertyName
GroupName -> [(PropertyName, Property)] -> Group
prop_sign :: Property
prop_signDifferentKey :: Property
prop_signDifferentData :: Property
discover

--------------------------------------------------------------------------------
-- Redeem Signature Properties
--------------------------------------------------------------------------------

-- | Signing and verification works
prop_sign :: Property
prop_sign :: Property
prop_sign = HasCallStack => PropertyT IO () -> Property
PropertyT IO () -> Property
property (PropertyT IO () -> Property) -> PropertyT IO () -> Property
forall a b. (a -> b) -> a -> b
$ do
  (vk, sk) <- Gen (VerificationKey, SigningKey)
-> PropertyT IO (VerificationKey, SigningKey)
forall (m :: * -> *) a.
(Monad m, Show a, HasCallStack) =>
Gen a -> PropertyT m a
forAll Gen (VerificationKey, SigningKey)
genKeypair
  a <- forAll genData

  assert
    $ verifySignature encCBOR Dummy.protocolMagicId SignForTestingOnly vk a
    $ sign Dummy.protocolMagicId SignForTestingOnly sk a

-- | Signing fails when the wrong 'VerificationKey' is used
prop_signDifferentKey :: Property
prop_signDifferentKey :: Property
prop_signDifferentKey = HasCallStack => PropertyT IO () -> Property
PropertyT IO () -> Property
property (PropertyT IO () -> Property) -> PropertyT IO () -> Property
forall a b. (a -> b) -> a -> b
$ do
  sk <- Gen SigningKey -> PropertyT IO SigningKey
forall (m :: * -> *) a.
(Monad m, Show a, HasCallStack) =>
Gen a -> PropertyT m a
forAll Gen SigningKey
genSigningKey
  vk <- forAll $ Gen.filter (/= toVerification sk) genVerificationKey
  a <- forAll genData

  assert
    . not
    $ verifySignature encCBOR Dummy.protocolMagicId SignForTestingOnly vk a
    $ sign Dummy.protocolMagicId SignForTestingOnly sk a

-- | Signing fails when then wrong signature data is used
prop_signDifferentData :: Property
prop_signDifferentData :: Property
prop_signDifferentData = HasCallStack => PropertyT IO () -> Property
PropertyT IO () -> Property
property (PropertyT IO () -> Property) -> PropertyT IO () -> Property
forall a b. (a -> b) -> a -> b
$ do
  (vk, sk) <- Gen (VerificationKey, SigningKey)
-> PropertyT IO (VerificationKey, SigningKey)
forall (m :: * -> *) a.
(Monad m, Show a, HasCallStack) =>
Gen a -> PropertyT m a
forAll Gen (VerificationKey, SigningKey)
genKeypair
  a <- forAll genData
  b <- forAll $ Gen.filter (/= a) genData

  assert
    . not
    $ verifySignature encCBOR Dummy.protocolMagicId SignForTestingOnly vk b
    $ sign Dummy.protocolMagicId SignForTestingOnly sk a

genData :: Gen [Int32]
genData :: Gen [Int32]
genData = Range Int -> GenT Identity Int32 -> Gen [Int32]
forall (m :: * -> *) a. MonadGen m => Range Int -> m a -> m [a]
Gen.list (Int -> Int -> Range Int
forall a. a -> a -> Range a
Range.constant Int
0 Int
50) (Range Int32 -> GenT Identity Int32
forall (m :: * -> *). MonadGen m => Range Int32 -> m Int32
Gen.int32 Range Int32
forall a. (Bounded a, Num a) => Range a
Range.constantBounded)