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 pass
from eos.core.bigint import * from eos.core.bigint import *
from eos.core.objects import *
# Libraries # Libraries
# ========= # =========
@ -68,6 +69,11 @@ class SHA256:
self.update_text(str(value)) self.update_text(str(value))
return self 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): def hash_as_b64(self):
if is_python: if is_python:
return base64.b64encode(self.impl.digest()).decode('utf-8') 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 self._instance[0].recurse_parents(cls)
return None return None
@property
def hash(self):
return SHA256().update_text(EosObject.to_json(EosObject.serialise_and_wrap(self))).hash_as_b64()
@staticmethod @staticmethod
def serialise_and_wrap(value, object_type=None): def serialise_and_wrap(value, object_type=None):
if object_type: if object_type:

View File

@ -63,16 +63,16 @@ class RPCMixnet:
if self.is_left: if self.is_left:
for i in range(len(permutations_and_reenc)): for i in range(len(permutations_and_reenc)):
val = permutations_and_reenc[i] val = permutations_and_reenc[i]
val_obj = MixChallengeResponse(index=val[0], reenc=val[1], rand=val[2]) val_obj = MixChallengeResponse(challenge_index=i, response_index=val[0], reenc=val[1], rand=val[2])
commitments.append(SHA256().update_text(EosObject.to_json(val_obj.serialise())).hash_as_bigint()) commitments.append(SHA256().update_obj(val_obj).hash_as_bigint())
else: else:
for i in range(len(permutations_and_reenc)): for i in range(len(permutations_and_reenc)):
# Find the answer that went to 'i' # 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) idx = next(idx for idx in range(len(permutations_and_reenc)) if permutations_and_reenc[idx][0] == i)
val = permutations_and_reenc[idx] val = permutations_and_reenc[idx]
val_obj = MixChallengeResponse(index=idx, reenc=val[1], rand=val[3]) val_obj = MixChallengeResponse(challenge_index=i, response_index=idx, reenc=val[1], rand=val[3])
commitments.append(SHA256().update_text(EosObject.to_json(val_obj.serialise())).hash_as_bigint()) commitments.append(SHA256().update_obj(val_obj).hash_as_bigint())
self.params = permutations_and_reenc self.params = permutations_and_reenc
return shuffled_answers, commitments return shuffled_answers, commitments
@ -80,8 +80,8 @@ class RPCMixnet:
def challenge(self, i): def challenge(self, i):
if self.is_left: if self.is_left:
val = self.params[i] 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: else:
idx = next(idx for idx in range(len(self.params)) if self.params[idx][0] == i) idx = next(idx for idx in range(len(self.params)) if self.params[idx][0] == i)
val = self.params[idx] 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) self.assertEqual(claimed_blocks[j].delta, reencrypted_block.delta)
for i in range(len(pts)): for i in range(len(pts)):
perm, reencs, rand = mixnet.challenge(i) val_obj = mixnet.challenge(i)
val_obj = MixChallengeResponse(index=perm, reenc=reencs, rand=rand) self.assertEqual(commitments[i], SHA256().update_obj(val_obj).hash_as_bigint())
self.assertEqual(commitments[i], SHA256().update_text(EosObject.to_json(val_obj.serialise())).hash_as_bigint())
if mixnet.is_left: if mixnet.is_left:
verify_shuffle(i, perm, reencs) verify_shuffle(val_obj.challenge_index, val_obj.response_index, val_obj.reenc)
else: 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 # NB: This isn't doing it in sequence, it's just testing a left mixnet and a right mixnet respectively
do_mixnet(0) do_mixnet(0)
@ -258,10 +257,25 @@ class ElectionTestCase(EosTestCase):
election.workflow.get_task('eos.psr.workflow.TaskMixVotes').exit() election.workflow.get_task('eos.psr.workflow.TaskMixVotes').exit()
election.save() election.save()
# Verify mixes # Prove mixes
election.workflow.get_task('eos.psr.workflow.TaskVerifyMixes').enter() election.workflow.get_task('eos.psr.workflow.TaskProveMixes').enter()
election.save() 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 # Record challenge responses
for i in range(len(election.questions)): for i in range(len(election.questions)):
for j in range(len(election.mixing_trustees)): for j in range(len(election.mixing_trustees)):
@ -280,14 +294,17 @@ class ElectionTestCase(EosTestCase):
should_reveal = ((j % 2) == (challenge_bit % 2)) should_reveal = ((j % 2) == (challenge_bit % 2))
if should_reveal: if should_reveal:
response = trustee.mixnets[i].challenge(k) response = trustee.mixnets[i].challenge(k)
trustee.response[i].append(MixChallengeResponse( trustee.response[i].append(response)
challenge_index=k,
response_index=response[0],
reenc=response[1],
rand=response[2]
))
election.workflow.get_task('eos.psr.workflow.TaskVerifyMixes').exit() # 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.TaskProveMixes').exit()
election.save() election.save()
# Decrypt votes, for realsies # Decrypt votes, for realsies
@ -295,7 +312,7 @@ class ElectionTestCase(EosTestCase):
election.save() election.save()
# Check result # 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)): for i in range(len(RESULTS)):
votes1 = RESULTS[i] votes1 = RESULTS[i]
votes2 = [x.choices for x in election.results[i].answers] 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 # Do not automatically exit this task
pass pass
class TaskVerifyMixes(WorkflowTask): class TaskProveMixes(WorkflowTask):
depends_on = ['eos.psr.workflow.TaskMixVotes'] depends_on = ['eos.psr.workflow.TaskMixVotes']
def on_enter(self): def on_enter(self):
@ -36,7 +36,7 @@ class TaskVerifyMixes(WorkflowTask):
pass pass
class TaskDecryptVotes(eos.base.workflow.TaskDecryptVotes): class TaskDecryptVotes(eos.base.workflow.TaskDecryptVotes):
depends_on = ['eos.psr.workflow.TaskVerifyMixes'] depends_on = ['eos.psr.workflow.TaskProveMixes']
def on_enter(self): def on_enter(self):
election = self.recurse_parents('eos.base.election.Election') election = self.recurse_parents('eos.base.election.Election')
@ -62,6 +62,6 @@ class PSRWorkflow(Workflow):
self.tasks.append(TaskOpenVoting()) self.tasks.append(TaskOpenVoting())
self.tasks.append(TaskCloseVoting()) self.tasks.append(TaskCloseVoting())
self.tasks.append(TaskMixVotes()) 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(TaskDecryptVotes()) # The PSR one, not the base one
self.tasks.append(TaskReleaseResults()) self.tasks.append(TaskReleaseResults())