protocol: polish comments
authorJulien Moutinho <julm+hjugement@autogeree.net>
Thu, 25 Apr 2019 20:58:22 +0000 (20:58 +0000)
committerJulien Moutinho <julm+hjugement@autogeree.net>
Thu, 25 Apr 2019 20:58:22 +0000 (20:58 +0000)
hjugement-protocol/Protocol/Credential.hs
hjugement-protocol/Protocol/Election.hs

index b8ce6181b30595e5c6cb3457ba207c1bc6bd6d50..43174282dca848ecc44c341d492fbd5d5051436e 100644 (file)
@@ -24,7 +24,7 @@ import Protocol.Arithmetic
 -- | A 'Credential' is a word of @('tokenLength'+1 '==' 15)@-characters
 -- from a base alphabet of (@'tokenBase' '==' 58)@ characters:
 -- "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
--- (beware the absence of "0", "O", "I", and "l").
+-- (beware the absence of "0", \"O", \"I", and "l").
 -- The last character is a checksum.
 -- The entropy is: @('tokenLength' * log 'tokenBase' / log 2) '==' 82.01… bits@.
 newtype Credential = Credential Text
index 458ef5d0a397b7dba44b0d16d465d18d5961213d..13ed300f55d9ce85975edcaec577bceec78e67ba 100644 (file)
@@ -32,22 +32,27 @@ import qualified Utils.Constraint as Constraint
 -- | ElGamal-like encryption.
 data Encryption q = Encryption
  { encryption_nonce :: G q
-   -- ^ Public part of the random 'secNonce': @('groupGen''^'r)@
+   -- ^ Public part of the random 'secNonce': @('groupGen' '^'r)@
  , encryption_vault :: G q
-   -- ^ Encrypted opinion: @('pubKey''^'r '*' 'groupGen''^'opinion)@
+   -- ^ Encrypted opinion: @('pubKey' '^'r '*' 'groupGen' '^'opinion)@
  } deriving (Eq,Show)
 
 -- | Additive homomorphism.
--- Using the fact that: @'groupGen''^'x '*' 'groupGen''^'y '==' 'groupGen''^'(x'+'y)@.
+-- Using the fact that: @'groupGen' '^'x '*' 'groupGen' '^'y '==' 'groupGen' '^'(x'+'y)@.
 instance SubGroup q => Additive (Encryption q) where
        zero = Encryption one one
        x+y = Encryption
         (encryption_nonce x * encryption_nonce y)
         (encryption_vault x * encryption_vault y)
 
+-- ** Type 'PublicKey'
 type PublicKey = G
+-- ** Type 'SecretKey'
 type SecretKey = E
+-- *** Type 'SecretNonce'
 type SecretNonce = E
+-- ** Type 'ZKP'
+-- | Zero-knowledge proof
 type ZKP = BS.ByteString
 
 -- ** Type 'Opinion'
@@ -110,20 +115,20 @@ nizkProof secNonce commits oracle = do
 type Commitment = G
 
 -- ** Type 'Disjunction'
--- | A 'Disjunction' is an 'inv'ersed @'groupGen''^'opinion@
+-- | A 'Disjunction' is an 'inv'ersed @('groupGen' '^'opinion)@
 -- it's used in 'proveEncryption' to generate a 'Proof'
--- that an 'encryption_vault' contains a given @'groupGen''^'opinion@,
+-- that an 'encryption_vault' contains a given @('groupGen' '^'opinion)@,
 type Disjunction = G
 
-validBool :: SubGroup q => ML.MeasuredList 2 (Disjunction q)
-validBool = fromJust $ ML.fromList $ List.take 2 groupGenInverses
+booleanDisjunctions :: SubGroup q => ML.MeasuredList 2 (Disjunction q)
+booleanDisjunctions = fromJust $ ML.fromList $ List.take 2 groupGenInverses
 
-validRange ::
+intervalDisjunctions ::
  forall q mini maxi.
  SubGroup q =>
  Bounds mini maxi ->
  ML.MeasuredList (maxi-mini) (Disjunction q)
-validRange Bounds{}
+intervalDisjunctions Bounds{}
  | Constraint.Proof <- (Nat.<=) @mini @maxi =
        fromJust $
        ML.fromList $
@@ -132,10 +137,10 @@ validRange Bounds{}
        groupGenInverses
 
 -- ** Type 'ValidityProof'
--- | A list of 'Proof' to prove that the 'Opinion' within an 'Encryption'
+-- | A list of 'Proof's to prove that the 'Opinion' within an 'Encryption'
 -- is indexing a 'Disjunction' within a list of them,
 -- without knowing which 'Opinion' it is.
-newtype ValidityProof n q = ValidityProof (ML.MeasuredList n (Proof q))
+newtype ValidityProof disjs q = ValidityProof (ML.MeasuredList disjs (Proof q))
  deriving (Eq,Show)
 
 encryptionStatement :: SubGroup q => ZKP -> Encryption q -> BS.ByteString
