packages feed

hjugement-protocol 0.0.0.20190511 → 0.0.0.20190513

raw patch · 20 files changed

+474/−301 lines, 20 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Voting.Protocol.Election: DecryptionShare :: [[DecryptionFactor q]] -> [[Proof q]] -> DecryptionShare q
- Voting.Protocol.Election: ErrorDecryptionShare_Invalid :: ErrorDecryptionShare
- Voting.Protocol.Election: ErrorDecryptionShare_Wrong :: ErrorDecryptionShare
- Voting.Protocol.Election: Tally :: Natural -> [[Encryption q]] -> [DecryptionShare q] -> [[Natural]] -> Tally q
- Voting.Protocol.Election: [decryptionShare_factors] :: DecryptionShare q -> [[DecryptionFactor q]]
- Voting.Protocol.Election: [decryptionShare_proofs] :: DecryptionShare q -> [[Proof q]]
- Voting.Protocol.Election: [election_publicKey] :: Election q -> PublicKey q
- Voting.Protocol.Election: [tally_countByQuestByBallot] :: Tally q -> [[Natural]]
- Voting.Protocol.Election: [tally_decShareByTrustee] :: Tally q -> [DecryptionShare q]
- Voting.Protocol.Election: [tally_encByQuestByBallot] :: Tally q -> [[Encryption q]]
- Voting.Protocol.Election: [tally_numBallots] :: Tally q -> Natural
- Voting.Protocol.Election: data DecryptionShare q
- Voting.Protocol.Election: data ErrorDecryptionShare
- Voting.Protocol.Election: data Tally q
- Voting.Protocol.Election: decryptionShareStatement :: SubGroup q => PublicKey q -> ByteString
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.DecryptionShare q)
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Tally q)
- Voting.Protocol.Election: instance Control.DeepSeq.NFData Voting.Protocol.Election.ErrorDecryptionShare
- Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.DecryptionShare q)
- Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Tally q)
- Voting.Protocol.Election: instance GHC.Classes.Eq Voting.Protocol.Election.ErrorDecryptionShare
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.DecryptionShare q)
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Tally q)
- Voting.Protocol.Election: instance GHC.Generics.Generic Voting.Protocol.Election.ErrorDecryptionShare
- Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.DecryptionShare q)
- Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Tally q)
- Voting.Protocol.Election: instance GHC.Show.Show Voting.Protocol.Election.ErrorDecryptionShare
- Voting.Protocol.Election: proveDecryptionFactor :: Monad m => SubGroup q => RandomGen r => SecretKey q -> Encryption q -> StateT r m (DecryptionFactor q, Proof q)
- Voting.Protocol.Election: proveDecryptionShare :: Monad m => SubGroup q => RandomGen r => SecretKey q -> [[Encryption q]] -> StateT r m (DecryptionShare q)
- Voting.Protocol.Election: proveTally :: Monad m => SubGroup q => [[Encryption q]] -> [DecryptionShare q] -> DecryptionShareCombinator q -> Except ErrorDecryptionShare (Tally q)
- Voting.Protocol.Election: type DecryptionFactor = G
- Voting.Protocol.Election: type DecryptionShareCombinator q = [DecryptionShare q] -> Except ErrorDecryptionShare [[DecryptionFactor q]]
- Voting.Protocol.Election: verifyDecryptionShare :: Monad m => SubGroup q => [[Encryption q]] -> PublicKey q -> DecryptionShare q -> ExceptT ErrorDecryptionShare m ()
- Voting.Protocol.Election: verifyTally :: Monad m => SubGroup q => DecryptionShareCombinator q -> Tally q -> Except ErrorDecryptionShare ()
- Voting.Protocol.Trustees.All: ErrorTrusteePublicKey_Wrong :: ErrorTrusteePublicKey
- Voting.Protocol.Trustees.All: TrusteePublicKey :: PublicKey q -> Proof q -> TrusteePublicKey q
- Voting.Protocol.Trustees.All: [trustee_PublicKey] :: TrusteePublicKey q -> PublicKey q
- Voting.Protocol.Trustees.All: [trustee_SecretKeyProof] :: TrusteePublicKey q -> Proof q
- Voting.Protocol.Trustees.All: combineDecryptionShares :: SubGroup q => [[Encryption q]] -> [PublicKey q] -> DecryptionShareCombinator q
- Voting.Protocol.Trustees.All: data ErrorTrusteePublicKey
- Voting.Protocol.Trustees.All: data TrusteePublicKey q
- Voting.Protocol.Trustees.All: electionPublicKey :: SubGroup q => [TrusteePublicKey q] -> PublicKey q
- Voting.Protocol.Trustees.All: instance GHC.Classes.Eq (Voting.Protocol.Trustees.All.TrusteePublicKey q)
- Voting.Protocol.Trustees.All: instance GHC.Classes.Eq Voting.Protocol.Trustees.All.ErrorTrusteePublicKey
- Voting.Protocol.Trustees.All: instance GHC.Show.Show (Voting.Protocol.Trustees.All.TrusteePublicKey q)
- Voting.Protocol.Trustees.All: instance GHC.Show.Show Voting.Protocol.Trustees.All.ErrorTrusteePublicKey
- Voting.Protocol.Trustees.All: proveTrusteePublicKey :: Monad m => RandomGen r => SubGroup q => SecretKey q -> StateT r m (TrusteePublicKey q)
- Voting.Protocol.Trustees.All: randomSecretKey :: Monad m => RandomGen r => SubGroup q => StateT r m (SecretKey q)
- Voting.Protocol.Trustees.All: trusteePublicKeyStatement :: PublicKey q -> ByteString
- Voting.Protocol.Trustees.All: verifyTrusteePublicKey :: Monad m => SubGroup q => TrusteePublicKey q -> ExceptT ErrorTrusteePublicKey m ()
+ Voting.Protocol.Credential: randomSecretKey :: Monad m => RandomGen r => SubGroup q => StateT r m (SecretKey q)
+ Voting.Protocol.Election: ErrorBallot_Wrong :: ErrorBallot
+ Voting.Protocol.Election: [election_PublicKey] :: Election q -> PublicKey q
+ Voting.Protocol.Tally: DecryptionShare :: [[DecryptionFactor q]] -> [[Proof q]] -> DecryptionShare q
+ Voting.Protocol.Tally: ErrorDecryptionShare_Invalid :: Text -> ErrorDecryptionShare
+ Voting.Protocol.Tally: ErrorDecryptionShare_InvalidMaxCount :: ErrorDecryptionShare
+ Voting.Protocol.Tally: ErrorDecryptionShare_Wrong :: ErrorDecryptionShare
+ Voting.Protocol.Tally: Tally :: Natural -> EncryptedTally q -> [DecryptionShare q] -> [[Natural]] -> Tally q
+ Voting.Protocol.Tally: [decryptionShare_factors] :: DecryptionShare q -> [[DecryptionFactor q]]
+ Voting.Protocol.Tally: [decryptionShare_proofs] :: DecryptionShare q -> [[Proof q]]
+ Voting.Protocol.Tally: [tally_countByChoiceByQuest] :: Tally q -> [[Natural]]
+ Voting.Protocol.Tally: [tally_countMax] :: Tally q -> Natural
+ Voting.Protocol.Tally: [tally_decShareByTrustee] :: Tally q -> [DecryptionShare q]
+ Voting.Protocol.Tally: [tally_encByChoiceByQuest] :: Tally q -> EncryptedTally q
+ Voting.Protocol.Tally: data DecryptionShare q
+ Voting.Protocol.Tally: data ErrorDecryptionShare
+ Voting.Protocol.Tally: data Tally q
+ Voting.Protocol.Tally: decryptionShareStatement :: SubGroup q => PublicKey q -> ByteString
+ Voting.Protocol.Tally: encryptedTally :: SubGroup q => [Ballot q] -> (EncryptedTally q, Natural)
+ Voting.Protocol.Tally: instance Control.DeepSeq.NFData (Voting.Protocol.Tally.DecryptionShare q)
+ Voting.Protocol.Tally: instance Control.DeepSeq.NFData (Voting.Protocol.Tally.Tally q)
+ Voting.Protocol.Tally: instance Control.DeepSeq.NFData Voting.Protocol.Tally.ErrorDecryptionShare
+ Voting.Protocol.Tally: instance GHC.Classes.Eq (Voting.Protocol.Tally.DecryptionShare q)
+ Voting.Protocol.Tally: instance GHC.Classes.Eq (Voting.Protocol.Tally.Tally q)
+ Voting.Protocol.Tally: instance GHC.Classes.Eq Voting.Protocol.Tally.ErrorDecryptionShare
+ Voting.Protocol.Tally: instance GHC.Generics.Generic (Voting.Protocol.Tally.DecryptionShare q)
+ Voting.Protocol.Tally: instance GHC.Generics.Generic (Voting.Protocol.Tally.Tally q)
+ Voting.Protocol.Tally: instance GHC.Generics.Generic Voting.Protocol.Tally.ErrorDecryptionShare
+ Voting.Protocol.Tally: instance GHC.Show.Show (Voting.Protocol.Tally.DecryptionShare q)
+ Voting.Protocol.Tally: instance GHC.Show.Show (Voting.Protocol.Tally.Tally q)
+ Voting.Protocol.Tally: instance GHC.Show.Show Voting.Protocol.Tally.ErrorDecryptionShare
+ Voting.Protocol.Tally: proveDecryptionFactor :: Monad m => SubGroup q => RandomGen r => SecretKey q -> Encryption q -> StateT r m (DecryptionFactor q, Proof q)
+ Voting.Protocol.Tally: proveDecryptionShare :: Monad m => SubGroup q => RandomGen r => EncryptedTally q -> SecretKey q -> StateT r m (DecryptionShare q)
+ Voting.Protocol.Tally: proveTally :: SubGroup q => (EncryptedTally q, Natural) -> [DecryptionShare q] -> DecryptionShareCombinator q -> Except ErrorDecryptionShare (Tally q)
+ Voting.Protocol.Tally: type DecryptionFactor = G
+ Voting.Protocol.Tally: type DecryptionShareCombinator q = [DecryptionShare q] -> Except ErrorDecryptionShare [[DecryptionFactor q]]
+ Voting.Protocol.Tally: type EncryptedTally q = [[Encryption q]]
+ Voting.Protocol.Tally: verifyDecryptionShare :: Monad m => SubGroup q => EncryptedTally q -> PublicKey q -> DecryptionShare q -> ExceptT ErrorDecryptionShare m ()
+ Voting.Protocol.Tally: verifyDecryptionShareByTrustee :: Monad m => SubGroup q => EncryptedTally q -> [PublicKey q] -> [DecryptionShare q] -> ExceptT ErrorDecryptionShare m ()
+ Voting.Protocol.Tally: verifyTally :: SubGroup q => Tally q -> DecryptionShareCombinator q -> Except ErrorDecryptionShare ()
+ Voting.Protocol.Trustee.Indispensable: ErrorTrusteePublicKey_Wrong :: ErrorTrusteePublicKey
+ Voting.Protocol.Trustee.Indispensable: TrusteePublicKey :: PublicKey q -> Proof q -> TrusteePublicKey q
+ Voting.Protocol.Trustee.Indispensable: [trustee_PublicKey] :: TrusteePublicKey q -> PublicKey q
+ Voting.Protocol.Trustee.Indispensable: [trustee_SecretKeyProof] :: TrusteePublicKey q -> Proof q
+ Voting.Protocol.Trustee.Indispensable: combineIndispensableDecryptionShares :: SubGroup q => [PublicKey q] -> EncryptedTally q -> DecryptionShareCombinator q
+ Voting.Protocol.Trustee.Indispensable: combineIndispensableTrusteePublicKeys :: SubGroup q => [TrusteePublicKey q] -> PublicKey q
+ Voting.Protocol.Trustee.Indispensable: data ErrorTrusteePublicKey
+ Voting.Protocol.Trustee.Indispensable: data TrusteePublicKey q
+ Voting.Protocol.Trustee.Indispensable: indispensableTrusteePublicKeyStatement :: PublicKey q -> ByteString
+ Voting.Protocol.Trustee.Indispensable: instance GHC.Classes.Eq (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey q)
+ Voting.Protocol.Trustee.Indispensable: instance GHC.Classes.Eq Voting.Protocol.Trustee.Indispensable.ErrorTrusteePublicKey
+ Voting.Protocol.Trustee.Indispensable: instance GHC.Show.Show (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey q)
+ Voting.Protocol.Trustee.Indispensable: instance GHC.Show.Show Voting.Protocol.Trustee.Indispensable.ErrorTrusteePublicKey
+ Voting.Protocol.Trustee.Indispensable: proveIndispensableTrusteePublicKey :: Monad m => RandomGen r => SubGroup q => SecretKey q -> StateT r m (TrusteePublicKey q)
+ Voting.Protocol.Trustee.Indispensable: verifyIndispensableDecryptionShareByTrustee :: SubGroup q => Monad m => EncryptedTally q -> [PublicKey q] -> [DecryptionShare q] -> ExceptT ErrorDecryptionShare m ()
+ Voting.Protocol.Trustee.Indispensable: verifyIndispensableTrusteePublicKey :: Monad m => SubGroup q => TrusteePublicKey q -> ExceptT ErrorTrusteePublicKey m ()

