{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

-- | BLS-based crypto scheme used in Peras voting committees
module Ouroboros.Consensus.Peras.Crypto.BLS
  ( PerasBLSCrypto
  , ElectionId
  , VoteCandidate
  , PerasPrivateKey (..)
  , PerasPublicKey (..)
  , VoteSignature (..)
  , VRFElectionInput (..)
  , VRFOutput (..)
  , AggregateVoteVerificationKey
  , AggregateVoteSignature

    -- * For testing purposes
  , PerasBLSCryptoAggregateVoteVerificationKey (..)
  , PerasBLSCryptoAggregateVoteSignature (..)
  ) where

import Cardano.Binary (FromCBOR, ToCBOR (..))
import Cardano.Crypto.DSIGN (BLS12381MinSigDSIGN, DSIGNAlgorithm (..))
import Cardano.Crypto.Hash (Hash)
import qualified Cardano.Crypto.Hash as Hash
import Cardano.Ledger.BaseTypes (Nonce (..), SlotNo (..))
import Cardano.Ledger.Binary (runByteBuilder)
import Cardano.Ledger.Hashes (HASH)
import qualified Data.ByteString.Builder as BS
import qualified Data.ByteString.Builder.Extra as BS
import qualified Data.ByteString.Short as BS
import Ouroboros.Consensus.Block.RealPoint
  ( bytes32RealPointHash
  , bytes32RealPointSlot
  )
import Ouroboros.Consensus.Block.SupportsPeras
  ( PerasBoostedBlock (..)
  , PerasRoundNo (..)
  )
import Ouroboros.Consensus.Committee.Crypto
  ( CryptoSupportsAggregateVoteSigning (..)
  , CryptoSupportsBatchVRFVerification (..)
  , CryptoSupportsVRF (..)
  , CryptoSupportsVoteSigning (..)
  , ElectionId
  , PrivateKey
  , PublicKey
  , VRFPoolContext (..)
  , VoteCandidate
  )
import Ouroboros.Consensus.Committee.Crypto.BLS (KeyRole (..))
import qualified Ouroboros.Consensus.Committee.Crypto.BLS as BLS

-- | BLS-based crypto scheme used in Peras voting committees
data PerasBLSCrypto

type instance ElectionId PerasBLSCrypto = PerasRoundNo
type instance VoteCandidate PerasBLSCrypto = PerasBoostedBlock

-- | Private key of a Peras committee member
data PerasPrivateKey
  = PerasPrivateKey
  { PerasPrivateKey -> PrivateKey SIGN
perasVoteSignKey :: BLS.PrivateKey SIGN
  , PerasPrivateKey -> PrivateKey VRF
perasVRFSignKey :: BLS.PrivateKey VRF
  }

type instance PrivateKey PerasBLSCrypto = PerasPrivateKey

-- | Public key of a Peras committee member
data PerasPublicKey
  = PerasPublicKey
  { PerasPublicKey -> PublicKey SIGN
perasVoteVerKey :: BLS.PublicKey SIGN
  , PerasPublicKey -> PublicKey VRF
perasVRFVerKey :: BLS.PublicKey VRF
  }

type instance PublicKey PerasBLSCrypto = PerasPublicKey

-- | Hash the message of a Peras vote
--
-- NOTE: this is inspired by the implementation used by the Praos VRF check in
-- 'Ouroboros.Consensus.Protocol.Praos.VRF.mkInputVRF'.
hashVoteSignature ::
  ElectionId PerasBLSCrypto ->
  VoteCandidate PerasBLSCrypto ->
  Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
hashVoteSignature :: ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
hashVoteSignature ElectionId PerasBLSCrypto
roundNo VoteCandidate PerasBLSCrypto
boostedBlock =
  Hash HASH ByteString -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
forall h a b. Hash h a -> Hash h b
Hash.castHash
    (Hash HASH ByteString -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN))
-> (Builder -> Hash HASH ByteString)
-> Builder
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> ByteString) -> ByteString -> Hash HASH ByteString
forall h a. HashAlgorithm h => (a -> ByteString) -> a -> Hash h a
Hash.hashWith ByteString -> ByteString
forall a. a -> a
id
    (ByteString -> Hash HASH ByteString)
-> (Builder -> ByteString) -> Builder -> Hash HASH ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Builder -> ByteString
runByteBuilder (Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
32)
    (Builder -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN))
-> Builder -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
forall a b. (a -> b) -> a -> b
$ Builder
roundNoBytes
      Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
boostedBlockSlotBytes
      Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
boostedBlockHashBytes
 where
  roundNoBytes :: Builder
roundNoBytes =
    Word64 -> Builder
BS.word64BE
      (Word64 -> Builder)
-> (ElectionId PerasBLSCrypto -> Word64)
-> ElectionId PerasBLSCrypto
-> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ElectionId PerasBLSCrypto -> Word64
PerasRoundNo -> Word64
unPerasRoundNo
      (ElectionId PerasBLSCrypto -> Builder)
-> ElectionId PerasBLSCrypto -> Builder
forall a b. (a -> b) -> a -> b
$ ElectionId PerasBLSCrypto
roundNo
  boostedBlockSlotBytes :: Builder
boostedBlockSlotBytes =
    Word64 -> Builder
BS.word64BE
      (Word64 -> Builder)
