{-# LANGUAGE TypeApplications #-}

module Hydra.CryptoSpec where

-- Unit under test
import Hydra.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 qualified as Map
import Hydra.Party (Party (vkey), deriveParty)
import Test.Aeson.GenericSpecs (roundtripAndGoldenSpecs)
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
    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"show includes escaped hex" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      SigningKey HydraKey -> String
forall b a. (Show a, IsString b) => a -> b
show (ByteString -> SigningKey HydraKey
generateSigningKey ByteString
"aaa") String -> String -> Expectation
forall a. (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation
`shouldContain` String
"\"983487"
    String -> Expectation -> SpecM (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 -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (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 ByteString -> SigningKey HydraKey
generateSigningKey ByteString
exceedingSizeSeedA SigningKey HydraKey -> SigningKey HydraKey -> Expectation
forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
`shouldNotBe` ByteString -> 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) -> do
      (ByteString
seedA ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
seedB) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
        (ByteString -> SigningKey HydraKey
generateSigningKey ByteString
seedA SigningKey HydraKey -> SigningKey HydraKey -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=/= ByteString -> SigningKey HydraKey
generateSigningKey ByteString
seedB)
    String -> Gen (SigningKey HydraKey) -> Spec
forall a. (Show a, Eq a) => String -> Gen a -> Spec
propCollisionResistant String
"arbitrary @(SigningKey HydraKey)" (forall a. Arbitrary a => Gen a
arbitrary @(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 -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"show includes escaped hex" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      VerificationKey HydraKey -> String
forall b a. (Show a, IsString b) => a -> b
show (SigningKey HydraKey -> VerificationKey HydraKey
forall keyrole.
(Key keyrole, HasTypeProxy keyrole) =>
SigningKey keyrole -> VerificationKey keyrole
getVerificationKey (SigningKey HydraKey -> VerificationKey HydraKey)
-> SigningKey HydraKey -> VerificationKey HydraKey
forall a b. (a -> b) -> a -> b
$ ByteString -> 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 -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"show includes escaped hex" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (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 {k} (a :: k). SigDSIGN Ed25519DSIGN -> Signature a
HydraSignature (PinnedSizedBytes CRYPTO_SIGN_ED25519_BYTES -> SigDSIGN Ed25519DSIGN
PinnedSizedBytes (SizeSigDSIGN 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
-> (SigningKey HydraKey -> ByteString -> ByteString -> Property)
-> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"can sign arbitrary messages" ((SigningKey HydraKey -> ByteString -> ByteString -> Property)
 -> Spec)
-> (SigningKey HydraKey -> ByteString -> ByteString -> Property)
-> Spec
forall a b. (a -> b) -> a -> b
$ \SigningKey HydraKey
sk (ByteString
msgA :: ByteString) (ByteString
msgB :: ByteString) ->
      (ByteString
msgA ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
/= ByteString
msgB) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
        (SigningKey HydraKey -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
SigningKey HydraKey -> a -> Signature a
sign SigningKey HydraKey
sk ByteString
msgA Signature ByteString -> Signature ByteString -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=/= SigningKey HydraKey -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
SigningKey HydraKey -> a -> Signature a
sign SigningKey HydraKey
sk ByteString
msgB)

    String -> (SigningKey HydraKey -> ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"sign/verify roundtrip" ((SigningKey HydraKey -> ByteString -> Property) -> Spec)
-> (SigningKey HydraKey -> ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \SigningKey HydraKey
sk (ByteString
msg :: ByteString) ->
      let sig :: Signature ByteString
sig = SigningKey HydraKey -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
SigningKey HydraKey -> a -> Signature a
sign SigningKey HydraKey
sk ByteString
msg
       in VerificationKey HydraKey
-> Signature ByteString -> ByteString -> Bool
forall a.
SignableRepresentation a =>
VerificationKey HydraKey -> Signature a -> a -> Bool
verify (SigningKey HydraKey -> VerificationKey HydraKey
forall keyrole.
(Key keyrole, HasTypeProxy keyrole) =>
SigningKey keyrole -> VerificationKey keyrole
getVerificationKey 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 {k} (a :: k). [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 {k} (a :: k). [Signature a] -> MultiSignature a
aggregate [Signature ByteString]
shuffled)

    String -> ([SigningKey HydraKey] -> ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"aggregate/verifyMultiSignature roundtrip" (([SigningKey HydraKey] -> ByteString -> Property) -> Spec)
-> ([SigningKey HydraKey] -> ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \[SigningKey HydraKey]
sks (ByteString
msg :: ByteString) ->
      let sigs :: [Signature ByteString]
sigs = (SigningKey HydraKey -> Signature ByteString)
-> [SigningKey HydraKey] -> [Signature ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (SigningKey HydraKey -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
SigningKey HydraKey -> a -> Signature a
`sign` ByteString
msg) [SigningKey HydraKey]
sks
          msig :: MultiSignature ByteString
msig = [Signature ByteString] -> MultiSignature ByteString
forall {k} (a :: k). [Signature a] -> MultiSignature a
aggregate [Signature ByteString]
sigs
          vks :: [VerificationKey HydraKey]
vks = SigningKey HydraKey -> VerificationKey HydraKey
forall keyrole.
(Key keyrole, HasTypeProxy keyrole) =>
SigningKey keyrole -> VerificationKey keyrole
getVerificationKey (SigningKey HydraKey -> VerificationKey HydraKey)
-> [SigningKey HydraKey] -> [VerificationKey HydraKey]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [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 -> ([SigningKey HydraKey] -> ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"aggregateInOrder/verifyMultiSignature roundtrip" (([SigningKey HydraKey] -> ByteString -> Property) -> Spec)
-> ([SigningKey HydraKey] -> ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \[SigningKey HydraKey]
sks (ByteString
msg :: ByteString) ->
      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
$ (SigningKey HydraKey -> (Party, Signature ByteString))
-> [SigningKey HydraKey] -> [(Party, Signature ByteString)]
forall a b. (a -> b) -> [a] -> [b]
map (\SigningKey HydraKey
sk -> (SigningKey HydraKey -> Party
deriveParty SigningKey HydraKey
sk, SigningKey HydraKey -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
SigningKey HydraKey -> a -> Signature a
sign SigningKey HydraKey
sk ByteString
msg)) [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 {k1} k2 (a :: k1).
Ord k2 =>
Map k2 (Signature a) -> [k2] -> 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
-> ([SigningKey HydraKey]
    -> ByteString -> Signature ByteString -> Property)
-> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"verifyMultiSignature fails when signature is missing" (([SigningKey HydraKey]
  -> ByteString -> Signature ByteString -> Property)
 -> Spec)
-> ([SigningKey HydraKey]
    -> ByteString -> Signature ByteString -> Property)
-> Spec
forall a b. (a -> b) -> a -> b
$ \[SigningKey HydraKey]
sks (ByteString
msg :: ByteString) Signature ByteString
dummySig ->
      ([SigningKey HydraKey] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [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 (SigningKey HydraKey)
-> (SigningKey HydraKey -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll ([SigningKey HydraKey] -> Gen (SigningKey HydraKey)
forall a. [a] -> Gen a
elements [SigningKey HydraKey]
sks) ((SigningKey HydraKey -> Property) -> Property)
-> (SigningKey HydraKey -> Property) -> Property
forall a b. (a -> b) -> a -> b
$
          \SigningKey HydraKey
missingKeySig ->
            let sigs :: [Signature ByteString]
sigs = (\SigningKey HydraKey
sk -> if SigningKey HydraKey
sk SigningKey HydraKey -> SigningKey HydraKey -> Bool
forall a. Eq a => a -> a -> Bool
/= SigningKey HydraKey
missingKeySig then SigningKey HydraKey -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
SigningKey HydraKey -> a -> Signature a
sign SigningKey HydraKey
sk ByteString
msg else Signature ByteString
dummySig) (SigningKey HydraKey -> Signature ByteString)
-> [SigningKey HydraKey] -> [Signature ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [SigningKey HydraKey]
sks
             in [VerificationKey HydraKey]
-> MultiSignature ByteString -> ByteString -> Verified
forall a.
SignableRepresentation a =>
[VerificationKey HydraKey] -> MultiSignature a -> a -> Verified
verifyMultiSignature ((SigningKey HydraKey -> VerificationKey HydraKey)
-> [SigningKey HydraKey] -> [VerificationKey HydraKey]
forall a b. (a -> b) -> [a] -> [b]
map SigningKey HydraKey -> VerificationKey HydraKey
forall keyrole.
(Key keyrole, HasTypeProxy keyrole) =>
SigningKey keyrole -> VerificationKey keyrole
getVerificationKey [SigningKey HydraKey]
sks) ([Signature ByteString] -> MultiSignature ByteString
forall {k} (a :: k). [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 -> ([SigningKey HydraKey] -> ByteString -> Property) -> Spec
forall prop.
(HasCallStack, Testable prop) =>
String -> prop -> Spec
prop String
"does not validate multisig if less keys given" (([SigningKey HydraKey] -> ByteString -> Property) -> Spec)
-> ([SigningKey HydraKey] -> ByteString -> Property) -> Spec
forall a b. (a -> b) -> a -> b
$ \[SigningKey HydraKey]
sks (ByteString
msg :: ByteString) -> do
      Gen [SigningKey HydraKey]
-> ([SigningKey HydraKey] -> Property) -> Property
forall a prop.
(Show a, Testable prop) =>
Gen a -> (a -> prop) -> Property
forAll ([SigningKey HydraKey] -> Gen [SigningKey HydraKey]
forall a. [a] -> Gen [a]
sublistOf [SigningKey HydraKey]
sks) (([SigningKey HydraKey] -> Property) -> Property)
-> ([SigningKey HydraKey] -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \[SigningKey HydraKey]
prefix ->
        ([SigningKey HydraKey] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [SigningKey HydraKey]
prefix Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< [SigningKey HydraKey] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [SigningKey HydraKey]
sks) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          let sigs :: MultiSignature ByteString
sigs = [Signature ByteString] -> MultiSignature ByteString
forall {k} (a :: k). [Signature a] -> MultiSignature a
aggregate ([Signature ByteString] -> MultiSignature ByteString)
-> [Signature ByteString] -> MultiSignature ByteString
forall a b. (a -> b) -> a -> b
$ (SigningKey HydraKey -> Signature ByteString)
-> [SigningKey HydraKey] -> [Signature ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (SigningKey HydraKey -> ByteString -> Signature ByteString
forall a.
SignableRepresentation a =>
SigningKey HydraKey -> a -> Signature a
`sign` ByteString
msg) ([SigningKey HydraKey] -> [SigningKey HydraKey]
forall a. [a] -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList [SigningKey HydraKey]
sks)
           in [VerificationKey HydraKey]
-> MultiSignature ByteString -> ByteString -> Verified
forall a.
SignableRepresentation a =>
[VerificationKey HydraKey] -> MultiSignature a -> a -> Verified
verifyMultiSignature ((SigningKey HydraKey -> VerificationKey HydraKey)
-> [SigningKey HydraKey] -> [VerificationKey HydraKey]
forall a b. (a -> b) -> [a] -> [b]
map SigningKey HydraKey -> VerificationKey HydraKey
forall keyrole.
(Key keyrole, HasTypeProxy keyrole) =>
SigningKey keyrole -> VerificationKey keyrole
getVerificationKey [SigningKey HydraKey]
prefix) 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 ([SigningKey HydraKey] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [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
"Keys: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> [SigningKey HydraKey] -> String
forall b a. (Show a, IsString b) => a -> b
show [SigningKey HydraKey]
prefix)
                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)