@@ -145,22 +150,22 @@ encryptionStatement zkp Encryption{..} =
        fromString (show (natG encryption_vault))<>"|"
 
 proveEncryption ::
- forall ds m r q.
- Nat.Known ds =>
+ forall disjs m r q.
+ Nat.Known disjs =>
  Monad m => RandomGen r => SubGroup q =>
  PublicKey q -> ZKP ->
- ML.MeasuredList ds (Disjunction q) -> Opinion ds ->
+ ML.MeasuredList disjs (Disjunction q) -> Opinion disjs ->
  (SecretNonce q, Encryption q) ->
- S.StateT r m (ValidityProof ds q)
+ S.StateT r m (ValidityProof disjs q)
 proveEncryption pubKey zkp disjs
  (Nat.Index (o::Proxy o))
  (secNonce, enc@Encryption{..})
  -- NOTE: the 'Constraint.Proof's below are needed to prove
  -- that the returned 'ValidityProof' has the same length
  -- than the given list of 'Disjunction's.
- | Constraint.Proof <- (Nat.+<=) @o @1 @ds -- prove that o+1<=ds implies 1<=ds-o and o<=ds
- , Constraint.Proof <- (Nat.<=) @o @ds     -- prove that o<=ds implies ds-o is a Natural and o+(ds-o) ~ ds
- , Constraint.Proof <- (Nat.<=) @1 @(ds-o) -- prove that ((ds-o)-1)+1 ~ ds-o
+ | Constraint.Proof <- (Nat.+<=) @o @1 @disjs -- prove that o+1<=disjs implies 1<=disjs-o and o<=disjs
+ , Constraint.Proof <- (Nat.<=) @o @disjs     -- prove that o<=disjs implies disjs-o is a Natural and o+(disjs-o) ~ disjs
+ , Constraint.Proof <- (Nat.<=) @1 @(disjs-o) -- prove that ((disjs-o)-1)+1 ~ disjs-o
  = do
        let (prevDisjs, ML.uncons -> (_indexedDisj,nextDisjs)) = ML.splitAt o disjs
        prevFakes <- fakeProof `mapM` prevDisjs
@@ -170,7 +175,7 @@ proveEncryption pubKey zkp disjs
                sum (proof_challenge . fst <$> prevFakes) +
                sum (proof_challenge . fst <$> nextFakes)
        genuineProof <- nizkProof secNonce [groupGen, pubKey] $
-        -- 'Oracle'
+        -- 'Oracle'
         \nizkCommitments ->
                let commitments =
                        foldMap snd prevFakes <>
@@ -271,11 +276,11 @@ answer pubKey zkp Question{..} opinions
        encryptions <- encrypt pubKey `mapM` opinions
        individualProofs <-
                sequence $ ML.zipWith
-                (proveEncryption pubKey zkp validBool)
+                (proveEncryption pubKey zkp booleanDisjunctions)
                 opinions encryptions
        sumProof <-
                proveEncryption pubKey zkp
-                (validRange question_bounds)
+                (intervalDisjunctions question_bounds)
                 (Nat.Index $ Proxy @(opinionsSum-mini))
                 ( sum (fst <$> encryptions)
                 , sum (snd <$> encryptions) )
@@ -293,9 +298,9 @@ validateAnswer ::
  Question choices mini maxi q ->
  Answer choices mini maxi q -> Bool
 validateAnswer pubKey zkp Question{..} Answer{..} =
-       and (validateEncryption pubKey zkp validBool <$> answer_opinions) &&
+       and (validateEncryption pubKey zkp booleanDisjunctions <$> answer_opinions) &&
        validateEncryption pubKey zkp
-        (validRange question_bounds)
+        (intervalDisjunctions question_bounds)
         ( sum (fst <$> answer_opinions)
         , answer_sumProof )
 
@@ -370,6 +375,30 @@ ballot Election{..} secKeyMay opinionsByQuest = do
                 , ballot_signature
                 }
 
+validateBallot ::
+ SubGroup q =>
+ Election quests choices mini maxi q ->
+ Ballot quests choices mini maxi q ->
+ Bool
+validateBallot Election{..} Ballot{..} =
+       ballot_election_uuid == election_uuid &&
+       ballot_election_hash == election_hash &&
+       let (validSign, zkp) =
+               case ballot_signature of
+                Nothing -> (True, "")
+                Just (Signature pubKey Proof{..}) ->
+                       let zkp = fromString (show (natG pubKey)) in
+                       let validSign =
+                               let commitment = groupGen ^ proof_response * pubKey ^ proof_challenge in
+                               let prefix     = signatureCommitments zkp commitment in
+                               let contents   = signatureStatement ballot_answers in
+                               hash prefix contents == proof_challenge
+                       in (validSign, zkp)
+       in
+       validSign &&
+       and (ML.zipWith (validateAnswer election_publicKey zkp)
+        election_questions ballot_answers)
+
 -- ** Type 'Signature'
 -- | Schnorr-like signature.
 --