1 {-# LANGUAGE DeriveAnyClass #-}
 
   2 {-# LANGUAGE DeriveGeneric #-}
 
   3 {-# LANGUAGE OverloadedStrings #-}
 
   4 {-# LANGUAGE UndecidableInstances #-} -- for Reifies instances
 
   5 module Voting.Protocol.Trustee.Indispensable where
 
   7 import Control.DeepSeq (NFData)
 
   8 import Control.Monad (Monad(..), foldM, unless)
 
   9 import Control.Monad.Trans.Except (ExceptT(..), throwE)
 
  10 import Data.Aeson (ToJSON(..),FromJSON(..))
 
  11 import Data.Eq (Eq(..))
 
  12 import Data.Function (($))
 
  13 import Data.Functor ((<$>))
 
  14 import Data.Maybe (maybe)
 
  15 import Data.Semigroup (Semigroup(..))
 
  16 import Data.Tuple (fst)
 
  17 import GHC.Generics (Generic)
 
  18 import Text.Show (Show(..))
 
  19 import qualified Control.Monad.Trans.State.Strict as S
 
  20 import qualified Data.ByteString as BS
 
  21 import qualified Data.List as List
 
  23 import Voting.Protocol.Utils
 
  24 import Voting.Protocol.FFC
 
  25 import Voting.Protocol.Credential
 
  26 import Voting.Protocol.Election
 
  27 import Voting.Protocol.Tally
 
  29 -- * Type 'TrusteePublicKey'
 
  30 data TrusteePublicKey c = TrusteePublicKey
 
  31  { trustee_PublicKey      :: !(PublicKey c)
 
  32  , trustee_SecretKeyProof :: !(Proof c)
 
  33         -- ^ NOTE: It is important to ensure
 
  34         -- that each trustee generates its key pair independently
 
  35         -- of the 'PublicKey's published by the other trustees.
 
  36         -- Otherwise, a dishonest trustee could publish as 'PublicKey'
 
  37         -- its genuine 'PublicKey' divided by the 'PublicKey's of the other trustees.
 
  38         -- This would then lead to the 'election_PublicKey'
 
  39         -- being equal to this dishonest trustee's 'PublicKey',
 
  40         -- which means that knowing its 'SecretKey' would be sufficient
 
  41         -- for decrypting messages encrypted to the 'election_PublicKey'.
 
  42         -- To avoid this attack, each trustee publishing a 'PublicKey'
 
  43         -- must 'prove' knowledge of the corresponding 'SecretKey'.
 
  44         -- Which is done in 'proveIndispensableTrusteePublicKey'
 
  45         -- and 'verifyIndispensableTrusteePublicKey'.
 
  46  } deriving (Eq,Show,Generic,NFData)
 
  47 deriving instance Reifies c FFC => ToJSON (TrusteePublicKey c)
 
  48 deriving instance Reifies c FFC => FromJSON (TrusteePublicKey c)
 
  50 -- ** Type 'ErrorTrusteePublicKey'
 
  51 data ErrorTrusteePublicKey
 
  52  =   ErrorTrusteePublicKey_WrongProof
 
  53      -- ^ The 'trustee_SecretKeyProof' is wrong.
 
  56 -- | @('proveIndispensableTrusteePublicKey' trustSecKey)@
 
  57 -- returns the 'PublicKey' associated to 'trustSecKey'
 
  58 -- and a 'Proof' of its knowledge.
 
  59 proveIndispensableTrusteePublicKey ::
 
  60  Reifies c FFC => Monad m => RandomGen r =>
 
  61  SecretKey c -> S.StateT r m (TrusteePublicKey c)
 
  62 proveIndispensableTrusteePublicKey trustSecKey = do
 
  63         let trustee_PublicKey = publicKey trustSecKey
 
  64         trustee_SecretKeyProof <-
 
  65                 prove trustSecKey [groupGen] $
 
  66                         hash (indispensableTrusteePublicKeyStatement trustee_PublicKey)
 
  67         return TrusteePublicKey{..}
 
  69 -- | @('verifyIndispensableTrusteePublicKey' trustPubKey)@
 
  70 -- returns 'True' iif. the given 'trustee_SecretKeyProof'
 
  71 -- does 'prove' that the 'SecretKey' associated with
 
  72 -- the given 'trustee_PublicKey' is known by the trustee.
 
  73 verifyIndispensableTrusteePublicKey ::
 
  74  Reifies c FFC => Monad m =>
 
  76  ExceptT ErrorTrusteePublicKey m ()
 
  77 verifyIndispensableTrusteePublicKey TrusteePublicKey{..} =
 
  78         unless ((proof_challenge trustee_SecretKeyProof ==) $
 
  80          (indispensableTrusteePublicKeyStatement trustee_PublicKey)
 
  81          [commit trustee_SecretKeyProof groupGen trustee_PublicKey]) $
 
  82                 throwE ErrorTrusteePublicKey_WrongProof
 
  85 indispensableTrusteePublicKeyStatement :: PublicKey c -> BS.ByteString
 
  86 indispensableTrusteePublicKeyStatement trustPubKey =
 
  87         "pok|"<>bytesNat trustPubKey<>"|"
 
  89 -- * 'Election''s 'PublicKey'
 
  91 combineIndispensableTrusteePublicKeys ::
 
  92  Reifies c FFC => [TrusteePublicKey c] -> PublicKey c
 
  93 combineIndispensableTrusteePublicKeys =
 
  94         List.foldr (\TrusteePublicKey{..} -> (trustee_PublicKey *)) one
 
  96 verifyIndispensableDecryptionShareByTrustee ::
 
  97  Reifies c FFC => Monad m =>
 
  98  EncryptedTally c -> [PublicKey c] -> [DecryptionShare c] ->
 
  99  ExceptT ErrorTally m ()
 
 100 verifyIndispensableDecryptionShareByTrustee encByChoiceByQuest =
 
 101         isoZipWithM_ (throwE $ ErrorTally_NumberOfTrustees)
 
 102          (verifyDecryptionShare encByChoiceByQuest)
 
 104 -- | @('combineDecryptionShares' pubKeyByTrustee decShareByTrustee)@
 
 105 -- returns the 'DecryptionFactor's by choice by 'Question'
 
 106 combineIndispensableDecryptionShares ::
 
 107  Reifies c FFC => [PublicKey c] -> DecryptionShareCombinator c
 
 108 combineIndispensableDecryptionShares
 
 111  decByChoiceByQuestByTrustee = do
 
 112         verifyIndispensableDecryptionShareByTrustee
 
 115          decByChoiceByQuestByTrustee
 
 117                 maybe (throwE ErrorTally_NumberOfTrustees) return $
 
 118                 List.uncons decByChoiceByQuestByTrustee
 
 119         foldM (isoZipWithM (throwE ErrorTally_NumberOfQuestions)
 
 120          (maybe (throwE ErrorTally_NumberOfChoices) return `o2`
 
 121                 isoZipWith (\a (decFactor, _proof) -> a * decFactor)))
 
 122          ((fst <$>) <$> dec0) decs