{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE UndecidableInstances #-}
module Voting.Protocol.Trustee.Indispensable where
import Control.DeepSeq (NFData)
import Control.Monad (Monad(..), foldM, unless)
import Control.Monad.Trans.Except (ExceptT(..), throwE)
import Data.Aeson (ToJSON(..),FromJSON(..),(.:),(.=))
import Data.Eq (Eq(..))
import Data.Function (($))
import Data.Functor ((<$>))
import Data.Maybe (maybe)
import Data.Reflection (Reifies(..))
import Data.Semigroup (Semigroup(..))
import Data.Tuple (fst)
import GHC.Generics (Generic)
import System.Random (RandomGen)
import Text.Show (Show(..))
import qualified Control.Monad.Trans.State.Strict as S
import qualified Data.Aeson as JSON
import qualified Data.ByteString as BS
import qualified Data.List as List
import Voting.Protocol.Utils
import Voting.Protocol.Arith
import Voting.Protocol.Credential
import Voting.Protocol.Election
import Voting.Protocol.Tally
data TrusteePublicKey crypto v c = TrusteePublicKey
{ trustee_PublicKey :: !(PublicKey crypto c)
, trustee_SecretKeyProof :: !(Proof crypto v c)
} deriving (Generic)
deriving instance Eq (FieldElement crypto c) => Eq (TrusteePublicKey crypto v c)
deriving instance (Show (FieldElement crypto c), Show (PublicKey crypto c)) => Show (TrusteePublicKey crypto v c)
deriving instance NFData (FieldElement crypto c) => NFData (TrusteePublicKey crypto v c)
instance
( Group crypto
, ToJSON (FieldElement crypto c)
) => ToJSON (TrusteePublicKey crypto v c) where
toJSON TrusteePublicKey{..} =
JSON.object
[ "pok" .= trustee_SecretKeyProof
, "public_key" .= trustee_PublicKey
]
toEncoding TrusteePublicKey{..} =
JSON.pairs
( "pok" .= trustee_SecretKeyProof
<> "public_key" .= trustee_PublicKey
)
instance
( Reifies c crypto
, Group crypto
, FromJSON (PublicKey crypto c)
) => FromJSON (TrusteePublicKey crypto v c) where
parseJSON = JSON.withObject "TrusteePublicKey" $ \o -> do
trustee_PublicKey <- o .: "public_key"
trustee_SecretKeyProof <- o .: "pok"
return TrusteePublicKey{..}
proveIndispensableTrusteePublicKey ::
Reifies v Version =>
Reifies c crypto =>
Group crypto =>
Key crypto =>
Multiplicative (FieldElement crypto c) =>
ToNatural (FieldElement crypto c) =>
Monad m => RandomGen r =>
SecretKey crypto c -> S.StateT r m (TrusteePublicKey crypto v c)
proveIndispensableTrusteePublicKey trustSecKey = do
let trustee_PublicKey = publicKey trustSecKey
trustee_SecretKeyProof <-
prove trustSecKey [groupGen] $
hash (indispensableTrusteePublicKeyStatement trustee_PublicKey)
return TrusteePublicKey{..}
verifyIndispensableTrusteePublicKey ::
Reifies v Version =>
Reifies c crypto =>
Group crypto =>
Multiplicative (FieldElement crypto c) =>
ToNatural (FieldElement crypto c) =>
Monad m =>
TrusteePublicKey crypto v c ->
ExceptT ErrorTrusteePublicKey m ()
verifyIndispensableTrusteePublicKey TrusteePublicKey{..} =
unless (
proof_challenge trustee_SecretKeyProof == hash
(indispensableTrusteePublicKeyStatement trustee_PublicKey)
[commit trustee_SecretKeyProof groupGen trustee_PublicKey]
) $
throwE ErrorTrusteePublicKey_WrongProof
data ErrorTrusteePublicKey
= ErrorTrusteePublicKey_WrongProof
deriving (Eq,Show)
indispensableTrusteePublicKeyStatement ::
Reifies c crypto =>
ToNatural (FieldElement crypto c) =>
PublicKey crypto c -> BS.ByteString
indispensableTrusteePublicKeyStatement trustPubKey =
"pok|"<>bytesNat trustPubKey<>"|"
combineIndispensableTrusteePublicKeys ::
Reifies c crypto =>
Multiplicative (FieldElement crypto c) =>
ToNatural (FieldElement crypto c) =>
[TrusteePublicKey crypto v c] -> PublicKey crypto c
combineIndispensableTrusteePublicKeys =
List.foldr (\TrusteePublicKey{..} -> (trustee_PublicKey *)) one
verifyIndispensableDecryptionShareByTrustee ::
Reifies v Version =>
Reifies c crypto =>
Group crypto =>
Multiplicative (FieldElement crypto c) =>
ToNatural (FieldElement crypto c) =>
Monad m =>
EncryptedTally crypto v c -> [PublicKey crypto c] -> [DecryptionShare crypto v c] ->
ExceptT ErrorTally m ()
verifyIndispensableDecryptionShareByTrustee encByChoiceByQuest =
isoZipWithM_ (throwE $ ErrorTally_NumberOfTrustees)
(verifyDecryptionShare encByChoiceByQuest)
combineIndispensableDecryptionShares ::
Reifies v Version =>
Reifies c crypto =>
Group crypto =>
Multiplicative (FieldElement crypto c) =>
ToNatural (FieldElement crypto c) =>
[PublicKey crypto c] -> DecryptionShareCombinator crypto v c
combineIndispensableDecryptionShares
pubKeyByTrustee
encByChoiceByQuest
decByChoiceByQuestByTrustee = do
verifyIndispensableDecryptionShareByTrustee
encByChoiceByQuest
pubKeyByTrustee
decByChoiceByQuestByTrustee
(DecryptionShare dec0,decs) <-
maybe (throwE ErrorTally_NumberOfTrustees) return $
List.uncons decByChoiceByQuestByTrustee
foldM (isoZipWithM (throwE ErrorTally_NumberOfQuestions)
(maybe (throwE ErrorTally_NumberOfChoices) return `o2`
isoZipWith (\a (decFactor, _proof) -> a * decFactor)))
((fst <$>) <$> dec0) (unDecryptionShare <$> decs)