{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

-- | Generic interface used by implementations of voting committees.
--
-- NOTE: concrete implementations might not need to implement all these
-- interfaces, especially the ones regarding VRF-based eligibility proofs and
-- aggregate vote signature verification.
module Ouroboros.Consensus.Committee.Crypto
  ( -- * Core types associated to voting committees
    PrivateKey
  , PublicKey
  , ElectionId
  , VoteCandidate

    -- * Vote signing interface
  , CryptoSupportsVoteSigning (..)
  , CryptoSupportsAggregateVoteSigning (..)

    -- ** Trivial aggregate vote signature verification helpers
  , TrivialAggregateVoteVerificationKey (..)
  , TrivialAggregateVoteSignature (..)
  , trivialLiftVoteVerificationKey
  , trivialLiftVoteSignature
  , trivialVerifyAggregateVoteSignature

    -- * VRF-based eligibility proofs interface
  , VRFPoolContext (..)
  , NormalizedVRFOutput (..)
  , CryptoSupportsVRF (..)
  , CryptoSupportsAggregateVRF (..)

    -- ** Trivial aggregate VRF verification helpers
  , TrivialAggregateVRFVerificationKey (..)
  , TrivialAggregateVRFOutput (..)
  , trivialLiftVRFVerificationKey
  , trivialLiftVRFOutput
  , trivialVerifyAggregateVRFOutput
  ) where

import Cardano.Ledger.BaseTypes (Nonce)
import Data.Containers.NonEmpty (HasNonEmpty (..))
import Data.Either (partitionEithers)
import Data.Kind (Type)
import Data.List (intercalate)
import qualified Data.List.NonEmpty as NonEmpty
import Data.Proxy (Proxy)

-- * Core types associated to voting committees

-- | Private key used within the voting committee
type family PrivateKey crypto :: Type

-- | Public key used within the voting committee
type family PublicKey crypto :: Type

-- | Election identifiers
type family ElectionId crypto :: Type

-- | Vote candidates, i.e., what's being voted for
type family VoteCandidate crypto :: Type

-- * Vote signing interface

-- | Crypto interface used for signing and verifying votes
class CryptoSupportsVoteSigning crypto where
  -- | Key used for signing votes
  type VoteSigningKey crypto :: Type

  -- | Key used for verifying votes
  type VoteVerificationKey crypto :: Type

  -- | Cryptographic signature of a vote
  data VoteSignature crypto :: Type

  -- | Derive a signing key from a voting committee private key
  getVoteSigningKey ::
    Proxy crypto ->
    PrivateKey crypto ->
    VoteSigningKey crypto

  -- | Derive a verification key from a voting committee public key
  getVoteVerificationKey ::
    Proxy crypto ->
    PublicKey crypto ->
    VoteVerificationKey crypto

  -- | Sign a vote candidate in a given election
  signVote ::
    VoteSigningKey crypto ->
    ElectionId crypto ->
    VoteCandidate crypto ->
    VoteSignature crypto

  -- | Verify the signature of a vote candidate in a given election
  verifyVoteSignature ::
    VoteVerificationKey crypto ->
    ElectionId crypto ->
    VoteCandidate crypto ->
    VoteSignature crypto ->
    Either String ()

-- | Crypto interface used for verifying aggregate vote signatures
class
  ( Semigroup (AggregateVoteVerificationKey crypto)
  , Semigroup (AggregateVoteSignature crypto)
  ) =>
  CryptoSupportsAggregateVoteSigning crypto
  where
  -- | Key used for verifying aggregate vote signatures
  type AggregateVoteVerificationKey crypto :: Type

  -- | Aggregate cryptographic signature of a vote
  type AggregateVoteSignature crypto :: Type

  -- | Lift a single vote signature verification key into an aggregate one
  liftVoteVerificationKey ::
    Proxy crypto ->
    VoteVerificationKey crypto ->
    AggregateVoteVerificationKey crypto

  -- | Lift a single vote signature into an aggregate one
  liftVoteSignature ::
    Proxy crypto ->
    VoteSignature crypto ->
    AggregateVoteSignature crypto

  -- | Verify an aggregate vote signature for a given election and candidate
  verifyAggregateVoteSignature ::
    Proxy crypto ->
    AggregateVoteVerificationKey crypto ->
    ElectionId crypto ->
    VoteCandidate crypto ->
    AggregateVoteSignature crypto ->
    Either String ()

-- ** Trivial aggregate vote signature verification helpers

newtype TrivialAggregateVoteVerificationKey crypto
  = TrivialAggregateVoteVerificationKey (NE [VoteVerificationKey crypto])
  deriving newtype NonEmpty (TrivialAggregateVoteVerificationKey crypto)
-> TrivialAggregateVoteVerificationKey crypto
TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
(TrivialAggregateVoteVerificationKey crypto
 -> TrivialAggregateVoteVerificationKey crypto
 -> TrivialAggregateVoteVerificationKey crypto)
-> (NonEmpty (TrivialAggregateVoteVerificationKey crypto)
    -> TrivialAggregateVoteVerificationKey crypto)
-> (forall b.
    Integral b =>
    b
    -> TrivialAggregateVoteVerificationKey crypto
    -> TrivialAggregateVoteVerificationKey crypto)
-> Semigroup (TrivialAggregateVoteVerificationKey crypto)
forall b.
Integral b =>
b
-> TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
forall crypto.
NonEmpty (TrivialAggregateVoteVerificationKey crypto)
-> TrivialAggregateVoteVerificationKey crypto
forall crypto.
TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
forall crypto b.
Integral b =>
b
-> TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
$c<> :: forall crypto.
TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
<> :: TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
$csconcat :: forall crypto.
NonEmpty (TrivialAggregateVoteVerificationKey crypto)
-> TrivialAggregateVoteVerificationKey crypto
sconcat :: NonEmpty (TrivialAggregateVoteVerificationKey crypto)
-> TrivialAggregateVoteVerificationKey crypto
$cstimes :: forall crypto b.
Integral b =>
b
-> TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
stimes :: forall b.
Integral b =>
b
-> TrivialAggregateVoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
Semigroup

newtype TrivialAggregateVoteSignature crypto
  = TrivialAggregateVoteSignature (NE [VoteSignature crypto])
  deriving newtype NonEmpty (TrivialAggregateVoteSignature crypto)
-> TrivialAggregateVoteSignature crypto
TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
(TrivialAggregateVoteSignature crypto
 -> TrivialAggregateVoteSignature crypto
 -> TrivialAggregateVoteSignature crypto)
-> (NonEmpty (TrivialAggregateVoteSignature crypto)
    -> TrivialAggregateVoteSignature crypto)
-> (forall b.
    Integral b =>
    b
    -> TrivialAggregateVoteSignature crypto
    -> TrivialAggregateVoteSignature crypto)
-> Semigroup (TrivialAggregateVoteSignature crypto)
forall b.
Integral b =>
b
-> TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
forall crypto.
NonEmpty (TrivialAggregateVoteSignature crypto)
-> TrivialAggregateVoteSignature crypto
forall crypto.
TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
forall crypto b.
Integral b =>
b
-> TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
$c<> :: forall crypto.
TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
<> :: TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
$csconcat :: forall crypto.
NonEmpty (TrivialAggregateVoteSignature crypto)
-> TrivialAggregateVoteSignature crypto
sconcat :: NonEmpty (TrivialAggregateVoteSignature crypto)
-> TrivialAggregateVoteSignature crypto
$cstimes :: forall crypto b.
Integral b =>
b
-> TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
stimes :: forall b.
Integral b =>
b
-> TrivialAggregateVoteSignature crypto
-> TrivialAggregateVoteSignature crypto
Semigroup

trivialLiftVoteVerificationKey ::
  Proxy crypto ->
  VoteVerificationKey crypto ->
  TrivialAggregateVoteVerificationKey crypto
trivialLiftVoteVerificationKey :: forall crypto.
Proxy crypto
-> VoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
trivialLiftVoteVerificationKey Proxy crypto
_ =
  NonEmpty (VoteVerificationKey crypto)
-> TrivialAggregateVoteVerificationKey crypto
NE [VoteVerificationKey crypto]
-> TrivialAggregateVoteVerificationKey crypto
forall crypto.
NE [VoteVerificationKey crypto]
-> TrivialAggregateVoteVerificationKey crypto
TrivialAggregateVoteVerificationKey
    (NonEmpty (VoteVerificationKey crypto)
 -> TrivialAggregateVoteVerificationKey crypto)
-> (VoteVerificationKey crypto
    -> NonEmpty (VoteVerificationKey crypto))
-> VoteVerificationKey crypto
-> TrivialAggregateVoteVerificationKey crypto
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VoteVerificationKey crypto -> NonEmpty (VoteVerificationKey crypto)
forall a. a -> NonEmpty a
NonEmpty.singleton

trivialLiftVoteSignature ::
  Proxy crypto ->
  VoteSignature crypto ->
  TrivialAggregateVoteSignature crypto
trivialLiftVoteSignature :: forall crypto.
Proxy crypto
-> VoteSignature crypto -> TrivialAggregateVoteSignature crypto
trivialLiftVoteSignature Proxy crypto
_ =
  NonEmpty (VoteSignature crypto)
-> TrivialAggregateVoteSignature crypto
NE [VoteSignature crypto] -> TrivialAggregateVoteSignature crypto
forall crypto.
NE [VoteSignature crypto] -> TrivialAggregateVoteSignature crypto
TrivialAggregateVoteSignature
    (NonEmpty (VoteSignature crypto)
 -> TrivialAggregateVoteSignature crypto)
-> (VoteSignature crypto -> NonEmpty (VoteSignature crypto))
-> VoteSignature crypto
-> TrivialAggregateVoteSignature crypto
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VoteSignature crypto -> NonEmpty (VoteSignature crypto)
forall a. a -> NonEmpty a
NonEmpty.singleton

trivialVerifyAggregateVoteSignature ::
  CryptoSupportsVoteSigning crypto =>
  Proxy crypto ->
  TrivialAggregateVoteVerificationKey crypto ->
  ElectionId crypto ->
  VoteCandidate crypto ->
  TrivialAggregateVoteSignature crypto ->
  Either String ()
trivialVerifyAggregateVoteSignature :: forall crypto.
CryptoSupportsVoteSigning crypto =>
Proxy crypto
-> TrivialAggregateVoteVerificationKey crypto
-> ElectionId crypto
-> VoteCandidate crypto
-> TrivialAggregateVoteSignature crypto
-> Either String ()
trivialVerifyAggregateVoteSignature
  Proxy crypto
_
  (TrivialAggregateVoteVerificationKey NE [VoteVerificationKey crypto]
keys)
  ElectionId crypto
electionId
  VoteCandidate crypto
candidate
  (TrivialAggregateVoteSignature NE [VoteSignature crypto]
signatures)
    | NonEmpty (VoteVerificationKey crypto) -> Int
forall a. NonEmpty a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length NonEmpty (VoteVerificationKey crypto)
NE [VoteVerificationKey crypto]
keys Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= NonEmpty (VoteSignature crypto) -> Int
forall a. NonEmpty a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length NonEmpty (VoteSignature crypto)
NE [VoteSignature crypto]
signatures =
        String -> Either String ()
forall a b. a -> Either a b
Left (String -> Either String ()) -> String -> Either String ()
forall a b. (a -> b) -> a -> b
$
          String
"Aggregate vote signature verification failed: "
            String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"number of keys and signatures do not match"
    | Bool -> Bool
not ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
errors) =
        String -> Either String ()