-> (VoteCandidate PerasBLSCrypto -> Word64)
-> VoteCandidate PerasBLSCrypto
-> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SlotNo -> Word64
unSlotNo
      (SlotNo -> Word64)
-> (PerasBoostedBlock -> SlotNo) -> PerasBoostedBlock -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes32RealPoint -> SlotNo
bytes32RealPointSlot
      (Bytes32RealPoint -> SlotNo)
-> (PerasBoostedBlock -> Bytes32RealPoint)
-> PerasBoostedBlock
-> SlotNo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PerasBoostedBlock -> Bytes32RealPoint
unPerasBoostedBlock
      (VoteCandidate PerasBLSCrypto -> Builder)
-> VoteCandidate PerasBLSCrypto -> Builder
forall a b. (a -> b) -> a -> b
$ VoteCandidate PerasBLSCrypto
boostedBlock
  boostedBlockHashBytes :: Builder
boostedBlockHashBytes =
    ByteString -> Builder
BS.byteStringCopy
      (ByteString -> Builder)
-> (VoteCandidate PerasBLSCrypto -> ByteString)
-> VoteCandidate PerasBLSCrypto
-> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortByteString -> ByteString
BS.fromShort
      (ShortByteString -> ByteString)
-> (PerasBoostedBlock -> ShortByteString)
-> PerasBoostedBlock
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes32RealPoint -> ShortByteString
bytes32RealPointHash
      (Bytes32RealPoint -> ShortByteString)
-> (PerasBoostedBlock -> Bytes32RealPoint)
-> PerasBoostedBlock
-> ShortByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PerasBoostedBlock -> Bytes32RealPoint
unPerasBoostedBlock
      (VoteCandidate PerasBLSCrypto -> Builder)
-> VoteCandidate PerasBLSCrypto -> Builder
forall a b. (a -> b) -> a -> b
$ VoteCandidate PerasBLSCrypto
boostedBlock

-- | Hash the input for the VRF used in Peras elections
--
-- NOTE: this is inspired by the implementation used by the Praos VRF check in
-- 'Ouroboros.Consensus.Protocol.Praos.VRF.mkInputVRF'.
hashVRFInput ::
  ElectionId PerasBLSCrypto ->
  Nonce ->
  Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
hashVRFInput :: ElectionId PerasBLSCrypto
-> Nonce -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
hashVRFInput ElectionId PerasBLSCrypto
roundNo Nonce
epochNonce =
  Hash HASH ByteString -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
forall h a b. Hash h a -> Hash h b
Hash.castHash
    (Hash HASH ByteString -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN))
-> (Builder -> Hash HASH ByteString)
-> Builder
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> ByteString) -> ByteString -> Hash HASH ByteString
forall h a. HashAlgorithm h => (a -> ByteString) -> a -> Hash h a
Hash.hashWith ByteString -> ByteString
forall a. a -> a
id
    (ByteString -> Hash HASH ByteString)
-> (Builder -> ByteString) -> Builder -> Hash HASH ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Builder -> ByteString
runByteBuilder (Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
32)
    (Builder -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN))
-> Builder -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
forall a b. (a -> b) -> a -> b
$ Builder
roundNoBytes Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
epochNonceBytes
 where
  roundNoBytes :: Builder
roundNoBytes =
    Word64 -> Builder
BS.word64BE (PerasRoundNo -> Word64
unPerasRoundNo ElectionId PerasBLSCrypto
PerasRoundNo
roundNo)
  epochNonceBytes :: Builder
epochNonceBytes =
    case Nonce
epochNonce of
      Nonce
NeutralNonce -> Builder
forall a. Monoid a => a
mempty
      Nonce Hash HASH Nonce
h -> ByteString -> Builder
BS.byteStringCopy (Hash HASH Nonce -> ByteString
forall h a. Hash h a -> ByteString
Hash.hashToBytes Hash HASH Nonce
h)

-- * Crypto instances

