{-# LANGUAGE TypeFamilies #-} -- | 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 (..) -- * VRF-based eligibility proofs interface , VRFPoolContext (..) , NormalizedVRFOutput (..) , CryptoSupportsVRF (..) -- * Aggregate verification interface , CryptoSupportsAggregateVoteSigning (..) , CryptoSupportsBatchVRFVerification (..) ) where import Cardano.Ledger.BaseTypes (Nonce) import Data.Containers.NonEmpty (HasNonEmpty (..)) import Data.Kind (Type) 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 () -- * 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 -> ShowS [NormalizedVRFOutput] -> ShowS NormalizedVRFOutput -> String (Int -> NormalizedVRFOutput -> ShowS) -> (NormalizedVRFOutput -> String) -> ([NormalizedVRFOutput] -> ShowS) -> Show NormalizedVRFOutput forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> NormalizedVRFOutput -> ShowS showsPrec :: Int -> NormalizedVRFOutput -> ShowS $cshow :: NormalizedVRFOutput -> String show :: NormalizedVRFOutput -> String $cshowList :: [NormalizedVRFOutput] -> ShowS showList :: [NormalizedVRFOutput] -> ShowS 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 -- * Aggregate verification interface -- -- NOTE: vote signatures and VRF outputs are treated asymmetrically here. -- -- On one hand, individual vote signatures are used to prove the identity of -- of their issuers for a given election and candidate being voted for. When -- forging a certificate, we might want to aggregate the signatures of multiple -- voters that participated in the same election and voted for the same -- candidate into a single aggregate signature that attests the participation of -- the entire group of voters. Such a signature is much smaller than the sum of -- the individual signatures of each voter, and can be verified more efficiently -- than verifying each individual signature separately. To do so, verifiers will -- first need to create an aggregate verification key by combining the -- verification key of each voter in the group (whose identity will likely have -- to be declared in the corresponding certificate), and then verify the -- aggregate signature using the aggregate verification key in a single step. -- Note that since all voters sign the same thing (election ID and candidate), -- swapping the signatures of two voters in the group would not have any effect -- on the aggregate signature. -- -- On the other hand, VRF outputs attest both the eligibility of a single voter -- to participate in a given election /and/ the number of seats they are -- entitled to in such election (which can directly affect their voting power). -- Because of this, their VRF outputs cannot be aggregated into a single one -- when forging a certificate, and must instead be included individually. When -- verifying a certificate, however, we can still take advantage of aggregation -- to verify the VRF outputs of all voters in a single step, but since each VRF -- output might grant each voter a different number of seats, we need to be -- careful about swap-attacks. This is where an adversary could swap their VRF -- output with someone else's before forging a certificate, stealing their -- (more favorable) eligibility proof. To avoid this, the interface for batch -- VRF verification explicitly expects unaggregated VRF verification keys and -- VRF outputs, so that the implementation should be able to first bind each -- VRF output to the corresponding voter's verification key via linearization. -- In layman terms, this means multiplying each VRF output by a unique scalar -- before aggregating them. This enforces that, during verification, the order -- of the VRF outputs must match the order of the verification keys verification -- keys, thus avoiding any attempt of swapping VRF outputs between voters. -- | Crypto interface used for creating and verifying aggregate vote signatures class CryptoSupportsVoteSigning crypto => CryptoSupportsAggregateVoteSigning crypto where -- | Aggregate vote verification keys type AggregateVoteVerificationKey crypto :: Type -- | Aggregate vote signatures type AggregateVoteSignature crypto :: Type -- | Combine multiple vote verification keys into a single aggregate one aggregateVoteVerificationKeys :: Proxy crypto -> NE [VoteVerificationKey crypto] -> Either String (AggregateVoteVerificationKey crypto) -- | Combine multiple vote signatures into a single aggregate one aggregateVoteSignatures :: Proxy crypto -> NE [VoteSignature crypto] -> Either String (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 () -- | Crypto interface used for verifying multiple VRF outputs at once class CryptoSupportsVRF crypto => CryptoSupportsBatchVRFVerification crypto where -- | Verify a list of VRF outputs for a given election input using the -- corresponding verification keys of their issuers. -- -- NOTE: this expects non-aggregate VRF verification keys and VRF outputs so -- that each (key_i, output_i) pair can be bound at verification time (e.g. -- via linearization). This per-pair binding defeats swap-attacks where an -- adversary swaps their VRF output with someone else's more-favorable one -- before forging a certificate. batchVerifyVRFOutputs :: NE [VRFVerificationKey crypto] -> VRFElectionInput crypto -> NE [VRFOutput crypto] -> Either String ()