forall a b. a -> Either a b
Left (String -> Either String ()) -> String -> Either String ()
forall a b. (a -> b) -> a -> b
$
          String
"Aggregate vote signature verification failed: "
            String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"; " [String]
errors
    | Bool
otherwise =
        () -> Either String ()
forall a b. b -> Either a b
Right ()
   where
    ([String]
errors, [()]
_) =
      [Either String ()] -> ([String], [()])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either String ()] -> ([String], [()]))
-> [Either String ()] -> ([String], [()])
forall a b. (a -> b) -> a -> b
$
        (VoteVerificationKey crypto
 -> VoteSignature crypto -> Either String ())
-> [VoteVerificationKey crypto]
-> [VoteSignature crypto]
-> [Either String ()]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith
          ( \VoteVerificationKey crypto
key VoteSignature crypto
sig ->
              VoteVerificationKey crypto
-> ElectionId crypto
-> VoteCandidate crypto
-> VoteSignature crypto
-> Either String ()
forall crypto.
CryptoSupportsVoteSigning crypto =>
VoteVerificationKey crypto
-> ElectionId crypto
-> VoteCandidate crypto
-> VoteSignature crypto
-> Either String ()
verifyVoteSignature VoteVerificationKey crypto
key ElectionId crypto
electionId VoteCandidate crypto
candidate VoteSignature crypto
sig
          )
          (NonEmpty (VoteVerificationKey crypto)
-> [VoteVerificationKey crypto]
forall a. NonEmpty a -> [a]
NonEmpty.toList NonEmpty (VoteVerificationKey crypto)
NE [VoteVerificationKey crypto]
keys)
          (NonEmpty (VoteSignature crypto) -> [VoteSignature crypto]
forall a. NonEmpty a -> [a]
NonEmpty.toList NonEmpty (VoteSignature crypto)
NE [VoteSignature crypto]
signatures)

