summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjulm <>2019-05-13 18:46:00 (GMT)
committerhdiff <hdiff@hdiff.luite.com>2019-05-13 18:46:00 (GMT)
commitc09719458ba041997078c969250bd7f8fa3e5a20 (patch)
treeac82ad134c537baed12cf6890dd60d82462658f9
parent4a5cf554f44d2e48bc0a7a4512ef7658cae02f27 (diff)
version 0.0.0.201905130.0.0.20190513
-rw-r--r--benchmarks/Election.hs4
-rw-r--r--hjugement-protocol.cabal9
-rw-r--r--src/Voting/Protocol.hs6
-rw-r--r--src/Voting/Protocol/Arithmetic.hs4
-rw-r--r--src/Voting/Protocol/Credential.hs8
-rw-r--r--src/Voting/Protocol/Election.hs151
-rw-r--r--src/Voting/Protocol/Tally.hs187
-rw-r--r--src/Voting/Protocol/Trustee.hs5
-rw-r--r--src/Voting/Protocol/Trustee/Indispensable.hs106
-rw-r--r--src/Voting/Protocol/Trustees.hs5
-rw-r--r--src/Voting/Protocol/Trustees/All.hs92
-rw-r--r--tests/HUnit.hs2
-rw-r--r--tests/HUnit/Arithmetic.hs2
-rw-r--r--tests/HUnit/Credential.hs3
-rw-r--r--tests/HUnit/Election.hs36
-rw-r--r--tests/HUnit/Trustee.hs9
-rw-r--r--tests/HUnit/Trustee/Indispensable.hs103
-rw-r--r--tests/QuickCheck/Election.hs14
-rw-r--r--tests/QuickCheck/Trustee.hs21
-rw-r--r--tests/Utils.hs8
20 files changed, 474 insertions, 301 deletions
diff --git a/benchmarks/Election.hs b/benchmarks/Election.hs
index c93e849..8af3fde 100644
--- a/benchmarks/Election.hs
+++ b/benchmarks/Election.hs
@@ -13,7 +13,7 @@ makeElection nQuests nChoices = Election
{ 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 @@ benchmarks =
| (nQuests,nChoices) <- inputs
]
, bgroup "verifyBallot"
- [ benchVerifyBallot @BeleniosParams nQuests nChoices
+ [ benchVerifyBallot @WeakParams nQuests nChoices
| (nQuests,nChoices) <- inputs
]
]
diff --git a/hjugement-protocol.cabal b/hjugement-protocol.cabal
index c32fa40..cbf673f 100644
--- a/hjugement-protocol.cabal
+++ b/hjugement-protocol.cabal
@@ -2,7 +2,7 @@ name: hjugement-protocol
-- 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 @@ Library
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 @@ Test-Suite hjugement-protocol-test
HUnit.Arithmetic
HUnit.Credential
HUnit.Election
+ HUnit.Trustee
+ HUnit.Trustee.Indispensable
QuickCheck
QuickCheck.Election
QuickCheck.Trustee
diff --git a/src/Voting/Protocol.hs b/src/Voting/Protocol.hs
index 5263493..6d973c5 100644
--- a/src/Voting/Protocol.hs
+++ b/src/Voting/Protocol.hs
@@ -2,10 +2,12 @@ module Voting.Protocol
( 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
diff --git a/src/Voting/Protocol/Arithmetic.hs b/src/Voting/Protocol/Arithmetic.hs
index 4a6bdeb..a8ff6b4 100644
--- a/src/Voting/Protocol/Arithmetic.hs
+++ b/src/Voting/Protocol/Arithmetic.hs
@@ -206,9 +206,7 @@ groupGenPowers = go one
-- 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
diff --git a/src/Voting/Protocol/Credential.hs b/src/Voting/Protocol/Credential.hs
index 9faae84..39ac87b 100644
--- a/src/Voting/Protocol/Credential.hs
+++ b/src/Voting/Protocol/Credential.hs
@@ -49,10 +49,7 @@ tokenLength ::Int
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 ->
@@ -108,6 +105,9 @@ randomUUID = do
-- ** 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'
-- using 'Crypto.fastPBKDF2_SHA256'.
diff --git a/src/Voting/Protocol/Election.hs b/src/Voting/Protocol/Election.hs
index f4a721f..a9660d8 100644
--- a/src/Voting/Protocol/Election.hs
+++ b/src/Voting/Protocol/Election.hs
@@ -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.Foldable (Foldable, foldMap, and)
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 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
@@ -88,7 +88,8 @@ encrypt pubKey clear = do
}
-- * 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 @@ type Opinion = E
-- 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 ErrorAnswer
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 @@ data Election q = Election
-- ** 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 @@ encryptBallot Election{..} ballotSecKeyMay opinionsByQuest
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 @@ verifyBallot Election{..} Ballot{..} =
(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 @@ data ErrorBallot
-- is different than the number of questions.
| ErrorBallot_Answer ErrorAnswer
-- ^ When 'encryptAnswer' raised an 'ErrorAnswer'.
+ | ErrorBallot_Wrong
+ -- ^ TODO: to be more precise.
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.
- 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
diff --git a/src/Voting/Protocol/Tally.hs b/src/Voting/Protocol/Tally.hs
new file mode 100644
index 0000000..5c709d2
--- /dev/null
+++ b/src/Voting/Protocol/Tally.hs
@@ -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)
diff --git a/src/Voting/Protocol/Trustee.hs b/src/Voting/Protocol/Trustee.hs
new file mode 100644
index 0000000..77e5e1e
--- /dev/null
+++ b/src/Voting/Protocol/Trustee.hs
@@ -0,0 +1,5 @@
+module Voting.Protocol.Trustee
+ ( module Voting.Protocol.Trustee.Indispensable
+ ) where
+
+import Voting.Protocol.Trustee.Indispensable
diff --git a/src/Voting/Protocol/Trustee/Indispensable.hs b/src/Voting/Protocol/Trustee/Indispensable.hs
new file mode 100644
index 0000000..bfa475c
--- /dev/null
+++ b/src/Voting/Protocol/Trustee/Indispensable.hs
@@ -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"
diff --git a/src/Voting/Protocol/Trustees.hs b/src/Voting/Protocol/Trustees.hs
deleted file mode 100644
index eb6bdf3..0000000
--- a/src/Voting/Protocol/Trustees.hs
+++ /dev/null
@@ -1,5 +0,0 @@
-module Voting.Protocol.Trustees
- ( module Voting.Protocol.Trustees.All
- ) where
-
-import Voting.Protocol.Trustees.All
diff --git a/src/Voting/Protocol/Trustees/All.hs b/src/Voting/Protocol/Trustees/All.hs
deleted file mode 100644
index cf94708..0000000
--- a/src/Voting/Protocol/Trustees/All.hs
+++ /dev/null
@@ -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
diff --git a/tests/HUnit.hs b/tests/HUnit.hs
index 8fd7aa6..76f2a48 100644
--- a/tests/HUnit.hs
+++ b/tests/HUnit.hs
@@ -3,6 +3,7 @@ import Test.Tasty
import qualified HUnit.Arithmetic
import qualified HUnit.Credential
import qualified HUnit.Election
+import qualified HUnit.Trustee
hunits :: TestTree
hunits =
@@ -10,4 +11,5 @@ hunits =
[ HUnit.Arithmetic.hunit
, HUnit.Credential.hunit
, HUnit.Election.hunit
+ , HUnit.Trustee.hunit
]
diff --git a/tests/HUnit/Arithmetic.hs b/tests/HUnit/Arithmetic.hs
index 724e701..6a4a304 100644
--- a/tests/HUnit/Arithmetic.hs
+++ b/tests/HUnit/Arithmetic.hs
@@ -3,7 +3,7 @@
module HUnit.Arithmetic where
import Test.Tasty.HUnit
-import Protocol.Arithmetic
+import Voting.Protocol
import Utils
hunit :: TestTree
diff --git a/tests/HUnit/Credential.hs b/tests/HUnit/Credential.hs
index 0b63b55..3e358f8 100644
--- a/tests/HUnit/Credential.hs
+++ b/tests/HUnit/Credential.hs
@@ -7,8 +7,7 @@ import Test.Tasty.HUnit
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
diff --git a/tests/HUnit/Election.hs b/tests/HUnit/Election.hs
index 9473d82..465f910 100644
--- a/tests/HUnit/Election.hs
+++ b/tests/HUnit/Election.hs
@@ -8,10 +8,7 @@ import Test.Tasty.HUnit
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 @@ hunit = testGroup "Election"
[ testsEncryptBallot @WeakParams
, testsEncryptBallot @BeleniosParams
]
- , testGroup "trustee" $
- [ testsTrustee @WeakParams
- ]
]
testsEncryptBallot :: forall q. Params q => TestTree
@@ -84,17 +78,17 @@ testEncryptBallot ::
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 @@ testEncryptBallot seed quests opins exp =
<$> 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
diff --git a/tests/HUnit/Trustee.hs b/tests/HUnit/Trustee.hs
new file mode 100644
index 0000000..212ea2e
--- /dev/null
+++ b/tests/HUnit/Trustee.hs
@@ -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
+ ]
diff --git a/tests/HUnit/Trustee/Indispensable.hs b/tests/HUnit/Trustee/Indispensable.hs
new file mode 100644
index 0000000..3de29c3
--- /dev/null
+++ b/tests/HUnit/Trustee/Indispensable.hs
@@ -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
+
diff --git a/tests/QuickCheck/Election.hs b/tests/QuickCheck/Election.hs
index fcfc20a..9ea92d8 100644
--- a/tests/QuickCheck/Election.hs
+++ b/tests/QuickCheck/Election.hs
@@ -10,9 +10,7 @@ import Data.Int (Int)
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 @@ quickcheck =
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 SubGroup q => Arbitrary (E q) where
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 @@ instance SubGroup q => Arbitrary (Election q) where
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 @@ boolsOfCombin nBits nTrue rank
-- 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]
diff --git a/tests/QuickCheck/Trustee.hs b/tests/QuickCheck/Trustee.hs
index dd03439..82cfe14 100644
--- a/tests/QuickCheck/Trustee.hs
+++ b/tests/QuickCheck/Trustee.hs
@@ -3,9 +3,8 @@ module QuickCheck.Trustee where
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 @@ import QuickCheck.Election ()
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
diff --git a/tests/Utils.hs b/tests/Utils.hs
index 09070e9..dc7bc66 100644
--- a/tests/Utils.hs
+++ b/tests/Utils.hs
@@ -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 @@ module Utils
, ExceptT
, runExcept
, throwE
- , StateT
+ , StateT(..)
, evalStateT
+ , modify'
, mkStdGen
, debug
, nCk
@@ -52,6 +54,8 @@ import System.Random (mkStdGen)
import Test.Tasty
import Text.Show (Show(..))
+import Voting.Protocol.Utils
+
debug msg x = trace (msg<>": "<>show x) x
-- | @'nCk' n k@ returns the number of combinations