instance CryptoSupportsVoteSigning PerasBLSCrypto where
  type VoteSigningKey PerasBLSCrypto = BLS.PrivateKey SIGN
  type VoteVerificationKey PerasBLSCrypto = BLS.PublicKey SIGN

  newtype VoteSignature PerasBLSCrypto
    = PerasBLSCryptoVoteSignature
    { VoteSignature PerasBLSCrypto -> Signature SIGN
unPerasBLSCryptoVoteSignature ::
        BLS.Signature BLS.SIGN
    }
    deriving stock (VoteSignature PerasBLSCrypto
-> VoteSignature PerasBLSCrypto -> Bool
(VoteSignature PerasBLSCrypto
 -> VoteSignature PerasBLSCrypto -> Bool)
-> (VoteSignature PerasBLSCrypto
    -> VoteSignature PerasBLSCrypto -> Bool)
-> Eq (VoteSignature PerasBLSCrypto)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: VoteSignature PerasBLSCrypto
-> VoteSignature PerasBLSCrypto -> Bool
== :: VoteSignature PerasBLSCrypto
-> VoteSignature PerasBLSCrypto -> Bool
$c/= :: VoteSignature PerasBLSCrypto
-> VoteSignature PerasBLSCrypto -> Bool
/= :: VoteSignature PerasBLSCrypto
-> VoteSignature PerasBLSCrypto -> Bool
Eq, Int -> VoteSignature PerasBLSCrypto -> ShowS
[VoteSignature PerasBLSCrypto] -> ShowS
VoteSignature PerasBLSCrypto -> String
(Int -> VoteSignature PerasBLSCrypto -> ShowS)
-> (VoteSignature PerasBLSCrypto -> String)
-> ([VoteSignature PerasBLSCrypto] -> ShowS)
-> Show (VoteSignature PerasBLSCrypto)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VoteSignature PerasBLSCrypto -> ShowS
showsPrec :: Int -> VoteSignature PerasBLSCrypto -> ShowS
$cshow :: VoteSignature PerasBLSCrypto -> String
show :: VoteSignature PerasBLSCrypto -> String
$cshowList :: [VoteSignature PerasBLSCrypto] -> ShowS
showList :: [VoteSignature PerasBLSCrypto] -> ShowS
Show)
    deriving newtype (Typeable (VoteSignature PerasBLSCrypto)
Typeable (VoteSignature PerasBLSCrypto) =>
(forall s. Decoder s (VoteSignature PerasBLSCrypto))
-> (Proxy (VoteSignature PerasBLSCrypto) -> Text)
-> FromCBOR (VoteSignature PerasBLSCrypto)
Proxy (VoteSignature PerasBLSCrypto) -> Text
forall s. Decoder s (VoteSignature PerasBLSCrypto)
forall a.
Typeable a =>
(forall s. Decoder s a) -> (Proxy a -> Text) -> FromCBOR a
$cfromCBOR :: forall s. Decoder s (VoteSignature PerasBLSCrypto)
fromCBOR :: forall s. Decoder s (VoteSignature PerasBLSCrypto)
$clabel :: Proxy (VoteSignature PerasBLSCrypto) -> Text
label :: Proxy (VoteSignature PerasBLSCrypto) -> Text
FromCBOR, Typeable (VoteSignature PerasBLSCrypto)
Typeable (VoteSignature PerasBLSCrypto) =>
(VoteSignature PerasBLSCrypto -> Encoding)
-> ((forall t. ToCBOR t => Proxy t -> Size)
    -> Proxy (VoteSignature PerasBLSCrypto) -> Size)
-> ((forall t. ToCBOR t => Proxy t -> Size)
    -> Proxy [VoteSignature PerasBLSCrypto] -> Size)
-> ToCBOR (VoteSignature PerasBLSCrypto)
VoteSignature PerasBLSCrypto -> Encoding
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [VoteSignature PerasBLSCrypto] -> Size
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (VoteSignature PerasBLSCrypto) -> Size
forall a.
Typeable a =>
(a -> Encoding)
-> ((forall t. ToCBOR t => Proxy t -> Size) -> Proxy a -> Size)
-> ((forall t. ToCBOR t => Proxy t -> Size) -> Proxy [a] -> Size)
-> ToCBOR a
$ctoCBOR :: VoteSignature PerasBLSCrypto -> Encoding
toCBOR :: VoteSignature PerasBLSCrypto -> Encoding
$cencodedSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (VoteSignature PerasBLSCrypto) -> Size
encodedSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (VoteSignature PerasBLSCrypto) -> Size
$cencodedListSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [VoteSignature PerasBLSCrypto] -> Size
encodedListSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [VoteSignature PerasBLSCrypto] -> Size
ToCBOR)

  getVoteSigningKey :: Proxy PerasBLSCrypto
-> PrivateKey PerasBLSCrypto -> VoteSigningKey PerasBLSCrypto
getVoteSigningKey Proxy PerasBLSCrypto
_ =
    PrivateKey PerasBLSCrypto -> VoteSigningKey PerasBLSCrypto
PerasPrivateKey -> PrivateKey SIGN
perasVoteSignKey
  getVoteVerificationKey :: Proxy PerasBLSCrypto
-> PublicKey PerasBLSCrypto -> VoteVerificationKey PerasBLSCrypto
getVoteVerificationKey Proxy PerasBLSCrypto
_ =
    PublicKey PerasBLSCrypto -> VoteVerificationKey PerasBLSCrypto
PerasPublicKey -> PublicKey SIGN
perasVoteVerKey

  signVote :: VoteSigningKey PerasBLSCrypto
-> ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> VoteSignature PerasBLSCrypto
signVote VoteSigningKey PerasBLSCrypto
sk ElectionId PerasBLSCrypto
roundNo VoteCandidate PerasBLSCrypto
boostedBlock =
    Signature SIGN -> VoteSignature PerasBLSCrypto
PerasBLSCryptoVoteSignature
      (Signature SIGN -> VoteSignature PerasBLSCrypto)
-> (Hash HASH (SigDSIGN BLS12381MinSigDSIGN) -> Signature SIGN)
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
-> VoteSignature PerasBLSCrypto
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (r :: KeyRole) msg.
(SignableRepresentation msg, HasBLSContext r) =>
PrivateKey r -> msg -> Signature r
BLS.signWithRole @SIGN VoteSigningKey PerasBLSCrypto
PrivateKey SIGN
sk
      (Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
 -> VoteSignature PerasBLSCrypto)
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
-> VoteSignature PerasBLSCrypto
forall a b. (a -> b) -> a -> b
$ ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
hashVoteSignature ElectionId PerasBLSCrypto
roundNo VoteCandidate PerasBLSCrypto
boostedBlock

  verifyVoteSignature :: VoteVerificationKey PerasBLSCrypto
-> ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> VoteSignature PerasBLSCrypto
-> Either String ()
verifyVoteSignature
    VoteVerificationKey PerasBLSCrypto
pk
    ElectionId PerasBLSCrypto
roundNo
    VoteCandidate PerasBLSCrypto
boostedBlock
    (PerasBLSCryptoVoteSignature Signature SIGN
sig) =
      forall (r :: KeyRole) msg.
(SignableRepresentation msg, HasBLSContext r) =>
PublicKey r -> msg -> Signature r -> Either String ()
BLS.verifyWithRole @SIGN
        VoteVerificationKey PerasBLSCrypto
PublicKey SIGN
pk
        (ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
hashVoteSignature ElectionId PerasBLSCrypto
roundNo VoteCandidate PerasBLSCrypto
boostedBlock)
        Signature SIGN
sig

instance CryptoSupportsVRF PerasBLSCrypto where
  type VRFSigningKey PerasBLSCrypto = BLS.PrivateKey VRF
  type VRFVerificationKey PerasBLSCrypto = BLS.PublicKey VRF

  newtype VRFElectionInput PerasBLSCrypto
    = PerasBLSCryptoVRFElectionInput
    { VRFElectionInput PerasBLSCrypto
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
unPerasBLSCryptoVRFElectionInput ::
        Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
    }
    deriving stock (VRFElectionInput PerasBLSCrypto
-> VRFElectionInput PerasBLSCrypto -> Bool
(VRFElectionInput PerasBLSCrypto
 -> VRFElectionInput PerasBLSCrypto -> Bool)
-> (VRFElectionInput PerasBLSCrypto
    -> VRFElectionInput PerasBLSCrypto -> Bool)
-> Eq (VRFElectionInput PerasBLSCrypto)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: VRFElectionInput PerasBLSCrypto
-> VRFElectionInput PerasBLSCrypto -> Bool
== :: VRFElectionInput PerasBLSCrypto
-> VRFElectionInput PerasBLSCrypto -> Bool
$c/= :: VRFElectionInput PerasBLSCrypto
-> VRFElectionInput PerasBLSCrypto -> Bool
/= :: VRFElectionInput PerasBLSCrypto
-> VRFElectionInput PerasBLSCrypto -> Bool
Eq, Int -> VRFElectionInput PerasBLSCrypto -> ShowS
[VRFElectionInput PerasBLSCrypto] -> ShowS
VRFElectionInput PerasBLSCrypto -> String
(Int -> VRFElectionInput PerasBLSCrypto -> ShowS)
-> (VRFElectionInput PerasBLSCrypto -> String)
-> ([VRFElectionInput PerasBLSCrypto] -> ShowS)
-> Show (VRFElectionInput PerasBLSCrypto)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VRFElectionInput PerasBLSCrypto -> ShowS
showsPrec :: Int -> VRFElectionInput PerasBLSCrypto -> ShowS
$cshow :: VRFElectionInput PerasBLSCrypto -> String
show :: VRFElectionInput PerasBLSCrypto -> String
$cshowList :: [VRFElectionInput PerasBLSCrypto] -> ShowS
showList :: [VRFElectionInput PerasBLSCrypto] -> ShowS
Show)

  newtype VRFOutput PerasBLSCrypto
    = PerasBLSCryptoVRFOutput
    { VRFOutput PerasBLSCrypto -> Signature VRF
unPerasBLSCryptoVRFOutput ::
        BLS.Signature VRF
    }
    deriving stock (VRFOutput PerasBLSCrypto -> VRFOutput PerasBLSCrypto -> Bool
(VRFOutput PerasBLSCrypto -> VRFOutput PerasBLSCrypto -> Bool)
-> (VRFOutput PerasBLSCrypto -> VRFOutput PerasBLSCrypto -> Bool)
-> Eq (VRFOutput PerasBLSCrypto)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: VRFOutput PerasBLSCrypto -> VRFOutput PerasBLSCrypto -> Bool
== :: VRFOutput PerasBLSCrypto -> VRFOutput PerasBLSCrypto -> Bool
$c/= :: VRFOutput PerasBLSCrypto -> VRFOutput PerasBLSCrypto -> Bool
/= :: VRFOutput PerasBLSCrypto -> VRFOutput PerasBLSCrypto -> Bool
Eq, Int -> VRFOutput PerasBLSCrypto -> ShowS
[VRFOutput PerasBLSCrypto] -> ShowS
VRFOutput PerasBLSCrypto -> String
(Int -> VRFOutput PerasBLSCrypto -> ShowS)
-> (VRFOutput PerasBLSCrypto -> String)
-> ([VRFOutput PerasBLSCrypto] -> ShowS)
-> Show (VRFOutput PerasBLSCrypto)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VRFOutput PerasBLSCrypto -> ShowS
showsPrec :: Int -> VRFOutput PerasBLSCrypto -> ShowS
$cshow :: VRFOutput PerasBLSCrypto -> String
show :: VRFOutput PerasBLSCrypto -> String
$cshowList :: [VRFOutput PerasBLSCrypto] -> ShowS
showList :: [VRFOutput PerasBLSCrypto] -> ShowS
Show)
    deriving newtype (Typeable (VRFOutput PerasBLSCrypto)
Typeable (VRFOutput PerasBLSCrypto) =>
(forall s. Decoder s (VRFOutput PerasBLSCrypto))
-> (Proxy (VRFOutput PerasBLSCrypto) -> Text)
-> FromCBOR (VRFOutput PerasBLSCrypto)
Proxy (VRFOutput PerasBLSCrypto) -> Text
forall s. Decoder s (VRFOutput PerasBLSCrypto)
forall a.
Typeable a =>
(forall s. Decoder s a) -> (Proxy a -> Text) -> FromCBOR a
$cfromCBOR :: forall s. Decoder s (VRFOutput PerasBLSCrypto)
fromCBOR :: forall s. Decoder s (VRFOutput PerasBLSCrypto)
$clabel :: Proxy (VRFOutput PerasBLSCrypto) -> Text
label :: Proxy (VRFOutput PerasBLSCrypto) -> Text
FromCBOR, Typeable (VRFOutput PerasBLSCrypto)
Typeable (VRFOutput PerasBLSCrypto) =>
(VRFOutput PerasBLSCrypto -> Encoding)
-> ((forall t. ToCBOR t => Proxy t -> Size)
    -> Proxy (VRFOutput PerasBLSCrypto) -> Size)
-> ((forall t. ToCBOR t => Proxy t -> Size)
    -> Proxy [VRFOutput PerasBLSCrypto] -> Size)
-> ToCBOR (VRFOutput PerasBLSCrypto)
VRFOutput PerasBLSCrypto -> Encoding
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [VRFOutput PerasBLSCrypto] -> Size
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (VRFOutput PerasBLSCrypto) -> Size
forall a.
Typeable a =>
(a -> Encoding)
-> ((forall t. ToCBOR t => Proxy t -> Size) -> Proxy a -> Size)
-> ((forall t. ToCBOR t => Proxy t -> Size) -> Proxy [a] -> Size)
-> ToCBOR a
$ctoCBOR :: VRFOutput PerasBLSCrypto -> Encoding
toCBOR :: VRFOutput PerasBLSCrypto -> Encoding
$cencodedSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (VRFOutput PerasBLSCrypto) -> Size
encodedSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy (VRFOutput PerasBLSCrypto) -> Size
$cencodedListSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [VRFOutput PerasBLSCrypto] -> Size
encodedListSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [VRFOutput PerasBLSCrypto] -> Size
ToCBOR)

  getVRFSigningKey :: Proxy PerasBLSCrypto
