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.Aeson as JSON
21 import qualified Data.ByteString as BS
22 import qualified Data.List as List
24 import Voting.Protocol.Utils
25 import Voting.Protocol.FFC
26 import Voting.Protocol.Credential
27 import Voting.Protocol.Election
28 import Voting.Protocol.Tally
30 -- * Type 'TrusteePublicKey'
31 data TrusteePublicKey c = TrusteePublicKey
32 { trustee_PublicKey :: !(PublicKey c)
33 , trustee_SecretKeyProof :: !(Proof c)
34 -- ^ NOTE: It is important to ensure
35 -- that each trustee generates its key pair independently
36 -- of the 'PublicKey's published by the other trustees.
37 -- Otherwise, a dishonest trustee could publish as 'PublicKey'
38 -- its genuine 'PublicKey' divided by the 'PublicKey's of the other trustees.
39 -- This would then lead to the 'election_PublicKey'
40 -- being equal to this dishonest trustee's 'PublicKey',
41 -- which means that knowing its 'SecretKey' would be sufficient
42 -- for decrypting messages encrypted to the 'election_PublicKey'.
43 -- To avoid this attack, each trustee publishing a 'PublicKey'
44 -- must 'prove' knowledge of the corresponding 'SecretKey'.
45 -- Which is done in 'proveIndispensableTrusteePublicKey'
46 -- and 'verifyIndispensableTrusteePublicKey'.
47 } deriving (Eq,Show,Generic,NFData)
48 instance ToJSON (TrusteePublicKey c) where
49 toJSON TrusteePublicKey{..} =
51 [ "pok" .= trustee_SecretKeyProof
52 , "public_key" .= trustee_PublicKey
54 toEncoding TrusteePublicKey{..} =
56 ( "pok" .= trustee_SecretKeyProof
57 <> "public_key" .= trustee_PublicKey
59 instance Reifies c FFC => FromJSON (TrusteePublicKey c) where
60 parseJSON = JSON.withObject "TrusteePublicKey" $ \o -> do
61 trustee_PublicKey <- o .: "public_key"
62 trustee_SecretKeyProof <- o .: "pok"
63 return TrusteePublicKey{..}
65 -- ** Generating a 'TrusteePublicKey'
67 -- | @('proveIndispensableTrusteePublicKey' trustSecKey)@
68 -- returns the 'PublicKey' associated to 'trustSecKey'
69 -- and a 'Proof' of its knowledge.
70 proveIndispensableTrusteePublicKey ::
71 Reifies c FFC => Monad m => RandomGen r =>
72 SecretKey c -> S.StateT r m (TrusteePublicKey c)
73 proveIndispensableTrusteePublicKey trustSecKey = do
74 let trustee_PublicKey = publicKey trustSecKey
75 trustee_SecretKeyProof <-
76 prove trustSecKey [groupGen] $
77 hash (indispensableTrusteePublicKeyStatement trustee_PublicKey)
78 return TrusteePublicKey{..}
80 -- ** Checking a 'TrusteePublicKey' before incorporating it into the 'Election''s 'PublicKey'
82 -- | @('verifyIndispensableTrusteePublicKey' trustPubKey)@
83 -- returns 'True' iif. the given 'trustee_SecretKeyProof'
84 -- does 'prove' that the 'SecretKey' associated with
85 -- the given 'trustee_PublicKey' is known by the trustee.
86 verifyIndispensableTrusteePublicKey ::
87 Reifies c FFC => Monad m =>
89 ExceptT ErrorTrusteePublicKey m ()
90 verifyIndispensableTrusteePublicKey TrusteePublicKey{..} =
92 proof_challenge trustee_SecretKeyProof == hash
93 (indispensableTrusteePublicKeyStatement trustee_PublicKey)
94 [commit trustee_SecretKeyProof groupGen trustee_PublicKey]
96 throwE ErrorTrusteePublicKey_WrongProof
98 -- ** Type 'ErrorTrusteePublicKey'
99 data ErrorTrusteePublicKey
100 = ErrorTrusteePublicKey_WrongProof
101 -- ^ The 'trustee_SecretKeyProof' is wrong.
105 indispensableTrusteePublicKeyStatement :: PublicKey c -> BS.ByteString
106 indispensableTrusteePublicKeyStatement trustPubKey =
107 "pok|"<>bytesNat trustPubKey<>"|"
109 -- * 'Election''s 'PublicKey'
111 -- ** Generating an 'Election''s 'PublicKey' from multiple 'TrusteePublicKey's.
113 combineIndispensableTrusteePublicKeys ::
114 Reifies c FFC => [TrusteePublicKey c] -> PublicKey c
115 combineIndispensableTrusteePublicKeys =
116 List.foldr (\TrusteePublicKey{..} -> (trustee_PublicKey *)) one
118 -- ** Checking the trustee's 'DecryptionShare's before decrypting an 'EncryptedTally'.
120 verifyIndispensableDecryptionShareByTrustee ::
121 Reifies c FFC => Monad m =>
122 EncryptedTally c -> [PublicKey c] -> [DecryptionShare c] ->
123 ExceptT ErrorTally m ()
124 verifyIndispensableDecryptionShareByTrustee encByChoiceByQuest =
125 isoZipWithM_ (throwE $ ErrorTally_NumberOfTrustees)
126 (verifyDecryptionShare encByChoiceByQuest)
128 -- ** Decrypting an 'EncryptedTally' from multiple 'TrusteePublicKey's.
130 -- | @('combineDecryptionShares' pubKeyByTrustee decShareByTrustee)@
131 -- returns the 'DecryptionFactor's by choice by 'Question'
132 combineIndispensableDecryptionShares ::
133 Reifies c FFC => [PublicKey c] -> DecryptionShareCombinator c
134 combineIndispensableDecryptionShares
137 decByChoiceByQuestByTrustee = do
138 verifyIndispensableDecryptionShareByTrustee
141 decByChoiceByQuestByTrustee
142 (DecryptionShare dec0,decs) <-
143 maybe (throwE ErrorTally_NumberOfTrustees) return $
144 List.uncons decByChoiceByQuestByTrustee
145 foldM (isoZipWithM (throwE ErrorTally_NumberOfQuestions)
146 (maybe (throwE ErrorTally_NumberOfChoices) return `o2`
147 isoZipWith (\a (decFactor, _proof) -> a * decFactor)))
148 ((fst <$>) <$> dec0) (unDecryptionShare <$> decs)