{-# LANGUAGE OverloadedStrings #-}
module Voting.Protocol.Trustees.All where
import Control.Monad (Monad(..), foldM, unless)
import Control.Monad.Trans.Except (ExceptT(..), throwE)
import Data.Eq (Eq(..))
import Data.Function (($))
import Data.Maybe (maybe)
import Data.Semigroup (Semigroup(..))
import Text.Show (Show(..))
import qualified Control.Monad.Trans.State.Strict as S
import qualified Data.ByteString as BS
import qualified Data.List as List
import Voting.Protocol.Utils
import Voting.Protocol.Arithmetic
import Voting.Protocol.Credential
import Voting.Protocol.Election
data TrusteePublicKey q = TrusteePublicKey
 { trustee_PublicKey      :: PublicKey q
 , trustee_SecretKeyProof :: Proof q
 } deriving (Eq,Show)
randomSecretKey :: Monad m => RandomGen r => SubGroup q => S.StateT r m (SecretKey q)
randomSecretKey = random
data ErrorTrusteePublicKey
 =   ErrorTrusteePublicKey_Wrong
     
 deriving (Eq,Show)
proveTrusteePublicKey ::
 Monad m => RandomGen r => SubGroup q =>
 SecretKey q -> S.StateT r m (TrusteePublicKey q)
proveTrusteePublicKey trustSecKey = do
        let trustee_PublicKey = publicKey trustSecKey
        trustee_SecretKeyProof <-
                prove trustSecKey [groupGen] $
                        hash (trusteePublicKeyStatement trustee_PublicKey)
        return TrusteePublicKey{..}
verifyTrusteePublicKey ::
 Monad m => SubGroup q =>
 TrusteePublicKey q ->
 ExceptT ErrorTrusteePublicKey m ()
verifyTrusteePublicKey TrusteePublicKey{..} =
        unless ((proof_challenge trustee_SecretKeyProof ==) $
        hash
         (trusteePublicKeyStatement trustee_PublicKey)
         [commit trustee_SecretKeyProof groupGen trustee_PublicKey]) $
                throwE ErrorTrusteePublicKey_Wrong
trusteePublicKeyStatement :: PublicKey q -> BS.ByteString
trusteePublicKeyStatement trustPubKey = "pok|"<>bytesNat trustPubKey<>"|"
electionPublicKey :: SubGroup q => [TrusteePublicKey q] -> PublicKey q
electionPublicKey = List.foldr (\TrusteePublicKey{..} -> (trustee_PublicKey *)) one
combineDecryptionShares ::
 SubGroup q =>
 [[Encryption q]] ->
 [PublicKey q] -> DecryptionShareCombinator q
combineDecryptionShares encByQuestByBallot pubKeyByTrustee decShareByTrustee = do
        isoZipWithM_ (throwE ErrorDecryptionShare_Invalid)
         (verifyDecryptionShare encByQuestByBallot)
         pubKeyByTrustee
         decShareByTrustee
        (d0,ds) <- maybe err return $ List.uncons decShareByTrustee
        foldM
         (\decFactorByQuestByBallot DecryptionShare{..} ->
                isoZipWithM err
                 (\acc df -> maybe err return $ isoZipWith (*) acc df)
                 decFactorByQuestByBallot decryptionShare_factors)
         (decryptionShare_factors d0) ds
        where err = throwE ErrorDecryptionShare_Invalid