{-# LANGUAGE TypeApplications #-}

module Hydra.CryptoSpec where

-- Unit under test
import Hydra.Tx.Crypto

import Hydra.Prelude
import Test.Hydra.Prelude

import Cardano.Crypto.DSIGN (SigDSIGN (SigEd25519DSIGN))
import Cardano.Crypto.PinnedSizedBytes (psbFromByteString)
import Data.ByteString qualified as BS
import Data.ByteString.Char8 qualified as Char8
import Data.Map.Strict qualified as Map
import Hydra.Tx.Party (Party (vkey), deriveParty)
import Hydra.Tx.Secret (Secret)
import Test.Aeson.GenericSpecs (roundtripAndGoldenSpecs)
import Test.Hydra.Tx.Gen ()
import Test.QuickCheck (
  classify,
  counterexample,
  elements,
  forAll,
  shuffle,
  sublistOf,
  (=/=),
  (===),
  (==>),
 )
import Test.QuickCheck.Instances.UnorderedContainers ()
import Test.Util (propCollisionResistant)

spec :: Spec
spec :: Spec
spec = do
  Spec
specSigningKey
  Spec
specVerificationKey
  Spec
specSignature
  Spec
specMultiSignature

specSigningKey :: Spec
specSigningKey :: Spec
specSigningKey =
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"SigningKey" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    -- Note: Show / ToJSON / FromJSON on `SigningKey HydraKey` are deliberately
    -- forbidden at compile time (see Hydra.Tx.Secret + Hydra.Tx.Crypto). The
    -- previous "show includes escaped hex" and JSON roundtrip golden tests
    -- have been removed because they exercised exactly the leak we now refuse.
    String -> Expectation -> SpecWith (Arg Expectation)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"can be generated when seed exceeds the max seed size for algorithm" (Expectation -> SpecWith (Arg Expectation))
-> Expectation -> SpecWith (Arg Expectation)
forall a b. (a -> b) -> a -> b
$
      let exceedingSizeSeedA :: ByteString
exceedingSizeSeedA = String -> ByteString
Char8.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
32 Char
'x' String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"a"
          exceedingSizeSeedB :: ByteString
exceedingSizeSeedB = String -> ByteString
Char8.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
32 Char
'x' String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"b"
       in -- Compare via the (public) verification key since 'Show' / equality
          -- on a raw SigningKey is forbidden.
          Secret (SigningKey HydraKey) -> VerificationKey HydraKey
forall s k. HasVerificationKey s k => s -> VerificationKey k
getVerificationKey (ByteString -> Secret (SigningKey HydraKey)
generateSigningKey ByteString
exceedingSizeSeedA)
            VerificationKey HydraKey -> VerificationKey HydraKey -> Expectation
forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
`shouldNotBe` Secret (SigningKey HydraKey) -> VerificationKey HydraKey
forall s k. HasVerificationKey s k => s -> VerificationKey k
getVerificationKey (ByteString -> Secret (SigningKey HydraKey)
generateSigningKey ByteString
exceedingSizeSeedB)
    String -> ((ByteString, ByteString) -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"can be generated" (((ByteString, ByteString) -> Property) -> Spec)
-> ((ByteString, ByteString) -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \(ByteString
seedA, ByteString
seedB) ->
      (ByteString
seedA ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
seedB) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
        let vkA :: VerificationKey HydraKey
vkA = Secret (SigningKey HydraKey) -> VerificationKey HydraKey
forall s k. HasVerificationKey s k => s -> VerificationKey k
getVerificationKey (ByteString -> Secret (SigningKey HydraKey)
generateSigningKey ByteString
seedA)
            vkB :: VerificationKey HydraKey
vkB = Secret (SigningKey HydraKey) -> VerificationKey HydraKey
forall s k. HasVerificationKey s k => s -> VerificationKey k
getVerificationKey (ByteString -> Secret (SigningKey HydraKey)
generateSigningKey ByteString
seedB)
         in VerificationKey HydraKey
vkA VerificationKey HydraKey -> VerificationKey HydraKey -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=/= VerificationKey HydraKey
vkB
    String -> Gen (Secret (SigningKey HydraKey)) -> Spec
forall a. (Show a, Eq a) => String -> Gen a -> Spec
propCollisionResistant String
"arbitrary @(Secret (SigningKey HydraKey))" (forall a. Arbitrary a => Gen a
arbitrary @(Secret (SigningKey HydraKey)))

specVerificationKey :: Spec
specVerificationKey :: Spec
specVerificationKey =
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"VerificationKey" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Expectation -> SpecWith (Arg Expectation)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"show includes escaped hex" (Expectation -> SpecWith (Arg Expectation))
-> Expectation -> SpecWith (Arg Expectation)
forall a b. (a -> b) -> a -> b
$
      VerificationKey HydraKey -> String
forall b a. (Show a, IsString b) => a -> b
show (Secret (SigningKey HydraKey) -> VerificationKey HydraKey
forall s k. HasVerificationKey s k => s -> VerificationKey k
getVerificationKey (ByteString -> Secret (SigningKey HydraKey)
generateSigningKey ByteString
"alice")) String -> String -> Expectation
forall a. (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation
`shouldContain` String
"d5bf4a3fcce717b03"

    Proxy (VerificationKey HydraKey) -> Spec
forall a.
(Arbitrary a, ToJSON a, FromJSON a, Typeable a) =>
Proxy a -> Spec
roundtripAndGoldenSpecs (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @(VerificationKey HydraKey))

specSignature :: Spec
specSignature :: Spec
specSignature =
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"Signature" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Expectation -> SpecWith (Arg Expectation)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"show includes escaped hex" (Expectation -> SpecWith (Arg Expectation))
-> Expectation -> SpecWith (Arg Expectation)
forall a b. (a -> b) -> a -> b
$
      Signature Any -> String
forall b a. (Show a, IsString b) => a -> b
show (SigDSIGN Ed25519DSIGN -> Signature Any
forall a. SigDSIGN Ed25519DSIGN -> Signature a
HydraSignature (PinnedSizedBytes CRYPTO_SIGN_ED25519_BYTES -> SigDSIGN Ed25519DSIGN
PinnedSizedBytes (SigSizeDSIGN Ed25519DSIGN)
-> SigDSIGN Ed25519DSIGN
SigEd25519DSIGN (PinnedSizedBytes CRYPTO_SIGN_ED25519_BYTES
 -> SigDSIGN Ed25519DSIGN)
-> ([Word8] -> PinnedSizedBytes CRYPTO_SIGN_ED25519_BYTES)
-> [Word8]
-> SigDSIGN Ed25519DSIGN
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> PinnedSizedBytes CRYPTO_SIGN_ED25519_BYTES
forall (n :: Nat). KnownNat n => ByteString -> PinnedSizedBytes n
psbFromByteString (ByteString -> PinnedSizedBytes CRYPTO_SIGN_ED25519_BYTES)
-> ([Word8] -> ByteString)
-> [Word8]
-> PinnedSizedBytes CRYPTO_SIGN_ED25519_BYTES
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
BS.pack ([Word8] -> SigDSIGN Ed25519DSIGN)
-> [Word8] -> SigDSIGN Ed25519DSIGN
forall a b. (a -> b) -> a -> b
$ Int -> Word8 -> [Word8]
forall a. Int -> a -> [a]
replicate Int
64 Word8
10))
        String -> String -> Expectation
forall a. (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation
`shouldEndWith` String
"0a0a0a\""

    String -> (ByteString -> ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"can sign arbitrary messages" ((ByteString -> ByteString -> Property) -> Spec)
-> (ByteString -> ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \(ByteString
msgA :: ByteString) (ByteString
msgB :: ByteString) ->
      Gen (Secret (SigningKey HydraKey))
-> (Secret (SigningKey HydraKey) -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll Gen (Secret (SigningKey HydraKey))
forall a. Arbitrary a => Gen a
arbitrary ((Secret (SigningKey HydraKey) -> Property) -> Property)
-> (Secret (SigningKey HydraKey) -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \(Secret (SigningKey HydraKey)
sk :: Secret (SigningKey HydraKey)) ->
        (ByteString
msgA ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
msgB) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          (Secret (SigningKey HydraKey) -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
Secret (SigningKey HydraKey) -> a -> Signature a
sign Secret (SigningKey HydraKey)
sk ByteString
msgA Signature ByteString -> Signature ByteString -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=/= Secret (SigningKey HydraKey) -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
Secret (SigningKey HydraKey) -> a -> Signature a
sign Secret (SigningKey HydraKey)
sk ByteString
msgB)

    String -> (ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"sign/verify roundtrip" ((ByteString -> Property) -> Spec)
-> (ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \(ByteString
msg :: ByteString) ->
      Gen (Secret (SigningKey HydraKey))
-> (Secret (SigningKey HydraKey) -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll Gen (Secret (SigningKey HydraKey))
forall a. Arbitrary a => Gen a
arbitrary ((Secret (SigningKey HydraKey) -> Property) -> Property)
-> (Secret (SigningKey HydraKey) -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \(Secret (SigningKey HydraKey)
sk :: Secret (SigningKey HydraKey)) ->
        let sig :: Signature ByteString
sig = Secret (SigningKey HydraKey) -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
Secret (SigningKey HydraKey) -> a -> Signature a
sign Secret (SigningKey HydraKey)
sk ByteString
msg
         in VerificationKey HydraKey
-> Signature ByteString -> ByteString -> Bool
forall a.
SignableRepresentation a =>
VerificationKey HydraKey -> Signature a -> a -> Bool
verify (Secret (SigningKey HydraKey) -> VerificationKey HydraKey
forall s k. HasVerificationKey s k => s -> VerificationKey k
getVerificationKey Secret (SigningKey HydraKey)
sk) Signature ByteString
sig ByteString
msg
              Bool -> (Bool -> Property) -> Property
forall a b. a -> (a -> b) -> b
& String -> Bool -> Property
forall prop. Testable prop => String -> prop -> Property
counterexample (Signature ByteString -> String
forall b a. (Show a, IsString b) => a -> b
show Signature ByteString
sig)

specMultiSignature :: Spec
specMultiSignature :: Spec
specMultiSignature =
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"MultiSignature" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> (HashSet (Signature ByteString) -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"is sensitive to order" ((HashSet (Signature ByteString) -> Property) -> Spec)
-> (HashSet (Signature ByteString) -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \(HashSet (Signature ByteString)
allSigs :: HashSet (Signature ByteString)) ->
      let sigs :: [Signature ByteString]
sigs = HashSet (Signature ByteString) -> [Signature ByteString]
forall a. HashSet a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList HashSet (Signature ByteString)
allSigs
       in Gen [Signature ByteString]
-> ([Signature ByteString] -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll ([Signature ByteString] -> Gen [Signature ByteString]
forall a. [a] -> Gen [a]
shuffle [Signature ByteString]
sigs) (([Signature ByteString] -> Property) -> Property)
-> ([Signature ByteString] -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \[Signature ByteString]
shuffled ->
            ([Signature ByteString] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Signature ByteString]
sigs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1 Bool -> Bool -> Bool
&& [Signature ByteString]
sigs [Signature ByteString] -> [Signature ByteString] -> Bool
forall a. Eq a => a -> a -> Bool
/= [Signature ByteString]
shuffled) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
              ([Signature ByteString] -> MultiSignature ByteString
forall a. [Signature a] -> MultiSignature a
aggregate [Signature ByteString]
sigs MultiSignature ByteString -> MultiSignature ByteString -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=/= [Signature ByteString] -> MultiSignature ByteString
forall a. [Signature a] -> MultiSignature a
aggregate [Signature ByteString]
shuffled)

    String -> (ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"aggregate/verifyMultiSignature roundtrip" ((ByteString -> Property) -> Spec)
-> (ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \(ByteString
msg :: ByteString) ->
      Gen [Secret (SigningKey HydraKey)]
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll Gen [Secret (SigningKey HydraKey)]
forall a. Arbitrary a => Gen a
arbitrary (([Secret (SigningKey HydraKey)] -> Property) -> Property)
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \([Secret (SigningKey HydraKey)]
sks :: [Secret (SigningKey HydraKey)]) ->
        let sigs :: [Signature ByteString]
sigs = (Secret (SigningKey HydraKey) -> Signature ByteString)
-> [Secret (SigningKey HydraKey)] -> [Signature ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (Secret (SigningKey HydraKey) -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
Secret (SigningKey HydraKey) -> a -> Signature a
`sign` ByteString
msg) [Secret (SigningKey HydraKey)]
sks
            msig :: MultiSignature ByteString
msig = [Signature ByteString] -> MultiSignature ByteString
forall a. [Signature a] -> MultiSignature a
aggregate [Signature ByteString]
sigs
            vks :: [VerificationKey HydraKey]
vks = (Secret (SigningKey HydraKey) -> VerificationKey HydraKey)
-> [Secret (SigningKey HydraKey)] -> [VerificationKey HydraKey]
forall a b. (a -> b) -> [a] -> [b]
map Secret (SigningKey HydraKey) -> VerificationKey HydraKey
forall s k. HasVerificationKey s k => s -> VerificationKey k
getVerificationKey [Secret (SigningKey HydraKey)]
sks
         in [VerificationKey HydraKey]
-> MultiSignature ByteString -> ByteString -> Verified
forall a.
SignableRepresentation a =>
[VerificationKey HydraKey] -> MultiSignature a -> a -> Verified
verifyMultiSignature [VerificationKey HydraKey]
vks MultiSignature ByteString
msig ByteString
msg Verified -> Verified -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Verified
Verified

    String -> (ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"aggregateInOrder/verifyMultiSignature roundtrip" ((ByteString -> Property) -> Spec)
-> (ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \(ByteString
msg :: ByteString) ->
      Gen [Secret (SigningKey HydraKey)]
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll Gen [Secret (SigningKey HydraKey)]
forall a. Arbitrary a => Gen a
arbitrary (([Secret (SigningKey HydraKey)] -> Property) -> Property)
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \([Secret (SigningKey HydraKey)]
sks :: [Secret (SigningKey HydraKey)]) ->
        let sigs :: Map Party (Signature ByteString)
sigs = [(Party, Signature ByteString)] -> Map Party (Signature ByteString)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(Party, Signature ByteString)]
 -> Map Party (Signature ByteString))
-> [(Party, Signature ByteString)]
-> Map Party (Signature ByteString)
forall a b. (a -> b) -> a -> b
$ (Secret (SigningKey HydraKey) -> (Party, Signature ByteString))
-> [Secret (SigningKey HydraKey)]
-> [(Party, Signature ByteString)]
forall a b. (a -> b) -> [a] -> [b]
map (\Secret (SigningKey HydraKey)
sk -> (Secret (SigningKey HydraKey) -> Party
deriveParty Secret (SigningKey HydraKey)
sk, Secret (SigningKey HydraKey) -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
Secret (SigningKey HydraKey) -> a -> Signature a
sign Secret (SigningKey HydraKey)
sk ByteString
msg)) [Secret (SigningKey HydraKey)]
sks
         in Gen [Party] -> ([Party] -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll ([Party] -> Gen [Party]
forall a. [a] -> Gen [a]
shuffle ([Party] -> Gen [Party]) -> [Party] -> Gen [Party]
forall a b. (a -> b) -> a -> b
$ Map Party (Signature ByteString) -> [Party]
forall k a. Map k a -> [k]
Map.keys Map Party (Signature ByteString)
sigs) (([Party] -> Property) -> Property)
-> ([Party] -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \[Party]
shuffled ->
              Bool -> Bool
not ([Party] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Party]
shuffled) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
                [VerificationKey HydraKey]
-> MultiSignature ByteString -> ByteString -> Verified
forall a.
SignableRepresentation a =>
[VerificationKey HydraKey] -> MultiSignature a -> a -> Verified
verifyMultiSignature ((Party -> VerificationKey HydraKey)
-> [Party] -> [VerificationKey HydraKey]
forall a b. (a -> b) -> [a] -> [b]
map Party -> VerificationKey HydraKey
vkey [Party]
shuffled) (Map Party (Signature ByteString)
-> [Party] -> MultiSignature ByteString
forall k a. Ord k => Map k (Signature a) -> [k] -> MultiSignature a
aggregateInOrder Map Party (Signature ByteString)
sigs [Party]
shuffled) ByteString
msg
                  Verified -> Verified -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Verified
Verified

    String -> (ByteString -> Signature ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"verifyMultiSignature fails when signature is missing" ((ByteString -> Signature ByteString -> Property) -> Spec)
-> (ByteString -> Signature ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \(ByteString
msg :: ByteString) Signature ByteString
dummySig ->
      Gen [Secret (SigningKey HydraKey)]
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll Gen [Secret (SigningKey HydraKey)]
forall a. Arbitrary a => Gen a
arbitrary (([Secret (SigningKey HydraKey)] -> Property) -> Property)
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \([Secret (SigningKey HydraKey)]
sks :: [Secret (SigningKey HydraKey)]) ->
        ([Secret (SigningKey HydraKey)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Secret (SigningKey HydraKey)]
sks Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
2) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          Gen (Secret (SigningKey HydraKey))
-> (Secret (SigningKey HydraKey) -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll ([Secret (SigningKey HydraKey)]
-> Gen (Secret (SigningKey HydraKey))
forall a. HasCallStack => [a] -> Gen a
elements [Secret (SigningKey HydraKey)]
sks) ((Secret (SigningKey HydraKey) -> Property) -> Property)
-> (Secret (SigningKey HydraKey) -> Property) -> Property
forall a b. (a -> b) -> a -> b
$
            \Secret (SigningKey HydraKey)
missingKeySig ->
              let sigs :: [Signature ByteString]
sigs = (\Secret (SigningKey HydraKey)
sk -> if Secret (SigningKey HydraKey)
sk Secret (SigningKey HydraKey)
-> Secret (SigningKey HydraKey) -> Bool
forall a. Eq a => a -> a -> Bool
/= Secret (SigningKey HydraKey)
missingKeySig then Secret (SigningKey HydraKey) -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
Secret (SigningKey HydraKey) -> a -> Signature a
sign Secret (SigningKey HydraKey)
sk ByteString
msg else Signature ByteString
dummySig) (Secret (SigningKey HydraKey) -> Signature ByteString)
-> [Secret (SigningKey HydraKey)] -> [Signature ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Secret (SigningKey HydraKey)]
sks
                  vks :: [VerificationKey HydraKey]
vks = (Secret (SigningKey HydraKey) -> VerificationKey HydraKey)
-> [Secret (SigningKey HydraKey)] -> [VerificationKey HydraKey]
forall a b. (a -> b) -> [a] -> [b]
map Secret (SigningKey HydraKey) -> VerificationKey HydraKey
forall s k. HasVerificationKey s k => s -> VerificationKey k
getVerificationKey [Secret (SigningKey HydraKey)]
sks
               in [VerificationKey HydraKey]
-> MultiSignature ByteString -> ByteString -> Verified
forall a.
SignableRepresentation a =>
[VerificationKey HydraKey] -> MultiSignature a -> a -> Verified
verifyMultiSignature [VerificationKey HydraKey]
vks ([Signature ByteString] -> MultiSignature ByteString
forall a. [Signature a] -> MultiSignature a
aggregate [Signature ByteString]
sigs) ByteString
msg
                    Verified -> Verified -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=/= Verified
Verified

    String -> (ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"does not validate multisig if less keys given" ((ByteString -> Property) -> Spec)
-> (ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \(ByteString
msg :: ByteString) -> do
      Gen [Secret (SigningKey HydraKey)]
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll Gen [Secret (SigningKey HydraKey)]
forall a. Arbitrary a => Gen a
arbitrary (([Secret (SigningKey HydraKey)] -> Property) -> Property)
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \([Secret (SigningKey HydraKey)]
sks :: [Secret (SigningKey HydraKey)]) ->
        Gen [Secret (SigningKey HydraKey)]
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll ([Secret (SigningKey HydraKey)]
-> Gen [Secret (SigningKey HydraKey)]
forall a. [a] -> Gen [a]
sublistOf [Secret (SigningKey HydraKey)]
sks) (([Secret (SigningKey HydraKey)] -> Property) -> Property)
-> ([Secret (SigningKey HydraKey)] -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \[Secret (SigningKey HydraKey)]
prefix ->
          ([Secret (SigningKey HydraKey)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Secret (SigningKey HydraKey)]
prefix Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< [Secret (SigningKey HydraKey)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Secret (SigningKey HydraKey)]
sks) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
            let sigs :: MultiSignature ByteString
sigs = [Signature ByteString] -> MultiSignature ByteString
forall a. [Signature a] -> MultiSignature a
aggregate ([Signature ByteString] -> MultiSignature ByteString)
-> [Signature ByteString] -> MultiSignature ByteString
forall a b. (a -> b) -> a -> b
$ (Secret (SigningKey HydraKey) -> Signature ByteString)
-> [Secret (SigningKey HydraKey)] -> [Signature ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (Secret (SigningKey HydraKey) -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
Secret (SigningKey HydraKey) -> a -> Signature a
`sign` ByteString
msg) ([Secret (SigningKey HydraKey)] -> [Secret (SigningKey HydraKey)]
forall a. [a] -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList [Secret (SigningKey HydraKey)]
sks)
                vks :: [VerificationKey HydraKey]
vks = (Secret (SigningKey HydraKey) -> VerificationKey HydraKey)
-> [Secret (SigningKey HydraKey)] -> [VerificationKey HydraKey]
forall a b. (a -> b) -> [a] -> [b]
map Secret (SigningKey HydraKey) -> VerificationKey HydraKey
forall s k. HasVerificationKey s k => s -> VerificationKey k
getVerificationKey [Secret (SigningKey HydraKey)]
prefix
             in [VerificationKey HydraKey]
-> MultiSignature ByteString -> ByteString -> Verified
forall a.
SignableRepresentation a =>
[VerificationKey HydraKey] -> MultiSignature a -> a -> Verified
verifyMultiSignature [VerificationKey HydraKey]
vks MultiSignature ByteString
sigs ByteString
msg
                  Verified -> Verified -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=/= Verified
Verified
                  Property -> (Property -> Property) -> Property
forall a b. a -> (a -> b) -> b
& Bool -> String -> Property -> Property
forall prop. Testable prop => Bool -> String -> prop -> Property
classify ([Secret (SigningKey HydraKey)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Secret (SigningKey HydraKey)]
prefix) String
"empty"
                  Property -> (Property -> Property) -> Property
forall a b. a -> (a -> b) -> b
& String -> Property -> Property
forall prop. Testable prop => String -> prop -> Property
counterexample (String
"Verification keys (prefix): " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> [VerificationKey HydraKey] -> String
forall b a. (Show a, IsString b) => a -> b
show [VerificationKey HydraKey]
vks)
                  Property -> (Property -> Property) -> Property
forall a b. a -> (a -> b) -> b
& String -> Property -> Property
forall prop. Testable prop => String -> prop -> Property
counterexample (String
"Signature: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> MultiSignature ByteString -> String
forall b a. (Show a, IsString b) => a -> b
show MultiSignature ByteString
sigs)