-- * VRF-based eligibility proofs interface

-- | Context in which a VRF input is evaluated.
--
-- This distinguishes between the case where we want to compute our own VRF
-- output, and the case where we want to verify the VRF output of someone else.
data VRFPoolContext crypto
  = -- | Compute our own VRF output by signing the VRF input with our signing key
    VRFSignContext (VRFSigningKey crypto)
  | -- | Verify the local sortition output of another participant by verifying
    -- their signature over the VRF input using their verification key
    VRFVerifyContext (VRFVerificationKey crypto) (VRFOutput crypto)

-- | Normalized VRF outputs as a rational between 0 and 1
newtype NormalizedVRFOutput = NormalizedVRFOutput
  { NormalizedVRFOutput -> Rational
unNormalizedVRFOutput :: Rational
  }
  deriving (NormalizedVRFOutput -> NormalizedVRFOutput -> Bool
(NormalizedVRFOutput -> NormalizedVRFOutput -> Bool)
-> (NormalizedVRFOutput -> NormalizedVRFOutput -> Bool)
-> Eq NormalizedVRFOutput
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NormalizedVRFOutput -> NormalizedVRFOutput -> Bool
== :: NormalizedVRFOutput -> NormalizedVRFOutput -> Bool
$c/= :: NormalizedVRFOutput -> NormalizedVRFOutput -> Bool
/= :: NormalizedVRFOutput -> NormalizedVRFOutput -> Bool
Eq, Int -> NormalizedVRFOutput -> String -> String
[NormalizedVRFOutput] -> String -> String
NormalizedVRFOutput -> String
(Int -> NormalizedVRFOutput -> String -> String)
-> (NormalizedVRFOutput -> String)
-> ([NormalizedVRFOutput] -> String -> String)
-> Show NormalizedVRFOutput
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> NormalizedVRFOutput -> String -> String
showsPrec :: Int -> NormalizedVRFOutput -> String -> String
$cshow :: NormalizedVRFOutput -> String
show :: NormalizedVRFOutput -> String
$cshowList :: [NormalizedVRFOutput] -> String -> String
showList :: [NormalizedVRFOutput] -> String -> String
Show)

