Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
full voting loop working with self-managed election
- Loading branch information
Showing
5 changed files
with
308 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
{% extends "base.html" %} | ||
{% block content %} | ||
<script language="javascript"> | ||
Helios.setup(); | ||
|
||
ELECTION_PK = ElGamal.PublicKey.fromJSONObject({{election_pk_json|safe}}); | ||
var ELECTION_SK = null; | ||
|
||
{% if election_sk %} | ||
ELECTION_SK = ElGamal.SecretKey.fromJSONObject({{election_sk_json|safe}}); | ||
{% endif %} | ||
|
||
$(document).ready(function() { | ||
if (ELECTION_SK != null) { | ||
$('#sk_section').hide(); | ||
} | ||
}); | ||
|
||
function load_election_and_ballots(election_id) { | ||
// BALLOTS by voter key | ||
ELECTION = null; | ||
ELECTION_ID = election_id; | ||
BALLOTS = {}; | ||
BALLOTS_LOADED = {}; | ||
VOTER_LIST = []; | ||
|
||
// get the election data | ||
Helios.get_election({'election_id' : election_id}, function(election_json) { | ||
var election = HELIOS.Election.fromJSONObject(election_json); | ||
ELECTION = election; | ||
|
||
// get the voters | ||
Helios.get_election_voters({'election_id' : election_id}, function(voters) { | ||
VOTER_LIST = voters; | ||
$(voters).each(function(v_num, v) { | ||
// download each voter's data, stuffing into BALLOTS | ||
Helios.get_election_voter({'election_id' : election_id, 'voter_id' : v.voter_id}, function(voter) { | ||
BALLOTS[voter.voter_id] = HELIOS.EncryptedVote.fromJSONObject(voter.vote, ELECTION); | ||
BALLOTS_LOADED[voter.voter_id] = true; | ||
}); | ||
}); | ||
|
||
when_ready_verify_ballots_and_tally(); | ||
}); | ||
}); | ||
} | ||
|
||
function when_ready_verify_ballots_and_tally() { | ||
var tally = verify_ballots_and_tally(); | ||
|
||
if (!tally) { | ||
setTimeout('when_ready_verify_ballots_and_tally()', 2000); | ||
} else { | ||
// store the tally | ||
$.post('/elections/{{election.election_id}}/set_tally', {tally: jQuery.toJSON(tally)}, function(result) { | ||
if (result == "success" || result == "SUCCESS") { | ||
alert('tally and proof done and uploaded'); | ||
document.location = "./view" | ||
} | ||
}); | ||
} | ||
} | ||
|
||
var NUM_VOTES = 0; | ||
|
||
function increment_vote_tally_count() { | ||
NUM_VOTES += 1; | ||
$('#num_votes').html(NUM_VOTES); | ||
} | ||
|
||
function verify_ballots_and_tally() { | ||
// check that ballots are here | ||
for (var i=0; i<VOTER_LIST.length; i++) { | ||
if (BALLOTS_LOADED[VOTER_LIST[i].voter_id] == null) { | ||
// not all ballots have been downloaded | ||
return false; | ||
} | ||
} | ||
|
||
// initialize the tallies | ||
var TALLY = []; | ||
$(ELECTION.questions).each(function(qnum, q) { | ||
TALLY[qnum] = $(q.answers).map(function(anum, a) { | ||
return 1; | ||
}); | ||
}); | ||
|
||
// voter hashes | ||
var voters = []; | ||
|
||
var VALID_P = true; | ||
|
||
// we need to keep track of the values of g^{voter_num} for decryption | ||
var DISCRETE_LOGS = {}; | ||
var CURRENT_EXP = 0; | ||
var CURRENT_RESULT = BigInt.ONE; | ||
DISCRETE_LOGS[CURRENT_RESULT.toString()] = CURRENT_EXP; | ||
|
||
// all ballots are here | ||
$(VOTER_LIST).each(function(vnum, voter) { | ||
var ballot = BALLOTS[voter.voter_id]; | ||
|
||
// non-voter? | ||
if (ballot == null) { | ||
return; | ||
} | ||
|
||
// this ballot will count, so let's increment the discrete log pre-computation mapping. | ||
CURRENT_EXP += 1; | ||
CURRENT_RESULT = CURRENT_RESULT.multiply(ELECTION.pk.g).mod(ELECTION.pk.p); | ||
DISCRETE_LOGS[CURRENT_RESULT.toString()] = CURRENT_EXP; | ||
|
||
var voter_hash = ballot.get_hash(); | ||
|
||
// verify the ballot | ||
var this_vote_result = ballot.verifyProofs(ELECTION.pk, function(answer_num, choice_num, result, choice) { | ||
if (choice_num != null) { | ||
// keep track of tally | ||
TALLY[answer_num][choice_num] = choice.multiply(TALLY[answer_num][choice_num]); | ||
} | ||
}); | ||
|
||
VALID_P = VALID_P && this_vote_result; | ||
|
||
increment_vote_tally_count(); | ||
}); | ||
|
||
// are we okay? | ||
if (!VALID_P) | ||
return false; | ||
|
||
var result= []; | ||
var result_proof= []; | ||
|
||
// decrypt the tallies | ||
$(TALLY).each(function(q_num, q_tally) { | ||
result[q_num] = []; | ||
result_proof[q_num] = []; | ||
$(q_tally).each(function(choice_num, choice_tally) { | ||
var one_choice_result = ELECTION_SK.decryptAndProve(choice_tally, ElGamal.fiatshamir_challenge_generator); | ||
result[q_num][choice_num] = DISCRETE_LOGS[one_choice_result.plaintext.getM().toString()]; | ||
result_proof[q_num][choice_num] = one_choice_result.proof; | ||
}); | ||
}); | ||
|
||
return {'result': result, 'result_proof' : result_proof}; | ||
} | ||
|
||
function do_tally() { | ||
if (ELECTION_SK == null) { | ||
ELECTION_SK = ElGamal.SecretKey.fromJSONObject($.secureEvalJSON($('#sk_textarea').val())); | ||
$('#sk_section').hide(); | ||
} | ||
|
||
load_election_and_ballots('{{election.election_id}}'); | ||
} | ||
</script> | ||
<h2 class="title">{{election.name}} -- Drive Tally</h2> | ||
|
||
<p> | ||
This page will tally the election and set the result back with the server. | ||
</p> | ||
|
||
<p align="center" style="font-size:16pt;"> | ||
<span id="num_votes">0</span> tallied. | ||
</p> | ||
|
||
<div id="sk_section"> | ||
<form onsubmit="return false;"> | ||
Your Secret Key:<br /> | ||
<textarea id="sk_textarea" cols="60" rows="5"></textarea> | ||
</form> | ||
</div> | ||
|
||
<p id="tally_section"> | ||
<button onclick="do_tally();">Tally!</button> | ||
</p> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.