From 7640eab9aa9269cf2ad2785563d1dc343d748c9a Mon Sep 17 00:00:00 2001
From: Ben Adida
Date: Sun, 4 Jan 2009 23:21:32 -0800
Subject: [PATCH] fixed python verification and added support for min and max,
added some debugging
---
client/heliosclient.py | 10 ++++---
crypto/electionalgs.py | 53 +++++++++++++++++++++++++++++++------
helios/templates/index.html | 4 +--
tests/heliosclient.py | 9 ++++---
4 files changed, 60 insertions(+), 16 deletions(-)
diff --git a/client/heliosclient.py b/client/heliosclient.py
index 705df33..9c340e6 100644
--- a/client/heliosclient.py
+++ b/client/heliosclient.py
@@ -10,19 +10,23 @@
from crypto import algs, electionalgs
class HeliosClient(object):
- def __init__(self, auth_info, host, port):
+ def __init__(self, auth_info, host, port, prefix=""):
"""
auth_info is consumer_key, ....
"""
self.consumer = oauth.OAuthConsumer(auth_info['consumer_key'],auth_info['consumer_secret'])
self.token = oauth.OAuthToken(auth_info['consumer_key'],auth_info['consumer_secret'])
self.client = oauthclient.MachineOAuthClient(self.consumer, self.token, host, port)
+ self.prefix = prefix
def get(self, url, parameters = None):
- return self.client.access_resource("GET", url, parameters= parameters)
+ print "getting " + self.prefix + url
+ return self.client.access_resource("GET", self.prefix + url, parameters= parameters)
def post(self, url, parameters = None):
- return self.client.access_resource("POST", url, parameters= parameters)
+ print "posting " + self.prefix + url
+ result = self.client.access_resource("POST", self.prefix + url, parameters= parameters)
+ return result
def params(self):
params_json = self.get("/elections/params")
diff --git a/crypto/electionalgs.py b/crypto/electionalgs.py
index ceae2a6..323d689 100644
--- a/crypto/electionalgs.py
+++ b/crypto/electionalgs.py
@@ -20,10 +20,27 @@ def __init__(self, choices=None, individual_proofs=None, overall_proof=None, ran
self.overall_proof = overall_proof
self.randomness = randomness
- def verify(self, pk):
- possible_plaintexts = [algs.EGPlaintext(1, pk), algs.EGPlaintext(pk.g, pk)]
- homomorphic_sum = 0
+ @classmethod
+ def generate_plaintexts(cls, pk, min=0, max=1):
+ plaintexts = []
+ running_product = 1
+
+ # run the product up to the min
+ for i in range(max+1):
+ # if we're in the range, add it to the array
+ if i >= min:
+ plaintexts.append(algs.EGPlaintext(running_product, pk))
+
+ # next value in running product
+ running_product = (running_product * pk.g) % pk.p
+
+ return plaintexts
+
+ def verify(self, pk, min=0, max=1):
+ possible_plaintexts = self.generate_plaintexts(pk)
+ homomorphic_sum = 0
+
for choice_num in range(len(self.choices)):
choice = self.choices[choice_num]
choice.pk = pk
@@ -36,8 +53,11 @@ def verify(self, pk):
# compute homomorphic sum
homomorphic_sum = choice * homomorphic_sum
+ # determine possible plaintexts for the sum
+ sum_possible_plaintexts = self.generate_plaintexts(pk, min=min, max=max)
+
# verify the sum
- return homomorphic_sum.verify_disjunctive_encryption_proof(possible_plaintexts, self.overall_proof, algs.EG_disjunctive_challenge_generator)
+ return homomorphic_sum.verify_disjunctive_encryption_proof(sum_possible_plaintexts, self.overall_proof, algs.EG_disjunctive_challenge_generator)
def toJSONDict(self):
return {
@@ -78,7 +98,7 @@ def fromElectionAndAnswer(cls, election, question_num, answer_indexes):
randomness = [None for a in range(len(answers))]
# possible plaintexts [0, 1]
- plaintexts = [algs.EGPlaintext(1, pk), algs.EGPlaintext(pk.g, pk)]
+ plaintexts = cls.generate_plaintexts(pk)
# keep track of number of options selected.
num_selected_answers = 0;
@@ -110,7 +130,18 @@ def fromElectionAndAnswer(cls, election, question_num, answer_indexes):
# prove that the sum is 0 or 1 (can be "blank vote" for this answer)
# num_selected_answers is 0 or 1, which is the index into the plaintext that is actually encoded
- overall_proof = homomorphic_sum.generate_disjunctive_encryption_proof(plaintexts, num_selected_answers, randomness_sum, algs.EG_disjunctive_challenge_generator);
+ min_answers = 0
+ if question.has_key('min'):
+ min_answers = question['min']
+ max_answers = question['max']
+
+ if num_selected_answers < min_answers:
+ raise Exception("Need to select at least %s answer(s)" % min_answers)
+
+ sum_plaintexts = cls.generate_plaintexts(pk, min=min_answers, max=max_answers)
+
+ # need to subtract the min from the offset
+ overall_proof = homomorphic_sum.generate_disjunctive_encryption_proof(sum_plaintexts, num_selected_answers - min_answers, randomness_sum, algs.EG_disjunctive_challenge_generator);
return cls(choices, individual_proofs, overall_proof, randomness)
@@ -138,8 +169,14 @@ def verify(self, election):
return False
# check proofs on all of answers
- for ea in self.encrypted_answers:
- if not ea.verify(election.pk):
+ for question_num in range(len(election.questions)):
+ ea = self.encrypted_answers[question_num]
+ question = election.questions[question_num]
+ min_answers = 0
+ if question.has_key('min'):
+ min_answers = question['min']
+
+ if not ea.verify(election.pk, min=min_answers, max=question['max']):
return False
return True
diff --git a/helios/templates/index.html b/helios/templates/index.html
index 23296c9..9992ba6 100644
--- a/helios/templates/index.html
+++ b/helios/templates/index.html
@@ -17,12 +17,12 @@
- Check out our Frequently Asked Questions.
+ Check out our Frequently Asked Questions.
{% endblock %}
\ No newline at end of file
diff --git a/tests/heliosclient.py b/tests/heliosclient.py
index 4f68d2e..8e9c587 100644
--- a/tests/heliosclient.py
+++ b/tests/heliosclient.py
@@ -16,7 +16,10 @@
# modify variables here
helios = heliosclient.HeliosClient({'consumer_key': 'test', 'consumer_secret': '123'},
host = '174.129.241.146',
- port = 80)
+# host = "localhost",
+ port = 80,
+ prefix = "/helios"
+ )
# get the El Gamal Parameters
params = helios.params()
@@ -33,7 +36,7 @@
helios.election_set_reg(election_id, open_reg= True)
# set questions
-questions = [{"answers": ["ice-cream", "cake"], "max": 1, "question": "ice-cream or cake?", "short_name": "dessert"}]
+questions = [{"answers": ["ice-cream", "cake"], "min": 1, "max": 1, "question": "ice-cream or cake?", "short_name": "dessert"}]
helios.election_questions_save(election_id, questions)
# freeze it
@@ -48,7 +51,7 @@
# create three ballots
ballot_1 = electionalgs.EncryptedVote.fromElectionAndAnswers(election, [[1]])
ballot_2 = electionalgs.EncryptedVote.fromElectionAndAnswers(election, [[1]])
-ballot_3 = electionalgs.EncryptedVote.fromElectionAndAnswers(election, [[0]])
+ballot_3 = electionalgs.EncryptedVote.fromElectionAndAnswers(election, [[]])
print "created 3 ballots"