-> PrivateKey PerasBLSCrypto -> VRFSigningKey PerasBLSCrypto
getVRFSigningKey Proxy PerasBLSCrypto
_ =
    PrivateKey PerasBLSCrypto -> VRFSigningKey PerasBLSCrypto
PerasPrivateKey -> PrivateKey VRF
perasVRFSignKey

  getVRFVerificationKey :: Proxy PerasBLSCrypto
-> PublicKey PerasBLSCrypto -> VRFVerificationKey PerasBLSCrypto
getVRFVerificationKey Proxy PerasBLSCrypto
_ =
    PublicKey PerasBLSCrypto -> VRFVerificationKey PerasBLSCrypto
PerasPublicKey -> PublicKey VRF
perasVRFVerKey

  mkVRFElectionInput :: Nonce
-> ElectionId PerasBLSCrypto -> VRFElectionInput PerasBLSCrypto
mkVRFElectionInput Nonce
epochNonce ElectionId PerasBLSCrypto
roundNo =
    Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
-> VRFElectionInput PerasBLSCrypto
PerasBLSCryptoVRFElectionInput (Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
 -> VRFElectionInput PerasBLSCrypto)
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
-> VRFElectionInput PerasBLSCrypto
forall a b. (a -> b) -> a -> b
$
      ElectionId PerasBLSCrypto
-> Nonce -> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
hashVRFInput ElectionId PerasBLSCrypto
roundNo Nonce
epochNonce

  evalVRF :: VRFPoolContext PerasBLSCrypto
-> VRFElectionInput PerasBLSCrypto
-> Either String (VRFOutput PerasBLSCrypto)
evalVRF VRFPoolContext PerasBLSCrypto
context (PerasBLSCryptoVRFElectionInput Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
input) =
    case VRFPoolContext PerasBLSCrypto
context of
      VRFSignContext VRFSigningKey PerasBLSCrypto
sk -> do
        let sig :: Signature VRF
sig = forall (r :: KeyRole) msg.
(SignableRepresentation msg, HasBLSContext r) =>
PrivateKey r -> msg -> Signature r
BLS.signWithRole @VRF (forall (r2 :: KeyRole) (r1 :: KeyRole).
PrivateKey r1 -> PrivateKey r2
BLS.coercePrivateKey @VRF VRFSigningKey PerasBLSCrypto
PrivateKey VRF
sk) Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
input
        VRFOutput PerasBLSCrypto
-> Either String (VRFOutput PerasBLSCrypto)
forall a. a -> Either String a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (VRFOutput PerasBLSCrypto
 -> Either String (VRFOutput PerasBLSCrypto))
-> VRFOutput PerasBLSCrypto
-> Either String (VRFOutput PerasBLSCrypto)
forall a b. (a -> b) -> a -> b
$ Signature VRF -> VRFOutput PerasBLSCrypto
PerasBLSCryptoVRFOutput Signature VRF
sig
      VRFVerifyContext VRFVerificationKey PerasBLSCrypto