Files

benchmarks/Election.hs view
@@ -13,7 +13,7 @@  { election_name = Text.pack $ "elec"<>show nQuests<>show nChoices  , election_description = "benchmarkable election"  , election_uuid- , election_publicKey =+ , election_PublicKey = 	let secKey = credentialSecretKey election_uuid (Credential "xLcs7ev6Jy6FHHE") in 	publicKey secKey  , election_hash = Hash "" -- FIXME: when implemented@@ -85,7 +85,7 @@ 		 | (nQuests,nChoices) <- inputs 		 ] 	 , bgroup "verifyBallot"-		 [ benchVerifyBallot @BeleniosParams nQuests nChoices+		 [ benchVerifyBallot @WeakParams nQuests nChoices 		 | (nQuests,nChoices) <- inputs 		 ] 	 ]
hjugement-protocol.cabal view
@@ -2,7 +2,7 @@ -- PVP:  +-+------- breaking API changes --       | | +----- non-breaking API additions --       | | | +--- code changes with no API change-version: 0.0.0.20190511+version: 0.0.0.20190513 category: Politic synopsis: A cryptographic protocol for the Majority Judgment. description:@@ -67,8 +67,9 @@     Voting.Protocol.Arithmetic     Voting.Protocol.Credential     Voting.Protocol.Election-    Voting.Protocol.Trustees-    Voting.Protocol.Trustees.All+    Voting.Protocol.Tally+    Voting.Protocol.Trustee+    Voting.Protocol.Trustee.Indispensable     Voting.Protocol.Utils   default-language: Haskell2010   default-extensions:@@ -123,6 +124,8 @@     HUnit.Arithmetic     HUnit.Credential     HUnit.Election+    HUnit.Trustee+    HUnit.Trustee.Indispensable     QuickCheck     QuickCheck.Election     QuickCheck.Trustee
src/Voting/Protocol.hs view
@@ -2,10 +2,12 @@  ( module Voting.Protocol.Arithmetic  , module Voting.Protocol.Credential  , module Voting.Protocol.Election- , module Voting.Protocol.Trustees+ , module Voting.Protocol.Tally+ , module Voting.Protocol.Trustee  ) where  import Voting.Protocol.Arithmetic import Voting.Protocol.Credential import Voting.Protocol.Election-import Voting.Protocol.Trustees+import Voting.Protocol.Tally+import Voting.Protocol.Trustee
src/Voting/Protocol/Arithmetic.hs view
@@ -206,9 +206,7 @@ -- Used by 'proveEncryption' and 'verifyEncryption', -- where the 'bs' usually contains the 'statement' to be proven, -- and the 'gs' contains the 'commitments'.-hash ::- SubGroup q =>- BS.ByteString -> [G q] -> E q+hash :: SubGroup q => BS.ByteString -> [G q] -> E q hash bs gs = 	let s = bs <> BS.intercalate (fromString ",") (bytesNat <$> gs) in 	let h = ByteArray.convert (Crypto.hashWith Crypto.SHA256 s) in
src/Voting/Protocol/Credential.hs view
@@ -49,10 +49,7 @@ tokenLength = 14  -- | @'randomCredential'@ generates a random 'Credential'.-randomCredential ::- Monad m =>- Random.RandomGen r =>- S.StateT r m Credential+randomCredential :: Monad m => Random.RandomGen r => S.StateT r m Credential randomCredential = do 	rs <- replicateM tokenLength (randomR (fromIntegral tokenBase)) 	let (tot, cs) = List.foldl' (\(acc,ds) d ->@@ -107,6 +104,9 @@  -- ** Type 'SecretKey' type SecretKey = E++randomSecretKey :: Monad m => RandomGen r => SubGroup q => S.StateT r m (SecretKey q)+randomSecretKey = random  -- | @('credentialSecretKey' uuid cred)@ returns the 'SecretKey' -- derived from given 'uuid' and 'cred'
src/Voting/Protocol/Election.hs view
@@ -1,12 +1,13 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE OverloadedStrings #-} module Voting.Protocol.Election where  import Control.DeepSeq (NFData)-import Control.Monad (Monad(..), join, mapM, replicateM, unless, zipWithM)+import Control.Monad (Monad(..), join, mapM, replicateM, zipWithM) import Control.Monad.Trans.Class (MonadTrans(..))-import Control.Monad.Trans.Except (Except, ExceptT, runExcept, throwE, withExceptT)+import Control.Monad.Trans.Except (ExceptT, runExcept, throwE, withExceptT) import Data.Bool import Data.Either (either) import Data.Eq (Eq(..))@@ -14,12 +15,12 @@ import Data.Function (($), id, const) import Data.Functor (Functor, (<$>)) import Data.Functor.Identity (Identity(..))-import Data.Maybe (Maybe(..), fromMaybe, maybe)+import Data.Maybe (Maybe(..), fromMaybe) import Data.Ord (Ord(..)) import Data.Semigroup (Semigroup(..)) import Data.Text (Text) import Data.Traversable (Traversable(..))-import Data.Tuple (fst, snd, uncurry)+import Data.Tuple (fst, snd) import GHC.Natural (minusNaturalMaybe) import GHC.Generics (Generic) import Numeric.Natural (Natural)@@ -28,7 +29,6 @@ import qualified Control.Monad.Trans.State.Strict as S import qualified Data.ByteString as BS import qualified Data.List as List-import qualified Data.Map.Strict as Map  import Voting.Protocol.Utils import Voting.Protocol.Arithmetic@@ -88,7 +88,8 @@ 		 }  -- * Type 'Proof'--- | 'Proof' of knowledge of a discrete logarithm:+-- | Non-Interactive Zero-Knowledge 'Proof'+-- of knowledge of a discrete logarithm: -- @(secret == logBase base (base^secret))@. data Proof q = Proof  { proof_challenge :: Challenge q@@ -236,7 +237,8 @@ -- is indexing a 'Disjunction' within a list of them, -- without revealing which 'Opinion' it is. newtype DisjProof q = DisjProof [Proof q]- deriving (Eq,Show,Generic,NFData)+ deriving (Eq,Show,Generic)+ deriving newtype NFData  -- | @('proveEncryption' elecPubKey voterZKP (prevDisjs,nextDisjs) (encNonce,enc))@ -- returns a 'DisjProof' that 'enc' 'encrypt's@@ -423,7 +425,7 @@ data Election q = Election  { election_name        :: Text  , election_description :: Text- , election_publicKey   :: PublicKey q+ , election_PublicKey   :: PublicKey q  , election_questions   :: [Question q]  , election_uuid        :: UUID  , election_hash        :: Hash -- TODO: serialize to JSON to calculate this@@ -431,7 +433,8 @@  -- ** Type 'Hash' newtype Hash = Hash Text- deriving (Eq,Ord,Show,Generic,NFData)+ deriving (Eq,Ord,Show,Generic)+ deriving newtype NFData  -- * Type 'Ballot' data Ballot q = Ballot@@ -465,7 +468,7 @@ 			where ballotPubKey = publicKey ballotSecKey 	ballot_answers <- 		S.mapStateT (withExceptT ErrorBallot_Answer) $-			zipWithM (encryptAnswer election_publicKey voterZKP)+			zipWithM (encryptAnswer election_PublicKey voterZKP) 			 election_questions opinionsByQuest 	ballot_signature <- case voterKeys of 	 Nothing -> return Nothing@@ -503,7 +506,7 @@ 				 (signatureStatement ballot_answers) 	in 	and $ isValidSign :-		List.zipWith (verifyAnswer election_publicKey zkpSign)+		List.zipWith (verifyAnswer election_PublicKey zkpSign) 		 election_questions ballot_answers  -- ** Type 'Signature'@@ -543,128 +546,6 @@      -- is different than the number of questions.  |   ErrorBallot_Answer ErrorAnswer      -- ^ When 'encryptAnswer' raised an 'ErrorAnswer'.- deriving (Eq,Show,Generic,NFData)---- * Type 'DecryptionShare'--- | A decryption share. It is computed by a trustee from his/her--- private key share and the encrypted tally,--- and contains a cryptographic 'Proof' that it didn't cheat.-data DecryptionShare q = DecryptionShare- { decryptionShare_factors :: [[DecryptionFactor q]]-   -- ^ 'DecryptionFactor' by voter, by 'Question'.- , decryptionShare_proofs  :: [[Proof q]]-   -- ^ 'Proof's that 'decryptionShare_factors' were correctly computed.- } deriving (Eq,Show,Generic,NFData)---- BELENIOS: compute_factor--- @('proveDecryptionShare' trusteeSecKey encByQuestByBallot)@-proveDecryptionShare ::- Monad m => SubGroup q => RandomGen r =>- SecretKey q -> [[Encryption q]] -> S.StateT r m (DecryptionShare q)-proveDecryptionShare secKey encs = do-	res <- (proveDecryptionFactor secKey `mapM`) `mapM` encs-	return $ uncurry DecryptionShare $ List.unzip (List.unzip <$> res)---- BELENIOS: eg_factor-proveDecryptionFactor ::- Monad m => SubGroup q => RandomGen r =>- SecretKey q -> Encryption q -> S.StateT r m (DecryptionFactor q, Proof q)-proveDecryptionFactor secKey Encryption{..} = do-	proof <- prove secKey [groupGen, encryption_nonce] (hash zkp)-	return (encryption_nonce^secKey, proof)-	where zkp = decryptionShareStatement (publicKey secKey)--decryptionShareStatement :: SubGroup q => PublicKey q -> BS.ByteString-decryptionShareStatement pubKey =-	"decrypt|"<>bytesNat pubKey<>"|"---- ** Type 'DecryptionFactor'-type DecryptionFactor = G---- ** Type 'ErrorDecryptionShare'-data ErrorDecryptionShare- =   ErrorDecryptionShare_Invalid-     -- ^ The number of 'DecryptionFactor's or-     -- the number of 'Proof's is not the same-     -- or not the expected number.- |   ErrorDecryptionShare_Wrong-     -- ^ The 'Proof' of a 'DecryptionFactor' is wrong.+ |   ErrorBallot_Wrong+     -- ^ TODO: to be more precise.  deriving (Eq,Show,Generic,NFData)---- BELENIOS: check_factor--- | @('verifyDecryptionShare' encByQuestByBallot pubKey decShare)@--- checks that 'decShare'--- (supposedly submitted by a trustee whose public key is 'pubKey')--- is valid with respect to the encrypted tally 'encByQuestByBallot'.-verifyDecryptionShare ::- Monad m => SubGroup q =>- [[Encryption q]] ->- PublicKey q -> DecryptionShare q -> ExceptT ErrorDecryptionShare m ()-verifyDecryptionShare encByQuestByBallot pubKey DecryptionShare{..} =-	let zkp = decryptionShareStatement pubKey in-	isoZipWith3M_ (throwE ErrorDecryptionShare_Invalid)-	 (isoZipWith3M_ (throwE ErrorDecryptionShare_Invalid) $-	 \Encryption{..} decFactor proof ->-		unless (proof_challenge proof == hash zkp-		 [ commit proof groupGen pubKey-		 , commit proof encryption_nonce decFactor-		 ]) $-			throwE ErrorDecryptionShare_Wrong)-	 encByQuestByBallot-	 decryptionShare_factors-	 decryptionShare_proofs---- * Type 'Tally'-data Tally q = Tally- { tally_numBallots :: Natural- , tally_encByQuestByBallot :: [[Encryption q]]-   -- ^ 'Encryption' by 'Question' by 'Ballot'.- , tally_decShareByTrustee :: [DecryptionShare q]-   -- ^ 'DecryptionShare' by trustee.- , tally_countByQuestByBallot :: [[Natural]]- } deriving (Eq,Show,Generic,NFData)--type DecryptionShareCombinator q =-	[DecryptionShare q] -> Except ErrorDecryptionShare [[DecryptionFactor q]]---- BELENIOS: compute_result-proveTally ::- Monad m => SubGroup q =>- [[Encryption q]] -> [DecryptionShare q] ->- DecryptionShareCombinator q ->- Except ErrorDecryptionShare (Tally q)-proveTally tally_encByQuestByBallot tally_decShareByTrustee decShareCombinator = do-	decFactorByQuestByBallot <- decShareCombinator tally_decShareByTrustee-	dec <- isoZipWithM err-	 (\encByQuest decFactorByQuest ->-		maybe err return $-			isoZipWith (\Encryption{..} decFactor -> encryption_vault / decFactor)-			 encByQuest-			 decFactorByQuest-	 )-	 tally_encByQuestByBallot-	 decFactorByQuestByBallot-	let tally_numBallots = fromIntegral $ List.length tally_encByQuestByBallot-	let logMap = Map.fromDistinctAscList $ List.zip groupGenPowers [0..tally_numBallots]-	let log x = maybe err return $ Map.lookup x logMap-	tally_countByQuestByBallot <- (log `mapM`)`mapM`dec-	return Tally{..}-	where err = throwE ErrorDecryptionShare_Invalid--verifyTally ::- Monad m => SubGroup q =>- DecryptionShareCombinator q -> Tally q ->- Except ErrorDecryptionShare ()-verifyTally decShareCombinator Tally{..} = do-	decFactorByQuestByBallot <- decShareCombinator tally_decShareByTrustee-	isoZipWith3M_ (throwE ErrorDecryptionShare_Invalid)-	 (isoZipWith3M_ (throwE ErrorDecryptionShare_Invalid)-		 (\Encryption{..} decFactor count -> do-			let dec = encryption_vault / decFactor-			unless (dec == groupGen ^ fromNatural count) $-				throwE ErrorDecryptionShare_Wrong-		 )-	 )-	 tally_encByQuestByBallot-	 decFactorByQuestByBallot-	 tally_countByQuestByBallot
+ src/Voting/Protocol/Tally.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+module Voting.Protocol.Tally where++import Control.DeepSeq (NFData)+import Control.Monad (Monad(..), mapM, unless)+import Control.Monad.Trans.Except (Except, ExceptT, throwE)+import Data.Eq (Eq(..))+import Data.Function (($))+import Data.Functor ((<$>))+import Data.Maybe (maybe)+import Data.Semigroup (Semigroup(..))+import Data.Text (Text)+import Data.Tuple (fst, uncurry)+import GHC.Generics (Generic)+import Numeric.Natural (Natural)+import Prelude (fromIntegral)+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 qualified Data.Map.Strict as Map++import Voting.Protocol.Utils+import Voting.Protocol.Arithmetic+import Voting.Protocol.Credential+import Voting.Protocol.Election++-- * Type 'Tally'+data Tally q = Tally+ { tally_countMax :: Natural+   -- ^ The maximal number of supportive 'Opinion's that a choice can get,+   -- which is here the same as the number of 'Ballot's.+   --+   -- Used in 'proveTally' to decrypt the actual+   -- count of votes obtained by a choice,+   -- by precomputing all powers of 'groupGen's up to it.+ , tally_encByChoiceByQuest :: EncryptedTally q+   -- ^ 'Encryption' by 'Question' by 'Ballot'.+ , tally_decShareByTrustee :: [DecryptionShare q]+   -- ^ 'DecryptionShare' by trustee.+ , tally_countByChoiceByQuest :: [[Natural]]+   -- ^ The decrypted count of supportive 'Opinion's, by choice by 'Question'.+ } deriving (Eq,Show,Generic,NFData)++-- ** Type 'EncryptedTally'+-- | 'Encryption' by 'Choice' by 'Question'.+type EncryptedTally q = [[Encryption q]]++-- | @('encryptedTally' ballots)@+-- returns the sum of the 'Encryption's of the given @ballots@,+-- along with the number of 'Ballot's.+encryptedTally :: SubGroup q => [Ballot q] -> (EncryptedTally q, Natural)+encryptedTally ballots =+	( List.foldr (\Ballot{..} ->+		List.zipWith (\Answer{..} ->+			List.zipWith (+)+			 (fst <$> answer_opinions))+		 ballot_answers+	 )+	 (List.repeat (List.repeat zero))+	 ballots+	, fromIntegral $ List.length ballots+	)++-- ** Type 'DecryptionShareCombinator'+type DecryptionShareCombinator q =+	[DecryptionShare q] -> Except ErrorDecryptionShare [[DecryptionFactor q]]++proveTally ::+ SubGroup q =>+ (EncryptedTally q, Natural) -> [DecryptionShare q] ->+ DecryptionShareCombinator q ->+ Except ErrorDecryptionShare (Tally q)+proveTally+ (tally_encByChoiceByQuest, tally_countMax)+ tally_decShareByTrustee+ decShareCombinator = do+	decFactorByChoiceByQuest <- decShareCombinator tally_decShareByTrustee+	dec <- isoZipWithM err+	 (\encByChoice decFactorByChoice ->+		maybe err return $+			isoZipWith (\Encryption{..} decFactor -> encryption_vault / decFactor)+			 encByChoice+			 decFactorByChoice)+	 tally_encByChoiceByQuest+	 decFactorByChoiceByQuest+	let logMap = Map.fromList $ List.zip groupGenPowers [0..tally_countMax]+	let log x =+		maybe (throwE $ ErrorDecryptionShare_InvalidMaxCount) return $+		Map.lookup x logMap+	tally_countByChoiceByQuest <- (log `mapM`)`mapM`dec+	return Tally{..}+	where err = throwE $ ErrorDecryptionShare_Invalid "proveTally"++verifyTally ::+ SubGroup q =>+ Tally q -> DecryptionShareCombinator q ->+ Except ErrorDecryptionShare ()+verifyTally Tally{..} decShareCombinator = do+	decFactorByChoiceByQuest <- decShareCombinator tally_decShareByTrustee+	isoZipWith3M_ (throwE $ ErrorDecryptionShare_Invalid "verifyTally")+	 (isoZipWith3M_ (throwE $ ErrorDecryptionShare_Invalid "verifyTally")+		 (\Encryption{..} decFactor count -> do+			let groupGenPowCount = encryption_vault / decFactor+			unless (groupGenPowCount == groupGen ^ fromNatural count) $+				throwE ErrorDecryptionShare_Wrong))+	 tally_encByChoiceByQuest+	 decFactorByChoiceByQuest+	 tally_countByChoiceByQuest++-- ** Type 'DecryptionShare'+-- | A decryption share. It is computed by a trustee+-- from its 'SecretKey' share and the 'EncryptedTally',+-- and contains a cryptographic 'Proof' that it hasn't cheated.+data DecryptionShare q = DecryptionShare+ { decryptionShare_factors :: [[DecryptionFactor q]]+   -- ^ 'DecryptionFactor' by choice by 'Question'.+ , decryptionShare_proofs  :: [[Proof q]]+   -- ^ 'Proof's that 'decryptionShare_factors' were correctly computed.+ } deriving (Eq,Show,Generic,NFData)++-- *** Type 'DecryptionFactor'+-- | @'encryption_nonce' '^'trusteeSecKey@+type DecryptionFactor = G++-- @('proveDecryptionShare' encByChoiceByQuest trusteeSecKey)@+proveDecryptionShare ::+ Monad m => SubGroup q => RandomGen r =>+ EncryptedTally q -> SecretKey q -> S.StateT r m (DecryptionShare q)+proveDecryptionShare encByChoiceByQuest trusteeSecKey = do+	res <- (proveDecryptionFactor trusteeSecKey `mapM`) `mapM` encByChoiceByQuest+	return $ uncurry DecryptionShare $ List.unzip (List.unzip <$> res)++proveDecryptionFactor ::+ Monad m => SubGroup q => RandomGen r =>+ SecretKey q -> Encryption q -> S.StateT r m (DecryptionFactor q, Proof q)+proveDecryptionFactor trusteeSecKey Encryption{..} = do+	proof <- prove trusteeSecKey [groupGen, encryption_nonce] (hash zkp)+	return (encryption_nonce^trusteeSecKey, proof)+	where zkp = decryptionShareStatement (publicKey trusteeSecKey)++decryptionShareStatement :: SubGroup q => PublicKey q -> BS.ByteString+decryptionShareStatement pubKey =+	"decrypt|"<>bytesNat pubKey<>"|"++-- *** Type 'ErrorDecryptionShare'+data ErrorDecryptionShare+ =   ErrorDecryptionShare_Invalid Text+     -- ^ The number of 'DecryptionFactor's or+     -- the number of 'Proof's is not the same+     -- or not the expected number.+ |   ErrorDecryptionShare_Wrong+     -- ^ The 'Proof' of a 'DecryptionFactor' is wrong.+ |   ErrorDecryptionShare_InvalidMaxCount+ deriving (Eq,Show,Generic,NFData)++-- | @('verifyDecryptionShare' encTally trusteePubKey trusteeDecShare)@+-- checks that 'trusteeDecShare'+-- (supposedly submitted by a trustee whose 'PublicKey' is 'trusteePubKey')+-- is valid with respect to the 'EncryptedTally' 'encTally'.+verifyDecryptionShare ::+ Monad m => SubGroup q =>+ EncryptedTally q -> PublicKey q -> DecryptionShare q ->+ ExceptT ErrorDecryptionShare m ()+verifyDecryptionShare encTally trusteePubKey DecryptionShare{..} =+	let zkp = decryptionShareStatement trusteePubKey in+	isoZipWith3M_ (throwE $ ErrorDecryptionShare_Invalid "verifyDecryptionShare")+	 (isoZipWith3M_ (throwE $ ErrorDecryptionShare_Invalid "verifyDecryptionShare") $+	 \Encryption{..} decFactor proof ->+		unless (proof_challenge proof == hash zkp+		 [ commit proof groupGen trusteePubKey+		 , commit proof encryption_nonce decFactor+		 ]) $+			throwE ErrorDecryptionShare_Wrong)+	 encTally+	 decryptionShare_factors+	 decryptionShare_proofs++verifyDecryptionShareByTrustee ::+ Monad m => SubGroup q =>+ EncryptedTally q -> [PublicKey q] -> [DecryptionShare q] ->+ ExceptT ErrorDecryptionShare m ()+verifyDecryptionShareByTrustee encTally =+	isoZipWithM_ (throwE $ ErrorDecryptionShare_Invalid "verifyDecryptionShare")+	 (verifyDecryptionShare encTally)
+ src/Voting/Protocol/Trustee.hs view
@@ -0,0 +1,5 @@+module Voting.Protocol.Trustee+ ( module Voting.Protocol.Trustee.Indispensable+ ) where++import Voting.Protocol.Trustee.Indispensable
+ src/Voting/Protocol/Trustee/Indispensable.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE OverloadedStrings #-}+module Voting.Protocol.Trustee.Indispensable 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+import Voting.Protocol.Tally++-- * Type 'TrusteePublicKey'+data TrusteePublicKey q = TrusteePublicKey+ { trustee_PublicKey      :: PublicKey q+ , trustee_SecretKeyProof :: Proof q+	-- ^ NOTE: It is important to ensure+	-- that each trustee generates its key pair independently+	-- of the 'PublicKey's published by the other trustees.+	-- Otherwise, a dishonest trustee could publish as 'PublicKey'+	-- its genuine 'PublicKey' divided by the 'PublicKey's of the other trustees.+	-- This would then lead to the 'election_PublicKey'+	-- being equal to this dishonest trustee's 'PublicKey',+	-- which means that knowing its 'SecretKey' would be sufficient+	-- for decrypting messages encrypted to the 'election_PublicKey'.+	-- To avoid this attack, each trustee publishing a 'PublicKey'+	-- must 'prove' knowledge of the corresponding 'SecretKey'.+	-- Which is done in 'proveIndispensableTrusteePublicKey'+	-- and 'verifyIndispensableTrusteePublicKey'.+ } deriving (Eq,Show)++-- ** Type 'ErrorTrusteePublicKey'+data ErrorTrusteePublicKey+ =   ErrorTrusteePublicKey_Wrong+     -- ^ The 'trustee_SecretKeyProof' is wrong.+ deriving (Eq,Show)++-- | @('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)+proveIndispensableTrusteePublicKey trustSecKey = do+	let trustee_PublicKey = publicKey trustSecKey+	trustee_SecretKeyProof <-+		prove trustSecKey [groupGen] $+			hash (indispensableTrusteePublicKeyStatement trustee_PublicKey)+	return TrusteePublicKey{..}++-- | @('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 ->+ ExceptT ErrorTrusteePublicKey m ()+verifyIndispensableTrusteePublicKey TrusteePublicKey{..} =+	unless ((proof_challenge trustee_SecretKeyProof ==) $+	hash+	 (indispensableTrusteePublicKeyStatement trustee_PublicKey)+	 [commit trustee_SecretKeyProof groupGen trustee_PublicKey]) $+		throwE ErrorTrusteePublicKey_Wrong++-- ** Hashing+indispensableTrusteePublicKeyStatement :: PublicKey q -> BS.ByteString+indispensableTrusteePublicKeyStatement trustPubKey = "pok|"<>bytesNat trustPubKey<>"|"++-- * 'Election''s 'PublicKey'++combineIndispensableTrusteePublicKeys ::+ SubGroup q => [TrusteePublicKey q] -> PublicKey q+combineIndispensableTrusteePublicKeys =+	List.foldr (\TrusteePublicKey{..} -> (trustee_PublicKey *)) one++verifyIndispensableDecryptionShareByTrustee ::+ SubGroup q => Monad m =>+ EncryptedTally q -> [PublicKey q] -> [DecryptionShare q] ->+ ExceptT ErrorDecryptionShare m ()+verifyIndispensableDecryptionShareByTrustee encTally =+	isoZipWithM_ (throwE $ ErrorDecryptionShare_Invalid "verifyIndispensableDecryptionShareByTrustee")+	 (verifyDecryptionShare encTally)++-- | @('combineDecryptionShares' pubKeyByTrustee decShareByTrustee)@+-- returns the 'DecryptionFactor's by choice by 'Question'+combineIndispensableDecryptionShares ::+ SubGroup q => [PublicKey q] -> EncryptedTally q -> DecryptionShareCombinator q+combineIndispensableDecryptionShares pubKeyByTrustee encTally decShareByTrustee = do+	verifyIndispensableDecryptionShareByTrustee encTally pubKeyByTrustee decShareByTrustee+	(d0,ds) <- maybe err return $ List.uncons decShareByTrustee+	foldM+	 (\decFactorByChoiceByQuest DecryptionShare{..} ->+		isoZipWithM err+		 (\acc df -> maybe err return $ isoZipWith (*) acc df)+		 decFactorByChoiceByQuest decryptionShare_factors)+	 (decryptionShare_factors d0) ds+	where err = throwE $ ErrorDecryptionShare_Invalid "combineIndispensableDecryptionShares"
− src/Voting/Protocol/Trustees.hs
@@ -1,5 +0,0 @@-module Voting.Protocol.Trustees- ( module Voting.Protocol.Trustees.All- ) where--import Voting.Protocol.Trustees.All
− src/Voting/Protocol/Trustees/All.hs
@@ -1,92 +0,0 @@-{-# 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---- * Type 'TrusteePublicKey'-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---- ** Type 'ErrorTrusteePublicKey'-data ErrorTrusteePublicKey- =   ErrorTrusteePublicKey_Wrong-     -- ^ The 'trustee_SecretKeyProof' is wrong.- deriving (Eq,Show)---- BELENIOS: MakeSimple.prove--- | @('proveTrusteePublicKey' trustSecKey)@--- returns the 'PublicKey' associated to 'trustSecKey'--- and a 'Proof' of its knowledge.-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{..}---- BELENIOS: MakeSimple.check--- | @('verifyTrusteePublicKey' trustPubKey)@--- returns 'True' iif. the given 'trustee_SecretKeyProof'--- does prove that the 'SecretKey' associated with--- the given 'trustee_PublicKey' is known by the trustee.-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---- ** Hashing-trusteePublicKeyStatement :: PublicKey q -> BS.ByteString-trusteePublicKeyStatement trustPubKey = "pok|"<>bytesNat trustPubKey<>"|"---- BELENIOS: MakeSimple.combine-electionPublicKey :: SubGroup q => [TrusteePublicKey q] -> PublicKey q-electionPublicKey = List.foldr (\TrusteePublicKey{..} -> (trustee_PublicKey *)) one---- BELENIOS: combine_factors--- | @('combineDecryptionShares' checker pubKeyByTrustee decShareByTrustee)@--- returns the 'DecryptionFactor's by voter by question-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
tests/HUnit.hs view
@@ -3,6 +3,7 @@ import qualified HUnit.Arithmetic import qualified HUnit.Credential import qualified HUnit.Election+import qualified HUnit.Trustee  hunits :: TestTree hunits =@@ -10,4 +11,5 @@ 	 [ HUnit.Arithmetic.hunit 	 , HUnit.Credential.hunit 	 , HUnit.Election.hunit+	 , HUnit.Trustee.hunit 	 ]
tests/HUnit/Arithmetic.hs view
@@ -3,7 +3,7 @@ module HUnit.Arithmetic where  import Test.Tasty.HUnit-import Protocol.Arithmetic+import Voting.Protocol import Utils  hunit :: TestTree
tests/HUnit/Credential.hs view
@@ -7,8 +7,7 @@ import qualified Control.Monad.Trans.State.Strict as S import qualified System.Random as Random -import Protocol.Arithmetic-import Protocol.Credential+import Voting.Protocol import Utils  hunit :: TestTree
tests/HUnit/Election.hs view
@@ -8,10 +8,7 @@ import qualified Data.List as List import qualified System.Random as Random -import Protocol.Arithmetic-import Protocol.Credential-import Protocol.Election-import Protocol.Trustees.Simple+import Voting.Protocol  import Utils @@ -29,9 +26,6 @@ 	 [ testsEncryptBallot @WeakParams 	 , testsEncryptBallot @BeleniosParams 	 ]- , testGroup "trustee" $-	 [ testsTrustee @WeakParams-	 ]  ]  testsEncryptBallot :: forall q. Params q => TestTree@@ -84,17 +78,17 @@  Either ErrorBallot Bool ->  TestTree testEncryptBallot seed quests opins exp =-	let verify =+	let got = 		runExcept $ 		(`evalStateT` Random.mkStdGen seed) $ do 			uuid <- randomUUID 			cred <- randomCredential 			let ballotSecKey = credentialSecretKey @q uuid cred-			let elecPubKey = publicKey ballotSecKey -- FIXME: wrong key+			elecPubKey <- publicKey <$> randomSecretKey 			let elec = Election 				 { election_name        = "election" 				 , election_description = "description"-				 , election_publicKey   = elecPubKey+				 , election_PublicKey   = elecPubKey 				 , election_questions   = quests 				 , election_uuid        = uuid 				 , election_hash        = Hash "" -- FIXME: when implemented@@ -103,24 +97,4 @@ 			 <$> encryptBallot elec (Just ballotSecKey) opins 	in 	testCase (show opins) $-		verify @?= exp--testsTrustee :: forall q. Params q => TestTree-testsTrustee =-	testGroup (paramsName @q)-	 [ testTrustee @q 0 (Right ())-	 ]--testTrustee ::- forall q. SubGroup q =>- Int -> Either ErrorTrusteePublicKey () -> TestTree-testTrustee seed exp =-	let verify =-		runExcept $-		(`evalStateT` Random.mkStdGen seed) $ do-			trustSecKey <- randomSecretKey @_ @_ @q-			trustPubKey <- proveTrusteePublicKey trustSecKey-			lift $ verifyTrusteePublicKey trustPubKey-	in-	testCase (show seed) $-		verify @?= exp+		got @?= exp
+ tests/HUnit/Trustee.hs view
@@ -0,0 +1,9 @@+module HUnit.Trustee where+import Test.Tasty+import qualified HUnit.Trustee.Indispensable++hunit :: TestTree+hunit =+	testGroup "Trustee"+	 [ HUnit.Trustee.Indispensable.hunit+	 ]
+ tests/HUnit/Trustee/Indispensable.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+module HUnit.Trustee.Indispensable where++import Test.Tasty.HUnit+import qualified System.Random as Random+import qualified Text.Printf as Printf++import Voting.Protocol++import Utils++hunit :: TestTree+hunit = testGroup "Indispensable"+ [ testGroup "verifyIndispensableTrusteePublicKey" $+	 [ testsVerifyIndispensableTrusteePublicKey @WeakParams+	 ]+ , testGroup "verifyTally" $+	 [ testsVerifyTally @WeakParams+	 , testsVerifyTally @BeleniosParams+	 ]+ ]++testsVerifyIndispensableTrusteePublicKey :: forall q. Params q => TestTree+testsVerifyIndispensableTrusteePublicKey =+	testGroup (paramsName @q)+	 [ testVerifyIndispensableTrusteePublicKey @q 0 (Right ())+	 ]++testVerifyIndispensableTrusteePublicKey ::+ forall q. Params q =>+ Int -> Either ErrorTrusteePublicKey () -> TestTree+testVerifyIndispensableTrusteePublicKey seed exp =+	let got =+		runExcept $+		(`evalStateT` Random.mkStdGen seed) $ do+			trusteeSecKey :: SecretKey q <- randomSecretKey+			trusteePubKey <- proveIndispensableTrusteePublicKey trusteeSecKey+			lift $ verifyIndispensableTrusteePublicKey trusteePubKey+	in+	testCase (show (paramsName @q)) $+		got @?= exp++testsVerifyTally :: forall q. Params q => TestTree+testsVerifyTally =+	testGroup (paramsName @q)+	 [ testVerifyTally @q 0 1 1 1+	 , testVerifyTally @q 0 2 1 1+	 , testVerifyTally @q 0 1 2 1+	 , testVerifyTally @q 0 2 2 1+	 , testVerifyTally @q 0 5 10 5+	 ]++testVerifyTally ::+ forall q. Params q =>+ Int -> Natural -> Natural -> Natural -> TestTree+testVerifyTally seed nTrustees nQuests nChoices =+	let clearTallyResult = dummyTallyResult nQuests nChoices in+	let decryptedTallyResult :: Either ErrorDecryptionShare [[Natural]] =+		runExcept $+		(`evalStateT` Random.mkStdGen seed) $ do+			secKeyByTrustee :: [SecretKey q] <-+				replicateM (fromIntegral nTrustees) $ randomSecretKey+			trusteePubKeys <- forM secKeyByTrustee $ proveIndispensableTrusteePublicKey+			let pubKeyByTrustee = trustee_PublicKey <$> trusteePubKeys+			let elecPubKey = combineIndispensableTrusteePublicKeys trusteePubKeys+			(encTally, countMax) <- encryptTallyResult elecPubKey clearTallyResult+			decShareByTrustee <- forM secKeyByTrustee $ proveDecryptionShare encTally+			lift $ verifyDecryptionShareByTrustee encTally pubKeyByTrustee decShareByTrustee+			tally@Tally{..} <- lift $+				proveTally (encTally, countMax) decShareByTrustee $+					combineIndispensableDecryptionShares pubKeyByTrustee encTally+			lift $ verifyTally tally $+				combineIndispensableDecryptionShares pubKeyByTrustee encTally+			return tally_countByChoiceByQuest+	in+	testCase (Printf.printf "nT=%i,nQ=%i,nC=%i (%i maxCount)"+	 nTrustees nQuests nChoices+	 (dummyTallyCount nQuests nChoices)) $+		decryptedTallyResult @?= Right clearTallyResult++dummyTallyCount :: Natural -> Natural -> Natural+dummyTallyCount quest choice = quest * choice++dummyTallyResult :: Natural -> Natural -> [[Natural]]+dummyTallyResult nQuests nChoices =+	[ [ dummyTallyCount q c | c <- [1..nChoices] ]+	| q <- [1..nQuests]+	]++encryptTallyResult ::+ Monad m => RandomGen r => SubGroup q =>+ PublicKey q -> [[Natural]] -> StateT r m (EncryptedTally q, Natural)+encryptTallyResult pubKey countByChoiceByQuest =+	(`runStateT` 0) $+		forM countByChoiceByQuest $+			mapM $ \count -> do+				modify' $ max count+				(_encNonce, enc) <- lift $ encrypt pubKey (fromNatural count)+				return enc+
tests/QuickCheck/Election.hs view
@@ -10,9 +10,7 @@ import Data.Ord (Ord(..)) import Prelude (undefined) -import Protocol.Arithmetic-import Protocol.Credential-import Protocol.Election+import Voting.Protocol  import Utils @@ -34,13 +32,13 @@ testElection :: forall q. Params q => TestTree testElection  = 	testGroup (paramsName @q)-	 [ testProperty "Right" $ \(seed, (elec::Election q) :> votes) ->+	 [ testProperty "verifyBallot" $ \(seed, (elec::Election q) :> votes) -> 		isRight $ runExcept $ 			(`evalStateT` mkStdGen seed) $ do 				-- ballotSecKey :: SecretKey q <- randomSecretKey 				ballot <- encryptBallot elec Nothing votes 				unless (verifyBallot elec ballot) $-					lift $ throwE $ ErrorBallot_WrongNumberOfAnswers 0 0+					lift $ throwE $ ErrorBallot_Wrong 	 ]  instance PrimeField p => Arbitrary (F p) where@@ -54,7 +52,7 @@ instance Arbitrary UUID where 	arbitrary = do 		seed <- arbitrary-		(`evalStateT` mkStdGen seed) $ do+		(`evalStateT` mkStdGen seed) $ 			randomUUID instance SubGroup q => Arbitrary (Proof q) where 	arbitrary = do@@ -80,7 +78,7 @@ 	arbitrary = do 		let election_name = "election" 		let election_description = "description"-		election_publicKey <- arbitrary+		election_PublicKey <- arbitrary 		election_questions <- resize (fromIntegral maxArbitraryQuestions) $ listOf1 arbitrary 		election_uuid <- arbitrary 		let election_hash = Hash ""@@ -140,7 +138,7 @@ -- to fit the requirement of the given @quest@. shrinkVotes :: Question q -> [Bool] -> [Bool] shrinkVotes Question{..} votes =-	(\(nTrue, b) -> if nTrue <= nat question_maxi then b else False)+	(\(nTrue, b) -> nTrue <= nat question_maxi && b) 	 <$> List.zip (countTrue votes) votes 	where 	countTrue :: [Bool] -> [Natural]
tests/QuickCheck/Trustee.hs view
@@ -3,9 +3,8 @@  import Test.Tasty.QuickCheck -import Protocol.Arithmetic-import Protocol.Credential-import Protocol.Trustees.Simple+import Voting.Protocol+import Voting.Protocol.Trustee.Indispensable  import Utils import QuickCheck.Election ()@@ -13,21 +12,21 @@ quickcheck :: TestTree quickcheck = 	testGroup "Trustee"-	 [ testGroup "verifyTrusteePublicKey" $-		 [ testTrusteePublicKey @WeakParams-		 , testTrusteePublicKey @BeleniosParams+	 [ testGroup "verifyIndispensableTrusteePublicKey" $+		 [ testIndispensableTrusteePublicKey @WeakParams+		 , testIndispensableTrusteePublicKey @BeleniosParams 		 ] 	 ] -testTrusteePublicKey :: forall q. Params q => TestTree-testTrusteePublicKey  =+testIndispensableTrusteePublicKey :: forall q. Params q => TestTree+testIndispensableTrusteePublicKey  = 	testGroup (paramsName @q) 	 [ testProperty "Right" $ \seed -> 		isRight $ runExcept $ 			(`evalStateT` mkStdGen seed) $ do-				trustSecKey :: SecretKey q <- randomSecretKey-				trustPubKey <- proveTrusteePublicKey trustSecKey-				lift $ verifyTrusteePublicKey trustPubKey+				trusteeSecKey :: SecretKey q <- randomSecretKey+				trusteePubKey <- proveIndispensableTrusteePublicKey trusteeSecKey+				lift $ verifyIndispensableTrusteePublicKey trusteePubKey 	 ]  instance SubGroup q => Arbitrary (TrusteePublicKey q) where
tests/Utils.hs view
@@ -1,8 +1,9 @@ module Utils  ( module Test.Tasty  , module Data.Bool+ , module Voting.Protocol.Utils  , Applicative(..)- , Monad(..), forM, replicateM, unless, when+ , Monad(..), forM, mapM, replicateM, unless, when  , Eq(..)  , Either(..), either, isLeft, isRight  , ($), (.), id, const, flip@@ -20,8 +21,9 @@  , ExceptT  , runExcept  , throwE- , StateT+ , StateT(..)  , evalStateT+ , modify'  , mkStdGen  , debug  , nCk@@ -51,6 +53,8 @@ import System.Random (mkStdGen) import Test.Tasty import Text.Show (Show(..))++import Voting.Protocol.Utils  debug msg x = trace (msg<>": "<>show x) x