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 +2/−2
- hjugement-protocol.cabal +6/−3
- src/Voting/Protocol.hs +4/−2
- src/Voting/Protocol/Arithmetic.hs +1/−3
- src/Voting/Protocol/Credential.hs +4/−4
- src/Voting/Protocol/Election.hs +16/−135
- src/Voting/Protocol/Tally.hs +187/−0
- src/Voting/Protocol/Trustee.hs +5/−0
- src/Voting/Protocol/Trustee/Indispensable.hs +106/−0
- src/Voting/Protocol/Trustees.hs +0/−5
- src/Voting/Protocol/Trustees/All.hs +0/−92
- tests/HUnit.hs +2/−0
- tests/HUnit/Arithmetic.hs +1/−1
- tests/HUnit/Credential.hs +1/−2
- tests/HUnit/Election.hs +5/−31
- tests/HUnit/Trustee.hs +9/−0
- tests/HUnit/Trustee/Indispensable.hs +103/−0
- tests/QuickCheck/Election.hs +6/−8
- tests/QuickCheck/Trustee.hs +10/−11
- tests/Utils.hs +6/−2
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