pk (PerasBLSCryptoVRFOutput Signature VRF
sig) -> do
        forall (r :: KeyRole) msg.
(SignableRepresentation msg, HasBLSContext r) =>
PublicKey r -> msg -> Signature r -> Either String ()
BLS.verifyWithRole @VRF (forall (r2 :: KeyRole) (r1 :: KeyRole).
PublicKey r1 -> PublicKey r2
BLS.coercePublicKey @VRF VRFVerificationKey PerasBLSCrypto
PublicKey VRF
pk) Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
input Signature VRF
sig
        VRFOutput PerasBLSCrypto
-> Either String (VRFOutput PerasBLSCrypto)
forall a. a -> Either String a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (VRFOutput PerasBLSCrypto
 -> Either String (VRFOutput PerasBLSCrypto))
-> VRFOutput PerasBLSCrypto
-> Either String (VRFOutput PerasBLSCrypto)
forall a b. (a -> b) -> a -> b
$ Signature VRF -> VRFOutput PerasBLSCrypto
PerasBLSCryptoVRFOutput Signature VRF
sig

  normalizeVRFOutput :: VRFOutput PerasBLSCrypto -> NormalizedVRFOutput
normalizeVRFOutput (PerasBLSCryptoVRFOutput Signature VRF
sig) =
    Signature VRF -> NormalizedVRFOutput
BLS.toNormalizedVRFOutput Signature VRF
sig

-- * Support for aggregate signatures and VRF outputs

-- | Wrapper around the aggregate vote signatures.
newtype PerasBLSCryptoAggregateVoteVerificationKey
  = PerasBLSCryptoAggregateVoteVerificationKey
  { PerasBLSCryptoAggregateVoteVerificationKey -> PublicKey SIGN
unPerasBLSCryptoAggregateVoteVerificationKey ::
      BLS.PublicKey SIGN
  }
  deriving stock (PerasBLSCryptoAggregateVoteVerificationKey
-> PerasBLSCryptoAggregateVoteVerificationKey -> Bool
(PerasBLSCryptoAggregateVoteVerificationKey
 -> PerasBLSCryptoAggregateVoteVerificationKey -> Bool)
-> (PerasBLSCryptoAggregateVoteVerificationKey
    -> PerasBLSCryptoAggregateVoteVerificationKey -> Bool)
-> Eq PerasBLSCryptoAggregateVoteVerificationKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PerasBLSCryptoAggregateVoteVerificationKey
-> PerasBLSCryptoAggregateVoteVerificationKey -> Bool
== :: PerasBLSCryptoAggregateVoteVerificationKey
-> PerasBLSCryptoAggregateVoteVerificationKey -> Bool
$c/= :: PerasBLSCryptoAggregateVoteVerificationKey
-> PerasBLSCryptoAggregateVoteVerificationKey -> Bool
/= :: PerasBLSCryptoAggregateVoteVerificationKey
-> PerasBLSCryptoAggregateVoteVerificationKey -> Bool
Eq, Int -> PerasBLSCryptoAggregateVoteVerificationKey -> ShowS
[PerasBLSCryptoAggregateVoteVerificationKey] -> ShowS
PerasBLSCryptoAggregateVoteVerificationKey -> String
(Int -> PerasBLSCryptoAggregateVoteVerificationKey -> ShowS)
-> (PerasBLSCryptoAggregateVoteVerificationKey -> String)
-> ([PerasBLSCryptoAggregateVoteVerificationKey] -> ShowS)
-> Show PerasBLSCryptoAggregateVoteVerificationKey
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PerasBLSCryptoAggregateVoteVerificationKey -> ShowS
showsPrec :: Int -> PerasBLSCryptoAggregateVoteVerificationKey -> ShowS
$cshow :: PerasBLSCryptoAggregateVoteVerificationKey -> String
show :: PerasBLSCryptoAggregateVoteVerificationKey -> String
$cshowList :: [PerasBLSCryptoAggregateVoteVerificationKey] -> ShowS
showList :: [PerasBLSCryptoAggregateVoteVerificationKey] -> ShowS
Show)