-- | Crypto interface used to proof eligibility via local sortition
class CryptoSupportsVRF crypto where
  -- | Private key used for computing our own VRF output
  type VRFSigningKey crypto :: Type

  -- | Public key used for verifying the VRF output of other participants
  type VRFVerificationKey crypto :: Type

  -- | Input to the verifiable random function.
  --
  -- This is fixed across all participants for a given election.
  data VRFElectionInput crypto :: Type

  -- | Output of the verifiable random function
  data VRFOutput crypto :: Type

  -- | Derive a VRF signing key from a voting committee private key
  getVRFSigningKey ::
    Proxy crypto ->
    PrivateKey crypto ->
    VRFSigningKey crypto

  -- | Derive a VRF verification key from a voting committee public key
  getVRFVerificationKey ::
    Proxy crypto ->
    PublicKey crypto ->
    VRFVerificationKey crypto

  -- | Construct a VRF input from a nonce and an election identifier
  mkVRFElectionInput ::
    Nonce ->
    ElectionId crypto ->
    VRFElectionInput crypto

  -- | Evaluate a VRF input in a given context
  evalVRF ::
    VRFPoolContext crypto ->
    VRFElectionInput crypto ->
    Either String (VRFOutput crypto)

  -- | Normalize a VRF output to a value in [0, 1]
  normalizeVRFOutput ::
    VRFOutput crypto ->
    NormalizedVRFOutput

