diff --git a/helios/crypto/elgamal.py b/helios/crypto/elgamal.py index 95e8e28de3d596a859f3c576880b6f341c5acf94..8b3b04794cef1853dbebc256d2fb625d4b768323 100644 --- a/helios/crypto/elgamal.py +++ b/helios/crypto/elgamal.py @@ -71,7 +71,7 @@ class KeyPair(object): self.sk.x = Utils.random_mpz_lt(p) self.pk.y = pow(g, self.sk.x, p) - self.sk.pk = self.pk + self.sk.public_key = self.pk class PublicKey: def __init__(self): @@ -148,11 +148,11 @@ class PublicKey: class SecretKey: def __init__(self): self.x = None - self.pk = None + self.public_key = None @property - def public_key(self): - return self.pk + def pk(self): + return self.public_key def decryption_factor(self, ciphertext): """ diff --git a/helios/datatypes/legacy.py b/helios/datatypes/legacy.py index 7ab6612e0c5ab0319d67fe592f01b152e3f23e2f..c2a89dfefbcfcbbf285fc903af7cab769c8ec40a 100644 --- a/helios/datatypes/legacy.py +++ b/helios/datatypes/legacy.py @@ -194,6 +194,10 @@ class Questions(LegacyObject): class Tally(LegacyObject): WRAPPED_OBJ_CLASS = homomorphic.Tally + FIELDS = ['tally', 'num_tallied'] + STRUCTURED_FIELDS = { + 'tally': arrayOf(arrayOf('legacy/EGCiphertext'))} + class Eligibility(LegacyObject): pass diff --git a/helios/models.py b/helios/models.py index ea93b4829c9db793daed0391ffb46195fa29fdb9..415132824b7d25cda174dcd509feb3f2db7999e7 100644 --- a/helios/models.py +++ b/helios/models.py @@ -19,6 +19,7 @@ import helios from helios import datatypes + # useful stuff in auth from auth.models import User, AUTH_SYSTEMS from auth.jsonfield import JSONField @@ -443,7 +444,9 @@ class Election(HeliosModel): return helios.get_election_url(self) def init_tally(self): - return Tally(election=self) + # FIXME: create the right kind of tally + from helios.workflows import homomorphic + return homomorphic.Tally(election=self) @property def registration_status_pretty(self): diff --git a/helios/tasks.py b/helios/tasks.py index 461150f96992ab226f202193b9f5cc444e53e0d2..43ca5f65d652fed41c33b642d5cd634d94dda2b4 100644 --- a/helios/tasks.py +++ b/helios/tasks.py @@ -87,7 +87,7 @@ def single_voter_notify(voter_uuid, notification_template, extra_vars={}): def election_compute_tally(election_id): election = Election.objects.get(id = election_id) election.compute_tally() - + election_notify_admin.delay(election_id = election_id, subject = "encrypted tally computed", body = """ @@ -97,7 +97,6 @@ The encrypted tally for election %s has been computed. Helios """ % election.name) - if election.has_helios_trustee(): tally_helios_decrypt.delay(election_id = election.id) diff --git a/helios/tests.py b/helios/tests.py index 464c1839e5c903d9db996e41042973364e14736a..203ff001bd6a5d1597f4c71890ded0499a9d5772 100644 --- a/helios/tests.py +++ b/helios/tests.py @@ -455,9 +455,23 @@ class ElectionBlackboxTests(TestCase): self.assertRedirects(response, "%s/helios/elections/%s/cast_done" % (settings.URL_HOST, election_id)) # encrypted tally + response = self.client.post("/helios/elections/%s/compute_tally" % election_id, { + "csrf_token" : self.client.session['csrf_token'] + }) + self.assertRedirects(response, "/helios/elections/%s/view" % election_id) # should trigger helios decryption automatically + self.assertNotEquals(models.Election.objects.get(uuid=election_id).get_helios_trustee().decryption_proofs, None) # combine decryptions + response = self.client.post("/helios/elections/%s/combine_decryptions" % election_id, { + "csrf_token" : self.client.session['csrf_token'], + "subject" : "tally subject", + "body" : "tally body", + "send_to" : "all" + }) + self.assertRedirects(response, "/helios/elections/%s/view" % election_id) # check that tally matches + response = self.client.get("/helios/elections/%s/result" % election_id) + self.assertEquals(utils.from_json(response.content), [0,1]) diff --git a/helios/workflows/homomorphic.py b/helios/workflows/homomorphic.py index 4e143520e2e9973b9fe0cf2f486f7fca848b8bc2..7eaea4b614edd37d1cb61cd8256c13089fb8b6b2 100644 --- a/helios/workflows/homomorphic.py +++ b/helios/workflows/homomorphic.py @@ -325,25 +325,27 @@ class Tally(WorkflowObject): """ def __init__(self, *args, **kwargs): - super(Tally, self).__init__(*args, **kwargs) - - self.election = kwargs.get('election',None) + super(Tally, self).__init__() + + election = kwargs.get('election',None) self.tally = None self.num_tallied = 0 - if self.election: - self.init_election(self.election) + if election: + self.init_election(election) + self.tally = [[0 for a in q['answers']] for q in self.questions] else: self.questions = None self.public_key = None + self.tally = None def init_election(self, election): """ given the election, initialize some params """ + self.election = election self.questions = election.questions self.public_key = election.public_key - self.tally = [[0 for a in q['answers']] for q in self.questions] def add_vote_batch(self, encrypted_votes, verify_p=True): """ @@ -393,8 +395,8 @@ class Tally(WorkflowObject): # look up appropriate discrete log # this is the string conversion - question_factors.append(str(dec_factor)) - question_proof.append(proof.toJSONDict()) + question_factors.append(dec_factor) + question_proof.append(proof) decryption_factors.append(question_factors) decryption_proof.append(question_proof)