-- | Wrapper around the aggregate vote verification keys.
newtype PerasBLSCryptoAggregateVoteSignature
  = PerasBLSCryptoAggregateVoteSignature
  { PerasBLSCryptoAggregateVoteSignature -> Signature SIGN
unPerasBLSCryptoAggregateVoteSignature ::
      BLS.Signature SIGN
  }
  deriving stock (PerasBLSCryptoAggregateVoteSignature
-> PerasBLSCryptoAggregateVoteSignature -> Bool
(PerasBLSCryptoAggregateVoteSignature
 -> PerasBLSCryptoAggregateVoteSignature -> Bool)
-> (PerasBLSCryptoAggregateVoteSignature
    -> PerasBLSCryptoAggregateVoteSignature -> Bool)
-> Eq PerasBLSCryptoAggregateVoteSignature
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PerasBLSCryptoAggregateVoteSignature
-> PerasBLSCryptoAggregateVoteSignature -> Bool
== :: PerasBLSCryptoAggregateVoteSignature
-> PerasBLSCryptoAggregateVoteSignature -> Bool
$c/= :: PerasBLSCryptoAggregateVoteSignature
-> PerasBLSCryptoAggregateVoteSignature -> Bool
/= :: PerasBLSCryptoAggregateVoteSignature
-> PerasBLSCryptoAggregateVoteSignature -> Bool
Eq, Int -> PerasBLSCryptoAggregateVoteSignature -> ShowS
[PerasBLSCryptoAggregateVoteSignature] -> ShowS
PerasBLSCryptoAggregateVoteSignature -> String
(Int -> PerasBLSCryptoAggregateVoteSignature -> ShowS)
-> (PerasBLSCryptoAggregateVoteSignature -> String)
-> ([PerasBLSCryptoAggregateVoteSignature] -> ShowS)
-> Show PerasBLSCryptoAggregateVoteSignature
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PerasBLSCryptoAggregateVoteSignature -> ShowS
showsPrec :: Int -> PerasBLSCryptoAggregateVoteSignature -> ShowS
$cshow :: PerasBLSCryptoAggregateVoteSignature -> String
show :: PerasBLSCryptoAggregateVoteSignature -> String
$cshowList :: [PerasBLSCryptoAggregateVoteSignature] -> ShowS
showList :: [PerasBLSCryptoAggregateVoteSignature] -> ShowS
Show)
  deriving newtype (Typeable PerasBLSCryptoAggregateVoteSignature
Typeable PerasBLSCryptoAggregateVoteSignature =>
(forall s. Decoder s PerasBLSCryptoAggregateVoteSignature)
-> (Proxy PerasBLSCryptoAggregateVoteSignature -> Text)
-> FromCBOR PerasBLSCryptoAggregateVoteSignature
Proxy PerasBLSCryptoAggregateVoteSignature -> Text
forall s. Decoder s PerasBLSCryptoAggregateVoteSignature
forall a.
Typeable a =>
(forall s. Decoder s a) -> (Proxy a -> Text) -> FromCBOR a
$cfromCBOR :: forall s. Decoder s PerasBLSCryptoAggregateVoteSignature
fromCBOR :: forall s. Decoder s PerasBLSCryptoAggregateVoteSignature
$clabel :: Proxy PerasBLSCryptoAggregateVoteSignature -> Text
label :: Proxy PerasBLSCryptoAggregateVoteSignature -> Text
FromCBOR, Typeable PerasBLSCryptoAggregateVoteSignature
Typeable PerasBLSCryptoAggregateVoteSignature =>
(PerasBLSCryptoAggregateVoteSignature -> Encoding)
-> ((forall t. ToCBOR t => Proxy t -> Size)
    -> Proxy PerasBLSCryptoAggregateVoteSignature -> Size)
-> ((forall t. ToCBOR t => Proxy t -> Size)
    -> Proxy [PerasBLSCryptoAggregateVoteSignature] -> Size)
-> ToCBOR PerasBLSCryptoAggregateVoteSignature
PerasBLSCryptoAggregateVoteSignature -> Encoding
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [PerasBLSCryptoAggregateVoteSignature] -> Size
(forall t. ToCBOR t => Proxy t -> Size)
-> Proxy PerasBLSCryptoAggregateVoteSignature -> Size
forall a.
Typeable a =>
(a -> Encoding)
-> ((forall t. ToCBOR t => Proxy t -> Size) -> Proxy a -> Size)
-> ((forall t. ToCBOR t => Proxy t -> Size) -> Proxy [a] -> Size)
-> ToCBOR a
$ctoCBOR :: PerasBLSCryptoAggregateVoteSignature -> Encoding
toCBOR :: PerasBLSCryptoAggregateVoteSignature -> Encoding
$cencodedSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy PerasBLSCryptoAggregateVoteSignature -> Size
encodedSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy PerasBLSCryptoAggregateVoteSignature -> Size
$cencodedListSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [PerasBLSCryptoAggregateVoteSignature] -> Size
encodedListSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size)
-> Proxy [PerasBLSCryptoAggregateVoteSignature] -> Size
ToCBOR)

instance CryptoSupportsAggregateVoteSigning PerasBLSCrypto where
  type
    AggregateVoteVerificationKey PerasBLSCrypto =
      PerasBLSCryptoAggregateVoteVerificationKey
  type
    AggregateVoteSignature PerasBLSCrypto =
      PerasBLSCryptoAggregateVoteSignature

  aggregateVoteVerificationKeys :: Proxy PerasBLSCrypto
-> NE [VoteVerificationKey PerasBLSCrypto]
-> Either String (AggregateVoteVerificationKey PerasBLSCrypto)
aggregateVoteVerificationKeys Proxy PerasBLSCrypto
_ NE [VoteVerificationKey PerasBLSCrypto]
pks = do
    aggPk <- forall (r :: KeyRole).
NE [PublicKey r] -> Either String (PublicKey r)
BLS.aggregatePublicKeys @SIGN NE [VoteVerificationKey PerasBLSCrypto]
NE [PublicKey SIGN]
pks
    pure (PerasBLSCryptoAggregateVoteVerificationKey aggPk)

  aggregateVoteSignatures :: Proxy PerasBLSCrypto