-- | Crypto interface used for verifying aggregate VRF signatures
class
  ( Semigroup (AggregateVRFVerificationKey crypto)
  , Semigroup (AggregateVRFOutput crypto)
  ) =>
  CryptoSupportsAggregateVRF crypto
  where
  -- | Key used for verifying aggregate VRF outputs
  type AggregateVRFVerificationKey crypto :: Type

  -- | Aggregate cryptographic signature of a VRF output
  type AggregateVRFOutput crypto :: Type

  -- | Lift a single VRF output verification key into an aggregate one
  liftVRFVerificationKey ::
    Proxy crypto ->
    VRFVerificationKey crypto ->
    AggregateVRFVerificationKey crypto

  -- | Lift a single VRF output into an aggregate one
  liftVRFOutput ::
    Proxy crypto ->
    VRFOutput crypto ->
    AggregateVRFOutput crypto

  -- | Verify an aggregate vote signature for a given election and candidate
  verifyAggregateVRFOutput ::
    AggregateVRFVerificationKey crypto ->
    VRFElectionInput crypto ->
    AggregateVRFOutput crypto ->
    Either String ()

-- ** Trivial aggregate VRF verification helpers

newtype TrivialAggregateVRFVerificationKey crypto
  = TrivialAggregateVRFVerificationKey (NE [VRFVerificationKey crypto])
  deriving newtype NonEmpty (TrivialAggregateVRFVerificationKey crypto)
-> TrivialAggregateVRFVerificationKey crypto
TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
(TrivialAggregateVRFVerificationKey crypto
 -> TrivialAggregateVRFVerificationKey crypto
 -> TrivialAggregateVRFVerificationKey crypto)
-> (NonEmpty (TrivialAggregateVRFVerificationKey crypto)
    -> TrivialAggregateVRFVerificationKey crypto)
-> (forall b.
    Integral b =>
    b
    -> TrivialAggregateVRFVerificationKey crypto
    -> TrivialAggregateVRFVerificationKey crypto)
-> Semigroup (TrivialAggregateVRFVerificationKey crypto)
forall b.
Integral b =>
b
-> TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
forall crypto.
NonEmpty (TrivialAggregateVRFVerificationKey crypto)
-> TrivialAggregateVRFVerificationKey crypto
forall crypto.
TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
forall crypto b.
Integral b =>
b
-> TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
$c<> :: forall crypto.
TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
<> :: TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
$csconcat :: forall crypto.
NonEmpty (TrivialAggregateVRFVerificationKey crypto)
-> TrivialAggregateVRFVerificationKey crypto
sconcat :: NonEmpty (TrivialAggregateVRFVerificationKey crypto)
-> TrivialAggregateVRFVerificationKey crypto
$cstimes :: forall crypto b.
Integral b =>
b
-> TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
stimes :: forall b.
Integral b =>
b
-> TrivialAggregateVRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
Semigroup

