hjugement-protocol 0.0.0.20190513 → 0.0.0.20190519
raw patch · 21 files changed
+1004/−767 lines, 21 filesdep +aesondep +base64-bytestringdep +binaryPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: aeson, base64-bytestring, binary, reflection
API changes (from Hackage documentation)
- Voting.Protocol.Arithmetic: (*) :: Multiplicative a => a -> a -> a
- Voting.Protocol.Arithmetic: (+) :: Additive a => a -> a -> a
- Voting.Protocol.Arithmetic: (-) :: Negable a => a -> a -> a
- Voting.Protocol.Arithmetic: (/) :: Invertible a => a -> a -> a
- Voting.Protocol.Arithmetic: (^) :: SubGroup q => G q -> E q -> G q
- Voting.Protocol.Arithmetic: -- q</tt>.
- Voting.Protocol.Arithmetic: -- | Setting <tt>q</tt> determines <tt>p</tt>, equals to <tt><a>P</a>
- Voting.Protocol.Arithmetic: E :: F (P q) -> E q
- Voting.Protocol.Arithmetic: F :: Natural -> F p
- Voting.Protocol.Arithmetic: G :: F (P q) -> G q
- Voting.Protocol.Arithmetic: [unE] :: E q -> F (P q)
- Voting.Protocol.Arithmetic: [unF] :: F p -> Natural
- Voting.Protocol.Arithmetic: [unG] :: G q -> F (P q)
- Voting.Protocol.Arithmetic: bytesNat :: ToNatural n => n -> ByteString
- Voting.Protocol.Arithmetic: class Additive a
- Voting.Protocol.Arithmetic: class FromNatural a
- Voting.Protocol.Arithmetic: class Multiplicative a => Invertible a
- Voting.Protocol.Arithmetic: class Multiplicative a
- Voting.Protocol.Arithmetic: class Additive a => Negable a
- Voting.Protocol.Arithmetic: class SubGroup q => Params q
- Voting.Protocol.Arithmetic: class PrimeField p
- Voting.Protocol.Arithmetic: class RandomGen g
- Voting.Protocol.Arithmetic: class (PrimeField (P q), Multiplicative (F (P q))) => SubGroup q where {
- Voting.Protocol.Arithmetic: class ToNatural a
- Voting.Protocol.Arithmetic: data BeleniosParams
- Voting.Protocol.Arithmetic: data Natural
- Voting.Protocol.Arithmetic: data WeakParams
- Voting.Protocol.Arithmetic: fieldCharac :: PrimeField p => Natural
- Voting.Protocol.Arithmetic: fromNatural :: FromNatural a => Natural -> a
- Voting.Protocol.Arithmetic: groupGen :: SubGroup q => G q
- Voting.Protocol.Arithmetic: groupGenInverses :: SubGroup q => [G q]
- Voting.Protocol.Arithmetic: groupGenPowers :: SubGroup q => [G q]
- Voting.Protocol.Arithmetic: groupOrder :: SubGroup q => F (P q)
- Voting.Protocol.Arithmetic: hash :: SubGroup q => ByteString -> [G q] -> E q
- Voting.Protocol.Arithmetic: infixl 6 +
- Voting.Protocol.Arithmetic: infixl 7 *
- Voting.Protocol.Arithmetic: infixr 8 ^
- Voting.Protocol.Arithmetic: instance (Voting.Protocol.Arithmetic.SubGroup q, Voting.Protocol.Arithmetic.Additive (Voting.Protocol.Arithmetic.F (Voting.Protocol.Arithmetic.P q))) => Voting.Protocol.Arithmetic.Additive (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance (Voting.Protocol.Arithmetic.SubGroup q, Voting.Protocol.Arithmetic.Multiplicative (Voting.Protocol.Arithmetic.F (Voting.Protocol.Arithmetic.P q))) => Voting.Protocol.Arithmetic.Invertible (Voting.Protocol.Arithmetic.G q)
- Voting.Protocol.Arithmetic: instance (Voting.Protocol.Arithmetic.SubGroup q, Voting.Protocol.Arithmetic.Multiplicative (Voting.Protocol.Arithmetic.F (Voting.Protocol.Arithmetic.P q))) => Voting.Protocol.Arithmetic.Multiplicative (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance (Voting.Protocol.Arithmetic.SubGroup q, Voting.Protocol.Arithmetic.Multiplicative (Voting.Protocol.Arithmetic.F (Voting.Protocol.Arithmetic.P q))) => Voting.Protocol.Arithmetic.Multiplicative (Voting.Protocol.Arithmetic.G q)
- Voting.Protocol.Arithmetic: instance (Voting.Protocol.Arithmetic.SubGroup q, Voting.Protocol.Arithmetic.Negable (Voting.Protocol.Arithmetic.F (Voting.Protocol.Arithmetic.P q))) => Voting.Protocol.Arithmetic.Negable (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance Control.DeepSeq.NFData (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance Control.DeepSeq.NFData (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance Control.DeepSeq.NFData (Voting.Protocol.Arithmetic.G q)
- Voting.Protocol.Arithmetic: instance GHC.Classes.Eq (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance GHC.Classes.Eq (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance GHC.Classes.Eq (Voting.Protocol.Arithmetic.G q)
- Voting.Protocol.Arithmetic: instance GHC.Classes.Ord (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance GHC.Classes.Ord (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance GHC.Classes.Ord (Voting.Protocol.Arithmetic.G q)
- Voting.Protocol.Arithmetic: instance GHC.Show.Show (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance GHC.Show.Show (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance GHC.Show.Show (Voting.Protocol.Arithmetic.G q)
- Voting.Protocol.Arithmetic: instance System.Random.Random GHC.Natural.Natural
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Additive GHC.Integer.Type.Integer
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Additive GHC.Natural.Natural
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Additive GHC.Types.Int
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Multiplicative GHC.Integer.Type.Integer
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Multiplicative GHC.Natural.Natural
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Multiplicative GHC.Types.Int
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Negable GHC.Integer.Type.Integer
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Negable GHC.Types.Int
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Params Voting.Protocol.Arithmetic.BeleniosParams
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.Params Voting.Protocol.Arithmetic.WeakParams
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.PrimeField (Voting.Protocol.Arithmetic.P q) => Voting.Protocol.Arithmetic.FromNatural (Voting.Protocol.Arithmetic.G q)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.PrimeField Voting.Protocol.Arithmetic.BeleniosParams
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.PrimeField Voting.Protocol.Arithmetic.WeakParams
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.PrimeField p => System.Random.Random (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.PrimeField p => Voting.Protocol.Arithmetic.Additive (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.PrimeField p => Voting.Protocol.Arithmetic.FromNatural (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.PrimeField p => Voting.Protocol.Arithmetic.Multiplicative (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.PrimeField p => Voting.Protocol.Arithmetic.Negable (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.SubGroup Voting.Protocol.Arithmetic.BeleniosParams
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.SubGroup Voting.Protocol.Arithmetic.WeakParams
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.SubGroup q => GHC.Enum.Enum (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.SubGroup q => System.Random.Random (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.SubGroup q => Voting.Protocol.Arithmetic.FromNatural (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.ToNatural (Voting.Protocol.Arithmetic.E q)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.ToNatural (Voting.Protocol.Arithmetic.F p)
- Voting.Protocol.Arithmetic: instance Voting.Protocol.Arithmetic.ToNatural (Voting.Protocol.Arithmetic.G q)
- Voting.Protocol.Arithmetic: inv :: Invertible a => a -> a
- Voting.Protocol.Arithmetic: nat :: ToNatural a => a -> Natural
- Voting.Protocol.Arithmetic: neg :: Negable a => a -> a
- Voting.Protocol.Arithmetic: newtype E q
- Voting.Protocol.Arithmetic: newtype F p
- Voting.Protocol.Arithmetic: newtype G q
- Voting.Protocol.Arithmetic: one :: Multiplicative a => a
- Voting.Protocol.Arithmetic: paramsName :: Params q => String
- Voting.Protocol.Arithmetic: random :: Monad m => RandomGen r => Random i => Negable i => Multiplicative i => StateT r m i
- Voting.Protocol.Arithmetic: randomR :: Monad m => RandomGen r => Random i => Negable i => Multiplicative i => i -> StateT r m i
- Voting.Protocol.Arithmetic: sum :: (Additive a, Foldable f) => f a -> a
- Voting.Protocol.Arithmetic: type family P q :: *;
- Voting.Protocol.Arithmetic: zero :: Additive a => a
- Voting.Protocol.Arithmetic: }
- Voting.Protocol.Credential: CredentialError_BadChar :: Char -> CredentialError
- Voting.Protocol.Credential: CredentialError_Checksum :: CredentialError
- Voting.Protocol.Credential: CredentialError_Length :: CredentialError
- Voting.Protocol.Credential: data CredentialError
- Voting.Protocol.Credential: instance Control.DeepSeq.NFData Voting.Protocol.Credential.CredentialError
- Voting.Protocol.Credential: instance GHC.Classes.Eq Voting.Protocol.Credential.CredentialError
- Voting.Protocol.Credential: instance GHC.Generics.Generic Voting.Protocol.Credential.CredentialError
- Voting.Protocol.Credential: instance GHC.Show.Show Voting.Protocol.Credential.CredentialError
- Voting.Protocol.Election: [election_PublicKey] :: Election q -> PublicKey q
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Answer q)
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Ballot q)
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.DisjProof q)
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Election q)
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Encryption q)
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Proof q)
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Question q)
- Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Signature q)
- Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Answer q)
- Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.DisjProof q)
- Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Election q)
- Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Encryption q)
- Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Proof q)
- Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Question q)
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Answer q)
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Ballot q)
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.DisjProof q)
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Election q)
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Encryption q)
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Proof q)
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Question q)
- Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Signature q)
- Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Answer q)
- Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.DisjProof q)
- Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Election q)
- Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Encryption q)
- Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Proof q)
- Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Question q)
- Voting.Protocol.Election: instance Voting.Protocol.Arithmetic.SubGroup q => Voting.Protocol.Arithmetic.Additive (Voting.Protocol.Election.Encryption 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: [decryptionShare_factors] :: DecryptionShare q -> [[DecryptionFactor q]]
- Voting.Protocol.Tally: [decryptionShare_proofs] :: DecryptionShare q -> [[Proof q]]
- Voting.Protocol.Tally: data DecryptionShare q
- Voting.Protocol.Tally: data ErrorDecryptionShare
- 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.Trustee.Indispensable: ErrorTrusteePublicKey_Wrong :: ErrorTrusteePublicKey
- Voting.Protocol.Trustee.Indispensable: instance GHC.Classes.Eq (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey q)
- Voting.Protocol.Trustee.Indispensable: instance GHC.Show.Show (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey q)
+ Voting.Protocol.Credential: ErrorToken_BadChar :: Char -> ErrorToken
+ Voting.Protocol.Credential: ErrorToken_Checksum :: ErrorToken
+ Voting.Protocol.Credential: ErrorToken_Length :: ErrorToken
+ Voting.Protocol.Credential: data ErrorToken
+ Voting.Protocol.Credential: instance Control.DeepSeq.NFData Voting.Protocol.Credential.ErrorToken
+ Voting.Protocol.Credential: instance Data.Aeson.Types.FromJSON.FromJSON Voting.Protocol.Credential.Credential
+ Voting.Protocol.Credential: instance Data.Aeson.Types.FromJSON.FromJSON Voting.Protocol.Credential.UUID
+ Voting.Protocol.Credential: instance Data.Aeson.Types.ToJSON.ToJSON Voting.Protocol.Credential.Credential
+ Voting.Protocol.Credential: instance Data.Aeson.Types.ToJSON.ToJSON Voting.Protocol.Credential.UUID
+ Voting.Protocol.Credential: instance GHC.Classes.Eq Voting.Protocol.Credential.ErrorToken
+ Voting.Protocol.Credential: instance GHC.Generics.Generic Voting.Protocol.Credential.ErrorToken
+ Voting.Protocol.Credential: instance GHC.Show.Show Voting.Protocol.Credential.ErrorToken
+ Voting.Protocol.Credential: readUUID :: Text -> Either ErrorToken UUID
+ Voting.Protocol.Election: ElectionCrypto_FFC :: !FFC -> !PublicKey c -> ElectionCrypto c
+ Voting.Protocol.Election: [electionCrypto_FFC_PublicKey] :: ElectionCrypto c -> !PublicKey c
+ Voting.Protocol.Election: [electionCrypto_FFC_params] :: ElectionCrypto c -> !FFC
+ Voting.Protocol.Election: [election_crypto] :: Election c -> !ElectionCrypto c
+ Voting.Protocol.Election: data ElectionCrypto c
+ Voting.Protocol.Election: hashElection :: Election c -> Election c
+ Voting.Protocol.Election: hashJSON :: ToJSON a => a -> Hash
+ Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Answer c)
+ Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Ballot c)
+ Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.DisjProof c)
+ Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Election c)
+ Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.ElectionCrypto c)
+ Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Encryption c)
+ Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Proof c)
+ Voting.Protocol.Election: instance Control.DeepSeq.NFData (Voting.Protocol.Election.Signature c)
+ Voting.Protocol.Election: instance Control.DeepSeq.NFData Voting.Protocol.Election.Question
+ Voting.Protocol.Election: instance Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Election.Election c)
+ Voting.Protocol.Election: instance Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Election.ElectionCrypto c)
+ Voting.Protocol.Election: instance Data.Aeson.Types.FromJSON.FromJSON Voting.Protocol.Election.Hash
+ Voting.Protocol.Election: instance Data.Aeson.Types.FromJSON.FromJSON Voting.Protocol.Election.Question
+ Voting.Protocol.Election: instance Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Election.Election c)
+ Voting.Protocol.Election: instance Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Election.ElectionCrypto c)
+ Voting.Protocol.Election: instance Data.Aeson.Types.ToJSON.ToJSON Voting.Protocol.Election.Hash
+ Voting.Protocol.Election: instance Data.Aeson.Types.ToJSON.ToJSON Voting.Protocol.Election.Question
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Election.Answer c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Election.Ballot c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Election.DisjProof c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Election.Encryption c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Election.Proof c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Election.Signature c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Election.Answer c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Election.Ballot c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Election.DisjProof c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Election.Encryption c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Election.Proof c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Election.Signature c)
+ Voting.Protocol.Election: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.Additive (Voting.Protocol.Election.Encryption c)
+ Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Answer c)
+ Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.DisjProof c)
+ Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Election c)
+ Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.ElectionCrypto c)
+ Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Encryption c)
+ Voting.Protocol.Election: instance GHC.Classes.Eq (Voting.Protocol.Election.Proof c)
+ Voting.Protocol.Election: instance GHC.Classes.Eq Voting.Protocol.Election.Question
+ Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Answer c)
+ Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Ballot c)
+ Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.DisjProof c)
+ Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Election c)
+ Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.ElectionCrypto c)
+ Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Encryption c)
+ Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Proof c)
+ Voting.Protocol.Election: instance GHC.Generics.Generic (Voting.Protocol.Election.Signature c)
+ Voting.Protocol.Election: instance GHC.Generics.Generic Voting.Protocol.Election.Question
+ Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Answer c)
+ Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.DisjProof c)
+ Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Election c)
+ Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.ElectionCrypto c)
+ Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Encryption c)
+ Voting.Protocol.Election: instance GHC.Show.Show (Voting.Protocol.Election.Proof c)
+ Voting.Protocol.Election: instance GHC.Show.Show Voting.Protocol.Election.Question
+ Voting.Protocol.Election: reifyElection :: Election () -> (forall c. Reifies c FFC => Election c -> k) -> k
+ Voting.Protocol.FFC: (*) :: Multiplicative a => a -> a -> a
+ Voting.Protocol.FFC: (+) :: Additive a => a -> a -> a
+ Voting.Protocol.FFC: (-) :: Negable a => a -> a -> a
+ Voting.Protocol.FFC: (/) :: Invertible a => a -> a -> a
+ Voting.Protocol.FFC: (^) :: Reifies c FFC => G c -> E c -> G c
+ Voting.Protocol.FFC: E :: Natural -> E c
+ Voting.Protocol.FFC: F :: Natural -> F c
+ Voting.Protocol.FFC: FFC :: Text -> !Natural -> !Natural -> !Natural -> FFC
+ Voting.Protocol.FFC: G :: F c -> G c
+ Voting.Protocol.FFC: Proxy :: Proxy
+ Voting.Protocol.FFC: [ffc_fieldCharac] :: FFC -> !Natural
+ Voting.Protocol.FFC: [ffc_groupGen] :: FFC -> !Natural
+ Voting.Protocol.FFC: [ffc_groupOrder] :: FFC -> !Natural
+ Voting.Protocol.FFC: [ffc_name] :: FFC -> Text
+ Voting.Protocol.FFC: [unE] :: E c -> Natural
+ Voting.Protocol.FFC: [unF] :: F c -> Natural
+ Voting.Protocol.FFC: [unG] :: G c -> F c
+ Voting.Protocol.FFC: beleniosFFC :: FFC
+ Voting.Protocol.FFC: bytesNat :: ToNatural n => n -> ByteString
+ Voting.Protocol.FFC: class Additive a
+ Voting.Protocol.FFC: class FromNatural a
+ Voting.Protocol.FFC: class Multiplicative a => Invertible a
+ Voting.Protocol.FFC: class Multiplicative a
+ Voting.Protocol.FFC: class Additive a => Negable a
+ Voting.Protocol.FFC: class RandomGen g
+ Voting.Protocol.FFC: class Reifies (s :: k) a | s -> a
+ Voting.Protocol.FFC: class ToNatural a
+ Voting.Protocol.FFC: data FFC
+ Voting.Protocol.FFC: data Natural
+ Voting.Protocol.FFC: data Proxy (t :: k) :: forall k. () => k -> Type
+ Voting.Protocol.FFC: fieldCharac :: forall c. Reifies c FFC => Natural
+ Voting.Protocol.FFC: fromNatural :: FromNatural a => Natural -> a
+ Voting.Protocol.FFC: groupGen :: forall c. Reifies c FFC => G c
+ Voting.Protocol.FFC: groupGenInverses :: forall c. Reifies c FFC => [G c]
+ Voting.Protocol.FFC: groupGenPowers :: forall c. Reifies c FFC => [G c]
+ Voting.Protocol.FFC: groupOrder :: forall c. Reifies c FFC => Natural
+ Voting.Protocol.FFC: hash :: Reifies c FFC => ByteString -> [G c] -> E c
+ Voting.Protocol.FFC: infixl 6 +
+ Voting.Protocol.FFC: infixl 7 *
+ Voting.Protocol.FFC: infixr 8 ^
+ Voting.Protocol.FFC: instance Control.DeepSeq.NFData (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Control.DeepSeq.NFData (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance Control.DeepSeq.NFData (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance Control.DeepSeq.NFData Voting.Protocol.FFC.FFC
+ Voting.Protocol.FFC: instance Data.Aeson.Types.FromJSON.FromJSON Voting.Protocol.FFC.FFC
+ Voting.Protocol.FFC: instance Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance Data.Aeson.Types.ToJSON.ToJSON Voting.Protocol.FFC.FFC
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => GHC.Enum.Enum (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => System.Random.Random (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => System.Random.Random (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.Additive (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.Additive (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.FromNatural (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.FromNatural (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.FromNatural (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.Invertible (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.Multiplicative (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.Multiplicative (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.Multiplicative (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.Negable (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Voting.Protocol.FFC.Negable (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance GHC.Classes.Eq (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance GHC.Classes.Eq (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance GHC.Classes.Eq (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance GHC.Classes.Eq Voting.Protocol.FFC.FFC
+ Voting.Protocol.FFC: instance GHC.Classes.Ord (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance GHC.Classes.Ord (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance GHC.Classes.Ord (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance GHC.Generics.Generic Voting.Protocol.FFC.FFC
+ Voting.Protocol.FFC: instance GHC.Show.Show (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance GHC.Show.Show (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance GHC.Show.Show (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance GHC.Show.Show Voting.Protocol.FFC.FFC
+ Voting.Protocol.FFC: instance System.Random.Random GHC.Natural.Natural
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.Additive GHC.Integer.Type.Integer
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.Additive GHC.Natural.Natural
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.Additive GHC.Types.Int
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.Multiplicative GHC.Integer.Type.Integer
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.Multiplicative GHC.Natural.Natural
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.Multiplicative GHC.Types.Int
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.Negable GHC.Integer.Type.Integer
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.Negable GHC.Types.Int
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.ToNatural (Voting.Protocol.FFC.E c)
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.ToNatural (Voting.Protocol.FFC.F c)
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.ToNatural (Voting.Protocol.FFC.G c)
+ Voting.Protocol.FFC: instance Voting.Protocol.FFC.ToNatural GHC.Natural.Natural
+ Voting.Protocol.FFC: inv :: Invertible a => a -> a
+ Voting.Protocol.FFC: nat :: ToNatural a => a -> Natural
+ Voting.Protocol.FFC: neg :: Negable a => a -> a
+ Voting.Protocol.FFC: newtype E c
+ Voting.Protocol.FFC: newtype F c
+ Voting.Protocol.FFC: newtype G c
+ Voting.Protocol.FFC: one :: Multiplicative a => a
+ Voting.Protocol.FFC: random :: Monad m => RandomGen r => Random i => Negable i => Multiplicative i => StateT r m i
+ Voting.Protocol.FFC: randomR :: Monad m => RandomGen r => Random i => Negable i => Multiplicative i => i -> StateT r m i
+ Voting.Protocol.FFC: reflect :: Reifies s a => proxy s -> a
+ Voting.Protocol.FFC: reify :: () => a -> (forall s. Reifies s a => Proxy s -> r) -> r
+ Voting.Protocol.FFC: sum :: (Additive a, Foldable f) => f a -> a
+ Voting.Protocol.FFC: weakFFC :: FFC
+ Voting.Protocol.FFC: zero :: Additive a => a
+ Voting.Protocol.Tally: ErrorTally_CannotDecryptCount :: ErrorTally
+ Voting.Protocol.Tally: ErrorTally_NumberOfChoices :: ErrorTally
+ Voting.Protocol.Tally: ErrorTally_NumberOfQuestions :: ErrorTally
+ Voting.Protocol.Tally: ErrorTally_NumberOfTrustees :: ErrorTally
+ Voting.Protocol.Tally: ErrorTally_WrongProof :: ErrorTally
+ Voting.Protocol.Tally: data ErrorTally
+ Voting.Protocol.Tally: instance Control.DeepSeq.NFData (Voting.Protocol.Tally.Tally c)
+ Voting.Protocol.Tally: instance Control.DeepSeq.NFData Voting.Protocol.Tally.ErrorTally
+ Voting.Protocol.Tally: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Tally.Tally c)
+ Voting.Protocol.Tally: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Tally.Tally c)
+ Voting.Protocol.Tally: instance GHC.Classes.Eq (Voting.Protocol.Tally.Tally c)
+ Voting.Protocol.Tally: instance GHC.Classes.Eq Voting.Protocol.Tally.ErrorTally
+ Voting.Protocol.Tally: instance GHC.Generics.Generic (Voting.Protocol.Tally.Tally c)
+ Voting.Protocol.Tally: instance GHC.Generics.Generic Voting.Protocol.Tally.ErrorTally
+ Voting.Protocol.Tally: instance GHC.Show.Show (Voting.Protocol.Tally.Tally c)
+ Voting.Protocol.Tally: instance GHC.Show.Show Voting.Protocol.Tally.ErrorTally
+ Voting.Protocol.Tally: type DecryptionShare c = [[(DecryptionFactor c, Proof c)]]
+ Voting.Protocol.Trustee.Indispensable: ErrorTrusteePublicKey_WrongProof :: ErrorTrusteePublicKey
+ Voting.Protocol.Trustee.Indispensable: instance Control.DeepSeq.NFData (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey c)
+ Voting.Protocol.Trustee.Indispensable: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.FromJSON.FromJSON (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey c)
+ Voting.Protocol.Trustee.Indispensable: instance Data.Reflection.Reifies c Voting.Protocol.FFC.FFC => Data.Aeson.Types.ToJSON.ToJSON (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey c)
+ Voting.Protocol.Trustee.Indispensable: instance GHC.Classes.Eq (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey c)
+ Voting.Protocol.Trustee.Indispensable: instance GHC.Generics.Generic (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey c)
+ Voting.Protocol.Trustee.Indispensable: instance GHC.Show.Show (Voting.Protocol.Trustee.Indispensable.TrusteePublicKey c)
+ Voting.Protocol.Utils: infixr 9 `o2`
+ Voting.Protocol.Utils: o2 :: (c -> d) -> (a -> b -> c) -> a -> b -> d
- Voting.Protocol.Credential: credentialSecretKey :: SubGroup q => UUID -> Credential -> SecretKey q
+ Voting.Protocol.Credential: credentialSecretKey :: Reifies c FFC => UUID -> Credential -> SecretKey c
- Voting.Protocol.Credential: publicKey :: SubGroup q => SecretKey q -> PublicKey q
+ Voting.Protocol.Credential: publicKey :: Reifies c FFC => SecretKey c -> PublicKey c
- Voting.Protocol.Credential: randomSecretKey :: Monad m => RandomGen r => SubGroup q => StateT r m (SecretKey q)
+ Voting.Protocol.Credential: randomSecretKey :: Reifies c FFC => Monad m => RandomGen r => StateT r m (SecretKey c)
- Voting.Protocol.Credential: readCredential :: Text -> Either CredentialError Credential
+ Voting.Protocol.Credential: readCredential :: Text -> Either ErrorToken Credential
- Voting.Protocol.Election: Answer :: [(Encryption q, DisjProof q)] -> DisjProof q -> Answer q
+ Voting.Protocol.Election: Answer :: ![(Encryption c, DisjProof c)] -> !DisjProof c -> Answer c
- Voting.Protocol.Election: Ballot :: [Answer q] -> Maybe (Signature q) -> UUID -> Hash -> Ballot q
+ Voting.Protocol.Election: Ballot :: ![Answer c] -> !Maybe (Signature c) -> !UUID -> !Hash -> Ballot c
- Voting.Protocol.Election: DisjProof :: [Proof q] -> DisjProof q
+ Voting.Protocol.Election: DisjProof :: [Proof c] -> DisjProof c
- Voting.Protocol.Election: Election :: Text -> Text -> PublicKey q -> [Question q] -> UUID -> Hash -> Election q
+ Voting.Protocol.Election: Election :: !Text -> !Text -> !ElectionCrypto c -> ![Question] -> !UUID -> !Hash -> Election c
- Voting.Protocol.Election: Encryption :: G q -> G q -> Encryption q
+ Voting.Protocol.Election: Encryption :: !G c -> !G c -> Encryption c
- Voting.Protocol.Election: Proof :: Challenge q -> E q -> Proof q
+ Voting.Protocol.Election: Proof :: Challenge c -> E c -> Proof c
- Voting.Protocol.Election: Question :: Text -> [Text] -> Opinion q -> Opinion q -> Question q
+ Voting.Protocol.Election: Question :: !Text -> ![Text] -> !Natural -> !Natural -> Question
- Voting.Protocol.Election: Signature :: PublicKey q -> Proof q -> Signature q
+ Voting.Protocol.Election: Signature :: !PublicKey c -> !Proof c -> Signature c
- Voting.Protocol.Election: [answer_opinions] :: Answer q -> [(Encryption q, DisjProof q)]
+ Voting.Protocol.Election: [answer_opinions] :: Answer c -> ![(Encryption c, DisjProof c)]
- Voting.Protocol.Election: [answer_sumProof] :: Answer q -> DisjProof q
+ Voting.Protocol.Election: [answer_sumProof] :: Answer c -> !DisjProof c
- Voting.Protocol.Election: [ballot_answers] :: Ballot q -> [Answer q]
+ Voting.Protocol.Election: [ballot_answers] :: Ballot c -> ![Answer c]
- Voting.Protocol.Election: [ballot_election_hash] :: Ballot q -> Hash
+ Voting.Protocol.Election: [ballot_election_hash] :: Ballot c -> !Hash
- Voting.Protocol.Election: [ballot_election_uuid] :: Ballot q -> UUID
+ Voting.Protocol.Election: [ballot_election_uuid] :: Ballot c -> !UUID
- Voting.Protocol.Election: [ballot_signature] :: Ballot q -> Maybe (Signature q)
+ Voting.Protocol.Election: [ballot_signature] :: Ballot c -> !Maybe (Signature c)
- Voting.Protocol.Election: [election_description] :: Election q -> Text
+ Voting.Protocol.Election: [election_description] :: Election c -> !Text
- Voting.Protocol.Election: [election_hash] :: Election q -> Hash
+ Voting.Protocol.Election: [election_hash] :: Election c -> !Hash
- Voting.Protocol.Election: [election_name] :: Election q -> Text
+ Voting.Protocol.Election: [election_name] :: Election c -> !Text
- Voting.Protocol.Election: [election_questions] :: Election q -> [Question q]
+ Voting.Protocol.Election: [election_questions] :: Election c -> ![Question]
- Voting.Protocol.Election: [election_uuid] :: Election q -> UUID
+ Voting.Protocol.Election: [election_uuid] :: Election c -> !UUID
- Voting.Protocol.Election: [encryption_nonce] :: Encryption q -> G q
+ Voting.Protocol.Election: [encryption_nonce] :: Encryption c -> !G c
- Voting.Protocol.Election: [encryption_vault] :: Encryption q -> G q
+ Voting.Protocol.Election: [encryption_vault] :: Encryption c -> !G c
- Voting.Protocol.Election: [proof_challenge] :: Proof q -> Challenge q
+ Voting.Protocol.Election: [proof_challenge] :: Proof c -> Challenge c
- Voting.Protocol.Election: [proof_response] :: Proof q -> E q
+ Voting.Protocol.Election: [proof_response] :: Proof c -> E c
- Voting.Protocol.Election: [question_choices] :: Question q -> [Text]
+ Voting.Protocol.Election: [question_choices] :: Question -> ![Text]
- Voting.Protocol.Election: [question_maxi] :: Question q -> Opinion q
+ Voting.Protocol.Election: [question_maxi] :: Question -> !Natural
- Voting.Protocol.Election: [question_mini] :: Question q -> Opinion q
+ Voting.Protocol.Election: [question_mini] :: Question -> !Natural
- Voting.Protocol.Election: [question_text] :: Question q -> Text
+ Voting.Protocol.Election: [question_text] :: Question -> !Text
- Voting.Protocol.Election: [signature_proof] :: Signature q -> Proof q
+ Voting.Protocol.Election: [signature_proof] :: Signature c -> !Proof c
- Voting.Protocol.Election: [signature_publicKey] :: Signature q -> PublicKey q
+ Voting.Protocol.Election: [signature_publicKey] :: Signature c -> !PublicKey c
- Voting.Protocol.Election: booleanDisjunctions :: SubGroup q => [Disjunction q]
+ Voting.Protocol.Election: booleanDisjunctions :: Reifies c FFC => [Disjunction c]
- Voting.Protocol.Election: commit :: SubGroup q => Proof q -> G q -> G q -> Commitment q
+ Voting.Protocol.Election: commit :: Reifies c FFC => Proof c -> G c -> G c -> Commitment c
- Voting.Protocol.Election: data Answer q
+ Voting.Protocol.Election: data Answer c
- Voting.Protocol.Election: data Ballot q
+ Voting.Protocol.Election: data Ballot c
- Voting.Protocol.Election: data Election q
+ Voting.Protocol.Election: data Election c
- Voting.Protocol.Election: data Encryption q
+ Voting.Protocol.Election: data Encryption c
- Voting.Protocol.Election: data Proof q
+ Voting.Protocol.Election: data Proof c
- Voting.Protocol.Election: data Question q
+ Voting.Protocol.Election: data Question
- Voting.Protocol.Election: data Signature q
+ Voting.Protocol.Election: data Signature c
- Voting.Protocol.Election: encrypt :: Monad m => RandomGen r => SubGroup q => PublicKey q -> E q -> StateT r m (EncryptionNonce q, Encryption q)
+ Voting.Protocol.Election: encrypt :: Reifies c FFC => Monad m => RandomGen r => PublicKey c -> E c -> StateT r m (EncryptionNonce c, Encryption c)
- Voting.Protocol.Election: encryptAnswer :: Monad m => RandomGen r => SubGroup q => PublicKey q -> ZKP -> Question q -> [Bool] -> StateT r (ExceptT ErrorAnswer m) (Answer q)
+ Voting.Protocol.Election: encryptAnswer :: Reifies c FFC => Monad m => RandomGen r => PublicKey c -> ZKP -> Question -> [Bool] -> StateT r (ExceptT ErrorAnswer m) (Answer c)
- Voting.Protocol.Election: encryptBallot :: Monad m => RandomGen r => SubGroup q => Election q -> Maybe (SecretKey q) -> [[Bool]] -> StateT r (ExceptT ErrorBallot m) (Ballot q)
+ Voting.Protocol.Election: encryptBallot :: Reifies c FFC => Monad m => RandomGen r => Election c -> Maybe (SecretKey c) -> [[Bool]] -> StateT r (ExceptT ErrorBallot m) (Ballot c)
- Voting.Protocol.Election: encryptionCommitments :: SubGroup q => PublicKey q -> Encryption q -> Disjunction q -> Proof q -> [G q]
+ Voting.Protocol.Election: encryptionCommitments :: Reifies c FFC => PublicKey c -> Encryption c -> Disjunction c -> Proof c -> [G c]
- Voting.Protocol.Election: encryptionStatement :: SubGroup q => ZKP -> Encryption q -> ByteString
+ Voting.Protocol.Election: encryptionStatement :: Reifies c FFC => ZKP -> Encryption c -> ByteString
- Voting.Protocol.Election: fakeProof :: Monad m => RandomGen r => SubGroup q => StateT r m (Proof q)
+ Voting.Protocol.Election: fakeProof :: Reifies c FFC => Monad m => RandomGen r => StateT r m (Proof c)
- Voting.Protocol.Election: intervalDisjunctions :: SubGroup q => Opinion q -> Opinion q -> [Disjunction q]
+ Voting.Protocol.Election: intervalDisjunctions :: Reifies c FFC => Natural -> Natural -> [Disjunction c]
- Voting.Protocol.Election: newtype DisjProof q
+ Voting.Protocol.Election: newtype DisjProof c
- Voting.Protocol.Election: prove :: Monad m => RandomGen r => SubGroup q => Functor list => E q -> list (G q) -> Oracle list q -> StateT r m (Proof q)
+ Voting.Protocol.Election: prove :: Reifies c FFC => Monad m => RandomGen r => Functor list => E c -> list (G c) -> Oracle list c -> StateT r m (Proof c)
- Voting.Protocol.Election: proveEncryption :: Monad m => RandomGen r => SubGroup q => PublicKey q -> ZKP -> ([Disjunction q], [Disjunction q]) -> (EncryptionNonce q, Encryption q) -> StateT r m (DisjProof q)
+ Voting.Protocol.Election: proveEncryption :: Reifies c FFC => Monad m => RandomGen r => PublicKey c -> ZKP -> ([Disjunction c], [Disjunction c]) -> (EncryptionNonce c, Encryption c) -> StateT r m (DisjProof c)
- Voting.Protocol.Election: signatureCommitments :: SubGroup q => ZKP -> Commitment q -> ByteString
+ Voting.Protocol.Election: signatureCommitments :: ZKP -> Commitment c -> ByteString
- Voting.Protocol.Election: signatureStatement :: Foldable f => SubGroup q => f (Answer q) -> [G q]
+ Voting.Protocol.Election: signatureStatement :: Reifies c FFC => Foldable f => f (Answer c) -> [G c]
- Voting.Protocol.Election: type Oracle list q = list (Commitment q) -> Challenge q
+ Voting.Protocol.Election: type Oracle list c = list (Commitment c) -> Challenge c
- Voting.Protocol.Election: verifyAnswer :: SubGroup q => PublicKey q -> ZKP -> Question q -> Answer q -> Bool
+ Voting.Protocol.Election: verifyAnswer :: Reifies c FFC => PublicKey c -> ZKP -> Question -> Answer c -> Bool
- Voting.Protocol.Election: verifyBallot :: SubGroup q => Election q -> Ballot q -> Bool
+ Voting.Protocol.Election: verifyBallot :: Reifies c FFC => Election c -> Ballot c -> Bool
- Voting.Protocol.Election: verifyEncryption :: Monad m => SubGroup q => PublicKey q -> ZKP -> [Disjunction q] -> (Encryption q, DisjProof q) -> ExceptT ErrorVerifyEncryption m Bool
+ Voting.Protocol.Election: verifyEncryption :: Reifies c FFC => Monad m => PublicKey c -> ZKP -> [Disjunction c] -> (Encryption c, DisjProof c) -> ExceptT ErrorVerifyEncryption m Bool
- Voting.Protocol.Tally: Tally :: Natural -> EncryptedTally q -> [DecryptionShare q] -> [[Natural]] -> Tally q
+ Voting.Protocol.Tally: Tally :: !Natural -> !EncryptedTally c -> ![DecryptionShare c] -> ![[Natural]] -> Tally c
- Voting.Protocol.Tally: [tally_countByChoiceByQuest] :: Tally q -> [[Natural]]
+ Voting.Protocol.Tally: [tally_countByChoiceByQuest] :: Tally c -> ![[Natural]]
- Voting.Protocol.Tally: [tally_countMax] :: Tally q -> Natural
+ Voting.Protocol.Tally: [tally_countMax] :: Tally c -> !Natural
- Voting.Protocol.Tally: [tally_decShareByTrustee] :: Tally q -> [DecryptionShare q]
+ Voting.Protocol.Tally: [tally_decShareByTrustee] :: Tally c -> ![DecryptionShare c]
- Voting.Protocol.Tally: [tally_encByChoiceByQuest] :: Tally q -> EncryptedTally q
+ Voting.Protocol.Tally: [tally_encByChoiceByQuest] :: Tally c -> !EncryptedTally c
- Voting.Protocol.Tally: data Tally q
+ Voting.Protocol.Tally: data Tally c
- Voting.Protocol.Tally: decryptionShareStatement :: SubGroup q => PublicKey q -> ByteString
+ Voting.Protocol.Tally: decryptionShareStatement :: Reifies c FFC => PublicKey c -> ByteString
- Voting.Protocol.Tally: encryptedTally :: SubGroup q => [Ballot q] -> (EncryptedTally q, Natural)
+ Voting.Protocol.Tally: encryptedTally :: Reifies c FFC => [Ballot c] -> (EncryptedTally c, Natural)
- Voting.Protocol.Tally: proveDecryptionFactor :: Monad m => SubGroup q => RandomGen r => SecretKey q -> Encryption q -> StateT r m (DecryptionFactor q, Proof q)
+ Voting.Protocol.Tally: proveDecryptionFactor :: Monad m => Reifies c FFC => RandomGen r => SecretKey c -> Encryption c -> StateT r m (DecryptionFactor c, Proof c)
- Voting.Protocol.Tally: proveDecryptionShare :: Monad m => SubGroup q => RandomGen r => EncryptedTally q -> SecretKey q -> StateT r m (DecryptionShare q)
+ Voting.Protocol.Tally: proveDecryptionShare :: Monad m => Reifies c FFC => RandomGen r => EncryptedTally c -> SecretKey c -> StateT r m (DecryptionShare c)
- Voting.Protocol.Tally: proveTally :: SubGroup q => (EncryptedTally q, Natural) -> [DecryptionShare q] -> DecryptionShareCombinator q -> Except ErrorDecryptionShare (Tally q)
+ Voting.Protocol.Tally: proveTally :: Reifies c FFC => (EncryptedTally c, Natural) -> [DecryptionShare c] -> DecryptionShareCombinator c -> Except ErrorTally (Tally c)
- Voting.Protocol.Tally: type DecryptionShareCombinator q = [DecryptionShare q] -> Except ErrorDecryptionShare [[DecryptionFactor q]]
+ Voting.Protocol.Tally: type DecryptionShareCombinator c = EncryptedTally c -> [DecryptionShare c] -> Except ErrorTally [[DecryptionFactor c]]
- Voting.Protocol.Tally: type EncryptedTally q = [[Encryption q]]
+ Voting.Protocol.Tally: type EncryptedTally c = [[Encryption c]]
- Voting.Protocol.Tally: verifyDecryptionShare :: Monad m => SubGroup q => EncryptedTally q -> PublicKey q -> DecryptionShare q -> ExceptT ErrorDecryptionShare m ()
+ Voting.Protocol.Tally: verifyDecryptionShare :: Monad m => Reifies c FFC => EncryptedTally c -> PublicKey c -> DecryptionShare c -> ExceptT ErrorTally m ()
- Voting.Protocol.Tally: verifyDecryptionShareByTrustee :: Monad m => SubGroup q => EncryptedTally q -> [PublicKey q] -> [DecryptionShare q] -> ExceptT ErrorDecryptionShare m ()
+ Voting.Protocol.Tally: verifyDecryptionShareByTrustee :: Monad m => Reifies c FFC => EncryptedTally c -> [PublicKey c] -> [DecryptionShare c] -> ExceptT ErrorTally m ()
- Voting.Protocol.Tally: verifyTally :: SubGroup q => Tally q -> DecryptionShareCombinator q -> Except ErrorDecryptionShare ()
+ Voting.Protocol.Tally: verifyTally :: Reifies c FFC => Tally c -> DecryptionShareCombinator c -> Except ErrorTally ()
- Voting.Protocol.Trustee.Indispensable: TrusteePublicKey :: PublicKey q -> Proof q -> TrusteePublicKey q
+ Voting.Protocol.Trustee.Indispensable: TrusteePublicKey :: !PublicKey c -> !Proof c -> TrusteePublicKey c
- Voting.Protocol.Trustee.Indispensable: [trustee_PublicKey] :: TrusteePublicKey q -> PublicKey q
+ Voting.Protocol.Trustee.Indispensable: [trustee_PublicKey] :: TrusteePublicKey c -> !PublicKey c
- Voting.Protocol.Trustee.Indispensable: [trustee_SecretKeyProof] :: TrusteePublicKey q -> Proof q
+ Voting.Protocol.Trustee.Indispensable: [trustee_SecretKeyProof] :: TrusteePublicKey c -> !Proof c
- Voting.Protocol.Trustee.Indispensable: combineIndispensableDecryptionShares :: SubGroup q => [PublicKey q] -> EncryptedTally q -> DecryptionShareCombinator q
+ Voting.Protocol.Trustee.Indispensable: combineIndispensableDecryptionShares :: Reifies c FFC => [PublicKey c] -> DecryptionShareCombinator c
- Voting.Protocol.Trustee.Indispensable: combineIndispensableTrusteePublicKeys :: SubGroup q => [TrusteePublicKey q] -> PublicKey q
+ Voting.Protocol.Trustee.Indispensable: combineIndispensableTrusteePublicKeys :: Reifies c FFC => [TrusteePublicKey c] -> PublicKey c
- Voting.Protocol.Trustee.Indispensable: data TrusteePublicKey q
+ Voting.Protocol.Trustee.Indispensable: data TrusteePublicKey c
- Voting.Protocol.Trustee.Indispensable: indispensableTrusteePublicKeyStatement :: PublicKey q -> ByteString
+ Voting.Protocol.Trustee.Indispensable: indispensableTrusteePublicKeyStatement :: PublicKey c -> ByteString
- Voting.Protocol.Trustee.Indispensable: proveIndispensableTrusteePublicKey :: Monad m => RandomGen r => SubGroup q => SecretKey q -> StateT r m (TrusteePublicKey q)
+ Voting.Protocol.Trustee.Indispensable: proveIndispensableTrusteePublicKey :: Reifies c FFC => Monad m => RandomGen r => SecretKey c -> StateT r m (TrusteePublicKey c)
- Voting.Protocol.Trustee.Indispensable: verifyIndispensableDecryptionShareByTrustee :: SubGroup q => Monad m => EncryptedTally q -> [PublicKey q] -> [DecryptionShare q] -> ExceptT ErrorDecryptionShare m ()
+ Voting.Protocol.Trustee.Indispensable: verifyIndispensableDecryptionShareByTrustee :: Reifies c FFC => Monad m => EncryptedTally c -> [PublicKey c] -> [DecryptionShare c] -> ExceptT ErrorTally m ()
- Voting.Protocol.Trustee.Indispensable: verifyIndispensableTrusteePublicKey :: Monad m => SubGroup q => TrusteePublicKey q -> ExceptT ErrorTrusteePublicKey m ()
+ Voting.Protocol.Trustee.Indispensable: verifyIndispensableTrusteePublicKey :: Reifies c FFC => Monad m => TrusteePublicKey c -> ExceptT ErrorTrusteePublicKey m ()
- Voting.Protocol.Utils: isoZipWith3M :: Applicative m => m () -> (a -> b -> c -> m d) -> [a] -> [b] -> [c] -> m [d]
+ Voting.Protocol.Utils: isoZipWith3M :: Applicative f => f () -> (a -> b -> c -> f d) -> [a] -> [b] -> [c] -> f [d]
- Voting.Protocol.Utils: isoZipWith3M_ :: Applicative m => m () -> (a -> b -> c -> m d) -> [a] -> [b] -> [c] -> m ()
+ Voting.Protocol.Utils: isoZipWith3M_ :: Applicative f => f () -> (a -> b -> c -> f d) -> [a] -> [b] -> [c] -> f ()
- Voting.Protocol.Utils: isoZipWithM :: Applicative m => m () -> (a -> b -> m c) -> [a] -> [b] -> m [c]
+ Voting.Protocol.Utils: isoZipWithM :: Applicative f => f () -> (a -> b -> f c) -> [a] -> [b] -> f [c]
- Voting.Protocol.Utils: isoZipWithM_ :: Applicative m => m () -> (a -> b -> m c) -> [a] -> [b] -> m ()
+ Voting.Protocol.Utils: isoZipWithM_ :: Applicative f => f () -> (a -> b -> f c) -> [a] -> [b] -> f ()
Files
- benchmarks/Election.hs +33/−33
- benchmarks/Utils.hs +1/−3
- hjugement-protocol.cabal +11/−10
- src/Voting/Protocol.hs +2/−2
- src/Voting/Protocol/Arithmetic.hs +0/−335
- src/Voting/Protocol/Credential.hs +50/−19
- src/Voting/Protocol/Election.hs +183/−86
- src/Voting/Protocol/FFC.hs +415/−0
- src/Voting/Protocol/Tally.hs +72/−76
- src/Voting/Protocol/Trustee/Indispensable.hs +47/−31
- src/Voting/Protocol/Utils.hs +14/−17
- stack.yaml +1/−1
- tests/HUnit.hs +2/−2
- tests/HUnit/Arithmetic.hs +0/−41
- tests/HUnit/Credential.hs +17/−17
- tests/HUnit/Election.hs +28/−25
- tests/HUnit/FFC.hs +46/−0
- tests/HUnit/Trustee/Indispensable.hs +32/−32
- tests/QuickCheck/Election.hs +39/−29
- tests/QuickCheck/Trustee.hs +10/−8
- tests/Utils.hs +1/−0
benchmarks/Election.hs view
@@ -8,15 +8,15 @@ import Voting.Protocol import Utils -makeElection :: SubGroup q => Int -> Int -> Election q-makeElection nQuests nChoices = Election+makeElection :: forall c. Reifies c FFC => Int -> Int -> Election c+makeElection nQuests nChoices = hashElection $ Election { election_name = Text.pack $ "elec"<>show nQuests<>show nChoices , election_description = "benchmarkable election" , election_uuid- , election_PublicKey =+ , election_crypto = ElectionCrypto_FFC (reflect (Proxy::Proxy c)) $ let secKey = credentialSecretKey election_uuid (Credential "xLcs7ev6Jy6FHHE") in publicKey secKey- , election_hash = Hash "" -- FIXME: when implemented+ , election_hash = Hash "" , election_questions = (<$> [1..nQuests]) $ \quest -> Question { question_text = Text.pack $ "quest"<>show quest@@ -26,16 +26,16 @@ } } where election_uuid = UUID "xLcs7ev6Jy6FHH" -makeVotes :: Election q -> [[Bool]]+makeVotes :: Election c -> [[Bool]] makeVotes Election{..} = [ True : List.tail [ False | _choice <- question_choices quest ] | quest <- election_questions ] -makeBallot :: forall q. SubGroup q => Election q -> Ballot q+makeBallot :: Reifies c FFC => Election c -> Ballot c makeBallot elec = case runExcept $ (`evalStateT` mkStdGen seed) $ do- ballotSecKey :: SecretKey q <- randomSecretKey+ ballotSecKey <- randomSecretKey encryptBallot elec (Just ballotSecKey) $ makeVotes elec of Right ballot -> ballot@@ -43,7 +43,7 @@ where seed = 0 -titleElection :: Election q -> String+titleElection :: Election c -> String titleElection Election{..} = Printf.printf "(questions=%i)×(choices=%i)==%i" nQuests nChoices (nQuests * nChoices)@@ -51,26 +51,26 @@ nQuests = List.length election_questions nChoices = List.foldr max 0 $ List.length . question_choices <$> election_questions -benchEncryptBallot :: forall q. Params q => Int -> Int -> Benchmark-benchEncryptBallot nQuests nChoices =- env setupEnv $ \ ~elec ->- bench (titleElection elec) $- nf makeBallot elec- where- setupEnv = do- let elec :: Election q = makeElection nQuests nChoices- return elec+benchEncryptBallot :: FFC -> Int -> Int -> Benchmark+benchEncryptBallot ffc nQuests nChoices =+ reify ffc $ \(Proxy::Proxy c) ->+ let setupEnv = do+ let elec :: Election c = makeElection nQuests nChoices+ return elec in+ env setupEnv $ \ ~(elec) ->+ bench (titleElection elec) $+ nf makeBallot elec -benchVerifyBallot :: forall q. Params q => Int -> Int -> Benchmark-benchVerifyBallot nQuests nChoices =- env setupEnv $ \ ~(elec,ballot) ->- bench (titleElection elec) $- nf (verifyBallot elec) ballot- where- setupEnv = do- let elec :: Election q = makeElection nQuests nChoices- let ballot = makeBallot elec- return (elec,ballot)+benchVerifyBallot :: FFC -> Int -> Int -> Benchmark+benchVerifyBallot ffc nQuests nChoices =+ reify ffc $ \(Proxy::Proxy c) ->+ let setupEnv = do+ let elec :: Election 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 =@@ -79,23 +79,23 @@ | nQ <- [1,5,10,15,20,25] , nC <- [5,7] ] in- [ bgroup "WeakParams"+ [ bgroup "weakFFC" [ bgroup "encryptBallot"- [ benchEncryptBallot @WeakParams nQuests nChoices+ [ benchEncryptBallot weakFFC nQuests nChoices | (nQuests,nChoices) <- inputs ] , bgroup "verifyBallot"- [ benchVerifyBallot @WeakParams nQuests nChoices+ [ benchVerifyBallot weakFFC nQuests nChoices | (nQuests,nChoices) <- inputs ] ]- , bgroup "BeleniosParams"+ , bgroup "beleniosFFC" [ bgroup "encryptBallot"- [ benchEncryptBallot @BeleniosParams nQuests nChoices+ [ benchEncryptBallot beleniosFFC nQuests nChoices | (nQuests,nChoices) <- inputs ] , bgroup "verifyBallot"- [ benchVerifyBallot @BeleniosParams nQuests nChoices+ [ benchVerifyBallot beleniosFFC nQuests nChoices | (nQuests,nChoices) <- inputs ] ]
benchmarks/Utils.hs view
@@ -16,8 +16,6 @@ , Text , Word8 , Num, Fractional(..), Integral(..), Integer, fromIntegral- , min- , max , Show(..) , MonadTrans(..) , ExceptT@@ -50,7 +48,7 @@ import Data.Text (Text) import Data.Word (Word8) import Debug.Trace-import Prelude (Num(..), Fractional(..), Integral(..), Integer, undefined, fromIntegral, error)+import Prelude (Num(..), Fractional(..), Integral(..), Integer, fromIntegral, error) import System.IO (IO) import System.Random (mkStdGen) import Text.Show (Show(..))
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.20190513+version: 0.0.0.20190519 category: Politic synopsis: A cryptographic protocol for the Majority Judgment. description:@@ -17,9 +17,6 @@ <http://stephane.glondu.net/ Stéphane Glondu> and Malika Izabachène. .- (TODO) Actually, this protocol is adapted a little bit here to better support- a better method of voting known as the <http://libgen.io/book/index.php?md5=BF67AA4298C1CE7633187546AA53E01D Majority Judgment>.- . * A large-public introduction (in french) to Helios-C is available here: <https://members.loria.fr/VCortier/files/Papers/Bulletin1024-2016.pdf Bulletin de la société informatique de France – numéro 9, novembre 2016>. * A more scientific (yet understandable) introduction (in english) to Belenios@@ -64,7 +61,7 @@ hs-source-dirs: src exposed-modules: Voting.Protocol- Voting.Protocol.Arithmetic+ Voting.Protocol.FFC Voting.Protocol.Credential Voting.Protocol.Election Voting.Protocol.Tally@@ -87,11 +84,11 @@ NoMonomorphismRestriction RecordWildCards ScopedTypeVariables+ StandaloneDeriving TupleSections TypeApplications TypeFamilies TypeOperators- UndecidableInstances ghc-options: -Wall -Wincomplete-uni-patterns@@ -100,6 +97,9 @@ -- -fhide-source-paths build-depends: base >= 4.6 && < 5+ , aeson >= 1.3+ , base64-bytestring >= 1.0+ , binary >= 0.8 , bytestring >= 0.10 , containers >= 0.5 , cryptonite >= 0.25@@ -110,7 +110,7 @@ -- , monad-classes >= 0.3 , deepseq >= 1.4 , random >= 1.1- -- , reflection >= 2.1+ , reflection >= 2.1 , text >= 1.2 , transformers >= 0.5 , unordered-containers >= 0.2.8@@ -121,7 +121,7 @@ main-is: Main.hs other-modules: HUnit- HUnit.Arithmetic+ HUnit.FFC HUnit.Credential HUnit.Election HUnit.Trustee@@ -146,11 +146,11 @@ NoMonomorphismRestriction RecordWildCards ScopedTypeVariables+ StandaloneDeriving TupleSections TypeApplications TypeFamilies TypeOperators- UndecidableInstances ghc-options: -Wall -Wincomplete-uni-patterns@@ -160,6 +160,7 @@ build-depends: hjugement-protocol , base >= 4.6 && < 5+ , aeson >= 1.3 , containers >= 0.5 -- , hashable >= 1.2.6 , QuickCheck >= 2.11@@ -196,11 +197,11 @@ NoMonomorphismRestriction RecordWildCards ScopedTypeVariables+ StandaloneDeriving TupleSections TypeApplications TypeFamilies TypeOperators- UndecidableInstances ghc-options: -Wall -Wincomplete-uni-patterns
src/Voting/Protocol.hs view
@@ -1,12 +1,12 @@ module Voting.Protocol- ( module Voting.Protocol.Arithmetic+ ( module Voting.Protocol.FFC , module Voting.Protocol.Credential , module Voting.Protocol.Election , module Voting.Protocol.Tally , module Voting.Protocol.Trustee ) where -import Voting.Protocol.Arithmetic+import Voting.Protocol.FFC import Voting.Protocol.Credential import Voting.Protocol.Election import Voting.Protocol.Tally
− src/Voting/Protocol/Arithmetic.hs
@@ -1,335 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-module Voting.Protocol.Arithmetic- ( module Voting.Protocol.Arithmetic- , Natural- , Random.RandomGen- ) where--import Control.Arrow (first)-import Control.DeepSeq (NFData)-import Control.Monad (Monad(..))-import Data.Bits-import Data.Bool-import Data.Eq (Eq(..))-import Data.Foldable (Foldable, foldl')-import Data.Function (($), (.))-import Data.Functor ((<$>))-import Data.Int (Int)-import Data.Maybe (Maybe(..))-import Data.Ord (Ord(..))-import Data.Semigroup (Semigroup(..))-import Data.String (String, IsString(..))-import Numeric.Natural (Natural)-import Prelude (Integer, Integral(..), fromIntegral, Enum(..))-import Text.Show (Show(..))-import qualified Control.Monad.Trans.State.Strict as S-import qualified Crypto.Hash as Crypto-import qualified Data.ByteArray as ByteArray-import qualified Data.ByteString as BS-import qualified Data.List as List-import qualified Prelude as Num-import qualified System.Random as Random---- * Type 'F'--- | The type of the elements of a 'PrimeField'.------ A field must satisfy the following properties:------ * @(f, ('+'), 'zero')@ forms an abelian group,--- called the 'Additive' group of 'f'.------ * @('NonNull' f, ('*'), 'one')@ forms an abelian group,--- called the 'Multiplicative' group of 'f'.------ * ('*') is associative:--- @(a'*'b)'*'c == a'*'(b'*'c)@ and--- @a'*'(b'*'c) == (a'*'b)'*'c@.------ * ('*') and ('+') are both commutative:--- @a'*'b == b'*'a@ and--- @a'+'b == b'+'a@------ * ('*') and ('+') are both left and right distributive:--- @a'*'(b'+'c) == (a'*'b) '+' (a'*'c)@ and--- @(a'+'b)'*'c == (a'*'c) '+' (b'*'c)@------ The 'Natural' is always within @[0..'fieldCharac'-1]@.-newtype F p = F { unF :: Natural }- deriving (Eq,Ord,Show,NFData)--instance PrimeField p => FromNatural (F p) where- fromNatural i = F (abs (i `mod` fieldCharac @p))- where abs x | x < 0 = x + fieldCharac @p- | otherwise = x-instance ToNatural (F p) where- nat = unF--instance PrimeField p => Additive (F p) where- zero = F 0- F x + F y = F ((x + y) `mod` fieldCharac @p)-instance PrimeField p => Negable (F p) where- neg (F x) | x == 0 = zero- | otherwise = F (fromIntegral (Num.negate (toInteger x) + toInteger (fieldCharac @p)))-instance PrimeField p => Multiplicative (F p) where- one = F 1- -- | Because 'fieldCharac' is prime,- -- all elements of the field are invertible modulo 'fieldCharac'.- F x * F y = F ((x * y) `mod` fieldCharac @p)-instance PrimeField p => Random.Random (F p) where- randomR (F lo, F hi) =- first (F . fromIntegral) .- Random.randomR- ( 0`max`toInteger lo- , toInteger hi`min`(toInteger (fieldCharac @p) - 1))- random = first (F . fromIntegral) . Random.randomR (0, toInteger (fieldCharac @p) - 1)---- ** Class 'PrimeField'--- | Parameter for a prime field.-class PrimeField p where- -- | The prime number characteristic of a 'PrimeField'.- --- -- ElGamal's hardness to decrypt requires a large prime number- -- to form the 'Multiplicative' 'SubGroup'.- fieldCharac :: Natural---- ** Class 'Additive'-class Additive a where- zero :: a- (+) :: a -> a -> a; infixl 6 +- sum :: Foldable f => f a -> a- sum = foldl' (+) zero-instance Additive Natural where- zero = 0- (+) = (Num.+)-instance Additive Integer where- zero = 0- (+) = (Num.+)-instance Additive Int where- zero = 0- (+) = (Num.+)---- *** Class 'Negable'-class Additive a => Negable a where- neg :: a -> a- (-) :: a -> a -> a; infixl 6 -- x-y = x + neg y-instance Negable Integer where- neg = Num.negate-instance Negable Int where- neg = Num.negate---- ** Class 'Multiplicative'-class Multiplicative a where- one :: a- (*) :: a -> a -> a; infixl 7 *-instance Multiplicative Natural where- one = 1- (*) = (Num.*)-instance Multiplicative Integer where- one = 1- (*) = (Num.*)-instance Multiplicative Int where- one = 1- (*) = (Num.*)---- ** Class 'Invertible'-class Multiplicative a => Invertible a where- inv :: a -> a- (/) :: a -> a -> a; infixl 7 /- x/y = x * inv y---- * Type 'G'--- | The type of the elements of a 'Multiplicative' 'SubGroup' of a 'PrimeField'.-newtype G q = G { unG :: F (P q) }- deriving (Eq,Ord,Show,NFData)--instance PrimeField (P q) => FromNatural (G q) where- fromNatural = G . fromNatural-instance ToNatural (G q) where- nat = unF . unG--instance (SubGroup q, Multiplicative (F (P q))) => Multiplicative (G q) where- one = G one- G x * G y = G (x * y)-instance (SubGroup q, Multiplicative (F (P q))) => Invertible (G q) where- -- | NOTE: add 'groupOrder' so the exponent given to (^) is positive.- inv = (^ E (neg one + groupOrder @q))---- ** Class 'SubGroup'--- | A 'SubGroup' of a 'Multiplicative' group of a 'PrimeField'.--- Used for signing (Schnorr) and encrypting (ElGamal).-class- ( PrimeField (P q)- , Multiplicative (F (P q))- ) => SubGroup q where- -- | Setting 'q' determines 'p', equals to @'P' q@.- type P q :: *- -- | A generator of the 'SubGroup'.- -- NOTE: since @F p@ is a 'PrimeField',- -- the 'Multiplicative' 'SubGroup' is cyclic,- -- and there are phi('fieldCharac'-1) many choices for the generator of the group,- -- where phi is the Euler totient function.- groupGen :: G q- -- | The order of the 'SubGroup'.- --- -- WARNING: 'groupOrder' MUST be a prime number dividing @('fieldCharac'-1)@- -- to ensure that ElGamal is secure in terms of the DDH assumption.- groupOrder :: F (P q)- - -- | 'groupGenInverses' returns the infinite list- -- of 'inv'erse powers of 'groupGen':- -- @['groupGen' '^' 'neg' i | i <- [0..]]@,- -- but by computing each value from the previous one.- --- -- NOTE: 'groupGenInverses' is in the 'SubGroup' class in order to keep- -- computed terms in memory across calls to 'groupGenInverses'.- --- -- Used by 'intervalDisjunctions'.- groupGenInverses :: [G q]- groupGenInverses = go one- where- go g = g : go (g * invGen)- invGen = inv groupGen--groupGenPowers :: SubGroup q => [G q]-groupGenPowers = go one- where go g = g : go (g * groupGen)---- | @('hash' bs gs)@ returns as a number in 'E'--- the SHA256 of the given 'BS.ByteString' 'bs'--- prefixing the decimal representation of given 'SubGroup' elements 'gs',--- with a comma (",") intercalated between them.------ NOTE: to avoid any collision when the 'hash' function is used in different contexts,--- a message 'gs' is actually prefixed by a 'bs' indicating the context.------ 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 bs gs =- let s = bs <> BS.intercalate (fromString ",") (bytesNat <$> gs) in- let h = ByteArray.convert (Crypto.hashWith Crypto.SHA256 s) in- fromNatural (BS.foldl' (\acc b -> acc`shiftL`3 + fromIntegral b) (0::Natural) h)---- * Type 'E'--- | An exponent of a (necessarily cyclic) 'SubGroup' of a 'PrimeField'.--- The value is always in @[0..'groupOrder'-1]@.-newtype E q = E { unE :: F (P q) }- deriving (Eq,Ord,Show,NFData)--instance SubGroup q => FromNatural (E q) where- fromNatural i = E (F (abs (i `mod` unF (groupOrder @q))))- where abs x | x < 0 = x + unF (groupOrder @q)- | otherwise = x-instance ToNatural (E q) where- nat = unF . unE--instance (SubGroup q, Additive (F (P q))) => Additive (E q) where- zero = E zero- E (F x) + E (F y) = E (F ((x + y) `mod` unF (groupOrder @q)))-instance (SubGroup q, Negable (F (P q))) => Negable (E q) where- neg (E (F x)) | x == 0 = zero- | otherwise = E (F (fromIntegral ( neg (toInteger x)- + toInteger (unF (groupOrder @q)) )))-instance (SubGroup q, Multiplicative (F (P q))) => Multiplicative (E q) where- one = E one- E (F x) * E (F y) = E (F ((x * y) `mod` unF (groupOrder @q)))-instance SubGroup q => Random.Random (E q) where- randomR (E (F lo), E (F hi)) =- first (E . F . fromIntegral) .- Random.randomR- ( 0`max`toInteger lo- , toInteger hi`min`(toInteger (unF (groupOrder @q)) - 1) )- random =- first (E . F . fromIntegral) .- Random.randomR (0, toInteger (unF (groupOrder @q)) - 1)-instance SubGroup q => Enum (E q) where- toEnum = fromNatural . fromIntegral- fromEnum = fromIntegral . nat- enumFromTo lo hi = List.unfoldr- (\i -> if i<=hi then Just (i, i+one) else Nothing) lo--infixr 8 ^--- | @(b '^' e)@ returns the modular exponentiation of base 'b' by exponent 'e'.-(^) :: SubGroup q => G q -> E q -> G q-(^) b (E (F e))- | e == zero = one- | otherwise = t * (b*b) ^ E (F (e`shiftR`1))- where- t | testBit e 0 = b- | otherwise = one---- | @('randomR' i)@ returns a random integer in @[0..i-1]@.-randomR ::- Monad m =>- Random.RandomGen r =>- Random.Random i =>- Negable i =>- Multiplicative i =>- i -> S.StateT r m i-randomR i = S.StateT $ return . Random.randomR (zero, i-one)---- | @('random')@ returns a random integer--- in the range determined by its type.-random ::- Monad m =>- Random.RandomGen r =>- Random.Random i =>- Negable i =>- Multiplicative i =>- S.StateT r m i-random = S.StateT $ return . Random.random--instance Random.Random Natural where- randomR (mini,maxi) =- first (fromIntegral::Integer -> Natural) .- Random.randomR (fromIntegral mini, fromIntegral maxi)- random = first (fromIntegral::Integer -> Natural) . Random.random---- * Groups---- * Type 'Params'-class SubGroup q => Params q where- paramsName :: String-instance Params WeakParams where- paramsName = "WeakParams"-instance Params BeleniosParams where- paramsName = "BeleniosParams"---- ** Type 'WeakParams'--- | Weak parameters for debugging purposes only.-data WeakParams-instance PrimeField WeakParams where- fieldCharac = 263-instance SubGroup WeakParams where- type P WeakParams = WeakParams- groupGen = G (F 2)- groupOrder = F 131---- ** Type 'BeleniosParams'--- | Parameters used in Belenios.--- A 2048-bit 'fieldCharac' of a 'PrimeField',--- with a 256-bit 'groupOrder' for a 'Multiplicative' 'SubGroup'--- generated by 'groupGen'.-data BeleniosParams-instance PrimeField BeleniosParams where- fieldCharac = 20694785691422546401013643657505008064922989295751104097100884787057374219242717401922237254497684338129066633138078958404960054389636289796393038773905722803605973749427671376777618898589872735865049081167099310535867780980030790491654063777173764198678527273474476341835600035698305193144284561701911000786737307333564123971732897913240474578834468260652327974647951137672658693582180046317922073668860052627186363386088796882120769432366149491002923444346373222145884100586421050242120365433561201320481118852408731077014151666200162313177169372189248078507711827842317498073276598828825169183103125680162072880719-instance SubGroup BeleniosParams where- type P BeleniosParams = BeleniosParams- groupGen = G (F 2402352677501852209227687703532399932712287657378364916510075318787663274146353219320285676155269678799694668298749389095083896573425601900601068477164491735474137283104610458681314511781646755400527402889846139864532661215055797097162016168270312886432456663834863635782106154918419982534315189740658186868651151358576410138882215396016043228843603930989333662772848406593138406010231675095763777982665103606822406635076697764025346253773085133173495194248967754052573659049492477631475991575198775177711481490920456600205478127054728238140972518639858334115700568353695553423781475582491896050296680037745308460627)- groupOrder = F 78571733251071885079927659812671450121821421258408794611510081919805623223441---- * Conversions---- ** Class 'FromNatural'-class FromNatural a where- fromNatural :: Natural -> a---- ** Class 'ToNatural'-class ToNatural a where- nat :: a -> Natural---- | @('bytesNat' x)@ returns the serialization of 'x'.-bytesNat :: ToNatural n => n -> BS.ByteString-bytesNat = fromString . show . nat
src/Voting/Protocol/Credential.hs view
@@ -1,26 +1,30 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-} module Voting.Protocol.Credential where import Control.DeepSeq (NFData)-import Control.Monad (Monad(..), replicateM)+import Control.Monad (Monad(..), forM_, replicateM) import Data.Bits import Data.Bool import Data.Char (Char)-import Data.Either (Either(..))+import Data.Either (Either(..), either) import Data.Eq (Eq(..)) import Data.Function (($)) import Data.Functor ((<$>)) import Data.Int (Int) import Data.Maybe (maybe) import Data.Ord (Ord(..))+import Data.Semigroup (Semigroup(..)) import Data.Text (Text) import GHC.Generics (Generic) import Numeric.Natural (Natural) import Prelude (Integral(..), fromIntegral, div)-import Text.Show (Show)+import Text.Show (Show(..)) import qualified Control.Monad.Trans.State.Strict as S import qualified Crypto.KDF.PBKDF2 as Crypto+import qualified Data.Aeson as JSON+import qualified Data.Aeson.Types as JSON import qualified Data.ByteArray as ByteArray import qualified Data.ByteString as BS import qualified Data.Char as Char@@ -29,7 +33,7 @@ import qualified Data.Text.Encoding as Text import qualified System.Random as Random -import Voting.Protocol.Arithmetic+import Voting.Protocol.FFC -- * Type 'Credential' -- | A 'Credential' is a word of @('tokenLength'+1 '==' 15)@-characters@@ -39,7 +43,14 @@ -- The last character is a checksum. -- The entropy is: @('tokenLength' * log 'tokenBase' / log 2) '==' 82.01… bits@. newtype Credential = Credential Text- deriving (Eq,Show,Generic,NFData)+ deriving (Eq,Show,Generic)+ deriving newtype NFData+ deriving newtype JSON.ToJSON+instance JSON.FromJSON Credential where+ parseJSON json@(JSON.String s) =+ either (\err -> JSON.typeMismatch ("Credential: "<>show err) json) return $+ readCredential s+ parseJSON json = JSON.typeMismatch "Credential" json credentialAlphabet :: [Char] -- TODO: make this an array credentialAlphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"@@ -63,9 +74,9 @@ -- | @'readCredential'@ reads and check the well-formedness of a 'Credential' -- from raw 'Text'.-readCredential :: Text -> Either CredentialError Credential+readCredential :: Text -> Either ErrorToken Credential readCredential s- | Text.length s /= tokenLength + 1 = Left CredentialError_Length+ | Text.length s /= tokenLength + 1 = Left ErrorToken_Length | otherwise = do tot <- Text.foldl' (\acc c -> acc >>= \a -> ((a * tokenBase) +) <$> digitOfChar c)@@ -74,22 +85,29 @@ checksum <- digitOfChar (Text.last s) if (tot + checksum) `mod` 53 == 0 then Right (Credential s)- else Left CredentialError_Checksum+ else Left ErrorToken_Checksum where digitOfChar c =- maybe (Left $ CredentialError_BadChar c) Right $+ maybe (Left $ ErrorToken_BadChar c) Right $ List.elemIndex c credentialAlphabet --- ** Type 'CredentialError'-data CredentialError- = CredentialError_BadChar Char.Char- | CredentialError_Checksum- | CredentialError_Length+-- ** Type 'ErrorToken'+data ErrorToken+ = ErrorToken_BadChar Char.Char+ | ErrorToken_Checksum+ | ErrorToken_Length deriving (Eq,Show,Generic,NFData) -- ** Type 'UUID' newtype UUID = UUID Text- deriving (Eq,Ord,Show,Generic,NFData)+ deriving (Eq,Ord,Show,Generic)+ deriving anyclass (JSON.ToJSON)+ deriving newtype NFData+instance JSON.FromJSON UUID where+ parseJSON json@(JSON.String s) =+ either (\err -> JSON.typeMismatch ("UUID: "<>show err) json) return $+ readUUID s+ parseJSON json = JSON.typeMismatch "UUID" json -- | @'randomUUID'@ generates a random 'UUID'. randomUUID ::@@ -102,16 +120,29 @@ where charOfDigit = (credentialAlphabet List.!!) +-- | @'readCredential'@ reads and check the well-formedness of a 'Credential'+-- from raw 'Text'.+readUUID :: Text -> Either ErrorToken UUID+readUUID s+ | Text.length s /= tokenLength = Left ErrorToken_Length+ | otherwise = do+ forM_ (Text.unpack s) digitOfChar+ return (UUID s)+ where+ digitOfChar c =+ maybe (Left $ ErrorToken_BadChar c) Right $+ List.elemIndex c credentialAlphabet+ -- ** Type 'SecretKey' type SecretKey = E -randomSecretKey :: Monad m => RandomGen r => SubGroup q => S.StateT r m (SecretKey q)+randomSecretKey :: Reifies c FFC => Monad m => RandomGen r => S.StateT r m (SecretKey c) randomSecretKey = random -- | @('credentialSecretKey' uuid cred)@ returns the 'SecretKey' -- derived from given 'uuid' and 'cred' -- using 'Crypto.fastPBKDF2_SHA256'.-credentialSecretKey :: SubGroup q => UUID -> Credential -> SecretKey q+credentialSecretKey :: Reifies c FFC => UUID -> Credential -> (SecretKey c) credentialSecretKey (UUID uuid) (Credential cred) = fromNatural $ BS.foldl' (\acc b -> acc`shiftL`3 + fromIntegral b)@@ -132,6 +163,6 @@ type PublicKey = G -- | @('publicKey' secKey)@ returns the 'PublicKey'--- derived from given 'SecretKey'.-publicKey :: SubGroup q => SecretKey q -> PublicKey q+-- derived from given 'SecretKey' @secKey@.+publicKey :: Reifies c FFC => SecretKey c -> PublicKey c publicKey = (groupGen ^)
src/Voting/Protocol/Election.hs view
@@ -2,36 +2,44 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Rank2Types #-} -- for reifyElection+{-# LANGUAGE UndecidableInstances #-} -- for Reifies instances module Voting.Protocol.Election where +import Control.Applicative (Applicative(..)) import Control.DeepSeq (NFData) import Control.Monad (Monad(..), join, mapM, replicateM, zipWithM) import Control.Monad.Trans.Class (MonadTrans(..)) import Control.Monad.Trans.Except (ExceptT, runExcept, throwE, withExceptT)+import Data.Aeson (ToJSON(..),FromJSON(..),(.:),(.=)) import Data.Bool import Data.Either (either) import Data.Eq (Eq(..)) import Data.Foldable (Foldable, foldMap, and)-import Data.Function (($), id, const)+import Data.Function (($), (.), id, const) import Data.Functor (Functor, (<$>)) import Data.Functor.Identity (Identity(..))-import Data.Maybe (Maybe(..), fromMaybe)+import Data.Maybe (Maybe(..), fromJust) import Data.Ord (Ord(..)) import Data.Semigroup (Semigroup(..)) import Data.Text (Text) import Data.Traversable (Traversable(..)) import Data.Tuple (fst, snd)-import GHC.Natural (minusNaturalMaybe) import GHC.Generics (Generic)+import GHC.Natural (minusNaturalMaybe) import Numeric.Natural (Natural) import Prelude (fromIntegral) import Text.Show (Show(..)) import qualified Control.Monad.Trans.State.Strict as S+import qualified Data.Aeson as JSON import qualified Data.ByteString as BS+import qualified Data.ByteString.Base64.Lazy as BSL64 import qualified Data.List as List+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL import Voting.Protocol.Utils-import Voting.Protocol.Arithmetic+import Voting.Protocol.FFC import Voting.Protocol.Credential -- * Type 'Encryption'@@ -46,18 +54,20 @@ -- -- NOTE: Since @('encryption_vault' '*' 'encryption_nonce' '==' 'encryption_nonce' '^' (secKey '+' clear))@, -- then: @(logBase 'encryption_nonce' ('encryption_vault' '*' 'encryption_nonce') '==' secKey '+' clear)@.-data Encryption q = Encryption- { encryption_nonce :: G q+data Encryption c = Encryption+ { encryption_nonce :: !(G c) -- ^ Public part of the randomness 'encNonce' used to 'encrypt' the 'clear' text, -- equal to @('groupGen' '^'encNonce)@- , encryption_vault :: G q+ , encryption_vault :: !(G c) -- ^ Encrypted 'clear' text, -- equal to @('pubKey' '^'encNone '*' 'groupGen' '^'clear)@ } deriving (Eq,Show,Generic,NFData)+deriving instance Reifies c FFC => ToJSON (Encryption c)+deriving instance Reifies c FFC => FromJSON (Encryption c) -- | Additive homomorphism. -- Using the fact that: @'groupGen' '^'x '*' 'groupGen' '^'y '==' 'groupGen' '^'(x'+'y)@.-instance SubGroup q => Additive (Encryption q) where+instance Reifies c FFC => Additive (Encryption c) where zero = Encryption one one x+y = Encryption (encryption_nonce x * encryption_nonce y)@@ -75,9 +85,10 @@ -- as it may be used to decipher the 'Encryption' -- without the 'SecretKey' associated with 'pubKey'. encrypt ::- Monad m => RandomGen r => SubGroup q =>- PublicKey q -> E q ->- S.StateT r m (EncryptionNonce q, Encryption q)+ Reifies c FFC =>+ Monad m => RandomGen r =>+ PublicKey c -> E c ->+ S.StateT r m (EncryptionNonce c, Encryption c) encrypt pubKey clear = do encNonce <- random -- NOTE: preserve the 'encNonce' for 'prove' in 'proveEncryption'.@@ -91,8 +102,8 @@ -- | Non-Interactive Zero-Knowledge 'Proof' -- of knowledge of a discrete logarithm: -- @(secret == logBase base (base^secret))@.-data Proof q = Proof- { proof_challenge :: Challenge q+data Proof c = Proof+ { proof_challenge :: Challenge c -- ^ 'Challenge' sent by the verifier to the prover -- to ensure that the prover really has knowledge -- of the secret and is not replaying.@@ -100,7 +111,7 @@ -- but derived from the prover's 'Commitment's and statements -- with a collision resistant 'hash'. -- Hence the prover cannot chose the 'proof_challenge' to his/her liking.- , proof_response :: E q+ , proof_response :: E c -- ^ A discrete logarithm sent by the prover to the verifier, -- as a response to 'proof_challenge'. --@@ -122,6 +133,8 @@ -- to ensure that each 'prove' does not reveal any information -- about its secret. } deriving (Eq,Show,Generic,NFData)+deriving instance Reifies c FFC => ToJSON (Proof c)+deriving instance Reifies c FFC => FromJSON (Proof c) -- ** Type 'ZKP' -- | Zero-knowledge proof.@@ -149,13 +162,13 @@ -- Indeed, the prover now handles the 'Challenge' -- which becomes a (collision resistant) 'hash' -- of the prover's commitments (and statements to be a stronger proof).-type Oracle list q = list (Commitment q) -> Challenge q+type Oracle list c = list (Commitment c) -> Challenge c --- | @('prove' sec commitBases oracle)@+-- | @('prove' sec commitmentBases oracle)@ -- returns a 'Proof' that @sec@ is known -- (by proving the knowledge of its discrete logarithm). ----- The 'Oracle' is given 'Commitment's equal to the 'commitBases'+-- The 'Oracle' is given 'Commitment's equal to the 'commitmentBases' -- raised to the power of the secret nonce of the 'Proof', -- as those are the 'Commitment's that the verifier will obtain -- when composing the 'proof_challenge' and 'proof_response' together@@ -169,11 +182,12 @@ -- because two 'Proof's using the same 'Commitment' -- can be used to deduce @sec@ (using the special-soundness). prove ::- Monad m => RandomGen r => SubGroup q => Functor list =>- E q -> list (G q) -> Oracle list q -> S.StateT r m (Proof q)-prove sec commitBases oracle = do+ Reifies c FFC =>+ Monad m => RandomGen r => Functor list =>+ E c -> list (G c) -> Oracle list c -> S.StateT r m (Proof c)+prove sec commitmentBases oracle = do nonce <- random- let commitments = (^ nonce) <$> commitBases+ let commitments = (^ nonce) <$> commitmentBases let proof_challenge = oracle commitments return Proof { proof_challenge@@ -188,7 +202,10 @@ -- -- Used in 'proveEncryption' to fill the returned 'DisjProof' -- with fake 'Proof's for all 'Disjunction's but the encrypted one.-fakeProof :: Monad m => RandomGen r => SubGroup q => S.StateT r m (Proof q)+fakeProof ::+ Reifies c FFC =>+ Monad m =>+ RandomGen r => S.StateT r m (Proof c) fakeProof = do proof_challenge <- random proof_response <- random@@ -202,7 +219,7 @@ -- | @('commit' proof base basePowSec)@ returns a 'Commitment' -- from the given 'Proof' with the knowledge of the verifier.-commit :: SubGroup q => Proof q -> G q -> G q -> Commitment q+commit :: Reifies c FFC => Proof c -> G c -> G c -> Commitment c commit Proof{..} base basePowSec = base^proof_response * basePowSec^proof_challenge@@ -218,12 +235,12 @@ -- that an 'encryption_vault' contains a given @('groupGen' '^'opinion)@, type Disjunction = G -booleanDisjunctions :: SubGroup q => [Disjunction q]+booleanDisjunctions :: Reifies c FFC => [Disjunction c] booleanDisjunctions = List.take 2 groupGenInverses -intervalDisjunctions :: SubGroup q => Opinion q -> Opinion q -> [Disjunction q]+intervalDisjunctions :: Reifies c FFC => Natural -> Natural -> [Disjunction c] intervalDisjunctions mini maxi =- List.genericTake (fromMaybe 0 $ (nat maxi + 1)`minusNaturalMaybe`nat mini) $+ List.genericTake (fromJust $ (nat maxi + 1)`minusNaturalMaybe`nat mini) $ List.genericDrop (nat mini) $ groupGenInverses @@ -236,9 +253,11 @@ -- | A list of 'Proof's to prove that the 'Opinion' within an 'Encryption' -- is indexing a 'Disjunction' within a list of them, -- without revealing which 'Opinion' it is.-newtype DisjProof q = DisjProof [Proof q]+newtype DisjProof c = DisjProof [Proof c] deriving (Eq,Show,Generic) deriving newtype NFData+deriving newtype instance Reifies c FFC => ToJSON (DisjProof c)+deriving newtype instance Reifies c FFC => FromJSON (DisjProof c) -- | @('proveEncryption' elecPubKey voterZKP (prevDisjs,nextDisjs) (encNonce,enc))@ -- returns a 'DisjProof' that 'enc' 'encrypt's@@ -251,11 +270,12 @@ -- -- DOC: Pierrick Gaudry. <https://hal.inria.fr/hal-01576379 Some ZK security proofs for Belenios>, 2017. proveEncryption ::- Monad m => RandomGen r => SubGroup q =>- PublicKey q -> ZKP ->- ([Disjunction q],[Disjunction q]) ->- (EncryptionNonce q, Encryption q) ->- S.StateT r m (DisjProof q)+ Reifies c FFC =>+ Monad m => RandomGen r =>+ PublicKey c -> ZKP ->+ ([Disjunction c],[Disjunction c]) ->+ (EncryptionNonce c, Encryption c) ->+ S.StateT r m (DisjProof c) proveEncryption elecPubKey voterZKP (prevDisjs,nextDisjs) (encNonce,enc) = do -- Fake proofs for all 'Disjunction's except the genuine one. prevFakeProofs <- replicateM (List.length prevDisjs) fakeProof@@ -279,9 +299,9 @@ return (DisjProof proofs) verifyEncryption ::- Monad m => SubGroup q =>- PublicKey q -> ZKP ->- [Disjunction q] -> (Encryption q, DisjProof q) ->+ Reifies c FFC => Monad m =>+ PublicKey c -> ZKP ->+ [Disjunction c] -> (Encryption c, DisjProof c) -> ExceptT ErrorVerifyEncryption m Bool verifyEncryption elecPubKey voterZKP disjs (enc, DisjProof proofs) = case isoZipWith (encryptionCommitments elecPubKey enc) disjs proofs of@@ -296,7 +316,7 @@ challengeSum = sum (proof_challenge <$> proofs) -- ** Hashing-encryptionStatement :: SubGroup q => ZKP -> Encryption q -> BS.ByteString+encryptionStatement :: Reifies c FFC => ZKP -> Encryption c -> BS.ByteString encryptionStatement (ZKP voterZKP) Encryption{..} = "prove|"<>voterZKP<>"|" <> bytesNat encryption_nonce<>","@@ -308,9 +328,9 @@ -- For the prover the 'Proof' comes from @fakeProof@, -- and for the verifier the 'Proof' comes from the prover. encryptionCommitments ::- SubGroup q =>- PublicKey q -> Encryption q ->- Disjunction q -> Proof q -> [G q]+ Reifies c FFC =>+ PublicKey c -> Encryption c ->+ Disjunction c -> Proof c -> [G c] encryptionCommitments elecPubKey Encryption{..} disj proof = [ commit proof groupGen encryption_nonce -- == groupGen ^ nonce if 'Proof' comes from 'prove'.@@ -330,40 +350,40 @@ deriving (Eq,Show) -- * Type 'Question'-data Question q = Question- { question_text :: Text- , question_choices :: [Text]- , question_mini :: Opinion q- , question_maxi :: Opinion q+data Question = Question+ { question_text :: !Text+ , question_choices :: ![Text]+ , question_mini :: !Natural+ , question_maxi :: !Natural -- , question_blank :: Maybe Bool- } deriving (Eq,Show,Generic,NFData)+ } deriving (Eq,Show,Generic,NFData,ToJSON,FromJSON) -- * Type 'Answer'-data Answer q = Answer- { answer_opinions :: [(Encryption q, DisjProof q)]+data Answer c = Answer+ { answer_opinions :: ![(Encryption c, DisjProof c)] -- ^ Encrypted 'Opinion' for each 'question_choices' -- with a 'DisjProof' that they belong to [0,1].- , answer_sumProof :: DisjProof q+ , answer_sumProof :: !(DisjProof c) -- ^ Proofs that the sum of the 'Opinon's encrypted in 'answer_opinions' -- is an element of @[mini..maxi]@. -- , answer_blankProof :: } deriving (Eq,Show,Generic,NFData)+deriving instance Reifies c FFC => ToJSON (Answer c)+deriving instance Reifies c FFC => FromJSON (Answer c) -- | @('encryptAnswer' elecPubKey zkp quest opinions)@ -- returns an 'Answer' validable by 'verifyAnswer', -- unless an 'ErrorAnswer' is returned. encryptAnswer ::- Monad m => RandomGen r => SubGroup q =>- PublicKey q -> ZKP ->- Question q -> [Bool] ->- S.StateT r (ExceptT ErrorAnswer m) (Answer q)+ Reifies c FFC =>+ Monad m => RandomGen r =>+ PublicKey c -> ZKP ->+ Question -> [Bool] ->+ S.StateT r (ExceptT ErrorAnswer m) (Answer c) encryptAnswer elecPubKey zkp Question{..} opinionByChoice | not (question_mini <= opinionsSum && opinionsSum <= question_maxi) = lift $ throwE $- ErrorAnswer_WrongSumOfOpinions- (nat opinionsSum)- (nat question_mini)- (nat question_maxi)+ ErrorAnswer_WrongSumOfOpinions opinionsSum question_mini question_maxi | List.length opinions /= List.length question_choices = lift $ throwE $ ErrorAnswer_WrongNumberOfOpinions@@ -374,12 +394,12 @@ individualProofs <- zipWithM (\opinion -> proveEncryption elecPubKey zkp $ if opinion- then ([booleanDisjunctions List.!!0],[])- else ([],[booleanDisjunctions List.!!1]))+ then (List.init booleanDisjunctions,[])+ else ([],List.tail booleanDisjunctions)) opinionByChoice encryptions sumProof <- proveEncryption elecPubKey zkp (List.tail <$> List.genericSplitAt- (nat (opinionsSum - question_mini))+ (fromJust $ opinionsSum`minusNaturalMaybe`question_mini) (intervalDisjunctions question_mini question_maxi)) ( sum (fst <$> encryptions) -- NOTE: sum the 'encNonce's , sum (snd <$> encryptions) -- NOTE: sum the 'Encryption's@@ -391,13 +411,13 @@ , answer_sumProof = sumProof } where- opinionsSum = sum opinions+ opinionsSum = sum $ nat <$> opinions opinions = (\o -> if o then one else zero) <$> opinionByChoice verifyAnswer ::- SubGroup q =>- PublicKey q -> ZKP ->- Question q -> Answer q -> Bool+ Reifies c FFC =>+ PublicKey c -> ZKP ->+ Question -> Answer c -> Bool verifyAnswer elecPubKey zkp Question{..} Answer{..} | List.length question_choices /= List.length answer_opinions = False | otherwise = either (const False) id $ runExcept $ do@@ -422,36 +442,110 @@ deriving (Eq,Show,Generic,NFData) -- * Type 'Election'-data Election q = Election- { election_name :: Text- , election_description :: Text- , election_PublicKey :: PublicKey q- , election_questions :: [Question q]- , election_uuid :: UUID- , election_hash :: Hash -- TODO: serialize to JSON to calculate this+data Election c = Election+ { election_name :: !Text+ , election_description :: !Text+ , election_crypto :: !(ElectionCrypto c)+ , election_questions :: ![Question]+ , election_uuid :: !UUID+ , election_hash :: !Hash } deriving (Eq,Show,Generic,NFData) +instance ToJSON (Election c) where+ toJSON Election{..} =+ JSON.object+ [ "name" .= election_name+ , "description" .= election_description+ , "public_key" .= election_crypto+ , "questions" .= election_questions+ , "uuid" .= election_uuid+ ]+ toEncoding Election{..} =+ JSON.pairs+ ( "name" .= election_name+ <> "description" .= election_description+ <> "public_key" .= election_crypto+ <> "questions" .= election_questions+ <> "uuid" .= election_uuid+ )+instance FromJSON (Election c) where+ parseJSON = JSON.withObject "Election" $ \o -> Election+ <$> o .: "name"+ <*> o .: "description"+ <*> o .: "public_key"+ <*> o .: "questions"+ <*> o .: "uuid"+ <*> pure (hashJSON (JSON.Object o))++-- ** Type 'ElectionCrypto'+data ElectionCrypto c =+ ElectionCrypto_FFC+ { electionCrypto_FFC_params :: !FFC+ , electionCrypto_FFC_PublicKey :: !(PublicKey c)+ } deriving (Eq,Show,Generic,NFData)++reifyElection :: Election () -> (forall c. Reifies c FFC => Election c -> k) -> k+reifyElection Election{..} k =+ case election_crypto of+ ElectionCrypto_FFC ffc (G (F pubKey)) ->+ reify ffc $ \(_::Proxy c) -> k @c+ Election{election_crypto = ElectionCrypto_FFC ffc (G (F pubKey)), ..}+++instance ToJSON (ElectionCrypto c) where+ toJSON (ElectionCrypto_FFC ffc pubKey) =+ JSON.object+ [ "group" .= ffc+ , "y" .= nat pubKey+ ]+ toEncoding (ElectionCrypto_FFC ffc pubKey) =+ JSON.pairs+ ( "group" .= ffc+ <> "y" .= nat pubKey+ )+instance FromJSON (ElectionCrypto c) where+ parseJSON = JSON.withObject "ElectionCrypto" $ \o -> do+ ffc <- o .: "group"+ pubKey <- reify ffc $ \(_::Proxy s) -> nat <$> ((.:) @(PublicKey s) o "y")+ {-+ unless (nat ffc_groupGen < ffc_fieldCharac) $+ JSON.typeMismatch "FFC: groupGen is not lower than fieldCharac" (JSON.Object o)+ -}+ return $ ElectionCrypto_FFC ffc (G (F pubKey))++ -- ** Type 'Hash' newtype Hash = Hash Text deriving (Eq,Ord,Show,Generic)+ deriving anyclass (ToJSON,FromJSON) deriving newtype NFData +hashJSON :: ToJSON a => a -> Hash+hashJSON = Hash . TL.toStrict . TL.decodeUtf8 . BSL64.encode . JSON.encode++hashElection :: Election c -> Election c+hashElection elec = elec{election_hash=hashJSON elec}+ -- * Type 'Ballot'-data Ballot q = Ballot- { ballot_answers :: [Answer q]- , ballot_signature :: Maybe (Signature q)- , ballot_election_uuid :: UUID- , ballot_election_hash :: Hash+data Ballot c = Ballot+ { ballot_answers :: ![Answer c]+ , ballot_signature :: !(Maybe (Signature c))+ , ballot_election_uuid :: !UUID+ , ballot_election_hash :: !Hash } deriving (Generic,NFData)+deriving instance Reifies c FFC => ToJSON (Ballot c)+deriving instance Reifies c FFC => FromJSON (Ballot c) -- | @('encryptBallot' elec ('Just' ballotSecKey) opinionsByQuest)@ -- returns a 'Ballot' signed by 'secKey' (the voter's secret key) -- where 'opinionsByQuest' is a list of 'Opinion's -- on each 'question_choices' of each 'election_questions'. encryptBallot ::- Monad m => RandomGen r => SubGroup q =>- Election q -> Maybe (SecretKey q) -> [[Bool]] ->- S.StateT r (ExceptT ErrorBallot m) (Ballot q)+ Reifies c FFC =>+ Monad m => RandomGen r =>+ Election c ->+ Maybe (SecretKey c) -> [[Bool]] ->+ S.StateT r (ExceptT ErrorBallot m) (Ballot c) encryptBallot Election{..} ballotSecKeyMay opinionsByQuest | List.length election_questions /= List.length opinionsByQuest = lift $ throwE $@@ -468,7 +562,7 @@ where ballotPubKey = publicKey ballotSecKey ballot_answers <- S.mapStateT (withExceptT ErrorBallot_Answer) $- zipWithM (encryptAnswer election_PublicKey voterZKP)+ zipWithM (encryptAnswer (electionCrypto_FFC_PublicKey election_crypto) voterZKP) election_questions opinionsByQuest ballot_signature <- case voterKeys of Nothing -> return Nothing@@ -490,8 +584,9 @@ , ballot_signature } -verifyBallot :: SubGroup q => Election q -> Ballot q -> Bool+verifyBallot :: Reifies c FFC => Election c -> Ballot c -> Bool verifyBallot Election{..} Ballot{..} =+ let elecPubKey = electionCrypto_FFC_PublicKey election_crypto in ballot_election_uuid == election_uuid && ballot_election_hash == election_hash && List.length election_questions == List.length ballot_answers &&@@ -506,7 +601,7 @@ (signatureStatement ballot_answers) in and $ isValidSign :- List.zipWith (verifyAnswer election_PublicKey zkpSign)+ List.zipWith (verifyAnswer elecPubKey zkpSign) election_questions ballot_answers -- ** Type 'Signature'@@ -515,25 +610,27 @@ -- Used by each voter to sign his/her encrypted 'Ballot' -- using his/her 'Credential', -- in order to avoid ballot stuffing.-data Signature q = Signature- { signature_publicKey :: PublicKey q+data Signature c = Signature+ { signature_publicKey :: !(PublicKey c) -- ^ Verification key.- , signature_proof :: Proof q+ , signature_proof :: !(Proof c) } deriving (Generic,NFData)+deriving instance Reifies c FFC => ToJSON (Signature c)+deriving instance Reifies c FFC => FromJSON (Signature c) -- *** Hashing -- | @('signatureStatement' answers)@ -- returns the encrypted material to be signed: -- all the 'encryption_nonce's and 'encryption_vault's of the given @answers@.-signatureStatement :: Foldable f => SubGroup q => f (Answer q) -> [G q]+signatureStatement :: Reifies c FFC => Foldable f => f (Answer c) -> [G c] signatureStatement = foldMap $ \Answer{..} -> (`foldMap` answer_opinions) $ \(Encryption{..}, _proof) -> [encryption_nonce, encryption_vault] -- | @('signatureCommitments' voterZKP commitment)@-signatureCommitments :: SubGroup q => ZKP -> Commitment q -> BS.ByteString+signatureCommitments :: ZKP -> Commitment c -> BS.ByteString signatureCommitments (ZKP voterZKP) commitment = "sig|"<>voterZKP<>"|" -- NOTE: this is actually part of the statement <> bytesNat commitment<>"|"
+ src/Voting/Protocol/FFC.hs view
@@ -0,0 +1,415 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE UndecidableInstances #-} -- for Reifies instances+{-# OPTIONS_GHC -fno-warn-orphans #-}+-- | Finite Field Cryptography (FFC)+-- is a method of implementing discrete logarithm cryptography+-- using finite field mathematics.+module Voting.Protocol.FFC+ ( module Voting.Protocol.FFC+ , Natural+ , Random.RandomGen+ , Reifies(..), reify+ , Proxy(..)+ ) where++import Control.Arrow (first)+import Control.Applicative (Applicative(..))+import Control.DeepSeq (NFData)+import Control.Monad (Monad(..), unless)+import Control.Monad.Trans.Reader (ReaderT(..), asks)+import Control.Monad.Trans.Class (MonadTrans(..))+import Data.Aeson (ToJSON(..),FromJSON(..),(.:),(.:?),(.=))+import Data.Bits+import Data.Bool+import Data.Eq (Eq(..))+import Data.Foldable (Foldable, foldl')+import Data.Function (($), (.), id)+import Data.Functor ((<$>))+import Data.Int (Int)+import Data.Maybe (Maybe(..), fromMaybe, fromJust)+import Data.Ord (Ord(..))+import Data.Proxy (Proxy(..))+import Data.Reflection (Reifies(..), reify)+import Data.Semigroup (Semigroup(..))+import Data.String (IsString(..))+import Data.Text (Text)+import GHC.Generics (Generic)+import GHC.Natural (minusNaturalMaybe)+import Numeric.Natural (Natural)+import Prelude (Integer, Integral(..), fromIntegral, Enum(..))+import Text.Read (readMaybe)+import Text.Show (Show(..))+import qualified Control.Monad.Trans.State.Strict as S+import qualified Crypto.Hash as Crypto+import qualified Data.Aeson as JSON+import qualified Data.Aeson.Types as JSON+import qualified Data.ByteArray as ByteArray+import qualified Data.ByteString as BS+import qualified Data.Char as Char+import qualified Data.List as List+import qualified Data.Text as Text+import qualified Prelude as Num+import qualified System.Random as Random++-- * Type 'FFC'+-- | Mutiplicative Sub-Group of a Finite Prime Field.+--+-- NOTE: an 'FFC' term-value is brought into the context of many functions+-- through a type-variable @c@ whose 'Reifies' constraint enables to 'reflect'+-- that 'FFC' at the term-level (a surprising technique but a very useful one).+-- Doing like this is simpler than working in a 'Monad' (like a 'Reader'),+-- and enables that 'FFC' term to be used simply in instances' methods+-- not supporting an inner 'Monad', like 'parseJSON', 'randomR', 'fromEnum' or 'arbitrary'.+-- Aside from that, the sharing of 'FFC' amongst several types+-- is encoded at the type-level by including @c@+-- as a phantom type of 'F', 'G' and 'E'.+data FFC = FFC+ { ffc_name :: Text+ , ffc_fieldCharac :: !Natural+ -- ^ The prime number characteristic of a Finite Prime Field.+ --+ -- ElGamal's hardness to decrypt requires a large prime number+ -- to form the 'Multiplicative' subgroup.+ , ffc_groupGen :: !Natural+ -- ^ A generator of the 'Multiplicative' subgroup of the Finite Prime Field.+ --+ -- NOTE: since 'ffc_fieldCharac' is prime,+ -- the 'Multiplicative' subgroup is cyclic,+ -- and there are phi('fieldCharac'-1) many choices for the generator of the group,+ -- where phi is the Euler totient function.+ , ffc_groupOrder :: !Natural+ -- ^ The order of the subgroup.+ --+ -- WARNING: 'ffc_groupOrder' MUST be a prime number dividing @('ffc_fieldCharac'-1)@+ -- to ensure that ElGamal is secure in terms of the DDH assumption.+ } deriving (Eq,Show,Generic,NFData)+deriving instance ToJSON FFC+instance FromJSON FFC where+ parseJSON = JSON.withObject "FFC" $ \o -> do+ ffc_name <- fromMaybe "" <$> (o .:? "name")+ ffc_fieldCharac <- o .: "p"+ ffc_groupGen <- o .: "g"+ ffc_groupOrder <- o .: "q"+ -- TODO: check p is probable prime+ -- TODO: check q is probable prime+ unless (nat ffc_groupGen < ffc_fieldCharac) $+ JSON.typeMismatch "FFC: groupGen is not lower than fieldCharac" (JSON.Object o)+ unless (ffc_groupOrder < ffc_fieldCharac) $+ JSON.typeMismatch "FFC: groupOrder is not lower than fieldCharac" (JSON.Object o)+ unless (nat ffc_groupGen > 1) $+ JSON.typeMismatch "FFC: groupGen is not greater than 1" (JSON.Object o)+ unless (fromJust (ffc_fieldCharac`minusNaturalMaybe`one) `rem` ffc_groupOrder == 0) $+ JSON.typeMismatch "FFC: groupOrder does not divide fieldCharac-1" (JSON.Object o)+ return FFC{..}++fieldCharac :: forall c. Reifies c FFC => Natural+fieldCharac = ffc_fieldCharac (reflect (Proxy::Proxy c))++groupGen :: forall c. Reifies c FFC => G c+groupGen = G $ F $ ffc_groupGen (reflect (Proxy::Proxy c))++groupOrder :: forall c. Reifies c FFC => Natural+groupOrder = ffc_groupOrder (reflect (Proxy::Proxy c))++-- ** Examples+-- | Weak parameters for debugging purposes only.+weakFFC :: FFC+weakFFC = FFC+ { ffc_name = "weakFFC"+ , ffc_fieldCharac = 263+ , ffc_groupGen = 2+ , ffc_groupOrder = 131+ }++-- | Parameters used in Belenios.+-- A 2048-bit 'fieldCharac' of a Finite Prime Field,+-- with a 256-bit 'groupOrder' for a 'Multiplicative' subgroup+-- generated by 'groupGen'.+beleniosFFC :: FFC+beleniosFFC = FFC+ { ffc_name = "beleniosFFC"+ , ffc_fieldCharac = 20694785691422546401013643657505008064922989295751104097100884787057374219242717401922237254497684338129066633138078958404960054389636289796393038773905722803605973749427671376777618898589872735865049081167099310535867780980030790491654063777173764198678527273474476341835600035698305193144284561701911000786737307333564123971732897913240474578834468260652327974647951137672658693582180046317922073668860052627186363386088796882120769432366149491002923444346373222145884100586421050242120365433561201320481118852408731077014151666200162313177169372189248078507711827842317498073276598828825169183103125680162072880719+ , ffc_groupGen = 2402352677501852209227687703532399932712287657378364916510075318787663274146353219320285676155269678799694668298749389095083896573425601900601068477164491735474137283104610458681314511781646755400527402889846139864532661215055797097162016168270312886432456663834863635782106154918419982534315189740658186868651151358576410138882215396016043228843603930989333662772848406593138406010231675095763777982665103606822406635076697764025346253773085133173495194248967754052573659049492477631475991575198775177711481490920456600205478127054728238140972518639858334115700568353695553423781475582491896050296680037745308460627+ , ffc_groupOrder = 78571733251071885079927659812671450121821421258408794611510081919805623223441+ }++-- * Type 'F'+-- | The type of the elements of a Finite Prime Field.+--+-- A field must satisfy the following properties:+--+-- * @(f, ('+'), 'zero')@ forms an abelian group,+-- called the 'Additive' group of 'f'.+--+-- * @('NonNull' f, ('*'), 'one')@ forms an abelian group,+-- called the 'Multiplicative' group of 'f'.+--+-- * ('*') is associative:+-- @(a'*'b)'*'c == a'*'(b'*'c)@ and+-- @a'*'(b'*'c) == (a'*'b)'*'c@.+--+-- * ('*') and ('+') are both commutative:+-- @a'*'b == b'*'a@ and+-- @a'+'b == b'+'a@+--+-- * ('*') and ('+') are both left and right distributive:+-- @a'*'(b'+'c) == (a'*'b) '+' (a'*'c)@ and+-- @(a'+'b)'*'c == (a'*'c) '+' (b'*'c)@+--+-- The 'Natural' is always within @[0..'fieldCharac'-1]@.+newtype F c = F { unF :: Natural }+ deriving (Eq,Ord,Show)+ deriving newtype NFData+instance ToJSON (F c) where+ toJSON (F x) = JSON.toJSON (show x)+instance Reifies c FFC => FromJSON (F c) where+ parseJSON (JSON.String s)+ | Just (c0,_) <- Text.uncons s+ , c0 /= '0'+ , Text.all Char.isDigit s+ , Just x <- readMaybe (Text.unpack s)+ , x < fieldCharac @c+ = return (F x)+ parseJSON json = JSON.typeMismatch "F" json+instance Reifies c FFC => FromNatural (F c) where+ fromNatural i = F $ abs $ i `mod` fieldCharac @c+ where+ abs x | x < 0 = x + fieldCharac @c+ | otherwise = x+instance ToNatural (F c) where+ nat = unF+instance Reifies c FFC => Additive (F c) where+ zero = F 0+ F x + F y = F $ (x + y) `mod` fieldCharac @c+instance Reifies c FFC => Negable (F c) where+ neg (F x)+ | x == 0 = zero+ | otherwise = F $ fromJust $ nat (fieldCharac @c)`minusNaturalMaybe`x+instance Reifies c FFC => Multiplicative (F c) where+ one = F 1+ F x * F y = F $ (x * y) `mod` fieldCharac @c+instance Reifies c FFC => Random.Random (F c) where+ randomR (F lo, F hi) =+ first (F . fromIntegral) .+ Random.randomR+ ( 0`max`toInteger lo+ , toInteger hi`min`(toInteger (fieldCharac @c) - 1) )+ random =+ first (F . fromIntegral) .+ Random.randomR (0, toInteger (fieldCharac @c) - 1)++-- ** Class 'Additive'+class Additive a where+ zero :: a+ (+) :: a -> a -> a; infixl 6 ++ sum :: Foldable f => f a -> a+ sum = foldl' (+) zero+instance Additive Natural where+ zero = 0+ (+) = (Num.+)+instance Additive Integer where+ zero = 0+ (+) = (Num.+)+instance Additive Int where+ zero = 0+ (+) = (Num.+)++-- *** Class 'Negable'+class Additive a => Negable a where+ neg :: a -> a+ (-) :: a -> a -> a; infixl 6 -+ x-y = x + neg y+instance Negable Integer where+ neg = Num.negate+instance Negable Int where+ neg = Num.negate++-- ** Class 'Multiplicative'+class Multiplicative a where+ one :: a+ (*) :: a -> a -> a; infixl 7 *+instance Multiplicative Natural where+ one = 1+ (*) = (Num.*)+instance Multiplicative Integer where+ one = 1+ (*) = (Num.*)+instance Multiplicative Int where+ one = 1+ (*) = (Num.*)++-- ** Class 'Invertible'+class Multiplicative a => Invertible a where+ inv :: a -> a+ (/) :: a -> a -> a; infixl 7 /+ x/y = x * inv y++-- * Type 'G'+-- | The type of the elements of a 'Multiplicative' subgroup of a Finite Prime Field.+newtype G c = G { unG :: F c }+ deriving (Eq,Ord,Show)+ deriving newtype NFData+instance ToJSON (G c) where+ toJSON (G x) = JSON.toJSON x+instance Reifies c FFC => FromJSON (G c) where+ parseJSON (JSON.String s)+ | Just (c0,_) <- Text.uncons s+ , c0 /= '0'+ , Text.all Char.isDigit s+ , Just x <- readMaybe (Text.unpack s)+ , x < fieldCharac @c+ , r <- G (F x)+ , r ^ E (groupOrder @c) == one+ = return r+ parseJSON json = JSON.typeMismatch "G" json+instance Reifies c FFC => FromNatural (G c) where+ fromNatural = G . fromNatural+instance ToNatural (G c) where+ nat = unF . unG+instance Reifies c FFC => Multiplicative (G c) where+ one = G $ F one+ G x * G y = G (x * y)+instance Reifies c FFC => Invertible (G c) where+ -- | NOTE: add 'groupOrder' so the exponent given to (^) is positive.+ inv = (^ E (fromJust $ groupOrder @c`minusNaturalMaybe`1))++-- | 'groupGenInverses' returns the infinite list+-- of 'inv'erse powers of 'groupGen':+-- @['groupGen' '^' 'neg' i | i <- [0..]]@,+-- but by computing each value from the previous one.+--+-- Used by 'intervalDisjunctions'.+groupGenInverses :: forall c. Reifies c FFC => [G c]+groupGenInverses = go one+ where+ invGen = inv $ groupGen @c+ go g = g : go (g * invGen)++groupGenPowers :: forall c. Reifies c FFC => [G c]+groupGenPowers = go one+ where go g = g : go (g * groupGen @c)++-- | @('hash' bs gs)@ returns as a number in 'E'+-- the SHA256 of the given 'BS.ByteString' 'bs'+-- prefixing the decimal representation of given subgroup elements 'gs',+-- with a comma (",") intercalated between them.+--+-- NOTE: to avoid any collision when the 'hash' function is used in different contexts,+-- a message 'gs' is actually prefixed by a 'bs' indicating the context.+--+-- Used by 'proveEncryption' and 'verifyEncryption',+-- where the 'bs' usually contains the 'statement' to be proven,+-- and the 'gs' contains the 'commitments'.+hash :: Reifies c FFC => BS.ByteString -> [G c] -> E c+hash bs gs = do+ let s = bs <> BS.intercalate (fromString ",") (bytesNat <$> gs)+ let h = ByteArray.convert (Crypto.hashWith Crypto.SHA256 s)+ fromNatural (BS.foldl' (\acc b -> acc`shiftL`3 + fromIntegral b) (0::Natural) h)++-- * Type 'E'+-- | An exponent of a (necessarily cyclic) subgroup of a Finite Prime Field.+-- The value is always in @[0..'groupOrder'-1]@.+newtype E c = E { unE :: Natural }+ deriving (Eq,Ord,Show)+ deriving newtype NFData+instance ToJSON (E c) where+ toJSON (E x) = JSON.toJSON x+instance Reifies c FFC => FromJSON (E c) where+ parseJSON (JSON.String s)+ | Just (c0,_) <- Text.uncons s+ , c0 /= '0'+ , Text.all Char.isDigit s+ , Just x <- readMaybe (Text.unpack s)+ , x < groupOrder @c+ = return (E x)+ parseJSON json = JSON.typeMismatch "E" json++instance Reifies c FFC => FromNatural (E c) where+ fromNatural i =+ E $ abs $ i `mod` groupOrder @c+ where+ abs x | x < 0 = x + groupOrder @c+ | otherwise = x+instance ToNatural (E c) where+ nat = unE++instance Reifies c FFC => Additive (E c) where+ zero = E zero+ E x + E y = E $ (x + y) `mod` groupOrder @c+instance Reifies c FFC => Negable (E c) where+ neg (E x)+ | x == 0 = zero+ | otherwise = E $ fromJust $ nat (groupOrder @c)`minusNaturalMaybe`x+instance Reifies c FFC => Multiplicative (E c) where+ one = E one+ E x * E y = E $ (x * y) `mod` groupOrder @c+instance Reifies c FFC => Random.Random (E c) where+ randomR (E lo, E hi) =+ first (E . fromIntegral) .+ Random.randomR+ ( 0`max`toInteger lo+ , toInteger hi`min`(toInteger (groupOrder @c) - 1) )+ random =+ first (E . fromIntegral) .+ Random.randomR (0, toInteger (groupOrder @c) - 1)+instance Reifies c FFC => Enum (E c) where+ toEnum = fromNatural . fromIntegral+ fromEnum = fromIntegral . nat+ enumFromTo lo hi = List.unfoldr+ (\i -> if i<=hi then Just (i, i+one) else Nothing) lo++infixr 8 ^+-- | @(b '^' e)@ returns the modular exponentiation of base 'b' by exponent 'e'.+(^) :: Reifies c FFC => G c -> E c -> G c+(^) b (E e)+ | e == 0 = one+ | otherwise = t * (b*b) ^ E (e`shiftR`1)+ where+ t | testBit e 0 = b+ | otherwise = one++-- | @('randomR' i)@ returns a random integer in @[0..i-1]@.+randomR ::+ Monad m =>+ Random.RandomGen r =>+ Random.Random i =>+ Negable i =>+ Multiplicative i =>+ i -> S.StateT r m i+randomR i = S.StateT $ return . Random.randomR (zero, i-one)++-- | @('random')@ returns a random integer+-- in the range determined by its type.+random ::+ Monad m =>+ Random.RandomGen r =>+ Random.Random i =>+ Negable i =>+ Multiplicative i =>+ S.StateT r m i+random = S.StateT $ return . Random.random++instance Random.Random Natural where+ randomR (mini,maxi) =+ first (fromIntegral::Integer -> Natural) .+ Random.randomR (fromIntegral mini, fromIntegral maxi)+ random = first (fromIntegral::Integer -> Natural) . Random.random++-- * Conversions++-- ** Class 'FromNatural'+class FromNatural a where+ fromNatural :: Natural -> a++-- ** Class 'ToNatural'+class ToNatural a where+ nat :: a -> Natural+instance ToNatural Natural where+ nat = id++-- | @('bytesNat' x)@ returns the serialization of 'x'.+bytesNat :: ToNatural n => n -> BS.ByteString+bytesNat = fromString . show . nat
src/Voting/Protocol/Tally.hs view
@@ -1,18 +1,19 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE UndecidableInstances #-} -- for Reifies instances 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.Aeson (ToJSON(..),FromJSON(..)) 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 Data.Tuple (fst) import GHC.Generics (Generic) import Numeric.Natural (Natural) import Prelude (fromIntegral)@@ -23,103 +24,97 @@ import qualified Data.Map.Strict as Map import Voting.Protocol.Utils-import Voting.Protocol.Arithmetic+import Voting.Protocol.FFC import Voting.Protocol.Credential import Voting.Protocol.Election -- * Type 'Tally'-data Tally q = Tally- { tally_countMax :: Natural+data Tally c = 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+ , tally_encByChoiceByQuest :: !(EncryptedTally c) -- ^ 'Encryption' by 'Question' by 'Ballot'.- , tally_decShareByTrustee :: [DecryptionShare q]+ , tally_decShareByTrustee :: ![DecryptionShare c] -- ^ 'DecryptionShare' by trustee.- , tally_countByChoiceByQuest :: [[Natural]]+ , tally_countByChoiceByQuest :: ![[Natural]] -- ^ The decrypted count of supportive 'Opinion's, by choice by 'Question'. } deriving (Eq,Show,Generic,NFData)+deriving instance Reifies c FFC => ToJSON (Tally c)+deriving instance Reifies c FFC => FromJSON (Tally c) -- ** Type 'EncryptedTally'--- | 'Encryption' by 'Choice' by 'Question'.-type EncryptedTally q = [[Encryption q]]+-- | 'Encryption' by choice by 'Question'.+type EncryptedTally c = [[Encryption c]] -- | @('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 :: Reifies c FFC => [Ballot c] -> (EncryptedTally c, Natural) encryptedTally ballots = ( List.foldr (\Ballot{..} -> 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]]+type DecryptionShareCombinator c =+ EncryptedTally c -> [DecryptionShare c] -> Except ErrorTally [[DecryptionFactor c]] proveTally ::- SubGroup q =>- (EncryptedTally q, Natural) -> [DecryptionShare q] ->- DecryptionShareCombinator q ->- Except ErrorDecryptionShare (Tally q)+ Reifies c FFC =>+ (EncryptedTally c, Natural) -> [DecryptionShare c] ->+ DecryptionShareCombinator c ->+ Except ErrorTally (Tally c) 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 ()+ Reifies c FFC =>+ Tally c -> DecryptionShareCombinator c ->+ 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 c = [[(DecryptionFactor c, Proof c)]] -- *** Type 'DecryptionFactor' -- | @'encryption_nonce' '^'trusteeSecKey@@@ -127,33 +122,37 @@ -- @('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)+ Monad m => Reifies c FFC => RandomGen r =>+ EncryptedTally c -> SecretKey c -> S.StateT r m (DecryptionShare c)+proveDecryptionShare encByChoiceByQuest trusteeSecKey =+ (proveDecryptionFactor trusteeSecKey `mapM`) `mapM` encByChoiceByQuest proveDecryptionFactor ::- Monad m => SubGroup q => RandomGen r =>- SecretKey q -> Encryption q -> S.StateT r m (DecryptionFactor q, Proof q)+ Monad m => Reifies c FFC => RandomGen r =>+ SecretKey c -> Encryption c -> S.StateT r m (DecryptionFactor c, Proof c) 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 :: Reifies c FFC => PublicKey c -> 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+-- *** 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)@@@ -161,27 +160,24 @@ -- (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{..} =+ Monad m => Reifies c FFC =>+ EncryptedTally c -> PublicKey c -> DecryptionShare c ->+ 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 ()+ Monad m => Reifies c FFC =>+ EncryptedTally c -> [PublicKey c] -> [DecryptionShare c] ->+ ExceptT ErrorTally m () verifyDecryptionShareByTrustee encTally =- isoZipWithM_ (throwE $ ErrorDecryptionShare_Invalid "verifyDecryptionShare")+ isoZipWithM_ (throwE ErrorTally_NumberOfTrustees) (verifyDecryptionShare encTally)
src/Voting/Protocol/Trustee/Indispensable.hs view
@@ -1,27 +1,35 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE UndecidableInstances #-} -- for Reifies instances module Voting.Protocol.Trustee.Indispensable where +import Control.DeepSeq (NFData) import Control.Monad (Monad(..), foldM, unless) import Control.Monad.Trans.Except (ExceptT(..), throwE)+import Data.Aeson (ToJSON(..),FromJSON(..)) import Data.Eq (Eq(..)) import Data.Function (($))+import Data.Functor ((<$>)) import Data.Maybe (maybe) import Data.Semigroup (Semigroup(..))+import Data.Tuple (fst)+import GHC.Generics (Generic) 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.FFC 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+data TrusteePublicKey c = TrusteePublicKey+ { trustee_PublicKey :: !(PublicKey c)+ , trustee_SecretKeyProof :: !(Proof c) -- ^ NOTE: It is important to ensure -- that each trustee generates its key pair independently -- of the 'PublicKey's published by the other trustees.@@ -35,11 +43,13 @@ -- must 'prove' knowledge of the corresponding 'SecretKey'. -- Which is done in 'proveIndispensableTrusteePublicKey' -- and 'verifyIndispensableTrusteePublicKey'.- } deriving (Eq,Show)+ } deriving (Eq,Show,Generic,NFData)+deriving instance Reifies c FFC => ToJSON (TrusteePublicKey c)+deriving instance Reifies c FFC => FromJSON (TrusteePublicKey c) -- ** Type 'ErrorTrusteePublicKey' data ErrorTrusteePublicKey- = ErrorTrusteePublicKey_Wrong+ = ErrorTrusteePublicKey_WrongProof -- ^ The 'trustee_SecretKeyProof' is wrong. deriving (Eq,Show) @@ -47,8 +57,8 @@ -- 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)+ Reifies c FFC => Monad m => RandomGen r =>+ SecretKey c -> S.StateT r m (TrusteePublicKey c) proveIndispensableTrusteePublicKey trustSecKey = do let trustee_PublicKey = publicKey trustSecKey trustee_SecretKeyProof <-@@ -61,46 +71,52 @@ -- does 'prove' that the 'SecretKey' associated with -- the given 'trustee_PublicKey' is known by the trustee. verifyIndispensableTrusteePublicKey ::- Monad m => SubGroup q =>- TrusteePublicKey q ->+ Reifies c FFC => Monad m =>+ TrusteePublicKey c -> ExceptT ErrorTrusteePublicKey m () verifyIndispensableTrusteePublicKey TrusteePublicKey{..} = unless ((proof_challenge trustee_SecretKeyProof ==) $ hash (indispensableTrusteePublicKeyStatement trustee_PublicKey) [commit trustee_SecretKeyProof groupGen trustee_PublicKey]) $- throwE ErrorTrusteePublicKey_Wrong+ throwE ErrorTrusteePublicKey_WrongProof -- ** Hashing-indispensableTrusteePublicKeyStatement :: PublicKey q -> BS.ByteString-indispensableTrusteePublicKeyStatement trustPubKey = "pok|"<>bytesNat trustPubKey<>"|"+indispensableTrusteePublicKeyStatement :: PublicKey c -> BS.ByteString+indispensableTrusteePublicKeyStatement trustPubKey =+ "pok|"<>bytesNat trustPubKey<>"|" -- * 'Election''s 'PublicKey' combineIndispensableTrusteePublicKeys ::- SubGroup q => [TrusteePublicKey q] -> PublicKey q+ Reifies c FFC => [TrusteePublicKey c] -> PublicKey c 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)+ Reifies c FFC => Monad m =>+ EncryptedTally c -> [PublicKey c] -> [DecryptionShare c] ->+ 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"+ Reifies c FFC => [PublicKey c] -> DecryptionShareCombinator c+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
src/Voting/Protocol/Utils.hs view
@@ -10,6 +10,12 @@ import Data.Traversable (Traversable(..)) import qualified Data.List as List +-- | Like ('.') but with two arguments.+o2 :: (c -> d) -> (a -> b -> c) -> a -> b -> d+o2 f g = \x y -> f (g x y)+infixr 9 `o2`+{-# INLINE o2 #-}+ -- | NOTE: check the lengths before applying @f@. isoZipWith :: (a->b->c) -> [a]->[b]->Maybe [c] isoZipWith f as bs@@ -25,38 +31,29 @@ where al = List.length as isoZipWithM ::- Applicative m =>- m () ->- (a -> b -> m c) ->- [a] -> [b] -> m [c]+ Applicative f =>+ f () -> (a->b->f c) -> [a]->[b]->f [c] isoZipWithM err f as bs = maybe ([] <$ err) sequenceA $ isoZipWith f as bs isoZipWithM_ ::- Applicative m =>- m () ->- (a -> b -> m c) ->- [a] -> [b] -> m ()+ Applicative f =>+ f () -> (a->b->f c) -> [a]->[b]->f () isoZipWithM_ err f as bs = maybe err sequenceA_ $ isoZipWith f as bs isoZipWith3M ::- Applicative m =>- m () ->- (a -> b -> c -> m d) ->- [a] -> [b] -> [c] -> m [d]+ Applicative f =>+ f () -> (a->b->c->f d) -> [a]->[b]->[c]->f [d] isoZipWith3M err f as bs cs = maybe ([] <$ err) sequenceA $ isoZipWith3 f as bs cs isoZipWith3M_ ::- Applicative m =>- m () ->- (a -> b -> c -> m d) ->- [a] -> [b] -> [c] ->- m ()+ Applicative f =>+ f () -> (a->b->c->f d) -> [a]->[b]->[c]->f () isoZipWith3M_ err f as bs cs = maybe err sequenceA_ $ isoZipWith3 f as bs cs
stack.yaml view
@@ -1,4 +1,4 @@-resolver: lts-12.26+resolver: lts-13.19 packages: - '.' - location: '../hjugement'
tests/HUnit.hs view
@@ -1,6 +1,6 @@ module HUnit where import Test.Tasty-import qualified HUnit.Arithmetic+import qualified HUnit.FFC import qualified HUnit.Credential import qualified HUnit.Election import qualified HUnit.Trustee@@ -8,7 +8,7 @@ hunits :: TestTree hunits = testGroup "HUnit"- [ HUnit.Arithmetic.hunit+ [ HUnit.FFC.hunit , HUnit.Credential.hunit , HUnit.Election.hunit , HUnit.Trustee.hunit
− tests/HUnit/Arithmetic.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE OverloadedStrings #-}-module HUnit.Arithmetic where--import Test.Tasty.HUnit-import Voting.Protocol-import Utils--hunit :: TestTree-hunit = testGroup "Arithmetic"- [ testGroup "inv"- [ testGroup "WeakParams"- [ testCase "groupGen" $- inv (groupGen @WeakParams) @?=- groupGen ^ E (groupOrder @WeakParams + neg one)- ]- , testGroup "BeleniosParams"- [ testCase "groupGen" $- inv (groupGen @BeleniosParams) @?=- groupGen ^ E (groupOrder @BeleniosParams + neg one)- ]- ]- , testGroup "hash"- [ testGroup "WeakParams"- [ testCase "[groupGen]" $- hash "start" [groupGen @WeakParams] @?=- fromNatural 100- , testCase "[groupGen, groupGen]" $- hash "start" [groupGen @WeakParams, groupGen] @?=- fromNatural 16- ]- , testGroup "BeleniosParams"- [ testCase "[groupGen]" $- hash "start" [groupGen @BeleniosParams] @?=- fromNatural 1832875488615060263192702367259- , testCase "[groupGen, groupGen]" $- hash "start" [groupGen @BeleniosParams, groupGen] @?=- fromNatural 2495277906542783643199702546512- ]- ]- ]
tests/HUnit/Credential.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE OverloadedStrings #-} module HUnit.Credential where @@ -25,29 +24,30 @@ , testGroup "readCredential" $ let (==>) inp exp = testCase (show inp) $ readCredential inp @?= exp in- [ "" ==> Left CredentialError_Length- , "xLcs7ev6Jy6FH_E" ==> Left (CredentialError_BadChar '_')- , "xLcs7ev6Jy6FHIE" ==> Left (CredentialError_BadChar 'I')- , "xLcs7ev6Jy6FH0E" ==> Left (CredentialError_BadChar '0')- , "xLcs7ev6Jy6FHOE" ==> Left (CredentialError_BadChar 'O')- , "xLcs7ev6Jy6FHlE" ==> Left (CredentialError_BadChar 'l')- , "xLcs7ev6Jy6FH6" ==> Left CredentialError_Length- , "xLcs7ev6Jy6FHHy1" ==> Left CredentialError_Length- , "xLcs7ev6Jy6FHHF" ==> Left CredentialError_Checksum+ [ "" ==> Left ErrorToken_Length+ , "xLcs7ev6Jy6FH_E" ==> Left (ErrorToken_BadChar '_')+ , "xLcs7ev6Jy6FHIE" ==> Left (ErrorToken_BadChar 'I')+ , "xLcs7ev6Jy6FH0E" ==> Left (ErrorToken_BadChar '0')+ , "xLcs7ev6Jy6FHOE" ==> Left (ErrorToken_BadChar 'O')+ , "xLcs7ev6Jy6FHlE" ==> Left (ErrorToken_BadChar 'l')+ , "xLcs7ev6Jy6FH6" ==> Left ErrorToken_Length+ , "xLcs7ev6Jy6FHHy1" ==> Left ErrorToken_Length+ , "xLcs7ev6Jy6FHHF" ==> Left ErrorToken_Checksum , "xLcs7ev6Jy6FHHE" ==> Right (Credential "xLcs7ev6Jy6FHHE") ] , testGroup "credentialSecretKey" $- [ testSecretKey @WeakParams 0 $ E (F 122)- , testSecretKey @WeakParams 1 $ E (F 35)- , testSecretKey @BeleniosParams 0 $ E (F 2317630607062989137269685509390)- , testSecretKey @BeleniosParams 1 $ E (F 1968146140481358915910346867611)+ [ testSecretKey weakFFC 0 122+ , testSecretKey weakFFC 1 35+ , testSecretKey beleniosFFC 0 2317630607062989137269685509390+ , testSecretKey beleniosFFC 1 1968146140481358915910346867611 ] ] -testSecretKey :: forall q. SubGroup q => Int -> E q -> TestTree-testSecretKey seed exp =+testSecretKey :: FFC -> Int -> Natural -> TestTree+testSecretKey ffc seed exp =+ reify ffc $ \(Proxy::Proxy c) -> let (uuid@(UUID u), cred@(Credential c)) = (`S.evalState` Random.mkStdGen seed) $ (,) <$> randomUUID <*> randomCredential in testCase (show (u,c)) $- credentialSecretKey @q uuid cred @?= exp+ credentialSecretKey @c uuid cred @?= E exp
tests/HUnit/Election.hs view
@@ -1,11 +1,12 @@-{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} module HUnit.Election where import Test.Tasty.HUnit+import qualified Data.Aeson as JSON import qualified Data.List as List+import qualified Data.Text as Text import qualified System.Random as Random import Voting.Protocol@@ -16,54 +17,56 @@ hunit = testGroup "Election" [ testGroup "groupGenInverses" [ testCase "WeakParams" $- List.take 10 (groupGenInverses @WeakParams) @?=- [groupGen^neg (fromNatural n) | n <- [0..9]]+ reify weakFFC $ \(Proxy::Proxy c) ->+ List.take 10 (groupGenInverses @c) @?=+ [groupGen^neg (fromNatural n) | n <- [0..9]] , testCase "BeleniosParams" $- List.take 10 (groupGenInverses @BeleniosParams) @?=- [groupGen^neg (fromNatural n) | n <- [0..9]]+ reify beleniosFFC $ \(Proxy::Proxy c) ->+ List.take 10 (groupGenInverses @c) @?=+ [groupGen^neg (fromNatural n) | n <- [0..9]] ] , testGroup "encryptBallot" $- [ testsEncryptBallot @WeakParams- , testsEncryptBallot @BeleniosParams+ [ testsEncryptBallot weakFFC+ , testsEncryptBallot beleniosFFC ] ] -testsEncryptBallot :: forall q. Params q => TestTree-testsEncryptBallot =- testGroup (paramsName @q)- [ testEncryptBallot @q 0+testsEncryptBallot :: FFC -> TestTree+testsEncryptBallot ffc =+ testGroup (Text.unpack $ ffc_name ffc)+ [ testEncryptBallot ffc 0 [Question "q1" ["a1","a2","a3"] zero one] [[True, False, False]] (Right True)- , testEncryptBallot @q 0+ , testEncryptBallot ffc 0 [Question "q1" ["a1","a2","a3"] zero one] [[False, False, False]] (Right True)- , testEncryptBallot @q 0+ , testEncryptBallot ffc 0 [Question "q1" ["a1","a2","a3"] zero one] [[False, False, False]] (Right True)- , testEncryptBallot @q 0+ , testEncryptBallot ffc 0 [Question "q1" [] zero one] [] (Left (ErrorBallot_WrongNumberOfAnswers 0 1))- , testEncryptBallot @q 0+ , testEncryptBallot ffc 0 [Question "q1" ["a1","a2"] one one] [[True]] (Left (ErrorBallot_Answer (ErrorAnswer_WrongNumberOfOpinions 1 2)))- , testEncryptBallot @q 0+ , testEncryptBallot ffc 0 [Question "q1" ["a1","a2","a3"] zero one] [[True, True, False]] (Left (ErrorBallot_Answer (ErrorAnswer_WrongSumOfOpinions 2 0 1)))- , testEncryptBallot @q 0+ , testEncryptBallot ffc 0 [Question "q1" ["a1","a2","a3"] one one] [[False, False, False]] (Left (ErrorBallot_Answer (ErrorAnswer_WrongSumOfOpinions 0 1 1)))- , testEncryptBallot @q 0+ , testEncryptBallot ffc 0 [Question "q1" ["a1","a2"] one one] [[False, False, True]] (Left (ErrorBallot_Answer (ErrorAnswer_WrongNumberOfOpinions 3 2)))- , testEncryptBallot @q 0+ , testEncryptBallot ffc 0 [ Question "q1" ["a11","a12","a13"] zero (one+one) , Question "q2" ["a21","a22","a23"] one one ]@@ -73,25 +76,25 @@ ] testEncryptBallot ::- forall q. SubGroup q =>- Int -> [Question q] -> [[Bool]] ->+ FFC -> Int -> [Question] -> [[Bool]] -> Either ErrorBallot Bool -> TestTree-testEncryptBallot seed quests opins exp =+testEncryptBallot ffc seed quests opins exp = let got =+ reify ffc $ \(Proxy::Proxy c) -> runExcept $ (`evalStateT` Random.mkStdGen seed) $ do uuid <- randomUUID cred <- randomCredential- let ballotSecKey = credentialSecretKey @q uuid cred+ let ballotSecKey = credentialSecretKey @c uuid cred elecPubKey <- publicKey <$> randomSecretKey let elec = Election { election_name = "election" , election_description = "description"- , election_PublicKey = elecPubKey+ , election_crypto = ElectionCrypto_FFC ffc elecPubKey , election_questions = quests , election_uuid = uuid- , election_hash = Hash "" -- FIXME: when implemented+ , election_hash = hashJSON JSON.Null } verifyBallot elec <$> encryptBallot elec (Just ballotSecKey) opins
+ tests/HUnit/FFC.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE OverloadedStrings #-}+module HUnit.FFC where++import GHC.Natural (minusNaturalMaybe)+import Data.Maybe (fromJust)+import Test.Tasty.HUnit+import Voting.Protocol+import Utils++hunit :: TestTree+hunit = testGroup "FFC"+ [ testGroup "inv"+ [ testGroup "WeakParams"+ [ testCase "groupGen" $+ reify weakFFC $ \(Proxy::Proxy c) ->+ inv (groupGen @c) @?=+ groupGen ^ E (fromJust $ groupOrder @c `minusNaturalMaybe` one)+ ]+ , testGroup "BeleniosParams"+ [ testCase "groupGen" $+ reify beleniosFFC $ \(Proxy::Proxy c) ->+ inv (groupGen @c) @?=+ groupGen ^ E (fromJust $ groupOrder @c `minusNaturalMaybe` one)+ ]+ ]+ , testGroup "hash"+ [ testGroup "WeakParams" $+ reify weakFFC $ \(Proxy::Proxy c) ->+ [ testCase "[groupGen]" $+ hash "start" [groupGen @c] @?=+ fromNatural 100+ , testCase "[groupGen, groupGen]" $+ hash "start" [groupGen @c, groupGen] @?=+ fromNatural 16+ ]+ , testGroup "BeleniosParams" $+ reify beleniosFFC $ \(Proxy::Proxy c) ->+ [ testCase "[groupGen]" $+ hash "start" [groupGen @c] @?=+ fromNatural 1832875488615060263192702367259+ , testCase "[groupGen, groupGen]" $+ hash "start" [groupGen @c, groupGen] @?=+ fromNatural 2495277906542783643199702546512+ ]+ ]+ ]
tests/HUnit/Trustee/Indispensable.hs view
@@ -1,10 +1,10 @@-{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} module HUnit.Trustee.Indispensable where import Test.Tasty.HUnit+import qualified Data.Text as Text import qualified System.Random as Random import qualified Text.Printf as Printf @@ -15,53 +15,52 @@ hunit :: TestTree hunit = testGroup "Indispensable" [ testGroup "verifyIndispensableTrusteePublicKey" $- [ testsVerifyIndispensableTrusteePublicKey @WeakParams+ [ testsVerifyIndispensableTrusteePublicKey weakFFC ] , testGroup "verifyTally" $- [ testsVerifyTally @WeakParams- , testsVerifyTally @BeleniosParams+ [ testsVerifyTally weakFFC+ , testsVerifyTally beleniosFFC ] ] -testsVerifyIndispensableTrusteePublicKey :: forall q. Params q => TestTree-testsVerifyIndispensableTrusteePublicKey =- testGroup (paramsName @q)- [ testVerifyIndispensableTrusteePublicKey @q 0 (Right ())+testsVerifyIndispensableTrusteePublicKey :: FFC -> TestTree+testsVerifyIndispensableTrusteePublicKey ffc =+ testGroup (Text.unpack $ ffc_name ffc)+ [ testVerifyIndispensableTrusteePublicKey ffc 0 (Right ()) ] testVerifyIndispensableTrusteePublicKey ::- forall q. Params q =>- Int -> Either ErrorTrusteePublicKey () -> TestTree-testVerifyIndispensableTrusteePublicKey seed exp =+ FFC -> Int -> Either ErrorTrusteePublicKey () -> TestTree+testVerifyIndispensableTrusteePublicKey ffc seed exp = let got =+ reify ffc $ \(Proxy::Proxy c) -> runExcept $ (`evalStateT` Random.mkStdGen seed) $ do- trusteeSecKey :: SecretKey q <- randomSecretKey+ trusteeSecKey :: SecretKey c <- randomSecretKey trusteePubKey <- proveIndispensableTrusteePublicKey trusteeSecKey lift $ verifyIndispensableTrusteePublicKey trusteePubKey in- testCase (show (paramsName @q)) $+ testCase (Text.unpack $ ffc_name ffc) $ 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+testsVerifyTally :: FFC -> TestTree+testsVerifyTally ffc =+ testGroup (Text.unpack $ ffc_name ffc)+ [ testVerifyTally ffc 0 1 1 1+ , testVerifyTally ffc 0 2 1 1+ , testVerifyTally ffc 0 1 2 1+ , testVerifyTally ffc 0 2 2 1+ , testVerifyTally ffc 0 5 10 5 ] -testVerifyTally ::- forall q. Params q =>- Int -> Natural -> Natural -> Natural -> TestTree-testVerifyTally seed nTrustees nQuests nChoices =+testVerifyTally :: FFC -> Int -> Natural -> Natural -> Natural -> TestTree+testVerifyTally ffc seed nTrustees nQuests nChoices = let clearTallyResult = dummyTallyResult nQuests nChoices in- let decryptedTallyResult :: Either ErrorDecryptionShare [[Natural]] =+ let decryptedTallyResult :: Either ErrorTally [[Natural]] =+ reify ffc $ \(Proxy::Proxy c) -> runExcept $ (`evalStateT` Random.mkStdGen seed) $ do- secKeyByTrustee :: [SecretKey q] <-+ secKeyByTrustee :: [SecretKey c] <- replicateM (fromIntegral nTrustees) $ randomSecretKey trusteePubKeys <- forM secKeyByTrustee $ proveIndispensableTrusteePublicKey let pubKeyByTrustee = trustee_PublicKey <$> trusteePubKeys@@ -71,12 +70,12 @@ lift $ verifyDecryptionShareByTrustee encTally pubKeyByTrustee decShareByTrustee tally@Tally{..} <- lift $ proveTally (encTally, countMax) decShareByTrustee $- combineIndispensableDecryptionShares pubKeyByTrustee encTally+ combineIndispensableDecryptionShares pubKeyByTrustee lift $ verifyTally tally $- combineIndispensableDecryptionShares pubKeyByTrustee encTally+ combineIndispensableDecryptionShares pubKeyByTrustee return tally_countByChoiceByQuest in- testCase (Printf.printf "nT=%i,nQ=%i,nC=%i (%i maxCount)"+ testCase (Printf.printf "#T=%i,#Q=%i,#C=%i (%i maxCount)" nTrustees nQuests nChoices (dummyTallyCount nQuests nChoices)) $ decryptedTallyResult @?= Right clearTallyResult@@ -91,8 +90,9 @@ ] encryptTallyResult ::- Monad m => RandomGen r => SubGroup q =>- PublicKey q -> [[Natural]] -> StateT r m (EncryptedTally q, Natural)+ Reifies c FFC =>+ Monad m => RandomGen r =>+ PublicKey c -> [[Natural]] -> StateT r m (EncryptedTally c, Natural) encryptTallyResult pubKey countByChoiceByQuest = (`runStateT` 0) $ forM countByChoiceByQuest $
tests/QuickCheck/Election.hs view
@@ -1,14 +1,18 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE UndecidableInstances #-} -- for Reifies instances {-# OPTIONS -fno-warn-orphans #-} module QuickCheck.Election where -import Test.Tasty.QuickCheck-import qualified Data.List as List-import qualified Data.Text as Text import Data.Eq (Eq(..)) import Data.Int (Int)+import Data.Maybe (fromJust) import Data.Ord (Ord(..))+import GHC.Natural (minusNaturalMaybe) import Prelude (undefined)+import Test.Tasty.QuickCheck+import qualified Data.Aeson as JSON+import qualified Data.List as List+import qualified Data.Text as Text import Voting.Protocol @@ -18,80 +22,86 @@ maxArbitraryChoices :: Natural maxArbitraryChoices = 5 maxArbitraryQuestions :: Natural-maxArbitraryQuestions = 5+maxArbitraryQuestions = 2 quickcheck :: TestTree quickcheck = testGroup "Election" [ testGroup "verifyBallot" $- [ testElection @WeakParams- , testElection @BeleniosParams+ [ testElection weakFFC+ , testElection beleniosFFC ] ] -testElection :: forall q. Params q => TestTree-testElection =- testGroup (paramsName @q)- [ testProperty "verifyBallot" $ \(seed, (elec::Election q) :> votes) ->+testElection :: FFC -> TestTree+testElection ffc =+ reify ffc $ \(Proxy::Proxy c) ->+ testGroup (Text.unpack $ ffc_name ffc)+ [ testProperty "verifyBallot" $ \(seed, (elec::Election c) :> votes) -> isRight $ runExcept $ (`evalStateT` mkStdGen seed) $ do- -- ballotSecKey :: SecretKey q <- randomSecretKey+ -- ballotSecKey :: SecretKey c <- randomSecretKey ballot <- encryptBallot elec Nothing votes unless (verifyBallot elec ballot) $ lift $ throwE $ ErrorBallot_Wrong ] -instance PrimeField p => Arbitrary (F p) where- arbitrary = choose (zero, F (fieldCharac @p) - one)-instance SubGroup q => Arbitrary (G q) where+instance Reifies c FFC => Arbitrary (F c) where+ arbitrary = F <$> choose (zero, fromJust $ fieldCharac @c `minusNaturalMaybe` one)+instance Reifies c FFC => Arbitrary (G c) where arbitrary = do m <- arbitrary return (groupGen ^ m)-instance SubGroup q => Arbitrary (E q) where- arbitrary = E <$> choose (zero, groupOrder @q - one)+instance Reifies c FFC => Arbitrary (E c) where+ arbitrary = E <$> choose (zero, fromJust $ groupOrder @c `minusNaturalMaybe` one) instance Arbitrary UUID where arbitrary = do seed <- arbitrary (`evalStateT` mkStdGen seed) $ randomUUID-instance SubGroup q => Arbitrary (Proof q) where+instance Reifies c FFC => Arbitrary (Proof c) where arbitrary = do proof_challenge <- arbitrary proof_response <- arbitrary return Proof{..}-instance SubGroup q => Arbitrary (Question q) where+instance Arbitrary Question where arbitrary = do let question_text = "question" choices :: Natural <- choose (1, maxArbitraryChoices) let question_choices = [Text.pack ("c"<>show c) | c <- [1..choices]]- question_mini <- fromNatural <$> choose (0, choices)- question_maxi <- fromNatural <$> choose (nat question_mini, choices)+ question_mini <- choose (0, choices)+ question_maxi <- choose (nat question_mini, choices) return Question{..} shrink quest = [ quest{question_choices, question_mini, question_maxi} | question_choices <- shrinkList pure $ question_choices quest- , let nChoices = fromNatural $ fromIntegral $ List.length question_choices- , question_mini <- shrink $ min nChoices $ max zero $ question_mini quest- , question_maxi <- shrink $ min nChoices $ max question_mini $ question_maxi quest+ , let nChoices = fromIntegral $ List.length question_choices+ , question_mini <- shrinkIntegral $ min nChoices $ max zero $ question_mini quest+ , question_maxi <- shrinkIntegral $ min nChoices $ max question_mini $ question_maxi quest ]-instance SubGroup q => Arbitrary (Election q) where+instance Reifies c FFC => Arbitrary (Election c) where arbitrary = do let election_name = "election" let election_description = "description"- election_PublicKey <- arbitrary+ election_crypto <- arbitrary election_questions <- resize (fromIntegral maxArbitraryQuestions) $ listOf1 arbitrary election_uuid <- arbitrary- let election_hash = Hash ""+ let election_hash = hashJSON JSON.Null return Election{..} shrink elec = [ elec{election_questions} | election_questions <- shrink $ election_questions elec ]+instance Reifies c FFC => Arbitrary (ElectionCrypto c) where+ arbitrary = do+ let electionCrypto_FFC_params = reflect (Proxy::Proxy c)+ electionCrypto_FFC_PublicKey <- arbitrary+ return ElectionCrypto_FFC{..} -- | A type to declare an 'Arbitrary' instance where @b@ depends on @a@. data (:>) a b = a :> b deriving (Eq,Show)-instance SubGroup q => Arbitrary (Question q :> [Bool]) where+instance Arbitrary (Question :> [Bool]) where arbitrary = do quest@Question{..} <- arbitrary votes <- do@@ -104,7 +114,7 @@ [ q :> shrinkVotes q votes | q <- shrink quest ]-instance SubGroup q => Arbitrary (Election q :> [[Bool]]) where+instance Reifies c FFC => Arbitrary (Election c :> [[Bool]]) where arbitrary = do elec@Election{..} <- arbitrary votes <- forM election_questions $ \Question{..} -> do@@ -136,7 +146,7 @@ -- | @('shrinkVotes' quest votes)@ -- returns a reduced version of the given @votes@ -- to fit the requirement of the given @quest@.-shrinkVotes :: Question q -> [Bool] -> [Bool]+shrinkVotes :: Question -> [Bool] -> [Bool] shrinkVotes Question{..} votes = (\(nTrue, b) -> nTrue <= nat question_maxi && b) <$> List.zip (countTrue votes) votes
tests/QuickCheck/Trustee.hs view
@@ -1,10 +1,11 @@ {-# OPTIONS -fno-warn-orphans #-}+{-# LANGUAGE UndecidableInstances #-} -- for Reifies instances module QuickCheck.Trustee where import Test.Tasty.QuickCheck+import qualified Data.Text as Text import Voting.Protocol-import Voting.Protocol.Trustee.Indispensable import Utils import QuickCheck.Election ()@@ -13,23 +14,24 @@ quickcheck = testGroup "Trustee" [ testGroup "verifyIndispensableTrusteePublicKey" $- [ testIndispensableTrusteePublicKey @WeakParams- , testIndispensableTrusteePublicKey @BeleniosParams+ [ testIndispensableTrusteePublicKey weakFFC+ , testIndispensableTrusteePublicKey beleniosFFC ] ] -testIndispensableTrusteePublicKey :: forall q. Params q => TestTree-testIndispensableTrusteePublicKey =- testGroup (paramsName @q)+testIndispensableTrusteePublicKey :: FFC -> TestTree+testIndispensableTrusteePublicKey ffc =+ reify ffc $ \(Proxy::Proxy c) ->+ testGroup (Text.unpack $ ffc_name ffc) [ testProperty "Right" $ \seed -> isRight $ runExcept $ (`evalStateT` mkStdGen seed) $ do- trusteeSecKey :: SecretKey q <- randomSecretKey+ trusteeSecKey :: SecretKey c <- randomSecretKey trusteePubKey <- proveIndispensableTrusteePublicKey trusteeSecKey lift $ verifyIndispensableTrusteePublicKey trusteePubKey ] -instance SubGroup q => Arbitrary (TrusteePublicKey q) where+instance Reifies c FFC => Arbitrary (TrusteePublicKey c) where arbitrary = do trustee_PublicKey <- arbitrary trustee_SecretKeyProof <- arbitrary
tests/Utils.hs view
@@ -56,6 +56,7 @@ import Voting.Protocol.Utils +debug :: Show a => String -> a -> a debug msg x = trace (msg<>": "<>show x) x -- | @'nCk' n k@ returns the number of combinations