Skip to content

Commit b236cf0

Browse files
committed
Ballot encryption on the front end.
1 parent 672a6d8 commit b236cf0

File tree

3 files changed

+42
-30
lines changed

3 files changed

+42
-30
lines changed

cryptovote/cryptovote/controllers/vote.py

+31-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
2-
from flask import Blueprint, render_template, redirect, url_for, session, request, flash
2+
from damgard_jurik import EncryptedNumber
3+
from flask import Blueprint, render_template, redirect, url_for, session, request, flash, json
34
from random import shuffle
45
from ..helpers import election_exists
56
from ..models import Voter, Candidate, Authority
@@ -57,42 +58,52 @@ def vote(election):
5758
return redirect(url_for('election.election_home', election=election.name))
5859
candidates = election.candidates
5960
shuffle(candidates)
61+
62+
authority = Authority.query.filter_by(election=election).first()
63+
if not authority:
64+
flash("Election is missing authorities.")
65+
return redirect(url_for('election.election_home', election=election.name))
66+
public_key = authority.public_key
67+
if not public_key:
68+
flash("Authority missing public key.")
69+
return redirect(url_for('election.election_home', election=election.name))
70+
6071
if request.method == 'GET':
61-
return render_template('vote/vote.html', election=election, candidates=candidates)
72+
return render_template('vote/vote.html', election=election, candidates=candidates, public_key=public_key)
6273
else:
6374
ballot = request.form.get("ballot")
6475
if not ballot:
6576
flash("No ballot submitted.")
6677
return render_template('vote/vote.html', election=election, candidates=candidates)
67-
authority = Authority.query.filter_by(election=election).first()
68-
if not authority:
69-
flash("Election is missing authorities.")
70-
return redirect(url_for('election.election_home', election=election.name))
71-
public_key = authority.public_key
72-
if not public_key:
73-
flash("Authority missing public key.")
74-
return redirect(url_for('election.election_home', election=election.name))
75-
candidates = []
76-
for candidate in ballot.split(','):
78+
ballot_dec = json.loads(ballot)
79+
80+
# here, candidates and preferences are strings
81+
cand_prefs_raw = [(cand_pref['candidate'], cand_pref['preference']) for cand_pref in ballot_dec]
82+
83+
# here they are both ints
84+
cand_prefs = []
85+
for candidate, preference in cand_prefs_raw:
7786
c = Candidate.query.filter_by(election=election, name=candidate).first()
7887
if not c:
7988
flash("Invalid ballot.")
8089
return render_template('vote/vote.html', election=election, candidates=candidates)
81-
candidates.append(c.id)
82-
if len(election.candidates) != len(candidates):
90+
91+
pref = EncryptedNumber(int(preference), public_key)
92+
cand_prefs.append((c.id, pref))
93+
94+
if len(election.candidates) != len(cand_prefs):
8395
flash("Invalid number of votes on ballot.")
8496
return render_template('vote/vote.html', election=election, candidates=candidates)
85-
preferences = list(range(1, len(candidates)+1))
86-
candidate_to_preference = {candidate: preference for candidate, preference in zip(candidates, preferences)}
87-
candidates.sort()
88-
preferences = [candidate_to_preference[candidate] for candidate in candidates]
97+
8998
weight = public_key.encrypt(1)
90-
enc_preferences = list(map(lambda p : public_key.encrypt(p), preferences))
99+
candidates = [cand_pref[0] for cand_pref in cand_prefs]
100+
enc_preferences = [cand_pref[1] for cand_pref in cand_prefs]
101+
91102
voter.ballot = CandidateOrderBallot(candidates, enc_preferences, weight)
92103
election.bulletin += f"{voter.id}: "
93104
for preference in enc_preferences:
94105
election.bulletin += str(preference.value) + " "
95106
election.bulletin += "\n\n"
96107
db.session.commit()
97108
flash("Ballot cast successfully")
98-
return redirect(url_for('election.election_home', election=election.name))
109+
return redirect(url_for('election.election_home', election=election.name))

cryptovote/cryptovote/static/js/encrypt-ballot.js

+5-8
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@ class PublicKey {
33
*
44
* @param n BigInt
55
* @param s BigInt
6-
* @param m BigInt
76
*/
8-
constructor(n, s, m) {
7+
constructor(n, s) {
98
this.s = s;
109
this.n = n;
11-
this.m = m;
1210
this.n_s = this.n ** this.s; // n^s
1311
this.n_s_1 = this.n_s * this.n; // n^(s+1)
14-
this.n_s_m = this.n_s * this.m; // n^s * m
1512
}
1613

1714
/**
@@ -21,14 +18,14 @@ class PublicKey {
2118
*/
2219
encrypt(m) {
2320
let r = PublicKey.get_random_below(this.n - 1n) + 1n;
24-
return PublicKey.pow_mod(this.n + 1, m, this.n_s_1) * PublicKey.pow_mod(r, this.n_s, this.n_s_1) % this.n_s_1
21+
return PublicKey.pow_mod(this.n + 1n, m, this.n_s_1) * PublicKey.pow_mod(r, this.n_s, this.n_s_1) % this.n_s_1
2522
}
2623

2724
static get_random_below(n) {
28-
let power = 1;
25+
let power = 1n;
2926
let i = 0;
3027
for (; power < n; i++)
31-
power *= 2;
28+
power *= 2n;
3229
let len = Math.ceil(i / 8);
3330

3431
// cryptographically secure random
@@ -41,7 +38,7 @@ class PublicKey {
4138
build += BigInt(rands[i]) * f;
4239
f *= byte;
4340
}
44-
return build % n;
41+
return build % BigInt(n);
4542
}
4643

4744
/**

cryptovote/cryptovote/templates/vote/vote.html

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
<div class="heading">
1212
<h1>Ballot</h1>
1313
</div>
14-
<form action="{{ url_for('vote.vote', election=election.name) }}" method="post">
14+
<form id="ballot-form" action="{{ url_for('vote.vote', election=election.name) }}" method="post" onsubmit="return submitForm()">
15+
<input type="hidden" name="key_s" value="{{ public_key.s }}">
16+
<input type="hidden" name="key_n" value="{{ public_key.n }}">
17+
1518
<div class="form-group">
1619

1720
<ul id="sortable_nav" class="sortable ui-sortable" >
@@ -26,7 +29,7 @@ <h1>Ballot</h1>
2629
</ul>
2730

2831
</div>
29-
<input type="hidden" id="ballot" name="ballot"></input>
32+
<input type="hidden" id="ballot" name="ballot"/>
3033
<div class="form-group" style="margin-top: 50px;">
3134
<button type="submit" class="btn btn-primary btn-block btn-lg" style="background-color: #0084da;">Submit Ballot</button>
3235
</div>
@@ -37,6 +40,7 @@ <h1>Ballot</h1>
3740

3841
{% block scripts %}
3942
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
43+
<script src="{{ url_for('static', filename='js/encrypt-ballot.js') }}"></script>
4044
<script type="text/javascript">
4145
$("#sortable_nav").sortable({
4246
placeholder: "ui-state-highlight",

0 commit comments

Comments
 (0)