newtype TrivialAggregateVRFOutput crypto
  = TrivialAggregateVRFOutput (NE [VRFOutput crypto])
  deriving newtype NonEmpty (TrivialAggregateVRFOutput crypto)
-> TrivialAggregateVRFOutput crypto
TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
(TrivialAggregateVRFOutput crypto
 -> TrivialAggregateVRFOutput crypto
 -> TrivialAggregateVRFOutput crypto)
-> (NonEmpty (TrivialAggregateVRFOutput crypto)
    -> TrivialAggregateVRFOutput crypto)
-> (forall b.
    Integral b =>
    b
    -> TrivialAggregateVRFOutput crypto
    -> TrivialAggregateVRFOutput crypto)
-> Semigroup (TrivialAggregateVRFOutput crypto)
forall b.
Integral b =>
b
-> TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
forall crypto.
NonEmpty (TrivialAggregateVRFOutput crypto)
-> TrivialAggregateVRFOutput crypto
forall crypto.
TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
forall crypto b.
Integral b =>
b
-> TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
$c<> :: forall crypto.
TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
<> :: TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
$csconcat :: forall crypto.
NonEmpty (TrivialAggregateVRFOutput crypto)
-> TrivialAggregateVRFOutput crypto
sconcat :: NonEmpty (TrivialAggregateVRFOutput crypto)
-> TrivialAggregateVRFOutput crypto
$cstimes :: forall crypto b.
Integral b =>
b
-> TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
stimes :: forall b.
Integral b =>
b
-> TrivialAggregateVRFOutput crypto
-> TrivialAggregateVRFOutput crypto
Semigroup

trivialLiftVRFVerificationKey ::
  Proxy crypto ->
  VRFVerificationKey crypto ->
  TrivialAggregateVRFVerificationKey crypto
trivialLiftVRFVerificationKey :: forall crypto.
Proxy crypto
-> VRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
trivialLiftVRFVerificationKey Proxy crypto
_ =
  NonEmpty (VRFVerificationKey crypto)
-> TrivialAggregateVRFVerificationKey crypto
NE [VRFVerificationKey crypto]
-> TrivialAggregateVRFVerificationKey crypto
forall crypto.
NE [VRFVerificationKey crypto]
-> TrivialAggregateVRFVerificationKey crypto
TrivialAggregateVRFVerificationKey
    (NonEmpty (VRFVerificationKey crypto)
 -> TrivialAggregateVRFVerificationKey crypto)
-> (VRFVerificationKey crypto
    -> NonEmpty (VRFVerificationKey crypto))
-> VRFVerificationKey crypto
-> TrivialAggregateVRFVerificationKey crypto
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VRFVerificationKey crypto -> NonEmpty (VRFVerificationKey crypto)
forall a. a -> NonEmpty a
NonEmpty.singleton

trivialLiftVRFOutput ::
  Proxy crypto ->
  VRFOutput crypto ->
  TrivialAggregateVRFOutput crypto
trivialLiftVRFOutput :: forall crypto.
Proxy crypto
-> VRFOutput crypto -> TrivialAggregateVRFOutput crypto
trivialLiftVRFOutput Proxy crypto
_ =
  NonEmpty (VRFOutput crypto) -> TrivialAggregateVRFOutput crypto
NE [VRFOutput crypto] -> TrivialAggregateVRFOutput crypto
forall crypto.
NE [VRFOutput crypto] -> TrivialAggregateVRFOutput crypto
TrivialAggregateVRFOutput
    (NonEmpty (VRFOutput crypto) -> TrivialAggregateVRFOutput crypto)
