packages feed

hjugement-protocol-0.0.9.20191031: benchmarks/Election.hs

{-# LANGUAGE OverloadedStrings #-}
module Election where

import Control.DeepSeq (NFData)
import qualified Data.List as List
import qualified Data.Text as Text
import qualified Text.Printf as Printf
import qualified Data.Aeson as JSON

import Voting.Protocol
import Utils

makeElection ::
 forall crypto v c.
 Reifies v Version =>
 GroupParams crypto c =>
 Key crypto =>
 JSON.ToJSON crypto =>
 Int -> Int -> Election crypto v c
makeElection nQuests nChoices = elec
	where
	election_uuid = UUID "xLcs7ev6Jy6FHH"
	elec = Election
	 { election_name = Text.pack $ "elec"<>show nQuests<>show nChoices
	 , election_description = "benchmarkable election"
	 , election_uuid
	 , election_crypto = reflect (Proxy @c)
	 , election_public_key =
		let secKey = credentialSecretKey election_uuid (Credential "xLcs7ev6Jy6FHHE") in
		publicKey secKey
	 , election_hash = hashElection elec
	 , election_version = Just (reflect (Proxy @v))
	 , election_questions =
		(<$> [1..nQuests]) $ \quest -> Question
		 { question_text = Text.pack $ "quest"<>show quest
		 , question_choices = (<$> [1..nChoices]) $ \choice -> Text.pack $ "choice"<>show choice
		 , question_mini = one
		 , question_maxi = one -- sum $ List.replicate nChoices one
		 }
	 }

makeVotes :: Election crypto v c -> [[Bool]]
makeVotes Election{..} =
	[ True : List.tail [ False | _choice <- question_choices quest ]
	| quest <- election_questions
	]

makeBallot ::
 Reifies v Version =>
 GroupParams crypto c => Key crypto =>
 Election crypto v c -> Ballot crypto v c
makeBallot elec =
	case runExcept $ (`evalStateT` mkStdGen seed) $ do
		ballotSecKey <- randomSecretKey
		encryptBallot elec (Just ballotSecKey) $
			makeVotes elec of
	 Right ballot -> ballot
	 Left err -> error ("encryptBallot: "<>show err)
	where
	seed = 0

titleElection :: Election crypto v c -> String
titleElection Election{..} =
	Printf.printf "(questions=%i)×(choices=%i)==%i"
	 nQuests nChoices (nQuests * nChoices)
	where
	nQuests  = List.length election_questions
	nChoices = List.foldr max 0 $ List.length . question_choices <$> election_questions

benchEncryptBallot ::
 forall crypto v c.
 GroupParams crypto c =>
 Reifies v Version =>
 Key crypto =>
 JSON.ToJSON crypto =>
 NFData crypto =>
 Proxy v -> Proxy c -> Int -> Int -> Benchmark
benchEncryptBallot _v _c nQuests nChoices =
	let setupEnv = do
		let elec :: Election crypto v c = makeElection nQuests nChoices
		return elec in
	env setupEnv $ \ ~(elec) ->
		bench (titleElection elec) $
			nf makeBallot elec

benchVerifyBallot ::
 forall crypto v c.
 Reifies v Version =>
 GroupParams crypto c =>
 Key crypto =>
 JSON.ToJSON crypto =>
 NFData crypto =>
 Proxy v -> Proxy c -> Int -> Int -> Benchmark
benchVerifyBallot (_v::Proxy v) (_c::Proxy c) nQuests nChoices =
	let setupEnv = do
		let elec :: Election crypto v c = makeElection nQuests nChoices
		let ballot = makeBallot elec
		return (elec,ballot) in
	env setupEnv $ \ ~(elec, ballot) ->
		bench (titleElection elec) $
			nf (verifyBallot elec) ballot

benchmarks :: [Benchmark]
benchmarks =
 [ benchsByVersion stableVersion
 -- , benchsByVersion experimentalVersion
 ]

benchsByVersion :: Version -> Benchmark
benchsByVersion version =
	reify version $ \v ->
	bgroup ("v"<>show version)
		[ benchsByCrypto v weakFFC
		, benchsByCrypto v beleniosFFC
		]

benchsByCrypto ::
 Reifies v Version =>
 ReifyCrypto crypto =>
 Key crypto =>
 JSON.ToJSON crypto =>
 NFData crypto =>
 Proxy v -> crypto -> Benchmark
benchsByCrypto v crypto =
	reifyCrypto crypto $ \c ->
	bgroup (Text.unpack (cryptoName crypto))
	 [ bgroup "encryptBallot"
		 [ benchEncryptBallot v c nQuests nChoices
		 | (nQuests,nChoices) <- inputs
		 ]
	 , bgroup "verifyBallot"
		 [ benchVerifyBallot v c nQuests nChoices
		 | (nQuests,nChoices) <- inputs
		 ]
	 ]
	where
	inputs =
		[ (nQ,nC)
		| nQ <- [1,5,10,15,20,25]
		, nC <- [5,7]
		]