Skip to content

Commit

Permalink
fixed voter_hash #7 and began adding better paging for votes
Browse files Browse the repository at this point in the history
  • Loading branch information
benadida committed Aug 29, 2008
1 parent 21322dd commit 3f1128f
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 65 deletions.
12 changes: 8 additions & 4 deletions base/DBObjectGAE.py
Expand Up @@ -67,7 +67,7 @@ def selectAll(cls, order_by = None, offset = None, limit = None):
if order_by:
query.order(order_by)

return query.fetch(limit or 1000, offset or 0)
return query.fetch(limit=limit or 1000, offset=offset or 0)

@classmethod
def selectAllByKey(cls, key_name, key_value, order_by = None, offset = None, limit = None):
Expand All @@ -76,7 +76,7 @@ def selectAllByKey(cls, key_name, key_value, order_by = None, offset = None, lim
return cls.selectAllByKeys(keys, order_by, offset, limit)

@classmethod
def selectAllByKeys(cls, keys, order_by = None, offset = None, limit = None):
def selectAllByKeys(cls, keys, order_by = None, offset = None, after = None, limit = None):
# unicode
for k,v in keys.items():
keys[k] = to_utf8(v)
Expand All @@ -91,8 +91,12 @@ def selectAllByKeys(cls, keys, order_by = None, offset = None, limit = None):
# conditions
for k,v in keys.items():
query.filter('%s' % k, v)

# after
if order_by and after:
query.filter('%s > ' % order_by, after)

return query.fetch(limit or 1000, offset or 0)
return query.fetch(limit=limit or 1000, offset=offset or 0)

def _load_from_row(self, row, extra_fields=[]):

Expand Down Expand Up @@ -178,4 +182,4 @@ def toJSONRecurse(item):
return json_dict

def toJSON(self):
return simplejson.dumps(self.toJSONDict())
return utils.to_json(self.toJSONDict())
4 changes: 2 additions & 2 deletions base/DBObjectStandalone.py
Expand Up @@ -111,7 +111,7 @@ def update(self):
"""
# GAE
self.save()

# DELETE inherited from GAE

@classmethod
Expand Down Expand Up @@ -171,4 +171,4 @@ def toJSONRecurse(item):
return json_dict

def toJSON(self):
return simplejson.dumps(self.toJSONDict())
return utils.to_json(self.toJSONDict())
4 changes: 3 additions & 1 deletion base/__init__.py
Expand Up @@ -4,6 +4,8 @@

import cherrypy

from base import utils

try:
from django.utils import simplejson
except:
Expand Down Expand Up @@ -34,7 +36,7 @@ def json(func):
web client.
"""
def convert_to_json(self, *args, **kwargs):
return simplejson.dumps(func(self, *args, **kwargs), sort_keys = True)
return utils.to_json(func(self, *args, **kwargs))

return convert_to_json

Expand Down
8 changes: 7 additions & 1 deletion base/utils.py
Expand Up @@ -257,7 +257,13 @@ def get_host():
if cherrypy.request.wsgi_environ['SERVER_PORT'] != '80':
host_port = ":" + cherrypy.request.wsgi_environ['SERVER_PORT']
return "%s%s" % (host_str, host_port)


def to_json(d):
return simplejson.dumps(d, sort_keys=True)

def from_json(json_str):
return simplejson.loads(json_str)

def JSONtoDict(json):
x=simplejson.loads(json)
return x
Expand Down
29 changes: 15 additions & 14 deletions controllers/election.py
Expand Up @@ -5,7 +5,7 @@
"""

from base import *
from base import REST, session, Controller, template, mail
from base import REST, session, Controller, template, mail, utils
from crypto import algs
import models as do

Expand Down Expand Up @@ -81,7 +81,7 @@ def delete(self, voter, email):
self.redirect("../../voters_manage")

@session.login_protect
def add(self, email, name):
def add(self, email, name, category=None):
"""
Add a new voter to an election.
"""
Expand All @@ -91,6 +91,7 @@ def add(self, email, name):
v.election = election
v.email = email
v.name = name
v.category = category
v.generate_password()
v.insert()

Expand Down Expand Up @@ -199,7 +200,7 @@ def new(self):
"""
The form for creating a new election.
"""
eg_params_json = simplejson.dumps(ELGAMAL_PARAMS.toJSONDict(), sort_keys=True)
eg_params_json = utils.to_json(ELGAMAL_PARAMS.toJSONDict())
return self.render('new')

@web
Expand All @@ -224,13 +225,13 @@ def new_2(self, name, public_key, private_key=None, voting_starts_at=None, votin
# keypair = ELGAMAL_PARAMS.generate_keypair()

# serialize the keys to JSON and store them
pk = algs.EGPublicKey.from_dict(simplejson.loads(public_key))
election.public_key_json = simplejson.dumps(pk.to_dict())
pk = algs.EGPublicKey.from_dict(utils.from_json(public_key))
election.public_key_json = utils.to_json(pk.to_dict())

# the private key can be stored by the server
if private_key and private_key != "":
sk = algs.EGSecretKey.from_dict(simplejson.loads(private_key))
election.private_key_json = simplejson.dumps(sk.to_dict())
sk = algs.EGSecretKey.from_dict(utils.from_json(private_key))
election.private_key_json = utils.to_json(sk.to_dict())

election.save()

Expand Down Expand Up @@ -315,7 +316,7 @@ def save(self, election, election_json):
"""
user, election = self.check(election)

election.save_dict(simplejson.loads(election_json))
election.save_dict(utils.from_json(election_json))

return self.render('build')

Expand Down Expand Up @@ -400,13 +401,13 @@ def email_voters(self, election_id):

@web
@session.login_protect
def email_voters_2(self, election, introductory_message, offset="0", limit="10"):
def email_voters_2(self, election, introductory_message):
"""
Send email to voters of an election.
"""
user, election = self.check(election, True, True)

voters = election.get_voters(offset = int(offset), limit = int(limit))
voters = election.get_voters()

for voter in voters:
message_header = """
Expand All @@ -433,7 +434,7 @@ def email_voters_2(self, election, introductory_message, offset="0", limit="10")
if len(voters) == 0:
return "DONE"
else:
return simplejson.dumps([v.toJSONDict() for v in voters])
return utils.to_json([v.toJSONDict() for v in voters])

@web
@session.login_protect
Expand Down Expand Up @@ -462,11 +463,11 @@ def drive_tally(self, election):
JavaScript-based driver for the entire tallying process, now done in JavaScript.
"""
election_pk = election.get_pk()
election_pk_json = simplejson.dumps(election_pk.toJSONDict())
election_pk_json = utils.to_json(election_pk.toJSONDict())

election_sk = election.get_sk()
if election_sk:
election_sk_json = simplejson.dumps(election_sk.toJSONDict())
election_sk_json = utils.to_json(election_sk.toJSONDict())

return self.render('drive_tally')

Expand All @@ -476,7 +477,7 @@ def set_tally(self, election, tally):
"""
Set the tally and proof.
"""
tally_obj = simplejson.loads(tally)
tally_obj = utils.from_json(tally)
election.set_result(tally_obj['result'], tally_obj['result_proof'])
election.update()
return "success"
Expand Down
20 changes: 19 additions & 1 deletion models/modelsGAE.py
Expand Up @@ -86,8 +86,26 @@ class Voter(mbase.VoterBase):
vote = db.TextProperty()
vote_hash = db.StringProperty()

# keep a copy of the voter_id that we can sort by
voter_id = db.StringProperty()

# categorize voters
category = db.StringProperty()

JSON_FIELDS = mbase.VoterBase.JSON_FIELDS
voter_id = property(DBObject.get_id)
#voter_id = property(DBObject.get_id)

def save(self):
"""
Save object.
Save it twice if it's a new voter
"""
# save once, get the key(), and store it in a separate field.
if not self.is_saved():
super(Voter, self).save()
self.voter_id = str(self.key())

super(Voter, self).save()



59 changes: 27 additions & 32 deletions models/modelsbase.py
Expand Up @@ -36,50 +36,52 @@ def toJSONDict(self):
return DBObject.toJSONDict(self)

def save_dict(self, d):
self.questions_json = simplejson.dumps(d['questions'])
self.questions_json = utils.to_json(d['questions'])
self.update()

def get_hash(self):
str_val = simplejson.dumps(self.toJSONDict(), sort_keys=True)
logging.info("election string to hash is " + str_val)
str_val = utils.to_json(self.toJSONDict())
# logging.info("election string to hash is " + str_val)
return utils.hash_b64(str_val)

def save_questions(self, questions):
self.questions_json = simplejson.dumps(questions)
self.questions_json = utils.to_json(questions)
self.update()

def set_pk(self, pk):
self.public_key_json = simplejson.dumps(pk.to_dict())
self.public_key_json = utils.to_json(pk.to_dict())

def get_pk(self):
pk_json = self.public_key_json or 'null'
return algs.EGPublicKey.from_dict(simplejson.loads(pk_json))
return algs.EGPublicKey.from_dict(utils.from_json(pk_json))

def set_sk(self, sk):
self.private_key_json = simplejson.dumps(sk.to_dict())
self.private_key_json = utils.to_json(sk.to_dict())

def get_sk(self):
sk_json = self.private_key_json or 'null'
return algs.EGSecretKey.from_dict(simplejson.loads(sk_json))
return algs.EGSecretKey.from_dict(utils.from_json(sk_json))

def get_questions(self):
questions_json = self.questions_json or '[]'
return simplejson.loads(questions_json)
return utils.from_json(questions_json)

def get_voters(self, offset=None, limit=None):
return models.Voter.selectAllByKeys({'election': self}, offset=offset, limit=limit)
def get_voters(self, category=None, after=None, limit=None):
keys = {'election': self}
if category:
keys['category'] = category

return models.Voter.selectAllByKeys(keys, after=after, limit=limit)

def get_cast_votes(self, offset=None, limit=None):
return [voter.get_vote() for voter in self.get_voters(offset = offset, limit = limit) if voter.cast_id != None]

def get_voters_hash(self):
voters = self.get_voters()
voters_json = simplejson.dumps([v.toJSONDict() for v in voters])
voters_json = utils.to_json([v.toJSONDict() for v in voters])
logging.info("json for voters is: " + voters_json)
return utils.hash_b64(voters_json)

def get_votes(self, question_num):
return models.Voter.selectAllWithVote(election = self, question_num = question_num)

def freeze(self):
self.frozen_at = datetime.datetime.utcnow()
self.update()
Expand All @@ -88,20 +90,20 @@ def is_frozen(self):
return self.frozen_at != None

def set_result(self, tally_d, proof_d):
self.result_json = simplejson.dumps(tally_d)
self.decryption_proof = simplejson.dumps(proof_d)
self.result_json = utils.to_json(tally_d)
self.decryption_proof = utils.to_json(proof_d)

def get_result(self):
return simplejson.loads(self.result_json or "null")
return utils.from_json(self.result_json or "null")

def get_result_proof(self):
return simplejson.loads(self.decryption_proof or "null")
return utils.from_json(self.decryption_proof or "null")

def set_running_tally(self, running_tally):
self.running_tally = simplejson.dumps([[c.toJSONDict() for c in q] for q in running_tally])
self.running_tally = utils.to_json([[c.toJSONDict() for c in q] for q in running_tally])

def get_running_tally(self):
running_tally = simplejson.loads(self.running_tally or "null")
running_tally = utils.from_json(self.running_tally or "null")
if running_tally:
return [[algs.EGCiphertext.from_dict(d) for d in q] for q in running_tally]
else:
Expand Down Expand Up @@ -238,7 +240,6 @@ def tally(self):
# count it
answer_ciphertext = algs.EGCiphertext.from_dict(vote[question_num]['choices'][answer_num])
answer_ciphertext.pk = pk
logging.info("answer ciphertext is %s " % simplejson.dumps(answer_ciphertext.toJSONDict()))
if answer_tally == None:
answer_tally = answer_ciphertext
else:
Expand All @@ -250,13 +251,13 @@ def tally(self):
# Now we have the tally for that whole question
tally[question_num] = question_tally

self.encrypted_tally = simplejson.dumps(tally)
self.encrypted_tally = utils.to_json(tally)
self.save()

def decrypt(self):
# get basic data needed
sk = self.get_sk()
encrypted_tally = simplejson.loads(self.encrypted_tally)
encrypted_tally = utils.from_json(self.encrypted_tally)

# for all choices of all questions (double list comprehension)
decrypted_tally = []
Expand Down Expand Up @@ -291,7 +292,7 @@ class ElectionExponentBase(DBObject):

@classmethod
def get_max_by_election(cls, election):
all_exps = cls.selectAllByKeys({'election' : election}, '-exponent', None, 1)
all_exps = cls.selectAllByKeys(keys={'election' : election}, order_by='-exponent', offset=None, limit=1)
if len(all_exps) == 0:
return None
else:
Expand Down Expand Up @@ -350,7 +351,7 @@ def compute_vote_hash(self):
return vote_hash

def get_vote(self):
return simplejson.loads(self.vote or "null")
return utils.from_json(self.vote or "null")

def verifyProofsAndTally(self, election, running_tally):
# copy the tally array
Expand Down Expand Up @@ -425,9 +426,3 @@ def verifyProofsAndTally(self, election, running_tally):
self.save()

return new_running_tally


@classmethod
def selectAllWithVote(cls, election, question_num):
# TODO: check that this is really what we want given that we reversed the voter/vote
return Vote.all().filter('election = ', election).filter('question_num=', question_num)
5 changes: 5 additions & 0 deletions static/forms.css
Expand Up @@ -30,6 +30,11 @@ input.pretty {
border: 1px solid black;
}

input.prettysmall {
font-size: 12pt;
border: 1px solid black;
}


table.pretty {
margin: 1em 1em 1em 2em;
Expand Down
4 changes: 2 additions & 2 deletions static/verification-programs/HeliosVerifyBallot.py
Expand Up @@ -91,7 +91,7 @@ def http_json_get(relative_url, with_hash = False):
req = urllib2.Request(url = SERVER_URL + relative_url)
f = urllib2.urlopen(req)
content = f.read()
parsed_content = simplejson.loads(content)
parsed_content = utils.from_json(content)

if with_hash:
return parsed_content, hash_b64(content)
Expand Down Expand Up @@ -156,5 +156,5 @@ def verify_ballot(ballot):
ballot_content = f.read()
f.close()

ballot = simplejson.loads(ballot_content)
ballot = utils.from_json(ballot_content)
verify_ballot(ballot)

0 comments on commit 3f1128f

Please sign in to comment.