-> (VRFOutput crypto -> NonEmpty (VRFOutput crypto))
-> VRFOutput crypto
-> TrivialAggregateVRFOutput crypto
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VRFOutput crypto -> NonEmpty (VRFOutput crypto)
forall a. a -> NonEmpty a
NonEmpty.singleton

trivialVerifyAggregateVRFOutput ::
  CryptoSupportsVRF crypto =>
  TrivialAggregateVRFVerificationKey crypto ->
  VRFElectionInput crypto ->
  TrivialAggregateVRFOutput crypto ->
  Either String ()
trivialVerifyAggregateVRFOutput :: forall crypto.
CryptoSupportsVRF crypto =>
TrivialAggregateVRFVerificationKey crypto
-> VRFElectionInput crypto
-> TrivialAggregateVRFOutput crypto
-> Either String ()
trivialVerifyAggregateVRFOutput
  (TrivialAggregateVRFVerificationKey NE [VRFVerificationKey crypto]
keys)
  VRFElectionInput crypto
vrfInput
  (TrivialAggregateVRFOutput NE [VRFOutput crypto]
vrfOutputs)
    | NonEmpty (VRFVerificationKey crypto) -> Int
forall a. NonEmpty a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length NonEmpty (VRFVerificationKey crypto)
NE [VRFVerificationKey crypto]
keys Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= NonEmpty (VRFOutput crypto) -> Int
forall a. NonEmpty a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length NonEmpty (VRFOutput crypto)
NE [VRFOutput crypto]
vrfOutputs =
        String -> Either String ()
forall a b. a -> Either a b
Left (String -> Either String ()) -> String -> Either String ()
forall a b. (a -> b) -> a -> b
$
          String
"Aggregate VRF output verification failed: "
            String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"number of keys and outputs do not match"
    | Bool -> Bool
not ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
errors) =
        String -> Either String ()
forall a b. a -> Either a b
Left (String -> Either String ()) -> String -> Either String ()
forall a b. (a -> b) -> a -> b
$
          String
"Aggregate VRF output verification failed: "
            String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"; " [String]
errors
    | Bool
otherwise =
        () -> Either String ()
forall a b. b -> Either a b
Right ()
   where
    ([String]
errors, [VRFOutput crypto]
_) =
      [Either String (VRFOutput crypto)]
-> ([String], [VRFOutput crypto])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either String (VRFOutput crypto)]
 -> ([String], [VRFOutput crypto]))
-> [Either String (VRFOutput crypto)]
-> ([String], [VRFOutput crypto])
forall a b. (a -> b) -> a -> b
$
        (VRFVerificationKey crypto
 -> VRFOutput crypto -> Either String (VRFOutput crypto))
-> [VRFVerificationKey crypto]
-> [VRFOutput crypto]
-> [Either String (VRFOutput crypto)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith
          ( \VRFVerificationKey crypto
key VRFOutput crypto
vrfOutput ->
              VRFPoolContext crypto
-> VRFElectionInput crypto -> Either String (VRFOutput crypto)
forall crypto.
CryptoSupportsVRF crypto =>
VRFPoolContext crypto
-> VRFElectionInput crypto -> Either String (VRFOutput crypto)
evalVRF (VRFVerificationKey crypto
-> VRFOutput crypto -> VRFPoolContext crypto
forall crypto.
VRFVerificationKey crypto
-> VRFOutput crypto -> VRFPoolContext crypto
VRFVerifyContext VRFVerificationKey crypto
key VRFOutput crypto
vrfOutput) VRFElectionInput crypto
vrfInput
          )
          (NonEmpty (VRFVerificationKey crypto) -> [VRFVerificationKey crypto]
forall a. NonEmpty a -> [a]
NonEmpty.toList NonEmpty (VRFVerificationKey crypto)
NE [VRFVerificationKey crypto]
keys)
          (NonEmpty (VRFOutput crypto) -> [VRFOutput crypto]
forall a. NonEmpty a -> [a]
NonEmpty.toList NonEmpty (VRFOutput crypto)
NE [VRFOutput crypto]
vrfOutputs)