Verify proofs as part of test

This commit is contained in:
Yingtong Li 2017-09-29 13:39:56 +10:00
parent 239c7be952
commit 805401ed43
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
5 changed files with 47 additions and 28 deletions

View File

@ -23,6 +23,7 @@ except:
pass
from eos.core.bigint import *
from eos.core.objects import *
# Libraries
# =========
@ -68,6 +69,11 @@ class SHA256:
self.update_text(str(value))
return self
def update_obj(self, *values):
for value in values:
self.update_text(EosObject.to_json(EosObject.serialise_and_wrap(value)))
return self
def hash_as_b64(self):
if is_python:
return base64.b64encode(self.impl.digest()).decode('utf-8')

View File

@ -151,10 +151,6 @@ class EosObject(metaclass=EosObjectType):
return self._instance[0].recurse_parents(cls)
return None
@property
def hash(self):
return SHA256().update_text(EosObject.to_json(EosObject.serialise_and_wrap(self))).hash_as_b64()
@staticmethod
def serialise_and_wrap(value, object_type=None):
if object_type:

View File

@ -63,16 +63,16 @@ class RPCMixnet:
if self.is_left:
for i in range(len(permutations_and_reenc)):
val = permutations_and_reenc[i]
val_obj = MixChallengeResponse(index=val[0], reenc=val[1], rand=val[2])
commitments.append(SHA256().update_text(EosObject.to_json(val_obj.serialise())).hash_as_bigint())
val_obj = MixChallengeResponse(challenge_index=i, response_index=val[0], reenc=val[1], rand=val[2])
commitments.append(SHA256().update_obj(val_obj).hash_as_bigint())
else:
for i in range(len(permutations_and_reenc)):
# Find the answer that went to 'i'
idx = next(idx for idx in range(len(permutations_and_reenc)) if permutations_and_reenc[idx][0] == i)
val = permutations_and_reenc[idx]
val_obj = MixChallengeResponse(index=idx, reenc=val[1], rand=val[3])
commitments.append(SHA256().update_text(EosObject.to_json(val_obj.serialise())).hash_as_bigint())
val_obj = MixChallengeResponse(challenge_index=i, response_index=idx, reenc=val[1], rand=val[3])
commitments.append(SHA256().update_obj(val_obj).hash_as_bigint())
self.params = permutations_and_reenc
return shuffled_answers, commitments
@ -80,8 +80,8 @@ class RPCMixnet:
def challenge(self, i):
if self.is_left:
val = self.params[i]
return [val[0], val[1], val[2]]
return MixChallengeResponse(challenge_index=i, response_index=val[0], reenc=val[1], rand=val[2])
else:
idx = next(idx for idx in range(len(self.params)) if self.params[idx][0] == i)
val = self.params[idx]
return [idx, val[1], val[3]]
return MixChallengeResponse(challenge_index=i, response_index=idx, reenc=val[1], rand=val[3])

View File

@ -157,14 +157,13 @@ class MixnetTestCase(EosTestCase):
self.assertEqual(claimed_blocks[j].delta, reencrypted_block.delta)
for i in range(len(pts)):
perm, reencs, rand = mixnet.challenge(i)
val_obj = MixChallengeResponse(index=perm, reenc=reencs, rand=rand)
self.assertEqual(commitments[i], SHA256().update_text(EosObject.to_json(val_obj.serialise())).hash_as_bigint())
val_obj = mixnet.challenge(i)
self.assertEqual(commitments[i], SHA256().update_obj(val_obj).hash_as_bigint())
if mixnet.is_left:
verify_shuffle(i, perm, reencs)
verify_shuffle(val_obj.challenge_index, val_obj.response_index, val_obj.reenc)
else:
verify_shuffle(perm, i, reencs)
verify_shuffle(val_obj.response_index, val_obj.challenge_index, val_obj.reenc)
# NB: This isn't doing it in sequence, it's just testing a left mixnet and a right mixnet respectively
do_mixnet(0)
@ -258,10 +257,25 @@ class ElectionTestCase(EosTestCase):
election.workflow.get_task('eos.psr.workflow.TaskMixVotes').exit()
election.save()
# Verify mixes
election.workflow.get_task('eos.psr.workflow.TaskVerifyMixes').enter()
# Prove mixes
election.workflow.get_task('eos.psr.workflow.TaskProveMixes').enter()
election.save()
def verify_shuffle(i, j, idx_left, idx_right, reencs):
if j > 0:
orig_answers = election.mixing_trustees[j - 1].mixed_questions[i]
else:
orig_answers = []
for voter in election.voters:
for ballot in voter.ballots:
orig_answers.append(ballot.encrypted_answers[i])
claimed_blocks = election.mixing_trustees[j].mixed_questions[i][idx_right].blocks
for k in range(len(orig_answers[idx_left].blocks)):
reencrypted_block, _ = orig_answers[idx_left].blocks[k].reencrypt(reencs[k])
self.assertEqual(claimed_blocks[k].gamma, reencrypted_block.gamma)
self.assertEqual(claimed_blocks[k].delta, reencrypted_block.delta)
# Record challenge responses
for i in range(len(election.questions)):
for j in range(len(election.mixing_trustees)):
@ -280,14 +294,17 @@ class ElectionTestCase(EosTestCase):
should_reveal = ((j % 2) == (challenge_bit % 2))
if should_reveal:
response = trustee.mixnets[i].challenge(k)
trustee.response[i].append(MixChallengeResponse(
challenge_index=k,
response_index=response[0],
reenc=response[1],
rand=response[2]
))
trustee.response[i].append(response)
# Verify proof
self.assertEqual(trustee.commitments[i][k], SHA256().update_obj(response).hash_as_bigint())
if j % 2 == 0:
verify_shuffle(i, j, response.challenge_index, response.response_index, response.reenc)
else:
verify_shuffle(i, j, response.response_index, response.challenge_index, response.reenc)
election.workflow.get_task('eos.psr.workflow.TaskVerifyMixes').exit()
election.workflow.get_task('eos.psr.workflow.TaskProveMixes').exit()
election.save()
# Decrypt votes, for realsies
@ -295,7 +312,7 @@ class ElectionTestCase(EosTestCase):
election.save()
# Check result
RESULTS = [[[0], [0, 1], [2]], [[0], [1], [0]]]
RESULTS = [[voter[i] for voter in VOTES] for i in range(len(election.questions))]
for i in range(len(RESULTS)):
votes1 = RESULTS[i]
votes2 = [x.choices for x in election.results[i].answers]

View File

@ -28,7 +28,7 @@ class TaskMixVotes(WorkflowTask):
# Do not automatically exit this task
pass
class TaskVerifyMixes(WorkflowTask):
class TaskProveMixes(WorkflowTask):
depends_on = ['eos.psr.workflow.TaskMixVotes']
def on_enter(self):
@ -36,7 +36,7 @@ class TaskVerifyMixes(WorkflowTask):
pass
class TaskDecryptVotes(eos.base.workflow.TaskDecryptVotes):
depends_on = ['eos.psr.workflow.TaskVerifyMixes']
depends_on = ['eos.psr.workflow.TaskProveMixes']
def on_enter(self):
election = self.recurse_parents('eos.base.election.Election')
@ -62,6 +62,6 @@ class PSRWorkflow(Workflow):
self.tasks.append(TaskOpenVoting())
self.tasks.append(TaskCloseVoting())
self.tasks.append(TaskMixVotes())
self.tasks.append(TaskVerifyMixes())
self.tasks.append(TaskProveMixes())
self.tasks.append(TaskDecryptVotes()) # The PSR one, not the base one
self.tasks.append(TaskReleaseResults())