import Data.Functor ((<$>))
import Data.Maybe (maybe)
import Data.Semigroup (Semigroup(..))
-import Data.Text (Text)
-import Data.Tuple (fst, uncurry)
+import Data.Tuple (fst)
import GHC.Generics (Generic)
import Numeric.Natural (Natural)
import Prelude (fromIntegral)
} deriving (Eq,Show,Generic,NFData)
-- ** Type 'EncryptedTally'
--- | 'Encryption' by 'Choice' by 'Question'.
+-- | 'Encryption' by choice by 'Question'.
type EncryptedTally q = [[Encryption q]]
-- | @('encryptedTally' ballots)@
List.zipWith (\Answer{..} ->
List.zipWith (+)
(fst <$> answer_opinions))
- ballot_answers
- )
+ ballot_answers)
(List.repeat (List.repeat zero))
ballots
, fromIntegral $ List.length ballots
-- ** Type 'DecryptionShareCombinator'
type DecryptionShareCombinator q =
- [DecryptionShare q] -> Except ErrorDecryptionShare [[DecryptionFactor q]]
+ EncryptedTally q -> [DecryptionShare q] -> Except ErrorTally [[DecryptionFactor q]]
proveTally ::
SubGroup q =>
(EncryptedTally q, Natural) -> [DecryptionShare q] ->
DecryptionShareCombinator q ->
- Except ErrorDecryptionShare (Tally q)
+ Except ErrorTally (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)
+ decFactorByChoiceByQuest <- decShareCombinator tally_encByChoiceByQuest tally_decShareByTrustee
+ dec <- isoZipWithM (throwE ErrorTally_NumberOfQuestions)
+ (maybe (throwE ErrorTally_NumberOfChoices) return `o2`
+ isoZipWith (\Encryption{..} decFactor -> encryption_vault / decFactor))
tally_encByChoiceByQuest
decFactorByChoiceByQuest
let logMap = Map.fromList $ List.zip groupGenPowers [0..tally_countMax]
let log x =
- maybe (throwE $ ErrorDecryptionShare_InvalidMaxCount) return $
+ maybe (throwE ErrorTally_CannotDecryptCount) 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 ()
+ Except ErrorTally ()
verifyTally Tally{..} decShareCombinator = do
- decFactorByChoiceByQuest <- decShareCombinator tally_decShareByTrustee
- isoZipWith3M_ (throwE $ ErrorDecryptionShare_Invalid "verifyTally")
- (isoZipWith3M_ (throwE $ ErrorDecryptionShare_Invalid "verifyTally")
+ decFactorByChoiceByQuest <- decShareCombinator tally_encByChoiceByQuest tally_decShareByTrustee
+ isoZipWith3M_ (throwE ErrorTally_NumberOfQuestions)
+ (isoZipWith3M_ (throwE ErrorTally_NumberOfChoices)
(\Encryption{..} decFactor count -> do
let groupGenPowCount = encryption_vault / decFactor
unless (groupGenPowCount == groupGen ^ fromNatural count) $
- throwE ErrorDecryptionShare_Wrong))
+ throwE ErrorTally_WrongProof))
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)
+-- | A decryption share is a 'DecryptionFactor' and a decryption 'Proof', by choice by 'Question'.
+-- Computed by a trustee in 'proveDecryptionShare'.
+type DecryptionShare q = [[(DecryptionFactor q, Proof q)]]
-- *** Type 'DecryptionFactor'
-- | @'encryption_nonce' '^'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)
+proveDecryptionShare encByChoiceByQuest trusteeSecKey =
+ (proveDecryptionFactor trusteeSecKey `mapM`) `mapM` encByChoiceByQuest
proveDecryptionFactor ::
Monad m => SubGroup q => RandomGen r =>
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
+-- *** Type 'ErrorTally'
+data ErrorTally
+ = ErrorTally_NumberOfQuestions
+ -- ^ The number of 'Question's is not the one expected.
+ | ErrorTally_NumberOfChoices
+ -- ^ The number of choices is not the one expected.
+ | ErrorTally_NumberOfTrustees
+ -- ^ The number of trustees is not the one expected.
+ | ErrorTally_WrongProof
-- ^ The 'Proof' of a 'DecryptionFactor' is wrong.
- | ErrorDecryptionShare_InvalidMaxCount
+ | ErrorTally_CannotDecryptCount
+ -- ^ Raised by 'proveTally' when the discrete logarithm of @'groupGen' '^'count@
+ -- cannot be computed, likely because 'tally_countMax' is wrong,
+ -- or because the 'EncryptedTally' or 'DecryptionShare's have not been verified.
deriving (Eq,Show,Generic,NFData)
-- | @('verifyDecryptionShare' encTally trusteePubKey trusteeDecShare)@
verifyDecryptionShare ::
Monad m => SubGroup q =>
EncryptedTally q -> PublicKey q -> DecryptionShare q ->
- ExceptT ErrorDecryptionShare m ()
-verifyDecryptionShare encTally trusteePubKey DecryptionShare{..} =
+ ExceptT ErrorTally m ()
+verifyDecryptionShare encByChoiceByQuest trusteePubKey =
let zkp = decryptionShareStatement trusteePubKey in
- isoZipWith3M_ (throwE $ ErrorDecryptionShare_Invalid "verifyDecryptionShare")
- (isoZipWith3M_ (throwE $ ErrorDecryptionShare_Invalid "verifyDecryptionShare") $
- \Encryption{..} decFactor proof ->
+ isoZipWithM_ (throwE ErrorTally_NumberOfQuestions)
+ (isoZipWithM_ (throwE ErrorTally_NumberOfChoices) $
+ \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
+ ]) $ throwE ErrorTally_WrongProof)
+ encByChoiceByQuest
verifyDecryptionShareByTrustee ::
Monad m => SubGroup q =>
EncryptedTally q -> [PublicKey q] -> [DecryptionShare q] ->
- ExceptT ErrorDecryptionShare m ()
+ ExceptT ErrorTally m ()
verifyDecryptionShareByTrustee encTally =
- isoZipWithM_ (throwE $ ErrorDecryptionShare_Invalid "verifyDecryptionShare")
+ isoZipWithM_ (throwE ErrorTally_NumberOfTrustees)
(verifyDecryptionShare encTally)
import Control.Monad.Trans.Except (ExceptT(..), throwE)
import Data.Eq (Eq(..))
import Data.Function (($))
+import Data.Functor ((<$>))
import Data.Maybe (maybe)
import Data.Semigroup (Semigroup(..))
+import Data.Tuple (fst)
import Text.Show (Show(..))
import qualified Control.Monad.Trans.State.Strict as S
import qualified Data.ByteString as BS
-- ** Type 'ErrorTrusteePublicKey'
data ErrorTrusteePublicKey
- = ErrorTrusteePublicKey_Wrong
+ = ErrorTrusteePublicKey_WrongProof
-- ^ The 'trustee_SecretKeyProof' is wrong.
deriving (Eq,Show)
hash
(indispensableTrusteePublicKeyStatement trustee_PublicKey)
[commit trustee_SecretKeyProof groupGen trustee_PublicKey]) $
- throwE ErrorTrusteePublicKey_Wrong
+ throwE ErrorTrusteePublicKey_WrongProof
-- ** Hashing
indispensableTrusteePublicKeyStatement :: PublicKey q -> BS.ByteString
verifyIndispensableDecryptionShareByTrustee ::
SubGroup q => Monad m =>
EncryptedTally q -> [PublicKey q] -> [DecryptionShare q] ->
- ExceptT ErrorDecryptionShare m ()
-verifyIndispensableDecryptionShareByTrustee encTally =
- isoZipWithM_ (throwE $ ErrorDecryptionShare_Invalid "verifyIndispensableDecryptionShareByTrustee")
- (verifyDecryptionShare encTally)
+ ExceptT ErrorTally m ()
+verifyIndispensableDecryptionShareByTrustee encByChoiceByQuest =
+ isoZipWithM_ (throwE $ ErrorTally_NumberOfTrustees)
+ (verifyDecryptionShare encByChoiceByQuest)
-- | @('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"
+combineIndispensableDecryptionShares :: SubGroup q => [PublicKey q] -> DecryptionShareCombinator q
+combineIndispensableDecryptionShares pubKeyByTrustee encByChoiceByQuest decByChoiceByQuestByTrustee = do
+ verifyIndispensableDecryptionShareByTrustee encByChoiceByQuest pubKeyByTrustee decByChoiceByQuestByTrustee
+ (dec0,decs) <-
+ maybe (throwE ErrorTally_NumberOfTrustees) return $
+ List.uncons decByChoiceByQuestByTrustee
+ foldM (isoZipWithM (throwE ErrorTally_NumberOfQuestions)
+ (maybe (throwE ErrorTally_NumberOfChoices) return `o2`
+ isoZipWith (\a (decFactor, _proof) -> a * decFactor)))
+ ((fst <$>) <$> dec0) decs