-> NE [VoteSignature PerasBLSCrypto]
-> Either String (AggregateVoteSignature PerasBLSCrypto)
aggregateVoteSignatures Proxy PerasBLSCrypto
_ NE [VoteSignature PerasBLSCrypto]
sigs = do
    aggSig <-
      forall (r :: KeyRole).
NE [Signature r] -> Either String (Signature r)
BLS.aggregateSignatures @SIGN
        (NonEmpty (Signature SIGN) -> Either String (Signature SIGN))
-> (NE [VoteSignature PerasBLSCrypto] -> NonEmpty (Signature SIGN))
-> NE [VoteSignature PerasBLSCrypto]
-> Either String (Signature SIGN)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (VoteSignature PerasBLSCrypto -> Signature SIGN)
-> NonEmpty (VoteSignature PerasBLSCrypto)
-> NonEmpty (Signature SIGN)
forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap VoteSignature PerasBLSCrypto -> Signature SIGN
unPerasBLSCryptoVoteSignature
        (NE [VoteSignature PerasBLSCrypto]
 -> Either String (Signature SIGN))
-> NE [VoteSignature PerasBLSCrypto]
-> Either String (Signature SIGN)
forall a b. (a -> b) -> a -> b
$ NE [VoteSignature PerasBLSCrypto]
sigs
    pure (PerasBLSCryptoAggregateVoteSignature aggSig)

  verifyAggregateVoteSignature :: Proxy PerasBLSCrypto
-> AggregateVoteVerificationKey PerasBLSCrypto
-> ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> AggregateVoteSignature PerasBLSCrypto
-> Either String ()
verifyAggregateVoteSignature
    Proxy PerasBLSCrypto
_
    AggregateVoteVerificationKey PerasBLSCrypto
aggPk
    ElectionId PerasBLSCrypto
roundNo
    VoteCandidate PerasBLSCrypto
boostedBlock
    AggregateVoteSignature PerasBLSCrypto
aggSig = do
      forall (r :: KeyRole) msg.
(SignableRepresentation msg, HasBLSContext r) =>
PublicKey r -> msg -> Signature r -> Either String ()
BLS.verifyWithRole @SIGN
        (PerasBLSCryptoAggregateVoteVerificationKey -> PublicKey SIGN
unPerasBLSCryptoAggregateVoteVerificationKey AggregateVoteVerificationKey PerasBLSCrypto
PerasBLSCryptoAggregateVoteVerificationKey
aggPk)
        (ElectionId PerasBLSCrypto
-> VoteCandidate PerasBLSCrypto
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
hashVoteSignature ElectionId PerasBLSCrypto
roundNo VoteCandidate PerasBLSCrypto
boostedBlock)
        (PerasBLSCryptoAggregateVoteSignature -> Signature SIGN
unPerasBLSCryptoAggregateVoteSignature AggregateVoteSignature PerasBLSCrypto
PerasBLSCryptoAggregateVoteSignature
aggSig)

instance CryptoSupportsBatchVRFVerification PerasBLSCrypto where
  -- NOTE: in contrast to vote signatures, we cannot aggregate multiple VRF
  -- outputs into a single one when forging a certificate (because we need to
  -- derive non-persistent seat numbers from each individual one). This means
  -- that, at verification time, @sigs@ will always contain one VRF output per
  -- non-persistent voter in the certificate, even when verifying a certificate
  -- forged by someone else that we received over the network.
  --
  -- However, we still want to verify all the VRF outputs in a single batch for
  -- efficiency reasons, and we can do that by first aggregating all the VRF
  -- outputs in the list locally (using linearization to avoid swap-attacks),
  -- and then verifying the resulting aggregate VRF output against the aggregate
  -- VRF verification key.
  batchVerifyVRFOutputs :: NE [VRFVerificationKey PerasBLSCrypto]
-> VRFElectionInput PerasBLSCrypto
-> NE [VRFOutput PerasBLSCrypto]
-> Either String ()
batchVerifyVRFOutputs
    NE [VRFVerificationKey PerasBLSCrypto]
pks
    (PerasBLSCryptoVRFElectionInput Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
input)
    NE [VRFOutput PerasBLSCrypto]
sigs = do
      NE [PublicKey VRF]
-> Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
-> NE [Signature VRF]
-> Either String ()
forall msg.
SignableRepresentation msg =>
NE [PublicKey VRF] -> msg -> NE [Signature VRF] -> Either String ()
BLS.linearizeAndVerifyVRFs
        NE [VRFVerificationKey PerasBLSCrypto]
NE [PublicKey VRF]
pks
        Hash HASH (SigDSIGN BLS12381MinSigDSIGN)
input
        (NonEmpty (Signature VRF) -> Either String ())
-> (NE [VRFOutput PerasBLSCrypto] -> NonEmpty (Signature VRF))
-> NE [VRFOutput PerasBLSCrypto]
-> Either String ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (VRFOutput PerasBLSCrypto -> Signature VRF)
-> NonEmpty (VRFOutput PerasBLSCrypto) -> NonEmpty (Signature VRF)
forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap VRFOutput PerasBLSCrypto -> Signature VRF
unPerasBLSCryptoVRFOutput
        (NE [VRFOutput PerasBLSCrypto] -> Either String ())
-> NE [VRFOutput PerasBLSCrypto] -> Either String ()
forall a b. (a -> b) -> a -> b
$ NE [VRFOutput PerasBLSCrypto]
sigs