lib: test: add type `G5`
[majurity.git] / hjugement-protocol / src / Voting / Protocol / Trustee / Indispensable.hs
index c5491d6f890a2f604c13b4d9782ad82100d1d14a..58bde8d43a7a8c77506f1a242a05e5f4f88c7d10 100644 (file)
@@ -1,29 +1,39 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE UndecidableInstances #-} -- for Reifies instances
 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.Arithmetic
+import Voting.Protocol.Version
+import Voting.Protocol.Cryptography
 import Voting.Protocol.Credential
-import Voting.Protocol.Election
 import Voting.Protocol.Tally
 
 -- * Type 'TrusteePublicKey'
-data TrusteePublicKey q = TrusteePublicKey
- { trustee_PublicKey      :: PublicKey q
- , trustee_SecretKeyProof :: Proof q
+data TrusteePublicKey crypto v c = TrusteePublicKey
+ { trustee_PublicKey      :: !(PublicKey crypto c)
+ , trustee_SecretKeyProof :: !(Proof crypto v c)
        -- ^ NOTE: It is important to ensure
        -- that each trustee generates its key pair independently
        -- of the 'PublicKey's published by the other trustees.
@@ -37,20 +47,44 @@ data TrusteePublicKey q = TrusteePublicKey
        -- must 'prove' knowledge of the corresponding 'SecretKey'.
        -- Which is done in 'proveIndispensableTrusteePublicKey'
        -- and 'verifyIndispensableTrusteePublicKey'.
- } deriving (Eq,Show)
+ } deriving (Generic)
+deriving instance Eq (G crypto c) => Eq (TrusteePublicKey crypto v c)
+deriving instance (Show (G crypto c), Show (PublicKey crypto c)) => Show (TrusteePublicKey crypto v c)
+deriving instance NFData (G crypto c) => NFData (TrusteePublicKey crypto v c)
+instance
+ ( Reifies v Version
+ , ToJSON (G 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 v Version
+ , CryptoParams 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{..}
 
--- ** Type 'ErrorTrusteePublicKey'
-data ErrorTrusteePublicKey
- =   ErrorTrusteePublicKey_WrongProof
-     -- ^ The 'trustee_SecretKeyProof' is wrong.
- deriving (Eq,Show)
+-- ** Generating a 'TrusteePublicKey'
 
 -- | @('proveIndispensableTrusteePublicKey' trustSecKey)@
 -- returns the 'PublicKey' associated to 'trustSecKey'
 -- and a 'Proof' of its knowledge.
 proveIndispensableTrusteePublicKey ::
- Monad m => RandomGen r => SubGroup q =>
- SecretKey q -> S.StateT r m (TrusteePublicKey q)
+ Reifies v Version =>
+ CryptoParams crypto c =>
+ Key crypto =>
+ 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 <-
@@ -58,49 +92,81 @@ proveIndispensableTrusteePublicKey trustSecKey = do
                        hash (indispensableTrusteePublicKeyStatement trustee_PublicKey)
        return TrusteePublicKey{..}
 
+-- ** Checking a 'TrusteePublicKey' before incorporating it into the 'Election''s 'PublicKey'
+
 -- | @('verifyIndispensableTrusteePublicKey' trustPubKey)@
 -- returns 'True' iif. the given 'trustee_SecretKeyProof'
 -- does 'prove' that the 'SecretKey' associated with
 -- the given 'trustee_PublicKey' is known by the trustee.
 verifyIndispensableTrusteePublicKey ::
- Monad m => SubGroup q =>
- TrusteePublicKey q ->
+ Reifies v Version =>
+ CryptoParams 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]) $
+       unless (
+               proof_challenge trustee_SecretKeyProof == hash
+                (indispensableTrusteePublicKeyStatement trustee_PublicKey)
+                [commit trustee_SecretKeyProof groupGen trustee_PublicKey]
+        ) $
                throwE ErrorTrusteePublicKey_WrongProof
 
+-- ** Type 'ErrorTrusteePublicKey'
+data ErrorTrusteePublicKey
+ =   ErrorTrusteePublicKey_WrongProof
+     -- ^ The 'trustee_SecretKeyProof' is wrong.
+ deriving (Eq,Show)
+
 -- ** Hashing
-indispensableTrusteePublicKeyStatement :: PublicKey q -> BS.ByteString
-indispensableTrusteePublicKeyStatement trustPubKey = "pok|"<>bytesNat trustPubKey<>"|"
+indispensableTrusteePublicKeyStatement ::
+ CryptoParams crypto c =>
+ PublicKey crypto c -> BS.ByteString
+indispensableTrusteePublicKeyStatement trustPubKey =
+       "pok|"<>bytesNat trustPubKey<>"|"
 
 -- * 'Election''s 'PublicKey'
 
+-- ** Generating an 'Election''s 'PublicKey' from multiple 'TrusteePublicKey's.
+
 combineIndispensableTrusteePublicKeys ::
- SubGroup q => [TrusteePublicKey q] -> PublicKey q
+ CryptoParams crypto c =>
+ [TrusteePublicKey crypto v c] -> PublicKey crypto c
 combineIndispensableTrusteePublicKeys =
        List.foldr (\TrusteePublicKey{..} -> (trustee_PublicKey *)) one
 
+-- ** Checking the trustee's 'DecryptionShare's before decrypting an 'EncryptedTally'.
+
 verifyIndispensableDecryptionShareByTrustee ::
- SubGroup q => Monad m =>
- EncryptedTally q -> [PublicKey q] -> [DecryptionShare q] ->
+ Reifies v Version =>
+ CryptoParams 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)
 
+-- ** Decrypting an 'EncryptedTally' from multiple 'TrusteePublicKey's.
+
 -- | @('combineDecryptionShares' pubKeyByTrustee decShareByTrustee)@
 -- returns the 'DecryptionFactor's by choice by 'Question'
-combineIndispensableDecryptionShares :: SubGroup q => [PublicKey q] -> DecryptionShareCombinator q
-combineIndispensableDecryptionShares pubKeyByTrustee encByChoiceByQuest decByChoiceByQuestByTrustee = do
-       verifyIndispensableDecryptionShareByTrustee encByChoiceByQuest pubKeyByTrustee decByChoiceByQuestByTrustee
-       (dec0,decs) <-
+combineIndispensableDecryptionShares ::
+ Reifies v Version =>
+ CryptoParams 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) decs
+        ((fst <$>) <$> dec0) (unDecryptionShare <$> decs)